diff --git a/.gitignore b/.gitignore index 15f6350..409d10a 100644 --- a/.gitignore +++ b/.gitignore @@ -329,3 +329,5 @@ ASALocalRun/ # MFractors (Xamarin productivity tool) working folder .mfractor/ From_Linux +My_Doom +doomgeneric-windows diff --git a/Media/Screenshots/Debugger.png b/Media/Screenshots/Debugger.png new file mode 100644 index 0000000..5708b3d Binary files /dev/null and b/Media/Screenshots/Debugger.png differ diff --git a/Media/Screenshots/LineCounter.png b/Media/Screenshots/LineCounter.png new file mode 100644 index 0000000..4e78176 Binary files /dev/null and b/Media/Screenshots/LineCounter.png differ diff --git a/Media/Screenshots/MyOS_GUI.gif b/Media/Screenshots/MyOS_GUI.gif new file mode 100644 index 0000000..7a00523 Binary files /dev/null and b/Media/Screenshots/MyOS_GUI.gif differ diff --git a/Media/Screenshots/MyOS_GUI_1.png b/Media/Screenshots/MyOS_GUI_1.png new file mode 100644 index 0000000..3ab0355 Binary files /dev/null and b/Media/Screenshots/MyOS_GUI_1.png differ diff --git a/Media/Screenshots/linux_lines.png b/Media/Screenshots/linux_lines.png new file mode 100644 index 0000000..daad11e Binary files /dev/null and b/Media/Screenshots/linux_lines.png differ diff --git a/Media/Screenshots/managarm_lines.png b/Media/Screenshots/managarm_lines.png new file mode 100644 index 0000000..36e257b Binary files /dev/null and b/Media/Screenshots/managarm_lines.png differ diff --git a/Media/Screenshots/reactos_lines.png b/Media/Screenshots/reactos_lines.png new file mode 100644 index 0000000..008495f Binary files /dev/null and b/Media/Screenshots/reactos_lines.png differ diff --git a/Media/Screenshots/serenityos_lines.png b/Media/Screenshots/serenityos_lines.png new file mode 100644 index 0000000..38bdaff Binary files /dev/null and b/Media/Screenshots/serenityos_lines.png differ diff --git a/Media/Screenshots/toaruos_lines.png b/Media/Screenshots/toaruos_lines.png new file mode 100644 index 0000000..3d53706 Binary files /dev/null and b/Media/Screenshots/toaruos_lines.png differ diff --git a/My-Doom b/My-Doom index c60abc6..2c2ea58 160000 --- a/My-Doom +++ b/My-Doom @@ -1 +1 @@ -Subproject commit c60abc6bc10bd30e733e29056e232c54e1dc283c +Subproject commit 2c2ea58e8e36389d39f79bb6e1e2f64b3abf7807 diff --git a/MyOS_1.sln b/MyOS_1.sln index 7911fd7..4c5b5d9 100644 --- a/MyOS_1.sln +++ b/MyOS_1.sln @@ -13,54 +13,128 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SDL_TestApp1_For_Windows", EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "My_Doom", "My-Doom\My_Doom.vcxproj", "{07EC26D7-871D-4847-AAC0-7A80B40B99CE}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MyOS_GUI_Shell", "MyOS_GUI_Shell\MyOS_GUI_Shell.vcxproj", "{DD34D14A-8D2B-41FA-9EA5-02A5355F9BC4}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MyOS_GUI_Shell_For_Windows", "MyOS_GUI_For_Windows\MyOS_GUI_For_Windows.vcxproj", "{19CF43DA-2745-451D-B811-0A40EF43BE2F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestApp2", "TestApp2\TestApp2.vcxproj", "{04870E40-8ABF-4BD7-AED0-3885C7F535D7}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestApp2ForWindows", "TestApp2ForWindows\TestApp2ForWindows.vcxproj", "{6BA12269-A558-4634-B51D-B61FD8143410}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleDebugger", "SupportApps\SimpleDebugger\SimpleDebugger.csproj", "{5DF601CC-B794-43C6-8138-3B9ED99F2843}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {31C0B908-9659-4141-AFE2-C6B742FCA313}.Debug|Any CPU.ActiveCfg = Debug|Win32 {31C0B908-9659-4141-AFE2-C6B742FCA313}.Debug|x64.ActiveCfg = Debug|x64 {31C0B908-9659-4141-AFE2-C6B742FCA313}.Debug|x64.Build.0 = Debug|x64 {31C0B908-9659-4141-AFE2-C6B742FCA313}.Debug|x86.ActiveCfg = Debug|Win32 {31C0B908-9659-4141-AFE2-C6B742FCA313}.Debug|x86.Build.0 = Debug|Win32 + {31C0B908-9659-4141-AFE2-C6B742FCA313}.Release|Any CPU.ActiveCfg = Release|Win32 {31C0B908-9659-4141-AFE2-C6B742FCA313}.Release|x64.ActiveCfg = Release|x64 {31C0B908-9659-4141-AFE2-C6B742FCA313}.Release|x64.Build.0 = Release|x64 {31C0B908-9659-4141-AFE2-C6B742FCA313}.Release|x86.ActiveCfg = Release|Win32 {31C0B908-9659-4141-AFE2-C6B742FCA313}.Release|x86.Build.0 = Release|Win32 + {5D4E87A7-5402-4E84-B89D-6A7B42936E4D}.Debug|Any CPU.ActiveCfg = Debug|Win32 {5D4E87A7-5402-4E84-B89D-6A7B42936E4D}.Debug|x64.ActiveCfg = Debug|x64 {5D4E87A7-5402-4E84-B89D-6A7B42936E4D}.Debug|x64.Build.0 = Debug|x64 {5D4E87A7-5402-4E84-B89D-6A7B42936E4D}.Debug|x86.ActiveCfg = Debug|Win32 {5D4E87A7-5402-4E84-B89D-6A7B42936E4D}.Debug|x86.Build.0 = Debug|Win32 + {5D4E87A7-5402-4E84-B89D-6A7B42936E4D}.Release|Any CPU.ActiveCfg = Release|Win32 {5D4E87A7-5402-4E84-B89D-6A7B42936E4D}.Release|x64.ActiveCfg = Release|x64 {5D4E87A7-5402-4E84-B89D-6A7B42936E4D}.Release|x64.Build.0 = Release|x64 {5D4E87A7-5402-4E84-B89D-6A7B42936E4D}.Release|x86.ActiveCfg = Release|Win32 {5D4E87A7-5402-4E84-B89D-6A7B42936E4D}.Release|x86.Build.0 = Release|Win32 + {E20F026A-1CE2-4B40-BEA7-39E9644F3A0C}.Debug|Any CPU.ActiveCfg = Debug|Win32 {E20F026A-1CE2-4B40-BEA7-39E9644F3A0C}.Debug|x64.ActiveCfg = Debug|x64 {E20F026A-1CE2-4B40-BEA7-39E9644F3A0C}.Debug|x64.Build.0 = Debug|x64 {E20F026A-1CE2-4B40-BEA7-39E9644F3A0C}.Debug|x86.ActiveCfg = Debug|Win32 {E20F026A-1CE2-4B40-BEA7-39E9644F3A0C}.Debug|x86.Build.0 = Debug|Win32 + {E20F026A-1CE2-4B40-BEA7-39E9644F3A0C}.Release|Any CPU.ActiveCfg = Release|Win32 {E20F026A-1CE2-4B40-BEA7-39E9644F3A0C}.Release|x64.ActiveCfg = Release|x64 {E20F026A-1CE2-4B40-BEA7-39E9644F3A0C}.Release|x64.Build.0 = Release|x64 {E20F026A-1CE2-4B40-BEA7-39E9644F3A0C}.Release|x86.ActiveCfg = Release|Win32 {E20F026A-1CE2-4B40-BEA7-39E9644F3A0C}.Release|x86.Build.0 = Release|Win32 + {E287BF76-1C8A-41CE-8698-A412691721BC}.Debug|Any CPU.ActiveCfg = Debug|Win32 {E287BF76-1C8A-41CE-8698-A412691721BC}.Debug|x64.ActiveCfg = Debug|x64 {E287BF76-1C8A-41CE-8698-A412691721BC}.Debug|x64.Build.0 = Debug|x64 {E287BF76-1C8A-41CE-8698-A412691721BC}.Debug|x86.ActiveCfg = Debug|Win32 {E287BF76-1C8A-41CE-8698-A412691721BC}.Debug|x86.Build.0 = Debug|Win32 + {E287BF76-1C8A-41CE-8698-A412691721BC}.Release|Any CPU.ActiveCfg = Release|Win32 {E287BF76-1C8A-41CE-8698-A412691721BC}.Release|x64.ActiveCfg = Release|x64 {E287BF76-1C8A-41CE-8698-A412691721BC}.Release|x64.Build.0 = Release|x64 {E287BF76-1C8A-41CE-8698-A412691721BC}.Release|x86.ActiveCfg = Release|Win32 {E287BF76-1C8A-41CE-8698-A412691721BC}.Release|x86.Build.0 = Release|Win32 + {07EC26D7-871D-4847-AAC0-7A80B40B99CE}.Debug|Any CPU.ActiveCfg = Debug|Win32 {07EC26D7-871D-4847-AAC0-7A80B40B99CE}.Debug|x64.ActiveCfg = Debug|x64 {07EC26D7-871D-4847-AAC0-7A80B40B99CE}.Debug|x64.Build.0 = Debug|x64 {07EC26D7-871D-4847-AAC0-7A80B40B99CE}.Debug|x86.ActiveCfg = Debug|Win32 {07EC26D7-871D-4847-AAC0-7A80B40B99CE}.Debug|x86.Build.0 = Debug|Win32 + {07EC26D7-871D-4847-AAC0-7A80B40B99CE}.Release|Any CPU.ActiveCfg = Release|Win32 {07EC26D7-871D-4847-AAC0-7A80B40B99CE}.Release|x64.ActiveCfg = Release|x64 {07EC26D7-871D-4847-AAC0-7A80B40B99CE}.Release|x64.Build.0 = Release|x64 {07EC26D7-871D-4847-AAC0-7A80B40B99CE}.Release|x86.ActiveCfg = Release|Win32 {07EC26D7-871D-4847-AAC0-7A80B40B99CE}.Release|x86.Build.0 = Release|Win32 + {DD34D14A-8D2B-41FA-9EA5-02A5355F9BC4}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {DD34D14A-8D2B-41FA-9EA5-02A5355F9BC4}.Debug|x64.ActiveCfg = Debug|x64 + {DD34D14A-8D2B-41FA-9EA5-02A5355F9BC4}.Debug|x64.Build.0 = Debug|x64 + {DD34D14A-8D2B-41FA-9EA5-02A5355F9BC4}.Debug|x86.ActiveCfg = Debug|Win32 + {DD34D14A-8D2B-41FA-9EA5-02A5355F9BC4}.Debug|x86.Build.0 = Debug|Win32 + {DD34D14A-8D2B-41FA-9EA5-02A5355F9BC4}.Release|Any CPU.ActiveCfg = Release|Win32 + {DD34D14A-8D2B-41FA-9EA5-02A5355F9BC4}.Release|x64.ActiveCfg = Release|x64 + {DD34D14A-8D2B-41FA-9EA5-02A5355F9BC4}.Release|x64.Build.0 = Release|x64 + {DD34D14A-8D2B-41FA-9EA5-02A5355F9BC4}.Release|x86.ActiveCfg = Release|Win32 + {DD34D14A-8D2B-41FA-9EA5-02A5355F9BC4}.Release|x86.Build.0 = Release|Win32 + {19CF43DA-2745-451D-B811-0A40EF43BE2F}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {19CF43DA-2745-451D-B811-0A40EF43BE2F}.Debug|x64.ActiveCfg = Debug|x64 + {19CF43DA-2745-451D-B811-0A40EF43BE2F}.Debug|x64.Build.0 = Debug|x64 + {19CF43DA-2745-451D-B811-0A40EF43BE2F}.Debug|x86.ActiveCfg = Debug|Win32 + {19CF43DA-2745-451D-B811-0A40EF43BE2F}.Debug|x86.Build.0 = Debug|Win32 + {19CF43DA-2745-451D-B811-0A40EF43BE2F}.Release|Any CPU.ActiveCfg = Release|Win32 + {19CF43DA-2745-451D-B811-0A40EF43BE2F}.Release|x64.ActiveCfg = Release|x64 + {19CF43DA-2745-451D-B811-0A40EF43BE2F}.Release|x64.Build.0 = Release|x64 + {19CF43DA-2745-451D-B811-0A40EF43BE2F}.Release|x86.ActiveCfg = Release|Win32 + {19CF43DA-2745-451D-B811-0A40EF43BE2F}.Release|x86.Build.0 = Release|Win32 + {04870E40-8ABF-4BD7-AED0-3885C7F535D7}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {04870E40-8ABF-4BD7-AED0-3885C7F535D7}.Debug|x64.ActiveCfg = Debug|x64 + {04870E40-8ABF-4BD7-AED0-3885C7F535D7}.Debug|x64.Build.0 = Debug|x64 + {04870E40-8ABF-4BD7-AED0-3885C7F535D7}.Debug|x86.ActiveCfg = Debug|Win32 + {04870E40-8ABF-4BD7-AED0-3885C7F535D7}.Debug|x86.Build.0 = Debug|Win32 + {04870E40-8ABF-4BD7-AED0-3885C7F535D7}.Release|Any CPU.ActiveCfg = Release|Win32 + {04870E40-8ABF-4BD7-AED0-3885C7F535D7}.Release|x64.ActiveCfg = Release|x64 + {04870E40-8ABF-4BD7-AED0-3885C7F535D7}.Release|x64.Build.0 = Release|x64 + {04870E40-8ABF-4BD7-AED0-3885C7F535D7}.Release|x86.ActiveCfg = Release|Win32 + {04870E40-8ABF-4BD7-AED0-3885C7F535D7}.Release|x86.Build.0 = Release|Win32 + {6BA12269-A558-4634-B51D-B61FD8143410}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {6BA12269-A558-4634-B51D-B61FD8143410}.Debug|x64.ActiveCfg = Debug|x64 + {6BA12269-A558-4634-B51D-B61FD8143410}.Debug|x64.Build.0 = Debug|x64 + {6BA12269-A558-4634-B51D-B61FD8143410}.Debug|x86.ActiveCfg = Debug|Win32 + {6BA12269-A558-4634-B51D-B61FD8143410}.Debug|x86.Build.0 = Debug|Win32 + {6BA12269-A558-4634-B51D-B61FD8143410}.Release|Any CPU.ActiveCfg = Release|Win32 + {6BA12269-A558-4634-B51D-B61FD8143410}.Release|x64.ActiveCfg = Release|x64 + {6BA12269-A558-4634-B51D-B61FD8143410}.Release|x64.Build.0 = Release|x64 + {6BA12269-A558-4634-B51D-B61FD8143410}.Release|x86.ActiveCfg = Release|Win32 + {6BA12269-A558-4634-B51D-B61FD8143410}.Release|x86.Build.0 = Release|Win32 + {5DF601CC-B794-43C6-8138-3B9ED99F2843}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5DF601CC-B794-43C6-8138-3B9ED99F2843}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5DF601CC-B794-43C6-8138-3B9ED99F2843}.Debug|x64.ActiveCfg = Debug|Any CPU + {5DF601CC-B794-43C6-8138-3B9ED99F2843}.Debug|x64.Build.0 = Debug|Any CPU + {5DF601CC-B794-43C6-8138-3B9ED99F2843}.Debug|x86.ActiveCfg = Debug|Any CPU + {5DF601CC-B794-43C6-8138-3B9ED99F2843}.Debug|x86.Build.0 = Debug|Any CPU + {5DF601CC-B794-43C6-8138-3B9ED99F2843}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5DF601CC-B794-43C6-8138-3B9ED99F2843}.Release|Any CPU.Build.0 = Release|Any CPU + {5DF601CC-B794-43C6-8138-3B9ED99F2843}.Release|x64.ActiveCfg = Release|Any CPU + {5DF601CC-B794-43C6-8138-3B9ED99F2843}.Release|x64.Build.0 = Release|Any CPU + {5DF601CC-B794-43C6-8138-3B9ED99F2843}.Release|x86.ActiveCfg = Release|Any CPU + {5DF601CC-B794-43C6-8138-3B9ED99F2843}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/MyOS_1/Build_Number.h b/MyOS_1/Build_Number.h index d7623d0..88bd708 100644 --- a/MyOS_1/Build_Number.h +++ b/MyOS_1/Build_Number.h @@ -3,4 +3,4 @@ // Define a build number. This number will be incremented by a simple console program called by a post-build event // It's put here in its own file to keep the other program from messing up the source #define \ -BUILD_NUMBER 4705 +BUILD_NUMBER 6510 diff --git a/MyOS_1/CPP_Support.cpp b/MyOS_1/CPP_Support.cpp new file mode 100644 index 0000000..c7265f7 --- /dev/null +++ b/MyOS_1/CPP_Support.cpp @@ -0,0 +1,48 @@ + +#include "misc.h" + +void* operator new(size_t size) +{ + // Allocate memory + return dbg_alloc(size); +} + + +void* operator new[](size_t size) +{ + // Allocate memory + return dbg_alloc(size); +} + + +void operator delete(void *p) +{ + if (p == 0) { + return; + } + + // Release allocated memory + dbg_release(p); +} + +void operator delete(void *p, size_t size) +{ + (void)size; + + if (p == 0) { + return; + } + + // Release allocated memory + dbg_release(p); +} + +void operator delete[](void *p) +{ + if (p == 0) { + return; + } + + // Release allocated memory + dbg_release(p); +} diff --git a/MyOS_1/Console_Serial.c b/MyOS_1/Console_Serial.c index 72ba0e2..bcd84a3 100644 --- a/MyOS_1/Console_Serial.c +++ b/MyOS_1/Console_Serial.c @@ -1,12 +1,15 @@ #include "Console_Serial.h" #include "System_Specific.h" +#include "printf.h" #ifndef USE_SERIAL void init_serial() {} -/*int serial_received() {} -char read_serial() {} -int is_transmit_empty() {}*/ +int serial_received() { return false; } +char read_serial() { return '\0'; } +int is_transmit_empty() { return true; } +int sprintf(char *messageFormat, ...) { return 0; } void write_serial(char a) {} +void write_serial_string(const char *str) {} #endif #ifdef USE_SERIAL @@ -34,9 +37,30 @@ int is_transmit_empty() { return inb(PORT + 5) & 0x20; } +int serial_printf(char *messageFormat, ...) +{ + char buffer[128] = { 0 }; + va_list va; + va_start(va, messageFormat); + const int ret = vsnprintf(buffer, 128, messageFormat, va); + + write_serial_string(buffer); + va_end(va); + + return ret; +} + void write_serial(char a) { while (is_transmit_empty() == 0); outb(PORT, a); } + +void write_serial_string(const char *str) +{ + int len = strlen(str); + for (int i = 0; i < len; ++i) + write_serial(str[i]); +} + #endif \ No newline at end of file diff --git a/MyOS_1/Console_Serial.h b/MyOS_1/Console_Serial.h index b2cbb1e..263359c 100644 --- a/MyOS_1/Console_Serial.h +++ b/MyOS_1/Console_Serial.h @@ -13,4 +13,8 @@ char read_serial(); int serial_received(); +int serial_printf(char *messageFormat, ...); + void write_serial(char a); + +void write_serial_string(const char *str); diff --git a/MyOS_1/Console_Shell.c b/MyOS_1/Console_Shell.c index fd73176..7d09a4d 100644 --- a/MyOS_1/Console_Shell.c +++ b/MyOS_1/Console_Shell.c @@ -2,6 +2,7 @@ #include "Build_Number.h" #include "Console_Shell.h" #include "Console_VGA.h" +#include "Tasks/Context.h" #include "misc.h" #include "Networking/TFTP.h" #include "Networking/IPv4.h" @@ -27,6 +28,10 @@ #include "printf.h" #include "Drivers/Virtio_GPU.h" #include "myos_io.h" +#include "Drivers\Keyboard.h" +#include "../MyOS_GUI_Shell/GUI_Kernel_Shell.h" +#include "Drivers/IDE.h" +#include "Debugging/Debug.h" int inputPosition = 0; #define COMMAND_HISTORY_SIZE 10 @@ -326,6 +331,17 @@ void Shell_Process_command(void) return; } + // Test writint + if (strcmp(currentCommand, "write") == 0) + { + tftpHideErrors = false; + + /*uint16_t sourcePort =*/ TFTP_WriteFile(tftpServerIP, "test.txt", TFTP_TYPE_BINARY, NIC_MAC); + + kprintf("Done.\n"); + return; + } + // Test IO functions if (strcmp(currentCommand, "testio") == 0) { @@ -411,6 +427,30 @@ void Shell_Process_command(void) return; } + // Display connected IDE drives + if (strcmp(currentCommand, "ide") == 0) + { + kprintf("Attached IDE devices:"); + bool deviceFound = false; + + for (uint8_t device = 0; device < 4; ++device) + { + if (ide_devices[device].Present) + { + deviceFound = true; + kprintf("\n%s drive at Channel %d device %d - %s", + ide_devices[device].Type == IDE_ATA ? " ATA" : " ATAPI", + ide_devices[device].Channel, + ide_devices[device].Drive, + ide_devices[device].Model); + } + } + + kprintf(deviceFound ? "\n" : " None\n"); + + return; + } + // Initialize mouse if (strcmp(currentCommand, "m") == 0) { @@ -463,6 +503,13 @@ void Shell_Process_command(void) return; } + // Test stack trace + if (strcmp(currentCommand, "bt") == 0) + { + DebugStackTrace(6); + return; + } + // Test memory allocation if (strcmp(currentCommand, "mem") == 0) { @@ -700,7 +747,7 @@ void Shell_Process_command(void) } // TODO: Switch to display HAL once that's implemented - BGA_SetResolution(800, 600, 32); + BGA_SetResolution(GRAPHICS_WIDTH, GRAPHICS_HEIGHT, 32); // Fill screen with color so we know it worked GraphicsFillScreen(0, 0, 0); @@ -867,9 +914,10 @@ void Shell_Process_command(void) // Run command memset(subCommand, 0, MAX_COMMAND_LENGTH); - strncpy(subCommand, currentCommand, strlen("run")); - if (strcmp(subCommand, "run") == 0) + strncpy(subCommand, currentCommand, strlen("run ")); + if (strcmp(subCommand, "run ") == 0) { + bool exclusive = false; memset(subCommand, 0, MAX_COMMAND_LENGTH); strncpy(subCommand, currentCommand + strlen("run "), MAX_COMMAND_LENGTH - strlen("run ")); @@ -879,10 +927,20 @@ void Shell_Process_command(void) return; } + // Check for "exclusive" option + if (strncmp(subCommand, "exclusive ", strlen("exclusive ")) == 0) + { + exclusive = true; + memset(subCommand, 0, MAX_COMMAND_LENGTH); + strncpy(subCommand, currentCommand + strlen("run exclusive "), MAX_COMMAND_LENGTH - strlen("run exclusive ")); + } + if (debugLevel) { terminal_writestring("Ok, I'll run "); terminal_writestring(subCommand); + if (exclusive) + terminal_writestring(" in exclusive mode"); terminal_newline(); } @@ -895,54 +953,73 @@ void Shell_Process_command(void) return; } - // TEMPTEMP we've hardcoded some memory starting at 0x800000. This was identity mapped when paging was enabled. - uint8_t *exeBuffer = (uint8_t*)0x800000; + // TEMPTEMP apps should start at 0x80 0000 + uint32_t exeBuffer = 0x800000; - // Get the size of the executable file - uint32_t fileSize; - if (!TFTP_GetFileSize(tftpServerIP, subCommand, &fileSize)) + // reset keyboard input buffer + keyReadIndex = keyWriteIndex = 0; + + LaunchApp(subCommand, exclusive, exeBuffer); + + terminal_resume(); + + if (debugLevel) + terminal_writestring("done!\n"); + + return; + } + + // Runhi command - used to load GUI at a different memory address than other programs, mapped into kernel space + memset(subCommand, 0, MAX_COMMAND_LENGTH); + strncpy(subCommand, currentCommand, strlen("runhi")); + if (strcmp(subCommand, "runhi") == 0) + { + bool exclusive = false; + memset(subCommand, 0, MAX_COMMAND_LENGTH); + strncpy(subCommand, currentCommand + strlen("runhi "), MAX_COMMAND_LENGTH - strlen("runhi ")); + + if (strlen(subCommand) == 0) { - terminal_writestring("Failed to determine size of "); - terminal_writestring(subCommand); - terminal_newline(); + terminal_writestring("You must specify the name of an executable to run!\n\nUsage: runhi [Name_Of_File.exe]\n"); return; } - // Allocate a buffer for the executable file - uint8_t *peBuffer = malloc(fileSize); - if (!peBuffer) + // Check for "exclusive" option + if (strcmp(subCommand, "exclusive ") == 0) { - terminal_writestring("Not enough memory to open bitmap file\n"); - return; + exclusive = true; + memset(subCommand, 0, MAX_COMMAND_LENGTH); + strncpy(currentCommand, currentCommand + strlen("runhi exclusive"), MAX_COMMAND_LENGTH - strlen("runhi exclusive")); } - //uint32_t peFileSize; - - if(debugLevel) - terminal_dumpHex(peBuffer, 32); - - // Download the executable - if (!TFTP_GetFile(tftpServerIP, subCommand, peBuffer, fileSize, NULL) ) + if (debugLevel) { - terminal_writestring("Error reading "); + terminal_writestring("Ok, I'll run "); terminal_writestring(subCommand); - terminal_writestring(" from server!\n"); - return; + if (exclusive) + terminal_writestring(" in exclusive mode"); + terminal_writestring(" at 12 MB"); + terminal_newline(); } - if(debugLevel) - terminal_dumpHex(peBuffer, 32); - - // Run the executable - if (!loadAndRunPE(exeBuffer, (DOS_Header*)peBuffer)) - terminal_writestring("Error running executable\n"); + // See if a batch file was requested + if (IsBatchFile(subCommand)) + { + OpenAndRunBatch(subCommand); + if (debugLevel) + terminal_writestring("done!\n"); + return; + } - // Free the memory for the pe - free(peBuffer); + // reset keyboard input buffer + keyReadIndex = keyWriteIndex = 0; + // TEMPTEMP we've hardcoded some memory starting at 0xC00000. This was identity mapped when paging was enabled. + LaunchApp(subCommand, exclusive, GUI_BASE_ADDRESS); + terminal_resume(); - if(debugLevel) + if (debugLevel) terminal_writestring("done!\n"); return; diff --git a/MyOS_1/Debugging/Debug.c b/MyOS_1/Debugging/Debug.c new file mode 100644 index 0000000..e30719a --- /dev/null +++ b/MyOS_1/Debugging/Debug.c @@ -0,0 +1,22 @@ +#include "Debug.h" +#include "../printf.h" +#include "../Tasks/Context.h" +#include "../Console_Serial.h" + +// This is meant to be used with the debugger support app, custom for MyOS +void DebugStackTrace(unsigned int MaxFrames) +{ + STACK_FRAME *pStackFrame; + __asm mov pStackFrame, ebp + + serial_printf("Stack trace:\n%s\n", tasks[currentTask].imageName); + + for (unsigned int frame = 0; pStackFrame && frame < MaxFrames; ++frame) + { + // Unwind to previous stack frame + serial_printf("0x%X\n", pStackFrame->eip); + if (pStackFrame->eip == 0) + break; + pStackFrame = pStackFrame->ebp; + } +} \ No newline at end of file diff --git a/MyOS_1/Debugging/Debug.h b/MyOS_1/Debugging/Debug.h new file mode 100644 index 0000000..7d21ee6 --- /dev/null +++ b/MyOS_1/Debugging/Debug.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +typedef struct STACK_FRAME +{ + struct STACK_FRAME* ebp; + uint32_t eip; +}STACK_FRAME; + +void DebugStackTrace(unsigned int MaxFrames); \ No newline at end of file diff --git a/MyOS_1/Drivers/IDE.c b/MyOS_1/Drivers/IDE.c new file mode 100644 index 0000000..2888e9a --- /dev/null +++ b/MyOS_1/Drivers/IDE.c @@ -0,0 +1,333 @@ +#include "IDE.h" +#include "../printf.h" +#include "../System_Specific.h" +#include "../Timers/System_Clock.h" +#include "../misc.h" +#include "../Interrupts/IDT.h" +#include "../Interrupts/Interrupts.h" + +// TODO: Support multiple IDE controllers +uint8_t IDE_bus; +uint8_t IDE_slot; +uint8_t IDE_function; +bool IDE_Present; + +IDE_CHANNEL_INFO channels[2]; + +uint8_t ide_buf[2048] = { 0 }; +bool ide_irq_invoked = 0; +//uint8_t atapi_packet[12] = { 0xA8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +void _declspec(naked) IDE_primary_channel_interrupt_handler() +{ + __asm + { + push ebp + mov ebp, esp + } + + ++interrupts_fired; + + if (debugLevel) + terminal_writestring(" --------- IDE 0 interrupt fired! -------\n"); + + ide_irq_invoked = true; + + PIC_sendEOI(HARDWARE_INTERRUPTS_BASE + channels[0].irq); + + if (debugLevel) + terminal_writestring(" --------- IDE 0 interrupt done! -------\n"); + + _asm + { + pop ebp + iretd + } +} +void _declspec(naked) IDE_secondary_channel_interrupt_handler() +{ + __asm + { + push ebp + mov ebp, esp + } + + ++interrupts_fired; + + if (debugLevel) + terminal_writestring(" --------- IDE 1 interrupt fired! -------\n"); + + ide_irq_invoked = true; + + PIC_sendEOI(HARDWARE_INTERRUPTS_BASE + channels[1].irq); + + if (debugLevel) + terminal_writestring(" --------- IDE 1 interrupt done! -------\n"); + + _asm + { + pop ebp + iretd + } +} + +void IDE_Init(uint8_t bus, uint8_t slot, uint8_t function) +{ + IDE_bus = bus; + IDE_slot = slot; + IDE_function = function; + + kprintf(" Initializing IDE controller driver..."); + + // Get the operating mode from the programming interface. We only support compatibility mode right now. + // TODO: Support PCI native and/or try writing to progIF to see if device can be put into compatibility mode + uint8_t progIF = PCI_GetProgrammingInterface(bus, slot, function); + if ((progIF & PROG_IF_PRIMARY_CHANNEL_PCI_NATIVE) || (progIF & PROG_IF_SECONDARY_CHANNEL_PCI_NATIVE)) + { + kprintf("\n we don't yet support PCI-native IDE controllers; aborting."); + IDE_Present = false; + return; + } + + // get the I/O ports - this is how it would be done for PCI-native + /*uint32_t primaryChannelBase = PCI_GetBaseAddress0(bus, slot, function) & ~3; + uint32_t primaryChannelControl = PCI_GetBaseAddress1(bus, slot, function) & ~3; + uint32_t secondaryChannelBase = PCI_GetBaseAddress2(bus, slot, function) & ~3; + uint32_t secondaryChannelControl = PCI_GetBaseAddress3(bus, slot, function) & ~3;*/ + + // Use the compatibility-mode I/O addresses + channels[0].base = IDE_COMPAT_PRIMARY_COMMAND_IO; + channels[0].ctrl = IDE_COMPAT_PRIMARY_CONTROL_IO; + channels[1].base = IDE_COMPAT_SECONDARY_COMMAND_IO; + channels[1].ctrl = IDE_COMPAT_SECONDARY_CONTROL_IO; + + kprintf(" 0x%X 0x%X 0x%X 0x%X", channels[0].base, channels[0].ctrl, channels[1].base, channels[1].ctrl); + + // Compatibility mode means we use IRQ's 14 and 15 + channels[0].irq = 14; + channels[1].irq = 15; + kprintf(" - IRQs %d&%d\n", channels[0].irq, channels[1].irq); + + // Register the IRQ handlers + Set_IDT_Entry((unsigned long)IDE_primary_channel_interrupt_handler, + HARDWARE_INTERRUPTS_BASE + channels[0].irq); + Set_IDT_Entry((unsigned long)IDE_secondary_channel_interrupt_handler, + HARDWARE_INTERRUPTS_BASE + channels[1].irq); + + // Tell the PIC to enable the IRQ + IRQ_Enable_Line(channels[0].irq); + IRQ_Enable_Line(channels[1].irq); + + IDE_Present = true; + + channels[0].bmide = PCI_GetBaseAddress4(bus, slot, function) & ~3; // Bus Master IDE + channels[1].bmide = (PCI_GetBaseAddress4(bus, slot, function) & ~3) + 8; // Bus Master IDE + + // 2- Disable IRQs: TODO: Need to disable interrupts per-device + IDE_WriteRegister(ATA_PRIMARY_CHANNEL, ATA_REG_CONTROL, ATA_CONTROL_REG_DISABLE_INTERRUPTS); + IDE_WriteRegister(ATA_SECONDARY_CHANNEL, ATA_REG_CONTROL, ATA_CONTROL_REG_DISABLE_INTERRUPTS); + + // 3- Detect ATA-ATAPI Devices: + int driveNumber = 0; + for (uint8_t channel = 0; channel < 2; channel++) + { + for (uint8_t device = 0; device < 2; device++) + { + uint8_t err = 0, type = IDE_ATA, status; + ide_devices[driveNumber].Present = 0; // Assuming that no drive here. + + // (I) Select Drive: + IDE_WriteRegister(channel, ATA_REG_HDDEVSEL, 0xA0 | (device << 4)); // Select Drive. + TimeDelayMS(1); // Wait 1ms for drive select to work. + //return; + // (II) Send ATA Identify Command: + IDE_WriteRegister(channel, ATA_REG_COMMAND, ATA_CMD_IDENTIFY); + TimeDelayMS(1); + + // (III) Polling: + if (IDE_ReadRegister(channel, ATA_REG_STATUS) == 0) + continue; // If Status = 0, No Device. + + // TODO: Timeout + while (1) + { + status = IDE_ReadRegister(channel, ATA_REG_STATUS); + if ((status & ATA_SR_ERR)) + { + err = 1; break; + } // If Err, Device is not ATA. + if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRQ)) + break; // Everything is right. + } + + // (IV) Probe for ATAPI Devices: + if (err != 0) + { + unsigned char cl = IDE_ReadRegister(channel, ATA_REG_LBA1); + unsigned char ch = IDE_ReadRegister(channel, ATA_REG_LBA2); + + if (cl == 0x14 && ch == 0xEB) + type = IDE_ATAPI; + else if (cl == 0x69 && ch == 0x96) + type = IDE_ATAPI; + else + continue; // Unknown Type (may not be a device). + + IDE_WriteRegister(channel, ATA_REG_COMMAND, ATA_CMD_IDENTIFY_PACKET); + TimeDelayMS(1); + } + + // (V) Read Identification Space of the Device: + IDE_ReadBuffer(channel, ATA_REG_DATA, (uint32_t *)ide_buf, 128); + + // (VI) Read Device Parameters: + ide_devices[driveNumber].Present = 1; + ide_devices[driveNumber].Type = type; + ide_devices[driveNumber].Channel = channel; + ide_devices[driveNumber].Drive = device; + ide_devices[driveNumber].Signature = *((unsigned short *)(ide_buf + ATA_IDENT_DEVICETYPE)); + ide_devices[driveNumber].Capabilities = *((unsigned short *)(ide_buf + ATA_IDENT_CAPABILITIES)); + ide_devices[driveNumber].CommandSets = *((unsigned int *)(ide_buf + ATA_IDENT_COMMANDSETS)); + + // (VII) Get Size: + if (ide_devices[driveNumber].CommandSets & (1 << 26)) + // Device uses 48-Bit Addressing: + ide_devices[driveNumber].Size = *((unsigned int *)(ide_buf + ATA_IDENT_MAX_LBA_EXT)); + else + // Device uses CHS or 28-bit Addressing: + ide_devices[driveNumber].Size = *((unsigned int *)(ide_buf + ATA_IDENT_MAX_LBA)); + + // (VIII) String indicates model of device (like Western Digital HDD and SONY DVD-RW...): + // model string is stored with every two bytes swapped + for (int k = 0; k < IDE_MODEL_STRING_LENGTH; k += 2) + { + ide_devices[driveNumber].Model[k] = ide_buf[ATA_IDENT_MODEL + k + 1]; + ide_devices[driveNumber].Model[k + 1] = ide_buf[ATA_IDENT_MODEL + k]; + } + ide_devices[driveNumber].Model[IDE_MODEL_STRING_LENGTH] = 0; // Terminate String. + + driveNumber++; + } + } + + // 4- Print Summary: + for (int i = 0; i < 4; i++) + { + if (ide_devices[i].Present == 1) + { + kprintf(" Found %s Drive - %s\n", + ide_devices[i].Type ? "ATAPI" : "ATA", // type + //ide_devices[i].Size / 1024 / 1024 / 2, // size + ide_devices[i].Model); + } + } + + kprintf(" IDE controller driver initialized\n"); +} + +uint8_t IDE_PollUntilNotBSY(uint8_t channel, uint8_t advanced_check) +{ + + // (I) Delay 400 nanosecond for BSY to be set: + // ------------------------------------------------- + for (int i = 0; i < 4; i++) + IDE_ReadRegister(channel, ATA_REG_ALTSTATUS); // Reading the Alternate Status port wastes 100ns; loop four times. + + // (II) Wait for BSY to be cleared: + // TODO: add timeout + while (IDE_ReadRegister(channel, ATA_REG_STATUS) & ATA_SR_BSY) + ; // Wait for BSY to be zero. + + if (advanced_check) + { + uint8_t state = IDE_ReadRegister(channel, ATA_REG_STATUS); // Read Status Register. + + // (III) Check For Errors: + if (state & ATA_SR_ERR) + return 2; // Error. + + // (IV) Check If Device fault: + if (state & ATA_SR_DF) + return 1; // Device Fault. + + // (V) Check DRQ: + // BSY = 0; DF = 0; ERR = 0 so we should check for DRQ now. + if ((state & ATA_SR_DRQ) == 0) + return 3; // DRQ should be set + } + + return 0; // No Error. +} + +uint8_t IDE_ReadRegister(uint8_t channel, uint8_t reg) +{ + uint8_t result = 0; + + // If we're reading from register ATA_REG_SECCOUNT1 or ATA_REG_LBA3 - 5 (the second device on the channel) + if (reg >= ATA_REG_SECCOUNT1 && reg <= ATA_REG_LBA5) + IDE_WriteRegister(channel, ATA_REG_CONTROL, 0x80 | channels[channel].disableInterrupts); + + if (reg <= ATA_REG_COMMAND) + result = inb(channels[channel].base + reg - 0x00); + else if (reg <= ATA_REG_LBA5) + result = inb(channels[channel].base + reg - 0x06); + else if (reg <= ATA_REG_DEVADDRESS) + result = inb(channels[channel].ctrl + reg - 0x0A); + else if (reg < 0x16) + result = inb(channels[channel].bmide + reg - 0x0E); + + // If we're reading from register ATA_REG_SECCOUNT1 or ATA_REG_LBA3 - 5 (the second device on the channel) + if (reg >= ATA_REG_SECCOUNT1 && reg <= ATA_REG_LBA5) + IDE_WriteRegister(channel, ATA_REG_CONTROL, channels[channel].disableInterrupts); + + return result; +} + +// TODO: Adapted from OSDev.org, need to rewrite in my own style +void IDE_ReadBuffer(uint8_t channel, uint8_t reg, uint32_t *buffer, unsigned int quads) +{ + if (reg > 0x07 && reg < 0x0C) + IDE_WriteRegister(channel, ATA_REG_CONTROL, 0x80 | channels[channel].disableInterrupts); + + for (unsigned int i = 0; i < quads; ++i) + { + if (reg < 0x08) + buffer[i] = inl(channels[channel].base + reg - 0x00); + else if (reg < 0x0C) + buffer[i] = inl(channels[channel].base + reg - 0x06); + else if (reg < 0x0E) + buffer[i] = inl(channels[channel].ctrl + reg - 0x0A); + else if (reg < 0x16) + buffer[i] = inl(channels[channel].bmide + reg - 0x0E); + } + + if (reg > 0x07 && reg < 0x0C) + IDE_WriteRegister(channel, ATA_REG_CONTROL, channels[channel].disableInterrupts); +} + +void IDE_WaitForIRQ() +{ + while (!ide_irq_invoked) + ; + ide_irq_invoked = false; +} + +void IDE_WriteRegister(uint8_t channel, uint8_t reg, uint8_t data) +{ + // If we're writing to register ATA_REG_SECCOUNT1 or ATA_REG_LBA3 - 5 (the second device on the channel) + if (reg >= ATA_REG_SECCOUNT1 && reg <= ATA_REG_LBA5) + IDE_WriteRegister(channel, ATA_REG_CONTROL, 0x80 | channels[channel].disableInterrupts); + + if (reg <= ATA_REG_COMMAND) + outb(channels[channel].base + reg - 0x00, data); + else if (reg <= ATA_REG_LBA5) + outb(channels[channel].base + reg - 0x06, data); + else if (reg <= ATA_REG_DEVADDRESS) + outb(channels[channel].ctrl + reg - 0x0A, data); + else if (reg < 0x16) + outb(channels[channel].bmide + reg - 0x0E, data); + + // If we're writing to register ATA_REG_SECCOUNT1 or ATA_REG_LBA3 - 5 (the second device on the channel) + if (reg >= ATA_REG_SECCOUNT1 && reg <= ATA_REG_LBA5) + IDE_WriteRegister(channel, ATA_REG_CONTROL, channels[channel].disableInterrupts); +} \ No newline at end of file diff --git a/MyOS_1/Drivers/IDE.h b/MyOS_1/Drivers/IDE.h new file mode 100644 index 0000000..30bd53e --- /dev/null +++ b/MyOS_1/Drivers/IDE.h @@ -0,0 +1,143 @@ +#pragma once + +#include "PCI_Bus.h" + +// Programming interface bits (from the PCI IDE specification) +// (No idea what "modes" the spec is referring to - it's not a great spec) +#define PROG_IF_PRIMARY_CHANNEL_PCI_NATIVE 0x01 +#define PROG_IF_PRIMARY_CHANNEL_BOTH_MODES 0x02 +#define PROG_IF_SECONDARY_CHANNEL_PCI_NATIVE 0x04 +#define PROG_IF_SECONDARY_CHANNEL_BOTH_MODES 0x08 +#define PROG_IF_BUS_MASTER_CAPABLE 0x80 + +#define IDE_COMPAT_PRIMARY_COMMAND_IO 0x1F0 +#define IDE_COMPAT_PRIMARY_CONTROL_IO 0x3F6 +#define IDE_COMPAT_SECONDARY_COMMAND_IO 0x170 +#define IDE_COMPAT_SECONDARY_CONTROL_IO 0x376 + +// Some defines from OSdev wiki: + +// STATUS +#define ATA_SR_BSY 0x80 // Busy +#define ATA_SR_DRDY 0x40 // Drive ready +#define ATA_SR_DF 0x20 // Drive write fault +#define ATA_SR_DSC 0x10 // Drive seek complete +#define ATA_SR_DRQ 0x08 // Data request ready +#define ATA_SR_CORR 0x04 // Corrected data +#define ATA_SR_IDX 0x02 // Index +#define ATA_SR_ERR 0x01 // Error + +// ERRORS +#define ATA_ER_BBK 0x80 // Bad block +#define ATA_ER_UNC 0x40 // Uncorrectable data +#define ATA_ER_MC 0x20 // Media changed +#define ATA_ER_IDNF 0x10 // ID mark not found +#define ATA_ER_MCR 0x08 // Media change request +#define ATA_ER_ABRT 0x04 // Command aborted +#define ATA_ER_TK0NF 0x02 // Track 0 not found +#define ATA_ER_AMNF 0x01 // No address mark + +// COMMANDS +#define ATA_CMD_READ_PIO 0x20 +#define ATA_CMD_READ_PIO_EXT 0x24 +#define ATA_CMD_READ_DMA 0xC8 +#define ATA_CMD_READ_DMA_EXT 0x25 +#define ATA_CMD_WRITE_PIO 0x30 +#define ATA_CMD_WRITE_PIO_EXT 0x34 +#define ATA_CMD_WRITE_DMA 0xCA +#define ATA_CMD_WRITE_DMA_EXT 0x35 +#define ATA_CMD_CACHE_FLUSH 0xE7 +#define ATA_CMD_CACHE_FLUSH_EXT 0xEA +#define ATA_CMD_PACKET 0xA0 +#define ATA_CMD_IDENTIFY_PACKET 0xA1 +#define ATA_CMD_IDENTIFY 0xEC +// ATAPI COMMANDS +#define ATAPI_CMD_READ 0xA8 +#define ATAPI_CMD_EJECT 0x1B + +// NOT SURE +#define ATA_IDENT_DEVICETYPE 0 +#define ATA_IDENT_CYLINDERS 2 +#define ATA_IDENT_HEADS 6 +#define ATA_IDENT_SECTORS 12 +#define ATA_IDENT_SERIAL 20 +#define ATA_IDENT_MODEL 54 +#define ATA_IDENT_CAPABILITIES 98 +#define ATA_IDENT_FIELDVALID 106 +#define ATA_IDENT_MAX_LBA 120 +#define ATA_IDENT_COMMANDSETS 164 +#define ATA_IDENT_MAX_LBA_EXT 200 + +#define IDE_ATA 0x00 +#define IDE_ATAPI 0x01 + +#define ATA_PRIMARY_CHANNEL 0 +#define ATA_SECONDARY_CHANNEL 1 +#define ATA_CHANNEL_DEVICE0 0x00 +#define ATA_CHANNEL_DEVICE1 0x01 + +// ATA-ATAPI "Task-File": +#define ATA_REG_DATA 0x00 +#define ATA_REG_ERROR 0x01 +#define ATA_REG_FEATURES 0x01 +#define ATA_REG_SECCOUNT0 0x02 +#define ATA_REG_LBA0 0x03 +#define ATA_REG_LBA1 0x04 +#define ATA_REG_LBA2 0x05 +#define ATA_REG_HDDEVSEL 0x06 +#define ATA_REG_COMMAND 0x07 +#define ATA_REG_STATUS 0x07 +#define ATA_REG_SECCOUNT1 0x08 +#define ATA_REG_LBA3 0x09 +#define ATA_REG_LBA4 0x0A +#define ATA_REG_LBA5 0x0B +#define ATA_REG_CONTROL 0x0C +#define ATA_REG_ALTSTATUS 0x0C +#define ATA_REG_DEVADDRESS 0x0D + +// defines for control register +#define ATA_CONTROL_REG_DISABLE_INTERRUPTS 2 +#define ATA_CONTROL_REG_SOFTWARE_RESET 4 +// Other registers are reserved or 0 + +typedef struct IDE_CHANNEL_INFO +{ + uint16_t base; // I/O Base. + uint16_t ctrl; // Control Base + uint16_t bmide; // Bus Master IDE + uint8_t disableInterrupts; + uint8_t irq; +} IDE_CHANNEL_INFO; + +#define IDE_MODEL_STRING_LENGTH 40 /* not including null-terminator */ + +struct ide_device { + uint8_t Present; // 0 (Empty) or 1 (This Drive really exists). + uint8_t Channel; // 0 (Primary Channel) or 1 (Secondary Channel). + uint8_t Drive; // 0 (Master Drive) or 1 (Slave Drive). + uint16_t Type; // 0: ATA, 1:ATAPI. + uint16_t Signature; // Drive Signature + uint16_t Capabilities;// Features. + uint32_t CommandSets; // Command Sets Supported. + uint32_t Size; // Size in Sectors. + uint8_t Model[IDE_MODEL_STRING_LENGTH + 1]; // Model string +} ide_devices[4]; + + + +// TODO: Support multiple IDE controllers +extern uint8_t IDE_bus; +extern uint8_t IDE_slot; +extern uint8_t IDE_function; +extern bool IDE_Present; + + +void IDE_Init(uint8_t bus, uint8_t slot, uint8_t function); + +uint8_t IDE_PollUntilNotBSY(uint8_t channel, uint8_t advanced_check); + +uint8_t IDE_ReadRegister(uint8_t channel, uint8_t reg); + +void IDE_ReadBuffer(uint8_t channel, uint8_t reg, uint32_t *buffer, unsigned int quads); + +void IDE_WriteRegister(uint8_t channel, uint8_t reg, uint8_t data); diff --git a/MyOS_1/Drivers/Keyboard.c b/MyOS_1/Drivers/Keyboard.c index a81af96..5f726c1 100644 --- a/MyOS_1/Drivers/Keyboard.c +++ b/MyOS_1/Drivers/Keyboard.c @@ -7,10 +7,19 @@ #include "../printf.h" unsigned char normal_keys_map[256]; +bool keys_down[256] = { false }; + bool left_shift_held; bool right_shift_held; bool awaitingSpecial = false; +// Circular-buffer for input that has been queued +// Just a very naive implementation for letting applications read keyboard input +// TODO: Make less-hacky and don't special-case the shell +uint16_t scanCodeBuffer[KEYS_BUFFER_SIZE] = { 0 }; +int keyReadIndex = 0; +int keyWriteIndex = 0; + bool key_released(unsigned char scanCode) { if(scanCode >= 128) @@ -38,11 +47,23 @@ void _declspec(naked) keyboard_interrupt_handler(void) if (scan_code == 0xE0) awaitingSpecial = true; else + { + // Handle keyboard input for the shell keyboard_key_received(scan_code); + + // Add scan code to queue for other running applications + // TODO: Handle buffer full + scanCodeBuffer[(keyWriteIndex++) % KEYS_BUFFER_SIZE] = scan_code; + } } else { + // Handle input for the shell keyboard_special_key_received(scan_code); + + // Add scan code to the keyboard queue; Have the upper byte start with 0xE0 to mark the key as special + scanCodeBuffer[(keyWriteIndex++) % KEYS_BUFFER_SIZE] = 0xE000 + scan_code; + awaitingSpecial = false; } } @@ -239,4 +260,14 @@ void keyboard_special_key_received(unsigned char scanCode) default: break; } +} + +bool keyboard_read_from_queue(uint16_t *pScanCode) +{ + if (keyReadIndex == keyWriteIndex) + return false; + + *pScanCode = scanCodeBuffer[(keyReadIndex++) % KEYS_BUFFER_SIZE]; + + return true; } \ No newline at end of file diff --git a/MyOS_1/Drivers/Keyboard.h b/MyOS_1/Drivers/Keyboard.h index 6fc8f60..bf7f391 100644 --- a/MyOS_1/Drivers/Keyboard.h +++ b/MyOS_1/Drivers/Keyboard.h @@ -80,6 +80,12 @@ extern bool awaitingSpecial; extern unsigned char scan_code; +// Circular-buffer for input that has been queued +#define KEYS_BUFFER_SIZE 64 +extern uint16_t scanCodeBuffer[KEYS_BUFFER_SIZE]; +extern int keyReadIndex; +extern int keyWriteIndex; + unsigned char unmap_key(unsigned char scanCode); void init_key_map(); @@ -88,4 +94,6 @@ void keyboard_key_received(unsigned char scanCode); void keyboard_special_key_received(unsigned char scanCode); +bool keyboard_read_from_queue(uint16_t *pScanCode); + void keyboard_interrupt_handler(void); diff --git a/MyOS_1/Drivers/PCI_Bus.c b/MyOS_1/Drivers/PCI_Bus.c index 05d9f84..123dbf5 100644 --- a/MyOS_1/Drivers/PCI_Bus.c +++ b/MyOS_1/Drivers/PCI_Bus.c @@ -5,6 +5,7 @@ #include "RTL_8139.h" #include "Bochs_VGA.h" #include "e1000.h" +#include "IDE.h" void VirtIO_Net_Init(uint8_t bus, uint8_t slot, uint8_t function); void VGPU_Init(uint8_t bus, uint8_t slot, uint8_t function); @@ -509,7 +510,7 @@ void PCI_CheckFunction(uint8_t bus, uint8_t device, uint8_t function, uint16_t v terminal_newline(); // try to load a driver for the device - PCI_DelegateToDriver(bus, device, function, vendorID, deviceID); + PCI_DelegateToDriver(bus, device, function, vendorID, deviceID, baseClass, subClass); /*if ((baseClass == 0x06) && (subClass == 0x04)) { @@ -519,7 +520,7 @@ void PCI_CheckFunction(uint8_t bus, uint8_t device, uint8_t function, uint16_t v } // Inelegant hack -void PCI_DelegateToDriver(uint8_t bus, uint8_t slot, uint8_t function, uint16_t vendorID, uint16_t deviceID) +void PCI_DelegateToDriver(uint8_t bus, uint8_t slot, uint8_t function, uint16_t vendorID, uint16_t deviceID, uint8_t baseClass, uint8_t subClass) { if (vendorID == PCI_VENDOR_REALTEK) { @@ -531,15 +532,19 @@ void PCI_DelegateToDriver(uint8_t bus, uint8_t slot, uint8_t function, uint16_t if (vendorID == PCI_VENDOR_QEMU) { if (deviceID == PCI_DEVICE_BGA) + { BGA_Init(bus, slot, function); - return; + return; + } } if (vendorID == PCI_VENDOR_VBOX) { if (deviceID == PCI_DEVICE_VBOX_BGA) + { BGA_Init(bus, slot, function); - return; + return; + } } if (vendorID == PCI_VENDOR_RED_HAT) @@ -554,7 +559,15 @@ void PCI_DelegateToDriver(uint8_t bus, uint8_t slot, uint8_t function, uint16_t if (vendorID == PCI_VENDOR_INTEL) { if (deviceID == PCI_DEVICE_82540EM) + { e1000_Net_Init(bus, slot, function); + return; + } + } + + if (baseClass == PCI_BASE_CLASS_MASS_STORAGE && subClass == PCI_SUBCLASS_IDE_CONTROLLER) + { + IDE_Init(bus, slot, function); return; } } @@ -710,6 +723,12 @@ uint8_t PCI_GetInterruptLine(uint8_t bus, uint8_t slot, uint8_t function) return PCI_ConfigReadWord(bus, slot, function, INTERRUPT_LINE_OFFSET) & 0xFF; } +uint8_t PCI_GetProgrammingInterface(uint8_t bus, uint8_t slot, uint8_t function) +{ + // PROG_IF is upper byte of 16 bits after revision ID + return (uint8_t)(PCI_ConfigReadWord(bus, slot, function, VENDOR_ID_OFFFSET) >> 8); +} + uint16_t PCI_GetVendorID(uint8_t bus, uint8_t slot, uint8_t function) { return PCI_ConfigReadWord(bus, slot, function, VENDOR_ID_OFFFSET); diff --git a/MyOS_1/Drivers/PCI_Bus.h b/MyOS_1/Drivers/PCI_Bus.h index 0b90df4..b0d5af8 100644 --- a/MyOS_1/Drivers/PCI_Bus.h +++ b/MyOS_1/Drivers/PCI_Bus.h @@ -8,6 +8,7 @@ #define VENDOR_ID_OFFFSET 0 #define DEVICE_ID_OFFSET 0x02 #define COMMAND_OFFSET 0x04 +#define REVISION_OFFSET 0x08 #define CLASSES_OFFSET 0x0A #define HEADER_TYPE_OFFSET 0x0E #define BAR0_OFFSET 0x10 @@ -42,6 +43,9 @@ #define PCI_VENDOR_INTEL 0x8086 #define PCI_DEVICE_82540EM 0x100E +#define PCI_BASE_CLASS_MASS_STORAGE 0x01 +#define PCI_SUBCLASS_IDE_CONTROLLER 0x01 + void PCI_CheckAllBuses(void); void PCI_CheckDevice(uint8_t bus, uint8_t device); @@ -54,7 +58,7 @@ uint16_t PCI_ConfigReadWord(uint8_t bus, uint8_t slot, uint8_t func, uint8_t off void PCI_ConfigWriteWord(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint16_t data); -void PCI_DelegateToDriver(uint8_t bus, uint8_t slot, uint8_t function, uint16_t vendorID, uint16_t deviceID); +void PCI_DelegateToDriver(uint8_t bus, uint8_t slot, uint8_t function, uint16_t vendorID, uint16_t deviceID, uint8_t baseClass, uint8_t subClass); void PCI_EnableBusMastering(uint8_t bus, uint8_t slot, uint8_t function); @@ -81,6 +85,8 @@ uint8_t PCI_GetHeaderType(uint8_t bus, uint8_t slot, uint8_t function); uint8_t PCI_GetInterruptLine(uint8_t bus, uint8_t slot, uint8_t function); +uint8_t PCI_GetProgrammingInterface(uint8_t bus, uint8_t slot, uint8_t function); + char *PCI_GetSubclassName(uint8_t baseClass, uint8_t subClass); uint16_t PCI_GetVendorID(uint8_t bus, uint8_t slot, uint8_t function); diff --git a/MyOS_1/Drivers/PS2_Mouse.c b/MyOS_1/Drivers/PS2_Mouse.c index ed3b7c6..e6d2386 100644 --- a/MyOS_1/Drivers/PS2_Mouse.c +++ b/MyOS_1/Drivers/PS2_Mouse.c @@ -12,11 +12,7 @@ bool mousePresent = false; bool fourBytePackets = false; -int mouseX = 0; -int mouseY = 0; -bool leftButton = false; -bool middleButton = false; -bool rightButton = false; +MOUSE_STATE mouseState = { 0, 0, false, false, false }; // For restoring the GUI data underneath the cursor int oldMouseX = 0; @@ -90,9 +86,9 @@ void _declspec(naked) Mouse_InterruptHandler() if (fourBytePackets) packetByte4 = inb(PS2_DATA_PORT); - leftButton = (packetByte1 & MOUSE_LEFT_BUTTON); - middleButton = (packetByte1 & MOUSE_MIDDLE_BUTTON); - rightButton = (packetByte1 & MOUSE_RIGHT_BUTTON); + mouseState.leftButton = (packetByte1 & MOUSE_LEFT_BUTTON); + mouseState.middleButton = (packetByte1 & MOUSE_MIDDLE_BUTTON); + mouseState.rightButton = (packetByte1 & MOUSE_RIGHT_BUTTON); if (!(packetByte1 & MOUSE_ALWAYS_1)) terminal_writestring("Not 1\n"); @@ -107,22 +103,22 @@ void _declspec(naked) Mouse_InterruptHandler() if ((packetByte1 & MOUSE_X_SIGN) == MOUSE_X_SIGN) xDelta |= 0xFFFFFF00; - mouseX += xDelta; + mouseState.mouseX += xDelta; if ((packetByte1 & MOUSE_Y_SIGN) == MOUSE_Y_SIGN) yDelta |= 0xFFFFFF00; - mouseY += yDelta; + mouseState.mouseY -= yDelta; - if (mouseX < 0) - mouseX = 0; - if (mouseX >= MAX_X_RES) - mouseX = MAX_X_RES - 1; + if (mouseState.mouseX < 0) + mouseState.mouseX = 0; + if (mouseState.mouseX >= MAX_X_RES) + mouseState.mouseX = MAX_X_RES - 1; - if (mouseY < 0) - mouseY = 0; - if (mouseY >= MAX_Y_RES) - mouseY = MAX_Y_RES - 1; + if (mouseState.mouseY < 0) + mouseState.mouseY = 0; + if (mouseState.mouseY >= MAX_Y_RES) + mouseState.mouseY = MAX_Y_RES - 1; } else terminal_writestring("Overflow\n"); @@ -226,8 +222,8 @@ void Mouse_Init(void) if (!textMode) { - mouseX = MAX_X_RES / 2; - mouseY = MAX_Y_RES / 2; + mouseState.mouseX = MAX_X_RES / 2; + mouseState.mouseY = MAX_Y_RES / 2; oldColor.red = 0; oldColor.green = 0; oldColor.blue = 0; diff --git a/MyOS_1/Drivers/PS2_Mouse.h b/MyOS_1/Drivers/PS2_Mouse.h index 112b63e..a59502d 100644 --- a/MyOS_1/Drivers/PS2_Mouse.h +++ b/MyOS_1/Drivers/PS2_Mouse.h @@ -3,6 +3,8 @@ #include #include #include "../Graphics/Display_HAL.h" +#include "../misc.h" +#include "mouse.h" #define PS2_DATA_PORT 0x60 #define PS2_STATUS_PORT 0x64 @@ -44,14 +46,10 @@ #define MOUSE_X_OVERFLOW 0x40 #define MOUSE_Y_OVERFLOW 0x80 +extern MOUSE_STATE mouseState; extern bool mousePresent; extern bool fourBytePackets; -extern int mouseX; -extern int mouseY; -extern bool leftButton; -extern bool middleButton; -extern bool rightButton; extern int oldMouseX; extern int oldMouseY; diff --git a/MyOS_1/Drivers/Virtio_GPU.h b/MyOS_1/Drivers/Virtio_GPU.h index 270fb90..ccbb1ae 100644 --- a/MyOS_1/Drivers/Virtio_GPU.h +++ b/MyOS_1/Drivers/Virtio_GPU.h @@ -15,6 +15,7 @@ // Sadly, VIRTIO_GPU_F_VIRGL doesn't work on Windows (which sucks because that's the whole reason I started implementing a virtio-gpu driver) // Qemu seems to insist on using these features, whether we negotiate them or not: +#undef REQUIRED_FEATURES #define REQUIRED_FEATURES (VIRTIO_F_VERSION_1 | VIRTIO_F_RING_INDIRECT_DESC | VIRTIO_F_RING_EVENT_IDX) #define VIRTIO_GPU_EVENT_DISPLAY (1 << 0) diff --git a/MyOS_1/Drivers/Virtio_Net.c b/MyOS_1/Drivers/Virtio_Net.c index 58edd3f..9231c25 100644 --- a/MyOS_1/Drivers/Virtio_Net.c +++ b/MyOS_1/Drivers/Virtio_Net.c @@ -228,6 +228,7 @@ void VirtIO_Net_Init(uint8_t bus, uint8_t slot, uint8_t function) void _declspec(naked) VirtIO_Net_InterruptHandler() { + _disable(); _asm pushad; ++interrupts_fired; @@ -369,7 +370,7 @@ void VirtIO_Net_SetupReceiveBuffers() // Allocate and add 16 buffers to receive queue for (uint16_t i = 0; i < 16; ++i) { - uint8_t *buffer = dbg_alloc(bufferSize); + uint8_t *buffer = Paging_Get_Physical_Address(dbg_alloc(bufferSize)); // Add buffer to the descriptor table receiveQueue.descriptors[i].address = (uint64_t)buffer; @@ -426,7 +427,7 @@ void VirtIO_Net_SendPacket(Ethernet_Header *packet, uint16_t dataSize) uint16_t bufferSize = sizeof(virtio_net_hdr); // Allocate a buffer for the header - virtio_net_hdr *netBuffer = dbg_alloc(bufferSize); + virtio_net_hdr *netBuffer = Paging_Get_Physical_Address(dbg_alloc(bufferSize)); if (!netBuffer) { @@ -473,7 +474,7 @@ void VirtIO_Net_SendPacket(Ethernet_Header *packet, uint16_t dataSize) // (TODO: malloc returns identity-mapped addresses for now but later we'll need a function to convert virtual to physical) // fill descriptor with ethernet packet - transmitQueue.descriptors[descIndex2].address = (uint64_t)packetBuffer; + transmitQueue.descriptors[descIndex2].address = (uint64_t)Paging_Get_Physical_Address(packetBuffer); if (transmitQueue.descriptors[descIndex2].address == 0xdeadbeef || transmitQueue.descriptors[descIndex].address == 0xdeadbeefdeadbeef) kprintf("Very bad\n"); transmitQueue.descriptors[descIndex2].flags = 0; @@ -546,7 +547,7 @@ void VirtIO_Net_ReceivePacket() bufferSize += receiveQueue.descriptors[(descIndex + i) % receiveQueue.elements].length; } - rxBegin = dbg_alloc(bufferSize); + rxBegin = Paging_Get_Physical_Address(dbg_alloc(bufferSize)); if (!rxBegin) { kprintf("Not enough memory to allocate rxBegin\n"); diff --git a/MyOS_1/Drivers/Virtio_Net.h b/MyOS_1/Drivers/Virtio_Net.h index 985eb6f..93e1b58 100644 --- a/MyOS_1/Drivers/Virtio_Net.h +++ b/MyOS_1/Drivers/Virtio_Net.h @@ -38,6 +38,7 @@ #define VIRTIO_F_ANY_LAYOUT (1 << 27) // These are the features required by this driver (VirtualBox is borken and won't work without VIRTIO_NET_F_MRG_RXBUF) +#undef REQUIRED_FEATURES #define REQUIRED_FEATURES (/*VIRTIO_NET_F_CSUM |*/ VIRTIO_NET_F_MAC | VIRTIO_NET_F_MRG_RXBUF) diff --git a/MyOS_1/Drivers/mouse.h b/MyOS_1/Drivers/mouse.h new file mode 100644 index 0000000..0e011ac --- /dev/null +++ b/MyOS_1/Drivers/mouse.h @@ -0,0 +1,10 @@ +#pragma once + +typedef struct MOUSE_STATE +{ + int mouseX; + int mouseY; + bool leftButton; + bool middleButton; + bool rightButton; +} MOUSE_STATE; diff --git a/MyOS_1/Executables/PE32.c b/MyOS_1/Executables/PE32.c index cee4597..be6a8f8 100644 --- a/MyOS_1/Executables/PE32.c +++ b/MyOS_1/Executables/PE32.c @@ -4,13 +4,24 @@ #include "PE32.h" #include "../Terminal.h" #include "../printf.h" - +#include "../Tasks/Context.h" +#include "../paging.h" +#include "../../MyOS_GUI_Shell/GUI_Kernel_Shell.h" jmp_buf peReturnBuf; // returns true on success -bool loadAndRunPE(uint8_t *executableDestination, DOS_Header *mzAddress) +bool loadAndRunPE(uint8_t *executableDestination, DOS_Header *mzAddress, const char *imageName, bool exclusive) { + uint32_t espVal; + + if (debugLevel) + { + _asm mov[espVal], esp + kprintf("Initial esp 0x%lX\n", espVal); + terminal_dumpHexAround((uint8_t *)espVal, 16, 16); + } + // Ensure the file starts with a 'mz' signature if (mzAddress->signature != DOS_MAGIC) { @@ -71,8 +82,48 @@ bool loadAndRunPE(uint8_t *executableDestination, DOS_Header *mzAddress) } } + // Disable interrupts while we mess with page tables + _disable(); + + // Get a new page directory for the new task + PAGE_DIRECTORY_ENTRY *newPageDirectory; + uint32_t physicalLocation = (uint32_t)executableDestination; + + // Create a new page directory unless we're loading the GUI, because GUI.exe shares the kernel's page directory and uses a hardcoded address + if ((uint32_t)executableDestination != GUI_BASE_ADDRESS) + { + newPageDirectory = (PAGE_DIRECTORY_ENTRY *)nextPageDirectory; + nextPageDirectory += sizeof(PAGE_DIRECTORY_ENTRY) * 1024; + + // Copy the kernel's page table to this new page table + memcpy((void*)newPageDirectory, pageDir, sizeof(PAGE_DIRECTORY_ENTRY) * 1024); + + // Allocate a page of memory for the new application + unsigned int pagesAllocated; + KPageAllocator(1, &pagesAllocated, &physicalLocation); + if (!pagesAllocated) + { + kprintf("Unable to allocate memory for %s", imageName); + _enable(); + return false; + } + + //kprintf("Got a page of memory at 0x%X\n", physicalLocation); + + // Map the page of memory into the process' page directory + newPageDirectory[(uint32_t)executableDestination / FOUR_MEGABYTES] = physicalLocation + | DIRECTORY_ENTRY_PRESENT | DIRECTORY_ENTRY_WRITABLE | DIRECTORY_ENTRY_4MB | DIRECTORY_ENTRY_USER_ACCESSIBLE; + + //Paging_Print_Page_Table(newPageDirectory); + } + else + newPageDirectory = pageDir; + + // It's safe for interrupts to run again; we're done messing with the page tables + _enable(); + // TEMPTEMP - zero out 5 0x1000 sections of memory (tailored to TestApp1.exe) - memset(executableDestination, 0, 0x5000); + memset((void*)physicalLocation, 0, 0x5000); // Get the address of the first section IMAGE_SECTION_HEADER *sectionHeader = (IMAGE_SECTION_HEADER*)((uint32_t)directory + sizeof(IMAGE_DATA_DIRECTORY)); @@ -88,9 +139,9 @@ bool loadAndRunPE(uint8_t *executableDestination, DOS_Header *mzAddress) terminal_writestring(sectionHeader->mName); terminal_newline(); } - + // Determine the destination of the current section - uint8_t *sectionDest = (uint8_t*)((uint32_t)executableDestination + sectionHeader->mVirtualAddress); + uint8_t *sectionDest = (uint8_t*)((uint32_t)physicalLocation + sectionHeader->mVirtualAddress); if (debugLevel) { terminal_writestring("Virtual address of section: "); @@ -127,11 +178,14 @@ bool loadAndRunPE(uint8_t *executableDestination, DOS_Header *mzAddress) terminal_newline(); } - // This is where the exit() system call will return to. If setjmp() doesn't return 0, then the executable used exit(). - if(setjmp(peReturnBuf) == 0) + // Run it! + DispatchNewTask((uint32_t)entryPoint, newPageDirectory, 0x20000, imageName, exclusive); + + if (debugLevel) { - // run the program - (*entryPoint)(); + _asm mov[espVal], esp + kprintf("Final esp 0x%lX\n", espVal); + terminal_dumpHexAround(0, espVal, 16); } return true; diff --git a/MyOS_1/Executables/PE32.h b/MyOS_1/Executables/PE32.h index 93c0c16..2e00b1a 100644 --- a/MyOS_1/Executables/PE32.h +++ b/MyOS_1/Executables/PE32.h @@ -101,4 +101,4 @@ typedef struct IMAGE_SECTION_HEADER //extern uint8_t peBuffer[10 * 1024]; -bool loadAndRunPE(uint8_t *executableDestination, DOS_Header *mzAddress); \ No newline at end of file +bool loadAndRunPE(uint8_t *executableDestination, DOS_Header *mzAddress, const char *imageName, bool exclusive); \ No newline at end of file diff --git a/MyOS_1/GUI_Kernel.c b/MyOS_1/GUI_Kernel.c new file mode 100644 index 0000000..dec5ef9 --- /dev/null +++ b/MyOS_1/GUI_Kernel.c @@ -0,0 +1,46 @@ +#include +#include "GUI_Kernel.h" +#include "GUI_Messages.h" +#include "Tasks/Context.h" +#include "printf.h" +#include "misc.h" + +GUI_CALLBACK guiCallback = NULL; + +// Send a formatted text string to the console window for the currently running application +int GUI_printf(const char *format, va_list va) +{ + GUI_CONSOLE_PRINT_DATA param; + char outString[MAX_GUI_CONSOLE_STRING_LENGTH]; + + int returnValue = vsnprintf(outString, MAX_GUI_CONSOLE_STRING_LENGTH, format, va); + + param.textString = outString; + + (*guiCallback)(tasks[currentTask].PID, GUI_MSG_CONSOLE_PRINT, ¶m); + + return returnValue; +} + +void GUI_CallbackAdded() +{ + // Send a new window message to the GUI shell for each running application + for (int i = 0; i < MAX_TASKS; ++i) + { + if (!tasks[i].inUse) + continue; + + GUI_CreateConsoleWindowForApp(i); + } +} + +void GUI_CreateConsoleWindowForApp(uint32_t taskNumber) +{ + // Construct the message data + GUI_NEW_CONSOLE_APP_DATA data; + //data.appName = tasks[taskNumber].imageName; + memset(data.appName, 0, MAX_IMAGE_NAME_LENGTH); + strncpy(data.appName, tasks[taskNumber].imageName, MAX_IMAGE_NAME_LENGTH - 1); + + (*guiCallback)(tasks[taskNumber].PID, GUI_MSG_NEW_CONSOLE_APP, &data); +} diff --git a/MyOS_1/GUI_Kernel.h b/MyOS_1/GUI_Kernel.h new file mode 100644 index 0000000..8b75027 --- /dev/null +++ b/MyOS_1/GUI_Kernel.h @@ -0,0 +1,16 @@ +#pragma once +#include + +// definitions for interfacing between User apps <> kernel <> GUI shell + +typedef void(*GUI_CALLBACK)(uint32_t PID, uint32_t messageType, void *pData); + +extern GUI_CALLBACK guiCallback; + +// Called immediately after a callback has been registered, to transition running apps into windowed consoles +void GUI_CallbackAdded(); + +// Sends the formatted text string to the running GUI application +int GUI_printf(const char *format, va_list va); + +void GUI_CreateConsoleWindowForApp(uint32_t taskNumber); \ No newline at end of file diff --git a/MyOS_1/GUI_Messages.h b/MyOS_1/GUI_Messages.h new file mode 100644 index 0000000..bab171d --- /dev/null +++ b/MyOS_1/GUI_Messages.h @@ -0,0 +1,26 @@ +#pragma once +#include + +// MESSAGES +#define GUI_MSG_NEW_CONSOLE_APP 0x1000 +#define GUI_MSG_CONSOLE_PRINT 0x1001 +// END OF MESSAGES + +#define MAX_GUI_CONSOLE_STRING_LENGTH 512 +#define MAX_IMAGE_NAME_LENGTH 32 + +// DATA TYPES USED BY MESSAGES + +// Data type used by GUI_MSG_NEW_CONSOLE_APP messages +typedef struct GUI_NEW_CONSOLE_APP_DATA +{ + char appName[MAX_IMAGE_NAME_LENGTH]; + // TODO: We may as well send the terminal contents over in the same message +} GUI_NEW_CONSOLE_APP_DATA; + +// Data type used by GUI_MSG_CONSOLE_PRINT +typedef struct GUI_CONSOLE_PRINT_DATA +{ + const char *textString; +} GUI_CONSOLE_PRINT_DATA; +// END OF DATA TYPES \ No newline at end of file diff --git a/MyOS_1/Graphics/Display_HAL.c b/MyOS_1/Graphics/Display_HAL.c index 5363982..bc94d55 100644 --- a/MyOS_1/Graphics/Display_HAL.c +++ b/MyOS_1/Graphics/Display_HAL.c @@ -1,6 +1,5 @@ #include "Display_HAL.h" #include "../Drivers/Bochs_VGA.h" -#include "picofont.h" #include "../multiboot.h" #include "../misc.h" #include "Graphical_Terminal.h" @@ -9,9 +8,9 @@ bool graphicsPresent = false; bool textMode = true; uint32_t *linearFrameBuffer = NULL; -unsigned int graphicsBpp; -unsigned int graphicsWidth; -unsigned int graphicsHeight; +unsigned int graphicsBpp = 32; +unsigned int graphicsWidth = GRAPHICS_WIDTH; +unsigned int graphicsHeight = GRAPHICS_HEIGHT; // TODO: Create HAL interface and tie Bochs_VGA into it diff --git a/MyOS_1/Graphics/Graphical_Terminal.c b/MyOS_1/Graphics/Graphical_Terminal.c index 7690f58..93688c9 100644 --- a/MyOS_1/Graphics/Graphical_Terminal.c +++ b/MyOS_1/Graphics/Graphical_Terminal.c @@ -2,6 +2,7 @@ #include "../Terminal.h" #include "../misc.h" #include "../printf.h" +#include "picofont.h" #include "Bitmap.h" // TODO: Support multiple graphical terminals diff --git a/MyOS_1/Graphics/Graphical_Terminal.h b/MyOS_1/Graphics/Graphical_Terminal.h index 42805ec..1366864 100644 --- a/MyOS_1/Graphics/Graphical_Terminal.h +++ b/MyOS_1/Graphics/Graphical_Terminal.h @@ -1,6 +1,5 @@ #pragma once #include "Display_HAL.h" -#include "picofont.h" // TODO: Support higher resolutions #define MAX_X_RES 800 diff --git a/MyOS_1/Graphics/picofont.h b/MyOS_1/Graphics/picofont.h index f5e9622..175b800 100644 --- a/MyOS_1/Graphics/picofont.h +++ b/MyOS_1/Graphics/picofont.h @@ -20,8 +20,8 @@ #define FNT_ROWSPACING 3 // put some margins around the borders -#define FNT_LEFTRIGHTMARGIN 3 -#define FNT_TOPBOTTOMMARGIN 3 +#define FNT_LEFTRIGHTMARGIN 3 +#define FNT_TOPBOTTOMMARGIN 3 typedef struct { diff --git a/MyOS_1/Interrupts/IDT.c b/MyOS_1/Interrupts/IDT.c index 63dd611..5f7d084 100644 --- a/MyOS_1/Interrupts/IDT.c +++ b/MyOS_1/Interrupts/IDT.c @@ -82,6 +82,27 @@ void IDT_Init(void) // Set handler for getting uptime in ms Set_IDT_Entry((unsigned long)time_get_uptime_ms_handler, SYSCALL_TIME_UPTIME_MS); + // Set handler for reading from keyboard + Set_IDT_Entry((unsigned long)read_from_keyboard_handler, SYSCALL_READ_FROM_KEYBOARD); + + // Set handler for dispatching a new task + Set_IDT_Entry((unsigned long)dispatch_new_task_interrupt_handler, SYSCALL_DISPATCH_NEW_TASK); + + // Set handler for getting mouse state + Set_IDT_Entry((unsigned long)get_mouse_state_interrupt_handler, SYSCALL_GET_MOUSE_STATE); + + // Set handler for hiding shell display elements + Set_IDT_Entry((unsigned long)hide_shell_display_interrupt_handler, SYSCALL_HIDE_SHELL_DISPLAY); + + // Set handler for the GUI telling the kernel how to send the GUI messages + Set_IDT_Entry((unsigned long)gui_register_callback_interrupt_handler, SYSCALL_REGISTER_GUI_CALLBACK); + + // Set handler for launching an app + Set_IDT_Entry((unsigned long)launch_app_interrupt_handler, SYSCALL_LAUNCH_APP); + + // Set handler for closing an app + Set_IDT_Entry((unsigned long)close_app_interrupt_handler, SYSCALL_CLOSE_APP); + /* fill the IDT descriptor */ IDT_ptr.base = (uint32_t)IDT; IDT_ptr.size = (sizeof(IDT_ENTRY) * 256); diff --git a/MyOS_1/Interrupts/Interrupts.c b/MyOS_1/Interrupts/Interrupts.c index 0072bbe..2a49973 100644 --- a/MyOS_1/Interrupts/Interrupts.c +++ b/MyOS_1/Interrupts/Interrupts.c @@ -12,6 +12,10 @@ #include "../Timers/System_Clock.h" #include "../Graphics/Display_HAL.h" #include "../myos_io.h" +#include "../Tasks/Context.h" +#include "../Drivers/PS2_Mouse.h" +#include "../GUI_Kernel.h" +#include "../Debugging/Debug.h" unsigned long interrupts_fired; @@ -93,6 +97,33 @@ void _declspec(naked) irq9_shared_interrupt_handler(void) } } +void _declspec(naked) close_app_interrupt_handler(int eflags, int cs, uint32_t PID) +{ + (void)eflags, (void)cs; + + __asm + { + // prologue + push ebp + mov ebp, esp + + // disable interrupts + cli + } + + ++interrupts_fired; + + CloseApp(PID); + + __asm + { + // epilogue + pop ebp + + iretd + } +} + void _declspec(naked) default_exception_handler(void) { //_asm pushad; @@ -113,12 +144,74 @@ void _declspec(naked) default_exception_handler(void) }*/ } +uint32_t espVal; +uint32_t *pReturnVal; +TASK_STACK_LAYOUT *pNewTask; + +// In calling this interrupt handler, we can keep track of how much the stack grows starting at oldStackStart and +// ending at espVal (remembering that the stack grows downward, so espVal < oldStackStart). Then we can copy those +// bytes to the new stack, and when we swap in the new stack in our PIT interrupt handler, it will have the same +// data already pushed onto it, ready to be popped off at the end of the interrupt handler. +uint32_t _declspec(naked) dispatch_new_task_interrupt_handler(uint32_t eflags, uint32_t cs, uint32_t newStackBegin, uint32_t oldStackStart) +{ + (void)eflags, (void)cs; + __asm + { + // prologue + push ebp + mov ebp, esp + + pushad + + // Keep track of where the stack starts (ends) for the new task + mov[espVal], esp + } + + pNewTask = (TASK_STACK_LAYOUT *)espVal; + + if (debugLevel) + { + terminal_writestring("eflags: "); + terminal_print_ulong_hex(pNewTask->eflags); + terminal_writestring("\ncs: "); + terminal_print_ulong_hex(pNewTask->cs); + pReturnVal = (uint32_t *)(pNewTask->returnAddress); + terminal_writestring("\nReturn value: "); + terminal_print_ulong_hex((uint32_t)pReturnVal); + terminal_newline(); + terminal_writestring("old Stack Start: "); + terminal_print_ulong_hex(oldStackStart); + terminal_writestring("\nnew Stack: "); + terminal_print_ulong_hex(newStackBegin); + terminal_newline(); + terminal_writestring("\nnew esp: "); + terminal_print_ulong_hex(espVal); + terminal_newline(); + terminal_dumpHexAround((uint8_t *)espVal, 32, 192); + } + + // copy the task stack to the new stack area + memmove((void *)(newStackBegin - sizeof(TASK_STACK_LAYOUT)), pNewTask, sizeof(TASK_STACK_LAYOUT)); + + __asm + { + popad + + // epilogue + mov esp, ebp + pop ebp + + iretd + } +} + void _declspec(naked) exit_interrupt_handler(int eflags, int cs) { // supress warning about unused parameters (void)eflags, (void)cs; - longjmp(peReturnBuf, 42); + //longjmp(peReturnBuf, 42); // Not only do I not like this way of exitting, it doesn't work right now + ExitApp(); // No need for iretd because we'll never return here } @@ -306,6 +399,30 @@ void _declspec(naked) get_graphics_interrupt_handler(int eflags, int cs, bool *g } } +void _declspec(naked) get_mouse_state_interrupt_handler(int eflags, int cs, MOUSE_STATE *pMouseState) +{ + // supress warning about unused parameters + (void)eflags, (void)cs; + _asm + { + push ebp + mov ebp, esp + + pushad + } + + *pMouseState = mouseState; + + //kprintf("getMouseState\n"); + + _asm + { + popad + pop ebp + iretd + } +} + void _declspec(naked) gpf_exception_handler(void) { //_asm pushad; @@ -370,6 +487,86 @@ void _declspec(naked) graphics_blit_interrupt_handler(int eflags, int cs, const } } +void _declspec(naked) gui_register_callback_interrupt_handler(int eflags, int cs, GUI_CALLBACK callbackFunc) +{ + // supress warning about unused parameters + (void)eflags, (void)cs, (void)callbackFunc; + + _asm + { + // prologue + push ebp + mov ebp, esp + pushad + } + + ++interrupts_fired; + + if (debugLevel) + terminal_writestring("GUI register callback interrupt handler fired.\n"); + + // TODO IMPORTANT The GUI application should be mapped to kernel space + + guiCallback = callbackFunc; + + GUI_CallbackAdded(); + + _asm + { + popad + // epilogue + pop ebp + + iretd + } +} + +void _declspec(naked) hide_shell_display_interrupt_handler(int eflags, int cs) +{ + // supress warning about unused parameters + (void)eflags, (void)cs; + _asm + { + push ebp + mov ebp, esp + } + + showOverlay = false; + cursorEnabled = false; + + _asm + { + pop ebp + iretd + } +} + +void _declspec(naked) launch_app_interrupt_handler(int eflags, int cs, const char *appFilename, bool exclusive, bool *pRetVal) +{ + // supress warning about unused parameters + (void)eflags, (void)cs; + + // prologue + _asm + { + push ebp + mov ebp, esp + + //pushad + } + + *pRetVal = LaunchApp(appFilename, exclusive, 0x800000); + + // epilogue + _asm + { + //popad + + pop ebp + iretd + } +} + void _declspec(naked) page_allocator_interrupt_handler(int eflags, int cs, unsigned int pages, unsigned int *pPagesAllocated, uint32_t *pRetVal) { // supress warning about unused parameters @@ -416,13 +613,33 @@ void _declspec(naked) page_fault_handler(void) terminal_fill(' ', VGA_COLOR_WHITE, VGA_COLOR_BLUE); - terminal_writestring("Page Fault handler fired.\nError code "); + terminal_writestring("Page Fault handler fired by "); + terminal_writestring(tasks[currentTask].imageName); + terminal_writestring(".\nError code "); terminal_print_ulong_hex(errorCode); terminal_writestring("\nOffending instruction at "); terminal_print_ulong_hex(address); terminal_writestring(".\nMemory looks like:\n"); //terminal_dumpHex((uint8_t *)address, 256); terminal_dumpHexAround((uint8_t *)address, 128, 128); + + uint32_t regvar; + __asm + { + mov regvar, esp + } + kprintf("Value of esp: 0x%lX\n", regvar); + + __asm + { + mov regvar, ebp + } + kprintf("Value of ebp: 0x%lX\n", regvar); + + kprintf("Memory address accessed: 0x%lX\n", __readcr2()); + + DebugStackTrace(10); + terminal_writestring("System halted.\n"); for (;;) @@ -448,10 +665,13 @@ void _declspec(naked) invalid_opcode_handler(void) { pop [address] } - + terminal_fill(' ', VGA_COLOR_WHITE, VGA_COLOR_BLUE); terminal_writestring("Invalid opcode handler fired.\nEncountered invalid opcode at "); terminal_print_ulong_hex(address); + + DebugStackTrace(10); + terminal_writestring(".\nMemory looks like:\n"); terminal_dumpHexAround((uint8_t *)address, 128, 128); terminal_writestring("System halted.\n"); @@ -594,7 +814,10 @@ void _declspec(naked) printf_interrupt_handler(int eflags, int cs, const char *f terminal_writestring("printf interrupt handler fired.\n"); // Here's where printf actually happens - vprintf_(fmt, va); + if (guiCallback) + GUI_printf(fmt, va); + else + vprintf_(fmt, va); _asm { @@ -610,6 +833,28 @@ void _declspec(naked) printf_interrupt_handler(int eflags, int cs, const char *f } } +void _declspec(naked) read_from_keyboard_handler(int eflags, int cs, uint16_t *pScanCode, bool *pRetVal) +{ + (void)eflags, (void)cs; + + __asm + { + // prologue + push ebp + mov ebp, esp + } + + *pRetVal = keyboard_read_from_queue(pScanCode) & 0xff; + + __asm + { + // epilogue + pop ebp + + iretd + } +} + void _declspec(naked) time_delay_ms_interrupt_handler(int eflags, int cs, uint32_t milliSeconds) { (void)eflags, (void)cs; diff --git a/MyOS_1/Interrupts/Interrupts.h b/MyOS_1/Interrupts/Interrupts.h index 92258eb..174a9de 100644 --- a/MyOS_1/Interrupts/Interrupts.h +++ b/MyOS_1/Interrupts/Interrupts.h @@ -6,17 +6,23 @@ #include "../Libs/SDL/include/SDL_rect.h" #include "../Graphics/Display_HAL.h" #include "../myos_io.h" +#include "../Drivers/mouse.h" +#include "../GUI_Kernel.h" #define HARDWARE_INTERRUPTS_BASE 0x20 extern unsigned long interrupts_fired; +void close_app_interrupt_handler(int eflags, int cs, uint32_t PID); + void default_exception_handler(void); void exit_interrupt_handler(int eflags, int cs); void default_interrupt_handler(void); +uint32_t dispatch_new_task_interrupt_handler(uint32_t eflags, uint32_t cs, uint32_t newStack, uint32_t oldStackStart); + void fclose_interrupt_handler(int eflags, int cs, int fp, int *pRetVal); void fopen_interrupt_handler(int eflags, int cs, const char *filename, const char *mode, int *fp); @@ -29,16 +35,24 @@ void ftell_interrupt_handler(int eflags, int cs, FILE *stream, long int *pRetVal void get_graphics_interrupt_handler(int eflags, int cs, bool *graphicsInitialized, int *width, int *height); +void get_mouse_state_interrupt_handler(int eflags, int cs, MOUSE_STATE *pMouseState); + void gpf_exception_handler(void); void graphics_blit_interrupt_handler(int eflags, int cs, const SDL_Rect *sourceRect, PIXEL_32BIT *image); +void gui_register_callback_interrupt_handler(int eflags, int cs, GUI_CALLBACK callbackFunc); + +void hide_shell_display_interrupt_handler(int eflags, int cs); + void Interrupts_Add_Shared_Handler(bool (*sharedHandlerAddress)(void), uint8_t irq); void Interrupts_Init(); void keyboard_interrupt_handler(void); +void launch_app_interrupt_handler(int eflags, int cs, const char *appFilename, bool exclusive, bool *pRetVal); + void page_allocator_interrupt_handler(int eflags, int cs, unsigned int pages, unsigned int *pPagesAllocated, uint32_t *pRetVal); void page_fault_handler(void); @@ -49,6 +63,8 @@ void print_string_interrupt_handler(int eflags, int cs, char *str); void printf_interrupt_handler(int eflags, int cs, const char *fmt, va_list va); +void read_from_keyboard_handler(int eflags, int cs, uint16_t *pScanCode, bool *pRetVal); + void time_delay_ms_interrupt_handler(int eflags, int cs, uint32_t milliSeconds); void time_get_uptime_ms_handler(int eflags, int cs, uint32_t *pRetVal); \ No newline at end of file diff --git a/MyOS_1/Interrupts/System_Calls.c b/MyOS_1/Interrupts/System_Calls.c index 4f0b28b..e561e4d 100644 --- a/MyOS_1/Interrupts/System_Calls.c +++ b/MyOS_1/Interrupts/System_Calls.c @@ -6,10 +6,26 @@ #include #include "../myos_io.h" #include +#include "../Drivers/Keyboard.h" -void SystemCallExit() +void SystemCallCloseApp(uint32_t PID) { + const int pointerSize = sizeof(uint32_t); + + __asm + { + push[PID] // push arguments onto stack + int SYSCALL_CLOSE_APP // call close_app_interrupt_handler(PID) + add esp, pointerSize // restore value of stack pointer + } +} + +void SystemCallExit(int returnCode) +{ + // returnCode is ignored for now + (void)returnCode; + //printf("exit called\n"); __asm @@ -75,6 +91,18 @@ size_t SystemCallFRead(void * bufPtr, size_t elemSize, size_t count, FILE * stre return retVal; } +void SystemCallRegisterGuiCallback(GUI_CALLBACK guiCallback) +{ + const int pointerSize = sizeof(GUI_CALLBACK); + + __asm + { + push [guiCallback] // push argument onto stack + int SYSCALL_REGISTER_GUI_CALLBACK // call gui_register_callback_interrupt_handler(guiCallback) + add esp, pointerSize // restore value of stack pointer + } +} + int SystemCallFSeek(FILE * stream, long int off, int origin) { int retVal; @@ -111,6 +139,25 @@ long int SystemCallFTell(FILE * stream) return retVal; } +bool SystemCallLaunchApp(const char * appFileName, bool exclusive) +{ + bool retVal; + bool *pRetVal = &retVal; + int exclusiveInt = exclusive; + const int pointerSize = sizeof(const char *) + sizeof(int) + sizeof(bool *); + + __asm + { + push[pRetVal] // push arguments onto stack + push[exclusiveInt] + push[appFileName] + int SYSCALL_LAUNCH_APP // call launch_app_interrupt_handler(appFilename, exclusiveInt, pRetVal) + add esp, pointerSize // restore value of stack pointer + } + + return retVal; +} + // Get graphics info void SystemCallGetGraphicsInfo(bool *graphicsMode, int *width, int *height) { @@ -139,6 +186,30 @@ void SystemCallGraphicsBlit(const SDL_Rect *sourceRect, PIXEL_32BIT *image) } } +// Get mouse state +MOUSE_STATE SystemCallGetMouseState() +{ + const int pointerSize = sizeof(MOUSE_STATE *); + + MOUSE_STATE retVal; + MOUSE_STATE *pRetVal = &retVal; + + __asm + { + push [pRetVal] // push argument onto stack + int SYSCALL_GET_MOUSE_STATE // call get_mouse_state_interrupt_handler(MOUSE_STATE *pMouseState) + add esp, pointerSize // restore value of stack pointer + } + + return retVal; +} + +// Hide shell elements +void SystemCallHideShellDisplay() +{ + __asm int SYSCALL_HIDE_SHELL_DISPLAY // call hide_shell_display_interrupt_handler() +} + // Allocate memory pages void SystemCallPageAllocator(unsigned int pages, unsigned int *pPagesAllocated, uint32_t *pReturnVal) { @@ -150,7 +221,7 @@ void SystemCallPageAllocator(unsigned int pages, unsigned int *pPagesAllocated, push pReturnVal push pPagesAllocated push pages - int SYSCALL_PAGE_ALLOCATOR // call PageAllocator(pagesToAllocate, pPagesAllocated, pReturnVal); + int SYSCALL_PAGE_ALLOCATOR // call page_allocator_interrupt_handler(pagesToAllocate, pPagesAllocated, pReturnVal); add esp, pointerSize // restore value of stack pointer } } @@ -168,7 +239,7 @@ void SystemCallPrint(char *msg) } // TODO: return the number of characters printed -int __cdecl SystemCallPrintf(const char* format, ...) +int SystemCallPrintf(const char* format, ...) { va_list va; va_start(va, format); @@ -219,9 +290,29 @@ uint32_t SystemCallTimeGetUptimeMS() __asm { push[pUptimeMS] // push uptimeMS argument onto the stack - int SYSCALL_TIME_UPTIME_MS // call time_get_uptime_ms() + int SYSCALL_TIME_UPTIME_MS // call time_get_uptime_ms_handler() add esp, pointerSize // restore stack pointer } return uptimeMS; +} + +// TODO: Evaluate for hacky-ness. Thrown together without much thought. +bool SystemCallReadFromKeyboard(uint16_t *key) +{ + const int pointerSize = sizeof(uint16_t *); + + bool returnVal; + bool *pReturnVal = &returnVal; + + // Do read keyboard system call + __asm + { + push[pReturnVal]; // push pReturnVal argument onto the stack + push[key] // push key address argument onto the stack + int SYSCALL_READ_FROM_KEYBOARD // call read_from_keyboard_handler(key, pReturnVal) + add esp, pointerSize // restore stack pointer + } + + return returnVal; } \ No newline at end of file diff --git a/MyOS_1/Interrupts/System_Calls.h b/MyOS_1/Interrupts/System_Calls.h index 301d414..7920bce 100644 --- a/MyOS_1/Interrupts/System_Calls.h +++ b/MyOS_1/Interrupts/System_Calls.h @@ -1,10 +1,16 @@ #pragma once +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + #include #include #include "../Graphics/Display_HAL.h" #include "../Libs/SDL/include/SDL_rect.h" #include "../myos_io.h" +#include "../Drivers/mouse.h" +#include "../GUI_Kernel.h" #define SYSCALL_PRINT 255 #define SYSCALL_PRINTF 254 @@ -19,8 +25,18 @@ #define SYSCALL_FTELL 245 #define SYSCALL_EXIT_APP 244 #define SYSCALL_TIME_UPTIME_MS 243 +#define SYSCALL_READ_FROM_KEYBOARD 242 +#define SYSCALL_DISPATCH_NEW_TASK 241 +#define SYSCALL_GET_MOUSE_STATE 240 +#define SYSCALL_HIDE_SHELL_DISPLAY 239 +#define SYSCALL_REGISTER_GUI_CALLBACK 238 +#define SYSCALL_LAUNCH_APP 237 +#define SYSCALL_CLOSE_APP 236 + +void SystemCallCloseApp(uint32_t PID); +#define closeApp SystemCallCloseApp -void SystemCallExit(); +void SystemCallExit(int returnCode); #define exit SystemCallExit int SystemCallFClose(FILE *fp); @@ -38,17 +54,32 @@ int SystemCallFSeek(FILE * stream, long int offset, int origin); long int SystemCallFTell(FILE * stream); #define ftell SystemCallFTell +bool SystemCallLaunchApp(const char *appFileName, bool exclusive); +#define launchApp SystemCallLaunchApp + void SystemCallPageAllocator(unsigned int pages, unsigned int *pPagesAllocated, uint32_t *pRreturnVal); #define pageAllocator SystemCallPageAllocator void SystemCallGetGraphicsInfo(bool *graphicsArePresent, int *width, int *height); #define getGraphicsInfo SystemCallGetGraphicsInfo +MOUSE_STATE SystemCallGetMouseState(); +#define getMouseState SystemCallGetMouseState + void SystemCallGraphicsBlit(const SDL_Rect *sourceRect, PIXEL_32BIT *image); #define graphicsBlit SystemCallGraphicsBlit +void SystemCallHideShellDisplay(); +#define hideShellDisplay SystemCallHideShellDisplay + void SystemCallPrint(char *str); +bool SystemCallReadFromKeyboard(uint16_t *key); +#define readFromKeyboard SystemCallReadFromKeyboard + +void SystemCallRegisterGuiCallback(GUI_CALLBACK guiCallback); +#define registerGuiCallback SystemCallRegisterGuiCallback + #define printf SystemCallPrintf int __cdecl SystemCallPrintf(const char* format, ...); @@ -56,4 +87,9 @@ void SystemCallTimeDelayMS(uint32_t milliSeconds); #define timeDelayMS SystemCallTimeDelayMS uint32_t SystemCallTimeGetUptimeMS(); -#define timeGetUptimeMS SystemCallTimeGetUptimeMS \ No newline at end of file +#define timeGetUptimeMS SystemCallTimeGetUptimeMS + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ \ No newline at end of file diff --git a/MyOS_1/Libs/SDL/include/SDL_cpuinfo.h b/MyOS_1/Libs/SDL/include/SDL_cpuinfo.h index 07ac196..979a4c9 100644 --- a/MyOS_1/Libs/SDL/include/SDL_cpuinfo.h +++ b/MyOS_1/Libs/SDL/include/SDL_cpuinfo.h @@ -32,7 +32,7 @@ /* Need to do this here because intrin.h has C++ code in it */ /* Visual Studio 2005 has a bug where intrin.h conflicts with winnt.h */ -#if defined(_MSC_VER) && (_MSC_VER >= 1500) && (defined(_M_IX86) || defined(_M_X64)) +#if defined(_MSC_VER) && (_MSC_VER >= 1500) && (defined(_M_IX86) || defined(_M_X64) && !defined(__MYOS)) #ifdef __clang__ /* Many of the intrinsics SDL uses are not implemented by clang with Visual Studio */ #undef __MMX__ diff --git a/MyOS_1/Libs/SDL/src/stdlib/SDL_malloc.c b/MyOS_1/Libs/SDL/src/stdlib/SDL_malloc.c index 4ba41f3..704e8a2 100644 --- a/MyOS_1/Libs/SDL/src/stdlib/SDL_malloc.c +++ b/MyOS_1/Libs/SDL/src/stdlib/SDL_malloc.c @@ -5435,6 +5435,9 @@ void SDL_free(void *ptr) return; } +#ifdef DEBUG_MEM + printf("Freeing %p\n", ptr); +#endif s_mem.free_func(ptr); (void)SDL_AtomicDecRef(&s_mem.num_allocations); } diff --git a/MyOS_1/Libs/SDL/src/video/myos/SDL_myosevents.c b/MyOS_1/Libs/SDL/src/video/myos/SDL_myosevents.c new file mode 100644 index 0000000..d97425d --- /dev/null +++ b/MyOS_1/Libs/SDL/src/video/myos/SDL_myosevents.c @@ -0,0 +1,98 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2019 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" +#include "SDL_myoskeyboard.h" + +#if SDL_VIDEO_DRIVER_MYOS + +/* Event driver for MyOS */ + +#include "../../events/SDL_events_c.h" +#include "../../../Interrupts/System_Calls.h" +#include "../../../Drivers/mouse.h" + +#include "SDL_myosvideo.h" +#include "SDL_myosevents_c.h" + +MOUSE_STATE oldMouseState = { 0, 0, false, false, false }; + +void +MYOS_PumpEvents(_THIS) +{ + // Check for keyboard events + uint16_t sc = 0; + unsigned char scancode; + + while (readFromKeyboard(&sc)) + { + scancode = sc & 0xff; + + unsigned char keyRelease = (0x80 & scancode); + + scancode = (0x7F & scancode); + + if (keyRelease) + SDL_SendKeyboardKey(SDL_RELEASED, MyOS_Keycodes[scancode]); + else + SDL_SendKeyboardKey(SDL_PRESSED, MyOS_Keycodes[scancode]); + } + + // Check for mouse motion + MOUSE_STATE mouseState = getMouseState(); + if (mouseState.mouseX != oldMouseState.mouseX + || mouseState.mouseY != oldMouseState.mouseY) + { + // send mouse motion + SDL_SendMouseMotion(NULL, 0, SDL_FALSE, mouseState.mouseX, mouseState.mouseY); + } + + // Check for mouse buttons changing + // left mouse button + if (mouseState.leftButton != oldMouseState.leftButton) + { + if (mouseState.leftButton) + SDL_SendMouseButton(NULL, 0, SDL_PRESSED, SDL_BUTTON_LEFT); + else + SDL_SendMouseButton(NULL, 0, SDL_RELEASED, SDL_BUTTON_LEFT); + } + // middle mouse button + if (mouseState.middleButton != oldMouseState.middleButton) + { + if (mouseState.middleButton) + SDL_SendMouseButton(NULL, 0, SDL_PRESSED, SDL_BUTTON_MIDDLE); + else + SDL_SendMouseButton(NULL, 0, SDL_RELEASED, SDL_BUTTON_MIDDLE); + } + // right mouse button + if (mouseState.rightButton != oldMouseState.rightButton) + { + if (mouseState.rightButton) + SDL_SendMouseButton(NULL, 0, SDL_PRESSED, SDL_BUTTON_RIGHT); + else + SDL_SendMouseButton(NULL, 0, SDL_RELEASED, SDL_BUTTON_RIGHT); + } + + oldMouseState = mouseState; +} + +#endif /* SDL_VIDEO_DRIVER_MYOS */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/MyOS_1/Libs/SDL/src/video/myos/SDL_myosevents_c.h b/MyOS_1/Libs/SDL/src/video/myos/SDL_myosevents_c.h new file mode 100644 index 0000000..a1fad3d --- /dev/null +++ b/MyOS_1/Libs/SDL/src/video/myos/SDL_myosevents_c.h @@ -0,0 +1,33 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2019 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_myosevents_c_h_ +#define SDL_myosevents_c_h_ + +#include "../../SDL_internal.h" + +#include "SDL_myosvideo.h" + +extern void MYOS_PumpEvents(_THIS); + +#endif /* SDL_myosevents_c_h_ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/MyOS_1/Libs/SDL/src/video/myos/SDL_myoskeyboard.c b/MyOS_1/Libs/SDL/src/video/myos/SDL_myoskeyboard.c new file mode 100644 index 0000000..ba36865 --- /dev/null +++ b/MyOS_1/Libs/SDL/src/video/myos/SDL_myoskeyboard.c @@ -0,0 +1,66 @@ + +#include "../../SDL_internal.h" +#include "SDL_MyOSkeyboard.h" +#include "../../../Drivers/Keyboard.h" + +SDL_Scancode MyOS_Keycodes[SDL_NUM_SCANCODES] = { SDL_SCANCODE_UNKNOWN }; + +void MyOS_InitKeyboard(void) +{ + MyOS_Keycodes[A_PRESSED] = SDL_SCANCODE_A; + MyOS_Keycodes[B_PRESSED] = SDL_SCANCODE_B; + MyOS_Keycodes[C_PRESSED] = SDL_SCANCODE_C; + MyOS_Keycodes[D_PRESSED] = SDL_SCANCODE_D; + MyOS_Keycodes[E_PRESSED] = SDL_SCANCODE_E; + MyOS_Keycodes[F_PRESSED] = SDL_SCANCODE_F; + MyOS_Keycodes[G_PRESSED] = SDL_SCANCODE_G; + MyOS_Keycodes[H_PRESSED] = SDL_SCANCODE_H; + MyOS_Keycodes[I_PRESSED] = SDL_SCANCODE_I; + MyOS_Keycodes[J_PRESSED] = SDL_SCANCODE_J; + MyOS_Keycodes[K_PRESSED] = SDL_SCANCODE_K; + MyOS_Keycodes[L_PRESSED] = SDL_SCANCODE_L; + MyOS_Keycodes[M_PRESSED] = SDL_SCANCODE_M; + MyOS_Keycodes[N_PRESSED] = SDL_SCANCODE_N; + MyOS_Keycodes[O_PRESSED] = SDL_SCANCODE_O; + MyOS_Keycodes[P_PRESSED] = SDL_SCANCODE_P; + MyOS_Keycodes[Q_PRESSED] = SDL_SCANCODE_Q; + MyOS_Keycodes[R_PRESSED] = SDL_SCANCODE_R; + MyOS_Keycodes[S_PRESSED] = SDL_SCANCODE_S; + MyOS_Keycodes[T_PRESSED] = SDL_SCANCODE_T; + MyOS_Keycodes[U_PRESSED] = SDL_SCANCODE_U; + MyOS_Keycodes[V_PRESSED] = SDL_SCANCODE_V; + MyOS_Keycodes[W_PRESSED] = SDL_SCANCODE_W; + MyOS_Keycodes[X_PRESSED] = SDL_SCANCODE_X; + MyOS_Keycodes[Y_PRESSED] = SDL_SCANCODE_Y; + MyOS_Keycodes[Z_PRESSED] = SDL_SCANCODE_Z; + + MyOS_Keycodes[LEFT_BRACKET_PRESSED] = SDL_SCANCODE_LEFTBRACKET; + MyOS_Keycodes[RIGHT_BRACKET_PRESSED] = SDL_SCANCODE_RIGHTBRACKET; + MyOS_Keycodes[ENTER_PRESSED] = SDL_SCANCODE_RETURN; + MyOS_Keycodes[COMMA_PRESSED] = SDL_SCANCODE_COMMA; + MyOS_Keycodes[SPACE_PRESSED] = SDL_SCANCODE_SPACE; + MyOS_Keycodes[BACKSP_PRESSED] = SDL_SCANCODE_BACKSPACE; + MyOS_Keycodes[TAB_PRESSED] = SDL_SCANCODE_TAB; + MyOS_Keycodes[PERIOD_PRESSED] = SDL_SCANCODE_PERIOD; + MyOS_Keycodes[FORWARD_SLASH_PRESSED] = SDL_SCANCODE_SLASH; + MyOS_Keycodes[BACK_SLASH_PRESSED] = SDL_SCANCODE_BACKSLASH; + MyOS_Keycodes[BACK_TICK_PRESSED] = SDL_SCANCODE_GRAVE; + MyOS_Keycodes[ONE_PRESSED] = SDL_SCANCODE_1; + MyOS_Keycodes[TWO_PRESSED] = SDL_SCANCODE_2; + MyOS_Keycodes[THREE_PRESSED] = SDL_SCANCODE_3; + MyOS_Keycodes[FOUR_PRESSED] = SDL_SCANCODE_4; + MyOS_Keycodes[FIVE_PRESSED] = SDL_SCANCODE_5; + MyOS_Keycodes[SIX_PRESSED] = SDL_SCANCODE_6; + MyOS_Keycodes[SEVEN_PRESSED] = SDL_SCANCODE_7; + MyOS_Keycodes[EIGHT_PRESSED] = SDL_SCANCODE_8; + MyOS_Keycodes[NINE_PRESSED] = SDL_SCANCODE_9; + MyOS_Keycodes[ZERO_PRESSED] = SDL_SCANCODE_0; + MyOS_Keycodes[HYPHEN_PRESSED] = '-'; + MyOS_Keycodes[EQUALS_PRESSED] = SDL_SCANCODE_EQUALS; + MyOS_Keycodes[SEMI_PRESSED] = SDL_SCANCODE_SEMICOLON; + MyOS_Keycodes[SINGLE_QUOTE_PRESSED] = SDL_SCANCODE_APOSTROPHE; + + // TODO: There are certainly more keypresses that need to be translated +} + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/MyOS_1/Libs/SDL/src/video/myos/SDL_myoskeyboard.h b/MyOS_1/Libs/SDL/src/video/myos/SDL_myoskeyboard.h new file mode 100644 index 0000000..4ee49f5 --- /dev/null +++ b/MyOS_1/Libs/SDL/src/video/myos/SDL_myoskeyboard.h @@ -0,0 +1,8 @@ +#include "../../SDL_internal.h" +#include "../include/SDL_scancode.h" + +extern SDL_Scancode MyOS_Keycodes[SDL_NUM_SCANCODES]; + +void MyOS_InitKeyboard(void); + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/MyOS_1/Libs/SDL/src/video/myos/SDL_myosvideo.c b/MyOS_1/Libs/SDL/src/video/myos/SDL_myosvideo.c index ae973c8..44ed6e4 100644 --- a/MyOS_1/Libs/SDL/src/video/myos/SDL_myosvideo.c +++ b/MyOS_1/Libs/SDL/src/video/myos/SDL_myosvideo.c @@ -35,7 +35,7 @@ #include "../../events/SDL_events_c.h" #include "SDL_myosvideo.h" -#include "../dummy/SDL_nullevents_c.h" +#include "SDL_myosevents_c.h" #include "SDL_myosframebuffer_c.h" #define MYOSVID_DRIVER_NAME "myos" @@ -77,7 +77,7 @@ MYOS_CreateDevice(int devindex) device->VideoInit = MYOS_VideoInit; device->VideoQuit = MYOS_VideoQuit; device->SetDisplayMode = MYOS_SetDisplayMode; - device->PumpEvents = DUMMY_PumpEvents; + device->PumpEvents = MYOS_PumpEvents; device->CreateWindowFramebuffer = SDL_MYOS_CreateWindowFramebuffer; device->UpdateWindowFramebuffer = SDL_MYOS_UpdateWindowFramebuffer; device->DestroyWindowFramebuffer = SDL_MYOS_DestroyWindowFramebuffer; @@ -125,6 +125,8 @@ MYOS_VideoInit(_THIS) SDL_zero(mode); SDL_AddDisplayMode(&_this->displays[0], &mode); + MyOS_InitKeyboard(); + /* We're done! */ return 0; } diff --git a/MyOS_1/MyOS_1.vcxproj b/MyOS_1/MyOS_1.vcxproj index a65d6d8..fc53ed0 100644 --- a/MyOS_1/MyOS_1.vcxproj +++ b/MyOS_1/MyOS_1.vcxproj @@ -217,9 +217,10 @@ true false true + true - "C:\Program Files\qemu\qemu-system-x86_64w.exe" -soundhw sb16,adlib -monitor stdio -netdev user,id=u1,tftp="C:\Users\Administrator\.VirtualBox\TFTP" -device virtio-net,netdev=u1 -kernel "$(TargetPath)" -object filter-dump,id=f1,netdev=u1,file="C:\Program Files\qemu\dump.dat" -accel hax && "C:\Users\Administrator\Documents\Visual Studio 2015\Projects\AutoIncrementBuild\Release\AutoIncrementBuild.exe" + "C:\Program Files\qemu\qemu-system-x86_64w.exe" -serial pipe:MyOS_PIPE -soundhw sb16,adlib -monitor stdio -netdev user,id=u1,tftp="C:\Users\Administrator\.VirtualBox\TFTP" -device virtio-net,netdev=u1 -kernel "$(TargetPath)" -object filter-dump,id=f1,netdev=u1,file="C:\Program Files\qemu\dump.dat" -accel hax && "$(SolutionDir)SupportApps\AutoIncrementBuild\Release\AutoIncrementBuild.exe" "$(ProjectDir)Build_Number.h" Launching QEMU @@ -277,9 +278,11 @@ Cdecl Cdecl + + @@ -299,6 +302,7 @@ + @@ -318,6 +322,7 @@ + @@ -327,11 +332,14 @@ + + + @@ -348,6 +356,8 @@ + + @@ -364,6 +374,7 @@ + diff --git a/MyOS_1/MyOS_1.vcxproj.filters b/MyOS_1/MyOS_1.vcxproj.filters index 451fc8e..d3813f3 100644 --- a/MyOS_1/MyOS_1.vcxproj.filters +++ b/MyOS_1/MyOS_1.vcxproj.filters @@ -58,6 +58,24 @@ {60dc38ca-6797-4fd4-b28a-ea7b37fb964b} + + {5f3642f8-f847-47cc-91f6-93d2ebb71ed0} + + + {b27b41e5-298f-4e04-9dea-743123199d72} + + + {441e1d72-2ac6-46dd-b47e-a3a9f01acb81} + + + {ed1bb142-e86a-48ef-85ae-82740aea315c} + + + {3b619734-27a0-45df-8fc4-302973758206} + + + {3ff4899d-7636-427e-b059-139fe21daa2e} + @@ -192,6 +210,18 @@ Source Files + + Source Files\Tasks + + + Source Files\GUI + + + Source Files\Drivers + + + Source Files\Debugging + @@ -326,6 +356,24 @@ Header Files + + Header Files\Tasks + + + Source Files\Drivers + + + Header Files\GUI + + + Header Files\GUI + + + Header Files\Drivers + + + Header Files\Debugging + diff --git a/MyOS_1/Networking/TFTP.c b/MyOS_1/Networking/TFTP.c index 2c4141e..d0b9d4d 100644 --- a/MyOS_1/Networking/TFTP.c +++ b/MyOS_1/Networking/TFTP.c @@ -3,6 +3,7 @@ #include "../Terminal.h" #include "Ethernet.h" #include "../Drivers/Virtio_Net.h" +#include "../Tasks/Context.h" // TODO: Support multiple transactions uint16_t transactionID; @@ -16,6 +17,7 @@ uint8_t *nextFilePointer; uint16_t currentBlockNumber; uint16_t virtualBoxBlockNumber; // workaround for VirtualBox's bullshit uint32_t tftpFileSize; +uint32_t tftpTaskIndex; // TEMPTEMP HACKHACK uint32_t tftpServerIP; // TODO, maybe, support more than one server @@ -30,9 +32,16 @@ bool TFTP_TransactionComplete() // will block until the file is transacted // TODO: Implement timeout, error-checking // TODO: Fix hanging if an invalid serverIP is given +// TODO: We'll need mutexes or some other sync method to support multiple tasks +// And / Or we'll need to replace globals with per-task variables // actualFileSize can be NULL if the caller doesn't care about the size -bool TFTP_GetFile(uint32_t serverIP, char *filename, uint8_t *destinationBuffer, uint32_t maxFileSize, uint32_t *actualFileSize) +bool TFTP_GetFile(uint32_t serverIP, const char *filename, uint8_t *destinationBuffer, uint32_t maxFileSize, uint32_t *actualFileSize) { + // TEMPTEMP HACKHACK block until any existing transfers have completed + while (transferInProgress) + { + } + if(actualFileSize) *actualFileSize = 0; @@ -41,6 +50,7 @@ bool TFTP_GetFile(uint32_t serverIP, char *filename, uint8_t *destinationBuffer, tftpFileBuffer = destinationBuffer; tftpFileBufferSize = maxFileSize; + tftpTaskIndex = currentTask; if (debugLevel) { @@ -77,8 +87,13 @@ bool TFTP_GetFile(uint32_t serverIP, char *filename, uint8_t *destinationBuffer, // TODO: Same as above // Retrieves the size of a file. This can take a while for large files, because we actually have to retrieve the entire file to know its size. -bool TFTP_GetFileSize(uint32_t serverIP, char *filename, uint32_t *pActualFileSize) +bool TFTP_GetFileSize(uint32_t serverIP, const char *filename, uint32_t *pActualFileSize) { + // TEMPTEMP HACKHACK block until any existing transfers have completed + while (transferInProgress) + { + } + // Ensure pActualFileSize is a valid pointer if (!pActualFileSize) return false; @@ -88,6 +103,7 @@ bool TFTP_GetFileSize(uint32_t serverIP, char *filename, uint32_t *pActualFileSi // TFTP doesn't support retreiving a file's size, so we request the file from the server, but don't store the file returned determiningFileSize = true; + tftpTaskIndex = currentTask; // Request the file from the server TFTP_RequestFile(serverIP, filename, TFTP_TYPE_BINARY, NIC_MAC); @@ -111,8 +127,8 @@ bool TFTP_GetFileSize(uint32_t serverIP, char *filename, uint32_t *pActualFileSi } // source port is used to keep track of different transactions -uint16_t TFTP_RequestFile(uint32_t serverIP, char *filename, char *transferMode, uint8_t *sourceMAC) -{ +uint16_t TFTP_RequestFile(uint32_t serverIP, const char *filename, const char *transferMode, uint8_t *sourceMAC) +{ TFTP_RequestHeader *tftpData; size_t filenameLength = strlen(filename) + 1; // length of filename plus null terminator size_t transferModeLength = strlen(transferMode) + 1; @@ -136,7 +152,44 @@ uint16_t TFTP_RequestFile(uint32_t serverIP, char *filename, char *transferMode, memset(tftpData, 0, dataSize); tftpData->opcode = TFTP_OP_READ_REQUEST; - + + strncpy(tftpData->filename, filename, filenameLength - 1); + char *transferModePtr = (char *)((uint32_t)tftpData->filename + filenameLength); + strncpy(transferModePtr, transferMode, transferModeLength); + + EthernetSendPacket(packet, packetSize); + + return sourcePort; +} + +// source port is used to keep track of different transactions +// TODO: Seems like Qemu and VirtualBox don't support writing files via TFTP so I can't finish this :( +uint16_t TFTP_WriteFile(uint32_t serverIP, const char *filename, const char *transferMode, uint8_t *sourceMAC) +{ + TFTP_RequestHeader *tftpData; + size_t filenameLength = strlen(filename) + 1; // length of filename plus null terminator + size_t transferModeLength = strlen(transferMode) + 1; + + // packet size is 2 bytes (for the opcode) plus length of filename plus length of transferMode (both strings are zero terminated) + uint16_t packetSize = (uint16_t)(sizeof(tftpData->opcode) + filenameLength + transferModeLength); + uint16_t dataSize = packetSize; + uint16_t sourcePort = 1235; // TODO: should be a random number (I think) + + // set some globals that will keep track of the transaction + transactionID = sourcePort; + transferInProgress = true; + nextFilePointer = tftpFileBuffer; + currentBlockNumber = 0; // TFTP Starts with block number 1 + tftpFileSize = 0; + tftpServerIP = serverIP; + transferError = false; + + // create the packet to send + Ethernet_Header *packet = UDP_Create_Packet(serverIP, sourcePort, TFTP_PORT, &packetSize, sourceMAC, &tftpData); + + memset(tftpData, 0, dataSize); + tftpData->opcode = TFTP_OP_WRITE_REQUEST; + strncpy(tftpData->filename, filename, filenameLength - 1); char *transferModePtr = (char *)((uint32_t)tftpData->filename + filenameLength); strncpy(transferModePtr, transferMode, transferModeLength); @@ -210,9 +263,44 @@ void TFTP_ProcessDataPacket(TFTP_DataHeader *dataPacket, uint16_t sourcePort, ui if (!determiningFileSize) { - // copy received data to the file buffer - memcpy(nextFilePointer, dataPacket->data, dataSize); - nextFilePointer += dataSize; + // TEMPTEMP HACKHACK + // Now we've received some data, but we have to be careful because the task that's currently active + // may not have the same virtual memory space as the task that gave us the destination buffer. + // We need to ensure interrupts are disabled because we can't allow a context switch while we play with page tables. + __asm + { + // TODO: Are interrupts already disabled when we reach this code? Need to check on that. + pushf + cli + } + + // Ensure we have the proper page directory loaded for nextFilePointer for the task which requested the file + if (currentTask == tftpTaskIndex || tasks[currentTask].cr3 == tasks[tftpTaskIndex].cr3) + { + // We don't need to do anything with paging + + // copy received data to the file buffer + memcpy(nextFilePointer, dataPacket->data, dataSize); + nextFilePointer += dataSize; + } + else + { + // We need to swap out the page directory with the one for the task that requested the file + __writecr3(tasks[tftpTaskIndex].cr3); + + // copy received data to the file buffer + memcpy(nextFilePointer, dataPacket->data, dataSize); + nextFilePointer += dataSize; + + // restore the page directory of the current task + __writecr3(tasks[currentTask].cr3); + } + + // Restore interrupt state + __asm + { + popf + } } tftpFileSize += dataSize; diff --git a/MyOS_1/Networking/TFTP.h b/MyOS_1/Networking/TFTP.h index 2c985d3..84eb732 100644 --- a/MyOS_1/Networking/TFTP.h +++ b/MyOS_1/Networking/TFTP.h @@ -84,11 +84,12 @@ extern bool tftpHideErrors; extern uint32_t tftpServerIP; -bool TFTP_GetFile(uint32_t serverIP, char *filename, uint8_t *destinationBuffer, uint32_t maxFileSize, uint32_t *actualFileSize); +bool TFTP_GetFile(uint32_t serverIP, const char *filename, uint8_t *destinationBuffer, uint32_t maxFileSize, uint32_t *actualFileSize); -bool TFTP_GetFileSize(uint32_t serverIP, char *filename, uint32_t *pActualFileSize); +bool TFTP_GetFileSize(uint32_t serverIP, const char *filename, uint32_t *pActualFileSize); -uint16_t TFTP_RequestFile(uint32_t serverIP, char *filename, char *transferMode, uint8_t *sourceMAC); +uint16_t TFTP_RequestFile(uint32_t serverIP, const char *filename, const char *transferMode, uint8_t *sourceMAC); void TFTP_ProcessPacket(TFTP_Header *packet, uint16_t sourcePort, uint16_t destinationPort, uint16_t packetLength, uint8_t *sourceMAC); +uint16_t TFTP_WriteFile(uint32_t serverIP, const char *filename, const char *transferMode, uint8_t *sourceMAC); \ No newline at end of file diff --git a/MyOS_1/Tasks/Context.h b/MyOS_1/Tasks/Context.h new file mode 100644 index 0000000..91bf361 --- /dev/null +++ b/MyOS_1/Tasks/Context.h @@ -0,0 +1,68 @@ +#pragma once +#include "../misc.h" +#include "../printf.h" +#include +#include "../paging.h" + +// TODO: Make less ghetto +#define MAX_TASKS 64 +#define TICKS_PER_TASK 1 +#define MAX_IMAGE_NAME_LENGTH 32 + +typedef struct CONTEXT_INFO +{ + /*uint32_t EBP; + uint32_t EBX; + uint32_t EDI; + uint32_t ESI; + uint32_t EIP;*/ + uint32_t ESP; // All the other registers are saved and restored with pusha / popa + + uint32_t stackSize; + char imageName[MAX_IMAGE_NAME_LENGTH]; + bool inUse; + bool exclusive; // True to disable switching to any other tasks + uint32_t PID; + uint32_t cr3; + // ? What else? +} CONTEXT_INFO, PROCESS_CONTROL_BLOCK; + +struct READY_QUEUE_ENTRY; +typedef struct READY_QUEUE_ENTRY +{ + uint32_t taskIndex; + void *nextEntry; +} READY_QUEUE_ENTRY; + +// this is the layout of a task's stack after an interrupt has fired and the prologue of the interrupt has happened +typedef struct TASK_STACK_LAYOUT +{ + uint32_t registers[8]; // My interrupt will execute pushad to push all regs onto the stack + uint32_t prologueEbp; // prologue of interrupt handler will push the old value of ebp onto the stack + uint32_t returnAddress; // Where execution will "resume" after the iretd is executed at the end of the interrupt + // cs and eflags names may be swapped at various points in my code. I ignore their actual values so I've yet to research which one is which. + uint32_t cs; // cs that calling the interrupt pushes onto the stack + uint32_t eflags; // calling the interrupt pushes this onto the stack +} TASK_STACK_LAYOUT; + +// Indices into TASK_STRUCT_LAYOUT.registers +#define REG_INDEX_ESP 3 +#define REG_INDEX_EBP 2 + +extern READY_QUEUE_ENTRY *readyQueueHead; +extern PROCESS_CONTROL_BLOCK tasks[MAX_TASKS]; +//extern READY_QUEUE_ENTRY readyQueuePool[MAX_TASKS]; +extern int ticksLeftInTask; +extern int currentTask; + +extern uint32_t nextPID; + +void CloseApp(uint32_t PID); + +void DispatchNewTask(uint32_t programStart, PAGE_DIRECTORY_ENTRY *newPageDirectory, uint32_t stackSize, const char *imageName, bool exclusive); + +void ExitApp(); + +bool LaunchApp(const char *appName, int exclusive, uint32_t exeLocation); + +void SwitchTask(uint32_t taskIndex); \ No newline at end of file diff --git a/MyOS_1/Tasks/Dispatcher.c b/MyOS_1/Tasks/Dispatcher.c new file mode 100644 index 0000000..a470be8 --- /dev/null +++ b/MyOS_1/Tasks/Dispatcher.c @@ -0,0 +1,318 @@ +#include "Context.h" +#include "../printf.h" +#include "../Interrupts/System_Calls.h" +#include "../paging.h" +#include "../Networking/TFTP.h" +#include "../Executables/PE32.h" +#include "../Console_Serial.h" + +PROCESS_CONTROL_BLOCK tasks[64] = { 0 }; +READY_QUEUE_ENTRY *readyQueueHead = NULL; + +int currentTask = 0; // 0 is for the main kernel thread +int ticksLeftInTask = TICKS_PER_TASK; +uint32_t nextPID = 1000; + +// This must be global so we can access it while playing with the stack in ways the compiler can't predict +uint32_t stackPtr; + +// TODO: rewrite when we have waiting queues +// Interrupts are disabled by interrupt handler for system call. +void CloseApp(uint32_t PID) +{ + // If this task is running, let ExitApp() close it + if (tasks[currentTask].PID == PID) + ExitApp(); + + serial_printf("closing %d", PID); + + // Find the index of the app that will be closed + int taskIndex; + for (taskIndex = 0; taskIndex < MAX_TASKS; ++taskIndex) + { + if (tasks[taskIndex].PID == PID) + break; + } + if (taskIndex >= MAX_TASKS) + { + kprintf("ERROR! CloseApp() called with invalid PID, %d!", PID); + return; + } + + serial_printf(" - %s\n", tasks[taskIndex].imageName); + + // Has the task been closed already? + if (!tasks[taskIndex].inUse) + return; + + if (!readyQueueHead) + { + kprintf("Attempted to close a task with an empty ready queue!\n"); + return; + } + + // Find the ready queue entry associated with the task (and the one that preceeds it) + READY_QUEUE_ENTRY *pPreviousEntry = NULL; + READY_QUEUE_ENTRY *pCurrent = readyQueueHead; + + while (pCurrent && pCurrent->taskIndex != taskIndex) + { + pPreviousEntry = pCurrent; + pCurrent = pCurrent->nextEntry; + } + + if (!pCurrent) + { + kprintf("ERROR! CloseApp() called with PID %d, but couldn't find it in the queue!\n", PID); + serial_printf("ERROR! CloseApp() called with PID %d, but couldn't find it in the queue\n", PID); + return; + } + + // Was the app to close listed in the first entry? + if (!pPreviousEntry) + { + dbg_release(readyQueueHead); + readyQueueHead = pCurrent; + } + else + { + // Remove the ready queue entry and delete it + pPreviousEntry->nextEntry = pCurrent->nextEntry; + dbg_release(pCurrent); + } + + + // TODO: Free all memory associated with the app, including its stack + + // Mark the index as being free to use + tasks[taskIndex].inUse = false; +} + +void DispatchNewTask(uint32_t programStart, PAGE_DIRECTORY_ENTRY *newPageDirectory, uint32_t stackSize, const char *imageName, bool exclusive) +{ + if (debugLevel) + { + kprintf("Dispatching %s\n", imageName); + kprintf("program starts at 0x%lX\n", programStart); + } + + // disable interrupts while we mess with task slots + _disable(); + + // Find a free task slot + uint16_t taskSlot; + for (taskSlot = 0; taskSlot < MAX_TASKS; ++taskSlot) + { + if (!tasks[taskSlot].inUse) + break; + } + + if (taskSlot >= MAX_TASKS) + { + kprintf("ERROR: Too many tasks are running to start %s\n", imageName); + goto endOfDispatch; + } + + // Allocate stack space (must be 16-byte aligned) + stackPtr = 0x400000; //TODO: FIX://// (uint32_t)malloc(stackSize + 0x100); + + if (!stackPtr) + { + kprintf("ERROR: Couldn't allocate stack space for %s\n", imageName); + goto endOfDispatch; + } + + // ensure stackPtr is properly-aligned + if (stackPtr % 0x100 != 0) + stackPtr += (0x100 - stackPtr % 0x100); + + // Advance stackPtr to the end of the stack (the stack grows downward from the top of the memory region) + stackPtr += stackSize + (stackSize * taskSlot); // TEMPTEMP - Make sure multiple programs have different stack addresses + + if (debugLevel) + kprintf("0x%lX\n", stackPtr); + + // To the top of our new stack, we'll "push" a 0 (end of stack frame) followed by the "return" address of ExitApp() + // This will allow apps returning from main() to terminate gracefully + uint32_t *dummyESP = (uint32_t *)stackPtr; + --dummyESP; + *dummyESP = 0; + --dummyESP; + *dummyESP = (uint32_t)ExitApp; + stackPtr = (uint32_t)dummyESP; + + // Add task to PCB + tasks[taskSlot].stackSize = stackSize; + tasks[taskSlot].ESP = stackPtr; + strncpy(tasks[taskSlot].imageName, imageName, MAX_IMAGE_NAME_LENGTH - 1); + tasks[taskSlot].inUse = true; + tasks[taskSlot].PID = nextPID++; + tasks[taskSlot].cr3 = (uint32_t)newPageDirectory; + + // Create ready queue entry + READY_QUEUE_ENTRY *queueEntry; + queueEntry = dbg_alloc(sizeof(READY_QUEUE_ENTRY)); + // TODO: Exitting programs will need to be cleaned up somehow + if (!queueEntry) + { + kprintf("ERROR: Couldn't allocate memory for ready queue entry!\n"); + goto endOfDispatch; + } + + queueEntry->taskIndex = taskSlot; + queueEntry->nextEntry = NULL; + + // Add queue entry to end of the ready queue + if (!readyQueueHead) + { + readyQueueHead = queueEntry; + } + else + { + // Walk through list until we've found the final entry + READY_QUEUE_ENTRY *finalEntry = readyQueueHead; + while (finalEntry->nextEntry) + finalEntry = finalEntry->nextEntry; + + finalEntry->nextEntry = queueEntry; + } + + // setup stack for the task, and copy the stack to stackPtr + __asm + { + sti + push esp + push [stackPtr] + int SYSCALL_DISPATCH_NEW_TASK // call dispatch_new_task_interrupt_handler(eflags, cs, stackPtr, esp) + add esp, 8 + cli + } + + // Update the task's "stack image" to represent values appropriate for the new task + TASK_STACK_LAYOUT *pNewTask = (TASK_STACK_LAYOUT *)((unsigned long)stackPtr - sizeof(TASK_STACK_LAYOUT)); + pNewTask->returnAddress = programStart; + pNewTask->registers[REG_INDEX_EBP] = (unsigned long)pNewTask + (sizeof(uint32_t) * 8); + pNewTask->registers[REG_INDEX_ESP] = (unsigned long)pNewTask + (sizeof(uint32_t) * 8); + pNewTask->prologueEbp = (unsigned long)stackPtr; + + tasks[taskSlot].ESP = (uint32_t)pNewTask; + tasks[taskSlot].exclusive = exclusive; + + // If a GUI shell is running, tell it about the new process + if (guiCallback) + { + GUI_CreateConsoleWindowForApp(taskSlot); + } + + if (debugLevel) + { + terminal_writestring("eflags: "); + terminal_print_ulong_hex(pNewTask->eflags); + terminal_writestring("\ncs: "); + terminal_print_ulong_hex(pNewTask->cs); + + terminal_writestring("\nReturn value: "); + terminal_print_ulong_hex(pNewTask->returnAddress); + terminal_newline(); + + terminal_writestring("\nREG_INDEX_ESP: "); + terminal_print_ulong_hex(pNewTask->registers[REG_INDEX_ESP]); + terminal_newline(); + + terminal_writestring("\nREG_INDEX_EBP: "); + terminal_print_ulong_hex(pNewTask->registers[REG_INDEX_EBP]); + terminal_newline(); + + terminal_writestring("\nPrologue ebp: "); + terminal_print_ulong_hex(pNewTask->prologueEbp); + terminal_newline(); + + terminal_dumpHexAround((uint8_t *)pNewTask, 16, sizeof(TASK_STACK_LAYOUT) + 16); + } + +endOfDispatch: + // re-enable interrupts + __asm sti +} + +// TODO: Handle multiple error codes +// returns true on success +bool LaunchApp(const char *appName, int exclusive, uint32_t exeLocation) +{ + // Get the size of the executable file + uint32_t fileSize; + bool succeeded = true; + + // we'll need to re-enable interrupts if they were disabled + _enable(); + + if (!TFTP_GetFileSize(tftpServerIP, appName, &fileSize)) + { + printf("Failed to determine size of %s\n", appName); + return false; + } + + // Allocate a buffer for the executable file + uint8_t *peBuffer = dbg_alloc(fileSize); + if (!peBuffer) + { + printf("Not enough memory to open %s\n", appName); + return false; + } + + // Download the executable + if (!TFTP_GetFile(tftpServerIP, appName, peBuffer, fileSize, NULL)) + { + printf("Error reading %s from server!\n", appName); + return false; + } + + // Run the executable + if (!loadAndRunPE((uint8_t*)exeLocation, (DOS_Header*)peBuffer, appName, exclusive)) + { + printf("Error running %s\n", appName); + succeeded = false; + } + + dbg_release(peBuffer); + + return succeeded; +} + +// This is where a running program will "return" to. We can also call it with the exit system call +void ExitApp() +{ + // Make sure interrupts are disabled + _disable(); + + // If the ready-queue is empty or contains only this task, + // or if we're not running in multitasking mode, there's nothing we can do here + if (!readyQueueHead || (!readyQueueHead->nextEntry && readyQueueHead->taskIndex == currentTask)) + { + kprintf("ExitApp called on only running app. System halted"); + for (;;) + __halt(); + } + + // Allow the task index to be reused + tasks[currentTask].inUse = false; + + // TODO: Free all memory associated with this task + // TODO: Free the stack or mark it as reusable (not sure how to do this right now) + + // Make sure this task can be swapped out ASAP + tasks[currentTask].exclusive = false; + ticksLeftInTask = 0; + + printf("\n%s has exited.\n", tasks[currentTask].imageName); + + // TODO: Tell the GUI the program has quit + + // Enable interrupts + _enable(); + + // TODO: Is there a better way to switch contexts from here? + // Now we'll just wait for the timer interrupt to fire and this task will never be revisitted + for (;;) + __halt(); +} \ No newline at end of file diff --git a/MyOS_1/Timers/PIT.c b/MyOS_1/Timers/PIT.c index 5085ac3..719b9cd 100644 --- a/MyOS_1/Timers/PIT.c +++ b/MyOS_1/Timers/PIT.c @@ -6,6 +6,7 @@ #include "../System_Specific.h" #include "../File Formats/VOC.h" #include "../Drivers/Sound_Blaster_16.h" +#include "../Tasks/Context.h" // TEMPTEMP bool playSound = false; @@ -59,20 +60,110 @@ void PIT_Set_Interval(uint32_t hz) ticksSinceReset = 0; } +uint32_t espVal; +uint32_t oldTaskIndex; +READY_QUEUE_ENTRY *oldHead; + // Interrupt handler for the PIT void _declspec(naked) timer_interrupt_handler(void) { - _disable(); - _asm pushad; + _asm { + push ebp + pushad; + } //++interrupts_fired; ++ticksSinceReset; + if(debugLevel) + kprintf("."); + + // Is there a task waiting to be run? + if (!tasks[currentTask].exclusive && readyQueueHead) + { + --ticksLeftInTask; + if (ticksLeftInTask <= 0) + { + if(debugLevel) + kprintf("Saving %s.", tasks[currentTask].imageName); + + // Save current context + _asm mov[espVal], esp + tasks[currentTask].ESP = espVal; + tasks[currentTask].cr3 = __readcr3(); + + oldTaskIndex = currentTask; + + // Find the last ready queue entry in the list + READY_QUEUE_ENTRY *finalReadyQueueEntry = readyQueueHead; + while (finalReadyQueueEntry->nextEntry) + finalReadyQueueEntry = finalReadyQueueEntry->nextEntry; + + // Pull info from the front of the ready queue + currentTask = readyQueueHead->taskIndex; + + // Is the old task still running? + if (tasks[oldTaskIndex].inUse) + { + // Move the current task to the end of the ready queue + // Are there more than two ready queue entries? + if (readyQueueHead != finalReadyQueueEntry) + { + readyQueueHead->taskIndex = oldTaskIndex; + finalReadyQueueEntry->nextEntry = readyQueueHead; + oldHead = readyQueueHead; + readyQueueHead = readyQueueHead->nextEntry; + oldHead->nextEntry = NULL; + } + else + { + readyQueueHead->taskIndex = oldTaskIndex; + } + } + else + { + // The old task has quit, so we shouldn't add it to the ready queue and we have to + // free a ready queue entry or else we'll have one too many + + // Is there more than one ready queue entry? + if (readyQueueHead->nextEntry) + { + oldHead = readyQueueHead; + readyQueueHead = readyQueueHead->nextEntry; + dbg_release(oldHead); + } + else + { + dbg_release(readyQueueHead); + readyQueueHead = NULL; + } + } + + if(debugLevel) + kprintf(" Switching to %s\n", tasks[currentTask].imageName); + + ticksLeftInTask = TICKS_PER_TASK; + + // Switch to the new task's page tables + if(tasks[currentTask].cr3 != __readcr3()) + __writecr3(tasks[currentTask].cr3); + + // Set the stack pointer to the stack pointer of the new task + espVal = tasks[currentTask].ESP; + + if(debugLevel) + terminal_dumpHexAround((uint8_t *)espVal, 32, 32); + + _asm mov esp, espVal + } + } + PIC_sendEOI(TIMER_INTERRUPT); _asm { popad + pop ebp iretd } } \ No newline at end of file diff --git a/MyOS_1/main.c b/MyOS_1/main.c index b0ba6e2..4c08f19 100644 --- a/MyOS_1/main.c +++ b/MyOS_1/main.c @@ -3,6 +3,7 @@ #include "Console_VGA.h" #include "Console_Serial.h" #include "Console_Shell.h" +#include "Tasks/Context.h" #include "GDT.h" #include "Drivers/Keyboard.h" #include "System_Specific.h" @@ -26,6 +27,7 @@ int debugLevel = 0; bool showOverlay = true; +bool cursorEnabled = true; // Add ability for GUI shell to handle the cursor directly in the future /* Check if the compiler thinks you are targeting the wrong operating system. */ #if defined(__linux__) @@ -92,6 +94,9 @@ void KeStartup() JumpToUpperHalf(); //kprintf("eipVal: 0x%lX\n", eipVal); + // Make sure KPageAllocator can find the kernel page directory + tasks[0].cr3 = (uint32_t)pageDir; + // Initialize graphical mode if Grub set one for us GraphicsInitFromGrub(multibootInfo); @@ -112,6 +117,11 @@ void KeStartupPhase2(multiboot_info *multibootInfo) // initialize keyboard mapping init_key_map(); + // Add kernel to list of tasks + tasks[0].inUse = true; + strncpy(tasks[0].imageName, "KERNEL PROCESS", sizeof("KERNEL PROCESS")); + tasks[0].PID = nextPID - 1; + // Initialize interrupts Interrupts_Init(); @@ -127,6 +137,7 @@ void KeStartupPhase2(multiboot_info *multibootInfo) // Say Hello terminal_writestring("Hello world!\n"); + write_serial_string("\nHello world!\n"); kprintf("Welcome to My OS (working title) build %d\n", BUILD_NUMBER); if (debugLevel) @@ -168,38 +179,35 @@ void KeStartupPhase2(multiboot_info *multibootInfo) } } - if (mousePresent) + if (mousePresent && showOverlay) { terminal_writestring_top(" ", 0); - if (leftButton) + if (mouseState.leftButton) terminal_writestring_top("L", 0); - if (middleButton) + if (mouseState.middleButton) terminal_writestring_top("M", 1); - if (rightButton) + if (mouseState.rightButton) terminal_writestring_top("R", 2); - terminal_print_int_top(mouseX, 3); + terminal_print_int_top(mouseState.mouseX, 3); terminal_writestring_top(",", 13); - terminal_print_int_top(mouseY, 14); + terminal_print_int_top(mouseState.mouseY, 14); - if (!textMode) + if (!textMode && cursorEnabled) { - int cursX = mouseX; + int cursX = mouseState.mouseX; if (cursX < 0) cursX = 0; if (cursX >= MAX_X_RES) cursX = MAX_X_RES - 1; - int cursY = mouseY; + int cursY = mouseState.mouseY; if (cursY < 0) cursY = 0; if (cursY >= MAX_Y_RES) cursY = MAX_Y_RES - 1; - // convert y to screen space - cursY = MAX_Y_RES - cursY; - // Restore backed-up image GraphicsBlit(oldMouseX, oldMouseY, (PIXEL_32BIT *)areaUnderCursor, 16, 16); //GraphicsPlotPixel(oldMouseX, oldMouseY, oldColor); @@ -252,10 +260,17 @@ MULTIBOOT_INFO _MultibootInfo = // GRUB doesn't actually copy the kernel there, so we need to do some math // to find the actual address of KeStartup. (uint32_t)KeStartup - (uint32_t)NonPagingAddressOffset, - (uint32_t)MODE_TYPE, +#if GRUB_GRAPHICS + (uint32_t)GRAPHICS_MODE, (uint32_t)GRAPHICS_WIDTH, (uint32_t)GRAPHICS_HEIGHT, (uint32_t)GRAPHICS_DEPTH +#else + (uint32_t)TEXT_MODE, + (uint32_t)TEXT_WIDTH, + (uint32_t)TEXT_HEIGHT, + (uint32_t)TEXT_DEPTH +#endif }; #pragma comment(linker, "/merge:.text=.a") \ No newline at end of file diff --git a/MyOS_1/misc.c b/MyOS_1/misc.c index f505b6a..1a26097 100644 --- a/MyOS_1/misc.c +++ b/MyOS_1/misc.c @@ -105,8 +105,8 @@ void free(void *ptr) printf(" from %s, line %d\n", dbgFreeFilename, dbgFreeLineNumber); dbgFreeFilename = noFileName; dbgFreeLineNumber = 0; - for (;;) - __halt(); + //for (;;) + // __halt(); #else printf("\n"); #endif @@ -421,7 +421,7 @@ void* malloc(size_t size) freeMemoryArray.inUse[nextFreeMemorySlot] = false; #ifdef DEBUG_MEM - printf("Reusing freed memory from slot %d, (reuse #%d)\n", i, ++reuses); + //printf("Reusing freed memory from slot %d, (reuse #%d)\n", i, ++reuses); #endif return (void *)allocationArray.address[nextAllocationSlot++]; } @@ -1088,11 +1088,6 @@ static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxl return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); } -int vsnprintf_(char* buffer, size_t count, const char* format, va_list va) -{ - return _vsnprintf(_out_buffer, buffer, count, format, va); -} - static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va) { unsigned int flags, width, precision, n; @@ -1375,6 +1370,11 @@ static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const return (int)idx; } +int vsnprintf_(char* buffer, size_t count, const char* format, va_list va) +{ + return _vsnprintf(_out_buffer, buffer, count, format, va); +} + int snprintf_(char* buffer, size_t count, const char* format, ...) { va_list va; diff --git a/MyOS_1/misc.h b/MyOS_1/misc.h index f5584a4..4ab9a94 100644 --- a/MyOS_1/misc.h +++ b/MyOS_1/misc.h @@ -1,4 +1,9 @@ #pragma once + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + #include #include @@ -51,6 +56,7 @@ extern unsigned int nextFreeMemorySlot; extern int debugLevel; extern bool showOverlay; +extern bool cursorEnabled; void* calloc(size_t num, size_t size); @@ -112,4 +118,9 @@ void showAllocations(void); char * strrchr(const char *str, int ch); -int toupper(int arg); \ No newline at end of file +int toupper(int arg); + + +#ifdef __cplusplus +}; +#endif /* __cplusplus */ \ No newline at end of file diff --git a/MyOS_1/multiboot.h b/MyOS_1/multiboot.h index a38eb0b..e89f386 100644 --- a/MyOS_1/multiboot.h +++ b/MyOS_1/multiboot.h @@ -320,17 +320,19 @@ BASE_ADDRESS 0xC0000000 #define STACK_SIZE 0x4000 #define CHECKSUM -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) -#define GRAPHICS_MODE 0 -#define TEXT_MODE 1 -#define FLIP_MODE "Love Em" -/*#define MODE_TYPE TEXT_MODE -#define GRAPHICS_WIDTH 80 -#define GRAPHICS_HEIGHT 25 -#define GRAPHICS_DEPTH 0*/ -#define MODE_TYPE GRAPHICS_MODE -#define GRAPHICS_WIDTH 800 -#define GRAPHICS_HEIGHT 600 -#define GRAPHICS_DEPTH 32 +#define GRUB_GRAPHICS 1 /* set to 1 to request GRUB to setup graphics, 0 for text-mode display (not working)*/ +#define GRAPHICS_MODE 0 +#define TEXT_MODE 1 +#define FLIP_MODE "Love Em" + +// TODO: Text mode has regressed when booting with GRUB (see paging.h), but I don't think we really need it +#define TEXT_WIDTH 80 +#define TEXT_HEIGHT 25 +#define TEXT_DEPTH 0 + +#define GRAPHICS_WIDTH 800 +#define GRAPHICS_HEIGHT 600 +#define GRAPHICS_DEPTH 32 #endif /* ! ASM_FILE */ diff --git a/MyOS_1/myos_io.c b/MyOS_1/myos_io.c index 25bef5f..07ef24d 100644 --- a/MyOS_1/myos_io.c +++ b/MyOS_1/myos_io.c @@ -5,6 +5,8 @@ OPEN_FILES openFiles = { 0 }; +extern uint32_t currentTask; + int file_close(int fp) { if (fp >= MAX_FILES || fp < 0) @@ -58,9 +60,14 @@ int file_open(const char * filename, const char * mode) return -1; } + openFiles.buffer[index] = buffer; + openFiles.taskIndex[index] = currentTask; + openFiles.isOpen[index] = true; + if (!TFTP_GetFile(tftpServerIP, (char *)filename, buffer, fileSize, NULL)) { kprintf("Not able to open %s", filename); + openFiles.isOpen[index] = false; return -1; } @@ -68,8 +75,7 @@ int file_open(const char * filename, const char * mode) openFiles.filePos[index] = 0; openFiles.fileSize[index] = fileSize; openFiles.readOnly[index] = true; - openFiles.isOpen[index] = true; - openFiles.buffer[index] = buffer; + kprintf("opened %s in slot %d\n", filename, index); diff --git a/MyOS_1/myos_io.h b/MyOS_1/myos_io.h index 4333839..4cd099d 100644 --- a/MyOS_1/myos_io.h +++ b/MyOS_1/myos_io.h @@ -27,6 +27,7 @@ typedef struct OPEN_FILES bool readOnly[MAX_FILES]; bool isOpen[MAX_FILES]; uint8_t *buffer[MAX_FILES]; + uint32_t taskIndex[MAX_FILES]; } OPEN_FILES; diff --git a/MyOS_1/paging.c b/MyOS_1/paging.c index 934bd64..ec37dc1 100644 --- a/MyOS_1/paging.c +++ b/MyOS_1/paging.c @@ -2,7 +2,8 @@ #include "Paging.h" #include "Console_VGA.h" #include -#include "Interrupts\System_Calls.h" +#include "Interrupts/System_Calls.h" +#include "Tasks/Context.h" // Allocate space for paging structures. We need enough space for three arrays with 0x1000 32-bit entries each. // Each array must be aligned on a 0x1000-byte boundary. @@ -16,6 +17,8 @@ uint32_t *pageDir; uint32_t pagingNextAvailableMemory; // physical address of the next available page uint32_t paging4MPagesAvailable; // number of 4M physical memory pages available to be mapped +uint32_t nextPageDirectory; // TEMPTEMP where the next created page directory will be stored + // Allocates a number of 4-megabyte, consecutive pages. Why 4 megs? Because that's how MyOS rolls. // We're just going to stick with identity mapping for now. Why? Because that's how MyOS rolls. // Returns a pointer to the virtual address of the first allocated page or NULL if there was a problem. @@ -25,6 +28,13 @@ uint32_t paging4MPagesAvailable; // number of 4M physical memory pages availa // TODO: Make multi-threading safe void KPageAllocator(unsigned int pages, unsigned int *pPagesAllocated, uint32_t *pRetVal) { + // Ensure interrupts are disabled + __asm + { + pushf + cli + } + *pPagesAllocated = 0; // make sure there's enough pages available @@ -47,12 +57,30 @@ void KPageAllocator(unsigned int pages, unsigned int *pPagesAllocated, uint32_t uint32_t nextPage = pagingNextAvailableMemory / FOUR_MEGABYTES; + // Get the page directory we'll be using + PAGE_DIRECTORY_ENTRY *pageDirectory = (PAGE_DIRECTORY_ENTRY *)tasks[currentTask].cr3; + // Add each page to the page directory for (size_t allocated = 0; allocated < pages; ++allocated) { // Add the current page to the page directory - pageDir[nextPage] = ((nextPage * FOUR_MEGABYTES) + pageDirectory[nextPage] = ((nextPage * FOUR_MEGABYTES) | DIRECTORY_ENTRY_PRESENT | DIRECTORY_ENTRY_USER_ACCESSIBLE | DIRECTORY_ENTRY_WRITABLE | DIRECTORY_ENTRY_4MB); + + // If we're mapping this into the kernel space, we need to copy that mapping into every running task + if (pageDirectory == pageDir) + { + for (int i = 0; i < MAX_TASKS; ++i) + { + if (!tasks[i].inUse || tasks[i].cr3 == (uint32_t)pageDir) + continue; + + PAGE_DIRECTORY_ENTRY *otherPageDir = (PAGE_DIRECTORY_ENTRY *)tasks[i].cr3; + + otherPageDir[nextPage] = ((nextPage * FOUR_MEGABYTES) + | DIRECTORY_ENTRY_PRESENT | DIRECTORY_ENTRY_USER_ACCESSIBLE | DIRECTORY_ENTRY_WRITABLE | DIRECTORY_ENTRY_4MB); + } + } // update pointers and stuff ++nextPage; @@ -60,4 +88,43 @@ void KPageAllocator(unsigned int pages, unsigned int *pPagesAllocated, uint32_t pagingNextAvailableMemory += FOUR_MEGABYTES; ++(*pPagesAllocated); } -} \ No newline at end of file + + //kprintf("Task: %s\n", tasks[currentTask].imageName); + //Paging_Print_Page_Table(pageDirectory); + + __asm popf +} + +bool Paging_Print_Page_Table(PAGE_DIRECTORY_ENTRY *thePageDir) +{ + bool done; + done = true; + + kprintf("Page table entries:\nLogical -> Physical -- flags\n"); + kprintf("continuing\n"); + for (int i = 0; i < 1024; ++i) + { + if (!(thePageDir[i] & PAGE_ENTRY_PRESENT)) + continue; + done = false; + kprintf("0x%X -> 0x%X - 0x%X\n", i * FOUR_MEGABYTES, thePageDir[i] & 0xFFFFF000, thePageDir[i] & 0xFFF); + } + return done; +} + +uint32_t Paging_Get_Physical_Address(void *address) +{ + uint32_t vAddr = (uint32_t)address; + + // TODO: don't always assume 4M entries + + uint32_t index = vAddr / FOUR_MEGABYTES; + uint32_t offset = vAddr - (index * FOUR_MEGABYTES); + + // Get page directory + PAGE_DIRECTORY_ENTRY *pDir = tasks[currentTask].cr3; + + uint32_t pAddr = pDir[index] & PAGING_ADDRESS_BITS; + + return pAddr + offset; +} diff --git a/MyOS_1/paging.h b/MyOS_1/paging.h index ef5309b..ccc09b2 100644 --- a/MyOS_1/paging.h +++ b/MyOS_1/paging.h @@ -10,21 +10,23 @@ typedef /*__declspec(align(4096))*/ uint32_t PAGE_DIRECTORY_ENTRY; typedef /*__declspec(align(4096))*/ uint32_t PAGE_TABLE_ENTRY; #define PAGE_ENTRY_PRESENT 1 -#define PAGE_ENTRY_USER_ACCESSIBLE 2 -#define PAGE_ENTRY_WRITABLE 4 +#define PAGE_ENTRY_WRITABLE 2 +#define PAGE_ENTRY_USER_ACCESSIBLE 4 #define DIRECTORY_ENTRY_PRESENT 1 -#define DIRECTORY_ENTRY_USER_ACCESSIBLE 2 -#define DIRECTORY_ENTRY_WRITABLE 4 +#define DIRECTORY_ENTRY_WRITABLE 2 +#define DIRECTORY_ENTRY_USER_ACCESSIBLE 4 #define DIRECTORY_ENTRY_4MB 0x80 #define FOUR_MEGABYTES 0x400000 +#define PAGING_ADDRESS_BITS 0xFFFFF000 extern uint32_t paging_space[0x3FFF]; extern uint32_t *pageDir; extern uint32_t pagingNextAvailableMemory; extern uint32_t paging4MPagesAvailable; +extern uint32_t nextPageDirectory; // TEMPTEMP typedef uint32_t ULONG_PTR; @@ -60,8 +62,17 @@ inline void Paging_Enable(multiboot_info *multibootInfo) // Setup identity mapping for the first four megabytes pageDirectory[0] = (PAGE_DIRECTORY_ENTRY)(0x00 | DIRECTORY_ENTRY_PRESENT | DIRECTORY_ENTRY_WRITABLE | DIRECTORY_ENTRY_4MB); + // Setup identity mapping for the four megabytes starting at megabyte 4 + pageDirectory[1] = (PAGE_DIRECTORY_ENTRY)((uint32_t)0x400000 | DIRECTORY_ENTRY_PRESENT | DIRECTORY_ENTRY_WRITABLE | DIRECTORY_ENTRY_4MB | DIRECTORY_ENTRY_USER_ACCESSIBLE); + // Setup identity mapping for the four megabytes starting at megabyte 8 - pageDirectory[2] = (PAGE_DIRECTORY_ENTRY)((uint32_t)0x800000 | DIRECTORY_ENTRY_PRESENT | DIRECTORY_ENTRY_WRITABLE | DIRECTORY_ENTRY_4MB); + pageDirectory[2] = (PAGE_DIRECTORY_ENTRY)((uint32_t)0x800000 | DIRECTORY_ENTRY_PRESENT | DIRECTORY_ENTRY_WRITABLE | DIRECTORY_ENTRY_4MB | DIRECTORY_ENTRY_USER_ACCESSIBLE); + + // Identity map the next four megs (this is used by the GUI shell) + pageDirectory[3] = (PAGE_DIRECTORY_ENTRY)((uint32_t)0xC00000 | DIRECTORY_ENTRY_PRESENT | DIRECTORY_ENTRY_WRITABLE | DIRECTORY_ENTRY_4MB | DIRECTORY_ENTRY_USER_ACCESSIBLE); + + // Identity map the next four megs + pageDirectory[4] = (PAGE_DIRECTORY_ENTRY)((uint32_t)0x1000000 | DIRECTORY_ENTRY_PRESENT | DIRECTORY_ENTRY_WRITABLE | DIRECTORY_ENTRY_4MB | DIRECTORY_ENTRY_USER_ACCESSIBLE); // Map the kernel (4 megs starting at 0x10 0000) to 0xC000 0000 for (i = 0; i < 1024; ++i) @@ -75,6 +86,8 @@ inline void Paging_Enable(multiboot_info *multibootInfo) // TEMPTEMP HACKHACK! - identity map the linear frame buffer, which on my Qemu starts at 0xFD00 0000 uint32_t lfbAddress = 0xFD000000; +// TODO: This section of code will bug out if GRUB_GRAPHICS isn't defined in VirtualBox +// TODO: We can conditionally comment this out, but then the gfx command fails to switch modes properly // see if Grub gave us an lfb address and use that one if it did if (multibootInfo->flags & MULTIBOOT_INFO_FRAMEBUFFER_INFO) { @@ -88,6 +101,7 @@ inline void Paging_Enable(multiboot_info *multibootInfo) { videoIdentityTable[i] = (lfbAddress + i * 0x1000) | PAGE_ENTRY_PRESENT | PAGE_ENTRY_WRITABLE; // attributes: supervisor level, read/write, present } +// End buggy section // put the lfb page table in the page directory uint32_t page = lfbAddress / 0x400000; @@ -106,7 +120,40 @@ inline void Paging_Enable(multiboot_info *multibootInfo) pageDir = pageDirectory; // determine available pages - pagingNextAvailableMemory = FOUR_MEGABYTES * 3; // Next available page will (likely) start at 12 Megs + pagingNextAvailableMemory = FOUR_MEGABYTES * 5; // TEMP: Next available page will (likely) start at 20 Megs // We'll assume we have 64 megs available paging4MPagesAvailable = 16; // TODO: Calculate based on the memory map Grub gave us + + // TEMPTEMP: put page directories between 16 - 20 megs + nextPageDirectory = FOUR_MEGABYTES * 4; + + // Walk through the mem map grub gave us + // TODO: Assert that grub gave us a memory map + // TODO: Don't assume we have memory at the beginning of RAM + // TODO: Use all the entries we get from GRUB + multiboot_mmap_entry *entry = (multiboot_mmap_entry *)multibootInfo->mmap_addr; + + // examine each mmap entry + for (uint32_t offset = 0; offset <= multibootInfo->mmap_length && entry->size; offset += entry->size + 4) + { + if (entry->type == MULTIBOOT_MEMORY_AVAILABLE) + { + // If the next page of memory we're assuming we can use resides here + if (pagingNextAvailableMemory >= entry->addr && pagingNextAvailableMemory < (entry->addr + entry->len)) + { + // determine how many pages we really have available + uint64_t addrEnd = entry->addr + entry->len; + uint64_t bytesAvailable = addrEnd - pagingNextAvailableMemory; + paging4MPagesAvailable = bytesAvailable / FOUR_MEGABYTES; + return; + } + } + + // advance pointer to next entry + entry = (multiboot_mmap_entry*)((uint32_t)entry + entry->size + 4); + } } + +bool Paging_Print_Page_Table(PAGE_DIRECTORY_ENTRY *thePageDir); + +uint32_t Paging_Get_Physical_Address(void *address); \ No newline at end of file diff --git a/MyOS_1/printf.c b/MyOS_1/printf.c index 9302974..5c66b23 100644 --- a/MyOS_1/printf.c +++ b/MyOS_1/printf.c @@ -185,7 +185,7 @@ static inline bool _is_digit(char ch) // internal ASCII string to unsigned int conversion -static unsigned int _atoi(const char** str) +/*static*/ unsigned int _atoi(const char** str) { unsigned int i = 0U; while (_is_digit(**str)) { diff --git a/MyOS_1/printf.h b/MyOS_1/printf.h index ec6786f..b5fd6c5 100644 --- a/MyOS_1/printf.h +++ b/MyOS_1/printf.h @@ -41,6 +41,7 @@ extern "C" { #endif +unsigned int _atoi(const char** str); /** * Output a character to a custom device like UART, used by the printf() function diff --git a/MyOS_GUI_For_Windows/MyOS_GUI_For_Windows.vcxproj b/MyOS_GUI_For_Windows/MyOS_GUI_For_Windows.vcxproj new file mode 100644 index 0000000..1b0634c --- /dev/null +++ b/MyOS_GUI_For_Windows/MyOS_GUI_For_Windows.vcxproj @@ -0,0 +1,186 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {19CF43DA-2745-451D-B811-0A40EF43BE2F} + Win32Proj + MyOS_GUI_For_Windows + 8.1 + MyOS_GUI_Shell_For_Windows + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(VC_IncludePath);$(WindowsSDK_IncludePath);C:\Users\Administrator\Downloads\SDL2-devel-2.0.9-VC\SDL2-2.0.9\include + $(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;C:\Users\Administrator\Downloads\SDL2-devel-2.0.9-VC\SDL2-2.0.9\lib\x86 + + + true + + + false + $(VC_IncludePath);$(WindowsSDK_IncludePath);C:\Users\Administrator\Downloads\SDL2-devel-2.0.9-VC\SDL2-2.0.9\include + $(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;C:\Users\Administrator\Downloads\SDL2-devel-2.0.9-VC\SDL2-2.0.9\lib\x86 + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + sdl2.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + kernel32.lib;user32.lib;sdl2.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MyOS_GUI_For_Windows/MyOS_GUI_For_Windows.vcxproj.filters b/MyOS_GUI_For_Windows/MyOS_GUI_For_Windows.vcxproj.filters new file mode 100644 index 0000000..25a7f19 --- /dev/null +++ b/MyOS_GUI_For_Windows/MyOS_GUI_For_Windows.vcxproj.filters @@ -0,0 +1,105 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/MyOS_GUI_For_Windows/SDL2.dll b/MyOS_GUI_For_Windows/SDL2.dll new file mode 100644 index 0000000..7017790 Binary files /dev/null and b/MyOS_GUI_For_Windows/SDL2.dll differ diff --git a/MyOS_GUI_For_Windows/kg2.bmp b/MyOS_GUI_For_Windows/kg2.bmp new file mode 100644 index 0000000..25433ad Binary files /dev/null and b/MyOS_GUI_For_Windows/kg2.bmp differ diff --git a/MyOS_GUI_For_Windows/kghr.bmp b/MyOS_GUI_For_Windows/kghr.bmp new file mode 100644 index 0000000..050d85f Binary files /dev/null and b/MyOS_GUI_For_Windows/kghr.bmp differ diff --git a/MyOS_GUI_For_Windows/kghrwide.bmp b/MyOS_GUI_For_Windows/kghrwide.bmp new file mode 100644 index 0000000..14c09d5 Binary files /dev/null and b/MyOS_GUI_For_Windows/kghrwide.bmp differ diff --git a/MyOS_GUI_Shell/GUI_Button.cpp b/MyOS_GUI_Shell/GUI_Button.cpp new file mode 100644 index 0000000..d486a0a --- /dev/null +++ b/MyOS_GUI_Shell/GUI_Button.cpp @@ -0,0 +1,112 @@ +#include "GUI_Button.h" + +GUI_Button::GUI_Button(const char * buttonText, uint32_t controlID, GUI_Window * pOwner) + : GUI_Control(pOwner, controlID) +{ + this->buttonText = SDL_strdup(buttonText); + this->controlID = controlID; + + // Create the surface for the text + SDL_Surface *pFontSurface = FNT_Render(buttonText, SDL_BLACK); + + // Create the surface for the button + pSurface = SDL_CreateRGBSurface(0, // Flags + pFontSurface->w + (GUI_BUTTON_TEXT_MARGIN * 2), // Width + pFontSurface->h + (GUI_BUTTON_TEXT_MARGIN * 2), // Height + 32, // Depth + 0, 0, 0, // R, G, and B masks (default) + 0x000000FF); // alpha mask + + // Fill Surface with the default button color + backgroundColor = SDL_DEFAULT_BUTTON_COLOR; + FillSurface(pSurface, SDL_DEFAULT_BUTTON_COLOR); + + // Draw font on button + SDL_Rect dstRect = { GUI_BUTTON_TEXT_MARGIN, GUI_BUTTON_TEXT_MARGIN, pFontSurface->w, pFontSurface->h }; + SDL_BlitSurface(pFontSurface, NULL, pSurface, &dstRect); + + SDL_FreeSurface(pFontSurface); + + // Draw border around the button + Draw3D_Box(pSurface, 0, 0, pSurface->w, pSurface->h); + + // Center the box on the window + dimensions.width = pSurface->w; + dimensions.height = pSurface->h; + dimensions.left = (pOwner->dimensions.width / 2) - (dimensions.width / 2); + dimensions.top = (pOwner->dimensions.height / 2) - (dimensions.height / 2); +} + +GUI_Button::GUI_Button(const char * buttonText, uint32_t controlID, GUI_Window * pOwner, GUI_Rect dimensions) + : GUI_Control(pOwner, controlID) +{ + this->buttonText = SDL_strdup(buttonText); + this->controlID = controlID; + this->dimensions = dimensions; + + backgroundColor = SDL_DEFAULT_BUTTON_COLOR; + pSurface = CreateSurface(); +} + +void GUI_Button::PaintToSurface(SDL_Surface *pTargetSurface) +{ + SDL_BlitSurface(pSurface, NULL, pTargetSurface, dimensions.GetSDL_Rect()); +} + +void GUI_Button::OnClick(int relX, int relY) +{ + Draw3D_InsetBox(pSurface, 0, 0, dimensions.width, dimensions.height); + + PaintToSurface(pOwner->pSurface); + + pOwner->ControlClicked(controlID); +} + +void GUI_Button::OnMouseUp(int relX, int relY) +{ + Draw3D_Box(pSurface, 0, 0, dimensions.width, dimensions.height); + + PaintToSurface(pOwner->pSurface); +} + +// TODO: Error-checking +void GUI_Button::Resize(GUI_Rect newDimensions) +{ + SDL_Surface *pOldSurface = pSurface; + + dimensions = newDimensions; + SDL_Surface *pNewSurface = CreateSurface(); + + pSurface = pNewSurface; + + SDL_FreeSurface(pOldSurface); +} + +// TODO: Error-checking +SDL_Surface *GUI_Button::CreateSurface() +{ + // Create the surface for the text + SDL_Surface *pFontSurface = FNT_Render(buttonText, SDL_BLACK); + + // Create the surface for the button + SDL_Surface *pNewSurface = SDL_CreateRGBSurface(0, // Flags + dimensions.width, // Width + dimensions.height, // Height + 32, // Depth + 0, 0, 0, // R, G, and B masks (default) + 0x000000FF); // alpha mask + + // Fill Surface with the default button color + FillSurface(pNewSurface, backgroundColor); + + // Draw font on button. For now, center text on button + SDL_Rect dstRect = { (dimensions.width / 2) - (pFontSurface->w / 2), (dimensions.height / 2) - (pFontSurface->h / 2), pFontSurface->w, pFontSurface->h }; + SDL_BlitSurface(pFontSurface, NULL, pNewSurface, &dstRect); + + SDL_FreeSurface(pFontSurface); + + // Draw border around the button + Draw3D_Box(pNewSurface, 0, 0, pNewSurface->w, pNewSurface->h); + + return pNewSurface; +} diff --git a/MyOS_GUI_Shell/GUI_Button.h b/MyOS_GUI_Shell/GUI_Button.h new file mode 100644 index 0000000..1abe7ce --- /dev/null +++ b/MyOS_GUI_Shell/GUI_Button.h @@ -0,0 +1,30 @@ +#pragma once + +#include "GUI_Control.h" + +#define GUI_BUTTON_TEXT_MARGIN 8 + +class GUI_Button : public GUI_Control +{ +public: + GUI_Button(const char *buttonText, uint32_t controlID, GUI_Window *pOwner); + GUI_Button(const char *buttonText, uint32_t controlID, GUI_Window *pOwner, GUI_Rect dimensions); + + ~GUI_Button() + { + SDL_free(buttonText); + } + + void PaintToSurface(SDL_Surface * pTargetSurface); + virtual void OnClick(int relX, int relY); + virtual void OnMouseUp(int relX, int relY); + void Resize(GUI_Rect newDimensions); // TODO: Make dimensions a private variable + + SDL_Color backgroundColor; + +protected: + SDL_Surface *CreateSurface(); + + char *buttonText; + SDL_Surface *pSurface; +}; \ No newline at end of file diff --git a/MyOS_GUI_Shell/GUI_Control.cpp b/MyOS_GUI_Shell/GUI_Control.cpp new file mode 100644 index 0000000..8eafbdc --- /dev/null +++ b/MyOS_GUI_Shell/GUI_Control.cpp @@ -0,0 +1,6 @@ +#include "GUI_Control.h" + +void GUI_Control::OnClick(int relX, int relY) +{ + pOwner->ControlClicked(controlID); +} diff --git a/MyOS_GUI_Shell/GUI_Control.h b/MyOS_GUI_Shell/GUI_Control.h new file mode 100644 index 0000000..2b654e4 --- /dev/null +++ b/MyOS_GUI_Shell/GUI_Control.h @@ -0,0 +1,48 @@ +#pragma once +#include "GUI_Object.h" +#include "GUI_Window.h" + +class GUI_Window; + +class GUI_Control : public GUI_Object +{ +public: + GUI_Control(GUI_Window *pOwner, uint32_t controlID) + { + this->pOwner = pOwner; + this->controlID = controlID; + } + + virtual void LoseFocus() {} + virtual void GainFocus() {} + virtual void OnHover(int relX, int relY) {} + virtual void OnClick(int relX, int relY); + virtual void OnDrag(int relClickX, int relClickY, int relDestX, int relDestY) {} + virtual void Resize(GUI_Rect newDimensions) { dimensions = newDimensions; } + virtual void SendChar(char c) {} + virtual void UpdateCursor() {} + + uint32_t controlID; +protected: + GUI_Window *pOwner; +}; + +// version of GUI_Control that will call external functions when public methods are called +// TODO: Maybe implement version with lambda functions? +// It's unclear to me how / if this will work between the shell and other apps. RPC? +class GUI_Control_Hooks : public GUI_Control +{ +public: + //void OnHover(int relX, int relY); + void OnClick(int relX, int relY); + void SetOnClickCallback(void(*Callback)(uint32_t param), uint32_t param); + + // OnClick callback that allows for passing a custom parameter (not sure if I'd need or use this) + //void OnClick(int relX, int relY, uint32_t customParam); + +protected: + //void(*OnClickCallback)(uint32_t param, uint32_t customParam); + + void (*OnClickCallback)(uint32_t param); + uint32_t onClickParam; // parameter that will be passed to the callback. Could be a button ID for example. +}; \ No newline at end of file diff --git a/MyOS_GUI_Shell/GUI_EditControl.cpp b/MyOS_GUI_Shell/GUI_EditControl.cpp new file mode 100644 index 0000000..c6437bb --- /dev/null +++ b/MyOS_GUI_Shell/GUI_EditControl.cpp @@ -0,0 +1,135 @@ +#include "GUI_EditControl.h" +#include +#include "MyOS_GUI_Shell.h" + +GUI_EditControl::GUI_EditControl(GUI_Rect guiRect, GUI_Window *pOwner, uint32_t controlID) + : GUI_Control(pOwner, controlID) +{ + pSurface = NULL; + dimensions = guiRect; + CreateSurface(); + cursorX = 2; + + memset(stringContents, 0, GUI_EDIT_MAX_STRING_LENGTH); + stringLength = 0; +} + + +GUI_EditControl::~GUI_EditControl() +{ + SDL_FreeSurface(pSurface); +} + +void GUI_EditControl::CreateSurface() +{ + if (pSurface) + SDL_FreeSurface(pSurface); + + pSurface = SDL_CreateRGBSurface(0, + dimensions.width, + dimensions.height, + 32, + 0xFF000000, + 0x00FF0000, + 0x0000FF00, + 0x000000FF); + + FillSurface(pSurface, SDL_WHITE); + + Draw3D_InsetBox(pSurface, 0, 0, dimensions.width - 1, dimensions.height - 1); +} + +void GUI_EditControl::LoseFocus() +{ + if(cursorBlinkOn) + DrawVerticalLine(pSurface, cursorX, 1, dimensions.height - 2, SDL_WHITE); + + cursorBlinkOn = false; +} + +void GUI_EditControl::OnClick(int relX, int relY) +{ + pOwner->SetFocus(controlID); +} + +void GUI_EditControl::PaintToSurface(SDL_Surface * pTargetSurface) +{ + SDL_BlitSurface(pSurface, NULL, pTargetSurface, dimensions.GetSDL_Rect()); +} + +// TODO: Handle horizontal scrolling +void GUI_EditControl::SendChar(char c) +{ + if (c == SDLK_LSHIFT || c == SDLK_RSHIFT) + return; + + char str[2] = { 0 }; + str[0] = c; + + if (c == SDLK_BACKSPACE) + { + if (stringLength == 0) + return; + + stringContents[stringLength--] = '\0'; + + // Erase the previous cursor + if (cursorBlinkOn) + DrawVerticalLine(pSurface, cursorX, 1, dimensions.height - 2, SDL_WHITE); + + cursorBlinkOn = true; + + // Erase the previous character + cursorX -= FNT_FONTWIDTH; + SDL_Rect charRect = { cursorX, FNT_TOPBOTTOMMARGIN, FNT_FONTWIDTH, FNT_FONTHEIGHT }; + SDL_FillRect(pSurface, &charRect, 0xFFFFFFFF); // fill the space with white + + // Redraw the cursor + DrawVerticalLine(pSurface, cursorX, 1, dimensions.height - 2, SDL_BLACK); + + return; + } + + if (stringLength >= GUI_EDIT_MAX_STRING_LENGTH) + { + MessageBox("Edit string is too long", "ERROR"); + return; + } + + // Copy char to internal string + stringContents[stringLength++] = c; + + // Erase the previous cursor + if(cursorBlinkOn) + DrawVerticalLine(pSurface, cursorX, 1, dimensions.height - 2, SDL_WHITE); + + cursorBlinkOn = true; + + // Render the char at the end of the string + { + SDL_Surface *pFont = FNT_Render(str, SDL_BLACK); + + SDL_Rect dest = { cursorX, FNT_TOPBOTTOMMARGIN, pFont->w, pFont->h }; + SDL_BlitSurface(pFont, NULL, pSurface, &dest); + + SDL_FreeSurface(pFont); + } + + // Advance the cursor and redraw it + cursorX += FNT_FONTWIDTH; + DrawVerticalLine(pSurface, cursorX, 1, dimensions.height - 2, SDL_BLACK); +} + +void GUI_EditControl::UpdateCursor() +{ + cursorBlinkOn = !cursorBlinkOn; + + if (cursorBlinkOn) + { + DrawVerticalLine(pSurface, cursorX, 1, dimensions.height - 2, SDL_BLACK); + } + else + { + DrawVerticalLine(pSurface, cursorX, 1, dimensions.height - 2, SDL_WHITE); + } +} diff --git a/MyOS_GUI_Shell/GUI_EditControl.h b/MyOS_GUI_Shell/GUI_EditControl.h new file mode 100644 index 0000000..2233410 --- /dev/null +++ b/MyOS_GUI_Shell/GUI_EditControl.h @@ -0,0 +1,28 @@ +#pragma once +#include "GUI_Control.h" + +#define GUI_EDIT_MAX_STRING_LENGTH 128 + +class GUI_EditControl : + public GUI_Control +{ +public: + GUI_EditControl(GUI_Rect guiRect, GUI_Window *pOwner, uint32_t controlID); + ~GUI_EditControl(); + + void CreateSurface(); + void LoseFocus(); + void OnClick(int relX, int relY); + void PaintToSurface(SDL_Surface *pTargetSurface); + void SendChar(char c); + void UpdateCursor(); + + SDL_Surface *pSurface; + + bool cursorBlinkOn; + int cursorX; + + char stringContents[GUI_EDIT_MAX_STRING_LENGTH]; + int stringLength; +}; + diff --git a/MyOS_GUI_Shell/GUI_Kernel_Shell.cpp b/MyOS_GUI_Shell/GUI_Kernel_Shell.cpp new file mode 100644 index 0000000..3ee5848 --- /dev/null +++ b/MyOS_GUI_Shell/GUI_Kernel_Shell.cpp @@ -0,0 +1,44 @@ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "GUI_Kernel_Shell.h" +#include "MyOS_GUI_Shell.h" +#include "../MyOS_1/GUI_Messages.h" + +extern int lastWindowID; + +void GUI_Kernel_Callback(uint32_t PID, uint32_t messageType, void * pData) +{ + GUI_Window *pWindow = NULL; + + switch (messageType) + { + case GUI_MSG_NEW_CONSOLE_APP: + // Create a new window with the app name + CreateTextWindow(PID, + ((GUI_NEW_CONSOLE_APP_DATA *)pData)->appName); + break; + + case GUI_MSG_CONSOLE_PRINT: + // Send the text to the window + + // Find the window associated with the PID + pWindow = GetWindowFromID(PID); + if (!pWindow) + { + MessageBox("GUI_Kernel_Callback called with unrecognized PID!", "ERROR"); + return; + } + pWindow->SendWindowText( ((GUI_CONSOLE_PRINT_DATA *)pData)->textString ); + break; + + default: + MessageBox("GUI_Kernel_Callback called with unrecognized messageType.", "ERROR"); + break; + } +} + +#ifdef __cplusplus +} +#endif diff --git a/MyOS_GUI_Shell/GUI_Kernel_Shell.h b/MyOS_GUI_Shell/GUI_Kernel_Shell.h new file mode 100644 index 0000000..e19cd13 --- /dev/null +++ b/MyOS_GUI_Shell/GUI_Kernel_Shell.h @@ -0,0 +1,21 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include + +// Used to define the interface between the Kernel and the GUI Shell (on the shell side) + +#define \ +GUI_BASE_ADDRESS 0xC00000 + +#define WINDOW_ID_IS_NOT_PID 0x80000000 /* Window ID's with this bit set aren't associated with an application */ + +// Called by the kernel to send messages to the GUI +void GUI_Kernel_Callback(uint32_t PID, uint32_t messageType, void *pData); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ \ No newline at end of file diff --git a/MyOS_GUI_Shell/GUI_MessageBox.cpp b/MyOS_GUI_Shell/GUI_MessageBox.cpp new file mode 100644 index 0000000..6ac8593 --- /dev/null +++ b/MyOS_GUI_Shell/GUI_MessageBox.cpp @@ -0,0 +1,30 @@ +#include "GUI_MessageBox.h" +#include "GUI_Object.h" +#include "GUI_Button.h" +#include "MyOS_GUI_Shell.h" + +GUI_MessageBox::GUI_MessageBox(char * messageText, char * windowTitle) + : GUI_Window( NewWindowPosition(MESSAGE_BOX_WIDTH, MESSAGE_BOX_HEIGHT), windowTitle, WINDOW_STYLE_NORMAL) +{ + // TODO: Use static memory so we can display out of memory messages + SDL_Surface *pFont = FNT_Render(messageText, SDL_BLACK); + const int messageMargin = 8; + + int minTextWidth = pFont->w + (messageMargin * 2); + + // Resize the message box if the text won't fit + if (dimensions.width < minTextWidth) + Resize( { dimensions.top, dimensions.left, minTextWidth, dimensions.height } ); + + SDL_Rect destRect = { messageMargin, + messageMargin + SYSTEM_MENU_HEIGHT, + minTextWidth, + dimensions.height - (messageMargin * 2) }; + + SDL_BlitSurface(pFont, NULL, pSurface, &destRect); + SDL_FreeSurface(pFont); + + // Create a button control for an "OK" button + pControls[0] = new GUI_Button("OK", SYSTEM_MENU_CLOSE_BUTTON_ID, this); +} + diff --git a/MyOS_GUI_Shell/GUI_MessageBox.h b/MyOS_GUI_Shell/GUI_MessageBox.h new file mode 100644 index 0000000..ad59663 --- /dev/null +++ b/MyOS_GUI_Shell/GUI_MessageBox.h @@ -0,0 +1,20 @@ +#pragma once +#include "GUI_Window.h" + +// TEMP TEMP (Maybe) +#define MAX_MESSAGE_LENGTH 256 + +// TEMP TEMP +#define MESSAGE_BOX_X 250 +#define MESSAGE_BOX_Y 225 +#define MESSAGE_BOX_WIDTH 300 +#define MESSAGE_BOX_HEIGHT 150 + +class GUI_MessageBox : public GUI_Window +{ +public: + GUI_MessageBox(char *messageText, char *windowTitle); + +private: + char messageText[MAX_MESSAGE_LENGTH]; +}; diff --git a/MyOS_GUI_Shell/GUI_Object.cpp b/MyOS_GUI_Shell/GUI_Object.cpp new file mode 100644 index 0000000..071c090 --- /dev/null +++ b/MyOS_GUI_Shell/GUI_Object.cpp @@ -0,0 +1,93 @@ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "GUI_Object.h" + +GUI_Object::GUI_Object() +{ +} + + +GUI_Object::~GUI_Object() +{ +} + +void GUI_Object::GetRelativePoint(int & x, int & y) +{ + x -= dimensions.left; + y -= dimensions.top; +} + +bool GUI_Object::PointInBounds(int x, int y) +{ + if (x < dimensions.left + || y < dimensions.top + || x > dimensions.left + dimensions.width + || y > dimensions.top + dimensions.height) + return false; + + return true; +} + +void GUI_Object::DrawVerticalLine(SDL_Surface *pSurface, int x, int startY, int endY, SDL_Color lineColor) +{ + uint32_t color = SDL_MapRGB(pSurface->format, lineColor.r, lineColor.g, lineColor.b); + + for (int y = startY; y <= endY; ++y) + { + uint32_t *pPixels = (uint32_t *)(pSurface->pixels); + pPixels[x + y*pSurface->w] = color; + } +} + +void GUI_Object::DrawHorizontalLine(SDL_Surface *pSurface, int startX, int endX, int y, SDL_Color lineColor) +{ + uint32_t color = SDL_MapRGB(pSurface->format, lineColor.r, lineColor.g, lineColor.b); + + uint32_t *pPixels = (uint32_t *)(pSurface->pixels); + pPixels += startX + y * pSurface->w; + + SDL_memset4(pPixels, color, endX - startX); +} + +void GUI_Object::Draw3D_Box(SDL_Surface * pSurface, int x, int y, int width, int height) +{ + // Draw a white border on the top and left edges + DrawVerticalLine(pSurface, x, y, y + height - 1, SDL_WHITE); + DrawHorizontalLine(pSurface, x, x + width - 1, y, SDL_WHITE); + + // Draw a black border around the bottom and right edges + DrawVerticalLine(pSurface, x + width - 1, y, y + height - 1, SDL_BLACK); + DrawHorizontalLine(pSurface, x + 1, x + width - 1, y + height - 1, SDL_BLACK); +} + +void GUI_Object::Draw3D_InsetBox(SDL_Surface * pSurface, int x, int y, int width, int height) +{ + // Draw a white border on the top and left edges + DrawVerticalLine(pSurface, x, y, y + height - 1, SDL_BLACK); + DrawHorizontalLine(pSurface, x, x + width - 1, y, SDL_BLACK); + + // Draw a black border around the bottom and right edges + DrawVerticalLine(pSurface, x + width - 1, y, y + height - 1, SDL_WHITE); + DrawHorizontalLine(pSurface, x + 1, x + width - 1, y + height - 1, SDL_WHITE); +} + +void GUI_Object::DrawBox(SDL_Surface *pSurface, int x, int y, int width, int height, SDL_Color lineColor) +{ + DrawHorizontalLine(pSurface, x, x + width, y, lineColor); + DrawVerticalLine(pSurface, x + width, y, y + height, lineColor); + DrawHorizontalLine(pSurface, x, x + width, y + height, lineColor); + DrawVerticalLine(pSurface, x, y, y + height, lineColor); +} + +// Fill a surface with a color +void GUI_Object::FillSurface(SDL_Surface * pSurface, SDL_Color color) +{ + uint32_t col = SDL_MapRGB(pSurface->format, color.r, color.g, color.b); + SDL_FillRect(pSurface, NULL, col); +} + +#ifdef __cplusplus +}; +#endif /* __cplusplus */ \ No newline at end of file diff --git a/MyOS_GUI_Shell/GUI_Object.h b/MyOS_GUI_Shell/GUI_Object.h new file mode 100644 index 0000000..5d4de2d --- /dev/null +++ b/MyOS_GUI_Shell/GUI_Object.h @@ -0,0 +1,63 @@ +#pragma once +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "SDL_picofont.h" +#include "GUI_Rect.h" + +#ifdef __MYOS +#include "../MyOS_1/Libs/SDL/include/SDL.h" +#else +#include +#endif + +#define SYSTEM_MENU_HEIGHT 24 +#define SYSTEM_MENU_COLOR_R 110 +#define SYSTEM_MENU_COLOR_G 160 +#define SYSTEM_MENU_COLOR_B 255 + +#define SDL_R_MASK 0xFF000000 +#define SDL_G_MASK 0x00FF0000 +#define SDL_B_MASK 0x0000FF00 +#define SDL_A_MASK 0x000000FF + +const SDL_Color SDL_BLACK = { 0, 0, 0, 255 }; +const SDL_Color SDL_DARKGRAY = { 40, 40, 40, 255 }; +const uint32_t RGB_BLACK = 0x000000; +const SDL_Color SDL_WHITE = { 255, 255, 255, 255 }; +const SDL_Color SDL_DEFAULT_BUTTON_COLOR = { 200, 200, 200, 255 }; +const SDL_Color SDL_SYS_MENU_COLOR = { SYSTEM_MENU_COLOR_R, SYSTEM_MENU_COLOR_G, SYSTEM_MENU_COLOR_B, 255 }; + +class GUI_Object +{ +public: + GUI_Object(); + ~GUI_Object(); + + virtual void GetRelativePoint(int &x, int &y); + int GetRelX(int x) { return x - dimensions.left; } + int GetRelY(int y) { return y - dimensions.top; } + virtual void PaintToSurface(SDL_Surface *pTargetSurface) {} + virtual bool MouseOver(int relX, int relY) { return false; } + virtual void OnClick(int relX, int relY) {} + virtual void OnDrag(int startRelX, int startRelY, int relX, int relY) {} + virtual void OnMouseUp(int relX, int relY) {} + virtual bool PointInBounds(int x, int y); + +//protected: + GUI_Rect dimensions; + +protected: + void DrawVerticalLine(SDL_Surface *pSurface, int x, int startY, int endY, SDL_Color lineColor); + void DrawHorizontalLine(SDL_Surface *pSurface, int startX, int endX, int y, SDL_Color lineColor); + void Draw3D_Box(SDL_Surface *pSurface, int x, int y, int width, int height); + void Draw3D_InsetBox(SDL_Surface * pSurface, int x, int y, int width, int height); + void DrawBox(SDL_Surface *pSurface, int x, int y, int width, int height, SDL_Color lineColor); + void FillSurface(SDL_Surface *pSurface, SDL_Color color); +}; + +#ifdef __cplusplus +}; +#endif /* __cplusplus */ + diff --git a/MyOS_GUI_Shell/GUI_PopupMenu.cpp b/MyOS_GUI_Shell/GUI_PopupMenu.cpp new file mode 100644 index 0000000..efd1d7b --- /dev/null +++ b/MyOS_GUI_Shell/GUI_PopupMenu.cpp @@ -0,0 +1,168 @@ +#include "GUI_PopupMenu.h" +#include "GUI_Window.h" +#include "SDL_picofont.h" +#include "MyOS_GUI_Shell.h" +#include + +GUI_PopupMenu::GUI_PopupMenu(GUI_Window *pOwner, MENU_HANDLER menuHandler, POPUP_TYPE popupType) : GUI_Control(pOwner, -1) +{ + choices = 0; + handlerCallback = menuHandler; + shown = false; + this->popupType = popupType; + pSurface = NULL; +} + +GUI_PopupMenu::~GUI_PopupMenu() +{ +} + +void GUI_PopupMenu::AddMenuItem(char * choiceText, int choiceID) +{ + choiceIDs[choices] = choiceID; + memset(choiceStrings[choices], 0, MENU_MAX_CHOICE_LENGTH); + strncpy(choiceStrings[choices++], choiceText, MENU_MAX_CHOICE_LENGTH - 1); + + CreateSurface(); +} + +void GUI_PopupMenu::CreateSurface() +{ + if (pSurface) + { + SDL_FreeSurface; + pSurface = NULL; + } + + // determine maximum width of menu + int maxChoiceLength = 1; + for (int i = 0; i < choices; ++i) + { + if (strlen(choiceStrings[i]) > maxChoiceLength) + maxChoiceLength = strlen(choiceStrings[i]); + } + + int menuWidth = (maxChoiceLength * FNT_FONTWIDTH) + (2 * FNT_LEFTRIGHTMARGIN); + choiceHeight = FNT_FONTHEIGHT; + int menuHeight = (choices * choiceHeight) + ((choices - 1) * FNT_ROWSPACING) + (2 * FNT_TOPBOTTOMMARGIN); + + pSurface = SDL_CreateRGBSurface(0, + menuWidth, + menuHeight, + 32, + 0xFF000000, + 0x00FF0000, + 0x0000FF00, + 0x000000FF); + + dimensions.width = menuWidth; + dimensions.height = menuHeight; + + Draw(-1); +} + +void GUI_PopupMenu::Draw(int selectedChoice) +{ + // Fill the surface with the default color + FillSurface(pSurface, SDL_DEFAULT_BUTTON_COLOR); + + // Draw the choices to the surface + SDL_Rect textDest = { FNT_LEFTRIGHTMARGIN, FNT_TOPBOTTOMMARGIN, 0, 0 }; + + int selectionY = FNT_TOPBOTTOMMARGIN; + + for (int i = 0; i < choices; ++i) + { + SDL_Surface *pFont; + + if (i == selectedChoice) + { + // Draw a box for the selection + SDL_Rect selectedDim = { 1, selectionY, dimensions.width - 3, choiceHeight }; + SDL_FillRect(pSurface, &selectedDim, SDL_MapRGB(pSurface->format, + SDL_SYS_MENU_COLOR.r, + SDL_SYS_MENU_COLOR.g, + SDL_SYS_MENU_COLOR.b)); + // Draw the text in white + pFont = FNT_Render(choiceStrings[i], SDL_WHITE); + } + else + { + pFont = FNT_Render(choiceStrings[i], SDL_BLACK); + selectionY += choiceHeight + FNT_ROWSPACING; + } + + textDest.w = pFont->w; + textDest.h = pFont->h; + + SDL_BlitSurface(pFont, NULL, pSurface, &textDest); + + textDest.y += choiceHeight + FNT_ROWSPACING; + + SDL_FreeSurface(pFont); + } + + // Draw a border around the menu + Draw3D_Box(pSurface, 0, 0, dimensions.width, dimensions.height); +} + +bool GUI_PopupMenu::MouseOver(int relX, int relY) +{ + if (relX < 0 || relY < 0 || relX > dimensions.width || relY > dimensions.height) + { + MessageBox("Menu called with mouse out of position\n", "ERROR"); + return false; + } + + // Highlight the appropriate option + int heightPerOption = dimensions.height / choices; + int selection = relY / heightPerOption; + + Draw(selection); + + return true; +} + +void GUI_PopupMenu::OnClick(int relX, int relY) +{ + if (relX < 0 || relY < 0 || relX > dimensions.width || relY > dimensions.height) + { + MessageBox("Menu called with mouse out of position\n", "ERROR"); + return; + } + + // Get the selection + int heightPerOption = dimensions.height / choices; + int selection = relY / heightPerOption; + + // Call the callback with the ID for this selection + (*handlerCallback)(choiceIDs[selection]); + + shown = false; +} + +void GUI_PopupMenu::PaintToSurface(SDL_Surface * pTargetSurface) +{ + if (!shown) + return; + + SDL_BlitSurface(pSurface, NULL, pTargetSurface, dimensions.GetSDL_Rect()); +} + +void GUI_PopupMenu::RegisterMenuHandler(MENU_HANDLER handler) +{ + handlerCallback = handler; +} + +void GUI_PopupMenu::ShowMenu(SDL_Point origin) +{ + if (!pSurface) + return; + + dimensions.left = origin.x; + + if (popupType == ABOVE_AND_RIGHT_OF_ORIGIN) + dimensions.top = origin.y - dimensions.height; + + shown = true; +} diff --git a/MyOS_GUI_Shell/GUI_PopupMenu.h b/MyOS_GUI_Shell/GUI_PopupMenu.h new file mode 100644 index 0000000..9ae28ac --- /dev/null +++ b/MyOS_GUI_Shell/GUI_PopupMenu.h @@ -0,0 +1,50 @@ +#pragma once +#include "GUI_Control.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define MENU_MAX_CHOICES 16 +#define MENU_MAX_CHOICE_LENGTH 32 + +typedef enum POPUP_TYPE +{ + ABOVE_AND_RIGHT_OF_ORIGIN = 0 +}POPUP_TYPE; + +typedef void(*MENU_HANDLER)(int choiceID); + +class GUI_PopupMenu : + public GUI_Control +{ +public: + GUI_PopupMenu(GUI_Window *pOwner, MENU_HANDLER menuHandler, POPUP_TYPE popupType); + ~GUI_PopupMenu(); + + void AddMenuItem(char *Choice, int choiceID); + void CreateSurface(); + void Draw(int selectedChoice); + bool MouseOver(int relX, int relY); + void OnClick(int relX, int relY); + void PaintToSurface(SDL_Surface *pTargetSurface); + void RegisterMenuHandler(MENU_HANDLER handler); + void ShowMenu(SDL_Point origin); + + char choiceStrings[MENU_MAX_CHOICES][MENU_MAX_CHOICE_LENGTH]; + int choiceIDs[MENU_MAX_CHOICES]; + int choices; + MENU_HANDLER handlerCallback; + bool shown; + POPUP_TYPE popupType; + SDL_Surface *pSurface; + +protected: + int choiceHeight; +}; + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + diff --git a/MyOS_GUI_Shell/GUI_Rect.h b/MyOS_GUI_Shell/GUI_Rect.h new file mode 100644 index 0000000..07dfe8f --- /dev/null +++ b/MyOS_GUI_Shell/GUI_Rect.h @@ -0,0 +1,43 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifdef __MYOS +#include "../MyOS_1/Libs/SDL/include/SDL.h" +#else +#include +#endif + +typedef struct GUI_Rect +{ + int top, left; + int width, height; + + int GetBottom() + { + return top + height; + } + + int GetRight() + { + return left + width; + } + + SDL_Rect *GetSDL_Rect() + { + sdlRect.x = left; + sdlRect.y = top; + sdlRect.w = width; + sdlRect.h = height; + + return &sdlRect; + } + + SDL_Rect sdlRect; +} GUI_Rect; + +#ifdef __cplusplus +}; +#endif /* __cplusplus */ diff --git a/MyOS_GUI_Shell/GUI_RunWindow.cpp b/MyOS_GUI_Shell/GUI_RunWindow.cpp new file mode 100644 index 0000000..b14ada4 --- /dev/null +++ b/MyOS_GUI_Shell/GUI_RunWindow.cpp @@ -0,0 +1,44 @@ +#include "GUI_RunWindow.h" +#include "MyOS_GUI_Shell.h" +#include "GUI_Button.h" +#include "GUI_EditControl.h" + +// TODO: place window relative to bottom-left +GUI_RunWindow::GUI_RunWindow() : GUI_Window(0, 0, RUN_WINDOW_WIDTH, RUN_WINDOW_HEIGHT, "Run", WINDOW_STYLE_NORMAL) +{ + // Create a button control for an "OK" button + pControls[0] = new GUI_Button("OK", BUTTON_ID_OK, this); + + // Move button to bottom-right corner + pControls[0]->dimensions.left = dimensions.width - pControls[0]->dimensions.width - 2; + pControls[0]->dimensions.top = dimensions.height - pControls[0]->dimensions.height - 2; + + pControls[1] = new GUI_EditControl(RunWindowEditBoxDimensions, this, 1); + + focusedControlIndex = 1; + enterClicksButtonID = BUTTON_ID_OK; + + AddNewWindow(this); +} + + +GUI_RunWindow::~GUI_RunWindow() +{ + +} + +void GUI_RunWindow::ControlClicked(uint32_t controlID) +{ + // We only care about the OK button + if (controlID != BUTTON_ID_OK) + return; + + // Get the edit control + GUI_EditControl *pEdit = (GUI_EditControl*)pControls[1]; + + // Launch the requested app + Shell_Launch_App(pEdit->stringContents); + + // Tell the shell to destroy this window + Shell_Destroy_Window(this); +} diff --git a/MyOS_GUI_Shell/GUI_RunWindow.h b/MyOS_GUI_Shell/GUI_RunWindow.h new file mode 100644 index 0000000..3339663 --- /dev/null +++ b/MyOS_GUI_Shell/GUI_RunWindow.h @@ -0,0 +1,21 @@ +#pragma once +#include "GUI_Window.h" + + +#define RUN_WINDOW_Y_FROM_BOTTOM 200 +#define RUN_WINDOW_WIDTH 300 +#define RUN_WINDOW_HEIGHT 75 + +const int editHeight = FNT_FONTHEIGHT + (FNT_TOPBOTTOMMARGIN * 2); +const GUI_Rect RunWindowEditBoxDimensions = { RUN_WINDOW_HEIGHT - 10 - editHeight, 10, RUN_WINDOW_WIDTH - 50, editHeight }; + +class GUI_RunWindow : + public GUI_Window +{ +public: + GUI_RunWindow(); + ~GUI_RunWindow(); + + void ControlClicked(uint32_t controlID); +}; + diff --git a/MyOS_GUI_Shell/GUI_SystemMenuControl.cpp b/MyOS_GUI_Shell/GUI_SystemMenuControl.cpp new file mode 100644 index 0000000..d59de9b --- /dev/null +++ b/MyOS_GUI_Shell/GUI_SystemMenuControl.cpp @@ -0,0 +1,111 @@ +#include "GUI_SystemMenuControl.h" +#include "GUI_Window.h" + + +GUI_SystemMenuControl::GUI_SystemMenuControl(GUI_Window *pOwner) : GUI_Control(pOwner, SYSTEM_MENU_CONTROL_ID), + closeButton("X", SYSTEM_MENU_CLOSE_BUTTON_ID, pOwner) +{ + dimensions.top = 1; + dimensions.left = 1; + dimensions.width = pOwner->dimensions.width - 2; + dimensions.height = SYSTEM_MENU_HEIGHT; + + pSurface = NULL; + CreateSurface(); + + // Make close button red + closeButton.backgroundColor = { 255, 120, 120, 255 }; + + // Calculate close button dimensions + int margin = 4; + int boxHeight = SYSTEM_MENU_HEIGHT - margin + 1; + int boxWidth = boxHeight; + int boxTop = (margin / 2); + int boxLeft = dimensions.width - boxWidth - margin + 2; + SDL_Rect boxRect = { boxLeft, boxTop, boxWidth, boxHeight }; + + closeButton.Resize({ boxTop, boxLeft, boxWidth, boxHeight }); +} + +GUI_SystemMenuControl::~GUI_SystemMenuControl() +{ + SDL_FreeSurface(pSurface); +} + +void GUI_SystemMenuControl::CreateSurface() +{ + if (pSurface) + SDL_FreeSurface(pSurface); + + + pSurface = SDL_CreateRGBSurface(0, + dimensions.width, + dimensions.height, + 32, + SDL_R_MASK, + SDL_G_MASK, + SDL_B_MASK, + SDL_A_MASK); + + if (!pSurface) + { + //printf("Error! Couldn't allocate surface for system menu\n"); + return; + } + + // Fill the surface with the menu color + FillSurface(pSurface, SDL_SYS_MENU_COLOR); + + // Draw the title of the window + SDL_Surface *pFont = FNT_Render(pOwner->windowName, SDL_BLACK); + SDL_Rect destRect = { 8, 8, 8, 32 }; + SDL_BlitSurface(pFont, NULL, pSurface, &destRect); + SDL_FreeSurface(pFont); + + // Draw the system boxes + int margin = 4; + int boxHeight = SYSTEM_MENU_HEIGHT - margin + 1; + int boxWidth = boxHeight; + int boxTop = (margin / 2); + int boxLeft = dimensions.width - boxWidth - margin + 2; + SDL_Rect boxRect = { boxLeft, boxTop, boxWidth, boxHeight }; + + boxLeft = boxLeft - boxWidth - 2; + boxRect = { boxLeft, boxTop, boxWidth, boxHeight }; + SDL_FillRect(pSurface, &boxRect, SDL_MapRGB(pSurface->format, 205, 205, 205)); + Draw3D_Box(pSurface, boxLeft, boxTop, boxWidth, boxHeight); + + pFont = FNT_Render("[", SDL_BLACK); + boxRect.x += 4; + boxRect.y += 7; + SDL_BlitSurface(pFont, NULL, pSurface, &boxRect); + boxRect.x += 4; + SDL_FreeSurface(pFont); + pFont = FNT_Render("]", SDL_BLACK); + SDL_BlitSurface(pFont, NULL, pSurface, &boxRect); + SDL_FreeSurface(pFont); + + boxLeft = boxLeft - boxWidth - 2; + boxRect = { boxLeft, boxTop, boxWidth, boxHeight }; + SDL_FillRect(pSurface, &boxRect, SDL_MapRGB(pSurface->format, 205, 205, 205)); + Draw3D_Box(pSurface, boxLeft, boxTop, boxWidth, boxHeight); + + pFont = FNT_Render("_", SDL_BLACK); + boxRect.x += 7; + boxRect.y += 7; + SDL_BlitSurface(pFont, NULL, pSurface, &boxRect); + SDL_FreeSurface(pFont); +} + +void GUI_SystemMenuControl::OnClick(int relX, int relY) +{ + // Pass click on to button controls + if (closeButton.PointInBounds(relX, relY)) + closeButton.OnClick(closeButton.GetRelX(relX), closeButton.GetRelY(relY)); +} + +void GUI_SystemMenuControl::PaintToSurface(SDL_Surface * pTargetSurface) +{ + closeButton.PaintToSurface(pSurface); + SDL_BlitSurface(pSurface, NULL, pTargetSurface, dimensions.GetSDL_Rect()); +} diff --git a/MyOS_GUI_Shell/GUI_SystemMenuControl.h b/MyOS_GUI_Shell/GUI_SystemMenuControl.h new file mode 100644 index 0000000..7e44374 --- /dev/null +++ b/MyOS_GUI_Shell/GUI_SystemMenuControl.h @@ -0,0 +1,20 @@ +#pragma once +#include "GUI_Control.h" +#include "GUI_Button.h" + +class GUI_SystemMenuControl : + public GUI_Control +{ +public: + GUI_SystemMenuControl(GUI_Window *pOwner); + ~GUI_SystemMenuControl(); + + void CreateSurface(); + void OnClick(int relX, int relY); + void PaintToSurface(SDL_Surface *pTargetSurface); + + SDL_Surface *pSurface; + + GUI_Button closeButton; +}; + diff --git a/MyOS_GUI_Shell/GUI_Taskbar.cpp b/MyOS_GUI_Shell/GUI_Taskbar.cpp new file mode 100644 index 0000000..db8c037 --- /dev/null +++ b/MyOS_GUI_Shell/GUI_Taskbar.cpp @@ -0,0 +1,250 @@ +#ifndef __MYOS +#include +#else +#include "../MyOS_1/Interrupts/System_Calls.h" +#endif +#include "GUI_Taskbar.h" +#include "GUI_Button.h" +#include "GUI_RunWindow.h" + +void StartMenuHandler(int choice) +{ + switch (choice) + { + case 0: + new GUI_RunWindow(); + break; + case 1: + //MessageBox("Option 1 clicked", "Click"); + Shell_Launch_App("testapp1.exe"); + break; + case 2: + MessageBox("Option 2 clicked", "Click"); + break; + } +} + +GUI_Taskbar::GUI_Taskbar(uint32_t desktopWidth, uint32_t desktopHeight) : + GUI_Window(desktopHeight - GUI_TASKBAR_HEIGHT, 0, desktopWidth, GUI_TASKBAR_HEIGHT, "Taskbar", WINDOW_STYLE_NO_SYSTEM_MENU) +{ + // taskbar has no system menu or "standard window controls + + backgroundColor = GUI_TASKBAR_COLOR; + + // Draw the background + FillSurface(backgroundColor); + + // Draw a 3d border + Draw3D_Box(pSurface, 0, 0, dimensions.width, dimensions.height); + + // Add a "Start" button control + pControls[0] = new GUI_Button("MyOS", GUI_TASKBAR_START_ID, this); + pControls[0]->dimensions.left = GUI_TASKBAR_BUTTON_MARGINS; + + // Create the start menu + pStartMenu = new GUI_PopupMenu(this, StartMenuHandler, ABOVE_AND_RIGHT_OF_ORIGIN); + + pStartMenu->AddMenuItem("Option 1", 1); + pStartMenu->AddMenuItem("Option 2", 2); + pStartMenu->AddMenuItem("Run", 0); + + windowButtons = 0; + pActiveWindowButton = NULL; +} + + +GUI_Taskbar::~GUI_Taskbar() +{ +} + +void GUI_Taskbar::AddWindow(uint32_t windowID, GUI_Window *pWindow) +{ + // Add button for window + + // Find an index for the window + int i; + for (i = 1; i < MAX_WINDOW_CONTROLS; ++i) + { + if (!pControls[i]) + break; + } + + if (i == MAX_WINDOW_CONTROLS) + { + printf("Error: Too many windows to add one to taskbar!\n"); + return; + } + + // Get the x position for the new window + int x = pControls[i - 1]->dimensions.left + pControls[i - 1]->dimensions.width + GUI_TASKBAR_BUTTON_MARGINS; + ++windowButtons; + // Set placement of new button + GUI_Rect buttonPlacement = { GUI_TASKBAR_BUTTON_MARGINS, + x, + GUI_TASKBAR_BUTTON_MAX_WIDTH, + GUI_TASKBAR_HEIGHT - (GUI_TASKBAR_BUTTON_MARGINS * 2) }; + + pControls[i] = new GUI_TaskbarButton(pWindow->windowName, windowID, this, buttonPlacement); + + // TODO: Don't calculate the position and size of button above just to redo it here: + ButtonsChanged(); + + WindowActivated(windowID); +} + +// TODO: Don't allow too many buttons / allow for multiple "panes" of buttons +void GUI_Taskbar::ButtonsChanged() +{ + //printf("%d buttons\n", windowButtons); + + // We need to redraw the taskbar background to erase the old buttons + FillSurface(backgroundColor); + + // Draw a 3d border + Draw3D_Box(pSurface, 0, 0, dimensions.width, dimensions.height); + + if (!windowButtons) + return; + + // Recalculate size and positions of buttons + + // Determine maximum size of each button based on how many buttons there are and how wide the taskbar is + + // We'll start drawing after the Start button + int leftX = pControls[0]->dimensions.left + pControls[0]->dimensions.width + GUI_TASKBAR_BUTTON_MARGINS; + + int width = dimensions.width - GUI_TASKBAR_BUTTON_MARGINS - leftX; + + int pixelsPerButton = width / windowButtons; + pixelsPerButton -= GUI_TASKBAR_BUTTON_MARGINS; + + if (pixelsPerButton > GUI_TASKBAR_BUTTON_MAX_WIDTH) + pixelsPerButton = GUI_TASKBAR_BUTTON_MAX_WIDTH; + + // Assign a new size and position to each button after the start button + for (int i = 1; i < MAX_WINDOW_CONTROLS; ++i) + { + if (!pControls[i]) + continue; + + pControls[i]->dimensions.left = leftX; + pControls[i]->dimensions.width = pixelsPerButton; + pControls[i]->Resize(pControls[i]->dimensions); + + leftX += pixelsPerButton + GUI_TASKBAR_BUTTON_MARGINS; + } +} + +void GUI_Taskbar::ControlClicked(uint32_t controlID) +{ + if (controlID != GUI_TASKBAR_START_ID) + { + pStartMenu->shown = false; + + if (pActiveWindowButton) + pActiveWindowButton->UnClick(); + + BringWindowID_ToFront(controlID); + // Find the control ID + for (int i = 0; i < MAX_WINDOW_CONTROLS; ++i) + { + pActiveWindowButton = (GUI_TaskbarButton *)pClickedControl; + return; + } + } + else + { + // start clicked + if (!pStartMenu->shown) + pStartMenu->ShowMenu({ GUI_TASKBAR_BUTTON_MARGINS, dimensions.top }); + else + pStartMenu->shown = false; + } +} + +void GUI_Taskbar::OnDrag(int startRelX, int startRelY, int relX, int relY) +{ + // Don't allow the taskbar itself to be dragged +} + +void GUI_Taskbar::PaintToSurface(SDL_Surface * pTargetSurface) +{ + GUI_Window::PaintToSurface(pTargetSurface); + + pStartMenu->PaintToSurface(pTargetSurface); +} + +// TODO: For now we assume the taskbar is always in the same position +/*bool GUI_Taskbar::PointInBounds(int x, int y) +{ + if (GUI_Object::PointInBounds(x, y)) + return true; + + // Check start menu + if (pStartMenu->shown && pStartMenu->PointInBounds(x, y)) + return true; + + return false; +}*/ + +void GUI_Taskbar::RemoveWindow(uint32_t windowID) +{ + // Find the control ID + for (int i = 1; i < MAX_WINDOW_CONTROLS; ++i) + { + if (pControls[i] && pControls[i]->controlID == windowID) + { + GUI_TaskbarButton *pButton = (GUI_TaskbarButton *)pControls[i]; + + // Remove all references to pButton + pControls[i] = NULL; + if (pActiveWindowButton == pButton) + pActiveWindowButton = NULL; + if (pClickedControl == pButton) + pClickedControl = NULL; + + delete pButton; + + --windowButtons; + + ButtonsChanged(); + + break; + } + } +} + +void GUI_Taskbar::WindowActivated(uint32_t windowID) +{ + // Find the control ID + for (int i = 1; i < MAX_WINDOW_CONTROLS; ++i) + { + if (pControls[i] && pControls[i]->controlID == windowID) + { + // if there's an active window button that's not the same button, de-highlight it + if (pActiveWindowButton && pActiveWindowButton != (GUI_TaskbarButton *)pControls[i]) + pActiveWindowButton->UnClick(); + + // highlight the button for the new window + pActiveWindowButton = (GUI_TaskbarButton *)pControls[i]; + pActiveWindowButton->Highlight(); + + return; + } + } +} + +void GUI_TaskbarButton::Highlight() +{ + Draw3D_InsetBox(pSurface, 0, 0, dimensions.width, dimensions.height); +} + +void GUI_TaskbarButton::OnMouseUp(int relX, int relY) +{ + // Clicked taskbar windows should stay active +} + +void GUI_TaskbarButton::UnClick() +{ + Draw3D_Box(pSurface, 0, 0, dimensions.width, dimensions.height); +} diff --git a/MyOS_GUI_Shell/GUI_Taskbar.h b/MyOS_GUI_Shell/GUI_Taskbar.h new file mode 100644 index 0000000..fd969a3 --- /dev/null +++ b/MyOS_GUI_Shell/GUI_Taskbar.h @@ -0,0 +1,47 @@ +#pragma once +#include "MyOS_GUI_Shell.h" +#include "GUI_Window.h" +#include "GUI_Button.h" +#include "GUI_PopupMenu.h" + +#define GUI_TASKBAR_HEIGHT 32 +#define GUI_TASKBAR_BUTTON_MARGINS 4 +#define GUI_TASKBAR_BUTTON_MAX_WIDTH 100 +//#define GUI_TASKBAR_START_WIDTH 50 +#define GUI_TASKBAR_COLOR { 200, 200, 200 } +#define GUI_TASKBAR_START_ID 0xFFFFFFFF + +class GUI_TaskbarButton : public GUI_Button +{ +public: + GUI_TaskbarButton(const char *buttonText, uint32_t controlID, GUI_Window *pOwner, GUI_Rect dimensions) + : GUI_Button(buttonText, controlID, pOwner, dimensions) {} + void Highlight(); + virtual void OnMouseUp(int relX, int relY); + void UnClick(); +}; + + +// Taskbar is created by the GUI Shell application and ties into it +class GUI_Taskbar : + public GUI_Window +{ +public: + GUI_Taskbar(uint32_t desktopWidth, uint32_t desktopHeight); + ~GUI_Taskbar(); + + void AddWindow(uint32_t windowID, GUI_Window *pWindow); + void ButtonsChanged(); + void ControlClicked(uint32_t controlID); + void OnDrag(int startRelX, int startRelY, int relX, int relY); + void PaintToSurface(SDL_Surface *pTargetSurface); + //bool PointInBounds(int x, int y); + void RemoveWindow(uint32_t windowID); + void WindowActivated(uint32_t windowID); + GUI_PopupMenu *pStartMenu; + +protected: + int windowButtons; + GUI_TaskbarButton *pActiveWindowButton; +}; + diff --git a/MyOS_GUI_Shell/GUI_TerminalWindow.cpp b/MyOS_GUI_Shell/GUI_TerminalWindow.cpp new file mode 100644 index 0000000..654c768 --- /dev/null +++ b/MyOS_GUI_Shell/GUI_TerminalWindow.cpp @@ -0,0 +1,188 @@ +#include "GUI_TerminalWindow.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifdef __MYOS +#include "../MyOS_1/Interrupts/System_Calls.h" +#endif + +#include + +GUI_TerminalWindow::GUI_TerminalWindow(const char *name) + : GUI_Window(NewWindowPosition(GUI_TERMINAL_DEFAULT_WIDTH, GUI_TERMINAL_DEFAULT_HEIGHT), name, WINDOW_STYLE_NORMAL) +{ + // TODO: Check for out of memory error + characterBuffer = new char(characterBufferSize); + + foregroundTextColor = SDL_MapRGB(pSurface->format, 255, 255, 255); + + // Set a dark gray background + backgroundTextColor = SDL_MapRGB(pSurface->format, 40, 40, 40); + backgroundColor = SDL_DARKGRAY; + + row = 0; + column = 0; + maxColumns = GUI_TERMINAL_DEFAULT_COLUMNS; + maxRows = GUI_TERMINAL_DEFAULT_ROWS; + + DrawWindow(); +} + +GUI_TerminalWindow::~GUI_TerminalWindow() +{ + delete characterBuffer; +} + +void GUI_TerminalWindow::PutEntryAt(char c, size_t x, size_t y) +{ + char str[2] = { 0 }; + + FNT_xy currentPos; + + currentPos.y = y * (FNT_FONTHEIGHT + FNT_ROWSPACING) + SYSTEM_MENU_HEIGHT; + currentPos.x = x * FNT_FONTWIDTH + 1; + + str[0] = c; + FNT_RenderMax(str, 1, currentPos); +} + +void GUI_TerminalWindow::PutChar(char c) +{ + if (c == '\n')//|| c == '\r') + { + column = 0; + row++; + } + + // Handle scrolling + if (row >= maxRows) + ScrollUp(); + + if (c != '\n' && c != '\r') + { + PutEntryAt(c, column, row); + + if (++column >= maxColumns) + { + column = 0; + ++row; + } + } + + // TODO: Update cursor +} + +void GUI_TerminalWindow::ScrollUp(void) +{ + column = 0; + row = maxRows - 1; + + /*if (backgroundImage && foregroundText) + { + // Read the contents of the foreground text, but don't copy the first line + uint32_t bufferSize = graphicsWidth * graphicsHeight * (graphicsBpp / 8); + uint32_t lineOffset = graphicsWidth * (FNT_FONTHEIGHT + FNT_TOPBOTTOMMARGIN) * (graphicsBpp / 8); + memcpy(scrollBuffer, (void *)((uint32_t)foregroundText + lineOffset), bufferSize - lineOffset); + + // Clear the bottom two rows of the foreground + uint32_t firstLine = graphicalRow * (FNT_FONTHEIGHT + FNT_TOPBOTTOMMARGIN); + uint32_t lines = (FNT_FONTHEIGHT + FNT_TOPBOTTOMMARGIN) * 2; + GraphicsClearLines(firstLine, lines, graphicalBackground, (uint32_t *)foregroundText); + + //GraphicsFillScreen(graphicalBackground.red, graphicalBackground.green, graphicalBackground.blue); + + // Copy the buffer back to the screen + memcpy(foregroundText, scrollBuffer, bufferSize - lineOffset); + + GraphicsBlit(0, 0, backgroundImage, graphicsWidth, graphicsHeight); + GraphicsBlitWithAlpha(0, 0, foregroundText, graphicsWidth, graphicsHeight); + } + else + { + // Read the contents of the screen, but don't copy the first line + uint32_t bufferSize = graphicsWidth * graphicsHeight * (graphicsBpp / 8); + uint32_t lineOffset = graphicsWidth * (FNT_FONTHEIGHT + FNT_TOPBOTTOMMARGIN) * (graphicsBpp / 8); + memcpy(scrollBuffer, (void *)((uint32_t)linearFrameBuffer + lineOffset), bufferSize - lineOffset); + + // Clear the bottom two rows of the screen (or the entire screen) + uint32_t firstLine = graphicalRow * (FNT_FONTHEIGHT + FNT_TOPBOTTOMMARGIN); + uint32_t lines = (FNT_FONTHEIGHT + FNT_TOPBOTTOMMARGIN) * 2; + GraphicsClearLines(firstLine, lines, graphicalBackground, linearFrameBuffer); + + //GraphicsFillScreen(graphicalBackground.red, graphicalBackground.green, graphicalBackground.blue); + + // Copy the buffer back to the screen + memcpy(linearFrameBuffer, scrollBuffer, bufferSize - lineOffset); + }*/ +} + +void GUI_TerminalWindow::SendWindowText(const char * text) +{ + size_t len = strlen(text); + for (size_t i = 0; i < len; ++i) + PutChar(text[i]); +} + +/* Code taken from picofont.c by Fredrik Hultin + http://nurd.se/~noname/sdl_picofont + modified for MyOS: +*/ + +FNT_xy GUI_TerminalWindow::FNT_Generate(const char* text, unsigned int len, unsigned int w, uint32_t *pixels, FNT_xy position) +{ + unsigned int i, x, y, col, row, stop; + unsigned char *fnt, chr; + FNT_xy xy; + + fnt = FNT_GetFont(); + + col = row = stop = 0; + xy.x = position.x + FNT_LEFTRIGHTMARGIN; + xy.y = position.y + FNT_TOPBOTTOMMARGIN; + + for (i = 0; i < len && text[i] != '\0'; i++) + { + col++; + chr = text[i]; + + if (stop) { + break; + } + + if (chr == 0 || w == 0) + continue; + + // TODO: print border based on FNT_ROWSPACING with background color + for (y = 0; y < FNT_FONTHEIGHT; y++) + { + for (x = 0; x < FNT_FONTWIDTH; x++) + { + if (fnt[text[i] * FNT_FONTHEIGHT + y] >> (7 - x) & 1) + pixels[((col - 1) * FNT_FONTWIDTH) + x + xy.x + (xy.y + y + row * (FNT_FONTHEIGHT + FNT_ROWSPACING)) * w] = foregroundTextColor; + else + { + //pixels[((col - 1) * FNT_FONTWIDTH) + x + xy.x + (xy.y + y + row * (FNT_FONTHEIGHT + FNT_ROWSPACING)) * w] = backgroundTextColor; + } + } + } + } + + return xy; +} + +void GUI_TerminalWindow::FNT_Render(const char* text, FNT_xy position) +{ + FNT_RenderMax(text, strlen(text), position); +} + +void GUI_TerminalWindow::FNT_RenderMax(const char* text, unsigned int len, FNT_xy position) +{ + FNT_Generate(text, len, pSurface->w, (uint32_t *)pSurface->pixels, position); +} +// End of picofont functions + +#ifdef __cplusplus +} +#endif /* __cplusplus */ \ No newline at end of file diff --git a/MyOS_GUI_Shell/GUI_TerminalWindow.h b/MyOS_GUI_Shell/GUI_TerminalWindow.h new file mode 100644 index 0000000..e59bbee --- /dev/null +++ b/MyOS_GUI_Shell/GUI_TerminalWindow.h @@ -0,0 +1,52 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "GUI_Window.h" +#include "MyOS_GUI_Shell.h" + +#define GUI_TERMINAL_DEFAULT_BUFFER_SIZE 4096 +#define GUI_TERMINAL_DEFAULT_TEXT_COLOR {255, 255, 255, 255} +#define GUI_TERMINAL_DEFAULT_BG_COLOR {40, 40, 40, 255} + + +#define GUI_TERMINAL_DEFAULT_COLUMNS 80 +#define GUI_TERMINAL_DEFAULT_ROWS 60 +#define GUI_TERMINAL_DEFAULT_WIDTH ((GUI_TERMINAL_DEFAULT_COLUMNS + 1) * FNT_FONTWIDTH) +#define GUI_TERMINAL_DEFAULT_HEIGHT (GUI_TERMINAL_DEFAULT_ROWS * (FNT_FONTHEIGHT + FNT_ROWSPACING) + 2) + + +class GUI_TerminalWindow : + public GUI_Window +{ +public: + GUI_TerminalWindow(const char *name); + ~GUI_TerminalWindow(); + + void ScrollUp(); + void SendWindowText(const char *text); + void PutChar(char c); + void PutEntryAt(char c, size_t x, size_t y); + + // Font functions from picofont by Fredrik Hultin + FNT_xy FNT_Generate(const char* text, unsigned int len, unsigned int w, uint32_t *pixels, FNT_xy position); + void FNT_Render(const char* text, FNT_xy position); + void FNT_RenderMax(const char* text, unsigned int len, FNT_xy position); + +private: + uint32_t foregroundTextColor; + uint32_t backgroundTextColor; + uint32_t characterBufferSize; + char *characterBuffer; + //FNT_xy currentPos; + int column; + int row; + int maxColumns; + int maxRows; +}; + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/MyOS_GUI_Shell/GUI_Window.cpp b/MyOS_GUI_Shell/GUI_Window.cpp new file mode 100644 index 0000000..c7c2c26 --- /dev/null +++ b/MyOS_GUI_Shell/GUI_Window.cpp @@ -0,0 +1,218 @@ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "GUI_Window.h" +#include "MyOS_GUI_Shell.h" +#include "GUI_SystemMenuControl.h" + +#ifdef __MYOS +#include "../MyOS_1/Interrupts/System_Calls.h" +#else +#include +#endif + + +GUI_Window::GUI_Window(GUI_Rect size, const char *name, int style) : GUI_Window(size.top, size.left, size.width, size.height, name, style) +{ +} + +GUI_Window::GUI_Window(int top, int left, int width, int height, const char *name, int windowStyle) +{ + dimensions.top = top; + dimensions.left = left; + dimensions.width = width; + dimensions.height = height; + + SDL_strlcpy(windowName, name, MAX_WINDOW_NAME_LENGTH); + CreateSurface(); + + style = windowStyle; + + for (int i = 0; i < MAX_WINDOW_CONTROLS; ++i) + pControls[i] = NULL; + + // Should we create a system menu control? + if (!(style & WINDOW_STYLE_NO_SYSTEM_MENU)) + { + // create system menu + pControls[MAX_WINDOW_CONTROLS - 1] = new GUI_SystemMenuControl(this); + } + + pClickedControl = NULL; + focusedControlIndex = -1; + enterClicksButtonID = -1; +} + +GUI_Window::~GUI_Window() +{ + if (!pSurface) + SDL_FreeSurface(pSurface); +} + +void GUI_Window::CreateSurface() +{ + pSurface = SDL_CreateRGBSurface(0, // flags (unused) + dimensions.width, + dimensions.height, + 32, // bit-depth + 0, // Rmask (default) + 0, // Gmask (default) + 0, // Bmask (default), + 0); // Amask*/ + + if (!pSurface) + return; + // printf("Error! Couldn't create RGB surface for window!\n"); + + backgroundColor = { 205, 205, 205, 255 }; + + DrawWindow(); +} + +void GUI_Window::SetFocus(int controlID) +{ + // Ignore if this control alread has the focus + if (focusedControlIndex >= 0 && pControls[focusedControlIndex]->controlID == controlID) + return; + + // Unfocus the previously focused control + if (focusedControlIndex >= 0) + pControls[focusedControlIndex]->LoseFocus(); + + // Find the control with the given ID and focus it + for (int i = 0; i < MAX_WINDOW_CONTROLS; ++i) + { + if (pControls[i] && pControls[i]->controlID == controlID) + { + focusedControlIndex = i; + return; + } + } + + MessageBox("Couldn't find a matching control for SetFocus", "ERROR"); +} + +void GUI_Window::PaintToSurface(SDL_Surface *pTargetSurface) +{ + // TEMP + for (int i = 0; i < MAX_WINDOW_CONTROLS; ++i) + { + if (pControls[i]) + pControls[i]->PaintToSurface(pSurface); + } + + SDL_BlitSurface(pSurface, NULL, pTargetSurface, dimensions.GetSDL_Rect()); +} + +void GUI_Window::UpdateCursor() +{ + if (focusedControlIndex < 0) + return; + + pControls[focusedControlIndex]->UpdateCursor(); +} + +void GUI_Window::ControlClicked(uint32_t controlID) +{ + if (controlID == SYSTEM_MENU_CLOSE_BUTTON_ID) + { + // TODO: Send exit signal / message to any associated app + + // Tell the shell to destroy this window + Shell_Destroy_Window(this); + } +} + +// Fill the entire window with a color +void GUI_Window::FillSurface(SDL_Color color) +{ + uint32_t col = SDL_MapRGB(pSurface->format, color.r, color.g, color.b); + SDL_FillRect(pSurface, NULL, col); +} + +void GUI_Window::LoseFocus() +{ + if (focusedControlIndex < 0) + return; + + pControls[focusedControlIndex]->LoseFocus(); +} + +void GUI_Window::OnClick(int relX, int relY) +{ + if (relX < 0 || relY < 0 || relX > dimensions.width || relY > dimensions.height) + { + printf("Window OnClick() called outside of range!\n"); + return; + } + + // Pass the click onto each control + for (int i = 0; i < MAX_WINDOW_CONTROLS; ++i) + { + if (pControls[i] && pControls[i]->PointInBounds(relX, relY)) + { + pClickedControl = pControls[i]; + pControls[i]->OnClick(relX - pControls[i]->dimensions.left, relY - pControls[i]->dimensions.top); + } + } +} + +void GUI_Window::OnDrag(int startRelX, int startRelY, int relX, int relY) +{ + dimensions.left += relX - startRelX; + dimensions.top += relY - startRelY; +} + +void GUI_Window::OnMouseUp(int relX, int relY) +{ + if (pClickedControl) + pClickedControl->OnMouseUp(relX - pClickedControl->dimensions.left, relY - pClickedControl->dimensions.top); +} + +void GUI_Window::Resize(GUI_Rect newDimensions) +{ + SDL_FreeSurface(pSurface); + + dimensions = newDimensions; + + CreateSurface(); + + DrawWindow(); +} + +void GUI_Window::SetBackgroundColor(SDL_Color color) +{ + backgroundColor = color; + DrawWindow(); +} + +void GUI_Window::SendChar(char c) +{ + if (c == SDLK_RETURN && enterClicksButtonID != -1) + { + ControlClicked(enterClicksButtonID); + return; + } + + if (focusedControlIndex < 0) + return; + + pControls[focusedControlIndex]->SendChar(c); +} + +void GUI_Window::DrawWindow() +{ + // Draw the background + FillSurface(backgroundColor); + + // Draw the system menu at the top + //DrawSystemMenu(pSurface, windowName); + + // Draw a black outline around the background + Draw3D_Box(pSurface, 0, 0, dimensions.width, dimensions.height); +} + +#ifdef __cplusplus +}; +#endif /* __cplusplus */ \ No newline at end of file diff --git a/MyOS_GUI_Shell/GUI_Window.h b/MyOS_GUI_Shell/GUI_Window.h new file mode 100644 index 0000000..04bd56f --- /dev/null +++ b/MyOS_GUI_Shell/GUI_Window.h @@ -0,0 +1,70 @@ +#pragma once +#include "GUI_Object.h" +#include "GUI_Rect.h" +#include "GUI_Control.h" +#include "SDL_picofont.h" + +#define MAX_WINDOW_NAME_LENGTH 64 +#define SYSTEM_MENU_CLOSE_BUTTON_ID (uint32_t)-1 +#define BUTTON_ID_OK (uint32_t)-2 +#define SYSTEM_MENU_CONTROL_ID (uint32_t)-3 +#define MAX_WINDOW_CONTROLS 24 /* TEMP */ + +#define WINDOW_STYLE_NORMAL 0 +#define WINDOW_STYLE_NO_SYSTEM_MENU 1 + +class GUI_Control; + +class GUI_Window : public GUI_Object +{ +public: + GUI_Window(GUI_Rect size, const char *name, int windowStyle); + + GUI_Window(int top, int left, int width, int height, const char *name, int windowStyle); + + ~GUI_Window(); + + virtual void ControlClicked(uint32_t controlID); + + void DrawWindow(); + + void FillSurface(SDL_Color color); + + virtual void LoseFocus(); + + void OnClick(int relX, int relY); + + void OnDrag(int startRelX, int startRelY, int relX, int relY); + + void OnMouseUp(int relX, int relY); + + virtual void Resize(GUI_Rect newDimensions); + + void SetBackgroundColor(SDL_Color color); + + void SendChar(char c); + + virtual void SendWindowText(const char *text) + { + (void)text; // text sent to GUI_Window base class is ignored + } + + void SetFocus(int controlID); + + SDL_Surface *GetSurface() { return pSurface; } + + void PaintToSurface(SDL_Surface *pTargetSurface); + + void UpdateCursor(); + + SDL_Surface *pSurface; + GUI_Control *pClickedControl; + char windowName[MAX_WINDOW_NAME_LENGTH]; +protected: + void GUI_Window::CreateSurface(); + SDL_Color backgroundColor; + GUI_Control *pControls[MAX_WINDOW_CONTROLS]; + int focusedControlIndex; + int enterClicksButtonID; // There's probably a better way to do this + int style; +}; diff --git a/MyOS_GUI_Shell/MyOS_GUI_Shell.cpp b/MyOS_GUI_Shell/MyOS_GUI_Shell.cpp new file mode 100644 index 0000000..d6f8362 --- /dev/null +++ b/MyOS_GUI_Shell/MyOS_GUI_Shell.cpp @@ -0,0 +1,724 @@ +// TestApp1.cpp : A super-simple application for testing with MyOS +// + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +//#include "stdafx.h" +#ifndef WIN32 +#include "../MyOS_1/Console_VGA.h" +#include "../MyOS_1/Interrupts/System_Calls.h" +#include "../MyOS_1/printf.h" +//#undef _MSVC_VER +#undef _WIN32 +//#define HAVE_LIBC 0 +#define SDL_ATOMIC_DISABLED 1 +//#define SDL_EVENTS_DISABLED 0 +//#define SDL_TIMERS_DISABLED 0 +#define HAVE_MALLOC 1 +#else +#include +#endif + +#define SDL_MAIN_HANDLED 1 + +#include "../MyOS_1/Libs/SDL/include/SDL.h" +#include "../MyOS_1/Libs/SDL/include/SDL_video.h" +#include "../MyOS_1/Graphics/Cursor.h" + +#include "GUI_Window.h" +#include "GUI_MessageBox.h" +#include "GUI_Taskbar.h" +#include "GUI_Kernel_Shell.h" +#include "GUI_TerminalWindow.h" + +#define MAX_GUI_WINDOWS 256 /*TEMP HACK*/ +GUI_Window *windowList[MAX_GUI_WINDOWS] = { NULL }; +// This would be something like a std::map when we have that +uint32_t windowIDs[MAX_GUI_WINDOWS] = { 0 }; + +#define DEFAULT_WINDOW_HEIGHT 320 +#define DEFAULT_WINDOW_WIDTH 480 + +int nextX = 11; +int nextY = 11; +#define MAX_WINDOW_X 500 +#define MAX_WINDOW_Y 400 +#define WINDOW_X_INC 21 +#define WINDOW_Y_INC 21 + +// probably TEMP: +int bgRed = 0; +int bgGreen = 40; +int bgBlue = 128; +#define BG_RED_INC 22 +#define BG_GREEN_INC 31 +#define BG_BLUE_INC 42 +GUI_Taskbar *pTaskbar; +#define DELETION_QUEUE_SIZE 16 +GUI_Window *pDeletionQueue[DELETION_QUEUE_SIZE]; // UGLY HACK +int nextDeletionQueueIndex = 0; +int lastWindowID = WINDOW_ID_IS_NOT_PID; + +#define CURSOR_X 16 +#define CURSOR_Y 16 + +SDL_Rect ball = { 0, 0, 20, 20 }; +SDL_Point velocity = { 2, 2 }; + +SDL_Rect cursorRect = { 0, 0, CURSOR_X, CURSOR_Y }; +SDL_Point oldMousePos; + +GUI_Window *pDraggedWindow = NULL; + +// Keep track of a stack of windows +// (Not a stack in the computer science sense, but in the sense that windows can overlap other windows) +GUI_WINDOW_STACK_ENTRY windowStack[MAX_GUI_WINDOWS] = { 0, 0, 0 }; +GUI_WINDOW_STACK_ENTRY *pStackTop = NULL;// &windowStack[0]; + +uint32_t previousTime; // system time of last loop iteration in milliseconds +#define CURSOR_BLINK_MS 450 +int timeBeforeCursorBlink = CURSOR_BLINK_MS; + +// TODO: implement SDL_GetTicks +#ifndef timeGetUptimeMS +#define timeGetUptimeMS SDL_GetTicks +#endif + +// Search the stack of windows, top to buttom to see whic window the mouse is hovering over +GUI_WINDOW_STACK_ENTRY *FindWindowFromPoint(int x, int y) +{ + GUI_WINDOW_STACK_ENTRY *pCurrent = pStackTop; + + while (pCurrent && pCurrent->pWindow) + { + if (pCurrent->pWindow->PointInBounds(x, y)) + return pCurrent; + + pCurrent = pCurrent->pUnderneath; + } + + return NULL; +} + +void RemoveWindowFromStack(GUI_WINDOW_STACK_ENTRY *pEntry) +{ + // bridge the hole left by this window being removed + if (pEntry->pAbove) + pEntry->pAbove->pUnderneath = pEntry->pUnderneath; + + if (pEntry->pUnderneath) + pEntry->pUnderneath->pAbove = pEntry->pAbove; + + // Check if this window was on top + if (pStackTop == pEntry) + pStackTop = pEntry->pUnderneath; +} + +void AddNewWindow(GUI_Window * pWindow) +{ + // find the first unused entry in the windowList + for (int i = 0; i < MAX_GUI_WINDOWS; ++i) + { + if (!windowList[i]) + { + windowList[i] = pWindow; + windowIDs[i] = ++lastWindowID; + + AddWindowToStack(windowList[i], &windowStack[i]); + + pTaskbar->AddWindow(lastWindowID, windowList[i]); + + return; + } + } + + printf("ERROR: Couldn't find any free window slots!\n"); +} + +// TODO: Not sure I like this / not sure windowID helps anything vs using pointers directly +void BringWindowID_ToFront(uint32_t windowID) +{ + // find window pointer associated with window ID + for (int i = 0; i < MAX_GUI_WINDOWS; ++i) + { + if (windowIDs[i] == windowID) + { + GUI_Window *pWindow = windowList[i]; + + // find stack entry associated with window ID + for (int j = 0; j < MAX_GUI_WINDOWS; ++j) + { + if (windowStack[j].pWindow == pWindow) + { + BringWindowToFront(&windowStack[j]); + return; + } + } + + printf("Couldn't find stack entry associated with window pointer!!\n"); + return; + } + } + + printf("Couldn't find window matching Window ID!\n"); +} + +void BringWindowToFront(GUI_WINDOW_STACK_ENTRY *pEntry) +{ + if (pStackTop == pEntry) + return; + + pStackTop->pWindow->LoseFocus(); + + // bridge the hole left by this window + RemoveWindowFromStack(pEntry); + + // previous stack top will be below this entry + pStackTop->pAbove = pEntry; + pEntry->pUnderneath = pStackTop; + pEntry->pAbove = NULL; + + pStackTop = pEntry; +} + +GUI_WINDOW_STACK_ENTRY *GetBottomWindow() +{ + if (!pStackTop) + return NULL; + + GUI_WINDOW_STACK_ENTRY *pCurrent = pStackTop; + + while (pCurrent->pUnderneath) + pCurrent = pCurrent->pUnderneath; + + return pCurrent; +} + +GUI_Window *GetWindowFromID(uint32_t uniqueID) +{ + for (int i = 0; i < MAX_GUI_WINDOWS; ++i) + { + if (windowIDs[i] == uniqueID) + return windowList[i]; + } + + return NULL; +} + +void AddWindowToStack(GUI_Window *window, GUI_WINDOW_STACK_ENTRY *pStackEntry) +{ + // Put this window in a stack entry and make it the topmost window + pStackEntry->pWindow = window; + pStackEntry->pAbove = NULL; + + if (pStackTop && pStackTop->pWindow) + { + pStackEntry->pUnderneath = pStackTop; + pStackTop->pAbove = pStackEntry; + pStackTop->pWindow->LoseFocus(); + } + else + pStackEntry->pUnderneath = NULL; + + pStackTop = pStackEntry; +} + +// This would probably be called with a process' PID +GUI_Window *CreateTextWindow(uint32_t uniqueID, const char *windowName) +{ + // find the first unused entry in the windowList + for (int i = 0; i < MAX_GUI_WINDOWS; ++i) + { + if (!windowList[i]) + { + windowList[i] = new GUI_TerminalWindow(windowName); + + // TODO: Check for NULL + windowIDs[i] = uniqueID; + + AddWindowToStack(windowList[i], &windowStack[i]); + + pTaskbar->AddWindow(uniqueID, windowList[i]); + + return windowList[i]; + } + } + + printf("ERROR: Couldn't find any free window slots!\n"); + return NULL; +} + +GUI_Rect NewWindowPosition(int width, int height) +{ + GUI_Rect windowPos = { nextY, nextX, width, height }; + + // Advance position of next window + nextX += WINDOW_X_INC; + nextX %= MAX_WINDOW_X; + nextY += WINDOW_Y_INC; + nextY %= MAX_WINDOW_Y; + + return windowPos; +} + +// This is kind of hacky and maybe I'll find a better way in the future. +// Windows can request their own removal, but if they're deleted at that point, execution will return to deleted code +void DeleteAllWindowsInQueue() +{ + for (int i = 0; i < nextDeletionQueueIndex; ++i) + delete pDeletionQueue[i]; + + nextDeletionQueueIndex = 0; +} + +// Add a GUI_Window to the deletion queue +void DeleteWindow(GUI_Window *pWindow) +{ + if (nextDeletionQueueIndex > DELETION_QUEUE_SIZE) + { + printf("Can't delete any more windows, Queue is full!!\n"); + return; + } + + pDeletionQueue[nextDeletionQueueIndex++] = pWindow; +} + +// Display MessageBox +// TODO: don't require any memory allocation so we can show out-of-memory errors +void MessageBox(char *messageText, char *windowTitle) +{ + for (int i = 0; i < MAX_GUI_WINDOWS; ++i) + { + if (!windowList[i]) + { + windowList[i] = new GUI_MessageBox(messageText, windowTitle); + AddWindowToStack(windowList[i], &windowStack[i]); + return; + } + } + printf("No free spot for window\n"); + for (;;) + __halt(); +} + +// Display MessageBox with printf-like ability +// TODO: don't require any memory allocation so we can show out-of-memory errors +void MessageBoxf(char *windowTitle, char *messageFormat, ...) +{ + for (int i = 0; i < MAX_GUI_WINDOWS; ++i) + { + if (!windowList[i]) + { + char buffer[128] = { 0 }; + va_list va; + va_start(va, messageFormat); + const int ret = vsnprintf(buffer, 128, messageFormat, va); + va_end(va); + + windowList[i] = new GUI_MessageBox(buffer, windowTitle); + AddWindowToStack(windowList[i], &windowStack[i]); + return; + } + } + printf("No free spot for window\n"); + for (;;) + __halt(); +} + +// Called by windows when they want to be destroyed +void Shell_Destroy_Window(GUI_Window *pWindow) +{ + if (!pWindow) + return; + + // Find window index + for (int i = 0; i < MAX_GUI_WINDOWS; ++i) + { + if (windowList[i] == pWindow) + { + // Is there an application associated with this window? + if ((windowIDs[i] & WINDOW_ID_IS_NOT_PID) == 0) + { +#ifdef __MYOS + closeApp(windowIDs[i]); +#endif + } + + windowList[i] = NULL; + + RemoveWindowFromStack(&windowStack[i]); + windowStack[i].pAbove = windowStack[i].pUnderneath = NULL; + windowStack[i].pWindow = NULL; + + if (windowIDs[i]) + { + pTaskbar->RemoveWindow(windowIDs[i]); + windowIDs[i] = 0; + } + + break; + } + } + + // Check if this window is being dragged / waiting for a MouseUp event + if (pDraggedWindow == pWindow) + pDraggedWindow = NULL; + + // Add window to deletion queue + DeleteWindow(pWindow); +} + +void Shell_Launch_App(const char * appName) +{ + // Only launch apps if we're running in MyOS +#ifdef __MYOS + + if (!launchApp(appName, false)) + { + MessageBoxf("ERROR", "Failed to launch %s", appName); + } +#endif +} + +// TODO: There are memory leaks that need debugging +int main(int argc, char* argv[]) +{ +#ifdef __MYOS + + // re-enable interrupts (TODO: FIXME: What is disabling them??) + __asm sti; + + // disable shell display elements + hideShellDisplay(); +#endif + + SDL_Window *window; // Declare a pointer + //The window we'll be rendering to + + SDL_Surface* screenSurface = NULL; // the surface to render to + + //printf("Running gui\n"); + + SDL_Init(SDL_INIT_VIDEO); // Initialize SDL2 + + // Create an application window with the following settings: + window = SDL_CreateWindow( + "An SDL2 window", // window title + SDL_WINDOWPOS_UNDEFINED, // initial x position + SDL_WINDOWPOS_UNDEFINED, // initial y position + 800, // width, in pixels (ignored) + 600, // height, in pixels (ignored + 0 + //SDL_WINDOW_FULLSCREEN_DESKTOP // Make the window the same size as the desktop + ); + + // Check that the window was successfully created + if (window == NULL) { + // In the case that the window could not be made... + printf("Could not create window: %s\n", SDL_GetError()); + return 1; + } + + // Get window surface + screenSurface = SDL_GetWindowSurface(window); + + // Fill the surface green + /*SDL_FillRect(screenSurface, NULL, SDL_MapRGB(screenSurface->format, 0x00, 0xFF, 0x7F)); + + // Update the surface + SDL_UpdateWindowSurface(window); + + SDL_Delay(500); // Pause execution for 500 milliseconds, for example + */ + // Load BMP + //char *filename = "kghrwide.bmp"; + char *filename = "kg2.bmp"; +#if __MYOS__ + filename = "kg2.bmp"; +#endif + SDL_Surface *bitmapSurface = SDL_LoadBMP(filename); + if (bitmapSurface == NULL) + { + printf("Unable to load image %s! SDL Error: %s\n", filename, SDL_GetError()); + //success = false; + return -1; + } + + uint32_t green = SDL_MapRGB(screenSurface->format, 0x00, 0xFF, 0x7F); + + // Create a GUI_Window + //GUI_Window bigWindow(200, 200, 200, 200); + +/// windowStack[0].pWindow = &bigWindow; + + bool done = false; + bool dragging = false; + + SDL_Event event; + + // Hide the mouse cursor + SDL_ShowCursor(SDL_DISABLE); + + // Create a surface for the cursor + // TODO: Should we use SDL_CreateSystemCursor()? + SDL_Surface *pCursor = SDL_CreateRGBSurface(0, // flags (unused) + CURSOR_X, // width, + CURSOR_Y, // height, + 32, // bit-depth + 0xFF000000, // Rmask (default) + 0x00FF0000, // Gmask (default) + 0x0000FF00, // Bmask (default), + 0x000000FF); // Amask*/ + if (!pCursor) + { + printf("ERROR: Couldn't create surface for cursor\n"); + } + + // Fill in cursor image (Not sure why the SDL_memcpy4 isn't working) + //SDL_memcpy4(pCursor->pixels, cursorImage, 16 * 16); + for (int y = 0; y < 16; ++y) + { + for (int x = 0; x < 16; ++x) + { + PIXEL_32BIT originalColor = cursorImage[y][x]; + uint32_t color = SDL_MapRGBA(pCursor->format, + originalColor.red, + originalColor.green, + originalColor.blue, + originalColor.alpha); + void *ptr = pCursor->pixels; + SDL_memcpy4( (void*)((uint32_t)ptr + (((y * 16) + x) * 4)), &color, 1); + } + } + + SDL_SetSurfaceBlendMode(pCursor, SDL_BLENDMODE_BLEND); + + // Create Taskbar + pTaskbar = new GUI_Taskbar(screenSurface->w, screenSurface->h); + +#ifdef __MYOS + // Tell the kernel how to talk to us + registerGuiCallback(GUI_Kernel_Callback); +#endif + + //GUI_Kernel_Callback(0, 0, NULL); + + previousTime = timeGetUptimeMS(); + + // Keep drawing everything + while (!done) + { + // Update cursor position + uint32_t mouseButtons = SDL_GetMouseState(&cursorRect.x, &cursorRect.y); + + GUI_WINDOW_STACK_ENTRY *pStackEntryUnderCursor = FindWindowFromPoint(cursorRect.x, cursorRect.y); + + // Check if cursor needs to blink + uint32_t ticks = timeGetUptimeMS(); + timeBeforeCursorBlink -= (ticks - previousTime); + + if (timeBeforeCursorBlink < 0) + { + if (pStackTop) + pStackTop->pWindow->UpdateCursor(); + + timeBeforeCursorBlink += CURSOR_BLINK_MS; + } + + previousTime = ticks; + + + if (SDL_PollEvent(&event)) + { + //GUI_Window *pWindow; + SDL_Color red = { 255, 0, 0 }; + SDL_Color green = { 0, 255, 0 }; + + switch (event.type) + { + case SDL_USEREVENT: + //TODO + break; + + case SDL_KEYDOWN: + //switch (event.key.keysym) + //CreateTextWindow(lastWindowID++, "New Window"); + + //MessageBox("Here's a test message", "Test Message"); + switch (event.key.keysym.sym) + { + case SDLK_n: + CreateTextWindow(lastWindowID++, "Test Window"); + break; + case SDLK_ESCAPE: + done = true; + break; + default: + //MessageBoxf("Key pressed", "Scan code: 0x%X - %c", event.key.keysym.scancode, event.key.keysym.sym); + if (pStackTop) + pStackTop->pWindow->SendChar(event.key.keysym.sym); + break; + }; + break; + + case SDL_MOUSEBUTTONUP: + if (event.button.button == SDL_BUTTON_LEFT) + dragging = false; + if (pDraggedWindow) + pDraggedWindow->OnMouseUp(cursorRect.x - pDraggedWindow->dimensions.left, cursorRect.y - pDraggedWindow->dimensions.top); + break; + + case SDL_MOUSEMOTION: + if (dragging && pDraggedWindow) + { + pDraggedWindow->OnDrag(oldMousePos.x, oldMousePos.y, cursorRect.x, cursorRect.y); + oldMousePos.x = cursorRect.x; + oldMousePos.y = cursorRect.y; + } + else + { + if (pTaskbar->pStartMenu->PointInBounds(cursorRect.x, cursorRect.y)) + pTaskbar->pStartMenu->MouseOver(cursorRect.x - pTaskbar->pStartMenu->dimensions.left, + cursorRect.y - pTaskbar->pStartMenu->dimensions.top); + } + + break; + + case SDL_MOUSEBUTTONDOWN: + //pWindow = CreateTextWindow(lastWindowID++); + + switch (event.button.button) + { + case SDL_BUTTON_LEFT: + //pWindow->SetBackgroundColor(red); + // Is the taskbar being clicked? + if (cursorRect.y >= pTaskbar->dimensions.top) + { + pTaskbar->OnClick(cursorRect.x, cursorRect.y - pTaskbar->dimensions.top); + pDraggedWindow = pTaskbar; + } + // What about the start menu? + else if (pTaskbar->pStartMenu->PointInBounds(cursorRect.x, cursorRect.y)) + { + pTaskbar->pStartMenu->OnClick(cursorRect.x - pTaskbar->pStartMenu->dimensions.left, + cursorRect.y - pTaskbar->pStartMenu->dimensions.top); + } + else if (pStackEntryUnderCursor) + { + BringWindowToFront(pStackEntryUnderCursor);// ->pWindow->SetBackgroundColor(red); + GUI_Window *pWindow = pStackEntryUnderCursor->pWindow; + pDraggedWindow = pWindow; + pWindow->OnClick(cursorRect.x - pWindow->dimensions.left, cursorRect.y - pWindow->dimensions.top); + + // Find windowID from window + for (int i = 0; i < MAX_GUI_WINDOWS; ++i) + { + if (windowList[i] == pWindow) + { + pTaskbar->WindowActivated(windowIDs[i]); + break; + } + } + } + else + pDraggedWindow = NULL; + + oldMousePos = { cursorRect.x, cursorRect.y }; + dragging = true; + break; + + case SDL_BUTTON_RIGHT: + if (pStackEntryUnderCursor) + Shell_Destroy_Window(pStackEntryUnderCursor->pWindow); + // pStackEntryUnderCursor->pWindow->SetBackgroundColor(green); + //pWindow->SetBackgroundColor(green); + break; + }; + break; + + case SDL_QUIT: + done = true; + break; + + default: + break; + } + } + + // draw the "background" + if (bitmapSurface) + { + // Blit bitmap to window + SDL_BlitScaled(bitmapSurface, NULL, screenSurface, NULL); + + //SDL_Delay(3000); // Pause execution for 3000 milliseconds, for example + } + + // Fill the background with black instead of an image for a little while + //SDL_FillRect(screenSurface, NULL, RGB_BLACK); + + // draw all of the windows +// bigWindow.PaintToSurface(screenSurface); + + /*for (int i = 0; i < MAX_GUI_WINDOWS; ++i) + { + if(windowList[i]) + windowList[i]->PaintToSurface(screenSurface); + }*/ + + GUI_WINDOW_STACK_ENTRY *nextWindowEntry = GetBottomWindow(); + while (nextWindowEntry) + { + if (nextWindowEntry->pWindow) + nextWindowEntry->pWindow->PaintToSurface(screenSurface); + + nextWindowEntry = nextWindowEntry->pAbove; + } + + // draw a bouncing ball + SDL_FillRect(screenSurface, &ball, green); + ball.x += velocity.x; + ball.y += velocity.y; + + if (ball.x > 800 || ball.x < 0) + velocity.x = -velocity.x; + if (ball.y > 600 || ball.y < 0) + velocity.y = -velocity.y; + + // Draw the Taskbar + pTaskbar->PaintToSurface(screenSurface); + + // Draw the cursor + SDL_BlitSurface(pCursor, NULL, screenSurface, &cursorRect); + + // Update the surface + SDL_UpdateWindowSurface(window); + + // Delete all windows in deletion queue + DeleteAllWindowsInQueue(); + + //SDL_Delay(1); + } + + // Close and destroy the window + SDL_DestroyWindow(window); + + // Free BMP surface + //printf("Pixels at %p\n", bitmapSurface->pixels); + SDL_FreeSurface(pCursor); + SDL_FreeSurface(bitmapSurface); + SDL_FreeSurface(screenSurface); + + // Clean up + SDL_Quit(); + + //printf("Done with SDL Test Program.\n"); + + return 0; +} + +#ifdef __cplusplus +}; +#endif /* __cplusplus */ \ No newline at end of file diff --git a/MyOS_GUI_Shell/MyOS_GUI_Shell.h b/MyOS_GUI_Shell/MyOS_GUI_Shell.h new file mode 100644 index 0000000..2c99d00 --- /dev/null +++ b/MyOS_GUI_Shell/MyOS_GUI_Shell.h @@ -0,0 +1,32 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "GUI_Window.h" + +struct GUI_WINDOW_STACK_ENTRY; +typedef struct GUI_WINDOW_STACK_ENTRY +{ + GUI_Window *pWindow; + GUI_WINDOW_STACK_ENTRY *pUnderneath; + GUI_WINDOW_STACK_ENTRY *pAbove; +} GUI_WINDOW_STACK_ENTRY; + +void AddNewWindow(GUI_Window *pWindow); +void AddWindowToStack(GUI_Window *window, GUI_WINDOW_STACK_ENTRY *pStackEntry); +void BringWindowID_ToFront(uint32_t windowID); +void BringWindowToFront(GUI_WINDOW_STACK_ENTRY *pEntry); +GUI_Window *CreateTextWindow(uint32_t uniqueID, const char *windowName); +GUI_Window *GetWindowFromID(uint32_t uniqueID); +GUI_Rect NewWindowPosition(int x, int y); +void MessageBox(char *messageText, char *windowTitle); +void MessageBoxf(char *windowTitle, char *messageFormat, ...); +void Shell_Destroy_Window(GUI_Window *pWindow); +void Shell_Launch_App(const char *appName); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ \ No newline at end of file diff --git a/MyOS_GUI_Shell/MyOS_GUI_Shell.vcxproj b/MyOS_GUI_Shell/MyOS_GUI_Shell.vcxproj new file mode 100644 index 0000000..7a42e1e --- /dev/null +++ b/MyOS_GUI_Shell/MyOS_GUI_Shell.vcxproj @@ -0,0 +1,312 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {DD34D14A-8D2B-41FA-9EA5-02A5355F9BC4} + Win32Proj + MyOS_GUI_Shell + 8.1 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + false + MultiByte + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + + + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + Level3 + + + Disabled + false + __MYOS;NDEBUG;_CONSOLE;HAVE_MALLOC;%(PreprocessorDefinitions) + ..\MyOS_1\Libs\SDL\include;%(AdditionalIncludeDirectories) + NoExtensions + false + false + false + false + false + false + + + Native + true + false + false + %(AdditionalDependencies) + true + Default + @GUI_Kernel_Shell.h,GUI_BASE_ADDRESS + false + GUI.map + true + false + main + true + false + true + + + Copying GUI.exe to TFTP directory + copy "$(TargetDir)$(TargetFileName)" C:\Users\Administrator\.VirtualBox\TFTP\GUI.exe + + + false + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cdecl + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MyOS_GUI_Shell/MyOS_GUI_Shell.vcxproj.filters b/MyOS_GUI_Shell/MyOS_GUI_Shell.vcxproj.filters new file mode 100644 index 0000000..ec41420 --- /dev/null +++ b/MyOS_GUI_Shell/MyOS_GUI_Shell.vcxproj.filters @@ -0,0 +1,420 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {c94e25be-285f-4acd-af60-cfe785341cee} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files\SDL + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files\SDL + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files\SDL + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/MyOS_GUI_Shell/SDL_picofont.h b/MyOS_GUI_Shell/SDL_picofont.h new file mode 100644 index 0000000..bf1b8d0 --- /dev/null +++ b/MyOS_GUI_Shell/SDL_picofont.h @@ -0,0 +1,52 @@ +/* sdl_picofont + + http://nurd.se/~noname/sdl_picofont + + File authors: + Fredrik Hultin + With Modifications for MyOS by Trevor Thompson + + License: GPLv2 +*/ + +#ifndef SDL_PICOFONT_H +#define SDL_PICOFONT_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifdef __MYOS +#include "../MyOS_1/Libs/SDL/include/SDL.h" +#else +#include +#endif + + +#define FNT_FONTHEIGHT 8 +#define FNT_FONTWIDTH 8 + +// put same space between rows to improve readability +#define FNT_ROWSPACING 3 + +// put some margins around the borders +#define FNT_LEFTRIGHTMARGIN 3 +#define FNT_TOPBOTTOMMARGIN 3 + +typedef struct +{ + int x; + int y; +}FNT_xy; + +SDL_Surface* FNT_Render(const char* text, SDL_Color color); +SDL_Surface* FNT_RenderMax(const char* text, unsigned int len, SDL_Color color); + +unsigned char* FNT_GetFont(); + + +#ifdef __cplusplus +}; +#endif /* __cplusplus */ + +#endif /* SDL_PICOFONT_H */ diff --git a/MyOS_GUI_Shell/font.c b/MyOS_GUI_Shell/font.c new file mode 100644 index 0000000..a55a215 --- /dev/null +++ b/MyOS_GUI_Shell/font.c @@ -0,0 +1,2596 @@ +/* sdl_picofont + + http://nurd.se/~noname/sdl_picofont + + File authors: + Fredrik Hultin + + With code from: + Greg Harp + John Shifflett + + License: GPLv2 +*/ + +/* This is the font_pearl_8x8.c file from the linux source with some minor modifications */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#include "SDL_picofont.h" + +unsigned char* FNT_GetFont() +{ + static const unsigned char spf_font[2048] = { + + /* 0 0x00 '^@' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 1 0x01 '^A' */ + 0x7e, /* 01111110 */ + 0x81, /* 10000001 */ + 0xa5, /* 10100101 */ + 0x81, /* 10000001 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0x81, /* 10000001 */ + 0x7e, /* 01111110 */ + + /* 2 0x02 '^B' */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xdb, /* 11011011 */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + + /* 3 0x03 '^C' */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + + /* 4 0x04 '^D' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + + /* 5 0x05 '^E' */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + + /* 6 0x06 '^F' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + + /* 7 0x07 '^G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 8 0x08 '^H' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xe7, /* 11100111 */ + 0xc3, /* 11000011 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 9 0x09 '^I' */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x42, /* 01000010 */ + 0x42, /* 01000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 10 0x0a '^J' */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0x99, /* 10011001 */ + 0xbd, /* 10111101 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0xc3, /* 11000011 */ + 0xff, /* 11111111 */ + + /* 11 0x0b '^K' */ + 0x0f, /* 00001111 */ + 0x07, /* 00000111 */ + 0x0f, /* 00001111 */ + 0x7d, /* 01111101 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + + /* 12 0x0c '^L' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + + /* 13 0x0d '^M' */ + 0x3f, /* 00111111 */ + 0x33, /* 00110011 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x70, /* 01110000 */ + 0xf0, /* 11110000 */ + 0xe0, /* 11100000 */ + + /* 14 0x0e '^N' */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x67, /* 01100111 */ + 0xe6, /* 11100110 */ + 0xc0, /* 11000000 */ + + /* 15 0x0f '^O' */ + 0x18, /* 00011000 */ + 0xdb, /* 11011011 */ + 0x3c, /* 00111100 */ + 0xe7, /* 11100111 */ + 0xe7, /* 11100111 */ + 0x3c, /* 00111100 */ + 0xdb, /* 11011011 */ + 0x18, /* 00011000 */ + + /* 16 0x10 '^P' */ + 0x80, /* 10000000 */ + 0xe0, /* 11100000 */ + 0xf8, /* 11111000 */ + 0xfe, /* 11111110 */ + 0xf8, /* 11111000 */ + 0xe0, /* 11100000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + + /* 17 0x11 '^Q' */ + 0x02, /* 00000010 */ + 0x0e, /* 00001110 */ + 0x3e, /* 00111110 */ + 0xfe, /* 11111110 */ + 0x3e, /* 00111110 */ + 0x0e, /* 00001110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + + /* 18 0x12 '^R' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + + /* 19 0x13 '^S' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + + /* 20 0x14 '^T' */ + 0x7f, /* 01111111 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7b, /* 01111011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x00, /* 00000000 */ + + /* 21 0x15 '^U' */ + 0x3e, /* 00111110 */ + 0x61, /* 01100001 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x86, /* 10000110 */ + 0x7c, /* 01111100 */ + + /* 22 0x16 '^V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 23 0x17 '^W' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + + /* 24 0x18 '^X' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 25 0x19 '^Y' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 26 0x1a '^Z' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 27 0x1b '^[' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 28 0x1c '^\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 29 0x1d '^]' */ + 0x00, /* 00000000 */ + 0x24, /* 00100100 */ + 0x66, /* 01100110 */ + 0xff, /* 11111111 */ + 0x66, /* 01100110 */ + 0x24, /* 00100100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 30 0x1e '^^' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 31 0x1f '^_' */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 32 0x20 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 33 0x21 '!' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 34 0x22 '"' */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 35 0x23 '#' */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 36 0x24 '$' */ + 0x18, /* 00011000 */ + 0x3e, /* 00111110 */ + 0x60, /* 01100000 */ + 0x3c, /* 00111100 */ + 0x06, /* 00000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 37 0x25 '%' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x66, /* 01100110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 38 0x26 '&' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x68, /* 01101000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 39 0x27 ''' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 40 0x28 '(' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + + /* 41 0x29 ')' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + + /* 42 0x2a '*' */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0xff, /* 11111111 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 43 0x2b '+' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 44 0x2c ',' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + + /* 45 0x2d '-' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 46 0x2e '.' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 47 0x2f '/' */ + 0x03, /* 00000011 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 48 0x30 '0' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xde, /* 11011110 */ + 0xfe, /* 11111110 */ + 0xf6, /* 11110110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 49 0x31 '1' */ + 0x18, /* 00011000 */ + 0x78, /* 01111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 50 0x32 '2' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 51 0x33 '3' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x1c, /* 00011100 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 52 0x34 '4' */ + 0x1c, /* 00011100 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + + /* 53 0x35 '5' */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 54 0x36 '6' */ + 0x38, /* 00111000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 55 0x37 '7' */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + + /* 56 0x38 '8' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 57 0x39 '9' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 58 0x3a ':' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 59 0x3b ';' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + + /* 60 0x3c '<' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + + /* 61 0x3d '=' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 62 0x3e '>' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + + /* 63 0x3f '?' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 64 0x40 '@' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 65 0x41 'A' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 66 0x42 'B' */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 67 0x43 'C' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 68 0x44 'D' */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 69 0x45 'E' */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xf8, /* 11111000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 70 0x46 'F' */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xf8, /* 11111000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 71 0x47 'G' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 72 0x48 'H' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 73 0x49 'I' */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 74 0x4a 'J' */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 75 0x4b 'K' */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0xd8, /* 11011000 */ + 0xf0, /* 11110000 */ + 0xd8, /* 11011000 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 76 0x4c 'L' */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 77 0x4d 'M' */ + 0x82, /* 10000010 */ + 0xc6, /* 11000110 */ + 0xee, /* 11101110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 78 0x4e 'N' */ + 0xc6, /* 11000110 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 79 0x4f 'O' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 80 0x50 'P' */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfc, /* 11111100 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 81 0x51 'Q' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xf6, /* 11110110 */ + 0xde, /* 11011110 */ + 0x7c, /* 01111100 */ + 0x06, /* 00000110 */ + + /* 82 0x52 'R' */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfc, /* 11111100 */ + 0xd8, /* 11011000 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 83 0x53 'S' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x38, /* 00111000 */ + 0x0c, /* 00001100 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 84 0x54 'T' */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 85 0x55 'U' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 86 0x56 'V' */ + 0xc3, /* 11000011 */ + 0xc3, /* 11000011 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 87 0x57 'W' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0xee, /* 11101110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 88 0x58 'X' */ + 0xc3, /* 11000011 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc3, /* 11000011 */ + 0x00, /* 00000000 */ + + /* 89 0x59 'Y' */ + 0xc3, /* 11000011 */ + 0xc3, /* 11000011 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 90 0x5a 'Z' */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 91 0x5b '[' */ + 0x3c, /* 00111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 92 0x5c '\' */ + 0xc0, /* 11000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x03, /* 00000011 */ + 0x00, /* 00000000 */ + + /* 93 0x5d ']' */ + 0x3c, /* 00111100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 94 0x5e '^' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 95 0x5f '_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + + /* 96 0x60 '`' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 97 0x61 'a' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0x06, /* 00000110 */ + 0x7e, /* 01111110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 98 0x62 'b' */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 99 0x63 'c' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 100 0x64 'd' */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x7e, /* 01111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 101 0x65 'e' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 102 0x66 'f' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + + /* 103 0x67 'g' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x7c, /* 01111100 */ + + /* 104 0x68 'h' */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 105 0x69 'i' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 106 0x6a 'j' */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + + /* 107 0x6b 'k' */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xcc, /* 11001100 */ + 0xd8, /* 11011000 */ + 0xf0, /* 11110000 */ + 0xd8, /* 11011000 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + + /* 108 0x6c 'l' */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 109 0x6d 'm' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xec, /* 11101100 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 110 0x6e 'n' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 111 0x6f 'o' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 112 0x70 'p' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfc, /* 11111100 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + + /* 113 0x71 'q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + + /* 114 0x72 'r' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0xe6, /* 11100110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 115 0x73 's' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x06, /* 00000110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 116 0x74 't' */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x7c, /* 01111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x36, /* 00110110 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + + /* 117 0x75 'u' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 118 0x76 'v' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 119 0x77 'w' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 120 0x78 'x' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 121 0x79 'y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc3, /* 11000011 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + + /* 122 0x7a 'z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x38, /* 00111000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 123 0x7b '{' */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x00, /* 00000000 */ + + /* 124 0x7c '|' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 125 0x7d '}' */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 126 0x7e '~' */ + 0x72, /* 01110010 */ + 0x9c, /* 10011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 127 0x7f '' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 128 0x80 '�' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + + /* 129 0x81 '�' */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 130 0x82 '�' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 131 0x83 '�' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 132 0x84 '�' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 133 0x85 '�' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 134 0x86 '�' */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 135 0x87 '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x7e, /* 01111110 */ + 0x0c, /* 00001100 */ + 0x38, /* 00111000 */ + + /* 136 0x88 '�' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 137 0x89 '�' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 138 0x8a '�' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 139 0x8b '�' */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 140 0x8c '�' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 141 0x8d '�' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 142 0x8e '�' */ + 0xc6, /* 11000110 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 143 0x8f '�' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 144 0x90 '�' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xf8, /* 11111000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 145 0x91 '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 146 0x92 '�' */ + 0x3e, /* 00111110 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xce, /* 11001110 */ + 0x00, /* 00000000 */ + + /* 147 0x93 '�' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 148 0x94 '�' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 149 0x95 '�' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 150 0x96 '�' */ + 0x78, /* 01111000 */ + 0x84, /* 10000100 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 151 0x97 '�' */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 152 0x98 '�' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0xfc, /* 11111100 */ + + /* 153 0x99 '�' */ + 0xc6, /* 11000110 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 154 0x9a '�' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 155 0x9b '�' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 156 0x9c '�' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x64, /* 01100100 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x66, /* 01100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 157 0x9d '�' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 158 0x9e '�' */ + 0xf8, /* 11111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xfa, /* 11111010 */ + 0xc6, /* 11000110 */ + 0xcf, /* 11001111 */ + 0xc6, /* 11000110 */ + 0xc7, /* 11000111 */ + + /* 159 0x9f '�' */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 160 0xa0 '�' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 161 0xa1 '�' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 162 0xa2 '�' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 163 0xa3 '�' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 164 0xa4 '�' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + + /* 165 0xa5 '�' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0x00, /* 00000000 */ + + /* 166 0xa6 '�' */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 167 0xa7 '�' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 168 0xa8 '�' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x63, /* 01100011 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + + /* 169 0xa9 '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 170 0xaa '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 171 0xab '�' */ + 0x63, /* 01100011 */ + 0xe6, /* 11100110 */ + 0x6c, /* 01101100 */ + 0x7e, /* 01111110 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x0f, /* 00001111 */ + + /* 172 0xac '�' */ + 0x63, /* 01100011 */ + 0xe6, /* 11100110 */ + 0x6c, /* 01101100 */ + 0x7a, /* 01111010 */ + 0x36, /* 00110110 */ + 0x6a, /* 01101010 */ + 0xdf, /* 11011111 */ + 0x06, /* 00000110 */ + + /* 173 0xad '�' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 174 0xae '�' */ + 0x00, /* 00000000 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x66, /* 01100110 */ + 0x33, /* 00110011 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 175 0xaf '�' */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0x66, /* 01100110 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 176 0xb0 '�' */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + + /* 177 0xb1 '�' */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + + /* 178 0xb2 '�' */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + + /* 179 0xb3 '�' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 180 0xb4 '�' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 181 0xb5 '�' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 182 0xb6 '�' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 183 0xb7 '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 184 0xb8 '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 185 0xb9 '�' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 186 0xba '�' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 187 0xbb '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 188 0xbc '�' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 189 0xbd '�' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 190 0xbe '�' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 191 0xbf '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 192 0xc0 '�' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 193 0xc1 '�' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 194 0xc2 '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 195 0xc3 '�' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 196 0xc4 '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 197 0xc5 '�' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 198 0xc6 '�' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 199 0xc7 '�' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 200 0xc8 '�' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 201 0xc9 '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 202 0xca '�' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 203 0xcb '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 204 0xcc '�' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 205 0xcd '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 206 0xce '�' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 207 0xcf '�' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 208 0xd0 '�' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 209 0xd1 '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 210 0xd2 '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 211 0xd3 '�' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 212 0xd4 '�' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 213 0xd5 '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 214 0xd6 '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 215 0xd7 '�' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 216 0xd8 '�' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 217 0xd9 '�' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 218 0xda '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 219 0xdb '�' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 220 0xdc '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 221 0xdd '�' */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + + /* 222 0xde '�' */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + + /* 223 0xdf '�' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 224 0xe0 '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xc8, /* 11001000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 225 0xe1 '�' */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xd8, /* 11011000 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + + /* 226 0xe2 '�' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 227 0xe3 '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 228 0xe4 '�' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 229 0xe5 '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 230 0xe6 '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0xc0, /* 11000000 */ + + /* 231 0xe7 '�' */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 232 0xe8 '�' */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + + /* 233 0xe9 '�' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 234 0xea '�' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xee, /* 11101110 */ + 0x00, /* 00000000 */ + + /* 235 0xeb '�' */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x3e, /* 00111110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 236 0xec '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 237 0xed '�' */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7e, /* 01111110 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + + /* 238 0xee '�' */ + 0x1e, /* 00011110 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x7e, /* 01111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + + /* 239 0xef '�' */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 240 0xf0 '�' */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 241 0xf1 '�' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 242 0xf2 '�' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 243 0xf3 '�' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 244 0xf4 '�' */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 245 0xf5 '�' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + + /* 246 0xf6 '�' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 247 0xf7 '�' */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 248 0xf8 '�' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 249 0xf9 '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 250 0xfa '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 251 0xfb '�' */ + 0x0f, /* 00001111 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xec, /* 11101100 */ + 0x6c, /* 01101100 */ + 0x3c, /* 00111100 */ + 0x1c, /* 00011100 */ + + /* 252 0xfc '�' */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 253 0xfd '�' */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 254 0xfe '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 255 0xff '�' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + }; + + return (unsigned char*)(&spf_font); +} + + +#ifdef __cplusplus +}; +#endif /* __cplusplus */ diff --git a/MyOS_GUI_Shell/spf.c b/MyOS_GUI_Shell/spf.c new file mode 100644 index 0000000..4df62e2 --- /dev/null +++ b/MyOS_GUI_Shell/spf.c @@ -0,0 +1,148 @@ +/* sdl_picofont + + http://nurd.se/~noname/sdl_picofont + + File authors: + Fredrik Hultin + + License: GPLv2 +*/ + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#include "SDL_picofont.h" + +//#include + +FNT_xy FNT_Generate(const char* text, unsigned int len, unsigned int w, unsigned char* pixels) +{ + unsigned int i, x, y, col, row, stop; + unsigned char *fnt, chr; + FNT_xy xy; + + fnt = FNT_GetFont(); + + xy.x = xy.y = col = row = stop = 0; + + for(i = 0; i < len; i++){ + switch(text[i]){ + case '\n': + row++; + col = 0; + chr = 0; + break; + + case '\r': + chr = 0; + break; + + case '\t': + chr = 0; + col += 4 - col % 4; + break; + + case '\0': + stop = 1; + chr = 0; + break; + + default: + col++; + chr = text[i]; + break; + } + + if(stop){ + break; + } + + if((col + 1) * FNT_FONTWIDTH > (unsigned int)xy.x){ + xy.x = col * FNT_FONTWIDTH; + } + + if((row + 1) * FNT_FONTHEIGHT > (unsigned int)xy.y){ + xy.y = (row + 1) * FNT_FONTHEIGHT; + } + + if(chr != 0 && w != 0){ + for(y = 0; y < FNT_FONTHEIGHT; y++){ + for(x = 0; x < FNT_FONTWIDTH; x++){ + if(fnt[text[i] * FNT_FONTHEIGHT + y] >> (7 - x) & 1){ + pixels[((col - 1) * FNT_FONTWIDTH) + x + (y + row * FNT_FONTHEIGHT) * w] = 1; + } + } + } + } + } + + return xy; +} + +SDL_Surface* FNT_Render(const char* text, SDL_Color color) +{ + return FNT_RenderMax(text, strlen(text), color); +} + +SDL_Surface* FNT_RenderMax(const char* text, unsigned int len, SDL_Color color) +{ + SDL_Surface* surface; + SDL_Color colors[2]; + FNT_xy xy; + + colors[0].r = (color.r + 0x7e) % 0xff; + colors[0].g = (color.g + 0x7e) % 0xff; + colors[0].b = (color.b + 0x7e) % 0xff; + + colors[1] = color; + + xy = FNT_Generate(text, len, 0, NULL); + + surface = SDL_CreateRGBSurface( + SDL_SWSURFACE, + xy.x, + xy.y, + 8, + 0, + 0, + 0, + 0 + ); + + if(!surface){ + return NULL; + } + + SDL_SetColorKey(surface, SDL_TRUE, SDL_MapRGB(surface->format, (color.r + 0x7e) % 0xff, (color.g + 0x7e) % 0xff, (color.b + 0x7e) % 0xff)); + + SDL_SetPaletteColors(surface->format->palette, colors, 0, 2); + + //SDL_FillRect(surface, NULL, SDL_MapRGB(surface->format, 0x0d, 0xea, 0xd0)); + + //SDL_SetColors(surface, colors, 0, 2); + /*SDL_SetColors(screen, color, 0, intColors); + +With: +SDL_ SDL_SetPaletteColors(screen->format->palette, color, 0, intColors);*/ + + + if(SDL_MUSTLOCK(surface)){ + SDL_LockSurface(surface); + } + + FNT_Generate(text, len, surface->w, (unsigned char*)surface->pixels); + + if(SDL_MUSTLOCK(surface)){ + SDL_UnlockSurface(surface); + } + + return surface; +} + + +#ifdef __cplusplus +}; +#endif /* __cplusplus */ diff --git a/README.md b/README.md index 2b36aba..d4ff2de 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,19 @@ # MyOS Yet another homebrew OS -"MyOS" is a hobby OS I've started working on. It is very basic and has only ever executed one program. It will (perhaps) become a more feature-rich OS in the distant future. +"MyOS" is my hobby OS. It's very basic but it can run some programs. It will (perhaps) become a more feature-rich OS in the distant future. The name is temporary and will be changed when I feel this project is large enough to warrant a decent name. ![Screenshot with test image](https://raw.githubusercontent.com/coderTrevor/MyOS/master/Media/Screenshots/MyOS_Graphical1.png "MyOS Screenshot") +![Doom running on MyOS](https://github.com/coderTrevor/My-Doom/blob/c60abc6bc10bd30e733e29056e232c54e1dc283c/screenshots/Doom%20on%20MyOS.gif?raw=true "Doom!") + +![GUI of MyOS](https://raw.githubusercontent.com/coderTrevor/MyOS/master/Media/Screenshots/MyOS_GUI.gif "MyOS GUI") + ## Motivation -First-things-first: I have no illusions about the fact that nobody will ever use this as their main operating system, or probably even use it at all. In the history of computing, only one hobby OS has ever achieved that, and today, Linux still faces many challenges despite how many contributors it has gathered. +I have no illusions about the fact that nobody will ever use this as an operating system, but developing it is fun. :) Mostly I wanted to make an OS for the following reasons: * To see how hard it is to make one & to say that I've done it. I've really just always wanted to make an OS. @@ -17,15 +21,24 @@ Mostly I wanted to make an OS for the following reasons: * To experiment with debugging methods that will allow for fast OS development on real hardware (again, with the goal of bringing some of these methods to ReactOS). * Perhaps, possibly, to investigate SMP and 64-bit kernels. I haven't decided if I'm going in that direction or not yet. -## Goals -I'll be happy when it can run its own port of Doom. In fact, I've been toying around with the idea of making the shell Doom itself. I'd call it "Shotgun Shell." That might be novel enough to get it some attention. +## Long-Term Goals +- [x] ~~I'll be happy when it can run its own port of Doom.~~ Oh SNAP! It runs Doom now! In fact, I've been toying around with the idea of making the shell Doom itself. I'd call it "Shotgun Shell." That might be novel enough to get it some attention. +- [ ] Should run SDL apps (like Doom and my NES emulator) in their own GUI windows +- [ ] Should work on real hardware (presently only tested with Qemu and VirtualBox) + +## Short-Term Goals +- [ ] Add support for reading a CD and produce an ISO which includes all relevant programs, making it very easy for someone else to check out the OS (on a Virtual Machine) +- [ ] Improve the MSVC files / build process and bundle all necessary libs and apps to make it relatively easy for someone else to build the OS with Visual Studio. Presently the project files take the paths of my development machine for granted. +- [ ] Include a debugging stub. +- [ ] Fix debug build ## Features, Limitations, & Quirks -There's not much here beyond what's provided with tutorials like those from the OSDev wiki and Brokenthorn. I haven't even finished all of those tutorials. The following is implemented: +This started out as a culmination of tutorials like those from the OSDev wiki and Brokenthorn, and has grown from there. I haven't even finished all of those tutorials. The following is implemented: * It will launch an .exe, provided the .exe is built to target MyOS (native app, based at 0x8000). * Paging is enabled * A GDT is used * The kernel is mapped to the upper-half of memory (and can be remapped easily) +* Malloc() and free() are implemented. * A do-little command line shell is provided * Minimal support for COM1 serial input and output (Currently commented-out) * Basic interrupt support, mostly just used by the keyboard and NIC drivers @@ -33,16 +46,17 @@ There's not much here beyond what's provided with tutorials like those from the * A virtio-net driver * An e1000 driver (only working in Qemu) * Some network protocols are minimally implemented, like ARP, IP, UDP, and a DHCP client -* Filesystem support is only offered through a TFTP client with a hardcoded server IP +* Filesystem support is only offered through a TFTP client. The TFTP server IP is determined via DHCP. * Can be built with MSVC 2015 (which makes it somewhat rare in the hobby OS world) * The OS builds as a .dll file. This file is multiboot-compliant and can be loaded by Qemu with the -kernel option, or you can boot it with GRUB. * It has graphical support (if available, provided either by Grub or a Bochs Graphics Adapter) and can display a bitmap. * It has the ability to set a background image. -* It has some very basic sound support and will play .voc files. +* It has some very basic SoundBlaster 16 support and will play .voc files. * It can run a collection of shell commands from a batch file. +* It totally runs Doom! Doooooooooooom!!!! ## Other Notes -The code style is very messy and inconsistent. Partly this is because I've copy-pasted code from different tutorials when I started this project. Also, I still haven't decided on what style I want to use for the project as a whole. When I do, I'll fix the inconsistencies. +The code style is somewhat messy and inconsistent. Partly this is because MyOS started its life as copy-pasted code from different tutorials and the styles of each part have been carried forward. Also, I still haven't decided on what style I want to use for the project as a whole. When I do, I'll fix the inconsistencies. Porting the code to be buildable from a gcc cross-compiler in Linux is probably a task I'll tackle soon. I want to make the code portable before the project gets too big. @@ -61,4 +75,4 @@ I would very much like to thank the following individuals and organizations who' Thank you all for making this available! ## Troubleshooting -If you can't build the source with MSVC, make sure you've selected x86 as the target platform. MSVC selects x64 by default. +If you can't build the source with MSVC, make sure you've selected x86 release as the target platform. MSVC selects x64 by default. Note that the project is in flux and it's not easy to build right now (see short-term goals). diff --git a/Release/MyOS_1.dll b/Release/MyOS_1.dll index 7d7c39d..95ce7a9 100644 Binary files a/Release/MyOS_1.dll and b/Release/MyOS_1.dll differ diff --git a/Release/myos.iso b/Release/myos.iso index 8338f96..fc81ca9 100644 Binary files a/Release/myos.iso and b/Release/myos.iso differ diff --git a/SDL_TestApp1/SDL_TestApp1.c b/SDL_TestApp1/SDL_TestApp1.cpp similarity index 79% rename from SDL_TestApp1/SDL_TestApp1.c rename to SDL_TestApp1/SDL_TestApp1.cpp index e175e89..c0d4e45 100644 --- a/SDL_TestApp1/SDL_TestApp1.c +++ b/SDL_TestApp1/SDL_TestApp1.cpp @@ -1,5 +1,8 @@ // TestApp1.cpp : A super-simple application for testing with MyOS // +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ //#include "stdafx.h" #ifndef WIN32 @@ -16,12 +19,14 @@ #include #endif +#include "TestCpp.h" + #define SDL_MAIN_HANDLED 1 #include "../MyOS_1/Libs/SDL/include/SDL.h" #include "../MyOS_1/Libs/SDL/include/SDL_video.h" -int main(int argc, char* argv[]) +int __cdecl main(int argc, char* argv[]) { SDL_Window *window; // Declare a pointer //The window we'll be rendering to @@ -35,9 +40,10 @@ int main(int argc, char* argv[]) "An SDL2 window", // window title SDL_WINDOWPOS_UNDEFINED, // initial x position SDL_WINDOWPOS_UNDEFINED, // initial y position - 800, // width, in pixels (ignored) - 600, // height, in pixels (ignored - SDL_WINDOW_FULLSCREEN_DESKTOP // Make the window the same size as the desktop + 640, // width, in pixels (ignored) + 480, // height, in pixels (ignored + 0 + //SDL_WINDOW_FULLSCREEN_DESKTOP // Make the window the same size as the desktop ); // Check that the window was successfully created @@ -58,7 +64,7 @@ int main(int argc, char* argv[]) // Update the surface SDL_UpdateWindowSurface(window); - SDL_Delay(500); // Pause execution for 500 milliseconds, for example + SDL_Delay(100); // Pause execution for 500 milliseconds, for example // Load BMP char *filename = "kghrwide.bmp"; @@ -80,7 +86,7 @@ int main(int argc, char* argv[]) // Update the surface SDL_UpdateWindowSurface(window); - SDL_Delay(3000); // Pause execution for 3000 milliseconds, for example + SDL_Delay(300); // Pause execution for 3000 milliseconds, for example } // Close and destroy the window @@ -94,5 +100,14 @@ int main(int argc, char* argv[]) printf("Done with SDL Test Program.\n"); + TestClass *pTesty = new TestClass(); + pTesty->PrintMessage(); + + exit(0); + return 0; -} \ No newline at end of file +} + +#ifdef __cplusplus +}; +#endif /* __cplusplus */ \ No newline at end of file diff --git a/SDL_TestApp1/SDL_TestApp1.vcxproj b/SDL_TestApp1/SDL_TestApp1.vcxproj index a2438c5..b34d4a4 100644 --- a/SDL_TestApp1/SDL_TestApp1.vcxproj +++ b/SDL_TestApp1/SDL_TestApp1.vcxproj @@ -124,10 +124,12 @@ false false NoExtensions - true + false + Cdecl + false - Console + Native true true true @@ -137,6 +139,9 @@ false %(AdditionalDependencies) true + false + true + true copy "$(TargetDir)$(TargetFileName)" C:\Users\Administrator\.VirtualBox\TFTP\$(TargetFileName) @@ -161,7 +166,10 @@ - + + + Cdecl + @@ -239,7 +247,9 @@ + + @@ -264,7 +274,15 @@ - + + Cdecl + + + + + + + diff --git a/SDL_TestApp1/SDL_TestApp1.vcxproj.filters b/SDL_TestApp1/SDL_TestApp1.vcxproj.filters index 11d075c..0a48251 100644 --- a/SDL_TestApp1/SDL_TestApp1.vcxproj.filters +++ b/SDL_TestApp1/SDL_TestApp1.vcxproj.filters @@ -18,9 +18,6 @@ - - Source Files - Source Files @@ -321,5 +318,31 @@ Source Files\SDL + + Source Files + + + Source Files + + + Source Files + + + Source Files\SDL + + + Source Files\SDL + + + + + Source Files\Header Files + + + Source Files\Header Files + + + Source Files + \ No newline at end of file diff --git a/SDL_TestApp1/TestCpp.cpp b/SDL_TestApp1/TestCpp.cpp new file mode 100644 index 0000000..50f18e6 --- /dev/null +++ b/SDL_TestApp1/TestCpp.cpp @@ -0,0 +1,14 @@ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "TestCpp.h" + +void TestClass::PrintMessage() +{ + printf("compiling a .cpp file works.\n"); +} + +#ifdef __cplusplus +}; +#endif /* __cplusplus */ \ No newline at end of file diff --git a/SDL_TestApp1/TestCpp.h b/SDL_TestApp1/TestCpp.h new file mode 100644 index 0000000..4cb4fc8 --- /dev/null +++ b/SDL_TestApp1/TestCpp.h @@ -0,0 +1,30 @@ +#pragma once + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef WIN32 +#include "../MyOS_1/Console_VGA.h" +#include "../MyOS_1/Interrupts/System_Calls.h" +//#undef _MSVC_VER +#undef _WIN32 +#define HAVE_LIBC 1 +#define SDL_ATOMIC_DISABLED 1 +#define SDL_EVENTS_DISABLED 1 +#define SDL_TIMERS_DISABLED 1 +#define HAVE_MALLOC 1 +#else +#include +#endif + +class TestClass +{ +public: + void PrintMessage(); +}; + +#ifdef __cplusplus +}; +#endif /* __cplusplus */ diff --git a/SDL_TestApp1_For_Windows/SDL_TestApp1_For_Windows.vcxproj b/SDL_TestApp1_For_Windows/SDL_TestApp1_For_Windows.vcxproj index f817456..25f995e 100644 --- a/SDL_TestApp1_For_Windows/SDL_TestApp1_For_Windows.vcxproj +++ b/SDL_TestApp1_For_Windows/SDL_TestApp1_For_Windows.vcxproj @@ -18,6 +18,10 @@ x64 + + + + {E287BF76-1C8A-41CE-8698-A412691721BC} Win32Proj @@ -145,9 +149,6 @@ true - - - diff --git a/SDL_TestApp1_For_Windows/SDL_TestApp1_For_Windows.vcxproj.filters b/SDL_TestApp1_For_Windows/SDL_TestApp1_For_Windows.vcxproj.filters index 0c9bee3..63a9f68 100644 --- a/SDL_TestApp1_For_Windows/SDL_TestApp1_For_Windows.vcxproj.filters +++ b/SDL_TestApp1_For_Windows/SDL_TestApp1_For_Windows.vcxproj.filters @@ -15,7 +15,10 @@ - + + Source Files + + Source Files diff --git a/SupportApps/AutoIncrementBuild/AutoIncrementBuild.sln b/SupportApps/AutoIncrementBuild/AutoIncrementBuild.sln new file mode 100644 index 0000000..f7779e3 --- /dev/null +++ b/SupportApps/AutoIncrementBuild/AutoIncrementBuild.sln @@ -0,0 +1,32 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AutoIncrementBuild", "AutoIncrementBuild\AutoIncrementBuild.vcxproj", "{5A5DC097-16F7-4A7B-B062-8D972F59C73D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5A5DC097-16F7-4A7B-B062-8D972F59C73D}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {5A5DC097-16F7-4A7B-B062-8D972F59C73D}.Debug|x64.ActiveCfg = Debug|x64 + {5A5DC097-16F7-4A7B-B062-8D972F59C73D}.Debug|x64.Build.0 = Debug|x64 + {5A5DC097-16F7-4A7B-B062-8D972F59C73D}.Debug|x86.ActiveCfg = Debug|Win32 + {5A5DC097-16F7-4A7B-B062-8D972F59C73D}.Debug|x86.Build.0 = Debug|Win32 + {5A5DC097-16F7-4A7B-B062-8D972F59C73D}.Release|Any CPU.ActiveCfg = Release|Win32 + {5A5DC097-16F7-4A7B-B062-8D972F59C73D}.Release|x64.ActiveCfg = Release|x64 + {5A5DC097-16F7-4A7B-B062-8D972F59C73D}.Release|x64.Build.0 = Release|x64 + {5A5DC097-16F7-4A7B-B062-8D972F59C73D}.Release|x86.ActiveCfg = Release|Win32 + {5A5DC097-16F7-4A7B-B062-8D972F59C73D}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/SupportApps/AutoIncrementBuild/AutoIncrementBuild/AutoIncrementBuild.cpp b/SupportApps/AutoIncrementBuild/AutoIncrementBuild/AutoIncrementBuild.cpp new file mode 100644 index 0000000..aee9fd7 --- /dev/null +++ b/SupportApps/AutoIncrementBuild/AutoIncrementBuild/AutoIncrementBuild.cpp @@ -0,0 +1,66 @@ +// AutoIncrementBuild.cpp : Updates a build number defined in a header file (with nothing else) +// +#include "stdafx.h" +#include +#include +#include +#include +using namespace std; + +// Nasty, nasty source + +// The last line of the file must be a definition name followed by a number or this won't work. +// See Build_Number.h in My_OS source for an exmaple formatting. +int main(int argc, char* argv[]) +{ + // open the build number header + fstream hFile, myfile2; + + string filename = "C:\\Users\\Administrator\\Documents\\Visual Studio 2015\\Projects\\MyOS\\MyOS_1\\Build_Number.h"; + + // Open a particular file if its name was given on the command-line + if (argc > 1) + { + filename = argv[1]; + } + + hFile.open(filename, ios::in | ios::out); + //myfile2.open(filename); + if (!hFile.is_open()) + { + cout << "Error: couldn't find " << filename << " input file!\n"; + return -1; + } + + string line = "test"; + string oldLine; + int gPos = 0, oldGPos = 0; + + // Read each line of the file, saving the file pointer at the beginning of the line, until we reach the last line + while (getline(hFile, line)) + { + oldGPos = gPos; + oldLine = line; + gPos = hFile.tellg(); + } + + // Stream in the string "BUILD_NUMBER" followed by an int. + istringstream lineStream(oldLine); + string buildVar; + int buildNumber; + lineStream >> buildVar >> buildNumber; + //cout << "String: " << buildVar << " number: " << buildNumber << endl; + + // increment build number + buildNumber++; + + // update the h file with the new definition + hFile.clear(); // Clear EOF bit of stream + hFile.seekg(oldGPos); // return to the beginning of the last line + + hFile << buildVar << " " << buildNumber; + hFile.flush(); + hFile.close(); + + return 0; +} \ No newline at end of file diff --git a/SupportApps/AutoIncrementBuild/AutoIncrementBuild/AutoIncrementBuild.vcxproj b/SupportApps/AutoIncrementBuild/AutoIncrementBuild/AutoIncrementBuild.vcxproj new file mode 100644 index 0000000..df97c37 --- /dev/null +++ b/SupportApps/AutoIncrementBuild/AutoIncrementBuild/AutoIncrementBuild.vcxproj @@ -0,0 +1,155 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {5A5DC097-16F7-4A7B-B062-8D972F59C73D} + Win32Proj + AutoIncrementBuild + 8.1 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + + + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SupportApps/AutoIncrementBuild/AutoIncrementBuild/AutoIncrementBuild.vcxproj.filters b/SupportApps/AutoIncrementBuild/AutoIncrementBuild/AutoIncrementBuild.vcxproj.filters new file mode 100644 index 0000000..b2cd1f4 --- /dev/null +++ b/SupportApps/AutoIncrementBuild/AutoIncrementBuild/AutoIncrementBuild.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/SupportApps/AutoIncrementBuild/AutoIncrementBuild/stdafx.cpp b/SupportApps/AutoIncrementBuild/AutoIncrementBuild/stdafx.cpp new file mode 100644 index 0000000..f2b986d --- /dev/null +++ b/SupportApps/AutoIncrementBuild/AutoIncrementBuild/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// AutoIncrementBuild.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/SupportApps/AutoIncrementBuild/AutoIncrementBuild/stdafx.h b/SupportApps/AutoIncrementBuild/AutoIncrementBuild/stdafx.h new file mode 100644 index 0000000..b005a83 --- /dev/null +++ b/SupportApps/AutoIncrementBuild/AutoIncrementBuild/stdafx.h @@ -0,0 +1,15 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#include +#include + + + +// TODO: reference additional headers your program requires here diff --git a/SupportApps/AutoIncrementBuild/AutoIncrementBuild/targetver.h b/SupportApps/AutoIncrementBuild/AutoIncrementBuild/targetver.h new file mode 100644 index 0000000..87c0086 --- /dev/null +++ b/SupportApps/AutoIncrementBuild/AutoIncrementBuild/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include diff --git a/SupportApps/CountLines.ahk b/SupportApps/CountLines.ahk new file mode 100644 index 0000000..de0fd50 --- /dev/null +++ b/SupportApps/CountLines.ahk @@ -0,0 +1,361 @@ +; I know; lines of code aren't a good metric, blah blah blah +; I would still like to know how many I've written :) +; This script isn't perfect and I'm sure there's many other/simpler ways to do this, but if that appealed to me, would I be writing an OS? :P + +TotalFiles := 0 +TotalDirectories := 0 +SourceFiles := 0 +SourceFilesCounted := 0 +NonSourceExts = dll +ExtensionsToParse = cs,c,cpp,h,ahk,hpp,cc,py,sh +;ExcludeFolders = SDL,My-Doom +SourceOnlyLines := 0 +CommentOnlyLines := 0 +SourceLinesWithComments := 0 +BlankLines := 0 +BracesOnlyLines := 0 +SkippedLines := 0 +TODOs := 0 +HACKs := 0 + +Directories := +SourceFileList := +Comments := + +SetWorkingDir, %A_ScriptDir%\.. + +; Let the user know that we're doing something +Progress, M2, (1 / 3), Counting Directories, Counting... + +; Just determine how many directories there are, for really big source trees (like ReactOS and Linux) +JustDirectories := 0 +Loop, Files, *, DR +{ + ; Even though this code isn't really meant for MyOS, I'll skip these directories for consistency: + IfInString, A_LoopFileFullPath,SDL\ + continue + IfInString A_LoopFileFullPath,My-Doom\ + continue + IfInString A_LoopFileFullPath,.git + continue + IfInString A_LoopFileFullPath,.vs + continue + IfInString A_LoopFileFullPath,font + continue + IfInString A_LoopFileFullPath,spf + continue + IfInString A_LoopFileFullPath,Debug + continue + IfInString A_LoopFileFullPath,Release + continue + IfInString A_LoopFileFullPath,x64 + continue + + JustDirectories += 1 +} + +Progress, R0-%JustDirectories% M2, (2 / 3), Counting Numer of Files, Counting... + +; Determine how many files and directories we need to scan +Loop, Files, *, DFR +{ + Progress, %TotalDirectories%, (2 / 3), Counting Numer of Files, Counting... + + ; Don't include files or folders which mostly contain source I didn't write + IfInString, A_LoopFileFullPath,SDL\ + continue + IfInString A_LoopFileFullPath,My-Doom\ + continue + IfInString A_LoopFileFullPath,.git + continue + IfInString A_LoopFileFullPath,.vs + continue + IfInString A_LoopFileFullPath,font + continue + IfInString A_LoopFileFullPath,spf + continue + IfInString A_LoopFileFullPath,Debug + continue + IfInString A_LoopFileFullPath,Release + continue + IfInString A_LoopFileFullPath,x64 + continue + + ; Don't include generated files + IfInString, A_LoopFileFullPath,TemporaryGeneratedFile + continue + + FileGetAttrib, Attributes, %A_LoopFileFullPath% + IfInString, Attributes, D + { + TotalDirectories += 1 + Directories := Directories . "`r`n" . A_LoopFileFullPath + } + else + { + TotalFiles += 1 + + if A_LoopFileExt in %ExtensionsToParse% + { + SourceFiles += 1 + SourceFileList := SourceFileList . "`r`n" . A_LoopFileFullPath + } + else + { + if (A_LoopFileExt <> "") + { + if A_LoopFileExt not in %NonSourceExts% + NonSourceExts = %NonSourceExts%,%A_LoopFileExt% + } + } + } +} + +; Display a window with a progress bar +;totalEverything := TotalFiles + TotalDirectories +Progress, R0-%SourceFiles% M2, %a_index%, %a_loopfilename%, Counting..., Counting Lines +Loop, Files, *, DFR +{ + Progress, %SourceFilesCounted%, %a_loopfilename%, Counting..., Counting Lines + IfNotInString, Attributes, D + { + ; Don't include files or folders which mostly contain source I didn't write + IfInString, A_LoopFileFullPath,SDL\ + continue + IfInString A_LoopFileFullPath,My-Doom\ + continue + IfInString A_LoopFileFullPath,.git + continue + IfInString A_LoopFileFullPath,.vs + continue + IfInString A_LoopFileFullPath,font + continue + IfInString A_LoopFileFullPath,spf + continue + IfInString A_LoopFileFullPath,Debug + continue + IfInString A_LoopFileFullPath,Release + continue + IfInString A_LoopFileFullPath,x64 + continue + + ; Don't include generated files + IfInString, A_LoopFileFullPath,TemporaryGeneratedFile + continue + + if A_LoopFileExt in %ExtensionsToParse% + { + CountLines(A_LoopFileFullPath) + SourceFilesCounted += 1 + } + else + { + if (A_LoopFileExt <> "") + { + if A_LoopFileExt not in %NonSourceExts% + NonSourceExts = %NonSourceExts%,%A_LoopFileExt% + } + } + } +} +Progress, Off + +; Format number with comma (From https://autohotkey.com/board/topic/41587-question-about-formating-numbers-1000-to-1000-how/ ) +VarSetCapacity( StringLines,32 ) +DllCall( "GetNumberFormat",UInt,0x0409,UInt,0,Str,SourceOnlyLines,UInt,0,Str,StringLines,Int,32 ) +StringTrimRight, StringLines, StringLines, 3 +;MsgBox, % StringLines + +;MsgBox %Directories% +CountSummary := +CountSummary .= NumericalFormat(SourceOnlyLines + SourceLinesWithComments + CommentOnlyLines) . " Total unique and meaningful lines`r`r" +CountSummary .= NumericalFormat(SourceOnlyLines + SourceLinesWithComments) . " Total lines with code`r" +CountSummary .= NumericalFormat(CommentOnlyLines + SourceLinesWithComments) . " Total lines with comments`r`r" +CountSummary .= NumericalFormat(SourceOnlyLines) . " lines with only code`r" +CountSummary .= NumericalFormat(SourceLinesWithComments) . " lines with comments and code`r" +CountSummary .= NumericalFormat(CommentOnlyLines) . " lines with only comments`r" +CountSummary .= NumericalFormat(BracesOnlyLines) . " lines with only braces`r" +CountSummary .= NumericalFormat(BlankLines) . " blank lines`r" +CountSummary .= NumericalFormat(TODOs) . " TODOs`r" +CountSummary .= NumericalFormat(HACKs) . " HACKs`r" +CountSummary .= "`rCounted in`r" +CountSummary .= NumericalFormat(SourceFiles) . " source files in`r" +CountSummary .= NumericalFormat(TotalDirectories) . " directories" + +; This can be used for debugging. Here I've set it out to show me lines with comments and code: +;Gui, Add, Edit, R50 w900 Multi vListingBox +;GuiControl,, ListingBox, %Comments% +;GuiControl,, ListingBox, %Directories% +;Gui, Show + +; Isolate the OS name from the working dir +StringGetPos, NameStart, A_WorkingDir,\,R +OSName := SubStr(A_WorkingDir, NameStart + 2) +MsgBox Results of scanning %OSName%:`r`r%CountSummary% +;`rNon-Source files with extensions of %NonSourceExts% +ExitApp ; Replace this with return during development + + +CountLines(sourceFile) +{ + global + local line + local inComment := false + local maxLines := 0 + + hasComment := false + + Loop, Read, %sourceFile% + { + MaxLines += 1 + } + + ;Progress, R1-%MaxLines%, , %a_loopfilename%, Counting..., Counting Lines + Loop, Read, %sourceFile% + { + + ;Progress, %A_Index%, %A_Index%, Counting..., Counting %sourceFile% - %A_Index% + line := Trim(A_LoopReadLine) + if (line <> "") + { + inComment := DetermineIfInComment(line, inComment) + + ;MsgBox %line%`r%inComment% + + if(inComment) + { + ;MsgBox In Comment + if(hasCode) + { + SourceLinesWithComments += 1 + Comments .= "`r`n" . line + } + else + CommentOnlyLines += 1 + } + else + { + ; not in a comment + if(hasComment) + { + if(hasCode) + { + SourceLinesWithComments += 1 + Comments .= "`r`n" . line + } + else + { + CommentOnlyLines += 1 + ;Comments .= "`r`n" . line + } + + } + else + { + ; no multi-block comments started here. + ; check for bracket-only lines + if(line <> "}" and line <> "{" and line <> "};") + { + ; line has more than brackets, check for inline comments + IfInString, line,// + { + if(InStr(line, "//") = 1) + CommentOnlyLines += 1 + else + { + SourceLinesWithComments += 1 + Comments .= "`r`n" . line + } + } + else + { + SourceOnlyLines += 1 + } + + IfInString line,HACK + HACKs += 1 + IfInString line,TODO + TODOs += 1 + } + else + BracesOnlyLines += 1 + } + } + } + else + BlankLines += 1 + } +} + +NumericalFormat(num) +{ + local returnString + ; Format number with comma (From https://autohotkey.com/board/topic/41587-question-about-formating-numbers-1000-to-1000-how/ ) + VarSetCapacity( returnString,32 ) + DllCall( "GetNumberFormat",UInt,0x0409,UInt,0,Str,num,UInt,0,Str,returnString,Int,32 ) + StringTrimRight, returnString, returnString, 3 + ;MsgBox, % StringLines + return returnString +} + +DetermineIfInComment(line, inComment) +{ + beginComment := "/*" + endComment := "*/" + global hasCode := false + global hasComment := false + while( strlen(line) <> 0 ) + { + if(inComment) + { + ; get the next occurrence of end comment + StringGetPos, EndPos, line,%endComment% + if(ErrorLevel = 1) + { + ; couldn't find end of comment, so we're still in a comment + hasComment := true + return true + } + + if(EndPos <> 0) + hasComment := true + + inComment := false + + endPos += 3 + + ;msgbox %line%`rEnd: %endpos% + line := SubStr(line, EndPos) + ;msgBox %line% + } + else + { + ; check for the next occurrence of begin comment + StringGetPos, BeginPos, line,%beginComment% + if(ErrorLevel = 1) + { + ; couldn't find beginning of comment, so we aren't in a comment + hasCode := true + return false + } + + if(BeginPos <> 0) + hasCode := true + + BeginPos += 3 + + inComment := true + + ;length := strlen(line) - BeginPos + ;msgbox %line%`rBegin: %beginpos%`rLength: %Length% + line := SubStr(line, BeginPos) + ;msgBox %line% + } + } + return inComment +} + +; Super-useful: reload the script everytime I press ctrl-s (every time I save the script I re-run it) +~^s:: +Reload +Exit \ No newline at end of file diff --git a/SupportApps/MapKeys.ahk b/SupportApps/MapKeys.ahk new file mode 100644 index 0000000..bf5436b --- /dev/null +++ b/SupportApps/MapKeys.ahk @@ -0,0 +1,23 @@ +GUI, new +Gui, Add, Edit, R20 w400 vMyEdit + +letterVar = A +var = `tMyOS_Keycodes[%letterVar%_PRESSED] = SDL_SCANCODE_%letterVar%; + +Transform, numberVar, Asc, %letterVar% + +Loop, 26 +{ + Transform, letterVar, Chr, %numberVar% + var = %var%`n`tMyOS_Keycodes[%letterVar%_PRESSED] = SDL_SCANCODE_%letterVar%; + numberVar += 1 +} + + + +GuiControl,, MyEdit, %var% +Gui, Show + +~^s:: +Reload +Exit \ No newline at end of file diff --git a/SupportApps/SimpleDebugger/App.config b/SupportApps/SimpleDebugger/App.config new file mode 100644 index 0000000..88fa402 --- /dev/null +++ b/SupportApps/SimpleDebugger/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/SupportApps/SimpleDebugger/Debugger.cs b/SupportApps/SimpleDebugger/Debugger.cs new file mode 100644 index 0000000..8f61d98 --- /dev/null +++ b/SupportApps/SimpleDebugger/Debugger.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SimpleDebugger +{ + class Debugger + { + } +} diff --git a/SupportApps/SimpleDebugger/MapFile.cs b/SupportApps/SimpleDebugger/MapFile.cs new file mode 100644 index 0000000..3b4345d --- /dev/null +++ b/SupportApps/SimpleDebugger/MapFile.cs @@ -0,0 +1,134 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SimpleDebugger +{ + class MapFile + { + public MapFile(string fileName) + { + filename = fileName; + } + + public void ParseFile() + { + string[] fileLines = File.ReadAllLines(filename); + + bool parsing = false; + foreach (string line in fileLines) + { + if(parsing) + { + if (line.Length == 0) + continue; + + if(line.Contains(" entry point at")) + { + parsing = false; + continue; + } + + // Skip the section:memory part and jump to the public name + string lineSub = line.Substring(21); + //System.Console.Write(lineSub + "\n"); + + string[] lineSplit = lineSub.Split(' '); + + //int spaces = 0; + int stage = 0; // stage 0 = public name; stage 1 = address; stage 2 = object name + foreach (string split in lineSplit) + { + if (split.Length == 0) + continue; + + if (split == "f" || split == "i") + continue; + + switch(stage) + { + case 0: + publicNames.Add(split); + break; + case 1: + addresses.Add(Convert.ToUInt32(split, 16)); + break; + case 2: + objectNames.Add(split); + break; + default: + System.Console.Write("Reached stage 3\n"); + break; + } + + ++stage; + /*for (int i = 0; i < spaces; ++i) + System.Console.Write(" "); + + spaces++; + System.Console.Write(split + "\n");*/ + } + } + else + { + // Not parsing yet, find the first line + if (line.Contains(" Address")) + parsing = true; + + //System.Console.Write(line + "\n"); + } + + } + } + + public string FindFunction(string hex) + { + UInt32 needle = Convert.ToUInt32(hex, 16); + + int i = 0; + UInt32 offset = 0; + // We need to find the index of the address that's equal to the address we're searching, + // or the index of the highest address that's less than the needle address + foreach(UInt32 address in addresses) + { + //if (needle > address) + // continue; + + if(needle == address) + { + // we're done + break; + } + + if(needle < address) + { + // we went too far + --i; + if (i >= 0) + offset = needle - addresses[i]; + break; + } + + ++i; + } + + if(i < 0) + { + return "
"; + } + + if (offset > 0) + return publicNames[i] + "+" + offset + " in " + objectNames[i]; + + return publicNames[i] + " in " + objectNames[i]; + } + + public string filename; + List publicNames = new List(); + List addresses = new List(); + List objectNames = new List(); + } +} diff --git a/SupportApps/SimpleDebugger/Program.cs b/SupportApps/SimpleDebugger/Program.cs new file mode 100644 index 0000000..57f18f2 --- /dev/null +++ b/SupportApps/SimpleDebugger/Program.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.IO; +using System.IO.Pipes; + + +namespace SimpleDebugger +{ + class Program + { + static void Main(string[] args) + { + MapFile mf = new MapFile("../../../../Release/MyOS_1.map"); + mf.ParseFile(); + //return; + + while (true) + { + using (NamedPipeClientStream pipeClient = + new NamedPipeClientStream(".", "MyOS_PIPE", PipeDirection.InOut)) + { + + // Connect to the pipe or wait until the pipe is available. + Console.Write("Attempting to connect to pipe..."); + pipeClient.Connect(); + + Console.WriteLine("Connected to pipe."); + Console.WriteLine("There are currently {0} pipe server instances open.", + pipeClient.NumberOfServerInstances); + using (StreamReader sr = new StreamReader(pipeClient)) + { + // Display the read text to the console + string temp; + bool awaitingModuleName = false; + bool canMap = false; + while ((temp = sr.ReadLine()) != null) + { + // If we see "Hello world!" we know the kernel restarted, and we should reload all map files + if(temp.Contains("Hello world!")) + { + Console.WriteLine("Reloading map files"); + mf.ParseFile(); + awaitingModuleName = false; + continue; + } + + if(temp == "Stack trace:") + { + awaitingModuleName = true; + continue; + } + + if(awaitingModuleName) + { + awaitingModuleName = false; + + // module name will be stored in temp + if (temp == "KERNEL PROCESS") + { + System.Console.WriteLine(temp); + System.Console.WriteLine("Using map file " + mf.filename + "\n"); + canMap = true; + continue; + } + else + { + System.Console.WriteLine("Don't know where to find map file for " + temp); + canMap = false; + } + } + + if (temp.Contains("0x") && canMap) + { + Console.WriteLine(mf.FindFunction(temp)); + } + else + { + // if address was in kernel space + if (temp.Contains("0x") && Convert.ToUInt32(temp, 16) >= 0xC0000000) + { + Console.WriteLine(mf.FindFunction(temp)); + } + else + Console.WriteLine("{0}", temp); + } + } + } + } + Console.Write("\nPipe closed, Reopening..."); + } + //Console.ReadLine(); + } + } +} diff --git a/SupportApps/SimpleDebugger/Properties/AssemblyInfo.cs b/SupportApps/SimpleDebugger/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..4098d6b --- /dev/null +++ b/SupportApps/SimpleDebugger/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SimpleDebugger")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SimpleDebugger")] +[assembly: AssemblyCopyright("Copyright © 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("5df601cc-b794-43c6-8138-3b9ed99f2843")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SupportApps/SimpleDebugger/SimpleDebugger.csproj b/SupportApps/SimpleDebugger/SimpleDebugger.csproj new file mode 100644 index 0000000..0a008ac --- /dev/null +++ b/SupportApps/SimpleDebugger/SimpleDebugger.csproj @@ -0,0 +1,62 @@ + + + + + Debug + AnyCPU + {5DF601CC-B794-43C6-8138-3B9ED99F2843} + Exe + Properties + SimpleDebugger + SimpleDebugger + v4.5.2 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TestApp1/TestApp1.c b/TestApp1/TestApp1.c index 5c5393e..e37d88b 100644 --- a/TestApp1/TestApp1.c +++ b/TestApp1/TestApp1.c @@ -10,7 +10,7 @@ int main() { - printf("Hello World from an .exe using a system call%s\nDid you know that the answer to life, the universe, and everything is %d?\n", " and printf()!", 42); + /*printf("Hello World from an .exe using a system call%s\nDid you know that the answer to life, the universe, and everything is %d?\n", " and printf()!", 42); if (malloc(1)) printf("malloc() success!\n"); @@ -59,13 +59,56 @@ int main() char * pch; pch = strrchr(str, 's'); printf("Last occurence of 's' found at %d \n", pch - str + 1); + */ + + // TODO: fix: + /* + printf("Press q to quit\n"); + + uint16_t key; + + while (true) + { + bool keyReady = readFromKeyboard(&key); + if (keyReady) + { + if(!(keyReady & 0x80)) + printf("%c\n", (char)key); + } + }*/ + + //printf("Done\n"); + + /*uint32_t spvar; + __asm + { + mov spvar, esp + } + printf("0x%lX\n", spvar);*/ + + timeDelayMS(500); + + printf("Hello World from an .exe using a system call%s\nDid you know that the answer to life, the universe, and everything is %d?\n", " and printf()!", 42); + + + //printf("This code will never be executed because of the call to exit()\n"); + + printf("Now printing a series of b's to test multitasking...\n"); + for(int i = 0; i < 20; ++i) + { + printf("b"); - printf("Done\n"); +//#ifdef __MYOS +#if 0 + MOUSE_STATE mouseState = getMouseState(); + printf("\n%d, %d\n", mouseState.mouseX, mouseState.mouseY); +#endif - exit(); + timeDelayMS(300); + } - printf("This code will never be executed because of the call to exit()\n"); + //exit(0); return 0; } \ No newline at end of file diff --git a/TestApp1/TestApp1.vcxproj b/TestApp1/TestApp1.vcxproj index 9d1d0e5..79b74ee 100644 --- a/TestApp1/TestApp1.vcxproj +++ b/TestApp1/TestApp1.vcxproj @@ -119,7 +119,7 @@ MinSpace false false - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + __MYOS;NDEBUG;_CONSOLE;HAVE_MALLOC;%(PreprocessorDefinitions) false MultiThreaded false diff --git a/TestApp2/TestApp2.c b/TestApp2/TestApp2.c new file mode 100644 index 0000000..aee1cfa --- /dev/null +++ b/TestApp2/TestApp2.c @@ -0,0 +1,63 @@ +// TestApp2.cpp : A super-simple application for testing multiprogramming with MyOS +// +#ifdef __MYOS +#include "../MyOS_1/Console_VGA.h" +#include "../MyOS_1/Interrupts/System_Calls.h" +#include "../MyOS_1/paging.h" +#include "../MyOS_1/misc.h" +#else +#include +#include +#include +#endif +#include +#include + + +uint32_t spBackup; + +void func2() +{ + printf("func2\n"); + + uint32_t spvar; + __asm + { + mov spvar, esp + } + printf("Value of esp: 0x%lX\n", spvar); + + //timeDelayMS(1); + //func2(); +} + +void func1() +{ + printf("func1\n"); + func2(); +} + +int main() +{ + printf("Here's a simple app the will continually print a character to the screen, for testing multi-programming\n"); + + // TODO: Why won't this work with large values of esp??? + __asm + { + mov [spBackup], esp + } + + printf("OK this seems to work... 0x%lX\n", spBackup); + func1(); + +#ifdef __MYOS + while (true) + { + printf("a"); + + timeDelayMS(150); + } +#endif + + return 0; +} \ No newline at end of file diff --git a/TestApp2/TestApp2.vcxproj b/TestApp2/TestApp2.vcxproj new file mode 100644 index 0000000..2dc221f --- /dev/null +++ b/TestApp2/TestApp2.vcxproj @@ -0,0 +1,174 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {04870E40-8ABF-4BD7-AED0-3885C7F535D7} + Win32Proj + TestApp2 + 8.1 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + + + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + Level3 + + + Disabled + false + false + __MYOS;NDEBUG;_CONSOLE;HAVE_MALLOC;%(PreprocessorDefinitions) + false + false + MultiThreaded + false + false + + + Native + false + true + false + %(AdditionalDependencies) + true + Default + 0x800000 + main + false + 0x100000 + 0x100000 + true + true + true + + + copy "$(TargetDir)$(TargetFileName)" C:\Users\Administrator\.VirtualBox\TFTP\$(TargetFileName) + Copying testapp2.exe to TFTP directory + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + + + /FAcs %(AdditionalOptions) + + + + + + \ No newline at end of file diff --git a/TestApp2/TestApp2.vcxproj.filters b/TestApp2/TestApp2.vcxproj.filters new file mode 100644 index 0000000..49572f2 --- /dev/null +++ b/TestApp2/TestApp2.vcxproj.filters @@ -0,0 +1,28 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/TestApp2ForWindows/TestApp2ForWindows.vcxproj b/TestApp2ForWindows/TestApp2ForWindows.vcxproj new file mode 100644 index 0000000..f85135b --- /dev/null +++ b/TestApp2ForWindows/TestApp2ForWindows.vcxproj @@ -0,0 +1,167 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {6BA12269-A558-4634-B51D-B61FD8143410} + Win32Proj + TestApp2ForWindows + 8.1 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + MultiByte + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + + + true + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + + + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + Level3 + + + Disabled + true + true + WIN32;__WIN32__;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + false + false + false + /FAcs %(AdditionalOptions) + + + Console + false + true + false + false + false + + + legacy_stdio_definitions.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + false + false + + + false + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + /FAcs %(AdditionalOptions) + + + + + + \ No newline at end of file diff --git a/TestApp2ForWindows/TestApp2ForWindows.vcxproj.filters b/TestApp2ForWindows/TestApp2ForWindows.vcxproj.filters new file mode 100644 index 0000000..2225782 --- /dev/null +++ b/TestApp2ForWindows/TestApp2ForWindows.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file