自制操作系统(五、重写引导部分和C语言的使用)

发布于:2025-06-09 ⋅ 阅读:(17) ⋅ 点赞:(0)

为了实现其他更多功能,我决定重新写引导部分的内容

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启动:

然而

 

如果去掉打印部分运行就正常

后面我们再修复