Espresso 0.0.2a
This commit is contained in:
@ -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 --
|
||||
25
Makefile
25
Makefile
@ -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
|
||||
|
||||
@ -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
57
arch/x86/cpuid.s
Normal 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
46
arch/x86/cpuid_asm.asm
Normal 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
0
arch/x86/cpuid_asm.s
Normal 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:
|
||||
@ -35,30 +26,6 @@ _enable_paging_asm:
|
||||
|
||||
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
|
||||
jmp _hang_asm
|
||||
@ -71,4 +38,6 @@ _sti_asm:
|
||||
sti
|
||||
ret
|
||||
|
||||
.section .data
|
||||
_cli_asm:
|
||||
cli
|
||||
ret
|
||||
|
||||
6
dev_notes/memory_mapping.txt
Normal file
6
dev_notes/memory_mapping.txt
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
|
||||
so far, heap starts at 0xC2000000, and is (8 * 1024 * 1024) (0x80000) or (8MiB) bytes, and ends at 0xC2080000
|
||||
|
||||
|
||||
@ -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.
|
||||
@ -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
117
drivers/fs/ssfs.c
Normal 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;
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,6 +15,10 @@ 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)
|
||||
|
||||
@ -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 */
|
||||
@ -43,12 +45,23 @@ static bool extended = false;
|
||||
static bool is_new_char = 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* gets_string = NULL;
|
||||
volatile int32_t current_length = 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 it’s 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);
|
||||
}
|
||||
|
||||
current_string = new_str;
|
||||
capacity = new_capacity;
|
||||
}
|
||||
|
||||
if (!current_string)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
current_string = new_str;
|
||||
capacity = new_capacity;
|
||||
}
|
||||
|
||||
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;
|
||||
@ -243,19 +523,34 @@ void keyboard_handler(void)
|
||||
return;
|
||||
}
|
||||
|
||||
if (gets_called)
|
||||
{
|
||||
gets_append_char(c);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (c)
|
||||
{
|
||||
current_char = 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
88
drivers/serio.c
Normal 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;
|
||||
}
|
||||
107
drivers/tty.c
107
drivers/tty.c
@ -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,16 +62,29 @@ 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')
|
||||
{
|
||||
terminal_column = 0;
|
||||
if (++terminal_row == VGA_HEIGHT)
|
||||
{
|
||||
if (1)
|
||||
{
|
||||
terminal_scroll();
|
||||
terminal_row = VGA_HEIGHT - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
terminal_clear();
|
||||
terminal_row = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
terminal_update_cursor();
|
||||
|
||||
return;
|
||||
}
|
||||
else if (uc == '\t')
|
||||
@ -76,27 +96,34 @@ 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_column = VGA_WIDTH;
|
||||
|
||||
terminal_putentryat(' ', terminal_getcolor(), (size_t)terminal_column, (size_t)terminal_row);
|
||||
terminal_row--;
|
||||
terminal_column = VGA_WIDTH - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
terminal_putentryat(' ', terminal_getcolor(), (size_t)--terminal_column, (size_t)terminal_row);
|
||||
terminal_update_cursor(); /* For good measure */
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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++)
|
||||
{
|
||||
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++)
|
||||
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++)
|
||||
{
|
||||
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
16
include/ctype.h
Normal 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
|
||||
@ -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);
|
||||
|
||||
@ -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
14
include/drivers/serio.h
Normal 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
19
include/fs/ssfs.h
Normal 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
15
include/kdebug.h
Normal 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
|
||||
@ -2,6 +2,6 @@
|
||||
#define _KERNEL_BOOT_H
|
||||
|
||||
|
||||
uint8_t parse_boot_data(const char* data);
|
||||
void clear_bss(void);
|
||||
|
||||
#endif
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
#include <types.h>
|
||||
|
||||
void intro_begin(void);
|
||||
int16_t begin_anim(const char* version);
|
||||
|
||||
#endif
|
||||
|
||||
7
include/kernel/ksh_debug.h
Normal file
7
include/kernel/ksh_debug.h
Normal 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
0
include/kernel/kshell.c
Normal file
8
include/kernel/kshell.h
Normal file
8
include/kernel/kshell.h
Normal 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
7
include/kernel/vars.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef _KERNEL_VARIABLES_H
|
||||
#define _KERNEL_VARIABLES_H
|
||||
|
||||
|
||||
void init_vars(void);
|
||||
|
||||
#endif
|
||||
@ -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
17
include/math.h
Normal 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
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
12
include/mm_macros.h
Normal 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
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
/*memset(&__bss_start, 0, &__bss_end - &__bss_start);*/
|
||||
|
||||
for (int i = 0; i < ((&__bss_end) - (&__bss_start)); i++)
|
||||
{
|
||||
return 0;
|
||||
(&(__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");
|
||||
}
|
||||
|
||||
return 0;
|
||||
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);
|
||||
}
|
||||
|
||||
@ -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)
|
||||
{
|
||||
@ -32,10 +43,17 @@ int16_t begin_anim(const char* version)
|
||||
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();
|
||||
}
|
||||
|
||||
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
25
kernel/kdebug.c
Normal 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;
|
||||
}
|
||||
@ -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("Guten tag and welcome to Espresso %s\n", kernel_version);
|
||||
|
||||
printf("%s\n", espresso_str);
|
||||
sleep(1000);
|
||||
|
||||
char buffer[512] = { 0 };
|
||||
intro_begin();
|
||||
|
||||
int32_t i = sfs_read_file("test.txt", buffer, -1);
|
||||
/*extern void terminal_clear(void);
|
||||
|
||||
printf("%i\n", i);
|
||||
terminal_clear();
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
printf("%s\n", buffer);
|
||||
}
|
||||
kshell_start(1, NULL);*/
|
||||
|
||||
while (true)
|
||||
{
|
||||
|
||||
54
kernel/ksh_debug.c
Normal file
54
kernel/ksh_debug.c
Normal 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
287
kernel/kshell.c
Normal 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
16
kernel/vars.c
Normal 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
6
kincl.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef _KERNEL_INCLUDE_H
|
||||
#define _KERNEL_INCLUDE_H
|
||||
|
||||
#define KERNEL_VERSION "0.0.2a"
|
||||
|
||||
#endif
|
||||
124
lib/ksymtab.c
124
lib/ksymtab.c
@ -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
37
lib/math.c
Normal 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;
|
||||
}
|
||||
186
lib/mm/heap.c
186
lib/mm/heap.c
@ -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;
|
||||
return curr;
|
||||
}
|
||||
|
||||
curr->free = 0;
|
||||
return (void*)((uint8_t*)curr + BLOCK_SIZE);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
108
lib/mm/paging.c
108
lib/mm/paging.c
@ -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_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
|
||||
}
|
||||
|
||||
|
||||
128
lib/mm/pmm.c
128
lib/mm/pmm.c
@ -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
|
||||
|
||||
total_pages = MAX_PAGES;
|
||||
|
||||
for (uint32_t i = 0; i < (total_pages / 8); i++)
|
||||
{
|
||||
bitmap[i] = 0xFF;
|
||||
}
|
||||
|
||||
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[i].type == 1) /* usable */
|
||||
{
|
||||
uint64_t start = mmap[i].addr;
|
||||
uint64_t end = start + mmap[i].len;
|
||||
for (uint64_t addr = start; addr < end; addr += 0x1000)
|
||||
{
|
||||
if (addr >= 0x100000) /* skip below 1MB */
|
||||
{
|
||||
size_t idx = addr / 0x1000;
|
||||
BITMAP_CLEAR(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
total_pages = MAX_PAGES;
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("[ PMM ] Physical memory manager initialized\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void clear_bit(uint32_t idx)
|
||||
void* pmm_alloc_page(void)
|
||||
{
|
||||
bitmap[idx / 8] &= ~(1 << (idx % 8));
|
||||
for (uint32_t i = 0; i < total_pages; ++i)
|
||||
{
|
||||
if (!BITMAP_TEST(i))
|
||||
{
|
||||
BITMAP_SET(i);
|
||||
return (void*)(i * 4096);
|
||||
}
|
||||
}
|
||||
|
||||
printf("pmm_alloc_page(): No free page found!\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int test_bit(uint32_t idx)
|
||||
|
||||
void pmm_free_page(void* addr)
|
||||
{
|
||||
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++)
|
||||
{
|
||||
bitmap[i] = 0xFF; /* Mark all as used */
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (mmap->type == 1) /* Usable */
|
||||
{
|
||||
uint64_t base = mmap->addr;
|
||||
uint64_t len = mmap->len;
|
||||
for (uint64_t addr = base; addr < base + len; addr += PAGE_SIZE)
|
||||
{
|
||||
if (addr >= 0x210000) /* Skip first 2.1MB, or ≈ 2.06MiB */
|
||||
{
|
||||
uint32_t idx = addr / PAGE_SIZE;
|
||||
|
||||
if (idx >= total_pages)
|
||||
{
|
||||
continue; /* skip entries above 4GB */
|
||||
}
|
||||
|
||||
clear_bit(idx);
|
||||
used_pages--;
|
||||
}
|
||||
}
|
||||
}
|
||||
mmap = (multiboot_memory_map_t*)((uint32_t)mmap + mmap->size + sizeof(mmap->size));
|
||||
}
|
||||
}
|
||||
|
||||
void* alloc_page(void) {
|
||||
for (uint32_t i = 0; i < total_pages; i++)
|
||||
{
|
||||
if (!test_bit(i))
|
||||
{
|
||||
set_bit(i);
|
||||
used_pages++;
|
||||
return (void*)(i * PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
return NULL; /* Out of memory */
|
||||
}
|
||||
|
||||
void free_page(void* ptr)
|
||||
{
|
||||
uint32_t idx = (uint32_t)ptr / PAGE_SIZE;
|
||||
clear_bit(idx);
|
||||
size_t idx = (uintptr_t)addr / 0x1000;
|
||||
BITMAP_CLEAR(idx);
|
||||
}
|
||||
|
||||
|
||||
265
lib/printf.c
265
lib/printf.c
@ -2,93 +2,160 @@
|
||||
#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);
|
||||
|
||||
for (size_t i = 0; format[i] != '\0'; ++i) {
|
||||
if (format[i] == '%' && format[i + 1] != '\0') {
|
||||
if (color != 0xFF)
|
||||
{
|
||||
terminal_setcolor(color);
|
||||
}
|
||||
|
||||
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') {
|
||||
if (format[i] == '0')
|
||||
{
|
||||
++i;
|
||||
while (format[i] >= '0' && format[i] <= '9') {
|
||||
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') {
|
||||
if (format[i] == 'l' && format[i + 1] == 'l')
|
||||
{
|
||||
is_ll = true;
|
||||
i += 2;
|
||||
}
|
||||
|
||||
switch (format[i]) {
|
||||
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) {
|
||||
if (is_ll)
|
||||
{
|
||||
uint64_t val = va_arg(args, uint64_t);
|
||||
print_hex64(val, width ? width : 16, false);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t val = va_arg(args, uint32_t);
|
||||
print_hex(val, width ? width : 8, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'X': {
|
||||
if (is_ll) {
|
||||
if (is_ll)
|
||||
{
|
||||
uint64_t val = va_arg(args, uint64_t);
|
||||
print_hex64(val, width ? width : 16, true);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t val = va_arg(args, uint32_t);
|
||||
print_hex(val, width ? width : 8, true);
|
||||
}
|
||||
@ -97,7 +164,15 @@ void printf(const char* format, ...)
|
||||
case 'p': {
|
||||
void* ptr = va_arg(args, void*);
|
||||
terminal_writestring("0x");
|
||||
print_hex((uint32_t)(uintptr_t)ptr, 8, true); // assumes 32-bit pointer
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write('0');
|
||||
serial_write('x');
|
||||
}
|
||||
|
||||
print_hex((uint32_t)(uintptr_t)ptr, 8, true);
|
||||
|
||||
break;
|
||||
}
|
||||
case 'f':
|
||||
@ -108,16 +183,36 @@ void printf(const char* format, ...)
|
||||
}
|
||||
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 {
|
||||
}
|
||||
else
|
||||
{
|
||||
terminal_putchar(format[i]);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write(format[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,27 +220,81 @@ void printf(const char* format, ...)
|
||||
}
|
||||
|
||||
|
||||
void print_int(int32_t value) {
|
||||
char buffer[12]; // Enough for 32-bit signed int (-2147483648)
|
||||
void print_int(int32_t value)
|
||||
{
|
||||
char buffer[12];
|
||||
int i = 0;
|
||||
uint32_t u;
|
||||
|
||||
if (value < 0) {
|
||||
if (value < 0)
|
||||
{
|
||||
terminal_putchar('-');
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write('-');
|
||||
}
|
||||
|
||||
u = (uint32_t)(-value);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
u = (uint32_t)value;
|
||||
}
|
||||
|
||||
// Convert to string in reverse
|
||||
do {
|
||||
do
|
||||
{
|
||||
buffer[i++] = '0' + (u % 10);
|
||||
u /= 10;
|
||||
} while (u > 0);
|
||||
|
||||
// Print in correct order
|
||||
while (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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,13 +304,20 @@ void print_hex(uint32_t value, int width, bool uppercase)
|
||||
char buffer[9]; // 8 hex digits max for 32-bit
|
||||
int i = 0;
|
||||
|
||||
do {
|
||||
do
|
||||
{
|
||||
buffer[i++] = hex_chars[value & 0xF];
|
||||
value >>= 4;
|
||||
} while (value || i < width); // ensure at least 'width' digits
|
||||
|
||||
while (i--) {
|
||||
while (i--)
|
||||
{
|
||||
terminal_putchar(buffer[i]);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write(buffer[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,9 +333,15 @@ void print_double(double value, int precision)
|
||||
// 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++) {
|
||||
for (int i = 0; i < precision; i++)
|
||||
{
|
||||
fractional_part *= 10;
|
||||
}
|
||||
|
||||
@ -187,34 +349,75 @@ void print_double(double value, int precision)
|
||||
print_int(frac_int);
|
||||
}
|
||||
|
||||
void print_uint(uint32_t value) {
|
||||
char buffer[11]; // Enough for 32-bit unsigned int
|
||||
void print_uint(uint32_t value)
|
||||
{
|
||||
char buffer[11];
|
||||
int i = 0;
|
||||
|
||||
do {
|
||||
do
|
||||
{
|
||||
buffer[i++] = '0' + (value % 10);
|
||||
value /= 10;
|
||||
} while (value > 0);
|
||||
|
||||
while (i--) {
|
||||
while (i--)
|
||||
{
|
||||
terminal_putchar(buffer[i]);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write(buffer[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_hex64(uint64_t value, int width, bool uppercase) {
|
||||
void print_luint(uint64_t value)
|
||||
{
|
||||
char buffer[21];
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_hex64(uint64_t value, int width, bool uppercase)
|
||||
{
|
||||
char buffer[17] = {0};
|
||||
const char* digits = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
|
||||
int i = 0;
|
||||
|
||||
do {
|
||||
do
|
||||
{
|
||||
buffer[i++] = digits[value % 16];
|
||||
value /= 16;
|
||||
} while (value > 0);
|
||||
|
||||
while (i < width)
|
||||
{
|
||||
buffer[i++] = '0';
|
||||
}
|
||||
|
||||
while (i--)
|
||||
{
|
||||
terminal_putchar(buffer[i]);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write(buffer[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
10
lib/stdio.c
10
lib/stdio.c
@ -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)
|
||||
|
||||
170
lib/string.c
170
lib/string.c
@ -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);
|
||||
}
|
||||
|
||||
|
||||
25
linker.ld
25
linker.ld
@ -19,32 +19,42 @@ SECTIONS
|
||||
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. */
|
||||
@ -65,7 +75,20 @@ SECTIONS
|
||||
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 = .;
|
||||
}
|
||||
|
||||
|
||||
5
serial.log
Normal file
5
serial.log
Normal 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
|
||||
Reference in New Issue
Block a user