Compare commits

..

7 Commits

Author SHA1 Message Date
f3b2f95af5 0.0.2d: Added BGA support, graphics! 2026-06-05 16:14:14 -05:00
5971218b56 Espresso 0.0.2c 2026-03-20 16:57:08 -05:00
021fdbbcef Espresso 0.0.2a 2026-02-12 20:33:46 -06:00
c0dc95e255 Espresso 0.0.2a 2025-10-20 21:59:48 -05:00
ff6cba1164 Espresso 0.0.2a 2025-10-20 21:57:30 -05:00
102d517097 Delete lib/syscall.c 2025-07-10 19:11:35 -05:00
2f8f6d2217 Update kernel/kernel.c 2025-07-10 19:10:25 -05:00
113 changed files with 6831 additions and 1369 deletions

20
.gitignore vendored Normal file
View File

@ -0,0 +1,20 @@
# probably don't change this? IDK let me know
# might include some of these types of files later???
*.sh
.*
*.a
*.o
*.exe
*.so
*.log
# I don't think we'll being including compressed files in the repo...
*.zip
*.tar
*.gz
*.xz
!.gitignore

View File

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

15
FEATURES.md Normal file
View File

@ -0,0 +1,15 @@
Features that the Espresso kernel currently has.
Might not be up-to-date, though should be.
General:
Syscalls via int 16 (decimal)
Input/Output:
TTY driver (which works thank goodness)
Keyboard driver (meager, but usable)
Very stupid terminal text output drivers (files need renaming, confusing when comparing tty.c to new_tty.c)
Filesystems:
FAT16 (no directory support yet)

View File

@ -1,18 +1,22 @@
# === Config ===
TARGET := boot/espresso.elf
ISO := boot/espresso.iso
FAT16_DISK := espresso.img
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 $(FAT16_DISK) 64M
MKFS_VFAT := sudo mkfs.vfat
MKFS_FLAGS := -F 32 -S 512
MKFS_FLAGS := -F 16 -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
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
CFLAGS := -std=gnu99 -ffreestanding -O2 -Wall -Wextra -msse $(WNOFLAGS) -nostdlib -nostartfiles -include include/kincl.h
LDFLAGS := -T linker.ld -ffreestanding -O2 -nostdlib -nostartfiles
QEMUFLAGS := -no-shutdown -drive file=$(FAT16_DISK),format=raw,if=ide,readonly=off,rerror=report,werror=report -cpu qemu32,sse4.1
QEMUFLGS_EXT := -vga std
MOR_QEMUFLGS := -net none -netdev user,id=n0 -device rtl8139,netdev=n0 -serial file:serial.log
QEMU_BOOT_FLG := -boot d -cdrom $(ISO)
QEMU_BOOT_RPI := -kernel $(TARGET)
SRC_DIRS := kernel drivers lib
INCLUDE_DIRS := include
ARCH_DIR := arch
@ -24,6 +28,9 @@ BOOT_DIR := $(ISO_DIR)/boot
GRUB_DIR := $(BOOT_DIR)/grub
GRUB_CFG := grub.cfg
# === Host checks ===
IS_RPI := $(shell [ -f /proc/device-tree/model ] && grep -qi "Raspberry Pi" /proc/device-tree/model && echo 1 || echo 0)
# === File collection ===
C_SRCS := $(foreach dir, $(SRC_DIRS), $(shell find $(dir) -name '*.c'))
S_SRCS := $(foreach dir, $(ARCH_DIR), $(shell find $(dir) -name '*.s'))
@ -46,6 +53,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))
@ -67,23 +78,47 @@ $(TARGET): ./arch/x86/boot/boot.o $(filter-out boot.o, $(OBJ_LINK_LIST))
iso: $(TARGET)
@grub-file --is-x86-multiboot $(TARGET) && echo "multiboot confirmed" || (echo "not multiboot" && exit 1)
mkdir -p $(GRUB_DIR)
cp $(TARGET) $(BOOT_DIR)/
cp $(GRUB_CFG) $(GRUB_DIR)/
cp $(TARGET) $(BOOT_DIR)
ifneq ($(IS_RPI),1)
cp $(GRUB_CFG) $(GRUB_DIR)
grub-mkrescue -o $(ISO) $(ISO_DIR)
endif
# === Run in QEMU ===
run: iso
$(QEMU_MKE_IMG)
echo "\n"
$(MKFS_VFAT) $(MKFS_FLAGS) espresso.img
qemu-system-i386 $(QEMUFLAGS) $(QEMUFLGS_EXT)
@if [ ! -f $(FAT16_DISK) ]; then \
$(QEMU_MKE_IMG); \
sudo mkfs.fat $(MKFS_FLAGS) espresso.img; \
fi
@echo $(IS_RPI)
ifeq ($(IS_RPI),1)
qemu-system-i386 $(QEMU_BOOT_RPI) $(QEMUFLAGS) $(QEMUFLGS_EXT) $(MOR_QEMUFLGS)
else
qemu-system-i386 $(QEMU_BOOT_FLG) $(QEMUFLAGS) $(QEMUFLGS_EXT) $(MOR_QEMUFLGS)
endif
# === Clean all build artifacts ===
clean:
rm -f $(INTERNAL_OBJS) $(TARGET) $(ISO)
rm -rf $(ISO_DIR)
clean_disk:
rm -f espresso.img
.PHONY: all clean iso run
# === Push code to repo ===
commit:
ifndef MSG
$(error MSG required)
endif
ifndef RELEASENUM
$(error RELEASENUM required)
endif
git add .
git commit -m "$(MSG)"
git push origin main
git tag -a "$(RELEASENUM)" -m "Espresso $(RELEASENUM)"
git push origin "$(RELEASENUM)"
.PHONY: all clean clean_disk iso run debug build buildc

24
TODO.md Normal file
View File

@ -0,0 +1,24 @@
Here are some of the things I think I/we should add to Espresso, in no particular order.
Important objectives:
More syscalls
Better C libs (both kernel and user)
VFS (Virtual FileSystem)
Scheduler (very important!)
General objectives:
More filesystems
PAE support
Better MM system
More CPU extentions, like AVX (if possible), more SSE, MMX, etc.
Better random number generation
Time system (probably use CMOS clock and stuff)
More in the future objectives:
VGA support
Mouse support
USB support
GPU support
Windowing compositor/desktop

View File

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

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

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

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

@ -0,0 +1,53 @@
global get_cpu_brand_string
section .text
; void get_cpu_brand_string(char* buffer)
get_cpu_brand_string:
pushad ; Save registers
mov edi, eax ; EAX = pointer to output buffer
mov eax, 0x80000000
cpuid
cmp eax, 0x80000004
jb .not_supported
mov esi, edi ; Buffer pointer → ESI
; ---- CPUID leaf 0x80000002 ----
mov eax, 0x80000002
cpuid
mov [esi], eax
mov [esi+4], ebx
mov [esi+8], ecx
mov [esi+12], edx
; ---- CPUID leaf 0x80000003 ----
mov eax, 0x80000003
cpuid
mov [esi+16], eax
mov [esi+20], ebx
mov [esi+24], ecx
mov [esi+28], edx
; ---- CPUID leaf 0x80000004 ----
mov eax, 0x80000004
cpuid
mov [esi+32], eax
mov [esi+36], ebx
mov [esi+40], ecx
mov [esi+44], edx
mov byte [esi+48], 0 ; Null terminator
jmp .done
.not_supported:
mov byte [edi], 0
.done:
popad
ret

18
arch/x86/exec/secf.s Normal file
View File

@ -0,0 +1,18 @@
/* see drivers/exec/secf.c for info on SECF */
.global _exec
.type _exec, @function
/* XXX: YOU NEED TO SAVE REGISTERS BEFORE CALLING THIS FUNCTION!!! THIS FUNCTION OVERWRITES REGISTERS!!! :XXX */
/* args (C style): void* var_area_ptr, char* arg_str, int arg_str_len, int var_area_size, void* entry_func_ptr */
_exec:
pop %edx /* var_area_ptr */
pop %esi /* arg_str */
pop %ecx /* arg_str_len */
pop %ebp /* var_area_size */
pop %eax /* entry_func_ptr */
call %eax
ret

View File

@ -1,163 +1,152 @@
[BITS 32]
[GLOBAL isr_stub_table]
[GLOBAL irq_stub_table]
extern irq_handler ; C function
[GLOBAL interrupt_entry]
extern interrupt_dispatcher
section .text
; --------------------------------------------
; ------------------- IRQs -------------------
; --------------------------------------------
; ============================================================
; COMMON INTERRUPT ENTRY
; ============================================================
%macro irq_stub 1
irq_stub_%+%1:
pusha
push ds
push es
push fs
interrupt_entry:
; Stack already contains:
; err_code
; int_no
; eip
; cs
; eflags
pusha ; eax, ecx, edx, ebx, esp, ebp, esi, edi
push gs
push fs
push es
push ds
mov ax, 0x10
mov ax, 0x10 ; load kernel data selector
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
push dword %1 ; Push IRQ number
call irq_handler
add esp, 4 ; Clean up stack
push esp ; pass pointer to registers_t
call interrupt_dispatcher
add esp, 4 ; I don't remember what this does... but don't remove it
; NVM, I remember: it cleans up the registers_t* argument we passed to interrupt_dispatcher
; Send EOI
mov al, 0x20
mov bl, %1
cmp bl, 8
jb .skip_slave_eoi
out 0xA0, al
.skip_slave_eoi:
out 0x20, al
; don't do this yet, it corrupts stuff. wait until the scheduler is finished
;mov esp, eax ; move the new stack pointer into esp
pop gs
pop fs
pop es
pop ds
popa
iret
add esp, 8 ; remove int_no + err_code
iret ; return from interrupt
; ============================================================
; IRQ STUBS
; ============================================================
%macro IRQ 1
irq_stub_%+%1:
push dword 0 ; fake error code
push dword (32 + %1) ; vector number
jmp interrupt_entry
%endmacro
; Define 16 IRQ stubs
irq_stub 0
irq_stub 1
irq_stub 2
irq_stub 3
irq_stub 4
irq_stub 5
irq_stub 6
irq_stub 7
irq_stub 8
irq_stub 9
irq_stub 10
irq_stub 11
irq_stub 12
irq_stub 13
irq_stub 14
irq_stub 15
IRQ 0
IRQ 1
IRQ 2
IRQ 3
IRQ 4
IRQ 5
IRQ 6
IRQ 7
IRQ 8
IRQ 9
IRQ 10
IRQ 11
IRQ 12
IRQ 13
IRQ 14
IRQ 15
IRQ 16
IRQ 17
IRQ 18
IRQ 19
irq_stub_table:
%assign i 0
%rep 16
%rep 20
dd irq_stub_%+i
%assign i i+1
%endrep
; --------------------------------------------
; ------------------- ISRs -------------------
; --------------------------------------------
; Common exception handler entry point
isr_common_handler:
pusha ; Push general-purpose registers
push ds
push es
push fs
push gs
; ============================================================
; EXCEPTION STUBS
; ============================================================
; Load known-good segment selectors
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
; Print exception number and error code
; You can insert direct port writes or call kernel logging function here
; For now, just hang
.halt:
cli
hlt
jmp .halt
; If you want to later restore:
pop gs
pop fs
pop es
pop ds
popa
add esp, 8 ; clean up int_no + err_code
iret
; Macro: for exceptions with error code
%macro isr_err_stub 1
%macro ISR_NOERR 1
isr_stub_%+%1:
cli
push dword %1 ; interrupt number
jmp isr_common_handler
push dword 0 ; fake error code
push dword %1 ; interrupt number
jmp interrupt_entry
%endmacro
; Macro: for exceptions without error code
%macro isr_no_err_stub 1
%macro ISR_ERR 1
isr_stub_%+%1:
cli
push dword 0 ; fake error code
push dword %1 ; interrupt number
jmp isr_common_handler
push dword %1 ; interrupt number
jmp interrupt_entry
%endmacro
; Define all 32 exception stubs
isr_no_err_stub 0
isr_no_err_stub 1
isr_no_err_stub 2
isr_no_err_stub 3
isr_no_err_stub 4
isr_no_err_stub 5
isr_no_err_stub 6
isr_no_err_stub 7
isr_err_stub 8
isr_no_err_stub 9
isr_err_stub 10
isr_err_stub 11
isr_err_stub 12
isr_err_stub 13
isr_err_stub 14
isr_no_err_stub 15
isr_no_err_stub 16
isr_err_stub 17
isr_no_err_stub 18
isr_no_err_stub 19
isr_no_err_stub 20
isr_no_err_stub 21
isr_no_err_stub 22
isr_no_err_stub 23
isr_no_err_stub 24
isr_no_err_stub 25
isr_no_err_stub 26
isr_no_err_stub 27
isr_no_err_stub 28
isr_no_err_stub 29
isr_err_stub 30
isr_no_err_stub 31
; Create jump table
; Exceptions 031
ISR_NOERR 0
ISR_NOERR 1
ISR_NOERR 2
ISR_NOERR 3
ISR_NOERR 4
ISR_NOERR 5
ISR_NOERR 6
ISR_NOERR 7
ISR_ERR 8
ISR_NOERR 9
ISR_ERR 10
ISR_ERR 11
ISR_ERR 12
ISR_ERR 13
ISR_ERR 14
ISR_NOERR 15
ISR_NOERR 16
ISR_ERR 17
ISR_NOERR 18
ISR_NOERR 19
ISR_NOERR 20
ISR_NOERR 21
ISR_NOERR 22
ISR_NOERR 23
ISR_NOERR 24
ISR_NOERR 25
ISR_NOERR 26
ISR_NOERR 27
ISR_NOERR 28
ISR_NOERR 29
ISR_ERR 30
ISR_NOERR 31
isr_stub_table:
%assign i 0
%rep 32

View File

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

386
boot/dump.txt Normal file
View File

