Compare commits
No commits in common. "dev" and "core" have entirely different histories.
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"files.associations": {
|
|
||||||
"random": "cpp"
|
|
||||||
}
|
|
||||||
}
|
|
73
Makefile
73
Makefile
@ -1,60 +1,67 @@
|
|||||||
CFLAGS = -g -w -std=gnu11 -m32 -mgeneral-regs-only -nostdlib -fno-builtin -fno-exceptions -fno-leading-underscore -fno-pie -fno-stack-protector -Wno-pointer-to-int-cast -Isrc/
|
CFLAGS = -g -std=gnu11 -m32 -mgeneral-regs-only -nostdlib -fno-builtin -fno-exceptions -fno-leading-underscore -fno-pie -fno-stack-protector -Wno-pointer-to-int-cast
|
||||||
CXXFLAGS = -g -w -m32 -fno-use-cxa-atexit -mgeneral-regs-only -nostdlib -fno-builtin -fno-rtti -fno-exceptions -fno-leading-underscore -fpermissive -fno-pie -fno-stack-protector -Isrc/
|
CXXFLAGS = -g -m32 -fno-use-cxa-atexit -mgeneral-regs-only -nostdlib -fno-builtin -fno-rtti -fno-exceptions -fno-leading-underscore -fpermissive -fno-pie -fno-stack-protector -I.
|
||||||
LDFLAGS =
|
LDFLAGS =
|
||||||
|
|
||||||
DISK_IMG_FILES = build/kernel/kernel.bin hello.txt alpha.txt
|
DISK_IMG_FILES = build/kernel/kernel.bin hello.txt alpha.txt \
|
||||||
|
build/hello/hello.bin
|
||||||
|
|
||||||
KERNEL_CPP_SRCS = $(shell find src/kernel/ -name '*.cpp')
|
KERNEL_CPP_SRCS = $(wildcard src/kernel/*.cpp) $(wildcard src/kernel/*/*.cpp)
|
||||||
KERNEL_ASM_SRCS = $(shell find src/kernel/ -name '*.asm')
|
KERNEL_ASM_SRCS = $(wildcard src/kernel/*.asm)
|
||||||
KERNEL_CPP_OBJS = $(patsubst src/%.cpp,build/%.o,$(KERNEL_CPP_SRCS))
|
KERNEL_CPP_OBJS = $(patsubst src/%.cpp,build/%.o,$(KERNEL_CPP_SRCS))
|
||||||
KERNEL_ASM_OBJS = $(patsubst src/%.asm,build/%.o,$(KERNEL_ASM_SRCS))
|
KERNEL_ASM_OBJS = $(patsubst src/%.asm,build/%.o,$(KERNEL_ASM_SRCS))
|
||||||
|
|
||||||
KERNEL_OBJS = build/kernel/isr.o $(KERNEL_CPP_OBJS) $(KERNEL_ASM_OBJS)
|
KERNEL_OBJS = build/kernel/isr.o $(KERNEL_CPP_OBJS) $(KERNEL_ASM_OBJS)
|
||||||
|
|
||||||
STAGE2_C_SRCS = $(wildcard src/bootstage2/*.c)
|
STAGE2_C_SRCS = $(wildcard src/boot_stage2/*.c)
|
||||||
STAGE2_C_OBJS = $(patsubst src/%.c,build/%.o,$(STAGE2_C_SRCS))
|
STAGE2_C_OBJS = $(patsubst src/%.c,build/%.o,$(STAGE2_C_SRCS))
|
||||||
|
|
||||||
STAGE2_OBJS = build/c_code_entry.o $(STAGE2_C_OBJS)
|
STAGE2_OBJS = build/c_code_entry.o $(STAGE2_C_OBJS)
|
||||||
|
|
||||||
PROGRAM_COMMON = build/programs/entry.o build/common/common.o
|
PROGRAM_COMMON = build/program_code_entry.o build/common/common.o
|
||||||
|
|
||||||
SRC_DIRS = $(shell find src/ -type d)
|
PROGRAM_C_SRCS = $(wildcard src/program/*.c)
|
||||||
BUILD_DIRS = $(subst src/,build/,$(SRC_DIRS))
|
PROGRAM_C_OBJS = $(patsubst src/%.c,build/%.o,$(PROGRAM_C_SRCS))
|
||||||
|
PROGRAM_OBJS = $(PROGRAM_COMMON) $(PROGRAM_C_OBJS)
|
||||||
|
|
||||||
PROGRAMS = $(shell find src/programs/* -type d)
|
HELLO_C_SRCS = $(wildcard src/hello/*.c)
|
||||||
$(foreach program,$(PROGRAMS),\
|
HELLO_C_OBJS = $(patsubst src/%.c,build/%.o,$(HELLO_C_SRCS))
|
||||||
$(eval $(program)_C_SRCS := $(shell find $(program) -name '*.c')) \
|
HELLO_OBJS = $(PROGRAM_COMMON) $(HELLO_C_OBJS)
|
||||||
$(eval $(program)_CPP_SRCS := $(shell find $(program) -name '*.cpp')) \
|
|
||||||
$(eval $(program)_OBJS := $(patsubst src/%.c,build/%.o,$($(program)_C_SRCS)) \
|
|
||||||
$(patsubst src/%.cpp,build/%.o,$($(program)_CPP_SRCS))) \
|
|
||||||
$(eval DISK_IMG_FILES += $(subst src/,build/,$(program))/$(shell basename $(program).bin)) \
|
|
||||||
)
|
|
||||||
|
|
||||||
.PHONY: run debug prepare clean cleanbuild
|
WORLD_C_SRCS = $(wildcard src/world/*.c)
|
||||||
|
WORLD_C_OBJS = $(patsubst src/%.c,build/%.o,$(WORLD_C_SRCS))
|
||||||
|
WORLD_OBJS = $(PROGRAM_COMMON) $(WORLD_C_OBJS)
|
||||||
|
|
||||||
|
.PHONY: run debug prepare clean
|
||||||
|
|
||||||
run: disk.img
|
run: disk.img
|
||||||
qemu-system-i386 disk.img
|
qemu-system-i386 disk.img
|
||||||
|
|
||||||
cleanbuild: clean disk.img
|
debug: disk.img
|
||||||
qemu-system-i386 disk.img
|
|
||||||
|
|
||||||
debug: clean disk.img
|
|
||||||
qemu-system-i386 -s -S -no-reboot -no-shutdown disk.img & gdb --command=gdbscript
|
qemu-system-i386 -s -S -no-reboot -no-shutdown disk.img & gdb --command=gdbscript
|
||||||
|
|
||||||
disk.img: prepare build/boot/boot.bin build/bootstage2/boot.bin $(DISK_IMG_FILES)
|
disk.img: prepare build/boot/boot.bin build/boot_stage2/boot.bin $(DISK_IMG_FILES) build/world/world.bin
|
||||||
dd if=/dev/zero of=disk.img count=43 bs=100k
|
dd if=/dev/zero of=disk.img count=43 bs=100k
|
||||||
dd if=build/boot/boot.bin of=disk.img conv=notrunc
|
dd if=build/boot/boot.bin of=disk.img conv=notrunc
|
||||||
dd obs=512 seek=1 if=build/bootstage2/boot.bin of=disk.img conv=notrunc
|
dd obs=512 seek=1 if=build/boot_stage2/boot.bin of=disk.img conv=notrunc
|
||||||
mount disk.img img.d
|
mount disk.img img.d
|
||||||
mkdir img.d/etc/
|
mkdir img.d/etc/
|
||||||
cp $(DISK_IMG_FILES) img.d/
|
cp $(DISK_IMG_FILES) img.d/
|
||||||
|
cp build/world/world.bin img.d/etc/world.bin
|
||||||
sleep 0.1
|
sleep 0.1
|
||||||
umount img.d
|
umount img.d
|
||||||
chmod 777 disk.img
|
chmod 777 disk.img
|
||||||
|
|
||||||
prepare:
|
prepare:
|
||||||
mkdir -p img.d
|
mkdir -p img.d
|
||||||
mkdir -p $(BUILD_DIRS)
|
mkdir -p build/boot
|
||||||
|
mkdir -p build/boot_stage2
|
||||||
|
mkdir -p build/kernel
|
||||||
|
mkdir -p build/kernel/datatypes
|
||||||
|
mkdir -p build/kernel/stdio
|
||||||
|
mkdir -p build/program
|
||||||
|
mkdir -p build/hello
|
||||||
|
mkdir -p build/world
|
||||||
|
mkdir -p build/common
|
||||||
mountpoint img.d | grep not || umount img.d
|
mountpoint img.d | grep not || umount img.d
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@ -64,10 +71,10 @@ build/boot/boot.bin: src/boot/boot.asm
|
|||||||
nasm $< -o $@
|
nasm $< -o $@
|
||||||
|
|
||||||
# Boot Stage 2
|
# Boot Stage 2
|
||||||
build/bootstage2/boot.bin: src/bootstage2/bootstage2.ld $(STAGE2_OBJS)
|
build/boot_stage2/boot.bin: src/boot_stage2/boot_stage2.ld $(STAGE2_OBJS)
|
||||||
ld $(LDFLAGS) -T $< $(STAGE2_OBJS)
|
ld $(LDFLAGS) -T $< $(STAGE2_OBJS)
|
||||||
|
|
||||||
build/bootstage2/%.o: src/bootstage2/%.c
|
build/boot_stage2/%.o: src/boot_stage2/%.c
|
||||||
gcc $(CFLAGS) -o $@ -c $<
|
gcc $(CFLAGS) -o $@ -c $<
|
||||||
|
|
||||||
# Kernel
|
# Kernel
|
||||||
@ -94,6 +101,12 @@ src/kernel/isr.S: src/kernel/isr.S.base src/kernel/gen_isr_asm.sh
|
|||||||
|
|
||||||
# Program
|
# Program
|
||||||
|
|
||||||
.SECONDEXPANSION:
|
build/program/program.bin: src/program/program.ld $(PROGRAM_OBJS)
|
||||||
build/programs/%.bin: src/programs/userspace.ld build/programs/entry.o $$(src/programs/$$(basename $$(notdir $$*))_OBJS) $(PROGRAM_COMMON)
|
echo $(PROGRAM_OBJS)
|
||||||
ld -o $@ -T $^
|
ld $(LDFLAGS) -T $< $(PROGRAM_OBJS)
|
||||||
|
|
||||||
|
build/hello/hello.bin: src/hello/hello.ld $(HELLO_OBJS)
|
||||||
|
ld $(LDFLAGS) -T $< $(HELLO_OBJS)
|
||||||
|
|
||||||
|
build/world/world.bin: src/world/world.ld $(WORLD_OBJS)
|
||||||
|
ld $(LDFLAGS) -T $< $(WORLD_OBJS)
|
@ -50,7 +50,7 @@ bootcode:
|
|||||||
|
|
||||||
mov ax, 2 ; Begin with the 2nd sector
|
mov ax, 2 ; Begin with the 2nd sector
|
||||||
call prep_i13
|
call prep_i13
|
||||||
mov al, 31 ; Load the next 31 sectors (15.5kb)
|
mov al, 31 ; Load the next 9 sectors (4.5k)
|
||||||
int 13h
|
int 13h
|
||||||
|
|
||||||
; We need to get the memory configuration from the BIOS now
|
; We need to get the memory configuration from the BIOS now
|
||||||
|
@ -11,8 +11,8 @@
|
|||||||
uint16_t identify_result[256];
|
uint16_t identify_result[256];
|
||||||
uint32_t total_28_lbas = 0;
|
uint32_t total_28_lbas = 0;
|
||||||
|
|
||||||
uint8_t* rootDirEntries = (uint8_t*)0x1000000;
|
uint8_t* rootDirEntries = 0x1000000;
|
||||||
uint16_t* FAT1 = (uint16_t*)0x1002000;
|
uint16_t* FAT1 = 0x1002000;
|
||||||
|
|
||||||
uint16_t countReserved;
|
uint16_t countReserved;
|
||||||
uint8_t countFATs;
|
uint8_t countFATs;
|
||||||
@ -60,7 +60,7 @@ void init_atapio() {
|
|||||||
|
|
||||||
// We've initialised now, let's load the FAT and RootDirEntries.
|
// We've initialised now, let's load the FAT and RootDirEntries.
|
||||||
read_sectors(sectorsPerFAT * countFATs + countReserved, countRDEs / 16, rootDirEntries);
|
read_sectors(sectorsPerFAT * countFATs + countReserved, countRDEs / 16, rootDirEntries);
|
||||||
read_sectors(countReserved, sectorsPerFAT, (uint8_t*)FAT1);
|
read_sectors(countReserved, sectorsPerFAT, FAT1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void read_sector(uint32_t address, uint8_t* buffer) {
|
void read_sector(uint32_t address, uint8_t* buffer) {
|
||||||
@ -95,7 +95,7 @@ uint16_t file_exists(char* filename) {
|
|||||||
for (int i=0; i<countRDEs; i++) {
|
for (int i=0; i<countRDEs; i++) {
|
||||||
bool found = strcmp(rootDirEntries+(i*32), filename, 11);
|
bool found = strcmp(rootDirEntries+(i*32), filename, 11);
|
||||||
if (found) {
|
if (found) {
|
||||||
uint16_t* correctEntry = (uint16_t*)(rootDirEntries+(i*32));
|
uint16_t* correctEntry = (rootDirEntries+(i*32));
|
||||||
return correctEntry[13];
|
return correctEntry[13];
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,14 +1,14 @@
|
|||||||
OUTPUT_FORMAT(binary)
|
OUTPUT_FORMAT(binary)
|
||||||
OUTPUT_ARCH(i386:i386)
|
OUTPUT_ARCH(i386:i386)
|
||||||
|
|
||||||
OUTPUT(build/bootstage2/boot.bin)
|
OUTPUT(build/boot_stage2/boot.bin)
|
||||||
|
|
||||||
SECTIONS {
|
SECTIONS {
|
||||||
. = 0x7E00;
|
. = 0x7E00;
|
||||||
|
|
||||||
.text : {
|
.text : {
|
||||||
build/c_code_entry.o(.text)
|
build/c_code_entry.o(.text)
|
||||||
build/bootstage2/main.o(.text)
|
build/boot_stage2/main.o(.text)
|
||||||
build/bootstage2/*(.text)
|
build/boot_stage2/*(.text)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
#include "atapio.h"
|
#include "atapio.h"
|
||||||
|
#include "screenstuff.h"
|
||||||
#include "paging.h"
|
#include "paging.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -10,7 +11,7 @@ typedef struct {
|
|||||||
uint32_t acpi3_extended;
|
uint32_t acpi3_extended;
|
||||||
}__attribute__((packed)) e820entry;
|
}__attribute__((packed)) e820entry;
|
||||||
|
|
||||||
uint8_t* bitmap = (uint8_t*)0x100000;
|
uint8_t* bitmap = 0x100000;
|
||||||
|
|
||||||
void set_bit(uint32_t offset, uint8_t* buffer) {
|
void set_bit(uint32_t offset, uint8_t* buffer) {
|
||||||
uint32_t index = offset / 8;
|
uint32_t index = offset / 8;
|
||||||
@ -46,30 +47,39 @@ void mark_unavailble(uint32_t address, uint32_t size, uint8_t* buffer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
char* stringify_type(uint32_t type) {
|
||||||
PDE* pde;
|
switch (type) {
|
||||||
uint32_t page_directory_phys_addr;
|
case 1:
|
||||||
uint32_t page_directory_phys_offset;
|
return "Usable";
|
||||||
uint32_t page_bitmap_phys;
|
case 3:
|
||||||
uint32_t page_bitmap_virt;
|
return "ACPI Reclaimable";
|
||||||
uint32_t stack_ptr;
|
case 4:
|
||||||
uint32_t vga_addr;
|
return "ACPI NVS";
|
||||||
uint32_t remainingPages;
|
case 5:
|
||||||
} KernelInformationStruct;
|
return "Bad memory";
|
||||||
|
default:
|
||||||
|
return "Reserved";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
init_term();
|
||||||
init_atapio();
|
init_atapio();
|
||||||
|
|
||||||
// e820 memory map exists at 0x20000
|
// e820 memory map exists at 0x20000
|
||||||
e820entry* e820_entries = (e820entry*)0x20000;
|
e820entry* e820_entries = 0x20000;
|
||||||
|
|
||||||
// Zero out the bitmap.
|
// Zero out the bitmap.
|
||||||
memset(bitmap, 0x20000, 0);
|
memset(bitmap, 0x20000, 0);
|
||||||
// Ensure the bitmap data is clear
|
// Ensure the bitmap data is clear
|
||||||
uint32_t pages;
|
|
||||||
|
for (int i=0; i<0x20000; i++)
|
||||||
|
if (bitmap[i])
|
||||||
|
printf("Found data in bitmap at %x!\n", (bitmap+i));
|
||||||
|
|
||||||
for (int i=0; e820_entries[i].length_low != 0 || e820_entries[i].length_high != 0; i++) {
|
for (int i=0; e820_entries[i].length_low != 0 || e820_entries[i].length_high != 0; i++) {
|
||||||
e820entry entry = e820_entries[i];
|
e820entry entry = e820_entries[i];
|
||||||
|
printf("BIOS-e820: Starting %x%x, length %x%x is %s\n", entry.base_high, entry.base_low, entry.length_high, entry.length_low, stringify_type(entry.type));
|
||||||
|
|
||||||
if (entry.type != 1)
|
if (entry.type != 1)
|
||||||
continue;
|
continue;
|
||||||
@ -86,18 +96,18 @@ void main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
uint32_t page_index = base / 4096;
|
uint32_t page_index = base / 4096;
|
||||||
pages += length / 4096;
|
|
||||||
|
printf("Page Index: %d\nLength (Pages): %d\n", page_index, length / 4096);
|
||||||
|
|
||||||
for (int j=0; length > 4096; length -= 4096, j++) {
|
for (int j=0; length > 4096; length -= 4096, j++) {
|
||||||
set_bit(page_index + j, bitmap);
|
set_bit(page_index + j, bitmap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mark_unavailble((uint32_t)bitmap, 0x20000, bitmap);
|
mark_unavailble(bitmap, 0x20000, bitmap);
|
||||||
mark_unavailble(0, 0xFFFFF, bitmap);
|
|
||||||
|
|
||||||
// Page Directory
|
// Page Directory
|
||||||
PDE* kernel_page_directory = (PDE*)(bitmap + 0x20000);
|
PDE* kernel_page_directory = bitmap + 0x20000;
|
||||||
|
|
||||||
// Clear the PD
|
// Clear the PD
|
||||||
memset((uint8_t*)kernel_page_directory, 4096, 0);
|
memset((uint8_t*)kernel_page_directory, 4096, 0);
|
||||||
@ -110,7 +120,7 @@ void main() {
|
|||||||
((uint32_t*)0x521000)[i] = 0x121000 + 0x1000*i;
|
((uint32_t*)0x521000)[i] = 0x121000 + 0x1000*i;
|
||||||
}
|
}
|
||||||
|
|
||||||
PTE** kernel_page_tables = (PTE**)0x521000;
|
PTE** kernel_page_tables = 0x521000;
|
||||||
|
|
||||||
for (int i = 0; i < 1023; i++) {
|
for (int i = 0; i < 1023; i++) {
|
||||||
kernel_page_directory[i] = (PDE){
|
kernel_page_directory[i] = (PDE){
|
||||||
@ -130,15 +140,15 @@ void main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mark unavailable bitmap to 0x522000
|
// Mark unavailable bitmap to 0x522000
|
||||||
mark_unavailble((uint32_t)bitmap, 0x4000000, bitmap);
|
mark_unavailble(bitmap, 0x4000000, bitmap);
|
||||||
|
|
||||||
// Now we want to map some stuff.
|
// Now we want to map some stuff.
|
||||||
// But first, we should load the kernel somewhere
|
// But first, we should load the kernel somewhere
|
||||||
|
|
||||||
uint8_t* kernel_location = (uint8_t*)0x542000; // Just load it at 0x524000 for now
|
uint8_t* kernel_location = 0x542000; // Just load it at 0x524000 for now
|
||||||
mark_unavailble((uint32_t)kernel_location, 0x20000, bitmap); // Just treat the kernel as not growing beyond 128k for now.
|
mark_unavailble(kernel_location, 0x10000, bitmap); // Just treat the kernel as not growing beyond 32k for now.
|
||||||
|
|
||||||
map_many_4k_phys_to_virt((uint32_t)kernel_location, 0xc0000000, kernel_page_directory, kernel_page_tables, 0x20); // Map 32 pages from 0x522000 to 0xc0000000;
|
map_many_4k_phys_to_virt(kernel_location, 0xc0000000, kernel_page_directory, kernel_page_tables, 0x10); // Map 16 pages from 0x522000 to 0xc0000000;
|
||||||
map_4k_phys_to_virt((uint32_t)kernel_page_directory, 0xc0100000, kernel_page_directory, kernel_page_tables); // Map the page directory to 0xc0100000
|
map_4k_phys_to_virt((uint32_t)kernel_page_directory, 0xc0100000, kernel_page_directory, kernel_page_tables); // Map the page directory to 0xc0100000
|
||||||
map_many_4k_phys_to_virt(0x121000, 0xc0101000, kernel_page_directory, kernel_page_tables, 1024); // Map 1024 pages from 0x121000 to 0xc0101000
|
map_many_4k_phys_to_virt(0x121000, 0xc0101000, kernel_page_directory, kernel_page_tables, 1024); // Map 1024 pages from 0x121000 to 0xc0101000
|
||||||
map_4k_phys_to_virt(0xb8000, 0xc0501000, kernel_page_directory, kernel_page_tables); // Map 0xb8000 (video) to 0xc0501000
|
map_4k_phys_to_virt(0xb8000, 0xc0501000, kernel_page_directory, kernel_page_tables); // Map 0xb8000 (video) to 0xc0501000
|
||||||
@ -148,12 +158,12 @@ void main() {
|
|||||||
mark_unavailble(0xa0000, 0x20000, bitmap);
|
mark_unavailble(0xa0000, 0x20000, bitmap);
|
||||||
|
|
||||||
|
|
||||||
uint8_t* vm_bitmap = (uint8_t*)0x522000;
|
uint8_t* vm_bitmap = 0x522000;
|
||||||
mark_unavailble((uint32_t)vm_bitmap, 0x20000, bitmap);
|
mark_unavailble(vm_bitmap, 0x20000, bitmap);
|
||||||
|
|
||||||
memset(vm_bitmap, 0x20000, 0xff);
|
memset(vm_bitmap, 0x20000, 0xff);
|
||||||
mark_unavailble(0xc07a0000, 0x20000, vm_bitmap);
|
mark_unavailble(0xc07a0000, 0x20000, vm_bitmap);
|
||||||
mark_unavailble(0xc0000000, 0x20000, vm_bitmap);
|
mark_unavailble(0xc0000000, 0x10000, vm_bitmap);
|
||||||
mark_unavailble(0xc0100000, 0x1000, vm_bitmap);
|
mark_unavailble(0xc0100000, 0x1000, vm_bitmap);
|
||||||
mark_unavailble(0xc0101000, 0x400000, vm_bitmap);
|
mark_unavailble(0xc0101000, 0x400000, vm_bitmap);
|
||||||
mark_unavailble(0xc0501000, 0x1000, vm_bitmap);
|
mark_unavailble(0xc0501000, 0x1000, vm_bitmap);
|
||||||
@ -173,31 +183,17 @@ void main() {
|
|||||||
map_many_4k_phys_to_virt(0x8a000, 0xc1000000, kernel_page_directory, kernel_page_tables, 16);
|
map_many_4k_phys_to_virt(0x8a000, 0xc1000000, kernel_page_directory, kernel_page_tables, 16);
|
||||||
mark_unavailble(0x8a000, 0x10000, bitmap);
|
mark_unavailble(0x8a000, 0x10000, bitmap);
|
||||||
|
|
||||||
// Identity map the first 1MiB of RAM
|
|
||||||
mark_unavailble(0, 0x100000, bitmap);
|
|
||||||
mark_unavailble(0, 0x100000, vm_bitmap);
|
|
||||||
map_many_4k_phys_to_virt_pl3(0, 0, kernel_page_directory, kernel_page_tables, 256);
|
|
||||||
|
|
||||||
load_file("KERNEL BIN", kernel_location);
|
load_file("KERNEL BIN", kernel_location);
|
||||||
|
|
||||||
|
printf("Stage2 success!\n");
|
||||||
|
|
||||||
|
//while (1);
|
||||||
|
|
||||||
asm volatile("mov %0, %%eax;"
|
asm volatile("mov %0, %%eax;"
|
||||||
"mov %%eax, %%cr3;"
|
"mov %%eax, %%cr3;"
|
||||||
"mov %%cr0, %%eax;"
|
"mov %%cr0, %%eax;"
|
||||||
"or $0x80000000, %%eax;"
|
"or $0x80000000, %%eax;"
|
||||||
"mov %%eax, %%cr0" : : "m" (kernel_page_directory));
|
"mov %%eax, %%cr0" : : "m" (kernel_page_directory));
|
||||||
|
|
||||||
asm volatile ("mov %0, %%esp":: "r"(0xc1000000 + 16*0x1000));
|
((void(*)(void))0xc0000000)();
|
||||||
|
|
||||||
KernelInformationStruct kstruct= (KernelInformationStruct){
|
|
||||||
.pde = (PDE*)0xc0100000,
|
|
||||||
.page_directory_phys_addr = (uint32_t)kernel_page_directory,
|
|
||||||
.page_directory_phys_offset = 0xc0100000 - (uint32_t)kernel_page_directory,
|
|
||||||
.page_bitmap_phys = 0xc0600000,
|
|
||||||
.page_bitmap_virt = 0xc0620000,
|
|
||||||
.stack_ptr = 0xc1000000 + 16*0x1000 - sizeof(KernelInformationStruct) - 4,
|
|
||||||
.vga_addr = 0xc07a0000,
|
|
||||||
.remainingPages = pages
|
|
||||||
};
|
|
||||||
|
|
||||||
((void(*)(KernelInformationStruct))0xc0000000)(kstruct);
|
|
||||||
}
|
}
|
@ -6,40 +6,6 @@ typedef struct {
|
|||||||
uint32_t pd_index : 10;
|
uint32_t pd_index : 10;
|
||||||
}__attribute__((packed)) split_addr;
|
}__attribute__((packed)) split_addr;
|
||||||
|
|
||||||
void map_4k_phys_to_virt_pl3(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables) {
|
|
||||||
split_addr* split = (split_addr*)&virtual;
|
|
||||||
|
|
||||||
page_directory[split->pd_index] = (PDE){
|
|
||||||
.address = (uint32_t)(page_tables[split->pd_index]) >> 12,
|
|
||||||
.available = 0,
|
|
||||||
.page_4mb = 0,
|
|
||||||
.accessed = 0,
|
|
||||||
.disable_cache = 0,
|
|
||||||
.write_through_cache = 0,
|
|
||||||
.privilege = 3,
|
|
||||||
.present = 1,
|
|
||||||
.read_write = 1,
|
|
||||||
|
|
||||||
.ignored = 0,
|
|
||||||
.ignored2 = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
page_tables[split->pd_index][split->pt_index] = (PTE){
|
|
||||||
.address = physical >> 12,
|
|
||||||
.available = 0,
|
|
||||||
.global = 0,
|
|
||||||
.accessed = 0,
|
|
||||||
.disable_cache = 0,
|
|
||||||
.dirty = 0,
|
|
||||||
.write_through_cache = 0,
|
|
||||||
.privilege = 3,
|
|
||||||
.present = 1,
|
|
||||||
.read_write = 1,
|
|
||||||
|
|
||||||
.ignored = 0
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void map_4k_phys_to_virt(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables) {
|
void map_4k_phys_to_virt(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables) {
|
||||||
split_addr* split = (split_addr*)&virtual;
|
split_addr* split = (split_addr*)&virtual;
|
||||||
|
|
||||||
@ -74,11 +40,6 @@ void map_4k_phys_to_virt(uint32_t physical, uint32_t virtual, PDE* page_director
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void map_many_4k_phys_to_virt_pl3(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables, uint32_t count) {
|
|
||||||
for (int i=0; i<count; i++)
|
|
||||||
map_4k_phys_to_virt_pl3(physical + 4096*i, virtual + 4096*i, page_directory, page_tables);
|
|
||||||
}
|
|
||||||
|
|
||||||
void map_many_4k_phys_to_virt(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables, uint32_t count) {
|
void map_many_4k_phys_to_virt(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables, uint32_t count) {
|
||||||
for (int i=0; i<count; i++)
|
for (int i=0; i<count; i++)
|
||||||
map_4k_phys_to_virt(physical + 4096*i, virtual + 4096*i, page_directory, page_tables);
|
map_4k_phys_to_virt(physical + 4096*i, virtual + 4096*i, page_directory, page_tables);
|
@ -34,5 +34,4 @@ typedef struct {
|
|||||||
|
|
||||||
void map_4k_phys_to_virt(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables);
|
void map_4k_phys_to_virt(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables);
|
||||||
void map_many_4k_phys_to_virt(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables, uint32_t count);
|
void map_many_4k_phys_to_virt(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables, uint32_t count);
|
||||||
void map_many_4k_phys_to_virt_pl3(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables, uint32_t count);
|
|
||||||
#endif
|
#endif
|
165
src/boot_stage2/screenstuff.c
Normal file
165
src/boot_stage2/screenstuff.c
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
#include "screenstuff.h"
|
||||||
|
|
||||||
|
uint16_t* VMEM_ADDR = (uint16_t*)0xb8000;
|
||||||
|
const int TERM_WIDTH = 80;
|
||||||
|
const int TERM_HEIGHT = 25;
|
||||||
|
|
||||||
|
int cursor_x = 0;
|
||||||
|
int cursor_y = 0;
|
||||||
|
|
||||||
|
uint16_t get_curpos() {
|
||||||
|
uint16_t cursor_position = 0;
|
||||||
|
uint8_t* cursor_position_split = (uint8_t*)&cursor_position;
|
||||||
|
outb(0x3D4, 0x0F);
|
||||||
|
cursor_position_split[0] = inb(0x3D5);
|
||||||
|
outb(0x3D4, 0x0E);
|
||||||
|
cursor_position_split[1] = inb(0x3D5);
|
||||||
|
return cursor_position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_term() {
|
||||||
|
uint16_t cursor_position = get_curpos();
|
||||||
|
|
||||||
|
cursor_y = cursor_position / TERM_WIDTH;
|
||||||
|
cursor_x = cursor_position % TERM_WIDTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_screen() {
|
||||||
|
for (int i=0; i<TERM_WIDTH*TERM_HEIGHT; i++) {
|
||||||
|
VMEM_ADDR[i] = 0x0720;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_line(int line) {
|
||||||
|
for (int x=0; x<TERM_WIDTH; x++) {
|
||||||
|
VMEM_ADDR[TERM_WIDTH*line + x] = 0x0720;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_curpos_raw(int curpos) {
|
||||||
|
uint8_t* cursor_position_split = (uint8_t*)&curpos;
|
||||||
|
outb(0x3D4, 0x0F);
|
||||||
|
outb(0x3D5, cursor_position_split[0]);
|
||||||
|
outb(0x3D4, 0x0E);
|
||||||
|
outb(0x3D5, cursor_position_split[1]);
|
||||||
|
|
||||||
|
cursor_x = (*(uint16_t*)cursor_position_split) % TERM_WIDTH;
|
||||||
|
cursor_y = (*(uint16_t*)cursor_position_split) / TERM_WIDTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_curpos(int x, int y) {
|
||||||
|
set_curpos_raw(y * TERM_WIDTH + x);
|
||||||
|
|
||||||
|
cursor_x = x;
|
||||||
|
cursor_y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
int int_to_decimal(unsigned int number, char* string_buffer) {
|
||||||
|
for (int i=0; i<11; i++)
|
||||||
|
string_buffer[i] = 0;
|
||||||
|
|
||||||
|
int index = 9;
|
||||||
|
unsigned int acc = number;
|
||||||
|
if (acc == 0)
|
||||||
|
string_buffer[index--] = '0';
|
||||||
|
while (acc != 0) {
|
||||||
|
string_buffer[index--] = 0x30+(acc%10);
|
||||||
|
acc /= 10;
|
||||||
|
}
|
||||||
|
return (index+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
char dec_to_hex[16] = "0123456789abcdef";
|
||||||
|
int int_to_hex(unsigned int number, char* string_buffer) {
|
||||||
|
for (int i=0; i<8; i++)
|
||||||
|
string_buffer[i] = '0';
|
||||||
|
string_buffer[8] = 0;
|
||||||
|
|
||||||
|
int index = 7;
|
||||||
|
unsigned int acc = number;
|
||||||
|
if (acc == 0)
|
||||||
|
string_buffer[index--] = '0';
|
||||||
|
while (acc != 0) {
|
||||||
|
string_buffer[index--] = dec_to_hex[acc%0x10];
|
||||||
|
acc /= 0x10;
|
||||||
|
}
|
||||||
|
return (index+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printf(const char* string, ...) {
|
||||||
|
va_list ptr;
|
||||||
|
va_start(ptr, string);
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
int count = 0;
|
||||||
|
char current;
|
||||||
|
while (current=string[index++]) {
|
||||||
|
count++;
|
||||||
|
if (current == '\n') {
|
||||||
|
cursor_x = 0;
|
||||||
|
cursor_y++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor_x == TERM_WIDTH) {
|
||||||
|
cursor_x = 0;
|
||||||
|
cursor_y++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor_y == TERM_HEIGHT) {
|
||||||
|
for (int i=1; i<TERM_HEIGHT; i++) {
|
||||||
|
for (int x=0; x<TERM_WIDTH; x++) {
|
||||||
|
int from = i * TERM_WIDTH + x;
|
||||||
|
int to = (i-1) * TERM_WIDTH + x;
|
||||||
|
VMEM_ADDR[to] = VMEM_ADDR[from];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clear_line(24);
|
||||||
|
cursor_y--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current == '%') {
|
||||||
|
int type = string[index++];
|
||||||
|
int offset;
|
||||||
|
switch (type) {
|
||||||
|
case 'd': {
|
||||||
|
char decimal_buffer[11];
|
||||||
|
offset = int_to_decimal(va_arg(ptr, int), decimal_buffer);
|
||||||
|
printf(decimal_buffer + offset);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'x': {
|
||||||
|
char hex_buffer[8];
|
||||||
|
offset = int_to_hex(va_arg(ptr, int), hex_buffer);
|
||||||
|
printf(hex_buffer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 's': {
|
||||||
|
printf(va_arg(ptr, const char*));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'c': {
|
||||||
|
int mem_pos = cursor_y * TERM_WIDTH + cursor_x++;
|
||||||
|
int promoted = va_arg(ptr, int);
|
||||||
|
char charred = promoted;
|
||||||
|
VMEM_ADDR[mem_pos] = charred + (0x07<<8);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current != '\n') {
|
||||||
|
int mem_pos = cursor_y * TERM_WIDTH + cursor_x++;
|
||||||
|
VMEM_ADDR[mem_pos] = current + (0x07<<8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set_curpos(cursor_x, cursor_y);
|
||||||
|
|
||||||
|
va_end(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void non_moving_put(char chr) {
|
||||||
|
int mem_pos = cursor_y * TERM_WIDTH + cursor_x;
|
||||||
|
VMEM_ADDR[mem_pos] = chr + (0x07<<8);
|
||||||
|
}
|
19
src/boot_stage2/screenstuff.h
Normal file
19
src/boot_stage2/screenstuff.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef SCREENSTUFF_H
|
||||||
|
#define SCREENSTUFF_H
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include "types.h"
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
|
uint16_t get_curpos();
|
||||||
|
void init_term();
|
||||||
|
void clear_screen();
|
||||||
|
void clear_line(int line);
|
||||||
|
void set_curpos_raw(int curpos);
|
||||||
|
void set_curpos(int x, int y);
|
||||||
|
int int_to_decimal(unsigned int number, char* string_buffer);
|
||||||
|
int int_to_hex(unsigned int number, char* string_buffer);
|
||||||
|
void printf(const char* string, ...);
|
||||||
|
void non_moving_put(char chr);
|
||||||
|
|
||||||
|
#endif
|
69
src/boot_stage2/strings.c
Normal file
69
src/boot_stage2/strings.c
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
#include "strings.h"
|
||||||
|
|
||||||
|
bool strcmp(char* a, char* b, int max) {
|
||||||
|
int index = 0;
|
||||||
|
while (index < max) {
|
||||||
|
if (a[index] != b[index])
|
||||||
|
return false;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* split_on_first(char delimeter, char* string) {
|
||||||
|
int index = 0;
|
||||||
|
char current;
|
||||||
|
|
||||||
|
while (current = string[index++]) {
|
||||||
|
if (current == delimeter) {
|
||||||
|
string[index-1] = 0;
|
||||||
|
return string+index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int string_split(char delimeter, char* string, char** pointer_array) {
|
||||||
|
int index = 0;
|
||||||
|
int last_split_index = 0;
|
||||||
|
int split_count = 0;
|
||||||
|
|
||||||
|
char current;
|
||||||
|
|
||||||
|
while (current = string[index]) {
|
||||||
|
if (current == delimeter) {
|
||||||
|
string[index] = 0;
|
||||||
|
pointer_array[split_count++] = (string+last_split_index);
|
||||||
|
last_split_index = (index+1);
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add remaining part of the string to the pointer_array
|
||||||
|
pointer_array[split_count] = (string+last_split_index);
|
||||||
|
|
||||||
|
return split_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void decode_filename(char* nice_name, char* filenamebuffer) {
|
||||||
|
// Clear filenamebuffer
|
||||||
|
for (int i=0; i<11; i++)
|
||||||
|
filenamebuffer[i] = ' ';
|
||||||
|
filenamebuffer[11] = 0;
|
||||||
|
|
||||||
|
int fbIndex = 0;
|
||||||
|
for (int i=0; i<12; i++) {
|
||||||
|
if (nice_name[i] == 0)
|
||||||
|
return;
|
||||||
|
if (nice_name[i] == '.') {
|
||||||
|
fbIndex = 8;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nice_name[i] >= 0x61 && nice_name[i] <= 0x7f)
|
||||||
|
filenamebuffer[fbIndex++] = nice_name[i] - 32;
|
||||||
|
else
|
||||||
|
filenamebuffer[fbIndex++] = nice_name[i];
|
||||||
|
}
|
||||||
|
}
|
11
src/boot_stage2/strings.h
Normal file
11
src/boot_stage2/strings.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef STRINGS_H
|
||||||
|
#define STRINGS_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
bool strcmp(char* a, char* b, int max);
|
||||||
|
char* split_on_first(char delimeter, char* string);
|
||||||
|
int string_split(char delimeter, char* string, char** pointer_array);
|
||||||
|
void decode_filename(char* nice_name, char* filenamebuffer);
|
||||||
|
|
||||||
|
#endif
|
@ -1,11 +0,0 @@
|
|||||||
#include "strings.h"
|
|
||||||
|
|
||||||
bool strcmp(char* a, char* b, int max) {
|
|
||||||
int index = 0;
|
|
||||||
while (index < max) {
|
|
||||||
if (a[index] != b[index])
|
|
||||||
return false;
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
#ifndef STRINGS_H
|
|
||||||
#define STRINGS_H
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
bool strcmp(char* a, char* b, int max);
|
|
||||||
|
|
||||||
#endif
|
|
@ -3,7 +3,6 @@
|
|||||||
_start:
|
_start:
|
||||||
mov ax, 10h
|
mov ax, 10h
|
||||||
mov ds, ax
|
mov ds, ax
|
||||||
mov es, ax
|
|
||||||
mov ss, ax
|
mov ss, ax
|
||||||
mov esp, 90000h
|
mov esp, 90000h
|
||||||
|
|
||||||
|
@ -1,81 +1,5 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
#define syscall_hdlr_0(a, b, c) \
|
|
||||||
a b() { \
|
|
||||||
asm volatile("mov $" c ", %%eax; int $0x80" : : :); \
|
|
||||||
}
|
|
||||||
#define syscall_hdlr_1(a, b, c, d, e) \
|
|
||||||
a b(d e) { \
|
|
||||||
asm volatile("mov $" c ", %%eax; mov %0, %%ebx; int $0x80" : : "m" (e) : "ebx"); \
|
|
||||||
}
|
|
||||||
#define syscall_hdlr_2(a, b, c, d, e, f, g) \
|
|
||||||
a b(d e, f g) { \
|
|
||||||
asm volatile("mov $" c ", %%eax; mov %0, %%ebx; mov %1, %%ecx; int $0x80" : : "m" (e), "m" (g) : "ebx", "ecx"); \
|
|
||||||
}
|
|
||||||
#define syscall_hdlr_3(a, b, c, d, e, f, g, h, i) \
|
|
||||||
a b(d e, f g, h i) { \
|
|
||||||
asm volatile("mov $" c ", %%eax; mov %0, %%ebx; mov %1, %%ecx; mov %2, %%edx; int $0x80" : : "m" (e), "m" (g), "m" (i) : "ebx", "ecx", "edx"); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "syscalls.h"
|
|
||||||
|
|
||||||
char** environ = 0;
|
|
||||||
|
|
||||||
uint32_t strcmpc(char* a, char* b, char c) {
|
|
||||||
for (int i=0; a[i] && b[i]; i++) {
|
|
||||||
if (a[i] == c)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void __setup(uint32_t argc, char** argv, char** envp) {
|
|
||||||
environ = envp;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* getenv(char* key) {
|
|
||||||
for (int i=0; environ[i]; i++) {
|
|
||||||
uint32_t pos;
|
|
||||||
if (pos = strcmpc(environ[i], key, '=')) {
|
|
||||||
return key+pos+1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setenv(char* key, char* value) {
|
|
||||||
uint32_t environ_count = 0;
|
|
||||||
for (int i=0; environ[i]; i++)
|
|
||||||
environ_count += 1;
|
|
||||||
char** new_environ = (char**)malloc((environ_count+2)*sizeof(char*));
|
|
||||||
for (int i=0; i<environ_count; i++)
|
|
||||||
new_environ[i] = environ[i];
|
|
||||||
|
|
||||||
uint32_t key_size = strlen(key);
|
|
||||||
uint32_t value_size = strlen(value);
|
|
||||||
char* new_entry = (char*)malloc(key_size + value_size + 2);
|
|
||||||
memcpy(new_entry, key, key_size);
|
|
||||||
new_entry[key_size] = '=';
|
|
||||||
memcpy(new_entry+key_size+1, value, value_size);
|
|
||||||
new_entry[key_size+1+value_size] = 0;
|
|
||||||
new_environ[environ_count] = new_entry;
|
|
||||||
new_environ[environ_count+1] = 0;
|
|
||||||
environ = new_environ;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t strlen(char* s) {
|
|
||||||
uint32_t i=0;
|
|
||||||
while (s[i]) i++;
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool strcmp(char* a, char* b) {
|
|
||||||
for (int i=0; a[i] && b[i]; i++)
|
|
||||||
if (a[i] != b[i])
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void print(char* string) {
|
void print(char* string) {
|
||||||
char* c = string;
|
char* c = string;
|
||||||
int i=0;
|
int i=0;
|
||||||
@ -84,6 +8,54 @@ void print(char* string) {
|
|||||||
write(i, 0, (uint8_t*)string);
|
write(i, 0, (uint8_t*)string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* localalloc(uint32_t size) {
|
||||||
|
asm volatile ("mov $4, %%eax; mov %0, %%esi; int $0x7f" : : "m" (size) : "esi");
|
||||||
|
}
|
||||||
|
|
||||||
|
void localdelete(void* ptr) {
|
||||||
|
asm volatile ("mov $5, %%eax; mov %0, %%esi; int $0x7f" : : "m" (ptr) : "esi");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t getPID() {
|
||||||
|
asm volatile ("mov $8, %%eax; int $0x7f" : : :);
|
||||||
|
}
|
||||||
|
|
||||||
|
int read(uint32_t count, void* filehanlder, uint8_t* buffer) {
|
||||||
|
asm volatile ("mov $10, %%eax; mov %0, %%ebx; mov %1, %%esi; mov %2, %%edi; int $0x7f" : : "m" (count), "m" (filehanlder), "m" (buffer): "ebx", "esi", "edi");
|
||||||
|
}
|
||||||
|
|
||||||
|
int write(uint32_t count, void* filehanlder, uint8_t* buffer) {
|
||||||
|
asm volatile ("mov $11, %%eax; mov %0, %%ebx; mov %1, %%esi; mov %2, %%edi; int $0x7f" : : "m" (count), "m" (filehanlder), "m" (buffer): "ebx", "esi", "edi");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t fork(uint32_t fh) {
|
||||||
|
asm volatile("mov $7, %%eax; mov %0, %%esi; int $0x7f" : : "m" (fh) : "esi");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t bindStdout(uint32_t PID) {
|
||||||
|
asm volatile("mov $13, %%eax; mov %0, %%esi; int $0x7f" : : "m" (PID) : "esi");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t bindStdin(uint32_t PID) {
|
||||||
|
asm volatile("mov $14, %%eax; mov %0, %%esi; int $0x7f" : : "m" (PID) : "esi");
|
||||||
|
}
|
||||||
|
|
||||||
|
int fopen(char* filename) {
|
||||||
|
asm volatile("mov $15, %%eax; mov %0, %%esi; int $0x7f" : : "m" (filename) : "esi");
|
||||||
|
}
|
||||||
|
|
||||||
|
void fclose(uint32_t fh) {
|
||||||
|
asm volatile("mov $16, %%eax; mov %0, %%esi; int $0x7f" : : "m" (fh) : "esi");
|
||||||
|
}
|
||||||
|
|
||||||
|
void kill(uint32_t pid) {
|
||||||
|
asm volatile("mov $17, %%eax; mov %0, %%esi; int $0x7f" : : "m" (pid) : "esi");
|
||||||
|
}
|
||||||
|
|
||||||
|
void bindToKeyboard() {
|
||||||
|
asm volatile ("mov $12, %%eax; int $0x7f" : : :);
|
||||||
|
}
|
||||||
|
|
||||||
int int_to_decimal(unsigned int number, char* string_buffer) {
|
int int_to_decimal(unsigned int number, char* string_buffer) {
|
||||||
for (int i=0; i<11; i++)
|
for (int i=0; i<11; i++)
|
||||||
string_buffer[i] = 0;
|
string_buffer[i] = 0;
|
||||||
@ -115,96 +87,3 @@ int int_to_hex(unsigned int number, char* string_buffer) {
|
|||||||
}
|
}
|
||||||
return (index+1);
|
return (index+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isnum(char c) {
|
|
||||||
return c >= 0x30 && c <= 0x39;
|
|
||||||
}
|
|
||||||
|
|
||||||
void printf(const char* string, ...) {
|
|
||||||
va_list ptr;
|
|
||||||
va_start(ptr, string);
|
|
||||||
|
|
||||||
int index = 0;
|
|
||||||
char current;
|
|
||||||
|
|
||||||
while (current=string[index++]) {
|
|
||||||
if (current == '%') {
|
|
||||||
uint32_t width = 0;
|
|
||||||
bool lp = false;
|
|
||||||
if (string[index] == '.') {
|
|
||||||
lp = true;
|
|
||||||
index++;
|
|
||||||
} else {
|
|
||||||
while (isnum(string[index])) {
|
|
||||||
width *= 10;
|
|
||||||
width += string[index] - 0x30;
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int type = string[index++];
|
|
||||||
int offset;
|
|
||||||
switch (type) {
|
|
||||||
case 'd': {
|
|
||||||
char decimal_buffer[11];
|
|
||||||
offset = int_to_decimal(va_arg(ptr, int), decimal_buffer);
|
|
||||||
print(decimal_buffer + offset);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'x': {
|
|
||||||
char hex_buffer[8];
|
|
||||||
offset = int_to_hex(va_arg(ptr, int), hex_buffer);
|
|
||||||
print(hex_buffer);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 's': {
|
|
||||||
if (width) {
|
|
||||||
char s[width+1];
|
|
||||||
s[width] = 0;
|
|
||||||
memcpy(s, va_arg(ptr, const char*), width);
|
|
||||||
print(s);
|
|
||||||
} else if (lp) {
|
|
||||||
int width = va_arg(ptr, int);
|
|
||||||
char s[width+1];
|
|
||||||
s[width] = 0;
|
|
||||||
memcpy(s, va_arg(ptr, const char*), width);
|
|
||||||
print(s);
|
|
||||||
} else {
|
|
||||||
print(va_arg(ptr, const char*));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'c': {
|
|
||||||
int promoted = va_arg(ptr, int);
|
|
||||||
char charred = promoted;
|
|
||||||
|
|
||||||
write(1, 0, &charred);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
write(1, 0, ¤t);
|
|
||||||
}
|
|
||||||
|
|
||||||
va_end(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void memset(void* ptr, char c, uint32_t count) {
|
|
||||||
for (int i=0; i<count; i++) {
|
|
||||||
((char*)ptr)[i] = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void memcpy(void* dst, void* src, uint32_t count) {
|
|
||||||
for (int i=0; i<count; i++)
|
|
||||||
((char*)dst)[i] = ((char*)src)[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t exec(uint32_t fh) {
|
|
||||||
uint8_t* zero = 0;
|
|
||||||
return execve(fh, &zero, (uint8_t**)environ);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t execv(uint32_t fh, char** argv) {
|
|
||||||
return execve(fh, (uint8_t**)argv, (uint8_t**)environ);
|
|
||||||
}
|
|
@ -2,57 +2,28 @@
|
|||||||
#define COMMON_H
|
#define COMMON_H
|
||||||
|
|
||||||
#include "../kernel/types.h"
|
#include "../kernel/types.h"
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
File,
|
|
||||||
Directory,
|
|
||||||
CharacterDev,
|
|
||||||
BlockDev,
|
|
||||||
NoExist
|
|
||||||
} FSType;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint16_t length;
|
|
||||||
uint8_t* path;
|
|
||||||
} PathEntry;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
PathEntry path;
|
|
||||||
FSType type;
|
|
||||||
uint32_t sizeBytes;
|
|
||||||
} FSDirectoryEntry;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t count;
|
|
||||||
uint32_t stringsLength;
|
|
||||||
FSDirectoryEntry entries[];
|
|
||||||
} FSDirectoryListing;
|
|
||||||
|
|
||||||
#define syscall_hdlr_0(a, b, c) \
|
|
||||||
a b();
|
|
||||||
#define syscall_hdlr_1(a, b, c, d, e) \
|
|
||||||
a b(d e);
|
|
||||||
#define syscall_hdlr_2(a, b, c, d, e, f, g) \
|
|
||||||
a b(d e, f g);
|
|
||||||
#define syscall_hdlr_3(a, b, c, d, e, f, g, h, i) \
|
|
||||||
a b(d e, f g, h i);
|
|
||||||
|
|
||||||
#include "syscalls.h"
|
|
||||||
|
|
||||||
char* getenv(char* key);
|
|
||||||
void setenv(char* key, char* value);
|
|
||||||
uint32_t strlen(char* s);
|
|
||||||
bool strcmp(char* a, char* b);
|
|
||||||
|
|
||||||
void memset(void* ptr, char c, uint32_t count);
|
|
||||||
void memcpy(void* dst, void* src, uint32_t count);
|
|
||||||
void print(char* string);
|
void print(char* string);
|
||||||
|
void readfile(char* filename, uint8_t* buffer);
|
||||||
|
void* localalloc(uint32_t size);
|
||||||
|
void localdelete(void* ptr);
|
||||||
|
uint32_t filesize(char* filename);
|
||||||
|
|
||||||
|
uint32_t fork(uint32_t fh);
|
||||||
|
uint32_t bindStdout(uint32_t PID);
|
||||||
|
uint32_t bindStdin(uint32_t PID);
|
||||||
|
|
||||||
|
uint32_t getPID();
|
||||||
|
|
||||||
|
int read(uint32_t count, void* filehandler, uint8_t* buffer);
|
||||||
|
int write(uint32_t count, void* filehandler, uint8_t* buffer);
|
||||||
|
void bindToKeyboard();
|
||||||
|
|
||||||
|
int fopen(char* filename);
|
||||||
|
void fclose(uint32_t fh);
|
||||||
|
void kill(uint32_t pid);
|
||||||
|
|
||||||
int int_to_decimal(unsigned int number, char* string_buffer);
|
int int_to_decimal(unsigned int number, char* string_buffer);
|
||||||
int int_to_hex(unsigned int number, char* string_buffer);
|
int int_to_hex(unsigned int number, char* string_buffer);
|
||||||
void printf(const char* string, ...);
|
|
||||||
|
|
||||||
uint32_t exec(uint32_t fh);
|
|
||||||
uint32_t execv(uint32_t fh, char** argv);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -1,31 +0,0 @@
|
|||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
syscall_hdlr_1(uint32_t, getDentsSize, "0", char*, path);
|
|
||||||
syscall_hdlr_2(void, getDents, "1", char*, path, uint8_t*, buffer);
|
|
||||||
syscall_hdlr_1(bool, exists, "2", char*, path);
|
|
||||||
syscall_hdlr_1(FSType, type, "3", char*, path);
|
|
||||||
syscall_hdlr_1(void*, malloc, "4", uint32_t, size);
|
|
||||||
syscall_hdlr_1(void, free, "5", void*, ptr);
|
|
||||||
syscall_hdlr_0(uint32_t, getMillisecondsElapsed, "6");
|
|
||||||
syscall_hdlr_3(uint32_t, execve, "7", uint32_t, fh, uint8_t**, argv, uint8_t**, envp);
|
|
||||||
syscall_hdlr_0(uint32_t, getPID, "8");
|
|
||||||
syscall_hdlr_1(void, die, "9", uint32_t, exit);
|
|
||||||
syscall_hdlr_3(int, read, "10", uint32_t, count, uint32_t, filehandler, uint8_t*, buffer);
|
|
||||||
syscall_hdlr_3(int, write, "11", uint32_t, count, uint32_t, filehandler, const uint8_t*, buffer);
|
|
||||||
syscall_hdlr_0(void, bindToKeyboard, "12");
|
|
||||||
syscall_hdlr_1(uint32_t, bindStdout, "13", uint32_t, PID);
|
|
||||||
syscall_hdlr_1(uint32_t, bindStdin, "14", uint32_t, PID);
|
|
||||||
syscall_hdlr_1(uint32_t, fopen, "15", char*, filename);
|
|
||||||
syscall_hdlr_1(void, fclose, "16", uint32_t, filehandler);
|
|
||||||
syscall_hdlr_1(void, kill, "17", uint32_t, PID);
|
|
||||||
syscall_hdlr_1(void, sleep, "18", uint32_t, time);
|
|
||||||
|
|
||||||
syscall_hdlr_0(uint32_t, getRemainingPages, "19");
|
|
||||||
syscall_hdlr_0(uint32_t, getInitPages, "20");
|
|
||||||
syscall_hdlr_0(uint32_t, getCurrentTerminalWidth, "21");
|
|
||||||
syscall_hdlr_0(uint32_t, getCurrentTerminalHeight, "22");
|
|
||||||
syscall_hdlr_1(uint32_t, getProcessState, "23", uint32_t, PID);
|
|
||||||
|
|
||||||
syscall_hdlr_1(void, spawnThread, "24", uint32_t, functionPointer);
|
|
||||||
syscall_hdlr_0(uint32_t, fork, "25");
|
|
||||||
syscall_hdlr_1(bool, programRunning, "26", uint32_t, pid);
|
|
40
src/hello/hello.c
Normal file
40
src/hello/hello.c
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#include "../common/common.h"
|
||||||
|
|
||||||
|
void readline(int count, char* buffer) {
|
||||||
|
int index = 0;
|
||||||
|
char c;
|
||||||
|
while (index < count) {
|
||||||
|
if (read(1, 1, &c)) {
|
||||||
|
if (c == '\n')
|
||||||
|
break;
|
||||||
|
if (c == '\b') {
|
||||||
|
if (index == 0)
|
||||||
|
continue;
|
||||||
|
else {
|
||||||
|
index--;
|
||||||
|
buffer[index] = 0;
|
||||||
|
write(1, 0, &c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[index++] = c;
|
||||||
|
write(1, 0, &c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
print("Hello, World!\n");
|
||||||
|
char buffer[32];
|
||||||
|
while (1) {
|
||||||
|
for (int i=0; i<32; i++)
|
||||||
|
buffer[i] = 0;
|
||||||
|
print(">>> ");
|
||||||
|
readline(32, buffer);
|
||||||
|
print("You said: ");
|
||||||
|
print(buffer);
|
||||||
|
print("\n\n");
|
||||||
|
}
|
||||||
|
}
|
14
src/hello/hello.ld
Normal file
14
src/hello/hello.ld
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
OUTPUT_FORMAT(binary)
|
||||||
|
OUTPUT_ARCH(i386:i386)
|
||||||
|
|
||||||
|
OUTPUT(build/hello/hello.bin)
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
. = 0x20;
|
||||||
|
|
||||||
|
.text : {
|
||||||
|
build/program_code_entry.o(.text)
|
||||||
|
build/hello/hello.o(.text)
|
||||||
|
build/common/common.o(.text)
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,12 @@ uint32_t kernel_allocate_area = 0xf0000000;
|
|||||||
|
|
||||||
uint32_t last_free_page = 0;
|
uint32_t last_free_page = 0;
|
||||||
|
|
||||||
|
/*void init_allocator() {
|
||||||
|
for (int i=0; i<1024; i++) {
|
||||||
|
kernel_page_tables[i] = 0xc0101000 + 0x1000*i;
|
||||||
|
}
|
||||||
|
}*/ // Don't do this.
|
||||||
|
|
||||||
void set_bit(uint32_t offset, uint8_t* buffer) {
|
void set_bit(uint32_t offset, uint8_t* buffer) {
|
||||||
uint32_t index = offset / 8;
|
uint32_t index = offset / 8;
|
||||||
uint32_t bit = offset % 8;
|
uint32_t bit = offset % 8;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "paging.h"
|
#include "paging.h"
|
||||||
#include "datatypes/tuple.h"
|
#include "datatypes/tuple.h"
|
||||||
|
//void init_allocator();
|
||||||
|
|
||||||
extern uint8_t* bitmap;
|
extern uint8_t* bitmap;
|
||||||
extern PDE* kernel_page_directory;
|
extern PDE* kernel_page_directory;
|
||||||
|
@ -1,169 +0,0 @@
|
|||||||
#include "ata.h"
|
|
||||||
|
|
||||||
uint16_t controlBase[4] = {0x1f0, 0x170, 0x1e8, 0x168};
|
|
||||||
uint16_t dcrBase[4] = {0x3f6, 0x376, 0x3e6, 0x366};
|
|
||||||
|
|
||||||
uint8_t ATA::readStatus() {
|
|
||||||
uint8_t status;
|
|
||||||
for (int i=0; i<15; i++)
|
|
||||||
status=StatusRegister.readb();
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t ATA::pollTillNotBSY() {
|
|
||||||
uint8_t lastStatus;
|
|
||||||
while (((lastStatus=StatusRegister.readb()) & 0x80))
|
|
||||||
if (lastStatus&0x1)
|
|
||||||
return lastStatus;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t ATA::pollTillDRQ() {
|
|
||||||
uint8_t lastStatus;
|
|
||||||
while (!((lastStatus=StatusRegister.readb()) & 0x8))
|
|
||||||
if (lastStatus&0x1)
|
|
||||||
return lastStatus;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ATA::ATA(uint32_t bus) :
|
|
||||||
DataRegister(controlBase[bus]+0),
|
|
||||||
ErrorRegister(controlBase[bus]+1),
|
|
||||||
FeaturesRegister(controlBase[bus]+1),
|
|
||||||
SectorCountRegister(controlBase[bus]+2),
|
|
||||||
LBALo(controlBase[bus]+3),
|
|
||||||
LBAMid(controlBase[bus]+4),
|
|
||||||
LBAHi(controlBase[bus]+5),
|
|
||||||
DriveSelectRegister(controlBase[bus]+6),
|
|
||||||
StatusRegister(controlBase[bus]+7),
|
|
||||||
CommandRegister(controlBase[bus]+7) {
|
|
||||||
this->isValid = 0;
|
|
||||||
|
|
||||||
DriveSelectRegister.writeb(0xA0);
|
|
||||||
LBALo.writeb(0);
|
|
||||||
LBAMid.writeb(0);
|
|
||||||
LBAHi.writeb(0);
|
|
||||||
CommandRegister.writeb(0xEC);
|
|
||||||
|
|
||||||
if (!readStatus()) {
|
|
||||||
this->isValid = false;
|
|
||||||
} else {
|
|
||||||
pollTillNotBSY();
|
|
||||||
uint8_t LBAmid;
|
|
||||||
uint8_t LBAhi;
|
|
||||||
if ((LBAmid = LBAMid.readb()) || (LBAhi = LBAHi.readb())) {
|
|
||||||
this->isValid = false;
|
|
||||||
} else {
|
|
||||||
uint8_t status = pollTillDRQ();
|
|
||||||
if (!(status&0x1)) {
|
|
||||||
for (int i=0; i<256; i++)
|
|
||||||
((uint16_t*)identifyResult)[i] = DataRegister.readw();
|
|
||||||
this->isValid = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this->isValid) {
|
|
||||||
this->totalLBA28Sectors = *((uint32_t*)(identifyResult+60));
|
|
||||||
this->diskSize = this->totalLBA28Sectors * 512;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ATA::validDevice() {
|
|
||||||
return this->isValid;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ATA::ATARead(uint32_t sector, uint8_t* buffer) {
|
|
||||||
driveLock.lock();
|
|
||||||
DriveSelectRegister.writeb(0xE0 | ((sector >> 24) & 0xf));
|
|
||||||
SectorCountRegister.writeb(1);
|
|
||||||
LBALo.writeb((uint8_t)sector);
|
|
||||||
LBAMid.writeb((uint8_t)(sector>>8));
|
|
||||||
LBAHi.writeb((uint8_t)(sector>>16));
|
|
||||||
CommandRegister.writeb(0x20);
|
|
||||||
pollTillNotBSY();
|
|
||||||
for (int i=0; i<256; i++)
|
|
||||||
((uint16_t*)buffer)[i] = DataRegister.readw();
|
|
||||||
driveLock.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ATA::ATAWrite(uint32_t sector, uint8_t* buffer) {
|
|
||||||
driveLock.lock();
|
|
||||||
DriveSelectRegister.writeb(0xE0 | ((sector >> 24) & 0xf));
|
|
||||||
SectorCountRegister.writeb(1);
|
|
||||||
LBALo.writeb((uint8_t)sector);
|
|
||||||
LBAMid.writeb((uint8_t)(sector>>8));
|
|
||||||
LBAHi.writeb((uint8_t)(sector>>16));
|
|
||||||
CommandRegister.writeb(0x30);
|
|
||||||
pollTillNotBSY();
|
|
||||||
for (int i=0; i<256; i++)
|
|
||||||
DataRegister.writew(((uint16_t*)buffer)[i]);
|
|
||||||
CommandRegister.writeb(0xe7);
|
|
||||||
driveLock.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
ATAReadWriter::ATAReadWriter(uint32_t bus):
|
|
||||||
ATA(bus) {
|
|
||||||
this->currentPosition = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t ATAReadWriter::read(uint32_t count, uint8_t* buffer) {
|
|
||||||
driveLock.lock();
|
|
||||||
uint32_t remainingBytes = count;
|
|
||||||
uint32_t inThisSector = currentPosition % 512;
|
|
||||||
|
|
||||||
uint32_t index=0;
|
|
||||||
|
|
||||||
uint32_t c=0;
|
|
||||||
|
|
||||||
ATARead(currentPosition / 512, sectorBuffer);
|
|
||||||
while (remainingBytes) {
|
|
||||||
if (currentPosition >= diskSize)
|
|
||||||
break;
|
|
||||||
buffer[index++] = sectorBuffer[inThisSector++];
|
|
||||||
remainingBytes--;
|
|
||||||
currentPosition++;
|
|
||||||
if (inThisSector == 512) {
|
|
||||||
ATARead(currentPosition / 512, sectorBuffer);
|
|
||||||
inThisSector = 0;
|
|
||||||
}
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
driveLock.unlock();
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
uint32_t ATAReadWriter::write(uint32_t count, uint8_t* buffer) {
|
|
||||||
driveLock.lock();
|
|
||||||
uint32_t remainingBytes = count;
|
|
||||||
uint32_t inThisSector = currentPosition % 512;
|
|
||||||
|
|
||||||
uint32_t index=0;
|
|
||||||
|
|
||||||
uint32_t c=0;
|
|
||||||
|
|
||||||
ATARead(currentPosition / 512, sectorBuffer);
|
|
||||||
while (remainingBytes) {
|
|
||||||
if (currentPosition >= diskSize)
|
|
||||||
break;
|
|
||||||
sectorBuffer[inThisSector++] = buffer[index++];
|
|
||||||
remainingBytes--;
|
|
||||||
currentPosition++;
|
|
||||||
if (inThisSector == 512) {
|
|
||||||
ATAWrite((currentPosition / 512) - 1, sectorBuffer);
|
|
||||||
ATARead(currentPosition / 512, sectorBuffer);
|
|
||||||
inThisSector = 0;
|
|
||||||
}
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
// Perform a final write to ensure that we've written everything to disk.
|
|
||||||
ATAWrite((currentPosition / 512), sectorBuffer);
|
|
||||||
driveLock.unlock();
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
uint32_t ATAReadWriter::size() {
|
|
||||||
return this->diskSize;
|
|
||||||
}
|
|
||||||
uint32_t ATAReadWriter::seek(uint32_t position) {
|
|
||||||
this->currentPosition = position;
|
|
||||||
return position;
|
|
||||||
}
|
|
110
src/kernel/ata.h
110
src/kernel/ata.h
@ -1,110 +0,0 @@
|
|||||||
#ifndef ATA_PIO
|
|
||||||
#define ATA_PIO
|
|
||||||
|
|
||||||
#include "io.h"
|
|
||||||
#include "types.h"
|
|
||||||
#include "strings.h"
|
|
||||||
#include "global.h"
|
|
||||||
|
|
||||||
#include "stdio/readwriter.h"
|
|
||||||
|
|
||||||
#include "spinlock.h"
|
|
||||||
|
|
||||||
// Bus 0
|
|
||||||
// Control Ports: 1F0-1F7
|
|
||||||
// DCR / Alt Status: 3F6
|
|
||||||
// IRQ: 14
|
|
||||||
|
|
||||||
// Bus 1
|
|
||||||
// Control Ports: 170-177
|
|
||||||
// DCR / Alt Status: 376
|
|
||||||
// IRQ: 15
|
|
||||||
|
|
||||||
// Bus 2
|
|
||||||
// Control Ports: 1E8-1EF
|
|
||||||
// DCR / Alt Status: 3E6
|
|
||||||
// IRQ: Determine via PCI
|
|
||||||
|
|
||||||
// Bus 3
|
|
||||||
// Control Ports: 168-16F
|
|
||||||
// DCR / Alt Status: 366
|
|
||||||
// IRQ: Determine via PCI
|
|
||||||
|
|
||||||
// Control Port Map
|
|
||||||
// Name | RW | Offset | Size28 | Size48
|
|
||||||
// Data Register RW 0 2 2
|
|
||||||
// Error Register R 1 1 2
|
|
||||||
// Features Reg. W 1 1 2
|
|
||||||
// Sector Count Reg. RW 2 1 2
|
|
||||||
// LBAlo RW 3 1 2
|
|
||||||
// LBAmid RW 4 1 2
|
|
||||||
// LBAhi RW 5 1 2
|
|
||||||
// Drive Select RW 6 1 1
|
|
||||||
// Status Reg R 7 1 1
|
|
||||||
// Command Reg W 7 1 1
|
|
||||||
|
|
||||||
// DCR Port Map
|
|
||||||
// Name | RW | Offset | Size28 | Size48
|
|
||||||
// Alt. Status R 0 1 1
|
|
||||||
// Device Control W 1 1 1
|
|
||||||
// Device Address R 1 1 1
|
|
||||||
|
|
||||||
enum ATADriveType {
|
|
||||||
ATA,
|
|
||||||
ATAPI,
|
|
||||||
SATA
|
|
||||||
};
|
|
||||||
|
|
||||||
class ATA {
|
|
||||||
private:
|
|
||||||
ATADriveType type;
|
|
||||||
Spinlock driveLock;
|
|
||||||
protected:
|
|
||||||
uint32_t bus;
|
|
||||||
|
|
||||||
uint32_t totalLBA28Sectors;
|
|
||||||
|
|
||||||
uint32_t diskSize;
|
|
||||||
uint8_t identifyResult[512];
|
|
||||||
|
|
||||||
Port DataRegister;
|
|
||||||
Port ErrorRegister;
|
|
||||||
Port FeaturesRegister;
|
|
||||||
Port SectorCountRegister;
|
|
||||||
Port LBALo;
|
|
||||||
Port LBAMid;
|
|
||||||
Port LBAHi;
|
|
||||||
Port DriveSelectRegister;
|
|
||||||
Port StatusRegister;
|
|
||||||
Port CommandRegister;
|
|
||||||
|
|
||||||
bool isValid;
|
|
||||||
|
|
||||||
uint8_t readStatus();
|
|
||||||
uint8_t pollTillNotBSY();
|
|
||||||
uint8_t pollTillDRQ();
|
|
||||||
public:
|
|
||||||
ATA(uint32_t bus);
|
|
||||||
|
|
||||||
bool validDevice();
|
|
||||||
|
|
||||||
void ATARead(uint32_t sector, uint8_t* buffer);
|
|
||||||
void ATAWrite(uint32_t sector, uint8_t* buffer);
|
|
||||||
};
|
|
||||||
|
|
||||||
class ATAReadWriter: public ReadWriter, public ATA {
|
|
||||||
private:
|
|
||||||
uint8_t sectorBuffer[512];
|
|
||||||
uint32_t currentPosition;
|
|
||||||
Spinlock driveLock;
|
|
||||||
|
|
||||||
public:
|
|
||||||
ATAReadWriter(uint32_t bus);
|
|
||||||
|
|
||||||
uint32_t read(uint32_t count, uint8_t* buffer) override;
|
|
||||||
uint32_t write(uint32_t count, uint8_t* buffer) override;
|
|
||||||
uint32_t size() override;
|
|
||||||
uint32_t seek(uint32_t position) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
255
src/kernel/atapio.cpp
Normal file
255
src/kernel/atapio.cpp
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
#include "atapio.h"
|
||||||
|
|
||||||
|
// Disk code
|
||||||
|
|
||||||
|
// Primary ATA Bus: 0x1f0 to 0x1f7
|
||||||
|
// Device Control Register: 0x3f6
|
||||||
|
// Secondary ATA Bus: 0x170 to 0x177
|
||||||
|
// Device Control Register: 0x376
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t identify_result[256];
|
||||||
|
uint32_t total_28_lbas = 0;
|
||||||
|
|
||||||
|
DirectoryEntry* rootDirEntries;
|
||||||
|
uint16_t* FAT1;
|
||||||
|
|
||||||
|
uint16_t countReserved;
|
||||||
|
uint8_t countFATs;
|
||||||
|
uint16_t countRDEs;
|
||||||
|
uint16_t sectorsPerFAT;
|
||||||
|
|
||||||
|
|
||||||
|
void init_atapio() {
|
||||||
|
rootDirEntries = (DirectoryEntry*)new uint8_t[8192];
|
||||||
|
FAT1 = (uint16_t*)(new uint8_t[512 * 34]);
|
||||||
|
|
||||||
|
uint32_t boot_sector = new uint32_t[1024];
|
||||||
|
read_sectors(0, 1, (uint8_t*)boot_sector);
|
||||||
|
|
||||||
|
countReserved = *((uint16_t*)(boot_sector + 0x0e));
|
||||||
|
countFATs = *((uint8_t*)(boot_sector + 0x10));
|
||||||
|
countRDEs = *((uint16_t*)(boot_sector + 0x11));
|
||||||
|
sectorsPerFAT = *((uint16_t*)(boot_sector + 0x16));
|
||||||
|
|
||||||
|
// Select Drive 0 on the Primary Bus
|
||||||
|
outb(0x1f6, 0xa0);
|
||||||
|
|
||||||
|
// Set sector count to 0 for IDENTIFY
|
||||||
|
outb(0x1f2, 0);
|
||||||
|
// Set LBAlo to 0
|
||||||
|
outb(0x1f3, 0);
|
||||||
|
// Set LBAmid to 0
|
||||||
|
outb(0x1f4, 0);
|
||||||
|
// Set LBAhi to 0
|
||||||
|
outb(0x1f5, 0);
|
||||||
|
|
||||||
|
// Send IDENTIFY command
|
||||||
|
outb(0x1f7, 0xec);
|
||||||
|
|
||||||
|
uint8_t status = inb(0x1f7);
|
||||||
|
if (status) {
|
||||||
|
while ((status = inb(0x1f7)) & 0x80);
|
||||||
|
|
||||||
|
if ( !(inb(0x1f4) || inb(0x1f5)) ) {
|
||||||
|
while ( !(status & 8 || status & 1) )
|
||||||
|
status = inb(0x1f7);
|
||||||
|
|
||||||
|
if (!(status & 1)) {
|
||||||
|
for (int index=0; index<256; index++)
|
||||||
|
identify_result[index] = inw(0x1f0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
total_28_lbas = *(uint32_t*)(identify_result+60);
|
||||||
|
|
||||||
|
// We've initialised now, let's load the FAT and RootDirEntries.
|
||||||
|
read_sectors(sectorsPerFAT * countFATs + countReserved, countRDEs / 16, (uint8_t*)rootDirEntries);
|
||||||
|
read_sectors(countReserved, sectorsPerFAT, (uint8_t*)FAT1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_sector(uint32_t address, uint8_t* buffer) {
|
||||||
|
outb(0x1f6, 0xe0 | ((address>>24)&0x0f));
|
||||||
|
// Read a single sector
|
||||||
|
outb(0x1f2, 1);
|
||||||
|
// Set LBAlo, LBAmid and LBAhi
|
||||||
|
outb(0x1f3, address);
|
||||||
|
outb(0x1f4, address>>8);
|
||||||
|
outb(0x1f5, address>>16);
|
||||||
|
|
||||||
|
// Send read command
|
||||||
|
outb(0x1f7, 0x20);
|
||||||
|
// Poll
|
||||||
|
uint8_t status = inb(0x1f7);
|
||||||
|
while ( (status & 0x80) && !(status & 8) )
|
||||||
|
status = inb(0x1f7);
|
||||||
|
|
||||||
|
for (int index=0; index<256; index++)
|
||||||
|
((uint16_t*)buffer)[index] = inw(0x1f0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_sectors(uint32_t address, int count, uint8_t* buffer) {
|
||||||
|
for (int i=0; i<count; i++) {
|
||||||
|
read_sector(address+i, buffer+512*i);
|
||||||
|
for (int i=0; i<15; i++)
|
||||||
|
inb(0x1f7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t clusterToSector(uint32_t cluster) {
|
||||||
|
return cluster + (sectorsPerFAT * countFATs) + (countRDEs / 16) + (countReserved - 1) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int split_on_char(char c, char* str, char** split) {
|
||||||
|
char* cstr = str;
|
||||||
|
char* last = str;
|
||||||
|
uint32_t count = 0;
|
||||||
|
while (*cstr) {
|
||||||
|
if (*cstr == c) {
|
||||||
|
*cstr = 0;
|
||||||
|
split[count++] = last;
|
||||||
|
last = cstr+1;
|
||||||
|
}
|
||||||
|
cstr++;
|
||||||
|
}
|
||||||
|
split[count++] = last;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void to83(char* filename, char* buf83) {
|
||||||
|
char* c = filename;
|
||||||
|
for (int i=0;i<11;i++)
|
||||||
|
buf83[i] = ' ';
|
||||||
|
uint32_t bufpos = 0;
|
||||||
|
while (*c && bufpos != 11) {
|
||||||
|
if (*c == '.')
|
||||||
|
bufpos = 8;
|
||||||
|
else
|
||||||
|
buf83[bufpos++] = *c & 223;
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_file(uint32_t location, uint8_t* destination) {
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
bool loaded = false;
|
||||||
|
while (!loaded) {
|
||||||
|
uint16_t fromSector = clusterToSector(location);
|
||||||
|
read_sector(fromSector, destination+offset);
|
||||||
|
offset += 512;
|
||||||
|
|
||||||
|
location = FAT1[location++];
|
||||||
|
if (location == 0xffff)
|
||||||
|
loaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int calc_size(uint32_t location) {
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
bool loaded = false;
|
||||||
|
while (!loaded) {
|
||||||
|
uint16_t fromSector = clusterToSector(location);
|
||||||
|
offset += 512;
|
||||||
|
|
||||||
|
location = FAT1[location++];
|
||||||
|
if (location == 0xffff)
|
||||||
|
loaded = true;
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectoryEntry* get_DE(char* filename) {
|
||||||
|
DirectoryEntry* dirbuf;
|
||||||
|
Directory dir = {
|
||||||
|
.entry = rootDirEntries,
|
||||||
|
.entries = countRDEs
|
||||||
|
};
|
||||||
|
|
||||||
|
char* levels[8];
|
||||||
|
int count = split_on_char('/', filename, levels);
|
||||||
|
|
||||||
|
for (int i=0; i<(count-1); i++) {
|
||||||
|
char normalname[11] = {' '};
|
||||||
|
to83(levels[i], normalname);
|
||||||
|
for (int e=0; e<dir.entries; e++) {
|
||||||
|
bool found=strcmp(dir.entry[e].name, normalname, 11);
|
||||||
|
if (found) {
|
||||||
|
DirectoryEntry* de = &dir.entry[e];
|
||||||
|
uint32_t size = calc_size(de->firstClusterLow);
|
||||||
|
dirbuf = (DirectoryEntry*)(new uint8_t[size]);
|
||||||
|
uint32_t cluster = de->firstClusterLow;
|
||||||
|
load_file(cluster, (uint8_t*)dirbuf);
|
||||||
|
dir.entry = dirbuf;
|
||||||
|
dir.entries = size / 32;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char normalname[11];
|
||||||
|
to83(levels[count-1], normalname);
|
||||||
|
|
||||||
|
for (int i=0; i<dir.entries; i++) {
|
||||||
|
bool found = strcmp(dir.entry[i].name, normalname, 11);
|
||||||
|
if (found) {
|
||||||
|
return &dir.entry[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t file_exists(char* filename) {
|
||||||
|
DirectoryEntry* de = get_DE(filename);
|
||||||
|
if (de)
|
||||||
|
return de->firstClusterLow;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t file_size(char* filename) {
|
||||||
|
for (int i=0; i<countRDEs; i++) {
|
||||||
|
bool found = strcmp(rootDirEntries[i].name, filename, 11);
|
||||||
|
if (found) {
|
||||||
|
if (rootDirEntries[i].size % 512)
|
||||||
|
return ((rootDirEntries[i].size / 512) + 1) * 512;
|
||||||
|
else
|
||||||
|
return rootDirEntries[i].size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_file(char* filename, uint8_t* location) {
|
||||||
|
DirectoryEntry* de = get_DE(filename);
|
||||||
|
load_file(de->firstClusterLow, location);
|
||||||
|
}
|
||||||
|
|
||||||
|
FATFileReadWriter::FATFileReadWriter(uint32_t owner, char* filename)
|
||||||
|
: ReadWriter(owner) {
|
||||||
|
this->bytesRead = 0;
|
||||||
|
DirectoryEntry* de = get_DE(filename);
|
||||||
|
this->sizeBytes = de->size;
|
||||||
|
this->currentCluster = de->firstClusterLow;
|
||||||
|
this->read_buffer = new uint8_t[512];
|
||||||
|
read_sector(clusterToSector(this->currentCluster), this->read_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t FATFileReadWriter::read(uint32_t count, uint8_t* buffer) {
|
||||||
|
int index = 0;
|
||||||
|
while (count) {
|
||||||
|
buffer[index] = this->read_buffer[this->bytesRead++];
|
||||||
|
if (this->bytesRead == 512) {
|
||||||
|
this->currentCluster = FAT1[this->currentCluster++];
|
||||||
|
read_sector(clusterToSector(this->currentCluster), this->read_buffer);
|
||||||
|
this->bytesRead = 0;
|
||||||
|
}
|
||||||
|
count--;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32_t FATFileReadWriter::write(uint32_t count, uint8_t* buffer) {}
|
||||||
|
uint32_t FATFileReadWriter::size() {
|
||||||
|
return this->sizeBytes;
|
||||||
|
}
|
77
src/kernel/atapio.h
Normal file
77
src/kernel/atapio.h
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#ifndef ATA_PIO
|
||||||
|
#define ATA_PIO
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "io.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "strings.h"
|
||||||
|
#include "allocate.h"
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
#include "stdio/readwriter.h"
|
||||||
|
|
||||||
|
struct __attribute__((packed)) DirectoryEntry {
|
||||||
|
char name[11];
|
||||||
|
uint8_t _ignored0 : 3;
|
||||||
|
uint8_t archive : 1;
|
||||||
|
uint8_t directory : 1;
|
||||||
|
uint8_t volumeid : 1;
|
||||||
|
uint8_t system : 1;
|
||||||
|
uint8_t hidden : 1;
|
||||||
|
uint8_t readonly : 1;
|
||||||
|
uint8_t _ignored1;
|
||||||
|
uint16_t createdHour : 5;
|
||||||
|
uint16_t createdMinute : 6;
|
||||||
|
uint16_t createdSecond : 5;
|
||||||
|
|
||||||
|
uint16_t createdYear : 7;
|
||||||
|
uint16_t createdMonth : 4;
|
||||||
|
uint16_t createdDay : 5;
|
||||||
|
|
||||||
|
uint16_t lastAccessYear : 7;
|
||||||
|
uint16_t lastAccessMonth : 4;
|
||||||
|
uint16_t lastAccessDay : 5;
|
||||||
|
|
||||||
|
uint16_t firstClusterHigh;
|
||||||
|
|
||||||
|
uint16_t modifiedHour : 5;
|
||||||
|
uint16_t modifiedMinute : 6;
|
||||||
|
uint16_t modifiedSecond : 5;
|
||||||
|
|
||||||
|
uint16_t modifiedYear : 7;
|
||||||
|
uint16_t modifiedMonth : 4;
|
||||||
|
uint16_t modifiedDay : 5;
|
||||||
|
|
||||||
|
uint16_t firstClusterLow;
|
||||||
|
uint32_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Directory {
|
||||||
|
DirectoryEntry* entry;
|
||||||
|
uint32_t entries;
|
||||||
|
};
|
||||||
|
|
||||||
|
void init_atapio();
|
||||||
|
void read_sector(uint32_t address, uint8_t* buffer);
|
||||||
|
void read_sectors(uint32_t address, int count, uint8_t* buffer);
|
||||||
|
uint16_t file_exists(char* filename);
|
||||||
|
void load_file(char* filename, uint8_t* location);
|
||||||
|
|
||||||
|
uint32_t file_size(char* filename);
|
||||||
|
|
||||||
|
class FATFileReadWriter : public ReadWriter {
|
||||||
|
private:
|
||||||
|
uint32_t sizeBytes;
|
||||||
|
uint32_t bytesRead;
|
||||||
|
uint32_t currentCluster;
|
||||||
|
uint8_t* read_buffer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FATFileReadWriter(uint32_t owner, char* filename);
|
||||||
|
uint32_t read(uint32_t count, uint8_t* buffer) override;
|
||||||
|
uint32_t write(uint32_t count, uint8_t* buffer) override;
|
||||||
|
uint32_t size() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -1,71 +0,0 @@
|
|||||||
#ifndef DYNARRAY_H
|
|
||||||
#define DYNARRAY_H
|
|
||||||
|
|
||||||
#include "../global.h"
|
|
||||||
#include "maybe.h"
|
|
||||||
#include "../spinlock.h"
|
|
||||||
|
|
||||||
namespace xnoe {
|
|
||||||
template<typename T>
|
|
||||||
class dynarray {
|
|
||||||
private:
|
|
||||||
uint32_t size = 128;
|
|
||||||
T* buffer;
|
|
||||||
uint32_t index = 0;
|
|
||||||
uint32_t start_index = 0;
|
|
||||||
Spinlock lock;
|
|
||||||
|
|
||||||
public:
|
|
||||||
dynarray(uint32_t start_index=0) {
|
|
||||||
this->buffer = new T[size];
|
|
||||||
this->index = this->start_index = start_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
dynarray(dynarray* d) {
|
|
||||||
this->size = d->size;
|
|
||||||
this->buffer = new T[size];
|
|
||||||
this->index = d->index;
|
|
||||||
this->start_index = d->start_index;
|
|
||||||
memcpy((uint8_t*)this->buffer, (uint8_t*)d->buffer, sizeof(T)*d->size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void push(T t) {
|
|
||||||
if (index == size) {
|
|
||||||
lock.lock();
|
|
||||||
uint32_t old_size = size;
|
|
||||||
size *= 2;
|
|
||||||
T* buffer_tmp = new T[size];
|
|
||||||
memcpy((uint8_t*)buffer_tmp, (uint8_t*)buffer, sizeof(T)*old_size);
|
|
||||||
delete buffer;
|
|
||||||
buffer = buffer_tmp;
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer[index++] = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t length() {
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
xnoe::maybe<T> pop() {
|
|
||||||
if (index == start_index)
|
|
||||||
return xnoe::maybe<T>();
|
|
||||||
return xnoe::maybe<T>(buffer[--index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
xnoe::maybe<T> get(uint32_t i) {
|
|
||||||
if (i>size)
|
|
||||||
return xnoe::maybe<T>();
|
|
||||||
return xnoe::maybe<T>(buffer[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set(uint32_t i, T t) {
|
|
||||||
if (i>size)
|
|
||||||
return;
|
|
||||||
buffer[i] = t;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -5,6 +5,7 @@
|
|||||||
#include "linkedlist.h"
|
#include "linkedlist.h"
|
||||||
#include "../memory.h"
|
#include "../memory.h"
|
||||||
#include "maybe.h"
|
#include "maybe.h"
|
||||||
|
#include "../screenstuff.h"
|
||||||
|
|
||||||
namespace xnoe {
|
namespace xnoe {
|
||||||
template <class key, class value>
|
template <class key, class value>
|
||||||
@ -39,19 +40,19 @@ namespace xnoe {
|
|||||||
list->append(xnoe::tuple<key, value>(k, v));
|
list->append(xnoe::tuple<key, value>(k, v));
|
||||||
}
|
}
|
||||||
|
|
||||||
xnoe::maybe<value> get(key k) {
|
xnoe::Maybe<value> get(key k) {
|
||||||
xnoe::linkedlist<xnoe::tuple<key, value>>* list = &table[xnoe::hash<key>(k) % 4096];
|
xnoe::linkedlist<xnoe::tuple<key, value>>* list = &table[xnoe::hash<key>(k) % 4096];
|
||||||
xnoe::linkedlistelem<xnoe::tuple<key, value>>* current = list->start;
|
xnoe::linkedlistelem<xnoe::tuple<key, value>>* current = list->start;
|
||||||
if (current) {
|
if (current) {
|
||||||
while (current) {
|
while (current) {
|
||||||
if (xnoe::get<0>(current->elem) == k)
|
if (xnoe::get<0>(current->elem) == k)
|
||||||
return xnoe::maybe<value>(xnoe::get<1>(current->elem));
|
return xnoe::Maybe<value>(xnoe::get<1>(current->elem));
|
||||||
|
|
||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return xnoe::maybe<value>();
|
return xnoe::Maybe<value>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove(key k) {
|
void remove(key k) {
|
||||||
@ -59,12 +60,11 @@ namespace xnoe {
|
|||||||
xnoe::linkedlistelem<xnoe::tuple<key, value>>* current = list->start;
|
xnoe::linkedlistelem<xnoe::tuple<key, value>>* current = list->start;
|
||||||
if (current) {
|
if (current) {
|
||||||
while (current) {
|
while (current) {
|
||||||
xnoe::linkedlistelem<xnoe::tuple<key, value>>* next = current->next;
|
|
||||||
if (xnoe::get<0>(current->elem) == k) {
|
if (xnoe::get<0>(current->elem) == k) {
|
||||||
list->remove(current);
|
list->remove(current);
|
||||||
delete current;
|
delete current;
|
||||||
}
|
}
|
||||||
current = next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
#ifndef LINKEDLIST_H
|
#ifndef LINKEDLIST_H
|
||||||
#define LINKEDLIST_H
|
#define LINKEDLIST_H
|
||||||
|
|
||||||
#include "../types.h"
|
|
||||||
#include "../memory.h"
|
#include "../memory.h"
|
||||||
#include "../spinlock.h"
|
|
||||||
|
|
||||||
namespace xnoe {
|
namespace xnoe {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@ -21,38 +19,25 @@ namespace xnoe {
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct linkedlist {
|
struct linkedlist {
|
||||||
xnoe::linkedlistelem<T>* start=0;
|
xnoe::linkedlistelem<T>* start;
|
||||||
xnoe::linkedlistelem<T>* end=0;
|
xnoe::linkedlistelem<T>* end;
|
||||||
Spinlock lock = Spinlock();
|
|
||||||
uint32_t length = 0;
|
|
||||||
|
|
||||||
bool has(T t) {
|
bool has(T t) {
|
||||||
xnoe::linkedlistelem<T>* current = this->start;
|
xnoe::linkedlistelem<T>* current = this->start;
|
||||||
while (start) {
|
while (start) {
|
||||||
if (start->elem == t)
|
if (start->elem == t)
|
||||||
return true;
|
return true;
|
||||||
//current = current->next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy() {
|
|
||||||
xnoe::linkedlistelem<T>* current = this->start;
|
|
||||||
while (current) {
|
|
||||||
xnoe::linkedlistelem<T>* c = current;
|
|
||||||
current = current->next;
|
|
||||||
delete c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void append(T t) {
|
void append(T t) {
|
||||||
xnoe::linkedlistelem<T>* llelem = new xnoe::linkedlistelem<T>(t);
|
xnoe::linkedlistelem<T>* llelem = new xnoe::linkedlistelem<T>(t);
|
||||||
append(llelem);
|
append(llelem);
|
||||||
}
|
}
|
||||||
|
|
||||||
void append(xnoe::linkedlistelem<T>* llelem) {
|
void append(xnoe::linkedlistelem<T>* llelem) {
|
||||||
lock.lock();
|
|
||||||
if (this->start && this->end) {
|
if (this->start && this->end) {
|
||||||
this->end->next = llelem;
|
this->end->next = llelem;
|
||||||
llelem->prev = this->end;
|
llelem->prev = this->end;
|
||||||
@ -62,8 +47,6 @@ namespace xnoe {
|
|||||||
this->start = llelem;
|
this->start = llelem;
|
||||||
this->end = llelem;
|
this->end = llelem;
|
||||||
}
|
}
|
||||||
length++;
|
|
||||||
lock.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void prepend(T t) {
|
void prepend(T t) {
|
||||||
@ -72,7 +55,6 @@ namespace xnoe {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void prepend(xnoe::linkedlistelem<T>* llelem) {
|
void prepend(xnoe::linkedlistelem<T>* llelem) {
|
||||||
lock.lock();
|
|
||||||
if (this->start && this->end) {
|
if (this->start && this->end) {
|
||||||
this->start->prev = llelem;
|
this->start->prev = llelem;
|
||||||
llelem->next = this->start;
|
llelem->next = this->start;
|
||||||
@ -82,19 +64,14 @@ namespace xnoe {
|
|||||||
this->start = llelem;
|
this->start = llelem;
|
||||||
this->end = llelem;
|
this->end = llelem;
|
||||||
}
|
}
|
||||||
length++;
|
|
||||||
lock.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert(linkedlist<T>* ll, uint32_t index) {
|
void insert(linkedlist<T>* ll, uint32_t index) {
|
||||||
lock.lock();
|
|
||||||
linkedlistelem<T>* current = this->start;
|
linkedlistelem<T>* current = this->start;
|
||||||
for (int i=0; i<index; i++, current = current->next);
|
for (int i=0; i<index; i++, current = current->next);
|
||||||
|
|
||||||
current->next->prev = ll->end;
|
current->next->prev = ll->end;
|
||||||
current->next = ll->start;
|
current->next = ll->start;
|
||||||
length += ll.length;
|
|
||||||
lock.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*void remove(uint32_t index) {
|
/*void remove(uint32_t index) {
|
||||||
@ -108,7 +85,6 @@ namespace xnoe {
|
|||||||
}*/
|
}*/
|
||||||
|
|
||||||
void remove(linkedlistelem<T>* elem) {
|
void remove(linkedlistelem<T>* elem) {
|
||||||
lock.lock();
|
|
||||||
linkedlistelem<T>* current = start;
|
linkedlistelem<T>* current = start;
|
||||||
while (current) {
|
while (current) {
|
||||||
if (current == elem) {
|
if (current == elem) {
|
||||||
@ -119,22 +95,18 @@ namespace xnoe {
|
|||||||
current->next->prev = current->prev;
|
current->next->prev = current->prev;
|
||||||
|
|
||||||
if (current == start)
|
if (current == start)
|
||||||
start = current->next;
|
start = 0;
|
||||||
|
|
||||||
if (current = end)
|
if (current = end)
|
||||||
end = current->prev;
|
end = 0;
|
||||||
|
|
||||||
length--;
|
|
||||||
lock.unlock();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
lock.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove(T elem) {
|
void remove(T elem) {
|
||||||
lock.lock();
|
|
||||||
linkedlistelem<T>* current = start;
|
linkedlistelem<T>* current = start;
|
||||||
while (current) {
|
while (current) {
|
||||||
if (current->elem == elem) {
|
if (current->elem == elem) {
|
||||||
@ -152,13 +124,10 @@ namespace xnoe {
|
|||||||
|
|
||||||
delete current;
|
delete current;
|
||||||
|
|
||||||
length--;
|
|
||||||
lock.unlock();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
lock.unlock();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -3,17 +3,17 @@
|
|||||||
|
|
||||||
namespace xnoe {
|
namespace xnoe {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class maybe {
|
class Maybe {
|
||||||
private:
|
private:
|
||||||
T t;
|
T t;
|
||||||
bool ok;
|
bool ok;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
maybe() {
|
Maybe() {
|
||||||
this->ok = false;
|
this->ok = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
maybe(T t) {
|
Maybe(T t) {
|
||||||
this->ok = true;
|
this->ok = true;
|
||||||
this->t = t;
|
this->t = t;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
[BITS 32]
|
[BITS 32]
|
||||||
|
|
||||||
_start:
|
_start:
|
||||||
|
mov esp, 0xc100a000
|
||||||
jmp main
|
jmp main
|
||||||
|
|
||||||
extern main
|
extern main
|
@ -1,5 +0,0 @@
|
|||||||
#include "devfs.h"
|
|
||||||
|
|
||||||
DevFS::DevFS() {
|
|
||||||
addEntry(createPathFromString("ata"), [](){return new ATAReadWriter(0);});
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
#ifndef DEVFS_H
|
|
||||||
#define DEVFS_H
|
|
||||||
|
|
||||||
#include "fstree.h"
|
|
||||||
#include "../ata.h"
|
|
||||||
#include "../kernel.h"
|
|
||||||
#include "vfs.h"
|
|
||||||
|
|
||||||
class DevFS : public VFS {
|
|
||||||
public:
|
|
||||||
DevFS();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,401 +0,0 @@
|
|||||||
#include "fat16.h"
|
|
||||||
|
|
||||||
uint32_t FAT16FileReadWriter::offsetBytesToCluster(uint32_t offset) {
|
|
||||||
uint32_t cluster = this->firstCluster;
|
|
||||||
uint32_t remaining = offset;
|
|
||||||
while (remaining > this->clusterSize) {
|
|
||||||
cluster = this->backingFS->FAT1[this->firstCluster];
|
|
||||||
remaining -= this->clusterSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cluster;
|
|
||||||
}
|
|
||||||
|
|
||||||
FAT16FileReadWriter::FAT16FileReadWriter(uint32_t firstCluster, uint32_t sizeBytes, FAT16FS* backingFS) {
|
|
||||||
this->firstCluster = firstCluster;
|
|
||||||
this->sizeBytes = sizeBytes;
|
|
||||||
this->currentPosition = 0;
|
|
||||||
this->backingFS = backingFS;
|
|
||||||
this->clusterSize = 512 * (uint32_t)(*this->backingFS->sectorsPerCluster);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t FAT16FileReadWriter::read(uint32_t count, uint8_t* buffer) {
|
|
||||||
//uint8_t* clusterBuffer = new uint8_t[this->clusterSize];
|
|
||||||
uint8_t clusterBuffer[this->clusterSize];
|
|
||||||
uint32_t clusterToRead = offsetBytesToCluster(this->currentPosition);
|
|
||||||
uint32_t sectorToRead = this->backingFS->clusterToSector(clusterToRead);
|
|
||||||
this->backingFS->backingDevice->seek(sectorToRead * this->clusterSize);
|
|
||||||
this->backingFS->backingDevice->read(this->clusterSize, clusterBuffer);
|
|
||||||
|
|
||||||
uint32_t currentClusterIndex = this->currentPosition % this->clusterSize;
|
|
||||||
if (this->currentPosition >= this->sizeBytes)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
uint32_t remaining = count;
|
|
||||||
|
|
||||||
uint32_t index = 0;
|
|
||||||
while (remaining) {
|
|
||||||
if (currentClusterIndex == this->clusterSize) {
|
|
||||||
clusterToRead = this->backingFS->FAT1[clusterToRead];
|
|
||||||
if (clusterToRead == 0xffff)
|
|
||||||
break;
|
|
||||||
sectorToRead = this->backingFS->clusterToSector(clusterToRead);
|
|
||||||
this->backingFS->backingDevice->seek(sectorToRead * this->clusterSize);
|
|
||||||
this->backingFS->backingDevice->read(this->clusterSize, clusterBuffer);
|
|
||||||
currentClusterIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer[index++] = clusterBuffer[currentClusterIndex++];
|
|
||||||
remaining--;
|
|
||||||
this->currentPosition++;
|
|
||||||
}
|
|
||||||
|
|
||||||
//delete[] clusterBuffer;
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t FAT16FileReadWriter::write(uint32_t count, uint8_t* buffer) {return;}
|
|
||||||
|
|
||||||
uint32_t FAT16FileReadWriter::size() {
|
|
||||||
return this->sizeBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t FAT16FileReadWriter::seek(uint32_t position) {
|
|
||||||
if (position < this->sizeBytes) {
|
|
||||||
this->currentPosition = position;
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char safeUppercase(char c) {
|
|
||||||
switch (c) {
|
|
||||||
case 'a'...'z':
|
|
||||||
return c & ~32;
|
|
||||||
default:
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FAT16FS::pathEntryTo83(PathEntry pe, char* buffer) {
|
|
||||||
uint32_t maxSize = pe.length;
|
|
||||||
uint8_t* data = pe.path;
|
|
||||||
|
|
||||||
uint32_t readIndex=0;
|
|
||||||
uint32_t writeIndex=0;
|
|
||||||
|
|
||||||
while (writeIndex<11 && readIndex < maxSize) {
|
|
||||||
char c;
|
|
||||||
if ((c=data[readIndex++]) == '.') {
|
|
||||||
writeIndex = 8;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
buffer[writeIndex++] = safeUppercase(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t FAT16FS::clusterToSector(uint32_t cluster) {
|
|
||||||
return (cluster * (uint32_t)(*this->sectorsPerCluster)) + (*sectorsPerFAT * *countFATs) + (*countRDEs / 16) + (*countReserved - 1) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FAT16FS::load_file(uint32_t location, uint8_t* destination) {
|
|
||||||
int offset = 0;
|
|
||||||
|
|
||||||
bool loaded = false;
|
|
||||||
while (!loaded) {
|
|
||||||
uint16_t fromSector = clusterToSector(location);
|
|
||||||
this->backingDevice->seek(fromSector * 512 * *this->sectorsPerCluster);
|
|
||||||
this->backingDevice->read(512 * *this->sectorsPerCluster, destination+offset);
|
|
||||||
offset += 512 * *this->sectorsPerCluster;
|
|
||||||
|
|
||||||
location = FAT1[location++];
|
|
||||||
if (location == 0xffff)
|
|
||||||
loaded = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t FAT16FS::calc_size(uint32_t location) {
|
|
||||||
int offset = 0;
|
|
||||||
|
|
||||||
bool loaded = false;
|
|
||||||
while (!loaded) {
|
|
||||||
uint16_t fromSector = clusterToSector(location);
|
|
||||||
offset += 512 * *this->sectorsPerCluster;
|
|
||||||
|
|
||||||
location = FAT1[location++];
|
|
||||||
if (location == 0xffff)
|
|
||||||
loaded = true;
|
|
||||||
}
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
xnoe::tuple<DirectoryEntry*, uint32_t, bool> FAT16FS::getDirectoryEntry(Path p) {
|
|
||||||
PathElement* current = p.start;
|
|
||||||
|
|
||||||
DirectoryEntry* currentDirectory = new DirectoryEntry[*countRDEs];
|
|
||||||
for (int i=0; i < *countRDEs; i++)
|
|
||||||
currentDirectory[i] = rootDirEntries[i];
|
|
||||||
|
|
||||||
uint32_t count = *countRDEs;
|
|
||||||
|
|
||||||
if (!current)
|
|
||||||
return xnoe::tuple<DirectoryEntry*, uint32_t, bool>(currentDirectory, count, true);
|
|
||||||
|
|
||||||
escape_for:
|
|
||||||
while (current != p.end) {
|
|
||||||
char name83[12] = " ";
|
|
||||||
pathEntryTo83(current->elem, name83);
|
|
||||||
for (int i=0; i < count; i++) {
|
|
||||||
if (strcmp(currentDirectory[i].name, name83, 11)) {
|
|
||||||
DirectoryEntry found = currentDirectory[i];
|
|
||||||
if (!(found.directory))
|
|
||||||
return xnoe::tuple<DirectoryEntry*, uint32_t, bool>(currentDirectory, count, true);
|
|
||||||
|
|
||||||
delete currentDirectory;
|
|
||||||
uint32_t sizeBytes = calc_size(found.firstClusterLow);
|
|
||||||
currentDirectory = (DirectoryEntry*)(new uint8_t[sizeBytes]);
|
|
||||||
|
|
||||||
load_file(found.firstClusterLow, (uint8_t*)currentDirectory);
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
count = sizeBytes / sizeof(DirectoryEntry);
|
|
||||||
|
|
||||||
current = current->next;
|
|
||||||
goto escape_for;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return xnoe::tuple<DirectoryEntry*, uint32_t, bool>(currentDirectory, 0, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return xnoe::tuple<DirectoryEntry*, uint32_t, bool>(currentDirectory, count, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
xnoe::tuple<DirectoryEntry*, uint32_t, bool> FAT16FS::getDirectoryEntryFull(Path p) {
|
|
||||||
PathElement* current = p.start;
|
|
||||||
|
|
||||||
DirectoryEntry* currentDirectory = new DirectoryEntry[*countRDEs];
|
|
||||||
for (int i=0; i < *countRDEs; i++)
|
|
||||||
currentDirectory[i] = rootDirEntries[i];
|
|
||||||
|
|
||||||
uint32_t count = *countRDEs;
|
|
||||||
|
|
||||||
if (!current)
|
|
||||||
return xnoe::tuple<DirectoryEntry*, uint32_t, bool>(currentDirectory, count, true);
|
|
||||||
|
|
||||||
escape_for:
|
|
||||||
while (current) {
|
|
||||||
char name83[12] = " ";
|
|
||||||
pathEntryTo83(current->elem, name83);
|
|
||||||
for (int i=0; i < count; i++) {
|
|
||||||
if (strcmp(currentDirectory[i].name, name83, 11)) {
|
|
||||||
DirectoryEntry found = currentDirectory[i];
|
|
||||||
if (!(found.directory))
|
|
||||||
return xnoe::tuple<DirectoryEntry*, uint32_t, bool>(currentDirectory, count, true);
|
|
||||||
|
|
||||||
delete currentDirectory;
|
|
||||||
uint32_t sizeBytes = calc_size(found.firstClusterLow);
|
|
||||||
currentDirectory = (DirectoryEntry*)(new uint8_t[sizeBytes]);
|
|
||||||
|
|
||||||
load_file(found.firstClusterLow, (uint8_t*)currentDirectory);
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
count = sizeBytes / sizeof(DirectoryEntry);
|
|
||||||
|
|
||||||
current = current->next;
|
|
||||||
goto escape_for;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return xnoe::tuple<DirectoryEntry*, uint32_t, bool>(currentDirectory, 0, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return xnoe::tuple<DirectoryEntry*, uint32_t, bool>(currentDirectory, count, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
FAT16FS::FAT16FS(ReadWriter* disk) {
|
|
||||||
this->backingDevice = disk;
|
|
||||||
|
|
||||||
this->backingDevice->seek(0);
|
|
||||||
this->backingDevice->read(512, sectorOne);
|
|
||||||
|
|
||||||
this->rootDirEntries = new DirectoryEntry[*countRDEs];
|
|
||||||
|
|
||||||
this->backingDevice->seek(((*sectorsPerFAT) * (*countFATs) + (*countReserved)) * 512);
|
|
||||||
this->backingDevice->read((*countRDEs) * sizeof(DirectoryEntry), (uint8_t*)this->rootDirEntries);
|
|
||||||
|
|
||||||
this->FAT1 = new uint16_t[(*sectorsPerFAT) * 256];
|
|
||||||
|
|
||||||
this->backingDevice->seek((*countReserved) * 512);
|
|
||||||
this->backingDevice->read((*sectorsPerFAT) * 512, (uint8_t*)FAT1);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FAT16FS::exists(Path p) {
|
|
||||||
xnoe::tuple<DirectoryEntry*, uint32_t, bool> directory = getDirectoryEntry(p);
|
|
||||||
if (!xnoe::get<2>(directory))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
bool found = false;
|
|
||||||
DirectoryEntry* directoryEntries = xnoe::get<0>(directory);
|
|
||||||
uint32_t count = xnoe::get<1>(directory);
|
|
||||||
|
|
||||||
PathElement* end = p.end;
|
|
||||||
if (!end)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
char name83[12] = " ";
|
|
||||||
name83[11] = 0;
|
|
||||||
pathEntryTo83(end->elem, name83);
|
|
||||||
for (int i=0; i<count; i++) {
|
|
||||||
if (strcmp(directoryEntries[i].name, name83, 11)) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete directoryEntries;
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
FSType FAT16FS::type(Path p) {
|
|
||||||
xnoe::tuple<DirectoryEntry*, uint32_t, bool> directory = getDirectoryEntry(p);
|
|
||||||
if (!xnoe::get<2>(directory))
|
|
||||||
return NoExist;
|
|
||||||
|
|
||||||
FSType found = NoExist;
|
|
||||||
DirectoryEntry* directoryEntries = xnoe::get<0>(directory);
|
|
||||||
uint32_t count = xnoe::get<1>(directory);
|
|
||||||
|
|
||||||
PathElement* end = p.end;
|
|
||||||
if (!end)
|
|
||||||
return NoExist;
|
|
||||||
|
|
||||||
char name83[12] = " ";
|
|
||||||
pathEntryTo83(end->elem, name83);
|
|
||||||
for (int i=0; i<count; i++) {
|
|
||||||
if (strcmp(directoryEntries[i].name, name83, 11)) {
|
|
||||||
if (directoryEntries[i].directory)
|
|
||||||
found = Directory;
|
|
||||||
else
|
|
||||||
found = File;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete directoryEntries;
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReadWriter* FAT16FS::open(Path p) {
|
|
||||||
xnoe::tuple<DirectoryEntry*, uint32_t, bool> directory = getDirectoryEntry(p);
|
|
||||||
if (!xnoe::get<2>(directory))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
DirectoryEntry* directoryEntries = xnoe::get<0>(directory);
|
|
||||||
uint32_t count = xnoe::get<1>(directory);
|
|
||||||
|
|
||||||
PathElement* end = p.end;
|
|
||||||
if (!end)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
uint32_t written=0;
|
|
||||||
|
|
||||||
char name83[12] = " ";
|
|
||||||
name83[11] = 0;
|
|
||||||
pathEntryTo83(end->elem, name83);
|
|
||||||
for (int i=0; i<count; i++) {
|
|
||||||
if (strcmp(directoryEntries[i].name, name83, 11)) {
|
|
||||||
if (!directoryEntries[i].directory)
|
|
||||||
return new FAT16FileReadWriter(((uint32_t)directoryEntries[i].firstClusterHigh << 16) | directoryEntries[i].firstClusterLow, directoryEntries[i].size, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delete directoryEntries;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
PathEntry name83ToPathEntry(char* name83, char* text) {
|
|
||||||
uint32_t mainLength = 8;
|
|
||||||
uint32_t index = 7;
|
|
||||||
while (name83[index] == ' ' && index--)
|
|
||||||
mainLength--;
|
|
||||||
|
|
||||||
uint32_t extLength = 3;
|
|
||||||
index = 10;
|
|
||||||
while (name83[index] == ' ' && index-- > 7)
|
|
||||||
extLength--;
|
|
||||||
|
|
||||||
memcpy(text, name83, mainLength);
|
|
||||||
if (name83[8] != ' ') {
|
|
||||||
text[mainLength] = '.';
|
|
||||||
memcpy(text+mainLength+1, name83+8, extLength);
|
|
||||||
}
|
|
||||||
text[mainLength+extLength+1] = 0;
|
|
||||||
return PathEntry{mainLength+extLength+1, text};
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t getRealCount(DirectoryEntry* directoryEntries, uint32_t c) {
|
|
||||||
uint32_t r = 0;
|
|
||||||
for (int i = 0; i < c; i++) {
|
|
||||||
if (directoryEntries[i].name[0] != 0 && directoryEntries[i].name[0] != 0xE5 && !directoryEntries[i].volumeid)
|
|
||||||
r++;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t FAT16FS::getDentsSize(Path p) {
|
|
||||||
xnoe::tuple<DirectoryEntry*, uint32_t, bool> directory = getDirectoryEntryFull(p);
|
|
||||||
DirectoryEntry* directoryEntries = xnoe::get<0>(directory);
|
|
||||||
if (!xnoe::get<2>(directory)) {
|
|
||||||
delete directoryEntries;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t found = 0;
|
|
||||||
uint32_t count = xnoe::get<1>(directory);
|
|
||||||
|
|
||||||
found += sizeof(FSDirectoryListing);
|
|
||||||
for (int i=0; i<count; i++) {
|
|
||||||
if (directoryEntries[i].name[0] != 0 && directoryEntries[i].name[0] != 0xE5 && !directoryEntries[i].volumeid) {
|
|
||||||
found += sizeof(FSDirectoryEntry);
|
|
||||||
found += 13;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete directoryEntries;
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FAT16FS::getDents(Path p, FSDirectoryListing* buffer) {
|
|
||||||
xnoe::tuple<DirectoryEntry*, uint32_t, bool> directory = getDirectoryEntryFull(p);
|
|
||||||
DirectoryEntry* directoryEntries = xnoe::get<0>(directory);
|
|
||||||
if (!xnoe::get<2>(directory)) {
|
|
||||||
delete directoryEntries;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t count = xnoe::get<1>(directory);
|
|
||||||
|
|
||||||
uint32_t written=0;
|
|
||||||
|
|
||||||
buffer->count = getRealCount(directoryEntries, count);
|
|
||||||
buffer->stringsLength = 0;
|
|
||||||
|
|
||||||
char* nameBuffer = ((char*)buffer);
|
|
||||||
nameBuffer += sizeof(FSDirectoryEntry)*buffer->count + sizeof(FSDirectoryListing);
|
|
||||||
|
|
||||||
for (int i=0; i<count; i++) {
|
|
||||||
if (directoryEntries[i].name[0] != 0 && directoryEntries[i].name[0] != 0xE5 && !directoryEntries[i].volumeid) {
|
|
||||||
buffer->entries[written] = FSDirectoryEntry {
|
|
||||||
name83ToPathEntry(directoryEntries[i].name, nameBuffer + 13*written),
|
|
||||||
directoryEntries[i].directory ? Directory : File,
|
|
||||||
directoryEntries[i].size
|
|
||||||
};
|
|
||||||
written++;
|
|
||||||
buffer->stringsLength += 13;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete directoryEntries;
|
|
||||||
}
|
|
@ -1,119 +0,0 @@
|
|||||||
#ifndef FAT16_H
|
|
||||||
#define FAT16_H
|
|
||||||
|
|
||||||
#include "fstree.h"
|
|
||||||
#include "../memory.h"
|
|
||||||
#include "../stdio/readwriter.h"
|
|
||||||
#include "../datatypes/tuple.h"
|
|
||||||
|
|
||||||
struct __attribute__((packed)) DirectoryEntry {
|
|
||||||
char name[11];
|
|
||||||
|
|
||||||
uint8_t readonly : 1;
|
|
||||||
uint8_t hidden : 1;
|
|
||||||
uint8_t system : 1;
|
|
||||||
uint8_t volumeid : 1;
|
|
||||||
uint8_t directory : 1;
|
|
||||||
uint8_t archive : 1;
|
|
||||||
uint8_t device : 1;
|
|
||||||
uint8_t _ignored0 : 1;
|
|
||||||
|
|
||||||
uint8_t f1 : 1;
|
|
||||||
uint8_t f2 : 1;
|
|
||||||
uint8_t f3 : 1;
|
|
||||||
uint8_t f4 : 1;
|
|
||||||
uint8_t _ignored1 : 1;
|
|
||||||
uint8_t deleteRequiresPassword : 1;
|
|
||||||
uint8_t writeRequiresPassword : 1;
|
|
||||||
uint8_t readRequiresPassword : 1;
|
|
||||||
|
|
||||||
uint8_t createTime10ms;
|
|
||||||
|
|
||||||
uint16_t createdHour : 5;
|
|
||||||
uint16_t createdMinute : 6;
|
|
||||||
uint16_t createdSecond : 5;
|
|
||||||
|
|
||||||
uint16_t createdYear : 7;
|
|
||||||
uint16_t createdMonth : 4;
|
|
||||||
uint16_t createdDay : 5;
|
|
||||||
|
|
||||||
uint16_t lastAccessYear : 7;
|
|
||||||
uint16_t lastAccessMonth : 4;
|
|
||||||
uint16_t lastAccessDay : 5;
|
|
||||||
|
|
||||||
uint16_t firstClusterHigh;
|
|
||||||
|
|
||||||
uint16_t modifiedHour : 5;
|
|
||||||
uint16_t modifiedMinute : 6;
|
|
||||||
uint16_t modifiedSecond : 5;
|
|
||||||
|
|
||||||
uint16_t modifiedYear : 7;
|
|
||||||
uint16_t modifiedMonth : 4;
|
|
||||||
uint16_t modifiedDay : 5;
|
|
||||||
|
|
||||||
uint16_t firstClusterLow;
|
|
||||||
uint32_t size;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Directory {
|
|
||||||
DirectoryEntry* entry;
|
|
||||||
uint32_t entries;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FAT16FS;
|
|
||||||
class FAT16FileReadWriter: public ReadWriter {
|
|
||||||
private:
|
|
||||||
uint32_t firstCluster;
|
|
||||||
uint32_t sizeBytes;
|
|
||||||
|
|
||||||
uint32_t currentPosition;
|
|
||||||
|
|
||||||
uint32_t offsetBytesToCluster(uint32_t offset);
|
|
||||||
|
|
||||||
uint32_t clusterSize;
|
|
||||||
|
|
||||||
FAT16FS* backingFS;
|
|
||||||
public:
|
|
||||||
FAT16FileReadWriter(uint32_t firstCluster, uint32_t sizeBytes, FAT16FS* backingFS);
|
|
||||||
|
|
||||||
uint32_t read(uint32_t count, uint8_t* buffer) override;
|
|
||||||
uint32_t write(uint32_t count, uint8_t* buffer) override;
|
|
||||||
uint32_t size() override;
|
|
||||||
uint32_t seek(uint32_t position) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FAT16FS: public FSTree {
|
|
||||||
public:
|
|
||||||
DirectoryEntry* rootDirEntries;
|
|
||||||
uint16_t* FAT1;
|
|
||||||
uint8_t sectorOne[512];
|
|
||||||
|
|
||||||
uint8_t* sectorsPerCluster = ((uint8_t*)(sectorOne + 0x0d));
|
|
||||||
uint16_t* countReserved = ((uint16_t*)(sectorOne + 0x0e));
|
|
||||||
uint8_t* countFATs = ((uint8_t*)(sectorOne + 0x10));
|
|
||||||
uint16_t* countRDEs = ((uint16_t*)(sectorOne + 0x11));
|
|
||||||
uint16_t* sectorsPerFAT = ((uint16_t*)(sectorOne + 0x16));
|
|
||||||
|
|
||||||
ReadWriter* backingDevice;
|
|
||||||
|
|
||||||
void pathEntryTo83(PathEntry pe, char* buffer);
|
|
||||||
|
|
||||||
uint32_t clusterToSector(uint32_t cluster);
|
|
||||||
void load_file(uint32_t location, uint8_t* destination);
|
|
||||||
uint32_t calc_size(uint32_t location);
|
|
||||||
|
|
||||||
xnoe::tuple<DirectoryEntry*, uint32_t, bool> getDirectoryEntry(Path p);
|
|
||||||
xnoe::tuple<DirectoryEntry*, uint32_t, bool> getDirectoryEntryFull(Path p);
|
|
||||||
|
|
||||||
FAT16FS(ReadWriter* disk);
|
|
||||||
|
|
||||||
bool exists(Path p) override;
|
|
||||||
FSType type(Path p) override;
|
|
||||||
|
|
||||||
ReadWriter* open(Path p) override;
|
|
||||||
|
|
||||||
uint32_t getDentsSize(Path p) override;
|
|
||||||
void getDents(Path p, FSDirectoryListing* buffer) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,270 +0,0 @@
|
|||||||
#include "fstree.h"
|
|
||||||
|
|
||||||
bool operator==(const PathEntry& lhs, const PathEntry& rhs) {
|
|
||||||
if (lhs.length == rhs.length)
|
|
||||||
if (lhs.length == 0)
|
|
||||||
return true;
|
|
||||||
else if (lhs.length < rhs.length)
|
|
||||||
return strcmp(lhs.path, rhs.path, lhs.length);
|
|
||||||
else
|
|
||||||
return strcmp(lhs.path, rhs.path, lhs.length);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(const PathEntry& lhs, const PathEntry& rhs) {
|
|
||||||
return !(lhs == rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FS Tree Skeleton
|
|
||||||
bool FSTree::exists(Path p){return;}
|
|
||||||
FSType FSTree::type(Path p){return;}
|
|
||||||
ReadWriter* FSTree::open(Path p){return;}
|
|
||||||
uint32_t FSTree::getDentsSize(Path p){return;}
|
|
||||||
void FSTree::getDents(Path p, FSDirectoryListing* buffer){return;}
|
|
||||||
|
|
||||||
// RootFSTree
|
|
||||||
|
|
||||||
RootFSTree::RootFSTree() {
|
|
||||||
this->node = new FSTreeNode{
|
|
||||||
PathEntry{0,0},
|
|
||||||
xnoe::linkedlist<FSTreeNode*>(),
|
|
||||||
0
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pathEntryInFSTreeNode(PathEntry p, FSTreeNode* n) {
|
|
||||||
xnoe::linkedlistelem<FSTreeNode*>* current = n->children.start;
|
|
||||||
while (current) {
|
|
||||||
if (current->elem->self == p)
|
|
||||||
return true;
|
|
||||||
current = current->next;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
FSTreeNode* getNodeFromPathEntry(PathEntry p, FSTreeNode* n) {
|
|
||||||
if (!n)
|
|
||||||
return 0;
|
|
||||||
xnoe::linkedlistelem<FSTreeNode*>* current = n->children.start;
|
|
||||||
while (current) {
|
|
||||||
if (current->elem->self == p)
|
|
||||||
return current->elem;
|
|
||||||
current = current->next;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
FSTreeNode* RootFSTree::makeNodeIfNotExist(Path p) {
|
|
||||||
PathElement* currentPathElement = p.start;
|
|
||||||
|
|
||||||
FSTreeNode* currentNode = this->node;
|
|
||||||
|
|
||||||
if (!currentPathElement || currentPathElement == p.end)
|
|
||||||
return currentNode;
|
|
||||||
|
|
||||||
nextPE:
|
|
||||||
while (currentPathElement) {
|
|
||||||
xnoe::linkedlistelem<FSTreeNode*>* currentChild = currentNode->children.start;
|
|
||||||
while (currentChild) {
|
|
||||||
if (currentChild->elem->self == currentPathElement->elem) {
|
|
||||||
currentNode = currentChild->elem;
|
|
||||||
currentPathElement = currentPathElement->next;
|
|
||||||
goto nextPE;
|
|
||||||
}
|
|
||||||
currentChild = currentChild->next;
|
|
||||||
}
|
|
||||||
currentNode->children.append(new FSTreeNode{currentPathElement->elem, xnoe::linkedlist<FSTreeNode*>(), 0});
|
|
||||||
currentNode = currentNode->children.end->elem;
|
|
||||||
currentPathElement = currentPathElement->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return currentNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
FSTree* RootFSTree::getLongestMatchingUnder(Path p) {
|
|
||||||
PathElement* currentPath = p.start;
|
|
||||||
FSTreeNode* currentNode = this->node;
|
|
||||||
FSTree* lastMountpoint = 0;
|
|
||||||
while (currentPath && currentNode) {
|
|
||||||
if ((currentPath->elem == currentNode->self) && currentNode->mountpoint)
|
|
||||||
lastMountpoint = currentNode->mountpoint;
|
|
||||||
currentNode = getNodeFromPathEntry(currentPath->elem, currentNode);
|
|
||||||
if (currentNode && currentNode->mountpoint)
|
|
||||||
lastMountpoint = currentNode->mountpoint;
|
|
||||||
currentPath = currentPath->next;
|
|
||||||
}
|
|
||||||
return lastMountpoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
Path* RootFSTree::getRemainingPath(Path p) {
|
|
||||||
PathElement* currentPath = p.start;
|
|
||||||
FSTreeNode* currentNode = this->node;
|
|
||||||
PathElement* lastMountpoint = 0;
|
|
||||||
while (currentPath && currentNode) {
|
|
||||||
if (currentPath->elem == currentNode->self && currentNode->mountpoint)
|
|
||||||
lastMountpoint = currentPath;
|
|
||||||
currentNode = getNodeFromPathEntry(currentPath->elem, currentNode);
|
|
||||||
if (currentNode && currentNode->mountpoint)
|
|
||||||
lastMountpoint = currentPath;
|
|
||||||
currentPath = currentPath->next;
|
|
||||||
}
|
|
||||||
lastMountpoint = lastMountpoint->next;
|
|
||||||
|
|
||||||
if (lastMountpoint) {
|
|
||||||
Path* np = new Path;
|
|
||||||
PathElement* current = lastMountpoint;
|
|
||||||
while (current) {
|
|
||||||
np->append(current->elem);
|
|
||||||
current = current->next;
|
|
||||||
}
|
|
||||||
return np;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
FSTreeNode* RootFSTree::getExhaustive(Path p) {
|
|
||||||
PathElement* currentPath = p.start;
|
|
||||||
FSTreeNode* currentNode = this->node;
|
|
||||||
if (!currentPath)
|
|
||||||
return 0;
|
|
||||||
if (currentPath->elem != currentNode->self)
|
|
||||||
return 0;
|
|
||||||
while (currentPath && currentNode) {
|
|
||||||
currentNode = getNodeFromPathEntry(currentPath->elem, currentNode);
|
|
||||||
currentPath = currentPath->next;
|
|
||||||
}
|
|
||||||
if (currentPath)
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return currentNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
T RootFSTree::attempt(T(FSTree::*fn)(Path), Path p, T fallback) {
|
|
||||||
FSTree* mp = getLongestMatchingUnder(p);
|
|
||||||
if (mp) {
|
|
||||||
Path* rp = getRemainingPath(p);
|
|
||||||
T r;
|
|
||||||
if (rp) {
|
|
||||||
r = (mp->*fn)(*rp);
|
|
||||||
rp->destroy();
|
|
||||||
} else {
|
|
||||||
r = (mp->*fn)(Path());
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
return fallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RootFSTree::attempt(void(FSTree::*fn)(Path, FSDirectoryListing*), Path p, FSDirectoryListing* b) {
|
|
||||||
FSTree* mp = getLongestMatchingUnder(p);
|
|
||||||
if (mp) {
|
|
||||||
Path* rp = getRemainingPath(p);
|
|
||||||
if (rp) {
|
|
||||||
(mp->*fn)(*rp, b);
|
|
||||||
rp->destroy();
|
|
||||||
} else {
|
|
||||||
(mp->*fn)(Path(), b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RootFSTree::exists(Path p) {
|
|
||||||
return attempt<bool>(&FSTree::exists, p, false);
|
|
||||||
}
|
|
||||||
FSType RootFSTree::type(Path p){
|
|
||||||
return attempt<FSType>(&FSTree::type, p, Directory);
|
|
||||||
}
|
|
||||||
ReadWriter* RootFSTree::open(Path p){
|
|
||||||
return attempt<ReadWriter*>(&FSTree::open, p, 0);
|
|
||||||
}
|
|
||||||
uint32_t RootFSTree::getDentsSize(Path p){
|
|
||||||
uint32_t size = attempt<uint32_t>(&FSTree::getDentsSize, p, 0);
|
|
||||||
FSTreeNode* n = getExhaustive(p);
|
|
||||||
if (n) {
|
|
||||||
xnoe::linkedlistelem<FSTreeNode*>* current = n->children.start;
|
|
||||||
while (current) {
|
|
||||||
size += sizeof(FSDirectoryEntry);
|
|
||||||
size += current->elem->self.length;
|
|
||||||
current = current->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
void RootFSTree::getDents(Path p, FSDirectoryListing* buffer){
|
|
||||||
attempt(&FSTree::getDents, p, buffer);
|
|
||||||
uint32_t oldCount = buffer->count;
|
|
||||||
uint32_t stringsOffset = buffer->count * sizeof(FSDirectoryEntry) + sizeof(FSDirectoryListing);
|
|
||||||
uint32_t addCount = 0;
|
|
||||||
char* strings = ((uint32_t)buffer) + stringsOffset;
|
|
||||||
FSTreeNode* n = getExhaustive(p);
|
|
||||||
if (n) {
|
|
||||||
xnoe::linkedlistelem<FSTreeNode*>* current = n->children.start;
|
|
||||||
while (current) {
|
|
||||||
addCount++;
|
|
||||||
current = current->next;
|
|
||||||
}
|
|
||||||
if (addCount) {
|
|
||||||
current = n->children.start;
|
|
||||||
for (int i=buffer->stringsLength; i>=0; i--)
|
|
||||||
strings[i+addCount*sizeof(FSDirectoryEntry)] = strings[i];
|
|
||||||
for (int i=0; i < buffer->count; i++)
|
|
||||||
buffer->entries[i].path.path += addCount*sizeof(FSDirectoryEntry);
|
|
||||||
while (current) {
|
|
||||||
strings += addCount*sizeof(FSDirectoryEntry) + buffer->stringsLength;
|
|
||||||
memcpy(strings, current->elem->self.path, current->elem->self.length);
|
|
||||||
buffer->entries[buffer->count++] = FSDirectoryEntry {
|
|
||||||
PathEntry{
|
|
||||||
current->elem->self.length,
|
|
||||||
strings
|
|
||||||
},
|
|
||||||
Directory,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
strings += current->elem->self.length;
|
|
||||||
current = current->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RootFSTree::isMountpoint(Path p) {
|
|
||||||
Path* mp = getRemainingPath(p);
|
|
||||||
if (mp->start->next)
|
|
||||||
return false;
|
|
||||||
else
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
void RootFSTree::mount(Path p, FSTree* f) {
|
|
||||||
FSTreeNode* fstn = makeNodeIfNotExist(p);
|
|
||||||
fstn->mountpoint = f;
|
|
||||||
}
|
|
||||||
void RootFSTree::unmount(Path p) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Path createPathFromString(char* s) {
|
|
||||||
Path p;
|
|
||||||
p.start = 0;
|
|
||||||
p.end = 0;
|
|
||||||
|
|
||||||
char* lastPtr = s;
|
|
||||||
uint32_t length = 0;
|
|
||||||
|
|
||||||
char c;
|
|
||||||
while (c=*(s++)) {
|
|
||||||
if (c == '/') {
|
|
||||||
if (length == 0)
|
|
||||||
p.append(PathEntry{length, 0});
|
|
||||||
else
|
|
||||||
p.append(PathEntry{length, lastPtr});
|
|
||||||
lastPtr = s;
|
|
||||||
length = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
length += 1;
|
|
||||||
}
|
|
||||||
if (length)
|
|
||||||
p.append(PathEntry{length, lastPtr});
|
|
||||||
return p;
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
#ifndef FSTREE_H
|
|
||||||
#define FSTREE_H
|
|
||||||
|
|
||||||
#include "../datatypes/linkedlist.h"
|
|
||||||
#include "../stdio/readwriter.h"
|
|
||||||
#include "../strings.h"
|
|
||||||
|
|
||||||
struct PathEntry {
|
|
||||||
uint16_t length;
|
|
||||||
uint8_t* path;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool operator==(const PathEntry& lhs, const PathEntry& rhs);
|
|
||||||
|
|
||||||
using Path = xnoe::linkedlist<PathEntry>;
|
|
||||||
using PathElement = xnoe::linkedlistelem<PathEntry>;
|
|
||||||
|
|
||||||
enum FSType {
|
|
||||||
File,
|
|
||||||
Directory,
|
|
||||||
CharacterDev,
|
|
||||||
BlockDev,
|
|
||||||
NoExist
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FSDirectoryEntry {
|
|
||||||
PathEntry path;
|
|
||||||
FSType type;
|
|
||||||
uint32_t sizeBytes;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FSDirectoryListing {
|
|
||||||
uint32_t count;
|
|
||||||
uint32_t stringsLength;
|
|
||||||
FSDirectoryEntry entries[];
|
|
||||||
};
|
|
||||||
|
|
||||||
class FSTreeNode;
|
|
||||||
class FSTree {
|
|
||||||
public:
|
|
||||||
virtual bool exists(Path p);
|
|
||||||
virtual FSType type(Path p);
|
|
||||||
|
|
||||||
virtual ReadWriter* open(Path p);
|
|
||||||
|
|
||||||
virtual uint32_t getDentsSize(Path p);
|
|
||||||
virtual void getDents(Path p, FSDirectoryListing* buffer);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FSTreeNode {
|
|
||||||
PathEntry self;
|
|
||||||
xnoe::linkedlist<FSTreeNode*> children;
|
|
||||||
FSTree* mountpoint;
|
|
||||||
};
|
|
||||||
|
|
||||||
class RootFSTree: public FSTree {
|
|
||||||
private:
|
|
||||||
FSTree* getLongestMatchingUnder(Path p);
|
|
||||||
Path* getRemainingPath(Path p);
|
|
||||||
FSTreeNode* getExhaustive(Path p);
|
|
||||||
|
|
||||||
FSTreeNode* makeNodeIfNotExist(Path p);
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
T attempt(T(FSTree::*fn)(Path), Path p, T fallback);
|
|
||||||
void attempt(void(FSTree::*fn)(Path, FSDirectoryListing*), Path p, FSDirectoryListing* b);
|
|
||||||
public:
|
|
||||||
RootFSTree();
|
|
||||||
|
|
||||||
FSTreeNode* node;
|
|
||||||
|
|
||||||
bool isMountpoint(Path p);
|
|
||||||
void mount(Path p, FSTree* f);
|
|
||||||
void unmount(Path p);
|
|
||||||
|
|
||||||
bool exists(Path p) override;
|
|
||||||
FSType type(Path p) override;
|
|
||||||
|
|
||||||
ReadWriter* open(Path p) override;
|
|
||||||
|
|
||||||
uint32_t getDentsSize(Path p) override;
|
|
||||||
void getDents(Path p, FSDirectoryListing* buffer) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
Path createPathFromString(char* s);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,28 +0,0 @@
|
|||||||
#include "sysfs.h"
|
|
||||||
|
|
||||||
SysFS::SysFS() {
|
|
||||||
addEntry(createPathFromString("remainingPages"), [](){
|
|
||||||
uint32_t remainingPages = Global::kernel->phys->remainingPages;
|
|
||||||
char str[11];
|
|
||||||
uint32_t offset = int_to_decimal(remainingPages, str);
|
|
||||||
return new OneShotReadWriter(str+offset);
|
|
||||||
});
|
|
||||||
addEntry(createPathFromString("initPages"), [](){
|
|
||||||
uint32_t initPages = Global::kernel->phys->initPages;
|
|
||||||
char str[11];
|
|
||||||
uint32_t offset = int_to_decimal(initPages, str);
|
|
||||||
return new OneShotReadWriter(str+offset);
|
|
||||||
});
|
|
||||||
addEntry(createPathFromString("terminalWidth"), [](){
|
|
||||||
uint32_t termWidth = Global::kernel->terminal->width;
|
|
||||||
char str[11];
|
|
||||||
uint32_t offset = int_to_decimal(termWidth, str);
|
|
||||||
return new OneShotReadWriter(str+offset);
|
|
||||||
});
|
|
||||||
addEntry(createPathFromString("terminalHeight"), [](){
|
|
||||||
uint32_t termHeight = Global::kernel->terminal->height;
|
|
||||||
char str[11];
|
|
||||||
uint32_t offset = int_to_decimal(termHeight, str);
|
|
||||||
return new OneShotReadWriter(str+offset);
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
#ifndef SYSFS_H
|
|
||||||
#define SYSFS_H
|
|
||||||
|
|
||||||
#include "vfs.h"
|
|
||||||
#include "../kernel.h"
|
|
||||||
#include "../strings.h"
|
|
||||||
#include "../stdio/oneshotreadwriter.h"
|
|
||||||
|
|
||||||
class SysFS : public VFS {
|
|
||||||
public:
|
|
||||||
SysFS();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,133 +0,0 @@
|
|||||||
#include "vfs.h"
|
|
||||||
|
|
||||||
void VFS::addEntry(Path p, ReadWriter*(*constructor)(Path)) {
|
|
||||||
PathElement* currentPathElement = p.start;
|
|
||||||
|
|
||||||
VFSTreeNode* currentNode = this->root;
|
|
||||||
|
|
||||||
if (!currentPathElement)
|
|
||||||
return currentNode;
|
|
||||||
|
|
||||||
nextPE:
|
|
||||||
while (currentPathElement) {
|
|
||||||
xnoe::linkedlistelem<VFSTreeNode*>* currentChild = currentNode->children.start;
|
|
||||||
while (currentChild) {
|
|
||||||
if (currentChild->elem->self == currentPathElement->elem) {
|
|
||||||
currentNode = currentChild->elem;
|
|
||||||
currentPathElement = currentPathElement->next;
|
|
||||||
goto nextPE;
|
|
||||||
}
|
|
||||||
currentChild = currentChild->next;
|
|
||||||
}
|
|
||||||
if (currentPathElement = p.end) {
|
|
||||||
currentNode->children.append(new VFSTreeNode{currentPathElement->elem, xnoe::linkedlist<VFSTreeNode*>(), constructor, false});
|
|
||||||
} else {
|
|
||||||
if (currentPathElement->elem == PathEntry{1, "*"})
|
|
||||||
currentNode->children.append(new VFSTreeNode{currentPathElement->elem, xnoe::linkedlist<VFSTreeNode*>(), 0, true});
|
|
||||||
else
|
|
||||||
currentNode->children.append(new VFSTreeNode{currentPathElement->elem, xnoe::linkedlist<VFSTreeNode*>(), 0, false});
|
|
||||||
}
|
|
||||||
currentNode = currentNode->children.end->elem;
|
|
||||||
currentPathElement = currentPathElement->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return currentNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
Constructor VFS::getEntry(Path p) {
|
|
||||||
PathElement* currentPathElement = p.start;
|
|
||||||
VFSTreeNode* currentNode = this->root;
|
|
||||||
|
|
||||||
if (!currentPathElement)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
nextPE:
|
|
||||||
while (currentPathElement) {
|
|
||||||
xnoe::linkedlistelem<VFSTreeNode*>* currentChild = currentNode->children.start;
|
|
||||||
while (currentChild) {
|
|
||||||
if (currentChild->elem->self == currentPathElement->elem || currentChild->elem->wildcard) {
|
|
||||||
currentNode = currentChild->elem;
|
|
||||||
currentPathElement = currentPathElement->next;
|
|
||||||
goto nextPE;
|
|
||||||
}
|
|
||||||
currentChild = currentChild->next;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (currentNode->children.length == 0)
|
|
||||||
return currentNode->constructor;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
VFSTreeNode* VFS::getNode(Path p) {
|
|
||||||
PathElement* currentPathElement = p.start;
|
|
||||||
VFSTreeNode* currentNode = this->root;
|
|
||||||
|
|
||||||
nextPE:
|
|
||||||
while (currentPathElement) {
|
|
||||||
xnoe::linkedlistelem<VFSTreeNode*>* currentChild = currentNode->children.start;
|
|
||||||
while (currentChild) {
|
|
||||||
if (currentChild->elem->self == currentPathElement->elem || currentChild->elem->wildcard) {
|
|
||||||
currentNode = currentChild->elem;
|
|
||||||
currentPathElement = currentPathElement->next;
|
|
||||||
goto nextPE;
|
|
||||||
}
|
|
||||||
currentChild = currentChild->next;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return currentNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VFS::exists(Path p) {
|
|
||||||
return getEntry(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReadWriter* VFS::open(Path p) {
|
|
||||||
Constructor c = getEntry(p);
|
|
||||||
return c(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t VFS::getDentsSize(Path p) {
|
|
||||||
VFSTreeNode* node = getNode(p);
|
|
||||||
if (!node)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
uint32_t total = sizeof(FSDirectoryListing);
|
|
||||||
xnoe::linkedlistelem<VFSTreeNode*>* currentNode = node->children.start;
|
|
||||||
while (currentNode) {
|
|
||||||
total += sizeof(FSDirectoryEntry);
|
|
||||||
total += currentNode->elem->self.length;
|
|
||||||
currentNode = currentNode->next;
|
|
||||||
}
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFS::getDents(Path p, FSDirectoryListing* buffer) {
|
|
||||||
VFSTreeNode* node = getNode(p);
|
|
||||||
if (!node)
|
|
||||||
return;
|
|
||||||
|
|
||||||
uint32_t total = sizeof(FSDirectoryListing);
|
|
||||||
xnoe::linkedlistelem<VFSTreeNode*>* currentNode = node->children.start;
|
|
||||||
buffer->count = 0;
|
|
||||||
while (currentNode) {
|
|
||||||
buffer->count++;
|
|
||||||
currentNode = currentNode->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t* strings = (uint8_t*)(buffer) + sizeof(FSDirectoryListing) + sizeof(FSDirectoryEntry) * buffer->count;
|
|
||||||
currentNode = node->children.start;
|
|
||||||
uint32_t index = 0;
|
|
||||||
while (currentNode) {
|
|
||||||
memcpy(strings, currentNode->elem->self.path, currentNode->elem->self.length);
|
|
||||||
buffer->entries[index++] = FSDirectoryEntry{
|
|
||||||
PathEntry{currentNode->elem->self.length, strings},
|
|
||||||
File,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
strings += currentNode->elem->self.length;
|
|
||||||
buffer->stringsLength += currentNode->elem->self.length;
|
|
||||||
currentNode = currentNode->next;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
#ifndef VFS_H
|
|
||||||
#define VFS_H
|
|
||||||
|
|
||||||
#include "fstree.h"
|
|
||||||
|
|
||||||
using Constructor = ReadWriter*(*)(Path);
|
|
||||||
|
|
||||||
struct VFSTreeNode {
|
|
||||||
PathEntry self;
|
|
||||||
xnoe::linkedlist<VFSTreeNode*> children;
|
|
||||||
ReadWriter*(*constructor)(Path);
|
|
||||||
bool wildcard;
|
|
||||||
};
|
|
||||||
|
|
||||||
class VFS : public FSTree {
|
|
||||||
VFSTreeNode* root = new VFSTreeNode{PathEntry{0,0},xnoe::linkedlist<VFSTreeNode*>(),0,false};
|
|
||||||
public:
|
|
||||||
|
|
||||||
void addEntry(Path p, ReadWriter*(*)(Path));
|
|
||||||
Constructor getEntry(Path p);
|
|
||||||
VFSTreeNode* getNode(Path p);
|
|
||||||
|
|
||||||
bool exists(Path p) override;
|
|
||||||
ReadWriter* open(Path p) override;
|
|
||||||
uint32_t getDentsSize(Path p) override;
|
|
||||||
void getDents(Path p, FSDirectoryListing* buffer) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -38,7 +38,7 @@ tss_struct tss = (tss_struct) {
|
|||||||
.ldtr = 0,
|
.ldtr = 0,
|
||||||
._reserved10 = 0,
|
._reserved10 = 0,
|
||||||
._reserved11 = 0,
|
._reserved11 = 0,
|
||||||
.iopb = sizeof(tss_struct)
|
.iopb = 104
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr gdt_entry::gdt_entry(uint32_t limit, uint32_t base, bool rw, bool exec, bool system, uint8_t ring) :
|
constexpr gdt_entry::gdt_entry(uint32_t limit, uint32_t base, bool rw, bool exec, bool system, uint8_t ring) :
|
||||||
@ -77,8 +77,7 @@ constexpr gdt_entry::gdt_entry() :
|
|||||||
base_hi(0)
|
base_hi(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
gdt_and_iopb gai = {
|
gdt_entry gdt[] = {
|
||||||
.gdt = {
|
|
||||||
gdt_entry(), // Null Segment
|
gdt_entry(), // Null Segment
|
||||||
gdt_entry(0xfffff, 0, 1, 1, 1, 0), // Kernel Code Segment
|
gdt_entry(0xfffff, 0, 1, 1, 1, 0), // Kernel Code Segment
|
||||||
gdt_entry(0xfffff, 0, 1, 0, 1, 0), // Kernel Data Segment
|
gdt_entry(0xfffff, 0, 1, 0, 1, 0), // Kernel Data Segment
|
||||||
@ -87,19 +86,16 @@ gdt_and_iopb gai = {
|
|||||||
gdt_entry(0xfffff, 0, 1, 0, 1, 3), // User Data Segment
|
gdt_entry(0xfffff, 0, 1, 0, 1, 3), // User Data Segment
|
||||||
|
|
||||||
gdt_entry() // Empty Task State Segment
|
gdt_entry() // Empty Task State Segment
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
gdt_descr descr = (gdt_descr){
|
gdt_descr descr = (gdt_descr){
|
||||||
.size = sizeof(gai.gdt) - 1,
|
.size = sizeof(gdt) - 1,
|
||||||
.offset = gai.gdt,
|
.offset = gdt,
|
||||||
};
|
};
|
||||||
|
|
||||||
void init_gdt() {
|
void init_gdt() {
|
||||||
gai.gdt[5] = gdt_entry(sizeof(tss) + 8193, &tss, 0, 1, 0, 0); // Initialise the TSS.
|
gdt[5] = gdt_entry(sizeof(tss), &tss, 0, 1, 0, 0); // Initialise the TSS.
|
||||||
gai.gdt[5].accessed = 1;
|
gdt[5].accessed = 1;
|
||||||
for (int i=0; i<8192; i++)
|
|
||||||
gai.iopb[i] = 0;
|
|
||||||
asm volatile("lgdt %0;"
|
asm volatile("lgdt %0;"
|
||||||
"mov $0x10, %%eax;"
|
"mov $0x10, %%eax;"
|
||||||
"mov %%eax, %%ss;"
|
"mov %%eax, %%ss;"
|
||||||
|
@ -76,11 +76,6 @@ struct __attribute__((packed)) gdt_descr {
|
|||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct __attribute__((packed)) gdt_and_iopb {
|
|
||||||
gdt_entry gdt[6];
|
|
||||||
uint8_t iopb[8192];
|
|
||||||
};
|
|
||||||
|
|
||||||
void init_gdt();
|
void init_gdt();
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -7,9 +7,6 @@ for i ({0..255}); do
|
|||||||
echo "isr$i:" >> isr.S
|
echo "isr$i:" >> isr.S
|
||||||
echo " push ebp" >> isr.S
|
echo " push ebp" >> isr.S
|
||||||
echo " mov ebp, esp" >> isr.S
|
echo " mov ebp, esp" >> isr.S
|
||||||
if (( (i == 8 || i == 17 || (i >= 10 && i <= 14) ) )); then
|
|
||||||
echo " add ebp, 4" >> isr.S
|
|
||||||
fi
|
|
||||||
if (( !(i == 8 || i == 17 || (i >= 10 && i <= 14) ) )); then
|
if (( !(i == 8 || i == 17 || (i >= 10 && i <= 14) ) )); then
|
||||||
echo " push 0" >> isr.S
|
echo " push 0" >> isr.S
|
||||||
fi
|
fi
|
||||||
|
@ -4,11 +4,9 @@ namespace Global {
|
|||||||
Allocator* allocator = 0;
|
Allocator* allocator = 0;
|
||||||
Kernel* kernel = 0;
|
Kernel* kernel = 0;
|
||||||
Process* currentProc = 0;
|
Process* currentProc = 0;
|
||||||
Thread* currentThread = 0;
|
|
||||||
tss_struct* tss = 0;
|
tss_struct* tss = 0;
|
||||||
bool currentProcValid = false;
|
bool currentProcValid = false;
|
||||||
uint32_t milliseconds_elapsed = 0;
|
xnoe::hashtable<void*, ReadWriter*>* FH; // Map of File Handlers -> Read Writer
|
||||||
uint32_t resp = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void* operator new (uint32_t size) {
|
void* operator new (uint32_t size) {
|
||||||
@ -34,11 +32,3 @@ void* operator new[] (uint32_t size) {
|
|||||||
void operator delete[] (void* ptr) {
|
void operator delete[] (void* ptr) {
|
||||||
Global::allocator->deallocate((uint32_t)ptr);
|
Global::allocator->deallocate((uint32_t)ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
int clamp(int a, int b, int c) {
|
|
||||||
if (a < b)
|
|
||||||
return b;
|
|
||||||
if (a > c)
|
|
||||||
return c;
|
|
||||||
return a;
|
|
||||||
}
|
|
@ -6,19 +6,20 @@
|
|||||||
class Kernel;
|
class Kernel;
|
||||||
class Allocator;
|
class Allocator;
|
||||||
class Process;
|
class Process;
|
||||||
class Thread;
|
|
||||||
struct tss_struct;
|
struct tss_struct;
|
||||||
class ReadWriter;
|
class ReadWriter;
|
||||||
|
namespace xnoe {
|
||||||
|
template<class, class>
|
||||||
|
class hashtable;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Global {
|
namespace Global {
|
||||||
extern Allocator* allocator;
|
extern Allocator* allocator;
|
||||||
extern Kernel* kernel;
|
extern Kernel* kernel;
|
||||||
extern Process* currentProc;
|
extern Process* currentProc;
|
||||||
extern Thread* currentThread;
|
|
||||||
extern tss_struct* tss;
|
extern tss_struct* tss;
|
||||||
extern bool currentProcValid;
|
extern bool currentProcValid;
|
||||||
extern uint32_t milliseconds_elapsed;
|
extern xnoe::hashtable<void*, ReadWriter*>* FH;
|
||||||
extern uint32_t resp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void* operator new (uint32_t size);
|
void* operator new (uint32_t size);
|
||||||
@ -29,6 +30,4 @@ void operator delete (void* ptr, unsigned int size);
|
|||||||
void* operator new[] (uint32_t size);
|
void* operator new[] (uint32_t size);
|
||||||
void operator delete[] (void* ptr);
|
void operator delete[] (void* ptr);
|
||||||
|
|
||||||
int clamp(int a, int b, int c);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -22,12 +22,11 @@ void set_entry(uint8_t interrupt_number, uint16_t code_segment, void(*handler)()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void handle_fault(frame_struct* frame) {
|
void handle_fault(frame_struct* frame) {
|
||||||
//frame_struct* frame = &Global::currentThread->frame;
|
|
||||||
// Clear interrupts, we don't want to perform a context switch whilst handling a fault.
|
// Clear interrupts, we don't want to perform a context switch whilst handling a fault.
|
||||||
asm ("cli");
|
asm ("cli");
|
||||||
uint32_t problem_address;
|
uint32_t problem_address;
|
||||||
asm ("mov %%cr2, %0" : "=a" (problem_address):);
|
asm ("mov %%cr2, %0" : "=a" (problem_address):);
|
||||||
Global::kernel->terminal->printf("\x1b[44;37;1m(CS %x EIP %x): ", frame->cs, frame->eip);
|
Global::kernel->terminal->printf("(CS %x EIP %x): ", frame->cs, frame->eip);
|
||||||
switch (frame->gate) {
|
switch (frame->gate) {
|
||||||
case 0: // Divide by zero
|
case 0: // Divide by zero
|
||||||
Global::kernel->terminal->printf("Divide by Zero");
|
Global::kernel->terminal->printf("Divide by Zero");
|
||||||
@ -37,23 +36,17 @@ void handle_fault(frame_struct* frame) {
|
|||||||
break;
|
break;
|
||||||
case 13: // GPF
|
case 13: // GPF
|
||||||
Global::kernel->terminal->printf("General Protection Fault!");
|
Global::kernel->terminal->printf("General Protection Fault!");
|
||||||
if (frame->eflags & 0x00020000) {
|
|
||||||
Global::kernel->terminal->printf("\x1b[42;37;1mv86 GPF! All is good!\n");
|
|
||||||
v86_monitor((v8086_frame_struct*)frame);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 14: // Page Fault
|
case 14: // Page Fault
|
||||||
Global::kernel->terminal->printf("Page Fault at %x", problem_address);
|
Global::kernel->terminal->printf("Page Fault at %x", problem_address);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Global::kernel->terminal->printf("Unkown Fault! Gate: %d", frame->gate);
|
Global::kernel->terminal->printf("Unkown Fault!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Global::kernel->terminal->printf(" Error Code: %x\n", frame->errcode);
|
Global::kernel->terminal->printf(" Error Code: %x\n", frame->errcode);
|
||||||
if (!(frame->cs & 3)) {
|
if (!(frame->cs & 3)) {
|
||||||
Global::kernel->terminal->printf("[FATAL] Kernel Fault!!!\n");
|
Global::kernel->terminal->printf("[FATAL] Kernel Fault!!!\n");
|
||||||
((VGAModeTerminal*)Global::kernel->terminal)->bufferToVRAM();
|
|
||||||
while (1) asm("hlt");
|
while (1) asm("hlt");
|
||||||
} else {
|
} else {
|
||||||
// Print an error message.
|
// Print an error message.
|
||||||
@ -65,14 +58,16 @@ void handle_fault(frame_struct* frame) {
|
|||||||
Global::kernel->destroyProcess(Global::currentProc);
|
Global::kernel->destroyProcess(Global::currentProc);
|
||||||
|
|
||||||
Global::currentProcValid = false;
|
Global::currentProcValid = false;
|
||||||
context_switch();
|
|
||||||
|
// Go in to an infinite loop
|
||||||
|
asm ("sti");
|
||||||
|
while (1) asm ("hlt");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ignore_interrupt(frame_struct* _) {}
|
void ignore_interrupt(frame_struct* frame) {}
|
||||||
|
|
||||||
void context_switch() {
|
void context_switch(frame_struct* frame) {
|
||||||
frame_struct* frame = &Global::currentThread->frame;
|
|
||||||
// When any interrupt occurs (including context_switch), SS:ESP is set to
|
// When any interrupt occurs (including context_switch), SS:ESP is set to
|
||||||
// the values of SS0:ESP0 in Global::tss
|
// the values of SS0:ESP0 in Global::tss
|
||||||
//
|
//
|
||||||
@ -88,123 +83,101 @@ void context_switch() {
|
|||||||
|
|
||||||
asm ("cli"); // Disable interrupts whilst handling the context switch.
|
asm ("cli"); // Disable interrupts whilst handling the context switch.
|
||||||
|
|
||||||
xnoe::linkedlist<Thread*>* threads = &Global::kernel->threads;
|
xnoe::linkedlist<Process*>* processes = &Global::kernel->processes;
|
||||||
|
|
||||||
if (!threads->start) {
|
if (!processes->start) {
|
||||||
Global::kernel->terminal->printf("[FATAL] No more processes! Halting!\n");
|
Global::kernel->terminal->printf("[FATAL] No more processes! Halting!\n");
|
||||||
while (1) asm ("hlt");
|
while (1) asm ("hlt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Global::currentProcValid)
|
||||||
|
Global::currentProc->kernelStackPtr = frame->new_esp;
|
||||||
|
|
||||||
// This cursed bit of code first determines if the processes list is longer than 1 and if it is
|
// This cursed bit of code first determines if the processes list is longer than 1 and if it is
|
||||||
// - Determines if it has 2 or more elements
|
// - Determines if it has 2 or more elements
|
||||||
// - If it has two, swap the first and last, update prev and next of each to be null or the other item
|
// - If it has two, swap the first and last, update prev and next of each to be null or the other item
|
||||||
// - If it has more than two, add the start to the end then set start to the second element
|
// - If it has more than two, add the start to the end then set start to the second element
|
||||||
uint32_t count = 0;
|
if (Global::currentProc) {
|
||||||
do {
|
if (processes->start->next != 0) {
|
||||||
if (count++ == threads->length)
|
if (processes->end->prev == processes->start) {
|
||||||
return;
|
xnoe::linkedlistelem<Process*>* tmp = processes->start;
|
||||||
if (Global::currentThread) {
|
processes->start = processes->end;
|
||||||
if (threads->start->next != 0) {
|
processes->end = tmp;
|
||||||
if (threads->end->prev == threads->start) {
|
|
||||||
xnoe::linkedlistelem<Thread*>* tmp = threads->start;
|
|
||||||
threads->start = threads->end;
|
|
||||||
threads->end = tmp;
|
|
||||||
|
|
||||||
threads->start->prev = 0;
|
processes->start->prev = 0;
|
||||||
threads->end->next = 0;
|
processes->end->next = 0;
|
||||||
threads->end->prev = threads->start;
|
processes->end->prev = processes->start;
|
||||||
threads->start->next = threads->end;
|
processes->start->next = processes->end;
|
||||||
} else {
|
} else {
|
||||||
threads->end->next = threads->start;
|
processes->end->next = processes->start;
|
||||||
threads->start = threads->start->next;
|
processes->start = processes->start->next;
|
||||||
threads->start->prev = 0;
|
processes->start->prev = 0;
|
||||||
xnoe::linkedlistelem<Thread*>* tmp = threads->end;
|
xnoe::linkedlistelem<Process*>* tmp = processes->end;
|
||||||
threads->end = threads->end->next;
|
processes->end = processes->end->next;
|
||||||
threads->end->next = 0;
|
processes->end->next = 0;
|
||||||
threads->end->prev = tmp;
|
processes->end->prev = tmp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Global::currentThread = threads->start->elem;
|
|
||||||
Global::currentProc = threads->start->elem->parent;
|
Global::currentProc = processes->start->elem;
|
||||||
} while (Global::currentThread->state != Running);
|
|
||||||
|
|
||||||
// Select the next processes page directory
|
// Select the next processes page directory
|
||||||
Global::currentThread->frame.new_cr3 = Global::currentThread->parent->PD->phys_addr;
|
frame->new_cr3 = Global::currentProc->PD->phys_addr;
|
||||||
|
// Restore kernelStackPtr of the new process.
|
||||||
|
frame->new_esp = Global::currentProc->kernelStackPtr;
|
||||||
|
|
||||||
Global::tss->esp0 = (uint32_t)Global::currentThread->kernelStackPtrDefault;
|
Global::tss->esp0 = Global::currentProc->kernelStackPtrDefault;
|
||||||
|
|
||||||
// Set the current proc to valid
|
// Set the current proc to valid
|
||||||
Global::currentProcValid = true;
|
Global::currentProcValid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Timer {
|
namespace Timer {
|
||||||
// counter, default count, function, argument, oneshot
|
using TimedEvent = xnoe::tuple<uint32_t, uint32_t, void(*)(frame_struct*, void*), void*>;
|
||||||
using TimedEvent = xnoe::tuple<uint32_t, uint32_t, void(*)(void*), void*, bool>;
|
|
||||||
xnoe::linkedlist<TimedEvent> timed_events;
|
xnoe::linkedlist<TimedEvent> timed_events;
|
||||||
void tick(frame_struct* _) {
|
void tick(frame_struct* frame) {
|
||||||
xnoe::linkedlistelem<TimedEvent>* current = timed_events.start;
|
xnoe::linkedlistelem<TimedEvent>* current = timed_events.start;
|
||||||
while (current) {
|
while (current) {
|
||||||
TimedEvent t = current->elem;
|
TimedEvent t = current->elem;
|
||||||
uint32_t count = xnoe::get<0>(t);
|
uint32_t count = xnoe::get<0>(t);
|
||||||
if (--count == 0) {
|
if (--count == 0) {
|
||||||
xnoe::get<2>(t)(xnoe::get<3>(t));
|
xnoe::get<2>(t)(frame, xnoe::get<3>(t));
|
||||||
count = xnoe::get<1>(t);
|
count = xnoe::get<1>(t);
|
||||||
|
|
||||||
if (xnoe::get<4>(t)) {
|
|
||||||
xnoe::linkedlistelem<TimedEvent>* prev = current;
|
|
||||||
current = current->next;
|
|
||||||
timed_events.remove(prev);
|
|
||||||
delete prev;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
current->elem = TimedEvent(count, xnoe::get<1>(t), xnoe::get<2>(t), xnoe::get<3>(t));
|
||||||
current->elem = TimedEvent(count, xnoe::get<1>(t), xnoe::get<2>(t), xnoe::get<3>(t), xnoe::get<4>(t));
|
|
||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
Global::milliseconds_elapsed++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void register_event(uint32_t milliseconds, void(*function)(void*), void* auxiliary, bool oneshot=false) {
|
void register_event(uint32_t milliseconds, void(*function)(frame_struct*, void*), void* auxiliary) {
|
||||||
timed_events.append(TimedEvent(milliseconds, milliseconds, function, auxiliary, oneshot));
|
timed_events.append(TimedEvent(milliseconds, milliseconds, function, auxiliary));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void awaken(Thread* t) {
|
void syscall(frame_struct* frame) {
|
||||||
t->state = Running;
|
|
||||||
}
|
|
||||||
|
|
||||||
void syscall(frame_struct* _) {
|
|
||||||
// Syscall ABI:
|
// Syscall ABI:
|
||||||
// 0: getDentsSize :: char* path -> uint32_t size
|
// 0: X
|
||||||
// 1: getDents :: char* path -> uint8_t* buffer -> void
|
// 1: X
|
||||||
// 2: exists :: char* path -> bool
|
// 2: X
|
||||||
// 3: type :: char* path -> FSType
|
// 3: X
|
||||||
// 4: localalloc :: uint32_t size -> void* ptr
|
// 4: localalloc: LocalAlloc: Allocate under current process (in esi: size; out eax void* ptr)
|
||||||
// 5: localdelete :: void* ptr -> void
|
// 5: localdelete: LocalDelete: Deallocate under current process (in esi: pointer)
|
||||||
// 6: getMillisecondsElapsed :: void -> uint32_t
|
// 6: X
|
||||||
// 7: exec :: void* filehandler -> int PID // Spawns a process and returns its PID.
|
// 7: fork :: char* filename esi -> int PID // Spawns a process and returns its PID.
|
||||||
// 8: getPID: returns the current process's PID (out eax: uint32_t)
|
// 8: getPID: returns the current process's PID (out eax: uint32_t)
|
||||||
// 9: die :: destroys the current process void -> void
|
// 9: getFileHandler :: char* path esi -> void* eax // Returns a file handlers for a specific file
|
||||||
// 10: read :: uint32_t count -> void* filehandler -> uint8_t* outputbuffer -> int read // Reads from a file handler in to a buffer, returns successful read
|
// 10: read :: uint32_t count ebx -> void* filehandler esi -> uint8_t* outputbuffer edi -> int read // Reads from a file handler in to a buffer, returns successful read
|
||||||
// 11: write :: uint32_t count -> void* filehandler -> uint8_t* inputbuffer -> int written // Reads from a buffer in to a file, returns successful written
|
// 11: write :: uint32_t count ebx -> void* filehandler esi -> uint8_t* inputbuffer edi -> int written // Reads from a buffer in to a file, returns successful written
|
||||||
// 12: bindToKeyboard :: void -> void // Binds the current process's stdout to the keyboard.
|
// 12: bindToKeyboard :: void -> void // Binds the current process's stdout to the keyboard.
|
||||||
|
|
||||||
// 13: bindStdout :: int PID -> int filehandler // Returns a filehandler for a CircularRWBuffer binding stdout of another process.
|
// 13: bindStdout :: int PID esi -> int filehandler // Returns a filehandler for a CircularRWBuffer binding stdout of another process.
|
||||||
// 14: bindStdin :: int PID -> int filehandler // Returns a filehandler for a CircularRWBuffer binding stdin of another process.
|
// 14: bindStdin :: int PID esi -> int filehandler // Returns a filehandler for a CircularRWBuffer binding stdin of another process.
|
||||||
|
|
||||||
// 15: fopen :: char* path -> int filehandler // Returns a filehandler to the file.
|
// 15: fopen :: char* path esi -> int filehandler // Returns a filehandler to the file.
|
||||||
// 16: fclose :: int filehandler -> void // Closes a file handler.
|
// 16: fclose :: int filehandler esi -> void // Closes a file handler.
|
||||||
|
|
||||||
// 17: kill :: int PID -> void // Destroys a process.
|
// 17: kill :: int PID esi -> void // Destroys a process.
|
||||||
|
|
||||||
// 18: sleep :: int time ms -> void // Sleeps the current process for time milliseconds.
|
|
||||||
|
|
||||||
// 19: getInitPages :: void -> uint_32 // Returns the amount of physical pages available at boot.
|
|
||||||
// 20: getRemainingPages :: void -> uint_32 // Returns the amount of physical pages remaining.
|
|
||||||
|
|
||||||
// 21: getCurrentTerminalWidth :: void -> uint32_t // Gets the width of the current terminal
|
|
||||||
// 22: getCurrentTerminalHeight :: void -> uint32_t // Gets the height of the current terminal
|
|
||||||
|
|
||||||
// File handlers:
|
// File handlers:
|
||||||
// 0: Stdout
|
// 0: Stdout
|
||||||
@ -212,143 +185,136 @@ void syscall(frame_struct* _) {
|
|||||||
// 2..7: Reserved
|
// 2..7: Reserved
|
||||||
// _: General use
|
// _: General use
|
||||||
|
|
||||||
frame_struct* frame = &Global::currentThread->frame;
|
uint32_t rval = frame->eax;
|
||||||
|
|
||||||
|
uint32_t esi = frame->esi;
|
||||||
|
uint32_t edi = frame->edi;
|
||||||
|
|
||||||
Process* currentProc = Global::currentProc;
|
Process* currentProc = Global::currentProc;
|
||||||
|
|
||||||
switch (frame->eax) {
|
switch (frame->eax) {
|
||||||
case 0: // getDentsSize
|
case 0:
|
||||||
frame->eax = Global::kernel->rootfs->getDentsSize(createPathFromString((char*)frame->ebx));
|
|
||||||
break;
|
break;
|
||||||
case 1: // getDents
|
case 1:
|
||||||
Global::kernel->rootfs->getDents(createPathFromString((char*)frame->ebx), (FSDirectoryListing*)frame->ecx);
|
|
||||||
break;
|
break;
|
||||||
case 2: // exists
|
case 2:
|
||||||
frame->eax = Global::kernel->rootfs->exists(createPathFromString((char*)frame->ebx));
|
|
||||||
break;
|
break;
|
||||||
case 3: // type
|
case 3:
|
||||||
frame->eax = Global::kernel->rootfs->type(createPathFromString((char*)frame->ebx));
|
|
||||||
break;
|
break;
|
||||||
case 4: // malloc
|
case 4:
|
||||||
frame->eax = (uint32_t)currentProc->allocate(frame->ebx);
|
rval = currentProc->allocate(esi);
|
||||||
break;
|
break;
|
||||||
case 5: // free
|
case 5:
|
||||||
currentProc->deallocate(frame->ebx);
|
currentProc->deallocate(esi);
|
||||||
break;
|
break;
|
||||||
case 6: // getMillisecondsElapsed
|
case 6:
|
||||||
frame->eax = Global::milliseconds_elapsed;
|
|
||||||
break;
|
break;
|
||||||
|
case 7: {
|
||||||
case 7: {// execve
|
|
||||||
asm("cli");
|
asm("cli");
|
||||||
xnoe::maybe<ReadWriter*> file = Global::currentProc->getFH(frame->ebx);
|
Process* p = Global::kernel->createProcess(esi);
|
||||||
if (file.is_ok()) {
|
rval = p->PID;
|
||||||
Process* p = Global::kernel->createProcess(file.get(), (uint8_t**)frame->ecx, (uint8_t**)frame->edx);
|
|
||||||
|
|
||||||
// Suspend the current thread and forward the current process's stdin and stdout to the new one.
|
|
||||||
Global::currentThread->state = Suspended;
|
|
||||||
p->stdin = Global::currentProc->stdin;
|
|
||||||
p->stdout = Global::currentProc->stdout;
|
|
||||||
p->threads.start->elem->suspending = Global::currentThread->TID;
|
|
||||||
context_switch();
|
|
||||||
} else {
|
|
||||||
frame->eax = 0;
|
|
||||||
}
|
|
||||||
asm("sti");
|
asm("sti");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 8:
|
||||||
case 8: // getPID
|
rval = currentProc->PID;
|
||||||
frame->eax = currentProc->PID;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 9: { // die
|
case 9:
|
||||||
Global::kernel->PD->select();
|
break;
|
||||||
Global::kernel->destroyProcess(Global::currentProc, frame->ebx);
|
|
||||||
Global::currentProcValid = false;
|
|
||||||
context_switch();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 10: { // read
|
case 10: {
|
||||||
xnoe::maybe<ReadWriter*> fh = Global::currentProc->getFH(frame->ecx);
|
if (esi == 1) {
|
||||||
|
ReadWriter* stdin = currentProc->stdin;
|
||||||
|
if (!stdin)
|
||||||
|
break;
|
||||||
|
|
||||||
|
rval = stdin->read(frame->ebx, edi);
|
||||||
|
} else {
|
||||||
|
xnoe::Maybe<ReadWriter*> fh = Global::FH->get(esi);
|
||||||
if (!fh.is_ok()) {
|
if (!fh.is_ok()) {
|
||||||
frame->eax = 0;
|
rval = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadWriter* rw = fh.get();
|
ReadWriter* rw = fh.get();
|
||||||
frame->eax = rw->read(frame->ebx, (uint8_t*)frame->edx);
|
rval = rw->read(frame->ebx, edi);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 11: { // write
|
case 11: {
|
||||||
xnoe::maybe<ReadWriter*> fh = Global::currentProc->getFH(frame->ecx);
|
if (esi == 0) {
|
||||||
|
ReadWriter* stdout = currentProc->stdout;
|
||||||
|
if (!stdout)
|
||||||
|
break;
|
||||||
|
|
||||||
|
rval = stdout->write(frame->ebx, edi);
|
||||||
|
} else {
|
||||||
|
xnoe::Maybe<ReadWriter*> fh = Global::FH->get(esi);
|
||||||
if (!fh.is_ok()) {
|
if (!fh.is_ok()) {
|
||||||
frame->eax = 0;
|
rval = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadWriter* rw = fh.get();
|
ReadWriter* rw = fh.get();
|
||||||
frame->eax = rw->write(frame->ebx, (uint8_t*)frame->edx);
|
rval = rw->write(frame->ebx, edi);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 12: // bindToKeyboard
|
case 12:
|
||||||
if (currentProc->stdin)
|
if (currentProc->stdin)
|
||||||
currentProc->stdin->close();
|
break;
|
||||||
|
|
||||||
currentProc->stdin = new CircularRWBuffer();
|
currentProc->stdin = new CircularRWBuffer(currentProc->PID, 0);
|
||||||
Global::kernel->KBListeners.append(currentProc);
|
Global::kernel->KBListeners.append(currentProc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 13: { // bindStdout
|
case 13: {
|
||||||
xnoe::maybe<Process*> pm = Global::kernel->pid_map->get(frame->ebx);
|
xnoe::Maybe<Process*> pm = Global::kernel->pid_map->get(esi);
|
||||||
if (!pm.is_ok())
|
if (!pm.is_ok())
|
||||||
break;
|
break;
|
||||||
Process* p = pm.get();
|
Process* p = pm.get();
|
||||||
//if (!p->stdout) {
|
if (!p->stdout) {
|
||||||
//ReadWriter* buffer = new CircularRWBuffer(currentProc->PID, frame->ebx);
|
ReadWriter* buffer = new CircularRWBuffer(currentProc->PID, esi);
|
||||||
//p->stdout = buffer;
|
p->stdout = buffer;
|
||||||
p->stdout->open();
|
rval = Global::kernel->mapFH(buffer);
|
||||||
frame->eax = Global::currentProc->mapFH(p->stdout);
|
}
|
||||||
//}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 14: { // bindStdin
|
case 14: {
|
||||||
xnoe::maybe<Process*> pm = Global::kernel->pid_map->get(frame->ebx);
|
xnoe::Maybe<Process*> pm = Global::kernel->pid_map->get(esi);
|
||||||
if (!pm.is_ok())
|
if (!pm.is_ok())
|
||||||
break;
|
break;
|
||||||
Process* p = pm.get();
|
Process* p = pm.get();
|
||||||
//if (!p->stdin) {
|
if (!p->stdin) {
|
||||||
//ReadWriter* buffer = new CircularRWBuffer(frame->ebx, currentProc->PID);
|
ReadWriter* buffer = new CircularRWBuffer(esi, currentProc->PID);
|
||||||
//p->stdin = buffer;
|
p->stdin = buffer;
|
||||||
p->stdin->open();
|
rval = Global::kernel->mapFH(buffer);
|
||||||
frame->eax = Global::currentProc->mapFH(p->stdin);
|
}
|
||||||
//}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 15: { // fopen
|
case 15: {
|
||||||
ReadWriter* file = Global::kernel->rootfs->open(createPathFromString((char*)frame->ebx));
|
ReadWriter* file = new FATFileReadWriter(0, esi);
|
||||||
if (file)
|
rval = Global::kernel->mapFH(file);
|
||||||
frame->eax = Global::currentProc->mapFH(file);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 16: { // fclose
|
case 16: {
|
||||||
xnoe::maybe<ReadWriter*> f = Global::currentProc->getFH(frame->ebx);
|
xnoe::Maybe<ReadWriter*> f = Global::FH->get(esi);
|
||||||
if (f.is_ok()) {
|
if (f.is_ok()) {
|
||||||
f.get()->close();
|
delete f.get();
|
||||||
Global::currentProc->unmapFH(frame->ebx);
|
Global::kernel->unmapFH(esi);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 17: { // kill
|
case 17: {
|
||||||
asm("cli");
|
asm("cli");
|
||||||
xnoe::maybe<Process*> p = Global::kernel->pid_map->get(frame->ebx);
|
xnoe::Maybe<Process*> p = Global::kernel->pid_map->get(esi);
|
||||||
if (p.is_ok()) {
|
if (p.is_ok()) {
|
||||||
Process* proc = p.get();
|
Process* proc = p.get();
|
||||||
Global::kernel->destroyProcess(proc);
|
Global::kernel->destroyProcess(proc);
|
||||||
@ -357,118 +323,11 @@ void syscall(frame_struct* _) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 18: { // sleep
|
|
||||||
Global::currentThread->state = Suspended;
|
|
||||||
Timer::register_event(frame->ebx, (void(*)(void*))&awaken, (void*)Global::currentThread, true);
|
|
||||||
context_switch();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 19: // getRemainingPages
|
|
||||||
frame->eax = Global::kernel->phys->remainingPages;
|
|
||||||
break;
|
|
||||||
case 20: // getInitPages
|
|
||||||
frame->eax = Global::kernel->phys->initPages;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 21: // getTerminalWidth
|
|
||||||
frame->eax = Global::kernel->terminal->width;
|
|
||||||
break;
|
|
||||||
case 22: // getTerminalHeight
|
|
||||||
frame->eax = Global::kernel->terminal->height;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 23: { // getProcessState
|
|
||||||
xnoe::maybe<Process*> p = Global::kernel->pid_map->get(frame->ebx);
|
|
||||||
if (p.is_ok()) {
|
|
||||||
Process* proc = p.get();
|
|
||||||
//frame->eax = proc->state;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 25: { // fork
|
|
||||||
Process* p = new Process(Global::currentProc);
|
|
||||||
Thread* t = new Thread(Global::currentThread, p);
|
|
||||||
t->parent = p;
|
|
||||||
p->threads.append(t);
|
|
||||||
Global::kernel->registerThread(t);
|
|
||||||
Global::kernel->registerProcess(p);
|
|
||||||
frame->eax = p->PID;
|
|
||||||
t->frame.eax = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 24: { // spawnThread
|
|
||||||
Thread* thread = new Thread(Global::currentProc);
|
|
||||||
thread->initKernelStack((void*)frame->ebx, thread->stack);
|
|
||||||
Global::kernel->registerThread(thread);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 26: {// programRunning
|
|
||||||
xnoe::maybe<Process*> p = Global::kernel->pid_map->get(frame->ebx);
|
|
||||||
frame->eax = p.is_ok();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void v86_monitor(v8086_frame_struct* frame) {
|
frame->eax = rval;
|
||||||
uint8_t* ip = (uint8_t*)((frame->cs<<4) + frame->eip);
|
|
||||||
uint16_t* sp = (uint16_t*)frame->esp;
|
|
||||||
uint16_t flags = (uint16_t)frame->eflags;
|
|
||||||
switch (*ip) {
|
|
||||||
case 0x9c:
|
|
||||||
*(--sp) = (uint16_t)frame->eflags;
|
|
||||||
frame->eip++;
|
|
||||||
break;
|
|
||||||
case 0x9d:
|
|
||||||
frame->eflags &= 0xffff0000;
|
|
||||||
frame->eflags |= *(sp++);
|
|
||||||
frame->eip++;
|
|
||||||
break;
|
|
||||||
case 0xcd: {
|
|
||||||
// Handle int
|
|
||||||
if (!ip[1]) {
|
|
||||||
asm("mov %0, %%esp"::"a"(Global::resp));
|
|
||||||
asm("popa");
|
|
||||||
asm("ret");
|
|
||||||
}
|
|
||||||
uint32_t vector_data = *(uint32_t*)(ip[1]<<2);
|
|
||||||
*(--sp) = flags;
|
|
||||||
frame->eflags &= ~(0x00040300);
|
|
||||||
*(--sp) = (uint16_t)frame->cs;
|
|
||||||
*(--sp) = (uint16_t)(frame->eip);
|
|
||||||
uint16_t* vector = (uint16_t*)&vector_data;
|
|
||||||
frame->cs = vector[1];
|
|
||||||
frame->eip = (uint32_t)vector[0];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0xcf: {
|
|
||||||
// Handle iret
|
|
||||||
frame->eip = *(sp++) + 2;
|
|
||||||
frame->cs = *(sp++);
|
|
||||||
frame->eflags &= 0xffff0000;
|
|
||||||
frame->eflags |= *(sp++);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0xfa:
|
|
||||||
asm("cli");
|
|
||||||
frame->eip++;
|
|
||||||
break;
|
|
||||||
case 0xfb:
|
|
||||||
asm("sti");
|
|
||||||
frame->eip++;
|
|
||||||
break;
|
|
||||||
default: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
frame->esp = (uint16_t)sp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_idt() {
|
void init_idt() {
|
||||||
@ -481,6 +340,7 @@ void init_idt() {
|
|||||||
for (int i=0; i<256; i++)
|
for (int i=0; i<256; i++)
|
||||||
gates[i] = &ignore_interrupt;
|
gates[i] = &ignore_interrupt;
|
||||||
|
|
||||||
|
gates[32] = &Timer::tick;
|
||||||
gates[0] = &handle_fault;
|
gates[0] = &handle_fault;
|
||||||
gates[5] = &handle_fault;
|
gates[5] = &handle_fault;
|
||||||
gates[6] = &handle_fault;
|
gates[6] = &handle_fault;
|
||||||
@ -500,9 +360,9 @@ void init_idt() {
|
|||||||
gates[29] = &handle_fault;
|
gates[29] = &handle_fault;
|
||||||
gates[30] = &handle_fault;
|
gates[30] = &handle_fault;
|
||||||
gates[31] = &handle_fault;
|
gates[31] = &handle_fault;
|
||||||
gates[128] = &syscall;
|
gates[127] = &syscall;
|
||||||
|
|
||||||
idt[128].privilege = 3;
|
idt[127].privilege = 3;
|
||||||
|
|
||||||
outb(0x20, 0x11);
|
outb(0x20, 0x11);
|
||||||
outb(0xA0, 0x11);
|
outb(0xA0, 0x11);
|
||||||
@ -521,10 +381,9 @@ void init_idt() {
|
|||||||
outb(0x40, _counter[0]);
|
outb(0x40, _counter[0]);
|
||||||
outb(0x40, _counter[1]);
|
outb(0x40, _counter[1]);
|
||||||
|
|
||||||
Timer::register_event(30, (void(*)(void*))&context_switch, 0);
|
Timer::register_event(30, &context_switch, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void enable_idt() {
|
void enable_idt() {
|
||||||
gates[32] = &Timer::tick;
|
|
||||||
asm ("sti");
|
asm ("sti");
|
||||||
}
|
}
|
@ -2,12 +2,13 @@
|
|||||||
#define IDT_H
|
#define IDT_H
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "screenstuff.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
#include "gdt.h"
|
#include "gdt.h"
|
||||||
#include "stdio/circularrwbuffer.h"
|
#include "stdio/circularrwbuffer.h"
|
||||||
|
|
||||||
struct __attribute__((packed)) v8086_frame_struct {
|
struct __attribute__((packed)) frame_struct {
|
||||||
uint32_t new_cr3;
|
uint32_t new_cr3;
|
||||||
uint32_t new_esp;
|
uint32_t new_esp;
|
||||||
|
|
||||||
@ -28,17 +29,9 @@ struct __attribute__((packed)) v8086_frame_struct {
|
|||||||
uint16_t cs;
|
uint16_t cs;
|
||||||
uint16_t _ignored0;
|
uint16_t _ignored0;
|
||||||
uint32_t eflags;
|
uint32_t eflags;
|
||||||
uint32_t esp;
|
|
||||||
uint16_t ss;
|
uint16_t ss;
|
||||||
uint16_t _ignored1;
|
uint16_t _ignored1;
|
||||||
uint16_t es;
|
uint32_t esp;
|
||||||
uint16_t _ignored2;
|
|
||||||
uint16_t ds;
|
|
||||||
uint16_t _ignored3;
|
|
||||||
uint16_t fs;
|
|
||||||
uint16_t _ignored4;
|
|
||||||
uint16_t gs;
|
|
||||||
uint16_t _ignored5;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void(*gates[256])(frame_struct*);
|
extern void(*gates[256])(frame_struct*);
|
||||||
@ -64,10 +57,4 @@ struct __attribute__((packed)) idt_desc {
|
|||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
void context_switch();
|
|
||||||
void handle_fault(frame_struct* frame);
|
|
||||||
void syscall();
|
|
||||||
void ignore_interrupt();
|
|
||||||
void v86_monitor(v8086_frame_struct* frame);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -19,21 +19,3 @@ extern "C" {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Port::Port(uint16_t a) {
|
|
||||||
this->addr = a;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t Port::readb() {
|
|
||||||
return inb(this->addr);
|
|
||||||
}
|
|
||||||
uint16_t Port::readw() {
|
|
||||||
return inw(this->addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Port::writeb(uint8_t d) {
|
|
||||||
outb(this->addr, d);
|
|
||||||
}
|
|
||||||
void Port::writew(uint16_t d) {
|
|
||||||
outw(this->addr, d);
|
|
||||||
}
|
|
@ -11,17 +11,4 @@ extern "C" {
|
|||||||
uint16_t inw(uint16_t portnumber);
|
uint16_t inw(uint16_t portnumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
class Port {
|
|
||||||
private:
|
|
||||||
uint16_t addr;
|
|
||||||
public:
|
|
||||||
Port(uint16_t a);
|
|
||||||
|
|
||||||
uint8_t readb();
|
|
||||||
uint16_t readw();
|
|
||||||
|
|
||||||
void writeb(uint8_t d);
|
|
||||||
void writew(uint16_t d);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -6,72 +6,64 @@ global catchall_return
|
|||||||
|
|
||||||
catchall: ; At this point the gate number has been pushed to the stack
|
catchall: ; At this point the gate number has been pushed to the stack
|
||||||
pushad
|
pushad
|
||||||
mov eax, cr3
|
|
||||||
|
push esp
|
||||||
|
sub esp, 4
|
||||||
push eax
|
push eax
|
||||||
push 0
|
mov eax, cr3
|
||||||
|
mov [esp+4], eax
|
||||||
|
pop eax
|
||||||
|
|
||||||
; Pushed 40 bytes
|
; Pushed 40 bytes
|
||||||
mov eax, [esp+40]
|
mov eax, [esp+40]
|
||||||
mov ebx, gates
|
mov ebx, gates
|
||||||
mov eax, [ebx+4*eax]
|
mov eax, [ebx+4*eax]
|
||||||
|
|
||||||
; Check if we came from Ring 3
|
|
||||||
movzx ecx, word [esp+56]
|
|
||||||
and ecx, 3
|
|
||||||
cmp ecx, 3
|
|
||||||
jne no_copy
|
|
||||||
|
|
||||||
mov ecx, 72
|
|
||||||
mov esi, esp
|
|
||||||
mov edi, [_ZN6Global13currentThreadE]
|
|
||||||
rep movsb
|
|
||||||
mov ecx, [_ZN6Global13currentThreadE]
|
|
||||||
push ecx
|
|
||||||
jmp call
|
|
||||||
no_copy:
|
|
||||||
push esp
|
push esp
|
||||||
jmp call
|
|
||||||
call:
|
|
||||||
; Increment the current thread's count
|
|
||||||
mov ecx, [_ZN6Global13currentThreadE]
|
|
||||||
mov edx, [ecx]
|
|
||||||
add edx, 1
|
|
||||||
mov [ecx], edx
|
|
||||||
|
|
||||||
call eax
|
call eax
|
||||||
|
|
||||||
catchall_return:
|
catchall_return:
|
||||||
add esp, 4
|
add esp, 4
|
||||||
|
|
||||||
push 0x20
|
push 0x20
|
||||||
push 0x20
|
push 0x20
|
||||||
call outb
|
call outb
|
||||||
add esp, 8
|
add esp, 8
|
||||||
|
|
||||||
; Decrement and check the current thread's count
|
push eax
|
||||||
|
mov eax, [esp+4]
|
||||||
mov ecx, [_ZN6Global13currentThreadE]
|
|
||||||
mov edx, [ecx]
|
|
||||||
sub edx, 1
|
|
||||||
mov [ecx], edx
|
|
||||||
cmp edx, 0
|
|
||||||
jne skip_copying
|
|
||||||
|
|
||||||
sub esp, 72
|
|
||||||
mov ecx, 72
|
|
||||||
mov esi, [_ZN6Global13currentThreadE]
|
|
||||||
mov edi, esp
|
|
||||||
rep movsb
|
|
||||||
|
|
||||||
skip_copying:
|
|
||||||
add esp, 4
|
|
||||||
pop eax
|
|
||||||
mov cr3, eax
|
mov cr3, eax
|
||||||
|
pop eax
|
||||||
|
add esp, 4
|
||||||
|
pop esp
|
||||||
|
|
||||||
popad
|
popad
|
||||||
add esp, 8
|
|
||||||
|
mov esp, ebp
|
||||||
pop ebp
|
pop ebp
|
||||||
iret
|
iret
|
||||||
|
|
||||||
extern gates ; (void(*)(frame_struct))*
|
extern gates ; (void(*)(frame_struct))*
|
||||||
extern outb
|
extern outb
|
||||||
extern _ZN6Global13currentThreadE
|
|
||||||
|
; struct frame_struct __attribute__((packed)) {
|
||||||
|
; popad
|
||||||
|
; uint32_t edi;
|
||||||
|
; uint32_t esi;
|
||||||
|
; uint32_t ebp;
|
||||||
|
; uint32_t esp;
|
||||||
|
; uint32_t ebx;
|
||||||
|
; uint32_t edx;
|
||||||
|
; uint32_t ecx;
|
||||||
|
; uint32_t eax;
|
||||||
|
;
|
||||||
|
; interrupt
|
||||||
|
; uint32_t eip;
|
||||||
|
; uint32_t cs;
|
||||||
|
; uint32_t eflags;
|
||||||
|
; uint32_t esp;
|
||||||
|
; uint32_t ss;
|
||||||
|
;
|
||||||
|
; if it's an error
|
||||||
|
; uint32_t err_code;
|
||||||
|
; }
|
||||||
|
|
||||||
|
@ -1,185 +1,60 @@
|
|||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
|
|
||||||
Kernel::Kernel(PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base, uint32_t stack)
|
Kernel::Kernel(PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base, uint32_t stack)
|
||||||
: Process(0x8a000, page_directory, phys, virt, virt_alloc_base)
|
: Process(0, 0x8a000, page_directory, phys, virt, virt_alloc_base)
|
||||||
{
|
{
|
||||||
|
this->currentPID = 1;
|
||||||
Global::allocator = this;
|
Global::allocator = this;
|
||||||
Global::kernel = this;
|
Global::kernel = this;
|
||||||
|
|
||||||
Global::currentProc = this;
|
Global::currentProc = 0;
|
||||||
|
|
||||||
this->stack = stack;
|
this->stack = stack;
|
||||||
|
|
||||||
this->lastFH = 8;
|
this->lastFH = 8;
|
||||||
|
|
||||||
|
//this->processes.append(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::init_kernel() {
|
void Kernel::init_kernel() {
|
||||||
this->pid_map = new xnoe::hashtable<uint32_t, Process*>();
|
this->pid_map = new xnoe::hashtable<uint32_t, Process*>();
|
||||||
this->tid_map = new xnoe::hashtable<uint32_t, Thread*>();
|
Global::FH = new xnoe::hashtable<void*, ReadWriter*>();
|
||||||
this->globalISRStack = (new uint8_t[0x8000]) + 0x8000;
|
this->globalISRStack = (new uint8_t[0x8000]) + 0x8000;
|
||||||
Global::currentThread = new Thread(this);
|
|
||||||
Global::currentThread->frame.count++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Process* Kernel::createProcess(ReadWriter* file, uint8_t** argv, uint8_t** envp) {
|
Process* Kernel::createProcess(uint32_t fh) {
|
||||||
// argv is currently stored on the stack of the calling process
|
Process* p = new Process(currentPID, this->PD, 0xc0000000, fh);
|
||||||
// We need to create a copy of it in the kernel stack for createProcess
|
this->pid_map->set(currentPID, p);
|
||||||
|
currentPID++;
|
||||||
|
|
||||||
// Determine the length of argv (null terminated)
|
this->processes.append(p);
|
||||||
uint32_t argc = 0;
|
|
||||||
for (int i=0; argv[i]; i++)
|
|
||||||
argc++;
|
|
||||||
|
|
||||||
// Determine the length of all stings under argv
|
|
||||||
|
|
||||||
uint32_t argv_strings_length = 0;
|
|
||||||
for (int i=0; i<argc; i++)
|
|
||||||
argv_strings_length += strlen(argv[i]);
|
|
||||||
|
|
||||||
// Allocate space for the strings + new argv
|
|
||||||
|
|
||||||
char argv_strings[argv_strings_length];
|
|
||||||
char* argv_new[argc];
|
|
||||||
|
|
||||||
// Copy the strings, fill argv_new
|
|
||||||
for (int i=0, string_index=0; argv[i]; string_index+=strlen(argv[i++])) {
|
|
||||||
memcpy(&argv_strings[string_index], argv[i], strlen(argv[i]));
|
|
||||||
argv_new[i] = &argv_strings[string_index];
|
|
||||||
}
|
|
||||||
|
|
||||||
// envp is currently stored on the stack of the calling process
|
|
||||||
// We need to create a copy of it in the kernel stack for createProcess
|
|
||||||
|
|
||||||
// Determine the length of envp (null terminated)
|
|
||||||
uint32_t envc = 0;
|
|
||||||
if (envp)
|
|
||||||
for (int i=0; envp[i]; i++)
|
|
||||||
envc++;
|
|
||||||
|
|
||||||
// Determine the length of all stings under envp
|
|
||||||
|
|
||||||
uint32_t envp_strings_length = 0;
|
|
||||||
for (int i=0; i<envc; i++)
|
|
||||||
envp_strings_length += strlen(envp[i]);
|
|
||||||
|
|
||||||
// Allocate space for the strings + new envp
|
|
||||||
|
|
||||||
char envp_strings[envp_strings_length];
|
|
||||||
char* envp_new[envc];
|
|
||||||
|
|
||||||
// Copy the strings, fill envp_new
|
|
||||||
if (envc) {
|
|
||||||
for (int i=0, string_index=0; envp[i]; string_index+=strlen(envp[i++])) {
|
|
||||||
memcpy(&envp_strings[string_index], envp[i], strlen(envp[i]));
|
|
||||||
envp_new[i] = &envp_strings[string_index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Process* p = new Process(this->PD, 0xc0000000, file, argc, argv_new, envc, envp_new);
|
|
||||||
this->pid_map->set(p->PID, p);
|
|
||||||
|
|
||||||
registerThread(p->threads.start->elem);
|
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
Process* Kernel::createProcess(ReadWriter* file, uint8_t** argv, ReadWriter* stdout) {
|
Process* Kernel::createProcess(uint32_t fh, ReadWriter* stdout) {
|
||||||
char* zero = 0;
|
Process* p = this->createProcess(fh);
|
||||||
Process* p = this->createProcess(file, argv, &zero);
|
|
||||||
p->stdout = stdout;
|
p->stdout = stdout;
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::registerProcess(Process* p) {
|
void Kernel::destroyProcess(Process* p) {
|
||||||
this->pid_map->set(p->PID, p);
|
if (Global::currentProc == p)
|
||||||
}
|
Global::currentProcValid = false;
|
||||||
|
this->processes.remove(p);
|
||||||
void Kernel::destroyProcess(Process* p, uint32_t exit_code) {
|
|
||||||
xnoe::linkedlistelem<Thread*>* currentThread = p->threads.start;
|
|
||||||
while (currentThread) {
|
|
||||||
destroyThread(currentThread->elem, exit_code);
|
|
||||||
currentThread = currentThread->next;
|
|
||||||
}
|
|
||||||
this->pid_map->remove(p->PID);
|
this->pid_map->remove(p->PID);
|
||||||
delete p;
|
delete p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::registerThread(Thread* t) {
|
int Kernel::mapFH(ReadWriter* fh) {
|
||||||
this->threads.append(t);
|
Global::FH->set(this->lastFH++, fh);
|
||||||
this->tid_map->set(t->TID, t);
|
return this->lastFH - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::destroyThread(Thread* t, uint32_t exit_code) {
|
void Kernel::unmapFH(uint32_t fh) {
|
||||||
this->tid_map->remove(t->TID);
|
Global::FH->remove((void*)fh);
|
||||||
t->parent->threads.remove(t);
|
|
||||||
this->threads.remove(t);
|
|
||||||
|
|
||||||
if (t->suspending) {
|
|
||||||
xnoe::maybe<Thread*> ts = this->tid_map->get(t->suspending);
|
|
||||||
if (ts.is_ok()) {
|
|
||||||
Thread* st = ts.get();
|
|
||||||
st->state = Running;
|
|
||||||
st->frame.eax = exit_code;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete t;
|
//void Kernel::loadPrimaryStack() {
|
||||||
}
|
// asm volatile("mov %0, %%esp"::"m"(this->stack - 64));
|
||||||
|
//}
|
||||||
void Kernel::v86(uint16_t ax, uint16_t bx, uint16_t cx, uint16_t es, uint16_t di, uint8_t intn) {
|
|
||||||
// Create the payload to perform an interrupt.
|
|
||||||
uint8_t payload[21] = {
|
|
||||||
0xb8, 0x00, 0x00, // mov ax, 0
|
|
||||||
0x8e, 0xc0, // mov es, ax
|
|
||||||
0xb8, 0x00, 0x00, // mov ax, 0
|
|
||||||
0xbb, 0x00, 0x00, // mov bx, 0
|
|
||||||
0xb9, 0x00, 0x00, // mov cx, 0
|
|
||||||
0xbf, 0x00, 0x00, // mov di, 0
|
|
||||||
0xcd, 0x00, // int 0
|
|
||||||
0xcd, 0x00 // int 0
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set the values in the payload.
|
|
||||||
uint16_t* ax1 = (uint16_t*)(payload+1);
|
|
||||||
uint16_t* ax2 = (uint16_t*)(payload+6);
|
|
||||||
uint16_t* bx1 = (uint16_t*)(payload+9);
|
|
||||||
uint16_t* cx1 = (uint16_t*)(payload+12);
|
|
||||||
uint16_t* di1 = (uint16_t*)(payload+15);
|
|
||||||
uint8_t* intn1 = (uint8_t*)(payload+18);
|
|
||||||
|
|
||||||
*ax1 = es;
|
|
||||||
*ax2 = ax;
|
|
||||||
*bx1 = bx;
|
|
||||||
*cx1 = cx;
|
|
||||||
*di1 = di;
|
|
||||||
*intn1 = intn;
|
|
||||||
|
|
||||||
// Construct a stack.
|
|
||||||
uint32_t* stack = 0x9000;
|
|
||||||
|
|
||||||
*(--stack) = 0; // GS
|
|
||||||
*(--stack) = 0; // FS
|
|
||||||
*(--stack) = 0; // DS
|
|
||||||
*(--stack) = 0; // ES
|
|
||||||
*(--stack) = 0; // SS
|
|
||||||
*(--stack) = 0x9000; // ESP
|
|
||||||
*(--stack) = 0x00020000; // EFLAGS
|
|
||||||
*(--stack) = 0; // CS
|
|
||||||
*(--stack) = 0x7c00; // EIP
|
|
||||||
|
|
||||||
// Copy 19 bytes from payload to 0x7c00
|
|
||||||
|
|
||||||
memcpy((uint8_t*)0x7c00, payload, 21);
|
|
||||||
|
|
||||||
asm("lea _after_iret, %eax");
|
|
||||||
asm("push %eax");
|
|
||||||
asm("pusha");
|
|
||||||
asm("mov %%esp, %0":"=m"(Global::resp)::);
|
|
||||||
|
|
||||||
asm("xor %eax, %eax; xor %ebx, %ebx; xor %ecx, %ecx; xor %edi, %edi");
|
|
||||||
|
|
||||||
asm("mov %0, %%esp"::"m"(stack):);
|
|
||||||
asm("iret");
|
|
||||||
|
|
||||||
asm("_after_iret:");
|
|
||||||
}
|
|
@ -5,38 +5,32 @@
|
|||||||
#include "datatypes/hashtable.h"
|
#include "datatypes/hashtable.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
#include "filesystem/fstree.h"
|
|
||||||
#include "gdt.h"
|
|
||||||
|
|
||||||
class Kernel : public Process {
|
class Kernel : public Process {
|
||||||
private:
|
private:
|
||||||
int lastFH;
|
int lastFH;
|
||||||
public:
|
public:
|
||||||
|
uint32_t currentPID;
|
||||||
uint32_t stack;
|
uint32_t stack;
|
||||||
uint32_t globalISRStack;
|
uint32_t globalISRStack;
|
||||||
Terminal* terminal;
|
Terminal* terminal;
|
||||||
|
|
||||||
xnoe::hashtable<uint32_t, Process*>* pid_map; // Map of PIDs -> Process*s
|
xnoe::hashtable<uint32_t, Process*>* pid_map; // Map of PIDs -> Process*s
|
||||||
xnoe::hashtable<uint32_t, Thread*>* tid_map; // Map of TIDs -> Thread*s
|
|
||||||
|
|
||||||
xnoe::linkedlist<Process*> processes;
|
xnoe::linkedlist<Process*> processes;
|
||||||
xnoe::linkedlist<Process*> KBListeners;
|
xnoe::linkedlist<Process*> KBListeners;
|
||||||
|
|
||||||
RootFSTree* rootfs;
|
|
||||||
|
|
||||||
Kernel(PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base, uint32_t stack);
|
Kernel(PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base, uint32_t stack);
|
||||||
|
|
||||||
void init_kernel();
|
void init_kernel();
|
||||||
|
|
||||||
Process* createProcess(ReadWriter* file, uint8_t** argv, uint8_t** envp);
|
Process* createProcess(uint32_t fh);
|
||||||
Process* createProcess(ReadWriter* file, uint8_t** argv, ReadWriter* stdout);
|
Process* createProcess(uint32_t fh, ReadWriter* stdout);
|
||||||
void registerProcess(Process* p);
|
void destroyProcess(Process* p);
|
||||||
void destroyProcess(Process* p, uint32_t exit_code=0);
|
|
||||||
|
|
||||||
void registerThread(Thread* t);
|
int mapFH(ReadWriter* fh);
|
||||||
void destroyThread(Thread* t, uint32_t exit_code=0);
|
void unmapFH(uint32_t fh);
|
||||||
|
//void loadPrimaryStack();
|
||||||
void v86(uint16_t ax, uint16_t bx, uint16_t cx, uint16_t es, uint16_t di, uint8_t intn);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
#include "screenstuff.h"
|
||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
|
|
||||||
void init_keyboard();
|
void init_keyboard();
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "screenstuff.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
#include "keyboard.h"
|
#include "keyboard.h"
|
||||||
#include "strings.h"
|
#include "strings.h"
|
||||||
#include "ata.h"
|
#include "atapio.h"
|
||||||
#include "gdt.h"
|
#include "gdt.h"
|
||||||
#include "paging.h"
|
#include "paging.h"
|
||||||
#include "allocate.h"
|
#include "allocate.h"
|
||||||
@ -13,36 +14,24 @@
|
|||||||
#include "datatypes/hashtable.h"
|
#include "datatypes/hashtable.h"
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
#include "filesystem/fstree.h"
|
|
||||||
#include "filesystem/fat16.h"
|
|
||||||
#include "filesystem/devfs.h"
|
|
||||||
#include "filesystem/sysfs.h"
|
|
||||||
|
|
||||||
struct KernelInformationStruct {
|
int main() {
|
||||||
PDE* pde;
|
|
||||||
uint32_t page_directory_phys_addr;
|
|
||||||
uint32_t page_directory_phys_offset;
|
|
||||||
uint32_t page_bitmap_phys;
|
|
||||||
uint32_t page_bitmap_virt;
|
|
||||||
uint32_t stack_ptr;
|
|
||||||
uint32_t vga_addr;
|
|
||||||
uint32_t remainingPages;
|
|
||||||
};
|
|
||||||
|
|
||||||
int main(KernelInformationStruct kstruct) {
|
|
||||||
init_gdt();
|
init_gdt();
|
||||||
|
init_term();
|
||||||
|
|
||||||
PageDirectory kernel_pd = PageDirectory(kstruct.pde, kstruct.page_directory_phys_addr, kstruct.page_directory_phys_offset);
|
PageDirectory kernel_pd = PageDirectory(0xc0100000, 0x120000, 0xbffe0000);
|
||||||
|
|
||||||
kernel_pd.select();
|
kernel_pd.select();
|
||||||
|
kernel_pd.unmap(0x8000);
|
||||||
|
|
||||||
PageMap phys_pm(kstruct.page_bitmap_phys, kstruct.remainingPages);
|
PageMap phys_pm(0xc0600000);
|
||||||
PageMap virt_pm(kstruct.page_bitmap_virt);
|
PageMap virt_pm(0xc0620000);
|
||||||
|
|
||||||
Kernel kernel = Kernel(&kernel_pd, &phys_pm, &virt_pm, 0xc0000000, kstruct.stack_ptr);
|
Kernel kernel = Kernel(&kernel_pd, &phys_pm, &virt_pm, 0xc0000000, 0xc1006000);
|
||||||
kernel.init_kernel();
|
kernel.init_kernel();
|
||||||
|
init_atapio();
|
||||||
|
|
||||||
VGAModeTerminal* term = new VGAModeTerminal(kstruct.vga_addr);
|
VGAModeTerminal* term = new VGAModeTerminal(0xc07a0000);
|
||||||
|
|
||||||
kernel.terminal = term;
|
kernel.terminal = term;
|
||||||
|
|
||||||
@ -51,31 +40,17 @@ int main(KernelInformationStruct kstruct) {
|
|||||||
term->activate();
|
term->activate();
|
||||||
term->clear_screen();
|
term->clear_screen();
|
||||||
|
|
||||||
/*kernel.v86(
|
|
||||||
0x4F00,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0x10
|
|
||||||
);*/
|
|
||||||
|
|
||||||
term->printf("Hello, World!\n\nWe are running XnoeOS Code in C++ now, Protected Mode has been achieved (as well as Virtual Memory / Paging!!!) and everything is working super nicely!\n\nHow wonderful!\n\nNow I just need to hope my print function works properly too~~\n");
|
term->printf("Hello, World!\n\nWe are running XnoeOS Code in C++ now, Protected Mode has been achieved (as well as Virtual Memory / Paging!!!) and everything is working super nicely!\n\nHow wonderful!\n\nNow I just need to hope my print function works properly too~~\n");
|
||||||
|
|
||||||
term->printf("KERNEL OK!\n");
|
term->printf("KERNEL OK!\n");
|
||||||
|
|
||||||
kernel.rootfs = new RootFSTree();
|
ReadWriter* worldbin = new FATFileReadWriter(0, "etc/world.bin");
|
||||||
kernel.rootfs->mount(createPathFromString("/dev"), new DevFS());
|
uint32_t fh = kernel.mapFH(worldbin);
|
||||||
kernel.rootfs->mount(createPathFromString("/sys"), new SysFS());
|
|
||||||
kernel.rootfs->mount(createPathFromString("/"), new FAT16FS(kernel.rootfs->open(createPathFromString("/dev/ata"))));
|
|
||||||
ReadWriter* init = kernel.rootfs->open(createPathFromString("/init.bin"));
|
|
||||||
|
|
||||||
char* zero = 0;
|
Process* p1 = kernel.createProcess(fh, term);
|
||||||
Process* p1 = kernel.createProcess(init, &zero, term);
|
|
||||||
|
|
||||||
Global::tss->esp0 = (new uint8_t[8192]) + 8192;
|
|
||||||
|
|
||||||
init_keyboard();
|
init_keyboard();
|
||||||
|
|
||||||
enable_idt();
|
enable_idt();
|
||||||
|
|
||||||
while (1) asm ("hlt");
|
while (1) asm ("hlt");
|
||||||
|
@ -5,14 +5,13 @@ void memset(uint8_t* address, uint32_t count, uint8_t value) {
|
|||||||
address[i] = value;
|
address[i] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void memcpy(uint8_t* dst, uint8_t* src, uint32_t count) {
|
void memcpy(uint8_t* src, uint8_t* dst, uint32_t count) {
|
||||||
for (int i = 0; i<count; i++)
|
for (int i = 0; i<count; i++)
|
||||||
dst[i] = src[i];
|
dst[i] = src[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
PageMap::PageMap(uint32_t map, uint32_t remainingPages) {
|
PageMap::PageMap(uint32_t map) {
|
||||||
this->pagemap = (uint8_t*)map;
|
this->pagemap = (uint8_t*)map;
|
||||||
this->initPages = this->remainingPages = remainingPages;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PageMap::PageMap() {
|
PageMap::PageMap() {
|
||||||
@ -39,8 +38,6 @@ void PageMap::unset_bit(uint32_t index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool PageMap::bit_set(uint32_t index) {
|
bool PageMap::bit_set(uint32_t index) {
|
||||||
if (!index)
|
|
||||||
return false;
|
|
||||||
uint32_t offset = index % 8;
|
uint32_t offset = index % 8;
|
||||||
uint32_t i = index / 8;
|
uint32_t i = index / 8;
|
||||||
|
|
||||||
@ -49,24 +46,20 @@ bool PageMap::bit_set(uint32_t index) {
|
|||||||
|
|
||||||
void PageMap::mark_unavailable(uint32_t address) {
|
void PageMap::mark_unavailable(uint32_t address) {
|
||||||
unset_bit(address >> 12);
|
unset_bit(address >> 12);
|
||||||
this->remainingPages--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageMap::mark_unavailable(uint32_t address, uint32_t count) {
|
void PageMap::mark_unavailable(uint32_t address, uint32_t count) {
|
||||||
for (int i=0; i<count; i++)
|
for (int i=0; i<count; i++)
|
||||||
unset_bit((address >> 12) + i);
|
unset_bit((address >> 12) + i);
|
||||||
this->remainingPages -= count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageMap::mark_available(uint32_t address) {
|
void PageMap::mark_available(uint32_t address) {
|
||||||
set_bit(address >> 12);
|
set_bit(address >> 12);
|
||||||
this->remainingPages++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageMap::mark_available(uint32_t address, uint32_t count) {
|
void PageMap::mark_available(uint32_t address, uint32_t count) {
|
||||||
for (int i=0; i<count; i++)
|
for (int i=0; i<count; i++)
|
||||||
set_bit((address >> 12) + i);
|
set_bit((address >> 12) + i);
|
||||||
this->remainingPages += count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PageMap::available(uint32_t address) {
|
bool PageMap::available(uint32_t address) {
|
||||||
@ -98,7 +91,6 @@ PageTable::PageTable(uint32_t phys, uint32_t virt) {
|
|||||||
virt_addr = virt;
|
virt_addr = virt;
|
||||||
|
|
||||||
page_table = (PTE*)virt;
|
page_table = (PTE*)virt;
|
||||||
valid = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PageTable::PageTable(){
|
PageTable::PageTable(){
|
||||||
@ -108,7 +100,6 @@ PageTable::PageTable(){
|
|||||||
phys_addr = (Global::allocator->virtual_to_physical(virt_addr)) >> 12;
|
phys_addr = (Global::allocator->virtual_to_physical(virt_addr)) >> 12;
|
||||||
|
|
||||||
page_table = (PTE*)virt_addr;
|
page_table = (PTE*)virt_addr;
|
||||||
valid = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PageTable::~PageTable() {
|
PageTable::~PageTable() {
|
||||||
@ -158,7 +149,7 @@ PageDirectory::PageDirectory(PDE* page_directory, uint32_t phys_addr, uint32_t o
|
|||||||
|
|
||||||
for (int i=0; i<1024; i++) {
|
for (int i=0; i<1024; i++) {
|
||||||
uint32_t table_phys_addr = page_directory[i].getPhysicalPTAddress();
|
uint32_t table_phys_addr = page_directory[i].getPhysicalPTAddress();
|
||||||
new (&page_tables[i]) PageTable(table_phys_addr >> 12, table_phys_addr + offset);
|
new (page_tables + i) PageTable(table_phys_addr >> 12, table_phys_addr + offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,7 +165,7 @@ PageDirectory::PageDirectory() {
|
|||||||
|
|
||||||
PageDirectory::~PageDirectory() {
|
PageDirectory::~PageDirectory() {
|
||||||
for (int i=0; i<1024; i++)
|
for (int i=0; i<1024; i++)
|
||||||
if (page_tables[i].valid)
|
if (page_tables[i].virt_addr)
|
||||||
page_tables[i].~PageTable();
|
page_tables[i].~PageTable();
|
||||||
delete page_directory;
|
delete page_directory;
|
||||||
}
|
}
|
||||||
@ -182,8 +173,8 @@ PageDirectory::~PageDirectory() {
|
|||||||
void PageDirectory::map(uint32_t phys, uint32_t virt, uint8_t privilege) {
|
void PageDirectory::map(uint32_t phys, uint32_t virt, uint8_t privilege) {
|
||||||
split_addr* split = (split_addr*)&virt;
|
split_addr* split = (split_addr*)&virt;
|
||||||
|
|
||||||
if (!page_tables[split->pd_index].valid)
|
if (!page_tables[split->pd_index].virt_addr)
|
||||||
new (&page_tables[split->pd_index]) PageTable();
|
new (page_tables + split->pd_index) PageTable();
|
||||||
|
|
||||||
page_directory[split->pd_index] = (PDE){
|
page_directory[split->pd_index] = (PDE){
|
||||||
.present = 1,
|
.present = 1,
|
||||||
|
@ -3,12 +3,13 @@
|
|||||||
|
|
||||||
#include "paging.h"
|
#include "paging.h"
|
||||||
#include "allocate.h"
|
#include "allocate.h"
|
||||||
|
#include "screenstuff.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
|
||||||
void memset(uint8_t* address, uint32_t count, uint8_t value);
|
void memset(uint8_t* address, uint32_t count, uint8_t value);
|
||||||
void memcpy(uint8_t* dst, uint8_t* src, uint32_t count);
|
void memcpy(uint8_t* src, uint8_t* dst, uint32_t count);
|
||||||
|
|
||||||
class PageMap {
|
class __attribute__((packed)) PageMap {
|
||||||
private:
|
private:
|
||||||
uint8_t* pagemap;
|
uint8_t* pagemap;
|
||||||
|
|
||||||
@ -18,10 +19,7 @@ private:
|
|||||||
bool bit_set(uint32_t index);
|
bool bit_set(uint32_t index);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
uint32_t remainingPages;
|
PageMap(uint32_t map);
|
||||||
uint32_t initPages;
|
|
||||||
|
|
||||||
PageMap(uint32_t map, uint32_t remainingPages=0x100000);
|
|
||||||
PageMap();
|
PageMap();
|
||||||
|
|
||||||
~PageMap();
|
~PageMap();
|
||||||
@ -43,8 +41,6 @@ struct PageTable {
|
|||||||
|
|
||||||
uint32_t phys_addr;
|
uint32_t phys_addr;
|
||||||
uint32_t virt_addr;
|
uint32_t virt_addr;
|
||||||
uint32_t valid = 0;
|
|
||||||
uint32_t reserved;
|
|
||||||
|
|
||||||
PageTable(uint32_t phys, uint32_t virt);
|
PageTable(uint32_t phys, uint32_t virt);
|
||||||
PageTable();
|
PageTable();
|
||||||
@ -82,12 +78,12 @@ public:
|
|||||||
|
|
||||||
class Allocator {
|
class Allocator {
|
||||||
protected:
|
protected:
|
||||||
uint32_t virt_alloc_base;
|
|
||||||
uint8_t privilege;
|
|
||||||
public:
|
|
||||||
static PageMap* phys;
|
static PageMap* phys;
|
||||||
PageMap* virt;
|
PageMap* virt;
|
||||||
|
|
||||||
|
uint32_t virt_alloc_base;
|
||||||
|
uint8_t privilege;
|
||||||
|
public:
|
||||||
PageDirectory* PD;
|
PageDirectory* PD;
|
||||||
|
|
||||||
Allocator(PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base);
|
Allocator(PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base);
|
||||||
@ -98,8 +94,6 @@ public:
|
|||||||
virtual void* allocate(uint32_t size);
|
virtual void* allocate(uint32_t size);
|
||||||
virtual void deallocate(uint32_t virt_addr);
|
virtual void deallocate(uint32_t virt_addr);
|
||||||
|
|
||||||
void* getMappingOf(uint32_t phys_addr, uint32_t length_pages);
|
|
||||||
|
|
||||||
uint32_t virtual_to_physical(uint32_t virt);
|
uint32_t virtual_to_physical(uint32_t virt);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#ifndef PAGING_H
|
#ifndef PAGING_H
|
||||||
#define PAGING_H
|
#define PAGING_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
struct __attribute__((packed)) split_addr {
|
struct __attribute__((packed)) split_addr {
|
||||||
|
@ -3,215 +3,91 @@
|
|||||||
extern void(*catchall_return)();
|
extern void(*catchall_return)();
|
||||||
|
|
||||||
AllocTracker::AllocTracker(void* base, uint32_t size, uint32_t count) : page_base(base), page_size(size), alloc_count(count) {}
|
AllocTracker::AllocTracker(void* base, uint32_t size, uint32_t count) : page_base(base), page_size(size), alloc_count(count) {}
|
||||||
AllocTracker::AllocTracker() {}
|
|
||||||
|
|
||||||
xnoe::maybe<xnoe::linkedlistelem<AllocTracker>*> Process::get_alloc_tracker(uint32_t address) {
|
xnoe::Maybe<xnoe::linkedlistelem<AllocTracker>*> Process::get_alloc_tracker(uint32_t address) {
|
||||||
xnoe::linkedlistelem<AllocTracker>* current = this->allocations.start;
|
xnoe::linkedlistelem<AllocTracker>* current = this->allocations.start;
|
||||||
while (current) {
|
while (current) {
|
||||||
if (current->elem.page_base <= address && (current->elem.page_base + 4096 * current->elem.page_size) > address) {
|
if (current->elem.page_base <= address && (current->elem.page_base + 4096 * current->elem.page_size) > address) {
|
||||||
return xnoe::maybe<xnoe::linkedlistelem<AllocTracker>*>(current);
|
return xnoe::Maybe<xnoe::linkedlistelem<AllocTracker>*>(current);
|
||||||
}
|
}
|
||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return xnoe::maybe<xnoe::linkedlistelem<AllocTracker>*>();
|
return xnoe::Maybe<xnoe::linkedlistelem<AllocTracker>*>();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Process::currentPID = 0;
|
Process::Process(uint32_t PID, void* stack, PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base)
|
||||||
|
|
||||||
Process::Process(void* stack, PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base)
|
|
||||||
: Allocator(page_directory, phys, virt, virt_alloc_base) {
|
: Allocator(page_directory, phys, virt, virt_alloc_base) {
|
||||||
this->PID = this->currentPID++;
|
this->PID = PID;
|
||||||
this->page_remaining = 0;
|
this->page_remaining = 0;
|
||||||
this->last_page_pointer = virt_alloc_base;
|
this->last_page_pointer = virt_alloc_base;
|
||||||
|
this->stack = stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
Process::Process()
|
Process::Process(uint32_t PID)
|
||||||
: Allocator(new PageDirectory, new PageMap, (uint32_t)0, 3) {
|
: Allocator(new PageDirectory, new PageMap, (uint32_t)0, 3) {
|
||||||
this->PID = 0;
|
this->PID = PID;
|
||||||
this->page_remaining = 0;
|
this->page_remaining = 0;
|
||||||
this->last_page_pointer = 0;
|
this->last_page_pointer = 0;
|
||||||
this->file_handlers = new xnoe::dynarray<ReadWriter*>(8);
|
this->stack = this->allocate(0x8000);
|
||||||
|
this->kernelStackPtr = (new uint8_t[0x1000]) + 0x1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
Process::Process(PageDirectory* inherit, uint32_t inheritBase, ReadWriter* filereader, uint32_t argc, char** argv, uint32_t envc, char** envp)
|
Process::Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase, uint32_t fh)
|
||||||
: Allocator(new PageDirectory, new PageMap, (uint32_t)0, 3) {
|
: Allocator(new PageDirectory, new PageMap, (uint32_t)0, 3) {
|
||||||
this->stdout = 0;
|
this->stdout = 0;
|
||||||
this->stdin = 0;
|
this->stdin = 0;
|
||||||
|
|
||||||
this->PID = this->currentPID++;
|
this->firstRun = true;
|
||||||
|
|
||||||
|
this->PID = PID;
|
||||||
this->page_remaining = 0;
|
this->page_remaining = 0;
|
||||||
this->last_page_pointer = 0;
|
this->last_page_pointer = 0;
|
||||||
|
|
||||||
this->file_handlers = new xnoe::dynarray<ReadWriter*>(8);
|
|
||||||
|
|
||||||
for (int index = inheritBase >> 22; index < 1024; index++)
|
for (int index = inheritBase >> 22; index < 1024; index++)
|
||||||
this->PD->page_directory[index] = inherit->page_directory[index];
|
this->PD->page_directory[index] = inherit->page_directory[index];
|
||||||
|
|
||||||
|
xnoe::Maybe<ReadWriter*> file = Global::FH->get(fh);
|
||||||
|
if (file.is_ok()) {
|
||||||
|
ReadWriter* filereader = file.get();
|
||||||
uint32_t filesize = filereader->size();
|
uint32_t filesize = filereader->size();
|
||||||
uint8_t* program_data = this->allocate(filesize + 12) + 12;
|
uint8_t* program_data = this->allocate(filesize + 12) + 12;
|
||||||
|
|
||||||
Thread* thread = new Thread(this);
|
this->stack = this->allocate(0x8000);
|
||||||
|
this->kernelStackPtr = (new uint8_t[0x1000]) + 0xffc;
|
||||||
|
this->kernelStackPtrDefault = this->kernelStackPtr;
|
||||||
|
|
||||||
uint32_t pCR3;
|
uint32_t pCR3;
|
||||||
asm ("mov %%cr3, %0" : "=a" (pCR3) :);
|
asm ("mov %%cr3, %0" : "=a" (pCR3) :);
|
||||||
this->PD->select();
|
this->PD->select();
|
||||||
|
|
||||||
uint32_t* stack = thread->stack + 0x8000;
|
// We also need to initialise ESP and the stack
|
||||||
uint8_t* argenvarea = this->allocate(0x2000) + 0x2000;
|
|
||||||
|
|
||||||
// Copy envp
|
|
||||||
// envp is null terminated
|
|
||||||
*(--stack) = 0;
|
|
||||||
for (int i=envc; i>0; i--) {
|
|
||||||
char* s = envp[i-1];
|
|
||||||
uint32_t c = strlen(s);
|
|
||||||
memcpy((uint8_t*)(argenvarea -= c), (uint8_t*)envp[i-1], c);
|
|
||||||
*(--stack) = argenvarea;
|
|
||||||
}
|
|
||||||
uint32_t envp_p = ((uint32_t)stack);
|
|
||||||
|
|
||||||
// Copy argv
|
|
||||||
for (int i=argc; i>0; i--) {
|
|
||||||
char* s = argv[i-1];
|
|
||||||
uint32_t c = strlen(s);
|
|
||||||
memcpy((uint8_t*)(argenvarea -= c), (uint8_t*)argv[i-1], c);
|
|
||||||
*(--stack) = argenvarea;
|
|
||||||
}
|
|
||||||
uint32_t argv_p = ((uint32_t)stack);
|
|
||||||
|
|
||||||
*(--stack) = envp_p;
|
|
||||||
*(--stack) = argv_p;
|
|
||||||
*(--stack) = argc;
|
|
||||||
|
|
||||||
filereader->seek(0);
|
|
||||||
filereader->read(filesize, program_data);
|
|
||||||
|
|
||||||
asm ("mov %0, %%cr3" : : "r" (pCR3));
|
|
||||||
|
|
||||||
thread->initKernelStack(program_data, stack);
|
|
||||||
|
|
||||||
this->threads.append(thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
Process::Process(Process* p)
|
|
||||||
: Allocator(new PageDirectory, new PageMap, (uint32_t)0, 3) {
|
|
||||||
// Clone a Process and produce an entirely new process.
|
|
||||||
|
|
||||||
this->file_handlers = new xnoe::dynarray<ReadWriter*>(p->file_handlers);
|
|
||||||
|
|
||||||
this->PID = this->currentPID++;
|
|
||||||
|
|
||||||
// Set up page directory.
|
|
||||||
for (int index = 0xc0000000 >> 22; index < 1024; index++)
|
|
||||||
this->PD->page_directory[index] = p->PD->page_directory[index];
|
|
||||||
|
|
||||||
// First, we need to switch in to p's memory space
|
|
||||||
uint32_t pCR3;
|
|
||||||
asm("mov %%cr3, %0":"=a"(pCR3)::);
|
|
||||||
p->PD->select();
|
|
||||||
|
|
||||||
// First, we need to copy all of p's allocations.
|
|
||||||
|
|
||||||
xnoe::linkedlist<xnoe::tuple<AllocTracker, void*>> allocations;
|
|
||||||
|
|
||||||
xnoe::linkedlistelem<AllocTracker>* current_old = p->allocations.start;
|
|
||||||
while (current_old) {
|
|
||||||
allocations.append(xnoe::tuple<AllocTracker, void*>(current_old->elem, new uint8_t[4096 * current_old->elem.page_size]));
|
|
||||||
void* location = xnoe::get<1>(allocations.end->elem);
|
|
||||||
memcpy((uint8_t*)location, (uint8_t*)current_old->elem.page_base, 4096 * current_old->elem.page_size);
|
|
||||||
current_old = current_old->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select our own CR3
|
|
||||||
this->PD->select();
|
|
||||||
|
|
||||||
// Go through every allocation from the old process, allocate it here, copy the data over, then free the buffer we created.
|
|
||||||
xnoe::linkedlistelem<xnoe::tuple<AllocTracker, void*>>* current_new = allocations.start;
|
|
||||||
while (current_new) {
|
|
||||||
AllocTracker at = xnoe::get<0>(current_new->elem);
|
|
||||||
uint8_t* buf = (uint8_t*)xnoe::get<1>(current_new->elem);
|
|
||||||
uint8_t* dbuf = (uint8_t*)this->allocate((at.page_size-1) * 4096, at.alloc_count);
|
|
||||||
memcpy(dbuf, buf + 0x14, at.page_size * 4096 - 0x14);
|
|
||||||
delete buf;
|
|
||||||
current_new = current_new->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore CR3
|
|
||||||
asm("mov %0, %%cr3"::"r"(pCR3):);
|
|
||||||
|
|
||||||
// Setting up threads, etc will be left to the caller.
|
|
||||||
this->stdin = p->stdin;
|
|
||||||
this->stdout = p->stdout;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t Thread::currentTID = 1;
|
|
||||||
|
|
||||||
Thread::Thread(Process* parent) {
|
|
||||||
this->TID = this->currentTID++;
|
|
||||||
this->parent = parent;
|
|
||||||
|
|
||||||
this->stack = this->parent->allocate(0x8000);
|
|
||||||
this->kspRaw = (new uint8_t[0x4000]);
|
|
||||||
this->kernelStackPtr = this->kspRaw + 0x4000;
|
|
||||||
this->kernelStackPtrDefault = this->kernelStackPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Thread::Thread(Thread* t, Process* parent) {
|
|
||||||
this->TID = this->currentTID++;
|
|
||||||
this->stack = t->stack;
|
|
||||||
|
|
||||||
uint8_t* s = new uint8_t[0x8000];
|
|
||||||
|
|
||||||
// Copy the kernel stack
|
|
||||||
this->kspRaw = (new uint8_t[0x4000]);
|
|
||||||
memcpy(this->kspRaw, t->kspRaw, 0x4000);
|
|
||||||
memcpy((uint8_t*)&this->frame, (uint8_t*)&t->frame, sizeof(frame_struct));
|
|
||||||
|
|
||||||
this->frame.new_cr3 = parent->PD->phys_addr;
|
|
||||||
|
|
||||||
this->kernelStackPtr = this->kspRaw + 0x4000;
|
|
||||||
this->kernelStackPtrDefault = this->kernelStackPtr;
|
|
||||||
|
|
||||||
this->frame.ebp = this->kernelStackPtr;
|
|
||||||
this->frame.oesp = this->kernelStackPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Thread::~Thread() {
|
|
||||||
//delete kernelStackPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Thread::initKernelStack(void* entryPoint, void* esp) {
|
|
||||||
uint32_t pCR3;
|
|
||||||
asm ("mov %%cr3, %0" : "=a" (pCR3) :);
|
|
||||||
this->parent->PD->select();
|
|
||||||
uint32_t* stack32 = ((uint32_t)this->kernelStackPtr);
|
uint32_t* stack32 = ((uint32_t)this->kernelStackPtr);
|
||||||
*(--stack32) = 0x23; // SS
|
*(--stack32) = 0x23; // SS
|
||||||
*(--stack32) = ((uint32_t)esp); // ESP
|
*(--stack32) = ((uint32_t)this->stack + 0x8000); // ESP
|
||||||
*(--stack32) = 0x200; // EFLAGS
|
*(--stack32) = 0x200; // EFLAGS
|
||||||
*(--stack32) = 27; // CS
|
*(--stack32) = 27; // CS
|
||||||
*(--stack32) = (uint32_t)entryPoint; // EIP
|
*(--stack32) = (uint32_t)program_data; // EIP
|
||||||
*(--stack32);
|
*(--stack32) = ((uint32_t)this->stack + 0x8000); // EBP
|
||||||
*(--stack32);
|
|
||||||
*(--stack32);
|
uint32_t rEBP = stack32;
|
||||||
|
|
||||||
*(--stack32) = 0; // EAX
|
*(--stack32) = 0; // EAX
|
||||||
*(--stack32) = 0; // ECX
|
*(--stack32) = 0; // ECX
|
||||||
*(--stack32) = 0; // EDX
|
*(--stack32) = 0; // EDX
|
||||||
*(--stack32) = 0; // EBX
|
*(--stack32) = 0; // EBX
|
||||||
*(--stack32) = 0; // ESP
|
*(--stack32) = 0; // ESP
|
||||||
*(--stack32) = 0; // EBP
|
*(--stack32) = rEBP; // EBP
|
||||||
*(--stack32) = 0; // ESI
|
*(--stack32) = 0; // ESI
|
||||||
*(--stack32) = 0; // EDI
|
*(--stack32) = 0; // EDI
|
||||||
|
|
||||||
*(--stack32) = 0; // CR3
|
|
||||||
*(--stack32) = 1;
|
|
||||||
|
|
||||||
memcpy((uint8_t*)&this->frame, (uint8_t*)stack32, 72);
|
|
||||||
|
|
||||||
this->kernelStackPtr = stack32;
|
this->kernelStackPtr = stack32;
|
||||||
|
|
||||||
|
filereader->read(filesize, program_data);
|
||||||
|
|
||||||
asm ("mov %0, %%cr3" : : "r" (pCR3));
|
asm ("mov %0, %%cr3" : : "r" (pCR3));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Process::~Process() {
|
Process::~Process() {
|
||||||
uint32_t pCR3;
|
uint32_t pCR3;
|
||||||
@ -222,60 +98,13 @@ Process::~Process() {
|
|||||||
xnoe::linkedlistelem<AllocTracker>* active = next;
|
xnoe::linkedlistelem<AllocTracker>* active = next;
|
||||||
next = next->next;
|
next = next->next;
|
||||||
|
|
||||||
this->deallocate(active->elem.page_base);
|
//printf("Deleted %x\n", active->elem.page_base);
|
||||||
|
|
||||||
|
this->deallocate(active->elem.page_base+1);
|
||||||
}
|
}
|
||||||
|
this->deallocate(stack);
|
||||||
asm ("mov %0, %%cr3" : : "r" (pCR3));
|
asm ("mov %0, %%cr3" : : "r" (pCR3));
|
||||||
|
delete kernelStackPtr;
|
||||||
for (int i=0; i<file_handlers->length();i++) {
|
|
||||||
xnoe::maybe<ReadWriter*> r;
|
|
||||||
if ((r=file_handlers->get(i)).is_ok())
|
|
||||||
if (r.get())
|
|
||||||
r.get()->close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*xnoe::linkedlistelem<Thread*>* currentThread = threads.start;
|
|
||||||
while (currentThread) {
|
|
||||||
delete currentThread->elem;
|
|
||||||
currentThread = currentThread->next;
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
|
|
||||||
void* Process::allocate(uint32_t size, uint32_t alloc_count) {
|
|
||||||
bool switched_PD = false;
|
|
||||||
uint32_t pCR3;
|
|
||||||
asm ("mov %%cr3, %0" : "=a" (pCR3) :);
|
|
||||||
if (Global::currentProc != this) {
|
|
||||||
switched_PD = true;
|
|
||||||
this->PD->select();
|
|
||||||
}
|
|
||||||
void* ptr;
|
|
||||||
|
|
||||||
// For cloning a process, always allocate new
|
|
||||||
|
|
||||||
uint32_t elem_size = sizeof(xnoe::linkedlistelem<AllocTracker>);
|
|
||||||
|
|
||||||
// Determine how many pages we'll allocate, and the remainder
|
|
||||||
uint32_t pages = size / 4096;
|
|
||||||
uint32_t remainder = 4096 - (size % 4096);
|
|
||||||
|
|
||||||
ptr = this->Allocator::allocate(size);
|
|
||||||
|
|
||||||
// Update local values
|
|
||||||
this->last_page_pointer = ptr + pages * 4096;
|
|
||||||
this->page_remaining = remainder;
|
|
||||||
|
|
||||||
// Create allocations entry
|
|
||||||
xnoe::linkedlistelem<AllocTracker>* elem = (xnoe::linkedlistelem<AllocTracker>*)ptr;
|
|
||||||
elem->next = 0;
|
|
||||||
elem->prev = 0;
|
|
||||||
elem->elem = AllocTracker(ptr, pages + 1, alloc_count);
|
|
||||||
this->allocations.append(elem);
|
|
||||||
|
|
||||||
ptr += elem_size;
|
|
||||||
|
|
||||||
asm ("mov %0, %%cr3" : : "r" (pCR3));
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void* Process::allocate(uint32_t size) {
|
void* Process::allocate(uint32_t size) {
|
||||||
@ -297,7 +126,7 @@ void* Process::allocate(uint32_t size) {
|
|||||||
uint32_t elem_size = sizeof(xnoe::linkedlistelem<AllocTracker>);
|
uint32_t elem_size = sizeof(xnoe::linkedlistelem<AllocTracker>);
|
||||||
size += elem_size;
|
size += elem_size;
|
||||||
|
|
||||||
// Determine how many pages we'll allocate, and the remainder
|
// Determine how many pages we'll allocate, and the remainder;
|
||||||
uint32_t pages = size / 4096;
|
uint32_t pages = size / 4096;
|
||||||
uint32_t remainder = 4096 - (size % 4096);
|
uint32_t remainder = 4096 - (size % 4096);
|
||||||
|
|
||||||
@ -323,7 +152,7 @@ void* Process::allocate(uint32_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Process::deallocate(uint32_t virt_addr) {
|
void Process::deallocate(uint32_t virt_addr) {
|
||||||
xnoe::maybe<xnoe::linkedlistelem<AllocTracker>*> alloc_tracker = this->get_alloc_tracker(virt_addr);
|
xnoe::Maybe<xnoe::linkedlistelem<AllocTracker>*> alloc_tracker = this->get_alloc_tracker(virt_addr);
|
||||||
if (alloc_tracker.is_ok()) {
|
if (alloc_tracker.is_ok()) {
|
||||||
AllocTracker* ac = &alloc_tracker.get()->elem;
|
AllocTracker* ac = &alloc_tracker.get()->elem;
|
||||||
ac->alloc_count--;
|
ac->alloc_count--;
|
||||||
@ -342,41 +171,10 @@ void Process::deallocate(uint32_t virt_addr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Process::count_allocations(uint32_t address) {
|
uint32_t Process::count_allocations(uint32_t address) {
|
||||||
xnoe::maybe<xnoe::linkedlistelem<AllocTracker>*> alloc_tracker = this->get_alloc_tracker(address);
|
xnoe::Maybe<xnoe::linkedlistelem<AllocTracker>*> alloc_tracker = this->get_alloc_tracker(address);
|
||||||
|
|
||||||
if (alloc_tracker.is_ok())
|
if (alloc_tracker.is_ok())
|
||||||
return alloc_tracker.get()->elem.alloc_count;
|
return alloc_tracker.get()->elem.alloc_count;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Process::mapFH(ReadWriter* rw) {
|
|
||||||
file_handlers->push(rw);
|
|
||||||
return file_handlers->length()-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Process::unmapFH(uint32_t file_handler) {
|
|
||||||
file_handlers->set(file_handler, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
xnoe::maybe<ReadWriter*> Process::getFH(uint32_t file_handler) {
|
|
||||||
if (file_handler == 1)
|
|
||||||
if (stdin)
|
|
||||||
return xnoe::maybe<ReadWriter*>(stdin);
|
|
||||||
else
|
|
||||||
return xnoe::maybe<ReadWriter*>();
|
|
||||||
if (file_handler == 0)
|
|
||||||
if (stdout)
|
|
||||||
return xnoe::maybe<ReadWriter*>(stdout);
|
|
||||||
else
|
|
||||||
return xnoe::maybe<ReadWriter*>();
|
|
||||||
|
|
||||||
xnoe::maybe<ReadWriter*> rw = file_handlers->get(file_handler);
|
|
||||||
if (!rw.is_ok())
|
|
||||||
return rw;
|
|
||||||
|
|
||||||
if (!rw.get())
|
|
||||||
return xnoe::maybe<ReadWriter*>();
|
|
||||||
|
|
||||||
return rw;
|
|
||||||
}
|
|
@ -6,70 +6,17 @@
|
|||||||
#include "datatypes/linkedlist.h"
|
#include "datatypes/linkedlist.h"
|
||||||
#include "datatypes/hashtable.h"
|
#include "datatypes/hashtable.h"
|
||||||
#include "datatypes/maybe.h"
|
#include "datatypes/maybe.h"
|
||||||
|
#include "screenstuff.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "processstate.h"
|
#include "atapio.h"
|
||||||
|
|
||||||
#include "stdio/readwriter.h"
|
#include "stdio/readwriter.h"
|
||||||
#include "datatypes/dynarray.h"
|
|
||||||
#include "filesystem/fstree.h"
|
|
||||||
#include "stdio/circularrwbuffer.h"
|
|
||||||
|
|
||||||
struct __attribute__((packed)) frame_struct {
|
|
||||||
uint32_t count;
|
|
||||||
uint32_t new_cr3;
|
|
||||||
|
|
||||||
uint32_t edi;
|
|
||||||
uint32_t esi;
|
|
||||||
uint32_t ebp;
|
|
||||||
uint32_t oesp;
|
|
||||||
uint32_t ebx;
|
|
||||||
uint32_t edx;
|
|
||||||
uint32_t ecx;
|
|
||||||
uint32_t eax;
|
|
||||||
|
|
||||||
uint32_t gate;
|
|
||||||
uint32_t __ignored2;
|
|
||||||
uint32_t errcode;
|
|
||||||
|
|
||||||
uint32_t eip;
|
|
||||||
uint16_t cs;
|
|
||||||
uint16_t _ignored0;
|
|
||||||
uint32_t eflags;
|
|
||||||
uint32_t esp;
|
|
||||||
uint16_t ss;
|
|
||||||
uint16_t _ignored1;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Process;
|
|
||||||
class Thread {
|
|
||||||
private:
|
|
||||||
static uint32_t currentTID;
|
|
||||||
public:
|
|
||||||
frame_struct frame;
|
|
||||||
uint32_t TID;
|
|
||||||
|
|
||||||
void* stack;
|
|
||||||
void* kspRaw;
|
|
||||||
void* kernelStackPtr;
|
|
||||||
void* kernelStackPtrDefault;
|
|
||||||
Process* parent;
|
|
||||||
ProcessState state;
|
|
||||||
bool firstRun;
|
|
||||||
|
|
||||||
uint32_t suspending=0;
|
|
||||||
|
|
||||||
Thread(Process* parent);
|
|
||||||
Thread(Thread* t, Process* parent);
|
|
||||||
~Thread();
|
|
||||||
|
|
||||||
void Thread::initKernelStack(void* entryPoint, void* esp);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AllocTracker {
|
struct AllocTracker {
|
||||||
void* page_base;
|
void* page_base;
|
||||||
uint32_t page_size;
|
uint32_t page_size;
|
||||||
uint32_t alloc_count;
|
uint32_t alloc_count;
|
||||||
|
|
||||||
AllocTracker();
|
|
||||||
AllocTracker(void* base, uint32_t size, uint32_t count);
|
AllocTracker(void* base, uint32_t size, uint32_t count);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -78,43 +25,35 @@ private:
|
|||||||
uint32_t last_page_pointer;
|
uint32_t last_page_pointer;
|
||||||
uint32_t page_remaining;
|
uint32_t page_remaining;
|
||||||
|
|
||||||
xnoe::maybe<xnoe::linkedlistelem<AllocTracker>*> get_alloc_tracker(uint32_t address);
|
void* stack;
|
||||||
|
|
||||||
Path currentWorkingDirectory;
|
|
||||||
|
|
||||||
static uint32_t currentPID;
|
|
||||||
|
|
||||||
public:
|
|
||||||
xnoe::dynarray<ReadWriter*>* file_handlers;
|
|
||||||
|
|
||||||
uint32_t PID;
|
|
||||||
uint32_t esp;
|
|
||||||
|
|
||||||
ReadWriter* stdout;
|
|
||||||
ReadWriter* stdin;
|
|
||||||
|
|
||||||
xnoe::linkedlist<Thread*> threads;
|
|
||||||
|
|
||||||
// List of pages this process has allocated
|
// List of pages this process has allocated
|
||||||
xnoe::linkedlist<AllocTracker> allocations;
|
xnoe::linkedlist<AllocTracker> allocations;
|
||||||
|
|
||||||
Process(void* stack, PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base);
|
xnoe::Maybe<xnoe::linkedlistelem<AllocTracker>*> get_alloc_tracker(uint32_t address);
|
||||||
Process();
|
|
||||||
Process(PageDirectory* inherit, uint32_t inheritBase, ReadWriter* filereader, uint32_t argc=0, char** argv=0, uint32_t envc=0, char** envp=0);
|
|
||||||
|
|
||||||
Process(Process* p);
|
public:
|
||||||
|
uint32_t PID;
|
||||||
|
uint32_t esp;
|
||||||
|
|
||||||
|
void* kernelStackPtr;
|
||||||
|
void* kernelStackPtrDefault;
|
||||||
|
|
||||||
|
ReadWriter* stdout;
|
||||||
|
ReadWriter* stdin;
|
||||||
|
|
||||||
|
bool firstRun;
|
||||||
|
|
||||||
|
Process(uint32_t PID, void* stack, PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base);
|
||||||
|
Process(uint32_t PID);
|
||||||
|
Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase, uint32_t fh);
|
||||||
|
|
||||||
~Process(); // Iterate through allocations and free those; delete stack
|
~Process(); // Iterate through allocations and free those; delete stack
|
||||||
|
|
||||||
void* allocate(uint32_t size, uint32_t alloc_count);
|
|
||||||
void* allocate(uint32_t size) override;
|
void* allocate(uint32_t size) override;
|
||||||
void deallocate(uint32_t virt_addr) override;
|
void deallocate(uint32_t virt_addr) override;
|
||||||
|
|
||||||
uint32_t count_allocations(uint32_t address);
|
uint32_t count_allocations(uint32_t address);
|
||||||
|
|
||||||
uint32_t mapFH(ReadWriter* rw);
|
|
||||||
void unmapFH(uint32_t file_handler);
|
|
||||||
xnoe::maybe<ReadWriter*> getFH(uint32_t file_handler);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -1,9 +0,0 @@
|
|||||||
#ifndef PROCESSSTATE_H
|
|
||||||
#define PROCESSSTATE_H
|
|
||||||
|
|
||||||
enum ProcessState {
|
|
||||||
Running=0,
|
|
||||||
Suspended=1
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
133
src/kernel/screenstuff.cpp
Normal file
133
src/kernel/screenstuff.cpp
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
#include "screenstuff.h"
|
||||||
|
|
||||||
|
uint16_t* VMEM_ADDR = (uint16_t*)0xc0501000;
|
||||||
|
const int TERM_WIDTH = 80;
|
||||||
|
const int TERM_HEIGHT = 25;
|
||||||
|
|
||||||
|
int cursor_x = 0;
|
||||||
|
int cursor_y = 0;
|
||||||
|
|
||||||
|
uint16_t get_curpos() {
|
||||||
|
uint16_t cursor_position = 0;
|
||||||
|
uint8_t* cursor_position_split = (uint8_t*)&cursor_position;
|
||||||
|
outb(0x3D4, 0x0F);
|
||||||
|
cursor_position_split[0] = inb(0x3D5);
|
||||||
|
outb(0x3D4, 0x0E);
|
||||||
|
cursor_position_split[1] = inb(0x3D5);
|
||||||
|
return cursor_position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_term() {
|
||||||
|
uint16_t cursor_position = get_curpos();
|
||||||
|
|
||||||
|
cursor_y = cursor_position / TERM_WIDTH;
|
||||||
|
cursor_x = cursor_position % TERM_WIDTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_screen() {
|
||||||
|
for (int i=0; i<TERM_WIDTH*TERM_HEIGHT; i++) {
|
||||||
|
VMEM_ADDR[i] = 0x0720;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_line(int line) {
|
||||||
|
for (int x=0; x<TERM_WIDTH; x++) {
|
||||||
|
VMEM_ADDR[TERM_WIDTH*line + x] = 0x0720;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_curpos_raw(int curpos) {
|
||||||
|
uint8_t* cursor_position_split = (uint8_t*)&curpos;
|
||||||
|
outb(0x3D4, 0x0F);
|
||||||
|
outb(0x3D5, cursor_position_split[0]);
|
||||||
|
outb(0x3D4, 0x0E);
|
||||||
|
outb(0x3D5, cursor_position_split[1]);
|
||||||
|
|
||||||
|
cursor_x = (*(uint16_t*)cursor_position_split) % TERM_WIDTH;
|
||||||
|
cursor_y = (*(uint16_t*)cursor_position_split) / TERM_WIDTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_curpos(int x, int y) {
|
||||||
|
set_curpos_raw(y * TERM_WIDTH + x);
|
||||||
|
|
||||||
|
cursor_x = x;
|
||||||
|
cursor_y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printf(const char* string, ...) {
|
||||||
|
va_list ptr;
|
||||||
|
va_start(ptr, string);
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
int count = 0;
|
||||||
|
char current;
|
||||||
|
while (current=string[index++]) {
|
||||||
|
count++;
|
||||||
|
if (current == '\n') {
|
||||||
|
cursor_x = 0;
|
||||||
|
cursor_y++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor_x == TERM_WIDTH) {
|
||||||
|
cursor_x = 0;
|
||||||
|
cursor_y++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor_y == TERM_HEIGHT) {
|
||||||
|
for (int i=1; i<TERM_HEIGHT; i++) {
|
||||||
|
for (int x=0; x<TERM_WIDTH; x++) {
|
||||||
|
int from = i * TERM_WIDTH + x;
|
||||||
|
int to = (i-1) * TERM_WIDTH + x;
|
||||||
|
VMEM_ADDR[to] = VMEM_ADDR[from];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clear_line(24);
|
||||||
|
cursor_y--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current == '%') {
|
||||||
|
int type = string[index++];
|
||||||
|
int offset;
|
||||||
|
switch (type) {
|
||||||
|
case 'd': {
|
||||||
|
char decimal_buffer[11];
|
||||||
|
offset = int_to_decimal(va_arg(ptr, int), decimal_buffer);
|
||||||
|
printf(decimal_buffer + offset);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'x': {
|
||||||
|
char hex_buffer[8];
|
||||||
|
offset = int_to_hex(va_arg(ptr, int), hex_buffer);
|
||||||
|
printf(hex_buffer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 's': {
|
||||||
|
printf(va_arg(ptr, const char*));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'c': {
|
||||||
|
int mem_pos = cursor_y * TERM_WIDTH + cursor_x++;
|
||||||
|
int promoted = va_arg(ptr, int);
|
||||||
|
char charred = promoted;
|
||||||
|
VMEM_ADDR[mem_pos] = charred + (0x07<<8);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current != '\n') {
|
||||||
|
int mem_pos = cursor_y * TERM_WIDTH + cursor_x++;
|
||||||
|
VMEM_ADDR[mem_pos] = current + (0x07<<8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set_curpos(cursor_x, cursor_y);
|
||||||
|
|
||||||
|
va_end(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void non_moving_put(char chr) {
|
||||||
|
int mem_pos = cursor_y * TERM_WIDTH + cursor_x;
|
||||||
|
VMEM_ADDR[mem_pos] = chr + (0x07<<8);
|
||||||
|
}
|
18
src/kernel/screenstuff.h
Normal file
18
src/kernel/screenstuff.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef SCREENSTUFF_H
|
||||||
|
#define SCREENSTUFF_H
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include "types.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "strings.h"
|
||||||
|
|
||||||
|
uint16_t get_curpos();
|
||||||
|
void init_term();
|
||||||
|
void clear_screen();
|
||||||
|
void clear_line(int line);
|
||||||
|
void set_curpos_raw(int curpos);
|
||||||
|
void set_curpos(int x, int y);
|
||||||
|
void printf(const char* string, ...);
|
||||||
|
void non_moving_put(char chr);
|
||||||
|
|
||||||
|
#endif
|
@ -1,8 +0,0 @@
|
|||||||
#include "spinlock.h"
|
|
||||||
|
|
||||||
void Spinlock::lock() {
|
|
||||||
asm volatile ("spin_lock: mov $1, %%eax; lock xchg %0, %%eax; test %%eax, %%eax; jnz spin_lock" :: "m"(locked) : "eax");
|
|
||||||
}
|
|
||||||
void Spinlock::unlock() {
|
|
||||||
asm volatile ("xor %%eax, %%eax; lock xchg %0, %%eax" :: "m"(locked) : "eax");
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
#ifndef SPINLOCK_H
|
|
||||||
#define SPINLOCK_H
|
|
||||||
|
|
||||||
#include "types.h"
|
|
||||||
|
|
||||||
class Spinlock {
|
|
||||||
private:
|
|
||||||
uint32_t locked = 0;
|
|
||||||
public:
|
|
||||||
void lock();
|
|
||||||
void unlock();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,16 +1,16 @@
|
|||||||
#include "circularrwbuffer.h"
|
#include "circularrwbuffer.h"
|
||||||
|
|
||||||
CircularRWBuffer::CircularRWBuffer() {
|
CircularRWBuffer::CircularRWBuffer(uint32_t reader, uint32_t writer)
|
||||||
|
: ReadWriter(0) {
|
||||||
|
this->giveReadPerm(reader);
|
||||||
|
this->giveWritePerm(writer);
|
||||||
|
|
||||||
this->bufferSize = 3072;
|
this->bufferSize = 3072;
|
||||||
this->buffer = new uint8_t[this->bufferSize];
|
this->buffer = new uint8_t[this->bufferSize];
|
||||||
this->readPtr = 0;
|
this->readPtr = 0;
|
||||||
this->writePtr = 0;
|
this->writePtr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
CircularRWBuffer::~CircularRWBuffer() {
|
|
||||||
delete this->buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t CircularRWBuffer::write(uint32_t count, uint8_t* buffer) {
|
uint32_t CircularRWBuffer::write(uint32_t count, uint8_t* buffer) {
|
||||||
int i=0;
|
int i=0;
|
||||||
while (i < count) {
|
while (i < count) {
|
||||||
|
@ -10,8 +10,7 @@ private:
|
|||||||
uint32_t writePtr;
|
uint32_t writePtr;
|
||||||
uint32_t bufferSize;
|
uint32_t bufferSize;
|
||||||
public:
|
public:
|
||||||
CircularRWBuffer();
|
CircularRWBuffer(uint32_t reader, uint32_t writer);
|
||||||
~CircularRWBuffer();
|
|
||||||
|
|
||||||
uint32_t read(uint32_t count, uint8_t* buffer) override;
|
uint32_t read(uint32_t count, uint8_t* buffer) override;
|
||||||
uint32_t write(uint32_t count, uint8_t* buffer) override;
|
uint32_t write(uint32_t count, uint8_t* buffer) override;
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
#include "oneshotreadwriter.h"
|
|
||||||
|
|
||||||
OneShotReadWriter::OneShotReadWriter(uint8_t* toRead) {
|
|
||||||
this->length = strlen(toRead);
|
|
||||||
|
|
||||||
this->buffer = new uint8_t[this->length];
|
|
||||||
|
|
||||||
memcpy(this->buffer, toRead, this->length);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t OneShotReadWriter::read(uint32_t count, uint8_t* buffer) {
|
|
||||||
uint32_t c=0;
|
|
||||||
while (index < length && c < count) {
|
|
||||||
buffer[c++] = this->buffer[index++];
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t OneShotReadWriter::size() {
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t OneShotReadWriter::seek(uint32_t position) {
|
|
||||||
index = clamp(0, length, position);
|
|
||||||
return index;
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
#ifndef ONESHOTREADWRITER_H
|
|
||||||
#define ONESHOTREADWRITER_H
|
|
||||||
|
|
||||||
#include "readwriter.h"
|
|
||||||
#include "../strings.h"
|
|
||||||
#include "../memory.h"
|
|
||||||
|
|
||||||
class OneShotReadWriter : public ReadWriter {
|
|
||||||
private:
|
|
||||||
uint8_t* buffer=0;
|
|
||||||
uint32_t length;
|
|
||||||
uint32_t index=0;
|
|
||||||
|
|
||||||
public:
|
|
||||||
OneShotReadWriter(uint8_t* toRead);
|
|
||||||
|
|
||||||
uint32_t read(uint32_t count, uint8_t* buffer) override;
|
|
||||||
uint32_t size() override;
|
|
||||||
uint32_t seek(uint32_t position) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,16 +1,37 @@
|
|||||||
#include "readwriter.h"
|
#include "readwriter.h"
|
||||||
|
|
||||||
uint32_t ReadWriter::read(uint32_t count, uint8_t* buffer){return;}
|
ReadWriter::ReadWriter(uint32_t owner) {
|
||||||
uint32_t ReadWriter::write(uint32_t count, uint8_t* buffer){return;}
|
this->owner = owner;
|
||||||
uint32_t ReadWriter::seek(uint32_t position){return;}
|
|
||||||
uint32_t ReadWriter::size(){return;}
|
|
||||||
|
|
||||||
void ReadWriter::open() {
|
|
||||||
this->opens++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReadWriter::close() {
|
void ReadWriter::giveReadPerm(uint32_t PID) {
|
||||||
this->opens--;
|
this->allowedRead.append(PID);
|
||||||
if (this->opens == 0)
|
}
|
||||||
delete this;
|
|
||||||
|
void ReadWriter::giveWritePerm(uint32_t PID) {
|
||||||
|
this->allowedWrite.append(PID);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ReadWriter::read(uint32_t count, uint8_t* buffer){}
|
||||||
|
uint32_t ReadWriter::write(uint32_t count, uint8_t* buffer){}
|
||||||
|
uint32_t ReadWriter::size(){}
|
||||||
|
|
||||||
|
bool ReadWriter::canRead(uint32_t PID) {
|
||||||
|
if (this->owner == PID)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (this->allowedRead.has(PID))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadWriter::canWrite(uint32_t PID) {
|
||||||
|
if (this->owner == PID)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (this->allowedWrite.has(PID))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
@ -6,17 +6,21 @@
|
|||||||
|
|
||||||
class ReadWriter {
|
class ReadWriter {
|
||||||
private:
|
private:
|
||||||
uint32_t opens=1;
|
uint32_t owner;
|
||||||
|
xnoe::linkedlist<uint32_t> allowedRead;
|
||||||
|
xnoe::linkedlist<uint32_t> allowedWrite;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
ReadWriter(uint32_t owner);
|
||||||
|
void giveReadPerm(uint32_t PID);
|
||||||
|
void giveWritePerm(uint32_t PID);
|
||||||
|
|
||||||
virtual uint32_t read(uint32_t count, uint8_t* buffer);
|
virtual uint32_t read(uint32_t count, uint8_t* buffer);
|
||||||
virtual uint32_t write(uint32_t count, uint8_t* buffer);
|
virtual uint32_t write(uint32_t count, uint8_t* buffer);
|
||||||
virtual uint32_t size();
|
virtual uint32_t size();
|
||||||
virtual uint32_t seek(uint32_t position);
|
|
||||||
uint32_t getOwner();
|
uint32_t getOwner();
|
||||||
|
bool canRead(uint32_t PID);
|
||||||
void open();
|
bool canWrite(uint32_t PID);
|
||||||
void close();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -1,11 +1,5 @@
|
|||||||
#include "strings.h"
|
#include "strings.h"
|
||||||
|
|
||||||
uint32_t strlen(char* s) {
|
|
||||||
uint32_t c = 0;
|
|
||||||
while (s[c++]);
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool strcmp(char* a, char* b, int max) {
|
bool strcmp(char* a, char* b, int max) {
|
||||||
int index = 0;
|
int index = 0;
|
||||||
while (index < max) {
|
while (index < max) {
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
#ifndef STRINGS_H
|
#ifndef STRINGS_H
|
||||||
#define STRINGS_H
|
#define STRINGS_H
|
||||||
|
|
||||||
#include "types.h"
|
#include <stdbool.h>
|
||||||
|
|
||||||
uint32_t strlen(char* s);
|
|
||||||
bool strcmp(char* a, char* b, int max);
|
bool strcmp(char* a, char* b, int max);
|
||||||
char* split_on_first(char delimeter, char* string);
|
char* split_on_first(char delimeter, char* string);
|
||||||
int string_split(char delimeter, char* string, char** pointer_array);
|
int string_split(char delimeter, char* string, char** pointer_array);
|
||||||
|
@ -1,18 +1,6 @@
|
|||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
|
|
||||||
int strToInt(char* str, uint32_t max) {
|
void Terminal::scroll_up() {
|
||||||
int r=0;
|
|
||||||
int i=0;
|
|
||||||
while (*str >= 0x30 && *str <= 0x39 && i < max) {
|
|
||||||
r *= 10;
|
|
||||||
r += *(str++) - 0x30;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Terminal::scroll_up(uint32_t count) {
|
|
||||||
for (int i=0; i<count; i++) {
|
|
||||||
// Scroll the entire buffer up.
|
// Scroll the entire buffer up.
|
||||||
for (int y = 0; y < (height * pages); y++) {
|
for (int y = 0; y < (height * pages); y++) {
|
||||||
uint16_t* cline = buffer + y * width;
|
uint16_t* cline = buffer + y * width;
|
||||||
@ -24,198 +12,27 @@ void Terminal::scroll_up(uint32_t count) {
|
|||||||
// Clear the last line
|
// Clear the last line
|
||||||
uint16_t* last_line = buffer + (height * pages - 1) * width;
|
uint16_t* last_line = buffer + (height * pages - 1) * width;
|
||||||
for (int x = 0; x < width; x++) {
|
for (int x = 0; x < width; x++) {
|
||||||
last_line[x] = 0x0720; //| (edata << 8);
|
last_line[x] = 0x0720;
|
||||||
}
|
}
|
||||||
this->cur_y--;
|
this->cur_y--;
|
||||||
}
|
|
||||||
|
|
||||||
this->update();
|
this->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Terminal::putchar(uint32_t ptr, uint8_t c, uint8_t edata) {
|
||||||
void Terminal::scroll_down(uint32_t count) {
|
|
||||||
for (int i=0; i<count; i++) {
|
|
||||||
// Scroll the entire buffer up.
|
|
||||||
for (int y = (height * pages)-2; y >= 0; y--) {
|
|
||||||
uint16_t* nline = buffer + y * width;
|
|
||||||
uint16_t* cline = buffer + (y+1) * width;
|
|
||||||
for (int x = 0; x < width; x++) {
|
|
||||||
cline[x] = nline[x];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Clear the last line
|
|
||||||
uint16_t* last_line = buffer + (height * (pages - 1)) * width;
|
|
||||||
for (int x = 0; x < width; x++) {
|
|
||||||
last_line[x] = 0x0720;// | (edata << 8);
|
|
||||||
}
|
|
||||||
this->cur_y--;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Terminal::putchar(uint8_t c) {
|
|
||||||
again:
|
|
||||||
switch (this->state) {
|
|
||||||
case None:
|
|
||||||
switch (c) {
|
|
||||||
case 0x1b:
|
|
||||||
this->state = EscapeCode;
|
|
||||||
break;
|
|
||||||
case '\n':
|
|
||||||
this->cur_x = 0;
|
|
||||||
this->cur_y++;
|
|
||||||
break;
|
|
||||||
case '\b':
|
|
||||||
if (this->cur_x == 0) {
|
|
||||||
if (this->cur_y > 0) {
|
|
||||||
this->cur_x = this->width-1;
|
|
||||||
this->cur_y--;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this->cur_x--;
|
|
||||||
}
|
|
||||||
last_page_pointer[this->cur_y*this->width+this->cur_x] = ' ' | (edata<<8);
|
|
||||||
if (active)
|
|
||||||
putchar_internal(this->cur_y*this->width+this->cur_x, ' ',this->edata);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (this->cur_x == this->width) {
|
|
||||||
this->cur_x = 0;
|
|
||||||
this->cur_y++;
|
|
||||||
}
|
|
||||||
// All modifications to the screen are done to the last page.
|
// All modifications to the screen are done to the last page.
|
||||||
last_page_pointer[this->cur_y*this->width+this->cur_x] = c | (edata<<8);
|
last_page_pointer[ptr] = c | (edata<<8);
|
||||||
|
|
||||||
if (active)
|
if (active)
|
||||||
putchar_internal(this->cur_y*this->width+this->cur_x, c, this->edata);
|
putchar_internal(ptr, c, edata);
|
||||||
this->cur_x++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EscapeCode:
|
|
||||||
switch (c) {
|
|
||||||
case '[':
|
|
||||||
this->state = CSI;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CSI:
|
|
||||||
this->state = ParameterBytes;
|
|
||||||
this->parameterIndex = 0;
|
|
||||||
this->intermediaryIndex = 0;
|
|
||||||
goto again;
|
|
||||||
break;
|
|
||||||
case ParameterBytes:
|
|
||||||
if (parameterIndex < 128 && c >= 0x30 && c <= 0x3F) {
|
|
||||||
parameterBytes[parameterIndex++] = c;
|
|
||||||
} else {
|
|
||||||
parameterIndex;
|
|
||||||
this->state = IntermediaryBytes;
|
|
||||||
goto again;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case IntermediaryBytes:
|
|
||||||
if (intermediaryIndex < 128 && c >= 0x20 && c <= 0x2F) {
|
|
||||||
intermediaryBytes[intermediaryIndex++] = c;
|
|
||||||
} else {
|
|
||||||
intermediaryIndex;
|
|
||||||
this->state = FinalByte;
|
|
||||||
goto again;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FinalByte:
|
|
||||||
switch (c) {
|
|
||||||
case 'A':
|
|
||||||
this->cur_y -= clamp(strToInt(parameterBytes, parameterIndex), 0, this->cur_y);
|
|
||||||
break;
|
|
||||||
case 'B':
|
|
||||||
this->cur_y += clamp(strToInt(parameterBytes, parameterIndex), 0, this->height - this->cur_y);
|
|
||||||
break;
|
|
||||||
case 'C':
|
|
||||||
this->cur_x += clamp(strToInt(parameterBytes, parameterIndex), 0, this->width - this->cur_x);
|
|
||||||
break;
|
|
||||||
case 'D':
|
|
||||||
this->cur_x -= clamp(strToInt(parameterBytes, parameterIndex), 0, this->cur_x);
|
|
||||||
break;
|
|
||||||
case 'E':
|
|
||||||
this->cur_y += clamp(strToInt(parameterBytes, parameterIndex), 0, this->height - this->cur_y);
|
|
||||||
this->cur_x = 0;
|
|
||||||
break;
|
|
||||||
case 'F':
|
|
||||||
this->cur_y -= clamp(strToInt(parameterBytes, parameterIndex), 0, this->cur_y);
|
|
||||||
this->cur_x = 0;
|
|
||||||
break;
|
|
||||||
case 'G':
|
|
||||||
this->cur_x = clamp(strToInt(parameterBytes, parameterIndex), 0, this->width);
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
case 'H': {
|
|
||||||
uint32_t semicolonIndex = 0;
|
|
||||||
while (parameterBytes[semicolonIndex++] != ';' && semicolonIndex <= parameterIndex);
|
|
||||||
this->cur_y = clamp(strToInt(parameterBytes, parameterIndex) - 1, 0, this->height) ;
|
|
||||||
this->cur_x = clamp(strToInt(parameterBytes+semicolonIndex, parameterIndex-semicolonIndex) - 1, 0, this->width);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'm':
|
|
||||||
this->state = SGR;
|
|
||||||
goto again;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
this->state = None;
|
|
||||||
break;
|
|
||||||
case SGR: {
|
|
||||||
uint32_t index = 0;
|
|
||||||
while (index <= parameterIndex) {
|
|
||||||
uint32_t n = strToInt(parameterBytes+index, parameterIndex-index);
|
|
||||||
switch (n) {
|
|
||||||
case 0:
|
|
||||||
this->edata = 0xf;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
if ((this->edata&0xf) <= 0x7)
|
|
||||||
this->edata += 8;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if ((this->edata&0xf) >= 0x7)
|
|
||||||
this->edata -= 8;
|
|
||||||
break;
|
|
||||||
case 30 ... 37:
|
|
||||||
this->edata &= 0xf0;
|
|
||||||
this->edata |= n-30;
|
|
||||||
break;
|
|
||||||
case 40 ... 47:
|
|
||||||
this->edata &= 0x0f;
|
|
||||||
this->edata |= (n-40)<<4;
|
|
||||||
break;
|
|
||||||
case 49:
|
|
||||||
this->edata &= 0x0f;
|
|
||||||
this->edata |= 0xf0;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
while (parameterBytes[index++] != ';' && index <= parameterIndex);
|
|
||||||
}
|
|
||||||
this->state = None;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (this->cur_y == this->height) {
|
|
||||||
this->cur_y--;
|
|
||||||
scroll_up();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terminal::update(){}
|
void Terminal::update(){}
|
||||||
void Terminal::update_cur(){}
|
void Terminal::update_cur(){}
|
||||||
void Terminal::putchar_internal(uint32_t ptr, uint8_t c, uint8_t edata) {}
|
void Terminal::putchar_internal(uint32_t ptr, uint8_t c, uint8_t edata) {}
|
||||||
|
|
||||||
Terminal::Terminal(uint32_t width, uint32_t height, uint32_t pages) {
|
Terminal::Terminal(uint32_t width, uint32_t height, uint32_t pages)
|
||||||
|
: ReadWriter(0) {
|
||||||
this->width = width;
|
this->width = width;
|
||||||
this->height = height;
|
this->height = height;
|
||||||
this->pages = pages;
|
this->pages = pages;
|
||||||
@ -229,19 +46,21 @@ Terminal::Terminal(uint32_t width, uint32_t height, uint32_t pages) {
|
|||||||
this->active = false;
|
this->active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terminal::resize(uint32_t width, uint32_t height, uint32_t pages) {
|
int strToInt(char* str) {
|
||||||
delete this->buffer;
|
int r=0;
|
||||||
this->width = width;
|
while (*str >= 0x30 && *str <= 0x39) {
|
||||||
this->height = height;
|
r *= 10;
|
||||||
this->pages = pages;
|
r += *(str++) - 0x30;
|
||||||
this->buffer = new uint16_t[width * height * pages];
|
}
|
||||||
this->last_page_pointer = buffer + (width * height * pages) - (width * height);
|
return r;
|
||||||
this->current_page_pointer = last_page_pointer;
|
}
|
||||||
|
|
||||||
this->cur_x = 0;
|
int clamp(int a, int b, int c) {
|
||||||
this->cur_y = 0;
|
if (a < b)
|
||||||
|
return b;
|
||||||
this->active = false;
|
if (a > c)
|
||||||
|
return c;
|
||||||
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terminal::printf(const char* string, ...) {
|
void Terminal::printf(const char* string, ...) {
|
||||||
@ -252,6 +71,73 @@ void Terminal::printf(const char* string, ...) {
|
|||||||
char current;
|
char current;
|
||||||
|
|
||||||
while (current=string[index++]) {
|
while (current=string[index++]) {
|
||||||
|
if (current == '\n') {
|
||||||
|
this->cur_x = 0;
|
||||||
|
this->cur_y++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current == 0x1b && string[index] == '[') {
|
||||||
|
index++;
|
||||||
|
char* parameterStart = (string+index);
|
||||||
|
while (string[index] >= 0x30 && string[index] <= 0x3F)
|
||||||
|
index++;
|
||||||
|
char* parameterEnd = (string+index);
|
||||||
|
|
||||||
|
char* intermediateStart = (string+index);
|
||||||
|
while (string[index] >= 0x20 && string[index] <= 0x2F)
|
||||||
|
index++;
|
||||||
|
|
||||||
|
char final = *(string+(index++));
|
||||||
|
|
||||||
|
switch (final) {
|
||||||
|
case 'A':
|
||||||
|
this->cur_y -= clamp(strToInt(parameterStart), 0, this->cur_y);
|
||||||
|
break;
|
||||||
|
case 'B':
|
||||||
|
this->cur_y += clamp(strToInt(parameterStart), 0, this->height - this->cur_y);
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
this->cur_x += clamp(strToInt(parameterStart), 0, this->width - this->cur_x);
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
this->cur_x -= clamp(strToInt(parameterStart), 0, this->cur_x);
|
||||||
|
break;
|
||||||
|
case 'H': {
|
||||||
|
char* s=parameterStart;
|
||||||
|
while (*s != ';' && s < parameterEnd)
|
||||||
|
s++;
|
||||||
|
s++;
|
||||||
|
this->cur_y = clamp(strToInt(parameterStart), 1, this->height) - 1;
|
||||||
|
this->cur_x = clamp(strToInt(s), 1, this->width) - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current == '\b') {
|
||||||
|
if (this->cur_x > 0) {
|
||||||
|
this->cur_x--;
|
||||||
|
} else if (this->cur_y > 0) {
|
||||||
|
this->cur_y--;
|
||||||
|
this->cur_x = this->width-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mem_pos = this->cur_y * this->width + this->cur_x;
|
||||||
|
|
||||||
|
this->putchar(mem_pos, ' ');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->cur_x == this->width) {
|
||||||
|
this->cur_x = 0;
|
||||||
|
this->cur_y++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->cur_y == this->height)
|
||||||
|
this->scroll_up();
|
||||||
|
|
||||||
if (current == '%') {
|
if (current == '%') {
|
||||||
int type = string[index++];
|
int type = string[index++];
|
||||||
int offset;
|
int offset;
|
||||||
@ -273,17 +159,22 @@ void Terminal::printf(const char* string, ...) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'c': {
|
case 'c': {
|
||||||
|
int mem_pos = this->cur_y * this->width + this->cur_x++;
|
||||||
int promoted = va_arg(ptr, int);
|
int promoted = va_arg(ptr, int);
|
||||||
char charred = promoted;
|
char charred = promoted;
|
||||||
|
|
||||||
this->putchar(charred);
|
this->putchar(mem_pos, charred);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->putchar(current);
|
if (current != '\n') {
|
||||||
|
int mem_pos = this->cur_y * this->width + this->cur_x++;
|
||||||
|
|
||||||
|
this->putchar(mem_pos, current);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->set_curpos(this->cur_x, this->cur_y);
|
this->set_curpos(this->cur_x, this->cur_y);
|
||||||
@ -292,14 +183,89 @@ void Terminal::printf(const char* string, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Terminal::write(uint32_t count, uint8_t* string) {
|
uint32_t Terminal::write(uint32_t count, uint8_t* string) {
|
||||||
for (int index=0; index < count; index++)
|
int index = 0;
|
||||||
this->putchar(string[index]);
|
char current;
|
||||||
|
|
||||||
this->set_curpos(this->cur_x, this->cur_y);
|
while (index < count) {
|
||||||
return count;
|
current=string[index++];
|
||||||
|
if (current == '\n') {
|
||||||
|
this->cur_x = 0;
|
||||||
|
this->cur_y++;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Terminal::read(uint32_t count, uint8_t* buffer) {return;}
|
if (current == 0x1b && string[index] == '[') {
|
||||||
|
index++;
|
||||||
|
char* parameterStart = (string+index);
|
||||||
|
while (string[index] >= 0x30 && string[index] <= 0x3F)
|
||||||
|
index++;
|
||||||
|
char* parameterEnd = (string+index);
|
||||||
|
|
||||||
|
char* intermediateStart = (string+index);
|
||||||
|
while (string[index] >= 0x20 && string[index] <= 0x2F)
|
||||||
|
index++;
|
||||||
|
|
||||||
|
char final = *(string+(index++));
|
||||||
|
|
||||||
|
switch (final) {
|
||||||
|
case 'A':
|
||||||
|
this->cur_y -= clamp(strToInt(parameterStart), 0, this->cur_y);
|
||||||
|
break;
|
||||||
|
case 'B':
|
||||||
|
this->cur_y += clamp(strToInt(parameterStart), 0, this->height - this->cur_y);
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
this->cur_x += clamp(strToInt(parameterStart), 0, this->width - this->cur_x);
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
this->cur_x -= clamp(strToInt(parameterStart), 0, this->cur_x);
|
||||||
|
break;
|
||||||
|
case 'H': {
|
||||||
|
char* s=parameterStart;
|
||||||
|
while (*s != ';' && s < parameterEnd)
|
||||||
|
s++;
|
||||||
|
s++;
|
||||||
|
this->cur_y = clamp(strToInt(parameterStart), 1, this->height) - 1;
|
||||||
|
this->cur_x = clamp(strToInt(s), 1, this->width) - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current == '\b') {
|
||||||
|
if (this->cur_x > 0) {
|
||||||
|
this->cur_x--;
|
||||||
|
} else if (this->cur_y > 0) {
|
||||||
|
this->cur_y--;
|
||||||
|
this->cur_x = this->width-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mem_pos = this->cur_y * this->width + this->cur_x;
|
||||||
|
|
||||||
|
this->putchar(mem_pos, ' ');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->cur_x == this->width) {
|
||||||
|
this->cur_x = 0;
|
||||||
|
this->cur_y++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->cur_y == this->height)
|
||||||
|
this->scroll_up();
|
||||||
|
|
||||||
|
if (current != '\n') {
|
||||||
|
int mem_pos = this->cur_y * this->width + this->cur_x++;
|
||||||
|
|
||||||
|
this->putchar(mem_pos, current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->set_curpos(this->cur_x, this->cur_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Terminal::read(uint32_t count, uint8_t* buffer) {}
|
||||||
|
|
||||||
void Terminal::clear_screen() {
|
void Terminal::clear_screen() {
|
||||||
for (int i=0; i < width * height * pages; i++) {
|
for (int i=0; i < width * height * pages; i++) {
|
||||||
@ -364,29 +330,10 @@ TextModeTerminal::TextModeTerminal(uint16_t* text_mode_pointer): Terminal(80, 25
|
|||||||
this->text_mode_pointer = text_mode_pointer;
|
this->text_mode_pointer = text_mode_pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t color_map[16] = {
|
|
||||||
0, // Black
|
|
||||||
0x00000080, // Blue
|
|
||||||
0x00008000, // Green
|
|
||||||
0x00008080, // Cyan
|
|
||||||
0x00800000, // Red
|
|
||||||
0x00800080, // Magenta
|
|
||||||
0x00008080, // Yellow
|
|
||||||
0x00808080, // White
|
|
||||||
0x00404040, // Black
|
|
||||||
0x000000ff, // Blue
|
|
||||||
0x0000ff00, // Green
|
|
||||||
0x0000ffff, // Cyan
|
|
||||||
0x000000ff, // Red
|
|
||||||
0x00ff00ff, // Magenta
|
|
||||||
0x00ffff00, // Yellow
|
|
||||||
0x00ffffff // White
|
|
||||||
};
|
|
||||||
|
|
||||||
void VGAModeTerminal::update() {
|
void VGAModeTerminal::update() {
|
||||||
for (int y = 0; y < height; y++) {
|
for (int y = 0; y < height; y++) {
|
||||||
for (int x = 0; x < width; x++) {
|
for (int x = 0; x < width; x++) {
|
||||||
putchar_internal(y * width + x, (uint8_t)(current_page_pointer[y * width + x]), (uint8_t)(current_page_pointer[y * width + x]>>8));
|
putchar_internal(y * width + x, (uint8_t)(current_page_pointer[y * width + x]), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -406,12 +353,15 @@ void VGAModeTerminal::putchar_internal(uint32_t ptr, uint8_t c, uint8_t edata) {
|
|||||||
return;
|
return;
|
||||||
uint8_t* char_data = font[c];
|
uint8_t* char_data = font[c];
|
||||||
|
|
||||||
for (int y=0; y<8; y++)
|
for (int y=0; y<8; y++) {
|
||||||
put_pixels_byte(sx, sy+y, edata, char_data[y]);
|
//for (int x=0; x<8; x++) {
|
||||||
|
put_pixels_byte(sx, sy+y, 15, char_data[y]);
|
||||||
|
//}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VGAModeTerminal::put_pixels_byte(uint32_t x, uint32_t y, uint8_t color, uint8_t pixel_byte) {
|
void VGAModeTerminal::put_pixels_byte(uint32_t x, uint32_t y, uint8_t color, uint8_t pixel_byte) {
|
||||||
uint32_t pixel = y * pixelWidth + x;
|
uint32_t pixel = y * 720 + x;
|
||||||
uint32_t pixelindex = pixel / 8;
|
uint32_t pixelindex = pixel / 8;
|
||||||
|
|
||||||
uint8_t trbyte = 0;
|
uint8_t trbyte = 0;
|
||||||
@ -421,18 +371,17 @@ void VGAModeTerminal::put_pixels_byte(uint32_t x, uint32_t y, uint8_t color, uin
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
this->planes[i][pixelindex] = 0;
|
|
||||||
if (color & (1<<i))
|
if (color & (1<<i))
|
||||||
this->planes[i][pixelindex] |= trbyte;
|
this->planes[i][pixelindex] = trbyte;
|
||||||
if ((color>>4) & (1<<i))
|
else
|
||||||
this->planes[i][pixelindex] |= ~trbyte;
|
this->planes[i][pixelindex] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VGAModeTerminal::put_pixel(uint32_t x, uint32_t y, uint8_t color) {
|
void VGAModeTerminal::put_pixel(uint32_t x, uint32_t y, uint8_t color) {
|
||||||
// For any pixel we need to write 1 bit to planes 0, 1, 2, and 3
|
// For any pixel we need to write 1 bit to planes 0, 1, 2, and 3
|
||||||
|
|
||||||
uint32_t pixel = y * pixelWidth + x;
|
uint32_t pixel = y * 720 + x;
|
||||||
uint32_t pixelindex = pixel / 8;
|
uint32_t pixelindex = pixel / 8;
|
||||||
uint32_t pixelbitindex = pixel % 8;
|
uint32_t pixelbitindex = pixel % 8;
|
||||||
|
|
||||||
@ -444,37 +393,40 @@ void VGAModeTerminal::put_pixel(uint32_t x, uint32_t y, uint8_t color) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VGAModeTerminal::bufferToVRAM() {
|
static void VGAModeTerminal::bufferToVRAM(frame_struct* frame, VGAModeTerminal* terminal) {
|
||||||
uint32_t count4 = (this->pixelWidth * this->pixelHeight) / 8 / 4;
|
uint32_t count4 = (720 * 480) / 8 / 4;
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
outb(0x3c4, 2);
|
outb(0x3c4, 2);
|
||||||
outb(0x3c5, 1<<i);
|
outb(0x3c5, 1<<i);
|
||||||
|
|
||||||
for (int c=0; c<count4; c++) {
|
for (int c=0; c<count4; c++) {
|
||||||
((uint32_t*)this->vga_pointer)[c] = ((uint32_t*)this->planes[i])[c];
|
((uint32_t*)terminal->vga_pointer)[c] = ((uint32_t*)terminal->planes[i])[c];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VGAModeTerminal::VGAModeTerminal(uint8_t* vga_pointer): Terminal(0, 0, 1) {
|
VGAModeTerminal::VGAModeTerminal(uint8_t* vga_pointer): Terminal(90, 60, 1) {
|
||||||
this->vga_pointer = vga_pointer;
|
this->vga_pointer = vga_pointer;
|
||||||
|
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
this->planes[i] = new uint8_t[720 * 480 / 8];
|
this->planes[i] = new uint8_t[720 * 480 / 8];
|
||||||
}
|
}
|
||||||
|
|
||||||
this->resize(pixelWidth / 8, pixelHeight / 8, 1);
|
|
||||||
|
|
||||||
unsigned char g_720x480x16[] =
|
unsigned char g_720x480x16[] =
|
||||||
{
|
{
|
||||||
|
/* MISC */
|
||||||
0xE7,
|
0xE7,
|
||||||
|
/* SEQ */
|
||||||
0x03, 0x01, 0x08, 0x00, 0x06,
|
0x03, 0x01, 0x08, 0x00, 0x06,
|
||||||
|
/* CRTC */
|
||||||
0x6B, 0x59, 0x5A, 0x82, 0x60, 0x8D, 0x0B, 0x3E,
|
0x6B, 0x59, 0x5A, 0x82, 0x60, 0x8D, 0x0B, 0x3E,
|
||||||
0x00, 0x40, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x40, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00,
|
||||||
0xEA, 0x0C, 0xDF, 0x2D, 0x08, 0xE8, 0x05, 0xE3,
|
0xEA, 0x0C, 0xDF, 0x2D, 0x08, 0xE8, 0x05, 0xE3,
|
||||||
0xFF,
|
0xFF,
|
||||||
|
/* GC */
|
||||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x0F,
|
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x0F,
|
||||||
0xFF,
|
0xFF,
|
||||||
|
/* AC */
|
||||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||||
0x01, 0x00, 0x0F, 0x00, 0x00,
|
0x01, 0x00, 0x0F, 0x00, 0x00,
|
||||||
@ -526,86 +478,5 @@ for (int i=0; i<4; i++) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer::register_event(16, (void(*)(void*))&VGAModeTerminal::bufferToVRAM, this);
|
Timer::register_event(16, &VGAModeTerminal::bufferToVRAM, this);
|
||||||
}
|
|
||||||
|
|
||||||
void BGAModeTerminal::update() {
|
|
||||||
for (int y = 0; y < height; y++) {
|
|
||||||
for (int x = 0; x < width; x++) {
|
|
||||||
putchar_internal(y * width + x, (uint8_t)(current_page_pointer[y * width + x]), (uint8_t)(current_page_pointer[y * width + x]>>8));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BGAModeTerminal::update_cur() {
|
|
||||||
// Todo: Implement cursor for VGAModeTerminal
|
|
||||||
}
|
|
||||||
|
|
||||||
void BGAModeTerminal::putchar_internal(uint32_t ptr, uint8_t c, uint8_t edata) {
|
|
||||||
uint32_t col = ptr % width;
|
|
||||||
uint32_t row = ptr / width;
|
|
||||||
|
|
||||||
uint32_t sx = col * 8;
|
|
||||||
uint32_t sy = row * 8;
|
|
||||||
|
|
||||||
if (c>127)
|
|
||||||
return;
|
|
||||||
uint8_t* char_data = font[c];
|
|
||||||
|
|
||||||
for (int y=0; y<8; y++)
|
|
||||||
put_pixels_byte(sx, sy+y, edata, char_data[y]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BGAModeTerminal::put_pixels_byte(uint32_t x, uint32_t y, uint8_t color, uint8_t pixel_byte) {
|
|
||||||
uint32_t pixel = y * pixelWidth + x;
|
|
||||||
|
|
||||||
for (int i=0; i<8; i++)
|
|
||||||
if (pixel_byte&(1<<i))
|
|
||||||
this->fb[pixel+i] = color_map[color&0xf];
|
|
||||||
else
|
|
||||||
this->fb[pixel+i] = color_map[(color>>4)&0xf];
|
|
||||||
}
|
|
||||||
|
|
||||||
void BGAModeTerminal::put_pixel(uint32_t x, uint32_t y, uint8_t color) {
|
|
||||||
// For any pixel we need to write 1 bit to planes 0, 1, 2, and 3
|
|
||||||
|
|
||||||
uint32_t pixel = y * pixelWidth + x;
|
|
||||||
uint32_t pixelindex = pixel / 8;
|
|
||||||
uint32_t pixelbitindex = pixel % 8;
|
|
||||||
|
|
||||||
this->fb[pixel] = color_map[color];
|
|
||||||
}
|
|
||||||
|
|
||||||
void BGAModeTerminal::bufferToVRAM() {
|
|
||||||
uint32_t c = this->pixelWidth * this->pixelHeight;
|
|
||||||
uint32_t bank=0;
|
|
||||||
uint32_t ctr=0;
|
|
||||||
for (int i=0; i<c; i++) {
|
|
||||||
if (i%16384 == 0) {
|
|
||||||
outw(0x1ce, 5);
|
|
||||||
outw(0x1cf, bank++);
|
|
||||||
}
|
|
||||||
((uint32_t*)this->vga_pointer)[i%16384] = ((uint32_t*)this->fb)[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BGAModeTerminal::BGAModeTerminal(uint8_t* vga_pointer): Terminal(0, 0, 1) {
|
|
||||||
this->vga_pointer = vga_pointer;
|
|
||||||
|
|
||||||
this->fb = new uint32_t[pixelWidth * pixelHeight];
|
|
||||||
|
|
||||||
this->resize(pixelWidth / 8, pixelHeight / 8, 1);
|
|
||||||
|
|
||||||
outw(0x1ce, 4);
|
|
||||||
outw(0x1cf, 0);
|
|
||||||
outw(0x1ce, 1);
|
|
||||||
outw(0x1cf, pixelWidth);
|
|
||||||
outw(0x1ce, 2);
|
|
||||||
outw(0x1cf, pixelHeight);
|
|
||||||
outw(0x1ce, 3);
|
|
||||||
outw(0x1cf, 32);
|
|
||||||
outw(0x1ce, 4);
|
|
||||||
outw(0x1cf, 1);
|
|
||||||
|
|
||||||
Timer::register_event(16, (void(*)(void*))&BGAModeTerminal::bufferToVRAM, this);
|
|
||||||
}
|
}
|
@ -14,38 +14,23 @@
|
|||||||
struct frame_struct;
|
struct frame_struct;
|
||||||
|
|
||||||
namespace Timer {
|
namespace Timer {
|
||||||
void register_event(uint32_t milliseconds, void(*function)(void*), void* auxiliary, bool oneshot=false);
|
void register_event(uint32_t milliseconds, void(*function)(frame_struct*, void*), void* auxiliary);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TerminalState {
|
|
||||||
None,
|
|
||||||
EscapeCode,
|
|
||||||
CSI,
|
|
||||||
ParameterBytes,
|
|
||||||
IntermediaryBytes,
|
|
||||||
FinalByte,
|
|
||||||
SGR
|
|
||||||
};
|
|
||||||
|
|
||||||
class Terminal: public ReadWriter {
|
class Terminal: public ReadWriter {
|
||||||
private:
|
private:
|
||||||
virtual void update();
|
virtual void update();
|
||||||
virtual void update_cur();
|
virtual void update_cur();
|
||||||
virtual void putchar_internal(uint32_t ptr, uint8_t c, uint8_t edata);
|
virtual void putchar_internal(uint32_t ptr, uint8_t c, uint8_t edata=0x07);
|
||||||
|
|
||||||
void scroll_up(uint32_t count=1);
|
void scroll_up();
|
||||||
void scroll_down(uint32_t count=1);
|
|
||||||
|
|
||||||
void putchar(uint8_t c);
|
void putchar(uint32_t ptr, uint8_t c, uint8_t edata=0x07);
|
||||||
|
|
||||||
TerminalState state = None;
|
|
||||||
uint8_t parameterBytes[128];
|
|
||||||
uint8_t intermediaryBytes[128];
|
|
||||||
uint32_t parameterIndex = 0;
|
|
||||||
uint32_t intermediaryIndex = 0;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint16_t* buffer;
|
uint16_t* buffer;
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
uint32_t pages;
|
uint32_t pages;
|
||||||
|
|
||||||
uint32_t cur_x;
|
uint32_t cur_x;
|
||||||
@ -55,14 +40,7 @@ protected:
|
|||||||
uint16_t* last_page_pointer;
|
uint16_t* last_page_pointer;
|
||||||
|
|
||||||
bool active;
|
bool active;
|
||||||
|
|
||||||
uint8_t edata=0x07;
|
|
||||||
void resize(uint32_t width, uint32_t height, uint32_t pages);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
uint32_t width;
|
|
||||||
uint32_t height;
|
|
||||||
|
|
||||||
Terminal(uint32_t width, uint32_t height, uint32_t pages);
|
Terminal(uint32_t width, uint32_t height, uint32_t pages);
|
||||||
|
|
||||||
void printf(const char* string, ...);
|
void printf(const char* string, ...);
|
||||||
@ -84,52 +62,29 @@ class TextModeTerminal : public Terminal {
|
|||||||
private:
|
private:
|
||||||
void update() override;
|
void update() override;
|
||||||
void update_cur() override;
|
void update_cur() override;
|
||||||
void putchar_internal(uint32_t ptr, uint8_t c, uint8_t edata) override;
|
void putchar_internal(uint32_t ptr, uint8_t c, uint8_t edata=0x07) override;
|
||||||
|
|
||||||
uint16_t* text_mode_pointer;
|
uint16_t* text_mode_pointer;
|
||||||
public:
|
public:
|
||||||
TextModeTerminal(uint16_t* text_mode_pointer);
|
TextModeTerminal(uint16_t* text_mode_pointer);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class VGAModeTerminal : public Terminal {
|
class VGAModeTerminal : public Terminal {
|
||||||
private:
|
private:
|
||||||
void update() override;
|
void update() override;
|
||||||
void update_cur() override;
|
void update_cur() override;
|
||||||
void putchar_internal(uint32_t ptr, uint8_t c,uint8_t edata) override;
|
void putchar_internal(uint32_t ptr, uint8_t c, uint8_t edata=0x07) override;
|
||||||
|
|
||||||
void put_pixel(uint32_t x, uint32_t y, uint8_t color);
|
void put_pixel(uint32_t x, uint32_t y, uint8_t color);
|
||||||
void put_pixels_byte(uint32_t x, uint32_t y, uint8_t color, uint8_t pixel_byte);
|
void put_pixels_byte(uint32_t x, uint32_t y, uint8_t color, uint8_t pixel_byte);
|
||||||
|
|
||||||
|
static void bufferToVRAM(frame_struct* frame, VGAModeTerminal* terminal);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void bufferToVRAM();
|
|
||||||
|
|
||||||
uint32_t pixelWidth = 720;
|
|
||||||
uint32_t pixelHeight = 480;
|
|
||||||
|
|
||||||
uint8_t* vga_pointer;
|
uint8_t* vga_pointer;
|
||||||
uint8_t* planes[4];
|
uint8_t* planes[4];
|
||||||
|
|
||||||
VGAModeTerminal(uint8_t* vga_pointer);
|
VGAModeTerminal(uint8_t* vga_pointer);
|
||||||
};
|
};
|
||||||
|
|
||||||
class BGAModeTerminal : public Terminal {
|
|
||||||
private:
|
|
||||||
void update() override;
|
|
||||||
void update_cur() override;
|
|
||||||
void putchar_internal(uint32_t ptr, uint8_t c,uint8_t edata) override;
|
|
||||||
|
|
||||||
void put_pixel(uint32_t x, uint32_t y, uint8_t color);
|
|
||||||
void put_pixels_byte(uint32_t x, uint32_t y, uint8_t color, uint8_t pixel_byte);
|
|
||||||
|
|
||||||
public:
|
|
||||||
void bufferToVRAM();
|
|
||||||
|
|
||||||
uint32_t pixelWidth = 720;
|
|
||||||
uint32_t pixelHeight = 480;
|
|
||||||
|
|
||||||
uint8_t* vga_pointer;
|
|
||||||
uint32_t* fb;
|
|
||||||
|
|
||||||
BGAModeTerminal(uint8_t* vga_pointer);
|
|
||||||
};
|
|
||||||
#endif
|
#endif
|
20
src/program/program.c
Normal file
20
src/program/program.c
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#include "../kernel/types.h"
|
||||||
|
#include "../common/common.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
print("Testing C code program\n");
|
||||||
|
print("My strings are messed up for some reason...\n");
|
||||||
|
|
||||||
|
uint32_t alpha_size = filesize("HELLO TXT");
|
||||||
|
char sizebuf[32];
|
||||||
|
uint32_t index = int_to_decimal(alpha_size, sizebuf);
|
||||||
|
print(sizebuf+index);
|
||||||
|
print("\n");
|
||||||
|
uint8_t* alpha_buffer = (uint8_t*)localalloc(alpha_size + 32);
|
||||||
|
print("alpha_buffer: ");
|
||||||
|
index = int_to_hex(alpha_buffer, sizebuf);
|
||||||
|
print(sizebuf+index);
|
||||||
|
print("\n");
|
||||||
|
readfile("HELLO TXT", alpha_buffer);
|
||||||
|
print(alpha_buffer);
|
||||||
|
}
|
14
src/program/program.ld
Normal file
14
src/program/program.ld
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
OUTPUT_FORMAT(binary)
|
||||||
|
OUTPUT_ARCH(i386:i386)
|
||||||
|
|
||||||
|
OUTPUT(build/program/program.bin)
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
. = 0x20;
|
||||||
|
|
||||||
|
.text : {
|
||||||
|
build/program_code_entry.o(.text)
|
||||||
|
build/program/program.o(.text)
|
||||||
|
build/common/common.o(.text)
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +0,0 @@
|
|||||||
#include "common/common.h"
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
|
||||||
for (int i=1; i<argc; i++) {
|
|
||||||
if (exists(argv[i])) {
|
|
||||||
uint32_t fh = fopen(argv[i]);
|
|
||||||
char buf[128];
|
|
||||||
uint32_t count;
|
|
||||||
while (count=read(128, fh, buf))
|
|
||||||
write(count, 0, buf);
|
|
||||||
fclose(fh);
|
|
||||||
} else {
|
|
||||||
printf("No such file or directory: %s", argv[i]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
#include "common/common.h"
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
|
||||||
for (int i=1; i<argc; i++) {
|
|
||||||
printf("%s%s", argv[i], (i==argc-1)?"\n":" ");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
[BITS 32]
|
|
||||||
|
|
||||||
_start:
|
|
||||||
call __setup
|
|
||||||
call main
|
|
||||||
push eax
|
|
||||||
call die
|
|
||||||
|
|
||||||
extern die
|
|
||||||
extern main
|
|
||||||
extern __setup
|
|
@ -1,10 +0,0 @@
|
|||||||
#include "common/common.h"
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
uint32_t pid = fork();
|
|
||||||
if (pid) {
|
|
||||||
printf("Parent PID: %d\nChild PID: %d\n", getPID(), pid);
|
|
||||||
} else {
|
|
||||||
printf("CHILD: Hello!\n");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
#include "common/common.h"
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
// The job of init will be to load the system configuration, mount devices, etc
|
|
||||||
|
|
||||||
bindToKeyboard();
|
|
||||||
|
|
||||||
char* fn = "/xosh.bin";
|
|
||||||
uint8_t* argv[] = {
|
|
||||||
fn,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
uint8_t* envp[] = {
|
|
||||||
"PATH=/",
|
|
||||||
0
|
|
||||||
};
|
|
||||||
uint32_t xosh_fh = fopen(fn);
|
|
||||||
uint32_t xosh = execve(xosh_fh, argv, envp);
|
|
||||||
|
|
||||||
while (1);
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
#include "common/common.h"
|
|
||||||
|
|
||||||
int main(uint32_t argc, char** argv, char** envp) {
|
|
||||||
printf("Environment: \n");
|
|
||||||
for (int i=0; envp[i]; i++)
|
|
||||||
printf("- %s\n", envp[i]);
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
#include "common/common.h"
|
|
||||||
|
|
||||||
char* filetype(FSType t) {
|
|
||||||
switch (t) {
|
|
||||||
case File:
|
|
||||||
return "File";
|
|
||||||
case Directory:
|
|
||||||
return "Directory";
|
|
||||||
case CharacterDev:
|
|
||||||
return "CharacterDev";
|
|
||||||
case BlockDev:
|
|
||||||
return "BlockDev";
|
|
||||||
case NoExist:
|
|
||||||
return "NoExist";
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
|
||||||
if (argc != 2) {
|
|
||||||
printf("Usage: %s <directory>", argv[0]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* directory = argv[1];
|
|
||||||
|
|
||||||
uint32_t dentsSize = getDentsSize(directory);
|
|
||||||
FSDirectoryListing* dents = (FSDirectoryListing*)malloc(dentsSize);
|
|
||||||
getDents(directory, (uint8_t*)dents);
|
|
||||||
|
|
||||||
for (int i=0; i<dents->count; i++) {
|
|
||||||
FSDirectoryEntry e = dents->entries[i];
|
|
||||||
printf("%.s %d %s\n", e.path.length, e.path.path, e.sizeBytes, filetype(e.type));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
OUTPUT_FORMAT(binary)
|
|
||||||
OUTPUT_ARCH(i386:i386)
|
|
||||||
|
|
||||||
SECTIONS {
|
|
||||||
. = 0x1020;
|
|
||||||
|
|
||||||
.text : {
|
|
||||||
build/programs/entry.o(.text)
|
|
||||||
build/common/common.o(.text)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,107 +0,0 @@
|
|||||||
#include "common/common.h"
|
|
||||||
|
|
||||||
void readline(char* buf, uint32_t lim) {
|
|
||||||
uint32_t idx = 0;
|
|
||||||
while (1) {
|
|
||||||
char c;
|
|
||||||
if (idx == lim) {
|
|
||||||
printf("\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (read(1, 1, &c)) {
|
|
||||||
if (c == '\n') {
|
|
||||||
write(1, 0, &c);
|
|
||||||
break;
|
|
||||||
} else if (c == '\b') {
|
|
||||||
if (idx > 0) {
|
|
||||||
buf[--idx] = 0;
|
|
||||||
write(1, 0, &c);
|
|
||||||
}
|
|
||||||
} else if (c == 0) {
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
buf[idx++] = c;
|
|
||||||
write(1, 0, &c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
Normal,
|
|
||||||
StringLiteral,
|
|
||||||
Escaped
|
|
||||||
} ParseState;
|
|
||||||
|
|
||||||
int main(int argc, char** argv, char** envp) {
|
|
||||||
// XOSH - The XnoeOS Shell
|
|
||||||
// XoSH is going to be a simple shell that can be used to execute programs.
|
|
||||||
|
|
||||||
printf("Welcome to %s!\n\n", argv[0]);
|
|
||||||
|
|
||||||
printf("Environment:\n");
|
|
||||||
for (int i=0; envp[i]; i++)
|
|
||||||
printf("- %s\n", envp[i]);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
printf("\x1b[0m# ");
|
|
||||||
char input[128];
|
|
||||||
memset(input, 0, 128);
|
|
||||||
readline(input, 128);
|
|
||||||
|
|
||||||
// Parse the input
|
|
||||||
char* result[32];
|
|
||||||
uint32_t ridx=0;
|
|
||||||
memset(result, 0, 32 * sizeof(char));
|
|
||||||
char c;
|
|
||||||
uint32_t idx=0;
|
|
||||||
char* lp = input;
|
|
||||||
ParseState s = Normal;
|
|
||||||
while (c=input[idx++]) {
|
|
||||||
switch (s) {
|
|
||||||
case Normal:
|
|
||||||
switch (c) {
|
|
||||||
case '"':
|
|
||||||
s = StringLiteral;
|
|
||||||
break;
|
|
||||||
case '\\':
|
|
||||||
s = Escaped;
|
|
||||||
break;
|
|
||||||
case ' ':
|
|
||||||
input[idx-1] = 0;
|
|
||||||
result[ridx++] = lp;
|
|
||||||
lp = (char*)(input+idx);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case StringLiteral:
|
|
||||||
if (c == '"') {
|
|
||||||
s = Normal;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Escaped:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result[ridx++] = lp;
|
|
||||||
|
|
||||||
if (ridx > 0) {
|
|
||||||
char* programName = result[0];
|
|
||||||
if (exists(programName)) {
|
|
||||||
char** argv = result;
|
|
||||||
uint32_t program = fopen(programName);
|
|
||||||
uint32_t e = execv(program, argv);
|
|
||||||
printf("\nExit code: %d\n\n", e);
|
|
||||||
} else if (strcmp(result[0], "set")) {
|
|
||||||
if (result[1] && result[2]) setenv(result[1], result[2]);
|
|
||||||
} else {
|
|
||||||
printf("No such executable file: `%s`\n\n", programName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
283
src/world/world.c
Normal file
283
src/world/world.c
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
#include "../common/common.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char* buffer;
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
uint32_t process;
|
||||||
|
uint32_t stdin;
|
||||||
|
uint32_t stdout;
|
||||||
|
} procbuffer;
|
||||||
|
|
||||||
|
void scrollBuffer(char* buf) {
|
||||||
|
for (int y=0; y<56; y++)
|
||||||
|
for (int x=0; x<43; x++)
|
||||||
|
if (y != 55)
|
||||||
|
buf[y*43+x] = buf[(y+1)*43+x];
|
||||||
|
else
|
||||||
|
buf[y*43+x] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToBuf(char c, procbuffer* buf) {
|
||||||
|
switch (c) {
|
||||||
|
case '\n':
|
||||||
|
buf->x = 0;
|
||||||
|
buf->y++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\b':
|
||||||
|
if (buf->x > 0)
|
||||||
|
buf->x--;
|
||||||
|
else if (buf->y > 0) {
|
||||||
|
buf->x = 42;
|
||||||
|
buf->y--;
|
||||||
|
}
|
||||||
|
buf->buffer[buf->y*43+buf->x] = ' ';
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
buf->buffer[buf->y*43+buf->x++] = c;
|
||||||
|
}
|
||||||
|
if (buf->x == 43) {
|
||||||
|
buf->x = 0;
|
||||||
|
buf->y++;
|
||||||
|
}
|
||||||
|
if (buf->y == 56) {
|
||||||
|
buf->y--;
|
||||||
|
scrollBuffer(buf->buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeCountToBuf(int count, char* c, procbuffer* buf) {
|
||||||
|
while (count--) {
|
||||||
|
writeToBuf(*(c++), buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearBuf(procbuffer* buf) {
|
||||||
|
for (int i=0; i<56*43;i++) {
|
||||||
|
buf->buffer[i] = ' ';
|
||||||
|
}
|
||||||
|
buf->x = 0;
|
||||||
|
buf->y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeStrToBuf(char* c, procbuffer* b) {
|
||||||
|
char* s = c;
|
||||||
|
while(*s)
|
||||||
|
writeToBuf(*(s++), b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayBuf(procbuffer* b, int dx, int dy) {
|
||||||
|
char pset[9] = "\x1b[00;00H";
|
||||||
|
for (int i=0; i<dy;i++) {
|
||||||
|
pset[3]++;
|
||||||
|
if (pset[3] == 0x3a) {
|
||||||
|
pset[3] = 0x30;
|
||||||
|
pset[2]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i=0; i<dx;i++) {
|
||||||
|
pset[6]++;
|
||||||
|
if (pset[6] == 0x3a) {
|
||||||
|
pset[6] = 0x30;
|
||||||
|
pset[5]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i=0; i<56; i++) {
|
||||||
|
print(pset);
|
||||||
|
write(43, 0, b->buffer+(43*i));
|
||||||
|
pset[3]++;
|
||||||
|
if (pset[3] == 0x3a) {
|
||||||
|
pset[3] = 0x30;
|
||||||
|
pset[2]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCurPos(int x, int y) {
|
||||||
|
char pset[9] = "\x1b[00;00H";
|
||||||
|
for (int i=0; i<y;i++) {
|
||||||
|
pset[3]++;
|
||||||
|
if (pset[3] == 0x3a) {
|
||||||
|
pset[3] = 0x30;
|
||||||
|
pset[2]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i=0; i<x;i++) {
|
||||||
|
pset[6]++;
|
||||||
|
if (pset[6] == 0x3a) {
|
||||||
|
pset[6] = 0x30;
|
||||||
|
pset[5]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print(pset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void readline(int count, char* buffer) {
|
||||||
|
int index = 0;
|
||||||
|
char c;
|
||||||
|
while (index < count) {
|
||||||
|
if (read(1, 1, &c)) {
|
||||||
|
if (c == '\n')
|
||||||
|
break;
|
||||||
|
if (c == '\b') {
|
||||||
|
if (index == 0)
|
||||||
|
continue;
|
||||||
|
else {
|
||||||
|
index--;
|
||||||
|
buffer[index] = 0;
|
||||||
|
write(1, 0, &c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[index++] = c;
|
||||||
|
write(1, 0, &c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool strcmp(char* a, char* b) {
|
||||||
|
int index=0;
|
||||||
|
while (a[index])
|
||||||
|
if (a[index] == b[index])
|
||||||
|
index++;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool strcmpcnt(int count, char* a, char* b) {
|
||||||
|
int index=0;
|
||||||
|
while (index < count)
|
||||||
|
if (a[index] == b[index])
|
||||||
|
index++;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
bindToKeyboard();
|
||||||
|
|
||||||
|
char space = ' ';
|
||||||
|
char plus = '+';
|
||||||
|
|
||||||
|
print("\x1b[1;1H");
|
||||||
|
for (int i=0; i < 1000; i++)
|
||||||
|
write(1, 0, &space);
|
||||||
|
print("\x1b[1;1H");
|
||||||
|
|
||||||
|
char* mid = "+ ++ +";
|
||||||
|
char* bottom = "+ +";
|
||||||
|
for (int i=0; i<90;i++)
|
||||||
|
write(1, 0, &plus);
|
||||||
|
for (int i=0; i<56;i++)
|
||||||
|
write(90, 0, mid);
|
||||||
|
for (int i=0; i<90;i++)
|
||||||
|
write(1, 0, &plus);
|
||||||
|
write(90, 0, bottom);
|
||||||
|
for (int i=0; i<90;i++)
|
||||||
|
write(1, 0, &plus);
|
||||||
|
|
||||||
|
uint32_t program = fopen("hello.bin");
|
||||||
|
uint32_t p1 = fork(program);
|
||||||
|
uint32_t p1out = bindStdout(p1);
|
||||||
|
uint32_t p1in = bindStdin(p1);
|
||||||
|
fclose(program);
|
||||||
|
program = fopen("hello.bin");
|
||||||
|
uint32_t p2 = fork(program);
|
||||||
|
uint32_t p2out = bindStdout(p2);
|
||||||
|
uint32_t p2in = bindStdin(p2);
|
||||||
|
fclose(program);
|
||||||
|
|
||||||
|
procbuffer b1 = {
|
||||||
|
.buffer = localalloc(56 * 43),
|
||||||
|
.x = 0,
|
||||||
|
.y = 0,
|
||||||
|
.process = p1,
|
||||||
|
.stdin = p1in,
|
||||||
|
.stdout = p1out
|
||||||
|
};
|
||||||
|
|
||||||
|
procbuffer b2 = {
|
||||||
|
.buffer = localalloc(56 * 43),
|
||||||
|
.x = 0,
|
||||||
|
.y = 0,
|
||||||
|
.process = p2,
|
||||||
|
.stdin = p2in,
|
||||||
|
.stdout = p2out
|
||||||
|
};
|
||||||
|
|
||||||
|
procbuffer* selectedBuf = &b1;
|
||||||
|
|
||||||
|
writeStrToBuf("XoSH (XOS SHell) v0.0.1\nPress : to use commands.\n :help for help.\n", &b1);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
char c[128];
|
||||||
|
int succ = 0;
|
||||||
|
if (b1.process)
|
||||||
|
if (succ = read(128, b1.stdout, c))
|
||||||
|
writeCountToBuf(succ, c, &b1);
|
||||||
|
if (b2.process)
|
||||||
|
if (succ = read(128, b2.stdout, c))
|
||||||
|
writeCountToBuf(succ, c, &b2);
|
||||||
|
if (read(1, 1, c)) {
|
||||||
|
if (c[0] == ':') {
|
||||||
|
char buf[32] = {0};
|
||||||
|
print("\x1b[59;2H");
|
||||||
|
print(": ");
|
||||||
|
print("\x1b[59;3H");
|
||||||
|
readline(32, buf);
|
||||||
|
if (strcmpcnt(6, buf, "switch")) {
|
||||||
|
if (selectedBuf == &b1) {
|
||||||
|
selectedBuf = &b2;
|
||||||
|
} else {
|
||||||
|
selectedBuf = &b1;
|
||||||
|
}
|
||||||
|
} else if (strcmpcnt(4, buf, "help")) {
|
||||||
|
writeStrToBuf("\n--------\n", selectedBuf);
|
||||||
|
writeStrToBuf(":help\n", selectedBuf);
|
||||||
|
writeStrToBuf(" Displays this message.\n", selectedBuf);
|
||||||
|
writeStrToBuf(":switch\n", selectedBuf);
|
||||||
|
writeStrToBuf(" Switches which process you're using\n", selectedBuf);
|
||||||
|
writeStrToBuf(":kill\n", selectedBuf);
|
||||||
|
writeStrToBuf(" Kills the current process\n", selectedBuf);
|
||||||
|
writeStrToBuf(":load <filename>\n", selectedBuf);
|
||||||
|
writeStrToBuf(" Loads and executes the program <filename>\n", selectedBuf);
|
||||||
|
writeStrToBuf("--------\n", selectedBuf);
|
||||||
|
} else if (strcmpcnt(4, buf, "kill")) {
|
||||||
|
if (selectedBuf->process) {
|
||||||
|
kill(selectedBuf->process);
|
||||||
|
clearBuf(selectedBuf);
|
||||||
|
selectedBuf->process = 0;
|
||||||
|
selectedBuf->stdin = 0;
|
||||||
|
selectedBuf->stdout = 0;
|
||||||
|
if (selectedBuf == &b1) {
|
||||||
|
selectedBuf = &b2;
|
||||||
|
} else {
|
||||||
|
selectedBuf = &b1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (strcmpcnt(4, buf, "load")) {
|
||||||
|
if (!selectedBuf->process) {
|
||||||
|
char* potFn = buf+5;
|
||||||
|
uint32_t fh = fopen(potFn);
|
||||||
|
selectedBuf->process = fork(fh);
|
||||||
|
selectedBuf->stdout = bindStdout(selectedBuf->process);
|
||||||
|
selectedBuf->stdin = bindStdin(selectedBuf->process);
|
||||||
|
fclose(fh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (selectedBuf->process)
|
||||||
|
write(1, selectedBuf->stdin, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
displayBuf(&b1, 2, 2);
|
||||||
|
displayBuf(&b2, 47, 2);
|
||||||
|
}
|
||||||
|
}
|
14
src/world/world.ld
Normal file
14
src/world/world.ld
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
OUTPUT_FORMAT(binary)
|
||||||
|
OUTPUT_ARCH(i386:i386)
|
||||||
|
|
||||||
|
OUTPUT(build/world/world.bin)
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
. = 0x20;
|
||||||
|
|
||||||
|
.text : {
|
||||||
|
build/program_code_entry.o(.text)
|
||||||
|
build/world/world.o(.text)
|
||||||
|
build/common/common.o(.text)
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user