1/** 2 * \file 3 * \brief x86-32 kernel page-table structures. 4 */ 5 6/* 7 * Copyright (c) 2007, 2008, 2009, 2010, ETH Zurich. 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#ifndef KERNEL_TARGET_X86_32_PAGING_H 16#define KERNEL_TARGET_X86_32_PAGING_H 17 18#include <capabilities.h> 19#include <barrelfish_kpi/paging_arch.h> 20 21// Functions defined elsewhere. Move the declerations to appropriate includes 22int paging_x86_32_map_memory(lpaddr_t base, size_t size); 23lvaddr_t paging_x86_32_map_special(lpaddr_t base, size_t size, uint64_t bitmap); 24lvaddr_t paging_x86_32_map_device(lpaddr_t base, size_t size); 25 26#ifdef CONFIG_PAE 27void paging_x86_32_make_good_pdpte(lpaddr_t base); 28#else 29void paging_x86_32_make_good_pdir(lpaddr_t base); 30#endif 31 32void paging_x86_32_reset(void); 33 34/// All arch-specific flags valid to be set from user-space 35#define X86_32_PTABLE_FLAGS_MASK \ 36 (X86_32_PTABLE_GLOBAL_PAGE | X86_32_PTABLE_ATTR_INDEX | \ 37 X86_32_PTABLE_DIRTY | PTABLE_ACCESSED | \ 38 PTABLE_CACHE_DISABLED | PTABLE_WRITE_THROUGH) 39 40/// All flags valid for page access protection from user-space 41#define X86_32_PTABLE_ACCESS_MASK \ 42 (X86_32_PTABLE_EXECUTE_DISABLE | X86_32_PTABLE_USER_SUPERVISOR | \ 43 X86_32_PTABLE_READ_WRITE) 44 45/// Mask out all arch-specific flags except those valid from user-space 46#define X86_32_PTABLE_FLAGS(flags) (flags & X86_32_PTABLE_FLAGS_MASK) 47 48/// Mask out all flags except those for access protection 49#define X86_32_PTABLE_ACCESS(flags) (flags & X86_32_PTABLE_ACCESS_MASK) 50 51#ifdef CONFIG_PAE 52 53/** True if page entry is present in memory */ 54#define X86_32_IS_PRESENT(entry) \ 55 ((*(uint64_t *)(entry)) & X86_32_PTABLE_PRESENT) 56 57#else 58 59/** True if page entry is present in memory */ 60#define X86_32_IS_PRESENT(entry) \ 61 ((*(uint32_t *)(entry)) & X86_32_PTABLE_PRESENT) 62 63#endif 64 65#ifdef CONFIG_PAE 66 67union x86_32_pdpte_entry { 68 uint64_t raw; 69 struct { 70 uint64_t present :1; 71 uint64_t reserved0 :2; 72 uint64_t write_through :1; 73 uint64_t cache_disabled :1; 74 uint64_t reserved :4; 75 uint64_t ignored :3; 76 uint64_t base_addr :52; 77 } d; 78}; 79 80/** 81 * A page directory entry. 82 */ 83union x86_32_pdir_entry { 84 uint64_t raw; 85 struct { 86 uint64_t present :1; 87 uint64_t read_write :1; 88 uint64_t user_supervisor :1; 89 uint64_t write_through :1; 90 uint64_t cache_disabled :1; 91 uint64_t accessed :1; 92 uint64_t reserved :3; 93 uint64_t available :3; 94 uint64_t base_addr :28; 95 uint64_t reserved2 :12; // XXX: Part of base_addr 96 uint64_t reserved3 :11; 97 uint64_t execute_disable :1; 98 } d; 99}; 100 101/** 102 * A page table entry. 103 */ 104union x86_32_ptable_entry { 105 uint64_t raw; 106 struct { 107 uint64_t present :1; 108 uint64_t read_write :1; 109 uint64_t user_supervisor :1; 110 uint64_t write_through :1; 111 uint64_t cache_disabled :1; 112 uint64_t accessed :1; 113 uint64_t dirty :1; 114 uint64_t always1 :1; 115 uint64_t global :1; 116 uint64_t available :3; 117 uint64_t attr_index :1; 118 uint64_t reserved :8; 119 uint64_t base_addr :42; 120 uint64_t execute_disable :1; 121 } large; 122 struct { 123 uint64_t present :1; 124 uint64_t read_write :1; 125 uint64_t user_supervisor :1; 126 uint64_t write_through :1; 127 uint64_t cache_disabled :1; 128 uint64_t accessed :1; 129 uint64_t dirty :1; 130 uint64_t attr_index :1; 131 uint64_t global :1; 132 uint64_t reserved :3; 133 uint64_t base_addr :51; 134 uint64_t execute_disable :1; 135 } base; 136}; 137 138#else 139 140/** 141 * A page directory entry. 142 */ 143union x86_32_pdir_entry { 144 uint32_t raw; 145 struct { 146 uint32_t present :1; 147 uint32_t read_write :1; 148 uint32_t user_supervisor :1; 149 uint32_t write_through :1; 150 uint32_t cache_disabled :1; 151 uint32_t accessed :1; 152 uint32_t available :1; 153 uint32_t always0 :1; 154 uint32_t reserved :4; 155 uint32_t base_addr :20; 156 } d; 157}; 158 159/** 160 * A page table entry. 161 */ 162union x86_32_ptable_entry { 163 uint32_t raw; 164 struct { 165 uint32_t present :1; 166 uint32_t read_write :1; 167 uint32_t user_supervisor :1; 168 uint32_t write_through :1; 169 uint32_t cache_disabled :1; 170 uint32_t accessed :1; 171 uint32_t dirty :1; 172 uint32_t always1 :1; 173 uint32_t global :1; 174 uint32_t available :3; 175 uint32_t attr_index :1; 176 uint32_t reserved :9; 177 uint32_t base_addr :10; 178 } large; 179 struct { 180 uint32_t present :1; 181 uint32_t read_write :1; 182 uint32_t user_supervisor :1; 183 uint32_t write_through :1; 184 uint32_t cache_disabled :1; 185 uint32_t accessed :1; 186 uint32_t dirty :1; 187 uint32_t attr_index :1; 188 uint32_t global :1; 189 uint32_t available :3; 190 uint32_t base_addr :20; 191 } base; 192}; 193 194#endif 195 196/** 197 * \brief Clear page directory. 198 * 199 * Clears page directory pointed to by 'p'. 200 * 201 * \param p Pointer to page directory to clear. 202 */ 203static inline void paging_x86_32_clear_pdir(union x86_32_pdir_entry * COUNT(X86_32_PTABLE_SIZE) 204 NONNULL p) 205{ 206 for (int i = 0; i < X86_32_PTABLE_SIZE; i++) { 207 p[i].raw = X86_32_PTABLE_CLEAR; 208 } 209} 210 211/** 212 * \brief Clear page table. 213 * 214 * Clears page table pointed to by 'p'. 215 * 216 * \param p Pointer to page table to clear. 217 */ 218static inline void paging_x86_32_clear_ptable(union x86_32_ptable_entry * COUNT(X86_32_PTABLE_SIZE) 219 NONNULL p) 220{ 221 for (int i = 0; i < X86_32_PTABLE_SIZE; i++) { 222 p[i].raw = X86_32_PTABLE_CLEAR; 223 } 224} 225 226/** 227 * \brief Maps from page directory entry to page directory/table. 228 * 229 * Maps page directory or table, based at 'base', from page directory entry 230 * pointed to by 'entry'. 231 * 232 * \param entry Pointer to page directory entry to point from. 233 * \param base Base virtual address of page directory/table to point to. 234 */ 235static inline void paging_x86_32_map_table(union x86_32_pdir_entry * NONNULL entry, 236 lpaddr_t base) 237{ 238 union x86_32_pdir_entry tmp; 239 tmp.raw = PTABLE_CLEAR; 240 241 tmp.d.present = 1; 242 tmp.d.read_write = 1; 243 tmp.d.user_supervisor = 1; 244 tmp.d.base_addr = base >> 12; 245 246 *entry = tmp; 247} 248 249#ifdef CONFIG_PAE 250static inline void paging_x86_32_map_pdpte(union x86_32_pdpte_entry *entry, 251 lpaddr_t base) 252{ 253 union x86_32_pdpte_entry tmp; 254 tmp.raw = X86_32_PTABLE_CLEAR; 255 256 tmp.d.present = 1; 257 tmp.d.base_addr = base >> 12; 258 259 *entry = tmp; 260} 261#endif 262 263/** 264 * \brief Maps a large page. 265 * 266 * From large page table entry, pointed to by 'entry', maps physical address 267 * 'base' with page attribute bitmap 'bitmap'. 268 * 269 * \param entry Pointer to page table entry to map from. 270 * \param base Physical address to map to (will be page-aligned). 271 * \param bitmap Bitmap to apply to page attributes. 272 */ 273static inline void paging_x86_32_map_large(union x86_32_ptable_entry * NONNULL entry, 274 lpaddr_t base, 275 paging_x86_32_flags_t bitmap) 276{ 277 union x86_32_ptable_entry tmp; 278 tmp.raw = X86_32_PTABLE_CLEAR; 279 280 tmp.large.present = bitmap & X86_32_PTABLE_PRESENT ? 1 : 0; 281 tmp.large.read_write = bitmap & X86_32_PTABLE_READ_WRITE ? 1 : 0; 282 tmp.large.user_supervisor = bitmap & X86_32_PTABLE_USER_SUPERVISOR ? 1 : 0; 283 tmp.large.write_through = bitmap & X86_32_PTABLE_WRITE_THROUGH ? 1 : 0; 284 tmp.large.cache_disabled = bitmap & X86_32_PTABLE_CACHE_DISABLED ? 1 : 0; 285 tmp.large.global = bitmap & X86_32_PTABLE_GLOBAL_PAGE ? 1 : 0; 286 tmp.large.attr_index = bitmap & X86_32_PTABLE_ATTR_INDEX ? 1 : 0; 287#ifdef CONFIG_NXE 288 tmp.large.execute_disable = bitmap & X86_32_PTABLE_EXECUTE_DISABLE ? 1 : 0; 289#endif 290 tmp.large.always1 = 1; 291#ifdef CONFIG_PAE 292 tmp.large.base_addr = base >> 21; 293#else 294 tmp.large.base_addr = base >> 22; 295#endif 296 297 *entry = tmp; 298} 299 300/** 301 * \brief Maps a normal (small) page. 302 * 303 * From small page table entry, pointed to by 'entry', maps physical address 304 * 'base' with page attribute bitmap 'bitmap'. 305 * 306 * \param entry Pointer to page table entry to map from. 307 * \param base Physical address to map to (will be page-aligned). 308 * \param bitmap Bitmap to apply to page attributes. 309 */ 310static inline void paging_x86_32_map(union x86_32_ptable_entry * NONNULL entry, 311 lpaddr_t base, 312 paging_x86_32_flags_t bitmap) 313{ 314 union x86_32_ptable_entry tmp; 315 tmp.raw = X86_32_PTABLE_CLEAR; 316 317 tmp.base.present = bitmap & X86_32_PTABLE_PRESENT ? 1 : 0; 318 tmp.base.read_write = bitmap & X86_32_PTABLE_READ_WRITE ? 1 : 0; 319 tmp.base.user_supervisor = bitmap & X86_32_PTABLE_USER_SUPERVISOR ? 1 : 0; 320 tmp.base.write_through = bitmap & X86_32_PTABLE_WRITE_THROUGH ? 1 : 0; 321 tmp.base.cache_disabled = bitmap & X86_32_PTABLE_CACHE_DISABLED ? 1 : 0; 322 tmp.base.attr_index = bitmap & X86_32_PTABLE_ATTR_INDEX ? 1 : 0; 323 tmp.base.global = bitmap & X86_32_PTABLE_GLOBAL_PAGE ? 1 : 0; 324#ifdef CONFIG_NXE 325 tmp.base.execute_disable = bitmap & X86_32_PTABLE_EXECUTE_DISABLE ? 1 : 0; 326#endif 327 tmp.base.base_addr = base >> 12; 328 329 *entry = tmp; 330} 331 332/** 333 * \brief Modify flags of a large page. 334 * 335 * Update small page table entry, pointed to by 'entry', with page attribute 336 * bitmap 'bitmap'. 337 * 338 * \param entry Pointer to page table entry to map from. 339 * \param bitmap Bitmap to apply to page attributes. 340 */ 341static inline void paging_x86_32_modify_flags_large(union x86_32_ptable_entry * NONNULL entry, 342 paging_x86_32_flags_t bitmap) 343{ 344 union x86_32_ptable_entry tmp = *entry; 345 346 tmp.base.present = bitmap & X86_32_PTABLE_PRESENT ? 1 : 0; 347 tmp.base.read_write = bitmap & X86_32_PTABLE_READ_WRITE ? 1 : 0; 348 tmp.base.user_supervisor = bitmap & X86_32_PTABLE_USER_SUPERVISOR ? 1 : 0; 349 tmp.base.write_through = bitmap & X86_32_PTABLE_WRITE_THROUGH ? 1 : 0; 350 tmp.base.cache_disabled = bitmap & X86_32_PTABLE_CACHE_DISABLED ? 1 : 0; 351 tmp.base.attr_index = bitmap & X86_32_PTABLE_ATTR_INDEX ? 1 : 0; 352 tmp.base.global = bitmap & X86_32_PTABLE_GLOBAL_PAGE ? 1 : 0; 353#ifdef CONFIG_NXE 354 tmp.base.execute_disable = bitmap & X86_32_PTABLE_EXECUTE_DISABLE ? 1 : 0; 355#endif 356 357 *entry = tmp; 358} 359 360/** 361 * \brief Modify flags of a normal (small) page. 362 * 363 * Update small page table entry, pointed to by 'entry', with page attribute 364 * bitmap 'bitmap'. 365 * 366 * \param entry Pointer to page table entry to map from. 367 * \param bitmap Bitmap to apply to page attributes. 368 */ 369static inline void paging_x86_32_modify_flags(union x86_32_ptable_entry * NONNULL entry, 370 paging_x86_32_flags_t bitmap) 371{ 372 union x86_32_ptable_entry tmp = *entry; 373 374 tmp.base.present = bitmap & X86_32_PTABLE_PRESENT ? 1 : 0; 375 tmp.base.read_write = bitmap & X86_32_PTABLE_READ_WRITE ? 1 : 0; 376 tmp.base.user_supervisor = bitmap & X86_32_PTABLE_USER_SUPERVISOR ? 1 : 0; 377 tmp.base.write_through = bitmap & X86_32_PTABLE_WRITE_THROUGH ? 1 : 0; 378 tmp.base.cache_disabled = bitmap & X86_32_PTABLE_CACHE_DISABLED ? 1 : 0; 379 tmp.base.attr_index = bitmap & X86_32_PTABLE_ATTR_INDEX ? 1 : 0; 380 tmp.base.global = bitmap & X86_32_PTABLE_GLOBAL_PAGE ? 1 : 0; 381#ifdef CONFIG_NXE 382 tmp.base.execute_disable = bitmap & X86_32_PTABLE_EXECUTE_DISABLE ? 1 : 0; 383#endif 384 385 *entry = tmp; 386} 387 388static inline void paging_x86_32_unmap(union x86_32_ptable_entry * NONNULL entry) 389{ 390 entry->raw = X86_32_PTABLE_CLEAR; 391} 392 393/** 394 * \brief Convert Capability access rights to X86-64 page flags. 395 * 396 * Returns corresponding X86-64 page flags to given capability access rights 397 * mask 'rights'. 398 * 399 * \param rights Capability rightsmask. 400 * 401 * \return X86-64 page flags. 402 */ 403static inline uint64_t paging_x86_32_cap_to_page_flags(CapRights rights) 404{ 405 uint64_t pageflags = 0; 406 407 // Sanity-check given flags 408 if(!(rights & CAPRIGHTS_READ) && 409 (rights & CAPRIGHTS_WRITE || rights & CAPRIGHTS_EXECUTE)) { 410 printk(LOG_ERR, "Page mapped writable and/or executable, but not " 411 "readable. Impossible on X86! Will map non-everything " 412 "instead.\n"); 413 } 414 415 // Convert flags 416 pageflags |= rights & CAPRIGHTS_READ ? X86_32_PTABLE_USER_SUPERVISOR : 0; 417 pageflags |= rights & CAPRIGHTS_WRITE ? X86_32_PTABLE_READ_WRITE : 0; 418 pageflags |= rights & CAPRIGHTS_EXECUTE ? 0 : X86_32_PTABLE_EXECUTE_DISABLE; 419 420 return pageflags; 421} 422 423/** 424 * \brief Switch context. 425 * 426 * Assigns given physical base address of PDPTE/PDE 'cr3' to the CR3 427 * register, effectively switching context to new address space. Be 428 * cautious that you only switch to "good" (as explained in 429 * paging_make_good_pdpte()/paging_make_good_pdir()) PDPTEs/PDEs! 430 * 431 * \param pdpte Physical base address of PDPTE/PDE table. 432 */ 433static void inline paging_x86_32_context_switch(lpaddr_t cr3) 434{ 435 __asm volatile("mov %[cr3], %%cr3" 436 : /* No output */ 437 : 438 [cr3] "r" (cr3) 439 ); 440} 441 442/** 443 * \brief Mask out page attributes. 444 * 445 * Masks out all attributes and access rights from 'attr' according to 446 * 'mask'. This is architecture-specific. On x86-64, except for the 447 * execute disable attribute, rights are given by setting a 448 * corresponding bit. Thus, setting that bit within 'mask' to zero, 449 * masks out the right. For the execute disable bit, the right is 450 * masked out when the bit is set, so the mask works the other way 451 * around in this case: When the bit is set in 'mask', but not set in 452 * 'attr', it will be set in the return value, so mask-out behavior is 453 * preserved. 454 * 455 * \param attr The page attributes to mask. 456 * \param mask Mask for the page attributes. 457 * 458 * \return Masked version of 'attr'. 459 */ 460static inline uint64_t paging_x86_32_mask_attrs(uint64_t attr, uint64_t mask) 461{ 462 // First, mask out all "bit-sets-enabled" attributes 463 attr &= mask | X86_32_PTABLE_EXECUTE_DISABLE; 464 465 // Now, mask out all "bit-sets-disabled" attributes 466 attr |= mask & X86_32_PTABLE_EXECUTE_DISABLE; 467 468 return attr; 469} 470 471#endif // KERNEL_TARGET_X86_32_PAGING_H 472