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;