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