Archive / / / / boot.c
2004-07-29 07:12:51 UTC
previous next
// $Id: boot.c 17 2003-07-23 03:13:46Z kr4z $ // $HeadURL: http://kryptos.kr4z.com/svn/trunk/kernel/boot/boot.c $ #include "boot.h" #include "malloc.h" void* video_mem; // Here is where the real programming starts; // we currently have a 100 dword long stack to use // and so we must quickly parse the multiboot structure, // change to virtual memory mode and jump to main() // using a 'real' stack void start(unsigned long magic, multiboot_info_t* mb_info) { // TODO: Make sure we are on video page 0 (0xb8000) boot_printf(VIDEO_WHITE, "Starting kryptOS...\n\n"); boot_printf(VIDEO_GREY, "Reading boot loader information...\n"); if (magic != 0x2BADB002) { boot_printf(VIDEO_RED, "\nError: "); boot_printf(VIDEO_GREY, "Please use a multiboot compatiable boot loader to use kryptOS"); hang(); } initmem_info_t* initmem_info = boot_malloc(sizeof(initmem_info_t)); boot_printf(VIDEO_GREY, "* Boot loader: "); if (mb_info->flags & (1<<9)) { // If the boot loader name was passed initmem_info->got_boot_loader_name = 1; initmem_info->boot_loader_name = boot_mallocstring(mb_info->boot_loader_name, 255); boot_printf(VIDEO_GREY, "%s\n", initmem_info->boot_loader_name); } else { // If no boot loader name initmem_info->got_boot_loader_name = 0; boot_printf(VIDEO_GREY, "(unknown)\n"); } boot_printf(VIDEO_GREY, "* Kernel command line: "); if (mb_info->flags & (1<<2)) { // If a command line was passed initmem_info->got_command_line = 1; initmem_info->command_line = boot_mallocstring(mb_info->cmdline, 255); boot_printf(VIDEO_GREY, "%s\n", initmem_info->command_line); } else { // If no command line initmem_info->got_command_line = 0; boot_printf(VIDEO_GREY, "(none passed)\n"); } boot_make_mmap(mb_info, initmem_info); mmap_section_t* this_mmap_section = initmem_info->mmap_addr; boot_printf(VIDEO_GREY, "* Boot modules:"); for(;;) { if (this_mmap_section->status == MMAP_MOD) { boot_printf(VIDEO_GREY, " %s", this_mmap_section->mod_name); } if (this_mmap_section->next != (void*)0) { this_mmap_section = this_mmap_section->next; } else { break; } } boot_printf(VIDEO_GREY, "\n\n"); // TODO: Make the physical memory layout only display when "verbose" is specified // on the kernel command line boot_printf(VIDEO_GREY, "Physical memory layout:\n"); this_mmap_section = initmem_info->mmap_addr; for(;;) { boot_printf(VIDEO_GREY, " %016llx - %016llx ", this_mmap_section->base_addr, this_mmap_section->base_addr+this_mmap_section->length); if (this_mmap_section->status == MMAP_RESERVED) { boot_printf(VIDEO_GREY, "(reserved)\n"); } else if (this_mmap_section->status == MMAP_FREE) { boot_printf(VIDEO_GREY, "(free)\n"); } else if (this_mmap_section->status == MMAP_MOD) { boot_printf(VIDEO_GREY, "(module: %s)\n", this_mmap_section->mod_name); } if (this_mmap_section->next) { this_mmap_section = this_mmap_section->next; } else { break; } } } void boot_make_mmap(multiboot_info_t* mb_info, initmem_info_t* initmem_info) { mb_mmap_section_t* this_mb_mmap_section; mb_mod_section_t* this_mb_mods_section; mmap_section_t* this_mmap_section = boot_malloc(sizeof(mmap_section_t)); this_mmap_section->prev = (void*)0; initmem_info->mmap_addr = this_mmap_section; for(;;) { this_mmap_section->base_addr = 0xFFFFFFFFFFFFFFFF; // To make sure that searches will definitely find one this_mmap_section->length = 0; // lower in memory then this one this_mmap_section->status = MMAP_RESERVED; // TODO: Check multiboot mmap_ bit before using it, and if not available, use mem_ sections // Search multiboot mmap_ sections for next memory map section this_mb_mmap_section = mb_info->mmap_addr; while(((unsigned long)this_mb_mmap_section + this_mb_mmap_section->size + sizeof(this_mb_mmap_section->size)) <= ((unsigned long)mb_info->mmap_addr + mb_info->mmap_length)) { if (this_mb_mmap_section->base_addr < this_mmap_section->base_addr && (this_mmap_section->prev == (void*)0 ? 1 : this_mb_mmap_section->base_addr > this_mmap_section->prev->base_addr) && this_mb_mmap_section->length != 0) { this_mmap_section->base_addr = this_mb_mmap_section->base_addr; this_mmap_section->length = this_mb_mmap_section->length; if (this_mb_mmap_section->type == 1) this_mmap_section->status = MMAP_FREE; else this_mmap_section->status = MMAP_RESERVED; } this_mb_mmap_section = (mb_mmap_section_t*)((unsigned long)this_mb_mmap_section + this_mb_mmap_section->size + sizeof(this_mb_mmap_section->size)); } // Search multiboot mods_ sections for next memory map section this_mb_mods_section = mb_info->mods_addr; while ((this_mb_mods_section-mb_info->mods_addr)/sizeof(mb_mod_section_t) < mb_info->mods_count) { if (this_mb_mods_section->mod_start < this_mmap_section->base_addr && (this_mmap_section->prev == (void*)0 ? 1 : this_mb_mods_section->mod_start > this_mmap_section->prev->base_addr) && this_mb_mods_section->mod_end != this_mb_mods_section->mod_start) { this_mmap_section->base_addr = this_mb_mods_section->mod_start; this_mmap_section->length = this_mb_mods_section->mod_end - this_mb_mods_section->mod_start; this_mmap_section->status = MMAP_MOD; char* mod_command_line = this_mb_mods_section->string; for (;*(++mod_command_line) != ' ';); *mod_command_line = 0; // Seperate mod_name from mod_command_line char* mod_name = mod_command_line; mod_command_line++; for (;*(--mod_name) != '/' && mod_name >= this_mb_mods_section->string;); mod_name++; this_mmap_section->mod_name = boot_mallocstring(mod_name, 255); this_mmap_section->mod_command_line = boot_mallocstring(mod_command_line, 255); } this_mb_mods_section++; } // Check to see if this new section overlaps with the last one if (this_mmap_section->prev != (void*)0 && (this_mmap_section->prev->base_addr+this_mmap_section->prev->length) > this_mmap_section->base_addr) { if (this_mmap_section->prev->status != MMAP_FREE) { boot_printf(VIDEO_RED, "\nError: "); boot_printf(VIDEO_GREY, "The physical memory map is invalid; check your boot loader"); hang(); } if ((this_mmap_section->prev->base_addr+this_mmap_section->prev->length) > (this_mmap_section->base_addr+this_mmap_section->length)) { this_mmap_section->next = boot_malloc(sizeof(mmap_section_t)); this_mmap_section->next->base_addr = this_mmap_section->base_addr + this_mmap_section->length; this_mmap_section->next->length = this_mmap_section->prev->length - (this_mmap_section->base_addr - this_mmap_section->prev->base_addr) - this_mmap_section->length; this_mmap_section->next->status = MMAP_FREE; this_mmap_section->next->prev = this_mmap_section; this_mmap_section->prev->length = this_mmap_section->base_addr - this_mmap_section->prev->base_addr; this_mmap_section = this_mmap_section->next; } else { this_mmap_section->prev->length = this_mmap_section->base_addr - this_mmap_section->prev->base_addr; } } if (this_mmap_section->base_addr == 0xFFFFFFFFFFFFFFFF) { if (this_mmap_section->prev == (void*)0) { boot_printf(VIDEO_RED, "\nError: "); boot_printf(VIDEO_GREY, "The physical memory map is invalid; check your boot loader"); hang(); } this_mmap_section->prev->next = (void*)0; boot_free(this_mmap_section); break; } this_mmap_section->next = boot_malloc(sizeof(mmap_section_t)); this_mmap_section->next->prev = this_mmap_section; this_mmap_section = this_mmap_section->next; } } char* boot_mallocstring(char* string, unsigned int maxlen) { char* ret; int stringlen = boot_strlen(string); if (stringlen > maxlen) stringlen = maxlen; ret = boot_malloc(stringlen+1); boot_strncpy(ret, string, stringlen); if (stringlen == maxlen) *(ret+255) = 0; return ret; } void boot_strncpy(char *str1, const char *str2, unsigned int count) { int chars_copied = 0; for (;chars_copied < count;chars_copied++) { if (*str2) { *(str1++) = *(str2++); } else { *(str1++) = 0; } } } int boot_strlen(char* str) { int len = 0; for (;*(str++);len++); return len; } void *boot_malloc(unsigned long size) { static malloc_chunk_t *nextchunk = (malloc_chunk_t*)initmem; malloc_chunk_t *thischunk = nextchunk; if (size < 8) size = 8; // Leave room for free chunk pointers thischunk->size = (size + 8 + 3) & ~3; nextchunk = (malloc_chunk_t*)((char*)nextchunk + thischunk->size); nextchunk->prev_size = thischunk->size; return (void*)((char*)thischunk + 8); // TODO: Check if we've run out of memory } void boot_free(void* address) { // TODO: Free memory } void boot_printf(unsigned char color, char* format_string, ...) { void* arg; char* arg_string; arg = (void*)&format_string + 4; // Pointer to argument after format_string outportb(0x3d4, 0x0E); // Get first byte of screen cursor offset video_mem = (void*)((long)inportb(0x3d5)); video_mem = (void*)((long)video_mem << 8); outportb(0x3d4, 0x0F); // Get second byte video_mem += inportb(0x3d5); video_mem = (void*)((long)video_mem << 1); // Multiply by two (since each character in video memory video_mem += 0xb8000; // takes 2 byes) and add 0xb8000 to get the memory address do { if (*format_string != '%') { boot_printf_char(color, *format_string); continue; } format_string++; // Advance to character after the % char pad_char = ' '; if (*format_string == '0') { pad_char = '0'; format_string++; } unsigned long min_field_width = 0; for(;;) { if (*format_string >= '0' && *format_string <= '9') { min_field_width *= 10; min_field_width += *format_string - '0'; format_string++; } else { break; } } switch (*format_string) { case 'c': boot_printf_char(color, *(char*)arg); arg += 4; continue; case 'u': case 'x': case 'X': boot_printf_number(*format_string, pad_char, min_field_width, color, *(unsigned long*)arg); arg += 4; continue; case 'l': if (*(format_string+1) == 'l') { format_string += 2; if (*format_string == 'X' || *format_string == 'x' || *format_string == 'u') { if (*(unsigned long*)(arg+4)) { boot_printf_number(*format_string, pad_char, min_field_width - (*format_string == 'u' ? 10 : 8), color, *(unsigned long*)(arg+4)); boot_printf_number(*format_string, '0', (*format_string == 'u' ? 10 : 8), color, *(unsigned long*)arg); } else { boot_printf_number(*format_string, pad_char, min_field_width, color, *(unsigned long*)arg); } arg += 8; } } continue; case 's': arg_string = *(char**)arg; // arg is a pointer to a pointer to a string boot_printf_char(color, *arg_string); while (*(++arg_string)) boot_printf_char(color, *arg_string); arg += 4; continue; case '%': boot_printf_char(color, '%'); continue; } } while(*(++format_string)); if ((long)video_mem > 0xB8FA0) scroll_screen(); video_mem -= 0xb8000; video_mem = (void*)((long)video_mem >> 1); outportb(0x3d4, 0x0E); outportb(0x3d5, (long)video_mem >> 8); outportb(0x3d4, 0x0F); outportb(0x3d5, (long)video_mem & 0xFF); } void scroll_screen(void) { int lines_over = (((long)video_mem - 0xB8FA0) / 160) + 1; char* src = (char*)(0xb8000 + (lines_over*160)); char* dest = (char*)0xb8000; for(;(long)src < (long)video_mem; *dest = *src, dest++, src++); video_mem = dest; for(;(long)dest < 0xB8FA0; *dest = 0, dest++); } void boot_printf_char(unsigned char color, char character) { if (character != '\n') { *(char*)video_mem = character; video_mem++; *(char*)video_mem = color; video_mem++; return; } /* video_mem = (void*)((((long)video_mem - 0xb8000) / 160) + 1); video_mem = (void*)(((long)video_mem * 160) + 0xb8000); */ // This part would probablly be optimized out of existance.. so I put it into asm int dummy_int; asm("subl $0xb8000, %0\n\t" "movl $0, %%edx\n\t" "movl $160, %1\n\t" "divl %1\n\t" "incl %0\n\t" "mull %1\n\t" "addl $0xb8000, %0" : "=a" (video_mem), "=rm" (dummy_int) : "0" (video_mem) : "edx"); } void boot_printf_number(char numbertype, char pad_char, unsigned long min_field_width, unsigned char color, unsigned long number) { char digit_string[11]; char* current_digit = digit_string; char base; if (numbertype == 'u') { base = 10; } else { base = 16; } if (number == 0) { if (min_field_width > 1) { for (int i = 0; i < (min_field_width-1); i++, boot_printf_char(color, pad_char)); } boot_printf_char(color, '0'); return; } while (number > 0) { *current_digit = (number % base) + '0'; if (*current_digit > '9') { if (numbertype == 'X') { *current_digit += 'A' - ('9'+1); } else { *current_digit += 'a' - ('9'+1); } } current_digit++; number /= base; } // Print any leading zeros or spaces as required by pad_char and min_field_width if (min_field_width > (current_digit - digit_string)) { unsigned int pad_size = min_field_width - (current_digit - digit_string); for (int i = 0; i < pad_size; i++, boot_printf_char(color, pad_char)); } // Print digit_string in reverse order starting with current_digit for (;(--current_digit) >= digit_string; boot_printf_char(color, *current_digit)); } inline unsigned char inportb(unsigned int port) { unsigned char ret; asm volatile ("inb %%dx,%%al":"=a" (ret):"d" (port)); return ret; } inline void outportb(unsigned int port, unsigned char value) { asm volatile ("outb %%al,%%dx": :"d" (port), "a" (value)); }