Espresso 0.0.2a

This commit is contained in:
2025-10-20 21:57:30 -05:00
parent 102d517097
commit ff6cba1164
59 changed files with 29272 additions and 773 deletions

View File

@ -1,21 +0,0 @@
Modules and Drivers API
This file contains documentation for the Module/Driver API.
The kernel symtab is always at 0xC0101000, and can go up to 0xC0101000 + 0x8086 ( See what I did there?)
ID number -- Function -- Returns -- Arguments
0 -- get_kinfo -- kinfo_t -- uint32_t leaf
1 -- make_kfunc -- kfunc_t -- void* addr, bool module, uint16_t module_id, uint32_t function_id
2 -- add_kfunc -- uint32_t -- void* addr, bool module, uint16_t module_id, uint32_t function_id
3 -- printf -- void -- const char* format, ...
4 -- malloc -- void* -- size_t size
5 -- free -- void -- void* ptr
6 -- calloc -- void* -- size_t nmemb, size_t size
7 -- realloc -- void* -- void* ptr, size_t size
8 -- get_key -- uint16_t -- void
9 -- get_string -- char* -- void
10 --

View File

@ -4,15 +4,16 @@ ISO := boot/espresso.iso
CC := i686-elf-gcc
AS := i686-elf-as
NASM := nasm
QEMU_MKE_IMG := qemu-img create -f raw espresso.img 256M
QEMU_MKE_IMG := qemu-img create -f raw espresso.img 64M
MKFS_VFAT := sudo mkfs.vfat
MKFS_FLAGS := -F 32 -S 512
NASMFLAGS := -f elf32
WNOFLAGS := -Wno-discarded-qualifiers
CFLAGS := -std=gnu99 -ffreestanding -O2 -Wall -Wextra -msse4 $(WNOFLAGS)
LDFLAGS := -T linker.ld -ffreestanding -O2 -nostdlib
CFLAGS := -std=gnu99 -ffreestanding -O2 -Wall -Wextra -msse $(WNOFLAGS) -nostdlib -nostartfiles -include kincl.h
LDFLAGS := -T linker.ld -ffreestanding -O2 -nostdlib -nostartfiles
QEMUFLAGS := -boot d -cdrom $(ISO) -drive file=espresso.img,format=raw,if=ide,readonly=off,rerror=report,werror=report -cpu qemu32,sse4.1
QEMUFLGS_EXT := -net none -netdev user,id=n0 -device rtl8139,netdev=n0 -vga std #-singlestep
QEMUFLGS_EXT := -vga std -d int,cpu_reset -D qemu.log -no-reboot #-singlestep
MOR_QEMUFLGS := -net none -netdev user,id=n0 -device rtl8139,netdev=n0 -serial file:serial.log
SRC_DIRS := kernel drivers lib
INCLUDE_DIRS := include
ARCH_DIR := arch
@ -46,6 +47,10 @@ buildc: all iso run clean
# === Default target ===
all: $(TARGET)
# === Debug build ===
debug:
$(MAKE) clean
$(MAKE) CFLAGS="$(CFLAGS) -D_DEBUG" $(TARGET)
# === Linking ===
$(TARGET): ./arch/x86/boot/boot.o $(filter-out boot.o, $(OBJ_LINK_LIST))
@ -73,10 +78,11 @@ iso: $(TARGET)
# === Run in QEMU ===
run: iso
$(QEMU_MKE_IMG)
echo "\n"
$(MKFS_VFAT) $(MKFS_FLAGS) espresso.img
qemu-system-i386 $(QEMUFLAGS) $(QEMUFLGS_EXT)
@if [ ! -f espresso.img ]; then \
$(QEMU_MKE_IMG); \
fi
@echo
qemu-system-i386 $(QEMUFLAGS) $(QEMUFLGS_EXT) $(MOR_QEMUFLGS)
# === Clean all build artifacts ===
@ -85,5 +91,4 @@ clean:
rm -rf $(ISO_DIR)
rm -f espresso.img
.PHONY: all clean iso run
.PHONY: all clean iso run debug build buildc

View File

@ -21,7 +21,7 @@ forced to be within the first 8 KiB of the kernel file.
/*
The multiboot standard does not define the value of the stack pointer register
(esp) and it is up to the kernel to provide a stack. This allocates room for a
small stack by creating a symbol at the bottom of it, then allocating 16384
small stack by creating a symbol at the bottom of it, then allocating 65536
bytes for it, and finally creating a symbol at the top. The stack grows
downwards on x86. The stack is in its own section so it can be marked nobits,
which means the kernel file is smaller because it does not contain an
@ -30,10 +30,10 @@ System V ABI standard and de-facto extensions. The compiler will assume the
stack is properly aligned and failure to align the stack will result in
undefined behavior.
*/
.section .bss
.section .stack
.align 16
stack_bottom:
.skip 16384 # 16 KiB
.skip 65536 # 64 KiB
stack_top:
/*
@ -183,7 +183,6 @@ _start:
/*
Call _kernel_early, early low-level initialization will happen there.
NOTE: I don't use 'jmp' because it doesn't work. Nice try.
*/
call _kernel_early

57
arch/x86/cpuid.s Normal file
View File

@ -0,0 +1,57 @@
/*
Just a bunch of CPUID stuff.
*/
.extern sse_initialized
.section .text
_init_cpuid:
pusha
pushf
pop %eax
mov %eax, %ecx
xor $0x200000, %eax
push %eax
popf
/*pushf*/
pop %eax
xor %ecx, %eax
jz .no_cpuid
lea _has_cpuid, %edi
movl $1, (%edi)
jmp .done
.no_cpuid:
lea _has_cpuid, %edi
movl $0, (%edi)
jmp .done
.done:
popa
ret
_sse_level:
lea _has_sse, %edi
lea sse_initialized, %esi
movl (%esi), %eax
movl %eax, (%edi)
.section .data
.global _has_cpuid
_has_cpuid: .int 0
_has_sse: .int 0
_has_mmx: .int 0

46
arch/x86/cpuid_asm.asm Normal file
View File

@ -0,0 +1,46 @@
.global get_cpu_brand_string
.type get_cpu_brand_string, @function
get_cpu_brand_string:
pushad # Save all general-purpose registers
mov ebx, eax # Save buffer pointer to ebx
mov eax, 0x80000000
cpuid
cmp eax, 0x80000004 # Check if brand string is supported
jb .not_supported
mov esi, ebx # Copy address to ESI
mov eax, 0x80000002
cpuid
mov [esi], eax
mov [esi + 4], ebx
mov [esi + 8], ecx
mov [esi + 12], edx
mov eax, 0x80000003
cpuid
mov [esi + 16], eax
mov [esi + 20], ebx
mov [esi + 24], ecx
mov [esi + 28], edx
mov eax, 0x80000004
cpuid
mov [esi + 32], eax
mov [esi + 36], ebx
mov [esi + 40], ecx
mov [esi + 44], edx
jmp .done
.not_supported:
mov byte [ebx], 0 # Null-terminate if not supported
.done:
popad
ret

0
arch/x86/cpuid_asm.s Normal file
View File

View File

@ -3,25 +3,16 @@
Mostly so I could get more experience in assembler.
*/
/*
DO NOT USE "pusha" AND/OR "popa"!!!
THEY ARE DEPRECATED (or something like that)
AND SHOULD NOT BE USED!!!
INSTEAD PUSH/POP REGISTERS ON/OFF THE STACK INDIVIDUALLY!!!
*/
.section .text
.global _enable_paging_asm
.global _push_regs
.global _pop_regs
.global _hang_asm
.global _halt_asm
.global _sti_asm
.global _cli_asm
_enable_paging_asm:
@ -34,30 +25,6 @@ _enable_paging_asm:
pop %eax
ret
_push_regs:
push %eax
push %ebx
push %ecx
push %edx
push %esi
push %edi
push %esp
push %ebp
ret
_pop_regs:
pop %ebp
pop %esp
pop %edi
pop %esi
pop %edx
pop %ecx
pop %ebx
pop %eax
ret
_hang_asm:
hlt
@ -70,5 +37,7 @@ _halt_asm:
_sti_asm:
sti
ret
.section .data
_cli_asm:
cli
ret

View File

@ -0,0 +1,6 @@
so far, heap starts at 0xC2000000, and is (8 * 1024 * 1024) (0x80000) or (8MiB) bytes, and ends at 0xC2080000

View File

@ -1,7 +0,0 @@
Notes about the PS/2 keyboard driver.
the actual key-codes are not what you might expect.
what I mean is, what does 0x3F mean? what key was pressed?
The keyset used by Espresso is pretty much the ASCII code set.
Minus a few codes, some are replaced with other functions.

View File

@ -13,10 +13,10 @@
elf_executable_t* load_elf32(void* elf_data)
{
Elf32_Ehdr* ehdr = (Elf32_Ehdr*)elf_data;
/*Elf32_Ehdr* ehdr = (Elf32_Ehdr*)elf_data;*/
/* Check ELF magic */
if (memcmp(ehdr->e_ident, (uint8_t*)("\x7F""ELF"), 4) != 0)
/*if (memcmp(ehdr->e_ident, (uint8_t*)("\x7F""ELF"), 4) != 0)
{
printf("Invalid ELF file\n");
return NULL;
@ -58,6 +58,8 @@ elf_executable_t* load_elf32(void* elf_data)
elf_executable_t* result = malloc(sizeof(elf_executable_t));
result->entry_point = (void*)(uintptr_t)ehdr->e_entry;
return result;
return result;*/
return NULL;
}

117
drivers/fs/ssfs.c Normal file
View File

@ -0,0 +1,117 @@
#include <types.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <drivers/ide.h>
#include <fs/ssfs.h>
#define SSFS_START_LBA 16
#define SSFS_FILE_HEADER_SIZE_BYTES 32
int ssfs_read_file(const char* name, void* buffer, int size)
{
if (strlen(name) > 15)
{
return -1;
}
uint8_t header_buf[512];
int r = read_sector(16, header_buf);
if (r != 0)
{
return -2;
}
ssfs_file_header_t f;
memcpy(&f, header_buf, sizeof(f));
if (strncmp(f.filename, name, 15) != 0)
{
return -3;
}
/* Clamp read size to actual file size */
if (size > (int)f.num_bytes)
size = (int)f.num_bytes;
int total_read = 0;
int sector_count = div_round_up(size, 512);
uint8_t sector_data[512];
for (int k = 0; k < sector_count; k++)
{
r = read_sector(f.start_sector + k, sector_data);
if (r != 0)
{
return -4; /* I/O error */
}
int to_copy = size - total_read;
if (to_copy > 512)
{
to_copy = 512;
}
memcpy((uint8_t*)buffer + total_read, sector_data, to_copy);
total_read += to_copy;
}
return 0;
}
/* size is number of bytes */
int ssfs_write_file(const char* name, void* data, int size)
{
ssfs_file_header_t* f = (ssfs_file_header_t*) malloc(sizeof(ssfs_file_header_t));
memset(f, 0, sizeof(ssfs_file_header_t));
if (strlen(name) > 15)
{
return -1;
}
strcpy(f->filename, name);
f->num_sectors = 0;
int sector_count = div_round_up(size, 512);
uint8_t* buffer = (uint8_t*) malloc(sector_count * 512);
memset(buffer, 0, sector_count * 512);
memcpy(buffer, data, (size_t) size);
int r = 0;
f->start_sector = 32;
for (int k = 0; k < sector_count; k++)
{
r = write_sector(f->start_sector + k, buffer + (k * 512));
if (r != 0)
{
break;
}
}
f->num_sectors = sector_count;
f->num_bytes = (uint32_t) size;
uint8_t header_buf[512];
memset(header_buf, 0, 512);
memcpy(header_buf, f, sizeof(*f));
write_sector(16, header_buf);
free(buffer);
free(f);
return 0;
}

