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));
}