very basic vga, ata, serial drivers. start of fat and fs drivers

This commit is contained in:
Benji Dial 2020-05-24 11:02:43 -04:00
parent 31d8ae388a
commit 02f14113cb
21 changed files with 633 additions and 65 deletions

View file

@ -1,4 +1,8 @@
0x0001.0000 - 0x0002.ffff: unused 0x0001.0000 - 0x0002.5fff: unused
0x0002.6000 - 0x0002.bfff: fat
0x0002.c000 - 0x0002.ffff: file buffers
0x0003.0000 - 0x0003.7fff: kernel 0x0003.0000 - 0x0003.7fff: kernel
0x0003.8000 - 0x0003.ffff: stack 0x0003.8000 - 0x0003.ffff: stack
0x0004.0000 - 0x0007.ffff: unused 0x0004.0000 - 0x0007.ffff: unused
0x0008.0000 - 0x000d.9fff: ramd
0x000d.a000 - 0xffff.ffff: unused

View file

@ -1,20 +1,32 @@
qemu: floppy disk: kernel boot
qemu-system-i386 out/floppy.img
floppy: kernel boot
mkdir -p obj out mkdir -p obj out
/sbin/mkfs.fat -C -R 17 -n "PORTLAND OS" obj/shadow.img 1440 /sbin/mkfs.fat -C -f 1 -F 12 -n "PORTLAND OS" -R 17 obj/shadow.img 8192
echo -n -e '\xeb\x3c' > obj/jmp.bin echo -n -e '\xeb\x3c' > obj/jmp.bin
dd if=obj/jmp.bin of=obj/shadow.img obs=2 conv=notrunc dd if=obj/jmp.bin of=obj/shadow.img obs=2 conv=notrunc
dd if=out/boot.bin of=obj/shadow.img obs=1 seek=62 conv=notrunc dd if=out/boot.bin of=obj/shadow.img obs=1 seek=62 conv=notrunc
dd if=out/kernel.bin of=obj/shadow.img seek=1 conv=notrunc dd if=out/kernel.bin of=obj/shadow.img seek=1 conv=notrunc
mv obj/shadow.img out/floppy.img mv obj/shadow.img out/disk.img
vbox-image: disk
VBoxManage convertfromraw out/disk.img out/disk.vdi --uuid a61929ed-3bf2-45ff-b98a-44f87c616dba
kdump: kernel
objdump -M intel -d obj/kernel.elf > out/kernel.dasm
kgccargs = -m32 -ffreestanding -fno-asynchronous-unwind-tables
kernel: kernel:
mkdir -p obj/kernel out mkdir -p obj/kernel out
gcc -m32 -ffreestanding -c src/kernel/main.c -o obj/kernel/main.o gcc ${kgccargs} -c src/kernel/main.c -o obj/kernel/main.o
gcc -m32 -ffreestanding -c src/kernel/vga.c -o obj/kernel/vga.o gcc ${kgccargs} -c src/kernel/vga.c -o obj/kernel/vga.o
ld -T src/kernel/link.ld obj/kernel/main.o obj/kernel/vga.o -o out/kernel.bin gcc ${kgccargs} -c src/kernel/fat.c -o obj/kernel/fat.o
gcc ${kgccargs} -c src/kernel/fs.c -o obj/kernel/fs.o
gcc ${kgccargs} -c src/kernel/ata.c -o obj/kernel/ata.o
gcc ${kgccargs} -c src/kernel/util.c -o obj/kernel/utilc.o
gcc ${kgccargs} -c src/kernel/panic.c -o obj/kernel/panic.o
gcc ${kgccargs} -c src/kernel/serial.c -o obj/kernel/serial.o
nasm -f elf32 src/kernel/util.asm -o obj/kernel/utila.o
ld -T src/kernel/link.ld obj/kernel/main.o obj/kernel/vga.o obj/kernel/fat.o obj/kernel/fs.o obj/kernel/ata.o obj/kernel/utilc.o obj/kernel/panic.o obj/kernel/utila.o obj/kernel/serial.o -o obj/kernel.elf
objcopy -O binary -j .entry -j .bin obj/kernel.elf out/kernel.bin
boot: boot:
mkdir -p out mkdir -p out

