setup.bin进入保护模式

一段存代码,没有任何注释,我也忘记了。功能是:初始化进入保护模式,检测内存,并分页,加载内核,跳转到kernel.bin执行kernel是elf格式的。


%include "pm.inc"
    org 1000h
    jmp start
    
    sectnum  dw  19
sectnum1 db 1
init_kernel_ofs dw  0000h
init_kernel_seg dw  8000h
FATOFS  dw  0000h
    FATSEG  dw  9000h
fatnum dw 9
fatnumcount dw 1
    fatentry dw 200h
    filename db  'KERNEL  BIN'
kernel_msg:   db  "Loading kernel"
nofound_msg: db  "No kernel."
    ready:   db  "Ready."
    
    ;descriptor limitl basel basem attrib baseh
    ;	  dw    dw    db     dw    db
gdt:
    null_des: descriptor  0,0,0,0,0
    code_des: descriptor 0ffffh,0,0,attrib_ce+attrib_32+atrrib_limit_4k,0
    data_des: descriptor 0ffffh,0h,0h,attrib_drw+attrib_32+atrrib_limit_4k,0
    video_des: descriptor 0ffffh,8000h,0bh,attrib_drw+attrib_32,0
    
page_dir_des: descriptor 4095,0000h,20h,attrib_drw,0
    page_tbl_des: descriptor 1023,1000h,20h,attrib_drw+atrrib_limit_4k ,0h
    gdt_len equ $-gdt
    code_sel equ code_des-gdt
    data_sel equ data_des-gdt
    
    video_sel equ video_des-gdt
    page_dir_sel equ page_dir_des-gdt
    page_tbl_sel equ page_tbl_des-gdt
    page_dir_base	 equ	200000h	; 页目录开始地址:	2M
    page_tbl_base	 equ	201000h	; 页表开始地址:	 2M + 4K
    base_setup_phyaddr equ 90000h   ;INITSEG 9000h INITOFS 1000h
    base_kernel_phyaddr equ 80000h  ;kernel offset
kernel_entry_phyaddr equ 000400h ;kernel entry
    vgdtr:   pdescriptor gdt_len-1,gdt+base_setup_phyaddr
   
stack:
    times 1024 db 0
top_stack equ $+base_setup_phyaddr
    
    count dw 0
    mem_size dd 0 
    mem_buffer times 512 db 0
    msg db "In protect mode!",0
    page_msg db "After paging!",0
   
    check_msg db "Checked    ok!",0
    check1_msg db "Checked  fail!",0  
    finish_msg  db "Checked finish!",0 
    ram_size_msg db "Ram size:"
     ards:       ;address range descriptor struture
        dd 0    ;base addr low
        dd 0    ;base addr high
        dd 0    ;length low
        dd 0    ;length high
        dd 0    ;type
        
    offset_msg equ msg+base_setup_phyaddr  
    offset_page_msg equ page_msg+base_setup_phyaddr 
    offset_count equ count+base_setup_phyaddr 
    offset_mem_buffer equ mem_buffer+base_setup_phyaddr 
    offset_check_msg equ check_msg+base_setup_phyaddr 
    offset_check1_msg equ check1_msg+base_setup_phyaddr 
    offset_finish_msg equ finish_msg+base_setup_phyaddr 
    offset_ards equ ards+base_setup_phyaddr
    offset_mem_size equ mem_size+base_setup_phyaddr 
    offset_ram_size_msg equ ram_size_msg+base_setup_phyaddr
start:
    mov	ax, cs
mov	ds, ax
mov	es, ax
mov	ss, ax
mov	sp, ax
xor ax,ax
    
    call read_mem_info  ;放前面,奇怪放后面就不行了
xor	ah, ah	 
xor	dl, dl	 
int	13h	 
    call load_kernel
call kill_motor
lgdt [vgdtr]
cli
    call enable_a20
    
    
    mov eax,cr0
    or eax,1
    mov cr0,eax
    jmp dword code_sel:base_setup_phyaddr+virtual
    
    
enable_a20:
    push ax
    in al,92h
    or al,2
    out 92h,al
    pop ax
    ret
