mirror of
https://github.com/seL4/seL4.git
synced 2026-03-27 10:29:57 +00:00
riscv: Map devices with large pages on 32 & 64-bit
For 64-bit, this adds a 2nd-level page table for mapping devices using 2MiB frames instead of 1GiB frames. The boot mapping and hardware header generator have also been fixed to correctly report the number of large frames needed for devices rather than only reporting the first. The frame size is also specified correctly (rather than assuming mapping with 4KiB frames). This likely fixes an issue whereby only the first 4KiB frame of a device was reserved but the remaining region of that kernel device could be mapped at user level. Signed-off-by: Curtis Millar <curtis.millar@data61.csiro.au>
This commit is contained in:
committed by
Curtis Millar
parent
8e57add854
commit
ab3d8c44cb
@@ -31,5 +31,6 @@ extern pte_t kernel_root_pageTable[BIT(PT_INDEX_BITS)] VISIBLE;
|
||||
* page entry to avoid PMP exception. */
|
||||
#if __riscv_xlen != 32
|
||||
extern pte_t kernel_image_level2_pt[BIT(PT_INDEX_BITS)];
|
||||
extern pte_t kernel_image_level2_dev_pt[BIT(PT_INDEX_BITS)];
|
||||
#endif
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* https://static.dev.sifive.com/U54-MC-RVCoreIP.pdf
|
||||
*/
|
||||
|
||||
#define PLIC_PPTR_BASE (PLIC_PPTR + 0x0C000000)
|
||||
#define PLIC_PPTR_BASE PLIC_PPTR
|
||||
|
||||
|
||||
#define PLIC_HART_ID (CONFIG_FIRST_HART_ID)
|
||||
|
||||
@@ -85,9 +85,22 @@ static pte_t pte_next(word_t phys_addr, bool_t is_leaf)
|
||||
|
||||
BOOT_CODE void map_kernel_frame(paddr_t paddr, pptr_t vaddr, vm_rights_t vm_rights)
|
||||
{
|
||||
#if __riscv_xlen == 32
|
||||
paddr = ROUND_DOWN(paddr, RISCV_GET_LVL_PGSIZE_BITS(0));
|
||||
assert((paddr % RISCV_GET_LVL_PGSIZE(0)) == 0);
|
||||
kernel_root_pageTable[RISCV_GET_PT_INDEX(vaddr, 0)] = pte_next(paddr, true);
|
||||
#else
|
||||
if (vaddr >= KDEV_BASE) {
|
||||
/* Map devices in 2nd-level page table */
|
||||
paddr = ROUND_DOWN(paddr, RISCV_GET_LVL_PGSIZE_BITS(1));
|
||||
assert((paddr % RISCV_GET_LVL_PGSIZE(1)) == 0);
|
||||
kernel_image_level2_dev_pt[RISCV_GET_PT_INDEX(vaddr, 1)] = pte_next(paddr, true);
|
||||
} else {
|
||||
paddr = ROUND_DOWN(paddr, RISCV_GET_LVL_PGSIZE_BITS(0));
|
||||
assert((paddr % RISCV_GET_LVL_PGSIZE(0)) == 0);
|
||||
kernel_root_pageTable[RISCV_GET_PT_INDEX(vaddr, 0)] = pte_next(paddr, true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOT_CODE VISIBLE void map_kernel_window(void)
|
||||
@@ -133,6 +146,10 @@ BOOT_CODE VISIBLE void map_kernel_window(void)
|
||||
pptr += RISCV_GET_LVL_PGSIZE(1);
|
||||
paddr += RISCV_GET_LVL_PGSIZE(1);
|
||||
}
|
||||
|
||||
/* Map kernel device page table */
|
||||
kernel_root_pageTable[RISCV_GET_PT_INDEX(KDEV_BASE, 0)] =
|
||||
pte_next(kpptr_to_paddr(kernel_image_level2_dev_pt), false);
|
||||
#endif
|
||||
|
||||
/* There should be 1GiB free where we put device mapping */
|
||||
|
||||
@@ -55,12 +55,12 @@ BOOT_CODE void map_kernel_devices(void)
|
||||
}
|
||||
|
||||
for (int i = 0; i < (sizeof(kernel_devices) / sizeof(kernel_frame_t)); i++) {
|
||||
map_kernel_frame(kernel_devices[i].paddr, KDEV_BASE,
|
||||
map_kernel_frame(kernel_devices[i].paddr, kernel_devices[i].pptr,
|
||||
VMKernelOnly);
|
||||
if (!kernel_devices[i].userAvailable) {
|
||||
p_region_t reg = {
|
||||
.start = kernel_devices[i].paddr,
|
||||
.end = kernel_devices[i].paddr + (1 << PAGE_BITS),
|
||||
.end = kernel_devices[i].paddr + (1 << seL4_LargePageBits),
|
||||
};
|
||||
reserve_region(reg);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ pte_t kernel_root_pageTable[BIT(PT_INDEX_BITS)] ALIGN_BSS(BIT(seL4_PageTableBits
|
||||
|
||||
#if __riscv_xlen != 32
|
||||
pte_t kernel_image_level2_pt[BIT(PT_INDEX_BITS)] ALIGN_BSS(BIT(seL4_PageTableBits));
|
||||
pte_t kernel_image_level2_dev_pt[BIT(PT_INDEX_BITS)] ALIGN_BSS(BIT(seL4_PageTableBits));
|
||||
#endif
|
||||
|
||||
SMP_STATE_DEFINE(core_map_t, coreMap);
|
||||
|
||||
@@ -245,6 +245,7 @@ devices:
|
||||
regions:
|
||||
- index: 0
|
||||
kernel: PLIC_PPTR
|
||||
kernel_size: 0x04000000
|
||||
|
||||
# elfloader rules
|
||||
- compatible:
|
||||
|
||||
@@ -25,6 +25,10 @@ class Config:
|
||||
''' Get page size in bits for this arch '''
|
||||
return 12 # 4096-byte pages
|
||||
|
||||
def get_device_page_bits(self) -> int:
|
||||
''' Get page size in bits for mapping devices for this arch '''
|
||||
return self.get_page_bits()
|
||||
|
||||
|
||||
class ARMConfig(Config):
|
||||
''' Config class for ARM '''
|
||||
@@ -46,6 +50,15 @@ class RISCVConfig(Config):
|
||||
of physical memory. Mark it as unavailable. '''
|
||||
return self.MEGA_PAGE_SIZE
|
||||
|
||||
def get_device_page_bits(self) -> int:
|
||||
''' Get page size in bits for mapping devices for this arch '''
|
||||
if self.addrspace_max > (1 << 32):
|
||||
# rv39 and rv48 use 2MiB device pages
|
||||
return 21
|
||||
else:
|
||||
# rv32 uses 4MiB device pages
|
||||
return 22
|
||||
|
||||
|
||||
def get_arch_config(arch: str, addrspace_max: int) -> Config:
|
||||
''' Return an appropriate Config object for the given architecture '''
|
||||
|
||||
@@ -168,14 +168,14 @@ class DeviceRule:
|
||||
kernel_name = rule['kernel']
|
||||
user = rule.get('user', False)
|
||||
macro = rule.get('macro', None)
|
||||
max_size = 1 << self.config.get_page_bits()
|
||||
max_size = 1 << self.config.get_device_page_bits()
|
||||
if 'kernel_size' in rule:
|
||||
max_size = rule['kernel_size']
|
||||
elif max_size < reg.size:
|
||||
logging.warning(
|
||||
"Only mapping {}/{} bytes from node {}, region {}. Set kernel_size in YAML to silence.".format(max_size, reg.size, node.path, i))
|
||||
ret.append(KernelRegionGroup(reg, kernel_name,
|
||||
self.config.get_page_bits(), max_size, macro, user))
|
||||
self.config.get_device_page_bits(), max_size, macro, user))
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
Reference in New Issue
Block a user