%include "asm/common/boot_loader_equ.asm" TEMP_HEADER_ADDRESS equ 0x400000 [bits 64] org 0x100000 section loader2 ;读取程序头部扇区,计算程序头表和elf64所占扇区数 xor rax,rbx mov rbx,TEMP_HEADER_ADDRESS mov eax,KERNEL_START_SECTOR call read_one_sector xor rcx,rcx mov cx,[TEMP_HEADER_ADDRESS+56] ;程序头表项数量 xor rax,rax mov ax,[TEMP_HEADER_ADDRESS+54] ;程序头表项大小 xor rdx,rdx mul cx shl edx,16 mov dx,ax add edx,64 ;当前edx中为程序头表+elf头大小 add edx,512 ;填补误差 mov rax,rdx shr rax,9 xor rcx,rcx mov ecx,eax ;当前ecx中为程序头表+elf头所占扇区 ;读取程序头部扇区和程序头表,直接读取200个扇区,统计程序大小 xor rbx,rbx mov rbx,TEMP_HEADER_ADDRESS mov eax,KERNEL_START_SECTOR ; mov rcx,200 read_header: call read_one_sector inc eax add rbx,512 loop read_header ;分析程序头表,统计程序大小 mov rbx,[TEMP_HEADER_ADDRESS+32] mov rax,TEMP_HEADER_ADDRESS add rbx,rax ;程序头表起始地址 xor rcx,rcx mov cx,[TEMP_HEADER_ADDRESS+56] ;程序头表项数量 xor rax,rax mov ax,[TEMP_HEADER_ADDRESS+54] ;程序头表项大小 xor rdi,rdi ;用于保存程序大小 calc_kernel_size: mov rsi,[rbx+32] add rdi,rsi add rbx,rax loop calc_kernel_size xor rdx,rdx mov cx,[TEMP_HEADER_ADDRESS+56] ;程序头表项数量 mul cx shl edx,16 mov dx,ax add rdi,rdx add rdi,64 ;当前rdi=程序头+ELF头+程序段总大小 xor rax,rax xor rcx,rcx xor rdx,rdx mov ax,[TEMP_HEADER_ADDRESS+58] mov cx,[TEMP_HEADER_ADDRESS+60] mul cx shl edx,16 mov dx,ax add rdi,rdx ;当前rdi=程序头+ELF头+程序段总大小+节头表 ;根据程序大小分配地址空间 add rdi,0x200000 ;多分配2M左右的空间 mov rax,rdi xor rdx,rdx mov rbx,0x200000 div rbx ;此时rax中就是内核映像需要分配的页数(按2M分页) mov r8,rax shl r8,21 add r8,KERNEL_CACHE_ADDRESS ;使用r8记录内核重定位时的相对地址 mov rcx,rax shl rcx,1 ;由于需要存放内核映像以及加载内核,因此需要分配两倍内存 lea rbx,[TWO_PAGE_ADDRESS_FIRST+5*8] lea rax,[0x200000*5] or rax,0x83 alloc_mem: mov [rbx],rax add rbx,8 add rax,0x200000 loop alloc_mem ;正式读取内核 mov rbx,KERNEL_CACHE_ADDRESS xor rax,rax mov eax,KERNEL_START_SECTOR mov rcx,KERNEL_ALL_SECTORS read_kernel: call read_one_sector add rbx,512 inc eax loop read_kernel ;重定位内核程序,相对地址在r8中 mov rbx,[KERNEL_CACHE_ADDRESS+32] mov rax,KERNEL_CACHE_ADDRESS add rbx,rax ;程序头表起始地址 xor rcx,rcx mov cx,[KERNEL_CACHE_ADDRESS+56] ;程序头表项数量 xor rax,rax mov ax,[KERNEL_CACHE_ADDRESS+54] ;程序头表项大小 relloc_kernel: mov rdi,[rbx+16] add rdi,r8 ;各个段被加载的目的地址 mov rsi,KERNEL_CACHE_ADDRESS add rsi,[rbx+8] ;各个段的源地址 mov r10,rcx mov rcx,[rbx+32] ;当前段所占字节数 call mem_copy mov rcx,r10 add rbx,rax loop relloc_kernel mov rax,[KERNEL_CACHE_ADDRESS+24] add rax,r8 ;内核入口 jmp rax ;内存拷贝过程 mem_copy: push rsi push rdi push rcx cld rep movsb pop rcx pop rdi pop rsi ret ;参数说明:eax为起始扇区号,rbx为缓冲区地址 read_one_sector: push rax push rbx push rcx push rdx push rsi mov rsi,rax mov al,1 mov dx,0x1f2 ;向端口0x1f2写入读取的扇区数 out dx,al mov rax,rsi inc dx out dx,al ;向端口0x1f3写入起始扇区号0-7位 inc dx shr eax,8 out dx,al ;向端口0x1f4写入起始扇区号8-15位 inc dx shr eax,8 out dx,al ;向端口0x1f5写入起始扇区号16-23位 inc dx shr eax,8 or al,0xe0 out dx,al ;向端口0x1f6写入起始扇区号24-31位 inc dx mov al,0x20 out dx,al ;向端口0x1f7写入磁盘读取命令0x20 .waits: in al,dx and al,0x88 cmp al,0x08 jne .waits xor rcx,rcx mov cx,256 mov dx,0x1f0 .read_word: in ax,dx ;循环读取512字节 mov [rbx],ax add rbx,2 loop .read_word pop rsi pop rdx pop rcx pop rbx pop rax ret