Add ability for other processes to bind to eachother's stdin and stdout. Add PoC for this functionality
This commit is contained in:
parent
55a5bea35a
commit
73c0fe429f
4
Makefile
4
Makefile
@ -2,7 +2,8 @@ CFLAGS = -g -std=gnu11 -m32 -mgeneral-regs-only -nostdlib -fno-builtin -fno-exce
|
||||
CXXFLAGS = -g -m32 -fno-use-cxa-atexit -mgeneral-regs-only -nostdlib -fno-builtin -fno-rtti -fno-exceptions -fno-leading-underscore -fpermissive -fno-pie -fno-stack-protector -I.
|
||||
LDFLAGS =
|
||||
|
||||
DISK_IMG_FILES = build/kernel/kernel.bin build/world/world.bin hello.txt alpha.txt
|
||||
DISK_IMG_FILES = build/kernel/kernel.bin build/world/world.bin hello.txt alpha.txt \
|
||||
build/hello/hello.bin
|
||||
|
||||
KERNEL_CPP_SRCS = $(wildcard src/kernel/*.cpp) $(wildcard src/kernel/*/*.cpp)
|
||||
KERNEL_ASM_SRCS = $(wildcard src/kernel/*.asm)
|
||||
@ -44,6 +45,7 @@ disk.img: clean prepare build/boot/boot.bin build/boot_stage2/boot.bin $(DISK_IM
|
||||
dd obs=512 seek=1 if=build/boot_stage2/boot.bin of=disk.img conv=notrunc
|
||||
mount disk.img img.d
|
||||
cp $(DISK_IMG_FILES) img.d/
|
||||
sleep 0.1
|
||||
umount img.d
|
||||
chmod 777 disk.img
|
||||
|
||||
|
@ -28,6 +28,18 @@ 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(char* filename) {
|
||||
asm volatile("mov $7, %%eax; mov %0, %%esi; int $0x7f" : : "m" (filename) : "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");
|
||||
}
|
||||
|
||||
void bindToKeyboard() {
|
||||
asm volatile ("mov $12, %%eax; int $0x7f" : : :);
|
||||
}
|
||||
|
@ -9,6 +9,10 @@ void* localalloc(uint32_t size);
|
||||
void localdelete(void* ptr);
|
||||
uint32_t filesize(char* filename);
|
||||
|
||||
uint32_t fork(char* filename);
|
||||
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);
|
||||
|
@ -1,16 +1,40 @@
|
||||
#include "../common/common.h"
|
||||
|
||||
void readline(int count, char* buffer) {
|
||||
int index = 0;
|
||||
char c;
|
||||
while (index < count) {
|
||||
if (read(1, 1, &c)) {
|
||||
if (c == '\n')
|
||||
break;
|
||||
if (c == '\b') {
|
||||
if (index == 0)
|
||||
continue;
|
||||
else {
|
||||
index--;
|
||||
buffer[index] = 0;
|
||||
write(1, 0, &c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
buffer[index++] = c;
|
||||
write(1, 0, &c);
|
||||
}
|
||||
}
|
||||
print("\n");
|
||||
}
|
||||
|
||||
int main() {
|
||||
uint32_t counter = 0;
|
||||
uint32_t PID = getPID();
|
||||
char intbuffer[32];
|
||||
uint32_t index = int_to_decimal(PID, intbuffer);
|
||||
print("Hello, World!\n");
|
||||
char buffer[32];
|
||||
while (1) {
|
||||
counter++;
|
||||
if (counter == 312500) {
|
||||
print(intbuffer+index);
|
||||
print(" ");
|
||||
counter = 0;
|
||||
}
|
||||
for (int i=0; i<32; i++)
|
||||
buffer[i] = 0;
|
||||
print(">>> ");
|
||||
readline(32, buffer);
|
||||
print("You said: ");
|
||||
print(buffer);
|
||||
print("\n\n");
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ namespace Global {
|
||||
Kernel* kernel = 0;
|
||||
Process* currentProc = 0;
|
||||
tss_struct* tss = 0;
|
||||
bool currentProcValid = true;
|
||||
bool currentProcValid = false;
|
||||
}
|
||||
|
||||
void* operator new (uint32_t size) {
|
||||
|
@ -21,18 +21,36 @@ void set_entry(uint8_t interrupt_number, uint16_t code_segment, void(*handler)()
|
||||
};
|
||||
}
|
||||
|
||||
void page_fault(frame_struct* frame) {
|
||||
// Clear interrupts, we don't want to perform a context switch during a page fault.
|
||||
void handle_fault(frame_struct* 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): Page Fault at %x Error Code: %x Gate: %d\n", frame->cs, frame->eip, problem_address, frame->errcode, frame->gate);
|
||||
Global::kernel->terminal->printf("(CS %x EIP %x): ", frame->cs, frame->eip);
|
||||
switch (frame->gate) {
|
||||
case 0: // Divide by zero
|
||||
Global::kernel->terminal->printf("Divide by Zero");
|
||||
break;
|
||||
case 6: // Invalid Opcode
|
||||
Global::kernel->terminal->printf("Invalid Opcode");
|
||||
break;
|
||||
case 13: // GPF
|
||||
Global::kernel->terminal->printf("General Protection Fault!");
|
||||
break;
|
||||
case 14: // Page Fault
|
||||
Global::kernel->terminal->printf("Page Fault at %x", problem_address);
|
||||
break;
|
||||
default:
|
||||
Global::kernel->terminal->printf("Unkown Fault!");
|
||||
break;
|
||||
}
|
||||
Global::kernel->terminal->printf(" Error Code: %x\n", frame->errcode);
|
||||
if (!(frame->cs & 3)) {
|
||||
Global::kernel->terminal->printf("[FATAL] Kernel Page Fault!!!\n");
|
||||
Global::kernel->terminal->printf("[FATAL] Kernel Fault!!!\n");
|
||||
while (1) asm("hlt");
|
||||
} else {
|
||||
// Print an error message.
|
||||
Global::kernel->terminal->printf("PID %d Terminated due to page fault!\n", Global::currentProc->PID);
|
||||
Global::kernel->terminal->printf("PID %d Terminated due to fault!\n", Global::currentProc->PID);
|
||||
asm volatile ("mov %0, %%esp" ::"m"(Global::kernel->globalISRStack));
|
||||
Global::kernel->PD->select();
|
||||
|
||||
@ -49,11 +67,6 @@ void page_fault(frame_struct* frame) {
|
||||
|
||||
void ignore_interrupt(frame_struct* frame) {}
|
||||
|
||||
void gpf(frame_struct* frame) {
|
||||
printf("(EIP %x) General Protection Fault %x\n", frame->eip, frame->errcode);
|
||||
while (1) asm("hlt");
|
||||
}
|
||||
|
||||
void context_switch(frame_struct* frame) {
|
||||
// When any interrupt occurs (including context_switch), SS:ESP is set to
|
||||
// the values of SS0:ESP0 in Global::tss
|
||||
@ -70,26 +83,21 @@ void context_switch(frame_struct* frame) {
|
||||
|
||||
asm ("cli"); // Disable interrupts whilst handling the context switch.
|
||||
|
||||
// Restore eax
|
||||
asm ("mov %0, %%eax"::"r"(frame->eax));
|
||||
xnoe::linkedlist<Process*>* processes = &Global::kernel->processes;
|
||||
|
||||
Process* currentProc = 0;
|
||||
Process* nextProc = 0;
|
||||
|
||||
if (Global::currentProcValid) {
|
||||
currentProc = Global::currentProc;
|
||||
// Write current esp to currentProc->kernelStackPtr
|
||||
asm ("mov %%esp, %0" : "=a" (currentProc->kernelStackPtr):);
|
||||
if (!processes->start) {
|
||||
Global::kernel->terminal->printf("[FATAL] No more processes! Halting!\n");
|
||||
while (1) asm ("hlt");
|
||||
}
|
||||
|
||||
if (currentProc || !Global::currentProcValid) {
|
||||
xnoe::linkedlist<Process*>* processes = &Global::kernel->processes;
|
||||
if (Global::currentProcValid)
|
||||
asm ("mov %%esp, %0" : "=a" (Global::currentProc->kernelStackPtr):);
|
||||
|
||||
// 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 (processes->start) {
|
||||
if (Global::currentProc) {
|
||||
if (processes->start->next != 0) {
|
||||
if (processes->end->prev == processes->start) {
|
||||
xnoe::linkedlistelem<Process*>* tmp = processes->start;
|
||||
@ -112,26 +120,17 @@ void context_switch(frame_struct* frame) {
|
||||
}
|
||||
}
|
||||
|
||||
// Get the next process.
|
||||
if (processes->start)
|
||||
nextProc = processes->start->elem;
|
||||
|
||||
if (nextProc == 0) {
|
||||
Global::kernel->terminal->printf("[FATAL] No more processes! Halting!\n");
|
||||
while (1) asm ("hlt");
|
||||
}
|
||||
|
||||
Global::currentProc = nextProc;
|
||||
Global::currentProc = processes->start->elem;
|
||||
|
||||
// Select the next processes page directory
|
||||
asm volatile ("mov %0, %%cr3" : : "r" (nextProc->PD->phys_addr));
|
||||
asm volatile ("mov %0, %%cr3" : : "r" (Global::currentProc->PD->phys_addr));
|
||||
// Restore kernelStackPtr of the new process.
|
||||
asm volatile ("mov %0, %%esp" : : "m" (Global::kernel->processes.start->elem->kernelStackPtr));
|
||||
asm volatile ("mov %0, %%esp" : : "m" (Global::currentProc->kernelStackPtr));
|
||||
|
||||
// At this point interrupts are disabled till iret so we can safely set
|
||||
// Global::tss->esp0 to the new Process's kernelStackPtrDefault
|
||||
|
||||
Global::tss->esp0 = Global::kernel->processes.start->elem->kernelStackPtrDefault;
|
||||
Global::tss->esp0 = Global::currentProc->kernelStackPtrDefault;
|
||||
|
||||
// Set the current proc to valid
|
||||
Global::currentProcValid = true;
|
||||
@ -140,7 +139,9 @@ void context_switch(frame_struct* frame) {
|
||||
Global::currentProc->firstRun = false;
|
||||
asm("add $4, %esp");
|
||||
asm("ret");
|
||||
}
|
||||
} else {
|
||||
asm("add $28, %esp");
|
||||
asm("ret");
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,13 +154,16 @@ void syscall(frame_struct* frame) {
|
||||
// 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: X
|
||||
// 7: fork :: char* filename esi -> int PID // Spawns a process and returns its PID.
|
||||
// 8: getPID: returns the current process's PID (out eax: uint32_t)
|
||||
// 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
|
||||
// 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.
|
||||
|
||||
// File handlers:
|
||||
// 0: Stdout
|
||||
// 1: Stdin
|
||||
@ -190,8 +194,16 @@ void syscall(frame_struct* frame) {
|
||||
break;
|
||||
case 6:
|
||||
break;
|
||||
case 7:
|
||||
case 7: {
|
||||
asm("cli");
|
||||
char filename[12];
|
||||
for (int i=0; i<12; i++)
|
||||
filename[i] = ((char*)(frame->esi))[i];
|
||||
Process* p = Global::kernel->createProcess(filename);
|
||||
rval = p->PID;
|
||||
asm("sti");
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
rval = currentProc->PID;
|
||||
break;
|
||||
@ -208,8 +220,10 @@ void syscall(frame_struct* frame) {
|
||||
rval = stdin->read(frame->ebx, edi);
|
||||
} else {
|
||||
xnoe::Maybe<ReadWriter*> fh = Global::kernel->FH->get(esi);
|
||||
if (!fh.is_ok())
|
||||
if (!fh.is_ok()) {
|
||||
rval = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
ReadWriter* rw = fh.get();
|
||||
rval = rw->read(frame->ebx, edi);
|
||||
@ -226,8 +240,10 @@ void syscall(frame_struct* frame) {
|
||||
rval = stdout->write(frame->ebx, edi);
|
||||
} else {
|
||||
xnoe::Maybe<ReadWriter*> fh = Global::kernel->FH->get(esi);
|
||||
if (!fh.is_ok())
|
||||
if (!fh.is_ok()) {
|
||||
rval = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
ReadWriter* rw = fh.get();
|
||||
rval = rw->write(frame->ebx, edi);
|
||||
@ -241,6 +257,33 @@ void syscall(frame_struct* frame) {
|
||||
|
||||
currentProc->stdin = new CircularRWBuffer(currentProc->PID, 0);
|
||||
Global::kernel->KBListeners.append(currentProc);
|
||||
break;
|
||||
|
||||
case 13: {
|
||||
xnoe::Maybe<Process*> pm = Global::kernel->pid_map->get(esi);
|
||||
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);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 14: {
|
||||
xnoe::Maybe<Process*> pm = Global::kernel->pid_map->get(esi);
|
||||
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);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
@ -259,12 +302,28 @@ void init_idt() {
|
||||
for (int i=0; i<256; i++)
|
||||
gates[i] = &ignore_interrupt;
|
||||
|
||||
gates[0x20] = &context_switch;
|
||||
gates[0xd] = &gpf;
|
||||
gates[0xe] = &page_fault;
|
||||
gates[0x7f] = &syscall;
|
||||
gates[32] = &context_switch;
|
||||
gates[0] = &handle_fault;
|
||||
gates[5] = &handle_fault;
|
||||
gates[6] = &handle_fault;
|
||||
gates[7] = &handle_fault;
|
||||
gates[9] = &handle_fault;
|
||||
gates[10] = &handle_fault;
|
||||
gates[11] = &handle_fault;
|
||||
gates[12] = &handle_fault;
|
||||
gates[13] = &handle_fault;
|
||||
gates[14] = &handle_fault;
|
||||
gates[16] = &handle_fault;
|
||||
gates[17] = &handle_fault;
|
||||
gates[19] = &handle_fault;
|
||||
gates[20] = &handle_fault;
|
||||
gates[21] = &handle_fault;
|
||||
gates[29] = &handle_fault;
|
||||
gates[30] = &handle_fault;
|
||||
gates[31] = &handle_fault;
|
||||
gates[127] = &syscall;
|
||||
|
||||
idt[0x7f].privilege = 3;
|
||||
idt[127].privilege = 3;
|
||||
|
||||
outb(0x20, 0x11);
|
||||
outb(0xA0, 0x11);
|
||||
|
@ -11,11 +11,14 @@ Kernel::Kernel(PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint
|
||||
|
||||
this->stack = stack;
|
||||
|
||||
this->lastFH = 8;
|
||||
|
||||
//this->processes.append(this);
|
||||
}
|
||||
|
||||
void Kernel::init_kernel() {
|
||||
this->pid_map = new xnoe::hashtable<uint32_t, Process*>();
|
||||
this->FH = new xnoe::hashtable<void*, ReadWriter*>();
|
||||
this->globalISRStack = (new uint8_t[0x8000]) + 0x8000;
|
||||
}
|
||||
|
||||
@ -41,6 +44,11 @@ void Kernel::destroyProcess(Process* p) {
|
||||
delete p;
|
||||
}
|
||||
|
||||
int Kernel::mapFH(ReadWriter* fh) {
|
||||
this->FH->set(this->lastFH++, fh);
|
||||
return this->lastFH - 1;
|
||||
}
|
||||
|
||||
//void Kernel::loadPrimaryStack() {
|
||||
// asm volatile("mov %0, %%esp"::"m"(this->stack - 64));
|
||||
//}
|
@ -7,6 +7,8 @@
|
||||
#include "terminal.h"
|
||||
|
||||
class Kernel : public Process {
|
||||
private:
|
||||
int lastFH;
|
||||
public:
|
||||
uint32_t currentPID;
|
||||
uint32_t stack;
|
||||
@ -26,6 +28,8 @@ public:
|
||||
Process* createProcess(char* filename);
|
||||
Process* createProcess(char* filename, ReadWriter* stdout);
|
||||
void destroyProcess(Process* p);
|
||||
|
||||
int mapFH(ReadWriter* fh);
|
||||
//void loadPrimaryStack();
|
||||
};
|
||||
|
||||
|
@ -36,12 +36,15 @@ bool shift_on = false;
|
||||
void keyboard_interrupt(frame_struct* frame) {
|
||||
uint8_t decoded = 0;
|
||||
uint8_t current_scancode = inb(0x60);
|
||||
outb(0x20, 0x21);
|
||||
if ((current_scancode&0x7f) == 0x2a)
|
||||
if ((current_scancode&0x7f) == 0x2a) {
|
||||
shift_on = !(current_scancode&0x80);
|
||||
return;
|
||||
}
|
||||
|
||||
if (current_scancode == 0x3a)
|
||||
if (current_scancode == 0x3a) {
|
||||
caps_on ^= 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (shift_on)
|
||||
decoded = key_to_char_shift[current_scancode&0x7f];
|
||||
|
@ -44,10 +44,7 @@ int main() {
|
||||
|
||||
term->printf("KERNEL OK!\n");
|
||||
|
||||
Global::currentProc = &kernel;
|
||||
|
||||
Process* p1 = kernel.createProcess("WORLD BIN", term);
|
||||
//kernel.createProcess("HELLO BIN");
|
||||
|
||||
init_keyboard();
|
||||
|
||||
|
@ -244,6 +244,9 @@ void* Allocator::allocate(uint32_t size) {
|
||||
this->PD->map(phys_addr, virt_addr + 4096 * i, this->privilege);
|
||||
}
|
||||
|
||||
for (int i=0; i<4096; i++)
|
||||
((uint8_t*)virt_addr)[i] = 0;
|
||||
|
||||
return virt_addr;
|
||||
}
|
||||
|
||||
|
@ -59,44 +59,26 @@ Process::Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase, cha
|
||||
|
||||
// We also need to initialise ESP and the stack
|
||||
uint32_t* stack32 = ((uint32_t)this->kernelStackPtr);
|
||||
stack32--;
|
||||
*stack32 = 0x23; // SS
|
||||
stack32--;
|
||||
*stack32 = ((uint32_t)this->stack + 0x8000); // ESP
|
||||
stack32--;
|
||||
*stack32 = 0x200; // EFLAGS
|
||||
stack32--;
|
||||
*stack32 = 27; // CS 0x08
|
||||
stack32--;
|
||||
*stack32 = (uint32_t)program_data; // EIP
|
||||
|
||||
stack32--;
|
||||
*stack32 = ((uint32_t)this->stack + 0x8000); // EBP
|
||||
*(--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 rEBP = stack32;
|
||||
|
||||
//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
|
||||
stack32--;
|
||||
*stack32 = 0; // EAX
|
||||
stack32--;
|
||||
*stack32 = 0; // ECX
|
||||
stack32--;
|
||||
*stack32 = 0; // EDX
|
||||
stack32--;
|
||||
*stack32 = 0; // EBX
|
||||
stack32--;
|
||||
*stack32 = 0; // ESP
|
||||
stack32--;
|
||||
*stack32 = rEBP; // EBP
|
||||
stack32--;
|
||||
*stack32 = 0; // ESI
|
||||
stack32--;
|
||||
*stack32 = 0; // EDI
|
||||
|
||||
stack32--;
|
||||
|
||||
stack32--;
|
||||
*stack32 = &catchall_return; // cachall_return
|
||||
|
||||
*(--stack32) = &catchall_return; // cachall_return
|
||||
stack32--;
|
||||
|
||||
this->kernelStackPtr = stack32;
|
||||
|
@ -46,6 +46,23 @@ 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;
|
||||
}
|
||||
|
||||
int clamp(int a, int b, int c) {
|
||||
if (a < b)
|
||||
return b;
|
||||
if (a > c)
|
||||
return c;
|
||||
return a;
|
||||
}
|
||||
|
||||
void Terminal::printf(const char* string, ...) {
|
||||
va_list ptr;
|
||||
va_start(ptr, string);
|
||||
@ -59,10 +76,50 @@ void Terminal::printf(const char* string, ...) {
|
||||
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 {
|
||||
} else if (this->cur_y > 0) {
|
||||
this->cur_y--;
|
||||
this->cur_x = this->width-1;
|
||||
}
|
||||
@ -125,14 +182,94 @@ void Terminal::printf(const char* string, ...) {
|
||||
va_end(ptr);
|
||||
}
|
||||
|
||||
int Terminal::write(uint32_t count, uint8_t* buffer) {
|
||||
char* buf = new char[count+1];
|
||||
int Terminal::write(uint32_t count, uint8_t* string) {
|
||||
/*char* buf = new char[count+1];
|
||||
for (int i=0;i<count;i++) {
|
||||
buf[i] = buffer[i];
|
||||
}
|
||||
buf[count] = 0;
|
||||
buf[count] = 0x00;
|
||||
printf(buf);
|
||||
delete buf;
|
||||
delete buf;*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
this->set_curpos(this->cur_x, this->cur_y);
|
||||
}
|
||||
|
||||
int Terminal::read(uint32_t count, uint8_t* buffer) {}
|
||||
|
@ -1,14 +1,137 @@
|
||||
#include "../common/common.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
void scrollBuffer(char* buf) {
|
||||
for (int y=0; y<21; y++)
|
||||
for (int x=0; x<38; x++)
|
||||
if (y != 20)
|
||||
buf[y*38+x] = buf[(y+1)*38+x];
|
||||
else
|
||||
buf[y*38+x] = ' ';
|
||||
}
|
||||
|
||||
void writeToBuf(char c, char* buf, int* cx, int* cy) {
|
||||
switch (c) {
|
||||
case '\n':
|
||||
*cx = 0;
|
||||
(*cy)++;
|
||||
break;
|
||||
|
||||
case '\b':
|
||||
if (*cx > 0)
|
||||
(*cx)--;
|
||||
else if (*cy > 0) {
|
||||
*cx = 37;
|
||||
(*cy)--;
|
||||
}
|
||||
buf[(*cy)*38+(*cx)] = ' ';
|
||||
break;
|
||||
|
||||
default:
|
||||
buf[(*cy)*38+(*cx)++] = c;
|
||||
}
|
||||
if (*cx == 38) {
|
||||
*cx = 0;
|
||||
(*cy)++;
|
||||
}
|
||||
if (*cy == 21) {
|
||||
(*cy)--;
|
||||
scrollBuffer(buf);
|
||||
}
|
||||
}
|
||||
|
||||
void writeStrToBuf(char* c, char* buf, int* cx, int* cy) {
|
||||
char* s = c;
|
||||
while(*s)
|
||||
writeToBuf(*(s++), buf, cx, cy);
|
||||
}
|
||||
|
||||
void displayBuf(char* buf, 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<21; i++) {
|
||||
print(pset);
|
||||
write(38, 0, buf+(38*i));
|
||||
pset[3]++;
|
||||
if (pset[3] == 0x3a) {
|
||||
pset[3] = 0x30;
|
||||
pset[2]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
bindToKeyboard();
|
||||
|
||||
print("Hello from Ring 3!\n");
|
||||
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<80;i++)
|
||||
write(1, 0, &plus);
|
||||
for (int i=0; i<21;i++)
|
||||
write(80, 0, mid);
|
||||
for (int i=0; i<80;i++)
|
||||
write(1, 0, &plus);
|
||||
write(80, 0, bottom);
|
||||
for (int i=0; i<80;i++)
|
||||
write(1, 0, &plus);
|
||||
|
||||
char* hello_bin = "HELLO BIN";
|
||||
uint32_t p1 = fork(hello_bin);
|
||||
uint32_t p2 = fork(hello_bin);
|
||||
|
||||
uint32_t p1out = bindStdout(p1);
|
||||
uint32_t p1in = bindStdin(p1);
|
||||
|
||||
uint32_t p2out = bindStdout(p2);
|
||||
uint32_t p2in = bindStdin(p2);
|
||||
|
||||
char* buf1 = localalloc(21 * 38);
|
||||
char* buf2 = localalloc(21 * 38);
|
||||
|
||||
int b1cx = 0;
|
||||
int b1cy = 0;
|
||||
|
||||
int b2cx = 0;
|
||||
int b2cy = 0;
|
||||
|
||||
char* selectedBuf = buf1;
|
||||
uint32_t selectedOut = p1out;
|
||||
uint32_t selectedIn = p1in;
|
||||
|
||||
|
||||
while (1) {
|
||||
char c;
|
||||
if (read(1, 1, &c))
|
||||
write(1, 0, &c);
|
||||
if (read(1, selectedOut, &c))
|
||||
writeToBuf(c, selectedBuf, &b1cx, &b1cy);
|
||||
if (read(1, p2out, &c))
|
||||
writeToBuf(c, buf2, &b2cx, &b2cy);
|
||||
if (read(1, 1, &c)) {
|
||||
write(1, selectedIn, &c);
|
||||
write(1, p2in, &c);
|
||||
}
|
||||
|
||||
displayBuf(selectedBuf, 2, 2);
|
||||
displayBuf(buf2, 42, 2);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user