/* 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();
}
}