Handle load from loader(8)
In locore, we must detect and handle different arguments passed by loader(8) compared to what we recieve when booting directly via SBI firmware. Currently we receive the hart ID in a0 and a pointer to the device tree blob in a1. loader(8) provides only a pointer to its metadata in a0. The solution to this is to add an additional entry point, _alt_start. This will be placed first in the .text section, so SBI firmware will enter here, and jump to the common pagetable setup shortly after. Since loader(8) understands our ELF kernel, it will enter at the ELF's entry address, which points to _start. This approach leads to very little guesswork as to which way we booted. Fix-up initriscv() to parse the loader's metadata, continuing to use fake_preload_metadata() in the SBI direct boot case. Reviewed by: markj, jrtc27 (asm portion) Differential Revision: https://reviews.freebsd.org/D24912
This commit is contained in:
parent
27b3db9709
commit
f7d2df2a8a
@ -43,12 +43,12 @@ struct riscv_bootparams {
|
||||
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_ */
|
||||
|
@ -107,3 +107,4 @@ ASSYM(RISCV_BOOTPARAMS_KERN_STACK, offsetof(struct riscv_bootparams,
|
||||
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));
|
||||
|
@ -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 @@ _start:
|
||||
*/
|
||||
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 @@ _start:
|
||||
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 @@ _start:
|
||||
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 @@ _start:
|
||||
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 @@ _start:
|
||||
/* Page tables END */
|
||||
|
||||
/* Setup supervisor trap vector */
|
||||
2:
|
||||
lla t0, va
|
||||
sub t0, t0, s9
|
||||
li t1, KERNBASE
|
||||
@ -201,12 +237,6 @@ va:
|
||||
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)
|
||||
@ -223,6 +253,8 @@ va:
|
||||
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 */
|
||||
call _C_LABEL(mi_startup)
|
||||
|
@ -122,7 +122,9 @@ int64_t dcache_line_size; /* The minimum D cache line size */
|
||||
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 @@ cache_setup(void)
|
||||
|
||||
/*
|
||||
* 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 @@ fake_preload_metadata(struct riscv_bootparams *rvbp)
|
||||
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 @@ fake_preload_metadata(struct riscv_bootparams *rvbp)
|
||||
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 @@ initriscv(struct riscv_bootparams *rvbp)
|
||||
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 @@ initriscv(struct riscv_bootparams *rvbp)
|
||||
/* Initialize SBI interface. */
|
||||
sbi_init();
|
||||
|
||||
/* Set the module data location */
|
||||
lastaddr = fake_preload_metadata(rvbp);
|
||||
|
||||
/* 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;
|
||||
/* Parse the boot metadata. */
|
||||
if (rvbp->modulep != 0) {
|
||||
preload_metadata = (caddr_t)rvbp->modulep;
|
||||
} else {
|
||||
fake_preload_metadata(rvbp);
|
||||
}
|
||||
lastaddr = parse_metadata();
|
||||
|
||||
#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.
|
||||
|
Loading…
Reference in New Issue
Block a user