boot2

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

mmu.c (2751B)


      1 /* aarch64 stage-1 MMU setup for QEMU virt. */
      2 
      3 typedef unsigned long u64;
      4 typedef unsigned int u32;
      5 typedef unsigned char u8;
      6 
      7 #include "arch.h"
      8 
      9 __attribute__((aligned(4096))) static u64 l1_pt[512];
     10 __attribute__((aligned(4096))) static u64 l2_user[512];
     11 
     12 static u64 pool_pa(int which) {
     13     return which ? ARCH_USER_POOL_B_PA : ARCH_USER_POOL_A_PA;
     14 }
     15 
     16 void arch_setup_mmu(void) {
     17     /* Block-descriptor attribute bits (block at L1 = bit[1]=0).
     18      *   V(0)=1, block(1)=0, AttrIdx[4:2]=Attr0(Normal)/Attr1(Device),
     19      *   NS(5)=0, AP[7:6]=00 (RW EL1 only), SH[9:8]=11 (ISH), AF(10)=1,
     20      *   nG(11)=0 -> 0x701 (Normal) / 0x705 (Device-nGnRnE).
     21      * Block descriptors at L2 use the same bit layout. */
     22     u64 normal = 0x701;
     23     u64 device = 0x705;
     24 
     25     for (int i = 0; i < 512; i++) l1_pt[i] = 0;
     26 
     27     l2_user[0] = 0;
     28     for (int i = ARCH_USER_POOL_FIRST_SLOT; i <= ARCH_USER_POOL_LAST_SLOT; i++) {
     29         u64 pa = ARCH_USER_POOL_A_PA + (u64)(i - ARCH_USER_POOL_FIRST_SLOT) * 0x200000UL;
     30         l2_user[i] = pa | normal;
     31     }
     32     for (int i = ARCH_USER_POOL_LAST_SLOT + 1; i < 512; i++) {
     33         u64 pa = (u64)i * 0x200000UL;
     34         l2_user[i] = pa | device;
     35     }
     36 
     37     l1_pt[0] = (u64)l2_user | 0x3UL;
     38     l1_pt[1] = 0x40000000UL | normal;
     39     l1_pt[2] = 0x80000000UL | normal;
     40     l1_pt[3] = 0xc0000000UL | normal;
     41     l1_pt[4] = 0x00000000UL | device;
     42 
     43     sysreg_write(SR_MAIR_EL1, 0x00000000000000ffUL);
     44 
     45     u64 tcr = (u64)25                /* T0SZ: 39-bit VA */
     46             | ((u64)1 << 8)          /* IRGN0 = WBWA */
     47             | ((u64)1 << 10)         /* ORGN0 = WBWA */
     48             | ((u64)3 << 12)         /* SH0   = inner shareable */
     49             | ((u64)0 << 14)         /* TG0   = 4KB */
     50             | ((u64)1 << 23)         /* EPD1  = disable TTBR1 walks */
     51             | ((u64)2 << 32);        /* IPS   = 40-bit phys */
     52     sysreg_write(SR_TCR_EL1, tcr);
     53     sysreg_write(SR_TTBR0_EL1, (u64)l1_pt);
     54 
     55     arm64_ic_iallu();
     56     arm64_barrier(BAR_DSB_ISH);
     57     arm64_tlbi_vmalle1();
     58     arm64_barrier(BAR_DSB_ISH);
     59     arm64_barrier(BAR_ISB);
     60 
     61     u64 sctlr = sysreg_read(SR_SCTLR_EL1);
     62     sctlr &= ~(u64)((1 << 1) | (1 << 19));
     63     sctlr |=  (u64)((1 << 0) | (1 << 2) | (1 << 12));
     64     sysreg_write(SR_SCTLR_EL1, sctlr);
     65     arm64_barrier(BAR_ISB);
     66 
     67     sysreg_write(SR_CPACR_EL1, (u64)3 << 20);
     68     arm64_barrier(BAR_ISB);
     69 }
     70 
     71 void arch_swap_user_pool(int which) {
     72     u64 normal = 0x701;
     73     u64 base = pool_pa(which);
     74     for (int i = ARCH_USER_POOL_FIRST_SLOT; i <= ARCH_USER_POOL_LAST_SLOT; i++) {
     75         l2_user[i] = (base + (u64)(i - ARCH_USER_POOL_FIRST_SLOT) * 0x200000UL) | normal;
     76     }
     77     arm64_barrier(BAR_DSB_ISH);
     78     arm64_tlbi_vmalle1();
     79     arm64_barrier(BAR_DSB_ISH);
     80     arm64_barrier(BAR_ISB);
     81 }