@ -0,0 +1,386 @@
0020efdf 00000001 b capslock_pressed
0020e020 00000001 B char_entered
0020c034 00000001 d color
0020d000 00000001 b completed.2
0020efd8 00000001 B current_char
0020e02c 00000001 b __debug
0020e024 00000001 B _debug
0020eb34 00000001 b duckfs_drive
0020efde 00000001 b extended
0020efdb 00000001 b gets_called
0020efda 00000001 b gets_finished
0020efdd 00000001 b is_new_char
0020efdc 00000001 b is_new_key
0020efe8 00000001 B pit_initialized
0020efd9 00000001 B ps2keyboard_initialized
0020eb38 00000001 B ramfs_initialized
00200230 00000001 T set_bit_bo
0020efe0 00000001 b shift_pressed
0020efa8 00000001 B terminal_color
00208d9a 00000002 T _cli_asm
0020efbc 00000002 B current_key
00208dc9 00000002 t .done
00208d96 00000002 T _halt_asm
00208d98 00000002 T _sti_asm
0020a052 00000003 r CSWTCH.121
00208d93 00000003 T _hang_asm
00206a80 00000003 T load_elf32
0020efc4 00000004 B capacity
0020eae4 00000004 b cluster_heap_lba
0020c010 00000004 D command
0020c04c 00000004 d __CTOR_END__
0020c048 00000004 d __CTOR_LIST__
0020eae0 00000004 b current_directory_cluster
0020efcc 00000004 B current_length
0020efd4 00000004 B current_string
0020c004 00000004 D __dso_handle
0020c054 00000004 D __DTOR_END__
0020d004 00000004 b dtor_idx.1
0020c050 00000004 d __DTOR_LIST__
0020c00c 00000004 D espresso_str
0020eb30 00000004 b fat32_drive
0020eae8 00000004 b fat_start_lba
0020effc 00000004 b free_list
0020efc0 00000004 B gets_capacity
0020efc8 00000004 B gets_length
0020efd0 00000004 B gets_string
0020c03c 00000004 D _has_cpuid
0020c044 00000004 d _has_mmx
0020c040 00000004 d _has_sse
0020f004 00000004 b heap_base
0020f000 00000004 b heap_size
0020efb4 00000004 B hook_count
0020efb8 00000004 B hooks
0020c008 00000004 D kernel_version
0020c018 00000004 d next_fd
0020c038 00000004 D next_id
0020f00c 00000004 b next_token.0
0020efa0 00000004 b num_irqs_missed
0020f008 00000004 b page_directory
0020e028 00000004 B prompt
0020eb3c 00000004 b ramfs_num_files
0020eb40 00000004 b ramfs_root
0020e8c8 00000004 B root
0020c014 00000004 D shell_version
0020c000 00000004 D sse_initialized
0020efa4 00000004 B terminal_buffer
0020efac 00000004 B terminal_column
0020efb0 00000004 B terminal_row
0020eff8 00000004 b total_pages
0020c030 00000004 d xorshift_state
00207f20 00000005 T atol
00206ad0 00000005 T gets
002091a6 00000005 t isr_stub_10
002091ab 00000005 t isr_stub_11
002091b0 00000005 t isr_stub_12
002091b5 00000005 t isr_stub_13
002091ba 00000005 t isr_stub_14
0020919a 00000005 t isr_stub_8
00208d80 00000005 T ksleep
00205ff0 00000005 T pci_init
00206380 00000006 T get_string
0020e040 00000006 B gp
0020e090 00000006 b idtr
002000a3 00000006 T _kernel_early
00203da0 00000006 T ramfs_get_files
00203d90 00000006 T ramfs_get_root
00205e00 00000006 T use_serial
0020009c 00000007 t .done
00209162 00000007 t isr_stub_0
00209169 00000007 t isr_stub_1
00209170 00000007 t isr_stub_2
00209177 00000007 t isr_stub_3
0020917e 00000007 t isr_stub_4
00209185 00000007 t isr_stub_5
0020918c 00000007 t isr_stub_6
00209193 00000007 t isr_stub_7
0020919f 00000007 t isr_stub_9
00200f60 00000008 T clear_debug
00200f80 00000008 T get_debug
002091d3 00000008 t isr_stub_17
00209253 00000008 t isr_stub_30
0020eff0 00000008 B pit_ticks
00203db0 00000008 T ramfs_get_initialized
00200f50 00000008 T set_debug
0020c020 00000008 D sfs_next_free_data_sector
0020c028 00000008 d state
00205550 00000008 T terminal_getcolor
00200f70 00000008 T toggle_debug
00209535 0000000a T _fini
00208e08 0000000a t irq_stub_0.skip_slave_eoi
00208ffc 0000000a t irq_stub_10.skip_slave_eoi
0020902e 0000000a t irq_stub_11.skip_slave_eoi
00209060 0000000a t irq_stub_12.skip_slave_eoi
00209092 0000000a t irq_stub_13.skip_slave_eoi
002090c4 0000000a t irq_stub_14.skip_slave_eoi
002090f6 0000000a t irq_stub_15.skip_slave_eoi
00208e3a 0000000a t irq_stub_1.skip_slave_eoi
00208e6c 0000000a t irq_stub_2.skip_slave_eoi
00208e9e 0000000a t irq_stub_3.skip_slave_eoi
00208ed0 0000000a t irq_stub_4.skip_slave_eoi
00208f02 0000000a t irq_stub_5.skip_slave_eoi
00208f34 0000000a t irq_stub_6.skip_slave_eoi
00208f66 0000000a t irq_stub_7.skip_slave_eoi
00208f98 0000000a t irq_stub_8.skip_slave_eoi
00208fca 0000000a t irq_stub_9.skip_slave_eoi
002091bf 0000000a t isr_stub_15
002091c9 0000000a t isr_stub_16
002091db 0000000a t isr_stub_18
002091e5 0000000a t isr_stub_19
002091ef 0000000a t isr_stub_20
002091f9 0000000a t isr_stub_21
00209203 0000000a t isr_stub_22
0020920d 0000000a t isr_stub_23
00209217 0000000a t isr_stub_24
00209221 0000000a t isr_stub_25
0020922b 0000000a t isr_stub_26
00209235 0000000a t isr_stub_27
0020923f 0000000a t isr_stub_28
00209249 0000000a t isr_stub_29
0020925b 0000000a t isr_stub_31
00200086 0000000a t .set_result
00200000 0000000c T __kernel_text_start
00200090 0000000c t .no_sse
00200240 0000000d T ack_char
0020005f 0000000d t .check_sse3
00200079 0000000d t .check_sse41
0020006c 0000000d t .check_ssse3
00203bd0 0000000d T duckfs_set_drive
00205540 0000000d T terminal_setcolor
00208d85 0000000e T _enable_paging_asm
002092f0 0000000e T gdt_flush
00208dbb 0000000e t .no_cpuid
00209526 0000000f T _init
00209153 0000000f t isr_common_handler.halt
002014c0 0000000f T vga_entry_color
00206000 00000010 T read_ehci_register
00206030 00000011 T initialize_ehci
00208150 00000011 T printf_set_color
00203d00 00000011 T ramfs_init
0020a040 00000012 r CSWTCH.125
002092fe 00000012 t gdt_flush.flush_label
002014d0 00000012 T vga_entry
00209140 00000013 t isr_common_handler
00206010 00000013 T write_ehci_register
00207d60 00000014 T ischar
00207e00 00000014 T isprint
00207da0 00000014 T lower
00200440 00000014 T start_kernel_shell
00207de0 00000014 T tolower
00207dc0 00000014 T toupper
00207d80 00000014 T upper
00206a90 00000015 T getchar
00206ab0 00000015 T getstring
00208c60 00000015 T sleep
00208dcb 00000015 t _sse_level
00207220 00000016 T enable_sse
002075f0 00000017 T int_vector_to_double_vector
00207d40 00000017 T isalpha
0020d008 00000018 b object.0
002055a0 00000018 T terminal_clear
00205400 00000019 T set_irq_handler
00205310 0000001a T read_sector
00207160 0000001a T ulrand
00205330 0000001a T write_sector
002075d0 0000001b T double_vector_to_int_vector
00207d20 0000001b T isspace
002076c0 0000001b T strlen
00200210 0000001c T init_vars
00205de0 0000001c T serial_read
00206320 0000001d T get_char
00206a20 0000001d T pit_handler
00206a00 0000001d T pit_init
00207140 0000001d T uirand_range
00208d9c 0000001f t _init_cpuid
00205d60 0000001f T serial_write
002000a9 00000020 T _start
00206c60 00000023 T pmm_free_page
0020933a 00000025 t @@
00207840 00000025 T strcpy
002071e0 00000026 T decode_float
00208d50 00000026 T make_process
00209389 00000027 t m
0020e060 00000028 B gdt
00208de0 00000028 t irq_stub_0
00208e12 00000028 t irq_stub_1
00208fd4 00000028 t irq_stub_10
00209006 00000028 t irq_stub_11
00209038 00000028 t irq_stub_12
0020906a 00000028 t irq_stub_13
0020909c 00000028 t irq_stub_14
002090ce 00000028 t irq_stub_15
00208e44 00000028 t irq_stub_2
00208e76 00000028 t irq_stub_3
00208ea8 00000028 t irq_stub_4
00208eda 00000028 t irq_stub_5
00208f0c 00000028 t irq_stub_6
00208f3e 00000028 t irq_stub_7
00208f70 00000028 t irq_stub_8
00208fa2 00000028 t irq_stub_9
0020e8a0 00000028 b super
00205970 00000028 T terminal_writechar_r
00209310 0000002a T _get_fonts_asm
0020935f 0000002a t _set_fonts_asm
00207bd0 0000002b T memcpy
002080c0 0000002b T printd
00206060 0000002c T keyboard_init
0020eb00 00000030 b bpb
0020a240 00000030 r ps_of_two
00207080 00000034 T seed_rand
00205560 00000036 T terminal_putentryat
00201370 00000038 T idt_set_descriptor
00206a40 00000039 T pit_sleep
00205e10 0000003a T pci_config_read
00207b40 0000003c T strchr
00206340 0000003d T get_key
00205e50 0000003d T pci_config_write
00205930 0000003d T terminal_write
002059a0 0000003d T terminal_writestring
00207e20 0000003e T lowers
00205ca0 0000003e T terminal_update_cursor
00207e60 0000003e T uppers
002053c0 0000003f T irq_handler
00208c80 0000003f T is_low_power_of_two
002013b0 0000003f T pic_remap
00208c20 0000003f T printwc
002000d0 00000040 t deregister_tm_clones
002093b0 00000040 t __do_global_ctors_aux
002001d0 00000040 t frame_dummy
00209100 00000040 T irq_stub_table
0020a000 00000040 R __kernel_rodata_start
00200110 00000040 t register_tm_clones
00206780 00000041 T free_current_string
00207b80 00000042 T memset
002072e0 00000044 T sse2_add_double_arrays
00207380 00000044 T sse2_add_int32_arrays
00207330 00000044 T sse2_add_int64_arrays
00207c00 00000046 T memcmp
00207740 00000049 T strncmp
00204350 0000004b T ramfs_resolve_fd
00201040 0000004d T print_gprs
002059e0 0000004d T terminal_writeline
00205360 00000051 T irq_init
0020000c 00000053 t enable_sse_asm
002080f0 00000053 T printdc
002054e0 00000053 T terminal_initialize
00207180 00000053 T ulrand_range
00206db0 00000054 T free
002076e0 00000054 T strcmp
00206e10 00000055 T calloc
002005c0 00000057 T clear_bss
00201770 00000057 T duckfs_mount
00201e60 00000057 T duckfs_read_file
00207c50 00000057 T memclr
002003e0 00000058 T intro_begin
00205d80 0000005d T serial_puts
00202ce0 00000060 T print_83
00206f70 00000063 T paging_init
00207900 00000064 T strcat
002062b0 00000067 T call_hooks
00203d20 00000068 T ramfs_make_root
00207cb0 0000006a T memmove
00203f50 0000006b T ramfs_read_file
00207ea0 00000072 T atoi
00205ce0 00000072 T serial_init
00205660 00000072 T terminal_scroll
00202b30 00000074 t find_free_cluster
0020a270 00000074 r __FRAME_END__
00205c20 00000078 T terminal_set_cursor
00206c90 0000007a T heap_init
00206be0 0000007a T pmm_alloc_page
00206ef0 0000007b T map_page
00201500 0000007e t duckfs_alloc_block
00205a30 0000007e T terminal_debug_writestring
002070c0 0000007f T uirand
00200150 00000080 t __do_global_dtors_aux
00206e70 00000080 T realloc
0020a060 00000080 r scancode_map
00203be0 00000082 T disk_read
00203c70 00000082 T disk_write
00207870 00000089 T strncpy
00209265 0000008b T isr_stub_table
002046f0 0000008b T sfs_get_formatted_name
00206390 0000008d T kbd_gets
00207970 0000008d T strdup
00208cc0 0000008e T int_pow
00204660 0000008f T sfs_init
00207610 00000091 T memclr_sse2
00203eb0 00000091 T ramfs_write_file
00202d40 00000092 T format_83_name
00204e80 00000092 T ide_initialize
00206fe0 00000092 T miner_main
00205f50 00000092 T pci_enumerate
00206d10 00000093 T malloc
00207240 00000097 T test_sse
002011f0 0000009c T create_descriptor
00208510 0000009d T print_uint
002055c0 0000009d T terminal_clearl
00200620 0000009f T get_cpu_vendor_string
002083c0 0000009f T print_hex
002073d0 000000a0 T sse2_memcpy
00207790 000000a1 T strcasecmp
002012c0 000000a2 T exception_dispatcher
00208460 000000a5 T print_double
00200f90 000000a7 T print_all_regs
00205420 000000b2 T terminal_initializec
00205e90 000000b9 T pci_config_read_block
002013f0 000000cd T idt_init
00204da0 000000dc T ide_identify
00203fc0 000000de T ramfs_delete_file
002006c0 000000e8 T get_cpu_brand_string
002040a0 000000ec T ramfs_resolve_path
00208170 000000ee T print_int
00203dc0 000000f0 T ramfs_create_file
002086c0 000000f7 T print_hex64
00206090 000000f7 T setup_hook
00202de0 000000ff T fat32_list_root
00206ae0 000000ff T pmm_init
00206670 00000102 T append_char
002085b0 0000010d T print_luint
00203900 0000011a T fat32_create_directory
00206190 0000011f T remove_hook
00202bb0 00000128 T fat32_init
00207a00 00000133 T strtok
002093f0 00000136 T __umoddi3
00204780 00000141 T sfs_create_file
00200460 00000148 T kernel_main
002043a0 0000014b T ssfs_read_file
00201090 00000154 T gdt_install
00207470 00000156 T sse2_strncpy
00208260 00000157 T print_lint
00207f30 0000015f T atof
002044f0 0000016a T ssfs_write_file
00205ab0 0000016a T terminal_get_shifted
00200250 0000018a T begin_anim
00203a20 000001a4 T fat32_change_directory
00204f20 000001a4 T ide_read48
00204190 000001b8 T ramfs_resolve_fd_dir
00201580 000001ea t duckfs_alloc_file_data
00201c70 000001ee T duckfs_create_dir
002048d0 000001f0 T sfs_read_file
002017d0 000001fb T duckfs_find
0020eb60 00000200 B buffer
0020e8e0 00000200 b sector
002023e0 00000214 T duckfs_truncate
002067d0 00000223 T keyboard_handler
002050d0 00000234 T ide_write48
002021a0 00000237 T duckfs_write_data
0020ed60 00000240 B func_list
002056e0 00000241 T terminal_putchar
00206420 00000247 T gets_append_char
002028a0 00000288 T duckfs_delete_dir
00203660 00000298 T fat32_create_file
002019d0 000002a0 T duckfs_create_file
00202600 000002a0 T duckfs_delete_file
00202ee0 000002c2 T fat32_read_file
00201ec0 000002d1 T duckfs_append_data
00204ac0 000002db T sfs_write_file
002007b0 0000034a T execute
00200b00 00000448 T kshell_start
002087c0 0000045c T printf
002031b0 000004a5 T fat32_write_file
0020e0a0 00000800 b idt
0020d020 00001000 B vars
00230000 00010000 n stack_bottom
00210000 00020000 b bitmap
00240000 ffff0000 B __kernel_end

View File

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

View File

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

46
drivers/audio/pcspeaker.c Normal file
View File

@ -0,0 +1,46 @@
#include <stdlib.h>
#include <port_io.h>
#include <drivers/audio/pcspeaker.h>
/*
this code is taken from the OSDev wiki: https://wiki.osdev.org/PC_Speaker
with slight modifications to the local variable and parameter names,
along with removing the 'static' keyword from play_sound and nosound (which is renamed to stop_sound)
*/
void play_sound(uint32_t nfrequence)
{
uint32_t div;
uint8_t tmp;
// Set the PIT to the desired frequency
div = 1193180 / nfrequence;
outb(0x43, 0xb6);
outb(0x42, (uint8_t) (div));
outb(0x42, (uint8_t) (div >> 8));
// And play the sound using the PC speaker
tmp = inb(0x61);
if (tmp != (tmp | 3))
{
outb(0x61, tmp | 3);
}
}
// make it shut up
void stop_sound(void)
{
uint8_t tmp = inb(0x61) & 0xFC;
outb(0x61, tmp);
}
// Make a beep
void beep(void)
{
play_sound(1000);
//timer_wait(10);
sleep(10);
stop_sound();
//set_PIT_2(old_frequency);
}

View File

@ -11,7 +11,7 @@
#define ALIGN_UP(x) (((x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
elf_executable_t* load_elf32(void* elf_data)
int load_elf32(void* elf_data, elf_executable_t** ptr)
{
Elf32_Ehdr* ehdr = (Elf32_Ehdr*)elf_data;
@ -19,18 +19,19 @@ elf_executable_t* load_elf32(void* elf_data)
if (memcmp(ehdr->e_ident, (uint8_t*)("\x7F""ELF"), 4) != 0)
{
printf("Invalid ELF file\n");
return NULL;
return -1;
}
if (ehdr->e_machine != 3 || ehdr->e_type != 2)
{
printf("Unsupported ELF type or architecture\n");
return NULL;
return -1;
}
Elf32_Phdr* phdrs = (Elf32_Phdr*)((uint8_t*)elf_data + ehdr->e_phoff);
for (int i = 0; i < ehdr->e_phnum; i++) {
for (int i = 0; i < ehdr->e_phnum; i++)
{
Elf32_Phdr* phdr = &phdrs[i];
if (phdr->p_type != PT_LOAD)
{
@ -43,7 +44,7 @@ elf_executable_t* load_elf32(void* elf_data)
for (uint32_t page = 0; page < segment_pages; page++)
{
void* phys = alloc_page();
void* phys = pmm_alloc_page();
void* virt = (void*)(vaddr_start + page * PAGE_SIZE);
map_page(phys, virt);
memset(virt, 0, PAGE_SIZE);
@ -53,11 +54,23 @@ elf_executable_t* load_elf32(void* elf_data)
void* src = (uint8_t*)elf_data + phdr->p_offset;
memcpy(dest, src, phdr->p_filesz);
printf("Mapped segment %d: 0x%08x0x%08x (memsz: %u, filesz: %u)\n", i, phdr->p_vaddr, phdr->p_vaddr + phdr->p_memsz, phdr->p_memsz, phdr->p_filesz);
#ifdef _DEBUG
printf("Mapped segment %d: ", i);
printf("0x%x - 0x%x (memsz: %u, filesz: %u)\n", phdr->p_vaddr, phdr->p_vaddr + phdr->p_memsz, phdr->p_memsz, phdr->p_filesz);
#endif
}
*ptr = malloc(sizeof(elf_executable_t));
if (ptr)
{
(*ptr)->entry_point = (elf_entry_t)(uintptr_t) ehdr->e_entry;
return 0;
}
/*
elf_executable_t* result = malloc(sizeof(elf_executable_t));
result->entry_point = (void*)(uintptr_t)ehdr->e_entry;
return result;
result->entry_point = (elf_entry_t)(uintptr_t)ehdr->e_entry;*/
return -1;
}

48
drivers/exec/secf.c Normal file
View File

@ -0,0 +1,48 @@
/*
Simple Executable Code Format
SECF is a executable format for any platform (though designed with x86(-32) in mind.)
that makes use of registers, syscalls/interrupts, and other tables/structures instead of libraries.
register map:
(unused means the program can use the register without any issue, no data used/passed by the SECF will be there)
EAX: unused
EBX: unused
ECX: arg string length
EDX: variable area size (bytes)
ESI: pointer to arg string
EDI: unused
ESP: unused, normal function
EBP: pointer to variable area
The variable area is a area of a specific size (size in EDX) that can be used for storing variables/temporary data.
Any additional memory space needed can be aquired via malloc.
The minimum size of the variable area is 16 bytes and a maximum size of 64KiB.
Use syscall/int (number TBT) to call functions
*/
#include <types.h>
#include <stdlib.h>
void* init_var_area(size_t size)
{
if (size == (size_t) 0)
{
return NULL; /* size 0 is invalid. */
}
else if (size >= 65536)
{
return NULL; /* size above 65,536 is invalid. */
}
else if (size < 16)
{
size = 16;
}
return malloc(size); /* No need to check for null because we'd return null in that case */
}

376
drivers/fs/fat16.c Normal file
View File

@ -0,0 +1,376 @@
#include <string.h>
#include <drivers/ide.h>
#include <stdio.h>
#include <fs/fat16.h>
/*
READ BELOW!!!
Before any of you (or me,) use this code, please note that the functions below REQUIRE 8.3 formatted names.
in fat16.h there is a helper function for convertion between normal filenames and 8.3 ones. ('filename_to_83', see static implementation in fat16.h)
*/
static fat16_fs_t fs;
static uint8_t boot_sector[SECTOR_SIZE];
int fat16_mount(uint8_t drive)
{
if (read_sector(0, boot_sector) != 0)
{
return -1;
}
(void) drive;
fs.bytes_per_sector = boot_sector[11] | (boot_sector[12] << 8);
fs.sectors_per_cluster = boot_sector[13];
fs.reserved_sector_count = boot_sector[14] | (boot_sector[15] << 8);
fs.num_fats = boot_sector[16];
fs.root_entry_count = boot_sector[17] | (boot_sector[18] << 8);
fs.total_sectors_16 = boot_sector[19] | (boot_sector[20] << 8);
fs.sectors_per_fat = boot_sector[22] | (boot_sector[23] << 8);
fs.total_sectors = fs.total_sectors_16 != 0 ? fs.total_sectors_16 : boot_sector[32] | (boot_sector[33]<<8) | (boot_sector[34]<<16) | (boot_sector[35]<<24);
fs.fat_start_lba = fs.reserved_sector_count;
fs.root_dir_lba = fs.fat_start_lba + (fs.num_fats * fs.sectors_per_fat);
fs.data_start_lba = fs.root_dir_lba + ((fs.root_entry_count * 32 + (fs.bytes_per_sector - 1)) / fs.bytes_per_sector);
return 0;
}
static uint32_t cluster_to_lba(uint16_t cluster)
{
return fs.data_start_lba + (cluster - 2) * fs.sectors_per_cluster;
}
/* ----------------------- FAT helpers ------------------------- */
static int read_fat_entry(uint16_t cluster, uint16_t* out_value)
{
uint32_t offset = (uint32_t)cluster * 2;
uint32_t sector_index = offset / fs.bytes_per_sector;
uint32_t idx = offset % fs.bytes_per_sector;
uint8_t sector[SECTOR_SIZE];
if (read_sector(fs.fat_start_lba + sector_index, sector) != 0)
{
return -1;
}
if (idx == (uint32_t)(fs.bytes_per_sector - 1))
{
/* entry spans boundary -> read next sector */
uint8_t next_sector[SECTOR_SIZE];
if (read_sector(fs.fat_start_lba + sector_index + 1, next_sector) != 0)
{
return -1;
}
*out_value = sector[idx] | (next_sector[0] << 8);
}
else
{
*out_value = sector[idx] | (sector[idx + 1] << 8);
}
return 0;
}
static int write_fat_entry(uint16_t cluster, uint16_t value)
{
uint32_t offset = cluster * 2;
uint32_t sector_lba = fs.fat_start_lba + (offset / fs.bytes_per_sector);
uint8_t sector[SECTOR_SIZE];
if (read_sector(sector_lba, sector) != 0)
{
return -1;
}
sector[offset % fs.bytes_per_sector] = value & 0xFF;
sector[(offset % fs.bytes_per_sector) + 1] = (value >> 8) & 0xFF;
/* write to all FAT copies */
for (uint8_t f = 0; f < fs.num_fats; f++)
{
if (write_sector(fs.fat_start_lba + f * fs.sectors_per_fat + (offset / fs.bytes_per_sector), sector) != 0)
{
return -1;
}
}
return 0;
}
static int find_free_cluster(uint16_t* out_cluster)
{
uint16_t total_clusters = (fs.total_sectors - fs.data_start_lba) / fs.sectors_per_cluster;
uint16_t value;
for (uint16_t c = 2; c < total_clusters; c++)
{
if (read_fat_entry(c, &value) != 0)
{
return -1;
}
if (value == 0x0000)
{
*out_cluster = c;
return 0;
}
}
return -1; /* no free cluster */
}
/* -------------------- Root directory ------------------------- */
static int find_free_root_entry(uint32_t* out_sector, uint32_t* out_offset)
{
uint32_t root_dir_sectors = ((fs.root_entry_count * 32) + (fs.bytes_per_sector - 1)) / fs.bytes_per_sector;
uint8_t sector[SECTOR_SIZE];
for (uint32_t i = 0; i < root_dir_sectors; i++)
{
if (read_sector(fs.root_dir_lba + i, sector) != 0)
{
return -1;
}
for (uint32_t offset = 0; offset < SECTOR_SIZE; offset += 32)
{
if (sector[offset] == 0x00 || sector[offset] == 0xE5)
{
*out_sector = fs.root_dir_lba + i;
*out_offset = offset;
return 0;
}
}
}
return -1;
}
/* -------------------- File operations ----------------------- */
int fat16_find_file(const char* name, fat16_file_t* out_file)
{
uint32_t root_dir_sectors = ((fs.root_entry_count * 32) + (fs.bytes_per_sector - 1)) / fs.bytes_per_sector;
uint8_t sector[SECTOR_SIZE];
for (uint32_t i = 0; i < root_dir_sectors; i++)
{
if (read_sector(fs.root_dir_lba + i, sector) != 0)
{
return -1;
}
for (uint32_t offset = 0; offset < SECTOR_SIZE; offset += 32)
{
if (sector[offset] == 0x00)
{
return -1; /* no more entries */
}
else if (sector[offset] == 0xE5)
{
continue; /* deleted entry */
}
if (memcmp(sector + offset, name, 11) == 0)
{
memcpy(out_file->name, sector + offset, 12);
out_file->attr = sector[offset + 11];
out_file->first_cluster = sector[offset + 26] | (sector[offset + 27] << 8);
out_file->size = sector[offset + 28] | (sector[offset + 29] << 8) | (sector[offset + 30] << 16) | (sector[offset + 31] << 24);
return 0;
}
}
}
return -1;
}
int fat16_create_file(const char* name, fat16_file_t* out_file)
{
uint16_t free_cluster;
if (find_free_cluster(&free_cluster) != 0)
{
return -1;
}
uint32_t sector_lba, offset;
if (find_free_root_entry(&sector_lba, &offset) != 0)
{
return -1;
}
uint8_t sector[SECTOR_SIZE];
if (read_sector(sector_lba, sector) != 0)
{
return -1;
}
/* Fill root entry */
memset(sector + offset, ' ', 11);
memcpy(sector + offset, name, 11);
sector[offset + 11] = 0x20; /* normal file */
sector[offset + 26] = free_cluster & 0xFF;
sector[offset + 27] = (free_cluster >> 8) & 0xFF;
sector[offset + 28] = 0; sector[offset + 29] = 0;
sector[offset + 30] = 0; sector[offset + 31] = 0;
if (write_sector(sector_lba, sector) != 0)
{
return -1;
}
/* mark cluster as end-of-chain */
if (write_fat_entry(free_cluster, 0xFFFF) != 0)
{
return -1;
}
if (out_file)
{
memset(out_file, 0, sizeof(fat16_file_t));
strncpy(out_file->name, name, 11);
out_file->first_cluster = free_cluster;
out_file->size = 0;
out_file->attr = 0x20;
}
return 0;
}
int fat16_write_file(fat16_file_t* file, const void* buffer, uint32_t size) {
const uint8_t* buf = (const uint8_t*)buffer;
uint32_t bytes_remaining = size;
uint16_t cluster = file->first_cluster;
if (cluster == 0) return -1; /* safety: file must have a cluster */
while (bytes_remaining > 0) {
uint32_t lba = cluster_to_lba(cluster);
for (uint8_t i = 0; i < fs.sectors_per_cluster && bytes_remaining > 0; i++) {
uint8_t sector[SECTOR_SIZE];
memset(sector, 0, SECTOR_SIZE);
uint32_t copy_bytes = bytes_remaining < SECTOR_SIZE ? bytes_remaining : SECTOR_SIZE;
memcpy(sector, buf, copy_bytes);
if (write_sector(lba + i, sector) != 0) return -1;
buf += copy_bytes;
bytes_remaining -= copy_bytes;
}
uint16_t next_cluster;
if (bytes_remaining > 0) {
if (find_free_cluster(&next_cluster) != 0) return -1;
if (write_fat_entry(cluster, next_cluster) != 0) return -1;
if (write_fat_entry(next_cluster, 0xFFFF) != 0) return -1;
cluster = next_cluster;
}
}
/* Update file size in root entry (your code already does this on disk) */
/* Now update the in-memory struct so subsequent reads use the new size */
file->size = size;
/* optionally: refresh metadata from disk:
fat16_find_file(file->name, file); */
return 0;
}
int fat16_read_file(fat16_file_t* file, void* buffer)
{
uint8_t sector[SECTOR_SIZE];
uint16_t cluster = file->first_cluster;
uint32_t bytes_remaining = file->size;
uint8_t* buf = (uint8_t*)buffer;
while (cluster >= 0x0002 && cluster < 0xFFF8)
{
uint32_t lba = cluster_to_lba(cluster);
for (uint8_t i = 0; i < fs.sectors_per_cluster && bytes_remaining > 0; i++)
{
if (read_sector(lba + i, sector) != 0)
{
return -1;
}
uint32_t copy_bytes = bytes_remaining < SECTOR_SIZE ? bytes_remaining : SECTOR_SIZE;
memcpy(buf, sector, copy_bytes);
buf += copy_bytes;
bytes_remaining -= copy_bytes;
}
/* read next cluster from FAT */
uint32_t fat_offset = cluster * 2; /* FAT16 */
uint32_t fat_sector = fs.fat_start_lba + (fat_offset / fs.bytes_per_sector);
uint16_t fat_entry;
if (read_sector(fat_sector, sector) != 0)
{
return -1;
}
fat_entry = sector[fat_offset % fs.bytes_per_sector] | (sector[(fat_offset % fs.bytes_per_sector) + 1] << 8);
cluster = fat_entry;
}
return 0;
}
int fat16_delete_file(const char* filename)
{
uint8_t sector[512];
uint32_t root_dir_sectors = ((fs.root_entry_count * 32) + (fs.bytes_per_sector - 1)) / fs.bytes_per_sector;
uint32_t root_dir_start = fs.root_dir_lba;
for (uint32_t s = 0; s < root_dir_sectors; s++)
{
if (read_sector(root_dir_start + s, sector) != 0)
return -1;
for (int i = 0; i < fs.bytes_per_sector; i += 32)
{
uint8_t* entry = &sector[i];
if (entry[0] == 0x00)
return -1; // end of directory
if (entry[0] == 0xE5)
continue; // already deleted
if (memcmp(entry, filename, 11) == 0)
{
// Found the file — mark as deleted
entry[0] = 0xE5;
if (write_sector(root_dir_start + s, sector) != 0)
return -1;
// Free FAT chain
uint16_t cluster = entry[26] | (entry[27] << 8);
while (cluster >= 0x0002 && cluster < 0xFFF8)
{
uint32_t fat_offset = cluster * 2;
uint32_t fat_sector = fs.fat_start_lba + (fat_offset / fs.bytes_per_sector);
uint32_t ent_offset = fat_offset % fs.bytes_per_sector;
if (read_sector(fat_sector, sector) != 0)
break;
uint16_t next_cluster = sector[ent_offset] | (sector[ent_offset + 1] << 8);
sector[ent_offset] = 0x00;
sector[ent_offset + 1] = 0x00;
if (write_sector(fat_sector, sector) != 0)
break;
cluster = next_cluster;
}
return 0; // success
}
}
}
return -1; // file not found
}

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

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

View File

@ -1,24 +1,50 @@
#include <stdlib.h>
#include <string.h>
#include <tty.h>
#include <fs/vfs.h>
typedef struct vfs_file_header {
char* filename; /* The filename, not the path. */
int32_t fd;
uint8_t type_info; /* Bits 0 - 3 -> File type, Bits 4 - 7 FS type */
uint16_t* fs_header;
struct vfs_file_header* next; /* Linked list */
} vfs_file_header_t;
/* we use something similar to the Linux kernel in terms of a VFS system */
vfs_file_header_t* root;
struct fdtable {
struct file* fds[MAX_FDS];
};
#if 0
struct fdtable* vfs_init_kernel_fdtable(void)
{
struct fdtable* ft = malloc(sizeof(struct fdtable));
struct file* _stdout = malloc(sizeof(struct file));
struct file* _stdin = malloc(sizeof(struct file));
if (!ft || !_stdin || !_stdout)
{
return NULL;
}
_stdout->f_inode = NULL;
_stdout->f_offset = 0;
_stdout->f_refcount = 1;
_stdout->f_ops = { .read = NULL, .write = vfs_handle_stdout };
return NULL;
}
#endif
int init_vfs(int argc, char** argv)
{
(void) argc;
(void) argv;
return 0;
}
/*
@ -28,5 +54,7 @@ vfs_file_header_t* root;
wow.
and now my CPU fan is going nuts.
--update: now it works. I had to go back to nouveau instead of the proprietary nVidia drivers..
--update: now it works. I had to go back to nouveau instead of the proprietary nVidia®©™ drivers..
--update: I wrote what months ago. now is 3/12/2026, I don't even remember what was going on well. wow.
*/

View File

@ -7,8 +7,8 @@
uint64_t gdt[GDT_ENTRIES];
struct {
uint16_t limit;
uint32_t base;
uint16_t limit;
uint32_t base;
} __attribute__((packed)) gp;

173
drivers/graphics/vga.c Normal file
View File

@ -0,0 +1,173 @@
#include <types.h>
#include <mm/paging.h>
#include <stdio.h>
#include <port_io.h>
#include <math.h>
#include <drivers/graphics/vga.h>
#define VBE_DISPI_IOPORT_INDEX 0x01CE
#define VBE_DISPI_IOPORT_DATA 0x01CF
#define VBE_DISPI_INDEX_ID 0x0
#define VBE_DISPI_INDEX_XRES 0x1
#define VBE_DISPI_INDEX_YRES 0x2
#define VBE_DISPI_INDEX_BPP 0x3
#define VBE_DISPI_INDEX_ENABLE 0x4
#define VBE_DISPI_INDEX_BANK 0x5
#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
#define VBE_DISPI_INDEX_X_OFFSET 0x8
#define VBE_DISPI_INDEX_Y_OFFSET 0x9
#define VBE_DISPI_DISABLED 0x00
#define VBE_DISPI_ENABLED 0x01
#define VBE_DISPI_LFB_ENABLED 0x40
static bool bga_init = false;
static bool bga_error = false;
uint32_t current_bpp = 0;
uint32_t current_xres = 0;
uint32_t current_yres = 0;
static struct bga_framebuffer bga_fb;
void init_bga_framebuffer(uint32_t* _p)
{
uint32_t width = 1024;
uint32_t height = 768;
uint32_t bpp = 32;
uint32_t pitch = width * (bpp / 8);
uint32_t fb_size = pitch * height;
fb_size = (fb_size + 0xFFF) & ~0xFFF;
uint8_t* bp = (uint8_t*) _p;
for (uint32_t off = 0; off < fb_size; off += 0x1000)
{
map_page(bp + off, bp + off);
}
bga_fb.addr = _p;
bga_fb.bpp = bpp;
bga_fb.height = height;
bga_fb.width = width;
bga_fb.pitch = pitch;
bga_init = true;
}
uint8_t* bga_get_framebuffer(void)
{
return bga_fb.addr;
}
void bga_write_register(uint16_t index, uint16_t data)
{
outw(VBE_DISPI_IOPORT_INDEX, index);
outw(VBE_DISPI_IOPORT_DATA, data);
}
uint16_t bga_read_register(uint16_t index)
{
outw(VBE_DISPI_IOPORT_INDEX, index);
return inw(VBE_DISPI_IOPORT_DATA);
}
void bga_set_video_mode(uint32_t width, uint32_t height, uint32_t bit_depth)
{
bga_write_register(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);
bga_write_register(VBE_DISPI_INDEX_XRES, width);
bga_write_register(VBE_DISPI_INDEX_YRES, height);
bga_write_register(VBE_DISPI_INDEX_BPP, bit_depth);
bga_write_register(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
/* now we check to see if any info we gave was rejected, in which case everything would be the way it was before we wrote the configuration info. */
uint16_t bpp = bga_read_register(VBE_DISPI_INDEX_BPP);
if (bpp != bit_depth)
{
bga_error = true;
}
else
{
current_bpp = bit_depth;
current_xres = width;
current_yres = height;
}
}
void bga_defaults(void)
{
// Disable device while changing settings
bga_write_register(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);
// Set resolution
bga_write_register(VBE_DISPI_INDEX_XRES, 1024);
bga_write_register(VBE_DISPI_INDEX_YRES, 768);
bga_write_register(VBE_DISPI_INDEX_BPP, 32);
// Enable graphics + linear framebuffer
bga_write_register(
VBE_DISPI_INDEX_ENABLE,
VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED
);
}
/*void bga_putpixel(uint32_t x, uint32_t y, uint32_t color)
{
if (current_bpp == 16)
{
uint16_t* fb = (uint16_t*) bga_framebuffer;
uint32_t idx = (y * current_xres + x) * 2;
*(fb + idx) = (uint16_t) color;
}
}*/
void bga_putpixel(uint32_t x, uint32_t y, uint32_t color)
{
uint32_t bytes_per_pixel = bga_fb.bpp / 8;
uint8_t* pixel = (uint8_t*)bga_fb.addr + (y * bga_fb.pitch) + (x * bytes_per_pixel);
*(volatile uint32_t*)pixel = color;
}
void bga_drawline(int x0, int y0, int x1, int y1, uint32_t color)
{
int dx = abs(x1 - x0);
int dy = abs(y1 - y0);
int sx = (x0 < x1) ? 1 : -1;
int sy = (y0 < y1) ? 1 : -1;
int err = dx - dy;
while (1)
{
bga_putpixel(x0, y0, color);
if (x0 == x1 && y0 == y1)
break;
int e2 = err * 2;
if (e2 > -dy)
{
err -= dy;
x0 += sx;
}
if (e2 < dx)
{
err += dx;
y0 += sy;
}
}
}

View File

@ -35,6 +35,12 @@ static int32_t ide_wait_ready(uint16_t io)
return 1;
}
int get_sector_size(uint8_t drive)
{
(void) drive;
return SECTOR_SIZE;
}
int32_t ide_identify(uint8_t drive, uint16_t* buffer)
{
uint16_t io = ATA_PRIMARY_IO;
@ -63,10 +69,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 +90,18 @@ void ide_initialize(void) {
model[40] = 0;
printf("Disk model: %s\n", model);
}
else
{
printf("ide_initialize(): ide_identify(0, identify_buf) did NOT return 0!\n");
}
#ifdef _DEBUG
printf("[ IDE ] IDE initialized\n");
#endif
}
int32_t ide_read48(uint8_t drive, uint64_t lba, uint8_t sector_count, void* buffer) {
int32_t ide_read48(uint8_t drive, uint64_t lba, uint8_t sector_count, void* buffer)
{
if (sector_count == 0)
{
return -1;

View File

@ -1,6 +1,11 @@
#include <stdio.h>
#include <port_io.h>
#include <scheduler.h>
#include <kernel/syscall.h>
#include <drivers/irq.h>
#include <drivers/idt.h>
@ -29,8 +34,7 @@ typedef struct {
} __attribute__((packed)) idtr_t;
__attribute__((aligned(0x10)))
static idt_entry_t idt[256]; // Create an array of IDT entries; aligned for performance
static idt_entry_t idt[256]; /* create an array of IDT entries; aligned for performance */
static idtr_t idtr;
@ -38,91 +42,6 @@ static bool vectors[IDT_MAX_DESCRIPTORS];
extern void* isr_stub_table[];
__attribute__((noreturn))
void exception_dispatcher(uint32_t int_no, uint32_t err_code)
{
switch (int_no)
{
case 0:
printf("Divide by zero exception\n");
break;
case 13:
printf("General Protection Fault: err=0x%x\n", err_code);
break;
case 14:
{
uint32_t cr2;
asm volatile ("mov %%cr2, %0" : "=r"(cr2));
printf("Page Fault at address: 0x%x, err=0x%x\n", cr2, err_code);
break;
}
default:
printf("Unhandled exception #%u, err=0x%x\n", int_no, err_code);
break;
}
uint16_t cs, ds, es, ss;
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("CS=0x%04x DS=0x%04x ES=0x%04x SS=0x%04x\n", cs, ds, es, ss);
asm volatile ("cli; hlt");
/* Will never be reached */
while (true)
{
asm volatile ("hlt" ::: "memory");
}
}
void idt_set_descriptor(uint8_t vector, void* isr, uint8_t flags)
{
idt_entry_t* descriptor = &idt[vector];
descriptor->isr_low = (uint32_t)isr & 0xFFFF;
descriptor->kernel_cs = 0x08;
descriptor->attributes = flags;
descriptor->isr_high = (uint32_t)isr >> 16;
descriptor->reserved = 0;
}
void pic_remap(void)
{
uint8_t a1, a2;
/* Save masks */
a1 = inb(PIC1_DATA);
a2 = inb(PIC2_DATA);
/* Start initialization sequence (in cascade mode) */
outb(PIC1_COMMAND, 0x11);
outb(PIC2_COMMAND, 0x11);
/* Set vector offset */
outb(PIC1_DATA, 0x20); /* IRQs 0-7 mapped to IDT entries 0x20-0x27 (3239) */
outb(PIC2_DATA, 0x28); /* IRQs 8-15 mapped to IDT entries 0x28-0x2F (4047) */
/* Tell Master PIC about Slave PIC at IRQ2 (0000 0100) */
outb(PIC1_DATA, 0x04);
/* Tell Slave PIC its cascade identity (0000 0010) */
outb(PIC2_DATA, 0x02);
/* Set 8086/88 mode */
outb(PIC1_DATA, 0x01);
outb(PIC2_DATA, 0x01);
/* Restore saved masks */
outb(PIC1_DATA, a1);
outb(PIC2_DATA, a2);
}
void idt_init(void)
{
idtr.base = (uintptr_t)&idt[0];
@ -136,13 +55,141 @@ void idt_init(void)
extern void* irq_stub_table[];
for (uint8_t i = 0; i < 16; i++)
for (uint8_t i = 0; i < 20; i++)
{
idt_set_descriptor(32 + i, irq_stub_table[i], 0x8E);
}
asm volatile ("lidt %0" : : "m"(idtr)); /* load the new IDT */
asm volatile ("sti"); /* set the interrupt flag */
//asm volatile ("sti"); /* set the interrupt flag */
}
registers_t* interrupt_dispatcher(registers_t* regs)
{
if (regs->int_no < 32)
{
printf("external: %s, IDT/GDT: %s, ", ((regs->err_code & 0x0001) ? "true" : "false"), (regs->err_code & 0x0006) ? "IDT" : "GDT");
printf("LDT: %s, selector: %x (%i)\n", ((regs->err_code & 0x0006) == 0b10) ? "true" : "false", regs->err_code & 0xFFF8, regs->err_code & 0xFFF8);
printf("int: %i (%x), err: %i (%x)\n", regs->int_no, regs->int_no, regs->err_code, regs->err_code);
exception_handler(regs);
}
else if (regs->int_no < 52)
{
uint32_t irq = regs->int_no - 32;
regs = irq_handler(irq, regs);
if (irq >= 8)
{
outb(0xA0, 0x20); /* acknowledge the IRQ to slave PIC */
}
outb(0x20, 0x20); /* acknowledge the IRQ to master PIC */
}
return regs;
}
__noreturn
void exception_handler(registers_t* regs)
{
uint32_t int_no = regs->int_no;
uint32_t err_code = regs->err_code;
switch (int_no)
{
case 0:
printf("Divide by zero exception (or other division error)\n");
break;
case 2:
printf("NMI encountered\n");
break;
case 6: /* XXX: NOTE: this can be used to emulate instructions that do not exist on the current CPU :NOTE :XXX */
printf("Invalid opcode encountered at %p\n", regs->eip);
break;
case 7: /* XXX: NOTE: use this for FPU emulation and for saving/restoring FPU registers in a multiprocessing enviroment :NOTE :XXX */
printf("FPU instructions used, but FPU is nonexistant/disabled\n");
break;
case 8: /* double fault */
printf("Double fault at %p, err %i\n", regs->eip, regs->err_code);
break;
case 13:
printf("General Protection Fault: err=0x%x at %p\n", err_code, regs->eip);
break;
case 14:
{
uint32_t cr2;
asm volatile ("mov %%cr2, %0" : "=r"(cr2));
printf("PF addr=%p eip=%p err=%x\n", cr2, regs->eip, err_code);
//printf("Page Fault at address: 0x%x, err=0x%x\n", cr2, err_code);
break;
}
default:
printf("Unhandled exception #%u, err=0x%x at %p\n", int_no, err_code, regs->eip);
break;
}
uint16_t cs, ds, es, ss;
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));
if (((uint16_t) regs->cs != cs) || ((uint16_t) regs->ds != ds) || ((uint16_t) regs->es != es))
{
printf("segment register mismatch!\n");
}
printf("cs: 0x%x, ds: 0x%x, es: 0x%x,\nss: 0x%x, fs: 0x%x, gs: 0x%x\n", regs->cs, regs->ds, regs->es, ss, regs->fs, regs->gs);
asm volatile ("cli; hlt");
/* Will never be reached */
while (true)
{
asm volatile ("hlt" ::: "memory");
}
}
void idt_set_descriptor(uint8_t vector, void* isr, uint8_t flags)
{
idt_entry_t* descriptor = &idt[vector];
descriptor->isr_low = (uint32_t) isr & 0xFFFF;
descriptor->kernel_cs = 0x08;
descriptor->attributes = flags;
descriptor->isr_high = (uint32_t) isr >> 16;
descriptor->reserved = 0;
}
void pic_remap(void)
{
uint8_t a1, a2;
/* save masks */
a1 = inb(PIC1_DATA);
a2 = inb(PIC2_DATA);
/* start initialization sequence (in cascade mode) */
outb(PIC1_COMMAND, 0x11);
outb(PIC2_COMMAND, 0x11);
/* set vector offset */
outb(PIC1_DATA, 0x20); /* IRQs 0-7 mapped to IDT entries 0x20-0x27 (3239) */
outb(PIC2_DATA, 0x28); /* IRQs 8-15 mapped to IDT entries 0x28-0x2F (4047) */
/* tell the master PIC about Slave PIC at IRQ2 (0000 0100) */
outb(PIC1_DATA, 0x04);
/* tell the slave PIC its cascade identity (0000 0010) */
outb(PIC2_DATA, 0x02);
/* set 8086/88 mode */
outb(PIC1_DATA, 0x01);
outb(PIC2_DATA, 0x01);
/* restore saved masks */
outb(PIC1_DATA, a1);
outb(PIC2_DATA, a2);
}

View File

@ -1,68 +1,76 @@
#include <stdio.h>
#include <drivers/ps2_keyboard.h>
#include <drivers/pit.h>
#include <port_io.h>
/* TEMP DEBUG */
#include <tty.h>
#include <kernel/syscall.h>
#include <drivers/irq.h>
#define NUM_IRQS 0x90
irq_func_t func_list[NUM_IRQS];
irq_func_t aux_func_list[NUM_IRQS];
#define MAX_IRQ_HANDLERS 128 /* the maximum number of irq handlers */
typedef struct {
uint32_t irq_no;
irq_func_t func;
} irq_handler_t;
static volatile uint32_t num_irqs_missed = 0;
uint32_t num_irq_handlers = 0;
irq_handler_t handler_list[MAX_IRQ_HANDLERS];
volatile uint32_t num_irqs_missed = 0;
void irq_init(void)
{
memset(func_list, 0x0, NUM_IRQS);
memset(aux_func_list, 0x0, NUM_IRQS);
set_irq_handler(0, (irq_func_t*)pit_handler);
set_irq_handler(1, (irq_func_t*)keyboard_handler);
}
void irq_handler(uint8_t irq_number)
{
if (irq_number < NUM_IRQS)
for (int i = 0; i < MAX_IRQ_HANDLERS; i++)
{
if (func_list[irq_number])
{
func_list[irq_number]();
}
else if (aux_func_list[irq_number])
{
aux_func_list[irq_number]();
}
else
{
num_irqs_missed++;
}
handler_list[i].irq_no = 0;
handler_list[i].func = NULL;
}
set_irq_handler(0, (irq_func_t) pit_handler);
//set_irq_handler(1, (irq_func_t) ps2_keyboard_handler);
}
void set_irq_handler(uint32_t num, irq_func_t* handler)
registers_t* irq_handler(uint32_t irq, registers_t* regs)
{
if (num < NUM_IRQS)
{
func_list[num] = (irq_func_t)handler;
}
}
uint8_t funcs_called = 0;
void add_irq_handler(uint32_t num, irq_func_t* handler)
{
if (num < NUM_IRQS)
{
if (func_list[num] != 0x0)
if (num_irq_handlers > 0)
{
for (unsigned int i = 0; i < MAX_IRQ_HANDLERS; i++)
{
if (aux_func_list[num] == 0x0)
if (handler_list[i].irq_no == irq && handler_list[i].func != NULL)
{
aux_func_list[num] = (irq_func_t)handler;
regs = handler_list[i].func(regs);
funcs_called++;
/* PIC IRQ acknowledgement happens in idt.c */
}
return;
}
}
if (funcs_called == 0)
{
num_irqs_missed++;
}
return regs;
}
uint32_t get_interrupts_missed(void)
{
return num_irqs_missed;
}
void set_irq_handler(uint32_t num, irq_func_t handler)
{
if (num < MAX_IRQ_HANDLERS)
{
handler_list[num].irq_no = num;
handler_list[num].func = handler;
func_list[num] = (irq_func_t)handler;
num_irq_handlers++;
}
}

201
drivers/keyboard.c Normal file
View File

@ -0,0 +1,201 @@
#include <types.h>
#include <port_io.h>
#include <new_tty.h>
#include <stdio.h>
#include <drivers/irq.h>
#include <drivers/keyboard.h>
/*
PS/2 Controller IO Ports
The PS/2 Controller itself uses 2 IO ports (IO ports 0x60 and 0x64). Like many IO ports, reads and writes may access different internal registers.
Historical note: The PC-XT PPI had used port 0x61 to reset the keyboard interrupt request signal (among other unrelated functions). Port 0x61 has no keyboard related functions on AT and PS/2 compatibles.
IO Port Access Type Purpose
0x60 Read/Write Data Port
0x64 Read Status Register
0x64 Write Command Register
*/
#define PS2_DATA_PORT 0x60
#define PS2_STATUS_PORT 0x64
#define KEYBOARD_IRQ 1
static const char scancode_map[128] = {
0, 27, '1','2','3','4','5','6','7','8','9','0','-','=','\b', /* Backspace */
'\t', /* Tab */
'q','w','e','r','t','y','u','i','o','p','[',']','\n', /* Enter */
0, /* Control */
'a','s','d','f','g','h','j','k','l',';','\'','`',
0, /* Left shift */
'\\','z','x','c','v','b','n','m',',','.','/',
0, /* Right shift */
'*',
0, /* Alt */
' ', /* Spacebar */
0, /* Caps lock */
/* The rest are function and control keys */
};
volatile uint32_t mods = 0;
volatile bool keyboard_initialied = false;
volatile bool extended = false;
int init_keyboard(void)
{
#ifdef _DEBUG
printf("Initializing the keyboard...\n");
#endif
keyboard_initialied = true;
set_irq_handler(1, (irq_func_t) keyboard_handler);
#ifdef _DEBUG
printf("Keyboard initialized\n");
#endif
return 0;
}
registers_t* keyboard_handler(registers_t* regs)
{
if (!(inb(PS2_STATUS_PORT) & 1))
{
return regs;
}
uint8_t scancode = inb(PS2_DATA_PORT);
if (scancode == 0xE0)
{
extended = true;
return regs;
}
bool is_release = scancode & 0x80;
uint8_t key = scancode & 0x7F;
if (extended)
{
if (is_release)
{
if (key == 0x1D)
{
mods &= ~MODIFIER_RCTRL;
}
}
else
{
if (key == 0x1D)
{
mods |= MODIFIER_RCTRL;
}
}
/* delete key, should add this functionality */
/*if (key == 0x53)*/
extended = false;
return regs;
}
if (is_release)
{
if (key == 0x2A || key == 0x36)
{
mods &= ~MODIFIER_SHIFT;
}
return regs;
}
else
{
if (key == 0x2A || key == 0x36)
{
mods |= MODIFIER_SHIFT;
return regs;
}
else if (key == 0x3A)
{
mods ^= MODIFIER_CAPS;
return regs;
}
}
uint16_t c = (uint16_t) scancode_map[scancode];
if (c)
{
//tty_receive_char(c, mods);
char ch = tty_translate_char(c, mods);
tty_input_char(tty_get_active(), ch);
}
return regs;
}
/* Handle shift press/release */
/*if (scancode == 0x2A || scancode == 0x36)
{
mods |= MODIFIER_SHIFT;
return regs;
}
else if (scancode == 0xAA || scancode == 0xB6)
{
mods &= MODIFIER_SHIFT_DESTROY;
return regs;
}
else if (scancode == 0x3A)
{
TOGGLE_BIT(mods, 0);
return regs;
}*/
/*else if (scancode == 0xE0)
{
extended = true;
return;
}*/
/* XXX: NOTE: we don't do extended codes yet. :NOTE :XXX */
/*if (extended)
{*/
/*switch (scancode)
{
case 0x48:
c = KEY_ARROW_UP;
break;
case 0x50:
c = KEY_ARROW_DOWN;
break;
case 0x4B:
c = KEY_ARROW_LEFT;
break;
case 0x4D:
c = KEY_ARROW_RIGHT;
break;
default:
c = KEY_NONE;
break;
}*/
/*tty_receive_char(c, mod);
extended = false;
return;
}*/
/*bool release = scancode & 0x80;
scancode &= 0x7F;
if (release)
{
return regs;
}*/

499
drivers/new_tty.c Normal file
View File

@ -0,0 +1,499 @@
#include <stdio.h>
#include <stdlib.h>
#include <processes.h>
#include <sync.h>
#include <types.h>
#include <new_tty.h>
static tty_t ttys[MAX_TTYS];
static uint8_t num_ttys = 0;
static tty_t* active_tty = NULL;
static inline size_t next_index(size_t index)
{
return (index + 1) % TTY_BUFFER_SIZE;
}
static inline bool tty_empty(tty_t* tty)
{
return tty->head == tty->tail;
}
static inline bool tty_full(tty_t* tty)
{
return ((tty->head + 1) % TTY_BUFFER_SIZE) == tty->tail;
}
static inline bool is_canonical(tty_t* tty)
{
return (tty->flags & TTY_CANONICAL) != 0;
}
static void raw_put(tty_t* tty, char c)
{
size_t next = (tty->raw_head + 1) % TTY_RAW_BUFFER_SIZE;
if (next != tty->raw_tail) // avoid overflow
{
tty->raw_buf[tty->raw_head] = c;
tty->raw_head = next;
}
}
tty_t* tty_get_active(void)
{
return active_tty;
}
int tty_fread(struct file* f, char* b, size_t s)
{
return (int) tty_read_active(b, s);
}
void tty_backspace(tty_t* tty)
{
if (tty->head == tty->tail)
{
return; /* buffer empty */
}
//tty->head = (tty->head + TTY_BUFFER_SIZE - 1) % TTY_BUFFER_SIZE;
tty->head = (tty->head + TTY_BUFFER_SIZE - 1) / TTY_BUFFER_SIZE;
}
void tty_and_flags(tty_t* tty, uint32_t flags)
{
tty->flags &= flags;
}
uint32_t tty_get_flags(tty_t* tty)
{
return tty->flags;
}
ssize_t tty_read_active(char* buf, size_t count)
{
return tty_read(active_tty, buf, count);
}
/*
this is special, because when this is called the char returned by this function
is NOT added to the TTY buffer.
This can be changed however by setting flag TTY_ADDCHAR_ALWAYS.
*/
/*char tty_get_char(void)
{
tty_t* tty = get_active_tty();
if (!tty)
{
return 0;
}
while (1)
{
IRQ_DISABLE();
spin_lock(&tty->lock);
if (tty->char_available)
{
char c = tty->last_char;
tty->char_available = false;
spin_unlock(&tty->lock);
IRQ_ENABLE();
return c;
}
spin_unlock(&tty->lock);
IRQ_ENABLE();
}
}*/
char tty_get_char(void)
{
tty_t* tty = get_active_tty();
if (!tty)
return 0;
while (1)
{
IRQ_DISABLE();
spin_lock(&tty->lock);
if (tty->raw_head != tty->raw_tail)
{
char c = tty->raw_buf[tty->raw_tail];
tty->raw_tail = (tty->raw_tail + 1) % TTY_RAW_BUFFER_SIZE;
spin_unlock(&tty->lock);
IRQ_ENABLE();
return c;
}
spin_unlock(&tty->lock);
IRQ_ENABLE();
}
}
ssize_t tty_read(tty_t* tty, char* buf, size_t count)
{
if (!tty || !buf)
{
return -1;
}
size_t bytes = 0;
while (1)
{
IRQ_DISABLE();
spin_lock(&tty->lock);
if (!tty->line_ready)
{
spin_unlock(&tty->lock);
IRQ_ENABLE();
continue; /* spin until newline */
}
while (bytes < count && tty->tail != tty->head)
{
char c = tty->input_buffer[tty->tail];
tty->tail = (tty->tail + 1) % TTY_BUFFER_SIZE;
buf[bytes++] = c;
if (c == '\n')
{
tty->line_ready = false;
break;
}
}
spin_unlock(&tty->lock);
IRQ_ENABLE();
break;
}
return bytes;
}
int input_buffer_put(tty_t* tty, char c)
{
IRQ_DISABLE();
spin_lock(&tty->lock);
size_t next = next_index(tty->head);
if (next == tty->tail)
{
spin_unlock(&tty->lock);
IRQ_ENABLE();
return -1;
}
tty->input_buffer[tty->head] = c;
tty->head = next;
spin_unlock(&tty->lock);
IRQ_ENABLE();
return 0;
}
int init_tty(void)
{
if (num_ttys >= MAX_TTYS)
{
return -1;
}
tty_t* t = &ttys[0];
memset(t, 0, sizeof(tty_t));
t->flags = TTY_NORMAL;
active_tty = t;
num_ttys = 1;
t->f_ops.read = tty_fread;
t->line_ready = false;
return 0;
}
tty_t* get_active_tty(void)
{
return active_tty;
}
tty_t* make_tty(uint32_t flags)
{
if (num_ttys >= MAX_TTYS)
{
return NULL;
}
tty_t* t = &ttys[num_ttys];
memset(t, 0, sizeof(tty_t));
t->flags = flags;
num_ttys++;
return t;
}
void tty_receive_char(char c, uint32_t kbd_mod)
{
if (!active_tty || c == 0)
{
return;
}
c = tty_translate_char(c, kbd_mod);
/* Handle backspace */
if (c == '\b')
{
tty_backspace(active_tty);
if (active_tty->head == active_tty->tail)
{
extern void terminal_putcharat(char c, uint16_t row, uint16_t column);
terminal_putcharat('Z', 20, 20);
}
if (active_tty->flags & TTY_ECHO)
{
/* erase character visually */
putc('\b');
}
return;
}
input_buffer_put(active_tty, c);
if (active_tty->flags & TTY_ECHO)
{
if ((active_tty->flags & TTY_PASSWORD) == 0)
{
putc(c);
}
else
{
putc('*');
}
}
}
/*void tty_input_char(tty_t* tty, char c)
{
if (!tty || c == 0)
{
return;
}
IRQ_DISABLE();
spin_lock(&tty->lock);
raw_put(tty, c);
if (c == '\b')
{
if (tty->head != tty->tail)
{
tty->head = (tty->head + TTY_BUFFER_SIZE - 1) % TTY_BUFFER_SIZE;
if (tty->flags & TTY_ECHO)
{
putc('\b');
}
}
spin_unlock(&tty->lock);
IRQ_ENABLE();
return;
}
size_t next = (tty->head + 1) % TTY_BUFFER_SIZE;
if (next != tty->tail)
{
tty->input_buffer[tty->head] = c;
tty->head = next;
if (c == '\n')
{
tty->line_ready = true;
}
}
spin_unlock(&tty->lock);
IRQ_ENABLE();
if (tty->flags & TTY_ECHO)
{
putc(c);
}
}*/
void tty_input_char(tty_t* tty, char c)
{
if (!tty || c == 0)
{
return;
}
IRQ_DISABLE();
spin_lock(&tty->lock);
/* RAW queue always gets input */
raw_put(tty, c);
if (!(tty->flags & TTY_RAW))
{
/* canonical behavior */
if (c == '\b')
{
if (tty->head != tty->tail)
{
tty->head = (tty->head + TTY_BUFFER_SIZE - 1) % TTY_BUFFER_SIZE;
putc('\b');
putc(' ');
putc('\b');
spin_unlock(&tty->lock);
IRQ_ENABLE();
return;
}
}
else
{
size_t next = next_index(tty->head);
if (next != tty->tail)
{
tty->input_buffer[tty->head] = c;
tty->head = next;
if (c == '\n')
{
tty->line_ready = true;
}
}
}
}
spin_unlock(&tty->lock);
IRQ_ENABLE();
if (tty->flags & TTY_ECHO)
{
putc(c);
}
}
char tty_translate_char(char c, uint32_t modifiers)
{
bool caps = (modifiers & MODIFIER_CAPS) != 0;
bool shift = (modifiers & MODIFIER_SHIFT) != 0;
bool ctrl = (modifiers & (MODIFIER_LCTRL | MODIFIER_RCTRL)) != 0;
/* handle alphabetic characters */
if (c >= 'a' && c <= 'z')
{
if (caps ^ shift) /* XOR logic */
{
return c - 32; /* to uppercase */
}
return c;
}
if (c >= 'A' && c <= 'Z')
{
if (caps ^ shift)
{
return c;
}
return c + 32; /* to lowercase */
}
/* handle ctrl (should later include control mapping/sending messages to processes via these) */
if (ctrl)
{
if (c >= 'a' && c <= 'z')
{
return c - 'a' + 1; /* Ctrl+A → 1 */
}
if (c >= 'A' && c <= 'Z')
{
return c - 'A' + 1;
}
}
/* shifted symbols (US layout) */
if (shift)
{
switch (c)
{
case '1':
return '!';
case '2':
return '@';
case '3':
return '#';
case '4':
return '$';
case '5':
return '%';
case '6':
return '^';
case '7':
return '&';
case '8':
return '*';
case '9':
return '(';
case '0':
return ')';
case '-':
return '_';
case '=':
return '+';
case '[':
return '{';
case ']':
return '}';
case ';':
return ':';
case '\'':
return '"';
case ',':
return '<';
case '.':
return '>';
case '/':
return '?';
case '\\':
return '|';
case '`':
return '~';
}
}
return c;
}

View File

@ -17,81 +17,104 @@
uint32_t pci_config_read(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset)
{
uint32_t address = 0;
address |= (bus << 16); /* Bus number (bits 23-16) */
address |= (device << 11); /* Device number (bits 15-11) */
address |= (function << 8); /* Function number (bits 10-8) */
address |= (offset & 0xFC); /* Register offset (bits 7-0) */
address |= (1 << 31); /* Enable configuration access */
uint32_t address = 0;
address |= (bus << 16); /* Bus number (bits 23-16) */
address |= (device << 11); /* Device number (bits 15-11) */
address |= (function << 8); /* Function number (bits 10-8) */
address |= (offset & 0xFC); /* Register offset (bits 7-0) */
address |= (1 << 31); /* Enable configuration access */
outl(PCI_CONFIG_ADDRESS, address); /* Write address to PCI config space */
return inl(PCI_CONFIG_DATA); /* Read data from PCI config space */
outl(PCI_CONFIG_ADDRESS, address); /* Write address to PCI config space */
return inl(PCI_CONFIG_DATA); /* Read data from PCI config space */
}
void pci_config_write(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value)
{
uint32_t address = 0x80000000 | (bus << 16) | (device << 11) | (function << 8) | (offset & 0xFC);
outl(PCI_CONFIG_ADDRESS, address); /* Send the address to PCI config space */
outl(PCI_CONFIG_DATA, value); /* Write data to PCI config space */
uint32_t address = 0x80000000 | (bus << 16) | (device << 11) | (function << 8) | (offset & 0xFC);
outl(PCI_CONFIG_ADDRESS, address); /* Send the address to PCI config space */
outl(PCI_CONFIG_DATA, value); /* Write data to PCI config space */
}
void pci_config_read_block(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, void* buffer, size_t size)
{
uint8_t* buf = (uint8_t*)buffer;
uint8_t* buf = (uint8_t*)buffer;
for (size_t i = 0; i < size; i += 4)
{
uint32_t value = pci_config_read(bus, device, function, offset + i);
for (size_t i = 0; i < size; i += 4)
{
uint32_t value = pci_config_read(bus, device, function, offset + i);
size_t remaining = size - i;
if (remaining >= 4)
{
*(uint32_t*)(buf + i) = value;
size_t remaining = size - i;
if (remaining >= 4)
{
*(uint32_t*)(buf + i) = value;
}
else
{
for (size_t j = 0; j < remaining; ++j)
{
buf[i + j] = (value >> (8 * j)) & 0xFF;
}
}
}
else
{
for (size_t j = 0; j < remaining; ++j)
{
buf[i + j] = (value >> (8 * j)) & 0xFF;
}
}
}
}
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)
{
for (uint16_t bus = 0; bus < 256; bus++) /* Maximum 256 buses */
{
for (uint8_t device = 0; device < 32; device++) /* Maximum 32 devices per bus */
for (uint16_t bus = 0; bus < 256; bus++) /* Maximum 256 buses */
{
for (uint8_t function = 0; function < 8; function++) /* Maximum 8 functions per device */
{
struct pci_header pre_header;
pci_config_read_block(bus, device, function, 0x00, &pre_header, sizeof(pre_header));
for (uint8_t device = 0; device < 32; device++) /* Maximum 32 devices per bus */
{
for (uint8_t function = 0; function < 8; function++) /* Maximum 8 functions per device */
{
struct pci_header pre_header;
pci_config_read_block(bus, device, function, 0x00, &pre_header, sizeof(pre_header));
if (pre_header.vendor_id == 0xFFFF)
{
continue; /* No device present */
}
if (pre_header.class_code == 0xB)
{
printf("Processor found on PCI bus, what?!?!\n");
continue;
}
if (pre_header.header_type == 0x00)
{
struct pci_header_type_0 hdr;
pci_config_read_block(bus, device, function, 0x00, &hdr, sizeof(hdr));
if (pre_header.vendor_id == 0xFFFF)
{
continue; /* No device present */
}
if (hdr.class_code == 0x1 && hdr.subclass == 0x6 && hdr.prog_if == 0x1)
{
/*configure_ahci_controller(hdr);*/
}
if (pre_header.class_code == 0xB)
{
printf("Processor found on PCI bus, what?!?!\n"); /* For some stupid reason, processors can be on the PCI bus? */
continue;
}
if (pre_header.header_type == 0x00)
{
struct pci_header_type_0 hdr;
pci_config_read_block(bus, device, function, 0x00, &hdr, sizeof(hdr));
if (hdr.class_code == 0x1 && hdr.subclass == 0x6 && hdr.prog_if == 0x1)
{
/*configure_ahci_controller(hdr);*/
}
if (hdr.class_code == 0x03)
{
uint32_t bar0 = hdr.bar0;
extern void init_bga_framebuffer(uint32_t* _p);
init_bga_framebuffer((uint32_t*) bar0);
printf("Found framebffer addr 0x%x on device %x \n", bar0, hdr.device_id);
}
/*printf("PCI device: cc: %x sc: %x pi: %x b: %x d: %x f: %x int: %x\n", hdr.class_code, hdr.subclass, hdr.prog_if, bus, device, function, (uint32_t) hdr.interrupt_line);*/
}
}
}
}
}
}
}

View File

@ -2,6 +2,8 @@
#include <port_io.h>
#include <stdio.h>
#include <scheduler.h>
#include <drivers/pit.h>
@ -15,7 +17,13 @@ bool pit_initialized = false;
void pit_init(void)
{
uint16_t divisor = (uint16_t)1193;
printf("pit_initialized addr = %x\n", &pit_initialized);
#ifdef _DEBUG
printf("[ PIT ] Initializing the PIT...\n");
#endif
uint16_t divisor = (uint16_t) 1193;
/* Send command byte */
outb(PIT_COMMAND, 0x36); /* Channel 0, low/high byte, mode 3 (square wave), binary */
@ -25,11 +33,16 @@ 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)
registers_t* pit_handler(registers_t* regs)
{
pit_ticks++;
return regs;
}
void pit_sleep(uint64_t ms)
@ -41,3 +54,13 @@ void pit_sleep(uint64_t ms)
}
}
/*void pit_sleep(uint64_t ms)
{
extern task_t* current_task;
current_task->wakeup_tick = pit_ticks + ms;
current_task->state = TASK_SLEEPING;
asm volatile("int $32");*/ /* force reschedule immediately */
/*}
*/

View File

@ -2,7 +2,9 @@
#include <port_io.h>
#include <tty.h>
#include <stdlib.h>
#include <ksymtab.h>
#include <new_tty.h>
#include <drivers/ps2_keyboard.h>
@ -29,6 +31,16 @@
#define KEYBOARD_IRQ 1
#define RETURN_STI() do { _sti_asm(); return; } while (0)
#define GETS_BUFFER_SIZE 256
static char gets_buffer[GETS_BUFFER_SIZE];
volatile char* gets_string = gets_buffer;
volatile int32_t gets_capacity = GETS_BUFFER_SIZE;
volatile int32_t gets_length = 0;
bool ps2keyboard_initialized = false;
/* State for shift key */
@ -41,14 +53,24 @@ static bool capslock_pressed = false;
static bool extended = false;
static bool is_new_char = false;
static bool is_new_key = false;
static bool is_new_key = false;
static bool gets_called = false;
static volatile bool gets_finished = false;
volatile unsigned char current_char;
volatile char* current_string = NULL;
volatile char* current_string = NULL;
volatile int32_t current_length = 0;
volatile int32_t capacity = 0;
volatile int32_t capacity = 0;
volatile uint16_t current_key;
volatile bool use_new_tty = false;
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 */
@ -66,18 +88,144 @@ static const char scancode_map[128] = {
/* The rest are function and control keys */
};
void set_use_new_tty(bool t)
{
use_new_tty = t;
}
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 = NULL;
set_use_new_tty(true);
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)
{
_sti_asm();
return;
}
for (int i = 0; i < hook_count; i++)
{
hooks[i](c);
}
_sti_asm();
}
char get_char(void)
{
/*
ASCII code 5 (Enquiry) is/was used in legacy systems meant for requesting a response from a remote terminal or device.
For example, one system might send ENQ (ASCII 5), and the receiver could reply with ACK (ASCII 6) to indicate its ready or still online.
For example, one system might send ENQ (ASCII 5), and the receiver could reply with ACK (ASCII 6) to indicate it's ready or still online.
In modern computing, ENQ is largely obsolete:
@ -87,16 +235,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 +267,136 @@ char* get_string(void)
return current_string;
}
static void append_char(char c)
static inline void print_(void)
{
static char ch = 'a';
int r = 0, c = 0;
terminal_get_cursor(&r, &c);
terminal_set_cursor((uint16_t) 30, (uint16_t) 0);
printf("%c", ch);
terminal_set_cursor((uint16_t) r, (uint16_t) c);
ch++;
}
char* kbd_gets(void)
{
gets_called = true;
gets_finished = false;
gets_length = 0;
gets_string[0] = '\0';
while (!gets_finished)
{
sleep(1);
}
_cli_asm();
char* result = strdup((char*) gets_string);
gets_length = 0;
gets_string[0] = '\0';
gets_called = false;
_sti_asm();
return result ? result : "";
}
void gets_append_char(unsigned char c)
{
if (!gets_called)
{
return;
}
if (c == KEY_ARROW_UP || c == KEY_ARROW_DOWN || c == KEY_ARROW_RIGHT || c == KEY_ARROW_LEFT)
{
if (GETS_BUFFER_SIZE >= 2)
{
gets_string[0] = (char)c;
gets_string[1] = '\0';
}
gets_finished = true;
return;
}
else if (c == '\n')
{
gets_finished = true;
printf("\n");
return;
}
else if (c == 27)
{
gets_string[0] = '\0';
gets_finished = true;
return;
}
else if (c == '\b')
{
if (gets_length > 0)
{
gets_length--;
gets_string[gets_length] = '\0';
printf("\b \b");
}
return;
}
if (gets_length < GETS_BUFFER_SIZE - 1)
{
gets_string[gets_length++] = (char)c;
gets_string[gets_length] = '\0';
printf("%c", c);
}
}
void append_char(char c)
{
_cli_asm();
if (current_length + 1 >= capacity)
{
/* Need more space (+1 for the null zero) */
int new_capacity = (capacity == 0) ? 16 : capacity * 2;
char* new_str = (char*)malloc(new_capacity);
if (!new_str) {
char* new_str = (char*) malloc(new_capacity);
if (!new_str)
{
printf("[keyboard] ERROR: malloc failed for new input buffer\n");
return;
}
if (current_string)
{
memcpy(new_str, current_string, current_length);
free(current_string);
}
if (!current_string)
{
return;
}
current_string = new_str;
capacity = new_capacity;
}
if (!current_string)
{
return;
}
current_string[current_length] = c;
current_length++;
current_string[current_length] = '\0'; /* Maintain null terminator */
current_string[current_length] = '\0';
_sti_asm();
}
static void free_current_string(void)
void free_current_string(void)
{
if (current_string)
{
@ -165,32 +407,45 @@ static void free_current_string(void)
}
}
void keyboard_handler(void)
registers_t* ps2_keyboard_handler(registers_t* regs)
{
#if 0
uint8_t scancode = inb(PS2_DATA_PORT);
/* Handle shift press/release */
if (scancode == 0x2A || scancode == 0x36)
{
shift_pressed = true;
return;
return regs;
}
else if (scancode == 0xAA || scancode == 0xB6)
{
shift_pressed = false;
return;
return regs;
}
else if (scancode == 0x3A)
{
capslock_pressed = !capslock_pressed;
return;
return regs;
}
else if (scancode == 0xE0)
{
extended = true;
return;
return regs;
}
uint32_t flags = 0;
if (capslock_pressed)
{
flags |= MODIFIER_CAPS;
}
if (shift_pressed)
{
flags |= MODIFIER_SHIFT;
}
if (scancode & 0x80)
{
@ -198,64 +453,95 @@ 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 (!use_new_tty)
{
c -= 32; /* Convert to uppercase */
if ((shift_pressed ^ capslock_pressed) && ((char) c >= 'a') && ((char) c <= 'z'))
{
c -= 32; /* Convert to uppercase */
}
else if (shift_pressed)
{
c = (uint16_t) terminal_get_shifted((unsigned char) c);
}
if (extended)
{
switch (scancode)
{
case 0x48:
c = KEY_ARROW_UP;
break;
case 0x50:
c = KEY_ARROW_DOWN;
break;
case 0x4B:
c = KEY_ARROW_LEFT;
break;
case 0x4D:
c = KEY_ARROW_RIGHT;
break;
default:
c = KEY_NONE;
break;
}
if (gets_called)
{
gets_append_char(c);
return regs;
}
current_key = c;
is_new_key = true;
extended = false;
return regs;
}
if (gets_called)
{
gets_append_char(c);
return regs;
}
if (c)
{
if (c != '\n')
{
append_char(c);
}
current_char = c;
is_new_char = true;
if (c == '\n')
{
/*append_char(c);
current_char = c;
is_new_char = true;*/
free_current_string();
}
}
}
else if (shift_pressed)
else
{
c = (uint16_t) terminal_get_shifted((unsigned char) c);
tty_receive_char(c, flags);
}
/*if (scancode == 0x1C) {
printf("\n");
return;
}*/
if (extended)
if (hook_count > 0)
{
switch (scancode)
{
case 0x48:
c = KEY_ARROW_UP;
break;
case 0x50:
c = KEY_ARROW_DOWN;
break;
case 0x4B:
c = KEY_ARROW_LEFT;
break;
case 0x4D:
c = KEY_ARROW_RIGHT;
break;
default:
c = KEY_NONE;
break;
}
current_key = c;
is_new_key = true;
extended = false;
return;
}
if (c)
{
current_char = c;
is_new_char = true;
if (c == '\n')
{
free_current_string();
}
append_char(c);
call_hooks(c);
}
}
#endif
return regs;
}

88
drivers/serio.c Normal file
View File

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

View File

@ -1,16 +1,42 @@
#include <string.h>
#include <vga/vga.h>
#include <stdio.h>
#include <port_io.h>
#include <new_tty.h>
#include <fs/vfs.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();
}
ssize_t tty_write(struct file* f, const char* buf, size_t size)
{
/*struct tty* tty = (struct tty*)f->private_data;*/
for (size_t i = 0; i < size; i++)
{
/*tty_putchar(tty, buf[i]);*/ /* do this when we have multiple TTY outputs & stuff */
terminal_putchar(buf[i]);
}
return size;
}
void terminal_get_cursor(int* row, int* column)
{
*row = (int) terminal_row;
*column = (int) terminal_column;
}
void terminal_initializec(uint8_t color)
@ -22,11 +48,13 @@ void terminal_initializec(uint8_t color)
{
terminal_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
}
else {
else
{
terminal_color = color;
}
terminal_buffer = VGA_MEMORY;
for (size_t y = 0; y < VGA_HEIGHT; y++)
{
for (size_t x = 0; x < VGA_WIDTH; x++)
@ -55,6 +83,7 @@ void terminal_putentryat(unsigned char c, uint8_t color, size_t x, size_t y)
void terminal_putchar(const char c)
{
unsigned char uc = c;
if (uc == '\n')
@ -62,9 +91,21 @@ void terminal_putchar(const char c)
terminal_column = 0;
if (++terminal_row == VGA_HEIGHT)
{
terminal_scroll();
terminal_row = VGA_HEIGHT - 1;
if (1)
{
terminal_scroll();
terminal_row = VGA_HEIGHT - 1;
}
else
{
terminal_clear();
terminal_row = 0;
}
}
terminal_update_cursor();
return;
}
else if (uc == '\t')
@ -76,28 +117,60 @@ void terminal_putchar(const char c)
terminal_putchar('\n');
}
terminal_update_cursor();
return;
}
/*else if (uc == '\b')
{
if (terminal_column == 0)
{
if (terminal_row > 0)
{
terminal_row--;
terminal_column = VGA_WIDTH - 1;
}
else
{
terminal_update_cursor();
return;
}
}
else
{
terminal_column--;
}
terminal_putentryat(' ', terminal_color, terminal_column, terminal_row);
terminal_update_cursor();
return;
}*/
else if (uc == '\b')
{
if (terminal_column == 0)
{
terminal_row -= 1;
if (terminal_row == (size_t)-1)
if (terminal_row > 0)
{
terminal_row = 0;
terminal_row--;
terminal_column = VGA_WIDTH - 1;
}
else
{
terminal_update_cursor();
terminal_column = VGA_WIDTH;
terminal_putentryat(' ', terminal_getcolor(), (size_t)terminal_column, (size_t)terminal_row);
return;
}
}
else
{
terminal_putentryat(' ', terminal_getcolor(), (size_t)--terminal_column, (size_t)terminal_row);
terminal_column--;
}
terminal_update_cursor();
return;
}
@ -110,9 +183,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)
@ -142,12 +216,15 @@ void terminal_writeline(const char* data)
void terminal_writechar_r(const char ch)
{
unsigned char uch = ch;
size_t saved_row = terminal_row;
size_t saved_col = terminal_column;
for (size_t i = 0; i < VGA_WIDTH; i++)
{
terminal_putchar(uch);
terminal_putentryat(ch, terminal_color, i, saved_row);
}
terminal_set_cursor(saved_row, saved_col);
}
void terminal_clear(void)
@ -163,42 +240,43 @@ void terminal_clearl(size_t num_lines)
}
else
{
/* XXX note to self: VGA_HEIGHT is 25, and VGA_WIDTH is 80 XXX */
/* static size_t terminal_row; static size_t terminal_column; */
terminal_row = VGA_HEIGHT;
terminal_column = 0;
while (terminal_row < num_lines)
if (num_lines > VGA_HEIGHT)
{
for (int32_t k = 0; k < (int32_t)VGA_WIDTH; k++)
{
terminal_putentryat((unsigned char)' ', terminal_getcolor(), (size_t)terminal_row, (size_t)k);
}
terminal_row -= 1;
num_lines = VGA_HEIGHT;
}
size_t start = VGA_HEIGHT - num_lines;
for (size_t y = start; y < VGA_HEIGHT; y++)
{
for (size_t x = 0; x < VGA_WIDTH; x++)
{
terminal_putentryat(' ', terminal_getcolor(), x, y);
}
}
terminal_set_cursor(start, 0);
}
}
void terminal_scroll(void)
{
for (size_t y = 1; y < VGA_HEIGHT; y++)
memmove(
terminal_buffer,
terminal_buffer + VGA_WIDTH,
sizeof(uint16_t) * VGA_WIDTH * (VGA_HEIGHT - 1)
);
terminal_row = VGA_HEIGHT - 1;
for (int32_t x = 0; x < (int32_t)VGA_WIDTH; x++)
{
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];
}
terminal_putentryat(' ', terminal_getcolor(), (size_t)x, (size_t)terminal_row);
}
for (size_t x = 0; x < VGA_WIDTH; x++)
{
const size_t index = (VGA_HEIGHT - 1) * VGA_WIDTH + x;
terminal_buffer[index] = (terminal_color << 8) | ' ';
}
terminal_column = 0;
terminal_update_cursor();
}
unsigned char terminal_get_shifted(unsigned char uc)
{
unsigned char lowerc[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '\0' };
@ -208,7 +286,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 +298,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 +310,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 +329,29 @@ 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));
}
void terminal_putcharat(char c, uint16_t row, uint16_t column)
{
int _r;
int _c;
terminal_get_cursor(&_r, &_c);
terminal_set_cursor(row, column);
terminal_putchar(c);
terminal_set_cursor((uint16_t) _r, (uint16_t) _c);
}

View File

@ -1,10 +1,12 @@
#include <stddef.h>
#include <vga/vga.h>
uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg) {
return fg | bg << 4;
uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg)
{
return fg | bg << 4;
}
uint16_t vga_entry(unsigned char uc, uint8_t color) {
return (uint16_t) uc | (uint16_t) color << 8;
uint16_t vga_entry(unsigned char uc, uint8_t color)
{
return (uint16_t) uc | (uint16_t) color << 8;
}

BIN
espresso.img Normal file

Binary file not shown.

View File

@ -1,4 +1,9 @@
set gfxmode=1024x768x32
set gfxpayload=keep
terminal_output gfxterm
menuentry "Espresso" {
multiboot /boot/espresso.elf
boot
}

15
include/arch/x86/intrin.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef _INTRINSICS_H
#define _INTRINSICS_H
#include <stdint.h>
static inline uint64_t rdtsc(void)
{
uint32_t lo, hi;
asm volatile ("rdtsc" : "=a"(lo), "=d"(hi));
return ((uint64_t) hi << 32) | lo;
}
#endif

16
include/ctype.h Normal file
View File

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

View File

@ -0,0 +1,11 @@
#ifndef ESPRESSO_PC_SPEAKER_H
#define ESPRESSO_PC_SPEAKER_H
#include <stdint.h>
void play_sound(uint32_t nfrequence);
void stop_sound(void);
void beep(void);
#endif

View File

@ -9,37 +9,40 @@
#define PT_LOAD 1
typedef struct {
unsigned char e_ident[EI_NIDENT];
uint16_t e_type;
uint16_t e_machine;
uint32_t e_version;
uint32_t e_entry;
uint32_t e_phoff;
uint32_t e_shoff;
uint32_t e_flags;
uint16_t e_ehsize;
uint16_t e_phentsize;
uint16_t e_phnum;
uint16_t e_shentsize;
uint16_t e_shnum;
uint16_t e_shstrndx;
unsigned char e_ident[EI_NIDENT];
uint16_t e_type;
uint16_t e_machine;
uint32_t e_version;
uint32_t e_entry;
uint32_t e_phoff;
uint32_t e_shoff;
uint32_t e_flags;
uint16_t e_ehsize;
uint16_t e_phentsize;
uint16_t e_phnum;
uint16_t e_shentsize;
uint16_t e_shnum;
uint16_t e_shstrndx;
} Elf32_Ehdr;
typedef struct {
uint32_t p_type;
uint32_t p_offset;
uint32_t p_vaddr;
uint32_t p_paddr;
uint32_t p_filesz;
uint32_t p_memsz;
uint32_t p_flags;
uint32_t p_align;
uint32_t p_type;
uint32_t p_offset;
uint32_t p_vaddr;
uint32_t p_paddr;
uint32_t p_filesz;
uint32_t p_memsz;
uint32_t p_flags;
uint32_t p_align;
} Elf32_Phdr;
//typedef int (*elf_entry_t)(int, char**);
typedef int (*elf_entry_t)(void);
typedef struct {
void* entry_point;
elf_entry_t entry_point;
} elf_executable_t;
elf_executable_t* load_elf32(void* elf_data);
int load_elf32(void* elf_data, elf_executable_t** ptr);
#endif

View File

@ -0,0 +1,26 @@
#ifndef _VGA_GRAPHICS_H
#define _VGA_GRAPHICS_H
#include <types.h>
struct bga_framebuffer
{
volatile uint8_t* addr;
uint32_t width;
uint32_t height;
uint32_t pitch; /* bytes per scanline */
uint32_t bpp;
};
void bga_defaults(void);
void bga_set_video_mode(uint32_t width, uint32_t height, uint32_t bit_depth);
void bga_putpixel(uint32_t x, uint32_t y, uint32_t color);
void bga_drawline(int x0, int y0, int x1, int y1, uint32_t color);
#endif

View File

@ -32,6 +32,9 @@
#define ATA_SR_DRQ 0x08
#define ATA_SR_ERR 0x01
#define SECTOR_SIZE 512
void ide_initialize(void);
int32_t ide_identify(uint8_t drive, uint16_t* buffer);
@ -41,4 +44,6 @@ int32_t ide_write48(uint8_t drive, uint64_t lba, uint8_t sector_count, const voi
int32_t read_sector(uint64_t lba, void* buffer);
int32_t write_sector(uint64_t lba, const void* buffer);
int get_sector_size(uint8_t drive);
#endif

View File

@ -1,13 +1,18 @@
#ifndef _IDT_H
#define _IDT_H
#include <drivers/irq.h>
#include <types.h>
void idt_init(void);
void pic_remap(void);
void idt_set_descriptor(uint8_t vector, void* isr, uint8_t flags);
void exception_dispatcher(uint32_t int_no, uint32_t err_code);
void exception_handler(registers_t* regs);
#endif

View File

@ -3,13 +3,28 @@
#include <types.h>
typedef void (*irq_func_t)(void);
typedef struct {
uint32_t ds, es, fs, gs;
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax;
uint32_t int_no;
uint32_t err_code;
uint32_t eip;
uint32_t cs;
uint32_t eflags;
} registers_t;
typedef registers_t* (*irq_func_t)(registers_t*);
void irq_init(void);
void irq_handler(uint8_t irq_number);
registers_t* irq_handler(uint32_t irq, registers_t* regs);
void set_irq_handler(uint32_t num, irq_func_t* handler);
void add_irq_handler(uint32_t num, irq_func_t* handler);
void set_irq_handler(uint32_t num, irq_func_t handler);
/*void add_irq_handler(uint32_t num, irq_func_t* handler);*/
uint32_t get_interrupts_missed(void);
#endif

View File

@ -0,0 +1,10 @@
#ifndef _KEYBOARD_DRIVER_H
#define _KEYBOARD_DRIVER_H
#include <drivers/irq.h>
int init_keyboard(void);
registers_t* keyboard_handler(registers_t* regs);
#endif

View File

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

View File

@ -3,10 +3,11 @@
#include <types.h>
extern volatile uint64_t pit_ticks;
#include <drivers/irq.h>
void pit_init(void);
void pit_handler(void);
registers_t* pit_handler(registers_t* regs);
void pit_sleep(uint64_t ms);
#endif

View File

@ -2,21 +2,38 @@
#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);
registers_t* ps2_keyboard_handler(registers_t* regs);
void set_use_new_tty(bool t);
char get_char(void);
uint16_t get_key(void);
char* get_string(void);
char* kbd_gets(void);
bool setup_hook(ps2_hook_t func);
bool remove_hook(ps2_hook_t func);
#endif

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

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

78
include/fs/fat16.h Normal file
View File

@ -0,0 +1,78 @@
#ifndef _FAT16_H
#define _FAT16_H
#include <stdint.h>
#include <string.h>
#include <ctype.h>
#define FAT16_MAX_FILENAME 12 /* 8.3 + null */
#define SECTOR_SIZE 512
typedef struct {
uint16_t bytes_per_sector;
uint8_t sectors_per_cluster;
uint16_t reserved_sector_count;
uint8_t num_fats;
uint16_t root_entry_count;
uint16_t total_sectors_16;
uint16_t sectors_per_fat;
uint32_t fat_start_lba;
uint32_t root_dir_lba;
uint32_t data_start_lba;
uint32_t total_sectors;
} fat16_fs_t;
typedef struct {
char name[FAT16_MAX_FILENAME]; /* 8.3 format */
uint8_t attr;
uint16_t first_cluster;
uint32_t size;
} fat16_file_t;
int fat16_mount(uint8_t drive);
int fat16_find_file(const char* name, fat16_file_t* out_file);
int fat16_create_file(const char* name, fat16_file_t* out_file);
int fat16_delete_file(const char* filename);
int fat16_read_file(fat16_file_t* file, void* buffer);
int fat16_write_file(fat16_file_t* file, const void* buffer, uint32_t size);
/*
Small helper function that converts a normal filename like "test.txt" into FAT16 8.3 uppercase format padded with spaces.
This makes creating and writing files much easier.
*/
static void filename_to_83(const char* input, char out[12])
{
memset(out, ' ', 11);
out[11] = '\0';
/* Find dot */
const char* dot = strchr(input, '.');
size_t name_len = dot ? (size_t) (dot - input) : strlen(input);
if (name_len > 8)
{
name_len = 8;
}
for (size_t i = 0; i < name_len; i++)
{
out[i] = toupper((unsigned char)input[i]);
}
if (dot)
{
size_t ext_len = strlen(dot + 1);
if (ext_len > 3) ext_len = 3;
for (size_t i = 0; i < ext_len; i++)
{
out[8 + i] = toupper((unsigned char)dot[1 + i]);
}
}
}
#endif

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

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

View File

@ -4,7 +4,32 @@
#include <types.h>
#define MAX_FDS 64
struct file;
struct inode {
size_t size;
int permissions;
/* | | */
/* \/ FS-specific \/ */
union {
void* fs_data;
void* private_data;
};
};
struct file_ops {
int (*read)(struct file*, char*, size_t);
int (*write)(struct file*, const char*, size_t);
};
struct file {
struct inode* f_inode;
size_t f_offset;
size_t f_refcount;
const struct file_ops* f_ops;
};
#endif

15
include/kdebug.h Normal file
View File

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

View File

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

View File

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

View File

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

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

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

@ -0,0 +1,6 @@
#ifndef _KERNEL_SHELL_H
#define _KERNEL_SHELL_H
void kshell_start(void);
#endif

111
include/kernel/syscall.h Normal file
View File

@ -0,0 +1,111 @@
#ifndef _ESPRESSO_SYSCALL_H
#define _ESPRESSO_SYSCALL_H
#include <drivers/idt.h>
#define SYSCALL_INT 0x30
enum {
SYS_MAP_PAGE = 0, /* void map_page(void* phys_addr, void* virt_addr); */
SYS_PMM_ALLOC_PAGE, /* void* pmm_alloc_page(void); */
SYS_PMM_FREE_PAGE, /* void pmm_free_page(void* addr); */
SYS_SERIAL_WRITE, /* void serial_write(char a); */
SYS_SERIAL_READ, /* char serial_read(void); */
SYS_SERIAL_PUTS, /* void serial_puts(const char* s); */
SYS_USE_SERIAL, /* bool use_serial(void); */
SYS_TERMINAL_SCROLL, /* void terminal_scroll(void); */
SYS_TERMINAL_CLEAR, /* void terminal_clear(void); */
SYS_TERMINAL_SET_CURSOR, /* void terminal_set_cursor(uint16_t row, uint16_t column); */
SYS_TERMINAL_GET_CURSOR, /* void terminal_get_cursor(int* row, int* column); */
SYS_TERMINAL_WRITE, /* void terminal_write(const char* data, size_t size); */
SYS_TERMINAL_WRITESTRING, /* void terminal_writestring(const char* data) */
SYS_TERMINAL_DEBUG_WRITESTRING, /* void terminal_debug_writestring(const char* data); */
SYS_TERMINAL_PUTCHAR, /* void terminal_putchar(char c); */
SYS_TERMINAL_PUTENTRYAT, /* void terminal_putentryat(unsigned char c, uint8_t color, size_t x, size_t y); */
SYS_TERMINAL_GETCOLOR, /* uint8_t terminal_getcolor(void); */
SYS_TERMINAL_SETCOLOR, /* void terminal_setcolor(uint8_t color); */
SYS_READ, /* int read(uint32_t fd, void* data, size_t max_len); */
SYS_WRITE, /* int write(uint32_t fd, void* data, size_t len); */
__ENUM_END_MARKER__,
};
#define syscall0(num) ({ \
int ret; \
asm volatile ( \
"int %1" \
: "=a"(ret) \
: "i"(SYSCALL_INT), "a"(num) \
: "memory" \
); \
ret; \
})
/* syscall 1 */
#define syscall1(num, a) ({ \
int ret; \
asm volatile ( \
"int %1" \
: "=a"(ret) \
: "i"(SYSCALL_INT), "a"(num), "b"(a) \
: "memory" \
); \
ret; \
})
#define syscall2(num, a, b) ({ \
int ret; \
asm volatile ( \
"int %1" \
: "=a"(ret) \
: "i"(SYSCALL_INT), "a"(num), "b"(a), "c"(b) \
: "memory" \
); \
ret; \
})
#define syscall3(num, a, b, c) ({ \
int ret; \
asm volatile ( \
"int %1" \
: "=a"(ret) \
: "i"(SYSCALL_INT), "a"(num), "b"(a), "c"(b), "d"(c) \
: "memory" \
); \
ret; \
})
#define syscall4(num, a, b, c, d) ({ \
int ret; \
asm volatile ( \
"int %1" \
: "=a"(ret) \
: "i"(SYSCALL_INT), "a"(num), "b"(a), "c"(b), "d"(c), "S"(d) \
: "memory" \
); \
ret; \
})
#define syscall5(num, a, b, c, d, e) ({ \
int ret; \
asm volatile ( \
"int %1" \
: "=a"(ret) \
: "i"(SYSCALL_INT), "a"(num), "b"(a), "c"(b), "d"(c), "S"(d), "D"(e) \
: "memory" \
); \
ret; \
})
/* some macros for commonly used functions */
#define syscall_terminal_writestring(ptr) syscall1(SYS_TERMINAL_WRITESTRING, ptr);
#define syscall_terminal_putchar(chr) syscall1(SYS_TERMINAL_PUTCHAR, chr);
#define syscall_map_page(phys, virt) syscall2(SYS_MAP_PAGE, phys, virt);
#define syscall_pmm_alloc_page() syscall0(SYS_PMM_ALLOC_PAGE);
#define syscall_pmm_free_page(addr) syscall1(SYS_PMM_FREE_PAGE, addr);
void init_sysints(void);
registers_t* int16_handler(registers_t* regs);
#endif

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

