/*
* Copyright (c) 2017-2020 The NetBSD Foundation, Inc. All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Maxime Villard.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
struct prekern_args {
int version;
int boothowto;
void *bootinfo;
void *bootspace;
int esym;
int biosextmem;
int biosbasemem;
int cpuid_level;
uint32_t nox_flag;
uint64_t PDPpaddr;
vaddr_t atdevbase;
vaddr_t lwp0uarea;
paddr_t first_avail;
};
struct prekern_args pkargs;
static void
init_prekern_args(void)
{
extern struct bootspace bootspace;
extern int esym;
extern int biosextmem;
extern int biosbasemem;
extern int cpuid_level;
extern uint32_t nox_flag;
extern uint64_t PDPpaddr;
extern vaddr_t iom_base;
extern paddr_t stkpa;
extern paddr_t pa_avail;
void
exec_kernel(vaddr_t ent)
{
int (*jumpfunc)(struct prekern_args *);
int ret;
/*
* Normally, the function does not return. If it does, it means the
* kernel had trouble processing the arguments, and we panic here. The
* return value is here for debug.
*/
jumpfunc = (void *)ent;
ret = (*jumpfunc)(&pkargs);
if (ret == -1) {
fatal("kernel returned: wrong API version");
} else {
fatal("kernel returned: unknown value");
}
}
/*
* Main entry point of the Prekern.
*/
void
init_prekern(paddr_t pa_start)
{
vaddr_t ent;
init_cons();
print_banner();
if (kernpa_start == 0 || kernpa_end == 0) {
fatal("init_prekern: unable to locate the kernel");
}
if (kernpa_start != (1UL << 21)) {
fatal("init_prekern: invalid kernpa_start");
}
if (kernpa_start % PAGE_SIZE != 0) {
fatal("init_prekern: kernpa_start not aligned");
}
if (kernpa_end % PAGE_SIZE != 0) {
fatal("init_prekern: kernpa_end not aligned");
}
if (kernpa_end <= kernpa_start) {
fatal("init_prekern: kernpa_end >= kernpa_start");
}
/*
* Our physical space starts after the end of the kernel.
*/
if (pa_start < kernpa_end) {
fatal("init_prekern: physical space inside kernel");
}
mm_init(pa_start);
/*
* Init the IDT. We mostly don't care about this, it's just here
* to properly handle traps.
*/
init_idt();
print_state(STATE_NORMAL, "Prekern loaded");
/*
* Init the PRNG.
*/
prng_init();
/*
* Relocate the kernel.
*/
mm_map_kernel();
elf_build_info();
ent = elf_kernel_reloc();
mm_bootspace_mprotect();
/*
* Build the arguments.
*/
init_prekern_args();
/*
* Finally, jump into the kernel.
*/
print_state(STATE_NORMAL, "Jumping into the kernel");
jump_kernel(ent);