| /* @r{kernel.c - the C part of the kernel} */ |
| /* @r{Copyright (C) 1999 Free Software Foundation, Inc. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.} */ |
| |
| #include <multiboot.h> |
| |
| /* @r{Macros.} */ |
| |
| /* @r{Check if the bit BIT in FLAGS is set.} */ |
| #define CHECK_FLAG(flags,bit) ((flags) & (1 << (bit))) |
| |
| /* @r{Some screen stuff.} */ |
| /* @r{The number of columns.} */ |
| #define COLUMNS 80 |
| /* @r{The number of lines.} */ |
| #define LINES 24 |
| /* @r{The attribute of an character.} */ |
| #define ATTRIBUTE 7 |
| /* @r{The video memory address.} */ |
| #define VIDEO 0xB8000 |
| |
| /* @r{Variables.} */ |
| /* @r{Save the X position.} */ |
| static int xpos; |
| /* @r{Save the Y position.} */ |
| static int ypos; |
| /* @r{Point to the video memory.} */ |
| static volatile unsigned char *video; |
| |
| /* @r{Forward declarations.} */ |
| void cmain (unsigned long magic, unsigned long addr); |
| static void cls (void); |
| static void itoa (char *buf, int base, int d); |
| static void putchar (int c); |
| void printf (const char *format, ...); |
| |
| /* @r{Check if MAGIC is valid and print the Multiboot information structure |
| pointed by ADDR.} */ |
| void |
| cmain (unsigned long magic, unsigned long addr) |
| @{ |
| multiboot_info_t *mbi; |
| |
| /* @r{Clear the screen.} */ |
| cls (); |
| |
| /* @r{Am I booted by a Multiboot-compliant boot loader?} */ |
| if (magic != MULTIBOOT_BOOTLOADER_MAGIC) |
| @{ |
| printf ("Invalid magic number: 0x%x\n", (unsigned) magic); |
| return; |
| @} |
| |
| /* @r{Set MBI to the address of the Multiboot information structure.} */ |
| mbi = (multiboot_info_t *) addr; |
| |
| /* @r{Print out the flags.} */ |
| printf ("flags = 0x%x\n", (unsigned) mbi->flags); |
| |
| /* @r{Are mem_* valid?} */ |
| if (CHECK_FLAG (mbi->flags, 0)) |
| printf ("mem_lower = %uKB, mem_upper = %uKB\n", |
| (unsigned) mbi->mem_lower, (unsigned) mbi->mem_upper); |
| |
| /* @r{Is boot_device valid?} */ |
| if (CHECK_FLAG (mbi->flags, 1)) |
| printf ("boot_device = 0x%x\n", (unsigned) mbi->boot_device); |
| |
| /* @r{Is the command line passed?} */ |
| if (CHECK_FLAG (mbi->flags, 2)) |
| printf ("cmdline = %s\n", (char *) mbi->cmdline); |
| |
| /* @r{Are mods_* valid?} */ |
| if (CHECK_FLAG (mbi->flags, 3)) |
| @{ |
| module_t *mod; |
| int i; |
| |
| printf ("mods_count = %d, mods_addr = 0x%x\n", |
| (int) mbi->mods_count, (int) mbi->mods_addr); |
| for (i = 0, mod = (module_t *) mbi->mods_addr; |
| i < mbi->mods_count; |
| i++, mod++) |
| printf (" mod_start = 0x%x, mod_end = 0x%x, string = %s\n", |
| (unsigned) mod->mod_start, |
| (unsigned) mod->mod_end, |
| (char *) mod->string); |
| @} |
| |
| /* @r{Bits 4 and 5 are mutually exclusive!} */ |
| if (CHECK_FLAG (mbi->flags, 4) && CHECK_FLAG (mbi->flags, 5)) |
| @{ |
| printf ("Both bits 4 and 5 are set.\n"); |
| return; |
| @} |
| |
| /* @r{Is the symbol table of a.out valid?} */ |
| if (CHECK_FLAG (mbi->flags, 4)) |
| @{ |
| aout_symbol_table_t *aout_sym = &(mbi->u.aout_sym); |
| |
| printf ("aout_symbol_table: tabsize = 0x%0x, " |
| "strsize = 0x%x, addr = 0x%x\n", |
| (unsigned) aout_sym->tabsize, |
| (unsigned) aout_sym->strsize, |
| (unsigned) aout_sym->addr); |
| @} |
| |
| /* @r{Is the section header table of ELF valid?} */ |
| if (CHECK_FLAG (mbi->flags, 5)) |
| @{ |
| elf_section_header_table_t *elf_sec = &(mbi->u.elf_sec); |
| |
| printf ("elf_sec: num = %u, size = 0x%x," |
| " addr = 0x%x, shndx = 0x%x\n", |
| (unsigned) elf_sec->num, (unsigned) elf_sec->size, |
| (unsigned) elf_sec->addr, (unsigned) elf_sec->shndx); |
| @} |
| |
| /* @r{Are mmap_* valid?} */ |
| if (CHECK_FLAG (mbi->flags, 6)) |
| @{ |
| memory_map_t *mmap; |
| |
| printf ("mmap_addr = 0x%x, mmap_length = 0x%x\n", |
| (unsigned) mbi->mmap_addr, (unsigned) mbi->mmap_length); |
| for (mmap = (memory_map_t *) mbi->mmap_addr; |
| (unsigned long) mmap < mbi->mmap_addr + mbi->mmap_length; |
| mmap = (memory_map_t *) ((unsigned long) mmap |
| + mmap->size + sizeof (mmap->size))) |
| printf (" size = 0x%x, base_addr = 0x%x%x," |
| " length = 0x%x%x, type = 0x%x\n", |
| (unsigned) mmap->size, |
| (unsigned) mmap->base_addr_high, |
| (unsigned) mmap->base_addr_low, |
| (unsigned) mmap->length_high, |
| (unsigned) mmap->length_low, |
| (unsigned) mmap->type); |
| @} |
| @} |
| |
| /* @r{Clear the screen and initialize VIDEO, XPOS and YPOS.} */ |
| static void |
| cls (void) |
| @{ |
| int i; |
| |
| video = (unsigned char *) VIDEO; |
| |
| for (i = 0; i < COLUMNS * LINES * 2; i++) |
| *(video + i) = 0; |
| |
| xpos = 0; |
| ypos = 0; |
| @} |
| |
| /* @r{Convert the integer D to a string and save the string in BUF. If |
| BASE is equal to 'd', interpret that D is decimal, and if BASE is |
| equal to 'x', interpret that D is hexadecimal.} */ |
| static void |
| itoa (char *buf, int base, int d) |
| @{ |
| char *p = buf; |
| char *p1, *p2; |
| unsigned long ud = d; |
| int divisor = 10; |
| |
| /* @r{If %d is specified and D is minus, put `-' in the head.} */ |
| if (base == 'd' && d < 0) |
| @{ |
| *p++ = '-'; |
| buf++; |
| ud = -d; |
| @} |
| else if (base == 'x') |
| divisor = 16; |
| |
| /* @r{Divide UD by DIVISOR until UD == 0.} */ |
| do |
| @{ |
| int remainder = ud % divisor; |
| |
| *p++ = (remainder < 10) ? remainder + '0' : remainder + 'a' - 10; |
| @} |
| while (ud /= divisor); |
| |
| /* @r{Terminate BUF.} */ |
| *p = 0; |
| |
| /* @r{Reverse BUF.} */ |
| p1 = buf; |
| p2 = p - 1; |
| while (p1 < p2) |
| @{ |
| char tmp = *p1; |
| *p1 = *p2; |
| *p2 = tmp; |
| p1++; |
| p2--; |
| @} |
| @} |
| |
| /* @r{Put the character C on the screen.} */ |
| static void |
| putchar (int c) |
| @{ |
| if (c == '\n' || c == '\r') |
| @{ |
| newline: |
| xpos = 0; |
| ypos++; |
| if (ypos >= LINES) |
| ypos = 0; |
| return; |
| @} |
| |
| *(video + (xpos + ypos * COLUMNS) * 2) = c & 0xFF; |
| *(video + (xpos + ypos * COLUMNS) * 2 + 1) = ATTRIBUTE; |
| |
| xpos++; |
| if (xpos >= COLUMNS) |
| goto newline; |
| @} |
| |
| /* @r{Format a string and print it on the screen, just like the libc |
| function printf.} */ |
| void |
| printf (const char *format, ...) |
| @{ |
| char **arg = (char **) &format; |
| int c; |
| char buf[20]; |
| |
| arg++; |
| |
| while ((c = *format++) != 0) |
| @{ |
| if (c != '%') |
| putchar (c); |
| else |
| @{ |
| char *p; |
| |
| c = *format++; |
| switch (c) |
| @{ |
| case 'd': |
| case 'u': |
| case 'x': |
| itoa (buf, c, *((int *) arg++)); |
| p = buf; |
| goto string; |
| break; |
| |
| case 's': |
| p = *arg++; |
| if (! p) |
| p = "(null)"; |
| |
| string: |
| while (*p) |
| putchar (*p++); |
| break; |
| |
| default: |
| putchar (*((int *) arg++)); |
| break; |
| @} |
| @} |
| @} |
| @} |