From 543b5096164a704aa7167fe0b9b23494237a297d Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Fri, 30 Sep 2016 16:02:16 -0400 Subject: Initial commit --- .gitignore | 2 + Makefile | 33 +++++++ boot.asm | 41 ++++++++ constants.asm | 25 +++++ io.asm | 25 +++++ irq.asm | 248 +++++++++++++++++++++++++++++++++++++++++++++++ kernel.asm | 305 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ link.ld | 9 ++ 8 files changed, 688 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 boot.asm create mode 100644 constants.asm create mode 100644 io.asm create mode 100644 irq.asm create mode 100644 kernel.asm create mode 100644 link.ld 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) } + } -- cgit