Espresso 0.0.2c

This commit is contained in:
2026-03-20 16:57:08 -05:00
parent 021fdbbcef
commit 5971218b56
77 changed files with 4538 additions and 518 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

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,19 @@
# === Config === # === Config ===
TARGET := boot/espresso.elf TARGET := boot/espresso.elf
ISO := boot/espresso.iso ISO := boot/espresso.iso
FAT16_DISK := espresso.img
CC := i686-elf-gcc CC := i686-elf-gcc
AS := i686-elf-as AS := i686-elf-as
NASM := nasm NASM := nasm
QEMU_MKE_IMG := qemu-img create -f raw espresso.img 64M QEMU_MKE_IMG := qemu-img create -f raw $(FAT16_DISK) 64M
MKFS_VFAT := sudo mkfs.vfat MKFS_VFAT := sudo mkfs.vfat
MKFS_FLAGS := -F 16 -S 512 MKFS_FLAGS := -F 16 -S 512
NASMFLAGS := -f elf32 NASMFLAGS := -f elf32
WNOFLAGS := -Wno-discarded-qualifiers WNOFLAGS := -Wno-discarded-qualifiers
CFLAGS := -std=gnu99 -ffreestanding -O2 -Wall -Wextra -msse $(WNOFLAGS) -nostdlib -nostartfiles -include include/kincl.h CFLAGS := -std=gnu99 -ffreestanding -O2 -Wall -Wextra -msse $(WNOFLAGS) -nostdlib -nostartfiles -include include/kincl.h
LDFLAGS := -T linker.ld -ffreestanding -O2 -nostdlib -nostartfiles LDFLAGS := -T linker.ld -ffreestanding -O2 -nostdlib -nostartfiles
QEMUFLAGS := -boot d -cdrom $(ISO) -drive file=espresso.img,format=raw,if=ide,readonly=off,rerror=report,werror=report -cpu qemu32,sse4.1 QEMUFLAGS := -no-shutdown -boot d -cdrom $(ISO) -drive file=$(FAT16_DISK),format=raw,if=ide,readonly=off,rerror=report,werror=report -cpu qemu32,sse4.1
QEMUFLGS_EXT := -vga std -d int,cpu_reset -D qemu.log -no-reboot #-singlestep QEMUFLGS_EXT := -vga std -d int,cpu_reset -D qemu.log # -audiodev pa,id=speaker -machine pcspk-audiodev=speaker
MOR_QEMUFLGS := -net none -netdev user,id=n0 -device rtl8139,netdev=n0 -serial file:serial.log MOR_QEMUFLGS := -net none -netdev user,id=n0 -device rtl8139,netdev=n0 -serial file:serial.log
SRC_DIRS := kernel drivers lib SRC_DIRS := kernel drivers lib
INCLUDE_DIRS := include INCLUDE_DIRS := include
@ -78,10 +79,10 @@ iso: $(TARGET)
# === Run in QEMU === # === Run in QEMU ===
run: iso run: iso
@if [ ! -f espresso.img ]; then \ @if [ ! -f $(FAT16_DISK) ]; then \
$(QEMU_MKE_IMG); \ $(QEMU_MKE_IMG); \
sudo mkfs.fat $(MKFS_FLAGS) espresso.img; \
fi fi
sudo mkfs.fat $(MKFS_FLAGS) espresso.img
@echo @echo
qemu-system-i386 $(QEMUFLAGS) $(QEMUFLGS_EXT) $(MOR_QEMUFLGS) qemu-system-i386 $(QEMUFLAGS) $(QEMUFLGS_EXT) $(MOR_QEMUFLGS)
@ -90,6 +91,17 @@ run: iso
clean: clean:
rm -f $(INTERNAL_OBJS) $(TARGET) $(ISO) rm -f $(INTERNAL_OBJS) $(TARGET) $(ISO)
rm -rf $(ISO_DIR) rm -rf $(ISO_DIR)
clean_disk:
rm -f espresso.img rm -f espresso.img
.PHONY: all clean iso run debug build buildc # === Push code to repo ===
commit:
ifndef MSG
$(error MSG required)
endif
git add .
git commit -m "$(MSG)"
git push
.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

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] [BITS 32]
[GLOBAL isr_stub_table] [GLOBAL isr_stub_table]
[GLOBAL irq_stub_table] [GLOBAL irq_stub_table]
extern irq_handler ; C function [GLOBAL interrupt_entry]
extern interrupt_dispatcher
section .text section .text
; -------------------------------------------- ; ============================================================
; ------------------- IRQs ------------------- ; COMMON INTERRUPT ENTRY
; -------------------------------------------- ; ============================================================
%macro irq_stub 1 interrupt_entry:
irq_stub_%+%1:
pusha ; Stack already contains:
push ds ; err_code
push es ; int_no
push fs ; eip
; cs
; eflags
pusha ; eax, ecx, edx, ebx, esp, ebp, esi, edi
push gs push gs
push fs
push es
push ds
mov ax, 0x10 mov ax, 0x10 ; load kernel data selector
mov ds, ax mov ds, ax
mov es, ax mov es, ax
mov fs, ax mov fs, ax
mov gs, ax mov gs, ax
push dword %1 ; Push IRQ number push esp ; pass pointer to registers_t
call irq_handler call interrupt_dispatcher
add esp, 4 ; Clean up stack 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 ; don't do this yet, it corrupts stuff. wait until the scheduler is finished
mov al, 0x20 ;mov esp, eax ; move the new stack pointer into esp
mov bl, %1
cmp bl, 8
jb .skip_slave_eoi
out 0xA0, al
.skip_slave_eoi:
out 0x20, al
pop gs pop gs
pop fs pop fs
pop es pop es
pop ds pop ds
popa 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 %endmacro
IRQ 0
; Define 16 IRQ stubs IRQ 1
irq_stub 0 IRQ 2
irq_stub 1 IRQ 3
irq_stub 2 IRQ 4
irq_stub 3 IRQ 5
irq_stub 4 IRQ 6
irq_stub 5 IRQ 7
irq_stub 6 IRQ 8
irq_stub 7 IRQ 9
irq_stub 8 IRQ 10
irq_stub 9 IRQ 11
irq_stub 10 IRQ 12
irq_stub 11 IRQ 13
irq_stub 12 IRQ 14
irq_stub 13 IRQ 15
irq_stub 14 IRQ 16
irq_stub 15 IRQ 17
IRQ 18
IRQ 19
irq_stub_table: irq_stub_table:
%assign i 0 %assign i 0
%rep 16 %rep 20
dd irq_stub_%+i dd irq_stub_%+i
%assign i i+1 %assign i i+1
%endrep %endrep
; --------------------------------------------
; ------------------- ISRs -------------------
; --------------------------------------------
; Common exception handler entry point ; ============================================================
isr_common_handler: ; EXCEPTION STUBS
pusha ; Push general-purpose registers ; ============================================================
push ds
push es
push fs
push gs
; Load known-good segment selectors %macro ISR_NOERR 1
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
isr_stub_%+%1: isr_stub_%+%1:
cli push dword 0 ; fake error code
push dword %1 ; interrupt number push dword %1 ; interrupt number
jmp isr_common_handler jmp interrupt_entry
%endmacro %endmacro
; Macro: for exceptions without error code %macro ISR_ERR 1
%macro isr_no_err_stub 1
isr_stub_%+%1: isr_stub_%+%1:
cli push dword %1 ; interrupt number
push dword 0 ; fake error code jmp interrupt_entry
push dword %1 ; interrupt number
jmp isr_common_handler
%endmacro %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: isr_stub_table:
%assign i 0 %assign i 0
%rep 32 %rep 32

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

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

