boot2

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

kernel.S (7291B)


      1 .section .text, "ax"
      2 
      3 #ifdef __TINYC__
      4 /* tcc 0.9.26's riscv64 assembler doesn't accept GAS's `off(reg)` form
      5  * for ld/sd/sw and parses three-comma operands as `<rs1>, <rs2>, <imm>`,
      6  * where rs1 is the base for both loads (rd ← [rs1+imm]) and stores
      7  * ([rs1+imm] ← rs2).  So `SD(rs, base, off)` must emit base FIRST. */
      8 #define LA(rd, sym) lla rd, sym
      9 #define LD(rd, base, off) ld rd, base, off
     10 #define SD(rs, base, off) sd base, rs, off
     11 #define SW(rs, base, off) sw base, rs, off
     12 #define J(label) jal zero, label
     13 #define RET jalr zero, ra, 0
     14 #define CSRW_STVEC_T0 .long 0x10529073
     15 #define CSRRW_SP_SSCRATCH_SP .long 0x14011173
     16 #define CSRR_T0_SSCRATCH .long 0x140022f3
     17 #define CSRR_T0_SEPC .long 0x141022f3
     18 #define CSRR_A0_SCAUSE .long 0x14202573
     19 #define CSRR_T0_SSTATUS .long 0x100022f3
     20 #define CSRW_SEPC_T0 .long 0x14129073
     21 #define CSRW_SSTATUS_T0 .long 0x10029073
     22 #define CSRW_SSCRATCH_T1 .long 0x14031073
     23 #define CSRW_SSCRATCH_T0 .long 0x14029073
     24 #define CSRW_SEPC_A0 .long 0x14151073
     25 #define CSRR_A0_STVAL .long 0x14302573
     26 #define CSRW_SATP_A0 .long 0x18051073
     27 #define SFENCE_VMA .long 0x12000073
     28 #define FENCE_I .long 0x0000100f
     29 #define FENCE_W_W .long 0x0110000f
     30 #define FENCE_R_R .long 0x0220000f
     31 #define SRET .long 0x10200073
     32 #define NOP .long 0x00000013
     33 #else
     34 #define LA(rd, sym) la rd, sym
     35 #define LD(rd, base, off) ld rd, off(base)
     36 #define SD(rs, base, off) sd rs, off(base)
     37 #define SW(rs, base, off) sw rs, off(base)
     38 #define J(label) j label
     39 #define RET ret
     40 #define CSRW_STVEC_T0 csrw stvec, t0
     41 #define CSRRW_SP_SSCRATCH_SP csrrw sp, sscratch, sp
     42 #define CSRR_T0_SSCRATCH csrr t0, sscratch
     43 #define CSRR_T0_SEPC csrr t0, sepc
     44 #define CSRR_A0_SCAUSE csrr a0, scause
     45 #define CSRR_T0_SSTATUS csrr t0, sstatus
     46 #define CSRW_SEPC_T0 csrw sepc, t0
     47 #define CSRW_SSTATUS_T0 csrw sstatus, t0
     48 #define CSRW_SSCRATCH_T1 csrw sscratch, t1
     49 #define CSRW_SSCRATCH_T0 csrw sscratch, t0
     50 #define CSRW_SEPC_A0 csrw sepc, a0
     51 #define CSRR_A0_STVAL csrr a0, stval
     52 #define CSRW_SATP_A0 csrw satp, a0
     53 #define SFENCE_VMA sfence.vma
     54 #define FENCE_I fence.i
     55 #define FENCE_W_W fence w, w
     56 #define FENCE_R_R fence r, r
     57 #define SRET sret
     58 #define NOP nop
     59 #endif
     60 
     61 .globl _start
     62 _start:
     63     mv      s0, a1
     64     LA(sp, kstack_top)
     65     LA(t0, trap_entry)
     66     CSRW_STVEC_T0
     67 
     68     LA(t0, __bss_start)
     69     LA(t1, _end)
     70 1:
     71 #ifdef __TINYC__
     72     bgeu    t0, t1, 16
     73 #else
     74     bgeu    t0, t1, 2f
     75 #endif
     76     SD(zero, t0, 0)
     77     addi    t0, t0, 8
     78     J(1b)
     79 2:
     80     mv      a0, s0
     81     jal     ra, kmain
     82 3:
     83     wfi
     84     J(3b)
     85 
     86 .align 2
     87 .globl trap_entry
     88 trap_entry:
     89     CSRRW_SP_SSCRATCH_SP
     90     addi    sp, sp, -272
     91 
     92     /* Save user regs first — including t0 (x5) and t1 (x6) — *before*
     93      * we clobber them for trap-entry bookkeeping.  Linux's RISC-V
     94      * syscall ABI preserves every GPR except a0; if t0/t1 carry caller
     95      * state across an ecall, they must be restored.  trap_entry's own
     96      * scratch must therefore come out of a register the kernel has
     97      * already preserved on the stack. */
     98     SD(x1, sp, 8)
     99     SD(x3, sp, 24)
    100     SD(x4, sp, 32)
    101     SD(x5, sp, 40)
    102     SD(x6, sp, 48)
    103     /* t0 and t1 are now in tf->x[5]/tf->x[6]; safe to clobber. */
    104     CSRR_T0_SSCRATCH
    105     SD(t0, sp, 16)
    106     LA(t1, saved_user_sp)
    107     SD(t0, t1, 0)
    108     SD(x7, sp, 56)
    109     SD(x8, sp, 64)
    110     SD(x9, sp, 72)
    111     SD(x10, sp, 80)
    112     SD(x11, sp, 88)
    113     SD(x12, sp, 96)
    114     SD(x13, sp, 104)
    115     SD(x14, sp, 112)
    116     SD(x15, sp, 120)
    117     SD(x16, sp, 128)
    118     SD(x17, sp, 136)
    119     SD(x18, sp, 144)
    120     SD(x19, sp, 152)
    121     SD(x20, sp, 160)
    122     SD(x21, sp, 168)
    123     SD(x22, sp, 176)
    124     SD(x23, sp, 184)
    125     SD(x24, sp, 192)
    126     SD(x25, sp, 200)
    127     SD(x26, sp, 208)
    128     SD(x27, sp, 216)
    129     SD(x28, sp, 224)
    130     SD(x29, sp, 232)
    131     SD(x30, sp, 240)
    132     SD(x31, sp, 248)
    133 
    134     CSRR_T0_SEPC
    135     CSRR_A0_SCAUSE
    136     li      t1, 8
    137 #ifdef __TINYC__
    138     bne     a0, t1, 8
    139 #else
    140     bne     a0, t1, 4f
    141 #endif
    142     addi    t0, t0, 4
    143 4:
    144     SD(t0, sp, 256)
    145     CSRR_T0_SSTATUS
    146     SD(t0, sp, 264)
    147 
    148     mv      a1, sp
    149     jal     ra, trap_sync
    150 
    151     LD(t0, sp, 256)
    152     CSRW_SEPC_T0
    153     LD(t0, sp, 264)
    154     CSRW_SSTATUS_T0
    155 
    156     LD(x1, sp, 8)
    157     LD(x3, sp, 24)
    158     LD(x4, sp, 32)
    159     LD(x7, sp, 56)
    160     LD(x8, sp, 64)
    161     LD(x9, sp, 72)
    162     LD(x10, sp, 80)
    163     LD(x11, sp, 88)
    164     LD(x12, sp, 96)
    165     LD(x13, sp, 104)
    166     LD(x14, sp, 112)
    167     LD(x15, sp, 120)
    168     LD(x16, sp, 128)
    169     LD(x17, sp, 136)
    170     LD(x18, sp, 144)
    171     LD(x19, sp, 152)
    172     LD(x20, sp, 160)
    173     LD(x21, sp, 168)
    174     LD(x22, sp, 176)
    175     LD(x23, sp, 184)
    176     LD(x24, sp, 192)
    177     LD(x25, sp, 200)
    178     LD(x26, sp, 208)
    179     LD(x27, sp, 216)
    180     LD(x28, sp, 224)
    181     LD(x29, sp, 232)
    182     LD(x30, sp, 240)
    183     LD(x31, sp, 248)
    184 
    185     LA(t0, saved_user_sp)
    186     LD(t1, t0, 0)
    187     CSRW_SSCRATCH_T1
    188     LD(x5, sp, 40)
    189     LD(x6, sp, 48)
    190     addi    sp, sp, 272
    191     CSRRW_SP_SSCRATCH_SP
    192     SRET
    193 
    194 .globl eret_to_user
    195 eret_to_user:
    196     LA(t0, saved_user_sp)
    197     SD(a1, t0, 0)
    198     LA(t0, kstack_top)
    199     CSRW_SSCRATCH_T0
    200     CSRW_SEPC_A0
    201     CSRR_T0_SSTATUS
    202     li      t1, -257
    203     and     t0, t0, t1
    204     lui     t1, 0x40
    205     addi    t1, t1, 32
    206     or      t0, t0, t1
    207     CSRW_SSTATUS_T0
    208     mv      sp, a1
    209     li      ra, 0
    210     li      gp, 0
    211     li      tp, 0
    212     li      t0, 0
    213     li      t1, 0
    214     li      t2, 0
    215     li      s0, 0
    216     li      s1, 0
    217     li      a0, 0
    218     li      a1, 0
    219     li      a2, 0
    220     li      a3, 0
    221     li      a4, 0
    222     li      a5, 0
    223     li      a6, 0
    224     li      a7, 0
    225     li      s2, 0
    226     li      s3, 0
    227     li      s4, 0
    228     li      s5, 0
    229     li      s6, 0
    230     li      s7, 0
    231     li      s8, 0
    232     li      s9, 0
    233     li      s10, 0
    234     li      s11, 0
    235     li      t3, 0
    236     li      t4, 0
    237     li      t5, 0
    238     li      t6, 0
    239     SRET
    240 
    241 /* C-callable thunks. arch.h synthesizes the arch_*() API on top of these
    242  * (mirrors aarch64's sysreg_read/arm64_barrier/cpu_pause primitive set). */
    243 
    244 /* PAUSE_* — matches arch.h enum. */
    245 .globl cpu_pause
    246 cpu_pause:
    247     li      t0, 1                  /* PAUSE_WFI */
    248 #ifdef __TINYC__
    249     beq     a0, t0, 12
    250 #else
    251     beq     a0, t0, 1f
    252 #endif
    253     NOP
    254     RET
    255 1:
    256     wfi
    257     RET
    258 
    259 /* BAR_* — matches arch.h enum. */
    260 .globl riscv_fence
    261 riscv_fence:
    262     li      t0, 1                  /* BAR_RMB */
    263 #ifdef __TINYC__
    264     beq     a0, t0, 28
    265 #else
    266     beq     a0, t0, 1f
    267 #endif
    268     li      t0, 2                  /* BAR_ICACHE */
    269 #ifdef __TINYC__
    270     beq     a0, t0, 28
    271 #else
    272     beq     a0, t0, 2f
    273 #endif
    274     li      t0, 3                  /* BAR_ICACHE_CTX */
    275 #ifdef __TINYC__
    276     beq     a0, t0, 28
    277 #else
    278     beq     a0, t0, 3f
    279 #endif
    280     /* default: BAR_WMB */
    281     FENCE_W_W
    282     RET
    283 1:
    284     FENCE_R_R
    285     RET
    286 2:
    287     FENCE_I
    288     RET
    289 3:
    290     SFENCE_VMA
    291     FENCE_I
    292     RET
    293 
    294 .globl riscv_read_stval
    295 riscv_read_stval:
    296     CSRR_A0_STVAL
    297     RET
    298 
    299 .globl riscv_write_satp
    300 riscv_write_satp:
    301     CSRW_SATP_A0
    302     SFENCE_VMA
    303     RET
    304 
    305 .globl riscv_set_sum
    306 riscv_set_sum:
    307     CSRR_T0_SSTATUS
    308     lui     t1, 0x40
    309     or      t0, t0, t1
    310     CSRW_SSTATUS_T0
    311     RET
    312 
    313 .globl arch_system_off
    314 arch_system_off:
    315     lui     t0, 0x100
    316     lui     t1, 5
    317     addi    t1, t1, 1365
    318     SW(t1, t0, 0)
    319 1:
    320     wfi
    321     J(1b)
    322 
    323 .section .bss, "aw", @nobits
    324 #ifdef __TINYC__
    325 .align 8
    326 #else
    327 .align 3
    328 #endif
    329 .globl saved_user_sp
    330 saved_user_sp:
    331     .skip 8
    332 #ifdef __TINYC__
    333 .align 16
    334 #else
    335 .align 4
    336 #endif
    337 .skip 0x10000
    338 .globl kstack_top
    339 kstack_top: