Added AMAZING boot menu to KBOOT

This commit is contained in:
2025-01-05 18:20:15 +01:00
parent 707733e449
commit 94ca8c935f
22 changed files with 651 additions and 16 deletions
+4 -3
View File
@@ -11,6 +11,7 @@ jmp short .bpb_end
nop nop
; FAT32 Bios Parameter Block ; FAT32 Bios Parameter Block
; Some BIOSes mess with it so we just leave it blank
.bpb: .bpb:
.bpb_oem_id: db "KERN " .bpb_oem_id: db "KERN "
.bpb_sector_size: dw 0 .bpb_sector_size: dw 0
@@ -115,17 +116,17 @@ err:
[bits 32] [bits 32]
; Protected mode entry vector ; Protected mode entry vector
vector: vector:
mov eax, 0x10 mov ax, 0x10
mov ds, ax mov ds, ax
mov es, ax mov es, ax
mov fs, ax mov fs, ax
mov gs, ax mov gs, ax
mov ss, ax mov ss, ax
and edx, 0xff and edx, 0xff ; Still should be boot drive number
; Call stage 2 bootloader ; Call stage 2 bootloader
call 0x70000 call code_seg:0x70000
; Padding and boot signature ; Padding and boot signature
times 510-($-$$) db 0 times 510-($-$$) db 0
+2 -2
View File
@@ -24,5 +24,5 @@ gdtp:
dd gdt ; Pointer dd gdt ; Pointer
; Segments ; Segments
code_seg equ gdt.code_desc - gdt code_seg: equ gdt.code_desc - gdt
data_seg equ gdt.data_desc - gdt data_seg: equ gdt.data_desc - gdt
+9
View File
@@ -0,0 +1,9 @@
#ifndef ATTR_H
#define ATTR_H
#define __packed __attribute__((packed))
#define __naked __attribute__((naked))
#define __section(_sect) __attribute__((section(_sect)))
#define noreturn __attribute__((noreturn))
#endif
+24
View File
@@ -0,0 +1,24 @@
#include "stdint.h"
#include "port.h"
#include "disk.h"
void readSectors(uint32_t lba, size_t count, void* dst) {
outb(PIO_PORT + 6, ((lba >> 24) & 0x0f) | 0xe0);
outb(PIO_PORT + 2, count);
outb(PIO_PORT + 3, lba & 0xff);
outb(PIO_PORT + 4, (lba >> 8) & 0xff);
outb(PIO_PORT + 5, (lba >> 16) & 0xff);
outb(PIO_PORT + 7, PIO_CMD_READ);
uint16_t* buf = (uint16_t*)dst;
for (size_t i = 0; i < count; i++) {
while (inb(PIO_PORT + 7) & (1 << 7)); // Wait until BSY is cleared
for (size_t j = 0; j < SECTOR_SIZE / 2; j++) *buf++ = inw(PIO_PORT);
for (uint8_t wait = 0; wait < 4; wait++) inb(PIO_ALT_STATUS);
}
}
/* TODO */
void writeSectors(uint32_t lba, size_t count, void* src) {}
+35
View File
@@ -0,0 +1,35 @@
#ifndef DISK_H
#define DISK_H
#include "stdint.h"
#include "attr.h"
#define SECTOR_SIZE 512
#define PIO_PORT 0x1f0
#define PIO_ALT_STATUS 0x3f6
#define PIO_MASTER 0xa0
#define PIO_CMD_READ 0x20
#define PIO_CMD_WRITE 0x30
#define PIO_CMD_FLUSH 0 // TODO
#define BOOTABLE 0x80
struct partition {
uint8_t bootable;
uint8_t startCHS[3];
uint8_t type;
uint8_t endCHS[3];
uint32_t startLBA;
uint32_t size;
} __packed;
struct MBR {
uint8_t bootstrap[446];
struct partition partitions[4];
uint16_t signature;
} __packed;
void readSectors(uint32_t lba, size_t count, void* buffer);
void writeSectors(uint32_t lba, size_t count, void* buffer);
#endif
+96 -1
View File
@@ -1,3 +1,98 @@
void entry() { #include "stdint.h"
#include "stdio.h"
#include "attr.h"
#include "disk.h"
#include "menu.h"
#include "kbd.h"
void drawPartitions(struct MBR* mbr, uint8_t sel);
void partitonInfo(struct partition* part);
__section("entry")
noreturn void main() {
keyboardInit();
struct MBR mbr;
readSectors(0, 1, &mbr);
// Select bootable partition by default
uint8_t selected = 0;
for (size_t i = 0; i < 4; i++) {
if (mbr.partitions[i].bootable != BOOTABLE) continue;
selected = i;
break;
}
// Initial draw
setAttr(0x0f);
cls();
hideCursor();
rect(0, 0, COLS, ROWS);
hline(0, 2, COLS);
setAttr(0x02);
text(COLS / 2, 1, "KBOOT");
drawPartitions(&mbr, selected);
partitonInfo(&mbr.partitions[selected]);
while (1) {
// Check for up/down arrow keys or enter
uint8_t scancode = getScancode();
if (scancode == SC_ENTER) { // Boot selected
if (mbr.partitions[selected].type != 0) break;
// Don't allow booting an unused partition
setAttr(0x4f);
text(COLS / 2, ROWS / 2 + 6, "Unused Partition");
} else if (scancode != SC_EXTENDED) continue; // Not an arrow key
scancode = getScancode();
if (scancode == SCE_ARROW_UP) selected--;
else if (scancode == SCE_ARROW_DOWN) selected++;
else continue;
if (selected == 0xff) selected = 3;
else if (selected == 4) selected = 0;
// Redraw
drawPartitions(&mbr, selected);
partitonInfo(&mbr.partitions[selected]);
}
setAttr(0x0f);
cls();
showCursor();
printf("Booting from Partition %d...", selected);
while (1); while (1);
} }
void drawPartitions(struct MBR* mbr, uint8_t sel) {
uint32_t basey = ROWS / 2 - 2;
for (size_t i = 0; i < 4; i++) {
if (i == sel) setAttr(0xf0);
else if (mbr->partitions[i].type == 0) setAttr(0x04);
else setAttr(0x0f);
text(COLS / 2, basey + i, " [ Partition %d ] ", i+1);
}
}
void partitonInfo(struct partition* part) {
uint32_t basey = ROWS / 2 + 6;
setAttr(0x02);
// Clear previous text
fill(1, basey, COLS - 2, 3, '\0');
if (part->type == 0) {
text(COLS / 2, basey, "Unused Partition");
return;
}
text(COLS / 2, basey, "Type: %02x%s", part->type,
(part->bootable == BOOTABLE) ? " Bootable" : "");
text(COLS / 2, basey + 1, "Start LBA: %d; End LBA: %d",
part->startLBA, part->startLBA + part->size);
text(COLS / 2, basey + 2, "Length: 0x%x", part->size);
}
+12
View File
@@ -0,0 +1,12 @@
#include "stdint.h"
#include "port.h"
#include "kbd.h"
// TODO: Maybe do some setup?
int keyboardInit() { return 0; }
uint8_t getScancode() {
while (inb(PS2_STAT_PORT) & 0x01 == 0);
return inb(PS2_DATA_PORT);
}
+19
View File
@@ -0,0 +1,19 @@
#ifndef _KBD_H
#define _KBD_H
#include "stdint.h"
#define PS2_DATA_PORT 0x60
#define PS2_STAT_PORT 0x64
// Scancodes
#define SC_ENTER 0x1C
#define SC_EXTENDED 0xE0
// Extended scancodes
#define SCE_ARROW_UP 0x48
#define SCE_ARROW_DOWN 0x50
int keyboardInit();
uint8_t getScancode();
#endif
+5 -8
View File
@@ -1,27 +1,24 @@
OUTPUT_FORMAT(binary) OUTPUT_FORMAT(binary)
ENTRY(entry) OUTPUT_ARCH(i386)
SECTIONS { SECTIONS {
/* Will be loaded at 0x70000 */
. = 0x70000; . = 0x70000;
.text : { .text : {
*(entry)
*(.text) *(.text)
*(.text.*) }
.rodata : {
*(.rodata) *(.rodata)
*(.rodata.*)
} }
.data : { .data : {
*(.data) *(.data)
*(.data.*)
} }
.bss : { .bss : {
*(COMMON) *(COMMON)
*(.bss) *(.bss)
*(.bss.*)
} }
_end = .;
} }
+73
View File
@@ -0,0 +1,73 @@
#include "stdarg.h"
#include "stdint.h"
#include "string.h"
#include "stdio.h"
#include "menu.h"
/*
* The reason we subtract one from the width and height (or length) is because
* we use the (in this example) width to offset from the (in this example) x
* position. If something has a width of 1 character, the end of it should be
* at 'x + w', so if 'w' were 1, it would be off by one. Therefore we subtract
* one from the given dimensions.
*/
void rect(uint32_t x, uint32_t y, uint32_t _w, uint32_t _h) {
if (_w < 2 || _h < 2) return;
uint32_t w = _w - 1;
uint32_t h = _h - 1;
// Top
putat(y, x, CORNER_TL);
for (size_t dx = 1; dx < w; dx++) putat(y, x + dx, LINE_H);
putat(y, x + w, CORNER_TR);
// Sides
for (size_t dy = 1; dy < h; dy++) {
putat(y + dy, x, LINE_V);
putat(y + dy, x + w, LINE_V);
}
// Bottom
putat(y + h, x, CORNER_BL);
for (size_t dx = 1; dx < w; dx++) putat(y + h, x + dx, LINE_H);
putat(y + h, x + w, CORNER_BR);
}
void fill(uint32_t x, uint32_t y, uint32_t w, uint32_t h, char c) {
// We don't add one to the dimensions here
for (size_t dy = 0; dy < h; dy++) {
for (size_t dx = 0; dx < w; dx++) {
putat(y + dy, x + dx, c);
}
}
}
void hline(uint32_t x, uint32_t y, uint32_t _len) {
uint32_t len = _len - 1;
putat(y, x, LINE_T_RIGHT);
for (size_t dx = 1; dx < len; dx++) putat(y, x + dx, LINE_H);
putat(y, x + len, LINE_T_LEFT);
}
void vline(uint32_t x, uint32_t y, uint32_t _len) {
uint32_t len = _len - 1;
putat(y, x, LINE_T_DOWN);
for (size_t dy = 1; dy < len; dy++) putat(y + dy, x, LINE_V);
putat(y + len, x, LINE_T_UP);
}
void text(uint32_t x, uint32_t y, char* fmt, ...) {
va_list args;
va_start(args, fmt);
char buf[256];
vsnprintf(buf, 256, fmt, args);
va_end(args);
uint32_t len = strlen(buf);
uint32_t basex = x - len / 2;
size_t i = 0;
while (buf[i] != '\0') putat(y, basex + i, buf[i++]);
}
+33
View File
@@ -0,0 +1,33 @@
#ifndef _MENU_H
#define _MENU_H
// Box drawing characters
#define SHADE_LIGHT 0xB0
#define SHADE_MEDIUM 0xB1
#define SHADE_DARK 0xB2
#define LINE_V 0xB3
#define LINE_T_LEFT 0xB4
#define CORNER_TR 0xBF
#define CORNER_BL 0xC0
#define LINE_T_UP 0xC1
#define LINE_T_DOWN 0xC2
#define LINE_T_RIGHT 0xC3
#define LINE_H 0xC4
#define LINE_CROSS 0xC5
#define CORNER_BR 0xD9
#define CORNER_TL 0xDA
#define BLOCK 0xDB
#define BLOCK_UPPER 0xDC
#define BLOCK_LEFT 0xDD
#define BLOCK_RIGHT 0xDE
#define BLOCK_LOWER 0xDF
#define INT_UPPER 0xF4
#define INT_LOWER 0xF5
void rect(uint32_t x, uint32_t y, uint32_t w, uint32_t h);
void fill(uint32_t x, uint32_t y, uint32_t w, uint32_t h, char c);
void hline(uint32_t x, uint32_t y, uint32_t len);
void vline(uint32_t x, uint32_t y, uint32_t len);
void text(uint32_t x, uint32_t y, char* fmt, ...);
#endif
+33
View File
@@ -0,0 +1,33 @@
#ifndef PORT_H
#define PORT_H
#include "stdint.h"
inline uint8_t inb(uint16_t port) {
uint8_t result;
__asm__ volatile("inb %1, %0" : "=a"(result) : "Nd"(port));
return result;
}
inline void outb(uint16_t port, uint8_t data) {
__asm__ volatile("outb %0, %1" :: "a"(data), "Nd"(port));
}
inline uint16_t inw(uint16_t port) {
uint16_t result;
__asm__ volatile("inw %1, %0" : "=a"(result) : "Nd"(port));
return result;
}
inline void outw(uint16_t port, uint16_t data) {
__asm__ volatile("outw %0, %1" :: "a"(data), "Nd"(port));
}
inline uint32_t inl(uint16_t port) {
uint32_t result;
__asm__ volatile("inl %1, %0" : "=a"(result) : "Nd"(port));
return result;
}
inline void outl(uint16_t port, uint32_t data) {
__asm__ volatile("outl %0, %1" :: "a"(data), "Nd"(port));
}
#endif
+10
View File
@@ -0,0 +1,10 @@
#ifndef _STDARG_H
#define _STDARG_H
typedef char* va_list;
#define va_start(ap, paramn) (void)((ap) = (char*)(&(paramn) + 1))
#define va_end(ap) (void)((ap) = 0)
#define va_arg(ap, type) (((type*)((ap) = ((ap) + sizeof(type))))[-1])
#endif
+22
View File
@@ -0,0 +1,22 @@
#ifndef _STDINT_H
#define _STDINT_H
#define NULL ((void*)0)
// Naitive size
typedef unsigned int size_t;
typedef signed int ssize_t;
// Signed ints
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long long int64_t;
// Unsigned ints
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
#endif
+141
View File
@@ -0,0 +1,141 @@
#include "stdarg.h"
#include "stdint.h"
#include "string.h"
#include "stdio.h"
#include "port.h"
static uint32_t xpos;
static uint32_t ypos;
static uint8_t attr;
void setAttr(uint8_t newattr) {
attr = newattr;
}
void setCursor(uint32_t row, uint32_t col) {
xpos = col;
ypos = row;
updateCursor();
}
void updateCursor() {
uint16_t pos = xpos + ypos * COLS;
outb(0x3d4, 0x0f);
outb(0x3d5, pos & 0xff);
outb(0x3d4, 0x0e);
outb(0x3d5, (pos >> 8) & 0xff);
}
void hideCursor() {
outb(0x3d4, 0x0a);
outb(0x3d5, 0x20);
}
void showCursor() {
uint8_t start = 0;
uint8_t end = 15;
outb(0x3d4, 0x0a);
outb(0x3d5, (inb(0x3d5) & 0xc0) | start);
outb(0x3d4, 0x0b);
outb(0x3d5, (inb(0x3d5) & 0xe0) | end);
}
void cls() {
uint8_t* vidmem = (uint8_t*)VIDMEM;
for (size_t i = 0; i < ROWS * COLS; i++) {
vidmem[i * 2] = 0;
vidmem[i * 2 + 1] = attr;
}
xpos = 0;
ypos = 0;
updateCursor();
}
void putat(uint32_t row, uint32_t col, int c) {
uint8_t* vidmem = (uint8_t*)VIDMEM;
vidmem[(col + row * COLS) * 2] = c & 0xFF;
vidmem[(col + row * COLS) * 2 + 1] = attr;
}
void newline() {
xpos = 0;
ypos++;
if (ypos >= ROWS) ypos = 0;
updateCursor();
}
void putc(int c) {
putat(ypos, xpos, c);
xpos++;
if (xpos >= COLS) newline();
updateCursor();
}
void puts(char* s) {
while (*s != '\0') {
if (*s == '\n' || *s == '\r') {
newline();
s++;
} else putc(*s++);
}
}
int vsnprintf(void* buf, size_t len, char* fmt, va_list args) {
char* str = (char*)buf;
size_t pos = 0;
while (*fmt != '\0') {
if (*fmt != '%') {
if (pos < len - 1) str[pos++] = *fmt++;
continue;
}
fmt++;
char pad = ' ';
int width = 0;
// TODO: padding
if (*fmt == '0') pad = '0';
while (*fmt >= '0' && *fmt <= '9') {
width *= 10;
width += *fmt++ - '0';
}
// DO NOT TALK ABOUT THIS ABOMINATION
char* s;
switch (*fmt++) {
case 'd': s = itoa(va_arg(args, int), 10); goto string;
case 'x': s = itoa(va_arg(args, int), 16); goto string;
case 's': s = va_arg(args, char*);
string: while (*s != '\0' && pos < len - 1) str[pos++] = *s++; break;
case 'c': if (pos < len - 1) str[pos++] = va_arg(args, char); break;
case '%': if (pos < len - 1) str[pos++] = '%'; break;
default:
if (pos < len - 1) str[pos++] = '%';
if (pos < len - 1) str[pos++] = *(fmt - 1);
break;
}
}
if (len > 0) {
if (pos < len) str[pos++] = '\0';
else str[len - 1] = '\0'; // Shouldn't be able to be reached, but who knows
}
return pos;
}
int printf(char* fmt, ...) {
va_list args;
va_start(args, fmt);
char buf[256];
int ret = vsnprintf(buf, 256, fmt, args);
va_end(args);
puts(buf);
return ret;
}
+25
View File
@@ -0,0 +1,25 @@
#ifndef _STDIO_H
#define _STDIO_H
#include "stdarg.h"
#include "stdint.h"
#define VIDMEM 0xb8000
#define COLS 80
#define ROWS 25
void setAttr(uint8_t attr);
void setCursor(uint32_t row, uint32_t col);
void updateCursor();
void hideCursor();
void showCursor();
void cls();
void newline();
void putc(int c);
void puts(char* s);
int printf(char* fmt, ...);
int vsnprintf(void* buf, size_t len, char* fmt, va_list args);
void putat(uint32_t row, uint32_t col, int c);
#endif
+74
View File
@@ -0,0 +1,74 @@
#include "stdint.h"
#include "string.h"
char* itoa(size_t val, int base) {
static char buf[32] = { 0 };
if (base == 0 || base > 16) return NULL;
if (val == 0) {
buf[0] = '0';
buf[1] = '\0';
return buf;
}
int i;
buf[31] = '\0';
for (i = 30; val && i; i--, val /= base) {
buf[i] = "0123456789abcdef"[val % base];
}
return &buf[i + 1];
}
void* memcpy(void* src, void* dst, size_t length) {
uint8_t* p = dst;
size_t i = 0;
while (i < length) p[i] = *(uint8_t*)(src + i);
return dst;
}
void* memset(void* dst, uint8_t val, size_t length) {
uint8_t* p = dst;
size_t i = 0;
while (i < length) p[i++] = val;
return dst;
}
char* strcpy(char* str1, const char* str2) {
char* p = str1;
while (*str2 != '\0') *p++ = *str2++;
return str1;
}
char* strcat(char* str1, const char* str2) {
char* p = str1;
while (*str2++ != '\0');
while (*str2 != '\0') *p++ = *str2++;
return str1;
}
char* strchr(const char* str, char c) {
char* p = (char*)str;
while (*p != '\0' && *p != c) p++;
return (*p == c) ? p : NULL;
}
int strcmp(const char* str1, const char* str2) {
while (*str1 != '\0' && *str1 == *str2) {
str1++;
str2++;
}
uint8_t c1 = (*(uint8_t*)str1);
uint8_t c2 = (*(uint8_t*)str2);
return ((c1 < c2) ? -1 : (c1 > c2));
}
size_t strlen(const char* str) {
size_t len = 0;
while (str[len++] != '\0');
return len;
}
+15
View File
@@ -0,0 +1,15 @@
#ifndef _STRING_H
#define _STRING_H
#include "stdint.h"
char* itoa(size_t val, int base);
void* memcpy(void* src, void* dst, size_t length);
void* memset(void* dst, uint8_t value, size_t length);
char* strcpy(char* str1, const char* str2);
char* strcat(char* str1, const char* str2);
char* strchr(const char* str, char c);
int strcmp(const char* str1, const char* str2);
size_t strlen(const char* str);
#endif
+1 -1
View File
@@ -8,7 +8,7 @@ OBJCOPY = i686-elf-objcopy
MAKE = make MAKE = make
# Flags # Flags
HOSTCFLAGS = -Wall -Wextra -Wpedantic -O2 -std=c17 -g HOSTCFLAGS = -Wall -Wextra -Wpedantic -Os -std=c17 -g
CFLAGS = -Wall -Wextra -Wpedantic -Wno-pointer-arith\ CFLAGS = -Wall -Wextra -Wpedantic -Wno-pointer-arith\
-ffreestanding -fno-stack-protector -fno-builtin -fno-pie -fcommon\ -ffreestanding -fno-stack-protector -fno-builtin -fno-pie -fcommon\
-O2 -std=c17 -nostdinc -nostdlib -z notext -march=i386 -g -O2 -std=c17 -nostdinc -nostdlib -z notext -march=i386 -g
+16
View File
@@ -196,3 +196,19 @@ The prefered way of ordering '#include' directives is as so:
Directives should be ordered by lenght, descending. If two or more includes Directives should be ordered by lenght, descending. If two or more includes
have the same length, order alphabetically. have the same length, order alphabetically.
Header Guards
*************
`#ifndef X #define X` header guards are preffered. To avoid conflicts they
should follow this format:
`#define _PATH_TO_HEADER_H`
For example `drivers/fat32.h would have this guard:
```
#ifndef _DRIVERS_FAT32_H
#define _DRIVERS_FAT32_H
/* Header stuff */
#endif
```
+1
View File
@@ -8,6 +8,7 @@ char* itoa(size_t val, int base) {
if (val == 0) { if (val == 0) {
buf[0] = '0'; buf[0] = '0';
buf[1] = '\0';
return buf; return buf;
} }
+1 -1
View File
@@ -29,7 +29,7 @@ clean:
qemu: qemu:
qemu-system-x86_64\ qemu-system-x86_64\
-drive format=raw,file=$(IMG),index=0,media=disk\ -drive format=raw,file=$(IMG),index=0,media=disk\
-m 256M -accel tcg -monitor stdio\ -m 256M -accel tcg -monitor stdio -net none\
-rtc base=localtime,clock=host,driftfix=slew\ -rtc base=localtime,clock=host,driftfix=slew\
-audiodev coreaudio,id=audio0 -machine pcspk-audiodev=audio0 -audiodev coreaudio,id=audio0 -machine pcspk-audiodev=audio0