/* * Load the information expected by a powerpc kernel. * * - The 'boothowto' argument is constructed * - The 'bootdev' argument is constructed * - The kernel environment is copied into kernel space. * - Module metadata are formatted and placed in kernel space. */ int md_load_dual(char *args, vm_offset_t *modulep, vm_offset_t *dtb, int kern64) { struct preloaded_file *kfp; struct preloaded_file *xp; struct file_metadata *md; vm_offset_t kernend; vm_offset_t addr; vm_offset_t envp; vm_offset_t fdtp; vm_offset_t size; uint64_t scratch64; char *rootdevname; int howto; align = kern64 ? 8 : 4; howto = md_getboothowto(args); /* * Allow the environment variable 'rootdev' to override the supplied device * This should perhaps go to MI code and/or have $rootdev tested/set by * MI code before launching the kernel. */ rootdevname = getenv("rootdev"); if (rootdevname == NULL) rootdevname = getenv("currdev"); /* Try reading the /etc/fstab file to select the root device */ getrootmount(rootdevname); /* find the last module in the chain */ addr = 0; for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { if (addr < (xp->f_addr + xp->f_size)) addr = xp->f_addr + xp->f_size; } /* pad to a page boundary */ addr = roundup(addr, PAGE_SIZE); /* copy our environment */ envp = addr; addr = md_copyenv(addr); /* pad to a page boundary */ addr = roundup(addr, PAGE_SIZE); /* Copy out FDT */ size = fdt_copy(addr); *dtb = fdtp = addr; addr = roundup(addr + size, PAGE_SIZE); kernend = 0; kfp = file_findfile(NULL, kern64 ? "elf64 kernel" : "elf32 kernel"); if (kfp == NULL) kfp = file_findfile(NULL, "elf kernel"); if (kfp == NULL) panic("can't find kernel file"); file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); if (kern64) { scratch64 = envp; file_addmetadata(kfp, MODINFOMD_ENVP, sizeof scratch64, &scratch64); scratch64 = fdtp; file_addmetadata(kfp, MODINFOMD_DTBP, sizeof scratch64, &scratch64); scratch64 = kernend; file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof scratch64, &scratch64); } else { file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); file_addmetadata(kfp, MODINFOMD_DTBP, sizeof fdtp, &fdtp); file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); } *modulep = addr; size = md_copymodules(0, kern64); kernend = roundup(addr + size, PAGE_SIZE); md = file_findmetadata(kfp, MODINFOMD_KERNEND); if (kern64) { scratch64 = kernend; bcopy(&scratch64, md->md_data, sizeof scratch64); } else { bcopy(&kernend, md->md_data, sizeof kernend); } (void)md_copymodules(addr, kern64); return(0); }
pid_t sys_fork(const struct trapframe *parent_tf, int *err) { struct process *parent = curthread->t_proc; // set up new process structure struct process *child = process_create(parent->ps_name); if (child == NULL) { *err = ENOMEM; return -1; } // Get a PID for the child. ENPROC is // the error code for "no more processes allowed // in the system." pid_t child_pid = process_identify(child); if (child_pid == 0) { *err = ENPROC; process_cleanup(child); return -1; } // copy the file descriptor table of the parent child->ps_fdt = fdt_copy(parent->ps_fdt); if (child->ps_fdt == NULL) { *err = ENOMEM; process_destroy(child_pid); return -1; } // copy the address space of the parent *err = as_copy(parent->ps_addrspace, &child->ps_addrspace); if (*err) { process_destroy(child_pid); return -1; } // add PID to children now. That way, if we fail to // allocate memory, we have not yet forked a thread *err = pid_set_add(parent->ps_children, child_pid); if (*err) { process_destroy(child_pid); return -1; } // allocate space for child trapframe in the kernel heap struct trapframe *child_tf = kmalloc(sizeof(struct trapframe)); if (child_tf == NULL) { process_destroy(child_pid); pid_set_remove(parent->ps_children, child_pid); *err = ENOMEM; return -1; } // copy trapframe memcpy(child_tf, parent_tf, sizeof(struct trapframe)); // abuse child_tf->TF_RET (which will be set to 0) // to pass the process struct to the child thread // this cast and assignment will always work, // as pointers always fit in machine registers child_tf->TF_RET = (uintptr_t)child; // child thread sets up child return value // and ps_thread/t_proc *err = thread_fork("user process", enter_forked_process, child_tf, 0, NULL); if (*err) { process_destroy(child_pid); kfree(child_tf); pid_set_remove(parent->ps_children, child_pid); return -1; } return child_pid; }