@ -13,10 +13,10 @@
elf_executable_t* load_elf32(void* elf_data) elf_executable_t* load_elf32(void* elf_data)
{ {
/*Elf32_Ehdr* ehdr = (Elf32_Ehdr*)elf_data;*/ Elf32_Ehdr* ehdr = (Elf32_Ehdr*)elf_data;
/* Check ELF magic */ /* Check ELF magic */
/*if (memcmp(ehdr->e_ident, (uint8_t*)("\x7F""ELF"), 4) != 0) if (memcmp(ehdr->e_ident, (uint8_t*)("\x7F""ELF"), 4) != 0)
{ {
printf("Invalid ELF file\n"); printf("Invalid ELF file\n");
return NULL; return NULL;
@ -30,7 +30,8 @@ elf_executable_t* load_elf32(void* elf_data)
Elf32_Phdr* phdrs = (Elf32_Phdr*)((uint8_t*)elf_data + ehdr->e_phoff); 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]; Elf32_Phdr* phdr = &phdrs[i];
if (phdr->p_type != PT_LOAD) 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++) 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); void* virt = (void*)(vaddr_start + page * PAGE_SIZE);
map_page(phys, virt); map_page(phys, virt);
memset(virt, 0, PAGE_SIZE); memset(virt, 0, PAGE_SIZE);
@ -53,12 +54,15 @@ elf_executable_t* load_elf32(void* elf_data)
void* src = (uint8_t*)elf_data + phdr->p_offset; void* src = (uint8_t*)elf_data + phdr->p_offset;
memcpy(dest, src, phdr->p_filesz); 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
} }
elf_executable_t* result = malloc(sizeof(elf_executable_t)); elf_executable_t* result = malloc(sizeof(elf_executable_t));
result->entry_point = (void*)(uintptr_t)ehdr->e_entry; result->entry_point = (elf_entry_t)(uintptr_t)ehdr->e_entry;
return result;*/ return result;
return NULL; return NULL;
} }

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 */
}

49
drivers/fs/ekfs.c Normal file
View File

@ -0,0 +1,49 @@
#include <types.h>
#include <string.h>
#include <drivers/ide.h>
#include <fs/ekfs.h>
/* work on this later */
#if 0
/* note: __l being 0 is allowed, because that way read() can be used to tell if a file exists (with return value 0) */
int ekfs_read(struct ekfs_file* __f, void* __b, size_t __l)
{
int rv = 0;
if (!__f || !__b || (!__f->f_inode))
{
return -1;
}
/* we assume drive 0 is already mounted */
char buffer[512];
memset(buffer, 0, 512);
int num_sectors = __f->f_inode->i_len / 512;
if ((__l / 512) > num_sectors)
{
return EKFS_E_FILETOOSMALL;
}
int read_sectors = num_sectors;
for (int i = 0; i < read_sectors; i++);
{
rv = read_sector(__f->f_inode->i_start, buffer);
if (rv != 0)
{
break;
}
}
return rv;
}
#endif

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

@ -0,0 +1,374 @@
#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;
}
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 == 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
}

View File

@ -1,24 +1,76 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <tty.h>
#include <fs/vfs.h> #include <fs/vfs.h>
/* we use something similar to the Linux kernel in terms of a VFS system */
typedef struct vfs_file_header { #define MAX_FDS 64
char* filename; /* The filename, not the path. */
struct inode {
int32_t fd; size_t size;
int permissions;
uint8_t type_info; /* Bits 0 - 3 -> File type, Bits 4 - 7 FS type */ void *fs_data; /* FS-specific */
};
uint16_t* fs_header;
struct file_ops {
struct vfs_file_header* next; /* Linked list */ int (*read)(struct file*, char*, size_t);
} vfs_file_header_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;
};
vfs_file_header_t* root;
struct fdtable {
struct file* fds[MAX_FDS];
};
int vfs_handle_stdout(struct file* __f, const char* __s, size_t __l)
{
(void) __f;
terminal_write(__s, __l);
return 0;
}
struct fdtable* vfs_init_kernel_fdtable(void)
{
#if 0
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 };
#endif
return NULL;
}
int init_vfs(int argc, char** argv)
{
(void) argc;
(void) argv;
return 0;
}
/* /*
@ -28,5 +80,7 @@ vfs_file_header_t* root;
wow. wow.
and now my CPU fan is going nuts. 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]; uint64_t gdt[GDT_ENTRIES];
struct { struct {
uint16_t limit; uint16_t limit;
uint32_t base; uint32_t base;
} __attribute__((packed)) gp; } __attribute__((packed)) gp;

View File

@ -1,6 +1,11 @@
#include <stdio.h> #include <stdio.h>
#include <port_io.h> #include <port_io.h>
#include <scheduler.h>
#include <kernel/syscall.h>
#include <drivers/irq.h>
#include <drivers/idt.h> #include <drivers/idt.h>
@ -29,8 +34,7 @@ typedef struct {
} __attribute__((packed)) idtr_t; } __attribute__((packed)) idtr_t;
__attribute__((aligned(0x10))) __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; static idtr_t idtr;
@ -38,91 +42,6 @@ static bool vectors[IDT_MAX_DESCRIPTORS];
extern void* isr_stub_table[]; 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) void idt_init(void)
{ {
idtr.base = (uintptr_t)&idt[0]; idtr.base = (uintptr_t)&idt[0];
@ -136,13 +55,141 @@ void idt_init(void)
extern void* irq_stub_table[]; 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); idt_set_descriptor(32 + i, irq_stub_table[i], 0x8E);
} }
asm volatile ("lidt %0" : : "m"(idtr)); /* load the new IDT */ 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

@ -3,46 +3,74 @@
#include <drivers/pit.h> #include <drivers/pit.h>
#include <port_io.h> #include <port_io.h>
/* TEMP DEBUG */
#include <tty.h>
#include <kernel/syscall.h>
#include <drivers/irq.h> #include <drivers/irq.h>
#define NUM_IRQS 0x90 #define MAX_IRQ_HANDLERS 128 /* the maximum number of irq handlers */
irq_func_t func_list[NUM_IRQS];
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) void irq_init(void)
{ {
for (int i = 0; i < NUM_IRQS; i++) for (int i = 0; i < MAX_IRQ_HANDLERS; i++)
{ {
func_list[i] = 0x0; handler_list[i].irq_no = 0;
handler_list[i].func = NULL;
} }
set_irq_handler(0, (irq_func_t*) pit_handler); set_irq_handler(0, (irq_func_t) pit_handler);
set_irq_handler(1, (irq_func_t*) keyboard_handler); //set_irq_handler(1, (irq_func_t) ps2_keyboard_handler);
} }
void irq_handler(uint8_t irq_number) registers_t* irq_handler(uint32_t irq, registers_t* regs)
{ {
if (irq_number < NUM_IRQS) uint8_t funcs_called = 0;
{
if (func_list[irq_number]) if (num_irq_handlers > 0)
{
for (unsigned int i = 0; i < MAX_IRQ_HANDLERS; i++)
{ {
func_list[irq_number](); if (handler_list[i].irq_no == irq && handler_list[i].func != NULL)
outb(0x20, 0x20); /* Acknowledge the IRQ to PIC */ {
} regs = handler_list[i].func(regs);
else funcs_called++;
{ /* PIC IRQ acknowledgement happens in idt.c */
num_irqs_missed++; }
} }
} }
if (funcs_called == 0)
{
num_irqs_missed++;
}
return regs;
} }
void set_irq_handler(uint32_t num, irq_func_t* handler) uint32_t get_interrupts_missed(void)
{ {
if (num < NUM_IRQS) return num_irqs_missed;
}
void set_irq_handler(uint32_t num, irq_func_t handler)
{
if (num < MAX_IRQ_HANDLERS)
{ {
func_list[num] = (irq_func_t)handler; handler_list[num].irq_no = num;
handler_list[num].func = handler;
num_irq_handlers++;
} }
} }

