--- /dev/null
+#include <sys/mman.h>
+#include <corax/ipc.h>
+#include <crxstd.h>
+#include <string.h>
+#include <stdio.h>
+
+enum vgacolor {
+ BLACK = 0,
+ BLUE,
+ GREEN,
+ CYAN,
+ RED,
+ MAGENTA,
+ BROWN,
+ LGRAY,
+ GRAY,
+ LBLUE,
+ LGREEN,
+ LCYAN,
+ LRED,
+ LMAGENTA,
+ YELLOW,
+ WHITE
+};
+
+#define FG(c) ((unsigned short)(((c) & 0xf) << 8))
+#define BG(c) ((unsigned short)(((c) & 0xf) << 12))
+
+#define VGA_BUFFER_ADDR ((void*)0xb8000)
+#define VGA_BUFFER_COLS 80
+#define VGA_BUFFER_ROWS 24
+#define VGA_ROW_BYTES (VGA_BUFFER_COLS << 1)
+#define VGA_SCROLL_SIZE (VGA_BUFFER_COLS * (VGA_BUFFER_ROWS - 1))
+#define VGA_SCROLL_BYTES (VGA_BUFFER_SIZE << 1)
+#define VGA_BUFFER_SIZE (VGA_BUFFER_COLS * VGA_BUFFER_ROWS)
+#define VGA_BUFFER_BYTES (VGA_BUFFER_SIZE << 1)
+
+struct context {
+ unsigned short *buffer;
+ long offset;
+ unsigned short attrs;
+};
+
+static void _putchar(struct context *ctx, int c)
+{
+ if(c == '\n') {
+ ctx->offset += VGA_BUFFER_COLS -
+ (ctx->offset % VGA_BUFFER_COLS);
+ } else {
+ if(ctx->offset >= VGA_BUFFER_SIZE) {
+ ctx->offset = VGA_SCROLL_SIZE;
+ memcpy((void*)ctx->buffer,
+ (void*)ctx->buffer + VGA_ROW_BYTES,
+ VGA_SCROLL_BYTES);
+ memset((void*)ctx->buffer + VGA_SCROLL_BYTES,
+ 0, VGA_ROW_BYTES);
+ }
+
+ ctx->buffer[ctx->offset++] = ctx->attrs | (c & 0xff);
+ }
+
+ return;
+}
+
+static int _puts(struct context *ctx, const char *s)
+{
+ int i;
+
+ for(i = 0; s[i]; i++) {
+ _putchar(ctx, s[i]);
+ }
+
+ return(i);
+}
+
+int main(int argc, char *argv[])
+{
+ struct context ctx;
+ char line[80];
+
+ ctx.buffer = mmap(VGA_BUFFER_ADDR, 0x1000, PROT_READ | PROT_WRITE,
+ MAP_PHYS, 0, 0);
+
+ if(!ctx.buffer) {
+ /* nothing to do if we can't get access to the VGA buffer */
+ return(1);
+ }
+
+ ctx.offset = VGA_BUFFER_SIZE;
+ ctx.attrs = FG(LGRAY) | BG(BLACK);
+ memset(ctx.buffer, 0, VGA_BUFFER_SIZE);
+
+ snprintf(line, sizeof(line), "VGA video memory mapped at %p\n",
+ ctx.buffer);
+
+ _puts(&ctx, line);
+
+ while(1) {
+ struct cxmsg msg;
+ int err;
+
+ memset(&msg, 0, sizeof(msg));
+
+ err = cxrecv(PID_ANY, &msg);
+
+ /* FIXME: Validate message */
+ /* FIXME: Only accept messages from IO process */
+
+ if(!err) {
+ err = _puts(&ctx, (const char*)msg.cm_data);
+ }
+
+ msg.cm_retval = err;
+ cxsend(msg.cm_src, &msg);
+ }
+
+ munmap(ctx.buffer, 0x1000);
+
+ return(0);
+}