Next: Other Multiboot2 kernels, Previous: boot.S, Up: Example OS code [Contents][Index]
And, in the file kernel.c:
/* kernel.c - the C part of the kernel */ /* Copyright (C) 1999, 2010 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 3 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, see <http://www.gnu.org/licenses/>. */ #include "multiboot2.h" /* Macros. */ /* Some screen stuff. */ /* The number of columns. */ #define COLUMNS 80 /* The number of lines. */ #define LINES 24 /* The attribute of an character. */ #define ATTRIBUTE 7 /* The video memory address. */ #define VIDEO 0xB8000 /* Variables. */ /* Save the X position. */ static int xpos; /* Save the Y position. */ static int ypos; /* Point to the video memory. */ static volatile unsigned char *video; /* 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, ...); /* Check if MAGIC is valid and print the Multiboot information structure pointed by ADDR. */ void cmain (unsigned long magic, unsigned long addr) { struct multiboot_tag *tag; unsigned size; /* Clear the screen. */ cls (); /* Am I booted by a Multiboot-compliant boot loader? */ if (magic != MULTIBOOT2_BOOTLOADER_MAGIC) { printf ("Invalid magic number: 0x%x\n", (unsigned) magic); return; } if (addr & 7) { printf ("Unaligned mbi: 0x%x\n", addr); return; } size = *(unsigned *) addr; printf ("Announced mbi size 0x%x\n", size); for (tag = (struct multiboot_tag *) (addr + 8); tag->type != MULTIBOOT_TAG_TYPE_END; tag = (struct multiboot_tag *) ((multiboot_uint8_t *) tag + ((tag->size + 7) & ~7))) { printf ("Tag 0x%x, Size 0x%x\n", tag->type, tag->size); switch (tag->type) { case MULTIBOOT_TAG_TYPE_CMDLINE: printf ("Command line = %s\n", ((struct multiboot_tag_string *) tag)->string); break; case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME: printf ("Boot loader name = %s\n", ((struct multiboot_tag_string *) tag)->string); break; case MULTIBOOT_TAG_TYPE_MODULE: printf ("Module at 0x%x-0x%x. Command line %s\n", ((struct multiboot_tag_module *) tag)->mod_start, ((struct multiboot_tag_module *) tag)->mod_end, ((struct multiboot_tag_module *) tag)->cmdline); break; case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO: printf ("mem_lower = %uKB, mem_upper = %uKB\n", ((struct multiboot_tag_basic_meminfo *) tag)->mem_lower, ((struct multiboot_tag_basic_meminfo *) tag)->mem_upper); break; case MULTIBOOT_TAG_TYPE_BOOTDEV: printf ("Boot device 0x%x,%u,%u\n", ((struct multiboot_tag_bootdev *) tag)->biosdev, ((struct multiboot_tag_bootdev *) tag)->slice, ((struct multiboot_tag_bootdev *) tag)->part); break; case MULTIBOOT_TAG_TYPE_MMAP: { multiboot_memory_map_t *mmap; printf ("mmap\n"); for (mmap = ((struct multiboot_tag_mmap *) tag)->entries; (multiboot_uint8_t *) mmap < (multiboot_uint8_t *) tag + tag->size; mmap = (multiboot_memory_map_t *) ((unsigned long) mmap + ((struct multiboot_tag_mmap *) tag)->entry_size)) printf (" base_addr = 0x%x%x," " length = 0x%x%x, type = 0x%x\n", (unsigned) (mmap->addr >> 32), (unsigned) (mmap->addr & 0xffffffff), (unsigned) (mmap->len >> 32), (unsigned) (mmap->len & 0xffffffff), (unsigned) mmap->type); } break; case MULTIBOOT_TAG_TYPE_FRAMEBUFFER: { multiboot_uint32_t color; unsigned i; struct multiboot_tag_framebuffer *tagfb = (struct multiboot_tag_framebuffer *) tag; void *fb = (void *) (unsigned long) tagfb->common.framebuffer_addr; switch (tagfb->common.framebuffer_type) { case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED: { unsigned best_distance, distance; struct multiboot_color *palette; palette = tagfb->framebuffer_palette; color = 0; best_distance = 4*256*256; for (i = 0; i < tagfb->framebuffer_palette_num_colors; i++) { distance = (0xff - palette[i].blue) * (0xff - palette[i].blue) + palette[i].red * palette[i].red + palette[i].green * palette[i].green; if (distance < best_distance) { color = i; best_distance = distance; } } } break; case MULTIBOOT_FRAMEBUFFER_TYPE_RGB: color = ((1 << tagfb->framebuffer_blue_mask_size) - 1) << tagfb->framebuffer_blue_field_position; break; case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT: color = '\\' | 0x0100; break; default: color = 0xffffffff; break; } for (i = 0; i < tagfb->common.framebuffer_width && i < tagfb->common.framebuffer_height; i++) { switch (tagfb->common.framebuffer_bpp) { case 8: { multiboot_uint8_t *pixel = fb + tagfb->common.framebuffer_pitch * i + i; *pixel = color; } break; case 15: case 16: { multiboot_uint16_t *pixel = fb + tagfb->common.framebuffer_pitch * i + 2 * i; *pixel = color; } break; case 24: { multiboot_uint32_t *pixel = fb + tagfb->common.framebuffer_pitch * i + 3 * i; *pixel = (color & 0xffffff) | (*pixel & 0xff000000); } break; case 32: { multiboot_uint32_t *pixel = fb + tagfb->common.framebuffer_pitch * i + 4 * i; *pixel = color; } break; } } break; } } } tag = (struct multiboot_tag *) ((multiboot_uint8_t *) tag + ((tag->size + 7) & ~7)); printf ("Total mbi size 0x%x\n", (unsigned) tag - addr); } /* 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; } /* 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; /* 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; /* Divide UD by DIVISOR until UD == 0. */ do { int remainder = ud % divisor; *p++ = (remainder < 10) ? remainder + '0' : remainder + 'a' - 10; } while (ud /= divisor); /* Terminate BUF. */ *p = 0; /* Reverse BUF. */ p1 = buf; p2 = p - 1; while (p1 < p2) { char tmp = *p1; *p1 = *p2; *p2 = tmp; p1++; p2--; } } /* 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; } /* 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, *p2; int pad0 = 0, pad = 0; c = *format++; if (c == '0') { pad0 = 1; c = *format++; } if (c >= '0' && c <= '9') { pad = c - '0'; 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: for (p2 = p; *p2; p2++); for (; p2 < p + pad; p2++) putchar (pad0 ? '0' : ' '); while (*p) putchar (*p++); break; default: putchar (*((int *) arg++)); break; } } } }
Next: Other Multiboot2 kernels, Previous: boot.S, Up: Example OS code [Contents][Index]