为了实现其他更多功能,我决定重新写引导部分的内容
boot.asm
; boot.asm
%include "config.inc"
setuplen equ 4
bootseg equ 0x07c0
initseg equ def_initseg
setupseg equ def_setupseg
sysseg equ def_sysseg
setupsector equ 2
syssector equ setupsector+setuplen
syscylind equ 7
ROOT_DEV equ 0
SWAP_DEV equ 0
jmp start
start:
mov ax, 0
mov ss, ax
mov sp, bootseg
mov ax, bootseg
mov ds, ax
mov si, welcome
call showmsg
mov word [root_dev], 0x021c
mov ax, initseg
mov es, ax
mov cx, 256
sub si, si
sub di, di
rep
movsw
jmp initseg:go
go:
mov ax, cs
mov ds, ax
mov si, msg1
call showmsg
mov ax, cs
mov ss, ax
mov sp, 0xfef4
mov si, msg2
call showmsg
mov ax, setupseg
mov es, ax
mov byte [sector+11], setupsector
call loadsetup
mov si, msg3
call showmsg
mov ax, sysseg
mov es, ax
mov byte [sector+11], syssector
call loadsystem
jmp setupseg:0
showmsg:
call newline
call printstr
call newline
ret
loadsetup:
call read1sector
mov ax, es
add ax, 0x0020
mov es, ax
inc byte [sector+11]
cmp byte [sector+11], setuplen+1+1
jne loadsetup
ret
loadsystem:
call read1sector
mov ax, es
add ax, 0x0020
mov es, ax
inc byte [sector+11]
cmp byte [sector+11], 18+1
jne loadsystem
mov byte [sector+11], 1
inc byte [header+11]
cmp byte [header+11], 1+1
jne loadsystem
mov byte [header+11], 0
inc byte [cylind+11]
cmp byte [cylind+11], syscylind+1
jne loadsystem
ret
numtoascii:
mov ax, 0
mov al, cl
mov bl, 10
div bl
add ax, 3030h
ret
readinfo:
mov si, cylind
call printstr
mov si, header
call printstr
mov si, sector
call printstr
ret
read1sector:
mov cl, [sector+11]
call numtoascii
mov [sector+7], al
mov [sector+8], ah
mov cl, [header+11]
call numtoascii
mov [header+7], al
mov [header+8], ah
mov cl, [cylind+11]
call numtoascii
mov [cylind+7], al
mov [cylind+8], ah
mov ch, [cylind+11]
mov dh, [header+11]
mov cl, [sector+11]
call readinfo
mov di, 0
retry:
mov ah, 02h
mov al, 1
mov bx, 0
mov dl, 00h
int 13h
jnc readok
inc di
mov ah, 0x00
mov dl, 0x00
int 0x13
cmp di, 5
jne retry
mov si, fyerror
call printstr
call newline
jmp exitread
readok:
mov si, floppyok
call printstr
call newline
exitread:
ret
printstr:
mov al, [si]
cmp al, '$'
je disover
mov ah, 0eh
int 10h
inc si
jmp printstr
disover:
ret
newline:
mov ah, 0eh
mov al, 0dh
int 10h
mov al, 0ah
int 10h
ret
welcome db '(i) Plain boot!', '$'
msg1 db '1.boot to 0x9000', '$'
msg2 db '2.setup to 0x9020', '$'
msg3 db '3.system to 0x1000', '$'
cylind db 'cylind:?? $', 0
header db 'header:?? $', 0
sector db 'sector:?? $', 1
floppyok db '-floppy read ok', '$'
fyerror db '-floppy read error', '$'
times 512-2*3-($-$$) db 0
swap_dev:
dw SWAP_DEV
root_dev:
dw ROOT_DEV
boot_flag: db 0x55, 0xaa
setup.asm
; setup.asm
%include "config.inc"
initseg equ def_initseg
sysseg equ def_sysseg
setupseg equ def_setupseg
jmp start
start:
mov ax, setupseg
mov ds, ax
mov si, welcome
call showmsg
mov ax, initseg
mov es, ax
mov si, msg1
call showmsg
mov ah, 0x88
int 0x15
mov [es:2], ax
mov si, msg2
call showmsg
mov ah, 0x12
mov bl, 0x10
int 0x10
mov [es:8], ax
mov [es:10], bx
mov [es:12], cx
mov ax, 0x5019
mov [es:14], ax
mov ah, 0x03
xor bh, bh
int 0x10
mov [es:0], dx
mov si, msg3
call showmsg
mov ah, 0x0f
int 0x10
mov [es:4], bx
mov [es:6], ax
mov si, msg4
call showmsg
push ds
mov ax, 0x0000
mov ds, ax
lds si, [4*0x41]
mov ax, initseg
mov es, ax
mov di, 0x0080
mov cx, 0x10
rep
movsb
pop ds
mov si, msg5
call showmsg
push ds
mov ax, 0x0000
mov ds, ax
lds si, [4*0x46]
mov ax, initseg
mov es, ax
mov di, 0x0090
mov cx, 0x10
rep
movsb
pop ds
mov si, msg6
call showmsg
mov ax, 0x01500
mov dl, 0x81
int 0x13
jc no_disk1
cmp ah, 3
je is_disk1
no_disk1:
mov ax, initseg
mov es, ax
mov di, 0x0090
mov cx, 0x10
mov ax, 0x00
rep
stosb
is_disk1:
mov si, msg7
call showmsg
mov si, msg8
call showmsg
mov cx, 14
line:
call newline
loop line
cli
call mov_system
mov ax, setupseg
mov ds, ax
lidt [idt_48]
lgdt [gdt_48]
call empty_8042
mov al, 0xd1
out 0x64, al
call empty_8042
mov al, 0xdf
out 0x60, al
call empty_8042
call set_8259a
mov ax, 0x0001
lmsw ax
jmp dword 1*8:0
mov_system:
mov ax, 0x0000
cld
do_move:
mov es, ax
add ax, 0x1000
cmp ax, 0x9000
jz end_move
mov ds, ax
sub di, di
sub si, si
mov cx, 0x8000
rep
movsw
jmp do_move
end_move:
ret
set_8259a:
mov al, 0x11
out 0x20, al
dw 0x00eb, 0x00eb
out 0xa0, al
dw 0x00eb, 0x00eb
mov al, 0x20
out 0x21, al
dw 0x00eb, 0x00eb
mov al, 0x28
out 0xa1, al
dw 0x00eb, 0x00eb
mov al, 0x04
out 0x21, al
dw 0x00eb, 0x00eb
mov al, 0x02
out 0xa1, al
dw 0x00eb, 0x00eb
mov al, 0x01
out 0x21, al
dw 0x00eb, 0x00eb
out 0xa1, al
dw 0x00eb, 0x00eb
mov al, 0xff
out 0x21, al
dw 0x00eb, 0x00eb
out 0xa1, al
ret
empty_8042:
dw 0x00eb, 0x00eb
in al, 0x64
test al, 2
jnz empty_8042
ret
idt_48:
dw 0x800
dw 0, 0
gdt_48:
dw 0x800
dw 512+gdt, 0x9
gdt:
dw 0, 0, 0, 0
dw 0x07ff, 0x0000, 0x9a00, 0x00c0
dw 0x07ff, 0x0000, 0x9200, 0x00c0
showmsg:
call newline
call printstr
ret
printstr:
mov al, [si]
cmp al, '$'
je disover
mov ah, 0x0e
int 0x10
inc si
jmp printstr
disover:
ret
newline:
mov ah, 0x0e
mov al, 0x0d
int 0x10
mov al, 0x0a
int 0x10
ret
welcome db '(ii) welcome Plain setup!', 0x0d, 0x0a, '$'
msg1 db '1.get memory size', '$'
msg2 db '2.check for ega/vga and some config parameters', '$'
msg3 db '3.get video-card data', '$'
msg4 db '4.get hd0 data', '$'
msg5 db '5.get hd1 data', '$'
msg6 db '6.check that there is a hd1', '$'
msg7 db '7.move system from 0x10000 to 0x00000', '$'
msg8 db '8.now ready to protect mode!', '$'
times 512*4-($-$$) db 0
head.asm
%include "config.inc"
setupseg equ def_setupseg
sysseg equ def_sysseg
_pg_dir equ 0x0000
pg0 equ 0x1000
pg1 equ 0x2000
pg2 equ 0x3000
pg3 equ 0x4000
_tmp_floppy_area equ 0x5000
len_floppy_area equ 0x400
[bits 32]
jmp start
times _tmp_floppy_area+len_floppy_area-($-$$) db 0
start:
mov eax, 2*8
mov ds, eax
mov es, eax
mov fs, eax
mov gs, eax
mov ss, eax
mov esi, sysmsg
mov cl, 0x0c
mov edi, 0xb8000+13*160
call printnew
mov esi, promsg
mov cl, 0x0c
mov edi, 0xb8000+15*160
call printnew
mov esi, headmsg
mov cl, 0x0c
mov edi, 0xb8000+16*160
call printnew
mov esp, 0x1e25c
call setup_idt
call setup_gdt
jmp 1*8:newgdt
nop
nop
newgdt:
mov esi, gdtmsg
mov cl, 0x09
mov edi, 0xb8000+17*160
call printnew
sti
int 00h
cli
call a20open
mov esi, a20msg
mov cl, 0x09
mov edi, 0xb8000+19*160
call printnew
call setup_paging
mov dword [_pg_dir+4*768], pg0+7
sgdt [gdt_descr]
add dword [gdt_descr + 2], kernel_virtual_address
add esp, kernel_virtual_address
xor eax, eax
mov cr3, eax
mov eax, cr0
or eax, 0x80000000
mov cr0, eax
lgdt [gdt_descr]
jmp 8:ready_c
nop
nop
ready_c:
call kernel_init
mov esp, kernel_virtual_address+0x51000
mov esi, mainmsg
mov cl, 0x09
mov edi, 0xb8000+22*160
call printnew
jmp kernel_entry_point
kernel_init:
xor eax, eax
xor ebx, ebx
xor ecx, ecx
xor edx, edx
mov dx, [kernel_bin_base_addr + 42]
mov ebx, [kernel_bin_base_addr + 28]
add ebx, kernel_bin_base_addr
mov cx, [kernel_bin_base_addr + 44]
.each_segment:
cmp byte [ebx + 0], pt_null
je .ptnull
push dword [ebx + 16]
mov eax, [ebx + 4]
add eax, kernel_bin_base_addr
push eax
push dword [ebx + 8]
call mem_copy
add esp, 12
.ptnull:
add ebx, edx
loop .each_segment
ret
mem_copy:
push ebp
mov ebp, esp
push esi
push edi
push ecx
mov edi, [ebp+8]
mov esi, [ebp+12]
mov ecx, [ebp+16]
cmp ecx, 0
je nocopy
cgoon:
mov eax, [esi]
add esi, 4
mov [edi], eax
add edi, 4
loop cgoon
nocopy:
pop ecx
pop edi
pop esi
pop ebp
ret
setup_paging:
mov dword [_pg_dir], pg0+7
mov dword [_pg_dir+4], pg1+7
mov dword [_pg_dir+8], pg2+7
mov dword [_pg_dir+12], pg3+7
mov edi, pg3+4092
mov eax, 0xfff007
std
goon:
stosd
sub eax, 0x1000
jge goon
mov esi, pagemsg
mov cl, 0x09
mov edi, 0xb8000+20*160
call printnew
mov esi, asmmsg
mov cl, 0x09
mov edi, 0xb8000+21*160
call printnew
ret
a20open:
xor eax, eax
inc eax
mov [0x000000], eax
cmp eax, [0x100000]
je a20open
ret
printnew:
mov bl, [ds:esi]
cmp bl, '$'
je printover
mov byte [ds:edi], bl
inc edi
mov byte [ds:edi], cl
inc esi
inc edi
jmp printnew
printover:
ret
setup_idt:
lea edx, [ignore_int]
mov eax, 0x00080000
mov ax, dx
mov dx, 0x8e00
lea edi, [_idt]
mov ecx, 256
rp_sidt:
mov [edi], eax
mov [edi+4], edx
add edi, 8
loop rp_sidt
lidt [idt_descr]
ret
ignore_int:
cli
pushad
push ds
push es
push fs
push gs
push ss
mov eax, 2*8
mov ds, eax
mov es, eax
mov fs, eax
mov gs, eax
mov ss, eax
mov esi, intmsg
mov cl, 0x09
mov edi, 0xb8000+18*160
call printnew
pop ss
pop gs
pop fs
pop es
pop ds
popad
iret
align 2
dw 0
idt_descr:
dw 256*8-1
dd _idt
ret
setup_gdt:
lgdt [gdt_descr]
ret
align 2
dw 0
gdt_descr:
dw 256*8-1
dd _gdt
sysmsg db '(iii) welcome Plain system!', '$'
promsg db '1.now already in protect mode', '$'
headmsg db '2.run head.asm in system program', '$'
gdtmsg db '3.reset gdt success:new cs\eip normal', '$'
intmsg db '4.reset idt success:unknown interrupt', '$'
a20msg db '5.check a20 address line stdate:open', '$'
pagemsg db '6.memory page store:page tables is set up', '$'
asmmsg db '7.pure asm program:bootsect->setup->head(system) is finished', '$'
mainmsg db '8.now come to c program entry:main()', '$'
_idt: times 256 dq 0
_gdt:
dq 0x0000000000000000
dq 0x00cf9a000000ffff
dq 0x00cf92000000ffff
dq 0x0000000000000000
times 252 dq 0
kernel_bin_base_addr:
config.inc
;%define debug ;不注释调试,注释用于生产
%ifdef debug
isdebug equ 1
%else
isdebug equ 0
%endif
def_initseg equ 0x9000 ;MBR程序挪动后的目标地址
def_sysseg equ 0x1000 ;SYSEM模块放置地址
def_setupseg equ 0x9020 ;SETUP模块放置地址
kernel_virtual_address equ 0xc0000000 ;内核程序虚拟地址3GB-4GB
kernel_entry_point equ 0x00051500 ;内核程序main.c入口地址
pt_null equ 0 ;ELF格式标准
接下来可以进入内核了
测试一下
kernel.asm
[BITS 32]
GLOBAL _asmfunc
GLOBAL _print_char
EXTERN _printstr
[SECTION .text]
;C语言调用汇编语言测试
;void asmfunc(char *s,char start_line_x,char start_col_y,char corlor)
_asmfunc:
push ebp
mov ebp,esp
;由于push ebp导致栈顶又多挪动了4位
push dword [EBP+16+4] ;corlor
push dword [EBP+12+4] ;start_col_y
push dword [EBP+08+4] ;start_line_x
push dword [EBP+04+4] ;*s
;汇编语言调用C语言测试
;void printstr(char *s,char start_line_x,char start_col_y,char corlor)
CALL _printstr
pop eax ;全是为了保持函数调用时push的栈平衡
pop eax
pop eax
pop eax
pop ebp
ret
_print_char:
mov esi, msg
mov cl, 0x09
mov edi, 0xb8000+24*160
call printnew
ret
printnew:
mov bl, [ds:esi]
cmp bl, '$'
je printover
mov byte [ds:edi], bl
inc edi
mov byte [ds:edi], cl
inc esi
inc edi
jmp printnew
printover:
ret
msg db 'hello!', '$'
main.c
void printchar(char c,char line_x,char col_y,char corlor);
void printstr(char *s,char start_line_x,char start_col_y,char corlor);
extern void asmfunc(char *s,char start_line_x,char start_col_y,char corlor);
extern void print_char(void);
void _main(void)
{
char *str="kernel";
printstr(str,23,20,0x0c);
//print_char();
//char *str2="C->A->C"; /*C调用汇编,汇编又调用C演示*/
//asmfunc(str2,24,20,0x0c);
while(1);
}
/*打印一个字符,参数:字符,行号,列号,字符颜色*/
void printchar(char c,char line_x,char col_y,char corlor)
{
*(char *)(0xb800+line_x*160+2*col_y) =c;
*(char *)(0xb800+line_x*160+2*col_y+1) =corlor;
}
/*打印一个字符串,参数:字符串首地址,开始行号,开始列号,字符颜色*/
void printstr(char *s,char start_line_x,char start_col_y,char corlor)
{
do
{
printchar(*s,start_line_x,start_col_y,corlor);
start_col_y++;
}
while (*(s++)!='\0');
}
makefile
#
# _oo0oo_
# o8888888o
# 88' . '88
# (| -_- |)
# 0\ = /0
# ___/`---'\___
# .' \| |// '.
# / \||| : |||// "
# / _||||| -:- |||||- "
# | | \\ - /// | |
# | \_| ''\---/'' |_/ |
# \ .-\__ '-' ___/-. /
# ___'. .' /--.--\ `. .'___
# .''' '< `.___\_<|>_/___.' >' '''.
# | | : `- \`.;`\ _ /`;.`/ - ` : | |
# \ \ `_. \_ __\ /__ _/ .-` / /
# =====`-.____`.___ \_____/___.-`___.-'=====
# `=---='
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# 佛祖保佑 永无bug
# 阿弥陀佛 功德无量
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Copyright (c) lhhasm & resfz
# Plain0.0.1 Makefile
all:
make out
1.bat
echo OK!!!
out:
nasm -I include/ bootloader/boot.asm -o bin/boot.bin
nasm -I include/ bootloader/setup.asm -o bin/setup.bin
nasm -I include/ bootloader/head.asm -o bin/head.bin
nasm -f elf kernel/kernel.asm -o bin/kernel.obj -l kernel/kernel.lst
gcc -c -m32 -Os -o bin/main.o kernel/main.c
i686-elf-ld -Ttext 0x0051500 -e main -Map kernel.map -o bin/kernel.bin bin/main.o bin/kernel.obj
make编译
qemu似乎无法运行
VMware启动:
然而
如果去掉打印部分运行就正常
后面我们再修复