148
drivers/keyboard.c Normal file
View File

@ -0,0 +1,148 @@
#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 & 0x80)
{
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); /* TOGGLE_BIT defined in types.h, should move elsewhere. */
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;
}
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;
}

382
drivers/new_tty.c Normal file
View File

@ -0,0 +1,382 @@
#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;
}
tty_t* tty_get_active(void)
{
return active_tty;
}
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;
}
ssize_t tty_read_active(char* buf, size_t count)
{
return tty_read(active_tty, buf, count);
}
/*ssize_t tty_read(tty_t* tty, char* buf, size_t count)
{
size_t bytes_read = 0;
while (bytes_read < count)
{
IRQ_DISABLE();
spin_lock(&tty->lock);
if (!tty_empty(tty))
{
char c = tty->input_buffer[tty->tail];
tty->tail = (tty->tail + 1) % TTY_BUFFER_SIZE;
tty->tail = next_index(tty->tail);
spin_unlock(&tty->lock);
IRQ_ENABLE(); /* change? *//*
buf[bytes_read++] = c;
if (is_canonical(tty) && c == '\n')
{
break;
}
}
else
{
spin_unlock(&tty->lock);
IRQ_ENABLE();
}
}
return bytes_read;
}*/
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;
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);
/* backspace */
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');/*
putc(' ');
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);
}
}
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

@ -2,6 +2,8 @@
#include <port_io.h> #include <port_io.h>
#include <stdio.h> #include <stdio.h>
#include <scheduler.h>
#include <drivers/pit.h> #include <drivers/pit.h>
@ -14,12 +16,14 @@ volatile uint64_t pit_ticks = 0;
bool pit_initialized = false; bool pit_initialized = false;
void pit_init(void) void pit_init(void)
{ {
printf("pit_initialized addr = %x\n", &pit_initialized);
#ifdef _DEBUG #ifdef _DEBUG
printf("[ PIT ] Initializing the PIT...\n"); printf("[ PIT ] Initializing the PIT...\n");
#endif #endif
uint16_t divisor = (uint16_t)1193; uint16_t divisor = (uint16_t) 1193;
/* Send command byte */ /* Send command byte */
outb(PIT_COMMAND, 0x36); /* Channel 0, low/high byte, mode 3 (square wave), binary */ outb(PIT_COMMAND, 0x36); /* Channel 0, low/high byte, mode 3 (square wave), binary */
@ -35,9 +39,10 @@ void pit_init(void)
#endif #endif
} }
void pit_handler(void) registers_t* pit_handler(registers_t* regs)
{ {
pit_ticks++; pit_ticks++;
return regs;
} }
void pit_sleep(uint64_t ms) void pit_sleep(uint64_t ms)
@ -48,3 +53,14 @@ void pit_sleep(uint64_t ms)
asm volatile ("hlt"); asm volatile ("hlt");
} }
} }
/*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

@ -3,6 +3,8 @@
#include <tty.h> #include <tty.h>
#include <stdlib.h> #include <stdlib.h>
#include <new_tty.h>
#include <drivers/ps2_keyboard.h> #include <drivers/ps2_keyboard.h>
@ -62,6 +64,8 @@ volatile int32_t current_length = 0;
volatile int32_t capacity = 0; volatile int32_t capacity = 0;
volatile uint16_t current_key; volatile uint16_t current_key;
volatile bool use_new_tty = false;
volatile ps2_hook_t* hooks = NULL; volatile ps2_hook_t* hooks = NULL;
volatile int hook_count = 0; volatile int hook_count = 0;
@ -84,6 +88,10 @@ static const char scancode_map[128] = {
/* The rest are function and control keys */ /* The rest are function and control keys */
}; };
void set_use_new_tty(bool t)
{
use_new_tty = t;
}
void keyboard_init(void) void keyboard_init(void)
{ {
@ -94,6 +102,8 @@ void keyboard_init(void)
outb(0x64, 0xAE); /* Enable keyboard interface (often optional, but here for safety) */ outb(0x64, 0xAE); /* Enable keyboard interface (often optional, but here for safety) */
hooks = NULL; hooks = NULL;
set_use_new_tty(true);
ps2keyboard_initialized = true; ps2keyboard_initialized = true;
@ -199,6 +209,7 @@ void call_hooks(char c)
if (hook_count == 0) if (hook_count == 0)
{ {
_sti_asm();
return; return;
} }
@ -396,32 +407,45 @@ 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); uint8_t scancode = inb(PS2_DATA_PORT);
/* Handle shift press/release */ /* Handle shift press/release */
if (scancode == 0x2A || scancode == 0x36) if (scancode == 0x2A || scancode == 0x36)
{ {
shift_pressed = true; shift_pressed = true;
return; return regs;
} }
else if (scancode == 0xAA || scancode == 0xB6) else if (scancode == 0xAA || scancode == 0xB6)
{ {
shift_pressed = false; shift_pressed = false;
return; return regs;
} }
else if (scancode == 0x3A) else if (scancode == 0x3A)
{ {
capslock_pressed = !capslock_pressed; capslock_pressed = !capslock_pressed;
return; return regs;
} }
else if (scancode == 0xE0) else if (scancode == 0xE0)
{ {
extended = true; extended = true;
return; return regs;
} }
uint32_t flags = 0;
if (capslock_pressed)
{
flags |= MODIFIER_CAPS;
}
if (shift_pressed)
{
flags |= MODIFIER_SHIFT;
}
if (scancode & 0x80) if (scancode & 0x80)
{ {
@ -430,84 +454,94 @@ void keyboard_handler(void)
else else
{ {
uint16_t c = (uint16_t) scancode_map[scancode]; uint16_t c = (uint16_t) scancode_map[scancode];
if ((shift_pressed ^ capslock_pressed) && ((char) c >= 'a') && ((char) c <= 'z'))
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 (hook_count > 0) if (hook_count > 0)
{ {
call_hooks(c); call_hooks(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;
}
current_key = c;
is_new_key = true;
extended = false;
return;
}
if (gets_called)
{
gets_append_char(c);
return;
}
if (c)
{
if (c != '\n')
{
append_char(c);
}
current_char = c;
is_new_char = true;
if (c == '\n')
{
/*append_char(c);
current_char = c;
is_new_char = true;*/
free_current_string();
}
}
} }
#endif
return regs;
} }

View File

@ -306,3 +306,12 @@ void terminal_update_cursor(void)
outb(0x3D5, (uint8_t) ((pos >> 8) & 0xFF)); 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);
}

177
files/idt.c Normal file
View File

@ -0,0 +1,177 @@
#include <stdio.h>
#include <port_io.h>
#include <drivers/irq.h>
#include <drivers/idt.h>
#define IDT_MAX_DESCRIPTORS 256
#define PIC1_COMMAND 0x20
#define PIC1_DATA 0x21
#define PIC2_COMMAND 0xA0
#define PIC2_DATA 0xA1
/*
Most of the code is this file (and idt.h) are taken from the osdev wiki: https://wiki.osdev.org/Interrupts_Tutorial, though not all of it.
*/
typedef struct {
uint16_t isr_low; // The lower 16 bits of the ISR's address
uint16_t kernel_cs; // The GDT segment selector that the CPU will load into CS before calling the ISR
uint8_t reserved; // Set to zero
uint8_t attributes; // Type and attributes; see the IDT page
uint16_t isr_high; // The higher 16 bits of the ISR's address
} __attribute__((packed)) idt_entry_t;
typedef struct {
uint16_t limit;
uint32_t base;
} __attribute__((packed)) idtr_t;
__attribute__((aligned(0x10)))
static idt_entry_t idt[256]; // Create an array of IDT entries; aligned for performance
static idtr_t idtr;
static bool vectors[IDT_MAX_DESCRIPTORS];
extern void* isr_stub_table[];
void idt_init(void)
{
idtr.base = (uintptr_t)&idt[0];
idtr.limit = (uint16_t)sizeof(idt_entry_t) * IDT_MAX_DESCRIPTORS - 1;
for (uint8_t vector = 0; vector < 32; vector++)
{
idt_set_descriptor(vector, isr_stub_table[vector], 0x8E);
vectors[vector] = true;
}
extern void* irq_stub_table[];
for (uint8_t i = 0; i < 16; 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 */
}
void interrupt_dispatcher(registers_t* regs)
{
if (regs->int_no < 32)
{
exception_handler(regs);
}
else if (regs->int_no < 48)
{
uint32_t irq = regs->int_no - 32;
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 */
}
}
__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\n");
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 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("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));
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 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);
}

