forked from PoliEcho-holding-org/kern
Implemented a proper libk
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
#include <disk/disk.h>
|
||||
#include <stdint.h>
|
||||
#include <ports/io.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
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
#include <error/bigerr.h>
|
||||
#include <stdint.h>
|
||||
#include <screen/gfxmode.h>
|
||||
|
||||
void rect(uint32_t c, uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
|
||||
uint8_t* vidmem = (uint8_t*)gfxMode->physicalBasePtr;
|
||||
uint8_t bytesPerPx = gfxMode->bpp / 8;
|
||||
uint32_t convColor = convertColor(c);
|
||||
|
||||
for (uint32_t dx = 0; dx < w; dx++) {
|
||||
for (uint32_t dy = 0; dy < h; dy++) {
|
||||
uint32_t offset = (((y + dy) * gfxMode->xRes) + (x + dx)) * bytesPerPx;
|
||||
|
||||
for (uint8_t i = 0; i < gfxMode->bpp; i++) {
|
||||
vidmem[offset + i] = (uint8_t)(convColor >> (i*8));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bigError(uint32_t err) {
|
||||
// Red BG
|
||||
rect(0x00ff0000, 0, 0, gfxMode->xRes, gfxMode->yRes);
|
||||
// E
|
||||
rect(0x00ffffff, 20, 10, 10, 50);
|
||||
rect(0x00ffffff, 30, 10, 30, 10);
|
||||
rect(0x00ffffff, 30, 30, 30, 10);
|
||||
rect(0x00ffffff, 30, 50, 30, 10);
|
||||
// R
|
||||
rect(0x00ffffff, 70, 10, 10, 50);
|
||||
rect(0x00ffffff, 70, 10, 30, 10);
|
||||
rect(0x00ffffff, 70, 30, 30, 10);
|
||||
rect(0x00ffffff, 90, 10, 10, 30);
|
||||
rect(0x00ffffff, 80, 40, 10, 10);
|
||||
rect(0x00ffffff, 90, 50, 10, 10);
|
||||
// R
|
||||
rect(0x00ffffff, 110, 10, 10, 50);
|
||||
rect(0x00ffffff, 110, 10, 30, 10);
|
||||
rect(0x00ffffff, 110, 30, 30, 10);
|
||||
rect(0x00ffffff, 130, 10, 10, 30);
|
||||
rect(0x00ffffff, 120, 40, 10, 10);
|
||||
rect(0x00ffffff, 130, 50, 10, 10);
|
||||
// O
|
||||
rect(0x00ffffff, 150, 10, 10, 50);
|
||||
rect(0x00ffffff, 170, 10, 10, 50);
|
||||
rect(0x00ffffff, 150, 10, 30, 10);
|
||||
rect(0x00ffffff, 150, 50, 30, 10);
|
||||
// R
|
||||
rect(0x00ffffff, 190, 10, 10, 50);
|
||||
rect(0x00ffffff, 190, 10, 30, 10);
|
||||
rect(0x00ffffff, 190, 30, 30, 10);
|
||||
rect(0x00ffffff, 210, 10, 10, 30);
|
||||
rect(0x00ffffff, 200, 40, 10, 10);
|
||||
rect(0x00ffffff, 210, 50, 10, 10);
|
||||
|
||||
__asm__ volatile ("cli; hlt" :: "a"(err));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
#include <fs/impl.h>
|
||||
#include <fs/fs.h>
|
||||
#include <memory/addresses.h>
|
||||
#include <disk/disk.h>
|
||||
#include <syscall.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.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 = 0;
|
||||
stdin->_flag = O_RDONLY;
|
||||
|
||||
stdout = fsInfo->openFileTable + 1;
|
||||
stdout->_file = 1;
|
||||
stdout->_flag = O_WRONLY | O_APPEND;
|
||||
|
||||
stderr = fsInfo->openFileTable + 2;
|
||||
stderr->_file = 2;
|
||||
stderr->_flag = O_WRONLY | O_APPEND;
|
||||
|
||||
fsInfo->openFiles = 3;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
#include <interrupt/exceptions.h>
|
||||
#include <interrupt/idt.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// Exception handlers
|
||||
__attribute__ ((interrupt))
|
||||
void excp_divideErr(intFrame_t* iframe) { // ISR 0
|
||||
printf("\x1b[1M[ Division Error ]\n\x1b[8M");
|
||||
iframe->eip++;
|
||||
}
|
||||
|
||||
__attribute__ ((interrupt))
|
||||
void excp_doubleFault(intFrame_t* iframe, uint32_t errCode) { // ISR 8
|
||||
printf("\x1b[1M[ Double Fault ]\n\x1b[8M"); // Error code should be 0 (TODO: Maybe check if it's != 0?)
|
||||
__asm__ volatile ("cli; hlt");
|
||||
}
|
||||
|
||||
__attribute__ ((interrupt))
|
||||
void excp_pageFault(intFrame_t* iframe, uint32_t errCode) { // ISR 14
|
||||
uint32_t badAddress = 0;
|
||||
|
||||
// cr2 should contain invalid address
|
||||
__asm__ volatile("movl %%cr2, %0" : "=r"(badAddress));
|
||||
|
||||
printf("\x1b[1M[ Page Fault : 0x%x ] - Tried to access 0x%x.\n\x1b[8M", errCode, badAddress);
|
||||
__asm__ volatile ("cli; hlt");
|
||||
}
|
||||
|
||||
__attribute__ ((interrupt))
|
||||
void excp_reserved(intFrame_t* iframe) { // ISR 15
|
||||
print("\x1b[1M[ Unknown Exception ]\n\x1b[8M");
|
||||
__asm__ volatile ("cli; hlt");
|
||||
}
|
||||
|
||||
// TODO: Add more (because there's always more)
|
||||
|
||||
// Repetative isr definitions
|
||||
void setupExceptions() {
|
||||
for (uint8_t i = 0; i < 32; i++) {
|
||||
idtSetGate(i, excp_reserved, TRAP_GATE_FLAGS); // Doesn't account for err codes, will just halt anyways
|
||||
}
|
||||
|
||||
idtSetGate(0, excp_divideErr, TRAP_GATE_FLAGS);
|
||||
idtSetGate(8, excp_doubleFault, TRAP_GATE_FLAGS);
|
||||
idtSetGate(14, excp_pageFault, TRAP_GATE_FLAGS);
|
||||
idtSetGate(15, excp_reserved, TRAP_GATE_FLAGS);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#include <interrupt/idt.h>
|
||||
#include <stdint.h>
|
||||
|
||||
__attribute__ ((aligned(0x10))) // For performance
|
||||
idtEntry_t idt[256] = { 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));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
#include <interrupt/pic.h>
|
||||
#include <ports/io.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void sendPicEOI(uint8_t irq) {
|
||||
if (irq >= 8) {
|
||||
outb(PIC_2_CMD, PIC_EOI);
|
||||
}
|
||||
outb(PIC_1_CMD, PIC_EOI);
|
||||
}
|
||||
|
||||
void disableIrqs() {
|
||||
outb(PIC_2_DATA, PIC_DISABLE);
|
||||
outb(PIC_1_DATA, PIC_DISABLE);
|
||||
}
|
||||
|
||||
void setIrqMask(uint8_t irq) {
|
||||
uint16_t port;
|
||||
uint8_t value;
|
||||
|
||||
if (irq < 8) {
|
||||
port = PIC_1_DATA;
|
||||
} else {
|
||||
irq -= 8;
|
||||
port = PIC_2_DATA;
|
||||
}
|
||||
|
||||
value = inb(port) | (1 << irq);
|
||||
outb(port, value);
|
||||
}
|
||||
|
||||
void unsetIrqMask(uint8_t irq) {
|
||||
uint16_t port;
|
||||
uint8_t value;
|
||||
|
||||
if (irq < 8) {
|
||||
port = PIC_1_DATA;
|
||||
} else {
|
||||
irq -= 8;
|
||||
port = PIC_2_DATA;
|
||||
}
|
||||
|
||||
value = inb(port) & ~(1 << irq);
|
||||
outb(port, value);
|
||||
}
|
||||
|
||||
void remapPic() {
|
||||
uint8_t pic1Mask = inb(PIC_1_DATA);
|
||||
uint8_t pic2Mask = inb(PIC_2_DATA);
|
||||
|
||||
// Send Init Control Word 1-4 to both PICs
|
||||
// ICW 1: bit 0 - send up to 4 ICWs, bit 4 - Init PIC
|
||||
outb(PIC_1_CMD, 0x11);
|
||||
ioWait(); // For slower machines
|
||||
outb(PIC_2_CMD, 0x11);
|
||||
ioWait();
|
||||
|
||||
// ICW 2: Where to map IRW bases in IDT
|
||||
outb(PIC_1_DATA, NEW_IRQ_0);
|
||||
ioWait();
|
||||
outb(PIC_2_DATA, NEW_IRQ_8);
|
||||
ioWait();
|
||||
|
||||
// ICW 3: Which IRQ in PIC1 is PIC2; Mapping PIC2 to IRQ 2
|
||||
outb(PIC_1_DATA, 0x04);
|
||||
ioWait();
|
||||
outb(PIC_2_DATA, 0x02);
|
||||
ioWait();
|
||||
|
||||
// ICW 4 - Set x86 mode
|
||||
outb(PIC_1_DATA, 0x01);
|
||||
ioWait();
|
||||
outb(PIC_2_DATA, 0x01);
|
||||
ioWait();
|
||||
|
||||
outb(PIC_1_DATA, pic1Mask);
|
||||
outb(PIC_2_DATA, pic2Mask);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
#include <interrupt/pit.h>
|
||||
#include <interrupt/idt.h>
|
||||
#include <interrupt/pic.h>
|
||||
#include <terminal/terminal.h>
|
||||
#include <memory/addresses.h>
|
||||
#include <ports/io.h>
|
||||
#include <stdint.h>
|
||||
|
||||
__attribute__ ((interrupt))
|
||||
void timerHandler(intFrame_t* iframe) {
|
||||
static uint32_t cursorTicks = 0;
|
||||
cursorTicks++;
|
||||
|
||||
if (!terminal->hideCursor) { // TODO: Make a better cursor drawing thing
|
||||
if (cursorTicks % 500 == 0) toggleCursor();
|
||||
}
|
||||
|
||||
if (*(uint32_t*)SLEEP_TIMER > 0) { --(*(uint32_t*)SLEEP_TIMER); }
|
||||
|
||||
sendPicEOI(0);
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
void setupTimer() { // Sets up IRQ 0 - PIT
|
||||
idtSetGate(0x20, timerHandler, INT_GATE_FLAGS);
|
||||
unsetIrqMask(0);
|
||||
setPitPhase(0, 2, 1000); // Default setup: 1000Hz - 1 tick per 1ms
|
||||
}
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
#include <interrupt/rtc.h>
|
||||
#include <interrupt/pic.h>
|
||||
#include <interrupt/idt.h>
|
||||
#include <screen/text.h>
|
||||
#include <screen/gfxmode.h>
|
||||
#include <terminal/terminal.h>
|
||||
#include <ports/io.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
static datetime_t* datetime = (datetime_t*)DATETIME_LOC;
|
||||
|
||||
bool 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");
|
||||
}
|
||||
|
||||
__attribute__ ((interrupt)) 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 (true) { // 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, terminal->fg, terminal->bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getRtcRegister(0x0c);
|
||||
sendPicEOI(8);
|
||||
|
||||
__asm__ volatile ("sti");
|
||||
}
|
||||
|
||||
void setupRtc() { // IRQ 8 - Real Time Clock
|
||||
idtSetGate(0x28, rtcHandler, INT_GATE_FLAGS);
|
||||
unsetIrqMask(8);
|
||||
enableRtc();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
#include <interrupt/syscalls.h>
|
||||
#include <interrupt/idt.h>
|
||||
#include <terminal/terminal.h>
|
||||
#include <keyboard/keyboard.h>
|
||||
#include <memory/malloc.h>
|
||||
#include <memory/addresses.h>
|
||||
#include <memory/physical.h>
|
||||
#include <fs/fs.h>
|
||||
#include <fs/impl.h>
|
||||
#include <stdio.h>
|
||||
#include <syscall.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
* XXX WARNING - Update MAX_SYSCALLS in the handler XXX
|
||||
*/
|
||||
|
||||
int sys_reserved(sys_regs_t) {
|
||||
printf("\e[1N\e[6M Illegal use of Reserved() system call! \e[8M\e[8N\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Args: ebx - number of miliseconds
|
||||
int sys_sleep(sys_regs_t regs) {
|
||||
uint32_t* sleepTimerTicks = (uint32_t*)SLEEP_TIMER;
|
||||
*sleepTimerTicks = regs.ebx;
|
||||
|
||||
while (*sleepTimerTicks > 0) { // Wait...
|
||||
__asm__ volatile ("sti;hlt;cli;");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Args: ebx - int fd
|
||||
// ecx - void* buf
|
||||
// edx - uint32_t len
|
||||
// Rets: Number of bytes written
|
||||
int sys_write(sys_regs_t regs) {
|
||||
int32_t fd = regs.ebx;
|
||||
void* buf = (void*)regs.ecx;
|
||||
uint32_t len = regs.edx;
|
||||
|
||||
// TODO: Open fd table?
|
||||
if (fd == 1) {
|
||||
return terminalWrite(buf, len); // Call a terminal print function
|
||||
} else { return -1; }
|
||||
}
|
||||
|
||||
// TODO: Use a Read() sycall and read from stdin
|
||||
// Args: ebx - char* buffer
|
||||
int sys_read(sys_regs_t regs) {
|
||||
char* s = (char*)regs.ebx;
|
||||
reads(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Args: ebx - size_t count
|
||||
// Rets: Pointer to malloc-ed memory
|
||||
int sys_malloc(sys_regs_t regs) {
|
||||
uint32_t count = regs.ebx;
|
||||
|
||||
// First Malloc()
|
||||
if (!mallocListHead) {
|
||||
mallocInit(count); // Setup malloc linked list
|
||||
}
|
||||
|
||||
void* ptr = mallocNextNode(count);
|
||||
mallocMergeFree();
|
||||
|
||||
return (uint32_t)ptr;
|
||||
}
|
||||
|
||||
// Args: ebx - void* ptr
|
||||
int sys_free(sys_regs_t regs) {
|
||||
void* ptr = (void*)regs.ebx;
|
||||
mallocFree(ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Args: ebx - path,
|
||||
// ecx - oflag
|
||||
// Rets: Opened file descriptor
|
||||
int sys_open(sys_regs_t regs) {
|
||||
int fd = 0;
|
||||
char* path = (char*)regs.ebx;
|
||||
uint32_t oflag = regs.ecx;
|
||||
|
||||
// TODO: better file finding
|
||||
inode_t* root = (inode_t*)impl_superblock->rootInodePtr;
|
||||
loadFile(root, (void*)SCRATCH_BLOCK_LOC);
|
||||
|
||||
inode_t* inode = getInode(path, (dirEntry_t*)SCRATCH_BLOCK_LOC);
|
||||
if (inode == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO: check if max open files have'nt been reached
|
||||
fd = fsInfo->openFiles++;
|
||||
FILE* fp = fsInfo->openFileTable + fd;
|
||||
fp->_ptr = (void*)0xd000;
|
||||
fp->_offset = 0;
|
||||
fp->_size = inode->sizeBytes;
|
||||
fp->_flag = oflag;
|
||||
fp->_file = fd;
|
||||
|
||||
loadFile(inode, fp->_ptr);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
// Args: ebx - int fd
|
||||
// Rets: status
|
||||
int sys_close(sys_regs_t regs) {
|
||||
int fd = regs.ebx;
|
||||
|
||||
FILE* fp = fsInfo->openFileTable + fd;
|
||||
free(fp->_ptr);
|
||||
fsInfo->openFiles--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO
|
||||
int sys_seek(sys_regs_t regs) { return -1; }
|
||||
|
||||
// System call table
|
||||
int (*syscalls[MAX_SYSCALLS])(sys_regs_t) = {
|
||||
[SYS_RESERVED] = sys_reserved,
|
||||
[SYS_SLEEP] = sys_sleep,
|
||||
[SYS_WRITE] = sys_write,
|
||||
[SYS_READ] = sys_read,
|
||||
[SYS_MALLOC] = sys_malloc,
|
||||
[SYS_FREE] = sys_free,
|
||||
[SYS_OPEN] = sys_open,
|
||||
[SYS_CLOSE] = sys_close,
|
||||
[SYS_SEEK] = sys_seek,
|
||||
};
|
||||
|
||||
// int 0x80 - Syscall interrupt, handled by this function
|
||||
// eax : Syscall number
|
||||
__attribute__ ((naked)) // No prologue or epilogue, just assembly
|
||||
void syscallHandler(intFrame_t* iframe) {
|
||||
// Interrupt - Stack should contain: ss, esp, eflags, cs, eip
|
||||
// We should also push these regs: ax, gs, fs, es, ds, bp, di, si, dx, cx, bx
|
||||
__asm__ volatile (
|
||||
".intel_syntax noprefix\n" // We use intel syntax
|
||||
".equ MAX_SYSCALLS, 9\n" // Define MAX_SYSCALLS again TODO: I don't want to have to do this
|
||||
|
||||
// Check if syscall exists
|
||||
"cmp eax, MAX_SYSCALLS - 1\n"
|
||||
"ja invalidSyscall\n"
|
||||
|
||||
// Call the syscall
|
||||
"push eax\n"
|
||||
"push gs\n"
|
||||
"push fs\n"
|
||||
"push es\n"
|
||||
"push ds\n"
|
||||
"push ebp\n"
|
||||
"push edi\n"
|
||||
"push esi\n"
|
||||
"push edx\n"
|
||||
"push ecx\n"
|
||||
"push ebx\n"
|
||||
"push esp\n" // Push stack pointer again (for variables and such idk)
|
||||
|
||||
"call [syscalls + eax * 4]\n" // Call syscall from table. Syscall number should be in eax
|
||||
"add esp, 4\n" // Do not override ESP
|
||||
"pop ebx\n"
|
||||
"pop ecx\n"
|
||||
"add esp, 4\n" // Do not override EDX, some syscalls use it
|
||||
|
||||
"pop esi\n"
|
||||
"pop edi\n"
|
||||
"pop ebp\n"
|
||||
"pop ds\n"
|
||||
"pop es\n"
|
||||
"pop fs\n"
|
||||
"pop gs\n"
|
||||
"add esp, 4\n" // Save eax value
|
||||
"iretd\n" // Return from interrupt (32 bit)
|
||||
|
||||
// TODO: Send an error or something here
|
||||
"invalidSyscall:\n"
|
||||
"mov eax, -1\n" // Current error thing
|
||||
"iretd\n"
|
||||
|
||||
".att_syntax" // Switch back to AT&T Syntax (Just in case)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
#include <keyboard/keyboard.h>
|
||||
#include <interrupt/idt.h>
|
||||
#include <interrupt/pic.h>
|
||||
#include <keyboard/keys.h>
|
||||
#include <memory/addresses.h>
|
||||
#include <ports/io.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
static const uint8_t US_Keyboard[2][128] = US_KEYBOARD;
|
||||
keyboardState_t* keyboard = (keyboardState_t*)KEYBOARD_STATE_LOC;
|
||||
|
||||
__attribute__ ((interrupt))
|
||||
void keyboardHandler(intFrame_t* iframe) { // TODO: Make this better and be able to read multi-byte scancode
|
||||
uint8_t scancode = inb(0x60);
|
||||
char c = US_Keyboard[keyboard->shift][scancode];
|
||||
|
||||
if (scancode == LEFT_SHIFT_PRESS || scancode == RIGHT_SHIFT_PRESS) {
|
||||
keyboard->shift = true;
|
||||
} else if (scancode == LEFT_SHIFT_RELEASE || scancode == RIGHT_SHIFT_RELEASE) {
|
||||
keyboard->shift = false;
|
||||
}
|
||||
|
||||
if (scancode & 0x80) { // Keyup
|
||||
} else if (c != '\0') {
|
||||
keyboard->character = c;
|
||||
}
|
||||
|
||||
sendPicEOI(1);
|
||||
}
|
||||
|
||||
void setupKeyboard() {
|
||||
idtSetGate(0x21, keyboardHandler, INT_GATE_FLAGS);
|
||||
unsetIrqMask(1);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
#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
|
||||
}
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
#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
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
#include <ports/io.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// Port functions
|
||||
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));
|
||||
}
|
||||
|
||||
void ioWait() {
|
||||
// Waits ~1 I/O Cycle (Linux uses this so it should be good)
|
||||
__asm__ volatile("outb %%al, $0x80" : : "a"(0));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
#include <screen/text.h>
|
||||
#include <terminal/terminal.h>
|
||||
#include <memory/addresses.h>
|
||||
#include <screen/gfxmode.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 (terminal->y+1 < terminal->height) { return; } // Check if we should scroll
|
||||
|
||||
uint32_t bytesPerLine = charHeight * gfxMode->bytesPerScanline;
|
||||
uint32_t lines = terminal->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(terminal->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;
|
||||
}
|
||||
|
||||
terminal->y--;
|
||||
}
|
||||
|
||||
// TODO: Make this comply with the new terminal.h thing!
|
||||
void clearScreen(uint32_t bgColor) {
|
||||
uint8_t* vidmem = (uint8_t*)gfxMode->physicalBasePtr;
|
||||
uint8_t bytesPerPx = (gfxMode->bpp+1) / 8;
|
||||
|
||||
terminal->x = 0;
|
||||
terminal->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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
#include <sound/pcspk.h>
|
||||
#include <sound/notes.h>
|
||||
#include <interrupt/pit.h>
|
||||
#include <ports/io.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);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
#include <terminal/terminal.h>
|
||||
#include <screen/gfxmode.h>
|
||||
#include <screen/text.h>
|
||||
#include <memory/addresses.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <color.h>
|
||||
|
||||
terminal_t* terminal = (terminal_t*)TERMINAL_INFO_LOC;
|
||||
|
||||
int32_t terminalWrite(const void* buf, uint32_t len) { // TODO fix font size
|
||||
terminal->width = gfxMode->xRes / 8;//*(uint8_t*)(FONT_LOC);
|
||||
terminal->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(' ', terminal->x, terminal->y, terminal->fg, terminal->bg);
|
||||
terminal->y++;
|
||||
terminal->x = 0;
|
||||
} else if (str[i] == '\b') {
|
||||
drawChar(' ', terminal->x, terminal->y, terminal->fg, terminal->bg);
|
||||
if (terminal->x == 0) {
|
||||
terminal->x = terminal->width - 1;
|
||||
terminal->y--; // Y could be 0?
|
||||
} else {
|
||||
terminal->x--;
|
||||
}
|
||||
drawChar(' ', terminal->x, terminal->y, terminal->fg, terminal->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
|
||||
terminal->y -= args[0];
|
||||
break;
|
||||
case 'B': // Cursor down
|
||||
terminal->y += args[0];
|
||||
break;
|
||||
case 'C': // Cursor left
|
||||
terminal->x -= args[0];
|
||||
break;
|
||||
case 'D': // Cursor right
|
||||
terminal->x += args[0];
|
||||
break;
|
||||
case 'E': // nth row
|
||||
terminal->x = args[0];
|
||||
break;
|
||||
case 'F': // nth col
|
||||
terminal->y = args[0];
|
||||
break;
|
||||
case 'G': // show/hide cursor
|
||||
terminal->hideCursor = args[0] ? false : true;
|
||||
break;
|
||||
case 'H': // move cursor to (x,y)
|
||||
terminal->x = args[0];
|
||||
terminal->y = args[1];
|
||||
break;
|
||||
case 'I': // RESERVED
|
||||
case 'J': // Erase screen
|
||||
clearScreen(terminal->bg);
|
||||
break;
|
||||
case 'K': // Erase line
|
||||
break; // TODO
|
||||
case 'L': // Erase collumn
|
||||
break; // TODO
|
||||
case 'M': // Set FG
|
||||
if (args[0] < 8) {
|
||||
terminal->fg = codeToColor(args[0]);
|
||||
} else if (args[0] == 8) {
|
||||
terminal->fg = FG_COLOR;
|
||||
}
|
||||
break;
|
||||
case 'N': // Set BG
|
||||
if (args[0] < 8) {
|
||||
terminal->bg = codeToColor(args[0]);
|
||||
} else if (args[0] == 8) {
|
||||
terminal->bg = BG_COLOR;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
} else {
|
||||
drawChar(str[i], terminal->x, terminal->y, terminal->fg, terminal->bg);
|
||||
terminal->x++;
|
||||
|
||||
if (terminal->x >= terminal->width) { // Go to next line
|
||||
terminal->y++;
|
||||
terminal->x = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
scroll();
|
||||
|
||||
return i; // Number of characters that were printed
|
||||
}
|
||||
|
||||
void toggleCursor() {
|
||||
static bool visible = false;
|
||||
visible = !visible;
|
||||
|
||||
drawChar(visible ? 127 : ' ', terminal->x, terminal->y, terminal->fg, terminal->bg);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user