View file

@ -41,9 +41,14 @@ pmode:
mov ds, ax mov ds, ax
mov ax, 0x18 mov ax, 0x18
mov ss, ax mov ss, ax
mov sp, 0x7ffc mov esp, 0x00008000
jmp kernel_segment * 16 xor ebp, ebp
call kernel_segment * 16
halt:
hlt
jmp halt
gdt: gdt:
dw .e - .t dw .e - .t

113
src/kernel/ata.c Normal file
View file

@ -0,0 +1,113 @@
#include <stdint.h>
#include "panic.h"
#include "util.h"
#include "ata.h"
enum {
AP_PRIMARY = 0x01f0,
AP_SECONDARY = 0x0170,
AP_DATA = 0x0,
AP_ERROR = 0x1,
AP_FEAT = 0x1,
AP_COUNT = 0x2,
AP_SEC = 0x3,
AP_CYL_L = 0x4,
AP_CYL_H = 0x5,
AP_HD_DR = 0x6,
AP_LBA0 = 0x3,
AP_LBA1 = 0x4,
AP_LBA2 = 0x5,
AP_L3_DR = 0x6,
AP_STAT = 0x7,
AP_CMD = 0x7,
APC_STAT = 0x0206,
APC_CTRL = 0x0206,
APC_ADDR = 0x0207
};
enum {
ADR_BASE = 0xa0,
ADR_CASCD = 0x10,
ADR_LBA = 0x40
};
enum {
AS_ERROR = 0x01,
AS_INDEX = 0x02,
AS_CORRECT = 0x04,
AS_DREADY = 0x08,
AS_SERVICE = 0x10,
AS_FAULT = 0x20,
AS_READY = 0x40,
AS_BUSY = 0x80
};
enum {
AC_READ = 0x20,
AC_WRITE = 0x30,
AC_FLUSH = 0xe7
};
void ata_ldelay() {
uint16_t i = 65535;
while (i--)
;
}
void ata_sdelay() {
uint8_t i = 255;
while (i--)
;
}
void ata_dpoll() {
uint8_t s;
while ((s = inb(AP_PRIMARY | AP_STAT) & (AS_BUSY | AS_DREADY)) != AS_DREADY)
if (s & (AS_ERROR | AS_FAULT))
panic("ATA controller error or fault.");
}
uint8_t read_sectors(uint16_t start, uint8_t count, void *buffer) {
outb(AP_PRIMARY | AP_L3_DR, ADR_BASE | ADR_LBA);
outb(AP_PRIMARY | AP_LBA2, 0);
outb(AP_PRIMARY | AP_LBA1, start >> 8);
outb(AP_PRIMARY | AP_LBA0, start & 0xff);
outb(AP_PRIMARY | AP_COUNT, count);
outb(AP_PRIMARY | AP_CMD, AC_READ);
uint8_t i = count - 1;
uint16_t *ptr = buffer;
do {
ata_dpoll();
uint8_t j = 255;
do
*(ptr++) = inw(AP_PRIMARY | AP_DATA);
while (j--);
ata_ldelay();
} while (i--);
return count;//TODO: return early if necessary
}
uint8_t write_sectors(uint16_t start, uint8_t count, void *buffer) {
outb(AP_PRIMARY | AP_L3_DR, ADR_BASE | ADR_LBA);
outb(AP_PRIMARY | AP_LBA2, 0);
outb(AP_PRIMARY | AP_LBA1, start >> 8);
outb(AP_PRIMARY | AP_LBA0, start & 0xff);
outb(AP_PRIMARY | AP_COUNT, count);
outb(AP_PRIMARY | AP_CMD, AC_WRITE);
uint8_t i = 0;
uint16_t *ptr = buffer;
do {
ata_dpoll();
uint8_t j = 0;
do {
ata_sdelay();
outw(AP_PRIMARY | AP_DATA, *(ptr++));
}
while (++j);
ata_ldelay();
} while (++i != count);
outb(AP_PRIMARY | AP_CMD, AC_FLUSH);
return count;//TODO: return early if necessary
}

