Compare commits

..

18 Commits
core ... dev

Author SHA1 Message Date
28138a54e2
Merge branch 'dev' of ssh://xnopyt.com:222/xnoe/xnoe-os into dev 2025-01-08 19:25:23 +00:00
fafae757e1
Miscellaneous changes and fixed (I think?) virtual 8086 mode 2025-01-08 18:46:58 +00:00
5a70976f5d
Various additions 2024-04-14 00:50:21 +01:00
b00f6d6217
Added multiple threads per process 2022-06-18 17:45:16 +01:00
f3b1bfc5ef
Added VFS, updated DevFS, Added SysFS 2022-06-18 15:41:32 +01:00
437c78d374
Fixed sleep 2022-06-18 15:12:20 +01:00
fdb77277a7
Renamed Maybe to maybe. Moved tracking of filehandlers to be per-process rather than global. Various improvements to code. 2022-06-18 11:42:09 +01:00
da5fc52afe
Updated the KernelInformationStruct, added BGA (Bochs Graphics Extensions) mode termimal, added new system calls to get terminal width. Updated world.bin to calculate sizes. Fixed a bug where GetExhaustive would crash when given a completely null path. Started work on V86 for VBE support. 2022-05-16 09:57:09 +01:00
6339b3e4bd
Added spinlocks 2022-04-15 21:10:10 +01:00
dc2fe698a3
Added oneshot timer functionality. Added sleep function. Added proper tracking of physical pages allocated. Made the 0th page invalid. Fixed a 4KiB memory leak when destroying processes. Fixed scrolling colour in terminal.cpp 2022-04-15 16:15:51 +01:00
0fc40ad5e4
Add system calls for more file system related functionality. Add ls command to world.c. Remove and reorganise certain source code files. Update terminal to no longer have two copies of ANSI escape code handling between write and printf. Massively simplify my printf function. Combine io and ioports. 2022-04-12 03:42:13 +01:00
8f4382793c
Fixed spelling mistake 2022-04-09 00:31:08 +01:00
bb69d6b713
Update how syscalls accept arguments in registers, change how syscalls are defined in common.c and common.h 2022-04-08 18:00:56 +01:00
7e5f20ef66
Added sleep syscall 2022-04-08 02:01:25 +01:00
c2f857fc88
Removed extra directories 2022-04-08 00:49:26 +01:00
edd6e82c2c
Remove old boot_stage2 directory 2022-04-06 20:59:33 +01:00
a0d0454e32
Moved to a new Filesystem, ATA and FAT16 driver. 2022-04-06 14:46:47 +01:00
ed34174d68
Rename boot_stage2 to bootstage2 2022-03-04 20:25:17 +00:00
92 changed files with 3615 additions and 1926 deletions

5
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,5 @@
{
"files.associations": {
"random": "cpp"
}
}

View File

@ -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 $^

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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];
}
}

View File

@ -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

View File

@ -11,8 +11,8 @@
uint16_t identify_result[256];
uint32_t total_28_lbas = 0;
uint8_t* rootDirEntries = 0x1000000;
uint16_t* FAT1 = 0x1002000;
uint8_t* rootDirEntries = (uint8_t*)0x1000000;
uint16_t* FAT1 = (uint16_t*)0x1002000;
uint16_t countReserved;
uint8_t countFATs;
@ -60,7 +60,7 @@ void init_atapio() {
// We've initialised now, let's load the FAT and RootDirEntries.
read_sectors(sectorsPerFAT * countFATs + countReserved, countRDEs / 16, rootDirEntries);
read_sectors(countReserved, sectorsPerFAT, FAT1);
read_sectors(countReserved, sectorsPerFAT, (uint8_t*)FAT1);
}
void read_sector(uint32_t address, uint8_t* buffer) {
@ -95,7 +95,7 @@ uint16_t file_exists(char* filename) {
for (int i=0; i<countRDEs; i++) {
bool found = strcmp(rootDirEntries+(i*32), filename, 11);
if (found) {
uint16_t* correctEntry = (rootDirEntries+(i*32));
uint16_t* correctEntry = (uint16_t*)(rootDirEntries+(i*32));
return correctEntry[13];
}
}

View File

@ -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)
}
}

View File

@ -1,5 +1,4 @@
#include "atapio.h"
#include "screenstuff.h"
#include "paging.h"
typedef struct {
@ -11,7 +10,7 @@ typedef struct {
uint32_t acpi3_extended;
}__attribute__((packed)) e820entry;
uint8_t* bitmap = 0x100000;
uint8_t* bitmap = (uint8_t*)0x100000;
void set_bit(uint32_t offset, uint8_t* buffer) {
uint32_t index = offset / 8;
@ -47,39 +46,30 @@ 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
e820entry* e820_entries = 0x20000;
e820entry* e820_entries = (e820entry*)0x20000;
// 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,18 +86,18 @@ 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);
}
}
mark_unavailble(bitmap, 0x20000, bitmap);
mark_unavailble((uint32_t)bitmap, 0x20000, bitmap);
mark_unavailble(0, 0xFFFFF, bitmap);
// Page Directory
PDE* kernel_page_directory = bitmap + 0x20000;
PDE* kernel_page_directory = (PDE*)(bitmap + 0x20000);
// Clear the PD
memset((uint8_t*)kernel_page_directory, 4096, 0);
@ -120,7 +110,7 @@ void main() {
((uint32_t*)0x521000)[i] = 0x121000 + 0x1000*i;
}
PTE** kernel_page_tables = 0x521000;
PTE** kernel_page_tables = (PTE**)0x521000;
for (int i = 0; i < 1023; i++) {
kernel_page_directory[i] = (PDE){
@ -140,15 +130,15 @@ void main() {
}
// Mark unavailable bitmap to 0x522000
mark_unavailble(bitmap, 0x4000000, bitmap);
mark_unavailble((uint32_t)bitmap, 0x4000000, bitmap);
// Now we want to map some stuff.
// 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.
uint8_t* kernel_location = (uint8_t*)0x542000; // Just load it at 0x524000 for now
mark_unavailble((uint32_t)kernel_location, 0x20000, bitmap); // Just treat the kernel as not growing beyond 128k for now.
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((uint32_t)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
@ -158,12 +148,12 @@ void main() {
mark_unavailble(0xa0000, 0x20000, bitmap);
uint8_t* vm_bitmap = 0x522000;
mark_unavailble(vm_bitmap, 0x20000, bitmap);
uint8_t* vm_bitmap = (uint8_t*)0x522000;
mark_unavailble((uint32_t)vm_bitmap, 0x20000, bitmap);
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 = (PDE*)0xc0100000,
.page_directory_phys_addr = (uint32_t)kernel_page_directory,
.page_directory_phys_offset = 0xc0100000 - (uint32_t)kernel_page_directory,
.page_bitmap_phys = 0xc0600000,
.page_bitmap_virt = 0xc0620000,
.stack_ptr = 0xc1000000 + 16*0x1000 - sizeof(KernelInformationStruct) - 4,
.vga_addr = 0xc07a0000,
.remainingPages = pages
};
((void(*)(KernelInformationStruct))0xc0000000)(kstruct);
}

View File

@ -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);

View File

@ -34,4 +34,5 @@ typedef struct {
void map_4k_phys_to_virt(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables);
void map_many_4k_phys_to_virt(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables, uint32_t count);
void map_many_4k_phys_to_virt_pl3(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables, uint32_t count);
#endif

11
src/bootstage2/strings.c Normal file
View 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
View File

@ -0,0 +1,8 @@
#ifndef STRINGS_H
#define STRINGS_H
#include <stdbool.h>
bool strcmp(char* a, char* b, int max);
#endif

View File

@ -3,6 +3,7 @@
_start:
mov ax, 10h
mov ds, ax
mov es, ax
mov ss, ax
mov esp, 90000h

View File

@ -1,5 +1,81 @@
#include "common.h"
#define syscall_hdlr_0(a, b, c) \
a b() { \
asm volatile("mov $" c ", %%eax; int $0x80" : : :); \
}
#define syscall_hdlr_1(a, b, c, d, e) \
a b(d e) { \
asm volatile("mov $" c ", %%eax; mov %0, %%ebx; int $0x80" : : "m" (e) : "ebx"); \
}
#define syscall_hdlr_2(a, b, c, d, e, f, g) \
a b(d e, f g) { \
asm volatile("mov $" c ", %%eax; mov %0, %%ebx; mov %1, %%ecx; int $0x80" : : "m" (e), "m" (g) : "ebx", "ecx"); \
}
#define syscall_hdlr_3(a, b, c, d, e, f, g, h, i) \
a b(d e, f g, h i) { \
asm volatile("mov $" c ", %%eax; mov %0, %%ebx; mov %1, %%ecx; mov %2, %%edx; int $0x80" : : "m" (e), "m" (g), "m" (i) : "ebx", "ecx", "edx"); \
}
#include "syscalls.h"
char** environ = 0;
uint32_t strcmpc(char* a, char* b, char c) {
for (int i=0; a[i] && b[i]; i++) {
if (a[i] == c)
return i;
}
return 0;
}
void __setup(uint32_t argc, char** argv, char** envp) {
environ = envp;
}
char* getenv(char* key) {
for (int i=0; environ[i]; i++) {
uint32_t pos;
if (pos = strcmpc(environ[i], key, '=')) {
return key+pos+1;
}
}
return 0;
}
void setenv(char* key, char* value) {
uint32_t environ_count = 0;
for (int i=0; environ[i]; i++)
environ_count += 1;
char** new_environ = (char**)malloc((environ_count+2)*sizeof(char*));
for (int i=0; i<environ_count; i++)
new_environ[i] = environ[i];
uint32_t key_size = strlen(key);
uint32_t value_size = strlen(value);
char* new_entry = (char*)malloc(key_size + value_size + 2);
memcpy(new_entry, key, key_size);
new_entry[key_size] = '=';
memcpy(new_entry+key_size+1, value, value_size);
new_entry[key_size+1+value_size] = 0;
new_environ[environ_count] = new_entry;
new_environ[environ_count+1] = 0;
environ = new_environ;
}
uint32_t strlen(char* s) {
uint32_t i=0;
while (s[i]) i++;
return i;
}
bool strcmp(char* a, char* b) {
for (int i=0; a[i] && b[i]; i++)
if (a[i] != b[i])
return false;
return true;
}
void print(char* string) {
char* c = string;
int i=0;
@ -8,54 +84,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 +115,96 @@ int int_to_hex(unsigned int number, char* string_buffer) {
}
return (index+1);
}
bool isnum(char c) {
return c >= 0x30 && c <= 0x39;
}
void printf(const char* string, ...) {
va_list ptr;
va_start(ptr, string);
int index = 0;
char current;
while (current=string[index++]) {
if (current == '%') {
uint32_t width = 0;
bool lp = false;
if (string[index] == '.') {
lp = true;
index++;
} else {
while (isnum(string[index])) {
width *= 10;
width += string[index] - 0x30;
index++;
}
}
int type = string[index++];
int offset;
switch (type) {
case 'd': {
char decimal_buffer[11];
offset = int_to_decimal(va_arg(ptr, int), decimal_buffer);
print(decimal_buffer + offset);
break;
}
case 'x': {
char hex_buffer[8];
offset = int_to_hex(va_arg(ptr, int), hex_buffer);
print(hex_buffer);
break;
}
case 's': {
if (width) {
char s[width+1];
s[width] = 0;
memcpy(s, va_arg(ptr, const char*), width);
print(s);
} else if (lp) {
int width = va_arg(ptr, int);
char s[width+1];
s[width] = 0;
memcpy(s, va_arg(ptr, const char*), width);
print(s);
} else {
print(va_arg(ptr, const char*));
}
break;
}
case 'c': {
int promoted = va_arg(ptr, int);
char charred = promoted;
write(1, 0, &charred);
break;
}
}
continue;
}
write(1, 0, &current);
}
va_end(ptr);
}
void memset(void* ptr, char c, uint32_t count) {
for (int i=0; i<count; i++) {
((char*)ptr)[i] = c;
}
}
void memcpy(void* dst, void* src, uint32_t count) {
for (int i=0; i<count; i++)
((char*)dst)[i] = ((char*)src)[i];
}
uint32_t exec(uint32_t fh) {
uint8_t* zero = 0;
return execve(fh, &zero, (uint8_t**)environ);
}
uint32_t execv(uint32_t fh, char** argv) {
return execve(fh, (uint8_t**)argv, (uint8_t**)environ);
}

View File

@ -2,28 +2,57 @@
#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"
char* getenv(char* key);
void setenv(char* key, char* value);
uint32_t strlen(char* s);
bool strcmp(char* a, char* b);
void memset(void* ptr, char c, uint32_t count);
void memcpy(void* dst, void* src, uint32_t count);
void print(char* string);
void 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, ...);
uint32_t exec(uint32_t fh);
uint32_t execv(uint32_t fh, char** argv);
#endif

31
src/common/syscalls.h Normal file
View 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_3(uint32_t, execve, "7", uint32_t, fh, uint8_t**, argv, uint8_t**, envp);
syscall_hdlr_0(uint32_t, getPID, "8");
syscall_hdlr_1(void, die, "9", uint32_t, exit);
syscall_hdlr_3(int, read, "10", uint32_t, count, uint32_t, filehandler, uint8_t*, buffer);
syscall_hdlr_3(int, write, "11", uint32_t, count, uint32_t, filehandler, const uint8_t*, buffer);
syscall_hdlr_0(void, bindToKeyboard, "12");
syscall_hdlr_1(uint32_t, bindStdout, "13", uint32_t, PID);
syscall_hdlr_1(uint32_t, bindStdin, "14", uint32_t, PID);
syscall_hdlr_1(uint32_t, fopen, "15", char*, filename);
syscall_hdlr_1(void, fclose, "16", uint32_t, filehandler);
syscall_hdlr_1(void, kill, "17", uint32_t, PID);
syscall_hdlr_1(void, sleep, "18", uint32_t, time);
syscall_hdlr_0(uint32_t, getRemainingPages, "19");
syscall_hdlr_0(uint32_t, getInitPages, "20");
syscall_hdlr_0(uint32_t, getCurrentTerminalWidth, "21");
syscall_hdlr_0(uint32_t, getCurrentTerminalHeight, "22");
syscall_hdlr_1(uint32_t, getProcessState, "23", uint32_t, PID);
syscall_hdlr_1(void, spawnThread, "24", uint32_t, functionPointer);
syscall_hdlr_0(uint32_t, fork, "25");
syscall_hdlr_1(bool, programRunning, "26", uint32_t, pid);

View File

@ -1,40 +0,0 @@
#include "../common/common.h"
void readline(int count, char* buffer) {
int index = 0;
char c;
while (index < count) {
if (read(1, 1, &c)) {
if (c == '\n')
break;
if (c == '\b') {
if (index == 0)
continue;
else {
index--;
buffer[index] = 0;
write(1, 0, &c);
continue;
}
}
buffer[index++] = c;
write(1, 0, &c);
}
}
print("\n");
}
int main() {
print("Hello, World!\n");
char buffer[32];
while (1) {
for (int i=0; i<32; i++)
buffer[i] = 0;
print(">>> ");
readline(32, buffer);
print("You said: ");
print(buffer);
print("\n\n");
}
}

View File

@ -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)
}
}

