2012-10-08 03:38:03 +02:00
|
|
|
/* This file contains code for initialization of protected mode, to initialize
|
|
|
|
* code and data segment descriptors, and to initialize global descriptors
|
|
|
|
* for local descriptors in the process table.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <assert.h>
|
2013-09-13 20:12:22 +02:00
|
|
|
#include <string.h>
|
|
|
|
|
2012-10-08 03:38:03 +02:00
|
|
|
#include <machine/multiboot.h>
|
|
|
|
|
|
|
|
#include "kernel/kernel.h"
|
|
|
|
|
2013-09-13 20:12:22 +02:00
|
|
|
#include "archconst.h"
|
2012-10-08 03:38:03 +02:00
|
|
|
#include "arch_proto.h"
|
|
|
|
|
2013-09-13 20:12:22 +02:00
|
|
|
#include <sys/exec.h>
|
2012-10-08 03:38:03 +02:00
|
|
|
#include <libexec.h>
|
|
|
|
|
|
|
|
struct tss_s tss[CONFIG_MAX_CPUS];
|
|
|
|
extern int exc_vector_table;
|
|
|
|
|
|
|
|
int prot_init_done = 0;
|
|
|
|
|
|
|
|
phys_bytes vir2phys(void *vir)
|
|
|
|
{
|
2013-12-17 16:20:37 +01:00
|
|
|
/* defined in kernel.lds */
|
|
|
|
extern char _kern_vir_base, _kern_phys_base;
|
2012-10-08 03:38:03 +02:00
|
|
|
u32_t offset = (vir_bytes) &_kern_vir_base -
|
2013-12-17 16:20:37 +01:00
|
|
|
(vir_bytes) &_kern_phys_base;
|
2012-10-08 03:38:03 +02:00
|
|
|
return (phys_bytes)vir - offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
int tss_init(unsigned cpu, void * kernel_stack)
|
|
|
|
{
|
|
|
|
|
|
|
|
struct tss_s * t = &tss[cpu];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* make space for process pointer and cpu id and point to the first
|
|
|
|
* usable word
|
|
|
|
*/
|
|
|
|
t->sp0 = ((unsigned) kernel_stack) - ARM_STACK_TOP_RESERVED;
|
|
|
|
/*
|
|
|
|
* set the cpu id at the top of the stack so we know on which cpu is
|
|
|
|
* this stak in use when we trap to kernel
|
|
|
|
*/
|
|
|
|
*((reg_t *)(t->sp0 + 1 * sizeof(reg_t))) = cpu;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
multiboot_module_t *bootmod(int pnr)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
assert(pnr >= 0);
|
|
|
|
|
|
|
|
/* Search for desired process in boot process
|
|
|
|
* list. The first NR_TASKS ones do not correspond
|
|
|
|
* to a module, however, so we don't search those.
|
|
|
|
*/
|
|
|
|
for(i = NR_TASKS; i < NR_BOOT_PROCS; i++) {
|
|
|
|
int p;
|
|
|
|
p = i - NR_TASKS;
|
|
|
|
if(image[i].proc_nr == pnr) {
|
|
|
|
assert(p < MULTIBOOT_MAX_MODS);
|
2013-12-10 22:47:53 +01:00
|
|
|
assert(p < kinfo.mbi.mi_mods_count);
|
2012-10-08 03:38:03 +02:00
|
|
|
return &kinfo.module_list[p];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
panic("boot module %d not found", pnr);
|
|
|
|
}
|
|
|
|
|
|
|
|
int booting_cpu = 0;
|
|
|
|
|
|
|
|
void prot_init()
|
|
|
|
{
|
2014-02-10 13:12:21 +01:00
|
|
|
/* tell the HW where we stored our vector table */
|
2013-12-17 16:20:37 +01:00
|
|
|
write_vbar((reg_t)&exc_vector_table);
|
2012-10-08 03:38:03 +02:00
|
|
|
|
2013-12-17 16:20:37 +01:00
|
|
|
/* Set up a new post-relocate bootstrap pagetable so that
|
|
|
|
* we can map in VM, and we no longer rely on pre-relocated
|
|
|
|
* data.
|
|
|
|
*/
|
2012-10-08 03:38:03 +02:00
|
|
|
|
2013-12-17 16:20:37 +01:00
|
|
|
pg_clear();
|
|
|
|
pg_identity(&kinfo); /* Still need 1:1 for device memory . */
|
|
|
|
pg_mapkernel();
|
|
|
|
pg_load();
|
2012-10-08 03:38:03 +02:00
|
|
|
|
2013-12-17 16:20:37 +01:00
|
|
|
prot_init_done = 1;
|
2012-10-08 03:38:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int alloc_for_vm = 0;
|
|
|
|
|
|
|
|
void arch_post_init(void)
|
|
|
|
{
|
2013-12-17 16:20:37 +01:00
|
|
|
/* Let memory mapping code know what's going on at bootstrap time */
|
|
|
|
struct proc *vm;
|
|
|
|
vm = proc_addr(VM_PROC_NR);
|
|
|
|
get_cpulocal_var(ptproc) = vm;
|
|
|
|
pg_info(&vm->p_seg.p_ttbr, &vm->p_seg.p_ttbr_v);
|
2012-10-08 03:38:03 +02:00
|
|
|
}
|
|
|
|
|
2013-03-07 16:55:22 +01:00
|
|
|
static int libexec_pg_alloc(struct exec_info *execi, vir_bytes vaddr, size_t len)
|
2012-10-08 03:38:03 +02:00
|
|
|
{
|
2013-12-17 16:20:37 +01:00
|
|
|
pg_map(PG_ALLOCATEME, vaddr, vaddr+len, &kinfo);
|
|
|
|
pg_load();
|
|
|
|
memset((char *) vaddr, 0, len);
|
2012-10-08 03:38:03 +02:00
|
|
|
alloc_for_vm += len;
|
2013-12-17 16:20:37 +01:00
|
|
|
return OK;
|
2012-10-08 03:38:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void arch_boot_proc(struct boot_image *ip, struct proc *rp)
|
|
|
|
{
|
|
|
|
multiboot_module_t *mod;
|
2013-09-13 20:12:22 +02:00
|
|
|
struct ps_strings *psp;
|
|
|
|
char *sp;
|
2012-10-08 03:38:03 +02:00
|
|
|
|
|
|
|
if(rp->p_nr < 0) return;
|
|
|
|
|
|
|
|
mod = bootmod(rp->p_nr);
|
|
|
|
|
|
|
|
/* Important special case: we put VM in the bootstrap pagetable
|
|
|
|
* so it can run.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if(rp->p_nr == VM_PROC_NR) {
|
|
|
|
struct exec_info execi;
|
|
|
|
|
|
|
|
memset(&execi, 0, sizeof(execi));
|
|
|
|
|
|
|
|
/* exec parameters */
|
|
|
|
execi.stack_high = kinfo.user_sp;
|
2013-02-19 13:52:52 +01:00
|
|
|
execi.stack_size = 64 * 1024; /* not too crazy as it must be preallocated */
|
2012-10-08 03:38:03 +02:00
|
|
|
execi.proc_e = ip->endpoint;
|
|
|
|
execi.hdr = (char *) mod->mod_start; /* phys mem direct */
|
2013-02-04 01:49:48 +01:00
|
|
|
execi.filesize = execi.hdr_len = mod->mod_end - mod->mod_start;
|
2013-09-13 20:12:22 +02:00
|
|
|
strlcpy(execi.progname, ip->proc_name, sizeof(execi.progname));
|
2012-10-08 03:38:03 +02:00
|
|
|
execi.frame_len = 0;
|
|
|
|
|
|
|
|
/* callbacks for use in the kernel */
|
|
|
|
execi.copymem = libexec_copy_memcpy;
|
|
|
|
execi.clearmem = libexec_clear_memset;
|
2013-03-16 04:46:37 +01:00
|
|
|
execi.allocmem_prealloc_junk = libexec_pg_alloc;
|
2013-09-13 20:12:22 +02:00
|
|
|
execi.allocmem_prealloc_cleared = libexec_pg_alloc;
|
2012-10-08 03:38:03 +02:00
|
|
|
execi.allocmem_ondemand = libexec_pg_alloc;
|
|
|
|
execi.clearproc = NULL;
|
|
|
|
|
|
|
|
/* parse VM ELF binary and alloc/map it into bootstrap pagetable */
|
2013-09-13 20:12:22 +02:00
|
|
|
if(libexec_load_elf(&execi) != OK)
|
|
|
|
panic("VM loading failed");
|
|
|
|
|
|
|
|
/* Setup a ps_strings struct on the stack, pointing to the
|
|
|
|
* following argv, envp. */
|
|
|
|
sp = (char *)execi.stack_high;
|
|
|
|
sp -= sizeof(struct ps_strings);
|
|
|
|
psp = (struct ps_strings *) sp;
|
2012-10-08 03:38:03 +02:00
|
|
|
|
2013-09-13 20:12:22 +02:00
|
|
|
/* Take the stack pointer down three words to give startup code
|
|
|
|
* something to use as "argc", "argv" and "envp".
|
2012-10-08 03:38:03 +02:00
|
|
|
*/
|
2013-09-13 20:12:22 +02:00
|
|
|
sp -= (sizeof(void *) + sizeof(void *) + sizeof(int));
|
|
|
|
|
|
|
|
// linear address space, so it is available.
|
|
|
|
psp->ps_argvstr = (char **)(sp + sizeof(int));
|
|
|
|
psp->ps_nargvstr = 0;
|
|
|
|
psp->ps_envstr = psp->ps_argvstr + sizeof(void *);
|
|
|
|
psp->ps_nenvstr = 0;
|
|
|
|
|
|
|
|
arch_proc_init(rp, execi.pc, (vir_bytes)sp,
|
|
|
|
execi.stack_high - sizeof(struct ps_strings),
|
|
|
|
ip->proc_name);
|
2012-10-08 03:38:03 +02:00
|
|
|
|
|
|
|
/* Free VM blob that was just copied into existence. */
|
2013-02-08 19:11:42 +01:00
|
|
|
add_memmap(&kinfo, mod->mod_start, mod->mod_end-mod->mod_start);
|
|
|
|
mod->mod_end = mod->mod_start = 0;
|
2012-10-08 03:38:03 +02:00
|
|
|
|
|
|
|
/* Remember them */
|
|
|
|
kinfo.vm_allocated_bytes = alloc_for_vm;
|
|
|
|
}
|
|
|
|
}
|