6
src/kernel/ata.h Normal file
View file

@ -0,0 +1,6 @@
#include <stdint.h>
void init_ata();
uint8_t read_sectors(uint16_t start, uint8_t count, void *buffer);
uint8_t write_sectors(uint16_t start, uint8_t count, void *buffer);

21
src/kernel/fat.c Normal file
View file

@ -0,0 +1,21 @@
#include "fat.h"
#include "ata.h"
#include "panic.h"
void load_fat() {
read_sectors(FAT_INFO->reserved_sectors, FAT_INFO->sectors_per_fat, FAT);
}
uint16_t get_cluster(uint16_t n) {
uint32_t t = *(uint32_t *)(FAT + (n / 2) * 3);
return (n % 2 ? (t >> 12) : t) & 0xfff;
}
void set_cluster(uint16_t n, uint16_t v) {
uint32_t *t = (uint32_t *)(FAT + (n / 2) * 3);
*t = (*t & (n % 2 ? 0xff000fff : 0xfffff000)) | (n % 2 ? v << 12 : v);
}
uint16_t get_start_cluster(uint8_t *path) {
panic("Not implemented (get_start_cluster).");
}

View file

@ -4,12 +4,12 @@
struct fat_info { struct fat_info {
uint8_t oem[8]; uint8_t oem[8];
uint16_t bytes_per_sector; uint16_t bytes_per_sector;//Assumed to be 512
uint8_t sectors_per_cluster; uint8_t sectors_per_cluster;//Assumed to be 1
uint16_t reserved_sectors; uint16_t reserved_sectors;
uint8_t fats; uint8_t fats;//Assumed to be 1
uint16_t root_entries; uint16_t root_entries;
uint16_t sectors; uint16_t sectors;//Assumed not to be 0
uint8_t media_type; uint8_t media_type;
uint16_t sectors_per_fat; uint16_t sectors_per_fat;
uint16_t sectors_per_track; uint16_t sectors_per_track;
@ -22,4 +22,11 @@ struct fat_info {
uint32_t volume_id; uint32_t volume_id;
uint8_t label[11]; uint8_t label[11];
uint8_t fs_type[8]; uint8_t fs_type[8];
} __attribute__ ((packed)); } __attribute__ ((packed));
#define FAT ((void *)0x00026000)
void load_fat();
uint16_t get_cluster(uint16_t n);
void set_cluster(uint16_t n, uint16_t v);
uint16_t get_start_cluster(uint8_t *path);

82
src/kernel/fs.c Normal file
View file

@ -0,0 +1,82 @@
#include <stdint.h>
#include "fs.h"
#include "ata.h"
#include "fat.h"
#include <stdbool.h>
#include "panic.h"
#define MAX_HANDLES 32
#define FILE_BUFFER(h) ((void *)(0x0002be00 + (h << 9)))
#define HANDLE(h) ((handles - 1)[h])
#define HEAD(h) (FILE_BUFFER(h) + HANDLE(h).seek % 512)
struct handle_info {
uint16_t start_cluster;
uint16_t seek;
uint16_t loaded_cluster;
bool dirty;
};
struct handle_info handles[MAX_HANDLES];
void clear_fs_handles() {
struct handle_info *f = handles;
while (f < handles + MAX_HANDLES)
(f++)->start_cluster = 0;
}
fs_handle next_handle() {
fs_handle r = 0;
while (HANDLE(++r).start_cluster)
if (r == MAX_HANDLES)
return 0;
return r;
}
void write_buffer(fs_handle handle) {
HANDLE(handle).dirty = false;
panic("Not implemented (write_buffer).");
}
void read_buffer(fs_handle handle) {
if (HANDLE(handle).dirty)
write_buffer(handle);
HANDLE(handle).loaded_cluster = HANDLE(handle).seek >> 9;
panic("Not implemented (read_buffer).");
}
fs_handle fs_open(uint8_t *path) {
fs_handle next = next_handle();
if (!next)
return 0;
uint16_t s = get_start_cluster(path);
if (!s)
return 0;
HANDLE(next).start_cluster = s;
HANDLE(next).seek = 0;
HANDLE(next).dirty = false;
read_buffer(next);
return next;
}
int16_t fs_seek(fs_handle handle, int16_t by) {
uint16_t old = HANDLE(handle).seek;
uint16_t to = -by > old ? 0 : old + by;
HANDLE(handle).seek = to;
if ((to ^ old) & 0xfe00)
read_buffer(handle);
}
uint16_t fs_read(fs_handle handle, uint16_t max, void *buffer) {
panic("Not implemented (fs_read).");
}
uint16_t fs_write(fs_handle handle, uint16_t max, void *buffer) {
panic("Not implemented (fs_write).");
}
void fs_close(fs_handle handle) {
if (HANDLE(handle).dirty)
write_buffer(handle);
HANDLE(handle).start_cluster = 0;
}

10
src/kernel/fs.h Normal file
View file

@ -0,0 +1,10 @@
#include <stdint.h>
void clear_fs_handles();
typedef uint8_t fs_handle;
fs_handle fs_open(uint8_t *path);
int16_t fs_seek(fs_handle handle, int16_t by);
uint16_t fs_read(fs_handle handle, uint16_t max, void *buffer);
uint16_t fs_write(fs_handle handle, uint16_t max, void *buffer);
void fs_close(fs_handle handle);

View file

@ -1,4 +1,4 @@
OUTPUT_FORMAT(binary) OUTPUT_FORMAT(elf32-i386)
OUTPUT_ARCH(i386) OUTPUT_ARCH(i386)
SECTIONS { SECTIONS {
@ -10,6 +10,8 @@ SECTIONS {
*(.text) *(.text)
*(.rodata) *(.rodata)
*(.data) *(.data)
}
/DISCARD/ : {
*(.bss) *(.bss)
} }
} }

