view src/os/shell.c @ 160:3d891b634acb default tip

Fix to make make work
author Jonathan Pevarnek <pevarnj@gmail.com>
date Fri, 25 Nov 2011 23:27:09 -0500
parents a6482018de66
children
line wrap: on
line source

#include <std.h>
#include <string.h>
#include <stdio.h>
#include <error.h>
#include <die.h>
#include <os/fs.h>
#include <os/elf.h>
#include <os/psw.h>
#include <os/svc.h>
#include <os/scall.h>
#include <os/pcb.h>
#include <os/storageKeys.h>
#include <os/memLayout.h>

#define MAX_INPUT_LENGTH 128 //128 characters maximum input
#define MAX_ARGS 10 //no more than ten arguments, including the program name

void start(u64 __memsize)
{
	char buffer[MAX_INPUT_LENGTH];
	char *c, *track;
	char *argStartLoc = (void*)PROGRAM_STACK_START - MAX_INPUT_LENGTH;

	ErrCode err;
	init_all(__memsize);
	if(isError(init_fs(0x100, __memsize))) die();
	set_svc_handler(svc_handler, (void*)(KERNEL_STACK_START - STACK_SPACING));
	
	sPrint("SOS online!\n");
	while(1) {
		sPrint("$ ");
		sGet(buffer, MAX_INPUT_LENGTH);
		memcpy(argStartLoc, buffer, MAX_INPUT_LENGTH); //copy the command+arguments over
		c = strtok_r(buffer, " ", &track);

		u32 fid;
		if(isError(err = lookupFile(c, &fid))) {
			if(errCode(err) == NOTFILE) sPrint("ERROR: command not found\n");
			continue;
		} else {
			u32 fileSize;
			if(isError(getFileSize(fid, &fileSize))) { //get the length of the file
				sPrint("ERROR: could not read file size\n");
				continue;
			}
			void *data = malloc(fileSize);
			if(!data) continue;
			if(isError(getFileData(fid, data))) goto loopCont;
			Elf64_Ehdr *eHdr = data;
			if(eHdr->e_ident[EI_MAG0] != ELFMAG0 || eHdr->e_ident[EI_MAG1] != ELFMAG1 ||
					eHdr->e_ident[EI_MAG2] != ELFMAG2 || eHdr->e_ident[EI_MAG3] != ELFMAG3) {
				goto loopCont; //problem with program, ask for a new one
			}
			if(eHdr->e_ident[EI_CLASS] != ELFCLASS64) goto loopCont;
			int i;
			size_t textEnd = PROGRAM_TEXT_START; //assume that there is no text
			for(i = 0; i < eHdr->e_phnum; i++) { //go through all the headers
				Elf64_Phdr *pHdr = ((Elf64_Phdr*)(data + eHdr->e_phoff) + i);
				if(pHdr->p_type == PT_LOAD) { //these segments get loaded into the memory
					void *fromLoc = data + pHdr->p_offset;
					void *toLoc = (void*)pHdr->p_vaddr;
					memcpy(toLoc, fromLoc, pHdr->p_filesz);
					size_t diff = pHdr->p_memsz - pHdr->p_filesz;
					if(diff) memset(toLoc + pHdr->p_filesz, 0, diff);
					size_t endLoc = pHdr->p_vaddr + pHdr->p_memsz;
					if(endLoc > textEnd) {
						textEnd = endLoc; //ending location of the program text
					}
				}
			}
			
			//allow the program to have read-only access to its text
			size_t sKeyPtr;
			for(sKeyPtr = PROGRAM_TEXT_START; sKeyPtr < textEnd; sKeyPtr += BLOCKSIZE) {
				setStorageKey(sKeyPtr, PROGSK, 0);
			}

			PCB pcb;
			memset(&pcb, 0, sizeof(pcb));

			/* TODO FUTURE PLAN FOR COMMAND LINE PARAMETERS
			 * Instead of the current way of copying things, I would like to eventually
			 * change it so that each argument is copied over and its location added to
			 * a stack.  Later, the items could be removed from the stack and placed in
			 * the program stack in the correct order
			 */

			char **argv = (void*)PROGRAM_STACK_START - MAX_INPUT_LENGTH - MAX_ARGS*(sizeof(char*));
			char **curArg = argv;
			char *b = argStartLoc;
			int argc = 0;
			
			while((*curArg++ = strtok_r(b, " ", &track))) {
				if(b) b = NULL;
				if(++argc == MAX_ARGS) break; //TODO find a better way to deal with this
			}

			size_t argOffset = MAX_INPUT_LENGTH + MAX_ARGS*(sizeof(char*));
			//I know the preceding line is a duplicate from the above, in the future
			//I want to get rid of MAX_ARGS so this will be actually calculated...

			pcb.registers[2] = argc;
			pcb.registers[3] = (u64)argv;
			pcb.registers[15] = PROGRAM_STACK_START - argOffset - STACK_SPACING;
			pcb.psw.p = 1;
			pcb.psw.ea = 1;
			pcb.psw.ba = 1;
			pcb.psw.key = PROGSK;
			pcb.psw.ptr = eHdr->e_entry;

			swapcontext_pcb(&shellPCB, &pcb);

			//unset any storage keys that were set for the program text
			for(sKeyPtr = PROGRAM_TEXT_START; sKeyPtr < textEnd; sKeyPtr += BLOCKSIZE) {
				setStorageKey(sKeyPtr, 0, 1);
			}
		loopCont:
			free(data);
		}
	}
}