Espresso 0.0.2c
This commit is contained in:
20
.gitignore
vendored
Normal file
20
.gitignore
vendored
Normal 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
15
FEATURES.md
Normal 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)
|
||||
24
Makefile
24
Makefile
@ -1,18 +1,19 @@
|
||||
# === Config ===
|
||||
TARGET := boot/espresso.elf
|
||||
ISO := boot/espresso.iso
|
||||
FAT16_DISK := espresso.img
|
||||
CC := i686-elf-gcc
|
||||
AS := i686-elf-as
|
||||
NASM := nasm
|
||||
QEMU_MKE_IMG := qemu-img create -f raw espresso.img 64M
|
||||
QEMU_MKE_IMG := qemu-img create -f raw $(FAT16_DISK) 64M
|
||||
MKFS_VFAT := sudo mkfs.vfat
|
||||
MKFS_FLAGS := -F 16 -S 512
|
||||
NASMFLAGS := -f elf32
|
||||
WNOFLAGS := -Wno-discarded-qualifiers
|
||||
CFLAGS := -std=gnu99 -ffreestanding -O2 -Wall -Wextra -msse $(WNOFLAGS) -nostdlib -nostartfiles -include include/kincl.h
|
||||
LDFLAGS := -T linker.ld -ffreestanding -O2 -nostdlib -nostartfiles
|
||||
QEMUFLAGS := -boot d -cdrom $(ISO) -drive file=espresso.img,format=raw,if=ide,readonly=off,rerror=report,werror=report -cpu qemu32,sse4.1
|
||||
QEMUFLGS_EXT := -vga std -d int,cpu_reset -D qemu.log -no-reboot #-singlestep
|
||||
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 # -audiodev pa,id=speaker -machine pcspk-audiodev=speaker
|
||||
MOR_QEMUFLGS := -net none -netdev user,id=n0 -device rtl8139,netdev=n0 -serial file:serial.log
|
||||
SRC_DIRS := kernel drivers lib
|
||||
INCLUDE_DIRS := include
|
||||
@ -78,10 +79,10 @@ iso: $(TARGET)
|
||||
|
||||
# === Run in QEMU ===
|
||||
run: iso
|
||||
@if [ ! -f espresso.img ]; then \
|
||||
@if [ ! -f $(FAT16_DISK) ]; then \
|
||||
$(QEMU_MKE_IMG); \
|
||||
sudo mkfs.fat $(MKFS_FLAGS) espresso.img; \
|
||||
fi
|
||||
sudo mkfs.fat $(MKFS_FLAGS) espresso.img
|
||||
@echo
|
||||
qemu-system-i386 $(QEMUFLAGS) $(QEMUFLGS_EXT) $(MOR_QEMUFLGS)
|
||||
|
||||
@ -90,6 +91,17 @@ run: iso
|
||||
clean:
|
||||
rm -f $(INTERNAL_OBJS) $(TARGET) $(ISO)
|
||||
rm -rf $(ISO_DIR)
|
||||
|
||||
clean_disk:
|
||||
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
24
TODO.md
Normal 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
18
arch/x86/exec/secf.s
Normal 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
|
||||
231
arch/x86/isr.asm
231
arch/x86/isr.asm
@ -1,163 +1,152 @@
|
||||
[BITS 32]
|
||||
|
||||
[GLOBAL isr_stub_table]
|
||||
[GLOBAL irq_stub_table]
|
||||
extern irq_handler ; C function
|
||||
[GLOBAL interrupt_entry]
|
||||
|
||||
extern interrupt_dispatcher
|
||||
|
||||
section .text
|
||||
|
||||
; --------------------------------------------
|
||||
; ------------------- IRQs -------------------
|
||||
; --------------------------------------------
|
||||
; ============================================================
|
||||
; COMMON INTERRUPT ENTRY
|
||||
; ============================================================
|
||||
|
||||
interrupt_entry:
|
||||
|
||||
; Stack already contains:
|
||||
; err_code
|
||||
; int_no
|
||||
; eip
|
||||
; cs
|
||||
; eflags
|
||||
|
||||
pusha ; eax, ecx, edx, ebx, esp, ebp, esi, edi
|
||||
|
||||
%macro irq_stub 1
|
||||
irq_stub_%+%1:
|
||||
pusha
|
||||
push ds
|
||||
push es
|
||||
push fs
|
||||
push gs
|
||||
push fs
|
||||
push es
|
||||
push ds
|
||||
|
||||
mov ax, 0x10
|
||||
mov ax, 0x10 ; load kernel data selector
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
push dword %1 ; Push IRQ number
|
||||
call irq_handler
|
||||
add esp, 4 ; Clean up stack
|
||||
push esp ; pass pointer to registers_t
|
||||
call interrupt_dispatcher
|
||||
add esp, 4 ; I don't remember what this does... but don't remove it
|
||||
; NVM, I remember: it cleans up the registers_t* argument we passed to interrupt_dispatcher
|
||||
|
||||
; Send EOI
|
||||
mov al, 0x20
|
||||
mov bl, %1
|
||||
cmp bl, 8
|
||||
jb .skip_slave_eoi
|
||||
out 0xA0, al
|
||||
.skip_slave_eoi:
|
||||
out 0x20, al
|
||||
; don't do this yet, it corrupts stuff. wait until the scheduler is finished
|
||||
;mov esp, eax ; move the new stack pointer into esp
|
||||
|
||||
pop gs
|
||||
pop fs
|
||||
pop es
|
||||
pop ds
|
||||
|
||||
popa
|
||||
iret
|
||||
|
||||
add esp, 8 ; remove int_no + err_code
|
||||
|
||||
iret ; return from interrupt
|
||||
|
||||
|
||||
; ============================================================
|
||||
; IRQ STUBS
|
||||
; ============================================================
|
||||
|
||||
%macro IRQ 1
|
||||
irq_stub_%+%1:
|
||||
push dword 0 ; fake error code
|
||||
push dword (32 + %1) ; vector number
|
||||
jmp interrupt_entry
|
||||
%endmacro
|
||||
|
||||
|
||||
; Define 16 IRQ stubs
|
||||
irq_stub 0
|
||||
irq_stub 1
|
||||
irq_stub 2
|
||||
irq_stub 3
|
||||
irq_stub 4
|
||||
irq_stub 5
|
||||
irq_stub 6
|
||||
irq_stub 7
|
||||
irq_stub 8
|
||||
irq_stub 9
|
||||
irq_stub 10
|
||||
irq_stub 11
|
||||
irq_stub 12
|
||||
irq_stub 13
|
||||
irq_stub 14
|
||||
irq_stub 15
|
||||
IRQ 0
|
||||
IRQ 1
|
||||
IRQ 2
|
||||
IRQ 3
|
||||
IRQ 4
|
||||
IRQ 5
|
||||
IRQ 6
|
||||
IRQ 7
|
||||
IRQ 8
|
||||
IRQ 9
|
||||
IRQ 10
|
||||
IRQ 11
|
||||
IRQ 12
|
||||
IRQ 13
|
||||
IRQ 14
|
||||
IRQ 15
|
||||
IRQ 16
|
||||
IRQ 17
|
||||
IRQ 18
|
||||
IRQ 19
|
||||
|
||||
irq_stub_table:
|
||||
%assign i 0
|
||||
%rep 16
|
||||
%rep 20
|
||||
dd irq_stub_%+i
|
||||
%assign i i+1
|
||||
%endrep
|
||||
|
||||
; --------------------------------------------
|
||||
; ------------------- ISRs -------------------
|
||||
; --------------------------------------------
|
||||
|
||||
; Common exception handler entry point
|
||||
isr_common_handler:
|
||||
pusha ; Push general-purpose registers
|
||||
push ds
|
||||
push es
|
||||
push fs
|
||||
push gs
|
||||
; ============================================================
|
||||
; EXCEPTION STUBS
|
||||
; ============================================================
|
||||
|
||||
; Load known-good segment selectors
|
||||
mov ax, 0x10
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
; Print exception number and error code
|
||||
; You can insert direct port writes or call kernel logging function here
|
||||
; For now, just hang
|
||||
.halt:
|
||||
cli
|
||||
hlt
|
||||
jmp .halt
|
||||
|
||||
; If you want to later restore:
|
||||
pop gs
|
||||
pop fs
|
||||
pop es
|
||||
pop ds
|
||||
popa
|
||||
add esp, 8 ; clean up int_no + err_code
|
||||
iret
|
||||
|
||||
; Macro: for exceptions with error code
|
||||
%macro isr_err_stub 1
|
||||
%macro ISR_NOERR 1
|
||||
isr_stub_%+%1:
|
||||
cli
|
||||
push dword %1 ; interrupt number
|
||||
jmp isr_common_handler
|
||||
push dword 0 ; fake error code
|
||||
push dword %1 ; interrupt number
|
||||
jmp interrupt_entry
|
||||
%endmacro
|
||||
|
||||
; Macro: for exceptions without error code
|
||||
%macro isr_no_err_stub 1
|
||||
%macro ISR_ERR 1
|
||||
isr_stub_%+%1:
|
||||
cli
|
||||
push dword 0 ; fake error code
|
||||
push dword %1 ; interrupt number
|
||||
jmp isr_common_handler
|
||||
push dword %1 ; interrupt number
|
||||
jmp interrupt_entry
|
||||
%endmacro
|
||||
|
||||
; Define all 32 exception stubs
|
||||
isr_no_err_stub 0
|
||||
isr_no_err_stub 1
|
||||
isr_no_err_stub 2
|
||||
isr_no_err_stub 3
|
||||
isr_no_err_stub 4
|
||||
isr_no_err_stub 5
|
||||
isr_no_err_stub 6
|
||||
isr_no_err_stub 7
|
||||
isr_err_stub 8
|
||||
isr_no_err_stub 9
|
||||
isr_err_stub 10
|
||||
isr_err_stub 11
|
||||
isr_err_stub 12
|
||||
isr_err_stub 13
|
||||
isr_err_stub 14
|
||||
isr_no_err_stub 15
|
||||
isr_no_err_stub 16
|
||||
isr_err_stub 17
|
||||
isr_no_err_stub 18
|
||||
isr_no_err_stub 19
|
||||
isr_no_err_stub 20
|
||||
isr_no_err_stub 21
|
||||
isr_no_err_stub 22
|
||||
isr_no_err_stub 23
|
||||
isr_no_err_stub 24
|
||||
isr_no_err_stub 25
|
||||
isr_no_err_stub 26
|
||||
isr_no_err_stub 27
|
||||
isr_no_err_stub 28
|
||||
isr_no_err_stub 29
|
||||
isr_err_stub 30
|
||||
isr_no_err_stub 31
|
||||
|
||||
; Create jump table
|
||||
; Exceptions 0–31
|
||||
|
||||
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
|
||||
|
||||
386
boot/dump.txt
Normal file
386
boot/dump.txt
Normal 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
46
drivers/audio/pcspeaker.c
Normal 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);
|
||||
}
|
||||
@ -13,10 +13,10 @@
|
||||
|
||||
elf_executable_t* load_elf32(void* elf_data)
|
||||
{
|
||||
/*Elf32_Ehdr* ehdr = (Elf32_Ehdr*)elf_data;*/
|
||||
Elf32_Ehdr* ehdr = (Elf32_Ehdr*)elf_data;
|
||||
|
||||
/* Check ELF magic */
|
||||
/*if (memcmp(ehdr->e_ident, (uint8_t*)("\x7F""ELF"), 4) != 0)
|
||||
if (memcmp(ehdr->e_ident, (uint8_t*)("\x7F""ELF"), 4) != 0)
|
||||
{
|
||||
printf("Invalid ELF file\n");
|
||||
return NULL;
|
||||
@ -30,7 +30,8 @@ elf_executable_t* load_elf32(void* elf_data)
|
||||
|
||||
Elf32_Phdr* phdrs = (Elf32_Phdr*)((uint8_t*)elf_data + ehdr->e_phoff);
|
||||
|
||||
for (int i = 0; i < ehdr->e_phnum; i++) {
|
||||
for (int i = 0; i < ehdr->e_phnum; i++)
|
||||
{
|
||||
Elf32_Phdr* phdr = &phdrs[i];
|
||||
if (phdr->p_type != PT_LOAD)
|
||||
{
|
||||
@ -43,7 +44,7 @@ elf_executable_t* load_elf32(void* elf_data)
|
||||
|
||||
for (uint32_t page = 0; page < segment_pages; page++)
|
||||
{
|
||||
void* phys = alloc_page();
|
||||
void* phys = pmm_alloc_page();
|
||||
void* virt = (void*)(vaddr_start + page * PAGE_SIZE);
|
||||
map_page(phys, virt);
|
||||
memset(virt, 0, PAGE_SIZE);
|
||||
@ -53,12 +54,15 @@ elf_executable_t* load_elf32(void* elf_data)
|
||||
void* src = (uint8_t*)elf_data + phdr->p_offset;
|
||||
memcpy(dest, src, phdr->p_filesz);
|
||||
|
||||
printf("Mapped segment %d: 0x%08x–0x%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));
|
||||
result->entry_point = (void*)(uintptr_t)ehdr->e_entry;
|
||||
return result;*/
|
||||
result->entry_point = (elf_entry_t)(uintptr_t)ehdr->e_entry;
|
||||
return result;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
48
drivers/exec/secf.c
Normal file
48
drivers/exec/secf.c
Normal 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
49
drivers/fs/ekfs.c
Normal 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
374
drivers/fs/fat16.c
Normal 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(§or_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 = §or[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
|
||||
}
|
||||
|
||||
@ -1,24 +1,76 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <tty.h>
|
||||
|
||||
#include <fs/vfs.h>
|
||||
|
||||
/* we use something similar to the Linux kernel in terms of a VFS system */
|
||||
|
||||
typedef struct vfs_file_header {
|
||||
char* filename; /* The filename, not the path. */
|
||||
#define MAX_FDS 64
|
||||
|
||||
int32_t fd;
|
||||
struct inode {
|
||||
size_t size;
|
||||
int permissions;
|
||||
void *fs_data; /* FS-specific */
|
||||
};
|
||||
|
||||
uint8_t type_info; /* Bits 0 - 3 -> File type, Bits 4 - 7 FS type */
|
||||
struct file_ops {
|
||||
int (*read)(struct file*, char*, size_t);
|
||||
int (*write)(struct file*, const char*, size_t);
|
||||
};
|
||||
|
||||
uint16_t* fs_header;
|
||||
|
||||
struct vfs_file_header* next; /* Linked list */
|
||||
} vfs_file_header_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.
|
||||
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.
|
||||
*/
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
uint64_t gdt[GDT_ENTRIES];
|
||||
|
||||
struct {
|
||||
uint16_t limit;
|
||||
uint32_t base;
|
||||
uint16_t limit;
|
||||
uint32_t base;
|
||||
} __attribute__((packed)) gp;
|
||||
|
||||
|
||||
|
||||
225
drivers/idt.c
225
drivers/idt.c
@ -1,6 +1,11 @@
|
||||
#include <stdio.h>
|
||||
#include <port_io.h>
|
||||
|
||||
#include <scheduler.h>
|
||||
#include <kernel/syscall.h>
|
||||
|
||||
#include <drivers/irq.h>
|
||||
|
||||
#include <drivers/idt.h>
|
||||
|
||||
|
||||
@ -29,8 +34,7 @@ typedef struct {
|
||||
} __attribute__((packed)) idtr_t;
|
||||
|
||||
__attribute__((aligned(0x10)))
|
||||
|
||||
static idt_entry_t idt[256]; // Create an array of IDT entries; aligned for performance
|
||||
static idt_entry_t idt[256]; /* create an array of IDT entries; aligned for performance */
|
||||
|
||||
static idtr_t idtr;
|
||||
|
||||
@ -38,91 +42,6 @@ static bool vectors[IDT_MAX_DESCRIPTORS];
|
||||
|
||||
extern void* isr_stub_table[];
|
||||
|
||||
|
||||
__attribute__((noreturn))
|
||||
void exception_dispatcher(uint32_t int_no, uint32_t err_code)
|
||||
{
|
||||
switch (int_no)
|
||||
{
|
||||
case 0:
|
||||
printf("Divide by zero exception\n");
|
||||
break;
|
||||
case 13:
|
||||
printf("General Protection Fault: err=0x%x\n", err_code);
|
||||
break;
|
||||
case 14:
|
||||
{
|
||||
uint32_t cr2;
|
||||
asm volatile ("mov %%cr2, %0" : "=r"(cr2));
|
||||
printf("Page Fault at address: 0x%x, err=0x%x\n", cr2, err_code);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("Unhandled exception #%u, err=0x%x\n", int_no, err_code);
|
||||
break;
|
||||
}
|
||||
|
||||
uint16_t cs, ds, es, ss;
|
||||
asm volatile ("mov %%cs, %0" : "=r"(cs));
|
||||
asm volatile ("mov %%ds, %0" : "=r"(ds));
|
||||
asm volatile ("mov %%es, %0" : "=r"(es));
|
||||
asm volatile ("mov %%ss, %0" : "=r"(ss));
|
||||
|
||||
printf("CS=0x%04x DS=0x%04x ES=0x%04x SS=0x%04x\n", cs, ds, es, ss);
|
||||
|
||||
asm volatile ("cli; hlt");
|
||||
|
||||
/* Will never be reached */
|
||||
while (true)
|
||||
{
|
||||
asm volatile ("hlt" ::: "memory");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void idt_set_descriptor(uint8_t vector, void* isr, uint8_t flags)
|
||||
{
|
||||
idt_entry_t* descriptor = &idt[vector];
|
||||
|
||||
descriptor->isr_low = (uint32_t)isr & 0xFFFF;
|
||||
descriptor->kernel_cs = 0x08;
|
||||
descriptor->attributes = flags;
|
||||
descriptor->isr_high = (uint32_t)isr >> 16;
|
||||
descriptor->reserved = 0;
|
||||
}
|
||||
|
||||
void pic_remap(void)
|
||||
{
|
||||
uint8_t a1, a2;
|
||||
|
||||
/* Save masks */
|
||||
a1 = inb(PIC1_DATA);
|
||||
a2 = inb(PIC2_DATA);
|
||||
|
||||
/* Start initialization sequence (in cascade mode) */
|
||||
outb(PIC1_COMMAND, 0x11);
|
||||
outb(PIC2_COMMAND, 0x11);
|
||||
|
||||
/* Set vector offset */
|
||||
outb(PIC1_DATA, 0x20); /* IRQs 0-7 mapped to IDT entries 0x20-0x27 (32–39) */
|
||||
outb(PIC2_DATA, 0x28); /* IRQs 8-15 mapped to IDT entries 0x28-0x2F (40–47) */
|
||||
|
||||
/* Tell Master PIC about Slave PIC at IRQ2 (0000 0100) */
|
||||
outb(PIC1_DATA, 0x04);
|
||||
|
||||
/* Tell Slave PIC its cascade identity (0000 0010) */
|
||||
outb(PIC2_DATA, 0x02);
|
||||
|
||||
/* Set 8086/88 mode */
|
||||
outb(PIC1_DATA, 0x01);
|
||||
outb(PIC2_DATA, 0x01);
|
||||
|
||||
/* Restore saved masks */
|
||||
outb(PIC1_DATA, a1);
|
||||
outb(PIC2_DATA, a2);
|
||||
}
|
||||
|
||||
void idt_init(void)
|
||||
{
|
||||
idtr.base = (uintptr_t)&idt[0];
|
||||
@ -136,13 +55,141 @@ void idt_init(void)
|
||||
|
||||
extern void* irq_stub_table[];
|
||||
|
||||
for (uint8_t i = 0; i < 16; i++)
|
||||
for (uint8_t i = 0; i < 20; i++)
|
||||
{
|
||||
idt_set_descriptor(32 + i, irq_stub_table[i], 0x8E);
|
||||
}
|
||||
|
||||
|
||||
asm volatile ("lidt %0" : : "m"(idtr)); /* load the new IDT */
|
||||
asm volatile ("sti"); /* set the interrupt flag */
|
||||
//asm volatile ("sti"); /* set the interrupt flag */
|
||||
}
|
||||
|
||||
registers_t* interrupt_dispatcher(registers_t* regs)
|
||||
{
|
||||
if (regs->int_no < 32)
|
||||
{
|
||||
printf("external: %s, IDT/GDT: %s, ", ((regs->err_code & 0x0001) ? "true" : "false"), (regs->err_code & 0x0006) ? "IDT" : "GDT");
|
||||
printf("LDT: %s, selector: %x (%i)\n", ((regs->err_code & 0x0006) == 0b10) ? "true" : "false", regs->err_code & 0xFFF8, regs->err_code & 0xFFF8);
|
||||
printf("int: %i (%x), err: %i (%x)\n", regs->int_no, regs->int_no, regs->err_code, regs->err_code);
|
||||
exception_handler(regs);
|
||||
}
|
||||
else if (regs->int_no < 52)
|
||||
{
|
||||
uint32_t irq = regs->int_no - 32;
|
||||
|
||||
regs = irq_handler(irq, regs);
|
||||
|
||||
if (irq >= 8)
|
||||
{
|
||||
outb(0xA0, 0x20); /* acknowledge the IRQ to slave PIC */
|
||||
}
|
||||
|
||||
outb(0x20, 0x20); /* acknowledge the IRQ to master PIC */
|
||||
}
|
||||
|
||||
return regs;
|
||||
}
|
||||
|
||||
__noreturn
|
||||
void exception_handler(registers_t* regs)
|
||||
{
|
||||
uint32_t int_no = regs->int_no;
|
||||
uint32_t err_code = regs->err_code;
|
||||
|
||||
switch (int_no)
|
||||
{
|
||||
case 0:
|
||||
printf("Divide by zero exception (or other division error)\n");
|
||||
break;
|
||||
case 2:
|
||||
printf("NMI encountered\n");
|
||||
break;
|
||||
case 6: /* XXX: NOTE: this can be used to emulate instructions that do not exist on the current CPU :NOTE :XXX */
|
||||
printf("Invalid opcode encountered at %p\n", regs->eip);
|
||||
break;
|
||||
case 7: /* XXX: NOTE: use this for FPU emulation and for saving/restoring FPU registers in a multiprocessing enviroment :NOTE :XXX */
|
||||
printf("FPU instructions used, but FPU is nonexistant/disabled\n");
|
||||
break;
|
||||
case 8: /* double fault */
|
||||
printf("Double fault at %p, err %i\n", regs->eip, regs->err_code);
|
||||
break;
|
||||
case 13:
|
||||
printf("General Protection Fault: err=0x%x at %p\n", err_code, regs->eip);
|
||||
break;
|
||||
case 14:
|
||||
{
|
||||
uint32_t cr2;
|
||||
asm volatile ("mov %%cr2, %0" : "=r"(cr2));
|
||||
printf("PF addr=%p eip=%p err=%x\n", cr2, regs->eip, err_code);
|
||||
//printf("Page Fault at address: 0x%x, err=0x%x\n", cr2, err_code);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("Unhandled exception #%u, err=0x%x at %p\n", int_no, err_code, regs->eip);
|
||||
break;
|
||||
}
|
||||
|
||||
uint16_t cs, ds, es, ss;
|
||||
asm volatile ("mov %%cs, %0" : "=r"(cs));
|
||||
asm volatile ("mov %%ds, %0" : "=r"(ds));
|
||||
asm volatile ("mov %%es, %0" : "=r"(es));
|
||||
asm volatile ("mov %%ss, %0" : "=r"(ss));
|
||||
|
||||
if (((uint16_t) regs->cs != cs) || ((uint16_t) regs->ds != ds) || ((uint16_t) regs->es != es))
|
||||
{
|
||||
printf("segment register mismatch!\n");
|
||||
}
|
||||
|
||||
printf("cs: 0x%x, ds: 0x%x, es: 0x%x,\nss: 0x%x, fs: 0x%x, gs: 0x%x\n", regs->cs, regs->ds, regs->es, ss, regs->fs, regs->gs);
|
||||
|
||||
asm volatile ("cli; hlt");
|
||||
|
||||
/* Will never be reached */
|
||||
while (true)
|
||||
{
|
||||
asm volatile ("hlt" ::: "memory");
|
||||
}
|
||||
}
|
||||
|
||||
void idt_set_descriptor(uint8_t vector, void* isr, uint8_t flags)
|
||||
{
|
||||
idt_entry_t* descriptor = &idt[vector];
|
||||
|
||||
descriptor->isr_low = (uint32_t) isr & 0xFFFF;
|
||||
descriptor->kernel_cs = 0x08;
|
||||
descriptor->attributes = flags;
|
||||
descriptor->isr_high = (uint32_t) isr >> 16;
|
||||
descriptor->reserved = 0;
|
||||
}
|
||||
|
||||
void pic_remap(void)
|
||||
{
|
||||
uint8_t a1, a2;
|
||||
|
||||
/* save masks */
|
||||
a1 = inb(PIC1_DATA);
|
||||
a2 = inb(PIC2_DATA);
|
||||
|
||||
/* start initialization sequence (in cascade mode) */
|
||||
outb(PIC1_COMMAND, 0x11);
|
||||
outb(PIC2_COMMAND, 0x11);
|
||||
|
||||
/* set vector offset */
|
||||
outb(PIC1_DATA, 0x20); /* IRQs 0-7 mapped to IDT entries 0x20-0x27 (32–39) */
|
||||
outb(PIC2_DATA, 0x28); /* IRQs 8-15 mapped to IDT entries 0x28-0x2F (40–47) */
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
@ -3,46 +3,74 @@
|
||||
#include <drivers/pit.h>
|
||||
#include <port_io.h>
|
||||
|
||||
/* TEMP DEBUG */
|
||||
#include <tty.h>
|
||||
|
||||
#include <kernel/syscall.h>
|
||||
|
||||
#include <drivers/irq.h>
|
||||
|
||||
#define NUM_IRQS 0x90
|
||||
|
||||
irq_func_t func_list[NUM_IRQS];
|
||||
#define MAX_IRQ_HANDLERS 128 /* the maximum number of irq handlers */
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t irq_no;
|
||||
irq_func_t func;
|
||||
} irq_handler_t;
|
||||
|
||||
static volatile uint32_t num_irqs_missed = 0;
|
||||
uint32_t num_irq_handlers = 0;
|
||||
irq_handler_t handler_list[MAX_IRQ_HANDLERS];
|
||||
|
||||
volatile uint32_t num_irqs_missed = 0;
|
||||
|
||||
void irq_init(void)
|
||||
{
|
||||
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(1, (irq_func_t*) keyboard_handler);
|
||||
set_irq_handler(0, (irq_func_t) pit_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 (num_irq_handlers > 0)
|
||||
{
|
||||
if (func_list[irq_number])
|
||||
for (unsigned int i = 0; i < MAX_IRQ_HANDLERS; i++)
|
||||
{
|
||||
func_list[irq_number]();
|
||||
outb(0x20, 0x20); /* Acknowledge the IRQ to PIC */
|
||||
}
|
||||
else
|
||||
{
|
||||
num_irqs_missed++;
|
||||
if (handler_list[i].irq_no == irq && handler_list[i].func != NULL)
|
||||
{
|
||||
regs = handler_list[i].func(regs);
|
||||
funcs_called++;
|
||||
/* PIC IRQ acknowledgement happens in idt.c */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
148
drivers/keyboard.c
Normal 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
382
drivers/new_tty.c
Normal 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;
|
||||
}
|
||||
@ -2,6 +2,8 @@
|
||||
#include <port_io.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <scheduler.h>
|
||||
|
||||
#include <drivers/pit.h>
|
||||
|
||||
|
||||
@ -15,11 +17,13 @@ bool pit_initialized = false;
|
||||
|
||||
void pit_init(void)
|
||||
{
|
||||
printf("pit_initialized addr = %x\n", &pit_initialized);
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("[ PIT ] Initializing the PIT...\n");
|
||||
#endif
|
||||
|
||||
uint16_t divisor = (uint16_t)1193;
|
||||
uint16_t divisor = (uint16_t) 1193;
|
||||
|
||||
/* Send command byte */
|
||||
outb(PIT_COMMAND, 0x36); /* Channel 0, low/high byte, mode 3 (square wave), binary */
|
||||
@ -35,9 +39,10 @@ void pit_init(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
void pit_handler(void)
|
||||
registers_t* pit_handler(registers_t* regs)
|
||||
{
|
||||
pit_ticks++;
|
||||
return regs;
|
||||
}
|
||||
|
||||
void pit_sleep(uint64_t ms)
|
||||
@ -48,3 +53,14 @@ void pit_sleep(uint64_t ms)
|
||||
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 */
|
||||
/*}
|
||||
*/
|
||||
|
||||
@ -3,6 +3,8 @@
|
||||
#include <tty.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <new_tty.h>
|
||||
|
||||
|
||||
#include <drivers/ps2_keyboard.h>
|
||||
|
||||
@ -62,6 +64,8 @@ volatile int32_t current_length = 0;
|
||||
volatile int32_t capacity = 0;
|
||||
volatile uint16_t current_key;
|
||||
|
||||
volatile bool use_new_tty = false;
|
||||
|
||||
volatile ps2_hook_t* hooks = NULL;
|
||||
volatile int hook_count = 0;
|
||||
|
||||
@ -84,6 +88,10 @@ static const char scancode_map[128] = {
|
||||
/* The rest are function and control keys */
|
||||
};
|
||||
|
||||
void set_use_new_tty(bool t)
|
||||
{
|
||||
use_new_tty = t;
|
||||
}
|
||||
|
||||
void keyboard_init(void)
|
||||
{
|
||||
@ -95,6 +103,8 @@ void keyboard_init(void)
|
||||
|
||||
hooks = NULL;
|
||||
|
||||
set_use_new_tty(true);
|
||||
|
||||
ps2keyboard_initialized = true;
|
||||
|
||||
#ifdef _DEBUG
|
||||
@ -199,6 +209,7 @@ void call_hooks(char c)
|
||||
|
||||
if (hook_count == 0)
|
||||
{
|
||||
_sti_asm();
|
||||
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);
|
||||
|
||||
/* Handle shift press/release */
|
||||
if (scancode == 0x2A || scancode == 0x36)
|
||||
{
|
||||
shift_pressed = true;
|
||||
return;
|
||||
return regs;
|
||||
}
|
||||
else if (scancode == 0xAA || scancode == 0xB6)
|
||||
{
|
||||
shift_pressed = false;
|
||||
return;
|
||||
return regs;
|
||||
}
|
||||
else if (scancode == 0x3A)
|
||||
{
|
||||
capslock_pressed = !capslock_pressed;
|
||||
return;
|
||||
return regs;
|
||||
}
|
||||
else if (scancode == 0xE0)
|
||||
{
|
||||
extended = true;
|
||||
return;
|
||||
return regs;
|
||||
}
|
||||
|
||||
uint32_t flags = 0;
|
||||
|
||||
if (capslock_pressed)
|
||||
{
|
||||
flags |= MODIFIER_CAPS;
|
||||
}
|
||||
|
||||
if (shift_pressed)
|
||||
{
|
||||
flags |= MODIFIER_SHIFT;
|
||||
}
|
||||
|
||||
if (scancode & 0x80)
|
||||
{
|
||||
@ -430,84 +454,94 @@ void keyboard_handler(void)
|
||||
else
|
||||
{
|
||||
uint16_t c = (uint16_t) scancode_map[scancode];
|
||||
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 (hook_count > 0)
|
||||
if (!use_new_tty)
|
||||
{
|
||||
call_hooks(c);
|
||||
}
|
||||
|
||||
if (extended)
|
||||
{
|
||||
switch (scancode)
|
||||
if ((shift_pressed ^ capslock_pressed) && ((char) c >= 'a') && ((char) c <= 'z'))
|
||||
{
|
||||
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;
|
||||
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;
|
||||
return regs;
|
||||
}
|
||||
|
||||
current_key = c;
|
||||
|
||||
is_new_key = true;
|
||||
extended = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (gets_called)
|
||||
{
|
||||
gets_append_char(c);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (c)
|
||||
{
|
||||
if (c != '\n')
|
||||
if (c)
|
||||
{
|
||||
append_char(c);
|
||||
}
|
||||
if (c != '\n')
|
||||
{
|
||||
append_char(c);
|
||||
}
|
||||
|
||||
current_char = c;
|
||||
is_new_char = true;
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
/*append_char(c);
|
||||
current_char = c;
|
||||
is_new_char = true;*/
|
||||
is_new_char = true;
|
||||
|
||||
free_current_string();
|
||||
if (c == '\n')
|
||||
{
|
||||
/*append_char(c);
|
||||
current_char = c;
|
||||
is_new_char = true;*/
|
||||
|
||||
free_current_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tty_receive_char(c, flags);
|
||||
}
|
||||
|
||||
if (hook_count > 0)
|
||||
{
|
||||
call_hooks(c);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return regs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -306,3 +306,12 @@ void terminal_update_cursor(void)
|
||||
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
177
files/idt.c
Normal 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 (32–39) */
|
||||
outb(PIC2_DATA, 0x28); /* IRQs 8-15 mapped to IDT entries 0x28-0x2F (40–47) */
|
||||
|
||||
/* 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
18
files/idt.h
Normal 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
69
files/irq.c
Normal 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
43
files/irq.h
Normal 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
154
files/isr.asm
Normal 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 0–31
|
||||
|
||||
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
164
files/kernel.c
Normal 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
62
files/pit.c
Normal 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
158
files/scheduler.c
Normal 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
32
files/scheduler.h
Normal 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
15
include/arch/x86/intrin.h
Normal 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
|
||||
11
include/drivers/audio/pcspeaker.h
Normal file
11
include/drivers/audio/pcspeaker.h
Normal 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
|
||||
@ -9,35 +9,37 @@
|
||||
#define PT_LOAD 1
|
||||
|
||||
typedef struct {
|
||||
unsigned char e_ident[EI_NIDENT];
|
||||
uint16_t e_type;
|
||||
uint16_t e_machine;
|
||||
uint32_t e_version;
|
||||
uint32_t e_entry;
|
||||
uint32_t e_phoff;
|
||||
uint32_t e_shoff;
|
||||
uint32_t e_flags;
|
||||
uint16_t e_ehsize;
|
||||
uint16_t e_phentsize;
|
||||
uint16_t e_phnum;
|
||||
uint16_t e_shentsize;
|
||||
uint16_t e_shnum;
|
||||
uint16_t e_shstrndx;
|
||||
unsigned char e_ident[EI_NIDENT];
|
||||
uint16_t e_type;
|
||||
uint16_t e_machine;
|
||||
uint32_t e_version;
|
||||
uint32_t e_entry;
|
||||
uint32_t e_phoff;
|
||||
uint32_t e_shoff;
|
||||
uint32_t e_flags;
|
||||
uint16_t e_ehsize;
|
||||
uint16_t e_phentsize;
|
||||
uint16_t e_phnum;
|
||||
uint16_t e_shentsize;
|
||||
uint16_t e_shnum;
|
||||
uint16_t e_shstrndx;
|
||||
} Elf32_Ehdr;
|
||||
|
||||
typedef struct {
|
||||
uint32_t p_type;
|
||||
uint32_t p_offset;
|
||||
uint32_t p_vaddr;
|
||||
uint32_t p_paddr;
|
||||
uint32_t p_filesz;
|
||||
uint32_t p_memsz;
|
||||
uint32_t p_flags;
|
||||
uint32_t p_align;
|
||||
uint32_t p_type;
|
||||
uint32_t p_offset;
|
||||
uint32_t p_vaddr;
|
||||
uint32_t p_paddr;
|
||||
uint32_t p_filesz;
|
||||
uint32_t p_memsz;
|
||||
uint32_t p_flags;
|
||||
uint32_t p_align;
|
||||
} Elf32_Phdr;
|
||||
|
||||
typedef int (*elf_entry_t)(void);
|
||||
|
||||
typedef struct {
|
||||
void* entry_point;
|
||||
elf_entry_t entry_point;
|
||||
} elf_executable_t;
|
||||
|
||||
elf_executable_t* load_elf32(void* elf_data);
|
||||
|
||||
@ -1,13 +1,18 @@
|
||||
#ifndef _IDT_H
|
||||
#define _IDT_H
|
||||
|
||||
#include <drivers/irq.h>
|
||||
|
||||
#include <types.h>
|
||||
|
||||
|
||||
void idt_init(void);
|
||||
|
||||
void pic_remap(void);
|
||||
|
||||
void idt_set_descriptor(uint8_t vector, void* isr, uint8_t flags);
|
||||
void exception_dispatcher(uint32_t int_no, uint32_t err_code);
|
||||
|
||||
void exception_handler(registers_t* regs);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@ -3,13 +3,28 @@
|
||||
|
||||
#include <types.h>
|
||||
|
||||
typedef void (*irq_func_t)(void);
|
||||
typedef struct {
|
||||
uint32_t ds, es, fs, gs;
|
||||
|
||||
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax;
|
||||
|
||||
uint32_t int_no;
|
||||
uint32_t err_code;
|
||||
|
||||
uint32_t eip;
|
||||
uint32_t cs;
|
||||
uint32_t eflags;
|
||||
} registers_t;
|
||||
|
||||
typedef registers_t* (*irq_func_t)(registers_t*);
|
||||
|
||||
void irq_init(void);
|
||||
|
||||
void irq_handler(uint8_t irq_number);
|
||||
registers_t* irq_handler(uint32_t irq, registers_t* regs);
|
||||
|
||||
void set_irq_handler(uint32_t num, irq_func_t* handler);
|
||||
void add_irq_handler(uint32_t num, irq_func_t* handler);
|
||||
void set_irq_handler(uint32_t num, irq_func_t handler);
|
||||
/*void add_irq_handler(uint32_t num, irq_func_t* handler);*/
|
||||
|
||||
uint32_t get_interrupts_missed(void);
|
||||
|
||||
#endif
|
||||
|
||||
10
include/drivers/keyboard.h
Normal file
10
include/drivers/keyboard.h
Normal 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
|
||||
@ -3,10 +3,11 @@
|
||||
|
||||
#include <types.h>
|
||||
|
||||
extern volatile uint64_t pit_ticks;
|
||||
|
||||
#include <drivers/irq.h>
|
||||
|
||||
void pit_init(void);
|
||||
void pit_handler(void);
|
||||
registers_t* pit_handler(registers_t* regs);
|
||||
void pit_sleep(uint64_t ms);
|
||||
|
||||
#endif
|
||||
|
||||
@ -23,7 +23,9 @@ typedef enum {
|
||||
typedef void (*ps2_hook_t)(char);
|
||||
|
||||
void keyboard_init(void);
|
||||
void keyboard_handler(void);
|
||||
registers_t* ps2_keyboard_handler(registers_t* regs);
|
||||
|
||||
void set_use_new_tty(bool t);
|
||||
|
||||
char get_char(void);
|
||||
uint16_t get_key(void);
|
||||
|
||||
37
include/fs/ekfs.h
Normal file
37
include/fs/ekfs.h
Normal 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
78
include/fs/fat16.h
Normal 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
|
||||
@ -1,8 +1,6 @@
|
||||
#ifndef _KERNEL_SHELL_H
|
||||
#define _KERNEL_SHELL_H
|
||||
|
||||
#include <types.h>
|
||||
|
||||
int kshell_start(int argc, char** argv);
|
||||
void kshell_start(void);
|
||||
|
||||
#endif
|
||||
|
||||
111
include/kernel/syscall.h
Normal file
111
include/kernel/syscall.h
Normal 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
|
||||
@ -3,7 +3,8 @@
|
||||
|
||||
#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_HANDLED 1
|
||||
@ -18,4 +19,14 @@
|
||||
#define __noreturn __attribute__((noreturn))
|
||||
#define __section(x) __attribute__((section(x)))
|
||||
|
||||
#define __noreturn __attribute__((noreturn))
|
||||
|
||||
extern void _cli_asm(void);
|
||||
extern void _sti_asm(void);
|
||||
|
||||
#define IRQ_DISABLE() _cli_asm();
|
||||
#define IRQ_ENABLE() _sti_asm();
|
||||
|
||||
//#define DEBUG_USE_SSE2
|
||||
|
||||
#endif
|
||||
|
||||
15
include/math/random.h
Normal file
15
include/math/random.h
Normal 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
73
include/new_tty.h
Normal 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
|
||||
@ -1,10 +1,10 @@
|
||||
#ifndef _PRINTF_H
|
||||
#define _PRINTF_H
|
||||
|
||||
#include <tty.h>
|
||||
//#include <tty.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <vga/vga.h> /* Only for the vga_color enum */
|
||||
//#include <vga/vga.h> /* Only for the vga_color enum */
|
||||
|
||||
|
||||
void printwc(const char*, uint8_t);
|
||||
|
||||
@ -5,15 +5,17 @@
|
||||
#include <drivers/elf.h>
|
||||
|
||||
|
||||
|
||||
typedef uint32_t pid_t;
|
||||
|
||||
typedef struct process {
|
||||
int32_t id;
|
||||
int32_t group;
|
||||
pid_t id;
|
||||
pid_t group;
|
||||
|
||||
elf_executable_t* exe;
|
||||
|
||||
struct process* next;
|
||||
} process_t;
|
||||
|
||||
int32_t make_process(char* name, char* group, elf_executable_t* exe);
|
||||
|
||||
pid_t make_process(char* name, char* group, elf_executable_t* exe);
|
||||
|
||||
#endif
|
||||
|
||||
21
include/scheduler.h
Normal file
21
include/scheduler.h
Normal 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
|
||||
@ -4,10 +4,23 @@
|
||||
#include <types.h>
|
||||
#include <printf.h>
|
||||
|
||||
#define STDIN 0
|
||||
#define STDOUT 1
|
||||
#define STDERR 2
|
||||
|
||||
int read(uint32_t fd, void* data, size_t max_len);
|
||||
int write(uint32_t fd, void* data, size_t len);
|
||||
|
||||
char getchar(void);
|
||||
char* getstring(void);
|
||||
char* gets(void); /* Use this instead of getstring() */
|
||||
|
||||
int getstr(char* dest);
|
||||
|
||||
char* gets_new(int* num);
|
||||
|
||||
void putc(char c);
|
||||
|
||||
static inline void putchar(char c)
|
||||
{
|
||||
printf("%c", c);
|
||||
|
||||
@ -17,8 +17,10 @@ char* strdup(const char* s);
|
||||
char* strtok(char* str, const char* delim);
|
||||
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);
|
||||
char* strnlstrip(const char* __s);
|
||||
void strlnstripip(char* s);
|
||||
|
||||
void lowers(char* str);
|
||||
void uppers(char* str);
|
||||
|
||||
14
include/sync.h
Normal file
14
include/sync.h
Normal 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
|
||||
@ -1,5 +1,5 @@
|
||||
#ifndef _TTY_H
|
||||
#define _TTY_H
|
||||
#ifndef TTY_H
|
||||
#define TTY_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_update_cursor(void);
|
||||
|
||||
|
||||
void terminal_putcharat(char c, uint16_t row, uint16_t column);
|
||||
|
||||
#endif
|
||||
|
||||
@ -5,6 +5,11 @@
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define ARG64_LO(x) ((uint32_t)(x))
|
||||
#define ARG64_HI(x) ((uint32_t)((x) >> 32))
|
||||
|
||||
#define TOGGLE_BIT(x, bit) ((x) ^= (1U << (bit)))
|
||||
|
||||
typedef unsigned char uchar;
|
||||
|
||||
typedef uint8_t u8;
|
||||
@ -12,4 +17,19 @@ typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
|
||||
typedef int8_t i8;
|
||||
typedef int16_t i16;
|
||||
typedef int32_t i32;
|
||||
typedef int64_t i64;
|
||||
|
||||
/* this might not be POSIX compatable. */
|
||||
typedef uint32_t size_t;
|
||||
typedef int32_t ssize_t;
|
||||
|
||||
#if 0
|
||||
#if sizeof(size_t) != sizeof(ssize_t)
|
||||
#error "size_t is a different size than ssize_t"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@ -13,11 +13,9 @@ char char_entered = 0x00;
|
||||
|
||||
void intro_begin(void)
|
||||
{
|
||||
extern char* kernel_version;
|
||||
|
||||
char* fin = (char*) malloc(strlen(kernel_version) + 6);
|
||||
memset(fin, 0, (strlen(kernel_version) + 5));
|
||||
strcpy(fin, kernel_version);
|
||||
char* fin = (char*) malloc(strlen(KERNEL_VERSION) + 6);
|
||||
memset(fin, 0, (strlen(KERNEL_VERSION) + 5));
|
||||
strcpy(fin, KERNEL_VERSION);
|
||||
|
||||
#ifdef _DEBUG
|
||||
strcat(fin, " DEBUG");
|
||||
|
||||
@ -16,6 +16,12 @@
|
||||
|
||||
#include <kernel/boot.h>
|
||||
#include <kernel/kshell.h>
|
||||
#include <kernel/syscall.h>
|
||||
|
||||
#include <tty.h>
|
||||
#include <vga/vga.h>
|
||||
|
||||
#include <new_tty.h>
|
||||
|
||||
#include <kdebug.h>
|
||||
|
||||
@ -23,54 +29,41 @@
|
||||
#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/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/duckfs.h>*/
|
||||
#include <fs/vfs.h>
|
||||
#include <fs/sfs.h>
|
||||
|
||||
#ifdef DEBUG_USE_SSE2
|
||||
#include <vector_extensions/sse.h>
|
||||
#endif
|
||||
|
||||
#include <kernel/intro.h>
|
||||
|
||||
#include <builtin_games/miner.h>
|
||||
|
||||
#include <fs/ssfs.h>
|
||||
|
||||
#define DEBUG
|
||||
|
||||
|
||||
extern void _hang_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)
|
||||
{
|
||||
|
||||
/* --- BEGIN INITIALIZATION SECTION --- */
|
||||
|
||||
/* We need to initialize the terminal so that any error/debugging messages show. */
|
||||
terminal_initialize();
|
||||
|
||||
printf("Loading Espresso %s... ", kernel_version);
|
||||
printf("Loading Espresso %s... ", KERNEL_VERSION);
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("[ DEBUG BUILD ]");
|
||||
@ -96,12 +89,8 @@ void kernel_main(multiboot_info_t* mbd, uint32_t magic)
|
||||
|
||||
gdt_install(false);
|
||||
|
||||
pic_remap();
|
||||
|
||||
pic_remap(); /* must be done before idt_init() */
|
||||
idt_init();
|
||||
|
||||
_sti_asm();
|
||||
|
||||
irq_init(); /* MUST be done after pic_remap() and idt_init() */
|
||||
|
||||
terminal_setcolor(VGA_COLOR_GREEN);
|
||||
@ -112,44 +101,65 @@ void kernel_main(multiboot_info_t* mbd, uint32_t magic)
|
||||
|
||||
heap_init(0xC2000000, 0x80000);
|
||||
|
||||
#ifdef DEBUG_USE_SSE2
|
||||
#ifdef _DEBUG
|
||||
printd("Testing SSE...\n");
|
||||
#endif
|
||||
int32_t sse_test_result = test_sse();
|
||||
if (sse_test_result != 0)
|
||||
{
|
||||
printf("[ DEBUG ] SSE test failed with RV %d\n", sse_test_result);
|
||||
printf("[ SSE ] SSE test failed with RV %d\n", sse_test_result);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
printd("SSE test passed\n");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
pit_init();
|
||||
|
||||
keyboard_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();
|
||||
init_keyboard();
|
||||
|
||||
ide_initialize();
|
||||
|
||||
pci_init();
|
||||
|
||||
init_sysints();
|
||||
|
||||
/*init_scheduler();*/
|
||||
|
||||
_sti_asm();
|
||||
|
||||
|
||||
/* --- END INITIALIZATION SECTION --- */
|
||||
|
||||
|
||||
terminal_setcolor(VGA_COLOR_LIGHT_GREEN);
|
||||
|
||||
printf("Guten tag and welcome to Espresso %s\n", kernel_version);
|
||||
printf("Guten tag and welcome to Espresso %s\n", KERNEL_VERSION);
|
||||
|
||||
sleep(1000);
|
||||
|
||||
intro_begin();
|
||||
|
||||
/*extern void terminal_clear(void);
|
||||
extern void terminal_clear(void);
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
230
kernel/kshell.c
230
kernel/kshell.c
@ -6,6 +6,12 @@
|
||||
#include <kernel/ksh_debug.h>
|
||||
#include <arch/x86/intrin.h>
|
||||
|
||||
#include <drivers/elf.h>
|
||||
|
||||
#include <kernel/syscall.h>
|
||||
|
||||
#include <scheduler.h>
|
||||
|
||||
#include <fs/fat16.h>
|
||||
|
||||
#include <kernel/kshell.h>
|
||||
@ -15,7 +21,7 @@ const char* shell_version = "0.0.2";
|
||||
|
||||
char* prompt = NULL;
|
||||
int command = -1;
|
||||
bool _debug = false;
|
||||
bool _debug = true;
|
||||
|
||||
int execute(void);
|
||||
|
||||
@ -44,18 +50,7 @@ static void print_intro(void)
|
||||
printf("CPU: %s\n", _temp == NULL ? "No info" : _temp);
|
||||
printf("CPU vendor: %s\n", temp_ == NULL ? "No info" : temp_);
|
||||
|
||||
printf("\nCopyright 2025 David J Goeke\n");
|
||||
}
|
||||
|
||||
static void parse_opts(int argc, char** argv)
|
||||
{
|
||||
for (int i = 0; i < argc; i++)
|
||||
{
|
||||
if (strcmp(argv[i], "--color") == 0)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
printf("\nCopyright %s David J Goeke\n", KERNEL_RELEASE_YEAR);
|
||||
}
|
||||
|
||||
static char* commands[] = {
|
||||
@ -76,19 +71,28 @@ static char* commands[] = {
|
||||
|
||||
"printrandom",
|
||||
|
||||
"acm", /* ACcess Memory */
|
||||
|
||||
"testfat16",
|
||||
|
||||
"printc",
|
||||
|
||||
"testscheduler",
|
||||
|
||||
"readfat16",
|
||||
|
||||
"help",
|
||||
|
||||
"exec",
|
||||
|
||||
"int16test",
|
||||
|
||||
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;
|
||||
(void)argv;
|
||||
printf("Welcome to the kshell!\n");
|
||||
|
||||
prompt = strdup(">");
|
||||
|
||||
@ -102,7 +106,17 @@ int kshell_start(int argc, char** argv)
|
||||
{
|
||||
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;
|
||||
|
||||
@ -165,14 +179,14 @@ int kshell_start(int argc, char** argv)
|
||||
|
||||
} while (1);
|
||||
|
||||
if (i != NULL)
|
||||
if (i)
|
||||
{
|
||||
free(i);
|
||||
}
|
||||
|
||||
printf("Goodbye!\n");
|
||||
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -194,7 +208,7 @@ int kshell_start(int argc, char** argv)
|
||||
|
||||
"printrandom",
|
||||
|
||||
"acm",
|
||||
"testfat16",
|
||||
|
||||
NULL,
|
||||
};
|
||||
@ -321,31 +335,6 @@ int execute(void)
|
||||
break;
|
||||
}
|
||||
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);
|
||||
|
||||
if (retv != 0)
|
||||
@ -402,6 +391,151 @@ int execute(void)
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
118
kernel/syscall.c
Normal file
118
kernel/syscall.c
Normal 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;
|
||||
}
|
||||
6
kincl.h
6
kincl.h
@ -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
58
lib/espresso/kstring.c
Normal 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
79
lib/math/random.c
Normal 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;
|
||||
}
|
||||
@ -111,7 +111,12 @@ void free(void* ptr)
|
||||
block_t* curr = free_list;
|
||||
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->next = curr->next->next;
|
||||
|
||||
24
lib/mm/pmm.c
24
lib/mm/pmm.c
@ -12,6 +12,10 @@ static size_t total_pages;
|
||||
#define BITMAP_CLEAR(i) (bitmap[(i) / 8] &= ~(1 << ((i) % 8)))
|
||||
#define BITMAP_TEST(i) (bitmap[(i) / 8] & (1 << ((i) % 8)))
|
||||
|
||||
|
||||
extern uint32_t __kernel_start;
|
||||
extern uint32_t __kernel_end;
|
||||
|
||||
void pmm_init(multiboot_info_t* mb)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
@ -46,6 +50,18 @@ void pmm_init(multiboot_info_t* mb)
|
||||
}
|
||||
total_pages = MAX_PAGES;
|
||||
|
||||
uintptr_t start = (uintptr_t)&__kernel_start;
|
||||
uintptr_t end = (uintptr_t)&__kernel_end;
|
||||
|
||||
start &= ~0xFFF;
|
||||
end = (end + 0xFFF) & ~0xFFF;
|
||||
|
||||
for (uintptr_t addr = start; addr < end; addr += 0x1000)
|
||||
{
|
||||
size_t idx = addr / 0x1000;
|
||||
BITMAP_SET(idx); // Mark kernel pages as USED
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("[ PMM ] Physical memory manager initialized\n");
|
||||
#endif
|
||||
@ -55,6 +71,14 @@ void* pmm_alloc_page(void)
|
||||
{
|
||||
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))
|
||||
{
|
||||
BITMAP_SET(i);
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
#include <stdint.h>
|
||||
#include <drivers/serio.h>
|
||||
|
||||
#include <tty.h>
|
||||
|
||||
#include <printf.h>
|
||||
|
||||
static uint8_t color = 0xFF;
|
||||
|
||||
@ -3,13 +3,18 @@
|
||||
#include <processes.h>
|
||||
|
||||
|
||||
int32_t next_id = 9; /* 0 through 8 are reserved for kernel operations */
|
||||
pid_t next_id = 1; /* start at 1 */
|
||||
|
||||
int32_t make_process(char* name, char* group, elf_executable_t* exe)
|
||||
pid_t make_process(char* name, char* group, elf_executable_t* exe)
|
||||
{
|
||||
pid_t ret = (pid_t) 0;
|
||||
|
||||
if (!name || !group || !exe)
|
||||
{
|
||||
return -1;
|
||||
return ret; /* ret is already zero */
|
||||
}
|
||||
return 0;
|
||||
|
||||
next_id++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
76
lib/scheduler.c
Normal file
76
lib/scheduler.c
Normal 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;
|
||||
}
|
||||
94
lib/stdio.c
94
lib/stdio.c
@ -2,8 +2,45 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <kernel/syscall.h>
|
||||
#include <tty.h>
|
||||
|
||||
#include <new_tty.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int write(uint32_t fd, void* data, size_t len)
|
||||
{
|
||||
if (fd == STDOUT)
|
||||
{
|
||||
print_uint((uint32_t) len);
|
||||
terminal_write((char*) data, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int read(uint32_t fd, void* data, size_t max_len)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
if (fd == STDIN)
|
||||
{
|
||||
char* sptr = (char*) data; /* this really shouldn't be needed... */
|
||||
sptr = gets_new(&rv);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
extern bool ps2keyboard_initialized;
|
||||
|
||||
char getchar(void)
|
||||
@ -31,40 +68,33 @@ char* gets(void)
|
||||
return kbd_gets();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*char* fgets(char* buf, int n, FILE file)
|
||||
char* gets_new(int* num)
|
||||
{
|
||||
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;
|
||||
char c;
|
||||
strcpy(dest, p);
|
||||
}
|
||||
|
||||
while (total_read < n - 1)
|
||||
{
|
||||
int bytes = 0*//*read_file(file, &c, 1)*/;
|
||||
|
||||
/*if (bytes <= 0)
|
||||
{
|
||||
break; *//* EOF or error */
|
||||
/*}
|
||||
|
||||
buf[total_read++] = c;
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
break; *//* Stop at newline */
|
||||
/*}
|
||||
}
|
||||
|
||||
if (total_read == 0)
|
||||
{
|
||||
return NULL; *//* Nothing read (e.g. EOF) */
|
||||
/*}
|
||||
|
||||
buf[total_read] = '\0';
|
||||
return buf;
|
||||
}*/
|
||||
void putc(char c)
|
||||
{
|
||||
syscall1(SYS_TERMINAL_PUTCHAR, c);
|
||||
}
|
||||
|
||||
47
lib/string.c
47
lib/string.c
@ -1,10 +1,12 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <vector_extensions/sse.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifdef DEBUG_USE_SSE2
|
||||
#include <vector_extensions/sse.h>
|
||||
extern int32_t sse_initialized;
|
||||
#endif
|
||||
|
||||
size_t strlen(const char* str)
|
||||
{
|
||||
@ -76,10 +78,12 @@ char* strcpy(char *dst, const char *src)
|
||||
|
||||
char* strncpy(char *dest, const char *src, uint32_t n)
|
||||
{
|
||||
#ifdef DEBUG_USE_SSE2
|
||||
if (sse_initialized > 0)
|
||||
{
|
||||
return sse2_strncpy(dest, src, n);
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t i = 0;
|
||||
for (; i < n && src[i]; ++i)
|
||||
@ -217,10 +221,12 @@ void* memset(void* dst, int c, size_t n)
|
||||
|
||||
void* memcpy(void *dst, const void *src, uint32_t n)
|
||||
{
|
||||
#ifdef DEBUG_USE_SSE2
|
||||
if (sse_initialized > 1)
|
||||
{
|
||||
return sse2_memcpy(dst, src, n);
|
||||
}
|
||||
#endif
|
||||
|
||||
char *d = dst;
|
||||
const char *s = src;
|
||||
@ -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)
|
||||
{
|
||||
const uint8_t *p1 = (const uint8_t *)s1;
|
||||
const uint8_t *p2 = (const uint8_t *)s2;
|
||||
const uint8_t *p1 = (const uint8_t*) s1;
|
||||
const uint8_t *p2 = (const uint8_t*) s2;
|
||||
|
||||
/*printf("p1: %i, p2: %i\n", (int32_t)*p1, (int32_t)*p2);*/
|
||||
|
||||
@ -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)
|
||||
{
|
||||
#ifdef DEBUG_USE_SSE2
|
||||
if (sse_initialized > 1)
|
||||
{
|
||||
return memclr_sse2(m_start, m_count);
|
||||
}
|
||||
#endif
|
||||
|
||||
return memset(m_start, '\0', (uint32_t)m_count);
|
||||
}
|
||||
@ -451,3 +459,36 @@ double atof(const char *str)
|
||||
return sign * (res + frac / frac_div);
|
||||
}
|
||||
|
||||
char* strnlstrip(const char* s)
|
||||
{
|
||||
if (!s)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* new = strdup(s);
|
||||
if (!new)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t len = strlen(new);
|
||||
|
||||
while (len > 0 && (new[len-1] == '\n' || new[len-1] == '\r'))
|
||||
{
|
||||
new[len-1] = '\0';
|
||||
len--;
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
void strlnstripip(char* s)
|
||||
{
|
||||
size_t len = strlen(s);
|
||||
|
||||
if (len > 0 && s[len-1] == '\n')
|
||||
{
|
||||
s[len-1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
40
lib/sync.c
Normal file
40
lib/sync.c
Normal 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);
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
#ifdef DEBUG_USE_SSE2
|
||||
|
||||
#include <types.h>
|
||||
#include <stdio.h>
|
||||
|
||||
@ -248,3 +250,5 @@ void* memclr_sse2(void *m_start, size_t m_count)
|
||||
|
||||
return m_start;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
9
libc/include/stdio.h
Normal file
9
libc/include/stdio.h
Normal 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
19
libc/include/string.h
Normal 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
22
libc/stdio.c
Normal 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
125
libc/string.c
Normal 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
110
syscall.h
Normal 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
|
||||
3
usefull_gcc_stuff.txt.junk
Normal file
3
usefull_gcc_stuff.txt.junk
Normal 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
BIN
user/hello.elf
Executable file
Binary file not shown.
75
user/test.c
Normal file
75
user/test.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user