Eigenbau-Kernel macht Probleme

11/07/2008 - 11:58 von Markus Wichmann | Report spam
Hi all,

ich wollte mich mal an etwas Neues wagen, und so fing ich an, einen
Betriebssystemkernel zu schreiben. Das Problem an der Sache: Ich kann
den Kernel erst testen, wenn er etwas auf den Bildschirm schreiben
sollte. Zu dem Zeitpunkt ist er aber schon relativ groß. Zumal ich mir
sagte, dass ich doch das ganze einfach mal in Assembler schreiben
könnte, nicht, wie es das Tutorial macht, in C. So nahm ich mir das
Tutorial (<http://www.osdever.net/bkerndev/index.php>) und schrieb
alles, was dort C war, in Assembler um. Der langen Rede kurzer Sinn:
Packe ich den Kernel auf eine GRUB-Floppy und boote diese (mit Bochs),
kann ich ihn zwar laden, aber nach dem "boot" passiert einfach nix.
Hier der Quelltext:

start.asm:

|%include "main.h"
|bits 32
|global start
|extern code, bss, ende
|start:
| mov esp, _sys_stack
| jmp stublet
|
|align 4
|mboot:
| .pa: equ 1
| .meminfo: equ 2
| .aout: equ 65536
| .headmag: equ 1BADB002h
| .headfl: equ .pa | .meminfo | .aout
| .checksum: equ -(.headmag + .headfl)
|
| ; multiboot header
| dd .headmag
| dd .headfl
| dd .checksum
|
| dd mboot
| dd code
| dd bss
| dd ende
| dd start
|
|stublet:
| jmp _main
|
|section .bss
| resb 8192 ; 8KB stack
|_sys_stack:

main.asm:

|%include "scrn.h"
|
|section .data
|str: db "Hello World!",10,0
|section .text
|
|; _memcpy : function
|; input on stack:
|; pointer dst
|; pointer src
|; uint32 count
|; output in registers:
|; eax: dst
|;
|; Description:
|; copies count bytes from src to dst
|
|global _memcpy
|
|_memcpy:
| cld
|
| pop edi
| pop esi
| pop ecx
|
| mov eax, edi ;return value
|
| rep movsb
| ret
|
|; _memset: function
|; input on stack:
|; pointer dst
|; int16 val
|; uint32 count
|; output in registers:
|; eax: dst
|;
|; Description:
|; copies val count bytes from dst on
|
|global _memset
|_memset:
| cld
|
| pop edi
| pop ax
| pop ecx
|
| mov esi, edi ;save return value
|
| rep stosb
|
| mov eax, esi
| ret
|
|; _memsetw: function
|; input on stack:
|; pointer dst
|; int16 val
|; uint32 count
|; output in registers:
|; eax: dst
|;
|; Description:
|; copies val as word count times begining at dst
|
|global _memsetw
|_memsetw:
| cld
|
| pop edi
| pop ax
| pop ecx
|
| mov esi, edi ;save return value
|
| rep stosw
|
| mov eax, esi
| ret
|
|; _strlen: function
|; input on stack:
|; pointer src
|; output in registers:
|; eax: uint32 len
|; Description:
|; expects a zero terminated string at src an returns its length
|
|global _strlen
|_strlen:
| cld
| pop edi
| xor al, al
| xor ecx, ecx
| dec ecx ; ecx mit -1 initialisieren
| mov edx, ecx ; edx auch
|
| repe scasb
|
| sub edx, ecx
| mov eax, edx
|
| ret
|
|; _inportb: function
|; input on stack:
|; uint16 portnumber
|; output in registers:
|; al: byte read
|; Description:
|; reads a byte from port portnumber
|
|global _inportb
|_inportb:
| pop dx
| in al, dx
| ret
|
|; _outportb: procedure
|; input:
|; uint16 portnumber
|; uint16 data
|; Description:
|; Outputs the lower byte of data to port portnumber.
|
|global _outportb
|_outportb:
| pop dx
| pop ax
| out dx, al
| ret
|
|; main function
|; currently just halting the processor
|
|global _main
|_main:
| call _init_video
| push str
| call _puts
| add esp, 4
| hlt

scrn.asm:

|%include "main.h"
|
|section .data
|textmemptr: equ 0B8000h
|attrib: db 0Fh
|csr_x: db 0
|csr_y: db 0
|
|section .text
|
|; _scroll: procedure
|; no input
|; Description: scrolls the screen
|
|global _scroll
|_scroll:
| enter 4, 0
| ;blank = ebp - 2
| ;temp = ebp - 4
|
| xor eax, eax
| mov ah, [attrib]
| mov al, 20h
| mov [ebp-2], ax
|
| xor eax, eax
|
| mov al, [csr_y]
| cmp al, 25
| js .dontScrollUp
|
| sub al, 24
| mov [ebp-4], ax
|
| mov cx, 25
| sub ax, cx
| neg ax
| mov cx, 160
| mul cx
| push eax ; (25 - temp) * 160
|
| xor eax, eax
| mov ax, [ebp-4]
| mov cx, 80
| mul cx
| mov ecx, textmemptr
| shl eax, 1
| add eax, ecx
| push eax ; temp * 80 + textmemptr
| push ecx ; textmemptr
|
| call _memcpy
| add esp, 3 * 4
|
| mov eax, 80
| push eax
|
| mov cx, [ebp-2]
| push cx
|
| mov cx, [ebp-4]
| mov dx, 25
| sub dx, cx
|
| mul dx
|
| mov ecx, textmemptr
| shl eax, 1
| add eax, ecx
| push eax
| call _memsetw
| add esp, 2 * 4 + 2
|
| mov eax, csr_y
| mov byte [eax], 25 - 1
|
|.dontScrollUp:
| leave
| ret
|
|; _move_csr: procedure
|; no input
|; updates the hardware cursor
|
|global _move_csr
|_move_csr:
| enter 2, 0
| ; temp = ebp - 2
| mov al, [csr_y]
| mov ah, 80
| mul ah
| xor bh, bh
| mov bl, [csr_x]
| add ax, bx
| xor ah, ah
| mov [ebp - 2], ax
|
| mov dx, 3D4h
| mov bx, 14
| xchg bx, ax
| out dx, al ;out 0x3D4, 14
|
| inc al
| inc dx
| xchg bx, ax
| xchg ah, al
| out dx, al ;out 0x3D5, temp >> 8
|
| dec dx
| xchg al, ah
| xchg ax, bx
| out dx, al ; out 0x3D4, 15
|
| inc dx
| xchg bx, ax
| out dx, al
|
| leave
| ret
|
|; cls: procedure
|; no input
|_cls:
| enter 2, 0
| ;blank = ebp - 2
| mov ah, [attrib]
| mov al, 20h
| mov [ebp - 2], ax
|
| xor ecx, ecx
| mov edx, 80
| mov ebx, textmemptr
|
|.loop1:
| push edx
| push word [ebp - 2]
| mov eax, edx
| mul cl
| shl eax, 1
| add eax, ebx
| push eax
| call _memsetw
| add esp, 2 * 4 + 2
| inc ecx
| cmp cl, 25
| js .loop1
|
| xor eax, eax
| mov [csr_x], ax
| leave
| jmp _move_csr
|
|; putch: procedure
|; input
|; uint16 char
|; Description: prints char on screen
|
|global _putch
|_putch:
| pop bx
| enter 4, 0
| xor eax, eax
| mov ax, [csr_x]
|
| cmp bl, 08h
| jnz .notBackspace
| or ah, ah
| jnz .notBackspace
| dec ah
| jmp .ende
|
|.notBackspace:
| cmp bl, 09h
| jnz .notTab
| add al, 8
| mov cl, 11111000b
| and ah, cl ;jetzt ist csr_x durch 8 teilbar
| ; also werden TABs jetzt richtig gesetzt
| jmp .ende
|
|.notTab:
| cmp bl, 0Dh
| jnz .notCR
| xor ah, ah
| jmp .ende
|
|.notCR:
| cmp bl, 0Ah
| jnz .notLF
| xor ah, ah
| inc al
| jmp .ende
|
|.notLF:
| cmp bl, 20h
| js .ende
| xor dh, dh
| mov dl, al
| mov al, ah
| mov cx, 80
| mul cl
| add ax, dx
| mov edx, textmemptr
| mov bh, [attrib]
| mov [eax*2+edx], bx
|
| mov ax, [csr_x]
| inc ah
|
|.ende:
| cmp ah, 80
| js .noNewLine
| xor ah, ah
| inc al
|
|.noNewLine:
| mov [csr_x], ax
|
| call _scroll
| jmp _move_csr
|
|; puts: procedure
|; input: pointer text
|; Description: Outputs text (as CString)
|
|global _puts
|_puts:
| call _strlen
| pop esi
| mov ecx, eax
| xor eax, eax
|
|
|.loop:
| lodsb
| push ax
| call _putch
| add esp, 2
| loop .loop
|
| ret
|
|; settextcolor: procedure
|; input: uint8 fgcolor
|; uint8 bgcolor
|; description: sets fg and bg color
|
|global _settextcolor
|_settextcolor:
| pop ax
| shl al, 4
| and ah, 0Fh
| or al, ah
| mov [attrib], al
| ret
|
|; init_video: procedure
|; no input
|; Description: calls cls
|global _init_video
|_init_video:
| jmp _cls

link.ld:

|OUTPUT_FORMAT("binary")
|ENTRY(start)
|phys = 0x00100000;
|SECTIONS
|{
| .text phys : AT(phys)
| {
| code = .;
| *(.text)
| *(.rodata)
| . = ALIGN(4096);
| }
| .data : AT(phys + data - code)
| {
| data = .;
| *(.data)
| . = ALIGN(4096);
| }
| .bss : AT(phys + bss - code)
| {
| bss = .;
| *(.bss)
| . = ALIGN(4096);
| }
| ende = .;
|}

Die .h-Dateien enthalten die Labels, die in der zugehörigen .asm-Datei
als global definiert wurden, als extern deklariert.

Schließlich noch die Makefile:

|OBJECTS=start.o main.o scrn.o
|ASM=/usr/bin/nasm
|ASMFLAGS=-felf
|LD=/usr/bin/ld
|LDSCRIPT=link.ld
|OUTPUT=kernel.bin
|RM=/bin/rm -f
|
|.PHONY: all clean
|
|all: $(OUTPUT)
|
|clean:
| $(RM) $(OUTPUT) $(OBJECTS)
|
|$(OUTPUT): $(LDSCRIPT) $(OBJECTS)
| $(LD) -o $@ -T $^
|
|%.o: %.asm
| $(ASM) $(ASMFLAGS) -o $@ $^


Wie gesagt: Irgendwo ist da der Wurm drin. Aber wo? Ich habe ja keine
Möglichkeit zu debuggen (wenn es doch gehen sollte, sagt mir bitte
wie).

Eins noch: GRUB gibt als Antwort auf die kernel-Zeile aus:

|[Multiboot-kludge, loadaddr=0x100000, text-and-data=0x2000, bss=0x2000,
| entry=0x100000]

Tschö,
Markus
Nur weil ein Genie nix reißt, muß ja nun nicht gleich jeder Idiot
pausieren... Bully hats ja auch geschafft.
 

Lesen sie die antworten

#1 Jens Kallup
11/07/2008 - 16:46 | Warnen spam
Hallo Markus,

schau doch auch mal hier vorbei:
http://kallup.part-time-scientists.com/MyOS.rar

Grüße
Jens

Ähnliche fragen