boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

mmu.c (2523B)


      1 typedef unsigned long u64;
      2 typedef unsigned int u32;
      3 typedef unsigned char u8;
      4 
      5 #include "arch.h"
      6 
      7 #define PTE_V 0x001UL
      8 #define PTE_R 0x002UL
      9 #define PTE_W 0x004UL
     10 #define PTE_X 0x008UL
     11 #define PTE_U 0x010UL
     12 #define PTE_G 0x020UL
     13 #define PTE_A 0x040UL
     14 #define PTE_D 0x080UL
     15 
     16 #define KFLAGS (PTE_V | PTE_R | PTE_W | PTE_X | PTE_A | PTE_D)
     17 #define DFLAGS (PTE_V | PTE_R | PTE_W | PTE_A | PTE_D)
     18 #define UFLAGS (PTE_V | PTE_R | PTE_W | PTE_X | PTE_U | PTE_A | PTE_D)
     19 
     20 __attribute__((aligned(4096))) static u64 l2_root[512];
     21 __attribute__((aligned(4096))) static u64 l1_user[512];
     22 
     23 extern void riscv_write_satp(u64 v);
     24 extern void riscv_set_sum(void);
     25 
     26 static u64 pte(u64 pa, u64 flags) {
     27     return (pa >> 2) | flags;
     28 }
     29 
     30 static u64 pool_pa(int which) {
     31     return which ? ARCH_USER_POOL_B_PA : ARCH_USER_POOL_A_PA;
     32 }
     33 
     34 static void fill_user_l1(int which) {
     35     for (int i = 0; i < 512; i++) {
     36         u64 pa = (u64)i * 0x200000UL;
     37         l1_user[i] = pte(pa, DFLAGS);
     38     }
     39     u64 base = pool_pa(which);
     40     for (int i = ARCH_USER_POOL_FIRST_SLOT; i <= ARCH_USER_POOL_LAST_SLOT; i++) {
     41         u64 pa = base + (u64)(i - ARCH_USER_POOL_FIRST_SLOT) * 0x200000UL;
     42         l1_user[i] = pte(pa, UFLAGS);
     43     }
     44 }
     45 
     46 void arch_setup_mmu(void) {
     47     for (int i = 0; i < 512; i++) l2_root[i] = 0;
     48     fill_user_l1(0);
     49 
     50     l2_root[0] = pte((u64)l1_user, PTE_V);
     51     l2_root[1] = pte(0x40000000UL,  DFLAGS);
     52     /* VA == PA identity map for kernel-side DRAM, slot per 1 GiB.
     53      * Covers PA 0x80000000 .. 0x1ffffffff (6 GiB), enough for QEMU
     54      * virt configurations up to ~6 GiB of RAM. The DTB lives near
     55      * the top of physical RAM (e.g. 0x13fe00000 with -m 3072M); we
     56      * read it via VA = dtb_phys, so it must fall inside this map. */
     57     l2_root[2] = pte(0x80000000UL,  KFLAGS);
     58     l2_root[3] = pte(0xc0000000UL,  KFLAGS);
     59     l2_root[4] = pte(0x100000000UL, KFLAGS);
     60     l2_root[5] = pte(0x140000000UL, KFLAGS);
     61     l2_root[6] = pte(0x180000000UL, KFLAGS);
     62     l2_root[7] = pte(0x1c0000000UL, KFLAGS);
     63     /* Device alias: VA ARCH_DEVICE_ALIAS_BASE + PA → PA, used by
     64      * arch_mmio_ptr / arch_console_putc to reach UART + virtio-mmio
     65      * regs whose low-PA addresses overlap the user pool L1 slots.
     66      * Lives well above the direct-map kernel window. */
     67     l2_root[8] = pte(0x00000000UL,  DFLAGS);
     68 
     69     riscv_set_sum();
     70     riscv_write_satp(((u64)8 << 60) | ((u64)l2_root >> 12));
     71 }
     72 
     73 void arch_swap_user_pool(int which) {
     74     fill_user_l1(which);
     75     riscv_write_satp(((u64)8 << 60) | ((u64)l2_root >> 12));
     76 }