ref: 086331e6bf7b682b12ca392130160a1afb371f12
parent: c2d48b328d4c3d0b91d657e89e2da3a97cd1b528
author: mkf <mkf@cloud9p.org>
date: Mon Nov 13 01:59:06 EST 2023
God knows what i did. add a half-baked ps2 thingi, add backspace support to console-vga, simplify boot.s, a simple shell like, some fixes on com.h as well.
--- a/Makefile
+++ b/Makefile
@@ -14,6 +14,8 @@
L=\
libc/strlen.o\
libc/strcmp.o\
+ libc/memcpy.o\
+ libc/memset.o\
K=\
pc/x86.o\
@@ -20,6 +22,7 @@
pc/kern.o\
pc/boot.o\
pc/vga.o\
+ pc/ps2.o\
pc/com.o\
${L}
@@ -37,4 +40,4 @@
rm -f *.o *.elf ${K}
qemu: teppich.elf
- $(QEMU) $(QFLAGS) teppich.elf
\ No newline at end of file
+ $(QEMU) $(QFLAGS) teppich.elf
--- a/include/com.h
+++ b/include/com.h
@@ -3,6 +3,8 @@
void com_init(uint16 port, uint32 baud_rate);
void com_putchar(uint16 port, uint8 c);
-uint8 com_getchar(uint16 port);
-void com1_putchar(char c);
-void com1_puts(char* s);
\ No newline at end of file
+void com_putc(char c);
+void com_puts(char* s);
+char com_getchar(uint16 port);
+char com_getc(void);
+char* com_getl(void);
\ No newline at end of file
--- a/include/libc.h
+++ b/include/libc.h
@@ -2,3 +2,5 @@
int strlen(char *s);
int strcmp(char *s1, char *s2);
+void* memset(void* src, char c, unsigned int len);
+void* memcpy(void *a1, void *a2, unsigned int len);
--- a/include/ps2.h
+++ b/include/ps2.h
@@ -1,6 +1,30 @@
#pragma once
#define KB 0x60
+static char keymap[128] = {
+ "\0\x1b""1234567890-=\b\t"
+ "qwertyuiop[]\r\0as"
+ "dfghjkl;'`\0\\zxcv"
+ "bnm,./\0*\0 \0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0""789-456+1"
+ "230."
+};
+
+static char shifted_kbmap[128] =
+{
+ "\0\x1b""!@#$%^&*()_+\b\t"
+ "QWERTYUIOP{}\r\0AS"
+ "DFGHJKL:\"~\0|ZXCV"
+ "BNM<>?\0\0\0 \0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0""789-456+1"
+ "230."
+};
+
+enum KB_CTR_CMD
+{
+ ENABLE = 0xAE,
+};
+
enum KB_CMD
{
SET_LED = 0xED,
@@ -31,91 +55,6 @@
};
/* minix's input.h, Bedankt anderw, heel gaaf! */
-enum {
- KEY_A = 0x0004,
- KEY_B,
- KEY_C,
- KEY_D,
- KEY_E,
- KEY_F,
- KEY_G,
- KEY_H,
- KEY_I,
- KEY_J,
- KEY_K,
- KEY_L,
- KEY_M,
- KEY_N,
- KEY_O,
- KEY_P,
- KEY_Q,
- KEY_R,
- KEY_S,
- KEY_T,
- KEY_U,
- KEY_V,
- KEY_W,
- KEY_X,
- KEY_Y,
- KEY_Z,
- KEY_1,
- KEY_2,
- KEY_3,
- KEY_4,
- KEY_5,
- KEY_6,
- KEY_7,
- KEY_8,
- KEY_9,
- KEY_0,
- KEY_ENTER,
- KEY_ESCAPE,
- KEY_BACKSPACE,
- KEY_TAB,
- KEY_SPACEBAR,
- KEY_DASH,
- KEY_EQUAL,
- KEY_OPEN_BRACKET,
- KEY_CLOSE_BRACKET,
- KEY_BACKSLASH,
- KEY_EUROPE_1,
- KEY_SEMICOLON,
- KEY_APOSTROPH,
- KEY_GRAVE_ACCENT,
- KEY_COMMA,
- KEY_PERIOD,
- KEY_SLASH,
- KEY_CAPS_LOCK,
-
- KEY_F1,
- KEY_F2,
- KEY_F3,
- KEY_F4,
- KEY_F5,
- KEY_F6,
- KEY_F7,
- KEY_F8,
- KEY_F9,
- KEY_F10,
- KEY_F11,
- KEY_F12,
-
- KEY_PRINT_SCREEN,
- KEY_SCROLL_LOCK,
- KEY_PAUSE,
- KEY_INSERT,
- KEY_HOME,
- KEY_PAGE_UP,
- KEY_DELETE,
- KEY_END,
- KEY_PAGE_DOWN,
- KEY_RIGHT_ARROW,
- KEY_LEFT_ARROW,
- KEY_DOWN_ARROW,
- KEY_UP_ARROW,
- KEY_NUM_LOCK,
-
- /* did you expected to see the reset of scan codes here?
- who do you think i am? a nerd? */
-};
+char ps2_getc(void);
+void ps2_init(void);
--- a/include/vga.h
+++ b/include/vga.h
@@ -31,8 +31,9 @@
static uint8 vga_gencolor(int fg, int bg);
static uint16 vga_char(unsigned char c, uint8 color);
+void vga_clear(char c);
void vga_init(int fg, int bg);
void vga_writeto(char c, uint8 color, int x, int y);
void vga_nl(void);
void vga_putc(char c);
-void vga_puts(char *s);
\ No newline at end of file
+void vga_puts(char *s);
--- a/include/x86.h
+++ b/include/x86.h
@@ -1,8 +1,9 @@
#pragma once
#include <u.h>
-#define COM1 0x3f8
+#define COM1 0x3F8
#define KB 0x60
+#define KB_CTR 0x64
#define outb(port,data) asm volatile("out %0, %1" : : "a" (data), "d" (port));
--- a/pc/boot.s
+++ b/pc/boot.s
@@ -36,33 +36,10 @@
.skip 16384 # 16 KiB
stack_top:
-/*
-The linker script specifies _start as the entry point to the kernel and the
-bootloader will jump to this position once the kernel has been loaded. It
-doesn't make sense to return from this function as the bootloader is gone.
-*/
.section .text
.global _start
-.type _start, @function
_start:
- /*
- The bootloader has loaded us into 32-bit protected mode on a x86
- machine. Interrupts are disabled. Paging is disabled. The processor
- state is as defined in the multiboot standard. The kernel has full
- control of the CPU. The kernel can only make use of hardware features
- and any code it provides as part of itself. There's no printf
- function, unless the kernel provides its own <stdio.h> header and a
- printf implementation. There are no security restrictions, no
- safeguards, no debugging mechanisms, only what the kernel provides
- itself. It has absolute and complete power over the
- machine.
- */
-
- /*
- To set up a stack, we set the esp register to point to the top of the
- stack (as it grows downwards on x86 systems). This is necessarily done
- in assembly as languages such as C cannot function without a stack.
- */
+ /* c needs a stack */
mov $stack_top, %esp
/*
@@ -86,24 +63,3 @@
*/
call kernel_main
- /*
- If the system has nothing more to do, put the computer into an
- infinite loop. To do that:
- 1) Disable interrupts with cli (clear interrupt enable in eflags).
- They are already disabled by the bootloader, so this is not needed.
- Mind that you might later enable interrupts and return from
- kernel_main (which is sort of nonsensical to do).
- 2) Wait for the next interrupt to arrive with hlt (halt instruction).
- Since they are disabled, this will lock up the computer.
- 3) Jump to the hlt instruction if it ever wakes up due to a
- non-maskable interrupt occurring or due to system management mode.
- */
- cli
-1: hlt
- jmp 1b
-
-/*
-Set the size of the _start symbol to the current location '.' minus its start.
-This is useful when debugging or when you implement call tracing.
-*/
-.size _start, . - _start
--- a/pc/com.c
+++ b/pc/com.c
@@ -52,7 +52,20 @@
outb(port, c);
}
-uint8
+void
+com_putc(char c)
+{
+ com_putchar(COM1, c);
+}
+
+void
+com_puts(char* s)
+{
+ for(int i = 0 ; i < strlen(s) ; i++)
+ com_putc(s[i]);
+}
+
+char
com_getchar(uint16 port)
{
while(!(inb(port + 5) & 1))
@@ -60,15 +73,21 @@
return inb(port);
}
-void
-com1_putchar(char c)
+char
+com_getc(void)
{
- com_putchar(COM1, c);
+ return com_getchar(COM1);
}
-void
-com1_puts(char* s)
+char*
+com_getl(void)
{
- for(int i = 0 ; i < strlen(s) ; i++)
- com1_putchar(s[i]);
+ char *cmd, c;
+ int i = 0;
+ /* might c be '\n'? unlikely */
+ while(c != '\n')
+ {
+ cmd[i] = c;
+ }
+ return cmd;
}
\ No newline at end of file
--- a/pc/kern.c
+++ b/pc/kern.c
@@ -1,17 +1,84 @@
#include <vga.h>
#include <com.h>
#include <ps2.h>
+#include <libc.h>
/* abandon hope, all ye who enter here */
-void panic(void)
+void
+panic(void)
{
vga_puts("panic: give up. it's over.\n");
- com1_puts("panic: give up. it's over.\n");
+ com_puts("panic: give up. it's over.\n");
+
}
-void kernel_main(void)
+int
+run(char* cmd)
{
+ /* vga_puts(cmd); */
+
+ /* replace it with a proper table */
+ if(!strcmp(cmd, "clear"))
+ {
+ vga_clear(' ');
+ }
+ else if(!strcmp(cmd, "hello"))
+ {
+ vga_puts("hi");
+ }
+ else if(!strcmp(cmd, "reboot"))
+ return 0;
+ else
+ vga_puts("no such command");
+
+ vga_putc('\n');
+ return 1;
+
+}
+
+void
+repl(void)
+{
+ char c;
+ char *cmd = "";
+ int i = 0;
+
+ vga_puts("salam az Teppich\n");
+ vga_puts("> ");
+
+ while(1)
+ {
+
+ c = ps2_getc();
+ if(c == 0)
+ continue;
+
+ vga_putc(c);
+
+ if(c == '\r' || c == '\n')
+ {
+ if(!run(cmd))
+ return;
+ /* clear the mess */
+ i = 0;
+ memset(cmd, 0, 16);
+
+ vga_puts("> ");
+
+ }
+ else
+ {
+ *(cmd+i) = c; /* heb */
+ i++;
+ }
+ }
+}
+
+
+void
+kernel_main(void)
+{
vga_init(WHITE, BLUE);
- vga_puts("check out serial console");
- com1_puts("check out VGA console");
+
+ repl();
}
--- a/pc/ps2.c
+++ b/pc/ps2.c
@@ -1,0 +1,34 @@
+#include <u.h>
+#include <x86.h>
+#include <ps2.h>
+
+uint8
+ps2_read_status(void)
+{
+ return inb(KB_CTR);
+}
+
+void
+ps2_init()
+{
+ int a = 256 - 3; // 2^8 - 1- 2
+ outb(0x64, SET_RATE);
+ outb(0x64, a);
+}
+
+char
+ps2_getc()
+{
+ char c;
+ while(1)
+ {
+ if(!(ps2_read_status() & 1))
+ return 0;
+
+ c = inb(KB);
+ if(c & 0x80)
+ return 0;
+ return keymap[c];
+
+ }
+}
--- a/pc/vga.c
+++ b/pc/vga.c
@@ -21,10 +21,12 @@
{
for (size_t x = 0; x < VGA_WIDTH; x++)
{
- const size_t index = y * VGA_WIDTH + x;
+ uint16 index = y * VGA_WIDTH + x;
vga_buf[index] = vga_char(c, vga_color);
}
}
+ vga_row = 0;
+ vga_col = 0;
}
void
@@ -57,8 +59,10 @@
void
vga_putc(char c)
{
+ int index = vga_row * VGA_WIDTH + vga_col;
switch(c)
{
+ case '\r':
case '\n':
vga_nl();
return;
@@ -65,6 +69,33 @@
case '\t':
for(int i = 0 ; i < 4 ; i++)
vga_putc(' ');
+ return;
+ case '\b':
+ if(vga_col > 0)
+ {
+ /* index points at current loction of cursor, which is empty. */
+ vga_buf[index - 1] = vga_char(' ', vga_color);
+ vga_col--;
+ }
+
+ /*
+ is the following needed? i wonder.
+ i'm aware of no OSes that allow their raw terminal interface
+ allow returing to previous lines.
+ only Plan 9 console driver allows this on rio.
+
+ maybe it's safer to skip it.... for now.
+
+ else if(vga_row == 0)
+ {
+ // we need a smarter terminal-ish version
+ // smh like
+ // vga_row = vga_find_last_nonchar(' ');
+
+ vga_row = VGA_WIDTH;
+ }
+ */
+
return;
default:
vga_writeto(c, vga_color, vga_col, vga_row);