static u32_t acpi_phys2vir(u32_t p) { if(!vm_running) { DEBUGEXTRA(("acpi: returning 0x%lx as vir addr\n", p)); return p; } panic("acpi: can't get virtual address of arbitrary physical address"); }
int get_segment(u32_t *vsec, long *size, u32_t *addr, u32_t limit) /* Read *size bytes starting at virtual sector *vsec to memory at *addr. */ { char *buf; size_t cnt, n; cnt= 0; while (*size > 0) { if (cnt == 0) { if ((buf= get_sector((*vsec)++)) == nil) return 0; cnt= SECTOR_SIZE; } if (*addr + click_size > limit) { DEBUGEXTRA(("get_segment: out of memory; " "addr=0x%lx; limit=0x%lx; size=%lx\n", *addr, limit, size)); errno= ENOMEM; return 0; } n= click_size; if (n > cnt) n= cnt; DEBUGMAX(("raw_copy(0x%lx, 0x%lx/0x%x, 0x%lx)... ", *addr, mon2abs(buf), buf, n)); raw_copy(*addr, mon2abs(buf), n); DEBUGMAX(("done\n")); *addr+= n; *size-= n; buf+= n; cnt-= n; } /* Zero extend to a click. */ n= align(*addr, click_size) - *addr; DEBUGMAX(("raw_clear(0x%lx, 0x%lx)... ", *addr, n)); raw_clear(*addr, n); DEBUGMAX(("done\n")); *addr+= n; *size-= n; return 1; }
void bsp_finish_booting(void) { int i; #if SPROFILE sprofiling = 0; /* we're not profiling until instructed to */ #endif /* SPROFILE */ cprof_procs_no = 0; /* init nr of hash table slots used */ cpu_identify(); vm_running = 0; krandom.random_sources = RANDOM_SOURCES; krandom.random_elements = RANDOM_ELEMENTS; /* MINIX is now ready. All boot image processes are on the ready queue. * Return to the assembly code to start running the current process. */ /* it should point somewhere */ get_cpulocal_var(bill_ptr) = get_cpulocal_var_ptr(idle_proc); get_cpulocal_var(proc_ptr) = get_cpulocal_var_ptr(idle_proc); announce(); /* print MINIX startup banner */ /* * we have access to the cpu local run queue, only now schedule the processes. * We ignore the slots for the former kernel tasks */ for (i=0; i < NR_BOOT_PROCS - NR_TASKS; i++) { RTS_UNSET(proc_addr(i), RTS_PROC_STOP); } /* * enable timer interrupts and clock task on the boot CPU */ if (boot_cpu_init_timer(system_hz)) { panic("FATAL : failed to initialize timer interrupts, " "cannot continue without any clock source!"); } fpu_init(); /* Warnings for sanity checks that take time. These warnings are printed * so it's a clear warning no full release should be done with them * enabled. */ #if DEBUG_SCHED_CHECK FIXME("DEBUG_SCHED_CHECK enabled"); #endif #if DEBUG_VMASSERT FIXME("DEBUG_VMASSERT enabled"); #endif #if DEBUG_PROC_CHECK FIXME("PROC check enabled"); #endif DEBUGEXTRA(("cycles_accounting_init()... ")); cycles_accounting_init(); DEBUGEXTRA(("done\n")); #ifdef CONFIG_SMP cpu_set_flag(bsp_cpu_id, CPU_IS_READY); machine.processors_count = ncpus; machine.bsp_id = bsp_cpu_id; #else machine.processors_count = 1; machine.bsp_id = 0; #endif /* Kernel may no longer use bits of memory as VM will be running soon */ kernel_may_alloc = 0; switch_to_user(); NOT_REACHABLE; }
/*===========================================================================* * cstart * *===========================================================================*/ void cstart() { /* Perform system initializations prior to calling main(). Most settings are * determined with help of the environment strings passed by MINIX' loader. */ register char *value; /* value in key=value pair */ int h; /* low-level initialization */ prot_init(); /* determine verbosity */ if ((value = env_get(VERBOSEBOOTVARNAME))) verboseboot = atoi(value); /* Get clock tick frequency. */ value = env_get("hz"); if(value) system_hz = atoi(value); if(!value || system_hz < 2 || system_hz > 50000) /* sanity check */ system_hz = DEFAULT_HZ; DEBUGEXTRA(("cstart\n")); /* Record miscellaneous information for user-space servers. */ kinfo.nr_procs = NR_PROCS; kinfo.nr_tasks = NR_TASKS; strlcpy(kinfo.release, OS_RELEASE, sizeof(kinfo.release)); strlcpy(kinfo.version, OS_VERSION, sizeof(kinfo.version)); /* Load average data initialization. */ kloadinfo.proc_last_slot = 0; for(h = 0; h < _LOAD_HISTORY; h++) kloadinfo.proc_load_history[h] = 0; #ifdef USE_APIC value = env_get("no_apic"); if(value) config_no_apic = atoi(value); else config_no_apic = 1; value = env_get("apic_timer_x"); if(value) config_apic_timer_x = atoi(value); else config_apic_timer_x = 1; #endif #ifdef USE_WATCHDOG value = env_get("watchdog"); if (value) watchdog_enabled = atoi(value); #endif #ifdef CONFIG_SMP if (config_no_apic) config_no_smp = 1; value = env_get("no_smp"); if(value) config_no_smp = atoi(value); else config_no_smp = 0; #endif DEBUGEXTRA(("intr_init(0)\n")); intr_init(0); arch_init(); }
/*===========================================================================* * kmain * *===========================================================================*/ void kmain(kinfo_t *local_cbi) { /* Start the ball rolling. */ struct boot_image *ip; /* boot image pointer */ register struct proc *rp; /* process pointer */ register int i, j; /* save a global copy of the boot parameters */ memcpy(&kinfo, local_cbi, sizeof(kinfo)); memcpy(&kmess, kinfo.kmess, sizeof(kmess)); #ifdef __arm__ /* We want to initialize serial before we do any output */ omap3_ser_init(); #endif /* We can talk now */ printf("MINIX booting\n"); /* Kernel may use bits of main memory before VM is started */ kernel_may_alloc = 1; assert(sizeof(kinfo.boot_procs) == sizeof(image)); memcpy(kinfo.boot_procs, image, sizeof(kinfo.boot_procs)); cstart(); BKL_LOCK(); DEBUGEXTRA(("main()\n")); proc_init(); if(NR_BOOT_MODULES != kinfo.mbi.mods_count) panic("expecting %d boot processes/modules, found %d", NR_BOOT_MODULES, kinfo.mbi.mods_count); /* Set up proc table entries for processes in boot image. */ for (i=0; i < NR_BOOT_PROCS; ++i) { int schedulable_proc; proc_nr_t proc_nr; int ipc_to_m, kcalls; sys_map_t map; ip = &image[i]; /* process' attributes */ DEBUGEXTRA(("initializing %s... ", ip->proc_name)); rp = proc_addr(ip->proc_nr); /* get process pointer */ ip->endpoint = rp->p_endpoint; /* ipc endpoint */ make_zero64(rp->p_cpu_time_left); if(i < NR_TASKS) /* name (tasks only) */ strlcpy(rp->p_name, ip->proc_name, sizeof(rp->p_name)); if(i >= NR_TASKS) { /* Remember this so it can be passed to VM */ multiboot_module_t *mb_mod = &kinfo.module_list[i - NR_TASKS]; ip->start_addr = mb_mod->mod_start; ip->len = mb_mod->mod_end - mb_mod->mod_start; } reset_proc_accounting(rp); /* See if this process is immediately schedulable. * In that case, set its privileges now and allow it to run. * Only kernel tasks and the root system process get to run immediately. * All the other system processes are inhibited from running by the * RTS_NO_PRIV flag. They can only be scheduled once the root system * process has set their privileges. */ proc_nr = proc_nr(rp); schedulable_proc = (iskerneln(proc_nr) || isrootsysn(proc_nr) || proc_nr == VM_PROC_NR); if(schedulable_proc) { /* Assign privilege structure. Force a static privilege id. */ (void) get_priv(rp, static_priv_id(proc_nr)); /* Priviliges for kernel tasks. */ if(proc_nr == VM_PROC_NR) { priv(rp)->s_flags = VM_F; priv(rp)->s_trap_mask = SRV_T; ipc_to_m = SRV_M; kcalls = SRV_KC; priv(rp)->s_sig_mgr = SELF; rp->p_priority = SRV_Q; rp->p_quantum_size_ms = SRV_QT; } else if(iskerneln(proc_nr)) { /* Privilege flags. */ priv(rp)->s_flags = (proc_nr == IDLE ? IDL_F : TSK_F); /* Allowed traps. */ priv(rp)->s_trap_mask = (proc_nr == CLOCK || proc_nr == SYSTEM ? CSK_T : TSK_T); ipc_to_m = TSK_M; /* allowed targets */ kcalls = TSK_KC; /* allowed kernel calls */ } /* Priviliges for the root system process. */ else { assert(isrootsysn(proc_nr)); priv(rp)->s_flags= RSYS_F; /* privilege flags */ priv(rp)->s_trap_mask= SRV_T; /* allowed traps */ ipc_to_m = SRV_M; /* allowed targets */ kcalls = SRV_KC; /* allowed kernel calls */ priv(rp)->s_sig_mgr = SRV_SM; /* signal manager */ rp->p_priority = SRV_Q; /* priority queue */ rp->p_quantum_size_ms = SRV_QT; /* quantum size */ } /* Fill in target mask. */ memset(&map, 0, sizeof(map)); if (ipc_to_m == ALL_M) { for(j = 0; j < NR_SYS_PROCS; j++) set_sys_bit(map, j); } fill_sendto_mask(rp, &map); /* Fill in kernel call mask. */ for(j = 0; j < SYS_CALL_MASK_SIZE; j++) { priv(rp)->s_k_call_mask[j] = (kcalls == NO_C ? 0 : (~0)); } } else { /* Don't let the process run for now. */ RTS_SET(rp, RTS_NO_PRIV | RTS_NO_QUANTUM); } /* Arch-specific state initialization. */ arch_boot_proc(ip, rp); /* scheduling functions depend on proc_ptr pointing somewhere. */ if(!get_cpulocal_var(proc_ptr)) get_cpulocal_var(proc_ptr) = rp; /* Process isn't scheduled until VM has set up a pagetable for it. */ if(rp->p_nr != VM_PROC_NR && rp->p_nr >= 0) { rp->p_rts_flags |= RTS_VMINHIBIT; rp->p_rts_flags |= RTS_BOOTINHIBIT; } rp->p_rts_flags |= RTS_PROC_STOP; rp->p_rts_flags &= ~RTS_SLOT_FREE; DEBUGEXTRA(("done\n")); } /* update boot procs info for VM */ memcpy(kinfo.boot_procs, image, sizeof(kinfo.boot_procs)); #define IPCNAME(n) { \ assert((n) >= 0 && (n) <= IPCNO_HIGHEST); \ assert(!ipc_call_names[n]); \ ipc_call_names[n] = #n; \ } arch_post_init(); IPCNAME(SEND); IPCNAME(RECEIVE); IPCNAME(SENDREC); IPCNAME(NOTIFY); IPCNAME(SENDNB); IPCNAME(SENDA); /* System and processes initialization */ memory_init(); DEBUGEXTRA(("system_init()... ")); system_init(); DEBUGEXTRA(("done\n")); /* The bootstrap phase is over, so we can add the physical * memory used for it to the free list. */ add_memmap(&kinfo, kinfo.bootstrap_start, kinfo.bootstrap_len); #ifdef CONFIG_SMP if (config_no_apic) { BOOT_VERBOSE(printf("APIC disabled, disables SMP, using legacy PIC\n")); smp_single_cpu_fallback(); } else if (config_no_smp) { BOOT_VERBOSE(printf("SMP disabled, using legacy PIC\n")); smp_single_cpu_fallback(); } else { smp_init(); /* * if smp_init() returns it means that it failed and we try to finish * single CPU booting */ bsp_finish_booting(); } #else /* * if configured for a single CPU, we are already on the kernel stack which we * are going to use everytime we execute kernel code. We finish booting and we * never return here */ bsp_finish_booting(); #endif NOT_REACHABLE; }
/*===========================================================================* * main * *===========================================================================*/ PUBLIC int main(void) { /* Start the ball rolling. */ struct boot_image *ip; /* boot image pointer */ register struct proc *rp; /* process pointer */ register int i, j; size_t argsz; /* size of arguments passed to crtso on stack */ BKL_LOCK(); /* Global value to test segment sanity. */ magictest = MAGICTEST; DEBUGEXTRA(("main()\n")); proc_init(); /* Set up proc table entries for processes in boot image. The stacks * of the servers have been added to the data segment by the monitor, so * the stack pointer is set to the end of the data segment. */ for (i=0; i < NR_BOOT_PROCS; ++i) { int schedulable_proc; proc_nr_t proc_nr; int ipc_to_m, kcalls; sys_map_t map; ip = &image[i]; /* process' attributes */ DEBUGEXTRA(("initializing %s... ", ip->proc_name)); rp = proc_addr(ip->proc_nr); /* get process pointer */ ip->endpoint = rp->p_endpoint; /* ipc endpoint */ make_zero64(rp->p_cpu_time_left); strncpy(rp->p_name, ip->proc_name, P_NAME_LEN); /* set process name */ reset_proc_accounting(rp); /* See if this process is immediately schedulable. * In that case, set its privileges now and allow it to run. * Only kernel tasks and the root system process get to run immediately. * All the other system processes are inhibited from running by the * RTS_NO_PRIV flag. They can only be scheduled once the root system * process has set their privileges. */ proc_nr = proc_nr(rp); schedulable_proc = (iskerneln(proc_nr) || isrootsysn(proc_nr)); if(schedulable_proc) { /* Assign privilege structure. Force a static privilege id. */ (void) get_priv(rp, static_priv_id(proc_nr)); /* Priviliges for kernel tasks. */ if(iskerneln(proc_nr)) { /* Privilege flags. */ priv(rp)->s_flags = (proc_nr == IDLE ? IDL_F : TSK_F); /* Allowed traps. */ priv(rp)->s_trap_mask = (proc_nr == CLOCK || proc_nr == SYSTEM ? CSK_T : TSK_T); ipc_to_m = TSK_M; /* allowed targets */ kcalls = TSK_KC; /* allowed kernel calls */ } /* Priviliges for the root system process. */ else if(isrootsysn(proc_nr)) { priv(rp)->s_flags= RSYS_F; /* privilege flags */ priv(rp)->s_trap_mask= SRV_T; /* allowed traps */ ipc_to_m = SRV_M; /* allowed targets */ kcalls = SRV_KC; /* allowed kernel calls */ priv(rp)->s_sig_mgr = SRV_SM; /* signal manager */ rp->p_priority = SRV_Q; /* priority queue */ rp->p_quantum_size_ms = SRV_QT; /* quantum size */ } /* Priviliges for ordinary process. */ else { NOT_REACHABLE; } /* Fill in target mask. */ memset(&map, 0, sizeof(map)); if (ipc_to_m == ALL_M) { for(j = 0; j < NR_SYS_PROCS; j++) set_sys_bit(map, j); } fill_sendto_mask(rp, &map); /* Fill in kernel call mask. */ for(j = 0; j < SYS_CALL_MASK_SIZE; j++) { priv(rp)->s_k_call_mask[j] = (kcalls == NO_C ? 0 : (~0)); } } else { /* Don't let the process run for now. */ RTS_SET(rp, RTS_NO_PRIV | RTS_NO_QUANTUM); } rp->p_memmap[T].mem_vir = ABS2CLICK(ip->memmap.text_vaddr); rp->p_memmap[T].mem_phys = ABS2CLICK(ip->memmap.text_paddr); rp->p_memmap[T].mem_len = ABS2CLICK(ip->memmap.text_bytes); rp->p_memmap[D].mem_vir = ABS2CLICK(ip->memmap.data_vaddr); rp->p_memmap[D].mem_phys = ABS2CLICK(ip->memmap.data_paddr); rp->p_memmap[D].mem_len = ABS2CLICK(ip->memmap.data_bytes); rp->p_memmap[S].mem_phys = ABS2CLICK(ip->memmap.data_paddr + ip->memmap.data_bytes + ip->memmap.stack_bytes); rp->p_memmap[S].mem_vir = ABS2CLICK(ip->memmap.data_vaddr + ip->memmap.data_bytes + ip->memmap.stack_bytes); rp->p_memmap[S].mem_len = 0; /* Set initial register values. The processor status word for tasks * is different from that of other processes because tasks can * access I/O; this is not allowed to less-privileged processes */ rp->p_reg.pc = ip->memmap.entry; rp->p_reg.psw = (iskerneln(proc_nr)) ? INIT_TASK_PSW : INIT_PSW; /* Initialize the server stack pointer. Take it down three words * to give crtso.s something to use as "argc", "argv" and "envp". */ if (isusern(proc_nr)) { /* user-space process? */ rp->p_reg.sp = (rp->p_memmap[S].mem_vir + rp->p_memmap[S].mem_len) << CLICK_SHIFT; argsz = 3 * sizeof(reg_t); rp->p_reg.sp -= argsz; phys_memset(rp->p_reg.sp - (rp->p_memmap[S].mem_vir << CLICK_SHIFT) + (rp->p_memmap[S].mem_phys << CLICK_SHIFT), 0, argsz); } /* scheduling functions depend on proc_ptr pointing somewhere. */ if(!get_cpulocal_var(proc_ptr)) get_cpulocal_var(proc_ptr) = rp; /* If this process has its own page table, VM will set the * PT up and manage it. VM will signal the kernel when it has * done this; until then, don't let it run. */ if(ip->flags & PROC_FULLVM) rp->p_rts_flags |= RTS_VMINHIBIT; rp->p_rts_flags |= RTS_PROC_STOP; rp->p_rts_flags &= ~RTS_SLOT_FREE; alloc_segments(rp); DEBUGEXTRA(("done\n")); } #define IPCNAME(n) { \ assert((n) >= 0 && (n) <= IPCNO_HIGHEST); \ assert(!ipc_call_names[n]); \ ipc_call_names[n] = #n; \ } IPCNAME(SEND); IPCNAME(RECEIVE); IPCNAME(SENDREC); IPCNAME(NOTIFY); IPCNAME(SENDNB); IPCNAME(SENDA); /* Architecture-dependent initialization. */ DEBUGEXTRA(("arch_init()... ")); arch_init(); DEBUGEXTRA(("done\n")); /* System and processes initialization */ DEBUGEXTRA(("system_init()... ")); system_init(); DEBUGEXTRA(("done\n")); #ifdef CONFIG_SMP if (config_no_apic) { BOOT_VERBOSE(printf("APIC disabled, disables SMP, using legacy PIC\n")); smp_single_cpu_fallback(); } else if (config_no_smp) { BOOT_VERBOSE(printf("SMP disabled, using legacy PIC\n")); smp_single_cpu_fallback(); } else { smp_init(); /* * if smp_init() returns it means that it failed and we try to finish * single CPU booting */ bsp_finish_booting(); } #else /* * if configured for a single CPU, we are already on the kernel stack which we * are going to use everytime we execute kernel code. We finish booting and we * never return here */ bsp_finish_booting(); #endif NOT_REACHABLE; return 1; }
void exec_image(char *image) /* Get a Minix image into core, patch it up and execute. */ { int i; struct image_header hdr; char *buf; u32_t vsec, addr, limit, aout, n, totalmem = 0; struct process *procp; /* Process under construction. */ long a_text, a_data, a_bss, a_stack; int banner= 0; long processor= a2l(b_value("processor")); u16_t kmagic, mode; char *console; char params[SECTOR_SIZE]; extern char *sbrk(int); char *verb; /* The stack is pretty deep here, so check if heap and stack collide. */ (void) sbrk(0); if ((verb= b_value(VERBOSEBOOTVARNAME)) != nil) verboseboot = a2l(verb); printf("\nLoading "); pretty_image(image); printf(".\n"); vsec= 0; /* Load this sector from image next. */ addr= mem[0].base; /* Into this memory block. */ limit= mem[0].base + mem[0].size; if (limit > caddr) limit= caddr; /* Allocate and clear the area where the headers will be placed. */ aout = (limit -= PROCESS_MAX * A_MINHDR); /* Clear the area where the headers will be placed. */ raw_clear(aout, PROCESS_MAX * A_MINHDR); /* Read the many different processes: */ for (i= 0; vsec < image_size; i++) { u32_t startaddr; startaddr = addr; if (i == PROCESS_MAX) { printf("There are more then %d programs in %s\n", PROCESS_MAX, image); errno= 0; return; } procp= &process[i]; /* Read header. */ DEBUGEXTRA(("Reading header... ")); for (;;) { if ((buf= get_sector(vsec++)) == nil) return; memcpy(&hdr, buf, sizeof(hdr)); if (BADMAG(hdr.process)) { errno= ENOEXEC; return; } /* Check the optional label on the process. */ if (selected(hdr.name)) break; /* Bad label, skip this process. */ vsec+= proc_size(&hdr); } DEBUGEXTRA(("done\n")); /* Sanity check: an 8086 can't run a 386 kernel. */ if (hdr.process.a_cpu == A_I80386 && processor < 386) { printf("You can't run a 386 kernel on this 80%ld\n", processor); errno= 0; return; } /* Get the click shift from the kernel text segment. */ if (i == KERNEL_IDX) { if (!get_clickshift(vsec, &hdr)) return; addr= align(addr, click_size); /* big kernels must be loaded into extended memory */ if (k_flags & K_KHIGH) { addr= mem[1].base; limit= mem[1].base + mem[1].size; } } /* Save a copy of the header for the kernel, with a_syms * misused as the address where the process is loaded at. */ DEBUGEXTRA(("raw_copy(0x%x, 0x%lx, 0x%x)... ", aout + i * A_MINHDR, mon2abs(&hdr.process), A_MINHDR)); hdr.process.a_syms= addr; raw_copy(aout + i * A_MINHDR, mon2abs(&hdr.process), A_MINHDR); DEBUGEXTRA(("done\n")); if (!banner) { DEBUGBASIC((" cs ds text data bss")); if (k_flags & K_CHMEM) DEBUGBASIC((" stack")); DEBUGBASIC(("\n")); banner= 1; } /* Segment sizes. */ DEBUGEXTRA(("a_text=0x%lx; a_data=0x%lx; a_bss=0x%lx; a_flags=0x%x)\n", hdr.process.a_text, hdr.process.a_data, hdr.process.a_bss, hdr.process.a_flags)); a_text= hdr.process.a_text; a_data= hdr.process.a_data; a_bss= hdr.process.a_bss; if (k_flags & K_CHMEM) { a_stack= hdr.process.a_total - a_data - a_bss; if (!(hdr.process.a_flags & A_SEP)) a_stack-= a_text; } else { a_stack= 0; } /* Collect info about the process to be. */ procp->cs= addr; /* Process may be page aligned so that the text segment contains * the header, or have an unmapped zero page against vaxisms. */ procp->entry= hdr.process.a_entry; if (hdr.process.a_flags & A_PAL) a_text+= hdr.process.a_hdrlen; if (hdr.process.a_flags & A_UZP) procp->cs-= click_size; /* Separate I&D: two segments. Common I&D: only one. */ if (hdr.process.a_flags & A_SEP) { /* Read the text segment. */ DEBUGEXTRA(("get_segment(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n", vsec, a_text, addr, limit)); if (!get_segment(&vsec, &a_text, &addr, limit)) return; DEBUGEXTRA(("get_segment done vsec=0x%lx a_text=0x%lx " "addr=0x%lx\n", vsec, a_text, addr)); /* The data segment follows. */ procp->ds= addr; if (hdr.process.a_flags & A_UZP) procp->ds-= click_size; procp->data= addr; } else { /* Add text to data to form one segment. */ procp->data= addr + a_text; procp->ds= procp->cs; a_data+= a_text; } /* Read the data segment. */ DEBUGEXTRA(("get_segment(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n", vsec, a_data, addr, limit)); if (!get_segment(&vsec, &a_data, &addr, limit)) return; DEBUGEXTRA(("get_segment done vsec=0x%lx a_data=0x%lx " "addr=0x%lx\n", vsec, a_data, addr)); /* Make space for bss and stack unless... */ if (i != KERNEL_IDX && (k_flags & K_CLAIM)) a_bss= a_stack= 0; DEBUGBASIC(("%07lx %07lx %8ld %8ld %8ld", procp->cs, procp->ds, hdr.process.a_text, hdr.process.a_data, hdr.process.a_bss)); if (k_flags & K_CHMEM) DEBUGBASIC((" %8ld", a_stack)); /* Note that a_data may be negative now, but we can look at it * as -a_data bss bytes. */ /* Compute the number of bss clicks left. */ a_bss+= a_data; n= align(a_bss, click_size); a_bss-= n; /* Zero out bss. */ DEBUGEXTRA(("\nraw_clear(0x%lx, 0x%lx); limit=0x%lx... ", addr, n, limit)); if (addr + n > limit) { errno= ENOMEM; return; } raw_clear(addr, n); DEBUGEXTRA(("done\n")); addr+= n; /* And the number of stack clicks. */ a_stack+= a_bss; n= align(a_stack, click_size); a_stack-= n; /* Add space for the stack. */ addr+= n; /* Process endpoint. */ procp->end= addr; if (verboseboot >= VERBOSEBOOT_BASIC) printf(" %s\n", hdr.name); else { u32_t mem; mem = addr-startaddr; printf("%s ", hdr.name); totalmem += mem; } if (i == 0 && (k_flags & (K_HIGH | K_KHIGH)) == K_HIGH) { /* Load the rest in extended memory. */ addr= mem[1].base; limit= mem[1].base + mem[1].size; } } if (verboseboot < VERBOSEBOOT_BASIC) printf("(%dk)\n", totalmem/1024); if ((n_procs= i) == 0) { printf("There are no programs in %s\n", image); errno= 0; return; } /* Check the kernel magic number. */ raw_copy(mon2abs(&kmagic), process[KERNEL_IDX].data + MAGIC_OFF, sizeof(kmagic)); if (kmagic != KERNEL_D_MAGIC) { printf("Kernel magic number is incorrect (0x%x@0x%lx)\n", kmagic, process[KERNEL_IDX].data + MAGIC_OFF); errno= 0; return; } /* Patch sizes, etc. into kernel data. */ DEBUGEXTRA(("patch_sizes()... ")); patch_sizes(); DEBUGEXTRA(("done\n")); #if !DOS if (!(k_flags & K_MEML)) { /* Copy the a.out headers to the old place. */ raw_copy(HEADERPOS, aout, PROCESS_MAX * A_MINHDR); } #endif /* Run the trailer function just before starting Minix. */ DEBUGEXTRA(("run_trailer()... ")); if (!run_trailer()) { errno= 0; return; } DEBUGEXTRA(("done\n")); /* Translate the boot parameters to what Minix likes best. */ DEBUGEXTRA(("params2params(0x%x, 0x%x)... ", params, sizeof(params))); if (!params2params(params, sizeof(params))) { errno= 0; return; } DEBUGEXTRA(("done\n")); /* Set the video to the required mode. */ if ((console= b_value("console")) == nil || (mode= a2x(console)) == 0) { mode= strcmp(b_value("chrome"), "color") == 0 ? COLOR_MODE : MONO_MODE; } DEBUGEXTRA(("set_mode(%d)... ", mode)); set_mode(mode); DEBUGEXTRA(("done\n")); /* Close the disk. */ DEBUGEXTRA(("dev_close()... ")); (void) dev_close(); DEBUGEXTRA(("done\n")); /* Minix. */ DEBUGEXTRA(("minix(0x%lx, 0x%lx, 0x%lx, 0x%x, 0x%x, 0x%lx)\n", process[KERNEL_IDX].entry, process[KERNEL_IDX].cs, process[KERNEL_IDX].ds, params, sizeof(params), aout)); minix(process[KERNEL_IDX].entry, process[KERNEL_IDX].cs, process[KERNEL_IDX].ds, params, sizeof(params), aout); if (!(k_flags & K_BRET)) { extern u32_t reboot_code; raw_copy(mon2abs(params), reboot_code, sizeof(params)); } parse_code(params); /* Return from Minix. Things may have changed, so assume nothing. */ fsok= -1; errno= 0; /* Read leftover character, if any. */ scan_keyboard(); /* Restore screen contents. */ restore_screen(); }
void exec_mb(char *kernel, char* modules) /* Get a Minix image into core, patch it up and execute. */ { int i; static char hdr[SECTOR_SIZE]; char *buf; u32_t vsec, addr, limit, n, totalmem = 0; u16_t kmagic, mode; char *console; char params[SECTOR_SIZE]; extern char *sbrk(int); char *verb; u32_t text_vaddr, text_paddr, text_filebytes, text_membytes; u32_t data_vaddr, data_paddr, data_filebytes, data_membytes; u32_t pc; u32_t text_offset, data_offset; i32_t segsize; int r; u32_t cs, ds; char *modstring, *mod; multiboot_info_t *mbinfo; multiboot_module_t *mbmodinfo; u32_t mbinfo_size, mbmodinfo_size; char *memvar; memory *mp; u32_t mod_cmdline_start, kernel_cmdline_start; u32_t modstringlen; int modnr; /* The stack is pretty deep here, so check if heap and stack collide. */ (void) sbrk(0); if ((verb= b_value(VERBOSEBOOTVARNAME)) != nil) verboseboot = a2l(verb); printf("\nLoading %s\n", kernel); vsec= 0; /* Load this sector from kernel next. */ addr= mem[0].base; /* Into this memory block. */ limit= mem[0].base + mem[0].size; if (limit > caddr) limit= caddr; /* set click size for get_segment */ click_size = PAGE_SIZE; k_flags = K_KHIGH|K_BRET|K_MEML|K_INT86|K_RET|K_HDR |K_HIGH|K_CHMEM|K_I386; /* big kernels must be loaded into extended memory */ addr= mem[1].base; limit= mem[1].base + mem[1].size; /* Get first sector */ DEBUGEXTRA(("get_sector\n")); if ((buf= get_sector(vsec++)) == nil) { DEBUGEXTRA(("get_sector failed\n")); return; } memcpy(hdr, buf, SECTOR_SIZE); /* Get ELF header */ DEBUGEXTRA(("read_header_elf\n")); r = read_header_elf(hdr, &text_vaddr, &text_paddr, &text_filebytes, &text_membytes, &data_vaddr, &data_paddr, &data_filebytes, &data_membytes, &pc, &text_offset, &data_offset); if (r < 0) { errno= ENOEXEC; return; } /* Read the text segment. */ addr = text_paddr; segsize = (i32_t) text_filebytes; vsec = text_offset / SECTOR_SIZE; DEBUGEXTRA(("get_segment(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n", vsec, segsize, addr, limit)); if (!get_segment(&vsec, &segsize, &addr, limit)) return; DEBUGEXTRA(("get_segment done vsec=0x%lx size=0x%lx " "addr=0x%lx\n", vsec, segsize, addr)); /* Read the data segment. */ addr = data_paddr; segsize = (i32_t) data_filebytes; vsec = data_offset / SECTOR_SIZE; DEBUGEXTRA(("get_segment(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n", vsec, segsize, addr, limit)); if (!get_segment(&vsec, &segsize, &addr, limit)) return; DEBUGEXTRA(("get_segment done vsec=0x%lx size=0x%lx " "addr=0x%lx\n", vsec, segsize, addr)); n = data_membytes - align(data_filebytes, click_size); /* Zero out bss. */ DEBUGEXTRA(("\nraw_clear(0x%lx, 0x%lx); limit=0x%lx... ", addr, n, limit)); if (addr + n > limit) { errno= ENOMEM; return; } raw_clear(addr, n); DEBUGEXTRA(("done\n")); addr+= n; /* Check the kernel magic number. */ raw_copy(mon2abs(&kmagic), data_paddr + MAGIC_OFF, sizeof(kmagic)); if (kmagic != KERNEL_D_MAGIC) { printf("Kernel magic number is incorrect (0x%x@0x%lx)\n", kmagic, data_paddr + MAGIC_OFF); errno= 0; return; } /* Translate the boot parameters to what Minix likes best. */ DEBUGEXTRA(("params2params(0x%x, 0x%x)... ", params, sizeof(params))); if (!params2params(params, sizeof(params))) { errno= 0; return; } DEBUGEXTRA(("done\n")); /* Create multiboot info struct */ mbinfo = malloc(sizeof(multiboot_info_t)); if (mbinfo == nil) { errno= ENOMEM; return; } memset(mbinfo, 0, sizeof(multiboot_info_t)); /* Module info structs start where kernel ends */ mbinfo->mods_addr = addr; modstring = strdup(modules); if (modstring == nil) {errno = ENOMEM; return; } modstringlen = strlen(modules); mbinfo->mods_count = split_module_list(modules); mbmodinfo_size = sizeof(multiboot_module_t) * mbinfo->mods_count; mbmodinfo = malloc(mbmodinfo_size); if (mbmodinfo == nil) { errno= ENOMEM; return; } addr+= mbmodinfo_size; addr= align(addr, click_size); mod_cmdline_start = mbinfo->mods_addr + sizeof(multiboot_module_t) * mbinfo->mods_count; raw_copy(mod_cmdline_start, mon2abs(modules), modstringlen+1); mbmodinfo[0].cmdline = mod_cmdline_start; modnr = 1; for (i= 0; i < modstringlen; ++i) { if (modules[i] == '\0') { mbmodinfo[modnr].cmdline = mod_cmdline_start + i + 1; ++modnr; } } kernel_cmdline_start = mod_cmdline_start + modstringlen + 1; mbinfo->cmdline = kernel_cmdline_start; raw_copy(kernel_cmdline_start, mon2abs(kernel), strlen(kernel)+1); mbinfo->flags = MULTIBOOT_INFO_MODS|MULTIBOOT_INFO_CMDLINE| MULTIBOOT_INFO_BOOTDEV|MULTIBOOT_INFO_MEMORY; mbinfo->boot_device = mbdev; mbinfo->mem_lower = mem[0].size/1024; mbinfo->mem_upper = mem[1].size/1024; for (i = 0, mod = strtok(modstring, " "); mod != nil; mod = strtok(nil, " "), i++) { mod = select_image(mod); if (mod == nil) {errno = 0; return; } mbmodinfo[i].mod_start = addr; mbmodinfo[i].mod_end = addr + image_bytes; mbmodinfo[i].pad = 0; segsize= image_bytes; vsec= 0; DEBUGEXTRA(("get_segment(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n", vsec, segsize, addr, limit)); if (!get_segment(&vsec, &segsize, &addr, limit)) return; DEBUGEXTRA(("get_segment done vsec=0x%lx size=0x%lx " "addr=0x%lx\n", vsec, segsize, addr)); addr+= segsize; addr= align(addr, click_size); } free(modstring); DEBUGEXTRA(("modinfo raw_copy: dst 0x%lx src 0x%lx sz 0x%lx\n", mbinfo->mods_addr, mon2abs(mbmodinfo), mbmodinfo_size)); raw_copy(mbinfo->mods_addr, mon2abs(mbmodinfo), mbmodinfo_size); free(mbmodinfo); raw_copy(MULTIBOOT_INFO_ADDR, mon2abs(mbinfo), sizeof(multiboot_info_t)); free(mbinfo); /* Run the trailer function just before starting Minix. */ DEBUGEXTRA(("run_trailer()... ")); if (!run_trailer()) { errno= 0; return; } DEBUGEXTRA(("done\n")); /* Set the video to the required mode. */ if ((console= b_value("console")) == nil || (mode= a2x(console)) == 0) { mode= strcmp(b_value("chrome"), "color") == 0 ? COLOR_MODE : MONO_MODE; } DEBUGEXTRA(("set_mode(%d)... ", mode)); set_mode(mode); DEBUGEXTRA(("done\n")); /* Close the disk. */ DEBUGEXTRA(("dev_close()... ")); (void) dev_close(); DEBUGEXTRA(("done\n")); /* Minix. */ cs = ds = text_paddr; DEBUGEXTRA(("minix(0x%lx, 0x%lx, 0x%lx, 0x%x, 0x%x, 0x%lx)\n", pc, cs, ds, params, sizeof(params), 0)); minix(pc, cs, ds, params, sizeof(params), 0); if (!(k_flags & K_BRET)) { extern u32_t reboot_code; raw_copy(mon2abs(params), reboot_code, sizeof(params)); } parse_code(params); /* Return from Minix. Things may have changed, so assume nothing. */ fsok= -1; errno= 0; /* Read leftover character, if any. */ scan_keyboard(); /* Restore screen contents. */ restore_screen(); }