From: Joshua Wise Date: Wed, 10 Sep 2008 19:17:51 +0000 (-0400) Subject: Add a little bit more functionality to grubload X-Git-Url: http://git.joshuawise.com/netwatch.git/commitdiff_plain/9b8c947be2d07e7c5006a92127e58b6022718cbd?ds=inline;hp=56553b7318d2a1466ad07c1955d30a5744b16f12 Add a little bit more functionality to grubload --- diff --git a/aseg/aseg.asm b/aseg/aseg.asm index c086b83..a6f71c2 100644 --- a/aseg/aseg.asm +++ b/aseg/aseg.asm @@ -40,7 +40,7 @@ noclear: align 0x4 gdtr: - db 0x1F, 0x00 + db 0x17, 0x00 dd gdt align 0x4 gdt: diff --git a/aseg/counter.c b/aseg/counter.c index 61f9b6f..8f807aa 100644 --- a/aseg/counter.c +++ b/aseg/counter.c @@ -25,7 +25,7 @@ unsigned char vgaread(unsigned char idx) void strblit(char *src) { - char *destp = (char*)(0xB8000 | (vgaread(0xC) << 5) | (vgaread(0xD) << 1)); + char *destp = (char*)(0xB8000UL | (((unsigned int)vgaread(0xC)) << 9) | (((unsigned int)vgaread(0xD)) << 1)); while (*src) { *(destp++) = *(src++); diff --git a/grubload/Makefile b/grubload/Makefile new file mode 100644 index 0000000..971fb5c --- /dev/null +++ b/grubload/Makefile @@ -0,0 +1,8 @@ +OBJS=multiboot_c.o multiboot_asm.o console.o minilib.o +CC=gcc +CFLAGS=-nostdlib -I../include -I. -fno-builtin -nostdinc + +all: multiboot + +multiboot: $(OBJS) + ld -o multiboot $(OBJS) -Ttext=0x100000 diff --git a/grubload/console-ext.h b/grubload/console-ext.h new file mode 100644 index 0000000..849fd16 --- /dev/null +++ b/grubload/console-ext.h @@ -0,0 +1,15 @@ +/** @file console-ext.h + * + * @brief Forward declarations for extended console functions + * + * @author Joshua Wise (jwise) + * @buf None known + */ + +#ifndef __CONSOLE_EXT_H +#define __CONSOLE_EXT_H + +void cons_backbuffer(); +void cons_debackbuffer(); + +#endif diff --git a/grubload/console.c b/grubload/console.c new file mode 100644 index 0000000..27880ba --- /dev/null +++ b/grubload/console.c @@ -0,0 +1,274 @@ +/** @file console.c + * @brief A console driver. + * + * @author Joshua Wise (jwise) + * @bug None known + */ + +#include +#include "console-ext.h" +#include + +#define POS_IS_VALID(row, col) ((row) >= 0 && (row) < CONSOLE_HEIGHT && (col) >= 0 && (col) < CONSOLE_WIDTH) + +/** @brief A structure describing a console that is backed by memory. + * + * In the mode of designing for extensibility, all of the console driver's + * state is encapsulated in a 'struct console', which would ostensibly make + * it easier to create virtual consoles later. All of the console driver's + * workings touch this struct; ideally, there are no references to + * CONSOLE_MEM_BASE or other hardware outside of this. In practice, this + * isn't quite the case (see update_cursor()).... but we're close. + */ +struct console { + int row; /**< The current row. */ + int col; /**< The current column. */ + unsigned char attr; /**< The current color/attribute. */ + unsigned char *base; /**< The current base to write data to. + * Might not be equal to physbase if we're + * in a different virtual console right + * now or we have requested a backbuffer! + */ + unsigned char *physbase; /**< The physical memory base for + * this console. + */ + int showcursor; /**< Whether the cursor should be shown + * by update_cursor(). + */ + int initialized; /**< Whether the console has been + * initialized. Functions should check + * this and call clear_console() before + * running if this is zero. + */ + int backbuffer; /**< Whether we're currently writing to a + * backbuffer instead of the physical + * video memory. + */ +}; + +/** @brief The structure describing the one console on the system. Should + * not be touched by anyone but the initializer for curcons! + */ +static struct console cons = { + .row = 0, + .col = 0, + .attr = FGND_LGRAY, + .base = (unsigned char *)CONSOLE_MEM_BASE, + .physbase = (unsigned char *)CONSOLE_MEM_BASE, + .showcursor = 1, + .initialized = 0, + .backbuffer = 0, +}; + +/** @brief The current console that all console.c operations work on. */ +static struct console *curcons = &cons; + +/** @brief Makes sure that the VGA cursor matches with the console.c's idea + * of where the cursor should be. + * + * update_cursor would be trivial, but for a few important checks. In + * particular, it won't touch the cursor at all if we're backbuffered + * (since that would make the cursor fly around a screen that isn't + * actually being updated), and if the cursor is hidden, it sets it to an + * out-of-bounds segment to make sure that it's actually hidden. + */ +static void update_cursor() +{ + if (curcons->backbuffer) + return; + if (curcons->showcursor) + { + unsigned short addr = (curcons->row * CONSOLE_WIDTH + curcons->col); + outb(CRTC_IDX_REG, CRTC_CURSOR_MSB_IDX); + outb(CRTC_DATA_REG, (addr >> 8)); + outb(CRTC_IDX_REG, CRTC_CURSOR_LSB_IDX); + outb(CRTC_DATA_REG, addr & 0xFF); + } else { + outb(CRTC_IDX_REG, CRTC_CURSOR_MSB_IDX); + outb(CRTC_DATA_REG, 255 /* invalid */); + outb(CRTC_IDX_REG, CRTC_CURSOR_LSB_IDX); + outb(CRTC_DATA_REG, 255 /* invalid */); + } +} + +/** @brief Redirects console writes to a backbuffer. + * + * Verifies that the console is not already backbuffered. If it's not, it + * allocates a backbuffer, copies the current console into the backbuffer, + * and sets the backbuffered flag. + * + * This isn't just theoretical, by the way. The game screen's timer causes + * it to repaint every frame (for lack of a better way to do it), which is + * fine in qemu (which is fast), but causes severe flicker in simics. This + * backbuffering logic seems to have alleviated the flicker. + * + * @see cons_debackbuffer + */ +/*void cons_backbuffer() +{ + if (!curcons->initialized) + clear_console(); + if (curcons->backbuffer) + return; + curcons->base = malloc(CONSOLE_WIDTH * CONSOLE_HEIGHT * 2); + memcpy(curcons->base, curcons->physbase, CONSOLE_WIDTH * CONSOLE_HEIGHT * 2); + curcons->backbuffer = 1; +}*/ + +/** @brief Turns off the backbuffer. + * + * Verifies that we are currently backbuffered. If so, copies the + * backbuffer into video memory, frees the backbuffer, sets the pointer + * back to video memory, clears the backbuffered flag, and updates the + * hardware cursor. + * + * @see cons_backbuffer + */ +/*void cons_debackbuffer() +{ + if (!curcons->initialized) + clear_console(); + if (!curcons->backbuffer) + return; + memcpy(curcons->physbase, curcons->base, CONSOLE_WIDTH * CONSOLE_HEIGHT * 2); + free(curcons->base); + curcons->base = curcons->physbase; + curcons->backbuffer = 0; + update_cursor(); +}*/ + +int putbyte(char ch) +{ + if (!curcons->initialized) + clear_console(); + + /* Make sure to handle special cases nicely.*/ + switch(ch) + { + case '\n': + curcons->row++; + if (curcons->row >= CONSOLE_HEIGHT) /* Moving off the end? Scroll. */ + { + int c; + memmove(curcons->base, curcons->base + 2*CONSOLE_WIDTH, 2*CONSOLE_WIDTH*(CONSOLE_HEIGHT-1)); + curcons->row--; + for (c=0; cbase[(curcons->row * CONSOLE_WIDTH + c) * 2] = ' '; + curcons->base[(curcons->row * CONSOLE_WIDTH + c) * 2 + 1] = curcons->attr; + } + } + // fall through + case '\r': + curcons->col = 0; + update_cursor(); + break; + case '\b': + if (curcons->col) + { + curcons->col--; + curcons->base[(curcons->row*CONSOLE_WIDTH + curcons->col) * 2] = ' '; + } + update_cursor(); + break; + default: + curcons->base[(curcons->row*CONSOLE_WIDTH + curcons->col) * 2] = ch; + curcons->base[(curcons->row*CONSOLE_WIDTH + curcons->col) * 2 + 1] = curcons->attr; + curcons->col++; + if (curcons->col >= CONSOLE_WIDTH) + putbyte('\n'); + update_cursor(); + } + return ch; +} + +void putbytes(const char *s, int len) +{ + if (!curcons->initialized) + clear_console(); + + while (len--) + putbyte(*(s++)); +} + +int set_term_color(int color) +{ + if (!curcons->initialized) + clear_console(); + + curcons->attr = (unsigned char)color; + return 0; +} + +void get_term_color(int *color) +{ + if (!curcons->initialized) + clear_console(); + + *color = (int)curcons->attr; +} + +int set_cursor(int row, int col) +{ + if (!curcons->initialized) + clear_console(); + if (!POS_IS_VALID(row, col)) + return -1; + curcons->row = row; + curcons->col = col; + update_cursor(); + return 0; +} + +void get_cursor(int *row, int *col) +{ + if (!curcons->initialized) + clear_console(); + *row = curcons->row; + *col = curcons->col; +} + +void hide_cursor() +{ + if (!curcons->initialized) + clear_console(); + curcons->showcursor = 0; + update_cursor(); +} + +void show_cursor() +{ + if (!curcons->initialized) + clear_console(); + curcons->showcursor = 1; + update_cursor(); +} + +void clear_console() +{ + int i; + curcons->initialized = 1; + curcons->row = 0; + curcons->col = 0; + for (i = 0; i < CONSOLE_WIDTH * CONSOLE_HEIGHT; i++) + { + curcons->base[i*2] = ' '; + curcons->base[i*2+1] = FGND_LGRAY; + } + update_cursor(); +} + +void draw_char(int row, int col, int ch, int color) +{ + if (!POS_IS_VALID(row, col)) + return; + curcons->base[2 * (CONSOLE_WIDTH * row + col)] = (unsigned char)ch; + curcons->base[2 * (CONSOLE_WIDTH * row + col)+1] = (unsigned char)color; +} + +char get_char(int row, int col) +{ + if (!POS_IS_VALID(row, col)) + return 0; + return curcons->base[2 * (CONSOLE_WIDTH * row + col)]; +} diff --git a/grubload/minilib.c b/grubload/minilib.c new file mode 100644 index 0000000..f2ab662 --- /dev/null +++ b/grubload/minilib.c @@ -0,0 +1,45 @@ +#include "console.h" + +void memcpy(unsigned char *a2, unsigned char *a1, int bytes) +{ + while (bytes--) + *(a2++) = *(a1++); +} + +void memmove(unsigned char *dest, unsigned char *src, int bytes) +{ + if ((dest > src) && (dest <= (src + bytes))) + { + /* do it backwards! */ + dest += bytes; + src += bytes; + while (bytes--) + *(--dest) = *(--src); + } else + while (bytes--) + *(dest++) = *(src++); +} + +int strlen(char *c) +{ + int l = 0; + while (*(c++)) + l++; + return l; +} + +void puts(char *c) +{ + putbytes(c, strlen(c)); +} + +static char hexarr[] = "0123456789ABCDEF"; +void puthex(unsigned long l) +{ + int i; + for (i = 0; i < 8; i++) + { + putbyte(hexarr[l >> 28]); + l <<= 4; + } +} diff --git a/grubload/multiboot.S b/grubload/multiboot_asm.S similarity index 92% rename from grubload/multiboot.S rename to grubload/multiboot_asm.S index bddd8fd..77eb4e0 100644 --- a/grubload/multiboot.S +++ b/grubload/multiboot_asm.S @@ -13,7 +13,8 @@ multiboot_entry: mov $_stack_top, %esp pushl %ebx /* Multiboot info structure */ pushl %eax /* Magic number */ - jmp c_start + call c_start +hang: jmp hang .align 4 _stack: diff --git a/grubload/multiboot_c.c b/grubload/multiboot_c.c index 7c6a4fd..c87b675 100644 --- a/grubload/multiboot_c.c +++ b/grubload/multiboot_c.c @@ -1,6 +1,46 @@ -void c_start(unsigned int magic, void *wee) +#include "console.h" + +struct mb_info { - *(unsigned char *)0xB8000 = 'A'; + unsigned long flags; + unsigned long mem_lower, mem_upper; + unsigned long boot_dev; + char *cmdline; + unsigned long mod_cnt; + struct mod_info *mods; +}; + +struct mod_info +{ + void *mod_start; + void *mod_end; + char *mod_string; + void *reserved; +}; + +void c_start(unsigned int magic, struct mb_info *wee) +{ + unsigned short *grubptr = 0x7CFE; + int i; + + puts("Magic is: "); + puthex(magic); + puts("\nMultiboot header is: "); + puthex(wee); + puts("\n"); + show_cursor(); + + puts("Grubptr is: "); + puthex(*grubptr); + puts("\n"); + + for (i = 0; i < wee->mod_cnt; i++) + { + puts("Module:\n"); + puts(" Start: "); puthex(wee->mods[i].mod_start); puts("\n"); + puts(" Size: "); puthex(wee->mods[i].mod_end - wee->mods[i].mod_start); puts("\n"); + puts(" Name: "); puts(wee->mods[i].mod_string); puts("\n"); + } while (1) ; } diff --git a/grubload/video_defines.h b/grubload/video_defines.h new file mode 100644 index 0000000..ca202ef --- /dev/null +++ b/grubload/video_defines.h @@ -0,0 +1,54 @@ +/* + * Name: video_defines.h + * Date: January 15th 2003 + * Author: Steve Muckle + * + * Description: + * + * Important values for console output. + */ + +#ifndef _VIDEO_DEFINES_H +#define _VIDEO_DEFINES_H + +#define CONSOLE_MEM_BASE 0xB8000 +#define CONSOLE_WIDTH 80 +#define CONSOLE_HEIGHT 25 + +/* Bits 3:0 are the foreground color, bits 6:4 are the + background color, and bit 7 specifies blink (annoying). */ +#define FGND_BLACK 0x0 +#define FGND_BLUE 0x1 +#define FGND_GREEN 0x2 +#define FGND_CYAN 0x3 +#define FGND_RED 0x4 +#define FGND_MAG 0x5 +#define FGND_BRWN 0x6 +#define FGND_LGRAY 0x7 /* Light gray. */ +#define FGND_DGRAY 0x8 /* Dark gray. */ +#define FGND_BBLUE 0x9 /* Bright blue. */ +#define FGND_BGRN 0xA /* Bright green. */ +#define FGND_BCYAN 0xB /* Bright cyan. */ +#define FGND_PINK 0xC +#define FGND_BMAG 0xD /* Bright magenta. */ +#define FGND_YLLW 0xE +#define FGND_WHITE 0xF + +#define BGND_BLACK 0x00 +#define BGND_BLUE 0x10 +#define BGND_GREEN 0x20 +#define BGND_CYAN 0x30 +#define BGND_RED 0x40 +#define BGND_MAG 0x50 +#define BGND_BRWN 0x60 +#define BGND_LGRAY 0x70 /* Light gray. */ + +#define BLINK 0x80 /* Annoying. */ + +/* --- CRTC Register Manipulation --- */ +#define CRTC_IDX_REG 0x3d4 +#define CRTC_DATA_REG 0x3d5 +#define CRTC_CURSOR_LSB_IDX 15 +#define CRTC_CURSOR_MSB_IDX 14 + +#endif