HAL for RISC-V 64 based targets¶
HAL for RISCV64 architecture is located in src/hal/riscv64.
Initialization¶
Kernel execution starts from _start symbol located in _init.S file.
_start:
/* Mask all interrupts */
csrw sie, zero
/* Save per-hart data pointer */
la t0, hal_riscvHartData
/* offset = hartId * 24 (sizeof(hal_riscvHartData_t)) */
slli t1, a0, 1
add t1, t1, a0
slli t1, t1, 3
add t0, t0, t1
/* save hartId */
sd a0, (t0)
la t1, _start
sub t0, t0, t1
li t2, VADDR_KERNEL
add t0, t0, t2
csrw sscratch, t0
mv s0, a0
/*
* Disable FPU to detect illegal usage of
* floating point in kernel space
*/
li t0, SSTATUS_FS
csrc sstatus, t0
/* Allow supervisor access to user space */
li t0, SSTATUS_SUM
csrs sstatus, t0
First instruction masks interrupts. Then per-hart data pointer is calculated and stored in sscratch CSR. Hart ID
received from bootloader is also stored in per-hart data structure. Next FPU is disabled to catch illegal usage of
floating point instructions in kernel space. Finally, SUM bit is set in sstatus CSR to allow supervisor mode access
to user space memory, which is necessary for interrupt handling.
/* Check if current hart is the boot hart */
lw s3, (a1) /* s3 = syspage->hs.boothartId */
bne s0, s3, _init_core
On multicore systems only boot hart continues with full initialization. Other harts jump to _init_core label.
la sp, pmap_common
li t0, 3 * SIZE_PAGE + SIZE_INITIAL_KSTACK
add sp, sp, t0
slli t0, s0, INITIAL_KSTACK_BIT
add sp, sp, t0
la t0, hal_syspage /* t0 = &hal_syspage (phy) */
la t1, VADDR_SYSPAGE
add t2, t1, s1
sub t2, t2, s2
/* store virt addr of syspage in hal_syspage */
sd t2, (t0)
la t3, hal_relOffs
sub t4, t2, a1 /* t4 = offset between syspage VADDR and syspage PHYADDR */
sd t4, (t3)
/* calculate phy addr of syspage end */
lw t2, 4(a1) /* t2 = syspage->size */
add t2, t2, t1
syspage_cpy:
ld t3, (a1)
addi a1, a1, 8
sd t3, (t1)
addi t1, t1, 8
bltu t1, t2, syspage_cpy
The next step is configuration of initial stack pointer and copying syspage to its virtual address.
dtb:
mv s4, a2
mv a0, a2
call dtb_save
The hardware configuration is passed to kernel using Device Tree Blob (DTB). Pointer to DTB passed in a2 register is
saved for later use.
mv a0, s4
call _pmap_preinit
After evaluating hardware configuration initial kernel page tables are initialized.
_init_core:
/* s1 = VADDR_KERNEL, s2 = _start (phy) */
sub a1, s1, s2
/* Point stvec to virtual address of intruction after satp write */
la a0, 1f
add a0, a0, a1
csrw stvec, a0
/* Relocate stack */
la sp, pmap_common
li t0, 3 * SIZE_PAGE + SIZE_INITIAL_KSTACK
add sp, sp, t0
slli t0, s0, INITIAL_KSTACK_BIT
add sp, sp, t0
add sp, sp, a1
la a0, pmap_common
srl a0, a0, 12
li a1, SATP_MODE_SV39
or a0, a0, a1
sfence.vma
csrw satp, a0
The system is set up for operation in virtual memory mode and relocation of the stack is performed.
/* Add dummy page fault trap handler */
la a0, .Lsecondary_park
csrw stvec, a0
/* s0 = hartId, s3 = bootHartId
* Boot hart will continue to main
*/
beq s0, s3, main
call hal_cpuInitCore
/* Enable IPI irq */
csrs sie, (1 << 1)
csrs sstatus, 2
2:
call hal_started
fence rw, rw
beqz a0, 2b
/* Enable interrupts */
li a0, -1
csrw sie, a0
.Lsecondary_park:
wfi
j .Lsecondary_park
Boot hart continues to main function while other harts perform per-core initialization and wait for the boot core to
finish system startup.