diff --git a/libc/Makefile b/libc/Makefile
index 82a9fdd8..0a6decfe 100644
--- a/libc/Makefile
+++ b/libc/Makefile
@@ -135,6 +135,7 @@ close.o \
$(CPUDIR)/fork.o \
$(CPUDIR)/signal.o \
$(CPUDIR)/syscall.o \
+dispmsg_issue.o \
dlfcn.o \
dup.o \
env.o \
diff --git a/libc/dispmsg_issue.cpp b/libc/dispmsg_issue.cpp
new file mode 100644
index 00000000..16beaccd
--- /dev/null
+++ b/libc/dispmsg_issue.cpp
@@ -0,0 +1,33 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ This file is part of the Sortix C Library.
+
+ The Sortix C Library 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.
+
+ The Sortix C Library 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 the Sortix C Library. If not, see .
+
+ dispmsg_issue.cpp
+ Send a message to the display engine.
+
+*******************************************************************************/
+
+#include
+#include
+
+DEFN_SYSCALL2(int, sys_dispmsg_issue, SYSCALL_DISPMSG_ISSUE, void*, size_t);
+
+extern "C" int dispmsg_issue(void* ptr, size_t size)
+{
+ return sys_dispmsg_issue(ptr, size);
+}
diff --git a/libc/include/sys/display.h b/libc/include/sys/display.h
new file mode 100644
index 00000000..541a9965
--- /dev/null
+++ b/libc/include/sys/display.h
@@ -0,0 +1,38 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ This file is part of the Sortix C Library.
+
+ The Sortix C Library 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.
+
+ The Sortix C Library 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 the Sortix C Library. If not, see .
+
+ sys/display.h
+ Display message passing.
+
+*******************************************************************************/
+
+#ifndef INCLUDE_SYS_DISPLAY_H
+#define INCLUDE_SYS_DISPLAY_H 1
+
+#include
+#include
+#include
+
+__BEGIN_DECLS
+
+int dispmsg_issue(void* ptr, size_t size);
+
+__END_DECLS
+
+#endif
diff --git a/sortix/Makefile b/sortix/Makefile
index 8e62966d..12adf8f9 100644
--- a/sortix/Makefile
+++ b/sortix/Makefile
@@ -92,6 +92,7 @@ crc32.o \
descriptors.o \
device.o \
directory.o \
+dispmsg.o \
elf.o \
filesystem.o \
fs/devfs.o \
diff --git a/sortix/dispmsg.cpp b/sortix/dispmsg.cpp
new file mode 100644
index 00000000..5d53038e
--- /dev/null
+++ b/sortix/dispmsg.cpp
@@ -0,0 +1,340 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ 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 .
+
+ dispmsg.cpp
+ User-space message-based interface for video framework access.
+
+*******************************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+#include
+#include
+
+#include "syscall.h"
+#include "dispmsg.h"
+
+namespace Sortix {
+namespace DisplayMessage {
+
+const uint64_t ONE_AND_ONLY_DEVICE = 0;
+const uint64_t ONE_AND_ONLY_CONNECTOR = 0;
+
+__attribute__((unused))
+static char* StringOfCrtcMode(struct dispmsg_crtc_mode mode)
+{
+ char bppstr[sizeof(mode.fb_format) * 3];
+ char xresstr[sizeof(mode.view_xres) * 3];
+ char yresstr[sizeof(mode.view_yres) * 3];
+ char magicstr[sizeof(mode.magic) * 3];
+ snprintf(bppstr, sizeof(bppstr), "%ju", (uintmax_t) mode.fb_format);
+ snprintf(xresstr, sizeof(xresstr), "%ju", (uintmax_t) mode.view_xres);
+ snprintf(yresstr, sizeof(yresstr), "%ju", (uintmax_t) mode.view_yres);
+ snprintf(magicstr, sizeof(magicstr), "%ju", (uintmax_t) mode.magic);
+ char* drivername = Video::GetDriverName(mode.driver_index);
+ if ( !drivername )
+ return NULL;
+ char* ret = String::Combine(10,
+ "driver=", drivername, ","
+ "bpp=", bppstr, ","
+ "width=", xresstr, ","
+ "height=", yresstr, ","
+ "modeid=", magicstr);
+ delete[] drivername;
+ return ret;
+}
+
+__attribute__((unused))
+struct dispmsg_crtc_mode CrtcModeOfString(const char* string, uint64_t driverid)
+{
+ char* xstr = NULL;
+ char* ystr = NULL;
+ char* bppstr = NULL;
+ char* modeidstr = NULL;
+ char* unsupportedstr = NULL;
+ struct dispmsg_crtc_mode ret;
+ ret.control = 0;
+ if ( !strcmp(string, "driver=none") )
+ return ret;
+ if ( !ReadParamString(string,
+ "width", &xstr,
+ "height", &ystr,
+ "bpp", &bppstr,
+ "modeid", &modeidstr,
+ "unsupported", &unsupportedstr,
+ NULL, NULL) )
+ return ret;
+ ret.driver_index = driverid;
+ ret.view_xres = xstr ? atol(xstr) : 0;
+ delete[] xstr;
+ ret.view_yres = ystr ? atol(ystr) : 0;
+ delete[] ystr;
+ ret.fb_format = bppstr ? atol(bppstr) : 0;
+ delete[] bppstr;
+ ret.magic = modeidstr ? atoll(modeidstr) : 0;
+ delete[] modeidstr;
+ if ( !unsupportedstr )
+ ret.control = 1;
+ delete[] unsupportedstr;
+ return ret;
+}
+
+__attribute__((unused))
+static bool TransmitString(struct dispmsg_string* dest, const char* str)
+{
+ size_t size = strlen(str) + 1;
+ size_t dest_size = dest->byte_size;
+ dest->byte_size = size;
+ if ( dest_size < size )
+ return errno = ERANGE, false;
+ strcpy(dest->str, str);
+ return true;
+}
+
+__attribute__((unused))
+static char* ReceiveString(struct dispmsg_string* src)
+{
+ if ( !src->byte_size )
+bad_input:
+ return errno = EINVAL, (char*) NULL;
+ char* ret = new char[src->byte_size];
+ if ( !ret )
+ return NULL;
+ memcpy(ret, src->str, src->byte_size);
+ if ( ret[src->byte_size-1] != '\0' ) { delete[] ret; goto bad_input; }
+ return ret;
+}
+
+static int EnumerateDevices(void* ptr, size_t size)
+{
+ if ( size != sizeof(struct dispmsg_enumerate_devices) )
+ return errno = EINVAL, -1;
+ struct dispmsg_enumerate_devices* msg =
+ (struct dispmsg_enumerate_devices*) ptr;
+ // TODO: HACK: Only one device is currently supported by our backend.
+ size_t num_devices = 1;
+ if ( msg->devices_length < num_devices )
+ {
+ msg->devices_length = num_devices;
+ return errno = ERANGE, -1;
+ }
+ msg->devices[0] = ONE_AND_ONLY_DEVICE;
+ return 0;
+}
+
+static int GetDriverCount(void* ptr, size_t size)
+{
+ if ( size != sizeof(struct dispmsg_get_driver_count) )
+ return errno = EINVAL, -1;
+ struct dispmsg_get_driver_count* msg =
+ (struct dispmsg_get_driver_count*) ptr;
+ if ( msg->device != ONE_AND_ONLY_DEVICE )
+ return errno = EINVAL, -1;
+ msg->driver_count = Video::GetNumDrivers();
+ return 0;
+}
+
+static int GetDriverName(void* ptr, size_t size)
+{
+ if ( size != sizeof(struct dispmsg_get_driver_name) )
+ return errno = EINVAL, -1;
+ struct dispmsg_get_driver_name* msg =
+ (struct dispmsg_get_driver_name* ) ptr;
+ if ( msg->device != ONE_AND_ONLY_DEVICE )
+ return errno = EINVAL, -1;
+ char* name = Video::GetDriverName(msg->driver_index);
+ if ( !name )
+ return -1;
+ bool success = TransmitString(&msg->name, name);
+ delete[] name;
+ return success ? 0 : -1;
+}
+
+static int GetDriver(void* ptr, size_t size)
+{
+ if ( size != sizeof(struct dispmsg_get_driver) )
+ return errno = EINVAL, -1;
+ struct dispmsg_get_driver* msg = (struct dispmsg_get_driver*) ptr;
+ if ( msg->device != ONE_AND_ONLY_DEVICE )
+ return errno = EINVAL, -1;
+ msg->driver_index = Video::GetCurrentDriverIndex();
+ return 0;
+}
+
+static int SetDriver(void* ptr, size_t size)
+{
+ if ( size != sizeof(struct dispmsg_set_driver) )
+ return errno = EINVAL, -1;
+ struct dispmsg_set_driver* msg = (struct dispmsg_set_driver*) ptr;
+ if ( msg->device != ONE_AND_ONLY_DEVICE )
+ return errno = EINVAL, -1;
+ return errno = ENOSYS, -1;
+}
+
+static int SetCrtcMode(void* ptr, size_t size)
+{
+ if ( size != sizeof(struct dispmsg_set_crtc_mode) )
+ return errno = EINVAL, -1;
+ struct dispmsg_set_crtc_mode* msg = (struct dispmsg_set_crtc_mode*) ptr;
+ if ( msg->device != ONE_AND_ONLY_DEVICE )
+ return errno = EINVAL, -1;
+ if ( msg->connector != ONE_AND_ONLY_CONNECTOR )
+ return errno = EINVAL, -1;
+ char* modestr = StringOfCrtcMode(msg->mode);
+ if ( !modestr )
+ return -1;
+ bool success = Video::SwitchMode(modestr);
+ delete[] modestr;
+ return success ? 0 : -1;
+}
+
+static int GetCrtcMode(void* ptr, size_t size)
+{
+ if ( size != sizeof(struct dispmsg_get_crtc_mode) )
+ return errno = EINVAL, -1;
+ struct dispmsg_get_crtc_mode* msg = (struct dispmsg_get_crtc_mode*) ptr;
+ if ( msg->device != ONE_AND_ONLY_DEVICE )
+ return errno = EINVAL, -1;
+ if ( msg->connector != ONE_AND_ONLY_CONNECTOR )
+ return errno = EINVAL, -1;
+ char* modestr = Video::GetCurrentMode();
+ if ( !modestr )
+ return -1;
+ msg->mode = CrtcModeOfString(modestr, Video::GetCurrentDriverIndex());
+ delete[] modestr;
+ return 0;
+}
+
+static int GetCrtcModes(void* ptr, size_t size)
+{
+ if ( size != sizeof(struct dispmsg_get_crtc_modes) )
+ return errno = EINVAL, -1;
+ struct dispmsg_get_crtc_modes* msg = (struct dispmsg_get_crtc_modes*) ptr;
+ if ( msg->device != ONE_AND_ONLY_DEVICE )
+ return errno = EINVAL, -1;
+ if ( msg->connector != ONE_AND_ONLY_CONNECTOR )
+ return errno = EINVAL, -1;
+ size_t nummodes;
+ char** modes = Video::GetModes(&nummodes);
+ if ( !modes )
+ return -1;
+ size_t dest_length = msg->modes_length;
+
+ int ret;
+ if ( nummodes <= dest_length )
+ {
+ ret = 0;
+ for ( size_t i = 0; i < nummodes; i++ )
+ {
+ const char* modestr = modes[i];
+ uint64_t driver_index = Video::LookupDriverIndexOfMode(modestr);
+ msg->modes[i] = CrtcModeOfString(modestr, driver_index);
+ }
+ }
+ else
+ {
+ errno = ERANGE;
+ ret = -1;
+ }
+ msg->modes_length = nummodes;
+ for ( size_t i = 0; i < nummodes; i++ )
+ delete[] modes[i];
+ delete[] modes;
+ return ret;
+}
+
+static int GetMemorySize(void* ptr, size_t size)
+{
+ if ( size != sizeof(struct dispmsg_get_memory_size) )
+ return errno = EINVAL, -1;
+ struct dispmsg_get_memory_size* msg =
+ (struct dispmsg_get_memory_size*) ptr;
+ msg->memory_size = Video::FrameSize();
+ return 0;
+}
+
+static int WriteMemory(void* ptr, size_t size)
+{
+ if ( size != sizeof(struct dispmsg_write_memory) )
+ return errno = EINVAL, -1;
+ struct dispmsg_write_memory* msg = (struct dispmsg_write_memory*) ptr;
+ if ( msg->device != ONE_AND_ONLY_DEVICE )
+ return errno = EINVAL, -1;
+ if ( OFF_MAX < msg->offset )
+ return errno = EOVERFLOW, -1;
+ off_t offset = msg->offset;
+ if ( Video::WriteAt(offset, msg->src, msg->size) < 0 )
+ return -1;
+ return 0;
+}
+
+static int ReadMemory(void* ptr, size_t size)
+{
+ if ( size != sizeof(struct dispmsg_read_memory) )
+ return errno = EINVAL, -1;
+ struct dispmsg_read_memory* msg = (struct dispmsg_read_memory*) ptr;
+ if ( msg->device != ONE_AND_ONLY_DEVICE )
+ return errno = EINVAL, -1;
+ if ( OFF_MAX < msg->offset )
+ return errno = EOVERFLOW, -1;
+ off_t offset = msg->offset;
+ if ( Video::ReadAt(offset, msg->dst, msg->size) < 0 )
+ return -1;
+ return 0;
+}
+
+// TODO: Secure this system call against bad user-space pointers.
+static int sys_dispmsg_issue(void* ptr, size_t size)
+{
+ struct dispmsg_header* hdr = (struct dispmsg_header*) ptr;
+ if ( size < sizeof(*hdr) )
+ return errno = EINVAL, -1;
+ switch ( hdr->msgid )
+ {
+ case DISPMSG_ENUMERATE_DEVICES: return EnumerateDevices(ptr, size);
+ case DISPMSG_GET_DRIVER_COUNT: return GetDriverCount(ptr, size);
+ case DISPMSG_GET_DRIVER_NAME: return GetDriverName(ptr, size);
+ case DISPMSG_GET_DRIVER: return GetDriver(ptr, size);
+ case DISPMSG_SET_DRIVER: return SetDriver(ptr, size);
+ case DISPMSG_SET_CRTC_MODE: return SetCrtcMode(ptr, size);
+ case DISPMSG_GET_CRTC_MODE: return GetCrtcMode(ptr, size);
+ case DISPMSG_GET_CRTC_MODES: return GetCrtcModes(ptr, size);
+ case DISPMSG_GET_MEMORY_SIZE: return GetMemorySize(ptr, size);
+ case DISPMSG_WRITE_MEMORY: return WriteMemory(ptr, size);
+ case DISPMSG_READ_MEMORY: return ReadMemory(ptr, size);
+ default:
+ return errno = ENOSYS, -1;
+ }
+}
+
+void Init()
+{
+ Syscall::Register(SYSCALL_DISPMSG_ISSUE, (void*) sys_dispmsg_issue);
+}
+
+} // namespace DisplayMessage
+} // namespace Sortix
diff --git a/sortix/dispmsg.h b/sortix/dispmsg.h
new file mode 100644
index 00000000..32d46f10
--- /dev/null
+++ b/sortix/dispmsg.h
@@ -0,0 +1,36 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ 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 .
+
+ dispmsg.h
+ User-space message-based interface for video framework access.
+
+*******************************************************************************/
+
+#ifndef SORTIX_DISPMSG_H
+#define SORTIX_DISPMSG_H
+
+namespace Sortix {
+namespace DisplayMessage {
+
+void Init();
+
+} // namespace DisplayMessage
+} // namespace Sortix
+
+#endif
diff --git a/sortix/include/sortix/display.h b/sortix/include/sortix/display.h
new file mode 100644
index 00000000..d723feba
--- /dev/null
+++ b/sortix/include/sortix/display.h
@@ -0,0 +1,162 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ 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 .
+
+ display.h
+ Display message declarations.
+
+*******************************************************************************/
+
+#ifndef SORTIX_INCLUDE_DISPLAY_H
+#define SORTIX_INCLUDE_DISPLAY_H
+
+#include
+#include
+
+__BEGIN_DECLS
+
+struct dispmsg_string
+{
+ size_t byte_size; // Including the terminating NUL-byte.
+ char* str;
+};
+
+struct dispmsg_crtc_mode
+{
+ uint64_t driver_index;
+ uint64_t magic;
+ uint32_t control;
+ uint32_t fb_format;
+ uint32_t view_xres;
+ uint32_t view_yres;
+ uint64_t fb_location;
+ uint64_t pitch;
+ uint32_t surf_off_x;
+ uint32_t surf_off_y;
+ uint32_t start_x;
+ uint32_t start_y;
+ uint32_t end_x;
+ uint32_t end_y;
+ uint32_t desktop_height;
+};
+
+struct dispmsg_header
+{
+ uint64_t msgid; // in
+};
+
+#define DISPMSG_ENUMERATE_DEVICES 0x00
+struct dispmsg_enumerate_devices
+{
+ uint64_t msgid; // in
+ size_t devices_length; // in, out
+ uint64_t* devices; // in, *out
+};
+
+#define DISPMSG_GET_DRIVER_COUNT 0x01
+struct dispmsg_get_driver_count
+{
+ uint64_t msgid; // in
+ uint64_t device; // in
+ uint64_t driver_count; // out
+};
+
+#define DISPMSG_GET_DRIVER_NAME 0x02
+struct dispmsg_get_driver_name
+{
+ uint64_t msgid; // in
+ uint64_t device; // in
+ uint64_t driver_index; // in
+ struct dispmsg_string name; // out
+};
+
+#define DISPMSG_GET_DRIVER 0x03
+struct dispmsg_get_driver
+{
+ uint64_t msgid; // in
+ uint64_t device; // in
+ uint64_t driver_index; // out
+};
+
+#define DISPMSG_SET_DRIVER 0x04
+struct dispmsg_set_driver
+{
+ uint64_t msgid; // in
+ uint64_t device; // in
+ uint64_t driver_index; // in
+};
+
+#define DISPMSG_SET_CRTC_MODE 0x05
+struct dispmsg_set_crtc_mode
+{
+ uint64_t msgid; // in
+ uint64_t device; // in
+ uint64_t connector; // in
+ struct dispmsg_crtc_mode mode; // in
+};
+
+#define DISPMSG_GET_CRTC_MODE 0x06
+struct dispmsg_get_crtc_mode
+{
+ uint64_t msgid; // in
+ uint64_t device; // in
+ uint64_t connector; // in
+ struct dispmsg_crtc_mode mode; // out
+};
+
+#define DISPMSG_GET_CRTC_MODES 0x07
+struct dispmsg_get_crtc_modes
+{
+ uint64_t msgid; // in
+ uint64_t device; // in
+ uint64_t connector; // in
+ size_t modes_length; // in, out
+ struct dispmsg_crtc_mode* modes; // in, *out
+};
+
+#define DISPMSG_GET_MEMORY_SIZE 0x08
+struct dispmsg_get_memory_size
+{
+ uint64_t msgid; // in
+ uint64_t device; // in
+ uint64_t memory_size; // out
+};
+
+#define DISPMSG_WRITE_MEMORY 0x09
+struct dispmsg_write_memory
+{
+ uint64_t msgid; // in
+ uint64_t device; // in
+ uint64_t offset; // in
+ size_t size; // in
+ uint8_t* src; // in, *in
+};
+
+#define DISPMSG_READ_MEMORY 0x0A
+struct dispmsg_read_memory
+{
+ uint64_t msgid; // in
+ uint64_t device; // in
+ uint64_t offset; // in
+ size_t size; // in
+ uint8_t* dst; // in, *out
+};
+
+__END_DECLS
+
+#endif
diff --git a/sortix/include/sortix/syscallnum.h b/sortix/include/sortix/syscallnum.h
index b7ac1bf1..105d812e 100644
--- a/sortix/include/sortix/syscallnum.h
+++ b/sortix/include/sortix/syscallnum.h
@@ -77,6 +77,7 @@
#define SYSCALL_TCGETWINSIZE 52
#define SYSCALL_RAISE 53
#define SYSCALL_OPENAT 54
-#define SYSCALL_MAX_NUM 55 /* index of highest constant + 1 */
+#define SYSCALL_DISPMSG_ISSUE 55
+#define SYSCALL_MAX_NUM 56 /* index of highest constant + 1 */
#endif
diff --git a/sortix/kernel.cpp b/sortix/kernel.cpp
index 9a64de31..dd909531 100644
--- a/sortix/kernel.cpp
+++ b/sortix/kernel.cpp
@@ -66,6 +66,7 @@
#include "mount.h"
#include "directory.h"
#include "interrupt.h"
+#include "dispmsg.h"
#include "fs/devfs.h"
// Keep the stack size aligned with $CPU/base.s
@@ -277,6 +278,9 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
// Initialize the BGA driver.
BGA::Init();
+ // Initialize the Display Message framework.
+ DisplayMessage::Init();
+
// Now that the base system has been loaded, it's time to go threaded. First
// we create an object that represents this thread.
Process* system = new Process;