*.swp
*.img
*.map
-dis1
-dis2
+dis
*.log
86kern
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)
.PHONY: disasm
disasm: $(bin)
- ndisasm -o 0x7c00 $< >dis1
- ndisasm -o 0x98000 -e 512 $< >dis2
+ ndisasm -o 0x600 $< >dis
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*);
}
* (.rodata*);
* (.data*);
}
- .bss ALIGN(4) (NOLOAD): {
+ .bss ALIGN(4): {
_bss_start = .;
_bss_start_off = _bss_start - _kern_start;
* (.bss*);
--- /dev/null
+#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_ */
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
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
--- /dev/null
+#ifndef CON_H_
+#define CON_H_
+
+struct console {
+ void (*clear)(void*);
+ void (*putc)(void*, char c);
+
+ void *data;
+};
+
+#endif /* CON_H_ */
--- /dev/null
+#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, ®s, ®s);
+ 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, ®s, ®s);
+ if(regs.h.bh == 0xff) {
+ return -1;
+ }
+
+ disp_type = DISP_EGA;
+ mono = regs.h.bh;
+ return 0;
+}
+
+static int detect_eqlist(void)
+{
+}
--- /dev/null
+#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_ */
--- /dev/null
+#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);
+}
--- /dev/null
+#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_ */
--- /dev/null
+; 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:
--- /dev/null
+#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_ */
+#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;
}
}
+ */
}