18
files/idt.h Normal file
View File

@ -0,0 +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_handler(registers_t* regs);
#endif

69
files/irq.c Normal file
View File

@ -0,0 +1,69 @@
#include <stdio.h>
#include <drivers/ps2_keyboard.h>
#include <drivers/pit.h>
#include <port_io.h>
#include <drivers/irq.h>
#define MAX_IRQ_HANDLERS 128 /* the maximum number of irq handlers */
typedef struct {
uint32_t irq_no;
irq_func_t func;
} irq_handler_t;
uint32_t num_irq_handlers = 0;
irq_handler_t handler_list[MAX_IRQ_HANDLERS];
static volatile uint32_t num_irqs_missed = 0;
void irq_init(void)
{
for (int i = 0; i < MAX_IRQ_HANDLERS; i++)
{
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 irq_handler(uint32_t irq, registers_t* regs)
{
uint8_t funcs_called = 0;
if (num_irq_handlers > 0)
{
for (unsigned int i = 0; i < num_irq_handlers; i++)
{
if (handler_list[i].irq_no == irq && handler_list[i].func != NULL)
{
handler_list[i].func(regs);
funcs_called++;
/* PIC IRQ acknowledgement happens in idt.c */
}
}
}
if (funcs_called == 0)
{
num_irqs_missed++;
}
}
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;
num_irq_handlers++;
}
}

43
files/irq.h Normal file
View File

@ -0,0 +1,43 @@
#ifndef _IRQ_H
#define _IRQ_H
#include <types.h>
/*
typedef struct registers {
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, cs, eflags;
} registers_t;
*/
typedef struct {
uint32_t ds, es, fs, gs;
uint32_t eax, ecx, edx, ebx;
uint32_t esp, ebp, esi, edi;
uint32_t int_no;
uint32_t err_code;
uint32_t eip, cs, eflags;
} registers_t;
typedef void (*irq_func_t)(registers_t*);
void irq_init(void);
void 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);*/
uint32_t get_interrupts_missed(void);
#endif

154
files/isr.asm Normal file
View File

@ -0,0 +1,154 @@
[BITS 32]
[GLOBAL isr_stub_table]
[GLOBAL irq_stub_table]
[GLOBAL interrupt_entry]
extern interrupt_dispatcher
section .text
; ============================================================
; COMMON INTERRUPT ENTRY
; ============================================================
interrupt_entry:
; Stack already contains:
; err_code
; int_no
; eip
; cs
; eflags
pusha ; eax, ecx, edx, ebx, esp, ebp, esi, edi
;push ds
;push es
;push fs
;push gs
push gs
push fs
push es
push ds
mov ax, 0x10 ; load kernel data selector
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
push esp ; pass pointer to registers_t
call interrupt_dispatcher
add esp, 4
pop gs
pop fs
pop es
pop ds
popa
add esp, 8 ; remove int_no + err_code
iret
; ============================================================
; IRQ STUBS
; ============================================================
%macro IRQ 1
irq_stub_%+%1:
push dword 0 ; fake error code
push dword (32 + %1) ; vector number
jmp interrupt_entry
%endmacro
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_stub_table:
%assign i 0
%rep 16
dd irq_stub_%+i
%assign i i+1
%endrep
; ============================================================
; EXCEPTION STUBS
; ============================================================
%macro ISR_NOERR 1
isr_stub_%+%1:
push dword 0 ; fake error code
push dword %1 ; interrupt number
jmp interrupt_entry
%endmacro
%macro ISR_ERR 1
isr_stub_%+%1:
push dword %1 ; interrupt number
jmp interrupt_entry
%endmacro
; 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
dd isr_stub_%+i
%assign i i+1
%endrep

164
files/kernel.c Normal file
View File

@ -0,0 +1,164 @@
/* Check if the compiler thinks you are targeting the wrong operating system. */
#if defined(__linux__)
#error "You are not using a cross-compiler, you will most certainly run into trouble"
#endif
/* This tutorial will only work for the 32-bit ix86 targets. */
#if !defined(__i386__)
#error "This kernel needs to be compiled with a ix86-elf compiler"
#endif
#include <types.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <kernel/boot.h>
#include <kernel/kshell.h>
#include <kdebug.h>
#include <gdt.h>
#include <drivers/idt.h>
#include <drivers/irq.h>
#include <scheduler.h>
#include <multiboot.h>
#include <drivers/pci.h>
#include <drivers/ps2_keyboard.h>
#include <drivers/pit.h>
/*#include <drivers/ahci.h>*/
#include <drivers/ide.h>
#include <mm/mm.h>
#include <fs/fat32.h>
/*#include <fs/duckfs.h>*/
#include <fs/vfs.h>
#include <fs/sfs.h>
#include <vector_extensions/sse.h>
#include <kernel/intro.h>
#include <builtin_games/miner.h>
#include <fs/ssfs.h>
extern void _hang_asm(void);
extern void _sti_asm(void);
void idle_task(void)
{
while (1)
asm volatile("hlt");
}
void kernel_main(multiboot_info_t* mbd, uint32_t magic)
{
/* --- BEGIN INITIALIZATION SECTION --- */
/* We need to initialize the terminal so that any error/debugging messages show. */
terminal_initialize();
printf("Loading Espresso %s... ", KERNEL_VERSION);
#ifdef _DEBUG
printf("[ DEBUG BUILD ]");
#endif
printf("\n");
terminal_setcolor(VGA_COLOR_RED);
/* Make sure the magic number matches for memory mapping */
if(magic != MULTIBOOT_BOOTLOADER_MAGIC)
{
printf("[ ERROR ] invalid magic number!\n");
_hang_asm();
}
/* Check bit 6 to see if we have a valid memory map */
if(!(mbd->flags >> 6 & 0x1))
{
printf("[ ERROR ] invalid memory map given by GRUB bootloader\n");
_hang_asm();
}
gdt_install(false);
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);
pmm_init(mbd);
paging_init();
heap_init(0xC2000000, 0x80000);
#ifdef _DEBUG
printd("Testing SSE...\n");
#endif
int32_t sse_test_result = test_sse();
if (sse_test_result != 0)
{
printf("[ SSE ] SSE test failed with RV %d\n", sse_test_result);
}
else
{
#ifdef _DEBUG
printd("SSE test passed\n");
#endif
}
pit_init();
keyboard_init();
ide_initialize();
pci_init();
scheduler_init();
/* --- END INITIALIZATION SECTION --- */
terminal_setcolor(VGA_COLOR_LIGHT_GREEN);
printf("Guten tag and welcome to Espresso %s\n", KERNEL_VERSION);
//terminal_clear();
create_task(kshell_start);
create_task(idle_task);
extern task_t* task_list;
extern task_t* current_task;
current_task = task_list;
printf("in kernel_main\n");
/*extern void terminal_clear(void);
terminal_clear();
kshell_start(1, NULL);*/
for(;;) /* Loop infinitely. We only do something when an interrupt/syscall happens now. */
{
asm volatile("hlt" ::: "memory");
}
}

