int _ioreq_enqueue(Drive *d, Fd *fd, Uint8 rd, Iostate state){ Status status; Key key; Iorequest *req; if( (status = _q_remove( free_req_q, (void **) &req ))!= SUCCESS ) { _kpanic( "_ioreq_enqueue", "No free requests. Status: %s", status ); } key.v =(void *) d; req->d=d; req->fd=fd; req->read=rd; req->st=state; if (state == WAIT_ON_IDLE){ status = _q_insert( idle_q,(void *) req, key); }else if (state == WAIT_ON_DATA){ status = _q_insert( data_q,(void *) req, key); }else{ //drop invalid request status=FAILURE; } if( status != SUCCESS ) { _kpanic( "_ioreq_enqueue", "IO queue insertion status %s", status ); } return 1; }
void _ioreq_handle_idle_request(Drive *d){ Status status; Key key; Iorequest *req; key.v = (void *) d; status = _q_remove_by_key( idle_q, (void **) &req, key ); if(status == NOT_FOUND || status == EMPTY_QUEUE){ d->state=IDLE; req = NULL; //wasn't found return; } else if (status != SUCCESS){ _kpanic("handle_idle_request", "remove status", status); } if (! (_ata_pio_read_status(d) & (BSY | DRQ)) ){ if (req->read){ //send read request and add the data queue d->state=READING; req->st = WAIT_ON_DATA; _q_insert(data_q, (void *) req, key); _ata_pio_send_read(req->fd->device_data); } else { //transfer data and send write reqest d->state=WRITING; _ata_pio_send_write(req->fd->device_data); _ata_pio_write_fd_block(req->fd); _fd_writeDone(req->fd); _ioreq_dealloc(req); } }else { //no idle request on disk, despite removing from idle queue.. this shouldn't happen _q_insert(idle_q, (void *) req, key); } }
void _ioreq_dealloc(Iorequest *req){ Key key; Status status; key.v = req->d; status = _q_insert(free_req_q, (void *) req,key); if( status != SUCCESS ) { _kpanic( "_ioreq_init", "IO free queue insertion status %s", status ); } }
void _dispatch( void ) { int i; Status status; // select a process from the highest-priority // ready queue that is not empty for( i = 0; i < N_READYQ; ++i ) { do { if( _q_empty(_ready[i]) ) { break; } // found one - make it the currently-running process status = _q_remove( _ready[i], (void **) &_current ); if( status == SUCCESS ) { // check to see if it needs to be cleaned up if( _current->state == KILLED ) { // yes - deallocate it _cleanup( _current ); // go back and re-check this queue continue; } _current->state = RUNNING; _current->quantum = STD_QUANTUM; return; } else { _kpanic( "_dispatch", "readyq deque status %s", status ); } } while( 1 ); } _kpanic( "_dispatch", "no non-empty readyq", EMPTY_QUEUE ); }
void _ioreq_init(void){ int i; Status status; status = _q_alloc( &data_q, &_comp_ascend_uint ); if( status != SUCCESS ) { _kpanic( "_ioreq_init", "IO read queue alloc status %s", status ); } status = _q_alloc( &idle_q, &_comp_ascend_uint ); if( status != SUCCESS ) { _kpanic( "_ioreq_init", "IO write queue alloc status %s", status ); } status = _q_alloc( &free_req_q, NULL); if( status != SUCCESS ) { _kpanic( "_ioreq_init", "IO free queue alloc status %s", status ); } for (i =0 ; i < ATA_MAX_REQUESTS; i++){ _ioreq_dealloc(&iorequest_pool[i]); } }
void _ioreq_handle_data_request(Drive *d){ Status status; Key key; Iorequest *req; key.v = d; status = _q_remove_by_key( data_q, (void **) &req, key ); if(status == NOT_FOUND || status == EMPTY_QUEUE){ req = NULL; //wasn't found //no data request on disk. Unsolicited data int i,j; for (i =0; i< 4;i++){ for (j=0;j<4;j++){ if (&_busses[i].drives[j]==d){ c_printf("bus[%d].drive[%d] %s",i,j,d->model); } } } _kpanic("handle_data_request", "Got unsolicited data.",FAILURE); return; } if (req->st == WAIT_ON_DATA){ if (req->read){ //send read request and add the data queue req->d->state=IDLE; _ata_read_finish(req->fd); _ioreq_dealloc(req); } else { //Unsolicited data... _kpanic("handle_data_request", "Got unsolicited, but waiting to write only.",FAILURE); } }else { //no data request on disk. Unsolicited data _kpanic("handle_data_request", "Got unsolicited data.",FAILURE); } }
void _sched_init( void ) { int i; Status status; for( i = 0; i < N_READYQ; ++i ) { status = _q_alloc( &_ready[i], NULL ); if( status != SUCCESS ) { _kpanic( "_sched_init", "readyq alloc status %s", status ); } } _current = NULL; c_puts( " scheduler" ); }
void _q_reset( queue_t *queue, q_compare_t compare, q_remove_t remove ) { // sanity check if( queue == NULL ) { _kpanic( "_q_reset", "null queue", 0 ); } // fill in all the fields queue->compare = compare; queue->remove = remove; queue->length = 0; queue->head = NULL; queue->tail = NULL; }
status_t _q_append( queue_t *queue, void *data, key_t key ) { qnode_t *qnode; status_t stat; // sanity check if( queue == NULL ) { // INCONSISTENCY _kpanic( "_q_append", "null queue", 0 ); } // first, get a qnode structure stat = _qnode_alloc( &qnode ); if( stat != E_SUCCESS ) { return( stat ); } // fill in the necessary information qnode->key = key; qnode->data = data; // add the node to the end of the queue if( _q_empty(queue) ) { queue->head = qnode; } else { queue->tail->next = qnode; } qnode->next = NULL; qnode->prev = queue->tail; queue->tail = qnode; queue->length += 1; return( E_SUCCESS ); }
void _init_stacks( void ) { int i; // first, put all stacks into the free pool // // NOTE: queues must have been initialized first! for( i = 0; i < N_PROCESSES; ++i ) { if( _free_stack(&g_stacks[i]) != ERR_NONE ) { _kpanic( "init stacks: enqueue failed" ); } } // set up the system stack _memclr( (void *)&g_system_stack, sizeof(Stack) ); g_system_esp = ((unsigned int *)(&g_system_stack + 1)) - 2; // announce that we have initialized the stack module c_puts( " stacks" ); }
static void _clock_isr( int vector, int code ) { (void)(vector); (void)(code); pcb_t *pcb; // spin the pinwheel ++_pinwheel; if( _pinwheel == (CLOCK_FREQUENCY / 10) ) { _pinwheel = 0; ++_pindex; c_putchar_at( 79, 0, "|/-\\"[ _pindex & 3 ] ); } // increment the system time ++_system_time; /* ** wake up any sleeper whose time has come ** ** we give awakened processes preference over the ** current process (when it is scheduled again) */ while( !_queue_empty(_sleeping) && (uint32_t) _queue_kpeek(_sleeping) <= _system_time ) { // time to wake up! remove it from the queue pcb = (pcb_t *) _queue_remove( _sleeping ); if( pcb == NULL ) { #ifdef DEBUG _kpanic( "_clock_isr", "NULL from sleep queue remove" ); #else c_puts( "*** _clock_isr: NULL from sleep queue\n" ); break; #endif } // and schedule it for dispatch _schedule( pcb ); } // check the current process to see if it needs to be scheduled // sanity check! _current->quantum -= 1; if( _current->quantum < 1 ) { _schedule( _current ); _dispatch(); } #ifdef DUMP_QUEUES // Approximately every 10 seconds, dump the queues, and // print the contents of the SIO buffers. if( (_system_time % SECONDS_TO_TICKS(10)) == 0 ) { c_printf( "Queue contents @%08x\n", _system_time ); _queue_dump( "ready[0]", _ready[0] ); _queue_dump( "ready[1]", _ready[1] ); _queue_dump( "ready[2]", _ready[2] ); _queue_dump( "ready[3]", _ready[3] ); _queue_dump( "sleep", _sleeping ); _sio_dump(); } #endif // tell the PIC we're done __outb( PIC_MASTER_CMD_PORT, PIC_EOI ); }
Status _elf_load_from_file(Pcb* pcb, const char* file_name) { // Need to copy the file_name into kernel land...because we're killing userland! const char* temp = file_name; file_name = (const char *)__kmalloc(_kstrlen(temp) + 1); _kmemcpy((void *)file_name, (void *)temp, _kstrlen(temp)+1); // Copy the null terminator as well serial_printf("---Elf: attempting to open: %s\n", file_name); if (pcb == NULL || file_name == NULL) { return BAD_PARAM; } // Try to open the file Elf32_Ehdr* elf32_hdr = (Elf32_Ehdr *)__kmalloc(sizeof(Elf32_Ehdr)); serial_printf("ELF header location: %x\n", elf32_hdr); Uint bytes_read = 0; VFSStatus vfs_status = raw_read(file_name, (void *)elf32_hdr, &bytes_read, 0, sizeof(Elf32_Ehdr)); if (vfs_status != FS_E_OK /* Couldn't read the file */ || bytes_read < sizeof(Elf32_Ehdr) /* Clearly not an ELF file */ || elf32_hdr->e_magic != ELF_MAGIC_NUM /* Need the magic number! */ || elf32_hdr->e_type != ET_EXEC /* Don't support relocatable or dynamic files yet */ || elf32_hdr->e_machine != EM_386 /* Make sure it's for our architecture */ || elf32_hdr->e_entry == 0x0 /* Need an entry point */ || elf32_hdr->e_version != EV_CURRENT /* We don't support extensions right now */ || elf32_hdr->e_phoff == 0 /* If there are no program headers, what do we load? */ || elf32_hdr->e_phnum == 0) /* ... */ // || elf32_hdr->e_ehsize != sizeof(Elf32_Ehdr)) /* The header size should match our struct */ { if (vfs_status != FS_E_OK) { serial_printf("RETURN VALUE: %x\n", vfs_status); _kpanic("ELF", "Failed to open file successfully\n", 0); } if (bytes_read < sizeof(Elf32_Ehdr)) _kpanic("ELF", "Read too small of a file!\n", 0); if (elf32_hdr->e_magic != ELF_MAGIC_NUM) _kpanic("ELF", "Bad magic number!\n", 0); if (elf32_hdr->e_type != ET_EXEC) _kpanic("ELF", "Not an executable ELF!\n", 0); if (elf32_hdr->e_machine != EM_386) _kpanic("ELF", "Not a i386 ELF!\n", 0); if (elf32_hdr->e_entry == 0x0) _kpanic("ELF", "Bad entry point!\n", 0); if (elf32_hdr->e_version != EV_CURRENT) _kpanic("ELF", "Don't support non-current versions!\n", 0); if (elf32_hdr->e_phoff == 0) _kpanic("ELF", "No program headers found!\n", 0); if (elf32_hdr->e_phnum == 0) _kpanic("ELF", "Zero program headers!\n", 0); _kpanic("ELF", "Couldn't open file!\n", 0); // Problem opening the file __kfree(elf32_hdr); return BAD_PARAM; } if (sizeof(Elf32_Phdr) != elf32_hdr->e_phentsize) { _kpanic("ELF", "program header size is different!\n", 0); } /* Okay lets start reading in and setting up the ELF file */ // We need a new buffer of size of (e_phentsize * e_phnum) Uint32 pheader_tbl_size = sizeof(Elf32_Phdr) * elf32_hdr->e_phnum; Elf32_Phdr* pheaders = (Elf32_Phdr *)__kmalloc(pheader_tbl_size); serial_printf("---ELF: program headers location: %x\n", pheaders); serial_printf("ELF: Reading program headers\n"); vfs_status = raw_read(file_name, (void *)pheaders, &bytes_read, elf32_hdr->e_phoff, pheader_tbl_size); if (vfs_status != FS_E_OK || bytes_read < pheader_tbl_size) { _kpanic("ELF", "error reading file!\n", 0); __kfree(pheaders); __kfree(elf32_hdr); return BAD_PARAM; } serial_printf("ELF: resetting page directory\n"); // Cleanup the old processes page directory, we're replacing everything __virt_reset_page_directory(); serial_printf("ELF: About to read the program sections\n"); /* We need to load all of the program sections now */ for (Int32 i = 0; i < elf32_hdr->e_phnum; ++i) { Elf32_Phdr* cur_phdr = &(pheaders[i]); if (cur_phdr->p_type == PT_LOAD) { if (cur_phdr->p_vaddr >= KERNEL_LINK_ADDR || cur_phdr->p_vaddr < 0x100000) { _kpanic("ELF", "An ELF with bad addresses loaded", 0); } serial_printf("\tELF: loading program section: %d at %x size: %x\n", i, cur_phdr->p_vaddr, cur_phdr->p_memsz); if (cur_phdr->p_memsz == 0) { serial_printf("\tELF: empty section, skipping\n"); continue; } // This is a loadable section //if (cur_phdr->p_align > 1) // _kpanic("ELF", "ELF loader doesn't support aligned program segments\n", 0); // Map these pages into memory! void* start_address = (void *)cur_phdr->p_vaddr; void* end_address = (void *)(start_address + cur_phdr->p_memsz); for (; start_address < end_address; start_address += PAGE_SIZE) { Uint32 flags = PG_USER; if ((cur_phdr->p_flags & PF_WRITE) > 0) { flags |= PG_READ_WRITE; } serial_printf("Checking address: %x\n", __virt_get_phys_addr(start_address)); serial_printf("Start address: %x\n", start_address); if (__virt_get_phys_addr(start_address) == (void *)0xFFFFFFFF) { serial_printf("ELF: Mapping page: %x - flags: %x\n", start_address, flags); __virt_map_page(__phys_get_free_4k(), start_address, flags); serial_printf("ELF: Done mapping page\n"); } else { serial_printf("Address: %x already mapped\n", start_address); } } serial_printf("ELF: about to memcpy program section: %x of size %d\n", cur_phdr->p_vaddr, cur_phdr->p_memsz); // Lets zero it out, we only need to zero the remaining bytes, p_filesz // may be zero for data sections, in this case the memory should be zeroed _kmemclr((void *)(cur_phdr->p_vaddr + (cur_phdr->p_memsz - cur_phdr->p_filesz)), cur_phdr->p_memsz - cur_phdr->p_filesz); serial_printf("ELF: done memory copying: %s\n", file_name); // Now we have to read it in from the file if (cur_phdr->p_filesz > 0) { serial_printf("\tAt offset: %x\n", cur_phdr->p_offset); vfs_status = raw_read(file_name, (void *)cur_phdr->p_vaddr, &bytes_read, cur_phdr->p_offset, cur_phdr->p_filesz); serial_printf("Read: %d - File size: %d\n", bytes_read, cur_phdr->p_filesz); if (bytes_read != cur_phdr->p_filesz) { _kpanic("ELF", "Failed to read data from the filesystem", 0); } if (vfs_status != FS_E_OK) { // TODO - cleanup if error _kpanic("ELF", "failed to read program section\n", 0); } //asm volatile("hlt"); } } else { serial_printf("\tELF: Non-loadable section: %d at %x size: %x type: %d\n", i, cur_phdr->p_vaddr, cur_phdr->p_memsz, cur_phdr->p_type); } } // Setup the PCB information // Allocate a stack and map some pages for it #define USER_STACK_LOCATION 0x2000000 #define USER_STACK_SIZE 0x4000 /* 16 KiB */ serial_printf("ELF: Allocating stack\n"); void* stack_start = (void *)USER_STACK_LOCATION; void* stack_end = (void *)(USER_STACK_LOCATION + USER_STACK_SIZE); for (; stack_start < stack_end; stack_start += PAGE_SIZE) { __virt_map_page(__phys_get_free_4k(), stack_start, PG_READ_WRITE | PG_USER); } _kmemclr((void *)USER_STACK_LOCATION, USER_STACK_SIZE); // Throw exit as the return address as a safe guard serial_printf("ELF: setting up context\n"); // Setup the context Context* context = ((Context *)(USER_STACK_LOCATION+USER_STACK_SIZE-4)) - 1; serial_printf("Context location: %x\n", context); pcb->context = context; context->esp = (Uint32)(((Uint32 *)context) - 1); context->ebp = (USER_STACK_LOCATION+USER_STACK_SIZE)-4; context->cs = GDT_CODE; context->ss = GDT_STACK; context->ds = GDT_DATA; context->es = GDT_DATA; context->fs = GDT_DATA; context->gs = GDT_DATA; serial_printf("ELF: setting entry point: %x\n", elf32_hdr->e_entry); // Entry point context->eip = elf32_hdr->e_entry; // Setup the rest of the PCB pcb->context->eflags = DEFAULT_EFLAGS; serial_printf("ELF: about to return\n"); __kfree(pheaders); __kfree(elf32_hdr); __kfree((void *)file_name); return SUCCESS; }
void _init( void ) { pcb_t *pcb; /* ** BOILERPLATE CODE - taken from basic framework ** ** Initialize interrupt stuff. */ __init_interrupts(); // IDT and PIC initialization // Ignore the 0x2A interrupt which happens when removing or inserting a // flash drive. __install_isr( 0x2A, _ignore_isr ); /* ** Console I/O system. */ c_io_init(); c_clearscreen(); #ifdef ISR_DEBUGGING_CODE c_setscroll( 0, 7, 99, 99 ); c_puts_at( 0, 6, "================================================================================" ); #endif /* ** 20123-SPECIFIC CODE STARTS HERE */ /* ** Initialize various OS modules ** ** Note: the clock, SIO, and syscall modules also install ** their ISRs. */ c_puts( "Module init: " ); _q_init(); // must be first _pcb_init(); _stack_init(); _sio_init(); _sys_init(); _sched_init(); _clock_init(); _pci_init(); _disk_init(); _net_init(); c_puts( "\n" ); c_puts("Launching the shell. Please be patient\n"); __delay(1000); c_clearscreen(); /* ** Create the initial system ESP ** ** This will be the address of the next-to-last ** longword in the system stack. */ _system_esp = ((uint32_t *) ( (&_system_stack) + 1)) - 2; /* ** Create the initial process ** ** Code mostly stolen from _sys_fork(); if that routine ** changes, SO MUST THIS!!! */ // allocate a PCB and stack pcb = _create_process( NULL ); if( pcb == NULL ) { _kpanic( "_init", "init() creation failed", FAILURE ); } // initialize the stack with the standard context pcb->context = _create_stack( pcb->stack ); if( pcb->context == NULL ) { _kpanic( "_init", "init() stack setup failed", FAILURE ); } // define the entry point for init() pcb->context->eip = (uint32_t) init; // set up various PCB fields pcb->pid = pcb->ppid = PID_INIT; // next PID is initially 1 pcb->prio = PRIO_HIGH; pcb->children = 1000; // remember this PCB for use in reparenting orphan processes _init_pcb = pcb; // make it the first process _schedule( pcb ); _dispatch(); /* ** Turn on the SIO receiver (the transmitter will be turned ** on/off as characters are being sent) */ _sio_enable( SIO_RX ); /* ** END OF 20123-SPECIFIC CODE ** ** Finally, report that we're all done. */ c_puts( "System initialization complete.\n" ); }
void _zombify( pcb_t *pcb ) { estatus_t *esptr; pid_t *pidptr; pid_t ppid; pcb_t *parent, *p2; int i; key_t key; status_t stat; // mark the process as no longer runnable pcb->state = ZOMBIE; // find the parent ppid = pcb->ppid; for( i = 0; i < N_PCBS; ++i ) { if( _pcbs[i].pid == ppid && _pcbs[i].state != FREE ) { parent = &_pcbs[i]; break; } } /* ** If we didn't find a parent, or if the parent was ** already unrunnable (zombied, killed), reparent this ** process to the init process */ if( i >= N_PCBS || _pcbs[i].state >= FIRST_DEAD_STATE ) { ppid = pcb->ppid = PID_INIT; parent = _init_pcb; } /* ** At this point, parent points to the parent's PCB, and ppid ** contains the parent's PID. ** ** If the parent is on the wait() queue, we'll awaken it and give ** it this child's information. ** ** Otherwise, we need to put this child on the zombie queue. */ if( parent->state == WAITING ) { // look for the parent on the wait queue key.u = ppid; stat = _q_remove_specific( &_waiting, (void **) &p2, key ); if( stat != SUCCESS ) { _kpanic( "_zombify", "parent wait remove status %s", stat ); } // verify that we found the same process if( p2 != parent ) { _pcb_dump( "*** p2: ", p2 ); _pcb_dump( "*** parent: ", parent ); _kpanic( "_zombify", "parent wait deque wrong", FAILURE ); } // OK, we have the right one. // Start by decrementing its "remaining children" // counter if it isn't the init process if( ppid != PID_INIT ) { parent->children -= 1; } // return the child's information to it. RET(parent) = U_SUCCESS; pidptr = (pid_t *) ARG(parent)[1]; *pidptr = pcb->pid; esptr = (estatus_t *) ARG(parent)[2]; *esptr = ARG(pcb)[1]; // schedule the parent (who returns from wait()) _schedule( parent ); // clean up the child process _pcb_cleanup( pcb ); } else { // place this child on the zombie queue, ordered by PID key.u = pcb->pid; pcb->status = ARG(pcb)[1]; stat = _q_insert( &_zombie, (void *)pcb, key ); if( stat != SUCCESS ) { _kpanic( "_zombify", "zombie insert status %s", stat ); } } }
void _init( void ) { Pcb *pcb; // // BOILERPLATE CODE - taken from basic framework // // Initialize interrupt stuff. // __init_interrupts(); // IDT and PIC initialization // // I/O system. // c_io_init(); c_clearscreen(); c_setscroll( 0, 7, 99, 99 ); c_puts_at( 0, 6, "================================================================================" ); c_puts( "Init: " ); // // 20073-SPECIFIC CODE STARTS HERE // // // Initialize various OS modules // _init_queues(); // must be first _init_memory(); _init_processes(); _init_stacks(); _init_sio(); _init_clock(); _init_syscalls(); c_puts( "\n" ); // // Create the initial process // // Code mostly stolen from _sys_fork() and _sys_exec(); // if either of those routines change, SO MUST THIS!!! // // // First, get a PCB and a stack // pcb = _get_pcb(); if( pcb == 0 ) { _kpanic( "_init - can't allocate first pcb" ); } pcb->stack = _get_stack(); if( pcb->stack == 0 ) { _kpanic( "_init - can't allocate first stack" ); } // // Next, set up various PCB fields // pcb->pid = g_next_pid++; pcb->prio = PRI_NORMAL; // // Set up the initial process context. // // See _sys_exec() for an explanation of how this works. // pcb->context = _setup_stack( pcb->stack, (unsigned int) first_main ); // Initialize memory segment. Equals that of the kernel's in the GDT. pcb->seg.mem.offset = 0x0; pcb->seg.mem.length = 0xFFFFFFFF; // Initialize LDT entries for this PCB // This is a "kernel" process, so we will just copy over the // descriptors from the GDT and stick them into this process' LDT. __copy_gdt_entry( &(pcb->seg.ldt.cseg), (GDT_INDEX(GDT_CODE)) ); __copy_gdt_entry( &(pcb->seg.ldt.dseg), (GDT_INDEX(GDT_DATA)) ); // Allocate a slot in the GDT for the LDT descriptor, // and initialize this PCB's LDT register variable. pcb->seg.ldtr = SEL_SETINDEX(_gdt_alloc()) | SEL_GDT | SEL_RPL(0); // Initialize the LDT descriptor located in the GDT __gdt_set_entry( SEL_GETINDEX(pcb->seg.ldtr), (u32_t)&(pcb->seg.ldt), sizeof(ldt_t), ACC_PRES | ACC_DPL(0) | ACC_SYS | SYS_LDT ); // // Give it to the scheduler. // _schedule( pcb ); // // Do it all again for the idle process. // pcb = _get_pcb(); if( pcb == 0 ) { _kpanic( "_init - can't allocate idle pcb" ); } pcb->stack = _get_stack(); if( pcb->stack == 0 ) { _kpanic( "_init - can't allocate idle stack" ); } pcb->pid = g_next_pid++; pcb->prio = PRI_MINIMUM; pcb->context = _setup_stack( pcb->stack, (unsigned int) idle_main ); pcb->seg.mem.offset = 0x0; pcb->seg.mem.length = 0xFFFFFFFF; __copy_gdt_entry( &(pcb->seg.ldt.cseg), (GDT_INDEX(GDT_CODE)) ); __copy_gdt_entry( &(pcb->seg.ldt.dseg), (GDT_INDEX(GDT_DATA)) ); pcb->seg.ldtr = SEL_SETINDEX(_gdt_alloc()) | SEL_GDT | SEL_RPL(0); __gdt_set_entry( SEL_GETINDEX(pcb->seg.ldtr), (u32_t)&(pcb->seg.ldt), sizeof(ldt_t), ACC_PRES | ACC_DPL(0) | ACC_SYS | SYS_LDT ); _schedule( pcb ); // // Dispatch the initial current process // _dispatch(); // // END OF 20073-SPECIFIC CODE // // Finally, report that we're all done. // c_puts( "System initialization complete.\n" ); }
void _zombify( pcb_t *pcb ) { pcb_t *parent; status_t stat; pid_t pid; key_t key; info_t *info; // sanity check if( pcb == NULL ) { _kpanic( "_zombify", "null pcb", 0 ); } // Locate the parent of this process parent = _pcb_find( pcb->ppid ); if( parent == NULL ) { c_printf( "** zombify(): pid %d ppid %d\n", pcb->pid, pcb->ppid ); _kpanic( "_zombify", "no process parent", 0 ); } // // Found the parent. If it's waiting for this process, // wake it up, give it this process' status, and clean up. // if( parent->state == WAITING ) { // get the address of the info structure from the // parent, and pull out the desired PID info = (info_t *) ARG(parent->context,1); pid = info->pid; // if the parent was waiting for any of its children // or was waiting for us specifically, give it our // information and terminate this process. // // if the parent was waiting for another child, // turn this process into a zombie. if( pid == 0 || pid == _current->pid ) { // pull the parent off the waiting queue key.u = parent->pid; stat = _q_remove_by_key(&_waiting,(void **)&parent,key); if( stat != E_SUCCESS ) { _kpanic( "_zombify", "wait remove status %s", stat ); } // return our PID and our termination status // to the parent info->pid = _current->pid; info->status = ARG(_current->context,1); // clean up this process stat = _stack_free( pcb->stack ); if( stat != E_SUCCESS ) { _kpanic( "_zombify", "stack free status %s", stat ); } stat = _pcb_free( pcb ); if( stat != E_SUCCESS ) { _kpanic( "_zombify", "pcb free status %s", stat ); } // schedule the parent; give it a quick dispatch _schedule( parent, PRIO_MAXIMUM ); return; } } // // Our parent either wasn't waiting, or was waiting for someone // else. Put this process on the zombie queue until our parent // wants us. // key.u = _current->pid; _current->state = ZOMBIE; stat = _q_insert( &_zombie, (void *)_current, key ); if( stat != E_SUCCESS ) { _kpanic( "_zombify", "zombie insert status %s", stat ); } }
status_t _q_remove_by_key( queue_t *queue, void **data, key_t key ) { qnode_t *qnode; status_t stat; // verify that our parameters are usable if( queue == NULL || data == NULL ) { return( E_BAD_PARAM ); } // if the queue is empty, nothing to do if( _q_empty(queue) ) { return( E_EMPTY ); } // if there is no specialized removal routine, do an ordinary remove if( queue->remove == NULL ) { return( _q_remove(queue,data) ); } // // Traverse the queue, looking for the correct element. // Use the built-in removal routine to determine when // we have found the correct entry. // qnode = queue->head; while( qnode != NULL && !queue->remove(qnode->key,key) ) { qnode = qnode->next; } // did we find the one we wanted? if( qnode == NULL ) { return( E_NOT_FOUND ); } // found the correct node - unlink it from the queue if( qnode->prev != NULL ) { qnode->prev->next = qnode->next; } else { queue->head = qnode->next; } if( qnode->next != NULL ) { qnode->next->prev = qnode->prev; } else { queue->tail = qnode->prev; } queue->length -= 1; // return the data from the node *data = qnode->data; // release the qnode // // INCONSISTENCY: _q_remove() just propogates the status stat = _qnode_free( qnode ); if( stat != E_SUCCESS ) { _kpanic( "_q_remove_by_key", "qnode free failed, %s", stat ); } return( E_SUCCESS ); }
void _init( void ) { pcb_t *pcb; context_t *context; status_t stat; /* ** BOILERPLATE CODE - taken from basic framework ** ** Initialize interrupt stuff. */ __init_interrupts(); // IDT and PIC initialization /* ** Console I/O system. */ c_io_init(); c_setscroll( 0, 7, 99, 99 ); c_puts_at( 0, 6, "================================================================================" ); /* ** 20103-SPECIFIC CODE STARTS HERE */ /* ** Initialize various OS modules */ c_puts( "Starting module init: " ); _q_init(); // must be first _pcb_init(); _stack_init(); _sio_init(); _syscall_init(); _sched_init(); _clock_init(); //_pci_init(); build_lapic_info(); _paging_init(); c_puts( "\n" ); c_puts(" Ending init\n"); initSMP(); /* ** Create the initial system ESP ** ** This will be the address of the next-to-last ** longword in the system stack. */ _system_esp = ((uint32_t *) ( (&_system_stack) + 1)) - 2; /* ** Install the ISRs */ __install_isr( INT_VEC_TIMER, _isr_clock ); __install_isr( INT_VEC_SYSCALL, _isr_syscall ); __install_isr( INT_VEC_SERIAL_PORT_1, _isr_sio ); /* ** Create the initial process ** ** Code mostly stolen from _sys_fork() and _sys_exec(); ** if either of those routines change, SO MUST THIS!!! ** ** First, get a PCB and a stack */ stat = _pcb_alloc( &pcb ); if( stat != E_SUCCESS ) { _kpanic( "_init", "first pcb alloc status %s", stat ); } stat = _stack_alloc( &(pcb->stack) ); if( stat != E_SUCCESS ) { _kpanic( "_init", "first stack alloc status %s", stat ); } /* ** Next, set up various PCB fields */ pcb->pid = PID_INIT; pcb->ppid = PID_INIT; pcb->prio = PRIO_MAXIMUM; /* ** Set up the initial process context. */ context = _setup_stack( pcb->stack, (uint32_t) init ); // Finally, set up the process' ESP context->esp = (uint32_t) context; // Make it the "current" process _current = pcb; _current->context = context; /* ** Starting up the idle routine is the responsibility ** of the initial user process. */ /* ** Turn on the SIO receiver (the transmitter will be turned ** on/off as characters are being sent) */ _sio_enable( SIO_RX ); /* ** END OF 20103-SPECIFIC CODE ** ** Finally, report that we're all done. */ c_puts( "System initialization complete.\n" ); }
Uint32 ext2_write_file_by_inode (struct ext2_filesystem_context *context, struct ext2_directory_entry *file, void *buffer, Uint32 start, Uint32 nbytes) { Uint32 inode_num = file->inode_number; struct ext2_inode *fp = get_inode( context, inode_num ); Uint32 block_size = get_block_size( context->sb ); Uint32 indirect_block_size = block_size * block_size / sizeof(Uint32); // If we're going to write off of the end of a file, we need to // allocate a new block for the inode. if( fp->size < (nbytes+start) ) { // We can't have a gap in our file; don't start writing past // the end of the file. if( start > fp->size ) { return EXT2_WRITE_NON_CONTIGUOUS; } else { increase_inode_size ( context, fp, nbytes+start-(fp->size) ); } } // At this point, we know that we have enough blocks to store the data. Uint32 remaining_bytes = nbytes; // Skip ahead to the block that we need to write Uint32 first_inode_block = start / block_size; // Literal inode block indexes Uint32 indirect_inode_block_idx; Uint32 direct_inode_block_idx; if( first_inode_block >= EXT2_INODE_INDIRECT_BLOCK_IDX ) { direct_inode_block_idx = EXT2_INODE_INDIRECT_BLOCK_IDX; indirect_inode_block_idx = first_inode_block - EXT2_INODE_INDIRECT_BLOCK_IDX; } else { direct_inode_block_idx = first_inode_block; indirect_inode_block_idx = 0; } // The number of bytes into the first block that we need to skip Uint32 block_offset = start % block_size; for (Uint32 inode_block_idx = direct_inode_block_idx; inode_block_idx < EXT2_INODE_TOTAL_BLOCKS; inode_block_idx++) { Uint32 block_number = fp->blocks[inode_block_idx]; PRINT_VARIABLE( block_number ); Uint32 direct_inode_block_idx = first_inode_block % EXT2_INODE_TOTAL_BLOCKS; const char *data = (const char*) (block_offset + ((void*) block_number_to_address( context, block_number ))); // Pointer to an indirect block data area (can't be declared // inside of the `switch' statement. const void *indirect_block; #if DEBUG_FILESYSTEM PRINT_VARIABLE( block_offset ); serial_printf("inode_block_idx: %d\n\r", inode_block_idx ); PRINT_VARIABLE( indirect_inode_block_idx ); PRINT_VARIABLE( dub_indirect_inode_block_idx ); PRINT_VARIABLE( trip_indirect_inode_block_idx ); #endif // TODO: Support dub. indirect, trip. indirect blocks switch( inode_block_idx ) { case EXT2_INODE_TRIP_INDIRECT_BLOCK_IDX: case EXT2_INODE_DUB_INDIRECT_BLOCK_IDX: _kpanic( "ext2", __FILE__ ":" CPP_STRINGIFY_RESULT(__LINE__) " No support for double or tripple indirect blocks", FEATURE_UNIMPLEMENTED ); case EXT2_INODE_INDIRECT_BLOCK_IDX: // Dont' factor in the block offset when getting the // indirect data block. indirect_block = (const void*) (block_number_to_address( context, block_number )); // Don't let the inode block index advance unless // we've used all of the blocks in the indirect data // block. if( indirect_inode_block_idx < indirect_data_block_size(context) ) { --inode_block_idx; } data = (const void*) block_number_to_address( context, ((Uint32*) indirect_block)[indirect_inode_block_idx] ); data += block_offset; serial_printf("data: %x\n\r", data ); ++indirect_inode_block_idx; } if( remaining_bytes < block_size ) { _kmemcpy( data, buffer, remaining_bytes ); // We've copied everything we need to. Time to leave. remaining_bytes = 0; break; } else { _kmemcpy( data, buffer, block_size-block_offset ); buffer += (block_size-block_offset); // There's more to read remaining_bytes -= (block_size-block_offset); } // Reset the block offset -- we only use it once! block_offset = 0; } return nbytes-remaining_bytes; }
static void _isr_sio( int vector, int code ) { Pcb *pcb; int eir; int ch; // // Must process all pending events; loop until the EIR // says there's nothing else to do. // for( ; ; ) { // get the "pending event" indicator eir = __inb( UA4_EIR ) & UA4_EIR_INT_PRI_MASK; // process this event switch( eir ) { case UA4_EIR_TX_INT_PENDING: // if there is another character, send it if( g_sending && g_outcount > 0 ) { __outb( UA4_TXD, *g_outnext ); ++g_outnext; --g_outcount; } else { // no more data - reset the output vars g_outcount = 0; g_outlast = g_outnext = g_outbuffer; g_sending = 0; } break; case UA4_EIR_RX_INT_PENDING: // get the character ch = __inb( UA4_RXD ); if( ch == '\r' ) { // map CR to LF ch = '\n'; } // // If there is a waiting process, this must be // the first input character; give it to that // process and awaken the process. // if( g_sio_blocked.front != 0 ) { if( _deque(&g_sio_blocked,(void **)&pcb) != ERR_NONE ) { _kpanic( "sio isr - serial wakeup failed" ); } pcb->context->eax = ch & 0xff; _schedule( pcb ); } else { // // Nobody waiting - add to the input buffer // if there is room, otherwise just ignore it. // if( g_incount < BUF_SIZE ) { *g_inlast++ = ch; ++g_incount; } } break; case UA4_EIR_NO_INT: // nothing to do - tell the PIC we're done __outb( PIC_MASTER_CMD_PORT, PIC_EOI ); return; default: _kpanic( "sio isr - unknown device status" ); } } }