boot/loader.s
#include "arch/ducky.h"
#include "arch/boot.h"
#include "arch/control.h"
#include "arch/bio.h"
.data
// Initial stack
.type init_stack, space, PAGE_SIZE
.text
// get our CPUID
ctr r0, CONTROL_CPUID
bnz __secondary_boot
j __primary_boot
// should not return, just in case
hlt 0xFFFF
//
// void __load_blocks(u32_t storage, u32_t block, u32_t cnt, void *buff)
//
__load_blocks:
push r10
push r11
push r12
li r11, BIO_MMIO_ADDRESS
// reset storage
li r10, BIO_SRST
mov r12, r11
add r12, BIO_MMIO_STATUS
stw r12, r10
// set storage ID
mov r12, r11
add r12, BIO_MMIO_SID
stw r12, r0
// set block ID
mov r12, r11
add r12, BIO_MMIO_BLOCK
stw r12, r1
// set number of blocks
mov r12, r11
add r12, BIO_MMIO_COUNT
stw r12, r2
// set buffer address
mov r12, r11
add r12, BIO_MMIO_ADDR
stw r12, r3
// execute
li r10, BIO_DMA
or r10, BIO_READ
mov r12, r11
add r12, BIO_MMIO_STATUS
stw r12, r10
mov r12, r11
add r12, BIO_MMIO_STATUS
__load_blocks_wait:
lw r10, r12
and r10, BIO_RDY
bz __load_blocks_wait
pop r12
pop r11
pop r10
ret
//
// void __primary_boot(u32_t cpuid) __attribute__ ((noreturn))
//
// Boot primary core - prepare some structures, and load next phase.
//
__primary_boot:
mov r27, r0
// use our initial stack
la sp, init_stack
add sp, PAGE_SIZE
mov fp, sp
// clear EVT
li r0, BOOT_EVT_ADDRESS
li r2, 0x00
li r1, PAGE_SIZE
__evt_reset_loop:
bz __evt_reset_finished
stw r0, r2
add r0, WORD_SIZE
sub r1, WORD_SIZE
j __evt_reset_loop
__evt_reset_finished:
// clear CWT
li r0, BOOT_CWT_ADDRESS
li r1, PAGE_SIZE
__cwt_reset_loop:
bz __cwt_reset_finished
stw r0, r2
add r0, WORD_SIZE
sub r1, WORD_SIZE
j __cwt_reset_loop
__cwt_reset_finished:
//
// Load next phase
//
// Hic sunt binary loading, from block device, or from FLASH memory, or ROM...
//
la r26, __primary_boot_halt
#ifdef BOOT_IMAGE
// load image from storage #0
li r0, 0x00
li r1, 0x00
li r2, 0x01
li r3, BOOT_OS_ADDRESS
call __load_blocks
li r0, 0x00
li r1, 0x01
li r3, BOOT_OS_ADDRESS
lw r2, r3
dec r2
call __load_blocks
#else
# error "No boot image loader provided"
#endif
li r26, BOOT_OS_ADDRESS
// cpuid is the first argument
mov r0, r27 // cpuid is the first argument
j r26 // and jump to the next phase
// it should never return, but just in case
hlt 0xFF
__primary_boot_halt:
hlt 0xFFFFF
//
// void __secondary_boot(u32_t cpuid) __attribute__ ((noreturn))
//
// Boot secondary core - fall asleep, and wait for primary core to tell us where
// to jump, by sending IPI to wake us up.
//
__secondary_boot:
// sleep and wait pro primary core to wake us up
idle
// CWT points to a list of values:
//
// +--------------+ <- CWT
// | IP |
// +--------------+
// | SP |
// +--------------+
// | flag addr |
// +--------------+
//
// Our job is to jump to IP, with SP set, passing CPUID and flag addr as arguments.
// Code we jumped to will do its own work, and then store 0xFFFFFFFF to a flag address.
// load necessary data
li r1, BOOT_CWT_ADDRESS
lw r2, r1 // IP
add r1, WORD_SIZE
lw sp, r1 // SP
mov fp, sp
add r1, WORD_SIZE
lw r1, r1 // flag addr
// and jump
j r2
// it should never return, but just in case
hlt 0xFF