Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59237ab375 | ||
|
|
a77b51699c | ||
|
|
312c543510 | ||
|
|
59b775457d | ||
|
|
ab2da499da
|
||
|
|
64d5cd1d2f
|
||
|
|
560003b6e3 | ||
|
|
93fe3a179b | ||
|
|
761789a42e | ||
|
|
64f86a961d | ||
|
|
466c1a61af | ||
|
|
9fe2331ca7 | ||
|
|
4cef109e90 | ||
|
|
3417fd7d13 | ||
|
|
9e68f71cd0 | ||
|
|
53e380e510 | ||
|
|
51dc254aa3 | ||
|
|
2a7f62e275 | ||
|
|
24caf9c8aa | ||
|
|
a358d0b1ac | ||
|
|
c8036a9aae | ||
|
|
697029016e | ||
|
|
1f90fb5825 | ||
|
|
0b0492e756 | ||
|
|
827189593c | ||
|
|
a66a5da039 | ||
|
|
0de9f026b6 | ||
|
|
c17c23ddd5 | ||
|
|
7dc522eb3d | ||
|
|
68033325d2 | ||
|
|
ccf954e1d6 | ||
|
|
57d2931b96 | ||
|
|
561de6a4e3 | ||
|
|
f4b0429062 | ||
|
|
26c8280059 | ||
|
|
88c1936e83 | ||
|
|
8c26f54d28 | ||
|
|
05fa945421 | ||
|
|
2019f87b14 | ||
|
|
f697fab390 | ||
|
|
1fb777adb0
|
||
|
|
3ca60aea00
|
||
|
|
bacf6f6782 | ||
|
|
2c8b5d4752 | ||
|
|
7c2f3735bf | ||
|
|
91e0379fc9 | ||
|
|
4c26652ee2 | ||
|
|
63938e1acd | ||
|
|
5b922ea773 | ||
|
|
a459751453 | ||
|
|
982f1a5fae | ||
|
|
649c4c56a4 | ||
|
|
fb8dd43dd3 | ||
|
|
9e21167bd3 | ||
|
|
7c43956ebe | ||
|
|
9bb6d9d1a5 | ||
|
|
fffa4b7699 | ||
|
|
92511dbcd7 | ||
|
|
9fdc551308 | ||
|
|
caa4005990 | ||
|
|
0628470a7c | ||
|
|
ce6e9642ee | ||
|
|
287ac77422 | ||
|
|
ea39cb85f3 | ||
|
|
d017f0b245 | ||
|
|
df45ffe2ce | ||
|
|
992d82c6d4 | ||
|
|
3ae26ed88a | ||
|
|
359e5c6d78 | ||
|
|
aac4375b8e | ||
|
|
8bc7e1d523 | ||
|
|
a01120cfe4 | ||
|
|
5b5de55919 | ||
|
|
a9f8e96ac9 | ||
|
|
c2293b8996 | ||
|
|
7f861a8b92 | ||
|
|
e793e45854 | ||
|
|
2a7baf1184 | ||
|
|
cbd2c52c20 | ||
|
|
e3eba88958 | ||
|
|
bfdd3b6b6a | ||
|
|
b769ac0a58 | ||
|
|
29de6e6f43 | ||
|
|
c047dd687b | ||
|
|
70d6aacb91 | ||
|
|
bb096f826a | ||
|
|
bf7d96865a | ||
|
|
4ccae473ca | ||
|
|
a9789b7f57 | ||
|
|
93f174827b | ||
|
|
5fa2393fd6 | ||
|
|
9f721a72b7 | ||
|
|
2408b67ccc | ||
|
|
ea6733fd46 | ||
|
|
01155234c6 | ||
|
|
541bc7172f | ||
|
|
d1ac41deeb | ||
|
|
5f87e55067 | ||
|
|
8fea7a8ec6 | ||
|
|
f47a4a451d | ||
|
|
9000d76441 | ||
|
|
33aa97c6ec | ||
|
|
d5f41b1ef9 | ||
|
|
681f509099 | ||
|
|
7c870636c5 | ||
|
|
c808a5d295 | ||
|
|
b8752ee39d | ||
|
|
bc0bd99f95 | ||
|
|
e2b596dcbd | ||
|
|
5d012b410d | ||
|
|
44d09ab13f | ||
|
|
2e372ae9c4 | ||
|
|
4fbaed321c | ||
|
|
767e74976f | ||
|
|
65f543fa92 | ||
|
|
745d85f413 | ||
|
|
0bf26a6c70 | ||
|
|
00c9560660 | ||
|
|
d4a14633ce | ||
|
|
b836a37264 | ||
|
|
7e97987e95 | ||
|
|
ab72a7ee18 |
+5
-1
@@ -1,3 +1,7 @@
|
||||
bin/
|
||||
myos.bin
|
||||
katauos.bin
|
||||
boot.iso
|
||||
.vscode/
|
||||
cross-compiler-i686/
|
||||
buildroot-2025.08/
|
||||
rootfs.iso9660
|
||||
|
||||
@@ -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/utils.o bin/string.o bin/stdio.o bin/disk.o bin/pic.o bin/pit.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
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
Executable
BIN
Binary file not shown.
@@ -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
|
||||
Binary file not shown.
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
@@ -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();
|
||||
@@ -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
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#ifndef ISR_H
|
||||
#define ISR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern uint32_t timer_ticks;
|
||||
|
||||
void isr0();
|
||||
void isr1();
|
||||
void isr2();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#ifndef SYSCALLS_H
|
||||
#define SYSCALLS_H
|
||||
#include "../include/task.h"
|
||||
|
||||
void handle_syscall(TrapFrame *tf);
|
||||
|
||||
#endif
|
||||
+76
-17
@@ -2,33 +2,92 @@
|
||||
#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
|
||||
{
|
||||
Ready,
|
||||
Running,
|
||||
Waiting,
|
||||
Terminated
|
||||
Ready,
|
||||
Running,
|
||||
Waiting,
|
||||
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 pid; // Process ID
|
||||
|
||||
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);
|
||||
void scheduler_init();
|
||||
void schedule();
|
||||
void scheduler_lock();
|
||||
void scheduler_unlock();
|
||||
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
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -1,96 +1,119 @@
|
||||
bits 32
|
||||
|
||||
section .multiboot
|
||||
align 4
|
||||
dd 0x1BADB002
|
||||
dd 0x00
|
||||
dd - (0x1BADB002+0x00)
|
||||
%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
|
||||
|
||||
section .data
|
||||
align 4
|
||||
multiboot_info:
|
||||
dd 0
|
||||
dd 0
|
||||
dd 0
|
||||
dd 0
|
||||
dd 0
|
||||
dd 0
|
||||
dd 0
|
||||
tmp_gdtr:
|
||||
dw ((3 * 8) - 1)
|
||||
tmp_gdta:
|
||||
dd tmp_gdt
|
||||
|
||||
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:
|
||||
tmp_gdt:
|
||||
; NULL DESCRIPTOR
|
||||
dw 0x0000
|
||||
dw 0x0000
|
||||
dw 0x0000
|
||||
dw 0x0000
|
||||
|
||||
section .bss
|
||||
stack_bottom:
|
||||
resb 16384
|
||||
stack_top:
|
||||
; 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)
|
||||
|
||||
section .gdt
|
||||
%include "src/gdt.asm"
|
||||
align 4
|
||||
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
|
||||
cli
|
||||
push ebx ; Сохраняем оригинальный ebx (указатель Multiboot)
|
||||
extern setup_tmp_pgdir
|
||||
extern bss_init
|
||||
extern gdt_init
|
||||
extern get_last_boot_addr
|
||||
extern kmain
|
||||
|
||||
lgdt [gdt]
|
||||
_start:
|
||||
cli
|
||||
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
|
||||
|
||||
; Заполняем адрес 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
|
||||
align 4
|
||||
global setup_kernel
|
||||
setup_kernel:
|
||||
mov esp, PAGE_OFFSET + 0x10000 ; default stack address (0xC0000000 + 0x10000)
|
||||
push 0 ; reset EFLAGS
|
||||
popf
|
||||
|
||||
mov ax, DATA_SEG
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
mov ss, ax
|
||||
jmp CODE_SEG:.huita
|
||||
push ebx ; save Multiboot info structure
|
||||
push eax ; save Multiboot magic value
|
||||
call setup_tmp_pgdir
|
||||
mov cr3, eax
|
||||
|
||||
.huita:
|
||||
mov ax, TSS_SEG
|
||||
ltr ax
|
||||
pop ebx ; Восстанавливаем оригинальный ebx
|
||||
push ebx ; Передаем его в kmain
|
||||
call kmain
|
||||
hlt
|
||||
.end:
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
jmp $
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
+57
-30
@@ -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
|
||||
uint8_t scancode = inb(0x60);
|
||||
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)
|
||||
{
|
||||
shift_pressed = true;
|
||||
return;
|
||||
}
|
||||
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
|
||||
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
|
||||
return;
|
||||
}
|
||||
char c;
|
||||
if (shift_pressed || caps_pressed) c = kbdus2[scancode];
|
||||
else c = kbdus[scancode];
|
||||
|
||||
if(shift_pressed || caps_pressed)
|
||||
printf("%c", kbdus2[scancode]);
|
||||
else
|
||||
printf("%c", kbdus[scancode]); //printf("(0x%X)%c", scancode, 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()
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
+62
-11
@@ -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')
|
||||
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;
|
||||
update_cursor(0, 0);
|
||||
}
|
||||
terminal_state = STATE_NORMAL;
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (++terminal_column >= VGA_WIDTH){
|
||||
terminal_column = 0;
|
||||
if (++terminal_row >= VGA_HEIGHT)
|
||||
terminal_scroll();
|
||||
}
|
||||
if(terminal_row >= VGA_HEIGHT){
|
||||
terminal_scroll();
|
||||
terminal_column++;
|
||||
}
|
||||
|
||||
if(c == '\n')
|
||||
{
|
||||
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));
|
||||
}
|
||||
@@ -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 = '-';
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
+114
-41
@@ -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);
|
||||
pic_end_int(0x0);
|
||||
timer_ticks++;
|
||||
if(lapic_enabled)
|
||||
{
|
||||
lapic_eoi();
|
||||
}
|
||||
else
|
||||
{
|
||||
pic_end_int(0x0);
|
||||
}
|
||||
|
||||
scheduler_lock();
|
||||
schedule();
|
||||
@@ -89,7 +142,27 @@ __attribute__((interrupt)) void isr_custom(struct interrupt_frame *frame)
|
||||
{
|
||||
//terminal_writestring("YOOOOO!!!!!! I LOVE KATYA!!!!");
|
||||
handle_keyboard();
|
||||
pic_end_int(0x1);
|
||||
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",
|
||||
|
||||
+105
-148
@@ -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");
|
||||
isr_install();
|
||||
pic_remap(0x20, 0x28);
|
||||
pit_init(100);
|
||||
|
||||
apply_pic_masks();
|
||||
if(magic != MULTIBOOT_BOOTLOADER_MAGIC) {
|
||||
printf("invalid magic number!\n");
|
||||
while(1){}
|
||||
}
|
||||
|
||||
paging_init();
|
||||
printf("paging_init done\n");
|
||||
test_paging();
|
||||
if(mbi.flags & MULTIBOOT_INFO_BOOT_LOADER_NAME) {
|
||||
printf("bootloader: %s\n", mbi.boot_loader_name);
|
||||
}
|
||||
|
||||
printf("init_allocator...");
|
||||
init_allocator();
|
||||
heap_init();
|
||||
printf("after heap_init\n");
|
||||
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);
|
||||
|
||||
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
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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");
|
||||
}
|
||||
|
||||
+129
-71
@@ -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);
|
||||
if (!(pd[pdindex] & 0x1)) {
|
||||
printf("GET_PTE ERROR: PT not present\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
*user_stack_top = stack_virt + 0x1000;
|
||||
next_user_virt += 0x400000; // Следующий 4 МБ блок
|
||||
return (void*)code_virt;
|
||||
}
|
||||
uint32_t *pt = (uint32_t*)(0xFFC00000 + (pdindex << 12));
|
||||
|
||||
void free_user_process(void* code_phys, void* stack_phys) {
|
||||
free_page(code_phys);
|
||||
free_page(stack_phys);
|
||||
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; // Все страницы "не присутствуют"
|
||||
}
|
||||
void map_page(void *physaddr, void *virtualaddr, unsigned int flags) {
|
||||
// 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); // Ошибка выравнивания
|
||||
// Invalidate the TLB entry for this virtual address
|
||||
asm volatile("invlpg (%0)" : : "r" (virtualaddr) : "memory");
|
||||
}
|
||||
}
|
||||
|
||||
pd[pdindex] = ((uint32_t)new_pt) | 0x3; // Временно записываем в каталог
|
||||
asm volatile("invlpg (%0)" : : "r" ((uint32_t)&pd[pdindex]) : "memory"); // Инвалидируем TLB
|
||||
/**
|
||||
* 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* pt = ((uint32_t*)0xFFC00000) + (0x400 * pdindex);
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
pt[i] = 0;
|
||||
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.
|
||||
}
|
||||
|
||||
// Получаем таблицу страниц
|
||||
uint32_t* pt = ((uint32_t*)0xFFC00000) + (0x400 * pdindex);
|
||||
void* phys = alloc_page();
|
||||
if (!phys) while(1);
|
||||
// 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);
|
||||
|
||||
// Проверяем, не занята ли страница
|
||||
if (pt[ptindex] & 0x1) while(1); // Ошибка: страница уже отображена
|
||||
// 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.
|
||||
|
||||
pt[ptindex] = (uint32_t)phys | (flags & 0xFFF) | 0x1; // supervisor, present
|
||||
asm volatile("invlpg (%0)" : : "r" (virtualaddr) : "memory");
|
||||
return 0; // Success
|
||||
}
|
||||
|
||||
+268
-80
@@ -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 для 0x00000000–0x003FFFFF
|
||||
for (i = 0; i < 1024; i++) {
|
||||
kernel_page_table[i] = (i * 0x1000) | 0x3; // supervisor, present
|
||||
}
|
||||
kernel_page_directory[0] = pt_phys | 0x3;
|
||||
|
||||
// Ring 3: 0x00400000–0x007FFFFF, 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;
|
||||
}
|
||||
@@ -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 МБ уже заняты ядром (0x00000000–0x003FFFFF)
|
||||
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 ГБ (0x00000000–0xBFFFFFFF) свободными для пользовательских процессов.
|
||||
**/
|
||||
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 для 0x00000000–0x003FFFFF
|
||||
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); // Переключаемся на процесс
|
||||
}
|
||||
*/
|
||||
@@ -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");
|
||||
}
|
||||
+36
-107
@@ -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)
|
||||
section .text
|
||||
global switchProcess
|
||||
extern current
|
||||
extern trapret
|
||||
|
||||
; void switchProcess(Process* next_process_ptr)
|
||||
switchProcess:
|
||||
; __________Stack___________
|
||||
; |------------------------|
|
||||
; | Return Address (EIP) | +0
|
||||
; |------------------------|
|
||||
; | Process* next | +4
|
||||
; |------------------------|
|
||||
mov edx, [esp + 4] ; edx = next_process_ptr (получаем аргумент СРАЗУ)
|
||||
cli ; Запретить прерывания
|
||||
|
||||
; Push volatile registers (per the 32-bit System V ABI)
|
||||
push ebx
|
||||
push esi
|
||||
push edi
|
||||
push ebp
|
||||
push ebp
|
||||
push ebx
|
||||
push esi
|
||||
push edi
|
||||
|
||||
; __________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
|
||||
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebx
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
|
||||
; 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
|
||||
; |-----| |------------------------|
|
||||
trapret:
|
||||
; Восстанавливаем сегментные регистры
|
||||
pop gs
|
||||
pop fs
|
||||
pop es
|
||||
pop ds
|
||||
|
||||
popad
|
||||
|
||||
; 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
|
||||
; |------------------------|
|
||||
|
||||
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
|
||||
|
||||
; 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
|
||||
iret
|
||||
; Теперь ESP указывает на eip, cs, eflags, esp, ss
|
||||
; (interrupt and error fields removed from TrapFrame)
|
||||
iret
|
||||
@@ -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
+186
-133
@@ -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,169 +15,218 @@ 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();
|
||||
}
|
||||
|
||||
Process* task_create(EntryPoint func, void** args, uint32_t arg_count)
|
||||
{
|
||||
Process* p = heap_alloc(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);
|
||||
|
||||
//put the arguments in stack
|
||||
for(int i = arg_count-1; i >=0; i--)
|
||||
*(--p->stackPointer) = (uintptr_t)args[i];
|
||||
|
||||
// Добавляем адрес возврата (фиктивный, для выравнивания)
|
||||
*(--p->stackPointer) = 0; // Фиктивный адрес возврата (не используется напрямую)
|
||||
|
||||
*(--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
|
||||
|
||||
p->page_directory = kernel_page_directory;
|
||||
|
||||
p->next = 0;
|
||||
|
||||
if(!queue)
|
||||
{
|
||||
queue = p;
|
||||
current = queue;
|
||||
}
|
||||
else
|
||||
{
|
||||
Process* curr = queue;
|
||||
while(curr->next)
|
||||
curr = curr->next;
|
||||
curr->next = p;
|
||||
}
|
||||
task_count++;
|
||||
return p;
|
||||
void *p_physical = alloc_page();
|
||||
if (!p_physical) {
|
||||
debug_log("task_create: alloc_page failed for process\n");
|
||||
return NULL;
|
||||
}
|
||||
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->ring = ring;
|
||||
|
||||
// Выделяем стек ядра
|
||||
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->kstack_top = (uint32_t)p->kstack + KSTACKSIZE;
|
||||
|
||||
uint8_t* sp = (uint8_t*)(p->kstack + KSTACKSIZE);
|
||||
|
||||
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) {
|
||||
queue = p;
|
||||
current = queue;
|
||||
} else {
|
||||
Process* curr = queue;
|
||||
while (curr->next)
|
||||
curr = curr->next;
|
||||
curr->next = p;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
// Остальные функции остаются без изменений
|
||||
void scheduler_lock()
|
||||
{
|
||||
asm volatile("cli");
|
||||
irq_disable_counter++;
|
||||
asm volatile("cli");
|
||||
irq_disable_counter++;
|
||||
}
|
||||
|
||||
void scheduler_unlock()
|
||||
{
|
||||
irq_disable_counter--;
|
||||
if(irq_disable_counter == 0)
|
||||
asm volatile("sti");
|
||||
irq_disable_counter--;
|
||||
if (irq_disable_counter == 0)
|
||||
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);
|
||||
switchProcess(next);
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
while (1) {
|
||||
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);
|
||||
uint32_t* kernel_tasks_pagedir = (uint32_t*)create_page_dir();
|
||||
if (!kernel_tasks_pagedir) {
|
||||
printf("scheduler_init: create_page_dir failed\n");
|
||||
while(1) {}
|
||||
}
|
||||
|
||||
void* args1[] = {(void*)42, (void*)"ebalo"};
|
||||
task_create((EntryPoint)&task1, args1, 2);
|
||||
void* args2[] = {(void*)69, (void*)420};
|
||||
task_create((EntryPoint)&task2, args2, 2);
|
||||
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) {}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
void task_kill(Process* proc) {
|
||||
if (!proc) return;
|
||||
|
||||
scheduler_lock();
|
||||
proc->state = Terminated;
|
||||
|
||||
if(proc == current)
|
||||
{
|
||||
schedule();
|
||||
}
|
||||
|
||||
// Временно отображаем code_phys в ядре
|
||||
uint32_t kernel_temp_virt = 0xC0100000;
|
||||
map_page(code_phys, (void*)kernel_temp_virt, 0x3); // Present, R/W, Supervisor
|
||||
|
||||
// Копируем код
|
||||
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];
|
||||
}
|
||||
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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
Binary file not shown.
Reference in New Issue
Block a user