Various additions
This commit is contained in:
parent
b00f6d6217
commit
5a70976f5d
2
Makefile
2
Makefile
@ -96,4 +96,4 @@ src/kernel/isr.S: src/kernel/isr.S.base src/kernel/gen_isr_asm.sh
|
||||
|
||||
.SECONDEXPANSION:
|
||||
build/programs/%.bin: src/programs/userspace.ld build/programs/entry.o $$(src/programs/$$(basename $$(notdir $$*))_OBJS) $(PROGRAM_COMMON)
|
||||
ld -o $@ -T $^
|
||||
ld -o $@ -T $^
|
||||
|
@ -3,6 +3,7 @@
|
||||
_start:
|
||||
mov ax, 10h
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov ss, ax
|
||||
mov esp, 90000h
|
||||
|
||||
|
@ -19,6 +19,63 @@
|
||||
|
||||
#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;
|
||||
@ -59,6 +116,10 @@ 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);
|
||||
@ -68,23 +129,48 @@ void printf(const char* string, ...) {
|
||||
|
||||
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);
|
||||
printf(decimal_buffer + offset);
|
||||
print(decimal_buffer + offset);
|
||||
break;
|
||||
}
|
||||
case 'x': {
|
||||
char hex_buffer[8];
|
||||
offset = int_to_hex(va_arg(ptr, int), hex_buffer);
|
||||
printf(hex_buffer);
|
||||
print(hex_buffer);
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
printf(va_arg(ptr, const char*));
|
||||
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': {
|
||||
@ -102,4 +188,24 @@ void printf(const char* string, ...) {
|
||||
}
|
||||
|
||||
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) {
|
||||
char* zero = 0;
|
||||
return execve(fh, &zero, environ);
|
||||
}
|
||||
|
||||
uint32_t execv(uint32_t fh, char** argv) {
|
||||
char* zero = 0;
|
||||
return execve(fh, argv, environ);
|
||||
}
|
@ -40,9 +40,19 @@ typedef struct {
|
||||
|
||||
#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);
|
||||
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
|
@ -7,9 +7,9 @@ syscall_hdlr_1(FSType, type, "3", char*, path);
|
||||
syscall_hdlr_1(void*, malloc, "4", uint32_t, size);
|
||||
syscall_hdlr_1(void, free, "5", void*, ptr);
|
||||
syscall_hdlr_0(uint32_t, getMillisecondsElapsed, "6");
|
||||
syscall_hdlr_1(uint32_t, exec, "7", uint32_t, filehandler);
|
||||
syscall_hdlr_3(uint32_t, execve, "7", uint32_t, fh, uint8_t**, argv, uint8_t**, envp);
|
||||
syscall_hdlr_0(uint32_t, getPID, "8");
|
||||
syscall_hdlr_0(void, die, "9");
|
||||
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");
|
||||
@ -22,10 +22,10 @@ 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_1(void, spawnThread, "24", uint32_t, functionPointer);
|
||||
syscall_hdlr_0(uint32_t, fork, "25");
|
||||
syscall_hdlr_1(bool, programRunning, "26", uint32_t, pid);
|
||||
|
@ -102,9 +102,8 @@ void ATA::ATAWrite(uint32_t sector, uint8_t* buffer) {
|
||||
driveLock.unlock();
|
||||
}
|
||||
|
||||
ATAReadWriter::ATAReadWriter(uint32_t owner, uint32_t bus):
|
||||
ATA(bus),
|
||||
ReadWriter(owner) {
|
||||
ATAReadWriter::ATAReadWriter(uint32_t bus):
|
||||
ATA(bus) {
|
||||
this->currentPosition = 0;
|
||||
}
|
||||
|
||||
@ -166,4 +165,5 @@ uint32_t ATAReadWriter::size() {
|
||||
}
|
||||
uint32_t ATAReadWriter::seek(uint32_t position) {
|
||||
this->currentPosition = position;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ private:
|
||||
Spinlock driveLock;
|
||||
|
||||
public:
|
||||
ATAReadWriter(uint32_t owner, uint32_t bus);
|
||||
ATAReadWriter(uint32_t bus);
|
||||
|
||||
uint32_t read(uint32_t count, uint8_t* buffer) override;
|
||||
uint32_t write(uint32_t count, uint8_t* buffer) override;
|
||||
@ -107,4 +107,4 @@ public:
|
||||
uint32_t seek(uint32_t position) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@ -21,6 +21,14 @@ namespace xnoe {
|
||||
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();
|
||||
|
@ -59,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "devfs.h"
|
||||
|
||||
DevFS::DevFS() {
|
||||
addEntry(createPathFromString("ata"), [](){return new ATAReadWriter(0,0);});
|
||||
addEntry(createPathFromString("ata"), [](){return new ATAReadWriter(0);});
|
||||
}
|
@ -11,8 +11,7 @@ uint32_t FAT16FileReadWriter::offsetBytesToCluster(uint32_t offset) {
|
||||
return cluster;
|
||||
}
|
||||
|
||||
FAT16FileReadWriter::FAT16FileReadWriter(uint32_t owner, uint32_t firstCluster, uint32_t sizeBytes, FAT16FS* backingFS)
|
||||
: ReadWriter(owner) {
|
||||
FAT16FileReadWriter::FAT16FileReadWriter(uint32_t firstCluster, uint32_t sizeBytes, FAT16FS* backingFS) {
|
||||
this->firstCluster = firstCluster;
|
||||
this->sizeBytes = sizeBytes;
|
||||
this->currentPosition = 0;
|
||||
@ -55,7 +54,7 @@ uint32_t FAT16FileReadWriter::read(uint32_t count, uint8_t* buffer) {
|
||||
return index;
|
||||
}
|
||||
|
||||
uint32_t FAT16FileReadWriter::write(uint32_t count, uint8_t* buffer) {}
|
||||
uint32_t FAT16FileReadWriter::write(uint32_t count, uint8_t* buffer) {return;}
|
||||
|
||||
uint32_t FAT16FileReadWriter::size() {
|
||||
return this->sizeBytes;
|
||||
@ -78,7 +77,7 @@ char safeUppercase(char c) {
|
||||
}
|
||||
}
|
||||
|
||||
bool FAT16FS::pathEntryTo83(PathEntry pe, char* buffer) {
|
||||
void FAT16FS::pathEntryTo83(PathEntry pe, char* buffer) {
|
||||
uint32_t maxSize = pe.length;
|
||||
uint8_t* data = pe.path;
|
||||
|
||||
@ -244,7 +243,8 @@ bool FAT16FS::exists(Path p) {
|
||||
if (!end)
|
||||
return false;
|
||||
|
||||
char name83[11] = {' '};
|
||||
char name83[12] = " ";
|
||||
name83[11] = 0;
|
||||
pathEntryTo83(end->elem, name83);
|
||||
for (int i=0; i<count; i++) {
|
||||
if (strcmp(directoryEntries[i].name, name83, 11)) {
|
||||
@ -271,7 +271,7 @@ FSType FAT16FS::type(Path p) {
|
||||
if (!end)
|
||||
return NoExist;
|
||||
|
||||
char name83[11] = {' '};
|
||||
char name83[12] = " ";
|
||||
pathEntryTo83(end->elem, name83);
|
||||
for (int i=0; i<count; i++) {
|
||||
if (strcmp(directoryEntries[i].name, name83, 11)) {
|
||||
@ -307,7 +307,7 @@ ReadWriter* FAT16FS::open(Path p) {
|
||||
for (int i=0; i<count; i++) {
|
||||
if (strcmp(directoryEntries[i].name, name83, 11)) {
|
||||
if (!directoryEntries[i].directory)
|
||||
return new FAT16FileReadWriter(0, ((uint32_t)directoryEntries[i].firstClusterHigh << 16) | directoryEntries[i].firstClusterLow, directoryEntries[i].size, this);
|
||||
return new FAT16FileReadWriter(((uint32_t)directoryEntries[i].firstClusterHigh << 16) | directoryEntries[i].firstClusterLow, directoryEntries[i].size, this);
|
||||
}
|
||||
}
|
||||
delete directoryEntries;
|
||||
@ -398,4 +398,4 @@ void FAT16FS::getDents(Path p, FSDirectoryListing* buffer) {
|
||||
}
|
||||
|
||||
delete directoryEntries;
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ private:
|
||||
|
||||
FAT16FS* backingFS;
|
||||
public:
|
||||
FAT16FileReadWriter(uint32_t owner, uint32_t firstCluster, uint32_t sizeBytes, FAT16FS* backingFS);
|
||||
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;
|
||||
@ -96,7 +96,7 @@ public:
|
||||
|
||||
ReadWriter* backingDevice;
|
||||
|
||||
bool pathEntryTo83(PathEntry pe, char* buffer);
|
||||
void pathEntryTo83(PathEntry pe, char* buffer);
|
||||
|
||||
uint32_t clusterToSector(uint32_t cluster);
|
||||
void load_file(uint32_t location, uint8_t* destination);
|
||||
@ -116,4 +116,4 @@ public:
|
||||
void getDents(Path p, FSDirectoryListing* buffer) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@ -16,11 +16,11 @@ bool operator!=(const PathEntry& lhs, const PathEntry& rhs) {
|
||||
}
|
||||
|
||||
// FS Tree Skeleton
|
||||
bool FSTree::exists(Path p){}
|
||||
FSType FSTree::type(Path p){}
|
||||
ReadWriter* FSTree::open(Path p){}
|
||||
uint32_t FSTree::getDentsSize(Path p){}
|
||||
void FSTree::getDents(Path p, FSDirectoryListing* buffer){}
|
||||
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
|
||||
|
||||
@ -267,4 +267,4 @@ Path createPathFromString(char* s) {
|
||||
if (length)
|
||||
p.append(PathEntry{length, lastPtr});
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
@ -5,24 +5,24 @@ SysFS::SysFS() {
|
||||
uint32_t remainingPages = Global::kernel->phys->remainingPages;
|
||||
char str[11];
|
||||
uint32_t offset = int_to_decimal(remainingPages, str);
|
||||
return new OneShotReadWriter(0, str+offset);
|
||||
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(0, str+offset);
|
||||
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(0, str+offset);
|
||||
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(0, str+offset);
|
||||
return new OneShotReadWriter(str+offset);
|
||||
});
|
||||
}
|
@ -80,7 +80,7 @@ nextPE:
|
||||
}
|
||||
|
||||
bool VFS::exists(Path p) {
|
||||
return false;
|
||||
return getEntry(p);
|
||||
}
|
||||
|
||||
ReadWriter* VFS::open(Path p) {
|
||||
|
@ -22,35 +22,37 @@ 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("\x1b[44;37;1m(CS %x EIP %x): ", frame->cs, frame->eip);*/
|
||||
Global::kernel->terminal->printf("\x1b[44;37;1m(CS %x EIP %x): ", frame->cs, frame->eip);
|
||||
switch (frame->gate) {
|
||||
case 0: // Divide by zero
|
||||
//Global::kernel->terminal->printf("Divide by Zero");
|
||||
Global::kernel->terminal->printf("Divide by Zero");
|
||||
break;
|
||||
case 6: // Invalid Opcode
|
||||
//Global::kernel->terminal->printf("Invalid Opcode");
|
||||
Global::kernel->terminal->printf("Invalid Opcode");
|
||||
break;
|
||||
case 13: // GPF
|
||||
//Global::kernel->terminal->printf("General Protection Fault!");
|
||||
Global::kernel->terminal->printf("General Protection Fault!");
|
||||
if (frame->eflags & 0x00020000) {
|
||||
v86_monitor((v8086_frame_struct*)frame);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 14: // Page Fault
|
||||
//Global::kernel->terminal->printf("Page Fault at %x", problem_address);
|
||||
Global::kernel->terminal->printf("Page Fault at %x", problem_address);
|
||||
break;
|
||||
default:
|
||||
//Global::kernel->terminal->printf("Unkown Fault!");
|
||||
Global::kernel->terminal->printf("Unkown Fault! Gate: %d", frame->gate);
|
||||
break;
|
||||
}
|
||||
/*Global::kernel->terminal->printf(" Error Code: %x\n", frame->errcode);*/
|
||||
Global::kernel->terminal->printf(" Error Code: %x\n", frame->errcode);
|
||||
if (!(frame->cs & 3)) {
|
||||
Global::kernel->terminal->printf("[FATAL] Kernel Fault!!!\n");
|
||||
((VGAModeTerminal*)Global::kernel->terminal)->bufferToVRAM();
|
||||
while (1) asm("hlt");
|
||||
} else {
|
||||
// Print an error message.
|
||||
@ -62,13 +64,14 @@ void handle_fault(frame_struct* frame) {
|
||||
Global::kernel->destroyProcess(Global::currentProc);
|
||||
|
||||
Global::currentProcValid = false;
|
||||
context_switch(frame);
|
||||
context_switch();
|
||||
}
|
||||
}
|
||||
|
||||
void ignore_interrupt(frame_struct* frame) {}
|
||||
void ignore_interrupt() {}
|
||||
|
||||
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
|
||||
//
|
||||
@ -90,9 +93,6 @@ void context_switch(frame_struct* frame) {
|
||||
Global::kernel->terminal->printf("[FATAL] No more processes! Halting!\n");
|
||||
while (1) asm ("hlt");
|
||||
}
|
||||
|
||||
if (Global::currentProcValid)
|
||||
Global::currentThread->kernelStackPtr = frame->new_esp;
|
||||
|
||||
// This cursed bit of code first determines if the processes list is longer than 1 and if it is
|
||||
// - Determines if it has 2 or more elements
|
||||
@ -128,11 +128,8 @@ void context_switch(frame_struct* frame) {
|
||||
Global::currentProc = threads->start->elem->parent;
|
||||
} while (Global::currentThread->state != Running);
|
||||
|
||||
|
||||
// Select the next processes page directory
|
||||
frame->new_cr3 = Global::currentThread->parent->PD->phys_addr;
|
||||
// Restore kernelStackPtr of the new process.
|
||||
frame->new_esp = Global::currentThread->kernelStackPtr;
|
||||
Global::currentThread->frame.new_cr3 = Global::currentThread->parent->PD->phys_addr;
|
||||
|
||||
Global::tss->esp0 = Global::currentThread->kernelStackPtrDefault;
|
||||
|
||||
@ -142,15 +139,15 @@ void context_switch(frame_struct* frame) {
|
||||
|
||||
namespace Timer {
|
||||
// counter, default count, function, argument, oneshot
|
||||
using TimedEvent = xnoe::tuple<uint32_t, uint32_t, void(*)(frame_struct*, void*), void*, bool>;
|
||||
using TimedEvent = xnoe::tuple<uint32_t, uint32_t, void(*)(void*), void*, bool>;
|
||||
xnoe::linkedlist<TimedEvent> timed_events;
|
||||
void tick(frame_struct* frame) {
|
||||
void tick() {
|
||||
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)) {
|
||||
@ -167,16 +164,16 @@ namespace Timer {
|
||||
Global::milliseconds_elapsed++;
|
||||
}
|
||||
|
||||
void register_event(uint32_t milliseconds, void(*function)(frame_struct*, void*), void* auxiliary, bool oneshot=false) {
|
||||
void register_event(uint32_t milliseconds, void(*function)(void*), void* auxiliary, bool oneshot=false) {
|
||||
timed_events.append(TimedEvent(milliseconds, milliseconds, function, auxiliary, oneshot));
|
||||
}
|
||||
}
|
||||
|
||||
void awaken(frame_struct* frame, Thread* t) {
|
||||
void awaken(Thread* t) {
|
||||
t->state = Running;
|
||||
}
|
||||
|
||||
void syscall(frame_struct* frame) {
|
||||
void syscall() {
|
||||
// Syscall ABI:
|
||||
// 0: getDentsSize :: char* path -> uint32_t size
|
||||
// 1: getDents :: char* path -> uint8_t* buffer -> void
|
||||
@ -214,87 +211,93 @@ void syscall(frame_struct* frame) {
|
||||
// 2..7: Reserved
|
||||
// _: General use
|
||||
|
||||
uint32_t rval = frame->eax;
|
||||
frame_struct* frame = &Global::currentThread->frame;
|
||||
|
||||
Process* currentProc = Global::currentProc;
|
||||
|
||||
switch (frame->eax) {
|
||||
case 0: // getDentsSize
|
||||
rval = Global::kernel->rootfs->getDentsSize(createPathFromString(frame->ebx));
|
||||
frame->eax = Global::kernel->rootfs->getDentsSize(createPathFromString(frame->ebx));
|
||||
break;
|
||||
case 1: // getDents
|
||||
Global::kernel->rootfs->getDents(createPathFromString(frame->ebx), frame->ecx);
|
||||
break;
|
||||
case 2: // exists
|
||||
rval = Global::kernel->rootfs->exists(createPathFromString(frame->ebx));
|
||||
frame->eax = Global::kernel->rootfs->exists(createPathFromString(frame->ebx));
|
||||
break;
|
||||
case 3: // type
|
||||
rval = Global::kernel->rootfs->type(createPathFromString(frame->ebx));
|
||||
frame->eax = Global::kernel->rootfs->type(createPathFromString(frame->ebx));
|
||||
break;
|
||||
case 4: // malloc
|
||||
rval = currentProc->allocate(frame->ebx);
|
||||
frame->eax = currentProc->allocate(frame->ebx);
|
||||
break;
|
||||
case 5: // free
|
||||
currentProc->deallocate(frame->ebx);
|
||||
break;
|
||||
case 6: // getMillisecondsElapsed
|
||||
rval = Global::milliseconds_elapsed;
|
||||
frame->eax = Global::milliseconds_elapsed;
|
||||
break;
|
||||
case 7: { // exec
|
||||
|
||||
case 7: {// execve
|
||||
asm("cli");
|
||||
xnoe::maybe<ReadWriter*> file = Global::currentProc->getFH(frame->ebx);
|
||||
if (file.is_ok()) {
|
||||
Process* p = Global::kernel->createProcess(file.get());
|
||||
rval = p->PID;
|
||||
Process* p = Global::kernel->createProcess(file.get(), (uint8_t**)frame->ecx, (uint8_t**)frame->edx);
|
||||
|
||||
// Suspend the current thread and forward the current process's stdin and stdout to the new one.
|
||||
Global::currentThread->state = Suspended;
|
||||
p->stdin = Global::currentProc->stdin;
|
||||
p->stdout = Global::currentProc->stdout;
|
||||
p->threads.start->elem->suspending = Global::currentThread->TID;
|
||||
context_switch();
|
||||
} else {
|
||||
rval = 0;
|
||||
frame->eax = 0;
|
||||
}
|
||||
asm("sti");
|
||||
break;
|
||||
}
|
||||
|
||||
case 8: // getPID
|
||||
rval = currentProc->PID;
|
||||
frame->eax = currentProc->PID;
|
||||
break;
|
||||
|
||||
case 9: // die
|
||||
case 9: { // die
|
||||
Global::kernel->PD->select();
|
||||
|
||||
// We can now safely delete the current process
|
||||
Global::kernel->destroyProcess(Global::currentProc);
|
||||
|
||||
Global::kernel->destroyProcess(Global::currentProc, frame->ebx);
|
||||
Global::currentProcValid = false;
|
||||
context_switch(frame);
|
||||
break;
|
||||
context_switch();
|
||||
return;
|
||||
}
|
||||
|
||||
case 10: { // read
|
||||
xnoe::maybe<ReadWriter*> fh = Global::currentProc->getFH(frame->ecx);
|
||||
if (!fh.is_ok()) {
|
||||
rval = 0;
|
||||
frame->eax = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
ReadWriter* rw = fh.get();
|
||||
rval = rw->read(frame->ebx, frame->edx);
|
||||
frame->eax = rw->read(frame->ebx, frame->edx);
|
||||
break;
|
||||
}
|
||||
|
||||
case 11: { // write
|
||||
xnoe::maybe<ReadWriter*> fh = Global::currentProc->getFH(frame->ecx);
|
||||
if (!fh.is_ok()) {
|
||||
rval = 0;
|
||||
frame->eax = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
ReadWriter* rw = fh.get();
|
||||
rval = rw->write(frame->ebx, frame->edx);
|
||||
frame->eax = rw->write(frame->ebx, frame->edx);
|
||||
break;
|
||||
}
|
||||
|
||||
case 12: // bindToKeyboard
|
||||
if (currentProc->stdin)
|
||||
break;
|
||||
currentProc->stdin->close();
|
||||
|
||||
currentProc->stdin = new CircularRWBuffer(currentProc->PID, 0);
|
||||
currentProc->stdin = new CircularRWBuffer();
|
||||
Global::kernel->KBListeners.append(currentProc);
|
||||
break;
|
||||
|
||||
@ -303,11 +306,12 @@ void syscall(frame_struct* frame) {
|
||||
if (!pm.is_ok())
|
||||
break;
|
||||
Process* p = pm.get();
|
||||
if (!p->stdout) {
|
||||
ReadWriter* buffer = new CircularRWBuffer(currentProc->PID, frame->ebx);
|
||||
p->stdout = buffer;
|
||||
rval = Global::currentProc->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;
|
||||
}
|
||||
|
||||
@ -316,25 +320,26 @@ void syscall(frame_struct* frame) {
|
||||
if (!pm.is_ok())
|
||||
break;
|
||||
Process* p = pm.get();
|
||||
if (!p->stdin) {
|
||||
ReadWriter* buffer = new CircularRWBuffer(frame->ebx, currentProc->PID);
|
||||
p->stdin = buffer;
|
||||
rval = Global::currentProc->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: { // fopen
|
||||
ReadWriter* file = Global::kernel->rootfs->open(createPathFromString(frame->ebx));
|
||||
if (file)
|
||||
rval = Global::currentProc->mapFH(file);
|
||||
frame->eax = Global::currentProc->mapFH(file);
|
||||
break;
|
||||
}
|
||||
|
||||
case 16: { // fclose
|
||||
xnoe::maybe<ReadWriter*> f = Global::currentProc->getFH(frame->ebx);
|
||||
if (f.is_ok()) {
|
||||
delete f.get();
|
||||
f.get()->close();
|
||||
Global::currentProc->unmapFH(frame->ebx);
|
||||
}
|
||||
break;
|
||||
@ -354,45 +359,61 @@ void syscall(frame_struct* frame) {
|
||||
case 18: { // sleep
|
||||
Global::currentThread->state = Suspended;
|
||||
Timer::register_event(frame->ebx, &awaken, (void*)Global::currentThread, true);
|
||||
context_switch(frame);
|
||||
context_switch();
|
||||
break;
|
||||
}
|
||||
|
||||
case 19: // getRemainingPages
|
||||
rval = Global::kernel->phys->remainingPages;
|
||||
frame->eax = Global::kernel->phys->remainingPages;
|
||||
break;
|
||||
case 20: // getInitPages
|
||||
rval = Global::kernel->phys->initPages;
|
||||
frame->eax = Global::kernel->phys->initPages;
|
||||
break;
|
||||
|
||||
case 21: // getTerminalWidth
|
||||
rval = Global::kernel->terminal->width;
|
||||
frame->eax = Global::kernel->terminal->width;
|
||||
break;
|
||||
case 22: // getTerminalHeight
|
||||
rval = Global::kernel->terminal->height;
|
||||
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();
|
||||
//rval = proc->state;
|
||||
//frame->eax = proc->state;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 24: { // Spawn Thread
|
||||
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(frame->ebx, thread->stack);
|
||||
Global::kernel->threads.append(thread);
|
||||
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) {
|
||||
|
@ -7,32 +7,6 @@
|
||||
#include "gdt.h"
|
||||
#include "stdio/circularrwbuffer.h"
|
||||
|
||||
struct __attribute__((packed)) frame_struct {
|
||||
uint32_t new_cr3;
|
||||
uint32_t new_esp;
|
||||
|
||||
uint32_t edi;
|
||||
uint32_t esi;
|
||||
uint32_t ebp;
|
||||
uint32_t oesp;
|
||||
uint32_t ebx;
|
||||
uint32_t edx;
|
||||
uint32_t ecx;
|
||||
uint32_t eax;
|
||||
|
||||
uint32_t gate;
|
||||
uint32_t __ignored2;
|
||||
uint32_t errcode;
|
||||
|
||||
uint32_t eip;
|
||||
uint16_t cs;
|
||||
uint16_t _ignored0;
|
||||
uint32_t eflags;
|
||||
uint32_t esp;
|
||||
uint16_t ss;
|
||||
uint16_t _ignored1;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) v8086_frame_struct {
|
||||
uint32_t new_cr3;
|
||||
uint32_t new_esp;
|
||||
@ -90,10 +64,10 @@ struct __attribute__((packed)) idt_desc {
|
||||
uint32_t offset;
|
||||
};
|
||||
|
||||
void context_switch(frame_struct* frame);
|
||||
void context_switch();
|
||||
void handle_fault(frame_struct* frame);
|
||||
void syscall(frame_struct* frame);
|
||||
void ignore_interrupt(frame_struct* frame);
|
||||
void syscall();
|
||||
void ignore_interrupt();
|
||||
void v86_monitor(v8086_frame_struct* frame);
|
||||
|
||||
#endif
|
@ -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 outb
|
||||
extern _ZN6Global13currentThreadE
|
||||
|
@ -1,13 +1,12 @@
|
||||
#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;
|
||||
|
||||
@ -16,38 +15,117 @@ Kernel::Kernel(PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint
|
||||
|
||||
void Kernel::init_kernel() {
|
||||
this->pid_map = new xnoe::hashtable<uint32_t, Process*>();
|
||||
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(ReadWriter* file) {
|
||||
char* name = "test";
|
||||
Process* p = new Process(currentPID, this->PD, 0xc0000000, file, 1, &name);
|
||||
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->threads.append(p->threads.start->elem);
|
||||
// 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(ReadWriter* file, ReadWriter* stdout) {
|
||||
Process* p = this->createProcess(file);
|
||||
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;
|
||||
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) {
|
||||
this->threads.remove(currentThread->elem);
|
||||
destroyThread(currentThread->elem, exit_code);
|
||||
currentThread = currentThread->next;
|
||||
}
|
||||
this->pid_map->remove(p->PID);
|
||||
delete p;
|
||||
}
|
||||
|
||||
void Kernel::registerThread(Thread* t) {
|
||||
this->threads.append(t);
|
||||
this->tid_map->set(t->TID, t);
|
||||
}
|
||||
|
||||
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::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] = {
|
||||
|
@ -12,12 +12,12 @@ 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;
|
||||
@ -28,9 +28,13 @@ public:
|
||||
|
||||
void init_kernel();
|
||||
|
||||
Process* createProcess(ReadWriter* file);
|
||||
Process* createProcess(ReadWriter* file, 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);
|
||||
|
||||
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);
|
||||
};
|
||||
|
@ -55,15 +55,14 @@ int main(KernelInformationStruct kstruct) {
|
||||
|
||||
term->printf("KERNEL OK!\n");
|
||||
|
||||
ReadWriter* atareadwriter = new ATAReadWriter(0, 0);
|
||||
|
||||
kernel.rootfs = new RootFSTree();
|
||||
kernel.rootfs->mount(createPathFromString("/dev"), new DevFS());
|
||||
kernel.rootfs->mount(createPathFromString("/sys"), new SysFS());
|
||||
kernel.rootfs->mount(createPathFromString("/"), new FAT16FS(kernel.rootfs->open(createPathFromString("/dev/ata"))));
|
||||
ReadWriter* worldbin = kernel.rootfs->open(createPathFromString("/world.bin"));
|
||||
ReadWriter* init = kernel.rootfs->open(createPathFromString("/init.bin"));
|
||||
|
||||
Process* p1 = kernel.createProcess(worldbin, term);
|
||||
char* zero = 0;
|
||||
Process* p1 = kernel.createProcess(init, &zero, term);
|
||||
|
||||
Global::tss->esp0 = (new uint8_t[8192]) + 8192;
|
||||
|
||||
@ -71,4 +70,4 @@ int main(KernelInformationStruct kstruct) {
|
||||
enable_idt();
|
||||
|
||||
while (1) asm ("hlt");
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
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::linkedlistelem<AllocTracker>* current = this->allocations.start;
|
||||
@ -16,27 +17,29 @@ xnoe::maybe<xnoe::linkedlistelem<AllocTracker>*> Process::get_alloc_tracker(uint
|
||||
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;
|
||||
}
|
||||
|
||||
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->file_handlers = new xnoe::dynarray<ReadWriter*>(8);
|
||||
}
|
||||
|
||||
Process::Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase, ReadWriter* filereader, uint32_t argc, char** argv)
|
||||
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->PID = PID;
|
||||
this->PID = this->currentPID++;
|
||||
this->page_remaining = 0;
|
||||
this->last_page_pointer = 0;
|
||||
|
||||
@ -55,17 +58,30 @@ Process::Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase, Rea
|
||||
this->PD->select();
|
||||
|
||||
uint32_t* stack = thread->stack + 0x8000;
|
||||
uint8_t* argenvarea = this->allocate(0x2000);
|
||||
uint32_t argenv = argenvarea + 0x2000;
|
||||
uint8_t* argenvarea = this->allocate(0x2000) + 0x2000;
|
||||
|
||||
// Copy envp
|
||||
// envp is null terminated
|
||||
*(--stack) = 0;
|
||||
for (int i=envc; i>0; i--) {
|
||||
char* s = envp[i-1];
|
||||
uint32_t c = strlen(s);
|
||||
memcpy((uint8_t*)(argenvarea -= c), (uint8_t*)envp[i-1], c);
|
||||
*(--stack) = argenvarea;
|
||||
}
|
||||
uint32_t envp_p = ((uint32_t)stack);
|
||||
|
||||
// Copy argv
|
||||
for (int i=argc; i>0; i--) {
|
||||
char* s = argv[i-1];
|
||||
uint32_t c = 0;
|
||||
while (*(c++, s++));
|
||||
memcpy((uint8_t*)(argenv -= c), (uint8_t*)argv[i-1], c);
|
||||
*(--stack) = argenv;
|
||||
uint32_t c = strlen(s);
|
||||
memcpy((uint8_t*)(argenvarea -= c), (uint8_t*)argv[i-1], c);
|
||||
*(--stack) = argenvarea;
|
||||
}
|
||||
*(--stack) = ((uint32_t)stack);
|
||||
uint32_t argv_p = ((uint32_t)stack);
|
||||
|
||||
*(--stack) = envp_p;
|
||||
*(--stack) = argv_p;
|
||||
*(--stack) = argc;
|
||||
|
||||
filereader->seek(0);
|
||||
@ -78,16 +94,91 @@ Process::Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase, Rea
|
||||
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->kernelStackPtr = (new uint8_t[0x4000]) + 0x4000;
|
||||
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;
|
||||
//delete kernelStackPtr;
|
||||
}
|
||||
|
||||
void Thread::initKernelStack(void* entryPoint, void* esp) {
|
||||
@ -100,19 +191,24 @@ void Thread::initKernelStack(void* entryPoint, void* esp) {
|
||||
*(--stack32) = 0x200; // EFLAGS
|
||||
*(--stack32) = 27; // CS
|
||||
*(--stack32) = (uint32_t)entryPoint; // EIP
|
||||
*(--stack32) = ((uint32_t)esp); // EBP
|
||||
|
||||
uint32_t rEBP = stack32;
|
||||
*(--stack32);
|
||||
*(--stack32);
|
||||
*(--stack32);
|
||||
|
||||
*(--stack32) = 0; // EAX
|
||||
*(--stack32) = 0; // ECX
|
||||
*(--stack32) = 0; // EDX
|
||||
*(--stack32) = 0; // EBX
|
||||
*(--stack32) = 0; // ESP
|
||||
*(--stack32) = rEBP; // EBP
|
||||
*(--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));
|
||||
}
|
||||
@ -134,14 +230,52 @@ Process::~Process() {
|
||||
xnoe::maybe<ReadWriter*> r;
|
||||
if ((r=file_handlers->get(i)).is_ok())
|
||||
if (r.get())
|
||||
delete r.get();
|
||||
r.get()->close();
|
||||
}
|
||||
|
||||
xnoe::linkedlistelem<Thread*>* currentThread = threads.start;
|
||||
/*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) {
|
||||
@ -163,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);
|
||||
|
||||
|
@ -11,28 +11,65 @@
|
||||
#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;
|
||||
void* page_base;
|
||||
uint32_t page_size;
|
||||
uint32_t alloc_count;
|
||||
|
||||
AllocTracker();
|
||||
AllocTracker(void* base, uint32_t size, uint32_t count);
|
||||
};
|
||||
|
||||
@ -41,16 +78,15 @@ private:
|
||||
uint32_t last_page_pointer;
|
||||
uint32_t page_remaining;
|
||||
|
||||
// List of pages this process has allocated
|
||||
xnoe::linkedlist<AllocTracker> allocations;
|
||||
|
||||
xnoe::maybe<xnoe::linkedlistelem<AllocTracker>*> get_alloc_tracker(uint32_t address);
|
||||
|
||||
xnoe::dynarray<ReadWriter*>* file_handlers;
|
||||
|
||||
Path currentWorkingDirectory;
|
||||
|
||||
static uint32_t currentPID;
|
||||
|
||||
public:
|
||||
xnoe::dynarray<ReadWriter*>* file_handlers;
|
||||
|
||||
uint32_t PID;
|
||||
uint32_t esp;
|
||||
|
||||
@ -59,12 +95,18 @@ public:
|
||||
|
||||
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, ReadWriter* filereader, uint32_t argc=0, char** argv=0);
|
||||
// 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;
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "oneshotreadwriter.h"
|
||||
|
||||
OneShotReadWriter::OneShotReadWriter(uint32_t owner, uint8_t* toRead) : ReadWriter(owner) {
|
||||
OneShotReadWriter::OneShotReadWriter(uint8_t* toRead) {
|
||||
this->length = strlen(toRead);
|
||||
|
||||
this->buffer = new uint8_t[this->length];
|
||||
|
@ -12,7 +12,7 @@ private:
|
||||
uint32_t index=0;
|
||||
|
||||
public:
|
||||
OneShotReadWriter(uint32_t owner, uint8_t* toRead);
|
||||
OneShotReadWriter(uint8_t* toRead);
|
||||
|
||||
uint32_t read(uint32_t count, uint8_t* buffer) override;
|
||||
uint32_t size() override;
|
||||
|
@ -1,38 +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::close() {
|
||||
this->opens--;
|
||||
if (this->opens == 0)
|
||||
delete this;
|
||||
}
|
||||
|
||||
void ReadWriter::giveWritePerm(uint32_t PID) {
|
||||
this->allowedWrite.append(PID);
|
||||
}
|
||||
|
||||
uint32_t ReadWriter::read(uint32_t count, uint8_t* buffer){}
|
||||
uint32_t ReadWriter::write(uint32_t count, uint8_t* buffer){}
|
||||
uint32_t ReadWriter::seek(uint32_t position){}
|
||||
uint32_t ReadWriter::size(){}
|
||||
|
||||
bool ReadWriter::canRead(uint32_t PID) {
|
||||
if (this->owner == PID)
|
||||
return true;
|
||||
|
||||
if (this->allowedRead.has(PID))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ReadWriter::canWrite(uint32_t PID) {
|
||||
if (this->owner == PID)
|
||||
return true;
|
||||
|
||||
if (this->allowedWrite.has(PID))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
@ -6,22 +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
|
||||
#endif
|
||||
|
@ -215,8 +215,7 @@ 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;
|
||||
@ -297,9 +296,10 @@ uint32_t Terminal::write(uint32_t count, uint8_t* string) {
|
||||
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++) {
|
||||
@ -444,14 +444,14 @@ 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 = (terminal->pixelWidth * terminal->pixelHeight) / 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];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -526,7 +526,7 @@ for (int i=0; i<4; i++) {
|
||||
}
|
||||
}
|
||||
|
||||
Timer::register_event(16, &VGAModeTerminal::bufferToVRAM, this);
|
||||
Timer::register_event(16, (void(*)(void*))&VGAModeTerminal::bufferToVRAM, this);
|
||||
}
|
||||
|
||||
void BGAModeTerminal::update() {
|
||||
@ -576,8 +576,8 @@ void BGAModeTerminal::put_pixel(uint32_t x, uint32_t y, uint8_t color) {
|
||||
this->fb[pixel] = color_map[color];
|
||||
}
|
||||
|
||||
static void BGAModeTerminal::bufferToVRAM(frame_struct* frame, BGAModeTerminal* terminal) {
|
||||
uint32_t c = terminal->pixelWidth * terminal->pixelHeight;
|
||||
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++) {
|
||||
@ -585,7 +585,7 @@ static void BGAModeTerminal::bufferToVRAM(frame_struct* frame, BGAModeTerminal*
|
||||
outw(0x1ce, 5);
|
||||
outw(0x1cf, bank++);
|
||||
}
|
||||
((uint32_t*)terminal->vga_pointer)[i%16384] = ((uint32_t*)terminal->fb)[i];
|
||||
((uint32_t*)this->vga_pointer)[i%16384] = ((uint32_t*)this->fb)[i];
|
||||
}
|
||||
}
|
||||
|
||||
@ -607,5 +607,5 @@ BGAModeTerminal::BGAModeTerminal(uint8_t* vga_pointer): Terminal(0, 0, 1) {
|
||||
outw(0x1ce, 4);
|
||||
outw(0x1cf, 1);
|
||||
|
||||
Timer::register_event(16, &BGAModeTerminal::bufferToVRAM, this);
|
||||
}
|
||||
Timer::register_event(16, (void(*)(void*))&BGAModeTerminal::bufferToVRAM, this);
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
struct frame_struct;
|
||||
|
||||
namespace Timer {
|
||||
void register_event(uint32_t milliseconds, void(*function)(frame_struct*, void*), void* auxiliary, bool oneshot=false);
|
||||
void register_event(uint32_t milliseconds, void(*function)(void*), void* auxiliary, bool oneshot=false);
|
||||
}
|
||||
|
||||
enum TerminalState {
|
||||
@ -99,10 +99,10 @@ private:
|
||||
|
||||
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;
|
||||
|
||||
@ -120,10 +120,10 @@ private:
|
||||
|
||||
void put_pixel(uint32_t x, uint32_t y, uint8_t color);
|
||||
void put_pixels_byte(uint32_t x, uint32_t y, uint8_t color, uint8_t pixel_byte);
|
||||
|
||||
static void bufferToVRAM(frame_struct* frame, BGAModeTerminal* terminal);
|
||||
|
||||
public:
|
||||
void bufferToVRAM();
|
||||
|
||||
uint32_t pixelWidth = 720;
|
||||
uint32_t pixelHeight = 480;
|
||||
|
||||
|
17
src/programs/cat/main.c
Normal file
17
src/programs/cat/main.c
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
int main() {
|
||||
// Cause a Division by zero by trying to divide by zero.
|
||||
int x = 1 / 0;
|
||||
}
|
7
src/programs/echo/main.c
Normal file
7
src/programs/echo/main.c
Normal 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":" ");
|
||||
}
|
||||
}
|
@ -1,8 +1,11 @@
|
||||
[BITS 32]
|
||||
|
||||
_start:
|
||||
call __setup
|
||||
call main
|
||||
push eax
|
||||
call die
|
||||
|
||||
extern die
|
||||
extern main
|
||||
extern main
|
||||
extern __setup
|
10
src/programs/forktest/main.c
Normal file
10
src/programs/forktest/main.c
Normal 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");
|
||||
}
|
||||
}
|
@ -1,42 +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(int argc, char** argv) {
|
||||
printf("Hi, I am %s, running with PID %d!\n", argv[0], getPID());
|
||||
|
||||
print("Hello, World!\n");
|
||||
char buffer[32];
|
||||
while (1) {
|
||||
for (int i=0; i<32; i++)
|
||||
buffer[i] = 0;
|
||||
print(">>> ");
|
||||
readline(32, buffer);
|
||||
print("You said: ");
|
||||
print(buffer);
|
||||
print("\n\n");
|
||||
}
|
||||
}
|
21
src/programs/init/main.c
Normal file
21
src/programs/init/main.c
Normal 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";
|
||||
char* argv[] = {
|
||||
fn,
|
||||
0
|
||||
};
|
||||
char* envp[] = {
|
||||
"PATH=/",
|
||||
0
|
||||
};
|
||||
uint32_t xosh_fh = fopen(fn);
|
||||
uint32_t xosh = execve(xosh_fh, argv, envp);
|
||||
|
||||
while (1);
|
||||
}
|
8
src/programs/listenvp/main.c
Normal file
8
src/programs/listenvp/main.c
Normal 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
35
src/programs/ls/main.c
Normal 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;
|
||||
}
|
||||
|
||||
char* directory = argv[1];
|
||||
|
||||
uint32_t dentsSize = getDentsSize(directory);
|
||||
FSDirectoryListing* dents = (FSDirectoryListing*)malloc(dentsSize);
|
||||
getDents(directory, dents);
|
||||
|
||||
for (int i=0; i<dents->count; i++) {
|
||||
FSDirectoryEntry e = dents->entries[i];
|
||||
printf("%.s %d %s\n", e.path.length, e.path.path, e.sizeBytes, filetype(e.type));
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
#include "common/common.h"
|
||||
|
||||
int main() {
|
||||
uint32_t crashBin = fopen("/crash.bin");
|
||||
uint32_t pid = getPID();
|
||||
while (1) {
|
||||
printf("Time Elapsed: %dms\n", getMillisecondsElapsed());
|
||||
printf("Init. Pages: %d\nRemaining Pages: %d\n", getInitPages(), getRemainingPages());
|
||||
|
||||
printf("PID 2 State: %s\n", (!getProcessState(2))?"Running":"Suspended");
|
||||
printf("I am PID %d\n", pid);
|
||||
|
||||
//exec(crashBin);
|
||||
sleep(1000);
|
||||
}
|
||||
}
|
@ -1,340 +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;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
} procbuffer;
|
||||
|
||||
void scrollBuffer(procbuffer* buf) {
|
||||
for (int y=0; y<buf->height; y++)
|
||||
for (int x=0; x<buf->width; x++)
|
||||
if (y != buf->height-1)
|
||||
buf->buffer[y*buf->width+x] = buf->buffer[(y+1)*buf->width+x];
|
||||
else
|
||||
buf->buffer[y*buf->width+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 = buf->width-1;
|
||||
buf->y--;
|
||||
}
|
||||
buf->buffer[buf->y*buf->width+buf->x] = ' ';
|
||||
break;
|
||||
|
||||
default:
|
||||
buf->buffer[buf->y*buf->width+buf->x++] = c;
|
||||
}
|
||||
if (buf->x == buf->width) {
|
||||
buf->x = 0;
|
||||
buf->y++;
|
||||
}
|
||||
if (buf->y == buf->height) {
|
||||
buf->y--;
|
||||
scrollBuffer(buf);
|
||||
}
|
||||
}
|
||||
|
||||
void writeCountToBuf(int count, char* c, procbuffer* buf) {
|
||||
while (count--) {
|
||||
writeToBuf(*(c++), buf);
|
||||
}
|
||||
}
|
||||
|
||||
void clearBuf(procbuffer* buf) {
|
||||
for (int i=0; i<buf->height*buf->width;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 setCurPos(int x, int y) {
|
||||
char pset[11] = "\x1b[000;000H";
|
||||
for (int i=0; i<y;i++) {
|
||||
pset[4]++;
|
||||
if (pset[4] == 0x3a) {
|
||||
pset[4] = 0x30;
|
||||
pset[3]++;
|
||||
}
|
||||
if (pset[3] == 0x3a) {
|
||||
pset[3] = 0x30;
|
||||
pset[2]++;
|
||||
}
|
||||
}
|
||||
for (int i=0; i<x;i++) {
|
||||
pset[8]++;
|
||||
if (pset[8] == 0x3a) {
|
||||
pset[8] = 0x30;
|
||||
pset[7]++;
|
||||
}
|
||||
if (pset[7] == 0x3a) {
|
||||
pset[7] = 0x30;
|
||||
pset[6]++;
|
||||
}
|
||||
}
|
||||
print(pset);
|
||||
}
|
||||
|
||||
void displayBuf(procbuffer* b, int dx, int dy) {
|
||||
print("\x1b[42;36;1m");
|
||||
char pset[9] = "\x1b[000;000H";
|
||||
for (int i=0; i<b->height; i++) {
|
||||
setCurPos(dx, dy++);
|
||||
write(b->width, 0, b->buffer+(b->width*i));
|
||||
}
|
||||
}
|
||||
|
||||
void readline(int count, char* buffer) {
|
||||
int index = 0;
|
||||
char c;
|
||||
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;
|
||||
}
|
||||
|
||||
procbuffer b1;
|
||||
procbuffer b2;
|
||||
|
||||
int bufferWidth;
|
||||
|
||||
void displayBuffer1() {
|
||||
char c[128];
|
||||
int succ=0;
|
||||
while (1) {
|
||||
if (b1.process)
|
||||
if (succ = read(128, b1.stdout, c))
|
||||
writeCountToBuf(succ, c, &b1);
|
||||
displayBuf(&b1, 2, 2);
|
||||
}
|
||||
}
|
||||
|
||||
void displayBuffer2() {
|
||||
char c[128];
|
||||
int succ=0;
|
||||
while (1) {
|
||||
if (b2.process)
|
||||
if (succ = read(128, b2.stdout, c))
|
||||
writeCountToBuf(succ, c, &b2);
|
||||
displayBuf(&b2, bufferWidth+4, 2);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
int width = getCurrentTerminalWidth();
|
||||
int height = getCurrentTerminalHeight();
|
||||
|
||||
bufferWidth = (width - 4) / 2;
|
||||
int bufferHeight = (height - 4);
|
||||
|
||||
bindToKeyboard();
|
||||
|
||||
char space = ' ';
|
||||
char plus = '+';
|
||||
|
||||
print("\x1b[1;1H");
|
||||
for (int i=0; i < 1000; i++)
|
||||
write(1, 0, &space);
|
||||
print("\x1b[1;1H");
|
||||
print("\x1b[45;33;1m");
|
||||
|
||||
for (int i=0; i<width;i++)
|
||||
write(1, 0, &plus);
|
||||
for (int i=0; i<bufferHeight;i++) {
|
||||
write(1, 0, &plus);
|
||||
for (int j=0; j<bufferWidth; j++)
|
||||
write(1, 0, &space);
|
||||
write(1, 0, &plus);
|
||||
write(1, 0, &plus);
|
||||
for (int j=0; j<bufferWidth; j++)
|
||||
write(1, 0, &space);
|
||||
write(1, 0, &plus);
|
||||
}
|
||||
for (int i=0; i<width;i++)
|
||||
write(1, 0, &plus);
|
||||
write(1, 0, &plus);
|
||||
for (int i=0; i< width - 2; i++)
|
||||
write(1, 0, &space);
|
||||
write(1, 0, &plus);
|
||||
for (int i=0; i<width;i++)
|
||||
write(1, 0, &plus);
|
||||
|
||||
uint32_t program = fopen("/hello.bin");
|
||||
uint32_t p1 = exec(program);
|
||||
uint32_t p1out = bindStdout(p1);
|
||||
uint32_t p1in = bindStdin(p1);
|
||||
fclose(program);
|
||||
program = fopen("/timer.bin");
|
||||
uint32_t p2 = exec(program);
|
||||
uint32_t p2out = bindStdout(p2);
|
||||
uint32_t p2in = bindStdin(p2);
|
||||
fclose(program);
|
||||
|
||||
b1 = (procbuffer) {
|
||||
.buffer = malloc(bufferWidth * bufferHeight),
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.process = p1,
|
||||
.stdin = p1in,
|
||||
.stdout = p1out,
|
||||
.width = bufferWidth,
|
||||
.height = bufferHeight
|
||||
};
|
||||
|
||||
b2 = (procbuffer) {
|
||||
.buffer = malloc(bufferWidth * bufferHeight),
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.process = p2,
|
||||
.stdin = p2in,
|
||||
.stdout = p2out,
|
||||
.width = bufferWidth,
|
||||
.height = bufferHeight
|
||||
};
|
||||
|
||||
spawnThread(&displayBuffer1);
|
||||
spawnThread(&displayBuffer2);
|
||||
|
||||
procbuffer* selectedBuf = &b1;
|
||||
|
||||
writeStrToBuf("XoSH (XOS SHell) v0.0.1\nPress : to use commands.\n :help for help.\n", &b1);
|
||||
|
||||
while (1) {
|
||||
char c[128];
|
||||
int succ = 0;
|
||||
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[45;33;1m");
|
||||
setCurPos(2, height-1);
|
||||
print(": ");
|
||||
setCurPos(3, height-1);
|
||||
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(":ls <path>\n", selectedBuf);
|
||||
writeStrToBuf(" Lists the files in directory <path>\n", selectedBuf);
|
||||
writeStrToBuf(":clear\n", selectedBuf);
|
||||
writeStrToBuf(" Clears the buffer\n", selectedBuf);
|
||||
writeStrToBuf(":type <filename>\n", selectedBuf);
|
||||
writeStrToBuf(" Writes out the contents of the file <filename>\n", selectedBuf);
|
||||
|
||||
writeStrToBuf("--------\n", selectedBuf);
|
||||
} else if (strcmpcnt(4, buf, "kill")) {
|
||||
if (selectedBuf->process) {
|
||||
kill(selectedBuf->process);
|
||||
clearBuf(selectedBuf);
|
||||
selectedBuf->process = 0;
|
||||
selectedBuf->stdin = 0;
|
||||
selectedBuf->stdout = 0;
|
||||
}
|
||||
} else if (strcmpcnt(4, buf, "load")) {
|
||||
if (!selectedBuf->process) {
|
||||
char* potFn = buf+5;
|
||||
uint32_t fh = fopen(potFn);
|
||||
selectedBuf->process = exec(fh);
|
||||
selectedBuf->stdout = bindStdout(selectedBuf->process);
|
||||
selectedBuf->stdin = bindStdin(selectedBuf->process);
|
||||
fclose(fh);
|
||||
}
|
||||
} else if (strcmpcnt(2, buf, "ls")) {
|
||||
uint32_t size = getDentsSize((char*)(buf+3));
|
||||
FSDirectoryListing* listing = (FSDirectoryListing*)malloc(size);
|
||||
getDents((char*)(buf+3), listing);
|
||||
writeStrToBuf("\n", selectedBuf);
|
||||
for (int i=0; i<listing->count; i++) {
|
||||
writeCountToBuf(listing->entries[i].path.length, listing->entries[i].path.path, selectedBuf);
|
||||
writeStrToBuf("\n", selectedBuf);
|
||||
}
|
||||
free(listing);
|
||||
} else if (strcmpcnt(5, buf, "clear")) {
|
||||
clearBuf(selectedBuf);
|
||||
} else if (strcmpcnt(4, buf, "type")) {
|
||||
uint32_t f = fopen(buf+5);
|
||||
char c;
|
||||
while (read(1, f, &c))
|
||||
writeCountToBuf(1, &c, selectedBuf);
|
||||
fclose(f);
|
||||
}
|
||||
} else {
|
||||
if (selectedBuf->process)
|
||||
write(1, selectedBuf->stdin, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
107
src/programs/xosh/main.c
Normal file
107
src/programs/xosh/main.c
Normal 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, 128);
|
||||
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")) {
|
||||
setenv(result[1], result[2]);
|
||||
} else {
|
||||
printf("No such executable file: `%s`\n\n", programName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user