62
files/pit.c Normal file
View File

@ -0,0 +1,62 @@
#include <types.h>
#include <port_io.h>
#include <stdio.h>
#include <scheduler.h>
#include <drivers/pit.h>
#define PIT_CHANNEL0 0x40
#define PIT_COMMAND 0x43
#define PIT_IRQ_LINE 0
#define PIT_FREQUENCY_BASE 1193182
volatile uint64_t pit_ticks = 0;
bool pit_initialized = false;
void pit_init(void)
{
#ifdef _DEBUG
printf("[ PIT ] Initializing the PIT...\n");
#endif
uint16_t divisor = (uint16_t) 1193;
/* Send command byte */
outb(PIT_COMMAND, 0x36); /* Channel 0, low/high byte, mode 3 (square wave), binary */
/* Send divisor low and high byte */
outb(PIT_CHANNEL0, (uint8_t)(divisor & 0xFF)); /* Low byte */
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)
{
pit_ticks++;
}
/*void pit_sleep(uint64_t ms)
{
uint64_t target = pit_ticks + ms;
while (pit_ticks < target)
{
asm volatile ("hlt");
}
}*/
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 */
}

158
files/scheduler.c Normal file
View File

@ -0,0 +1,158 @@
#include <stdlib.h>
#include <string.h>
#include <drivers/irq.h>
#include <scheduler.h>
#define STACK_SIZE 4096
task_t* task_list = NULL;
task_t* current_task = NULL;
uint32_t next_task_id = 1;
static void schedule(void);
/* scheduler init */
void scheduler_init(void)
{
set_irq_handler(0, (irq_func_t) scheduler_tick);
}
static void schedule(void)
{
if (!task_list)
{
return;
}
/* wake sleeping tasks */
task_t* t = task_list;
extern uint64_t pit_ticks;
do
{
if (t->state == TASK_SLEEPING && pit_ticks >= t->wakeup_tick)
{
t->state = TASK_READY;
}
t = t->next;
}
while (t != task_list);
/* find next ready task */
task_t* start = current_task;
do
{
current_task = current_task->next;
if (current_task->state == TASK_READY)
{
return;
}
}
while (current_task != start);
}
/* tick handler */
void scheduler_tick(registers_t* regs)
{
if (!task_list)
{
printf("!task_list\n");
return;
}
if (!current_task)
{
printf("!current_task\n");
current_task = task_list;
}
/* save current task state */
*(current_task->regs) = *regs;
/* pick next */
schedule();
/* load next task state */
*regs = *(current_task->regs);
}
/* task creation */
task_t* create_task(void (*entry)())
{
task_t* task = malloc(sizeof(task_t));
if (!task)
{
return NULL;
}
memset(task, 0, sizeof(task_t));
/* allocate stack */
uint8_t* stack = malloc(STACK_SIZE);
if (!stack)
{
free(task);
return NULL;
}
printf("Creating task %i @ %p\n", next_task_id, entry);
/*
align stack to 16 bytes for safety (SSE friendly).
stack grows downward.
*/
uintptr_t stack_top = (uintptr_t)(stack + STACK_SIZE);
stack_top &= ~0xF;
registers_t* regs = (registers_t*) (stack_top - sizeof(registers_t));
memset(regs, 0, sizeof(registers_t));
/* initialize register frame */
regs->eip = (uint32_t) entry;
regs->cs = 0x08; /* Kernel code segment */
regs->eflags = 0x202; /* IF=1 */
task->id = next_task_id++;
task->regs = regs;
task->stack_base = (uint32_t*) stack;
task->state = TASK_READY;
/* insert into circular list */
if (!task_list)
{
task_list = task;
task->next = task;
}
else
{
task_t* last = task_list;
while (last->next != task_list)
{
last = last->next;
}
last->next = task;
task->next = task_list;
}
printf("Task %i @ %p created successfully\n", next_task_id - 1, entry);
return task;
}
/* task destruction */
void destroy_task(task_t* task)
{
free(task->stack_base);
free(task);
}

32
files/scheduler.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef _SCHEDULER_H
#define _SCHEDULER_H
#include <drivers/irq.h>
#include <types.h>
typedef enum {
TASK_READY,
TASK_RUNNING,
TASK_SLEEPING,
TASK_BLOCKED,
TASK_TERMINATED,
} task_state_t;
typedef struct task {
uint32_t id;
registers_t* regs; /* pointer to saved register frame */
uint32_t* stack_base; /* original malloc() pointer */
task_state_t state;
struct task* next;
uint64_t wakeup_tick;
} task_t;
void scheduler_init(void);
task_t* create_task(void (*entry)());
void scheduler_tick(registers_t* regs);
#endif

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

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

View File

@ -1,13 +1,18 @@
#ifndef _IDT_H #ifndef _IDT_H
#define _IDT_H #define _IDT_H
#include <drivers/irq.h>
#include <types.h> #include <types.h>
void idt_init(void); void idt_init(void);
void pic_remap(void); void pic_remap(void);
void idt_set_descriptor(uint8_t vector, void* isr, uint8_t flags); 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 #endif

View File

@ -3,13 +3,28 @@
#include <types.h> #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_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 set_irq_handler(uint32_t num, irq_func_t handler);
void add_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 #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

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

View File

@ -23,7 +23,9 @@ typedef enum {
typedef void (*ps2_hook_t)(char); typedef void (*ps2_hook_t)(char);
void keyboard_init(void); 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); char get_char(void);
uint16_t get_key(void); uint16_t get_key(void);

37
include/fs/ekfs.h Normal file
View File

@ -0,0 +1,37 @@
//#ifndef _ESPRESSO_KERNEL_FS_H
#if 0
#define _ESPRESSO_KERNEL_FS_H
#include <types.h>
#define EKFS_FILENAME_MAX_LEN 64
enum {
EKFS_E_FILETOOSMALL = -16;
};
struct ekfs_inode {
char i_name[EKFS_FILENAME_MAX_LEN];
uint64_t i_start; /* LBA48 */
size_t i_len; /* rounded up to the nearest multiple of 512 */
} __attribute__((packed));
struct ekfs_ops {
int (*read)(struct ekfs_file*, void*, size_t);
int (*write)(struct ekfs_file*, void*, size_t);
};
struct ekfs_file {
struct ekfs_inode* f_inode;
size_t f_offset;
size_t f_refcount;
struct ekfs_ops f_ops;
};
int ekfs_read(struct ekfs_file* __f, void* __b, size_t __l);
#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

View File

@ -1,8 +1,6 @@
#ifndef _KERNEL_SHELL_H #ifndef _KERNEL_SHELL_H
#define _KERNEL_SHELL_H #define _KERNEL_SHELL_H
#include <types.h> void kshell_start(void);
int kshell_start(int argc, char** argv);
#endif #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

View File

@ -3,7 +3,8 @@
#define ESPRESSO_KERNEL_ #define ESPRESSO_KERNEL_
#define KERNEL_VERSION "0.0.2a" #define KERNEL_VERSION "0.0.2c"
#define KERNEL_RELEASE_YEAR "2026"
#define _STATE_NORMAL 0 #define _STATE_NORMAL 0
#define _STATE_HANDLED 1 #define _STATE_HANDLED 1
@ -18,4 +19,14 @@
#define __noreturn __attribute__((noreturn)) #define __noreturn __attribute__((noreturn))
#define __section(x) __attribute__((section(x))) #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 #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

73
include/new_tty.h Normal file
View File

@ -0,0 +1,73 @@
#ifndef _TTY_H
#define _TTY_H
#include <types.h>
#include <processes.h>
#include <sync.h>
#define TTY_BUFFER_SIZE 4096
#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_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;
spinlock_t lock;
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);
tty_t* get_active_tty(void);
tty_t* tty_get_active(void);
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

