diff --git a/Makefile b/Makefile index 3aeedac3..53c5384a 100644 --- a/Makefile +++ b/Makefile @@ -19,11 +19,11 @@ ISOFILE:=builds/$(DEBNAME).iso INITRDDIR:=initrd INITRD=sortix/sortix.initrd +all: $(INITRD) + suball: (for D in $(MODULES); do $(MAKE) all $(MFLAGS) --directory $$D || exit 1; done) -all: $(INITRD) - clean: rm -f $(INITRD) (for D in $(MODULES); do $(MAKE) clean $(MFLAGS) --directory $$D || exit 1; done) diff --git a/games/snake.cpp b/games/snake.cpp index d9d8059a..5be965d2 100644 --- a/games/snake.cpp +++ b/games/snake.cpp @@ -31,6 +31,11 @@ char direction[buffersize]; uint16_t animal = '%' | (COLOR8_RED<<8); uint16_t snake = ' ' | (COLOR8_GREEN<<12); +const int defaultspeed = 75; +const int speedincrease = -5; +const int maxspeed = 40; +volatile int speed; + // HACK: Sortix has no random number generator yet! int random_seed=1337; int rand(int max) @@ -43,7 +48,7 @@ int rand(int max) void Clear() { // Reset the game data. - for ( int i = 0; i < buffersize; i++ ) { frame->text[i] = 0; direction[i] = -1; } + for ( int i = 0; i < buffersize; i++ ) { frame->text[i] = ' '; direction[i] = -1; } } void Reset() @@ -66,6 +71,8 @@ void Reset() tailmax = 3; frame->text[animaly * width + animalx] = animal; + + speed = defaultspeed; } int Init() @@ -125,7 +132,7 @@ void Update() // Move the tail, if needed. if ( taillen == tailmax ) { - frame->text[taily * width + tailx] = 0; taillen--; + frame->text[taily * width + tailx] = ' '; taillen--; switch ( direction[taily * width + tailx] ) { case 0: tailx--; break; @@ -144,6 +151,7 @@ void Update() tailmax++; animalx = 2 + rand(width-4); animaly = 2 + rand(height-4); + if ( maxspeed < speed ) { speed += speedincrease; } } frame->text[animaly * width + animalx] = animal; @@ -167,11 +175,10 @@ int main(int argc, char* argv[]) int result = Init(); if ( result != 0 ) { return result; } - // Update the game every 300th milisecond. + // Update the game every once in a while. while ( true ) { - const int sleepms = 75; - Thread::USleep(sleepms * 1000); + Thread::USleep(speed * 1000); Update(); } diff --git a/sortix/.gitignore b/sortix/.gitignore index c413d6e0..643aa562 100644 --- a/sortix/.gitignore +++ b/sortix/.gitignore @@ -5,3 +5,4 @@ *.so *.a *.initrd +*.out diff --git a/sortix/Makefile b/sortix/Makefile index 42666c86..66a508be 100644 --- a/sortix/Makefile +++ b/sortix/Makefile @@ -3,7 +3,8 @@ ifndef CPU endif ifeq ($(CPU),x86) - X86FAMILY=1 + BUILDID=x86 + X86FAMILY=1 CPUDEFINES=-DPLATFORM_X86 CPUFLAGS=-m32 CPULDFLAGS=-melf_i386 @@ -13,7 +14,8 @@ ifeq ($(CPU),x86) endif ifeq ($(CPU),x64) - X86FAMILY=1 + BUILDID=x64 + X86FAMILY=1 CPUDEFINES=-DPLATFORM_X64 CPUFLAGS=-m64 -ffreestanding -mcmodel=large -mno-red-zone CPULDFLAGS=-melf64-little -z max-page-size=0x1000 @@ -34,13 +36,10 @@ endif DIRS=. x64 x86 x86-family DEFINES:=-DSORTIX_KERNEL $(CPUDEFINES) -DEFINES:=$(DEFINES) -DPLATFORM_VIRTUAL_MEMORY -DEFINES:=$(DEFINES) -DPLATFORM_KERNEL_HEAP -#DEFINES:=$(DEFINES) -DPLATFORM_SERIAL -#DEFINES:=$(DEFINES) -DPLATFORM_HTP -#DEFINES:=$(DEFINES) -DCONWAY -#DEFINES:=$(DEFINES) -DPONG -DEFINES:=$(DEFINES) -DINITRD +ifeq ($(JSSORTIX),1) + DEFINES:=$(DEFINES) -DPLATFORM_SERIAL -DJSSORTIX + BUILDID:=$(BUILDID)-js +endif CPPFLAGSRELEASE=-s -O3 CPPFLAGSDEBUG= CPPFLAGS=-I.. -I. $(CPUDEFINES) $(CPUFLAGS) -std=gnu++0x -Wall -Wextra -nostdlib -fno-builtin -nostartfiles -nodefaultlibs -fno-exceptions -fno-rtti -fno-stack-protector $(DEFINES) $(CPPFLAGSRELEASE) @@ -76,9 +75,9 @@ all: sortix.bin jssortix: jssortix.bin -jssortix.bin: $(JSOBJS) - ld -melf_i386 -Ttext 100000 -o jssortix.out $(JSOBJS) - objcopy -O binary jssortix.out jssortix.bin +sortix-x86-js.tmp: $(OBJS) + ld -melf_i386 -Ttext 100000 -o sortix-x86-js-internal.out $(OBJS) + objcopy -O binary sortix-x86-js-internal.out $@ # x64 compilation x64/boot.o: x64/boot.s @@ -101,7 +100,7 @@ sortix-x86.tmp: $(OBJS) # general rules -sortix.bin: sortix-$(CPU).tmp +sortix.bin: sortix-$(BUILDID).tmp cp -vu $< $@ %.o: %.cpp @@ -113,15 +112,6 @@ sortix.bin: sortix-$(CPU).tmp %.o: %.asm nasm $(CPUNASMFLAGS) $< -o $@ -%-js.o: %.cpp - g++ -c $< -o $@ $(CPPFLAGS) -DJSSORTIX - -%-js.o: %.s - as $(CPUASFLAGS) $< -o $@ - -%-js.o: %.asm - nasm $(CPUNASMFLAGS) $< -o $@ - clean: for D in $(DIRS); do rm -fv $$D/*.o $$D/*.bin $$D/*.out $$D/*.tmp; done diff --git a/sortix/interrupt.cpp b/sortix/interrupt.cpp index f661d712..18c82d76 100644 --- a/sortix/interrupt.cpp +++ b/sortix/interrupt.cpp @@ -60,7 +60,7 @@ namespace Sortix ? exceptions[regs->int_no] : "Unknown"; // Halt and catch fire if we are the kernel. - if ( (regs->cs & (0x4-1)) == 0 ) + if ( (regs->cs & (0x4-1)) == 0 || regs->int_no == 13 ) { PanicF("Unhandled CPU Exception id %zu '%s' at eip=0x%zx " "(cr2=0x%p, err_code=0x%p)", regs->int_no, message, diff --git a/sortix/kernel.cpp b/sortix/kernel.cpp index 8c4fa951..4c0d826f 100644 --- a/sortix/kernel.cpp +++ b/sortix/kernel.cpp @@ -115,6 +115,7 @@ namespace Sortix Log::Print(" / \\ / \\ \n"); Log::Print(" /_____________\\ /____________\\ \n"); Log::Print(" \n"); + Log::Print(" BOOTING OPERATING SYSTEM... "); } void DoWelcome() @@ -124,22 +125,6 @@ namespace Sortix #endif DoMaxsiLogo(); - -#ifdef PLATFORM_SERIAL -#ifdef PONG - Log::Print(" = THE SORTIX KERNEL - PONG EDITION = "); -#elif defined(CONWAY) - Log::Print(" = THE SORTIX KERNEL - CONWAY'S GAME OF LIFE EDITION = "); -#else - Log::Print(" "); -#endif - Log::Print(" "); - Log::Print(" "); - Log::Print(" "); - Log::Print(" "); - Log::Print(" "); - Log::Print(" "); -#endif } extern "C" void KernelInit(unsigned long Magic, multiboot_info_t* BootInfo) @@ -197,7 +182,7 @@ namespace Sortix uint8_t* initrd = NULL; size_t initrdsize = 0; -#ifdef INITRD +#ifndef JSSORTIX uint8_t** modules = (uint8_t**) BootInfo->mods_addr; for ( uint32_t I = 0; I < BootInfo->mods_count; I++ ) { @@ -205,9 +190,13 @@ namespace Sortix initrd = modules[2*I+0]; break; } +#else + // TODO: UGLY HACK because JSVM doesn't support multiboot yet! + initrd = (uint8_t*) 0x180000UL; + initrdsize = 0x80000; // 512 KiB +#endif if ( initrd == NULL ) { PanicF("No initrd provided"); } -#endif // Initialize the GDT and TSS structures. GDT::Init(); @@ -217,16 +206,12 @@ namespace Sortix if ( BootInfo == NULL ) { Panic("kernel.cpp: The bootinfo structure was NULL. Are your bootloader multiboot compliant?"); } -#ifdef PLATFORM_VIRTUAL_MEMORY // Initialize virtual memory. TODO: This is not fully working yet. VirtualMemory::Init(); -#ifdef PLATFORM_KERNEL_HEAP // Initialize the kernel heap. Maxsi::Memory::Init(); -#endif -#endif // Initialize the keyboard. Keyboard::Init(); diff --git a/sortix/keyboard.h b/sortix/keyboard.h index 24e7a861..3e94ed17 100644 --- a/sortix/keyboard.h +++ b/sortix/keyboard.h @@ -42,6 +42,7 @@ namespace Sortix void SetLEDs(uint8_t Toggle); void OnIRQ1(CPU::InterruptRegisters* Regs); void SysReceieveKeystroke(CPU::InterruptRegisters* R); + bool QueueKeystroke(uint32_t keystroke); } } diff --git a/sortix/scheduler.cpp b/sortix/scheduler.cpp index 231ca5d9..cfa54a39 100644 --- a/sortix/scheduler.cpp +++ b/sortix/scheduler.cpp @@ -223,11 +223,9 @@ namespace Sortix addr_t KernelStackPage = Page::Get(); if ( KernelStackPage == 0 ) { Panic("scheduler.cpp: could not allocate kernel interrupt stack for tss!"); } -#ifdef PLATFORM_VIRTUAL_MEMORY uintptr_t MapTo = 0x80000000; VirtualMemory::MapKernel(MapTo, (uintptr_t) KernelStackPage); -#endif GDT::SetKernelStack((size_t*) (MapTo+4096)); } @@ -236,7 +234,6 @@ namespace Sortix // simply awaits an IRQ0 and then we shall be scheduling. void MainLoop() { - Log::PrintF("Waiting for IRQ0\n"); // Simply wait for the next IRQ0 and then the OS will run. while ( true ) { } } @@ -253,43 +250,25 @@ namespace Sortix // TODO: We only support stacks of up to one page! if ( 4096 < StackSize ) { StackSize = 4096; } -#ifndef PLATFORM_KERNEL_HEAP - // TODO: Use the proper memory management systems using new and delete instead of these hacks! - // TODO: These allocations might NOT be thread safe! - void* ThreadPage = Page::Get(); - if ( ThreadPage == NULL ) { return NULL; } -#endif - // Allocate a stack for this thread. size_t StackLength = StackSize / sizeof(size_t); addr_t PhysStack = Page::Get(); if ( PhysStack == 0 ) { -#ifndef PLATFORM_KERNEL_HEAP - Page::Put(ThreadPage); -#endif return NULL; } // Create a new thread data structure. - Thread* thread = new -#ifndef PLATFORM_KERNEL_HEAP - (ThreadPage) -#endif - Thread(Process, AllocatedThreadId++, PhysStack, StackLength); + Thread* thread = new Thread(Process, AllocatedThreadId++, PhysStack, StackLength); #ifdef PLATFORM_X86 -#ifdef PLATFORM_VIRTUAL_MEMORY uintptr_t StackPos = 0x80000000UL; uintptr_t MapTo = StackPos - 4096UL; addr_t OldAddrSpace = VirtualMemory::SwitchAddressSpace(Process->GetAddressSpace()); VirtualMemory::MapUser(MapTo, PhysStack); -#else - uintptr_t StackPos = (uintptr_t) PhysStack + 4096; -#endif size_t* Stack = (size_t*) StackPos; #ifdef PLATFORM_X86 @@ -311,10 +290,8 @@ namespace Sortix // Mark the thread as running, which adds it to the scheduler's linked list. thread->SetState(Thread::State::RUNNABLE); -#ifdef PLATFORM_VIRTUAL_MEMORY // Avoid side effects by restoring the old address space. VirtualMemory::SwitchAddressSpace(OldAddrSpace); -#endif return thread; } @@ -390,7 +367,8 @@ namespace Sortix #ifdef PLATFORM_X86 - if ( currentThread != NoopThread ) + // TODO: HACK: Find a more accurate way to test for kernel code. + if ( R->eip >= 0x400000UL ) { uint32_t RPL = 0x3; @@ -460,11 +438,7 @@ namespace Sortix // TODO: What do we do with the result parameter? Thread->~Thread(); //Log::PrintF("\n", Thread); -#ifndef PLATFORM_KERNEL_HEAP - Page::Put((addr_t) Thread); -#else delete Thread; -#endif //Log::PrintF("\n", Thread); if ( Thread == currentThread ) { currentThread = NULL; } diff --git a/sortix/serialterminal.cpp b/sortix/serialterminal.cpp index 0d630640..b701f43e 100644 --- a/sortix/serialterminal.cpp +++ b/sortix/serialterminal.cpp @@ -25,8 +25,10 @@ #include "platform.h" #include #include "log.h" +#include "vga.h" #include "uart.h" #include "serialterminal.h" +#include "vgaterminal.h" namespace Sortix { @@ -46,7 +48,12 @@ namespace Sortix size_t Print(void* /*user*/, const char* string, size_t stringlen) { +#ifdef JSSORTIX + VGATerminal::Print(NULL, string, stringlen); + UART::RenderVGA((VGA::Frame*) 0xB8000); +#else UART::Write(string, stringlen); +#endif return stringlen; } } diff --git a/sortix/time.cpp b/sortix/time.cpp index 40a42583..05c3d856 100644 --- a/sortix/time.cpp +++ b/sortix/time.cpp @@ -29,6 +29,13 @@ #include "scheduler.h" #include "log.h" +#ifdef PLATFORM_SERIAL +#include +#include "keyboard.h" +#include "vga.h" +#include "uart.h" +#endif + #if !defined(PLATFORM_X86_FAMILY) #error No time subsystem is available for this CPU #endif @@ -72,6 +79,8 @@ namespace Sortix } bool didUglyIRQ0Hack; + bool isEsc; + bool isEscDepress; void Init() { @@ -86,10 +95,47 @@ namespace Sortix didUglyIRQ0Hack = false; RequestIQR0(); + + isEsc = isEscDepress = false; } void OnIRQ0(CPU::InterruptRegisters* Regs) { +#ifdef PLATFORM_SERIAL + // TODO: Yeah, this is a bad hack. + int c; + while ( (c=UART::TryPopChar()) != -1 ) + { + using namespace Maxsi::Keyboard; + + if ( !isEsc && c == '\e' ) { isEsc = true; continue; } + if ( isEsc && c == '\e' ) { isEsc = false; } + if ( isEsc && c == '[' ) { continue; } + if ( isEsc && c == ']' ) { isEscDepress = true; continue; } + if ( isEsc && !isEscDepress && c == 'A' ) { Keyboard::QueueKeystroke(UP); } + if ( isEsc && !isEscDepress && c == 'B' ) { Keyboard::QueueKeystroke(DOWN); } + if ( isEsc && !isEscDepress && c == 'C' ) { Keyboard::QueueKeystroke(RIGHT); } + if ( isEsc && !isEscDepress && c == 'D' ) { Keyboard::QueueKeystroke(LEFT); } + if ( isEsc && isEscDepress && c == 'A' ) { Keyboard::QueueKeystroke(UP | DEPRESSED); } + if ( isEsc && isEscDepress && c == 'B' ) { Keyboard::QueueKeystroke(DOWN | DEPRESSED); } + if ( isEsc && isEscDepress && c == 'C' ) { Keyboard::QueueKeystroke(RIGHT | DEPRESSED); } + if ( isEsc && isEscDepress && c == 'D' ) { Keyboard::QueueKeystroke(LEFT | DEPRESSED); } + if ( isEsc ) { isEsc = false; isEscDepress = false; continue; } + if ( c == '\e' ) { c = ESC; } + if ( c == ('\e' | (1<<7)) ) { c = ESC | DEPRESSED; } + if ( c == 3 ) { SigInt(); continue; } + if ( c == 127 ) { c = '\b'; } + if ( c & (1<<7) ) + { + c &= ~(1<<7); c |= DEPRESSED; + } + Keyboard::QueueKeystroke(c); + } + + // TODO: But this hack may be worse. + UART::RenderVGA((VGA::Frame*) 0xB8000); +#endif + Ticks++; // Let the scheduler switch to the next task. diff --git a/sortix/uart.cpp b/sortix/uart.cpp index 2a6393cb..c950070a 100644 --- a/sortix/uart.cpp +++ b/sortix/uart.cpp @@ -24,6 +24,7 @@ #include "platform.h" #include +#include #ifdef PLATFORM_SERIAL #include "vga.h" #endif @@ -216,15 +217,11 @@ namespace Sortix void RenderVGA(const VGA::Frame* Frame) { -#if 0 - // Set the cursor to (0,0) - const char InitMessage[] = { String::ASCII_ESCAPE, '[', 'H' }; - UART::Write(InitMessage, sizeof(InitMessage)); - const uint16_t* Source = Frame->Data; nat LastColor = 1337; nat SkippedSince = 0; + bool posundefined = true; for ( nat Y = 0; Y < Frame->Height; Y++) { @@ -237,33 +234,42 @@ namespace Sortix if ( Element == OldElement ) { continue; } - VGALastFrame.Data[Index] = Element; - // Update the position if we skipped some characters. - if ( Index - SkippedSince > 8 ) + if ( Index - SkippedSince > 8 || posundefined ) { const nat LineId = Y + 1; const nat ColumnId = X + 1; if ( ColumnId > 1 ) { - const char Message[] = { String::ASCII_ESCAPE, '[', '0' + LineId / 10, '0' + LineId % 10, ';', '0' + ColumnId / 10, '0' + ColumnId % 10, 'H' }; - UART::Write(Message, sizeof(Message)); + UART::WriteChar('\e'); + UART::WriteChar('['); + UART::WriteChar('0' + LineId / 10); + UART::WriteChar('0' + LineId % 10); + UART::WriteChar(';'); + UART::WriteChar('0' + ColumnId / 10); + UART::WriteChar('0' + ColumnId % 10); + UART::WriteChar('H'); } else { - const char Message[] = { String::ASCII_ESCAPE, '[', '0' + LineId / 10, '0' + LineId % 10, 'H' }; - UART::Write(Message, sizeof(Message)); + UART::WriteChar('\e'); + UART::WriteChar('['); + UART::WriteChar('0' + LineId / 10); + UART::WriteChar('0' + LineId % 10); + UART::WriteChar('H'); } SkippedSince = Index; + posundefined = false; } for ( nat Pos = SkippedSince; Pos <= Index; Pos++ ) { Element = Source[Pos]; + OldElement = VGALastFrame.Data[Pos]; - nat NewColor = ConversionTable[ (Element >> 12) & 0xF ] << 3 | ConversionTable[ (Element >> 8) & 0xF ]; + nat NewColor = (ConversionTable[ (Element >> 12) & 0xF ] << 3) | (ConversionTable[ (Element >> 8) & 0xF ]); // Change the color if we need to. if ( LastColor != NewColor ) @@ -272,26 +278,41 @@ namespace Sortix nat OldBGColor = LastColor / 8; nat FGColor = NewColor % 8; nat BGColor = NewColor / 8; + if ( LastColor == 1337 ) { OldFGColor = 9; OldBGColor = 9; } if ( (OldFGColor != FGColor) && (OldBGColor != BGColor) ) { - const char Message[] = { String::ASCII_ESCAPE, '[', '3', '0' + FGColor, ';', '4', '0' + BGColor, 'm' }; - UART::Write(Message, sizeof(Message)); + UART::WriteChar('\e'); + UART::WriteChar('['); + UART::WriteChar('3'); + UART::WriteChar('0' + FGColor); + UART::WriteChar(';'); + UART::WriteChar('4'); + UART::WriteChar('0' + BGColor); + UART::WriteChar('m'); } else if ( OldFGColor != FGColor ) { - const char Message[] = { String::ASCII_ESCAPE, '[', '3', '0' + FGColor, 'm' }; - UART::Write(Message, sizeof(Message)); + UART::WriteChar('\e'); + UART::WriteChar('['); + UART::WriteChar('3'); + UART::WriteChar('0' + FGColor); + UART::WriteChar('m'); } else if ( OldBGColor != BGColor ) { - const char Message[] = { String::ASCII_ESCAPE, '[', '4', '0' + BGColor, 'm' }; - UART::Write(Message, sizeof(Message)); + UART::WriteChar('\e'); + UART::WriteChar('['); + UART::WriteChar('4'); + UART::WriteChar('0' + BGColor); + UART::WriteChar('m'); } LastColor = NewColor; } + VGALastFrame.Data[Pos] = Element; + Element &= 0x7F; // Filter away any non-printable characters. @@ -303,7 +324,6 @@ namespace Sortix SkippedSince = Index + 1; } } -#endif } #endif } diff --git a/sortix/x86/interrupt.asm b/sortix/x86/interrupt.asm index 0a806e0c..b28276ac 100644 --- a/sortix/x86/interrupt.asm +++ b/sortix/x86/interrupt.asm @@ -119,7 +119,7 @@ isr_common_stub: popa ; Pops edi,esi,ebp... add esp, 8 ; Cleans up the pushed error code and pushed ISR number - sti + ;sti iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP ; In isr.c @@ -155,7 +155,7 @@ irq_common_stub: popa ; Pops edi,esi,ebp... add esp, 8 ; Cleans up the pushed error code and pushed ISR number - sti + ;sti iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP diff --git a/utils/init.cpp b/utils/init.cpp index 687a9b38..de059a90 100644 --- a/utils/init.cpp +++ b/utils/init.cpp @@ -4,7 +4,7 @@ int main(int argc, char* argv[]) { // Reset the terminal's color and the rest of it. - printf("\e[m\e[J"); + printf("\r\e[m\e[J"); const char* programname = "sh"; const char* newargv[] = { programname };