View file

@ -1,14 +1,36 @@
#include <stdint.h> #include <stdint.h>
#include "vga.h" #include "vga.h"
#include "fat.h" #include "fat.h"
#include "fs.h"
#include "ata.h"
#include "panic.h"
#include "serial.h"
#include "util.h"
uint8_t nbuf[11];
void main() { void main() {
vga_blank(); vga_blank();
vga_printsz("In kernel-land\n\nDisk label: "); vga_printsz("Initializing drivers...");
sinit();
vga_printsz("\n Serial ready.");
load_fat();
clear_fs_handles();
vga_printsz("\n File system ready.\n\nDisk label: ");
vga_printsn(FAT_INFO->label, 11); vga_printsn(FAT_INFO->label, 11);
vga_printsz("\nDisk size: "); vga_printsz("\nDisk size: ");
vga_printu32((FAT_INFO->sectors * FAT_INFO->bytes_per_sector) >> 10); u32_dec(FAT_INFO->sectors >> 1, nbuf);
vga_printsz("k\n\nHalting..."); vga_printsz(nbuf);
vga_printsz("k\n\nFAT start:\n");
nbuf[3] = 0;
for (uint8_t r = 0; r < 192; r += 24) {
for (uint8_t c = 0; c < 24; ++c) {
u8_hex(*(uint8_t *)(FAT + r + c), nbuf);
nbuf[2] = ' ';
vga_printsz(nbuf);
}
vga_printch('\n');
}
while (1) while (1)
asm ("hlt"); asm ("hlt");
} }

31
src/kernel/panic.c Normal file
View file

