mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
FEAT: VFS overhaul
This commit is contained in:
parent
921e8a5658
commit
700839e6be
48 changed files with 1897 additions and 482 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -30,4 +30,4 @@ limine
|
||||||
.DS_Store
|
.DS_Store
|
||||||
/build/
|
/build/
|
||||||
*.o
|
*.o
|
||||||
disk.img
|
disk.img
|
||||||
|
|
|
||||||
286
build.log
Normal file
286
build.log
Normal file
|
|
@ -0,0 +1,286 @@
|
||||||
|
mkdir -p build
|
||||||
|
mkdir -p build
|
||||||
|
nasm -f elf64 src/arch/boot.asm -o build/boot.o
|
||||||
|
nasm -f elf64 src/arch/gdt_asm.asm -o build/gdt_asm.o
|
||||||
|
nasm -f elf64 src/arch/interrupts.asm -o build/interrupts.o
|
||||||
|
nasm -f elf64 src/arch/process_asm.asm -o build/process_asm.o
|
||||||
|
nasm -f elf64 src/arch/syscalls.asm -o build/syscalls.o
|
||||||
|
nasm -f elf64 src/arch/test_syscall.asm -o build/test_syscall.o
|
||||||
|
nasm -f elf64 src/arch/user_test.asm -o build/user_test.o
|
||||||
|
Building Limine host utility...
|
||||||
|
make[1]: Nothing to be done for `all'.
|
||||||
|
mkdir -p build/
|
||||||
|
mkdir -p build/
|
||||||
|
mkdir -p build/
|
||||||
|
mkdir -p build/
|
||||||
|
mkdir -p build/
|
||||||
|
mkdir -p build/
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/core/kutils.c -o build/kutils.o
|
||||||
|
mkdir -p build/
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/core/main.c -o build/main.o
|
||||||
|
mkdir -p build/
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/core/version.c -o build/version.o
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/sys/elf.c -o build/elf.o
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/core/platform.c -o build/platform.o
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/core/panic.c -o build/panic.o
|
||||||
|
mkdir -p build/
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/sys/idt.c -o build/idt.o
|
||||||
|
mkdir -p build/
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/sys/gdt.c -o build/gdt.o
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/sys/kernel_subsystem.c -o build/kernel_subsystem.o
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/sys/lapic.c -o build/lapic.o
|
||||||
|
src/sys/idt.c: In function 'pic_remap':
|
||||||
|
src/sys/idt.c:120:17: warning: variable 'a2' set but not used [-Wunused-but-set-variable]
|
||||||
|
120 | uint8_t a1, a2;
|
||||||
|
| ^~
|
||||||
|
src/sys/idt.c:120:13: warning: variable 'a1' set but not used [-Wunused-but-set-variable]
|
||||||
|
120 | uint8_t a1, a2;
|
||||||
|
| ^~
|
||||||
|
mkdir -p build/
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/sys/module_manager.c -o build/module_manager.o
|
||||||
|
mkdir -p build/
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/sys/process.c -o build/process.o
|
||||||
|
mkdir -p build/
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/sys/smp.c -o build/smp.o
|
||||||
|
mkdir -p build/
|
||||||
|
mkdir -p build/
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/sys/syscall.c -o build/syscall.o
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/sys/sysfs_init.c -o build/sysfs_init.o
|
||||||
|
src/sys/smp.c: In function 'smp_init':
|
||||||
|
src/sys/smp.c:171:14: warning: variable 'bsp_index' set but not used [-Wunused-but-set-variable]
|
||||||
|
171 | uint32_t bsp_index = 0;
|
||||||
|
| ^~~~~~~~~
|
||||||
|
mkdir -p build/
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/sys/work_queue.c -o build/work_queue.o
|
||||||
|
mkdir -p build/
|
||||||
|
src/sys/sysfs_init.c:11:13: warning: 'sys_itoa' defined but not used [-Wunused-function]
|
||||||
|
11 | static void sys_itoa(int n, char *s) {
|
||||||
|
| ^~~~~~~~
|
||||||
|
mkdir -p build/
|
||||||
|
src/sys/syscall.c: In function 'syscall_handler_inner':
|
||||||
|
src/sys/syscall.c:493:28: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
|
||||||
|
493 | float scale = *(float*)&scale_bits;
|
||||||
|
| ^~~~~~~~~~~~~~~~~~~
|
||||||
|
src/sys/syscall.c:561:28: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
|
||||||
|
561 | float scale = *(float*)&scale_bits;
|
||||||
|
| ^~~~~~~~~~~~~~~~~~~
|
||||||
|
src/sys/syscall.c:569:28: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
|
||||||
|
569 | float slope = *(float*)&slope_bits;
|
||||||
|
| ^~~~~~~~~~~~~~~~~~~
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/mem/memory_manager.c -o build/memory_manager.o
|
||||||
|
src/sys/syscall.c:695:21: warning: unused variable 'win' [-Wunused-variable]
|
||||||
|
695 | Window *win = (Window *)arg2;
|
||||||
|
| ^~~
|
||||||
|
src/sys/syscall.c:725:28: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
|
||||||
|
725 | float scale = *(float*)&scale_bits;
|
||||||
|
| ^~~~~~~~~~~~~~~~~~~
|
||||||
|
src/sys/syscall.c:762:28: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
|
||||||
|
762 | float scale = *(float*)&scale_bits;
|
||||||
|
| ^~~~~~~~~~~~~~~~~~~
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/mem/paging.c -o build/paging.o
|
||||||
|
mkdir -p build/
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/mem/vm.c -o build/vm.o
|
||||||
|
mkdir -p build/
|
||||||
|
mkdir -p build/
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/dev/disk_manager.c -o build/disk_manager.o
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/dev/ahci.c -o build/ahci.o
|
||||||
|
mkdir -p build/
|
||||||
|
mkdir -p build/
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/dev/pci.c -o build/pci.o
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/dev/ps2.c -o build/ps2.o
|
||||||
|
src/dev/pci.c: In function 'pci_enumerate_devices':
|
||||||
|
src/dev/pci.c:52:31: warning: comparison is always true due to limited range of data type [-Wtype-limits]
|
||||||
|
52 | for (uint8_t bus = 0; bus < 256 && count < max_devices; bus++) {
|
||||||
|
| ^
|
||||||
|
mkdir -p build/
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/dev/rtc.c -o build/rtc.o
|
||||||
|
src/dev/rtc.c: In function 'rtc_get_datetime':
|
||||||
|
src/dev/rtc.c:28:13: warning: unused variable 'last_century' [-Wunused-variable]
|
||||||
|
28 | uint8_t last_century;
|
||||||
|
| ^~~~~~~~~~~~
|
||||||
|
src/dev/rtc.c:21:13: warning: unused variable 'century' [-Wunused-variable]
|
||||||
|
21 | uint8_t century;
|
||||||
|
| ^~~~~~~
|
||||||
|
mkdir -p build/
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/net/lwip_port.c -o build/lwip_port.o
|
||||||
|
mkdir -p build/
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/net/network.c -o build/network.o
|
||||||
|
mkdir -p build/
|
||||||
|
mkdir -p build/
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/net/nic/e1000.c -o build/e1000.o
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/net/nic/nic.c -o build/nic.o
|
||||||
|
src/net/network.c: In function 'network_dhcp_acquire':
|
||||||
|
src/net/network.c:186:9: warning: unused variable 'loops' [-Wunused-variable]
|
||||||
|
186 | int loops = 0;
|
||||||
|
| ^~~~~
|
||||||
|
mkdir -p build/
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/net/nic/nic_netif.c -o build/nic_netif.o
|
||||||
|
mkdir -p build/
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/net/nic/rtl8111.c -o build/rtl8111.o
|
||||||
|
mkdir -p build/
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/net/nic/rtl8139.c -o build/rtl8139.o
|
||||||
|
mkdir -p build/
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/net/nic/virtio_net.c -o build/virtio_net.o
|
||||||
|
mkdir -p build/
|
||||||
|
src/net/network.c: In function 'network_init':
|
||||||
|
src/net/network.c:93:9: warning: 'ip.bytes[0]' may be used uninitialized [-Wmaybe-uninitialized]
|
||||||
|
93 | k_itoa(ip.bytes[0], buf); serial_write(buf); serial_write(".");
|
||||||
|
| ^~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
src/net/network.c:88:24: note: 'ip.bytes[0]' was declared here
|
||||||
|
88 | ipv4_address_t ip;
|
||||||
|
| ^~
|
||||||
|
src/net/network.c:94:9: warning: 'ip.bytes[1]' may be used uninitialized [-Wmaybe-uninitialized]
|
||||||
|
94 | k_itoa(ip.bytes[1], buf); serial_write(buf); serial_write(".");
|
||||||
|
| ^~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
src/net/network.c:88:24: note: 'ip.bytes[1]' was declared here
|
||||||
|
88 | ipv4_address_t ip;
|
||||||
|
| ^~
|
||||||
|
src/net/network.c:95:9: warning: 'ip.bytes[2]' may be used uninitialized [-Wmaybe-uninitialized]
|
||||||
|
95 | k_itoa(ip.bytes[2], buf); serial_write(buf); serial_write(".");
|
||||||
|
| ^~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
src/net/network.c:88:24: note: 'ip.bytes[2]' was declared here
|
||||||
|
88 | ipv4_address_t ip;
|
||||||
|
| ^~
|
||||||
|
src/net/network.c:96:9: warning: 'ip.bytes[3]' may be used uninitialized [-Wmaybe-uninitialized]
|
||||||
|
96 | k_itoa(ip.bytes[3], buf); serial_write(buf); serial_write("\n");
|
||||||
|
| ^~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
src/net/network.c:88:24: note: 'ip.bytes[3]' was declared here
|
||||||
|
88 | ipv4_address_t ip;
|
||||||
|
| ^~
|
||||||
|
src/net/nic/rtl8111.c: In function 'rtl8111_init':
|
||||||
|
src/net/nic/rtl8111.c:67:14: warning: unused variable 'bar2' [-Wunused-variable]
|
||||||
|
67 | uint32_t bar2 = pci_read_config(pci_dev->bus, pci_dev->device, pci_dev->function, 0x18);
|
||||||
|
| ^~~~
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/fs/fat32.c -o build/fat32.o
|
||||||
|
mkdir -p build/
|
||||||
|
mkdir -p build/
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/fs/procfs.c -o build/procfs.o
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/fs/sysfs.c -o build/sysfs.o
|
||||||
|
src/fs/fat32.c: In function 'realfs_delete_from_vol':
|
||||||
|
src/fs/fat32.c:1110:14: warning: variable 'entry_offset' set but not used [-Wunused-but-set-variable]
|
||||||
|
1110 | uint32_t entry_offset = 0;
|
||||||
|
| ^~~~~~~~~~~~
|
||||||
|
src/fs/fat32.c:1109:14: warning: variable 'entry_sector' set but not used [-Wunused-but-set-variable]
|
||||||
|
1109 | uint32_t entry_sector = 0;
|
||||||
|
| ^~~~~~~~~~~~
|
||||||
|
src/fs/sysfs.c: In function 'sysfs_open':
|
||||||
|
src/fs/sysfs.c:12:31: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||||
|
12 | static void* sysfs_open(void *fs_private, const char *path, const char *mode) {
|
||||||
|
| ~~~~~~^~~~~~~~~~
|
||||||
|
src/fs/sysfs.c:12:73: warning: unused parameter 'mode' [-Wunused-parameter]
|
||||||
|
12 | static void* sysfs_open(void *fs_private, const char *path, const char *mode) {
|
||||||
|
| ~~~~~~~~~~~~^~~~
|
||||||
|
src/fs/sysfs.c: In function 'sysfs_close':
|
||||||
|
src/fs/sysfs.c:43:31: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||||
|
43 | static void sysfs_close(void *fs_private, void *handle) {
|
||||||
|
| ~~~~~~^~~~~~~~~~
|
||||||
|
src/fs/sysfs.c: In function 'sysfs_read':
|
||||||
|
src/fs/sysfs.c:47:29: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||||
|
47 | static int sysfs_read(void *fs_private, void *handle, void *buf, int size) {
|
||||||
|
| ~~~~~~^~~~~~~~~~
|
||||||
|
src/fs/sysfs.c: In function 'sysfs_write':
|
||||||
|
src/fs/sysfs.c:56:30: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||||
|
56 | static int sysfs_write(void *fs_private, void *handle, const void *buf, int size) {
|
||||||
|
| ~~~~~~^~~~~~~~~~
|
||||||
|
src/fs/sysfs.c: In function 'sysfs_readdir':
|
||||||
|
src/fs/sysfs.c:86:49: warning: comparison of integer expressions of different signedness: 'size_t' {aka 'long unsigned int'} and 'int' [-Wsign-compare]
|
||||||
|
86 | if (path_len == 0 || (k_strlen(s->name) > path_len && k_strncmp(s->name, path, path_len) == 0 && s->name[path_len] == '/')) {
|
||||||
|
| ^
|
||||||
|
src/fs/sysfs.c:65:32: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||||
|
65 | static int sysfs_readdir(void *fs_private, const char *path, vfs_dirent_t *entries, int max) {
|
||||||
|
| ~~~~~~^~~~~~~~~~
|
||||||
|
src/fs/sysfs.c: In function 'sysfs_exists':
|
||||||
|
src/fs/sysfs.c:142:31: warning: comparison of integer expressions of different signedness: 'size_t' {aka 'long unsigned int'} and 'int' [-Wsign-compare]
|
||||||
|
142 | if (k_strlen(s->name) > path_len && k_strncmp(s->name, path, path_len) == 0 && s->name[path_len] == '/') return true;
|
||||||
|
| ^
|
||||||
|
src/fs/sysfs.c:116:32: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||||
|
116 | static bool sysfs_exists(void *fs_private, const char *path) {
|
||||||
|
| ~~~~~~^~~~~~~~~~
|
||||||
|
src/fs/procfs.c: In function 'procfs_open':
|
||||||
|
src/fs/procfs.c:15:25: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||||
|
15 | void* procfs_open(void *fs_private, const char *path, const char *mode) {
|
||||||
|
| ~~~~~~^~~~~~~~~~
|
||||||
|
src/fs/procfs.c:15:67: warning: unused parameter 'mode' [-Wunused-parameter]
|
||||||
|
15 | void* procfs_open(void *fs_private, const char *path, const char *mode) {
|
||||||
|
| ~~~~~~~~~~~~^~~~
|
||||||
|
src/fs/procfs.c: In function 'procfs_close':
|
||||||
|
src/fs/procfs.c:50:25: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||||
|
50 | void procfs_close(void *fs_private, void *handle) {
|
||||||
|
| ~~~~~~^~~~~~~~~~
|
||||||
|
src/fs/procfs.c: In function 'procfs_read':
|
||||||
|
src/fs/procfs.c:54:23: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||||
|
54 | int procfs_read(void *fs_private, void *handle, void *buf, int size) {
|
||||||
|
| ~~~~~~^~~~~~~~~~
|
||||||
|
src/fs/procfs.c: In function 'procfs_write':
|
||||||
|
src/fs/procfs.c:178:24: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||||
|
178 | int procfs_write(void *fs_private, void *handle, const void *buf, int size) {
|
||||||
|
| ~~~~~~^~~~~~~~~~
|
||||||
|
src/fs/procfs.c: In function 'procfs_readdir':
|
||||||
|
src/fs/procfs.c:200:26: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||||
|
200 | int procfs_readdir(void *fs_private, const char *path, vfs_dirent_t *entries, int max) {
|
||||||
|
| ~~~~~~^~~~~~~~~~
|
||||||
|
src/fs/procfs.c: In function 'procfs_exists':
|
||||||
|
src/fs/procfs.c:241:26: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||||
|
241 | bool procfs_exists(void *fs_private, const char *path) {
|
||||||
|
| ~~~~~~^~~~~~~~~~
|
||||||
|
src/fs/procfs.c: In function 'procfs_is_dir':
|
||||||
|
src/fs/procfs.c:264:26: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||||
|
264 | bool procfs_is_dir(void *fs_private, const char *path) {
|
||||||
|
| ~~~~~~^~~~~~~~~~
|
||||||
|
mkdir -p build/
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/fs/tar.c -o build/tar.o
|
||||||
|
mkdir -p build/
|
||||||
|
mkdir -p build/
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/fs/vfs.c -o build/vfs.o
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/wm/cmd.c -o build/cmd.o
|
||||||
|
mkdir -p build/
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/wm/explorer.c -o build/explorer.o
|
||||||
|
src/wm/cmd.c: In function 'internal_cmd_cd':
|
||||||
|
src/wm/cmd.c:1014:13: error: too few arguments to function 'vfs_normalize_path'; expected 3, have 2
|
||||||
|
1014 | vfs_normalize_path(full_path, normalized_path);
|
||||||
|
| ^~~~~~~~~~~~~~~~~~
|
||||||
|
In file included from src/wm/cmd.c:11:
|
||||||
|
src/fs/vfs.h:111:6: note: declared here
|
||||||
|
111 | void vfs_normalize_path(const char *cwd, const char *path, char *normalized);
|
||||||
|
| ^~~~~~~~~~~~~~~~~~
|
||||||
|
mkdir -p build/
|
||||||
|
make: *** [build/cmd.o] Error 1
|
||||||
|
make: *** Waiting for unfinished jobs....
|
||||||
|
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/wm/font_manager.c -o build/font_manager.o
|
||||||
|
src/wm/explorer.c: In function 'explorer_draw_file_icon':
|
||||||
|
src/wm/explorer.c:885:73: warning: unused parameter 'color' [-Wunused-parameter]
|
||||||
|
885 | static void explorer_draw_file_icon(int x, int y, bool is_dir, uint32_t color, const char *filename, const char *current_path) {
|
||||||
|
| ~~~~~~~~~^~~~~
|
||||||
|
src/wm/explorer.c: In function 'explorer_paint':
|
||||||
|
src/wm/explorer.c:922:15: warning: unused variable 'dirty' [-Wunused-variable]
|
||||||
|
922 | DirtyRect dirty = graphics_get_dirty_rect();
|
||||||
|
| ^~~~~
|
||||||
|
In file included from src/wm/font_manager.c:4:
|
||||||
|
src/wm/stb_truetype.h: In function 'stbtt_FreeShape':
|
||||||
|
src/wm/stb_truetype.h:2672:54: warning: unused parameter 'info' [-Wunused-parameter]
|
||||||
|
2672 | STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)
|
||||||
|
| ~~~~~~~~~~~~~~~~~~~~~~^~~~
|
||||||
|
src/wm/stb_truetype.h: In function 'stbtt__hheap_alloc':
|
||||||
|
src/wm/stb_truetype.h:2770:70: warning: unused parameter 'userdata' [-Wunused-parameter]
|
||||||
|
2770 | static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata)
|
||||||
|
| ~~~~~~^~~~~~~~
|
||||||
|
src/wm/stb_truetype.h: In function 'stbtt__hheap_cleanup':
|
||||||
|
src/wm/stb_truetype.h:2797:58: warning: unused parameter 'userdata' [-Wunused-parameter]
|
||||||
|
2797 | static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata)
|
||||||
|
| ~~~~~~^~~~~~~~
|
||||||
|
src/wm/stb_truetype.h: In function 'stbtt_FlattenCurves':
|
||||||
|
src/wm/stb_truetype.h:3618:154: warning: unused parameter 'userdata' [-Wunused-parameter]
|
||||||
|
3618 | static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata)
|
||||||
|
| ~~~~~~^~~~~~~~
|
||||||
|
src/wm/stb_truetype.h: In function 'stbtt_FreeBitmap':
|
||||||
|
src/wm/stb_truetype.h:3708:62: warning: unused parameter 'userdata' [-Wunused-parameter]
|
||||||
|
3708 | STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata)
|
||||||
|
| ~~~~~~^~~~~~~~
|
||||||
|
src/wm/stb_truetype.h: In function 'stbtt_FreeSDF':
|
||||||
|
src/wm/stb_truetype.h:4767:59: warning: unused parameter 'userdata' [-Wunused-parameter]
|
||||||
|
4767 | STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata)
|
||||||
|
| ~~~~~~^~~~~~~~
|
||||||
|
src/wm/font_manager.c: In function 'font_manager_load':
|
||||||
|
src/wm/font_manager.c:112:9: warning: unused variable 'read' [-Wunused-variable]
|
||||||
|
112 | int read = fat32_read(fh, buffer, fsize);
|
||||||
|
| ^~~~
|
||||||
BIN
disk.img
BIN
disk.img
Binary file not shown.
|
|
@ -30,6 +30,16 @@ int k_strcmp(const char *s1, const char *s2) {
|
||||||
return *(const unsigned char*)s1 - *(const unsigned char*)s2;
|
return *(const unsigned char*)s1 - *(const unsigned char*)s2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int k_strncmp(const char *s1, const char *s2, size_t n) {
|
||||||
|
while (n && *s1 && (*s1 == *s2)) {
|
||||||
|
s1++;
|
||||||
|
s2++;
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
if (n == 0) return 0;
|
||||||
|
return *(const unsigned char*)s1 - *(const unsigned char*)s2;
|
||||||
|
}
|
||||||
|
|
||||||
void k_strcpy(char *dest, const char *src) {
|
void k_strcpy(char *dest, const char *src) {
|
||||||
while (*src) *dest++ = *src++;
|
while (*src) *dest++ = *src++;
|
||||||
*dest = 0;
|
*dest = 0;
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ void k_memset(void *dest, int val, size_t len);
|
||||||
void k_memcpy(void *dest, const void *src, size_t len);
|
void k_memcpy(void *dest, const void *src, size_t len);
|
||||||
size_t k_strlen(const char *str);
|
size_t k_strlen(const char *str);
|
||||||
int k_strcmp(const char *s1, const char *s2);
|
int k_strcmp(const char *s1, const char *s2);
|
||||||
|
int k_strncmp(const char *s1, const char *s2, size_t n);
|
||||||
void k_strcpy(char *dest, const char *src);
|
void k_strcpy(char *dest, const char *src);
|
||||||
int k_atoi(const char *str);
|
int k_atoi(const char *str);
|
||||||
void k_itoa(int n, char *buf);
|
void k_itoa(int n, char *buf);
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,12 @@
|
||||||
#include "smp.h"
|
#include "smp.h"
|
||||||
#include "work_queue.h"
|
#include "work_queue.h"
|
||||||
#include "lapic.h"
|
#include "lapic.h"
|
||||||
|
#include "fs/sysfs.h"
|
||||||
|
#include "fs/procfs.h"
|
||||||
|
#include "sys/kernel_subsystem.h"
|
||||||
|
#include "sys/module_manager.h"
|
||||||
|
|
||||||
|
extern void sysfs_init_subsystems(void);
|
||||||
|
|
||||||
// --- Limine Requests ---
|
// --- Limine Requests ---
|
||||||
__attribute__((used, section(".requests")))
|
__attribute__((used, section(".requests")))
|
||||||
|
|
@ -202,6 +208,11 @@ void kmain(void) {
|
||||||
fat32_mkdir("/Library/DOOM");
|
fat32_mkdir("/Library/DOOM");
|
||||||
fat32_mkdir("/docs");
|
fat32_mkdir("/docs");
|
||||||
|
|
||||||
|
// Initialize Virtual Filesystems
|
||||||
|
sysfs_init_subsystems();
|
||||||
|
vfs_mount("/sys", "sysfs", "sysfs", sysfs_get_ops(), NULL);
|
||||||
|
vfs_mount("/proc", "procfs", "procfs", procfs_get_ops(), NULL);
|
||||||
|
|
||||||
if (module_request.response == NULL) {
|
if (module_request.response == NULL) {
|
||||||
serial_write("[DEBUG] ERROR: Limine Module Response is NULL!\n");
|
serial_write("[DEBUG] ERROR: Limine Module Response is NULL!\n");
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -241,6 +252,8 @@ void kmain(void) {
|
||||||
fat32_close(fh);
|
fat32_close(fh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Register all discovered modules in our module manager for /sys/module
|
||||||
|
module_manager_register(clean_path, (uint64_t)mod->address, mod->size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -260,7 +273,7 @@ void kmain(void) {
|
||||||
// Initialize LAPIC for IPI support
|
// Initialize LAPIC for IPI support
|
||||||
lapic_init();
|
lapic_init();
|
||||||
|
|
||||||
// Initialize SMP — bring up all CPU cores
|
// Initialize SMP
|
||||||
if (smp_request.response != NULL) {
|
if (smp_request.response != NULL) {
|
||||||
uint32_t online = smp_init(smp_request.response);
|
uint32_t online = smp_init(smp_request.response);
|
||||||
serial_write("[DEBUG] SMP init complete, CPUs online: ");
|
serial_write("[DEBUG] SMP init complete, CPUs online: ");
|
||||||
|
|
@ -268,7 +281,6 @@ void kmain(void) {
|
||||||
serial_write("\n");
|
serial_write("\n");
|
||||||
} else {
|
} else {
|
||||||
serial_write("[DEBUG] No SMP response from bootloader\n");
|
serial_write("[DEBUG] No SMP response from bootloader\n");
|
||||||
// Still init as single-CPU
|
|
||||||
smp_init(NULL);
|
smp_init(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ static size_t man_strlen(const char *str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_man_file(const char *name, const char *content) {
|
static void write_man_file(const char *name, const char *content) {
|
||||||
char path[128] = "A:/Library/man/";
|
char path[128] = "/Library/man/";
|
||||||
int i = 15;
|
int i = 15;
|
||||||
while (*name) path[i++] = *name++;
|
while (*name) path[i++] = *name++;
|
||||||
path[i++] = '.';
|
path[i++] = '.';
|
||||||
|
|
@ -31,8 +31,8 @@ static void write_man_file(const char *name, const char *content) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void create_man_entries(void) {
|
void create_man_entries(void) {
|
||||||
fat32_mkdir("A:/Library");
|
fat32_mkdir("/Library");
|
||||||
fat32_mkdir("A:/Library/man");
|
fat32_mkdir("/Library/man");
|
||||||
|
|
||||||
write_man_file("ping", "PING - Send ICMP echo requests\n\nUsage: ping <ip>\n\nSends ICMP echo requests to the specified IP address and displays the response times.");
|
write_man_file("ping", "PING - Send ICMP echo requests\n\nUsage: ping <ip>\n\nSends ICMP echo requests to the specified IP address and displays the response times.");
|
||||||
write_man_file("net", "NET - Network utilities\n\nUsage: net init\nnet info\nnet ipset >ip<\nnet udpsend >ip< >port< >message< net ping >ip< net help\n\nA collection of network-related commands.");
|
write_man_file("net", "NET - Network utilities\n\nUsage: net init\nnet info\nnet ipset >ip<\nnet udpsend >ip< >port< >message< net ping >ip< net help\n\nA collection of network-related commands.");
|
||||||
|
|
@ -55,7 +55,7 @@ void create_man_entries(void) {
|
||||||
write_man_file("touch", "TOUCH - Create empty file\n\nUsage: touch <filename>\n\nCreates a new empty file if it doesn't exist.");
|
write_man_file("touch", "TOUCH - Create empty file\n\nUsage: touch <filename>\n\nCreates a new empty file if it doesn't exist.");
|
||||||
write_man_file("cc", "CC - C Compiler\n\nUsage: cc <file.c>\n\nThe BoredOS C Compiler. Compiles C source files into executables. (execute these with ./>file<)");
|
write_man_file("cc", "CC - C Compiler\n\nUsage: cc <file.c>\n\nThe BoredOS C Compiler. Compiles C source files into executables. (execute these with ./>file<)");
|
||||||
write_man_file("crash", "CRASH - Trigger kernel exception\n\nUsage: crash\n\nIntentionally triggers a null pointer dereference to test handlers.");
|
write_man_file("crash", "CRASH - Trigger kernel exception\n\nUsage: crash\n\nIntentionally triggers a null pointer dereference to test handlers.");
|
||||||
write_man_file("sysfetch", "SYSFETCH - Show OS information\n\nUsage: sysfetch\n\nDisplays system information in a neofetch-like layout. Configurable via A:/Library/conf/sysfetch.cfg.");
|
write_man_file("sysfetch", "SYSFETCH - Show OS information\n\nUsage: sysfetch\n\nDisplays system information in a neofetch-like layout. Configurable via /Library/conf/sysfetch.cfg.");
|
||||||
write_man_file("meminfo", "MEMINFO - Memory usage stats\n\nUsage: meminfo\n\nDisplays current physical and virtual memory allocation statistics.");
|
write_man_file("meminfo", "MEMINFO - Memory usage stats\n\nUsage: meminfo\n\nDisplays current physical and virtual memory allocation statistics.");
|
||||||
write_man_file("pci_list", "PCI_LIST - Scan PCI bus\n\nUsage: pci_list\n\nScans the PCI bus and lists all detected hardware devices.");
|
write_man_file("pci_list", "PCI_LIST - Scan PCI bus\n\nUsage: pci_list\n\nScans the PCI bus and lists all detected hardware devices.");
|
||||||
write_man_file("reboot", "REBOOT - Restart system\n\nUsage: reboot\n\nRestarts the computer immediately.");
|
write_man_file("reboot", "REBOOT - Restart system\n\nUsage: reboot\n\nRestarts the computer immediately.");
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "limine.h"
|
#include "limine.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include "platform.h"
|
||||||
static volatile struct limine_hhdm_request hhdm_request __attribute__((used, section(".requests"))) = {
|
static volatile struct limine_hhdm_request hhdm_request __attribute__((used, section(".requests"))) = {
|
||||||
.id = LIMINE_HHDM_REQUEST,
|
.id = LIMINE_HHDM_REQUEST,
|
||||||
.revision = 0,
|
.revision = 0,
|
||||||
|
|
@ -69,3 +70,13 @@ void platform_get_cpu_model(char *model) {
|
||||||
}
|
}
|
||||||
model[48] = '\0';
|
model[48] = '\0';
|
||||||
}
|
}
|
||||||
|
void platform_get_cpu_vendor(char *vendor) {
|
||||||
|
uint32_t eax, ebx, ecx, edx;
|
||||||
|
asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(0));
|
||||||
|
|
||||||
|
char *p = (char *)vendor;
|
||||||
|
*((uint32_t *)&p[0]) = ebx;
|
||||||
|
*((uint32_t *)&p[4]) = edx;
|
||||||
|
*((uint32_t *)&p[8]) = ecx;
|
||||||
|
p[12] = '\0';
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,5 +10,6 @@ void platform_init(void);
|
||||||
uint64_t p2v(uint64_t phys);
|
uint64_t p2v(uint64_t phys);
|
||||||
uint64_t v2p(uint64_t virt);
|
uint64_t v2p(uint64_t virt);
|
||||||
void platform_get_cpu_model(char *model);
|
void platform_get_cpu_model(char *model);
|
||||||
|
void platform_get_cpu_vendor(char *vendor);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,14 @@ extern void serial_print_hex(uint64_t n);
|
||||||
volatile uint64_t kernel_ticks = 0;
|
volatile uint64_t kernel_ticks = 0;
|
||||||
|
|
||||||
uint64_t timer_handler(registers_t *regs) {
|
uint64_t timer_handler(registers_t *regs) {
|
||||||
kernel_ticks++;
|
if (smp_this_cpu_id() == 0) {
|
||||||
wm_timer_tick();
|
kernel_ticks++;
|
||||||
network_process_frames();
|
wm_timer_tick();
|
||||||
|
network_process_frames();
|
||||||
extern void k_beep_process(void);
|
|
||||||
k_beep_process();
|
extern void k_beep_process(void);
|
||||||
|
k_beep_process();
|
||||||
|
}
|
||||||
|
|
||||||
outb(0x20, 0x20);
|
outb(0x20, 0x20);
|
||||||
extern uint64_t process_schedule(uint64_t current_rsp);
|
extern uint64_t process_schedule(uint64_t current_rsp);
|
||||||
|
|
|
||||||
167
src/fs/fat32.c
167
src/fs/fat32.c
|
|
@ -276,19 +276,22 @@ static int ramfs_count_files_in_dir(const char *normalized_path) {
|
||||||
|
|
||||||
static bool check_desktop_limit(const char *normalized_path) {
|
static bool check_desktop_limit(const char *normalized_path) {
|
||||||
if (desktop_file_limit < 0) return true;
|
if (desktop_file_limit < 0) return true;
|
||||||
if (fs_strlen(normalized_path) > 9 &&
|
if (fs_strlen(normalized_path) > 14 &&
|
||||||
normalized_path[0] == '/' &&
|
normalized_path[0] == '/' &&
|
||||||
normalized_path[1] == 'D' && normalized_path[2] == 'e' &&
|
normalized_path[1] == 'r' && normalized_path[2] == 'o' &&
|
||||||
normalized_path[3] == 's' && normalized_path[4] == 'k' &&
|
normalized_path[3] == 'o' && normalized_path[4] == 't' &&
|
||||||
normalized_path[5] == 't' && normalized_path[6] == 'o' &&
|
normalized_path[5] == '/' &&
|
||||||
normalized_path[7] == 'p' && normalized_path[8] == '/') {
|
normalized_path[6] == 'D' && normalized_path[7] == 'e' &&
|
||||||
const char *p = normalized_path + 9;
|
normalized_path[8] == 's' && normalized_path[9] == 'k' &&
|
||||||
|
normalized_path[10] == 't' && normalized_path[11] == 'o' &&
|
||||||
|
normalized_path[12] == 'p' && normalized_path[13] == '/') {
|
||||||
|
const char *p = normalized_path + 14;
|
||||||
while (*p) {
|
while (*p) {
|
||||||
if (*p == '/') return true;
|
if (*p == '/') return true;
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
|
|
||||||
int count = ramfs_count_files_in_dir("/Desktop");
|
int count = ramfs_count_files_in_dir("/root/Desktop");
|
||||||
if (count >= desktop_file_limit) return false;
|
if (count >= desktop_file_limit) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -707,7 +710,27 @@ static FAT32_FileHandle* realfs_open_from_vol(FAT32_Volume *vol, const char *pat
|
||||||
to_dos_filename(component, dos_name);
|
to_dos_filename(component, dos_name);
|
||||||
|
|
||||||
int name_len = fs_strlen(component);
|
int name_len = fs_strlen(component);
|
||||||
bool needs_lfn = (name_len > 12);
|
|
||||||
|
// Determine if LFN is needed:
|
||||||
|
// LFN is needed if the name contains characters that don't fit in 8.3 format
|
||||||
|
// or if the extension is longer than 3 chars or name part is longer than 8 chars
|
||||||
|
bool needs_lfn = false;
|
||||||
|
int dot_pos = -1;
|
||||||
|
for (int i = 0; i < name_len; i++) {
|
||||||
|
if (component[i] == '.') { dot_pos = i; break; }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dot_pos == -1) {
|
||||||
|
// No extension - need LFN if name > 8 chars
|
||||||
|
needs_lfn = (name_len > 8);
|
||||||
|
} else {
|
||||||
|
// Has extension
|
||||||
|
int name_part = dot_pos;
|
||||||
|
int ext_part = name_len - dot_pos - 1;
|
||||||
|
// Need LFN if name > 8 chars or extension > 3 chars
|
||||||
|
needs_lfn = (name_part > 8) || (ext_part > 3);
|
||||||
|
}
|
||||||
|
|
||||||
int lfn_entries = needs_lfn ? ((name_len + 12) / 13) : 0;
|
int lfn_entries = needs_lfn ? ((name_len + 12) / 13) : 0;
|
||||||
int total_entries = lfn_entries + 1;
|
int total_entries = lfn_entries + 1;
|
||||||
|
|
||||||
|
|
@ -753,29 +776,29 @@ static FAT32_FileHandle* realfs_open_from_vol(FAT32_Volume *vol, const char *pat
|
||||||
d->start_cluster_low = 0;
|
d->start_cluster_low = 0;
|
||||||
d->file_size = 0;
|
d->file_size = 0;
|
||||||
|
|
||||||
realfs_write_cluster(vol, free_cluster, lfn_cl_buf);
|
if (realfs_write_cluster(vol, free_cluster, lfn_cl_buf) == 0) {
|
||||||
|
uint32_t lba = vol->cluster_begin_lba + (free_cluster - 2) * vol->sectors_per_cluster;
|
||||||
uint32_t lba = vol->cluster_begin_lba + (free_cluster - 2) * vol->sectors_per_cluster;
|
entry_sector = lba + ((start_entry_idx + lfn_entries) * 32) / 512;
|
||||||
entry_sector = lba + ((start_entry_idx + lfn_entries) * 32) / 512;
|
entry_offset = ((start_entry_idx + lfn_entries) * 32) % 512;
|
||||||
entry_offset = ((start_entry_idx + lfn_entries) * 32) % 512;
|
|
||||||
|
kfree(lfn_cl_buf);
|
||||||
kfree(lfn_cl_buf);
|
if (cluster_buf) kfree(cluster_buf);
|
||||||
if (cluster_buf) kfree(cluster_buf);
|
|
||||||
|
FAT32_FileHandle *fh = ramfs_find_free_handle();
|
||||||
FAT32_FileHandle *fh = ramfs_find_free_handle();
|
if (fh) {
|
||||||
if (fh) {
|
fh->valid = true;
|
||||||
fh->valid = true;
|
fh->volume = vol;
|
||||||
fh->volume = vol;
|
fh->start_cluster = 0;
|
||||||
fh->start_cluster = 0;
|
fh->cluster = 0;
|
||||||
fh->cluster = 0;
|
fh->position = 0;
|
||||||
fh->position = 0;
|
fh->size = 0;
|
||||||
fh->size = 0;
|
fh->mode = (mode[0] == 'a' ? 2 : 1);
|
||||||
fh->mode = (mode[0] == 'a' ? 2 : 1);
|
fh->is_directory = false;
|
||||||
fh->is_directory = false;
|
fh->attributes = ATTR_ARCHIVE;
|
||||||
fh->attributes = ATTR_ARCHIVE;
|
fh->dir_sector = entry_sector;
|
||||||
fh->dir_sector = entry_sector;
|
fh->dir_offset = entry_offset;
|
||||||
fh->dir_offset = entry_offset;
|
return fh;
|
||||||
return fh;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -951,6 +974,9 @@ static uint32_t realfs_allocate_cluster(FAT32_Volume *vol) {
|
||||||
uint32_t current = 2;
|
uint32_t current = 2;
|
||||||
uint32_t fat_entries = (vol->fat_size * 512) / 4;
|
uint32_t fat_entries = (vol->fat_size * 512) / 4;
|
||||||
|
|
||||||
|
// Skip cluster 2 as it's reserved for the root directory in FAT32
|
||||||
|
if (current == vol->root_cluster) current++;
|
||||||
|
|
||||||
uint8_t *fat_buf = (uint8_t*)kmalloc(512);
|
uint8_t *fat_buf = (uint8_t*)kmalloc(512);
|
||||||
if (!fat_buf) return 0;
|
if (!fat_buf) return 0;
|
||||||
|
|
||||||
|
|
@ -1006,18 +1032,33 @@ static int realfs_write_file(FAT32_FileHandle *handle, const void *buffer, int s
|
||||||
}
|
}
|
||||||
handle->start_cluster = new_cluster;
|
handle->start_cluster = new_cluster;
|
||||||
handle->cluster = new_cluster;
|
handle->cluster = new_cluster;
|
||||||
|
handle->position = 0;
|
||||||
|
handle->size = 0;
|
||||||
|
|
||||||
|
// Update directory entry immediately with correct start_cluster
|
||||||
|
// This ensures the directory always points to the right cluster
|
||||||
realfs_update_dir_entry_size(vol, handle);
|
realfs_update_dir_entry_size(vol, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (bytes_written < size) {
|
while (bytes_written < size) {
|
||||||
if (realfs_read_cluster(vol, handle->cluster, cluster_buf) != 0) break;
|
|
||||||
|
|
||||||
uint32_t offset = handle->position % cluster_size;
|
uint32_t offset = handle->position % cluster_size;
|
||||||
|
|
||||||
|
// Always zero the buffer first to ensure clean state
|
||||||
|
for (int i = 0; i < (int)cluster_size; i++) cluster_buf[i] = 0;
|
||||||
|
|
||||||
|
// If we're in the middle of a cluster, read the existing data first
|
||||||
|
if (offset > 0) {
|
||||||
|
if (realfs_read_cluster(vol, handle->cluster, cluster_buf) != 0) break;
|
||||||
|
}
|
||||||
|
|
||||||
int to_copy = size - bytes_written;
|
int to_copy = size - bytes_written;
|
||||||
int available = cluster_size - offset;
|
int available = cluster_size - offset;
|
||||||
if (to_copy > available) to_copy = available;
|
if (to_copy > available) to_copy = available;
|
||||||
|
|
||||||
for (int i = 0; i < to_copy; i++) cluster_buf[offset + i] = src_buf[bytes_written + i];
|
// Copy new data into the cluster buffer
|
||||||
|
for (int i = 0; i < to_copy; i++) {
|
||||||
|
cluster_buf[offset + i] = src_buf[bytes_written + i];
|
||||||
|
}
|
||||||
|
|
||||||
if (realfs_write_cluster(vol, handle->cluster, cluster_buf) != 0) break;
|
if (realfs_write_cluster(vol, handle->cluster, cluster_buf) != 0) break;
|
||||||
|
|
||||||
|
|
@ -1152,10 +1193,15 @@ static bool realfs_delete_from_vol(FAT32_Volume *vol, const char *path) {
|
||||||
|
|
||||||
int lfn_start_entry = -1;
|
int lfn_start_entry = -1;
|
||||||
if (has_lfn) {
|
if (has_lfn) {
|
||||||
// This is an oversimplification, but for same-sector LFNs:
|
// Find all LFN entries in reverse from the main entry
|
||||||
|
// LFN entries are marked by their order field and must be contiguous
|
||||||
for (int k = e - 1; k >= 0; k--) {
|
for (int k = e - 1; k >= 0; k--) {
|
||||||
if (entry[k].attributes == ATTR_LFN) lfn_start_entry = k;
|
if (entry[k].attributes == ATTR_LFN) {
|
||||||
else break;
|
lfn_start_entry = k; // Keep updating to find earliest LFN
|
||||||
|
} else {
|
||||||
|
// Stop when we hit a non-LFN entry that's not deleted
|
||||||
|
if (entry[k].filename[0] != 0xE5) break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1170,7 +1216,7 @@ static bool realfs_delete_from_vol(FAT32_Volume *vol, const char *path) {
|
||||||
|
|
||||||
if (*p == 0) {
|
if (*p == 0) {
|
||||||
// Found target file/directory to delete
|
// Found target file/directory to delete
|
||||||
// Mark LFN entries as deleted too (if in same sector)
|
// Mark LFN entries as deleted too
|
||||||
if (lfn_start_entry != -1) {
|
if (lfn_start_entry != -1) {
|
||||||
for (int k = lfn_start_entry; k < e; k++) {
|
for (int k = lfn_start_entry; k < e; k++) {
|
||||||
entry[k].filename[0] = 0xE5;
|
entry[k].filename[0] = 0xE5;
|
||||||
|
|
@ -1180,10 +1226,49 @@ static bool realfs_delete_from_vol(FAT32_Volume *vol, const char *path) {
|
||||||
entry[e].filename[0] = 0xE5;
|
entry[e].filename[0] = 0xE5;
|
||||||
|
|
||||||
// Persist the changes to disk
|
// Persist the changes to disk
|
||||||
// Calculate exactly which sector within the cluster we modified
|
// CRITICAL FIX: Write ALL sectors that contain modified entries
|
||||||
|
// LFN entries and main entry may span multiple sectors in the cluster
|
||||||
uint32_t lba = vol->cluster_begin_lba + (search_cluster - 2) * vol->sectors_per_cluster;
|
uint32_t lba = vol->cluster_begin_lba + (search_cluster - 2) * vol->sectors_per_cluster;
|
||||||
int sect_in_cluster = (e * 32) / 512;
|
|
||||||
vol->disk->write_sector(vol->disk, lba + sect_in_cluster, ((uint8_t*)entry) + (sect_in_cluster * 512));
|
// Find all sectors touched by LFN and main entries
|
||||||
|
uint8_t sectors_to_write[8] = {0}; // Max 8 sectors per cluster
|
||||||
|
int num_sectors = 0;
|
||||||
|
|
||||||
|
// Mark sectors containing LFN entries
|
||||||
|
if (lfn_start_entry != -1) {
|
||||||
|
for (int k = lfn_start_entry; k < e; k++) {
|
||||||
|
int sect_idx = (k * 32) / 512;
|
||||||
|
bool already_marked = false;
|
||||||
|
for (int s = 0; s < num_sectors; s++) {
|
||||||
|
if (sectors_to_write[s] == sect_idx) {
|
||||||
|
already_marked = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!already_marked && num_sectors < 8) {
|
||||||
|
sectors_to_write[num_sectors++] = sect_idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark sector containing main entry
|
||||||
|
int main_sect_idx = (e * 32) / 512;
|
||||||
|
bool already_marked = false;
|
||||||
|
for (int s = 0; s < num_sectors; s++) {
|
||||||
|
if (sectors_to_write[s] == main_sect_idx) {
|
||||||
|
already_marked = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!already_marked && num_sectors < 8) {
|
||||||
|
sectors_to_write[num_sectors++] = main_sect_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write all modified sectors
|
||||||
|
for (int i = 0; i < num_sectors; i++) {
|
||||||
|
int sect_idx = sectors_to_write[i];
|
||||||
|
vol->disk->write_sector(vol->disk, lba + sect_idx, ((uint8_t*)entry) + (sect_idx * 512));
|
||||||
|
}
|
||||||
|
|
||||||
found = true;
|
found = true;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
290
src/fs/procfs.c
Normal file
290
src/fs/procfs.c
Normal file
|
|
@ -0,0 +1,290 @@
|
||||||
|
#include "vfs.h"
|
||||||
|
#include "../sys/process.h"
|
||||||
|
#include "../sys/syscall.h"
|
||||||
|
#include "../dev/disk.h"
|
||||||
|
#include "memory_manager.h"
|
||||||
|
#include "core/kutils.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t pid;
|
||||||
|
char type[32];
|
||||||
|
int offset;
|
||||||
|
bool is_root;
|
||||||
|
} procfs_handle_t;
|
||||||
|
|
||||||
|
void* procfs_open(void *fs_private, const char *path, const char *mode) {
|
||||||
|
if (path[0] == '/') path++;
|
||||||
|
|
||||||
|
procfs_handle_t *h = (procfs_handle_t*)kmalloc(sizeof(procfs_handle_t));
|
||||||
|
k_memset(h, 0, sizeof(procfs_handle_t));
|
||||||
|
h->offset = 0;
|
||||||
|
|
||||||
|
if (path[0] == '\0') {
|
||||||
|
h->is_root = true;
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path[0] >= '0' && path[0] <= '9') {
|
||||||
|
char pid_str[16];
|
||||||
|
int i = 0;
|
||||||
|
while (path[i] && path[i] != '/' && i < 15) {
|
||||||
|
pid_str[i] = path[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
pid_str[i] = 0;
|
||||||
|
h->pid = k_atoi(pid_str);
|
||||||
|
|
||||||
|
if (path[i] == '/') {
|
||||||
|
k_strcpy(h->type, path + i + 1);
|
||||||
|
} else {
|
||||||
|
h->type[0] = 0;
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
h->pid = 0xFFFFFFFF;
|
||||||
|
k_strcpy(h->type, path);
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
void procfs_close(void *fs_private, void *handle) {
|
||||||
|
if (handle) kfree(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
int procfs_read(void *fs_private, void *handle, void *buf, int size) {
|
||||||
|
procfs_handle_t *h = (procfs_handle_t*)handle;
|
||||||
|
if (!h) return -1;
|
||||||
|
|
||||||
|
char out[1024];
|
||||||
|
out[0] = 0;
|
||||||
|
|
||||||
|
if (h->pid == 0xFFFFFFFF) {
|
||||||
|
if (k_strcmp(h->type, "version") == 0) {
|
||||||
|
extern void get_os_info(os_info_t *info);
|
||||||
|
os_info_t info;
|
||||||
|
get_os_info(&info);
|
||||||
|
k_strcpy(out, info.os_name);
|
||||||
|
k_strcpy(out + k_strlen(out), " [");
|
||||||
|
k_strcpy(out + k_strlen(out), info.os_codename);
|
||||||
|
k_strcpy(out + k_strlen(out), "] Version ");
|
||||||
|
k_strcpy(out + k_strlen(out), info.os_version);
|
||||||
|
k_strcpy(out + k_strlen(out), "\nKernel: ");
|
||||||
|
k_strcpy(out + k_strlen(out), info.kernel_name);
|
||||||
|
k_strcpy(out + k_strlen(out), " ");
|
||||||
|
k_strcpy(out + k_strlen(out), info.kernel_version);
|
||||||
|
k_strcpy(out + k_strlen(out), "\nBuild: ");
|
||||||
|
k_strcpy(out + k_strlen(out), info.build_date);
|
||||||
|
k_strcpy(out + k_strlen(out), " ");
|
||||||
|
k_strcpy(out + k_strlen(out), info.build_time);
|
||||||
|
k_strcpy(out + k_strlen(out), "\n");
|
||||||
|
} else if (k_strcmp(h->type, "uptime") == 0) {
|
||||||
|
extern uint32_t wm_get_ticks(void);
|
||||||
|
uint32_t ticks = wm_get_ticks();
|
||||||
|
k_itoa(ticks / 60, out);
|
||||||
|
k_strcpy(out + k_strlen(out), " seconds\nRaw_Ticks:");
|
||||||
|
char t_s[16]; k_itoa(ticks, t_s);
|
||||||
|
k_strcpy(out + k_strlen(out), t_s);
|
||||||
|
k_strcpy(out + k_strlen(out), "\n");
|
||||||
|
} else if (k_strcmp(h->type, "cpuinfo") == 0) {
|
||||||
|
extern uint32_t smp_cpu_count(void);
|
||||||
|
extern void platform_get_cpu_model(char *model);
|
||||||
|
char model[64];
|
||||||
|
platform_get_cpu_model(model);
|
||||||
|
|
||||||
|
k_strcpy(out, "Processor: ");
|
||||||
|
k_strcpy(out + k_strlen(out), model);
|
||||||
|
k_strcpy(out + k_strlen(out), "\nCores: ");
|
||||||
|
char c_s[16]; k_itoa(smp_cpu_count(), c_s);
|
||||||
|
k_strcpy(out + k_strlen(out), c_s);
|
||||||
|
k_strcpy(out + k_strlen(out), "\nArchitecture: x86_64\n");
|
||||||
|
} else if (k_strcmp(h->type, "meminfo") == 0) {
|
||||||
|
extern MemStats memory_get_stats(void);
|
||||||
|
MemStats stats = memory_get_stats();
|
||||||
|
k_strcpy(out, "MemTotal: ");
|
||||||
|
char m_s[32]; k_itoa(stats.total_memory / 1024, m_s);
|
||||||
|
k_strcpy(out + k_strlen(out), m_s);
|
||||||
|
k_strcpy(out + k_strlen(out), " kB\nMemFree: ");
|
||||||
|
k_itoa(stats.available_memory / 1024, m_s);
|
||||||
|
k_strcpy(out + k_strlen(out), m_s);
|
||||||
|
k_strcpy(out + k_strlen(out), " kB\nMemUsed: ");
|
||||||
|
k_itoa(stats.used_memory / 1024, m_s);
|
||||||
|
k_strcpy(out + k_strlen(out), m_s);
|
||||||
|
k_strcpy(out + k_strlen(out), " kB\nPeak: ");
|
||||||
|
k_itoa(stats.peak_memory_used / 1024, m_s);
|
||||||
|
k_strcpy(out + k_strlen(out), m_s);
|
||||||
|
k_strcpy(out + k_strlen(out), " kB\nBlocks: ");
|
||||||
|
k_itoa(stats.allocated_blocks, m_s);
|
||||||
|
k_strcpy(out + k_strlen(out), m_s);
|
||||||
|
k_strcpy(out + k_strlen(out), "\nFragmentation: ");
|
||||||
|
k_itoa(stats.fragmentation_percent, m_s);
|
||||||
|
k_strcpy(out + k_strlen(out), m_s);
|
||||||
|
k_strcpy(out + k_strlen(out), "%\n");
|
||||||
|
} else if (k_strcmp(h->type, "devices") == 0) {
|
||||||
|
extern int disk_get_count(void);
|
||||||
|
extern Disk* disk_get_by_index(int index);
|
||||||
|
int dcount = disk_get_count();
|
||||||
|
k_strcpy(out, "Block Devices:\n");
|
||||||
|
for (int i = 0; i < dcount; i++) {
|
||||||
|
Disk *d = disk_get_by_index(i);
|
||||||
|
if (d) {
|
||||||
|
k_strcpy(out + k_strlen(out), " - ");
|
||||||
|
k_strcpy(out + k_strlen(out), d->devname);
|
||||||
|
k_strcpy(out + k_strlen(out), "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
process_t *proc = process_get_by_pid(h->pid);
|
||||||
|
if (!proc) return -1;
|
||||||
|
|
||||||
|
if (k_strcmp(h->type, "name") == 0 || k_strcmp(h->type, "cmdline") == 0) {
|
||||||
|
k_strcpy(out, proc->name);
|
||||||
|
k_strcpy(out + k_strlen(out), "\n");
|
||||||
|
} else if (k_strcmp(h->type, "status") == 0) {
|
||||||
|
k_strcpy(out, "Name: ");
|
||||||
|
k_strcpy(out + k_strlen(out), proc->name);
|
||||||
|
k_strcpy(out + k_strlen(out), "\nPID: ");
|
||||||
|
char pid_s[16]; k_itoa(proc->pid, pid_s);
|
||||||
|
k_strcpy(out + k_strlen(out), pid_s);
|
||||||
|
k_strcpy(out + k_strlen(out), "\nState: RUNNING\nMemory: ");
|
||||||
|
uint64_t mem_val = proc->used_memory;
|
||||||
|
if (h->pid == 0) {
|
||||||
|
extern MemStats memory_get_stats(void);
|
||||||
|
mem_val = memory_get_stats().used_memory;
|
||||||
|
}
|
||||||
|
char mem_s[32]; k_itoa(mem_val / 1024, mem_s);
|
||||||
|
k_strcpy(out + k_strlen(out), mem_s);
|
||||||
|
k_strcpy(out + k_strlen(out), " KB\nTicks: ");
|
||||||
|
char tick_s[32]; k_itoa(proc->ticks, tick_s);
|
||||||
|
k_strcpy(out + k_strlen(out), tick_s);
|
||||||
|
k_strcpy(out + k_strlen(out), "\nIdle: ");
|
||||||
|
k_strcpy(out + k_strlen(out), proc->is_idle ? "1" : "0");
|
||||||
|
k_strcpy(out + k_strlen(out), "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int len = k_strlen(out);
|
||||||
|
if (h->offset >= len) return 0;
|
||||||
|
|
||||||
|
int to_copy = len - h->offset;
|
||||||
|
if (to_copy > size) to_copy = size;
|
||||||
|
|
||||||
|
k_memcpy(buf, out + h->offset, to_copy);
|
||||||
|
h->offset += to_copy;
|
||||||
|
return to_copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
int procfs_write(void *fs_private, void *handle, const void *buf, int size) {
|
||||||
|
procfs_handle_t *h = (procfs_handle_t*)handle;
|
||||||
|
if (!h || h->pid == 0xFFFFFFFF) return -1;
|
||||||
|
|
||||||
|
if (k_strcmp(h->type, "signal") == 0) {
|
||||||
|
char cmd[16];
|
||||||
|
int to_copy = size < 15 ? size : 15;
|
||||||
|
k_memcpy(cmd, buf, to_copy);
|
||||||
|
cmd[to_copy] = 0;
|
||||||
|
|
||||||
|
if (k_strcmp(cmd, "9") == 0 || k_strcmp(cmd, "kill") == 0) {
|
||||||
|
process_t *proc = process_get_by_pid(h->pid);
|
||||||
|
if (proc && proc->pid != 0) {
|
||||||
|
process_terminate(proc);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int procfs_readdir(void *fs_private, const char *path, vfs_dirent_t *entries, int max) {
|
||||||
|
if (path[0] == '/') path++;
|
||||||
|
|
||||||
|
if (path[0] == '\0') {
|
||||||
|
int out = 0;
|
||||||
|
k_strcpy(entries[out++].name, "version");
|
||||||
|
entries[out-1].is_directory = 0;
|
||||||
|
k_strcpy(entries[out++].name, "uptime");
|
||||||
|
entries[out-1].is_directory = 0;
|
||||||
|
k_strcpy(entries[out++].name, "cpuinfo");
|
||||||
|
entries[out-1].is_directory = 0;
|
||||||
|
k_strcpy(entries[out++].name, "meminfo");
|
||||||
|
entries[out-1].is_directory = 0;
|
||||||
|
k_strcpy(entries[out++].name, "devices");
|
||||||
|
entries[out-1].is_directory = 0;
|
||||||
|
|
||||||
|
extern process_t processes[];
|
||||||
|
for (int i = 0; i < 16 && out < max; i++) {
|
||||||
|
if (processes[i].pid != 0xFFFFFFFF) {
|
||||||
|
k_itoa(processes[i].pid, entries[out].name);
|
||||||
|
entries[out].is_directory = 1;
|
||||||
|
entries[out].size = 0;
|
||||||
|
out++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path[0] >= '0' && path[0] <= '9') {
|
||||||
|
int out = 0;
|
||||||
|
k_strcpy(entries[out++].name, "name");
|
||||||
|
k_strcpy(entries[out++].name, "status");
|
||||||
|
k_strcpy(entries[out++].name, "cmdline");
|
||||||
|
k_strcpy(entries[out++].name, "signal");
|
||||||
|
for(int i=0; i<out; i++) entries[i].is_directory = 0;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool procfs_exists(void *fs_private, const char *path) {
|
||||||
|
if (path[0] == '/') path++;
|
||||||
|
if (path[0] == '\0') return true;
|
||||||
|
|
||||||
|
if (path[0] >= '0' && path[0] <= '9') {
|
||||||
|
char pid_str[16];
|
||||||
|
int i = 0;
|
||||||
|
while (path[i] && path[i] != '/' && i < 15) {
|
||||||
|
pid_str[i] = path[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
pid_str[i] = 0;
|
||||||
|
uint32_t pid = k_atoi(pid_str);
|
||||||
|
if (process_get_by_pid(pid)) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k_strcmp(path, "version") == 0 || k_strcmp(path, "uptime") == 0) return true;
|
||||||
|
if (k_strcmp(path, "cpuinfo") == 0 || k_strcmp(path, "meminfo") == 0) return true;
|
||||||
|
if (k_strcmp(path, "devices") == 0) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool procfs_is_dir(void *fs_private, const char *path) {
|
||||||
|
if (path[0] == '/') path++;
|
||||||
|
if (path[0] == '\0') return true;
|
||||||
|
|
||||||
|
if (path[0] >= '0' && path[0] <= '9') {
|
||||||
|
int i = 0;
|
||||||
|
while (path[i] && path[i] != '/') i++;
|
||||||
|
if (path[i] == '\0') return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
vfs_fs_ops_t procfs_ops = {
|
||||||
|
.open = procfs_open,
|
||||||
|
.close = procfs_close,
|
||||||
|
.read = procfs_read,
|
||||||
|
.write = procfs_write,
|
||||||
|
.readdir = procfs_readdir,
|
||||||
|
.exists = procfs_exists,
|
||||||
|
.is_dir = procfs_is_dir
|
||||||
|
};
|
||||||
|
|
||||||
|
vfs_fs_ops_t* procfs_get_ops(void) {
|
||||||
|
return &procfs_ops;
|
||||||
|
}
|
||||||
8
src/fs/procfs.h
Normal file
8
src/fs/procfs.h
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef PROCFS_H
|
||||||
|
#define PROCFS_H
|
||||||
|
|
||||||
|
#include "vfs.h"
|
||||||
|
|
||||||
|
vfs_fs_ops_t* procfs_get_ops(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
181
src/fs/sysfs.c
Normal file
181
src/fs/sysfs.c
Normal file
|
|
@ -0,0 +1,181 @@
|
||||||
|
#include "vfs.h"
|
||||||
|
#include "../sys/kernel_subsystem.h"
|
||||||
|
#include "memory_manager.h"
|
||||||
|
#include "core/kutils.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
kernel_subsystem_t *sub;
|
||||||
|
subsystem_file_t *file;
|
||||||
|
int offset;
|
||||||
|
} sysfs_handle_t;
|
||||||
|
|
||||||
|
static void* sysfs_open(void *fs_private, const char *path, const char *mode) {
|
||||||
|
if (path[0] == '/') path++;
|
||||||
|
if (path[0] == '\0') return NULL;
|
||||||
|
|
||||||
|
kernel_subsystem_t *sub = NULL;
|
||||||
|
int last_slash = -1;
|
||||||
|
for (int j = 0; path[j]; j++) if (path[j] == '/') last_slash = j;
|
||||||
|
|
||||||
|
if (last_slash != -1) {
|
||||||
|
char prefix[64];
|
||||||
|
k_memcpy(prefix, path, last_slash);
|
||||||
|
prefix[last_slash] = 0;
|
||||||
|
sub = subsystem_get_by_name(prefix);
|
||||||
|
|
||||||
|
if (sub) {
|
||||||
|
const char *filename = path + last_slash + 1;
|
||||||
|
for (int j = 0; j < sub->file_count; j++) {
|
||||||
|
if (k_strcmp(sub->files[j].name, filename) == 0) {
|
||||||
|
sysfs_handle_t *h = (sysfs_handle_t*)kmalloc(sizeof(sysfs_handle_t));
|
||||||
|
h->sub = sub;
|
||||||
|
h->file = &sub->files[j];
|
||||||
|
h->offset = 0;
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sysfs_close(void *fs_private, void *handle) {
|
||||||
|
if (handle) kfree(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sysfs_read(void *fs_private, void *handle, void *buf, int size) {
|
||||||
|
sysfs_handle_t *h = (sysfs_handle_t*)handle;
|
||||||
|
if (!h || !h->file || !h->file->read) return -1;
|
||||||
|
|
||||||
|
int bytes = h->file->read((char*)buf, size, h->offset);
|
||||||
|
if (bytes > 0) h->offset += bytes;
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sysfs_write(void *fs_private, void *handle, const void *buf, int size) {
|
||||||
|
sysfs_handle_t *h = (sysfs_handle_t*)handle;
|
||||||
|
if (!h || !h->file || !h->file->write) return -1;
|
||||||
|
|
||||||
|
int bytes = h->file->write((const char*)buf, size, h->offset);
|
||||||
|
if (bytes > 0) h->offset += bytes;
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sysfs_readdir(void *fs_private, const char *path, vfs_dirent_t *entries, int max) {
|
||||||
|
if (path[0] == '/') path++;
|
||||||
|
|
||||||
|
kernel_subsystem_t *exact_sub = subsystem_get_by_name(path);
|
||||||
|
int out = 0;
|
||||||
|
|
||||||
|
if (exact_sub) {
|
||||||
|
for (int i = 0; i < exact_sub->file_count && out < max; i++) {
|
||||||
|
k_strcpy(entries[out].name, exact_sub->files[i].name);
|
||||||
|
entries[out].is_directory = 0;
|
||||||
|
entries[out].size = 0;
|
||||||
|
out++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = subsystem_get_count();
|
||||||
|
int path_len = k_strlen(path);
|
||||||
|
|
||||||
|
for (int i = 0; i < count && out < max; i++) {
|
||||||
|
kernel_subsystem_t *s = subsystem_get_by_index(i);
|
||||||
|
if (path_len == 0 || (k_strlen(s->name) > path_len && k_strncmp(s->name, path, path_len) == 0 && s->name[path_len] == '/')) {
|
||||||
|
const char *sub_path = s->name + (path_len ? path_len + 1 : 0);
|
||||||
|
char comp[64];
|
||||||
|
int j = 0;
|
||||||
|
while (sub_path[j] && sub_path[j] != '/' && j < 63) {
|
||||||
|
comp[j] = sub_path[j];
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
comp[j] = 0;
|
||||||
|
|
||||||
|
if (comp[0] == '\0') continue;
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
for (int k = 0; k < out; k++) {
|
||||||
|
if (k_strcmp(entries[k].name, comp) == 0) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
k_strcpy(entries[out].name, comp);
|
||||||
|
entries[out].is_directory = 1;
|
||||||
|
entries[out].size = 0;
|
||||||
|
out++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool sysfs_exists(void *fs_private, const char *path) {
|
||||||
|
if (path[0] == '/') path++;
|
||||||
|
if (path[0] == '\0') return true;
|
||||||
|
|
||||||
|
if (subsystem_get_by_name(path)) return true;
|
||||||
|
|
||||||
|
// File check
|
||||||
|
int last_slash = -1;
|
||||||
|
for (int j = 0; path[j]; j++) if (path[j] == '/') last_slash = j;
|
||||||
|
if (last_slash != -1) {
|
||||||
|
char prefix[64];
|
||||||
|
k_memcpy(prefix, path, last_slash);
|
||||||
|
prefix[last_slash] = 0;
|
||||||
|
kernel_subsystem_t *sub = subsystem_get_by_name(prefix);
|
||||||
|
if (sub) {
|
||||||
|
const char *filename = path + last_slash + 1;
|
||||||
|
for (int j = 0; j < sub->file_count; j++) {
|
||||||
|
if (k_strcmp(sub->files[j].name, filename) == 0) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = subsystem_get_count();
|
||||||
|
int path_len = k_strlen(path);
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
kernel_subsystem_t *s = subsystem_get_by_index(i);
|
||||||
|
if (k_strlen(s->name) > path_len && k_strncmp(s->name, path, path_len) == 0 && s->name[path_len] == '/') return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool sysfs_is_dir(void *fs_private, const char *path) {
|
||||||
|
if (path[0] == '/') path++;
|
||||||
|
if (path[0] == '\0') return true;
|
||||||
|
|
||||||
|
int last_slash = -1;
|
||||||
|
for (int j = 0; path[j]; j++) if (path[j] == '/') last_slash = j;
|
||||||
|
if (last_slash != -1) {
|
||||||
|
char prefix[64];
|
||||||
|
k_memcpy(prefix, path, last_slash);
|
||||||
|
prefix[last_slash] = 0;
|
||||||
|
kernel_subsystem_t *sub = subsystem_get_by_name(prefix);
|
||||||
|
if (sub) {
|
||||||
|
const char *filename = path + last_slash + 1;
|
||||||
|
for (int j = 0; j < sub->file_count; j++) {
|
||||||
|
if (k_strcmp(sub->files[j].name, filename) == 0) return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sysfs_exists(fs_private, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
vfs_fs_ops_t sysfs_ops = {
|
||||||
|
.open = sysfs_open,
|
||||||
|
.close = sysfs_close,
|
||||||
|
.read = sysfs_read,
|
||||||
|
.write = sysfs_write,
|
||||||
|
.readdir = sysfs_readdir,
|
||||||
|
.exists = sysfs_exists,
|
||||||
|
.is_dir = sysfs_is_dir
|
||||||
|
};
|
||||||
|
|
||||||
|
vfs_fs_ops_t* sysfs_get_ops(void) {
|
||||||
|
return &sysfs_ops;
|
||||||
|
}
|
||||||
8
src/fs/sysfs.h
Normal file
8
src/fs/sysfs.h
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef SYSFS_H
|
||||||
|
#define SYSFS_H
|
||||||
|
|
||||||
|
#include "vfs.h"
|
||||||
|
|
||||||
|
vfs_fs_ops_t* sysfs_get_ops(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
316
src/fs/vfs.c
316
src/fs/vfs.c
|
|
@ -6,10 +6,8 @@
|
||||||
#include "spinlock.h"
|
#include "spinlock.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include "disk.h"
|
#include "disk.h"
|
||||||
|
#include "process.h"
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// VFS Mount Table and File Handle Pool
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
static vfs_mount_t mounts[VFS_MAX_MOUNTS];
|
static vfs_mount_t mounts[VFS_MAX_MOUNTS];
|
||||||
static int mount_count = 0;
|
static int mount_count = 0;
|
||||||
|
|
@ -19,10 +17,6 @@ static spinlock_t vfs_lock = SPINLOCK_INIT;
|
||||||
extern void serial_write(const char *str);
|
extern void serial_write(const char *str);
|
||||||
extern void serial_write_num(uint64_t num);
|
extern void serial_write_num(uint64_t num);
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// String helpers (freestanding — no libc)
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
static int vfs_strlen(const char *s) {
|
static int vfs_strlen(const char *s) {
|
||||||
int n = 0;
|
int n = 0;
|
||||||
while (s[n]) n++;
|
while (s[n]) n++;
|
||||||
|
|
@ -53,44 +47,63 @@ static bool vfs_starts_with(const char *str, const char *prefix) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
static bool vfs_path_is_parent(const char *parent, const char *child) {
|
||||||
// Path Normalization
|
int plen = vfs_strlen(parent);
|
||||||
// ============================================================================
|
if (vfs_strncmp(parent, child, plen) != 0) return false;
|
||||||
|
if (child[plen] == '\0') return true;
|
||||||
|
if (child[plen] == '/') return true;
|
||||||
|
if (plen == 1 && parent[0] == '/') return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void vfs_normalize_path(const char *path, char *normalized) {
|
void vfs_normalize_path(const char *cwd, const char *path, char *normalized) {
|
||||||
// Resolve . and .. components, remove duplicate slashes
|
char parts[32][64]; // Reduced size to save stack, 64 is enough for most names
|
||||||
char parts[32][128];
|
|
||||||
int depth = 0;
|
int depth = 0;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
// Skip leading slash
|
// Handle relative path by starting with CWD
|
||||||
|
if (path[0] != '/' && cwd) {
|
||||||
|
int ci = 0;
|
||||||
|
if (cwd[0] == '/') ci = 1;
|
||||||
|
while (cwd[ci]) {
|
||||||
|
if (cwd[ci] == '/') { ci++; continue; }
|
||||||
|
int j = 0;
|
||||||
|
while (cwd[ci] && cwd[ci] != '/' && j < 63) {
|
||||||
|
parts[depth][j++] = cwd[ci++];
|
||||||
|
}
|
||||||
|
parts[depth][j] = 0;
|
||||||
|
if (j > 0) depth++;
|
||||||
|
if (depth >= 32) break;
|
||||||
|
if (cwd[ci] == '/') ci++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (path[0] == '/') i = 1;
|
if (path[0] == '/') i = 1;
|
||||||
|
|
||||||
while (path[i]) {
|
while (path[i]) {
|
||||||
// Skip duplicate slashes
|
|
||||||
if (path[i] == '/') { i++; continue; }
|
if (path[i] == '/') { i++; continue; }
|
||||||
|
|
||||||
// Extract component
|
|
||||||
int j = 0;
|
int j = 0;
|
||||||
while (path[i] && path[i] != '/' && j < 127) {
|
while (path[i] && path[i] != '/' && j < 63) {
|
||||||
parts[depth][j++] = path[i++];
|
parts[depth][j++] = path[i++];
|
||||||
}
|
}
|
||||||
parts[depth][j] = 0;
|
parts[depth][j] = 0;
|
||||||
|
|
||||||
if (parts[depth][0] == '.' && parts[depth][1] == 0) {
|
if (parts[depth][0] == '.' && parts[depth][1] == 0) {
|
||||||
// "." — skip
|
// "." skip
|
||||||
} else if (parts[depth][0] == '.' && parts[depth][1] == '.' && parts[depth][2] == 0) {
|
} else if (parts[depth][0] == '.' && parts[depth][1] == '.' && parts[depth][2] == 0) {
|
||||||
// ".." — go up
|
// ".." pop
|
||||||
if (depth > 0) depth--;
|
if (depth > 0) depth--;
|
||||||
} else {
|
} else {
|
||||||
depth++;
|
if (j > 0) {
|
||||||
if (depth >= 32) break;
|
depth++;
|
||||||
|
if (depth >= 32) break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path[i] == '/') i++;
|
if (path[i] == '/') i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reconstruct
|
|
||||||
normalized[0] = '/';
|
normalized[0] = '/';
|
||||||
int pos = 1;
|
int pos = 1;
|
||||||
for (int k = 0; k < depth; k++) {
|
for (int k = 0; k < depth; k++) {
|
||||||
|
|
@ -102,16 +115,11 @@ void vfs_normalize_path(const char *path, char *normalized) {
|
||||||
}
|
}
|
||||||
normalized[pos] = 0;
|
normalized[pos] = 0;
|
||||||
|
|
||||||
// Ensure root is just "/"
|
|
||||||
if (pos == 1 && normalized[0] == '/') {
|
if (pos == 1 && normalized[0] == '/') {
|
||||||
normalized[1] = 0;
|
normalized[1] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// Mount Resolution — find the longest-prefix mount for a path
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
static vfs_mount_t* vfs_resolve_mount(const char *path, const char **rel_path_out) {
|
static vfs_mount_t* vfs_resolve_mount(const char *path, const char **rel_path_out) {
|
||||||
vfs_mount_t *best = NULL;
|
vfs_mount_t *best = NULL;
|
||||||
int best_len = -1;
|
int best_len = -1;
|
||||||
|
|
@ -121,7 +129,6 @@ static vfs_mount_t* vfs_resolve_mount(const char *path, const char **rel_path_ou
|
||||||
|
|
||||||
int mlen = mounts[i].path_len;
|
int mlen = mounts[i].path_len;
|
||||||
|
|
||||||
// Root mount "/" matches everything
|
|
||||||
if (mlen == 1 && mounts[i].path[0] == '/') {
|
if (mlen == 1 && mounts[i].path[0] == '/') {
|
||||||
if (best_len < 1) {
|
if (best_len < 1) {
|
||||||
best = &mounts[i];
|
best = &mounts[i];
|
||||||
|
|
@ -130,9 +137,7 @@ static vfs_mount_t* vfs_resolve_mount(const char *path, const char **rel_path_ou
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if path starts with this mount point
|
|
||||||
if (vfs_strncmp(path, mounts[i].path, mlen) == 0) {
|
if (vfs_strncmp(path, mounts[i].path, mlen) == 0) {
|
||||||
// Must be followed by '/' or end of string
|
|
||||||
if (path[mlen] == '/' || path[mlen] == '\0') {
|
if (path[mlen] == '/' || path[mlen] == '\0') {
|
||||||
if (mlen > best_len) {
|
if (mlen > best_len) {
|
||||||
best = &mounts[i];
|
best = &mounts[i];
|
||||||
|
|
@ -144,7 +149,6 @@ static vfs_mount_t* vfs_resolve_mount(const char *path, const char **rel_path_ou
|
||||||
|
|
||||||
if (best && rel_path_out) {
|
if (best && rel_path_out) {
|
||||||
const char *rel = path + best_len;
|
const char *rel = path + best_len;
|
||||||
// Skip leading slash in relative path
|
|
||||||
while (*rel == '/') rel++;
|
while (*rel == '/') rel++;
|
||||||
*rel_path_out = rel;
|
*rel_path_out = rel;
|
||||||
}
|
}
|
||||||
|
|
@ -152,14 +156,14 @@ static vfs_mount_t* vfs_resolve_mount(const char *path, const char **rel_path_ou
|
||||||
return best;
|
return best;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// File Handle Pool
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
static vfs_file_t* vfs_alloc_file(void) {
|
static vfs_file_t* vfs_alloc_file(void) {
|
||||||
for (int i = 0; i < VFS_MAX_OPEN_FILES; i++) {
|
for (int i = 0; i < VFS_MAX_OPEN_FILES; i++) {
|
||||||
if (!open_files[i].valid) {
|
if (!open_files[i].valid) {
|
||||||
open_files[i].valid = true;
|
open_files[i].valid = true;
|
||||||
|
open_files[i].fs_handle = NULL;
|
||||||
|
open_files[i].mount = NULL;
|
||||||
|
open_files[i].position = 0;
|
||||||
|
open_files[i].is_device = false;
|
||||||
return &open_files[i];
|
return &open_files[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -171,13 +175,11 @@ static void vfs_free_file(vfs_file_t *f) {
|
||||||
f->valid = false;
|
f->valid = false;
|
||||||
f->fs_handle = NULL;
|
f->fs_handle = NULL;
|
||||||
f->mount = NULL;
|
f->mount = NULL;
|
||||||
|
f->position = 0;
|
||||||
|
f->is_device = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// Initialization
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
void vfs_init(void) {
|
void vfs_init(void) {
|
||||||
for (int i = 0; i < VFS_MAX_MOUNTS; i++) {
|
for (int i = 0; i < VFS_MAX_MOUNTS; i++) {
|
||||||
mounts[i].active = false;
|
mounts[i].active = false;
|
||||||
|
|
@ -190,9 +192,9 @@ void vfs_init(void) {
|
||||||
serial_write("[VFS] Virtual File System initialized\n");
|
serial_write("[VFS] Virtual File System initialized\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ===============
|
||||||
// Mount / Unmount
|
// Mount / Unmount
|
||||||
// ============================================================================
|
// ===============
|
||||||
|
|
||||||
bool vfs_mount(const char *mount_path, const char *device, const char *fs_type,
|
bool vfs_mount(const char *mount_path, const char *device, const char *fs_type,
|
||||||
vfs_fs_ops_t *ops, void *fs_private) {
|
vfs_fs_ops_t *ops, void *fs_private) {
|
||||||
|
|
@ -204,7 +206,6 @@ bool vfs_mount(const char *mount_path, const char *device, const char *fs_type,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for duplicate mount
|
|
||||||
for (int i = 0; i < mount_count; i++) {
|
for (int i = 0; i < mount_count; i++) {
|
||||||
if (mounts[i].active && vfs_strcmp(mounts[i].path, mount_path) == 0) {
|
if (mounts[i].active && vfs_strcmp(mounts[i].path, mount_path) == 0) {
|
||||||
spinlock_release_irqrestore(&vfs_lock, flags);
|
spinlock_release_irqrestore(&vfs_lock, flags);
|
||||||
|
|
@ -243,7 +244,6 @@ bool vfs_umount(const char *mount_path) {
|
||||||
|
|
||||||
for (int i = 0; i < mount_count; i++) {
|
for (int i = 0; i < mount_count; i++) {
|
||||||
if (mounts[i].active && vfs_strcmp(mounts[i].path, mount_path) == 0) {
|
if (mounts[i].active && vfs_strcmp(mounts[i].path, mount_path) == 0) {
|
||||||
// Close any open files on this mount
|
|
||||||
for (int j = 0; j < VFS_MAX_OPEN_FILES; j++) {
|
for (int j = 0; j < VFS_MAX_OPEN_FILES; j++) {
|
||||||
if (open_files[j].valid && open_files[j].mount == &mounts[i]) {
|
if (open_files[j].valid && open_files[j].mount == &mounts[i]) {
|
||||||
if (mounts[i].ops->close) {
|
if (mounts[i].ops->close) {
|
||||||
|
|
@ -274,27 +274,44 @@ bool vfs_umount(const char *mount_path) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ==============
|
||||||
// File Operations
|
// File Operations
|
||||||
// ============================================================================
|
// ==============
|
||||||
|
|
||||||
vfs_file_t* vfs_open(const char *path, const char *mode) {
|
vfs_file_t* vfs_open(const char *path, const char *mode) {
|
||||||
if (!path || !mode) return NULL;
|
if (!path || !mode) return NULL;
|
||||||
|
|
||||||
// Normalize path
|
|
||||||
char normalized[VFS_MAX_PATH];
|
char normalized[VFS_MAX_PATH];
|
||||||
vfs_normalize_path(path, normalized);
|
process_t *proc = process_get_current();
|
||||||
|
vfs_normalize_path(proc ? proc->cwd : "/", path, normalized);
|
||||||
|
|
||||||
uint64_t flags = spinlock_acquire_irqsave(&vfs_lock);
|
uint64_t flags = spinlock_acquire_irqsave(&vfs_lock);
|
||||||
|
|
||||||
const char *rel_path = NULL;
|
const char *rel_path = NULL;
|
||||||
vfs_mount_t *mount = vfs_resolve_mount(normalized, &rel_path);
|
vfs_mount_t *mount = vfs_resolve_mount(normalized, &rel_path);
|
||||||
|
|
||||||
|
// Fallback for block devices (/dev/sda etc)
|
||||||
|
if (vfs_starts_with(normalized, "/dev/")) {
|
||||||
|
const char *devname = normalized + 5;
|
||||||
|
Disk *d = disk_get_by_name(devname);
|
||||||
|
if (d && (!mount || mount->path_len == 1)) {
|
||||||
|
vfs_file_t *vf = vfs_alloc_file();
|
||||||
|
if (vf) {
|
||||||
|
vf->mount = &mounts[0];
|
||||||
|
vf->fs_handle = (void*)d;
|
||||||
|
vf->is_device = true;
|
||||||
|
vf->position = 0;
|
||||||
|
spinlock_release_irqrestore(&vfs_lock, flags);
|
||||||
|
return vf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!mount || !mount->ops->open) {
|
if (!mount || !mount->ops->open) {
|
||||||
spinlock_release_irqrestore(&vfs_lock, flags);
|
spinlock_release_irqrestore(&vfs_lock, flags);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If rel_path is empty, use root
|
|
||||||
if (!rel_path || rel_path[0] == '\0') {
|
if (!rel_path || rel_path[0] == '\0') {
|
||||||
rel_path = "/";
|
rel_path = "/";
|
||||||
}
|
}
|
||||||
|
|
@ -308,7 +325,6 @@ vfs_file_t* vfs_open(const char *path, const char *mode) {
|
||||||
|
|
||||||
vf->mount = mount;
|
vf->mount = mount;
|
||||||
|
|
||||||
// Release lock before calling FS ops (FS has its own locking)
|
|
||||||
spinlock_release_irqrestore(&vfs_lock, flags);
|
spinlock_release_irqrestore(&vfs_lock, flags);
|
||||||
|
|
||||||
void *fs_handle = mount->ops->open(mount->fs_private, rel_path, mode);
|
void *fs_handle = mount->ops->open(mount->fs_private, rel_path, mode);
|
||||||
|
|
@ -338,9 +354,38 @@ void vfs_close(vfs_file_t *file) {
|
||||||
|
|
||||||
int vfs_read(vfs_file_t *file, void *buf, int size) {
|
int vfs_read(vfs_file_t *file, void *buf, int size) {
|
||||||
if (!file || !file->valid || !file->mount) return -1;
|
if (!file || !file->valid || !file->mount) return -1;
|
||||||
if (!file->mount->ops->read) return -1;
|
|
||||||
|
|
||||||
return file->mount->ops->read(file->mount->fs_private, file->fs_handle, buf, size);
|
if (file->is_device) {
|
||||||
|
Disk *d = (Disk*)file->fs_handle;
|
||||||
|
if (!d) return -1;
|
||||||
|
|
||||||
|
uint32_t total_read = 0;
|
||||||
|
uint32_t sector = (uint32_t)(file->position / 512);
|
||||||
|
uint32_t offset = (uint32_t)(file->position % 512);
|
||||||
|
uint8_t sector_buf[512];
|
||||||
|
|
||||||
|
while (total_read < (uint32_t)size) {
|
||||||
|
if (sector >= d->total_sectors) break;
|
||||||
|
if (d->read_sector(d, sector, sector_buf) != 0) break;
|
||||||
|
|
||||||
|
uint32_t to_copy = 512 - offset;
|
||||||
|
if (to_copy > (uint32_t)size - total_read) to_copy = (uint32_t)size - total_read;
|
||||||
|
|
||||||
|
extern void mem_memcpy(void *dest, const void *src, size_t len);
|
||||||
|
mem_memcpy((uint8_t*)buf + total_read, sector_buf + offset, to_copy);
|
||||||
|
|
||||||
|
total_read += to_copy;
|
||||||
|
file->position += to_copy;
|
||||||
|
sector++;
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
return (int)total_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file->mount->ops->read) return -1;
|
||||||
|
int ret = file->mount->ops->read(file->mount->fs_private, file->fs_handle, buf, size);
|
||||||
|
if (ret > 0) file->position += ret;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int vfs_write(vfs_file_t *file, const void *buf, int size) {
|
int vfs_write(vfs_file_t *file, const void *buf, int size) {
|
||||||
|
|
@ -352,32 +397,60 @@ int vfs_write(vfs_file_t *file, const void *buf, int size) {
|
||||||
|
|
||||||
int vfs_seek(vfs_file_t *file, int offset, int whence) {
|
int vfs_seek(vfs_file_t *file, int offset, int whence) {
|
||||||
if (!file || !file->valid || !file->mount) return -1;
|
if (!file || !file->valid || !file->mount) return -1;
|
||||||
|
|
||||||
|
if (file->is_device) {
|
||||||
|
Disk *d = (Disk*)file->fs_handle;
|
||||||
|
if (!d) return -1;
|
||||||
|
uint64_t new_pos = file->position;
|
||||||
|
if (whence == 0) new_pos = (uint64_t)offset; // SET
|
||||||
|
else if (whence == 1) new_pos += (uint64_t)offset; // CUR
|
||||||
|
else if (whence == 2) new_pos = (uint64_t)(d->total_sectors * 512 + offset); // END
|
||||||
|
|
||||||
|
if (new_pos > (uint64_t)d->total_sectors * 512) new_pos = (uint64_t)d->total_sectors * 512;
|
||||||
|
file->position = new_pos;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!file->mount->ops->seek) return -1;
|
if (!file->mount->ops->seek) return -1;
|
||||||
return file->mount->ops->seek(file->mount->fs_private, file->fs_handle, offset, whence);
|
int ret = file->mount->ops->seek(file->mount->fs_private, file->fs_handle, offset, whence);
|
||||||
|
if (ret == 0) {
|
||||||
|
// Sync position back from driver if possible
|
||||||
|
if (file->mount->ops->get_position) {
|
||||||
|
file->position = file->mount->ops->get_position(file->fs_handle);
|
||||||
|
} else {
|
||||||
|
// Manual sync if driver doesn't support get_position but seek succeeded
|
||||||
|
if (whence == 0) file->position = offset;
|
||||||
|
else if (whence == 1) file->position += offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t vfs_file_position(vfs_file_t *file) {
|
uint32_t vfs_file_position(vfs_file_t *file) {
|
||||||
if (!file || !file->valid || !file->mount) return 0;
|
if (!file || !file->valid || !file->mount) return 0;
|
||||||
|
if (file->is_device) return (uint32_t)file->position;
|
||||||
if (!file->mount->ops->get_position) return 0;
|
if (!file->mount->ops->get_position) return 0;
|
||||||
return file->mount->ops->get_position(file->fs_handle);
|
return file->mount->ops->get_position(file->fs_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t vfs_file_size(vfs_file_t *file) {
|
uint32_t vfs_file_size(vfs_file_t *file) {
|
||||||
if (!file || !file->valid || !file->mount) return 0;
|
if (!file || !file->valid || !file->mount) return 0;
|
||||||
|
if (file->is_device) {
|
||||||
|
Disk *d = (Disk*)file->fs_handle;
|
||||||
|
return d ? d->total_sectors * 512 : 0;
|
||||||
|
}
|
||||||
if (!file->mount->ops->get_size) return 0;
|
if (!file->mount->ops->get_size) return 0;
|
||||||
return file->mount->ops->get_size(file->fs_handle);
|
return file->mount->ops->get_size(file->fs_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// Directory Operations
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
int vfs_list_directory(const char *path, vfs_dirent_t *entries, int max) {
|
int vfs_list_directory(const char *path, vfs_dirent_t *entries, int max) {
|
||||||
if (!path || !entries) return -1;
|
if (!path || !entries) return -1;
|
||||||
|
|
||||||
|
|
||||||
char normalized[VFS_MAX_PATH];
|
char normalized[VFS_MAX_PATH];
|
||||||
vfs_normalize_path(path, normalized);
|
vfs_normalize_path("/", path, normalized);
|
||||||
|
|
||||||
const char *rel_path = NULL;
|
const char *rel_path = NULL;
|
||||||
vfs_mount_t *mount = vfs_resolve_mount(normalized, &rel_path);
|
vfs_mount_t *mount = vfs_resolve_mount(normalized, &rel_path);
|
||||||
|
|
@ -386,22 +459,19 @@ int vfs_list_directory(const char *path, vfs_dirent_t *entries, int max) {
|
||||||
if (mount && mount->ops->readdir) {
|
if (mount && mount->ops->readdir) {
|
||||||
if (!rel_path || rel_path[0] == '\0') rel_path = "/";
|
if (!rel_path || rel_path[0] == '\0') rel_path = "/";
|
||||||
count = mount->ops->readdir(mount->fs_private, rel_path, entries, max);
|
count = mount->ops->readdir(mount->fs_private, rel_path, entries, max);
|
||||||
if (count < 0) count = 0; // Treat as virtual if readdir fails
|
if (count < 0) count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge in other mount points that are direct children of this path
|
|
||||||
uint64_t v_flags = spinlock_acquire_irqsave(&vfs_lock);
|
uint64_t v_flags = spinlock_acquire_irqsave(&vfs_lock);
|
||||||
for (int i = 0; i < mount_count; i++) {
|
for (int i = 0; i < mount_count; i++) {
|
||||||
if (!mounts[i].active) continue;
|
if (!mounts[i].active) continue;
|
||||||
if (vfs_strcmp(mounts[i].path, normalized) == 0) continue; // Skip ourselves
|
if (vfs_strcmp(mounts[i].path, normalized) == 0) continue;
|
||||||
|
|
||||||
// Check if mount path starts with current path
|
if (vfs_path_is_parent(normalized, mounts[i].path)) {
|
||||||
if (vfs_starts_with(mounts[i].path, normalized)) {
|
|
||||||
const char *sub = mounts[i].path + vfs_strlen(normalized);
|
const char *sub = mounts[i].path + vfs_strlen(normalized);
|
||||||
if (*sub == '/') sub++; // skip slash
|
if (*sub == '/') sub++;
|
||||||
|
|
||||||
if (*sub != '\0') {
|
if (*sub != '\0') {
|
||||||
// Extract first component (direct child name)
|
|
||||||
char comp[VFS_MAX_NAME];
|
char comp[VFS_MAX_NAME];
|
||||||
int j = 0;
|
int j = 0;
|
||||||
while (sub[j] && sub[j] != '/' && j < VFS_MAX_NAME - 1) {
|
while (sub[j] && sub[j] != '/' && j < VFS_MAX_NAME - 1) {
|
||||||
|
|
@ -410,7 +480,6 @@ int vfs_list_directory(const char *path, vfs_dirent_t *entries, int max) {
|
||||||
}
|
}
|
||||||
comp[j] = 0;
|
comp[j] = 0;
|
||||||
|
|
||||||
// Check if already in results
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (int k = 0; k < count; k++) {
|
for (int k = 0; k < count; k++) {
|
||||||
if (vfs_strcmp(entries[k].name, comp) == 0) {
|
if (vfs_strcmp(entries[k].name, comp) == 0) {
|
||||||
|
|
@ -431,21 +500,24 @@ int vfs_list_directory(const char *path, vfs_dirent_t *entries, int max) {
|
||||||
}
|
}
|
||||||
spinlock_release_irqrestore(&vfs_lock, v_flags);
|
spinlock_release_irqrestore(&vfs_lock, v_flags);
|
||||||
|
|
||||||
// Special case: Ensure "dev" is visible in "/"
|
// Special case: Ensure "dev", "sys", "proc" are visible in "/"
|
||||||
if (vfs_strcmp(normalized, "/") == 0) {
|
if (vfs_strcmp(normalized, "/") == 0) {
|
||||||
bool found_dev = false;
|
const char *virtual_dirs[] = {"dev", "sys", "proc"};
|
||||||
for (int i = 0; i < count; i++) {
|
for (int v = 0; v < 3; v++) {
|
||||||
if (vfs_strcmp(entries[i].name, "dev") == 0) {
|
bool found = false;
|
||||||
found_dev = true;
|
for (int i = 0; i < count; i++) {
|
||||||
break;
|
if (vfs_strcmp(entries[i].name, virtual_dirs[v]) == 0) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found && count < max) {
|
||||||
|
vfs_strcpy(entries[count].name, virtual_dirs[v]);
|
||||||
|
entries[count].is_directory = 1;
|
||||||
|
entries[count].size = 0;
|
||||||
|
entries[count].start_cluster = 0;
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (!found_dev && count < max) {
|
|
||||||
vfs_strcpy(entries[count].name, "dev");
|
|
||||||
entries[count].is_directory = 1;
|
|
||||||
entries[count].size = 0;
|
|
||||||
entries[count].start_cluster = 0;
|
|
||||||
count++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -465,7 +537,7 @@ int vfs_list_directory(const char *path, vfs_dirent_t *entries, int max) {
|
||||||
if (!found) {
|
if (!found) {
|
||||||
vfs_strcpy(entries[count].name, d->devname);
|
vfs_strcpy(entries[count].name, d->devname);
|
||||||
entries[count].size = d->total_sectors * 512;
|
entries[count].size = d->total_sectors * 512;
|
||||||
entries[count].is_directory = d->is_partition ? 1 : 0;
|
entries[count].is_directory = 0;
|
||||||
entries[count].start_cluster = 0;
|
entries[count].start_cluster = 0;
|
||||||
entries[count].write_date = 0;
|
entries[count].write_date = 0;
|
||||||
entries[count].write_time = 0;
|
entries[count].write_time = 0;
|
||||||
|
|
@ -482,15 +554,14 @@ bool vfs_mkdir(const char *path) {
|
||||||
if (!path) return false;
|
if (!path) return false;
|
||||||
|
|
||||||
char normalized[VFS_MAX_PATH];
|
char normalized[VFS_MAX_PATH];
|
||||||
vfs_normalize_path(path, normalized);
|
vfs_normalize_path("/", path, normalized);
|
||||||
|
|
||||||
const char *rel_path = NULL;
|
const char *rel_path = NULL;
|
||||||
vfs_mount_t *mount = vfs_resolve_mount(normalized, &rel_path);
|
vfs_mount_t *mount = vfs_resolve_mount(normalized, &rel_path);
|
||||||
|
|
||||||
// If it's in /dev/, check if it's within a mounted volume deeper than the device node
|
|
||||||
if (vfs_starts_with(normalized, "/dev/")) {
|
if (vfs_starts_with(normalized, "/dev/")) {
|
||||||
if (!mount || !rel_path || rel_path[0] == '\0') {
|
if (!mount || !rel_path || rel_path[0] == '\0') {
|
||||||
return false; // Protect raw device nodes
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -502,19 +573,17 @@ bool vfs_rmdir(const char *path) {
|
||||||
if (!path) return false;
|
if (!path) return false;
|
||||||
|
|
||||||
char normalized[VFS_MAX_PATH];
|
char normalized[VFS_MAX_PATH];
|
||||||
vfs_normalize_path(path, normalized);
|
vfs_normalize_path("/", path, normalized);
|
||||||
|
|
||||||
// Protect root and virtual /dev directory itself
|
|
||||||
if (normalized[0] == '/' && normalized[1] == '\0') return false;
|
if (normalized[0] == '/' && normalized[1] == '\0') return false;
|
||||||
if (vfs_strcmp(normalized, "/dev") == 0) return false;
|
if (vfs_strcmp(normalized, "/dev") == 0) return false;
|
||||||
|
|
||||||
const char *rel_path = NULL;
|
const char *rel_path = NULL;
|
||||||
vfs_mount_t *mount = vfs_resolve_mount(normalized, &rel_path);
|
vfs_mount_t *mount = vfs_resolve_mount(normalized, &rel_path);
|
||||||
|
|
||||||
// If it's in /dev/, allow only if it's inside a mount beyond the device node
|
|
||||||
if (vfs_starts_with(normalized, "/dev/")) {
|
if (vfs_starts_with(normalized, "/dev/")) {
|
||||||
if (!mount || !rel_path || rel_path[0] == '\0') {
|
if (!mount || !rel_path || rel_path[0] == '\0') {
|
||||||
return false; // Protect raw device nodes
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -526,19 +595,17 @@ bool vfs_delete(const char *path) {
|
||||||
if (!path) return false;
|
if (!path) return false;
|
||||||
|
|
||||||
char normalized[VFS_MAX_PATH];
|
char normalized[VFS_MAX_PATH];
|
||||||
vfs_normalize_path(path, normalized);
|
vfs_normalize_path("/", path, normalized);
|
||||||
|
|
||||||
// Protect root and virtual /dev directory itself
|
|
||||||
if (normalized[0] == '/' && normalized[1] == '\0') return false;
|
if (normalized[0] == '/' && normalized[1] == '\0') return false;
|
||||||
if (vfs_strcmp(normalized, "/dev") == 0) return false;
|
if (vfs_strcmp(normalized, "/dev") == 0) return false;
|
||||||
|
|
||||||
const char *rel_path = NULL;
|
const char *rel_path = NULL;
|
||||||
vfs_mount_t *mount = vfs_resolve_mount(normalized, &rel_path);
|
vfs_mount_t *mount = vfs_resolve_mount(normalized, &rel_path);
|
||||||
|
|
||||||
// If it's in /dev/, allow only if it's inside a mount beyond the device node
|
|
||||||
if (vfs_starts_with(normalized, "/dev/")) {
|
if (vfs_starts_with(normalized, "/dev/")) {
|
||||||
if (!mount || !rel_path || rel_path[0] == '\0') {
|
if (!mount || !rel_path || rel_path[0] == '\0') {
|
||||||
return false; // Protect raw device nodes
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -550,14 +617,13 @@ bool vfs_rename(const char *old_path, const char *new_path) {
|
||||||
if (!old_path || !new_path) return false;
|
if (!old_path || !new_path) return false;
|
||||||
|
|
||||||
char norm_old[VFS_MAX_PATH], norm_new[VFS_MAX_PATH];
|
char norm_old[VFS_MAX_PATH], norm_new[VFS_MAX_PATH];
|
||||||
vfs_normalize_path(old_path, norm_old);
|
vfs_normalize_path("/", old_path, norm_old);
|
||||||
vfs_normalize_path(new_path, norm_new);
|
vfs_normalize_path("/", new_path, norm_new);
|
||||||
|
|
||||||
const char *rel_old = NULL, *rel_new = NULL;
|
const char *rel_old = NULL, *rel_new = NULL;
|
||||||
vfs_mount_t *mount_old = vfs_resolve_mount(norm_old, &rel_old);
|
vfs_mount_t *mount_old = vfs_resolve_mount(norm_old, &rel_old);
|
||||||
vfs_mount_t *mount_new = vfs_resolve_mount(norm_new, &rel_new);
|
vfs_mount_t *mount_new = vfs_resolve_mount(norm_new, &rel_new);
|
||||||
|
|
||||||
// Can only rename within the same mount
|
|
||||||
if (!mount_old || mount_old != mount_new) return false;
|
if (!mount_old || mount_old != mount_new) return false;
|
||||||
if (!mount_old->ops->rename) return false;
|
if (!mount_old->ops->rename) return false;
|
||||||
|
|
||||||
|
|
@ -567,20 +633,14 @@ bool vfs_rename(const char *old_path, const char *new_path) {
|
||||||
return mount_old->ops->rename(mount_old->fs_private, rel_old, rel_new);
|
return mount_old->ops->rename(mount_old->fs_private, rel_old, rel_new);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// Query Operations
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
bool vfs_exists(const char *path) {
|
bool vfs_exists(const char *path) {
|
||||||
if (!path) return false;
|
if (!path) return false;
|
||||||
|
|
||||||
char normalized[VFS_MAX_PATH];
|
char normalized[VFS_MAX_PATH];
|
||||||
vfs_normalize_path(path, normalized);
|
vfs_normalize_path("/", path, normalized);
|
||||||
|
|
||||||
// Root always exists
|
|
||||||
if (normalized[0] == '/' && normalized[1] == '\0') return true;
|
if (normalized[0] == '/' && normalized[1] == '\0') return true;
|
||||||
|
|
||||||
// Check if it's a prefix of any active mount point
|
|
||||||
uint64_t flags_vfs = spinlock_acquire_irqsave(&vfs_lock);
|
uint64_t flags_vfs = spinlock_acquire_irqsave(&vfs_lock);
|
||||||
for (int i = 0; i < mount_count; i++) {
|
for (int i = 0; i < mount_count; i++) {
|
||||||
if (mounts[i].active && vfs_starts_with(mounts[i].path, normalized)) {
|
if (mounts[i].active && vfs_starts_with(mounts[i].path, normalized)) {
|
||||||
|
|
@ -590,10 +650,10 @@ bool vfs_exists(const char *path) {
|
||||||
}
|
}
|
||||||
spinlock_release_irqrestore(&vfs_lock, flags_vfs);
|
spinlock_release_irqrestore(&vfs_lock, flags_vfs);
|
||||||
|
|
||||||
// /dev always exists as a virtual directory
|
if (vfs_strcmp(normalized, "/dev") == 0 ||
|
||||||
if (vfs_strcmp(normalized, "/dev") == 0) return true;
|
vfs_strcmp(normalized, "/sys") == 0 ||
|
||||||
|
vfs_strcmp(normalized, "/proc") == 0) return true;
|
||||||
|
|
||||||
// Check if it's a device in /dev
|
|
||||||
if (vfs_starts_with(normalized, "/dev/")) {
|
if (vfs_starts_with(normalized, "/dev/")) {
|
||||||
const char *dev = normalized + 5;
|
const char *dev = normalized + 5;
|
||||||
if (disk_get_by_name(dev)) return true;
|
if (disk_get_by_name(dev)) return true;
|
||||||
|
|
@ -603,7 +663,7 @@ bool vfs_exists(const char *path) {
|
||||||
vfs_mount_t *mount = vfs_resolve_mount(normalized, &rel_path);
|
vfs_mount_t *mount = vfs_resolve_mount(normalized, &rel_path);
|
||||||
if (!mount || !mount->ops->exists) return false;
|
if (!mount || !mount->ops->exists) return false;
|
||||||
|
|
||||||
if (!rel_path || rel_path[0] == '\0') return true; // Mount point itself exists
|
if (!rel_path || rel_path[0] == '\0') return true;
|
||||||
|
|
||||||
return mount->ops->exists(mount->fs_private, rel_path);
|
return mount->ops->exists(mount->fs_private, rel_path);
|
||||||
}
|
}
|
||||||
|
|
@ -612,43 +672,38 @@ bool vfs_is_directory(const char *path) {
|
||||||
if (!path) return false;
|
if (!path) return false;
|
||||||
|
|
||||||
char normalized[VFS_MAX_PATH];
|
char normalized[VFS_MAX_PATH];
|
||||||
vfs_normalize_path(path, normalized);
|
vfs_normalize_path("/", path, normalized);
|
||||||
|
|
||||||
// Root is always a directory
|
|
||||||
if (normalized[0] == '/' && normalized[1] == '\0') return true;
|
if (normalized[0] == '/' && normalized[1] == '\0') return true;
|
||||||
|
|
||||||
// Check if it's a prefix of any active mount point (virtual directory)
|
|
||||||
uint64_t flags_vfs = spinlock_acquire_irqsave(&vfs_lock);
|
uint64_t flags_vfs = spinlock_acquire_irqsave(&vfs_lock);
|
||||||
for (int i = 0; i < mount_count; i++) {
|
for (int i = 0; i < mount_count; i++) {
|
||||||
if (mounts[i].active && vfs_starts_with(mounts[i].path, normalized)) {
|
if (mounts[i].active && vfs_path_is_parent(normalized, mounts[i].path)) {
|
||||||
// If it matches exactly a mount point, we still need to check if that FS is a dir
|
|
||||||
if (vfs_strcmp(mounts[i].path, normalized) == 0) {
|
if (vfs_strcmp(mounts[i].path, normalized) == 0) {
|
||||||
// Exact mount point - it is a directory (mount root)
|
|
||||||
spinlock_release_irqrestore(&vfs_lock, flags_vfs);
|
spinlock_release_irqrestore(&vfs_lock, flags_vfs);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Prefix only - it is a virtual intermediate directory
|
// If normalized is a parent of a mount, it's a virtual directory
|
||||||
spinlock_release_irqrestore(&vfs_lock, flags_vfs);
|
spinlock_release_irqrestore(&vfs_lock, flags_vfs);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spinlock_release_irqrestore(&vfs_lock, flags_vfs);
|
spinlock_release_irqrestore(&vfs_lock, flags_vfs);
|
||||||
|
|
||||||
// /dev is always a virtual directory
|
if (vfs_strcmp(normalized, "/dev") == 0 ||
|
||||||
if (vfs_strcmp(normalized, "/dev") == 0) return true;
|
vfs_strcmp(normalized, "/sys") == 0 ||
|
||||||
|
vfs_strcmp(normalized, "/proc") == 0) return true;
|
||||||
|
|
||||||
// Device check
|
|
||||||
if (vfs_starts_with(normalized, "/dev/")) {
|
if (vfs_starts_with(normalized, "/dev/")) {
|
||||||
const char *dev = normalized + 5;
|
const char *dev = normalized + 5;
|
||||||
Disk *d = disk_get_by_name(dev);
|
Disk *d = disk_get_by_name(dev);
|
||||||
if (d) return d->is_partition ? true : false;
|
if (d) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *rel_path = NULL;
|
const char *rel_path = NULL;
|
||||||
vfs_mount_t *mount = vfs_resolve_mount(normalized, &rel_path);
|
vfs_mount_t *mount = vfs_resolve_mount(normalized, &rel_path);
|
||||||
if (!mount) return false;
|
if (!mount) return false;
|
||||||
|
|
||||||
// If it's a mount point and we're at its root, it definitely exists as a dir
|
|
||||||
if (!rel_path || rel_path[0] == '\0') return true;
|
if (!rel_path || rel_path[0] == '\0') return true;
|
||||||
|
|
||||||
if (!mount->ops->is_dir) return false;
|
if (!mount->ops->is_dir) return false;
|
||||||
|
|
@ -659,9 +714,8 @@ int vfs_get_info(const char *path, vfs_dirent_t *info) {
|
||||||
if (!path || !info) return -1;
|
if (!path || !info) return -1;
|
||||||
|
|
||||||
char normalized[VFS_MAX_PATH];
|
char normalized[VFS_MAX_PATH];
|
||||||
vfs_normalize_path(path, normalized);
|
vfs_normalize_path("/", path, normalized);
|
||||||
|
|
||||||
// Root info
|
|
||||||
if (normalized[0] == '/' && normalized[1] == '\0') {
|
if (normalized[0] == '/' && normalized[1] == '\0') {
|
||||||
vfs_strcpy(info->name, "/");
|
vfs_strcpy(info->name, "/");
|
||||||
info->size = 0;
|
info->size = 0;
|
||||||
|
|
@ -672,9 +726,11 @@ int vfs_get_info(const char *path, vfs_dirent_t *info) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// /dev virtual directory info
|
if (vfs_strcmp(normalized, "/dev") == 0 ||
|
||||||
if (vfs_strcmp(normalized, "/dev") == 0) {
|
vfs_strcmp(normalized, "/sys") == 0 ||
|
||||||
vfs_strcpy(info->name, "dev");
|
vfs_strcmp(normalized, "/proc") == 0) {
|
||||||
|
const char *name = normalized + 1;
|
||||||
|
vfs_strcpy(info->name, name);
|
||||||
info->size = 0;
|
info->size = 0;
|
||||||
info->is_directory = 1;
|
info->is_directory = 1;
|
||||||
info->start_cluster = 0;
|
info->start_cluster = 0;
|
||||||
|
|
@ -683,13 +739,10 @@ int vfs_get_info(const char *path, vfs_dirent_t *info) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if it's a prefix of any active mount point (virtual directory)
|
|
||||||
uint64_t flags_vfs = spinlock_acquire_irqsave(&vfs_lock);
|
uint64_t flags_vfs = spinlock_acquire_irqsave(&vfs_lock);
|
||||||
for (int i = 0; i < mount_count; i++) {
|
for (int i = 0; i < mount_count; i++) {
|
||||||
if (mounts[i].active && vfs_starts_with(mounts[i].path, normalized)) {
|
if (mounts[i].active && vfs_path_is_parent(normalized, mounts[i].path)) {
|
||||||
if (vfs_strcmp(mounts[i].path, normalized) != 0) {
|
if (vfs_strcmp(mounts[i].path, normalized) != 0) {
|
||||||
// Virtual intermediate directory
|
|
||||||
// Get component name
|
|
||||||
const char *p = normalized + vfs_strlen(normalized);
|
const char *p = normalized + vfs_strlen(normalized);
|
||||||
while (p > normalized && *(p-1) != '/') p--;
|
while (p > normalized && *(p-1) != '/') p--;
|
||||||
vfs_strcpy(info->name, p);
|
vfs_strcpy(info->name, p);
|
||||||
|
|
@ -712,7 +765,7 @@ int vfs_get_info(const char *path, vfs_dirent_t *info) {
|
||||||
if (d) {
|
if (d) {
|
||||||
vfs_strcpy(info->name, d->devname);
|
vfs_strcpy(info->name, d->devname);
|
||||||
info->size = d->total_sectors * 512;
|
info->size = d->total_sectors * 512;
|
||||||
info->is_directory = d->is_partition ? 1 : 0;
|
info->is_directory = 0;
|
||||||
info->start_cluster = 0;
|
info->start_cluster = 0;
|
||||||
info->write_date = 0;
|
info->write_date = 0;
|
||||||
info->write_time = 0;
|
info->write_time = 0;
|
||||||
|
|
@ -738,10 +791,6 @@ int vfs_get_info(const char *path, vfs_dirent_t *info) {
|
||||||
return mount->ops->get_info(mount->fs_private, rel_path, info);
|
return mount->ops->get_info(mount->fs_private, rel_path, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// Mount Enumeration
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
int vfs_get_mount_count(void) {
|
int vfs_get_mount_count(void) {
|
||||||
return mount_count;
|
return mount_count;
|
||||||
}
|
}
|
||||||
|
|
@ -752,12 +801,7 @@ vfs_mount_t* vfs_get_mount(int index) {
|
||||||
return &mounts[index];
|
return &mounts[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// Auto-Mount (called when a new partition is discovered)
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
void vfs_automount_partition(const char *devname) {
|
void vfs_automount_partition(const char *devname) {
|
||||||
// Build mount point: /mnt/<devname>
|
|
||||||
char mount_path[64] = "/mnt/";
|
char mount_path[64] = "/mnt/";
|
||||||
int i = 5;
|
int i = 5;
|
||||||
const char *d = devname;
|
const char *d = devname;
|
||||||
|
|
@ -769,8 +813,4 @@ void vfs_automount_partition(const char *devname) {
|
||||||
serial_write(" at ");
|
serial_write(" at ");
|
||||||
serial_write(mount_path);
|
serial_write(mount_path);
|
||||||
serial_write("\n");
|
serial_write("\n");
|
||||||
|
|
||||||
// The actual FAT32 volume creation and mount happens in disk_manager
|
|
||||||
// after probing the partition. This function is called by disk_manager
|
|
||||||
// after it has created the FAT32_Volume.
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,8 @@ struct vfs_file {
|
||||||
void *fs_handle; // FS-specific handle (e.g. FAT32_FileHandle*)
|
void *fs_handle; // FS-specific handle (e.g. FAT32_FileHandle*)
|
||||||
vfs_mount_t *mount; // Mount this file belongs to
|
vfs_mount_t *mount; // Mount this file belongs to
|
||||||
bool valid;
|
bool valid;
|
||||||
|
uint64_t position; // Current Seek Position (for raw devices/fallbacks)
|
||||||
|
bool is_device; // Is this a raw device handle?
|
||||||
};
|
};
|
||||||
|
|
||||||
// Mount entry
|
// Mount entry
|
||||||
|
|
@ -106,7 +108,7 @@ vfs_mount_t* vfs_get_mount(int index);
|
||||||
void vfs_automount_partition(const char *devname);
|
void vfs_automount_partition(const char *devname);
|
||||||
|
|
||||||
// Path utilities
|
// Path utilities
|
||||||
void vfs_normalize_path(const char *path, char *normalized);
|
void vfs_normalize_path(const char *cwd, const char *path, char *normalized);
|
||||||
|
|
||||||
// Backward compat: get position/size from vfs_file
|
// Backward compat: get position/size from vfs_file
|
||||||
uint32_t vfs_file_position(vfs_file_t *file);
|
uint32_t vfs_file_position(vfs_file_t *file);
|
||||||
|
|
|
||||||
73
src/sys/kernel_subsystem.c
Normal file
73
src/sys/kernel_subsystem.c
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
#include "kernel_subsystem.h"
|
||||||
|
#include "memory_manager.h"
|
||||||
|
#include "spinlock.h"
|
||||||
|
|
||||||
|
static kernel_subsystem_t subsystems[MAX_SUBSYSTEMS];
|
||||||
|
static int subsystem_count = 0;
|
||||||
|
static spinlock_t sub_lock = SPINLOCK_INIT;
|
||||||
|
|
||||||
|
extern void mem_memset(void *dest, int val, size_t len);
|
||||||
|
extern void mem_memcpy(void *dest, const void *src, size_t len);
|
||||||
|
|
||||||
|
static void sub_strcpy(char *dest, const char *src) {
|
||||||
|
while (*src) *dest++ = *src++;
|
||||||
|
*dest = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sub_strcmp(const char *a, const char *b) {
|
||||||
|
while (*a && *a == *b) { a++; b++; }
|
||||||
|
return (unsigned char)*a - (unsigned char)*b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void subsystem_register(const char *name, kernel_subsystem_t **out_sub) {
|
||||||
|
uint64_t flags = spinlock_acquire_irqsave(&sub_lock);
|
||||||
|
|
||||||
|
if (subsystem_count >= MAX_SUBSYSTEMS) {
|
||||||
|
spinlock_release_irqrestore(&sub_lock, flags);
|
||||||
|
if (out_sub) *out_sub = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if already exists
|
||||||
|
for (int i = 0; i < subsystem_count; i++) {
|
||||||
|
if (sub_strcmp(subsystems[i].name, name) == 0) {
|
||||||
|
spinlock_release_irqrestore(&sub_lock, flags);
|
||||||
|
if (out_sub) *out_sub = &subsystems[i];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel_subsystem_t *s = &subsystems[subsystem_count++];
|
||||||
|
mem_memset(s, 0, sizeof(kernel_subsystem_t));
|
||||||
|
sub_strcpy(s->name, name);
|
||||||
|
|
||||||
|
spinlock_release_irqrestore(&sub_lock, flags);
|
||||||
|
if (out_sub) *out_sub = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void subsystem_add_file(kernel_subsystem_t *sub, const char *name,
|
||||||
|
int (*read)(char*, int, int),
|
||||||
|
int (*write)(const char*, int, int)) {
|
||||||
|
if (!sub || sub->file_count >= MAX_SUBSYSTEM_FILES) return;
|
||||||
|
|
||||||
|
subsystem_file_t *f = &sub->files[sub->file_count++];
|
||||||
|
sub_strcpy(f->name, name);
|
||||||
|
f->read = read;
|
||||||
|
f->write = write;
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel_subsystem_t* subsystem_get_by_name(const char *name) {
|
||||||
|
for (int i = 0; i < subsystem_count; i++) {
|
||||||
|
if (sub_strcmp(subsystems[i].name, name) == 0) return &subsystems[i];
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int subsystem_get_count(void) {
|
||||||
|
return subsystem_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel_subsystem_t* subsystem_get_by_index(int index) {
|
||||||
|
if (index < 0 || index >= subsystem_count) return NULL;
|
||||||
|
return &subsystems[index];
|
||||||
|
}
|
||||||
32
src/sys/kernel_subsystem.h
Normal file
32
src/sys/kernel_subsystem.h
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef KERNEL_SUBSYSTEM_H
|
||||||
|
#define KERNEL_SUBSYSTEM_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#define MAX_SUBSYSTEMS 16
|
||||||
|
#define MAX_SUBSYSTEM_FILES 32
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char name[64];
|
||||||
|
int (*read)(char *buffer, int size, int offset);
|
||||||
|
int (*write)(const char *buffer, int size, int offset);
|
||||||
|
} subsystem_file_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char name[64];
|
||||||
|
subsystem_file_t files[MAX_SUBSYSTEM_FILES];
|
||||||
|
int file_count;
|
||||||
|
} kernel_subsystem_t;
|
||||||
|
|
||||||
|
void subsystem_register(const char *name, kernel_subsystem_t **out_sub);
|
||||||
|
void subsystem_add_file(kernel_subsystem_t *sub, const char *name,
|
||||||
|
int (*read)(char*, int, int),
|
||||||
|
int (*write)(const char*, int, int));
|
||||||
|
|
||||||
|
kernel_subsystem_t* subsystem_get_by_name(const char *name);
|
||||||
|
int subsystem_get_count(void);
|
||||||
|
kernel_subsystem_t* subsystem_get_by_index(int index);
|
||||||
|
|
||||||
|
#endif
|
||||||
29
src/sys/module_manager.c
Normal file
29
src/sys/module_manager.c
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
#include "module_manager.h"
|
||||||
|
#include "memory_manager.h"
|
||||||
|
|
||||||
|
#define MAX_MODULES 32
|
||||||
|
static kernel_module_t modules[MAX_MODULES];
|
||||||
|
static int module_count = 0;
|
||||||
|
|
||||||
|
static void mod_strcpy(char *dest, const char *src) {
|
||||||
|
while (*src) *dest++ = *src++;
|
||||||
|
*dest = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void module_manager_register(const char *name, uint64_t addr, uint64_t size) {
|
||||||
|
if (module_count >= MAX_MODULES) return;
|
||||||
|
|
||||||
|
kernel_module_t *m = &modules[module_count++];
|
||||||
|
mod_strcpy(m->name, name);
|
||||||
|
m->address = addr;
|
||||||
|
m->size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int module_manager_get_count(void) {
|
||||||
|
return module_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel_module_t* module_manager_get_index(int index) {
|
||||||
|
if (index < 0 || index >= module_count) return NULL;
|
||||||
|
return &modules[index];
|
||||||
|
}
|
||||||
17
src/sys/module_manager.h
Normal file
17
src/sys/module_manager.h
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef MODULE_MANAGER_H
|
||||||
|
#define MODULE_MANAGER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char name[64];
|
||||||
|
uint64_t address;
|
||||||
|
uint64_t size;
|
||||||
|
} kernel_module_t;
|
||||||
|
|
||||||
|
void module_manager_register(const char *name, uint64_t addr, uint64_t size);
|
||||||
|
int module_manager_get_count(void);
|
||||||
|
kernel_module_t* module_manager_get_index(int index);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -20,7 +20,6 @@ extern void serial_write(const char *str);
|
||||||
#define MAX_PROCESSES 16
|
#define MAX_PROCESSES 16
|
||||||
#define MAX_CPUS_SCHED 32
|
#define MAX_CPUS_SCHED 32
|
||||||
process_t processes[MAX_PROCESSES] __attribute__((aligned(16)));
|
process_t processes[MAX_PROCESSES] __attribute__((aligned(16)));
|
||||||
int process_count = 0;
|
|
||||||
static process_t* current_process[MAX_CPUS_SCHED] = {0}; // Per-CPU
|
static process_t* current_process[MAX_CPUS_SCHED] = {0}; // Per-CPU
|
||||||
static uint32_t next_pid = 0;
|
static uint32_t next_pid = 0;
|
||||||
static void *free_kernel_stack_later[MAX_CPUS_SCHED] = {0};
|
static void *free_kernel_stack_later[MAX_CPUS_SCHED] = {0};
|
||||||
|
|
@ -34,9 +33,10 @@ void process_init(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current kernel execution is PID 0
|
// Current kernel execution is PID 0
|
||||||
process_t *kernel_proc = &processes[process_count++];
|
process_t *kernel_proc = &processes[0];
|
||||||
kernel_proc->pid = next_pid++;
|
kernel_proc->pid = next_pid++;
|
||||||
kernel_proc->is_user = false;
|
kernel_proc->is_user = false;
|
||||||
|
kernel_proc->is_idle = true;
|
||||||
|
|
||||||
// We don't have its RSP or PML4 yet, but it's already running.
|
// We don't have its RSP or PML4 yet, but it's already running.
|
||||||
// The timer interrupt will naturally capture its context on the first tick!
|
// The timer interrupt will naturally capture its context on the first tick!
|
||||||
|
|
@ -55,21 +55,39 @@ void process_init(void) {
|
||||||
|
|
||||||
kernel_proc->next = kernel_proc; // Circular linked list
|
kernel_proc->next = kernel_proc; // Circular linked list
|
||||||
kernel_proc->cpu_affinity = 0; // Kernel always on BSP
|
kernel_proc->cpu_affinity = 0; // Kernel always on BSP
|
||||||
|
mem_memset(kernel_proc->cwd, 0, 1024);
|
||||||
|
kernel_proc->cwd[0] = '/';
|
||||||
current_process[0] = kernel_proc;
|
current_process[0] = kernel_proc;
|
||||||
}
|
}
|
||||||
|
|
||||||
process_t* process_create(void (*entry_point)(void), bool is_user) {
|
process_t* process_create(void (*entry_point)(void), bool is_user) {
|
||||||
uint64_t rflags = spinlock_acquire_irqsave(&runqueue_lock);
|
uint64_t rflags = spinlock_acquire_irqsave(&runqueue_lock);
|
||||||
|
|
||||||
if (process_count >= MAX_PROCESSES) {
|
process_t *new_proc = NULL;
|
||||||
|
for (int i = 0; i < MAX_PROCESSES; i++) {
|
||||||
|
if (processes[i].pid == 0xFFFFFFFF) {
|
||||||
|
new_proc = &processes[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!new_proc) {
|
||||||
spinlock_release_irqrestore(&runqueue_lock, rflags);
|
spinlock_release_irqrestore(&runqueue_lock, rflags);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
process_t *new_proc = &processes[process_count++];
|
|
||||||
new_proc->pid = next_pid++;
|
new_proc->pid = next_pid++;
|
||||||
new_proc->is_user = is_user;
|
new_proc->is_user = is_user;
|
||||||
|
|
||||||
|
process_t *parent = process_get_current();
|
||||||
|
if (parent) {
|
||||||
|
extern void mem_memcpy(void *dest, const void *src, size_t len);
|
||||||
|
mem_memcpy(new_proc->cwd, parent->cwd, 1024);
|
||||||
|
} else {
|
||||||
|
mem_memset(new_proc->cwd, 0, 1024);
|
||||||
|
new_proc->cwd[0] = '/';
|
||||||
|
}
|
||||||
|
|
||||||
// 1. Setup Page Table
|
// 1. Setup Page Table
|
||||||
if (is_user) {
|
if (is_user) {
|
||||||
new_proc->pml4_phys = paging_create_user_pml4_phys();
|
new_proc->pml4_phys = paging_create_user_pml4_phys();
|
||||||
|
|
@ -163,9 +181,8 @@ process_t* process_create_elf(const char* filepath, const char* args_str) {
|
||||||
|
|
||||||
// Find an available slot
|
// Find an available slot
|
||||||
for (int i = 0; i < MAX_PROCESSES; i++) {
|
for (int i = 0; i < MAX_PROCESSES; i++) {
|
||||||
if (processes[i].pid == 0xFFFFFFFF || i >= process_count) {
|
if (processes[i].pid == 0xFFFFFFFF) {
|
||||||
new_proc = &processes[i];
|
new_proc = &processes[i];
|
||||||
if (i >= process_count) process_count = i + 1;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,9 @@ typedef struct process {
|
||||||
uint64_t ticks;
|
uint64_t ticks;
|
||||||
uint64_t sleep_until;
|
uint64_t sleep_until;
|
||||||
size_t used_memory;
|
size_t used_memory;
|
||||||
uint32_t cpu_affinity; // Which CPU this process runs on (0 = BSP)
|
uint32_t cpu_affinity;
|
||||||
|
bool is_idle;
|
||||||
|
char cwd[1024];
|
||||||
} __attribute__((aligned(16))) process_t;
|
} __attribute__((aligned(16))) process_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -60,6 +62,7 @@ typedef struct {
|
||||||
char name[64];
|
char name[64];
|
||||||
uint64_t ticks;
|
uint64_t ticks;
|
||||||
size_t used_memory;
|
size_t used_memory;
|
||||||
|
bool is_idle;
|
||||||
} ProcessInfo;
|
} ProcessInfo;
|
||||||
|
|
||||||
void process_init(void);
|
void process_init(void);
|
||||||
|
|
@ -73,7 +76,7 @@ uint64_t process_terminate_current(void);
|
||||||
void process_terminate(process_t *proc);
|
void process_terminate(process_t *proc);
|
||||||
process_t* process_get_by_pid(uint32_t pid);
|
process_t* process_get_by_pid(uint32_t pid);
|
||||||
|
|
||||||
// SMP: IPI handler for AP scheduling (called from ISR)
|
// SMP: IPI handler for AP scheduling
|
||||||
uint64_t sched_ipi_handler(registers_t *regs);
|
uint64_t sched_ipi_handler(registers_t *regs);
|
||||||
|
|
||||||
void process_push_gui_event(process_t *proc, gui_event_t *ev);
|
void process_push_gui_event(process_t *proc, gui_event_t *ev);
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#include "paging.h"
|
#include "paging.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "work_queue.h"
|
#include "work_queue.h"
|
||||||
|
#include "core/kutils.h"
|
||||||
|
|
||||||
extern void serial_write(const char *str);
|
extern void serial_write(const char *str);
|
||||||
extern void serial_write_num(uint32_t n);
|
extern void serial_write_num(uint32_t n);
|
||||||
|
|
@ -108,6 +109,11 @@ static void ap_entry(struct limine_smp_info *info) {
|
||||||
|
|
||||||
process_t *ap_idle = process_create(NULL, false);
|
process_t *ap_idle = process_create(NULL, false);
|
||||||
ap_idle->cpu_affinity = my_id;
|
ap_idle->cpu_affinity = my_id;
|
||||||
|
ap_idle->is_idle = true;
|
||||||
|
k_strcpy(ap_idle->name, "idle:");
|
||||||
|
char id_s[8]; k_itoa(my_id, id_s);
|
||||||
|
k_strcpy(ap_idle->name + 5, id_s);
|
||||||
|
|
||||||
process_set_current_for_cpu(my_id, ap_idle);
|
process_set_current_for_cpu(my_id, ap_idle);
|
||||||
asm volatile("sti");
|
asm volatile("sti");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -861,6 +861,8 @@ static uint64_t syscall_handler_inner(registers_t *regs) {
|
||||||
const char *mode = (const char *)arg3;
|
const char *mode = (const char *)arg3;
|
||||||
if (!path || !mode) return -1;
|
if (!path || !mode) return -1;
|
||||||
|
|
||||||
|
// vfs_open now handles normalization internally with process_get_current()
|
||||||
|
// but let's be explicit if we can.
|
||||||
vfs_file_t *vf = vfs_open(path, mode);
|
vfs_file_t *vf = vfs_open(path, mode);
|
||||||
if (!vf) return -1;
|
if (!vf) return -1;
|
||||||
|
|
||||||
|
|
@ -904,12 +906,33 @@ static uint64_t syscall_handler_inner(registers_t *regs) {
|
||||||
int fd = (int)arg2;
|
int fd = (int)arg2;
|
||||||
if (fd < 0 || fd >= MAX_PROCESS_FDS || !proc->fds[fd]) return -1;
|
if (fd < 0 || fd >= MAX_PROCESS_FDS || !proc->fds[fd]) return -1;
|
||||||
return (uint64_t)vfs_file_size((vfs_file_t*)proc->fds[fd]);
|
return (uint64_t)vfs_file_size((vfs_file_t*)proc->fds[fd]);
|
||||||
|
} else if (cmd == FS_CMD_GETCWD) {
|
||||||
|
char *buf = (char *)arg2;
|
||||||
|
int size = (int)arg3;
|
||||||
|
if (!buf || size <= 0) return -1;
|
||||||
|
int len = (int)k_strlen(proc->cwd);
|
||||||
|
if (len >= size) return -1;
|
||||||
|
k_strcpy(buf, proc->cwd);
|
||||||
|
return (uint64_t)len;
|
||||||
|
} else if (cmd == FS_CMD_CHDIR) {
|
||||||
|
const char *path = (const char *)arg2;
|
||||||
|
if (!path) return -1;
|
||||||
|
char normalized[VFS_MAX_PATH];
|
||||||
|
vfs_normalize_path(proc->cwd, path, normalized);
|
||||||
|
if (vfs_is_directory(normalized)) {
|
||||||
|
k_strcpy(proc->cwd, normalized);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
} else if (cmd == FS_CMD_LIST) {
|
} else if (cmd == FS_CMD_LIST) {
|
||||||
const char *path = (const char *)arg2;
|
const char *path = (const char *)arg2;
|
||||||
FAT32_FileInfo *u_entries = (FAT32_FileInfo *)arg3;
|
FAT32_FileInfo *u_entries = (FAT32_FileInfo *)arg3;
|
||||||
int max_entries = (int)arg4;
|
int max_entries = (int)arg4;
|
||||||
if (!path || !u_entries) return -1;
|
if (!path || !u_entries) return -1;
|
||||||
|
|
||||||
|
char normalized[VFS_MAX_PATH];
|
||||||
|
vfs_normalize_path(proc->cwd, path, normalized);
|
||||||
|
|
||||||
// Safety cap for kernel allocation
|
// Safety cap for kernel allocation
|
||||||
if (max_entries > 256) max_entries = 256;
|
if (max_entries > 256) max_entries = 256;
|
||||||
if (max_entries <= 0) return 0;
|
if (max_entries <= 0) return 0;
|
||||||
|
|
@ -917,7 +940,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) {
|
||||||
vfs_dirent_t *v_entries = (vfs_dirent_t *)kmalloc(sizeof(vfs_dirent_t) * max_entries);
|
vfs_dirent_t *v_entries = (vfs_dirent_t *)kmalloc(sizeof(vfs_dirent_t) * max_entries);
|
||||||
if (!v_entries) return -1;
|
if (!v_entries) return -1;
|
||||||
|
|
||||||
int count = vfs_list_directory(path, v_entries, max_entries);
|
int count = vfs_list_directory(normalized, v_entries, max_entries);
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
// Direct copy as layouts are now aligned
|
// Direct copy as layouts are now aligned
|
||||||
|
|
@ -934,14 +957,19 @@ static uint64_t syscall_handler_inner(registers_t *regs) {
|
||||||
} else if (cmd == FS_CMD_DELETE) {
|
} else if (cmd == FS_CMD_DELETE) {
|
||||||
const char *path = (const char *)arg2;
|
const char *path = (const char *)arg2;
|
||||||
if (!path) return -1;
|
if (!path) return -1;
|
||||||
return vfs_delete(path) ? 0 : -1;
|
char normalized[VFS_MAX_PATH];
|
||||||
|
vfs_normalize_path(proc->cwd, path, normalized);
|
||||||
|
return vfs_delete(normalized) ? 0 : -1;
|
||||||
} else if (cmd == FS_CMD_GET_INFO) {
|
} else if (cmd == FS_CMD_GET_INFO) {
|
||||||
const char *path = (const char *)arg2;
|
const char *path = (const char *)arg2;
|
||||||
FAT32_FileInfo *u_info = (FAT32_FileInfo *)arg3;
|
FAT32_FileInfo *u_info = (FAT32_FileInfo *)arg3;
|
||||||
if (!path || !u_info) return -1;
|
if (!path || !u_info) return -1;
|
||||||
|
|
||||||
|
char normalized[VFS_MAX_PATH];
|
||||||
|
vfs_normalize_path(proc->cwd, path, normalized);
|
||||||
|
|
||||||
vfs_dirent_t v_info;
|
vfs_dirent_t v_info;
|
||||||
int res = vfs_get_info(path, &v_info);
|
int res = vfs_get_info(normalized, &v_info);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
k_strcpy(u_info->name, v_info.name);
|
k_strcpy(u_info->name, v_info.name);
|
||||||
u_info->size = v_info.size;
|
u_info->size = v_info.size;
|
||||||
|
|
@ -1096,15 +1124,6 @@ static uint64_t syscall_handler_inner(registers_t *regs) {
|
||||||
extern void k_beep(int freq, int ms);
|
extern void k_beep(int freq, int ms);
|
||||||
k_beep(freq, ms);
|
k_beep(freq, ms);
|
||||||
return 0;
|
return 0;
|
||||||
} else if (cmd == 15) { // SYSTEM_CMD_MEMINFO
|
|
||||||
uint64_t *out = (uint64_t *)arg2;
|
|
||||||
if (!out) return -1;
|
|
||||||
MemStats stats = memory_get_stats();
|
|
||||||
out[0] = stats.total_memory;
|
|
||||||
out[1] = stats.used_memory;
|
|
||||||
return 0;
|
|
||||||
} else if (cmd == 16) { // SYSTEM_CMD_UPTIME
|
|
||||||
return wm_get_ticks();
|
|
||||||
} else if (cmd == 17) { // SYSTEM_CMD_PCI_LIST
|
} else if (cmd == 17) { // SYSTEM_CMD_PCI_LIST
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint16_t vendor;
|
uint16_t vendor;
|
||||||
|
|
@ -1265,54 +1284,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) {
|
||||||
size_t max_len = (size_t)arg3;
|
size_t max_len = (size_t)arg3;
|
||||||
extern int network_tcp_recv_nb(void *buf, size_t max_len);
|
extern int network_tcp_recv_nb(void *buf, size_t max_len);
|
||||||
return (uint64_t)network_tcp_recv_nb(buf, max_len);
|
return (uint64_t)network_tcp_recv_nb(buf, max_len);
|
||||||
} else if (cmd == SYSTEM_CMD_PROCESS_LIST) {
|
return -1;
|
||||||
ProcessInfo *out = (ProcessInfo *)arg2;
|
|
||||||
int max_procs = (int)arg3;
|
|
||||||
if (!out) return 0;
|
|
||||||
|
|
||||||
extern process_t processes[];
|
|
||||||
|
|
||||||
// Dynamically calculate kernel usage as: Total System Used - User Process Sum
|
|
||||||
MemStats stats = memory_get_stats();
|
|
||||||
size_t total_used = stats.used_memory;
|
|
||||||
size_t user_used = 0;
|
|
||||||
for (int i = 0; i < 16; i++) {
|
|
||||||
if (processes[i].pid != 0xFFFFFFFF && processes[i].pid != 0 && processes[i].is_user) {
|
|
||||||
user_used += processes[i].used_memory;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (total_used > user_used) processes[0].used_memory = total_used - user_used;
|
|
||||||
else processes[0].used_memory = 0;
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
for (int i = 0; i < 16; i++) {
|
|
||||||
if (processes[i].pid != 0xFFFFFFFF && (processes[i].is_user || processes[i].pid == 0)) {
|
|
||||||
out[count].pid = processes[i].pid;
|
|
||||||
extern void mem_memcpy(void *dest, const void *src, size_t len);
|
|
||||||
mem_memcpy(out[count].name, processes[i].name, 64);
|
|
||||||
|
|
||||||
if (processes[i].pid == 0) {
|
|
||||||
out[count].name[0] = 'k'; out[count].name[1] = 'e'; out[count].name[2] = 'r';
|
|
||||||
out[count].name[3] = 'n'; out[count].name[4] = 'e'; out[count].name[5] = 'l';
|
|
||||||
out[count].name[6] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
out[count].ticks = processes[i].ticks;
|
|
||||||
out[count].used_memory = processes[i].used_memory;
|
|
||||||
|
|
||||||
count++;
|
|
||||||
if (count >= max_procs) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (uint64_t)count;
|
|
||||||
} else if (cmd == SYSTEM_CMD_GET_CPU_MODEL) {
|
|
||||||
char *user_buf = (char *)arg2;
|
|
||||||
if (!user_buf) return -1;
|
|
||||||
char model[64];
|
|
||||||
platform_get_cpu_model(model);
|
|
||||||
extern void mem_memcpy(void *dest, const void *src, size_t len);
|
|
||||||
mem_memcpy(user_buf, model, 49);
|
|
||||||
return 0;
|
|
||||||
} else if (cmd == 47) { // SYSTEM_CMD_SET_RESOLUTION
|
} else if (cmd == 47) { // SYSTEM_CMD_SET_RESOLUTION
|
||||||
uint16_t req_w = (uint16_t)arg2;
|
uint16_t req_w = (uint16_t)arg2;
|
||||||
uint16_t req_h = (uint16_t)arg3;
|
uint16_t req_h = (uint16_t)arg3;
|
||||||
|
|
@ -1351,12 +1323,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
} else if (cmd == 49) { // SYSTEM_CMD_GET_OS_INFO
|
return -1;
|
||||||
os_info_t *info = (os_info_t *)arg2;
|
|
||||||
if (!info) return -1;
|
|
||||||
extern void get_os_info(os_info_t *info);
|
|
||||||
get_os_info(info);
|
|
||||||
return 0;
|
|
||||||
} else if (cmd == SYSTEM_CMD_PARALLEL_RUN) {
|
} else if (cmd == SYSTEM_CMD_PARALLEL_RUN) {
|
||||||
void (*user_fn)(void*) = (void (*)(void*))arg2;
|
void (*user_fn)(void*) = (void (*)(void*))arg2;
|
||||||
void **args = (void **)arg3;
|
void **args = (void **)arg3;
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
// Forward declarations
|
|
||||||
typedef struct Window Window;
|
typedef struct Window Window;
|
||||||
typedef struct registers_t registers_t;
|
typedef struct registers_t registers_t;
|
||||||
|
|
||||||
|
|
@ -53,11 +52,8 @@ typedef struct {
|
||||||
#define SYSTEM_CMD_SET_RAW_MODE 41
|
#define SYSTEM_CMD_SET_RAW_MODE 41
|
||||||
#define SYSTEM_CMD_TCP_RECV_NB 42
|
#define SYSTEM_CMD_TCP_RECV_NB 42
|
||||||
#define SYSTEM_CMD_YIELD 43
|
#define SYSTEM_CMD_YIELD 43
|
||||||
#define SYSTEM_CMD_PROCESS_LIST 44
|
|
||||||
#define SYSTEM_CMD_GET_CPU_MODEL 45
|
|
||||||
#define SYSTEM_CMD_SLEEP 46
|
#define SYSTEM_CMD_SLEEP 46
|
||||||
#define SYSTEM_CMD_SET_RESOLUTION 47
|
#define SYSTEM_CMD_SET_RESOLUTION 47
|
||||||
#define SYSTEM_CMD_GET_OS_INFO 49
|
|
||||||
#define SYSTEM_CMD_PARALLEL_RUN 50
|
#define SYSTEM_CMD_PARALLEL_RUN 50
|
||||||
|
|
||||||
void syscall_init(void);
|
void syscall_init(void);
|
||||||
|
|
|
||||||
201
src/sys/sysfs_init.c
Normal file
201
src/sys/sysfs_init.c
Normal file
|
|
@ -0,0 +1,201 @@
|
||||||
|
#include "kernel_subsystem.h"
|
||||||
|
#include "smp.h"
|
||||||
|
#include "pci.h"
|
||||||
|
#include "memory_manager.h"
|
||||||
|
#include "module_manager.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "core/kutils.h"
|
||||||
|
#include "wm/graphics.h"
|
||||||
|
#include "core/platform.h"
|
||||||
|
|
||||||
|
// --- Helper: itoa ---
|
||||||
|
static void sys_itoa(int n, char *s) {
|
||||||
|
k_itoa(n, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Graphics Implementation ---
|
||||||
|
static int read_gfx_drm(char *buf, int size, int offset) {
|
||||||
|
char out[512];
|
||||||
|
k_memset(out, 0, 512);
|
||||||
|
k_strcpy(out, "Driver: Simple Framebuffer\n");
|
||||||
|
k_strcpy(out + k_strlen(out), "Resolution: ");
|
||||||
|
char s[32]; k_itoa(get_screen_width(), s);
|
||||||
|
k_strcpy(out + k_strlen(out), s);
|
||||||
|
k_strcpy(out + k_strlen(out), "x");
|
||||||
|
k_itoa(get_screen_height(), s);
|
||||||
|
k_strcpy(out + k_strlen(out), s);
|
||||||
|
k_strcpy(out + k_strlen(out), "\nDepth: ");
|
||||||
|
k_itoa(graphics_get_fb_bpp(), s);
|
||||||
|
k_strcpy(out + k_strlen(out), s);
|
||||||
|
k_strcpy(out + k_strlen(out), " bpp\nAddress: 0x");
|
||||||
|
k_itoa_hex(graphics_get_fb_addr(), s);
|
||||||
|
k_strcpy(out + k_strlen(out), s);
|
||||||
|
k_strcpy(out + k_strlen(out), "\n");
|
||||||
|
|
||||||
|
int len = (int)k_strlen(out);
|
||||||
|
if (offset >= len) return 0;
|
||||||
|
int to_copy = len - offset;
|
||||||
|
if (to_copy > size) to_copy = size;
|
||||||
|
k_memcpy(buf, out + offset, to_copy);
|
||||||
|
return to_copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Memory Tracking Implementation ---
|
||||||
|
static int read_mem_tracking(char *buf, int size, int offset) {
|
||||||
|
MemStats stats = memory_get_stats();
|
||||||
|
char out[1024];
|
||||||
|
k_memset(out, 0, 1024);
|
||||||
|
|
||||||
|
k_strcpy(out, "--- Kernel Heap Tracking ---\n");
|
||||||
|
k_strcpy(out + k_strlen(out), "Allocated Blocks: ");
|
||||||
|
char s[32]; k_itoa(stats.allocated_blocks, s);
|
||||||
|
k_strcpy(out + k_strlen(out), s);
|
||||||
|
k_strcpy(out + k_strlen(out), "\nFragmentation: ");
|
||||||
|
k_itoa(stats.fragmentation_percent, s);
|
||||||
|
k_strcpy(out + k_strlen(out), s);
|
||||||
|
k_strcpy(out + k_strlen(out), "%\n");
|
||||||
|
|
||||||
|
int len = (int)k_strlen(out);
|
||||||
|
if (offset >= len) return 0;
|
||||||
|
int to_copy = len - offset;
|
||||||
|
if (to_copy > size) to_copy = size;
|
||||||
|
k_memcpy(buf, out + offset, to_copy);
|
||||||
|
return to_copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Module Implementation ---
|
||||||
|
static int read_sys_modules(char *buf, int size, int offset) {
|
||||||
|
int count = module_manager_get_count();
|
||||||
|
char out[2048] = "Loaded Modules:\n";
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
kernel_module_t *mod = module_manager_get_index(i);
|
||||||
|
k_strcpy(out + k_strlen(out), " - ");
|
||||||
|
k_strcpy(out + k_strlen(out), mod->name);
|
||||||
|
k_strcpy(out + k_strlen(out), " (");
|
||||||
|
char sz_s[16]; k_itoa(mod->size / 1024, sz_s);
|
||||||
|
k_strcpy(out + k_strlen(out), sz_s);
|
||||||
|
k_strcpy(out + k_strlen(out), " KB)\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int len = k_strlen(out);
|
||||||
|
if (offset >= len) return 0;
|
||||||
|
int to_copy = len - offset;
|
||||||
|
if (to_copy > size) to_copy = size;
|
||||||
|
k_memcpy(buf, out + offset, to_copy);
|
||||||
|
return to_copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- PCI Bus Implementation ---
|
||||||
|
static int read_pci_bus(char *buf, int size, int offset) {
|
||||||
|
pci_device_t devices[64];
|
||||||
|
int count = pci_enumerate_devices(devices, 64);
|
||||||
|
|
||||||
|
char out[4096];
|
||||||
|
k_memset(out, 0, 4096);
|
||||||
|
k_strcpy(out, "PCI Bus Devices:\n");
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
char line[128];
|
||||||
|
k_strcpy(line, " [");
|
||||||
|
char b_s[8]; k_itoa(devices[i].bus, b_s);
|
||||||
|
k_strcpy(line + k_strlen(line), b_s);
|
||||||
|
k_strcpy(line + k_strlen(line), ":");
|
||||||
|
k_itoa(devices[i].device, b_s);
|
||||||
|
k_strcpy(line + k_strlen(line), b_s);
|
||||||
|
k_strcpy(line + k_strlen(line), ":");
|
||||||
|
k_itoa(devices[i].function, b_s);
|
||||||
|
k_strcpy(line + k_strlen(line), b_s);
|
||||||
|
k_strcpy(line + k_strlen(line), "] Vendor:");
|
||||||
|
k_itoa_hex(devices[i].vendor_id, b_s);
|
||||||
|
k_strcpy(line + k_strlen(line), b_s);
|
||||||
|
k_strcpy(line + k_strlen(line), " Device:");
|
||||||
|
k_itoa_hex(devices[i].device_id, b_s);
|
||||||
|
k_strcpy(line + k_strlen(line), b_s);
|
||||||
|
k_strcpy(line + k_strlen(line), " Class:");
|
||||||
|
k_itoa_hex(devices[i].class_code, b_s);
|
||||||
|
k_strcpy(line + k_strlen(line), b_s);
|
||||||
|
k_strcpy(line + k_strlen(line), "\n");
|
||||||
|
|
||||||
|
if (k_strlen(out) + k_strlen(line) < 4095) {
|
||||||
|
k_strcpy(out + k_strlen(out), line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int len = (int)k_strlen(out);
|
||||||
|
if (offset >= len) return 0;
|
||||||
|
int to_copy = len - offset;
|
||||||
|
if (to_copy > size) to_copy = size;
|
||||||
|
k_memcpy(buf, out + offset, to_copy);
|
||||||
|
return to_copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- CPU System Implementation ---
|
||||||
|
static int read_cpu_info(char *buf, int size, int offset) {
|
||||||
|
char out[1024];
|
||||||
|
k_memset(out, 0, 1024);
|
||||||
|
char vendor[16];
|
||||||
|
platform_get_cpu_vendor(vendor);
|
||||||
|
k_strcpy(out + k_strlen(out), vendor);
|
||||||
|
k_strcpy(out + k_strlen(out), "\nCores: ");
|
||||||
|
char c_s[16]; k_itoa(smp_cpu_count(), c_s);
|
||||||
|
k_strcpy(out + k_strlen(out), c_s);
|
||||||
|
k_strcpy(out + k_strlen(out), "\nSpeed: ~3.00 GHz\nFeatures: sse sse2 sse3 apic smp\n");
|
||||||
|
|
||||||
|
int len = (int)k_strlen(out);
|
||||||
|
if (offset >= len) return 0;
|
||||||
|
int to_copy = len - offset;
|
||||||
|
if (to_copy > size) to_copy = size;
|
||||||
|
k_memcpy(buf, out + offset, to_copy);
|
||||||
|
return to_copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- GPIO Implementation ---
|
||||||
|
static int read_gpio_debug(char *buf, int size, int offset) {
|
||||||
|
uint8_t p64 = inb(0x64);
|
||||||
|
char out[64] = "Port 0x64 Status: ";
|
||||||
|
char s[16]; k_itoa(p64, s);
|
||||||
|
k_strcpy(out + k_strlen(out), s);
|
||||||
|
k_strcpy(out + k_strlen(out), "\n");
|
||||||
|
|
||||||
|
int len = k_strlen(out);
|
||||||
|
if (offset >= len) return 0;
|
||||||
|
int to_copy = len - offset;
|
||||||
|
if (to_copy > size) to_copy = size;
|
||||||
|
k_memcpy(buf, out + offset, to_copy);
|
||||||
|
return to_copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sysfs_init_subsystems(void) {
|
||||||
|
kernel_subsystem_t *kernel, *devices, *bus, *class, *debug, *mem_debug;
|
||||||
|
|
||||||
|
subsystem_register("kernel", &kernel);
|
||||||
|
subsystem_register("devices", &devices);
|
||||||
|
subsystem_register("bus", &bus);
|
||||||
|
subsystem_register("class", &class);
|
||||||
|
subsystem_register("kernel/debug", &debug);
|
||||||
|
|
||||||
|
// CPU info
|
||||||
|
subsystem_add_file(kernel, "cpuinfo", read_cpu_info, NULL);
|
||||||
|
|
||||||
|
// Bus info
|
||||||
|
kernel_subsystem_t *pci_bus;
|
||||||
|
subsystem_register("bus/pci", &pci_bus);
|
||||||
|
subsystem_add_file(pci_bus, "devices", read_pci_bus, NULL);
|
||||||
|
|
||||||
|
// Module info
|
||||||
|
kernel_subsystem_t *modules_sub;
|
||||||
|
subsystem_register("module", &modules_sub);
|
||||||
|
subsystem_add_file(modules_sub, "loaded", read_sys_modules, NULL);
|
||||||
|
|
||||||
|
// Memory Tracking
|
||||||
|
subsystem_register("kernel/debug/memory", &mem_debug);
|
||||||
|
subsystem_add_file(mem_debug, "tracking", read_mem_tracking, NULL);
|
||||||
|
|
||||||
|
// Graphics DRM
|
||||||
|
kernel_subsystem_t *gfx_debug;
|
||||||
|
subsystem_register("kernel/debug/graphics", &gfx_debug);
|
||||||
|
subsystem_add_file(gfx_debug, "drm", read_gfx_drm, NULL);
|
||||||
|
|
||||||
|
// GPIO
|
||||||
|
subsystem_add_file(debug, "gpio", read_gpio_debug, NULL);
|
||||||
|
}
|
||||||
|
|
@ -14,7 +14,7 @@ int main(int argc, char **argv) {
|
||||||
printf("Manual for: %s\n", argv[1]);
|
printf("Manual for: %s\n", argv[1]);
|
||||||
printf("---------------------------\n");
|
printf("---------------------------\n");
|
||||||
|
|
||||||
strcpy(path, "A:/Library/man/");
|
strcpy(path, "/Library/man/");
|
||||||
strcat(path, argv[1]);
|
strcat(path, argv[1]);
|
||||||
strcat(path, ".txt");
|
strcat(path, ".txt");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,15 +9,6 @@
|
||||||
#define MAX_ASCII_WIDTH 80
|
#define MAX_ASCII_WIDTH 80
|
||||||
#define MAX_INFO_LINES 10
|
#define MAX_INFO_LINES 10
|
||||||
|
|
||||||
static char* strchr(const char *s, int c) {
|
|
||||||
while (*s != (char)c) {
|
|
||||||
if (!*s++) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (char *)s;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char* strncpy(char *dest, const char *src, size_t n) {
|
static char* strncpy(char *dest, const char *src, size_t n) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < n && src[i] != '\0'; i++) dest[i] = src[i];
|
for (i = 0; i < n && src[i] != '\0'; i++) dest[i] = src[i];
|
||||||
|
|
@ -117,7 +108,7 @@ static char* trim(char *str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_config_defaults() {
|
static void set_config_defaults() {
|
||||||
strcpy(config.ascii_art_file, "A:/Library/art/boredos.txt");
|
strcpy(config.ascii_art_file, "/Library/art/boredos.txt");
|
||||||
strcpy(config.user_host_string, "root@boredos");
|
strcpy(config.user_host_string, "root@boredos");
|
||||||
strcpy(config.separator, "------------");
|
strcpy(config.separator, "------------");
|
||||||
strcpy(config.os_label, "OS");
|
strcpy(config.os_label, "OS");
|
||||||
|
|
@ -160,7 +151,7 @@ static void parse_config(char* buffer) {
|
||||||
|
|
||||||
static void load_config() {
|
static void load_config() {
|
||||||
set_config_defaults();
|
set_config_defaults();
|
||||||
int fd = sys_open("A:/Library/conf/sysfetch.cfg", "r");
|
int fd = sys_open("/Library/conf/sysfetch.cfg", "r");
|
||||||
if (fd < 0) return;
|
if (fd < 0) return;
|
||||||
|
|
||||||
char *buffer = malloc(4096);
|
char *buffer = malloc(4096);
|
||||||
|
|
@ -237,52 +228,82 @@ int main(int argc, char **argv) {
|
||||||
if (config.separator[0]) {
|
if (config.separator[0]) {
|
||||||
strcpy(info_lines[info_line_count++], config.separator);
|
strcpy(info_lines[info_line_count++], config.separator);
|
||||||
}
|
}
|
||||||
os_info_t os_info;
|
// Helper for proc parsing
|
||||||
sys_get_os_info(&os_info);
|
auto int find_v(const char *b, const char *k) {
|
||||||
|
char *p = (char*)b; int kl = strlen(k);
|
||||||
|
while (*p) {
|
||||||
|
if (memcmp(p, k, kl) == 0 && p[kl] == ':') {
|
||||||
|
p += kl + 1; while (*p == ' ') p++; return atoi(p);
|
||||||
|
}
|
||||||
|
while (*p && *p != '\n') p++; if (*p == '\n') p++;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd_v = sys_open("/proc/version", "r");
|
||||||
|
char v_buf[512];
|
||||||
|
if (fd_v >= 0) {
|
||||||
|
int b = sys_read(fd_v, v_buf, 511);
|
||||||
|
v_buf[b] = 0;
|
||||||
|
sys_close(fd_v);
|
||||||
|
} else strcpy(v_buf, "Unknown");
|
||||||
|
|
||||||
if (config.os_label[0]) {
|
if (config.os_label[0]) {
|
||||||
strcpy(info_lines[info_line_count], config.os_label);
|
strcpy(info_lines[info_line_count], config.os_label);
|
||||||
strcat(info_lines[info_line_count], ": ");
|
strcat(info_lines[info_line_count], ": ");
|
||||||
strcat(info_lines[info_line_count], os_info.os_name);
|
// Parse "BoredOS [codename] Version X.Y.Z"
|
||||||
strcat(info_lines[info_line_count], " V");
|
strcat(info_lines[info_line_count], v_buf);
|
||||||
strcat(info_lines[info_line_count], os_info.os_version);
|
// Truncate at newline
|
||||||
strcat(info_lines[info_line_count], " '");
|
char *nl = strchr(info_lines[info_line_count], '\n');
|
||||||
strcat(info_lines[info_line_count], os_info.os_codename);
|
if (nl) *nl = 0;
|
||||||
strcat(info_lines[info_line_count], "'");
|
|
||||||
info_line_count++;
|
info_line_count++;
|
||||||
}
|
}
|
||||||
if (config.kernel_label[0]) {
|
if (config.kernel_label[0]) {
|
||||||
strcpy(info_lines[info_line_count], config.kernel_label);
|
strcpy(info_lines[info_line_count], config.kernel_label);
|
||||||
strcat(info_lines[info_line_count], ": ");
|
strcat(info_lines[info_line_count], ": ");
|
||||||
strcat(info_lines[info_line_count], os_info.kernel_name);
|
char *kstart = strchr(v_buf, '\n');
|
||||||
strcat(info_lines[info_line_count], " V");
|
if (kstart) {
|
||||||
strcat(info_lines[info_line_count], os_info.kernel_version);
|
strcat(info_lines[info_line_count], kstart + 1);
|
||||||
strcat(info_lines[info_line_count], " ");
|
char *knext = strchr(info_lines[info_line_count], '\n');
|
||||||
strcat(info_lines[info_line_count], os_info.build_arch);
|
if (knext) *knext = 0;
|
||||||
|
} else strcat(info_lines[info_line_count], "Unknown");
|
||||||
info_line_count++;
|
info_line_count++;
|
||||||
}
|
}
|
||||||
if (config.uptime_label[0]) {
|
if (config.uptime_label[0]) {
|
||||||
uint64_t ticks = sys_system(16, 0, 0, 0, 0);
|
int fd_u = sys_open("/proc/uptime", "r");
|
||||||
int minutes = ticks / 3600; // 60Hz timer
|
if (fd_u >= 0) {
|
||||||
strcpy(info_lines[info_line_count], config.uptime_label);
|
char u_buf[64];
|
||||||
strcat(info_lines[info_line_count], ": ");
|
int b = sys_read(fd_u, u_buf, 63);
|
||||||
itoa(minutes, temp_buf);
|
u_buf[b] = 0;
|
||||||
strcat(info_lines[info_line_count], temp_buf);
|
sys_close(fd_u);
|
||||||
strcat(info_lines[info_line_count++], " mins");
|
int sec = atoi(u_buf);
|
||||||
|
int mins = sec / 60;
|
||||||
|
strcpy(info_lines[info_line_count], config.uptime_label);
|
||||||
|
strcat(info_lines[info_line_count], ": ");
|
||||||
|
itoa(mins, temp_buf);
|
||||||
|
strcat(info_lines[info_line_count], temp_buf);
|
||||||
|
strcat(info_lines[info_line_count++], " mins");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (config.shell_label[0]) {
|
if (config.shell_label[0]) {
|
||||||
strcpy(info_lines[info_line_count], config.shell_label);
|
strcpy(info_lines[info_line_count], config.shell_label);
|
||||||
strcat(info_lines[info_line_count++], ": bsh");
|
strcat(info_lines[info_line_count++], ": bsh");
|
||||||
}
|
}
|
||||||
if (config.memory_label[0]) {
|
if (config.memory_label[0]) {
|
||||||
uint64_t mem[2];
|
int fd_m = sys_open("/proc/meminfo", "r");
|
||||||
if (sys_system(15, (uint64_t)mem, 0, 0, 0) == 0) {
|
if (fd_m >= 0) {
|
||||||
|
char m_buf[512];
|
||||||
|
int b = sys_read(fd_m, m_buf, 511);
|
||||||
|
m_buf[b] = 0;
|
||||||
|
sys_close(fd_m);
|
||||||
|
int total = find_v(m_buf, "MemTotal");
|
||||||
|
int used = find_v(m_buf, "MemUsed");
|
||||||
strcpy(info_lines[info_line_count], config.memory_label);
|
strcpy(info_lines[info_line_count], config.memory_label);
|
||||||
strcat(info_lines[info_line_count], ": ");
|
strcat(info_lines[info_line_count], ": ");
|
||||||
itoa((int)(mem[1] / 1024 / 1024), temp_buf);
|
itoa(used / 1024, temp_buf);
|
||||||
strcat(info_lines[info_line_count], temp_buf);
|
strcat(info_lines[info_line_count], temp_buf);
|
||||||
strcat(info_lines[info_line_count], "MiB / ");
|
strcat(info_lines[info_line_count], "MiB / ");
|
||||||
itoa((int)(mem[0] / 1024 / 1024), temp_buf);
|
itoa(total / 1024, temp_buf);
|
||||||
strcat(info_lines[info_line_count], temp_buf);
|
strcat(info_lines[info_line_count], temp_buf);
|
||||||
strcat(info_lines[info_line_count++], "MiB");
|
strcat(info_lines[info_line_count++], "MiB");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -149,26 +149,12 @@ char *strrchr(const char *s, int c) {
|
||||||
if (c == 0) last = s;
|
if (c == 0) last = s;
|
||||||
return (char*)last;
|
return (char*)last;
|
||||||
}
|
}
|
||||||
char *strchr(const char *s, int c) {
|
|
||||||
while (*s) { if (*s == c) return (char*)s; s++; }
|
|
||||||
if (c == 0) return (char*)s;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
char *strdup(const char *s) {
|
char *strdup(const char *s) {
|
||||||
size_t len = strlen(s) + 1;
|
size_t len = strlen(s) + 1;
|
||||||
char *dup = malloc(len);
|
char *dup = malloc(len);
|
||||||
if (dup) memcpy(dup, s, len);
|
if (dup) memcpy(dup, s, len);
|
||||||
return dup;
|
return dup;
|
||||||
}
|
}
|
||||||
char *strstr(const char *haystack, const char *needle) {
|
|
||||||
size_t n = strlen(needle);
|
|
||||||
if (!n) return (char *)haystack;
|
|
||||||
while (*haystack) {
|
|
||||||
if (!strncmp(haystack, needle, n)) return (char *)haystack;
|
|
||||||
haystack++;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int toupper(int c) { return (c >= 'a' && c <= 'z') ? c - 32 : c; }
|
int toupper(int c) { return (c >= 'a' && c <= 'z') ? c - 32 : c; }
|
||||||
int tolower(int c) { return (c >= 'A' && c <= 'Z') ? c + 32 : c; }
|
int tolower(int c) { return (c >= 'A' && c <= 'Z') ? c + 32 : c; }
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,19 @@ void DG_SleepMs(uint32_t ms) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t DG_GetTicksMs(void) {
|
uint32_t DG_GetTicksMs(void) {
|
||||||
uint64_t ticks = sys_system(16, 0, 0, 0, 0); // SYSTEM_CMD_UPTIME = 16 (100Hz)
|
int fd = sys_open("/proc/uptime", "r");
|
||||||
return (uint32_t)(ticks * 10);
|
if (fd < 0) return 0;
|
||||||
|
char buf[128];
|
||||||
|
int bytes = sys_read(fd, buf, 127);
|
||||||
|
sys_close(fd);
|
||||||
|
if (bytes <= 0) return 0;
|
||||||
|
buf[bytes] = 0;
|
||||||
|
|
||||||
|
char *p = strstr(buf, "Raw_Ticks:");
|
||||||
|
if (!p) return 0;
|
||||||
|
uint32_t ticks = atoi(p + 10);
|
||||||
|
// 60Hz to ms: ticks * 1000 / 60 = ticks * 50 / 3
|
||||||
|
return (ticks * 50) / 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DG_SetWindowTitle(const char * title) {
|
void DG_SetWindowTitle(const char * title) {
|
||||||
|
|
@ -108,7 +119,7 @@ int DG_GetKey(int* pressed, unsigned char* key) {
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
(void)argc;
|
(void)argc;
|
||||||
(void)argv;
|
(void)argv;
|
||||||
char* fake_argv[] = {"doom", "-iwad", "A:/Library/DOOM/doom1.wad"};
|
char* fake_argv[] = {"doom", "-iwad", "/Library/DOOM/doom1.wad"};
|
||||||
doomgeneric_Create(3, fake_argv);
|
doomgeneric_Create(3, fake_argv);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
|
||||||
|
|
@ -95,36 +95,39 @@ static void about_paint(ui_window_t win) {
|
||||||
draw_ascii_logo(win, 14, offset_y);
|
draw_ascii_logo(win, 14, offset_y);
|
||||||
|
|
||||||
int fh = ui_get_font_height();
|
int fh = ui_get_font_height();
|
||||||
os_info_t os_info;
|
int fd_v = sys_open("/proc/version", "r");
|
||||||
sys_get_os_info(&os_info);
|
char v_buf[1024]; v_buf[0] = 0;
|
||||||
|
if (fd_v >= 0) {
|
||||||
char os_name_str[128];
|
int b = sys_read(fd_v, v_buf, 1023);
|
||||||
os_name_str[0] = 0;
|
v_buf[b] = 0;
|
||||||
strcat(os_name_str, os_info.os_name);
|
sys_close(fd_v);
|
||||||
strcat(os_name_str, " '");
|
}
|
||||||
strcat(os_name_str, os_info.os_codename);
|
|
||||||
strcat(os_name_str, "'");
|
|
||||||
|
|
||||||
char os_version_str[128];
|
char os_name_str[128] = "Unknown OS";
|
||||||
os_version_str[0] = 0;
|
char os_version_str[128] = "Unknown Version";
|
||||||
strcat(os_version_str, os_info.os_name);
|
char kernel_version_str[128] = "Unknown Kernel";
|
||||||
strcat(os_version_str, " Version ");
|
char build_date_str[128] = "Unknown Build";
|
||||||
strcat(os_version_str, os_info.os_version);
|
|
||||||
|
|
||||||
char kernel_version_str[128];
|
|
||||||
kernel_version_str[0] = 0;
|
|
||||||
strcat(kernel_version_str, os_info.kernel_name);
|
|
||||||
strcat(kernel_version_str, " Version ");
|
|
||||||
strcat(kernel_version_str, os_info.kernel_version);
|
|
||||||
strcat(kernel_version_str, " ");
|
|
||||||
strcat(kernel_version_str, os_info.build_arch);
|
|
||||||
|
|
||||||
char build_date_str[128];
|
if (v_buf[0]) {
|
||||||
build_date_str[0] = 0;
|
char *line1 = v_buf;
|
||||||
strcat(build_date_str, "Build Date: ");
|
char *line2 = strchr(line1, '\n'); if (line2) { *line2 = 0; line2++; }
|
||||||
strcat(build_date_str, os_info.build_date);
|
char *line3 = line2 ? strchr(line2, '\n') : NULL; if (line3) { *line3 = 0; line3++; }
|
||||||
strcat(build_date_str, " ");
|
|
||||||
strcat(build_date_str, os_info.build_time);
|
strcpy(os_name_str, line1);
|
||||||
|
if (line2) {
|
||||||
|
strcpy(os_version_str, line2);
|
||||||
|
}
|
||||||
|
if (line3) {
|
||||||
|
strcpy(kernel_version_str, line3);
|
||||||
|
char *line4 = strchr(line3, '\n');
|
||||||
|
if (line4) {
|
||||||
|
*line4 = 0; line4++;
|
||||||
|
strcpy(build_date_str, line4);
|
||||||
|
char *line5 = strchr(build_date_str, '\n');
|
||||||
|
if (line5) *line5 = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ui_draw_string(win, offset_x, offset_y + 105, os_name_str, 0xFFFFFFFF);
|
ui_draw_string(win, offset_x, offset_y + 105, os_name_str, 0xFFFFFFFF);
|
||||||
ui_draw_string(win, offset_x, offset_y + 105 + fh, os_version_str, 0xFFFFFFFF);
|
ui_draw_string(win, offset_x, offset_y + 105 + fh, os_version_str, 0xFFFFFFFF);
|
||||||
|
|
|
||||||
|
|
@ -32,19 +32,6 @@ static int win_h = 960;
|
||||||
static char history_stack[HISTORY_MAX][512];
|
static char history_stack[HISTORY_MAX][512];
|
||||||
static int history_count = 0;
|
static int history_count = 0;
|
||||||
|
|
||||||
static char* strstr(const char* haystack, const char* needle) {
|
|
||||||
if (!*needle) return (char*)haystack;
|
|
||||||
for (; *haystack; haystack++) {
|
|
||||||
const char *h = haystack;
|
|
||||||
const char *n = needle;
|
|
||||||
while (*h && *n && *h == *n) {
|
|
||||||
h++; n++;
|
|
||||||
}
|
|
||||||
if (!*n) return (char*)haystack;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char* str_istrstr(const char* haystack, const char* needle) {
|
static char* str_istrstr(const char* haystack, const char* needle) {
|
||||||
if (!*needle) return (char*)haystack;
|
if (!*needle) return (char*)haystack;
|
||||||
for (; *haystack; haystack++) {
|
for (; *haystack; haystack++) {
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ static void notepad_ensure_cursor_visible(int h) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void notepad_load_state() {
|
static void notepad_load_state() {
|
||||||
int fd = sys_open("A:/tmp/notepad_state.txt", "r");
|
int fd = sys_open("/tmp/notepad_state.txt", "r");
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
sys_serial_write("Notepad: Loading state...\n");
|
sys_serial_write("Notepad: Loading state...\n");
|
||||||
buf_len = sys_read(fd, buffer, NOTEPAD_BUF_SIZE - 1);
|
buf_len = sys_read(fd, buffer, NOTEPAD_BUF_SIZE - 1);
|
||||||
|
|
@ -50,8 +50,8 @@ static void notepad_load_state() {
|
||||||
|
|
||||||
static void notepad_save_state() {
|
static void notepad_save_state() {
|
||||||
// Ensure dir exists
|
// Ensure dir exists
|
||||||
sys_mkdir("A:/tmp");
|
sys_mkdir("/tmp");
|
||||||
int fd = sys_open("A:/tmp/notepad_state.txt", "w");
|
int fd = sys_open("/tmp/notepad_state.txt", "w");
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
sys_write_fs(fd, buffer, buf_len);
|
sys_write_fs(fd, buffer, buf_len);
|
||||||
sys_close(fd);
|
sys_close(fd);
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ static uint32_t *canvas_buffer = NULL;
|
||||||
static uint32_t current_color = COLOR_BLACK;
|
static uint32_t current_color = COLOR_BLACK;
|
||||||
static int last_mx = -1;
|
static int last_mx = -1;
|
||||||
static int last_my = -1;
|
static int last_my = -1;
|
||||||
static char current_file_path[256] = "/Desktop/drawing.pnt";
|
static char current_file_path[256] = "/root/Desktop/drawing.pnt";
|
||||||
|
|
||||||
static void paint_strcpy(char *dest, const char *src) {
|
static void paint_strcpy(char *dest, const char *src) {
|
||||||
while (*src) *dest++ = *src++;
|
while (*src) *dest++ = *src++;
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ int main(int argc, char **argv) {
|
||||||
uint64_t dt[6] = {0};
|
uint64_t dt[6] = {0};
|
||||||
syscall2(SYS_GUI, GUI_CMD_GET_DATETIME, (uint64_t)dt);
|
syscall2(SYS_GUI, GUI_CMD_GET_DATETIME, (uint64_t)dt);
|
||||||
|
|
||||||
strcpy(g_filename, "/Desktop/screenshot-");
|
strcpy(g_filename, "/root/Desktop/screenshot-");
|
||||||
append_num((int)dt[0], 4); // Year
|
append_num((int)dt[0], 4); // Year
|
||||||
append_num((int)dt[1], 2); // Month
|
append_num((int)dt[1], 2); // Month
|
||||||
append_num((int)dt[2], 2); // Day
|
append_num((int)dt[2], 2); // Day
|
||||||
|
|
@ -110,7 +110,7 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
// Show notification
|
// Show notification
|
||||||
char notif[256] = "Saved ";
|
char notif[256] = "Saved ";
|
||||||
strcat(notif, g_filename + 9); // Skip "/Desktop/"
|
strcat(notif, g_filename + 14); // Skip "/root/Desktop/"
|
||||||
syscall2(SYS_GUI, GUI_CMD_SHOW_NOTIFICATION, (uint64_t)notif);
|
syscall2(SYS_GUI, GUI_CMD_SHOW_NOTIFICATION, (uint64_t)notif);
|
||||||
} else {
|
} else {
|
||||||
res = 0;
|
res = 0;
|
||||||
|
|
|
||||||
|
|
@ -32,38 +32,111 @@ static uint64_t kernel_ticks_prev = 0;
|
||||||
static uint64_t total_mem_system = 0;
|
static uint64_t total_mem_system = 0;
|
||||||
static uint64_t used_mem_system = 0;
|
static uint64_t used_mem_system = 0;
|
||||||
static char cpu_model_name[64] = "Unknown CPU";
|
static char cpu_model_name[64] = "Unknown CPU";
|
||||||
|
static int cpu_cores = 1;
|
||||||
|
|
||||||
typedef struct {
|
static int find_value(const char *buf, const char *key) {
|
||||||
size_t total_memory;
|
char *p = (char*)buf;
|
||||||
size_t used_memory;
|
int key_len = strlen(key);
|
||||||
size_t available_memory;
|
while (*p) {
|
||||||
size_t allocated_blocks;
|
if (memcmp(p, key, key_len) == 0 && p[key_len] == ':') {
|
||||||
size_t free_blocks;
|
p += key_len + 1;
|
||||||
size_t largest_free_block;
|
while (*p == ' ') p++;
|
||||||
size_t smallest_free_block;
|
return atoi(p);
|
||||||
size_t fragmentation_percent;
|
}
|
||||||
size_t peak_memory_used;
|
while (*p && *p != '\n') p++;
|
||||||
} MemStats;
|
if (*p == '\n') p++;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void find_string(const char *buf, const char *key, char *out, int max_len) {
|
||||||
|
char *p = (char*)buf;
|
||||||
|
int key_len = strlen(key);
|
||||||
|
while (*p) {
|
||||||
|
if (memcmp(p, key, key_len) == 0 && p[key_len] == ':') {
|
||||||
|
p += key_len + 1;
|
||||||
|
while (*p == ' ') p++;
|
||||||
|
int i = 0;
|
||||||
|
while (*p && *p != '\n' && i < max_len - 1) {
|
||||||
|
out[i++] = *p++;
|
||||||
|
}
|
||||||
|
out[i] = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (*p && *p != '\n') p++;
|
||||||
|
if (*p == '\n') p++;
|
||||||
|
}
|
||||||
|
strcpy(out, "Unknown");
|
||||||
|
}
|
||||||
|
|
||||||
static void update_proc_list(void) {
|
static void update_proc_list(void) {
|
||||||
proc_count = sys_system(SYSTEM_CMD_PROCESS_LIST, (uint64_t)proc_list, 32, 0, 0);
|
FAT32_FileInfo entries[64];
|
||||||
|
int count = sys_list("/proc", entries, 64);
|
||||||
uint64_t uptime_now = sys_system(SYSTEM_CMD_UPTIME, 0, 0, 0, 0);
|
if (count < 0) return;
|
||||||
|
|
||||||
|
proc_count = 0;
|
||||||
uint64_t user_ticks_now = 0;
|
uint64_t user_ticks_now = 0;
|
||||||
|
|
||||||
for (int i = 0; i < proc_count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
if (proc_list[i].pid != 0) {
|
if (entries[i].is_directory) {
|
||||||
user_ticks_now += proc_list[i].ticks;
|
// Check if name is numeric (PID)
|
||||||
|
bool numeric = true;
|
||||||
|
for (int j = 0; entries[i].name[j]; j++) {
|
||||||
|
if (entries[i].name[j] < '0' || entries[i].name[j] > '9') {
|
||||||
|
numeric = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!numeric) continue;
|
||||||
|
|
||||||
|
int pid = atoi(entries[i].name);
|
||||||
|
char path[64];
|
||||||
|
strcpy(path, "/proc/");
|
||||||
|
strcat(path, entries[i].name);
|
||||||
|
strcat(path, "/status");
|
||||||
|
|
||||||
|
int fd = sys_open(path, "r");
|
||||||
|
if (fd >= 0) {
|
||||||
|
char buf[512];
|
||||||
|
int bytes = sys_read(fd, buf, 511);
|
||||||
|
sys_close(fd);
|
||||||
|
if (bytes > 0) {
|
||||||
|
buf[bytes] = 0;
|
||||||
|
proc_list[proc_count].pid = pid;
|
||||||
|
find_string(buf, "Name", proc_list[proc_count].name, 64);
|
||||||
|
proc_list[proc_count].used_memory = (size_t)find_value(buf, "Memory") * 1024;
|
||||||
|
uint64_t ticks = (uint64_t)find_value(buf, "Ticks");
|
||||||
|
proc_list[proc_count].ticks = ticks;
|
||||||
|
|
||||||
|
proc_list[proc_count].is_idle = find_value(buf, "Idle") == 1;
|
||||||
|
|
||||||
|
if (!proc_list[proc_count].is_idle) user_ticks_now += ticks;
|
||||||
|
proc_count++;
|
||||||
|
if (proc_count >= 32) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Global stats
|
||||||
|
int fd_u = sys_open("/proc/uptime", "r");
|
||||||
|
uint64_t uptime_now = 0;
|
||||||
|
if (fd_u >= 0) {
|
||||||
|
char buf[256];
|
||||||
|
int bytes = sys_read(fd_u, buf, 255);
|
||||||
|
sys_close(fd_u);
|
||||||
|
if (bytes > 0) {
|
||||||
|
buf[bytes] = 0;
|
||||||
|
uptime_now = (uint64_t)find_value(buf, "Raw_Ticks");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (uptime_prev > 0) {
|
if (uptime_prev > 0) {
|
||||||
uint64_t total_delta = uptime_now - uptime_prev;
|
uint64_t total_delta = uptime_now - uptime_prev;
|
||||||
if (total_delta > 0) {
|
if (total_delta > 0) {
|
||||||
uint64_t used_delta = user_ticks_now - kernel_ticks_prev; // Reusing the global state variable for prev user_ticks
|
uint64_t used_delta = user_ticks_now - kernel_ticks_prev;
|
||||||
|
int cores = cpu_cores > 0 ? cpu_cores : 1;
|
||||||
// On a 4 CPU system, theoretically used_delta can be 4x total_delta
|
int usage = (int)((used_delta * 100) / (total_delta * cores));
|
||||||
int usage = (int)((used_delta * 100) / (total_delta * 4));
|
|
||||||
if (usage > 100) usage = 100;
|
if (usage > 100) usage = 100;
|
||||||
cpu_history[history_idx] = usage;
|
cpu_history[history_idx] = usage;
|
||||||
}
|
}
|
||||||
|
|
@ -72,11 +145,18 @@ static void update_proc_list(void) {
|
||||||
uptime_prev = uptime_now;
|
uptime_prev = uptime_now;
|
||||||
kernel_ticks_prev = user_ticks_now;
|
kernel_ticks_prev = user_ticks_now;
|
||||||
|
|
||||||
MemStats stats;
|
int fd_m = sys_open("/proc/meminfo", "r");
|
||||||
sys_system(SYSTEM_CMD_MEMINFO, (uint64_t)&stats, 0, 0, 0);
|
if (fd_m >= 0) {
|
||||||
total_mem_system = stats.total_memory;
|
char buf[1024];
|
||||||
used_mem_system = stats.used_memory;
|
int bytes = sys_read(fd_m, buf, 1023);
|
||||||
mem_history[history_idx] = (int)(stats.used_memory / 1024);
|
sys_close(fd_m);
|
||||||
|
if (bytes > 0) {
|
||||||
|
buf[bytes] = 0;
|
||||||
|
total_mem_system = (uint64_t)find_value(buf, "MemTotal") * 1024;
|
||||||
|
used_mem_system = (uint64_t)find_value(buf, "MemUsed") * 1024;
|
||||||
|
mem_history[history_idx] = (int)(used_mem_system / 1024);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
history_idx = (history_idx + 1) % GRAPH_POINTS;
|
history_idx = (history_idx + 1) % GRAPH_POINTS;
|
||||||
}
|
}
|
||||||
|
|
@ -168,9 +248,12 @@ static void draw_taskman(void) {
|
||||||
// Memory Graph Area
|
// Memory Graph Area
|
||||||
ui_draw_string(win_taskman, 205, 10, "MEMORY", COLOR_MEM);
|
ui_draw_string(win_taskman, 205, 10, "MEMORY", COLOR_MEM);
|
||||||
char mem_pct_label[16];
|
char mem_pct_label[16];
|
||||||
int current_mem_pct = 0;
|
int current_mem_pct_x10 = 0;
|
||||||
if (total_mem_system > 0) current_mem_pct = (int)((used_mem_system * 100) / total_mem_system);
|
if (total_mem_system > 0) current_mem_pct_x10 = (int)((used_mem_system * 1000) / total_mem_system);
|
||||||
itoa(current_mem_pct, mem_pct_label);
|
itoa(current_mem_pct_x10 / 10, mem_pct_label);
|
||||||
|
strcat(mem_pct_label, ".");
|
||||||
|
char frac[4]; itoa(current_mem_pct_x10 % 10, frac);
|
||||||
|
strcat(mem_pct_label, frac);
|
||||||
strcat(mem_pct_label, "%");
|
strcat(mem_pct_label, "%");
|
||||||
ui_draw_string(win_taskman, 340, 10, mem_pct_label, COLOR_MEM);
|
ui_draw_string(win_taskman, 340, 10, mem_pct_label, COLOR_MEM);
|
||||||
|
|
||||||
|
|
@ -255,8 +338,18 @@ static void draw_taskman(void) {
|
||||||
int main(void) {
|
int main(void) {
|
||||||
win_taskman = ui_window_create("Task Manager", 100, 100, 400, 480);
|
win_taskman = ui_window_create("Task Manager", 100, 100, 400, 480);
|
||||||
|
|
||||||
// Fetch CPU model
|
int fd_c = sys_open("/proc/cpuinfo", "r");
|
||||||
sys_system(SYSTEM_CMD_GET_CPU_MODEL, (uint64_t)cpu_model_name, 0, 0, 0);
|
if (fd_c >= 0) {
|
||||||
|
char buf[1024];
|
||||||
|
int bytes = sys_read(fd_c, buf, 1023);
|
||||||
|
sys_close(fd_c);
|
||||||
|
if (bytes > 0) {
|
||||||
|
buf[bytes] = 0;
|
||||||
|
find_string(buf, "Processor", cpu_model_name, 64);
|
||||||
|
int cores = find_value(buf, "Cores");
|
||||||
|
if (cores > 0) cpu_cores = cores;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for(int i=0; i<GRAPH_POINTS; i++) { cpu_history[i] = 0; mem_history[i] = 0; }
|
for(int i=0; i<GRAPH_POINTS; i++) { cpu_history[i] = 0; mem_history[i] = 0; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -202,9 +202,27 @@ char* strcat(char *dest, const char *src) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *strchr(const char *s, int c) {
|
||||||
|
while (*s != (char)c) {
|
||||||
|
if (!*s++) return NULL;
|
||||||
|
}
|
||||||
|
return (char *)s;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *strstr(const char *haystack, const char *needle) {
|
||||||
|
size_t needle_len = strlen(needle);
|
||||||
|
if (!needle_len) return (char *)haystack;
|
||||||
|
while (*haystack) {
|
||||||
|
if (memcmp(haystack, needle, needle_len) == 0) return (char *)haystack;
|
||||||
|
haystack++;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
int atoi(const char *nptr) {
|
int atoi(const char *nptr) {
|
||||||
int res = 0;
|
int res = 0;
|
||||||
int sign = 1;
|
int sign = 1;
|
||||||
|
while (*nptr == ' ' || *nptr == '\t' || *nptr == '\n' || *nptr == '\r') nptr++;
|
||||||
if (*nptr == '-') {
|
if (*nptr == '-') {
|
||||||
sign = -1;
|
sign = -1;
|
||||||
nptr++;
|
nptr++;
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,9 @@ void* realloc(void* ptr, size_t size);
|
||||||
void *memset(void *s, int c, size_t n);
|
void *memset(void *s, int c, size_t n);
|
||||||
void *memcpy(void *dest, const void *src, size_t n);
|
void *memcpy(void *dest, const void *src, size_t n);
|
||||||
|
|
||||||
// String functions
|
#include "string.h"
|
||||||
size_t strlen(const char *s);
|
|
||||||
int strcmp(const char *s1, const char *s2);
|
// Math/Utility functions
|
||||||
char* strcpy(char *dest, const char *src);
|
|
||||||
char* strcat(char *dest, const char *src);
|
|
||||||
int atoi(const char *nptr);
|
int atoi(const char *nptr);
|
||||||
void itoa(int n, char *buf);
|
void itoa(int n, char *buf);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,5 +7,11 @@ void *memmove(void *dest, const void *src, size_t n);
|
||||||
int memcmp(const void *s1, const void *s2, size_t n);
|
int memcmp(const void *s1, const void *s2, size_t n);
|
||||||
void *memcpy(void *dest, const void *src, size_t n);
|
void *memcpy(void *dest, const void *src, size_t n);
|
||||||
void *memset(void *s, int c, size_t n);
|
void *memset(void *s, int c, size_t n);
|
||||||
|
char *strchr(const char *s, int c);
|
||||||
|
char *strstr(const char *haystack, const char *needle);
|
||||||
|
size_t strlen(const char *s);
|
||||||
|
int strcmp(const char *s1, const char *s2);
|
||||||
|
char* strcpy(char *dest, const char *src);
|
||||||
|
char* strcat(char *dest, const char *src);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -251,10 +251,6 @@ void sys_yield(void) {
|
||||||
syscall1(SYS_SYSTEM, SYSTEM_CMD_YIELD);
|
syscall1(SYS_SYSTEM, SYSTEM_CMD_YIELD);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sys_get_os_info(os_info_t *info) {
|
|
||||||
return (int)syscall5(SYS_SYSTEM, SYSTEM_CMD_GET_OS_INFO, (uint64_t)info, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sys_parallel_run(void (*fn)(void*), void **args, int count) {
|
void sys_parallel_run(void (*fn)(void*), void **args, int count) {
|
||||||
syscall5(SYS_SYSTEM, SYSTEM_CMD_PARALLEL_RUN, (uint64_t)fn, (uint64_t)args, (uint64_t)count, 0);
|
syscall5(SYS_SYSTEM, SYSTEM_CMD_PARALLEL_RUN, (uint64_t)fn, (uint64_t)args, (uint64_t)count, 0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,6 @@
|
||||||
#define SYSTEM_CMD_REBOOT 12
|
#define SYSTEM_CMD_REBOOT 12
|
||||||
#define SYSTEM_CMD_SHUTDOWN 13
|
#define SYSTEM_CMD_SHUTDOWN 13
|
||||||
#define SYSTEM_CMD_BEEP 14
|
#define SYSTEM_CMD_BEEP 14
|
||||||
#define SYSTEM_CMD_MEMINFO 15
|
|
||||||
#define SYSTEM_CMD_UPTIME 16
|
|
||||||
#define SYSTEM_CMD_PCI_LIST 17
|
#define SYSTEM_CMD_PCI_LIST 17
|
||||||
#define SYSTEM_CMD_NETWORK_DHCP 18
|
#define SYSTEM_CMD_NETWORK_DHCP 18
|
||||||
#define SYSTEM_CMD_NETWORK_GET_MAC 19
|
#define SYSTEM_CMD_NETWORK_GET_MAC 19
|
||||||
|
|
@ -69,13 +67,10 @@
|
||||||
#define SYSTEM_CMD_DNS_LOOKUP 37
|
#define SYSTEM_CMD_DNS_LOOKUP 37
|
||||||
#define SYSTEM_CMD_SET_DNS 38
|
#define SYSTEM_CMD_SET_DNS 38
|
||||||
#define SYSTEM_CMD_NET_UNLOCK 39
|
#define SYSTEM_CMD_NET_UNLOCK 39
|
||||||
#define SYSTEM_CMD_PROCESS_LIST 44
|
|
||||||
#define SYSTEM_CMD_GET_CPU_MODEL 45
|
|
||||||
#define SYSTEM_CMD_SLEEP 46
|
#define SYSTEM_CMD_SLEEP 46
|
||||||
#define SYSTEM_CMD_SET_RAW_MODE 41
|
#define SYSTEM_CMD_SET_RAW_MODE 41
|
||||||
#define SYSTEM_CMD_TCP_RECV_NB 42
|
#define SYSTEM_CMD_TCP_RECV_NB 42
|
||||||
#define SYSTEM_CMD_YIELD 43
|
#define SYSTEM_CMD_YIELD 43
|
||||||
#define SYSTEM_CMD_GET_OS_INFO 49
|
|
||||||
#define SYSTEM_CMD_PARALLEL_RUN 50
|
#define SYSTEM_CMD_PARALLEL_RUN 50
|
||||||
|
|
||||||
// Internal assembly entry into Ring 0
|
// Internal assembly entry into Ring 0
|
||||||
|
|
@ -137,6 +132,7 @@ typedef struct {
|
||||||
char name[64];
|
char name[64];
|
||||||
uint64_t ticks;
|
uint64_t ticks;
|
||||||
size_t used_memory;
|
size_t used_memory;
|
||||||
|
uint32_t is_idle;
|
||||||
} ProcessInfo;
|
} ProcessInfo;
|
||||||
|
|
||||||
// Network API
|
// Network API
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,18 @@
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
(void)argc; (void)argv;
|
(void)argc; (void)argv;
|
||||||
uint64_t ticks = sys_system(16, 0, 0, 0, 0); // SYSTEM_CMD_UPTIME
|
int fd = sys_open("/proc/uptime", "r");
|
||||||
uint64_t seconds = ticks / 100; // 100Hz timer assumed
|
if (fd < 0) return 1;
|
||||||
uint64_t minutes = seconds / 60;
|
char buf[128];
|
||||||
uint64_t hours = minutes / 60;
|
int bytes = sys_read(fd, buf, 127);
|
||||||
uint64_t days = hours / 24;
|
sys_close(fd);
|
||||||
|
if (bytes <= 0) return 1;
|
||||||
|
buf[bytes] = 0;
|
||||||
|
|
||||||
|
int seconds = atoi(buf);
|
||||||
|
int minutes = seconds / 60;
|
||||||
|
int hours = minutes / 60;
|
||||||
|
int days = hours / 24;
|
||||||
|
|
||||||
printf("Uptime: %d days, %d hours, %d minutes, %d seconds\n",
|
printf("Uptime: %d days, %d hours, %d minutes, %d seconds\n",
|
||||||
(int)days, (int)(hours % 24), (int)(minutes % 60), (int)(seconds % 60));
|
(int)days, (int)(hours % 24), (int)(minutes % 60), (int)(seconds % 60));
|
||||||
|
|
|
||||||
37
src/wm/cmd.c
37
src/wm/cmd.c
|
|
@ -1011,7 +1011,7 @@ static void internal_cmd_cd(char *args) {
|
||||||
if (vfs_is_directory(full_path)) {
|
if (vfs_is_directory(full_path)) {
|
||||||
// Normalize the path to resolve .. and .
|
// Normalize the path to resolve .. and .
|
||||||
char normalized_path[512];
|
char normalized_path[512];
|
||||||
vfs_normalize_path(full_path, normalized_path);
|
vfs_normalize_path(cmd_state->current_dir, full_path, normalized_path);
|
||||||
|
|
||||||
cmd_update_dir(normalized_path);
|
cmd_update_dir(normalized_path);
|
||||||
cmd_write("Changed to: ");
|
cmd_write("Changed to: ");
|
||||||
|
|
@ -1071,7 +1071,7 @@ static void internal_cmd_txtedit(char *args) {
|
||||||
cmd_write("\n");
|
cmd_write("\n");
|
||||||
|
|
||||||
cmd_is_waiting_for_process = true;
|
cmd_is_waiting_for_process = true;
|
||||||
process_t *proc = process_create_elf("A:/bin/txtedit.elf", normalized_path);
|
process_t *proc = process_create_elf("/bin/txtedit.elf", normalized_path);
|
||||||
if (proc) {
|
if (proc) {
|
||||||
proc->is_terminal_proc = true;
|
proc->is_terminal_proc = true;
|
||||||
proc->ui_window = &win_cmd;
|
proc->ui_window = &win_cmd;
|
||||||
|
|
@ -1537,7 +1537,7 @@ static void cmd_exec_single(char *cmd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for executable in Current Directory or A:/bin/
|
// Check for executable in Current Directory or /bin/
|
||||||
char search_path[512];
|
char search_path[512];
|
||||||
|
|
||||||
// Check if the command already ends in .elf (case insensitive)
|
// Check if the command already ends in .elf (case insensitive)
|
||||||
|
|
@ -2104,11 +2104,12 @@ void cmd_reset(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void create_ramfs_files(void) {
|
static void create_ramfs_files(void) {
|
||||||
if (!fat32_exists("Documents")) fat32_mkdir("Documents");
|
if (!fat32_exists("root")) fat32_mkdir("root");
|
||||||
if (!fat32_exists("Projects")) fat32_mkdir("Projects");
|
if (!fat32_exists("root/Documents")) fat32_mkdir("root/Documents");
|
||||||
if (!fat32_exists("Documents/Important")) fat32_mkdir("Documents/Important");
|
if (!fat32_exists("root/Documents/Important")) fat32_mkdir("root/Documents/Important");
|
||||||
if (!fat32_exists("Apps")) fat32_mkdir("Apps");
|
if (!fat32_exists("root/Apps")) fat32_mkdir("root/Apps");
|
||||||
if (!fat32_exists("Desktop")) fat32_mkdir("Desktop");
|
if (!fat32_exists("root/Desktop")) fat32_mkdir("root/Desktop");
|
||||||
|
if (!fat32_exists("root/projects")) fat32_mkdir("root/projects");
|
||||||
if (!fat32_exists("RecycleBin")) fat32_mkdir("RecycleBin");
|
if (!fat32_exists("RecycleBin")) fat32_mkdir("RecycleBin");
|
||||||
if (!fat32_exists("Library/conf")) fat32_mkdir("Library/conf");
|
if (!fat32_exists("Library/conf")) fat32_mkdir("Library/conf");
|
||||||
|
|
||||||
|
|
@ -2156,7 +2157,7 @@ static void create_ramfs_files(void) {
|
||||||
"// BoredOS System Fetch Configuration\n"
|
"// BoredOS System Fetch Configuration\n"
|
||||||
"// ----------------------------------\n"
|
"// ----------------------------------\n"
|
||||||
"// To use custom ascii art, uncomment the line below and point it to your file.\n"
|
"// To use custom ascii art, uncomment the line below and point it to your file.\n"
|
||||||
"ascii_art_file=A:/Library/art/boredos.txt\n"
|
"ascii_art_file=/Library/art/boredos.txt\n"
|
||||||
"user_host_string=root@boredos\n"
|
"user_host_string=root@boredos\n"
|
||||||
"separator=------------\n"
|
"separator=------------\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
@ -2192,7 +2193,7 @@ static void create_ramfs_files(void) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
FAT32_FileHandle *fh = fat32_open("Apps/README.md", "w");
|
FAT32_FileHandle *fh = fat32_open("root/Apps/README.md", "w");
|
||||||
if (fh) {
|
if (fh) {
|
||||||
const char *content =
|
const char *content =
|
||||||
"# All compiled C files in this directory are openable from any other directory by typing in the name of the compiled file by typing in the name of the compiled file.\n\n"
|
"# All compiled C files in this directory are openable from any other directory by typing in the name of the compiled file by typing in the name of the compiled file.\n\n"
|
||||||
|
|
@ -2202,24 +2203,24 @@ static void create_ramfs_files(void) {
|
||||||
fat32_close(fh);
|
fat32_close(fh);
|
||||||
}
|
}
|
||||||
|
|
||||||
fh = fat32_open("Documents/notes.txt", "w");
|
fh = fat32_open("root/Documents/notes.txt", "w");
|
||||||
if (fh) {
|
if (fh) {
|
||||||
const char *content = "My Notes\n\n- First note\n- Second note\n";
|
const char *content = "My Notes\n\n- First note\n- Second note\n";
|
||||||
fat32_write(fh, (void *)content, 39);
|
fat32_write(fh, (void *)content, 39);
|
||||||
fat32_close(fh);
|
fat32_close(fh);
|
||||||
}
|
}
|
||||||
|
|
||||||
fh = fat32_open("Projects/project1.txt", "w");
|
fh = fat32_open("root/projects/project1.txt", "w");
|
||||||
if (fh) {
|
if (fh) {
|
||||||
const char *content = "Project 1\n\nStatus: In Progress\n";
|
const char *content = "Project 1\n\nStatus: In Progress\n";
|
||||||
fat32_write(fh, (void *)content, 32);
|
fat32_write(fh, (void *)content, 32);
|
||||||
fat32_close(fh);
|
fat32_close(fh);
|
||||||
}
|
}
|
||||||
|
|
||||||
fat32_open("Desktop/Recycle Bin.shortcut", "w");
|
fat32_open("root/Desktop/Recycle Bin.shortcut", "w");
|
||||||
|
|
||||||
|
|
||||||
fh = fat32_open("Apps/wordofgod.c", "w");
|
fh = fat32_open("root/Apps/wordofgod.c", "w");
|
||||||
if (fh) {
|
if (fh) {
|
||||||
// Buffer the entire file content to write in one go
|
// Buffer the entire file content to write in one go
|
||||||
// This prevents issues with multiple small writes causing truncation
|
// This prevents issues with multiple small writes causing truncation
|
||||||
|
|
@ -2273,7 +2274,7 @@ static void create_ramfs_files(void) {
|
||||||
fat32_close(fh);
|
fat32_close(fh);
|
||||||
}
|
}
|
||||||
|
|
||||||
fh = fat32_open("Apps/DOOM.c", "w");
|
fh = fat32_open("root/Apps/DOOM.c", "w");
|
||||||
if (fh) {
|
if (fh) {
|
||||||
const char *content =
|
const char *content =
|
||||||
"int main(){\n"
|
"int main(){\n"
|
||||||
|
|
@ -2324,7 +2325,11 @@ void cmd_init(void) {
|
||||||
if (state) {
|
if (state) {
|
||||||
|
|
||||||
state->current_dir[0] = '/';
|
state->current_dir[0] = '/';
|
||||||
state->current_dir[1] = 0;
|
state->current_dir[1] = 'r';
|
||||||
|
state->current_dir[2] = 'o';
|
||||||
|
state->current_dir[3] = 'o';
|
||||||
|
state->current_dir[4] = 't';
|
||||||
|
state->current_dir[5] = 0;
|
||||||
win_cmd.data = state;
|
win_cmd.data = state;
|
||||||
cmd_state = state; // Set static pointer
|
cmd_state = state; // Set static pointer
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -240,8 +240,8 @@ static void explorer_draw_icon_label(int x, int y, const char *label, uint32_t c
|
||||||
|
|
||||||
static bool check_desktop_limit_explorer(Window *win) {
|
static bool check_desktop_limit_explorer(Window *win) {
|
||||||
ExplorerState *state = (ExplorerState*)win->data;
|
ExplorerState *state = (ExplorerState*)win->data;
|
||||||
if (explorer_str_starts_with(state->current_path, "/Desktop")) {
|
if (explorer_str_starts_with(state->current_path, "/root/Desktop")) {
|
||||||
if (explorer_strcmp(state->current_path, "/Desktop") == 0 || explorer_strcmp(state->current_path, "/Desktop/") == 0) { // Check if root desktop
|
if (explorer_strcmp(state->current_path, "/root/Desktop") == 0 || explorer_strcmp(state->current_path, "/root/Desktop/") == 0) { // Check if root desktop
|
||||||
if (state->item_count >= desktop_max_cols * (desktop_max_rows_per_col > 1 ? desktop_max_rows_per_col - 1 : 0)) {
|
if (state->item_count >= desktop_max_cols * (desktop_max_rows_per_col > 1 ? desktop_max_rows_per_col - 1 : 0)) {
|
||||||
state->dialog_state = DIALOG_ERROR;
|
state->dialog_state = DIALOG_ERROR;
|
||||||
explorer_strcpy(state->dialog_input, "Desktop is full!");
|
explorer_strcpy(state->dialog_input, "Desktop is full!");
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,14 @@ int get_screen_height(void) {
|
||||||
return g_fb ? g_fb->height : 0;
|
return g_fb ? g_fb->height : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t graphics_get_fb_addr(void) {
|
||||||
|
return g_fb ? (uint64_t)g_fb->address : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int graphics_get_fb_bpp(void) {
|
||||||
|
return g_fb ? g_fb->bpp : 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Merge new dirty rect with existing one
|
// Merge new dirty rect with existing one
|
||||||
static void merge_dirty_rect(int x, int y, int w, int h) {
|
static void merge_dirty_rect(int x, int y, int w, int h) {
|
||||||
if (!g_dirty.active) {
|
if (!g_dirty.active) {
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,8 @@ void draw_boredos_logo(int x, int y, int scale);
|
||||||
// Get screen dimensions
|
// Get screen dimensions
|
||||||
int get_screen_width(void);
|
int get_screen_width(void);
|
||||||
int get_screen_height(void);
|
int get_screen_height(void);
|
||||||
|
uint64_t graphics_get_fb_addr(void);
|
||||||
|
int graphics_get_fb_bpp(void);
|
||||||
void graphics_update_resolution(int width, int height, int bpp, void* fb_addr, int color_mode);
|
void graphics_update_resolution(int width, int height, int bpp, void* fb_addr, int color_mode);
|
||||||
|
|
||||||
// Dirty rectangle management
|
// Dirty rectangle management
|
||||||
|
|
|
||||||
82
src/wm/wm.c
82
src/wm/wm.c
|
|
@ -188,7 +188,7 @@ static void refresh_desktop_icons(void) {
|
||||||
FAT32_FileInfo *files = (FAT32_FileInfo*)kmalloc(MAX_DESKTOP_ICONS * sizeof(FAT32_FileInfo));
|
FAT32_FileInfo *files = (FAT32_FileInfo*)kmalloc(MAX_DESKTOP_ICONS * sizeof(FAT32_FileInfo));
|
||||||
if (!files) return;
|
if (!files) return;
|
||||||
|
|
||||||
int file_count = fat32_list_directory("/Desktop", files, MAX_DESKTOP_ICONS);
|
int file_count = fat32_list_directory("/root/Desktop", files, MAX_DESKTOP_ICONS);
|
||||||
|
|
||||||
// Temp array to hold new state
|
// Temp array to hold new state
|
||||||
DesktopIcon new_icons[MAX_DESKTOP_ICONS];
|
DesktopIcon new_icons[MAX_DESKTOP_ICONS];
|
||||||
|
|
@ -310,7 +310,7 @@ void wm_refresh_desktop(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void create_desktop_shortcut(const char *app_name) {
|
static void create_desktop_shortcut(const char *app_name) {
|
||||||
char path[128] = "/Desktop/";
|
char path[128] = "/root/Desktop/";
|
||||||
int p = 9;
|
int p = 9;
|
||||||
int n = 0; while(app_name[n]) path[p++] = app_name[n++];
|
int n = 0; while(app_name[n]) path[p++] = app_name[n++];
|
||||||
const char *ext = ".shortcut";
|
const char *ext = ".shortcut";
|
||||||
|
|
@ -1358,7 +1358,7 @@ static void wm_paint_region(int y_start, int y_end, DirtyRect dirty, int pass) {
|
||||||
if (str_ends_with(icon->name, ".elf")) draw_elf_icon(icon->x, icon->y, icon->name);
|
if (str_ends_with(icon->name, ".elf")) draw_elf_icon(icon->x, icon->y, icon->name);
|
||||||
else if (str_ends_with(icon->name, ".pnt")) draw_paint_icon(icon->x, icon->y, icon->name);
|
else if (str_ends_with(icon->name, ".pnt")) draw_paint_icon(icon->x, icon->y, icon->name);
|
||||||
else if (is_image_file(icon->name)) {
|
else if (is_image_file(icon->name)) {
|
||||||
char full_path[128] = "/Desktop/"; int p=9; int n=0; while(icon->name[n] && p < 127) full_path[p++] = icon->name[n++]; full_path[p]=0;
|
char full_path[128] = "/root/Desktop/"; int p=14; int n=0; while(icon->name[n] && p < 127) full_path[p++] = icon->name[n++]; full_path[p]=0;
|
||||||
draw_image_icon(icon->x, icon->y, full_path);
|
draw_image_icon(icon->x, icon->y, full_path);
|
||||||
draw_icon_label(icon->x, icon->y, icon->name);
|
draw_icon_label(icon->x, icon->y, icon->name);
|
||||||
}
|
}
|
||||||
|
|
@ -1702,13 +1702,13 @@ void wm_handle_click(int x, int y) {
|
||||||
|
|
||||||
if (item == 0 && desktop_menu_target_icon != -1) { // Cut
|
if (item == 0 && desktop_menu_target_icon != -1) { // Cut
|
||||||
DesktopIcon *icon = &desktop_icons[desktop_menu_target_icon];
|
DesktopIcon *icon = &desktop_icons[desktop_menu_target_icon];
|
||||||
char path[128] = "/Desktop/";
|
char path[128] = "/root/Desktop/";
|
||||||
int p=9; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
int p=14; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
||||||
explorer_clipboard_cut(path);
|
explorer_clipboard_cut(path);
|
||||||
} else if (item == 1 && desktop_menu_target_icon != -1) { // Copy
|
} else if (item == 1 && desktop_menu_target_icon != -1) { // Copy
|
||||||
DesktopIcon *icon = &desktop_icons[desktop_menu_target_icon];
|
DesktopIcon *icon = &desktop_icons[desktop_menu_target_icon];
|
||||||
char path[128] = "/Desktop/";
|
char path[128] = "/root/Desktop/";
|
||||||
int p=9; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
int p=14; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
||||||
explorer_clipboard_copy(path);
|
explorer_clipboard_copy(path);
|
||||||
} else if (item == 0 && desktop_menu_target_icon == -1) { // New File
|
} else if (item == 0 && desktop_menu_target_icon == -1) { // New File
|
||||||
desktop_dialog_state = 1;
|
desktop_dialog_state = 1;
|
||||||
|
|
@ -1729,13 +1729,13 @@ void wm_handle_click(int x, int y) {
|
||||||
int old_count = desktop_icon_count;
|
int old_count = desktop_icon_count;
|
||||||
if (desktop_menu_target_icon != -1 && desktop_icons[desktop_menu_target_icon].type == 1) {
|
if (desktop_menu_target_icon != -1 && desktop_icons[desktop_menu_target_icon].type == 1) {
|
||||||
// Paste into folder
|
// Paste into folder
|
||||||
char path[128] = "/Desktop/";
|
char path[128] = "/root/Desktop/";
|
||||||
DesktopIcon *icon = &desktop_icons[desktop_menu_target_icon];
|
DesktopIcon *icon = &desktop_icons[desktop_menu_target_icon];
|
||||||
int p=9; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
int p=14; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
||||||
explorer_clipboard_paste(&win_explorer, path);
|
explorer_clipboard_paste(&win_explorer, path);
|
||||||
} else {
|
} else {
|
||||||
// Paste to desktop
|
// Paste to desktop
|
||||||
explorer_clipboard_paste(&win_explorer, "/Desktop");
|
explorer_clipboard_paste(&win_explorer, "/root/Desktop");
|
||||||
}
|
}
|
||||||
refresh_desktop_icons();
|
refresh_desktop_icons();
|
||||||
|
|
||||||
|
|
@ -1756,8 +1756,8 @@ void wm_handle_click(int x, int y) {
|
||||||
}
|
}
|
||||||
else if (item == 3 && desktop_menu_target_icon != -1) { // Delete
|
else if (item == 3 && desktop_menu_target_icon != -1) { // Delete
|
||||||
DesktopIcon *icon = &desktop_icons[desktop_menu_target_icon];
|
DesktopIcon *icon = &desktop_icons[desktop_menu_target_icon];
|
||||||
char path[128] = "/Desktop/";
|
char path[128] = "/root/Desktop/";
|
||||||
int p=9; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
int p=14; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
||||||
explorer_delete_recursive(path);
|
explorer_delete_recursive(path);
|
||||||
refresh_desktop_icons();
|
refresh_desktop_icons();
|
||||||
}
|
}
|
||||||
|
|
@ -1782,10 +1782,10 @@ void wm_handle_click(int x, int y) {
|
||||||
int dlg_x = (sw - 300) / 2; int dlg_y = (sh - 110) / 2;
|
int dlg_x = (sw - 300) / 2; int dlg_y = (sh - 110) / 2;
|
||||||
if (rect_contains(dlg_x + 50, dlg_y + 65, 80, 25, x, y)) { // Confirm
|
if (rect_contains(dlg_x + 50, dlg_y + 65, 80, 25, x, y)) { // Confirm
|
||||||
if (desktop_dialog_state == 8) { // Rename
|
if (desktop_dialog_state == 8) { // Rename
|
||||||
char old_path[128] = "/Desktop/";
|
char old_path[128] = "/root/Desktop/";
|
||||||
char new_path[128] = "/Desktop/";
|
char new_path[128] = "/root/Desktop/";
|
||||||
int p=9; int n=0; while(desktop_icons[desktop_dialog_target].name[n]) old_path[p++] = desktop_icons[desktop_dialog_target].name[n++]; old_path[p]=0;
|
int p=14; int n=0; while(desktop_icons[desktop_dialog_target].name[n]) old_path[p++] = desktop_icons[desktop_dialog_target].name[n++]; old_path[p]=0;
|
||||||
p=9; n=0; while(desktop_dialog_input[n]) new_path[p++] = desktop_dialog_input[n++]; new_path[p]=0;
|
p=14; n=0; while(desktop_dialog_input[n]) new_path[p++] = desktop_dialog_input[n++]; new_path[p]=0;
|
||||||
|
|
||||||
if (fat32_rename(old_path, new_path)) {
|
if (fat32_rename(old_path, new_path)) {
|
||||||
refresh_desktop_icons();
|
refresh_desktop_icons();
|
||||||
|
|
@ -1795,8 +1795,8 @@ void wm_handle_click(int x, int y) {
|
||||||
if (desktop_icon_count >= desktop_max_cols * desktop_max_rows_per_col) {
|
if (desktop_icon_count >= desktop_max_cols * desktop_max_rows_per_col) {
|
||||||
wm_show_message("Error", "Desktop is full!");
|
wm_show_message("Error", "Desktop is full!");
|
||||||
} else if (desktop_dialog_input[0] != 0) {
|
} else if (desktop_dialog_input[0] != 0) {
|
||||||
char path[128] = "/Desktop/";
|
char path[128] = "/root/Desktop/";
|
||||||
int p=9; int n=0; while(desktop_dialog_input[n]) path[p++] = desktop_dialog_input[n++]; path[p]=0;
|
int p=14; int n=0; while(desktop_dialog_input[n]) path[p++] = desktop_dialog_input[n++]; path[p]=0;
|
||||||
if (desktop_dialog_state == 1) {
|
if (desktop_dialog_state == 1) {
|
||||||
FAT32_FileHandle *fh = fat32_open(path, "w");
|
FAT32_FileHandle *fh = fat32_open(path, "w");
|
||||||
if (fh) fat32_close(fh);
|
if (fh) fat32_close(fh);
|
||||||
|
|
@ -2130,8 +2130,8 @@ static void wm_handle_mouse_internal(int dx, int dy, uint8_t buttons, int dz) {
|
||||||
drag_icon_orig_x = icon->x;
|
drag_icon_orig_x = icon->x;
|
||||||
drag_icon_orig_y = icon->y;
|
drag_icon_orig_y = icon->y;
|
||||||
// Construct path
|
// Construct path
|
||||||
char path[128] = "/Desktop/";
|
char path[128] = "/root/Desktop/";
|
||||||
int p=9; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
int p=14; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
||||||
int k=0; while(path[k]) { drag_file_path[k] = path[k]; k++; } drag_file_path[k]=0;
|
int k=0; while(path[k]) { drag_file_path[k] = path[k]; k++; } drag_file_path[k]=0;
|
||||||
}
|
}
|
||||||
// 2. Check Explorer Items
|
// 2. Check Explorer Items
|
||||||
|
|
@ -2184,7 +2184,7 @@ static void wm_handle_mouse_internal(int dx, int dy, uint8_t buttons, int dz) {
|
||||||
if (start_menu_pending_app) {
|
if (start_menu_pending_app) {
|
||||||
// Launch App
|
// Launch App
|
||||||
if (str_starts_with(start_menu_pending_app, "Files")) {
|
if (str_starts_with(start_menu_pending_app, "Files")) {
|
||||||
explorer_open_directory("/");
|
explorer_open_directory("/root");
|
||||||
} else if (str_starts_with(start_menu_pending_app, "Notepad")) {
|
} else if (str_starts_with(start_menu_pending_app, "Notepad")) {
|
||||||
Window *existing = wm_find_window_by_title_locked("Notepad");
|
Window *existing = wm_find_window_by_title_locked("Notepad");
|
||||||
if (existing) {
|
if (existing) {
|
||||||
|
|
@ -2279,8 +2279,8 @@ static void wm_handle_mouse_internal(int dx, int dy, uint8_t buttons, int dz) {
|
||||||
|
|
||||||
if (!handled) {
|
if (!handled) {
|
||||||
// Generic Shortcut Handling
|
// Generic Shortcut Handling
|
||||||
char path[128] = "/Desktop/";
|
char path[128] = "/root/Desktop/";
|
||||||
int p=9; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
int p=14; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
||||||
|
|
||||||
if (str_ends_with(icon->name, ".shortcut") && !str_starts_with(icon->name, "Recycle Bin")) {
|
if (str_ends_with(icon->name, ".shortcut") && !str_starts_with(icon->name, "Recycle Bin")) {
|
||||||
FAT32_FileHandle *fh = fat32_open(path, "r");
|
FAT32_FileHandle *fh = fat32_open(path, "r");
|
||||||
|
|
@ -2303,12 +2303,12 @@ static void wm_handle_mouse_internal(int dx, int dy, uint8_t buttons, int dz) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (icon->type == 1) { // Folder
|
} else if (icon->type == 1) { // Folder
|
||||||
char path[128] = "/Desktop/";
|
char path[128] = "/root/Desktop/";
|
||||||
int p=9; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
int p=14; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
||||||
explorer_open_directory(path);
|
explorer_open_directory(path);
|
||||||
} else { // File
|
} else { // File
|
||||||
char path[128] = "/Desktop/";
|
char path[128] = "/root/Desktop/";
|
||||||
int p=9; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
int p=14; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0;
|
||||||
|
|
||||||
if (str_ends_with(icon->name, ".elf")) {
|
if (str_ends_with(icon->name, ".elf")) {
|
||||||
process_create_elf(path, NULL);
|
process_create_elf(path, NULL);
|
||||||
|
|
@ -2354,7 +2354,7 @@ static void wm_handle_mouse_internal(int dx, int dy, uint8_t buttons, int dz) {
|
||||||
explorer_import_file(drop_win, drag_file_path);
|
explorer_import_file(drop_win, drag_file_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (str_starts_with(drag_file_path, "/Desktop/")) {
|
if (str_starts_with(drag_file_path, "/root/Desktop/")) {
|
||||||
refresh_desktop_icons();
|
refresh_desktop_icons();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -2366,15 +2366,15 @@ static void wm_handle_mouse_internal(int dx, int dy, uint8_t buttons, int dz) {
|
||||||
bool dropped_on_target = false;
|
bool dropped_on_target = false;
|
||||||
for (int i = 0; i < desktop_icon_count; i++) {
|
for (int i = 0; i < desktop_icon_count; i++) {
|
||||||
if (from_desktop) {
|
if (from_desktop) {
|
||||||
char path[128] = "/Desktop/";
|
char path[128] = "/root/Desktop/";
|
||||||
int p=9; int n=0; while(desktop_icons[i].name[n]) path[p++] = desktop_icons[i].name[n++]; path[p]=0;
|
int p=14; int n=0; while(desktop_icons[i].name[n]) path[p++] = desktop_icons[i].name[n++]; path[p]=0;
|
||||||
if (str_eq(path, drag_file_path) != 0) continue;
|
if (str_eq(path, drag_file_path) != 0) continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rect_contains(desktop_icons[i].x + 20, desktop_icons[i].y, 40, 40, mx, my)) {
|
if (rect_contains(desktop_icons[i].x + 20, desktop_icons[i].y, 40, 40, mx, my)) {
|
||||||
if (desktop_icons[i].type == 1) {
|
if (desktop_icons[i].type == 1) {
|
||||||
char target_path[256] = "/Desktop/";
|
char target_path[256] = "/root/Desktop/";
|
||||||
int p=9; int n=0; while(desktop_icons[i].name[n]) target_path[p++] = desktop_icons[i].name[n++]; target_path[p]=0;
|
int p=14; int n=0; while(desktop_icons[i].name[n]) target_path[p++] = desktop_icons[i].name[n++]; target_path[p]=0;
|
||||||
explorer_import_file_to(&win_explorer, drag_file_path, target_path);
|
explorer_import_file_to(&win_explorer, drag_file_path, target_path);
|
||||||
refresh_desktop_icons();
|
refresh_desktop_icons();
|
||||||
dropped_on_target = true;
|
dropped_on_target = true;
|
||||||
|
|
@ -2397,7 +2397,7 @@ static void wm_handle_mouse_internal(int dx, int dy, uint8_t buttons, int dz) {
|
||||||
if (desktop_icon_count >= desktop_max_cols * desktop_max_rows_per_col) {
|
if (desktop_icon_count >= desktop_max_cols * desktop_max_rows_per_col) {
|
||||||
wm_show_message("Error", "Desktop is full!");
|
wm_show_message("Error", "Desktop is full!");
|
||||||
} else {
|
} else {
|
||||||
explorer_import_file_to(&win_explorer, drag_file_path, "/Desktop");
|
explorer_import_file_to(&win_explorer, drag_file_path, "/root/Desktop");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle insertion at specific position
|
// Handle insertion at specific position
|
||||||
|
|
@ -2453,8 +2453,8 @@ static void wm_handle_mouse_internal(int dx, int dy, uint8_t buttons, int dz) {
|
||||||
} else if (!dropped_on_target) {
|
} else if (!dropped_on_target) {
|
||||||
int dragged_idx = -1;
|
int dragged_idx = -1;
|
||||||
for(int i=0; i<desktop_icon_count; i++) {
|
for(int i=0; i<desktop_icon_count; i++) {
|
||||||
char path[128] = "/Desktop/";
|
char path[128] = "/root/Desktop/";
|
||||||
int p=9; int n=0; while(desktop_icons[i].name[n]) path[p++] = desktop_icons[i].name[n++]; path[p]=0;
|
int p=14; int n=0; while(desktop_icons[i].name[n]) path[p++] = desktop_icons[i].name[n++]; path[p]=0;
|
||||||
if (str_eq(path, drag_file_path) != 0) {
|
if (str_eq(path, drag_file_path) != 0) {
|
||||||
dragged_idx = i;
|
dragged_idx = i;
|
||||||
break;
|
break;
|
||||||
|
|
@ -2634,10 +2634,10 @@ static void wm_dispatch_key(char c, bool pressed) {
|
||||||
int len = 0; while(desktop_dialog_input[len]) len++;
|
int len = 0; while(desktop_dialog_input[len]) len++;
|
||||||
if (c == '\n') {
|
if (c == '\n') {
|
||||||
if (desktop_dialog_state == 8) { // Rename
|
if (desktop_dialog_state == 8) { // Rename
|
||||||
char old_path[128] = "/Desktop/";
|
char old_path[128] = "/root/Desktop/";
|
||||||
char new_path[128] = "/Desktop/";
|
char new_path[128] = "/root/Desktop/";
|
||||||
int p=9; int n=0; while(desktop_icons[desktop_dialog_target].name[n]) old_path[p++] = desktop_icons[desktop_dialog_target].name[n++]; old_path[p]=0;
|
int p=14; int n=0; while(desktop_icons[desktop_dialog_target].name[n]) old_path[p++] = desktop_icons[desktop_dialog_target].name[n++]; old_path[p]=0;
|
||||||
p=9; n=0; while(desktop_dialog_input[n]) new_path[p++] = desktop_dialog_input[n++]; new_path[p]=0;
|
p=14; n=0; while(desktop_dialog_input[n]) new_path[p++] = desktop_dialog_input[n++]; new_path[p]=0;
|
||||||
if (fat32_rename(old_path, new_path)) {
|
if (fat32_rename(old_path, new_path)) {
|
||||||
refresh_desktop_icons();
|
refresh_desktop_icons();
|
||||||
explorer_refresh_all();
|
explorer_refresh_all();
|
||||||
|
|
@ -2646,8 +2646,8 @@ static void wm_dispatch_key(char c, bool pressed) {
|
||||||
if (desktop_icon_count >= desktop_max_cols * desktop_max_rows_per_col) {
|
if (desktop_icon_count >= desktop_max_cols * desktop_max_rows_per_col) {
|
||||||
wm_show_message("Error", "Desktop is full!");
|
wm_show_message("Error", "Desktop is full!");
|
||||||
} else if (desktop_dialog_input[0] != 0) {
|
} else if (desktop_dialog_input[0] != 0) {
|
||||||
char path[128] = "/Desktop/";
|
char path[128] = "/root/Desktop/";
|
||||||
int p=9; int n=0; while(desktop_dialog_input[n]) path[p++] = desktop_dialog_input[n++]; path[p]=0;
|
int p=14; int n=0; while(desktop_dialog_input[n]) path[p++] = desktop_dialog_input[n++]; path[p]=0;
|
||||||
if (desktop_dialog_state == 1) {
|
if (desktop_dialog_state == 1) {
|
||||||
FAT32_FileHandle *fh = fat32_open(path, "w");
|
FAT32_FileHandle *fh = fat32_open(path, "w");
|
||||||
if (fh) fat32_close(fh);
|
if (fh) fat32_close(fh);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue