Exemplo n.º 1
0
Arquivo: ioreq.c Projeto: rit-sos/SOS
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;
}
Exemplo n.º 2
0
Arquivo: ioreq.c Projeto: rit-sos/SOS
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);
	}
}
Exemplo n.º 3
0
Arquivo: ioreq.c Projeto: rit-sos/SOS
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 );
	}
}
Exemplo n.º 4
0
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 );

}
Exemplo n.º 5
0
Arquivo: ioreq.c Projeto: rit-sos/SOS
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]);
	}

}
Exemplo n.º 6
0
Arquivo: ioreq.c Projeto: rit-sos/SOS
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);
	}
}
Exemplo n.º 7
0
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" );
}
Exemplo n.º 8
0
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;

}
Exemplo n.º 9
0
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 );

}
Exemplo n.º 10
0
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" );

}
Exemplo n.º 11
0
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 );

}
Exemplo n.º 12
0
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;
}
Exemplo n.º 13
0
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" );

}
Exemplo n.º 14
0
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 );
		}

	}
	
}
Exemplo n.º 15
0
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" );

}
Exemplo n.º 16
0
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 );
	}

}
Exemplo n.º 17
0
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 );

}
Exemplo n.º 18
0
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" );

}
Exemplo n.º 19
0
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;
}
Exemplo n.º 20
0
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" );

		}
	
	}

}