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]; }
void _kgfx_init(void) { _kmemclr((uint8_t *)context_pid, sizeof(context_pid)); _kgfx_delete_context(0); //delete all contexts num_contexts = 0; screen = create_bitmap(SCREEN_W, SCREEN_H, -1, (uint8_t *)VGA_START); font = create_bitmap(1024, 8, 255, font_data); for (int i = 0; i < FONT_BYTES; i++) { font_data_white[i] = font_data[i] == 255 ? 0 : 1; } font_white = create_bitmap(1024, 8, 0, font_data_white); cleartocolor(&screen, 5 * 16 + 8); text(&screen, "Welcome", 160, 75, 1); text(&screen, "to", 160, 85, 1); text(&screen, "ChemanOS", 160, 95, 1); }
/** * Initializes the gl library and the vga devices. Then initializes all of the * memory required for the window manager, and sets all default values. * */ void _win_man_init( void ) { int i = 0; int j = 0; void* bPtrOffset = 0; int dW, dH = 0; int x, y; Uint32 s_arr_size, buff_size; _vga_init(); //setup the memory for the arrays and // this module wm_memory = (void *)( 0x20000000 ); //array of screen_infos screen_info_arr = (screen_info *)( ((Uint32)wm_memory) + WIN_MAN_MEM ); //get screen info dW = vga_mode_info->XResolution / 2; dH = vga_mode_info->YResolution / 2; //begining of buffers s_arr_size = (DEFAULT_SCREENS) * sizeof( struct screen_info ); buff_size = (DEFAULT_SCREENS) * dH * dW * 4; bPtrOffset = (void *)((Uint32)screen_info_arr + s_arr_size ); _vmeml2_static_address( (Uint32) _vga_get_start_mem(), (Uint32) _vga_get_end_mem(), TRUE ); _vmeml2_static_address( ( (Uint32) wm_memory ), (Uint32) ( (Uint32) wm_memory ) + s_arr_size + buff_size + WIN_MAN_MEM , TRUE ); _gl_init(); // c_printf("\n%x %x\n", (Uint32) _vga_get_start_mem(), (Uint32) _vga_get_end_mem() ); // c_printf("\n%x %x\n", ( (Uint32) wm_memory ), (Uint32) ( (Uint32) wm_memory ) + buff_size + s_arr_size + WIN_MAN_MEM); // c_printf("\nscrn: %x bOff: %x \n", screen_info_arr, bPtrOffset); //fill out the default screens [[ * vga_mode_info->LinbytesPerScanLine)/8) ]] for(i = 0; i < DEFAULT_SCREENS; i++) { screen_info_arr[i].buf_num = i; screen_info_arr[i].w = dW; screen_info_arr[i].h = dH; screen_info_arr[i].bPtr = (Uint32 *)(((Uint32)bPtrOffset) + (( i * dH * dW * 4 ))); screen_info_arr[i].pid = 0; screen_info_arr[i].active = 0; screen_info_arr[i].blocking = 0; screen_info_arr[i].dirty = 1; //default dirty //gl_print stuff screen_info_arr[i].x_max = dW / FONT_WIDTH; screen_info_arr[i].y_max = (dH / FONT_HEIGHT)-1; screen_info_arr[i].curr_x = 0; screen_info_arr[i].curr_y = 0; screen_info_arr[i].buf_x = 0; for(y = 0; y < 200; y++){ for(x = 0; x < 200; x++) screen_info_arr[i].lines[y][x] = '\0'; } #ifdef WM_DEBUG c_printf("%d - %x || ", i, screen_info_arr[i].bPtr); #endif } //c_printf("%x %x %x %x size_struct:%x \n", screen_info_arr[0].bPtr, buff_size, s_arr_size, WIN_MAN_MEM, sizeof( struct screen_info )); //clear buffer mem _kmemclr(screen_info_arr[0].bPtr, buff_size ); #ifdef WM_DEBUG c_printf("\n-Total Memory(B): %d blocks(x64KB), %d\n", vga_vesa_info->TotalMemory, (vga_vesa_info->TotalMemory * 64)*1024); for(i = 0; i < DEFAULT_SCREENS; i++) { c_printf("%d - (%d, %d) - %x || ", screen_info_arr[i].buf_num, screen_info_arr[i].w, screen_info_arr[i].h, screen_info_arr[i].bPtr); } #endif //set the default displayed screens wm_memory->screens[0] = 0; wm_memory->screens[1] = 1; wm_memory->screens[2] = 2; wm_memory->screens[3] = 3; //test for(i = 0; i < screen_info_arr[0].w; i++) { for(j = 0; j < screen_info_arr[0].h; j++) { screen_info_arr[0].bPtr[ ( j * screen_info_arr[0].w ) + i] = 0x18181818; } } for(i = 0; i < screen_info_arr[2].w; i++) { for(j = 0; j < screen_info_arr[2].h; j++) { screen_info_arr[2].bPtr[ ( j * screen_info_arr[2].w ) + i] = 0xffffffff; } } wm_memory->active_quad = 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; }
context_t *_create_stack( stack_t *stack ) { uint32_t *ptr; context_t *context; // sanity check! if( stack == NULL ) { return( NULL ); } // start by clearing the stack _kmemclr( (void *) stack, sizeof(stack_t) ); /* ** Set up the initial stack contents for a (new) user process. ** ** We reserve one longword at the bottom of the stack as ** scratch space. Above that, we simulate a call to exit() by ** pushing the special exit status EXIT_DEFAULT and the address ** of exit() as a "return address". Finally, we simulate a call ** from the entry point of exit() to main(). Above that, we ** place an context_t area that is initialized with the ** standard initial register contents. ** ** The low end of the stack will contain these values: ** ** esp -> ? <- context save area ** ... <- context save area ** ? <- context save area ** exit <- return address for faked call to main() ** 0 <- return address for faked call to exit() ** code <- special exit status ** 0 <- last word in stack ** ** When this process is dispatched, the context restore code ** will pop all the saved context information off the stack, ** leaving the "return address" on the stack as if the main() ** for the process had been "called" from the exit() stub. ** When main() returns, it will "return" to the entry point of ** exit(), which will clean it up. */ // first, find the address following the stack ptr = ((uint32_t *) (stack + 1)) - 2; // assign the filler data *--ptr = 0; // assign the default exit status *--ptr = EXIT_DEFAULT; // assign the return address for the faked call to exit() *--ptr = 0; // assign the return address for the faked call to main() *--ptr = (uint32_t) exit; // next, set up the process context context = ((context_t *) ptr) - 1; // initialize all the fields that should be non-zero, starting // with the segment registers context->cs = GDT_CODE; context->ss = GDT_STACK; context->ds = GDT_DATA; context->es = GDT_DATA; context->fs = GDT_DATA; context->gs = GDT_DATA; // EFLAGS must be set up to re-enable IF when we switch // "back" to this context context->eflags = DEFAULT_EFLAGS; /* ** Note that we do *not* assign EIP here; we leave that ** to the calling routine */ // all done - return the context pointer return( context ); }