Compare commits
7 Commits
6baa95a064
...
0.0.2d
| Author | SHA1 | Date | |
|---|---|---|---|
| f3b2f95af5 | |||
| 5971218b56 | |||
| 021fdbbcef | |||
| c0dc95e255 | |||
| ff6cba1164 | |||
| 102d517097 | |||
| 2f8f6d2217 |
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
|
||||
@ -1,21 +0,0 @@
|
||||
Modules and Drivers API
|
||||
|
||||
|
||||
This file contains documentation for the Module/Driver API.
|
||||
|
||||
|
||||
The kernel symtab is always at 0xC0101000, and can go up to 0xC0101000 + 0x8086 ( See what I did there?)
|
||||
|
||||
|
||||
ID number -- Function -- Returns -- Arguments
|
||||
0 -- get_kinfo -- kinfo_t -- uint32_t leaf
|
||||
1 -- make_kfunc -- kfunc_t -- void* addr, bool module, uint16_t module_id, uint32_t function_id
|
||||
2 -- add_kfunc -- uint32_t -- void* addr, bool module, uint16_t module_id, uint32_t function_id
|
||||
3 -- printf -- void -- const char* format, ...
|
||||
4 -- malloc -- void* -- size_t size
|
||||
5 -- free -- void -- void* ptr
|
||||
6 -- calloc -- void* -- size_t nmemb, size_t size
|
||||
7 -- realloc -- void* -- void* ptr, size_t size
|
||||
8 -- get_key -- uint16_t -- void
|
||||
9 -- get_string -- char* -- void
|
||||
10 --
|
||||
15
FEATURES.md
Normal file
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)
|
||||
61
Makefile
61
Makefile
@ -1,18 +1,22 @@
|
||||
# === Config ===
|
||||
TARGET := boot/espresso.elf
|
||||
ISO := boot/espresso.iso
|
||||
FAT16_DISK := espresso.img
|
||||
CC := i686-elf-gcc
|
||||
AS := i686-elf-as
|
||||
NASM := nasm
|
||||
QEMU_MKE_IMG := qemu-img create -f raw espresso.img 256M
|
||||
QEMU_MKE_IMG := qemu-img create -f raw $(FAT16_DISK) 64M
|
||||
MKFS_VFAT := sudo mkfs.vfat
|
||||
MKFS_FLAGS := -F 32 -S 512
|
||||
MKFS_FLAGS := -F 16 -S 512
|
||||
NASMFLAGS := -f elf32
|
||||
WNOFLAGS := -Wno-discarded-qualifiers
|
||||
CFLAGS := -std=gnu99 -ffreestanding -O2 -Wall -Wextra -msse4 $(WNOFLAGS)
|
||||
LDFLAGS := -T linker.ld -ffreestanding -O2 -nostdlib
|
||||
QEMUFLAGS := -boot d -cdrom $(ISO) -drive file=espresso.img,format=raw,if=ide,readonly=off,rerror=report,werror=report -cpu qemu32,sse4.1
|
||||
QEMUFLGS_EXT := -net none -netdev user,id=n0 -device rtl8139,netdev=n0 -vga std #-singlestep
|
||||
CFLAGS := -std=gnu99 -ffreestanding -O2 -Wall -Wextra -msse $(WNOFLAGS) -nostdlib -nostartfiles -include include/kincl.h
|
||||
LDFLAGS := -T linker.ld -ffreestanding -O2 -nostdlib -nostartfiles
|
||||
QEMUFLAGS := -no-shutdown -drive file=$(FAT16_DISK),format=raw,if=ide,readonly=off,rerror=report,werror=report -cpu qemu32,sse4.1
|
||||
QEMUFLGS_EXT := -vga std
|
||||
MOR_QEMUFLGS := -net none -netdev user,id=n0 -device rtl8139,netdev=n0 -serial file:serial.log
|
||||
QEMU_BOOT_FLG := -boot d -cdrom $(ISO)
|
||||
QEMU_BOOT_RPI := -kernel $(TARGET)
|
||||
SRC_DIRS := kernel drivers lib
|
||||
INCLUDE_DIRS := include
|
||||
ARCH_DIR := arch
|
||||
@ -24,6 +28,9 @@ BOOT_DIR := $(ISO_DIR)/boot
|
||||
GRUB_DIR := $(BOOT_DIR)/grub
|
||||
GRUB_CFG := grub.cfg
|
||||
|
||||
# === Host checks ===
|
||||
IS_RPI := $(shell [ -f /proc/device-tree/model ] && grep -qi "Raspberry Pi" /proc/device-tree/model && echo 1 || echo 0)
|
||||
|
||||
# === File collection ===
|
||||
C_SRCS := $(foreach dir, $(SRC_DIRS), $(shell find $(dir) -name '*.c'))
|
||||
S_SRCS := $(foreach dir, $(ARCH_DIR), $(shell find $(dir) -name '*.s'))
|
||||
@ -46,6 +53,10 @@ buildc: all iso run clean
|
||||
# === Default target ===
|
||||
all: $(TARGET)
|
||||
|
||||
# === Debug build ===
|
||||
debug:
|
||||
$(MAKE) clean
|
||||
$(MAKE) CFLAGS="$(CFLAGS) -D_DEBUG" $(TARGET)
|
||||
|
||||
# === Linking ===
|
||||
$(TARGET): ./arch/x86/boot/boot.o $(filter-out boot.o, $(OBJ_LINK_LIST))
|
||||
@ -67,23 +78,47 @@ $(TARGET): ./arch/x86/boot/boot.o $(filter-out boot.o, $(OBJ_LINK_LIST))
|
||||
iso: $(TARGET)
|
||||
@grub-file --is-x86-multiboot $(TARGET) && echo "multiboot confirmed" || (echo "not multiboot" && exit 1)
|
||||
mkdir -p $(GRUB_DIR)
|
||||
cp $(TARGET) $(BOOT_DIR)/
|
||||
cp $(GRUB_CFG) $(GRUB_DIR)/
|
||||
cp $(TARGET) $(BOOT_DIR)
|
||||
ifneq ($(IS_RPI),1)
|
||||
cp $(GRUB_CFG) $(GRUB_DIR)
|
||||
grub-mkrescue -o $(ISO) $(ISO_DIR)
|
||||
endif
|
||||
|
||||
# === Run in QEMU ===
|
||||
run: iso
|
||||
$(QEMU_MKE_IMG)
|
||||
echo "\n"
|
||||
$(MKFS_VFAT) $(MKFS_FLAGS) espresso.img
|
||||
qemu-system-i386 $(QEMUFLAGS) $(QEMUFLGS_EXT)
|
||||
@if [ ! -f $(FAT16_DISK) ]; then \
|
||||
$(QEMU_MKE_IMG); \
|
||||
sudo mkfs.fat $(MKFS_FLAGS) espresso.img; \
|
||||
fi
|
||||
@echo $(IS_RPI)
|
||||
ifeq ($(IS_RPI),1)
|
||||
qemu-system-i386 $(QEMU_BOOT_RPI) $(QEMUFLAGS) $(QEMUFLGS_EXT) $(MOR_QEMUFLGS)
|
||||
else
|
||||
qemu-system-i386 $(QEMU_BOOT_FLG) $(QEMUFLAGS) $(QEMUFLGS_EXT) $(MOR_QEMUFLGS)
|
||||
endif
|
||||
|
||||
|
||||
# === Clean all build artifacts ===
|
||||
clean:
|
||||
rm -f $(INTERNAL_OBJS) $(TARGET) $(ISO)
|
||||
rm -rf $(ISO_DIR)
|
||||
|
||||
clean_disk:
|
||||
rm -f espresso.img
|
||||
|
||||
.PHONY: all clean iso run
|
||||
# === Push code to repo ===
|
||||
commit:
|
||||
ifndef MSG
|
||||
$(error MSG required)
|
||||
endif
|
||||
ifndef RELEASENUM
|
||||
$(error RELEASENUM required)
|
||||
endif
|
||||
git add .
|
||||
git commit -m "$(MSG)"
|
||||
git push origin main
|
||||
|
||||
git tag -a "$(RELEASENUM)" -m "Espresso $(RELEASENUM)"
|
||||
git push origin "$(RELEASENUM)"
|
||||
|
||||
.PHONY: all clean clean_disk iso run debug build buildc
|
||||
|
||||
24
TODO.md
Normal file
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
|
||||
@ -21,7 +21,7 @@ forced to be within the first 8 KiB of the kernel file.
|
||||
/*
|
||||
The multiboot standard does not define the value of the stack pointer register
|
||||
(esp) and it is up to the kernel to provide a stack. This allocates room for a
|
||||
small stack by creating a symbol at the bottom of it, then allocating 16384
|
||||
small stack by creating a symbol at the bottom of it, then allocating 65536
|
||||
bytes for it, and finally creating a symbol at the top. The stack grows
|
||||
downwards on x86. The stack is in its own section so it can be marked nobits,
|
||||
which means the kernel file is smaller because it does not contain an
|
||||
@ -30,10 +30,10 @@ System V ABI standard and de-facto extensions. The compiler will assume the
|
||||
stack is properly aligned and failure to align the stack will result in
|
||||
undefined behavior.
|
||||
*/
|
||||
.section .bss
|
||||
.section .stack
|
||||
.align 16
|
||||
stack_bottom:
|
||||
.skip 16384 # 16 KiB
|
||||
.skip 65536 # 64 KiB
|
||||
stack_top:
|
||||
|
||||
/*
|
||||
@ -183,7 +183,6 @@ _start:
|
||||
|
||||
/*
|
||||
Call _kernel_early, early low-level initialization will happen there.
|
||||
NOTE: I don't use 'jmp' because it doesn't work. Nice try.
|
||||
*/
|
||||
call _kernel_early
|
||||
|
||||
|
||||
57
arch/x86/cpuid.s
Normal file
57
arch/x86/cpuid.s
Normal file
@ -0,0 +1,57 @@
|
||||
|
||||
|
||||
/*
|
||||
Just a bunch of CPUID stuff.
|
||||
*/
|
||||
|
||||
.extern sse_initialized
|
||||
|
||||
.section .text
|
||||
|
||||
|
||||
_init_cpuid:
|
||||
pusha
|
||||
|
||||
pushf
|
||||
pop %eax
|
||||
mov %eax, %ecx
|
||||
xor $0x200000, %eax
|
||||
push %eax
|
||||
popf
|
||||
/*pushf*/
|
||||
pop %eax
|
||||
xor %ecx, %eax
|
||||
jz .no_cpuid
|
||||
|
||||
lea _has_cpuid, %edi
|
||||
movl $1, (%edi)
|
||||
|
||||
jmp .done
|
||||
|
||||
.no_cpuid:
|
||||
lea _has_cpuid, %edi
|
||||
movl $0, (%edi)
|
||||
|
||||
jmp .done
|
||||
|
||||
.done:
|
||||
popa
|
||||
|
||||
ret
|
||||
|
||||
_sse_level:
|
||||
lea _has_sse, %edi
|
||||
lea sse_initialized, %esi
|
||||
|
||||
movl (%esi), %eax
|
||||
|
||||
movl %eax, (%edi)
|
||||
|
||||
|
||||
.section .data
|
||||
|
||||
.global _has_cpuid
|
||||
|
||||
_has_cpuid: .int 0
|
||||
_has_sse: .int 0
|
||||
_has_mmx: .int 0
|
||||
53
arch/x86/cpuid_asm.asm
Normal file
53
arch/x86/cpuid_asm.asm
Normal file
@ -0,0 +1,53 @@
|
||||
global get_cpu_brand_string
|
||||
|
||||
section .text
|
||||
|
||||
; void get_cpu_brand_string(char* buffer)
|
||||
|
||||
get_cpu_brand_string:
|
||||
pushad ; Save registers
|
||||
|
||||
mov edi, eax ; EAX = pointer to output buffer
|
||||
|
||||
mov eax, 0x80000000
|
||||
cpuid
|
||||
cmp eax, 0x80000004
|
||||
jb .not_supported
|
||||
|
||||
mov esi, edi ; Buffer pointer → ESI
|
||||
|
||||
; ---- CPUID leaf 0x80000002 ----
|
||||
mov eax, 0x80000002
|
||||
cpuid
|
||||
mov [esi], eax
|
||||
mov [esi+4], ebx
|
||||
mov [esi+8], ecx
|
||||
mov [esi+12], edx
|
||||
|
||||
; ---- CPUID leaf 0x80000003 ----
|
||||
mov eax, 0x80000003
|
||||
cpuid
|
||||
mov [esi+16], eax
|
||||
mov [esi+20], ebx
|
||||
mov [esi+24], ecx
|
||||
mov [esi+28], edx
|
||||
|
||||
; ---- CPUID leaf 0x80000004 ----
|
||||
mov eax, 0x80000004
|
||||
cpuid
|
||||
mov [esi+32], eax
|
||||
mov [esi+36], ebx
|
||||
mov [esi+40], ecx
|
||||
mov [esi+44], edx
|
||||
|
||||
mov byte [esi+48], 0 ; Null terminator
|
||||
|
||||
jmp .done
|
||||
|
||||
.not_supported:
|
||||
mov byte [edi], 0
|
||||
|
||||
.done:
|
||||
popad
|
||||
ret
|
||||
|
||||
18
arch/x86/exec/secf.s
Normal file
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
|
||||
; ============================================================
|
||||
|
||||
%macro irq_stub 1
|
||||
irq_stub_%+%1:
|
||||
pusha
|
||||
push ds
|
||||
push es
|
||||
push fs
|
||||
interrupt_entry:
|
||||
|
||||
; Stack already contains:
|
||||
; err_code
|
||||
; int_no
|
||||
; eip
|
||||
; cs
|
||||
; eflags
|
||||
|
||||
pusha ; eax, ecx, edx, ebx, esp, ebp, esi, edi
|
||||
|
||||
push gs
|
||||
push fs
|
||||
push es
|
||||
push ds
|
||||
|
||||
mov ax, 0x10
|
||||
mov ax, 0x10 ; load kernel data selector
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
push dword %1 ; Push IRQ number
|
||||
call irq_handler
|
||||
add esp, 4 ; Clean up stack
|
||||
push esp ; pass pointer to registers_t
|
||||
call interrupt_dispatcher
|
||||
add esp, 4 ; I don't remember what this does... but don't remove it
|
||||
; NVM, I remember: it cleans up the registers_t* argument we passed to interrupt_dispatcher
|
||||
|
||||
; Send EOI
|
||||
mov al, 0x20
|
||||
mov bl, %1
|
||||
cmp bl, 8
|
||||
jb .skip_slave_eoi
|
||||
out 0xA0, al
|
||||
.skip_slave_eoi:
|
||||
out 0x20, al
|
||||
; don't do this yet, it corrupts stuff. wait until the scheduler is finished
|
||||
;mov esp, eax ; move the new stack pointer into esp
|
||||
|
||||
pop gs
|
||||
pop fs
|
||||
pop es
|
||||
pop ds
|
||||
|
||||
popa
|
||||
iret
|
||||
|
||||
add esp, 8 ; remove int_no + err_code
|
||||
|
||||
iret ; return from interrupt
|
||||
|
||||
|
||||
; ============================================================
|
||||
; IRQ STUBS
|
||||
; ============================================================
|
||||
|
||||
%macro IRQ 1
|
||||
irq_stub_%+%1:
|
||||
push dword 0 ; fake error code
|
||||
push dword (32 + %1) ; vector number
|
||||
jmp interrupt_entry
|
||||
%endmacro
|
||||
|
||||
|
||||
; Define 16 IRQ stubs
|
||||
irq_stub 0
|
||||
irq_stub 1
|
||||
irq_stub 2
|
||||
irq_stub 3
|
||||
irq_stub 4
|
||||
irq_stub 5
|
||||
irq_stub 6
|
||||
irq_stub 7
|
||||
irq_stub 8
|
||||
irq_stub 9
|
||||
irq_stub 10
|
||||
irq_stub 11
|
||||
irq_stub 12
|
||||
irq_stub 13
|
||||
irq_stub 14
|
||||
irq_stub 15
|
||||
IRQ 0
|
||||
IRQ 1
|
||||
IRQ 2
|
||||
IRQ 3
|
||||
IRQ 4
|
||||
IRQ 5
|
||||
IRQ 6
|
||||
IRQ 7
|
||||
IRQ 8
|
||||
IRQ 9
|
||||
IRQ 10
|
||||
IRQ 11
|
||||
IRQ 12
|
||||
IRQ 13
|
||||
IRQ 14
|
||||
IRQ 15
|
||||
IRQ 16
|
||||
IRQ 17
|
||||
IRQ 18
|
||||
IRQ 19
|
||||
|
||||
irq_stub_table:
|
||||
%assign i 0
|
||||
%rep 16
|
||||
%rep 20
|
||||
dd irq_stub_%+i
|
||||
%assign i i+1
|
||||
%endrep
|
||||
|
||||
; --------------------------------------------
|
||||
; ------------------- ISRs -------------------
|
||||
; --------------------------------------------
|
||||
|
||||
; Common exception handler entry point
|
||||
isr_common_handler:
|
||||
pusha ; Push general-purpose registers
|
||||
push ds
|
||||
push es
|
||||
push fs
|
||||
push gs
|
||||
; ============================================================
|
||||
; EXCEPTION STUBS
|
||||
; ============================================================
|
||||
|
||||
; Load known-good segment selectors
|
||||
mov ax, 0x10
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
; Print exception number and error code
|
||||
; You can insert direct port writes or call kernel logging function here
|
||||
; For now, just hang
|
||||
.halt:
|
||||
cli
|
||||
hlt
|
||||
jmp .halt
|
||||
|
||||
; If you want to later restore:
|
||||
pop gs
|
||||
pop fs
|
||||
pop es
|
||||
pop ds
|
||||
popa
|
||||
add esp, 8 ; clean up int_no + err_code
|
||||
iret
|
||||
|
||||
; Macro: for exceptions with error code
|
||||
%macro isr_err_stub 1
|
||||
%macro ISR_NOERR 1
|
||||
isr_stub_%+%1:
|
||||
cli
|
||||
push dword %1 ; interrupt number
|
||||
jmp isr_common_handler
|
||||
push dword 0 ; fake error code
|
||||
push dword %1 ; interrupt number
|
||||
jmp interrupt_entry
|
||||
%endmacro
|
||||
|
||||
; Macro: for exceptions without error code
|
||||
%macro isr_no_err_stub 1
|
||||
%macro ISR_ERR 1
|
||||
isr_stub_%+%1:
|
||||
cli
|
||||
push dword 0 ; fake error code
|
||||
push dword %1 ; interrupt number
|
||||
jmp isr_common_handler
|
||||
push dword %1 ; interrupt number
|
||||
jmp interrupt_entry
|
||||
%endmacro
|
||||
|
||||
; Define all 32 exception stubs
|
||||
isr_no_err_stub 0
|
||||
isr_no_err_stub 1
|
||||
isr_no_err_stub 2
|
||||
isr_no_err_stub 3
|
||||
isr_no_err_stub 4
|
||||
isr_no_err_stub 5
|
||||
isr_no_err_stub 6
|
||||
isr_no_err_stub 7
|
||||
isr_err_stub 8
|
||||
isr_no_err_stub 9
|
||||
isr_err_stub 10
|
||||
isr_err_stub 11
|
||||
isr_err_stub 12
|
||||
isr_err_stub 13
|
||||
isr_err_stub 14
|
||||
isr_no_err_stub 15
|
||||
isr_no_err_stub 16
|
||||
isr_err_stub 17
|
||||
isr_no_err_stub 18
|
||||
isr_no_err_stub 19
|
||||
isr_no_err_stub 20
|
||||
isr_no_err_stub 21
|
||||
isr_no_err_stub 22
|
||||
isr_no_err_stub 23
|
||||
isr_no_err_stub 24
|
||||
isr_no_err_stub 25
|
||||
isr_no_err_stub 26
|
||||
isr_no_err_stub 27
|
||||
isr_no_err_stub 28
|
||||
isr_no_err_stub 29
|
||||
isr_err_stub 30
|
||||
isr_no_err_stub 31
|
||||
|
||||
; Create jump table
|
||||
; Exceptions 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
|
||||
|
||||
@ -3,25 +3,16 @@
|
||||
Mostly so I could get more experience in assembler.
|
||||
*/
|
||||
|
||||
/*
|
||||
DO NOT USE "pusha" AND/OR "popa"!!!
|
||||
THEY ARE DEPRECATED (or something like that)
|
||||
AND SHOULD NOT BE USED!!!
|
||||
INSTEAD PUSH/POP REGISTERS ON/OFF THE STACK INDIVIDUALLY!!!
|
||||
*/
|
||||
|
||||
|
||||
.section .text
|
||||
|
||||
.global _enable_paging_asm
|
||||
|
||||
.global _push_regs
|
||||
.global _pop_regs
|
||||
|
||||
.global _hang_asm
|
||||
.global _halt_asm
|
||||
|
||||
.global _sti_asm
|
||||
.global _cli_asm
|
||||
|
||||
|
||||
_enable_paging_asm:
|
||||
@ -34,30 +25,6 @@ _enable_paging_asm:
|
||||
pop %eax
|
||||
|
||||
ret
|
||||
|
||||
_push_regs:
|
||||
push %eax
|
||||
push %ebx
|
||||
push %ecx
|
||||
push %edx
|
||||
push %esi
|
||||
push %edi
|
||||
push %esp
|
||||
push %ebp
|
||||
|
||||
ret
|
||||
|
||||
_pop_regs:
|
||||
pop %ebp
|
||||
pop %esp
|
||||
pop %edi
|
||||
pop %esi
|
||||
pop %edx
|
||||
pop %ecx
|
||||
pop %ebx
|
||||
pop %eax
|
||||
|
||||
ret
|
||||
|
||||
_hang_asm:
|
||||
hlt
|
||||
@ -70,5 +37,7 @@ _halt_asm:
|
||||
_sti_asm:
|
||||
sti
|
||||
ret
|
||||
|
||||
.section .data
|
||||
|
||||
_cli_asm:
|
||||
cli
|
||||
ret
|
||||
|
||||
386
boot/dump.txt
Normal file
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
|
||||
6
dev_notes/memory_mapping.txt
Normal file
6
dev_notes/memory_mapping.txt
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
|
||||
so far, heap starts at 0xC2000000, and is (8 * 1024 * 1024) (0x80000) or (8MiB) bytes, and ends at 0xC2080000
|
||||
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
Notes about the PS/2 keyboard driver.
|
||||
|
||||
|
||||
the actual key-codes are not what you might expect.
|
||||
what I mean is, what does 0x3F mean? what key was pressed?
|
||||
The keyset used by Espresso is pretty much the ASCII code set.
|
||||
Minus a few codes, some are replaced with other functions.
|
||||
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);
|
||||
}
|
||||
@ -11,7 +11,7 @@
|
||||
#define ALIGN_UP(x) (((x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
|
||||
|
||||
|
||||
elf_executable_t* load_elf32(void* elf_data)
|
||||
int load_elf32(void* elf_data, elf_executable_t** ptr)
|
||||
{
|
||||
Elf32_Ehdr* ehdr = (Elf32_Ehdr*)elf_data;
|
||||
|
||||
@ -19,18 +19,19 @@ elf_executable_t* load_elf32(void* elf_data)
|
||||
if (memcmp(ehdr->e_ident, (uint8_t*)("\x7F""ELF"), 4) != 0)
|
||||
{
|
||||
printf("Invalid ELF file\n");
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ehdr->e_machine != 3 || ehdr->e_type != 2)
|
||||
{
|
||||
printf("Unsupported ELF type or architecture\n");
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
Elf32_Phdr* phdrs = (Elf32_Phdr*)((uint8_t*)elf_data + ehdr->e_phoff);
|
||||
|
||||
for (int i = 0; i < ehdr->e_phnum; i++) {
|
||||
for (int i = 0; i < ehdr->e_phnum; i++)
|
||||
{
|
||||
Elf32_Phdr* phdr = &phdrs[i];
|
||||
if (phdr->p_type != PT_LOAD)
|
||||
{
|
||||
@ -43,7 +44,7 @@ elf_executable_t* load_elf32(void* elf_data)
|
||||
|
||||
for (uint32_t page = 0; page < segment_pages; page++)
|
||||
{
|
||||
void* phys = alloc_page();
|
||||
void* phys = pmm_alloc_page();
|
||||
void* virt = (void*)(vaddr_start + page * PAGE_SIZE);
|
||||
map_page(phys, virt);
|
||||
memset(virt, 0, PAGE_SIZE);
|
||||
@ -53,11 +54,23 @@ elf_executable_t* load_elf32(void* elf_data)
|
||||
void* src = (uint8_t*)elf_data + phdr->p_offset;
|
||||
memcpy(dest, src, phdr->p_filesz);
|
||||
|
||||
printf("Mapped segment %d: 0x%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
|
||||
}
|
||||
|
||||
*ptr = malloc(sizeof(elf_executable_t));
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
(*ptr)->entry_point = (elf_entry_t)(uintptr_t) ehdr->e_entry;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
elf_executable_t* result = malloc(sizeof(elf_executable_t));
|
||||
result->entry_point = (void*)(uintptr_t)ehdr->e_entry;
|
||||
return result;
|
||||
result->entry_point = (elf_entry_t)(uintptr_t)ehdr->e_entry;*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
48
drivers/exec/secf.c
Normal file
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 */
|
||||
}
|
||||
376
drivers/fs/fat16.c
Normal file
376
drivers/fs/fat16.c
Normal file
@ -0,0 +1,376 @@
|
||||
#include <string.h>
|
||||
#include <drivers/ide.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <fs/fat16.h>
|
||||
|
||||
/*
|
||||
READ BELOW!!!
|
||||
Before any of you (or me,) use this code, please note that the functions below REQUIRE 8.3 formatted names.
|
||||
in fat16.h there is a helper function for convertion between normal filenames and 8.3 ones. ('filename_to_83', see static implementation in fat16.h)
|
||||
*/
|
||||
|
||||
static fat16_fs_t fs;
|
||||
static uint8_t boot_sector[SECTOR_SIZE];
|
||||
|
||||
int fat16_mount(uint8_t drive)
|
||||
{
|
||||
if (read_sector(0, boot_sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
(void) drive;
|
||||
|
||||
fs.bytes_per_sector = boot_sector[11] | (boot_sector[12] << 8);
|
||||
fs.sectors_per_cluster = boot_sector[13];
|
||||
fs.reserved_sector_count = boot_sector[14] | (boot_sector[15] << 8);
|
||||
fs.num_fats = boot_sector[16];
|
||||
fs.root_entry_count = boot_sector[17] | (boot_sector[18] << 8);
|
||||
fs.total_sectors_16 = boot_sector[19] | (boot_sector[20] << 8);
|
||||
fs.sectors_per_fat = boot_sector[22] | (boot_sector[23] << 8);
|
||||
fs.total_sectors = fs.total_sectors_16 != 0 ? fs.total_sectors_16 : boot_sector[32] | (boot_sector[33]<<8) | (boot_sector[34]<<16) | (boot_sector[35]<<24);
|
||||
fs.fat_start_lba = fs.reserved_sector_count;
|
||||
fs.root_dir_lba = fs.fat_start_lba + (fs.num_fats * fs.sectors_per_fat);
|
||||
fs.data_start_lba = fs.root_dir_lba + ((fs.root_entry_count * 32 + (fs.bytes_per_sector - 1)) / fs.bytes_per_sector);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t cluster_to_lba(uint16_t cluster)
|
||||
{
|
||||
return fs.data_start_lba + (cluster - 2) * fs.sectors_per_cluster;
|
||||
}
|
||||
|
||||
/* ----------------------- FAT helpers ------------------------- */
|
||||
static int read_fat_entry(uint16_t cluster, uint16_t* out_value)
|
||||
{
|
||||
uint32_t offset = (uint32_t)cluster * 2;
|
||||
uint32_t sector_index = offset / fs.bytes_per_sector;
|
||||
uint32_t idx = offset % fs.bytes_per_sector;
|
||||
uint8_t sector[SECTOR_SIZE];
|
||||
|
||||
if (read_sector(fs.fat_start_lba + sector_index, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (idx == (uint32_t)(fs.bytes_per_sector - 1))
|
||||
{
|
||||
/* entry spans boundary -> read next sector */
|
||||
uint8_t next_sector[SECTOR_SIZE];
|
||||
|
||||
if (read_sector(fs.fat_start_lba + sector_index + 1, next_sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
*out_value = sector[idx] | (next_sector[0] << 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
*out_value = sector[idx] | (sector[idx + 1] << 8);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int write_fat_entry(uint16_t cluster, uint16_t value)
|
||||
{
|
||||
uint32_t offset = cluster * 2;
|
||||
uint32_t sector_lba = fs.fat_start_lba + (offset / fs.bytes_per_sector);
|
||||
uint8_t sector[SECTOR_SIZE];
|
||||
|
||||
if (read_sector(sector_lba, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sector[offset % fs.bytes_per_sector] = value & 0xFF;
|
||||
sector[(offset % fs.bytes_per_sector) + 1] = (value >> 8) & 0xFF;
|
||||
|
||||
/* write to all FAT copies */
|
||||
for (uint8_t f = 0; f < fs.num_fats; f++)
|
||||
{
|
||||
if (write_sector(fs.fat_start_lba + f * fs.sectors_per_fat + (offset / fs.bytes_per_sector), sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int find_free_cluster(uint16_t* out_cluster)
|
||||
{
|
||||
uint16_t total_clusters = (fs.total_sectors - fs.data_start_lba) / fs.sectors_per_cluster;
|
||||
uint16_t value;
|
||||
for (uint16_t c = 2; c < total_clusters; c++)
|
||||
{
|
||||
if (read_fat_entry(c, &value) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (value == 0x0000)
|
||||
{
|
||||
*out_cluster = c;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1; /* no free cluster */
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- Root directory ------------------------- */
|
||||
static int find_free_root_entry(uint32_t* out_sector, uint32_t* out_offset)
|
||||
{
|
||||
uint32_t root_dir_sectors = ((fs.root_entry_count * 32) + (fs.bytes_per_sector - 1)) / fs.bytes_per_sector;
|
||||
uint8_t sector[SECTOR_SIZE];
|
||||
|
||||
for (uint32_t i = 0; i < root_dir_sectors; i++)
|
||||
{
|
||||
if (read_sector(fs.root_dir_lba + i, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (uint32_t offset = 0; offset < SECTOR_SIZE; offset += 32)
|
||||
{
|
||||
if (sector[offset] == 0x00 || sector[offset] == 0xE5)
|
||||
{
|
||||
*out_sector = fs.root_dir_lba + i;
|
||||
*out_offset = offset;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* -------------------- File operations ----------------------- */
|
||||
int fat16_find_file(const char* name, fat16_file_t* out_file)
|
||||
{
|
||||
uint32_t root_dir_sectors = ((fs.root_entry_count * 32) + (fs.bytes_per_sector - 1)) / fs.bytes_per_sector;
|
||||
uint8_t sector[SECTOR_SIZE];
|
||||
|
||||
for (uint32_t i = 0; i < root_dir_sectors; i++)
|
||||
{
|
||||
if (read_sector(fs.root_dir_lba + i, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (uint32_t offset = 0; offset < SECTOR_SIZE; offset += 32)
|
||||
{
|
||||
if (sector[offset] == 0x00)
|
||||
{
|
||||
return -1; /* no more entries */
|
||||
}
|
||||
else if (sector[offset] == 0xE5)
|
||||
{
|
||||
continue; /* deleted entry */
|
||||
}
|
||||
|
||||
if (memcmp(sector + offset, name, 11) == 0)
|
||||
{
|
||||
memcpy(out_file->name, sector + offset, 12);
|
||||
out_file->attr = sector[offset + 11];
|
||||
out_file->first_cluster = sector[offset + 26] | (sector[offset + 27] << 8);
|
||||
out_file->size = sector[offset + 28] | (sector[offset + 29] << 8) | (sector[offset + 30] << 16) | (sector[offset + 31] << 24);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fat16_create_file(const char* name, fat16_file_t* out_file)
|
||||
{
|
||||
uint16_t free_cluster;
|
||||
|
||||
if (find_free_cluster(&free_cluster) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t sector_lba, offset;
|
||||
|
||||
if (find_free_root_entry(§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
|
||||
}
|
||||
|
||||
117
drivers/fs/ssfs.c
Normal file
117
drivers/fs/ssfs.c
Normal file
@ -0,0 +1,117 @@
|
||||
#include <types.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <drivers/ide.h>
|
||||
|
||||
#include <fs/ssfs.h>
|
||||
|
||||
|
||||
|
||||
#define SSFS_START_LBA 16
|
||||
#define SSFS_FILE_HEADER_SIZE_BYTES 32
|
||||
|
||||
|
||||
int ssfs_read_file(const char* name, void* buffer, int size)
|
||||
{
|
||||
if (strlen(name) > 15)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t header_buf[512];
|
||||
int r = read_sector(16, header_buf);
|
||||
|
||||
if (r != 0)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
ssfs_file_header_t f;
|
||||
memcpy(&f, header_buf, sizeof(f));
|
||||
|
||||
if (strncmp(f.filename, name, 15) != 0)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
/* Clamp read size to actual file size */
|
||||
if (size > (int)f.num_bytes)
|
||||
size = (int)f.num_bytes;
|
||||
|
||||
int total_read = 0;
|
||||
int sector_count = div_round_up(size, 512);
|
||||
uint8_t sector_data[512];
|
||||
|
||||
for (int k = 0; k < sector_count; k++)
|
||||
{
|
||||
r = read_sector(f.start_sector + k, sector_data);
|
||||
|
||||
if (r != 0)
|
||||
{
|
||||
return -4; /* I/O error */
|
||||
}
|
||||
|
||||
int to_copy = size - total_read;
|
||||
|
||||
if (to_copy > 512)
|
||||
{
|
||||
to_copy = 512;
|
||||
}
|
||||
|
||||
memcpy((uint8_t*)buffer + total_read, sector_data, to_copy);
|
||||
total_read += to_copy;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* size is number of bytes */
|
||||
int ssfs_write_file(const char* name, void* data, int size)
|
||||
{
|
||||
ssfs_file_header_t* f = (ssfs_file_header_t*) malloc(sizeof(ssfs_file_header_t));
|
||||
memset(f, 0, sizeof(ssfs_file_header_t));
|
||||
|
||||
if (strlen(name) > 15)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(f->filename, name);
|
||||
f->num_sectors = 0;
|
||||
|
||||
int sector_count = div_round_up(size, 512);
|
||||
|
||||
uint8_t* buffer = (uint8_t*) malloc(sector_count * 512);
|
||||
|
||||
memset(buffer, 0, sector_count * 512);
|
||||
memcpy(buffer, data, (size_t) size);
|
||||
|
||||
int r = 0;
|
||||
|
||||
f->start_sector = 32;
|
||||
|
||||
for (int k = 0; k < sector_count; k++)
|
||||
{
|
||||
r = write_sector(f->start_sector + k, buffer + (k * 512));
|
||||
|
||||
if (r != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
f->num_sectors = sector_count;
|
||||
f->num_bytes = (uint32_t) size;
|
||||
|
||||
uint8_t header_buf[512];
|
||||
memset(header_buf, 0, 512);
|
||||
memcpy(header_buf, f, sizeof(*f));
|
||||
write_sector(16, header_buf);
|
||||
|
||||
free(buffer);
|
||||
free(f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1,24 +1,50 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <tty.h>
|
||||
|
||||
#include <fs/vfs.h>
|
||||
|
||||
|
||||
typedef struct vfs_file_header {
|
||||
char* filename; /* The filename, not the path. */
|
||||
|
||||
int32_t fd;
|
||||
|
||||
uint8_t type_info; /* Bits 0 - 3 -> File type, Bits 4 - 7 FS type */
|
||||
|
||||
uint16_t* fs_header;
|
||||
|
||||
struct vfs_file_header* next; /* Linked list */
|
||||
} vfs_file_header_t;
|
||||
/* we use something similar to the Linux kernel in terms of a VFS system */
|
||||
|
||||
|
||||
vfs_file_header_t* root;
|
||||
|
||||
|
||||
|
||||
struct fdtable {
|
||||
struct file* fds[MAX_FDS];
|
||||
};
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
struct fdtable* vfs_init_kernel_fdtable(void)
|
||||
{
|
||||
struct fdtable* ft = malloc(sizeof(struct fdtable));
|
||||
struct file* _stdout = malloc(sizeof(struct file));
|
||||
struct file* _stdin = malloc(sizeof(struct file));
|
||||
|
||||
if (!ft || !_stdin || !_stdout)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_stdout->f_inode = NULL;
|
||||
_stdout->f_offset = 0;
|
||||
_stdout->f_refcount = 1;
|
||||
_stdout->f_ops = { .read = NULL, .write = vfs_handle_stdout };
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
int init_vfs(int argc, char** argv)
|
||||
{
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
@ -28,5 +54,7 @@ vfs_file_header_t* root;
|
||||
wow.
|
||||
and now my CPU fan is going nuts.
|
||||
|
||||
--update: now it works. I had to go back to nouveau instead of the proprietary nVidia drivers..
|
||||
--update: now it works. I had to go back to nouveau instead of the proprietary nVidia®©™ drivers..
|
||||
|
||||
--update: I wrote what months ago. now is 3/12/2026, I don't even remember what was going on well. wow.
|
||||
*/
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
uint64_t gdt[GDT_ENTRIES];
|
||||
|
||||
struct {
|
||||
uint16_t limit;
|
||||
uint32_t base;
|
||||
uint16_t limit;
|
||||
uint32_t base;
|
||||
} __attribute__((packed)) gp;
|
||||
|
||||
|
||||
|
||||
173
drivers/graphics/vga.c
Normal file
173
drivers/graphics/vga.c
Normal file
@ -0,0 +1,173 @@
|
||||
#include <types.h>
|
||||
#include <mm/paging.h>
|
||||
#include <stdio.h>
|
||||
#include <port_io.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <drivers/graphics/vga.h>
|
||||
|
||||
#define VBE_DISPI_IOPORT_INDEX 0x01CE
|
||||
#define VBE_DISPI_IOPORT_DATA 0x01CF
|
||||
|
||||
#define VBE_DISPI_INDEX_ID 0x0
|
||||
#define VBE_DISPI_INDEX_XRES 0x1
|
||||
#define VBE_DISPI_INDEX_YRES 0x2
|
||||
#define VBE_DISPI_INDEX_BPP 0x3
|
||||
#define VBE_DISPI_INDEX_ENABLE 0x4
|
||||
#define VBE_DISPI_INDEX_BANK 0x5
|
||||
#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
|
||||
#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
|
||||
#define VBE_DISPI_INDEX_X_OFFSET 0x8
|
||||
#define VBE_DISPI_INDEX_Y_OFFSET 0x9
|
||||
|
||||
#define VBE_DISPI_DISABLED 0x00
|
||||
#define VBE_DISPI_ENABLED 0x01
|
||||
#define VBE_DISPI_LFB_ENABLED 0x40
|
||||
|
||||
static bool bga_init = false;
|
||||
static bool bga_error = false;
|
||||
|
||||
uint32_t current_bpp = 0;
|
||||
uint32_t current_xres = 0;
|
||||
uint32_t current_yres = 0;
|
||||
|
||||
static struct bga_framebuffer bga_fb;
|
||||
|
||||
void init_bga_framebuffer(uint32_t* _p)
|
||||
{
|
||||
uint32_t width = 1024;
|
||||
uint32_t height = 768;
|
||||
uint32_t bpp = 32;
|
||||
|
||||
uint32_t pitch = width * (bpp / 8);
|
||||
|
||||
uint32_t fb_size = pitch * height;
|
||||
|
||||
fb_size = (fb_size + 0xFFF) & ~0xFFF;
|
||||
|
||||
uint8_t* bp = (uint8_t*) _p;
|
||||
|
||||
for (uint32_t off = 0; off < fb_size; off += 0x1000)
|
||||
{
|
||||
map_page(bp + off, bp + off);
|
||||
}
|
||||
|
||||
|
||||
bga_fb.addr = _p;
|
||||
bga_fb.bpp = bpp;
|
||||
bga_fb.height = height;
|
||||
bga_fb.width = width;
|
||||
bga_fb.pitch = pitch;
|
||||
|
||||
bga_init = true;
|
||||
}
|
||||
|
||||
uint8_t* bga_get_framebuffer(void)
|
||||
{
|
||||
return bga_fb.addr;
|
||||
}
|
||||
|
||||
void bga_write_register(uint16_t index, uint16_t data)
|
||||
{
|
||||
outw(VBE_DISPI_IOPORT_INDEX, index);
|
||||
outw(VBE_DISPI_IOPORT_DATA, data);
|
||||
}
|
||||
|
||||
uint16_t bga_read_register(uint16_t index)
|
||||
{
|
||||
outw(VBE_DISPI_IOPORT_INDEX, index);
|
||||
return inw(VBE_DISPI_IOPORT_DATA);
|
||||
}
|
||||
|
||||
void bga_set_video_mode(uint32_t width, uint32_t height, uint32_t bit_depth)
|
||||
{
|
||||
bga_write_register(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);
|
||||
bga_write_register(VBE_DISPI_INDEX_XRES, width);
|
||||
bga_write_register(VBE_DISPI_INDEX_YRES, height);
|
||||
bga_write_register(VBE_DISPI_INDEX_BPP, bit_depth);
|
||||
bga_write_register(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
|
||||
|
||||
/* now we check to see if any info we gave was rejected, in which case everything would be the way it was before we wrote the configuration info. */
|
||||
uint16_t bpp = bga_read_register(VBE_DISPI_INDEX_BPP);
|
||||
if (bpp != bit_depth)
|
||||
{
|
||||
bga_error = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
current_bpp = bit_depth;
|
||||
current_xres = width;
|
||||
current_yres = height;
|
||||
}
|
||||
}
|
||||
|
||||
void bga_defaults(void)
|
||||
{
|
||||
// Disable device while changing settings
|
||||
bga_write_register(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);
|
||||
|
||||
// Set resolution
|
||||
bga_write_register(VBE_DISPI_INDEX_XRES, 1024);
|
||||
bga_write_register(VBE_DISPI_INDEX_YRES, 768);
|
||||
bga_write_register(VBE_DISPI_INDEX_BPP, 32);
|
||||
|
||||
// Enable graphics + linear framebuffer
|
||||
bga_write_register(
|
||||
VBE_DISPI_INDEX_ENABLE,
|
||||
VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED
|
||||
);
|
||||
}
|
||||
|
||||
/*void bga_putpixel(uint32_t x, uint32_t y, uint32_t color)
|
||||
{
|
||||
if (current_bpp == 16)
|
||||
{
|
||||
uint16_t* fb = (uint16_t*) bga_framebuffer;
|
||||
uint32_t idx = (y * current_xres + x) * 2;
|
||||
|
||||
*(fb + idx) = (uint16_t) color;
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
void bga_putpixel(uint32_t x, uint32_t y, uint32_t color)
|
||||
{
|
||||
uint32_t bytes_per_pixel = bga_fb.bpp / 8;
|
||||
|
||||
uint8_t* pixel = (uint8_t*)bga_fb.addr + (y * bga_fb.pitch) + (x * bytes_per_pixel);
|
||||
|
||||
*(volatile uint32_t*)pixel = color;
|
||||
}
|
||||
|
||||
void bga_drawline(int x0, int y0, int x1, int y1, uint32_t color)
|
||||
{
|
||||
int dx = abs(x1 - x0);
|
||||
int dy = abs(y1 - y0);
|
||||
|
||||
int sx = (x0 < x1) ? 1 : -1;
|
||||
int sy = (y0 < y1) ? 1 : -1;
|
||||
|
||||
int err = dx - dy;
|
||||
|
||||
while (1)
|
||||
{
|
||||
bga_putpixel(x0, y0, color);
|
||||
|
||||
if (x0 == x1 && y0 == y1)
|
||||
break;
|
||||
|
||||
int e2 = err * 2;
|
||||
|
||||
if (e2 > -dy)
|
||||
{
|
||||
err -= dy;
|
||||
x0 += sx;
|
||||
}
|
||||
|
||||
if (e2 < dx)
|
||||
{
|
||||
err += dx;
|
||||
y0 += sy;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -35,6 +35,12 @@ static int32_t ide_wait_ready(uint16_t io)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int get_sector_size(uint8_t drive)
|
||||
{
|
||||
(void) drive;
|
||||
return SECTOR_SIZE;
|
||||
}
|
||||
|
||||
int32_t ide_identify(uint8_t drive, uint16_t* buffer)
|
||||
{
|
||||
uint16_t io = ATA_PRIMARY_IO;
|
||||
@ -63,10 +69,16 @@ int32_t ide_identify(uint8_t drive, uint16_t* buffer)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ide_initialize(void) {
|
||||
void ide_initialize(void)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
printf("[ IDE ] Initializing IDE system...\n");
|
||||
#endif
|
||||
|
||||
outb(ATA_PRIMARY_CTRL, 0x02); /* Disable IRQs from IDE disk controllers TODO: should probably use IRQs soon */
|
||||
|
||||
uint16_t identify_buf[256];
|
||||
volatile uint16_t identify_buf[256];
|
||||
|
||||
if (ide_identify(0, identify_buf) == 0)
|
||||
{
|
||||
char model[41];
|
||||
@ -78,9 +90,18 @@ void ide_initialize(void) {
|
||||
model[40] = 0;
|
||||
printf("Disk model: %s\n", model);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("ide_initialize(): ide_identify(0, identify_buf) did NOT return 0!\n");
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("[ IDE ] IDE initialized\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
int32_t ide_read48(uint8_t drive, uint64_t lba, uint8_t sector_count, void* buffer) {
|
||||
int32_t ide_read48(uint8_t drive, uint64_t lba, uint8_t sector_count, void* buffer)
|
||||
{
|
||||
if (sector_count == 0)
|
||||
{
|
||||
return -1;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1,68 +1,76 @@
|
||||
#include <stdio.h>
|
||||
#include <drivers/ps2_keyboard.h>
|
||||
#include <drivers/pit.h>
|
||||
#include <port_io.h>
|
||||
|
||||
/* TEMP DEBUG */
|
||||
#include <tty.h>
|
||||
|
||||
#include <kernel/syscall.h>
|
||||
|
||||
#include <drivers/irq.h>
|
||||
|
||||
#define NUM_IRQS 0x90
|
||||
|
||||
irq_func_t func_list[NUM_IRQS];
|
||||
irq_func_t aux_func_list[NUM_IRQS];
|
||||
#define MAX_IRQ_HANDLERS 128 /* the maximum number of irq handlers */
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t irq_no;
|
||||
irq_func_t func;
|
||||
} irq_handler_t;
|
||||
|
||||
static volatile uint32_t num_irqs_missed = 0;
|
||||
uint32_t num_irq_handlers = 0;
|
||||
irq_handler_t handler_list[MAX_IRQ_HANDLERS];
|
||||
|
||||
volatile uint32_t num_irqs_missed = 0;
|
||||
|
||||
void irq_init(void)
|
||||
{
|
||||
memset(func_list, 0x0, NUM_IRQS);
|
||||
memset(aux_func_list, 0x0, NUM_IRQS);
|
||||
|
||||
set_irq_handler(0, (irq_func_t*)pit_handler);
|
||||
set_irq_handler(1, (irq_func_t*)keyboard_handler);
|
||||
}
|
||||
|
||||
void irq_handler(uint8_t irq_number)
|
||||
{
|
||||
if (irq_number < NUM_IRQS)
|
||||
for (int i = 0; i < MAX_IRQ_HANDLERS; i++)
|
||||
{
|
||||
if (func_list[irq_number])
|
||||
{
|
||||
func_list[irq_number]();
|
||||
}
|
||||
else if (aux_func_list[irq_number])
|
||||
{
|
||||
aux_func_list[irq_number]();
|
||||
}
|
||||
else
|
||||
{
|
||||
num_irqs_missed++;
|
||||
}
|
||||
handler_list[i].irq_no = 0;
|
||||
handler_list[i].func = NULL;
|
||||
}
|
||||
set_irq_handler(0, (irq_func_t) pit_handler);
|
||||
//set_irq_handler(1, (irq_func_t) ps2_keyboard_handler);
|
||||
}
|
||||
|
||||
void set_irq_handler(uint32_t num, irq_func_t* handler)
|
||||
registers_t* irq_handler(uint32_t irq, registers_t* regs)
|
||||
{
|
||||
if (num < NUM_IRQS)
|
||||
{
|
||||
func_list[num] = (irq_func_t)handler;
|
||||
}
|
||||
}
|
||||
uint8_t funcs_called = 0;
|
||||
|
||||
void add_irq_handler(uint32_t num, irq_func_t* handler)
|
||||
{
|
||||
if (num < NUM_IRQS)
|
||||
{
|
||||
if (func_list[num] != 0x0)
|
||||
if (num_irq_handlers > 0)
|
||||
{
|
||||
for (unsigned int i = 0; i < MAX_IRQ_HANDLERS; i++)
|
||||
{
|
||||
if (aux_func_list[num] == 0x0)
|
||||
if (handler_list[i].irq_no == irq && handler_list[i].func != NULL)
|
||||
{
|
||||
aux_func_list[num] = (irq_func_t)handler;
|
||||
regs = handler_list[i].func(regs);
|
||||
funcs_called++;
|
||||
/* PIC IRQ acknowledgement happens in idt.c */
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (funcs_called == 0)
|
||||
{
|
||||
num_irqs_missed++;
|
||||
}
|
||||
|
||||
return regs;
|
||||
}
|
||||
|
||||
uint32_t get_interrupts_missed(void)
|
||||
{
|
||||
return num_irqs_missed;
|
||||
}
|
||||
|
||||
void set_irq_handler(uint32_t num, irq_func_t handler)
|
||||
{
|
||||
if (num < MAX_IRQ_HANDLERS)
|
||||
{
|
||||
handler_list[num].irq_no = num;
|
||||
handler_list[num].func = handler;
|
||||
|
||||
func_list[num] = (irq_func_t)handler;
|
||||
num_irq_handlers++;
|
||||
}
|
||||
}
|
||||
|
||||
201
drivers/keyboard.c
Normal file
201
drivers/keyboard.c
Normal file
@ -0,0 +1,201 @@
|
||||
#include <types.h>
|
||||
#include <port_io.h>
|
||||
#include <new_tty.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <drivers/irq.h>
|
||||
|
||||
#include <drivers/keyboard.h>
|
||||
|
||||
/*
|
||||
PS/2 Controller IO Ports
|
||||
|
||||
The PS/2 Controller itself uses 2 IO ports (IO ports 0x60 and 0x64). Like many IO ports, reads and writes may access different internal registers.
|
||||
|
||||
Historical note: The PC-XT PPI had used port 0x61 to reset the keyboard interrupt request signal (among other unrelated functions). Port 0x61 has no keyboard related functions on AT and PS/2 compatibles.
|
||||
IO Port Access Type Purpose
|
||||
0x60 Read/Write Data Port
|
||||
0x64 Read Status Register
|
||||
0x64 Write Command Register
|
||||
*/
|
||||
|
||||
#define PS2_DATA_PORT 0x60
|
||||
#define PS2_STATUS_PORT 0x64
|
||||
|
||||
#define KEYBOARD_IRQ 1
|
||||
|
||||
static const char scancode_map[128] = {
|
||||
0, 27, '1','2','3','4','5','6','7','8','9','0','-','=','\b', /* Backspace */
|
||||
'\t', /* Tab */
|
||||
'q','w','e','r','t','y','u','i','o','p','[',']','\n', /* Enter */
|
||||
0, /* Control */
|
||||
'a','s','d','f','g','h','j','k','l',';','\'','`',
|
||||
0, /* Left shift */
|
||||
'\\','z','x','c','v','b','n','m',',','.','/',
|
||||
0, /* Right shift */
|
||||
'*',
|
||||
0, /* Alt */
|
||||
' ', /* Spacebar */
|
||||
0, /* Caps lock */
|
||||
/* The rest are function and control keys */
|
||||
};
|
||||
|
||||
volatile uint32_t mods = 0;
|
||||
volatile bool keyboard_initialied = false;
|
||||
volatile bool extended = false;
|
||||
|
||||
int init_keyboard(void)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
printf("Initializing the keyboard...\n");
|
||||
#endif
|
||||
|
||||
keyboard_initialied = true;
|
||||
|
||||
set_irq_handler(1, (irq_func_t) keyboard_handler);
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("Keyboard initialized\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
registers_t* keyboard_handler(registers_t* regs)
|
||||
{
|
||||
if (!(inb(PS2_STATUS_PORT) & 1))
|
||||
{
|
||||
return regs;
|
||||
}
|
||||
|
||||
uint8_t scancode = inb(PS2_DATA_PORT);
|
||||
|
||||
if (scancode == 0xE0)
|
||||
{
|
||||
extended = true;
|
||||
return regs;
|
||||
}
|
||||
|
||||
bool is_release = scancode & 0x80;
|
||||
uint8_t key = scancode & 0x7F;
|
||||
|
||||
if (extended)
|
||||
{
|
||||
if (is_release)
|
||||
{
|
||||
if (key == 0x1D)
|
||||
{
|
||||
mods &= ~MODIFIER_RCTRL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (key == 0x1D)
|
||||
{
|
||||
mods |= MODIFIER_RCTRL;
|
||||
}
|
||||
}
|
||||
|
||||
/* delete key, should add this functionality */
|
||||
/*if (key == 0x53)*/
|
||||
|
||||
extended = false;
|
||||
return regs;
|
||||
}
|
||||
|
||||
if (is_release)
|
||||
{
|
||||
if (key == 0x2A || key == 0x36)
|
||||
{
|
||||
mods &= ~MODIFIER_SHIFT;
|
||||
}
|
||||
|
||||
return regs;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (key == 0x2A || key == 0x36)
|
||||
{
|
||||
mods |= MODIFIER_SHIFT;
|
||||
return regs;
|
||||
}
|
||||
else if (key == 0x3A)
|
||||
{
|
||||
mods ^= MODIFIER_CAPS;
|
||||
return regs;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t c = (uint16_t) scancode_map[scancode];
|
||||
|
||||
if (c)
|
||||
{
|
||||
//tty_receive_char(c, mods);
|
||||
char ch = tty_translate_char(c, mods);
|
||||
tty_input_char(tty_get_active(), ch);
|
||||
}
|
||||
|
||||
return regs;
|
||||
}
|
||||
|
||||
|
||||
/* Handle shift press/release */
|
||||
/*if (scancode == 0x2A || scancode == 0x36)
|
||||
{
|
||||
mods |= MODIFIER_SHIFT;
|
||||
return regs;
|
||||
}
|
||||
else if (scancode == 0xAA || scancode == 0xB6)
|
||||
{
|
||||
mods &= MODIFIER_SHIFT_DESTROY;
|
||||
return regs;
|
||||
}
|
||||
else if (scancode == 0x3A)
|
||||
{
|
||||
TOGGLE_BIT(mods, 0);
|
||||
return regs;
|
||||
}*/
|
||||
|
||||
|
||||
/*else if (scancode == 0xE0)
|
||||
{
|
||||
extended = true;
|
||||
return;
|
||||
}*/
|
||||
/* XXX: NOTE: we don't do extended codes yet. :NOTE :XXX */
|
||||
/*if (extended)
|
||||
{*/
|
||||
/*switch (scancode)
|
||||
{
|
||||
case 0x48:
|
||||
c = KEY_ARROW_UP;
|
||||
break;
|
||||
case 0x50:
|
||||
c = KEY_ARROW_DOWN;
|
||||
break;
|
||||
case 0x4B:
|
||||
c = KEY_ARROW_LEFT;
|
||||
break;
|
||||
case 0x4D:
|
||||
c = KEY_ARROW_RIGHT;
|
||||
break;
|
||||
default:
|
||||
c = KEY_NONE;
|
||||
break;
|
||||
}*/
|
||||
|
||||
|
||||
/*tty_receive_char(c, mod);
|
||||
|
||||
extended = false;
|
||||
|
||||
return;
|
||||
}*/
|
||||
|
||||
/*bool release = scancode & 0x80;
|
||||
scancode &= 0x7F;
|
||||
|
||||
if (release)
|
||||
{
|
||||
return regs;
|
||||
}*/
|
||||
499
drivers/new_tty.c
Normal file
499
drivers/new_tty.c
Normal file
@ -0,0 +1,499 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <processes.h>
|
||||
#include <sync.h>
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include <new_tty.h>
|
||||
|
||||
|
||||
|
||||
static tty_t ttys[MAX_TTYS];
|
||||
static uint8_t num_ttys = 0;
|
||||
static tty_t* active_tty = NULL;
|
||||
|
||||
static inline size_t next_index(size_t index)
|
||||
{
|
||||
return (index + 1) % TTY_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
static inline bool tty_empty(tty_t* tty)
|
||||
{
|
||||
return tty->head == tty->tail;
|
||||
}
|
||||
|
||||
static inline bool tty_full(tty_t* tty)
|
||||
{
|
||||
return ((tty->head + 1) % TTY_BUFFER_SIZE) == tty->tail;
|
||||
}
|
||||
|
||||
static inline bool is_canonical(tty_t* tty)
|
||||
{
|
||||
return (tty->flags & TTY_CANONICAL) != 0;
|
||||
}
|
||||
|
||||
static void raw_put(tty_t* tty, char c)
|
||||
{
|
||||
size_t next = (tty->raw_head + 1) % TTY_RAW_BUFFER_SIZE;
|
||||
|
||||
if (next != tty->raw_tail) // avoid overflow
|
||||
{
|
||||
tty->raw_buf[tty->raw_head] = c;
|
||||
tty->raw_head = next;
|
||||
}
|
||||
}
|
||||
|
||||
tty_t* tty_get_active(void)
|
||||
{
|
||||
return active_tty;
|
||||
}
|
||||
|
||||
int tty_fread(struct file* f, char* b, size_t s)
|
||||
{
|
||||
return (int) tty_read_active(b, s);
|
||||
}
|
||||
|
||||
void tty_backspace(tty_t* tty)
|
||||
{
|
||||
if (tty->head == tty->tail)
|
||||
{
|
||||
return; /* buffer empty */
|
||||
}
|
||||
//tty->head = (tty->head + TTY_BUFFER_SIZE - 1) % TTY_BUFFER_SIZE;
|
||||
tty->head = (tty->head + TTY_BUFFER_SIZE - 1) / TTY_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
void tty_and_flags(tty_t* tty, uint32_t flags)
|
||||
{
|
||||
tty->flags &= flags;
|
||||
}
|
||||
|
||||
uint32_t tty_get_flags(tty_t* tty)
|
||||
{
|
||||
return tty->flags;
|
||||
}
|
||||
|
||||
ssize_t tty_read_active(char* buf, size_t count)
|
||||
{
|
||||
return tty_read(active_tty, buf, count);
|
||||
}
|
||||
|
||||
/*
|
||||
this is special, because when this is called the char returned by this function
|
||||
is NOT added to the TTY buffer.
|
||||
This can be changed however by setting flag TTY_ADDCHAR_ALWAYS.
|
||||
*/
|
||||
/*char tty_get_char(void)
|
||||
{
|
||||
tty_t* tty = get_active_tty();
|
||||
if (!tty)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
IRQ_DISABLE();
|
||||
spin_lock(&tty->lock);
|
||||
|
||||
if (tty->char_available)
|
||||
{
|
||||
char c = tty->last_char;
|
||||
tty->char_available = false;
|
||||
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
}
|
||||
}*/
|
||||
|
||||
char tty_get_char(void)
|
||||
{
|
||||
tty_t* tty = get_active_tty();
|
||||
if (!tty)
|
||||
return 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
IRQ_DISABLE();
|
||||
spin_lock(&tty->lock);
|
||||
|
||||
if (tty->raw_head != tty->raw_tail)
|
||||
{
|
||||
char c = tty->raw_buf[tty->raw_tail];
|
||||
tty->raw_tail = (tty->raw_tail + 1) % TTY_RAW_BUFFER_SIZE;
|
||||
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t tty_read(tty_t* tty, char* buf, size_t count)
|
||||
{
|
||||
if (!tty || !buf)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t bytes = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
IRQ_DISABLE();
|
||||
spin_lock(&tty->lock);
|
||||
|
||||
if (!tty->line_ready)
|
||||
{
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
continue; /* spin until newline */
|
||||
}
|
||||
|
||||
while (bytes < count && tty->tail != tty->head)
|
||||
{
|
||||
char c = tty->input_buffer[tty->tail];
|
||||
tty->tail = (tty->tail + 1) % TTY_BUFFER_SIZE;
|
||||
|
||||
buf[bytes++] = c;
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
tty->line_ready = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
int input_buffer_put(tty_t* tty, char c)
|
||||
{
|
||||
IRQ_DISABLE();
|
||||
spin_lock(&tty->lock);
|
||||
|
||||
size_t next = next_index(tty->head);
|
||||
|
||||
if (next == tty->tail)
|
||||
{
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
return -1;
|
||||
}
|
||||
|
||||
tty->input_buffer[tty->head] = c;
|
||||
tty->head = next;
|
||||
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int init_tty(void)
|
||||
{
|
||||
if (num_ttys >= MAX_TTYS)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
tty_t* t = &ttys[0];
|
||||
|
||||
memset(t, 0, sizeof(tty_t));
|
||||
|
||||
t->flags = TTY_NORMAL;
|
||||
|
||||
active_tty = t;
|
||||
num_ttys = 1;
|
||||
|
||||
t->f_ops.read = tty_fread;
|
||||
t->line_ready = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
tty_t* get_active_tty(void)
|
||||
{
|
||||
return active_tty;
|
||||
}
|
||||
|
||||
tty_t* make_tty(uint32_t flags)
|
||||
{
|
||||
if (num_ttys >= MAX_TTYS)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tty_t* t = &ttys[num_ttys];
|
||||
|
||||
memset(t, 0, sizeof(tty_t));
|
||||
t->flags = flags;
|
||||
|
||||
num_ttys++;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void tty_receive_char(char c, uint32_t kbd_mod)
|
||||
{
|
||||
if (!active_tty || c == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
c = tty_translate_char(c, kbd_mod);
|
||||
|
||||
/* Handle backspace */
|
||||
if (c == '\b')
|
||||
{
|
||||
tty_backspace(active_tty);
|
||||
|
||||
if (active_tty->head == active_tty->tail)
|
||||
{
|
||||
extern void terminal_putcharat(char c, uint16_t row, uint16_t column);
|
||||
terminal_putcharat('Z', 20, 20);
|
||||
}
|
||||
|
||||
if (active_tty->flags & TTY_ECHO)
|
||||
{
|
||||
/* erase character visually */
|
||||
putc('\b');
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
input_buffer_put(active_tty, c);
|
||||
|
||||
if (active_tty->flags & TTY_ECHO)
|
||||
{
|
||||
if ((active_tty->flags & TTY_PASSWORD) == 0)
|
||||
{
|
||||
putc(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
putc('*');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*void tty_input_char(tty_t* tty, char c)
|
||||
{
|
||||
if (!tty || c == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IRQ_DISABLE();
|
||||
spin_lock(&tty->lock);
|
||||
|
||||
raw_put(tty, c);
|
||||
|
||||
if (c == '\b')
|
||||
{
|
||||
if (tty->head != tty->tail)
|
||||
{
|
||||
tty->head = (tty->head + TTY_BUFFER_SIZE - 1) % TTY_BUFFER_SIZE;
|
||||
|
||||
if (tty->flags & TTY_ECHO)
|
||||
{
|
||||
putc('\b');
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
return;
|
||||
}
|
||||
|
||||
size_t next = (tty->head + 1) % TTY_BUFFER_SIZE;
|
||||
|
||||
if (next != tty->tail)
|
||||
{
|
||||
tty->input_buffer[tty->head] = c;
|
||||
tty->head = next;
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
tty->line_ready = true;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
|
||||
if (tty->flags & TTY_ECHO)
|
||||
{
|
||||
putc(c);
|
||||
}
|
||||
}*/
|
||||
|
||||
void tty_input_char(tty_t* tty, char c)
|
||||
{
|
||||
if (!tty || c == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IRQ_DISABLE();
|
||||
spin_lock(&tty->lock);
|
||||
|
||||
/* RAW queue always gets input */
|
||||
raw_put(tty, c);
|
||||
|
||||
if (!(tty->flags & TTY_RAW))
|
||||
{
|
||||
/* canonical behavior */
|
||||
|
||||
if (c == '\b')
|
||||
{
|
||||
if (tty->head != tty->tail)
|
||||
{
|
||||
tty->head = (tty->head + TTY_BUFFER_SIZE - 1) % TTY_BUFFER_SIZE;
|
||||
|
||||
putc('\b');
|
||||
putc(' ');
|
||||
putc('\b');
|
||||
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t next = next_index(tty->head);
|
||||
|
||||
if (next != tty->tail)
|
||||
{
|
||||
tty->input_buffer[tty->head] = c;
|
||||
tty->head = next;
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
tty->line_ready = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&tty->lock);
|
||||
IRQ_ENABLE();
|
||||
|
||||
if (tty->flags & TTY_ECHO)
|
||||
{
|
||||
putc(c);
|
||||
}
|
||||
}
|
||||
|
||||
char tty_translate_char(char c, uint32_t modifiers)
|
||||
{
|
||||
bool caps = (modifiers & MODIFIER_CAPS) != 0;
|
||||
bool shift = (modifiers & MODIFIER_SHIFT) != 0;
|
||||
bool ctrl = (modifiers & (MODIFIER_LCTRL | MODIFIER_RCTRL)) != 0;
|
||||
|
||||
/* handle alphabetic characters */
|
||||
if (c >= 'a' && c <= 'z')
|
||||
{
|
||||
if (caps ^ shift) /* XOR logic */
|
||||
{
|
||||
return c - 32; /* to uppercase */
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
{
|
||||
if (caps ^ shift)
|
||||
{
|
||||
return c;
|
||||
}
|
||||
|
||||
return c + 32; /* to lowercase */
|
||||
}
|
||||
|
||||
/* handle ctrl (should later include control mapping/sending messages to processes via these) */
|
||||
if (ctrl)
|
||||
{
|
||||
if (c >= 'a' && c <= 'z')
|
||||
{
|
||||
return c - 'a' + 1; /* Ctrl+A → 1 */
|
||||
}
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
{
|
||||
return c - 'A' + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* shifted symbols (US layout) */
|
||||
if (shift)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '1':
|
||||
return '!';
|
||||
case '2':
|
||||
return '@';
|
||||
case '3':
|
||||
return '#';
|
||||
case '4':
|
||||
return '$';
|
||||
case '5':
|
||||
return '%';
|
||||
case '6':
|
||||
return '^';
|
||||
case '7':
|
||||
return '&';
|
||||
case '8':
|
||||
return '*';
|
||||
case '9':
|
||||
return '(';
|
||||
case '0':
|
||||
return ')';
|
||||
case '-':
|
||||
return '_';
|
||||
case '=':
|
||||
return '+';
|
||||
case '[':
|
||||
return '{';
|
||||
case ']':
|
||||
return '}';
|
||||
case ';':
|
||||
return ':';
|
||||
case '\'':
|
||||
return '"';
|
||||
case ',':
|
||||
return '<';
|
||||
case '.':
|
||||
return '>';
|
||||
case '/':
|
||||
return '?';
|
||||
case '\\':
|
||||
return '|';
|
||||
case '`':
|
||||
return '~';
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
133
drivers/pci.c
133
drivers/pci.c
@ -17,81 +17,104 @@
|
||||
|
||||
uint32_t pci_config_read(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset)
|
||||
{
|
||||
uint32_t address = 0;
|
||||
address |= (bus << 16); /* Bus number (bits 23-16) */
|
||||
address |= (device << 11); /* Device number (bits 15-11) */
|
||||
address |= (function << 8); /* Function number (bits 10-8) */
|
||||
address |= (offset & 0xFC); /* Register offset (bits 7-0) */
|
||||
address |= (1 << 31); /* Enable configuration access */
|
||||
uint32_t address = 0;
|
||||
address |= (bus << 16); /* Bus number (bits 23-16) */
|
||||
address |= (device << 11); /* Device number (bits 15-11) */
|
||||
address |= (function << 8); /* Function number (bits 10-8) */
|
||||
address |= (offset & 0xFC); /* Register offset (bits 7-0) */
|
||||
address |= (1 << 31); /* Enable configuration access */
|
||||
|
||||
outl(PCI_CONFIG_ADDRESS, address); /* Write address to PCI config space */
|
||||
return inl(PCI_CONFIG_DATA); /* Read data from PCI config space */
|
||||
outl(PCI_CONFIG_ADDRESS, address); /* Write address to PCI config space */
|
||||
return inl(PCI_CONFIG_DATA); /* Read data from PCI config space */
|
||||
}
|
||||
|
||||
void pci_config_write(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value)
|
||||
{
|
||||
uint32_t address = 0x80000000 | (bus << 16) | (device << 11) | (function << 8) | (offset & 0xFC);
|
||||
outl(PCI_CONFIG_ADDRESS, address); /* Send the address to PCI config space */
|
||||
outl(PCI_CONFIG_DATA, value); /* Write data to PCI config space */
|
||||
uint32_t address = 0x80000000 | (bus << 16) | (device << 11) | (function << 8) | (offset & 0xFC);
|
||||
outl(PCI_CONFIG_ADDRESS, address); /* Send the address to PCI config space */
|
||||
outl(PCI_CONFIG_DATA, value); /* Write data to PCI config space */
|
||||
}
|
||||
|
||||
void pci_config_read_block(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, void* buffer, size_t size)
|
||||
{
|
||||
uint8_t* buf = (uint8_t*)buffer;
|
||||
uint8_t* buf = (uint8_t*)buffer;
|
||||
|
||||
for (size_t i = 0; i < size; i += 4)
|
||||
{
|
||||
uint32_t value = pci_config_read(bus, device, function, offset + i);
|
||||
for (size_t i = 0; i < size; i += 4)
|
||||
{
|
||||
uint32_t value = pci_config_read(bus, device, function, offset + i);
|
||||
|
||||
size_t remaining = size - i;
|
||||
if (remaining >= 4)
|
||||
{
|
||||
*(uint32_t*)(buf + i) = value;
|
||||
size_t remaining = size - i;
|
||||
if (remaining >= 4)
|
||||
{
|
||||
*(uint32_t*)(buf + i) = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t j = 0; j < remaining; ++j)
|
||||
{
|
||||
buf[i + j] = (value >> (8 * j)) & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t j = 0; j < remaining; ++j)
|
||||
{
|
||||
buf[i + j] = (value >> (8 * j)) & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pci_init(void)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
printf("[ PCI ] Initializing PCI...\n");
|
||||
#endif
|
||||
|
||||
pci_enumerate();
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("[ PCI ] PCI initialized\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void pci_enumerate(void)
|
||||
{
|
||||
for (uint16_t bus = 0; bus < 256; bus++) /* Maximum 256 buses */
|
||||
{
|
||||
for (uint8_t device = 0; device < 32; device++) /* Maximum 32 devices per bus */
|
||||
for (uint16_t bus = 0; bus < 256; bus++) /* Maximum 256 buses */
|
||||
{
|
||||
for (uint8_t function = 0; function < 8; function++) /* Maximum 8 functions per device */
|
||||
{
|
||||
struct pci_header pre_header;
|
||||
pci_config_read_block(bus, device, function, 0x00, &pre_header, sizeof(pre_header));
|
||||
for (uint8_t device = 0; device < 32; device++) /* Maximum 32 devices per bus */
|
||||
{
|
||||
for (uint8_t function = 0; function < 8; function++) /* Maximum 8 functions per device */
|
||||
{
|
||||
struct pci_header pre_header;
|
||||
pci_config_read_block(bus, device, function, 0x00, &pre_header, sizeof(pre_header));
|
||||
|
||||
if (pre_header.vendor_id == 0xFFFF)
|
||||
{
|
||||
continue; /* No device present */
|
||||
}
|
||||
|
||||
if (pre_header.class_code == 0xB)
|
||||
{
|
||||
printf("Processor found on PCI bus, what?!?!\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pre_header.header_type == 0x00)
|
||||
{
|
||||
struct pci_header_type_0 hdr;
|
||||
pci_config_read_block(bus, device, function, 0x00, &hdr, sizeof(hdr));
|
||||
if (pre_header.vendor_id == 0xFFFF)
|
||||
{
|
||||
continue; /* No device present */
|
||||
}
|
||||
|
||||
if (hdr.class_code == 0x1 && hdr.subclass == 0x6 && hdr.prog_if == 0x1)
|
||||
{
|
||||
/*configure_ahci_controller(hdr);*/
|
||||
}
|
||||
if (pre_header.class_code == 0xB)
|
||||
{
|
||||
printf("Processor found on PCI bus, what?!?!\n"); /* For some stupid reason, processors can be on the PCI bus? */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pre_header.header_type == 0x00)
|
||||
{
|
||||
struct pci_header_type_0 hdr;
|
||||
pci_config_read_block(bus, device, function, 0x00, &hdr, sizeof(hdr));
|
||||
|
||||
if (hdr.class_code == 0x1 && hdr.subclass == 0x6 && hdr.prog_if == 0x1)
|
||||
{
|
||||
/*configure_ahci_controller(hdr);*/
|
||||
}
|
||||
|
||||
if (hdr.class_code == 0x03)
|
||||
{
|
||||
uint32_t bar0 = hdr.bar0;
|
||||
extern void init_bga_framebuffer(uint32_t* _p);
|
||||
init_bga_framebuffer((uint32_t*) bar0);
|
||||
printf("Found framebffer addr 0x%x on device %x \n", bar0, hdr.device_id);
|
||||
}
|
||||
|
||||
|
||||
/*printf("PCI device: cc: %x sc: %x pi: %x b: %x d: %x f: %x int: %x\n", hdr.class_code, hdr.subclass, hdr.prog_if, bus, device, function, (uint32_t) hdr.interrupt_line);*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
#include <port_io.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <scheduler.h>
|
||||
|
||||
#include <drivers/pit.h>
|
||||
|
||||
|
||||
@ -15,7 +17,13 @@ bool pit_initialized = false;
|
||||
|
||||
void pit_init(void)
|
||||
{
|
||||
uint16_t divisor = (uint16_t)1193;
|
||||
printf("pit_initialized addr = %x\n", &pit_initialized);
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("[ PIT ] Initializing the PIT...\n");
|
||||
#endif
|
||||
|
||||
uint16_t divisor = (uint16_t) 1193;
|
||||
|
||||
/* Send command byte */
|
||||
outb(PIT_COMMAND, 0x36); /* Channel 0, low/high byte, mode 3 (square wave), binary */
|
||||
@ -25,11 +33,16 @@ void pit_init(void)
|
||||
outb(PIT_CHANNEL0, (uint8_t)((divisor >> 8) & 0xFF)); /* High byte */
|
||||
|
||||
pit_initialized = true;
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("[ PIT ] PIT Initialized\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void pit_handler(void)
|
||||
registers_t* pit_handler(registers_t* regs)
|
||||
{
|
||||
pit_ticks++;
|
||||
return regs;
|
||||
}
|
||||
|
||||
void pit_sleep(uint64_t ms)
|
||||
@ -41,3 +54,13 @@ void pit_sleep(uint64_t ms)
|
||||
}
|
||||
}
|
||||
|
||||
/*void pit_sleep(uint64_t ms)
|
||||
{
|
||||
extern task_t* current_task;
|
||||
|
||||
current_task->wakeup_tick = pit_ticks + ms;
|
||||
current_task->state = TASK_SLEEPING;
|
||||
|
||||
asm volatile("int $32");*/ /* force reschedule immediately */
|
||||
/*}
|
||||
*/
|
||||
|
||||
@ -2,7 +2,9 @@
|
||||
#include <port_io.h>
|
||||
#include <tty.h>
|
||||
#include <stdlib.h>
|
||||
#include <ksymtab.h>
|
||||
|
||||
#include <new_tty.h>
|
||||
|
||||
|
||||
#include <drivers/ps2_keyboard.h>
|
||||
|
||||
@ -29,6 +31,16 @@
|
||||
|
||||
#define KEYBOARD_IRQ 1
|
||||
|
||||
#define RETURN_STI() do { _sti_asm(); return; } while (0)
|
||||
|
||||
|
||||
#define GETS_BUFFER_SIZE 256
|
||||
|
||||
static char gets_buffer[GETS_BUFFER_SIZE];
|
||||
volatile char* gets_string = gets_buffer;
|
||||
volatile int32_t gets_capacity = GETS_BUFFER_SIZE;
|
||||
volatile int32_t gets_length = 0;
|
||||
|
||||
bool ps2keyboard_initialized = false;
|
||||
|
||||
/* State for shift key */
|
||||
@ -41,14 +53,24 @@ static bool capslock_pressed = false;
|
||||
static bool extended = false;
|
||||
|
||||
static bool is_new_char = false;
|
||||
static bool is_new_key = false;
|
||||
static bool is_new_key = false;
|
||||
|
||||
static bool gets_called = false;
|
||||
static volatile bool gets_finished = false;
|
||||
|
||||
volatile unsigned char current_char;
|
||||
volatile char* current_string = NULL;
|
||||
volatile char* current_string = NULL;
|
||||
volatile int32_t current_length = 0;
|
||||
volatile int32_t capacity = 0;
|
||||
volatile int32_t capacity = 0;
|
||||
volatile uint16_t current_key;
|
||||
|
||||
volatile bool use_new_tty = false;
|
||||
|
||||
volatile ps2_hook_t* hooks = NULL;
|
||||
volatile int hook_count = 0;
|
||||
|
||||
extern void _cli_asm(void);
|
||||
extern void _sti_asm(void);
|
||||
|
||||
static const char scancode_map[128] = {
|
||||
0, 27, '1','2','3','4','5','6','7','8','9','0','-','=','\b', /* Backspace */
|
||||
@ -66,18 +88,144 @@ static const char scancode_map[128] = {
|
||||
/* The rest are function and control keys */
|
||||
};
|
||||
|
||||
void set_use_new_tty(bool t)
|
||||
{
|
||||
use_new_tty = t;
|
||||
}
|
||||
|
||||
void keyboard_init(void)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
printf("[ PS/2 KBD ] Initializing the PS/2 keyboard...\n");
|
||||
#endif
|
||||
|
||||
outb(0x64, 0xAE); /* Enable keyboard interface (often optional, but here for safety) */
|
||||
|
||||
hooks = NULL;
|
||||
|
||||
set_use_new_tty(true);
|
||||
|
||||
ps2keyboard_initialized = true;
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("[ PS/2 KBD ] PS/2 Keyboard initialized\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
bool setup_hook(ps2_hook_t func)
|
||||
{
|
||||
_cli_asm();
|
||||
|
||||
ps2_hook_t* copy = malloc(sizeof(ps2_hook_t) * hook_count);
|
||||
|
||||
if (hook_count > 0 && copy == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hook_count > 0)
|
||||
{
|
||||
memcpy(copy, hooks, sizeof(ps2_hook_t) * hook_count);
|
||||
}
|
||||
|
||||
free((void*) hooks);
|
||||
|
||||
hooks = malloc(sizeof(ps2_hook_t) * (hook_count + 1));
|
||||
|
||||
if (hooks == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hook_count > 0)
|
||||
{
|
||||
memcpy((void*) hooks, copy, sizeof(ps2_hook_t) * hook_count);
|
||||
}
|
||||
|
||||
free(copy);
|
||||
|
||||
hooks[hook_count] = func;
|
||||
hook_count++;
|
||||
|
||||
_sti_asm();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool remove_hook(ps2_hook_t func)
|
||||
{
|
||||
_cli_asm();
|
||||
|
||||
int index = -1;
|
||||
|
||||
for (int i = 0; i < hook_count; i++)
|
||||
{
|
||||
if (hooks[i] == func)
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = index; i < hook_count - 1; i++)
|
||||
{
|
||||
hooks[i] = hooks[i + 1];
|
||||
}
|
||||
|
||||
hook_count--;
|
||||
|
||||
if (hook_count == 0)
|
||||
{
|
||||
free((void*) hooks);
|
||||
hooks = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
ps2_hook_t* smaller = malloc(sizeof(ps2_hook_t) * hook_count);
|
||||
|
||||
if (smaller == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(smaller, (void*) hooks, sizeof(ps2_hook_t) * hook_count);
|
||||
free((void*) hooks);
|
||||
hooks = smaller;
|
||||
|
||||
_sti_asm();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void call_hooks(char c)
|
||||
{
|
||||
_cli_asm();
|
||||
|
||||
if (hook_count == 0)
|
||||
{
|
||||
_sti_asm();
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < hook_count; i++)
|
||||
{
|
||||
hooks[i](c);
|
||||
}
|
||||
|
||||
_sti_asm();
|
||||
}
|
||||
|
||||
char get_char(void)
|
||||
{
|
||||
/*
|
||||
ASCII code 5 (Enquiry) is/was used in legacy systems meant for requesting a response from a remote terminal or device.
|
||||
For example, one system might send ENQ (ASCII 5), and the receiver could reply with ACK (ASCII 6) to indicate it’s ready or still online.
|
||||
For example, one system might send ENQ (ASCII 5), and the receiver could reply with ACK (ASCII 6) to indicate it's ready or still online.
|
||||
|
||||
In modern computing, ENQ is largely obsolete:
|
||||
|
||||
@ -87,16 +235,13 @@ char get_char(void)
|
||||
|
||||
- It may still appear in legacy systems, embedded devices, or proprietary serial protocols, but that's niche.
|
||||
*/
|
||||
char temp = 5;
|
||||
|
||||
if (is_new_char)
|
||||
if (!is_new_char)
|
||||
{
|
||||
temp = current_char;
|
||||
return 5;
|
||||
}
|
||||
|
||||
|
||||
is_new_char = false;
|
||||
|
||||
return temp;
|
||||
return current_char;
|
||||
}
|
||||
|
||||
uint16_t get_key(void)
|
||||
@ -122,39 +267,136 @@ char* get_string(void)
|
||||
return current_string;
|
||||
}
|
||||
|
||||
static void append_char(char c)
|
||||
static inline void print_(void)
|
||||
{
|
||||
static char ch = 'a';
|
||||
|
||||
int r = 0, c = 0;
|
||||
|
||||
terminal_get_cursor(&r, &c);
|
||||
terminal_set_cursor((uint16_t) 30, (uint16_t) 0);
|
||||
printf("%c", ch);
|
||||
terminal_set_cursor((uint16_t) r, (uint16_t) c);
|
||||
|
||||
ch++;
|
||||
}
|
||||
|
||||
char* kbd_gets(void)
|
||||
{
|
||||
gets_called = true;
|
||||
gets_finished = false;
|
||||
gets_length = 0;
|
||||
gets_string[0] = '\0';
|
||||
|
||||
while (!gets_finished)
|
||||
{
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
_cli_asm();
|
||||
|
||||
char* result = strdup((char*) gets_string);
|
||||
|
||||
gets_length = 0;
|
||||
gets_string[0] = '\0';
|
||||
gets_called = false;
|
||||
|
||||
_sti_asm();
|
||||
|
||||
return result ? result : "";
|
||||
}
|
||||
|
||||
void gets_append_char(unsigned char c)
|
||||
{
|
||||
if (!gets_called)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (c == KEY_ARROW_UP || c == KEY_ARROW_DOWN || c == KEY_ARROW_RIGHT || c == KEY_ARROW_LEFT)
|
||||
{
|
||||
if (GETS_BUFFER_SIZE >= 2)
|
||||
{
|
||||
gets_string[0] = (char)c;
|
||||
gets_string[1] = '\0';
|
||||
}
|
||||
|
||||
gets_finished = true;
|
||||
return;
|
||||
}
|
||||
else if (c == '\n')
|
||||
{
|
||||
gets_finished = true;
|
||||
printf("\n");
|
||||
return;
|
||||
}
|
||||
else if (c == 27)
|
||||
{
|
||||
gets_string[0] = '\0';
|
||||
gets_finished = true;
|
||||
return;
|
||||
}
|
||||
else if (c == '\b')
|
||||
{
|
||||
if (gets_length > 0)
|
||||
{
|
||||
gets_length--;
|
||||
gets_string[gets_length] = '\0';
|
||||
printf("\b \b");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (gets_length < GETS_BUFFER_SIZE - 1)
|
||||
{
|
||||
gets_string[gets_length++] = (char)c;
|
||||
gets_string[gets_length] = '\0';
|
||||
printf("%c", c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void append_char(char c)
|
||||
{
|
||||
_cli_asm();
|
||||
|
||||
if (current_length + 1 >= capacity)
|
||||
{
|
||||
/* Need more space (+1 for the null zero) */
|
||||
int new_capacity = (capacity == 0) ? 16 : capacity * 2;
|
||||
|
||||
char* new_str = (char*)malloc(new_capacity);
|
||||
if (!new_str) {
|
||||
char* new_str = (char*) malloc(new_capacity);
|
||||
|
||||
if (!new_str)
|
||||
{
|
||||
printf("[keyboard] ERROR: malloc failed for new input buffer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (current_string)
|
||||
{
|
||||
memcpy(new_str, current_string, current_length);
|
||||
free(current_string);
|
||||
}
|
||||
|
||||
if (!current_string)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
current_string = new_str;
|
||||
capacity = new_capacity;
|
||||
}
|
||||
|
||||
if (!current_string)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
current_string[current_length] = c;
|
||||
current_length++;
|
||||
current_string[current_length] = '\0'; /* Maintain null terminator */
|
||||
current_string[current_length] = '\0';
|
||||
|
||||
_sti_asm();
|
||||
}
|
||||
|
||||
static void free_current_string(void)
|
||||
|
||||
void free_current_string(void)
|
||||
{
|
||||
if (current_string)
|
||||
{
|
||||
@ -165,32 +407,45 @@ static void free_current_string(void)
|
||||
}
|
||||
}
|
||||
|
||||
void keyboard_handler(void)
|
||||
|
||||
registers_t* ps2_keyboard_handler(registers_t* regs)
|
||||
{
|
||||
#if 0
|
||||
uint8_t scancode = inb(PS2_DATA_PORT);
|
||||
|
||||
/* Handle shift press/release */
|
||||
if (scancode == 0x2A || scancode == 0x36)
|
||||
{
|
||||
shift_pressed = true;
|
||||
return;
|
||||
return regs;
|
||||
}
|
||||
else if (scancode == 0xAA || scancode == 0xB6)
|
||||
{
|
||||
shift_pressed = false;
|
||||
return;
|
||||
return regs;
|
||||
}
|
||||
else if (scancode == 0x3A)
|
||||
{
|
||||
capslock_pressed = !capslock_pressed;
|
||||
return;
|
||||
return regs;
|
||||
}
|
||||
else if (scancode == 0xE0)
|
||||
{
|
||||
extended = true;
|
||||
return;
|
||||
return regs;
|
||||
}
|
||||
|
||||
uint32_t flags = 0;
|
||||
|
||||
if (capslock_pressed)
|
||||
{
|
||||
flags |= MODIFIER_CAPS;
|
||||
}
|
||||
|
||||
if (shift_pressed)
|
||||
{
|
||||
flags |= MODIFIER_SHIFT;
|
||||
}
|
||||
|
||||
if (scancode & 0x80)
|
||||
{
|
||||
@ -198,64 +453,95 @@ void keyboard_handler(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t c = (uint16_t)scancode_map[scancode];
|
||||
if ((shift_pressed ^ capslock_pressed) && ((char)c >= 'a') && ((char)c <= 'z'))
|
||||
uint16_t c = (uint16_t) scancode_map[scancode];
|
||||
|
||||
if (!use_new_tty)
|
||||
{
|
||||
c -= 32; /* Convert to uppercase */
|
||||
if ((shift_pressed ^ capslock_pressed) && ((char) c >= 'a') && ((char) c <= 'z'))
|
||||
{
|
||||
c -= 32; /* Convert to uppercase */
|
||||
}
|
||||
else if (shift_pressed)
|
||||
{
|
||||
c = (uint16_t) terminal_get_shifted((unsigned char) c);
|
||||
}
|
||||
|
||||
if (extended)
|
||||
{
|
||||
switch (scancode)
|
||||
{
|
||||
case 0x48:
|
||||
c = KEY_ARROW_UP;
|
||||
break;
|
||||
case 0x50:
|
||||
c = KEY_ARROW_DOWN;
|
||||
break;
|
||||
case 0x4B:
|
||||
c = KEY_ARROW_LEFT;
|
||||
break;
|
||||
case 0x4D:
|
||||
c = KEY_ARROW_RIGHT;
|
||||
break;
|
||||
default:
|
||||
c = KEY_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (gets_called)
|
||||
{
|
||||
gets_append_char(c);
|
||||
|
||||
return regs;
|
||||
}
|
||||
|
||||
current_key = c;
|
||||
|
||||
is_new_key = true;
|
||||
extended = false;
|
||||
|
||||
return regs;
|
||||
}
|
||||
|
||||
if (gets_called)
|
||||
{
|
||||
gets_append_char(c);
|
||||
|
||||
return regs;
|
||||
}
|
||||
|
||||
if (c)
|
||||
{
|
||||
if (c != '\n')
|
||||
{
|
||||
append_char(c);
|
||||
}
|
||||
|
||||
current_char = c;
|
||||
is_new_char = true;
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
/*append_char(c);
|
||||
current_char = c;
|
||||
is_new_char = true;*/
|
||||
|
||||
free_current_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (shift_pressed)
|
||||
else
|
||||
{
|
||||
c = (uint16_t) terminal_get_shifted((unsigned char) c);
|
||||
tty_receive_char(c, flags);
|
||||
}
|
||||
|
||||
/*if (scancode == 0x1C) {
|
||||
printf("\n");
|
||||
return;
|
||||
}*/
|
||||
|
||||
|
||||
if (extended)
|
||||
if (hook_count > 0)
|
||||
{
|
||||
switch (scancode)
|
||||
{
|
||||
case 0x48:
|
||||
c = KEY_ARROW_UP;
|
||||
break;
|
||||
case 0x50:
|
||||
c = KEY_ARROW_DOWN;
|
||||
break;
|
||||
case 0x4B:
|
||||
c = KEY_ARROW_LEFT;
|
||||
break;
|
||||
case 0x4D:
|
||||
c = KEY_ARROW_RIGHT;
|
||||
break;
|
||||
default:
|
||||
c = KEY_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
current_key = c;
|
||||
|
||||
is_new_key = true;
|
||||
extended = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (c)
|
||||
{
|
||||
current_char = c;
|
||||
|
||||
is_new_char = true;
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
free_current_string();
|
||||
}
|
||||
|
||||
append_char(c);
|
||||
call_hooks(c);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return regs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
88
drivers/serio.c
Normal file
88
drivers/serio.c
Normal file
@ -0,0 +1,88 @@
|
||||
|
||||
/*
|
||||
Driver for serial output.
|
||||
Mostly useful for debug output because QEMU allows the redirection of serial output to either stdio or a file on the host computer.
|
||||
*/
|
||||
|
||||
#include <types.h>
|
||||
#include <port_io.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <drivers/serio.h>
|
||||
|
||||
|
||||
#define COM1_IO_ADDR 0x3F8
|
||||
#define COM2_IO_ADDR 0x2F8
|
||||
|
||||
#define COM1_IRQ 0x4
|
||||
#define COM2_IRQ 0x3
|
||||
|
||||
#define COM1_LCR (COM1_IO_ADDR + 3)
|
||||
#define COM2_LCR (COM2_IO_ADDR + 3)
|
||||
|
||||
#define BAUD 57600
|
||||
#define DIVISOR 2
|
||||
|
||||
|
||||
int serial_init(void)
|
||||
{
|
||||
/* The following is taken from https://wiki.osdev.org/Serial_Ports */
|
||||
|
||||
outb(COM1_IO_ADDR + 1, 0x00); // Disable all interrupts
|
||||
outb(COM1_IO_ADDR + 3, 0x80); // Enable DLAB (set baud rate divisor)
|
||||
outb(COM1_IO_ADDR + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud
|
||||
outb(COM1_IO_ADDR + 1, 0x00); // (hi byte)
|
||||
outb(COM1_IO_ADDR + 3, 0x03); // 8 bits, no parity, one stop bit
|
||||
outb(COM1_IO_ADDR + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
|
||||
outb(COM1_IO_ADDR + 4, 0x0B); // IRQs enabled, RTS/DSR set
|
||||
outb(COM1_IO_ADDR + 4, 0x1E); // Set in loopback mode, test the serial chip
|
||||
outb(COM1_IO_ADDR + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte)
|
||||
|
||||
// Check if serial is faulty (i.e: not same byte as sent)
|
||||
if(inb(COM1_IO_ADDR + 0) != 0xAE)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// If serial is not faulty set it in normal operation mode
|
||||
// (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled)
|
||||
outb(COM1_IO_ADDR + 4, 0x0F);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_transmit_empty(void)
|
||||
{
|
||||
return inb(COM1_IO_ADDR + 5) & 0x20;
|
||||
}
|
||||
|
||||
static int serial_received(void)
|
||||
{
|
||||
return inb(COM1_IO_ADDR + 5) & 1;
|
||||
}
|
||||
|
||||
void serial_write(char a)
|
||||
{
|
||||
while (is_transmit_empty() == 0);
|
||||
|
||||
outb(COM1_IO_ADDR, a);
|
||||
}
|
||||
|
||||
void serial_puts(const char* s)
|
||||
{
|
||||
for (int i = 0; i < (int) strlen(s); i++)
|
||||
{
|
||||
serial_write(s[i]);
|
||||
}
|
||||
}
|
||||
|
||||
char serial_read(void)
|
||||
{
|
||||
while (serial_received() == 0);
|
||||
|
||||
return inb(COM1_IO_ADDR);
|
||||
}
|
||||
|
||||
bool use_serial(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
194
drivers/tty.c
194
drivers/tty.c
@ -1,16 +1,42 @@
|
||||
#include <string.h>
|
||||
#include <vga/vga.h>
|
||||
#include <stdio.h>
|
||||
#include <port_io.h>
|
||||
#include <new_tty.h>
|
||||
#include <fs/vfs.h>
|
||||
|
||||
#include <tty.h>
|
||||
|
||||
static size_t terminal_row;
|
||||
static size_t terminal_column;
|
||||
static uint8_t terminal_color;
|
||||
static uint16_t* terminal_buffer;
|
||||
size_t terminal_row;
|
||||
size_t terminal_column;
|
||||
uint8_t terminal_color;
|
||||
uint16_t* terminal_buffer;
|
||||
|
||||
|
||||
void terminal_initialize(void)
|
||||
{
|
||||
terminal_initializec(0x00);
|
||||
|
||||
terminal_update_cursor();
|
||||
}
|
||||
|
||||
ssize_t tty_write(struct file* f, const char* buf, size_t size)
|
||||
{
|
||||
/*struct tty* tty = (struct tty*)f->private_data;*/
|
||||
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
/*tty_putchar(tty, buf[i]);*/ /* do this when we have multiple TTY outputs & stuff */
|
||||
terminal_putchar(buf[i]);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void terminal_get_cursor(int* row, int* column)
|
||||
{
|
||||
*row = (int) terminal_row;
|
||||
*column = (int) terminal_column;
|
||||
}
|
||||
|
||||
void terminal_initializec(uint8_t color)
|
||||
@ -22,11 +48,13 @@ void terminal_initializec(uint8_t color)
|
||||
{
|
||||
terminal_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
terminal_color = color;
|
||||
}
|
||||
|
||||
terminal_buffer = VGA_MEMORY;
|
||||
|
||||
for (size_t y = 0; y < VGA_HEIGHT; y++)
|
||||
{
|
||||
for (size_t x = 0; x < VGA_WIDTH; x++)
|
||||
@ -55,6 +83,7 @@ void terminal_putentryat(unsigned char c, uint8_t color, size_t x, size_t y)
|
||||
|
||||
void terminal_putchar(const char c)
|
||||
{
|
||||
|
||||
unsigned char uc = c;
|
||||
|
||||
if (uc == '\n')
|
||||
@ -62,9 +91,21 @@ void terminal_putchar(const char c)
|
||||
terminal_column = 0;
|
||||
if (++terminal_row == VGA_HEIGHT)
|
||||
{
|
||||
terminal_scroll();
|
||||
terminal_row = VGA_HEIGHT - 1;
|
||||
if (1)
|
||||
{
|
||||
terminal_scroll();
|
||||
terminal_row = VGA_HEIGHT - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
terminal_clear();
|
||||
terminal_row = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
terminal_update_cursor();
|
||||
|
||||
return;
|
||||
}
|
||||
else if (uc == '\t')
|
||||
@ -76,28 +117,60 @@ void terminal_putchar(const char c)
|
||||
terminal_putchar('\n');
|
||||
}
|
||||
|
||||
terminal_update_cursor();
|
||||
|
||||
return;
|
||||
}
|
||||
/*else if (uc == '\b')
|
||||
{
|
||||
if (terminal_column == 0)
|
||||
{
|
||||
if (terminal_row > 0)
|
||||
{
|
||||
terminal_row--;
|
||||
terminal_column = VGA_WIDTH - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
terminal_update_cursor();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
terminal_column--;
|
||||
}
|
||||
|
||||
terminal_putentryat(' ', terminal_color, terminal_column, terminal_row);
|
||||
|
||||
terminal_update_cursor();
|
||||
|
||||
return;
|
||||
}*/
|
||||
else if (uc == '\b')
|
||||
{
|
||||
if (terminal_column == 0)
|
||||
{
|
||||
terminal_row -= 1;
|
||||
|
||||
if (terminal_row == (size_t)-1)
|
||||
if (terminal_row > 0)
|
||||
{
|
||||
terminal_row = 0;
|
||||
terminal_row--;
|
||||
terminal_column = VGA_WIDTH - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
terminal_update_cursor();
|
||||
|
||||
terminal_column = VGA_WIDTH;
|
||||
|
||||
terminal_putentryat(' ', terminal_getcolor(), (size_t)terminal_column, (size_t)terminal_row);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
terminal_putentryat(' ', terminal_getcolor(), (size_t)--terminal_column, (size_t)terminal_row);
|
||||
terminal_column--;
|
||||
}
|
||||
|
||||
terminal_update_cursor();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -110,9 +183,10 @@ void terminal_putchar(const char c)
|
||||
if (++terminal_row == VGA_HEIGHT)
|
||||
{
|
||||
terminal_scroll();
|
||||
terminal_row = VGA_HEIGHT - 1;
|
||||
}
|
||||
}
|
||||
|
||||
terminal_update_cursor();
|
||||
}
|
||||
|
||||
void terminal_write(const char* data, size_t size)
|
||||
@ -142,12 +216,15 @@ void terminal_writeline(const char* data)
|
||||
|
||||
void terminal_writechar_r(const char ch)
|
||||
{
|
||||
unsigned char uch = ch;
|
||||
size_t saved_row = terminal_row;
|
||||
size_t saved_col = terminal_column;
|
||||
|
||||
for (size_t i = 0; i < VGA_WIDTH; i++)
|
||||
{
|
||||
terminal_putchar(uch);
|
||||
terminal_putentryat(ch, terminal_color, i, saved_row);
|
||||
}
|
||||
|
||||
terminal_set_cursor(saved_row, saved_col);
|
||||
}
|
||||
|
||||
void terminal_clear(void)
|
||||
@ -163,42 +240,43 @@ void terminal_clearl(size_t num_lines)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* XXX note to self: VGA_HEIGHT is 25, and VGA_WIDTH is 80 XXX */
|
||||
/* static size_t terminal_row; static size_t terminal_column; */
|
||||
|
||||
terminal_row = VGA_HEIGHT;
|
||||
terminal_column = 0;
|
||||
|
||||
while (terminal_row < num_lines)
|
||||
if (num_lines > VGA_HEIGHT)
|
||||
{
|
||||
for (int32_t k = 0; k < (int32_t)VGA_WIDTH; k++)
|
||||
{
|
||||
terminal_putentryat((unsigned char)' ', terminal_getcolor(), (size_t)terminal_row, (size_t)k);
|
||||
}
|
||||
terminal_row -= 1;
|
||||
num_lines = VGA_HEIGHT;
|
||||
}
|
||||
|
||||
size_t start = VGA_HEIGHT - num_lines;
|
||||
for (size_t y = start; y < VGA_HEIGHT; y++)
|
||||
{
|
||||
for (size_t x = 0; x < VGA_WIDTH; x++)
|
||||
{
|
||||
terminal_putentryat(' ', terminal_getcolor(), x, y);
|
||||
}
|
||||
}
|
||||
|
||||
terminal_set_cursor(start, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void terminal_scroll(void)
|
||||
{
|
||||
for (size_t y = 1; y < VGA_HEIGHT; y++)
|
||||
memmove(
|
||||
terminal_buffer,
|
||||
terminal_buffer + VGA_WIDTH,
|
||||
sizeof(uint16_t) * VGA_WIDTH * (VGA_HEIGHT - 1)
|
||||
);
|
||||
|
||||
terminal_row = VGA_HEIGHT - 1;
|
||||
for (int32_t x = 0; x < (int32_t)VGA_WIDTH; x++)
|
||||
{
|
||||
for (size_t x = 0; x < VGA_WIDTH; x++)
|
||||
{
|
||||
const size_t src_index = y * VGA_WIDTH + x;
|
||||
const size_t dst_index = (y - 1) * VGA_WIDTH + x;
|
||||
terminal_buffer[dst_index] = terminal_buffer[src_index];
|
||||
}
|
||||
terminal_putentryat(' ', terminal_getcolor(), (size_t)x, (size_t)terminal_row);
|
||||
}
|
||||
|
||||
for (size_t x = 0; x < VGA_WIDTH; x++)
|
||||
{
|
||||
const size_t index = (VGA_HEIGHT - 1) * VGA_WIDTH + x;
|
||||
terminal_buffer[index] = (terminal_color << 8) | ' ';
|
||||
}
|
||||
terminal_column = 0;
|
||||
terminal_update_cursor();
|
||||
}
|
||||
|
||||
|
||||
unsigned char terminal_get_shifted(unsigned char uc)
|
||||
{
|
||||
unsigned char lowerc[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '\0' };
|
||||
@ -208,7 +286,7 @@ unsigned char terminal_get_shifted(unsigned char uc)
|
||||
unsigned char syms1[] = { ',', '.', '/', ';', '\'', '[', ']', '`', '-', '=', '\\', '\0' };
|
||||
unsigned char syms2[] = { '<', '>', '?', ':', '\"', '{', '}', '~', '_', '+', '|', '\0' };
|
||||
|
||||
for (int32_t i = 0; i < (int32_t)(strlen((char*)lowerc)); ++i)
|
||||
for (int32_t i = 0; i < (int32_t) (strlen((char*)lowerc)); ++i)
|
||||
{
|
||||
if (uc == lowerc[i])
|
||||
{
|
||||
@ -220,7 +298,7 @@ unsigned char terminal_get_shifted(unsigned char uc)
|
||||
}
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < (int32_t)(strlen((char*)nums)); ++i)
|
||||
for (int32_t i = 0; i < (int32_t) (strlen((char*)nums)); ++i)
|
||||
{
|
||||
if (uc == nums[i])
|
||||
{
|
||||
@ -232,7 +310,7 @@ unsigned char terminal_get_shifted(unsigned char uc)
|
||||
}
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < (int32_t)(strlen((char*)syms1)); ++i)
|
||||
for (int32_t i = 0; i < (int32_t) (strlen((char*) syms1)); ++i)
|
||||
{
|
||||
if (uc == syms1[i])
|
||||
{
|
||||
@ -251,7 +329,29 @@ void terminal_set_cursor(uint16_t row, uint16_t column)
|
||||
{
|
||||
if (row < VGA_HEIGHT && column < VGA_WIDTH)
|
||||
{
|
||||
terminal_row = (size_t)row;
|
||||
terminal_column = (size_t)column;
|
||||
terminal_row = (size_t) row;
|
||||
terminal_column = (size_t) column;
|
||||
}
|
||||
|
||||
terminal_update_cursor();
|
||||
}
|
||||
|
||||
void terminal_update_cursor(void)
|
||||
{
|
||||
uint16_t pos = terminal_row * VGA_WIDTH + terminal_column;
|
||||
|
||||
outb(0x3D4, 0x0F);
|
||||
outb(0x3D5, (uint8_t) (pos & 0xFF));
|
||||
outb(0x3D4, 0x0E);
|
||||
outb(0x3D5, (uint8_t) ((pos >> 8) & 0xFF));
|
||||
}
|
||||
|
||||
void terminal_putcharat(char c, uint16_t row, uint16_t column)
|
||||
{
|
||||
int _r;
|
||||
int _c;
|
||||
terminal_get_cursor(&_r, &_c);
|
||||
terminal_set_cursor(row, column);
|
||||
terminal_putchar(c);
|
||||
terminal_set_cursor((uint16_t) _r, (uint16_t) _c);
|
||||
}
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
#include <stddef.h>
|
||||
#include <vga/vga.h>
|
||||
|
||||
uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg) {
|
||||
return fg | bg << 4;
|
||||
uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg)
|
||||
{
|
||||
return fg | bg << 4;
|
||||
}
|
||||
|
||||
uint16_t vga_entry(unsigned char uc, uint8_t color) {
|
||||
return (uint16_t) uc | (uint16_t) color << 8;
|
||||
uint16_t vga_entry(unsigned char uc, uint8_t color)
|
||||
{
|
||||
return (uint16_t) uc | (uint16_t) color << 8;
|
||||
}
|
||||
|
||||
BIN
espresso.img
Normal file
BIN
espresso.img
Normal file
Binary file not shown.
5
grub.cfg
5
grub.cfg
@ -1,4 +1,9 @@
|
||||
|
||||
set gfxmode=1024x768x32
|
||||
set gfxpayload=keep
|
||||
terminal_output gfxterm
|
||||
|
||||
menuentry "Espresso" {
|
||||
multiboot /boot/espresso.elf
|
||||
boot
|
||||
}
|
||||
|
||||
15
include/arch/x86/intrin.h
Normal file
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
|
||||
16
include/ctype.h
Normal file
16
include/ctype.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef _CHAR_TYPE_H
|
||||
#define _CHAR_TYPE_H
|
||||
|
||||
#include <types.h>
|
||||
|
||||
int32_t ischar(int32_t c);
|
||||
int32_t isspace(char c);
|
||||
int32_t isalpha(char c);
|
||||
int isprint(int c);
|
||||
char upper(char c);
|
||||
char toupper(char c);
|
||||
char lower(char c);
|
||||
char toupper(char c);
|
||||
char lower(char c);
|
||||
|
||||
#endif
|
||||
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,37 +9,40 @@
|
||||
#define PT_LOAD 1
|
||||
|
||||
typedef struct {
|
||||
unsigned char e_ident[EI_NIDENT];
|
||||
uint16_t e_type;
|
||||
uint16_t e_machine;
|
||||
uint32_t e_version;
|
||||
uint32_t e_entry;
|
||||
uint32_t e_phoff;
|
||||
uint32_t e_shoff;
|
||||
uint32_t e_flags;
|
||||
uint16_t e_ehsize;
|
||||
uint16_t e_phentsize;
|
||||
uint16_t e_phnum;
|
||||
uint16_t e_shentsize;
|
||||
uint16_t e_shnum;
|
||||
uint16_t e_shstrndx;
|
||||
unsigned char e_ident[EI_NIDENT];
|
||||
uint16_t e_type;
|
||||
uint16_t e_machine;
|
||||
uint32_t e_version;
|
||||
uint32_t e_entry;
|
||||
uint32_t e_phoff;
|
||||
uint32_t e_shoff;
|
||||
uint32_t e_flags;
|
||||
uint16_t e_ehsize;
|
||||
uint16_t e_phentsize;
|
||||
uint16_t e_phnum;
|
||||
uint16_t e_shentsize;
|
||||
uint16_t e_shnum;
|
||||
uint16_t e_shstrndx;
|
||||
} Elf32_Ehdr;
|
||||
|
||||
typedef struct {
|
||||
uint32_t p_type;
|
||||
uint32_t p_offset;
|
||||
uint32_t p_vaddr;
|
||||
uint32_t p_paddr;
|
||||
uint32_t p_filesz;
|
||||
uint32_t p_memsz;
|
||||
uint32_t p_flags;
|
||||
uint32_t p_align;
|
||||
uint32_t p_type;
|
||||
uint32_t p_offset;
|
||||
uint32_t p_vaddr;
|
||||
uint32_t p_paddr;
|
||||
uint32_t p_filesz;
|
||||
uint32_t p_memsz;
|
||||
uint32_t p_flags;
|
||||
uint32_t p_align;
|
||||
} Elf32_Phdr;
|
||||
|
||||
//typedef int (*elf_entry_t)(int, char**);
|
||||
typedef int (*elf_entry_t)(void);
|
||||
|
||||
typedef struct {
|
||||
void* entry_point;
|
||||
elf_entry_t entry_point;
|
||||
} elf_executable_t;
|
||||
|
||||
elf_executable_t* load_elf32(void* elf_data);
|
||||
int load_elf32(void* elf_data, elf_executable_t** ptr);
|
||||
|
||||
#endif
|
||||
|
||||
26
include/drivers/graphics/vga.h
Normal file
26
include/drivers/graphics/vga.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef _VGA_GRAPHICS_H
|
||||
#define _VGA_GRAPHICS_H
|
||||
|
||||
#include <types.h>
|
||||
|
||||
struct bga_framebuffer
|
||||
{
|
||||
volatile uint8_t* addr;
|
||||
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
|
||||
uint32_t pitch; /* bytes per scanline */
|
||||
uint32_t bpp;
|
||||
};
|
||||
|
||||
|
||||
void bga_defaults(void);
|
||||
void bga_set_video_mode(uint32_t width, uint32_t height, uint32_t bit_depth);
|
||||
|
||||
void bga_putpixel(uint32_t x, uint32_t y, uint32_t color);
|
||||
|
||||
|
||||
void bga_drawline(int x0, int y0, int x1, int y1, uint32_t color);
|
||||
|
||||
#endif
|
||||
@ -32,6 +32,9 @@
|
||||
#define ATA_SR_DRQ 0x08
|
||||
#define ATA_SR_ERR 0x01
|
||||
|
||||
|
||||
#define SECTOR_SIZE 512
|
||||
|
||||
void ide_initialize(void);
|
||||
|
||||
int32_t ide_identify(uint8_t drive, uint16_t* buffer);
|
||||
@ -41,4 +44,6 @@ int32_t ide_write48(uint8_t drive, uint64_t lba, uint8_t sector_count, const voi
|
||||
int32_t read_sector(uint64_t lba, void* buffer);
|
||||
int32_t write_sector(uint64_t lba, const void* buffer);
|
||||
|
||||
int get_sector_size(uint8_t drive);
|
||||
|
||||
#endif
|
||||
|
||||
@ -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
|
||||
@ -62,6 +62,8 @@ struct pci_header_type_0 {
|
||||
uint8_t max_latency;
|
||||
} __attribute__((packed));
|
||||
|
||||
void pci_init(void);
|
||||
|
||||
uint32_t pci_config_read(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset);
|
||||
void pci_config_write(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value);
|
||||
void pci_enumerate(void);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -2,21 +2,38 @@
|
||||
#define _PS2_KEYBOARD_H
|
||||
|
||||
#include <types.h>
|
||||
#include <drivers/irq.h>
|
||||
|
||||
typedef enum {
|
||||
KEY_NONE = 0,
|
||||
KEY_ARROW_UP = 0xAA0,
|
||||
KEY_ARROW_UP = 0xFC,
|
||||
KEY_ARROW_DOWN,
|
||||
KEY_ARROW_LEFT,
|
||||
KEY_ARROW_RIGHT,
|
||||
/* Note: add more special keys here */
|
||||
} special_key;
|
||||
|
||||
typedef enum {
|
||||
KEY_UP = 0x1E,
|
||||
KEY_DOWN = 0x1F,
|
||||
KEY_RIGHT = 0x1C,
|
||||
KEY_LEFT = 0x1D,
|
||||
} lower_key;
|
||||
|
||||
typedef void (*ps2_hook_t)(char);
|
||||
|
||||
void keyboard_init(void);
|
||||
void keyboard_handler(void);
|
||||
registers_t* ps2_keyboard_handler(registers_t* regs);
|
||||
|
||||
void set_use_new_tty(bool t);
|
||||
|
||||
char get_char(void);
|
||||
uint16_t get_key(void);
|
||||
char* get_string(void);
|
||||
|
||||
char* kbd_gets(void);
|
||||
|
||||
bool setup_hook(ps2_hook_t func);
|
||||
bool remove_hook(ps2_hook_t func);
|
||||
|
||||
#endif
|
||||
|
||||
14
include/drivers/serio.h
Normal file
14
include/drivers/serio.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef _SERIAL_IO_H
|
||||
#define _SERIAL_IO_H
|
||||
|
||||
#include <types.h>
|
||||
|
||||
int serial_init(void);
|
||||
|
||||
void serial_write(char a);
|
||||
void serial_puts(const char* s);
|
||||
char serial_read(void);
|
||||
|
||||
bool use_serial(void);
|
||||
|
||||
#endif
|
||||
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
|
||||
19
include/fs/ssfs.h
Normal file
19
include/fs/ssfs.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef _STUPID_SIMPLE_FS_H
|
||||
#define _STUPID_SIMPLE_FS_H
|
||||
|
||||
#include <types.h>
|
||||
|
||||
typedef struct ssfs_file_header {
|
||||
char filename[16]; /* 15 chars + null zero */
|
||||
|
||||
uint32_t num_sectors;
|
||||
uint64_t start_sector;
|
||||
uint32_t num_bytes;
|
||||
|
||||
/*uint8_t padding_[11];*/ /* 32 bytes without this */
|
||||
} __attribute__((packed)) ssfs_file_header_t;
|
||||
|
||||
int ssfs_read_file(const char* name, void* buffer, int size);
|
||||
int ssfs_write_file(const char* name, void* data, int size);
|
||||
|
||||
#endif
|
||||
@ -4,7 +4,32 @@
|
||||
#include <types.h>
|
||||
|
||||
|
||||
#define MAX_FDS 64
|
||||
|
||||
struct file;
|
||||
|
||||
struct inode {
|
||||
size_t size;
|
||||
int permissions;
|
||||
/* | | */
|
||||
/* \/ FS-specific \/ */
|
||||
union {
|
||||
void* fs_data;
|
||||
void* private_data;
|
||||
};
|
||||
};
|
||||
|
||||
struct file_ops {
|
||||
int (*read)(struct file*, char*, size_t);
|
||||
int (*write)(struct file*, const char*, size_t);
|
||||
};
|
||||
|
||||
struct file {
|
||||
struct inode* f_inode;
|
||||
size_t f_offset;
|
||||
size_t f_refcount;
|
||||
const struct file_ops* f_ops;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
15
include/kdebug.h
Normal file
15
include/kdebug.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef _KERNEL_DEBUG_H
|
||||
#define _KERNEL_DEBUG_H
|
||||
|
||||
#include <types.h>
|
||||
|
||||
void set_debug(void);
|
||||
|
||||
void clear_debug(void);
|
||||
|
||||
void toggle_debug(void);
|
||||
|
||||
bool get_debug(void);
|
||||
|
||||
|
||||
#endif
|
||||
@ -2,6 +2,6 @@
|
||||
#define _KERNEL_BOOT_H
|
||||
|
||||
|
||||
uint8_t parse_boot_data(const char* data);
|
||||
void clear_bss(void);
|
||||
|
||||
#endif
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
#include <types.h>
|
||||
|
||||
void intro_begin(void);
|
||||
int16_t begin_anim(const char* version);
|
||||
|
||||
#endif
|
||||
|
||||
7
include/kernel/ksh_debug.h
Normal file
7
include/kernel/ksh_debug.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef _KERNEL_SHELL_DEBUGGER_H
|
||||
#define _KERNEL_SHELL_DEBUGGER_H
|
||||
|
||||
void print_all_regs(void);
|
||||
void print_gprs(void);
|
||||
|
||||
#endif
|
||||
0
include/kernel/kshell.c
Normal file
0
include/kernel/kshell.c
Normal file
6
include/kernel/kshell.h
Normal file
6
include/kernel/kshell.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef _KERNEL_SHELL_H
|
||||
#define _KERNEL_SHELL_H
|
||||
|
||||
void kshell_start(void);
|
||||
|
||||
#endif
|
||||
111
include/kernel/syscall.h
Normal file
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
|
||||
9
include/kernel/vars.h
Normal file
9
include/kernel/vars.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef _KERNEL_VARIABLES_H
|
||||
#define _KERNEL_VARIABLES_H
|
||||
|
||||
|
||||
#define KERNEL_VARIABLES_SIZE 4096 /* in bytes (note: it take up a whole page, yes.) */
|
||||
|
||||
void init_vars(void);
|
||||
|
||||
#endif
|
||||
@ -1,6 +1,32 @@
|
||||
#ifndef _KERNEL_INCLUDES_H
|
||||
#define _KERNEL_INCLUDES_H
|
||||
|
||||
#define KERNEL_VERSION "0.0.1e"
|
||||
#define ESPRESSO_KERNEL_
|
||||
|
||||
#define KERNEL_VERSION "0.0.2c"
|
||||
#define KERNEL_RELEASE_YEAR "2026"
|
||||
|
||||
#define _STATE_NORMAL 0
|
||||
#define _STATE_HANDLED 1
|
||||
#define _STATE_INTERRUPT -1
|
||||
#define _STATE_EXCEPTION -2
|
||||
#define _STATE_CRASH -555
|
||||
|
||||
|
||||
#define __always_inline inline __attribute__((always_inline))
|
||||
#define __hot __attribute__((hot))
|
||||
#define __cold __attribute__((cold))
|
||||
#define __noreturn __attribute__((noreturn))
|
||||
#define __section(x) __attribute__((section(x)))
|
||||
|
||||
#define __noreturn __attribute__((noreturn))
|
||||
|
||||
extern void _cli_asm(void);
|
||||
extern void _sti_asm(void);
|
||||
|
||||
#define IRQ_DISABLE() _cli_asm();
|
||||
#define IRQ_ENABLE() _sti_asm();
|
||||
|
||||
//#define DEBUG_USE_SSE2
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,23 +0,0 @@
|
||||
#ifndef _KSYMTAB_H
|
||||
#define _KSYMTAB_H
|
||||
|
||||
#include <types.h>
|
||||
|
||||
typedef struct kfunc {
|
||||
/*
|
||||
Bit 31 = 1 -> driver/module function, Bit 31 = 0 -> kernel function
|
||||
Bits 30-20 -> module/driver ID (11 bits)
|
||||
Bits 19-0 -> function ID (20 bits)
|
||||
*/
|
||||
uint32_t id;
|
||||
|
||||
uint32_t addr; /* Pointer to function, 0x0 if nonexistent */
|
||||
} kfunc_t;
|
||||
|
||||
uint64_t kfunc_call(kfunc_t* func, uint32_t a, uint32_t b, uint32_t c, uint32_t d);
|
||||
uint64_t call_kfunc_by_id(uint32_t id, uint32_t a, uint32_t b, uint32_t c, uint32_t d);
|
||||
|
||||
uint32_t add_kfunc(void* addr, bool module, uint16_t module_id, uint32_t function_id);
|
||||
kfunc_t make_kfunc(void* addr, bool module, uint16_t module_id, uint32_t function_id);
|
||||
|
||||
#endif
|
||||
19
include/math.h
Normal file
19
include/math.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef _MATH_H
|
||||
#define _MATH_H
|
||||
|
||||
#include <types.h>
|
||||
|
||||
bool is_low_power_of_two(int n);
|
||||
|
||||
uint64_t int_pow(uint64_t base, uint32_t exp);
|
||||
|
||||
/* Divide a by b, rounding up */
|
||||
static inline int div_round_up(int a, int b)
|
||||
{
|
||||
return (a + b - 1) / b;
|
||||
}
|
||||
|
||||
int abs(int x);
|
||||
|
||||
|
||||
#endif
|
||||
15
include/math/random.h
Normal file
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
|
||||
@ -1,19 +1,13 @@
|
||||
#ifndef _HEAP_H
|
||||
#define _HEAP_H
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#define HEAP_START 0xC0000000
|
||||
#define HEAP_SIZE (1024 * 4096) /* 1MB heap */
|
||||
|
||||
void heap_init(void);
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void heap_init(uint32_t start, uint32_t size);
|
||||
void* malloc(size_t size);
|
||||
void* malloc_aligned(size_t size, size_t alignment);
|
||||
|
||||
void free(void* ptr);
|
||||
void* calloc(size_t nmemb, size_t size);
|
||||
void* realloc(void* ptr, size_t size);
|
||||
|
||||
void free(void* ptr);
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
#ifndef _PAGING_H
|
||||
#define _PAGING_H
|
||||
|
||||
#include <types.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void paging_init(void);
|
||||
void map_page(void* phys, void* virt);
|
||||
void map_page(void* phys_addr, void* virt_addr);
|
||||
|
||||
#endif
|
||||
|
||||
@ -4,8 +4,8 @@
|
||||
#include <types.h>
|
||||
#include <multiboot.h>
|
||||
|
||||
void pmm_init(multiboot_info_t* mb_info);
|
||||
void* alloc_page(void);
|
||||
void free_page(void* ptr);
|
||||
void pmm_init(multiboot_info_t* mb);
|
||||
void* pmm_alloc_page(void);
|
||||
void pmm_free_page(void* addr);
|
||||
|
||||
#endif
|
||||
|
||||
12
include/mm_macros.h
Normal file
12
include/mm_macros.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef _MM_MACROS_H
|
||||
#define _MM_MACROS_H
|
||||
|
||||
#define MEMSET(ptr, value, num) \
|
||||
do { \
|
||||
unsigned char *_p = (unsigned char*)(ptr); \
|
||||
for (size_t _i = 0; _i < (num); ++_i) \
|
||||
_p[_i] = (unsigned char)(value); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#endif
|
||||
93
include/new_tty.h
Normal file
93
include/new_tty.h
Normal file
@ -0,0 +1,93 @@
|
||||
#ifndef _TTY_H
|
||||
#define _TTY_H
|
||||
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include <fs/vfs.h>
|
||||
|
||||
#include <processes.h>
|
||||
#include <sync.h>
|
||||
|
||||
|
||||
#define TTY_BUFFER_SIZE 4096
|
||||
#define TTY_RAW_BUFFER_SIZE 16
|
||||
#define MAX_TTYS 8 /* to make things easy, might change later */
|
||||
|
||||
#define TTY_ECHO 0x10 /* 0b00010000 */
|
||||
#define TTY_PASSWORD 0x20 /* 0b00100000 */
|
||||
#define TTY_ACTIVE 0x01 /* 0b00000001 */
|
||||
|
||||
#define TTY_CANONICAL 0x40 /* 0b01000000 */
|
||||
#define TTY_RAW 0x04 /* 0b00000100 */
|
||||
|
||||
#define TTY_ADDCHAR_ALWAYS 0x02 /* 0b00000010 */
|
||||
|
||||
#define TTY_NULL 0x80 /* 0b10000000 --- used to end the list of tty_t structs in the ttys array */
|
||||
|
||||
#define TTY_NORMAL TTY_ECHO | TTY_ACTIVE | TTY_CANONICAL
|
||||
|
||||
#define MODIFIER_CAPS 0x01 /* 0b00000001 */
|
||||
#define MODIFIER_CAPS_DESTROY 0b11111110
|
||||
#define MODIFIER_SHIFT 0x02 /* 0b00000010 */
|
||||
#define MODIFIER_SHIFT_DESTROY 0b11111101
|
||||
#define MODIFIER_ALT 0x04 /* 0b00000100 */
|
||||
#define MODIFIER_ALT_DESTROY 0b11111011
|
||||
#define MODIFIER_LCTRL 0x10 /* 0b00010000 */
|
||||
#define MODIFIER_LCTRL_DESTROY 0b11101111
|
||||
#define MODIFIER_RCTRL 0x0 /* 0b00100000*/
|
||||
#define MODIFIER_RCTRL_DESTROY 0b11011111
|
||||
|
||||
|
||||
typedef struct tty_t {
|
||||
char input_buffer[TTY_BUFFER_SIZE];
|
||||
size_t head;
|
||||
size_t tail;
|
||||
|
||||
uint32_t flags;
|
||||
|
||||
bool canonical;
|
||||
bool line_ready;
|
||||
|
||||
/* for raw mode */
|
||||
char raw_buf[TTY_RAW_BUFFER_SIZE];
|
||||
size_t raw_head;
|
||||
size_t raw_tail;
|
||||
|
||||
spinlock_t lock;
|
||||
|
||||
size_t user_input_start;
|
||||
size_t user_input_end;
|
||||
|
||||
struct file_ops f_ops;
|
||||
|
||||
pid_t foreground_pgid; /* not used yet */
|
||||
} tty_t;
|
||||
|
||||
/* essentially, key is non-zero if a key like the up arrow is pressed, otherwise c is the char that was entered */
|
||||
struct keyevent {
|
||||
uint8_t key;
|
||||
char c;
|
||||
};
|
||||
|
||||
int init_tty(void);
|
||||
|
||||
ssize_t tty_read(tty_t* tty, char* buf, size_t count);
|
||||
ssize_t tty_read_active(char* buf, size_t count);
|
||||
|
||||
char tty_get_char(void);
|
||||
|
||||
tty_t* get_active_tty(void);
|
||||
tty_t* tty_get_active(void);
|
||||
|
||||
void tty_and_flags(tty_t* tty, uint32_t flags);
|
||||
uint32_t tty_get_flags(tty_t* tty);
|
||||
|
||||
tty_t* make_tty(uint32_t flags);
|
||||
|
||||
void tty_receive_char(char c, uint32_t kbd_mod);
|
||||
char tty_translate_char(char c, uint32_t modifiers);
|
||||
|
||||
void tty_input_char(tty_t* tty, char c);
|
||||
|
||||
#endif
|
||||
@ -10,12 +10,24 @@ static inline uint32_t inl(uint16_t port)
|
||||
return rv;
|
||||
}
|
||||
|
||||
static inline void outl(uint16_t port, uint32_t data)
|
||||
static inline uint16_t inw(uint16_t port)
|
||||
{
|
||||
uint16_t rv;
|
||||
asm volatile ("inw %%dx, %%ax" : "=a" (rv) : "dN" (port));
|
||||
return rv;
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline)) void outl(uint16_t port, uint32_t data)
|
||||
{
|
||||
asm volatile ("outl %%eax, %%dx" : : "dN" (port), "a" (data));
|
||||
}
|
||||
|
||||
static inline void outb(uint16_t port, uint8_t val)
|
||||
static inline __attribute__((always_inline)) void outw(uint16_t port, uint16_t val)
|
||||
{
|
||||
asm volatile ( "outw %0, %1" : : "a"(val), "Nd"(port) : "memory");
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline)) void outb(uint16_t port, uint8_t val)
|
||||
{
|
||||
asm volatile ( "outb %0, %1" : : "a"(val), "Nd"(port) : "memory");
|
||||
}
|
||||
@ -30,17 +42,19 @@ static inline uint8_t inb(uint16_t port)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void io_wait()
|
||||
static inline __attribute__((always_inline)) void io_wait()
|
||||
{
|
||||
outb(0x80, 0);
|
||||
}
|
||||
|
||||
static inline void insw(uint16_t port, void* addr, uint32_t count) {
|
||||
__asm__ volatile ("rep insw" : "+D"(addr), "+c"(count) : "d"(port) : "memory");
|
||||
static inline __attribute__((always_inline)) void insw(uint16_t port, void* addr, uint32_t count)
|
||||
{
|
||||
asm volatile ("rep insw" : "+D"(addr), "+c"(count) : "d"(port) : "memory");
|
||||
}
|
||||
|
||||
static inline void outsw(uint16_t port, const void* addr, uint32_t count) {
|
||||
__asm__ volatile ("rep outsw" : "+S"(addr), "+c"(count) : "d"(port));
|
||||
static inline __attribute__((always_inline)) void outsw(uint16_t port, const void* addr, uint32_t count)
|
||||
{
|
||||
asm volatile ("rep outsw" : "+S"(addr), "+c"(count) : "d"(port));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
#ifndef _PRINTF_H
|
||||
#define _PRINTF_H
|
||||
|
||||
#include <tty.h>
|
||||
//#include <tty.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <vga/vga.h> /* Only for the vga_color enum */
|
||||
//#include <vga/vga.h> /* Only for the vga_color enum */
|
||||
|
||||
|
||||
void printwc(const char*, uint8_t);
|
||||
@ -12,9 +12,13 @@ void printd(const char* str);
|
||||
void printf(const char*, ...);
|
||||
|
||||
void print_int(int32_t value);
|
||||
void print_lint(int64_t value);
|
||||
void print_uint(uint32_t value);
|
||||
void print_luint(uint64_t value);
|
||||
void print_hex(uint32_t value, int width, bool uppercase);
|
||||
void print_hex64(uint64_t value, int width, bool uppercase);
|
||||
void print_double(double value, int precision);
|
||||
|
||||
void printf_set_color(uint8_t _color);
|
||||
|
||||
#endif
|
||||
|
||||
@ -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,7 +4,26 @@
|
||||
#include <types.h>
|
||||
#include <printf.h>
|
||||
|
||||
#define STDIN 0
|
||||
#define STDOUT 1
|
||||
#define STDERR 2
|
||||
|
||||
int read(uint32_t fd, void* data, size_t max_len);
|
||||
int write(uint32_t fd, void* data, size_t len);
|
||||
|
||||
char getchar(void);
|
||||
char* getstring(void);
|
||||
char* gets(void); /* Use this instead of getstring() */
|
||||
|
||||
int getstr(char* dest);
|
||||
|
||||
char* gets_new(int* num);
|
||||
|
||||
void putc(char c);
|
||||
|
||||
static inline void putchar(char c)
|
||||
{
|
||||
printf("%c", c);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#define STRING_H
|
||||
|
||||
#include <types.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* TODO: change all applicable `int32_t`s with `size_t`s. */
|
||||
|
||||
@ -16,18 +17,24 @@ char* strdup(const char* s);
|
||||
char* strtok(char* str, const char* delim);
|
||||
char* strchr(const char* s, int c);
|
||||
|
||||
int32_t ischar(int32_t c);
|
||||
int32_t isspace(char c);
|
||||
int32_t isalpha(char c);
|
||||
char upper(char c);
|
||||
char lower(char c);
|
||||
char toupper(char c);
|
||||
char lower(char c);
|
||||
void lowers(char* str);
|
||||
void uppers(char* str);
|
||||
|
||||
void* memset(void *dst, char c, uint32_t n);
|
||||
void* memset(void* dst, int c, size_t n);
|
||||
void* memcpy(void *dst, const void *src, uint32_t n);
|
||||
int32_t memcmp(const void *s1, const void *s2, size_t n);
|
||||
void* memclr(void* m_start, size_t m_count);
|
||||
void* memmove(void* dest, const void* src, size_t n);
|
||||
|
||||
int atoi(const char *str);
|
||||
long atol(const char *str);
|
||||
double atof(const char *str);
|
||||
|
||||
/* these functions are NOT in the standard C library */
|
||||
int num_strchr(const char* s, int c);
|
||||
char* strnlstrip(const char* __s);
|
||||
void strlnstripip(char* s);
|
||||
char** split(const char* str, char delim);
|
||||
void free_split(char** parts);
|
||||
|
||||
#endif
|
||||
|
||||
14
include/sync.h
Normal file
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>
|
||||
|
||||
@ -16,6 +16,9 @@ void terminal_write(const char* data, size_t size);
|
||||
void terminal_writestring(const char* data);
|
||||
void terminal_debug_writestring(const char* data);
|
||||
|
||||
void terminal_writeline(const char* data);
|
||||
void terminal_writechar_r(const char ch);
|
||||
|
||||
void terminal_setcolor(uint8_t color);
|
||||
uint8_t terminal_getcolor(void);
|
||||
|
||||
@ -26,5 +29,10 @@ void terminal_scroll(void);
|
||||
unsigned char terminal_get_shifted(unsigned char uc);
|
||||
|
||||
void terminal_set_cursor(uint16_t row, uint16_t column);
|
||||
void terminal_get_cursor(int* row, int* column);
|
||||
void terminal_update_cursor(void);
|
||||
|
||||
|
||||
void terminal_putcharat(char c, uint16_t row, uint16_t column);
|
||||
|
||||
#endif
|
||||
|
||||
@ -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
|
||||
|
||||
@ -21,7 +21,7 @@ void *sse2_memcpy(void *dst, const void *src, uint32_t n);
|
||||
void double_vector_to_int_vector(const double *src, int32_t *dst);
|
||||
void int_vector_to_double_vector(const int32_t *src, double *dst);
|
||||
|
||||
void *memclr_sse2(const void *const m_start, const size_t m_count);
|
||||
void* memclr_sse2(void *m_start, size_t m_count);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@ -5,22 +5,22 @@
|
||||
|
||||
/* Hardware text mode color constants. */
|
||||
enum vga_color {
|
||||
VGA_COLOR_BLACK = 0,
|
||||
VGA_COLOR_BLUE = 1,
|
||||
VGA_COLOR_GREEN = 2,
|
||||
VGA_COLOR_CYAN = 3,
|
||||
VGA_COLOR_RED = 4,
|
||||
VGA_COLOR_MAGENTA = 5,
|
||||
VGA_COLOR_BROWN = 6,
|
||||
VGA_COLOR_LIGHT_GREY = 7,
|
||||
VGA_COLOR_DARK_GREY = 8,
|
||||
VGA_COLOR_LIGHT_BLUE = 9,
|
||||
VGA_COLOR_LIGHT_GREEN = 10,
|
||||
VGA_COLOR_LIGHT_CYAN = 11,
|
||||
VGA_COLOR_LIGHT_RED = 12,
|
||||
VGA_COLOR_LIGHT_MAGENTA = 13,
|
||||
VGA_COLOR_LIGHT_BROWN = 14,
|
||||
VGA_COLOR_WHITE = 15,
|
||||
VGA_COLOR_BLACK = 0,
|
||||
VGA_COLOR_BLUE = 1,
|
||||
VGA_COLOR_GREEN = 2,
|
||||
VGA_COLOR_CYAN = 3,
|
||||
VGA_COLOR_RED = 4,
|
||||
VGA_COLOR_MAGENTA = 5,
|
||||
VGA_COLOR_BROWN = 6,
|
||||
VGA_COLOR_LIGHT_GREY = 7,
|
||||
VGA_COLOR_DARK_GREY = 8,
|
||||
VGA_COLOR_LIGHT_BLUE = 9,
|
||||
VGA_COLOR_LIGHT_GREEN = 10,
|
||||
VGA_COLOR_LIGHT_CYAN = 11,
|
||||
VGA_COLOR_LIGHT_RED = 12,
|
||||
VGA_COLOR_LIGHT_MAGENTA = 13,
|
||||
VGA_COLOR_LIGHT_BROWN = 14,
|
||||
VGA_COLOR_WHITE = 15,
|
||||
};
|
||||
|
||||
uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg);
|
||||
|
||||
@ -1,16 +1,66 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <cpuid.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <kernel/boot.h>
|
||||
|
||||
|
||||
uint8_t parse_boot_data(const char* data)
|
||||
extern uint8_t __bss_start;
|
||||
extern uint8_t __bss_end;
|
||||
|
||||
|
||||
void clear_bss(void)
|
||||
{
|
||||
if (strlen(data) == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
/*memset(&__bss_start, 0, &__bss_end - &__bss_start);*/
|
||||
|
||||
return 0;
|
||||
for (int i = 0; i < ((&__bss_end) - (&__bss_start)); i++)
|
||||
{
|
||||
(&(__bss_start))[i] = 0x0;
|
||||
}
|
||||
}
|
||||
|
||||
char* get_cpu_vendor_string(void)
|
||||
{
|
||||
unsigned int eax, ebx, ecx, edx;
|
||||
char vendor[13];
|
||||
|
||||
if (!__get_cpuid(0, &eax, &ebx, &ecx, &edx))
|
||||
{
|
||||
return strdup("Unknown");
|
||||
}
|
||||
|
||||
memcpy(&vendor[0], &ebx, 4);
|
||||
memcpy(&vendor[4], &edx, 4);
|
||||
memcpy(&vendor[8], &ecx, 4);
|
||||
vendor[12] = '\0';
|
||||
|
||||
return strdup(vendor);
|
||||
}
|
||||
|
||||
/*char* get_cpu_brand_string(void)
|
||||
{
|
||||
unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0;
|
||||
|
||||
int k = __get_cpuid_max(0x80000000, NULL);
|
||||
|
||||
if (k >= (int) 0x80000005)
|
||||
{
|
||||
return strdup("Unknown");
|
||||
}
|
||||
|
||||
char brand[49];
|
||||
unsigned int* brand_ptr = (unsigned int*) brand;
|
||||
|
||||
for (unsigned int i = 0; i < 3; ++i)
|
||||
{
|
||||
__get_cpuid(0x80000002 + i, &eax, &ebx, &ecx, &edx);
|
||||
brand_ptr[i * 4 + 0] = eax;
|
||||
brand_ptr[i * 4 + 1] = ebx;
|
||||
brand_ptr[i * 4 + 2] = ecx;
|
||||
brand_ptr[i * 4 + 3] = edx;
|
||||
}
|
||||
|
||||
brand[48] = '\0';
|
||||
return strdup(brand);
|
||||
}*/
|
||||
|
||||
@ -1,19 +1,28 @@
|
||||
#include <string.h>
|
||||
#include <tty.h>
|
||||
#include <stdio.h>
|
||||
#include <port_io.h>
|
||||
#include <stdlib.h>
|
||||
#include <drivers/ps2_keyboard.h>
|
||||
|
||||
#include <kernel/intro.h>
|
||||
|
||||
void delay_us(uint32_t microseconds, uint32_t cpu_mhz)
|
||||
{
|
||||
uint32_t count = cpu_mhz * microseconds;
|
||||
while (count--)
|
||||
{
|
||||
asm volatile ("nop" ::: "memory");
|
||||
}
|
||||
}
|
||||
void ack_char(char c);
|
||||
void start_kernel_shell(void);
|
||||
|
||||
char char_entered = 0x00;
|
||||
|
||||
void intro_begin(void)
|
||||
{
|
||||
char* fin = (char*) malloc(strlen(KERNEL_VERSION) + 6);
|
||||
memset(fin, 0, (strlen(KERNEL_VERSION) + 5));
|
||||
strcpy(fin, KERNEL_VERSION);
|
||||
|
||||
#ifdef _DEBUG
|
||||
strcat(fin, " DEBUG");
|
||||
#endif
|
||||
|
||||
begin_anim(fin);
|
||||
}
|
||||
|
||||
int16_t begin_anim(const char* version)
|
||||
{
|
||||
@ -31,11 +40,18 @@ int16_t begin_anim(const char* version)
|
||||
int16_t b = 0;
|
||||
int32_t sh_pos = VGA_WIDTH / 2;
|
||||
int32_t sv_pos = VGA_HEIGHT / 2;
|
||||
|
||||
setup_hook((ps2_hook_t) ack_char);
|
||||
|
||||
while (true)
|
||||
{
|
||||
terminal_clear();
|
||||
|
||||
if (char_entered != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
for (int32_t i = 0; n[i]; ++i)
|
||||
{
|
||||
terminal_putentryat(n[i], terminal_getcolor(), sh_pos, sv_pos);
|
||||
@ -64,11 +80,35 @@ int16_t begin_anim(const char* version)
|
||||
|
||||
b = 0;
|
||||
|
||||
delay_us(50000, 5000);
|
||||
sleep(1000);
|
||||
}
|
||||
|
||||
if (char_entered != 0)
|
||||
{
|
||||
start_kernel_shell();
|
||||
}
|
||||
else
|
||||
{
|
||||
terminal_clear();
|
||||
}
|
||||
|
||||
terminal_clear();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ack_char(char c)
|
||||
{
|
||||
char_entered = c;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void start_kernel_shell(void)
|
||||
{
|
||||
/* terminal_clear() already called by begin_anim() */
|
||||
|
||||
extern int kshell_start(int argc, char** argv);
|
||||
|
||||
kshell_start(0, NULL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
25
kernel/kdebug.c
Normal file
25
kernel/kdebug.c
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
|
||||
#include <kdebug.h>
|
||||
|
||||
static bool __debug = false;
|
||||
|
||||
void set_debug(void)
|
||||
{
|
||||
__debug = true;
|
||||
}
|
||||
|
||||
void clear_debug(void)
|
||||
{
|
||||
__debug = false;
|
||||
}
|
||||
|
||||
void toggle_debug(void)
|
||||
{
|
||||
__debug = !__debug;
|
||||
}
|
||||
|
||||
bool get_debug(void)
|
||||
{
|
||||
return __debug;
|
||||
}
|
||||
141
kernel/kernel.c
141
kernel/kernel.c
@ -11,61 +11,67 @@
|
||||
#include <types.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <kernel/boot.h>
|
||||
#include <panic.h>
|
||||
#include <kernel/kshell.h>
|
||||
#include <kernel/syscall.h>
|
||||
|
||||
#include <tty.h>
|
||||
#include <vga/vga.h>
|
||||
|
||||
#include <new_tty.h>
|
||||
|
||||
#include <kdebug.h>
|
||||
|
||||
#include <gdt.h>
|
||||
#include <drivers/idt.h>
|
||||
#include <drivers/irq.h>
|
||||
|
||||
#include <scheduler.h>
|
||||
|
||||
#include <multiboot.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <drivers/pci.h>
|
||||
#include <drivers/ps2_keyboard.h>
|
||||
#include <drivers/keyboard.h>
|
||||
#include <drivers/pit.h>
|
||||
#include <drivers/graphics/vga.h>
|
||||
/*#include <drivers/ahci.h>*/
|
||||
#include <drivers/ide.h>
|
||||
#include <mm/mm.h>
|
||||
#include <fs/fat32.h>
|
||||
#include <fs/duckfs.h>
|
||||
/*#include <fs/duckfs.h>*/
|
||||
#include <fs/vfs.h>
|
||||
#include <fs/sfs.h>
|
||||
|
||||
#ifdef DEBUG_USE_SSE2
|
||||
#include <vector_extensions/sse.h>
|
||||
#endif
|
||||
|
||||
#include <kernel/intro.h>
|
||||
|
||||
#include <builtin_games/miner.h>
|
||||
|
||||
#define DEBUG
|
||||
|
||||
|
||||
extern void _hang_asm(void);
|
||||
extern void _sti_asm(void);
|
||||
|
||||
char* espresso_str = ""
|
||||
"####### ##### ###### ###### ####### ##### ##### #######\n"
|
||||
"# # # # # # # # # # # # # #\n"
|
||||
"# # # # # # # # # # #\n"
|
||||
"##### ##### ###### ###### ##### ##### ##### # #\n"
|
||||
"# # # # # # # # # #\n"
|
||||
"# # # # # # # # # # # # #\n"
|
||||
"####### ##### # # # ####### ##### ##### #######\n";
|
||||
|
||||
|
||||
void kernel_main(multiboot_info_t* mbd, uint32_t magic)
|
||||
{
|
||||
|
||||
{
|
||||
/* --- BEGIN INITIALIZATION SECTION --- */
|
||||
|
||||
const char* espresso_kernel_version = "0.0.1e";
|
||||
|
||||
/* We need to initialize the terminal so that any error/debugging messages show. */
|
||||
terminal_initialize();
|
||||
|
||||
printf("Loading Espresso %s...\n", espresso_kernel_version);
|
||||
printf("Loading Espresso %s... ", KERNEL_VERSION);
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("[ DEBUG BUILD ]");
|
||||
#endif
|
||||
|
||||
printf("\n");
|
||||
|
||||
terminal_setcolor(VGA_COLOR_RED);
|
||||
|
||||
@ -85,89 +91,80 @@ void kernel_main(multiboot_info_t* mbd, uint32_t magic)
|
||||
|
||||
gdt_install(false);
|
||||
|
||||
pic_remap();
|
||||
pic_remap(); /* must be done before idt_init() */
|
||||
idt_init();
|
||||
_sti_asm();
|
||||
|
||||
irq_init(); /* MUST be done after pic_remap() and idt_init() */
|
||||
|
||||
terminal_setcolor(VGA_COLOR_GREEN);
|
||||
|
||||
printd("Initializing physical memory manager...\n");
|
||||
|
||||
pmm_init(mbd);
|
||||
printd("Physical memory manager initialized\n");
|
||||
|
||||
printd("Initializing paging...\n");
|
||||
paging_init();
|
||||
printd("Paging initialized\n");
|
||||
|
||||
printd("Initializing heap allocator...\n");
|
||||
heap_init();
|
||||
printd("Heap allocator initialized\n");
|
||||
heap_init(0xC2000000, 0x80000);
|
||||
|
||||
#ifdef DEBUG_USE_SSE2
|
||||
#ifdef _DEBUG
|
||||
printd("Testing SSE...\n");
|
||||
#endif
|
||||
int32_t sse_test_result = test_sse();
|
||||
if (sse_test_result != 0)
|
||||
{
|
||||
printf("[ DEBUG ] SSE test failed with RV %d\n", sse_test_result);
|
||||
printf("[ SSE ] SSE test failed with RV %d\n", sse_test_result);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
printd("SSE test passed\n");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
pit_init();
|
||||
|
||||
int j = init_tty();
|
||||
|
||||
if (j != 0)
|
||||
{
|
||||
printwc("[ ERROR ] init_tty failed\n", VGA_COLOR_RED);
|
||||
while (1)
|
||||
{
|
||||
asm volatile ("nop" ::: "memory");
|
||||
}
|
||||
}
|
||||
|
||||
printd("Initializing the PIT...\n");
|
||||
pit_init();
|
||||
printd("PIT initialized\n");
|
||||
//keyboard_init();
|
||||
init_keyboard();
|
||||
|
||||
printd("Initializing the PS/2 keyboard...\n");
|
||||
keyboard_init();
|
||||
printd("PS/2 Keyboard initialized\n");
|
||||
|
||||
/*
|
||||
printd("Initalizing AHCI...\n");
|
||||
ahci_init();
|
||||
printd("AHCI initialized\n");
|
||||
*/
|
||||
|
||||
printd("Initializing IDE system...\n");
|
||||
ide_initialize();
|
||||
printd("IDE initialized\n");
|
||||
|
||||
/*printd("Initializing DuckFS...\n");
|
||||
duckfs_init();
|
||||
printd("DuckFS initialized\n");*/
|
||||
|
||||
printd("Initializing PCI...\n");
|
||||
pci_enumerate();
|
||||
printd("PCI initialized\n");
|
||||
|
||||
pci_init();
|
||||
|
||||
init_sysints();
|
||||
|
||||
/*init_scheduler();*/
|
||||
|
||||
_sti_asm();
|
||||
|
||||
|
||||
/* --- END INITIALIZATION SECTION --- */
|
||||
|
||||
|
||||
|
||||
terminal_setcolor(VGA_COLOR_LIGHT_GREEN);
|
||||
|
||||
printf("Guten tag and welcome to Espresso %s\n", KERNEL_VERSION);
|
||||
|
||||
/*pit_sleep(4000);
|
||||
begin_anim(espresso_kernel_version);*/
|
||||
extern void terminal_clear(void);
|
||||
|
||||
//bga_defaults();
|
||||
|
||||
printf("Guten tag and welcome to Espresso %s\n", espresso_kernel_version);
|
||||
|
||||
printf("%s\n", espresso_str);
|
||||
|
||||
char buffer[512] = { 0 };
|
||||
|
||||
int32_t i = sfs_read_file("test.txt", buffer, -1);
|
||||
terminal_clear();
|
||||
|
||||
printf("%i\n", i);
|
||||
kshell_start();
|
||||
|
||||
if (i == 0)
|
||||
for(;;) /* Loop infinitely. We only do something when an interrupt/syscall happens now. */
|
||||
{
|
||||
printf("%s\n", buffer);
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
/* Loop infinitely. We only do something when a syscall happens now. */
|
||||
asm volatile("hlt" ::: "memory");
|
||||
}
|
||||
}
|
||||
|
||||
54
kernel/ksh_debug.c
Normal file
54
kernel/ksh_debug.c
Normal file
@ -0,0 +1,54 @@
|
||||
#include <stdio.h>
|
||||
#include <types.h>
|
||||
|
||||
#include <kernel/ksh_debug.h>
|
||||
|
||||
|
||||
|
||||
void print_all_regs(void)
|
||||
{
|
||||
uint32_t eax, ebx, ecx, edx, esi, edi, esp, ebp, eip;
|
||||
uint16_t cs, ds, es, ss;
|
||||
|
||||
asm volatile ("mov %%eax, %0" : "=r"(eax));
|
||||
asm volatile ("mov %%ebx, %0" : "=r"(ebx));
|
||||
asm volatile ("mov %%ecx, %0" : "=r"(ecx));
|
||||
asm volatile ("mov %%edx, %0" : "=r"(edx));
|
||||
asm volatile ("mov %%esi, %0" : "=r"(esi));
|
||||
asm volatile ("mov %%edi, %0" : "=r"(edi));
|
||||
asm volatile ("mov %%esp, %0" : "=r"(esp));
|
||||
asm volatile ("mov %%ebp, %0" : "=r"(ebp));
|
||||
|
||||
asm volatile (
|
||||
"call 1f\n"
|
||||
"1: pop %0\n"
|
||||
: "=r"(eip)
|
||||
);
|
||||
|
||||
asm volatile ("mov %%cs, %0" : "=r"(cs));
|
||||
asm volatile ("mov %%ds, %0" : "=r"(ds));
|
||||
asm volatile ("mov %%es, %0" : "=r"(es));
|
||||
asm volatile ("mov %%ss, %0" : "=r"(ss));
|
||||
|
||||
printf("EAX -> 0x%x EBX -> 0x%x ECX -> 0x%x EDX -> 0x%x\n", eax, ebx, ecx, edx);
|
||||
printf("ESI -> 0x%x EDI -> 0x%x ESP -> 0x%x EBP -> 0x%x\n", esi, edi, esp, ebp);
|
||||
printf("EIP (maybe) -> 0x%x\n", eip);
|
||||
printf("CS -> 0x%04x DS -> 0x%04x ES -> 0x%04x SS -> 0x%04x\n", cs, ds, es, ss);
|
||||
}
|
||||
|
||||
void print_gprs(void)
|
||||
{
|
||||
uint32_t eax, ebx, ecx, edx, esi, edi, esp, ebp;
|
||||
|
||||
asm volatile ("mov %%eax, %0" : "=r"(eax));
|
||||
asm volatile ("mov %%ebx, %0" : "=r"(ebx));
|
||||
asm volatile ("mov %%ecx, %0" : "=r"(ecx));
|
||||
asm volatile ("mov %%edx, %0" : "=r"(edx));
|
||||
asm volatile ("mov %%esi, %0" : "=r"(esi));
|
||||
asm volatile ("mov %%edi, %0" : "=r"(edi));
|
||||
asm volatile ("mov %%esp, %0" : "=r"(esp));
|
||||
asm volatile ("mov %%ebp, %0" : "=r"(ebp));
|
||||
|
||||
printf("EAX -> 0x%x EBX -> 0x%x ECX -> 0x%x EDX -> 0x%x\n", eax, ebx, ecx, edx);
|
||||
printf("ESI -> 0x%x EDI -> 0x%x ESP -> 0x%x EBP -> 0x%x\n", esi, edi, esp, ebp);
|
||||
}
|
||||
576
kernel/kshell.c
Normal file
576
kernel/kshell.c
Normal file
@ -0,0 +1,576 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <drivers/ps2_keyboard.h>
|
||||
#include <tty.h>
|
||||
#include <kernel/ksh_debug.h>
|
||||
#include <arch/x86/intrin.h>
|
||||
|
||||
#include <drivers/elf.h>
|
||||
|
||||
#include <kernel/syscall.h>
|
||||
|
||||
#include <scheduler.h>
|
||||
|
||||
#include <fs/fat16.h>
|
||||
|
||||
#include <kernel/kshell.h>
|
||||
|
||||
|
||||
const char* shell_version = "0.0.2";
|
||||
|
||||
char* prompt = NULL;
|
||||
int command = -1;
|
||||
bool _debug = false;
|
||||
|
||||
int execute(void);
|
||||
|
||||
|
||||
static void print_intro(void)
|
||||
{
|
||||
printf("Espresso kshell, ver %s on Espresso %s", shell_version, KERNEL_VERSION);
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf(" DEBUG BUILD");
|
||||
#endif
|
||||
|
||||
printf("\nSSE level: ");
|
||||
|
||||
command = 1;
|
||||
|
||||
execute();
|
||||
|
||||
extern char* get_cpu_vendor_string(void);
|
||||
extern char* get_cpu_brand_string(void);
|
||||
|
||||
/* XXX: NOTE: these do not need freeing. */
|
||||
char* temp_ = get_cpu_vendor_string();
|
||||
char* _temp = get_cpu_brand_string();
|
||||
|
||||
printf("CPU: %s\n", _temp == NULL ? "No info" : _temp);
|
||||
printf("CPU vendor: %s\n", temp_ == NULL ? "No info" : temp_);
|
||||
|
||||
printf("\nCopyright %s David J Goeke\n", KERNEL_RELEASE_YEAR);
|
||||
}
|
||||
|
||||
static char* commands[] = {
|
||||
"kinfo",
|
||||
"sseinfo",
|
||||
"kernelmem",
|
||||
"sectionmem",
|
||||
|
||||
"enable_debug",
|
||||
"disable_debug",
|
||||
"toggle_debug",
|
||||
"get_debug",
|
||||
|
||||
"dumpregs",
|
||||
"dumpgprs",
|
||||
|
||||
"testascii",
|
||||
|
||||
"printrandom",
|
||||
|
||||
"testfat16",
|
||||
|
||||
"printc",
|
||||
|
||||
"testscheduler",
|
||||
|
||||
"readfat16",
|
||||
|
||||
"help",
|
||||
|
||||
"exec",
|
||||
|
||||
"int16test",
|
||||
|
||||
"startbga",
|
||||
|
||||
NULL,
|
||||
};
|
||||
|
||||
const int NUM_COMMANDS = 21; /* Yes, including the NULL */
|
||||
|
||||
void kshell_start(void)
|
||||
{
|
||||
printf("Welcome to the kshell!\n");
|
||||
|
||||
prompt = strdup(">");
|
||||
|
||||
char* i = NULL;
|
||||
|
||||
print_intro();
|
||||
|
||||
command = -1;
|
||||
|
||||
do
|
||||
{
|
||||
printf("%s ", prompt);
|
||||
|
||||
/*i = gets();*/
|
||||
int j = 0;
|
||||
i = gets_new(&j);
|
||||
|
||||
if (j == 0)
|
||||
{
|
||||
printf("Error?\n");
|
||||
break;
|
||||
}
|
||||
|
||||
i = strnlstrip(i);
|
||||
|
||||
command = -1;
|
||||
|
||||
if (strlen(i) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (strcmp(i, "exit") == 0 || strcmp(i, "quit") == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/*char** argv = split(i, ' ');*/
|
||||
|
||||
|
||||
for (int j = 0; j < NUM_COMMANDS; j++)
|
||||
{
|
||||
if (strcmp(i, commands[j]) == 0)
|
||||
{
|
||||
command = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (command == -1)
|
||||
{
|
||||
printf("Unknown command %s len %i\n", i, strlen(i));
|
||||
}
|
||||
else if (command == 4)
|
||||
{
|
||||
_debug = true;
|
||||
}
|
||||
else if (command == 5)
|
||||
{
|
||||
_debug = false;
|
||||
}
|
||||
else if (command == 6)
|
||||
{
|
||||
_debug = !_debug;
|
||||
}
|
||||
else if (command == 7)
|
||||
{
|
||||
printf("Debugging: %s\n", _debug == true ? "On" : "Off");
|
||||
}
|
||||
|
||||
if (_debug)
|
||||
{
|
||||
printf(" ASCII -> ");
|
||||
|
||||
size_t len = strlen(i) + 1;
|
||||
|
||||
for (size_t n = 0; n < len; n++)
|
||||
{
|
||||
printf("%02X ", (int) i[n]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("C: %s; %i\n", commands[command], command);
|
||||
}
|
||||
|
||||
execute();
|
||||
|
||||
} while (1);
|
||||
|
||||
if (i)
|
||||
{
|
||||
free(i);
|
||||
}
|
||||
|
||||
printf("Goodbye!\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
static char* commands[] = {
|
||||
"kinfo",
|
||||
"sseinfo",
|
||||
"kernelmem",
|
||||
"sectionmem",
|
||||
|
||||
"enable_debug",
|
||||
"disable_debug",
|
||||
"toggle_debug",
|
||||
"get_debug",
|
||||
|
||||
"dumpregs",
|
||||
"dumpgprs",
|
||||
|
||||
"testascii",
|
||||
|
||||
"printrandom",
|
||||
|
||||
"testfat16",
|
||||
|
||||
NULL,
|
||||
};
|
||||
*/
|
||||
|
||||
int execute(void)
|
||||
{
|
||||
switch (command)
|
||||
{
|
||||
case 0: {
|
||||
printf("Espresso %s ", KERNEL_VERSION);
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("DEBUG BUILD");
|
||||
#endif
|
||||
|
||||
printf("\n");
|
||||
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
extern int sse_initialized;
|
||||
|
||||
switch (sse_initialized)
|
||||
{
|
||||
case 0:
|
||||
printf("No SSE support");
|
||||
break;
|
||||
case 1:
|
||||
printf("SSE1");
|
||||
break;
|
||||
case 2:
|
||||
printf("SSE2");
|
||||
break;
|
||||
case 3:
|
||||
printf("SSE3");
|
||||
break;
|
||||
case 4:
|
||||
printf("SSSE3");
|
||||
break;
|
||||
case 5:
|
||||
printf("SSE4.1");
|
||||
break;
|
||||
case 6:
|
||||
printf("SSE4.2");
|
||||
break;
|
||||
default:
|
||||
printf("WARNING: sse_initialized is in a invalid state!");
|
||||
break;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
extern uint8_t __kernel_start;
|
||||
extern uint8_t __kernel_end;
|
||||
size_t kernel_size = (size_t)&__kernel_end - (size_t)&__kernel_start;
|
||||
|
||||
printf("Kernel start: %p\n", (&__kernel_start));
|
||||
printf("Kernel end: %p\n", (&__kernel_end));
|
||||
printf("Kernel size (bytes): %llu\n", (uint64_t) kernel_size);
|
||||
printf("Kernel size (kbytes): %llu\n", (((uint64_t) kernel_size) / 1000));
|
||||
printf("Kernel size (mbytes): %f\n", (((uint64_t) kernel_size) / 1000.0) / 1000.0);
|
||||
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
extern uint8_t __kernel_text_start;
|
||||
extern uint8_t __kernel_text_end;
|
||||
extern uint8_t __kernel_rodata_start;
|
||||
extern uint8_t __kernel_rodata_end;
|
||||
extern uint8_t __kernel_data_start;
|
||||
extern uint8_t __kernel_data_end;
|
||||
extern uint8_t __bss_start;
|
||||
extern uint8_t __bss_end;
|
||||
|
||||
printf(".text: %i\n.data: %i\n.rodata: %i\n.bss: %i\n", ((&__kernel_text_end) - (&__kernel_text_start)),
|
||||
((&__kernel_data_end) - (&__kernel_data_start)),
|
||||
((&__kernel_rodata_end) - (&__kernel_rodata_start)),
|
||||
((&__bss_end) - (&__bss_start)));
|
||||
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
print_all_regs();
|
||||
break;
|
||||
}
|
||||
case 9: {
|
||||
print_gprs();
|
||||
break;
|
||||
}
|
||||
case 10: {
|
||||
/*extern void terminal_clear(void);*/
|
||||
|
||||
terminal_clear();
|
||||
|
||||
printf("Printing ASCII chars 0x00 through 0xFE, hit enter to exit\n");
|
||||
|
||||
sleep(2500);
|
||||
|
||||
terminal_clear();
|
||||
|
||||
for (int i = 0x00; i < 0xFF; i++)
|
||||
{
|
||||
printf("%c", (char) i);
|
||||
}
|
||||
|
||||
printf("\n\n\\/ Cool ASCII art \\/\n%c%c\n%c%c\n", 0xDA, 0xBF, 0xC0, 0xD9);
|
||||
|
||||
gets();
|
||||
|
||||
break;
|
||||
}
|
||||
case 11: {
|
||||
extern void seed_rand(uint32_t seed);
|
||||
extern uint32_t ulrand(void);
|
||||
|
||||
uint64_t v = rdtsc();
|
||||
|
||||
seed_rand((uint32_t) v);
|
||||
|
||||
printf("%ull\n", ulrand());
|
||||
|
||||
break;
|
||||
}
|
||||
case 12: {
|
||||
int retv = fat16_mount(0);
|
||||
|
||||
if (retv != 0)
|
||||
{
|
||||
printf("There was an error while mounting volume 0.\n");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
printf("Volume 0 mounted successfully.\n");
|
||||
|
||||
char fat_name[12];
|
||||
fat16_file_t file;
|
||||
|
||||
filename_to_83("test.txt", fat_name);
|
||||
|
||||
retv = fat16_create_file(fat_name, &file);
|
||||
|
||||
if (retv != 0)
|
||||
{
|
||||
printf("There was an error while creating a file on volume 0.\n");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t buf[512];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
strcpy((char*) buf, "fg");
|
||||
|
||||
retv = fat16_write_file(&file, buf, (strlen((char*) buf)));
|
||||
|
||||
if (retv != 0)
|
||||
{
|
||||
printf("There was an error while writing to a file on volume 0.\n");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t rbuf[512];
|
||||
memset(rbuf, 0, sizeof(rbuf));
|
||||
|
||||
retv = fat16_read_file(&file, rbuf);
|
||||
|
||||
if (retv != 0)
|
||||
{
|
||||
printf("There was an error while reading from a file on volume 0.\n");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
printf("The data read should be: %s\n", (char*) buf);
|
||||
printf("Read data: %s\n", (char*) rbuf);
|
||||
printf("Deleting test file\n");
|
||||
|
||||
fat16_delete_file(fat_name);
|
||||
|
||||
break;
|
||||
}
|
||||
case 13:
|
||||
{
|
||||
printf("Enter char to print in decimal: ");
|
||||
char* g = gets();
|
||||
|
||||
int val = atoi(g);
|
||||
|
||||
if (*g == '\0')
|
||||
{
|
||||
printf("Empty string entered\n");
|
||||
break;
|
||||
}
|
||||
|
||||
printf("%c\n", (char) val);
|
||||
|
||||
break;
|
||||
}
|
||||
case 14:
|
||||
{
|
||||
#if 1
|
||||
void taskA() { while (1) printf("A"); }
|
||||
void taskB() { while (1) printf("B"); }
|
||||
|
||||
create_task(taskA);
|
||||
create_task(taskB);
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
case 15:
|
||||
{
|
||||
char* filename = "t.bin";
|
||||
|
||||
int retv = fat16_mount(0);
|
||||
|
||||
if (retv != 0)
|
||||
{
|
||||
printf("There was an error while mounting volume 0.\n");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
printf("Volume 0 mounted successfully.\n");
|
||||
|
||||
char fat_name[12];
|
||||
fat16_file_t file;
|
||||
|
||||
filename_to_83(filename, fat_name);
|
||||
retv = fat16_find_file(fat_name, &file);
|
||||
|
||||
if (retv != 0)
|
||||
{
|
||||
printf("file %s could not be found\n", filename);
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t buffer[256];
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
|
||||
retv = fat16_read_file(&file, buffer);
|
||||
|
||||
if (retv != 0)
|
||||
{
|
||||
printf("Could not read file s\n", (char*) filename);
|
||||
break;
|
||||
}
|
||||
|
||||
printf("read data: %s\n", (char*) buffer);
|
||||
break;
|
||||
}
|
||||
case 16:
|
||||
{
|
||||
printf("Commands:\n");
|
||||
|
||||
for (int i = 0; i < NUM_COMMANDS; i++)
|
||||
{
|
||||
printf("%s\n", commands[i]);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 17:
|
||||
{
|
||||
char* filename = "hello.elf";
|
||||
|
||||
printf("Loading and executing file %s\n", filename);
|
||||
|
||||
int retv = fat16_mount(0);
|
||||
|
||||
if (retv != 0)
|
||||
{
|
||||
printf("There was an error while mounting volume 0.\n");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
printf("Volume 0 mounted successfully.\n");
|
||||
|
||||
char fat_name[12];
|
||||
fat16_file_t file;
|
||||
|
||||
filename_to_83(filename, fat_name);
|
||||
retv = fat16_find_file(fat_name, &file);
|
||||
|
||||
if (retv != 0)
|
||||
{
|
||||
printf("file %s could not be found\n", filename);
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t* buffer = malloc(file.size);
|
||||
memset(buffer, 0, file.size);
|
||||
|
||||
retv = fat16_read_file(&file, buffer);
|
||||
|
||||
if (retv != 0)
|
||||
{
|
||||
printf("Could not read file s\n", (char*) filename);
|
||||
break;
|
||||
}
|
||||
|
||||
printf("Parsing ELF headers\n");
|
||||
|
||||
elf_executable_t* f = NULL;
|
||||
int j = load_elf32(buffer, &f);
|
||||
|
||||
if (j != 0)
|
||||
{
|
||||
printf("Invalid ELF file\n");
|
||||
goto b_1;
|
||||
}
|
||||
|
||||
printf("Attempting execution of executable at (%p)...\n", f->entry_point);
|
||||
|
||||
retv = f->entry_point();
|
||||
|
||||
printf("\nreturn value: %i\n", retv);
|
||||
|
||||
b_1:
|
||||
|
||||
if (f)
|
||||
{
|
||||
free(f);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 18:
|
||||
{
|
||||
printf("testing int 16\n");
|
||||
|
||||
const char* str = "HELLO!\n";
|
||||
|
||||
syscall1(SYS_TERMINAL_WRITESTRING, str);
|
||||
|
||||
printf("test ran\n");
|
||||
|
||||
break;
|
||||
}
|
||||
case 19:
|
||||
{
|
||||
extern void bga_defaults(void);
|
||||
|
||||
bga_defaults();
|
||||
|
||||
extern void bga_drawline(int, int, int, int, uint32_t);
|
||||
bga_drawline(0, 0, 100, 100, 0x00FFFF00);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
118
kernel/syscall.c
Normal file
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;
|
||||
}
|
||||
25
kernel/vars.c
Normal file
25
kernel/vars.c
Normal file
@ -0,0 +1,25 @@
|
||||
#include <types.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <kernel/vars.h>
|
||||
|
||||
/*
|
||||
Number of bytes in kernel variable space: 4096 (4KiB)
|
||||
Number of bits in kernel variable space: 32768 (32Mib)
|
||||
*/
|
||||
|
||||
uint8_t vars[KERNEL_VARIABLES_SIZE];
|
||||
|
||||
void init_vars(void)
|
||||
{
|
||||
memset(vars, 0, KERNEL_VARIABLES_SIZE);
|
||||
}
|
||||
|
||||
/* bo = bit offset */
|
||||
void set_bit_bo(uint32_t offset, uint8_t val)
|
||||
{
|
||||
/* First, extract the byte offset. (round down to a multiple of 8, and divide by 8. */
|
||||
(void) offset;
|
||||
(void) val;
|
||||
}
|
||||
@ -2,75 +2,230 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <drivers/ps2_keyboard.h>
|
||||
|
||||
#include <new_tty.h>
|
||||
|
||||
#include <builtin_games/miner.h>
|
||||
|
||||
|
||||
#define PLAYER '@'
|
||||
#define SHOP '$'
|
||||
#define STONE '#'
|
||||
#define IRON ';'
|
||||
#define COAL ':'
|
||||
#define COPPER '^'
|
||||
#define GOLD '%'
|
||||
#define RUBY '*'
|
||||
#define DIAMOND '~'
|
||||
#define PLATINUM '&'
|
||||
#define NOTHING ' '
|
||||
|
||||
|
||||
/*
|
||||
static const size_t VGA_WIDTH = 80;
|
||||
static const size_t VGA_HEIGHT = 25;
|
||||
*/
|
||||
|
||||
/* clear screen */
|
||||
void cls(void)
|
||||
{
|
||||
terminal_clear();
|
||||
}
|
||||
|
||||
static bool pointer_valid(void* ptr)
|
||||
{
|
||||
if (ptr/* && (ptr < (heap_end + 4096))*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool valid_pointer(void* ptr)
|
||||
{
|
||||
return pointer_valid(ptr);
|
||||
}
|
||||
|
||||
/*const char PLAYER = '@';
|
||||
const char ENEMY = '*';
|
||||
const char PLAYER_BULLET = '^';
|
||||
const char ENEMY_BULLET = '`'
|
||||
const char BOMB = '*';
|
||||
const char EMPTY = ' ';*/
|
||||
|
||||
#define MAP_ROWS 25
|
||||
#define MAP_COLUMNS 25
|
||||
|
||||
#define PLAYER_STARTING_POS (MAP_COLUMNS / 2) /* for MAP_COLUMNS being 25, this will be 12. */
|
||||
|
||||
#define STARTING_ENEMY_NUM 4
|
||||
|
||||
enum {
|
||||
PLAYER = '@',
|
||||
PLAYER_BULLET = '^',
|
||||
ENEMY = '%',
|
||||
ENEMY_BULLET = '`',
|
||||
BOMB = '*',
|
||||
EMPTY = ' ',
|
||||
};
|
||||
|
||||
struct bullet {
|
||||
bool players; /* if enemies, false */
|
||||
|
||||
int row;
|
||||
int column;
|
||||
};
|
||||
|
||||
struct game_vars {
|
||||
tty_t* tty;
|
||||
uint32_t stored_tty_flags;
|
||||
|
||||
int v;
|
||||
|
||||
char c;
|
||||
|
||||
int player_score;
|
||||
int player_credits;
|
||||
|
||||
bool error;
|
||||
|
||||
int num_enemies;
|
||||
int num_enemy_step;
|
||||
char** map; /* char map[MAP_ROWS][MAP_COLUMNS] */
|
||||
|
||||
bool enemys[MAP_COLUMNS]; /* enemy bitmap */
|
||||
|
||||
struct bullet* bullets;
|
||||
int num_bullets;
|
||||
};
|
||||
|
||||
|
||||
void init_map(struct game_vars* gv)
|
||||
{
|
||||
for (int i = 0; i < MAP_ROWS; i++)
|
||||
{
|
||||
for (int j = 0; j < MAP_COLUMNS; j++)
|
||||
{
|
||||
gv->map[i][j] = EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
gv->map[0][PLAYER_STARTING_POS] = PLAYER;
|
||||
|
||||
int enemy_pos = 0;
|
||||
|
||||
for (int b = 0; b < STARTING_ENEMY_NUM; b++)
|
||||
{
|
||||
gv->map[24][enemy_pos] = ENEMY;
|
||||
enemy_pos++;
|
||||
gv->num_enemies++;
|
||||
gv->enemys[b] = true;
|
||||
}
|
||||
|
||||
if (!valid_pointer(gv->map))
|
||||
{
|
||||
gv->error = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ai(struct game_vars* gv)
|
||||
{
|
||||
for (int i = 0; i < MAP_COLUMNS; i++)
|
||||
{
|
||||
if ((gv->map[24][i] == ENEMY) && (gv->map[0][i] == PLAYER))
|
||||
{
|
||||
gv->map[23][i] = ENEMY_BULLET;
|
||||
int num_bullets = gv->num_bullets;
|
||||
gv->bullets[num_bullets].players = false;
|
||||
gv->bullets[num_bullets].column = i;
|
||||
gv->bullets[num_bullets].row = 23;
|
||||
gv->num_bullets++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tick(struct game_vars* gv)
|
||||
{
|
||||
for (int i = 0; i < gv->num_bullets; i++)
|
||||
{
|
||||
struct bullet* b = &gv->bullets[i];
|
||||
gv->map[b->row][b->column] = EMPTY;
|
||||
b->column++;
|
||||
b->row++;
|
||||
gv->map[b->row][b->column] = b->players ? PLAYER_BULLET : ENEMY_BULLET;
|
||||
}
|
||||
}
|
||||
|
||||
int init_game(struct game_vars* ptr)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
ptr->error = false;
|
||||
|
||||
init_map(ptr);
|
||||
|
||||
ptr->num_enemy_step++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void miner_main(void)
|
||||
{
|
||||
terminal_clear();
|
||||
#if 0
|
||||
cls();
|
||||
|
||||
struct game_vars gv = { .tty = get_active_tty(), .stored_tty_flags = tty_get_flags(get_active_tty()),
|
||||
.v = 0, .c = 0,
|
||||
.player_score = 0, .player_credits = 0,
|
||||
.error = false,
|
||||
.num_enemies = STARTING_ENEMY_NUM, .num_enemy_step = 0,
|
||||
.map = malloc(MAP_COLUMNS * MAP_ROWS),
|
||||
.bullets = NULL, .num_bullets = 0,
|
||||
};
|
||||
|
||||
memset(gv.enemys, 0, sizeof(gv.enemys));
|
||||
|
||||
if (!gv.map)
|
||||
{
|
||||
goto quit;
|
||||
}
|
||||
|
||||
printf("gv.map = %p\n", gv.map);
|
||||
|
||||
gv.tty->flags |= TTY_RAW;
|
||||
gv.tty->flags &= ~TTY_CANONICAL;
|
||||
gv.tty->flags &= ~TTY_ECHO; /* disable echo */
|
||||
|
||||
printf("\n\tMiner\n\t\tMine ores to sell for money and upgrade your drone\n\n\n\t\t\tHIT ENTER TO CONTINUE, TAB TO EXIT\n");
|
||||
|
||||
char b = get_char();
|
||||
|
||||
while (b != '\n' && b != '\t')
|
||||
|
||||
/*while (gv.c != '\n' && gv.c != '\t')
|
||||
{
|
||||
sleep(10);
|
||||
b = get_char();
|
||||
gv.c = getchar();
|
||||
}
|
||||
|
||||
if (b == '\t')
|
||||
|
||||
if (gv.c == '\t')
|
||||
{
|
||||
return;
|
||||
goto quit;
|
||||
}
|
||||
|
||||
uint16_t c = 0x0;
|
||||
|
||||
terminal_clear();
|
||||
|
||||
while (true)
|
||||
|
||||
cls();*/
|
||||
|
||||
while (1)
|
||||
{
|
||||
sleep(10);
|
||||
gv.c = getchar();
|
||||
|
||||
c = get_key();
|
||||
|
||||
if (c == 0xFFFA || c == 0x0)
|
||||
if (gv.c == '\t')
|
||||
{
|
||||
continue;
|
||||
goto quit;
|
||||
}
|
||||
|
||||
break;
|
||||
sleep(500);
|
||||
}
|
||||
|
||||
b = getchar();
|
||||
|
||||
while (b == 0x5)
|
||||
|
||||
quit:
|
||||
|
||||
gv.tty->flags = gv.stored_tty_flags;
|
||||
if (gv.map && pointer_valid(gv.map))
|
||||
{
|
||||
sleep(10);
|
||||
b = getchar();
|
||||
free(gv.map);
|
||||
}
|
||||
|
||||
terminal_clear();
|
||||
|
||||
cls();
|
||||
|
||||
printf("Goodbye!\n");
|
||||
|
||||
sleep(2000);
|
||||
|
||||
cls();
|
||||
#endif
|
||||
}
|
||||
|
||||
58
lib/espresso/kstring.c
Normal file
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;
|
||||
}
|
||||
124
lib/ksymtab.c
124
lib/ksymtab.c
@ -1,124 +0,0 @@
|
||||
|
||||
|
||||
#include <ksymtab.h>
|
||||
|
||||
|
||||
|
||||
|
||||
#define KFUNC_TABLE_ADDRESS 0xC0101000
|
||||
|
||||
#define KSYMTAB_MAX 0x8086FF
|
||||
|
||||
#define IS_MODULE_FUNC(id) ((id) & 0x80000000)
|
||||
#define GET_MODULE_ID(id) (((id) >> 20) & 0x7FF)
|
||||
#define GET_FUNC_ID(id) ((id) & 0xFFFFF)
|
||||
#define EXISTS(id) ((id) > 0x0)
|
||||
|
||||
#define MAKE_KERNEL_FUNC(id) ((id) & 0x7FFFFFFF)
|
||||
|
||||
#define MAKE_MODULE_FUNC(mid, fid) (0x80000000 | ((mid) << 20) | ((fid) & 0xFFFFF))
|
||||
|
||||
kfunc_t* kfunc_table = (kfunc_t*)KFUNC_TABLE_ADDRESS;
|
||||
|
||||
static uint32_t ktab_size = 0;
|
||||
|
||||
|
||||
uint64_t kfunc_call(kfunc_t* func, uint32_t a, uint32_t b, uint32_t c, uint32_t d)
|
||||
{
|
||||
uint32_t eax_ret, edx_ret;
|
||||
|
||||
asm volatile (
|
||||
"push %[d]\n\t"
|
||||
"push %[c]\n\t"
|
||||
"push %[b]\n\t"
|
||||
"push %[a]\n\t"
|
||||
"call *%[fn]\n\t"
|
||||
"add $16, %%esp\n\t" /* clean up stack (4 args * 4 bytes) */
|
||||
: "=a"(eax_ret), "=d"(edx_ret)
|
||||
: [a]"r"(a), [b]"r"(b), [c]"r"(c), [d]"r"(d), [fn]"r"(func->addr)
|
||||
: "memory"
|
||||
);
|
||||
|
||||
return ((uint64_t)edx_ret << 32) | eax_ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint64_t call_kfunc_by_id(uint32_t id, uint32_t a, uint32_t b, uint32_t c, uint32_t d)
|
||||
{
|
||||
for (int i = 0; i < (int)ktab_size; i++)
|
||||
{
|
||||
if (kfunc_table[i].id == id)
|
||||
{
|
||||
if (kfunc_table[i].addr == 0x0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return kfunc_call(&kfunc_table[i], a, b, c, d);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
uint32_t add_kfunc(void* addr, bool module, uint16_t module_id, uint32_t function_id)
|
||||
{
|
||||
if (ktab_size >= KSYMTAB_MAX)
|
||||
{
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
kfunc_t kf = make_kfunc(addr, module, module_id, function_id);
|
||||
kfunc_table[ktab_size] = kf;
|
||||
|
||||
ktab_size++;
|
||||
|
||||
return kf.id;
|
||||
}
|
||||
|
||||
/*
|
||||
Constructs and returns a kfunc_t:
|
||||
- 'addr' is the address of the function (can be NULL/0)
|
||||
- 'module' indicates if it's a module/driver function
|
||||
- 'module_id' is used only if 'module' is true (11 bits max)
|
||||
- 'function_id':
|
||||
- 20 bits if module is true
|
||||
- 31 bits if kernel function
|
||||
*/
|
||||
kfunc_t make_kfunc(void* addr, bool module, uint16_t module_id, uint32_t function_id)
|
||||
{
|
||||
uint32_t id;
|
||||
|
||||
if (module)
|
||||
{
|
||||
id = 0x80000000 | ((module_id & 0x7FF) << 20) | (function_id & 0xFFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (function_id == UINT32_MAX)
|
||||
{
|
||||
function_id = ktab_size;
|
||||
}
|
||||
id = function_id & 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
kfunc_t result = {
|
||||
.id = id,
|
||||
.addr = (uint32_t)(uintptr_t)addr
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
kfunc_t* find_kfunc(uint32_t id)
|
||||
{
|
||||
for (uint32_t i = 0; i < ktab_size; i++)
|
||||
{
|
||||
if (kfunc_table[i].id == id)
|
||||
{
|
||||
return &kfunc_table[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
43
lib/math.c
Normal file
43
lib/math.c
Normal file
@ -0,0 +1,43 @@
|
||||
#include <types.h>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
|
||||
static int ps_of_two[12] = { 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 };
|
||||
|
||||
bool is_low_power_of_two(int n)
|
||||
{
|
||||
for (int i = 0; i < 11; i++)
|
||||
{
|
||||
if (n == ps_of_two[i])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t int_pow(uint64_t base, uint32_t exp)
|
||||
{
|
||||
uint64_t result = 1;
|
||||
|
||||
while (exp)
|
||||
{
|
||||
if (exp & 1)
|
||||
{
|
||||
result *= base;
|
||||
}
|
||||
|
||||
exp >>= 1;
|
||||
base *= base;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int abs(int x)
|
||||
{
|
||||
return (x < 0) ? -x : x;
|
||||
}
|
||||
79
lib/math/random.c
Normal file
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;
|
||||
}
|
||||
195
lib/mm/heap.c
195
lib/mm/heap.c
@ -1,76 +1,143 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <mm/heap.h>
|
||||
#include <mm/pmm.h>
|
||||
#include <mm/paging.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <mm_macros.h>
|
||||
|
||||
#include <mm/heap.h>
|
||||
|
||||
#define ALIGNMENT 8
|
||||
#define ALIGN(size) (((size) + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1))
|
||||
#define ALIGN4(x) (((x) + 3) & ~3)
|
||||
#define MIN_BLOCK_SIZE 16
|
||||
|
||||
typedef struct block_header {
|
||||
typedef struct block {
|
||||
size_t size;
|
||||
struct block_header* next;
|
||||
struct block* next;
|
||||
int free;
|
||||
} block_header_t;
|
||||
} block_t;
|
||||
|
||||
#define BLOCK_SIZE sizeof(block_header_t)
|
||||
#define BLOCK_SIZE sizeof(block_t)
|
||||
|
||||
static uint8_t* heap_base = (uint8_t*)HEAP_START;
|
||||
static uint8_t* heap_end = (uint8_t*)(HEAP_START + HEAP_SIZE);
|
||||
static uint8_t* heap_base;
|
||||
static uint8_t* heap_end;
|
||||
static size_t heap_size;
|
||||
static block_t* free_list;
|
||||
|
||||
static block_header_t* free_list = NULL;
|
||||
|
||||
|
||||
void heap_init(void)
|
||||
void heap_init(uint32_t start, uint32_t size)
|
||||
{
|
||||
free_list = (block_header_t*)heap_base;
|
||||
free_list->size = HEAP_SIZE - BLOCK_SIZE;
|
||||
free_list->next = NULL;
|
||||
#ifdef _DEBUG
|
||||
printf("[ HEAP ] Initializing heap allocator...\n");
|
||||
#endif
|
||||
|
||||
heap_base = (uint8_t*) ALIGN4((uintptr_t) start);
|
||||
heap_end = heap_base;
|
||||
heap_size = size;
|
||||
free_list = NULL;
|
||||
|
||||
for (uint32_t i = 0; i < size; i += 0x1000)
|
||||
{
|
||||
map_page(pmm_alloc_page(), (void*)(start + i));
|
||||
}
|
||||
|
||||
/* Set up initial free block */
|
||||
free_list = (block_t*)heap_base;
|
||||
free_list->size = heap_size - BLOCK_SIZE;
|
||||
free_list->free = 1;
|
||||
free_list->next = NULL;
|
||||
|
||||
heap_end = heap_base + size;
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("[ HEAP ] Heap allocator initialized\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void* malloc(size_t size)
|
||||
static block_t* find_free_block(size_t size)
|
||||
{
|
||||
size = ALIGN(size);
|
||||
block_header_t* curr = free_list;
|
||||
|
||||
block_t* curr = free_list;
|
||||
while (curr)
|
||||
{
|
||||
if (curr->free && curr->size >= size)
|
||||
{
|
||||
/* Split if there's space for another block */
|
||||
if (curr->size >= size + BLOCK_SIZE + ALIGNMENT)
|
||||
{
|
||||
block_header_t* new_block = (block_header_t*)((uint8_t*)curr + BLOCK_SIZE + size);
|
||||
new_block->size = curr->size - size - BLOCK_SIZE;
|
||||
new_block->next = curr->next;
|
||||
new_block->free = 1;
|
||||
|
||||
curr->next = new_block;
|
||||
curr->size = size;
|
||||
}
|
||||
|
||||
curr->free = 0;
|
||||
return (void*)((uint8_t*)curr + BLOCK_SIZE);
|
||||
return curr;
|
||||
}
|
||||
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
printd("Malloc failed due to lack of free memory\n");
|
||||
|
||||
printf("find_free_block(): No free block found!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void split_block(block_t* blk, size_t size)
|
||||
{
|
||||
if (blk->size >= size + BLOCK_SIZE + MIN_BLOCK_SIZE)
|
||||
{
|
||||
block_t* new_blk = (block_t*)((uint8_t*)blk + BLOCK_SIZE + size);
|
||||
new_blk->size = blk->size - size - BLOCK_SIZE;
|
||||
new_blk->free = 1;
|
||||
new_blk->next = blk->next;
|
||||
blk->next = new_blk;
|
||||
blk->size = size;
|
||||
}
|
||||
}
|
||||
|
||||
void* malloc(size_t size)
|
||||
{
|
||||
size = ALIGN4(size);
|
||||
block_t* blk = find_free_block(size);
|
||||
|
||||
if (!blk)
|
||||
{
|
||||
printf("malloc(): No free block found!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
split_block(blk, size);
|
||||
blk->free = 0;
|
||||
return (void*)((uint8_t*)blk + BLOCK_SIZE);
|
||||
}
|
||||
|
||||
void free(void* ptr)
|
||||
{
|
||||
if (!ptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
block_t* blk = (block_t*)((uint8_t*)ptr - BLOCK_SIZE);
|
||||
blk->free = 1;
|
||||
|
||||
/* coalesce */
|
||||
block_t* curr = free_list;
|
||||
while (curr && curr->next)
|
||||
{
|
||||
/*if (curr->free && curr->next->free)
|
||||
{
|
||||
curr->size += BLOCK_SIZE + curr->next->size;
|
||||
curr->next = curr->next->next;
|
||||
}*/
|
||||
if (curr->free && curr->next->free && (uint8_t*)curr + BLOCK_SIZE + curr->size == (uint8_t*)curr->next)
|
||||
{
|
||||
curr->size += BLOCK_SIZE + curr->next->size;
|
||||
curr->next = curr->next->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
curr = curr->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
size_t total = nmemb * size;
|
||||
void* ptr = malloc(total);
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
memset(ptr, 0, total);
|
||||
MEMSET(ptr, 0, total);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@ -81,57 +148,25 @@ void* realloc(void* ptr, size_t size)
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
if (!size)
|
||||
{
|
||||
free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
block_header_t* block = (block_header_t*)((uint8_t*)ptr - BLOCK_SIZE);
|
||||
if (block->size >= size)
|
||||
block_t* blk = (block_t*)((uint8_t*)ptr - BLOCK_SIZE);
|
||||
if (blk->size >= size)
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* new_ptr = malloc(size);
|
||||
if (new_ptr) {
|
||||
memcpy(new_ptr, ptr, block->size);
|
||||
|
||||
if (new_ptr)
|
||||
{
|
||||
memcpy(new_ptr, ptr, blk->size);
|
||||
free(ptr);
|
||||
}
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
void free(void* ptr)
|
||||
{
|
||||
if (!ptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
block_header_t* block = (block_header_t*)((uint8_t*)ptr - BLOCK_SIZE);
|
||||
block->free = 1;
|
||||
|
||||
/* Forward coalescing */
|
||||
if (block->next && block->next->free)
|
||||
{
|
||||
block->size += BLOCK_SIZE + block->next->size;
|
||||
block->next = block->next->next;
|
||||
}
|
||||
|
||||
/* Backward coalescing */
|
||||
block_header_t* prev = NULL;
|
||||
block_header_t* curr = free_list;
|
||||
|
||||
while (curr && curr != block)
|
||||
{
|
||||
prev = curr;
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
if (prev && prev->free)
|
||||
{
|
||||
prev->size += BLOCK_SIZE + block->size;
|
||||
prev->next = block->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
110
lib/mm/paging.c
110
lib/mm/paging.c
@ -1,82 +1,60 @@
|
||||
#include <mm/pmm.h>
|
||||
#include <string.h>
|
||||
#include <mm_macros.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <mm/paging.h>
|
||||
#include <mm/pmm.h>
|
||||
#include <mm/heap.h>
|
||||
|
||||
#define PAGE_DIRECTORY_ENTRIES 1024
|
||||
#define PAGE_TABLE_ENTRIES 1024
|
||||
#define PAGE_SIZE 4096
|
||||
#define PAGE_PRESENT 0x1
|
||||
#define PAGE_WRITE 0x2
|
||||
#define PAGE_SIZE 4096
|
||||
|
||||
typedef uint32_t page_directory_entry_t;
|
||||
typedef uint32_t page_table_entry_t;
|
||||
|
||||
static page_directory_entry_t* page_directory = NULL; /* Will be allocated */
|
||||
static page_table_entry_t* page_tables[PAGE_DIRECTORY_ENTRIES];
|
||||
|
||||
extern void _enable_paging_asm(void);
|
||||
|
||||
void paging_init(void)
|
||||
{
|
||||
/* Allocate and clear the page directory */
|
||||
page_directory = (page_directory_entry_t*)alloc_page();
|
||||
memset(page_directory, 0, PAGE_SIZE);
|
||||
|
||||
/* Allocate and set up the first identity-mapped page table (0-4MB) */
|
||||
page_tables[0] = (page_table_entry_t*)alloc_page();
|
||||
memset(page_tables[0], 0, PAGE_SIZE);
|
||||
for (uint32_t i = 0; i < PAGE_TABLE_ENTRIES; i++)
|
||||
{
|
||||
page_tables[0][i] = (i * PAGE_SIZE) | 3; /* Present | RW */
|
||||
}
|
||||
page_directory[0] = ((uint32_t)page_tables[0]) | 3;
|
||||
|
||||
/* Allocate and clear the heap page table */
|
||||
uint32_t heap_pd_index = HEAP_START >> 22; /* 0xC0000000 >> 22 = 768 */
|
||||
page_tables[heap_pd_index] = (page_table_entry_t*)alloc_page();
|
||||
memset(page_tables[heap_pd_index], 0, PAGE_SIZE);
|
||||
|
||||
/* Map 4MB heap pages */
|
||||
for (uint32_t i = 0; i < PAGE_TABLE_ENTRIES; i++) /* 1024 pages = 4MB */
|
||||
{
|
||||
void* phys = alloc_page();
|
||||
if (phys == 0)
|
||||
{
|
||||
printf("Out of physical memory during heap mapping!\n");
|
||||
while (1);
|
||||
}
|
||||
page_tables[heap_pd_index][i] = ((uint32_t)phys & 0xFFFFF000) | 3; /* Present | RW */
|
||||
}
|
||||
page_directory[heap_pd_index] = ((uint32_t)page_tables[heap_pd_index]) | 3;
|
||||
|
||||
/* Load page directory */
|
||||
asm volatile ("mov %0, %%cr3" : : "r"(page_directory));
|
||||
|
||||
/* Enable paging */
|
||||
_enable_paging_asm();
|
||||
}
|
||||
static uint32_t* page_directory;
|
||||
|
||||
void map_page(void* phys_addr, void* virt_addr)
|
||||
{
|
||||
uint32_t pd_index = ((uint32_t)virt_addr >> 22) & 0x3FF;
|
||||
uint32_t pt_index = ((uint32_t)virt_addr >> 12) & 0x3FF;
|
||||
uint32_t pd_idx = ((uint32_t)virt_addr >> 22) & 0x3FF;
|
||||
uint32_t pt_idx = ((uint32_t)virt_addr >> 12) & 0x3FF;
|
||||
|
||||
/* Allocate page table if necessary */
|
||||
if (!(page_directory[pd_index] & 1))
|
||||
uint32_t* page_table;
|
||||
|
||||
if (!(page_directory[pd_idx] & PAGE_PRESENT))
|
||||
{
|
||||
void* pt_phys = alloc_page();
|
||||
page_tables[pd_index] = (page_table_entry_t*)((uint32_t)pt_phys + 0xC0000000); /* Map it higher */
|
||||
|
||||
memset(page_tables[pd_index], 0, PAGE_SIZE);
|
||||
|
||||
page_directory[pd_index] = ((uint32_t)pt_phys) | 0x3; /* Present, R/W */
|
||||
page_table = (uint32_t*) pmm_alloc_page();
|
||||
MEMSET(page_table, 0, PAGE_SIZE);
|
||||
page_directory[pd_idx] = ((uint32_t)page_table) | PAGE_PRESENT | PAGE_WRITE;
|
||||
}
|
||||
else
|
||||
{
|
||||
page_table = (uint32_t*)(page_directory[pd_idx] & ~0xFFF);
|
||||
}
|
||||
|
||||
page_table_entry_t* page_table = (page_table_entry_t*)((page_directory[pd_index] & 0xFFFFF000) + 0xC0000000);
|
||||
page_table[pt_index] = ((uint32_t)phys_addr & 0xFFFFF000) | 0x3; /* Present, R/W */
|
||||
|
||||
asm volatile ("invlpg (%0)" :: "r" (virt_addr) : "memory");
|
||||
page_table[pt_idx] = ((uint32_t)phys_addr) | PAGE_PRESENT | PAGE_WRITE;
|
||||
}
|
||||
|
||||
void paging_init(void)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
printf("[ PAGING ] Initializing paging...\n");
|
||||
#endif
|
||||
|
||||
page_directory = (uint32_t*)pmm_alloc_page();
|
||||
|
||||
MEMSET(page_directory, 0, PAGE_SIZE);
|
||||
|
||||
for (uint32_t addr = 0; addr < 0x800000; addr += PAGE_SIZE)
|
||||
{
|
||||
map_page((void*) addr, (void*) addr); /* identity map first 8MB */
|
||||
}
|
||||
|
||||
asm volatile("mov %0, %%cr3" :: "r"(page_directory));
|
||||
uint32_t cr0;
|
||||
asm volatile("mov %%cr0, %0" : "=r"(cr0));
|
||||
cr0 |= 0x80000000;
|
||||
asm volatile("mov %0, %%cr0" :: "r"(cr0));
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("[ PAGING ] Paging initialized\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
122
lib/mm/pmm.c
122
lib/mm/pmm.c
@ -1,80 +1,100 @@
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <mm/pmm.h>
|
||||
|
||||
#define PAGE_SIZE 4096
|
||||
#define BITMAP_SIZE (1024 * 1024) /* Supports up to 4GB RAM (1 bit per page) */
|
||||
|
||||
static uint8_t bitmap[BITMAP_SIZE / 8];
|
||||
static uint32_t total_pages;
|
||||
static uint32_t used_pages = 0;
|
||||
#define MAX_PAGES (1024 * 1024) /* 4GB / 4KB */
|
||||
static uint8_t bitmap[MAX_PAGES / 8] __attribute__((section(".pmm_bitmap")));
|
||||
static size_t total_pages;
|
||||
|
||||
static inline void set_bit(uint32_t idx)
|
||||
#define BITMAP_SET(i) (bitmap[(i) / 8] |= (1 << ((i) % 8)))
|
||||
#define BITMAP_CLEAR(i) (bitmap[(i) / 8] &= ~(1 << ((i) % 8)))
|
||||
#define BITMAP_TEST(i) (bitmap[(i) / 8] & (1 << ((i) % 8)))
|
||||
|
||||
|
||||
extern uint32_t __kernel_start;
|
||||
extern uint32_t __kernel_end;
|
||||
|
||||
void pmm_init(multiboot_info_t* mb)
|
||||
{
|
||||
bitmap[idx / 8] |= (1 << (idx % 8));
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
printf("[ PMM ] Initializing physical memory manager...\n");
|
||||
#endif
|
||||
|
||||
static inline void clear_bit(uint32_t idx)
|
||||
{
|
||||
bitmap[idx / 8] &= ~(1 << (idx % 8));
|
||||
}
|
||||
|
||||
static inline int test_bit(uint32_t idx)
|
||||
{
|
||||
return (bitmap[idx / 8] >> (idx % 8)) & 1;
|
||||
}
|
||||
|
||||
void pmm_init(multiboot_info_t* mb_info)
|
||||
{
|
||||
total_pages = 0x100000; /* 4GB / 4KB = 1M pages */
|
||||
for (uint32_t i = 0; i < total_pages / 8; i++)
|
||||
total_pages = MAX_PAGES;
|
||||
|
||||
for (uint32_t i = 0; i < (total_pages / 8); i++)
|
||||
{
|
||||
bitmap[i] = 0xFF; /* Mark all as used */
|
||||
bitmap[i] = 0xFF;
|
||||
}
|
||||
|
||||
multiboot_memory_map_t* mmap = (multiboot_memory_map_t*) mb_info->mmap_addr;
|
||||
while ((uint32_t)mmap < mb_info->mmap_addr + mb_info->mmap_length)
|
||||
multiboot_memory_map_t* mmap = (void*)(uintptr_t)mb->mmap_addr;
|
||||
size_t entries = mb->mmap_length / sizeof(multiboot_memory_map_t);
|
||||
|
||||
for (size_t i = 0; i < entries; i++)
|
||||
{
|
||||
if (mmap->type == 1) /* Usable */
|
||||
if (mmap[i].type == 1) /* usable */
|
||||
{
|
||||
uint64_t base = mmap->addr;
|
||||
uint64_t len = mmap->len;
|
||||
for (uint64_t addr = base; addr < base + len; addr += PAGE_SIZE)
|
||||
uint64_t start = mmap[i].addr;
|
||||
uint64_t end = start + mmap[i].len;
|
||||
for (uint64_t addr = start; addr < end; addr += 0x1000)
|
||||
{
|
||||
if (addr >= 0x210000) /* Skip first 2.1MB, or ≈ 2.06MiB */
|
||||
if (addr >= 0x100000) /* skip below 1MB */
|
||||
{
|
||||
uint32_t idx = addr / PAGE_SIZE;
|
||||
|
||||
if (idx >= total_pages)
|
||||
{
|
||||
continue; /* skip entries above 4GB */
|
||||
}
|
||||
|
||||
clear_bit(idx);
|
||||
used_pages--;
|
||||
size_t idx = addr / 0x1000;
|
||||
BITMAP_CLEAR(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
mmap = (multiboot_memory_map_t*)((uint32_t)mmap + mmap->size + sizeof(mmap->size));
|
||||
}
|
||||
total_pages = MAX_PAGES;
|
||||
|
||||
uintptr_t start = (uintptr_t)&__kernel_start;
|
||||
uintptr_t end = (uintptr_t)&__kernel_end;
|
||||
|
||||
start &= ~0xFFF;
|
||||
end = (end + 0xFFF) & ~0xFFF;
|
||||
|
||||
for (uintptr_t addr = start; addr < end; addr += 0x1000)
|
||||
{
|
||||
size_t idx = addr / 0x1000;
|
||||
BITMAP_SET(idx); // Mark kernel pages as USED
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("[ PMM ] Physical memory manager initialized\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void* alloc_page(void) {
|
||||
for (uint32_t i = 0; i < total_pages; i++)
|
||||
void* pmm_alloc_page(void)
|
||||
{
|
||||
for (uint32_t i = 0; i < total_pages; ++i)
|
||||
{
|
||||
if (!test_bit(i))
|
||||
void* page = (void*)(i * 4096);
|
||||
|
||||
if ((uintptr_t)page >= (uintptr_t)&__kernel_start &&
|
||||
(uintptr_t)page < (uintptr_t)&__kernel_end)
|
||||
{
|
||||
set_bit(i);
|
||||
used_pages++;
|
||||
return (void*)(i * PAGE_SIZE);
|
||||
printf("PMM allocating inside kernel at %x\n", page);
|
||||
}
|
||||
|
||||
if (!BITMAP_TEST(i))
|
||||
{
|
||||
BITMAP_SET(i);
|
||||
return (void*)(i * 4096);
|
||||
}
|
||||
}
|
||||
return NULL; /* Out of memory */
|
||||
|
||||
printf("pmm_alloc_page(): No free page found!\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void free_page(void* ptr)
|
||||
|
||||
void pmm_free_page(void* addr)
|
||||
{
|
||||
uint32_t idx = (uint32_t)ptr / PAGE_SIZE;
|
||||
clear_bit(idx);
|
||||
size_t idx = (uintptr_t)addr / 0x1000;
|
||||
BITMAP_CLEAR(idx);
|
||||
}
|
||||
|
||||
|
||||
507
lib/printf.c
507
lib/printf.c
@ -2,219 +2,424 @@
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <drivers/serio.h>
|
||||
|
||||
#include <tty.h>
|
||||
|
||||
#include <printf.h>
|
||||
|
||||
static uint8_t color = 0xFF;
|
||||
|
||||
void printwc(const char* str, uint8_t color)
|
||||
{
|
||||
uint8_t c = terminal_getcolor();
|
||||
|
||||
terminal_setcolor(color);
|
||||
|
||||
printf(str);
|
||||
|
||||
terminal_setcolor(c);
|
||||
}
|
||||
|
||||
void printd(const char* str)
|
||||
{
|
||||
terminal_debug_writestring(str);
|
||||
|
||||
serial_puts("[ DEBUG ] ");
|
||||
serial_puts(str);
|
||||
}
|
||||
|
||||
void printdc(const char* str, uint8_t color)
|
||||
{
|
||||
uint8_t c = terminal_getcolor();
|
||||
terminal_setcolor(color);
|
||||
|
||||
printd(str);
|
||||
|
||||
terminal_setcolor(c);
|
||||
}
|
||||
|
||||
void printf_set_color(uint8_t _color)
|
||||
{
|
||||
if (_color == 0xFF)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
color = _color;
|
||||
}
|
||||
|
||||
void printf(const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
if (color != 0xFF)
|
||||
{
|
||||
terminal_setcolor(color);
|
||||
}
|
||||
|
||||
for (size_t i = 0; format[i] != '\0'; ++i) {
|
||||
if (format[i] == '%' && format[i + 1] != '\0') {
|
||||
++i;
|
||||
for (size_t i = 0; format[i] != '\0'; ++i)
|
||||
{
|
||||
if (format[i] == '%' && format[i + 1] != '\0')
|
||||
{
|
||||
++i;
|
||||
|
||||
// Check for width (like %016llx)
|
||||
int width = 0;
|
||||
if (format[i] == '0') {
|
||||
++i;
|
||||
while (format[i] >= '0' && format[i] <= '9') {
|
||||
width = width * 10 + (format[i] - '0');
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for 'll' prefix
|
||||
bool is_ll = false;
|
||||
if (format[i] == 'l' && format[i + 1] == 'l') {
|
||||
is_ll = true;
|
||||
i += 2;
|
||||
}
|
||||
|
||||
switch (format[i]) {
|
||||
case 's': {
|
||||
const char* str = va_arg(args, const char*);
|
||||
terminal_writestring(str ? str : "(null)");
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
char c = (char) va_arg(args, int);
|
||||
terminal_putchar(c);
|
||||
break;
|
||||
}
|
||||
case 'd':
|
||||
case 'i': {
|
||||
int32_t val = va_arg(args, int32_t);
|
||||
print_int(val);
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
uint32_t val = va_arg(args, uint32_t);
|
||||
print_uint(val);
|
||||
break;
|
||||
}
|
||||
case 'x': {
|
||||
if (is_ll) {
|
||||
uint64_t val = va_arg(args, uint64_t);
|
||||
print_hex64(val, width ? width : 16, false);
|
||||
} else {
|
||||
uint32_t val = va_arg(args, uint32_t);
|
||||
print_hex(val, width ? width : 8, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'X': {
|
||||
if (is_ll) {
|
||||
uint64_t val = va_arg(args, uint64_t);
|
||||
print_hex64(val, width ? width : 16, true);
|
||||
} else {
|
||||
uint32_t val = va_arg(args, uint32_t);
|
||||
print_hex(val, width ? width : 8, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'p': {
|
||||
void* ptr = va_arg(args, void*);
|
||||
terminal_writestring("0x");
|
||||
print_hex((uint32_t)(uintptr_t)ptr, 8, true); // assumes 32-bit pointer
|
||||
break;
|
||||
}
|
||||
case 'f':
|
||||
case 'F': {
|
||||
double val = va_arg(args, double);
|
||||
print_double(val, 2);
|
||||
break;
|
||||
}
|
||||
case '%': {
|
||||
terminal_putchar('%');
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
terminal_putchar('%');
|
||||
terminal_putchar(format[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
terminal_putchar(format[i]);
|
||||
int width = 0;
|
||||
if (format[i] == '0')
|
||||
{
|
||||
++i;
|
||||
while (format[i] >= '0' && format[i] <= '9')
|
||||
{
|
||||
width = width * 10 + (format[i] - '0');
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
bool is_ll = false;
|
||||
if (format[i] == 'l' && format[i + 1] == 'l')
|
||||
{
|
||||
is_ll = true;
|
||||
i += 2;
|
||||
}
|
||||
|
||||
switch (format[i])
|
||||
{
|
||||
case 's': {
|
||||
const char* str = va_arg(args, const char*);
|
||||
|
||||
terminal_writestring(str ? str : "(null)");
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_puts(str ? str : "(null)");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
char c = (char) va_arg(args, int);
|
||||
terminal_putchar(c);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write(c);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 'd':
|
||||
case 'i': {
|
||||
if (is_ll)
|
||||
{
|
||||
int64_t val = va_arg(args, int64_t);
|
||||
print_lint(val);
|
||||
}
|
||||
else
|
||||
{
|
||||
int32_t val = va_arg(args, int32_t);
|
||||
print_int(val);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
if (is_ll)
|
||||
{
|
||||
uint64_t val = va_arg(args, uint64_t);
|
||||
print_luint(val);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t val = va_arg(args, uint32_t);
|
||||
print_uint(val);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 'x': {
|
||||
if (is_ll)
|
||||
{
|
||||
uint64_t val = va_arg(args, uint64_t);
|
||||
print_hex64(val, width ? width : 16, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t val = va_arg(args, uint32_t);
|
||||
print_hex(val, width ? width : 8, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'X': {
|
||||
if (is_ll)
|
||||
{
|
||||
uint64_t val = va_arg(args, uint64_t);
|
||||
print_hex64(val, width ? width : 16, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t val = va_arg(args, uint32_t);
|
||||
print_hex(val, width ? width : 8, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'p': {
|
||||
void* ptr = va_arg(args, void*);
|
||||
terminal_writestring("0x");
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write('0');
|
||||
serial_write('x');
|
||||
}
|
||||
|
||||
print_hex((uint32_t)(uintptr_t)ptr, 8, true);
|
||||
|
||||
break;
|
||||
}
|
||||
case 'f':
|
||||
case 'F': {
|
||||
double val = va_arg(args, double);
|
||||
print_double(val, 2);
|
||||
break;
|
||||
}
|
||||
case '%': {
|
||||
terminal_putchar('%');
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write('%');
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
terminal_putchar('%');
|
||||
terminal_putchar(format[i]);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write('%');
|
||||
serial_write(format[i]);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
terminal_putchar(format[i]);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write(format[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
void print_int(int32_t value) {
|
||||
char buffer[12]; // Enough for 32-bit signed int (-2147483648)
|
||||
int i = 0;
|
||||
uint32_t u;
|
||||
void print_int(int32_t value)
|
||||
{
|
||||
char buffer[12];
|
||||
int i = 0;
|
||||
uint32_t u;
|
||||
|
||||
if (value < 0) {
|
||||
terminal_putchar('-');
|
||||
u = (uint32_t)(-value);
|
||||
} else {
|
||||
u = (uint32_t)value;
|
||||
if (value < 0)
|
||||
{
|
||||
terminal_putchar('-');
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write('-');
|
||||
}
|
||||
|
||||
u = (uint32_t)(-value);
|
||||
}
|
||||
else
|
||||
{
|
||||
u = (uint32_t)value;
|
||||
}
|
||||
|
||||
// Convert to string in reverse
|
||||
do {
|
||||
buffer[i++] = '0' + (u % 10);
|
||||
u /= 10;
|
||||
} while (u > 0);
|
||||
do
|
||||
{
|
||||
buffer[i++] = '0' + (u % 10);
|
||||
u /= 10;
|
||||
} while (u > 0);
|
||||
|
||||
// Print in correct order
|
||||
while (i--) {
|
||||
terminal_putchar(buffer[i]);
|
||||
while (i--)
|
||||
{
|
||||
terminal_putchar(buffer[i]);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write(buffer[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_lint(int64_t value)
|
||||
{
|
||||
char buffer[21];
|
||||
int i = 0;
|
||||
uint64_t u;
|
||||
|
||||
if (value < 0)
|
||||
{
|
||||
terminal_putchar('-');
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write('-');
|
||||
}
|
||||
|
||||
u = (uint64_t) (-value);
|
||||
}
|
||||
else
|
||||
{
|
||||
u = (uint64_t) value;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
buffer[i++] = '0' + (u % 10);
|
||||
u /= 10;
|
||||
} while (u > 0);
|
||||
|
||||
while (i--)
|
||||
{
|
||||
terminal_putchar(buffer[i]);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write(buffer[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_hex(uint32_t value, int width, bool uppercase)
|
||||
{
|
||||
const char* hex_chars = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
|
||||
char buffer[9]; // 8 hex digits max for 32-bit
|
||||
int i = 0;
|
||||
const char* hex_chars = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
|
||||
char buffer[9]; /* 8 hex digits max for 32-bit */
|
||||
int i = 0;
|
||||
|
||||
do {
|
||||
buffer[i++] = hex_chars[value & 0xF];
|
||||
value >>= 4;
|
||||
} while (value || i < width); // ensure at least 'width' digits
|
||||
do
|
||||
{
|
||||
buffer[i++] = hex_chars[value & 0xF];
|
||||
value >>= 4;
|
||||
} while (value || i < width); /* ensure at least 'width' digits */
|
||||
|
||||
while (i--) {
|
||||
terminal_putchar(buffer[i]);
|
||||
while (i--)
|
||||
{
|
||||
terminal_putchar(buffer[i]);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write(buffer[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_double(double value, int precision)
|
||||
{
|
||||
// Handle the integer part
|
||||
int32_t integer_part = (int32_t)value;
|
||||
double fractional_part = value - integer_part;
|
||||
// Handle the integer part
|
||||
int32_t integer_part = (int32_t)value;
|
||||
double fractional_part = value - integer_part;
|
||||
|
||||
// Print the integer part
|
||||
print_int(integer_part);
|
||||
// Print the integer part
|
||||
print_int(integer_part);
|
||||
|
||||
// Print the decimal point
|
||||
terminal_putchar('.');
|
||||
// Print the decimal point
|
||||
terminal_putchar('.');
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write('.');
|
||||
}
|
||||
|
||||
// Print the fractional part (scaled up)
|
||||
fractional_part *= 1;
|
||||
for (int i = 0; i < precision; i++) {
|
||||
fractional_part *= 10;
|
||||
// Print the fractional part (scaled up)
|
||||
fractional_part *= 1;
|
||||
for (int i = 0; i < precision; i++)
|
||||
{
|
||||
fractional_part *= 10;
|
||||
}
|
||||
|
||||
int32_t frac_int = (int32_t)fractional_part;
|
||||
print_int(frac_int);
|
||||
}
|
||||
|
||||
void print_uint(uint32_t value)
|
||||
{
|
||||
char buffer[11];
|
||||
int i = 0;
|
||||
|
||||
do
|
||||
{
|
||||
buffer[i++] = '0' + (value % 10);
|
||||
value /= 10;
|
||||
} while (value > 0);
|
||||
|
||||
while (i--)
|
||||
{
|
||||
terminal_putchar(buffer[i]);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write(buffer[i]);
|
||||
}
|
||||
|
||||
int32_t frac_int = (int32_t)fractional_part;
|
||||
print_int(frac_int);
|
||||
}
|
||||
}
|
||||
|
||||
void print_uint(uint32_t value) {
|
||||
char buffer[11]; // Enough for 32-bit unsigned int
|
||||
int i = 0;
|
||||
void print_luint(uint64_t value)
|
||||
{
|
||||
char buffer[21];
|
||||
int i = 0;
|
||||
|
||||
do {
|
||||
buffer[i++] = '0' + (value % 10);
|
||||
value /= 10;
|
||||
} while (value > 0);
|
||||
do
|
||||
{
|
||||
buffer[i++] = '0' + (value % 10);
|
||||
value /= 10;
|
||||
} while (value > 0);
|
||||
|
||||
while (i--) {
|
||||
terminal_putchar(buffer[i]);
|
||||
while (i--)
|
||||
{
|
||||
terminal_putchar(buffer[i]);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write(buffer[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_hex64(uint64_t value, int width, bool uppercase) {
|
||||
char buffer[17] = {0};
|
||||
const char* digits = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
|
||||
int i = 0;
|
||||
void print_hex64(uint64_t value, int width, bool uppercase)
|
||||
{
|
||||
char buffer[17] = {0};
|
||||
const char* digits = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
|
||||
int i = 0;
|
||||
|
||||
do {
|
||||
buffer[i++] = digits[value % 16];
|
||||
value /= 16;
|
||||
} while (value > 0);
|
||||
do
|
||||
{
|
||||
buffer[i++] = digits[value % 16];
|
||||
value /= 16;
|
||||
} while (value > 0);
|
||||
|
||||
while (i < width)
|
||||
buffer[i++] = '0';
|
||||
while (i < width)
|
||||
{
|
||||
buffer[i++] = '0';
|
||||
}
|
||||
|
||||
while (i--)
|
||||
terminal_putchar(buffer[i]);
|
||||
while (i--)
|
||||
{
|
||||
terminal_putchar(buffer[i]);
|
||||
|
||||
if (use_serial())
|
||||
{
|
||||
serial_write(buffer[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
114
lib/stdio.c
114
lib/stdio.c
@ -1,18 +1,58 @@
|
||||
#include <types.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <drivers/ps2_keyboard.h>
|
||||
#include <fs/vfs.h>
|
||||
#include <kernel/syscall.h>
|
||||
#include <tty.h>
|
||||
|
||||
#include <new_tty.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int write(uint32_t fd, void* data, size_t len)
|
||||
{
|
||||
if (fd == STDOUT)
|
||||
{
|
||||
/*print_uint((uint32_t) len);*/
|
||||
terminal_write((char*) data, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int read(uint32_t fd, void* data, size_t max_len)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
if (fd == STDIN)
|
||||
{
|
||||
char* rd = gets_new(&rv);
|
||||
size_t sz = strlen(rd);
|
||||
memcpy(data, rd, (sz < max_len) ? sz : max_len);
|
||||
|
||||
if (!rd)
|
||||
{
|
||||
printf("rd is NULL!\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
extern bool ps2keyboard_initialized;
|
||||
|
||||
char getchar(void)
|
||||
{
|
||||
if (ps2keyboard_initialized)
|
||||
{
|
||||
return get_char();
|
||||
}
|
||||
|
||||
return '\0';
|
||||
return tty_get_char();
|
||||
}
|
||||
|
||||
char* getstring(void)
|
||||
@ -25,38 +65,40 @@ char* getstring(void)
|
||||
return "HELLO\0";
|
||||
}
|
||||
|
||||
/*char* fgets(char* buf, int n, FILE file)
|
||||
char* gets(void)
|
||||
{
|
||||
if (!buf || n <= 1 || file < 1)
|
||||
return kbd_gets();
|
||||
}
|
||||
|
||||
char* gets_new(int* num)
|
||||
{
|
||||
char* __s = malloc(256);
|
||||
|
||||
memset(__s, 0, 256);
|
||||
|
||||
ssize_t n = tty_read_active(__s, 255);
|
||||
|
||||
*num = (int) n;
|
||||
|
||||
return __s;
|
||||
}
|
||||
|
||||
int getstr(char* dest)
|
||||
{
|
||||
int i = 0;
|
||||
char* p = gets_new(&i);
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int total_read = 0;
|
||||
char c;
|
||||
strcpy(dest, p);
|
||||
|
||||
while (total_read < n - 1)
|
||||
{
|
||||
int bytes = 0*//*read_file(file, &c, 1)*/;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*if (bytes <= 0)
|
||||
{
|
||||
break; *//* EOF or error */
|
||||
/*}
|
||||
|
||||
buf[total_read++] = c;
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
break; *//* Stop at newline */
|
||||
/*}
|
||||
}
|
||||
|
||||
if (total_read == 0)
|
||||
{
|
||||
return NULL; *//* Nothing read (e.g. EOF) */
|
||||
/*}
|
||||
|
||||
buf[total_read] = '\0';
|
||||
return buf;
|
||||
}*/
|
||||
void putc(char c)
|
||||
{
|
||||
syscall1(SYS_TERMINAL_PUTCHAR, c);
|
||||
}
|
||||
|
||||
310
lib/string.c
310
lib/string.c
@ -1,11 +1,12 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <vector_extensions/sse.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#ifdef DEBUG_USE_SSE2
|
||||
#include <vector_extensions/sse.h>
|
||||
extern int32_t sse_initialized;
|
||||
#endif
|
||||
|
||||
size_t strlen(const char* str)
|
||||
{
|
||||
@ -77,10 +78,12 @@ char* strcpy(char *dst, const char *src)
|
||||
|
||||
char* strncpy(char *dest, const char *src, uint32_t n)
|
||||
{
|
||||
#ifdef DEBUG_USE_SSE2
|
||||
if (sse_initialized > 0)
|
||||
{
|
||||
return sse2_strncpy(dest, src, n);
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t i = 0;
|
||||
for (; i < n && src[i]; ++i)
|
||||
@ -173,9 +176,9 @@ char* strchr(const char* s, int c)
|
||||
{
|
||||
while (*s)
|
||||
{
|
||||
if (*s == (char)c)
|
||||
if (*s == (char) c)
|
||||
{
|
||||
return (char*)s;
|
||||
return (char*) s;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
@ -183,23 +186,47 @@ char* strchr(const char* s, int c)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void* memset(void *dst, char c, uint32_t n)
|
||||
int num_strchr(const char* s, int c)
|
||||
{
|
||||
char *temp = dst;
|
||||
for (; n != 0; n--)
|
||||
int rv = 0;
|
||||
|
||||
while (*s)
|
||||
{
|
||||
*temp++ = c;
|
||||
if (*s == (char) c)
|
||||
{
|
||||
rv++;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
void* memset(void* dst, int c, size_t n)
|
||||
{
|
||||
/*printf("memset(%p, %d, %u)\n", dst, c, n);*/
|
||||
|
||||
unsigned char* temp = (unsigned char*) dst;
|
||||
unsigned char val = (unsigned char) c;
|
||||
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
temp[i] = val;
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
void* memcpy(void *dst, const void *src, uint32_t n)
|
||||
{
|
||||
#ifdef DEBUG_USE_SSE2
|
||||
if (sse_initialized > 1)
|
||||
{
|
||||
return sse2_memcpy(dst, src, n);
|
||||
}
|
||||
#endif
|
||||
|
||||
char *d = dst;
|
||||
const char *s = src;
|
||||
@ -213,10 +240,10 @@ void* memcpy(void *dst, const void *src, uint32_t n)
|
||||
|
||||
int32_t memcmp(const void *s1, const void *s2, size_t n)
|
||||
{
|
||||
const uint8_t *p1 = (const uint8_t *)s1;
|
||||
const uint8_t *p2 = (const uint8_t *)s2;
|
||||
const uint8_t *p1 = (const uint8_t*) s1;
|
||||
const uint8_t *p2 = (const uint8_t*) s2;
|
||||
|
||||
printf("p1: %i, p2: %i\n", (int32_t)*p1, (int32_t)*p2);
|
||||
/*printf("p1: %i, p2: %i\n", (int32_t)*p1, (int32_t)*p2);*/
|
||||
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
@ -231,14 +258,44 @@ int32_t memcmp(const void *s1, const void *s2, size_t n)
|
||||
|
||||
void* memclr(void* m_start, size_t m_count)
|
||||
{
|
||||
#ifdef DEBUG_USE_SSE2
|
||||
if (sse_initialized > 1)
|
||||
{
|
||||
return memclr_sse2(m_start, m_count);
|
||||
}
|
||||
#endif
|
||||
|
||||
return memset(m_start, '\0', (uint32_t)m_count);
|
||||
}
|
||||
|
||||
void* memmove(void* dest, const void* src, size_t n)
|
||||
{
|
||||
unsigned char* d = (unsigned char*) dest;
|
||||
const unsigned char* s = (const unsigned char*) src;
|
||||
|
||||
if (d == s || n == 0)
|
||||
{
|
||||
return dest;
|
||||
}
|
||||
|
||||
if (d < s)
|
||||
{
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
d[i] = s[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = n; i > 0; i--)
|
||||
{
|
||||
d[i - 1] = s[i - 1];
|
||||
}
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
int32_t isspace(char c)
|
||||
{
|
||||
return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r';
|
||||
@ -281,3 +338,232 @@ char tolower(char c)
|
||||
{
|
||||
return lower(c);
|
||||
}
|
||||
|
||||
int isprint(int c)
|
||||
{
|
||||
return (c >= 32 && c < 127);
|
||||
}
|
||||
|
||||
void lowers(char* str)
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
str[i] = lower(str[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void uppers(char* str)
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
str[i] = upper(str[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int atoi(const char *str)
|
||||
{
|
||||
int res = 0, sign = 1;
|
||||
|
||||
while (*str == ' ' || *str == '\t')
|
||||
{
|
||||
str++;
|
||||
}
|
||||
|
||||
if (*str == '-')
|
||||
{
|
||||
sign = -1; str++;
|
||||
}
|
||||
else if (*str == '+')
|
||||
{
|
||||
str++;
|
||||
}
|
||||
|
||||
while (*str >= '0' && *str <= '9')
|
||||
{
|
||||
res = res * 10 + (*str - '0');
|
||||
str++;
|
||||
}
|
||||
|
||||
return res * sign;
|
||||
}
|
||||
|
||||
long atol(const char *str)
|
||||
{
|
||||
long res = 0;
|
||||
int sign = 1;
|
||||
|
||||
while (*str == ' ' || *str == '\t')
|
||||
{
|
||||
str++;
|
||||
}
|
||||
|
||||
if (*str == '-')
|
||||
{
|
||||
sign = -1; str++;
|
||||
}
|
||||
else if (*str == '+')
|
||||
{
|
||||
str++;
|
||||
}
|
||||
|
||||
while (*str >= '0' && *str <= '9')
|
||||
{
|
||||
res = res * 10 + (*str - '0');
|
||||
str++;
|
||||
}
|
||||
|
||||
return res * sign;
|
||||
}
|
||||
|
||||
double atof(const char *str)
|
||||
{
|
||||
double res = 0.0, frac = 0.0;
|
||||
int sign = 1, frac_div = 1;
|
||||
|
||||
while (*str == ' ' || *str == '\t')
|
||||
{
|
||||
str++;
|
||||
}
|
||||
|
||||
if (*str == '-')
|
||||
{
|
||||
sign = -1; str++;
|
||||
}
|
||||
else if (*str == '+')
|
||||
{
|
||||
str++;
|
||||
}
|
||||
|
||||
while (*str >= '0' && *str <= '9')
|
||||
{
|
||||
res = res * 10 + (*str - '0');
|
||||
str++;
|
||||
}
|
||||
|
||||
if (*str == '.')
|
||||
{
|
||||
str++;
|
||||
|
||||
while (*str >= '0' && *str <= '9')
|
||||
{
|
||||
frac = frac * 10 + (*str - '0');
|
||||
frac_div *= 10;
|
||||
str++;
|
||||
}
|
||||
}
|
||||
|
||||
return sign * (res + frac / frac_div);
|
||||
}
|
||||
|
||||
char* strnlstrip(const char* s)
|
||||
{
|
||||
if (!s)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* new = strdup(s);
|
||||
if (!new)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t len = strlen(new);
|
||||
|
||||
while (len > 0 && (new[len-1] == '\n' || new[len-1] == '\r'))
|
||||
{
|
||||
new[len-1] = '\0';
|
||||
len--;
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
void strlnstripip(char* s)
|
||||
{
|
||||
size_t len = strlen(s);
|
||||
|
||||
if (len > 0 && s[len-1] == '\n')
|
||||
{
|
||||
s[len-1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
char** split(const char* str, char delim)
|
||||
{
|
||||
if (!str)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t count = 1;
|
||||
for (const char* p = str; *p; p++)
|
||||
{
|
||||
if (*p == delim)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
char** result = malloc((count + 1) * sizeof(char*));
|
||||
if (!result)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t idx = 0;
|
||||
const char* start = str;
|
||||
|
||||
for (const char* p = str; ; p++)
|
||||
{
|
||||
if (*p == delim || *p == '\0')
|
||||
{
|
||||
size_t len = p - start;
|
||||
|
||||
char* token = malloc(len + 1);
|
||||
if (!token)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
token[i] = start[i];
|
||||
}
|
||||
|
||||
token[len] = '\0';
|
||||
|
||||
result[idx++] = token;
|
||||
|
||||
start = p + 1;
|
||||
|
||||
if (*p == '\0')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result[idx] = NULL; /* null-terminate the array */
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void free_split(char** parts)
|
||||
{
|
||||
if (!parts)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; parts[i] != NULL; i++)
|
||||
{
|
||||
free(parts[i]);
|
||||
}
|
||||
|
||||
free(parts);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user