【OS学习笔记】二十 保护模式六:保户模式下操作系统内核如何加载用户程序并运行 对应的汇编代码之主引导扇区程序
发布日期:2021-07-01 00:05:43
浏览次数:2
分类:技术文章
本文共 7156 字,大约阅读时间需要 23 分钟。
本汇编代码对应 的实际主引导扇区代码:
- 对应的内核代码在:
- 对应的用户程序代码在:
;代码清单13-1 ;文件名:c13_mbr.asm ;文件说明:硬盘主引导扇区代码 ;创建日期:2011-10-28 22:35 ;设置堆栈段和栈指针 core_base_address equ 0x00040000 ;常数,内核加载的起始内存地址 core_start_sector equ 0x00000001 ;常数,内核的起始逻辑扇区号 mov ax,cs mov ss,ax mov sp,0x7c00 ;计算GDT所在的逻辑段地址 mov eax,[cs:pgdt+0x7c00+0x02] ;GDT的32位物理地址 xor edx,edx mov ebx,16 div ebx ;分解成16位逻辑地址 mov ds,eax ;令DS指向该段以进行操作 mov ebx,edx ;段内起始偏移地址 ;跳过0#号描述符的槽位 ;创建1#描述符,这是一个数据段,对应0~4GB的线性地址空间 mov dword [ebx+0x08],0x0000ffff ;基地址为0,段界限为0xFFFFF mov dword [ebx+0x0c],0x00cf9200 ;粒度为4KB,存储器段描述符 ;创建保护模式下初始代码段描述符 mov dword [ebx+0x10],0x7c0001ff ;基地址为0x00007c00,界限0x1FF mov dword [ebx+0x14],0x00409800 ;粒度为1个字节,代码段描述符 ;建立保护模式下的堆栈段描述符 ;基地址为0x00007C00,界限0xFFFFE mov dword [ebx+0x18],0x7c00fffe ;粒度为4KB mov dword [ebx+0x1c],0x00cf9600 ;建立保护模式下的显示缓冲区描述符 mov dword [ebx+0x20],0x80007fff ;基地址为0x000B8000,界限0x07FFF mov dword [ebx+0x24],0x0040920b ;粒度为字节 ;初始化描述符表寄存器GDTR mov word [cs: pgdt+0x7c00],39 ;描述符表的界限 lgdt [cs: pgdt+0x7c00] in al,0x92 ;南桥芯片内的端口 or al,0000_0010B out 0x92,al ;打开A20 cli ;中断机制尚未工作 mov eax,cr0 or eax,1 mov cr0,eax ;设置PE位 ;以下进入保护模式... ... jmp dword 0x0010:flush ;16位的描述符选择子:32位偏移 ;清流水线并串行化处理器 [bits 32] flush: mov eax,0x0008 ;加载数据段(0..4GB)选择子 mov ds,eax mov eax,0x0018 ;加载堆栈段选择子 mov ss,eax xor esp,esp ;堆栈指针 <- 0 ;以下加载系统核心程序 mov edi,core_base_address mov eax,core_start_sector mov ebx,edi ;起始地址 call read_hard_disk_0 ;以下读取程序的起始部分(一个扇区) ;以下判断整个程序有多大 mov eax,[edi] ;核心程序尺寸 xor edx,edx mov ecx,512 ;512字节每扇区 div ecx or edx,edx jnz @1 ;未除尽,因此结果比实际扇区数少1 dec eax ;已经读了一个扇区,扇区总数减1 @1: or eax,eax ;考虑实际长度≤512个字节的情况 jz setup ;EAX=0 ? ;读取剩余的扇区 mov ecx,eax ;32位模式下的LOOP使用ECX mov eax,core_start_sector inc eax ;从下一个逻辑扇区接着读 @2: call read_hard_disk_0 inc eax loop @2 ;循环读,直到读完整个内核 setup: mov esi,[0x7c00+pgdt+0x02] ;不可以在代码段内寻址pgdt,但可以 ;通过4GB的段来访问 ;建立公用例程段描述符 mov eax,[edi+0x04] ;公用例程代码段起始汇编地址 mov ebx,[edi+0x08] ;核心数据段汇编地址 sub ebx,eax dec ebx ;公用例程段界限 add eax,edi ;公用例程段基地址 mov ecx,0x00409800 ;字节粒度的代码段描述符 call make_gdt_descriptor mov [esi+0x28],eax mov [esi+0x2c],edx ;建立核心数据段描述符 mov eax,[edi+0x08] ;核心数据段起始汇编地址 mov ebx,[edi+0x0c] ;核心代码段汇编地址 sub ebx,eax dec ebx ;核心数据段界限 add eax,edi ;核心数据段基地址 mov ecx,0x00409200 ;字节粒度的数据段描述符 call make_gdt_descriptor mov [esi+0x30],eax mov [esi+0x34],edx ;建立核心代码段描述符 mov eax,[edi+0x0c] ;核心代码段起始汇编地址 mov ebx,[edi+0x00] ;程序总长度 sub ebx,eax dec ebx ;核心代码段界限 add eax,edi ;核心代码段基地址 mov ecx,0x00409800 ;字节粒度的代码段描述符 call make_gdt_descriptor mov [esi+0x38],eax mov [esi+0x3c],edx mov word [0x7c00+pgdt],63 ;描述符表的界限 lgdt [0x7c00+pgdt] jmp far [edi+0x10] ;-------------------------------------------------------------------------------read_hard_disk_0: ;从硬盘读取一个逻辑扇区 ;EAX=逻辑扇区号 ;DS:EBX=目标缓冲区地址 ;返回:EBX=EBX+512 push eax push ecx push edx push eax mov dx,0x1f2 mov al,1 out dx,al ;读取的扇区数 inc dx ;0x1f3 pop eax out dx,al ;LBA地址7~0 inc dx ;0x1f4 mov cl,8 shr eax,cl out dx,al ;LBA地址15~8 inc dx ;0x1f5 shr eax,cl out dx,al ;LBA地址23~16 inc dx ;0x1f6 shr eax,cl or al,0xe0 ;第一硬盘 LBA地址27~24 out dx,al inc dx ;0x1f7 mov al,0x20 ;读命令 out dx,al .waits: in al,dx and al,0x88 cmp al,0x08 jnz .waits ;不忙,且硬盘已准备好数据传输 mov ecx,256 ;总共要读取的字数 mov dx,0x1f0 .readw: in ax,dx mov [ebx],ax add ebx,2 loop .readw pop edx pop ecx pop eax ret;-------------------------------------------------------------------------------make_gdt_descriptor: ;构造描述符 ;输入:EAX=线性基地址 ; EBX=段界限 ; ECX=属性(各属性位都在原始 ; 位置,其它没用到的位置0) ;返回:EDX:EAX=完整的描述符 mov edx,eax shl eax,16 or ax,bx ;描述符前32位(EAX)构造完毕 and edx,0xffff0000 ;清除基地址中无关的位 rol edx,8 bswap edx ;装配基址的31~24和23~16 (80486+) xor bx,bx or edx,ebx ;装配段界限的高4位 or edx,ecx ;装配属性 ret ;------------------------------------------------------------------------------- pgdt dw 0 dd 0x00007e00 ;GDT的物理地址;------------------------------------------------------------------------------- times 510-($-$$) db 0 db 0x55,0xaa
转载地址:https://lyy-0217.blog.csdn.net/article/details/84996777 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
不错!
[***.144.177.141]2024年04月14日 06时45分27秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!