1# 2# Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3# 4# SPDX-License-Identifier: GPL-2.0-only 5# 6from typing import List, Set 7from hardware.memory import Region 8 9 10class Config: 11 ''' Abstract config class ''' 12 arch = 'unknown' 13 14 def __init__(self, addrspace_max): 15 self.addrspace_max = addrspace_max 16 17 def get_kernel_phys_align(self) -> int: 18 ''' Used to align the base of physical memory. Returns alignment size in bits. ''' 19 return 0 20 21 def get_bootloader_reserve(self) -> int: 22 ''' Used to reserve a fixed amount of memory for the bootloader. Offsets 23 the kernel load address by the amount returned in bytes. ''' 24 return 0 25 26 def get_page_bits(self) -> int: 27 ''' Get page size in bits for this arch ''' 28 return 12 # 4096-byte pages 29 30 def get_smallest_kernel_object_alignment(self) -> int: 31 return 4 # seL4_MinUntypedBits is 4 for all configurations 32 33 def get_device_page_bits(self) -> int: 34 ''' Get page size in bits for mapping devices for this arch ''' 35 return self.get_page_bits() 36 37 def align_memory(self, regions: Set[Region]) -> List[Region]: 38 ''' Given a set of regions, sort them and align the first so that the 39 ELF loader will be able to load the kernel into it. Will return the 40 aligned memory region list, a set of any regions of memory that were 41 aligned out and the physBase value that the kernel will use. memory 42 region list, a set of any regions of memory that were aligned out and 43 the physBase value that the kernel will use. ''' 44 pass 45 46 47class ARMConfig(Config): 48 ''' Config class for ARM ''' 49 SUPERSECTION_BITS = 24 50 arch = 'arm' 51 52 def get_kernel_phys_align(self) -> int: 53 ''' on ARM the ELF loader expects to be able to map a supersection page to load the kernel. ''' 54 return self.SUPERSECTION_BITS 55 56 def align_memory(self, regions: Set[Region]) -> List[Region]: 57 ''' Arm wants physBase to be the physical load address of the kernel. ''' 58 ret = sorted(regions) 59 extra_reserved = set() 60 61 new = ret[0].align_base(self.get_kernel_phys_align()) 62 resv = Region(ret[0].base, new.base - ret[0].base) 63 extra_reserved.add(resv) 64 ret[0] = new 65 66 physBase = ret[0].base 67 68 return ret, extra_reserved, physBase 69 70 71class RISCVConfig(Config): 72 ''' Config class for RISCV ''' 73 MEGA_PAGE_SIZE = 0x200000 74 arch = 'riscv' 75 76 def get_bootloader_reserve(self) -> int: 77 ''' on RISC-V OpenSBI is loaded at the start 78 of physical memory. Mark it as unavailable. ''' 79 return self.MEGA_PAGE_SIZE 80 81 def align_memory(self, regions: Set[Region]) -> List[Region]: 82 ''' Currently the RISC-V port expects physBase to be the address that the 83 bootloader is loaded at. To be generalised in the future. ''' 84 ret = sorted(regions) 85 extra_reserved = set() 86 87 physBase = ret[0].base 88 89 resv = Region(ret[0].base, self.get_bootloader_reserve()) 90 extra_reserved.add(resv) 91 ret[0].base += self.get_bootloader_reserve() 92 ret[0].size -= self.get_bootloader_reserve() 93 94 return ret, extra_reserved, physBase 95 96 def get_device_page_bits(self) -> int: 97 ''' Get page size in bits for mapping devices for this arch ''' 98 if self.addrspace_max > (1 << 32): 99 # rv39 and rv48 use 2MiB device pages 100 return 21 101 else: 102 # rv32 uses 4MiB device pages 103 return 22 104 105 106def get_arch_config(arch: str, addrspace_max: int) -> Config: 107 ''' Return an appropriate Config object for the given architecture ''' 108 if arch == 'arm': 109 return ARMConfig(addrspace_max) 110 elif arch == 'riscv': 111 return RISCVConfig(addrspace_max) 112 raise ValueError('Unsupported arch specified.') 113