@ -1,10 +1,10 @@
#ifndef _PRINTF_H #ifndef _PRINTF_H
#define _PRINTF_H #define _PRINTF_H
#include <tty.h> //#include <tty.h>
#include <string.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); void printwc(const char*, uint8_t);

View File

@ -5,15 +5,17 @@
#include <drivers/elf.h> #include <drivers/elf.h>
typedef uint32_t pid_t;
typedef struct process { typedef struct process {
int32_t id; pid_t id;
int32_t group; pid_t group;
elf_executable_t* exe; elf_executable_t* exe;
struct process* next;
} process_t; } 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 #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,10 +4,23 @@
#include <types.h> #include <types.h>
#include <printf.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 getchar(void);
char* getstring(void); char* getstring(void);
char* gets(void); /* Use this instead of getstring() */ 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) static inline void putchar(char c)
{ {
printf("%c", c); printf("%c", c);

View File

@ -17,8 +17,10 @@ char* strdup(const char* s);
char* strtok(char* str, const char* delim); char* strtok(char* str, const char* delim);
char* strchr(const char* s, int c); char* strchr(const char* s, int c);
/* this function is NOT in the standard C library */ /* these functions are NOT in the standard C library */
int num_strchr(const char* s, int c); int num_strchr(const char* s, int c);
char* strnlstrip(const char* __s);
void strlnstripip(char* s);
void lowers(char* str); void lowers(char* str);
void uppers(char* str); void uppers(char* str);

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 #ifndef TTY_H
#define _TTY_H #define TTY_H
#include <types.h> #include <types.h>
@ -32,4 +32,7 @@ void terminal_set_cursor(uint16_t row, uint16_t column);
void terminal_get_cursor(int* row, int* column); void terminal_get_cursor(int* row, int* column);
void terminal_update_cursor(void); void terminal_update_cursor(void);
void terminal_putcharat(char c, uint16_t row, uint16_t column);
#endif #endif

View File

@ -5,6 +5,11 @@
#include <stddef.h> #include <stddef.h>
#include <stdbool.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 unsigned char uchar;
typedef uint8_t u8; typedef uint8_t u8;
@ -12,4 +17,19 @@ typedef uint16_t u16;
typedef uint32_t u32; typedef uint32_t u32;
typedef uint64_t u64; 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 #endif

View File

@ -13,11 +13,9 @@ char char_entered = 0x00;
void intro_begin(void) void intro_begin(void)
{ {
extern char* kernel_version; char* fin = (char*) malloc(strlen(KERNEL_VERSION) + 6);
memset(fin, 0, (strlen(KERNEL_VERSION) + 5));
char* fin = (char*) malloc(strlen(kernel_version) + 6); strcpy(fin, KERNEL_VERSION);
memset(fin, 0, (strlen(kernel_version) + 5));
strcpy(fin, kernel_version);
#ifdef _DEBUG #ifdef _DEBUG
strcat(fin, " DEBUG"); strcat(fin, " DEBUG");

View File

@ -16,6 +16,12 @@
#include <kernel/boot.h> #include <kernel/boot.h>
#include <kernel/kshell.h> #include <kernel/kshell.h>
#include <kernel/syscall.h>
#include <tty.h>
#include <vga/vga.h>
#include <new_tty.h>
#include <kdebug.h> #include <kdebug.h>
@ -23,54 +29,41 @@
#include <drivers/idt.h> #include <drivers/idt.h>
#include <drivers/irq.h> #include <drivers/irq.h>
#include <scheduler.h>
#include <multiboot.h> #include <multiboot.h>
#include <drivers/pci.h> #include <drivers/pci.h>
#include <drivers/ps2_keyboard.h> #include <drivers/ps2_keyboard.h>
#include <drivers/keyboard.h>
#include <drivers/pit.h> #include <drivers/pit.h>
/*#include <drivers/ahci.h>*/ /*#include <drivers/ahci.h>*/
#include <drivers/ide.h> #include <drivers/ide.h>
#include <mm/mm.h> #include <mm/mm.h>
#include <fs/fat32.h> #include <fs/fat32.h>
#include <fs/duckfs.h> /*#include <fs/duckfs.h>*/
#include <fs/vfs.h> #include <fs/vfs.h>
#include <fs/sfs.h>
#ifdef DEBUG_USE_SSE2
#include <vector_extensions/sse.h> #include <vector_extensions/sse.h>
#endif
#include <kernel/intro.h> #include <kernel/intro.h>
#include <builtin_games/miner.h> #include <builtin_games/miner.h>
#include <fs/ssfs.h>
#define DEBUG
extern void _hang_asm(void); extern void _hang_asm(void);
extern void _sti_asm(void); extern void _sti_asm(void);
char* espresso_str = ""
"####### ##### ###### ###### ####### ##### ##### #######\n"
"# # # # # # # # # # # # # #\n"
"# # # # # # # # # # #\n"
"##### ##### ###### ###### ##### ##### ##### # #\n"
"# # # # # # # # # #\n"
"# # # # # # # # # # # # #\n"
"####### ##### # # # ####### ##### ##### #######\n";
char* kernel_version = "0.0.2a";
void kernel_main(multiboot_info_t* mbd, uint32_t magic) void kernel_main(multiboot_info_t* mbd, uint32_t magic)
{ {
/* --- BEGIN INITIALIZATION SECTION --- */ /* --- BEGIN INITIALIZATION SECTION --- */
/* We need to initialize the terminal so that any error/debugging messages show. */ /* We need to initialize the terminal so that any error/debugging messages show. */
terminal_initialize(); terminal_initialize();
printf("Loading Espresso %s... ", kernel_version); printf("Loading Espresso %s... ", KERNEL_VERSION);
#ifdef _DEBUG #ifdef _DEBUG
printf("[ DEBUG BUILD ]"); printf("[ DEBUG BUILD ]");
@ -96,12 +89,8 @@ void kernel_main(multiboot_info_t* mbd, uint32_t magic)
gdt_install(false); gdt_install(false);
pic_remap(); pic_remap(); /* must be done before idt_init() */
idt_init(); idt_init();
_sti_asm();
irq_init(); /* MUST be done after pic_remap() and idt_init() */ irq_init(); /* MUST be done after pic_remap() and idt_init() */
terminal_setcolor(VGA_COLOR_GREEN); terminal_setcolor(VGA_COLOR_GREEN);
@ -112,44 +101,65 @@ void kernel_main(multiboot_info_t* mbd, uint32_t magic)
heap_init(0xC2000000, 0x80000); heap_init(0xC2000000, 0x80000);
#ifdef DEBUG_USE_SSE2
#ifdef _DEBUG
printd("Testing SSE...\n"); printd("Testing SSE...\n");
#endif
int32_t sse_test_result = test_sse(); int32_t sse_test_result = test_sse();
if (sse_test_result != 0) 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 else
{ {
#ifdef _DEBUG
printd("SSE test passed\n"); printd("SSE test passed\n");
#endif
} }
#endif
pit_init(); pit_init();
int j = init_tty();
if (j != 0)
{
printwc("[ ERROR ] init_tty failed\n", VGA_COLOR_RED);
while (1)
{
asm volatile ("nop" ::: "memory");
}
}
keyboard_init(); //keyboard_init();
init_keyboard();
ide_initialize(); ide_initialize();
pci_init(); pci_init();
init_sysints();
/*init_scheduler();*/
_sti_asm();
/* --- END INITIALIZATION SECTION --- */ /* --- END INITIALIZATION SECTION --- */
terminal_setcolor(VGA_COLOR_LIGHT_GREEN); terminal_setcolor(VGA_COLOR_LIGHT_GREEN);
printf("Guten tag and welcome to Espresso %s\n", kernel_version); printf("Guten tag and welcome to Espresso %s\n", KERNEL_VERSION);
sleep(1000); extern void terminal_clear(void);
intro_begin();
/*extern void terminal_clear(void);
terminal_clear(); terminal_clear();
kshell_start(1, NULL);*/ kshell_start();
while (true) for(;;) /* Loop infinitely. We only do something when an interrupt/syscall happens now. */
{ {
/* Loop infinitely. We only do something when a syscall happens now. */ asm volatile("hlt" ::: "memory");
} }
} }

View File

@ -6,6 +6,12 @@
#include <kernel/ksh_debug.h> #include <kernel/ksh_debug.h>
#include <arch/x86/intrin.h> #include <arch/x86/intrin.h>
#include <drivers/elf.h>
#include <kernel/syscall.h>
#include <scheduler.h>
#include <fs/fat16.h> #include <fs/fat16.h>
#include <kernel/kshell.h> #include <kernel/kshell.h>
@ -15,7 +21,7 @@ const char* shell_version = "0.0.2";
char* prompt = NULL; char* prompt = NULL;
int command = -1; int command = -1;
bool _debug = false; bool _debug = true;
int execute(void); int execute(void);
@ -44,18 +50,7 @@ static void print_intro(void)
printf("CPU: %s\n", _temp == NULL ? "No info" : _temp); printf("CPU: %s\n", _temp == NULL ? "No info" : _temp);
printf("CPU vendor: %s\n", temp_ == NULL ? "No info" : temp_); printf("CPU vendor: %s\n", temp_ == NULL ? "No info" : temp_);
printf("\nCopyright 2025 David J Goeke\n"); printf("\nCopyright %s David J Goeke\n", KERNEL_RELEASE_YEAR);
}
static void parse_opts(int argc, char** argv)
{
for (int i = 0; i < argc; i++)
{
if (strcmp(argv[i], "--color") == 0)
{
}
}
} }
static char* commands[] = { static char* commands[] = {
@ -76,19 +71,28 @@ static char* commands[] = {
"printrandom", "printrandom",
"acm", /* ACcess Memory */
"testfat16", "testfat16",
"printc",
"testscheduler",
"readfat16",
"help",
"exec",
"int16test",
NULL, NULL,
}; };
#define NUM_COMMANDS 15 /* Yes, including the NULL */ const int NUM_COMMANDS = 19; /* Yes, including the NULL */
int kshell_start(int argc, char** argv) void kshell_start(void)
{ {
(void)argc; printf("Welcome to the kshell!\n");
(void)argv;
prompt = strdup(">"); prompt = strdup(">");
@ -102,7 +106,17 @@ int kshell_start(int argc, char** argv)
{ {
printf("%s ", prompt); printf("%s ", prompt);
i = gets(); /*i = gets();*/
int j = 0;
i = gets_new(&j);
if (j == 0)
{
printf("Error?\n");
break;
}
i = strnlstrip(i);
command = -1; command = -1;
@ -165,14 +179,14 @@ int kshell_start(int argc, char** argv)
} while (1); } while (1);
if (i != NULL) if (i)
{ {
free(i); free(i);
} }
printf("Goodbye!\n"); printf("Goodbye!\n");
return 0; return;
} }
/* /*
@ -194,7 +208,7 @@ int kshell_start(int argc, char** argv)
"printrandom", "printrandom",
"acm", "testfat16",
NULL, NULL,
}; };
@ -321,31 +335,6 @@ int execute(void)
break; break;
} }
case 12: { case 12: {
printf("Enter hexadecimal address to access: ");
char* g = gets();
int val = atoi(g);
if (val == 0)
{
printf("Improper/Malformed string entered\n");
break;
}
else if (val < 0x100000)
{
printf("Invalid address, must be higher than 0x100000\n");
break;
}
int val_ = *((int*) val);
printf("value at %u: %i\n", val, val_);
break;
}
case 13: {
int retv = fat16_mount(0); int retv = fat16_mount(0);
if (retv != 0) if (retv != 0)
@ -402,6 +391,151 @@ int execute(void)
fat16_delete_file(fat_name); 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 0
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 = load_elf32(buffer);
printf("Attempting execution of executable...\n");
retv = f->entry_point();
printf("\nreturn value: %i\n", retv);
break;
}
case 18:
{
printf("testing int 16\n");
const char* str = "HELLO!\n";
syscall1(SYS_TERMINAL_WRITESTRING, str);
printf("test ran\n");
break; break;
} }
} }

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;
}

View File

@ -1,6 +0,0 @@
#ifndef _KERNEL_INCLUDE_H
#define _KERNEL_INCLUDE_H
#define KERNEL_VERSION "0.0.2a"
#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;
}

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

@ -111,7 +111,12 @@ void free(void* ptr)
block_t* curr = free_list; block_t* curr = free_list;
while (curr && curr->next) while (curr && curr->next)
{ {
if (curr->free && curr->next->free) /*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->size += BLOCK_SIZE + curr->next->size;
curr->next = curr->next->next; curr->next = curr->next->next;

View File

@ -12,6 +12,10 @@ static size_t total_pages;
#define BITMAP_CLEAR(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))) #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) void pmm_init(multiboot_info_t* mb)
{ {
#ifdef _DEBUG #ifdef _DEBUG
@ -45,6 +49,18 @@ void pmm_init(multiboot_info_t* mb)
} }
} }
total_pages = MAX_PAGES; 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 #ifdef _DEBUG
printf("[ PMM ] Physical memory manager initialized\n"); printf("[ PMM ] Physical memory manager initialized\n");
@ -55,6 +71,14 @@ void* pmm_alloc_page(void)
{ {
for (uint32_t i = 0; i < total_pages; ++i) for (uint32_t i = 0; i < total_pages; ++i)
{ {
void* page = (void*)(i * 4096);
if ((uintptr_t)page >= (uintptr_t)&__kernel_start &&
(uintptr_t)page < (uintptr_t)&__kernel_end)
{
printf("PMM allocating inside kernel at %x\n", page);
}
if (!BITMAP_TEST(i)) if (!BITMAP_TEST(i))
{ {
BITMAP_SET(i); BITMAP_SET(i);

View File

@ -4,6 +4,8 @@
#include <stdint.h> #include <stdint.h>
#include <drivers/serio.h> #include <drivers/serio.h>
#include <tty.h>
#include <printf.h> #include <printf.h>
static uint8_t color = 0xFF; static uint8_t color = 0xFF;

View File

@ -3,13 +3,18 @@
#include <processes.h> #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) 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

@ -2,8 +2,45 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <kernel/syscall.h>
#include <tty.h>
#include <new_tty.h>
#include <stdio.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* sptr = (char*) data; /* this really shouldn't be needed... */
sptr = gets_new(&rv);
}
else
{
return -1;
}
return rv;
}
extern bool ps2keyboard_initialized; extern bool ps2keyboard_initialized;
char getchar(void) char getchar(void)
@ -31,40 +68,33 @@ char* gets(void)
return kbd_gets(); return kbd_gets();
} }
char* gets_new(int* num)
/*char* fgets(char* buf, int n, FILE file)
{ {
if (!buf || n <= 1 || file < 1) 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; strcpy(dest, p);
char c; }
while (total_read < n - 1) void putc(char c)
{ {
int bytes = 0*//*read_file(file, &c, 1)*/; syscall1(SYS_TERMINAL_PUTCHAR, c);
}
/*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;
}*/

