自制操作系统(五、重写引导部分和C语言的使用)
为了实现其他更多功能,我决定重新写引导部分的内容
boot.asm
; boot.asm
%include "config.inc"setuplen equ 4
bootseg equ 0x07c0
initseg equ def_initseg
setupseg equ def_setupseg
sysseg equ def_syssegsetupsector equ 2
syssector equ setupsector+setuplen
syscylind equ 7ROOT_DEV equ 0
SWAP_DEV equ 0jmp startstart:mov ax, 0mov ss, axmov sp, bootsegmov ax, bootsegmov ds, axmov si, welcomecall showmsgmov word [root_dev], 0x021cmov ax, initsegmov es, axmov cx, 256sub si, sisub di, direpmovswjmp initseg:gogo:mov ax, csmov ds, axmov si, msg1call showmsgmov ax, csmov ss, axmov sp, 0xfef4mov si, msg2call showmsgmov ax, setupsegmov es, axmov byte [sector+11], setupsectorcall loadsetupmov si, msg3call showmsgmov ax, syssegmov es, axmov byte [sector+11], syssectorcall loadsystemjmp setupseg:0showmsg:call newlinecall printstrcall newlineretloadsetup:call read1sectormov ax, esadd ax, 0x0020mov es, axinc byte [sector+11]cmp byte [sector+11], setuplen+1+1jne loadsetupretloadsystem:call read1sectormov ax, esadd ax, 0x0020mov es, axinc byte [sector+11]cmp byte [sector+11], 18+1jne loadsystemmov byte [sector+11], 1inc byte [header+11]cmp byte [header+11], 1+1jne loadsystemmov byte [header+11], 0inc byte [cylind+11]cmp byte [cylind+11], syscylind+1jne loadsystemretnumtoascii:mov ax, 0mov al, clmov bl, 10div bladd ax, 3030hretreadinfo:mov si, cylindcall printstrmov si, headercall printstrmov si, sectorcall printstrretread1sector:mov cl, [sector+11]call numtoasciimov [sector+7], almov [sector+8], ahmov cl, [header+11]call numtoasciimov [header+7], almov [header+8], ahmov cl, [cylind+11]call numtoasciimov [cylind+7], almov [cylind+8], ahmov ch, [cylind+11]mov dh, [header+11]mov cl, [sector+11]call readinfomov di, 0
retry:mov ah, 02hmov al, 1mov bx, 0mov dl, 00hint 13hjnc readokinc dimov ah, 0x00mov dl, 0x00int 0x13cmp di, 5jne retrymov si, fyerrorcall printstrcall newlinejmp exitread
readok:mov si, floppyokcall printstrcall newline
exitread:retprintstr:mov al, [si]cmp al, '$'je disovermov ah, 0ehint 10hinc sijmp printstr
disover:retnewline:mov ah, 0ehmov al, 0dhint 10hmov al, 0ahint 10hretwelcome 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 0swap_dev:dw SWAP_DEV
root_dev:dw ROOT_DEVboot_flag: db 0x55, 0xaa
setup.asm
; setup.asm
%include "config.inc"initseg equ def_initseg
sysseg equ def_sysseg
setupseg equ def_setupsegjmp startstart:mov ax, setupsegmov ds, axmov si, welcomecall showmsgmov ax, initsegmov es, axmov si, msg1call showmsgmov ah, 0x88int 0x15mov [es:2], axmov si, msg2call showmsgmov ah, 0x12mov bl, 0x10int 0x10mov [es:8], axmov [es:10], bxmov [es:12], cxmov ax, 0x5019mov [es:14], axmov ah, 0x03xor bh, bhint 0x10mov [es:0], dxmov si, msg3call showmsgmov ah, 0x0fint 0x10mov [es:4], bxmov [es:6], axmov si, msg4call showmsgpush dsmov ax, 0x0000mov ds, axlds si, [4*0x41]mov ax, initsegmov es, axmov di, 0x0080mov cx, 0x10repmovsbpop dsmov si, msg5call showmsgpush dsmov ax, 0x0000mov ds, axlds si, [4*0x46]mov ax, initsegmov es, axmov di, 0x0090mov cx, 0x10repmovsbpop dsmov si, msg6call showmsgmov ax, 0x01500mov dl, 0x81int 0x13jc no_disk1cmp ah, 3je is_disk1
no_disk1:mov ax, initsegmov es, axmov di, 0x0090mov cx, 0x10mov ax, 0x00repstosb
is_disk1:mov si, msg7call showmsgmov si, msg8call showmsgmov cx, 14
line:call newlineloop lineclicall mov_systemmov ax, setupsegmov ds, axlidt [idt_48]lgdt [gdt_48]call empty_8042mov al, 0xd1out 0x64, alcall empty_8042mov al, 0xdfout 0x60, alcall empty_8042call set_8259amov ax, 0x0001lmsw axjmp dword 1*8:0mov_system:mov ax, 0x0000cld
do_move:mov es, axadd ax, 0x1000cmp ax, 0x9000jz end_movemov ds, axsub di, disub si, simov cx, 0x8000repmovswjmp do_move
end_move:retset_8259a:mov al, 0x11out 0x20, aldw 0x00eb, 0x00ebout 0xa0, aldw 0x00eb, 0x00ebmov al, 0x20out 0x21, aldw 0x00eb, 0x00ebmov al, 0x28out 0xa1, aldw 0x00eb, 0x00ebmov al, 0x04out 0x21, aldw 0x00eb, 0x00ebmov al, 0x02out 0xa1, aldw 0x00eb, 0x00ebmov al, 0x01out 0x21, aldw 0x00eb, 0x00ebout 0xa1, aldw 0x00eb, 0x00ebmov al, 0xffout 0x21, aldw 0x00eb, 0x00ebout 0xa1, alretempty_8042:dw 0x00eb, 0x00ebin al, 0x64test al, 2jnz empty_8042retidt_48:dw 0x800dw 0, 0
gdt_48:dw 0x800dw 512+gdt, 0x9gdt:dw 0, 0, 0, 0dw 0x07ff, 0x0000, 0x9a00, 0x00c0dw 0x07ff, 0x0000, 0x9200, 0x00c0showmsg:call newlinecall printstrretprintstr:mov al, [si]cmp al, '$'je disovermov ah, 0x0eint 0x10inc sijmp printstr
disover:retnewline:mov ah, 0x0emov al, 0x0dint 0x10mov al, 0x0aint 0x10retwelcome 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 starttimes _tmp_floppy_area+len_floppy_area-($-$$) db 0start:mov eax, 2*8mov ds, eaxmov es, eaxmov fs, eaxmov gs, eaxmov ss, eaxmov esi, sysmsgmov cl, 0x0cmov edi, 0xb8000+13*160call printnewmov esi, promsgmov cl, 0x0cmov edi, 0xb8000+15*160call printnewmov esi, headmsgmov cl, 0x0cmov edi, 0xb8000+16*160call printnewmov esp, 0x1e25ccall setup_idtcall setup_gdtjmp 1*8:newgdtnopnop
newgdt:mov esi, gdtmsgmov cl, 0x09mov edi, 0xb8000+17*160call printnewstiint 00hclicall a20openmov esi, a20msgmov cl, 0x09mov edi, 0xb8000+19*160call printnewcall setup_pagingmov dword [_pg_dir+4*768], pg0+7sgdt [gdt_descr]add dword [gdt_descr + 2], kernel_virtual_addressadd esp, kernel_virtual_addressxor eax, eaxmov cr3, eaxmov eax, cr0or eax, 0x80000000mov cr0, eaxlgdt [gdt_descr]jmp 8:ready_cnopnopready_c:call kernel_initmov esp, kernel_virtual_address+0x51000mov esi, mainmsgmov cl, 0x09mov edi, 0xb8000+22*160call printnewjmp kernel_entry_pointkernel_init:xor eax, eaxxor ebx, ebxxor ecx, ecxxor edx, edxmov dx, [kernel_bin_base_addr + 42]mov ebx, [kernel_bin_base_addr + 28]add ebx, kernel_bin_base_addrmov cx, [kernel_bin_base_addr + 44].each_segment:cmp byte [ebx + 0], pt_nullje .ptnullpush dword [ebx + 16]mov eax, [ebx + 4]add eax, kernel_bin_base_addrpush eaxpush dword [ebx + 8]call mem_copyadd esp, 12
.ptnull:add ebx, edxloop .each_segmentretmem_copy:push ebpmov ebp, esppush esipush edipush ecxmov edi, [ebp+8]mov esi, [ebp+12]mov ecx, [ebp+16]cmp ecx, 0je nocopy
cgoon:mov eax, [esi]add esi, 4mov [edi], eaxadd edi, 4loop cgoon
nocopy:pop ecxpop edipop esipop ebpretsetup_paging:mov dword [_pg_dir], pg0+7mov dword [_pg_dir+4], pg1+7mov dword [_pg_dir+8], pg2+7mov dword [_pg_dir+12], pg3+7mov edi, pg3+4092mov eax, 0xfff007std
goon:stosdsub eax, 0x1000jge goonmov esi, pagemsgmov cl, 0x09mov edi, 0xb8000+20*160call printnewmov esi, asmmsgmov cl, 0x09mov edi, 0xb8000+21*160call printnewreta20open:xor eax, eaxinc eaxmov [0x000000], eaxcmp eax, [0x100000]je a20openretprintnew:mov bl, [ds:esi]cmp bl, '$'je printovermov byte [ds:edi], blinc edimov byte [ds:edi], clinc esiinc edijmp printnew
printover:retsetup_idt:lea edx, [ignore_int]mov eax, 0x00080000mov ax, dxmov dx, 0x8e00lea edi, [_idt]mov ecx, 256
rp_sidt:mov [edi], eaxmov [edi+4], edxadd edi, 8loop rp_sidtlidt [idt_descr]retignore_int:clipushadpush dspush espush fspush gspush ssmov eax, 2*8mov ds, eaxmov es, eaxmov fs, eaxmov gs, eaxmov ss, eaxmov esi, intmsgmov cl, 0x09mov edi, 0xb8000+18*160call printnewpop sspop gspop fspop espop dspopadiretalign 2
dw 0idt_descr:dw 256*8-1dd _idtretsetup_gdt:lgdt [gdt_descr]retalign 2
dw 0gdt_descr:dw 256*8-1dd _gdtsysmsg 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 0x0000000000000000dq 0x00cf9a000000ffffdq 0x00cf92000000ffffdq 0x0000000000000000times 252 dq 0kernel_bin_base_addr:
config.inc
;%define debug ;不注释调试,注释用于生产
%ifdef debug
isdebug equ 1
%else
isdebug equ 0
%endifdef_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 ebpmov ebp,esp;由于push ebp导致栈顶又多挪动了4位push dword [EBP+16+4] ;corlorpush dword [EBP+12+4] ;start_col_ypush dword [EBP+08+4] ;start_line_xpush dword [EBP+04+4] ;*s;汇编语言调用C语言测试
;void printstr(char *s,char start_line_x,char start_col_y,char corlor)CALL _printstrpop eax ;全是为了保持函数调用时push的栈平衡pop eaxpop eaxpop eaxpop ebpret_print_char:mov esi, msgmov cl, 0x09mov edi, 0xb8000+24*160call printnewretprintnew:mov bl, [ds:esi]cmp bl, '$'je printovermov byte [ds:edi], blinc edimov byte [ds:edi], clinc esiinc edijmp printnew
printover:retmsg 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 out1.batecho OK!!!out:nasm -I include/ bootloader/boot.asm -o bin/boot.binnasm -I include/ bootloader/setup.asm -o bin/setup.binnasm -I include/ bootloader/head.asm -o bin/head.binnasm -f elf kernel/kernel.asm -o bin/kernel.obj -l kernel/kernel.lstgcc -c -m32 -Os -o bin/main.o kernel/main.ci686-elf-ld -Ttext 0x0051500 -e main -Map kernel.map -o bin/kernel.bin bin/main.o bin/kernel.obj
make编译
qemu似乎无法运行
VMware启动:
然而
如果去掉打印部分运行就正常
后面我们再修复