@ -0,0 +1,9 @@
#ifndef _KERNEL_VARIABLES_H
#define _KERNEL_VARIABLES_H
#define KERNEL_VARIABLES_SIZE 4096 /* in bytes (note: it take up a whole page, yes.) */
void init_vars(void);
#endif

View File

@ -1,6 +1,32 @@
#ifndef _KERNEL_INCLUDES_H
#define _KERNEL_INCLUDES_H
#define KERNEL_VERSION "0.0.1e"
#define ESPRESSO_KERNEL_
#define KERNEL_VERSION "0.0.2c"
#define KERNEL_RELEASE_YEAR "2026"
#define _STATE_NORMAL 0
#define _STATE_HANDLED 1
#define _STATE_INTERRUPT -1
#define _STATE_EXCEPTION -2
#define _STATE_CRASH -555
#define __always_inline inline __attribute__((always_inline))
#define __hot __attribute__((hot))
#define __cold __attribute__((cold))
#define __noreturn __attribute__((noreturn))
#define __section(x) __attribute__((section(x)))
#define __noreturn __attribute__((noreturn))
extern void _cli_asm(void);
extern void _sti_asm(void);
#define IRQ_DISABLE() _cli_asm();
#define IRQ_ENABLE() _sti_asm();
//#define DEBUG_USE_SSE2
#endif

