Compare commits

122 Commits
Author SHA1 Message Date
rusya 59237ab375 sb16: cleanup and add stereo support 2026-05-20 15:24:01 +03:00
rusya a77b51699c sb16: finally make the driver work 2026-05-20 14:50:17 +03:00
rusya 312c543510 sb16: continue trying to add a driver 2026-05-09 15:21:07 +03:00
rusya 59b775457d sb16: start adding sb16 driver 2026-05-09 14:51:54 +03:00
rusya ab2da499da mm: kill current task on usermode pagefault and fix destroy_page_dir destroying kernel space mappings 2026-04-16 15:19:12 +03:00
rusya 64d5cd1d2f tasking: prevent many page faults 2026-04-16 15:19:12 +03:00
rusya 560003b6e3 syscalls: implement statx syscall 2026-01-31 20:51:47 +03:00
rusya 93fe3a179b syscalls: stop freezing on brk syscall where ebx < current brk 2026-01-31 20:49:52 +03:00
rusya 761789a42e get rid of useless types.h header 2026-01-16 17:59:26 +03:00
rusya 64f86a961d syscalls: let open syscall work with directories 2026-01-16 17:46:00 +03:00
rusya 466c1a61af tasking: don't forget to free the cwd on a dead process 2026-01-13 23:29:49 +03:00
rusya 9fe2331ca7 syscalls: implement stat and fstat syscalls 2026-01-13 23:29:16 +03:00
rusya 4cef109e90 add cdrom-debug makefile target 2025-12-10 23:50:28 +03:00
rusya 3417fd7d13 syscalls: fix execve crash and heap-related problems 2025-12-10 23:47:21 +03:00
rusya 9e68f71cd0 mm: make page bitmap smaller and stop whining if a page was already free in clear_bit 2025-12-10 00:48:35 +03:00
rusya 53e380e510 syscalls: fix execve to use heap and make it work better with fork 2025-12-10 00:47:46 +03:00
rusya 51dc254aa3 mm: improve stability by making the page bitmap full by default, also implement liballoc_lock and liballoc_unlock 2025-12-09 23:35:15 +03:00
rusya 2a7f62e275 mm: make get_physaddr return NULL if PD or PT is not present 2025-12-09 23:34:15 +03:00
rusya 24caf9c8aa syscalls: fix execve syscall making GPF 2025-11-23 15:55:18 +03:00
rusya a358d0b1ac syscalls: hopefully fix fork syscall 2025-11-23 15:23:38 +03:00
rusya c8036a9aae screen: fix backspace handling 2025-11-20 21:20:11 +03:00
rusya 697029016e syscalls: hopefully fix chdir syscall breaking sometimes 2025-11-20 21:12:05 +03:00
rusya 1f90fb5825 screen: implement cursor positioning 2025-11-20 20:13:45 +03:00
rusya 0b0492e756 syscalls: stop requiring a trailing slash for directories in chdir and vfs: emove some debug_log calls in follow_path 2025-11-20 20:13:45 +03:00
rusya 827189593c syscalls: make chdir follow path from the current->cwd and return 0 if there's no error 2025-11-20 16:12:40 +03:00
rusya a66a5da039 add creation of directory /katau/huy into the makefile 2025-11-20 16:11:16 +03:00
rusya 0de9f026b6 vfs: make vfs_read_file_by_path return error on error 2025-11-20 16:10:49 +03:00
rusya c17c23ddd5 tasking: make idle task halt 2025-11-20 15:53:57 +03:00
rusya 7dc522eb3d syscalls: remove excessive debug_log from sys_brk 2025-11-18 17:54:24 +03:00
rusya 68033325d2 implement prover stdin reading 2025-11-18 17:54:24 +03:00
rusya ccf954e1d6 mm: add a warning in map_page if a page is already mapped 2025-11-05 21:03:06 +03:00
rusya 57d2931b96 mm: fix mapping memory in non-present PDEs 2025-11-05 20:59:01 +03:00
rusya 561de6a4e3 syscalls: hopefully implement chdir syscall 2025-10-30 22:29:06 +03:00
rusya f4b0429062 syscalls: implement getcwd syscall 2025-10-30 20:26:28 +03:00
rusya 26c8280059 syscalls: fix page count for mapping in sys_execve and make caller run coreutils 2025-10-07 23:41:55 +03:00
rusya 88c1936e83 syscalls: make execve and vfs_read_file_by_path use follow_path, fix vfs_read_file_by_path name, fix execve-related pagefault 2025-10-07 23:41:55 +03:00
rusya 8c26f54d28 update buildroot-config 2025-10-01 21:15:38 +03:00
rusya 05fa945421 continue working on correct shell loading 2025-10-01 21:15:26 +03:00
rusya 2019f87b14 make exec_from_file take l9660_file* instead of a filename 2025-09-23 20:13:34 +03:00
rusya f697fab390 vfs: add follow_path function 2025-09-23 19:38:14 +03:00
rusya 1fb777adb0 improve makefile to work with buildroot iso 2025-09-18 14:54:27 +03:00
rusya 3ca60aea00 fix buildroot config 2025-09-18 14:53:27 +03:00
rusya bacf6f6782 update buildroot config to have linux use arch default config 2025-09-16 23:02:59 +03:00
rusya 2c8b5d4752 syscalls: implement argv and envp handling in execve 2025-09-16 22:41:32 +03:00
rusya 7c2f3735bf add buildroot config 2025-09-14 18:12:39 +03:00
rusya 91e0379fc9 syscalls: implement basic execve syscall, no argc, argv, envp support yet 2025-09-14 17:17:42 +03:00
rusya 4c26652ee2 syscalls: remove start_time from sys_nanosleep 2025-09-03 16:49:52 +03:00
rusya 63938e1acd syscalls: fix nanosleep, thanks to gemini, sorry for that 2025-09-03 16:35:07 +03:00
rusya 5b922ea773 syscalls: start trying to add nanosleep syscall 2025-09-02 00:15:29 +03:00
rusya a459751453 apic: init apic timer using pit, not precise on qemu 2025-09-01 23:22:33 +03:00
rusya 982f1a5fae apic: make msr-related function names consistent with the overall style 2025-08-30 21:11:51 +03:00
rusya 649c4c56a4 apic: fix timer and keyboard handling 2025-08-30 20:57:44 +03:00
rusya fb8dd43dd3 start implementing APIC utils 2025-08-29 18:35:22 +03:00
rusya 9e21167bd3 vfs: put test_iso9660 into vfs.c 2025-08-29 17:08:06 +03:00
rusya 7c43956ebe vfs: introduce adjustable ISO9660 buffer length for file reading 2025-08-22 17:50:42 +03:00
rusya 9bb6d9d1a5 screen: implement cursorhome terminal command 2025-08-22 17:43:41 +03:00
rusya fffa4b7699 kmain: allocate first 16 pages for stack 2025-08-20 21:01:09 +03:00
rusya 92511dbcd7 tasking: fix stack corruption on the scheduler trigger 2025-08-20 20:59:08 +03:00
rusya 9fdc551308 syscalls: improve working with files using vfs 2025-08-17 16:03:41 +03:00
rusya caa4005990 exec_from_file and vfs: fix reading file 2025-08-17 15:02:09 +03:00
rusya 0628470a7c still trying to read a file 2025-08-16 21:43:42 +03:00
rusya ce6e9642ee continue working on implementing lib9660 into the kernel 2025-08-16 19:41:48 +03:00
rusya 287ac77422 add lib9660 and test_iso9660 function 2025-08-14 21:41:54 +03:00
rusya ea39cb85f3 add atapi driver 2025-08-14 21:13:10 +03:00
rusya d017f0b245 syscalls: continue making brk syscall 2025-07-31 17:54:20 +03:00
rusya df45ffe2ce tasking: add brk to process struct 2025-07-31 17:02:56 +03:00
rusya 992d82c6d4 syscalls: make use of stderr and fix chdir syscall return value 2025-07-18 22:43:34 +03:00
rusya 3ae26ed88a syscalls: fix cwd-related stuff 2025-07-18 21:02:54 +03:00
rusya 359e5c6d78 syscalls: add chdir and getcwd syscalls, not tested yet 2025-07-16 15:42:35 +03:00
rusya aac4375b8e syscalls: add getpid syscall 2025-07-16 15:21:19 +03:00
rusya 8bc7e1d523 syscalls: fix handle_syscall function performing more that 1 syscall at a time 2025-07-09 17:23:18 +03:00
rusya a01120cfe4 tasking: switch tss.esp0 on switching process 2025-07-09 16:44:19 +03:00
rusya 5b5de55919 i'm so close 2025-07-08 18:53:06 +03:00
rusya a9f8e96ac9 fuck that fork syscall 2025-07-08 18:42:33 +03:00
rusya c2293b8996 syscalls: close to being done with fork syscall 2025-07-07 22:22:10 +03:00
rusya 7f861a8b92 mm: fix copy_page_dir 2025-07-07 20:37:48 +03:00
rusya e793e45854 syscalls: continue working on fork syscall 2025-07-07 00:19:35 +03:00
rusya 2a7baf1184 syscalls: start adding fork syscall, not done yet 2025-07-06 22:49:05 +03:00
rusya cbd2c52c20 a little cleanup 2025-06-24 17:41:38 +03:00
rusya e3eba88958 mm: fix page fault on process exit 2025-06-24 17:08:22 +03:00
rusya bfdd3b6b6a mm: replace some printfs with debug_log 2025-06-23 23:47:29 +03:00
rusya b769ac0a58 tasking: continue fixing task_kill 2025-06-23 23:41:01 +03:00
rusya 29de6e6f43 tasking: a small cleanup 2025-06-23 00:36:07 +03:00
rusya c047dd687b tasking: implement task_kill function, thanks deepseek 2025-06-23 00:25:23 +03:00
rusya 70d6aacb91 syscalls: start adding exit syscall, not done yet 2025-06-21 18:54:52 +03:00
rusya bb096f826a syscalls: implement read syscall 2025-06-21 17:09:34 +03:00
rusya bf7d96865a syscalls: done with open, write, close syscalls 2025-06-20 23:06:01 +03:00
rusya 4ccae473ca syscalls: start implementing some basic syscalls 2025-06-20 21:59:08 +03:00
rusya a9789b7f57 tasking: fix syscall handling, use debug_log instead of printf in some places 2025-06-19 18:31:15 +03:00
rusya 93f174827b tasking: start handling syscalls 2025-06-19 17:58:49 +03:00
rusya 5fa2393fd6 tasking: fix ELF file execution 2025-06-07 18:18:05 +03:00
rusya 9f721a72b7 tasking: fix virtual mapping count in exec_from_file 2025-06-07 15:07:26 +03:00
rusya 2408b67ccc tasking: continue working on executing ELF files 2025-06-06 20:20:45 +03:00
rusya ea6733fd46 kmain: fix heap initialization and use kvalloc instead of alloc_page 2025-06-06 14:16:47 +03:00
rusya 01155234c6 tools: add elf tool 2025-06-06 00:39:21 +03:00
rusya 541bc7172f mm: implement heap with liballoc, might review later 2025-06-06 00:36:22 +03:00
rusya d1ac41deeb tasking, mm: remove unused functions and page_directory field from the Task struct 2025-06-01 14:04:49 +03:00
rusya 5f87e55067 tasking: make jump_usermode2 lock the scheduler & test the second user task 2025-06-01 13:53:06 +03:00
rusya 8fea7a8ec6 tasking: isolate ring3 tasks 2025-06-01 01:24:31 +03:00
rusya f47a4a451d tasking: fix separate page directory creation for new ring0 tasks 2025-06-01 00:15:06 +03:00
rusya 9000d76441 tasking: continue working on page directory switching 2025-05-31 19:43:38 +03:00
rusya 33aa97c6ec mm: add get_page_dir & set_page_dir 2025-05-31 18:09:56 +03:00
rusya d5f41b1ef9 mm: fix pagetable calculation in get_physaddr & map_page 2025-05-31 17:52:36 +03:00
rusya 681f509099 some cleanups here and there 2025-05-31 17:47:56 +03:00
rusya 7c870636c5 a little cleanup in task.c and paging.h 2025-05-29 23:13:03 +03:00
rusya c808a5d295 fix creating ring 3 tasks finally 2025-05-29 21:18:09 +03:00
rusya b8752ee39d gonna ask tsoding for help, fuck this shit 2025-05-20 00:10:37 +03:00
rusya bc0bd99f95 fuck1 2025-05-19 21:44:07 +03:00
rusya e2b596dcbd fuckfuckfuckfuck 2025-05-16 16:44:13 +03:00
rusya 5d012b410d yo almost, i guess... 2025-05-16 16:34:30 +03:00
rusya 44d09ab13f fuckfuck 2025-05-16 15:49:50 +03:00
rusya 2e372ae9c4 maybe i'm close to fixing multitasking 2025-05-16 14:55:19 +03:00
rusya 4fbaed321c rename myos.bin to katauos.bin everywhere 2025-05-10 15:48:10 +03:00
rusya 767e74976f merge branch memory-shit into higher-half 2025-05-10 15:48:10 +03:00
rusya 65f543fa92 put memory map detection into paging.c (grub_memory_map function) 2025-05-10 15:48:10 +03:00
rusya 745d85f413 add getting memory map from grub 2025-05-10 15:48:10 +03:00
rusya 0bf26a6c70 organization 2025-05-10 15:48:10 +03:00
rusya 00c9560660 kmain: add multiboot magic as an argument 2025-05-10 15:48:10 +03:00
rusya d4a14633ce something 2025-05-10 15:48:10 +03:00
rusya b836a37264 some test things 2025-05-10 15:48:06 +03:00
rusya 7e97987e95 add multiboot.h 2025-04-14 16:30:10 +03:00
rusya ab72a7ee18 kmain: get bootloader name as a test of mbi thing 2025-04-14 16:29:59 +03:00
70 changed files with 20266 additions and 1568 deletions
+5 -1
View File
@@ -1,3 +1,7 @@
bin/
myos.bin
katauos.bin
boot.iso
.vscode/
cross-compiler-i686/
buildroot-2025.08/
rootfs.iso9660
+97 -18
View File
@@ -1,44 +1,48 @@
# Define the object files
OBJS = bin/boot.o bin/kernel.o bin/idt.o bin/isr.o bin/screen.o \
bin/utils.o bin/string.o bin/stdio.o bin/disk.o bin/pic.o bin/pit.o \
bin/keyboard.o bin/paging.o bin/heap.o bin/page_alloc.o bin/page_tables.o \
bin/fat.o bin/task.o bin/switch.o bin/sys_exit.o
bin/keyboard.o bin/paging.o bin/page_alloc.o bin/page_tables.o \
bin/fat.o bin/task.o bin/switch.o bin/sys_exit.o bin/gdt.o bin/isr-asm.o \
bin/kheap.o bin/liballoc.o bin/exec_from_file.o bin/syscalls.o bin/atapi.o \
bin/lib9660.o bin/vfs.o bin/apic.o bin/sb16.o
# Define the compiler and assembler
#CC = i686-elf-gcc -D__is_katauos
CC = gcc -D__is_katauos
AS = nasm
#LD = i686-elf-ld
LD = ld
# Define the compiler flags
CFLAGS = -I./include/ -std=gnu99 -ffreestanding -O0 -Wall -Wextra -m32 -g
CFLAGS = -I./include/ -std=gnu99 -ffreestanding -O0 -Wall -Wextra -m32 -fno-pie -fno-common -g
ASFLAGS = -f elf32
# Define the linker flags
LDFLAGS = -ffreestanding -O0 -nostdlib -m32 -g -lgcc
LDFLAGS = -m elf_i386 -L$(shell $(CC) -print-libgcc-file-name | xargs dirname)/32/ -lgcc
LDSCRIPT = link.ld
# Define the output file
OUTPUT = myos.bin
OUTPUT = katauos.bin
all: $(OUTPUT)
create-image:
cp myos.bin grubshit/boot/
cp katauos.bin grubshit/boot/
dd if=/dev/zero of=boot.iso bs=1M count=256
parted boot.iso --script mklabel msdos
parted boot.iso --script mkpart primary fat32 1MiB 100%
sudo losetup /dev/loop0 boot.iso
sudo losetup /dev/loop1 boot.iso -o 1048576
#sudo mkdosfs -F32 -f 2 /dev/loop1
sudo mkfs.vfat -F32 -f 2 /dev/loop1
sudo mount /dev/loop1 /mnt
sudo grub-install --root-directory=/mnt --no-floppy --modules="normal part_msdos ext2 multiboot biosdisk" /dev/loop0 #there was biosdev also
sudo grub-install --root-directory=/mnt --no-floppy --modules="normal part_msdos ext2 multiboot biosdisk" /dev/loop0
sudo cp -r grubshit/* /mnt/
sync
sudo umount /mnt
sudo losetup -D
image:
cp myos.bin grubshit/boot
cp katauos.bin grubshit/boot
sudo losetup /dev/loop0 boot.iso
sudo losetup /dev/loop1 boot.iso -o 1048576
sudo mount /dev/loop1 /mnt
@@ -47,18 +51,63 @@ image:
sudo umount /mnt
sudo losetup -D
iso:
mkdir -p tmp
mkdir -p katauos
mkdir -p katauos/katau/huy
sudo mount rootfs.iso9660 tmp/
sudo cp -R tmp/* katauos/
sudo chown -R kali:kali katauos/
cp katauos.bin grubshit/boot
cp katauos.bin katauos/boot/
cp grubshit/boot/grub/grub.cfg katauos/boot/grub/grub.cfg
cp grubshit/caller katauos/katau/caller
cp grubshit/callee katauos/katau/callee
cp grubshit/callee2 katauos/katau/callee2
cp grubshit/zsh katauos/katau/zsh
cp grubshit/ksh katauos/katau/ksh
cp grubshit/ls katauos/katau/ls
cp grubshit/stat katauos/katau/stat
cp grubshit/stat.c katauos/katau/stat.c
cp grubshit/main katauos/main
cp grubshit/video.dat katauos/katau/video.dat
cp grubshit/statx katauos/katau/statx
cp grubshit/kplayer katauos/katau/kplr
cp grubshit/iosys.wav katauos/katau/io.wav
cp grubshit/iosys_stereo.wav katauos/katau/ios.wav
sudo umount tmp/
grub-mkrescue -o boot.iso katauos/
test-cdrom:
qemu-system-i386 -cdrom boot.iso -m 4096M -d int
cdrom:
qemu-system-i386 -cdrom boot.iso -m 32M -device sb16
cdrom-debug:
qemu-system-i386 -s -S -cdrom boot.iso -m 32M -monitor stdio
debug-cdrom:
qemu-system-i386 -s -S -cdrom boot.iso -m 4096M -monitor stdio
test:
qemu-system-i386 -drive file=boot.iso,media=disk,format=raw -m 512M -d int
#qemu-system-i386 -s -S -kernel myos.bin
qemu-system-i386 -drive file=boot.iso,media=disk,format=raw -m 4096M -d int
debug:
qemu-system-i386 -s -S -kernel myos.bin
qemu-system-i386 -s -S -kernel katauos.bin -monitor stdio
debug2:
qemu-system-i386 -s -S -drive file=boot.iso,media=disk,format=raw -m 4096M -monitor stdio
test-bochs:
bochs -f bochsrc
$(OUTPUT): $(OBJS)
$(CC) -T $(LDSCRIPT) -o $@ $(OBJS) $(LDFLAGS)
$(LD) -N -T $(LDSCRIPT) -nostdlib -o $@ $(OBJS) $(LDFLAGS)
bin/boot.o: src/boot.asm
$(AS) $(ASFLAGS) $< -o $@
@@ -99,16 +148,13 @@ bin/keyboard.o: src/drivers/keyboard.c
bin/paging.o: src/mm/paging.c
$(CC) $(CFLAGS) -c $< -o $@
bin/heap.o: src/mm/heap.c
$(CC) $(CFLAGS) -c $< -o $@
bin/page_alloc.o: src/mm/page_alloc.c
$(CC) $(CFLAGS) -c $< -o $@
bin/page_tables.o: src/mm/page_tables.c
$(CC) $(CFLAGS) -c $< -o $@
bin/fat.o: src/drivers/fat.c
bin/fat.o: src/fs/fat.c
$(CC) $(CFLAGS) -c $< -o $@
bin/switch.o: src/tasking/switch.asm
@@ -120,9 +166,42 @@ bin/task.o: src/tasking/task.c
bin/sys_exit.o: src/tasking/sys_exit.asm
$(AS) $(ASFLAGS) $< -o $@
bin/gdt.o: src/kernel/gdt.c
$(CC) $(CFLAGS) -c $< -o $@
bin/isr-asm.o: src/kernel/isr.asm
$(AS) $(ASFLAGS) $< -o $@
bin/kheap.o: src/mm/kheap.c
$(CC) $(CFLAGS) -c $< -o $@
bin/liballoc.o: src/mm/liballoc.c
$(CC) $(CFLAGS) -c $< -o $@
bin/exec_from_file.o: src/tasking/exec_from_file.c
$(CC) $(CFLAGS) -c $< -o $@
bin/syscalls.o: src/tasking/syscalls.c
$(CC) $(CFLAGS) -c $< -o $@
bin/atapi.o: src/drivers/atapi.c
$(CC) $(CFLAGS) -c $< -o $@
bin/lib9660.o: src/fs/lib9660.c
$(CC) $(CFLAGS) -c $< -o $@
bin/vfs.o: src/fs/vfs.c
$(CC) $(CFLAGS) -c $< -o $@
bin/apic.o: src/kernel/apic.c
$(CC) $(CFLAGS) -c $< -o $@
bin/sb16.o: src/drivers/sb16.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -rf bin/
rm -f $(OUTPUT)
rm boot.iso
rm -f boot.iso
.PHONY: all clean
+4 -4
View File
@@ -1,6 +1,6 @@
romimage: file=$BXSHARE/BIOS-bochs-latest
vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest
#boot: cdrom
#ata0-master: type=cdrom, path="boot.iso", status=inserted
boot:disk
ata0-master: type=disk, path="boot.iso", cylinders=306, heads=16, spt=17
boot: cdrom
ata0-master: type=cdrom, path="boot.iso", status=inserted
#boot:disk
#ata0-master: type=disk, path="boot.iso", cylinders=306, heads=16, spt=17
+6457
View File
File diff suppressed because it is too large Load Diff
Executable
BIN
View File
Binary file not shown.
+45
View File
@@ -0,0 +1,45 @@
section .data
file_path db 'test.txt', 0 ; File path
message db 'Hello, World from KatauOS!', 10, 0 ; Message with newline
message_len equ $ - message - 1 ; Length excluding null terminator
section .bss
buffer resb 256 ; Buffer for reading file content
read_count resd 1 ; Store bytes read count
section .text
global _start
_start:
; Reopen file for reading
mov eax, 5 ; sys_open
mov ebx, file_path
mov ecx, 0 ; O_RDONLY
mov edx, 0 ; Mode (unused)
int 0x80
mov edi, eax ; Save new descriptor
; Read file content
mov eax, 3 ; sys_read
mov ebx, edi
mov ecx, buffer
mov edx, 256
int 0x80
mov [read_count], eax ; Save bytes read count
; Write to stdout
mov eax, 4 ; sys_write
mov ebx, 1 ; stdout
mov ecx, buffer
mov edx, [read_count] ; Use actual bytes read
int 0x80
; Close file
mov eax, 6 ; sys_close
mov ebx, edi
int 0x80
; Exit
mov eax, 1 ; sys_exit
xor ebx, ebx ; Return 0
int 0x80
BIN
View File
Binary file not shown.
+2 -2
View File
@@ -1,8 +1,8 @@
set default=0
set timeout=5
menuentry "katauOS" {
multiboot /boot/myos.bin
menuentry "KatauOS" {
multiboot /boot/katauos.bin
# set gfxpayload=1280x720x32
boot
}
+22
View File
@@ -0,0 +1,22 @@
// callee.c
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[], char *envp[]) {
printf("--- In callee.c ---\n");
printf("This program has taken over the process.\n");
printf("argc: %d\n", argc);
printf("\nArguments (argv):\n");
for (int i = 0; argv[i] != NULL; i++) {
printf(" argv[%d]: %s\n", i, argv[i]);
}
printf("\nEnvironment Variables (envp):\n");
for (int i = 0; envp[i] != NULL; i++) {
printf(" %s\n", envp[i]);
}
return 0;
}
+26
View File
@@ -0,0 +1,26 @@
// caller.c
#include <stdio.h>
#include <unistd.h>
int main() {
printf("--- In caller.c ---\n");
printf("This message is from the original program.\n");
printf("Calling execve to run './callee'...\n\n");
// Arguments for the new program
// The first argument is conventionally the program name
char *argv[] = { "/katau/dash", "--help", NULL };
// Environment variables for the new program
char *envp[] = { "CUSTOM_VAR=Hello from caller!", "ANOTHER_VAR=123", NULL };
// The execve system call
// The first argument is the path to the executable
// The second is the array of arguments
// The third is the array of environment variables
execve("/katau/dash.", argv, envp);
// This part of the code will only be reached if execve fails
perror("execve failed");
return 1;
}
BIN
View File
Binary file not shown.
+24
View File
@@ -0,0 +1,24 @@
#include "../include/utils.h"
#include <stdint.h>
#include <stdbool.h>
extern bool lapic_enabled;
bool check_apic();
void enable_apic();
void lapic_write(uint32_t reg_offset, uint32_t value);
uint32_t lapic_read(uint32_t reg_offset);
void lapic_eoi();
void ioapic_init();
uint32_t ioapic_read(void *ioapicaddr, uint32_t reg);
void ioapic_write(void *ioapicaddr, uint32_t reg, uint32_t value);
void ioapic_redirect(int gsi, int vector);
void enable_symmetric_io_mode();
void init_pit_timer_apic(uint32_t reload_value);
void init_apic_timer();
void mask_pit_interrupt();
+9
View File
@@ -0,0 +1,9 @@
#ifndef ATAPI_H
#define ATAPI_H
#include <stdint.h>
#include <stdbool.h>
int read_cdrom(uint16_t port, bool slave, uint32_t lba, uint32_t sectors, uint16_t *buffer);
#endif
-1
View File
@@ -11,7 +11,6 @@ typedef struct {
} disk_info;
void get_disk_info(disk_info *info);
int ide_check_disk_present();
bool ata_read(uint8_t *buffer, uint32_t lba);
bool ata_write(const uint8_t *buffer, uint32_t lba);
+3934
View File
File diff suppressed because it is too large Load Diff
+12
View File
@@ -0,0 +1,12 @@
#include "../include/elf.h"
#include "../include/stdio.h"
#include "../include/vfs.h"
#include "../include/lib9660.h"
#define DivRoundUp(number, divisor) ((number + divisor - 1) / divisor)
#define USER_STACK_TOP 0xBFFFFFF0 // Top of user space memory
#define USER_STACK_SIZE 0x4000 // 16KB stack (4 pages)
#define USER_STACK_BOTTOM (USER_STACK_TOP - USER_STACK_SIZE)
void exec_from_file(l9660_file* fs_file, l9660_dir* dir);
+95
View File
@@ -0,0 +1,95 @@
#ifndef GDT_H
#define GDT_H
#include <stdint.h>
extern char _end[], _edata[];
#define KERNEL_CS 0x08 /* kernel code segment */
#define KERNEL_DS 0x10 /* kernel data segment */
#define USER_CS 0x18 /* user code segment */
#define USER_DS 0x20 /* user data segment */
#define TSS 0x28 /* TSS segment */
#define KERNEL_BSS_SIZE ((int)_end - (int)_edata)
#define NR_GDT_ENTRIES 6 /* entries in GDT descriptor */
#define NR_IDT_ENTRIES 256 /* entries in IDT descriptor */
/* low flags of Segment Descriptors */
#define SD_CODE 0x0A /* CODE Exec/Read */
#define SD_DATA 0x02 /* DATA Read/Write */
#define SD_32INTRGATE 0x0E /* 32-bit Interrupt Gate (0D110) */
#define SD_32TRAPGATE 0x0F /* 32-bit Trap Gate (0D111) */
#define SD_CD 0x10 /* 0 = system / 1 = code/data */
#define SD_DPL0 0x00 /* priority level 0 (kernel) */
#define SD_DPL3 0x60 /* priority level 3 (user) */
#define SD_PRESENT 0x80 /* segment present or valid */
/* high flags Segment Descriptors */
#define SD_OPSIZE32 0x04 /* 32-bit code and data segments */
#define SD_PAGE4KB 0x08 /* page granularity (4KB) */
/* low flags of the TSS Descriptors */
#define SD_TSSPRESENT 0x89 /* TSS present and not busy flag */
/* EFLAGS */
#define EF_IOPL 12 /* IOPL bit */
struct desc_r {
uint16_t limit;
uint32_t base_addr;
} __attribute__((packed));
struct seg_desc {
unsigned sd_lolimit : 16; /* segment limit 0-15 bits */
unsigned sd_lobase : 24; /* base address 0-23 bits */
unsigned sd_loflags : 8; /* flags (P, DPL, S and TYPE) */
unsigned sd_hilimit : 4; /* segment limit 16-19 bits */
unsigned sd_hiflags : 4; /* flags (G, DB, 0 and AVL) */
unsigned sd_hibase : 8; /* base address 24-31 bits */
} __attribute__((packed));
struct gate_desc {
unsigned gd_looffset: 16; /* offset 0-15 bits */
unsigned gd_selector: 16; /* segment selector */
unsigned gd_flags : 16; /* flags (P, DPL, TYPE, 0 and NULL) */
unsigned gd_hioffset: 16; /* offset 16-31 bits */
} __attribute__((packed));
struct tss_entry_struct {
uint32_t prev_tss; // The previous TSS - with hardware task switching these form a kind of backward linked list.
uint32_t esp0; // The stack pointer to load when changing to kernel mode.
uint32_t ss0; // The stack segment to load when changing to kernel mode.
// Everything below here is unused.
uint32_t esp1; // esp and ss 1 and 2 would be used when switching to rings 1 or 2.
uint32_t ss1;
uint32_t esp2;
uint32_t ss2;
uint32_t cr3;
uint32_t eip;
uint32_t eflags;
uint32_t eax;
uint32_t ecx;
uint32_t edx;
uint32_t ebx;
uint32_t esp;
uint32_t ebp;
uint32_t esi;
uint32_t edi;
uint32_t es;
uint32_t cs;
uint32_t ss;
uint32_t ds;
uint32_t fs;
uint32_t gs;
uint32_t ldt;
uint16_t trap;
uint16_t iomap_base;
} __attribute__((packed));
extern struct tss_entry_struct tss;
#endif
+1 -2
View File
@@ -1,6 +1,5 @@
#ifndef IDT_H
#define IDT_H
#include "../include/types.h"
#include <stdint.h>
typedef struct {
@@ -21,7 +20,7 @@ typedef struct {
static idtr_t idtr;
void idt_set_descriptor(uint8 vector, uint32 isr, uint8_t flags);
void idt_set_descriptor(uint8_t vector, uint32_t isr, uint8_t flags);
void idt_set();
#endif
+4
View File
@@ -1,6 +1,10 @@
#ifndef ISR_H
#define ISR_H
#include <stdint.h>
extern uint32_t timer_ticks;
void isr0();
void isr1();
void isr2();
+7
View File
@@ -3,7 +3,14 @@
#include "../include/utils.h"
#include "../include/stdio.h"
#include <stdbool.h>
#define STDIN_BUFFER_SIZE 4096
extern char stdin_buffer[STDIN_BUFFER_SIZE];
extern int stdin_pos;
extern bool stdin_has_line;
void handle_keyboard();
void init_keyboard();
#endif
+16
View File
@@ -0,0 +1,16 @@
#ifndef KERNEL_HEAP_H
#define KERNEL_HEAP_H
#include <stdint.h>
#include <stddef.h>
#define KHEAP_START 0xE0000000 // Start of kernel heap
#define KHEAP_INITIAL_SIZE 0x400000 // 1 MiB initial size
#define KHEAP_END (KHEAP_START + KHEAP_INITIAL_SIZE)
#define KHEAP_PAGES (KHEAP_INITIAL_SIZE / PAGE_SIZE)
void kheap_init();
void* kvalloc(size_t npages);
void kvfree(void* addr, size_t npages);
#endif
+204
View File
@@ -0,0 +1,204 @@
/* lib9660: a simple ISO9660 reader library especially suited to embedded
* systems
*
* SPDX-License-Identifier: LicenseRef-ISC1
* SPDX-FileCopyrightText: © 2014 Erin Shepherd
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice appears in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef LIB9660_H
#define LIB9660_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#ifdef L9660_HAVE_STDIO
#include <stdio.h>
#define L9660_SEEK_END SEEK_END
#define L9660_SEEK_SET SEEK_SET
#define L9660_SEEK_CUR SEEK_CUR
#else
#define L9660_SEEK_END -1
#define L9660_SEEK_SET 0
#define L9660_SEEK_CUR +1
#endif
/* Our error return format */
typedef enum {
/*! Success! */
L9660_OK = 0,
/*! read_sector callback returned false */
L9660_EIO,
/*! file system is bad */
L9660_EBADFS,
/*! specified name does not exist */
L9660_ENOENT,
/*! attempted to open a non-file (e.g. a directory) as a file */
L9660_ENOTFILE,
/*! attempted to open a non-directory (e.g. a file) as a directory
* may be returned by l9660_openat if e.g. you pass path "a/b" and
* "a" is a file
*/
L9660_ENOTDIR,
} l9660_status;
/* ISO9660 uses big/little/dual endian integers */
typedef struct { uint8_t le[2]; } l9660_luint16;
typedef struct { uint8_t be[2]; } l9660_buint16;
typedef struct { uint8_t le[2], be[2]; } l9660_duint16;
typedef struct { uint8_t le[4]; } l9660_luint32;
typedef struct { uint8_t be[4]; } l9660_buint32;
typedef struct { uint8_t le[4], be[4]; } l9660_duint32;
/* Descriptor time format */
typedef struct {
char d[17];
} l9660_desctime;
/* File time format */
typedef struct {
char d[7];
} l9660_filetime;
/* Directory entry */
typedef struct {
uint8_t length;
uint8_t xattr_length;
l9660_duint32 sector;
l9660_duint32 size;
l9660_filetime time;
uint8_t flags;
uint8_t unit_size;
uint8_t gap_size;
l9660_duint16 vol_seq_number;
uint8_t name_len;
char name[/*name_len*/];
} l9660_dirent;
/* Volume descriptor header */
typedef struct {
uint8_t type;
char magic[5];
uint8_t version;
} l9660_vdesc_header;
/* Primary volume descriptor */
typedef struct {
l9660_vdesc_header hdr;
char pad0[1];
char system_id[32];
char volume_id[32];
char pad1[8];
l9660_duint32 volume_space_size;
char pad2[32];
l9660_duint16 volume_set_size;
l9660_duint16 volume_seq_number;
l9660_duint16 logical_block_size;
l9660_duint32 path_table_size;
l9660_luint32 path_table_le;
l9660_luint32 path_table_opt_le;
l9660_buint32 path_table_be;
l9660_buint32 path_table_opt_be;
union {
l9660_dirent root_dir_ent;
char pad3[34];
};
char volume_set_id[128];
char data_preparer_id[128];
char app_id[128];
char copyright_file[38];
char abstract_file[36];
char bibliography_file[37];
l9660_desctime volume_created,
volume_modified,
volume_expires,
volume_effective;
uint8_t file_structure_version;
char pad4[1];
char app_reserved[512];
char reserved[653];
} l9660_vdesc_primary;
/* A generic volume descriptor (i.e. 2048 bytes) */
typedef union {
l9660_vdesc_header hdr;
char _bits[2048];
} l9660_vdesc;
/* File system structure.
* Stick this inside your own structure and cast/offset as appropriate to store
* private data
*/
typedef struct l9660_fs {
#ifdef L9660_SINGLEBUFFER
union {
l9660_dirent root_dir_ent;
char root_dir_pad[34];
};
#else
/* Sector buffer to hold the PVD */
l9660_vdesc pvd;
#endif
/* read_sector func */
bool (*read_sector)(struct l9660_fs *fs, void *buf, uint32_t sector);
} l9660_fs;
typedef struct {
#ifndef L9660_SINGLEBUFFER
/* single sector buffer */
char buf[2048];
#endif
l9660_fs *fs;
uint32_t first_sector;
uint32_t position;
uint32_t length;
} l9660_file;
typedef struct {
/* directories are mostly just files with special accessors, but we like type safetey */
l9660_file file;
} l9660_dir;
/* Open a file system, initialising *fs. */
l9660_status l9660_openfs(
l9660_fs *fs,
bool (*read_sector)(l9660_fs *fs, void *buf, uint32_t sector));
/*void l9660_closefs(l9660_fs *fs); (nop) */
/*! Open the root directory */
l9660_status l9660_fs_open_root(l9660_dir *dir, l9660_fs *fs);
/*! Open the subdirectory given by \p path */
l9660_status l9660_opendirat(l9660_dir *dir, l9660_dir *parent, const char *path);
/*! Returns the next directory entry. If end-of-directory is reached, *dirent is
* set to NULL. */
l9660_status l9660_readdir(l9660_dir *dir, l9660_dirent **dirent);
#define l9660_seekdir(dir, pos) (l9660_seek(&(dir)->file, L9660_SEEK_SET, (pos)))
#define l9660_telldir(dir) (l9660_tell(&(dir)->file))
/*! Open the file given by \p path in \p parent */
l9660_status l9660_openat(l9660_file *file, l9660_dir *parent, const char *path);
/*! Read \p size bytes into \p buf. The number of bytes read will be returned in
* \p *read. May be less than \p size (but only 0 on EOF)
*/
l9660_status l9660_read(l9660_file *file, void* buf, size_t size, size_t *read);
/*! Seek the file to \p offset from \p whence */
l9660_status l9660_seek(l9660_file *file, int whence, int32_t offset);
/*! Return the current position (suitable for passing to l9660_seek(file, SEEK_SET, ...)) */
uint32_t l9660_tell(l9660_file *file);
#endif
+89
View File
@@ -0,0 +1,89 @@
#ifndef _LIBALLOC_H
#define _LIBALLOC_H
// If we are told to not define our own size_t, then we
// skip the define.
#ifndef _ALLOC_SKIP_DEFINE
#ifndef _HAVE_SIZE_T
#define _HAVE_SIZE_T
typedef unsigned int size_t;
#endif
#ifndef NULL
#define NULL 0
#endif
#endif
/** This is a boundary tag which is prepended to the
* page or section of a page which we have allocated. It is
* used to identify valid memory blocks that the
* application is trying to free.
*/
struct boundary_tag
{
unsigned int magic; //< It's a kind of ...
unsigned int size; //< Requested size.
unsigned int real_size; //< Actual size.
int index; //< Location in the page table.
struct boundary_tag *split_left; //< Linked-list info for broken pages.
struct boundary_tag *split_right; //< The same.
struct boundary_tag *next; //< Linked list info.
struct boundary_tag *prev; //< Linked list info.
};
/** This function is supposed to lock the memory data structures. It
* could be as simple as disabling interrupts or acquiring a spinlock.
* It's up to you to decide.
*
* \return 0 if the lock was acquired successfully. Anything else is
* failure.
*/
extern int liballoc_lock();
/** This function unlocks what was previously locked by the liballoc_lock
* function. If it disabled interrupts, it enables interrupts. If it
* had acquiried a spinlock, it releases the spinlock. etc.
*
* \return 0 if the lock was successfully released.
*/
extern int liballoc_unlock();
/** This is the hook into the local system which allocates pages. It
* accepts an integer parameter which is the number of pages
* required. The page size was set up in the liballoc_init function.
*
* \return NULL if the pages were not allocated.
* \return A pointer to the allocated memory.
*/
extern void* liballoc_alloc(int);
/** This frees previously allocated memory. The void* parameter passed
* to the function is the exact same value returned from a previous
* liballoc_alloc call.
*
* The integer value is the number of pages to free.
*
* \return 0 if the memory was successfully freed.
*/
extern int liballoc_free(void*,int);
void *malloc(size_t); //< The standard function.
void *realloc(void *, size_t); //< The standard function.
void *calloc(size_t, size_t); //< The standard function.
void free(void *); //< The standard function.
#endif
+276
View File
@@ -0,0 +1,276 @@
/* multiboot.h - Multiboot header file. */
/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY
* DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef MULTIBOOT_HEADER
#define MULTIBOOT_HEADER 1
/* How many bytes from the start of the file we search for the header. */
#define MULTIBOOT_SEARCH 8192
#define MULTIBOOT_HEADER_ALIGN 4
/* The magic field should contain this. */
#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
/* This should be in %eax. */
#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
/* Alignment of multiboot modules. */
#define MULTIBOOT_MOD_ALIGN 0x00001000
/* Alignment of the multiboot info structure. */
#define MULTIBOOT_INFO_ALIGN 0x00000004
/* Flags set in the flags member of the multiboot header. */
/* Align all boot modules on i386 page (4KB) boundaries. */
#define MULTIBOOT_PAGE_ALIGN 0x00000001
/* Must pass memory information to OS. */
#define MULTIBOOT_MEMORY_INFO 0x00000002
/* Must pass video information to OS. */
#define MULTIBOOT_VIDEO_MODE 0x00000004
/* This flag indicates the use of the address fields in the header. */
#define MULTIBOOT_AOUT_KLUDGE 0x00010000
/* Flags to be set in the flags member of the multiboot info structure. */
/* is there basic lower/upper memory information? */
#define MULTIBOOT_INFO_MEMORY 0x00000001
/* is there a boot device set? */
#define MULTIBOOT_INFO_BOOTDEV 0x00000002
/* is the command-line defined? */
#define MULTIBOOT_INFO_CMDLINE 0x00000004
/* are there modules to do something with? */
#define MULTIBOOT_INFO_MODS 0x00000008
/* These next two are mutually exclusive */
/* is there a symbol table loaded? */
#define MULTIBOOT_INFO_AOUT_SYMS 0x00000010
/* is there an ELF section header table? */
#define MULTIBOOT_INFO_ELF_SHDR 0X00000020
/* is there a full memory map? */
#define MULTIBOOT_INFO_MEM_MAP 0x00000040
/* Is there drive info? */
#define MULTIBOOT_INFO_DRIVE_INFO 0x00000080
/* Is there a config table? */
#define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100
/* Is there a boot loader name? */
#define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200
/* Is there a APM table? */
#define MULTIBOOT_INFO_APM_TABLE 0x00000400
/* Is there video information? */
#define MULTIBOOT_INFO_VBE_INFO 0x00000800
#define MULTIBOOT_INFO_FRAMEBUFFER_INFO 0x00001000
#ifndef ASM_FILE
typedef unsigned char multiboot_uint8_t;
typedef unsigned short multiboot_uint16_t;
typedef unsigned int multiboot_uint32_t;
typedef unsigned long long multiboot_uint64_t;
struct multiboot_header
{
/* Must be MULTIBOOT_MAGIC - see above. */
multiboot_uint32_t magic;
/* Feature flags. */
multiboot_uint32_t flags;
/* The above fields plus this one must equal 0 mod 2^32. */
multiboot_uint32_t checksum;
/* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */
multiboot_uint32_t header_addr;
multiboot_uint32_t load_addr;
multiboot_uint32_t load_end_addr;
multiboot_uint32_t bss_end_addr;
multiboot_uint32_t entry_addr;
/* These are only valid if MULTIBOOT_VIDEO_MODE is set. */
multiboot_uint32_t mode_type;
multiboot_uint32_t width;
multiboot_uint32_t height;
multiboot_uint32_t depth;
};
/* The symbol table for a.out. */
struct multiboot_aout_symbol_table
{
multiboot_uint32_t tabsize;
multiboot_uint32_t strsize;
multiboot_uint32_t addr;
multiboot_uint32_t reserved;
};
typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t;
/* The section header table for ELF. */
struct multiboot_elf_section_header_table
{
multiboot_uint32_t num;
multiboot_uint32_t size;
multiboot_uint32_t addr;
multiboot_uint32_t shndx;
};
typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t;
struct multiboot_info
{
/* Multiboot info version number */
multiboot_uint32_t flags;
/* Available memory from BIOS */
multiboot_uint32_t mem_lower;
multiboot_uint32_t mem_upper;
/* "root" partition */
multiboot_uint32_t boot_device;
/* Kernel command line */
multiboot_uint32_t cmdline;
/* Boot-Module list */
multiboot_uint32_t mods_count;
multiboot_uint32_t mods_addr;
union
{
multiboot_aout_symbol_table_t aout_sym;
multiboot_elf_section_header_table_t elf_sec;
} u;
/* Memory Mapping buffer */
multiboot_uint32_t mmap_length;
multiboot_uint32_t mmap_addr;
/* Drive Info buffer */
multiboot_uint32_t drives_length;
multiboot_uint32_t drives_addr;
/* ROM configuration table */
multiboot_uint32_t config_table;
/* Boot Loader Name */
multiboot_uint32_t boot_loader_name;
/* APM table */
multiboot_uint32_t apm_table;
/* Video */
multiboot_uint32_t vbe_control_info;
multiboot_uint32_t vbe_mode_info;
multiboot_uint16_t vbe_mode;
multiboot_uint16_t vbe_interface_seg;
multiboot_uint16_t vbe_interface_off;
multiboot_uint16_t vbe_interface_len;
multiboot_uint64_t framebuffer_addr;
multiboot_uint32_t framebuffer_pitch;
multiboot_uint32_t framebuffer_width;
multiboot_uint32_t framebuffer_height;
multiboot_uint8_t framebuffer_bpp;
#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1
#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2
multiboot_uint8_t framebuffer_type;
union
{
struct
{
multiboot_uint32_t framebuffer_palette_addr;
multiboot_uint16_t framebuffer_palette_num_colors;
};
struct
{
multiboot_uint8_t framebuffer_red_field_position;
multiboot_uint8_t framebuffer_red_mask_size;
multiboot_uint8_t framebuffer_green_field_position;
multiboot_uint8_t framebuffer_green_mask_size;
multiboot_uint8_t framebuffer_blue_field_position;
multiboot_uint8_t framebuffer_blue_mask_size;
};
};
};
typedef struct multiboot_info multiboot_info_t;
struct multiboot_color
{
multiboot_uint8_t red;
multiboot_uint8_t green;
multiboot_uint8_t blue;
};
struct multiboot_mmap_entry
{
multiboot_uint32_t size;
multiboot_uint32_t addr_low;
multiboot_uint32_t addr_high;
multiboot_uint32_t len_low;
multiboot_uint32_t len_high;
#define MULTIBOOT_MEMORY_AVAILABLE 1
#define MULTIBOOT_MEMORY_RESERVED 2
#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3
#define MULTIBOOT_MEMORY_NVS 4
#define MULTIBOOT_MEMORY_BADRAM 5
multiboot_uint32_t type;
} __attribute__((packed));
typedef struct multiboot_mmap_entry multiboot_memory_map_t;
struct multiboot_mod_list
{
/* the memory used goes from bytes mod_start to mod_end-1 inclusive */
multiboot_uint32_t mod_start;
multiboot_uint32_t mod_end;
/* Module command line */
multiboot_uint32_t cmdline;
/* padding to take it to 16 bytes (must be zero) */
multiboot_uint32_t pad;
};
typedef struct multiboot_mod_list multiboot_module_t;
/* APM BIOS info. */
struct multiboot_apm_info
{
multiboot_uint16_t version;
multiboot_uint16_t cseg;
multiboot_uint32_t offset;
multiboot_uint16_t cseg_16;
multiboot_uint16_t dseg;
multiboot_uint16_t flags;
multiboot_uint16_t cseg_len;
multiboot_uint16_t cseg_16_len;
multiboot_uint16_t dseg_len;
};
#endif /* ! ASM_FILE */
#endif /* ! MULTIBOOT_HEADER */
+43 -14
View File
@@ -2,34 +2,63 @@
#define PAGING_H
#include "../include/stdio.h"
#include "../include/multiboot.h"
#include <stdint.h>
#define PAGE_OFFSET 0xC0000000
#define PAGE_SIZE 4096
#define PAGE_SHIFT 0x0C
extern uint32_t kernel_page_directory[1024] __attribute__((aligned(4096)));
extern uint32_t kernel_page_table[1024] __attribute__((aligned(4096)));
extern uint32_t user_page_table[1024] __attribute__((aligned(4096)));
#define PAGE_MASK ~(PAGE_SIZE - 1) /* 0xFFFFF000 */
#define PAGE_ALIGN(addr) (((addr) + (PAGE_SIZE - 1)) & PAGE_MASK)
#define PAGE_PRESENT 0x1
#define PAGE_RW 0x002 /* Read/Write */
#define PAGE_USER 0x004 /* User */
#define PAGE_NOALLOC 0x200 /* No Page Allocated (OS managed) */
#define GDT_BASE (0xFFFFFFFF - (PAGE_OFFSET - 1))
#define GET_PGDIR(address) ((uint32_t)((address) >> 22) & 0x3FF)
#define GET_PGTBL(address) ((uint32_t)((address) >> 12) & 0x3FF)
// Общий размер памяти
#define MEMORY_SIZE (0xFFFFFFFF-0xC0000000)
// Количество страниц
#define PAGE_COUNT (MEMORY_SIZE / PAGE_SIZE)
// Размер битмапа в байтах (округлено вверх)
#define BITMAP_SIZE 1024//(PAGE_COUNT / 8)
extern uint32_t *kpage_dir;
//paging.c
void enablePaging();
void loadPageDirectory(uint32_t* page_directory);
void paging_init();
void test_paging();
void grub_memory_map(unsigned int magic, struct multiboot_info* mbi);
uint32_t* get_page_dir();
void set_page_dir(uint32_t new_page_dir);
uint32_t phys_to_virt(uint32_t phys);
uint32_t* create_page_dir();
void destroy_page_dir(uint32_t* page_dir);
uint32_t* copy_page_dir(uint32_t* page_dir_virt);
static inline uint32_t virt_to_phys(void* virt) {
return (uint32_t)virt - 0xC0000000;
}
//page_alloc.c
int is_page_in_use(uint32_t page_index);
void set_bit(uint32_t page_index);
void clear_bit(uint32_t page_index);
void init_allocator();
void* alloc_page();
void free_page(void* physaddr);
//page_tables.c
void *get_physaddr(void *virtualaddr);
uint32_t get_pte(void *virtualaddr);
void map_page(void* physaddr, void* virtualaddr, unsigned int flags);
void map_kernel_page(void* virtualaddr, unsigned int flags);
void* setup_user_process(void* user_code_phys, uint32_t* user_stack_top);
//heap.c
void heap_init();
void* heap_alloc(uint32_t size);
void heap_free(void* ptr);
void unmap_page(void *virtualaddr);
int map_page_in_directory(uint32_t* pd_virt_addr, void* phys_addr, void* virt_addr, uint32_t flags);
#endif
+2
View File
@@ -4,6 +4,8 @@
#include "../include/utils.h"
void pic_remap(int offset1, int offset2);
void pic_disable(void);
void pic_end_int(uint8_t irq);
void pic_apply_masks();
#endif
+12
View File
@@ -0,0 +1,12 @@
#ifndef SB16_H
#define SB16_H
extern int sb16_irq;
bool sb16_is_full();
void sb16_ack();
size_t sb16_write(uint8_t* input_buffer, size_t size);
bool sb16_is_playing();
void sb16_init();
#endif
+2
View File
@@ -34,9 +34,11 @@ uint16_t vga_entry(unsigned char uc, uint8_t color);
size_t strlen(const char* str);
void terminal_initialize(void);
void terminal_setcolor(uint8_t color);
uint8_t terminal_getcolor();
void terminal_putentryat(char c, uint8_t color, size_t x, size_t y);
void terminal_putchar(char c);
void terminal_write(const char* data, size_t size);
void terminal_writestring(const char* data);
void update_cursor(int x, int y);
#endif
+16
View File
@@ -1,13 +1,29 @@
#ifndef STDIO_H
#define STDIO_H
#include <stddef.h>
#include <stdbool.h>
//TODO: these should be contained in newlib i guess
//but until i implement it let it be here yo
#define EOF (-1)
#define INT_MAX 2147483647
bool print(const char* data, size_t length);
int printf(const char* __restrict, ...);
int putchar(int);
int puts(const char*);
#define KATAU_DEBUG
#ifdef KATAU_DEBUG
#define debug_log printf
#else
static int debug_log(const char* restrict format, ...)
{
}
#endif
#endif
+5
View File
@@ -8,5 +8,10 @@ void* memcpy(void* __restrict, const void* __restrict, size_t);
void* memmove(void*, const void*, size_t);
void* memset(void*, int, size_t);
size_t strlen(const char*);
char *strcat(char *dest, const char *src);
char *strcpy(char *dest, const char *src);
char *strtok(char *str, const char *delim);
char *strrchr(const char *s, int c);
int strcmp(const char* s1, const char* s2);
#endif
+7
View File
@@ -0,0 +1,7 @@
#ifndef SYSCALLS_H
#define SYSCALLS_H
#include "../include/task.h"
void handle_syscall(TrapFrame *tf);
#endif
+67 -8
View File
@@ -2,6 +2,22 @@
#define TASK_H
#include <stdint.h>
#include "../include/lib9660.h"
// Сегменты для ядра и пользователя
#define SEG_KCODE 0x08 // Сегмент кода ядра
#define SEG_KDATA 0x10 // Сегмент данных ядра
#define SEG_UCODE 0x18 // Сегмент кода пользователя
#define SEG_UDATA 0x20 // Сегмент данных пользователя
#define DPL_KERNEL 0 // Уровень привилегий ring 0
#define DPL_USER 3 // Уровень привилегий ring 3
// Флаги процессора
#define FL_IF 0x202 // Разрешить прерывания
#define MAX_OPEN_FILES 32
#define KSTACKSIZE 4096
typedef enum TaskState
{
@@ -11,24 +27,67 @@ typedef enum TaskState
Terminated
} TaskState;
enum WaitingReason {
NONE,
TIMER,
STDIN,
};
typedef void (*EntryPoint)(void);
// Структура контекста для переключения между процессами
typedef struct __attribute__((packed)) Context {
uint32_t edi;
uint32_t esi;
uint32_t ebx;
uint32_t ebp;
uint32_t eip;
} Context;
// Структура trap frame для перехода в ring 3
typedef struct __attribute__((packed)) TrapFrame {
uint32_t gs,fs,es,ds;
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax;
uint32_t eip, cs, eflags, usermode_esp, usermode_ss;
} TrapFrame;
typedef struct Process
{
uint32_t pid; // Process ID
TaskState state; // Process state
uintptr_t programCounter; // Program Counter
uintptr_t* stackBase; // Top of the stack
uintptr_t* stackPointer; // Stack Pointer
uint32_t flags; // Status/Flags register
struct Process* next; // Pointer to the next task in the list
uint32_t* page_directory;
uint32_t kesp;
uint32_t kesp_bottom;
uint32_t *pagedir;
TaskState state; // Состояние процесса
char* kstack; // Стек ядра
Context* context; // Контекст для переключения
TrapFrame* tf; // Trap frame (только для ring 3)
uint32_t ring; // Уровень привилегий (0 или 3)
struct Process* next; // Следующий процесс
l9660_file* file_descriptors[MAX_OPEN_FILES];
l9660_dir* cwd;
void* brk;
uint32_t kstack_top;
size_t wake_up_time;//wake up time in ticks of the processor, gets set by nanosleep syscall
enum WaitingReason waiting_reason;
} Process;
Process* task_create(EntryPoint func, void** args, uint32_t arg_count);
extern Process* current;
extern uint32_t pid_counter;
extern Process* queue;
Process* task_create(uint32_t func, uint32_t user_esp, uint32_t ring, uint32_t* pagedir);
void task_kill(Process* proc);
void scheduler_init();
void schedule();
void scheduler_lock();
void scheduler_unlock();
#endif
-21
View File
@@ -1,21 +0,0 @@
#ifndef TYPES_H
#define TYPES_H
typedef signed char int8;
typedef unsigned char uint8;
typedef signed short int16;
typedef unsigned short uint16;
typedef signed int int32;
typedef unsigned int uint32;
typedef signed long long int64;
typedef unsigned long long uint64;
typedef char* string;
#define low_16(address) (uint16)((address) & 0xFFFF)
#define high_16(address) (uint16)(((address) >> 16) & 0xFFFF)
#endif
+8 -3
View File
@@ -1,16 +1,21 @@
#ifndef UTILS_H
#define UTILS_H
#include "../include/types.h"
#include "../include/stdio.h"
#include <stdint.h>
uint8 inportb(uint16 _port);
void outportb(uint16 _port, uint8 _data);
uint8_t inportb(uint16_t _port);
void outportb(uint16_t _port, uint8_t _data);
uint8_t get_rtc(uint8_t reg);
void get_fancy_datetime();
void get_datetime(uint16_t *year, uint8_t *month, uint8_t *day, uint8_t *hour, uint8_t *minute, uint8_t *second);
uint32_t fat32_datetime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second);
//got these from osdev.org
void cpuid(int code, uint32_t *a, uint32_t *d);
bool cpu_has_msr();
void cpu_get_msr(uint32_t msr, uint32_t *lo, uint32_t *hi);
void cpu_set_msr(uint32_t msr, uint32_t lo, uint32_t hi);
#define inb inportb
#define outb outportb
+28
View File
@@ -0,0 +1,28 @@
#ifndef VFS_H
#define VFS_H
#define ISO_9660_BUFFER_LENGTH 2048
#include <stdbool.h>
#include "../include/atapi.h"
#include "../include/lib9660.h"
extern l9660_fs* global_fs;
extern l9660_dir* root_dir;
bool read_sector_callback(l9660_fs *fs, void *buf, uint32_t sector);
void mount_fs();
void list_files(l9660_dir *dir);
size_t vfs_read_file(l9660_file *file, uint8_t* buffer);
size_t vfs_read_file_length(l9660_file *file, uint8_t* buffer, size_t length);
void test_iso9660();
int vfs_read_file_by_path(const char* path, uint8_t** buffer);
int follow_path(const char* path, l9660_file* file, l9660_dir* dir);
l9660_status find_name_for_sector(char* name_buf, int buf_len, l9660_dir* parent_dir, uint32_t child_sector);
bool is_root_dir(l9660_dir* dir);
#endif
+39 -10
View File
@@ -1,17 +1,46 @@
OUTPUT_FORMAT(elf32-i386)
ENTRY(start)
OUTPUT_FORMAT("elf32-i386")
OUTPUT_ARCH("i386")
ENTRY(_start)
vaddr = 0xC0000000; /* virtual start address */
paddr = 0x100000; /* physical address at 1MB */
SECTIONS
{
. = 0x100000;
.text BLOCK(4K) : ALIGN(4K) {
*(.multiboot)
.setup ALIGN(4096) :
{
*(.setup)
}
. += vaddr;
.text : AT(ADDR(.text)-vaddr) {
*(.text)
}
.rodata BLOCK(4K) : ALIGN(4K) { *(.rodata) }
.data BLOCK(4K) : ALIGN(4K) { *(.data) }
.bss BLOCK(4K) : ALIGN(4K) {
*(.COMMON)
*(.bss)
_etext = .;
.data ALIGN(4096) : AT(ADDR(.data) - vaddr)
{
*(.data)
*(.rodata*)
}
kernel_end = .;
_edata = .;
/* uninitialized data */
.bss ALIGN(4096) : AT(ADDR(.bss) - vaddr)
{
*(COMMON*)
*(.bss*)
}
_end = .;
/DISCARD/ :
{
*(.comment)
*(.eh_frame)
*(.note*)
}
}
+103 -80
View File
@@ -1,96 +1,119 @@
bits 32
section .multiboot
%define MULTIBOOT_PAGE_ALIGN 0x00000001
%define MULTIBOOT_MEMORY_INFO 0x00000002
%define MULTIBOOT_HEADER_MAGIC 0x1BADB002
%define MULTIBOOT_HEADER_FLAGS (MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO)
%define CR0_MP 0x00000002 /* bit 01 -> enable monitor coprocessor */
%define CR0_NE 0x00000020 /* bit 05 -> enable native x87 FPU mode */
%define CR0_WP 0x00010000 /* bit 16 -> enable write protect (for CoW) */
%define CR0_AM 0x00040000 /* bit 18 -> enable alignment checking */
%define CR0_PG 0x80000000 /* bit 31 -> enable paging */
%define PAGE_OFFSET 0xC0000000
%define GDT_BASE (0xFFFFFFFF - (PAGE_OFFSET - 1))
%define KERNEL_CS 0x8
%define KERNEL_DS 0x10
section .setup
align 4
dd 0x1BADB002
dd 0x00
dd - (0x1BADB002+0x00)
tmp_gdtr:
dw ((3 * 8) - 1)
tmp_gdta:
dd tmp_gdt
section .data
align 4
multiboot_info:
dd 0
dd 0
dd 0
dd 0
dd 0
dd 0
dd 0
tmp_gdt:
; NULL DESCRIPTOR
dw 0x0000
dw 0x0000
dw 0x0000
dw 0x0000
; KERNEL CODE
dw 0xFFFF ; segment limit 15-00
dw 0x0000 ; base address 15-00
db 0x00 ; base address 23-16
db 0x9A ; P=1 DPL=00 S=1 TYPE=1010 (exec/read)
db 0xCF ; G=1 DB=1 0=0 AVL=0 SEGLIM=1111
db (GDT_BASE >> 24) ; base address 31-24 (0x40)
; KERNEL DATA
dw 0xFFFF ; segment limit 15-00
dw 0x0000 ; base address 15-00
db 0x00 ; base address 23-16
db 0x92 ; P=1 DPL=00 S=1 TYPE=0010 (read/write)
db 0xCF ; G=1 DB=1 0=0 AVL=0 SEGLIM=1111
db (GDT_BASE >> 24) ; base address 31-24 (0x40)
global tss
global tss_end
align 4
tss:
dd 0 ; 0-3
dd stack_top ; 4-7
dd DATA_SEG ; 8-11
dd 0 ; 12-15
dd 0 ; 16-19
dd 0 ; 20-23
dd 0 ; 24-27
dd 0 ; 28-31
dd 0 ; 32-35
dd 0 ; 36-39
dd 0 ; 40-43
dd 0 ; 44-47
dd 0 ; 48-51
dd 0 ; 52-55
dd 0 ; 56-59
dd 0 ; 60-63
dd 0 ; 64-67
dd 0 ; 68-71
dd DATA_SEG ; 72-75
dd CODE_SEG ; 76-79
dd DATA_SEG ; 80-83
dd DATA_SEG ; 84-87
dd DATA_SEG ; 88-91
dd DATA_SEG ; 92-95
dd 0 ; 96-99
dw 0 ; 100-101
dw 104 ; 102-103
tss_end:
section .bss
stack_bottom:
resb 16384
stack_top:
section .gdt
%include "src/gdt.asm"
multiboot_header:
dd MULTIBOOT_HEADER_MAGIC
dd MULTIBOOT_HEADER_FLAGS
dd -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
dd 0 ; header_addr
dd 0 ; load_addr
dd 0 ; load_end_addr
dd 0 ; bss_end_addr
dd 0 ; entry_addr
dd 0 ; mode_type
dd 0 ; width
dd 0 ; height
dd 0 ; depth
section .text
global start:function (start.end - start)
extern kmain ; this function is gonna be located in our c code(kernel.c)
global _start
start:
mov esp, stack_top
extern setup_tmp_pgdir
extern bss_init
extern gdt_init
extern get_last_boot_addr
extern kmain
_start:
cli
push ebx ; Сохраняем оригинальный ebx (указатель Multiboot)
lgdt [tmp_gdtr] ; load GDTR with the temporary GDT
mov cx, KERNEL_DS
mov ds, cx
mov es, cx
mov fs, cx
mov gs, cx
mov ss, cx
jmp KERNEL_CS:setup_kernel
lgdt [gdt]
align 4
global setup_kernel
setup_kernel:
mov esp, PAGE_OFFSET + 0x10000 ; default stack address (0xC0000000 + 0x10000)
push 0 ; reset EFLAGS
popf
; Заполняем адрес TSS в дескрипторе GDT
mov eax, tss ; Получаем 32-битный адрес tss
mov ebx, gdt_tss ; Адрес дескриптора TSS в GDT
mov [ebx + 2], ax ; Нижние 16 бит адреса TSS
shr eax, 16 ; Сдвигаем для доступа к старшим битам
mov [ebx + 4], al ; Средние 8 бит адреса TSS
mov [ebx + 7], ah ; Верхние 8 бит адреса TSS
push ebx ; save Multiboot info structure
push eax ; save Multiboot magic value
call setup_tmp_pgdir
mov cr3, eax
mov ax, DATA_SEG
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp CODE_SEG:.huita
mov eax, cr0
and eax, 0x00000011 ; disable all, preserve ET & PE (GRUB)
or eax, 0x80000000 ; CR0_PG ; enable PG
or eax, 0x40000 ; CR0_AM ; enable AM
or eax, 0x10000 ; CR0_WP ; enable WP
or eax, 0x20 ; CR0_NE ; enable NE
or eax, 0x02 ; CR0_MP ; enable MP
mov cr0, eax
.huita:
mov ax, TSS_SEG
ltr ax
pop ebx ; Восстанавливаем оригинальный ebx
push ebx ; Передаем его в kmain
call bss_init ; initialize BSS segment
call gdt_init ; setup and load the definitive GDT
call get_last_boot_addr
pop ecx ; restore Multiboot magic value
pop ebx ; restore Multiboot info structure
push eax ; save the last boot address
push ebx ; save Multiboot info structure
push ecx ; save Multiboot magic value
call kmain
hlt
.end:
jmp $
+94
View File
@@ -0,0 +1,94 @@
#include "../include/atapi.h"
#include "../include/utils.h"
// Handy register number defines
#define DATA 0
#define ERROR_R 1
#define SECTOR_COUNT 2
#define LBA_LOW 3
#define LBA_MID 4
#define LBA_HIGH 5
#define DRIVE_SELECT 6
#define COMMAND_REGISTER 7
// Control register defines
#define CONTROL 0x206
#define ALTERNATE_STATUS 0
static __inline void insw(uint16_t __port, void *__buf, unsigned long __n)
{
__asm__ __volatile__("cld; rep; insw"
: "+D"(__buf), "+c"(__n)
: "d"(__port));
}
static __inline__ void outsw(uint16_t __port, const void *__buf, unsigned long __n)
{
__asm__ __volatile__("cld; rep; outsw"
: "+S"(__buf), "+c"(__n)
: "d"(__port));
}
// This code is to wait 400 ns
static void ata_io_wait(const uint8_t p)
{
inportb(p + CONTROL + ALTERNATE_STATUS);
inportb(p + CONTROL + ALTERNATE_STATUS);
inportb(p + CONTROL + ALTERNATE_STATUS);
inportb(p + CONTROL + ALTERNATE_STATUS);
}
// Reads sectors starting from lba to buffer
int read_cdrom(uint16_t port, bool slave, uint32_t lba, uint32_t sectors, uint16_t *buffer)
{
// The command
volatile uint8_t read_cmd[12] = {0xA8, 0,
(lba >> 0x18) & 0xFF, (lba >> 0x10) & 0xFF, (lba >> 0x08) & 0xFF,
(lba >> 0x00) & 0xFF,
(sectors >> 0x18) & 0xFF, (sectors >> 0x10) & 0xFF, (sectors >> 0x08) & 0xFF,
(sectors >> 0x00) & 0xFF,
0, 0};
outportb(port + DRIVE_SELECT, 0xA0 & (slave << 4)); // Drive select
ata_io_wait(port);
outportb(port + ERROR_R, 0x00);
outportb(port + LBA_MID, 2048 & 0xFF);
outportb(port + LBA_HIGH, 2048 >> 8);
outportb(port + COMMAND_REGISTER, 0xA0); // Packet command
ata_io_wait(port); // I think we might need this delay, not sure, so keep this
// Wait for status
while (1)
{
uint8_t status = inportb(port + COMMAND_REGISTER);
if ((status & 0x01) == 1)
return 1;
if (!(status & 0x80) && (status & 0x08))
break;
ata_io_wait(port);
}
// Send command
outsw(port + DATA, (uint16_t *)read_cmd, 6);
// Read words
for (uint32_t i = 0; i < sectors; i++)
{
// Wait until ready
while (1)
{
uint8_t status = inportb(port + COMMAND_REGISTER);
if (status & 0x01)
return 1;
if (!(status & 0x80) && (status & 0x08))
break;
}
int size = inportb(port + LBA_HIGH) << 8 | inportb(port + LBA_MID); // Get the size of transfer
insw(port + DATA, (uint16_t *)((uint8_t *)buffer + i * 0x800), size / 2); // Read it
}
return 0;
}
+51 -24
View File
@@ -1,5 +1,11 @@
#include "../include/keyboard.h"
#include <stdbool.h>
#include "../include/task.h"
#include "../include/string.h"
char stdin_buffer[STDIN_BUFFER_SIZE];
int stdin_pos = 0;
bool stdin_has_line = false;
unsigned char kbdus[128] =
{
@@ -87,39 +93,60 @@ bool caps_pressed;
void keyboard_wait();
void handle_keyboard()
{//3a
void handle_keyboard() {
uint8_t scancode = inb(0x60);
if(scancode & 0x80)//key released
{
scancode = scancode-0x80;
if(scancode == 0x2a || scancode == 0x36)
shift_pressed = false;
//printf("(%X)%c released ", scancode, kbdus[scancode-0x80]);
}
else//key pressed
{
if(scancode == 0x2a || scancode == 0x36)
{
if (scancode & 0x80) { // Released
scancode -= 0x80;
if (scancode == 0x2A || scancode == 0x36) shift_pressed = false;
} else { // Pressed
if (scancode == 0x2A || scancode == 0x36) {
shift_pressed = true;
return;
}
if(scancode == 0x3a)
{
caps_pressed = !caps_pressed;
outb(0x60, 0xed);//set LED command
keyboard_wait();
outb(0x60, caps_pressed << 2);//0 is scroll lock, 1 is numlock, 2 is caps lock
if (scancode == 0x3A) { // Caps
return;
}
if(shift_pressed || caps_pressed)
printf("%c", kbdus2[scancode]);
else
printf("%c", kbdus[scancode]); //printf("(0x%X)%c", scancode, kbdus[scancode]);
char c;
if (shift_pressed || caps_pressed) c = kbdus2[scancode];
else c = kbdus[scancode];
if (c == '\b') { //Backspace
if (stdin_pos > 0) {
stdin_pos--;
printf("\b \b");
}
} else if (c == '\n') { // Enter
if (stdin_pos < STDIN_BUFFER_SIZE - 1) {
stdin_buffer[stdin_pos++] = '\n';
printf("\n");
}
stdin_has_line = true;
// Wake-up: wake up all Waiting tasks on STDIN
scheduler_lock();
Process *p = queue;
while (p) {
if (p->state == Waiting && p->waiting_reason == STDIN) {
p->state = Ready;
p->waiting_reason = NONE;
}
p = p->next;
}
scheduler_unlock();
} else if (c != 0 && stdin_pos < STDIN_BUFFER_SIZE - 1) {//if printable
stdin_buffer[stdin_pos++] = c;
printf("%c", c);//echo
}
}
}
void init_keyboard()
{
memset(stdin_buffer, 0, STDIN_BUFFER_SIZE);
stdin_pos = 0;
stdin_has_line = false;
}
void keyboard_wait()
+242
View File
@@ -0,0 +1,242 @@
#include "../include/utils.h"
#include "../include/paging.h"
#include "../include/liballoc.h"
#include "../include/string.h"
#include "../include/sb16.h"
#include "../include/apic.h"
#include "../include/kheap.h"
#include "../include/task.h"
#define DSP_RESET 0x226
#define DSP_READ 0x22A
#define DSP_WRITE 0x22C
#define MIXER 0x224
#define MIXER_DATA 0x225
extern bool lapic_enabled;
int sb16_irq = 0;
void* buffer_phys;
void* buffer_virt;
#define BUFFER_PAGE_COUNT 16
const size_t buffer_size = BUFFER_PAGE_COUNT*4096;//64 KB
static uint8_t current_slot;
static bool slot_has_anything[2];
static bool is_playing = false;
static size_t slot_sizes[2];
static bool stereo = true;
#define min(a, b) ((a) < (b) ? (a) : (b))
void sb16_enable_irq() {
if (!lapic_enabled) {
uint8_t mask = inb(0x21);
mask &= ~(1 << sb16_irq);
outb(0x21, mask);
} else {
ioapic_redirect(sb16_irq, 0x20 + sb16_irq);
}
}
int sb16_dsp_reset()
{
outb(DSP_RESET, 1);
//dirty hack to wait 3 microseconds
for(int i = 0; i < 3*100; i++)
{
inb(0x1FC);
}
outb(DSP_RESET, 0);
return inb(DSP_READ);
}
int sb16_get_irq()
{
outb(MIXER, 0x80);
int irq_code = inb(MIXER_DATA);
int irq = 0;
switch(irq_code)
{
case 0x01:
irq = 2;
break;
case 0x02:
irq = 5;
break;
case 0x04:
irq = 7;
break;
case 0x08:
irq = 10;
break;
}
return irq;
}
void sb16_allocate_buf()
{
buffer_virt = kvalloc(BUFFER_PAGE_COUNT);
buffer_phys = get_physaddr(buffer_virt);
memset(buffer_virt, 0x80, buffer_size);//fill the buffer with silence
}
void sb16_get_version(int* major, int* minor)
{
outb(DSP_WRITE, 0xE1);//0xE1 is get version
*major = inb(DSP_READ);
*minor = inb(DSP_READ);
}
void sb16_program_dma(uint32_t buf_size)
{
const int transfer_mode = 0x48;
const int channel = 1;
int buffer_pos = (uint32_t)buffer_phys + (current_slot << 15);
int count = buf_size;
outb(0x0A, 0x4 + channel);//0x4 + channel number (1 in this case)
outb(0x0C, 1);//flip flop
outb(0x0B, transfer_mode + channel);
outb(0x83, ((uint32_t)buffer_pos >> 16) & 0xFF);
//set the position
outb(0x02, ((uint32_t)buffer_pos) & 0xFF);
outb(0x02, ((uint32_t)buffer_pos >> 8) & 0xFF);
//set the count
outb(0x03, (count - 1) & 0xFF);
outb(0x03, ((count - 1) >> 8) & 0xFF);
outb(0x0A, 1);
}
void sb16_program(uint32_t buf_size)
{
const int samples_count = stereo ? buf_size / 2 : buf_size;
outb(DSP_WRITE, 0x41);//sample rate
const int sample_rate = 44100;
outb(DSP_WRITE, (sample_rate >> 8) & 0xff);
outb(DSP_WRITE, (sample_rate) & 0xff);
uint8_t mode = 0x0;
if(stereo)
{
mode |= (1 << 5);//set the 5th bit to 1 if stereo
}
outb(DSP_WRITE, 0xC0);//8-bit sound
outb(DSP_WRITE, mode);
outb(DSP_WRITE, (samples_count - 1) & 0xFF);
outb(DSP_WRITE, ((samples_count - 1) >> 8) & 0xFF);
}
void sb16_stop()
{
outb(DSP_WRITE, 0xD0);
}
void sb16_play()
{
outb(DSP_WRITE, 0xD4);
}
bool sb16_is_playing()
{
return is_playing;
}
bool sb16_is_full()
{
return slot_has_anything[0] && slot_has_anything[1];
}
void sb16_ack()
{
inb(0x22E);
//debug_log("sb16: IRQ ACK, slot: 0x%X\n", current_slot);
slot_has_anything[current_slot] = false;
current_slot = !current_slot;
if(slot_has_anything[current_slot])
{
sb16_program_dma(slot_sizes[current_slot]);
sb16_program(slot_sizes[current_slot]);
}
else
{
debug_log("sb16: next slot contains nothing, stopping...\n");
sb16_stop();
is_playing = false;
}
}
size_t sb16_write(uint8_t* input_buffer, size_t size)
{
const size_t out_size = min(size, 32768);//32KB max
const uint8_t next_slot = !current_slot;
uint8_t *dst_buffer = buffer_virt + (next_slot << 15);
memcpy(dst_buffer, input_buffer, out_size);
if(out_size < 32768)
{
memset(dst_buffer + out_size, 0x80, 32768 - out_size);
}
scheduler_lock();
slot_sizes[next_slot] = out_size;
slot_has_anything[next_slot] = true;
if(!is_playing){
current_slot = next_slot;
sb16_program_dma(slot_sizes[current_slot]);
sb16_program(slot_sizes[current_slot]);
is_playing = true;
}
scheduler_unlock();
return out_size;
}
void sb16_init()
{
int status = sb16_dsp_reset();
printf("sb16 status: 0x%X\n", status);
sb16_irq = sb16_get_irq();
printf("sb16 irq: 0x%X\n", sb16_irq);
sb16_allocate_buf();
printf("sb16 buffer: phys: 0x%X virt: 0x%X\n", buffer_phys, buffer_virt);
int major, minor = 0;
sb16_get_version(&major, &minor);
printf("sb16 version: %X.%X\n", major, minor);
outb(DSP_WRITE, 0xD1);//enable speaker
printf("PIC mask before enable: 0x%X\n", inb(0x21));
sb16_enable_irq();
printf("PIC mask after enable: 0x%X\n", inb(0x21));
current_slot = 0;
slot_has_anything[0] = false;
slot_has_anything[1] = false;
outb(MIXER, 0x80);
printf("SB16 raw irq_code: 0x%X\n", inb(MIXER_DATA));
}
+61 -10
View File
@@ -1,12 +1,19 @@
// screen.c
#include "../include/screen.h"
#include "../include/string.h"
#include "../include/utils.h"
static size_t terminal_row;
static size_t terminal_column;
static uint8_t terminal_color;
static uint16_t* terminal_buffer;
static enum {
STATE_NORMAL,
STATE_ESCAPE,
STATE_BRACKET,
} terminal_state = STATE_NORMAL;
inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg)
{
return fg | bg << 4;
@@ -36,6 +43,11 @@ void terminal_setcolor(uint8_t color)
terminal_color = color;
}
uint8_t terminal_getcolor()
{
return terminal_color;
}
void terminal_putentryat(char c, uint8_t color, size_t x, size_t y)
{
const size_t index = y * VGA_WIDTH + x;
@@ -61,24 +73,53 @@ void terminal_scroll(void)
void terminal_putchar(char c)
{
if(c != '\n')
terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
if (++terminal_column >= VGA_WIDTH){
if (terminal_state == STATE_ESCAPE) {
if (c == '[') {
terminal_state = STATE_BRACKET;
} else {
terminal_state = STATE_NORMAL;
}
return;
} else if (terminal_state == STATE_BRACKET) {
if (c == 'H') {
terminal_row = 0;
terminal_column = 0;
if (++terminal_row >= VGA_HEIGHT)
terminal_scroll();
update_cursor(0, 0);
}
if(terminal_row >= VGA_HEIGHT){
terminal_scroll();
terminal_state = STATE_NORMAL;
return;
}
if(c == '\n')
{
if (c == '\033') {//ESC
terminal_state = STATE_ESCAPE;
return;
}
if (c == '\b') {
if (terminal_column > 0) {
terminal_column--;
} else if (terminal_row > 0) {
terminal_row--;
terminal_column = VGA_WIDTH - 1;
}
}
else if (c == '\n') {
terminal_column = 0;
terminal_row++;
} else {
terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
terminal_column++;
}
if (terminal_column > VGA_WIDTH) {
terminal_column = 0;
terminal_row++;
}
if (terminal_row >= VGA_HEIGHT) {
terminal_scroll();
}
update_cursor(terminal_column, terminal_row);
}
void terminal_write(const char* data, size_t size)
@@ -91,3 +132,13 @@ void terminal_writestring(const char* data)
{
terminal_write(data, strlen(data));
}
void update_cursor(int x, int y)
{
uint16_t pos = y * VGA_WIDTH + x;
outb(0x3D4, 0x0F);
outb(0x3D5, (uint8_t) (pos & 0xFF));
outb(0x3D4, 0x0E);
outb(0x3D5, (uint8_t) ((pos >> 8) & 0xFF));
}
+3 -3
View File
@@ -149,9 +149,9 @@ static void fmt_put(char** buf, char* end, char c)
}
//------------------------------------------------------------------------------
static void fmt_put_num(long long val, int flags, int width, char** buf, char* end)
static void fmt_put_num(long val, int flags, int width, char** buf, char* end)
{
unsigned long long uval = (unsigned long long)val;
unsigned long uval = (unsigned long)val;
int size = 0;
char tmp[65]; // Binary digits in uint64_t plus sign
@@ -162,7 +162,7 @@ static void fmt_put_num(long long val, int flags, int width, char** buf, char* e
if (!(flags & FMT_UNSIGNED) && val < 0)
{
uval = (unsigned long long)-val;
uval = (unsigned long)-val;
if (!(flags & FMT_NO_SIGN))
sign = '-';
}
+337
View File
@@ -0,0 +1,337 @@
/* lib9660: a simple ISO9660 reader library especially suited to embedded
* systems
*
* SPDX-License-Identifier: LicenseRef-ISC1
* SPDX-FileCopyrightText: © 2014 Erin Shepherd
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice appears in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "lib9660.h"
#include <string.h>
#ifdef DEBUG
#include <stdlib.h>
#endif
#ifdef L9660_HAVE_STDIO
#include <stdio.h>
#else
#define SEEK_END L9660_SEEK_END
#define SEEK_SET L9660_SEEK_SET
#define SEEK_CUR L9660_SEEK_CUR
#endif
#define DENT_EXISTS (1 << 0)
#define DENT_ISDIR (1 << 1)
#define DENT_ASSOCIATED (1 << 2)
#define DENT_RECORD (1 << 3)
#define DENT_PROTECTION (1 << 4)
#define DENT_MULTIEXTENT (1 << 5)
#define PVD(vdesc) ((l9660_vdesc_primary*)(vdesc))
#ifdef L9660_BIG_ENDIAN
#define READ16(v) (((v).be[1]) | ((v).be[0] << 8))
#define READ32(v) (((v).be[3]) | ((v).be[2] << 8) | ((v).be[1]) << 16 | ((v).be[0] << 24))
#else
#define READ16(v) (((v).le[0]) | ((v).le[1] << 8))
#define READ32(v) (((v).le[0]) | ((v).le[1] << 8) | ((v).le[2]) << 16 | ((v).le[3] << 24))
#endif
#ifndef L9660_SINGLEBUFFER
#define HAVEBUFFER(f) (true)
#define BUF(f) ((f)->buf)
#else
#define HAVEBUFFER(f) ((f) == last_file)
#define BUF(f) (gbuf)
static l9660_file *last_file;
static char gbuf[2048];
#endif
static char *strchrnul(const char *s, int c)
{
while (*s) {
if((*s++) == c)
break;
}
return (char *) s;
}
static inline uint16_t fsectoff(l9660_file *f)
{
return f->position % 2048;
}
static inline uint32_t fsector(l9660_file *f)
{
return f->position / 2048;
}
static inline uint32_t fnextsectpos(l9660_file *f)
{
return (f->position + 2047) & ~2047;
}
l9660_status l9660_openfs(
l9660_fs *fs,
bool (*read_sector)(l9660_fs *fs, void *buf, uint32_t sector))
{
fs->read_sector = read_sector;
#ifndef L9660_SINGLEBUFFER
l9660_vdesc_primary *pvd = PVD(&fs->pvd);
#else
last_file = NULL;
l9660_vdesc_primary *pvd = PVD(gbuf);
#endif
uint32_t idx = 0x10;
for (;;) {
// Read next sector
if (!read_sector(fs, pvd, idx))
return L9660_EIO;
// Validate magic
if (memcmp(pvd->hdr.magic, "CD001", 5) != 0)
return L9660_EBADFS;
if (pvd->hdr.type == 1)
break; // Found PVD
else if(pvd->hdr.type == 255)
return L9660_EBADFS;
}
#ifdef L9660_SINGLEBUFFER
memcpy(&fs->root_dir_ent, &pvd->root_dir_ent, pvd->root_dir_ent.length);
#endif
return L9660_OK;
}
l9660_status l9660_fs_open_root(l9660_dir *dir, l9660_fs *fs)
{
l9660_file *f = &dir->file;
#ifndef L9660_SINGLEBUFFER
l9660_dirent *dirent = &PVD(&fs->pvd)->root_dir_ent;
#else
l9660_dirent *dirent = &fs->root_dir_ent;
#endif
f->fs = fs;
f->first_sector = READ32(dirent->sector);
f->length = READ32(dirent->size);
f->position = 0;
return L9660_OK;
}
static l9660_status buffer(l9660_file *f)
{
#ifdef L9660_SINGLEBUFFER
last_file = f;
#endif
if (!f->fs->read_sector(f->fs, BUF(f), f->first_sector + f->position / 2048))
return L9660_EIO;
else
return L9660_OK;
}
static l9660_status prebuffer(l9660_file *f)
{
if (!HAVEBUFFER(f) || (f->position % 2048) == 0)
return buffer(f);
else return L9660_OK;
}
#if defined(DEBUG)
static void print_dirent(l9660_dirent *dent)
{
if (!getenv("L9660_DEBUG"))
return;
printf("| ---- dirent\n");
printf("| length %d\n", dent->length);
printf("| xattr_length %d\n", dent->xattr_length);
printf("| sector %u\n", READ32(dent->sector));
printf("| size %u\n", READ32(dent->size));
printf("| name \"%.*s\"\n", dent->name_len, dent->name);
printf("| ---- end dirent\n");
}
#endif
static l9660_status openat_raw(l9660_file *child, l9660_dir *parent, const char *name, bool isdir)
{
l9660_status rv;
l9660_dirent *dent = NULL;
if ((rv = l9660_seekdir(parent, 0))) return rv;
do {
const char *seg = name;
name = strchrnul(name, '/');
size_t seglen = name - seg;
/* ISO9660 stores '.' as '\0' */
if (seglen == 1 && *seg == '.')
seg = "\0";
/* ISO9660 stores ".." as '\1' */
if (seglen == 2 && seg[0] == '.' && seg[1] == '.') {
seg = "\1";
seglen = 1;
}
for(;;) {
if ((rv = l9660_readdir(parent, &dent)))
return rv;
/* EOD */
if (!dent)
return L9660_ENOENT;
#ifdef DEBUG
print_dirent(dent);
#endif
/* wrong length */
if (seglen > dent->name_len)
continue;
/* check name */
if (memcmp(seg, dent->name, seglen) != 0)
continue;
/* check for a revision tag */
if (dent->name_len > seglen && dent->name[seglen] != ';')
continue;
/* all tests pass */
break;
}
child->fs = parent->file.fs;
child->first_sector = READ32(dent->sector) + dent->xattr_length;
child->length = READ32(dent->size);
child->position = 0;
if (*name && (dent->flags & DENT_ISDIR) != 0)
return L9660_ENOTDIR;
parent = (l9660_dir*) child;
} while(*name);
if (isdir) {
if ((dent->flags & DENT_ISDIR) == 0)
return L9660_ENOTDIR;
} else {
if ((dent->flags & DENT_ISDIR) != 0)
return L9660_ENOTFILE;
}
return L9660_OK;
}
l9660_status l9660_opendirat(l9660_dir *dir, l9660_dir *parent, const char *path)
{
return openat_raw(&dir->file, parent, path, true);
}
static inline unsigned aligneven(unsigned v) {
return v + (v & 1);
}
l9660_status l9660_readdir(l9660_dir *dir, l9660_dirent **pdirent)
{
l9660_status rv;
l9660_file *f = &dir->file;
rebuffer:
if(f->position >= f->length) {
*pdirent = NULL;
return L9660_OK;
}
if ((rv = prebuffer(f)))
return rv;
char *off = BUF(f) + fsectoff(f);
if (*off == 0) {
// Padded end of sector
f->position = fnextsectpos(f);
goto rebuffer;
}
l9660_dirent *dirent = (l9660_dirent*) off;
f->position += aligneven(dirent->length);
*pdirent = dirent;
return L9660_OK;
}
l9660_status l9660_openat(l9660_file *child, l9660_dir *parent, const char * name)
{
return openat_raw(child, parent, name, false);
}
/*! Seek the file to \p offset from \p whence */
l9660_status l9660_seek(l9660_file *f, int whence, int32_t offset)
{
l9660_status rv;
uint32_t cursect = fsector(f);
switch (whence) {
case SEEK_SET:
f->position = offset;
break;
case SEEK_CUR:
f->position = f->position + offset;
break;
case SEEK_END:
f->position = f->length - offset;
break;
}
if (fsector(f) != cursect && fsectoff(f) != 0) {
if ((rv = buffer(f)))
return rv;
}
return L9660_OK;
}
uint32_t l9660_tell(l9660_file *f)
{
return f->position;
}
l9660_status l9660_read(l9660_file *f, void* buf, size_t size, size_t *read)
{
l9660_status rv;
if ((rv = prebuffer(f)))
return rv;
uint16_t rem = 2048 - fsectoff(f);
if (rem > f->length - f->position)
rem = f->length - f->position;
if (rem < size)
size = rem;
memcpy(buf, BUF(f) + fsectoff(f), size);
*read = size;
f->position += size;
return L9660_OK;
}
+342
View File
@@ -0,0 +1,342 @@
#include "../include/vfs.h"
#include "../include/stdio.h"
#include "../include/string.h"
#include "../include/paging.h"
#include "../include/liballoc.h"
l9660_fs* global_fs;
l9660_dir* root_dir;
bool read_sector_callback(l9660_fs *fs, void *buf, uint32_t sector) {
// The 'fs' parameter is not needed for our simple case, so we can ignore it.
(void)fs;
// Call your existing CD-ROM read function to read 1 sector.
// We assume the CD-ROM is the secondary master (0x170).
int result = read_cdrom(0x170, false, sector, 1, (uint16_t*)buf);
// lib9660 expects 'true' for success and 'false' for failure.
// Your read_cdrom returns 0 for success.
return (result == 0);
}
void mount_fs()
{
global_fs = malloc(sizeof(l9660_fs));
l9660_status status = l9660_openfs(global_fs, read_sector_callback);
if (status != L9660_OK) {
printf("Error opening ISO9660 filesystem!\n");
return;
}
printf("FS mounted\n");
root_dir = malloc(sizeof(l9660_dir));
status = l9660_fs_open_root(root_dir, global_fs);
if(status != L9660_OK)
{
printf("Error opening root dir\n");
return;
}
printf("root dir opened\n");
}
void list_files(l9660_dir *dir)
{
debug_log("----------CONTENTS----------");
l9660_status status;
for (;;) {
l9660_dirent *dent;
status = l9660_readdir(dir, &dent);
if (dent == NULL || status != L9660_OK) {
break; // End of directory or error
}
// Print the filename. It's not null-terminated, so use the length field.
for (int i = 0; i < dent->name_len; ++i) {
printf("%c", dent->name[i]);
}
printf("\n");
}
}
size_t vfs_read_file(l9660_file *file, uint8_t* buffer)
{
size_t total_read = 0;
l9660_status status;
for(;;) {
char buf[ISO_9660_BUFFER_LENGTH];
size_t read;
status = l9660_read(file, buf, ISO_9660_BUFFER_LENGTH, &read);
if (status != L9660_OK) {
printf("An error occurred during file read!\n");
break;
}
//check for EOF
if (read == 0)
break;
memcpy(buffer + total_read, buf, read);
total_read += read;
}
return total_read;
}
size_t vfs_read_file_length(l9660_file *file, uint8_t* buffer, size_t length)
{
size_t total_read = 0;
l9660_status status;
while(total_read < length) {
char buf[ISO_9660_BUFFER_LENGTH];
size_t to_read = (length - total_read) < ISO_9660_BUFFER_LENGTH ? (length - total_read) : ISO_9660_BUFFER_LENGTH;
size_t read = 0;
status = l9660_read(file, buf, to_read, &read);
if (status != L9660_OK) {
printf("An error occurred during file read!\n");
break;
}
//check for EOF
if (read == 0)
break;
memcpy(buffer + total_read, buf, read);
total_read += read;
}
return total_read;
}
void test_iso9660()
{
l9660_file g_test_file;
l9660_status status;
printf("Files in root directory:\n");
for (;;) {
l9660_dirent *dent;
status = l9660_readdir(root_dir, &dent);
if (dent == NULL || status != L9660_OK) {
break; // End of directory or error
}
// Print the filename. It's not null-terminated, so use the length field.
for (int i = 0; i < dent->name_len; ++i) {
printf("%c", dent->name[i]);
}
printf("\n");
}
printf("\nReading content of /TEST.TXT:\n");
// Re-open the root directory to reset its position before searching
l9660_fs_open_root(root_dir, global_fs);
l9660_dir boot_dir;
l9660_dir grub_dir;
status = l9660_opendirat(&boot_dir, root_dir, "boot");
printf("STATUS %X\n", status);
status = l9660_opendirat(&grub_dir, &boot_dir, "grub");
printf("STATUS %X\n", status);
status = l9660_openat(&g_test_file, &grub_dir, "grub.cfg");
if (status != L9660_OK) {
printf("Error opening TEST.TXT;1. Error code: ");
printf("%X\n", status); // Print the error code
printf("\n");
} else {
char file_buffer[129];
size_t bytes_read;
uint32_t total_bytes;
for (;;) {
// Read the next chunk of the file
status = l9660_read(&g_test_file, file_buffer, 128, &bytes_read);
// Check for a read error
if (status != L9660_OK) {
printf("An error occurred during file read!\n");
break;
}
// Check for End-Of-File
if (bytes_read == 0) {
break; // We're done
}
// Process the data we just read
total_bytes += bytes_read;
file_buffer[bytes_read] = '\0'; // Null-terminate the chunk
printf(file_buffer); // Print the chunk
}
printf("\n--- EOF ---\n");
printf("Total bytes read: ");
printf("0x%X\n", total_bytes);
}
}
int vfs_read_file_by_path(const char* path, uint8_t** buffer)
{
l9660_file* file = (l9660_file*)malloc(sizeof(l9660_file));
l9660_dir* dir = (l9660_dir*)malloc(sizeof(l9660_dir));
l9660_status err;
err = follow_path(path, file, dir);
if(err != L9660_OK)
{
free(file);
free(dir);
*buffer = NULL;
return err;
}
debug_log("HEHE %s\n", path);
l9660_seek(file, L9660_SEEK_END, 0);
uint32_t file_size = l9660_tell(file);
debug_log("file_size: %X\n", file_size);
l9660_seek(file, L9660_SEEK_SET, 0);
*buffer = (uint8_t*)malloc(file_size);
debug_log("eeee\n");
size_t read;
read = vfs_read_file(file, *buffer);
free(file);
free(dir);
debug_log("bytes read: 0x%X\n", read);
return 0;
}
int follow_path(const char* path, l9660_file* file, l9660_dir* dir)
{
int pos = 0;
int start_from_root = 0;
char buf[32];
int bufpos = 0;
int isdir = 0;
memset(buf, 0, sizeof(buf));
if (path[pos] == '/')
{
start_from_root = 1;
pos++;
l9660_fs_open_root(dir, global_fs);
//debug_log("start_from_root\n");
//debug_log("/");
}
//printf("start_from_root: %X\n\n", start_from_root);
l9660_status status;
while(path[pos] != '\0')
{
while (path[pos] != '/' && path[pos] != '\0')
{
buf[bufpos] = path[pos];
pos++;
bufpos++;
}
buf[bufpos] = '\0'; // Null-terminate the string
bufpos = 0;
if(path[pos] != '\0')
{
isdir = 1;
//debug_log("%s->", buf);//this is a directory
l9660_dir dir2;
status = l9660_opendirat(&dir2, dir, buf);
if(status != L9660_OK)
{
//debug_log("FUCKFUCKFUCKFUCK BLYAAAT!!!!!\n");
return status;
}
*dir = dir2;
}
else
{
isdir = 0;
//debug_log("%s", buf);//this is a file
status = l9660_openat(file, dir, buf);
if(status != L9660_OK)
{
//debug_log("PIZDAPIZDA BLYAAAT!!!!!\n");
return status;
}
return status;
}
pos++;
}
//debug_log("\n");
//printf("buf: %s\n", buf);
//debug_log("isdir: %X\n", isdir);
return status;
}
#ifdef L9660_BIG_ENDIAN
#define READ32(v) (((v).be[3]) | ((v).be[2] << 8) | ((v).be[1]) << 16 | ((v).be[0] << 24))
#else
#define READ32(v) (((v).le[0]) | ((v).le[1] << 8) | ((v).le[2]) << 16 | ((v).le[3] << 24))
#endif
bool is_root_dir(l9660_dir* dir) {
l9660_dirent* dent;
l9660_seekdir(dir, 0);//rewind to start
l9660_readdir(dir, &dent);//reaed .
l9660_readdir(dir, &dent);//read ..
//if .. reads to the directory itself it means that this is the root directory
if (dent != NULL && READ32(dent->sector) == dir->file.first_sector) {
return true;
}
return false;
}
/**
* I'm bad at such loops and ESPECIALLY at such loops which involve sectors and so on
*/
l9660_status find_name_for_sector(char* name_buf, int buf_len, l9660_dir* parent_dir, uint32_t child_sector) {
l9660_dirent* dent;
l9660_status status;
l9660_seekdir(parent_dir, 0); // Rewind parent to search from the start
while (true) {
status = l9660_readdir(parent_dir, &dent);
if (status != L9660_OK) return status;
if (dent == NULL) break; // End of directory
// Is this the entry we are looking for?
if (READ32(dent->sector) == child_sector) {
int len = dent->name_len;
if (len >= buf_len) len = buf_len - 1;
memcpy(name_buf, dent->name, len);
name_buf[len] = '\0';
return L9660_OK;
}
}
return L9660_ENOENT;
}
-61
View File
@@ -1,61 +0,0 @@
section .gdt
extern tss ; Объявляем tss как внешний символ из .data
extern tss_end
gdt_start:
; null entry
dd 0
dd 0
gdt_code:
dw 0xffff ; 00-15 limit
dw 0 ; 16-31 base
db 0 ; 32-39 base
db 10011010b ; 40-47 access
db 11101111b ; 48-55 limit (48-51) and flags (52-55)
db 0 ; 56-63 base
gdt_data:
dw 0xffff ; 00-15 limit
dw 0 ; 16-31 base
db 0 ; 32-39 base
db 10010010b ; 40-47 access
db 11101111b ; 48-55 limit (48-51) and flags (52-55)
db 0 ; 56-63 base
gdt_code_ring3:
dw 0xffff
dw 0
db 0
db 11111010b
db 11101111b
db 0
gdt_data_ring3:
dw 0xffff
dw 0
db 0
db 11110010b
db 11101111b
db 0
gdt_tss:
dw 103 ;tss_end - tss - 1 ; Limit (размер TSS - 1)
dw 0 ; Base (будет заполнено вручную в boot.asm)
db 0 ; Base (средние 8 бит)
db 10001001b ; Access: Present, Ring 0, Type 9 (Available TSS)
db 00000000b ; Limit (48-51) и Flags (52-55): Granularity=0, Size=0
db 0 ; Base (верхние 8 бит)
gdt_end:
gdt:
dw gdt_end - gdt_start - 1
dd gdt_start
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
CODE_SEG_RING3 equ gdt_code_ring3 - gdt_start
DATA_SEG_RING3 equ gdt_data_ring3 - gdt_start
TSS_SEG equ gdt_tss - gdt_start
+183
View File
@@ -0,0 +1,183 @@
#include "../include/apic.h"
#include "../include/paging.h"
#define IA32_APIC_BASE_MSR 0x1B
#define IA32_APIC_BASE_MSR_BSP 0x100 // Processor is a BSP
#define IA32_APIC_BASE_MSR_ENABLE 0x800
#define LAPIC_ID_REG 0x020 // ID Register
#define LAPIC_EOI_REG 0x0B0 // End-of-Interrupt Register
#define LAPIC_SPURIOUS_REG 0x0F0 // Spurious Interrupt Vector Register
#define IOAPIC_REGSEL 0x00
#define IOAPIC_IOWIN 0x10
#define REG_VER 0x1
#define REG_ID 0x0
#define T_IRQ0 32
#define REG_TABLE 0x10
#define INT_DISABLED 0x10000
#define PAGE_WRITE (1 << 1)
#define PAGE_WRITE_THROUGH (1 << 3)
#define PAGE_CACHE_DISABLE (1 << 4)
const unsigned int APIC_PAGE_FLAGS = PAGE_PRESENT | PAGE_WRITE | PAGE_WRITE_THROUGH | PAGE_CACHE_DISABLE;
bool lapic_enabled = false;
volatile uint32_t* lapic_ptr = NULL;
volatile uint32_t* ioapic_ptr = NULL;
bool check_apic()
{
uint32_t eax, edx;
cpuid(1, &eax, &edx);
return edx & (1 << 9);
}
void cpu_set_apic_base(uintptr_t apic) {
uint32_t edx = 0;
uint32_t eax = (apic & 0xfffff000) | IA32_APIC_BASE_MSR_ENABLE;
#ifdef __PHYSICAL_MEMORY_EXTENSION__
edx = (apic >> 32) & 0x0f;
#endif
cpu_set_msr(IA32_APIC_BASE_MSR, eax, edx);
}
uintptr_t cpu_get_apic_base() {
uint32_t eax, edx;
cpu_get_msr(IA32_APIC_BASE_MSR, &eax, &edx);
#ifdef __PHYSICAL_MEMORY_EXTENSION__
return (eax & 0xfffff000) | ((edx & 0x0f) << 32);
#else
return (eax & 0xfffff000);
#endif
}
void enable_apic() {
/* Section 11.4.1 of 3rd volume of Intel SDM recommends mapping the base address page as strong uncacheable for correct APIC operation. */
/* Hardware enable the Local APIC if it wasn't enabled */
cpu_set_apic_base(cpu_get_apic_base());
printf("APIC base: 0x%X\n", cpu_get_apic_base());
map_page((void*)cpu_get_apic_base(), (void*)cpu_get_apic_base(), APIC_PAGE_FLAGS);
lapic_ptr = (uint32_t*)cpu_get_apic_base();
/* Set the Spurious Interrupt Vector Register bit 8 to start receiving interrupts */
lapic_write(LAPIC_SPURIOUS_REG, 0x1FF);
}
void lapic_write(uint32_t offset, uint32_t value) {
*(volatile uint32_t*)((uintptr_t)lapic_ptr + offset) = value;
}
uint32_t lapic_read(uint32_t offset) {
return *(volatile uint32_t*)((uintptr_t)lapic_ptr + offset);
}
void lapic_eoi() {
lapic_write(LAPIC_EOI_REG, 0);
}
void ioapic_init()
{
ioapic_ptr = (uint32_t*)0xFEC00000;
map_page((void*)ioapic_ptr, (void*)ioapic_ptr, APIC_PAGE_FLAGS);
int maxintr = (ioapic_read(ioapic_ptr, REG_VER) >> 16) & 0xFF;
// Mark all interrupts edge-triggered, active high, disabled,
// and not routed to any CPUs.
for(int i = 0; i <= maxintr; i++){
ioapic_write(ioapic_ptr, REG_TABLE+2*i, INT_DISABLED | (T_IRQ0 + i));
ioapic_write(ioapic_ptr, REG_TABLE+2*i+1, 0);
}
}
uint32_t ioapic_read(void *ioapicaddr, uint32_t reg)
{
*(volatile uint32_t*)((uintptr_t)ioapicaddr + IOAPIC_REGSEL) = (reg & 0xff);
return *(volatile uint32_t*)((uintptr_t)ioapicaddr + IOAPIC_IOWIN);
}
void ioapic_write(void *ioapicaddr, uint32_t reg, uint32_t value)
{
*(volatile uint32_t*)((uintptr_t)ioapicaddr + IOAPIC_REGSEL) = (reg & 0xff);
*(volatile uint32_t*)((uintptr_t)ioapicaddr + IOAPIC_IOWIN) = value;
}
uint32_t get_lapic_id() {
return lapic_read(LAPIC_ID_REG) >> 24;
}
void ioapic_redirect(int gsi, int vector) {
ioapic_write(ioapic_ptr, REG_TABLE + 2 * gsi, vector);
ioapic_write(ioapic_ptr, REG_TABLE + 2 * gsi + 1, get_lapic_id() << 24);
}
void enable_symmetric_io_mode() {
outb(0x22, 0x70); // Select IMCR
outb(0x23, 0x01); // Set to Symmetric I/O mode (bypass PIC)
}
#include "../include/isr.h"
#define APIC_REGISTER_TIMER_DIV 0x3E0
#define APIC_REGISTER_TIMER_INITCNT 0x380
#define APIC_REGISTER_LVT_TIMER 0x320
#define APIC_LVT_INT_MASKED 0x10000
#define APIC_REGISTER_TIMER_CURRCNT 0x390
#define APIC_LVT_TIMER_MODE_PERIODIC (1 << 17)
void init_pit_timer_apic(uint32_t reload_value) {
int timerFrequency = 1193182 / reload_value;
outb(0x43, 0b00110100);
uint8_t l = (uint8_t)(timerFrequency & 0xFF);
uint8_t h = (uint8_t)(timerFrequency >> 8 & 0xFF);
outb(0x40, l);
outb(0x40, h);
}
void init_apic_timer()
{
lapic_write(APIC_REGISTER_TIMER_DIV, 0x3);
// Prepare the PIT to sleep for 10ms (10000µs)
init_pit_timer_apic(10000);
__asm__ __volatile__ ("sti");
// Set APIC init counter to -1
lapic_write(APIC_REGISTER_TIMER_INITCNT, 0xFFFFFFFF);
uint32_t target_ticks = timer_ticks + 10;//+10ms
while(timer_ticks < target_ticks)
{}
// Stop the APIC timer
lapic_write(APIC_REGISTER_LVT_TIMER, APIC_LVT_INT_MASKED);
// Now we know how often the APIC timer has ticked in 10ms
uint32_t ticksIn10ms = 0xFFFFFFFF - lapic_read(APIC_REGISTER_TIMER_CURRCNT);
// Start timer as periodic on IRQ 0, divider 16, with the number of ticks we counted
lapic_write(APIC_REGISTER_LVT_TIMER, 32 | APIC_LVT_TIMER_MODE_PERIODIC);
lapic_write(APIC_REGISTER_TIMER_DIV, 0x3);
lapic_write(APIC_REGISTER_TIMER_INITCNT, ticksIn10ms);
}
void mask_pit_interrupt() {
// Mask PIT interrupt (GSI 0, IRQ 0)
ioapic_write(ioapic_ptr, REG_TABLE + 2 * 0, INT_DISABLED | T_IRQ0);
ioapic_write(ioapic_ptr, REG_TABLE + 2 * 0 + 1, 0); // Clear destination field
}
+94
View File
@@ -0,0 +1,94 @@
#include "../include/gdt.h"
#include "../include/string.h"
#include "../include/paging.h"
struct tss_entry_struct tss;
struct seg_desc gdt[NR_GDT_ENTRIES];
struct desc_r gdtr = {
sizeof(gdt) - 1,
(uint32_t)&gdt
};
void bss_init()
{
memset((void *)((int)_edata), 0, KERNEL_BSS_SIZE);
}
uint32_t get_last_boot_addr()
{
return ((uint32_t)_end & PAGE_MASK) + PAGE_SIZE;
}
void load_gdt(uint32_t gdt_ptr) {
asm volatile (
"lgdt (%0)\n\t"
"movw %1, %%ax\n\t"
"movw %%ax, %%ds\n\t"
"movw %%ax, %%es\n\t"
"movw %%ax, %%fs\n\t"
"movw %%ax, %%gs\n\t"
"movw %%ax, %%ss\n\t"
"ljmp %2, $1f\n\t"
"1:\n\t"
:
: "r" (gdt_ptr), "i" (KERNEL_DS), "i" (KERNEL_CS)
: "eax"
);
}
void flush_tss(void) {
asm volatile (
"mov %0, %%ax\n\t"
"ltr %%ax\n\t"
:
: "i" (0x28)
: "ax"
);
}
static void gdt_set_entry(int num, uint32_t base_addr, uint32_t limit, char loflags, char hiflags)
{
num /= sizeof(struct seg_desc);
gdt[num].sd_lolimit = limit & 0xFFFF;
gdt[num].sd_lobase = base_addr & 0xFFFFFF;
gdt[num].sd_loflags = loflags;
gdt[num].sd_hilimit = (limit >> 16) & 0x0F;
gdt[num].sd_hiflags = hiflags;
gdt[num].sd_hibase = (base_addr >> 24) & 0xFF;
}
void gdt_init(void)
{
uint8_t loflags;
memset(&tss, 0, sizeof(tss));
tss.ss0 = KERNEL_DS;
tss.iomap_base = 0xFFFF; // Disable I/O bitmap
tss.esp0 = 0xC0010000; /* kernel stack address (firstly defined in boot.asm)*/
tss.cs = KERNEL_CS;
tss.ds = KERNEL_DS;
tss.es = KERNEL_DS;
tss.fs = KERNEL_DS;
tss.gs = KERNEL_DS;
tss.ss = KERNEL_DS;
gdt_set_entry(0, 0, 0, 0, 0); /* null descriptor */
loflags = SD_CODE | SD_CD | SD_DPL0 | SD_PRESENT;
gdt_set_entry(KERNEL_CS, 0, 0xFFFFFFFF, loflags, SD_OPSIZE32 | SD_PAGE4KB);
loflags = SD_DATA | SD_CD | SD_DPL0 | SD_PRESENT;
gdt_set_entry(KERNEL_DS, 0, 0xFFFFFFFF, loflags, SD_OPSIZE32 | SD_PAGE4KB);
loflags = SD_CODE | SD_CD | SD_DPL3 | SD_PRESENT;
gdt_set_entry(USER_CS, 0, 0xFFFFFFFF, loflags, SD_OPSIZE32 | SD_PAGE4KB);
loflags = SD_DATA | SD_CD | SD_DPL3 | SD_PRESENT;
gdt_set_entry(USER_DS, 0, 0xFFFFFFFF, loflags, SD_OPSIZE32 | SD_PAGE4KB);
loflags = 0x89; // P=1, DPL=0, S=0 (system), Type=0x9 (32-bit TSS)
gdt_set_entry(TSS, (uint32_t)&tss, sizeof(struct tss_entry_struct) - 1, SD_PRESENT | SD_DPL0 | SD_TSSPRESENT, 0);
load_gdt((uint32_t)&gdtr);
flush_tss();
}
+5 -2
View File
@@ -6,14 +6,17 @@ extern void* isr_stub_table[];
#define KERNEL_CS 0x08
#define low_16(address) (uint16_t)((address) & 0xFFFF)
#define high_16(address) (uint16_t)(((address) >> 16) & 0xFFFF)
void idt_set() {
idtr.base = (uint32) &idt;
idtr.base = (uint32_t) &idt;
idtr.limit = sizeof(idt) * sizeof(idt_entry_t) - 1;
__asm__ __volatile__("lidt %0" : : "m" (idtr));
}
void idt_set_descriptor(uint8_t vector, uint32 isr, uint8_t flags) {
void idt_set_descriptor(uint8_t vector, uint32_t isr, uint8_t flags) {
idt_entry_t* descriptor = &idt[vector];
descriptor->isr_low = isr & 0xFFFF;
+57
View File
@@ -0,0 +1,57 @@
section .text
global page_fault_handler
extern handle_page_fault ; C function to process the fault
page_fault_handler:
; Save registers to preserve state
pushad ; Push EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI
push ds
push es
push fs
push gs
; Set up kernel data segment
mov ax, 0x10 ; Kernel data segment selector (adjust based on your GDT)
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
; Get the faulting address from CR2
mov eax, cr2
; Stack layout AFTER pushad + 4 pushes (user-mode fault, ring change):
; [esp+0..15] gs, fs, es, ds (our pushes, gs is lowest)
; [esp+16..47] pushad registers (edi..eax, edi is lowest)
; [esp+48] Error Code (pushed by CPU last = lowest CPU-pushed addr)
; [esp+52] EIP
; [esp+56] CS
; [esp+60] EFLAGS
; [esp+64] ESP (user, only on privilege change)
; [esp+68] SS (user, only on privilege change)
mov ebx, [esp + 48] ; Error code is at this offset
; Push parameters for the C function:
; - Faulting address (from CR2)
; - Error code (from correct offset)
push eax ; Push CR2 (faulting address)
push ebx ; Push error code
; Call the C handler
call handle_page_fault
; Clean up parameters from stack
add esp, 8 ; Remove error code and CR2
; Restore registers
pop gs
pop fs
pop es
pop ds
popad
; Remove error code from stack
add esp, 4 ; Pop error code
; Return from interrupt
iret ; Restore EIP, CS, EFLAGS (and ESP, SS if privilege change)
+112 -39
View File
@@ -1,10 +1,11 @@
#include "../include/idt.h"
#include "../include/isr.h"
#include "../include/types.h"
#include "../include/pic.h"
#include "../include/pit.h"
#include "../include/keyboard.h"
#include "../include/task.h"
#include "../include/apic.h"
#include "../include/sb16.h"
#include <stddef.h>
@@ -18,53 +19,59 @@ struct interrupt_frame
uword_t ss;
};
__attribute__((interrupt)) void spurious(struct interrupt_frame *frame);
__attribute__((interrupt)) void isr_timer(struct interrupt_frame *frame);
__attribute__((interrupt)) void isr_sb16(struct interrupt_frame *frame);
void isr_custom();
void default_handler();
extern void sys_exit_handler();
extern void page_fault_handler();
void isr_install() {
idt_set_descriptor(0, (uint32)isr0, 0x8E);
idt_set_descriptor(1, (uint32)isr1, 0x8E);
idt_set_descriptor(2, (uint32)isr2, 0x8E);
idt_set_descriptor(3, (uint32)isr3, 0x8E);
idt_set_descriptor(4, (uint32)isr4, 0x8E);
idt_set_descriptor(5, (uint32)isr5, 0x8E);
idt_set_descriptor(6, (uint32)isr6, 0x8E);
idt_set_descriptor(7, (uint32)isr7, 0x8E);
idt_set_descriptor(8, (uint32)isr8, 0x8E);
idt_set_descriptor(9, (uint32)isr9, 0x8E);
idt_set_descriptor(10, (uint32)isr10, 0x8E);
idt_set_descriptor(11, (uint32)isr11, 0x8E);
idt_set_descriptor(12, (uint32)isr12, 0x8E);
idt_set_descriptor(13, (uint32)isr13, 0x8E);
idt_set_descriptor(14, (uint32)isr14, 0x8E);
idt_set_descriptor(15, (uint32)isr15, 0x8E);
idt_set_descriptor(16, (uint32)isr16, 0x8E);
idt_set_descriptor(17, (uint32)isr17, 0x8E);
idt_set_descriptor(18, (uint32)isr18, 0x8E);
idt_set_descriptor(19, (uint32)isr19, 0x8E);
idt_set_descriptor(20, (uint32)isr20, 0x8E);
idt_set_descriptor(21, (uint32)isr21, 0x8E);
idt_set_descriptor(22, (uint32)isr22, 0x8E);
idt_set_descriptor(23, (uint32)isr23, 0x8E);
idt_set_descriptor(24, (uint32)isr24, 0x8E);
idt_set_descriptor(25, (uint32)isr25, 0x8E);
idt_set_descriptor(26, (uint32)isr26, 0x8E);
idt_set_descriptor(27, (uint32)isr27, 0x8E);
idt_set_descriptor(28, (uint32)isr28, 0x8E);
idt_set_descriptor(29, (uint32)isr29, 0x8E);
idt_set_descriptor(30, (uint32)isr30, 0x8E);
idt_set_descriptor(31, (uint32)isr31, 0x8E);
idt_set_descriptor(0, (uint32_t)isr0, 0x8E);
idt_set_descriptor(1, (uint32_t)isr1, 0x8E);
idt_set_descriptor(2, (uint32_t)isr2, 0x8E);
idt_set_descriptor(3, (uint32_t)isr3, 0x8E);
idt_set_descriptor(4, (uint32_t)isr4, 0x8E);
idt_set_descriptor(5, (uint32_t)isr5, 0x8E);
idt_set_descriptor(6, (uint32_t)isr6, 0x8E);
idt_set_descriptor(7, (uint32_t)isr7, 0x8E);
idt_set_descriptor(8, (uint32_t)isr8, 0x8E);
idt_set_descriptor(9, (uint32_t)isr9, 0x8E);
idt_set_descriptor(10, (uint32_t)isr10, 0x8E);
idt_set_descriptor(11, (uint32_t)isr11, 0x8E);
idt_set_descriptor(12, (uint32_t)isr12, 0x8E);
idt_set_descriptor(13, (uint32_t)isr13, 0x8E);
idt_set_descriptor(14, (uint32_t)page_fault_handler, 0x8E);
idt_set_descriptor(15, (uint32_t)isr15, 0x8E);
idt_set_descriptor(16, (uint32_t)isr16, 0x8E);
idt_set_descriptor(17, (uint32_t)isr17, 0x8E);
idt_set_descriptor(18, (uint32_t)isr18, 0x8E);
idt_set_descriptor(19, (uint32_t)isr19, 0x8E);
idt_set_descriptor(20, (uint32_t)isr20, 0x8E);
idt_set_descriptor(21, (uint32_t)isr21, 0x8E);
idt_set_descriptor(22, (uint32_t)isr22, 0x8E);
idt_set_descriptor(23, (uint32_t)isr23, 0x8E);
idt_set_descriptor(24, (uint32_t)isr24, 0x8E);
idt_set_descriptor(25, (uint32_t)isr25, 0x8E);
idt_set_descriptor(26, (uint32_t)isr26, 0x8E);
idt_set_descriptor(27, (uint32_t)isr27, 0x8E);
idt_set_descriptor(28, (uint32_t)isr28, 0x8E);
idt_set_descriptor(29, (uint32_t)isr29, 0x8E);
idt_set_descriptor(30, (uint32_t)isr30, 0x8E);
idt_set_descriptor(31, (uint32_t)isr31, 0x8E);
for(int i = 32; i < 255; i++)
idt_set_descriptor(i, (uint32)default_handler, 0x8E);
idt_set_descriptor(i, (uint32_t)default_handler, 0x8E);
idt_set_descriptor(0x20, (uint32)isr_timer, 0x8E);
idt_set_descriptor(0x21, (uint32)isr_custom, 0x8E);
idt_set_descriptor(0x20, (uint32_t)isr_timer, 0x8E);
idt_set_descriptor(0x21, (uint32_t)isr_custom, 0x8E);
idt_set_descriptor(0x25, (uint32_t)isr_sb16, 0x8E);
idt_set_descriptor(0x80, (uint32)sys_exit_handler, 0xEE);
idt_set_descriptor(0x80, (uint32_t)sys_exit_handler, 0xEE);
idt_set_descriptor(255, (uint32_t)spurious, 0x8E);
idt_set(); // Load with ASM
printf("isr_install done\n");
@@ -75,10 +82,56 @@ void default_handler()
}
#include "../include/paging.h"
void handle_page_fault(uint32_t error_code, uint32_t faulting_address)
{
int present = !(error_code & 0x1); // Bit 0: 0 = not present, 1 = protection violation
int write = error_code & 0x2; // Bit 1: 0 = read, 1 = write
int user = error_code & 0x4; // Bit 2: 0 = supervisor, 1 = user
int reserved = error_code & 0x8; // Bit 3: 0 = no reserved bits, 1 = reserved bits
int instruction = error_code & 0x10; // Bit 4: 0 = data, 1 = instruction fetch
uint32_t pte = get_pte((void*)faulting_address);
printf("Page fault at address 0x%x\n", faulting_address);
printf("Present: %X, Write: %X, User: %X, Reserved: %X, Instruction: %X\n",
present, write, user, reserved, instruction);
printf("PTE: 0x%X (phys: 0x%X, %s, %s)\n", pte, pte & ~0xFFF,
(pte & 0x2) ? "writable" : "read-only",
(pte & 0x4) ? "user" : "supervisor");
printf("ERR: 0x%X\n", error_code);
if (user) {
printf("page fault, killing task %x\n", current->pid);
task_kill(current);
asm volatile("sti");
while (1) {}
}
asm("hlt");
}
__attribute__((interrupt)) void spurious(struct interrupt_frame *frame)
{
lapic_eoi();
}
uint32_t timer_ticks = 0;
__attribute__((interrupt)) void isr_timer(struct interrupt_frame *frame)
{
pit_init(100);
timer_ticks++;
if(lapic_enabled)
{
lapic_eoi();
}
else
{
pic_end_int(0x0);
}
scheduler_lock();
schedule();
@@ -89,8 +142,28 @@ __attribute__((interrupt)) void isr_custom(struct interrupt_frame *frame)
{
//terminal_writestring("YOOOOO!!!!!! I LOVE KATYA!!!!");
handle_keyboard();
if(lapic_enabled)
{
lapic_eoi();
}
else
{
pic_end_int(0x1);
}
}
__attribute__((interrupt)) void isr_sb16(struct interrupt_frame *frame)
{
sb16_ack();
if(lapic_enabled)
{
lapic_eoi();
}
else
{
pic_end_int(sb16_irq);
}
}
void isr0()
{
@@ -253,7 +326,7 @@ void isr31()
asm("hlt");
}
static string exception_messages[] = {
static char* exception_messages[] = {
"Division By Zero",
"Debug",
"Non Maskable Interrupt",
+102 -145
View File
@@ -9,148 +9,101 @@
#include "../include/paging.h"
#include "../include/fat.h"
#include "../include/task.h"
#include "../include/multiboot.h"
#include "../include/liballoc.h"
#include "../include/kheap.h"
#include "../include/exec_from_file.h"
#include "../include/atapi.h"
#include "../include/vfs.h"
#include "../include/apic.h"
#include "../include/keyboard.h"
#include "../include/sb16.h"
#include <stdint.h>
disk_ops_t ops =
void kmain(unsigned int magic, unsigned int info)
{
.read = ata_read,
.write = ata_write,
};
struct multiboot_info mbi;
memcpy(&mbi, (void*)info, sizeof(struct multiboot_info));
static fat_t g_fat;
static const char* months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
static int cat(const char* path)
{
file_t file;
int err = fat_fopen(&file, path, "r");
if (err)
return err;
uint8_t buf[512];
for (;;)
{
int cnt = fat_fread(&file, buf, 512);
if (cnt < 0)
return cnt;
printf("%.*s\n", cnt, buf);
printf("%s\n", buf);
if (cnt < 512)
break;
}
return fat_fclose(&file);
}
static int ls(const char* path)
{
dir_t dir;
dir_info_t info;
int err = fat_opendir(&dir, path);
if (err)
return err;
for (;;)
{
err = fat_readdir(&dir, &info);
if (err == FAT_ERR_EOF)
return FAT_ERR_NONE;
if (err)
return err;
printf("%X %s %x %x:%x %x %s%c\n",
info.size, months[info.modified.month], info.modified.day,
info.modified.hour, info.modified.min,
info.namelen, info.name, info.attr & FAT_ATTR_DIR ? '/' : ' ');
err = fat_nextdir(&dir);
if (err)
return err;
}
}
void test(int err, const char* huy)
{
if(err != 0)
printf("ERROR: %X %s\n", err, huy);
else
printf("%s done", huy);
}
void file_fuckery()
{
int err, cnt;
err = fat_mount(&ops, 0, &g_fat, "ebalo");
if(err)
printf("KATYAKATYAKATYAKATYAKATYA: %X\n", err);
printf("%X\n", err);
err = ls("/ebalo");
printf("\n\n\n");
err = fat_mkdir("/ebalo/numbers");
err = fat_mkdir("/ebalo/numbers/nigga");
printf("MKDIR ERR: %X\n", err);
err = fat_unlink("/ebalo/numbers/nigga/");
printf("UNLINK ERR: %X\n", err);
err = fat_unlink("/ebalo/numbers/");
printf("UNLINK ERR: %X\n", err);
/*err = fat_mkdir("/ebalo/numbers");
//err = cat("/ebalo/boot/grub/grub.cfg");
char *filenames[] = {"/ebalo/numbers/d","/ebalo/numbers/e"};
for(int i = 0; i < 2; i++){
printf(filenames[i]);
file_t file;
err = fat_fopen(&file, filenames[i], "w");
if (err)
{printf("1 err %X\n", err); goto unmount;}
for (int i = 0; i < 10; i++)
{
cnt = fat_fprintf(&file, "This is test number %d\n", i);
if (cnt < 0)
{printf("2 cnt: %X\n", cnt); goto unmount;}
}
err = fat_fclose(&file);
}
*/
unmount:
printf("err%X\n", err);
err = fat_umount(&g_fat);
test(err, "unmount");
}
void apply_pic_masks()
{
//0x21 is master pic, 0xa1 is slave pic
outb(0x21,0xfc);//0b11111100 (bit 0 is PIT, bit 1 is keyboard and so on)
outb(0xa1,0xff);
}
void kmain()
{
terminal_initialize();
printf("KatauOS booting up\n");
if(magic != MULTIBOOT_BOOTLOADER_MAGIC) {
printf("invalid magic number!\n");
while(1){}
}
if(mbi.flags & MULTIBOOT_INFO_BOOT_LOADER_NAME) {
printf("bootloader: %s\n", mbi.boot_loader_name);
}
printf("init_allocator...");
init_allocator();
printf("done\n");
printf("grub_memory_map...");
grub_memory_map(magic, &mbi);
printf("done\n");
isr_install();
if(cpu_has_msr())
{
printf("CPU has MSR\n");
}
if(check_apic() && cpu_has_msr())
{
printf("APIC is present\n");
lapic_enabled = true;
}
if(!lapic_enabled)
{
pic_remap(0x20, 0x28);
pit_init(100);
apply_pic_masks();
pic_apply_masks();
}
else
{
pic_disable();
enable_symmetric_io_mode();
enable_apic();
ioapic_init();
printf("IOAPIC init done\n");
ioapic_redirect(2, 32);//timer
ioapic_redirect(1, 33);//keyboard
paging_init();
printf("paging_init done\n");
test_paging();
init_allocator();
heap_init();
printf("after heap_init\n");
init_apic_timer();
mask_pit_interrupt();
}
printf("done fucking with pages and memory map!\n");
char *test_str;
printf("test_str: %X, &test_str %X\n", test_str, &test_str);
test_str = alloc_page();
printf("test_str: %X, &test_str %X\n", test_str, &test_str);
free_page(test_str);
//reserve first 16 pages (64KB) for the stack whose top address is defined as 0xC0010000 in the boot.asm
for(int i = 0; i < 16; i++)
{
alloc_page();
}
//while(1){}
//paging_init();
//printf("paging_init done\n");
//test_paging();
//heap_init();
//printf("after heap_init\n");
kheap_init();
__asm__ __volatile__ ("sti");
scheduler_init();
printf("Kernel init sequence completed\n");
@@ -158,9 +111,9 @@ void kmain()
char yooo[256] = "heheh";
printf("test string: %s\n", yooo);
disk_info info;
get_disk_info(&info);
printf("CYL HEAD SECT: %X %X %X\n", info.cylinders, info.heads, info.sectors);
disk_info info1;
get_disk_info(&info1);
printf("CYL HEAD SECT: %X %X %X\n", info1.cylinders, info1.heads, info1.sectors);
//file_fuckery();
@@ -169,8 +122,8 @@ void kmain()
char temp1[1024] = "rusya_krutoy";
char temp2[1024] = "katya_tozhe_krutaya";
huy = heap_alloc(1024);
huy2 = heap_alloc(1024);
huy = kvalloc(1);//alloc_page();
huy2 = kvalloc(2);//alloc_page();
memcpy(huy, temp1, sizeof(temp1));
memcpy(huy2, temp2, sizeof(temp1));
@@ -179,18 +132,22 @@ void kmain()
printf("huy1 points to: 0x%X huy2 points to:0x%X\n", huy, huy2);
printf("huy1: %s\nhuy2: %s", huy, huy2);
mount_fs();
init_keyboard();
l9660_dir dir;
l9660_file file;
follow_path("/katau/ksh.", &file, &dir);
sb16_init();
exec_from_file(&file, &dir);
while(1)
{
/* if(inportb(0x64) & 0x1)
{
unsigned char key = inportb(0x60);
if(key == 2)
terminal_writestring("1\n");
else if(key == 4)
terminal_writestring("3\n");
else
terminal_writestring("dunno what is it\n");
asm("sti; hlt");
}
*/ }
}
+7
View File
@@ -75,3 +75,10 @@ void pic_end_int(uint8_t irq) {
if (irq >= 8) outb(PIC2_COMMAND, 0x20);
outb(PIC1_COMMAND, 0x20);
}
void pic_apply_masks()
{
//0x21 is master pic, 0xa1 is slave pic
outb(0x21,0xfc);//0b11111100 (bit 0 is PIT, bit 1 is keyboard and so on)
outb(0xa1,0xff);
}
-127
View File
@@ -1,127 +0,0 @@
#include "../include/paging.h"
#include <stdint.h>
#include "../include/stdio.h"
// Структура заголовка блока памяти
typedef struct Block {
uint32_t size; // Размер блока (в байтах, включая заголовок)
uint32_t is_free; // 1 = свободен, 0 = занят
struct Block* next; // Указатель на следующий блок
} Block;
// Структура для управления кучей
typedef struct {
void* start; // Начало кучи
uint32_t size; // Текущий размер кучи в байтах
Block* first; // Первый блок в куче
} Heap;
Heap kernel_heap;
void heap_init() {
kernel_heap.start = (void*)0xD0000000; // Начало кучи в ядре
kernel_heap.size = 0x1000; // Начальный размер — 1 страница (4 КБ)
printf("before map_kernel_page\n");
// Отображаем первую страницу
map_kernel_page(kernel_heap.start, 0x2); // writable, supervisor
printf("after map_kernel_page\n");
// Создаём первый блок, который занимает всю страницу
Block* initial_block = (Block*)kernel_heap.start;
initial_block->size = 0x1000 - sizeof(Block); // Размер без учёта заголовка
initial_block->is_free = 1; // Свободен
initial_block->next = (Block*)0; // Пока нет следующего
kernel_heap.first = initial_block;
}
void* heap_alloc(uint32_t size) {
// Выравниваем размер до 4 байт
size = (size + 3) & ~3;
Block* current = kernel_heap.first;
Block* prev = (Block*)0;
// Ищем подходящий свободный блок
while (current) {
if (current->is_free && current->size >= size) {
if (current->size >= size + sizeof(Block) + 4) {
Block* new_block = (Block*)((uint32_t)current + sizeof(Block) + size);
new_block->size = current->size - size - sizeof(Block);
new_block->is_free = 1;
new_block->next = current->next;
current->size = size;
current->next = new_block;
}
current->is_free = 0;
return (void*)((uint32_t)current + sizeof(Block));
}
prev = current;
current = current->next;
}
// Нет подходящего блока — выделяем нужное количество страниц
uint32_t total_size = size + sizeof(Block); // Размер с заголовком
uint32_t pages_needed = (total_size + 0xFFF) / 0x1000; // Округляем вверх до страниц
uint32_t alloc_size = pages_needed * 0x1000; // Сколько байт выделяем
void* new_page = (void*)((uint32_t)kernel_heap.start + kernel_heap.size);
for (uint32_t i = 0; i < pages_needed; i++) {
map_kernel_page((void*)((uint32_t)new_page + i * 0x1000), 0x2);
}
kernel_heap.size += alloc_size;
Block* new_block = (Block*)new_page;
new_block->size = alloc_size - sizeof(Block);
new_block->is_free = 1;
new_block->next = (Block*)0;
if (prev) prev->next = new_block;
if (!kernel_heap.first) kernel_heap.first = new_block;
// Теперь current указывает на новый блок, продолжаем цикл
current = new_block;
if (current->size >= size) {
if (current->size >= size + sizeof(Block) + 4) {
Block* split_block = (Block*)((uint32_t)current + sizeof(Block) + size);
split_block->size = current->size - size - sizeof(Block);
split_block->is_free = 1;
split_block->next = current->next;
current->size = size;
current->next = split_block;
}
current->is_free = 0;
return (void*)((uint32_t)current + sizeof(Block));
}
// Если что-то пошло не так, возвращаем NULL
return (void*)0;
}
void heap_free(void* ptr) {
if (!ptr || (uint32_t)ptr < (uint32_t)kernel_heap.start) return;
// Находим блок по указателю (указатель указывает после заголовка)
Block* block = (Block*)((uint32_t)ptr - sizeof(Block));
block->is_free = 1;
// Слияние с предыдущим блоком, если он свободен
Block* current = kernel_heap.first;
Block* prev = (Block*)0;
while (current && current != block) {
prev = current;
current = current->next;
}
if (prev && prev->is_free) {
prev->size += sizeof(Block) + block->size;
prev->next = block->next;
block = prev;
}
// Слияние с следующим блоком, если он свободен
if (block->next && block->next->is_free) {
block->size += sizeof(Block) + block->next->size;
block->next = block->next->next;
}
}
+159
View File
@@ -0,0 +1,159 @@
// kernel_heap.c
#include "../include/kheap.h"
#include "../include/paging.h"
#include "../include/stdio.h"
#include "../include/string.h"
#include <liballoc.h>
int liballoc_lock() {
// Implement locking (disable interrupts or use spinlock)
asm volatile("cli");
return 0;
}
int liballoc_unlock() {
// Implement unlocking
asm volatile("sti");
return 0;
}
void* liballoc_alloc(int pages) {
return kvalloc(pages);
}
int liballoc_free(void* ptr, int pages) {
kvfree(ptr, pages);
return 0;
}
static uint8_t kheap_bitmap[KHEAP_PAGES / 8];
// Test a bit in kernel heap bitmap
static int kheap_bitmap_test(uint32_t index) {
uint32_t byte = index / 8;
uint8_t bit = index % 8;
return (kheap_bitmap[byte] >> bit) & 1;
}
// Set a bit in kernel heap bitmap
static void kheap_bitmap_set(uint32_t index) {
uint32_t byte = index / 8;
uint8_t bit = index % 8;
kheap_bitmap[byte] |= (1 << bit);
}
// Clear a bit in kernel heap bitmap
static void kheap_bitmap_clear(uint32_t index) {
uint32_t byte = index / 8;
uint8_t bit = index % 8;
kheap_bitmap[byte] &= ~(1 << bit);
}
// Initialize kernel heap
void kheap_init() {
memset(kheap_bitmap, 0, sizeof(kheap_bitmap));
void* temp_phys = alloc_page();
if (!temp_phys) {
printf("CRITICAL: Failed to init heap - No physical memory\n");
while(1);
}
uint32_t heap_limit = 4 * 1024 * 1024;
for (uint32_t vaddr = KHEAP_START; vaddr < KHEAP_START + heap_limit; vaddr += 0x400000) {
// This call checks if the Page Table exists.
// If not, it allocates a new Page Table and inserts it into the Current PD.
map_page(temp_phys, (void*)vaddr, PAGE_PRESENT | PAGE_RW);
// We don't actually want the page mapped, we just wanted the Side Effect
// of creating the Page Table. So we unmap the page immediately.
// unmap_page clears the Entry, but DOES NOT free the Page Table itself.
unmap_page((void*)vaddr);
}
// Free the dummy page
free_page(temp_phys);
printf("Kernel Heap Initialized (Pre-allocated tables for 0x%X MB)\n", heap_limit / 1024 / 1024);
}
// Allocate contiguous virtual pages
void* kvalloc(size_t npages) {
// Limit allocation size for safety
if (npages > 1024 || npages == 0) {
return NULL;
}
uint32_t start = 0;
uint32_t count = 0;
// Find contiguous free pages in bitmap
for (uint32_t i = 0; i < KHEAP_PAGES; i++) {
if (!kheap_bitmap_test(i)) {
count++;
if (count >= npages) {
start = i - npages + 1;
break;
}
} else {
count = 0;
}
}
if (count < npages) {
return NULL; // Not enough contiguous space
}
// Temporarily store physical addresses
uint32_t vaddr = KHEAP_START + start * PAGE_SIZE;
for (uint32_t i = 0; i < npages; i++) {
void* phys = alloc_page();
if (!phys) {
debug_log("NO MEMORY FOR KVALLOC!!\n");
while(1){asm volatile("cli; hlt");}
kvfree((void*)vaddr, i);
return NULL;
}
// Map the page
map_page(phys, (void*)(vaddr + i * PAGE_SIZE), PAGE_PRESENT | PAGE_RW);
}
// Mark virtual pages as allocated
for (uint32_t i = start; i < start + npages; i++) {
kheap_bitmap_set(i);
}
return (void*)vaddr;
}
// Free allocated pages
void kvfree(void* addr, size_t npages) {
uint32_t vaddr = (uint32_t)addr;
if (vaddr < KHEAP_START || vaddr >= KHEAP_END) {
printf("kvfree: invalid address 0x%x\n", vaddr);
return;
}
uint32_t start = (vaddr - KHEAP_START) / PAGE_SIZE;
for (uint32_t i = 0; i < npages; i++) {
uint32_t current_vaddr = vaddr + i * PAGE_SIZE;
void* phys = get_physaddr((void*)current_vaddr);
if (phys) {
free_page(phys);
} else {
debug_log("kvfree: no phys mapping for %x\n", current_vaddr);
}
unmap_page((void*)current_vaddr);
kheap_bitmap_clear(start + i);
}
}
+533
View File
@@ -0,0 +1,533 @@
#include <liballoc.h>
/** Durand's Ridiculously Amazing Super Duper Memory functions. */
//#define DEBUG
#define LIBALLOC_MAGIC 0xc001c0de
#define MAXCOMPLETE 5
#define MAXEXP 32
#define MINEXP 8
#define MODE_BEST 0
#define MODE_INSTANT 1
#define MODE MODE_BEST
#ifdef DEBUG
#include <stdio.h>
#endif
struct boundary_tag* l_freePages[MAXEXP]; //< Allowing for 2^MAXEXP blocks
int l_completePages[MAXEXP]; //< Allowing for 2^MAXEXP blocks
#ifdef DEBUG
unsigned int l_allocated = 0; //< The real amount of memory allocated.
unsigned int l_inuse = 0; //< The amount of memory in use (malloc'ed).
#endif
static int l_initialized = 0; //< Flag to indicate initialization.
static int l_pageSize = 4096; //< Individual page size
static int l_pageCount = 16; //< Minimum number of pages to allocate.
// *********** HELPER FUNCTIONS *******************************
/** Returns the exponent required to manage 'size' amount of memory.
*
* Returns n where 2^n <= size < 2^(n+1)
*/
static inline int getexp( unsigned int size )
{
if ( size < (1<<MINEXP) )
{
#ifdef DEBUG
printf("getexp returns -1 for %i less than MINEXP\n", size );
#endif
return -1; // Smaller than the quantum.
}
int shift = MINEXP;
while ( shift < MAXEXP )
{
if ( (1<<shift) > size ) break;
shift += 1;
}
#ifdef DEBUG
printf("getexp returns %i (%i bytes) for %i size\n", shift - 1, (1<<(shift -1)), size );
#endif
return shift - 1;
}
static void* liballoc_memset(void* s, int c, size_t n)
{
int i;
for ( i = 0; i < n ; i++)
((char*)s)[i] = c;
return s;
}
static void* liballoc_memcpy(void* s1, const void* s2, size_t n)
{
char *cdest;
char *csrc;
unsigned int *ldest = (unsigned int*)s1;
unsigned int *lsrc = (unsigned int*)s2;
while ( n >= sizeof(unsigned int) )
{
*ldest++ = *lsrc++;
n -= sizeof(unsigned int);
}
cdest = (char*)ldest;
csrc = (char*)lsrc;
while ( n > 0 )
{
*cdest++ = *csrc++;
n -= 1;
}
return s1;
}
#ifdef DEBUG
static void dump_array()
{
int i = 0;
struct boundary_tag *tag = NULL;
printf("------ Free pages array ---------\n");
printf("System memory allocated: %i\n", l_allocated );
printf("Memory in used (malloc'ed): %i\n", l_inuse );
for ( i = 0; i < MAXEXP; i++ )
{
printf("%.2i(%i): ",i, l_completePages[i] );
tag = l_freePages[ i ];
while ( tag != NULL )
{
if ( tag->split_left != NULL ) printf("*");
printf("%i", tag->real_size );
if ( tag->split_right != NULL ) printf("*");
printf(" ");
tag = tag->next;
}
printf("\n");
}
printf("'*' denotes a split to the left/right of a tag\n");
fflush( stdout );
}
#endif
static inline void insert_tag( struct boundary_tag *tag, int index )
{
int realIndex;
if ( index < 0 )
{
realIndex = getexp( tag->real_size - sizeof(struct boundary_tag) );
if ( realIndex < MINEXP ) realIndex = MINEXP;
}
else
realIndex = index;
tag->index = realIndex;
if ( l_freePages[ realIndex ] != NULL )
{
l_freePages[ realIndex ]->prev = tag;
tag->next = l_freePages[ realIndex ];
}
l_freePages[ realIndex ] = tag;
}
static inline void remove_tag( struct boundary_tag *tag )
{
if ( l_freePages[ tag->index ] == tag ) l_freePages[ tag->index ] = tag->next;
if ( tag->prev != NULL ) tag->prev->next = tag->next;
if ( tag->next != NULL ) tag->next->prev = tag->prev;
tag->next = NULL;
tag->prev = NULL;
tag->index = -1;
}
static inline struct boundary_tag* melt_left( struct boundary_tag *tag )
{
struct boundary_tag *left = tag->split_left;
left->real_size += tag->real_size;
left->split_right = tag->split_right;
if ( tag->split_right != NULL ) tag->split_right->split_left = left;
return left;
}
static inline struct boundary_tag* absorb_right( struct boundary_tag *tag )
{
struct boundary_tag *right = tag->split_right;
remove_tag( right ); // Remove right from free pages.
tag->real_size += right->real_size;
tag->split_right = right->split_right;
if ( right->split_right != NULL )
right->split_right->split_left = tag;
return tag;
}
static inline struct boundary_tag* split_tag( struct boundary_tag* tag )
{
unsigned int remainder = tag->real_size - sizeof(struct boundary_tag) - tag->size;
struct boundary_tag *new_tag =
(struct boundary_tag*)((unsigned int)tag + sizeof(struct boundary_tag) + tag->size);
new_tag->magic = LIBALLOC_MAGIC;
new_tag->real_size = remainder;
new_tag->next = NULL;
new_tag->prev = NULL;
new_tag->split_left = tag;
new_tag->split_right = tag->split_right;
if (new_tag->split_right != NULL) new_tag->split_right->split_left = new_tag;
tag->split_right = new_tag;
tag->real_size -= new_tag->real_size;
insert_tag( new_tag, -1 );
return new_tag;
}
// ***************************************************************
static struct boundary_tag* allocate_new_tag( unsigned int size )
{
unsigned int pages;
unsigned int usage;
struct boundary_tag *tag;
// This is how much space is required.
usage = size + sizeof(struct boundary_tag);
// Perfect amount of space
pages = usage / l_pageSize;
if ( (usage % l_pageSize) != 0 ) pages += 1;
// Make sure it's >= the minimum size.
if ( pages < l_pageCount ) pages = l_pageCount;
tag = (struct boundary_tag*)liballoc_alloc( pages );
if ( tag == NULL ) return NULL; // uh oh, we ran out of memory.
tag->magic = LIBALLOC_MAGIC;
tag->size = size;
tag->real_size = pages * l_pageSize;
tag->index = -1;
tag->next = NULL;
tag->prev = NULL;
tag->split_left = NULL;
tag->split_right = NULL;
#ifdef DEBUG
printf("Resource allocated %x of %i pages (%i bytes) for %i size.\n", tag, pages, pages * l_pageSize, size );
l_allocated += pages * l_pageSize;
printf("Total memory usage = %i KB\n", (int)((l_allocated / (1024))) );
#endif
return tag;
}
void *malloc(size_t size)
{
int index;
void *ptr;
struct boundary_tag *tag = NULL;
liballoc_lock();
if ( l_initialized == 0 )
{
#ifdef DEBUG
printf("%s\n","liballoc initializing.");
#endif
for ( index = 0; index < MAXEXP; index++ )
{
l_freePages[index] = NULL;
l_completePages[index] = 0;
}
l_initialized = 1;
}
index = getexp( size ) + MODE;
if ( index < MINEXP ) index = MINEXP;
// Find one big enough.
tag = l_freePages[ index ]; // Start at the front of the list.
while ( tag != NULL )
{
// If there's enough space in this tag.
if ( (tag->real_size - sizeof(struct boundary_tag))
>= (size + sizeof(struct boundary_tag) ) )
{
#ifdef DEBUG
printf("Tag search found %i >= %i\n",(tag->real_size - sizeof(struct boundary_tag)), (size + sizeof(struct boundary_tag) ) );
#endif
break;
}
tag = tag->next;
}
// No page found. Make one.
if ( tag == NULL )
{
if ( (tag = allocate_new_tag( size )) == NULL )
{
liballoc_unlock();
return NULL;
}
index = getexp( tag->real_size - sizeof(struct boundary_tag) );
}
else
{
remove_tag( tag );
if ( (tag->split_left == NULL) && (tag->split_right == NULL) )
l_completePages[ index ] -= 1;
}
// We have a free page. Remove it from the free pages list.
tag->size = size;
// Removed... see if we can re-use the excess space.
#ifdef DEBUG
printf("Found tag with %i bytes available (requested %i bytes, leaving %i), which has exponent: %i (%i bytes)\n", tag->real_size - sizeof(struct boundary_tag), size, tag->real_size - size - sizeof(struct boundary_tag), index, 1<<index );
#endif
unsigned int remainder = tag->real_size - size - sizeof( struct boundary_tag ) * 2; // Support a new tag + remainder
if ( ((int)(remainder) > 0) /*&& ( (tag->real_size - remainder) >= (1<<MINEXP))*/ )
{
int childIndex = getexp( remainder );
if ( childIndex >= 0 )
{
#ifdef DEBUG
printf("Seems to be splittable: %i >= 2^%i .. %i\n", remainder, childIndex, (1<<childIndex) );
#endif
struct boundary_tag *new_tag = split_tag( tag );
new_tag = new_tag; // Get around the compiler warning about unused variables.
#ifdef DEBUG
printf("Old tag has become %i bytes, new tag is now %i bytes (%i exp)\n", tag->real_size, new_tag->real_size, new_tag->index );
#endif
}
}
ptr = (void*)((unsigned int)tag + sizeof( struct boundary_tag ) );
#ifdef DEBUG
l_inuse += size;
printf("malloc: %x, %i, %i\n", ptr, (int)l_inuse / 1024, (int)l_allocated / 1024 );
dump_array();
#endif
liballoc_unlock();
return ptr;
}
void free(void *ptr)
{
int index;
struct boundary_tag *tag;
if ( ptr == NULL ) return;
liballoc_lock();
tag = (struct boundary_tag*)((unsigned int)ptr - sizeof( struct boundary_tag ));
if ( tag->magic != LIBALLOC_MAGIC )
{
liballoc_unlock(); // release the lock
return;
}
#ifdef DEBUG
l_inuse -= tag->size;
printf("free: %x, %i, %i\n", ptr, (int)l_inuse / 1024, (int)l_allocated / 1024 );
#endif
// MELT LEFT...
while ( (tag->split_left != NULL) && (tag->split_left->index >= 0) )
{
#ifdef DEBUG
printf("Melting tag left into available memory. Left was %i, becomes %i (%i)\n", tag->split_left->real_size, tag->split_left->real_size + tag->real_size, tag->split_left->real_size );
#endif
tag = melt_left( tag );
remove_tag( tag );
}
// MELT RIGHT...
while ( (tag->split_right != NULL) && (tag->split_right->index >= 0) )
{
#ifdef DEBUG
printf("Melting tag right into available memory. This was was %i, becomes %i (%i)\n", tag->real_size, tag->split_right->real_size + tag->real_size, tag->split_right->real_size );
#endif
tag = absorb_right( tag );
}
// Where is it going back to?
index = getexp( tag->real_size - sizeof(struct boundary_tag) );
if ( index < MINEXP ) index = MINEXP;
// A whole, empty block?
if ( (tag->split_left == NULL) && (tag->split_right == NULL) )
{
if ( l_completePages[ index ] == MAXCOMPLETE )
{
// Too many standing by to keep. Free this one.
unsigned int pages = tag->real_size / l_pageSize;
if ( (tag->real_size % l_pageSize) != 0 ) pages += 1;
if ( pages < l_pageCount ) pages = l_pageCount;
liballoc_free( tag, pages );
#ifdef DEBUG
l_allocated -= pages * l_pageSize;
printf("Resource freeing %x of %i pages\n", tag, pages );
dump_array();
#endif
liballoc_unlock();
return;
}
l_completePages[ index ] += 1; // Increase the count of complete pages.
}
// ..........
insert_tag( tag, index );
#ifdef DEBUG
printf("Returning tag with %i bytes (requested %i bytes), which has exponent: %i\n", tag->real_size, tag->size, index );
dump_array();
#endif
liballoc_unlock();
}
void* calloc(size_t nobj, size_t size)
{
int real_size;
void *p;
real_size = nobj * size;
p = malloc( real_size );
liballoc_memset( p, 0, real_size );
return p;
}
void* realloc(void *p, size_t size)
{
void *ptr;
struct boundary_tag *tag;
int real_size;
if ( size == 0 )
{
free( p );
return NULL;
}
if ( p == NULL ) return malloc( size );
if ( liballoc_lock != NULL ) liballoc_lock(); // lockit
tag = (struct boundary_tag*)((unsigned int)p - sizeof( struct boundary_tag ));
real_size = tag->size;
if ( liballoc_unlock != NULL ) liballoc_unlock();
if ( real_size > size ) real_size = size;
ptr = malloc( size );
liballoc_memcpy( ptr, p, real_size );
free( p );
return ptr;
}
+48 -53
View File
@@ -1,62 +1,71 @@
#include "../include/paging.h"
#include <stdint.h>
#include "../include/stdio.h"
#define PAGE_SIZE 0x1000 // 4 КБ
// Общий размер памяти
#define MEMORY_SIZE 0x100000000 // 4 ГБ
// Количество страниц
#define PAGE_COUNT (MEMORY_SIZE / PAGE_SIZE) // 1 048 576 страниц
// Размер битмапа в байтах (округлено вверх)
#define BITMAP_SIZE (PAGE_COUNT / 8) // 131 072 байт
#include "../include/string.h"
// Битмап для отслеживания страниц
// Каждый бит представляет одну страницу: 0 = свободна, 1 = занята
uint8_t page_bitmap[BITMAP_SIZE];
int is_page_in_use(uint32_t page_index) {
if (page_index >= PAGE_COUNT) {
return 0; // Out of range is considered "not in use by our allocator"
}
uint32_t byte_index = page_index / 8;
uint8_t bit_offset = page_index % 8;
return (page_bitmap[byte_index] & (1 << bit_offset));
}
// Установить бит (пометить страницу как занятую)
void set_bit(uint32_t page_index) {
uint32_t byte_index = page_index / 8; // Номер байта в битовой карте
uint8_t bit_offset = page_index % 8; // Смещение бита в байте
page_bitmap[byte_index] |= (1 << bit_offset); // Устанавливаем бит
}
// Сбросить бит (пометить страницу как свободную)
void clear_bit(uint32_t page_index) {
if (page_index >= PAGE_COUNT) {
printf("clear_bit: address %X out of range\n", page_index);
return;
}
if (!is_page_in_use(page_index)) {
//printf("clear_bit: warning, page #0x%X was already free.\n", page_index);
return;
}
uint32_t byte_index = page_index / 8;
uint8_t bit_offset = page_index % 8;
page_bitmap[byte_index] &= ~(1 << bit_offset); // Сбрасываем бит
}
// Инициализация аллокатора страниц
void init_allocator() {
int i;
// Помечаем все страницы как свободные (0)
for (i = 0; i < BITMAP_SIZE; i++) {
page_bitmap[i] = 0;
}
// Резервируем первые 4 МБ для ядра (0x00000000-0x003FFFFF)
// Это 1024 страницы или 128 байт битмапа
for (i = 0; i < 1024 / 8; i++) {
page_bitmap[i] = 0xFF; // Все биты = 1 (занято)
}
// Если вы используете higher-half kernel, то нужно также
// зарезервировать соответствующую область в верхней части памяти
// Например, если ядро отображено начиная с 0xC0000000 (3 ГБ):
uint32_t kernel_higher_start = 0xC0000000 / PAGE_SIZE / 8; // Индекс в битмапе
for (i = kernel_higher_start; i < kernel_higher_start + 1024 / 8; i++) {
page_bitmap[i] = 0xFF;
}
memset(page_bitmap, 0xFF, BITMAP_SIZE);
}
void* alloc_page() {
asm volatile("cli");
int i, j;
// Проходим по всему битмапу
for (i = 0; i < BITMAP_SIZE; i++) {
if (page_bitmap[i] != 0xFF) { // Если в этом байте есть свободная страница
//printf("!!!free page at 0x%X!!!\n", i);
for (j = 0; j < 8; j++) {
if (!(page_bitmap[i] & (1 << j))) { // Если этот бит = 0 (свободен)
page_bitmap[i] |= (1 << j); // Помечаем как занятый
// Вычисляем физический адрес страницы
uint32_t page_num = i * 8 + j;
void* addr = (void*)(page_num * PAGE_SIZE);
printf("allocated page at 0x%X (page #0x%X)\n", addr, page_num);
if(page_num == 0)
continue;
//debug_log("allocating page %X\n", page_num * PAGE_SIZE);
page_bitmap[i] |= (1 << j); // Помечаем как занятый
asm volatile("sti");
return (void*)(page_num * PAGE_SIZE);
}
}
@@ -64,6 +73,7 @@ void* alloc_page() {
}
printf("no bitches? no free pages?\n");
asm volatile("sti");
return (void*)0; // Нет свободных страниц
}
@@ -79,22 +89,7 @@ void free_page(void* physaddr) {
// Вычисляем номер страницы
uint32_t page_num = addr / PAGE_SIZE;
// Проверка границ
if (page_num >= PAGE_COUNT) {
printf("free_page: address out of range\n");
return;
}
// Вычисляем индекс байта и бита в битмапе
uint32_t byte_idx = page_num / 8;
uint32_t bit_idx = page_num % 8;
// Проверяем, не освобождаем ли уже свободную страницу
if (!(page_bitmap[byte_idx] & (1 << bit_idx))) {
printf("free_page: page already free\n");
return;
}
// Освобождаем страницу
page_bitmap[byte_idx] &= ~(1 << bit_idx);
asm volatile("cli");
clear_bit(page_num);
asm volatile("sti");
}
+134 -76
View File
@@ -1,24 +1,20 @@
#include "../include/paging.h"
#include <stdint.h>
#include "../include/string.h"
static uint32_t next_user_virt = 0x00400000;
void* setup_user_process(void* user_code_phys, uint32_t* user_stack_top) {
void* stack_phys = alloc_page();
if (!stack_phys) return 0;
uint32_t get_pte(void *virtualaddr) {
uint32_t pdindex = (uint32_t)virtualaddr >> 22;
uint32_t ptindex = (uint32_t)virtualaddr >> 12 & 0x3FF;
uint32_t *pd = (uint32_t *)0xFFFFF000;
uint32_t code_virt = next_user_virt;
uint32_t stack_virt = code_virt + 0x3FF000; // 4 МБ - 4 КБ
map_page(user_code_phys, (void*)code_virt, 0x7);
map_page(stack_phys, (void*)stack_virt, 0x7);
*user_stack_top = stack_virt + 0x1000;
next_user_virt += 0x400000; // Следующий 4 МБ блок
return (void*)code_virt;
if (!(pd[pdindex] & 0x1)) {
printf("GET_PTE ERROR: PT not present\n");
return 0;
}
void free_user_process(void* code_phys, void* stack_phys) {
free_page(code_phys);
free_page(stack_phys);
uint32_t *pt = (uint32_t*)(0xFFC00000 + (pdindex << 12));
return pt[ptindex];
}
void *get_physaddr(void *virtualaddr) {
@@ -26,83 +22,145 @@ void *get_physaddr(void *virtualaddr) {
unsigned long ptindex = (unsigned long)virtualaddr >> 12 & 0x03FF;
unsigned long *pd = (unsigned long *)0xFFFFF000;
// Here you need to check whether the PD entry is present.
if(!(pd[pdindex] & PAGE_PRESENT))
{
debug_log("get_physaddr: no PD (virt address is %X)\n", virtualaddr);
return NULL;
}
unsigned long *pt = ((unsigned long *)0xFFC00000) + (0x400 * pdindex);
// Here you need to check whether the PT entry is present.
uint32_t *pt = (uint32_t*)(0xFFC00000 + (pdindex << 12));
if(!(pt[ptindex] & PAGE_PRESENT))
{
debug_log("get_physaddr: no PT (virt address is %X)\n", virtualaddr);
return NULL;
}
return (void *)((pt[ptindex] & ~0xFFF) + ((unsigned long)virtualaddr & 0xFFF));
}
void map_page(void *physaddr, void *virtualaddr, unsigned int flags) {
// Убеждаемся, что адреса выровнены по 4 КБ
uint32_t phys = (uint32_t)physaddr & ~0xFFF; // Обнуляем младшие 12 бит
uint32_t virt = (uint32_t)virtualaddr & ~0xFFF;
// Вычисляем индексы
uint32_t pdindex = virt >> 22; // Индекс в каталоге страниц
uint32_t ptindex = (virt >> 12) & 0x3FF; // Индекс в таблице страниц
uint32_t *pd = (uint32_t *)0xFFFFF000; // Адрес каталога страниц в виртуальной памяти
// Проверяем, существует ли таблица страниц
if (!(pd[pdindex] & 0x1)) { // Бит 0 — "present"
// Если таблицы нет, создаём новую
void *new_pt = alloc_page();
if (!new_pt) while (1); // Нет памяти
pd[pdindex] = (uint32_t)new_pt | 0x3; // present, writable
// Очищаем новую таблицу
uint32_t *pt = ((uint32_t *)0xFFC00000) + (0x400 * pdindex);
for (int i = 0; i < 1024; i++) {
pt[i] = 0; // Все страницы "не присутствуют"
}
// Make sure that both addresses are page-aligned.
if ((unsigned long)physaddr & 0xFFF || (unsigned long)virtualaddr & 0xFFF) {
// Error handling: addresses not page-aligned
printf("MAP_PAGE ERROR: address not page-aligned\n");
return;
}
// Получаем адрес таблицы страниц
uint32_t *pt = ((uint32_t *)0xFFC00000) + (0x400 * pdindex);
// Устанавливаем отображение
pt[ptindex] = phys | (flags & 0xFFF) | 0x1; // Флаги + present
unsigned long pdindex = (unsigned long)virtualaddr >> 22;
unsigned long ptindex = (unsigned long)virtualaddr >> 12 & 0x03FF;
// Сбрасываем TLB для этого адреса
unsigned long *pd = (unsigned long *)0xFFFFF000;
// Here you need to check whether the PD entry is present.
// When it is not present, you need to create a new empty PT and
// adjust the PDE accordingly.
if (!(pd[pdindex] & 0x1)) { // If PDE not present
void *new_pt_phys = alloc_page();
if (!new_pt_phys) {
printf("failed to allocate a new page table\n");
return;
}
unsigned int pde_flags = PAGE_PRESENT | PAGE_RW;
if (flags & PAGE_USER) {
pde_flags |= PAGE_USER;
}
pd[pdindex] = (unsigned long)new_pt_phys | pde_flags;
uint32_t *pt_virt = (uint32_t*)(0xFFC00000 + (pdindex << 12));
asm volatile("invlpg (%0)" : : "r" (pt_virt) : "memory");
memset(pt_virt, 0, 4096);
}
uint32_t *pt = (uint32_t*)(0xFFC00000 + (pdindex << 12));
// Here you need to check whether the PT entry is present.
// When it is, then there is already a mapping present. What do you do now?
if(pt[ptindex] & 0x1)
{
printf("this page 0x%X is already mapped\n", virtualaddr);
}
pt[ptindex] = ((unsigned long)physaddr) | (flags & 0xFFF); // Present
// Now you need to flush the entry in the TLB
// or you might not notice the change.
asm volatile("invlpg (%0)" : : "r" (virtualaddr) : "memory");
}
void map_kernel_page(void* virtualaddr, unsigned int flags) {
uint32_t virt = (uint32_t)virtualaddr & ~0xFFF; // Выравниваем по 4 КБ
if (virt < 0xC0000000) while(1); // Ошибка: ядро только выше 3 ГБ
void unmap_page(void *virtualaddr) {
// Calculate page directory and page table indices
unsigned long pdindex = (unsigned long)virtualaddr >> 22;
unsigned long ptindex = (unsigned long)virtualaddr >> 12 & 0x03FF;
uint32_t pdindex = virt >> 22; // Индекс в каталоге
uint32_t ptindex = (virt >> 12) & 0x3FF; // Индекс в таблице страниц
// Get the page directory
unsigned long *pd = (unsigned long *)0xFFFFF000;
uint32_t* pd = (uint32_t*)0xFFFFF000; // Каталог страниц
if (pd[pdindex] & 0x1) { // Check if the page directory entry is present
// Get the page table
unsigned long *pt = (unsigned long *)(0xFFC00000 + (pdindex << 12));
// Проверяем, существует ли таблица страниц
if (!(pd[pdindex] & 0x1)) {
void* new_pt = alloc_page();
if (!new_pt) while(1); // Нет памяти
// Clear the page table entry (remove the mapping)
pt[ptindex] = 0;
// Убеждаемся, что адрес выровнен
if ((uint32_t)new_pt & 0xFFF) while(1); // Ошибка выравнивания
pd[pdindex] = ((uint32_t)new_pt) | 0x3; // Временно записываем в каталог
asm volatile("invlpg (%0)" : : "r" ((uint32_t)&pd[pdindex]) : "memory"); // Инвалидируем TLB
uint32_t* pt = ((uint32_t*)0xFFC00000) + (0x400 * pdindex);
for (int i = 0; i < 1024; i++) {
pt[i] = 0;
}
}
// Получаем таблицу страниц
uint32_t* pt = ((uint32_t*)0xFFC00000) + (0x400 * pdindex);
void* phys = alloc_page();
if (!phys) while(1);
// Проверяем, не занята ли страница
if (pt[ptindex] & 0x1) while(1); // Ошибка: страница уже отображена
pt[ptindex] = (uint32_t)phys | (flags & 0xFFF) | 0x1; // supervisor, present
// Invalidate the TLB entry for this virtual address
asm volatile("invlpg (%0)" : : "r" (virtualaddr) : "memory");
}
}
/**
* Maps a physical page to a virtual address in a SPECIFIED page directory.
* pd_virt_addr: Kernel virtual address of the target page directory table.
* phys_addr: Physical address of the page to map.
* virt_addr: Virtual address to map to.
* flags: PTE flags (e.g., PAGE_PRESENT | PAGE_USER | PAGE_RW).
* Returns 0 on success, -1 on failure.
*/
int map_page_in_directory(uint32_t* pd_virt_addr, void* phys_addr, void* virt_addr, uint32_t flags) {
uint32_t pde_idx = (uint32_t)virt_addr >> 22;
uint32_t pte_idx = ((uint32_t)virt_addr >> 12) & 0x3FF;
uint32_t pde = pd_virt_addr[pde_idx];
uint32_t* pt_virt_for_modification; // Virtual address of the page table to write PTEs into
if (!(pde & PAGE_PRESENT)) {
// Page table not present, need to allocate one
void* pt_phys_addr = alloc_page();
if (!pt_phys_addr) {
printf("map_page_in_directory: alloc_page failed for new page table (VA: %x)\n", (uint32_t)virt_addr);
return -1;
}
// Get a kernel virtual address for this new page table to initialize it
pt_virt_for_modification = (uint32_t*)phys_to_virt((uint32_t)pt_phys_addr);
// Temporarily map this new PT page into the *current* address space to zero it.
// This assumes map_page modifies the current CR3's address space.
map_page(pt_phys_addr, (void*)pt_virt_for_modification, PAGE_PRESENT | PAGE_RW);
memset(pt_virt_for_modification, 0, PAGE_SIZE);
// Now, point the PDE in the target page directory (pd_virt_addr) to the new page table.
// The PDE stores the PHYSICAL address of the page table.
pd_virt_addr[pde_idx] = (uint32_t)pt_phys_addr | PAGE_PRESENT | PAGE_RW | PAGE_USER; // Ensure PAGE_USER if PTEs will have USER bit
// Note: If map_page for the PT itself isn't needed long-term in current PD, you might unmap it.
// However, if phys_to_virt gives a stable kernel mapping, this explicit map/unmap might be simplified.
} else {
// Page table already exists. Get its physical address from PDE, then its kernel virtual address.
pt_virt_for_modification = (uint32_t*)phys_to_virt(pde & ~0xFFF);
// This assumes that any existing page table pointed to by a PDE is already
// accessible via its phys_to_virt address for modification.
}
// Set the PTE entry in this page table
// Ensure phys_addr is page-aligned; flags should not include low 12 bits of phys_addr
pt_virt_for_modification[pte_idx] = ((uint32_t)phys_addr & ~0xFFF) | (flags & 0xFFF);
// When CR3 for the target task is loaded, TLB entries for virt_addr will be appropriately managed.
// If virt_addr was previously mapped by another process using this same PD (unlikely for new tasks),
// more complex TLB invalidation might be needed, but typically not for initial setup.
// invlpg may be needed here if you are re-mapping an address in a PD already in use by another CPU or
// if the PD is the current CR3 and the mapping changes. For setting up a new PD not yet in CR3, it's usually fine.
return 0; // Success
}
+268 -80
View File
@@ -1,88 +1,276 @@
#include "../include/paging.h"
#include <stdint.h>
#include "../include/string.h"
#include "../include/kheap.h"
#include "../include/liballoc.h"
uint32_t kernel_page_directory[1024] __attribute__((aligned(4096)));
uint32_t kernel_page_table[1024] __attribute__((aligned(4096)));
uint32_t user_page_table[1024] __attribute__((aligned(4096)));
uint32_t *kpage_dir;
uint32_t setup_tmp_pgdir(uint32_t magic, uint32_t info)
{
int n, pd;
uint32_t pagedir_address, memksize;
uint32_t *page_table;
struct multiboot_info *mbi;
void enablePaging() {
asm volatile (
"mov %%cr0, %%eax\n"
"or $0x80000000, %%eax\n"
"mov %%eax, %%cr0\n"
"jmp 1f\n"
"1:\n"
"mov %%cr3, %%eax\n" // Перезагрузка CR3 для сброса TLB
"mov %%eax, %%cr3\n"
"nop\n"
:
:
: "eax", "memory"
);
}
void loadPageDirectory(uint32_t* page_directory) {
asm volatile (
"mov %0, %%cr3\n" // Загружаем физический адрес каталога страниц в CR3
: // Нет выходных операндов
: "r" (page_directory) // Входной операнд — адрес каталога
: // Нет изменяемых регистров
);
}
void paging_init() {
int i;
// Проверяем физические адреса
uint32_t pd_phys = (uint32_t)kernel_page_directory;
uint32_t pt_phys = (uint32_t)kernel_page_table;
uint32_t user_pt_phys = (uint32_t)user_page_table;
if (pd_phys & 0xFFF || pt_phys & 0xFFF || user_pt_phys & 0xFFF) {
while (1); // Ошибка выравнивания
}
// Заполняем каталог страниц
for (i = 0; i < 1024; i++) {
kernel_page_directory[i] = 0x00000002; // not present
}
// Identity mapping для 0x000000000x003FFFFF
for (i = 0; i < 1024; i++) {
kernel_page_table[i] = (i * 0x1000) | 0x3; // supervisor, present
}
kernel_page_directory[0] = pt_phys | 0x3;
// Ring 3: 0x004000000x007FFFFF, User-accessible
for (i = 0; i < 1024; i++) {
user_page_table[i] = 0; // Изначально не отображено
}
kernel_page_directory[1] = user_pt_phys | 0x7; // Present, R/W, User
// Рекурсивное отображение
kernel_page_directory[1023] = pd_phys | 0x3;
// Проверяем перед загрузкой
if (kernel_page_directory[0] != (pt_phys | 0x3) ||
kernel_page_directory[1023] != (pd_phys | 0x3)) {
printf("OSHIBKA ZAPISI BLYA\n");
while (1); // Ошибка записи
}
loadPageDirectory(kernel_page_directory);
enablePaging();
}
void test_paging() {
uint32_t* pd = (uint32_t*)0xFFFFF000;
uint32_t expected = (uint32_t)kernel_page_table | 0x3;
// Игнорируем дополнительные флаги, проверяем только базовый адрес и present
if ((pd[0] & ~0xFFF) == (expected & ~0xFFF)) {
// Успех
if(magic != MULTIBOOT_BOOTLOADER_MAGIC) {
memksize = 4096;
} else {
printf("RECURSION BROKEN!!\n");
printf("pd[0] = 0x%X\n");
printf("(uint32_t)first_page_table | 0x3 = %X", (uint32_t)kernel_page_table | 0x3);
while (1); // Рекурсия сломана
mbi = (struct multiboot_info *)(PAGE_OFFSET + info);
if(!(mbi->flags & MULTIBOOT_INFO_MEMORY)) {
memksize = 4096;
} else {
memksize = (uint32_t)mbi->mem_upper + 1024;
if(memksize > ((0xFFFFFFFF - PAGE_OFFSET) / 1024)) {
memksize = (0xFFFFFFFF - PAGE_OFFSET) / 1024;
}
}
}
/* Address is PAGE_OFFSET plus memory size minus 4KB */
pagedir_address = PAGE_OFFSET + (memksize * 1024) - memksize;
pagedir_address = PAGE_ALIGN(pagedir_address);
kpage_dir = (uint32_t *)pagedir_address;
memset(kpage_dir, 0, PAGE_SIZE);
pagedir_address += PAGE_SIZE;
page_table = (uint32_t *)pagedir_address;
memset(page_table, 0, memksize);
for(n = 0; n < memksize / sizeof(uint32_t); n++) {
page_table[n] = (n << PAGE_SHIFT) | PAGE_PRESENT | PAGE_RW;
if(!(n % 1024)) {
pd = n / 1024;
kpage_dir[pd] = (unsigned int)(pagedir_address + (PAGE_SIZE * pd) + GDT_BASE) | PAGE_PRESENT | PAGE_RW;
kpage_dir[GET_PGDIR(PAGE_OFFSET) + pd] = (unsigned int)(pagedir_address + (PAGE_SIZE * pd) + GDT_BASE) | PAGE_PRESENT | PAGE_RW;
}
}
uint32_t pd_phys = (uint32_t)kpage_dir - PAGE_OFFSET;
kpage_dir[1023] = pd_phys | PAGE_PRESENT | PAGE_RW; // Recursive mapping
return (uint32_t)kpage_dir - PAGE_OFFSET;
}
void grub_memory_map(unsigned int magic, struct multiboot_info* mbi)
{
/* Check bit 6 to see if we have a valid memory map */
if(!(mbi->flags >> 6 & 0x1)) {
printf("invalid memory map given by GRUB bootloader\n");
while(1){}
}
/* Loop through the memory map and display the values */
int i;
for(i = 0; i < mbi->mmap_length;
i += sizeof(multiboot_memory_map_t))
{
multiboot_memory_map_t* mmmt =
(multiboot_memory_map_t*) (mbi->mmap_addr + i);
printf("Start Addr: %x | Length: %x | Size: %x | Type: %x\n",
mmmt->addr_low, mmmt->len_low, mmmt->size, mmmt->type);
if(mmmt->type == MULTIBOOT_MEMORY_AVAILABLE) {
/*
* Do something with this memory block!
* BE WARNED that some of memory shown as availiable is actually
* actively being used by the kernel! You'll need to take that
* into account before writing to memory!
*/
printf("available\n");
uint32_t size_in_pages = mmmt->len_low / PAGE_SIZE;
printf("size_in_pages: 0x%X\n", size_in_pages);
uint32_t base_page = mmmt->addr_low / PAGE_SIZE;
uint32_t page_count = mmmt->len_low / PAGE_SIZE;
printf("page_base: %X, page_count: %X\n", base_page, page_count);
for (uint32_t j = 0; j < page_count; j++) {
// Only clear the bit if it fits in our bitmap
if ((base_page + j) < (BITMAP_SIZE * 8)) {
clear_bit(base_page + j);
}
}
}
}
extern uint32_t _start, _end; // From linker script
uint32_t kernel_start_phys = (uint32_t)&_start - 0xC0000000;
uint32_t kernel_end_phys = (uint32_t)&_end - 0xC0000000;
uint32_t kernel_start_page = kernel_start_phys / PAGE_SIZE;
uint32_t kernel_end_page = (kernel_end_phys + PAGE_SIZE - 1) / PAGE_SIZE;
printf("Kernel phys range: 0x%X to 0x%X, pages: 0x%X to 0x%X\n",
kernel_start_phys, kernel_end_phys, kernel_start_page, kernel_end_page);
for (uint32_t i = kernel_start_page; i < kernel_end_page; i++) {
if (i < BITMAP_SIZE) {
set_bit(i);
} else {
printf("Bitmap overflow at kernel page %u\n", i);
}
}
}
uint32_t* get_page_dir()
{
uint32_t cr3_value;
asm volatile("mov %%cr3, %0" : "=r" (cr3_value));
return (uint32_t*) cr3_value;
}
void set_page_dir(uint32_t new_page_dir) {
asm volatile("mov %0, %%cr3" : : "r" (new_page_dir));
}
uint32_t phys_to_virt(uint32_t phys)
{
return phys+0xC0000000;
}
void* phys_to_virt2(void* phys)
{
return phys+0xC0000000;
}
uint32_t* create_page_dir()
{
void* ppp = alloc_page();
if (!ppp) {
debug_log("create_page_dir: alloc_page returned NULL\n");
return NULL;
}
uint32_t* new_pd = (uint32_t*)phys_to_virt((uint32_t)ppp);
memset(new_pd, 0, 0x1000);
uint32_t* current_pd = (uint32_t*)0xFFFFF000; // Current PD (self-mapped)
for(int i = 768; i < 1024; i++)
{
if(current_pd[i] & PAGE_PRESENT) {
new_pd[i] = current_pd[i];
}
}
int vga_pde_index = 0; // Virtual address 0x000B8000 is covered by PDE[0]
if (current_pd[vga_pde_index] & PAGE_PRESENT) {
new_pd[vga_pde_index] = current_pd[vga_pde_index];
}
new_pd[1023] = (uint32_t)ppp | 0x03; // Present + Read/Write
return new_pd;
}
void destroy_page_dir(uint32_t* page_dir_virt) {
if (page_dir_virt == NULL) {
return;
}
// Iterate through user-space page directory entries (PDEs 0-767).
// Kernel space (768+) is shared and should not be freed.
for (int i = 1; i < 768; i++) {
uint32_t pde = page_dir_virt[i];
// Check if the page directory entry is present
if (pde & PAGE_PRESENT) {
// Get the physical address of the page table
uint32_t pt_phys = pde & ~0xFFF;
if(is_page_in_use(pt_phys / PAGE_SIZE)){
// Convert it to a virtual address the kernel can access
uint32_t* page_table_virt = (uint32_t*)phys_to_virt(pt_phys);
// Iterate through all 1024 entries in this page table
for (int j = 0; j < 1024; j++) {
uint32_t pte = page_table_virt[j];
// If the page table entry is present, free the physical page (frame) it points to
if (pte & PAGE_PRESENT) {
//debug_log("freeing page %X\n", pte);
free_page((void*)(pte & ~0xFFF));
}
}
// After freeing all pages within the table, free the page table itself
free_page((void*)pt_phys);
}
}
}
// Finally, free the page directory itself.
// We need its physical address to pass to the physical memory manager.
debug_log("freeing PD page %X\n", virt_to_phys(page_dir_virt));
free_page((void*)virt_to_phys(page_dir_virt));
}
static void* scratch_src = (void*)0xE1000000;
static void* scratch_dst = (void*)0xE1001000;
uint32_t* copy_page_dir(uint32_t* page_dir_virt)
{
if(page_dir_virt == NULL)
return 0;
debug_log("====%X %X\n", scratch_dst, scratch_src);
uint32_t* new_pagedir = create_page_dir();
for(int i = 1; i < 768; i++)
{
uint32_t pde = page_dir_virt[i];
if(pde & PAGE_PRESENT)
{
debug_log("PDE %X present\n", pde);
uint32_t* new_page_table = (uint32_t*)alloc_page();
if(new_page_table == NULL) {
return NULL;
}
uint32_t* new_page_table_virt = (uint32_t*)phys_to_virt((uint32_t)new_page_table);
// Get original page table (physical address from PDE)
uint32_t* orig_page_table = (uint32_t*)phys_to_virt(pde & ~0xFFF);
for(int j = 0; j < 1024; j++)
{
uint32_t pte = orig_page_table[j];
if(pte & PAGE_PRESENT)
{
void* new_phys_page = alloc_page();
if(!new_phys_page)
{
return NULL;
}
void* orig_phys_page = (void*)(pte & ~0xFFF);
map_page(orig_phys_page, scratch_src, PAGE_PRESENT | PAGE_RW);
map_page(new_phys_page, scratch_dst, PAGE_PRESENT | PAGE_RW);
memcpy(scratch_dst, scratch_src, PAGE_SIZE);
unmap_page(scratch_dst);
unmap_page(scratch_src);
new_page_table_virt[j] = (uint32_t)new_phys_page | (pte & 0xFFF);
}
else
{
new_page_table_virt[j] = pte;
}
}
// Set the new PDE in the child's page directory
new_pagedir[i] = (uint32_t)new_page_table | (pde & 0xFFF);
}
else
{
new_pagedir[i] = pde;
}
}
debug_log("ENDENDENDEND\n");
return new_pagedir;
}
-503
View File
@@ -1,503 +0,0 @@
#include "../include/paging.h"
#include <stdint.h>
#include "../include/stdio.h"
void enablePaging() {
asm volatile (
"mov %%cr0, %%eax\n"
"or $0x80000000, %%eax\n"
"mov %%eax, %%cr0\n"
"jmp 1f\n"
"1:\n"
"mov %%cr3, %%eax\n" // Перезагрузка CR3 для сброса TLB
"mov %%eax, %%cr3\n"
"nop\n"
:
:
: "eax", "memory"
);
}
void loadPageDirectory(uint32_t* page_directory) {
asm volatile (
"mov %0, %%cr3\n" // Загружаем физический адрес каталога страниц в CR3
: // Нет выходных операндов
: "r" (page_directory) // Входной операнд — адрес каталога
: // Нет изменяемых регистров
);
}
uint32_t kernel_page_directory[1024] __attribute__((aligned(4096)));
uint32_t kernel_page_table[1024] __attribute__((aligned(4096)));
// 16 МБ = 16 * 1024 * 1024 байт = 4096 страниц (по 4 КБ)
// 4096 бит = 512 байт
uint8_t page_bitmap[512]; // 1 бит на страницу
/**
page_bitmap — массив, где каждый бит соответствует странице (0 = свободна, 1 = занята).
init_allocator помечает первые 4 МБ как занятые (там ядро).
alloc_page ищет первый свободный бит и возвращает адрес страницы.
free_page освобождает страницу, сбрасывая бит.
**/
void init_allocator() {
int i;
// Помечаем все страницы как свободные (0)
for (i = 0; i < 512; i++) {
page_bitmap[i] = 0;
}
// Первые 4 МБ уже заняты ядром (0x000000000x003FFFFF)
for (i = 0; i < 1024 / 8; i++) { // 1024 страницы = 128 байт
page_bitmap[i] = 0xFF; // Все биты = 1 (занято)
}
}
// Выделяем свободную страницу
void* alloc_page() {
// printf("alloc_page called\n");
int i, j;
for (i = 0; i < 512; i++) {
if (page_bitmap[i] != 0xFF) {
for (j = 0; j < 8; j++) {
if (!(page_bitmap[i] & (1 << j))) {
page_bitmap[i] |= (1 << j);
return (void*)(((i * 8) + j) * 0x1000);
}
}
}
}
printf("no bitches? no free pages?\n");
return (void*)0; // Нет свободных страниц
}
void test_paging() {
uint32_t* pd = (uint32_t*)0xFFFFF000;
uint32_t expected = (uint32_t)kernel_page_table | 0x3;
// Игнорируем дополнительные флаги, проверяем только базовый адрес и present
if ((pd[0] & ~0xFFF) == (expected & ~0xFFF)) {
// Успех
} else {
printf("RECURSION BROKEN!!\n");
printf("pd[0] = 0x%X\n");
printf("(uint32_t)first_page_table | 0x3 = %X", (uint32_t)kernel_page_table | 0x3);
while (1); // Рекурсия сломана
}
}
// Освобождаем страницу
void free_page(void *physaddr) {
uint32_t page_num = (uint32_t)physaddr / 0x1000;
uint32_t byte_idx = page_num / 8;
uint32_t bit_idx = page_num % 8;
page_bitmap[byte_idx] &= ~(1 << bit_idx); // Сбрасываем бит
}
/**
Теперь первые 4 МБ физической памяти отображаются на виртуальный адрес 0xC0000000 (3 ГБ), а не на 0x00000000.
Это оставляет нижние 3 ГБ (0x000000000xBFFFFFFF) свободными для пользовательских процессов.
**/
void paging_init()
{
int i;
// Проверяем физические адреса
uint32_t pd_phys = (uint32_t)kernel_page_directory;
uint32_t pt_phys = (uint32_t)kernel_page_table;
if (pd_phys & 0xFFF || pt_phys & 0xFFF) {
while (1); // Ошибка выравнивания
}
// Заполняем каталог страниц
for (i = 0; i < 1024; i++) {
kernel_page_directory[i] = 0x00000002; // not present
}
// Identity mapping для 0x000000000x003FFFFF
for (i = 0; i < 1024; i++) {
kernel_page_table[i] = (i * 0x1000) | 0x3; // supervisor, present
}
kernel_page_directory[0] = pt_phys | 0x3;
// Рекурсивное отображение
kernel_page_directory[1023] = pd_phys | 0x3;
// Проверяем перед загрузкой
if (kernel_page_directory[0] != (pt_phys | 0x3) ||
kernel_page_directory[1023] != (pd_phys | 0x3)) {
printf("OSHIBKA ZAPISI BLYA\n");
while (1); // Ошибка записи
}
loadPageDirectory(kernel_page_directory);
enablePaging();
}
void *get_physaddr(void *virtualaddr) {
unsigned long pdindex = (unsigned long)virtualaddr >> 22;
unsigned long ptindex = (unsigned long)virtualaddr >> 12 & 0x03FF;
unsigned long *pd = (unsigned long *)0xFFFFF000;
// Here you need to check whether the PD entry is present.
unsigned long *pt = ((unsigned long *)0xFFC00000) + (0x400 * pdindex);
// Here you need to check whether the PT entry is present.
return (void *)((pt[ptindex] & ~0xFFF) + ((unsigned long)virtualaddr & 0xFFF));
}
/**
Проверяем, существует ли таблица страниц (бит present в записи каталога).
Используем invlpg (inline assembly) для сброса TLB, чтобы процессор увидел изменения.
Пока вместо выделения новой таблицы страниц я добавил бесконечный цикл (while(1)). Позже мы заменим это аллокатором.
**/
void map_page(void *physaddr, void *virtualaddr, unsigned int flags) {
// Убеждаемся, что адреса выровнены по 4 КБ
uint32_t phys = (uint32_t)physaddr & ~0xFFF; // Обнуляем младшие 12 бит
uint32_t virt = (uint32_t)virtualaddr & ~0xFFF;
// Вычисляем индексы
uint32_t pdindex = virt >> 22; // Индекс в каталоге страниц
uint32_t ptindex = (virt >> 12) & 0x3FF; // Индекс в таблице страниц
uint32_t *pd = (uint32_t *)0xFFFFF000; // Адрес каталога страниц в виртуальной памяти
// Проверяем, существует ли таблица страниц
if (!(pd[pdindex] & 0x1)) { // Бит 0 — "present"
// Если таблицы нет, создаём новую (для простоты пока паникуем)
void *new_pt = alloc_page();
if (!new_pt) while (1); // Нет памяти
pd[pdindex] = (uint32_t)new_pt | 0x3; // present, writable
// Очищаем новую таблицу
uint32_t *pt = ((uint32_t *)0xFFC00000) + (0x400 * pdindex);
for (int i = 0; i < 1024; i++) {
pt[i] = 0; // Все страницы "не присутствуют"
}
}
// Получаем адрес таблицы страниц
uint32_t *pt = ((uint32_t *)0xFFC00000) + (0x400 * pdindex);
// Устанавливаем отображение
pt[ptindex] = phys | (flags & 0xFFF) | 0x1; // Флаги + present
// Сбрасываем TLB для этого адреса
asm volatile("invlpg (%0)" : : "r" (virtualaddr) : "memory");
}
//map_kernel_page((void*)0xC0100000, 0x2); — отобразит страницу в ядре.
void map_kernel_page(void* virtualaddr, unsigned int flags) {
uint32_t virt = (uint32_t)virtualaddr & ~0xFFF; // Выравниваем по 4 КБ
if (virt < 0xC0000000) while(1); // Ошибка: ядро только выше 3 ГБ
uint32_t pdindex = virt >> 22; // Индекс в каталоге
uint32_t ptindex = (virt >> 12) & 0x3FF; // Индекс в таблице страниц
uint32_t* pd = (uint32_t*)0xFFFFF000; // Каталог страниц
// Проверяем, существует ли таблица страниц
if (!(pd[pdindex] & 0x1)) {
void* new_pt = alloc_page();
if (!new_pt) while(1); // Нет памяти
// Убеждаемся, что адрес выровнен (опционально, если alloc_page() не гарантирует)
if ((uint32_t)new_pt & 0xFFF) while(1); // Ошибка выравнивания
pd[pdindex] = ((uint32_t)new_pt) | 0x3; // Временно записываем в каталог
asm volatile("invlpg (%0)" : : "r" ((uint32_t)&pd[pdindex]) : "memory"); // Инвалидируем TLB
uint32_t* pt = ((uint32_t*)0xFFC00000) + (0x400 * pdindex);
for (int i = 0; i < 1024; i++) {
pt[i] = 0;
}
}
// Получаем таблицу страниц
uint32_t* pt = ((uint32_t*)0xFFC00000) + (0x400 * pdindex);
void* phys = alloc_page();
if (!phys) while(1);
// Проверяем, не занята ли страница
if (pt[ptindex] & 0x1) while(1); // Ошибка: страница уже отображена
pt[ptindex] = (uint32_t)phys | (flags & 0xFFF) | 0x1; // supervisor, present
asm volatile("invlpg (%0)" : : "r" (virtualaddr) : "memory");
}
// Структура заголовка блока памяти
typedef struct Block {
uint32_t size; // Размер блока (в байтах, включая заголовок)
uint32_t is_free; // 1 = свободен, 0 = занят
struct Block* next; // Указатель на следующий блок
} Block;
// Структура для управления кучей
typedef struct {
void* start; // Начало кучи
uint32_t size; // Текущий размер кучи в байтах
Block* first; // Первый блок в куче
} Heap;
Heap kernel_heap;
void heap_init() {
kernel_heap.start = (void*)0xD0000000; // Начало кучи в ядре
kernel_heap.size = 0x1000; // Начальный размер — 1 страница (4 КБ)
printf("before map_kernel_page\n");
// Отображаем первую страницу
map_kernel_page(kernel_heap.start, 0x2); // writable, supervisor
printf("after map_kernel_page\n");
// Создаём первый блок, который занимает всю страницу
Block* initial_block = (Block*)kernel_heap.start;
initial_block->size = 0x1000 - sizeof(Block); // Размер без учёта заголовка
initial_block->is_free = 1; // Свободен
initial_block->next = (Block*)0; // Пока нет следующего
kernel_heap.first = initial_block;
}
// Выделение памяти из кучи
//Ищет свободный блок подходящего размера. Если блок большой, делит его.
//Если свободных блоков нет, добавляет страницу.
void* heap_alloc(uint32_t size) {
// Выравниваем размер до 4 байт
size = (size + 3) & ~3;
Block* current = kernel_heap.first;
Block* prev = (Block*)0;
// Ищем подходящий свободный блок
while (current) {
if (current->is_free && current->size >= size) {
if (current->size >= size + sizeof(Block) + 4) {
Block* new_block = (Block*)((uint32_t)current + sizeof(Block) + size);
new_block->size = current->size - size - sizeof(Block);
new_block->is_free = 1;
new_block->next = current->next;
current->size = size;
current->next = new_block;
}
current->is_free = 0;
return (void*)((uint32_t)current + sizeof(Block));
}
prev = current;
current = current->next;
}
// Нет подходящего блока — выделяем нужное количество страниц
uint32_t total_size = size + sizeof(Block); // Размер с заголовком
uint32_t pages_needed = (total_size + 0xFFF) / 0x1000; // Округляем вверх до страниц
uint32_t alloc_size = pages_needed * 0x1000; // Сколько байт выделяем
void* new_page = (void*)((uint32_t)kernel_heap.start + kernel_heap.size);
for (uint32_t i = 0; i < pages_needed; i++) {
map_kernel_page((void*)((uint32_t)new_page + i * 0x1000), 0x2);
}
kernel_heap.size += alloc_size;
Block* new_block = (Block*)new_page;
new_block->size = alloc_size - sizeof(Block);
new_block->is_free = 1;
new_block->next = (Block*)0;
if (prev) prev->next = new_block;
if (!kernel_heap.first) kernel_heap.first = new_block;
// Теперь current указывает на новый блок, продолжаем цикл
current = new_block;
if (current->size >= size) {
if (current->size >= size + sizeof(Block) + 4) {
Block* split_block = (Block*)((uint32_t)current + sizeof(Block) + size);
split_block->size = current->size - size - sizeof(Block);
split_block->is_free = 1;
split_block->next = current->next;
current->size = size;
current->next = split_block;
}
current->is_free = 0;
return (void*)((uint32_t)current + sizeof(Block));
}
// Если что-то пошло не так, возвращаем NULL
return (void*)0;
}
// Освобождение памяти
//Помечает блок как свободный и пытается объединить его с соседними свободными блоками,
//чтобы уменьшить фрагментацию.
void heap_free(void* ptr) {
if (!ptr || (uint32_t)ptr < (uint32_t)kernel_heap.start) return;
// Находим блок по указателю (указатель указывает после заголовка)
Block* block = (Block*)((uint32_t)ptr - sizeof(Block));
block->is_free = 1;
// Слияние с предыдущим блоком, если он свободен
Block* current = kernel_heap.first;
Block* prev = (Block*)0;
while (current && current != block) {
prev = current;
current = current->next;
}
if (prev && prev->is_free) {
prev->size += sizeof(Block) + block->size;
prev->next = block->next;
block = prev;
}
// Слияние с следующим блоком, если он свободен
if (block->next && block->next->is_free) {
block->size += sizeof(Block) + block->next->size;
block->next = block->next->next;
}
}
// Функция проверки страниц
void test_pages() {
// Тест 1: Проверка ядра
void* kernel_addr = (void*)0xC0100000;
map_kernel_page(kernel_addr, 0x2); // writable, supervisor
// Записываем значение в страницу
uint32_t* kernel_ptr = (uint32_t*)kernel_addr;
*kernel_ptr = 0xDEADBEEF;
// Проверяем, что значение записалось
if (*kernel_ptr == 0xDEADBEEF) {
// Успех! (в реальной ОС тут можно вывести сообщение через UART или VGA)
} else {
while (1); // Ошибка
}
/*
// Тест 2: Проверка пользовательского процесса
Process* proc = create_process(1); // Создаём процесс
void* user_addr = (void*)0x1000;
map_user_page(proc, user_addr, 0x6); // writable, user
// Переключаемся на процесс
switch_to_process(proc);
// Записываем значение
uint32_t* user_ptr = (uint32_t*)user_addr;
*user_ptr = 0xCAFEBABE;
// Проверяем
if (*user_ptr == 0xCAFEBABE) {
// Успех!
} else {
while (1); // Ошибка
}
// Возвращаемся в ядро
switch_to_process((Process*)0); // Предполагаем, что 0 вернёт нас к kernel_page_directory
*/
// Тест 3: Проверка кучи
heap_init();
void* heap_ptr1 = heap_alloc(16);
uint32_t* heap_data1 = (uint32_t*)heap_ptr1;
*heap_data1 = 0x12345678;
void* heap_ptr2 = heap_alloc(200);
uint32_t* heap_data2 = (uint32_t*)heap_ptr2;
*heap_data2 = 0x87654321;
heap_free(heap_ptr1);
void* heap_ptr3 = heap_alloc(12); // Должно взять место ptr1
if (*heap_data1 == 0x12345678 && *heap_data2 == 0x87654321 &&
heap_ptr3 == heap_ptr1) {
// Успех!
} else {
while (1); // Ошибка
}
}
/**
0xD0000000: Произвольный адрес в ядре (выше 0xC0000000), выбран для кучи, чтобы не пересекаться с другими данными.
0xFFFFF000: Виртуальный адрес каталога страниц благодаря рекурсивному отображению (последняя запись указывает на себя).
0xFFC00000: Начало области, где лежат все таблицы страниц, доступные через рекурсию.
**/
/**
Dalshe idyot to chto napisal grok dlya processov v buduschem
**/
/*
// Структура для процесса
typedef struct {
uint32_t page_directory[1024] __attribute__((aligned(4096))); // Каталог страниц процесса
uint32_t pid; // ID процесса (для примера)
} Process;
// Создание нового процесса
//Создаёт новый каталог страниц для процесса, копируя ядро (768–1023 записи) и оставляя нижние 3 ГБ пустыми.
Process* create_process(uint32_t pid) {
Process* proc = (Process*)alloc_page(); // Выделяем страницу под структуру
if (!proc) return (Process*)0; // Нет памяти
int i;
// Копируем каталог ядра в каталог процесса
for (i = 0; i < 1024; i++) {
proc->page_directory[i] = kernel_page_directory[i];
}
// Нижние 3 ГБ (0-767) изначально пустые
for (i = 0; i < 768; i++) {
proc->page_directory[i] = 0x00000002; // not present
}
proc->pid = pid;
return proc;
}
// Переключение на процесс
//Переключает процессор на каталог страниц процесса.
void switch_to_process(Process* proc) {
loadPageDirectory(proc->page_directory);
}
//Выделяет страницу в пользовательском пространстве (ниже 0xC0000000) с флагами user-level (бит 2 = 1).
void map_user_page(Process* proc, void* virtualaddr, unsigned int flags) {
uint32_t virt = (uint32_t)virtualaddr & ~0xFFF;
if (virt >= 0xC0000000) while(1); // Ошибка: пользователь не может трогать ядро!
uint32_t pdindex = virt >> 22;
uint32_t ptindex = (virt >> 12) & 0x3FF;
// Проверяем, есть ли таблица страниц
if (!(proc->page_directory[pdindex] & 0x1)) {
void* new_pt = alloc_page();
if (!new_pt) while(1); // Нет памяти
// Новая таблица: user, writable, present (0x7 = 111b)
proc->page_directory[pdindex] = ((uint32_t)new_pt) | 0x7;
// Очищаем таблицу
uint32_t* pt = (uint32_t*)new_pt;
for (int i = 0; i < 1024; i++) {
pt[i] = 0; // Все страницы "не присутствуют"
}
}
// Получаем таблицу страниц
uint32_t* pt = (uint32_t*)(proc->page_directory[pdindex] & ~0xFFF);
void* phys = alloc_page();
if (!phys) while(1); // Нет памяти
// Отображаем страницу: user, flags, present
pt[ptindex] = (uint32_t)phys | (flags & 0xFFF) | 0x5; // 0x5 = 101b (present, user)
// Сбрасываем TLB
asm volatile("invlpg (%0)" : : "r" (virtualaddr) : "memory");
}
// Пример использования
void test_process() {
Process* proc = create_process(1); // Создаём процесс с PID 1
map_user_page(proc, (void*)0x1000, 0x6); // Отображаем страницу на 0x1000 (writable, user)
switch_to_process(proc); // Переключаемся на процесс
}
*/
+167
View File
@@ -0,0 +1,167 @@
#include "../include/exec_from_file.h"
#include "../include/disk.h"
#include "../include/kheap.h"
#include "../include/liballoc.h"
#include "../include/string.h"
#include "../include/paging.h"
#include "../include/task.h"
void exec_from_file(l9660_file* fs_file, l9660_dir* dir)
{
asm volatile("cli");
int err;
uint8_t* file;
//l9660_dir dir;
l9660_status status;
//status = l9660_opendirat(&dir, root_dir, dirname);
//debug_log("l9660_opendirat status: 0x%X\n", status);
//list_files(&dir);
uint32_t bss_start, bss_end;
l9660_seek(fs_file, L9660_SEEK_END, 0);
uint32_t file_size = l9660_tell(fs_file);
debug_log("[exec_from_file] file_size: %X\n", file_size);
l9660_seek(fs_file, L9660_SEEK_SET, 0);
file = (uint8_t*)malloc(file_size);
//err = vsf_read_file_by_path(filename, &file, &dir);
err = vfs_read_file(fs_file, file);
/*if(err != 0)
{
return;
}
*/
//debug_log("result: %X\n", result);
//debug_log("buffer: %s\n", file);
Elf32_Ehdr *elf_ehdr = (Elf32_Ehdr*)file;
int program_header_table_entry_count = elf_ehdr->e_phnum;
//int program_header_table_entry_size = elf_ehdr->e_phentsize;
//debug_log("magic: %X, type: %X, entry: 0x%X\n", elf_ehdr->e_ident, elf_ehdr->e_type, elf_ehdr->e_entry);
//debug_log("PHNUM: %X\n", program_header_table_entry_count);
//debug_log("PHENTSIZE: %X\n\n", program_header_table_entry_size);
uint32_t* proc_pd = create_page_dir();
if (!proc_pd) {
printf("exec_from_file: create_page_dir failed\n");
free(file);
asm volatile("sti");
return;
}
uint32_t proc_pd_phys = (uint32_t)get_physaddr((void*)proc_pd);
debug_log("proc_pd_phys: 0x%X\n", proc_pd_phys);
uint32_t* curr_pd_virt = get_page_dir(); // CR3 содержит физический адрес, но get_page_dir возвращает его как uint32_t*
uint32_t curr_pd_phys = (uint32_t)curr_pd_virt; // Просто приводим к uint32_t, так как CR3 содержит физический адрес
set_page_dir(proc_pd_phys);
for(int i = 0; i < program_header_table_entry_count; i++)
{
Elf32_Phdr *elf_phdr = (Elf32_Phdr *)((uint32_t)file + elf_ehdr->e_phoff +
i * elf_ehdr->e_phentsize);
//debug_log("HEADER %X, type: 0x%X, vaddr: 0x%X, paddr: 0x%X, memsz: 0x%X\n", i, elf_phdr->p_type, elf_phdr->p_vaddr, elf_phdr->p_paddr, elf_phdr->p_memsz);
if(elf_phdr->p_type != PT_LOAD)
{
//debug_log("not PT_LOAD, skipping...\n");
continue;
}
uint32_t start_addr = elf_phdr->p_vaddr;
uint32_t end_addr = start_addr + elf_phdr->p_memsz;
uint32_t start_page = start_addr & ~0xFFF;
uint32_t end_page = (end_addr - 1) & ~0xFFF;
int pages_needed = ((end_page - start_page) / 0x1000) + 1;
//int pages_needed = DivRoundUp(elf_phdr->p_memsz, 0x1000);//(elf_phdr->p_memsz / 0x1000) + 1;
//debug_log("pages needed: %X\n", pages_needed);
for(int j = 0; j < pages_needed; j++)
{
uint32_t vaddr = start_page + j * 0x1000;
void* phys_addr = alloc_page();
if (!phys_addr) {
printf("exec_from_file: alloc_page failed for segment\n");
set_page_dir(curr_pd_phys);
//TODO: free previously allocated pages
free(file);
asm volatile("sti");
return;
}
debug_log("mapping 0x%X -> 0x%X\n", phys_addr, vaddr);
map_page(phys_addr, (void*)vaddr, PAGE_PRESENT | PAGE_RW | PAGE_USER);
}
memcpy((void*)elf_phdr->p_vaddr, file+elf_phdr->p_offset, elf_phdr->p_filesz);
if (elf_phdr->p_memsz > elf_phdr->p_filesz) {
bss_start = elf_phdr->p_vaddr + elf_phdr->p_filesz;
bss_end = elf_phdr->p_vaddr + elf_phdr->p_memsz;
memset((void*)bss_start, 0, bss_end - bss_start);
}
//debug_log("p_filesz: 0x%X (%X)\n", elf_phdr->p_filesz, elf_phdr->p_filesz);
//debug_log("================================\n\n\n\n");
}
debug_log("BSS: %X - %X (%X)\n", bss_start, bss_end, DivRoundUp(bss_end+1, 0x1000));
debug_log("setting up the user stack...\n");
//TODO: i think this thing allocates more pages than needed
for (uint32_t vaddr = USER_STACK_BOTTOM; vaddr <= USER_STACK_TOP; vaddr += PAGE_SIZE) {
void* phys_addr = alloc_page();
if(!phys_addr)
{
printf("error allocating user stack page, aborting...\n");
set_page_dir(curr_pd_phys);
//TODO: free previously allocated pages
return;
}
map_page(phys_addr, (void*)(vaddr & ~0xFFF), PAGE_PRESENT | PAGE_RW | PAGE_USER);
debug_log("mapping stack 0x%X -> 0x%X (0x%X)\n", (uint32_t)phys_addr, vaddr, (vaddr & ~0xFFF));
memset((void*)(vaddr & ~0xFFF), 0, PAGE_SIZE); // Add this
}
/*
uint32_t user_esp = USER_STACK_TOP;
// envp (environment pointer array) = NULL terminator
user_esp -= 4;
*(uint32_t*)user_esp = 0;
// argv (argument pointer array) = NULL terminator
user_esp -= 4;
*(uint32_t*)user_esp = 0;
// argc (argument count) = 0
user_esp -= 4;
*(uint32_t*)user_esp = 0;
*/
set_page_dir(curr_pd_phys);
Process* p_task1 = task_create(elf_ehdr->e_entry, USER_STACK_TOP, 3, proc_pd);
if (!p_task1) {
printf("exec_from_file: task_create failed\n");
set_page_dir(curr_pd_phys);
free(file);
asm volatile("sti");
return;
}
p_task1->cwd = dir;
uint32_t brk_address = DivRoundUp(bss_end+1, 0x1000)*0x1000;
debug_log("initial brk address: 0x%X\n", brk_address);
p_task1->brk = (void*)brk_address;
asm volatile("sti");
}
+29 -100
View File
@@ -1,117 +1,46 @@
extern current
global switchProcess
struc PCB
.PID resd 1 ; Offset: 0
.STATE resd 1 ; Offset: 4
.PROGRAM_COUNTER resd 1 ; Offset: 8
.STACK_BASE resd 1 ; Offset: 12
.STACK_POINTER resd 1 ; Offset: 16
.FLAGS resd 1 ; Offset: 20
.NEXT resd 1 ; Offset: 24
endstruc
section .text
; void switchProcess(Process* next)
switchProcess:
; __________Stack___________
; |------------------------|
; | Return Address (EIP) | +0
; |------------------------|
; | Process* next | +4
; |------------------------|
section .text
global switchProcess
extern current
extern trapret
; Push volatile registers (per the 32-bit System V ABI)
; void switchProcess(Process* next_process_ptr)
switchProcess:
mov edx, [esp + 4] ; edx = next_process_ptr (получаем аргумент СРАЗУ)
cli ; Запретить прерывания
push ebp
push ebx
push esi
push edi
push ebp
; __________Stack___________
; |------------------------|
; | EBP | +0
; |------------------------|
; | EDI | +4
; |------------------------|
; | ESI | +8
; |------------------------|
; | EBX | +12
; |-------- ---------------|
; | Return Address (EIP) | +16
; |------------------------|
; | Process* next | +20
; |------------------------|
mov eax, [current]
mov [eax + 4], esp ; current->kesp = esp
; Save current process' state
mov edi, [current]
; EDI now contains the pointer to [Process* current]
; |-----|
; | EDI | <== [Process* current]
; |-----|
; edx уже содержит next_process_ptr
mov esp, [edx + 4] ; esp = next_process_ptr->kesp
mov [current], edx ; current = next_process_ptr
; Set [current->PCB.STACK_POINTER] to the value in ESP
; Process* current->PCB.STACK_POINTER <== ESP
mov [edi + PCB.STACK_POINTER], esp
mov eax, [edx + 12]
sub eax, 0xC0000000
mov cr3, eax
; Load next process' state
; ESP has been decremented by 16, so instead of +4,
; we need to do +20. 4 pushes, 1 return address, 4
; bytes each.
mov esi, [esp + 20]
; ESI now contains the pointer to [Process* next]
; __________Stack___________
; |------------------------|
; | Return Address (EIP) | +16
; |-----| |------------------------|
; | ESI | <== | Process* next | +20
; |-----| |------------------------|
; Set [EXTERN Process* current] to the value in ESI
; Process* current <== ESI (Process* next)
mov [current], esi
mov esp, [esi + PCB.STACK_POINTER]
; |-----| |-----|
; | ESP | <== | ESI |
; |-----| |-----|
; Restore non-volatile registers (per the 32-bit System V ABI)
pop ebp
pop edi
pop esi
pop ebx
; The stack is now restored to its original state.
; __________Stack___________
; |------------------------|
; | Return Address (EIP) | +0
; |------------------------|
; | Process* next | +4
; |------------------------|
pop ebp
ret
global jump_usermode
extern test_user_function
jump_usermode:
mov ax, (4 * 8) | 3 ; ring 3 data with bottom 2 bits set for ring 3
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax ; SS is handled by iret
; and eax, ~0x80000000
; mov cr0, eax
trapret:
; Восстанавливаем сегментные регистры
pop gs
pop fs
pop es
pop ds
; set up the stack frame iret expects
mov eax, esp
push (4 * 8) | 3 ; data selector
push eax ; current esp
pushf ; eflags
push (3 * 8) | 3 ; code selector (ring 3 code with bottom 2 bits set for ring 3)
push test_user_function ; instruction address to return to
popad
; Теперь ESP указывает на eip, cs, eflags, esp, ss
; (interrupt and error fields removed from TrapFrame)
iret
+20 -8
View File
@@ -1,6 +1,7 @@
; TODO: maybe put it near idt.c?
global sys_exit_handler
extern printf
extern handle_syscall
sys_exit_handler:
; Сохраняем регистры Ring 3
pusha
@@ -16,9 +17,8 @@ sys_exit_handler:
mov fs, ax
mov gs, ax
; Выполняем действие
push sys_exit_msg
call printf
push esp
call handle_syscall
add esp, 4
; Восстанавливаем сегменты Ring 3
@@ -31,11 +31,23 @@ sys_exit_handler:
; Возвращаемся в Ring 3
iret
global test_user_function
test_user_function:
mov eax, 0xDEADBEEF
int 0x80
jmp $
global execve_return
execve_return:
; tf is passed as first argument in cdecl at [esp+4]
; We need to move ESP to point to the TrapFrame that tf points to.
; Save tf pointer in eax first (before changing esp)
mov eax, [esp+4] ; eax = tf pointer
; Now load ESP with the trapframe
mov esp, eax ; esp = tf, now stack is: gs, fs, es, ds, edi, esi...
pop gs
pop fs
pop es
pop ds
popa
iret
section .data
sys_exit_msg: db "Returned from Ring 3", 0
File diff suppressed because it is too large Load Diff
+157 -104
View File
@@ -1,6 +1,10 @@
#include "../include/task.h"
#include "../include/stdio.h"
#include "../include/paging.h"
#include "../include/string.h"
#include "../include/liballoc.h"
#include "../include/gdt.h"
#include "../include/isr.h"
#include <stddef.h>
@@ -11,59 +15,86 @@ uint32_t irq_disable_counter = 0;
uint32_t pid_counter;
uint32_t task_count;
#define STACK_SIZE 4096
extern void trapret(void);
extern void switchProcess(Process* next);
static void processStartup()
Process* task_create(uint32_t func, uint32_t user_esp, uint32_t ring, uint32_t* pagedir)
{
printf("startup\n");
scheduler_unlock();
void *p_physical = alloc_page();
if (!p_physical) {
debug_log("task_create: alloc_page failed for process\n");
return NULL;
}
Process* task_create(EntryPoint func, void** args, uint32_t arg_count)
{
Process* p = heap_alloc(sizeof(Process));
Process* p = (Process*)((uint32_t)p_physical+0xC0000000);
map_page(p_physical, (void*)p, PAGE_PRESENT | PAGE_RW);
memset(p, 0, sizeof(Process));
p->pid = ++pid_counter;
p->state = Ready;
p->programCounter = 0;
p->stackBase = heap_alloc(STACK_SIZE);
p->stackPointer = (uintptr_t*)((uint32_t)p->stackBase + STACK_SIZE);
p->ring = ring;
//put the arguments in stack
for(int i = arg_count-1; i >=0; i--)
*(--p->stackPointer) = (uintptr_t)args[i];
// Выделяем стек ядра
void *kstack_physical = alloc_page();
if (!kstack_physical) {
debug_log("task_create: alloc_page failed for kernel stack\n");
//TODO: free p_physical and its page table entry
return NULL;
}
p->kstack = (char*)((uint32_t)kstack_physical+0xC0000000);
map_page(kstack_physical, p->kstack, PAGE_PRESENT | PAGE_RW);
debug_log("kstack: %X!!!!!!!!!!!!\n", p->kstack);
// Добавляем адрес возврата (фиктивный, для выравнивания)
*(--p->stackPointer) = 0; // Фиктивный адрес возврата (не используется напрямую)
p->kstack_top = (uint32_t)p->kstack + KSTACKSIZE;
*(--p->stackPointer) = (uintptr_t)func;
*(--p->stackPointer) = (uintptr_t)processStartup;
*(--p->stackPointer) = 0;//ebp
*(--p->stackPointer) = 0;//edi
*(--p->stackPointer) = 0;//esi
*(--p->stackPointer) = 0;//ebx
uint8_t* sp = (uint8_t*)(p->kstack + KSTACKSIZE);
p->page_directory = kernel_page_directory;
sp -= sizeof(TrapFrame);
p->tf = (TrapFrame*)sp;
memset(p->tf, 0, sizeof(TrapFrame));
p->tf->cs = ring == 3 ? (SEG_UCODE | DPL_USER) : (SEG_KCODE);
p->tf->ds = ring == 3 ? (SEG_UDATA | DPL_USER) : (SEG_KDATA);
p->tf->es = p->tf->ds;
p->tf->fs = p->tf->ds;
p->tf->gs = p->tf->ds;
p->tf->usermode_ss = ring == 3 ? (SEG_UDATA | DPL_USER) : (SEG_KDATA);
p->tf->eflags = FL_IF;
p->tf->eip = (uint32_t)func;
p->tf->esp = (uint32_t)p->tf + offsetof(TrapFrame, eip);
p->pagedir = pagedir;
if(ring == 3)
{
p->tf->usermode_esp = user_esp;
}
sp -= sizeof(Context);
p->context = (Context*)sp;
memset(p->context, 0, sizeof(Context));
p->context->eip = (uint32_t)trapret;
p->kesp = (uint32_t)sp;
p->wake_up_time = 0;
p->next = 0;
if(!queue)
{
if (!queue) {
queue = p;
current = queue;
}
else
{
} else {
Process* curr = queue;
while (curr->next)
curr = curr->next;
curr->next = p;
}
task_count++;
return p;
}
// Остальные функции остаются без изменений
void scheduler_lock()
{
asm volatile("cli");
@@ -77,103 +108,125 @@ void scheduler_unlock()
asm volatile("sti");
}
void schedule()
{
if(!current)
return;
//TODO: there's an issue with this. If there's only one task in the queue (or is it there really?),
//the scheduler doesn't switch the context to it, but just does nothing
void schedule() {
scheduler_lock();
Process* next = current->next;
if(!next)
next = queue;
if(next != current)
{
loadPageDirectory(next->page_directory);
// Step 1: Iterate through all processes to wake up any that are due.
Process* p = queue;
while (p) {
if(p->state == Waiting){
if (p->waiting_reason == TIMER && timer_ticks >= p->wake_up_time) {
p->state = Ready;
p->waiting_reason = NONE;
}
}
p = p->next;
}
// Step 2: Clean up any terminated processes.
Process* prev = NULL;
p = queue;
while (p) {
if (p->state == Terminated && p != current) {
Process* to_free = p;
// Unlink from queue
if (prev) {
prev->next = p->next;
p = p->next; // Move to next
} else {
queue = p->next;
p = queue; // Move to head
}
// Safe to free resources now because we are NOT running on this stack
free(to_free->cwd);
destroy_page_dir(to_free->pagedir);
free_page((void*)virt_to_phys(to_free->kstack));
free_page((void*)virt_to_phys(to_free));
// Continue loop without advancing prev (since we removed p)
continue;
}
prev = p;
p = p->next;
}
Process* start_search = (current && current->next) ? current->next : queue;
if (!start_search) start_search = queue;
Process* next = start_search;
if (next) { // Check if queue is empty
do {
if (next->state == Ready) {
if (next != current) {
tss.esp0 = next->kstack_top;
switchProcess(next);
}
scheduler_unlock();
return;
}
next = next->next;
if (!next) next = queue;
} while (next != start_search);
}
// If current is Terminated and we found no one else, we MUST run idle
// otherwise we return to a dead stack.
if (current->state == Terminated) {
// Find idle task or panic.
// Assuming first task (pid 1) is idle/init and never dies.
// For now, just unlock (unsafe if current is dead) or loop.
}
scheduler_unlock();
}
void idle()
{
while(1){}
while (1) { asm volatile("sti; hlt");}
}
void task1(int arg1, char* arg2)
void task1()
{
while (1) {
if(arg1 == 42)
printf("task1 0x%x %s\n", arg1, arg2);
else
printf("ZHOPA %s\n", arg2);
printf("task1\n");
}
}
void task2(int arg1, int arg2)
void task2()
{
while(1){printf("task2 %X %X\n", arg1, arg2);}
int a = 0;
while (1) { a++; printf("task2 %X\n", a); }
}
void jump_usermode2(void);
void scheduler_init()
{
//jump_usermode2();
//we create this task two times because in other case it just won't start
task_create((EntryPoint)&idle, NULL, 0);
task_create((EntryPoint)&idle, NULL, 0);
void* args1[] = {(void*)42, (void*)"ebalo"};
task_create((EntryPoint)&task1, args1, 2);
void* args2[] = {(void*)69, (void*)420};
task_create((EntryPoint)&task2, args2, 2);
uint32_t* kernel_tasks_pagedir = (uint32_t*)create_page_dir();
if (!kernel_tasks_pagedir) {
printf("scheduler_init: create_page_dir failed\n");
while(1) {}
}
extern void test_user_function(void);
void jump_usermode2(void) {
void* code_phys = alloc_page();
if (!code_phys) {
printf("No memory for user code\n");
while (1);
Process* idle_proc = task_create((uint32_t)idle, 0, 0, kernel_tasks_pagedir);
if (!idle_proc) {
printf("scheduler_init: task_create failed\n");
while(1) {}
}
}
// Временно отображаем code_phys в ядре
uint32_t kernel_temp_virt = 0xC0100000;
map_page(code_phys, (void*)kernel_temp_virt, 0x3); // Present, R/W, Supervisor
void task_kill(Process* proc) {
if (!proc) return;
// Копируем код
uint32_t* src = (uint32_t*)test_user_function;
uint32_t* dst = (uint32_t*)kernel_temp_virt;
for (int i = 0; i < 1024; i++) {
dst[i] = src[i];
scheduler_lock();
proc->state = Terminated;
if(proc == current)
{
schedule();
}
printf("Copied code to 0x%x (virt 0x%x): 0x%x 0x%x 0x%x\n",
(uint32_t)code_phys, kernel_temp_virt, dst[0], dst[1], dst[2]);
// Настраиваем Ring 3
uint32_t user_stack_top;
void* user_code_virt = setup_user_process(code_phys, &user_stack_top);
if (!user_code_virt) {
printf("Failed to setup user process\n");
while (1);
}
printf("user_code_virt: 0x%x, user_stack_top: 0x%x\n",
(uint32_t)user_code_virt, user_stack_top);
asm volatile (
"mov $0x23, %%dx\n"
"mov %%dx, %%ds\n"
"mov %%dx, %%es\n"
"mov %%dx, %%fs\n"
"mov %%dx, %%gs\n"
"push $0x23\n"
"push %0\n"
"pushf\n"
"push $0x1B\n"
"push %1\n"
"iret\n"
:
: "r" (user_stack_top), "r" (user_code_virt)
: "dx", "memory"
);
__builtin_unreachable();
scheduler_unlock();
}
+1 -7
View File
@@ -4,21 +4,15 @@
#include <stddef.h>
#include "../include/string.h"
#ifdef __is_katauos
#include "../include/screen.h"
#endif
int puts(const char* string) {
return printf("%s\n", string);
}
int putchar(int ic) {
#if defined(__is_katauos)
char c = (char) ic;
terminal_write(&c, sizeof(c));
#else
// TODO: Implement stdio and the write system call.
#endif
return ic;
}
@@ -69,7 +63,7 @@ void intToString(int value, char *buffer, char format) {
buffer[i] = '\0';
}
static bool print(const char* data, size_t length) {
bool print(const char* data, size_t length) {
const unsigned char* bytes = (const unsigned char*) data;
for (size_t i = 0; i < length; i++)
if (putchar(bytes[i]) == EOF)
+123
View File
@@ -48,3 +48,126 @@ size_t strlen(const char* str)
len++;
return len;
}
char *strcat(char *dest, const char *src) {
char *original_dest = dest;
while (*dest != '\0') {
dest++;
}
while ((*dest++ = *src++) != '\0')
;
return original_dest;
}
char *strcpy(char *dest, const char *src) {
char *original_dest = dest;
while ((*dest++ = *src++) != '\0')
;
return original_dest;
}
static char *next_token = NULL;
static char *strpbrk_custom(const char *str, const char *delim) {
if (!str || !delim) {
return NULL;
}
while (*str) {
const char *d = delim;
while (*d) {
if (*str == *d) {
return (char *)str;
}
d++;
}
str++;
}
return NULL;
}
char *strtok(char *str, const char *delim) {
char *token_start;
char *token_end;
if (str != NULL) {
next_token = str;
}
if (next_token == NULL || *next_token == '\0') {
return NULL;
}
token_start = next_token;
while (*token_start) {
const char *d = delim;
int is_delim = 0;
while (*d) {
if (*token_start == *d) {
is_delim = 1;
break;
}
d++;
}
if (!is_delim) {
break;
}
token_start++;
}
if (*token_start == '\0') {
next_token = NULL;
return NULL;
}
token_end = token_start;
while (*token_end) {
const char *d = delim;
int is_delim = 0;
while (*d) {
if (*token_end == *d) {
is_delim = 1;
break;
}
d++;
}
if (is_delim) {
break;
}
token_end++;
}
if (*token_end == '\0') {
next_token = NULL;
} else {
*token_end = '\0';
next_token = token_end + 1;
}
return token_start;
}
char *strrchr(const char *s, int c) {
const char *p = NULL;
for (;;) {
if (*s == (char)c)
p = s;
if (*s++ == '\0')
return (char *)p;
}
}
int strcmp(const char* s1, const char* s2)
{
while(*s1 && (*s1 == *s2))
{
s1++;
s2++;
}
return *(const unsigned char*)s1 - *(const unsigned char*)s2;
}
+27 -4
View File
@@ -1,14 +1,13 @@
#include "../include/types.h"
#include "../include/utils.h"
uint8 inportb(uint16 _port)
uint8_t inportb(uint16_t _port)
{
uint8 rv;
uint8_t rv;
__asm__ __volatile__ ("inb %1, %0" : "=a" (rv) : "dN" (_port));
return rv;
}
void outportb(uint16 _port, uint8 _data)
void outportb(uint16_t _port, uint8_t _data)
{
__asm__ __volatile__ ("outb %1, %0" : : "dN" (_port), "a" (_data));
}
@@ -57,3 +56,27 @@ uint32_t fat32_datetime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour,
return fat_datetime;
}
inline void cpuid(int code, uint32_t *a, uint32_t *d)
{
asm volatile("cpuid":"=a"(*a),"=d"(*d):"a"(code):"ecx","ebx");
}
const uint32_t CPUID_FLAG_MSR = 1 << 5;
bool cpu_has_msr()
{
static uint32_t a, d; // eax, edx
cpuid(1, &a, &d);
return d & CPUID_FLAG_MSR;
}
void cpu_get_msr(uint32_t msr, uint32_t *lo, uint32_t *hi)
{
asm volatile("rdmsr" : "=a"(*lo), "=d"(*hi) : "c"(msr));
}
void cpu_set_msr(uint32_t msr, uint32_t lo, uint32_t hi)
{
asm volatile("wrmsr" : : "a"(lo), "d"(hi), "c"(msr));
}
+3934
View File
File diff suppressed because it is too large Load Diff
+64
View File
@@ -0,0 +1,64 @@
#include <stdio.h>
#include <stdlib.h>
#include "elf.h"
int main(int argc, char** argv)
{
FILE* fp;
long file_size;
fp = fopen("testfile", "rb");
fseek(fp, 0, SEEK_END);
file_size = ftell(fp);
fseek(fp, 0, SEEK_SET);
printf("size: %d!!\n", file_size);
uint8_t* file = (uint8_t*)malloc(file_size);
fread(file, 1, file_size, fp);
Elf32_Ehdr *elf_ehdr = (Elf32_Ehdr*)file;
int program_header_table_entry_count = elf_ehdr->e_phnum;
int program_header_table_entry_size = elf_ehdr->e_phentsize;
printf("magic: %s, type: %d, entry: 0x%X\n", elf_ehdr->e_ident, elf_ehdr->e_type, elf_ehdr->e_entry);
printf("PHNUM: %d\n", program_header_table_entry_count);
printf("PHENTSIZE: %d\n\n", program_header_table_entry_size);
for(int i = 0; i < program_header_table_entry_count; i++)
{
Elf32_Phdr *elf_phdr = (Elf32_Phdr *)((uint32_t)file + elf_ehdr->e_phoff +
i * elf_ehdr->e_phentsize);
printf("HEADER %d, type: 0x%X, vaddr: 0x%X, paddr: 0x%X, memsz: 0x%X\n", i, elf_phdr->p_type, elf_phdr->p_vaddr, elf_phdr->p_paddr, elf_phdr->p_memsz);
if(elf_phdr->p_type != PT_LOAD)
{
printf("not PT_LOAD, skipping...\n");
continue;
}
int pages_needed = elf_phdr->p_memsz / 0x1000;
printf("pages needed: %d\n", pages_needed);
///////////////////////////
//MAP HERE
///////////////////////////
//memcpy(elf_phdr->p_vaddr, file+elf_phdr->p_offset, elf_phdr->p_filesz);
uint32_t file_start = elf_phdr->p_vaddr + elf_phdr->p_filesz;
uint32_t file_end = elf_phdr->p_vaddr + pages_needed * 0x1000;
//memset(file_start, 0, file_end - file_start);
printf("p_filesz: 0x%X (%d)\n", elf_phdr->p_filesz, elf_phdr->p_filesz);
printf("================================\n\n\n\n");
}
fclose(fp);
free(file);
return 0;
}
Executable
BIN
View File
Binary file not shown.