diff --git a/libmaxsi/Makefile b/libmaxsi/Makefile index 727c4c47..5f0f503e 100644 --- a/libmaxsi/Makefile +++ b/libmaxsi/Makefile @@ -44,8 +44,8 @@ c/h/stdio.h COMMONOBJS=c++.o thread.o io.o memory.o string.o error.o format.o SORTIXOBJS:=$(addprefix sortix/,$(COMMONOBJS)) -LIBMAXSIOBJS:=$(COMMONOBJS) -HEADERS=error.h io.h memory.h platform.h string.h syscall.h thread.h types.h format.h +LIBMAXSIOBJS:=$(COMMONOBJS) sortix-vga.o +HEADERS=error.h io.h memory.h platform.h string.h syscall.h thread.h types.h format.h sortix-vga.h OBJS:=$(LIBMAXSIOBJS) BINS:=libmaxsi.so diff --git a/libmaxsi/hsrc/sortix-vga.h b/libmaxsi/hsrc/sortix-vga.h new file mode 100644 index 00000000..c4f24711 --- /dev/null +++ b/libmaxsi/hsrc/sortix-vga.h @@ -0,0 +1,76 @@ +/****************************************************************************** + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011. + + This file is part of LibMaxsi. + + LibMaxsi is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + LibMaxsi is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + more details. + + You should have received a copy of the GNU Lesser General Public License + along with LibMaxsi. If not, see . + + sortix-vga.h + Provides access to the VGA framebuffer under Sortix. This is highly + unportable and is very likely to be removed or changed radically. + +******************************************************************************/ + +#ifndef LIBMAXSI_SORTIX_VGA_H +#define LIBMAXSI_SORTIX_VGA_H + +namespace System +{ + namespace VGA + { + // This is the contents of a VGA framebuffer used in text mode. The + // lower 8 lower bits correspond to an ASCII character, the next 4 bits + // is the text color, and the upper 4 bits are the background color. + struct Frame + { + public: + // The width of each line in characters. + const static size_t width = 80; + + // The number of lines. + const static size_t height = 25; + + // The data containing the frame. + uint16_t text[width * height]; + + // An opaque file descriptor that defines this frame. Used to change + // the current frame or deleting frames. + int fd; + + // Beware: The kernel may or may keep more hidden data here. You may + // not depend on the usage of this area. + + private: + // Only the kernel may create an instance of this structure. + Frame() { } + + }; + + // Allocates a framebuffer able to store VGA data. This buffer is not + // relocatable and must remain at this position. + Frame* CreateFrame(); + + // Sets the process' current VGA frame. If the process currently have + // focus, then this is the frame shown on the screen. Any edits done + // on this frame while it is active will be shown instantly on the + // screen if the process have focus. + int ChangeFrame(int fd); + + // Deletes a frame. This is equivalent to IO::Close(fd). + int DeleteFrame(int fd); + } +} + +#endif diff --git a/libmaxsi/sortix-vga.cpp b/libmaxsi/sortix-vga.cpp new file mode 100644 index 00000000..292d3745 --- /dev/null +++ b/libmaxsi/sortix-vga.cpp @@ -0,0 +1,54 @@ +/****************************************************************************** + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011. + + This file is part of LibMaxsi. + + LibMaxsi is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + LibMaxsi is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + more details. + + You should have received a copy of the GNU Lesser General Public License + along with LibMaxsi. If not, see . + + sortix-vga.cpp + Provides access to the VGA framebuffer under Sortix. This is highly + unportable and is very likely to be removed or changed radically. + +******************************************************************************/ + +#include "platform.h" +#include "syscall.h" +#include "sortix-vga.h" + +namespace System +{ + namespace VGA + { + + DEFN_SYSCALL0(Frame*, SysCreateFrame, 5); + DEFN_SYSCALL1(int, SysChangeFrame, 6, int); + DEFN_SYSCALL1(int, SysDeleteFrame, 7, int); + + Frame* CreateFrame() + { + return SysCreateFrame(); + } + + int ChangeFrame(int fd) + { + return SysChangeFrame(fd); + } + + int DeleteFrame(int fd) + { + return SysDeleteFrame(fd); + } + } +} diff --git a/sortix/Makefile b/sortix/Makefile index 9bd869e7..f4c2c664 100644 --- a/sortix/Makefile +++ b/sortix/Makefile @@ -43,7 +43,7 @@ DEFINES:=$(DEFINES) -DINITRD CPPFLAGSRELEASE=-s -O3 CPPFLAGSDEBUG= CPPFLAGS=-I.. $(CPUDEFINES) $(CPUFLAGS) -std=gnu++0x -Wall -Wextra -nostdlib -fno-builtin -nostartfiles -nodefaultlibs -fno-exceptions -fno-rtti -fno-stack-protector $(DEFINES) $(CPPFLAGSRELEASE) -OBJS=$(CPUOBJS) kernel.o descriptor_tables.o isr.o time.o log.o iprintable.o panic.o keyboard.o memorymanagement.o scheduler.o syscall.o application.o pong.o sound.o pci.o uart.o conway.o test.o http.o vgaterminal.o serialterminal.o descriptors.o device.o ../libmaxsi/libmaxsi-sortix.a +OBJS=$(CPUOBJS) kernel.o descriptor_tables.o isr.o time.o log.o iprintable.o panic.o keyboard.o memorymanagement.o scheduler.o syscall.o application.o pong.o sound.o pci.o uart.o conway.o test.o http.o vgaterminal.o serialterminal.o descriptors.o device.o vga.o ../libmaxsi/libmaxsi-sortix.a JSOBJS:=$(subst .o,-js.o,$(OBJS)) all: sortix.bin diff --git a/sortix/syscall.cpp b/sortix/syscall.cpp index 509decd9..0e36950d 100644 --- a/sortix/syscall.cpp +++ b/sortix/syscall.cpp @@ -31,6 +31,7 @@ #include "iprintable.h" #include "log.h" #include "panic.h" +#include "vga.h" namespace Sortix { @@ -47,7 +48,7 @@ namespace Sortix #endif } - const size_t NumSyscalls = 5; + const size_t NumSyscalls = 8; const Syscall Syscalls[NumSyscalls] = { &Scheduler::SysCreateThread, @@ -55,6 +56,9 @@ namespace Sortix &Scheduler::SysSleep, &Scheduler::SysUSleep, &SysStdOutPrint, + &VGA::SysCreateFrame, + &VGA::SysChangeFrame, + &VGA::SysDeleteFrame, }; void Init() diff --git a/sortix/vga.cpp b/sortix/vga.cpp new file mode 100644 index 00000000..3e95f4b3 --- /dev/null +++ b/sortix/vga.cpp @@ -0,0 +1,185 @@ +/****************************************************************************** + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011. + + This file is part of Sortix. + + Sortix is free software: you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation, either version 3 of the License, or (at your option) any later + version. + + Sortix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + + You should have received a copy of the GNU General Public License along + with Sortix. If not, see . + + vga.h + A Video Graphics Array driver. + +******************************************************************************/ + +#include "platform.h" +#include +#include "vga.h" +#include "memorymanagement.h" +#include "scheduler.h" + +using namespace Maxsi; + +namespace Sortix +{ + namespace VGA + { + uint16_t* const vga = (uint16_t* const) 0xB8000; + + DevVGAFrame* currentframe; + + void Init() + { + currentframe = NULL; + } + + void SysCreateFrame(CPU::InterruptRegisters* R) + { + addr_t page = Page::Get(); + if ( page == NULL ) { R->eax = 0; return; } + + Process* process = CurrentProcess(); + addr_t mapto = Page::AlignUp(process->_endcodesection); + UserFrame* userframe = (UserFrame*) mapto; + + // TODO: Check if mapto collides with any other memory section! + + if ( !VirtualMemory::MapUser(mapto, page) ) + { + Page::Put(page); R->eax = 0; return; + } + + Memory::Set(userframe, 0, sizeof(UserFrame)); + + DevVGAFrame* frame = new DevVGAFrame(); + if ( frame == NULL ) + { + VirtualMemory::UnmapUser(mapto); + Page::Put(page); R->eax = 0; return; + } + + int fd = process->descriptors.Allocate(frame); + if ( fd < 0 ) + { + delete frame; + VirtualMemory::UnmapUser(mapto); + Page::Put(page); R->eax = 0; return; + } + + userframe->fd = fd; + + frame->process = process; + frame->physical = page; + frame->userframe = userframe; + + process->_endcodesection = mapto + 0x1000; + + R->eax = mapto; + } + + void SysChangeFrame(CPU::InterruptRegisters* R) + { + int fd = (int) R->ebx; + + Process* process = CurrentProcess(); + Device* device = process->descriptors.Get(fd); + if ( device == NULL ) { R->eax = -1; return; } + + if ( !device->IsType(Device::VGABUFFER) ) { R->eax = -2; return; } + + DevVGAFrame* frame = (DevVGAFrame*) device; + + ASSERT(frame->process == process); + ASSERT(frame->physical != 0); + ASSERT(frame->userframe != NULL); + ASSERT(frame->onscreen == (frame == currentframe)); + + // TODO: Check if userframe is actually user-space writable! + + //Log::PrintF("changeframe: fd = %u, frame = 0x%p, currentframe = 0x%p\n", fd, frame, currentframe); + + // Check if we need to do anything. + if ( frame == currentframe ) { R->eax = 0; return; } + + // If there is already a currently used frame? If so, swap it from + // the VGA memory and back to the RAM. This should be done + // transparently such that the program doesn't feel the difference. + if ( currentframe != NULL ) + { + ASSERT(currentframe->physical != frame->physical); + ASSERT(currentframe->userframe != frame->userframe); + ASSERT(currentframe->onscreen == true); + + if ( currentframe->process != process ) + { + VirtualMemory::SwitchAddressSpace(currentframe->process->GetAddressSpace()); + } + + // Remap the pages in the owning process. + // TODO: Check if userframe is actually user-space writable! + VirtualMemory::UnmapUser((addr_t) currentframe->userframe); + VirtualMemory::MapUser((addr_t) currentframe->userframe, currentframe->physical); + + // Restore the contents of this frame to the VGA framebuffer. + Memory::Copy(currentframe->userframe, vga, sizeof(UserFrame)); + + if ( currentframe->process != process ) + { + VirtualMemory::SwitchAddressSpace(process->GetAddressSpace()); + } + + currentframe->onscreen = false; + } + + // Now move the contents of this frame to the VGA framebuffer. + Memory::Copy(vga, frame->userframe, sizeof(UserFrame)); + + // Remap the pages such that the current process now uses the vga. + VirtualMemory::UnmapUser((addr_t) frame->userframe); + VirtualMemory::MapUser((addr_t) frame->userframe, (addr_t) vga); + + frame->onscreen = true; + currentframe = frame; + } + + void SysDeleteFrame(CPU::InterruptRegisters* R) + { + int fd = (int) R->ebx; + + Process* process = CurrentProcess(); + Device* device = process->descriptors.Get(fd); + process->descriptors.Free(fd); + + if ( device == NULL ) { R->eax = -1; return; } + if ( !device->Close() ) { R->eax = -1; return; } + R->eax = 0; + } + } + + DevVGAFrame::DevVGAFrame() + { + process = NULL; + userframe = NULL; + physical = 0; + onscreen = false; + } + + DevVGAFrame::~DevVGAFrame() + { + if ( process != NULL ) { ASSERT(CurrentProcess() == process); } + if ( userframe != NULL ) { VirtualMemory::UnmapUser((addr_t) userframe); } + if ( physical != 0 ) { Page::Put(physical); } + } + + nat DevVGAFrame::Flags() { return Device::VGABUFFER; } +} diff --git a/sortix/vga.h b/sortix/vga.h index a5607ae6..42b1feb0 100644 --- a/sortix/vga.h +++ b/sortix/vga.h @@ -25,8 +25,12 @@ #ifndef SORTIX_VGA_H #define SORTIX_VGA_H +#include "device.h" + namespace Sortix { + class Process; + namespace VGA { // TODO: Move these to a better place @@ -55,7 +59,36 @@ namespace Sortix uint16_t Data[80*25]; }; + + struct UserFrame : public Frame + { + int fd; + }; + + void Init(); + + // System Calls. + void SysCreateFrame(CPU::InterruptRegisters* R); + void SysChangeFrame(CPU::InterruptRegisters* R); + void SysDeleteFrame(CPU::InterruptRegisters* R); } + + class DevVGAFrame : public Device + { + public: + virtual nat Flags(); + + public: + DevVGAFrame(); + ~DevVGAFrame(); + + public: + Process* process; + addr_t physical; + VGA::UserFrame* userframe; + bool onscreen; + + }; } #endif