mirror of
https://github.com/Tom-on64/kern.git
synced 2026-11-04 02:23:10 +00:00
MAJOR RESTRUCTURE
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
#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));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
; 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
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
#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"); }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#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
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#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; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
#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");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
#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");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
#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
|
||||
@@ -0,0 +1,27 @@
|
||||
#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
|
||||
@@ -0,0 +1,19 @@
|
||||
#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
|
||||
@@ -0,0 +1,14 @@
|
||||
#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
|
||||
@@ -0,0 +1,48 @@
|
||||
#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
|
||||
@@ -0,0 +1,14 @@
|
||||
#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
|
||||
@@ -0,0 +1,25 @@
|
||||
#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
|
||||
@@ -0,0 +1,23 @@
|
||||
#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
|
||||
@@ -0,0 +1,14 @@
|
||||
#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
|
||||
@@ -0,0 +1,83 @@
|
||||
#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
|
||||
@@ -0,0 +1,22 @@
|
||||
#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
|
||||
@@ -0,0 +1,61 @@
|
||||
#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
|
||||
@@ -0,0 +1,27 @@
|
||||
#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
|
||||
@@ -0,0 +1,33 @@
|
||||
#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
|
||||
@@ -0,0 +1,70 @@
|
||||
#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
|
||||
@@ -0,0 +1,72 @@
|
||||
#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
|
||||
@@ -0,0 +1,18 @@
|
||||
#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
|
||||
@@ -0,0 +1,18 @@
|
||||
#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
|
||||
@@ -0,0 +1,23 @@
|
||||
#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
|
||||
@@ -0,0 +1,19 @@
|
||||
#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
|
||||
@@ -0,0 +1,17 @@
|
||||
#
|
||||
# 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
|
||||
|
||||
@@ -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,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 <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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#include <syscalls/syscalls.h>
|
||||
#include <cpu/isr.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int sys_close(intFrame_t* iframe) {
|
||||
// TODO
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#include <syscalls/syscalls.h>
|
||||
#include <cpu/isr.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int sys_open(intFrame_t* iframe) {
|
||||
// TODO
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <syscalls/syscalls.h>
|
||||
#include <cpu/isr.h>
|
||||
|
||||
int sys_seek(intFrame_t* iframe) {
|
||||
// TODO
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
#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; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
#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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user