【OS学习笔记】二十 保护模式六:保户模式下操作系统内核如何加载用户程序并运行 对应的汇编代码之主引导扇区程序

本汇编代码对应保户模式下操作系统内核如何加载用户程序并运行 的实际主引导扇区代码:

         ;代码清单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~2423~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
全部评论

相关推荐

豆泥🍀:同26届,加油,我也还没找到查看图片
点赞 评论 收藏
分享
03-15 14:55
已编辑
门头沟学院 golang
bg:双非学院本&nbsp;ACM银&nbsp;go选手timeline:3.1号开始暑期投递3.7号第二家公司离职顽岩科技&nbsp;ai服务中台方向&nbsp;笔试➕两轮面试,二面挂(钱真的好多😭)厦门纳克希科技&nbsp;搞AI的,一面OC猎豹移动&nbsp;搞AIGC方向&nbsp;一面OC北京七牛云&nbsp;搞AI接口方向&nbsp;一面OC上海古德猫宁&nbsp;搞AIGC方向&nbsp;二面OC上海简文&nbsp;面试撞了直接拒深圳图灵&nbsp;搞AIGC方向一面后无消息懒得问了,面试官当场反馈不错其他小厂没记,通过率80%,小厂杀手😂北京字节&nbsp;具体业务不方便透露也是AIGC后端方向2.28约面&nbsp;(不知道怎么捞的我,我也没在别的地方投过字节简历哇)3.6一面&nbsp;一小时&nbsp;半小时拷打简历(主要是AIGC部分)剩余半小时两个看代码猜结果(经典go问题)➕合并二叉树(秒a,但是造case造了10分钟哈哈)一天后约二面3.12&nbsp;二面,让我挑简历上两个亮点说,主要说的docker容器生命周期管理和raft协议使用二分法优化新任leader上任后与follower同步时间。跟面试官有共鸣,面试官还问我docker底层cpu隔离原理和是否知道虚拟显存。之后一道easy算法,(o1空间解决&nbsp;给定字符串含有{和}是否合法)秒a,之后进阶版如何用10台机加快构建,想五分钟后a出来。面试官以为45分钟面试时间,留了18分钟让我跟他随便聊,后面考了linux&nbsp;top和free的部分数据说什么意思(专业对口了只能说,但是当时没答很好)。因为当时手里有7牛云offer,跟面试官说能否快点面试,马上另外一家时间到了。10分钟后约hr面3.13,上午hr面,下午走完流程offer到手3.14腾讯技术运营约面,想直接拒😂感受:&nbsp;因为有AIGC经验所以特别受AI初创公司青睐,AIGC后端感觉竞争很小(指今年),全是简历拷打,基本没有人问我八股(八股吟唱被打断.jpeg),学的东西比较广的同时也能纵向深挖学习,也运气比较好了哈哈可能出于性格原因,没有走主流Java路线,也没有去主动跟着课写项目,项目都是自己研究和写的哈哈
烤点老白薯:你根本不是典型学院本的那种人,贵了你这能力
查看7道真题和解析
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务