disable_a20:
    push ax
    in al,92h
    and al,0fdh
    out 92h,al
    pop ax
    ret
    
read_mem_info:
    mov di,mem_buffer
    mov ebx,0
rl:   
    mov eax,0E820h
    mov ecx,20
    mov edx,534D4150h 
    int 15h
    jc faile
    add di,20
    inc word [count]
    cmp ebx,0
    jne rl 
    jmp ok
faile:
    mov word [mem_size],0
    jmp finish
ok: 
finish:
    ret
load_kernel:
    push ax
    push bx
    push cx
    push si
    push di
    
    mov cx,14
mov si,kernel_msg
call print16_string
nof:
mov ax,[sectnum]
;mov ax,21
cmp ax,32
ja fail
mov di,[FATOFS]
push ax
mov ax,[FATSEG]
    mov es,ax
    pop ax
    call read_sect
    call search_file
    inc word [sectnum]
    cmp ax,-1
    je nof
    
    ;ax=file first sector
fatread:
push ax
mov es,[init_kernel_seg]
mov di,[init_kernel_ofs]
    add ax,31
call read_sect 
pop ax 
add word[init_kernel_ofs],200h
mov bx,[init_kernel_ofs]
push ax
mov al,'.'
call print16_char
pop ax
call get_entry
cmp ax,0ff8h
jae fatreadend
    jmp fatread
fatreadend: 
 
   call print16_newline
    
push si
mov cx,6
    mov si,ready
    call print16_string
    pop si
    jmp o
fail:
    call print16_newline
    mov cx,10
    mov si,nofound_msg
    call print16_string      
o:  
    pop di
    pop si
    pop cx
    pop bx
    pop ax
    ret
kill_motor:
    push ax
    push dx
    mov dx,03f2h
    mov al,0
    out dx,al
    pop dx
    pop ax
    ret
        
;es: di=地址 ds: si=filename ax->起始扇区号 ax=-1 没找到
search_file:
    push bx
    push cx
    push si
    cld
    mov bx,di
goon:
    mov di,bx
    and di,0ffe0h
    mov si,filename 
    mov cx,11
    repz cmpsb
    cmp cx,0
    jz find 
    add bx,32 
    cmp bx,200h ;FATOFS+512byte one sector
    jae nofind
    jmp goon
find:
    ;print
    add di,15
    mov ax,[es:di]  
    ;add ax,31 
    jmp endserch
nofind:   
    mov ax,-1
endserch:
    pop si
    pop cx
    pop bx
    ret
;sectornum/18 ch=Q>>1 cl=R+1 dh=Q&1
;ax=扇区号,sectnum1=扇区数 es:di=mem addr
read_sect:
    push ax
    push bx
    push cx
    push dx
    push di
 
    mov bh,18
    div bh
    mov ch,al
    shr ch,1
    and al,1
    mov dh,al
    inc ah
    mov cl,ah
    mov dl,00h
    mov bx,di
readagine:
    ;mov bx,[init_kernel_ofs]
    ;mov es,[init_kernel_seg]
    mov ah,02h
    mov al,1
    int 13h
    jc readagine
    pop di
    pop dx
    pop cx
    pop bx
    pop ax
    ret
    
;ax=sector es:di=fat men addr
get_entry:
    push bx
    push cx
    push dx
    push es
    push di
    mov bx,3
    mul bx
    mov bx,2
    div bx 
a: 
    cmp ax,[fatentry]      ;first time=200h
jbe next
mov es,[FATSEG]
mov di,[FATOFS]
push ax
mov ax,[fatnumcount]
cmp ax,9
ja endread           ;fat 9 项            
call read_sect
pop ax
inc word[fatnumcount]
add word[fatentry],200h 
      ;200h
jmp a
next: 
    push ax
    mov es,[FATSEG]
mov di,[FATOFS]
mov ax,[fatnumcount]     
call read_sect
pop ax
    add ax,200h
    sub ax,[fatentry]
    add di,ax
    
    mov ax,[es:di]
    
    cmp dx,0
    je even1
    mov cl,4
    shr ax,cl
    jmp endread
