forked from PoliEcho-holding-org/kern
Added AMAZING boot menu to KBOOT
This commit is contained in:
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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) {}
|
||||||
|
|
||||||
@@ -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
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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 = .;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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++]);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user