View File

@ -63,10 +63,16 @@ int32_t ide_identify(uint8_t drive, uint16_t* buffer)
return 0;
}
void ide_initialize(void) {
void ide_initialize(void)
{
#ifdef _DEBUG
printf("[ IDE ] Initializing IDE system...\n");
#endif
outb(ATA_PRIMARY_CTRL, 0x02); /* Disable IRQs from IDE disk controllers TODO: should probably use IRQs soon */
uint16_t identify_buf[256];
volatile uint16_t identify_buf[256];
if (ide_identify(0, identify_buf) == 0)
{
char model[41];
@ -78,9 +84,18 @@ void ide_initialize(void) {
model[40] = 0;
printf("Disk model: %s\n", model);
}
else
{
printf("ide_initialize(): ide_identify(0, identify_buf) did NOT return 0!\n");
}
#ifdef _DEBUG
printf("[ IDE ] IDE initialized\n");
#endif
}
int32_t ide_read48(uint8_t drive, uint64_t lba, uint8_t sector_count, void* buffer) {
int32_t ide_read48(uint8_t drive, uint64_t lba, uint8_t sector_count, void* buffer)
{
if (sector_count == 0)
{
return -1;

View File

@ -1,13 +1,13 @@
#include <stdio.h>
#include <drivers/ps2_keyboard.h>
#include <drivers/pit.h>
#include <port_io.h>
#include <drivers/irq.h>
#define NUM_IRQS 0x90
irq_func_t func_list[NUM_IRQS];
irq_func_t aux_func_list[NUM_IRQS];
@ -15,9 +15,10 @@ static volatile uint32_t num_irqs_missed = 0;
void irq_init(void)
{
memset(func_list, 0x0, NUM_IRQS);
memset(aux_func_list, 0x0, NUM_IRQS);
for (int i = 0; i < NUM_IRQS; i++)
{
func_list[i] = 0x0;
}
set_irq_handler(0, (irq_func_t*)pit_handler);
set_irq_handler(1, (irq_func_t*)keyboard_handler);
}
@ -29,10 +30,7 @@ void irq_handler(uint8_t irq_number)
if (func_list[irq_number])
{
func_list[irq_number]();
}
else if (aux_func_list[irq_number])
{
aux_func_list[irq_number]();
outb(0x20, 0x20); /* Acknowledge the IRQ to PIC */
}
else
{
@ -48,21 +46,3 @@ void set_irq_handler(uint32_t num, irq_func_t* handler)
func_list[num] = (irq_func_t)handler;
}
}
void add_irq_handler(uint32_t num, irq_func_t* handler)
{
if (num < NUM_IRQS)
{
if (func_list[num] != 0x0)
{
if (aux_func_list[num] == 0x0)
{
aux_func_list[num] = (irq_func_t)handler;
}
return;
}
func_list[num] = (irq_func_t)handler;
}
}

View File

@ -58,6 +58,18 @@ void pci_config_read_block(uint8_t bus, uint8_t device, uint8_t function, uint8_
}
}
void pci_init(void)
{
#ifdef _DEBUG
printf("[ PCI ] Initializing PCI...\n");
#endif
pci_enumerate();
#ifdef _DEBUG
printf("[ PCI ] PCI initialized\n");
#endif
}
void pci_enumerate(void)
{
@ -77,7 +89,7 @@ void pci_enumerate(void)
if (pre_header.class_code == 0xB)
{
printf("Processor found on PCI bus, what?!?!\n");
printf("Processor found on PCI bus, what?!?!\n"); /* For some stupid reason, processors can be on the PCI bus? */
continue;
}
@ -90,6 +102,9 @@ void pci_enumerate(void)
{
/*configure_ahci_controller(hdr);*/
}
/*printf("PCI device: cc: %x sc: %x pi: %x b: %x d: %x f: %x int: %x\n", hdr.class_code, hdr.subclass, hdr.prog_if, bus, device, function, (uint32_t) hdr.interrupt_line);*/
}
}
}

View File

@ -14,7 +14,11 @@ volatile uint64_t pit_ticks = 0;
bool pit_initialized = false;
void pit_init(void)
{
{
#ifdef _DEBUG
printf("[ PIT ] Initializing the PIT...\n");
#endif
uint16_t divisor = (uint16_t)1193;
/* Send command byte */
@ -25,6 +29,10 @@ void pit_init(void)
outb(PIT_CHANNEL0, (uint8_t)((divisor >> 8) & 0xFF)); /* High byte */
pit_initialized = true;
#ifdef _DEBUG
printf("[ PIT ] PIT Initialized\n");
#endif
}
void pit_handler(void)

View File

@ -2,7 +2,7 @@
#include <port_io.h>
#include <tty.h>
#include <stdlib.h>
#include <ksymtab.h>
#include <drivers/ps2_keyboard.h>
@ -29,6 +29,8 @@
#define KEYBOARD_IRQ 1
#define RETURN_STI() do { _sti_asm(); return; } while (0)
bool ps2keyboard_initialized = false;
/* State for shift key */
@ -41,14 +43,25 @@ static bool capslock_pressed = false;
static bool extended = false;
static bool is_new_char = false;
static bool is_new_key = false;
static bool is_new_key = false;
static bool gets_called = false;
static volatile bool gets_finished = false;
volatile unsigned char current_char;
volatile char* current_string = NULL;
volatile char* current_string = NULL;
volatile char* gets_string = NULL;
volatile int32_t current_length = 0;
volatile int32_t capacity = 0;
volatile int32_t gets_length = 0;
volatile int32_t capacity = 0;
volatile int32_t gets_capacity = 0;
volatile uint16_t current_key;
volatile ps2_hook_t* hooks = NULL;
volatile int hook_count = 0;
extern void _cli_asm(void);
extern void _sti_asm(void);
static const char scancode_map[128] = {
0, 27, '1','2','3','4','5','6','7','8','9','0','-','=','\b', /* Backspace */
@ -69,15 +82,134 @@ static const char scancode_map[128] = {
void keyboard_init(void)
{
#ifdef _DEBUG
printf("[ PS/2 KBD ] Initializing the PS/2 keyboard...\n");
#endif
outb(0x64, 0xAE); /* Enable keyboard interface (often optional, but here for safety) */
hooks = (ps2_hook_t*) malloc(sizeof(ps2_hook_t) * hook_count);
ps2keyboard_initialized = true;
#ifdef _DEBUG
printf("[ PS/2 KBD ] PS/2 Keyboard initialized\n");
#endif
}
bool setup_hook(ps2_hook_t func)
{
_cli_asm();
ps2_hook_t* copy = malloc(sizeof(ps2_hook_t) * hook_count);
if (hook_count > 0 && copy == NULL)
{
return false;
}
if (hook_count > 0)
{
memcpy(copy, hooks, sizeof(ps2_hook_t) * hook_count);
}
free((void*) hooks);
hooks = malloc(sizeof(ps2_hook_t) * (hook_count + 1));
if (hooks == NULL)
{
return false;
}
if (hook_count > 0)
{
memcpy((void*) hooks, copy, sizeof(ps2_hook_t) * hook_count);
}
free(copy);
hooks[hook_count] = func;
hook_count++;
_sti_asm();
return true;
}
bool remove_hook(ps2_hook_t func)
{
_cli_asm();
int index = -1;
for (int i = 0; i < hook_count; i++)
{
if (hooks[i] == func)
{
index = i;
break;
}
}
if (index == -1)
{
return false;
}
for (int i = index; i < hook_count - 1; i++)
{
hooks[i] = hooks[i + 1];
}
hook_count--;
if (hook_count == 0)
{
free((void*) hooks);
hooks = NULL;
return false;
}
ps2_hook_t* smaller = malloc(sizeof(ps2_hook_t) * hook_count);
if (smaller == NULL)
{
return false;
}
memcpy(smaller, (void*) hooks, sizeof(ps2_hook_t) * hook_count);
free((void*) hooks);
hooks = smaller;
_sti_asm();
return true;
}
void call_hooks(char c)
{
_cli_asm();
if (hook_count == 0)
{
return;
}
for (int i = 0; i < hook_count; i++)
{
hooks[i](c);
}
_sti_asm();
}
char get_char(void)
{
/*
ASCII code 5 (Enquiry) is/was used in legacy systems meant for requesting a response from a remote terminal or device.
For example, one system might send ENQ (ASCII 5), and the receiver could reply with ACK (ASCII 6) to indicate its ready or still online.
For example, one system might send ENQ (ASCII 5), and the receiver could reply with ACK (ASCII 6) to indicate it's ready or still online.
In modern computing, ENQ is largely obsolete:
@ -87,16 +219,13 @@ char get_char(void)
- It may still appear in legacy systems, embedded devices, or proprietary serial protocols, but that's niche.
*/
char temp = 5;
if (is_new_char)
if (!is_new_char)
{
temp = current_char;
return 5;
}
is_new_char = false;
return temp;
return current_char;
}
uint16_t get_key(void)
@ -122,39 +251,184 @@ char* get_string(void)
return current_string;
}
static void append_char(char c)
char* kbd_gets(void)
{
gets_called = true;
gets_finished = false;
while (gets_finished != true)
{
sleep(1);
}
char* result = strdup(gets_string); /* Could be NULL, that is checked below */
free(gets_string);
gets_string = NULL;
gets_capacity = 0;
gets_length = 0;
gets_called = false;
return result == NULL ? "" : result;
}
void gets_append_char(unsigned char c)
{
_cli_asm();
if (!gets_string && gets_capacity > 0)
{
printf("[keyboard] ERROR: gets_string is NULL but capacity > 0!\n");
RETURN_STI();
}
if (c == KEY_ARROW_UP || c == KEY_ARROW_DOWN || c == KEY_ARROW_RIGHT || c == KEY_ARROW_LEFT)
{
gets_string[1] = '\0';
char tc = '\0';
switch (c)
{
case KEY_ARROW_UP:
tc = KEY_UP;
break;
case KEY_ARROW_DOWN:
tc = KEY_DOWN;
break;
case KEY_ARROW_RIGHT:
tc = KEY_RIGHT;
break;
case KEY_ARROW_LEFT:
tc = KEY_LEFT;
break;
default:
tc = '\0';
break;
}
gets_string[0] = tc;
gets_finished = true;
RETURN_STI();
}
else if (c == '\n')
{
/* The returned string must/will not have newlines in it, so we return here after setting gets_finished to 'true'. */
gets_finished = true;
printf("\n");
RETURN_STI();
}
else if (c == 27) /* ASCII escape, here it's used to cancel input. */
{
gets_finished = true;
gets_string[0] = '\0';
RETURN_STI();
}
else if (c == '\b')
{
if (gets_length < 1)
{
RETURN_STI();
}
gets_length--;
gets_string[gets_length] = '\0';
printf("\b \b");
RETURN_STI();
}
if ((gets_length) >= gets_capacity)
{
int new_capacity = (gets_capacity == 0) ? 64 : gets_capacity * 2;
char* new_str = (char*) malloc(new_capacity);
if (!new_str)
{
RETURN_STI();
}
if (gets_string)
{
for (int i = 0; i < gets_length; i++)
{
new_str[i] = gets_string[i];
}
new_str[gets_length] = '\0';
free(gets_string);
}
gets_string = new_str;
gets_capacity = new_capacity;
}
if (!gets_string)
{
RETURN_STI();
}
gets_string[gets_length] = (char) c;
gets_length++;
gets_string[gets_length] = '\0';
printf("%c", c);
RETURN_STI();
}
void append_char(char c)
{
_cli_asm();
if (current_length + 1 >= capacity)
{
/* Need more space (+1 for the null zero) */
int new_capacity = (capacity == 0) ? 16 : capacity * 2;
char* new_str = (char*)malloc(new_capacity);
if (!new_str) {
char* new_str = (char*) malloc(new_capacity);
if (!new_str)
{
printf("[keyboard] ERROR: malloc failed for new input buffer\n");
return;
}
if (current_string)
{
memcpy(new_str, current_string, current_length);
free(current_string);
}
if (!current_string)
{
return;
}
current_string = new_str;
capacity = new_capacity;
}
if (!current_string)
{
return;
}
current_string[current_length] = c;
current_length++;
current_string[current_length] = '\0'; /* Maintain null terminator */
current_string[current_length] = '\0';
_sti_asm();
}
static void free_current_string(void)
void free_current_string(void)
{
if (current_string)
{
@ -198,8 +472,8 @@ void keyboard_handler(void)
}
else
{
uint16_t c = (uint16_t)scancode_map[scancode];
if ((shift_pressed ^ capslock_pressed) && ((char)c >= 'a') && ((char)c <= 'z'))
uint16_t c = (uint16_t) scancode_map[scancode];
if ((shift_pressed ^ capslock_pressed) && ((char) c >= 'a') && ((char) c <= 'z'))
{
c -= 32; /* Convert to uppercase */
}
@ -208,11 +482,10 @@ void keyboard_handler(void)
c = (uint16_t) terminal_get_shifted((unsigned char) c);
}
/*if (scancode == 0x1C) {
printf("\n");
return;
}*/
if (hook_count > 0)
{
call_hooks(c);
}
if (extended)
{
@ -235,6 +508,13 @@ void keyboard_handler(void)
break;
}
if (gets_called)
{
gets_append_char(c);
return;
}
current_key = c;
is_new_key = true;
@ -242,20 +522,35 @@ void keyboard_handler(void)
return;
}
if (gets_called)
{
gets_append_char(c);
return;
}
if (c)
{
if (c != '\n')
{
append_char(c);
}
current_char = c;
is_new_char = true;
if (c == '\n')
{
/*append_char(c);
current_char = c;
is_new_char = true;*/
free_current_string();
}
append_char(c);
}
}
}

88
drivers/serio.c Normal file
View File

@ -0,0 +1,88 @@
/*
Driver for serial output.
Mostly useful for debug output because QEMU allows the redirection of serial output to either stdio or a file on the host computer.
*/
#include <types.h>
#include <port_io.h>
#include <string.h>
#include <drivers/serio.h>
#define COM1_IO_ADDR 0x3F8
#define COM2_IO_ADDR 0x2F8
#define COM1_IRQ 0x4
#define COM2_IRQ 0x3
#define COM1_LCR (COM1_IO_ADDR + 3)
#define COM2_LCR (COM2_IO_ADDR + 3)
#define BAUD 57600
#define DIVISOR 2
int serial_init(void)
{
/* The following is taken from https://wiki.osdev.org/Serial_Ports */
outb(COM1_IO_ADDR + 1, 0x00); // Disable all interrupts
outb(COM1_IO_ADDR + 3, 0x80); // Enable DLAB (set baud rate divisor)
outb(COM1_IO_ADDR + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud
outb(COM1_IO_ADDR + 1, 0x00); // (hi byte)
outb(COM1_IO_ADDR + 3, 0x03); // 8 bits, no parity, one stop bit
outb(COM1_IO_ADDR + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
outb(COM1_IO_ADDR + 4, 0x0B); // IRQs enabled, RTS/DSR set
outb(COM1_IO_ADDR + 4, 0x1E); // Set in loopback mode, test the serial chip
outb(COM1_IO_ADDR + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte)
// Check if serial is faulty (i.e: not same byte as sent)
if(inb(COM1_IO_ADDR + 0) != 0xAE)
{
return 1;
}
// If serial is not faulty set it in normal operation mode
// (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled)
outb(COM1_IO_ADDR + 4, 0x0F);
return 0;
}
static int is_transmit_empty(void)
{
return inb(COM1_IO_ADDR + 5) & 0x20;
}
static int serial_received(void)
{
return inb(COM1_IO_ADDR + 5) & 1;
}
void serial_write(char a)
{
while (is_transmit_empty() == 0);
outb(COM1_IO_ADDR, a);
}
void serial_puts(const char* s)
{
for (int i = 0; i < (int) strlen(s); i++)
{
serial_write(s[i]);
}
}
char serial_read(void)
{
while (serial_received() == 0);
return inb(COM1_IO_ADDR);
}
bool use_serial(void)
{
return true;
}

View File

@ -1,16 +1,21 @@
#include <string.h>
#include <vga/vga.h>
#include <stdio.h>
#include <port_io.h>
#include <tty.h>
static size_t terminal_row;
static size_t terminal_column;
static uint8_t terminal_color;
static uint16_t* terminal_buffer;
size_t terminal_row;
size_t terminal_column;
uint8_t terminal_color;
uint16_t* terminal_buffer;
void terminal_initialize(void)
{
terminal_initializec(0x00);
terminal_update_cursor();
}
void terminal_initializec(uint8_t color)
@ -22,11 +27,13 @@ void terminal_initializec(uint8_t color)
{
terminal_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
}
else {
else
{
terminal_color = color;
}
terminal_buffer = VGA_MEMORY;
for (size_t y = 0; y < VGA_HEIGHT; y++)
{
for (size_t x = 0; x < VGA_WIDTH; x++)
@ -55,6 +62,7 @@ void terminal_putentryat(unsigned char c, uint8_t color, size_t x, size_t y)
void terminal_putchar(const char c)
{
unsigned char uc = c;
if (uc == '\n')
@ -62,9 +70,21 @@ void terminal_putchar(const char c)
terminal_column = 0;
if (++terminal_row == VGA_HEIGHT)
{
terminal_scroll();
terminal_row = VGA_HEIGHT - 1;
if (1)
{
terminal_scroll();
terminal_row = VGA_HEIGHT - 1;
}
else
{
terminal_clear();
terminal_row = 0;
}
}
terminal_update_cursor();
return;
}
else if (uc == '\t')
@ -76,28 +96,35 @@ void terminal_putchar(const char c)
terminal_putchar('\n');
}
terminal_update_cursor();
return;
}
else if (uc == '\b')
{
if (terminal_column == 0)
{
terminal_row -= 1;
if (terminal_row == (size_t)-1)
if (terminal_row > 0)
{
terminal_row = 0;
terminal_row--;
terminal_column = VGA_WIDTH - 1;
}
else
{
terminal_update_cursor(); /* For good measure */
terminal_column = VGA_WIDTH;
terminal_putentryat(' ', terminal_getcolor(), (size_t)terminal_column, (size_t)terminal_row);
return;
}
}
else
{
terminal_putentryat(' ', terminal_getcolor(), (size_t)--terminal_column, (size_t)terminal_row);
terminal_column--;
}
terminal_putentryat(' ', terminal_color, terminal_column, terminal_row);
terminal_update_cursor();
return;
}
@ -110,9 +137,10 @@ void terminal_putchar(const char c)
if (++terminal_row == VGA_HEIGHT)
{
terminal_scroll();
terminal_row = VGA_HEIGHT - 1;
}
}
terminal_update_cursor();
}
void terminal_write(const char* data, size_t size)
@ -157,7 +185,7 @@ void terminal_clear(void)
void terminal_clearl(size_t num_lines)
{
if (num_lines == (size_t)-1)
if (num_lines == (size_t) -1)
{
terminal_initializec(terminal_getcolor());
}
@ -182,20 +210,18 @@ void terminal_clearl(size_t num_lines)
void terminal_scroll(void)
{
for (size_t y = 1; y < VGA_HEIGHT; y++)
memmove(
terminal_buffer,
terminal_buffer + VGA_WIDTH,
sizeof(uint16_t) * VGA_WIDTH * (VGA_HEIGHT/* + 1*/)
);
terminal_row = VGA_HEIGHT - 1;
for (int32_t k = 0; k < (int32_t)VGA_WIDTH; k++)
{
for (size_t x = 0; x < VGA_WIDTH; x++)
{
const size_t src_index = y * VGA_WIDTH + x;
const size_t dst_index = (y - 1) * VGA_WIDTH + x;
terminal_buffer[dst_index] = terminal_buffer[src_index];
}
}
for (size_t x = 0; x < VGA_WIDTH; x++)
{
const size_t index = (VGA_HEIGHT - 1) * VGA_WIDTH + x;
terminal_buffer[index] = (terminal_color << 8) | ' ';
terminal_putentryat((unsigned char)' ', terminal_getcolor(), (size_t)terminal_row, (size_t)k);
}
}
@ -208,7 +234,7 @@ unsigned char terminal_get_shifted(unsigned char uc)
unsigned char syms1[] = { ',', '.', '/', ';', '\'', '[', ']', '`', '-', '=', '\\', '\0' };
unsigned char syms2[] = { '<', '>', '?', ':', '\"', '{', '}', '~', '_', '+', '|', '\0' };
for (int32_t i = 0; i < (int32_t)(strlen((char*)lowerc)); ++i)
for (int32_t i = 0; i < (int32_t) (strlen((char*)lowerc)); ++i)
{
if (uc == lowerc[i])
{
@ -220,7 +246,7 @@ unsigned char terminal_get_shifted(unsigned char uc)
}
}
for (int32_t i = 0; i < (int32_t)(strlen((char*)nums)); ++i)
for (int32_t i = 0; i < (int32_t) (strlen((char*)nums)); ++i)
{
if (uc == nums[i])
{
@ -232,7 +258,7 @@ unsigned char terminal_get_shifted(unsigned char uc)
}
}
for (int32_t i = 0; i < (int32_t)(strlen((char*)syms1)); ++i)
for (int32_t i = 0; i < (int32_t) (strlen((char*) syms1)); ++i)
{
if (uc == syms1[i])
{
@ -251,7 +277,20 @@ void terminal_set_cursor(uint16_t row, uint16_t column)
{
if (row < VGA_HEIGHT && column < VGA_WIDTH)
{
terminal_row = (size_t)row;
terminal_column = (size_t)column;
terminal_row = (size_t) row;
terminal_column = (size_t) column;
}
terminal_update_cursor();
}
void terminal_update_cursor(void)
{
uint16_t pos = terminal_row * VGA_WIDTH + terminal_column;
outb(0x3D4, 0x0F);
outb(0x3D5, (uint8_t) (pos & 0xFF));
outb(0x3D4, 0x0E);
outb(0x3D5, (uint8_t) ((pos >> 8) & 0xFF));
}

16
include/ctype.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef _CHAR_TYPE_H
#define _CHAR_TYPE_H
#include <types.h>
int32_t ischar(int32_t c);
int32_t isspace(char c);
int32_t isalpha(char c);
int isprint(int c);
char upper(char c);
char toupper(char c);
char lower(char c);
char toupper(char c);
char lower(char c);
#endif

View File

@ -62,6 +62,8 @@ struct pci_header_type_0 {
uint8_t max_latency;
} __attribute__((packed));
void pci_init(void);
uint32_t pci_config_read(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset);
void pci_config_write(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value);
void pci_enumerate(void);

View File

@ -2,16 +2,26 @@
#define _PS2_KEYBOARD_H
#include <types.h>
#include <drivers/irq.h>
typedef enum {
KEY_NONE = 0,
KEY_ARROW_UP = 0xAA0,
KEY_ARROW_UP = 0xFC,
KEY_ARROW_DOWN,
KEY_ARROW_LEFT,
KEY_ARROW_RIGHT,
/* Note: add more special keys here */
} special_key;
typedef enum {
KEY_UP = 0x1E,
KEY_DOWN = 0x1F,
KEY_RIGHT = 0x1C,
KEY_LEFT = 0x1D,
} lower_key;
typedef void (*ps2_hook_t)(char);
void keyboard_init(void);
void keyboard_handler(void);
@ -19,4 +29,9 @@ char get_char(void);
uint16_t get_key(void);
char* get_string(void);
char* kbd_gets(void);
bool setup_hook(ps2_hook_t func);
bool remove_hook(ps2_hook_t func);
#endif

14
include/drivers/serio.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef _SERIAL_IO_H
#define _SERIAL_IO_H
#include <types.h>
int serial_init(void);
void serial_write(char a);
void serial_puts(const char* s);
char serial_read(void);
bool use_serial(void);
#endif

19
include/fs/ssfs.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef _STUPID_SIMPLE_FS_H
#define _STUPID_SIMPLE_FS_H
#include <types.h>
typedef struct ssfs_file_header {
char filename[16]; /* 15 chars + null zero */
uint32_t num_sectors;
uint64_t start_sector;
uint32_t num_bytes;
/*uint8_t padding_[11];*/ /* 32 bytes without this */
} __attribute__((packed)) ssfs_file_header_t;
int ssfs_read_file(const char* name, void* buffer, int size);
int ssfs_write_file(const char* name, void* data, int size);
#endif

15
include/kdebug.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef _KERNEL_DEBUG_H
#define _KERNEL_DEBUG_H
#include <types.h>
void set_debug(void);
void clear_debug(void);
void toggle_debug(void);
bool get_debug(void);
#endif

View File

@ -2,6 +2,6 @@
#define _KERNEL_BOOT_H
uint8_t parse_boot_data(const char* data);
void clear_bss(void);
#endif

View File

@ -3,6 +3,7 @@
#include <types.h>
void intro_begin(void);
int16_t begin_anim(const char* version);
#endif

View File

@ -0,0 +1,7 @@
#ifndef _KERNEL_SHELL_DEBUGGER_H
#define _KERNEL_SHELL_DEBUGGER_H
void print_all_regs(void);
void print_gprs(void);
#endif

0
include/kernel/kshell.c Normal file
View File

8
include/kernel/kshell.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _KERNEL_SHELL_H
#define _KERNEL_SHELL_H
#include <types.h>
int kshell_start(int argc, char** argv);
#endif

7
include/kernel/vars.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _KERNEL_VARIABLES_H
#define _KERNEL_VARIABLES_H
void init_vars(void);
#endif

View File

@ -1,23 +0,0 @@
#ifndef _KSYMTAB_H
#define _KSYMTAB_H
#include <types.h>
typedef struct kfunc {
/*
Bit 31 = 1 -> driver/module function, Bit 31 = 0 -> kernel function
Bits 30-20 -> module/driver ID (11 bits)
Bits 19-0 -> function ID (20 bits)
*/
uint32_t id;
uint32_t addr; /* Pointer to function, 0x0 if nonexistent */
} kfunc_t;
uint64_t kfunc_call(kfunc_t* func, uint32_t a, uint32_t b, uint32_t c, uint32_t d);
uint64_t call_kfunc_by_id(uint32_t id, uint32_t a, uint32_t b, uint32_t c, uint32_t d);
uint32_t add_kfunc(void* addr, bool module, uint16_t module_id, uint32_t function_id);
kfunc_t make_kfunc(void* addr, bool module, uint16_t module_id, uint32_t function_id);
#endif

17
include/math.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef _MATH_H
#define _MATH_H
#include <types.h>
bool is_low_power_of_two(int n);
uint64_t int_pow(uint64_t base, uint32_t exp);
/* Divide a by b, rounding up */
static inline int div_round_up(int a, int b)
{
return (a + b - 1) / b;
}
#endif

View File

@ -1,19 +1,13 @@
#ifndef _HEAP_H
#define _HEAP_H
#include <types.h>
#define HEAP_START 0xC0000000
#define HEAP_SIZE (1024 * 4096) /* 1MB heap */
void heap_init(void);
#include <stddef.h>
#include <stdint.h>
void heap_init(uint32_t start, uint32_t size);
void* malloc(size_t size);
void* malloc_aligned(size_t size, size_t alignment);
void free(void* ptr);
void* calloc(size_t nmemb, size_t size);
void* realloc(void* ptr, size_t size);
void free(void* ptr);
#endif

View File

@ -1,9 +1,9 @@
#ifndef _PAGING_H
#define _PAGING_H
#include <types.h>
#include <stdint.h>
void paging_init(void);
void map_page(void* phys, void* virt);
void map_page(void* phys_addr, void* virt_addr);
#endif

View File

@ -4,8 +4,8 @@
#include <types.h>
#include <multiboot.h>
void pmm_init(multiboot_info_t* mb_info);
void* alloc_page(void);
void free_page(void* ptr);
void pmm_init(multiboot_info_t* mb);
void* pmm_alloc_page(void);
void pmm_free_page(void* addr);
#endif

12
include/mm_macros.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef _MM_MACROS_H
#define _MM_MACROS_H
#define MEMSET(ptr, value, num) \
do { \
unsigned char *_p = (unsigned char*)(ptr); \
for (size_t _i = 0; _i < (num); ++_i) \
_p[_i] = (unsigned char)(value); \
} while (0)
#endif

View File

@ -12,9 +12,13 @@ void printd(const char* str);
void printf(const char*, ...);
void print_int(int32_t value);
void print_lint(int64_t value);
void print_uint(uint32_t value);
void print_luint(uint64_t value);
void print_hex(uint32_t value, int width, bool uppercase);
void print_hex64(uint64_t value, int width, bool uppercase);
void print_double(double value, int precision);
void printf_set_color(uint8_t _color);
#endif

View File

@ -6,5 +6,11 @@
char getchar(void);
char* getstring(void);
char* gets(void); /* Use this instead of getstring() */
static inline void putchar(char c)
{
printf("%c", c);
}
#endif

View File

@ -2,6 +2,7 @@
#define STRING_H
#include <types.h>
#include <ctype.h>
/* TODO: change all applicable `int32_t`s with `size_t`s. */
@ -16,18 +17,17 @@ char* strdup(const char* s);
char* strtok(char* str, const char* delim);
char* strchr(const char* s, int c);
int32_t ischar(int32_t c);
int32_t isspace(char c);
int32_t isalpha(char c);
char upper(char c);
char lower(char c);
char toupper(char c);
char lower(char c);
void lowers(char* str);
void uppers(char* str);
void* memset(void *dst, char c, uint32_t n);
void* memset(void* dst, int c, size_t n);
void* memcpy(void *dst, const void *src, uint32_t n);
int32_t memcmp(const void *s1, const void *s2, size_t n);
void* memclr(void* m_start, size_t m_count);
void* memmove(void* dest, const void* src, size_t n);
int atoi(const char *str);
long atol(const char *str);
double atof(const char *str);
#endif

View File

@ -26,5 +26,6 @@ void terminal_scroll(void);
unsigned char terminal_get_shifted(unsigned char uc);
void terminal_set_cursor(uint16_t row, uint16_t column);
void terminal_update_cursor(void);
#endif

View File

@ -1,16 +1,66 @@
#include <stdint.h>
#include <string.h>
#include <cpuid.h>
#include <stdlib.h>
#include <kernel/boot.h>
uint8_t parse_boot_data(const char* data)
extern uint8_t __bss_start;
extern uint8_t __bss_end;
void clear_bss(void)
{
if (strlen(data) == 0)
{
return 0;
}
/*memset(&__bss_start, 0, &__bss_end - &__bss_start);*/
return 0;
for (int i = 0; i < ((&__bss_end) - (&__bss_start)); i++)
{
(&(__bss_start))[i] = 0x0;
}
}
char* get_cpu_vendor_string(void)
{
unsigned int eax, ebx, ecx, edx;
char vendor[13];
if (!__get_cpuid(0, &eax, &ebx, &ecx, &edx))
{
return strdup("Unknown");
}
memcpy(&vendor[0], &ebx, 4);
memcpy(&vendor[4], &edx, 4);
memcpy(&vendor[8], &ecx, 4);
vendor[12] = '\0';
return strdup(vendor);
}
char* get_cpu_brand_string(void)
{
unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0;
int k = __get_cpuid_max(0x80000000, NULL);
if (k >= (int) 0x80000005)
{
return strdup("Unknown");
}
char brand[49];
unsigned int* brand_ptr = (unsigned int*) brand;
for (unsigned int i = 0; i < 3; ++i)
{
__get_cpuid(0x80000002 + i, &eax, &ebx, &ecx, &edx);
brand_ptr[i * 4 + 0] = eax;
brand_ptr[i * 4 + 1] = ebx;
brand_ptr[i * 4 + 2] = ecx;
brand_ptr[i * 4 + 3] = edx;
}
brand[48] = '\0';
return strdup(brand);
}

View File

@ -1,19 +1,30 @@
#include <string.h>
#include <tty.h>
#include <stdio.h>
#include <port_io.h>
#include <stdlib.h>
#include <drivers/ps2_keyboard.h>
#include <kernel/intro.h>
void delay_us(uint32_t microseconds, uint32_t cpu_mhz)
{
uint32_t count = cpu_mhz * microseconds;
while (count--)
{
asm volatile ("nop" ::: "memory");
}
}
void ack_char(char c);
void start_kernel_shell(void);
char char_entered = 0x00;
void intro_begin(void)
{
extern char* kernel_version;
char* fin = (char*) malloc(strlen(kernel_version) + 6);
memset(fin, 0, (strlen(kernel_version) + 5));
strcpy(fin, kernel_version);
#ifdef _DEBUG
strcat(fin, " DEBUG");
#endif
begin_anim(fin);
}
int16_t begin_anim(const char* version)
{
@ -31,11 +42,18 @@ int16_t begin_anim(const char* version)
int16_t b = 0;
int32_t sh_pos = VGA_WIDTH / 2;
int32_t sv_pos = VGA_HEIGHT / 2;
setup_hook((ps2_hook_t) ack_char);
while (true)
{
terminal_clear();
if (char_entered != 0)
{
break;
}
for (int32_t i = 0; n[i]; ++i)
{
terminal_putentryat(n[i], terminal_getcolor(), sh_pos, sv_pos);
@ -64,11 +82,35 @@ int16_t begin_anim(const char* version)
b = 0;
delay_us(50000, 5000);
sleep(1000);
}
if (char_entered != 0)
{
start_kernel_shell();
}
else
{
terminal_clear();
}
terminal_clear();
return 0;
}
void ack_char(char c)
{
char_entered = c;
return;
}
void start_kernel_shell(void)
{
/* terminal_clear() already called by begin_anim() */
extern int kshell_start(int argc, char** argv);
kshell_start(0, NULL);
return;
}

25
kernel/kdebug.c Normal file
View File

@ -0,0 +1,25 @@
#include <kdebug.h>
static bool __debug = false;
void set_debug(void)
{
__debug = true;
}
void clear_debug(void)
{
__debug = false;
}
void toggle_debug(void)
{
__debug = !__debug;
}
bool get_debug(void)
{
return __debug;
}

View File

@ -11,8 +11,13 @@
#include <types.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <kernel/boot.h>
#include <kernel/kshell.h>
#include <kdebug.h>
#include <gdt.h>
#include <drivers/idt.h>
@ -20,7 +25,6 @@
#include <multiboot.h>
#include <stdio.h>
#include <drivers/pci.h>
#include <drivers/ps2_keyboard.h>
#include <drivers/pit.h>
@ -38,6 +42,8 @@
#include <builtin_games/miner.h>
#include <fs/ssfs.h>
#define DEBUG
@ -53,18 +59,24 @@ char* espresso_str = ""
"# # # # # # # # # # # # #\n"
"####### ##### # # # ####### ##### ##### #######\n";
char* kernel_version = "0.0.2a";
void kernel_main(multiboot_info_t* mbd, uint32_t magic)
{
/* --- BEGIN INITIALIZATION SECTION --- */
const char* espresso_kernel_version = "0.0.1e";
/* We need to initialize the terminal so that any error/debugging messages show. */
terminal_initialize();
printf("Loading Espresso %s...\n", espresso_kernel_version);
printf("Loading Espresso %s... ", kernel_version);
#ifdef _DEBUG
printf("[ DEBUG BUILD ]");
#endif
printf("\n");
terminal_setcolor(VGA_COLOR_RED);
@ -85,24 +97,20 @@ void kernel_main(multiboot_info_t* mbd, uint32_t magic)
gdt_install(false);
pic_remap();
idt_init();
_sti_asm();
irq_init(); /* MUST be done after pic_remap() and idt_init() */
terminal_setcolor(VGA_COLOR_GREEN);
printd("Initializing physical memory manager...\n");
pmm_init(mbd);
printd("Physical memory manager initialized\n");
printd("Initializing paging...\n");
paging_init();
printd("Paging initialized\n");
printd("Initializing heap allocator...\n");
heap_init();
printd("Heap allocator initialized\n");
heap_init(0xC2000000, 0x80000);
printd("Testing SSE...\n");
int32_t sse_test_result = test_sse();
@ -115,31 +123,13 @@ void kernel_main(multiboot_info_t* mbd, uint32_t magic)
printd("SSE test passed\n");
}
printd("Initializing the PIT...\n");
pit_init();
printd("PIT initialized\n");
printd("Initializing the PS/2 keyboard...\n");
keyboard_init();
printd("PS/2 Keyboard initialized\n");
/*
printd("Initalizing AHCI...\n");
ahci_init();
printd("AHCI initialized\n");
*/
printd("Initializing IDE system...\n");
ide_initialize();
printd("IDE initialized\n");
/*printd("Initializing DuckFS...\n");
duckfs_init();
printd("DuckFS initialized\n");*/
printd("Initializing PCI...\n");
pci_enumerate();
printd("PCI initialized\n");
pci_init();
/* --- END INITIALIZATION SECTION --- */
@ -148,22 +138,19 @@ void kernel_main(multiboot_info_t* mbd, uint32_t magic)
/*pit_sleep(4000);
begin_anim(espresso_kernel_version);*/
begin_anim(kernel_version);*/
printf("Guten tag and welcome to Espresso %s\n", espresso_kernel_version);
printf("%s\n", espresso_str);
char buffer[512] = { 0 };
printf("Guten tag and welcome to Espresso %s\n", kernel_version);
int32_t i = sfs_read_file("test.txt", buffer, -1);
sleep(1000);
printf("%i\n", i);
intro_begin();
/*extern void terminal_clear(void);
if (i == 0)
{
printf("%s\n", buffer);
}
terminal_clear();
kshell_start(1, NULL);*/
while (true)
{

54
kernel/ksh_debug.c Normal file
View File

@ -0,0 +1,54 @@
#include <stdio.h>
#include <types.h>
#include <kernel/ksh_debug.h>
void print_all_regs(void)
{
uint32_t eax, ebx, ecx, edx, esi, edi, esp, ebp, eip;
uint16_t cs, ds, es, ss;
asm volatile ("mov %%eax, %0" : "=r"(eax));
asm volatile ("mov %%ebx, %0" : "=r"(ebx));
asm volatile ("mov %%ecx, %0" : "=r"(ecx));
asm volatile ("mov %%edx, %0" : "=r"(edx));
asm volatile ("mov %%esi, %0" : "=r"(esi));
asm volatile ("mov %%edi, %0" : "=r"(edi));
asm volatile ("mov %%esp, %0" : "=r"(esp));
asm volatile ("mov %%ebp, %0" : "=r"(ebp));
asm volatile (
"call 1f\n"
"1: pop %0\n"
: "=r"(eip)
);
asm volatile ("mov %%cs, %0" : "=r"(cs));
asm volatile ("mov %%ds, %0" : "=r"(ds));
asm volatile ("mov %%es, %0" : "=r"(es));
asm volatile ("mov %%ss, %0" : "=r"(ss));
printf("EAX -> 0x%x EBX -> 0x%x ECX -> 0x%x EDX -> 0x%x\n", eax, ebx, ecx, edx);
printf("ESI -> 0x%x EDI -> 0x%x ESP -> 0x%x EBP -> 0x%x\n", esi, edi, esp, ebp);
printf("EIP (maybe) -> 0x%x\n", eip);
printf("CS -> 0x%04x DS -> 0x%04x ES -> 0x%04x SS -> 0x%04x\n", cs, ds, es, ss);
}
void print_gprs(void)
{
uint32_t eax, ebx, ecx, edx, esi, edi, esp, ebp;
asm volatile ("mov %%eax, %0" : "=r"(eax));
asm volatile ("mov %%ebx, %0" : "=r"(ebx));
asm volatile ("mov %%ecx, %0" : "=r"(ecx));
asm volatile ("mov %%edx, %0" : "=r"(edx));
asm volatile ("mov %%esi, %0" : "=r"(esi));
asm volatile ("mov %%edi, %0" : "=r"(edi));
asm volatile ("mov %%esp, %0" : "=r"(esp));
asm volatile ("mov %%ebp, %0" : "=r"(ebp));
printf("EAX -> 0x%x EBX -> 0x%x ECX -> 0x%x EDX -> 0x%x\n", eax, ebx, ecx, edx);
printf("ESI -> 0x%x EDI -> 0x%x ESP -> 0x%x EBP -> 0x%x\n", esi, edi, esp, ebp);
}

287
kernel/kshell.c Normal file
View File

@ -0,0 +1,287 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <drivers/ps2_keyboard.h>
#include <tty.h>
#include <kernel/ksh_debug.h>
#include <kernel/kshell.h>
const char* shell_version = "0.0.2";
char* prompt = NULL;
int command = -1;
bool _debug = false;
int execute(void);
static void print_intro(void)
{
printf("Espresso kshell, ver %s on Espresso %s", shell_version, KERNEL_VERSION);
#ifdef _DEBUG
printf(" DEBUG BUILD");
#endif
printf("\nSSE level: ");
command = 0;
execute();
extern char* get_cpu_vendor_string(void);
extern char* get_cpu_brand_string(void);
char* temp_ = get_cpu_vendor_string();
char* _temp = get_cpu_brand_string();
printf("CPU: %s\n", _temp == NULL ? "No info" : _temp);
printf("CPU vendor: %s\n", temp_ == NULL ? "No info" : temp_);
if (temp_)
{
free(temp_);
}
if (_temp)
{
free(_temp);
}
printf("\nCopyright 2025 David J Goeke\n");
}
static void parse_opts(int argc, char** argv)
{
for (int i = 0; i < argc; i++)
{
if (strcmp(argv[i], "--color") == 0)
{
}
}
}
int kshell_start(int argc, char** argv)
{
(void)argc;
(void)argv;
prompt = strdup(">");
char* i = NULL;
terminal_setcolor(VGA_COLOR_LIGHT_BLUE);
print_intro();
command = -1;
do
{
printf("%s ", prompt);
i = gets();
command = -1;
if (strcmp(i, "") == 0)
{
continue;
}
else if (strcmp(i, "exit") == 0 || strcmp(i, "quit") == 0)
{
break;
}
else if (strcmp(i, "sseinfo") == 0)
{
command = 0;
}
else if (strcmp(i, "kinfo") == 0)
{
command = 1;
}
else if (strcmp(i, "enable_debug") == 0)
{
_debug = true;
}
else if (strcmp(i, "disable_debug") == 0)
{
_debug = false;
}
else if (strcmp(i, "toggle_debug") == 0)
{
_debug = !_debug;
}
else if (strcmp(i, "get_debug") == 0)
{
printf("Debugging: %s\n", _debug == true ? "On" : "Off");
}
else if (strcmp(i, "dumpregs") == 0)
{
command = 2;
}
else if (strcmp(i, "dumpgprs") == 0)
{
command = 3;
}
else if (strcmp(i, "kernelmem") == 0)
{
command = 4;
}
else if (strcmp(i, "sectionmem") == 0)
{
command = 5;
}
else if (strcmp(i, "testascii") == 0)
{
command = 6;
}
else if (strcmp(i, "asciitype") == 0)
{
command = 7;
}
else
{
printf("Unknown command %s len %i\n", i, strlen(i));
}
if (_debug)
{
printf(" ASCII -> ");
size_t len = strlen(i) + 1;
for (size_t n = 0; n < len; n++)
{
printf("%02X ", (int) i[n]);
}
printf("\n");
}
execute();
} while (1);
free(i);
printf("Goodbye\n");
return 0;
}
int execute(void)
{
switch (command)
{
case 0: {
extern int sse_initialized;
switch (sse_initialized)
{
case 0:
printf("No SSE support");
break;
case 1:
printf("SSE1");
break;
case 2:
printf("SSE2");
break;
case 3:
printf("SSE3");
break;
case 4:
printf("SSSE3");
break;
case 5:
printf("SSE4.1");
break;
case 6:
printf("SSE4.2");
break;
default:
printf("WARNING: sse_initialized is in a invalid state!");
break;
}
printf("\n");
break;
}
case 1: {
printf("Espresso %s\n", KERNEL_VERSION);
break;
}
case 2: {
print_all_regs();
break;
}
case 3: {
print_gprs();
break;
}
case 4: {
extern uint8_t __kernel_start;
extern uint8_t __kernel_end;
size_t kernel_size = (size_t)&__kernel_end - (size_t)&__kernel_start;
printf("Kernel start: 0x%x\n", (&__kernel_start));
printf("Kernel end: 0x%x\n", (&__kernel_end));
printf("Kernel size (bytes): %llu\n", (uint64_t) kernel_size);
printf("Kernel size (kbytes): %llu\n", (((uint64_t) kernel_size) / 1000));
printf("Kernel size (mbytes): %f\n", (((uint64_t) kernel_size) / 1000.0) / 1000.0);
break;
}
case 5: {
extern uint8_t __kernel_text_start;
extern uint8_t __kernel_text_end;
extern uint8_t __kernel_rodata_start;
extern uint8_t __kernel_rodata_end;
extern uint8_t __kernel_data_start;
extern uint8_t __kernel_data_end;
extern uint8_t __bss_start;
extern uint8_t __bss_end;
printf(".text: %i\n.data: %i\n.rodata: %i\n.bss: %i\n", ((&__kernel_text_end) - (&__kernel_text_start)), ((&__kernel_data_end) - (&__kernel_data_start)),
((&__kernel_rodata_end) - (&__kernel_rodata_start)), ((&__bss_end) - (&__bss_start)));
break;
}
case 6: {
/*extern void terminal_clear(void);*/
terminal_clear();
printf("Printing ASCII chars 0x00 through 0xFE, hit enter to exit\n");
sleep(2500);
terminal_clear();
for (int i = 0x00; i < 0xFF; i++)
{
printf("%c", (char) i);
}
printf("\nCool ASCII art\n%c%c\n%c%c\n", 0xDA, 0xBF, 0xC0, 0xD9);
gets();
break;
}
case 7: {
break;
}
}
return 0;
}

16
kernel/vars.c Normal file
View File

@ -0,0 +1,16 @@
#include <types.h>
#include <string.h>
#include <stdlib.h>
#include <kernel/vars.h>
static uint8_t* vars_start = NULL;
static int num_bytes_used = 0;
void init_vars(void)
{
vars_start = (uint8_t*) malloc(8 * 1024); /* 1 KiB */
memclr(vars_start, (size_t) 1024);
}

6
kincl.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef _KERNEL_INCLUDE_H
#define _KERNEL_INCLUDE_H
#define KERNEL_VERSION "0.0.2a"
#endif

View File

@ -1,124 +0,0 @@
#include <ksymtab.h>
#define KFUNC_TABLE_ADDRESS 0xC0101000
#define KSYMTAB_MAX 0x8086FF
#define IS_MODULE_FUNC(id) ((id) & 0x80000000)
#define GET_MODULE_ID(id) (((id) >> 20) & 0x7FF)
#define GET_FUNC_ID(id) ((id) & 0xFFFFF)
#define EXISTS(id) ((id) > 0x0)
#define MAKE_KERNEL_FUNC(id) ((id) & 0x7FFFFFFF)
#define MAKE_MODULE_FUNC(mid, fid) (0x80000000 | ((mid) << 20) | ((fid) & 0xFFFFF))
kfunc_t* kfunc_table = (kfunc_t*)KFUNC_TABLE_ADDRESS;
static uint32_t ktab_size = 0;
uint64_t kfunc_call(kfunc_t* func, uint32_t a, uint32_t b, uint32_t c, uint32_t d)
{
uint32_t eax_ret, edx_ret;
asm volatile (
"push %[d]\n\t"
"push %[c]\n\t"
"push %[b]\n\t"
"push %[a]\n\t"
"call *%[fn]\n\t"
"add $16, %%esp\n\t" /* clean up stack (4 args * 4 bytes) */
: "=a"(eax_ret), "=d"(edx_ret)
: [a]"r"(a), [b]"r"(b), [c]"r"(c), [d]"r"(d), [fn]"r"(func->addr)
: "memory"
);
return ((uint64_t)edx_ret << 32) | eax_ret;
}
uint64_t call_kfunc_by_id(uint32_t id, uint32_t a, uint32_t b, uint32_t c, uint32_t d)
{
for (int i = 0; i < (int)ktab_size; i++)
{
if (kfunc_table[i].id == id)
{
if (kfunc_table[i].addr == 0x0)
{
return -1;
}
return kfunc_call(&kfunc_table[i], a, b, c, d);
}
}
return -1;
}
uint32_t add_kfunc(void* addr, bool module, uint16_t module_id, uint32_t function_id)
{
if (ktab_size >= KSYMTAB_MAX)
{
return 0xFFFFFFFF;
}
kfunc_t kf = make_kfunc(addr, module, module_id, function_id);
kfunc_table[ktab_size] = kf;
ktab_size++;
return kf.id;
}
/*
Constructs and returns a kfunc_t:
- 'addr' is the address of the function (can be NULL/0)
- 'module' indicates if it's a module/driver function
- 'module_id' is used only if 'module' is true (11 bits max)
- 'function_id':
- 20 bits if module is true
- 31 bits if kernel function
*/
kfunc_t make_kfunc(void* addr, bool module, uint16_t module_id, uint32_t function_id)
{
uint32_t id;
if (module)
{
id = 0x80000000 | ((module_id & 0x7FF) << 20) | (function_id & 0xFFFFF);
}
else
{
if (function_id == UINT32_MAX)
{
function_id = ktab_size;
}
id = function_id & 0x7FFFFFFF;
}
kfunc_t result = {
.id = id,
.addr = (uint32_t)(uintptr_t)addr
};
return result;
}
kfunc_t* find_kfunc(uint32_t id)
{
for (uint32_t i = 0; i < ktab_size; i++)
{
if (kfunc_table[i].id == id)
{
return &kfunc_table[i];
}
}
return NULL;
}

37
lib/math.c Normal file
View File

@ -0,0 +1,37 @@
#include <types.h>
#include <math.h>
static int ps_of_two[12] = { 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 };
bool is_low_power_of_two(int n)
{
for (int i = 0; i < 11; i++)
{
if (n == ps_of_two[i])
{
return true;
}
}
return false;
}
uint64_t int_pow(uint64_t base, uint32_t exp)
{
uint64_t result = 1;
while (exp)
{
if (exp & 1)
{
result *= base;
}
exp >>= 1;
base *= base;
}
return result;
}

View File

@ -1,76 +1,138 @@
#include <stdio.h>
#include <string.h>
#include <mm/heap.h>
#include <mm/pmm.h>
#include <mm/paging.h>
#include <string.h>
#include <stdio.h>
#include <mm_macros.h>
#include <mm/heap.h>
#define ALIGNMENT 8
#define ALIGN(size) (((size) + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1))
#define ALIGN4(x) (((x) + 3) & ~3)
#define MIN_BLOCK_SIZE 16
typedef struct block_header {
typedef struct block {
size_t size;
struct block_header* next;
struct block* next;
int free;
} block_header_t;
} block_t;
#define BLOCK_SIZE sizeof(block_header_t)
#define BLOCK_SIZE sizeof(block_t)
static uint8_t* heap_base = (uint8_t*)HEAP_START;
static uint8_t* heap_end = (uint8_t*)(HEAP_START + HEAP_SIZE);
static uint8_t* heap_base;
static uint8_t* heap_end;
static size_t heap_size;
static block_t* free_list;
static block_header_t* free_list = NULL;
void heap_init(void)
void heap_init(uint32_t start, uint32_t size)
{
free_list = (block_header_t*)heap_base;
free_list->size = HEAP_SIZE - BLOCK_SIZE;
free_list->next = NULL;
#ifdef _DEBUG
printf("[ HEAP ] Initializing heap allocator...\n");
#endif
heap_base = (uint8_t*) ALIGN4((uintptr_t) start);
heap_end = heap_base;
heap_size = size;
free_list = NULL;
for (uint32_t i = 0; i < size; i += 0x1000)
{
map_page(pmm_alloc_page(), (void*)(start + i));
}
/* Set up initial free block */
free_list = (block_t*)heap_base;
free_list->size = heap_size - BLOCK_SIZE;
free_list->free = 1;
free_list->next = NULL;
heap_end = heap_base + size;
#ifdef _DEBUG
printf("[ HEAP ] Heap allocator initialized\n");
#endif
}
void* malloc(size_t size)
static block_t* find_free_block(size_t size)
{
size = ALIGN(size);
block_header_t* curr = free_list;
block_t* curr = free_list;
while (curr)
{
if (curr->free && curr->size >= size)
{
/* Split if there's space for another block */
if (curr->size >= size + BLOCK_SIZE + ALIGNMENT)
{
block_header_t* new_block = (block_header_t*)((uint8_t*)curr + BLOCK_SIZE + size);
new_block->size = curr->size - size - BLOCK_SIZE;
new_block->next = curr->next;
new_block->free = 1;
curr->next = new_block;
curr->size = size;
}
curr->free = 0;
return (void*)((uint8_t*)curr + BLOCK_SIZE);
return curr;
}
curr = curr->next;
}
printd("Malloc failed due to lack of free memory\n");
printf("find_free_block(): No free block found!\n");
return NULL;
}
static void split_block(block_t* blk, size_t size)
{
if (blk->size >= size + BLOCK_SIZE + MIN_BLOCK_SIZE)
{
block_t* new_blk = (block_t*)((uint8_t*)blk + BLOCK_SIZE + size);
new_blk->size = blk->size - size - BLOCK_SIZE;
new_blk->free = 1;
new_blk->next = blk->next;
blk->next = new_blk;
blk->size = size;
}
}
void* malloc(size_t size)
{
size = ALIGN4(size);
block_t* blk = find_free_block(size);
if (!blk)
{
printf("malloc(): No free block found!\n");
return NULL;
}
split_block(blk, size);
blk->free = 0;
return (void*)((uint8_t*)blk + BLOCK_SIZE);
}
void free(void* ptr)
{
if (!ptr)
{
return;
}
block_t* blk = (block_t*)((uint8_t*)ptr - BLOCK_SIZE);
blk->free = 1;
/* coalesce */
block_t* curr = free_list;
while (curr && curr->next)
{
if (curr->free && curr->next->free)
{
curr->size += BLOCK_SIZE + curr->next->size;
curr->next = curr->next->next;
}
else
{
curr = curr->next;
}
}
}
void* calloc(size_t nmemb, size_t size)
{
size_t total = nmemb * size;
void* ptr = malloc(total);
if (ptr)
{
memset(ptr, 0, total);
MEMSET(ptr, 0, total);
}
return ptr;
}
@ -81,57 +143,25 @@ void* realloc(void* ptr, size_t size)
return malloc(size);
}
if (size == 0)
if (!size)
{
free(ptr);
return NULL;
}
block_header_t* block = (block_header_t*)((uint8_t*)ptr - BLOCK_SIZE);
if (block->size >= size)
block_t* blk = (block_t*)((uint8_t*)ptr - BLOCK_SIZE);
if (blk->size >= size)
{
return ptr;
}
void* new_ptr = malloc(size);
if (new_ptr) {
memcpy(new_ptr, ptr, block->size);
if (new_ptr)
{
memcpy(new_ptr, ptr, blk->size);
free(ptr);
}
return new_ptr;
}
void free(void* ptr)
{
if (!ptr)
{
return;
}
block_header_t* block = (block_header_t*)((uint8_t*)ptr - BLOCK_SIZE);
block->free = 1;
/* Forward coalescing */
if (block->next && block->next->free)
{
block->size += BLOCK_SIZE + block->next->size;
block->next = block->next->next;
}
/* Backward coalescing */
block_header_t* prev = NULL;
block_header_t* curr = free_list;
while (curr && curr != block)
{
prev = curr;
curr = curr->next;
}
if (prev && prev->free)
{
prev->size += BLOCK_SIZE + block->size;
prev->next = block->next;
}
}

View File

@ -1,82 +1,60 @@
#include <mm/pmm.h>
#include <string.h>
#include <mm_macros.h>
#include <stdio.h>
#include <mm/paging.h>
#include <mm/pmm.h>
#include <mm/heap.h>
#define PAGE_DIRECTORY_ENTRIES 1024
#define PAGE_TABLE_ENTRIES 1024
#define PAGE_SIZE 4096
#define PAGE_PRESENT 0x1
#define PAGE_WRITE 0x2
#define PAGE_SIZE 4096
typedef uint32_t page_directory_entry_t;
typedef uint32_t page_table_entry_t;
static page_directory_entry_t* page_directory = NULL; /* Will be allocated */
static page_table_entry_t* page_tables[PAGE_DIRECTORY_ENTRIES];
extern void _enable_paging_asm(void);
void paging_init(void)
{
/* Allocate and clear the page directory */
page_directory = (page_directory_entry_t*)alloc_page();
memset(page_directory, 0, PAGE_SIZE);
/* Allocate and set up the first identity-mapped page table (0-4MB) */
page_tables[0] = (page_table_entry_t*)alloc_page();
memset(page_tables[0], 0, PAGE_SIZE);
for (uint32_t i = 0; i < PAGE_TABLE_ENTRIES; i++)
{
page_tables[0][i] = (i * PAGE_SIZE) | 3; /* Present | RW */
}
page_directory[0] = ((uint32_t)page_tables[0]) | 3;
/* Allocate and clear the heap page table */
uint32_t heap_pd_index = HEAP_START >> 22; /* 0xC0000000 >> 22 = 768 */
page_tables[heap_pd_index] = (page_table_entry_t*)alloc_page();
memset(page_tables[heap_pd_index], 0, PAGE_SIZE);
/* Map 4MB heap pages */
for (uint32_t i = 0; i < PAGE_TABLE_ENTRIES; i++) /* 1024 pages = 4MB */
{
void* phys = alloc_page();
if (phys == 0)
{
printf("Out of physical memory during heap mapping!\n");
while (1);
}
page_tables[heap_pd_index][i] = ((uint32_t)phys & 0xFFFFF000) | 3; /* Present | RW */
}
page_directory[heap_pd_index] = ((uint32_t)page_tables[heap_pd_index]) | 3;
/* Load page directory */
asm volatile ("mov %0, %%cr3" : : "r"(page_directory));
/* Enable paging */
_enable_paging_asm();
}
static uint32_t* page_directory;
void map_page(void* phys_addr, void* virt_addr)
{
uint32_t pd_index = ((uint32_t)virt_addr >> 22) & 0x3FF;
uint32_t pt_index = ((uint32_t)virt_addr >> 12) & 0x3FF;
uint32_t pd_idx = ((uint32_t)virt_addr >> 22) & 0x3FF;
uint32_t pt_idx = ((uint32_t)virt_addr >> 12) & 0x3FF;
/* Allocate page table if necessary */
if (!(page_directory[pd_index] & 1))
uint32_t* page_table;
if (!(page_directory[pd_idx] & PAGE_PRESENT))
{
void* pt_phys = alloc_page();
page_tables[pd_index] = (page_table_entry_t*)((uint32_t)pt_phys + 0xC0000000); /* Map it higher */
memset(page_tables[pd_index], 0, PAGE_SIZE);
page_directory[pd_index] = ((uint32_t)pt_phys) | 0x3; /* Present, R/W */
page_table = (uint32_t*) pmm_alloc_page();
MEMSET(page_table, 0, PAGE_SIZE);
page_directory[pd_idx] = ((uint32_t)page_table) | PAGE_PRESENT | PAGE_WRITE;
}
else
{
page_table = (uint32_t*)(page_directory[pd_idx] & ~0xFFF);
}
page_table_entry_t* page_table = (page_table_entry_t*)((page_directory[pd_index] & 0xFFFFF000) + 0xC0000000);
page_table[pt_index] = ((uint32_t)phys_addr & 0xFFFFF000) | 0x3; /* Present, R/W */
asm volatile ("invlpg (%0)" :: "r" (virt_addr) : "memory");
page_table[pt_idx] = ((uint32_t)phys_addr) | PAGE_PRESENT | PAGE_WRITE;
}
void paging_init(void)
{
#ifdef _DEBUG
printf("[ PAGING ] Initializing paging...\n");
#endif
page_directory = (uint32_t*)pmm_alloc_page();
MEMSET(page_directory, 0, PAGE_SIZE);
for (uint32_t addr = 0; addr < 0x800000; addr += PAGE_SIZE)
{
map_page((void*) addr, (void*) addr); /* identity map first 8MB */
}
asm volatile("mov %0, %%cr3" :: "r"(page_directory));
uint32_t cr0;
asm volatile("mov %%cr0, %0" : "=r"(cr0));
cr0 |= 0x80000000;
asm volatile("mov %0, %%cr0" :: "r"(cr0));
#ifdef _DEBUG
printf("[ PAGING ] Paging initialized\n");
#endif
}

View File

@ -1,80 +1,76 @@
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <mm/pmm.h>
#define PAGE_SIZE 4096
#define BITMAP_SIZE (1024 * 1024) /* Supports up to 4GB RAM (1 bit per page) */
static uint8_t bitmap[BITMAP_SIZE / 8];
static uint32_t total_pages;
static uint32_t used_pages = 0;
#define MAX_PAGES (1024 * 1024) /* 4GB / 4KB */
static uint8_t bitmap[MAX_PAGES / 8] __attribute__((section(".pmm_bitmap")));
static size_t total_pages;
static inline void set_bit(uint32_t idx)
#define BITMAP_SET(i) (bitmap[(i) / 8] |= (1 << ((i) % 8)))
#define BITMAP_CLEAR(i) (bitmap[(i) / 8] &= ~(1 << ((i) % 8)))
#define BITMAP_TEST(i) (bitmap[(i) / 8] & (1 << ((i) % 8)))
void pmm_init(multiboot_info_t* mb)
{
bitmap[idx / 8] |= (1 << (idx % 8));
}
#ifdef _DEBUG
printf("[ PMM ] Initializing physical memory manager...\n");
#endif
static inline void clear_bit(uint32_t idx)
{
bitmap[idx / 8] &= ~(1 << (idx % 8));
}
static inline int test_bit(uint32_t idx)
{
return (bitmap[idx / 8] >> (idx % 8)) & 1;
}
void pmm_init(multiboot_info_t* mb_info)
{
total_pages = 0x100000; /* 4GB / 4KB = 1M pages */
for (uint32_t i = 0; i < total_pages / 8; i++)
total_pages = MAX_PAGES;
for (uint32_t i = 0; i < (total_pages / 8); i++)
{
bitmap[i] = 0xFF; /* Mark all as used */
bitmap[i] = 0xFF;
}
multiboot_memory_map_t* mmap = (multiboot_memory_map_t*) mb_info->mmap_addr;
while ((uint32_t)mmap < mb_info->mmap_addr + mb_info->mmap_length)
multiboot_memory_map_t* mmap = (void*)(uintptr_t)mb->mmap_addr;
size_t entries = mb->mmap_length / sizeof(multiboot_memory_map_t);
for (size_t i = 0; i < entries; i++)
{
if (mmap->type == 1) /* Usable */
if (mmap[i].type == 1) /* usable */
{
uint64_t base = mmap->addr;
uint64_t len = mmap->len;
for (uint64_t addr = base; addr < base + len; addr += PAGE_SIZE)
uint64_t start = mmap[i].addr;
uint64_t end = start + mmap[i].len;
for (uint64_t addr = start; addr < end; addr += 0x1000)
{
if (addr >= 0x210000) /* Skip first 2.1MB, or ≈ 2.06MiB */
if (addr >= 0x100000) /* skip below 1MB */
{
uint32_t idx = addr / PAGE_SIZE;
if (idx >= total_pages)
{
continue; /* skip entries above 4GB */
}
clear_bit(idx);
used_pages--;
size_t idx = addr / 0x1000;
BITMAP_CLEAR(idx);
}
}
}
mmap = (multiboot_memory_map_t*)((uint32_t)mmap + mmap->size + sizeof(mmap->size));
}
total_pages = MAX_PAGES;
#ifdef _DEBUG
printf("[ PMM ] Physical memory manager initialized\n");
#endif
}
void* alloc_page(void) {
for (uint32_t i = 0; i < total_pages; i++)
void* pmm_alloc_page(void)
{
for (uint32_t i = 0; i < total_pages; ++i)
{
if (!test_bit(i))
if (!BITMAP_TEST(i))
{
set_bit(i);
used_pages++;
return (void*)(i * PAGE_SIZE);
BITMAP_SET(i);
return (void*)(i * 4096);
}
}
return NULL; /* Out of memory */
printf("pmm_alloc_page(): No free page found!\n");
return NULL;
}
void free_page(void* ptr)
void pmm_free_page(void* addr)
{
uint32_t idx = (uint32_t)ptr / PAGE_SIZE;
clear_bit(idx);
size_t idx = (uintptr_t)addr / 0x1000;
BITMAP_CLEAR(idx);
}

View File

@ -2,219 +2,422 @@
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include <drivers/serio.h>
#include <printf.h>
static uint8_t color = 0xFF;
void printwc(const char* str, uint8_t color)
{
uint8_t c = terminal_getcolor();
terminal_setcolor(color);
printf(str);
terminal_setcolor(c);
}
void printd(const char* str)
{
terminal_debug_writestring(str);
serial_puts("[ DEBUG ] ");
serial_puts(str);
}
void printdc(const char* str, uint8_t color)
{
uint8_t c = terminal_getcolor();
terminal_setcolor(color);
printd(str);
terminal_setcolor(c);
}
void printf_set_color(uint8_t _color)
{
if (_color == 0xFF)
{
return;
}
color = _color;
}
void printf(const char* format, ...)
{
va_list args;
va_start(args, format);
va_list args;
va_start(args, format);
if (color != 0xFF)
{
terminal_setcolor(color);
}
for (size_t i = 0; format[i] != '\0'; ++i) {
if (format[i] == '%' && format[i + 1] != '\0') {
++i;
for (size_t i = 0; format[i] != '\0'; ++i)
{
if (format[i] == '%' && format[i + 1] != '\0')
{
++i;
// Check for width (like %016llx)
int width = 0;
if (format[i] == '0') {
++i;
while (format[i] >= '0' && format[i] <= '9') {
width = width * 10 + (format[i] - '0');
++i;
}
}
// Check for 'll' prefix
bool is_ll = false;
if (format[i] == 'l' && format[i + 1] == 'l') {
is_ll = true;
i += 2;
}
switch (format[i]) {
case 's': {
const char* str = va_arg(args, const char*);
terminal_writestring(str ? str : "(null)");
break;
}
case 'c': {
char c = (char) va_arg(args, int);
terminal_putchar(c);
break;
}
case 'd':
case 'i': {
int32_t val = va_arg(args, int32_t);
print_int(val);
break;
}
case 'u': {
uint32_t val = va_arg(args, uint32_t);
print_uint(val);
break;
}
case 'x': {
if (is_ll) {
uint64_t val = va_arg(args, uint64_t);
print_hex64(val, width ? width : 16, false);
} else {
uint32_t val = va_arg(args, uint32_t);
print_hex(val, width ? width : 8, false);
}
break;
}
case 'X': {
if (is_ll) {
uint64_t val = va_arg(args, uint64_t);
print_hex64(val, width ? width : 16, true);
} else {
uint32_t val = va_arg(args, uint32_t);
print_hex(val, width ? width : 8, true);
}
break;
}
case 'p': {
void* ptr = va_arg(args, void*);
terminal_writestring("0x");
print_hex((uint32_t)(uintptr_t)ptr, 8, true); // assumes 32-bit pointer
break;
}
case 'f':
case 'F': {
double val = va_arg(args, double);
print_double(val, 2);
break;
}
case '%': {
terminal_putchar('%');
break;
}
default: {
terminal_putchar('%');
terminal_putchar(format[i]);
break;
}
}
} else {
terminal_putchar(format[i]);
int width = 0;
if (format[i] == '0')
{
++i;
while (format[i] >= '0' && format[i] <= '9')
{
width = width * 10 + (format[i] - '0');
++i;
}
}
}
va_end(args);
bool is_ll = false;
if (format[i] == 'l' && format[i + 1] == 'l')
{
is_ll = true;
i += 2;
}
switch (format[i])
{
case 's': {
const char* str = va_arg(args, const char*);
terminal_writestring(str ? str : "(null)");
if (use_serial())
{
serial_puts(str ? str : "(null)");
}
break;
}
case 'c': {
char c = (char) va_arg(args, int);
terminal_putchar(c);
if (use_serial())
{
serial_write(c);
}
break;
}
case 'd':
case 'i': {
if (is_ll)
{
int64_t val = va_arg(args, int64_t);
print_lint(val);
}
else
{
int32_t val = va_arg(args, int32_t);
print_int(val);
}
break;
}
case 'u': {
if (is_ll)
{
uint64_t val = va_arg(args, uint64_t);
print_luint(val);
}
else
{
uint32_t val = va_arg(args, uint32_t);
print_uint(val);
}
break;
}
case 'x': {
if (is_ll)
{
uint64_t val = va_arg(args, uint64_t);
print_hex64(val, width ? width : 16, false);
}
else
{
uint32_t val = va_arg(args, uint32_t);
print_hex(val, width ? width : 8, false);
}
break;
}
case 'X': {
if (is_ll)
{
uint64_t val = va_arg(args, uint64_t);
print_hex64(val, width ? width : 16, true);
}
else
{
uint32_t val = va_arg(args, uint32_t);
print_hex(val, width ? width : 8, true);
}
break;
}
case 'p': {
void* ptr = va_arg(args, void*);
terminal_writestring("0x");
if (use_serial())
{
serial_write('0');
serial_write('x');
}
print_hex((uint32_t)(uintptr_t)ptr, 8, true);
break;
}
case 'f':
case 'F': {
double val = va_arg(args, double);
print_double(val, 2);
break;
}
case '%': {
terminal_putchar('%');
if (use_serial())
{
serial_write('%');
}
break;
}
default: {
terminal_putchar('%');
terminal_putchar(format[i]);
if (use_serial())
{
serial_write('%');
serial_write(format[i]);
}
break;
}
}
}
else
{
terminal_putchar(format[i]);
if (use_serial())
{
serial_write(format[i]);
}
}
}
va_end(args);
}
void print_int(int32_t value) {
char buffer[12]; // Enough for 32-bit signed int (-2147483648)
int i = 0;
uint32_t u;
void print_int(int32_t value)
{
char buffer[12];
int i = 0;
uint32_t u;
if (value < 0) {
terminal_putchar('-');
u = (uint32_t)(-value);
} else {
u = (uint32_t)value;
if (value < 0)
{
terminal_putchar('-');
if (use_serial())
{
serial_write('-');
}
u = (uint32_t)(-value);
}
else
{
u = (uint32_t)value;
}
// Convert to string in reverse
do {
buffer[i++] = '0' + (u % 10);
u /= 10;
} while (u > 0);
do
{
buffer[i++] = '0' + (u % 10);
u /= 10;
} while (u > 0);
// Print in correct order
while (i--) {
terminal_putchar(buffer[i]);
while (i--)
{
terminal_putchar(buffer[i]);
if (use_serial())
{
serial_write(buffer[i]);
}
}
}
void print_lint(int64_t value)
{
char buffer[21];
int i = 0;
uint64_t u;
if (value < 0)
{
terminal_putchar('-');
if (use_serial())
{
serial_write('-');
}
u = (uint64_t) (-value);
}
else
{
u = (uint64_t) value;
}
do
{
buffer[i++] = '0' + (u % 10);
u /= 10;
} while (u > 0);
while (i--)
{
terminal_putchar(buffer[i]);
if (use_serial())
{
serial_write(buffer[i]);
}
}
}
void print_hex(uint32_t value, int width, bool uppercase)
{
const char* hex_chars = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
char buffer[9]; // 8 hex digits max for 32-bit
int i = 0;
const char* hex_chars = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
char buffer[9]; // 8 hex digits max for 32-bit
int i = 0;
do {
buffer[i++] = hex_chars[value & 0xF];
value >>= 4;
} while (value || i < width); // ensure at least 'width' digits
do
{
buffer[i++] = hex_chars[value & 0xF];
value >>= 4;
} while (value || i < width); // ensure at least 'width' digits
while (i--) {
terminal_putchar(buffer[i]);
while (i--)
{
terminal_putchar(buffer[i]);
if (use_serial())
{
serial_write(buffer[i]);
}
}
}
void print_double(double value, int precision)
{
// Handle the integer part
int32_t integer_part = (int32_t)value;
double fractional_part = value - integer_part;
// Handle the integer part
int32_t integer_part = (int32_t)value;
double fractional_part = value - integer_part;
// Print the integer part
print_int(integer_part);
// Print the integer part
print_int(integer_part);
// Print the decimal point
terminal_putchar('.');
// Print the decimal point
terminal_putchar('.');
if (use_serial())
{
serial_write('.');
}
// Print the fractional part (scaled up)
fractional_part *= 1;
for (int i = 0; i < precision; i++) {
fractional_part *= 10;
// Print the fractional part (scaled up)
fractional_part *= 1;
for (int i = 0; i < precision; i++)
{
fractional_part *= 10;
}
int32_t frac_int = (int32_t)fractional_part;
print_int(frac_int);
}
void print_uint(uint32_t value)
{
char buffer[11];
int i = 0;
do
{
buffer[i++] = '0' + (value % 10);
value /= 10;
} while (value > 0);
while (i--)
{
terminal_putchar(buffer[i]);
if (use_serial())
{
serial_write(buffer[i]);
}
int32_t frac_int = (int32_t)fractional_part;
print_int(frac_int);
}
}
void print_uint(uint32_t value) {
char buffer[11]; // Enough for 32-bit unsigned int
int i = 0;
void print_luint(uint64_t value)
{
char buffer[21];
int i = 0;
do {
buffer[i++] = '0' + (value % 10);
value /= 10;
} while (value > 0);
do
{
buffer[i++] = '0' + (value % 10);
value /= 10;
} while (value > 0);
while (i--) {
terminal_putchar(buffer[i]);
while (i--)
{
terminal_putchar(buffer[i]);
if (use_serial())
{
serial_write(buffer[i]);
}
}
}
void print_hex64(uint64_t value, int width, bool uppercase) {
char buffer[17] = {0};
const char* digits = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
int i = 0;
void print_hex64(uint64_t value, int width, bool uppercase)
{
char buffer[17] = {0};
const char* digits = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
int i = 0;
do {
buffer[i++] = digits[value % 16];
value /= 16;
} while (value > 0);
do
{
buffer[i++] = digits[value % 16];
value /= 16;
} while (value > 0);
while (i < width)
buffer[i++] = '0';
while (i < width)
{
buffer[i++] = '0';
}
while (i--)
terminal_putchar(buffer[i]);
while (i--)
{
terminal_putchar(buffer[i]);
if (use_serial())
{
serial_write(buffer[i]);
}
}
}

View File

@ -1,5 +1,6 @@
#include <drivers/ps2_keyboard.h>
#include <fs/vfs.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
@ -25,6 +26,13 @@ char* getstring(void)
return "HELLO\0";
}
char* gets(void)
{
return kbd_gets();
}
/*char* fgets(char* buf, int n, FILE file)
{
if (!buf || n <= 1 || file < 1)

View File

@ -4,7 +4,6 @@
#include <string.h>
extern int32_t sse_initialized;
size_t strlen(const char* str)
@ -184,22 +183,28 @@ char* strchr(const char* s, int c)
}
void* memset(void *dst, char c, uint32_t n)
void* memset(void* dst, int c, size_t n)
{
char *temp = dst;
for (; n != 0; n--)
/*printf("memset(%p, %d, %u)\n", dst, c, n);*/
unsigned char* temp = (unsigned char*) dst;
unsigned char val = (unsigned char) c;
for (size_t i = 0; i < n; i++)
{
*temp++ = c;
temp[i] = val;
}
return dst;
}
void* memcpy(void *dst, const void *src, uint32_t n)
{
if (sse_initialized > 1)
/*if (sse_initialized > 1)
{
return sse2_memcpy(dst, src, n);
}
}*/
char *d = dst;
const char *s = src;
@ -216,7 +221,7 @@ int32_t memcmp(const void *s1, const void *s2, size_t n)
const uint8_t *p1 = (const uint8_t *)s1;
const uint8_t *p2 = (const uint8_t *)s2;
printf("p1: %i, p2: %i\n", (int32_t)*p1, (int32_t)*p2);
/*printf("p1: %i, p2: %i\n", (int32_t)*p1, (int32_t)*p2);*/
for (size_t i = 0; i < n; i++)
{
@ -239,6 +244,34 @@ void* memclr(void* m_start, size_t m_count)
return memset(m_start, '\0', (uint32_t)m_count);
}
void* memmove(void* dest, const void* src, size_t n)
{
unsigned char* d = (unsigned char*) dest;
const unsigned char* s = (const unsigned char*) src;
if (d == s || n == 0)
{
return dest;
}
if (d < s)
{
for (size_t i = 0; i < n; i++)
{
d[i] = s[i];
}
}
else
{
for (size_t i = n; i > 0; i--)
{
d[i - 1] = s[i - 1];
}
}
return dest;
}
int32_t isspace(char c)
{
return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r';
@ -281,3 +314,124 @@ char tolower(char c)
{
return lower(c);
}
int isprint(int c)
{
return (c >= 32 && c < 127);
}
void lowers(char* str)
{
size_t len = strlen(str);
for (size_t i = 0; i < len; i++)
{
str[i] = lower(str[i]);
}
}
void uppers(char* str)
{
size_t len = strlen(str);
for (size_t i = 0; i < len; i++)
{
str[i] = upper(str[i]);
}
}
int atoi(const char *str)
{
int res = 0, sign = 1;
while (*str == ' ' || *str == '\t')
{
str++;
}
if (*str == '-')
{
sign = -1; str++;
}
else if (*str == '+')
{
str++;
}
while (*str >= '0' && *str <= '9')
{
res = res * 10 + (*str - '0');
str++;
}
return res * sign;
}
long atol(const char *str)
{
long res = 0;
int sign = 1;
while (*str == ' ' || *str == '\t')
{
str++;
}
if (*str == '-')
{
sign = -1; str++;
}
else if (*str == '+')
{
str++;
}
while (*str >= '0' && *str <= '9')
{
res = res * 10 + (*str - '0');
str++;
}
return res * sign;
}
double atof(const char *str)
{
double res = 0.0, frac = 0.0;
int sign = 1, frac_div = 1;
while (*str == ' ' || *str == '\t')
{
str++;
}
if (*str == '-')
{
sign = -1; str++;
}
else if (*str == '+')
{
str++;
}
while (*str >= '0' && *str <= '9')
{
res = res * 10 + (*str - '0');
str++;
}
if (*str == '.')
{
str++;
while (*str >= '0' && *str <= '9')
{
frac = frac * 10 + (*str - '0');
frac_div *= 10;
str++;
}
}
return sign * (res + frac / frac_div);
}

View File

@ -18,33 +18,43 @@ SECTIONS
work around this issue. This does not use that feature, so 2M was
chosen as a safer option than the traditional 1M. */
. = 2M;
__kernel_start = .;
/* First put the multiboot header, as it is required to be put very early
in the image or the bootloader won't recognize the file format.
Next we'll put the .text section. */
.text BLOCK(4K) : ALIGN(4K)
{
__kernel_text_start = .;
KEEP(*(.multiboot))
*(.text)
__kernel_text_end = .;
}
/* Read-only data. */
.rodata BLOCK(4K) : ALIGN(4K)
{
__kernel_rodata_start = .;
*(.rodata)
__kernel_rodata_end = .;
}
/* Read-write data (initialized) */
.data BLOCK(4K) : ALIGN(4K)
{
__kernel_data_start = .;
*(.data)
__kernel_data_end = .;
}
/* Read-write data (uninitialized) and stack */
/* Read-write data (uninitialized) */
.bss BLOCK(4K) : ALIGN(4K)
{
__bss_start = .;
*(COMMON)
*(.bss)
__bss_end = .;
}
/* Include the list of initialization functions sorted. */
@ -64,8 +74,21 @@ SECTIONS
KEEP (*(EXCLUDE_FILE(crti.o crtn.o) .fini_array))
crtn.o(.fini_array)
}
.pmm_bitmap (NOLOAD) : ALIGN(4K)
{
KEEP(*(.pmm_bitmap))
}
.stack : ALIGN(16)
{
*(.stack)
}
/* The compiler may produce other sections, by default it will put them in
a segment with the same name. Simply add stuff here as needed. */
__kernel_end = .;
}

26994
qemu.log Normal file

File diff suppressed because it is too large Load Diff

5
serial.log Normal file
View File

@ -0,0 +1,5 @@
Loading Espresso 0.0.2a...
[ DEBUG ] Testing SSE...
[ DEBUG ] SSE test passed
Disk model: QEMU HARDDISK
Guten tag and welcome to Espresso 0.0.2a