even1:
    and ax,0fffh
endread:    
    ;int 3h
    pop di
    pop es
    pop dx
    pop cx
    pop bx
    ret
    
print16_newline:
    push ax
     mov al,0dh
    call print16_char
    mov al,0ah
    call print16_char
    pop ax
    ret
;al char
print16_char:
    push	ax	  
push	bx	  
mov	ah, 0eh	  
;mov	al, '.'	  
mov bx,000ch	 
int	10h	  
pop	bx	 
pop	ax
    ret
;si addr ,cx count ,dh row ,dl col
print16_string:
    push ax
ps16:
    mov al,[si]
    call print16_char
    inc si
    loop ps16
pend16:
    pop ax    
ret 
;-----------------------------------protect
 
bits 32
virtual:
    mov ax,data_sel
    mov ds,ax
    mov ss,ax
    mov es,ax
    mov fs,ax
    mov ax,video_sel
mov	gs, ax
mov esp,0ff00h
    
    xor esi,esi
    mov dx,0400h
mov cx,16
    mov esi,offset_msg
    call print_string
    call print_newline
    mov cx,14
    mov esi,offset_finish_msg
    call print_string
    call print_newline
    mov cx,14
    mov esi,offset_check_msg
    call print_string
    call print_newline
    
    mov bx,[offset_count]
    call print_bx
    call print_newline
    ;call init8259a
    call dump_mem
    call print_newline
   
    call setup_paging
    mov cx,13
    mov esi,offset_page_msg
    call print_string  
call mov_kernel
    
jmp code_sel:kernel_entry_phyaddr
mov_kernel:
push eax
push ecx
push edx
push esi
xor eax,eax
mov ax,[80000h+2ch]	;elf_heder ->e_phnum
mov esi,[80000h+1ch] ;elf_header->e_phoff
add esi,80000h
coniue:
mov edx,[esi]   ;p_type
cmp edx,0
jz noload
push eax
push esi
mov ecx,[esi+16] ;p_filesz  size
mov edi,[esi+8]  ;p_vaddr	des
mov esi,[esi+4] ;p_offset	src
add esi,base_kernel_phyaddr
;call mem_cpy
cpy2:
cmp ecx,0
jle cpy1
mov eax,[esi]
mov [edi],eax
add edi,4
add esi,4
sub ecx,4
jmp cpy2
cpy1:
pop esi
pop eax
noload:
add esi,020h
dec eax
jnz coniue
 	pop esi
 	pop edx
 	pop ecx
 	pop eax
ret  
;es:edi des ,ds:esi src ,ecx size    
mem_cpy:
cpy12:
cmp ecx,0
jle cpy11
mov eax,[esi]
mov [edi],eax
add edi,4
add esi,4
sub ecx,4
jmp cpy12
cpy11:
ret
 
setup_paging:
    push edx
    xor edx,edx
    mov eax,[offset_mem_size]
    mov ebx,1024*4096
    div ebx         ;edx remainder eax 
    test edx,edx
    jz no_remainder
    inc eax
no_remainder:
    mov ecx,eax
    push eax
    
    mov ax,page_dir_sel
    mov es,ax
    mov ecx,1024
    xor edi,edi
    xor eax,eax
    mov eax,page_tbl_base|page_p|page_usu|page_rww
s1:
    stosd
    add eax,4096
    loop s1
    mov ax,page_tbl_sel
    mov es,ax
    pop eax
    ;mov ecx,1024*1024
    mov ebx,1024
    mul ebx
    mov ecx,eax
    xor edi,edi
    xor eax,eax
    mov eax,page_p|page_usu|page_rww
s2: 
    stosd
    add eax,4096
    loop s2
    mov eax,page_dir_base
    mov cr3,eax
    mov eax,cr0
    or eax,80000000h
    mov cr0,eax
    jmp	short .3
.3:
nop
pop edx
    ret 
