aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2015-03-11 11:51:01 +0100
committerAlex Auvolat <alex@adnab.me>2015-03-11 11:51:01 +0100
commitbde334e6393b142d9953328e9ea2881ce88a1a7b (patch)
treef3ed7bbc6c8a534fccbd2cf653e7ecb1f24b9fd4
parentaa5e2760711c092e1235105ebf097ac594512370 (diff)
downloadkogata-bde334e6393b142d9953328e9ea2881ce88a1a7b.tar.gz
kogata-bde334e6393b142d9953328e9ea2881ce88a1a7b.zip
Begin work on GIP (Graphics Initiation Protocol)
-rw-r--r--src/kernel/core/idt.c2
-rw-r--r--src/kernel/user/process.c4
-rw-r--r--src/lib/include/gip.h55
-rw-r--r--src/lib/include/mainloop.h47
-rw-r--r--src/lib/include/proto/gip.h118
-rw-r--r--src/lib/libkogata/Makefile5
-rw-r--r--src/lib/libkogata/gip.c207
-rw-r--r--src/lib/libkogata/mainloop.c135
-rw-r--r--src/sysbin/giosrv/Makefile2
-rw-r--r--src/sysbin/giosrv/main.c112
-rw-r--r--src/sysbin/init/Makefile2
-rw-r--r--src/sysbin/init/main.c2
-rw-r--r--src/sysbin/login/Makefile2
-rw-r--r--src/sysbin/login/main.c65
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 :*/