View File

@ -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;

View File

@ -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
View 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 bus):
ATA(bus) {
this->currentPosition = 0;
}
uint32_t ATAReadWriter::read(uint32_t count, uint8_t* buffer) {
driveLock.lock();
uint32_t remainingBytes = count;
uint32_t inThisSector = currentPosition % 512;
uint32_t index=0;
uint32_t c=0;
ATARead(currentPosition / 512, sectorBuffer);
while (remainingBytes) {
if (currentPosition >= diskSize)
break;
buffer[index++] = sectorBuffer[inThisSector++];
remainingBytes--;
currentPosition++;
if (inThisSector == 512) {
ATARead(currentPosition / 512, sectorBuffer);
inThisSector = 0;
}
c++;
}
driveLock.unlock();
return c;
}
uint32_t ATAReadWriter::write(uint32_t count, uint8_t* buffer) {
driveLock.lock();
uint32_t remainingBytes = count;
uint32_t inThisSector = currentPosition % 512;
uint32_t index=0;
uint32_t c=0;
ATARead(currentPosition / 512, sectorBuffer);
while (remainingBytes) {
if (currentPosition >= diskSize)
break;
sectorBuffer[inThisSector++] = buffer[index++];
remainingBytes--;
currentPosition++;
if (inThisSector == 512) {
ATAWrite((currentPosition / 512) - 1, sectorBuffer);
ATARead(currentPosition / 512, sectorBuffer);
inThisSector = 0;
}
c++;
}
// Perform a final write to ensure that we've written everything to disk.
ATAWrite((currentPosition / 512), sectorBuffer);
driveLock.unlock();
return c;
}
uint32_t ATAReadWriter::size() {
return this->diskSize;
}
uint32_t ATAReadWriter::seek(uint32_t position) {
this->currentPosition = position;
return position;
}

110
src/kernel/ata.h Normal file
View 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 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

View File

@ -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;
}

View File

@ -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

View File

@ -0,0 +1,71 @@
#ifndef DYNARRAY_H
#define DYNARRAY_H
#include "../global.h"
#include "maybe.h"
#include "../spinlock.h"
namespace xnoe {
template<typename T>
class dynarray {
private:
uint32_t size = 128;
T* buffer;
uint32_t index = 0;
uint32_t start_index = 0;
Spinlock lock;
public:
dynarray(uint32_t start_index=0) {
this->buffer = new T[size];
this->index = this->start_index = start_index;
}
dynarray(dynarray* d) {
this->size = d->size;
this->buffer = new T[size];
this->index = d->index;
this->start_index = d->start_index;
memcpy((uint8_t*)this->buffer, (uint8_t*)d->buffer, sizeof(T)*d->size);
}
void push(T t) {
if (index == size) {
lock.lock();
uint32_t old_size = size;
size *= 2;
T* buffer_tmp = new T[size];
memcpy((uint8_t*)buffer_tmp, (uint8_t*)buffer, sizeof(T)*old_size);
delete buffer;
buffer = buffer_tmp;
lock.unlock();
}
buffer[index++] = t;
}
uint32_t length() {
return index;
}
xnoe::maybe<T> pop() {
if (index == start_index)
return xnoe::maybe<T>();
return xnoe::maybe<T>(buffer[--index]);
}
xnoe::maybe<T> get(uint32_t i) {
if (i>size)
return xnoe::maybe<T>();
return xnoe::maybe<T>(buffer[i]);
}
void set(uint32_t i, T t) {
if (i>size)
return;
buffer[i] = t;
}
};
}
#endif

View File

@ -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) {
@ -60,11 +59,12 @@ namespace xnoe {
xnoe::linkedlistelem<xnoe::tuple<key, value>>* current = list->start;
if (current) {
while (current) {
xnoe::linkedlistelem<xnoe::tuple<key, value>>* next = current->next;
if (xnoe::get<0>(current->elem) == k) {
list->remove(current);
delete current;
}
current = current->next;
current = next;
}
}
}

View File

@ -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();
}
};
}

View File

@ -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;
}

View File

@ -1,7 +1,6 @@
[BITS 32]
_start:
mov esp, 0xc100a000
jmp main
extern main

View File

@ -0,0 +1,5 @@
#include "devfs.h"
DevFS::DevFS() {
addEntry(createPathFromString("ata"), [](){return new ATAReadWriter(0);});
}

View 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

View 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 firstCluster, uint32_t sizeBytes, FAT16FS* backingFS) {
this->firstCluster = firstCluster;
this->sizeBytes = sizeBytes;
this->currentPosition = 0;
this->backingFS = backingFS;
this->clusterSize = 512 * (uint32_t)(*this->backingFS->sectorsPerCluster);
}
uint32_t FAT16FileReadWriter::read(uint32_t count, uint8_t* buffer) {
//uint8_t* clusterBuffer = new uint8_t[this->clusterSize];
uint8_t clusterBuffer[this->clusterSize];
uint32_t clusterToRead = offsetBytesToCluster(this->currentPosition);
uint32_t sectorToRead = this->backingFS->clusterToSector(clusterToRead);
this->backingFS->backingDevice->seek(sectorToRead * this->clusterSize);
this->backingFS->backingDevice->read(this->clusterSize, clusterBuffer);
uint32_t currentClusterIndex = this->currentPosition % this->clusterSize;
if (this->currentPosition >= this->sizeBytes)
return 0;
uint32_t remaining = count;
uint32_t index = 0;
while (remaining) {
if (currentClusterIndex == this->clusterSize) {
clusterToRead = this->backingFS->FAT1[clusterToRead];
if (clusterToRead == 0xffff)
break;
sectorToRead = this->backingFS->clusterToSector(clusterToRead);
this->backingFS->backingDevice->seek(sectorToRead * this->clusterSize);
this->backingFS->backingDevice->read(this->clusterSize, clusterBuffer);
currentClusterIndex = 0;
}
buffer[index++] = clusterBuffer[currentClusterIndex++];
remaining--;
this->currentPosition++;
}
//delete[] clusterBuffer;
return index;
}
uint32_t FAT16FileReadWriter::write(uint32_t count, uint8_t* buffer) {return;}
uint32_t FAT16FileReadWriter::size() {
return this->sizeBytes;
}
uint32_t FAT16FileReadWriter::seek(uint32_t position) {
if (position < this->sizeBytes) {
this->currentPosition = position;
return position;
}
return 0;
}
char safeUppercase(char c) {
switch (c) {
case 'a'...'z':
return c & ~32;
default:
return c;
}
}
void FAT16FS::pathEntryTo83(PathEntry pe, char* buffer) {
uint32_t maxSize = pe.length;
uint8_t* data = pe.path;
uint32_t readIndex=0;
uint32_t writeIndex=0;
while (writeIndex<11 && readIndex < maxSize) {
char c;
if ((c=data[readIndex++]) == '.') {
writeIndex = 8;
continue;
}
buffer[writeIndex++] = safeUppercase(c);
}
}
uint32_t FAT16FS::clusterToSector(uint32_t cluster) {
return (cluster * (uint32_t)(*this->sectorsPerCluster)) + (*sectorsPerFAT * *countFATs) + (*countRDEs / 16) + (*countReserved - 1) - 1;
}
void FAT16FS::load_file(uint32_t location, uint8_t* destination) {
int offset = 0;
bool loaded = false;
while (!loaded) {
uint16_t fromSector = clusterToSector(location);
this->backingDevice->seek(fromSector * 512 * *this->sectorsPerCluster);
this->backingDevice->read(512 * *this->sectorsPerCluster, destination+offset);
offset += 512 * *this->sectorsPerCluster;
location = FAT1[location++];
if (location == 0xffff)
loaded = true;
}
}
uint32_t FAT16FS::calc_size(uint32_t location) {
int offset = 0;
bool loaded = false;
while (!loaded) {
uint16_t fromSector = clusterToSector(location);
offset += 512 * *this->sectorsPerCluster;
location = FAT1[location++];
if (location == 0xffff)
loaded = true;
}
return offset;
}
xnoe::tuple<DirectoryEntry*, uint32_t, bool> FAT16FS::getDirectoryEntry(Path p) {
PathElement* current = p.start;
DirectoryEntry* currentDirectory = new DirectoryEntry[*countRDEs];
for (int i=0; i < *countRDEs; i++)
currentDirectory[i] = rootDirEntries[i];
uint32_t count = *countRDEs;
if (!current)
return xnoe::tuple<DirectoryEntry*, uint32_t, bool>(currentDirectory, count, true);
escape_for:
while (current != p.end) {
char name83[12] = " ";
pathEntryTo83(current->elem, name83);
for (int i=0; i < count; i++) {
if (strcmp(currentDirectory[i].name, name83, 11)) {
DirectoryEntry found = currentDirectory[i];
if (!(found.directory))
return xnoe::tuple<DirectoryEntry*, uint32_t, bool>(currentDirectory, count, true);
delete currentDirectory;
uint32_t sizeBytes = calc_size(found.firstClusterLow);
currentDirectory = (DirectoryEntry*)(new uint8_t[sizeBytes]);
load_file(found.firstClusterLow, (uint8_t*)currentDirectory);
i=0;
count = sizeBytes / sizeof(DirectoryEntry);
current = current->next;
goto escape_for;
}
}
return xnoe::tuple<DirectoryEntry*, uint32_t, bool>(currentDirectory, 0, false);
}
return xnoe::tuple<DirectoryEntry*, uint32_t, bool>(currentDirectory, count, true);
}
xnoe::tuple<DirectoryEntry*, uint32_t, bool> FAT16FS::getDirectoryEntryFull(Path p) {
PathElement* current = p.start;
DirectoryEntry* currentDirectory = new DirectoryEntry[*countRDEs];
for (int i=0; i < *countRDEs; i++)
currentDirectory[i] = rootDirEntries[i];
uint32_t count = *countRDEs;
if (!current)
return xnoe::tuple<DirectoryEntry*, uint32_t, bool>(currentDirectory, count, true);
escape_for:
while (current) {
char name83[12] = " ";
pathEntryTo83(current->elem, name83);
for (int i=0; i < count; i++) {
if (strcmp(currentDirectory[i].name, name83, 11)) {
DirectoryEntry found = currentDirectory[i];
if (!(found.directory))
return xnoe::tuple<DirectoryEntry*, uint32_t, bool>(currentDirectory, count, true);
delete currentDirectory;
uint32_t sizeBytes = calc_size(found.firstClusterLow);
currentDirectory = (DirectoryEntry*)(new uint8_t[sizeBytes]);
load_file(found.firstClusterLow, (uint8_t*)currentDirectory);
i=0;
count = sizeBytes / sizeof(DirectoryEntry);
current = current->next;
goto escape_for;
}
}
return xnoe::tuple<DirectoryEntry*, uint32_t, bool>(currentDirectory, 0, false);
}
return xnoe::tuple<DirectoryEntry*, uint32_t, bool>(currentDirectory, count, true);
}
FAT16FS::FAT16FS(ReadWriter* disk) {
this->backingDevice = disk;
this->backingDevice->seek(0);
this->backingDevice->read(512, sectorOne);
this->rootDirEntries = new DirectoryEntry[*countRDEs];
this->backingDevice->seek(((*sectorsPerFAT) * (*countFATs) + (*countReserved)) * 512);
this->backingDevice->read((*countRDEs) * sizeof(DirectoryEntry), (uint8_t*)this->rootDirEntries);
this->FAT1 = new uint16_t[(*sectorsPerFAT) * 256];
this->backingDevice->seek((*countReserved) * 512);
this->backingDevice->read((*sectorsPerFAT) * 512, (uint8_t*)FAT1);
}
bool FAT16FS::exists(Path p) {
xnoe::tuple<DirectoryEntry*, uint32_t, bool> directory = getDirectoryEntry(p);
if (!xnoe::get<2>(directory))
return false;
bool found = false;
DirectoryEntry* directoryEntries = xnoe::get<0>(directory);
uint32_t count = xnoe::get<1>(directory);
PathElement* end = p.end;
if (!end)
return false;
char name83[12] = " ";
name83[11] = 0;
pathEntryTo83(end->elem, name83);
for (int i=0; i<count; i++) {
if (strcmp(directoryEntries[i].name, name83, 11)) {
found = true;
break;
}
}
delete directoryEntries;
return found;
}
FSType FAT16FS::type(Path p) {
xnoe::tuple<DirectoryEntry*, uint32_t, bool> directory = getDirectoryEntry(p);
if (!xnoe::get<2>(directory))
return NoExist;
FSType found = NoExist;
DirectoryEntry* directoryEntries = xnoe::get<0>(directory);
uint32_t count = xnoe::get<1>(directory);
PathElement* end = p.end;
if (!end)
return NoExist;
char name83[12] = " ";
pathEntryTo83(end->elem, name83);
for (int i=0; i<count; i++) {
if (strcmp(directoryEntries[i].name, name83, 11)) {
if (directoryEntries[i].directory)
found = Directory;
else
found = File;
}
}
delete directoryEntries;
return found;
}
ReadWriter* FAT16FS::open(Path p) {
xnoe::tuple<DirectoryEntry*, uint32_t, bool> directory = getDirectoryEntry(p);
if (!xnoe::get<2>(directory))
return 0;
DirectoryEntry* directoryEntries = xnoe::get<0>(directory);
uint32_t count = xnoe::get<1>(directory);
PathElement* end = p.end;
if (!end)
return 0;
uint32_t written=0;
char name83[12] = " ";
name83[11] = 0;
pathEntryTo83(end->elem, name83);
for (int i=0; i<count; i++) {
if (strcmp(directoryEntries[i].name, name83, 11)) {
if (!directoryEntries[i].directory)
return new FAT16FileReadWriter(((uint32_t)directoryEntries[i].firstClusterHigh << 16) | directoryEntries[i].firstClusterLow, directoryEntries[i].size, this);
}
}
delete directoryEntries;
return 0;
}
PathEntry name83ToPathEntry(char* name83, char* text) {
uint32_t mainLength = 8;
uint32_t index = 7;
while (name83[index] == ' ' && index--)
mainLength--;
uint32_t extLength = 3;
index = 10;
while (name83[index] == ' ' && index-- > 7)
extLength--;
memcpy(text, name83, mainLength);
if (name83[8] != ' ') {
text[mainLength] = '.';
memcpy(text+mainLength+1, name83+8, extLength);
}
text[mainLength+extLength+1] = 0;
return PathEntry{mainLength+extLength+1, text};
}
uint32_t getRealCount(DirectoryEntry* directoryEntries, uint32_t c) {
uint32_t r = 0;
for (int i = 0; i < c; i++) {
if (directoryEntries[i].name[0] != 0 && directoryEntries[i].name[0] != 0xE5 && !directoryEntries[i].volumeid)
r++;
}
return r;
}
uint32_t FAT16FS::getDentsSize(Path p) {
xnoe::tuple<DirectoryEntry*, uint32_t, bool> directory = getDirectoryEntryFull(p);
DirectoryEntry* directoryEntries = xnoe::get<0>(directory);
if (!xnoe::get<2>(directory)) {
delete directoryEntries;
return 0;
}
uint32_t found = 0;
uint32_t count = xnoe::get<1>(directory);
found += sizeof(FSDirectoryListing);
for (int i=0; i<count; i++) {
if (directoryEntries[i].name[0] != 0 && directoryEntries[i].name[0] != 0xE5 && !directoryEntries[i].volumeid) {
found += sizeof(FSDirectoryEntry);
found += 13;
}
}
delete directoryEntries;
return found;
}
void FAT16FS::getDents(Path p, FSDirectoryListing* buffer) {
xnoe::tuple<DirectoryEntry*, uint32_t, bool> directory = getDirectoryEntryFull(p);
DirectoryEntry* directoryEntries = xnoe::get<0>(directory);
if (!xnoe::get<2>(directory)) {
delete directoryEntries;
return 0;
}
uint32_t count = xnoe::get<1>(directory);
uint32_t written=0;
buffer->count = getRealCount(directoryEntries, count);
buffer->stringsLength = 0;
char* nameBuffer = ((char*)buffer);
nameBuffer += sizeof(FSDirectoryEntry)*buffer->count + sizeof(FSDirectoryListing);
for (int i=0; i<count; i++) {
if (directoryEntries[i].name[0] != 0 && directoryEntries[i].name[0] != 0xE5 && !directoryEntries[i].volumeid) {
buffer->entries[written] = FSDirectoryEntry {
name83ToPathEntry(directoryEntries[i].name, nameBuffer + 13*written),
directoryEntries[i].directory ? Directory : File,
directoryEntries[i].size
};
written++;
buffer->stringsLength += 13;
}
}
delete directoryEntries;
}

View 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 firstCluster, uint32_t sizeBytes, FAT16FS* backingFS);
uint32_t read(uint32_t count, uint8_t* buffer) override;
uint32_t write(uint32_t count, uint8_t* buffer) override;
uint32_t size() override;
uint32_t seek(uint32_t position) override;
};
class FAT16FS: public FSTree {
public:
DirectoryEntry* rootDirEntries;
uint16_t* FAT1;
uint8_t sectorOne[512];
uint8_t* sectorsPerCluster = ((uint8_t*)(sectorOne + 0x0d));
uint16_t* countReserved = ((uint16_t*)(sectorOne + 0x0e));
uint8_t* countFATs = ((uint8_t*)(sectorOne + 0x10));
uint16_t* countRDEs = ((uint16_t*)(sectorOne + 0x11));
uint16_t* sectorsPerFAT = ((uint16_t*)(sectorOne + 0x16));
ReadWriter* backingDevice;
void pathEntryTo83(PathEntry pe, char* buffer);
uint32_t clusterToSector(uint32_t cluster);
void load_file(uint32_t location, uint8_t* destination);
uint32_t calc_size(uint32_t location);
xnoe::tuple<DirectoryEntry*, uint32_t, bool> getDirectoryEntry(Path p);
xnoe::tuple<DirectoryEntry*, uint32_t, bool> getDirectoryEntryFull(Path p);
FAT16FS(ReadWriter* disk);
bool exists(Path p) override;
FSType type(Path p) override;
ReadWriter* open(Path p) override;
uint32_t getDentsSize(Path p) override;
void getDents(Path p, FSDirectoryListing* buffer) override;
};
#endif

View 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){return;}
FSType FSTree::type(Path p){return;}
ReadWriter* FSTree::open(Path p){return;}
uint32_t FSTree::getDentsSize(Path p){return;}
void FSTree::getDents(Path p, FSDirectoryListing* buffer){return;}
// RootFSTree
RootFSTree::RootFSTree() {
this->node = new FSTreeNode{
PathEntry{0,0},
xnoe::linkedlist<FSTreeNode*>(),
0
};
}
bool pathEntryInFSTreeNode(PathEntry p, FSTreeNode* n) {
xnoe::linkedlistelem<FSTreeNode*>* current = n->children.start;
while (current) {
if (current->elem->self == p)
return true;
current = current->next;
}
return false;
}
FSTreeNode* getNodeFromPathEntry(PathEntry p, FSTreeNode* n) {
if (!n)
return 0;
xnoe::linkedlistelem<FSTreeNode*>* current = n->children.start;
while (current) {
if (current->elem->self == p)
return current->elem;
current = current->next;
}
return 0;
}
FSTreeNode* RootFSTree::makeNodeIfNotExist(Path p) {
PathElement* currentPathElement = p.start;
FSTreeNode* currentNode = this->node;
if (!currentPathElement || currentPathElement == p.end)
return currentNode;
nextPE:
while (currentPathElement) {
xnoe::linkedlistelem<FSTreeNode*>* currentChild = currentNode->children.start;
while (currentChild) {
if (currentChild->elem->self == currentPathElement->elem) {
currentNode = currentChild->elem;
currentPathElement = currentPathElement->next;
goto nextPE;
}
currentChild = currentChild->next;
}
currentNode->children.append(new FSTreeNode{currentPathElement->elem, xnoe::linkedlist<FSTreeNode*>(), 0});
currentNode = currentNode->children.end->elem;
currentPathElement = currentPathElement->next;
}
return currentNode;
}
FSTree* RootFSTree::getLongestMatchingUnder(Path p) {
PathElement* currentPath = p.start;
FSTreeNode* currentNode = this->node;
FSTree* lastMountpoint = 0;
while (currentPath && currentNode) {
if ((currentPath->elem == currentNode->self) && currentNode->mountpoint)
lastMountpoint = currentNode->mountpoint;
currentNode = getNodeFromPathEntry(currentPath->elem, currentNode);
if (currentNode && currentNode->mountpoint)
lastMountpoint = currentNode->mountpoint;
currentPath = currentPath->next;
}
return lastMountpoint;
}
Path* RootFSTree::getRemainingPath(Path p) {
PathElement* currentPath = p.start;
FSTreeNode* currentNode = this->node;
PathElement* lastMountpoint = 0;
while (currentPath && currentNode) {
if (currentPath->elem == currentNode->self && currentNode->mountpoint)
lastMountpoint = currentPath;
currentNode = getNodeFromPathEntry(currentPath->elem, currentNode);
if (currentNode && currentNode->mountpoint)
lastMountpoint = currentPath;
currentPath = currentPath->next;
}
lastMountpoint = lastMountpoint->next;
if (lastMountpoint) {
Path* np = new Path;
PathElement* current = lastMountpoint;
while (current) {
np->append(current->elem);
current = current->next;
}
return np;
}
return 0;
}
FSTreeNode* RootFSTree::getExhaustive(Path p) {
PathElement* currentPath = p.start;
FSTreeNode* currentNode = this->node;
if (!currentPath)
return 0;
if (currentPath->elem != currentNode->self)
return 0;
while (currentPath && currentNode) {
currentNode = getNodeFromPathEntry(currentPath->elem, currentNode);
currentPath = currentPath->next;
}
if (currentPath)
return 0;
else
return currentNode;
}
template<typename T>
T RootFSTree::attempt(T(FSTree::*fn)(Path), Path p, T fallback) {
FSTree* mp = getLongestMatchingUnder(p);
if (mp) {
Path* rp = getRemainingPath(p);
T r;
if (rp) {
r = (mp->*fn)(*rp);
rp->destroy();
} else {
r = (mp->*fn)(Path());
}
return r;
}
return fallback;
}
void RootFSTree::attempt(void(FSTree::*fn)(Path, FSDirectoryListing*), Path p, FSDirectoryListing* b) {
FSTree* mp = getLongestMatchingUnder(p);
if (mp) {
Path* rp = getRemainingPath(p);
if (rp) {
(mp->*fn)(*rp, b);
rp->destroy();
} else {
(mp->*fn)(Path(), b);
}
}
}
bool RootFSTree::exists(Path p) {
return attempt<bool>(&FSTree::exists, p, false);
}
FSType RootFSTree::type(Path p){
return attempt<FSType>(&FSTree::type, p, Directory);
}
ReadWriter* RootFSTree::open(Path p){
return attempt<ReadWriter*>(&FSTree::open, p, 0);
}
uint32_t RootFSTree::getDentsSize(Path p){
uint32_t size = attempt<uint32_t>(&FSTree::getDentsSize, p, 0);
FSTreeNode* n = getExhaustive(p);
if (n) {
xnoe::linkedlistelem<FSTreeNode*>* current = n->children.start;
while (current) {
size += sizeof(FSDirectoryEntry);
size += current->elem->self.length;
current = current->next;
}
}
return size;
}
void RootFSTree::getDents(Path p, FSDirectoryListing* buffer){
attempt(&FSTree::getDents, p, buffer);
uint32_t oldCount = buffer->count;
uint32_t stringsOffset = buffer->count * sizeof(FSDirectoryEntry) + sizeof(FSDirectoryListing);
uint32_t addCount = 0;
char* strings = ((uint32_t)buffer) + stringsOffset;
FSTreeNode* n = getExhaustive(p);
if (n) {
xnoe::linkedlistelem<FSTreeNode*>* current = n->children.start;
while (current) {
addCount++;
current = current->next;
}
if (addCount) {
current = n->children.start;
for (int i=buffer->stringsLength; i>=0; i--)
strings[i+addCount*sizeof(FSDirectoryEntry)] = strings[i];
for (int i=0; i < buffer->count; i++)
buffer->entries[i].path.path += addCount*sizeof(FSDirectoryEntry);
while (current) {
strings += addCount*sizeof(FSDirectoryEntry) + buffer->stringsLength;
memcpy(strings, current->elem->self.path, current->elem->self.length);
buffer->entries[buffer->count++] = FSDirectoryEntry {
PathEntry{
current->elem->self.length,
strings
},
Directory,
0
};
strings += current->elem->self.length;
current = current->next;
}
}
}
}
bool RootFSTree::isMountpoint(Path p) {
Path* mp = getRemainingPath(p);
if (mp->start->next)
return false;
else
return true;
}
void RootFSTree::mount(Path p, FSTree* f) {
FSTreeNode* fstn = makeNodeIfNotExist(p);
fstn->mountpoint = f;
}
void RootFSTree::unmount(Path p) {
}
Path createPathFromString(char* s) {
Path p;
p.start = 0;
p.end = 0;
char* lastPtr = s;
uint32_t length = 0;
char c;
while (c=*(s++)) {
if (c == '/') {
if (length == 0)
p.append(PathEntry{length, 0});
else
p.append(PathEntry{length, lastPtr});
lastPtr = s;
length = 0;
continue;
}
length += 1;
}
if (length)
p.append(PathEntry{length, lastPtr});
return p;
}

