Beispiel #1
0
GFX_CONTEXT *_kgfx_new_context(int pid) {
    int context = -1;
    //check for existing context for this pid
    for (int i = 0; i < MAX_CONTEXTS; i++) {
        if (context_pid[i] == pid) {
            context = i;
            break;
        }
    }

    if (context == -1) {
        //take first unused context
        for (int i = 0; i < MAX_CONTEXTS; i++) {
            if (!context_pid[i]) {
                num_contexts++;
                context_pid[i] = pid;
                context = i;
                break;
            }
        }
    }

    _kmemclr(contexts[context].backbuffer->data, VGA_SIZE);
    _kmemcpy((uint8_t *)&palettes[context], (uint8_t *)&default_palette, PALETTE_SIZE);


    return &contexts[context];

}
Beispiel #2
0
ext2_write_status
ext2_raw_write
	(struct ext2_filesystem_context *context,
	const char *path,
	const void *buffer,
	Uint32 *bytes_written,
	Uint32 start,
	Uint32 nbytes)
{
	if( !bytes_written )
	{
		Uint32 throwaway = 0;
		bytes_written = &throwaway;
	}
	*bytes_written = 0;

	if( path[0] != DIRECTORY_SEPARATOR )
	{
		return EXT2_WRITE_NO_LEADING_SLASH;
	}

	// Split up the path into the filename and dirname components
	Uint path_length = _kstrlen( path );
	const char *filename = _kstrrchr( path, DIRECTORY_SEPARATOR ) + 1;

	// Set up the directory name, keep the trailing slash, ignore filename.
	char dirname[path_length+1];
	_kmemcpy( dirname, path, path_length+1 );
	serial_printf( __FILE__ ":" CPP_STRINGIFY_RESULT(__LINE__)
			", dirname before excluding filename: %s\n\r",
			dirname );
	((char *)_kstrrchr( dirname, DIRECTORY_SEPARATOR ))[1] = '\0';
	serial_printf( __FILE__ ":" CPP_STRINGIFY_RESULT(__LINE__)
			", dirname after excluding filename: %s\n\r",
			dirname );
	((char *)_kstrrchr( dirname, DIRECTORY_SEPARATOR ))[1] = '\0';

	struct ext2_directory_entry* file =
		get_file_from_dir_path( context, dirname, filename );

	if( file )
	{
		*bytes_written = ext2_write_file_by_inode(context, file, buffer, start, nbytes);
		return EXT2_WRITE_SUCCESS;
	}
	else
	{
		return EXT2_WRITE_FILE_NOT_FOUND;
	}
}
Beispiel #3
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;
}
Beispiel #4
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;
}
Beispiel #5
0
pcb_t *_create_process( pcb_t *curr ) {
	pcb_t *pcb;
	stack_t *stack;
	int offset;
	uint32_t *ptr;
	
	// allocate the new structures

	pcb = _pcb_alloc();
	if( pcb == NULL ) {
		return( NULL );
	}

	stack = _stack_alloc();
	if( stack == NULL ) {
		_pcb_free(pcb);
		return( NULL );
	}
	
	/*
	** The PCB argument will be NULL if this function is called
	** from the system initialization, and non-NULL if called 
	** from the fork() implementation.
	**
	** In the former case, we initialize the new data structures for
	** a brand-new process.
	**
	** In the latter case, we replicate the information from the
	** existing process whose PCB was passed in.
	*/

	if( curr != NULL ) {	// called from fork()
	
		// duplicate the PCB and stack contents

		_kmemcpy( (void *) pcb, (void *) curr, sizeof(pcb_t) );
		_kmemcpy( (void *) stack, (void *) curr->stack, sizeof(stack_t) );
		
		// update the entries which should be changed in the PCB

		pcb->pid = _next_pid++;
		pcb->ppid = curr->pid;
		pcb->stack = stack;
		
	        /*
		** We duplicated the original stack contents, which
		** means that the context pointer and ESP and EBP values
		** in the new stack are still pointing into the original
		** stack.  We need to correct all of these.
		**
		** We have to change EBP because that's how the compiled
		** code for the user process accesses its local variables.
		** If we didn't change this, as soon as the new process
		** was dispatched, it would start to stomp on the local
		** variables in the original process' stack.  We also
       		** have to fix the EBP chain in the child process.
		**
		** None of this would be an issue if we were doing "real"
		** virtual memory, as we would be talking about virtual
		** addresses here rather than physical addresses, and all
		** processes would share the same virtual address space
		** layout.
		**
		** First, determine the distance (in bytes) between the
		** two stacks.  This is the adjustment value we must add
		** to the three pointers to correct them.  Note that this
		** distance may be positive or negative, depending on the
		** relative placement of the two stacks in memory.
		*/

		offset = (void *) (pcb->stack) - (void *) (curr->stack);
		
		// modify the context pointer for the new process

		pcb->context = (context_t *)( (void *) (pcb->context) + offset );
		// now, change ESP and EBP in the new process (easy to
		// do because they're just uint32_t values, not really
		// pointers)

		pcb->context->esp += offset;
		pcb->context->ebp += offset;

		/*
        	** Next, we must fix the EBP chain in the new stack.  This
		** is necessary in the situation where the fork() occurred
		** in a nested function call sequence; we fixed EBP, but
		** the "saved" EBP in the stack frame is pointing to the
		** calling function's frame in the original stack, not the
		** new stack.
		**
		** We are guaranteed that the chain of frames ends at the
		** frame for the original process' main() routine, because
		** exec() will initialize EBP for the process to 0, and the
		** entry prologue code in main() routine will push EBP,
		** ensuring a NULL pointer in the chain.
        	*/

		// start at the current frame

		ptr = (uint32_t *) pcb->context->ebp;

		// follow the chain of frame pointers to its end
		while( *ptr != 0 ) {
			// update the link from this frame to the previous
			*ptr += offset;
			// follow the updated link
			ptr = (uint32_t *) *ptr;
		}
		
	} else {		// called from init

		pcb->pid = pcb->ppid = PID_INIT;
		pcb->stack = stack;
	
	}
	
	// all done - return the new PCB

	return( pcb );
}