Compare commits
15 Commits
core
...
b00f6d6217
Author | SHA1 | Date | |
---|---|---|---|
b00f6d6217 | |||
f3b1bfc5ef | |||
437c78d374 | |||
fdb77277a7 | |||
da5fc52afe | |||
6339b3e4bd | |||
dc2fe698a3 | |||
0fc40ad5e4 | |||
8f4382793c | |||
bb69d6b713 | |||
7e5f20ef66 | |||
c2f857fc88 | |||
edd6e82c2c | |||
a0d0454e32 | |||
ed34174d68 |
73
Makefile
73
Makefile
@ -1,67 +1,60 @@
|
||||
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 -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.
|
||||
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/
|
||||
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/
|
||||
LDFLAGS =
|
||||
|
||||
DISK_IMG_FILES = build/kernel/kernel.bin hello.txt alpha.txt \
|
||||
build/hello/hello.bin
|
||||
DISK_IMG_FILES = build/kernel/kernel.bin hello.txt alpha.txt
|
||||
|
||||
KERNEL_CPP_SRCS = $(wildcard src/kernel/*.cpp) $(wildcard src/kernel/*/*.cpp)
|
||||
KERNEL_ASM_SRCS = $(wildcard src/kernel/*.asm)
|
||||
KERNEL_CPP_SRCS = $(shell find src/kernel/ -name '*.cpp')
|
||||
KERNEL_ASM_SRCS = $(shell find src/kernel/ -name '*.asm')
|
||||
KERNEL_CPP_OBJS = $(patsubst src/%.cpp,build/%.o,$(KERNEL_CPP_SRCS))
|
||||
KERNEL_ASM_OBJS = $(patsubst src/%.asm,build/%.o,$(KERNEL_ASM_SRCS))
|
||||
|
||||
KERNEL_OBJS = build/kernel/isr.o $(KERNEL_CPP_OBJS) $(KERNEL_ASM_OBJS)
|
||||
|
||||
STAGE2_C_SRCS = $(wildcard src/boot_stage2/*.c)
|
||||
STAGE2_C_SRCS = $(wildcard src/bootstage2/*.c)
|
||||
STAGE2_C_OBJS = $(patsubst src/%.c,build/%.o,$(STAGE2_C_SRCS))
|
||||
|
||||
STAGE2_OBJS = build/c_code_entry.o $(STAGE2_C_OBJS)
|
||||
|
||||
PROGRAM_COMMON = build/program_code_entry.o build/common/common.o
|
||||
PROGRAM_COMMON = build/programs/entry.o build/common/common.o
|
||||
|
||||
PROGRAM_C_SRCS = $(wildcard src/program/*.c)
|
||||
PROGRAM_C_OBJS = $(patsubst src/%.c,build/%.o,$(PROGRAM_C_SRCS))
|
||||
PROGRAM_OBJS = $(PROGRAM_COMMON) $(PROGRAM_C_OBJS)
|
||||
SRC_DIRS = $(shell find src/ -type d)
|
||||
BUILD_DIRS = $(subst src/,build/,$(SRC_DIRS))
|
||||
|
||||
HELLO_C_SRCS = $(wildcard src/hello/*.c)
|
||||
HELLO_C_OBJS = $(patsubst src/%.c,build/%.o,$(HELLO_C_SRCS))
|
||||
HELLO_OBJS = $(PROGRAM_COMMON) $(HELLO_C_OBJS)
|
||||
PROGRAMS = $(shell find src/programs/* -type d)
|
||||
$(foreach program,$(PROGRAMS),\
|
||||
$(eval $(program)_C_SRCS := $(shell find $(program) -name '*.c')) \
|
||||
$(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)) \
|
||||
)
|
||||
|
||||
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
|
||||
.PHONY: run debug prepare clean cleanbuild
|
||||
|
||||
run: disk.img
|
||||
qemu-system-i386 disk.img
|
||||
|
||||
debug: disk.img
|
||||
cleanbuild: clean 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
|
||||
|
||||
disk.img: prepare build/boot/boot.bin build/boot_stage2/boot.bin $(DISK_IMG_FILES) build/world/world.bin
|
||||
disk.img: prepare build/boot/boot.bin build/bootstage2/boot.bin $(DISK_IMG_FILES)
|
||||
dd if=/dev/zero of=disk.img count=43 bs=100k
|
||||
dd if=build/boot/boot.bin of=disk.img conv=notrunc
|
||||
dd obs=512 seek=1 if=build/boot_stage2/boot.bin of=disk.img conv=notrunc
|
||||
dd obs=512 seek=1 if=build/bootstage2/boot.bin of=disk.img conv=notrunc
|
||||
mount disk.img img.d
|
||||
mkdir img.d/etc/
|
||||
cp $(DISK_IMG_FILES) img.d/
|
||||
cp build/world/world.bin img.d/etc/world.bin
|
||||
sleep 0.1
|
||||
umount img.d
|
||||
chmod 777 disk.img
|
||||
|
||||
prepare:
|
||||
mkdir -p img.d
|
||||
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
|
||||
mkdir -p $(BUILD_DIRS)
|
||||
mountpoint img.d | grep not || umount img.d
|
||||
|
||||
clean:
|
||||
@ -71,10 +64,10 @@ build/boot/boot.bin: src/boot/boot.asm
|
||||
nasm $< -o $@
|
||||
|
||||
# Boot Stage 2
|
||||
build/boot_stage2/boot.bin: src/boot_stage2/boot_stage2.ld $(STAGE2_OBJS)
|
||||
build/bootstage2/boot.bin: src/bootstage2/bootstage2.ld $(STAGE2_OBJS)
|
||||
ld $(LDFLAGS) -T $< $(STAGE2_OBJS)
|
||||
|
||||
build/boot_stage2/%.o: src/boot_stage2/%.c
|
||||
build/bootstage2/%.o: src/bootstage2/%.c
|
||||
gcc $(CFLAGS) -o $@ -c $<
|
||||
|
||||
# Kernel
|
||||
@ -101,12 +94,6 @@ src/kernel/isr.S: src/kernel/isr.S.base src/kernel/gen_isr_asm.sh
|
||||
|
||||
# Program
|
||||
|
||||
build/program/program.bin: src/program/program.ld $(PROGRAM_OBJS)
|
||||
echo $(PROGRAM_OBJS)
|
||||
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)
|
||||
.SECONDEXPANSION:
|
||||
build/programs/%.bin: src/programs/userspace.ld build/programs/entry.o $$(src/programs/$$(basename $$(notdir $$*))_OBJS) $(PROGRAM_COMMON)
|
||||
ld -o $@ -T $^
|
@ -50,7 +50,7 @@ bootcode:
|
||||
|
||||
mov ax, 2 ; Begin with the 2nd sector
|
||||
call prep_i13
|
||||
mov al, 31 ; Load the next 9 sectors (4.5k)
|
||||
mov al, 31 ; Load the next 31 sectors (15.5kb)
|
||||
int 13h
|
||||
|
||||
; We need to get the memory configuration from the BIOS now
|
||||
|
@ -1,165 +0,0 @@
|
||||
#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);
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
#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
|
@ -1,69 +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;
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
#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,14 +1,14 @@
|
||||
OUTPUT_FORMAT(binary)
|
||||
OUTPUT_ARCH(i386:i386)
|
||||
|
||||
OUTPUT(build/boot_stage2/boot.bin)
|
||||
OUTPUT(build/bootstage2/boot.bin)
|
||||
|
||||
SECTIONS {
|
||||
. = 0x7E00;
|
||||
|
||||
.text : {
|
||||
build/c_code_entry.o(.text)
|
||||
build/boot_stage2/main.o(.text)
|
||||
build/boot_stage2/*(.text)
|
||||
build/bootstage2/main.o(.text)
|
||||
build/bootstage2/*(.text)
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
#include "atapio.h"
|
||||
#include "screenstuff.h"
|
||||
#include "paging.h"
|
||||
|
||||
typedef struct {
|
||||
@ -47,23 +46,18 @@ void mark_unavailble(uint32_t address, uint32_t size, uint8_t* buffer) {
|
||||
}
|
||||
}
|
||||
|
||||
char* stringify_type(uint32_t type) {
|
||||
switch (type) {
|
||||
case 1:
|
||||
return "Usable";
|
||||
case 3:
|
||||
return "ACPI Reclaimable";
|
||||
case 4:
|
||||
return "ACPI NVS";
|
||||
case 5:
|
||||
return "Bad memory";
|
||||
default:
|
||||
return "Reserved";
|
||||
}
|
||||
}
|
||||
typedef struct {
|
||||
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;
|
||||
} KernelInformationStruct;
|
||||
|
||||
void main() {
|
||||
init_term();
|
||||
init_atapio();
|
||||
|
||||
// e820 memory map exists at 0x20000
|
||||
@ -72,14 +66,10 @@ void main() {
|
||||
// Zero out the bitmap.
|
||||
memset(bitmap, 0x20000, 0);
|
||||
// Ensure the bitmap data is clear
|
||||
|
||||
for (int i=0; i<0x20000; i++)
|
||||
if (bitmap[i])
|
||||
printf("Found data in bitmap at %x!\n", (bitmap+i));
|
||||
uint32_t pages;
|
||||
|
||||
for (int i=0; e820_entries[i].length_low != 0 || e820_entries[i].length_high != 0; 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)
|
||||
continue;
|
||||
@ -96,8 +86,7 @@ void main() {
|
||||
}
|
||||
}
|
||||
uint32_t page_index = base / 4096;
|
||||
|
||||
printf("Page Index: %d\nLength (Pages): %d\n", page_index, length / 4096);
|
||||
pages += length / 4096;
|
||||
|
||||
for (int j=0; length > 4096; length -= 4096, j++) {
|
||||
set_bit(page_index + j, bitmap);
|
||||
@ -105,6 +94,7 @@ void main() {
|
||||
}
|
||||
|
||||
mark_unavailble(bitmap, 0x20000, bitmap);
|
||||
mark_unavailble(0, 0xFFFFF, bitmap);
|
||||
|
||||
// Page Directory
|
||||
PDE* kernel_page_directory = bitmap + 0x20000;
|
||||
@ -146,9 +136,9 @@ void main() {
|
||||
// But first, we should load the kernel somewhere
|
||||
|
||||
uint8_t* kernel_location = 0x542000; // Just load it at 0x524000 for now
|
||||
mark_unavailble(kernel_location, 0x10000, bitmap); // Just treat the kernel as not growing beyond 32k for now.
|
||||
mark_unavailble(kernel_location, 0x20000, bitmap); // Just treat the kernel as not growing beyond 128k for now.
|
||||
|
||||
map_many_4k_phys_to_virt(kernel_location, 0xc0000000, kernel_page_directory, kernel_page_tables, 0x10); // Map 16 pages from 0x522000 to 0xc0000000;
|
||||
map_many_4k_phys_to_virt(kernel_location, 0xc0000000, kernel_page_directory, kernel_page_tables, 0x20); // Map 32 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_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
|
||||
@ -163,7 +153,7 @@ void main() {
|
||||
|
||||
memset(vm_bitmap, 0x20000, 0xff);
|
||||
mark_unavailble(0xc07a0000, 0x20000, vm_bitmap);
|
||||
mark_unavailble(0xc0000000, 0x10000, vm_bitmap);
|
||||
mark_unavailble(0xc0000000, 0x20000, vm_bitmap);
|
||||
mark_unavailble(0xc0100000, 0x1000, vm_bitmap);
|
||||
mark_unavailble(0xc0101000, 0x400000, vm_bitmap);
|
||||
mark_unavailble(0xc0501000, 0x1000, vm_bitmap);
|
||||
@ -183,17 +173,31 @@ void main() {
|
||||
map_many_4k_phys_to_virt(0x8a000, 0xc1000000, kernel_page_directory, kernel_page_tables, 16);
|
||||
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);
|
||||
|
||||
printf("Stage2 success!\n");
|
||||
|
||||
//while (1);
|
||||
|
||||
asm volatile("mov %0, %%eax;"
|
||||
"mov %%eax, %%cr3;"
|
||||
"mov %%cr0, %%eax;"
|
||||
"or $0x80000000, %%eax;"
|
||||
"mov %%eax, %%cr0" : : "m" (kernel_page_directory));
|
||||
|
||||
((void(*)(void))0xc0000000)();
|
||||
asm volatile ("mov %0, %%esp":: "r"(0xc1000000 + 16*0x1000));
|
||||
|
||||
KernelInformationStruct kstruct= (KernelInformationStruct){
|
||||
.pde = 0xc0100000,
|
||||
.page_directory_phys_addr = 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,6 +6,40 @@ typedef struct {
|
||||
uint32_t pd_index : 10;
|
||||
}__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) {
|
||||
split_addr* split = (split_addr*)&virtual;
|
||||
|
||||
@ -40,6 +74,11 @@ 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) {
|
||||
for (int i=0; i<count; i++)
|
||||
map_4k_phys_to_virt(physical + 4096*i, virtual + 4096*i, page_directory, page_tables);
|
11
src/bootstage2/strings.c
Normal file
11
src/bootstage2/strings.c
Normal file
@ -0,0 +1,11 @@
|
||||
#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;
|
||||
}
|
8
src/bootstage2/strings.h
Normal file
8
src/bootstage2/strings.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef STRINGS_H
|
||||
#define STRINGS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
bool strcmp(char* a, char* b, int max);
|
||||
|
||||
#endif
|
@ -1,5 +1,24 @@
|
||||
#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"
|
||||
|
||||
void print(char* string) {
|
||||
char* c = string;
|
||||
int i=0;
|
||||
@ -8,54 +27,6 @@ void print(char* 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) {
|
||||
for (int i=0; i<11; i++)
|
||||
string_buffer[i] = 0;
|
||||
@ -87,3 +58,48 @@ int int_to_hex(unsigned int number, char* string_buffer) {
|
||||
}
|
||||
return (index+1);
|
||||
}
|
||||
|
||||
void printf(const char* string, ...) {
|
||||
va_list ptr;
|
||||
va_start(ptr, string);
|
||||
|
||||
int index = 0;
|
||||
char current;
|
||||
|
||||
while (current=string[index++]) {
|
||||
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 promoted = va_arg(ptr, int);
|
||||
char charred = promoted;
|
||||
|
||||
write(1, 0, &charred);
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
write(1, 0, ¤t);
|
||||
}
|
||||
|
||||
va_end(ptr);
|
||||
}
|
@ -2,28 +2,47 @@
|
||||
#define COMMON_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"
|
||||
|
||||
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_hex(unsigned int number, char* string_buffer);
|
||||
void printf(const char* string, ...);
|
||||
|
||||
#endif
|
31
src/common/syscalls.h
Normal file
31
src/common/syscalls.h
Normal file
@ -0,0 +1,31 @@
|
||||
#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_1(uint32_t, exec, "7", uint32_t, filehandler);
|
||||
syscall_hdlr_0(uint32_t, getPID, "8");
|
||||
syscall_hdlr_0(void, die, "9");
|
||||
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);
|
@ -1,14 +0,0 @@
|
||||
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,12 +8,6 @@ uint32_t kernel_allocate_area = 0xf0000000;
|
||||
|
||||
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) {
|
||||
uint32_t index = offset / 8;
|
||||
uint32_t bit = offset % 8;
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
#include "paging.h"
|
||||
#include "datatypes/tuple.h"
|
||||
//void init_allocator();
|
||||
|
||||
extern uint8_t* bitmap;
|
||||
extern PDE* kernel_page_directory;
|
||||
|
169
src/kernel/ata.cpp
Normal file
169
src/kernel/ata.cpp
Normal file
@ -0,0 +1,169 @@
|
||||
#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 owner, uint32_t bus):
|
||||
ATA(bus),
|
||||
ReadWriter(owner) {
|
||||
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;
|
||||
}
|
110
src/kernel/ata.h
Normal file
110
src/kernel/ata.h
Normal file
@ -0,0 +1,110 @@
|
||||
#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 owner, 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
|
@ -1,255 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
#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
|
63
src/kernel/datatypes/dynarray.h
Normal file
63
src/kernel/datatypes/dynarray.h
Normal file
@ -0,0 +1,63 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
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,7 +5,6 @@
|
||||
#include "linkedlist.h"
|
||||
#include "../memory.h"
|
||||
#include "maybe.h"
|
||||
#include "../screenstuff.h"
|
||||
|
||||
namespace xnoe {
|
||||
template <class key, class value>
|
||||
@ -40,19 +39,19 @@ namespace xnoe {
|
||||
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::linkedlistelem<xnoe::tuple<key, value>>* current = list->start;
|
||||
if (current) {
|
||||
while (current) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return xnoe::Maybe<value>();
|
||||
return xnoe::maybe<value>();
|
||||
}
|
||||
|
||||
void remove(key k) {
|
||||
|
@ -1,7 +1,9 @@
|
||||
#ifndef LINKEDLIST_H
|
||||
#define LINKEDLIST_H
|
||||
|
||||
#include "../types.h"
|
||||
#include "../memory.h"
|
||||
#include "../spinlock.h"
|
||||
|
||||
namespace xnoe {
|
||||
template<typename T>
|
||||
@ -19,25 +21,38 @@ namespace xnoe {
|
||||
|
||||
template<typename T>
|
||||
struct linkedlist {
|
||||
xnoe::linkedlistelem<T>* start;
|
||||
xnoe::linkedlistelem<T>* end;
|
||||
xnoe::linkedlistelem<T>* start=0;
|
||||
xnoe::linkedlistelem<T>* end=0;
|
||||
Spinlock lock = Spinlock();
|
||||
uint32_t length = 0;
|
||||
|
||||
bool has(T t) {
|
||||
xnoe::linkedlistelem<T>* current = this->start;
|
||||
while (start) {
|
||||
if (start->elem == t)
|
||||
return true;
|
||||
//current = current->next;
|
||||
}
|
||||
|
||||
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) {
|
||||
xnoe::linkedlistelem<T>* llelem = new xnoe::linkedlistelem<T>(t);
|
||||
append(llelem);
|
||||
}
|
||||
|
||||
void append(xnoe::linkedlistelem<T>* llelem) {
|
||||
lock.lock();
|
||||
if (this->start && this->end) {
|
||||
this->end->next = llelem;
|
||||
llelem->prev = this->end;
|
||||
@ -47,6 +62,8 @@ namespace xnoe {
|
||||
this->start = llelem;
|
||||
this->end = llelem;
|
||||
}
|
||||
length++;
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
void prepend(T t) {
|
||||
@ -55,6 +72,7 @@ namespace xnoe {
|
||||
}
|
||||
|
||||
void prepend(xnoe::linkedlistelem<T>* llelem) {
|
||||
lock.lock();
|
||||
if (this->start && this->end) {
|
||||
this->start->prev = llelem;
|
||||
llelem->next = this->start;
|
||||
@ -64,14 +82,19 @@ namespace xnoe {
|
||||
this->start = llelem;
|
||||
this->end = llelem;
|
||||
}
|
||||
length++;
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
void insert(linkedlist<T>* ll, uint32_t index) {
|
||||
lock.lock();
|
||||
linkedlistelem<T>* current = this->start;
|
||||
for (int i=0; i<index; i++, current = current->next);
|
||||
|
||||
current->next->prev = ll->end;
|
||||
current->next = ll->start;
|
||||
length += ll.length;
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
/*void remove(uint32_t index) {
|
||||
@ -85,6 +108,7 @@ namespace xnoe {
|
||||
}*/
|
||||
|
||||
void remove(linkedlistelem<T>* elem) {
|
||||
lock.lock();
|
||||
linkedlistelem<T>* current = start;
|
||||
while (current) {
|
||||
if (current == elem) {
|
||||
@ -95,18 +119,22 @@ namespace xnoe {
|
||||
current->next->prev = current->prev;
|
||||
|
||||
if (current == start)
|
||||
start = 0;
|
||||
start = current->next;
|
||||
|
||||
if (current = end)
|
||||
end = 0;
|
||||
end = current->prev;
|
||||
|
||||
length--;
|
||||
lock.unlock();
|
||||
return;
|
||||
}
|
||||
current = current->next;
|
||||
}
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
void remove(T elem) {
|
||||
lock.lock();
|
||||
linkedlistelem<T>* current = start;
|
||||
while (current) {
|
||||
if (current->elem == elem) {
|
||||
@ -124,10 +152,13 @@ namespace xnoe {
|
||||
|
||||
delete current;
|
||||
|
||||
length--;
|
||||
lock.unlock();
|
||||
return;
|
||||
}
|
||||
current = current->next;
|
||||
}
|
||||
lock.unlock();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -3,17 +3,17 @@
|
||||
|
||||
namespace xnoe {
|
||||
template<typename T>
|
||||
class Maybe {
|
||||
class maybe {
|
||||
private:
|
||||
T t;
|
||||
bool ok;
|
||||
|
||||
public:
|
||||
Maybe() {
|
||||
maybe() {
|
||||
this->ok = false;
|
||||
}
|
||||
|
||||
Maybe(T t) {
|
||||
maybe(T t) {
|
||||
this->ok = true;
|
||||
this->t = t;
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
[BITS 32]
|
||||
|
||||
_start:
|
||||
mov esp, 0xc100a000
|
||||
jmp main
|
||||
|
||||
extern main
|
5
src/kernel/filesystem/devfs.cpp
Normal file
5
src/kernel/filesystem/devfs.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include "devfs.h"
|
||||
|
||||
DevFS::DevFS() {
|
||||
addEntry(createPathFromString("ata"), [](){return new ATAReadWriter(0,0);});
|
||||
}
|
14
src/kernel/filesystem/devfs.h
Normal file
14
src/kernel/filesystem/devfs.h
Normal file
@ -0,0 +1,14 @@
|
||||
#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
|
401
src/kernel/filesystem/fat16.cpp
Normal file
401
src/kernel/filesystem/fat16.cpp
Normal file
@ -0,0 +1,401 @@
|
||||
#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 owner, uint32_t firstCluster, uint32_t sizeBytes, FAT16FS* backingFS)
|
||||
: ReadWriter(owner) {
|
||||
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) {}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
bool 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[11] = {' '};
|
||||
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[11] = {' '};
|
||||
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(0, ((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;
|
||||
}
|
119
src/kernel/filesystem/fat16.h
Normal file
119
src/kernel/filesystem/fat16.h
Normal file
@ -0,0 +1,119 @@
|
||||
#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 owner, 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;
|
||||
|
||||
bool 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
|
270
src/kernel/filesystem/fstree.cpp
Normal file
270
src/kernel/filesystem/fstree.cpp
Normal file
@ -0,0 +1,270 @@
|
||||
#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){}
|
||||
FSType FSTree::type(Path p){}
|
||||
ReadWriter* FSTree::open(Path p){}
|
||||
uint32_t FSTree::getDentsSize(Path p){}
|
||||
void FSTree::getDents(Path p, FSDirectoryListing* buffer){}
|
||||
|
||||
// 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;
|
||||
}
|
87
src/kernel/filesystem/fstree.h
Normal file
87
src/kernel/filesystem/fstree.h
Normal file
@ -0,0 +1,87 @@
|
||||
#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
|
28
src/kernel/filesystem/sysfs.cpp
Normal file
28
src/kernel/filesystem/sysfs.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#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(0, 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(0, 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(0, 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(0, str+offset);
|
||||
});
|
||||
}
|
14
src/kernel/filesystem/sysfs.h
Normal file
14
src/kernel/filesystem/sysfs.h
Normal file
@ -0,0 +1,14 @@
|
||||
#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
|
133
src/kernel/filesystem/vfs.cpp
Normal file
133
src/kernel/filesystem/vfs.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
#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 false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
29
src/kernel/filesystem/vfs.h
Normal file
29
src/kernel/filesystem/vfs.h
Normal file
@ -0,0 +1,29 @@
|
||||
#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,
|
||||
._reserved10 = 0,
|
||||
._reserved11 = 0,
|
||||
.iopb = 104
|
||||
.iopb = sizeof(tss_struct)
|
||||
};
|
||||
|
||||
constexpr gdt_entry::gdt_entry(uint32_t limit, uint32_t base, bool rw, bool exec, bool system, uint8_t ring) :
|
||||
@ -77,7 +77,8 @@ constexpr gdt_entry::gdt_entry() :
|
||||
base_hi(0)
|
||||
{}
|
||||
|
||||
gdt_entry gdt[] = {
|
||||
gdt_and_iopb gai = {
|
||||
.gdt = {
|
||||
gdt_entry(), // Null Segment
|
||||
gdt_entry(0xfffff, 0, 1, 1, 1, 0), // Kernel Code Segment
|
||||
gdt_entry(0xfffff, 0, 1, 0, 1, 0), // Kernel Data Segment
|
||||
@ -86,16 +87,19 @@ gdt_entry gdt[] = {
|
||||
gdt_entry(0xfffff, 0, 1, 0, 1, 3), // User Data Segment
|
||||
|
||||
gdt_entry() // Empty Task State Segment
|
||||
}
|
||||
};
|
||||
|
||||
gdt_descr descr = (gdt_descr){
|
||||
.size = sizeof(gdt) - 1,
|
||||
.offset = gdt,
|
||||
.size = sizeof(gai.gdt) - 1,
|
||||
.offset = gai.gdt,
|
||||
};
|
||||
|
||||
void init_gdt() {
|
||||
gdt[5] = gdt_entry(sizeof(tss), &tss, 0, 1, 0, 0); // Initialise the TSS.
|
||||
gdt[5].accessed = 1;
|
||||
gai.gdt[5] = gdt_entry(sizeof(tss) + 8193, &tss, 0, 1, 0, 0); // Initialise the TSS.
|
||||
gai.gdt[5].accessed = 1;
|
||||
for (int i=0; i<8192; i++)
|
||||
gai.iopb[i] = 0;
|
||||
asm volatile("lgdt %0;"
|
||||
"mov $0x10, %%eax;"
|
||||
"mov %%eax, %%ss;"
|
||||
|
@ -76,6 +76,11 @@ struct __attribute__((packed)) gdt_descr {
|
||||
uint32_t offset;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) gdt_and_iopb {
|
||||
gdt_entry gdt[6];
|
||||
uint8_t iopb[8192];
|
||||
};
|
||||
|
||||
void init_gdt();
|
||||
|
||||
#endif
|
@ -7,6 +7,9 @@ for i ({0..255}); do
|
||||
echo "isr$i:" >> isr.S
|
||||
echo " push ebp" >> 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
|
||||
echo " push 0" >> isr.S
|
||||
fi
|
||||
|
@ -4,9 +4,11 @@ namespace Global {
|
||||
Allocator* allocator = 0;
|
||||
Kernel* kernel = 0;
|
||||
Process* currentProc = 0;
|
||||
Thread* currentThread = 0;
|
||||
tss_struct* tss = 0;
|
||||
bool currentProcValid = false;
|
||||
xnoe::hashtable<void*, ReadWriter*>* FH; // Map of File Handlers -> Read Writer
|
||||
uint32_t milliseconds_elapsed = 0;
|
||||
uint32_t resp = 0;
|
||||
}
|
||||
|
||||
void* operator new (uint32_t size) {
|
||||
@ -32,3 +34,11 @@ void* operator new[] (uint32_t size) {
|
||||
void operator delete[] (void* 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,20 +6,19 @@
|
||||
class Kernel;
|
||||
class Allocator;
|
||||
class Process;
|
||||
class Thread;
|
||||
struct tss_struct;
|
||||
class ReadWriter;
|
||||
namespace xnoe {
|
||||
template<class, class>
|
||||
class hashtable;
|
||||
}
|
||||
|
||||
namespace Global {
|
||||
extern Allocator* allocator;
|
||||
extern Kernel* kernel;
|
||||
extern Process* currentProc;
|
||||
extern Thread* currentThread;
|
||||
extern tss_struct* tss;
|
||||
extern bool currentProcValid;
|
||||
extern xnoe::hashtable<void*, ReadWriter*>* FH;
|
||||
extern uint32_t milliseconds_elapsed;
|
||||
extern uint32_t resp;
|
||||
}
|
||||
|
||||
void* operator new (uint32_t size);
|
||||
@ -30,4 +29,6 @@ void operator delete (void* ptr, unsigned int size);
|
||||
void* operator new[] (uint32_t size);
|
||||
void operator delete[] (void* ptr);
|
||||
|
||||
int clamp(int a, int b, int c);
|
||||
|
||||
#endif
|
@ -26,31 +26,35 @@ void handle_fault(frame_struct* frame) {
|
||||
asm ("cli");
|
||||
uint32_t problem_address;
|
||||
asm ("mov %%cr2, %0" : "=a" (problem_address):);
|
||||
Global::kernel->terminal->printf("(CS %x EIP %x): ", frame->cs, frame->eip);
|
||||
/*Global::kernel->terminal->printf("\x1b[44;37;1m(CS %x EIP %x): ", frame->cs, frame->eip);*/
|
||||
switch (frame->gate) {
|
||||
case 0: // Divide by zero
|
||||
Global::kernel->terminal->printf("Divide by Zero");
|
||||
//Global::kernel->terminal->printf("Divide by Zero");
|
||||
break;
|
||||
case 6: // Invalid Opcode
|
||||
Global::kernel->terminal->printf("Invalid Opcode");
|
||||
//Global::kernel->terminal->printf("Invalid Opcode");
|
||||
break;
|
||||
case 13: // GPF
|
||||
Global::kernel->terminal->printf("General Protection Fault!");
|
||||
//Global::kernel->terminal->printf("General Protection Fault!");
|
||||
if (frame->eflags & 0x00020000) {
|
||||
v86_monitor((v8086_frame_struct*)frame);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
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;
|
||||
default:
|
||||
Global::kernel->terminal->printf("Unkown Fault!");
|
||||
//Global::kernel->terminal->printf("Unkown Fault!");
|
||||
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)) {
|
||||
Global::kernel->terminal->printf("[FATAL] Kernel Fault!!!\n");
|
||||
while (1) asm("hlt");
|
||||
} else {
|
||||
// Print an error message.
|
||||
Global::kernel->terminal->printf("PID %d Terminated due to fault!\n", Global::currentProc->PID);
|
||||
//Global::kernel->terminal->printf("PID %d Terminated due to fault!\n", Global::currentProc->PID);
|
||||
asm volatile ("mov %0, %%esp" ::"m"(Global::kernel->globalISRStack));
|
||||
Global::kernel->PD->select();
|
||||
|
||||
@ -58,10 +62,7 @@ void handle_fault(frame_struct* frame) {
|
||||
Global::kernel->destroyProcess(Global::currentProc);
|
||||
|
||||
Global::currentProcValid = false;
|
||||
|
||||
// Go in to an infinite loop
|
||||
asm ("sti");
|
||||
while (1) asm ("hlt");
|
||||
context_switch(frame);
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,58 +84,65 @@ void context_switch(frame_struct* frame) {
|
||||
|
||||
asm ("cli"); // Disable interrupts whilst handling the context switch.
|
||||
|
||||
xnoe::linkedlist<Process*>* processes = &Global::kernel->processes;
|
||||
xnoe::linkedlist<Thread*>* threads = &Global::kernel->threads;
|
||||
|
||||
if (!processes->start) {
|
||||
if (!threads->start) {
|
||||
Global::kernel->terminal->printf("[FATAL] No more processes! Halting!\n");
|
||||
while (1) asm ("hlt");
|
||||
}
|
||||
|
||||
if (Global::currentProcValid)
|
||||
Global::currentProc->kernelStackPtr = frame->new_esp;
|
||||
Global::currentThread->kernelStackPtr = frame->new_esp;
|
||||
|
||||
// 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
|
||||
// - 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 (Global::currentProc) {
|
||||
if (processes->start->next != 0) {
|
||||
if (processes->end->prev == processes->start) {
|
||||
xnoe::linkedlistelem<Process*>* tmp = processes->start;
|
||||
processes->start = processes->end;
|
||||
processes->end = tmp;
|
||||
uint32_t count = 0;
|
||||
do {
|
||||
if (count++ == threads->length)
|
||||
return;
|
||||
if (Global::currentThread) {
|
||||
if (threads->start->next != 0) {
|
||||
if (threads->end->prev == threads->start) {
|
||||
xnoe::linkedlistelem<Thread*>* tmp = threads->start;
|
||||
threads->start = threads->end;
|
||||
threads->end = tmp;
|
||||
|
||||
processes->start->prev = 0;
|
||||
processes->end->next = 0;
|
||||
processes->end->prev = processes->start;
|
||||
processes->start->next = processes->end;
|
||||
threads->start->prev = 0;
|
||||
threads->end->next = 0;
|
||||
threads->end->prev = threads->start;
|
||||
threads->start->next = threads->end;
|
||||
} else {
|
||||
processes->end->next = processes->start;
|
||||
processes->start = processes->start->next;
|
||||
processes->start->prev = 0;
|
||||
xnoe::linkedlistelem<Process*>* tmp = processes->end;
|
||||
processes->end = processes->end->next;
|
||||
processes->end->next = 0;
|
||||
processes->end->prev = tmp;
|
||||
threads->end->next = threads->start;
|
||||
threads->start = threads->start->next;
|
||||
threads->start->prev = 0;
|
||||
xnoe::linkedlistelem<Thread*>* tmp = threads->end;
|
||||
threads->end = threads->end->next;
|
||||
threads->end->next = 0;
|
||||
threads->end->prev = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
Global::currentThread = threads->start->elem;
|
||||
Global::currentProc = threads->start->elem->parent;
|
||||
} while (Global::currentThread->state != Running);
|
||||
|
||||
Global::currentProc = processes->start->elem;
|
||||
|
||||
// Select the next processes page directory
|
||||
frame->new_cr3 = Global::currentProc->PD->phys_addr;
|
||||
frame->new_cr3 = Global::currentThread->parent->PD->phys_addr;
|
||||
// Restore kernelStackPtr of the new process.
|
||||
frame->new_esp = Global::currentProc->kernelStackPtr;
|
||||
frame->new_esp = Global::currentThread->kernelStackPtr;
|
||||
|
||||
Global::tss->esp0 = Global::currentProc->kernelStackPtrDefault;
|
||||
Global::tss->esp0 = Global::currentThread->kernelStackPtrDefault;
|
||||
|
||||
// Set the current proc to valid
|
||||
Global::currentProcValid = true;
|
||||
}
|
||||
|
||||
namespace Timer {
|
||||
using TimedEvent = xnoe::tuple<uint32_t, uint32_t, void(*)(frame_struct*, void*), void*>;
|
||||
// counter, default count, function, argument, oneshot
|
||||
using TimedEvent = xnoe::tuple<uint32_t, uint32_t, void(*)(frame_struct*, void*), void*, bool>;
|
||||
xnoe::linkedlist<TimedEvent> timed_events;
|
||||
void tick(frame_struct* frame) {
|
||||
xnoe::linkedlistelem<TimedEvent>* current = timed_events.start;
|
||||
@ -144,40 +152,61 @@ namespace Timer {
|
||||
if (--count == 0) {
|
||||
xnoe::get<2>(t)(frame, xnoe::get<3>(t));
|
||||
count = xnoe::get<1>(t);
|
||||
}
|
||||
current->elem = TimedEvent(count, xnoe::get<1>(t), xnoe::get<2>(t), xnoe::get<3>(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), xnoe::get<4>(t));
|
||||
current = current->next;
|
||||
}
|
||||
Global::milliseconds_elapsed++;
|
||||
}
|
||||
|
||||
void register_event(uint32_t milliseconds, void(*function)(frame_struct*, void*), void* auxiliary, bool oneshot=false) {
|
||||
timed_events.append(TimedEvent(milliseconds, milliseconds, function, auxiliary, oneshot));
|
||||
}
|
||||
}
|
||||
|
||||
void register_event(uint32_t milliseconds, void(*function)(frame_struct*, void*), void* auxiliary) {
|
||||
timed_events.append(TimedEvent(milliseconds, milliseconds, function, auxiliary));
|
||||
}
|
||||
void awaken(frame_struct* frame, Thread* t) {
|
||||
t->state = Running;
|
||||
}
|
||||
|
||||
void syscall(frame_struct* frame) {
|
||||
// Syscall ABI:
|
||||
// 0: X
|
||||
// 1: X
|
||||
// 2: X
|
||||
// 3: X
|
||||
// 4: localalloc: LocalAlloc: Allocate under current process (in esi: size; out eax void* ptr)
|
||||
// 5: localdelete: LocalDelete: Deallocate under current process (in esi: pointer)
|
||||
// 6: X
|
||||
// 7: fork :: char* filename esi -> int PID // Spawns a process and returns its PID.
|
||||
// 0: getDentsSize :: char* path -> uint32_t size
|
||||
// 1: getDents :: char* path -> uint8_t* buffer -> void
|
||||
// 2: exists :: char* path -> bool
|
||||
// 3: type :: char* path -> FSType
|
||||
// 4: localalloc :: uint32_t size -> void* ptr
|
||||
// 5: localdelete :: void* ptr -> void
|
||||
// 6: getMillisecondsElapsed :: void -> uint32_t
|
||||
// 7: exec :: void* filehandler -> int PID // Spawns a process and returns its PID.
|
||||
// 8: getPID: returns the current process's PID (out eax: uint32_t)
|
||||
// 9: getFileHandler :: char* path esi -> void* eax // Returns a file handlers for a specific file
|
||||
// 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 ebx -> void* filehandler esi -> uint8_t* inputbuffer edi -> int written // Reads from a buffer in to a file, returns successful written
|
||||
// 9: die :: destroys the current process void -> void
|
||||
// 10: read :: uint32_t count -> void* filehandler -> uint8_t* outputbuffer -> 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
|
||||
// 12: bindToKeyboard :: void -> void // Binds the current process's stdout to the keyboard.
|
||||
|
||||
// 13: bindStdout :: int PID esi -> int filehandler // Returns a filehandler for a CircularRWBuffer binding stdout of another process.
|
||||
// 14: bindStdin :: int PID esi -> int filehandler // Returns a filehandler for a CircularRWBuffer binding stdin of another process.
|
||||
// 13: bindStdout :: int PID -> 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.
|
||||
|
||||
// 15: fopen :: char* path esi -> int filehandler // Returns a filehandler to the file.
|
||||
// 16: fclose :: int filehandler esi -> void // Closes a file handler.
|
||||
// 15: fopen :: char* path -> int filehandler // Returns a filehandler to the file.
|
||||
// 16: fclose :: int filehandler -> void // Closes a file handler.
|
||||
|
||||
// 17: kill :: int PID esi -> void // Destroys a process.
|
||||
// 17: kill :: int PID -> 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:
|
||||
// 0: Stdout
|
||||
@ -187,83 +216,81 @@ void syscall(frame_struct* frame) {
|
||||
|
||||
uint32_t rval = frame->eax;
|
||||
|
||||
uint32_t esi = frame->esi;
|
||||
uint32_t edi = frame->edi;
|
||||
|
||||
Process* currentProc = Global::currentProc;
|
||||
|
||||
switch (frame->eax) {
|
||||
case 0:
|
||||
case 0: // getDentsSize
|
||||
rval = Global::kernel->rootfs->getDentsSize(createPathFromString(frame->ebx));
|
||||
break;
|
||||
case 1:
|
||||
case 1: // getDents
|
||||
Global::kernel->rootfs->getDents(createPathFromString(frame->ebx), frame->ecx);
|
||||
break;
|
||||
case 2:
|
||||
case 2: // exists
|
||||
rval = Global::kernel->rootfs->exists(createPathFromString(frame->ebx));
|
||||
break;
|
||||
case 3:
|
||||
case 3: // type
|
||||
rval = Global::kernel->rootfs->type(createPathFromString(frame->ebx));
|
||||
break;
|
||||
case 4:
|
||||
rval = currentProc->allocate(esi);
|
||||
case 4: // malloc
|
||||
rval = currentProc->allocate(frame->ebx);
|
||||
break;
|
||||
case 5:
|
||||
currentProc->deallocate(esi);
|
||||
case 5: // free
|
||||
currentProc->deallocate(frame->ebx);
|
||||
break;
|
||||
case 6:
|
||||
case 6: // getMillisecondsElapsed
|
||||
rval = Global::milliseconds_elapsed;
|
||||
break;
|
||||
case 7: {
|
||||
case 7: { // exec
|
||||
asm("cli");
|
||||
Process* p = Global::kernel->createProcess(esi);
|
||||
xnoe::maybe<ReadWriter*> file = Global::currentProc->getFH(frame->ebx);
|
||||
if (file.is_ok()) {
|
||||
Process* p = Global::kernel->createProcess(file.get());
|
||||
rval = p->PID;
|
||||
} else {
|
||||
rval = 0;
|
||||
}
|
||||
asm("sti");
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
case 8: // getPID
|
||||
rval = currentProc->PID;
|
||||
break;
|
||||
|
||||
case 9:
|
||||
case 9: // die
|
||||
Global::kernel->PD->select();
|
||||
|
||||
// We can now safely delete the current process
|
||||
Global::kernel->destroyProcess(Global::currentProc);
|
||||
|
||||
Global::currentProcValid = false;
|
||||
context_switch(frame);
|
||||
break;
|
||||
|
||||
case 10: {
|
||||
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);
|
||||
case 10: { // read
|
||||
xnoe::maybe<ReadWriter*> fh = Global::currentProc->getFH(frame->ecx);
|
||||
if (!fh.is_ok()) {
|
||||
rval = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
ReadWriter* rw = fh.get();
|
||||
rval = rw->read(frame->ebx, edi);
|
||||
}
|
||||
rval = rw->read(frame->ebx, frame->edx);
|
||||
break;
|
||||
}
|
||||
|
||||
case 11: {
|
||||
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);
|
||||
case 11: { // write
|
||||
xnoe::maybe<ReadWriter*> fh = Global::currentProc->getFH(frame->ecx);
|
||||
if (!fh.is_ok()) {
|
||||
rval = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
ReadWriter* rw = fh.get();
|
||||
rval = rw->write(frame->ebx, edi);
|
||||
}
|
||||
rval = rw->write(frame->ebx, frame->edx);
|
||||
break;
|
||||
}
|
||||
|
||||
case 12:
|
||||
case 12: // bindToKeyboard
|
||||
if (currentProc->stdin)
|
||||
break;
|
||||
|
||||
@ -271,50 +298,51 @@ void syscall(frame_struct* frame) {
|
||||
Global::kernel->KBListeners.append(currentProc);
|
||||
break;
|
||||
|
||||
case 13: {
|
||||
xnoe::Maybe<Process*> pm = Global::kernel->pid_map->get(esi);
|
||||
case 13: { // bindStdout
|
||||
xnoe::maybe<Process*> pm = Global::kernel->pid_map->get(frame->ebx);
|
||||
if (!pm.is_ok())
|
||||
break;
|
||||
Process* p = pm.get();
|
||||
if (!p->stdout) {
|
||||
ReadWriter* buffer = new CircularRWBuffer(currentProc->PID, esi);
|
||||
ReadWriter* buffer = new CircularRWBuffer(currentProc->PID, frame->ebx);
|
||||
p->stdout = buffer;
|
||||
rval = Global::kernel->mapFH(buffer);
|
||||
rval = Global::currentProc->mapFH(buffer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 14: {
|
||||
xnoe::Maybe<Process*> pm = Global::kernel->pid_map->get(esi);
|
||||
case 14: { // bindStdin
|
||||
xnoe::maybe<Process*> pm = Global::kernel->pid_map->get(frame->ebx);
|
||||
if (!pm.is_ok())
|
||||
break;
|
||||
Process* p = pm.get();
|
||||
if (!p->stdin) {
|
||||
ReadWriter* buffer = new CircularRWBuffer(esi, currentProc->PID);
|
||||
ReadWriter* buffer = new CircularRWBuffer(frame->ebx, currentProc->PID);
|
||||
p->stdin = buffer;
|
||||
rval = Global::kernel->mapFH(buffer);
|
||||
rval = Global::currentProc->mapFH(buffer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 15: {
|
||||
ReadWriter* file = new FATFileReadWriter(0, esi);
|
||||
rval = Global::kernel->mapFH(file);
|
||||
case 15: { // fopen
|
||||
ReadWriter* file = Global::kernel->rootfs->open(createPathFromString(frame->ebx));
|
||||
if (file)
|
||||
rval = Global::currentProc->mapFH(file);
|
||||
break;
|
||||
}
|
||||
|
||||
case 16: {
|
||||
xnoe::Maybe<ReadWriter*> f = Global::FH->get(esi);
|
||||
case 16: { // fclose
|
||||
xnoe::maybe<ReadWriter*> f = Global::currentProc->getFH(frame->ebx);
|
||||
if (f.is_ok()) {
|
||||
delete f.get();
|
||||
Global::kernel->unmapFH(esi);
|
||||
Global::currentProc->unmapFH(frame->ebx);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 17: {
|
||||
case 17: { // kill
|
||||
asm("cli");
|
||||
xnoe::Maybe<Process*> p = Global::kernel->pid_map->get(esi);
|
||||
xnoe::maybe<Process*> p = Global::kernel->pid_map->get(frame->ebx);
|
||||
if (p.is_ok()) {
|
||||
Process* proc = p.get();
|
||||
Global::kernel->destroyProcess(proc);
|
||||
@ -323,6 +351,43 @@ void syscall(frame_struct* frame) {
|
||||
break;
|
||||
}
|
||||
|
||||
case 18: { // sleep
|
||||
Global::currentThread->state = Suspended;
|
||||
Timer::register_event(frame->ebx, &awaken, (void*)Global::currentThread, true);
|
||||
context_switch(frame);
|
||||
break;
|
||||
}
|
||||
|
||||
case 19: // getRemainingPages
|
||||
rval = Global::kernel->phys->remainingPages;
|
||||
break;
|
||||
case 20: // getInitPages
|
||||
rval = Global::kernel->phys->initPages;
|
||||
break;
|
||||
|
||||
case 21: // getTerminalWidth
|
||||
rval = Global::kernel->terminal->width;
|
||||
break;
|
||||
case 22: // getTerminalHeight
|
||||
rval = 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();
|
||||
//rval = proc->state;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 24: { // Spawn Thread
|
||||
Thread* thread = new Thread(Global::currentProc);
|
||||
thread->initKernelStack(frame->ebx, thread->stack);
|
||||
Global::kernel->threads.append(thread);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -330,6 +395,60 @@ void syscall(frame_struct* frame) {
|
||||
frame->eax = rval;
|
||||
}
|
||||
|
||||
void v86_monitor(v8086_frame_struct* frame) {
|
||||
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++);
|
||||
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 = sp;
|
||||
}
|
||||
|
||||
void init_idt() {
|
||||
idt_desc desc = {.size = 256 * sizeof(GateEntry) - 1, .offset = (uint32_t)idt};
|
||||
asm volatile("lidt %0" : : "m" (desc));
|
||||
@ -340,7 +459,6 @@ void init_idt() {
|
||||
for (int i=0; i<256; i++)
|
||||
gates[i] = &ignore_interrupt;
|
||||
|
||||
gates[32] = &Timer::tick;
|
||||
gates[0] = &handle_fault;
|
||||
gates[5] = &handle_fault;
|
||||
gates[6] = &handle_fault;
|
||||
@ -360,9 +478,9 @@ void init_idt() {
|
||||
gates[29] = &handle_fault;
|
||||
gates[30] = &handle_fault;
|
||||
gates[31] = &handle_fault;
|
||||
gates[127] = &syscall;
|
||||
gates[128] = &syscall;
|
||||
|
||||
idt[127].privilege = 3;
|
||||
idt[128].privilege = 3;
|
||||
|
||||
outb(0x20, 0x11);
|
||||
outb(0xA0, 0x11);
|
||||
@ -385,5 +503,6 @@ void init_idt() {
|
||||
}
|
||||
|
||||
void enable_idt() {
|
||||
gates[32] = &Timer::tick;
|
||||
asm ("sti");
|
||||
}
|
@ -2,7 +2,6 @@
|
||||
#define IDT_H
|
||||
|
||||
#include "types.h"
|
||||
#include "screenstuff.h"
|
||||
#include "global.h"
|
||||
#include "kernel.h"
|
||||
#include "gdt.h"
|
||||
@ -29,9 +28,43 @@ struct __attribute__((packed)) frame_struct {
|
||||
uint16_t cs;
|
||||
uint16_t _ignored0;
|
||||
uint32_t eflags;
|
||||
uint32_t esp;
|
||||
uint16_t ss;
|
||||
uint16_t _ignored1;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) v8086_frame_struct {
|
||||
uint32_t new_cr3;
|
||||
uint32_t new_esp;
|
||||
|
||||
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;
|
||||
uint16_t es;
|
||||
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*);
|
||||
@ -57,4 +90,10 @@ struct __attribute__((packed)) idt_desc {
|
||||
uint32_t offset;
|
||||
};
|
||||
|
||||
void context_switch(frame_struct* frame);
|
||||
void handle_fault(frame_struct* frame);
|
||||
void syscall(frame_struct* frame);
|
||||
void ignore_interrupt(frame_struct* frame);
|
||||
void v86_monitor(v8086_frame_struct* frame);
|
||||
|
||||
#endif
|
@ -19,3 +19,21 @@ extern "C" {
|
||||
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,4 +11,17 @@ extern "C" {
|
||||
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
|
@ -12,28 +12,26 @@ Kernel::Kernel(PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint
|
||||
this->stack = stack;
|
||||
|
||||
this->lastFH = 8;
|
||||
|
||||
//this->processes.append(this);
|
||||
}
|
||||
|
||||
void Kernel::init_kernel() {
|
||||
this->pid_map = new xnoe::hashtable<uint32_t, Process*>();
|
||||
Global::FH = new xnoe::hashtable<void*, ReadWriter*>();
|
||||
this->globalISRStack = (new uint8_t[0x8000]) + 0x8000;
|
||||
}
|
||||
|
||||
Process* Kernel::createProcess(uint32_t fh) {
|
||||
Process* p = new Process(currentPID, this->PD, 0xc0000000, fh);
|
||||
Process* Kernel::createProcess(ReadWriter* file) {
|
||||
char* name = "test";
|
||||
Process* p = new Process(currentPID, this->PD, 0xc0000000, file, 1, &name);
|
||||
this->pid_map->set(currentPID, p);
|
||||
currentPID++;
|
||||
|
||||
this->processes.append(p);
|
||||
this->threads.append(p->threads.start->elem);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
Process* Kernel::createProcess(uint32_t fh, ReadWriter* stdout) {
|
||||
Process* p = this->createProcess(fh);
|
||||
Process* Kernel::createProcess(ReadWriter* file, ReadWriter* stdout) {
|
||||
Process* p = this->createProcess(file);
|
||||
p->stdout = stdout;
|
||||
return p;
|
||||
}
|
||||
@ -41,20 +39,69 @@ Process* Kernel::createProcess(uint32_t fh, ReadWriter* stdout) {
|
||||
void Kernel::destroyProcess(Process* p) {
|
||||
if (Global::currentProc == p)
|
||||
Global::currentProcValid = false;
|
||||
this->processes.remove(p);
|
||||
xnoe::linkedlistelem<Thread*>* currentThread = p->threads.start;
|
||||
while (currentThread) {
|
||||
this->threads.remove(currentThread->elem);
|
||||
currentThread = currentThread->next;
|
||||
}
|
||||
this->pid_map->remove(p->PID);
|
||||
delete p;
|
||||
}
|
||||
|
||||
int Kernel::mapFH(ReadWriter* fh) {
|
||||
Global::FH->set(this->lastFH++, fh);
|
||||
return this->lastFH - 1;
|
||||
}
|
||||
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
|
||||
};
|
||||
|
||||
void Kernel::unmapFH(uint32_t fh) {
|
||||
Global::FH->remove((void*)fh);
|
||||
}
|
||||
// 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);
|
||||
|
||||
//void Kernel::loadPrimaryStack() {
|
||||
// asm volatile("mov %0, %%esp"::"m"(this->stack - 64));
|
||||
//}
|
||||
*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,6 +5,8 @@
|
||||
#include "datatypes/hashtable.h"
|
||||
#include "global.h"
|
||||
#include "terminal.h"
|
||||
#include "filesystem/fstree.h"
|
||||
#include "gdt.h"
|
||||
|
||||
class Kernel : public Process {
|
||||
private:
|
||||
@ -20,17 +22,17 @@ public:
|
||||
xnoe::linkedlist<Process*> processes;
|
||||
xnoe::linkedlist<Process*> KBListeners;
|
||||
|
||||
RootFSTree* rootfs;
|
||||
|
||||
Kernel(PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base, uint32_t stack);
|
||||
|
||||
void init_kernel();
|
||||
|
||||
Process* createProcess(uint32_t fh);
|
||||
Process* createProcess(uint32_t fh, ReadWriter* stdout);
|
||||
Process* createProcess(ReadWriter* file);
|
||||
Process* createProcess(ReadWriter* file, ReadWriter* stdout);
|
||||
void destroyProcess(Process* p);
|
||||
|
||||
int mapFH(ReadWriter* fh);
|
||||
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
|
@ -3,7 +3,6 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "io.h"
|
||||
#include "screenstuff.h"
|
||||
#include "idt.h"
|
||||
|
||||
void init_keyboard();
|
||||
|
@ -1,10 +1,9 @@
|
||||
#include "types.h"
|
||||
#include "screenstuff.h"
|
||||
#include "io.h"
|
||||
#include "idt.h"
|
||||
#include "keyboard.h"
|
||||
#include "strings.h"
|
||||
#include "atapio.h"
|
||||
#include "ata.h"
|
||||
#include "gdt.h"
|
||||
#include "paging.h"
|
||||
#include "allocate.h"
|
||||
@ -14,24 +13,36 @@
|
||||
#include "datatypes/hashtable.h"
|
||||
#include "terminal.h"
|
||||
#include "kernel.h"
|
||||
#include "filesystem/fstree.h"
|
||||
#include "filesystem/fat16.h"
|
||||
#include "filesystem/devfs.h"
|
||||
#include "filesystem/sysfs.h"
|
||||
|
||||
int main() {
|
||||
struct KernelInformationStruct {
|
||||
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_term();
|
||||
|
||||
PageDirectory kernel_pd = PageDirectory(0xc0100000, 0x120000, 0xbffe0000);
|
||||
PageDirectory kernel_pd = PageDirectory(kstruct.pde, kstruct.page_directory_phys_addr, kstruct.page_directory_phys_offset);
|
||||
|
||||
kernel_pd.select();
|
||||
kernel_pd.unmap(0x8000);
|
||||
|
||||
PageMap phys_pm(0xc0600000);
|
||||
PageMap virt_pm(0xc0620000);
|
||||
PageMap phys_pm(kstruct.page_bitmap_phys, kstruct.remainingPages);
|
||||
PageMap virt_pm(kstruct.page_bitmap_virt);
|
||||
|
||||
Kernel kernel = Kernel(&kernel_pd, &phys_pm, &virt_pm, 0xc0000000, 0xc1006000);
|
||||
Kernel kernel = Kernel(&kernel_pd, &phys_pm, &virt_pm, 0xc0000000, kstruct.stack_ptr);
|
||||
kernel.init_kernel();
|
||||
init_atapio();
|
||||
|
||||
VGAModeTerminal* term = new VGAModeTerminal(0xc07a0000);
|
||||
VGAModeTerminal* term = new VGAModeTerminal(kstruct.vga_addr);
|
||||
|
||||
kernel.terminal = term;
|
||||
|
||||
@ -44,13 +55,19 @@ int main() {
|
||||
|
||||
term->printf("KERNEL OK!\n");
|
||||
|
||||
ReadWriter* worldbin = new FATFileReadWriter(0, "etc/world.bin");
|
||||
uint32_t fh = kernel.mapFH(worldbin);
|
||||
ReadWriter* atareadwriter = new ATAReadWriter(0, 0);
|
||||
|
||||
Process* p1 = kernel.createProcess(fh, term);
|
||||
kernel.rootfs = new RootFSTree();
|
||||
kernel.rootfs->mount(createPathFromString("/dev"), new DevFS());
|
||||
kernel.rootfs->mount(createPathFromString("/sys"), new SysFS());
|
||||
kernel.rootfs->mount(createPathFromString("/"), new FAT16FS(kernel.rootfs->open(createPathFromString("/dev/ata"))));
|
||||
ReadWriter* worldbin = kernel.rootfs->open(createPathFromString("/world.bin"));
|
||||
|
||||
Process* p1 = kernel.createProcess(worldbin, term);
|
||||
|
||||
Global::tss->esp0 = (new uint8_t[8192]) + 8192;
|
||||
|
||||
init_keyboard();
|
||||
|
||||
enable_idt();
|
||||
|
||||
while (1) asm ("hlt");
|
||||
|
@ -5,13 +5,14 @@ void memset(uint8_t* address, uint32_t count, uint8_t value) {
|
||||
address[i] = value;
|
||||
}
|
||||
|
||||
void memcpy(uint8_t* src, uint8_t* dst, uint32_t count) {
|
||||
void memcpy(uint8_t* dst, uint8_t* src, uint32_t count) {
|
||||
for (int i = 0; i<count; i++)
|
||||
dst[i] = src[i];
|
||||
}
|
||||
|
||||
PageMap::PageMap(uint32_t map) {
|
||||
PageMap::PageMap(uint32_t map, uint32_t remainingPages) {
|
||||
this->pagemap = (uint8_t*)map;
|
||||
this->initPages = this->remainingPages = remainingPages;
|
||||
}
|
||||
|
||||
PageMap::PageMap() {
|
||||
@ -38,6 +39,8 @@ void PageMap::unset_bit(uint32_t index) {
|
||||
}
|
||||
|
||||
bool PageMap::bit_set(uint32_t index) {
|
||||
if (!index)
|
||||
return false;
|
||||
uint32_t offset = index % 8;
|
||||
uint32_t i = index / 8;
|
||||
|
||||
@ -46,20 +49,24 @@ bool PageMap::bit_set(uint32_t index) {
|
||||
|
||||
void PageMap::mark_unavailable(uint32_t address) {
|
||||
unset_bit(address >> 12);
|
||||
this->remainingPages--;
|
||||
}
|
||||
|
||||
void PageMap::mark_unavailable(uint32_t address, uint32_t count) {
|
||||
for (int i=0; i<count; i++)
|
||||
unset_bit((address >> 12) + i);
|
||||
this->remainingPages -= count;
|
||||
}
|
||||
|
||||
void PageMap::mark_available(uint32_t address) {
|
||||
set_bit(address >> 12);
|
||||
this->remainingPages++;
|
||||
}
|
||||
|
||||
void PageMap::mark_available(uint32_t address, uint32_t count) {
|
||||
for (int i=0; i<count; i++)
|
||||
set_bit((address >> 12) + i);
|
||||
this->remainingPages += count;
|
||||
}
|
||||
|
||||
bool PageMap::available(uint32_t address) {
|
||||
@ -91,6 +98,7 @@ PageTable::PageTable(uint32_t phys, uint32_t virt) {
|
||||
virt_addr = virt;
|
||||
|
||||
page_table = (PTE*)virt;
|
||||
valid = 1;
|
||||
}
|
||||
|
||||
PageTable::PageTable(){
|
||||
@ -100,6 +108,7 @@ PageTable::PageTable(){
|
||||
phys_addr = (Global::allocator->virtual_to_physical(virt_addr)) >> 12;
|
||||
|
||||
page_table = (PTE*)virt_addr;
|
||||
valid = 1;
|
||||
}
|
||||
|
||||
PageTable::~PageTable() {
|
||||
@ -149,7 +158,7 @@ PageDirectory::PageDirectory(PDE* page_directory, uint32_t phys_addr, uint32_t o
|
||||
|
||||
for (int i=0; i<1024; i++) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,7 +174,7 @@ PageDirectory::PageDirectory() {
|
||||
|
||||
PageDirectory::~PageDirectory() {
|
||||
for (int i=0; i<1024; i++)
|
||||
if (page_tables[i].virt_addr)
|
||||
if (page_tables[i].valid)
|
||||
page_tables[i].~PageTable();
|
||||
delete page_directory;
|
||||
}
|
||||
@ -173,8 +182,8 @@ PageDirectory::~PageDirectory() {
|
||||
void PageDirectory::map(uint32_t phys, uint32_t virt, uint8_t privilege) {
|
||||
split_addr* split = (split_addr*)&virt;
|
||||
|
||||
if (!page_tables[split->pd_index].virt_addr)
|
||||
new (page_tables + split->pd_index) PageTable();
|
||||
if (!page_tables[split->pd_index].valid)
|
||||
new (&page_tables[split->pd_index]) PageTable();
|
||||
|
||||
page_directory[split->pd_index] = (PDE){
|
||||
.present = 1,
|
||||
|
@ -3,13 +3,12 @@
|
||||
|
||||
#include "paging.h"
|
||||
#include "allocate.h"
|
||||
#include "screenstuff.h"
|
||||
#include "global.h"
|
||||
|
||||
void memset(uint8_t* address, uint32_t count, uint8_t value);
|
||||
void memcpy(uint8_t* src, uint8_t* dst, uint32_t count);
|
||||
void memcpy(uint8_t* dst, uint8_t* src, uint32_t count);
|
||||
|
||||
class __attribute__((packed)) PageMap {
|
||||
class PageMap {
|
||||
private:
|
||||
uint8_t* pagemap;
|
||||
|
||||
@ -19,7 +18,10 @@ private:
|
||||
bool bit_set(uint32_t index);
|
||||
|
||||
public:
|
||||
PageMap(uint32_t map);
|
||||
uint32_t remainingPages;
|
||||
uint32_t initPages;
|
||||
|
||||
PageMap(uint32_t map, uint32_t remainingPages=0x100000);
|
||||
PageMap();
|
||||
|
||||
~PageMap();
|
||||
@ -41,6 +43,8 @@ struct PageTable {
|
||||
|
||||
uint32_t phys_addr;
|
||||
uint32_t virt_addr;
|
||||
uint32_t valid = 0;
|
||||
uint32_t reserved;
|
||||
|
||||
PageTable(uint32_t phys, uint32_t virt);
|
||||
PageTable();
|
||||
@ -78,12 +82,12 @@ public:
|
||||
|
||||
class Allocator {
|
||||
protected:
|
||||
static PageMap* phys;
|
||||
PageMap* virt;
|
||||
|
||||
uint32_t virt_alloc_base;
|
||||
uint8_t privilege;
|
||||
public:
|
||||
static PageMap* phys;
|
||||
PageMap* virt;
|
||||
|
||||
PageDirectory* PD;
|
||||
|
||||
Allocator(PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base);
|
||||
@ -94,6 +98,8 @@ public:
|
||||
virtual void* allocate(uint32_t size);
|
||||
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);
|
||||
};
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
#ifndef PAGING_H
|
||||
#define PAGING_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "types.h"
|
||||
|
||||
struct __attribute__((packed)) split_addr {
|
||||
|
@ -4,16 +4,16 @@ extern void(*catchall_return)();
|
||||
|
||||
AllocTracker::AllocTracker(void* base, uint32_t size, uint32_t count) : page_base(base), page_size(size), alloc_count(count) {}
|
||||
|
||||
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;
|
||||
while (current) {
|
||||
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;
|
||||
}
|
||||
|
||||
return xnoe::Maybe<xnoe::linkedlistelem<AllocTracker>*>();
|
||||
return xnoe::maybe<xnoe::linkedlistelem<AllocTracker>*>();
|
||||
}
|
||||
|
||||
Process::Process(uint32_t PID, void* stack, PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base)
|
||||
@ -21,7 +21,6 @@ Process::Process(uint32_t PID, void* stack, PageDirectory* page_directory, PageM
|
||||
this->PID = PID;
|
||||
this->page_remaining = 0;
|
||||
this->last_page_pointer = virt_alloc_base;
|
||||
this->stack = stack;
|
||||
}
|
||||
|
||||
Process::Process(uint32_t PID)
|
||||
@ -29,46 +28,79 @@ Process::Process(uint32_t PID)
|
||||
this->PID = PID;
|
||||
this->page_remaining = 0;
|
||||
this->last_page_pointer = 0;
|
||||
this->stack = this->allocate(0x8000);
|
||||
this->kernelStackPtr = (new uint8_t[0x1000]) + 0x1000;
|
||||
this->file_handlers = new xnoe::dynarray<ReadWriter*>(8);
|
||||
}
|
||||
|
||||
Process::Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase, uint32_t fh)
|
||||
Process::Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase, ReadWriter* filereader, uint32_t argc, char** argv)
|
||||
: Allocator(new PageDirectory, new PageMap, (uint32_t)0, 3) {
|
||||
this->stdout = 0;
|
||||
this->stdin = 0;
|
||||
|
||||
this->firstRun = true;
|
||||
|
||||
this->PID = PID;
|
||||
this->page_remaining = 0;
|
||||
this->last_page_pointer = 0;
|
||||
|
||||
this->file_handlers = new xnoe::dynarray<ReadWriter*>(8);
|
||||
|
||||
for (int index = inheritBase >> 22; index < 1024; 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();
|
||||
uint8_t* program_data = this->allocate(filesize + 12) + 12;
|
||||
|
||||
this->stack = this->allocate(0x8000);
|
||||
this->kernelStackPtr = (new uint8_t[0x1000]) + 0xffc;
|
||||
this->kernelStackPtrDefault = this->kernelStackPtr;
|
||||
Thread* thread = new Thread(this);
|
||||
|
||||
uint32_t pCR3;
|
||||
asm ("mov %%cr3, %0" : "=a" (pCR3) :);
|
||||
this->PD->select();
|
||||
|
||||
// We also need to initialise ESP and the stack
|
||||
uint32_t* stack = thread->stack + 0x8000;
|
||||
uint8_t* argenvarea = this->allocate(0x2000);
|
||||
uint32_t argenv = argenvarea + 0x2000;
|
||||
for (int i=argc; i>0; i--) {
|
||||
char* s = argv[i-1];
|
||||
uint32_t c = 0;
|
||||
while (*(c++, s++));
|
||||
memcpy((uint8_t*)(argenv -= c), (uint8_t*)argv[i-1], c);
|
||||
*(--stack) = argenv;
|
||||
}
|
||||
*(--stack) = ((uint32_t)stack);
|
||||
|
||||
*(--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);
|
||||
}
|
||||
|
||||
Thread::Thread(Process* parent) {
|
||||
this->parent = parent;
|
||||
|
||||
this->stack = this->parent->allocate(0x8000);
|
||||
this->kernelStackPtr = (new uint8_t[0x4000]) + 0x4000;
|
||||
this->kernelStackPtrDefault = 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);
|
||||
*(--stack32) = 0x23; // SS
|
||||
*(--stack32) = ((uint32_t)this->stack + 0x8000); // ESP
|
||||
*(--stack32) = ((uint32_t)esp); // ESP
|
||||
*(--stack32) = 0x200; // EFLAGS
|
||||
*(--stack32) = 27; // CS
|
||||
*(--stack32) = (uint32_t)program_data; // EIP
|
||||
*(--stack32) = ((uint32_t)this->stack + 0x8000); // EBP
|
||||
*(--stack32) = (uint32_t)entryPoint; // EIP
|
||||
*(--stack32) = ((uint32_t)esp); // EBP
|
||||
|
||||
uint32_t rEBP = stack32;
|
||||
|
||||
@ -82,12 +114,8 @@ Process::Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase, uin
|
||||
*(--stack32) = 0; // EDI
|
||||
|
||||
this->kernelStackPtr = stack32;
|
||||
|
||||
filereader->read(filesize, program_data);
|
||||
|
||||
asm ("mov %0, %%cr3" : : "r" (pCR3));
|
||||
}
|
||||
}
|
||||
|
||||
Process::~Process() {
|
||||
uint32_t pCR3;
|
||||
@ -98,13 +126,22 @@ Process::~Process() {
|
||||
xnoe::linkedlistelem<AllocTracker>* active = next;
|
||||
next = next->next;
|
||||
|
||||
//printf("Deleted %x\n", active->elem.page_base);
|
||||
|
||||
this->deallocate(active->elem.page_base+1);
|
||||
this->deallocate(active->elem.page_base);
|
||||
}
|
||||
this->deallocate(stack);
|
||||
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())
|
||||
delete r.get();
|
||||
}
|
||||
|
||||
xnoe::linkedlistelem<Thread*>* currentThread = threads.start;
|
||||
while (currentThread) {
|
||||
delete currentThread->elem;
|
||||
currentThread = currentThread->next;
|
||||
}
|
||||
}
|
||||
|
||||
void* Process::allocate(uint32_t size) {
|
||||
@ -152,7 +189,7 @@ void* Process::allocate(uint32_t size) {
|
||||
}
|
||||
|
||||
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()) {
|
||||
AllocTracker* ac = &alloc_tracker.get()->elem;
|
||||
ac->alloc_count--;
|
||||
@ -171,10 +208,41 @@ void Process::deallocate(uint32_t virt_addr) {
|
||||
}
|
||||
|
||||
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())
|
||||
return alloc_tracker.get()->elem.alloc_count;
|
||||
else
|
||||
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,11 +6,27 @@
|
||||
#include "datatypes/linkedlist.h"
|
||||
#include "datatypes/hashtable.h"
|
||||
#include "datatypes/maybe.h"
|
||||
#include "screenstuff.h"
|
||||
#include "global.h"
|
||||
#include "atapio.h"
|
||||
|
||||
#include "processstate.h"
|
||||
#include "stdio/readwriter.h"
|
||||
#include "datatypes/dynarray.h"
|
||||
#include "filesystem/fstree.h"
|
||||
|
||||
class Process;
|
||||
class Thread {
|
||||
public:
|
||||
void* stack;
|
||||
void* kernelStackPtr;
|
||||
void* kernelStackPtrDefault;
|
||||
Process* parent;
|
||||
ProcessState state;
|
||||
bool firstRun;
|
||||
|
||||
Thread(Process* parent);
|
||||
~Thread();
|
||||
|
||||
void Thread::initKernelStack(void* entryPoint, void* esp);
|
||||
};
|
||||
|
||||
struct AllocTracker {
|
||||
void* page_base;
|
||||
@ -25,28 +41,27 @@ private:
|
||||
uint32_t last_page_pointer;
|
||||
uint32_t page_remaining;
|
||||
|
||||
void* stack;
|
||||
|
||||
// List of pages this process has allocated
|
||||
xnoe::linkedlist<AllocTracker> allocations;
|
||||
|
||||
xnoe::Maybe<xnoe::linkedlistelem<AllocTracker>*> get_alloc_tracker(uint32_t address);
|
||||
xnoe::maybe<xnoe::linkedlistelem<AllocTracker>*> get_alloc_tracker(uint32_t address);
|
||||
|
||||
xnoe::dynarray<ReadWriter*>* file_handlers;
|
||||
|
||||
Path currentWorkingDirectory;
|
||||
|
||||
public:
|
||||
uint32_t PID;
|
||||
uint32_t esp;
|
||||
|
||||
void* kernelStackPtr;
|
||||
void* kernelStackPtrDefault;
|
||||
|
||||
ReadWriter* stdout;
|
||||
ReadWriter* stdin;
|
||||
|
||||
bool firstRun;
|
||||
xnoe::linkedlist<Thread*> threads;
|
||||
|
||||
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(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase, ReadWriter* filereader, uint32_t argc=0, char** argv=0);
|
||||
|
||||
~Process(); // Iterate through allocations and free those; delete stack
|
||||
|
||||
@ -54,6 +69,10 @@ public:
|
||||
void deallocate(uint32_t virt_addr) override;
|
||||
|
||||
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
|
9
src/kernel/processstate.h
Normal file
9
src/kernel/processstate.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef PROCESSSTATE_H
|
||||
#define PROCESSSTATE_H
|
||||
|
||||
enum ProcessState {
|
||||
Running=0,
|
||||
Suspended=1
|
||||
};
|
||||
|
||||
#endif
|
@ -1,133 +0,0 @@
|
||||
#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);
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
#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
|
8
src/kernel/spinlock.cpp
Normal file
8
src/kernel/spinlock.cpp
Normal file
@ -0,0 +1,8 @@
|
||||
#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");
|
||||
}
|
14
src/kernel/spinlock.h
Normal file
14
src/kernel/spinlock.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef SPINLOCK_H
|
||||
#define SPINLOCK_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
class Spinlock {
|
||||
private:
|
||||
uint32_t locked = 0;
|
||||
public:
|
||||
void lock();
|
||||
void unlock();
|
||||
};
|
||||
|
||||
#endif
|
26
src/kernel/stdio/oneshotreadwriter.cpp
Normal file
26
src/kernel/stdio/oneshotreadwriter.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
#include "oneshotreadwriter.h"
|
||||
|
||||
OneShotReadWriter::OneShotReadWriter(uint32_t owner, uint8_t* toRead) : ReadWriter(owner) {
|
||||
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;
|
||||
}
|
22
src/kernel/stdio/oneshotreadwriter.h
Normal file
22
src/kernel/stdio/oneshotreadwriter.h
Normal file
@ -0,0 +1,22 @@
|
||||
#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(uint32_t owner, 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
|
@ -14,6 +14,7 @@ void ReadWriter::giveWritePerm(uint32_t PID) {
|
||||
|
||||
uint32_t ReadWriter::read(uint32_t count, uint8_t* buffer){}
|
||||
uint32_t ReadWriter::write(uint32_t count, uint8_t* buffer){}
|
||||
uint32_t ReadWriter::seek(uint32_t position){}
|
||||
uint32_t ReadWriter::size(){}
|
||||
|
||||
bool ReadWriter::canRead(uint32_t PID) {
|
||||
|
@ -18,6 +18,7 @@ public:
|
||||
virtual uint32_t read(uint32_t count, uint8_t* buffer);
|
||||
virtual uint32_t write(uint32_t count, uint8_t* buffer);
|
||||
virtual uint32_t size();
|
||||
virtual uint32_t seek(uint32_t position);
|
||||
uint32_t getOwner();
|
||||
bool canRead(uint32_t PID);
|
||||
bool canWrite(uint32_t PID);
|
||||
|
@ -1,5 +1,11 @@
|
||||
#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) {
|
||||
int index = 0;
|
||||
while (index < max) {
|
||||
|
@ -1,8 +1,9 @@
|
||||
#ifndef STRINGS_H
|
||||
#define STRINGS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "types.h"
|
||||
|
||||
uint32_t strlen(char* s);
|
||||
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);
|
||||
|
@ -1,6 +1,18 @@
|
||||
#include "terminal.h"
|
||||
|
||||
void Terminal::scroll_up() {
|
||||
int strToInt(char* str, uint32_t max) {
|
||||
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.
|
||||
for (int y = 0; y < (height * pages); y++) {
|
||||
uint16_t* cline = buffer + y * width;
|
||||
@ -12,19 +24,191 @@ void Terminal::scroll_up() {
|
||||
// Clear the last line
|
||||
uint16_t* last_line = buffer + (height * pages - 1) * width;
|
||||
for (int x = 0; x < width; x++) {
|
||||
last_line[x] = 0x0720;
|
||||
last_line[x] = 0x0720; //| (edata << 8);
|
||||
}
|
||||
this->cur_y--;
|
||||
}
|
||||
|
||||
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.
|
||||
last_page_pointer[ptr] = c | (edata<<8);
|
||||
last_page_pointer[this->cur_y*this->width+this->cur_x] = c | (edata<<8);
|
||||
|
||||
if (active)
|
||||
putchar_internal(ptr, c, edata);
|
||||
putchar_internal(this->cur_y*this->width+this->cur_x, c, this->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(){}
|
||||
@ -46,21 +230,19 @@ Terminal::Terminal(uint32_t width, uint32_t height, uint32_t pages)
|
||||
this->active = false;
|
||||
}
|
||||
|
||||
int strToInt(char* str) {
|
||||
int r=0;
|
||||
while (*str >= 0x30 && *str <= 0x39) {
|
||||
r *= 10;
|
||||
r += *(str++) - 0x30;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
void Terminal::resize(uint32_t width, uint32_t height, uint32_t pages) {
|
||||
delete this->buffer;
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->pages = pages;
|
||||
this->buffer = new uint16_t[width * height * pages];
|
||||
this->last_page_pointer = buffer + (width * height * pages) - (width * height);
|
||||
this->current_page_pointer = last_page_pointer;
|
||||
|
||||
int clamp(int a, int b, int c) {
|
||||
if (a < b)
|
||||
return b;
|
||||
if (a > c)
|
||||
return c;
|
||||
return a;
|
||||
this->cur_x = 0;
|
||||
this->cur_y = 0;
|
||||
|
||||
this->active = false;
|
||||
}
|
||||
|
||||
void Terminal::printf(const char* string, ...) {
|
||||
@ -71,73 +253,6 @@ void Terminal::printf(const char* string, ...) {
|
||||
char current;
|
||||
|
||||
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 == '%') {
|
||||
int type = string[index++];
|
||||
int offset;
|
||||
@ -159,22 +274,17 @@ void Terminal::printf(const char* string, ...) {
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
int mem_pos = this->cur_y * this->width + this->cur_x++;
|
||||
int promoted = va_arg(ptr, int);
|
||||
char charred = promoted;
|
||||
|
||||
this->putchar(mem_pos, charred);
|
||||
this->putchar(charred);
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current != '\n') {
|
||||
int mem_pos = this->cur_y * this->width + this->cur_x++;
|
||||
|
||||
this->putchar(mem_pos, current);
|
||||
}
|
||||
this->putchar(current);
|
||||
}
|
||||
|
||||
this->set_curpos(this->cur_x, this->cur_y);
|
||||
@ -183,84 +293,8 @@ void Terminal::printf(const char* string, ...) {
|
||||
}
|
||||
|
||||
uint32_t Terminal::write(uint32_t count, uint8_t* string) {
|
||||
int index = 0;
|
||||
char current;
|
||||
|
||||
while (index < count) {
|
||||
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 != '\n') {
|
||||
int mem_pos = this->cur_y * this->width + this->cur_x++;
|
||||
|
||||
this->putchar(mem_pos, current);
|
||||
}
|
||||
}
|
||||
for (int index=0; index < count; index++)
|
||||
this->putchar(string[index]);
|
||||
|
||||
this->set_curpos(this->cur_x, this->cur_y);
|
||||
}
|
||||
@ -330,10 +364,29 @@ TextModeTerminal::TextModeTerminal(uint16_t* text_mode_pointer): Terminal(80, 25
|
||||
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() {
|
||||
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]), 0);
|
||||
putchar_internal(y * width + x, (uint8_t)(current_page_pointer[y * width + x]), (uint8_t)(current_page_pointer[y * width + x]>>8));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -353,15 +406,12 @@ void VGAModeTerminal::putchar_internal(uint32_t ptr, uint8_t c, uint8_t edata) {
|
||||
return;
|
||||
uint8_t* char_data = font[c];
|
||||
|
||||
for (int y=0; y<8; y++) {
|
||||
//for (int x=0; x<8; x++) {
|
||||
put_pixels_byte(sx, sy+y, 15, char_data[y]);
|
||||
//}
|
||||
}
|
||||
for (int y=0; y<8; y++)
|
||||
put_pixels_byte(sx, sy+y, edata, char_data[y]);
|
||||
}
|
||||
|
||||
void VGAModeTerminal::put_pixels_byte(uint32_t x, uint32_t y, uint8_t color, uint8_t pixel_byte) {
|
||||
uint32_t pixel = y * 720 + x;
|
||||
uint32_t pixel = y * pixelWidth + x;
|
||||
uint32_t pixelindex = pixel / 8;
|
||||
|
||||
uint8_t trbyte = 0;
|
||||
@ -371,17 +421,18 @@ void VGAModeTerminal::put_pixels_byte(uint32_t x, uint32_t y, uint8_t color, uin
|
||||
}
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
if (color & (1<<i))
|
||||
this->planes[i][pixelindex] = trbyte;
|
||||
else
|
||||
this->planes[i][pixelindex] = 0;
|
||||
if (color & (1<<i))
|
||||
this->planes[i][pixelindex] |= trbyte;
|
||||
if ((color>>4) & (1<<i))
|
||||
this->planes[i][pixelindex] |= ~trbyte;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
uint32_t pixel = y * 720 + x;
|
||||
uint32_t pixel = y * pixelWidth + x;
|
||||
uint32_t pixelindex = pixel / 8;
|
||||
uint32_t pixelbitindex = pixel % 8;
|
||||
|
||||
@ -394,7 +445,7 @@ void VGAModeTerminal::put_pixel(uint32_t x, uint32_t y, uint8_t color) {
|
||||
}
|
||||
|
||||
static void VGAModeTerminal::bufferToVRAM(frame_struct* frame, VGAModeTerminal* terminal) {
|
||||
uint32_t count4 = (720 * 480) / 8 / 4;
|
||||
uint32_t count4 = (terminal->pixelWidth * terminal->pixelHeight) / 8 / 4;
|
||||
for (int i=0; i<4; i++) {
|
||||
outb(0x3c4, 2);
|
||||
outb(0x3c5, 1<<i);
|
||||
@ -405,28 +456,25 @@ static void VGAModeTerminal::bufferToVRAM(frame_struct* frame, VGAModeTerminal*
|
||||
}
|
||||
}
|
||||
|
||||
VGAModeTerminal::VGAModeTerminal(uint8_t* vga_pointer): Terminal(90, 60, 1) {
|
||||
VGAModeTerminal::VGAModeTerminal(uint8_t* vga_pointer): Terminal(0, 0, 1) {
|
||||
this->vga_pointer = vga_pointer;
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
this->planes[i] = new uint8_t[720 * 480 / 8];
|
||||
}
|
||||
|
||||
this->resize(pixelWidth / 8, pixelHeight / 8, 1);
|
||||
|
||||
unsigned char g_720x480x16[] =
|
||||
{
|
||||
/* MISC */
|
||||
0xE7,
|
||||
/* SEQ */
|
||||
0x03, 0x01, 0x08, 0x00, 0x06,
|
||||
/* CRTC */
|
||||
0x6B, 0x59, 0x5A, 0x82, 0x60, 0x8D, 0x0B, 0x3E,
|
||||
0x00, 0x40, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00,
|
||||
0xEA, 0x0C, 0xDF, 0x2D, 0x08, 0xE8, 0x05, 0xE3,
|
||||
0xFF,
|
||||
/* GC */
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x0F,
|
||||
0xFF,
|
||||
/* AC */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x01, 0x00, 0x0F, 0x00, 0x00,
|
||||
@ -480,3 +528,84 @@ VGAModeTerminal::VGAModeTerminal(uint8_t* vga_pointer): Terminal(90, 60, 1) {
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
static void BGAModeTerminal::bufferToVRAM(frame_struct* frame, BGAModeTerminal* terminal) {
|
||||
uint32_t c = terminal->pixelWidth * terminal->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*)terminal->vga_pointer)[i%16384] = ((uint32_t*)terminal->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, &BGAModeTerminal::bufferToVRAM, this);
|
||||
}
|
@ -14,23 +14,38 @@
|
||||
struct frame_struct;
|
||||
|
||||
namespace Timer {
|
||||
void register_event(uint32_t milliseconds, void(*function)(frame_struct*, void*), void* auxiliary);
|
||||
void register_event(uint32_t milliseconds, void(*function)(frame_struct*, void*), void* auxiliary, bool oneshot=false);
|
||||
}
|
||||
|
||||
enum TerminalState {
|
||||
None,
|
||||
EscapeCode,
|
||||
CSI,
|
||||
ParameterBytes,
|
||||
IntermediaryBytes,
|
||||
FinalByte,
|
||||
SGR
|
||||
};
|
||||
|
||||
class Terminal: public ReadWriter {
|
||||
private:
|
||||
virtual void update();
|
||||
virtual void update_cur();
|
||||
virtual void putchar_internal(uint32_t ptr, uint8_t c, uint8_t edata=0x07);
|
||||
virtual void putchar_internal(uint32_t ptr, uint8_t c, uint8_t edata);
|
||||
|
||||
void scroll_up();
|
||||
void scroll_up(uint32_t count=1);
|
||||
void scroll_down(uint32_t count=1);
|
||||
|
||||
void putchar(uint32_t ptr, uint8_t c, uint8_t edata=0x07);
|
||||
void putchar(uint8_t c);
|
||||
|
||||
TerminalState state = None;
|
||||
uint8_t parameterBytes[128];
|
||||
uint8_t intermediaryBytes[128];
|
||||
uint32_t parameterIndex = 0;
|
||||
uint32_t intermediaryIndex = 0;
|
||||
|
||||
protected:
|
||||
uint16_t* buffer;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t pages;
|
||||
|
||||
uint32_t cur_x;
|
||||
@ -40,7 +55,14 @@ protected:
|
||||
uint16_t* last_page_pointer;
|
||||
|
||||
bool active;
|
||||
|
||||
uint8_t edata=0x07;
|
||||
void resize(uint32_t width, uint32_t height, uint32_t pages);
|
||||
|
||||
public:
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
|
||||
Terminal(uint32_t width, uint32_t height, uint32_t pages);
|
||||
|
||||
void printf(const char* string, ...);
|
||||
@ -62,19 +84,18 @@ class TextModeTerminal : public Terminal {
|
||||
private:
|
||||
void update() override;
|
||||
void update_cur() override;
|
||||
void putchar_internal(uint32_t ptr, uint8_t c, uint8_t edata=0x07) override;
|
||||
void putchar_internal(uint32_t ptr, uint8_t c, uint8_t edata) override;
|
||||
|
||||
uint16_t* text_mode_pointer;
|
||||
public:
|
||||
TextModeTerminal(uint16_t* text_mode_pointer);
|
||||
};
|
||||
|
||||
|
||||
class VGAModeTerminal : public Terminal {
|
||||
private:
|
||||
void update() override;
|
||||
void update_cur() override;
|
||||
void putchar_internal(uint32_t ptr, uint8_t c, uint8_t edata=0x07) 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);
|
||||
@ -82,9 +103,33 @@ private:
|
||||
static void bufferToVRAM(frame_struct* frame, VGAModeTerminal* terminal);
|
||||
|
||||
public:
|
||||
uint32_t pixelWidth = 720;
|
||||
uint32_t pixelHeight = 480;
|
||||
|
||||
uint8_t* vga_pointer;
|
||||
uint8_t* planes[4];
|
||||
|
||||
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);
|
||||
|
||||
static void bufferToVRAM(frame_struct* frame, BGAModeTerminal* terminal);
|
||||
|
||||
public:
|
||||
uint32_t pixelWidth = 720;
|
||||
uint32_t pixelHeight = 480;
|
||||
|
||||
uint8_t* vga_pointer;
|
||||
uint32_t* fb;
|
||||
|
||||
BGAModeTerminal(uint8_t* vga_pointer);
|
||||
};
|
||||
#endif
|
@ -1,20 +0,0 @@
|
||||
#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);
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
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)
|
||||
}
|
||||
}
|
4
src/programs/crash/crash.c
Normal file
4
src/programs/crash/crash.c
Normal file
@ -0,0 +1,4 @@
|
||||
int main() {
|
||||
// Cause a Division by zero by trying to divide by zero.
|
||||
int x = 1 / 0;
|
||||
}
|
8
src/programs/entry.asm
Normal file
8
src/programs/entry.asm
Normal file
@ -0,0 +1,8 @@
|
||||
[BITS 32]
|
||||
|
||||
_start:
|
||||
call main
|
||||
call die
|
||||
|
||||
extern die
|
||||
extern main
|
@ -1,4 +1,4 @@
|
||||
#include "../common/common.h"
|
||||
#include "common/common.h"
|
||||
|
||||
void readline(int count, char* buffer) {
|
||||
int index = 0;
|
||||
@ -25,7 +25,9 @@ void readline(int count, char* buffer) {
|
||||
print("\n");
|
||||
}
|
||||
|
||||
int main() {
|
||||
int main(int argc, char** argv) {
|
||||
printf("Hi, I am %s, running with PID %d!\n", argv[0], getPID());
|
||||
|
||||
print("Hello, World!\n");
|
||||
char buffer[32];
|
||||
while (1) {
|
16
src/programs/timer/timer.c
Normal file
16
src/programs/timer/timer.c
Normal file
@ -0,0 +1,16 @@
|
||||
#include "common/common.h"
|
||||
|
||||
int main() {
|
||||
uint32_t crashBin = fopen("/crash.bin");
|
||||
uint32_t pid = getPID();
|
||||
while (1) {
|
||||
printf("Time Elapsed: %dms\n", getMillisecondsElapsed());
|
||||
printf("Init. Pages: %d\nRemaining Pages: %d\n", getInitPages(), getRemainingPages());
|
||||
|
||||
printf("PID 2 State: %s\n", (!getProcessState(2))?"Running":"Suspended");
|
||||
printf("I am PID %d\n", pid);
|
||||
|
||||
//exec(crashBin);
|
||||
sleep(1000);
|
||||
}
|
||||
}
|
11
src/programs/userspace.ld
Normal file
11
src/programs/userspace.ld
Normal file
@ -0,0 +1,11 @@
|
||||
OUTPUT_FORMAT(binary)
|
||||
OUTPUT_ARCH(i386:i386)
|
||||
|
||||
SECTIONS {
|
||||
. = 0x1020;
|
||||
|
||||
.text : {
|
||||
build/programs/entry.o(.text)
|
||||
build/common/common.o(.text)
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
#include "../common/common.h"
|
||||
#include "common/common.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
@ -8,15 +8,17 @@ typedef struct {
|
||||
uint32_t process;
|
||||
uint32_t stdin;
|
||||
uint32_t stdout;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
} 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];
|
||||
void scrollBuffer(procbuffer* buf) {
|
||||
for (int y=0; y<buf->height; y++)
|
||||
for (int x=0; x<buf->width; x++)
|
||||
if (y != buf->height-1)
|
||||
buf->buffer[y*buf->width+x] = buf->buffer[(y+1)*buf->width+x];
|
||||
else
|
||||
buf[y*43+x] = ' ';
|
||||
buf->buffer[y*buf->width+x] = ' ';
|
||||
}
|
||||
|
||||
void writeToBuf(char c, procbuffer* buf) {
|
||||
@ -30,22 +32,22 @@ void writeToBuf(char c, procbuffer* buf) {
|
||||
if (buf->x > 0)
|
||||
buf->x--;
|
||||
else if (buf->y > 0) {
|
||||
buf->x = 42;
|
||||
buf->x = buf->width-1;
|
||||
buf->y--;
|
||||
}
|
||||
buf->buffer[buf->y*43+buf->x] = ' ';
|
||||
buf->buffer[buf->y*buf->width+buf->x] = ' ';
|
||||
break;
|
||||
|
||||
default:
|
||||
buf->buffer[buf->y*43+buf->x++] = c;
|
||||
buf->buffer[buf->y*buf->width+buf->x++] = c;
|
||||
}
|
||||
if (buf->x == 43) {
|
||||
if (buf->x == buf->width) {
|
||||
buf->x = 0;
|
||||
buf->y++;
|
||||
}
|
||||
if (buf->y == 56) {
|
||||
if (buf->y == buf->height) {
|
||||
buf->y--;
|
||||
scrollBuffer(buf->buffer);
|
||||
scrollBuffer(buf);
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,7 +58,7 @@ void writeCountToBuf(int count, char* c, procbuffer* buf) {
|
||||
}
|
||||
|
||||
void clearBuf(procbuffer* buf) {
|
||||
for (int i=0; i<56*43;i++) {
|
||||
for (int i=0; i<buf->height*buf->width;i++) {
|
||||
buf->buffer[i] = ' ';
|
||||
}
|
||||
buf->x = 0;
|
||||
@ -69,52 +71,42 @@ void writeStrToBuf(char* c, procbuffer* b) {
|
||||
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";
|
||||
char pset[11] = "\x1b[000;000H";
|
||||
for (int i=0; i<y;i++) {
|
||||
pset[4]++;
|
||||
if (pset[4] == 0x3a) {
|
||||
pset[4] = 0x30;
|
||||
pset[3]++;
|
||||
}
|
||||
if (pset[3] == 0x3a) {
|
||||
pset[3] = 0x30;
|
||||
pset[2]++;
|
||||
}
|
||||
}
|
||||
for (int i=0; i<x;i++) {
|
||||
pset[8]++;
|
||||
if (pset[8] == 0x3a) {
|
||||
pset[8] = 0x30;
|
||||
pset[7]++;
|
||||
}
|
||||
if (pset[7] == 0x3a) {
|
||||
pset[7] = 0x30;
|
||||
pset[6]++;
|
||||
if (pset[6] == 0x3a) {
|
||||
pset[6] = 0x30;
|
||||
pset[5]++;
|
||||
}
|
||||
}
|
||||
print(pset);
|
||||
}
|
||||
|
||||
void displayBuf(procbuffer* b, int dx, int dy) {
|
||||
print("\x1b[42;36;1m");
|
||||
char pset[9] = "\x1b[000;000H";
|
||||
for (int i=0; i<b->height; i++) {
|
||||
setCurPos(dx, dy++);
|
||||
write(b->width, 0, b->buffer+(b->width*i));
|
||||
}
|
||||
}
|
||||
|
||||
void readline(int count, char* buffer) {
|
||||
int index = 0;
|
||||
char c;
|
||||
@ -159,7 +151,40 @@ bool strcmpcnt(int count, char* a, char* b) {
|
||||
return true;
|
||||
}
|
||||
|
||||
procbuffer b1;
|
||||
procbuffer b2;
|
||||
|
||||
int bufferWidth;
|
||||
|
||||
void displayBuffer1() {
|
||||
char c[128];
|
||||
int succ=0;
|
||||
while (1) {
|
||||
if (b1.process)
|
||||
if (succ = read(128, b1.stdout, c))
|
||||
writeCountToBuf(succ, c, &b1);
|
||||
displayBuf(&b1, 2, 2);
|
||||
}
|
||||
}
|
||||
|
||||
void displayBuffer2() {
|
||||
char c[128];
|
||||
int succ=0;
|
||||
while (1) {
|
||||
if (b2.process)
|
||||
if (succ = read(128, b2.stdout, c))
|
||||
writeCountToBuf(succ, c, &b2);
|
||||
displayBuf(&b2, bufferWidth+4, 2);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
int width = getCurrentTerminalWidth();
|
||||
int height = getCurrentTerminalHeight();
|
||||
|
||||
bufferWidth = (width - 4) / 2;
|
||||
int bufferHeight = (height - 4);
|
||||
|
||||
bindToKeyboard();
|
||||
|
||||
char space = ' ';
|
||||
@ -169,48 +194,65 @@ int main() {
|
||||
for (int i=0; i < 1000; i++)
|
||||
write(1, 0, &space);
|
||||
print("\x1b[1;1H");
|
||||
print("\x1b[45;33;1m");
|
||||
|
||||
char* mid = "+ ++ +";
|
||||
char* bottom = "+ +";
|
||||
for (int i=0; i<90;i++)
|
||||
for (int i=0; i<width;i++)
|
||||
write(1, 0, &plus);
|
||||
for (int i=0; i<56;i++)
|
||||
write(90, 0, mid);
|
||||
for (int i=0; i<90;i++)
|
||||
for (int i=0; i<bufferHeight;i++) {
|
||||
write(1, 0, &plus);
|
||||
write(90, 0, bottom);
|
||||
for (int i=0; i<90;i++)
|
||||
for (int j=0; j<bufferWidth; j++)
|
||||
write(1, 0, &space);
|
||||
write(1, 0, &plus);
|
||||
write(1, 0, &plus);
|
||||
for (int j=0; j<bufferWidth; j++)
|
||||
write(1, 0, &space);
|
||||
write(1, 0, &plus);
|
||||
}
|
||||
for (int i=0; i<width;i++)
|
||||
write(1, 0, &plus);
|
||||
write(1, 0, &plus);
|
||||
for (int i=0; i< width - 2; i++)
|
||||
write(1, 0, &space);
|
||||
write(1, 0, &plus);
|
||||
for (int i=0; i<width;i++)
|
||||
write(1, 0, &plus);
|
||||
|
||||
uint32_t program = fopen("hello.bin");
|
||||
uint32_t p1 = fork(program);
|
||||
uint32_t program = fopen("/hello.bin");
|
||||
uint32_t p1 = exec(program);
|
||||
uint32_t p1out = bindStdout(p1);
|
||||
uint32_t p1in = bindStdin(p1);
|
||||
fclose(program);
|
||||
program = fopen("hello.bin");
|
||||
uint32_t p2 = fork(program);
|
||||
program = fopen("/timer.bin");
|
||||
uint32_t p2 = exec(program);
|
||||
uint32_t p2out = bindStdout(p2);
|
||||
uint32_t p2in = bindStdin(p2);
|
||||
fclose(program);
|
||||
|
||||
procbuffer b1 = {
|
||||
.buffer = localalloc(56 * 43),
|
||||
b1 = (procbuffer) {
|
||||
.buffer = malloc(bufferWidth * bufferHeight),
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.process = p1,
|
||||
.stdin = p1in,
|
||||
.stdout = p1out
|
||||
.stdout = p1out,
|
||||
.width = bufferWidth,
|
||||
.height = bufferHeight
|
||||
};
|
||||
|
||||
procbuffer b2 = {
|
||||
.buffer = localalloc(56 * 43),
|
||||
b2 = (procbuffer) {
|
||||
.buffer = malloc(bufferWidth * bufferHeight),
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.process = p2,
|
||||
.stdin = p2in,
|
||||
.stdout = p2out
|
||||
.stdout = p2out,
|
||||
.width = bufferWidth,
|
||||
.height = bufferHeight
|
||||
};
|
||||
|
||||
spawnThread(&displayBuffer1);
|
||||
spawnThread(&displayBuffer2);
|
||||
|
||||
procbuffer* selectedBuf = &b1;
|
||||
|
||||
writeStrToBuf("XoSH (XOS SHell) v0.0.1\nPress : to use commands.\n :help for help.\n", &b1);
|
||||
@ -218,18 +260,16 @@ int main() {
|
||||
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("\x1b[45;33;1m");
|
||||
setCurPos(2, height-1);
|
||||
print(": ");
|
||||
print("\x1b[59;3H");
|
||||
setCurPos(3, height-1);
|
||||
readline(32, buf);
|
||||
if (strcmpcnt(6, buf, "switch")) {
|
||||
if (selectedBuf == &b1) {
|
||||
@ -247,6 +287,13 @@ int main() {
|
||||
writeStrToBuf(" Kills the current process\n", selectedBuf);
|
||||
writeStrToBuf(":load <filename>\n", selectedBuf);
|
||||
writeStrToBuf(" Loads and executes the program <filename>\n", selectedBuf);
|
||||
writeStrToBuf(":ls <path>\n", selectedBuf);
|
||||
writeStrToBuf(" Lists the files in directory <path>\n", selectedBuf);
|
||||
writeStrToBuf(":clear\n", selectedBuf);
|
||||
writeStrToBuf(" Clears the buffer\n", selectedBuf);
|
||||
writeStrToBuf(":type <filename>\n", selectedBuf);
|
||||
writeStrToBuf(" Writes out the contents of the file <filename>\n", selectedBuf);
|
||||
|
||||
writeStrToBuf("--------\n", selectedBuf);
|
||||
} else if (strcmpcnt(4, buf, "kill")) {
|
||||
if (selectedBuf->process) {
|
||||
@ -255,29 +302,39 @@ int main() {
|
||||
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->process = exec(fh);
|
||||
selectedBuf->stdout = bindStdout(selectedBuf->process);
|
||||
selectedBuf->stdin = bindStdin(selectedBuf->process);
|
||||
fclose(fh);
|
||||
}
|
||||
} else if (strcmpcnt(2, buf, "ls")) {
|
||||
uint32_t size = getDentsSize((char*)(buf+3));
|
||||
FSDirectoryListing* listing = (FSDirectoryListing*)malloc(size);
|
||||
getDents((char*)(buf+3), listing);
|
||||
writeStrToBuf("\n", selectedBuf);
|
||||
for (int i=0; i<listing->count; i++) {
|
||||
writeCountToBuf(listing->entries[i].path.length, listing->entries[i].path.path, selectedBuf);
|
||||
writeStrToBuf("\n", selectedBuf);
|
||||
}
|
||||
free(listing);
|
||||
} else if (strcmpcnt(5, buf, "clear")) {
|
||||
clearBuf(selectedBuf);
|
||||
} else if (strcmpcnt(4, buf, "type")) {
|
||||
uint32_t f = fopen(buf+5);
|
||||
char c;
|
||||
while (read(1, f, &c))
|
||||
writeCountToBuf(1, &c, selectedBuf);
|
||||
fclose(f);
|
||||
}
|
||||
} else {
|
||||
if (selectedBuf->process)
|
||||
write(1, selectedBuf->stdin, c);
|
||||
}
|
||||
}
|
||||
|
||||
displayBuf(&b1, 2, 2);
|
||||
displayBuf(&b2, 47, 2);
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
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