View 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

View 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(str+offset);
});
addEntry(createPathFromString("initPages"), [](){
uint32_t initPages = Global::kernel->phys->initPages;
char str[11];
uint32_t offset = int_to_decimal(initPages, str);
return new OneShotReadWriter(str+offset);
});
addEntry(createPathFromString("terminalWidth"), [](){
uint32_t termWidth = Global::kernel->terminal->width;
char str[11];
uint32_t offset = int_to_decimal(termWidth, str);
return new OneShotReadWriter(str+offset);
});
addEntry(createPathFromString("terminalHeight"), [](){
uint32_t termHeight = Global::kernel->terminal->height;
char str[11];
uint32_t offset = int_to_decimal(termHeight, str);
return new OneShotReadWriter(str+offset);
});
}

View 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

View 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 getEntry(p);
}
ReadWriter* VFS::open(Path p) {
Constructor c = getEntry(p);
return c(p);
}
uint32_t VFS::getDentsSize(Path p) {
VFSTreeNode* node = getNode(p);
if (!node)
return 0;
uint32_t total = sizeof(FSDirectoryListing);
xnoe::linkedlistelem<VFSTreeNode*>* currentNode = node->children.start;
while (currentNode) {
total += sizeof(FSDirectoryEntry);
total += currentNode->elem->self.length;
currentNode = currentNode->next;
}
return total;
}
void VFS::getDents(Path p, FSDirectoryListing* buffer) {
VFSTreeNode* node = getNode(p);
if (!node)
return;
uint32_t total = sizeof(FSDirectoryListing);
xnoe::linkedlistelem<VFSTreeNode*>* currentNode = node->children.start;
buffer->count = 0;
while (currentNode) {
buffer->count++;
currentNode = currentNode->next;
}
uint8_t* strings = (uint8_t*)(buffer) + sizeof(FSDirectoryListing) + sizeof(FSDirectoryEntry) * buffer->count;
currentNode = node->children.start;
uint32_t index = 0;
while (currentNode) {
memcpy(strings, currentNode->elem->self.path, currentNode->elem->self.length);
buffer->entries[index++] = FSDirectoryEntry{
PathEntry{currentNode->elem->self.length, strings},
File,
0
};
strings += currentNode->elem->self.length;
buffer->stringsLength += currentNode->elem->self.length;
currentNode = currentNode->next;
}
}

View 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

View File

@ -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,25 +77,29 @@ constexpr gdt_entry::gdt_entry() :
base_hi(0)
{}
gdt_entry 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
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
gdt_entry(0xfffff, 0, 1, 1, 1, 3), // User Code Segment
gdt_entry(0xfffff, 0, 1, 0, 1, 3), // User Data Segment
gdt_entry(0xfffff, 0, 1, 1, 1, 3), // User Code Segment
gdt_entry(0xfffff, 0, 1, 0, 1, 3), // User Data Segment
gdt_entry() // Empty Task State Segment
gdt_entry() // Empty Task State Segment
}
};
gdt_descr descr = (gdt_descr){
.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;"

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -22,11 +22,12 @@ void set_entry(uint8_t interrupt_number, uint16_t code_segment, void(*handler)()
}
void handle_fault(frame_struct* frame) {
//frame_struct* frame = &Global::currentThread->frame;
// Clear interrupts, we don't want to perform a context switch whilst handling a fault.
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");
@ -36,17 +37,23 @@ void handle_fault(frame_struct* frame) {
break;
case 13: // GPF
Global::kernel->terminal->printf("General Protection Fault!");
if (frame->eflags & 0x00020000) {
Global::kernel->terminal->printf("\x1b[42;37;1mv86 GPF! All is good!\n");
v86_monitor((v8086_frame_struct*)frame);
return;
}
break;
case 14: // Page Fault
Global::kernel->terminal->printf("Page Fault at %x", problem_address);
break;
default:
Global::kernel->terminal->printf("Unkown Fault!");
Global::kernel->terminal->printf("Unkown Fault! Gate: %d", frame->gate);
break;
}
Global::kernel->terminal->printf(" Error Code: %x\n", frame->errcode);
if (!(frame->cs & 3)) {
Global::kernel->terminal->printf("[FATAL] Kernel Fault!!!\n");
((VGAModeTerminal*)Global::kernel->terminal)->bufferToVRAM();
while (1) asm("hlt");
} else {
// Print an error message.
@ -58,16 +65,14 @@ 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();
}
}
void ignore_interrupt(frame_struct* frame) {}
void ignore_interrupt(frame_struct* _) {}
void context_switch(frame_struct* frame) {
void context_switch() {
frame_struct* frame = &Global::currentThread->frame;
// When any interrupt occurs (including context_switch), SS:ESP is set to
// the values of SS0:ESP0 in Global::tss
//
@ -83,101 +88,123 @@ 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;
// 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;
} 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->start->prev = 0;
threads->end->next = 0;
threads->end->prev = threads->start;
threads->start->next = threads->end;
} else {
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::currentProc = processes->start->elem;
Global::currentThread = threads->start->elem;
Global::currentProc = threads->start->elem->parent;
} while (Global::currentThread->state != Running);
// Select the next processes page directory
frame->new_cr3 = Global::currentProc->PD->phys_addr;
// Restore kernelStackPtr of the new process.
frame->new_esp = Global::currentProc->kernelStackPtr;
Global::currentThread->frame.new_cr3 = Global::currentThread->parent->PD->phys_addr;
Global::tss->esp0 = Global::currentProc->kernelStackPtrDefault;
Global::tss->esp0 = (uint32_t)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(*)(void*), void*, bool>;
xnoe::linkedlist<TimedEvent> timed_events;
void tick(frame_struct* frame) {
void tick(frame_struct* _) {
xnoe::linkedlistelem<TimedEvent>* current = timed_events.start;
while (current) {
TimedEvent t = current->elem;
uint32_t count = xnoe::get<0>(t);
if (--count == 0) {
xnoe::get<2>(t)(frame, xnoe::get<3>(t));
xnoe::get<2>(t)(xnoe::get<3>(t));
count = xnoe::get<1>(t);
if (xnoe::get<4>(t)) {
xnoe::linkedlistelem<TimedEvent>* prev = current;
current = current->next;
timed_events.remove(prev);
delete prev;
continue;
}
}
current->elem = TimedEvent(count, xnoe::get<1>(t), xnoe::get<2>(t), xnoe::get<3>(t));
current->elem = TimedEvent(count, xnoe::get<1>(t), xnoe::get<2>(t), xnoe::get<3>(t), xnoe::get<4>(t));
current = current->next;
}
Global::milliseconds_elapsed++;
}
void register_event(uint32_t milliseconds, void(*function)(frame_struct*, void*), void* auxiliary) {
timed_events.append(TimedEvent(milliseconds, milliseconds, function, auxiliary));
void register_event(uint32_t milliseconds, void(*function)(void*), void* auxiliary, bool oneshot=false) {
timed_events.append(TimedEvent(milliseconds, milliseconds, function, auxiliary, oneshot));
}
}
void syscall(frame_struct* frame) {
void awaken(Thread* t) {
t->state = Running;
}
void syscall(frame_struct* _) {
// 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
@ -185,136 +212,143 @@ void syscall(frame_struct* frame) {
// 2..7: Reserved
// _: General use
uint32_t rval = frame->eax;
uint32_t esi = frame->esi;
uint32_t edi = frame->edi;
frame_struct* frame = &Global::currentThread->frame;
Process* currentProc = Global::currentProc;
switch (frame->eax) {
case 0:
case 0: // getDentsSize
frame->eax = Global::kernel->rootfs->getDentsSize(createPathFromString((char*)frame->ebx));
break;
case 1:
case 1: // getDents
Global::kernel->rootfs->getDents(createPathFromString((char*)frame->ebx), (FSDirectoryListing*)frame->ecx);
break;
case 2:
case 2: // exists
frame->eax = Global::kernel->rootfs->exists(createPathFromString((char*)frame->ebx));
break;
case 3:
case 3: // type
frame->eax = Global::kernel->rootfs->type(createPathFromString((char*)frame->ebx));
break;
case 4:
rval = currentProc->allocate(esi);
case 4: // malloc
frame->eax = (uint32_t)currentProc->allocate(frame->ebx);
break;
case 5:
currentProc->deallocate(esi);
case 5: // free
currentProc->deallocate(frame->ebx);
break;
case 6:
case 6: // getMillisecondsElapsed
frame->eax = Global::milliseconds_elapsed;
break;
case 7: {
case 7: {// execve
asm("cli");
Process* p = Global::kernel->createProcess(esi);
rval = p->PID;
xnoe::maybe<ReadWriter*> file = Global::currentProc->getFH(frame->ebx);
if (file.is_ok()) {
Process* p = Global::kernel->createProcess(file.get(), (uint8_t**)frame->ecx, (uint8_t**)frame->edx);
// Suspend the current thread and forward the current process's stdin and stdout to the new one.
Global::currentThread->state = Suspended;
p->stdin = Global::currentProc->stdin;
p->stdout = Global::currentProc->stdout;
p->threads.start->elem->suspending = Global::currentThread->TID;
context_switch();
} else {
frame->eax = 0;
}
asm("sti");
break;
}
case 8:
rval = currentProc->PID;
case 8: // getPID
frame->eax = currentProc->PID;
break;
case 9:
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);
if (!fh.is_ok()) {
rval = 0;
break;
}
ReadWriter* rw = fh.get();
rval = rw->read(frame->ebx, edi);
}
break;
case 9: { // die
Global::kernel->PD->select();
Global::kernel->destroyProcess(Global::currentProc, frame->ebx);
Global::currentProcValid = false;
context_switch();
return;
}
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);
if (!fh.is_ok()) {
rval = 0;
break;
}
ReadWriter* rw = fh.get();
rval = rw->write(frame->ebx, edi);
}
break;
}
case 12:
if (currentProc->stdin)
case 10: { // read
xnoe::maybe<ReadWriter*> fh = Global::currentProc->getFH(frame->ecx);
if (!fh.is_ok()) {
frame->eax = 0;
break;
}
currentProc->stdin = new CircularRWBuffer(currentProc->PID, 0);
ReadWriter* rw = fh.get();
frame->eax = rw->read(frame->ebx, (uint8_t*)frame->edx);
break;
}
case 11: { // write
xnoe::maybe<ReadWriter*> fh = Global::currentProc->getFH(frame->ecx);
if (!fh.is_ok()) {
frame->eax = 0;
break;
}
ReadWriter* rw = fh.get();
frame->eax = rw->write(frame->ebx, (uint8_t*)frame->edx);
break;
}
case 12: // bindToKeyboard
if (currentProc->stdin)
currentProc->stdin->close();
currentProc->stdin = new CircularRWBuffer();
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);
p->stdout = buffer;
rval = Global::kernel->mapFH(buffer);
}
//if (!p->stdout) {
//ReadWriter* buffer = new CircularRWBuffer(currentProc->PID, frame->ebx);
//p->stdout = buffer;
p->stdout->open();
frame->eax = Global::currentProc->mapFH(p->stdout);
//}
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);
p->stdin = buffer;
rval = Global::kernel->mapFH(buffer);
}
//if (!p->stdin) {
//ReadWriter* buffer = new CircularRWBuffer(frame->ebx, currentProc->PID);
//p->stdin = buffer;
p->stdin->open();
frame->eax = Global::currentProc->mapFH(p->stdin);
//}
break;
}
case 15: {
ReadWriter* file = new FATFileReadWriter(0, esi);
rval = Global::kernel->mapFH(file);
case 15: { // fopen
ReadWriter* file = Global::kernel->rootfs->open(createPathFromString((char*)frame->ebx));
if (file)
frame->eax = 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);
f.get()->close();
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,11 +357,118 @@ void syscall(frame_struct* frame) {
break;
}
case 18: { // sleep
Global::currentThread->state = Suspended;
Timer::register_event(frame->ebx, (void(*)(void*))&awaken, (void*)Global::currentThread, true);
context_switch();
break;
}
case 19: // getRemainingPages
frame->eax = Global::kernel->phys->remainingPages;
break;
case 20: // getInitPages
frame->eax = Global::kernel->phys->initPages;
break;
case 21: // getTerminalWidth
frame->eax = Global::kernel->terminal->width;
break;
case 22: // getTerminalHeight
frame->eax = Global::kernel->terminal->height;
break;
case 23: { // getProcessState
xnoe::maybe<Process*> p = Global::kernel->pid_map->get(frame->ebx);
if (p.is_ok()) {
Process* proc = p.get();
//frame->eax = proc->state;
}
break;
}
case 25: { // fork
Process* p = new Process(Global::currentProc);
Thread* t = new Thread(Global::currentThread, p);
t->parent = p;
p->threads.append(t);
Global::kernel->registerThread(t);
Global::kernel->registerProcess(p);
frame->eax = p->PID;
t->frame.eax = 0;
break;
}
case 24: { // spawnThread
Thread* thread = new Thread(Global::currentProc);
thread->initKernelStack((void*)frame->ebx, thread->stack);
Global::kernel->registerThread(thread);
break;
}
case 26: {// programRunning
xnoe::maybe<Process*> p = Global::kernel->pid_map->get(frame->ebx);
frame->eax = p.is_ok();
break;
}
default:
break;
}
}
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++) + 2;
frame->cs = *(sp++);
frame->eflags &= 0xffff0000;
frame->eflags |= *(sp++);
break;
}
case 0xfa:
asm("cli");
frame->eip++;
break;
case 0xfb:
asm("sti");
frame->eip++;
break;
default: {
break;
}
}
frame->esp = (uint16_t)sp;
}
void init_idt() {
@ -340,7 +481,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 +500,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);
@ -381,9 +521,10 @@ void init_idt() {
outb(0x40, _counter[0]);
outb(0x40, _counter[1]);
Timer::register_event(30, &context_switch, 0);
Timer::register_event(30, (void(*)(void*))&context_switch, 0);
}
void enable_idt() {
gates[32] = &Timer::tick;
asm ("sti");
}

