MAJOR REWRITE

- Kernel got pretty much deleted, will be rewriting in following days
- Bootloader got rewritten, stage1 works, stage2 will be written in following days
- Libc is still the same
- User will contains userspace stuff
- Rewrote makefiles again
- Got rid of backup (see previous commits for that)
- Image has 1 MBR partition for FAT32 which contains 'kern.bin' file
- Remade info files to be more "big project" style (all caps plain text)
- Added some dumb docs
This commit is contained in:
2024-12-31 20:05:37 +01:00
parent 81255d13ce
commit 707733e449
82 changed files with 261 additions and 6986 deletions
+1
View File
@@ -15,6 +15,7 @@
*.elf
*.hdd
*.iso
*.img
*.sys
*.dtb
*~
-12
View File
@@ -1,12 +0,0 @@
#
# KBOOT Makefile
#
include make.defaults
$(BOOTSECT): $(BOOTSECT_SRC)
$(AS) -fbin $(BOOT_DIR)/bootsect.s -o $(BOOTSECT)
$(BOOTLOAD): $(BOOTLOAD_SRC)
@echo TODO
-405
View File
@@ -1,405 +0,0 @@
#include <syscalls/syscalls.h>
#include <memory/addresses.h>
#include <memory/physical.h>
#include <memory/virtual.h>
#include <memory/malloc.h>
#include <drivers/keyboard.h>
#include <drivers/serial.h>
#include <drivers/timer.h>
#include <drivers/pcspk.h>
#include <drivers/disk.h>
#include <drivers/rtc.h>
#include <screen/graphics.h>
#include <screen/gfxmode.h>
#include <screen/text.h>
#include <screen/tty.h>
#include <cpu/system.h>
#include <cpu/isr.h>
#include <fs/kernfs.h>
#include <fs/fs.h>
#include <sys/notes.h>
#include <sys/gfx.h>
#include <syscall.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
/* Little teaser
#include <math.h>
void mathTest() {
printf("|-4| = %d\n", abs(-4));
printf("|-3.14| = %f\n", fabs(-3.14));
printf("e^3 = %f\n", exp(3));
printf("e^5 = %f\n", exp2(5));
printf("ln(2) = %f\n", log(2));
printf("log2(69) = %f\n", log2(69));
printf("log10(100) = %f\n", log10(100));
printf("sqrt(2) = %f\n", sqrt(2));
printf("cbrt(27) = %f\n", cbrt(27));
printf("hyp(8, 6) = %f\n", hypot(8, 6));
printf("3^4 = %f\n", pow(3, 4));
}
*/
#define PROMPT "#>"
// FS things
char* cwd;
// Function declarations
void listFiles();
void printRegs();
void printPhysicalMemmap();
void initOpenFileTable();
__attribute__ ((section("entry")))
void main() {
// Retrieve global variables
currentPd = (pageDirectory_t*)*(uint32_t*)CURRENT_PAGE_DIR_ADDR; // Don't ask
memoryMap = (uint32_t*)MEMMAP_AREA;
maxBlocks = *(uint32_t*)PHYS_MEM_MAX_BLOCKS;
usedBlocks = *(uint32_t*)PHYS_MEM_USED_BLOCKS;
// Setup serial output for debugf()
if (setupSerial(PORT_COM1) != 0) { printf("\x1b[1MFailed to initialize serial interface\x1b[8M\n"); }
else {
debugf("\x1b[H\x1b[J"); // Clear
debugf("kern. \x1b[36m(Serial console)\x1b[0m\n\n");
}
// Interrupt setup
setupIsrs();
// Programmable Interval Timer
registerIrq(0, timerHandler);
setPitPhase(0, 2, 1000); // 1000Hz
// Real Time Clock
registerIrq(8, rtcHandler);
enableRtc();
// Keyboard
registerIrq(1, keyboardHandler);
// Setup kernel malloc variables
mallocNode_t* kernelMallocListHead = 0;
uint32_t kernelMallocVirtualAddr = KERNEL_MALLOC_AREA;
uint32_t kernelMallocPhysicalAddr = (uint32_t)allocBlocks(16); // TODO: Kernel may use more than 64kB?
uint32_t kernelMallocPages = 1;
mapPage((void*)kernelMallocPhysicalAddr, (void*)kernelMallocVirtualAddr);
ptEntry_t* kernelMallocPage = getPage(kernelMallocVirtualAddr);
SET_ATTR(kernelMallocPage, PTE_READ_WRITE);
kernelMallocListHead = (mallocNode_t*)kernelMallocVirtualAddr;
kernelMallocListHead->size = PAGE_SIZE - sizeof(mallocNode_t);
kernelMallocListHead->free = true;
kernelMallocListHead->next = NULL;
mallocListHead = kernelMallocListHead;
mallocVirtualAddr = kernelMallocVirtualAddr;
mallocPhysicalAddr = kernelMallocPhysicalAddr;
mallocPages = kernelMallocPages;
// FS Setup
initOpenFileTable();
cwd = malloc(1024);
strcpy(cwd, "/");
// Terminal setup
console->fg = FG_COLOR;
console->bg = BG_COLOR;
printf("\x1b[J"); // Clear
printf("kern.\n\n");
while (1) {
printf("\x1b[6M%s \x1b[2M%s \x1b[8M", cwd, PROMPT);
char input[256];
char* inPtr = &input[0];
gets(inPtr, 256);
}
}
int _m() {
// Run Interactive Shell Program
// TODO: Make it in another file
while (1) {
printf("\x1b[6M%s \x1b[2M%s ", cwd, PROMPT);
char input[256];
char* inputPtr = input;
gets(input, 256);
if (*input == '\0') continue;
int argc = 0;
char* argv[10] = { NULL };
while (*inputPtr == ' ') inputPtr++;
argv[argc++] = inputPtr;
while (*inputPtr != '\0') {
if (*inputPtr == ' ') {
*inputPtr++ = '\0';
while (*inputPtr == ' ') inputPtr++; // Skip extra spaces
argv[argc++] = inputPtr;
} else {
inputPtr++;
}
}
if (strcmp(argv[0], "clear") == 0) {
printf("\x1b[J");
} else if (strcmp(argv[0], "echo") == 0) {
if (argc < 2) continue;
char* str = argv[1];
char* printStr = argv[1];
while (*argv[1] != '\0') {
if (*argv[1] == '\\') {
argv[1]++;
if (*argv[1] == 'n') *str++ = '\n';
else if (*argv[1] == 'b') *str++ = '\b';
else if (*argv[1] == 'e') *str++ = '\x1b';
else if (*argv[1] == '\\') *str++ = '\\';
else {
*str++ = '\\';
*str++ = *argv[1];
}
argv[1]++;
} else {
*str++ = *argv[1]++;
}
}
*str = '\0';
printf("%s\n", printStr);
} else if (strcmp(argv[0], "exit") == 0) {
break;
} else if (strcmp(argv[0], "gfx") == 0) {
printf("\x1b[J");
// Draw some stuff :)
for (size_t i = 0; i < 120; i++) {
for (size_t j = 0; j < 120; j++) {
drawPixel(200 + i, 200 + j, GREEN);
}
}
fillRect(200, 200, 320, 320, GREEN);
drawLine(200, 200, 320, 320, RED);
drawLine(320, 200, 200, 320, RED);
drawLine(800, 300, 900, 400, BLUE);
drawLine(900, 400, 1000, 300, BLUE);
drawLine(1000, 300, 900, 200, BLUE);
drawLine(900, 200, 800, 300, BLUE);
drawLine(400, 350, 420, 100, rgb(0xee, 0x9f, 0x00));
drawTriangle(200, 400, 400, 600, 200, 600, MAGENTA);
fillTriangle(750, 400, 800, 450, 700, 450, CYAN);
drawTriangle(960, 400, 1000, 500, 990, 580, YELLOW);
drawRect(100, 650, 800, 900, rgb(0xe0, 0x0a, 0x3a));
drawCircle(1500, 600, 300, WHITE);
fillCircle(950, 750, 75, rgb(0xa2, 0xd6, 0xf9));
getc(stdin); // Wait until we get a keystroke
printf("\x1b[J");
} else if (strcmp(argv[0], "help") == 0) {
printf("Available Commands:\n");
printf(" clear | Clears the screen\n");
printf(" echo | Prints a message to stdout\n");
printf(" exit | Exits shell\n");
printf(" gfx | Does a graphics test\n");
printf(" help | Prints this message\n");
printf(" ls | Lists files in current directory\n");
printf(" memmap | Prints the memory map and info\n");
printf(" reboot | Reboots the system\n");
printf(" regs | Prints register values\n");
printf(" sleep | Sleeps for input number of seconds\n");
printf(" soundtest | Plays a tune :)\n");
} else if (strcmp(argv[0], "ls") == 0) {
listFiles();
} else if (strcmp(argv[0], "memmap") == 0) {
printPhysicalMemmap();
} else if (strcmp(argv[0], "reboot") == 0) {
outb(0x64, 0xFE);
} else if (strcmp(argv[0], "regs") == 0) {
printRegs();
} else if (strcmp(argv[0], "sleep") == 0) {
if (*argv[1] == '\0') continue;
uint32_t ms = atoi(argv[1]) * 1000; // Convert seconds to miliseconds
if (ms == 0) continue;
msleep(ms);
} else if (strcmp(argv[0], "soundtest") == 0) {
printf("Playing...\n");
enableSpeaker();
/*
* Megalovania - Toby Fox
* |-D-D-d--A---Ab--G--F--D-F-G-| (Goofy ahh notation)
* (The timing may be off)
*/
for (uint8_t i = 0; i < 4; i++) {
note_t first[4] = { D4, C4, H3, Hb3 };
playNote(first[i], 120);
playNote(first[i], 120);
playNote(D5, 240);
playNote(A4, 360);
playNote(Ab4, 240);
playNote(G4, 240);
playNote(F4, 240);
playNote(D4, 120);
playNote(F4, 120);
playNote(G4, 120);
}
rest(120);
disableSpeaker();
} else { // TODO: Use cwd for this
char* fileName = argv[0];
FILE* _f = fopen(fileName, "rb");
if (_f == NULL) {
printf("Command not found: %s\n", fileName);
continue;
}
FILE* fp = fsInfo->openFileTable + _f->_file;
printf("%d: 0x%x Bytes\n", fp->_file, fp->_size);
for (size_t i = 0; i < fp->_size; i++) {
if (i % 32 == 0) {
if (i != 0) {
printf(" ");
size_t oldi = i;
i -= 32;
while (i < oldi) {
char c = fp->_ptr[i++];
printf("%c", c < 32 ? '.' : c);
}
putc('\n', stdout);
}
printf("%04x: ", i);
}
printf("%02x ", fp->_ptr[i]);
}
if (fp->_size % 32 != 0) {
for (size_t i = 0; i < 32-(fp->_size % 32); i++) {
printf(" ");
}
}
printf(" ");
for (size_t i = fp->_size-(fp->_size%32); i < fp->_size; i++) {
char c = fp->_ptr[i];
printf("%c", c < 32 ? '.' : c);
}
printf("\n");
free(_f);
fclose(fp);
}
}
outw(0x604, 0x2000); // QEMU - Quit emulator
while (1); // Just hang
}
void listFiles() {
inode_t* root = (inode_t*)impl_superblock->rootInodePtr;
diskRead(root->extent[0].block * 8, root->extent[0].length * 8, (void*)SCRATCH_BLOCK_LOC);
dirEntry_t* dentry = (dirEntry_t*)SCRATCH_BLOCK_LOC;
uint32_t total = 0;
while ((dentry + total)->name[0] != '\0') { total++; }
putc(' ', stdout); // TODO
printf("\bTotal %d\n", total);
while (dentry->name[0] != '\0') {
inode_t* inode = (inode_t*)BOOT_FIRST_INODE_LOC + dentry->id;
printf("%s", dentry->name);
for (uint32_t pad = (16 - strlen(dentry->name)); pad > 0; pad--) { putc(' ', stdout); }
switch (inode->type) {
case FT_FILE: printf("%dB\n", inode->sizeBytes); break;
case FT_DIR: printf("[dir]\n"); break;
}
dentry++;
}
}
void printRegs() {
uint32_t val;
// a, b, c, d
__asm__ volatile ("movl %%eax, %0" : "=r"(val));
printf("eax 0x%08x\n", val);
__asm__ volatile ("movl %%ebx, %0" : "=r"(val));
printf("ebx 0x%08x\n", val);
__asm__ volatile ("movl %%ecx, %0" : "=r"(val));
printf("ecx 0x%08x\n", val);
__asm__ volatile ("movl %%edx, %0" : "=r"(val));
printf("edx 0x%08x\n", val);
// si, di
__asm__ volatile ("movl %%esi, %0" : "=r"(val));
printf("esi 0x%08x\n", val);
__asm__ volatile ("movl %%edi, %0" : "=r"(val));
printf("edi 0x%08x\n", val);
// cs, ds, es, ss
__asm__ volatile ("movl %%cs, %0" : "=r"(val));
printf("cs 0x%08x\n", val);
__asm__ volatile ("movl %%ds, %0" : "=r"(val));
printf("ds 0x%08x\n", val);
__asm__ volatile ("movl %%es, %0" : "=r"(val));
printf("es 0x%08x\n", val);
__asm__ volatile ("movl %%ss, %0" : "=r"(val));
printf("ss 0x%08x\n", val);
// stack
__asm__ volatile ("movl %%esp, %0" : "=r"(val));
printf("esp 0x%08x\n", val);
__asm__ volatile ("movl %%ebp, %0" : "=r"(val));
printf("ebp 0x%08x\n", val);
}
void printPhysicalMemmap() {
uint32_t entryCount = *(uint32_t*)SMAP_ENTRY_COUNT;
smapEntry_t* smapEntry = (smapEntry_t*)SMAP_ENTRIES;
for (uint32_t i = 0; i < entryCount; i++) {
printf("Region %02d - base: 0x%08x length: 0x%08x type: %2d ", i, (uint32_t)smapEntry->baseAddress, (uint32_t)smapEntry->length, smapEntry->type);
switch (smapEntry->type) {
case 1: printf("(Available)\n"); break;
case 2: printf("(Reserved)\n"); break;
case 3: printf("(ACPI Reclaim)\n"); break;
case 4: printf("(ACPI NVS)\n"); break;
default: printf("(Reserved)\n"); break;
}
smapEntry++;
}
smapEntry--; // We incremented it after the last entry
printf("\nTotal memory: 0x%x Bytes\n", smapEntry->baseAddress + smapEntry->length - 1);
printf("Total 4kB Blocks: %d\n", maxBlocks);
printf("Used or reserved blocks: %d\n", usedBlocks);
printf("Free blocks: %d\n\n", maxBlocks - usedBlocks);
}
-17
View File
@@ -1,17 +0,0 @@
OUTPUT_FORMAT("binary")
SECTIONS {
.text 0xC0000000 : {
*(entry);
*(.text*);
}
.data : {
*(.data*);
}
.rodata : {
*(.rodata*);
}
.bss : {
*(.bss*);
}
}
-11
View File
@@ -1,11 +0,0 @@
#
# Kernel makefile
#
include make.defaults
$(KERNEL): $(KERNEL_SRC) $(LIBC) $(LIBK)
@echo "Compiling $(KERNEL_SRC)..."
$(CC) $(CFLAGS) -I$(LIBK_INC) -I$(LIBC_INC) -o $(BIN)/kernel/kernel.o -c $(KERNEL_SRC)
$(LD) $(LDFLAGS) -T$(KERNEL_DIR)/linker.ld -o $@ $(BIN)/kernel/kernel.o $(LIBK)
-25
View File
@@ -1,25 +0,0 @@
#include <cpu/idt.h>
#include <stdint.h>
__attribute__ ((aligned(0x10))) // For performance
idtEntry_t idt[IDT_ENTRIES] = { 0 };
idtp_t idtp;
void idtSetGate(uint8_t i, void* handler, uint8_t flags) {
uint32_t offset = (uint32_t)handler;
idtEntry_t* entry = &idt[i];
entry->offsetLow = (uint16_t)offset;
entry->selector = 0x08;
entry->zero = 0;
entry->typeAttr = flags;
entry->offsetHigh = (uint16_t)(offset >> 16);
}
void setupIdt() {
idtp.limit = sizeof(idtEntry_t) * 256;
idtp.base = (uint32_t)&idt;
__asm__ volatile ("lidt %0" : : "m"(idtp));
}
-102
View File
@@ -1,102 +0,0 @@
#include <syscalls/syscalls.h>
#include <drivers/serial.h>
#include <cpu/system.h>
#include <cpu/idt.h>
#include <cpu/isr.h>
const char* format = "\x1b[31m[kernel] %s!\n\x1b[0m";
const char* exceptions[] = {
"Division By Zero",
"Debug",
"Non Maskable Interrupt",
"Breakpoint",
"Into Detected Overflow",
"Out of Bounds",
"Invalid Opcode",
"No Coprocessor",
"Double Fault",
"Coprocessor Segment Overrun",
"Bad TSS",
"Segment Not Present",
"Stack Fault",
"General Protection Fault",
"Page Fault",
"Unknown Interrupt",
"Coprocessor Fault",
"Alignment Check",
"Machine Check",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved"
};
void remapPic() {
outb(0x20, 0x11);
outb(0xa0, 0x11);
outb(0x21, 0x20);
outb(0xa1, 0x28);
outb(0x21, 0x04);
outb(0xa1, 0x02);
outb(0x21, 0x01);
outb(0xa1, 0x01);
outb(0x21, 0x00);
outb(0xa1, 0x00);
}
HandlerPtr irqHandlers[16] = { 0 }; // IRQ 0-15
void setupIsrs() {
setupIdt();
remapPic(); // Remap IRQs 0-15 -> 32-48
for (int i = 0; i < 48; i++) {
idtSetGate(i, asm_isrRedirectTable[i], TRAP_GATE_FLAGS);
}
// System call
idtSetGate(0x80, isr128, USR_INT_GATE_FLAGS);
__asm__ volatile ("sti");
}
void registerIrq(uint8_t id, HandlerPtr handler) {
irqHandlers[id] = handler;
}
void sendPicEOI(uint8_t irq) {
if (irq >= 8) {
outb(0xA0, 0x20); // PIC2 Command
}
outb(0x20, 0x20); // PIC1 Command
}
int handleInterrupt(intFrame_t iframe) {
if (iframe.interrupt < 32) {
// ISRs 0-31 - Exceptions
debugf(format, exceptions[iframe.interrupt]);
panic();
} else if (iframe.interrupt >= 32 && iframe.interrupt < 48) {
// ISRs 32-47 - Hardware interrupts
uint8_t irq = iframe.interrupt - 32;
if (irqHandlers[irq]) {
irqHandlers[irq](&iframe);
sendPicEOI(irq);
}
} else if (iframe.interrupt == 128) {
// ISR 128 - System call
return syscallHandler(&iframe);
}
return 0;
}
-116
View File
@@ -1,116 +0,0 @@
; ISR Assembly
[bits 32]
isrCommon:
;; Push registers to the intFrame_t struct
push eax
push gs
push fs
push es
push ds
push ebp
push edi
push esi
push edx
push ecx
push ebx
push esp
[extern handleInterrupt]
call handleInterrupt
isrReturn:
add esp, 4 ; Keep ESP
pop ebx
pop ecx
pop edx
pop esi
pop edi
pop ebp
pop ds
pop es
pop fs
pop gs
add esp, 4 ; Keep EAX
add esp, 8 ; Pop interupt number and error code
iretd ; Pop CS, EIP & EFLAGS (Also SS & ESP if it's from userspace)
%macro ISR_WITH_ERRNO 1
isr%1:
push dword %1
jmp isrCommon
%endmacro
%macro ISR_WITHOUT_ERRNO 1
isr%1:
push dword 0 ; Instead of error code
push dword %1
jmp isrCommon
%endmacro
;; Exceptions
ISR_WITHOUT_ERRNO 0
ISR_WITHOUT_ERRNO 1
ISR_WITHOUT_ERRNO 2
ISR_WITHOUT_ERRNO 3
ISR_WITHOUT_ERRNO 4
ISR_WITHOUT_ERRNO 5
ISR_WITHOUT_ERRNO 6
ISR_WITHOUT_ERRNO 7
ISR_WITH_ERRNO 8
ISR_WITHOUT_ERRNO 9
ISR_WITH_ERRNO 10
ISR_WITH_ERRNO 11
ISR_WITH_ERRNO 12
ISR_WITH_ERRNO 13
ISR_WITH_ERRNO 14
ISR_WITHOUT_ERRNO 15
ISR_WITHOUT_ERRNO 16
ISR_WITHOUT_ERRNO 17
ISR_WITHOUT_ERRNO 18
ISR_WITHOUT_ERRNO 19
ISR_WITHOUT_ERRNO 20
ISR_WITHOUT_ERRNO 21
ISR_WITHOUT_ERRNO 22
ISR_WITHOUT_ERRNO 23
ISR_WITHOUT_ERRNO 24
ISR_WITHOUT_ERRNO 25
ISR_WITHOUT_ERRNO 26
ISR_WITHOUT_ERRNO 27
ISR_WITHOUT_ERRNO 28
ISR_WITHOUT_ERRNO 29
ISR_WITHOUT_ERRNO 30
ISR_WITHOUT_ERRNO 31
;; IRQs 0-15 (mapped 32-47)
ISR_WITHOUT_ERRNO 32
ISR_WITHOUT_ERRNO 33
ISR_WITHOUT_ERRNO 34
ISR_WITHOUT_ERRNO 35
ISR_WITHOUT_ERRNO 36
ISR_WITHOUT_ERRNO 37
ISR_WITHOUT_ERRNO 38
ISR_WITHOUT_ERRNO 39
ISR_WITHOUT_ERRNO 40
ISR_WITHOUT_ERRNO 41
ISR_WITHOUT_ERRNO 42
ISR_WITHOUT_ERRNO 43
ISR_WITHOUT_ERRNO 44
ISR_WITHOUT_ERRNO 45
ISR_WITHOUT_ERRNO 46
ISR_WITHOUT_ERRNO 47
;; Syscall ISR128
[global isr128]
ISR_WITHOUT_ERRNO 128
;; Create table of ISRs
[global asm_isrRedirectTable]
asm_isrRedirectTable:
%assign i 0
%rep 48
dd isr%+i
%assign i i+1
%endrep
-49
View File
@@ -1,49 +0,0 @@
#include <cpu/system.h>
#include <drivers/serial.h>
#include <stdint.h>
void cpuid(uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx) {
__asm__ volatile (
"cpuid"
: "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
: "a"(*eax)
);
}
uint8_t inb(uint16_t port) {
uint8_t result;
__asm__ volatile("inb %1, %0" : "=a"(result) : "Nd"(port));
return result;
}
void outb(uint16_t port, uint8_t data) {
__asm__ volatile("outb %0, %1" :: "a"(data), "Nd"(port));
}
uint16_t inw(uint16_t port) {
uint16_t result;
__asm__ volatile("inw %1, %0" : "=a"(result) : "Nd"(port));
return result;
}
void outw(uint16_t port, uint16_t data) {
__asm__ volatile("outw %0, %1" :: "a"(data), "Nd"(port));
}
uint32_t inl(uint16_t port) {
uint32_t result;
__asm__ volatile("inl %1, %0" : "=a"(result) : "Nd"(port));
return result;
}
void outl(uint16_t port, uint32_t data) {
__asm__ volatile("outl %0, %1" :: "a"(data), "Nd"(port));
}
void ioWait() {
// Waits ~1 I/O Cycle (Linux uses this so it should be good)
__asm__ volatile("outb %%al, $0x80" : : "a"(0));
}
void panic() {
debugf("\x1b[31m[kernel] Kern panic!\x1b[0m\n");
while (1) { __asm__ volatile ("cli; hlt"); }
}
-53
View File
@@ -1,53 +0,0 @@
#include <drivers/disk.h>
#include <cpu/system.h>
#include <stdint.h>
void diskRead(uint32_t lbaAddress, uint8_t sectorCount, char* dst) {
outb(PIO_PORT + 6, ((lbaAddress >> 24) & 0x0f) | 0xe0); // 6 - Use LBA; 4 - Drive number; 3-0 - Highest lba address nibble
outb(PIO_PORT + 2, sectorCount); // Sector count register
outb(PIO_PORT + 3, (uint8_t)(lbaAddress)); // Lowest lba address byte
outb(PIO_PORT + 4, (uint8_t)(lbaAddress >> 8)); // Middle lba address byte
outb(PIO_PORT + 5, (uint8_t)(lbaAddress >> 16)); // High lba address byte
outb(PIO_PORT + 7, READ_COMMAND); // Command register
uint16_t* address = (uint16_t*)dst;
for (uint8_t i = sectorCount; i > 0; i--) {
while (inb(PIO_PORT + 7) & (1 << 7)); // Poll status register untill BSY bit is clear
for (size_t j = 0; j < 256; j++) {
*address++ = inw(PIO_PORT); // Read 256 words (512 Bytes = 1 Sector)
}
for (uint8_t delay = 0; delay < 4; delay++) { // 400ns delay
inb(0x3f6); // Alternate status register
}
}
}
void diskWrite(uint32_t lbaAddress, uint8_t sectorCount, char* src) {
outb(PIO_PORT + 6, ((lbaAddress >> 24) & 0x0f) | 0xe0); // 6 - Use LBA; 4 - Drive number; 3-0 - Highest lba address nibble
outb(PIO_PORT + 2, sectorCount); // Sector count register
outb(PIO_PORT + 3, (uint8_t)(lbaAddress)); // Lowest lba address byte
outb(PIO_PORT + 4, (uint8_t)(lbaAddress >> 8)); // Middle lba address byte
outb(PIO_PORT + 5, (uint8_t)(lbaAddress >> 16)); // High lba address byte
outb(PIO_PORT + 7, WRITE_COMMAND); // Command register
uint16_t* address = (uint16_t*)src;
for (uint8_t i = sectorCount; i > 0; i--) {
while (inb(PIO_PORT + 7) & (1 << 7)); // Poll status register untill BSY bit is clear
for (size_t j = 0; j < 256; j++) {
outw(PIO_PORT, *address++); // Write 256 words (512 Bytes = 1 Sector)
}
for (uint8_t delay = 0; delay < 4; delay++) { // 400ns delay
inb(0x3f6); // Alternate status register
}
}
outb(PIO_PORT + 7, CACHE_FLUSH); // Cache flush
while (inb(PIO_PORT + 7) & (1 << 7)); // Poll status register untill BSY bit is clear
}
-23
View File
@@ -1,23 +0,0 @@
#include <drivers/keyboard.h>
#include <memory/addresses.h>
#include <cpu/system.h>
#include <cpu/isr.h>
static const uint8_t US_Keyboard[2][128] = US_KEYBOARD;
keyboardState_t* keyboard = (keyboardState_t*)KEYBOARD_STATE_LOC;
// TODO: Make this better and be able to read multi-byte scancode
void keyboardHandler(intFrame_t*) {
uint8_t scancode = inb(0x60);
char c = US_Keyboard[keyboard->shift][scancode];
if (scancode == LEFT_SHIFT_PRESS || scancode == RIGHT_SHIFT_PRESS) {
keyboard->shift = 1;
} else if (scancode == LEFT_SHIFT_RELEASE || scancode == RIGHT_SHIFT_RELEASE) {
keyboard->shift = 0;
}
if (scancode & 0x80) { // Keyup
} else if (c != '\0') { keyboard->character = c; }
}
-27
View File
@@ -1,27 +0,0 @@
#include <drivers/pcspk.h>
#include <drivers/timer.h>
#include <cpu/system.h>
#include <sys/notes.h>
#include <stdint.h>
#include <time.h>
void enableSpeaker() {
uint8_t temp = inb(PC_SPEAKER);
outb(PC_SPEAKER, temp | 0x03); // Set first 2 bits
}
void disableSpeaker() {
uint8_t temp = inb(PC_SPEAKER);
outb(PC_SPEAKER, temp & 0xfc); // Set first 2 bits
}
void playNote(note_t note, uint32_t ms) {
setPitPhase(2, 3, note);
sleep(ms);
}
void rest(uint32_t ms) {
setPitPhase(2, 3, 30000); // Unhearable noise
sleep(ms);
}
-131
View File
@@ -1,131 +0,0 @@
#include <drivers/rtc.h>
#include <screen/gfxmode.h>
#include <screen/text.h>
#include <screen/tty.h>
#include <cpu/system.h>
#include <cpu/isr.h>
#include <string.h>
static datetime_t* datetime = (datetime_t*)DATETIME_LOC;
int cmosUpdateProgress() {
outb(CMOS_ADDRESS, 0x8a); // Read status reg A, disable NMI
return inb(CMOS_DATA) & 0x80;
}
uint8_t getRtcRegister(uint8_t reg) {
outb(CMOS_ADDRESS, reg | 0x80); // Disable NMI when sending
return inb(CMOS_DATA);
}
void enableRtc() {
uint8_t regB = getRtcRegister(0x0b);
outb(CMOS_ADDRESS, 0x8b);
outb(CMOS_DATA, regB | 0x40); // Set bit 6 - periodic int at 1024Hz
getRtcRegister(0x0c); // Clear pending interrupts
}
void disableRtc() {
__asm__ volatile ("cli");
uint8_t regB = getRtcRegister(0x0b);
outb(CMOS_ADDRESS, 0x8b);
outb(CMOS_DATA, regB & 0xbf); // Clear bit 6
__asm__ volatile ("sti");
}
void rtcHandler(intFrame_t* iframe) {
datetime_t newDatetime, oldDatetime;
static uint16_t rtcTicks = 0;
__asm__ volatile ("cli");
rtcTicks++;
if (rtcTicks % 1024 == 0) { // 1 Second has passed
while (cmosUpdateProgress()); // Wait
newDatetime.second = getRtcRegister(0);
newDatetime.minute = getRtcRegister(2);
newDatetime.hour = getRtcRegister(4);
newDatetime.day = getRtcRegister(7);
newDatetime.month = getRtcRegister(8);
newDatetime.year = getRtcRegister(9);
do {
oldDatetime = newDatetime;
while (cmosUpdateProgress()); // Wait
newDatetime.second = getRtcRegister(0);
newDatetime.minute = getRtcRegister(2);
newDatetime.hour = getRtcRegister(4);
newDatetime.day = getRtcRegister(7);
newDatetime.month = getRtcRegister(8);
newDatetime.year = getRtcRegister(9);
} while (
newDatetime.second != oldDatetime.second ||
newDatetime.minute != oldDatetime.minute ||
newDatetime.hour != oldDatetime.hour ||
newDatetime.day != oldDatetime.day ||
newDatetime.month != oldDatetime.month ||
newDatetime.year != oldDatetime.year
);
uint8_t regB = getRtcRegister(0x0b);
if (!(regB & 0x04)) {
newDatetime.second = (newDatetime.second & 0x0f) + ((newDatetime.second >> 4) * 10);
newDatetime.minute = (newDatetime.minute & 0x0f) + ((newDatetime.minute >> 4) * 10);
newDatetime.hour = ((newDatetime.hour & 0x0F) + (((newDatetime.hour & 0x70) / 16) * 10)) | (newDatetime.hour & 0x80); // 12/24 Hour format bs
newDatetime.day = (newDatetime.day & 0x0f) + ((newDatetime.day >> 4) * 10);
newDatetime.month = (newDatetime.month & 0x0f) + ((newDatetime.month >> 4) * 10);
newDatetime.year = (newDatetime.year & 0x0f) + ((newDatetime.year >> 4) * 10);
}
// Convert 12 to 14 hour format
if (!(regB & 0x02) && (newDatetime.hour & 0x80)) {
newDatetime.hour = ((newDatetime.hour & 0x7f) + 12) % 24;
}
newDatetime.year += 2000; // Add current century
//*datetime = newDatetime;
datetime->second = newDatetime.second;
datetime->minute = newDatetime.minute;
datetime->hour = newDatetime.hour;
datetime->day = newDatetime.day;
datetime->month = newDatetime.month;
datetime->year = newDatetime.year;
if (1) { // TODO: Probably get rid of this idk
char buf[20] = { 0 }; // "12/12 2012 12:12:12" - Max string 20 chars with null byte
strcat(buf, itoa(datetime->day, 10));
strcat(buf, "/");
strcat(buf, itoa(datetime->month, 10));
strcat(buf, " ");
strcat(buf, itoa(datetime->year, 10));
strcat(buf, " ");
if (datetime->hour < 10) strcat(buf, "0");
strcat(buf, itoa(datetime->hour, 10));
strcat(buf, ":");
if (datetime->minute < 10) strcat(buf, "0");
strcat(buf, itoa(datetime->minute, 10));
strcat(buf, ":");
if (datetime->second < 10) strcat(buf, "0");
strcat(buf, itoa(datetime->second, 10));
// The clock is a little offset down (about 0.4 of a character) It does look nice though!
uint8_t len = strlen(buf);
uint32_t x = gfxMode->xRes - len - 1;
char* str = &buf[0];
for (uint8_t i = 0; i != len; i++, x++) {
drawChar(str[i], x, 0, console->fg, console->bg);
}
}
}
getRtcRegister(0x0c);
__asm__ volatile ("sti");
}
-50
View File
@@ -1,50 +0,0 @@
#include <drivers/serial.h>
#include <cpu/system.h>
#include <stdio.h>
#include <stdarg.h>
int serialEnable(int port) {
outb(port + 1, 0x00); // Disable all interrupts
outb(port + 3, 0x80); // Enable DLAB (set baud rate divisor)
outb(port + 0, 0x03); // Set divisor to 3 (low byte) 38400 baud
outb(port + 1, 0x00); // (high byte)
outb(port + 3, 0x03); // 8 bits, no parity, one stop bit
outb(port + 2, 0xC7); // Enable FIFO, clear them, with 14 byte threshold
outb(port + 4, 0x0B); // IRQs enabled, RTS/DSR set
outb(port + 4, 0x1E); // Set in loopback mode, test the serial chip
outb(port + 0, 0xAE); // Test serial chip (send byte 0xAE and check if it returns)
if (inb(port + 0) != 0xAE) return 1;
outb(port + 4, 0x0F); // non-loopback, IRQs enabled, OUT#1 and OUT#2 bits enabled
return 0;
}
int setupSerial() {
if (serialEnable(PORT_COM1) != 0) { return 1; }
outb(PORT_COM1 + 1, 0x01);
return 0;
}
static int serialTransimitEmpty(int port) { return inb(port + 5) & 0x20; }
static int serialRecieved(int port) { return inb(port + 5) & 0x01; }
void serialWrite(int port, char c) { while (!serialTransimitEmpty(port)); outb(port, c); }
char serialRead(int port) { while (!serialRecieved(port)); return inb(port); }
char serialReadAsync(int port) { return inb(port); }
void _dbgPutc(char c, void* arg) {
(void)arg;
serialWrite(PORT_COM1, c);
if (c == '\n') serialWrite(PORT_COM1, '\r');
}
int vdebugf(const char* fmt, va_list va) { return vpprintf(_dbgPutc, NULL, fmt, va); }
int debugf(const char* fmt, ...) {
va_list va;
va_start(va, fmt);
int ret = vdebugf(fmt, va);
va_end(va);
return ret;
}
-33
View File
@@ -1,33 +0,0 @@
#include <drivers/timer.h>
#include <memory/addresses.h>
#include <screen/tty.h>
#include <cpu/system.h>
#include <cpu/isr.h>
#include <stdint.h>
void timerHandler(intFrame_t*) {
static uint32_t cursorTicks = 0;
cursorTicks++;
if (!console->hideCursor) { // TODO: Make a better cursor drawing thing
if (cursorTicks % 500 == 0) toggleCursor();
}
if (*(uint32_t*)SLEEP_TIMER > 0) { --(*(uint32_t*)SLEEP_TIMER); }
}
void setPitPhase(uint8_t channel, uint8_t opMode, uint16_t hz) {
if (channel > 2 || opMode > 7) { return; }
__asm__ volatile ("cli");
// Send command - bits 7-6 channel, 5-4 Access mode, 3-1 operating mode, 0 - Should be zero in x86
outb(COMMAND, ((channel << 6) | (3 << 4) | (opMode << 1)));
// Send frequency
uint16_t freq = INPUT_CLK / hz; // I solved an equation to figure this out
outb(CHANNEL_0 + channel, (uint8_t)freq);
outb(CHANNEL_0 + channel, (uint8_t)(freq >> 8));
__asm__ volatile ("sti");
}
-63
View File
@@ -1,63 +0,0 @@
#include <fs/kernfs.h>
#include <memory/addresses.h>
#include <drivers/disk.h>
#include <fs/fs.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
superblock_t* impl_superblock = (superblock_t*)SUPERBLOCK_LOC;
fsInfo_t* fsInfo = (fsInfo_t*)FS_INFO_LOC;
inode_t* getInode(char* path, dirEntry_t* dentries) {
while (dentries->name[0] != '\0') {
if (strcmp(dentries->name, path) == 0) break;
dentries++;
}
if (dentries->name[0] == '\0') { return NULL; }
inode_t* inode = (inode_t*)BOOT_FIRST_INODE_LOC + dentries->id;
return inode;
}
uint8_t loadFile(inode_t* inode, void* dest) {
uint32_t totalBlocks = BYTES2BLOCKS(inode->sizeBytes);
uint32_t offset = 0;
for (uint8_t i = 0; i < 4 && totalBlocks > 0; i++) {
diskRead(inode->extent[i].block * 8, inode->extent[i].length * 8, dest + offset);
offset += inode->extent[i].length * FS_BLOCK_SIZE;
totalBlocks -= inode->extent[i].length;
}
if (totalBlocks > 0) {
// TODO: Indirect extents
return 1;
}
return 0;
}
void initOpenFileTable() {
fsInfo->openFileTable = malloc(sizeof(FILE) * MAX_OPEN_FILES);
if (fsInfo->openFileTable == NULL) { printf("\e[1MFailed to init file table! Malloc() error.\e[8M"); }
memset(fsInfo->openFileTable, 0, sizeof(FILE) * MAX_OPEN_FILES);
// offset and ptr are unused in these
stdin = fsInfo->openFileTable + 0;
stdin->_file = STDIN_FILENO;
stdin->_flag = O_RDONLY;
stdout = fsInfo->openFileTable + 1;
stdout->_file = STDOUT_FILENO;
stdout->_flag = O_WRONLY | O_APPEND;
stderr = fsInfo->openFileTable + 2;
stderr->_file = STDERR_FILENO;
stderr->_flag = O_WRONLY | O_APPEND;
fsInfo->openFiles = 3;
}
-28
View File
@@ -1,28 +0,0 @@
#ifndef _CPU_IDT_H
#define _CPU_IDT_H
#include <stdint.h>
#define IDT_ENTRIES 256
#define TRAP_GATE_FLAGS 0x8f // P = 1, DPL = 00, S = 0, Type = 1111 (32-bit Trap gate)
#define INT_GATE_FLAGS 0x8e // P = 1, DPL = 00, S = 0, Type = 1110 (32-bit Int gate)
#define USR_INT_GATE_FLAGS 0xee // P = 1, DPL = 11, S = 0, Type = 1110 (32-bit Int gate)
typedef struct {
uint16_t offsetLow;
uint16_t selector;
uint8_t zero;
uint8_t typeAttr;
uint16_t offsetHigh;
} __attribute__ ((packed)) idtEntry_t;
typedef struct {
uint16_t limit;
uint32_t base;
} __attribute__ ((packed)) idtp_t;
void idtSetGate(uint8_t i, void* handler, uint8_t flags);
void setupIdt();
#endif
-27
View File
@@ -1,27 +0,0 @@
#ifndef _CPU_ISR_H
#define _CPU_ISR_H
#include <stdint.h>
typedef struct {
// Pushed by OS
uint32_t esp, ebx, ecx, edx, esi, edi, ebp;
uint32_t ds, es, fs, gs, eax;
uint32_t interrupt, error;
// Pushed by CPU
uint32_t eip, cs, eflags, user_esp, user_ss;
} intFrame_t;
typedef void (*HandlerPtr)(intFrame_t* iframe);
void setupIsrs();
void registerIrq(uint8_t id, HandlerPtr handler);
int handleInterrupt(intFrame_t iframe);
// ISR Table
extern void* asm_isrRedirectTable[48];
// Int 0x80 - Syscall
extern void isr128();
#endif
-19
View File
@@ -1,19 +0,0 @@
#ifndef _CPU_SYSTEM_H
#define _CPU_SYSTEM_H
#include <stdint.h>
void cpuid(uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx);
void outb(uint16_t port, uint8_t data);
void outw(uint16_t port, uint16_t data);
void outl(uint16_t port, uint32_t data);
uint8_t inb(uint16_t port);
uint16_t inw(uint16_t port);
uint32_t inl(uint16_t port);
void ioWait();
void panic();
#endif
-14
View File
@@ -1,14 +0,0 @@
#ifndef _DRIVERS_DISK_H
#define _DRIVERS_DISK_H
#include <stdint.h>
#define PIO_PORT 0x1f0
#define READ_COMMAND 0x20
#define WRITE_COMMAND 0x30
#define CACHE_FLUSH 0xE7
void diskRead(uint32_t lbaAddress, uint8_t sectorCount, char* dst);
void diskWrite(uint32_t lbaAddress, uint8_t sectorCount, char* src);
#endif
-48
View File
@@ -1,48 +0,0 @@
#ifndef _DRIVERS_KEYBOARD_H
#define _DRIVERS_KEYBOARD_H
#include <cpu/isr.h>
// Special keys
#define LEFT_SHIFT_PRESS 0x2a
#define LEFT_SHIFT_RELEASE (LEFT_SHIFT_PRESS | 0x80)
#define RIGHT_SHIFT_PRESS 0x36
#define RIGHT_SHIFT_RELEASE (RIGHT_SHIFT_PRESS | 0x80)
#define LEFT_CTRL_PRESS 0x1D
#define LEFT_CTRL_RELEASE (LEFT_CTRL_PRESS | 0x80)
#define RIGHT_CTRL_PRESS 0x1D
#define RIGHT_CTRL_RELEASE (RIGHT_CTRL_PRESS | 0x80)
#define LEFT_ALT_PRESS 0x38
#define LEFT_ALT_RELEASE (LEFT_ALT_PRESS | 0x80)
#define RIGHT_ALT_PRESS 0x38
#define RIGHT_ALT_RELEASE (RIGHT_ALT_PRESS | 0x80)
// Basic US Keyboard layout
#define US_KEYBOARD {\
{\
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',\
'\t','q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',\
0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'','`',\
0, '\\','z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0,\
'*', 0, ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\
'7', '8', '9', '-', '4', '5', '6', '+', '1', '2', '3', '0', '.',\
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\
},\
{\
0, 27, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b', '\t',\
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', 0, 'A', 'S',\
'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', 0, '|', 'Z', 'X', 'C', 'V',\
'B', 'N', 'M', '<', '>', '?', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\
0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1', '2', '3', '0', '.',\
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\
}\
}
typedef struct {
char character;
int shift;
} keyboardState_t;
void keyboardHandler(intFrame_t*);
#endif
-14
View File
@@ -1,14 +0,0 @@
#ifndef _DRIVERS_PCSPK_H
#define _DRIVERS_PCSPK_H
#include <sys/notes.h>
#include <stdint.h>
#define PC_SPEAKER 0x61
void enableSpeaker();
void disableSpeaker();
void playNote(note_t note, uint32_t ms);
void rest(uint32_t ms);
#endif
-25
View File
@@ -1,25 +0,0 @@
#ifndef _DRIVERS_RTC_H
#define _DRIVERS_RTC_H
#include <cpu/isr.h>
#include <stdint.h>
#define CMOS_ADDRESS 0x70
#define CMOS_DATA 0x71
typedef struct {
uint8_t second;
uint8_t minute;
uint8_t hour;
uint8_t day;
uint8_t month;
uint16_t year;
} __attribute__ ((packed)) datetime_t;
void rtcHandler(intFrame_t*);
int cmosUpdateProgress();
uint8_t getRtcRegister(uint8_t reg);
void enableRtc();
void disableRtc();
#endif
-23
View File
@@ -1,23 +0,0 @@
#ifndef _DRIVERS_SERIAL_H
#define _DRIVERS_SERIAL_H
#include <stdarg.h>
#define PORT_COM1 0x3f8
#define PORT_COM2 0x2f8
#define PORT_COM3 0x3e8
#define PORT_COM4 0x2e8
// IRQ4 -> COM1, IRQ3 -> COM2
#define SERIAL_IRQ 4
int serialEnable(int port);
int setupSerial();
void serialWrite(int port, char c);
char serialRead(int port);
char serialReadAsync(int port);
int debugf(const char* fmt, ...);
int vdebugf(const char* fmt, va_list va);
#endif
-14
View File
@@ -1,14 +0,0 @@
#ifndef _DRIVERS_TIMER_H
#define _DRIVERS_TIMER_H
#include <cpu/isr.h>
#include <stdint.h>
#define CHANNEL_0 0x40 // Offset it by 1 or 2 for ch1 and ch2
#define COMMAND 0x43
#define INPUT_CLK 1193182
void timerHandler(intFrame_t*);
void setPitPhase(uint8_t channel, uint8_t opMode, uint16_t hz);
#endif
-83
View File
@@ -1,83 +0,0 @@
#ifndef _FS_FS_H
#define _FS_FS_H
/*
* For info, read the fs-spec.txt document inside of docs/
*/
#include <stdint.h>
// FS Definitions
#define FS_SECTOR_SIZE 512
#define FS_BLOCK_SIZE 4096
// Conversion Macros (beatiful)
#define BYTES2BLOCKS(_n) ( (_n) == 0 ? 0 : \
(_n) <= (FS_BLOCK_SIZE) ? 1 : \
((_n) / FS_BLOCK_SIZE) + (((_n) % FS_BLOCK_SIZE) > 0 ? 1 : 0) )
#define BYTES2SECTORS(_n) ( (_n) == 0 ? 0 : \
(_n) <= (FS_SECTOR_SIZE) ? 1 : \
((_n) / FS_SECTOR_SIZE) + (((_n) % FS_SECTOR_SIZE) > 0 ? 1 : 0) )
// Filetypes
#define FT_FILE 0
#define FT_DIR 1
// FS Structures
// TODO: datetime_t?
typedef struct {
uint8_t sectors[FS_BLOCK_SIZE / FS_SECTOR_SIZE][FS_SECTOR_SIZE];
} __attribute__ ((packed)) bootblock_t;
// Superblock - Padded to 4096 Bytes
typedef struct {
// Constant data
uint16_t deviceId;
uint16_t extentsPerIndirect;
uint32_t maxFileSize;
uint16_t inodesPerSector;
// INode data
uint32_t inodeCount;
uint32_t inodeBitmapBlock;
uint32_t inodesStart;
uint32_t inodeBlockCount;
// Data data :)
uint32_t dataBitmapBlock;
uint32_t dataStart;
uint32_t dataBlockCount;
// Other
uint32_t rootInodePtr;
uint32_t firstUnreservedInode;
} __attribute__ ((packed)) superblock_t;
// Extent - 8 Bytes
typedef struct {
uint32_t block;
uint32_t length;
} __attribute__ ((packed)) extent_t;
// INode - 64 Bytes
typedef struct {
uint32_t id;
uint8_t type;
uint32_t sizeBytes; // Size in bytes
uint32_t sizeSectors; // Size in sectors
uint8_t mode; // Access permisions
extent_t extent[4];
uint32_t singleIndirect;
uint32_t doubleIndirect;
uint8_t reserved[10];
} __attribute__ ((packed)) inode_t;
typedef struct {
char name[60];
uint32_t id;
} __attribute__ ((packed)) dirEntry_t;
#endif
-22
View File
@@ -1,22 +0,0 @@
#ifndef _FS_KERNFS_H
#define _FS_KERNFS_H
#include <fs/fs.h>
#include <stdint.h>
#include <stdio.h>
#define MAX_OPEN_FILES 256
typedef struct {
FILE* openFileTable;
uint32_t openFiles;
} fsInfo_t;
extern superblock_t* impl_superblock;
extern fsInfo_t* fsInfo;
inode_t* getInode(char* path, dirEntry_t* dentries);
uint8_t loadFile(inode_t* inode, void* dest);
void initOpenFileTable();
#endif
-61
View File
@@ -1,61 +0,0 @@
#ifndef _MEMORY_ADDRESSES_H
#define _MEMORY_ADDRESSES_H
/*
* Memory layout of addresses 0x0000 - 0x12000
* 0x0000-0x0fff - Probably shouldn't mess with this? idk it feels wrong
* 0x1000-0x17ff - Free
* 0x1800-0x1fff - Global Variables
* 0x2000-0x2fff - Larger structs
* 0x3000-0x3fff - Filesystem Info
* 0x4000-0x4fff - Font area
* 0x6000-0x6fff - VBE info area
* 0x7000-0x7bff - SMAP Area
* 0x7c00-0x8bff - Bootblock
* 0x8c00-0x9bff - Superblock
* 0x9c00-0xafff - Free
* 0xb000-0xbfff - Bootloader first INode
* 0xc000-0xcfff - Scratch INode block
*/
// Global Variables 0x1800-0x1fff
#define SLEEP_TIMER 0x1800
#define CURRENT_PAGE_DIR_ADDR 0x1804
#define PHYS_MEM_MAX_BLOCKS 0x1808
#define PHYS_MEM_USED_BLOCKS 0x180C
// Some structs 0x2000-0x2fff
#define CONSOLE_INFO_LOC 0x2000
#define KEYBOARD_STATE_LOC 0x2100
#define DATETIME_LOC 0x2200
// Filesystem Area 0x3000 - 0x3fff
#define FS_INFO_LOC 0x3000
// Font area 0x4000 - 0x4fff
#define FONT_LOC 0x4000
// VBE Info Area 0x6000 - 0x6fff
#define MODE_INFO_BLOCK_LOC 0x6000 // 512 Bytes
// Smap Area 0x7000 - 0x7bff
#define SMAP_ENTRY_COUNT 0x7000
#define SMAP_ENTRIES 0x7004
// Bootblock 0x7c00-0x9bff
#define BOOTBLOCK_LOC 0x7c00
// Superblock 0x9c00-0xabff
#define SUPERBLOCK_LOC 0x8c00
// First INode from bootloader
#define BOOT_FIRST_INODE_LOC 0xb000
#define SCRATCH_BLOCK_LOC 0xc000
// Other addresses
#define KERNEL_LOC 0x100000
#define KERNEL_MALLOC_AREA 0x300000
#define MEMMAP_AREA 0x30000
#define OPEN_FILE_LOC 0xd000
#endif
-27
View File
@@ -1,27 +0,0 @@
#ifndef _MEMORY_MALLOC_H
#define _MEMORY_MALLOC_H
#include <memory/virtual.h>
#include <memory/physical.h>
#include <stdbool.h>
#include <stdint.h>
// Singly linked list!
typedef struct mallocNode_s {
uint32_t size;
bool free;
struct mallocNode_s* next;
} mallocNode_t;
extern mallocNode_t* mallocListHead;
extern uint32_t mallocVirtualAddr;
extern uint32_t mallocPhysicalAddr;
extern uint32_t mallocPages;
void mallocInit(uint32_t size);
void mallocSplit(mallocNode_t* node, uint32_t size);
void* mallocNextNode(uint32_t size);
void mallocMergeFree();
void mallocFree(void* ptr);
#endif
-33
View File
@@ -1,33 +0,0 @@
#ifndef _MEMORY_PHYSICAL_H
#define _MEMORY_PHYSICAL_H
#include <memory/addresses.h>
#include <string.h>
#include <stdint.h>
#define BLOCK_SIZE 4096 // 4kB
#define BLOCKS_PER_BYTE 8
typedef struct smapEntry_s {
uint64_t baseAddress;
uint64_t length;
uint32_t type;
uint32_t acpiAttr;
} __attribute__ ((packed)) smapEntry_t;
extern uint32_t* memoryMap;
extern uint32_t maxBlocks;
extern uint32_t usedBlocks;
void setBlock(uint32_t block);
void unsetBlock(uint32_t block);
uint8_t testBlock(uint32_t block);
int32_t findFreeBlocks(uint32_t blockCount);
void setupPhysicalMemoryManager(uint32_t startAddress, uint32_t size);
void initMemoryRegion(uint32_t baseAddress, uint32_t size);
void deinitMemoryRegion(uint32_t baseAddress, uint32_t size);
void* allocBlocks(uint32_t blockCount);
void freeBlocks(void* address, uint32_t blockCount);
#endif
-70
View File
@@ -1,70 +0,0 @@
#ifndef _MEMORY_VIRTUAL_H
#define _MEMORY_VIRTUAL_H
#include <memory/physical.h>
#include <stdint.h>
#define PAGES_PER_TABLE 1024
#define TABLES_PER_DIRECTORY 1024
#define PAGE_SIZE 4096
#define PD_INDEX(_vAddress) ((_vAddress) >> 22)
#define PT_INDEX(_vAddress) (((_vAddress) >> 12) & 0x3ff)
#define PAGE_PHYS_ADDRESS(_dirEntry) (*(_dirEntry) & ~ 0xfff)
#define SET_ATTR(_entry, _attr) (*(_entry) |= (_attr))
#define CLEAR_ATTR(_entry, _attr) (*(_entry) &= ~(_attr))
#define TEST_ATTR(_entry, _attr) (*(_entry) & (_attr))
#define SET_FRAME(_entry, _address) (*(_entry) = (*(_entry) & ~0xfffff000) | (_address))
typedef uint32_t ptEntry_t;
typedef uint32_t pdEntry_t;
typedef enum {
PTE_PRESENT = 0x01,
PTE_READ_WRITE = 0x02,
PTE_USER = 0x04,
PTE_WRITE_THROUGH = 0x08,
PTE_CACHE_DISABLE = 0x10,
PTE_ACCESSED = 0x20,
PTE_DIRTY = 0x40,
PTE_PAT = 0x80,
PTE_GLOBAL = 0x100,
PTE_FRAME = 0x7ffff000,
} PAGE_TABLE_FLAGS;
typedef enum {
PDE_PRESENT = 0x01,
PDE_READ_WRITE = 0x02,
PDE_USER = 0x04,
PDE_WRITE_THROUGH = 0x08,
PDE_CACHE_DISABLE = 0x10,
PDE_ACCESSED = 0x20,
PDE_DIRTY = 0x40, // Only with 4MB pages
PDE_PAGE_SIZE = 0x80, // Is page 4MB
PDE_GLOBAL = 0x100,
PDE_PAT = 0x2000,
PDE_FRAME = 0x7ffff000,
} PAGE_DIR_FLAGS;
typedef struct {
ptEntry_t entries[PAGES_PER_TABLE];
} pageTable_t;
typedef struct {
pdEntry_t entries[TABLES_PER_DIRECTORY];
} pageDirectory_t;
extern pageDirectory_t* currentPd;
ptEntry_t* getPtEntry(pageTable_t* pt, uint32_t virtualAddress);
pdEntry_t* getPdEntry(pageDirectory_t* pd, uint32_t virtualAddress);
ptEntry_t* getPage(uint32_t virtualAddress);
void* allocPage(ptEntry_t* page);
void freePage(ptEntry_t* page);
uint8_t setPageDirectory(pageDirectory_t* pd);
void flushTlbEntry(uint32_t virtualAddress);
uint8_t mapPage(void* physicalAddr, void* virtualAddr);
void unmapPage(void* virtualAddress);
uint8_t setupVirtualMemoryManager();
#endif
-72
View File
@@ -1,72 +0,0 @@
#ifndef _SCREEN_GFXMODE_H
#define _SCREEN_GFXMODE_H
#include <memory/addresses.h>
#include <stdint.h>
#define BG_COLOR 0x00010b17
#define FG_COLOR 0x00ebddf4
typedef struct modeInfoBlock_s {
// Required by all VBE revisions
uint16_t modeAttr;
uint8_t windowAAtrr;
uint8_t windowBAttr;
uint16_t windowGranularity;
uint16_t windowSize;
uint16_t windowASegment;
uint16_t windowBSegment;
uint32_t windowFunctionPtr;
uint16_t bytesPerScanline;
// Required by VBE 1.2+
uint16_t xRes;
uint16_t yRes;
uint8_t xCharSize;
uint8_t yCharSize;
uint8_t planeCount;
uint8_t bpp;
uint8_t bankCount;
uint8_t memoryModel;
uint8_t bankSize;
uint8_t imagePageCount;
uint8_t reserved1;
// Direct color fields
uint8_t redMaskSize;
uint8_t redFieldPos;
uint8_t greenMaskSize;
uint8_t greenFieldPos;
uint8_t blueMaskSize;
uint8_t blueFieldPos;
uint8_t reservedMaskSize;
uint8_t reservedFieldPos;
uint8_t directColorModeInfo;
// Required by VBE 2.0+
uint32_t physicalBasePtr;
uint32_t reserved2;
uint16_t reserved3;
// Required by VBE 3.0+
uint16_t linearBytesPerScanline;
uint8_t bankImagePageCount;
uint8_t linearImagePageCount;
uint8_t linearRedMaskSize;
uint8_t linearRedFieldPos;
uint8_t linearGreenMaskSize;
uint8_t linearGreenFieldPos;
uint8_t linearBlueMaskSize;
uint8_t linearBlueFieldPos;
uint8_t linearReservedMaskSize;
uint8_t linearReservedFieldPos;
uint32_t maxPixelClock;
uint8_t reserved4[190];
} __attribute__ ((packed)) modeInfoBlock_t;
extern modeInfoBlock_t* gfxMode;
uint32_t convertColor(uint32_t color);
#endif
-18
View File
@@ -1,18 +0,0 @@
#ifndef _SCREEN_GRAPHICS_H
#define _SCREEN_GRAPHICS_H
#include <stdint.h>
#define rgb(_r,_g,_b) ( ((_r) << 16 | (_g) << 8 | (_b)) & 0x00ffffff )
void drawPixel(int32_t x, int32_t y, uint32_t color);
void drawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color);
void drawRect(int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color);
void drawTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, uint32_t color);
void drawCircle(int32_t x, int32_t y, uint16_t radius, uint32_t color);
void boundaryFill(int32_t x, int32_t y, uint32_t fillColor, uint32_t boundaryColor);
void fillRect(int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color);
void fillTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, uint32_t color);
void fillCircle(int32_t x, int32_t y, uint16_t radius, uint32_t color);
#endif
-18
View File
@@ -1,18 +0,0 @@
#ifndef _SCREEN_TEXT_H
#define _SCREEN_TEXT_H
#include <stdint.h>
typedef union {
struct {
uint8_t width;
uint8_t height;
};
uint8_t data[4096];
} __attribute__ ((packed)) font_t;
void drawChar(char c, uint32_t x, uint32_t y, uint32_t fgColor, uint32_t bgColor);
void scroll();
void clearScreen(uint32_t bgColor);
#endif
-23
View File
@@ -1,23 +0,0 @@
#ifndef _SCREEN_TTY_H
#define _SCREEN_TTY_H
#include <stdint.h>
#include <stdbool.h>
struct console {
uint32_t x; // X Position of cursor in characters
uint32_t y; // Y Position of cursor in characters
uint32_t bg; // Printed character background
uint32_t fg; // Printed character foreground
uint32_t width; // Width in characters
uint32_t height; // Height in characters
char cursorChar; // Character to use as a cursor
bool hideCursor; // Should we display the cursor
}
extern struct console* console;
int32_t consoleWrite(const void* buf, uint32_t len);
void toggleCursor();
#endif
-19
View File
@@ -1,19 +0,0 @@
#ifndef _SYSCALLS_SYSCALLS_H
#define _SYSCALLS_SYSCALLS_H
#include <cpu/isr.h>
int sys_exit (intFrame_t* iframe);
int sys_read (intFrame_t* iframe);
int sys_write (intFrame_t* iframe);
int sys_open (intFrame_t* iframe);
int sys_close (intFrame_t* iframe);
int sys_seek (intFrame_t* iframe);
int sys_malloc (intFrame_t* iframe);
int sys_free (intFrame_t* iframe);
int sys_sleep (intFrame_t* iframe);
// Main syscall handler/dispatcher
int syscallHandler(intFrame_t* iframe);
#endif
-17
View File
@@ -1,17 +0,0 @@
#
# Kernel library
#
include make.defaults
LIBK_ASM=$(LIBK_DIR)/cpu/isr.s
$(LIBK): $(LIBK_SRC) $(LIBK_ASM) $(LIBC)
@echo "Building $(LIBK)..."
nasm -felf32 -o $(BIN)/libk/isr_asm.o $(LIBK_ASM)
for f in $(LIBK_SRC); do\
filename=$$(basename $$f .c);\
$(CC) $(CFLAGS) -I$(LIBC_INC) -I$(LIBK_INC) -o $(BIN)/libk/$$filename.o -c $$f;\
done
$(LD) $(LDFLAGS) -r -o $(LIBK) $(LIBC) $(BIN)/libk/**.o
-114
View File
@@ -1,114 +0,0 @@
#include <memory/virtual.h>
#include <memory/physical.h>
#include <memory/malloc.h>
#include <stdbool.h>
#include <stdint.h>
mallocNode_t* mallocListHead = NULL;
uint32_t mallocVirtualAddr = 0;
uint32_t mallocPhysicalAddr = 0;
uint32_t mallocPages = 0;
void mallocInit(uint32_t size) {
mallocPages = size / PAGE_SIZE;
if (size % PAGE_SIZE > 0) { mallocPages++; }
mallocPhysicalAddr = (uint32_t)allocBlocks(mallocPages);
mallocListHead = (mallocNode_t*)mallocVirtualAddr;
// Map pages
for (uint32_t i = 0, virtualAddr = mallocVirtualAddr; i < mallocPages; i++, virtualAddr += PAGE_SIZE) {
mapPage((void*)(mallocPhysicalAddr + i * PAGE_SIZE), (void*)virtualAddr);
ptEntry_t* page = getPage(virtualAddr);
SET_ATTR(page, PTE_READ_WRITE);
}
if (mallocListHead) {
mallocListHead->size = (mallocPages * PAGE_SIZE) - sizeof(mallocNode_t);
mallocListHead->free = true;
mallocListHead->next = NULL;
}
}
void mallocSplit(mallocNode_t* node, uint32_t size) {
if (node->size < size + sizeof(mallocNode_t)) { return; } // Can't split - node too small
// Remainder node
mallocNode_t* newNode = (mallocNode_t*)((void*)node + size + sizeof(mallocNode_t));
newNode->size = node->size - size - sizeof(mallocNode_t);
newNode->free = true;
newNode->next = node->next;
// Split node
node->size = size;
node->free = false;
node->next = newNode;
}
void* mallocNextNode(uint32_t size) {
if (size == 0) { return NULL; } // Why would you try that? (undefined behaviour i guess)
mallocNode_t* current = mallocListHead;
if (mallocListHead->size == 0) { mallocInit(size); }
while (((current->size < size) || !current->free) && current->next != NULL) {
current = current->next;
}
if (current->size == size) {
current->free = false;
} else if (current->size > size + sizeof(mallocNode_t)) {
mallocSplit(current, size); // Modifies current into the right size and makes it point to the remainder
} else { // There's no large enough node -> try to allocate more pages
uint8_t pageCount = 1;
while (current->size + pageCount * PAGE_SIZE < size + sizeof(mallocNode_t)) {
pageCount++;
}
// Allocate and map new pages
uint32_t virtualAddr = mallocVirtualAddr + mallocPages * PAGE_SIZE;
for (uint32_t i = 0; i < pageCount; i++) {
ptEntry_t page = 0;
uint32_t* temp = allocPage(&page);
mapPage((void*)temp, (void*)virtualAddr);
SET_ATTR(&page, PTE_READ_WRITE);
virtualAddr += PAGE_SIZE;
current->size += PAGE_SIZE;
mallocPages++;
}
mallocSplit(current, size);
}
return (void*)current + sizeof(mallocNode_t);
}
void mallocMergeFree() {
mallocNode_t* current = mallocListHead;
while (current && current->next != NULL) {
if (current->free && current->next->free) {
current->size += (current->next->size) + sizeof(mallocNode_t);
current->next = current->next->next;
}
current = current->next;
}
}
void mallocFree(void* ptr) {
mallocNode_t* current = mallocListHead;
while (current->next) {
if ((void*)current + sizeof(mallocNode_t) == ptr) {
current->free = true;
mallocMergeFree();
break;
}
current = current->next;
}
}
-122
View File
@@ -1,122 +0,0 @@
#include <memory/physical.h>
#include <memory/addresses.h>
#include <string.h>
#include <stdint.h>
uint32_t* memoryMap = 0;
uint32_t maxBlocks;
uint32_t usedBlocks = 0;
void setBlock(uint32_t block) {
// Set the right bit to 1
memoryMap[block/32] |= (1 << (block % 32));
}
void unsetBlock(uint32_t block) {
// Set the right bit to 0
memoryMap[block/32] &= ~(1 << (block % 32));
}
uint8_t testBlock(uint32_t block) {
// Check the bit
return memoryMap[block/32] & (1 << (block % 32)) ? 1 : 0;
}
// TODO: Refactor whatever the fuck this is
int32_t findFreeBlocks(uint32_t blockCount) {
if (blockCount == 0) { // Error
return -1;
}
uint32_t maxBlockEntries = maxBlocks / 32;
for (uint32_t i = 0; i < maxBlockEntries; i++) {
if (memoryMap[i] != 0xffffffff) {
for (uint8_t j = 0; j < 32; j++) {
uint32_t block = 1 << j;
if (!(memoryMap[i] & block)) {
// uint32_t startBlock = i * 32 + block;
// uint32_t freeBlocks = 0;
for (uint32_t count = i, freeBlocks = 0; count < blockCount; count++) {
if (j + count > 31 && i + 1 <= maxBlocks / 32) {
if (!(memoryMap[i+1] & (1 << (j + count)))) {
freeBlocks++;
}
} else {
if (!(memoryMap[i] & (1 << (j + count)))) {
freeBlocks++;
}
}
if (freeBlocks == blockCount) {
return i * 32 + j;
}
}
}
}
}
}
return -1; // No free memory found :/
}
void setupPhysicalMemoryManager(uint32_t startAddress, uint32_t size) {
memoryMap = (uint32_t*)startAddress;
maxBlocks = size / BLOCK_SIZE;
usedBlocks = maxBlocks;
memset((char*)memoryMap, 0xff, maxBlocks / BLOCKS_PER_BYTE);
}
void initMemoryRegion(uint32_t baseAddress, uint32_t size) {
uint32_t align = baseAddress / BLOCK_SIZE;
uint32_t blockCount = size / BLOCK_SIZE;
while (blockCount-- > 0) {
unsetBlock(align++);
usedBlocks--;
}
setBlock(0); // Make sure we don't override the first block that contains IDT, BIOS stuff etc.
}
void deinitMemoryRegion(uint32_t baseAddress, uint32_t size) {
uint32_t align = baseAddress / BLOCK_SIZE;
uint32_t blockCount = size / BLOCK_SIZE;
while (blockCount-- > 0) {
setBlock(align++);
usedBlocks++;
}
}
void* allocBlocks(uint32_t blockCount) {
if ((maxBlocks - usedBlocks) < blockCount) {
return NULL;
}
int32_t startBlock = findFreeBlocks(blockCount);
if (startBlock == -1) {
return NULL;
}
for (uint32_t i = 0; i < blockCount; i++) {
setBlock(startBlock + i);
usedBlocks++;
}
return (void*)(startBlock * BLOCK_SIZE);
}
void freeBlocks(void* address, uint32_t blockCount) {
uint32_t startBlock = (uint32_t)(address) / BLOCK_SIZE;
for (uint32_t i = 0; i < blockCount; i++) {
unsetBlock(startBlock + i);
usedBlocks--;
}
setBlock(0); // Make sure that block 0 is always set
}
-153
View File
@@ -1,153 +0,0 @@
#include <memory/virtual.h>
#include <memory/physical.h>
#include <memory/addresses.h>
#include <string.h>
#include <stdint.h>
pageDirectory_t* currentPd = NULL;
ptEntry_t* getPtEntry(pageTable_t* pt, uint32_t virtualAddress) {
if (pt) return &pt->entries[PT_INDEX(virtualAddress)];
return NULL;
}
pdEntry_t* getPdEntry(pageDirectory_t* pd, uint32_t virtualAddress) {
if (pd) return &pd->entries[PT_INDEX(virtualAddress)]; // It it supposed to be PT_INDEX, don't worry
return NULL;
}
ptEntry_t* getPage(uint32_t virtualAddress) {
pageDirectory_t* pd = currentPd;
pdEntry_t* entry = &pd->entries[PD_INDEX(virtualAddress)];
pageTable_t* table = (pageTable_t*)PAGE_PHYS_ADDRESS(entry);
ptEntry_t* page = &table->entries[PT_INDEX(virtualAddress)];
return page;
}
void* allocPage(ptEntry_t* page) {
void* block = allocBlocks(1);
if (block) {
SET_FRAME(page, (uint32_t)block);
SET_ATTR(page, PTE_PRESENT);
}
return block;
}
void freePage(ptEntry_t* page) {
void* address = (void*)PAGE_PHYS_ADDRESS(page);
if (address) {
freeBlocks(address, 1);
}
CLEAR_ATTR(page, PTE_PRESENT);
}
uint8_t setPageDirectory(pageDirectory_t* pd) {
if (!pd) { return 1; } // Nuh uh
currentPd = pd;
// cr3 (Control register 3) - current page dir address
__asm__ volatile("movl %%eax, %%cr3" : : "a"(currentPd));
return 0; // Success
}
void flushTlbEntry(uint32_t virtualAddress) {
__asm__ volatile("cli; invlpg (%0); sti" : : "r"(virtualAddress));
}
uint8_t mapPage(void* physicalAddr, void* virtualAddr) {
pageDirectory_t* pd = currentPd;
pdEntry_t* entry = &pd->entries[PD_INDEX((uint32_t)virtualAddr)];
if (!TEST_ATTR(entry, PTE_PRESENT)) {
// Assuming that the page is not allocated since it's not present
pageTable_t* table = (pageTable_t*)allocBlocks(1);
if (!table) return 1; // Out of memory!!
// Clear page table (may be slow?)
memset(table, 0, sizeof(pageTable_t));
pdEntry_t* entry = &pd->entries[PD_INDEX((uint32_t)virtualAddr)];
// Enable attributes and map in table
SET_ATTR(entry, PDE_PRESENT);
SET_ATTR(entry, PDE_READ_WRITE);
SET_FRAME(entry, (uint32_t)table);
}
pageTable_t* table = (pageTable_t*)PAGE_PHYS_ADDRESS(entry);
ptEntry_t* page = &table->entries[PT_INDEX((uint32_t)virtualAddr)];
SET_ATTR(page, PTE_PRESENT);
SET_FRAME(page, (uint32_t)physicalAddr);
return 0; // Success
}
void unmapPage(void* virtualAddress) {
ptEntry_t* page = getPage((uint32_t)virtualAddress);
SET_FRAME(page, 0);
CLEAR_ATTR(page, PDE_PRESENT);
}
uint8_t setupVirtualMemoryManager() {
// Create a default page dir
pageDirectory_t* dir = (pageDirectory_t*)allocBlocks(3);
if (!dir) { return 1; } // Out of memory
memset(dir, 0, sizeof(pageDirectory_t));
for (uint32_t i = 0; i < 1024; i++) {
dir->entries[i] = 0x02; // Supervisor, r/w, not present
}
// Alloc default page table
pageTable_t* table = (pageTable_t*)allocBlocks(1);
if (!table) { return 1; } // Out of memory
// Alloc a 3GB page
pageTable_t* table3gb = (pageTable_t*)allocBlocks(1);
if (!table) { return 1; } // Out of memory
memset(table, 0, sizeof(pageTable_t));
memset(table3gb, 0, sizeof(pageTable_t));
// Identity map first 4MB
for (uint32_t i = 0, frame = 0, virt = 0; i < 1024; i++, frame += PAGE_SIZE, virt += PAGE_SIZE) {
ptEntry_t page = 0;
SET_ATTR(&page, PTE_PRESENT);
SET_ATTR(&page, PTE_READ_WRITE);
SET_FRAME(&page, frame);
table3gb->entries[PT_INDEX(virt)] = page;
}
// Map kernel to 3GB+
for (uint32_t i = 0, frame = KERNEL_LOC, virt = 0xc0000000; i < 1024; i++, frame += PAGE_SIZE, virt += PAGE_SIZE) {
ptEntry_t page = 0;
SET_ATTR(&page, PTE_PRESENT);
SET_ATTR(&page, PTE_READ_WRITE);
SET_FRAME(&page, frame);
table->entries[PT_INDEX(virt)] = page;
}
pdEntry_t* entry = &dir->entries[PD_INDEX(0xc0000000)];
SET_ATTR(entry, PDE_PRESENT);
SET_ATTR(entry, PDE_READ_WRITE);
SET_FRAME(entry, (uint32_t)table);
pdEntry_t* entry2 = &dir->entries[PD_INDEX(0x00000000)];
SET_ATTR(entry2, PDE_PRESENT);
SET_ATTR(entry2, PDE_READ_WRITE);
SET_FRAME(entry2, (uint32_t)table3gb);
setPageDirectory(dir);
// ENABLE PAGING!!! Set PG bit 31 and PE bit 0 in cr0
__asm__ volatile("movl %cr0, %eax; orl $0x80000001, %eax; movl %eax, %cr0");
return 0; // Success
}
-20
View File
@@ -1,20 +0,0 @@
#include <screen/gfxmode.h>
#include <memory/addresses.h>
#include <stdint.h>
modeInfoBlock_t* gfxMode = (modeInfoBlock_t*)MODE_INFO_BLOCK_LOC;
uint32_t convertColor(uint32_t color) {
if (gfxMode->bpp == 8) { // Uses VGA Color pallete, idk how to support that
return color & 0xff;
}
// TODO: !! Important !! - Is should be divided by 255.0 (for floats), but using '-mgeneral-regs-only' removes fp-registers and
// wants to use some dumb functions for converting fp numbers in the stdlib (that we don't have)
uint8_t red = ((color >> 16) & 0xff) * (((1 << gfxMode->linearRedMaskSize) - 1) / 255);
uint8_t green = ((color >> 8 ) & 0xff) * (((1 << gfxMode->linearGreenMaskSize) - 1) / 255);
uint8_t blue = ((color ) & 0xff) * (((1 << gfxMode->linearBlueMaskSize) - 1) / 255);
return (red << gfxMode->redFieldPos) | (green << gfxMode->greenFieldPos) | (blue << gfxMode->blueFieldPos);
}
-143
View File
@@ -1,143 +0,0 @@
#include <screen/graphics.h>
#include <screen/text.h>
#include <screen/gfxmode.h>
#include <stdint.h>
#include <math.h>
void drawPixel(int32_t x, int32_t y, uint32_t color) {
uint8_t* vidmem = (uint8_t*)gfxMode->physicalBasePtr;
uint8_t bytesPerPx = gfxMode->bpp / 8;
uint32_t convColor = convertColor(color); // Idk if i should convert this for every px or just put in a preconverted color
uint32_t offset = ((y * gfxMode->xRes) + x) * bytesPerPx;
for (uint8_t i = 0; i < bytesPerPx; i++) {
vidmem[offset + i] = (uint8_t)(convColor >> (i*8));
}
}
// Source: https://en.wikipedia.org/wiki/Bresenham's_line_algorithm
void drawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color) {
int32_t dx = abs(x2 - x1);
int32_t dy = -abs(y2 - y1);
int8_t sx = (x1 < x2) ? 1 : -1;
int8_t sy = (y1 < y2) ? 1 : -1;
int16_t err = dx + dy;
// TODO: Sometimes the condition isn't met for some reason and it breaks everything
while (!(x1 == x2 && y1 == y2)) {
drawPixel(x1, y1, color);
if (err * 2 >= dy) {
err += dy;
x1 += sx;
}
if (err * 2 <= dx) {
err += dx;
y1 += sy;
}
}
}
void drawRect(int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color) {
drawLine(x1, y1, x2, y1, color);
drawLine(x2, y1, x2, y2, color);
drawLine(x2, y2, x1, y2, color);
drawLine(x1, y2, x1, y1, color);
}
void drawTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, uint32_t color) {
drawLine(x1, y1, x2, y2, color);
drawLine(x2, y2, x3, y3, color);
drawLine(x3, y3, x1, y1, color);
}
void drawCircle(int32_t x, int32_t y, uint16_t radius, uint32_t color) {
int16_t offX = 0;
int16_t offY = radius;
int16_t p = 1 - radius;
// Draw 8 octant points
drawPixel(x + offX, y + offY, color);
drawPixel(x - offX, y + offY, color);
drawPixel(x + offX, y - offY, color);
drawPixel(x - offX, y - offY, color);
drawPixel(x + offY, y + offX, color);
drawPixel(x - offY, y + offX, color);
drawPixel(x + offY, y - offX, color);
drawPixel(x - offY, y - offX, color);
while (offX < offY) {
offX++;
if (p < 0) p += 2 * offX + 1;
else {
offY--;
p += 2 * (offX - offY) + 1;
}
drawPixel(x + offX, y + offY, color);
drawPixel(x - offX, y + offY, color);
drawPixel(x + offX, y - offY, color);
drawPixel(x - offX, y - offY, color);
drawPixel(x + offY, y + offX, color);
drawPixel(x - offY, y + offX, color);
drawPixel(x + offY, y - offX, color);
drawPixel(x - offY, y - offX, color);
}
}
// Recursive (may need large stack)
// TODO: Fix this for all bpp values
void boundaryFill(int32_t x, int32_t y, uint32_t fillColor, uint32_t boundaryColor) {
uint8_t* vidmem = (uint8_t*)gfxMode->physicalBasePtr;
uint8_t bytesPerPx = (gfxMode->bpp+1) / 8;
uint32_t convColorF = convertColor(fillColor);
uint32_t convColorB = convertColor(boundaryColor);
uint32_t offset = (y * gfxMode->xRes + x) * bytesPerPx;
uint8_t draw = 0;
for (uint8_t i = 0; i < bytesPerPx; i++) {
if (vidmem[offset + i] != (uint8_t)(convColorF >> (i*8)) && vidmem[offset + i] != (uint8_t)(convColorB >> (i*8))) {
draw = 1;
break;
}
}
if (draw) {
for (uint8_t i = 0; i < bytesPerPx; i++) {
vidmem[offset + i] = (uint8_t)(convColorF >> (i*8));
}
boundaryFill(x + 1, y, fillColor, boundaryColor);
boundaryFill(x, y + 1, fillColor, boundaryColor);
boundaryFill(x - 1, y, fillColor, boundaryColor);
boundaryFill(x, y - 1, fillColor, boundaryColor);
}
}
// TODO: After i fix boundary fill, uncomment it from these functions
void fillRect(int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color) {
int32_t cx = (x1 + x2) / 2;
int32_t cy = (y1 + y2) / 2;
drawRect(x1, y1, x2, y2, color - 1);
boundaryFill(cx, cy, color, color - 1);
drawRect(x1, y1, x2, y2, color);
}
void fillTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, uint32_t color) {
int32_t cx = (x1 + x2 + x3) / 3;
int32_t cy = (y1 + y2 + y3) / 3;
drawTriangle(x1, y1, x2, y2, x3, y3, color - 1);
boundaryFill(cx, cy, color, color - 1);
drawTriangle(x1, y1, x2, y2, x3, y3, color);
}
void fillCircle(int32_t x, int32_t y, uint16_t radius, uint32_t color) {
drawCircle(x, y, radius, color - 1);
// boundaryFill(x, y, color, color - 1); TODO: It just doesn't feel like working here and hangs
drawCircle(x, y, radius, color);
}
-91
View File
@@ -1,91 +0,0 @@
#include <screen/text.h>
#include <screen/gfxmode.h>
#include <screen/tty.h>
#include <memory/addresses.h>
#include <stdint.h>
#include <string.h>
// TODO: Reimplement larger text
void drawChar(char c, uint32_t x, uint32_t y, uint32_t fgColor, uint32_t bgColor) {
// Font info
font_t* font = (font_t*)FONT_LOC;
uint8_t charWidth = font->width;
uint8_t charHeight = font->height;
// uint8_t bitmapRowLen = (charWidth - 1) / 8 + 1; // TODO: Larger font support
// Video stuff
uint8_t bytesPerPx = (gfxMode->bpp+7) / 8;
uint8_t* vidmem = (uint8_t*)gfxMode->physicalBasePtr;
uint32_t offset = (gfxMode->xRes * y * charHeight + x * charWidth) * bytesPerPx;
uint8_t* bitmap = &font->data[(c - 1) * charHeight];
for (uint8_t i = 0; i < charHeight; i++) { // Rows
uint8_t bitmapRow = bitmap[i];
uint32_t color = convertColor((bitmapRow & 0x80) ? fgColor : bgColor);
for (uint8_t j = 0; j < charWidth * bytesPerPx; ++j) { // Cols
uint8_t byte = j % bytesPerPx;
vidmem[offset + j] = (uint8_t)(color >> (8 * byte));
if (byte == bytesPerPx - 1) {
bitmapRow = bitmapRow << 1;
color = convertColor((bitmapRow & 0x80) ? fgColor : bgColor);
}
}
offset += gfxMode->linearBytesPerScanline; // gfxMode->xRes * bytesPerPx
}
}
void scroll() { // TODO: Make this faster (still kinda slow, but memcpy32() helped alot)
uint8_t charHeight = ((font_t*)FONT_LOC)->height;
if (console->y+1 < console->height) { return; } // Check if we should scroll
uint32_t bytesPerLine = charHeight * gfxMode->bytesPerScanline;
uint32_t lines = console->height;
uint32_t vidmem = gfxMode->physicalBasePtr;
for (uint32_t i = 1; i < lines; i++) {
uint32_t address = vidmem + i * bytesPerLine;
memcpy32((char*)address, (char*)(address - bytesPerLine), bytesPerLine);
}
uint32_t color = convertColor(console->bg);
uint8_t* lastLine = (uint8_t*)(vidmem + (lines-1) * bytesPerLine);
uint8_t bytesPerPx = (gfxMode->bpp+1) / 8;
for (uint32_t i = 0; i < bytesPerLine; i++) {
for (uint8_t j = 0; j < bytesPerPx; j++) {
lastLine[j] = (uint8_t)(color >> (j * 8));
}
lastLine += bytesPerPx;
}
console->y--;
}
// TODO: Make this comply with the new console.h thing!
void clearScreen(uint32_t bgColor) {
uint8_t* vidmem = (uint8_t*)gfxMode->physicalBasePtr;
uint8_t bytesPerPx = (gfxMode->bpp+1) / 8;
console->x = 0;
console->y = 0;
uint32_t color = convertColor(bgColor);
for (uint32_t i = 0; i < gfxMode->xRes; i++) { // Clear one line of pixels
for (uint8_t j = 0; j < bytesPerPx; j++) {
vidmem[j] = (uint8_t)(color >> (j * 8));
}
vidmem += bytesPerPx;
}
vidmem -= gfxMode->bytesPerScanline;
for (uint32_t i = 0; i < gfxMode->yRes; i++) { // Copy that line to clear the entire screen (using memcpy32 is fast!)
memcpy32(vidmem, vidmem + gfxMode->bytesPerScanline, gfxMode->bytesPerScanline);
vidmem += gfxMode->bytesPerScanline;
}
}
-129
View File
@@ -1,129 +0,0 @@
#include <screen/tty.h>
#include <screen/gfxmode.h>
#include <screen/text.h>
#include <memory/addresses.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <sys/gfx.h>
console_t* console = (console_t*)CONSOLE_INFO_LOC;
int32_t consoleWrite(const void* buf, uint32_t len) { // TODO fix font size
console->width = gfxMode->xRes / 8;//*(uint8_t*)(FONT_LOC);
console->height = gfxMode->yRes / 16;//*(uint8_t*)(FONT_LOC+1);
char* str = (char*)buf;
uint32_t i;
// Do we need to check for NULL? Can we just skip it/ignore it?
for (i = 0; i < len && str[i] != '\0'; i++) {
if (str[i] == '\n') {
drawChar(' ', console->x, console->y, console->fg, console->bg);
console->y++;
console->x = 0;
} else if (str[i] == '\b') {
drawChar(' ', console->x, console->y, console->fg, console->bg);
if (console->x == 0) {
console->x = console->width - 1;
console->y--; // Y could be 0?
} else {
console->x--;
}
drawChar(' ', console->x, console->y, console->fg, console->bg);
} else if (str[i] == '\x1b') { // Escape sequence
if (str[++i] != '[') { // TODO: Support more types of escape sequences
i--;
continue;
}
i++;
uint32_t args[8] = { 0 };
uint8_t argc = 0;
while (1) { // I'm not 100% sure this works, but i'd like to imagine it does
if (argc > 8) break; // Max arg count? idk
uint32_t value = atoi(&str[i]);
args[argc++] = value;
while (value != 0) { // Skip by the number string
value /= 10;
i++;
}
if (str[i] != ';') break;
i++;
}
switch (str[i]) { // TODO: Add default values (see docs/escape.txt)
case 'A': // Cursor up
console->y -= args[0];
break;
case 'B': // Cursor down
console->y += args[0];
break;
case 'C': // Cursor left
console->x -= args[0];
break;
case 'D': // Cursor right
console->x += args[0];
break;
case 'E': // nth row
console->x = args[0];
break;
case 'F': // nth col
console->y = args[0];
break;
case 'G': // show/hide cursor
console->hideCursor = args[0] ? false : true;
break;
case 'H': // move cursor to (x,y)
console->x = args[0];
console->y = args[1];
break;
case 'I': // RESERVED
case 'J': // Erase screen
clearScreen(console->bg);
break;
case 'K': // Erase line
break; // TODO
case 'L': // Erase collumn
break; // TODO
case 'M': // Set FG
if (args[0] < 8) {
console->fg = codeToColor(args[0]);
} else if (args[0] == 8) {
console->fg = FG_COLOR;
}
break;
case 'N': // Set BG
if (args[0] < 8) {
console->bg = codeToColor(args[0]);
} else if (args[0] == 8) {
console->bg = BG_COLOR;
}
break;
default: break;
}
} else {
drawChar(str[i], console->x, console->y, console->fg, console->bg);
console->x++;
if (console->x >= console->width) { // Go to next line
console->y++;
console->x = 0;
}
}
}
scroll();
return i; // Number of characters that were printed
}
void toggleCursor() {
static bool visible = false;
visible = !visible;
drawChar(visible ? 127 : ' ', console->x, console->y, console->fg, console->bg);
}
-9
View File
@@ -1,9 +0,0 @@
#include <syscalls/syscalls.h>
#include <cpu/isr.h>
#include <stdio.h>
int sys_close(intFrame_t* iframe) {
// TODO
return -1;
}
-9
View File
@@ -1,9 +0,0 @@
#include <syscalls/syscalls.h>
#include <drivers/serial.h>
#include <cpu/isr.h>
int sys_exit(intFrame_t* iframe) {
debugf("Tried to exit with %d", iframe->eax);
return iframe->eax;
}
-10
View File
@@ -1,10 +0,0 @@
#include <syscalls/syscalls.h>
#include <memory/malloc.h>
#include <cpu/isr.h>
int sys_free(intFrame_t* iframe) {
void* ptr = (void*)iframe->ebx;
mallocFree(ptr);
return 0;
}
-18
View File
@@ -1,18 +0,0 @@
#include <syscalls/syscalls.h>
#include <memory/malloc.h>
#include <cpu/isr.h>
#include <stddef.h>
int sys_malloc(intFrame_t* iframe) {
size_t count = iframe->ebx;
// First Malloc()
if (!mallocListHead) {
mallocInit(count); // Setup malloc linked list
}
void* ptr = mallocNextNode(count);
mallocMergeFree();
return (size_t)ptr;
}
-9
View File
@@ -1,9 +0,0 @@
#include <syscalls/syscalls.h>
#include <cpu/isr.h>
#include <stdio.h>
int sys_open(intFrame_t* iframe) {
// TODO
return -1;
}
-11
View File
@@ -1,11 +0,0 @@
#include <syscalls/syscalls.h>
#include <cpu/isr.h>
#include <stdio.h>
int sys_read(intFrame_t* iframe) {
char* s = (char*)iframe->ebx;
gets(s, 0xffffffff);
return 0;
}
-8
View File
@@ -1,8 +0,0 @@
#include <syscalls/syscalls.h>
#include <cpu/isr.h>
int sys_seek(intFrame_t* iframe) {
// TODO
return -1;
}
-14
View File
@@ -1,14 +0,0 @@
#include <syscalls/syscalls.h>
#include <memory/addresses.h>
#include <cpu/isr.h>
#include <stdint.h>
int sys_sleep(intFrame_t* iframe) {
uint32_t* sleepTimerTicks = (uint32_t*)SLEEP_TIMER;
*sleepTimerTicks = iframe->ebx;
while (*sleepTimerTicks > 0) { __asm__ volatile ("sti; hlt"); }
return 0;
}
-15
View File
@@ -1,15 +0,0 @@
#include <syscalls/syscalls.h>
#include <screen/tty.h>
#include <cpu/isr.h>
#include <stddef.h>
int sys_write(intFrame_t* iframe) {
int fd = iframe->ebx;
void* buf = (void*)iframe->ecx;
size_t len = iframe->edx;
if (fd == 1) {
return consoleWrite(buf, len);
} else { return -1; }
}
-28
View File
@@ -1,28 +0,0 @@
#include <syscalls/syscalls.h>
#include <drivers/serial.h>
#include <cpu/isr.h>
#include <syscall.h>
// System call table
int (*syscalls[SYSCALL_COUNT])(intFrame_t*) = {
[SYS_EXIT] = sys_exit,
[SYS_READ] = sys_read,
[SYS_WRITE] = sys_write,
[SYS_OPEN] = sys_open,
[SYS_CLOSE] = sys_close,
[SYS_SEEK] = sys_seek,
[SYS_MALLOC] = sys_malloc,
[SYS_FREE] = sys_free,
[SYS_SLEEP] = sys_sleep,
};
// Syscall handler
int syscallHandler(intFrame_t* iframe) {
if (iframe->eax > SYSCALL_COUNT-1) { // Syscall doesn't exist
debugf("Error: Syscall(%d) does not exist!\n", iframe->eax);
return -1;
}
return syscalls[iframe->eax](iframe);
}
-48
View File
@@ -1,48 +0,0 @@
#
# Makefile variables
#
# Tools
HOSTCC = cc
CC = i686-elf-gcc
LD = i686-elf-ld
AS = nasm
MAKE = make
# Flags
CFLAGS = -Wall -Wextra -Wno-pointer-sign -Wno-pointer-arith -Wno-unused-parameter\
-Os -std=c17 -nostdinc -g -Werror\
-ffreestanding -fno-stack-protector -fno-builtin -fno-pie -fcommon\
-m32 -march=i386
LDFLAGS = -z notext -nostdlib -melf_i386
ASFLAGS =
# Directories
BIN = ./bin
IMG = kern.img
# Kernel
KERNEL = $(BIN)/kernel.bin
KERNEL_DIR = ./kernel
KERNEL_SRC = $(KERNEL_DIR)/kernel.c
# Bootloader
BOOTSECT = $(BIN)/bootsect.bin
BOOTLOAD = $(BIN)/bootload.bin
BOOT_DIR = ./boot
BOOT_SRC_ASM = $(shell find $(BOOT_DIR) -type f -name "**.s")
BOOT_SRC_C = $(shell find $(BOOT_DIR) -type f -name "**.c")
# Libc
LIBC = $(BIN)/libc.o
LIBC_DIR = ./libc
LIBC_SRC = $(shell find $(LIBC_DIR) -type f -name "**.c")
# Userspace
FONT_DIR = ./usr/fonts
FONTS = testfont term16n
# Include directories
LIBC_INC = $(LIBC_DIR)/include
KERNEL_INC = $(KERNEL_DIR)/include
-268
View File
@@ -1,268 +0,0 @@
// A utility to build the disk
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <fs.h>
#define IMAGE_NAME "kern.img"
#define BIN_DIR "./bin/"
#define DISK_SIZE (2880 * 512) // 1.44MB
uint8_t nullBlock[FS_BLOCK_SIZE] = { 0 };
typedef struct {
char name[60];
uint32_t size;
FILE* fp;
} fileInfo_t;
fileInfo_t files[] = { // TODO: Not have to list all of the files, loop through a directory or smth
/* Bootloader */
{ BIN_DIR"stage1.bin" },
{ BIN_DIR"stage2.bin" },
{ BIN_DIR"stage3.bin" },
/* Kernel stuff */
{ BIN_DIR"kernel.bin" },
{ BIN_DIR"term16n.fnt" },
{ BIN_DIR"testfont.fnt" },
/* Userspace files */
{ "./usr/test.txt" },
//{ BIN_DIR"calc.bin" },
//{ BIN_DIR"edit.bin" },
};
superblock_t superblock = { 0 };
FILE* imagePtr;
uint32_t diskSize = DISK_SIZE;
uint32_t fileCount;
uint32_t fileBlocks = 0;
uint32_t dataBlocks;
uint32_t dataBitCount;
void writeBootblock();
void writeSuperblock();
void writeINodeBitmapBlocks();
void writeDataBitmapBlocks();
void writeINodeBlocks();
void writeDataBlocks();
uint32_t paddingBytes(uint32_t bytes, uint32_t bound) {
if (bytes % bound == 0) return 0;
return (bytes - (bytes % bound) + bound) - bytes;
}
int main(int argc, char** argv) {
imagePtr = fopen(IMAGE_NAME, "wb");
fileCount = sizeof(files) / sizeof(files[0]);
// Open files and get file info
for (int i = 0; i < fileCount; i++) {
files[i].fp = fopen(files[i].name, "rb");
fseek(files[i].fp, 0, SEEK_END);
files[i].size = ftell(files[i].fp);
rewind(files[i].fp);
fileBlocks += BYTES2BLOCKS(files[i].size);
}
printf("Building disk image %s...\n", IMAGE_NAME);
printf("Block size: %d Bytes, Total disk blocks: %d (%d Bytes)\n\n", FS_BLOCK_SIZE, BYTES2BLOCKS(diskSize), diskSize);
printf("%d files (2 hidden)\n", fileCount); // Stage 1 and 2 is hidden
// Build disk image
writeBootblock();
writeSuperblock();
writeINodeBitmapBlocks();
writeDataBitmapBlocks();
writeINodeBlocks();
writeDataBlocks();
uint32_t writtenBlocks = 4 + superblock.inodeBlockCount + superblock.dataBlockCount;
printf("\nWritten blocks: %d (%d Bytes)\n", writtenBlocks, writtenBlocks * FS_BLOCK_SIZE);
printf("Free blocks: %d (%d Bytes)\n", BYTES2BLOCKS(diskSize) - writtenBlocks, diskSize - writtenBlocks * FS_BLOCK_SIZE);
// Pad out to the whole disk size
for (uint32_t i = 0; i < BYTES2BLOCKS(diskSize) - writtenBlocks; i++) {
assert(fwrite(nullBlock, FS_BLOCK_SIZE, 1, imagePtr) == 1);
}
// Cleanup
for (uint32_t i = 0; i < fileCount; i++) {
fclose(files[i].fp);
}
fclose(imagePtr);
return 0;
}
void writeBootblock() {
bootblock_t bootBlock = { 0 };
assert(fread(bootBlock.sectors[0], FS_SECTOR_SIZE, 1, files[0].fp) == 1); // File 0 - Stage 1
for (uint8_t i = 1; i < BYTES2SECTORS(files[i].size); i++) {
if (i > 7) {
fprintf(stderr, "%s is too large, maximum size of bootblock is 7 sectors (%d Bytes)\n", files[1].name, 7 * FS_SECTOR_SIZE);
exit(1);
}
assert(fread(bootBlock.sectors[i], FS_SECTOR_SIZE, 1, files[1].fp) == 1); // File 1 - Stage 2
}
// Write bootblock to disk
for (uint8_t i = 0; i < FS_BLOCK_SIZE / FS_SECTOR_SIZE; i++) {
assert(fwrite(bootBlock.sectors[i], FS_SECTOR_SIZE, 1, imagePtr) == 1);
}
}
void writeSuperblock() {
/* Block Layout
* 0 - Boot
* 1 - Super
* 2 - INode Bitmap
* 3 - Data Bitmap
* 4 - First INode Block
*/
// Constant
superblock.deviceId = 0x01;
superblock.extentsPerIndirect = FS_BLOCK_SIZE / sizeof(extent_t);
superblock.maxFileSize = 0xffffffff;
superblock.inodesPerSector = (FS_SECTOR_SIZE / sizeof(inode_t));
// INode
superblock.inodeCount = fileCount + 2; // 2 reserved INodes (0 - Invalid, 1 - Root)
superblock.inodeBitmapBlock = 2;
superblock.inodesStart = 4;
superblock.inodeBlockCount = BYTES2BLOCKS(superblock.inodeCount * sizeof(inode_t));
// Data
dataBlocks = BYTES2BLOCKS(diskSize);
superblock.dataBitmapBlock = 3;
superblock.dataStart = superblock.inodesStart + superblock.inodeBlockCount;
superblock.dataBlockCount = fileBlocks; // +1 for Root, -1 for Boot
// Other
superblock.rootInodePtr = 0; // Will be filled at runtime
superblock.firstUnreservedInode = 3; // 0 - Invalid, 1 - Root, 2 - Bootloader
assert(fwrite(&superblock, sizeof(superblock_t), 1, imagePtr) == 1);
assert(fwrite(nullBlock, paddingBytes(sizeof(superblock_t), FS_BLOCK_SIZE), 1, imagePtr) == 1); // Padding
}
void writeINodeBitmapBlocks() {
uint8_t temp[FS_SECTOR_SIZE] = { 0 };
// Set number of bits = number of inodes
*(uint32_t*)temp |= (2 << (superblock.inodeCount - 1)) - 1;
assert(fwrite(temp, FS_SECTOR_SIZE, 1, imagePtr) == 1);
// Padd out
assert(fwrite(nullBlock, paddingBytes(FS_SECTOR_SIZE, FS_BLOCK_SIZE), 1, imagePtr) == 1);
}
void writeDataBitmapBlocks() {
uint64_t bitChunk = 0;
uint32_t totalBlocks = superblock.dataBlockCount / 32;
uint32_t bytesWritten = 0;
while (totalBlocks > 0) {
bitChunk = 0xffffffff;
totalBlocks--;
assert(fwrite(&bitChunk, 4, 1, imagePtr) == 1);
bytesWritten += 4;
}
bitChunk = (2 << ((superblock.dataBlockCount % 32) - 1)) - 1;
assert(fwrite(&bitChunk, 4, 1, imagePtr) == 1);
bytesWritten += 4;
assert(fwrite(nullBlock, paddingBytes(bytesWritten, FS_BLOCK_SIZE), 1, imagePtr) == 1);
}
void writeINodeBlocks() {
inode_t inode = { 0 };
// INode 0 - Invalid
assert(fwrite(&inode, sizeof(inode), 1, imagePtr) == 1);
// INode 1 - Root directory
inode.id = 1;
inode.type = FT_DIR;
inode.sizeBytes = sizeof(dirEntry_t) * fileCount;
inode.sizeSectors = BYTES2SECTORS(inode.sizeBytes);
// TODO: Mode
inode.extent[0].block = superblock.dataStart;
inode.extent[0].length = BYTES2BLOCKS(inode.sizeBytes);
assert(fwrite(&inode, sizeof(inode), 1, imagePtr) == 1);
// INode 2 - Bootloader (stage 3) followed by other INodes
uint32_t block = superblock.dataStart + inode.extent[0].length;
for (uint32_t i = 2; i < fileCount; i++) {
memset(&inode, 0, sizeof(inode));
inode.id = i;
inode.type = FT_FILE;
inode.sizeBytes = files[i].size;
inode.sizeSectors = BYTES2SECTORS(inode.sizeBytes);
inode.extent[0].block = block,
inode.extent[0].length = BYTES2BLOCKS(inode.sizeBytes);
assert(fwrite(&inode, sizeof(inode), 1, imagePtr) == 1);
block += inode.extent[0].length;
}
assert(fwrite(nullBlock, paddingBytes(fileCount * sizeof(inode_t), FS_BLOCK_SIZE), 1, imagePtr) == 1);
}
void writeDataBlocks() {
uint8_t sector[FS_SECTOR_SIZE] = { 0 };
dirEntry_t dirEntry = {
.id = 1,
.name = ".",
};
assert(fwrite(&dirEntry, sizeof(dirEntry), 1, imagePtr) == 1);
strcpy(dirEntry.name, "..");
assert(fwrite(&dirEntry, sizeof(dirEntry), 1, imagePtr) == 1);
for (uint32_t i = 2; i < fileCount; i++) {
dirEntry.id = i;
strcpy(dirEntry.name, strrchr(files[i].name, '/') + 1); // We skip the './build/'
assert(fwrite(&dirEntry, sizeof(dirEntry), 1, imagePtr) == 1);
}
// Pad out
assert(fwrite(nullBlock, paddingBytes(fileCount * sizeof(dirEntry_t), FS_BLOCK_SIZE), 1, imagePtr) == 1);
// Write actual file data
for (uint32_t i = 2; i < fileCount; i++) {
uint32_t blockCount = BYTES2BLOCKS(files[i].size);
uint32_t bytesWritten = 0;
printf("%s, %d Bytes -> %d Blocks\n", files[i].name, files[i].size, blockCount);
for (uint32_t j = 0; j < blockCount * (FS_BLOCK_SIZE / FS_SECTOR_SIZE); j++) {
uint32_t byteCount = fread(sector, 1, sizeof(sector), files[i].fp);
fwrite(sector, 1, byteCount, imagePtr);
bytesWritten += byteCount;
if (byteCount < sizeof(sector)) break; // EOF
}
memset(sector, 0, sizeof(sector));
// Padd out block
fwrite(nullBlock, paddingBytes(bytesWritten, FS_BLOCK_SIZE), 1, imagePtr);
}
}
-44
View File
@@ -1,44 +0,0 @@
#
# Main kern makefile
#
export VERSION = 0.2.2
# Configurable variables (eg. CC, CFLAGS, ...)
include make.defaults
# The directories containing other makefiles
SUBDIRS = libc libk boot kernel
all: msg $(IMG)
msg:
@echo\
"\x1b[36mBuilding \x1b[1mkern.\x1b[22m V$(VERSION)\x1b[0m\n\x1b[32m (c) Tom-on 2024\x1b[0m\n"
# Build the final disk image
$(IMG): $(SUBDIRS) $(FONTS)
$(HOSTCC) ./makedisk.c -I$(LIBK_INC)/fs -o ./makedisk
./makedisk
@echo "\n\x1b[32mDone!\x1b[0m\n"
$(SUBDIRS):
mkdir -p $(BIN)/$@
$(MAKE) -C . -f $@/makefile
$(FONTS):
cp $(FONT_DIR)/$@.fnt $(BIN)/$@.fnt
.PHONY: all $(SUBDIRS) fonts clean qemu
clean:
rm -rf $(BIN)
rm -rf $(IMG)
rm -f makedisk
qemu:
qemu-system-x86_64\
-drive format=raw,file=$(IMG),index=0,media=disk\
-m 256M -accel tcg -monitor stdio\
-rtc base=localtime,clock=host,driftfix=slew\
-audiodev coreaudio,id=audio0 -machine pcspk-audiodev=audio0
-328
View File
@@ -1,328 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include "shell.h"
#define COMMAND_COUNT 11
#define MAX_INPUT 256
#define MAX_ARGC 9 // 10 - 1 (because 0 is also an arg)
typedef struct {
char* command;
int (*handler)(int argc, char** argv);
char* help;
} command_t;
command_t commands[COMMAND_COUNT] = {
{ "clear", cmd_clear, "Clears the screen" },
{ "echo", cmd_echo, "Prints a message to stdout" },
{ "exit", cmd_exit, "Exits shell" },
{ "gfxtest", cmd_gfxtest, "Does a graphics test" },
{ "help", cmd_help, "Prints this message" },
{ "ls", cmd_ls, "Lists files in current directory" },
{ "memmap", cmd_memmap, "Prints the memory map and info" },
{ "reboot", cmd_reboot, "Reboots the system" },
{ "regs", cmd_regs, "Prints register values" },
{ "sleep", cmd_sleep, "Sleeps for input number of seconds" },
{ "soundtest", cmd_soundtest, "Plays a tune :)" },
};
int prompt() {
printf("\x1b[6M%s \x1b[2M%s ", cwd, PROMPT);
char input[256];
gets(input, 256);
// Empty line
if (*input == '\0') return 0;
// Parse argc & argv
char* inptr = input;
int argc;
char* argv[10] = { NULL };
while (*inptr == ' ') inptr++;
argv[argc++] = inptr;
while (*inptr != '\0') {
if (*inptr == ' ') {
*inptr++ = '\0';
while (*inptr == ' ') inptr++; // Skip extra spaces
argv[argc++] = inptr;
} else {
inptr++;
}
}
return eval(argc, argv);
}
int eval(int argc, char** argv) {
for (size_t i = 0; i < COMMAND_COUNT; i++) {
if (strcmp(argv[0], commands[i].name) == 0) {
return commands[i].handler(argc, argv);
}
}
// TODO: read PATH
return 1;
}
int cmd_clear(int argc, char** argv) {
printf("\x1b[J");
return 0;
}
int cmd_echo(int argc, char** argv) {
if (argc < 2) continue;
char* str = argv[1];
char* printStr = argv[1];
while (*argv[1] != '\0') {
if (*argv[1] == '\\') {
argv[1]++;
if (*argv[1] == 'n') *str++ = '\n';
else if (*argv[1] == 'b') *str++ = '\b';
else if (*argv[1] == 'e') *str++ = '\x1b';
else if (*argv[1] == '\\') *str++ = '\\';
else {
*str++ = '\\';
*str++ = *argv[1];
}
argv[1]++;
} else {
*str++ = *argv[1]++;
}
}
*str = '\0';
printf("%s\n", printStr);
return 0;
}
int cmd_exit(int argc, char** argv) {
outw(0x604, 0x2000); // QEMU - Quit emulator
while (1) { __asm__ volatile ("cli; hlt"); }
return 1; // Unreachable
}
int cmd_gfxtest(int argc, char** argv) {
printf("\x1b[J");
// Draw some stuff :)
for (size_t i = 0; i < 120; i++) {
for (size_t j = 0; j < 120; j++) {
drawPixel(200 + i, 200 + j, GREEN);
}
}
fillRect(200, 200, 320, 320, GREEN);
drawLine(200, 200, 320, 320, RED);
drawLine(320, 200, 200, 320, RED);
drawLine(800, 300, 900, 400, BLUE);
drawLine(900, 400, 1000, 300, BLUE);
drawLine(1000, 300, 900, 200, BLUE);
drawLine(900, 200, 800, 300, BLUE);
drawLine(400, 350, 420, 100, rgb(0xee, 0x9f, 0x00));
drawTriangle(200, 400, 400, 600, 200, 600, MAGENTA);
fillTriangle(750, 400, 800, 450, 700, 450, CYAN);
drawTriangle(960, 400, 1000, 500, 990, 580, YELLOW);
drawRect(100, 650, 800, 900, rgb(0xe0, 0x0a, 0x3a));
drawCircle(1500, 600, 300, WHITE);
fillCircle(950, 750, 75, rgb(0xa2, 0xd6, 0xf9));
getc(stdin); // Wait until we get a keystroke
printf("\x1b[J");
return 0;
}
int cmd_help(int argc, char** argv) {
printf("Available commands:\n");
for (int i = 0; i < COMMAND_COUNT; i++) {
printf(" %11s | %s\n", commands[i].command, commands[i].help);
}
return 0;
}
int cmd_ls(int argc, char** argv) {
inode_t* root = (inode_t*)impl_superblock->rootInodePtr;
diskRead(root->extent[0].block * 8, root->extent[0].length * 8, (void*)SCRATCH_BLOCK_LOC);
dirEntry_t* dentry = (dirEntry_t*)SCRATCH_BLOCK_LOC;
uint32_t total = 0;
while ((dentry + total)->name[0] != '\0') { total++; }
putc(' ', stdout); // TODO
printf("\bTotal %d\n", total);
while (dentry->name[0] != '\0') {
inode_t* inode = (inode_t*)BOOT_FIRST_INODE_LOC + dentry->id;
printf("%s", dentry->name);
for (uint32_t pad = (16 - strlen(dentry->name)); pad > 0; pad--) { putc(' ', stdout); }
switch (inode->type) {
case FT_FILE: printf("%dB\n", inode->sizeBytes); break;
case FT_DIR: printf("[dir]\n"); break;
}
dentry++;
}
return 0;
}
int cmd_memmap(int argc, char** argv) {
uint32_t entryCount = *(uint32_t*)SMAP_ENTRY_COUNT;
smapEntry_t* smapEntry = (smapEntry_t*)SMAP_ENTRIES;
for (uint32_t i = 0; i < entryCount; i++) {
printf("Region %02d - base: 0x%08x length: 0x%08x type: %2d ", i, (uint32_t)smapEntry->baseAddress, (uint32_t)smapEntry->length, smapEntry->type);
switch (smapEntry->type) {
case 1: printf("(Available)\n"); break;
case 2: printf("(Reserved)\n"); break;
case 3: printf("(ACPI Reclaim)\n"); break;
case 4: printf("(ACPI NVS)\n"); break;
default: printf("(Reserved)\n"); break;
}
smapEntry++;
}
smapEntry--; // We incremented it after the last entry
printf("\nTotal memory: 0x%x Bytes\n", smapEntry->baseAddress + smapEntry->length - 1);
printf("Total 4kB Blocks: %d\n", maxBlocks);
printf("Used or reserved blocks: %d\n", usedBlocks);
printf("Free blocks: %d\n\n", maxBlocks - usedBlocks);
return 0;
}
int cmd_reboot(int argc, char** argv) {
outb(0x64, 0xFE);
return 1;
}
int cmd_regs(int argc, char** argv) {
uint32_t val;
// a, b, c, d
__asm__ volatile ("movl %%eax, %0" : "=r"(val));
printf("eax 0x%08x\n", val);
__asm__ volatile ("movl %%ebx, %0" : "=r"(val));
printf("ebx 0x%08x\n", val);
__asm__ volatile ("movl %%ecx, %0" : "=r"(val));
printf("ecx 0x%08x\n", val);
__asm__ volatile ("movl %%edx, %0" : "=r"(val));
printf("edx 0x%08x\n", val);
// si, di
__asm__ volatile ("movl %%esi, %0" : "=r"(val));
printf("esi 0x%08x\n", val);
__asm__ volatile ("movl %%edi, %0" : "=r"(val));
printf("edi 0x%08x\n", val);
// cs, ds, es, ss
__asm__ volatile ("movl %%cs, %0" : "=r"(val));
printf("cs 0x%08x\n", val);
__asm__ volatile ("movl %%ds, %0" : "=r"(val));
printf("ds 0x%08x\n", val);
__asm__ volatile ("movl %%es, %0" : "=r"(val));
printf("es 0x%08x\n", val);
__asm__ volatile ("movl %%ss, %0" : "=r"(val));
printf("ss 0x%08x\n", val);
// stack
__asm__ volatile ("movl %%esp, %0" : "=r"(val));
printf("esp 0x%08x\n", val);
__asm__ volatile ("movl %%ebp, %0" : "=r"(val));
printf("ebp 0x%08x\n", val);
return 0;
}
int cmd_sleep(int argc, char** argv) {
if (*argv[1] == '\0') continue;
uint32_t ms = atoi(argv[1]) * 1000; // Convert seconds to miliseconds
if (ms == 0) continue;
msleep(ms);
return 0;
}
int cmd_soundtest(int argc, char** argv) {
printf("Playing...\n");
enableSpeaker();
/*
* Megalovania - Toby Fox
* |-D-D-d--A---Ab--G--F--D-F-G-| (Goofy ahh notation)
* (The timing may be off)
*/
for (uint8_t i = 0; i < 4; i++) {
note_t first[4] = { D4, C4, H3, Hb3 };
playNote(first[i], 120);
playNote(first[i], 120);
playNote(D5, 240);
playNote(A4, 360);
playNote(Ab4, 240);
playNote(G4, 240);
playNote(F4, 240);
playNote(D4, 120);
playNote(F4, 120);
playNote(G4, 120);
}
rest(120);
disableSpeaker();
return 0;
}
_m() {
char* fileName = argv[0];
FILE* _f = fopen(fileName, "rb");
if (_f == NULL) {
printf("Command not found: %s\n", fileName);
continue;
}
FILE* fp = fsInfo->openFileTable + _f->_file;
printf("%d: 0x%x Bytes\n", fp->_file, fp->_size);
for (size_t i = 0; i < fp->_size; i++) {
if (i % 32 == 0) {
if (i != 0) {
printf(" ");
size_t oldi = i;
i -= 32;
while (i < oldi) {
char c = fp->_ptr[i++];
printf("%c", c < 32 ? '.' : c);
}
putc('\n', stdout);
}
printf("%04x: ", i);
}
printf("%02x ", fp->_ptr[i]);
}
if (fp->_size % 32 != 0) {
for (size_t i = 0; i < 32-(fp->_size % 32); i++) {
printf(" ");
}
}
printf(" ");
for (size_t i = fp->_size-(fp->_size%32); i < fp->_size; i++) {
char c = fp->_ptr[i];
printf("%c", c < 32 ? '.' : c);
}
printf("\n");
free(_f);
fclose(fp);
}
-109
View File
@@ -1,109 +0,0 @@
#include <stdio.h>
#include <string.h>
int evalExpr(char* expr, int* res);
int parseTerm(char** ptr);
int parseFactor(char** ptr);
int parseNumber(char** ptr);
// TODO: Parsing doesn't account for addition/subtraction inside brackets, fix that
__attribute__ ((section("entry")))
int main(int argc, char** argv) {
printf("Welcome to calc.\n");
char input[256];
while (1) {
printf("> ");
reads(input);
// Remove whitespace
char* old = input;
char* new = input;
while (*old != '\0') {
if (*old == ' ') old++;
*new++ = *old++;
}
*new = '\0';
if (strcmp(input, "exit") == 0) {
break;
}
int res;
if (evalExpr(input, &res)) {
printf("%d\n", res);
} else {
printf("?\n");
}
}
return 0;
}
int evalExpr(char* expr, int* res) {
char* ptr = expr;
*res = parseTerm(&ptr);
while (*ptr != '\0') {
if (*ptr == '+') {
ptr++;
*res += parseTerm(&ptr);
} else if (*ptr == '-') {
ptr++;
*res -= parseTerm(&ptr);
} else {
return 0; // Invalid
}
}
return 1; // Success
}
int parseTerm(char** ptr) {
int res = parseFactor(ptr);
while (**ptr == '*' || **ptr == '/') {
if (**ptr == '*') {
(*ptr)++;
res *= parseFactor(ptr);
} else if (**ptr == '/') {
(*ptr)++;
int div = parseFactor(ptr);
if (div != 0) {
res /= div;
} else {
return 0;
}
}
}
return res;
}
int parseFactor(char** ptr) {
if (**ptr == '(') {
(*ptr)++;
int res = parseTerm(ptr);
if (**ptr == ')') {
(*ptr)++;
} else {
printf("Error: Missing ')'");
return 0;
}
return res;
} else {
return parseNumber(ptr);
}
}
int parseNumber(char** ptr) {
int res = 0;
while (**ptr >= '0' && **ptr <= '9') {
res *= 10;
res += *(*ptr)++ - '0';
}
return res;
}
-16
View File
@@ -1,16 +0,0 @@
SECTIONS {
.text 0x400000 : {
*(entry);
*(.text*);
}
.data : {
*(.data*);
}
.rodata : {
*(.rodata*);
}
.bss : {
*(.bss*);
}
}
-13
View File
@@ -1,13 +0,0 @@
#include <stdio.h>
__attribute__ ((section("entry")))
int main(int argc, char** argv) {
if (argc < 2) {
printf("Usage: %s <file>\n", argv[0]);
return 1;
}
printf("%s\n", argv[1]);
return 0;
}
-16
View File
@@ -1,16 +0,0 @@
SECTIONS {
.text 0x400000 : {
*(entry);
*(.text*);
}
.data : {
*(.data*);
}
.rodata : {
*(.rodata*);
}
.bss : {
*(.bss*);
}
}
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
-1
View File
@@ -1 +0,0 @@
This is a test file. Should be saved in test.txt!
-133
View File
@@ -1,133 +0,0 @@
; KBOOT - Kern Bootloader
; Most of the code is taken from Limine (https://github.com/limine-bootloader/limine)
; I tried to add more documentation than the Limine code had, but it's not everything
; Any of my code is pretty bad, so i recommend using an existing bootloader
[org 0x7c00]
[bits 16]
start:
jmp .bpb_end
; Some BIOSes will override the FAT BPB area,
; so we just fill it out to avoid pottentially
; overriding bootloader code.
; Source: https://github.com/limine-bootloader/limine/blob/trunk/stage1/hdd/bootsect.asm
.bpb:
times 3-($-$$) db 0
.bpb_oem_id: db "KBOOT "
.bpb_sector_size dw 512
.bpb_sects_per_clust: db 0
.bpb_reserved_sects: dw 0
.bpb_fat_count: db 0
.bpb_root_dir_entries: dw 0
.bpb_sector_count: dw 0
.bpb_media_type: db 0
.bpb_sects_per_fat: dw 0
.bpb_sects_per_track: dw 18
.bpb_heads_count: dw 2
.bpb_hidden_sects: dd 0
.bpb_sect_count_big: dd 0
.bpb_drive_num: db 0
.bpb_reserved: db 0
.bpb_signature: db 0
.bpb_volume_id: dd 0
.bpb_volume_label: db "KBOOT "
.bpb_filesystem_type: times 8 db 0
.bpb_end:
cli
cld
jmp 0x0000:.init_codeseg ; Long jump to set CS = 0
; Zero out segment regs (Because segmentation is shit)
.init_codeseg:
xor si, si ; We cannot change segment regs directly
mov ds, si ; Data Segment
mov es, si ; Extra Segment
mov ss, si ; Stack Segment
mov sp, 0x7c00 ; Set Stack Pointer
sti
; We probably won't be booting from a floppy, so
; ignore if boot drive is < 0x80 and assume an error
cmp dl, 0x80
jl err.0
; Also anything above 0x8f is "dubious" so we also
; just assume an error
cmp dl, 0x8f
jg err.1
; Check that int 13h extensions are supported
.int13chk:
mov ah, 0x41
mov bx, 0x55aa ; Expects bx to be this magic value
int 0x13 ; Will se CF if unsupported
jc err.2
cmp bx, 0xaa55 ; Also sets bx to this magic
jne err.3
; Load the stage 2 bootloader code to 0x70000
.load_stage2:
push 0x7000
pop es ; ES = 0x7000
xor bx, bx ; ES:BX = 0x70000
mov eax, 512
xor ebp, ebp
mov ecx, 512
call read_sectors
jc err.4 ; CF was set -> failed to read from disk
.enable_protected:
; Load GDT Pointer
lgdt [gdtp]
; Set PE (Protected mode Enable) flag
cli
mov eax, cr0
or eax, 1 ; Bit 1 - PE
mov cr0, eax
; Far jump to protected mode
jmp code_seg:vector
%include "boot/disk.s" ; Disk I/O helper functions
%include "boot/gdt.s" ; Global Descriptor Table
; Handles an error
err:
; Error codes
.4: inc si ; Failed to read stage2 from disk
.3: inc si ; Int 13h extensions unsupported (BX wasn't magic)
.2: inc si ; Int 13h extensions unsupported (CF was set)
.1: inc si ; Invalid boot drive number (> 0x8f)
.0: ; Invalid boot drive number (< 0x80)
; Common error handler
add si, '0' | (0x4f << 8) ; Store error code number char in SI, white on red
push 0xb800 ; VGA Text mode video memory
pop es ; ES = 0xb800
mov word [es:0], si ; Write character
; Hang
sti
.h: hlt
jmp .h
[bits 32]
; Protected mode entry vector
vector:
mov eax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
and edx, 0xff
; Call stage 2 bootloader
call 0x70000
; Padding and boot signature
times 510-($-$$) db 0
dw 0xaa55
-80
View File
@@ -1,80 +0,0 @@
; Reads sectors from disk
; Args:
; eax - LBA low 32 bits
; ebp - LBA high 32 bits
; dl - Drive number
; es - Destination segment
; bx - Destination offset
; ecx - Byte count
; Rets:
; CF - Set on error
read_sectors:
pusha
; Fill out Disk Address Packet
mov si, .da_packet
mov word [si], 0x10 ; Packet Size and Unused
mov word [si+2], 1 ; Sector count
mov word [si+4], bx ; Dest. offset
mov word [si+6], es ; Dest. segment
; Store some regs for later
push dx
push si
push eax
push ebp
; Get bytes per sector
mov ah, 0x48 ; Extended read drive parameters
mov si, .drive_params ; DS:SI - result buffer
mov word [si], 0x1e ; Buffer size
int 0x13
jc .done ; CF set - error; we never pop ebp, eax, si & dx! (could cause issues)
mov bp, word [si+24] ; Bytes per sector
; Convert byte count in ECX to sector count in CX
mov ax, cx ; Low word
shr ecx, 16 ; Shift high word into low word of ECX (therefore just CX)
mov dx, cx ; High word
xor cx, cx ; Clear CX
div bp ; Divide byte count in ax (low word) by bytes per sector
test dx, dx ; DX will contain remainder
setnz cl ; (dx != 0) ? cl = 1 : cl = 0
add cx, ax ; Add remaining sectors to cx
pop edx ; Restore pushed EBP to EDX
pop eax ; Restore EAX
pop si ; Restore SI
; Calculate destination LBA
div ebp ; Divide EAX by EBP
mov dword [si+8], eax ; LBA low
mov dword [si+12], 0 ; LBA high
pop dx ; Restore DX
; Read sectors one by one
.loop:
mov ah, 0x42 ; Extended read
clc ; Clear CF
int 0x13
jc .done ; Error
add word [si+4], bp ; Increment destination by sector byte count
xor ebx, ebx ; EBX = 0
inc dword [si+8] ; Increment LBA low
seto bl ; Will set BL to 1 in case of overflow
add dword [si+12], ebx ; Increment LBA high
loop .loop ; dec cx; jnz .loop
.done:
popa
ret
; Disk Address Packet
.da_packet: equ 0x8000
; Drive Parameters from int 13h, ah = 0x48
.drive_params: equ 0x8010
+26 -2
View File
@@ -1,7 +1,31 @@
include ../defaults.mk
BIN = ./bin
STAGE1_SRC = ./stage1
STAGE2_SRC = ./stage2
STAGE1_SRCS = $(wildcard $(STAGE1_SRC)/*.s)
STAGE2_SRCS = $(wildcard $(STAGE2_SRC)/*.c)
STAGE2_OBJS = $(patsubst $(STAGE2_SRC)/%.c, $(BIN)/%.o, $(STAGE2_SRCS))
LINKER = $(STAGE2_SRC)/linker.ld
STAGE1 = stage1.bin
STAGE2 = stage2.bin
.PHONY: all clean
all:
@echo "TODO: Write this makefile..."
all: $(STAGE1) $(STAGE2)
$(STAGE1): $(STAGE1_SRCS)
$(AS) $(ASFLAGS) -fbin -o $@ $(STAGE1_SRC)/bootsect.s
$(STAGE2): $(STAGE2_OBJS)
$(LD) $(LDFLAGS) -T$(LINKER) -o $@ $^
$(BIN)/%.o: $(STAGE2_SRC)/%.c
@mkdir -p $(dir $@)
$(CC) $(CFLAGS) -c -o $@ $<
clean:
rm -fr $(BIN) $(STAGE1) $(STAGE2)
+132
View File
@@ -0,0 +1,132 @@
; KBOOT - Kern Bootloader
; Most of the code is taken from Limine (https://github.com/limine-bootloader/limine)
; I tried to add more documentation than the Limine code had, but it's not everything
; Any of my code is pretty bad, so i recommend using an existing bootloader
[org 0x7c00]
[bits 16]
; BPB Requires these
jmp short .bpb_end
nop
; FAT32 Bios Parameter Block
.bpb:
.bpb_oem_id: db "KERN "
.bpb_sector_size: dw 0
.bpb_sects_per_clust: db 0
.bpb_reserved_sects: dw 0
.bpb_fat_count: db 0
.bpb_root_dir_entries: dw 0
.bpb_sector_count: dw 0
.bpb_media_type: db 0
.bpb_sects_per_fat: dw 0
.bpb_sects_per_track: dw 18
.bpb_heads_count: dw 2
.bpb_hidden_sects: dd 0
.bpb_sect_count_big: dd 0
; Extended BPB
.bpb_drive_num: db 0
.bpb_reserved: db 0
.bpb_signature: db 0
.bpb_volume_id: dd 0
.bpb_volume_label: dd "KERN "
.bpb_fs_type: times 8 db 0
.bpb_end:
cli
cld
jmp 0x0000:.init_codeseg ; Long jump to set CS = 0
; Zero out segment regs (Because segmentation is shit)
.init_codeseg:
xor si, si ; We cannot change segment regs directly
mov ds, si ; Data Segment
mov es, si ; Extra Segment
mov ss, si ; Stack Segment
mov sp, 0x7c00 ; Set Stack Pointer
sti
; We probably won't be booting from a floppy, so
; ignore if boot drive is < 0x80 and assume an error
cmp dl, 0x80
jl err.0
; Also anything above 0x8f is "dubious" so we also
; just assume an error
cmp dl, 0x8f
jg err.1
; Check that int 13h extensions are supported
.int13chk:
mov ah, 0x41
mov bx, 0x55aa ; Expects bx to be this magic value
int 0x13 ; Will se CF if unsupported
jc err.2
cmp bx, 0xaa55 ; Also sets bx to this magic
jne err.3
; Load the stage 2 bootloader code to 0x70000
.load_stage2:
mov eax, 1 ; LBA
mov cx, 20 ; Read 20 sectors (we have space for 2048)
; Destination - 0x70000
push 0x7000
pop es
xor bx, bx
call read_sectors
jc err.4 ; Failed to read stage 2
.enable_protected:
; Load GDT Pointer
lgdt [gdtp]
; Set PE (Protected mode Enable) flag
cli
mov eax, cr0
or eax, 1 ; Bit 1 - PE
mov cr0, eax
; Far jump to protected mode
jmp code_seg:vector
%include "stage1/disk.s" ; Disk I/O helper functions
%include "stage1/gdt.s" ; Global Descriptor Table
; Handles an error
err:
; Error codes
.4: inc si ; Failed to read stage2 from disk
.3: inc si ; Int 13h extensions unsupported (BX wasn't magic)
.2: inc si ; Int 13h extensions unsupported (CF was set)
.1: inc si ; Invalid boot drive number (> 0x8f)
.0: ; Invalid boot drive number (< 0x80)
; Common error handler
add si, '0' | (0x4f << 8) ; Store error code number char in SI, white on red
push 0xb800 ; VGA Text mode video memory
pop es ; ES = 0xb800
mov word [es:0], si ; Write character
; Hang
sti
.h: hlt
jmp .h
[bits 32]
; Protected mode entry vector
vector:
mov eax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
and edx, 0xff
; Call stage 2 bootloader
call 0x70000
; Padding and boot signature
times 510-($-$$) db 0
dw 0xaa55
+26
View File
@@ -0,0 +1,26 @@
; Reads sectors from disk
; eax - LBA
; cx - Sector count
; dl - Drive number
; es:dx - Destination
read_sectors:
pusha
; Fill out Disk Address Packet
mov si, .da_packet
mov word [si], 0x10 ; Packet Size and Unused
mov word [si+2], cx ; Sector count
mov word [si+4], bx ; Dest. offset
mov word [si+6], es ; Dest. segment
mov dword [si+8], eax ; LBA
mov ah, 0x42 ; Extended read
clc ; Clear CF
int 0x13
.done:
popa
ret
; Disk Address Packet
.da_packet: equ 0x8000
-1
View File
@@ -26,4 +26,3 @@ gdtp:
; Segments
code_seg equ gdt.code_desc - gdt
data_seg equ gdt.data_desc - gdt
+3
View File
@@ -0,0 +1,3 @@
void entry() {
while (1);
}
+27
View File
@@ -0,0 +1,27 @@
OUTPUT_FORMAT(binary)
ENTRY(entry)
SECTIONS {
/* Will be loaded at 0x70000 */
. = 0x70000;
.text : {
*(.text)
*(.text.*)
*(.rodata)
*(.rodata.*)
}
.data : {
*(.data)
*(.data.*)
}
.bss : {
*(COMMON)
*(.bss)
*(.bss.*)
}
_end = .;
}
+1
View File
@@ -5,6 +5,7 @@ LD = i686-elf-ld
AS = nasm
AR = i686-elf-ar
OBJCOPY = i686-elf-objcopy
MAKE = make
# Flags
HOSTCFLAGS = -Wall -Wextra -Wpedantic -O2 -std=c17 -g
+1 -1
View File
@@ -1,4 +1,4 @@
OUTPUT_FORMAT(elf32-i386)
OUTPUT_FORMAT(binary)
ENTRY(start)
SECTIONS {
+9 -7
View File
@@ -1,14 +1,16 @@
include ../defaults.mk
INC = ./include
SRC = ./src
BIN = ./bin
SRCS_C = $(shell find . -name '*.c')
SRCS_S = $(shell find . -name '*.s')
OBJS = $(patsubst %.c, $(BIN)/%.o, $(SRCS_C)) \
$(patsubst %.s, $(BIN)/%.s.o, $(SRCS_S))
SRCS_C = $(shell find $(SRC) -name '*.c')
SRCS_S = $(shell find $(SRC) -name '*.s')
OBJS = $(patsubst $(SRC)/%.c, $(BIN)/%.o, $(SRCS_C)) \
$(patsubst $(SRC)/%.s, $(BIN)/%.s.o, $(SRCS_S))
LINKER = ./linker.ld
OUT = ./kernel.elf
OUT = ./kern.bin
.PHONY: all clean
@@ -16,11 +18,11 @@ all: $(OUT)
$(OUT): $(OBJS)
$(LD) $(LDFLAGS) -T$(LINKER) -o $@ $^
$(BIN)/%.o: %.c
$(BIN)/%.o: $(SRC)/%.c
@mkdir -p $(dir $@)
$(CC) $(CFLAGS) -I$(INC) -c -o $@ $<
$(BIN)/%.s.o: %.s
$(BIN)/%.s.o: $(SRC)/%.s
@mkdir -p $(dir $@)
$(AS) $(ASFLAGS) -felf32 -o $@ $<
+35 -2
View File
@@ -1,2 +1,35 @@
all:
@echo TODO
IMG = kern.img
BOOT = ./boot
KERNEL = ./kernel
LIBC = ./libc
MODULES = $(BOOT)\
$(KERNEL)\
$(LIBC)
.PHONY: all clean $(MODULES) qemu
all: $(IMG)
$(IMG): $(MODULES)
dd if=/dev/zero of=$(IMG) bs=512 count=131072
dd if=$(BOOT)/stage1.bin of=$(IMG) bs=512 seek=0 conv=notrunc
dd if=$(BOOT)/stage2.bin of=$(IMG) bs=512 seek=1 conv=notrunc
echo ',,b,*' | sfdisk $(IMG)
echo 'drive A:\n\tfile="$(IMG)"\n\tpartition=1' > ~/.mtoolsrc
mformat -F 'A:'
mcopy $(KERNEL)/kern.bin 'A:'
$(MODULES):
$(MAKE) -C $@
clean:
rm -f $(IMG)
for m in $(MODULES); do $(MAKE) -C $$m clean; done
qemu:
qemu-system-x86_64\
-drive format=raw,file=$(IMG),index=0,media=disk\
-m 256M -accel tcg -monitor stdio\
-rtc base=localtime,clock=host,driftfix=slew\
-audiodev coreaudio,id=audio0 -machine pcspk-audiodev=audio0
-7
View File
@@ -1,7 +0,0 @@
.PHONY: all clean
all:
@echo "TODO: Write this makefile..."
clean: