os

Toy OS
git clone git://git.christosmarg.xyz
Log | Files | Refs | README | LICENSE

commit 664d56875223ab8cb8de82892aad2dcc33bc7012
parent 3b623972a8fd45b2b3b28daafd72d754a852a805
Author: Christos Margiolis <christos@margiolis.net>
Date:   Fri, 16 Jul 2021 03:28:10 +0300

organizing stuff

Diffstat:
MMakefile | 4++--
MREADME | 1+
Dboot/Makefile | 51---------------------------------------------------
Dboot/extern.h | 21---------------------
Dboot/idt.c | 166-------------------------------------------------------------------------------
Dboot/idt.h | 99-------------------------------------------------------------------------------
Dboot/io.h | 51---------------------------------------------------
Dboot/kbd.c | 61-------------------------------------------------------------
Dboot/kbd.h | 8--------
Dboot/kmain.c | 16----------------
Dboot/printf.c | 88-------------------------------------------------------------------------------
Dboot/string.c | 45---------------------------------------------
Dboot/string.h | 11-----------
Dboot/timer.c | 25-------------------------
Dboot/tty.c | 120-------------------------------------------------------------------------------
Dboot/tty.h | 47-----------------------------------------------
Dhier | 11-----------
Ainclude/dev/kbd.h | 6++++++
Rboot/stdarg.h -> include/stdarg.h | 0
Ainclude/sys/idt.h | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/sys/io.h | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/sys/libk.h | 26++++++++++++++++++++++++++
Rboot/port.h -> include/sys/port.h | 0
Rboot/timer.h -> include/sys/timer.h | 0
Ainclude/sys/tty.h | 34++++++++++++++++++++++++++++++++++
Akern/Makefile | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Rboot/boot.asm -> kern/boot.asm | 0
Akern/idt.c | 162+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rboot/int.asm -> kern/int.asm | 0
Akern/kbd.c | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akern/kern_main.c | 29+++++++++++++++++++++++++++++
Akern/libk.c | 150+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akern/timer.c | 26++++++++++++++++++++++++++
Akern/tty.c | 139+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rboot/unused/lm.asm -> kern/unused/lm.asm | 0
35 files changed, 859 insertions(+), 822 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,11 +1,11 @@ TGTDIR = build all: - cd boot && make install clean && cd - + cd kern && make install clean && cd - run: qemu-system-i386 -hdd ${TGTDIR}/os.bin clean: rm -rf ${TGTDIR} - cd boot && make clean && cd - + cd kern && make clean && cd - diff --git a/README b/README @@ -1,5 +1,6 @@ My OS ===== + Linux users are afraid of it. Build diff --git a/boot/Makefile b/boot/Makefile @@ -1,51 +0,0 @@ -BIN = os.bin -BINDIR = ../build - -CC = cc -ASM = nasm -LD = ld -CFLAGS = -g -m32 -nostdlib -ffreestanding -Wall -Wextra -std=c99 -O2 -LDFLAGS = -Ttext 0x1000 --oformat binary - -BOOTFILE = boot.asm -BOOT_BIN = boot.bin -KERNEL_BIN = kernel.bin -SRC = *.c *.asm -OBJ = kmain.o \ - string.o \ - tty.o \ - idt.o \ - int.o \ - kbd.o \ - timer.o - -all: options ${BIN} - -options: - @echo ${BIN} build options - @echo CC = ${CC} - @echo ASM = ${ASM} - @echo LD = ${LD} - @echo CFLAGS = ${CFLAGS} - @echo LDFLAGS = ${LDFLAGS} - -${BIN}: ${OBJ} - mkdir -p ${BINDIR} - ${ASM} -fbin ${BOOTFILE} -o ${BOOT_BIN} - ${LD} ${LDFLAGS} ${OBJ} -o ${KERNEL_BIN} - dd if=/dev/zero bs=1000000 count=1 >> ${KERNEL_BIN} - cat ${BOOT_BIN} ${KERNEL_BIN} > $@ - -.c.o: - ${CC} -c ${CFLAGS} $< - -.asm.o: - ${ASM} -felf $< - -install: all - mv ${BIN} ${BINDIR} - -clean: - rm -rf *.bin *.o - -.PHONY: all options install clean diff --git a/boot/extern.h b/boot/extern.h @@ -1,21 +0,0 @@ -#ifndef _KERNEL_EXTERN_H_ -#define _KERNEL_EXTERN_H_ - -#include <stddef.h> -#include <stdint.h> - -#include "stdarg.h" -#include "io.h" -#include "tty.h" -#include "string.h" - -#define BUFSIZ 1024 - -#define ARRLEN(x) (sizeof(x) / sizeof((x)[0])) -#define sizeof_field(s, f) (sizeof(((t *)0)->f)) - -int vsprintf(char *, const char *, va_list); -int sprintf(char *, const char *, ...); -int printf(const char *, ...); - -#endif /* _KERNEL_EXTERN_H_ */ diff --git a/boot/idt.c b/boot/idt.c @@ -1,166 +0,0 @@ -#include "extern.h" -#include "idt.h" -#include "port.h" - -#define N_INT 256 -#define KERN_CODESEG 0x08 - -static void idt_set_gate(uint8_t, uint32_t); - -static struct idt_gate idt[N_INT]; -static void *isr[16] = {NULL}; -/* Exception messages for the first 32 interrupts. */ -static const char *except[] = { - "Division By Zero Exception", - "Debug Exception", - "Non Maskable Interrupt Exception", - "Breakpoint Exception", - "Into Detected Overflow Exception", - "Out of Bounds Exception", - "Invalid Opcode Exception", - "No Coprocessor Exception", - "Double Fault Exception", - "Coprocessor Segment Overrun Exception", - "Bad TSS Exception", - "Segment Not Present Exception", - "Stack Fault Exception", - "General Protection Fault Exception", - "Page Fault Exception", - "Unknown Interrupt Exception", - "Coprocessor Fault Exception", - "Alignment Check Exception (486+)", - "Machine Check Exception (Pentium/586+)", - "Reserved Exception", - "Reserved Exception", - "Reserved Exception", - "Reserved Exception", - "Reserved Exception", - "Reserved Exception", - "Reserved Exception", - "Reserved Exception", - "Reserved Exception", - "Reserved Exception", - "Reserved Exception", - "Reserved Exception", - "Reserved Exception", -}; - -static void -idt_set_gate(uint8_t n, uint32_t ptr) -{ - idt[n].off_lo = ptr & 0xffff; - idt[n].sel = KERN_CODESEG; - idt[n].zero = 0; - /* The gate is present and is running in kernel mode. */ - idt[n].flags = 0x8e; - idt[n].off_hi = (ptr >> 16) & 0xffff; -} - -void -idt_init(void) -{ - struct idt_reg { - uint16_t limit; /* IDT size in bytes. */ - uint32_t base; /* Points at `idt[0]`. */ - } __attribute__((packed)) idtr; - - (void)memset(&idt, 0, sizeof(idt)); - - /* Set up exception interrupts. */ - idt_set_gate(0, (uint32_t)ex0); - idt_set_gate(1, (uint32_t)ex1); - idt_set_gate(2, (uint32_t)ex2); - idt_set_gate(3, (uint32_t)ex3); - idt_set_gate(4, (uint32_t)ex4); - idt_set_gate(5, (uint32_t)ex5); - idt_set_gate(6, (uint32_t)ex6); - idt_set_gate(7, (uint32_t)ex7); - idt_set_gate(8, (uint32_t)ex8); - idt_set_gate(9, (uint32_t)ex9); - idt_set_gate(10, (uint32_t)ex10); - idt_set_gate(11, (uint32_t)ex11); - idt_set_gate(12, (uint32_t)ex12); - idt_set_gate(13, (uint32_t)ex13); - idt_set_gate(14, (uint32_t)ex14); - idt_set_gate(15, (uint32_t)ex15); - idt_set_gate(16, (uint32_t)ex16); - idt_set_gate(17, (uint32_t)ex17); - idt_set_gate(18, (uint32_t)ex18); - idt_set_gate(19, (uint32_t)ex19); - idt_set_gate(20, (uint32_t)ex20); - idt_set_gate(21, (uint32_t)ex21); - idt_set_gate(22, (uint32_t)ex22); - idt_set_gate(23, (uint32_t)ex23); - idt_set_gate(24, (uint32_t)ex24); - idt_set_gate(25, (uint32_t)ex25); - idt_set_gate(26, (uint32_t)ex26); - idt_set_gate(27, (uint32_t)ex27); - idt_set_gate(28, (uint32_t)ex28); - idt_set_gate(29, (uint32_t)ex29); - idt_set_gate(30, (uint32_t)ex30); - idt_set_gate(31, (uint32_t)ex31); - - /* Remap the PIC */ - /* TODO: explain.*/ - outb(P_PIC1_CMD, 0x11); - outb(P_PIC2_CMD, 0x11); - outb(P_PIC1_DATA, 0x20); - outb(P_PIC2_DATA, 0x28); - outb(P_PIC1_DATA, 0x04); - outb(P_PIC2_DATA, 0x02); - outb(P_PIC1_DATA, 0x01); - outb(P_PIC2_DATA, 0x01); - outb(P_PIC1_DATA, 0x00); - outb(P_PIC2_DATA, 0x00); - - /* Set up IRQs */ - idt_set_gate(32, (uint32_t)irq0); - idt_set_gate(33, (uint32_t)irq1); - idt_set_gate(34, (uint32_t)irq2); - idt_set_gate(35, (uint32_t)irq3); - idt_set_gate(36, (uint32_t)irq4); - idt_set_gate(37, (uint32_t)irq5); - idt_set_gate(38, (uint32_t)irq6); - idt_set_gate(39, (uint32_t)irq7); - idt_set_gate(40, (uint32_t)irq8); - idt_set_gate(41, (uint32_t)irq9); - idt_set_gate(42, (uint32_t)irq10); - idt_set_gate(43, (uint32_t)irq11); - idt_set_gate(44, (uint32_t)irq12); - idt_set_gate(45, (uint32_t)irq13); - idt_set_gate(46, (uint32_t)irq14); - idt_set_gate(47, (uint32_t)irq15); - - /* https://wiki.osdev.org/Interrupt_Descriptor_Table#Location_and_Size */ - idtr.base = (uint32_t)&idt; - idtr.limit = N_INT * sizeof(struct idt_gate) - 1; - __asm__ __volatile__ ("lidtl (%0)" : : "r" (&idtr)); -} - -void -int_handler(struct reg *r) -{ - void (*handler)(struct reg *); - - /* - * We'll call the handler only if the interrupt number is > 32, - * which means that we're dealing with an IRQ and not an exception. - */ - if (r->intno >= 32 && (handler = isr[r->intno - 32]) != NULL) - handler(r); - /* Entries below index 32 in the IDT are exceptions, we need to hang. */ - else if (r->intno < 32) { - tty_write(except[r->intno]); - tty_write(". System halted...\n"); - __asm__ __volatile__ ("hlt"); - } - if (r->intno >= 40) - outb(P_PIC2_CMD, 0x20); - outb(P_PIC1_CMD, 0x20); -} - -void -int_add_handler(uint8_t intno, void (*handler)(struct reg *r)) -{ - isr[intno] = handler; -} diff --git a/boot/idt.h b/boot/idt.h @@ -1,99 +0,0 @@ -#ifndef _KERNEL_IDT_H_ -#define _KERNEL_IDT_H_ - -/* IA-32 */ -struct idt_gate { - uint16_t off_lo; - uint16_t sel; - uint8_t zero; - uint8_t flags; - uint16_t off_hi; -} __attribute__((packed)); - -/* This will be populated by `int_common_stub` in `int.asm`. */ -struct reg { - /* Will be popped last. */ - uint32_t gs; - uint32_t fs; - uint32_t es; - uint32_t ds; - /* Pushed by `pusha`. */ - uint32_t edi; - uint32_t esi; - uint32_t ebp; - uint32_t esp; - uint32_t ebx; - uint32_t edx; - uint32_t ecx; - uint32_t eax; - /* Interrupt info. Pushed by `push byte`. */ - uint32_t intno; - uint32_t err; - /* Pushed by the CPU. */ - uint32_t eip; - uint32_t cs; - uint32_t eflags; - uint32_t uesp; - uint32_t ss; -}; - -/* Called by `kmain`. */ -void idt_init(void); - -/* Called by drivers. */ -void int_handler(struct reg *); -void int_add_handler(uint8_t, void (*)(struct reg *)); - -/* The first 32 interrupts are reserved for exceptions. */ -void ex0(void); -void ex1(void); -void ex2(void); -void ex3(void); -void ex4(void); -void ex5(void); -void ex6(void); -void ex7(void); -void ex8(void); -void ex9(void); -void ex10(void); -void ex11(void); -void ex12(void); -void ex13(void); -void ex14(void); -void ex15(void); -void ex16(void); -void ex17(void); -void ex18(void); -void ex19(void); -void ex20(void); -void ex21(void); -void ex22(void); -void ex23(void); -void ex24(void); -void ex25(void); -void ex26(void); -void ex27(void); -void ex28(void); -void ex29(void); -void ex30(void); -void ex31(void); - -/* IRQs */ -void irq0(void); -void irq1(void); -void irq2(void); -void irq3(void); -void irq4(void); -void irq5(void); -void irq6(void); -void irq7(void); -void irq8(void); -void irq9(void); -void irq10(void); -void irq11(void); -void irq12(void); -void irq13(void); -void irq14(void); -void irq15(void); - -#endif /* _KERNEL_IDT_H_ */ diff --git a/boot/io.h b/boot/io.h @@ -1,51 +0,0 @@ -#ifndef _KERNEL_IO_H_ -#define _KERNEL_IO_H_ - -#include <stdint.h> - -static inline uint8_t -inb(uint16_t port) -{ - uint8_t res; - - __asm__ __volatile__ ("in %%dx, %%al" : "=a" (res) : "d" (port)); - return res; -} - -static inline void -outb(uint16_t port, uint8_t v) -{ - __asm__ __volatile__ ("out %%al, %%dx" : : "a" (v), "d" (port)); -} - -static inline uint16_t -inw(uint16_t port) -{ - uint16_t res; - - __asm__ __volatile__ ("in %%dx, %%ax" : "=a" (res) : "d" (port)); - return res; -} - -static inline void -outw(uint16_t port, uint16_t v) -{ - __asm__ __volatile__ ("out %%ax, %%dx" : : "a" (v), "d" (port)); -} - -static inline uint32_t -inl(uint16_t port) -{ - uint32_t res; - - __asm__ __volatile__ ("in %%dx, %%eax" : "=a" (res) : "d" (port)); - return res; -} - -static inline void -outl(uint16_t port, uint32_t v) -{ - __asm__ __volatile__ ("out %%eax, %%dx" : : "a" (v), "d" (port)); -} - -#endif /* _KERNEL_IO_H_ */ diff --git a/boot/kbd.c b/boot/kbd.c @@ -1,61 +0,0 @@ -#include "extern.h" -#include "idt.h" -#include "port.h" - -static void kbd_callback(struct reg *); - -static unsigned char kbdus[128] = { - 0, /* Error */ - 27, /* Escape */ - '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', - '-', '=', '\b', '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', - '[', ']', '\n', - 0, /* Control */ - 'a', 's', 'd', 'f', 'g', - 'h', 'j', 'k', 'l', ';', '\'', '`', - 0, /* Left Shift */ - '\\', 'z', 'x', - 'c', 'v', 'b', 'n', 'm', ',', '.', '/', - 0, /* Right Shift */ - '*', - 0, /* Alt */ - ' ', - 0, /* Caps Lock */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F1-F10 */ - 0, /* Num Lock */ - 0, /* Scroll Lock */ - 0, /* Home Key */ - 0, /* Up Arrow */ - 0, /* Page Up */ - '-', - 0, /* Left Arrow */ - 0, - 0, /* Right Arrow */ - '+', - 0, /* End Key */ - 0, /* Down Arrow */ - 0, /* Page Down */ - 0, /* Insert Key */ - 0, /* Delete Key */ - 0, 0, 0, - 0, 0, /* F11, F12 */ - 0, /* The rest are undefined */ -}; - -static void -kbd_callback(struct reg *r) -{ - uint8_t sc; - - if ((sc = inb(P_KBD)) & 0x80) { - } else { - tty_putc(kbdus[sc]); - } - (void)r; -} - -void -kbd_init(void) -{ - int_add_handler(1, kbd_callback); -} diff --git a/boot/kbd.h b/boot/kbd.h @@ -1,8 +0,0 @@ -#ifndef _KERNEL_KBD_H_ -#define _KERNEL_KBD_H_ - -#include "extern.h" - -void kbd_init(void); - -#endif /* _KERNEL_KBD_H_ */ diff --git a/boot/kmain.c b/boot/kmain.c @@ -1,16 +0,0 @@ -#include "extern.h" -#include "idt.h" -#include "kbd.h" -#include "timer.h" - -void -kmain(void) -{ - tty_clear(); - idt_init(); - timer_init(50); - kbd_init(); - __asm__ __volatile__ ("sti"); - - for (;;); -} diff --git a/boot/printf.c b/boot/printf.c @@ -1,88 +0,0 @@ -#include "extern.h" - -static char * -itoa(int n, char *buf, int base) -{ - (void)n; - (void)base; - - return buf; -} - -int -vsprintf(char *buf, const char *fmt, va_list args) -{ - char *str, *s; - int base, i, n; - - for (str = buf; *fmt != '\0'; fmt++) { - base = 10; - if (*fmt != '%') { - *str++ = *fmt; - continue; - } - if (*fmt == '%') { - switch (*(++fmt)) { - case 'c': - *str++ = (unsigned char)va_arg(args, int); - continue; - case 's': - s = va_arg(args, char *); - n = strlen(s); - for (i = 0; i < n; i++) - *str++ = *s++; - continue; - case 'p': - continue; - case 'd': /* FALLTHROUGH */ - case 'i': - n = va_arg(args, int); - break; - case 'u': - n = va_arg(args, unsigned int); - break; - case 'o': - base = 8; - break; - case 'X': - base = 16; - break; - case '%': - *str++ = '%'; - continue; - } - str = itoa(n, str, base); - } - } - *str = '\0'; - - return str - buf; -} - -int -sprintf(char *buf, const char *fmt, ...) -{ - va_list args; - int n; - - va_start(args, fmt); - n = vsprintf(buf, fmt, args); - va_end(args); - - return n; -} - -int -printf(const char *fmt, ...) -{ - char buf[BUFSIZ]; - va_list args; - int n; - - va_start(args, fmt); - n = vsprintf(buf, fmt, args); - va_end(args); - tty_write(buf); - - return n; -} diff --git a/boot/string.c b/boot/string.c @@ -1,45 +0,0 @@ -#include "string.h" - -void * -memset(void *dst, int v, size_t len) -{ - unsigned char *dst0; - - dst0 = dst; - while (len--) - *dst0++ = v; - return dst; -} - -void * -memcpy(void *dst, const void *src, size_t len) -{ - const unsigned char *src0; - unsigned char *dst0; - - src0 = src; - dst0 = dst; - - while (len--) - *dst0++ = *src0++; - return dst; -} - -size_t -strlen(const char *str) -{ - const char *s; - - for (s = str; *s != '\0'; s++) - ; - return (s - str); -} - -int -strcmp(const char *s1, const char *s2) -{ - while (*s1 == *s2++) - if (*s1++ == '\0') - return 0; - return *(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1); -} diff --git a/boot/string.h b/boot/string.h @@ -1,11 +0,0 @@ -#ifndef _KERNEL_STRING_H_ -#define _KERNEL_STRING_H_ - -#include <stddef.h> - -void *memset(void *, int, size_t); -void *memcpy(void *, const void *, size_t); -size_t strlen(const char *); -int strcmp(const char *, const char *); - -#endif /* _KERNEL_STRING_H_ */ diff --git a/boot/timer.c b/boot/timer.c @@ -1,25 +0,0 @@ -#include "extern.h" -#include "idt.h" -#include "port.h" - -static void timer_callback(struct reg *); - -static uint32_t timer_ticks = 0; - -static void -timer_callback(struct reg *r) -{ - timer_ticks++; - (void)r; -} - -void -timer_init(uint32_t hz) -{ - uint32_t div = 1193180 / hz; - - int_add_handler(0, timer_callback); - outb(P_TIMER_CMD, 0x36); - outb(P_TIMER_DATA, (uint8_t)(div & 0xff)); - outb(P_TIMER_DATA, (uint8_t)((div >> 8) & 0xff)); -} diff --git a/boot/tty.c b/boot/tty.c @@ -1,120 +0,0 @@ -#include "io.h" -#include "port.h" -#include "tty.h" - -static struct tty_info tty; - -void -tty_clear(void) -{ - size_t y, x; - - tty_curs_enable(0x0e, 0x0f); /* Low cursor shape. */ - tty_curs_setpos(0, 0); - tty.row = 0; - tty.col = 0; - tty.color = VGA_SET_COLOR(VGA_BLUE, VGA_WHITE); - tty.buf = (uint16_t *)_VGA_MEM; - for (x = 0; x < _VGA_COLS; x++) - for (y = 0; y < _VGA_ROWS; y++) - tty.buf[y * _VGA_COLS + x] = _PUTC(' '); -} - -void -tty_putc(char c) -{ - switch (c) { - case '\n': - tty.row++; - tty.col = 0; - break; - case '\b': - tty.col--; - tty.buf[tty.row * _VGA_COLS + tty.col] = _PUTC(' '); - break; - case '\r': - tty.col = 0; - break; - case '\t': - tty.col += 8; - break; - default: - tty.buf[tty.row * _VGA_COLS + tty.col] = _PUTC(c); - tty.col++; - } - - if (tty.row >= _VGA_ROWS) { - tty.row = 0; - tty.col = 0; - } - if (tty.col >= _VGA_COLS) { - tty.row++; - tty.col = 0; - } - tty_curs_setpos(tty.col, tty.row); -} - -void -tty_write(const char *str) -{ - while (*str != '\0') - tty_putc(*str++); -} - -/* - * The arguments `start` and `end` define the shape of the cursor. - * The lowest scaline value is 0x00 and the highest 0x0f. A cursor shape - * with `start = 0x00` and `end = 0x0f` is effectively a block cursor. - */ -void -tty_curs_enable(uint8_t start, uint8_t end) -{ - /* 0x0a: Low cursor shape */ - outb(P_CURS_CMD, 0x0a); - outb(P_CURS_DATA, (inb(P_CURS_DATA) & 0xc0) | start); - outb(P_CURS_CMD, 0x0b); - outb(P_CURS_DATA, (inb(P_CURS_DATA) & 0xe0) | end); -} - -void -tty_curs_disable(void) -{ - outb(P_CURS_CMD, 0x0a); - /* - * Bit representation: - * 7 6 | 5 | 4 0 - * Unused | Disable | Shape - */ - outb(P_CURS_DATA, 0x20); -} - -/* - * Returns the position in `y * _VGA_COLS + x` format. - * x = pos % _VGA_COLS - * y = pos / _VGA_COLS - */ -uint16_t -tty_curs_getpos(void) -{ - uint16_t pos = 0; - - outb(P_CURS_CMD, 0x0e); - pos |= (uint16_t)inb(P_CURS_DATA) << 8; - outb(P_CURS_CMD, 0x0f); - pos |= inb(P_CURS_DATA); - - return pos; -} - -void -tty_curs_setpos(int x, int y) -{ - uint16_t pos = y * _VGA_COLS + x; - - /* Expect 8 highest bits */ - outb(P_CURS_CMD, 0x0e); - outb(P_CURS_DATA, (uint8_t)((pos >> 8) & 0xff)); - /* Expect 8 lowest bits */ - outb(P_CURS_CMD, 0x0f); - outb(P_CURS_DATA, (uint8_t)(pos & 0xff)); -} diff --git a/boot/tty.h b/boot/tty.h @@ -1,47 +0,0 @@ -#ifndef _KERNEL_TTY_H_ -#define _KERNEL_TTY_H_ - -#include <stddef.h> - -#define _VGA_MEM 0xb8000; -#define _VGA_COLS 80 -#define _VGA_ROWS 25 -#define _PUTC(c) (((uint16_t)tty.color << 8) | (c)) - -#define VGA_SET_COLOR(fg, bg) ((fg) | (bg) << 4) - -struct tty_info { - volatile uint16_t *buf; - size_t row; - size_t col; - uint8_t color; -}; - -enum vga_color { - VGA_BLACK = 0, - VGA_BLUE, - VGA_GREEN, - VGA_CYAN, - VGA_RED, - VGA_MAGENTA, - VGA_BROWN, - VGA_LIGHT_GREY, - VGA_DARK_GREY, - VGA_LIGHT_BLUE, - VGA_LIGHT_GREEN, - VGA_LIGHT_CYAN, - VGA_LIGHT_RED, - VGA_LIGHT_MAGENTA, - VGA_LIGHT_BROWN, - VGA_WHITE, -}; - -void tty_clear(void); -void tty_putc(char); -void tty_write(const char *); -void tty_curs_enable(uint8_t, uint8_t); -void tty_curs_disable(void); -void tty_curs_setpos(int, int); -uint16_t tty_curs_getpos(void); - -#endif /* _KERNEL_TTY_H_ */ diff --git a/hier b/hier @@ -1,11 +0,0 @@ -/bin/ - boot/ -/dev/ -/sys/ - include/ - dev/ - kernel/ - sys/ - lib/ - src/ -/usr diff --git a/include/dev/kbd.h b/include/dev/kbd.h @@ -0,0 +1,6 @@ +#ifndef _KERNEL_KBD_H_ +#define _KERNEL_KBD_H_ + +void kbd_init(void); + +#endif /* _KERNEL_KBD_H_ */ diff --git a/boot/stdarg.h b/include/stdarg.h diff --git a/include/sys/idt.h b/include/sys/idt.h @@ -0,0 +1,99 @@ +#ifndef _KERNEL_IDT_H_ +#define _KERNEL_IDT_H_ + +/* IA-32 */ +struct idt_gate { + uint16_t off_lo; + uint16_t sel; + uint8_t zero; + uint8_t flags; + uint16_t off_hi; +} __attribute__((packed)); + +/* This will be populated by `int_common_stub` in `int.asm`. */ +struct reg { + /* Will be popped last. */ + uint32_t gs; + uint32_t fs; + uint32_t es; + uint32_t ds; + /* Pushed by `pusha`. */ + uint32_t edi; + uint32_t esi; + uint32_t ebp; + uint32_t esp; + uint32_t ebx; + uint32_t edx; + uint32_t ecx; + uint32_t eax; + /* Interrupt info. Pushed by `push byte`. */ + uint32_t intno; + uint32_t err; + /* Pushed by the CPU. */ + uint32_t eip; + uint32_t cs; + uint32_t eflags; + uint32_t uesp; + uint32_t ss; +}; + +/* Called by `kern_main`. */ +void idt_init(void); + +/* Called by drivers. */ +void int_handler(struct reg *); +void int_add_handler(uint8_t, void (*)(struct reg *)); + +/* The first 32 interrupts are reserved for exceptions. */ +void ex0(void); +void ex1(void); +void ex2(void); +void ex3(void); +void ex4(void); +void ex5(void); +void ex6(void); +void ex7(void); +void ex8(void); +void ex9(void); +void ex10(void); +void ex11(void); +void ex12(void); +void ex13(void); +void ex14(void); +void ex15(void); +void ex16(void); +void ex17(void); +void ex18(void); +void ex19(void); +void ex20(void); +void ex21(void); +void ex22(void); +void ex23(void); +void ex24(void); +void ex25(void); +void ex26(void); +void ex27(void); +void ex28(void); +void ex29(void); +void ex30(void); +void ex31(void); + +/* IRQs */ +void irq0(void); +void irq1(void); +void irq2(void); +void irq3(void); +void irq4(void); +void irq5(void); +void irq6(void); +void irq7(void); +void irq8(void); +void irq9(void); +void irq10(void); +void irq11(void); +void irq12(void); +void irq13(void); +void irq14(void); +void irq15(void); + +#endif /* _KERNEL_IDT_H_ */ diff --git a/include/sys/io.h b/include/sys/io.h @@ -0,0 +1,69 @@ +#ifndef _KERNEL_IO_H_ +#define _KERNEL_IO_H_ + +#include <stdint.h> + +static inline uint8_t +inb(uint16_t port) +{ + uint8_t res; + + __asm__ __volatile__ ("in %%dx, %%al" : "=a" (res) : "d" (port)); + return (res); +} + +static inline void +outb(uint16_t port, uint8_t v) +{ + __asm__ __volatile__ ("out %%al, %%dx" : : "a" (v), "d" (port)); +} + +static inline uint16_t +inw(uint16_t port) +{ + uint16_t res; + + __asm__ __volatile__ ("in %%dx, %%ax" : "=a" (res) : "d" (port)); + return (res); +} + +static inline void +outw(uint16_t port, uint16_t v) +{ + __asm__ __volatile__ ("out %%ax, %%dx" : : "a" (v), "d" (port)); +} + +static inline uint32_t +inl(uint16_t port) +{ + uint32_t res; + + __asm__ __volatile__ ("in %%dx, %%eax" : "=a" (res) : "d" (port)); + return (res); +} + +static inline void +outl(uint16_t port, uint32_t v) +{ + __asm__ __volatile__ ("out %%eax, %%dx" : : "a" (v), "d" (port)); +} + +static inline void +hlt(void) +{ + __asm__ __volatile__ ("hlt"); +} + +static inline void +cli(void) +{ + __asm__ __volatile__ ("cli"); +} + +static inline void +sti(void) +{ + __asm__ __volatile__ ("sti"); +} + +#endif /* _KERNEL_IO_H_ */ diff --git a/include/sys/libk.h b/include/sys/libk.h @@ -0,0 +1,26 @@ +#ifndef _KERNEL_LIBK_H_ +#define _KERNEL_LIBK_H_ + +#include <stddef.h> +#include <stdint.h> +#include <stdarg.h> + +#include <sys/io.h> +#include <sys/tty.h> + +#define BUFSIZ 1024 + +#define ARRLEN(x) (sizeof(x) / sizeof((x)[0])) +#define UNUSED(x) ((void)(x)) +#define sizeof_field(s, f) (sizeof(((t *)0)->f)) + +void *memset(void *, int, size_t); +void *memcpy(void *, const void *, size_t); +size_t strlen(const char *); +int strcmp(const char *, const char *); +int vsprintf(char *, const char *, va_list); +int sprintf(char *, const char *, ...); +int printf(const char *, ...); +void panic(const char *, ...); + +#endif /* _KERNEL_LIBK_H_ */ diff --git a/boot/port.h b/include/sys/port.h diff --git a/boot/timer.h b/include/sys/timer.h diff --git a/include/sys/tty.h b/include/sys/tty.h @@ -0,0 +1,34 @@ +#ifndef _KERNEL_TTY_H_ +#define _KERNEL_TTY_H_ + +#include <stddef.h> + +enum vga_color: uint8_t { + VGA_BLACK = 0, + VGA_BLUE, + VGA_GREEN, + VGA_CYAN, + VGA_RED, + VGA_MAGENTA, + VGA_BROWN, + VGA_LIGHT_GREY, + VGA_DARK_GREY, + VGA_LIGHT_BLUE, + VGA_LIGHT_GREEN, + VGA_LIGHT_CYAN, + VGA_LIGHT_RED, + VGA_LIGHT_MAGENTA, + VGA_LIGHT_BROWN, + VGA_WHITE, +}; + +void tty_clear(uint8_t, uint8_t); +void tty_set_color(uint8_t, uint8_t); +void tty_putc(char); +void tty_write(const char *); +void tty_curs_enable(uint8_t, uint8_t); +void tty_curs_disable(void); +void tty_curs_setpos(int, int); +uint16_t tty_curs_getpos(void); + +#endif /* _KERNEL_TTY_H_ */ diff --git a/kern/Makefile b/kern/Makefile @@ -0,0 +1,52 @@ +BIN = os.bin +BINDIR = ../build + +CC = cc +ASM = nasm +LD = ld +INCDIR = ../include +CFLAGS = -g -m32 -nostdlib -ffreestanding -Wall -Wextra -std=c99 -O2 -I${INCDIR} +LDFLAGS = -Ttext 0x1000 --oformat binary + +BOOTFILE = boot.asm +BOOT_BIN = boot.bin +KERNEL_BIN = kernel.bin +SRC = *.c *.asm +OBJ = kern_main.o \ + libk.o \ + tty.o \ + idt.o \ + int.o \ + kbd.o \ + timer.o + +all: options ${BIN} + +options: + @echo ${BIN} build options + @echo CC = ${CC} + @echo ASM = ${ASM} + @echo LD = ${LD} + @echo CFLAGS = ${CFLAGS} + @echo LDFLAGS = ${LDFLAGS} + +${BIN}: ${OBJ} + mkdir -p ${BINDIR} + ${ASM} -fbin ${BOOTFILE} -o ${BOOT_BIN} + ${LD} ${LDFLAGS} ${OBJ} -o ${KERNEL_BIN} + dd if=/dev/zero bs=1000000 count=1 >> ${KERNEL_BIN} + cat ${BOOT_BIN} ${KERNEL_BIN} > $@ + +.c.o: + ${CC} -c ${CFLAGS} $< + +.asm.o: + ${ASM} -felf $< + +install: all + mv ${BIN} ${BINDIR} + +clean: + rm -rf *.bin *.o + +.PHONY: all options install clean diff --git a/boot/boot.asm b/kern/boot.asm diff --git a/kern/idt.c b/kern/idt.c @@ -0,0 +1,162 @@ +#include <sys/libk.h> +#include <sys/idt.h> +#include <sys/port.h> + +#define N_INT 256 +#define KERN_CODESEG 0x08 + +static void idt_set_gate(uint8_t, uint32_t); + +static struct idt_gate idt[N_INT]; +static void *isr[16] = {NULL}; +static const char *except[] = { + "Division By Zero Exception", + "Debug Exception", + "Non Maskable Interrupt Exception", + "Breakpoint Exception", + "Into Detected Overflow Exception", + "Out of Bounds Exception", + "Invalid Opcode Exception", + "No Coprocessor Exception", + "Double Fault Exception", + "Coprocessor Segment Overrun Exception", + "Bad TSS Exception", + "Segment Not Present Exception", + "Stack Fault Exception", + "General Protection Fault Exception", + "Page Fault Exception", + "Unknown Interrupt Exception", + "Coprocessor Fault Exception", + "Alignment Check Exception (486+)", + "Machine Check Exception (Pentium/586+)", + "Reserved Exception", + "Reserved Exception", + "Reserved Exception", + "Reserved Exception", + "Reserved Exception", + "Reserved Exception", + "Reserved Exception", + "Reserved Exception", + "Reserved Exception", + "Reserved Exception", + "Reserved Exception", + "Reserved Exception", + "Reserved Exception", +}; + +static void +idt_set_gate(uint8_t n, uint32_t ptr) +{ + idt[n].off_lo = ptr & 0xffff; + idt[n].sel = KERN_CODESEG; + idt[n].zero = 0; + /* The gate is present and is running in kernel mode. */ + idt[n].flags = 0x8e; + idt[n].off_hi = (ptr >> 16) & 0xffff; +} + +void +idt_init(void) +{ + struct idt_reg { + uint16_t limit; /* IDT size in bytes. */ + uint32_t base; /* Points at `idt[0]`. */ + } __attribute__((packed)) idtr; + + (void)memset(&idt, 0, sizeof(idt)); + + /* Set up exception interrupts. */ + idt_set_gate(0, (uint32_t)ex0); + idt_set_gate(1, (uint32_t)ex1); + idt_set_gate(2, (uint32_t)ex2); + idt_set_gate(3, (uint32_t)ex3); + idt_set_gate(4, (uint32_t)ex4); + idt_set_gate(5, (uint32_t)ex5); + idt_set_gate(6, (uint32_t)ex6); + idt_set_gate(7, (uint32_t)ex7); + idt_set_gate(8, (uint32_t)ex8); + idt_set_gate(9, (uint32_t)ex9); + idt_set_gate(10, (uint32_t)ex10); + idt_set_gate(11, (uint32_t)ex11); + idt_set_gate(12, (uint32_t)ex12); + idt_set_gate(13, (uint32_t)ex13); + idt_set_gate(14, (uint32_t)ex14); + idt_set_gate(15, (uint32_t)ex15); + idt_set_gate(16, (uint32_t)ex16); + idt_set_gate(17, (uint32_t)ex17); + idt_set_gate(18, (uint32_t)ex18); + idt_set_gate(19, (uint32_t)ex19); + idt_set_gate(20, (uint32_t)ex20); + idt_set_gate(21, (uint32_t)ex21); + idt_set_gate(22, (uint32_t)ex22); + idt_set_gate(23, (uint32_t)ex23); + idt_set_gate(24, (uint32_t)ex24); + idt_set_gate(25, (uint32_t)ex25); + idt_set_gate(26, (uint32_t)ex26); + idt_set_gate(27, (uint32_t)ex27); + idt_set_gate(28, (uint32_t)ex28); + idt_set_gate(29, (uint32_t)ex29); + idt_set_gate(30, (uint32_t)ex30); + idt_set_gate(31, (uint32_t)ex31); + + /* Remap the PIC */ + /* TODO: explain.*/ + outb(P_PIC1_CMD, 0x11); + outb(P_PIC2_CMD, 0x11); + outb(P_PIC1_DATA, 0x20); + outb(P_PIC2_DATA, 0x28); + outb(P_PIC1_DATA, 0x04); + outb(P_PIC2_DATA, 0x02); + outb(P_PIC1_DATA, 0x01); + outb(P_PIC2_DATA, 0x01); + outb(P_PIC1_DATA, 0x00); + outb(P_PIC2_DATA, 0x00); + + /* Set up IRQs */ + idt_set_gate(32, (uint32_t)irq0); + idt_set_gate(33, (uint32_t)irq1); + idt_set_gate(34, (uint32_t)irq2); + idt_set_gate(35, (uint32_t)irq3); + idt_set_gate(36, (uint32_t)irq4); + idt_set_gate(37, (uint32_t)irq5); + idt_set_gate(38, (uint32_t)irq6); + idt_set_gate(39, (uint32_t)irq7); + idt_set_gate(40, (uint32_t)irq8); + idt_set_gate(41, (uint32_t)irq9); + idt_set_gate(42, (uint32_t)irq10); + idt_set_gate(43, (uint32_t)irq11); + idt_set_gate(44, (uint32_t)irq12); + idt_set_gate(45, (uint32_t)irq13); + idt_set_gate(46, (uint32_t)irq14); + idt_set_gate(47, (uint32_t)irq15); + + /* https://wiki.osdev.org/Interrupt_Descriptor_Table#Location_and_Size */ + idtr.base = (uint32_t)&idt; + idtr.limit = N_INT * sizeof(struct idt_gate) - 1; + __asm__ __volatile__ ("lidtl (%0)" : : "r" (&idtr)); +} + +void +int_handler(struct reg *r) +{ + void (*handler)(struct reg *); + + /* + * We'll call the handler only if the interrupt number is > 32, + * which means that we're dealing with an IRQ and not an exception. + */ + if (r->intno >= 32 && (handler = isr[r->intno - 32]) != NULL) + handler(r); + /* Entries below index 32 in the IDT are exceptions, we need to hang. */ + else if (r->intno < 32) + panic("%s: System halted...\n", except[r->intno]); + if (r->intno >= 40) + outb(P_PIC2_CMD, 0x20); + outb(P_PIC1_CMD, 0x20); +} + +void +int_add_handler(uint8_t intno, void (*handler)(struct reg *r)) +{ + isr[intno] = handler; +} diff --git a/boot/int.asm b/kern/int.asm diff --git a/kern/kbd.c b/kern/kbd.c @@ -0,0 +1,64 @@ +#include <sys/libk.h> +#include <sys/idt.h> +#include <sys/port.h> + +#include <dev/kbd.h> + +static void kbd_callback(struct reg *); + +static unsigned char kbdus[128] = { + 0, /* Error */ + 27, /* Escape */ + '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', + '-', '=', '\b', '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', + '[', ']', '\n', + 0, /* Control */ + 'a', 's', 'd', 'f', 'g', + 'h', 'j', 'k', 'l', ';', '\'', '`', + 0, /* Left Shift */ + '\\', 'z', 'x', + 'c', 'v', 'b', 'n', 'm', ',', '.', '/', + 0, /* Right Shift */ + '*', + 0, /* Alt */ + ' ', + 0, /* Caps Lock */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F1-F10 */ + 0, /* Num Lock */ + 0, /* Scroll Lock */ + 0, /* Home Key */ + 0, /* Up Arrow */ + 0, /* Page Up */ + '-', + 0, /* Left Arrow */ + 0, + 0, /* Right Arrow */ + '+', + 0, /* End Key */ + 0, /* Down Arrow */ + 0, /* Page Down */ + 0, /* Insert Key */ + 0, /* Delete Key */ + 0, 0, 0, + 0, 0, /* F11, F12 */ + 0, /* The rest are undefined */ +}; + +static void +kbd_callback(struct reg *r) +{ + uint8_t sc; + + if ((sc = inb(P_KBD)) & 0x80) { + } else { + tty_putc(kbdus[sc]); + } + + UNUSED(r); +} + +void +kbd_init(void) +{ + int_add_handler(1, kbd_callback); +} diff --git a/kern/kern_main.c b/kern/kern_main.c @@ -0,0 +1,29 @@ +#include <sys/libk.h> +#include <sys/idt.h> +#include <sys/io.h> +#include <sys/timer.h> + +#include <dev/kbd.h> + +#define OK() ((void)printf("ok\n")) + +void +kern_main(void) +{ + tty_clear(VGA_BLUE, VGA_WHITE); + + printf("IDT... "); + idt_init(); + OK(); + + printf("Timer... "); + timer_init(50); + OK(); + + printf("Keyboard... "); + kbd_init(); + OK(); + + sti(); + for (;;); +} diff --git a/kern/libk.c b/kern/libk.c @@ -0,0 +1,150 @@ +#include <sys/libk.h> +#include <sys/io.h> + +static char * +itoa(int n, char *buf, int base) +{ + (void)n; + (void)base; + + return (buf); +} + +void * +memset(void *dst, int v, size_t len) +{ + unsigned char *dst0; + + dst0 = dst; + while (len--) + *dst0++ = v; + + return (dst); +} + +void * +memcpy(void *dst, const void *src, size_t len) +{ + const unsigned char *src0; + unsigned char *dst0; + + src0 = src; + dst0 = dst; + + while (len--) + *dst0++ = *src0++; + + return (dst); +} + +size_t +strlen(const char *str) +{ + const char *s; + + for (s = str; *s != '\0'; s++) + ; /* nothing */ + + return (s - str); +} + +int +strcmp(const char *s1, const char *s2) +{ + while (*s1 == *s2++) + if (*s1++ == '\0') + return (0); + + return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1)); +} + +int +vsprintf(char *buf, const char *fmt, va_list args) +{ + char *str, *s; + int base, i, n; + + for (str = buf; *fmt != '\0'; fmt++) { + base = 10; + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + if (*fmt == '%') { + switch (*(++fmt)) { + case 'c': + *str++ = (unsigned char)va_arg(args, int); + continue; + case 's': + s = va_arg(args, char *); + n = strlen(s); + for (i = 0; i < n; i++) + *str++ = *s++; + continue; + case 'p': + continue; + case 'd': /* FALLTHROUGH */ + case 'i': + n = va_arg(args, int); + break; + case 'u': + n = va_arg(args, unsigned int); + break; + case 'o': + base = 8; + break; + case 'X': + base = 16; + break; + case '%': + *str++ = '%'; + continue; + } + str = itoa(n, str, base); + } + } + *str = '\0'; + + return (str - buf); +} + +int +sprintf(char *buf, const char *fmt, ...) +{ + va_list args; + int n; + + va_start(args, fmt); + n = vsprintf(buf, fmt, args); + va_end(args); + + return (n); +} + +int +printf(const char *fmt, ...) +{ + char buf[BUFSIZ]; + va_list args; + int n; + + va_start(args, fmt); + n = vsprintf(buf, fmt, args); + va_end(args); + tty_write(buf); + + return (n); +} + +void +panic(const char *fmt, ...) +{ + va_list args; + + cli(); + printf("Kernel panic!\n"); + va_start(args, fmt); + printf(fmt, args); + va_end(args); + hlt(); +} diff --git a/kern/timer.c b/kern/timer.c @@ -0,0 +1,26 @@ +#include <sys/libk.h> +#include <sys/idt.h> +#include <sys/port.h> + +static void timer_callback(struct reg *); + +static uint32_t timer_ticks = 0; + +static void +timer_callback(struct reg *r) +{ + timer_ticks++; + + UNUSED(r); +} + +void +timer_init(uint32_t hz) +{ + uint32_t div = 1193180 / hz; + + int_add_handler(0, timer_callback); + outb(P_TIMER_CMD, 0x36); + outb(P_TIMER_DATA, (uint8_t)(div & 0xff)); + outb(P_TIMER_DATA, (uint8_t)((div >> 8) & 0xff)); +} diff --git a/kern/tty.c b/kern/tty.c @@ -0,0 +1,139 @@ +#include <sys/libk.h> +#include <sys/io.h> +#include <sys/port.h> +#include <sys/tty.h> + +#define VGA_MEM 0xb8000; +#define VGA_COLS 80 +#define VGA_ROWS 25 +#define TTY_PUTC(c) (((uint16_t)tty.color << 8) | (c)) + +struct tty_info { + volatile uint16_t *buf; + size_t row; + size_t col; + uint8_t color; +}; + +static struct tty_info tty; + +void +tty_clear(uint8_t fg, uint8_t bg) +{ + size_t y, x; + + tty_curs_enable(0x0e, 0x0f); /* Low cursor shape. */ + tty_curs_setpos(0, 0); + tty.row = 0; + tty.col = 0; + tty.buf = (uint16_t *)VGA_MEM; + tty_set_color(fg, bg); + for (x = 0; x < VGA_COLS; x++) + for (y = 0; y < VGA_ROWS; y++) + tty.buf[y * VGA_COLS + x] = TTY_PUTC(' '); +} + +void +tty_set_color(uint8_t fg, uint8_t bg) +{ + tty.color = fg | (bg << 4); +} + +void +tty_putc(char c) +{ + switch (c) { + case '\n': + tty.row++; + tty.col = 0; + break; + case '\b': + tty.col--; + tty.buf[tty.row * VGA_COLS + tty.col] = TTY_PUTC(' '); + break; + case '\r': + tty.col = 0; + break; + case '\t': + tty.col += 8; + break; + default: + tty.buf[tty.row * VGA_COLS + tty.col] = TTY_PUTC(c); + tty.col++; + } + + if (tty.row >= VGA_ROWS) { + tty.row = 0; + tty.col = 0; + } + if (tty.col >= VGA_COLS) { + tty.row++; + tty.col = 0; + } + tty_curs_setpos(tty.col, tty.row); +} + +void +tty_write(const char *str) +{ + while (*str != '\0') + tty_putc(*str++); +} + +/* + * The arguments `start` and `end` define the shape of the cursor. + * The lowest scaline value is 0x00 and the highest 0x0f. A cursor shape + * with `start = 0x00` and `end = 0x0f` is effectively a block cursor. + */ +void +tty_curs_enable(uint8_t start, uint8_t end) +{ + /* 0x0a: Low cursor shape */ + outb(P_CURS_CMD, 0x0a); + outb(P_CURS_DATA, (inb(P_CURS_DATA) & 0xc0) | start); + outb(P_CURS_CMD, 0x0b); + outb(P_CURS_DATA, (inb(P_CURS_DATA) & 0xe0) | end); +} + +void +tty_curs_disable(void) +{ + outb(P_CURS_CMD, 0x0a); + /* + * Bit representation: + * 7 6 | 5 | 4 0 + * Unused | Disable | Shape + */ + outb(P_CURS_DATA, 0x20); +} + +/* + * Returns the position in `y * VGA_COLS + x` format. + * x = pos % VGA_COLS + * y = pos / VGA_COLS + */ +uint16_t +tty_curs_getpos(void) +{ + uint16_t pos = 0; + + outb(P_CURS_CMD, 0x0e); + pos |= (uint16_t)inb(P_CURS_DATA) << 8; + outb(P_CURS_CMD, 0x0f); + pos |= inb(P_CURS_DATA); + + return (pos); +} + +void +tty_curs_setpos(int x, int y) +{ + uint16_t pos = y * VGA_COLS + x; + + /* Expect 8 highest bits */ + outb(P_CURS_CMD, 0x0e); + outb(P_CURS_DATA, (uint8_t)((pos >> 8) & 0xff)); + /* Expect 8 lowest bits */ + outb(P_CURS_CMD, 0x0f); + outb(P_CURS_DATA, (uint8_t)(pos & 0xff)); +} diff --git a/boot/unused/lm.asm b/kern/unused/lm.asm