View File

@ -2,13 +2,12 @@
#define IDT_H
#include "types.h"
#include "screenstuff.h"
#include "global.h"
#include "kernel.h"
#include "gdt.h"
#include "stdio/circularrwbuffer.h"
struct __attribute__((packed)) frame_struct {
struct __attribute__((packed)) v8086_frame_struct {
uint32_t new_cr3;
uint32_t new_esp;
@ -29,9 +28,17 @@ struct __attribute__((packed)) frame_struct {
uint16_t cs;
uint16_t _ignored0;
uint32_t eflags;
uint32_t esp;
uint16_t ss;
uint16_t _ignored1;
uint32_t esp;
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 +64,10 @@ struct __attribute__((packed)) idt_desc {
uint32_t offset;
};
void context_switch();
void handle_fault(frame_struct* frame);
void syscall();
void ignore_interrupt();
void v86_monitor(v8086_frame_struct* frame);
#endif

View File

@ -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);
}

View File

@ -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

View File

@ -6,64 +6,72 @@ global catchall_return
catchall: ; At this point the gate number has been pushed to the stack
pushad
push esp
sub esp, 4
push eax
mov eax, cr3
mov [esp+4], eax
pop eax
push eax
push 0
; Pushed 40 bytes
mov eax, [esp+40]
mov ebx, gates
mov eax, [ebx+4*eax]
; Check if we came from Ring 3
movzx ecx, word [esp+56]
and ecx, 3
cmp ecx, 3
jne no_copy
mov ecx, 72
mov esi, esp
mov edi, [_ZN6Global13currentThreadE]
rep movsb
mov ecx, [_ZN6Global13currentThreadE]
push ecx
jmp call
no_copy:
push esp
jmp call
call:
; Increment the current thread's count
mov ecx, [_ZN6Global13currentThreadE]
mov edx, [ecx]
add edx, 1
mov [ecx], edx
call eax
catchall_return:
add esp, 4
push 0x20
push 0x20
call outb
add esp, 8
push eax
mov eax, [esp+4]
mov cr3, eax
pop eax
; Decrement and check the current thread's count
mov ecx, [_ZN6Global13currentThreadE]
mov edx, [ecx]
sub edx, 1
mov [ecx], edx
cmp edx, 0
jne skip_copying
sub esp, 72
mov ecx, 72
mov esi, [_ZN6Global13currentThreadE]
mov edi, esp
rep movsb
skip_copying:
add esp, 4
pop esp
pop eax
mov cr3, eax
popad
mov esp, ebp
add esp, 8
pop ebp
iret
extern gates ; (void(*)(frame_struct))*
extern outb
; struct frame_struct __attribute__((packed)) {
; popad
; uint32_t edi;
; uint32_t esi;
; uint32_t ebp;
; uint32_t esp;
; uint32_t ebx;
; uint32_t edx;
; uint32_t ecx;
; uint32_t eax;
;
; interrupt
; uint32_t eip;
; uint32_t cs;
; uint32_t eflags;
; uint32_t esp;
; uint32_t ss;
;
; if it's an error
; uint32_t err_code;
; }
extern _ZN6Global13currentThreadE

View File

@ -1,60 +1,185 @@
#include "kernel.h"
Kernel::Kernel(PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base, uint32_t stack)
: Process(0, 0x8a000, page_directory, phys, virt, virt_alloc_base)
: Process(0x8a000, page_directory, phys, virt, virt_alloc_base)
{
this->currentPID = 1;
Global::allocator = this;
Global::kernel = this;
Global::currentProc = 0;
Global::currentProc = this;
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->tid_map = new xnoe::hashtable<uint32_t, Thread*>();
this->globalISRStack = (new uint8_t[0x8000]) + 0x8000;
Global::currentThread = new Thread(this);
Global::currentThread->frame.count++;
}
Process* Kernel::createProcess(uint32_t fh) {
Process* p = new Process(currentPID, this->PD, 0xc0000000, fh);
this->pid_map->set(currentPID, p);
currentPID++;
Process* Kernel::createProcess(ReadWriter* file, uint8_t** argv, uint8_t** envp) {
// argv is currently stored on the stack of the calling process
// We need to create a copy of it in the kernel stack for createProcess
this->processes.append(p);
// Determine the length of argv (null terminated)
uint32_t argc = 0;
for (int i=0; argv[i]; i++)
argc++;
// Determine the length of all stings under argv
uint32_t argv_strings_length = 0;
for (int i=0; i<argc; i++)
argv_strings_length += strlen(argv[i]);
// Allocate space for the strings + new argv
char argv_strings[argv_strings_length];
char* argv_new[argc];
// Copy the strings, fill argv_new
for (int i=0, string_index=0; argv[i]; string_index+=strlen(argv[i++])) {
memcpy(&argv_strings[string_index], argv[i], strlen(argv[i]));
argv_new[i] = &argv_strings[string_index];
}
// envp is currently stored on the stack of the calling process
// We need to create a copy of it in the kernel stack for createProcess
// Determine the length of envp (null terminated)
uint32_t envc = 0;
if (envp)
for (int i=0; envp[i]; i++)
envc++;
// Determine the length of all stings under envp
uint32_t envp_strings_length = 0;
for (int i=0; i<envc; i++)
envp_strings_length += strlen(envp[i]);
// Allocate space for the strings + new envp
char envp_strings[envp_strings_length];
char* envp_new[envc];
// Copy the strings, fill envp_new
if (envc) {
for (int i=0, string_index=0; envp[i]; string_index+=strlen(envp[i++])) {
memcpy(&envp_strings[string_index], envp[i], strlen(envp[i]));
envp_new[i] = &envp_strings[string_index];
}
}
Process* p = new Process(this->PD, 0xc0000000, file, argc, argv_new, envc, envp_new);
this->pid_map->set(p->PID, p);
registerThread(p->threads.start->elem);
return p;
}
Process* Kernel::createProcess(uint32_t fh, ReadWriter* stdout) {
Process* p = this->createProcess(fh);
Process* Kernel::createProcess(ReadWriter* file, uint8_t** argv, ReadWriter* stdout) {
char* zero = 0;
Process* p = this->createProcess(file, argv, &zero);
p->stdout = stdout;
return p;
}
void Kernel::destroyProcess(Process* p) {
if (Global::currentProc == p)
Global::currentProcValid = false;
this->processes.remove(p);
void Kernel::registerProcess(Process* p) {
this->pid_map->set(p->PID, p);
}
void Kernel::destroyProcess(Process* p, uint32_t exit_code) {
xnoe::linkedlistelem<Thread*>* currentThread = p->threads.start;
while (currentThread) {
destroyThread(currentThread->elem, exit_code);
currentThread = currentThread->next;
}
this->pid_map->remove(p->PID);
delete p;
}
int Kernel::mapFH(ReadWriter* fh) {
Global::FH->set(this->lastFH++, fh);
return this->lastFH - 1;
void Kernel::registerThread(Thread* t) {
this->threads.append(t);
this->tid_map->set(t->TID, t);
}
void Kernel::unmapFH(uint32_t fh) {
Global::FH->remove((void*)fh);
void Kernel::destroyThread(Thread* t, uint32_t exit_code) {
this->tid_map->remove(t->TID);
t->parent->threads.remove(t);
this->threads.remove(t);
if (t->suspending) {
xnoe::maybe<Thread*> ts = this->tid_map->get(t->suspending);
if (ts.is_ok()) {
Thread* st = ts.get();
st->state = Running;
st->frame.eax = exit_code;
}
}
delete t;
}
//void Kernel::loadPrimaryStack() {
// asm volatile("mov %0, %%esp"::"m"(this->stack - 64));
//}
void Kernel::v86(uint16_t ax, uint16_t bx, uint16_t cx, uint16_t es, uint16_t di, uint8_t intn) {
// Create the payload to perform an interrupt.
uint8_t payload[21] = {
0xb8, 0x00, 0x00, // mov ax, 0
0x8e, 0xc0, // mov es, ax
0xb8, 0x00, 0x00, // mov ax, 0
0xbb, 0x00, 0x00, // mov bx, 0
0xb9, 0x00, 0x00, // mov cx, 0
0xbf, 0x00, 0x00, // mov di, 0
0xcd, 0x00, // int 0
0xcd, 0x00 // int 0
};
// Set the values in the payload.
uint16_t* ax1 = (uint16_t*)(payload+1);
uint16_t* ax2 = (uint16_t*)(payload+6);
uint16_t* bx1 = (uint16_t*)(payload+9);
uint16_t* cx1 = (uint16_t*)(payload+12);
uint16_t* di1 = (uint16_t*)(payload+15);
uint8_t* intn1 = (uint8_t*)(payload+18);
*ax1 = es;
*ax2 = ax;
*bx1 = bx;
*cx1 = cx;
*di1 = di;
*intn1 = intn;
// Construct a stack.
uint32_t* stack = 0x9000;
*(--stack) = 0; // GS
*(--stack) = 0; // FS
*(--stack) = 0; // DS
*(--stack) = 0; // ES
*(--stack) = 0; // SS
*(--stack) = 0x9000; // ESP
*(--stack) = 0x00020000; // EFLAGS
*(--stack) = 0; // CS
*(--stack) = 0x7c00; // EIP
// Copy 19 bytes from payload to 0x7c00
memcpy((uint8_t*)0x7c00, payload, 21);
asm("lea _after_iret, %eax");
asm("push %eax");
asm("pusha");
asm("mov %%esp, %0":"=m"(Global::resp)::);
asm("xor %eax, %eax; xor %ebx, %ebx; xor %ecx, %ecx; xor %edi, %edi");
asm("mov %0, %%esp"::"m"(stack):);
asm("iret");
asm("_after_iret:");
}

View File

@ -5,32 +5,38 @@
#include "datatypes/hashtable.h"
#include "global.h"
#include "terminal.h"
#include "filesystem/fstree.h"
#include "gdt.h"
class Kernel : public Process {
private:
int lastFH;
public:
uint32_t currentPID;
uint32_t stack;
uint32_t globalISRStack;
Terminal* terminal;
xnoe::hashtable<uint32_t, Process*>* pid_map; // Map of PIDs -> Process*s
xnoe::hashtable<uint32_t, Thread*>* tid_map; // Map of TIDs -> Thread*s
xnoe::linkedlist<Process*> processes;
xnoe::linkedlist<Process*> 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);
void destroyProcess(Process* p);
Process* createProcess(ReadWriter* file, uint8_t** argv, uint8_t** envp);
Process* createProcess(ReadWriter* file, uint8_t** argv, ReadWriter* stdout);
void registerProcess(Process* p);
void destroyProcess(Process* p, uint32_t exit_code=0);
int mapFH(ReadWriter* fh);
void unmapFH(uint32_t fh);
//void loadPrimaryStack();
void registerThread(Thread* t);
void destroyThread(Thread* t, uint32_t exit_code=0);
void v86(uint16_t ax, uint16_t bx, uint16_t cx, uint16_t es, uint16_t di, uint8_t intn);
};
#endif

View File

@ -3,7 +3,6 @@
#include <stdbool.h>
#include "io.h"
#include "screenstuff.h"
#include "idt.h"
void init_keyboard();

View File

@ -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;
@ -40,17 +51,31 @@ int main() {
term->activate();
term->clear_screen();
/*kernel.v86(
0x4F00,
0,
0,
0,
0,
0x10
);*/
term->printf("Hello, World!\n\nWe are running XnoeOS Code in C++ now, Protected Mode has been achieved (as well as Virtual Memory / Paging!!!) and everything is working super nicely!\n\nHow wonderful!\n\nNow I just need to hope my print function works properly too~~\n");
term->printf("KERNEL OK!\n");
ReadWriter* worldbin = new FATFileReadWriter(0, "etc/world.bin");
uint32_t fh = kernel.mapFH(worldbin);
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* init = kernel.rootfs->open(createPathFromString("/init.bin"));
Process* p1 = kernel.createProcess(fh, term);
char* zero = 0;
Process* p1 = kernel.createProcess(init, &zero, term);
Global::tss->esp0 = (new uint8_t[8192]) + 8192;
init_keyboard();
enable_idt();
while (1) asm ("hlt");

View File

@ -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,

View File

@ -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);
};

View File

@ -1,7 +1,6 @@
#ifndef PAGING_H
#define PAGING_H
#include <stdbool.h>
#include "types.h"
struct __attribute__((packed)) split_addr {

View File

@ -3,90 +3,214 @@
extern void(*catchall_return)();
AllocTracker::AllocTracker(void* base, uint32_t size, uint32_t count) : page_base(base), page_size(size), alloc_count(count) {}
AllocTracker::AllocTracker() {}
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)
uint32_t Process::currentPID = 0;
Process::Process(void* stack, PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base)
: Allocator(page_directory, phys, virt, virt_alloc_base) {
this->PID = PID;
this->PID = this->currentPID++;
this->page_remaining = 0;
this->last_page_pointer = virt_alloc_base;
this->stack = stack;
}
Process::Process(uint32_t PID)
Process::Process()
: Allocator(new PageDirectory, new PageMap, (uint32_t)0, 3) {
this->PID = PID;
this->PID = 0;
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(PageDirectory* inherit, uint32_t inheritBase, ReadWriter* filereader, uint32_t argc, char** argv, uint32_t envc, char** envp)
: Allocator(new PageDirectory, new PageMap, (uint32_t)0, 3) {
this->stdout = 0;
this->stdin = 0;
this->firstRun = true;
this->PID = PID;
this->PID = this->currentPID++;
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;
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();
uint32_t pCR3;
asm ("mov %%cr3, %0" : "=a" (pCR3) :);
this->PD->select();
// We also need to initialise ESP and the stack
uint32_t* stack32 = ((uint32_t)this->kernelStackPtr);
*(--stack32) = 0x23; // SS
*(--stack32) = ((uint32_t)this->stack + 0x8000); // ESP
*(--stack32) = 0x200; // EFLAGS
*(--stack32) = 27; // CS
*(--stack32) = (uint32_t)program_data; // EIP
*(--stack32) = ((uint32_t)this->stack + 0x8000); // EBP
uint32_t* stack = thread->stack + 0x8000;
uint8_t* argenvarea = this->allocate(0x2000) + 0x2000;
uint32_t rEBP = stack32;
*(--stack32) = 0; // EAX
*(--stack32) = 0; // ECX
*(--stack32) = 0; // EDX
*(--stack32) = 0; // EBX
*(--stack32) = 0; // ESP
*(--stack32) = rEBP; // EBP
*(--stack32) = 0; // ESI
*(--stack32) = 0; // EDI
this->kernelStackPtr = stack32;
filereader->read(filesize, program_data);
asm ("mov %0, %%cr3" : : "r" (pCR3));
// Copy envp
// envp is null terminated
*(--stack) = 0;
for (int i=envc; i>0; i--) {
char* s = envp[i-1];
uint32_t c = strlen(s);
memcpy((uint8_t*)(argenvarea -= c), (uint8_t*)envp[i-1], c);
*(--stack) = argenvarea;
}
uint32_t envp_p = ((uint32_t)stack);
// Copy argv
for (int i=argc; i>0; i--) {
char* s = argv[i-1];
uint32_t c = strlen(s);
memcpy((uint8_t*)(argenvarea -= c), (uint8_t*)argv[i-1], c);
*(--stack) = argenvarea;
}
uint32_t argv_p = ((uint32_t)stack);
*(--stack) = envp_p;
*(--stack) = argv_p;
*(--stack) = argc;
filereader->seek(0);
filereader->read(filesize, program_data);
asm ("mov %0, %%cr3" : : "r" (pCR3));
thread->initKernelStack(program_data, stack);
this->threads.append(thread);
}
Process::Process(Process* p)
: Allocator(new PageDirectory, new PageMap, (uint32_t)0, 3) {
// Clone a Process and produce an entirely new process.
this->file_handlers = new xnoe::dynarray<ReadWriter*>(p->file_handlers);
this->PID = this->currentPID++;
// Set up page directory.
for (int index = 0xc0000000 >> 22; index < 1024; index++)
this->PD->page_directory[index] = p->PD->page_directory[index];
// First, we need to switch in to p's memory space
uint32_t pCR3;
asm("mov %%cr3, %0":"=a"(pCR3)::);
p->PD->select();
// First, we need to copy all of p's allocations.
xnoe::linkedlist<xnoe::tuple<AllocTracker, void*>> allocations;
xnoe::linkedlistelem<AllocTracker>* current_old = p->allocations.start;
while (current_old) {
allocations.append(xnoe::tuple<AllocTracker, void*>(current_old->elem, new uint8_t[4096 * current_old->elem.page_size]));
void* location = xnoe::get<1>(allocations.end->elem);
memcpy((uint8_t*)location, (uint8_t*)current_old->elem.page_base, 4096 * current_old->elem.page_size);
current_old = current_old->next;
}
// Select our own CR3
this->PD->select();
// Go through every allocation from the old process, allocate it here, copy the data over, then free the buffer we created.
xnoe::linkedlistelem<xnoe::tuple<AllocTracker, void*>>* current_new = allocations.start;
while (current_new) {
AllocTracker at = xnoe::get<0>(current_new->elem);
uint8_t* buf = (uint8_t*)xnoe::get<1>(current_new->elem);
uint8_t* dbuf = (uint8_t*)this->allocate((at.page_size-1) * 4096, at.alloc_count);
memcpy(dbuf, buf + 0x14, at.page_size * 4096 - 0x14);
delete buf;
current_new = current_new->next;
}
// Restore CR3
asm("mov %0, %%cr3"::"r"(pCR3):);
// Setting up threads, etc will be left to the caller.
this->stdin = p->stdin;
this->stdout = p->stdout;
}
uint32_t Thread::currentTID = 1;
Thread::Thread(Process* parent) {
this->TID = this->currentTID++;
this->parent = parent;
this->stack = this->parent->allocate(0x8000);
this->kspRaw = (new uint8_t[0x4000]);
this->kernelStackPtr = this->kspRaw + 0x4000;
this->kernelStackPtrDefault = this->kernelStackPtr;
}
Thread::Thread(Thread* t, Process* parent) {
this->TID = this->currentTID++;
this->stack = t->stack;
uint8_t* s = new uint8_t[0x8000];
// Copy the kernel stack
this->kspRaw = (new uint8_t[0x4000]);
memcpy(this->kspRaw, t->kspRaw, 0x4000);
memcpy((uint8_t*)&this->frame, (uint8_t*)&t->frame, sizeof(frame_struct));
this->frame.new_cr3 = parent->PD->phys_addr;
this->kernelStackPtr = this->kspRaw + 0x4000;
this->kernelStackPtrDefault = this->kernelStackPtr;
this->frame.ebp = this->kernelStackPtr;
this->frame.oesp = this->kernelStackPtr;
}
Thread::~Thread() {
//delete kernelStackPtr;
}
void Thread::initKernelStack(void* entryPoint, void* esp) {
uint32_t pCR3;
asm ("mov %%cr3, %0" : "=a" (pCR3) :);
this->parent->PD->select();
uint32_t* stack32 = ((uint32_t)this->kernelStackPtr);
*(--stack32) = 0x23; // SS
*(--stack32) = ((uint32_t)esp); // ESP
*(--stack32) = 0x200; // EFLAGS
*(--stack32) = 27; // CS
*(--stack32) = (uint32_t)entryPoint; // EIP
*(--stack32);
*(--stack32);
*(--stack32);
*(--stack32) = 0; // EAX
*(--stack32) = 0; // ECX
*(--stack32) = 0; // EDX
*(--stack32) = 0; // EBX
*(--stack32) = 0; // ESP
*(--stack32) = 0; // EBP
*(--stack32) = 0; // ESI
*(--stack32) = 0; // EDI
*(--stack32) = 0; // CR3
*(--stack32) = 1;
memcpy((uint8_t*)&this->frame, (uint8_t*)stack32, 72);
this->kernelStackPtr = stack32;
asm ("mov %0, %%cr3" : : "r" (pCR3));
}
Process::~Process() {
@ -98,13 +222,60 @@ 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())
r.get()->close();
}
/*xnoe::linkedlistelem<Thread*>* currentThread = threads.start;
while (currentThread) {
delete currentThread->elem;
currentThread = currentThread->next;
}*/
}
void* Process::allocate(uint32_t size, uint32_t alloc_count) {
bool switched_PD = false;
uint32_t pCR3;
asm ("mov %%cr3, %0" : "=a" (pCR3) :);
if (Global::currentProc != this) {
switched_PD = true;
this->PD->select();
}
void* ptr;
// For cloning a process, always allocate new
uint32_t elem_size = sizeof(xnoe::linkedlistelem<AllocTracker>);
// Determine how many pages we'll allocate, and the remainder
uint32_t pages = size / 4096;
uint32_t remainder = 4096 - (size % 4096);
ptr = this->Allocator::allocate(size);
// Update local values
this->last_page_pointer = ptr + pages * 4096;
this->page_remaining = remainder;
// Create allocations entry
xnoe::linkedlistelem<AllocTracker>* elem = (xnoe::linkedlistelem<AllocTracker>*)ptr;
elem->next = 0;
elem->prev = 0;
elem->elem = AllocTracker(ptr, pages + 1, alloc_count);
this->allocations.append(elem);
ptr += elem_size;
asm ("mov %0, %%cr3" : : "r" (pCR3));
return ptr;
}
void* Process::allocate(uint32_t size) {
@ -126,7 +297,7 @@ void* Process::allocate(uint32_t size) {
uint32_t elem_size = sizeof(xnoe::linkedlistelem<AllocTracker>);
size += elem_size;
// Determine how many pages we'll allocate, and the remainder;
// Determine how many pages we'll allocate, and the remainder
uint32_t pages = size / 4096;
uint32_t remainder = 4096 - (size % 4096);
@ -152,7 +323,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 +342,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;
}

View File

@ -6,17 +6,70 @@
#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"
#include "stdio/circularrwbuffer.h"
struct __attribute__((packed)) frame_struct {
uint32_t count;
uint32_t new_cr3;
uint32_t edi;
uint32_t esi;
uint32_t ebp;
uint32_t oesp;
uint32_t ebx;
uint32_t edx;
uint32_t ecx;
uint32_t eax;
uint32_t gate;
uint32_t __ignored2;
uint32_t errcode;
uint32_t eip;
uint16_t cs;
uint16_t _ignored0;
uint32_t eflags;
uint32_t esp;
uint16_t ss;
uint16_t _ignored1;
};
class Process;
class Thread {
private:
static uint32_t currentTID;
public:
frame_struct frame;
uint32_t TID;
void* stack;
void* kspRaw;
void* kernelStackPtr;
void* kernelStackPtrDefault;
Process* parent;
ProcessState state;
bool firstRun;
uint32_t suspending=0;
Thread(Process* parent);
Thread(Thread* t, Process* parent);
~Thread();
void Thread::initKernelStack(void* entryPoint, void* esp);
};
struct AllocTracker {
void* page_base;
uint32_t page_size;
uint32_t alloc_count;
AllocTracker();
AllocTracker(void* base, uint32_t size, uint32_t count);
};
@ -25,35 +78,43 @@ private:
uint32_t last_page_pointer;
uint32_t page_remaining;
void* stack;
xnoe::maybe<xnoe::linkedlistelem<AllocTracker>*> get_alloc_tracker(uint32_t address);
// List of pages this process has allocated
xnoe::linkedlist<AllocTracker> allocations;
Path currentWorkingDirectory;
xnoe::Maybe<xnoe::linkedlistelem<AllocTracker>*> get_alloc_tracker(uint32_t address);
static uint32_t currentPID;
public:
xnoe::dynarray<ReadWriter*>* file_handlers;
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);
// List of pages this process has allocated
xnoe::linkedlist<AllocTracker> allocations;
Process(void* stack, PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base);
Process();
Process(PageDirectory* inherit, uint32_t inheritBase, ReadWriter* filereader, uint32_t argc=0, char** argv=0, uint32_t envc=0, char** envp=0);
Process(Process* p);
~Process(); // Iterate through allocations and free those; delete stack
void* allocate(uint32_t size, uint32_t alloc_count);
void* allocate(uint32_t size) override;
void 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

View File

@ -0,0 +1,9 @@
#ifndef PROCESSSTATE_H
#define PROCESSSTATE_H
enum ProcessState {
Running=0,
Suspended=1
};
#endif

View File

@ -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);
}

View File

@ -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
View 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
View 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

View File

@ -1,16 +1,16 @@
#include "circularrwbuffer.h"
CircularRWBuffer::CircularRWBuffer(uint32_t reader, uint32_t writer)
: ReadWriter(0) {
this->giveReadPerm(reader);
this->giveWritePerm(writer);
CircularRWBuffer::CircularRWBuffer() {
this->bufferSize = 3072;
this->buffer = new uint8_t[this->bufferSize];
this->readPtr = 0;
this->writePtr = 0;
}
CircularRWBuffer::~CircularRWBuffer() {
delete this->buffer;
}
uint32_t CircularRWBuffer::write(uint32_t count, uint8_t* buffer) {
int i=0;
while (i < count) {

View File

@ -10,7 +10,8 @@ private:
uint32_t writePtr;
uint32_t bufferSize;
public:
CircularRWBuffer(uint32_t reader, uint32_t writer);
CircularRWBuffer();
~CircularRWBuffer();
uint32_t read(uint32_t count, uint8_t* buffer) override;
uint32_t write(uint32_t count, uint8_t* buffer) override;

View File

@ -0,0 +1,26 @@
#include "oneshotreadwriter.h"
OneShotReadWriter::OneShotReadWriter(uint8_t* toRead) {
this->length = strlen(toRead);
this->buffer = new uint8_t[this->length];
memcpy(this->buffer, toRead, this->length);
}
uint32_t OneShotReadWriter::read(uint32_t count, uint8_t* buffer) {
uint32_t c=0;
while (index < length && c < count) {
buffer[c++] = this->buffer[index++];
}
return c;
}
uint32_t OneShotReadWriter::size() {
return length;
}
uint32_t OneShotReadWriter::seek(uint32_t position) {
index = clamp(0, length, position);
return index;
}

View 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(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

View File

@ -1,37 +1,16 @@
#include "readwriter.h"
ReadWriter::ReadWriter(uint32_t owner) {
this->owner = owner;
uint32_t ReadWriter::read(uint32_t count, uint8_t* buffer){return;}
uint32_t ReadWriter::write(uint32_t count, uint8_t* buffer){return;}
uint32_t ReadWriter::seek(uint32_t position){return;}
uint32_t ReadWriter::size(){return;}
void ReadWriter::open() {
this->opens++;
}
void ReadWriter::giveReadPerm(uint32_t PID) {
this->allowedRead.append(PID);
}
void ReadWriter::giveWritePerm(uint32_t PID) {
this->allowedWrite.append(PID);
}
uint32_t ReadWriter::read(uint32_t count, uint8_t* buffer){}
uint32_t ReadWriter::write(uint32_t count, uint8_t* buffer){}
uint32_t ReadWriter::size(){}
bool ReadWriter::canRead(uint32_t PID) {
if (this->owner == PID)
return true;
if (this->allowedRead.has(PID))
return true;
return false;
}
bool ReadWriter::canWrite(uint32_t PID) {
if (this->owner == PID)
return true;
if (this->allowedWrite.has(PID))
return true;
return false;
void ReadWriter::close() {
this->opens--;
if (this->opens == 0)
delete this;
}

View File

@ -6,21 +6,17 @@
class ReadWriter {
private:
uint32_t owner;
xnoe::linkedlist<uint32_t> allowedRead;
xnoe::linkedlist<uint32_t> allowedWrite;
uint32_t opens=1;
public:
ReadWriter(uint32_t owner);
void giveReadPerm(uint32_t PID);
void giveWritePerm(uint32_t PID);
virtual uint32_t read(uint32_t count, uint8_t* buffer);
virtual uint32_t 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);
void open();
void close();
};
#endif

View File

@ -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) {

View File

@ -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);

View File

@ -1,38 +1,221 @@
#include "terminal.h"
void Terminal::scroll_up() {
// Scroll the entire buffer up.
for (int y = 0; y < (height * pages); y++) {
uint16_t* cline = buffer + y * width;
uint16_t* nline = buffer + (y+1) * width;
for (int x = 0; x < width; x++) {
cline[x] = nline[x];
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;
uint16_t* nline = 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--;
}
// Clear the last line
uint16_t* last_line = buffer + (height * pages - 1) * width;
for (int x = 0; x < width; x++) {
last_line[x] = 0x0720;
}
this->cur_y--;
this->update();
}
void Terminal::putchar(uint32_t ptr, uint8_t c, uint8_t edata) {
// All modifications to the screen are done to the last page.
last_page_pointer[ptr] = c | (edata<<8);
if (active)
putchar_internal(ptr, c, 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[this->cur_y*this->width+this->cur_x] = c | (edata<<8);
if (active)
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(){}
void Terminal::update_cur(){}
void Terminal::putchar_internal(uint32_t ptr, uint8_t c, uint8_t edata) {}
Terminal::Terminal(uint32_t width, uint32_t height, uint32_t pages)
: ReadWriter(0) {
Terminal::Terminal(uint32_t width, uint32_t height, uint32_t pages) {
this->width = width;
this->height = height;
this->pages = pages;
@ -46,21 +229,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 +252,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 +273,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,89 +292,14 @@ 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);
return count;
}
uint32_t Terminal::read(uint32_t count, uint8_t* buffer) {}
uint32_t Terminal::read(uint32_t count, uint8_t* buffer) {return;}
void Terminal::clear_screen() {
for (int i=0; i < width * height * pages; i++) {
@ -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++) {
this->planes[i][pixelindex] = 0;
if (color & (1<<i))
this->planes[i][pixelindex] = trbyte;
else
this->planes[i][pixelindex] = 0;
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;
@ -393,40 +444,37 @@ 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;
void VGAModeTerminal::bufferToVRAM() {
uint32_t count4 = (this->pixelWidth * this->pixelHeight) / 8 / 4;
for (int i=0; i<4; i++) {
outb(0x3c4, 2);
outb(0x3c5, 1<<i);
for (int c=0; c<count4; c++) {
((uint32_t*)terminal->vga_pointer)[c] = ((uint32_t*)terminal->planes[i])[c];
((uint32_t*)this->vga_pointer)[c] = ((uint32_t*)this->planes[i])[c];
}
}
}
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++) {
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,
@ -478,5 +526,86 @@ VGAModeTerminal::VGAModeTerminal(uint8_t* vga_pointer): Terminal(90, 60, 1) {
}
}
Timer::register_event(16, &VGAModeTerminal::bufferToVRAM, this);
Timer::register_event(16, (void(*)(void*))&VGAModeTerminal::bufferToVRAM, this);
}
void BGAModeTerminal::update() {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
putchar_internal(y * width + x, (uint8_t)(current_page_pointer[y * width + x]), (uint8_t)(current_page_pointer[y * width + x]>>8));
}
}
}
void BGAModeTerminal::update_cur() {
// Todo: Implement cursor for VGAModeTerminal
}
void BGAModeTerminal::putchar_internal(uint32_t ptr, uint8_t c, uint8_t edata) {
uint32_t col = ptr % width;
uint32_t row = ptr / width;
uint32_t sx = col * 8;
uint32_t sy = row * 8;
if (c>127)
return;
uint8_t* char_data = font[c];
for (int y=0; y<8; y++)
put_pixels_byte(sx, sy+y, edata, char_data[y]);
}
void BGAModeTerminal::put_pixels_byte(uint32_t x, uint32_t y, uint8_t color, uint8_t pixel_byte) {
uint32_t pixel = y * pixelWidth + x;
for (int i=0; i<8; i++)
if (pixel_byte&(1<<i))
this->fb[pixel+i] = color_map[color&0xf];
else
this->fb[pixel+i] = color_map[(color>>4)&0xf];
}
void BGAModeTerminal::put_pixel(uint32_t x, uint32_t y, uint8_t color) {
// For any pixel we need to write 1 bit to planes 0, 1, 2, and 3
uint32_t pixel = y * pixelWidth + x;
uint32_t pixelindex = pixel / 8;
uint32_t pixelbitindex = pixel % 8;
this->fb[pixel] = color_map[color];
}
void BGAModeTerminal::bufferToVRAM() {
uint32_t c = this->pixelWidth * this->pixelHeight;
uint32_t bank=0;
uint32_t ctr=0;
for (int i=0; i<c; i++) {
if (i%16384 == 0) {
outw(0x1ce, 5);
outw(0x1cf, bank++);
}
((uint32_t*)this->vga_pointer)[i%16384] = ((uint32_t*)this->fb)[i];
}
}
BGAModeTerminal::BGAModeTerminal(uint8_t* vga_pointer): Terminal(0, 0, 1) {
this->vga_pointer = vga_pointer;
this->fb = new uint32_t[pixelWidth * pixelHeight];
this->resize(pixelWidth / 8, pixelHeight / 8, 1);
outw(0x1ce, 4);
outw(0x1cf, 0);
outw(0x1ce, 1);
outw(0x1cf, pixelWidth);
outw(0x1ce, 2);
outw(0x1cf, pixelHeight);
outw(0x1ce, 3);
outw(0x1cf, 32);
outw(0x1ce, 4);
outw(0x1cf, 1);
Timer::register_event(16, (void(*)(void*))&BGAModeTerminal::bufferToVRAM, this);
}

View File

@ -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)(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,29 +84,52 @@ 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);
static void bufferToVRAM(frame_struct* frame, VGAModeTerminal* terminal);
public:
void bufferToVRAM();
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);
public:
void bufferToVRAM();
uint32_t pixelWidth = 720;
uint32_t pixelHeight = 480;
uint8_t* vga_pointer;
uint32_t* fb;
BGAModeTerminal(uint8_t* vga_pointer);
};
#endif

View File

@ -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);
}

View File

@ -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)
}
}

