void mm2_closemap(uint64_t id){ hold_lock hl(mmap_lock, false); if(mmappings->has_key(id)){ mmapping m = (*mmappings)[id]; pid_t curpid = proc_current_pid; proc_switch(m.pid); flush_mapping(m); if(m.size > MM2_Page_Size){ for(size_t i = 0; i < m.pages; ++i){ char *pageaddr = m.page_addr + (i * MM2_Page_Size); if(!current_pagedir->is_mapped(pageaddr)){ uint32_t flags = MM2_PageFlags::Present | MM2_PageFlags::Writable; if((uint32_t)m.addr >= MM2_Kernel_Boundary) flags = MM2_PageFlags::Present | MM2_PageFlags::Writable | MM2_PageFlags::Usermode; current_pagedir->map_page_at(pageaddr, flags); } } } if(m.size > MM2_Page_Size){ if((uint32_t)m.addr < MM2_Kernel_Boundary){ kernel_pagedir->remove_region(m.page_addr); }else{ current_pagedir->remove_region(m.page_addr); } } mmappings->erase(id); if(mmappings->has_key(id)) panic("(MM2) Mapping removal failed!"); proc_switch(curpid); } }
void module_init(multiboot_t *multiboot) { /* * disable interrupts, module loading messes around with address space * switches so we don't want to confuse the scheduler */ intr_lock(); /* keep a copy of the old process */ proc_t *old_proc = proc_get(); multiboot_tag_t *tag = multiboot_get(multiboot, MULTIBOOT_TAG_MODULE); while (tag) { module_load(tag); tag = multiboot_get_after(multiboot, tag, MULTIBOOT_TAG_MODULE); } /* switch back to the correct address space */ if (old_proc) proc_switch(old_proc); /* enable interrupts again */ intr_unlock(); }
static void module_load(multiboot_tag_t *tag) { /* calculate size and phy32 pointer */ size_t size = tag->module.mod_end - tag->module.mod_start; elf64_ehdr_t *elf = (elf64_ehdr_t *) aphy32_to_virt(tag->module.mod_start); /* make a new process */ proc_t *proc = proc_create(); if (!proc) panic("couldn't create process for module"); /* switch our address space */ proc_switch(proc); /* load the ELF file */ if (!elf64_load(elf, size)) panic("couldn't load elf64 file"); /* make a new thread */ thread_t *thread = thread_create(proc, 0); if (!thread) panic("couldn't create thread for module"); /* set entry point of the thread */ thread->rip = elf->e_entry; /* add thread to the scheduler's ready queue */ thread_resume(thread); }
void shm_close_map(uint64_t id){ hold_lock(shm_lock, false); if(mappings->has_key(id)){ shm_mapping *mapping = (*mappings)[id]; bt_pid_t pid = proc_current_pid; proc_switch(mapping->pid); current_pagedir->remove_region(mapping->addr); void *addr = mapping->addr; for(uint32_t i = (uint32_t)addr; i < (uint32_t)addr + (mapping->pages * MM2_Page_Size); i += MM2_Page_Size){ current_pagedir->map_page_at((void*)i, MM2_PageFlags::Present | MM2_PageFlags::Writable | MM2_PageFlags::Usermode); } delete mapping; mappings->erase(id); proc_switch(pid); } }
static void flush_mapping(mmapping &m){ pid_t curpid = proc_current_pid; proc_switch(m.pid); bt_filesize_t pos = fs_seek(m.file, 0, FS_Relative); if(m.size <= MM2_Page_Size){ fs_seek(m.file, m.offset, FS_Set); fs_write(m.file, m.size, m.addr); fs_seek(m.file, pos, FS_Set); proc_switch(curpid); return; } if(m.pre){ fs_seek(m.file, m.offset, FS_Set); fs_write(m.file, m.pre, m.addr); } if(m.post){ bt_filesize_t postoffset = m.page_offset + (m.pages * MM2_Page_Size); char *postaddr = (char*)((uint32_t)m.page_addr + (m.pages * MM2_Page_Size)); fs_seek(m.file, postoffset, FS_Set); fs_write(m.file, m.post, postaddr); } for(size_t i = 0; i < m.pages; ++i){ char *pageaddr = m.page_addr + (i * MM2_Page_Size); if(current_pagedir->is_mapped(pageaddr)){ bt_filesize_t fileoffset = m.page_offset + (i * MM2_Page_Size); fs_seek(m.file, fileoffset, FS_Set); fs_write(m.file, MM2_Page_Size, pageaddr); current_pagedir->free_pages(pageaddr, 1); } current_pagedir->guard_page_at(pageaddr); } fs_seek(m.file, pos, FS_Set); proc_switch(curpid); }
/** * Sleep until any of the signals in \a sigs occurs. * \return the signal(s) that have awoken the process. */ sigmask_t sig_wait(sigmask_t sigs) { sigmask_t result; /* Sleeping with IRQs disabled or preemption forbidden is illegal */ IRQ_ASSERT_ENABLED(); ASSERT(proc_preemptAllowed()); /* * This is subtle: there's a race condition where a concurrent process * or an interrupt may call sig_send()/sig_post() to set a bit in * Process.sig_recv just after we have checked for it, but before we've * set Process.sig_wait to let them know we want to be awaken. * * In this case, we'd deadlock with the signal bit already set and the * process never being reinserted into the ready list. */ IRQ_DISABLE; /* Loop until we get at least one of the signals */ while (!(result = current_process->sig_recv & sigs)) { /* * Tell "them" that we want to be awaken when any of these * signals arrives. */ current_process->sig_wait = sigs; /* Go to sleep and proc_switch() to another process. */ proc_switch(); /* * When we come back here, the wait mask must have been * cleared by someone through sig_send()/sig_post(), and at * least one of the signals we were expecting must have been * delivered to us. */ ASSERT(!current_process->sig_wait); ASSERT(current_process->sig_recv & sigs); } /* Signals found: clear them and return */ current_process->sig_recv &= ~sigs; IRQ_ENABLE; return result; }
/** * Terminate the current process */ void proc_exit(void) { LOG_INFO("%p:%s", current_process, proc_currentName()); #if CONFIG_KERN_MONITOR monitor_remove(current_process); #endif proc_forbid(); #if CONFIG_KERN_HEAP /* * Set the task as zombie, its resources will be freed in proc_new() in * a lazy way, when another process will be created. */ proc_addZombie(current_process); #endif current_process = NULL; proc_permit(); proc_switch(); /* never reached */ ASSERT(0); }
/** * Opens the references file, reads in each line, and dispatches the commands * specified as appropriate to the CPU and OS modules. */ void sim_readdata(void) { FILE *fp; char buff[512]; if ((fp = fopen(filename, "r")) == NULL) { PERROR(filename); exit(EXIT_FAILURE); } /* For each line in the file... */ while (fgets(buff, sizeof(buff), fp) != NULL) { char *cmd, *arg1, *arg2, *arg3; int pid; vaddr_t addr; word_t val, val2; /* Parse command and possible arguments */ cmd = strtok(buff, WHITESPACE); arg1 = strtok(NULL, WHITESPACE); arg2 = strtok(NULL, WHITESPACE); arg3 = strtok(NULL, WHITESPACE); switch (cmd[0]) { /* Create a new process */ case '@': pid = atoi(arg1); if (pid < max_jobs) { printf("Forking new process %s. Assigning pid: %d.\n\n", arg2, pid); proc_fork(pid, arg2); } else { printf("Too many jobs, not forking new process!\n"); } break; /* Load from a memory location */ case 'l': pid = atoi(arg1); addr = atoi(arg2); val = atoi(arg3) % 256; if (pid >= max_jobs) { break; } else if (current == NULL || current->pid != pid) { printf("===================================================\n"); printf("Switching to process: %s. Corresponding pid: %d.\n", proc_getname(pid), pid); printf("===================================================\n\n"); proc_switch(pid); } val2 = mem_load(addr); printf("Value Loaded: %d\n", val2); if (val2 != val) { printf(" ERROR! loaded value did not equal expected!\nValue Expected: %d\n\n", val); /* XXX: Dump a mem image here and quit */ } else { printf("Complete\n\n"); } break; /* Store to a memory location */ case 's': pid = atoi(arg1); addr = atoi(arg2); val = atoi(arg3) % 256; if (pid >= max_jobs) { break; } else if (current == NULL || current->pid != pid) { printf("===================================================\n"); printf("Switching to process: %s. Corresponding pid: %d.\n", proc_getname(pid), pid); printf("===================================================\n\n"); proc_switch(pid); } mem_store(addr, val); printf("Complete\n\n"); /* Ignore other commands (for comments and the like */ default: break; } } fclose(fp); }