/* needs to stay the first line */ asm(".code16gcc;" "jmp $0, $main"); #define BLACK 0x0 #define BLUE 0x1 #define GREEN 0x2 #define CYAN 0x3 #define RED 0x4 #define MAGENTA 0x5 #define BROWN 0x6 #define L_GRAY 0x7 #define GRAY 0x8 #define L_BLUE 0x9 #define L_GREEN 0xA #define L_CYAN 0xB #define L_RED 0xC #define L_MAGENTA 0xD #define YELLOW 0xE #define WHITE 0xF #define BG_COLOR BLACK #define FG_COLOR MAGENTA #define COLOR(FG, BG) (BG << 4 | FG) #define TEXT_COLOR COLOR(FG_COLOR, BG_COLOR) void putc_color(char c, char color) { asm volatile( "mov $0x09, %%ah;" // using Int 10h AH=09 for attributes "and $0x00FF, %%bx;" // erase higher bits of bx "mov $0x0001, %%cx;" // write the char once "int $0x10;" // we need to manually move the cursor "mov $0x0300, %%ax;" // get cursor position "int $0x10;" "inc %%dl;" // raise column by one (normally we would need to check for end of // line; respective end of screen here - for simplicity (and binary // size) sake, leave that out - could cause bugs) "mov $0x0200, %%ax;" // set cursor position "int $0x10;" ::"al"(c), "bl"(color) : "cx", "dx"); } void print(char const *const str) { for (int i = 0; str[i] != '\0'; ++i) { putc_color(str[i], TEXT_COLOR); } } void new_line() { // using Int10h AH=0E (teletype print char) here, because it does evaluate \n and \r // (and others) asm volatile("mov $0x0E0a, %%ax;" // \n "int $0x10;" "mov $0x0E0d, %%ax;" // \r "int $0x10;" :: : "ax"); } char getc() { char ret; asm volatile( ".no_key:" "xor %%ax, %%ax;" "mov $0x0100, %%ax;" // check for keystroke: "int $0x16;" // http://www.ctyme.com/intr/rb-1755.htm "jz .no_key;" // wait for a key "xor %%ax, %%ax;" "mov $0x1000, %%ax;" // get keystroke: http://www.ctyme.com/intr/rb-1754.htm "int $0x16;" "mov %%al, %%bl;" // temp store char in bl "mov $0x0400, %%ax;" // clear keyboard buffer: "int $0x16;" // http://www.ctyme.com/intr/rb-1759.htm : "=b"(ret) : : "ax"); return ret; } void sleep(long ys) { // http://www.ctyme.com/intr/rb-1525.htm : Int 15/AH=86h bios wait asm volatile("mov $0x8600, %%ax;" "int $0x15;" ::"cx"((ys >> 16)), "dx"(ys)); } void main(void) { print("Hello!"); new_line(); asm volatile("mov $0x00A2, %%ax;" // switch to video mode "int $0x10" :: : "ax"); while (1) { char buf[9]; // 8 chars + \0 unsigned char i = 0; for (; i < 8; i++) { // read at most 8 chars char c = getc(); if (c == '\r') { if (i == 0) { // empty entry print("Reboot!"); sleep(500000); // sleep 500ms, to see the reboot print out, even if // short asm volatile( "cli;" // disable interrupts "mov $0x0FE, %%al;" // tell the keyboard controller to... "out %%al, $0x64;" // ...activate the CPU reset line ".halt:" "hlt;" // some motherboards require this "jmp .halt;" :: // and again, just to be sure : "al"); } else { break; } } buf[i] = c; // buffer the char buf[i + 1] = 0; // set the following to \0 putc_color('*', COLOR(GREEN, BLACK)); // hard coded green on black } if (i == 8) { while (getc() != '\r') ; // wait for enter press, ignoring other keys } new_line(); print(buf); new_line(); } }