Rev 2128 | Rev 2467 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 2128 | Rev 2465 | ||
|---|---|---|---|
| Line 1... | Line 1... | ||
| 1 | /* |
1 | /* |
| 2 | * Copyright (c) 2003-2007 Jakub Jermar |
2 | * Copyright (c) 2007 Pavel Jancik, Michal Kebrt |
| 3 | * All rights reserved. |
3 | * All rights reserved. |
| 4 | * |
4 | * |
| 5 | * Redistribution and use in source and binary forms, with or without |
5 | * Redistribution and use in source and binary forms, with or without |
| 6 | * modification, are permitted provided that the following conditions |
6 | * modification, are permitted provided that the following conditions |
| 7 | * are met: |
7 | * are met: |
| Line 28... | Line 28... | ||
| 28 | 28 | ||
| 29 | /** @addtogroup arm32mm |
29 | /** @addtogroup arm32mm |
| 30 | * @{ |
30 | * @{ |
| 31 | */ |
31 | */ |
| 32 | /** @file |
32 | /** @file |
| - | 33 | * @brief Paging related declarations. |
|
| 33 | */ |
34 | */ |
| 34 | 35 | ||
| 35 | #ifndef KERN_arm32_PAGE_H_ |
36 | #ifndef KERN_arm32_PAGE_H_ |
| 36 | #define KERN_arm32_PAGE_H_ |
37 | #define KERN_arm32_PAGE_H_ |
| 37 | 38 | ||
| 38 | #include <arch/mm/frame.h> |
39 | #include <arch/mm/frame.h> |
| - | 40 | #include <mm/mm.h> |
|
| - | 41 | #include <arch/exception.h> |
|
| 39 | 42 | ||
| 40 | #define PAGE_WIDTH FRAME_WIDTH |
43 | #define PAGE_WIDTH FRAME_WIDTH |
| 41 | #define PAGE_SIZE FRAME_SIZE |
44 | #define PAGE_SIZE FRAME_SIZE |
| 42 | 45 | ||
| 43 | #define PAGE_COLOR_BITS 0 /* dummy */ |
46 | #define PAGE_COLOR_BITS 0 /* dummy */ |
| Line 50... | Line 53... | ||
| 50 | # define PA2KA(x) ((x) + 0x80000000) |
53 | # define PA2KA(x) ((x) + 0x80000000) |
| 51 | #endif |
54 | #endif |
| 52 | 55 | ||
| 53 | #ifdef KERNEL |
56 | #ifdef KERNEL |
| 54 | 57 | ||
| 55 | #define PTL0_ENTRIES_ARCH 0 /* TODO */ |
58 | #define PTL0_ENTRIES_ARCH (2 << 12) /* 4096 */ |
| 56 | #define PTL1_ENTRIES_ARCH 0 /* TODO */ |
59 | #define PTL1_ENTRIES_ARCH 0 |
| 57 | #define PTL2_ENTRIES_ARCH 0 /* TODO */ |
60 | #define PTL2_ENTRIES_ARCH 0 |
| - | 61 | ||
| - | 62 | /* coarse page tables used (256 * 4 = 1KB per page) */ |
|
| 58 | #define PTL3_ENTRIES_ARCH 0 /* TODO */ |
63 | #define PTL3_ENTRIES_ARCH (2 << 8) /* 256 */ |
| 59 | 64 | ||
| 60 | #define PTL0_INDEX_ARCH(vaddr) 0 /* TODO */ |
65 | #define PTL0_SIZE_ARCH FOUR_FRAMES |
| 61 | #define PTL1_INDEX_ARCH(vaddr) 0 /* TODO */ |
66 | #define PTL1_SIZE_ARCH 0 |
| 62 | #define PTL2_INDEX_ARCH(vaddr) 0 /* TODO */ |
67 | #define PTL2_SIZE_ARCH 0 |
| 63 | #define PTL3_INDEX_ARCH(vaddr) 0 /* TODO */ |
68 | #define PTL3_SIZE_ARCH ONE_FRAME |
| 64 | 69 | ||
| - | 70 | #define PTL0_INDEX_ARCH(vaddr) (((vaddr) >> 20) & 0xfff) |
|
| - | 71 | #define PTL1_INDEX_ARCH(vaddr) 0 |
|
| 65 | #define SET_PTL0_ADDRESS_ARCH(ptl0) |
72 | #define PTL2_INDEX_ARCH(vaddr) 0 |
| - | 73 | #define PTL3_INDEX_ARCH(vaddr) (((vaddr) >> 12) & 0x0ff) |
|
| 66 | 74 | ||
| 67 | #define GET_PTL1_ADDRESS_ARCH(ptl0, i) 0 /* TODO */ |
75 | #define GET_PTL1_ADDRESS_ARCH(ptl0, i) \ |
| - | 76 | ((pte_t *) ((((pte_level0_t *)(ptl0))[(i)]).coarse_table_addr << 10)) |
|
| 68 | #define GET_PTL2_ADDRESS_ARCH(ptl1, i) 0 /* TODO */ |
77 | #define GET_PTL2_ADDRESS_ARCH(ptl1, i) \ |
| - | 78 | (ptl1) |
|
| 69 | #define GET_PTL3_ADDRESS_ARCH(ptl2, i) 0 /* TODO */ |
79 | #define GET_PTL3_ADDRESS_ARCH(ptl2, i) \ |
| - | 80 | (ptl2) |
|
| 70 | #define GET_FRAME_ADDRESS_ARCH(ptl3, i) 0 /* TODO */ |
81 | #define GET_FRAME_ADDRESS_ARCH(ptl3, i) \ |
| - | 82 | ((uintptr_t) ((((pte_level1_t *)(ptl3))[(i)]).frame_base_addr << 12)) |
|
| 71 | 83 | ||
| - | 84 | #define SET_PTL0_ADDRESS_ARCH(ptl0) \ |
|
| - | 85 | (set_ptl0_addr((pte_level0_t *) (ptl0))) |
|
| 72 | #define SET_PTL1_ADDRESS_ARCH(ptl0, i, a) /* TODO */ |
86 | #define SET_PTL1_ADDRESS_ARCH(ptl0, i, a) \ |
| - | 87 | (((pte_level0_t *) (ptl0))[(i)].coarse_table_addr = (a) >> 10) |
|
| 73 | #define SET_PTL2_ADDRESS_ARCH(ptl1, i, a) /* TODO */ |
88 | #define SET_PTL2_ADDRESS_ARCH(ptl1, i, a) |
| 74 | #define SET_PTL3_ADDRESS_ARCH(ptl2, i, a) /* TODO */ |
89 | #define SET_PTL3_ADDRESS_ARCH(ptl2, i, a) |
| 75 | #define SET_FRAME_ADDRESS_ARCH(ptl3, i, a) /* TODO */ |
90 | #define SET_FRAME_ADDRESS_ARCH(ptl3, i, a) \ |
| - | 91 | (((pte_level1_t *) (ptl3))[(i)].frame_base_addr = (a) >> 12) |
|
| 76 | 92 | ||
| 77 | #define GET_PTL1_FLAGS_ARCH(ptl0, i) 0 /* TODO */ |
93 | #define GET_PTL1_FLAGS_ARCH(ptl0, i) \ |
| - | 94 | get_pt_level0_flags((pte_level0_t *) (ptl0), (index_t) (i)) |
|
| 78 | #define GET_PTL2_FLAGS_ARCH(ptl1, i) 0 /* TODO */ |
95 | #define GET_PTL2_FLAGS_ARCH(ptl1, i) \ |
| - | 96 | PAGE_PRESENT |
|
| 79 | #define GET_PTL3_FLAGS_ARCH(ptl2, i) 0 /* TODO */ |
97 | #define GET_PTL3_FLAGS_ARCH(ptl2, i) \ |
| - | 98 | PAGE_PRESENT |
|
| 80 | #define GET_FRAME_FLAGS_ARCH(ptl3, i) 0 /* TODO */ |
99 | #define GET_FRAME_FLAGS_ARCH(ptl3, i) \ |
| - | 100 | get_pt_level1_flags((pte_level1_t *) (ptl3), (index_t) (i)) |
|
| 81 | 101 | ||
| 82 | #define SET_PTL1_FLAGS_ARCH(ptl0, i, x) /* TODO */ |
102 | #define SET_PTL1_FLAGS_ARCH(ptl0, i, x) \ |
| - | 103 | set_pt_level0_flags((pte_level0_t *) (ptl0), (index_t) (i), (x)) |
|
| 83 | #define SET_PTL2_FLAGS_ARCH(ptl1, i, x) /* TODO */ |
104 | #define SET_PTL2_FLAGS_ARCH(ptl1, i, x) |
| 84 | #define SET_PTL3_FLAGS_ARCH(ptl2, i, x) /* TODO */ |
105 | #define SET_PTL3_FLAGS_ARCH(ptl2, i, x) |
| 85 | #define SET_FRAME_FLAGS_ARCH(ptl3, i, x) /* TODO */ |
106 | #define SET_FRAME_FLAGS_ARCH(ptl3, i, x) \ |
| - | 107 | set_pt_level1_flags((pte_level1_t *) (ptl3), (index_t) (i), (x)) |
|
| 86 | 108 | ||
| 87 | #define PTE_VALID_ARCH(pte) 0 /* TODO */ |
109 | #define PTE_VALID_ARCH(pte) \ |
| - | 110 | (*((uint32_t *) (pte)) != 0) |
|
| 88 | #define PTE_PRESENT_ARCH(pte) 0 /* TODO */ |
111 | #define PTE_PRESENT_ARCH(pte) \ |
| - | 112 | (((pte_level0_t *) (pte))->descriptor_type != 0) |
|
| - | 113 | ||
| - | 114 | /* pte should point into ptl3 */ |
|
| 89 | #define PTE_GET_FRAME_ARCH(pte) 0 /* TODO */ |
115 | #define PTE_GET_FRAME_ARCH(pte) \ |
| - | 116 | (((pte_level1_t *) (pte))->frame_base_addr << FRAME_WIDTH) |
|
| - | 117 | ||
| - | 118 | /* pte should point into ptl3 */ |
|
| 90 | #define PTE_WRITABLE_ARCH(pte) 0 /* TODO */ |
119 | #define PTE_WRITABLE_ARCH(pte) \ |
| - | 120 | (((pte_level1_t *) (pte))->access_permission_0 == \ |
|
| - | 121 | PTE_AP_USER_RW_KERNEL_RW) |
|
| - | 122 | ||
| 91 | #define PTE_EXECUTABLE_ARCH(pte) 0 /* TODO */ |
123 | #define PTE_EXECUTABLE_ARCH(pte) \ |
| - | 124 | 1 |
|
| 92 | 125 | ||
| 93 | #ifndef __ASM__ |
126 | #ifndef __ASM__ |
| 94 | 127 | ||
| - | 128 | /** Level 0 page table entry. */ |
|
| 95 | #include <mm/mm.h> |
129 | typedef struct { |
| - | 130 | /* 0b01 for coarse tables, see below for details */ |
|
| - | 131 | unsigned descriptor_type : 2; |
|
| - | 132 | unsigned impl_specific : 3; |
|
| - | 133 | unsigned domain : 4; |
|
| - | 134 | unsigned should_be_zero : 1; |
|
| - | 135 | ||
| - | 136 | /* Pointer to the coarse 2nd level page table (holding entries for small |
|
| - | 137 | * (4KB) or large (64KB) pages. ARM also supports fine 2nd level page |
|
| - | 138 | * tables that may hold even tiny pages (1KB) but they are bigger (4KB |
|
| - | 139 | * per table in comparison with 1KB per the coarse table) |
|
| - | 140 | */ |
|
| - | 141 | unsigned coarse_table_addr : 22; |
|
| - | 142 | } ATTRIBUTE_PACKED pte_level0_t; |
|
| - | 143 | ||
| - | 144 | /** Level 1 page table entry (small (4KB) pages used). */ |
|
| - | 145 | typedef struct { |
|
| - | 146 | ||
| - | 147 | /* 0b10 for small pages */ |
|
| - | 148 | unsigned descriptor_type : 2; |
|
| - | 149 | unsigned bufferable : 1; |
|
| - | 150 | unsigned cacheable : 1; |
|
| - | 151 | ||
| - | 152 | /* access permissions for each of 4 subparts of a page |
|
| - | 153 | * (for each 1KB when small pages used */ |
|
| - | 154 | unsigned access_permission_0 : 2; |
|
| - | 155 | unsigned access_permission_1 : 2; |
|
| - | 156 | unsigned access_permission_2 : 2; |
|
| 96 | #include <arch/exception.h> |
157 | unsigned access_permission_3 : 2; |
| - | 158 | unsigned frame_base_addr : 20; |
|
| - | 159 | } ATTRIBUTE_PACKED pte_level1_t; |
|
| - | 160 | ||
| - | 161 | ||
| - | 162 | /* Level 1 page tables access permissions */ |
|
| - | 163 | ||
| - | 164 | /** User mode: no access, privileged mode: no access. */ |
|
| - | 165 | #define PTE_AP_USER_NO_KERNEL_NO 0 |
|
| - | 166 | ||
| - | 167 | /** User mode: no access, privileged mode: read/write. */ |
|
| - | 168 | #define PTE_AP_USER_NO_KERNEL_RW 1 |
|
| - | 169 | ||
| - | 170 | /** User mode: read only, privileged mode: read/write. */ |
|
| - | 171 | #define PTE_AP_USER_RO_KERNEL_RW 2 |
|
| - | 172 | ||
| - | 173 | /** User mode: read/write, privileged mode: read/write. */ |
|
| - | 174 | #define PTE_AP_USER_RW_KERNEL_RW 3 |
|
| - | 175 | ||
| - | 176 | ||
| - | 177 | /* pte_level0_t and pte_level1_t descriptor_type flags */ |
|
| - | 178 | ||
| - | 179 | /** pte_level0_t and pte_level1_t "not present" flag (used in descriptor_type). */ |
|
| - | 180 | #define PTE_DESCRIPTOR_NOT_PRESENT 0 |
|
| - | 181 | ||
| - | 182 | /** pte_level0_t coarse page table flag (used in descriptor_type). */ |
|
| - | 183 | #define PTE_DESCRIPTOR_COARSE_TABLE 1 |
|
| - | 184 | ||
| - | 185 | /** pte_level1_t small page table flag (used in descriptor type). */ |
|
| - | 186 | #define PTE_DESCRIPTOR_SMALL_PAGE 2 |
|
| - | 187 | ||
| - | 188 | ||
| - | 189 | /** Sets the address of level 0 page table. |
|
| - | 190 | * |
|
| - | 191 | * @param pt Pointer to the page table to set. |
|
| - | 192 | */ |
|
| - | 193 | static inline void set_ptl0_addr( pte_level0_t *pt) |
|
| - | 194 | { |
|
| - | 195 | asm volatile ( |
|
| - | 196 | "mcr p15, 0, %0, c2, c0, 0 \n" |
|
| - | 197 | : |
|
| - | 198 | : "r"(pt) |
|
| - | 199 | ); |
|
| - | 200 | } |
|
| - | 201 | ||
| - | 202 | ||
| - | 203 | /** Returns level 0 page table entry flags. |
|
| - | 204 | * |
|
| - | 205 | * @param pt Level 0 page table. |
|
| - | 206 | * @param i Index of the entry to return. |
|
| - | 207 | */ |
|
| - | 208 | static inline int get_pt_level0_flags(pte_level0_t *pt, index_t i) |
|
| - | 209 | { |
|
| - | 210 | pte_level0_t *p = &pt[i]; |
|
| - | 211 | int np = (p->descriptor_type == PTE_DESCRIPTOR_NOT_PRESENT); |
|
| - | 212 | ||
| - | 213 | return (np << PAGE_PRESENT_SHIFT) | (1 << PAGE_USER_SHIFT) | |
|
| - | 214 | (1 << PAGE_READ_SHIFT) | (1 << PAGE_WRITE_SHIFT) | |
|
| - | 215 | (1 << PAGE_EXEC_SHIFT) | (1 << PAGE_CACHEABLE_SHIFT); |
|
| - | 216 | } |
|
| - | 217 | ||
| - | 218 | /** Returns level 1 page table entry flags. |
|
| - | 219 | * |
|
| - | 220 | * @param pt Level 1 page table. |
|
| - | 221 | * @param i Index of the entry to return. |
|
| - | 222 | */ |
|
| - | 223 | static inline int get_pt_level1_flags(pte_level1_t *pt, index_t i) |
|
| - | 224 | { |
|
| - | 225 | pte_level1_t *p = &pt[i]; |
|
| 97 | 226 | ||
| - | 227 | int dt = p->descriptor_type; |
|
| - | 228 | int ap = p->access_permission_0; |
|
| - | 229 | ||
| - | 230 | return ((dt == PTE_DESCRIPTOR_NOT_PRESENT) << PAGE_PRESENT_SHIFT) | |
|
| - | 231 | ((ap == PTE_AP_USER_RO_KERNEL_RW) << PAGE_READ_SHIFT) | |
|
| - | 232 | ((ap == PTE_AP_USER_RW_KERNEL_RW) << PAGE_READ_SHIFT) | |
|
| - | 233 | ((ap == PTE_AP_USER_RW_KERNEL_RW) << PAGE_WRITE_SHIFT) | |
|
| - | 234 | ((ap != PTE_AP_USER_NO_KERNEL_RW) << PAGE_USER_SHIFT) | |
|
| - | 235 | ((ap == PTE_AP_USER_NO_KERNEL_RW) << PAGE_READ_SHIFT) | |
|
| - | 236 | ((ap == PTE_AP_USER_NO_KERNEL_RW) << PAGE_WRITE_SHIFT) | |
|
| - | 237 | (1 << PAGE_EXEC_SHIFT) | |
|
| - | 238 | (p->bufferable << PAGE_CACHEABLE); |
|
| - | 239 | } |
|
| - | 240 | ||
| - | 241 | ||
| - | 242 | /** Sets flags of level 0 page table entry. |
|
| - | 243 | * |
|
| - | 244 | * @param pt level 0 page table |
|
| - | 245 | * @param i index of the entry to be changed |
|
| - | 246 | * @param flags new flags |
|
| - | 247 | */ |
|
| 98 | static inline int get_pt_flags(pte_t *pt, index_t i) |
248 | static inline void set_pt_level0_flags(pte_level0_t *pt, index_t i, int flags) |
| 99 | { |
249 | { |
| 100 | return 0; /* TODO */ |
250 | pte_level0_t *p = &pt[i]; |
| - | 251 | ||
| - | 252 | if (flags & PAGE_NOT_PRESENT) { |
|
| - | 253 | p->descriptor_type = PTE_DESCRIPTOR_NOT_PRESENT; |
|
| - | 254 | /* |
|
| - | 255 | * Ensures that the entry will be recognized as valid when |
|
| - | 256 | * PTE_VALID_ARCH applied. |
|
| - | 257 | */ |
|
| - | 258 | p->should_be_zero = 1; |
|
| - | 259 | } else { |
|
| - | 260 | p->descriptor_type = PTE_DESCRIPTOR_COARSE_TABLE; |
|
| - | 261 | p->should_be_zero = 0; |
|
| - | 262 | } |
|
| 101 | } |
263 | } |
| 102 | 264 | ||
| - | 265 | ||
| - | 266 | /** Sets flags of level 1 page table entry. |
|
| - | 267 | * |
|
| - | 268 | * We use same access rights for the whole page. When page is not preset we |
|
| - | 269 | * store 1 in acess_rigts_3 so that at least one bit is 1 (to mark correct |
|
| - | 270 | * page entry, see #PAGE_VALID_ARCH). |
|
| - | 271 | * |
|
| - | 272 | * @param pt Level 1 page table. |
|
| - | 273 | * @param i Index of the entry to be changed. |
|
| - | 274 | * @param flags New flags. |
|
| - | 275 | */ |
|
| 103 | static inline void set_pt_flags(pte_t *pt, index_t i, int flags) |
276 | static inline void set_pt_level1_flags(pte_level1_t *pt, index_t i, int flags) |
| 104 | { |
277 | { |
| - | 278 | pte_level1_t *p = &pt[i]; |
|
| - | 279 | ||
| - | 280 | if (flags & PAGE_NOT_PRESENT) { |
|
| - | 281 | p->descriptor_type = PTE_DESCRIPTOR_NOT_PRESENT; |
|
| - | 282 | p->access_permission_3 = 1; |
|
| 105 | /* TODO */ |
283 | } else { |
| - | 284 | p->descriptor_type = PTE_DESCRIPTOR_SMALL_PAGE; |
|
| - | 285 | p->access_permission_3 = p->access_permission_0; |
|
| - | 286 | } |
|
| - | 287 | ||
| - | 288 | p->cacheable = p->bufferable = (flags & PAGE_CACHEABLE) != 0; |
|
| - | 289 | ||
| - | 290 | /* default access permission */ |
|
| - | 291 | p->access_permission_0 = p->access_permission_1 = |
|
| - | 292 | p->access_permission_2 = p->access_permission_3 = |
|
| - | 293 | PTE_AP_USER_NO_KERNEL_RW; |
|
| - | 294 | ||
| - | 295 | if (flags & PAGE_USER) { |
|
| - | 296 | if (flags & PAGE_READ) { |
|
| - | 297 | p->access_permission_0 = p->access_permission_1 = |
|
| - | 298 | p->access_permission_2 = p->access_permission_3 = |
|
| - | 299 | PTE_AP_USER_RO_KERNEL_RW; |
|
| - | 300 | } |
|
| - | 301 | if (flags & PAGE_WRITE) { |
|
| - | 302 | p->access_permission_0 = p->access_permission_1 = |
|
| - | 303 | p->access_permission_2 = p->access_permission_3 = |
|
| - | 304 | PTE_AP_USER_RW_KERNEL_RW; |
|
| 106 | return; |
305 | } |
| - | 306 | } |
|
| 107 | } |
307 | } |
| 108 | 308 | ||
| - | 309 | ||
| 109 | extern void page_arch_init(void); |
310 | extern void page_arch_init(void); |
| 110 | 311 | ||
| - | 312 | ||
| 111 | #endif /* __ASM__ */ |
313 | #endif /* __ASM__ */ |
| 112 | 314 | ||
| 113 | #endif /* KERNEL */ |
315 | #endif /* KERNEL */ |
| 114 | 316 | ||
| 115 | #endif |
317 | #endif |