@ -0,0 +1,31 @@
#include <stdint.h>
#include "vga.h"
#include "serial.h"
#include "util.h"
void halt() {
while (1)
asm volatile ("hlt");
}
void panic(uint8_t *message) {
uint32_t frame;
asm (
"movl %%ebp, %0"
: "=r" (frame));
vga_set_color(0x4f);
vga_blank();
vga_printsz("Kernel panic: ");
vga_printsz(message);
vga_printsz("\n\nStack trace:");
uint8_t stb[6];
while (1) {
uint32_t ip = *(uint32_t *)(0x38000 + frame + 4);
if (!ip)
halt();
vga_printsz("\n 0x");
u16_hex(ip - 0x30000 - 5, stb);//assumes would return to just after a call instruction
vga_printsz(stb);
frame = *(uint32_t *)(0x38000 + frame);
}
}

4
src/kernel/panic.h Normal file
View file

@ -0,0 +1,4 @@
#include <stdint.h>
void panic(uint8_t *message) __attribute__ ((noreturn));
void halt() __attribute__ ((noreturn));

100
src/kernel/serial.c Normal file
View file

@ -0,0 +1,100 @@
#include <stdint.h>
#include <stdbool.h>
#include "util.h"
enum {
CP_DATA = 0x0,
CP_INT = 0x1,
CP_FIFO = 0x2,
CP_LINE = 0x3,
CP_MODEM = 0x4,
CP_LINE_S = 0x5,
CP_MODEM_S = 0x6,
CP_DIVLOW = 0x0,
CP_DIVHIGH = 0x1,
CP_1 = 0x03f8,
CP_2 = 0x02f8,
CP_3 = 0x03e8,
CP_4 = 0x02e8
};
enum {
CL_BAUD = 0x80,
CL_PODD = 0x08,
CL_PEVEN = 0x0c,
CL_PON = 0x18,
CL_POFF = 0x1c,
CL_LSTOP = 0x4,
CL_5BIT = 0x0,
CL_6BIT = 0x1,
CL_7BIT = 0x2,
CL_8BIT = 0x3
};
enum {
CLS_B_ERR = 0x80,
CLS_IDLE = 0x40,
CLS_WRITE = 0x20,
CLS_BREAK = 0x10,
CLS_FRAME = 0x08,
CLS_PAR = 0x04,
CLS_OVER = 0x02,
CLS_READ = 0x01
};
bool error;
#define SERIAL_SPIN_LIMIT 65535
bool serr() {
return error;
}
void sinit() {
error = false;
outb(CP_1 | CP_INT, 0);
outb(CP_1 | CP_LINE, CL_BAUD);
outb(CP_1 | CP_DIVLOW, 0x03);//38400
outb(CP_1 | CP_DIVHIGH, 0x00);//baud
outb(CP_1 | CP_LINE, CL_8BIT);
outb(CP_1 | CP_FIFO, 0xc7);//?
}
void sout(uint8_t b) {
if (error)
return;
uint16_t s = SERIAL_SPIN_LIMIT;
while (!(inb(CP_1 | CP_LINE_S) & CLS_WRITE))
if (!--s) {
error = true;
return;
}
outb(CP_1 | CP_DATA, b);
}
void soutsz(uint8_t *s) {
while (*s)
sout(*(s++));
}
void soutsn(uint8_t *s, uint8_t n) {
while (n--)
sout(*(s++));
}
uint8_t sin() {
if (error)
return 0;
while (!(inb(CP_1 | CP_LINE_S) & CLS_READ))
;//spin
return inb(CP_1 | CP_DATA);
}
void sinsn(uint8_t *s, uint8_t n) {
while (n--)
*(s++) = sin();
}

10
src/kernel/serial.h Normal file
View file

@ -0,0 +1,10 @@
#include <stdint.h>
#include <stdbool.h>
bool serr();
void sinit();
void sout(uint8_t b);
void soutsz(uint8_t *s);
void soutsn(uint8_t *s, uint8_t n);
uint8_t sin();
void sinsn(uint8_t *s, uint8_t n);

37
src/kernel/util.asm Normal file
View file

@ -0,0 +1,37 @@
bits 32
global outb
global inb
global outw
global inw
section .text
outb:
;word [esp + 4] = port
;byte [esp + 8] = value
mov dx, word [esp + 4]
mov al, byte [esp + 8]
out dx, al
ret
inb:
;word [esp + 4] = port
;al out = value
mov dx, word [esp + 4]
in al, dx
ret
outw:
;word [esp + 4] = port
;word [esp + 8] = value
mov dx, word [esp + 4]
mov ax, word [esp + 8]
out dx, ax
ret
inw:
;word [esp + 4] = port
;ax out = value
mov dx, word [esp + 4]
in ax, dx
ret

100
src/kernel/util.c Normal file
View file

@ -0,0 +1,100 @@
#include <stdint.h>
#include "panic.h"
#include <stdbool.h>
void memcpy(void *from, void *to, uint32_t n) {
panic("Not implemented (memcpy).");
}
void u32_dec(uint32_t n, uint8_t *b) {
if (!n) {
*(uint16_t *)b = '0';
return;
}
bool zero = false;
for (uint32_t m = 1000000000; m; m /= 10) {
uint8_t d = (n / m) % 10;
if (zero)
*(b++) = d + '0';
else if (d) {
zero = true;
*(b++) = d + '0';
}
}
*b = 0;
}
void u16_dec(uint16_t n, uint8_t *b) {
if (!n) {
*(uint16_t *)b = '0';
return;
}
bool zero = false;
for (uint32_t m = 10000; m; m /= 10) {
uint8_t d = (n / m) % 10;
if (zero)
*(b++) = d + '0';
else if (d) {
zero = true;
*(b++) = d + '0';
}
}
*b = 0;
}
void u8_dec(uint8_t n, uint8_t *b) {
if (!n) {
*(uint16_t *)b = '0';
return;
}
bool zero = false;
for (uint32_t m = 100; m; m /= 10) {
uint8_t d = (n / m) % 10;
if (zero)
*(b++) = d + '0';
else if (d) {
zero = true;
*(b++) = d + '0';
}
}
*b = 0;
}
void u32_hex(uint32_t n, uint8_t *b) {
uint8_t m = 28;
while (1) {
uint8_t d = (n >> m) & 0xf;
*(b++) = d >= 10 ? 'a' + d - 10 : '0' + d;
if (!m) {
*b = 0;
return;
}
m -= 4;
}
}
void u16_hex(uint16_t n, uint8_t *b) {
uint8_t m = 12;
while (1) {
uint8_t d = (n >> m) & 0xf;
*(b++) = d >= 10 ? 'a' + d - 10 : '0' + d;
if (!m) {
*b = 0;
return;
}
m -= 4;
}
}
void u8_hex(uint8_t n, uint8_t *b) {
uint8_t m = 4;
while (1) {
uint8_t d = (n >> m) & 0xf;
*(b++) = d >= 10 ? 'a' + d - 10 : '0' + d;
if (!m) {
*b = 0;
return;
}
m -= 4;
}
}

13
src/kernel/util.h Normal file
View file

@ -0,0 +1,13 @@
#include <stdint.h>
void memcpy(void *from, void *to, uint32_t n);
void outb(uint16_t port, uint8_t value);
uint8_t inb(uint16_t port);
void outw(uint16_t port, uint16_t value);
uint16_t inw(uint16_t port);
void u32_dec(uint32_t n, uint8_t *b);
void u16_dec(uint16_t n, uint8_t *b);
void u8_dec(uint8_t n, uint8_t *b);
void u32_hex(uint32_t n, uint8_t *b);
void u16_hex(uint16_t n, uint8_t *b);
void u8_hex(uint8_t n, uint8_t *b);

View file

