riscv64/mmu: use struct bitfield for flags and std::atomic

Fixes some PTE concurrent access bugs.

Change-Id: I09ec56861fae389a8a3e228b17a3921b85202c8b
Reviewed-on: https://review.haiku-os.org/c/haiku/+/6949
Reviewed-by: Alex von Gluck IV <[email protected]>
This commit is contained in:
X512
2023-09-25 15:50:59 +00:00
committed by Alex von Gluck IV
parent f83058d1ed
commit 98895d0417
7 changed files with 270 additions and 230 deletions
@@ -124,23 +124,20 @@ enum {
pteIdxBits = 9, pteIdxBits = 9,
}; };
enum {
pteValid = 0,
pteRead = 1,
pteWrite = 2,
pteExec = 3,
pteUser = 4,
pteGlobal = 5,
pteAccessed = 6,
pteDirty = 7,
};
union Pte { union Pte {
struct { struct {
uint64 flags: 8; uint64 isValid: 1;
uint64 rsw: 2; uint64 isRead: 1;
uint64 ppn: 44; uint64 isWrite: 1;
uint64 reserved: 10; uint64 isExec: 1;
uint64 isUser: 1;
uint64 isGlobal: 1;
uint64 isAccessed: 1;
uint64 isDirty: 1;
uint64 rsw: 2;
uint64 ppn: 44;
uint64 reserved: 10;
}; };
uint64 val; uint64 val;
}; };
@@ -63,15 +63,15 @@ WritePteFlags(uint32 flags)
if ((1 << i) & flags) { if ((1 << i) & flags) {
if (first) first = false; else dprintf(", "); if (first) first = false; else dprintf(", ");
switch (i) { switch (i) {
case pteValid: dprintf("valid"); break; case 0: dprintf("valid"); break;
case pteRead: dprintf("read"); break; case 1: dprintf("read"); break;
case pteWrite: dprintf("write"); break; case 2: dprintf("write"); break;
case pteExec: dprintf("exec"); break; case 3: dprintf("exec"); break;
case pteUser: dprintf("user"); break; case 4: dprintf("user"); break;
case pteGlobal: dprintf("global"); break; case 5: dprintf("global"); break;
case pteAccessed: dprintf("accessed"); break; case 6: dprintf("accessed"); break;
case pteDirty: dprintf("dirty"); break; case 7: dprintf("dirty"); break;
default: dprintf("%" B_PRIu32, i); default: dprintf("%" B_PRIu32, i);
} }
} }
} }
@@ -106,8 +106,8 @@ DumpPageTableInt(Pte* pte, uint64_t virtAdr, uint32_t level, uint64& firstVirt,
uint64& firstFlags, uint64& len) uint64& firstFlags, uint64& len)
{ {
for (uint32 i = 0; i < pteCount; i++) { for (uint32 i = 0; i < pteCount; i++) {
if (((1 << pteValid) & pte[i].flags) != 0) { if (pte[i].isValid) {
if ((((1 << pteRead) | (1 << pteWrite) | (1 << pteExec)) & pte[i].flags) == 0) { if (!pte[i].isRead && !pte[i].isWrite && !pte[i].isExec) {
if (level == 0) if (level == 0)
panic("internal page table on level 0"); panic("internal page table on level 0");
@@ -119,7 +119,7 @@ DumpPageTableInt(Pte* pte, uint64_t virtAdr, uint32_t level, uint64& firstVirt,
SignExtendVirtAdr(virtAdr + ((uint64_t)i << (pageBits + pteIdxBits*level))), SignExtendVirtAdr(virtAdr + ((uint64_t)i << (pageBits + pteIdxBits*level))),
pte[i].ppn * B_PAGE_SIZE, pte[i].ppn * B_PAGE_SIZE,
1 << (pageBits + pteIdxBits*level), 1 << (pageBits + pteIdxBits*level),
pte[i].flags, pte[i].val & 0xff,
firstVirt, firstPhys, firstFlags, len); firstVirt, firstPhys, firstFlags, len);
} }
} }
@@ -151,14 +151,19 @@ LookupPte(addr_t virtAdr, bool alloc)
Pte *pte = (Pte*)VirtFromPhys(sPageTable); Pte *pte = (Pte*)VirtFromPhys(sPageTable);
for (int level = 2; level > 0; level --) { for (int level = 2; level > 0; level --) {
pte += VirtAdrPte(virtAdr, level); pte += VirtAdrPte(virtAdr, level);
if (((1 << pteValid) & pte->flags) == 0) { if (!pte->isValid) {
if (!alloc) if (!alloc)
return NULL; return NULL;
pte->ppn = mmu_allocate_page() / B_PAGE_SIZE; uint64 ppn = mmu_allocate_page() / B_PAGE_SIZE;
if (pte->ppn == 0) if (ppn == 0)
return NULL; return NULL;
memset((Pte*)VirtFromPhys(B_PAGE_SIZE * pte->ppn), 0, B_PAGE_SIZE); memset((Pte*)VirtFromPhys(B_PAGE_SIZE * ppn), 0, B_PAGE_SIZE);
pte->flags |= (1 << pteValid) | (IS_KERNEL_ADDRESS(virtAdr) ? (1 << pteGlobal) : 0); Pte newPte {
.isValid = true,
.isGlobal = IS_KERNEL_ADDRESS(virtAdr),
.ppn = ppn
};
pte->val = newPte.val;
} }
pte = (Pte*)VirtFromPhys(B_PAGE_SIZE * pte->ppn); pte = (Pte*)VirtFromPhys(B_PAGE_SIZE * pte->ppn);
} }
@@ -174,10 +179,15 @@ Map(addr_t virtAdr, phys_addr_t physAdr, uint64 flags)
Pte* pte = LookupPte(virtAdr, true); Pte* pte = LookupPte(virtAdr, true);
if (pte == NULL) panic("can't allocate page table"); if (pte == NULL) panic("can't allocate page table");
pte->ppn = physAdr / B_PAGE_SIZE; Pte newPte {
pte->flags = (1 << pteValid) | (1 << pteAccessed) | (1 << pteDirty) .isValid = true,
| (IS_KERNEL_ADDRESS(virtAdr) ? (1 << pteGlobal) : 0) .isGlobal = IS_KERNEL_ADDRESS(virtAdr),
| flags; .isAccessed = true,
.isDirty = true,
};
newPte.val |= flags;
pte->val = newPte.val;
} }
@@ -230,11 +240,16 @@ PreallocKernelRange()
Pte* root = (Pte*)VirtFromPhys(sPageTable); Pte* root = (Pte*)VirtFromPhys(sPageTable);
for (uint64 i = VirtAdrPte(KERNEL_BASE, 2); i <= VirtAdrPte(KERNEL_TOP, 2); for (uint64 i = VirtAdrPte(KERNEL_BASE, 2); i <= VirtAdrPte(KERNEL_TOP, 2);
i++) { i++) {
Pte *pte = &root[i]; Pte* pte = &root[i];
pte->ppn = mmu_allocate_page() / B_PAGE_SIZE; uint64 ppn = mmu_allocate_page() / B_PAGE_SIZE;
if (pte->ppn == 0) panic("can't alloc early physical page"); if (ppn == 0) panic("can't alloc early physical page");
memset(VirtFromPhys(B_PAGE_SIZE * pte->ppn), 0, B_PAGE_SIZE); memset(VirtFromPhys(B_PAGE_SIZE * pte->ppn), 0, B_PAGE_SIZE);
pte->flags |= (1 << pteValid) | (1 << pteGlobal); Pte newPte {
.isValid = true,
.isGlobal = true,
.ppn = ppn
};
pte->val = newPte.val;
} }
} }
@@ -366,7 +381,7 @@ arch_mmu_generate_post_efi_page_tables(size_t memoryMapSize, efi_memory_descript
gKernelArgs.arch_args.physMap.start = KERNEL_TOP + 1 - physMemRange.size; gKernelArgs.arch_args.physMap.start = KERNEL_TOP + 1 - physMemRange.size;
gKernelArgs.arch_args.physMap.size = physMemRange.size; gKernelArgs.arch_args.physMap.size = physMemRange.size;
MapRange(gKernelArgs.arch_args.physMap.start, physMemRange.start, physMemRange.size, MapRange(gKernelArgs.arch_args.physMap.start, physMemRange.start, physMemRange.size,
(1 << pteRead) | (1 << pteWrite)); Pte {.isRead = true, .isWrite = true}.val);
// Boot loader // Boot loader
TRACE("Boot loader:\n"); TRACE("Boot loader:\n");
@@ -376,7 +391,7 @@ arch_mmu_generate_post_efi_page_tables(size_t memoryMapSize, efi_memory_descript
case EfiLoaderCode: case EfiLoaderCode:
case EfiLoaderData: case EfiLoaderData:
MapRange(entry->VirtualStart, entry->PhysicalStart, entry->NumberOfPages * B_PAGE_SIZE, MapRange(entry->VirtualStart, entry->PhysicalStart, entry->NumberOfPages * B_PAGE_SIZE,
(1 << pteRead) | (1 << pteWrite) | (1 << pteExec)); Pte {.isRead = true, .isWrite = true, .isExec = true}.val);
break; break;
default: default:
; ;
@@ -393,7 +408,7 @@ arch_mmu_generate_post_efi_page_tables(size_t memoryMapSize, efi_memory_descript
efi_memory_descriptor* entry = &memoryMap[i]; efi_memory_descriptor* entry = &memoryMap[i];
if ((entry->Attribute & EFI_MEMORY_RUNTIME) != 0) if ((entry->Attribute & EFI_MEMORY_RUNTIME) != 0)
MapRange(entry->VirtualStart, entry->PhysicalStart, entry->NumberOfPages * B_PAGE_SIZE, MapRange(entry->VirtualStart, entry->PhysicalStart, entry->NumberOfPages * B_PAGE_SIZE,
(1 << pteRead) | (1 << pteWrite) | (1 << pteExec)); Pte {.isRead = true, .isWrite = true, .isExec = true}.val);
} }
// Memory regions // Memory regions
@@ -403,22 +418,22 @@ arch_mmu_generate_post_efi_page_tables(size_t memoryMapSize, efi_memory_descript
phys_addr_t physAdr; phys_addr_t physAdr;
size_t size; size_t size;
while (mmu_next_region(&cookie, &virtAdr, &physAdr, &size)) { while (mmu_next_region(&cookie, &virtAdr, &physAdr, &size)) {
MapRange(virtAdr, physAdr, size, (1 << pteRead) | (1 << pteWrite) | (1 << pteExec)); MapRange(virtAdr, physAdr, size, Pte {.isRead = true, .isWrite = true, .isExec = true}.val);
} }
// Devices // Devices
TRACE("Devices:\n"); TRACE("Devices:\n");
MapAddrRange(gKernelArgs.arch_args.clint, (1 << pteRead) | (1 << pteWrite)); MapAddrRange(gKernelArgs.arch_args.clint, Pte {.isRead = true, .isWrite = true}.val);
MapAddrRange(gKernelArgs.arch_args.htif, (1 << pteRead) | (1 << pteWrite)); MapAddrRange(gKernelArgs.arch_args.htif, Pte {.isRead = true, .isWrite = true}.val);
MapAddrRange(gKernelArgs.arch_args.plic, (1 << pteRead) | (1 << pteWrite)); MapAddrRange(gKernelArgs.arch_args.plic, Pte {.isRead = true, .isWrite = true}.val);
if (strcmp(gKernelArgs.arch_args.uart.kind, "") != 0) { if (strcmp(gKernelArgs.arch_args.uart.kind, "") != 0) {
MapRange(gKernelArgs.arch_args.uart.regs.start, MapRange(gKernelArgs.arch_args.uart.regs.start,
gKernelArgs.arch_args.uart.regs.start, gKernelArgs.arch_args.uart.regs.start,
gKernelArgs.arch_args.uart.regs.size, gKernelArgs.arch_args.uart.regs.size,
(1 << pteRead) | (1 << pteWrite)); Pte {.isRead = true, .isWrite = true}.val);
MapAddrRange(gKernelArgs.arch_args.uart.regs, MapAddrRange(gKernelArgs.arch_args.uart.regs,
(1 << pteRead) | (1 << pteWrite)); Pte {.isRead = true, .isWrite = true}.val);
} }
sort_address_ranges(gKernelArgs.virtual_allocated_range, sort_address_ranges(gKernelArgs.virtual_allocated_range,
+49 -35
View File
@@ -54,15 +54,15 @@ WritePteFlags(uint32 flags)
if ((1 << i) & flags) { if ((1 << i) & flags) {
if (first) first = false; else dprintf(", "); if (first) first = false; else dprintf(", ");
switch (i) { switch (i) {
case pteValid: dprintf("valid"); break; case 0: dprintf("valid"); break;
case pteRead: dprintf("read"); break; case 1: dprintf("read"); break;
case pteWrite: dprintf("write"); break; case 2: dprintf("write"); break;
case pteExec: dprintf("exec"); break; case 3: dprintf("exec"); break;
case pteUser: dprintf("user"); break; case 4: dprintf("user"); break;
case pteGlobal: dprintf("global"); break; case 5: dprintf("global"); break;
case pteAccessed: dprintf("accessed"); break; case 6: dprintf("accessed"); break;
case pteDirty: dprintf("dirty"); break; case 7: dprintf("dirty"); break;
default: dprintf("%" B_PRIu32, i); default: dprintf("%" B_PRIu32, i);
} }
} }
} }
@@ -139,14 +139,19 @@ LookupPte(addr_t virtAdr, bool alloc)
Pte *pte = (Pte*)VirtFromPhys(sPageTable); Pte *pte = (Pte*)VirtFromPhys(sPageTable);
for (int level = 2; level > 0; level--) { for (int level = 2; level > 0; level--) {
pte += VirtAdrPte(virtAdr, level); pte += VirtAdrPte(virtAdr, level);
if (!((1 << pteValid) & pte->flags)) { if (!pte->isValid) {
if (!alloc) if (!alloc)
return NULL; return NULL;
pte->ppn = AllocPhysPage() / B_PAGE_SIZE; uint64 ppn = AllocPhysPage() / B_PAGE_SIZE;
if (pte->ppn == 0) if (ppn == 0)
return NULL; return NULL;
memset((Pte*)VirtFromPhys(B_PAGE_SIZE * pte->ppn), 0, B_PAGE_SIZE); memset((Pte*)VirtFromPhys(B_PAGE_SIZE * ppn), 0, B_PAGE_SIZE);
pte->flags |= (1 << pteValid) | (IS_KERNEL_ADDRESS(virtAdr) ? (1 << pteGlobal) : 0); Pte newPte {
.isValid = true,
.isGlobal = IS_KERNEL_ADDRESS(virtAdr),
.ppn = ppn
};
pte->val = newPte.val;
} }
pte = (Pte*)VirtFromPhys(B_PAGE_SIZE * pte->ppn); pte = (Pte*)VirtFromPhys(B_PAGE_SIZE * pte->ppn);
} }
@@ -163,10 +168,16 @@ Map(addr_t virtAdr, phys_addr_t physAdr, uint64 flags)
if (pte == NULL) if (pte == NULL)
panic("can't allocate page table"); panic("can't allocate page table");
pte->ppn = physAdr / B_PAGE_SIZE; Pte newPte {
pte->flags = (1 << pteValid) | (1 << pteAccessed) | (1 << pteDirty) .isValid = true,
| (IS_KERNEL_ADDRESS(virtAdr) ? (1 << pteGlobal) : 0) .isGlobal = IS_KERNEL_ADDRESS(virtAdr),
| flags; .isAccessed = true,
.isDirty = true,
.ppn = physAdr / B_PAGE_SIZE
};
newPte.val |= flags;
pte->val = newPte.val;
} }
@@ -215,10 +226,15 @@ PreallocKernelRange()
for (uint64 i = VirtAdrPte(KERNEL_BASE, 2); i <= VirtAdrPte(KERNEL_TOP, 2); for (uint64 i = VirtAdrPte(KERNEL_BASE, 2); i <= VirtAdrPte(KERNEL_TOP, 2);
i++) { i++) {
Pte* pte = &root[i]; Pte* pte = &root[i];
pte->ppn = AllocPhysPage() / B_PAGE_SIZE; uint64 ppn = AllocPhysPage() / B_PAGE_SIZE;
if (pte->ppn == 0) panic("can't alloc early physical page"); if (ppn == 0) panic("can't alloc early physical page");
memset(VirtFromPhys(B_PAGE_SIZE * pte->ppn), 0, B_PAGE_SIZE); memset(VirtFromPhys(B_PAGE_SIZE * pte->ppn), 0, B_PAGE_SIZE);
pte->flags |= (1 << pteValid) | (1 << pteGlobal); Pte newPte {
.isValid = true,
.isGlobal = true,
.ppn = ppn
};
pte->val = newPte.val;
} }
} }
@@ -239,32 +255,30 @@ SetupPageTable()
MapRange(gKernelArgs.arch_args.physMap.start, MapRange(gKernelArgs.arch_args.physMap.start,
gKernelArgs.physical_memory_range[0].start, gKernelArgs.physical_memory_range[0].start,
gKernelArgs.arch_args.physMap.size, gKernelArgs.arch_args.physMap.size,
(1 << pteRead) | (1 << pteWrite)); Pte {.isRead = true, .isWrite = true}.val);
// Boot loader // Boot loader
MapRangeIdentity((addr_t)gMemBase, &gStackEnd - gMemBase, MapRangeIdentity((addr_t)gMemBase, &gStackEnd - gMemBase,
(1 << pteRead) | (1 << pteWrite) | (1 << pteExec)); Pte {.isRead = true, .isWrite = true, .isExec = true}.val);
// Memory regions // Memory regions
MemoryRegion* region; MemoryRegion* region;
for (region = sRegions; region != NULL; region = region->next) { for (region = sRegions; region != NULL; region = region->next) {
uint64 flags = 0; Pte flags {
if ((region->protection & B_READ_AREA) != 0) .isRead = (region->protection & B_READ_AREA) != 0,
flags |= (1 << pteRead); .isWrite = (region->protection & B_WRITE_AREA) != 0,
if ((region->protection & B_WRITE_AREA) != 0) .isExec = (region->protection & B_EXECUTE_AREA) != 0
flags |= (1 << pteWrite); };
if ((region->protection & B_EXECUTE_AREA) != 0) MapRange(region->virtAdr, region->physAdr, region->size, flags.val);
flags |= (1 << pteExec);
MapRange(region->virtAdr, region->physAdr, region->size, flags);
} }
// Devices // Devices
MapAddrRange(gKernelArgs.arch_args.clint, (1 << pteRead) | (1 << pteWrite)); MapAddrRange(gKernelArgs.arch_args.clint, Pte {.isRead = true, .isWrite = true}.val);
MapAddrRange(gKernelArgs.arch_args.htif, (1 << pteRead) | (1 << pteWrite)); MapAddrRange(gKernelArgs.arch_args.htif, Pte {.isRead = true, .isWrite = true}.val);
MapAddrRange(gKernelArgs.arch_args.plic, (1 << pteRead) | (1 << pteWrite)); MapAddrRange(gKernelArgs.arch_args.plic, Pte {.isRead = true, .isWrite = true}.val);
if (strcmp(gKernelArgs.arch_args.uart.kind, "") != 0) { if (strcmp(gKernelArgs.arch_args.uart.kind, "") != 0) {
MapAddrRange(gKernelArgs.arch_args.uart.regs, MapAddrRange(gKernelArgs.arch_args.uart.regs,
(1 << pteRead) | (1 << pteWrite)); Pte {.isRead = true, .isWrite = true}.val);
} }
} }
@@ -122,7 +122,7 @@ FreePageTable(page_num_t ppn, bool isKernel, uint32 level = 2)
end = VirtAdrPte(USER_TOP, 2); end = VirtAdrPte(USER_TOP, 2);
} }
for (uint64 i = beg; i <= end; i++) { for (uint64 i = beg; i <= end; i++) {
if ((1 << pteValid) & pte[i].flags) if (pte[i].isValid)
FreePageTable(pte[i].ppn, isKernel, level - 1); FreePageTable(pte[i].ppn, isKernel, level - 1);
} }
} }
@@ -150,7 +150,7 @@ GetPageTableSize(page_num_t ppn, bool isKernel, uint32 level = 2)
end = VirtAdrPte(USER_TOP, 2); end = VirtAdrPte(USER_TOP, 2);
} }
for (uint64 i = beg; i <= end; i++) { for (uint64 i = beg; i <= end; i++) {
if ((1 << pteValid) & pte[i].flags) if (pte[i].isValid)
size += GetPageTableSize(pte[i].ppn, isKernel, level - 1); size += GetPageTableSize(pte[i].ppn, isKernel, level - 1);
} }
return size; return size;
@@ -160,7 +160,7 @@ GetPageTableSize(page_num_t ppn, bool isKernel, uint32 level = 2)
//#pragma mark RISCV64VMTranslationMap //#pragma mark RISCV64VMTranslationMap
Pte* std::atomic<Pte>*
RISCV64VMTranslationMap::LookupPte(addr_t virtAdr, bool alloc, RISCV64VMTranslationMap::LookupPte(addr_t virtAdr, bool alloc,
vm_page_reservation* reservation) vm_page_reservation* reservation)
{ {
@@ -185,26 +185,31 @@ RISCV64VMTranslationMap::LookupPte(addr_t virtAdr, bool alloc,
i <= VirtAdrPte(KERNEL_TOP, 2); i++) { i <= VirtAdrPte(KERNEL_TOP, 2); i++) {
Pte *pte = &userPageTable[i]; Pte *pte = &userPageTable[i];
pte->ppn = kernelPageTable[i].ppn; pte->ppn = kernelPageTable[i].ppn;
pte->flags |= (1 << pteValid); pte->isValid = true;
} }
} }
} }
Pte *pte = (Pte*)VirtFromPhys(fPageTable); auto pte = (std::atomic<Pte>*)VirtFromPhys(fPageTable);
for (int level = 2; level > 0; level--) { for (int level = 2; level > 0; level--) {
pte += VirtAdrPte(virtAdr, level); pte += VirtAdrPte(virtAdr, level);
if (!((1 << pteValid) & pte->flags)) { if (!pte->load().isValid) {
if (!alloc) if (!alloc)
return NULL; return NULL;
vm_page* page = vm_page_allocate_page(reservation, vm_page* page = vm_page_allocate_page(reservation,
PAGE_STATE_WIRED | VM_PAGE_ALLOC_CLEAR); PAGE_STATE_WIRED | VM_PAGE_ALLOC_CLEAR);
pte->ppn = page->physical_page_number; page_num_t ppn = page->physical_page_number;
if (pte->ppn == 0) if (ppn == 0)
return NULL; return NULL;
DEBUG_PAGE_ACCESS_END(page); DEBUG_PAGE_ACCESS_END(page);
fPageTableSize++; fPageTableSize++;
pte->flags |= (1 << pteValid) | (fIsKernel ? (1 << pteGlobal) : 0); Pte newPte {
.isValid = true,
.isGlobal = fIsKernel,
.ppn = ppn
};
pte->store(newPte);
} }
pte = (Pte*)VirtFromPhys(B_PAGE_SIZE * pte->ppn); pte = (std::atomic<Pte>*)VirtFromPhys(B_PAGE_SIZE * pte->load().ppn);
} }
pte += VirtAdrPte(virtAdr, 0); pte += VirtAdrPte(virtAdr, 0);
return pte; return pte;
@@ -214,12 +219,15 @@ RISCV64VMTranslationMap::LookupPte(addr_t virtAdr, bool alloc,
phys_addr_t phys_addr_t
RISCV64VMTranslationMap::LookupAddr(addr_t virtAdr) RISCV64VMTranslationMap::LookupAddr(addr_t virtAdr)
{ {
Pte* pte = LookupPte(virtAdr, false, NULL); std::atomic<Pte>* pte = LookupPte(virtAdr, false, NULL);
if (pte == NULL || !((1 << pteValid) & pte->flags)) if (pte == NULL)
return 0; return 0;
if (fIsKernel != (((1 << pteUser) & pte->flags) == 0)) Pte pteVal = pte->load();
if (!pteVal.isValid)
return 0; return 0;
return pte->ppn * B_PAGE_SIZE; if (fIsKernel != !pteVal.isUser)
return 0;
return pteVal.ppn * B_PAGE_SIZE;
} }
@@ -313,36 +321,38 @@ RISCV64VMTranslationMap::Map(addr_t virtualAddress, phys_addr_t physicalAddress,
ThreadCPUPinner pinner(thread_get_current_thread()); ThreadCPUPinner pinner(thread_get_current_thread());
Pte* pte = LookupPte(virtualAddress, true, reservation); std::atomic<Pte>* pte = LookupPte(virtualAddress, true, reservation);
if (pte == NULL) if (pte == NULL)
panic("can't allocate page table"); panic("can't allocate page table");
Pte newPte; Pte newPte {
newPte.ppn = physicalAddress / B_PAGE_SIZE; .isValid = true,
newPte.flags = (1 << pteValid) | (fIsKernel ? (1 << pteGlobal) : 0); .isGlobal = fIsKernel,
.ppn = physicalAddress / B_PAGE_SIZE
};
if ((attributes & B_USER_PROTECTION) != 0) { if ((attributes & B_USER_PROTECTION) != 0) {
newPte.flags |= (1 << pteUser); newPte.isUser = true;
if ((attributes & B_READ_AREA) != 0) if ((attributes & B_READ_AREA) != 0)
newPte.flags |= (1 << pteRead); newPte.isRead = true;
if ((attributes & B_WRITE_AREA) != 0) if ((attributes & B_WRITE_AREA) != 0)
newPte.flags |= (1 << pteWrite); newPte.isWrite = true;
if ((attributes & B_EXECUTE_AREA) != 0) { if ((attributes & B_EXECUTE_AREA) != 0) {
newPte.flags |= (1 << pteExec); newPte.isExec = true;
fInvalidCode = true; fInvalidCode = true;
} }
} else { } else {
if ((attributes & B_KERNEL_READ_AREA) != 0) if ((attributes & B_KERNEL_READ_AREA) != 0)
newPte.flags |= (1 << pteRead); newPte.isRead = true;
if ((attributes & B_KERNEL_WRITE_AREA) != 0) if ((attributes & B_KERNEL_WRITE_AREA) != 0)
newPte.flags |= (1 << pteWrite); newPte.isWrite = true;
if ((attributes & B_KERNEL_EXECUTE_AREA) != 0) { if ((attributes & B_KERNEL_EXECUTE_AREA) != 0) {
newPte.flags |= (1 << pteExec); newPte.isExec = true;
fInvalidCode = true; fInvalidCode = true;
} }
} }
*pte = newPte; pte->store(newPte);
// Note: We don't need to invalidate the TLB for this address, as previously // Note: We don't need to invalidate the TLB for this address, as previously
// the entry was not present and the TLB doesn't cache those entries. // the entry was not present and the TLB doesn't cache those entries.
@@ -362,11 +372,11 @@ RISCV64VMTranslationMap::Unmap(addr_t start, addr_t end)
ThreadCPUPinner pinner(thread_get_current_thread()); ThreadCPUPinner pinner(thread_get_current_thread());
for (addr_t page = start; page < end; page += B_PAGE_SIZE) { for (addr_t page = start; page < end; page += B_PAGE_SIZE) {
Pte* pte = LookupPte(page, false, NULL); std::atomic<Pte>* pte = LookupPte(page, false, NULL);
if (pte != NULL) { if (pte != NULL) {
fMapCount--; fMapCount--;
Pte oldPte{.val = (uint64)atomic_get_and_set64((int64*)&pte->val, 0)}; Pte oldPte = pte->exchange({});
if ((oldPte.flags & (1 << pteAccessed)) != 0) if (oldPte.isAccessed)
InvalidatePage(page); InvalidatePage(page);
} }
} }
@@ -406,24 +416,23 @@ RISCV64VMTranslationMap::UnmapPage(VMArea* area, addr_t address,
ThreadCPUPinner pinner(thread_get_current_thread()); ThreadCPUPinner pinner(thread_get_current_thread());
Pte* pte = LookupPte(address, false, NULL); std::atomic<Pte>* pte = LookupPte(address, false, NULL);
if (pte == NULL || ((1 << pteValid) & pte->flags) == 0) if (pte == NULL || !pte->load().isValid)
return B_ENTRY_NOT_FOUND; return B_ENTRY_NOT_FOUND;
RecursiveLocker locker(fLock); RecursiveLocker locker(fLock);
Pte oldPte{.val = (uint64)atomic_get_and_set64((int64*)&pte->val, 0)}; Pte oldPte = pte->exchange({});
fMapCount--; fMapCount--;
pinner.Unlock(); pinner.Unlock();
if ((oldPte.flags & (1 << pteAccessed)) != 0) if (oldPte.isAccessed)
InvalidatePage(address); InvalidatePage(address);
Flush(); Flush();
locker.Detach(); // PageUnmapped takes ownership locker.Detach(); // PageUnmapped takes ownership
PageUnmapped(area, oldPte.ppn, ((1 << pteAccessed) & oldPte.flags) != 0, PageUnmapped(area, oldPte.ppn, oldPte.isAccessed, oldPte.isDirty, updatePageQueue);
((1 << pteDirty) & oldPte.flags) != 0, updatePageQueue);
return B_OK; return B_OK;
} }
@@ -446,17 +455,17 @@ RISCV64VMTranslationMap::UnmapPages(VMArea* area, addr_t base, size_t size,
ThreadCPUPinner pinner(thread_get_current_thread()); ThreadCPUPinner pinner(thread_get_current_thread());
for (addr_t start = base; start < end; start += B_PAGE_SIZE) { for (addr_t start = base; start < end; start += B_PAGE_SIZE) {
Pte* pte = LookupPte(start, false, NULL); std::atomic<Pte>* pte = LookupPte(start, false, NULL);
if (pte == NULL) if (pte == NULL)
continue; continue;
Pte oldPte{.val = (uint64)atomic_get_and_set64((int64*)&pte->val, 0)}; Pte oldPte = pte->exchange({});
if ((oldPte.flags & (1 << pteValid)) == 0) if (!oldPte.isValid)
continue; continue;
fMapCount--; fMapCount--;
if ((oldPte.flags & (1 << pteAccessed)) != 0) if (oldPte.isAccessed)
InvalidatePage(start); InvalidatePage(start);
if (area->cache_type != CACHE_TYPE_DEVICE) { if (area->cache_type != CACHE_TYPE_DEVICE) {
@@ -470,10 +479,8 @@ RISCV64VMTranslationMap::UnmapPages(VMArea* area, addr_t base, size_t size,
DEBUG_PAGE_ACCESS_START(page); DEBUG_PAGE_ACCESS_START(page);
// transfer the accessed/dirty flags to the page // transfer the accessed/dirty flags to the page
if ((oldPte.flags & (1 << pteAccessed)) != 0) page->accessed = oldPte.isAccessed;
page->accessed = true; page->modified = oldPte.isDirty;
if ((oldPte.flags & (1 << pteDirty)) != 0)
page->modified = true;
// remove the mapping object/decrement the wired_count of the // remove the mapping object/decrement the wired_count of the
// page // page
@@ -572,27 +579,26 @@ RISCV64VMTranslationMap::UnmapArea(VMArea* area, bool deletingAddressSpace,
+ ((page->cache_offset * B_PAGE_SIZE) + ((page->cache_offset * B_PAGE_SIZE)
- area->cache_offset); - area->cache_offset);
Pte* pte = LookupPte(address, false, NULL); std::atomic<Pte>* pte = LookupPte(address, false, NULL);
if (pte == NULL if (pte == NULL || !pte->load().isValid) {
|| ((1 << pteValid) & pte->flags) == 0) {
panic("page %p has mapping for area %p " panic("page %p has mapping for area %p "
"(%#" B_PRIxADDR "), but has no " "(%#" B_PRIxADDR "), but has no "
"page table", page, area, address); "page table", page, area, address);
continue; continue;
} }
Pte oldPte{.val = (uint64)atomic_get_and_set64((int64*)&pte->val, 0)}; Pte oldPte = pte->exchange({});
// transfer the accessed/dirty flags to the page and // transfer the accessed/dirty flags to the page and
// invalidate the mapping, if necessary // invalidate the mapping, if necessary
if (((1 << pteAccessed) & oldPte.flags) != 0) { if (oldPte.isAccessed) {
page->accessed = true; page->accessed = true;
if (!deletingAddressSpace) if (!deletingAddressSpace)
InvalidatePage(address); InvalidatePage(address);
} }
if (((1 << pteDirty) & oldPte.flags) != 0) if (oldPte.isDirty)
page->modified = true; page->modified = true;
if (pageFullyUnmapped) { if (pageFullyUnmapped) {
@@ -642,32 +648,32 @@ RISCV64VMTranslationMap::Query(addr_t virtualAddress,
if (fPageTable == 0) if (fPageTable == 0)
return B_OK; return B_OK;
Pte* pte = LookupPte(virtualAddress, false, NULL); std::atomic<Pte>* pte = LookupPte(virtualAddress, false, NULL);
if (pte == 0) if (pte == NULL)
return B_OK; return B_OK;
Pte pteVal = *pte; Pte pteVal = pte->load();
*_physicalAddress = pteVal.ppn * B_PAGE_SIZE; *_physicalAddress = pteVal.ppn * B_PAGE_SIZE;
if (((1 << pteValid) & pteVal.flags) != 0) if (pteVal.isValid)
*_flags |= PAGE_PRESENT; *_flags |= PAGE_PRESENT;
if (((1 << pteDirty) & pteVal.flags) != 0) if (pteVal.isDirty)
*_flags |= PAGE_MODIFIED; *_flags |= PAGE_MODIFIED;
if (((1 << pteAccessed) & pteVal.flags) != 0) if (pteVal.isAccessed)
*_flags |= PAGE_ACCESSED; *_flags |= PAGE_ACCESSED;
if (((1 << pteUser) & pteVal.flags) != 0) { if (pteVal.isUser) {
if (((1 << pteRead) & pteVal.flags) != 0) if (pteVal.isRead)
*_flags |= B_READ_AREA; *_flags |= B_READ_AREA;
if (((1 << pteWrite) & pteVal.flags) != 0) if (pteVal.isWrite)
*_flags |= B_WRITE_AREA; *_flags |= B_WRITE_AREA;
if (((1 << pteExec) & pteVal.flags) != 0) if (pteVal.isExec)
*_flags |= B_EXECUTE_AREA; *_flags |= B_EXECUTE_AREA;
} else { } else {
if (((1 << pteRead) & pteVal.flags) != 0) if (pteVal.isRead)
*_flags |= B_KERNEL_READ_AREA; *_flags |= B_KERNEL_READ_AREA;
if (((1 << pteWrite) & pteVal.flags) != 0) if (pteVal.isWrite)
*_flags |= B_KERNEL_WRITE_AREA; *_flags |= B_KERNEL_WRITE_AREA;
if (((1 << pteExec) & pteVal.flags) != 0) if (pteVal.isExec)
*_flags |= B_KERNEL_EXECUTE_AREA; *_flags |= B_KERNEL_EXECUTE_AREA;
} }
@@ -693,41 +699,38 @@ status_t RISCV64VMTranslationMap::Protect(addr_t base, addr_t top,
for (addr_t page = base; page < top; page += B_PAGE_SIZE) { for (addr_t page = base; page < top; page += B_PAGE_SIZE) {
Pte* pte = LookupPte(page, false, NULL); std::atomic<Pte>* pte = LookupPte(page, false, NULL);
if (pte == NULL || ((1 << pteValid) & pte->flags) == 0) { if (pte == NULL || !pte->load().isValid) {
TRACE("attempt to protect not mapped page: 0x%" TRACE("attempt to protect not mapped page: 0x%"
B_PRIxADDR "\n", page); B_PRIxADDR "\n", page);
continue; continue;
} }
Pte oldPte = *pte; Pte oldPte {};
Pte newPte = oldPte; Pte newPte {};
newPte.flags &= (1 << pteValid) | (1 << pteGlobal) while (true) {
| (1 << pteAccessed) | (1 << pteDirty); oldPte = pte->load();
if ((attributes & B_USER_PROTECTION) != 0) { newPte = oldPte;
newPte.flags |= (1 << pteUser); if ((attributes & B_USER_PROTECTION) != 0) {
if ((attributes & B_READ_AREA) != 0) newPte.isUser = true;
newPte.flags |= (1 << pteRead); newPte.isRead = (attributes & B_READ_AREA) != 0;
if ((attributes & B_WRITE_AREA) != 0) newPte.isWrite = (attributes & B_WRITE_AREA) != 0;
newPte.flags |= (1 << pteWrite); newPte.isExec = (attributes & B_EXECUTE_AREA) != 0;
if ((attributes & B_EXECUTE_AREA) != 0) { } else {
newPte.flags |= (1 << pteExec); newPte.isUser = false;
fInvalidCode = true; newPte.isRead = (attributes & B_KERNEL_READ_AREA) != 0;
} newPte.isWrite = (attributes & B_KERNEL_WRITE_AREA) != 0;
} else { newPte.isExec = (attributes & B_KERNEL_EXECUTE_AREA) != 0;
if ((attributes & B_KERNEL_READ_AREA) != 0)
newPte.flags |= (1 << pteRead);
if ((attributes & B_KERNEL_WRITE_AREA) != 0)
newPte.flags |= (1 << pteWrite);
if ((attributes & B_KERNEL_EXECUTE_AREA) != 0) {
newPte.flags |= (1 << pteExec);
fInvalidCode = true;
} }
if (pte->compare_exchange_strong(oldPte, newPte))
break;
} }
*pte = newPte;
if ((oldPte.flags & (1 << pteAccessed)) != 0) fInvalidCode = newPte.isExec;
if (oldPte.isAccessed)
InvalidatePage(page); InvalidatePage(page);
} }
@@ -752,11 +755,14 @@ RISCV64VMTranslationMap::ProtectArea(VMArea* area, uint32 attributes)
} }
static inline uint32 static inline uint64
ConvertAccessedFlags(uint32 flags) ConvertAccessedFlags(uint32 flags)
{ {
return ((flags & PAGE_MODIFIED) ? (1 << pteDirty ) : 0) Pte pteFlags {
| ((flags & PAGE_ACCESSED) ? (1 << pteAccessed) : 0); .isAccessed = (flags & PAGE_ACCESSED) != 0,
.isDirty = (flags & PAGE_MODIFIED) != 0
};
return pteFlags.val;
} }
@@ -766,11 +772,11 @@ RISCV64VMTranslationMap::SetFlags(addr_t address, uint32 flags)
// Only called from interrupt handler with interrupts disabled for CPUs that don't support // Only called from interrupt handler with interrupts disabled for CPUs that don't support
// setting accessed/modified flags by hardware. // setting accessed/modified flags by hardware.
Pte* pte = LookupPte(address, false, NULL); std::atomic<Pte>* pte = LookupPte(address, false, NULL);
if (pte == NULL || ((1 << pteValid) & pte->flags) == 0) if (pte == NULL || !pte->load().isValid)
return; return;
pte->flags |= ConvertAccessedFlags(flags); *(std::atomic<uint64>*)pte |= ConvertAccessedFlags(flags);
if (IS_KERNEL_ADDRESS(address)) if (IS_KERNEL_ADDRESS(address))
FlushTlbPage(address); FlushTlbPage(address);
@@ -786,11 +792,11 @@ RISCV64VMTranslationMap::ClearFlags(addr_t address, uint32 flags)
{ {
ThreadCPUPinner pinner(thread_get_current_thread()); ThreadCPUPinner pinner(thread_get_current_thread());
Pte* pte = LookupPte(address, false, NULL); std::atomic<Pte>* pte = LookupPte(address, false, NULL);
if (pte == NULL || ((1 << pteValid) & pte->flags) == 0) if (pte == NULL || !pte->load().isValid)
return B_OK; return B_OK;
pte->flags &= ~ConvertAccessedFlags(flags); *(std::atomic<uint64>*)pte &= ~ConvertAccessedFlags(flags);
InvalidatePage(address); InvalidatePage(address);
return B_OK; return B_OK;
} }
@@ -807,35 +813,33 @@ RISCV64VMTranslationMap::ClearAccessedAndModified(VMArea* area, addr_t address,
RecursiveLocker locker(fLock); RecursiveLocker locker(fLock);
ThreadCPUPinner pinner(thread_get_current_thread()); ThreadCPUPinner pinner(thread_get_current_thread());
Pte* pte = LookupPte(address, false, NULL); std::atomic<Pte>* pte = LookupPte(address, false, NULL);
if (pte == NULL || ((1 << pteValid) & pte->flags) == 0) if (pte == NULL || !pte->load().isValid)
return false; return false;
Pte oldPte; Pte oldPte {};
if (unmapIfUnaccessed) { if (unmapIfUnaccessed) {
for (;;) { for (;;) {
oldPte = *pte; oldPte = pte->load();
if (((1 << pteValid) & oldPte.flags) == 0) if (!oldPte.isValid)
return false; return false;
if (((1 << pteAccessed) & oldPte.flags) != 0) { if (oldPte.isAccessed) {
oldPte.val = atomic_and64((int64*)&pte->val, oldPte.val = ((std::atomic<uint64>*)pte)->fetch_and(
~((1 << pteAccessed) | (1 << pteDirty))); ~Pte {.isAccessed = true, .isDirty = true}.val);
break; break;
} }
if (atomic_test_and_set64((int64*)&pte->val, 0, oldPte.val) if (pte->compare_exchange_strong(oldPte, {}))
== (int64)oldPte.val) {
break; break;
}
} }
} else { } else {
oldPte.val = atomic_and64((int64*)&pte->val, oldPte.val = ((std::atomic<uint64>*)pte)->fetch_and(
~((1 << pteAccessed) | (1 << pteDirty))); ~Pte {.isAccessed = true, .isDirty = true}.val);
} }
pinner.Unlock(); pinner.Unlock();
_modified = ((1 << pteDirty) & oldPte.flags) != 0; _modified = oldPte.isDirty;
if (((1 << pteAccessed) & oldPte.flags) != 0) { if (oldPte.isAccessed) {
InvalidatePage(address); InvalidatePage(address);
Flush(); Flush();
return true; return true;
@@ -9,6 +9,8 @@
#define _RISCV64VMTRANSLATIONMAP_H_ #define _RISCV64VMTRANSLATIONMAP_H_
#include <atomic>
#include <vm/VMTranslationMap.h> #include <vm/VMTranslationMap.h>
#include <arch_cpu_defs.h> #include <arch_cpu_defs.h>
#include <kernel/smp.h> #include <kernel/smp.h>
@@ -97,7 +99,7 @@ struct RISCV64VMTranslationMap: public VMTranslationMap {
inline void InvalidatePage(addr_t address); inline void InvalidatePage(addr_t address);
private: private:
Pte* LookupPte(addr_t virtAdr, bool alloc, std::atomic<Pte>* LookupPte(addr_t virtAdr, bool alloc,
vm_page_reservation* reservation); vm_page_reservation* reservation);
phys_addr_t LookupAddr(addr_t virtAdr); phys_addr_t LookupAddr(addr_t virtAdr);
+15 -16
View File
@@ -36,7 +36,7 @@ LookupPte(phys_addr_t pageTable, addr_t virtAdr)
Pte *pte = (Pte*)VirtFromPhys(pageTable); Pte *pte = (Pte*)VirtFromPhys(pageTable);
for (int level = 2; level > 0; level --) { for (int level = 2; level > 0; level --) {
pte += VirtAdrPte(virtAdr, level); pte += VirtAdrPte(virtAdr, level);
if (!((1 << pteValid) & pte->flags)) { if (!pte->isValid) {
return NULL; return NULL;
} }
// TODO: Handle superpages (RWX=0 when not at lowest level) // TODO: Handle superpages (RWX=0 when not at lowest level)
@@ -61,28 +61,28 @@ WritePteFlags(uint32 flags)
dprintf(", "); dprintf(", ");
switch (i) { switch (i) {
case pteValid: case 0:
dprintf("valid"); dprintf("valid");
break; break;
case pteRead: case 1:
dprintf("read"); dprintf("read");
break; break;
case pteWrite: case 2:
dprintf("write"); dprintf("write");
break; break;
case pteExec: case 3:
dprintf("exec"); dprintf("exec");
break; break;
case pteUser: case 4:
dprintf("user"); dprintf("user");
break; break;
case pteGlobal: case 5:
dprintf("global"); dprintf("global");
break; break;
case pteAccessed: case 6:
dprintf("accessed"); dprintf("accessed");
break; break;
case pteDirty: case 7:
dprintf("dirty"); dprintf("dirty");
break; break;
default: default:
@@ -140,9 +140,8 @@ static void
DumpPageTableInt(Pte* pte, uint64_t virtAdr, uint32_t level, PageTableDumper& dumper) DumpPageTableInt(Pte* pte, uint64_t virtAdr, uint32_t level, PageTableDumper& dumper)
{ {
for (uint32 i = 0; i < pteCount; i++) { for (uint32 i = 0; i < pteCount; i++) {
if (((1 << pteValid) & pte[i].flags) != 0) { if (pte[i].isValid) {
if ((((1 << pteRead) | (1 << pteWrite) if (!pte[i].isRead && !pte[i].isWrite && !pte[i].isExec) {
| (1 << pteExec)) & pte[i].flags) == 0) {
if (level == 0) if (level == 0)
kprintf(" internal page table on level 0\n"); kprintf(" internal page table on level 0\n");
@@ -154,7 +153,7 @@ DumpPageTableInt(Pte* pte, uint64_t virtAdr, uint32_t level, PageTableDumper& du
dumper.Write(SignExtendVirtAdr(virtAdr dumper.Write(SignExtendVirtAdr(virtAdr
+ ((uint64_t)i << (pageBits + pteIdxBits*level))), + ((uint64_t)i << (pageBits + pteIdxBits*level))),
pte[i].ppn * B_PAGE_SIZE, 1 << (pageBits + pteIdxBits * level), pte[i].ppn * B_PAGE_SIZE, 1 << (pageBits + pteIdxBits * level),
pte[i].flags); pte[i].val & 0xff);
} }
} }
} }
@@ -215,10 +214,10 @@ DumpPageTable(int argc, char** argv)
} else { } else {
for (; size > 0; base += B_PAGE_SIZE, size -= B_PAGE_SIZE) { for (; size > 0; base += B_PAGE_SIZE, size -= B_PAGE_SIZE) {
Pte* pte = LookupPte(satp.ppn * B_PAGE_SIZE, base); Pte* pte = LookupPte(satp.ppn * B_PAGE_SIZE, base);
if (pte == NULL || (pte->flags & (1 << pteValid)) == 0) if (pte == NULL || !pte->isValid)
continue; continue;
dumper.Write(base, pte->ppn * B_PAGE_SIZE, B_PAGE_SIZE, pte->flags); dumper.Write(base, pte->ppn * B_PAGE_SIZE, B_PAGE_SIZE, pte->val & 0xff);
} }
} }
@@ -265,7 +264,7 @@ DumpVirtPage(int argc, char** argv)
} }
PageTableDumper dumper; PageTableDumper dumper;
dumper.Write(virt, pte->ppn * B_PAGE_SIZE, B_PAGE_SIZE, pte->flags); dumper.Write(virt, pte->ppn * B_PAGE_SIZE, B_PAGE_SIZE, pte->val & 0xff);
return 0; return 0;
} }
@@ -48,14 +48,19 @@ LookupPte(addr_t virtAdr, bool alloc, kernel_args* args,
Pte *pte = (Pte*)VirtFromPhys(sPageTable); Pte *pte = (Pte*)VirtFromPhys(sPageTable);
for (int level = 2; level > 0; level --) { for (int level = 2; level > 0; level --) {
pte += VirtAdrPte(virtAdr, level); pte += VirtAdrPte(virtAdr, level);
if (!((1 << pteValid) & pte->flags)) { if (!pte->isValid) {
if (!alloc) if (!alloc)
return NULL; return NULL;
pte->ppn = get_free_page(args); page_num_t ppn = get_free_page(args);
if (pte->ppn == 0) if (ppn == 0)
return NULL; return NULL;
memset((Pte*)VirtFromPhys(B_PAGE_SIZE * pte->ppn), 0, B_PAGE_SIZE); memset((Pte*)VirtFromPhys(B_PAGE_SIZE * ppn), 0, B_PAGE_SIZE);
pte->flags |= (1 << pteValid) | (1 << pteGlobal); Pte newPte {
.isValid = true,
.isGlobal = true,
.ppn = ppn
};
pte->val = newPte.val;
} }
pte = (Pte*)VirtFromPhys(B_PAGE_SIZE * pte->ppn); pte = (Pte*)VirtFromPhys(B_PAGE_SIZE * pte->ppn);
} }
@@ -72,10 +77,16 @@ Map(addr_t virtAdr, phys_addr_t physAdr, uint64 flags, kernel_args* args,
Pte* pte = LookupPte(virtAdr, true, args, get_free_page); Pte* pte = LookupPte(virtAdr, true, args, get_free_page);
if (pte == NULL) panic("can't allocate page table"); if (pte == NULL) panic("can't allocate page table");
pte->ppn = physAdr / B_PAGE_SIZE; Pte newPte {
pte->flags = (1 << pteValid) | (1 << pteAccessed) | (1 << pteDirty) .isValid = true,
| (1 << pteGlobal) // we map only kernel pages here so always set global flag .isGlobal = true, // we map only kernel pages here so always set global flag
| flags; .isAccessed = true,
.isDirty = true,
.ppn = physAdr / B_PAGE_SIZE
};
newPte.val |= flags;
pte->val = newPte.val;
FlushTlbPage(virtAdr); FlushTlbPage(virtAdr);
} }
@@ -155,14 +166,12 @@ arch_vm_translation_map_early_map(kernel_args *args,
phys_addr_t (*get_free_page)(kernel_args *)) phys_addr_t (*get_free_page)(kernel_args *))
{ {
//dprintf("early_map(%#" B_PRIxADDR ", %#" B_PRIxADDR ")\n", virtAdr, physAdr); //dprintf("early_map(%#" B_PRIxADDR ", %#" B_PRIxADDR ")\n", virtAdr, physAdr);
uint64 flags = 0; Pte flags {
if ((attributes & B_KERNEL_READ_AREA) != 0) .isRead = (attributes & B_KERNEL_READ_AREA) != 0,
flags |= (1 << pteRead); .isWrite = (attributes & B_KERNEL_WRITE_AREA) != 0,
if ((attributes & B_KERNEL_WRITE_AREA) != 0) .isExec = (attributes & B_KERNEL_EXECUTE_AREA) != 0,
flags |= (1 << pteWrite); };
if ((attributes & B_KERNEL_EXECUTE_AREA) != 0) Map(virtAdr, physAdr, flags.val, args, get_free_page);
flags |= (1 << pteExec);
Map(virtAdr, physAdr, flags, args, get_free_page);
return B_OK; return B_OK;
} }