forked from PoliEcho-holding-org/kern
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:
@@ -15,6 +15,7 @@
|
|||||||
*.elf
|
*.elf
|
||||||
*.hdd
|
*.hdd
|
||||||
*.iso
|
*.iso
|
||||||
|
*.img
|
||||||
*.sys
|
*.sys
|
||||||
*.dtb
|
*.dtb
|
||||||
*~
|
*~
|
||||||
|
|||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
OUTPUT_FORMAT("binary")
|
|
||||||
|
|
||||||
SECTIONS {
|
|
||||||
.text 0xC0000000 : {
|
|
||||||
*(entry);
|
|
||||||
*(.text*);
|
|
||||||
}
|
|
||||||
.data : {
|
|
||||||
*(.data*);
|
|
||||||
}
|
|
||||||
.rodata : {
|
|
||||||
*(.rodata*);
|
|
||||||
}
|
|
||||||
.bss : {
|
|
||||||
*(.bss*);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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)
|
|
||||||
|
|
||||||
@@ -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));
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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; }
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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");
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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");
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
#include <syscalls/syscalls.h>
|
|
||||||
#include <cpu/isr.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
int sys_close(intFrame_t* iframe) {
|
|
||||||
// TODO
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
#include <syscalls/syscalls.h>
|
|
||||||
#include <cpu/isr.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
int sys_open(intFrame_t* iframe) {
|
|
||||||
// TODO
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#include <syscalls/syscalls.h>
|
|
||||||
#include <cpu/isr.h>
|
|
||||||
|
|
||||||
int sys_seek(intFrame_t* iframe) {
|
|
||||||
// TODO
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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; }
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
SECTIONS {
|
|
||||||
.text 0x400000 : {
|
|
||||||
*(entry);
|
|
||||||
*(.text*);
|
|
||||||
}
|
|
||||||
.data : {
|
|
||||||
*(.data*);
|
|
||||||
}
|
|
||||||
.rodata : {
|
|
||||||
*(.rodata*);
|
|
||||||
}
|
|
||||||
.bss : {
|
|
||||||
*(.bss*);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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 +0,0 @@
|
|||||||
This is a test file. Should be saved in test.txt!
|
|
||||||
-133
@@ -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
@@ -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
@@ -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
|
.PHONY: all clean
|
||||||
|
|
||||||
all:
|
all: $(STAGE1) $(STAGE2)
|
||||||
@echo "TODO: Write this makefile..."
|
|
||||||
|
$(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:
|
clean:
|
||||||
|
rm -fr $(BIN) $(STAGE1) $(STAGE2)
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -26,4 +26,3 @@ gdtp:
|
|||||||
; Segments
|
; Segments
|
||||||
code_seg equ gdt.code_desc - gdt
|
code_seg equ gdt.code_desc - gdt
|
||||||
data_seg equ gdt.data_desc - gdt
|
data_seg equ gdt.data_desc - gdt
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
void entry() {
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
@@ -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 = .;
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ LD = i686-elf-ld
|
|||||||
AS = nasm
|
AS = nasm
|
||||||
AR = i686-elf-ar
|
AR = i686-elf-ar
|
||||||
OBJCOPY = i686-elf-objcopy
|
OBJCOPY = i686-elf-objcopy
|
||||||
|
MAKE = make
|
||||||
|
|
||||||
# Flags
|
# Flags
|
||||||
HOSTCFLAGS = -Wall -Wextra -Wpedantic -O2 -std=c17 -g
|
HOSTCFLAGS = -Wall -Wextra -Wpedantic -O2 -std=c17 -g
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
OUTPUT_FORMAT(elf32-i386)
|
OUTPUT_FORMAT(binary)
|
||||||
ENTRY(start)
|
ENTRY(start)
|
||||||
|
|
||||||
SECTIONS {
|
SECTIONS {
|
||||||
|
|||||||
+9
-7
@@ -1,14 +1,16 @@
|
|||||||
include ../defaults.mk
|
include ../defaults.mk
|
||||||
|
|
||||||
INC = ./include
|
INC = ./include
|
||||||
|
SRC = ./src
|
||||||
BIN = ./bin
|
BIN = ./bin
|
||||||
|
|
||||||
SRCS_C = $(shell find . -name '*.c')
|
SRCS_C = $(shell find $(SRC) -name '*.c')
|
||||||
SRCS_S = $(shell find . -name '*.s')
|
SRCS_S = $(shell find $(SRC) -name '*.s')
|
||||||
OBJS = $(patsubst %.c, $(BIN)/%.o, $(SRCS_C)) \
|
OBJS = $(patsubst $(SRC)/%.c, $(BIN)/%.o, $(SRCS_C)) \
|
||||||
$(patsubst %.s, $(BIN)/%.s.o, $(SRCS_S))
|
$(patsubst $(SRC)/%.s, $(BIN)/%.s.o, $(SRCS_S))
|
||||||
|
|
||||||
LINKER = ./linker.ld
|
LINKER = ./linker.ld
|
||||||
OUT = ./kernel.elf
|
OUT = ./kern.bin
|
||||||
|
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
|
|
||||||
@@ -16,11 +18,11 @@ all: $(OUT)
|
|||||||
$(OUT): $(OBJS)
|
$(OUT): $(OBJS)
|
||||||
$(LD) $(LDFLAGS) -T$(LINKER) -o $@ $^
|
$(LD) $(LDFLAGS) -T$(LINKER) -o $@ $^
|
||||||
|
|
||||||
$(BIN)/%.o: %.c
|
$(BIN)/%.o: $(SRC)/%.c
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
$(CC) $(CFLAGS) -I$(INC) -c -o $@ $<
|
$(CC) $(CFLAGS) -I$(INC) -c -o $@ $<
|
||||||
|
|
||||||
$(BIN)/%.s.o: %.s
|
$(BIN)/%.s.o: $(SRC)/%.s
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
$(AS) $(ASFLAGS) -felf32 -o $@ $<
|
$(AS) $(ASFLAGS) -felf32 -o $@ $<
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,35 @@
|
|||||||
all:
|
IMG = kern.img
|
||||||
@echo TODO
|
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
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
.PHONY: all clean
|
|
||||||
|
|
||||||
all:
|
|
||||||
@echo "TODO: Write this makefile..."
|
|
||||||
|
|
||||||
clean:
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user