Implemented custom font and text drawing in VBE graphics mode! No colors :(

This commit is contained in:
2024-04-19 13:23:55 +02:00
parent 5d517b1654
commit 12c0fafa1f
10 changed files with 1822 additions and 190 deletions
+3 -1
View File
@@ -14,10 +14,12 @@ BUILD = ./build
# Main compilation target # Main compilation target
os: $(BUILD) bootloader kernel os: $(BUILD) bootloader kernel
@$(AS) -fbin -o $(BUILD)/filetable.bin $(SRC)/filetable.asm @$(AS) -fbin -o $(BUILD)/filetable.bin $(SRC)/filetable.asm
@$(AS) -fbin -o $(BUILD)/testfont.bin $(SRC)/testfont.asm
@cat $(BUILD)/boot.bin $(BUILD)/filetable.bin $(BUILD)/kernel.bin > $(BUILD)/os.bin @cat $(BUILD)/boot.bin $(BUILD)/filetable.bin $(BUILD)/kernel.bin > $(BUILD)/os.bin
@dd if=/dev/zero of=kern.iso bs=512 count=2880 @dd if=/dev/zero of=kern.iso bs=512 count=2880
@dd if=$(BUILD)/os.bin of=kern.iso conv=notrunc @dd if=$(BUILD)/os.bin of=kern.iso conv=notrunc
@dd if=$(SRC)/fs/test.txt of=kern.iso bs=512 seek=25 conv=notrunc @dd if=$(BUILD)/testfont.bin of=kern.iso bs=512 seek=25 conv=notrunc
@dd if=$(SRC)/fs/test.txt of=kern.iso bs=512 seek=29 conv=notrunc
$(BUILD): $(BUILD):
@[ -d $(BUILD) ] || mkdir $(BUILD) @[ -d $(BUILD) ] || mkdir $(BUILD)
+2
View File
@@ -14,6 +14,8 @@ Since there's always more to do, here are the [todos](todo.txt).
- Filesystem (filetable) - Filesystem (filetable)
- Interactive Shell - Interactive Shell
- Disk I/O - Disk I/O
- Font support (funky format)
- 1920x1080 Resolution, 32bpp
## Building & Running ## Building & Running
If you want to try kern for some reason, you can. If you want to try kern for some reason, you can.
+3 -3
View File
@@ -113,11 +113,11 @@ void setupIsrs() {
void faultHandler(struct regs* r) { void faultHandler(struct regs* r) {
if (r->intNo < 32) { if (r->intNo < 32) {
print(exceptionMessages[r->intNo], 0x04); print(exceptionMessages[r->intNo]);
if (r->errCode) { if (r->errCode) {
print(": 0x", 0x04); print(": 0x");
print(itoa(r->errCode, 16), 0x04); print(itoa(r->errCode, 16));
} }
cli(); cli();
+3 -5
View File
@@ -49,7 +49,6 @@ uint8_t shift = 0;
uint16_t bufferLen = 0; uint16_t bufferLen = 0;
char buffer[MAX_BUFFER_SIZE + 1] = { 0 }; char buffer[MAX_BUFFER_SIZE + 1] = { 0 };
bool echo = false; bool echo = false;
uint8_t echoAttr = 0x0f;
bool canBackspace = false; bool canBackspace = false;
void keyboardHandler() { void keyboardHandler() {
@@ -64,7 +63,7 @@ void keyboardHandler() {
if (scancode & 0x80) { // Keyup if (scancode & 0x80) { // Keyup
} else if (c != 0) { } else if (c != 0) {
if (!canBackspace && c == '\b') return; if (!canBackspace && c == '\b') return;
if (echo) putc(c, echoAttr); if (echo) putc(c);
buffer[bufferLen] = c; buffer[bufferLen] = c;
@@ -76,10 +75,9 @@ void keyboardHandler() {
} }
} }
char* read(char terminator, uint8_t attr) { char* read(char terminator) {
bufferLen = 0; bufferLen = 0;
echo = attr ? true : false; echo = true;
echoAttr = attr;
while (buffer[bufferLen-1] != terminator && bufferLen < MAX_BUFFER_SIZE); while (buffer[bufferLen-1] != terminator && bufferLen < MAX_BUFFER_SIZE);
+48 -112
View File
@@ -1,138 +1,74 @@
#ifndef SCREEN_H #ifndef SCREEN_H
#define SCREEN_H #define SCREEN_H
#include "screen.h"
#include "stdint.h" #include "stdint.h"
#include "system.h"
#include "string.h"
#define VIDMEM 0xb8000 #define MODE_INFO_BLOCK 0x5000
#define CURSOR_HIGH 14 #define WIDTH 1920
#define CURSOR_LOW 15 #define HEIGHT 1080
#define CTRLREG 0x3d4 #define BG_COLOR 0xff1f2937
#define DATAREG 0x3d5 #define FG_COLOR 0xffd1d5db
// 80x25 VGA Text mode struct cursor_s {
#define ROWS 25 uint32_t x;
#define COLS 80 uint32_t y;
#define CHARS (ROWS*COLS) };
uint32_t cursor = 0; char* font;
uint32_t* vidmem;
uint16_t bytesPerScanline;
void updateCursor() { struct cursor_s cursor = { 0, 0 };
// Move visual cursor position
outb(0x3d4, 0x0f); // Low byte void setupScreen() {
outb(0x3d5, cursor & 0xff); vidmem = *(uint32_t**)(MODE_INFO_BLOCK + 40); // Vidmem pointer location
outb(0x3d4, 0x0e); // High byte bytesPerScanline = *(uint16_t*)(MODE_INFO_BLOCK + 16); // Bytes per scanline location
outb(0x3d5, cursor >> 8);
} }
void setCursorPos(uint32_t offset) { void putcAt(char c, uint32_t x, uint32_t y) {
cursor = offset; uint32_t offset = WIDTH * y * 16 + x * 8;
updateCursor();
char* bitmap = &font[(c-1) * 16];
for (uint8_t i = 0; i < 16; i++) { // Rows
char bitmapRow = bitmap[i];
for (uint8_t j = 0; j < 8; j++) { // Cols
vidmem[offset + j] = (bitmapRow & 0x80) ? FG_COLOR : BG_COLOR;
bitmapRow = bitmapRow << 1;
}
offset += WIDTH;
}
} }
uint32_t getCursorPos() { void putc(char c) {
return cursor; putcAt(c, cursor.x, cursor.y);
}
uint32_t calcOffset(uint8_t col, uint8_t row) {
return row * COLS + col;
}
void scroll() {
if (cursor < COLS * ROWS) return;
for (int i = 1; i < ROWS; i++) {
memcopy((char*)(calcOffset(0, i)*2)+VIDMEM, (char*)(calcOffset(0, i-1)*2)+VIDMEM, COLS*2);
}
char* lastRow = (char*)(calcOffset(0, ROWS-1)*2)+VIDMEM;
for (int i = 0; i < COLS*2; i += 2) {
lastRow[i] = '\0';
lastRow[i+1] = 0x0f;
}
cursor = calcOffset(0, ROWS-1);
}
void putc(char c, uint8_t attr) {
if (c == '\n') { if (c == '\n') {
uint16_t line = cursor - (cursor % COLS); cursor.y++;
setCursorPos(line + COLS); cursor.x = 0;
scroll(); } else {
updateCursor(); cursor.x++;
return;
} else if (c == '\b') {
cursor--;
int mem = VIDMEM + cursor * 2;
*(char*)(mem) = ' ';
*(char*)(mem+1) = attr;
updateCursor();
return;
}
int mem = VIDMEM + cursor * 2;
*(char*)(mem) = c;
*(char*)(mem+1) = attr;
cursor++;
scroll();
updateCursor();
}
void print(char* s, uint8_t attr) {
char c = *s;
while (c != '\0') {
putc(c, attr);
c = *(++s);
}
scroll();
updateCursor();
}
void putcAt(char c, uint8_t attr, uint8_t col, uint8_t row) {
uint16_t offset = calcOffset(col, row);
*(char*)(VIDMEM + offset * 2) = c;
*(char*)(VIDMEM + offset * 2 + 1) = attr;
}
void printAt(char* s, uint8_t attr, uint8_t col, uint8_t row) {
uint16_t offset = calcOffset(col, row);
char c = *s;
while (c != '\0') {
*(char*)(VIDMEM + offset * 2) = c;
*(char*)(VIDMEM + offset * 2 + 1) = attr;
c = *(++s);
offset++;
} }
} }
void clear(uint8_t attr) { void print(const char* str) {
for (int i = 0; i < CHARS*2; i += 2) { while (*str != '\0') {
*(char*)(VIDMEM + i) = ' '; putc(*str++);
*(char*)(VIDMEM + i + 1) = attr;
} }
cursor = 0;
updateCursor();
} }
void enableCursor(uint8_t start, uint8_t end) { void clear() {
outb(0x3d4, 0x0a); // Sending cursor start size_t i = 0;
outb(0x3d5, (inb(0x3d5) & 0xc0) | start); while (i < WIDTH*HEIGHT) {
vidmem[i] = BG_COLOR; // #1f2937
outb(0x3d4, 0x0b); // Sending cursor end i++;
outb(0x3d5, (inb(0x3d5) & 0xe0) | end);
} }
void disableCursor() { cursor.x = 0;
outb(0x3d4, 0x0a); cursor.y = 0;
outb(0x3d4, 0x0b);
} }
void loadFont(char* address) {
font = address;
}
#endif #endif
+2 -1
View File
@@ -13,7 +13,8 @@ filetable:
db "boot",0,0,0,0,0,0, "bin",0,0,4 db "boot",0,0,0,0,0,0, "bin",0,0,4
db "filetable",0, "tab",0,4,1 db "filetable",0, "tab",0,4,1
db "kernel",0,0,0,0, "bin",0,5,20 db "kernel",0,0,0,0, "bin",0,5,20
db "test",0,0,0,0,0,0, "txt",0,25,1 db "testfont",0,0, "fnt",0,25,4
db "test",0,0,0,0,0,0, "txt",0,29,1
times 512-($-$$) db 0 times 512-($-$$) db 0
+66 -59
View File
@@ -10,7 +10,8 @@
#define PROMPT "#> " #define PROMPT "#> "
char filetable[512]; // TODO: Put this at a set address
char filetable[512] = { 0 };
void main() { void main() {
// Interrupts // Interrupts
@@ -22,18 +23,22 @@ void main() {
setupKeyboard(); setupKeyboard();
setupTimer(); setupTimer();
timerPhase(100); // 1 tick per 10ms timerPhase(100); // 1 tick per 10ms
enableCursor(14, 15);
clear(0x0f); // Screen setup
print("kern.\n\n", 0x0f); diskRead(25, 4, (char*)0x6000); // Read font from disk
setupScreen();
loadFont((char*)0x6000);
clear();
print("kern.\n\n");
diskRead(4, 1, filetable); // Read the filetable and store it in memory diskRead(4, 1, filetable); // Read the filetable and store it in memory
// Run Interactive Shell Program // Run Interactive Shell Program
// TODO: Make it in another file // TODO: Make it in another file
while (1) { while (1) {
print(PROMPT, 0x0a); print(PROMPT);
char* input = read('\n', 0x0f); char* input = read('\n');
if (input[0] == '\n') continue; if (input[0] == '\n') continue;
@@ -45,14 +50,14 @@ void main() {
*args++ = '\0'; // Separate command from args *args++ = '\0'; // Separate command from args
if (strcmp(input, "clear") == 0) { if (strcmp(input, "clear") == 0) {
clear(0x0f); clear();
} else if (strcmp(input, "disk") == 0) { } else if (strcmp(input, "disk") == 0) {
char buf[512] = { 0 }; char buf[512] = { 0 };
if (*args == '\0') { if (*args == '\0') {
print("disk: ", 0x0f); print("disk: ");
print("No arguments given\n", 0x0c); print("No arguments given\n");
print("Usage: disk <r/w> <sector> [data]\n", 0x0f); print("Usage: disk <r/w> <sector> [data]\n");
continue; continue;
} }
@@ -62,30 +67,30 @@ void main() {
if (mode == 'r') { if (mode == 'r') {
if (*args == '\0') { if (*args == '\0') {
print("disk: ", 0x0f); print("disk: ");
print("Sector not specified\n", 0x0c); print("Sector not specified\n");
print("Usage: disk <r/w> <sector> [data]\n", 0x0f); print("Usage: disk <r/w> <sector> [data]\n");
continue; continue;
} }
uint32_t sector = atoi(args); uint32_t sector = atoi(args);
print("Reading...\n", 0x0f); print("Reading...\n");
diskRead(sector, 1, buf); diskRead(sector, 1, buf);
print("Contents:\n", 0x0f); print("Contents:\n");
for (size_t i = 0; i < 512; i++) { for (size_t i = 0; i < 512; i++) {
if (buf[i] != '\0') { if (buf[i] != '\0') {
putc(buf[i], 0x0f); putc(buf[i]);
} }
} }
putc('\n', 0x0f); putc('\n');
} else if (mode == 'w') { } else if (mode == 'w') {
char* data; char* data;
if ((data = strchr(args, ' ')) == NULL) { if ((data = strchr(args, ' ')) == NULL) {
print("disk: ", 0x0f); print("disk: ");
print("No data given\n", 0x0c); print("No data given\n");
print("Usage: disk <r/w> <sector> [data]\n", 0x0f); print("Usage: disk <r/w> <sector> [data]\n");
continue; continue;
} }
@@ -95,28 +100,28 @@ void main() {
while (isSpace(*args)) { args++; } // Skip whitespace while (isSpace(*args)) { args++; } // Skip whitespace
strcpy(buf, data); strcpy(buf, data);
print("Writing...\n", 0x0f); print("Writing...\n");
diskWrite(sector, 1, buf); diskWrite(sector, 1, buf);
} else { } else {
print("disk: ", 0x0f); print("disk: ");
print("Invalid access mode. Use r(ead) or w(rite)\n", 0x0c); print("Invalid access mode. Use r(ead) or w(rite)\n");
print("Usage: disk <r/w> <sector> [data]\n", 0x0f); print("Usage: disk <r/w> <sector> [data]\n");
continue; continue;
} }
} else if (strcmp(input, "echo") == 0) { } else if (strcmp(input, "echo") == 0) {
print(args, 0x0f); print(args);
} else if (strcmp(input, "exit") == 0) { } else if (strcmp(input, "exit") == 0) {
break; break;
} else if (strcmp(input, "help") == 0) { } else if (strcmp(input, "help") == 0) {
print("Available Commands:\n", 0x0f); print("Available Commands:\n");
print(" clear | Clears the screen\n", 0x0f); print(" clear | Clears the screen\n");
print(" disk | Reads/Writes data from/to the disk\n", 0x0f); print(" disk | Reads/Writes data from/to the disk\n");
print(" echo | Prints a message to stdout\n", 0x0f); print(" echo | Prints a message to stdout\n");
print(" exit | Exits shell\n", 0x0f); print(" exit | Exits shell\n");
print(" help | Prints this message\n", 0x0f); print(" help | Prints this message\n");
print(" ls | Lists all available files\n", 0x0f); print(" ls | Lists all available files\n");
// TODO: print(" reboot | Reboots the system\n", 0x0f); print(" reboot | Reboots the system\n");
print(" test | Performs tests\n", 0x0f); print(" test | Performs tests\n");
} else if (strcmp(input, "ls") == 0) { } else if (strcmp(input, "ls") == 0) {
char* ft = filetable; char* ft = filetable;
@@ -136,47 +141,49 @@ void main() {
uint8_t sector = *ft++; uint8_t sector = *ft++;
uint8_t size = *ft++; uint8_t size = *ft++;
if (sector < 10) putc('0', 0x0f); if (sector < 10) putc('0');
if (sector == 0) putc('0', 0x0f); if (sector == 0) putc('0');
else print(itoa(sector, 10), 0x0f); else print(itoa(sector, 10));
print(": ", 0x0f); print(": ");
print(filename, 0x0f); print(filename);
for (uint8_t i = 14 - strlen(filename); i > 0; i--) { for (uint8_t i = 14 - strlen(filename); i > 0; i--) {
putc(' ', 0x0f); putc(' ');
} }
print(" | ", 0x0f); print(" | ");
if (size >> 1) { if (size >> 1) {
print(itoa(size >> 1, 10), 0x0f); print(itoa(size >> 1, 10));
if (size & 0x01) { print(".5", 0x0f); } if (size & 0x01) { print(".5"); }
print("kB\n", 0x0f); print("kB\n");
} else { } else {
print(itoa(size*512, 10), 0x0f); print(itoa(size*512, 10));
print("B\n", 0x0f); print("B\n");
} }
} }
} else if (strcmp(input, "reboot") == 0) {
outb(0x64, 0xFE);
} else if (strcmp(input, "test") == 0) { } else if (strcmp(input, "test") == 0) {
print("Running Tests...\n", 0x0f); print("Running Tests...\n");
uint8_t buf[512]; uint8_t buf[512];
print("Read Test .......... ", 0x0f); print("Read Test .......... ");
diskRead(0, 1, (char*)buf); diskRead(0, 1, (char*)buf);
if (buf[510] == 0x55 && buf[511] == 0xaa) { if (buf[510] == 0x55 && buf[511] == 0xaa) {
print("[ DONE ]\n", 0x0a); print("[ DONE ]\n");
} else { } else {
print("[ FAIL ]\n", 0x0c); print("[ FAIL ]\n");
} }
print("Write Test ......... ", 0x0f); print("Write Test ......... ");
buf[510] = 0x55; buf[511] = 0xaa; buf[510] = 0x55; buf[511] = 0xaa;
diskWrite(0, 1, (char*)buf); diskWrite(0, 1, (char*)buf);
diskRead(0, 1, (char*)buf); // Idk how else to test if the right data was written (also could break the bootloader if it fails) diskRead(0, 1, (char*)buf); // Idk how else to test if the right data was written (also could break the bootloader if it fails)
if (buf[510] == 0x55 && buf[511] == 0xaa) { if (buf[510] == 0x55 && buf[511] == 0xaa) {
print("[ DONE ]\n", 0x0a); print("[ DONE ]\n");
} else { } else {
print("[ FAIL ]\n", 0x0c); print("[ FAIL ]\n");
} }
print("Tests Finished!\n", 0x0f); print("Tests Finished!\n");
} else { } else {
char* ft = filetable; char* ft = filetable;
uint8_t found = 0; uint8_t found = 0;
@@ -203,10 +210,10 @@ void main() {
for (size_t i = 0; i < size * 512; i++) { for (size_t i = 0; i < size * 512; i++) {
if (buf[i] != '\0') { if (buf[i] != '\0') {
putc(buf[i], 0x0f); putc(buf[i]);
} }
} }
putc('\n', 0x0f); putc('\n');
found++; // Set found to 1 found++; // Set found to 1
break; break;
@@ -216,9 +223,9 @@ void main() {
} }
if (!found) { if (!found) {
print("Command not found: ", 0x0c); print("Command not found: ");
print(input, 0x0c); print(input);
putc('\n', 0x0f); putc('\n');
} }
} }
} }
+42 -4
View File
@@ -85,6 +85,17 @@ start:
cmp al, [modeInfoBlock.bpp] cmp al, [modeInfoBlock.bpp]
jne .nextMode jne .nextMode
mov ax, [vbeInfoBlock.videoModePtr]
ror ax, 8
call printHex
ror ax, 8
call printHex
mov ax, [vbeInfoBlock.videoModePtr+2]
ror ax, 8
call printHex
ror ax, 8
call printHex
; Set VBE mode ; Set VBE mode
mov ax, 0x4f02 mov ax, 0x4f02
mov bx, [mode] mov bx, [mode]
@@ -104,14 +115,14 @@ start:
jmp .findMode jmp .findMode
.endOfModes: .endOfModes:
mov ax, 0x0e4e ; Print 'N' mov si, modeNotFoundErr
int 0x10 call print
cli cli
hlt hlt
error: error:
mov ax, 0x0e46 ; Print 'F' mov si, vbeErr
int 0x10 call print
cli cli
hlt hlt
@@ -157,6 +168,23 @@ printHex:
pop ax pop ax
ret ret
;;
;; Prints a null terminated string
;; si - pointer to string
;;
print:
push ax
mov ah, 0x0e
.loop:
lodsb ; mov al, [si] inc si
cmp al, 0
je .done
int 0x10
jmp .loop
.done:
pop ax
ret
;; 32 Bit entry code ;; 32 Bit entry code
[bits 32] [bits 32]
protected_start: protected_start:
@@ -172,6 +200,13 @@ protected_start:
mov ebp, 0x90000 mov ebp, 0x90000
mov esp, ebp mov esp, ebp
; Store VBE Mode Info Block in memory
mov esi, modeInfoBlock
mov edi, 0x5000 ; Destination
mov ecx, 64 ; 64 * 4 = 256B (size of modeInfoBlock)
rep movsd
; Perform The far jump ; Perform The far jump
mov al, [driveNum] mov al, [driveNum]
push ax push ax
@@ -181,6 +216,9 @@ protected_start:
;; Data ;; Data
driveNum: db 0 driveNum: db 0
vbeErr: db "VBE Error!", 0
modeNotFoundErr: db "VBE Mode not found!", 0
;; GDT ;; GDT
GDT: GDT:
.start: .start:
+1645
View File
File diff suppressed because it is too large Load Diff
+7 -4
View File
@@ -1,13 +1,17 @@
=== Todo === === Todo ===
- [*] Multistage Bootloader - [*] Multistage Bootloader
- [ ] Write down where stuff is in memory (0x1000 - kernel, 0x2000 - filetable, 0x5000 - VBE Mode Info, 0x6000 - Font)
- [ ] Screen - [ ] Screen
- [*] Scrolling - [ ] Scrolling
- [ ] Scroll-back - [ ] Scroll-back
- [ ] Color codes (and just multicolor text in general)
- [*] VESA BIOS Extensions - [*] VESA BIOS Extensions
- [*] Better resolution - [*] Better resolution
- [*] Graphics mode - [*] Graphics mode
- [ ] Custom font - [*] Custom font
- [ ] Larger text size
- [ ] color codes
- [ ] Filesystem - [ ] Filesystem
- [ ] Utility for filesystem building (not just an assembly file) - [ ] Utility for filesystem building (not just an assembly file)
- [*] Filetable - [*] Filetable
@@ -40,14 +44,13 @@
- [ ] touch (make file) - [ ] touch (make file)
- [ ] rm - [ ] rm
- [ ] mkdir (add dirs first) - [ ] mkdir (add dirs first)
- [ ] reboot - [*] reboot
- [ ] cd - [ ] cd
- [ ] Standard I/O stuff - [ ] Standard I/O stuff
- [ ] stdin - [ ] stdin
- [ ] stdout - [ ] stdout
- [ ] stderr - [ ] stderr
- [ ] printf - [ ] printf
- [ ] color codes
- [ ] Virtual Memory - [ ] Virtual Memory
- [ ] Paging - [ ] Paging
- [ ] User (or system) programs - [ ] User (or system) programs