source: mainline/kernel/arch/arm64/src/interrupt.c@ 84176f3

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 84176f3 was 84176f3, checked in by Jakub Jermář <jakub@…>, 7 years ago

arm64: Add support for the architecture

This changeset adds basic support to run HelenOS on AArch64, targeting
the QEMU virt platform.

Boot:

  • Boot relies on the EDK II firmware, GRUB2 for EFI and the HelenOS bootloader (UEFI application). EDK II loads GRUB2 from a CD, GRUB2 loads the HelenOS bootloader (via UEFI) which loads OS components.
  • UEFI applications use the PE/COFF format and must be relocatable. The first problem is solved by manually having the PE/COFF headers and tables written in assembler. The relocatable requirement is addressed by compiling the code with -fpic and having the bootloader relocate itself at its startup.

Kernel:

  • Kernel code for AArch64 consists mostly of stubbing out various architecture-specific hooks: virtual memory management, interrupt and exception handling, context switching (including FPU lazy switching), support for virtual timer, atomic sequences and barriers, cache and TLB maintenance, thread and process initialization.
  • The patch adds a kernel driver for GICv2 (interrupt controller).
  • The PL011 kernel driver is extended to allow userspace to take ownership of the console.
  • The current code is not able to dynamically obtain information about available devices on the underlying machine. The port instead implements a machine-func interface similar to the one implemented by arm32. It defines a machine for the QEMU AArch64 virt platform. The configuration (device addresses and IRQ numbers) is then baked into the machine definition.

User space:

  • Uspace code for AArch64 similarly mostly implements architecture-specific hooks: context saving/restoring, syscall support, TLS support.

The patchset allows to boot the system but user interaction with the OS
is not yet possible.

  • Property mode set to 100644
File size: 4.3 KB
RevLine 
[84176f3]1/*
2 * Copyright (c) 2015 Petr Pavlu
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup kernel_arm64
30 * @{
31 */
32/** @file
33 * @brief Interrupts controlling routines.
34 */
35
36#include <arch/interrupt.h>
37#include <arch/machine_func.h>
38#include <ddi/irq.h>
39#include <interrupt.h>
40#include <time/clock.h>
41
42static irq_t timer_irq;
43static uint64_t timer_increment;
44
45/** Disable interrupts.
46 *
47 * @return Old interrupt priority level.
48 */
49ipl_t interrupts_disable(void)
50{
51 uint64_t daif = DAIF_read();
52
53 DAIF_write(daif | DAIF_IRQ_FLAG);
54
55 return (daif >> DAIF_IRQ_SHIFT) & 1;
56}
57
58/** Enable interrupts.
59 *
60 * @return Old interrupt priority level.
61 */
62ipl_t interrupts_enable(void)
63{
64 uint64_t daif = DAIF_read();
65
66 DAIF_write(daif & ~DAIF_IRQ_FLAG);
67
68 return (daif >> DAIF_IRQ_SHIFT) & 1;
69}
70
71/** Restore interrupt priority level.
72 *
73 * @param ipl Saved interrupt priority level.
74 */
75void interrupts_restore(ipl_t ipl)
76{
77 uint64_t daif = DAIF_read();
78
79 DAIF_write((daif & ~DAIF_IRQ_FLAG) |
80 ((ipl & 1) << DAIF_IRQ_SHIFT));
81}
82
83/** Read interrupt priority level.
84 *
85 * @return Current interrupt priority level.
86 */
87ipl_t interrupts_read(void)
88{
89 return (DAIF_read() >> DAIF_IRQ_SHIFT) & 1;
90}
91
92/** Check interrupts state.
93 *
94 * @return True if interrupts are disabled.
95 */
96bool interrupts_disabled(void)
97{
98 return DAIF_read() & DAIF_IRQ_FLAG;
99}
100
101/** Suspend the virtual timer. */
102static void timer_suspend(void)
103{
104 uint64_t cntv_ctl = CNTV_CTL_EL0_read();
105
106 CNTV_CTL_EL0_write(cntv_ctl | CNTV_CTL_IMASK_FLAG);
107}
108
109/** Start the virtual timer. */
110static void timer_start(void)
111{
112 uint64_t cntfrq = CNTFRQ_EL0_read();
113 uint64_t cntvct = CNTVCT_EL0_read();
114 uint64_t cntv_ctl = CNTV_CTL_EL0_read();
115
116 /* Calculate the increment. */
117 timer_increment = cntfrq / HZ;
118
119 /* Program the timer. */
120 CNTV_CVAL_EL0_write(cntvct + timer_increment);
121 CNTV_CTL_EL0_write(
122 (cntv_ctl & ~CNTV_CTL_IMASK_FLAG) | CNTV_CTL_ENABLE_FLAG);
123}
124
125/** Claim the virtual timer interrupt. */
126static irq_ownership_t timer_claim(irq_t *irq)
127{
128 return IRQ_ACCEPT;
129}
130
131/** Handle the virtual timer interrupt. */
132static void timer_irq_handler(irq_t *irq)
133{
134 uint64_t cntvct = CNTVCT_EL0_read();
135 uint64_t cntv_cval = CNTV_CVAL_EL0_read();
136
137 uint64_t drift = cntvct - cntv_cval;
138 while (drift > timer_increment) {
139 drift -= timer_increment;
140 CPU->missed_clock_ticks++;
141 }
142 CNTV_CVAL_EL0_write(cntvct + timer_increment - drift);
143
144 /*
145 * We are holding a lock which prevents preemption.
146 * Release the lock, call clock() and reacquire the lock again.
147 */
148 irq_spinlock_unlock(&irq->lock, false);
149 clock();
150 irq_spinlock_lock(&irq->lock, false);
151}
152
153/** Initialize basic tables for exception dispatching. */
154void interrupt_init(void)
155{
156 size_t irq_count = machine_get_irq_count();
157 irq_init(irq_count, irq_count);
158
159 /* Initialize virtual timer. */
160 timer_suspend();
161 inr_t timer_inr = machine_enable_vtimer_irq();
162
163 irq_initialize(&timer_irq);
164 timer_irq.inr = timer_inr;
165 timer_irq.claim = timer_claim;
166 timer_irq.handler = timer_irq_handler;
167 irq_register(&timer_irq);
168
169 timer_start();
170}
171
172/** @}
173 */
Note: See TracBrowser for help on using the repository browser.