View File

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

19
include/math.h Normal file
View File

@ -0,0 +1,19 @@
#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;
}
int abs(int x);
#endif

15
include/math/random.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef _RANDOM_H
#define _RANDOM_H
#include <types.h>
void seed_rand(uint32_t seed);
uint32_t uirand(void); /* 32 bits / 4 bytes */
uint64_t ulrand(void); /* 64 bits / 8 bytes */
/* get a number between 0 and max-1 */
uint32_t uirand_range(uint32_t max);
uint64_t ulrand_range(uint64_t max);
#endif

View File

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

View File

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

View File

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

12
include/mm_macros.h Normal file
View File

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

93
include/new_tty.h Normal file
View File

@ -0,0 +1,93 @@
#ifndef _TTY_H
#define _TTY_H
#include <types.h>
#include <fs/vfs.h>
#include <processes.h>
#include <sync.h>
#define TTY_BUFFER_SIZE 4096
#define TTY_RAW_BUFFER_SIZE 16
#define MAX_TTYS 8 /* to make things easy, might change later */
#define TTY_ECHO 0x10 /* 0b00010000 */
#define TTY_PASSWORD 0x20 /* 0b00100000 */
#define TTY_ACTIVE 0x01 /* 0b00000001 */
#define TTY_CANONICAL 0x40 /* 0b01000000 */
#define TTY_RAW 0x04 /* 0b00000100 */
#define TTY_ADDCHAR_ALWAYS 0x02 /* 0b00000010 */
#define TTY_NULL 0x80 /* 0b10000000 --- used to end the list of tty_t structs in the ttys array */
#define TTY_NORMAL TTY_ECHO | TTY_ACTIVE | TTY_CANONICAL
#define MODIFIER_CAPS 0x01 /* 0b00000001 */
#define MODIFIER_CAPS_DESTROY 0b11111110
#define MODIFIER_SHIFT 0x02 /* 0b00000010 */
#define MODIFIER_SHIFT_DESTROY 0b11111101
#define MODIFIER_ALT 0x04 /* 0b00000100 */
#define MODIFIER_ALT_DESTROY 0b11111011
#define MODIFIER_LCTRL 0x10 /* 0b00010000 */
#define MODIFIER_LCTRL_DESTROY 0b11101111
#define MODIFIER_RCTRL 0x0 /* 0b00100000*/
#define MODIFIER_RCTRL_DESTROY 0b11011111
typedef struct tty_t {
char input_buffer[TTY_BUFFER_SIZE];
size_t head;
size_t tail;
uint32_t flags;
bool canonical;
bool line_ready;
/* for raw mode */
char raw_buf[TTY_RAW_BUFFER_SIZE];
size_t raw_head;
size_t raw_tail;
spinlock_t lock;
size_t user_input_start;
size_t user_input_end;
struct file_ops f_ops;
pid_t foreground_pgid; /* not used yet */
} tty_t;
/* essentially, key is non-zero if a key like the up arrow is pressed, otherwise c is the char that was entered */
struct keyevent {
uint8_t key;
char c;
};
int init_tty(void);
ssize_t tty_read(tty_t* tty, char* buf, size_t count);
ssize_t tty_read_active(char* buf, size_t count);
char tty_get_char(void);
tty_t* get_active_tty(void);
tty_t* tty_get_active(void);
void tty_and_flags(tty_t* tty, uint32_t flags);
uint32_t tty_get_flags(tty_t* tty);
tty_t* make_tty(uint32_t flags);
void tty_receive_char(char c, uint32_t kbd_mod);
char tty_translate_char(char c, uint32_t modifiers);
void tty_input_char(tty_t* tty, char c);
#endif

View File

@ -10,12 +10,24 @@ static inline uint32_t inl(uint16_t port)
return rv;
}
static inline void outl(uint16_t port, uint32_t data)
static inline uint16_t inw(uint16_t port)
{
uint16_t rv;
asm volatile ("inw %%dx, %%ax" : "=a" (rv) : "dN" (port));
return rv;
}
static inline __attribute__((always_inline)) void outl(uint16_t port, uint32_t data)
{
asm volatile ("outl %%eax, %%dx" : : "dN" (port), "a" (data));
}
static inline void outb(uint16_t port, uint8_t val)
static inline __attribute__((always_inline)) void outw(uint16_t port, uint16_t val)
{
asm volatile ( "outw %0, %1" : : "a"(val), "Nd"(port) : "memory");
}
static inline __attribute__((always_inline)) void outb(uint16_t port, uint8_t val)
{
asm volatile ( "outb %0, %1" : : "a"(val), "Nd"(port) : "memory");
}
@ -30,17 +42,19 @@ static inline uint8_t inb(uint16_t port)
return ret;
}
static inline void io_wait()
static inline __attribute__((always_inline)) void io_wait()
{
outb(0x80, 0);
}
static inline void insw(uint16_t port, void* addr, uint32_t count) {
__asm__ volatile ("rep insw" : "+D"(addr), "+c"(count) : "d"(port) : "memory");
static inline __attribute__((always_inline)) void insw(uint16_t port, void* addr, uint32_t count)
{
asm volatile ("rep insw" : "+D"(addr), "+c"(count) : "d"(port) : "memory");
}
static inline void outsw(uint16_t port, const void* addr, uint32_t count) {
__asm__ volatile ("rep outsw" : "+S"(addr), "+c"(count) : "d"(port));
static inline __attribute__((always_inline)) void outsw(uint16_t port, const void* addr, uint32_t count)
{
asm volatile ("rep outsw" : "+S"(addr), "+c"(count) : "d"(port));
}
#endif

View File

@ -1,10 +1,10 @@
#ifndef _PRINTF_H
#define _PRINTF_H
#include <tty.h>
//#include <tty.h>
#include <string.h>
#include <vga/vga.h> /* Only for the vga_color enum */
//#include <vga/vga.h> /* Only for the vga_color enum */
void printwc(const char*, uint8_t);
@ -12,9 +12,13 @@ void printd(const char* str);
void printf(const char*, ...);
void print_int(int32_t value);
void print_lint(int64_t value);
void print_uint(uint32_t value);
void print_luint(uint64_t value);
void print_hex(uint32_t value, int width, bool uppercase);
void print_hex64(uint64_t value, int width, bool uppercase);
void print_double(double value, int precision);
void printf_set_color(uint8_t _color);
#endif

View File

@ -5,15 +5,17 @@
#include <drivers/elf.h>
typedef uint32_t pid_t;
typedef struct process {
int32_t id;
int32_t group;
pid_t id;
pid_t group;
elf_executable_t* exe;
struct process* next;
} process_t;
int32_t make_process(char* name, char* group, elf_executable_t* exe);
pid_t make_process(char* name, char* group, elf_executable_t* exe);
#endif

21
include/scheduler.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef _SCHEDULER_H
#define _SCHEDULER_H
#include <drivers/irq.h>
#include <types.h>
typedef struct task {
registers_t* regs; /* saved interrupt frame */
uint32_t id;
struct task* next;
} task_t;
void init_scheduler(void);
registers_t* schedule(registers_t* regs);
task_t* create_task(void (*entry)());
#endif

View File

@ -4,7 +4,26 @@
#include <types.h>
#include <printf.h>
#define STDIN 0
#define STDOUT 1
#define STDERR 2
int read(uint32_t fd, void* data, size_t max_len);
int write(uint32_t fd, void* data, size_t len);
char getchar(void);
char* getstring(void);
char* gets(void); /* Use this instead of getstring() */
int getstr(char* dest);
char* gets_new(int* num);
void putc(char c);
static inline void putchar(char c)
{
printf("%c", c);
}
#endif

View File

@ -2,6 +2,7 @@
#define STRING_H
#include <types.h>
#include <ctype.h>
/* TODO: change all applicable `int32_t`s with `size_t`s. */
@ -16,18 +17,24 @@ 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);
/* these functions are NOT in the standard C library */
int num_strchr(const char* s, int c);
char* strnlstrip(const char* __s);
void strlnstripip(char* s);
char** split(const char* str, char delim);
void free_split(char** parts);
#endif

14
include/sync.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef _SYNC_H
#define _SYNC_H
typedef struct {
volatile int locked;
} spinlock_t;
void spinlock_init(spinlock_t* lock);
void spin_lock(spinlock_t* lock);
void spin_unlock(spinlock_t* lock);
#endif

View File

@ -1,5 +1,5 @@
#ifndef _TTY_H
#define _TTY_H
#ifndef TTY_H
#define TTY_H
#include <types.h>
@ -16,6 +16,9 @@ void terminal_write(const char* data, size_t size);
void terminal_writestring(const char* data);
void terminal_debug_writestring(const char* data);
void terminal_writeline(const char* data);
void terminal_writechar_r(const char ch);
void terminal_setcolor(uint8_t color);
uint8_t terminal_getcolor(void);
@ -26,5 +29,10 @@ void terminal_scroll(void);
unsigned char terminal_get_shifted(unsigned char uc);
void terminal_set_cursor(uint16_t row, uint16_t column);
void terminal_get_cursor(int* row, int* column);
void terminal_update_cursor(void);
void terminal_putcharat(char c, uint16_t row, uint16_t column);
#endif

View File

@ -5,6 +5,11 @@
#include <stddef.h>
#include <stdbool.h>
#define ARG64_LO(x) ((uint32_t)(x))
#define ARG64_HI(x) ((uint32_t)((x) >> 32))
#define TOGGLE_BIT(x, bit) ((x) ^= (1U << (bit)))
typedef unsigned char uchar;
typedef uint8_t u8;
@ -12,4 +17,19 @@ typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t i8;
typedef int16_t i16;
typedef int32_t i32;
typedef int64_t i64;
/* this might not be POSIX compatable. */
typedef uint32_t size_t;
typedef int32_t ssize_t;
#if 0
#if sizeof(size_t) != sizeof(ssize_t)
#error "size_t is a different size than ssize_t"
#endif
#endif
#endif

View File

@ -21,7 +21,7 @@ void *sse2_memcpy(void *dst, const void *src, uint32_t n);
void double_vector_to_int_vector(const double *src, int32_t *dst);
void int_vector_to_double_vector(const int32_t *src, double *dst);
void *memclr_sse2(const void *const m_start, const size_t m_count);
void* memclr_sse2(void *m_start, size_t m_count);
#endif

View File

@ -5,22 +5,22 @@
/* Hardware text mode color constants. */
enum vga_color {
VGA_COLOR_BLACK = 0,
VGA_COLOR_BLUE = 1,
VGA_COLOR_GREEN = 2,
VGA_COLOR_CYAN = 3,
VGA_COLOR_RED = 4,
VGA_COLOR_MAGENTA = 5,
VGA_COLOR_BROWN = 6,
VGA_COLOR_LIGHT_GREY = 7,
VGA_COLOR_DARK_GREY = 8,
VGA_COLOR_LIGHT_BLUE = 9,
VGA_COLOR_LIGHT_GREEN = 10,
VGA_COLOR_LIGHT_CYAN = 11,
VGA_COLOR_LIGHT_RED = 12,
VGA_COLOR_LIGHT_MAGENTA = 13,
VGA_COLOR_LIGHT_BROWN = 14,
VGA_COLOR_WHITE = 15,
VGA_COLOR_BLACK = 0,
VGA_COLOR_BLUE = 1,
VGA_COLOR_GREEN = 2,
VGA_COLOR_CYAN = 3,
VGA_COLOR_RED = 4,
VGA_COLOR_MAGENTA = 5,
VGA_COLOR_BROWN = 6,
VGA_COLOR_LIGHT_GREY = 7,
VGA_COLOR_DARK_GREY = 8,
VGA_COLOR_LIGHT_BLUE = 9,
VGA_COLOR_LIGHT_GREEN = 10,
VGA_COLOR_LIGHT_CYAN = 11,
VGA_COLOR_LIGHT_RED = 12,
VGA_COLOR_LIGHT_MAGENTA = 13,
VGA_COLOR_LIGHT_BROWN = 14,
VGA_COLOR_WHITE = 15,
};
uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg);

