请选择 进入手机版 | 继续访问电脑版

4Ameta

 找回密码
 立即注册
搜索
查看: 70|回复: 0

Learn x86 protected mode assembly language-c17_core.asm

[复制链接]

26

主题

26

帖子

119

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
119
发表于 2022-9-12 21:17:05 | 显示全部楼层 |阅读模式
  1.          ;代码清单17-2
  2.          ;文件名:c17_core.asm
  3.          ;文件说明:保护模式微型核心程序
  4.          ;创建日期:2012-07-12 23:15
  5. ;-------------------------------------------------------------------------------
  6.          ;以下定义常量
  7.          flat_4gb_code_seg_sel  equ  0x0008      ;平坦模型下的4GB代码段选择子
  8.          flat_4gb_data_seg_sel  equ  0x0018      ;平坦模型下的4GB数据段选择子
  9.          idt_linear_address     equ  0x8001f000  ;中断描述符表的线性基地址
  10. ;-------------------------------------------------------------------------------         
  11.          ;以下定义宏
  12.          %macro alloc_core_linear 0              ;在内核空间中分配虚拟内存
  13.                mov ebx,[core_tcb+0x06]
  14.                add dword [core_tcb+0x06],0x1000
  15.                call flat_4gb_code_seg_sel:alloc_inst_a_page
  16.          %endmacro
  17. ;-------------------------------------------------------------------------------
  18.          %macro alloc_user_linear 0              ;在任务空间中分配虚拟内存
  19.                mov ebx,[esi+0x06]
  20.                add dword [esi+0x06],0x1000
  21.                call flat_4gb_code_seg_sel:alloc_inst_a_page
  22.          %endmacro
  23.          
  24. ;===============================================================================
  25. SECTION  core  vstart=0x80040000

  26.          ;以下是系统核心的头部,用于加载核心程序
  27.          core_length      dd core_end       ;核心程序总长度#00

  28.          core_entry       dd start          ;核心代码段入口点#04

  29. ;-------------------------------------------------------------------------------
  30.          [bits 32]
  31. ;-------------------------------------------------------------------------------
  32.          ;字符串显示例程(适用于平坦内存模型)
  33. put_string:                                 ;显示0终止的字符串并移动光标
  34.                                             ;输入:EBX=字符串的线性地址

  35.          push ebx
  36.          push ecx

  37.          cli                                ;硬件操作期间,关中断

  38.   .getc:
  39.          mov cl,[ebx]
  40.          or cl,cl                           ;检测串结束标志(0)
  41.          jz .exit                           ;显示完毕,返回
  42.          call put_char
  43.          inc ebx
  44.          jmp .getc

  45.   .exit:

  46.          sti                                ;硬件操作完毕,开放中断

  47.          pop ecx
  48.          pop ebx

  49.          retf                               ;段间返回

  50. ;-------------------------------------------------------------------------------
  51. put_char:                                   ;在当前光标处显示一个字符,并推进
  52.                                             ;光标。仅用于段内调用
  53.                                             ;输入:CL=字符ASCII码
  54.          pushad

  55.          ;以下取当前光标位置
  56.          mov dx,0x3d4
  57.          mov al,0x0e
  58.          out dx,al
  59.          inc dx                             ;0x3d5
  60.          in al,dx                           ;高字
  61.          mov ah,al

  62.          dec dx                             ;0x3d4
  63.          mov al,0x0f
  64.          out dx,al
  65.          inc dx                             ;0x3d5
  66.          in al,dx                           ;低字
  67.          mov bx,ax                          ;BX=代表光标位置的16位数
  68.          and ebx,0x0000ffff                 ;准备使用32位寻址方式访问显存
  69.          
  70.          cmp cl,0x0d                        ;回车符?
  71.          jnz .put_0a                        
  72.          
  73.          mov ax,bx                          ;以下按回车符处理
  74.          mov bl,80
  75.          div bl
  76.          mul bl
  77.          mov bx,ax
  78.          jmp .set_cursor

  79.   .put_0a:
  80.          cmp cl,0x0a                        ;换行符?
  81.          jnz .put_other
  82.          add bx,80                          ;增加一行
  83.          jmp .roll_screen

  84.   .put_other:                               ;正常显示字符
  85.          shl bx,1
  86.          mov [0x800b8000+ebx],cl            ;在光标位置处显示字符

  87.          ;以下将光标位置推进一个字符
  88.          shr bx,1
  89.          inc bx

  90.   .roll_screen:
  91.          cmp bx,2000                        ;光标超出屏幕?滚屏
  92.          jl .set_cursor

  93.          cld
  94.          mov esi,0x800b80a0                 ;小心!32位模式下movsb/w/d
  95.          mov edi,0x800b8000                 ;使用的是esi/edi/ecx
  96.          mov ecx,1920
  97.          rep movsd
  98.          mov bx,3840                        ;清除屏幕最底一行
  99.          mov ecx,80                         ;32位程序应该使用ECX
  100.   .cls:
  101.          mov word [0x800b8000+ebx],0x0720
  102.          add bx,2
  103.          loop .cls

  104.          mov bx,1920

  105.   .set_cursor:
  106.          mov dx,0x3d4
  107.          mov al,0x0e
  108.          out dx,al
  109.          inc dx                             ;0x3d5
  110.          mov al,bh
  111.          out dx,al
  112.          dec dx                             ;0x3d4
  113.          mov al,0x0f
  114.          out dx,al
  115.          inc dx                             ;0x3d5
  116.          mov al,bl
  117.          out dx,al
  118.          
  119.          popad
  120.          
  121.          ret                              

  122. ;-------------------------------------------------------------------------------
  123. read_hard_disk_0:                           ;从硬盘读取一个逻辑扇区(平坦模型)
  124.                                             ;EAX=逻辑扇区号
  125.                                             ;EBX=目标缓冲区线性地址
  126.                                             ;返回:EBX=EBX+512
  127.          cli
  128.          
  129.          push eax
  130.          push ecx
  131.          push edx
  132.       
  133.          push eax
  134.          
  135.          mov dx,0x1f2
  136.          mov al,1
  137.          out dx,al                          ;读取的扇区数

  138.          inc dx                             ;0x1f3
  139.          pop eax
  140.          out dx,al                          ;LBA地址7~0

  141.          inc dx                             ;0x1f4
  142.          mov cl,8
  143.          shr eax,cl
  144.          out dx,al                          ;LBA地址15~8

  145.          inc dx                             ;0x1f5
  146.          shr eax,cl
  147.          out dx,al                          ;LBA地址23~16

  148.          inc dx                             ;0x1f6
  149.          shr eax,cl
  150.          or al,0xe0                         ;第一硬盘  LBA地址27~24
  151.          out dx,al

  152.          inc dx                             ;0x1f7
  153.          mov al,0x20                        ;读命令
  154.          out dx,al

  155.   .waits:
  156.          in al,dx
  157.          and al,0x88
  158.          cmp al,0x08
  159.          jnz .waits                         ;不忙,且硬盘已准备好数据传输

  160.          mov ecx,256                        ;总共要读取的字数
  161.          mov dx,0x1f0
  162.   .readw:
  163.          in ax,dx
  164.          mov [ebx],ax
  165.          add ebx,2
  166.          loop .readw

  167.          pop edx
  168.          pop ecx
  169.          pop eax
  170.       
  171.          sti
  172.       
  173.          retf                               ;远返回

  174. ;-------------------------------------------------------------------------------
  175. ;汇编语言程序是极难一次成功,而且调试非常困难。这个例程可以提供帮助
  176. put_hex_dword:                              ;在当前光标处以十六进制形式显示
  177.                                             ;一个双字并推进光标
  178.                                             ;输入:EDX=要转换并显示的数字
  179.                                             ;输出:无
  180.          pushad

  181.          mov ebx,bin_hex                    ;指向核心地址空间内的转换表
  182.          mov ecx,8
  183.   .xlt:   
  184.          rol edx,4
  185.          mov eax,edx
  186.          and eax,0x0000000f
  187.          xlat
  188.       
  189.          push ecx
  190.          mov cl,al                           
  191.          call put_char
  192.          pop ecx
  193.       
  194.          loop .xlt
  195.       
  196.          popad
  197.          retf
  198.       
  199. ;-------------------------------------------------------------------------------
  200. set_up_gdt_descriptor:                      ;在GDT内安装一个新的描述符
  201.                                             ;输入:EDX:EAX=描述符
  202.                                             ;输出:CX=描述符的选择子
  203.          push eax
  204.          push ebx
  205.          push edx

  206.          sgdt [pgdt]                        ;取得GDTR的界限和线性地址

  207.          movzx ebx,word [pgdt]              ;GDT界限
  208.          inc bx                             ;GDT总字节数,也是下一个描述符偏移
  209.          add ebx,[pgdt+2]                   ;下一个描述符的线性地址

  210.          mov [ebx],eax
  211.          mov [ebx+4],edx

  212.          add word [pgdt],8                  ;增加一个描述符的大小

  213.          lgdt [pgdt]                        ;对GDT的更改生效

  214.          mov ax,[pgdt]                      ;得到GDT界限值
  215.          xor dx,dx
  216.          mov bx,8
  217.          div bx                             ;除以8,去掉余数
  218.          mov cx,ax
  219.          shl cx,3                           ;将索引号移到正确位置

  220.          pop edx
  221.          pop ebx
  222.          pop eax

  223.          retf
  224. ;-------------------------------------------------------------------------------
  225. make_seg_descriptor:                        ;构造存储器和系统的段描述符
  226.                                             ;输入:EAX=线性基地址
  227.                                             ;      EBX=段界限
  228.                                             ;      ECX=属性。各属性位都在原始
  229.                                             ;          位置,无关的位清零
  230.                                             ;返回:EDX:EAX=描述符
  231.          mov edx,eax
  232.          shl eax,16
  233.          or ax,bx                           ;描述符前32位(EAX)构造完毕

  234.          and edx,0xffff0000                 ;清除基地址中无关的位
  235.          rol edx,8
  236.          bswap edx                          ;装配基址的31~24和23~16  (80486+)

  237.          xor bx,bx
  238.          or edx,ebx                         ;装配段界限的高4位

  239.          or edx,ecx                         ;装配属性

  240.          retf

  241. ;-------------------------------------------------------------------------------
  242. make_gate_descriptor:                       ;构造门的描述符(调用门等)
  243.                                             ;输入:EAX=门代码在段内偏移地址
  244.                                             ;       BX=门代码所在段的选择子
  245.                                             ;       CX=段类型及属性等(各属
  246.                                             ;          性位都在原始位置)
  247.                                             ;返回:EDX:EAX=完整的描述符
  248.          push ebx
  249.          push ecx
  250.       
  251.          mov edx,eax
  252.          and edx,0xffff0000                 ;得到偏移地址高16位
  253.          or dx,cx                           ;组装属性部分到EDX
  254.       
  255.          and eax,0x0000ffff                 ;得到偏移地址低16位
  256.          shl ebx,16                          
  257.          or eax,ebx                         ;组装段选择子部分
  258.       
  259.          pop ecx
  260.          pop ebx
  261.       
  262.          retf                                   
  263.                              
  264. ;-------------------------------------------------------------------------------
  265. allocate_a_4k_page:                         ;分配一个4KB的页
  266.                                             ;输入:无
  267.                                             ;输出:EAX=页的物理地址
  268.          push ebx
  269.          push ecx
  270.          push edx

  271.          xor eax,eax
  272.   .b1:
  273.          bts [page_bit_map],eax
  274.          jnc .b2
  275.          inc eax
  276.          cmp eax,page_map_len*8
  277.          jl .b1
  278.          
  279.          mov ebx,message_3
  280.          call flat_4gb_code_seg_sel:put_string
  281.          hlt                                ;没有可以分配的页,停机
  282.          
  283.   .b2:
  284.          shl eax,12                         ;乘以4096(0x1000)
  285.          
  286.          pop edx
  287.          pop ecx
  288.          pop ebx
  289.          
  290.          ret
  291.          
  292. ;-------------------------------------------------------------------------------
  293. alloc_inst_a_page:                          ;分配一个页,并安装在当前活动的
  294.                                             ;层级分页结构中
  295.                                             ;输入:EBX=页的线性地址
  296.          push eax
  297.          push ebx
  298.          push esi
  299.          
  300.          ;检查该线性地址所对应的页表是否存在
  301.          mov esi,ebx
  302.          and esi,0xffc00000
  303.          shr esi,20                         ;得到页目录索引,并乘以4
  304.          or esi,0xfffff000                  ;页目录自身的线性地址+表内偏移

  305.          test dword [esi],0x00000001        ;P位是否为“1”。检查该线性地址是
  306.          jnz .b1                            ;否已经有对应的页表
  307.          
  308.          ;创建该线性地址所对应的页表
  309.          call allocate_a_4k_page            ;分配一个页做为页表
  310.          or eax,0x00000007
  311.          mov [esi],eax                      ;在页目录中登记该页表
  312.          
  313.   .b1:
  314.          ;开始访问该线性地址所对应的页表
  315.          mov esi,ebx
  316.          shr esi,10
  317.          and esi,0x003ff000                 ;或者0xfffff000,因高10位是零
  318.          or esi,0xffc00000                  ;得到该页表的线性地址
  319.          
  320.          ;得到该线性地址在页表内的对应条目(页表项)
  321.          and ebx,0x003ff000
  322.          shr ebx,10                         ;相当于右移12位,再乘以4
  323.          or esi,ebx                         ;页表项的线性地址
  324.          call allocate_a_4k_page            ;分配一个页,这才是要安装的页
  325.          or eax,0x00000007
  326.          mov [esi],eax
  327.          
  328.          pop esi
  329.          pop ebx
  330.          pop eax
  331.          
  332.          retf  

  333. ;-------------------------------------------------------------------------------
  334. create_copy_cur_pdir:                       ;创建新页目录,并复制当前页目录内容
  335.                                             ;输入:无
  336.                                             ;输出:EAX=新页目录的物理地址
  337.          push esi
  338.          push edi
  339.          push ebx
  340.          push ecx
  341.          
  342.          call allocate_a_4k_page            
  343.          mov ebx,eax
  344.          or ebx,0x00000007
  345.          mov [0xfffffff8],ebx

  346.          invlpg [0xfffffff8]

  347.          mov esi,0xfffff000                 ;ESI->当前页目录的线性地址
  348.          mov edi,0xffffe000                 ;EDI->新页目录的线性地址
  349.          mov ecx,1024                       ;ECX=要复制的目录项数
  350.          cld
  351.          repe movsd
  352.          
  353.          pop ecx
  354.          pop ebx
  355.          pop edi
  356.          pop esi
  357.          
  358.          retf
  359.          
  360. ;-------------------------------------------------------------------------------
  361. general_interrupt_handler:                  ;通用的中断处理过程
  362.          push eax
  363.          
  364.          mov al,0x20                        ;中断结束命令EOI
  365.          out 0xa0,al                        ;向从片发送
  366.          out 0x20,al                        ;向主片发送
  367.          
  368.          pop eax
  369.          
  370.          iretd

  371. ;-------------------------------------------------------------------------------
  372. general_exception_handler:                  ;通用的异常处理过程
  373.          mov ebx,excep_msg
  374.          call flat_4gb_code_seg_sel:put_string
  375.          
  376.          hlt

  377. ;-------------------------------------------------------------------------------
  378. rtm_0x70_interrupt_handle:                  ;实时时钟中断处理过程

  379.          pushad

  380.          mov al,0x20                        ;中断结束命令EOI
  381.          out 0xa0,al                        ;向8259A从片发送
  382.          out 0x20,al                        ;向8259A主片发送

  383.          mov al,0x0c                        ;寄存器C的索引。且开放NMI
  384.          out 0x70,al
  385.          in al,0x71                         ;读一下RTC的寄存器C,否则只发生一次中断
  386.                                             ;此处不考虑闹钟和周期性中断的情况
  387.          ;找当前任务(状态为忙的任务)在链表中的位置
  388.          mov eax,tcb_chain                  
  389.   .b0:                                      ;EAX=链表头或当前TCB线性地址
  390.          mov ebx,[eax]                      ;EBX=下一个TCB线性地址
  391.          or ebx,ebx
  392.          jz .irtn                           ;链表为空,或已到末尾,从中断返回
  393.          cmp word [ebx+0x04],0xffff         ;是忙任务(当前任务)?
  394.          je .b1
  395.          mov eax,ebx                        ;定位到下一个TCB(的线性地址)
  396.          jmp .b0         

  397.          ;将当前为忙的任务移到链尾
  398.   .b1:
  399.          mov ecx,[ebx]                      ;下游TCB的线性地址
  400.          mov [eax],ecx                      ;将当前任务从链中拆除

  401.   .b2:                                      ;此时,EBX=当前任务的线性地址
  402.          mov edx,[eax]
  403.          or edx,edx                         ;已到链表尾端?
  404.          jz .b3
  405.          mov eax,edx
  406.          jmp .b2

  407.   .b3:
  408.          mov [eax],ebx                      ;将忙任务的TCB挂在链表尾端
  409.          mov dword [ebx],0x00000000         ;将忙任务的TCB标记为链尾

  410.          ;从链首搜索第一个空闲任务
  411.          mov eax,tcb_chain
  412.   .b4:
  413.          mov eax,[eax]
  414.          or eax,eax                         ;已到链尾(未发现空闲任务)
  415.          jz .irtn                           ;未发现空闲任务,从中断返回
  416.          cmp word [eax+0x04],0x0000         ;是空闲任务?
  417.          jnz .b4

  418.          ;将空闲任务和当前任务的状态都取反
  419.          not word [eax+0x04]                ;设置空闲任务的状态为忙
  420.          not word [ebx+0x04]                ;设置当前任务(忙)的状态为空闲
  421.          jmp far [eax+0x14]                 ;任务转换

  422.   .irtn:
  423.          popad

  424.          iretd

  425. ;-------------------------------------------------------------------------------
  426. terminate_current_task:                     ;终止当前任务
  427.                                             ;注意,执行此例程时,当前任务仍在
  428.                                             ;运行中。此例程其实也是当前任务的
  429.                                             ;一部分
  430.          ;找当前任务(状态为忙的任务)在链表中的位置
  431.          mov eax,tcb_chain
  432.   .b0:                                      ;EAX=链表头或当前TCB线性地址
  433.          mov ebx,[eax]                      ;EBX=下一个TCB线性地址
  434.          cmp word [ebx+0x04],0xffff         ;是忙任务(当前任务)?
  435.          je .b1
  436.          mov eax,ebx                        ;定位到下一个TCB(的线性地址)
  437.          jmp .b0
  438.          
  439.   .b1:
  440.          mov word [ebx+0x04],0x3333         ;修改当前任务的状态为“退出”
  441.          
  442.   .b2:
  443.          hlt                                ;停机,等待程序管理器恢复运行时,
  444.                                             ;将其回收
  445.          jmp .b2

  446. ;-------------------------------------------------------------------------------
  447.          pgdt             dw  0             ;用于设置和修改GDT
  448.                           dd  0

  449.          pidt             dw  0
  450.                           dd  0
  451.                           
  452.          ;任务控制块链
  453.          tcb_chain        dd  0

  454.          core_tcb   times  32  db 0         ;内核(程序管理器)的TCB

  455.          page_bit_map     db  0xff,0xff,0xff,0xff,0xff,0xff,0x55,0x55
  456.                           db  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
  457.                           db  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
  458.                           db  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
  459.                           db  0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55
  460.                           db  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  461.                           db  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  462.                           db  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  463.          page_map_len     equ $-page_bit_map
  464.                           
  465.          ;符号地址检索表
  466.          salt:
  467.          salt_1           db  '@PrintString'
  468.                      times 256-($-salt_1) db 0
  469.                           dd  put_string
  470.                           dw  flat_4gb_code_seg_sel

  471.          salt_2           db  '@ReadDiskData'
  472.                      times 256-($-salt_2) db 0
  473.                           dd  read_hard_disk_0
  474.                           dw  flat_4gb_code_seg_sel

  475.          salt_3           db  '@PrintDwordAsHexString'
  476.                      times 256-($-salt_3) db 0
  477.                           dd  put_hex_dword
  478.                           dw  flat_4gb_code_seg_sel

  479.          salt_4           db  '@TerminateProgram'
  480.                      times 256-($-salt_4) db 0
  481.                           dd  terminate_current_task
  482.                           dw  flat_4gb_code_seg_sel

  483.          salt_item_len   equ $-salt_4
  484.          salt_items      equ ($-salt)/salt_item_len

  485.          excep_msg        db  '********Exception encounted********',0

  486.          message_0        db  '  Working in system core with protection '
  487.                           db  'and paging are all enabled.System core is mapped '
  488.                           db  'to address 0x80000000.',0x0d,0x0a,0

  489.          message_1        db  '  System wide CALL-GATE mounted.',0x0d,0x0a,0
  490.          
  491.          message_3        db  '********No more pages********',0
  492.          
  493.          core_msg0        db  '  System core task running!',0x0d,0x0a,0
  494.          
  495.          bin_hex          db '0123456789ABCDEF'
  496.                                             ;put_hex_dword子过程用的查找表

  497.          core_buf   times 512 db 0          ;内核用的缓冲区

  498.          cpu_brnd0        db 0x0d,0x0a,'  ',0
  499.          cpu_brand  times 52 db 0
  500.          cpu_brnd1        db 0x0d,0x0a,0x0d,0x0a,0

  501. ;-------------------------------------------------------------------------------
  502. fill_descriptor_in_ldt:                     ;在LDT内安装一个新的描述符
  503.                                             ;输入:EDX:EAX=描述符
  504.                                             ;          EBX=TCB基地址
  505.                                             ;输出:CX=描述符的选择子
  506.          push eax
  507.          push edx
  508.          push edi

  509.          mov edi,[ebx+0x0c]                 ;获得LDT基地址
  510.          
  511.          xor ecx,ecx
  512.          mov cx,[ebx+0x0a]                  ;获得LDT界限
  513.          inc cx                             ;LDT的总字节数,即新描述符偏移地址
  514.          
  515.          mov [edi+ecx+0x00],eax
  516.          mov [edi+ecx+0x04],edx             ;安装描述符

  517.          add cx,8                           
  518.          dec cx                             ;得到新的LDT界限值

  519.          mov [ebx+0x0a],cx                  ;更新LDT界限值到TCB

  520.          mov ax,cx
  521.          xor dx,dx
  522.          mov cx,8
  523.          div cx
  524.          
  525.          mov cx,ax
  526.          shl cx,3                           ;左移3位,并且
  527.          or cx,0000_0000_0000_0100B         ;使TI位=1,指向LDT,最后使RPL=00

  528.          pop edi
  529.          pop edx
  530.          pop eax
  531.      
  532.          ret
  533.       
  534. ;-------------------------------------------------------------------------------
  535. load_relocate_program:                      ;加载并重定位用户程序
  536.                                             ;输入: PUSH 逻辑扇区号
  537.                                             ;      PUSH 任务控制块基地址
  538.                                             ;输出:无
  539.          pushad
  540.       
  541.          mov ebp,esp                        ;为访问通过堆栈传递的参数做准备
  542.       
  543.          ;清空当前页目录的前半部分(对应低2GB的局部地址空间)
  544.          mov ebx,0xfffff000
  545.          xor esi,esi
  546.   .b1:
  547.          mov dword [ebx+esi*4],0x00000000
  548.          inc esi
  549.          cmp esi,512
  550.          jl .b1

  551.          mov eax,cr3
  552.          mov cr3,eax                        ;刷新TLB
  553.          
  554.          ;以下开始分配内存并加载用户程序
  555.          mov eax,[ebp+40]                   ;从堆栈中取出用户程序起始扇区号
  556.          mov ebx,core_buf                   ;读取程序头部数据
  557.          call flat_4gb_code_seg_sel:read_hard_disk_0

  558.          ;以下判断整个程序有多大
  559.          mov eax,[core_buf]                 ;程序尺寸
  560.          mov ebx,eax
  561.          and ebx,0xfffff000                 ;使之4KB对齐
  562.          add ebx,0x1000                        
  563.          test eax,0x00000fff                ;程序的大小正好是4KB的倍数吗?
  564.          cmovnz eax,ebx                     ;不是。使用凑整的结果

  565.          mov ecx,eax
  566.          shr ecx,12                         ;程序占用的总4KB页数
  567.          
  568.          mov eax,[ebp+40]                   ;起始扇区号
  569.          mov esi,[ebp+36]                   ;从堆栈中取得TCB的基地址
  570.   .b2:
  571.          alloc_user_linear                  ;宏:在用户任务地址空间上分配内存
  572.          
  573.          push ecx
  574.          mov ecx,8
  575.   .b3:
  576.          call flat_4gb_code_seg_sel:read_hard_disk_0               
  577.          inc eax
  578.          loop .b3

  579.          pop ecx
  580.          loop .b2

  581.          ;在内核地址空间内创建用户任务的TSS
  582.          alloc_core_linear                  ;宏:在内核的地址空间上分配内存
  583.                                             ;用户任务的TSS必须在全局空间上分配
  584.          
  585.          mov [esi+0x14],ebx                 ;在TCB中填写TSS的线性地址
  586.          mov word [esi+0x12],103            ;在TCB中填写TSS的界限值
  587.          
  588.          ;在用户任务的局部地址空间内创建LDT
  589.          alloc_user_linear                  ;宏:在用户任务地址空间上分配内存

  590.          mov [esi+0x0c],ebx                 ;填写LDT线性地址到TCB中

  591.          ;建立程序代码段描述符
  592.          mov eax,0x00000000
  593.          mov ebx,0x000fffff                 
  594.          mov ecx,0x00c0f800                 ;4KB粒度的代码段描述符,特权级3
  595.          call flat_4gb_code_seg_sel:make_seg_descriptor
  596.          mov ebx,esi                        ;TCB的基地址
  597.          call fill_descriptor_in_ldt
  598.          or cx,0000_0000_0000_0011B         ;设置选择子的特权级为3
  599.          
  600.          mov ebx,[esi+0x14]                 ;从TCB中获取TSS的线性地址
  601.          mov [ebx+76],cx                    ;填写TSS的CS域

  602.          ;建立程序数据段描述符
  603.          mov eax,0x00000000
  604.          mov ebx,0x000fffff                 
  605.          mov ecx,0x00c0f200                 ;4KB粒度的数据段描述符,特权级3
  606.          call flat_4gb_code_seg_sel:make_seg_descriptor
  607.          mov ebx,esi                        ;TCB的基地址
  608.          call fill_descriptor_in_ldt
  609.          or cx,0000_0000_0000_0011B         ;设置选择子的特权级为3
  610.          
  611.          mov ebx,[esi+0x14]                 ;从TCB中获取TSS的线性地址
  612.          mov [ebx+84],cx                    ;填写TSS的DS域
  613.          mov [ebx+72],cx                    ;填写TSS的ES域
  614.          mov [ebx+88],cx                    ;填写TSS的FS域
  615.          mov [ebx+92],cx                    ;填写TSS的GS域
  616.          
  617.          ;将数据段作为用户任务的3特权级固有堆栈
  618.          alloc_user_linear                  ;宏:在用户任务地址空间上分配内存
  619.          
  620.          mov ebx,[esi+0x14]                 ;从TCB中获取TSS的线性地址
  621.          mov [ebx+80],cx                    ;填写TSS的SS域
  622.          mov edx,[esi+0x06]                 ;堆栈的高端线性地址
  623.          mov [ebx+56],edx                   ;填写TSS的ESP域

  624.          ;在用户任务的局部地址空间内创建0特权级堆栈
  625.          alloc_user_linear                  ;宏:在用户任务地址空间上分配内存

  626.          mov eax,0x00000000
  627.          mov ebx,0x000fffff
  628.          mov ecx,0x00c09200                 ;4KB粒度的堆栈段描述符,特权级0
  629.          call flat_4gb_code_seg_sel:make_seg_descriptor
  630.          mov ebx,esi                        ;TCB的基地址
  631.          call fill_descriptor_in_ldt
  632.          or cx,0000_0000_0000_0000B         ;设置选择子的特权级为0

  633.          mov ebx,[esi+0x14]                 ;从TCB中获取TSS的线性地址
  634.          mov [ebx+8],cx                     ;填写TSS的SS0域
  635.          mov edx,[esi+0x06]                 ;堆栈的高端线性地址
  636.          mov [ebx+4],edx                    ;填写TSS的ESP0域

  637.          ;在用户任务的局部地址空间内创建1特权级堆栈
  638.          alloc_user_linear                  ;宏:在用户任务地址空间上分配内存

  639.          mov eax,0x00000000
  640.          mov ebx,0x000fffff
  641.          mov ecx,0x00c0b200                 ;4KB粒度的堆栈段描述符,特权级1
  642.          call flat_4gb_code_seg_sel:make_seg_descriptor
  643.          mov ebx,esi                        ;TCB的基地址
  644.          call fill_descriptor_in_ldt
  645.          or cx,0000_0000_0000_0001B         ;设置选择子的特权级为1

  646.          mov ebx,[esi+0x14]                 ;从TCB中获取TSS的线性地址
  647.          mov [ebx+16],cx                    ;填写TSS的SS1域
  648.          mov edx,[esi+0x06]                 ;堆栈的高端线性地址
  649.          mov [ebx+12],edx                   ;填写TSS的ESP1域

  650.          ;在用户任务的局部地址空间内创建2特权级堆栈
  651.          alloc_user_linear                  ;宏:在用户任务地址空间上分配内存

  652.          mov eax,0x00000000
  653.          mov ebx,0x000fffff
  654.          mov ecx,0x00c0d200                 ;4KB粒度的堆栈段描述符,特权级2
  655.          call flat_4gb_code_seg_sel:make_seg_descriptor
  656.          mov ebx,esi                        ;TCB的基地址
  657.          call fill_descriptor_in_ldt
  658.          or cx,0000_0000_0000_0010B         ;设置选择子的特权级为2

  659.          mov ebx,[esi+0x14]                 ;从TCB中获取TSS的线性地址
  660.          mov [ebx+24],cx                    ;填写TSS的SS2域
  661.          mov edx,[esi+0x06]                 ;堆栈的高端线性地址
  662.          mov [ebx+20],edx                   ;填写TSS的ESP2域

  663.          ;重定位U-SALT
  664.          cld

  665.          mov ecx,[0x0c]                     ;U-SALT条目数
  666.          mov edi,[0x08]                     ;U-SALT在4GB空间内的偏移
  667.   .b4:
  668.          push ecx
  669.          push edi
  670.       
  671.          mov ecx,salt_items
  672.          mov esi,salt
  673.   .b5:
  674.          push edi
  675.          push esi
  676.          push ecx

  677.          mov ecx,64                         ;检索表中,每条目的比较次数
  678.          repe cmpsd                         ;每次比较4字节
  679.          jnz .b6
  680.          mov eax,[esi]                      ;若匹配,则esi恰好指向其后的地址
  681.          mov [edi-256],eax                  ;将字符串改写成偏移地址
  682.          mov ax,[esi+4]
  683.          or ax,0000000000000011B            ;以用户程序自己的特权级使用调用门
  684.                                             ;故RPL=3
  685.          mov [edi-252],ax                   ;回填调用门选择子
  686.   .b6:
  687.       
  688.          pop ecx
  689.          pop esi
  690.          add esi,salt_item_len
  691.          pop edi                            ;从头比较
  692.          loop .b5
  693.       
  694.          pop edi
  695.          add edi,256
  696.          pop ecx
  697.          loop .b4

  698.          ;在GDT中登记LDT描述符
  699.          mov esi,[ebp+36]                   ;从堆栈中取得TCB的基地址
  700.          mov eax,[esi+0x0c]                 ;LDT的起始线性地址
  701.          movzx ebx,word [esi+0x0a]          ;LDT段界限
  702.          mov ecx,0x00408200                 ;LDT描述符,特权级0
  703.          call flat_4gb_code_seg_sel:make_seg_descriptor
  704.          call flat_4gb_code_seg_sel:set_up_gdt_descriptor
  705.          mov [esi+0x10],cx                  ;登记LDT选择子到TCB中

  706.          mov ebx,[esi+0x14]                 ;从TCB中获取TSS的线性地址
  707.          mov [ebx+96],cx                    ;填写TSS的LDT域

  708.          mov word [ebx+0],0                 ;反向链=0
  709.       
  710.          mov dx,[esi+0x12]                  ;段长度(界限)
  711.          mov [ebx+102],dx                   ;填写TSS的I/O位图偏移域
  712.       
  713.          mov word [ebx+100],0               ;T=0
  714.       
  715.          mov eax,[0x04]                     ;从任务的4GB地址空间获取入口点
  716.          mov [ebx+32],eax                   ;填写TSS的EIP域

  717.          pushfd
  718.          pop edx
  719.          mov [ebx+36],edx                   ;填写TSS的EFLAGS域

  720.          ;在GDT中登记TSS描述符
  721.          mov eax,[esi+0x14]                 ;从TCB中获取TSS的起始线性地址
  722.          movzx ebx,word [esi+0x12]          ;段长度(界限)
  723.          mov ecx,0x00408900                 ;TSS描述符,特权级0
  724.          call flat_4gb_code_seg_sel:make_seg_descriptor
  725.          call flat_4gb_code_seg_sel:set_up_gdt_descriptor
  726.          mov [esi+0x18],cx                  ;登记TSS选择子到TCB

  727.          ;创建用户任务的页目录
  728.          ;注意!页的分配和使用是由页位图决定的,可以不占用线性地址空间
  729.          call flat_4gb_code_seg_sel:create_copy_cur_pdir
  730.          mov ebx,[esi+0x14]                 ;从TCB中获取TSS的线性地址
  731.          mov dword [ebx+28],eax             ;填写TSS的CR3(PDBR)域
  732.                   
  733.          popad
  734.       
  735.          ret 8                              ;丢弃调用本过程前压入的参数
  736.       
  737. ;-------------------------------------------------------------------------------
  738. append_to_tcb_link:                         ;在TCB链上追加任务控制块
  739.                                             ;输入:ECX=TCB线性基地址
  740.          cli
  741.          
  742.          push eax
  743.          push ebx

  744.          mov eax,tcb_chain
  745.   .b0:                                      ;EAX=链表头或当前TCB线性地址
  746.          mov ebx,[eax]                      ;EBX=下一个TCB线性地址
  747.          or ebx,ebx
  748.          jz .b1                             ;链表为空,或已到末尾
  749.          mov eax,ebx                        ;定位到下一个TCB(的线性地址)
  750.          jmp .b0

  751.   .b1:
  752.          mov [eax],ecx
  753.          mov dword [ecx],0x00000000         ;当前TCB指针域清零,以指示这是最
  754.                                             ;后一个TCB
  755.          pop ebx
  756.          pop eax
  757.          
  758.          sti
  759.          
  760.          ret
  761.          
  762. ;-------------------------------------------------------------------------------
  763. start:
  764.          ;创建中断描述符表IDT
  765.          ;在此之前,禁止调用put_string过程,以及任何含有sti指令的过程。
  766.          
  767.          ;前20个向量是处理器异常使用的
  768.          mov eax,general_exception_handler  ;门代码在段内偏移地址
  769.          mov bx,flat_4gb_code_seg_sel       ;门代码所在段的选择子
  770.          mov cx,0x8e00                      ;32位中断门,0特权级
  771.          call flat_4gb_code_seg_sel:make_gate_descriptor

  772.          mov ebx,idt_linear_address         ;中断描述符表的线性地址
  773.          xor esi,esi
  774.   .idt0:
  775.          mov [ebx+esi*8],eax
  776.          mov [ebx+esi*8+4],edx
  777.          inc esi
  778.          cmp esi,19                         ;安装前20个异常中断处理过程
  779.          jle .idt0

  780.          ;其余为保留或硬件使用的中断向量
  781.          mov eax,general_interrupt_handler  ;门代码在段内偏移地址
  782.          mov bx,flat_4gb_code_seg_sel       ;门代码所在段的选择子
  783.          mov cx,0x8e00                      ;32位中断门,0特权级
  784.          call flat_4gb_code_seg_sel:make_gate_descriptor

  785.          mov ebx,idt_linear_address         ;中断描述符表的线性地址
  786.   .idt1:
  787.          mov [ebx+esi*8],eax
  788.          mov [ebx+esi*8+4],edx
  789.          inc esi
  790.          cmp esi,255                        ;安装普通的中断处理过程
  791.          jle .idt1

  792.          ;设置实时时钟中断处理过程
  793.          mov eax,rtm_0x70_interrupt_handle  ;门代码在段内偏移地址
  794.          mov bx,flat_4gb_code_seg_sel       ;门代码所在段的选择子
  795.          mov cx,0x8e00                      ;32位中断门,0特权级
  796.          call flat_4gb_code_seg_sel:make_gate_descriptor

  797.          mov ebx,idt_linear_address         ;中断描述符表的线性地址
  798.          mov [ebx+0x70*8],eax
  799.          mov [ebx+0x70*8+4],edx

  800.          ;准备开放中断
  801.          mov word [pidt],256*8-1            ;IDT的界限
  802.          mov dword [pidt+2],idt_linear_address
  803.          lidt [pidt]                        ;加载中断描述符表寄存器IDTR

  804.          ;设置8259A中断控制器
  805.          mov al,0x11
  806.          out 0x20,al                        ;ICW1:边沿触发/级联方式
  807.          mov al,0x20
  808.          out 0x21,al                        ;ICW2:起始中断向量
  809.          mov al,0x04
  810.          out 0x21,al                        ;ICW3:从片级联到IR2
  811.          mov al,0x01
  812.          out 0x21,al                        ;ICW4:非总线缓冲,全嵌套,正常EOI

  813.          mov al,0x11
  814.          out 0xa0,al                        ;ICW1:边沿触发/级联方式
  815.          mov al,0x70
  816.          out 0xa1,al                        ;ICW2:起始中断向量
  817.          mov al,0x04
  818.          out 0xa1,al                        ;ICW3:从片级联到IR2
  819.          mov al,0x01
  820.          out 0xa1,al                        ;ICW4:非总线缓冲,全嵌套,正常EOI

  821.          ;设置和时钟中断相关的硬件
  822.          mov al,0x0b                        ;RTC寄存器B
  823.          or al,0x80                         ;阻断NMI
  824.          out 0x70,al
  825.          mov al,0x12                        ;设置寄存器B,禁止周期性中断,开放更
  826.          out 0x71,al                        ;新结束后中断,BCD码,24小时制

  827.          in al,0xa1                         ;读8259从片的IMR寄存器
  828.          and al,0xfe                        ;清除bit 0(此位连接RTC)
  829.          out 0xa1,al                        ;写回此寄存器

  830.          mov al,0x0c
  831.          out 0x70,al
  832.          in al,0x71                         ;读RTC寄存器C,复位未决的中断状态

  833.          sti                                ;开放硬件中断

  834.          mov ebx,message_0
  835.          call flat_4gb_code_seg_sel:put_string

  836.          ;显示处理器品牌信息
  837.          mov eax,0x80000002
  838.          cpuid
  839.          mov [cpu_brand + 0x00],eax
  840.          mov [cpu_brand + 0x04],ebx
  841.          mov [cpu_brand + 0x08],ecx
  842.          mov [cpu_brand + 0x0c],edx
  843.       
  844.          mov eax,0x80000003
  845.          cpuid
  846.          mov [cpu_brand + 0x10],eax
  847.          mov [cpu_brand + 0x14],ebx
  848.          mov [cpu_brand + 0x18],ecx
  849.          mov [cpu_brand + 0x1c],edx

  850.          mov eax,0x80000004
  851.          cpuid
  852.          mov [cpu_brand + 0x20],eax
  853.          mov [cpu_brand + 0x24],ebx
  854.          mov [cpu_brand + 0x28],ecx
  855.          mov [cpu_brand + 0x2c],edx

  856.          mov ebx,cpu_brnd0                  ;显示处理器品牌信息
  857.          call flat_4gb_code_seg_sel:put_string
  858.          mov ebx,cpu_brand
  859.          call flat_4gb_code_seg_sel:put_string
  860.          mov ebx,cpu_brnd1
  861.          call flat_4gb_code_seg_sel:put_string

  862.          ;以下开始安装为整个系统服务的调用门。特权级之间的控制转移必须使用门
  863.          mov edi,salt                       ;C-SALT表的起始位置
  864.          mov ecx,salt_items                 ;C-SALT表的条目数量
  865.   .b4:
  866.          push ecx   
  867.          mov eax,[edi+256]                  ;该条目入口点的32位偏移地址
  868.          mov bx,[edi+260]                   ;该条目入口点的段选择子
  869.          mov cx,1_11_0_1100_000_00000B      ;特权级3的调用门(3以上的特权级才
  870.                                             ;允许访问),0个参数(因为用寄存器
  871.                                             ;传递参数,而没有用栈)
  872.          call flat_4gb_code_seg_sel:make_gate_descriptor
  873.          call flat_4gb_code_seg_sel:set_up_gdt_descriptor
  874.          mov [edi+260],cx                   ;将返回的门描述符选择子回填
  875.          add edi,salt_item_len              ;指向下一个C-SALT条目
  876.          pop ecx
  877.          loop .b4

  878.          ;对门进行测试
  879.          mov ebx,message_1
  880.          call far [salt_1+256]              ;通过门显示信息(偏移量将被忽略)

  881.          ;初始化创建程序管理器任务的任务控制块TCB
  882.          mov word [core_tcb+0x04],0xffff    ;任务状态:忙碌
  883.          mov dword [core_tcb+0x06],0x80100000   
  884.                                             ;内核虚拟空间的分配从这里开始。
  885.          mov word [core_tcb+0x0a],0xffff    ;登记LDT初始的界限到TCB中(未使用)
  886.          mov ecx,core_tcb
  887.          call append_to_tcb_link            ;将此TCB添加到TCB链中

  888.          ;为程序管理器的TSS分配内存空间
  889.          alloc_core_linear                  ;宏:在内核的虚拟地址空间分配内存

  890.          ;在程序管理器的TSS中设置必要的项目
  891.          mov word [ebx+0],0                 ;反向链=0
  892.          mov eax,cr3
  893.          mov dword [ebx+28],eax             ;登记CR3(PDBR)
  894.          mov word [ebx+96],0                ;没有LDT。处理器允许没有LDT的任务。
  895.          mov word [ebx+100],0               ;T=0
  896.          mov word [ebx+102],103             ;没有I/O位图。0特权级事实上不需要。
  897.          
  898.          ;创建程序管理器的TSS描述符,并安装到GDT中
  899.          mov eax,ebx                        ;TSS的起始线性地址
  900.          mov ebx,103                        ;段长度(界限)
  901.          mov ecx,0x00408900                 ;TSS描述符,特权级0
  902.          call flat_4gb_code_seg_sel:make_seg_descriptor
  903.          call flat_4gb_code_seg_sel:set_up_gdt_descriptor
  904.          mov [core_tcb+0x18],cx             ;登记内核任务的TSS选择子到其TCB

  905.          ;任务寄存器TR中的内容是任务存在的标志,该内容也决定了当前任务是谁。
  906.          ;下面的指令为当前正在执行的0特权级任务“程序管理器”后补手续(TSS)。
  907.          ltr cx

  908.          ;现在可认为“程序管理器”任务正执行中

  909.          ;创建用户任务的任务控制块
  910.          alloc_core_linear                  ;宏:在内核的虚拟地址空间分配内存
  911.          
  912.          mov word [ebx+0x04],0              ;任务状态:空闲
  913.          mov dword [ebx+0x06],0             ;用户任务局部空间的分配从0开始。
  914.          mov word [ebx+0x0a],0xffff         ;登记LDT初始的界限到TCB中
  915.       
  916.          push dword 50                      ;用户程序位于逻辑50扇区
  917.          push ebx                           ;压入任务控制块起始线性地址
  918.          call load_relocate_program
  919.          mov ecx,ebx         
  920.          call append_to_tcb_link            ;将此TCB添加到TCB链中

  921.          ;创建用户任务的任务控制块
  922.          alloc_core_linear                  ;宏:在内核的虚拟地址空间分配内存

  923.          mov word [ebx+0x04],0              ;任务状态:空闲
  924.          mov dword [ebx+0x06],0             ;用户任务局部空间的分配从0开始。
  925.          mov word [ebx+0x0a],0xffff         ;登记LDT初始的界限到TCB中

  926.          push dword 100                     ;用户程序位于逻辑100扇区
  927.          push ebx                           ;压入任务控制块起始线性地址
  928.          call load_relocate_program
  929.          mov ecx,ebx
  930.          call append_to_tcb_link            ;将此TCB添加到TCB链中

  931.   .core:
  932.          mov ebx,core_msg0
  933.          call flat_4gb_code_seg_sel:put_string
  934.          
  935.          ;这里可以编写回收已终止任务内存的代码
  936.          
  937.          jmp .core
  938.             
  939. core_code_end:

  940. ;-------------------------------------------------------------------------------
  941. SECTION core_trail
  942. ;-------------------------------------------------------------------------------
  943. core_end:
复制代码


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|4ameta

GMT+8, 2022-10-3 00:07 , Processed in 0.045102 second(s), 29 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表