17
src/programs/cat/main.c Normal file
View File

@ -0,0 +1,17 @@
#include "common/common.h"
int main(int argc, char** argv) {
for (int i=1; i<argc; i++) {
if (exists(argv[i])) {
uint32_t fh = fopen(argv[i]);
char buf[128];
uint32_t count;
while (count=read(128, fh, buf))
write(count, 0, buf);
fclose(fh);
} else {
printf("No such file or directory: %s", argv[i]);
break;
}
}
}

7
src/programs/echo/main.c Normal file
View File

@ -0,0 +1,7 @@
#include "common/common.h"
int main(int argc, char** argv) {
for (int i=1; i<argc; i++) {
printf("%s%s", argv[i], (i==argc-1)?"\n":" ");
}
}

11
src/programs/entry.asm Normal file
View File

@ -0,0 +1,11 @@
[BITS 32]
_start:
call __setup
call main
push eax
call die
extern die
extern main
extern __setup

View File

@ -0,0 +1,10 @@
#include "common/common.h"
int main() {
uint32_t pid = fork();
if (pid) {
printf("Parent PID: %d\nChild PID: %d\n", getPID(), pid);
} else {
printf("CHILD: Hello!\n");
}
}

21
src/programs/init/main.c Normal file
View File

@ -0,0 +1,21 @@
#include "common/common.h"
int main() {
// The job of init will be to load the system configuration, mount devices, etc
bindToKeyboard();
char* fn = "/xosh.bin";
uint8_t* argv[] = {
fn,
0
};
uint8_t* envp[] = {
"PATH=/",
0
};
uint32_t xosh_fh = fopen(fn);
uint32_t xosh = execve(xosh_fh, argv, envp);
while (1);
}

