ref: bf6d794b8e8eb4bebd0bc8e692d5dec6265d285c
parent: bde44feca3fd7d9bf18732e478e379c39705efdd
author: mkf <mkf@cloud9p.org>
date: Thu Nov 9 11:19:51 EST 2023
import sources², add serial console
--- /dev/null
+++ b/include/com.h
@@ -1,0 +1,8 @@
+#pragma once
+#include <u.h>
+
+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
--- /dev/null
+++ b/include/libc.h
@@ -1,0 +1,4 @@
+#pragma once
+
+int strlen(char *s);
+int strcmp(char *s1, char *s2);
--- /dev/null
+++ b/include/pc.h
@@ -1,0 +1,2 @@
+#define COM1 0x3f8
+#define KB 0x60
--- /dev/null
+++ b/include/ps2.h
@@ -1,0 +1,121 @@
+#pragma once
+#define KB 0x60
+
+enum KB_CMD
+{
+ SET_LED = 0xED,
+ ECHO = 0xEE, /* no knock-knock jokes are allowed in this comment*/
+ SET_SCANCODE = 0xF0,
+ IDENTIFY_KB = 0xF2, /* checks if something is there */
+ SET_RATE = 0xF3, /* also sets delay */
+
+ DO_SCAN = 0xF4,
+ DONT_SCAN = 0xF5, /* may also restore default parameters */
+
+ C_RESEND = 0xFE,
+ RESET = 0xFF,
+};
+
+enum KB_ANS
+{
+ INT_ERR1 = 0x00,
+ INT_ERR2 = 0xFF,
+
+ TEST_OK = 0xAA,
+ ECHO_ACK = 0xEE,
+ CMD_ACK = 0xFA,
+ A_RESEND = 0xFE,
+
+ TEST_ERR1 = 0xFC, /* either of which may happen */
+ TEST_ERR2 = 0xFD,
+};
+
+/* 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? */
+};
--- /dev/null
+++ b/include/u.h
@@ -1,0 +1,14 @@
+#pragma once
+
+#define nil ((void*)0x0)
+
+typedef int size_t;
+
+typedef unsigned char uint8;
+typedef char int8;
+
+typedef unsigned short uint16;
+typedef short int16;
+
+typedef unsigned long uint32;
+typedef long int32;
\ No newline at end of file
--- /dev/null
+++ b/include/vga.h
@@ -1,0 +1,38 @@
+#pragma once
+#include <u.h>
+
+static const size_t VGA_WIDTH = 80; /* x */
+static const size_t VGA_HEIGHT = 25; /* y */
+
+size_t vga_row;
+size_t vga_col;
+
+uint8 vga_color;
+uint16* vga_buf;
+
+enum {
+ BLACK = 0,
+ BLUE,
+ GREEN,
+ CYAN,
+ RED,
+ MAGENTA,
+ BROWN,
+ LIGHT_GREY,
+ DARK_GREY,
+ LIGHT_BLUE,
+ LIGHT_GREEN,
+ LIGHT_CYAN,
+ LIGHT_RED,
+ LIGHT_MAGENTA,
+ LIGHT_BROWN,
+ WHITE,
+};
+
+static uint8 vga_gencolor(int fg, int bg);
+static uint16 vga_char(unsigned char c, uint8 color);
+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
--- /dev/null
+++ b/include/x86.h
@@ -1,0 +1,18 @@
+#pragma once
+#include <u.h>
+
+#define COM1 0x3f8
+#define KB 0x60
+
+#define outb(port,data) asm volatile("out %0, %1" : : "a" (data), "d" (port));
+
+#define inb(port) ({ \
+unsigned char _v; \
+__asm__ volatile ("inb %%dx,%%al":"=a" (_v):"d" (port)); \
+_v; \
+})
+
+void instr(uint16 port, uint8* address, uint32 size);
+void sti(void);
+void cli(void);
+void nop(void);
--- /dev/null
+++ b/libc/strcmp.c
@@ -1,0 +1,17 @@
+int
+strcmp(char *s1, char *s2)
+{
+ unsigned int c1, c2;
+
+ for(;;) {
+ c1 = *s1++;
+ c2 = *s2++;
+ if(c1 != c2) {
+ if(c1 > c2)
+ return 1;
+ return -1;
+ }
+ if(c1 == 0)
+ return 0;
+ }
+}
--- /dev/null
+++ b/libc/strlen.c
@@ -1,0 +1,8 @@
+int
+strlen(char *s)
+{
+ int i = 0;
+ while(s[i])
+ i++;
+ return i;
+}
\ No newline at end of file
--- /dev/null
+++ b/pc/boot.s
@@ -1,0 +1,109 @@
+/* Declare constants for the multiboot header. */
+.set ALIGN, 1<<0 /* align loaded modules on page boundaries */
+.set MEMINFO, 1<<1 /* provide memory map */
+.set FLAGS, ALIGN | MEMINFO /* this is the Multiboot 'flag' field */
+.set MAGIC, 0x1BADB002 /* 'magic number' lets bootloader find the header */
+.set CHECKSUM, -(MAGIC + FLAGS) /* checksum of above, to prove we are multiboot */
+
+/*
+Declare a multiboot header that marks the program as a kernel. These are magic
+values that are documented in the multiboot standard. The bootloader will
+search for this signature in the first 8 KiB of the kernel file, aligned at a
+32-bit boundary. The signature is in its own section so the header can be
+forced to be within the first 8 KiB of the kernel file.
+*/
+.section .multiboot
+.align 4
+.long MAGIC
+.long FLAGS
+.long CHECKSUM
+
+/*
+The multiboot standard does not define the value of the stack pointer register
+(esp) and it is up to the kernel to provide a stack. This allocates room for a
+small stack by creating a symbol at the bottom of it, then allocating 16384
+bytes for it, and finally creating a symbol at the top. The stack grows
+downwards on x86. The stack is in its own section so it can be marked nobits,
+which means the kernel file is smaller because it does not contain an
+uninitialized stack. The stack on x86 must be 16-byte aligned according to the
+System V ABI standard and de-facto extensions. The compiler will assume the
+stack is properly aligned and failure to align the stack will result in
+undefined behavior.
+*/
+.section .bss
+.align 16
+stack_bottom:
+.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.
+ */
+ mov $stack_top, %esp
+
+ /*
+ This is a good place to initialize crucial processor state before the
+ high-level kernel is entered. It's best to minimize the early
+ environment where crucial features are offline. Note that the
+ processor is not fully initialized yet: Features such as floating
+ point instructions and instruction set extensions are not initialized
+ yet. The GDT should be loaded here. Paging should be enabled here.
+ C++ features such as global constructors and exceptions will require
+ runtime support to work as well.
+ */
+
+ /*
+ Enter the high-level kernel. The ABI requires the stack is 16-byte
+ aligned at the time of the call instruction (which afterwards pushes
+ the return pointer of size 4 bytes). The stack was originally 16-byte
+ aligned above and we've pushed a multiple of 16 bytes to the
+ stack since (pushed 0 bytes so far), so the alignment has thus been
+ preserved and the call is well defined.
+ */
+ 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