@ -1,6 +1,12 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#define VGA_COM_MIRROR
#ifdef VGA_COM_MIRROR
#include "serial.h"
#endif
#define VGA_COLUMNS 80 #define VGA_COLUMNS 80
#define VGA_LINES 25 #define VGA_LINES 25
#define VGA_START (uint16_t *)0x000b8000 #define VGA_START (uint16_t *)0x000b8000
@ -8,11 +14,18 @@
uint16_t *cursor = VGA_START; uint16_t *cursor = VGA_START;
uint16_t color = 0x1f00; uint16_t color = 0x1f00;
void vga_set_color(uint8_t new_color) {
color = new_color << 8;
}
void vga_scroll() { void vga_scroll() {
cursor = VGA_START; cursor = VGA_START;
} }
void vga_blank() { void vga_blank() {
#ifdef VGA_COM_MIRROR
soutsz("\r\n\r\n<CLEAR>\r\n\r\n");
#endif
uint32_t f = (color << 16) | color | 0x00200020; uint32_t f = (color << 16) | color | 0x00200020;
uint32_t *p = (uint32_t *)VGA_START; uint32_t *p = (uint32_t *)VGA_START;
while (p < (uint32_t *)VGA_END) while (p < (uint32_t *)VGA_END)
@ -22,10 +35,16 @@ void vga_blank() {
void vga_printch(uint8_t ch) { void vga_printch(uint8_t ch) {
if (ch == '\n') { if (ch == '\n') {
#ifdef VGA_COM_MIRROR
soutsz("\r\n");
#endif
if ((cursor = cursor - (cursor - VGA_START) % VGA_COLUMNS + VGA_COLUMNS) == VGA_END) if ((cursor = cursor - (cursor - VGA_START) % VGA_COLUMNS + VGA_COLUMNS) == VGA_END)
vga_scroll(); vga_scroll();
return; return;
} }
#ifdef VGA_COM_MIRROR
sout(ch);
#endif
*(cursor++) = color | ch; *(cursor++) = color | ch;
if (cursor == VGA_END) if (cursor == VGA_END)
vga_scroll(); vga_scroll();
@ -39,43 +58,4 @@ void vga_printsz(uint8_t *sz) {
void vga_printsn(uint8_t *sn, uint8_t n) { void vga_printsn(uint8_t *sn, uint8_t n) {
while (n--) while (n--)
vga_printch(*(sn++)); vga_printch(*(sn++));
}
void vga_printu32(uint32_t n) {
bool zero = false;
for (uint32_t m = 1000000000; m; m /= 10) {
uint8_t d = (n / m) % 10;
if (zero)
vga_printch(d + '0');
else if (d) {
zero = true;
vga_printch(d + '0');
}
}
}
void vga_printu16(uint16_t n) {
bool zero = false;
for (uint16_t m = 10000; m; m /= 10) {
uint8_t d = (n / m) % 10;
if (zero)
vga_printch(d + '0');
else if (d) {
zero = true;
vga_printch(d + '0');
}
}
}
void vga_printu8(uint8_t n) {
bool zero = false;
for (uint8_t m = 100; m; m /= 10) {
uint8_t d = (n / m) % 10;
if (zero)
vga_printch(d + '0');
else if (d) {
zero = true;
vga_printch(d + '0');
}
}
} }

View file

@ -1,10 +1,8 @@
#include <stdint.h> #include <stdint.h>
void vga_set_color(uint8_t color);
void vga_blank(); void vga_blank();
void vga_scroll(); void vga_scroll();
void vga_printch(uint8_t ch); void vga_printch(uint8_t ch);
void vga_printsz(uint8_t *sz); void vga_printsz(uint8_t *sz);
void vga_printsn(uint8_t *sn, uint8_t n); void vga_printsn(uint8_t *sn, uint8_t n);
void vga_printu32(uint32_t n);
void vga_printu16(uint16_t n);
void vga_printu8(uint8_t n);

11
src/kernel/vga.inc Normal file
View file

@ -0,0 +1,11 @@
extern vga_set_color
extern vga_blank
extern vga_scroll
extern vga_printch
extern vga_printsz
extern vga_printsn
extern vga_printu32
extern vga_printu16
extern vga_printu8
extern vga_printu32h
extern vga_printu8h