View File

@ -0,0 +1,8 @@
#include "common/common.h"
int main(uint32_t argc, char** argv, char** envp) {
printf("Environment: \n");
for (int i=0; envp[i]; i++)
printf("- %s\n", envp[i]);
printf("\n");
}

35
src/programs/ls/main.c Normal file
View File

@ -0,0 +1,35 @@
#include "common/common.h"
char* filetype(FSType t) {
switch (t) {
case File:
return "File";
case Directory:
return "Directory";
case CharacterDev:
return "CharacterDev";
case BlockDev:
return "BlockDev";
case NoExist:
return "NoExist";
}
return "";
}
int main(int argc, char** argv) {
if (argc != 2) {
printf("Usage: %s <directory>", argv[0]);
return 1;
}
char* directory = argv[1];
uint32_t dentsSize = getDentsSize(directory);
FSDirectoryListing* dents = (FSDirectoryListing*)malloc(dentsSize);
getDents(directory, (uint8_t*)dents);
for (int i=0; i<dents->count; i++) {
FSDirectoryEntry e = dents->entries[i];
printf("%.s %d %s\n", e.path.length, e.path.path, e.sizeBytes, filetype(e.type));
}
}

11
src/programs/userspace.ld Normal file
View 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)
}
}

107
src/programs/xosh/main.c Normal file
View File