init8259a:
    mov al,011h ;master icw1
    out 20h,al
    call io_delay
    out 0a0h,al ;slaver icw1
    call io_delay
    mov al,020h ;irq0   0x20
    out 21h,al  ;master icw2
    call io_delay
    mov al,028h ;irq8 0x28
    out 0a1h,al ;slaver icw2
    call io_delay
    mov al,004h ;ir2
    out 021h,al  ;master icw3
    call io_delay
    mov al,002h ;ir2
    out 0a1h,al
    call io_delay
    mov al,01h
    out 021h,al ;master icw4
    call io_delay
    
    ;mov	al, 11111110b	; 仅仅开启定时器中断
    mov al,0ffh ;ocw1
    out 021h,al 
    call io_delay
    mov al,0ffh ;owc1
    out 0a1h,al 
    call io_delay
    
    ret
    
io_delay:
    nop
    nop
    nop
    nop
    nop
    nop
    ret
;bx
print_bx:
    rol bx,8
    call print_bl
    rol bx,8
    call print_bl
    ret
    
print_ebx:
    push cx
    mov cl,4
ee:
    rol ebx,8
    call print_bl
    add dl,2
    loop ee
    pop cx
    
    ret
    
;bl 
print_bl:
    push ax
    push cx
    push dx
    mov ax,dx
    mov ch,2
l22:   
     mov cl,4
     rol bl,cl
     mov dl,bl
     and dl,0fh
     add dl,30h
     cmp dl,39h
     jbe l11
     add dl,7
l11:  
    push ax
    mov ah,al
    mov al,dl
    mov dl,ah
    call print_char
    pop ax
    inc al
    dec ch
    jnz l22
    mov dx,ax
    pop dx
    pop cx
    pop ax
    ret 
;dh,dl row,col
print_newline:
    xor dl,dl
    inc dh
    ret 
;al char ,gs video_sel ,dh row,dl col
print_char:
    push eax
    push ebx
    push ecx
    push edi
    xor ebx,ebx
    xor ecx,ecx
    mov bl,dh
    mov cl,dh
    shl ebx,6
    shl ecx,4
    add ebx,ecx
    xor ecx,ecx
    mov cl,dl
    add ebx,ecx
    shl ebx,1
mov	edi,ebx	 
mov	ah, 07h	  
mov	[gs:edi],ax  
pop edi
pop ecx
pop ebx
pop eax
ret   
;esi addr ,cx count ,dh row ,dl col
print_string:
    push ax
    
ps:
    mov al,[esi]
    call print_char
    inc dl
    inc esi
    loop ps
pend:
    pop ax    
ret
dump_mem:       ;display mem info
    push esi
    push ebx
    push ecx
    mov esi,offset_mem_buffer
    
    mov cx,[offset_count]
du:
 
    mov ebx,[esi+4]
    call print_ebx
    inc dl 
    mov ebx,[esi]
    call print_ebx
    inc dl
    mov ebx,[esi+12]
    call print_ebx
    inc dl
    mov ebx,[esi+8]
    call print_ebx
    inc dl
    mov ebx,[esi+16]
    call print_ebx
    call print_newline
 
    cmp ebx,1
    jne du1
    push edx
    mov edx,[esi]
    add edx,[esi+8]
    cmp edx,[offset_mem_size]
    jb ld
    mov [offset_mem_size],edx
    mov edx,[esi]
    mov [offset_ards],edx
    mov edx,[esi+4]
    mov [offset_ards+4],edx
    mov edx,[esi+8]
    mov [offset_ards+8],edx
    mov edx,[esi+12]
    mov [offset_ards+12],edx
    mov edx,[esi+16]
    mov [offset_ards+16],edx
ld:
    pop edx 
du1:
    add esi,20
    dec cx
    jnz  du
    call print_newline
    mov cx,5
    mov esi,offset_ards
du2:
    mov ebx,[esi]
    call print_ebx
    inc dl
    add esi,4
    loop du2
    inc dl
    call print_newline
    mov cx,9
    mov esi,offset_ram_size_msg
    call print_string
    mov ebx,[offset_mem_size]
    call print_ebx
    
    pop ecx
    pop ebx
    pop esi
    ret
;初始化进入保护模式,检测内存,并分页,加载内核,跳转到kernel.bin执行kernel是elf格式的。