View File

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

View File

@ -1,19 +1,28 @@
#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)
{
char* fin = (char*) malloc(strlen(KERNEL_VERSION) + 6);
memset(fin, 0, (strlen(KERNEL_VERSION) + 5));
strcpy(fin, KERNEL_VERSION);
#ifdef _DEBUG
strcat(fin, " DEBUG");
#endif
begin_anim(fin);
}
int16_t begin_anim(const char* version)
{
@ -31,11 +40,18 @@ int16_t begin_anim(const char* version)
int16_t b = 0;
int32_t sh_pos = VGA_WIDTH / 2;
int32_t sv_pos = VGA_HEIGHT / 2;
setup_hook((ps2_hook_t) ack_char);
while (true)
{
terminal_clear();
if (char_entered != 0)
{
break;
}
for (int32_t i = 0; n[i]; ++i)
{
terminal_putentryat(n[i], terminal_getcolor(), sh_pos, sv_pos);
@ -64,11 +80,35 @@ int16_t begin_anim(const char* version)
b = 0;
delay_us(50000, 5000);
sleep(1000);
}
if (char_entered != 0)
{
start_kernel_shell();
}
else
{
terminal_clear();
}
terminal_clear();
return 0;
}
void ack_char(char c)
{
char_entered = c;
return;
}
void start_kernel_shell(void)
{
/* terminal_clear() already called by begin_anim() */
extern int kshell_start(int argc, char** argv);
kshell_start(0, NULL);
return;
}

25
kernel/kdebug.c Normal file
View File

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

View File

@ -11,61 +11,67 @@
#include <types.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <kernel/boot.h>
#include <panic.h>
#include <kernel/kshell.h>
#include <kernel/syscall.h>
#include <tty.h>
#include <vga/vga.h>
#include <new_tty.h>
#include <kdebug.h>
#include <gdt.h>
#include <drivers/idt.h>
#include <drivers/irq.h>
#include <scheduler.h>
#include <multiboot.h>
#include <stdio.h>
#include <drivers/pci.h>
#include <drivers/ps2_keyboard.h>
#include <drivers/keyboard.h>
#include <drivers/pit.h>
#include <drivers/graphics/vga.h>
/*#include <drivers/ahci.h>*/
#include <drivers/ide.h>
#include <mm/mm.h>
#include <fs/fat32.h>
#include <fs/duckfs.h>
/*#include <fs/duckfs.h>*/
#include <fs/vfs.h>
#include <fs/sfs.h>
#ifdef DEBUG_USE_SSE2
#include <vector_extensions/sse.h>
#endif
#include <kernel/intro.h>
#include <builtin_games/miner.h>
#define DEBUG
extern void _hang_asm(void);
extern void _sti_asm(void);
char* espresso_str = ""
"####### ##### ###### ###### ####### ##### ##### #######\n"
"# # # # # # # # # # # # # #\n"
"# # # # # # # # # # #\n"
"##### ##### ###### ###### ##### ##### ##### # #\n"
"# # # # # # # # # #\n"
"# # # # # # # # # # # # #\n"
"####### ##### # # # ####### ##### ##### #######\n";
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,89 +91,80 @@ void kernel_main(multiboot_info_t* mbd, uint32_t magic)
gdt_install(false);
pic_remap();
pic_remap(); /* must be done before idt_init() */
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);
#ifdef DEBUG_USE_SSE2
#ifdef _DEBUG
printd("Testing SSE...\n");
#endif
int32_t sse_test_result = test_sse();
if (sse_test_result != 0)
{
printf("[ DEBUG ] SSE test failed with RV %d\n", sse_test_result);
printf("[ SSE ] SSE test failed with RV %d\n", sse_test_result);
}
else
{
#ifdef _DEBUG
printd("SSE test passed\n");
#endif
}
#endif
pit_init();
int j = init_tty();
if (j != 0)
{
printwc("[ ERROR ] init_tty failed\n", VGA_COLOR_RED);
while (1)
{
asm volatile ("nop" ::: "memory");
}
}
printd("Initializing the PIT...\n");
pit_init();
printd("PIT initialized\n");
//keyboard_init();
init_keyboard();
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();
init_sysints();
/*init_scheduler();*/
_sti_asm();
/* --- END INITIALIZATION SECTION --- */
terminal_setcolor(VGA_COLOR_LIGHT_GREEN);
printf("Guten tag and welcome to Espresso %s\n", KERNEL_VERSION);
/*pit_sleep(4000);
begin_anim(espresso_kernel_version);*/
extern void terminal_clear(void);
//bga_defaults();
printf("Guten tag and welcome to Espresso %s\n", espresso_kernel_version);
printf("%s\n", espresso_str);
char buffer[512] = { 0 };
int32_t i = sfs_read_file("test.txt", buffer, -1);
terminal_clear();
printf("%i\n", i);
kshell_start();
if (i == 0)
for(;;) /* Loop infinitely. We only do something when an interrupt/syscall happens now. */
{
printf("%s\n", buffer);
}
while (true)
{
/* Loop infinitely. We only do something when a syscall happens now. */
asm volatile("hlt" ::: "memory");
}
}

54
kernel/ksh_debug.c Normal file
View File

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

576
kernel/kshell.c Normal file
View File

