foo
authorJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 19 Nov 2022 02:40:01 +0000 (04:40 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 19 Nov 2022 02:40:01 +0000 (04:40 +0200)
13 files changed:
.gitignore
kern/Makefile
kern/kern.ld
kern/src/asmutil.h [new file with mode: 0644]
kern/src/boot.asm
kern/src/con.h [new file with mode: 0644]
kern/src/disp.c [new file with mode: 0644]
kern/src/disp.h [new file with mode: 0644]
kern/src/intr.c [new file with mode: 0644]
kern/src/intr.h [new file with mode: 0644]
kern/src/intrent.asm [new file with mode: 0644]
kern/src/libc/inttypes.h [new file with mode: 0644]
kern/src/main.c

index 8a10a5b..8821a9c 100644 (file)
@@ -3,7 +3,6 @@
 *.swp
 *.img
 *.map
-dis1
-dis2
+dis
 *.log
 86kern
index 70e479b..f4ff034 100644 (file)
@@ -13,13 +13,14 @@ CC = ia16-elf-gcc
 LD = ia16-elf-ld
 
 CFLAGS = -march=i8088 -mtune=i8088 -MMD
+LDFLAGS = -T kern.ld -Map kern.map
 
 $(img): $(bin)
        dd if=/dev/zero of=$@ bs=512 count=$(disk_numsec)
        dd if=$< of=$@ bs=512 conv=notrunc
 
 $(bin): $(obj)
-       $(LD) -T kern.ld -Map kern.map -o $@ $(obj)
+       $(LD) -o $@ $(obj) $(LDFLAGS)
 
 -include $(dep)
 
@@ -45,5 +46,4 @@ debug: $(img)
 
 .PHONY: disasm
 disasm: $(bin)
-       ndisasm -o 0x7c00 $< >dis1
-       ndisasm -o 0x98000 -e 512 $< >dis2
+       ndisasm -o 0x600 $< >dis
index 3922811..c851a6d 100644 (file)
@@ -2,19 +2,18 @@ OUTPUT_FORMAT(binary)
 ENTRY(_start)
 
 SECTIONS {
-       . = 0x7c00;
+       /* we'll relocate the boot sector to this address immediately, and
+        * continue loading the kernel from the end of it
+        */
+       . = 0x600;
+       _bootsect_start = .;
        .bootsect : {
                * (.bootsect);
        }
-       _bootsect_end = .;
 
-       /* load high out of the way, to leave the rest of RAM for userland
-        * reserving the top 32kb for the kernel for now
-        */
-       . = 0x98000;
        _kern_start = .;
        _kern_start_seg = _kern_start >> 4;
-       .text : AT(_bootsect_end) {
+       .text : {
                * (.startup);
                * (.text*);
        }
@@ -22,7 +21,7 @@ SECTIONS {
                * (.rodata*);
                * (.data*);
        }
-       .bss ALIGN(4) (NOLOAD): {
+       .bss ALIGN(4): {
                _bss_start = .;
                _bss_start_off = _bss_start - _kern_start;
                * (.bss*);
diff --git a/kern/src/asmutil.h b/kern/src/asmutil.h
new file mode 100644 (file)
index 0000000..751def6
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef ASMUTIL_H_
+#define ASMUTIL_H_
+
+#include <inttypes.h>
+
+struct wordregs {
+       uint16_t ax, bx, cx, dx;
+       uint16_t si, di, cflag;
+} __attribute__((packed));
+
+struct byteregs {
+       uint8_t al, ah;
+       uint8_t bl, bh;
+       uint8_t cl, ch;
+       uint8_t dl, dh;
+} __attribute__((packed));
+
+union regs {
+       struct wordregs w;
+       struct byteregs h;
+};
+
+void int86(int n, union regs *inregs, union regs *outregs);
+
+#define FP_SEG(x)      ((uint16_t)((uint32_t)(x) >> 16))
+#define FP_OFFS(x)     ((uint16_t)(x))
+#define MK_FP(s, o)    (((uint32_t)(s) << 16) | (uint32_t)(o))
+
+#define enable() asm("sti")
+#define disable() asm("cli")
+
+#define outp(p, v)     \
+       asm volatile( \
+               "outb %1, %0" \
+               :: "d"(p), "a"((unsigned char)v))
+
+#define outpw(p, v)    \
+       asm volatile( \
+               "outw %1, %0" \
+               :: "d"(p), "a"((unsigned short)v))
+
+static inline unsigned char inp(int p)
+{
+       unsigned char res;
+       asm volatile(
+               "inb %1, %0" \
+               : "=a"(res) : "d"(p));
+       return res;
+}
+
+static inline unsigned short inpw(int p)
+{
+       unsigned short res;
+       asm volatile(
+               "inw %1, %0" \
+               : "=a"(res) : "d"(p));
+       return res;
+}
+
+
+#endif /* ASMUTIL_H_ */
index 5be618b..25486e6 100644 (file)
@@ -3,18 +3,19 @@
        bits 16
        section .bootsect
 
+extern _bootsect_start
 extern _kern_start_seg
 extern _kern_size
 
-boot_driveno   equ 7b00h
-num_read_tries equ 7b06h       ; 2 bytes
-sect_pending   equ 7b08h       ; 2 bytes
-sect_per_track equ 7b0ah       ; 2 bytes
-cur_head       equ 7b0ch       ; 2 bytes - current head
-start_sect     equ 7b0eh       ; 2 bytes - start sector in track
-destptr                equ 7b10h       ; 2 bytes - destination pointer
-num_heads      equ 7b12h       ; 2 bytes - number of heads
-cur_cyl                equ 7b14h       ; 2 bytes - current cylinder
+boot_driveno   equ 0500h
+num_read_tries equ 0506h       ; 2 bytes
+sect_pending   equ 0508h       ; 2 bytes
+sect_per_track equ 050ah       ; 2 bytes
+cur_head       equ 050ch       ; 2 bytes - current head
+start_sect     equ 050eh       ; 2 bytes - start sector in track
+destptr                equ 0510h       ; 2 bytes - destination pointer
+num_heads      equ 0512h       ; 2 bytes - number of heads
+cur_cyl                equ 0514h       ; 2 bytes - current cylinder
 
 %macro floppy_motor_off 0
        pushf
@@ -66,10 +67,17 @@ start:
        mov ds, ax
        mov es, ax
        mov ss, ax
+       mov [boot_driveno], dl  ; save boot drive number
+
+       ; relocate boot sector to 600h
+       mov si, 0x7c00
+       mov di, _bootsect_start
+       mov cx, 256
+       rep movsw
+
        jmp 00:.setcs
 .setcs:
-       mov sp, 0x7b00  ; temp stack below our vars
-       mov [boot_driveno], dl
+       mov sp, _bootsect_start ; temp stack below our relocated address
 
        ; query sectors per track
        mov ah, 8       ; get drive parameters call, dl already has the drive
diff --git a/kern/src/con.h b/kern/src/con.h
new file mode 100644 (file)
index 0000000..9a356fc
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef CON_H_
+#define CON_H_
+
+struct console {
+       void (*clear)(void*);
+       void (*putc)(void*, char c);
+
+       void *data;
+};
+
+#endif /* CON_H_ */
diff --git a/kern/src/disp.c b/kern/src/disp.c
new file mode 100644 (file)
index 0000000..f6e9014
--- /dev/null
@@ -0,0 +1,104 @@
+#include "disp.h"
+
+static void detect_video(void);
+
+struct console con_disp = { clear_disp, disp_putc, 0 };
+
+static uint16_t __far *vmem;
+static uint16_t cur_attr;
+static int cur_x, cur_y;
+static int cur_scroll;
+static int mono;
+
+void init_disp(void)
+{
+       detect_video();
+}
+
+static void detect_video(void)
+{
+       mono = 0;
+       disp_type = DISP_UNK;
+
+       if(detect_vgainfo() == 0) {
+               goto done;
+       }
+       if(detect_egainfo() == 0) {
+               goto done;
+       }
+       if(detect_eqlist() == 0) {
+               goto done;
+       }
+
+done:
+       vmem = mono ? MK_FP(0xb000, 0) : MK_FP(0xb800, 0);
+}
+
+static int detect_vgainfo(void)
+{
+       union regs regs;
+
+       regs.w.ax = 0x1a00;
+       int86(0x10, &regs, &regs);
+       if(regs.h.al != 0x1a) {
+               return -1;
+       }
+
+       switch(regs.h.bl) {
+       case 1:
+               disp_type = DISP_MDA;
+               mono = 1;
+               break;
+       case 2:
+               disp_type = DISP_CGA;
+               break;
+       case 4:
+               disp_type = DISP_EGA;
+               break;
+       case 5:
+               disp_type = DISP_EGA;
+               mono = 1;
+               break;
+       case 6:
+               disp_type = DISP_PGA;
+               break;
+       case 7:
+               disp_type = DISP_VGA;
+               mono = 1;
+               break;
+       case 8:
+               disp_type = DISP_VGA;
+               break;
+       case 0xa:
+       case 0xc:
+               disp_type = DISP_MCGA;
+               break;
+       case 0xb:
+               disp_type = DISP_MCGA;
+               mono = 1;
+               break;
+       default:
+               return -1;
+       }
+       return 0;
+}
+
+static int detect_egainfo(void)
+{
+       union regs regs;
+
+       regs.w.ax = 0x1200;
+       regs.w.bx = 0xff10;
+       int86(0x10, &regs, &regs);
+       if(regs.h.bh == 0xff) {
+               return -1;
+       }
+
+       disp_type = DISP_EGA;
+       mono = regs.h.bh;
+       return 0;
+}
+
+static int detect_eqlist(void)
+{
+}
diff --git a/kern/src/disp.h b/kern/src/disp.h
new file mode 100644 (file)
index 0000000..48a4d0a
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef DISP_H_
+#define DISP_H_
+
+#include <inttypes.h>
+#include "con.h"
+
+enum {
+       BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, BROWN, LTGREY,
+       GREY, LTBLUE, LTGREEN, LTCYAN, LTRED, LTMAGENTA, YELLOW, WHITE
+};
+
+enum { DISP_UNK, DISP_MDA, DISP_CGA, DISP_EGA, DISP_PGA, DISP_MCGA, DISP_VGA };
+
+#define DISP_ATTR(fg, bg)      (((uint8_t)(bg) << 4) | ((uint8_t)(fg)))
+
+extern struct console con_disp;
+int disp_type;
+
+void init_disp(void);
+
+void clear_disp(void);
+void scroll_disp(int line);
+
+void set_cursor(int x, int y);
+void set_fgcolor(int color);
+void set_bgcolor(int color);
+
+void draw_glyph(int x, int y, int c, int attr);
+void draw_text(int x, int y, const char *s, int attr);
+
+#endif /* DISP_H_ */
diff --git a/kern/src/intr.c b/kern/src/intr.c
new file mode 100644 (file)
index 0000000..e682b30
--- /dev/null
@@ -0,0 +1,109 @@
+#include "intr.h"
+
+/* PIC command and data ports */
+#define PIC1_CMD       0x20
+#define PIC1_DATA      0x21
+#define PIC2_CMD       0xa0
+#define PIC2_DATA      0xa1
+
+/* PIC initialization command word 1 bits */
+#define ICW1_ICW4_NEEDED       (1 << 0)
+#define ICW1_SINGLE                    (1 << 1)
+#define ICW1_INTERVAL4         (1 << 2)
+#define ICW1_LEVEL                     (1 << 3)
+#define ICW1_INIT                      (1 << 4)
+/* PIC initialization command word 4 bits */
+#define ICW4_8086                      (1 << 0)
+#define ICW4_AUTO_EOI          (1 << 1)
+#define ICW4_BUF_SLAVE         (1 << 3) /* 1000 */
+#define ICW4_BUF_MASTER                (3 << 2) /* 1100 */
+#define ICW4_SPECIAL           (1 << 4)
+/* PIC operation command word 2 bits */
+#define OCW2_EOI       (1 << 5)
+
+
+#define MAX_INTR       32
+static intr_func_t intrfunc[MAX_INTR];
+
+static void (*intr_unhandled)(struct intr_frame *frm);
+
+void intr_entry_div();
+void intr_entry_trap();
+void intr_entry_nmi();
+void intr_entry_break();
+void intr_entry_ovf();
+void intr_entry_bound();
+void intr_entry_ill();
+void intr_entry_irq0();
+void intr_entry_irq1();
+void intr_entry_irq2();
+void intr_entry_irq3();
+void intr_entry_irq4();
+void intr_entry_irq5();
+void intr_entry_irq6();
+void intr_entry_irq7();
+
+extern int _kern_start_seg;
+#define KERN_CS        ((uint16_t)(&_kern_start_seg))
+
+
+void init_intr(void)
+{
+       int i;
+
+       for(i=0; i<MAX_INTR; i++) {
+               intrfunc[i] = 0;
+       }
+
+       set_intr_vect(0, KERN_CS, (uint16_t)intr_entry_div);
+}
+
+void dispatch_intr(struct intr_frame frm)
+{
+       intrfunc[frm.inum](&frm);
+}
+
+void set_intr_vect(int n, uint16_t seg, uint16_t offs)
+{
+       uint16_t *ivt = 0;
+
+       ivt[n * 4] = offs;
+       ivt[n * 4 + 1] = seg;
+}
+
+void set_intr(int n, intr_func_t func)
+{
+       intrfunc[n] = func;
+}
+
+void mask_irq(int n)
+{
+       int port;
+       unsigned char mask;
+
+       if(n < 8) {
+               port = PIC1_DATA;
+       } else {
+               port = PIC2_DATA;
+               n -= 8;
+       }
+
+       mask = inp(port) | (1 << n);
+       outp(port, mask);
+}
+
+void unmask_irq(int n)
+{
+       int port;
+       unsigned char mask;
+
+       if(n < 8) {
+               port = PIC1_DATA;
+       } else {
+               port = PIC2_DATA;
+               n -= 8;
+       }
+
+       mask = inp(port) & ~(1 << n);
+       outp(port, mask);
+}
diff --git a/kern/src/intr.h b/kern/src/intr.h
new file mode 100644 (file)
index 0000000..569dbd7
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef INTR_H_
+#define INTR_H_
+
+#include <inttypes.h>
+#include "asmutil.h"
+
+#define IRQ_TO_INUM(x) ((x) + 8)
+#define INUM_TO_IRQ(x) ((x) - 8)
+
+/* general purpose registers, pushed by interrupt entry routine */
+struct registers {
+       uint16_t di, si, bp, sp;
+       uint16_t bx, dx, cx, ax;
+} __attribute__((packed));
+
+struct intr_frame {
+       /* registers pushed by intr_entry_* */
+       struct registers regs;
+       /* interrupt number */
+       uint16_t inum;
+       /* pushed by CPU during interrupt entry */
+       uint16_t ip, cs, flags;
+} __attribute__((packed));
+
+typedef void (*intr_func_t)(struct intr_frame *frm);
+
+void init_intr(void);
+void dispatch_intr(struct intr_frame frm);
+
+/* set low level interrupt vector */
+void set_intr_vect(int n, uint16_t seg, uint16_t offs);
+/* set interrupt callback */
+void set_intr(int n, intr_func_t func);
+
+void mask_irq(int n);
+void unmask_irq(int n);
+
+#define end_of_irq(n) \
+       asm volatile( \
+               "\n\ttest $8, %0" \
+               "\n\tjz 0f" \
+               "\n\tmov $0x20, %%ax" \
+               "\n\tout %%ax, $0xa0" \
+               "\n0:\tmov $0x20, %%ax" \
+               "\n\tout %%ax, $0x20" \
+               :: "a"(n))
+
+#endif /* INTR_H_ */
diff --git a/kern/src/intrent.asm b/kern/src/intrent.asm
new file mode 100644 (file)
index 0000000..0fd515d
--- /dev/null
@@ -0,0 +1,63 @@
+; interrupt entry routines
+       cpu 8086
+       bits 16
+       section .text
+
+extern dispatch_intr
+
+%macro INTR_ENTRY 2
+global intr_entry_%2
+intr_entry_%2:
+       push bp
+       push ax
+       push bp
+       mov bp, sp
+       mov ax, %1
+       mov [bp + 4], ax
+       pop bp
+       pop ax
+       jmp intr_entry_common
+%endmacro
+
+intr_entry_common:
+       push ax
+       mov ax, sp
+       add ax, 2
+       push cx
+       push dx
+       push bx
+       push ax ; saved sp
+       push bp
+       push si
+       push di
+       call dispatch_intr
+       pop di
+       pop si
+       pop bp
+       pop bx  ; throw away saved sp
+       pop bx
+       pop dx
+       pop cx
+       pop ax
+       add sp, 2       ; remove interrupt number from the stack
+       iret
+
+; CPU exceptions
+INTR_ENTRY 0, div
+INTR_ENTRY 1, trap
+INTR_ENTRY 2, nmi
+INTR_ENTRY 3, break
+INTR_ENTRY 4, ovf
+INTR_ENTRY 5, bound
+INTR_ENTRY 6, ill
+; IRQs
+INTR_ENTRY 8, irq0
+INTR_ENTRY 9, irq1
+INTR_ENTRY 10, irq2
+INTR_ENTRY 11, irq3
+INTR_ENTRY 12, irq4
+INTR_ENTRY 13, irq5
+INTR_ENTRY 14, irq6
+INTR_ENTRY 15, irq7
+
+; vi:ts=8 sts=8 sw=8 ft=nasm:
diff --git a/kern/src/libc/inttypes.h b/kern/src/libc/inttypes.h
new file mode 100644 (file)
index 0000000..27fc5ab
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef KLIBC_INTTYPES_H_
+#define KLIBC_INTTYPES_H_
+
+typedef signed char int8_t;
+typedef short int16_t;
+typedef long int32_t;
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned long uint32_t;
+
+#endif /* KLIBC_INTTYPES_H_ */
index 1ca879b..71a613f 100644 (file)
@@ -1,13 +1,22 @@
+#include "intr.h"
+
 void kmain(void)
 {
+       /*
        int i, j;
        unsigned short __far *vmem = (void __far*)0xb8000000ul;
        unsigned short c;
+       */
+
+       init_disp();
+       init_intr();
 
+       /*
        for(i=0; i<25; i++) {
                c = ((i & 0xf) << 8) | '@';
                for(j=0; j<80; j++) {
                        *vmem++ = c;
                }
        }
+       */
 }