diff options
author | Alex Auvolat <alex@adnab.me> | 2015-03-11 11:51:01 +0100 |
---|---|---|
committer | Alex Auvolat <alex@adnab.me> | 2015-03-11 11:51:01 +0100 |
commit | bde334e6393b142d9953328e9ea2881ce88a1a7b (patch) | |
tree | f3ed7bbc6c8a534fccbd2cf653e7ecb1f24b9fd4 /src | |
parent | aa5e2760711c092e1235105ebf097ac594512370 (diff) | |
download | kogata-bde334e6393b142d9953328e9ea2881ce88a1a7b.tar.gz kogata-bde334e6393b142d9953328e9ea2881ce88a1a7b.zip |
Begin work on GIP (Graphics Initiation Protocol)
Diffstat (limited to 'src')
-rw-r--r-- | src/kernel/core/idt.c | 2 | ||||
-rw-r--r-- | src/kernel/user/process.c | 4 | ||||
-rw-r--r-- | src/lib/include/gip.h | 55 | ||||
-rw-r--r-- | src/lib/include/mainloop.h | 47 | ||||
-rw-r--r-- | src/lib/include/proto/gip.h | 118 | ||||
-rw-r--r-- | src/lib/libkogata/Makefile | 5 | ||||
-rw-r--r-- | src/lib/libkogata/gip.c | 207 | ||||
-rw-r--r-- | src/lib/libkogata/mainloop.c | 135 | ||||
-rw-r--r-- | src/sysbin/giosrv/Makefile | 2 | ||||
-rw-r--r-- | src/sysbin/giosrv/main.c | 112 | ||||
-rw-r--r-- | src/sysbin/init/Makefile | 2 | ||||
-rw-r--r-- | src/sysbin/init/main.c | 2 | ||||
-rw-r--r-- | src/sysbin/login/Makefile | 2 | ||||
-rw-r--r-- | src/sysbin/login/main.c | 65 |
14 files changed, 732 insertions, 26 deletions
diff --git a/src/kernel/core/idt.c b/src/kernel/core/idt.c index b94695f..f99460f 100644 --- a/src/kernel/core/idt.c +++ b/src/kernel/core/idt.c @@ -122,7 +122,7 @@ void idt_irq_handler(registers_t *regs) { if (regs->err_code == 0) { irq0_handler(regs, st); } else { - dbg_printf("irq%d.", regs->err_code); + /*dbg_printf("irq%d.", regs->err_code);*/ if (irq_handlers[regs->err_code] != 0) { irq_handlers[regs->err_code](regs); diff --git a/src/kernel/user/process.c b/src/kernel/user/process.c index e46fde8..542c294 100644 --- a/src/kernel/user/process.c +++ b/src/kernel/user/process.c @@ -726,7 +726,7 @@ void probe_for_read(const void* addr, size_t len) { process_t *proc = current_process(); user_region_t *r = find_user_region(proc, addr); if (r == 0 || addr + len > r->addr + r->size || !(r->mode & MM_READ)) { - dbg_printf("Access violation on read at 0x%p len 0x%p in process %d : exiting.\n", + dbg_printf("Access violation (kernel reading user data) at 0x%p len 0x%p in process %d : exiting.\n", addr, len, proc->pid); current_process_exit(PS_FAILURE, FAIL_SC_SEGFAULT); } @@ -736,7 +736,7 @@ void probe_for_write(const void* addr, size_t len) { process_t *proc = current_process(); user_region_t *r = find_user_region(proc, addr); if (r == 0 || addr + len > r->addr + r->size || !(r->mode & MM_WRITE)) { - dbg_printf("Access violation on write at 0x%p len 0x%p in process %d : exiting.\n", + dbg_printf("Access violation (kernel writing user data) at 0x%p len 0x%p in process %d : exiting.\n", addr, len, proc->pid); current_process_exit(PS_FAILURE, FAIL_SC_SEGFAULT); } diff --git a/src/lib/include/gip.h b/src/lib/include/gip.h new file mode 100644 index 0000000..98b4655 --- /dev/null +++ b/src/lib/include/gip.h @@ -0,0 +1,55 @@ +#pragma once + +// Not thread safe + +#include <hashtbl.h> + +#include <proto/gip.h> +#include <mainloop.h> + +typedef struct gip_handler gip_handler_t; + +typedef void (*noarg_gip_callback_t)(gip_handler_t *s, gip_msg_header *m); +typedef void (*gip_reply_callback_t)(gip_handler_t *s, gip_msg_header *m, void* data); + +typedef struct { + noarg_gip_callback_t + reset, initiate, ok, failure, + enable_features, disable_features, + query_mode, set_mode, switch_buffer; + void (*buffer_info)(gip_handler_t *s, gip_msg_header *m, gip_buffer_info_msg *i); + void (*mode_info)(gip_handler_t *s, gip_msg_header *m, gip_mode_info_msg *i); + void (*buffer_damage)(gip_handler_t *s, gip_msg_header *m, gip_buffer_damage_msg *i); + void (*unknown_msg)(gip_handler_t *s, gip_msg_header *m); + void (*fd_error)(gip_handler_t *s); +} gip_handler_callbacks_t; + +typedef struct gip_handler { + gip_handler_callbacks_t* cb; + void* data; + + gip_msg_header msg_buf; + gip_buffer_info_msg buffer_info_msg_buf; + gip_mode_info_msg mode_info_msg_buf; + gip_buffer_damage_msg buffer_damage_msg_buf; + + hashtbl_t *requests_in_progress; + uint32_t next_req_id; + + mainloop_fd_t mainloop_item; +} gip_handler_t; + +gip_handler_t *new_gip_handler(gip_handler_callbacks_t *cb, void* data); +void delete_gip_handler(gip_handler_t *h); + +// GIP send messages + +bool gip_cmd(gip_handler_t *h, gip_msg_header *msg, void* msg_data, gip_reply_callback_t cb, void* cb_data); + +bool gip_reply(gip_handler_t *h, gip_msg_header *orig_request, gip_msg_header *msg, void* msg_data); +bool gip_reply_fail(gip_handler_t *h, gip_msg_header *o); +bool gip_reply_ok(gip_handler_t *h, gip_msg_header *o); + +bool gip_notify(gip_handler_t *h, gip_msg_header *msg, void* msg_data); + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/lib/include/mainloop.h b/src/lib/include/mainloop.h new file mode 100644 index 0000000..1e71ffb --- /dev/null +++ b/src/lib/include/mainloop.h @@ -0,0 +1,47 @@ +#pragma once + +// These functions are not thread safe, their purpose +// is to multiplex several IO operations on a +// single thread. + +#include <syscall.h> + +#define MAINLOOP_MAX_WR_BUFS 4 + +typedef struct mainloop_fd mainloop_fd_t; + +typedef void (*buf_full_callback_t)(mainloop_fd_t *fd); +typedef void (*fd_error_callback_t)(mainloop_fd_t *fd); + +typedef struct { + size_t size, written; + void* buf; + bool must_free; +} mainloop_wr_buf_t; + +typedef struct mainloop_fd { + fd_t fd; + + size_t rd_buf_expect_size, rd_buf_filled; + void* rd_buf; + + mainloop_wr_buf_t wr_bufs[MAINLOOP_MAX_WR_BUFS]; + + void* data; + + buf_full_callback_t rd_on_full; + fd_error_callback_t on_error; + + mainloop_fd_t *next; +} mainloop_fd_t; + +void mainloop_add_fd(mainloop_fd_t* fd); +void mainloop_rm_fd(mainloop_fd_t* fd); + +void mainloop_expect(mainloop_fd_t *fd, void* buf, size_t size, buf_full_callback_t cb); +bool mainloop_nonblocking_write(mainloop_fd_t *fd, void* buf, size_t size, bool must_free_buf); + +void mainloop_run(); +void mainloop_exit(); + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/lib/include/proto/gip.h b/src/lib/include/proto/gip.h new file mode 100644 index 0000000..f79e29f --- /dev/null +++ b/src/lib/include/proto/gip.h @@ -0,0 +1,118 @@ +#pragma once + +#include <proto/fb.h> + +#include <syscall.h> + +/* + Definition of the GIP protocol (Graphics Initiation Protocol). + This is a protocol meant for communication on a local machine between + a process providing a graphics window (screen & input) and a client + process that does user interaction. + + Examples : + - giosrv makes the hardware available as a GIP server + - the login manager is a GIP client of giosrv + - the user window manager is a GIP client of the login manager + (when a user session is active, the login manager is mostly a GIP proxy, + but it intercepts the Ctrl+Alt+Del keyboard shortcut to terminate/lock + the active user session) + - each window managed by the WM acts as a GIP server. + - the GUI library basically knows how to be a GIP client that does actually + usefull stuff (displaying a gui) + + Features of the GIP protocol for OUTPUT : + - as an option, mode setting (for when the buffer is a display) + - as an option, buffer resizing (for when the buffer is a window) + TODO: interacts somehow with WMP (window managing protocol) + - server-side allocation of a framebuffer + - as an option, double buffering (server allocates two buffers, + client tells server to switch buffers) + - "buffer damage" notification from clients on active buffer, + (not necessary, and disabled, when the buffer is actually the + display output itself) + (a buffer switch request implies a global buffer damage notification) + + Features of the GIP protocol for KEYBOARD INPUT : + - raw keycode notification from server on keypress/keyrelease + + Features of the GIP protocol for MOUSE INPUT : + - as an option, raw mouse data input + - as an option, mouse data parsing & notification in terms + of (mouse_x, mouse_y) + - as an option, cursor display handling (server mouse data + parsing must be enabled) + + The active/inactive features are defined on a per-GIP-channel basis. + + Typical GIP session : + - C: RESET + - S: INTIATE (available features) + - S: BUFFER_INFO (base buffer) + - C: ENABLE_FEATURES (desired features) + - S: OK + - S: BUFFER_INFO (double buffering is enabled! new buffers needed) + - C: draws on buffer 1 + - C: SWITCH_BUFFER 1 + - S does not answer to SWITCH_BUFFER messages (they happen too often!) + - C: draws on buffer 0 + - C: SWITCH_BUFFER 0 + - ... + */ + +// GIP features +#define GIPF_DOUBLE_BUFFER 0x01 +#define GIPF_DAMAGE_NOTIF 0x02 +#define GIPF_MODESET 0x04 +// #define GIP_F_RESIZING 0x08 // TODO semantics for this shit +#define GIPF_MOUSE_XY 0x10 +#define GIPF_MOUSE_CURSOR 0x20 + +// GIP message IDs +// ---- GIPC : commands, expect a reply +// ---- GIPR : reply to a command +// ---- GIPN : notification, no reply expected +#define GIPC_RESET 0 // client: plz open new session +#define GIPR_INITIATE 1 // server: ok, here is supported feature list +#define GIPR_OK 2 +#define GIPR_FAILURE 3 +#define GIPC_ENABLE_FEATURES 4 +#define GIPC_DISABLE_FEATURES 5 + +#define GIPN_BUFFER_INFO 10 // server: buffer #i is at #token and has #geom +#define GIPC_QUERY_MODE 11 // client: what about mode #i? +#define GIPR_MODE_INFO 12 // server: mode #i is xxyy +#define GIPC_SET_MODE 13 // client: please switch to mode #i +#define GIPN_BUFFER_DAMAGE 14 // client: please update region +#define GIPC_SWITCH_BUFFER 15 // client: please switch to buffer b (0 or 1) + +#define GIPN_KEY_DOWN 20 // server: key k down +#define GIPN_KEY_UP 21 // server: key k up + +#define GIPN_MOUSE_DATA 30 // server: raw mouse data +#define GIPN_MOUSE_XY 31 // server: mouse moved at xy ; client: put mouse at xy +#define GIPN_MOUSE_PRESSED 32 // server: button b pressed +#define GIPN_MOUSE_RELEASED 33 // server: button b released +#define GIPC_LOAD_CURSOR 34 // client: this is graphics for cursor #i +#define GIPC_SET_CURSOR 35 // client: please use cursor #i (0 = hide cursor) + +typedef struct { + uint32_t code; // message type + uint32_t req_id; // for reply messages, code of the reply + uint32_t arg; +} gip_msg_header; + +typedef struct { + token_t tok; + framebuffer_info_t geom; +} gip_buffer_info_msg; + +typedef struct { + framebuffer_info_t geom; +} gip_mode_info_msg; + +typedef struct { + uint32_t x, y, w, h; +} gip_buffer_damage_msg; + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/lib/libkogata/Makefile b/src/lib/libkogata/Makefile index ee00fa3..48c6bc2 100644 --- a/src/lib/libkogata/Makefile +++ b/src/lib/libkogata/Makefile @@ -1,6 +1,7 @@ -OBJ = start.o malloc.o debug.o syscall.o user_region.o +OBJ = start.o malloc.o debug.o syscall.o user_region.o \ + mainloop.o gip.o -LIB = ../../common/libkogata/libkogata.lib +LIB = ../../common/libkogata/libkogata.lib ../../common/libalgo/libalgo.lib ../../common/libc/libc.lib CFLAGS = -I ../include -I ../../common/include diff --git a/src/lib/libkogata/gip.c b/src/lib/libkogata/gip.c new file mode 100644 index 0000000..3b6084c --- /dev/null +++ b/src/lib/libkogata/gip.c @@ -0,0 +1,207 @@ +#include <string.h> +#include <malloc.h> + +#include <gip.h> + +typedef struct { + gip_reply_callback_t cb; + void* data; +} gip_cmd_t; + +void giph_msg_header(mainloop_fd_t *fd); +void giph_buffer_info(mainloop_fd_t *fd); +void giph_mode_info(mainloop_fd_t *fd); +void giph_buffer_damage(mainloop_fd_t *fd); + +void gip_error(mainloop_fd_t *fd); + +gip_handler_t *new_gip_handler(gip_handler_callbacks_t *cb, void* data) { + gip_handler_t *h = (gip_handler_t*)malloc(sizeof(gip_handler_t)); + if (h == 0) return 0; + + memset(h, 0, sizeof(gip_handler_t)); + + h->cb = cb; + h->data = data; + + h->requests_in_progress = create_hashtbl(id_key_eq_fun, id_hash_fun, free_val); + if (h->requests_in_progress == 0) { + free(h); + return 0; + } + + h->mainloop_item.data = h; + h->mainloop_item.on_error = &gip_error; + h->next_req_id = 1; + + mainloop_expect(&h->mainloop_item, &h->msg_buf, sizeof(gip_msg_header), giph_msg_header); + + return h; +} + +void delete_gip_handler(gip_handler_t *h) { + delete_hashtbl(h->requests_in_progress); + free(h); +} + +bool gip_send_msg(gip_handler_t *h, gip_msg_header *msg, void* msg_data) { + // ---- Write message + size_t extra_size = 0; + if (msg->code == GIPN_BUFFER_INFO) extra_size = sizeof(gip_buffer_info_msg); + if (msg->code == GIPR_MODE_INFO) extra_size = sizeof(gip_mode_info_msg); + if (msg->code == GIPN_BUFFER_DAMAGE) extra_size = sizeof(gip_buffer_damage_msg); + + bool ok = false; + + char* buf = (char*)malloc(sizeof(gip_msg_header) + extra_size); + + if (buf != 0) { + memcpy(buf, msg, sizeof(gip_msg_header)); + if (extra_size) memcpy(buf + sizeof(gip_msg_header), msg_data, extra_size); + ok = mainloop_nonblocking_write(&h->mainloop_item, buf, sizeof(gip_msg_header) + extra_size, true); + } + + if (!ok) { + dbg_printf("GIP warning: failed to send message (type %d)\n", msg->code); + if (buf) free(buf); + } + + return ok; +} + +bool gip_cmd(gip_handler_t *h, gip_msg_header *msg, void* msg_data, gip_reply_callback_t cb, void* cb_data) { + msg->req_id = 0; + + // ---- Add callback handler + if (cb != 0) { + gip_cmd_t *c = (gip_cmd_t*)malloc(sizeof(gip_cmd_t)); + if (c == 0) return false; + + c->cb = cb; + c->data = cb_data; + + while(msg->req_id == 0) msg->req_id = (h->next_req_id++); + + bool add_ok = hashtbl_add(h->requests_in_progress, (void*)msg->req_id, c); + if (!add_ok) { + free(c); + return false; + } + } + + bool ok = gip_send_msg(h, msg, msg_data); + if (!ok && msg->req_id != 0) hashtbl_remove(h->requests_in_progress, (void*)msg->req_id); + + return ok; +} + +bool gip_reply(gip_handler_t *h, gip_msg_header *orig_request, gip_msg_header *msg, void* msg_data) { + msg->req_id = orig_request->req_id; + return gip_send_msg(h, msg, msg_data); +} + +bool gip_reply_fail(gip_handler_t *h, gip_msg_header *o) { + gip_msg_header m = { + .code = GIPR_FAILURE, + .arg = 0, + }; + return gip_reply(h, o, &m, 0); +} + +bool gip_reply_ok(gip_handler_t *h, gip_msg_header *o) { + gip_msg_header m = { + .code = GIPR_OK, + .arg = 0, + }; + return gip_reply(h, o, &m, 0); +} + +bool gip_notify(gip_handler_t *h, gip_msg_header *msg, void* msg_data) { + msg->req_id = 0; + return gip_send_msg(h, msg, msg_data); +} + +// ---- Message handlers + +void giph_got_reply(gip_handler_t *h, gip_msg_header *msg) { + gip_cmd_t *c = (gip_cmd_t*)hashtbl_find(h->requests_in_progress, (void*)msg->req_id);; + if (c != 0) { + c->cb(h, msg, c->data); + hashtbl_remove(h->requests_in_progress, (void*)msg->req_id); + } +} + +void giph_msg_header(mainloop_fd_t *fd) { + gip_handler_t *h = (gip_handler_t*)fd->data; + + int code = h->msg_buf.code; + noarg_gip_callback_t use_cb = 0; + if (code == GIPC_RESET) { + use_cb = h->cb->reset; + } else if (code == GIPR_INITIATE) { + use_cb = h->cb->initiate; + giph_got_reply(h, &h->msg_buf); + } else if (code == GIPR_OK) { + use_cb = h->cb->ok; + giph_got_reply(h, &h->msg_buf); + } else if (code == GIPR_FAILURE) { + use_cb = h->cb->failure; + giph_got_reply(h, &h->msg_buf); + } else if (code == GIPC_ENABLE_FEATURES) { + use_cb = h->cb->enable_features; + } else if (code == GIPC_DISABLE_FEATURES) { + use_cb = h->cb->disable_features; + } else if (code == GIPC_QUERY_MODE) { + use_cb = h->cb->query_mode; + } else if (code == GIPC_SET_MODE) { + use_cb = h->cb->set_mode; + } else if (code == GIPC_SWITCH_BUFFER) { + use_cb = h->cb->switch_buffer; + } else if (code == GIPN_BUFFER_INFO) { + mainloop_expect(fd, &h->buffer_info_msg_buf, sizeof(gip_buffer_info_msg), giph_buffer_info); + } else if (code == GIPR_MODE_INFO) { + mainloop_expect(fd, &h->mode_info_msg_buf, sizeof(gip_mode_info_msg), giph_mode_info); + // this is a reply but we cannot call giph_got_reply immediately since more data is needed + // giph_got_reply(h, id); + } else if (code == GIPN_BUFFER_DAMAGE) { + mainloop_expect(fd, &h->buffer_damage_msg_buf, sizeof(gip_buffer_damage_msg), giph_buffer_damage); + } else { + use_cb = h->cb->unknown_msg; + } + + if (use_cb) use_cb(h, &h->msg_buf); +} + +void giph_buffer_info(mainloop_fd_t *fd) { + gip_handler_t *h = (gip_handler_t*)fd->data; + + if (h->cb->buffer_info) h->cb->buffer_info(h, &h->msg_buf, &h->buffer_info_msg_buf); + + mainloop_expect(&h->mainloop_item, &h->msg_buf, sizeof(gip_msg_header), giph_msg_header); +} + +void giph_mode_info(mainloop_fd_t *fd) { + gip_handler_t *h = (gip_handler_t*)fd->data; + + if (h->cb->mode_info) h->cb->mode_info(h, &h->msg_buf, &h->mode_info_msg_buf); + + // call giph_got_reply with more data ? + + mainloop_expect(&h->mainloop_item, &h->msg_buf, sizeof(gip_msg_header), giph_msg_header); +} + +void giph_buffer_damage(mainloop_fd_t *fd) { + gip_handler_t *h = (gip_handler_t*)fd->data; + + if (h->cb->buffer_damage) h->cb->buffer_damage(h, &h->msg_buf, &h->buffer_damage_msg_buf); + + mainloop_expect(&h->mainloop_item, &h->msg_buf, sizeof(gip_msg_header), giph_msg_header); +} + +void gip_error(mainloop_fd_t *fd) { + gip_handler_t *h = (gip_handler_t*)fd->data; + + if (h->cb->fd_error) h->cb->fd_error(h); +} + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/lib/libkogata/mainloop.c b/src/lib/libkogata/mainloop.c new file mode 100644 index 0000000..d3c0c50 --- /dev/null +++ b/src/lib/libkogata/mainloop.c @@ -0,0 +1,135 @@ +#include <malloc.h> +#include <string.h> + +#include <mainloop.h> + +mainloop_fd_t *mainloop_fds = 0; +bool mainloop_fds_change = false; +bool mainloop_must_exit = false; + +void mainloop_add_fd(mainloop_fd_t* fd) { + mainloop_fds_change = true; + + fd->next = mainloop_fds; + mainloop_fds = fd; + + fd->rd_buf_filled = 0; +} + +void mainloop_rm_fd(mainloop_fd_t* fd) { + mainloop_fds_change = true; + + if (mainloop_fds == fd) { + mainloop_fds = fd->next; + } else { + for (mainloop_fd_t *it = mainloop_fds; it->next != 0; it = it->next) { + if (it->next == fd) { + it->next = fd->next; + break; + } + } + } +} + +void mainloop_expect(mainloop_fd_t *fd, void* buf, size_t size, buf_full_callback_t cb) { + fd->rd_buf = buf; + fd->rd_on_full = cb; + fd->rd_buf_expect_size = size; + fd->rd_buf_filled = 0; +} + +bool mainloop_nonblocking_write(mainloop_fd_t *fd, void* buf, size_t size, bool must_free_buf) { + for (int i = 0; i < MAINLOOP_MAX_WR_BUFS; i++) { + if (fd->wr_bufs[i].buf == 0) { + fd->wr_bufs[i].buf = buf; + fd->wr_bufs[i].written = 0; + fd->wr_bufs[i].size = size; + fd->wr_bufs[i].must_free = must_free_buf; + + return true; + } + } + + return false; +} + +void mainloop_run() { + sel_fd_t *sel_arg = 0; + int nfds = 0; + + mainloop_fds_change = true; + mainloop_must_exit = false; + while(!mainloop_must_exit) { + if (mainloop_fds_change) { + nfds = 0; + for (mainloop_fd_t *fd = mainloop_fds; fd != 0; fd = fd->next) + nfds++; + + if (sel_arg != 0) free(sel_arg); + sel_arg = (sel_fd_t*)malloc(nfds * sizeof(sel_fd_t)); + if (sel_arg == 0) { + dbg_printf("(mainloop) Out of memory.\n"); + return; + } + + + mainloop_fds_change = false; + } + + { // Setup flags we are waiting for + int i = 0; + for (mainloop_fd_t *fd = mainloop_fds; fd != 0; fd = fd->next) { + sel_arg[i].fd = fd->fd; + sel_arg[i].req_flags = + (fd->rd_buf != 0 ? SEL_READ : 0) + | (fd->wr_bufs[0].buf != 0 ? SEL_WRITE : 0) | SEL_ERROR; + i++; + } + } + + // ---- Do the select + bool ok = select(sel_arg, nfds, -1); + if (!ok) { + dbg_printf("(mainloop) Failed to select.\n"); + free(sel_arg); + return; + } + + { // Parse result + int i = 0; + for (mainloop_fd_t *fd = mainloop_fds; fd != 0 && !mainloop_fds_change; fd = fd->next) { + if (sel_arg[i].got_flags & SEL_ERROR) { + fd->on_error(fd); + } else if ((sel_arg[i].got_flags & SEL_READ) && fd->rd_buf != 0) { + fd->rd_buf_filled += + read(fd->fd, 0, fd->rd_buf_expect_size - fd->rd_buf_filled, fd->rd_buf + fd->rd_buf_filled); + if (fd->rd_buf_filled == fd->rd_buf_expect_size) { + fd->rd_buf_filled = 0; + fd->rd_on_full(fd); + } + } else if ((sel_arg[i].got_flags & SEL_WRITE) && fd->wr_bufs[0].buf != 0) { + size_t remain_size = fd->wr_bufs[0].size - fd->wr_bufs[0].written; + void* write_ptr = fd->wr_bufs[0].buf + fd->wr_bufs[0].written; + + fd->wr_bufs[0].written += write(fd->fd, 0, remain_size, write_ptr); + + if (fd->wr_bufs[0].written == fd->wr_bufs[0].size) { + if (fd->wr_bufs[0].must_free) free(fd->wr_bufs[0].buf); + for (int i = 1; i < MAINLOOP_MAX_WR_BUFS; i++) { + fd->wr_bufs[i-1] = fd->wr_bufs[i]; + } + memset(&fd->wr_bufs[MAINLOOP_MAX_WR_BUFS-1].buf, 0, sizeof(mainloop_wr_buf_t)); + } + } + i++; + } + } + } +} + +void mainloop_exit() { + mainloop_must_exit = true; +} + + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/sysbin/giosrv/Makefile b/src/sysbin/giosrv/Makefile index 102bf4c..9adc05a 100644 --- a/src/sysbin/giosrv/Makefile +++ b/src/sysbin/giosrv/Makefile @@ -1,7 +1,7 @@ OBJ = main.o -LIB = ../../lib/libkogata/libkogata.lib ../../common/libc/libc.lib +LIB = ../../lib/libkogata/libkogata.lib CFLAGS = -I ./include -I ../../common/include -I ../../lib/include diff --git a/src/sysbin/giosrv/main.c b/src/sysbin/giosrv/main.c index 7827670..9dfd697 100644 --- a/src/sysbin/giosrv/main.c +++ b/src/sysbin/giosrv/main.c @@ -6,29 +6,117 @@ #include <debug.h> #include <user_region.h> -#include <proto/fb.h> +#include <gip.h> + +typedef struct { + framebuffer_info_t mode; + fd_t fd; + uint32_t features; +} giosrv_t; + +void reset(gip_handler_t *s, gip_msg_header *p); +void enable_features(gip_handler_t *s, gip_msg_header *p); +void disable_features(gip_handler_t *s, gip_msg_header *p); +void query_mode(gip_handler_t *s, gip_msg_header *p); +void set_mode(gip_handler_t *s, gip_msg_header *p); +void unknown_msg(gip_handler_t *s, gip_msg_header *p); +void fd_error(gip_handler_t *s); + +gip_handler_callbacks_t giosrv_cb = { + .reset = reset, + .initiate = 0, + .ok = 0, + .failure = 0, + .enable_features = enable_features, + .disable_features = disable_features, + .query_mode = query_mode, + .set_mode = set_mode, + .buffer_info = 0, + .mode_info = 0, + .buffer_damage = 0, + .unknown_msg = unknown_msg, + .fd_error = fd_error, +}; int main(int argc, char **argv) { dbg_print("[giosrv] Starting up.\n"); - fd_t fbdev = open("io:/display/vesa", FM_IOCTL | FM_READ | FM_WRITE | FM_MMAP); - if (fbdev == 0) PANIC("Could not open fbdev"); + giosrv_t srv; + + srv.fd = open("io:/display/vesa", FM_IOCTL | FM_READ | FM_WRITE | FM_MMAP); + if (srv.fd == 0) PANIC("Could not open fbdev"); - framebuffer_info_t i; - int r = ioctl(fbdev, IOCTL_FB_GET_INFO, &i); - dbg_printf("[giosrv] ioctl -> %d\n", r); + + int r = ioctl(srv.fd, IOCTL_FB_GET_INFO, &srv.mode); ASSERT(r == 1); - dbg_printf("[giosrv] Running on FB %dx%d\n", i.width, i.height); + dbg_printf("[giosrv] Running on FB %dx%d\n", srv.mode.width, srv.mode.height); - void* fb_map = region_alloc(i.height * i.pitch, "Framebuffer"); - ASSERT(fb_map != 0); + gip_handler_t *h = new_gip_handler(&giosrv_cb, &srv); + ASSERT(h != 0); - ASSERT(mmap_file(fbdev, 0, fb_map, i.height * i.pitch, MM_READ | MM_WRITE)); - memset(fb_map, 0, i.height * i.pitch); + h->mainloop_item.fd = 1; + mainloop_add_fd(&h->mainloop_item); + mainloop_run(); - while(true); // nothing to do + dbg_printf("[giosrv] Main loop exited, terminating.\n"); return 0; } +void send_buffer_info(gip_handler_t *h, giosrv_t *s) { + gip_msg_header msg = { + .code = GIPN_BUFFER_INFO, + .arg = 0, + }; + gip_buffer_info_msg msg_data; + + msg_data.geom = s->mode; + if (!gen_token(s->fd, &msg_data.tok)) { + dbg_printf("Could not generate token for buffer_info_msg.\n"); + } else { + dbg_printf("Token: %x %x\n", ((uint32_t*)&msg_data.tok)[0], ((uint32_t*)&msg_data.tok)[1]); + gip_notify(h, &msg, &msg_data); + } +} + +void reset(gip_handler_t *h, gip_msg_header *p) { + giosrv_t *s = (giosrv_t*)h->data; + + s->features = 0; + + // ---- Send initiate message + gip_msg_header msg = { + .code = GIPR_INITIATE, + .arg = GIPF_MODESET + }; + gip_reply(h, p, &msg, 0); + + // ---- Send buffer information + send_buffer_info(h, s); +} + +void enable_features(gip_handler_t *h, gip_msg_header *p) { + gip_reply_fail(h, p); +} + +void disable_features(gip_handler_t *h, gip_msg_header *p) { + gip_reply_fail(h, p); +} + +void query_mode(gip_handler_t *h, gip_msg_header *p) { + // TODO +} + +void set_mode(gip_handler_t *h, gip_msg_header *p) { + // TODO +} + +void unknown_msg(gip_handler_t *h, gip_msg_header *p) { + // TODO +} + +void fd_error(gip_handler_t *h) { + // TODO +} + /* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/sysbin/init/Makefile b/src/sysbin/init/Makefile index 53a1f45..e56d4c0 100644 --- a/src/sysbin/init/Makefile +++ b/src/sysbin/init/Makefile @@ -1,7 +1,7 @@ OBJ = main.o -LIB = ../../lib/libkogata/libkogata.lib ../../common/libc/libc.lib ../../common/libalgo/libalgo.lib +LIB = ../../lib/libkogata/libkogata.lib CFLAGS = -I ./include -I ../../common/include -I ../../lib/include diff --git a/src/sysbin/init/main.c b/src/sysbin/init/main.c index a2c607d..d7f3f36 100644 --- a/src/sysbin/init/main.c +++ b/src/sysbin/init/main.c @@ -140,7 +140,7 @@ void launch_login() { ok = bind_fs(login_pid, "config", "config"); if (!ok) PANIC("[init] Could not bind config:/ to login"); - ok = bind_fd(login_pid, 1, root_gip_chan.a); + ok = bind_fd(login_pid, 1, root_gip_chan.b); if (!ok) PANIC("[init] Could not bind root GIP channel FD to login"); ok = proc_exec(login_pid, "sys:/bin/login.bin"); diff --git a/src/sysbin/login/Makefile b/src/sysbin/login/Makefile index 01be4e1..1232fa8 100644 --- a/src/sysbin/login/Makefile +++ b/src/sysbin/login/Makefile @@ -1,7 +1,7 @@ OBJ = main.o -LIB = ../../lib/libkogata/libkogata.lib ../../common/libc/libc.lib +LIB = ../../lib/libkogata/libkogata.lib CFLAGS = -I ./include -I ../../common/include -I ../../lib/include diff --git a/src/sysbin/login/main.c b/src/sysbin/login/main.c index f92b18c..b836eec 100644 --- a/src/sysbin/login/main.c +++ b/src/sysbin/login/main.c @@ -1,19 +1,74 @@ #include <string.h> - #include <malloc.h> -#include <syscall.h> #include <debug.h> -#include <user_region.h> + +#include <gip.h> + +typedef struct { + framebuffer_info_t mode; + void* map; + fd_t fd; + uint32_t features; +} loginc_t; + +void c_buffer_info(gip_handler_t *s, gip_msg_header *p, gip_buffer_info_msg *m); +void c_unknown_msg(gip_handler_t *s, gip_msg_header *p); +void c_fd_error(gip_handler_t *s); + +void c_async_initiate(gip_handler_t *s, gip_msg_header *p, void* data); + +gip_handler_callbacks_t loginc_cb = { + .reset = 0, + .initiate = 0, + .ok = 0, + .failure = 0, + .enable_features = 0, + .disable_features = 0, + .query_mode = 0, + .set_mode = 0, + .buffer_info = c_buffer_info, + .mode_info = 0, + .buffer_damage = 0, + .unknown_msg = c_unknown_msg, + .fd_error = c_fd_error, +}; int main(int argc, char **argv) { dbg_print("[login] Starting up.\n"); - usleep(10000000); // pretend we are doing something + loginc_t loginc; + memset(&loginc, 0, sizeof(loginc)); + + gip_handler_t *h = new_gip_handler(&loginc_cb, &loginc); + ASSERT(h != 0); + + h->mainloop_item.fd = 1; + mainloop_add_fd(&h->mainloop_item); + + gip_msg_header reset_msg = { .code = GIPC_RESET, .arg = 0 }; + gip_cmd(h, &reset_msg, 0, c_async_initiate, 0); - // and now pretend we have exited due to some kind of failure + mainloop_run(); return 0; } +void c_buffer_info(gip_handler_t *s, gip_msg_header *p, gip_buffer_info_msg *m) { + dbg_printf("[login] Got buffer info msg\n"); + // TODO +} + +void c_unknown_msg(gip_handler_t *s, gip_msg_header *p) { + // TODO +} + +void c_fd_error(gip_handler_t *s) { + // TODO +} + +void c_async_initiate(gip_handler_t *s, gip_msg_header *p, void* data) { + dbg_printf("[login] Got initiate reply to reset request.\n"); +} + /* vim: set ts=4 sw=4 tw=0 noet :*/ |