@ -0,0 +1,576 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <drivers/ps2_keyboard.h>
#include <tty.h>
#include <kernel/ksh_debug.h>
#include <arch/x86/intrin.h>
#include <drivers/elf.h>
#include <kernel/syscall.h>
#include <scheduler.h>
#include <fs/fat16.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 = 1;
execute();
extern char* get_cpu_vendor_string(void);
extern char* get_cpu_brand_string(void);
/* XXX: NOTE: these do not need freeing. */
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_);
printf("\nCopyright %s David J Goeke\n", KERNEL_RELEASE_YEAR);
}
static char* commands[] = {
"kinfo",
"sseinfo",
"kernelmem",
"sectionmem",
"enable_debug",
"disable_debug",
"toggle_debug",
"get_debug",
"dumpregs",
"dumpgprs",
"testascii",
"printrandom",
"testfat16",
"printc",
"testscheduler",
"readfat16",
"help",
"exec",
"int16test",
"startbga",
NULL,
};
const int NUM_COMMANDS = 21; /* Yes, including the NULL */
void kshell_start(void)
{
printf("Welcome to the kshell!\n");
prompt = strdup(">");
char* i = NULL;
print_intro();
command = -1;
do
{
printf("%s ", prompt);
/*i = gets();*/
int j = 0;
i = gets_new(&j);
if (j == 0)
{
printf("Error?\n");
break;
}
i = strnlstrip(i);
command = -1;
if (strlen(i) == 0)
{
continue;
}
else if (strcmp(i, "exit") == 0 || strcmp(i, "quit") == 0)
{
break;
}
/*char** argv = split(i, ' ');*/
for (int j = 0; j < NUM_COMMANDS; j++)
{
if (strcmp(i, commands[j]) == 0)
{
command = j;
break;
}
}
if (command == -1)
{
printf("Unknown command %s len %i\n", i, strlen(i));
}
else if (command == 4)
{
_debug = true;
}
else if (command == 5)
{
_debug = false;
}
else if (command == 6)
{
_debug = !_debug;
}
else if (command == 7)
{
printf("Debugging: %s\n", _debug == true ? "On" : "Off");
}
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");
printf("C: %s; %i\n", commands[command], command);
}
execute();
} while (1);
if (i)
{
free(i);
}
printf("Goodbye!\n");
return;
}
/*
static char* commands[] = {
"kinfo",
"sseinfo",
"kernelmem",
"sectionmem",
"enable_debug",
"disable_debug",
"toggle_debug",
"get_debug",
"dumpregs",
"dumpgprs",
"testascii",
"printrandom",
"testfat16",
NULL,
};
*/
int execute(void)
{
switch (command)
{
case 0: {
printf("Espresso %s ", KERNEL_VERSION);
#ifdef _DEBUG
printf("DEBUG BUILD");
#endif
printf("\n");
break;
}
case 1: {
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 2: {
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: %p\n", (&__kernel_start));
printf("Kernel end: %p\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 3: {
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 8: {
print_all_regs();
break;
}
case 9: {
print_gprs();
break;
}
case 10: {
/*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("\n\n\\/ Cool ASCII art \\/\n%c%c\n%c%c\n", 0xDA, 0xBF, 0xC0, 0xD9);
gets();
break;
}
case 11: {
extern void seed_rand(uint32_t seed);
extern uint32_t ulrand(void);
uint64_t v = rdtsc();
seed_rand((uint32_t) v);
printf("%ull\n", ulrand());
break;
}
case 12: {
int retv = fat16_mount(0);
if (retv != 0)
{
printf("There was an error while mounting volume 0.\n");
break;
}
printf("Volume 0 mounted successfully.\n");
char fat_name[12];
fat16_file_t file;
filename_to_83("test.txt", fat_name);
retv = fat16_create_file(fat_name, &file);
if (retv != 0)
{
printf("There was an error while creating a file on volume 0.\n");
break;
}
uint8_t buf[512];
memset(buf, 0, sizeof(buf));
strcpy((char*) buf, "fg");
retv = fat16_write_file(&file, buf, (strlen((char*) buf)));
if (retv != 0)
{
printf("There was an error while writing to a file on volume 0.\n");
break;
}
uint8_t rbuf[512];
memset(rbuf, 0, sizeof(rbuf));
retv = fat16_read_file(&file, rbuf);
if (retv != 0)
{
printf("There was an error while reading from a file on volume 0.\n");
break;
}
printf("The data read should be: %s\n", (char*) buf);
printf("Read data: %s\n", (char*) rbuf);
printf("Deleting test file\n");
fat16_delete_file(fat_name);
break;
}
case 13:
{
printf("Enter char to print in decimal: ");
char* g = gets();
int val = atoi(g);
if (*g == '\0')
{
printf("Empty string entered\n");
break;
}
printf("%c\n", (char) val);
break;
}
case 14:
{
#if 1
void taskA() { while (1) printf("A"); }
void taskB() { while (1) printf("B"); }
create_task(taskA);
create_task(taskB);
#endif
break;
}
case 15:
{
char* filename = "t.bin";
int retv = fat16_mount(0);
if (retv != 0)
{
printf("There was an error while mounting volume 0.\n");
break;
}
printf("Volume 0 mounted successfully.\n");
char fat_name[12];
fat16_file_t file;
filename_to_83(filename, fat_name);
retv = fat16_find_file(fat_name, &file);
if (retv != 0)
{
printf("file %s could not be found\n", filename);
break;
}
uint8_t buffer[256];
memset(buffer, 0, sizeof(buffer));
retv = fat16_read_file(&file, buffer);
if (retv != 0)
{
printf("Could not read file s\n", (char*) filename);
break;
}
printf("read data: %s\n", (char*) buffer);
break;
}
case 16:
{
printf("Commands:\n");
for (int i = 0; i < NUM_COMMANDS; i++)
{
printf("%s\n", commands[i]);
}
break;
}
case 17:
{
char* filename = "hello.elf";
printf("Loading and executing file %s\n", filename);
int retv = fat16_mount(0);
if (retv != 0)
{
printf("There was an error while mounting volume 0.\n");
break;
}
printf("Volume 0 mounted successfully.\n");
char fat_name[12];
fat16_file_t file;
filename_to_83(filename, fat_name);
retv = fat16_find_file(fat_name, &file);
if (retv != 0)
{
printf("file %s could not be found\n", filename);
break;
}
uint8_t* buffer = malloc(file.size);
memset(buffer, 0, file.size);
retv = fat16_read_file(&file, buffer);
if (retv != 0)
{
printf("Could not read file s\n", (char*) filename);
break;
}
printf("Parsing ELF headers\n");
elf_executable_t* f = NULL;
int j = load_elf32(buffer, &f);
if (j != 0)
{
printf("Invalid ELF file\n");
goto b_1;
}
printf("Attempting execution of executable at (%p)...\n", f->entry_point);
retv = f->entry_point();
printf("\nreturn value: %i\n", retv);
b_1:
if (f)
{
free(f);
}
break;
}
case 18:
{
printf("testing int 16\n");
const char* str = "HELLO!\n";
syscall1(SYS_TERMINAL_WRITESTRING, str);
printf("test ran\n");
break;
}
case 19:
{
extern void bga_defaults(void);
bga_defaults();
extern void bga_drawline(int, int, int, int, uint32_t);
bga_drawline(0, 0, 100, 100, 0x00FFFF00);
break;
}
}
return 0;
}

118
kernel/syscall.c Normal file
View File

@ -0,0 +1,118 @@
#include <stdio.h>
#include <drivers/irq.h>
#include <mm/pmm.h>
#include <mm/paging.h>
#include <tty.h>
#include <drivers/serio.h>
#include <kernel/syscall.h>
/*
Espresso has two types of syscalls.
one: int 16, the only one I've worked on. should be able to be used in kernel code and user-space.
two: syscall/sysenter, the ones I haven't worked on because it has to do with userspace code.
*/
/*
NOTE: passing arguments to fuctions
to pass args to functions, use all registers except eax,
so ebx is arg0, ecx arg1, edx arg2, esi arg3, edi arg4, ebp arg5
*/
void init_sysints(void)
{
/* actually nothing to do */
set_irq_handler(16, (irq_func_t) int16_handler);
}
/* 0 in eax means success most of the time */
registers_t* int16_handler(registers_t* regs)
{
//printf("eax: %0x%x\n", regs->eax);
uint32_t eax = regs->eax;
if (eax >= __ENUM_END_MARKER__)
{
printf("Invalid system call %i\n", eax);
return regs;
}
switch (eax)
{
case SYS_MAP_PAGE:
map_page((void*) regs->ebx, (void*) regs->ecx);
break;
case SYS_PMM_ALLOC_PAGE:
eax = (uint32_t) pmm_alloc_page();
break;
case SYS_PMM_FREE_PAGE:
pmm_free_page((void*) regs->ebx);
break;
case SYS_SERIAL_WRITE:
serial_write(regs->ebx);
break;
case SYS_SERIAL_READ:
eax = serial_read();
break;
case SYS_SERIAL_PUTS:
serial_puts((const char*) regs->ebx);
break;
case SYS_USE_SERIAL:
eax = use_serial();
break;
case SYS_TERMINAL_SCROLL:
terminal_scroll();
break;
case SYS_TERMINAL_CLEAR:
terminal_clear();
break;
case SYS_TERMINAL_SET_CURSOR:
terminal_set_cursor(regs->ebx, regs->ecx);
break;
case SYS_TERMINAL_GET_CURSOR:
terminal_get_cursor((int*) regs->ebx, (int*) regs->ecx);
break;
case SYS_TERMINAL_WRITE:
terminal_write((const char*) regs->ebx, regs->ecx);
break;
case SYS_TERMINAL_WRITESTRING:
terminal_writestring((const char*) regs->ebx);
break;
case SYS_TERMINAL_DEBUG_WRITESTRING:
terminal_debug_writestring((const char*) regs->ebx);
break;
case SYS_TERMINAL_PUTCHAR:
terminal_putchar(regs->ebx);
break;
case SYS_TERMINAL_PUTENTRYAT:
terminal_putentryat(regs->ebx, regs->ecx, regs->edx, regs->esi);
break;
case SYS_TERMINAL_GETCOLOR:
eax = terminal_getcolor();
break;
case SYS_TERMINAL_SETCOLOR:
terminal_setcolor(regs->ebx);
break;
case SYS_READ:
eax = read(regs->ebx, (void*) regs->ecx, regs->edx);
break;
case SYS_WRITE:
eax = write(regs->ebx, (void*) regs->ecx, regs->edx);
break;
default:
printf("nothing happened.\n");
break;
}
regs->eax = eax;
return regs;
}

25
kernel/vars.c Normal file
View File

@ -0,0 +1,25 @@
#include <types.h>
#include <string.h>
#include <stdlib.h>
#include <kernel/vars.h>
/*
Number of bytes in kernel variable space: 4096 (4KiB)
Number of bits in kernel variable space: 32768 (32Mib)
*/
uint8_t vars[KERNEL_VARIABLES_SIZE];
void init_vars(void)
{
memset(vars, 0, KERNEL_VARIABLES_SIZE);
}
/* bo = bit offset */
void set_bit_bo(uint32_t offset, uint8_t val)
{
/* First, extract the byte offset. (round down to a multiple of 8, and divide by 8. */
(void) offset;
(void) val;
}

View File

@ -2,75 +2,230 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <drivers/ps2_keyboard.h>
#include <new_tty.h>
#include <builtin_games/miner.h>
#define PLAYER '@'
#define SHOP '$'
#define STONE '#'
#define IRON ';'
#define COAL ':'
#define COPPER '^'
#define GOLD '%'
#define RUBY '*'
#define DIAMOND '~'
#define PLATINUM '&'
#define NOTHING ' '
/*
static const size_t VGA_WIDTH = 80;
static const size_t VGA_HEIGHT = 25;
*/
/* clear screen */
void cls(void)
{
terminal_clear();
}
static bool pointer_valid(void* ptr)
{
if (ptr/* && (ptr < (heap_end + 4096))*/)
{
return true;
}
return false;
}
static inline bool valid_pointer(void* ptr)
{
return pointer_valid(ptr);
}
/*const char PLAYER = '@';
const char ENEMY = '*';
const char PLAYER_BULLET = '^';
const char ENEMY_BULLET = '`'
const char BOMB = '*';
const char EMPTY = ' ';*/
#define MAP_ROWS 25
#define MAP_COLUMNS 25
#define PLAYER_STARTING_POS (MAP_COLUMNS / 2) /* for MAP_COLUMNS being 25, this will be 12. */
#define STARTING_ENEMY_NUM 4
enum {
PLAYER = '@',
PLAYER_BULLET = '^',
ENEMY = '%',
ENEMY_BULLET = '`',
BOMB = '*',
EMPTY = ' ',
};
struct bullet {
bool players; /* if enemies, false */
int row;
int column;
};
struct game_vars {
tty_t* tty;
uint32_t stored_tty_flags;
int v;
char c;
int player_score;
int player_credits;
bool error;
int num_enemies;
int num_enemy_step;
char** map; /* char map[MAP_ROWS][MAP_COLUMNS] */
bool enemys[MAP_COLUMNS]; /* enemy bitmap */
struct bullet* bullets;
int num_bullets;
};
void init_map(struct game_vars* gv)
{
for (int i = 0; i < MAP_ROWS; i++)
{
for (int j = 0; j < MAP_COLUMNS; j++)
{
gv->map[i][j] = EMPTY;
}
}
gv->map[0][PLAYER_STARTING_POS] = PLAYER;
int enemy_pos = 0;
for (int b = 0; b < STARTING_ENEMY_NUM; b++)
{
gv->map[24][enemy_pos] = ENEMY;
enemy_pos++;
gv->num_enemies++;
gv->enemys[b] = true;
}
if (!valid_pointer(gv->map))
{
gv->error = true;
}
}
void ai(struct game_vars* gv)
{
for (int i = 0; i < MAP_COLUMNS; i++)
{
if ((gv->map[24][i] == ENEMY) && (gv->map[0][i] == PLAYER))
{
gv->map[23][i] = ENEMY_BULLET;
int num_bullets = gv->num_bullets;
gv->bullets[num_bullets].players = false;
gv->bullets[num_bullets].column = i;
gv->bullets[num_bullets].row = 23;
gv->num_bullets++;
}
}
}
void tick(struct game_vars* gv)
{
for (int i = 0; i < gv->num_bullets; i++)
{
struct bullet* b = &gv->bullets[i];
gv->map[b->row][b->column] = EMPTY;
b->column++;
b->row++;
gv->map[b->row][b->column] = b->players ? PLAYER_BULLET : ENEMY_BULLET;
}
}
int init_game(struct game_vars* ptr)
{
if (ptr)
{
ptr->error = false;
init_map(ptr);
ptr->num_enemy_step++;
return 0;
}
return -1;
}
void miner_main(void)
{
terminal_clear();
#if 0
cls();
struct game_vars gv = { .tty = get_active_tty(), .stored_tty_flags = tty_get_flags(get_active_tty()),
.v = 0, .c = 0,
.player_score = 0, .player_credits = 0,
.error = false,
.num_enemies = STARTING_ENEMY_NUM, .num_enemy_step = 0,
.map = malloc(MAP_COLUMNS * MAP_ROWS),
.bullets = NULL, .num_bullets = 0,
};
memset(gv.enemys, 0, sizeof(gv.enemys));
if (!gv.map)
{
goto quit;
}
printf("gv.map = %p\n", gv.map);
gv.tty->flags |= TTY_RAW;
gv.tty->flags &= ~TTY_CANONICAL;
gv.tty->flags &= ~TTY_ECHO; /* disable echo */
printf("\n\tMiner\n\t\tMine ores to sell for money and upgrade your drone\n\n\n\t\t\tHIT ENTER TO CONTINUE, TAB TO EXIT\n");
char b = get_char();
while (b != '\n' && b != '\t')
/*while (gv.c != '\n' && gv.c != '\t')
{
sleep(10);
b = get_char();
gv.c = getchar();
}
if (b == '\t')
if (gv.c == '\t')
{
return;
goto quit;
}
uint16_t c = 0x0;
terminal_clear();
while (true)
cls();*/
while (1)
{
sleep(10);
gv.c = getchar();
c = get_key();
if (c == 0xFFFA || c == 0x0)
if (gv.c == '\t')
{
continue;
goto quit;
}
break;
sleep(500);
}
b = getchar();
while (b == 0x5)
quit:
gv.tty->flags = gv.stored_tty_flags;
if (gv.map && pointer_valid(gv.map))
{
sleep(10);
b = getchar();
free(gv.map);
}
terminal_clear();
cls();
printf("Goodbye!\n");
sleep(2000);
cls();
#endif
}

58
lib/espresso/kstring.c Normal file
View File

@ -0,0 +1,58 @@
#include <stdlib.h>
#include <types.h>
#include <string.h>
/*
A custom standard for strings for use in the Espresso kernel.
*/
struct kstring {
size_t s_len;
char* data; /* NOT null-terminated */
};
/*
if the length of initial_data is more than initial_len, only initial_len bytes will be copied.
if the length of initial_data is less then initial_len, the rest of the bytes are zeroed.
if initial_data is null, no data is copied and the string in set to zero.
*/
struct kstring* make_kstring(size_t initial_len, const char* initial_data)
{
struct kstring* str = malloc(sizeof(struct kstring));
if (!str)
{
return NULL;
}
str->s_len = initial_len;
str->data = malloc(initial_len);
if (!str->data)
{
return NULL;
}
memset(str->data, 0, initial_len);
if (initial_data)
{
size_t slen = strlen(initial_data);
if (slen < initial_len)
{
strncpy(str->data, initial_data, slen);
}
else if (slen > initial_len)
{
strncpy(str->data, initial_data, initial_len);
}
else
{
strcpy(str->data, initial_data);
}
}
return str;
}

View File

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

43
lib/math.c Normal file
View File

@ -0,0 +1,43 @@
#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;
}
int abs(int x)
{
return (x < 0) ? -x : x;
}

79
lib/math/random.c Normal file
View File

@ -0,0 +1,79 @@
#include <types.h>
#include <math/random.h>
/*
This code uses Xorshift (high speed, small) and PCG (Permuted Congruential Generator).
PCG may or may not be slightly slower than Xorshift.
*/
static uint32_t xorshift_state = 2463534242;
static void srand_xorshift(uint32_t seed)
{
xorshift_state = seed;
}
static inline uint32_t rand_xorshift(void)
{
uint32_t x = xorshift_state;
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
return xorshift_state = x;
}
static uint64_t state = 0x853c49e6748fea9bULL;
static uint64_t inc = 0xda3e39cb94b95bdbULL;
static inline uint32_t rand_pcg32(void)
{
uint64_t oldstate = state;
state = oldstate * 6364136223846793005ULL + (inc | 1);
uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
uint32_t rot = oldstate >> 59u;
return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
}
void seed_rand(uint32_t seed)
{
srand_xorshift(seed);
state = seed * 6364136223846793005ULL + (seed | 1);
}
uint32_t uirand(void)
{
return rand_pcg32() ^ rand_xorshift();
}
/* get a number between 0 and max-1 */
uint32_t uirand_range(uint32_t max)
{
if (max == 0)
{
return 0;
}
return uirand() % max;
}
uint64_t ulrand(void)
{
uint64_t hi = uirand();
uint64_t lo = uirand();
return (hi << 32) | lo;
}
/* get a number between 0 and max-1 */
uint64_t ulrand_range(uint64_t max)
{
if (max == 0)
{
return 0;
}
return ulrand() % max;
}

View File

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

View File

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

View File

@ -1,80 +1,100 @@
#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)))
extern uint32_t __kernel_start;
extern uint32_t __kernel_end;
void pmm_init(multiboot_info_t* mb)
{
bitmap[idx / 8] |= (1 << (idx % 8));
}
#ifdef _DEBUG
printf("[ PMM ] Initializing physical memory manager...\n");
#endif
static inline void clear_bit(uint32_t idx)
{
bitmap[idx / 8] &= ~(1 << (idx % 8));
}
static inline int test_bit(uint32_t idx)
{
return (bitmap[idx / 8] >> (idx % 8)) & 1;
}
void pmm_init(multiboot_info_t* mb_info)
{
total_pages = 0x100000; /* 4GB / 4KB = 1M pages */
for (uint32_t i = 0; i < total_pages / 8; i++)
total_pages = MAX_PAGES;
for (uint32_t i = 0; i < (total_pages / 8); i++)
{
bitmap[i] = 0xFF; /* Mark all as used */
bitmap[i] = 0xFF;
}
multiboot_memory_map_t* mmap = (multiboot_memory_map_t*) mb_info->mmap_addr;
while ((uint32_t)mmap < mb_info->mmap_addr + mb_info->mmap_length)
multiboot_memory_map_t* mmap = (void*)(uintptr_t)mb->mmap_addr;
size_t entries = mb->mmap_length / sizeof(multiboot_memory_map_t);
for (size_t i = 0; i < entries; i++)
{
if (mmap->type == 1) /* Usable */
if (mmap[i].type == 1) /* usable */
{
uint64_t base = mmap->addr;
uint64_t len = mmap->len;
for (uint64_t addr = base; addr < base + len; addr += PAGE_SIZE)
uint64_t start = mmap[i].addr;
uint64_t end = start + mmap[i].len;
for (uint64_t addr = start; addr < end; addr += 0x1000)
{
if (addr >= 0x210000) /* Skip first 2.1MB, or ≈ 2.06MiB */
if (addr >= 0x100000) /* skip below 1MB */
{
uint32_t idx = addr / PAGE_SIZE;
if (idx >= total_pages)
{
continue; /* skip entries above 4GB */
}
clear_bit(idx);
used_pages--;
size_t idx = addr / 0x1000;
BITMAP_CLEAR(idx);
}
}
}
mmap = (multiboot_memory_map_t*)((uint32_t)mmap + mmap->size + sizeof(mmap->size));
}
total_pages = MAX_PAGES;
uintptr_t start = (uintptr_t)&__kernel_start;
uintptr_t end = (uintptr_t)&__kernel_end;
start &= ~0xFFF;
end = (end + 0xFFF) & ~0xFFF;
for (uintptr_t addr = start; addr < end; addr += 0x1000)
{
size_t idx = addr / 0x1000;
BITMAP_SET(idx); // Mark kernel pages as USED
}
#ifdef _DEBUG
printf("[ PMM ] Physical memory manager initialized\n");
#endif
}
void* alloc_page(void) {
for (uint32_t i = 0; i < total_pages; i++)
void* pmm_alloc_page(void)
{
for (uint32_t i = 0; i < total_pages; ++i)
{
if (!test_bit(i))
void* page = (void*)(i * 4096);
if ((uintptr_t)page >= (uintptr_t)&__kernel_start &&
(uintptr_t)page < (uintptr_t)&__kernel_end)
{
set_bit(i);
used_pages++;
return (void*)(i * PAGE_SIZE);
printf("PMM allocating inside kernel at %x\n", page);
}
if (!BITMAP_TEST(i))
{
BITMAP_SET(i);
return (void*)(i * 4096);
}
}
return NULL; /* Out of memory */
printf("pmm_alloc_page(): No free page found!\n");
return NULL;
}
void free_page(void* ptr)
void pmm_free_page(void* addr)
{
uint32_t idx = (uint32_t)ptr / PAGE_SIZE;
clear_bit(idx);
size_t idx = (uintptr_t)addr / 0x1000;
BITMAP_CLEAR(idx);
}

View File

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

View File

@ -3,13 +3,18 @@
#include <processes.h>
int32_t next_id = 9; /* 0 through 8 are reserved for kernel operations */
pid_t next_id = 1; /* start at 1 */
int32_t make_process(char* name, char* group, elf_executable_t* exe)
pid_t make_process(char* name, char* group, elf_executable_t* exe)
{
pid_t ret = (pid_t) 0;
if (!name || !group || !exe)
{
return -1;
return ret; /* ret is already zero */
}
return 0;
next_id++;
return ret;
}

76
lib/scheduler.c Normal file
View File

@ -0,0 +1,76 @@
#include <stdlib.h>
#include <string.h>
#include <drivers/irq.h>
#include <scheduler.h>
#define STACK_SIZE (8192)
task_t* current_task = NULL;
task_t* task_list = NULL;
uint32_t next_pid = 1;
void init_scheduler(void)
{
set_irq_handler(0, (irq_func_t) schedule);
}
void scheduler(registers_t* boot_regs)
{
task_t* task = malloc(sizeof(task_t));
task->id = next_pid++;
task->regs = boot_regs;
task->next = task;
task_list = task;
current_task = task;
}
registers_t* schedule(registers_t* regs)
{
if (!current_task)
{
return regs;
}
current_task->regs = regs;
current_task = current_task->next;
return current_task->regs;
}
task_t* create_task(void (*entry)())
{
task_t* task = malloc(sizeof(task_t));
uint32_t* stack = malloc(STACK_SIZE);
uint32_t stack_top = (uint32_t)stack + 4096;
stack_top -= sizeof(registers_t);
registers_t* regs = (registers_t*)stack_top;
memset(regs, 0, sizeof(registers_t));
regs->eip = (uint32_t) entry;
regs->cs = 0x08; /* kernel code */
regs->ds = 0x10;
regs->es = 0x10;
regs->fs = 0x10;
regs->gs = 0x10;
regs->eflags = 0x202; /* IF = 1 */
task->id = next_pid++;
task->regs = regs;
/* insert into circular list */
task->next = task_list->next;
task_list->next = task;
return task;
}

View File

@ -1,18 +1,58 @@
#include <types.h>
#include <stdlib.h>
#include <string.h>
#include <drivers/ps2_keyboard.h>
#include <fs/vfs.h>
#include <kernel/syscall.h>
#include <tty.h>
#include <new_tty.h>
#include <stdio.h>
int write(uint32_t fd, void* data, size_t len)
{
if (fd == STDOUT)
{
/*print_uint((uint32_t) len);*/
terminal_write((char*) data, len);
}
else
{
return -1;
}
return 0;
}
int read(uint32_t fd, void* data, size_t max_len)
{
int rv = 0;
if (fd == STDIN)
{
char* rd = gets_new(&rv);
size_t sz = strlen(rd);
memcpy(data, rd, (sz < max_len) ? sz : max_len);
if (!rd)
{
printf("rd is NULL!\n");
}
}
else
{
return -1;
}
return rv;
}
extern bool ps2keyboard_initialized;
char getchar(void)
{
if (ps2keyboard_initialized)
{
return get_char();
}
return '\0';
return tty_get_char();
}
char* getstring(void)
@ -25,38 +65,40 @@ char* getstring(void)
return "HELLO\0";
}
/*char* fgets(char* buf, int n, FILE file)
char* gets(void)
{
if (!buf || n <= 1 || file < 1)
return kbd_gets();
}
char* gets_new(int* num)
{
char* __s = malloc(256);
memset(__s, 0, 256);
ssize_t n = tty_read_active(__s, 255);
*num = (int) n;
return __s;
}
int getstr(char* dest)
{
int i = 0;
char* p = gets_new(&i);
if (i != 0)
{
return NULL;
return -1;
}
int total_read = 0;
char c;
strcpy(dest, p);
while (total_read < n - 1)
{
int bytes = 0*//*read_file(file, &c, 1)*/;
return 0;
}
/*if (bytes <= 0)
{
break; *//* EOF or error */
/*}
buf[total_read++] = c;
if (c == '\n')
{
break; *//* Stop at newline */
/*}
}
if (total_read == 0)
{
return NULL; *//* Nothing read (e.g. EOF) */
/*}
buf[total_read] = '\0';
return buf;
}*/
void putc(char c)
{
syscall1(SYS_TERMINAL_PUTCHAR, c);
}

View File

@ -1,11 +1,12 @@
#include <stdlib.h>
#include <stdio.h>
#include <vector_extensions/sse.h>
#include <string.h>
#ifdef DEBUG_USE_SSE2
#include <vector_extensions/sse.h>
extern int32_t sse_initialized;
#endif
size_t strlen(const char* str)
{
@ -77,10 +78,12 @@ char* strcpy(char *dst, const char *src)
char* strncpy(char *dest, const char *src, uint32_t n)
{
#ifdef DEBUG_USE_SSE2
if (sse_initialized > 0)
{
return sse2_strncpy(dest, src, n);
}
#endif
uint32_t i = 0;
for (; i < n && src[i]; ++i)
@ -173,9 +176,9 @@ char* strchr(const char* s, int c)
{
while (*s)
{
if (*s == (char)c)
if (*s == (char) c)
{
return (char*)s;
return (char*) s;
}
s++;
}
@ -183,23 +186,47 @@ char* strchr(const char* s, int c)
return NULL;
}
void* memset(void *dst, char c, uint32_t n)
int num_strchr(const char* s, int c)
{
char *temp = dst;
for (; n != 0; n--)
int rv = 0;
while (*s)
{
*temp++ = c;
if (*s == (char) c)
{
rv++;
}
s++;
}
return rv;
}
void* memset(void* dst, int c, size_t 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[i] = val;
}
return dst;
}
void* memcpy(void *dst, const void *src, uint32_t n)
{
#ifdef DEBUG_USE_SSE2
if (sse_initialized > 1)
{
return sse2_memcpy(dst, src, n);
}
#endif
char *d = dst;
const char *s = src;
@ -213,10 +240,10 @@ void* memcpy(void *dst, const void *src, uint32_t n)
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;
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++)
{
@ -231,14 +258,44 @@ int32_t memcmp(const void *s1, const void *s2, size_t n)
void* memclr(void* m_start, size_t m_count)
{
#ifdef DEBUG_USE_SSE2
if (sse_initialized > 1)
{
return memclr_sse2(m_start, m_count);
}
#endif
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 +338,232 @@ 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);
}
char* strnlstrip(const char* s)
{
if (!s)
{
return NULL;
}
char* new = strdup(s);
if (!new)
{
return NULL;
}
size_t len = strlen(new);
while (len > 0 && (new[len-1] == '\n' || new[len-1] == '\r'))
{
new[len-1] = '\0';
len--;
}
return new;
}
void strlnstripip(char* s)
{
size_t len = strlen(s);
if (len > 0 && s[len-1] == '\n')
{
s[len-1] = '\0';
}
}
char** split(const char* str, char delim)
{
if (!str)
{
return NULL;
}
size_t count = 1;
for (const char* p = str; *p; p++)
{
if (*p == delim)
{
count++;
}
}
char** result = malloc((count + 1) * sizeof(char*));
if (!result)
{
return NULL;
}
size_t idx = 0;
const char* start = str;
for (const char* p = str; ; p++)
{
if (*p == delim || *p == '\0')
{
size_t len = p - start;
char* token = malloc(len + 1);
if (!token)
{
return NULL;
}
for (size_t i = 0; i < len; i++)
{
token[i] = start[i];
}
token[len] = '\0';
result[idx++] = token;
start = p + 1;
if (*p == '\0')
{
break;
}
}
}
result[idx] = NULL; /* null-terminate the array */
return result;
}
void free_split(char** parts)
{
if (!parts)
{
return;
}
for (int i = 0; parts[i] != NULL; i++)
{
free(parts[i]);
}
free(parts);
}

Some files were not shown because too many files have changed in this diff Show More