summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Makefile33
-rw-r--r--boot.asm41
-rw-r--r--constants.asm25
-rw-r--r--io.asm25
-rw-r--r--irq.asm248
-rw-r--r--kernel.asm305
-rw-r--r--link.ld9
8 files changed, 688 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c4ced56
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+*.o
+kernel
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..8bb5127
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,33 @@
+nasm=nasm -f elf -g
+TARGET=kernel
+
+all: $(TARGET)
+
+boot.o: boot.asm
+ $(nasm) -o boot.o boot.asm
+
+io.o: io.asm
+ $(nasm) -o io.o io.asm
+
+irq.o: irq.asm
+ $(nasm) -o irq.o irq.asm
+
+kernel.o: kernel.asm
+ $(nasm) -o kernel.o kernel.asm
+
+$(TARGET): irq.o io.o kernel.o boot.o
+ ld -g -m elf_i386 -T link.ld -o $(TARGET) boot.o io.o irq.o kernel.o
+
+run: $(TARGET)
+ qemu-system-i386 -m 2M -kernel $(TARGET)
+
+debug: $(TARGET)
+ qemu-system-i386 -d int,guest_errors -no-reboot -s -S -m 8M -kernel $(TARGET) &
+ gdb -ex 'kdev' \
+ -ex 'continue' \
+ $(TARGET)
+
+clean:
+ rm -f kernel
+ rm *.o
+
diff --git a/boot.asm b/boot.asm
new file mode 100644
index 0000000..66009e8
--- /dev/null
+++ b/boot.asm
@@ -0,0 +1,41 @@
+bits 32
+
+section .text
+ align 4
+ dd 0x1BADB002
+ dd 0x00
+ dd - (0x1BADB002 + 0x00)
+
+global start
+extern kmain
+
+start:
+ cli
+ mov esp, stack_top
+ call marker_begin
+ call kmain
+ call marker_done
+.hltloop:
+ hlt
+jmp .hltloop
+
+marker_begin:
+ mov word [VIDEO_RAM + CONSOLE_SIZE - 2], \
+ 0x4F << 8 | 'B' ; END OF MAIN MARKER
+ ret
+
+marker_done:
+ mov word [VIDEO_RAM + CONSOLE_SIZE - 2], \
+ 0x4F << 8 | 'H' ; END OF MAIN MARKER
+ ret
+
+section .data
+
+%include 'constants.asm'
+
+section .bss
+align 4
+stack_bottom:
+ resb 8192
+stack_top:
+EOK:
diff --git a/constants.asm b/constants.asm
new file mode 100644
index 0000000..d509f7d
--- /dev/null
+++ b/constants.asm
@@ -0,0 +1,25 @@
+; Interrupt Controller
+PIC1 equ 0x20 ; IO base address for master PIC
+PIC2 equ 0xA0 ; IO base address for slave PIC
+PIC1_COMMAND equ PIC1
+PIC1_DATA equ (PIC1+1)
+PIC2_COMMAND equ PIC2
+PIC2_DATA equ (PIC2+1)
+
+ICW1_ICW4 equ 0x01 ; ICW4 (not) needed
+ICW1_SINGLE equ 0x02 ; Single (cascade) mode
+ICW1_INTERVAL4 equ 0x04 ; Call address interval 4 (8)
+ICW1_LEVEL equ 0x08 ; Level triggered (edge) mode
+ICW1_INIT equ 0x10 ; Initialization - required!
+
+ICW4_8086 equ 0x01 ; 8086/88 (MCS-80/85) mode
+ICW4_AUTO equ 0x02 ; Auto (normal) EOI
+ICW4_BUF_SLAVE equ 0x08 ; Buffered mode/slave
+ICW4_BUF_MASTER equ 0x0C ; Buffered mode/master
+ICW4_SFNM equ 0x10 ; Special fully nested (not)
+
+; Video
+CONSOLE_W equ 80
+CONSOLE_H equ 25
+CONSOLE_SIZE equ CONSOLE_W * CONSOLE_H * 2
+VIDEO_RAM equ 0xb8000
diff --git a/io.asm b/io.asm
new file mode 100644
index 0000000..fd45e99
--- /dev/null
+++ b/io.asm
@@ -0,0 +1,25 @@
+section .text
+
+global pio_read
+global pio_write
+
+pio_read:
+ push ebp
+ mov ebp, esp
+
+ mov edx, [esp + 8]
+ in al, dx
+
+ leave
+ ret
+
+pio_write:
+ push ebp
+ mov ebp, esp
+
+ mov edx, [esp + 8]
+ mov al, [esp + 12]
+ out dx, al
+
+ leave
+ ret
diff --git a/irq.asm b/irq.asm
new file mode 100644
index 0000000..40ac990
--- /dev/null
+++ b/irq.asm
@@ -0,0 +1,248 @@
+section .text
+global idt_entry
+global PIC_sendEOI
+global idt_init
+extern interrupt_handler
+
+extern pio_read
+extern pio_write
+
+struc idt_entry
+ .base_low: resw 1
+ .selector: resw 1
+ .zero: resb 1
+ .flags: resb 1
+ .base_high: resw 1
+endstruc
+
+%macro no_error_code_interrupt_handler 1
+global interrupt_handler_%1:
+interrupt_handler_%1:
+ push dword 0
+ push dword %1
+ jmp common_interrupt_handler
+%endmacro
+
+%macro error_code_interrupt_handler 1
+global interrupt_handler_%1
+interrupt_handler_%1:
+ push dword %1
+ jmp common_interrupt_handler
+%endmacro
+
+%macro idt_set_gate 2
+ ; Assign values to IDT entry at interrupt (ecx)
+ ; with the offset of the interrupt handler (edx)
+ mov edx, %2
+ mov [idt + %1 * 8 + idt_entry.base_low], dx
+ mov word [idt + %1 * 8 + idt_entry.selector], 0x8
+ mov byte [idt + %1 * 8 + idt_entry.zero], 0x0
+ mov byte [idt + %1 * 8 + idt_entry.flags], 0x8e
+ shr edx, 16
+ mov word [idt + %1 * 8 + idt_entry.base_high], dx
+%endmacro
+
+common_interrupt_handler:
+ pushad
+ call interrupt_handler
+ popad
+ add esp, 8
+ iret
+
+no_error_code_interrupt_handler 0
+no_error_code_interrupt_handler 1
+no_error_code_interrupt_handler 2
+no_error_code_interrupt_handler 3
+no_error_code_interrupt_handler 4
+no_error_code_interrupt_handler 5
+no_error_code_interrupt_handler 6
+no_error_code_interrupt_handler 7
+error_code_interrupt_handler 8
+no_error_code_interrupt_handler 9
+error_code_interrupt_handler 10
+error_code_interrupt_handler 11
+error_code_interrupt_handler 12
+error_code_interrupt_handler 13
+error_code_interrupt_handler 14
+no_error_code_interrupt_handler 15
+no_error_code_interrupt_handler 16
+no_error_code_interrupt_handler 17
+no_error_code_interrupt_handler 18
+no_error_code_interrupt_handler 19
+no_error_code_interrupt_handler 20
+no_error_code_interrupt_handler 21
+no_error_code_interrupt_handler 22
+no_error_code_interrupt_handler 23
+no_error_code_interrupt_handler 24
+no_error_code_interrupt_handler 25
+no_error_code_interrupt_handler 26
+no_error_code_interrupt_handler 27
+no_error_code_interrupt_handler 28
+no_error_code_interrupt_handler 29
+no_error_code_interrupt_handler 30
+no_error_code_interrupt_handler 31
+; 32 unused
+no_error_code_interrupt_handler 33
+
+
+;interrupt_handler:
+; cmp byte [esp + 4], 0x21
+; je .int21
+;
+; jmp .end
+;
+;.int21:
+; mov dword [0xB8000], ': ) '
+; push m
+; call kprint
+;
+;.end:
+; ret
+
+PIC_sendEOI:
+ ret
+
+PIC_remap:
+ ;arguments:
+ ;offset1 - vector offset for master PIC
+ ; vectors on the master become offset1..offset1+7
+ ;offset2 - same for slave PIC: offset2..offset2+7
+
+ push ebp
+ mov ebp, esp
+
+ sub ebp, 8
+
+ push PIC1_DATA
+ call pio_read
+ mov [ebp - 4], al ; save PIC1 mask
+
+ push PIC2_DATA
+ call pio_read
+ mov [ebp - 8], al ; save PIC2 mask
+
+ push PIC1_COMMAND
+ push ICW1_INIT+ICW1_ICW4 ; initialization sequence (cascade)
+ call pio_write
+
+ push PIC2_COMMAND
+ push ICW1_INIT+ICW1_ICW4 ; initialization sequence (cascade)
+ call pio_write
+
+ push PIC1_DATA
+ push word [ebp + 8] ; ICW2: Master PIC vector offset
+ call pio_write
+
+ push PIC2_DATA
+ push word [ebp + 12] ; ICW2: Save PIC vector offset
+ call pio_write
+
+ push PIC1_DATA
+ push 0x4 ; ICW3: tell Master PIC there is a slave PIC at IRQ2 (0000 0100)
+ call pio_write
+
+ push PIC2_DATA
+ push 2 ; ICW3: tell Slave PIC its cacade identity (0000 0010)
+ call pio_write
+
+ push PIC1_DATA
+ push ICW4_8086
+ call pio_write
+
+ push PIC2_DATA
+ push ICW4_8086
+ call pio_write
+
+
+ ;; ICW3
+ ;push PIC1_DATA
+ ;push 0x20
+ ;call pio_write
+
+ ;push PIC2_DATA
+ ;push 0x28
+ ;call pio_write
+
+ ;; ICW4
+ ;push PIC1_DATA
+ ;push 0x00
+ ;call pio_write
+
+ ;push PIC2_DATA
+ ;push 0x01
+ ;call pio_write
+
+ ;; mask interrupts
+ ;push PIC1_DATA
+ ;push 0xff
+ ;call pio_write
+
+ ;push PIC2_DATA
+ ;push 0xff
+ ;call pio_write
+
+ push PIC1_DATA
+ push word [ebp - 4]
+ call pio_write
+
+ push PIC2_DATA
+ push word [ebp - 8]
+ call pio_write
+
+ add ebp, 8
+ leave
+ ret
+
+
+idt_init:
+ push ebp
+ mov ebp, esp
+
+ mov al, 0x0 ; idt's initial value
+ mov ecx, idt_entry_size * 256 - 1 ; Size of: idt
+ mov edi, idt ; pointer to: idt
+ cld ; clear direction flag
+ rep stosb ; fill array with zeros
+
+
+ idt_set_gate 33, interrupt_handler_33 ; implement INT 21
+
+ mov ebx, idt_entry_size * 256 - 1 ; size of: idt - 1
+ mov eax, idt ; pointer to: idt
+
+ mov [idt_ptr], ebx ; describe ITDR limit
+ mov [idt_ptr + 2], eax ; describe ITDR offset
+
+ push idt_ptr
+ call idt_load ; load IDTR register
+
+ leave
+ ret
+
+
+
+idt_load:
+ push ebp
+ mov ebp, esp
+
+ mov edx, [esp + 8]
+ lidt [edx]
+
+ leave
+ ret
+
+
+section .data
+%include 'constants.asm'
+
+section .bss
+align 4
+
+idt_ptr:
+ resw 1
+ resd 1
+
+idt:
+ resb idt_entry_size * 256
+
+
diff --git a/kernel.asm b/kernel.asm
new file mode 100644
index 0000000..490273c
--- /dev/null
+++ b/kernel.asm
@@ -0,0 +1,305 @@
+section .text
+align 4
+global kmain
+global interrupt_handler
+extern idt_init
+extern pio_read
+extern pio_write
+
+interrupt_handler:
+ mov ebx, [esp + 34]
+ shr ebx, 16
+ cmp ebx, 0x21
+ je .int21
+
+ jmp .end
+
+.int21:
+
+ cmp ah, 0x1
+ je .int21.kprint
+ jmp .end
+
+.int21.kprint:
+ ;sub esp, 4
+ ;mov [esp - 4], bx
+
+ ;shr bx, 8
+ ;push word bx
+
+ ;mov bx, [esp - 4]
+ ;and bx, 0xff
+ ;push bx
+
+ ;call screen_gotoxy
+ ;add esp, 8
+
+ push edx
+ call kprint
+ add esp, 4
+
+.end:
+ ret
+
+cursor_move:
+ push ebp
+ mov ebp, esp
+
+ sub ebp, 4
+ call screen_getxy
+ mov [ebp - 4], eax
+
+ push 0x3D4
+ push 14
+ call pio_write
+
+ mov ebx, [ebp + 4]
+ shr ebx, 8
+ push 0x3D5
+ push word [ebx]
+ call pio_write
+
+ push 0x3D4
+ push 15
+ call pio_write
+
+ mov ebx, [ebp + 4]
+ push 0x3D5
+ push word [ebx]
+ call pio_write
+
+ add ebp, 4
+ leave
+ ret
+
+screen_fill:
+ ; = purpose
+ ; Fills the screen with a character and color
+ ;
+ ; = stack arguments (order of use)
+ ; push ' ' ; character
+ ; push 0x07 ; color attribute
+
+ push ebp
+ mov ebp, esp
+
+ xor eax, eax ; clear eax
+ mov eax, [ebp + 8] ; get character
+ shl eax, 8 ; shift character into MSB
+ or eax, [ebp + 12] ; set color attribute
+
+ mov ecx, CONSOLE_SIZE ; use entire screen
+ mov edi, screen_buffer ; destination = screen_buffer
+ cld ; will increment esi and edi
+ rep stosw ; char+color -> screen_buffer
+
+ mov esp, ebp
+ pop ebp
+
+ ret
+
+screen_refresh:
+ push ebp
+ mov ebp, esp
+ pusha
+
+ mov ecx, CONSOLE_SIZE ; use entire screen
+ mov esi, screen_buffer ; source = screen_buffer
+ mov edi, VIDEO_RAM ; destination = video RAM
+ cld ; will increment esi and edi
+ rep movsw ; char+color -> screen_buffer
+
+ popa
+ mov esp, ebp
+ pop ebp
+ ret
+
+screen_gotoxy:
+ push ebp
+ mov ebp, esp
+ pusha
+
+ ; y * width + x
+ mov ebx, CONSOLE_W * 2
+ mov eax, [ebp + 12]
+ mul ebx
+ add eax, [ebp + 8]
+ mov [screen_pos], eax
+
+ popa
+ leave
+ ret
+
+screen_getxy:
+ push ebp
+ mov ebp, esp
+
+ mov eax, [screen_pos]
+
+ leave
+ ret
+
+screen_updatexy:
+ push ebp
+ mov ebp, esp
+
+ add word [screen_pos], 2
+
+ cmp word [screen_pos], CONSOLE_SIZE
+ call screen_scroll_up
+
+ leave
+ ret
+
+screen_scroll_up:
+ push ebp
+ mov ebp, esp
+
+ nop
+
+ leave
+ ret
+
+screen_scroll_down:
+ push ebp
+ mov ebp, esp
+
+ nop
+
+ leave
+ ret
+
+
+kprint:
+ ; = purpose
+ ; Writes a buffer to the screen
+ ;
+ ; = globals
+ ; kprint_delay: if != 0; echo slowly
+ ;
+ ; = stack arguments (order of use)
+ ; push buffer
+
+ push ebp
+ mov ebp, esp
+
+ xor ebx, ebx
+ xor esi, esi
+ xor edi, edi
+
+ mov esi, [ebp + 8] ; source buffer
+ mov edi, screen_buffer ; output to screen buffer
+ mov ebx, [screen_pos] ; get current screen position
+ add edi, ebx ; move to current screen position
+ mov ecx, 0xff ; delay counter
+
+.write:
+
+ cmp byte [kprint_delay], 0 ; determine if we want a delay
+ je .nodelay ; if kprint_nodelay == 0:
+ ; nodelay()
+ ; else:
+ ; delay()
+
+.delay:
+ dec ecx ; while ecx != 0: ecx--
+ call screen_refresh
+ jne .delay
+
+.nodelay:
+ mov ebx, [esi] ; get value from source buffer
+ mov [edi], bl ; write value to screen buffer
+ inc esi ; next char in source buffer
+ add edi, 2 ; skip over screen attribute byte
+ call screen_updatexy ; update screen_pos
+
+ cmp bl, 0 ; if ch != 0: write
+ jne .write
+
+ call screen_refresh ; dump screen buffer to video ram
+
+ leave
+ ret
+
+kputc:
+ push ebp
+ mov ebp, esp
+
+ mov esi, [screen_pos]
+ mov edi, screen_buffer
+ add edi, esi
+
+ mov [edi], dl
+ call screen_updatexy
+ call screen_refresh
+
+ leave
+ ret
+
+kprintnl:
+ push ebp
+ mov ebp, esp
+
+ nop
+
+ leave
+ ret
+
+kmain:
+ push ebp
+ mov ebp, esp
+
+ mov byte [screen_pos], 2 ; Initialize screen position
+ ;call cursor_move
+
+ call idt_init
+
+ ; Fill screen with
+ push ' ' ; spaces &&
+ push 0x07 ; white forground on blue background
+ call screen_fill ; fill the screen buffer
+ call screen_refresh ; dump screen buffer to video ram
+
+ ;push 12
+ ;push 30
+ ;call screen_gotoxy
+
+ ;mov byte [kprint_delay], 1 ; tell kprint to delay writes
+ push message ; push message address as argument
+ call kprint ; print message
+
+ call kprintnl
+
+ mov dl, 'A'
+ call kputc
+
+ mov word [VIDEO_RAM + CONSOLE_SIZE - 6], \
+ 0x4F << 8 | 'I' ; END OF MAIN MARKER
+ ;mov ah, 1
+ ;mov bh, 2
+ ;mov bl, 2
+ ;mov edx, message2
+ ;int 21h ; here goes nothing
+
+ mov word [VIDEO_RAM + CONSOLE_SIZE - 6], \
+ 0x2F << 8 | 'I' ; END OF MAIN MARKER
+
+ mov word [VIDEO_RAM + CONSOLE_SIZE - 4], \
+ 0x2F << 8 | 'K' ; END OF MAIN MARKER
+
+ mov esp, ebp
+ pop ebp
+ ret
+
+section .data
+%include 'constants.asm'
+
+message: db 'Kernel programming is fun!', 0
+message2: db 'This is a test.', 0
+
+section .bss
+kprint_delay: resb 1
+screen_pos: resd 1
+screen_buffer: resb CONSOLE_SIZE
+screen_buffer_end:
+
diff --git a/link.ld b/link.ld
new file mode 100644
index 0000000..1819a67
--- /dev/null
+++ b/link.ld
@@ -0,0 +1,9 @@
+OUTPUT_FORMAT(elf32-i386)
+ENTRY(start)
+SECTIONS
+ {
+ . = 0x100000;
+ .text : { *(.text) }
+ .data : { *(.data) }
+ .bss : { *(.bss) }
+ }