@ -0,0 +1,107 @@
#include "common/common.h"
void readline(char* buf, uint32_t lim) {
uint32_t idx = 0;
while (1) {
char c;
if (idx == lim) {
printf("\n");
break;
}
if (read(1, 1, &c)) {
if (c == '\n') {
write(1, 0, &c);
break;
} else if (c == '\b') {
if (idx > 0) {
buf[--idx] = 0;
write(1, 0, &c);
}
} else if (c == 0) {
continue;
} else {
buf[idx++] = c;
write(1, 0, &c);
}
}
}
}
typedef enum {
Normal,
StringLiteral,
Escaped
} ParseState;
int main(int argc, char** argv, char** envp) {
// XOSH - The XnoeOS Shell
// XoSH is going to be a simple shell that can be used to execute programs.
printf("Welcome to %s!\n\n", argv[0]);
printf("Environment:\n");
for (int i=0; envp[i]; i++)
printf("- %s\n", envp[i]);
printf("\n");
while (1) {
printf("\x1b[0m# ");
char input[128];
memset(input, 0, 128);
readline(input, 128);
// Parse the input
char* result[32];
uint32_t ridx=0;
memset(result, 0, 32 * sizeof(char));
char c;
uint32_t idx=0;
char* lp = input;
ParseState s = Normal;
while (c=input[idx++]) {
switch (s) {
case Normal:
switch (c) {
case '"':
s = StringLiteral;
break;
case '\\':
s = Escaped;
break;
case ' ':
input[idx-1] = 0;
result[ridx++] = lp;
lp = (char*)(input+idx);
break;
default:
break;
}
break;
case StringLiteral:
if (c == '"') {
s = Normal;
}
break;
case Escaped:
break;
default:
break;
}
}
result[ridx++] = lp;
if (ridx > 0) {
char* programName = result[0];
if (exists(programName)) {
char** argv = result;
uint32_t program = fopen(programName);
uint32_t e = execv(program, argv);
printf("\nExit code: %d\n\n", e);
} else if (strcmp(result[0], "set")) {
if (result[1] && result[2]) setenv(result[1], result[2]);
} else {
printf("No such executable file: `%s`\n\n", programName);
}
}
}
}

View File

@ -1,283 +0,0 @@
#include "../common/common.h"
#include <stdbool.h>
typedef struct {
char* buffer;
int x;
int y;
uint32_t process;
uint32_t stdin;
uint32_t stdout;
} procbuffer;
void scrollBuffer(char* buf) {
for (int y=0; y<56; y++)
for (int x=0; x<43; x++)
if (y != 55)
buf[y*43+x] = buf[(y+1)*43+x];
else
buf[y*43+x] = ' ';
}
void writeToBuf(char c, procbuffer* buf) {
switch (c) {
case '\n':
buf->x = 0;
buf->y++;
break;
case '\b':
if (buf->x > 0)
buf->x--;
else if (buf->y > 0) {
buf->x = 42;
buf->y--;
}
buf->buffer[buf->y*43+buf->x] = ' ';
break;
default:
buf->buffer[buf->y*43+buf->x++] = c;
}
if (buf->x == 43) {
buf->x = 0;
buf->y++;
}
if (buf->y == 56) {
buf->y--;
scrollBuffer(buf->buffer);
}
}
void writeCountToBuf(int count, char* c, procbuffer* buf) {
while (count--) {
writeToBuf(*(c++), buf);
}
}
void clearBuf(procbuffer* buf) {
for (int i=0; i<56*43;i++) {
buf->buffer[i] = ' ';
}
buf->x = 0;
buf->y = 0;
}
void writeStrToBuf(char* c, procbuffer* b) {
char* s = c;
while(*s)
writeToBuf(*(s++), b);
}
void displayBuf(procbuffer* b, int dx, int dy) {
char pset[9] = "\x1b[00;00H";
for (int i=0; i<dy;i++) {
pset[3]++;
if (pset[3] == 0x3a) {
pset[3] = 0x30;
pset[2]++;
}
}
for (int i=0; i<dx;i++) {
pset[6]++;
if (pset[6] == 0x3a) {
pset[6] = 0x30;
pset[5]++;
}
}
for (int i=0; i<56; i++) {
print(pset);
write(43, 0, b->buffer+(43*i));
pset[3]++;
if (pset[3] == 0x3a) {
pset[3] = 0x30;
pset[2]++;
}
}
}
void setCurPos(int x, int y) {
char pset[9] = "\x1b[00;00H";
for (int i=0; i<y;i++) {
pset[3]++;
if (pset[3] == 0x3a) {
pset[3] = 0x30;
pset[2]++;
}
}
for (int i=0; i<x;i++) {
pset[6]++;
if (pset[6] == 0x3a) {
pset[6] = 0x30;
pset[5]++;
}
}
print(pset);
}
void readline(int count, char* buffer) {
int index = 0;
char c;
while (index < count) {
if (read(1, 1, &c)) {
if (c == '\n')
break;
if (c == '\b') {
if (index == 0)
continue;
else {
index--;
buffer[index] = 0;
write(1, 0, &c);
continue;
}
}
buffer[index++] = c;
write(1, 0, &c);
}
}
}
bool strcmp(char* a, char* b) {
int index=0;
while (a[index])
if (a[index] == b[index])
index++;
else
return false;
return true;
}
bool strcmpcnt(int count, char* a, char* b) {
int index=0;
while (index < count)
if (a[index] == b[index])
index++;
else
return false;
return true;
}
int main() {
bindToKeyboard();
char space = ' ';
char plus = '+';
print("\x1b[1;1H");
for (int i=0; i < 1000; i++)
write(1, 0, &space);
print("\x1b[1;1H");
char* mid = "+ ++ +";
char* bottom = "+ +";
for (int i=0; i<90;i++)
write(1, 0, &plus);
for (int i=0; i<56;i++)
write(90, 0, mid);
for (int i=0; i<90;i++)
write(1, 0, &plus);
write(90, 0, bottom);
for (int i=0; i<90;i++)
write(1, 0, &plus);
uint32_t program = fopen("hello.bin");
uint32_t p1 = fork(program);
uint32_t p1out = bindStdout(p1);
uint32_t p1in = bindStdin(p1);
fclose(program);
program = fopen("hello.bin");
uint32_t p2 = fork(program);
uint32_t p2out = bindStdout(p2);
uint32_t p2in = bindStdin(p2);
fclose(program);
procbuffer b1 = {
.buffer = localalloc(56 * 43),
.x = 0,
.y = 0,
.process = p1,
.stdin = p1in,
.stdout = p1out
};
procbuffer b2 = {
.buffer = localalloc(56 * 43),
.x = 0,
.y = 0,
.process = p2,
.stdin = p2in,
.stdout = p2out
};
procbuffer* selectedBuf = &b1;
writeStrToBuf("XoSH (XOS SHell) v0.0.1\nPress : to use commands.\n :help for help.\n", &b1);
while (1) {
char c[128];
int succ = 0;
if (b1.process)
if (succ = read(128, b1.stdout, c))
writeCountToBuf(succ, c, &b1);
if (b2.process)
if (succ = read(128, b2.stdout, c))
writeCountToBuf(succ, c, &b2);
if (read(1, 1, c)) {
if (c[0] == ':') {
char buf[32] = {0};
print("\x1b[59;2H");
print(": ");
print("\x1b[59;3H");
readline(32, buf);
if (strcmpcnt(6, buf, "switch")) {
if (selectedBuf == &b1) {
selectedBuf = &b2;
} else {
selectedBuf = &b1;
}
} else if (strcmpcnt(4, buf, "help")) {
writeStrToBuf("\n--------\n", selectedBuf);
writeStrToBuf(":help\n", selectedBuf);
writeStrToBuf(" Displays this message.\n", selectedBuf);
writeStrToBuf(":switch\n", selectedBuf);
writeStrToBuf(" Switches which process you're using\n", selectedBuf);
writeStrToBuf(":kill\n", selectedBuf);
writeStrToBuf(" Kills the current process\n", selectedBuf);
writeStrToBuf(":load <filename>\n", selectedBuf);
writeStrToBuf(" Loads and executes the program <filename>\n", selectedBuf);
writeStrToBuf("--------\n", selectedBuf);
} else if (strcmpcnt(4, buf, "kill")) {
if (selectedBuf->process) {
kill(selectedBuf->process);
clearBuf(selectedBuf);
selectedBuf->process = 0;
selectedBuf->stdin = 0;
selectedBuf->stdout = 0;
if (selectedBuf == &b1) {
selectedBuf = &b2;
} else {
selectedBuf = &b1;
}
}
} else if (strcmpcnt(4, buf, "load")) {
if (!selectedBuf->process) {
char* potFn = buf+5;
uint32_t fh = fopen(potFn);
selectedBuf->process = fork(fh);
selectedBuf->stdout = bindStdout(selectedBuf->process);
selectedBuf->stdin = bindStdin(selectedBuf->process);
fclose(fh);
}
}
} else {
if (selectedBuf->process)
write(1, selectedBuf->stdin, c);
}
}
displayBuf(&b1, 2, 2);
displayBuf(&b2, 47, 2);
}
}

View File

@ -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)
}
}