Index: head/sys/riscv/include/machdep.h =================================================================== --- head/sys/riscv/include/machdep.h +++ head/sys/riscv/include/machdep.h @@ -43,12 +43,12 @@ vm_offset_t kern_stack; vm_offset_t dtbp_virt; /* Device tree blob virtual addr */ vm_offset_t dtbp_phys; /* Device tree blob physical addr */ + vm_offset_t modulep; /* loader(8) metadata */ }; extern vm_paddr_t physmap[PHYS_AVAIL_ENTRIES]; extern u_int physmap_idx; -vm_offset_t fake_preload_metadata(struct riscv_bootparams *rbp); void initriscv(struct riscv_bootparams *); #endif /* _MACHINE_MACHDEP_H_ */ Index: head/sys/riscv/riscv/genassym.c =================================================================== --- head/sys/riscv/riscv/genassym.c +++ head/sys/riscv/riscv/genassym.c @@ -107,3 +107,4 @@ kern_stack)); ASSYM(RISCV_BOOTPARAMS_DTBP_VIRT, offsetof(struct riscv_bootparams, dtbp_virt)); ASSYM(RISCV_BOOTPARAMS_DTBP_PHYS, offsetof(struct riscv_bootparams, dtbp_phys)); +ASSYM(RISCV_BOOTPARAMS_MODULEP, offsetof(struct riscv_bootparams, modulep)); Index: head/sys/riscv/riscv/locore.S =================================================================== --- head/sys/riscv/riscv/locore.S +++ head/sys/riscv/riscv/locore.S @@ -46,24 +46,24 @@ .globl kernbase .set kernbase, KERNBASE - /* Trap entries */ .text - - /* Reset vector */ - .text - .globl _start -_start: +/* + * Alternate entry point. Used when booting via SBI firmware. It must be placed + * at the beginning of the .text section. Arguments are as follows: + * - a0 = hart ID + * - a1 = dtbp + * + * Multiple CPUs might enter from this point, so we perform a hart lottery and + * send the losers to mpentry. + */ + .globl _alt_start +_alt_start: /* Set the global pointer */ .option push .option norelax lla gp, __global_pointer$ .option pop - /* - * a0 = hart id - * a1 = dtbp - */ - /* Pick a hart to run the boot process. */ lla t0, hart_lottery li t1, 1 @@ -75,11 +75,43 @@ */ beqz t0, 1f j mpentry +1: + /* Store the boot hart */ + lla t0, boot_hart + sw a0, 0(t0) + /* Load zero as modulep */ + mv a0, zero + j pagetables + +/* + * Main entry point. This routine is marked as the ELF entry, and is where + * loader(8) will enter the kernel. Arguments are as follows: + * - a0 = modulep + * - a1 = ??? + * + * It is expected that only a single CPU will enter here. + */ + .globl _start +_start: + /* Set the global pointer */ +.option push +.option norelax + lla gp, __global_pointer$ +.option pop + /* - * Page tables + * Zero a1 to indicate that we have no DTB pointer. It is already + * included in the loader(8) metadata. */ -1: + mv a1, zero + + /* + * Page tables setup + * a0 - modulep or zero + * a1 - zero or dtbp + */ +pagetables: /* Get the kernel's load address */ jal get_physmem @@ -107,7 +139,7 @@ li t2, 512 /* Build 512 entries */ add t3, t4, t2 li t5, 0 -2: +1: li t0, (PTE_KERN | PTE_X) slli t2, t4, PTE_PPN1_S /* << PTE_PPN1_S */ or t5, t0, t2 @@ -115,7 +147,7 @@ addi s1, s1, PTE_SIZE addi t4, t4, 1 - bltu t4, t3, 2b + bltu t4, t3, 1b /* Create an L1 page for early devmap */ lla s1, pagetable_l1 @@ -135,6 +167,9 @@ add t0, s1, a5 sd t6, (t0) + /* Check if we have a DTB that needs to be mapped */ + beqz a1, 2f + /* Create an L2 page superpage for DTB */ lla s1, pagetable_l2_devmap mv s2, a1 @@ -156,6 +191,7 @@ /* Page tables END */ /* Setup supervisor trap vector */ +2: lla t0, va sub t0, t0, s9 li t1, KERNBASE @@ -201,12 +237,6 @@ addi s0, s0, 8 bltu s0, s1, 1b -#ifdef SMP - /* Store boot hart id. */ - la t0, boot_hart - sw a0, 0(t0) -#endif - /* Fill riscv_bootparams */ la t0, pagetable_l1 sd t0, RISCV_BOOTPARAMS_KERN_L1PT(sp) @@ -222,6 +252,8 @@ add t0, t0, t1 sd t0, RISCV_BOOTPARAMS_DTBP_VIRT(sp) sd a1, RISCV_BOOTPARAMS_DTBP_PHYS(sp) + + sd a0, RISCV_BOOTPARAMS_MODULEP(sp) mv a0, sp call _C_LABEL(initriscv) /* Off we go */ Index: head/sys/riscv/riscv/machdep.c =================================================================== --- head/sys/riscv/riscv/machdep.c +++ head/sys/riscv/riscv/machdep.c @@ -122,7 +122,9 @@ int64_t icache_line_size; /* The minimum I cache line size */ int64_t idcache_line_size; /* The minimum cache line size */ -uint32_t boot_hart; /* The hart we booted on. */ +#define BOOT_HART_INVALID 0xffffffff +uint32_t boot_hart = BOOT_HART_INVALID; /* The hart we booted on. */ + cpuset_t all_harts; extern int *end; @@ -723,12 +725,11 @@ /* * Fake up a boot descriptor table. - * RISCVTODO: This needs to be done via loader (when it's available). */ -vm_offset_t +static void fake_preload_metadata(struct riscv_bootparams *rvbp) { - static uint32_t fake_preload[35]; + static uint32_t fake_preload[48]; vm_offset_t lastaddr; size_t fake_size, dtb_size; @@ -771,6 +772,14 @@ memmove((void *)lastaddr, (const void *)rvbp->dtbp_virt, dtb_size); lastaddr = roundup(lastaddr + dtb_size, sizeof(int)); + PRELOAD_PUSH_VALUE(uint32_t, MODINFO_METADATA | MODINFOMD_KERNEND); + PRELOAD_PUSH_VALUE(uint32_t, sizeof(vm_offset_t)); + PRELOAD_PUSH_VALUE(vm_offset_t, lastaddr); + + PRELOAD_PUSH_VALUE(uint32_t, MODINFO_METADATA | MODINFOMD_HOWTO); + PRELOAD_PUSH_VALUE(uint32_t, sizeof(int)); + PRELOAD_PUSH_VALUE(int, RB_VERBOSE); + /* End marker */ PRELOAD_PUSH_VALUE(uint32_t, 0); PRELOAD_PUSH_VALUE(uint32_t, 0); @@ -789,7 +798,38 @@ printf("FDT phys (%lx-%lx), kernel phys (%lx-%lx)\n", rvbp->dtbp_phys, rvbp->dtbp_phys + dtb_size, rvbp->kern_phys, rvbp->kern_phys + (lastaddr - KERNBASE)); +} +static vm_offset_t +parse_metadata(void) +{ + caddr_t kmdp; + vm_offset_t lastaddr; +#ifdef DDB + vm_offset_t ksym_start, ksym_end; +#endif + char *kern_envp; + + /* Find the kernel address */ + kmdp = preload_search_by_type("elf kernel"); + if (kmdp == NULL) + kmdp = preload_search_by_type("elf64 kernel"); + KASSERT(kmdp != NULL, ("No preload metadata found!")); + + /* Read the boot metadata */ + boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int); + lastaddr = MD_FETCH(kmdp, MODINFOMD_KERNEND, vm_offset_t); + kern_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *); + if (kern_envp != NULL) + init_static_kenv(kern_envp, 0); +#ifdef DDB + ksym_start = MD_FETCH(kmdp, MODINFOMD_SSYM, uintptr_t); + ksym_end = MD_FETCH(kmdp, MODINFOMD_ESYM, uintptr_t); + db_fetch_ksymtab(ksym_start, ksym_end); +#endif +#ifdef FDT + try_load_dtb(kmdp); +#endif return (lastaddr); } @@ -801,14 +841,16 @@ int mem_regions_sz; vm_offset_t lastaddr; vm_size_t kernlen; - caddr_t kmdp; +#ifdef FDT + phandle_t chosen; + uint32_t hart; +#endif TSRAW(&thread0, TS_ENTER, __func__, NULL); /* Set the pcpu data, this is needed by pmap_bootstrap */ pcpup = &__pcpu[0]; pcpu_init(pcpup, 0, sizeof(struct pcpu)); - pcpup->pc_hart = boot_hart; /* Set the pcpu pointer */ __asm __volatile("mv tp, %0" :: "r"(pcpup)); @@ -818,22 +860,31 @@ /* Initialize SBI interface. */ sbi_init(); - /* Set the module data location */ - lastaddr = fake_preload_metadata(rvbp); + /* Parse the boot metadata. */ + if (rvbp->modulep != 0) { + preload_metadata = (caddr_t)rvbp->modulep; + } else { + fake_preload_metadata(rvbp); + } + lastaddr = parse_metadata(); - /* Find the kernel address */ - kmdp = preload_search_by_type("elf kernel"); - if (kmdp == NULL) - kmdp = preload_search_by_type("elf64 kernel"); - - boothowto = RB_VERBOSE | RB_SINGLE; - boothowto = RB_VERBOSE; - - kern_envp = NULL; - #ifdef FDT - try_load_dtb(kmdp); + /* + * Look for the boot hart ID. This was either passed in directly from + * the SBI firmware and handled by locore, or was stored in the device + * tree by an earlier boot stage. + */ + chosen = OF_finddevice("/chosen"); + if (OF_getencprop(chosen, "boot-hartid", &hart, sizeof(hart)) != -1) { + boot_hart = hart; + } +#endif + if (boot_hart == BOOT_HART_INVALID) { + panic("Boot hart ID was not properly set"); + } + pcpup->pc_hart = boot_hart; +#ifdef FDT /* * Exclude reserved memory specified by the device tree. Typically, * this contains an entry for memory used by the runtime SBI firmware.