1/** 2 * \file 3 * \brief x86-64 kernel page-table structures. 4 */ 5 6/* 7 * Copyright (c) 2007-2013 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, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#ifndef KERNEL_TARGET_X86_64_PAGING_H 16#define KERNEL_TARGET_X86_64_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_64_map_memory(lpaddr_t base, size_t size); 23lvaddr_t paging_x86_64_map_device(lpaddr_t base, size_t size); 24void paging_x86_64_reset(void); 25void paging_x86_64_make_good_pml4(lpaddr_t base); 26 27/// All flags valid for page access protection from user-space 28#define X86_64_PTABLE_ACCESS_MASK \ 29 (X86_64_PTABLE_EXECUTE_DISABLE | X86_64_PTABLE_USER_SUPERVISOR | \ 30 X86_64_PTABLE_READ_WRITE) 31 32/// All arch-specific flags valid to be set from user-space 33#ifdef __k1om__ 34#define X86_64_PTABLE_FLAGS_MASK \ 35 (X86_64_PTABLE_ATTR_INDEX | X86_64_PTABLE_DIRTY | \ 36 X86_64_PTABLE_ACCESSED | X86_64_PTABLE_CACHE_DISABLED | \ 37 X86_64_PTABLE_WRITE_THROUGH) 38#else 39#define X86_64_PTABLE_FLAGS_MASK \ 40 (X86_64_PTABLE_GLOBAL_PAGE | X86_64_PTABLE_ATTR_INDEX | \ 41 X86_64_PTABLE_DIRTY | X86_64_PTABLE_ACCESSED | \ 42 X86_64_PTABLE_CACHE_DISABLED | X86_64_PTABLE_WRITE_THROUGH) 43#endif 44 45/// Mask out all arch-specific flags except those valid from user-space 46#define X86_64_PTABLE_FLAGS(flags) (flags & X86_64_PTABLE_FLAGS_MASK) 47 48/// Mask out all flags except those for access protection 49#define X86_64_PTABLE_ACCESS(flags) (flags & X86_64_PTABLE_ACCESS_MASK) 50 51/** True if page entry is present in memory */ 52#define X86_64_IS_PRESENT(entry) \ 53 ((*(uint64_t *)(entry)) & X86_64_PTABLE_PRESENT) 54 55/** 56 * A page directory entry. 57 */ 58union x86_64_pdir_entry { 59 uint64_t raw; 60 struct { 61 uint64_t present :1; 62 uint64_t read_write :1; 63 uint64_t user_supervisor :1; 64 uint64_t write_through :1; 65 uint64_t cache_disabled :1; 66 uint64_t accessed :1; 67 uint64_t reserved :3; 68 uint64_t available :3; 69 uint64_t base_addr :28; 70 uint64_t reserved2 :12; 71 uint64_t available2 :11; 72 uint64_t execute_disable :1; 73 } d; 74}; 75 76#ifdef __k1om__ 77#define X86_64_PHYSADDR_BITS X1OM_PADDR_SPACE_BITS // TODO: Take that from offsets target 78#else 79#define X86_64_PHYSADDR_BITS X86_64_PADDR_SPACE_BITS 80#endif 81#define X86_64_PAGING_ENTRY_SIZE 64 82#define X86_64_PAGING_AVAIL2_BITS 11 83#define X86_64_PAGING_FLAG_BITS 12 84#define X86_64_PAGING_LARGE_FLAGE_BITS 21 85#define X86_64_PAGING_RESERVED_BITS \ 86 (X86_64_PAGING_ENTRY_SIZE - X86_64_PHYSADDR_BITS - \ 87 X86_64_PAGING_AVAIL2_BITS - 1) 88#define X86_64_PAGING_LARGE_BASE_BITS \ 89 (X86_64_PHYSADDR_BITS - X86_64_PAGING_LARGE_FLAGE_BITS) 90#define X86_64_PAGING_BASE_BASE_BITS \ 91 (X86_64_PHYSADDR_BITS - X86_64_PAGING_FLAG_BITS) 92 93 94/** 95 * A page table entry. 96 */ 97union x86_64_ptable_entry { 98 uint64_t raw; 99 struct { 100 uint64_t present :1; 101 uint64_t read_write :1; 102 uint64_t user_supervisor :1; 103 uint64_t write_through :1; 104 uint64_t cache_disabled :1; 105 uint64_t accessed :1; 106 uint64_t dirty :1; 107 uint64_t always1 :1; 108 uint64_t global :1; 109 uint64_t available :2; 110 uint64_t vtd_snoop :1; 111 uint64_t attr_index :1; 112 uint64_t reserved :17; 113 uint64_t base_addr :10; 114 uint64_t reserved2 :12; 115 uint64_t available2 :11; 116 uint64_t execute_disable :1; 117 } huge; 118 struct { 119 uint64_t present :1; 120 uint64_t read_write :1; 121 uint64_t user_supervisor :1; 122 uint64_t write_through :1; 123 uint64_t cache_disabled :1; 124 uint64_t accessed :1; 125 uint64_t dirty :1; 126 uint64_t always1 :1; 127 uint64_t global :1; 128 uint64_t available :2; 129 uint64_t vtd_snoop :1; 130 uint64_t attr_index :1; 131 uint64_t reserved :8; 132 uint64_t base_addr :X86_64_PAGING_LARGE_BASE_BITS; 133 uint64_t reserved2 :X86_64_PAGING_RESERVED_BITS; 134 uint64_t available2 :11; 135 uint64_t execute_disable :1; 136 } large; 137 struct { 138 uint64_t present :1; 139 uint64_t read_write :1; 140 uint64_t user_supervisor :1; 141 uint64_t write_through :1; 142 uint64_t cache_disabled :1; 143 uint64_t accessed :1; 144 uint64_t dirty :1; 145 uint64_t attr_index :1; 146 uint64_t global :1; 147 uint64_t available :2; 148 uint64_t vtd_snoop :1; 149 uint64_t base_addr :X86_64_PAGING_BASE_BASE_BITS; 150 uint64_t reserved2 :X86_64_PAGING_RESERVED_BITS; 151 uint64_t available2 :11; 152 uint64_t execute_disable :1; 153 } base; 154}; 155 156STATIC_ASSERT_SIZEOF(union x86_64_ptable_entry, (X86_64_PAGING_ENTRY_SIZE / 8)); 157 158/** 159 * \brief Clear page directory. 160 * 161 * Clears page directory pointed to by 'p'. 162 * 163 * \param p Pointer to page directory to clear. 164 */ 165static inline void paging_x86_64_clear_pdir(union x86_64_pdir_entry * COUNT(X86_64_PTABLE_SIZE) 166 NONNULL p) 167{ 168 for (int i = 0; i < X86_64_PTABLE_SIZE; i++) { 169 p[i].raw = X86_64_PTABLE_CLEAR; 170 } 171} 172 173/** 174 * \brief Clear page table. 175 * 176 * Clears page table pointed to by 'p'. 177 * 178 * \param p Pointer to page table to clear. 179 */ 180static inline void paging_x86_64_clear_ptable(union x86_64_ptable_entry * COUNT(X86_64_PTABLE_SIZE) 181 NONNULL p) 182{ 183 for (int i = 0; i < X86_64_PTABLE_SIZE; i++) { 184 p[i].raw = X86_64_PTABLE_CLEAR; 185 } 186} 187 188/** 189 * \brief Maps from page directory entry to page directory/table. 190 * 191 * Maps page directory or table, based at 'base', from page directory entry 192 * pointed to by 'entry'. 193 * 194 * \param entry Pointer to page directory entry to point from. 195 * \param base Base virtual address of page directory/table to point to. 196 */ 197static inline void paging_x86_64_map_table(union x86_64_pdir_entry *entry, 198 lpaddr_t base) 199{ 200 union x86_64_pdir_entry tmp; 201 tmp.raw = X86_64_PTABLE_CLEAR; 202 203 tmp.d.present = 1; 204 tmp.d.read_write = 1; 205 tmp.d.user_supervisor = 1; 206 tmp.d.base_addr = base >> 12; 207 208 *entry = tmp; 209} 210 211/** 212 * \brief Maps a huge page. 213 * 214 * From huge page table entry, pointed to by 'entry', maps physical address 215 * 'base' with page attribute bitmap 'bitmap'. 216 * 217 * \param entry Pointer to page table entry to map from. 218 * \param base Physical address to map to (will be page-aligned). 219 * \param bitmap Bitmap to apply to page attributes. 220 */ 221static inline void paging_x86_64_map_huge(union x86_64_ptable_entry *entry, 222 lpaddr_t base, uint64_t bitmap) 223{ 224 union x86_64_ptable_entry tmp; 225 tmp.raw = X86_64_PTABLE_CLEAR; 226 227 tmp.huge.present = bitmap & X86_64_PTABLE_PRESENT ? 1 : 0; 228 tmp.huge.read_write = bitmap & X86_64_PTABLE_READ_WRITE ? 1 : 0; 229 tmp.huge.user_supervisor = bitmap & X86_64_PTABLE_USER_SUPERVISOR ? 1 : 0; 230 tmp.huge.write_through = bitmap & X86_64_PTABLE_WRITE_THROUGH ? 1 : 0; 231 tmp.huge.cache_disabled = bitmap & X86_64_PTABLE_CACHE_DISABLED ? 1 : 0; 232 tmp.huge.global = bitmap & X86_64_PTABLE_GLOBAL_PAGE ? 1 : 0; 233 tmp.huge.attr_index = bitmap & X86_64_PTABLE_ATTR_INDEX ? 1 : 0; 234 tmp.huge.execute_disable = bitmap & X86_64_PTABLE_EXECUTE_DISABLE ? 1 : 0; 235 tmp.huge.always1 = 1; 236 tmp.huge.base_addr = base >> X86_64_HUGE_PAGE_BITS; 237 238 *entry = tmp; 239} 240 241/** 242 * \brief Maps a large page. 243 * 244 * From large page table entry, pointed to by 'entry', maps physical address 245 * 'base' with page attribute bitmap 'bitmap'. 246 * 247 * \param entry Pointer to page table entry to map from. 248 * \param base Physical address to map to (will be page-aligned). 249 * \param bitmap Bitmap to apply to page attributes. 250 */ 251static inline void paging_x86_64_map_large(union x86_64_ptable_entry *entry, 252 lpaddr_t base, uint64_t bitmap) 253{ 254 union x86_64_ptable_entry tmp; 255 tmp.raw = X86_64_PTABLE_CLEAR; 256 257 tmp.large.present = bitmap & X86_64_PTABLE_PRESENT ? 1 : 0; 258 tmp.large.read_write = bitmap & X86_64_PTABLE_READ_WRITE ? 1 : 0; 259 tmp.large.user_supervisor = bitmap & X86_64_PTABLE_USER_SUPERVISOR ? 1 : 0; 260 tmp.large.write_through = bitmap & X86_64_PTABLE_WRITE_THROUGH ? 1 : 0; 261 tmp.large.cache_disabled = bitmap & X86_64_PTABLE_CACHE_DISABLED ? 1 : 0; 262#ifdef __k1om__ 263 /* The Xeon Phi has no support for global pages */ 264 tmp.large.global = 0; 265#else 266 tmp.large.global = bitmap & X86_64_PTABLE_GLOBAL_PAGE ? 1 : 0; 267#endif 268 tmp.large.attr_index = bitmap & X86_64_PTABLE_ATTR_INDEX ? 1 : 0; 269 tmp.large.execute_disable = bitmap & X86_64_PTABLE_EXECUTE_DISABLE ? 1 : 0; 270 tmp.large.always1 = 1; 271 tmp.large.vtd_snoop = bitmap & X86_64_VTD_PAGE_SNOOP ? 1 : 0; 272 tmp.large.base_addr = base >> 21; 273 274 *entry = tmp; 275} 276 277/** 278 * \brief Maps a normal (small) page. 279 * 280 * From small page table entry, pointed to by 'entry', maps physical address 281 * 'base' with page attribute bitmap 'bitmap'. 282 * 283 * \param entry Pointer to page table entry to map from. 284 * \param base Physical address to map to (will be page-aligned). 285 * \param bitmap Bitmap to apply to page attributes. 286 */ 287static inline void paging_x86_64_map(union x86_64_ptable_entry * NONNULL entry, 288 lpaddr_t base, uint64_t bitmap) 289{ 290 union x86_64_ptable_entry tmp; 291 tmp.raw = X86_64_PTABLE_CLEAR; 292 293 tmp.base.present = bitmap & X86_64_PTABLE_PRESENT ? 1 : 0; 294 tmp.base.read_write = bitmap & X86_64_PTABLE_READ_WRITE ? 1 : 0; 295 tmp.base.user_supervisor = bitmap & X86_64_PTABLE_USER_SUPERVISOR ? 1 : 0; 296 tmp.base.write_through = bitmap & X86_64_PTABLE_WRITE_THROUGH ? 1 : 0; 297 tmp.base.cache_disabled = bitmap & X86_64_PTABLE_CACHE_DISABLED ? 1 : 0; 298 tmp.base.attr_index = bitmap & X86_64_PTABLE_ATTR_INDEX ? 1 : 0; 299#ifdef __k1om__ 300 /* The Xeon Phi has no support for global pages */ 301 tmp.base.global = 0; 302#else 303 tmp.base.global = bitmap & X86_64_PTABLE_GLOBAL_PAGE ? 1 : 0; 304#endif 305 tmp.base.execute_disable = bitmap & X86_64_PTABLE_EXECUTE_DISABLE ? 1 : 0; 306 tmp.base.vtd_snoop = bitmap & X86_64_VTD_PAGE_SNOOP ? 1 : 0; 307 tmp.base.base_addr = base >> 12; 308 309 *entry = tmp; 310} 311 312 313/** 314 * \brief Modify flags of a huge page. 315 * 316 * From small page table entry, pointed to by 'entry', maps physical address 317 * 'base' with page attribute bitmap 'bitmap'. 318 * 319 * \param entry Pointer to page table entry to map from. 320 * \param bitmap Bitmap to apply to page attributes. 321 */ 322static inline void paging_x86_64_modify_flags_huge(union x86_64_ptable_entry * entry, 323 uint64_t bitmap) 324{ 325 union x86_64_ptable_entry tmp = *entry; 326 327 tmp.huge.present = bitmap & X86_64_PTABLE_PRESENT ? 1 : 0; 328 tmp.huge.read_write = bitmap & X86_64_PTABLE_READ_WRITE ? 1 : 0; 329 tmp.huge.user_supervisor = bitmap & X86_64_PTABLE_USER_SUPERVISOR ? 1 : 0; 330 tmp.huge.write_through = bitmap & X86_64_PTABLE_WRITE_THROUGH ? 1 : 0; 331 tmp.huge.cache_disabled = bitmap & X86_64_PTABLE_CACHE_DISABLED ? 1 : 0; 332#ifdef __k1om__ 333 tmp.huge.global = 0; 334#else 335 tmp.huge.global = bitmap & X86_64_PTABLE_GLOBAL_PAGE ? 1 : 0; 336#endif 337 tmp.huge.attr_index = bitmap & X86_64_PTABLE_ATTR_INDEX ? 1 : 0; 338 tmp.huge.execute_disable = bitmap & X86_64_PTABLE_EXECUTE_DISABLE ? 1 : 0; 339 tmp.huge.always1 = 1; 340 341 *entry = tmp; 342} 343 344 345/** 346 * \brief Modify flags of a large page. 347 * 348 * From small page table entry, pointed to by 'entry', maps physical address 349 * 'base' with page attribute bitmap 'bitmap'. 350 * 351 * \param entry Pointer to page table entry to map from. 352 * \param bitmap Bitmap to apply to page attributes. 353 */ 354static inline void paging_x86_64_modify_flags_large(union x86_64_ptable_entry *entry, 355 uint64_t bitmap) 356{ 357 union x86_64_ptable_entry tmp = *entry; 358 359 tmp.large.present = bitmap & X86_64_PTABLE_PRESENT ? 1 : 0; 360 tmp.large.read_write = bitmap & X86_64_PTABLE_READ_WRITE ? 1 : 0; 361 tmp.large.user_supervisor = bitmap & X86_64_PTABLE_USER_SUPERVISOR ? 1 : 0; 362 tmp.large.write_through = bitmap & X86_64_PTABLE_WRITE_THROUGH ? 1 : 0; 363 tmp.large.cache_disabled = bitmap & X86_64_PTABLE_CACHE_DISABLED ? 1 : 0; 364#ifdef __k1om__ 365 /* The Xeon Phi has no support for global pages */ 366 tmp.large.global = 0; 367#else 368 tmp.large.global = bitmap & X86_64_PTABLE_GLOBAL_PAGE ? 1 : 0; 369#endif 370 tmp.large.attr_index = bitmap & X86_64_PTABLE_ATTR_INDEX ? 1 : 0; 371 tmp.large.execute_disable = bitmap & X86_64_PTABLE_EXECUTE_DISABLE ? 1 : 0; 372 tmp.large.always1 = 1; 373 374 *entry = tmp; 375} 376 377/** 378 * \brief Modify flags of a normal (small) page. 379 * 380 * From small page table entry, pointed to by 'entry', maps physical address 381 * 'base' with page attribute bitmap 'bitmap'. 382 * 383 * \param entry Pointer to page table entry to map from. 384 * \param bitmap Bitmap to apply to page attributes. 385 */ 386static inline void paging_x86_64_modify_flags(union x86_64_ptable_entry * NONNULL entry, 387 uint64_t bitmap) 388{ 389 union x86_64_ptable_entry tmp = *entry; 390 391 tmp.base.present = bitmap & X86_64_PTABLE_PRESENT ? 1 : 0; 392 tmp.base.read_write = bitmap & X86_64_PTABLE_READ_WRITE ? 1 : 0; 393 tmp.base.user_supervisor = bitmap & X86_64_PTABLE_USER_SUPERVISOR ? 1 : 0; 394 tmp.base.write_through = bitmap & X86_64_PTABLE_WRITE_THROUGH ? 1 : 0; 395 tmp.base.cache_disabled = bitmap & X86_64_PTABLE_CACHE_DISABLED ? 1 : 0; 396 tmp.base.attr_index = bitmap & X86_64_PTABLE_ATTR_INDEX ? 1 : 0; 397#ifdef __k1om__ 398 /* XXX: The Xeon Phi does no support global pages */ 399 tmp.base.global = 0; 400#else 401 tmp.base.global = bitmap & X86_64_PTABLE_GLOBAL_PAGE ? 1 : 0; 402#endif 403 tmp.base.execute_disable = bitmap & X86_64_PTABLE_EXECUTE_DISABLE ? 1 : 0; 404 405 *entry = tmp; 406} 407static inline void paging_x86_64_pdir_modify_flags(union x86_64_pdir_entry * NONNULL entry, 408 uint64_t bitmap) 409{ 410 union x86_64_pdir_entry tmp = *entry; 411 412 tmp.d.present = bitmap & X86_64_PTABLE_PRESENT ? 1 : 0; 413 tmp.d.read_write = bitmap & X86_64_PTABLE_READ_WRITE ? 1 : 0; 414 tmp.d.user_supervisor = bitmap & X86_64_PTABLE_USER_SUPERVISOR ? 1 : 0; 415 tmp.d.write_through = bitmap & X86_64_PTABLE_WRITE_THROUGH ? 1 : 0; 416 tmp.d.cache_disabled = bitmap & X86_64_PTABLE_CACHE_DISABLED ? 1 : 0; 417 tmp.d.execute_disable = bitmap & X86_64_PTABLE_EXECUTE_DISABLE ? 1 : 0; 418 419 *entry = tmp; 420} 421 422static inline void paging_unmap(union x86_64_ptable_entry * NONNULL entry) 423{ 424 entry->raw = X86_64_PTABLE_CLEAR; 425} 426 427/** 428 * \brief Convert Capability access rights to X86-64 page flags. 429 * 430 * Returns corresponding X86-64 page flags to given capability access rights 431 * mask 'rights'. 432 * 433 * \param rights Capability rightsmask. 434 * 435 * \return X86-64 page flags. 436 */ 437static inline uint64_t paging_x86_64_cap_to_page_flags(CapRights rights) 438{ 439 uint64_t pageflags = 0; 440 441 // Sanity-check given flags 442 if(!(rights & CAPRIGHTS_READ) && 443 (rights & CAPRIGHTS_WRITE || rights & CAPRIGHTS_EXECUTE)) { 444 printk(LOG_ERR, "Page mapped writable and/or executable, but not " 445 "readable. Impossible on X86! Will map non-everything " 446 "instead.\n"); 447 } 448 449 // Convert flags 450 pageflags |= rights & CAPRIGHTS_READ ? X86_64_PTABLE_USER_SUPERVISOR : 0; 451 pageflags |= rights & CAPRIGHTS_WRITE ? X86_64_PTABLE_READ_WRITE : 0; 452 pageflags |= rights & CAPRIGHTS_EXECUTE ? 0 : X86_64_PTABLE_EXECUTE_DISABLE; 453 454 return pageflags; 455} 456 457/** 458 * \brief Switch context. 459 * 460 * Assigns given physical base address of PML4 'pml4' to the CR3 461 * register, effectively switching context to new address space. Be 462 * cautious that you only switch to "good" (as explained in 463 * paging_make_good_pml4()) PML4s! 464 * 465 * \param pml4 Physical base address of PML4 table. 466 */ 467static void inline paging_x86_64_context_switch(lpaddr_t pml4) 468{ 469 __asm volatile("mov %[pml4], %%cr3" 470 : /* No output */ 471 : 472 [pml4] "r" (pml4) 473 ); 474} 475 476/** 477 * \brief Mask out page attributes. 478 * 479 * Masks out all attributes and access rights from 'attr' according to 480 * 'mask'. This is architecture-specific. On x86-64, except for the 481 * execute disable attribute, rights are given by setting a 482 * corresponding bit. Thus, setting that bit within 'mask' to zero, 483 * masks out the right. For the execute disable bit, the right is 484 * masked out when the bit is set, so the mask works the other way 485 * around in this case: When the bit is set in 'mask', but not set in 486 * 'attr', it will be set in the return value, so mask-out behavior is 487 * preserved. 488 * 489 * \param attr The page attributes to mask. 490 * \param mask Mask for the page attributes. 491 * 492 * \return Masked version of 'attr'. 493 */ 494static inline uint64_t paging_x86_64_mask_attrs(uint64_t attr, uint64_t mask) 495{ 496 // First, mask out all "bit-sets-enabled" attributes 497 attr &= mask | X86_64_PTABLE_EXECUTE_DISABLE; 498 499 // Now, mask out all "bit-sets-disabled" attributes 500 attr |= mask & X86_64_PTABLE_EXECUTE_DISABLE; 501 502 return attr; 503} 504 505#endif // KERNEL_TARGET_X86_64_PAGING_H 506