source: mainline/kernel/arch/arm64/include/arch/mm/page.h@ 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: 13.3 KB
Line 
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_mm
30 * @{
31 */
32/** @file
33 * @brief Paging related declarations.
34 */
35
36#ifndef KERN_arm64_PAGE_H_
37#define KERN_arm64_PAGE_H_
38
39#include <arch/mm/frame.h>
40#include <mm/mm.h>
41#include <trace.h>
42
43#ifndef __ASSEMBLER__
44#include <typedefs.h>
45#endif /* __ASSEMBLER__ */
46
47#define PAGE_WIDTH FRAME_WIDTH
48#define PAGE_SIZE FRAME_SIZE
49
50#ifndef __ASSEMBLER__
51
52extern uintptr_t physmem_base;
53
54#define KA2PA(x) \
55 (((uintptr_t) (x)) - UINT64_C(0xffffffff80000000) + physmem_base)
56#define PA2KA(x) \
57 (((uintptr_t) (x)) + UINT64_C(0xffffffff80000000) - physmem_base)
58
59#endif /* __ASSEMBLER__ */
60
61/** Log2 size of each translation table entry. */
62#define PTL_ENTRY_SIZE_SHIFT 3
63
64/* Number of entries in each level. */
65#define PTL0_ENTRIES_ARCH 512
66#define PTL1_ENTRIES_ARCH 512
67#define PTL2_ENTRIES_ARCH 512
68#define PTL3_ENTRIES_ARCH 512
69
70/* Page table sizes for each level. */
71#define PTL0_FRAMES_ARCH 1
72#define PTL1_FRAMES_ARCH 1
73#define PTL2_FRAMES_ARCH 1
74#define PTL3_FRAMES_ARCH 1
75
76/* Starting bit of virtual address portion translated in each level. */
77#define PTL0_VA_SHIFT 39
78#define PTL1_VA_SHIFT 30
79#define PTL2_VA_SHIFT 21
80#define PTL3_VA_SHIFT 12
81
82/* Size mask of virtual address portion translated in each level. */
83#define PTL0_VA_MASK 0x1ff
84#define PTL1_VA_MASK 0x1ff
85#define PTL2_VA_MASK 0x1ff
86#define PTL3_VA_MASK 0x1ff
87
88/* Macros calculating indices into page tables for each level. */
89#define PTL0_INDEX_ARCH(vaddr) (((vaddr) >> PTL0_VA_SHIFT) & PTL0_VA_MASK)
90#define PTL1_INDEX_ARCH(vaddr) (((vaddr) >> PTL1_VA_SHIFT) & PTL1_VA_MASK)
91#define PTL2_INDEX_ARCH(vaddr) (((vaddr) >> PTL2_VA_SHIFT) & PTL2_VA_MASK)
92#define PTL3_INDEX_ARCH(vaddr) (((vaddr) >> PTL3_VA_SHIFT) & PTL3_VA_MASK)
93
94/* Get PTE address accessors for each level. */
95#define GET_PTL1_ADDRESS_ARCH(ptl0, i) \
96 ((pte_t *) (((uintptr_t) ((pte_t *) (ptl0))[(i)].output_address) << 12))
97#define GET_PTL2_ADDRESS_ARCH(ptl1, i) \
98 ((pte_t *) (((uintptr_t) ((pte_t *) (ptl1))[(i)].output_address) << 12))
99#define GET_PTL3_ADDRESS_ARCH(ptl2, i) \
100 ((pte_t *) (((uintptr_t) ((pte_t *) (ptl2))[(i)].output_address) << 12))
101#define GET_FRAME_ADDRESS_ARCH(ptl3, i) \
102 (((uintptr_t) ((pte_t *) (ptl3))[(i)].output_address) << 12)
103
104/*
105 * Set PTE address accessors for each level. Setting of the level 0 table is
106 * ignored because it must be done only by calling as_install_arch() which also
107 * changes ASID.
108 */
109#define SET_PTL0_ADDRESS_ARCH(ptl0)
110#define SET_PTL1_ADDRESS_ARCH(ptl0, i, a) \
111 (((pte_t *) (ptl0))[(i)].output_address = (a) >> 12)
112#define SET_PTL2_ADDRESS_ARCH(ptl1, i, a) \
113 (((pte_t *) (ptl1))[(i)].output_address = (a) >> 12)
114#define SET_PTL3_ADDRESS_ARCH(ptl2, i, a) \
115 (((pte_t *) (ptl2))[(i)].output_address = (a) >> 12)
116#define SET_FRAME_ADDRESS_ARCH(ptl3, i, a) \
117 (((pte_t *) (ptl3))[(i)].output_address = (a) >> 12)
118
119/* Get PTE flags accessors for each level. */
120#define GET_PTL1_FLAGS_ARCH(ptl0, i) \
121 get_pt_level012_flags((pte_t *) (ptl0), (size_t) (i))
122#define GET_PTL2_FLAGS_ARCH(ptl1, i) \
123 get_pt_level012_flags((pte_t *) (ptl1), (size_t) (i))
124#define GET_PTL3_FLAGS_ARCH(ptl2, i) \
125 get_pt_level012_flags((pte_t *) (ptl2), (size_t) (i))
126#define GET_FRAME_FLAGS_ARCH(ptl3, i) \
127 get_pt_level3_flags((pte_t *) (ptl3), (size_t) (i))
128
129/* Set PTE flags accessors for each level. */
130#define SET_PTL1_FLAGS_ARCH(ptl0, i, x) \
131 set_pt_level012_flags((pte_t *) (ptl0), (size_t) (i), (x))
132#define SET_PTL2_FLAGS_ARCH(ptl1, i, x) \
133 set_pt_level012_flags((pte_t *) (ptl1), (size_t) (i), (x))
134#define SET_PTL3_FLAGS_ARCH(ptl2, i, x) \
135 set_pt_level012_flags((pte_t *) (ptl2), (size_t) (i), (x))
136#define SET_FRAME_FLAGS_ARCH(ptl3, i, x) \
137 set_pt_level3_flags((pte_t *) (ptl3), (size_t) (i), (x))
138
139/* Set PTE present bit accessors for each level. */
140#define SET_PTL1_PRESENT_ARCH(ptl0, i) \
141 set_pt_present((pte_t *) (ptl0), (size_t) (i))
142#define SET_PTL2_PRESENT_ARCH(ptl1, i) \
143 set_pt_present((pte_t *) (ptl1), (size_t) (i))
144#define SET_PTL3_PRESENT_ARCH(ptl2, i) \
145 set_pt_present((pte_t *) (ptl2), (size_t) (i))
146#define SET_FRAME_PRESENT_ARCH(ptl3, i) \
147 set_pt_present((pte_t *) (ptl3), (size_t) (i))
148
149/* Macros for querying the last-level PTE entries. */
150#define PTE_VALID_ARCH(pte) \
151 (((pte_t *) (pte))->valid != 0)
152#define PTE_PRESENT_ARCH(pte) \
153 (((pte_t *) (pte))->valid != 0)
154#define PTE_GET_FRAME_ARCH(pte) \
155 (((uintptr_t) ((pte_t *) (pte))->output_address) << FRAME_WIDTH)
156#define PTE_WRITABLE_ARCH(pte) \
157 get_pt_writable((pte_t *) (pte))
158#define PTE_EXECUTABLE_ARCH(pte) \
159 get_pt_executable((pte_t *) (pte))
160
161/* Level 3 access permissions. */
162
163/** Data access permission. User mode: no access, privileged mode: read/write.
164 */
165#define PTE_AP_USER_NO_KERNEL_FULL 0
166
167/** Data access permission. User mode: read/write, privileged mode: read/write.
168 */
169#define PTE_AP_USER_FULL_KERNEL_FULL 1
170
171/** Data access permission. User mode: no access, privileged mode: read only. */
172#define PTE_AP_USER_NO_KERNEL_LIMITED 2
173
174/** Data access permission. User mode: read only, privileged mode: read only. */
175#define PTE_AP_USER_LIMITED_KERNEL_LIMITED 3
176
177/*
178 * Memory types. MAIR_EL1 index 0 is unused, which assures that if a page
179 * table entry is non-null then it is valid (PTE_VALID_ARCH() returns true).
180 */
181
182/** Write-Back Cacheable Normal memory, Inner shareable, Read-write cache
183 * allocation. Defined in MAIR_EL1 index 1.
184 */
185#define MAIR_EL1_NORMAL_MEMORY_ATTR 0xff
186#define MAIR_EL1_NORMAL_MEMORY_INDEX 1
187
188/** Device-nGnRE memory (Device non-Gathering, non-Reordering, Early Write
189 * Acknowledgement). Equivalent to the Device memory type in earlier versions of
190 * the architecture. Defined in MAIR_EL1 index 2.
191 */
192#define MAIR_EL1_DEVICE_MEMORY_ATTR 0x04
193#define MAIR_EL1_DEVICE_MEMORY_INDEX 2
194
195/** Bit width of one memory attribute field in MAIR_EL1. */
196#define MAIR_EL1_ATTR_SHIFT 8
197
198/* Level 0, 1, 2 descriptor types. */
199
200/** Block descriptor (valid in level 0, 1, 2 page translation tables). */
201#define PTE_L012_TYPE_BLOCK 0
202
203/** Next-table descriptor (valid in level 0, 1, 2 page translation tables). */
204#define PTE_L012_TYPE_TABLE 1
205
206/* Level 3 descriptor types. */
207
208/** Page descriptor (valid in level 3 page translation tables). */
209#define PTE_L3_TYPE_PAGE 1
210
211/** HelenOS descriptor type. Table for level 0, 1, 2 page translation tables,
212 * page for level 3 tables. Block descriptors are not used by HelenOS during
213 * normal processing.
214 */
215#define PTE_L0123_TYPE_HELENOS 1
216
217/* Page table entry access macros. */
218
219/** Shift to access the next-level table address in a page table entry. */
220#define PTE_NEXT_LEVEL_ADDRESS_SHIFT 12
221
222/** Shift to access the resulting address in a page table entry. */
223#define PTE_OUTPUT_ADDRESS_SHIFT 12
224
225/** Shift to access the access bit in a page table entry. */
226#define PTE_ACCESS_SHIFT 10
227
228/** Shift to access the attr_index field in a page table entry. */
229#define PTE_ATTR_INDEX_SHIFT 2
230
231/** Shift to access the type bit in a page table entry. */
232#define PTE_TYPE_SHIFT 1
233
234/** Shift to access the present bit in a page table entry. */
235#define PTE_PRESENT_SHIFT 0
236
237/** The present bit in a page table entry. */
238#define PTE_PRESENT_FLAG (1 << PTE_PRESENT_SHIFT)
239
240#ifndef __ASSEMBLER__
241
242#include <arch/interrupt.h>
243
244/** Page Table Entry.
245 *
246 * HelenOS model:
247 * * Level 0, 1, 2 translation tables hold next-level table descriptors. Block
248 * descriptors are not used during normal processing.
249 * * Level 3 tables store 4kB page descriptors.
250 */
251typedef struct {
252 /* Common bits. */
253 /** Flag indicating entry contains valid data and can be used for page
254 * translation.
255 *
256 * Note: The flag is called `valid' in the official ARM terminology
257 * but it has the `present' (valid+active) sense in HelenOS.
258 */
259 unsigned valid : 1;
260 unsigned type : 1;
261
262 /* Lower block and page attributes. */
263 unsigned attr_index : 3;
264 unsigned non_secure : 1;
265 unsigned access_permission : 2;
266 unsigned shareability : 2;
267 unsigned access : 1;
268 unsigned not_global : 1;
269
270 /* Common output address. */
271 uint64_t output_address : 36;
272
273 unsigned : 4;
274
275 /* Upper block and page attributes. */
276 unsigned contiguous : 1;
277 unsigned privileged_execute_never : 1;
278 unsigned unprivileged_execute_never : 1;
279
280 unsigned : 4;
281
282 /* Next-level table attributes. */
283 unsigned privileged_execute_never_table : 1;
284 unsigned unprivileged_execute_never_table : 1;
285 unsigned access_permission_table : 2;
286 unsigned non_secure_table : 1;
287} __attribute__((packed)) pte_t;
288
289/** Returns level 0, 1, 2 page table entry flags.
290 *
291 * @param pt Level 0, 1, 2 page table.
292 * @param i Index of the entry to return.
293 */
294_NO_TRACE static inline unsigned int get_pt_level012_flags(pte_t *pt, size_t i)
295{
296 pte_t *p = &pt[i];
297
298 return (1 << PAGE_CACHEABLE_SHIFT) |
299 (!p->valid << PAGE_PRESENT_SHIFT) | (1 << PAGE_USER_SHIFT) |
300 (1 << PAGE_READ_SHIFT) | (1 << PAGE_WRITE_SHIFT) |
301 (1 << PAGE_EXEC_SHIFT);
302}
303
304/** Returns level 3 page table entry flags.
305 *
306 * @param pt Level 3 page table.
307 * @param i Index of the entry to return.
308 */
309_NO_TRACE static inline unsigned int get_pt_level3_flags(pte_t *pt, size_t i)
310{
311 pte_t *p = &pt[i];
312
313 int cacheable = (p->attr_index == MAIR_EL1_NORMAL_MEMORY_INDEX);
314 int user = (p->access_permission == PTE_AP_USER_FULL_KERNEL_FULL ||
315 p->access_permission == PTE_AP_USER_LIMITED_KERNEL_LIMITED);
316 int write = (p->access_permission == PTE_AP_USER_FULL_KERNEL_FULL ||
317 p->access_permission == PTE_AP_USER_NO_KERNEL_FULL);
318 int exec = ((user && !p->unprivileged_execute_never) ||
319 (!user && !p->privileged_execute_never));
320
321 return (cacheable << PAGE_CACHEABLE_SHIFT) |
322 (!p->valid << PAGE_PRESENT_SHIFT) | (user << PAGE_USER_SHIFT) |
323 (1 << PAGE_READ_SHIFT) | (write << PAGE_WRITE_SHIFT) |
324 (exec << PAGE_EXEC_SHIFT) | (!p->not_global << PAGE_GLOBAL_SHIFT);
325}
326
327/** Sets flags of level 0, 1, 2 page table entry.
328 *
329 * @param pt Level 0, 1, 2 page table.
330 * @param i Index of the entry to be changed.
331 * @param flags New flags.
332 */
333_NO_TRACE static inline void set_pt_level012_flags(pte_t *pt, size_t i,
334 int flags)
335{
336 pte_t *p = &pt[i];
337
338 p->valid = (flags & PAGE_PRESENT) != 0;
339 p->type = PTE_L012_TYPE_TABLE;
340}
341
342/** Sets flags of level 3 page table entry.
343 *
344 * @param pt Level 3 page table.
345 * @param i Index of the entry to be changed.
346 * @param flags New flags.
347 */
348_NO_TRACE static inline void set_pt_level3_flags(pte_t *pt, size_t i,
349 int flags)
350{
351 pte_t *p = &pt[i];
352
353 if (flags & PAGE_CACHEABLE)
354 p->attr_index = MAIR_EL1_NORMAL_MEMORY_INDEX;
355 else
356 p->attr_index = MAIR_EL1_DEVICE_MEMORY_INDEX;
357 p->valid = (flags & PAGE_PRESENT) != 0;
358 p->type = PTE_L3_TYPE_PAGE;
359
360 /* Translate page permissions to access permissions. */
361 if (flags & PAGE_USER) {
362 if (flags & PAGE_WRITE)
363 p->access_permission = PTE_AP_USER_FULL_KERNEL_FULL;
364 else
365 p->access_permission =
366 PTE_AP_USER_LIMITED_KERNEL_LIMITED;
367 } else {
368 if (flags & PAGE_WRITE)
369 p->access_permission = PTE_AP_USER_NO_KERNEL_FULL;
370 else
371 p->access_permission = PTE_AP_USER_NO_KERNEL_LIMITED;
372 }
373 p->access = 1;
374 p->unprivileged_execute_never = p->privileged_execute_never =
375 (flags & PAGE_EXEC) == 0;
376
377 p->not_global = (flags & PAGE_GLOBAL) == 0;
378}
379
380/** Sets the present flag of page table entry.
381 *
382 * @param pt Level 0, 1, 2, 3 page table.
383 * @param i Index of the entry to be changed.
384 */
385_NO_TRACE static inline void set_pt_present(pte_t *pt, size_t i)
386{
387 pte_t *p = &pt[i];
388
389 p->valid = 1;
390}
391
392/** Gets the executable flag of page table entry.
393 *
394 * @param pte Page table entry.
395 */
396_NO_TRACE static inline bool get_pt_executable(pte_t *pte)
397{
398 if (pte->access_permission == PTE_AP_USER_NO_KERNEL_FULL ||
399 pte->access_permission == PTE_AP_USER_NO_KERNEL_LIMITED)
400 return pte->privileged_execute_never;
401 else
402 return pte->unprivileged_execute_never;
403}
404
405/** Gets the writable flag of page table entry.
406 *
407 * @param pte Page table entry.
408 */
409_NO_TRACE static inline bool get_pt_writable(pte_t *pte)
410{
411 return pte->access_permission == PTE_AP_USER_FULL_KERNEL_FULL ||
412 pte->access_permission == PTE_AP_USER_NO_KERNEL_FULL;
413}
414
415extern void page_arch_init(void);
416
417#endif /* __ASSEMBLER__ */
418
419#endif
420
421/** @}
422 */
Note: See TracBrowser for help on using the repository browser.