View File

@ -1,10 +1,12 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <vector_extensions/sse.h>
#include <string.h> #include <string.h>
#ifdef DEBUG_USE_SSE2
#include <vector_extensions/sse.h>
extern int32_t sse_initialized; extern int32_t sse_initialized;
#endif
size_t strlen(const char* str) size_t strlen(const char* str)
{ {
@ -76,10 +78,12 @@ char* strcpy(char *dst, const char *src)
char* strncpy(char *dest, const char *src, uint32_t n) char* strncpy(char *dest, const char *src, uint32_t n)
{ {
#ifdef DEBUG_USE_SSE2
if (sse_initialized > 0) if (sse_initialized > 0)
{ {
return sse2_strncpy(dest, src, n); return sse2_strncpy(dest, src, n);
} }
#endif
uint32_t i = 0; uint32_t i = 0;
for (; i < n && src[i]; ++i) for (; i < n && src[i]; ++i)
@ -217,10 +221,12 @@ void* memset(void* dst, int c, size_t n)
void* memcpy(void *dst, const void *src, uint32_t n) void* memcpy(void *dst, const void *src, uint32_t n)
{ {
#ifdef DEBUG_USE_SSE2
if (sse_initialized > 1) if (sse_initialized > 1)
{ {
return sse2_memcpy(dst, src, n); return sse2_memcpy(dst, src, n);
} }
#endif
char *d = dst; char *d = dst;
const char *s = src; const char *s = src;
@ -234,8 +240,8 @@ void* memcpy(void *dst, const void *src, uint32_t n)
int32_t memcmp(const void *s1, const void *s2, size_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 *p1 = (const uint8_t*) s1;
const uint8_t *p2 = (const uint8_t *)s2; 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);*/
@ -252,10 +258,12 @@ int32_t memcmp(const void *s1, const void *s2, size_t n)
void* memclr(void* m_start, size_t m_count) void* memclr(void* m_start, size_t m_count)
{ {
#ifdef DEBUG_USE_SSE2
if (sse_initialized > 1) if (sse_initialized > 1)
{ {
return memclr_sse2(m_start, m_count); return memclr_sse2(m_start, m_count);
} }
#endif
return memset(m_start, '\0', (uint32_t)m_count); return memset(m_start, '\0', (uint32_t)m_count);
} }
@ -451,3 +459,36 @@ double atof(const char *str)
return sign * (res + frac / frac_div); 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';
}
}

40
lib/sync.c Normal file
View File

@ -0,0 +1,40 @@
#include <sync.h>
void spinlock_init(spinlock_t* lock)
{
lock->locked = 0;
}
static inline int atomic_xchg(volatile int* addr, int newval)
{
int result;
asm volatile (
"xchg %0, %1"
: "=r"(result), "+m"(*addr)
: "0"(newval)
: "memory"
);
return result;
}
void spin_lock(spinlock_t* lock)
{
while (atomic_xchg(&lock->locked, 1))
{
while (lock->locked)
{
asm volatile("pause");
}
}
}
void spin_unlock(spinlock_t* lock)
{
__atomic_clear(&lock->locked, __ATOMIC_RELEASE);
}

View File

@ -1,3 +1,5 @@
#ifdef DEBUG_USE_SSE2
#include <types.h> #include <types.h>
#include <stdio.h> #include <stdio.h>
@ -248,3 +250,5 @@ void* memclr_sse2(void *m_start, size_t m_count)
return m_start; return m_start;
} }
#endif

9
libc/include/stdio.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef LIBC_STDIO_H
#define LIBC_STDIO_H
int writestring(const char* __s);
void writechar(char __c);
int getstring(char* __str);
#endif

19
libc/include/string.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef _LIBC_STRING_H
#define _LIBC_STRING_H
#include <stddef.h>
#include <stdint.h>
size_t strlen(const char* str);
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
char* strcpy(char *dst, const char *src);
char* strncpy(char *dest, const char *src, uint32_t n);
char* strcat(char *dest, const char *src);
/*char* strdup(const char* s);*/
int memcmp(const void *s1, const void *s2, size_t n);
void* memcpy(void *dst, const void *src, uint32_t n);
void* memset(void* dst, int c, size_t n);
#endif

22
libc/stdio.c Normal file
View File

@ -0,0 +1,22 @@
#include "include/string.h"
#include "../syscall.h"
#include "include/stdio.h"
int writestring(const char* __s)
{
/*syscall1(SYS_TERMINAL_WRITESTRING, __s);*/
return syscall3(SYS_WRITE, 1, __s, strlen(__s));
}
void writechar(char __c)
{
syscall1(SYS_TERMINAL_PUTCHAR, __c);
}
int getstring(char* __str)
{
return syscall3(SYS_READ, 0, __str, 0);
}

125
libc/string.c Normal file
View File

@ -0,0 +1,125 @@
#include <stdint.h>
#include <stddef.h>
#include "include/string.h"
size_t strlen(const char* str)
{
size_t len = 0;
while (str[len])
{
len++;
}
return len;
}
int strcmp(const char *s1, const char *s2)
{
while (*s1 && (*s1 == *s2))
{
s1++;
s2++;
}
return (unsigned char)*s1 - (unsigned char)*s2;
}
int strncmp(const char *s1, const char *s2, size_t n)
{
while (n--)
{
unsigned char c1 = (unsigned char)*s1++;
unsigned char c2 = (unsigned char)*s2++;
if (c1 != c2)
{
return c1 - c2;
}
if (c1 == '\0')
{
break;
}
}
return 0;
}
char* strcpy(char *dst, const char *src)
{
char *ret = dst;
while ((*dst++ = *src++) != 0);
return ret;
}
char* strncpy(char *dest, const char *src, uint32_t n)
{
uint32_t i = 0;
for (; i < n && src[i]; ++i)
{
dest[i] = src[i];
}
for (; i < n; ++i)
{
dest[i] = '\0';
}
return dest;
}
char* strcat(char *dest, const char *src)
{
char *end = dest + strlen(dest);
while (*src)
{
*end++ = *src++;
}
*end = '\0';
return dest;
}
/*char* strdup(const char* s)
{
if (!s)
{
return NULL;
}
size_t len = strlen(s);
char* copy = (char*)malloc(len + 1);
if (!copy)
{
return NULL;
}
memcpy(copy, s, len);
copy[len] = '\0';
return copy;
}*/
void* memset(void* dst, int c, size_t 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)
{
char *d = dst;
const char *s = src;
while (n--)
{
*d++ = *s++;
}
return dst;
}

110
syscall.h Normal file
View File

@ -0,0 +1,110 @@
#ifndef _ESPRESSO_SYSCALL_H
#define _ESPRESSO_SYSCALL_H
/*
Use this file to use syscalls in Espresso.
do not use kernel/syscall.h, because it has some defiitions which are not used/needed here.
*/
#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);
#endif

View File

@ -0,0 +1,3 @@
https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-_005f_005fbuiltin_005fprefetch
https://gcc.gnu.org/onlinedocs/gcc/Bit-Operation-Builtins.html

BIN
user/hello.elf Executable file

Binary file not shown.

75
user/test.c Normal file
View File

@ -0,0 +1,75 @@
#include "../libc/include/stdio.h"
#include "../libc/include/string.h"
/*extern void writestring(const char* __s);
extern char* getstring(void);*/
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--)
{
writechar(buffer[i]);
}
}
int main(void)
{
while (1)
{
writestring("command: ");
char* istr;
int rv = getstring(istr);
if (!istr)
{
writestring("\nERROR: getstring returned NULL\n");
break;
}
if (rv != 0)
{
writestring("\nERROR: getstring did not return 0\n");
break;
}
size_t len = strlen(istr);
if (len > 0 && istr[len - 1] == '\n')
{
istr[len - 1] = '\0';
}
writestring("you entered: ");
writestring(istr);
writestring(" ASCII -> ");
for (size_t n = 0; n < (len + 1); n++)
{
print_uint(istr[n]);
writechar(' ');
}
writechar('\n');
if (strcmp(istr, "exit") == 0)
{
return 0;
}
}
return 0;
}