diff options
author | Lizzy Fleckenstein <lizzy@vlhl.dev> | 2023-12-19 01:54:39 +0100 |
---|---|---|
committer | Lizzy Fleckenstein <lizzy@vlhl.dev> | 2023-12-19 02:11:32 +0100 |
commit | 6d263c7d4e0f4b1d34694b5d3d159ccb20b3db02 (patch) | |
tree | 41578268cf68b2d9ea1737687a0f98af979948d8 | |
parent | 5881b4d5c1040c762599f90e091e4cc4c3abe6b1 (diff) | |
download | cuddles-6d263c7d4e0f4b1d34694b5d3d159ccb20b3db02.tar.xz |
keyboard driver and threads
* PS/2 keyboard driver
* interactive shell
* move away from \0 terminated strings to sized slices
* coroutine threads and IRQ queues
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | fs/init | 9 | ||||
-rw-r--r-- | fs/keymap/de | bin | 0 -> 256 bytes | |||
-rw-r--r-- | fs/keymap/us | bin | 0 -> 256 bytes | |||
-rwxr-xr-x | mkkeymap.sh | 5 | ||||
-rw-r--r-- | stage3/ata.c | 34 | ||||
-rw-r--r-- | stage3/def.h | 8 | ||||
-rw-r--r-- | stage3/font.c | 42 | ||||
-rw-r--r-- | stage3/font.h | 9 | ||||
-rw-r--r-- | stage3/fs.c | 13 | ||||
-rw-r--r-- | stage3/fs.h | 7 | ||||
-rw-r--r-- | stage3/gfx.c | 2 | ||||
-rw-r--r-- | stage3/gfx.h | 2 | ||||
-rw-r--r-- | stage3/halt.c | 9 | ||||
-rw-r--r-- | stage3/halt.h | 6 | ||||
-rw-r--r-- | stage3/heap.c | 14 | ||||
-rw-r--r-- | stage3/interrupts.c | 143 | ||||
-rw-r--r-- | stage3/interrupts.h | 2 | ||||
-rw-r--r-- | stage3/io.h | 5 | ||||
-rw-r--r-- | stage3/isr.lua | 2 | ||||
-rw-r--r-- | stage3/main.c | 183 | ||||
-rw-r--r-- | stage3/pci.c | 10 | ||||
-rw-r--r-- | stage3/pic.c | 5 | ||||
-rw-r--r-- | stage3/pic.h | 1 | ||||
-rw-r--r-- | stage3/ps2.c | 205 | ||||
-rw-r--r-- | stage3/ps2.h | 6 | ||||
-rw-r--r-- | stage3/shell.c | 172 | ||||
-rw-r--r-- | stage3/shell.h | 9 | ||||
-rw-r--r-- | stage3/string.c | 74 | ||||
-rw-r--r-- | stage3/string.h | 9 | ||||
-rw-r--r-- | stage3/thread.c | 82 | ||||
-rw-r--r-- | stage3/thread.h | 40 | ||||
-rw-r--r-- | stage3/yield.asm | 45 | ||||
-rw-r--r-- | util/dump2cuddlekeys/.gitignore | 1 | ||||
-rw-r--r-- | util/dump2cuddlekeys/Makefile | 8 | ||||
-rw-r--r-- | util/dump2cuddlekeys/main.c | 89 |
36 files changed, 936 insertions, 323 deletions
@@ -28,7 +28,11 @@ STAGE3 = \ stage3/ata.o \ stage3/string.o \ stage3/pci.o \ - stage3/fs.o + stage3/fs.o \ + stage3/yield.o \ + stage3/ps2.o \ + stage3/thread.o \ + stage3/shell.o PAD_BOUNDARY = pad() { truncate -s $$(echo "($$(du -b $$1 | cut -f1)+$$2-1)/$$2*$$2" | bc) $$1; }; pad @@ -52,7 +56,7 @@ stage3/%.o: stage3/%.asm nasm -f elf64 $< -o $@ stage3/%.o: stage3/%.c - cc $(CFLAGS) -c $< -o $@ + gcc $(CFLAGS) -c $< -o $@ stage3/isr.asm: stage3/isr.lua lua stage3/isr.lua > stage3/isr.asm @@ -1,10 +1,3 @@ font fonts/Bm437_IBM_VGA_8x16.cuddlefont +loadkeys keymap/de echo hello world -cat uwu.txt -charset_demo -lspci -echo meow meow meow -img blahaj.cuddleimg -font fonts/ter-u16n.cuddlefont -echo This is the terminus font! -charset_demo diff --git a/fs/keymap/de b/fs/keymap/de Binary files differnew file mode 100644 index 0000000..bf81c13 --- /dev/null +++ b/fs/keymap/de diff --git a/fs/keymap/us b/fs/keymap/us Binary files differnew file mode 100644 index 0000000..035cd7f --- /dev/null +++ b/fs/keymap/us diff --git a/mkkeymap.sh b/mkkeymap.sh new file mode 100755 index 0000000..953d1fc --- /dev/null +++ b/mkkeymap.sh @@ -0,0 +1,5 @@ +#!/bin/bash +set -e +make -qC util/dump2cuddlekeys +doas loadkeys -C/dev/tty1 "$1" +dumpkeys -C/dev/tty1 | util/dump2cuddlekeys/dump2cuddlekeys > "fs/keymap/$1" diff --git a/stage3/ata.c b/stage3/ata.c index ccfd695..6eb4c9c 100644 --- a/stage3/ata.c +++ b/stage3/ata.c @@ -34,7 +34,7 @@ typedef struct __attribute__((packed)) { typedef struct { unsigned int bits : 4; - bool doll : 1; + bool doll : 1; bool one0 : 1; bool lba : 1; bool one1 : 1; @@ -48,22 +48,22 @@ void ata_recv(u16 *buffer) if (status.err) { u8 err = inb(IO_ATA0_DATA + ATA_IO_ERR); - const char *errors[] = { - "address mark not found\n", - "track zero not found\n", - "aborted command\n", - "media change request\n", - "id not found\n", - "media changed\n", - "uncorrectable data error\n", - "bad block detected\n", + str errors[] = { + S("address mark not found\n"), + S("track zero not found\n"), + S("aborted command\n"), + S("media change request\n"), + S("id not found\n"), + S("media changed\n"), + S("uncorrectable data error\n"), + S("bad block detected\n"), }; for (int i = 0; i < 8; i++) if (err & (1 << i)) print(errors[i]); - - panic("ata0-witch error\n"); + + panic(S("ata0-witch error\n")); } else if (status.drq) break; } @@ -75,14 +75,14 @@ void ata_recv(u16 *buffer) void ata_delay() { for (int i = 0; i < 15; i++) - inb(IO_ATA0_DATA + ATA_IO_STATUS); + inb(IO_ATA0_DATA + ATA_IO_STATUS); } void ata_init() { u8 floating = inb(IO_ATA0_DATA + ATA_IO_STATUS); if (floating == 0xFF) - panic("ata0 floating\n"); + panic(S("ata0 floating\n")); outb(IO_ATA0_DATA + ATA_IO_HEAD, BITCAST(((ata_head) { .bits = 0, @@ -99,19 +99,19 @@ void ata_init() u8 status_byte = inb(IO_ATA0_DATA + ATA_IO_STATUS); if (status_byte == 0) - panic("no ata0-witch drive\n"); + panic(S("no ata0-witch drive\n")); while (BITCAST(status_byte, u8, ata_status).bsy) status_byte = inb(IO_ATA0_DATA + ATA_IO_STATUS); if (inb(IO_ATA0_DATA + ATA_IO_LBA_MID) != 0 || inb(IO_ATA0_DATA + ATA_IO_LBA_HIGH) != 0) - panic("ata0-witch is not ATA\n"); + panic(S("ata0-witch is not ATA\n")); u16 *idvec = malloc(256 * sizeof *idvec); ata_recv(idvec); if (!(idvec[83] & (1 << 10))) - panic("ata0-witch does not support LBA48 mode\n"); + panic(S("ata0-witch does not support LBA48 mode\n")); // u64 lba48_sectors = *(u64 *) &idvec[100]; // print_num(lba48_sectors, 10, 0); print("\n"); diff --git a/stage3/def.h b/stage3/def.h index e973d5e..1da628e 100644 --- a/stage3/def.h +++ b/stage3/def.h @@ -24,4 +24,12 @@ typedef u8 bool; #define BITCAST(expr, from, to) (((union { from f; to t; }) { .f = expr }).t) +typedef struct { + usize len; + char *data; +} str; + +#define S(x) ((str) { sizeof (x) - 1, (x) }) +#define NILS ((str) { 0, nil }) + #endif diff --git a/stage3/font.c b/stage3/font.c index 9e315e6..69017ca 100644 --- a/stage3/font.c +++ b/stage3/font.c @@ -142,37 +142,41 @@ void print_char(char c) fix_cursor(); } -void print(const char *line) +void print(str line) { - while (*line != '\0') - print_char(*line++); + for (usize i = 0; i < line.len; i++) + print_char(line.data[i]); } -void printn(const char *line, usize len) +void print_num_pad(u64 x, u8 base, u8 pad_len, char pad_char) { - for (usize i = 0; i < len; i++) - print_char(*line++); -} - -void print_padded(u64 x, u8 base, u8 pad_len, char pad_char) -{ - char digit[65]; - char *ptr = &digit[64]; - *ptr = '\0'; + char buffer[64]; + usize idx = 64; do { u8 digit = x % base; - *--ptr = digit + (digit < 10 ? '0' : ('A' - 10)); + buffer[--idx] = digit + (digit < 10 ? '0' : ('A' - 10)); x /= base; } while (x != 0); - while (ptr > digit + 64 - pad_len) - *--ptr = pad_char; + while (idx > (usize) (64 - pad_len)) + buffer[--idx] = pad_char; + + print((str) { 64 - idx, &buffer[idx] }); +} + +void print_num(u64 x, u8 base) +{ + print_num_pad(x, base, 0, ' '); +} - print(ptr); +void print_dec(u64 x) +{ + print_num(x, 10); } -void print_num(u64 x, u8 base, u8 pad) +void print_hex(u64 x) { - print_padded(x, base, pad, ' '); + print_num(x, 16); } + diff --git a/stage3/font.h b/stage3/font.h index ec99118..400fb3d 100644 --- a/stage3/font.h +++ b/stage3/font.h @@ -8,10 +8,11 @@ void font_set_size(u16 size); void font_load_blob(const void *blob); void font_load_classic(); -void print(const char *line); -void printn(const char *line, usize len); +void print(str line); void print_char(char c); -void print_num(u64 x, u8 base, u8 pad_len); -void print_padded(u64 x, u8 base, u8 pad_len, char pad_char); +void print_dec(u64 x); +void print_hex(u64 x); +void print_num(u64 x, u8 base); +void print_num_pad(u64 x, u8 base, u8 pad_len, char pad_char); #endif diff --git a/stage3/fs.c b/stage3/fs.c index 9f7ea51..d4a325f 100644 --- a/stage3/fs.c +++ b/stage3/fs.c @@ -4,7 +4,7 @@ #include "memory.h" #include "heap.h" -file fs_read(const char *filename) +str fs_read(str filename) { u64 start = (*(u32 *) (0x1000-10-8))/512; @@ -13,16 +13,17 @@ file fs_read(const char *filename) if (memcmp(info+257, "ustar", 5) != 0) { free(info); - return (file) { .len = 0, .data = nil }; + return NILS; } - u8 *infop = info+124; - usize fsize = parse_num(&infop, 8, 11); + usize fsize; + str_parse_num((str) { 11, (char *) info+124 }, 8, &fsize); + usize fsect = (fsize+511)/512; - if (memcmp(info, filename, strlen(filename) + 1) == 0) { + if (memcmp(info, filename.data, filename.len) == 0 && info[filename.len] == '\0') { free(info); - return (file) { .len = fsize, .data = ata_read_full(start+1, fsect) }; + return (str) { .len = fsize, .data = ata_read_full(start+1, fsect) }; } else { free(info); start += 1 + fsect; diff --git a/stage3/fs.h b/stage3/fs.h index b585577..c1fea24 100644 --- a/stage3/fs.h +++ b/stage3/fs.h @@ -3,11 +3,6 @@ #include "def.h" -typedef struct { - usize len; - void *data; -} file; - -file fs_read(const char *filename); +str fs_read(str filename); #endif diff --git a/stage3/gfx.c b/stage3/gfx.c index 79c76a3..b01e89a 100644 --- a/stage3/gfx.c +++ b/stage3/gfx.c @@ -32,7 +32,7 @@ void gfx_set_area(u16 x, u16 y, u16 w, u16 h, u32 col) } } -void gfx_draw_img(u16 x, u16 y, u16 w, u16 h, color *img) +void gfx_draw_img(u16 x, u16 y, u16 w, u16 h, u32 *img) { void *cbeg = (void *) (u64) (gfx_info->framebuffer + y * gfx_info->pitch + x * sizeof(color)); for (u16 yi = 0; yi < h; cbeg += gfx_info->pitch, yi++) diff --git a/stage3/gfx.h b/stage3/gfx.h index 6eee074..5d9c8b3 100644 --- a/stage3/gfx.h +++ b/stage3/gfx.h @@ -17,6 +17,6 @@ typedef struct __attribute__((packed)) { u32 make_color(color col); void gfx_set_pixel(u16 x, u16 y, u32 col); void gfx_set_area(u16 x, u16 y, u16 w, u16 h, u32 col); -void gfx_draw_img(u16 x, u16 y, u16 w, u16 h, color *img); +void gfx_draw_img(u16 x, u16 y, u16 w, u16 h, u32 *img); #endif diff --git a/stage3/halt.c b/stage3/halt.c index 9e0ecce..b53a4f2 100644 --- a/stage3/halt.c +++ b/stage3/halt.c @@ -1,14 +1,15 @@ #include "halt.h" #include "font.h" +#include "pic.h" -void halt() +void freeze() { for (;;) - asm volatile("hlt"); + wait_irq(); } -void panic(char *msg) +void panic(str msg) { print(msg); - halt(); + freeze(); } diff --git a/stage3/halt.h b/stage3/halt.h index 99b1717..6e7ca34 100644 --- a/stage3/halt.h +++ b/stage3/halt.h @@ -1,7 +1,9 @@ #ifndef HALT_H #define HALT_H -void halt(); -void panic(char *msg); +#include "def.h" + +void freeze(); +void panic(str msg); #endif diff --git a/stage3/heap.c b/stage3/heap.c index 0a82213..c9e7edb 100644 --- a/stage3/heap.c +++ b/stage3/heap.c @@ -18,7 +18,7 @@ void free(void *ptr) Header *h = ((Header *) ptr) - 1; if (h->next != MAGIC) - panic("free: invalid pointer"); + panic(S("free: invalid pointer")); Header *next = free_ptr->next; free_ptr->next = h; @@ -28,7 +28,7 @@ void free(void *ptr) static void defragment() { //usize num_blocks = 0; - panic("defragment not implemented"); + panic(S("defragment not implemented")); } void *try_malloc(usize size) @@ -64,13 +64,13 @@ void *malloc(usize size) { void *p; - p = try_malloc(size); - if (p) return p; - defragment(); + // p = try_malloc(size); + // if (p) return p; + // defragment(); p = try_malloc(size); if (p) return p; - panic("out of memory"); + panic(S("out of memory")); return nil; } @@ -83,7 +83,7 @@ void *realloc(void *ptr, usize size) Header *h = ((Header *) ptr) - 1; if (h->next != MAGIC) - panic("realloc: invalid pointer"); + panic(S("realloc: invalid pointer")); void *new = malloc(size); diff --git a/stage3/interrupts.c b/stage3/interrupts.c index 71f953f..4a4687c 100644 --- a/stage3/interrupts.c +++ b/stage3/interrupts.c @@ -3,102 +3,115 @@ #include "font.h" #include "heap.h" #include "pic.h" +#include "thread.h" +#include "io.h" extern u64 idt_entries[256]; // isr.asm -typedef struct { - u64 which; - u64 error_code; - // automatically pushed - u64 rip; - u64 cs; - u64 rflags; - u64 rsp; - u64 ss; +typedef struct __attribute__((packed)) { + u64 rax, rdx, rcx, rsi, rdi, r8, r9, r10, r11; + u64 which, error_code; + u64 rip, cs, rflags, rsp, ss; } interrupt_frame; -static const char *exception[32] = { - "Division Error", - "Debug", - "Non-maskable Interrupt", - "Breakpoint", - "Overflow", - "Bound Range Exceeded", - "Invalid Opcode", - "Device Not Available", - "Double Fault", - "Coprocessor Segment Overrun", - "Invalid TSS", - "Segment Not Present", - "Stack-Segment Fault", - "General Protection Fault", - "Page Fault", - nil, - "x87 Floating-Point Exception", - "Alignment Check", - "Machine Check", - "SIMD Floating-Point Exception", - "Virtualization Exception", - "Control Protection Exception", - nil, nil, nil, nil, nil, nil, - "Hypervisor Injection Exception", - "VMM Communication Exception", - "Security Exception", - nil, +static str exception[32] = { + S("Division Error"), + S("Debug"), + S("Non-maskable Interrupt"), + S("Breakpoint"), + S("Overflow"), + S("Bound Range Exceeded"), + S("Invalid Opcode"), + S("Device Not Available"), + S("Double Fault"), + S("Coprocessor Segment Overrun"), + S("Invalid TSS"), + S("Segment Not Present"), + S("Stack-Segment Fault"), + S("General Protection Fault"), + S("Page Fault"), + NILS, + S("x87 Floating-Point Exception"), + S("Alignment Check"), + S("Machine Check"), + S("SIMD Floating-Point Exception"), + S("Virtualization Exception"), + S("Control Protection Exception"), + NILS, NILS, NILS, NILS, NILS, NILS, + S("Hypervisor Injection Exception"), + S("VMM Communication Exception"), + S("Security Exception"), + NILS, }; static void dump_frame(interrupt_frame *frame) { - print("rip = "); print_num(frame->rip, 16, 0); print("\n"); - print("cs = "); print_num(frame->cs, 16, 0); print("\n"); - print("rflags = "); print_num(frame->rflags, 16, 0); print("\n"); - print("rsp = "); print_num(frame->rsp, 16, 0); print("\n"); - print("ss = "); print_num(frame->ss, 16, 0); print("\n"); + print(S("rip = ")); print_hex(frame->rip); print_char('\n'); + print(S("cs = ")); print_hex(frame->cs); print_char('\n'); + print(S("rflags = ")); print_hex(frame->rflags); print_char('\n'); + print(S("rsp = ")); print_hex(frame->rsp); print_char('\n'); + print(S("ss = ")); print_hex(frame->ss); print_char('\n'); } void interrupt_handler(interrupt_frame *frame) { if (frame->which < 32) { - if (exception[frame->which] == nil) { - print("Unknown Exception "); - print_num(frame->which, 10, 0); + // TODO: possible race condition due to printing here + // when exception happens in printing code itself + + if (exception[frame->which].data != nil) { + print(S("Unknown Exception ")); + print_dec(frame->which); } else { print(exception[frame->which]); } - print("\n"); + print_char('\n'); if (frame->which == 13) { - const char *bits[8] = { - "present", - "write", - "user", - "reserved_write", - "instruction_fetch", - "protection_key", - "shadow_stack", - "software_guard_extensions", + str bits[8] = { + S("present"), + S("write"), + S("user"), + S("reserved_write"), + S("instruction_fetch"), + S("protection_key"), + S("shadow_stack"), + S("software_guard_extensions"), }; u8 err = frame->error_code; for (int i = 0; i < 8; i++) { - print(bits[i]); print(" = "); print((err & 1) ? "true\n" : "false\n"); + print(bits[i]); print(S(" = ")); print((err & 1) ? S("true\n") : S("false\n")); err >>= 1; } } else { - print("error_code = "); print_num(frame->error_code, 10, 0); print("\n"); + print(S("error_code = ")); print_dec(frame->error_code); print_char('\n'); } dump_frame(frame); - - halt(); + freeze(); } else if (frame->which-32 < 16) { - u64 irq = frame->which-32; - print("IRQ "); print_num(irq, 10, 0); print("\n"); - ack_irq(irq); + if (queue_write.len == queue_write.cap) { + panic(S("queue exceeded\n")); + /* + // TODO: malloc would cause a race condition + queue_write.cap = queue_write.cap == 0 ? 1 : queue_write.cap * 2; + queue_write.data = realloc(queue_write.data, queue_write.cap); + */ + } + + event *e = &queue_write.data[queue_write.len++]; + e->irq = frame->which-32; + + if (e->irq == 1) { + e->data.scancode = inb(IO_PS2_DATA); + } + + ack_irq(e->irq); } else { - print("Spurious Interrupt "); print_num(frame->which, 10, 0); print("\n"); - dump_frame(frame); + // print("Spurious Interrupt "); print_num(frame->which, 10, 0); print("\n"); + // dump_frame(frame); } } @@ -109,7 +122,7 @@ typedef struct { idt_descriptor idtr; -void init_interrupts() +void interrupts_init() { typedef struct { u16 offset_1; diff --git a/stage3/interrupts.h b/stage3/interrupts.h index 79d3488..333aca0 100644 --- a/stage3/interrupts.h +++ b/stage3/interrupts.h @@ -1,6 +1,6 @@ #ifndef INTERRUPTS_H #define INTERRUPTS_H -void init_interrupts(); +void interrupts_init(); #endif diff --git a/stage3/io.h b/stage3/io.h index 1265043..bca094d 100644 --- a/stage3/io.h +++ b/stage3/io.h @@ -39,11 +39,6 @@ static inline u32 inl(u16 port) return val; } -static inline void hlt() -{ - asm volatile("hlt"); -} - typedef enum { IO_PIC1_CTRL = 0x20, IO_PIC1_DATA = 0x21, diff --git a/stage3/isr.lua b/stage3/isr.lua index 6c81180..83515a5 100644 --- a/stage3/isr.lua +++ b/stage3/isr.lua @@ -36,7 +36,7 @@ isr_common: push rax cld - lea rdi, [rsp+8*9] + mov rdi, rsp call interrupt_handler pop rax diff --git a/stage3/main.c b/stage3/main.c index 5362984..c8ff971 100644 --- a/stage3/main.c +++ b/stage3/main.c @@ -14,16 +14,40 @@ void init() #include "interrupts.h" #include "pic.h" #include "io.h" -#include "memory.h" #include "ata.h" -#include "fs.h" -#include "string.h" #include "pci.h" +#include "ps2.h" +#include "thread.h" +#include "shell.h" -void eat_whitespace(char **str) +char keymap[256] = { '\0' }; + +void keyboard_handler() { - while (**str == ' ' || **str == '\t') - (*str)++; + str buffer = NILS; + usize cap = 0; + print(S("$ ")); + + for (;;) { + event *e = yield(nil); + + char c = keymap[e->data.scancode]; + if (c != '\0') { + print_char(c); + + if (c == '\n') { + shell_run_cmd(buffer); + buffer.len = 0; + print(S("$ ")); + } else { + if (buffer.len == cap) + buffer.data = realloc(buffer.data, cap = cap ? cap*2 : 1); + buffer.data[buffer.len++] = c; + } + } + + free(e); + } } void kmain() @@ -61,142 +85,31 @@ void kmain() font_load_classic(); // memory map - print("memory map:\n"); + print(S("memory map:\n")); for (usize i = 0; i < n_mreg; i++) { - print_num((u64) mregs[i].start, 16, 16); - print(" | "); - print_num((u64) mregs[i].start + mregs[i].size, 16, 16); - print(" | "); - print_num(mregs[i].used, 10, 0); - print("\n"); + print_num_pad((u64) mregs[i].start, 16, 16, ' '); + print(S(" | ")); + print_num_pad((u64) mregs[i].start + mregs[i].size, 16, 16, ' '); + print(S(" | ")); + print_dec(mregs[i].used); + print(S("\n")); } - init_interrupts(); + interrupts_init(); pic_init(); - ata_init(); - - file f = fs_read("init"); - if (f.data == nil) - panic("no init script"); - - // this is horrible horrible horrible - // if you read this i am genuinely sorry - - char *init = malloc(f.len+1); - char *init_orig = init; - init[f.len] = '\0'; - memcpy(init, f.data, f.len); - free(f.data); - - for (;;) { - eat_whitespace(&init); + thread_init(); - if (*init == '\0') - break; - else if (*init == '\n') { - init++; - continue; - } - - if (strncmp(init, "echo ", strlen("echo ")) == 0) { - init += strlen("echo "); - usize idx = find_char(init, '\n'); - printn(init, idx); - print("\n"); - init += idx; - } else if (strncmp(init, "cat ", strlen("cat ")) == 0) { - init += strlen("cat "); - usize idx = find_char(init, '\n'); - - char filename[idx+1]; - filename[idx] = '\0'; - memcpy(filename, init, idx); - - file f = fs_read(filename); - if (f.data == nil) { - print("cat: file not found: "); - print(filename); - print("\n"); - } else { - printn(f.data, f.len); - free(f.data); - } - - init += idx; - } else if (strncmp(init, "font ", strlen("font ")) == 0) { - init += strlen("font "); - usize idx = find_char(init, '\n'); - - char filename[idx+1]; - filename[idx] = '\0'; - memcpy(filename, init, idx); - - file f = fs_read(filename); - if (f.data == nil) { - print("font: file not found: "); - print(filename); - print("\n"); - } else { - if (f.len == 16*256) - font_load_blob(f.data); - else - print("font: file has wrong size\n"); - free(f.data); - } + ata_init(); + ps2_init(); - init += idx; - } else if (strncmp(init, "img ", strlen("img ")) == 0) { - init += strlen("img "); - usize idx = find_char(init, '\n'); + shell_run_file(S("init")); - char filename[idx+1]; - filename[idx] = '\0'; - memcpy(filename, init, idx); + thread *keyboard_thread = thread_create(S("keyboard"), &keyboard_handler); + irq_services[1] = keyboard_thread; - file f = fs_read(filename); - if (f.data == nil) { - print("img: file not found: "); - print(filename); - print("\n"); - } else { - if (f.len < 2 * sizeof(u32)) - print("img: missing header\n"); - else { - u32 width = ((u32 *) f.data)[0]; - u32 height = ((u32 *) f.data)[1]; - if (f.len != 2 * sizeof(u32) + width * height * sizeof(color)) - panic("img: invalid file size\n"); - gfx_draw_img(gfx_info->width-width, 0, width, height, f.data + 2 * sizeof(u32)); - } - free(f.data); - } - - init += idx; - } else if (strncmp(init, "lspci", strlen("lspci")) == 0) { - pci_enumerate(); - init += find_char(init, '\n'); - } else if (strncmp(init, "charset_demo", strlen("charset_demo")) == 0) { - const u8 max = '~' - '!' + 1; - - char str[max + 1]; - str[max] = '\0'; - - for (u8 i = 0; i < max; i++) - str[i] = i + '!'; - - print("charset demo:\n"); - print(str); - print("\n"); - init += find_char(init, '\n'); - } else { - print("unknown command: "); - usize idx = find_char(init, '\n'); - printn(init, idx); - print("\n"); - init += idx; - } - } + unmask_irq(1); + enable_irqs(); - free(init_orig); - halt(); + thread_sched(nil, nil); + freeze(); } diff --git a/stage3/pci.c b/stage3/pci.c index 164071d..d764171 100644 --- a/stage3/pci.c +++ b/stage3/pci.c @@ -30,11 +30,11 @@ void pci_enumerate() outl(PCI_CONFIG_ADDRESS, BITCAST(addr, pci_config_addr, u32)); u32 x = inl(PCI_CONFIG_DATA); if (x != 0xFFFFFFFF) { - print("bus: "); print_num(bus, 16, 2); - print(" dev: "); print_num(dev, 16, 1); - print(" vendor: "); print_num(x & 0xFFFF, 16, 4); - print(" id: "); print_num((x >> 16) & 0xFFFF, 16, 4); - print("\n"); + print(S("bus: ")); print_num_pad(bus, 16, 2, ' '); + print(S(" dev: ")); print_num_pad(dev, 16, 1, ' '); + print(S(" vendor: ")); print_num_pad(x & 0xFFFF, 16, 4, ' '); + print(S(" id: ")); print_num_pad((x >> 16) & 0xFFFF, 16, 4, ' '); + print(S("\n")); } } } diff --git a/stage3/pic.c b/stage3/pic.c index 726a6da..4ece7c3 100644 --- a/stage3/pic.c +++ b/stage3/pic.c @@ -19,6 +19,11 @@ void ack_irq(u8 lane) outb(IO_PIC1_CTRL, 1 << 5); } +void wait_irq() +{ + asm volatile("hlt"); +} + void unmask_irq(u8 lane) { u8 port = IO_PIC1_DATA; diff --git a/stage3/pic.h b/stage3/pic.h index eebe119..6afb919 100644 --- a/stage3/pic.h +++ b/stage3/pic.h @@ -26,6 +26,7 @@ void disable_irqs(); void enable_irqs(); void unmask_irq(u8 lane); void ack_irq(u8 lane); +void wait_irq(); void pic_init(); #endif diff --git a/stage3/ps2.c b/stage3/ps2.c new file mode 100644 index 0000000..61f3582 --- /dev/null +++ b/stage3/ps2.c @@ -0,0 +1,205 @@ +#include "ps2.h" +#include "def.h" +#include "io.h" +#include "font.h" +#include "halt.h" + +// this should probably be refactored some time - i dont have the energy rn + +typedef enum { + PS2_CMD_READ_INTERNAL = 0x20, + PS2_CMD_WRITE_INTERNAL = 0x60, + PS2_CMD_DISABLE_PORT2 = 0xA7, + PS2_CMD_ENABLE_PORT2 = 0xA8, + PS2_CMD_TEST_PORT2 = 0xA9, + PS2_CMD_TEST_CTRL = 0xAA, + PS2_CMD_TEST_PORT1 = 0xAB, + PS2_CMD_DIAGNOSTIC_DUMP = 0xAC, + PS2_CMD_DISABLE_PORT1 = 0xAD, + PS2_CMD_ENABLE_PORT1 = 0xAE, + PS2_CMD_READ_CTRL_IN = 0xC0, + PS2_CMD_COPY_TO_STATUS_LOW = 0xC1, + PS2_CMD_COPY_TO_STATUS_HIGH = 0xC2, + PS2_CMD_READ_CTRL_OUT = 0xD0, + PS2_CMD_WRITE_CTRL_OUT = 0xD1, + PS2_CMD_WRITE_PORT1_OUT = 0xD2, + PS2_CMD_WRITE_PORT2_OUT = 0xD3, + PS2_CMD_WRITE_PORT2_IN = 0xD4, + PS2_CMD_PULSE_OUT = 0xF0, +} ps2_cmd; + +typedef enum { + PS2_STATUS_OUT = 1 >> 0, + PS2_STATUS_IN = 1 >> 1, + PS2_STATUS_POST = 1 >> 2, + PS2_STATUS_RECEIVER = 1 >> 3, + PS2_STATUS_ERR_TIMEOUT = 1 >> 6, + PS2_STATUS_ERR_PARITY = 1 >> 7, +} Ps2Status; + +typedef struct { + bool output : 1; + bool input : 1; + bool post : 1; + bool receiver : 1; + bool unknown_1 : 1; + bool unknown_2 : 1; + bool err_timeout : 1; + bool err_parity : 1; +} __attribute__((packed)) ps2_status; + +typedef struct { + bool int_port1 : 1; + bool int_port2 : 1; + bool post : 1; + bool zero_1 : 1; + bool clk_port1 : 1; + bool clk_port2 : 1; + bool translation : 1; + bool zero_2 : 1; +} __attribute__((packed)) ps2_ctrl_cfg; + +typedef enum { + PS2_CFG_INT_PORT1 = 1 >> 0, + PS2_CFG_INT_PORT2 = 1 >> 1, + PS2_CFG_POST = 1 >> 2, + // PS2_CFG_ZERO1 = 1 >> 3, + PS2_CFG_CLK_PORT1 = 1 >> 4, + PS2_CFG_CLK_PORT2 = 1 >> 5, + PS2_CFG_TRANS_PORT1 = 1 >> 6, + // PS2_CFG_ZERO2 = 1 >> 7, +} Ps2CtrlCfg; + +typedef enum { + PS2_CTRL_SYSRESET = 1 >> 0, + PS2_CTRL_A20 = 1 >> 1, + PS2_CTRL_CLK_PORT2 = 1 >> 2, + PS2_CTRL_DATA_PORT2 = 1 >> 3, + PS2_CTRL_OUT_PORT1 = 1 >> 4, + PS2_CTRL_OUT_PORT2 = 1 >> 5, + PS2_CTRL_CLK_PORT1 = 1 >> 6, + PS2_CTRL_DATA_PORT1 = 1 >> 7, +} Ps2CtrlOut; + +typedef enum { + PS2_TEST_CTRL_PASS = 0x55, + PS2_TEST_CTRL_FAIL = 0xFC, +} Ps2TestCtrl; + +typedef enum { + PS2_TEST_PORT_PASS = 0x00, + PS2_TEST_PORT_CLK_STUCK_LOW = 0x01, + PS2_TEST_PORT_CLK_STUCK_HIGH = 0x02, + PS2_TEST_PORT_DATA_STUCK_LOW = 0x03, + PS2_TEST_PORT_DATA_STUCK_HIGH = 0x04, +} Ps2TestPort; + +void ps2_poll_status(u8 mask, bool set) +{ + // TODO: wait instead of busy polling + // TODO: timeout + while (set == !(inb(IO_PS2_CTRL) & mask)) + ; +} + +u8 ps2_read_data() +{ + ps2_poll_status(PS2_STATUS_OUT, true); + return inb(IO_PS2_DATA); +} + +void ps2_write_data(u8 val) +{ + ps2_poll_status(PS2_STATUS_IN, false); + outb(IO_PS2_DATA, val); +} + +void ps2_write_ctrl(u8 val) +{ + ps2_poll_status(PS2_STATUS_IN, false); + outb(IO_PS2_CTRL, val); +} + +u8 ps2_read_mem(u8 byte) +{ + ps2_write_ctrl(PS2_CMD_READ_INTERNAL + byte); + return ps2_read_data(); +} + +void ps2_write_mem(u8 byte, u8 val) +{ + ps2_write_ctrl(PS2_CMD_WRITE_INTERNAL + byte); + ps2_write_data(val); +} + +void ps2_test_port(ps2_cmd cmd, str desc) +{ + ps2_write_ctrl(cmd); + print(S("PS/2 ")); print(desc); print(S(" test: ")); + u8 b = ps2_read_data(); + switch (b) { + case PS2_TEST_PORT_PASS: print(S("pass\n")); break; + case PS2_TEST_PORT_CLK_STUCK_LOW: panic(S("clock stuck low\n")); break; + case PS2_TEST_PORT_CLK_STUCK_HIGH: panic(S("clock stuck high\n")); break; + case PS2_TEST_PORT_DATA_STUCK_LOW: panic(S("data stuck low\n")); break; + case PS2_TEST_PORT_DATA_STUCK_HIGH: panic(S("data stuck high\n")); break; + default: print_hex(b); panic(S(" (unknown response)\n")); break; + } +} + +void ps2_init() +{ + // TODO: USB bullshit + // TODO: determine if exists + + // disable devices + ps2_write_ctrl(PS2_CMD_DISABLE_PORT1); + ps2_write_ctrl(PS2_CMD_DISABLE_PORT2); + + // flush output buffer + inb(IO_PS2_DATA); + + // disable IRQs and translation + u8 config = ps2_read_mem(0); + config &= ~(PS2_CFG_INT_PORT1 | PS2_CFG_INT_PORT2 | PS2_CFG_TRANS_PORT1); + ps2_write_mem(0, config); + + // perform self-test + ps2_write_ctrl(PS2_CMD_TEST_CTRL); + print(S("PS/2 controller test: ")); + switch (ps2_read_data()) { + case PS2_TEST_CTRL_PASS: print(S("pass\n")); break; + case PS2_TEST_CTRL_FAIL: panic(S("fail\n")); break; + default: panic(S("unknown response\n")); break; + } + ps2_write_mem(0, config); // restore config byte + + // check if dual + bool dual = !!(config & PS2_CFG_CLK_PORT2); + if (dual) { + ps2_write_ctrl(PS2_CMD_ENABLE_PORT2); + config = ps2_read_mem(0); + dual = !(config & PS2_CFG_CLK_PORT2); + + if (dual) + ps2_write_ctrl(PS2_CMD_DISABLE_PORT2); + } + print(S("PS/2 second port ")); print(dual ? S("enabled\n") : S("disabled\n")); + + // test devices + ps2_test_port(PS2_CMD_TEST_PORT1, S("port 1")); + if (dual) + ps2_test_port(PS2_CMD_TEST_PORT2, S("port 2")); + + // enable devices + ps2_write_ctrl(PS2_CMD_ENABLE_PORT1); + if (dual) + ps2_write_ctrl(PS2_CMD_ENABLE_PORT2); + + // enable IRQs + config |= PS2_CFG_INT_PORT1; + ps2_write_mem(0, config); + + ps2_write_data(0xFF); + ps2_read_data(); +} diff --git a/stage3/ps2.h b/stage3/ps2.h new file mode 100644 index 0000000..428ee15 --- /dev/null +++ b/stage3/ps2.h @@ -0,0 +1,6 @@ +#ifndef PS2_H +#define PS2_H + +void ps2_init(); + +#endif diff --git a/stage3/shell.c b/stage3/shell.c new file mode 100644 index 0000000..f8d5ada --- /dev/null +++ b/stage3/shell.c @@ -0,0 +1,172 @@ +#include "shell.h" +#include "font.h" +#include "heap.h" +#include "fs.h" +#include "gfx.h" +#include "string.h" +#include "pci.h" +#include "memory.h" + +static void cmd_echo(str arg) +{ + print(arg); + print_char('\n'); +} + +static void cmd_cat(str arg) +{ + str f = fs_read(arg); + + if (f.data == nil) { + print(S("cat: file not found: ")); + print(arg); + print(S("\n")); + } else { + print(f); + free(f.data); + } +} + +static void cmd_font(str arg) +{ + str f = fs_read(arg); + + if (f.data == nil) { + print(S("font: file not found: ")); + print(arg); + print(S("\n")); + } else { + if (f.len == 16*256) + font_load_blob(f.data); + else + print(S("font: invalid file size\n")); + + free(f.data); + } +} + +static void cmd_fontdemo() +{ + const u8 max = '~' - '!' + 1; + char buf[max]; + + for (u8 i = 0; i < max; i++) + buf[i] = i + '!'; + + print(S("fontdemo:\n")); + print((str) { max, buf }); + print(S("\n")); +} + +static void cmd_img(str arg) +{ + str f = fs_read(arg); + + if (f.data == nil) { + print(S("img: file not found: ")); + print(arg); + print(S("\n")); + } else { + if (f.len < 2 * sizeof(u32)) + print(S("img: missing header\n")); + else { + u32 width = ((u32 *) f.data)[0]; + u32 height = ((u32 *) f.data)[1]; + + if (f.len != 2 * sizeof(u32) + width * height * sizeof(color)) + print(S("img: invalid file size\n")); + else + gfx_draw_img(gfx_info->width-width, 0, width, height, + (void *) (f.data + 2 * sizeof(u32))); + } + + free(f.data); + } +} + +static void cmd_lspci(str arg) +{ + (void) arg; + pci_enumerate(); +} + +static void cmd_run(str arg) +{ + shell_run_file(arg); +} + +extern char keymap[256]; + +static void cmd_loadkeys(str arg) +{ + str f = fs_read(arg); + + if (f.data == nil) { + print(S("loadkeys: file not found: ")); + print(arg); + print(S("\n")); + } else { + if (f.len == 256) + memcpy(keymap, f.data, 256); + else + print(S("loadkeys: invalid file size\n")); + + free(f.data); + } +} + +typedef struct { + str name; + void (*fn)(str arg); +} command; + +static command registry[] = { + { S("echo"), &cmd_echo }, + { S("cat"), &cmd_cat }, + { S("font"), &cmd_font }, + { S("fontdemo"), &cmd_fontdemo }, + { S("img"), &cmd_img }, + { S("lspci"), &cmd_lspci }, + { S("run"), &cmd_run }, + { S("loadkeys"), &cmd_loadkeys }, +}; + +void shell_run_cmd(str cmd) +{ + str prog = str_split_walk(&cmd, S(" \t")); + + if (prog.len == 0) + return; + + for (usize i = 0; i < sizeof registry / sizeof *registry; i++) { + if (str_cmp(prog, registry[i].name) == 0) { + registry[i].fn(cmd); + return; + } + } + + print(S("shell: unknown command: ")); + print(prog); + print(S("\n")); +} + +void shell_run_file(str filename) +{ + str f = fs_read(filename); + + if (f.data == nil) { + print(S("shell: file not found: ")); + print(filename); + print(S("\n")); + } else { + str iter = f; + for (;;) { + str cmd = str_split_walk(&iter, S("\n")); + if (cmd.data == nil) + break; + shell_run_cmd(cmd); + } + + free(f.data); + } +} diff --git a/stage3/shell.h b/stage3/shell.h new file mode 100644 index 0000000..2336d21 --- /dev/null +++ b/stage3/shell.h @@ -0,0 +1,9 @@ +#ifndef SHELL_H +#define SHELL_H + +#include "def.h" + +void shell_run_cmd(str arg); +void shell_run_file(str arg); + +#endif diff --git a/stage3/string.c b/stage3/string.c index ff4bfc3..2f95b99 100644 --- a/stage3/string.c +++ b/stage3/string.c @@ -1,19 +1,39 @@ #include "string.h" +#include "memory.h" +#include "heap.h" -usize find_char(const char *str, char chr) +isize str_cmp(str s1, str s2) { - usize ret = 0; - while (*str != chr && *str != '\0') - str++, ret++; - return ret; + if (s1.len != s2.len) + return (isize) s1.len - (isize) s2.len; + + return memcmp(s1.data, s2.data, s1.len); +} + +static bool match_char(char c, str tokens) +{ + for (usize t = 0; t < tokens.len; t++) + if (c == tokens.data[t]) + return true; + + return false; +} + +usize str_find(str s, str tokens) +{ + for (usize i = 0; i < s.len; i++) + if (match_char(s.data[i], tokens)) + return i; + + return s.len; } -u64 parse_num(u8 **str, u8 base, isize size) +usize str_parse_num(str s, u8 base, u64 *x) { - u64 x = 0; + *x = 0; - while (size-- != 0) { - u8 c = **str; + for (usize i = 0; i < s.len; i++) { + u8 c = s.data[i]; u64 d; if (c >= '0' && c <= '9') @@ -23,34 +43,30 @@ u64 parse_num(u8 **str, u8 base, isize size) else if (c >= 'A' && c <= 'z') d = c - 'A'; else - return x; + return i; if (d >= base) - return x; + return i; - (*str)++; - x = x * base + d; + *x = *x * base + d; } - return x; + return s.len; } -usize strlen(const char *str) +str str_split_walk(str *s, str sep) { - return find_char(str, '\0'); -} + if (s->len == 0) + return NILS; -int strcmp(const char *p1, const char *p2) -{ - while (*p1 == *p2 && *p1 != '\0') - p1++, p2++; - return *p1 - *p2; -} + usize x = str_find(*s, sep); + usize o = x + (x < s->len); -int strncmp(const char *p1, const char *p2, usize size) -{ - for (usize i = 0; i < size; i++) - if (p1[i] != p2[i]) - return p1[i]-p2[i]; - return 0; + s->len -= o; + s->data += o; + + if (x == 0) + return str_split_walk(s, sep); + else + return (str) { x, s->data - o }; } diff --git a/stage3/string.h b/stage3/string.h index 2738f60..8375136 100644 --- a/stage3/string.h +++ b/stage3/string.h @@ -3,10 +3,9 @@ #include "def.h" -u64 parse_num(u8 **str, u8 base, isize size); -usize find_char(const char *str, char chr); -usize strlen(const char *str); -int strcmp(const char *p1, const char *p2); -int strncmp(const char *p1, const char *p2, usize size); +isize str_cmp(str s1, str s2); +usize str_find(str s, str tokens); +usize str_parse_num(str s, u8 base, u64 *x); +str str_split_walk(str *s, str sep); #endif diff --git a/stage3/thread.c b/stage3/thread.c new file mode 100644 index 0000000..f78b80a --- /dev/null +++ b/stage3/thread.c @@ -0,0 +1,82 @@ +#include "thread.h" +#include "heap.h" +#include "pic.h" + +static thread *current_thread = nil; +void *thread_sched_stack = nil; + +static event_queue queue_read = { 0, 0, nil }; +event_queue queue_write = { 0, 0, nil }; + +thread *irq_services[16] = { nil }; + +void resume(void *stack, void *ret); // yield.asm + +void thread_resume(void *ret, thread *t) +{ + current_thread = t; + resume(t->stack, ret); +} + +#define STACK_SIZE 0xffff + +thread *thread_create(str name, void *init) +{ + thread *t = malloc(sizeof *t); + t->name = name; + t->stack_bottom = malloc(STACK_SIZE); + t->stack = t->stack_bottom + STACK_SIZE - 8; + *(void **) t->stack = init; + t->stack -= 8*8; + return t; +} + +void thread_sched(yield_arg *arg, void *stack) +{ + if (current_thread != nil) + current_thread->stack = stack; + + if (arg == nil) { + // TODO: add to some sort of runqueue? (nil means not polling for anything) + } else if (arg->exit) { + free(current_thread->stack_bottom); + free(current_thread); + current_thread = nil; + } else if (arg->timeout >= 0) { + // TODO: meow + } + + for (;;) { + if (queue_read.len == 0) { + disable_irqs(); + + // swap queues + event_queue tmp = queue_read; + queue_read = queue_write; + queue_write = tmp; + + enable_irqs(); + } + + if (queue_read.len > 0) { + event *e = malloc(sizeof *e); + *e = queue_read.data[--queue_read.len]; + + if (irq_services[e->irq] == nil) + free(e); // *shrug* + else + // this never returns. callee must free e + thread_resume(e, irq_services[e->irq]); + } + + wait_irq(); + } +} + +void thread_init() +{ + thread_sched_stack = malloc(STACK_SIZE); + + queue_read = (event_queue) { 0, 1024, malloc(1024 * sizeof(event)) }; + queue_write = (event_queue) { 0, 1024, malloc(1024 * sizeof(event)) }; +} diff --git a/stage3/thread.h b/stage3/thread.h new file mode 100644 index 0000000..9f5ff2f --- /dev/null +++ b/stage3/thread.h @@ -0,0 +1,40 @@ +#ifndef THREAD_H +#define THREAD_H + +#include "def.h" + +typedef struct { + bool exit; + i64 timeout; +} yield_arg; + +void *yield(void *arg); + +typedef struct { + str name; + void *stack_bottom; + void *stack; +} thread; + +typedef struct { + u8 irq; + union { + u8 scancode; + } data; +} event; + +typedef struct { + usize len; + usize cap; + event *data; +} event_queue; + +extern event_queue queue_write; +extern thread *irq_services[16]; + +void thread_init(); +void thread_resume(void *ret, thread *t); +thread *thread_create(str name, void *init); +void thread_sched(yield_arg *arg, void *stack); + +#endif diff --git a/stage3/yield.asm b/stage3/yield.asm new file mode 100644 index 0000000..c078f16 --- /dev/null +++ b/stage3/yield.asm @@ -0,0 +1,45 @@ +extern thread_sched, thread_sched_stack +global yield, resume + +extern print_num, halt + +yield: + ; push rip (done using call) + push rbx + push rbp + push rdi + push rsi + push r12 + push r13 + push r14 + push r15 + + cld + ; mov rdi, rdi + mov rsi, rsp + mov rsp, [thread_sched_stack] + jmp thread_sched + +; stack in rdi +; return in rsi +resume: + mov rsp, rdi + mov rax, rsi + + pop r15 + pop r14 + pop r13 + pop r12 + pop rsi + pop rdi + pop rbp + pop rbx + + ;mov rdi, [rsp] + ;mov rsi, 16 + ;mov rdx, 0 + ;call print_num + ;cli + ;call halt + + ret ; pop rip diff --git a/util/dump2cuddlekeys/.gitignore b/util/dump2cuddlekeys/.gitignore new file mode 100644 index 0000000..ba69a71 --- /dev/null +++ b/util/dump2cuddlekeys/.gitignore @@ -0,0 +1 @@ +dump2cuddlekeys diff --git a/util/dump2cuddlekeys/Makefile b/util/dump2cuddlekeys/Makefile new file mode 100644 index 0000000..07b7bb2 --- /dev/null +++ b/util/dump2cuddlekeys/Makefile @@ -0,0 +1,8 @@ +dump2cuddlekeys: main.c + gcc -Wall -Wextra main.c -o dump2cuddlekeys + +dumpkeys: + dumpkeys -C/dev/tty1 | grep '^keycode' | less + +preview: map2cuddlekeys + dumpkeys -C/dev/tty1 | ./dump2cuddlekeys | hexdump -C diff --git a/util/dump2cuddlekeys/main.c b/util/dump2cuddlekeys/main.c new file mode 100644 index 0000000..ec0039e --- /dev/null +++ b/util/dump2cuddlekeys/main.c @@ -0,0 +1,89 @@ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +int main() +{ + char keymap[256] = { '\0' }; + + char *line = NULL; + size_t cap = 0; + ssize_t len; + while ((len = getline(&line, &cap, stdin)) != -1) { + int code; + char key[len+1]; + + if (sscanf(line, "keycode %d = %s", &code, key) != 2) + continue; + + char c = '\0'; + + struct { + char c; + const char *name; + } defs[] = { + { '\n', "Return" }, + { ' ', "space" }, + { '\b', "Delete" }, + { '!', "exclam" }, + { '&', "ampersand" }, + { '%', "percent" }, + { '$', "dollar" }, + { '\'', "apostrophe" }, + { '(', "parenleft" }, + { ')', "parenright" }, + { '*', "asterisk" }, + { '+', "plus" }, + { ',', "comma" }, + { '-', "minus" }, + { '.', "period" }, + { '/', "slash" }, + { '0', "zero" }, + { '1', "one" }, + { '2', "two" }, + { '3', "three" }, + { '4', "four" }, + { '5', "five" }, + { '6', "six" }, + { '7', "seven" }, + { '8', "eight" }, + { '9', "nine" }, + { ':', "colon" }, + { ';', "semicolon" }, + { '<', "less" }, + { '=', "equal" }, + { '>', "greater" }, + { '?', "question" }, + { '\n', "linefeed" }, + { '\\', "backslash" }, + { '\t', "Tab" }, + { '@', "at" }, + { '[', "bracketleft" }, + { ']', "bracketright" }, + { '(', "{" }, + { ')', "}" }, + { '#', "numbersign" }, + { '^', "asciicircum" }, + }; + + if (strlen(key) == 1) + c = key[0]; + else if (strlen(key) == 2 && key[0] == '+') + c = key[1]; + else for (size_t i = 0; i < sizeof defs / sizeof *defs; i++) + if (strcmp(defs[i].name, key) == 0) { + c = defs[i].c; + break; + } + + if (c != '\0') + keymap[(unsigned char) code] = (char) c; + else if (strcmp(key, "nul") != 0) + {} // fprintf(stderr, "unhandled: %s\n", key); + } + + if (line != NULL) + free(line); + + fwrite(keymap, 1, 256, stdout); +} |