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

4Ameta

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

Learn x86 protected mode assembly language-c16.asm

[复制链接]

26

主题

26

帖子

119

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
119
发表于 2022-9-12 21:15:36 | 显示全部楼层 |阅读模式
  1.          ;代码清单16-2
  2.          ;文件名:c16.asm
  3.          ;文件说明:用户程序
  4.          ;创建日期:2012-05-25 13:53   

  5.          program_length   dd program_end          ;程序总长度#0x00
  6.          entry_point      dd start                ;程序入口点#0x04
  7.          salt_position    dd salt_begin           ;SALT表起始偏移量#0x08
  8.          salt_items       dd (salt_end-salt_begin)/256 ;SALT条目数#0x0C

  9. ;-------------------------------------------------------------------------------

  10.          ;符号地址检索表
  11.          salt_begin:                                    

  12.          PrintString      db  '@PrintString'
  13.                      times 256-($-PrintString) db 0
  14.                      
  15.          TerminateProgram db  '@TerminateProgram'
  16.                      times 256-($-TerminateProgram) db 0
  17. ;-------------------------------------------------------------------------------

  18.          reserved  times 256*500 db 0            ;保留一个空白区,以演示分页

  19. ;-------------------------------------------------------------------------------
  20.          ReadDiskData     db  '@ReadDiskData'
  21.                      times 256-($-ReadDiskData) db 0
  22.          
  23.          PrintDwordAsHex  db  '@PrintDwordAsHexString'
  24.                      times 256-($-PrintDwordAsHex) db 0
  25.          
  26.          salt_end:

  27.          message_0        db  0x0d,0x0a,
  28.                           db  '  ............User task is running with '
  29.                           db  'paging enabled!............',0x0d,0x0a,0

  30.          space            db  0x20,0x20,0
  31.          
  32. ;-------------------------------------------------------------------------------
  33.       [bits 32]
  34. ;-------------------------------------------------------------------------------

  35. start:
  36.          
  37.          mov ebx,message_0
  38.          call far [PrintString]
  39.          
  40.          xor esi,esi
  41.          mov ecx,88
  42.   .b1:
  43.          mov ebx,space
  44.          call far [PrintString]
  45.          
  46.          mov edx,[esi*4]
  47.          call far [PrintDwordAsHex]
  48.          
  49.          inc esi
  50.          loop .b1
  51.         
  52.          call far [TerminateProgram]              ;退出,并将控制权返回到核心
  53.    
  54. ;-------------------------------------------------------------------------------
  55. program_end:
复制代码



  1.          ;代码清单16-1
  2.          ;文件名:c16_core.asm
  3.          ;文件说明:保护模式微型核心程序
  4.          ;创建日期:2012-06-20 00:05

  5.          ;以下常量定义部分。内核的大部分内容都应当固定
  6.          core_code_seg_sel     equ  0x38    ;内核代码段选择子
  7.          core_data_seg_sel     equ  0x30    ;内核数据段选择子
  8.          sys_routine_seg_sel   equ  0x28    ;系统公共例程代码段的选择子
  9.          video_ram_seg_sel     equ  0x20    ;视频显示缓冲区的段选择子
  10.          core_stack_seg_sel    equ  0x18    ;内核堆栈段选择子
  11.          mem_0_4_gb_seg_sel    equ  0x08    ;整个0-4GB内存的段的选择子

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

  15.          sys_routine_seg  dd section.sys_routine.start
  16.                                             ;系统公用例程段位置#04

  17.          core_data_seg    dd section.core_data.start
  18.                                             ;核心数据段位置#08

  19.          core_code_seg    dd section.core_code.start
  20.                                             ;核心代码段位置#0c


  21.          core_entry       dd start          ;核心代码段入口点#10
  22.                           dw core_code_seg_sel

  23. ;===============================================================================
  24.          [bits 32]
  25. ;===============================================================================
  26. SECTION sys_routine vstart=0                ;系统公共例程代码段
  27. ;-------------------------------------------------------------------------------
  28.          ;字符串显示例程
  29. put_string:                                 ;显示0终止的字符串并移动光标
  30.                                             ;输入:DS:EBX=串地址
  31.          push ecx
  32.   .getc:
  33.          mov cl,[ebx]
  34.          or cl,cl
  35.          jz .exit
  36.          call put_char
  37.          inc ebx
  38.          jmp .getc

  39.   .exit:
  40.          pop ecx
  41.          retf                               ;段间返回

  42. ;-------------------------------------------------------------------------------
  43. put_char:                                   ;在当前光标处显示一个字符,并推进
  44.                                             ;光标。仅用于段内调用
  45.                                             ;输入:CL=字符ASCII码
  46.          pushad

  47.          ;以下取当前光标位置
  48.          mov dx,0x3d4
  49.          mov al,0x0e
  50.          out dx,al
  51.          inc dx                             ;0x3d5
  52.          in al,dx                           ;高字
  53.          mov ah,al

  54.          dec dx                             ;0x3d4
  55.          mov al,0x0f
  56.          out dx,al
  57.          inc dx                             ;0x3d5
  58.          in al,dx                           ;低字
  59.          mov bx,ax                          ;BX=代表光标位置的16位数

  60.          cmp cl,0x0d                        ;回车符?
  61.          jnz .put_0a
  62.          mov ax,bx
  63.          mov bl,80
  64.          div bl
  65.          mul bl
  66.          mov bx,ax
  67.          jmp .set_cursor

  68.   .put_0a:
  69.          cmp cl,0x0a                        ;换行符?
  70.          jnz .put_other
  71.          add bx,80
  72.          jmp .roll_screen

  73.   .put_other:                               ;正常显示字符
  74.          push es
  75.          mov eax,video_ram_seg_sel          ;0x800b8000段的选择子
  76.          mov es,eax
  77.          shl bx,1
  78.          mov [es:bx],cl
  79.          pop es

  80.          ;以下将光标位置推进一个字符
  81.          shr bx,1
  82.          inc bx

  83.   .roll_screen:
  84.          cmp bx,2000                        ;光标超出屏幕?滚屏
  85.          jl .set_cursor

  86.          push ds
  87.          push es
  88.          mov eax,video_ram_seg_sel
  89.          mov ds,eax
  90.          mov es,eax
  91.          cld
  92.          mov esi,0xa0                       ;小心!32位模式下movsb/w/d
  93.          mov edi,0x00                       ;使用的是esi/edi/ecx
  94.          mov ecx,1920
  95.          rep movsd
  96.          mov bx,3840                        ;清除屏幕最底一行
  97.          mov ecx,80                         ;32位程序应该使用ECX
  98.   .cls:
  99.          mov word[es:bx],0x0720
  100.          add bx,2
  101.          loop .cls

  102.          pop es
  103.          pop ds

  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.          popad
  119.          
  120.          ret                                

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

  135.          inc dx                             ;0x1f3
  136.          pop eax
  137.          out dx,al                          ;LBA地址7~0

  138.          inc dx                             ;0x1f4
  139.          mov cl,8
  140.          shr eax,cl
  141.          out dx,al                          ;LBA地址15~8

  142.          inc dx                             ;0x1f5
  143.          shr eax,cl
  144.          out dx,al                          ;LBA地址23~16

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

  149.          inc dx                             ;0x1f7
  150.          mov al,0x20                        ;读命令
  151.          out dx,al

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

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

  164.          pop edx
  165.          pop ecx
  166.          pop eax
  167.       
  168.          retf                               ;段间返回

  169. ;-------------------------------------------------------------------------------
  170. ;汇编语言程序是极难一次成功,而且调试非常困难。这个例程可以提供帮助
  171. put_hex_dword:                              ;在当前光标处以十六进制形式显示
  172.                                             ;一个双字并推进光标
  173.                                             ;输入:EDX=要转换并显示的数字
  174.                                             ;输出:无
  175.          pushad
  176.          push ds
  177.       
  178.          mov ax,core_data_seg_sel           ;切换到核心数据段
  179.          mov ds,ax
  180.       
  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.          pop ds
  197.          popad
  198.          
  199.          retf
  200.       
  201. ;-------------------------------------------------------------------------------
  202. set_up_gdt_descriptor:                      ;在GDT内安装一个新的描述符
  203.                                             ;输入:EDX:EAX=描述符
  204.                                             ;输出:CX=描述符的选择子
  205.          push eax
  206.          push ebx
  207.          push edx

  208.          push ds
  209.          push es

  210.          mov ebx,core_data_seg_sel          ;切换到核心数据段
  211.          mov ds,ebx

  212.          sgdt [pgdt]                        ;以便开始处理GDT

  213.          mov ebx,mem_0_4_gb_seg_sel
  214.          mov es,ebx

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

  218.          mov [es:ebx],eax
  219.          mov [es:ebx+4],edx

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

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

  222.          mov ax,[pgdt]                      ;得到GDT界限值
  223.          xor dx,dx
  224.          mov bx,8
  225.          div bx                             ;除以8,去掉余数
  226.          mov cx,ax
  227.          shl cx,3                           ;将索引号移到正确位置

  228.          pop es
  229.          pop ds

  230.          pop edx
  231.          pop ebx
  232.          pop eax

  233.          retf
  234. ;-------------------------------------------------------------------------------
  235. make_seg_descriptor:                        ;构造存储器和系统的段描述符
  236.                                             ;输入:EAX=线性基地址
  237.                                             ;      EBX=段界限
  238.                                             ;      ECX=属性。各属性位都在原始
  239.                                             ;          位置,无关的位清零
  240.                                             ;返回:EDX:EAX=描述符
  241.          mov edx,eax
  242.          shl eax,16
  243.          or ax,bx                           ;描述符前32位(EAX)构造完毕

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

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

  249.          or edx,ecx                         ;装配属性

  250.          retf

  251. ;-------------------------------------------------------------------------------
  252. make_gate_descriptor:                       ;构造门的描述符(调用门等)
  253.                                             ;输入:EAX=门代码在段内偏移地址
  254.                                             ;       BX=门代码所在段的选择子
  255.                                             ;       CX=段类型及属性等(各属
  256.                                             ;          性位都在原始位置)
  257.                                             ;返回:EDX:EAX=完整的描述符
  258.          push ebx
  259.          push ecx
  260.       
  261.          mov edx,eax
  262.          and edx,0xffff0000                 ;得到偏移地址高16位
  263.          or dx,cx                           ;组装属性部分到EDX
  264.       
  265.          and eax,0x0000ffff                 ;得到偏移地址低16位
  266.          shl ebx,16                          
  267.          or eax,ebx                         ;组装段选择子部分
  268.       
  269.          pop ecx
  270.          pop ebx
  271.       
  272.          retf                                   
  273.                              
  274. ;-------------------------------------------------------------------------------
  275. allocate_a_4k_page:                         ;分配一个4KB的页
  276.                                             ;输入:无
  277.                                             ;输出:EAX=页的物理地址
  278.          push ebx
  279.          push ecx
  280.          push edx
  281.          push ds
  282.          
  283.          mov eax,core_data_seg_sel
  284.          mov ds,eax
  285.          
  286.          xor eax,eax
  287.   .b1:
  288.          bts [page_bit_map],eax
  289.          jnc .b2
  290.          inc eax
  291.          cmp eax,page_map_len*8
  292.          jl .b1
  293.          
  294.          mov ebx,message_3
  295.          call sys_routine_seg_sel:put_string
  296.          hlt                                ;没有可以分配的页,停机
  297.          
  298.   .b2:
  299.          shl eax,12                         ;乘以4096(0x1000)
  300.          
  301.          pop ds
  302.          pop edx
  303.          pop ecx
  304.          pop ebx
  305.          
  306.          ret
  307.          
  308. ;-------------------------------------------------------------------------------
  309. alloc_inst_a_page:                          ;分配一个页,并安装在当前活动的
  310.                                             ;层级分页结构中
  311.                                             ;输入:EBX=页的线性地址
  312.          push eax
  313.          push ebx
  314.          push esi
  315.          push ds
  316.          
  317.          mov eax,mem_0_4_gb_seg_sel
  318.          mov ds,eax
  319.          
  320.          ;检查该线性地址所对应的页表是否存在
  321.          mov esi,ebx
  322.          and esi,0xffc00000
  323.          shr esi,20                         ;得到页目录索引,并乘以4
  324.          or esi,0xfffff000                  ;页目录自身的线性地址+表内偏移

  325.          test dword [esi],0x00000001        ;P位是否为“1”。检查该线性地址是
  326.          jnz .b1                            ;否已经有对应的页表
  327.          
  328.          ;创建该线性地址所对应的页表
  329.          call allocate_a_4k_page            ;分配一个页做为页表
  330.          or eax,0x00000007
  331.          mov [esi],eax                      ;在页目录中登记该页表
  332.          
  333.   .b1:
  334.          ;开始访问该线性地址所对应的页表
  335.          mov esi,ebx
  336.          shr esi,10
  337.          and esi,0x003ff000                 ;或者0xfffff000,因高10位是零
  338.          or esi,0xffc00000                  ;得到该页表的线性地址
  339.          
  340.          ;得到该线性地址在页表内的对应条目(页表项)
  341.          and ebx,0x003ff000
  342.          shr ebx,10                         ;相当于右移12位,再乘以4
  343.          or esi,ebx                         ;页表项的线性地址
  344.          call allocate_a_4k_page            ;分配一个页,这才是要安装的页
  345.          or eax,0x00000007
  346.          mov [esi],eax
  347.          
  348.          pop ds
  349.          pop esi
  350.          pop ebx
  351.          pop eax
  352.          
  353.          retf  

  354. ;-------------------------------------------------------------------------------
  355. create_copy_cur_pdir:                       ;创建新页目录,并复制当前页目录内容
  356.                                             ;输入:无
  357.                                             ;输出:EAX=新页目录的物理地址
  358.          push ds
  359.          push es
  360.          push esi
  361.          push edi
  362.          push ebx
  363.          push ecx
  364.          
  365.          mov ebx,mem_0_4_gb_seg_sel
  366.          mov ds,ebx
  367.          mov es,ebx
  368.          
  369.          call allocate_a_4k_page            
  370.          mov ebx,eax
  371.          or ebx,0x00000007
  372.          mov [0xfffffff8],ebx
  373.          
  374.          mov esi,0xfffff000                 ;ESI->当前页目录的线性地址
  375.          mov edi,0xffffe000                 ;EDI->新页目录的线性地址
  376.          mov ecx,1024                       ;ECX=要复制的目录项数
  377.          cld
  378.          repe movsd
  379.          
  380.          pop ecx
  381.          pop ebx
  382.          pop edi
  383.          pop esi
  384.          pop es
  385.          pop ds
  386.          
  387.          retf
  388.          
  389. ;-------------------------------------------------------------------------------
  390. terminate_current_task:                     ;终止当前任务
  391.                                             ;注意,执行此例程时,当前任务仍在
  392.                                             ;运行中。此例程其实也是当前任务的
  393.                                             ;一部分
  394.          mov eax,core_data_seg_sel
  395.          mov ds,eax

  396.          pushfd
  397.          pop edx

  398.          test dx,0100_0000_0000_0000B       ;测试NT位
  399.          jnz .b1                            ;当前任务是嵌套的,到.b1执行iretd
  400.          jmp far [program_man_tss]          ;程序管理器任务
  401.   .b1:
  402.          iretd

  403. sys_routine_end:

  404. ;===============================================================================
  405. SECTION core_data vstart=0                  ;系统核心的数据段
  406. ;-------------------------------------------------------------------------------
  407.          pgdt             dw  0             ;用于设置和修改GDT
  408.                           dd  0

  409.          page_bit_map     db  0xff,0xff,0xff,0xff,0xff,0x55,0x55,0xff
  410.                           db  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
  411.                           db  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
  412.                           db  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
  413.                           db  0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55
  414.                           db  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  415.                           db  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  416.                           db  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  417.          page_map_len     equ $-page_bit_map
  418.                           
  419.          ;符号地址检索表
  420.          salt:
  421.          salt_1           db  '@PrintString'
  422.                      times 256-($-salt_1) db 0
  423.                           dd  put_string
  424.                           dw  sys_routine_seg_sel

  425.          salt_2           db  '@ReadDiskData'
  426.                      times 256-($-salt_2) db 0
  427.                           dd  read_hard_disk_0
  428.                           dw  sys_routine_seg_sel

  429.          salt_3           db  '@PrintDwordAsHexString'
  430.                      times 256-($-salt_3) db 0
  431.                           dd  put_hex_dword
  432.                           dw  sys_routine_seg_sel

  433.          salt_4           db  '@TerminateProgram'
  434.                      times 256-($-salt_4) db 0
  435.                           dd  terminate_current_task
  436.                           dw  sys_routine_seg_sel

  437.          salt_item_len   equ $-salt_4
  438.          salt_items      equ ($-salt)/salt_item_len

  439.          message_0        db  '  Working in system core,protect mode.'
  440.                           db  0x0d,0x0a,0

  441.          message_1        db  '  Paging is enabled.System core is mapped to'
  442.                           db  ' address 0x80000000.',0x0d,0x0a,0
  443.          
  444.          message_2        db  0x0d,0x0a
  445.                           db  '  System wide CALL-GATE mounted.',0x0d,0x0a,0
  446.          
  447.          message_3        db  '********No more pages********',0
  448.          
  449.          message_4        db  0x0d,0x0a,'  Task switching...@_@',0x0d,0x0a,0
  450.          
  451.          message_5        db  0x0d,0x0a,'  Processor HALT.',0
  452.          
  453.         
  454.          bin_hex          db '0123456789ABCDEF'
  455.                                             ;put_hex_dword子过程用的查找表

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

  457.          cpu_brnd0        db 0x0d,0x0a,'  ',0
  458.          cpu_brand  times 52 db 0
  459.          cpu_brnd1        db 0x0d,0x0a,0x0d,0x0a,0

  460.          ;任务控制块链
  461.          tcb_chain        dd  0

  462.          ;内核信息
  463.          core_next_laddr  dd  0x80100000    ;内核空间中下一个可分配的线性地址        
  464.          program_man_tss  dd  0             ;程序管理器的TSS描述符选择子
  465.                           dw  0

  466. core_data_end:
  467.                
  468. ;===============================================================================
  469. SECTION core_code vstart=0
  470. ;-------------------------------------------------------------------------------
  471. fill_descriptor_in_ldt:                     ;在LDT内安装一个新的描述符
  472.                                             ;输入:EDX:EAX=描述符
  473.                                             ;          EBX=TCB基地址
  474.                                             ;输出:CX=描述符的选择子
  475.          push eax
  476.          push edx
  477.          push edi
  478.          push ds

  479.          mov ecx,mem_0_4_gb_seg_sel
  480.          mov ds,ecx

  481.          mov edi,[ebx+0x0c]                 ;获得LDT基地址
  482.          
  483.          xor ecx,ecx
  484.          mov cx,[ebx+0x0a]                  ;获得LDT界限
  485.          inc cx                             ;LDT的总字节数,即新描述符偏移地址
  486.          
  487.          mov [edi+ecx+0x00],eax
  488.          mov [edi+ecx+0x04],edx             ;安装描述符

  489.          add cx,8                           
  490.          dec cx                             ;得到新的LDT界限值

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

  492.          mov ax,cx
  493.          xor dx,dx
  494.          mov cx,8
  495.          div cx
  496.          
  497.          mov cx,ax
  498.          shl cx,3                           ;左移3位,并且
  499.          or cx,0000_0000_0000_0100B         ;使TI位=1,指向LDT,最后使RPL=00

  500.          pop ds
  501.          pop edi
  502.          pop edx
  503.          pop eax
  504.      
  505.          ret
  506.       
  507. ;-------------------------------------------------------------------------------
  508. load_relocate_program:                      ;加载并重定位用户程序
  509.                                             ;输入: PUSH 逻辑扇区号
  510.                                             ;      PUSH 任务控制块基地址
  511.                                             ;输出:无
  512.          pushad
  513.       
  514.          push ds
  515.          push es
  516.       
  517.          mov ebp,esp                        ;为访问通过堆栈传递的参数做准备
  518.       
  519.          mov ecx,mem_0_4_gb_seg_sel
  520.          mov es,ecx
  521.       
  522.          ;清空当前页目录的前半部分(对应低2GB的局部地址空间)
  523.          mov ebx,0xfffff000
  524.          xor esi,esi
  525.   .b1:
  526.          mov dword [es:ebx+esi*4],0x00000000
  527.          inc esi
  528.          cmp esi,512
  529.          jl .b1
  530.          
  531.          ;以下开始分配内存并加载用户程序
  532.          mov eax,core_data_seg_sel
  533.          mov ds,eax                         ;切换DS到内核数据段

  534.          mov eax,[ebp+12*4]                 ;从堆栈中取出用户程序起始扇区号
  535.          mov ebx,core_buf                   ;读取程序头部数据
  536.          call sys_routine_seg_sel:read_hard_disk_0

  537.          ;以下判断整个程序有多大
  538.          mov eax,[core_buf]                 ;程序尺寸
  539.          mov ebx,eax
  540.          and ebx,0xfffff000                 ;使之4KB对齐
  541.          add ebx,0x1000                        
  542.          test eax,0x00000fff                ;程序的大小正好是4KB的倍数吗?
  543.          cmovnz eax,ebx                     ;不是。使用凑整的结果

  544.          mov ecx,eax
  545.          shr ecx,12                         ;程序占用的总4KB页数
  546.          
  547.          mov eax,mem_0_4_gb_seg_sel         ;切换DS到0-4GB的段
  548.          mov ds,eax

  549.          mov eax,[ebp+12*4]                 ;起始扇区号
  550.          mov esi,[ebp+11*4]                 ;从堆栈中取得TCB的基地址
  551.   .b2:
  552.          mov ebx,[es:esi+0x06]              ;取得可用的线性地址
  553.          add dword [es:esi+0x06],0x1000
  554.          call sys_routine_seg_sel:alloc_inst_a_page

  555.          push ecx
  556.          mov ecx,8
  557.   .b3:
  558.          call sys_routine_seg_sel:read_hard_disk_0
  559.          inc eax
  560.          loop .b3

  561.          pop ecx
  562.          loop .b2

  563.          ;在内核地址空间内创建用户任务的TSS
  564.          mov eax,core_data_seg_sel          ;切换DS到内核数据段
  565.          mov ds,eax

  566.          mov ebx,[core_next_laddr]          ;用户任务的TSS必须在全局空间上分配
  567.          call sys_routine_seg_sel:alloc_inst_a_page
  568.          add dword [core_next_laddr],4096
  569.          
  570.          mov [es:esi+0x14],ebx              ;在TCB中填写TSS的线性地址
  571.          mov word [es:esi+0x12],103         ;在TCB中填写TSS的界限值
  572.          
  573.          ;在用户任务的局部地址空间内创建LDT
  574.          mov ebx,[es:esi+0x06]              ;从TCB中取得可用的线性地址
  575.          add dword [es:esi+0x06],0x1000
  576.          call sys_routine_seg_sel:alloc_inst_a_page
  577.          mov [es:esi+0x0c],ebx              ;填写LDT线性地址到TCB中

  578.          ;建立程序代码段描述符
  579.          mov eax,0x00000000
  580.          mov ebx,0x000fffff                 
  581.          mov ecx,0x00c0f800                 ;4KB粒度的代码段描述符,特权级3
  582.          call sys_routine_seg_sel:make_seg_descriptor
  583.          mov ebx,esi                        ;TCB的基地址
  584.          call fill_descriptor_in_ldt
  585.          or cx,0000_0000_0000_0011B         ;设置选择子的特权级为3
  586.          
  587.          mov ebx,[es:esi+0x14]              ;从TCB中获取TSS的线性地址
  588.          mov [es:ebx+76],cx                 ;填写TSS的CS域

  589.          ;建立程序数据段描述符
  590.          mov eax,0x00000000
  591.          mov ebx,0x000fffff                 
  592.          mov ecx,0x00c0f200                 ;4KB粒度的数据段描述符,特权级3
  593.          call sys_routine_seg_sel:make_seg_descriptor
  594.          mov ebx,esi                        ;TCB的基地址
  595.          call fill_descriptor_in_ldt
  596.          or cx,0000_0000_0000_0011B         ;设置选择子的特权级为3
  597.          
  598.          mov ebx,[es:esi+0x14]              ;从TCB中获取TSS的线性地址
  599.          mov [es:ebx+84],cx                 ;填写TSS的DS域
  600.          mov [es:ebx+72],cx                 ;填写TSS的ES域
  601.          mov [es:ebx+88],cx                 ;填写TSS的FS域
  602.          mov [es:ebx+92],cx                 ;填写TSS的GS域
  603.          
  604.          ;将数据段作为用户任务的3特权级固有堆栈
  605.          mov ebx,[es:esi+0x06]              ;从TCB中取得可用的线性地址
  606.          add dword [es:esi+0x06],0x1000
  607.          call sys_routine_seg_sel:alloc_inst_a_page
  608.          
  609.          mov ebx,[es:esi+0x14]              ;从TCB中获取TSS的线性地址
  610.          mov [es:ebx+80],cx                 ;填写TSS的SS域
  611.          mov edx,[es:esi+0x06]              ;堆栈的高端线性地址
  612.          mov [es:ebx+56],edx                ;填写TSS的ESP域

  613.          ;在用户任务的局部地址空间内创建0特权级堆栈
  614.          mov ebx,[es:esi+0x06]              ;从TCB中取得可用的线性地址
  615.          add dword [es:esi+0x06],0x1000
  616.          call sys_routine_seg_sel:alloc_inst_a_page

  617.          mov eax,0x00000000
  618.          mov ebx,0x000fffff
  619.          mov ecx,0x00c09200                 ;4KB粒度的堆栈段描述符,特权级0
  620.          call sys_routine_seg_sel:make_seg_descriptor
  621.          mov ebx,esi                        ;TCB的基地址
  622.          call fill_descriptor_in_ldt
  623.          or cx,0000_0000_0000_0000B         ;设置选择子的特权级为0

  624.          mov ebx,[es:esi+0x14]              ;从TCB中获取TSS的线性地址
  625.          mov [es:ebx+8],cx                  ;填写TSS的SS0域
  626.          mov edx,[es:esi+0x06]              ;堆栈的高端线性地址
  627.          mov [es:ebx+4],edx                 ;填写TSS的ESP0域

  628.          ;在用户任务的局部地址空间内创建1特权级堆栈
  629.          mov ebx,[es:esi+0x06]              ;从TCB中取得可用的线性地址
  630.          add dword [es:esi+0x06],0x1000
  631.          call sys_routine_seg_sel:alloc_inst_a_page

  632.          mov eax,0x00000000
  633.          mov ebx,0x000fffff
  634.          mov ecx,0x00c0b200                 ;4KB粒度的堆栈段描述符,特权级1
  635.          call sys_routine_seg_sel:make_seg_descriptor
  636.          mov ebx,esi                        ;TCB的基地址
  637.          call fill_descriptor_in_ldt
  638.          or cx,0000_0000_0000_0001B         ;设置选择子的特权级为1

  639.          mov ebx,[es:esi+0x14]              ;从TCB中获取TSS的线性地址
  640.          mov [es:ebx+16],cx                 ;填写TSS的SS1域
  641.          mov edx,[es:esi+0x06]              ;堆栈的高端线性地址
  642.          mov [es:ebx+12],edx                ;填写TSS的ESP1域

  643.          ;在用户任务的局部地址空间内创建2特权级堆栈
  644.          mov ebx,[es:esi+0x06]              ;从TCB中取得可用的线性地址
  645.          add dword [es:esi+0x06],0x1000
  646.          call sys_routine_seg_sel:alloc_inst_a_page

  647.          mov eax,0x00000000
  648.          mov ebx,0x000fffff
  649.          mov ecx,0x00c0d200                 ;4KB粒度的堆栈段描述符,特权级2
  650.          call sys_routine_seg_sel:make_seg_descriptor
  651.          mov ebx,esi                        ;TCB的基地址
  652.          call fill_descriptor_in_ldt
  653.          or cx,0000_0000_0000_0010B         ;设置选择子的特权级为2

  654.          mov ebx,[es:esi+0x14]              ;从TCB中获取TSS的线性地址
  655.          mov [es:ebx+24],cx                 ;填写TSS的SS2域
  656.          mov edx,[es:esi+0x06]              ;堆栈的高端线性地址
  657.          mov [es:ebx+20],edx                ;填写TSS的ESP2域


  658.          ;重定位SALT
  659.          mov eax,mem_0_4_gb_seg_sel         ;访问任务的4GB虚拟地址空间时用
  660.          mov es,eax                        
  661.                                                    
  662.          mov eax,core_data_seg_sel
  663.          mov ds,eax
  664.       
  665.          cld

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

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

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

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

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

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

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

  728.          ;创建用户任务的页目录
  729.          ;注意!页的分配和使用是由页位图决定的,可以不占用线性地址空间
  730.          call sys_routine_seg_sel:create_copy_cur_pdir
  731.          mov ebx,[es:esi+0x14]              ;从TCB中获取TSS的线性地址
  732.          mov dword [es:ebx+28],eax          ;填写TSS的CR3(PDBR)域
  733.                   
  734.          pop es                             ;恢复到调用此过程前的es段
  735.          pop ds                             ;恢复到调用此过程前的ds段
  736.       
  737.          popad
  738.       
  739.          ret 8                              ;丢弃调用本过程前压入的参数
  740.       
  741. ;-------------------------------------------------------------------------------
  742. append_to_tcb_link:                         ;在TCB链上追加任务控制块
  743.                                             ;输入:ECX=TCB线性基地址
  744.          push eax
  745.          push edx
  746.          push ds
  747.          push es
  748.          
  749.          mov eax,core_data_seg_sel          ;令DS指向内核数据段
  750.          mov ds,eax
  751.          mov eax,mem_0_4_gb_seg_sel         ;令ES指向0..4GB段
  752.          mov es,eax
  753.          
  754.          mov dword [es: ecx+0x00],0         ;当前TCB指针域清零,以指示这是最
  755.                                             ;后一个TCB
  756.                                              
  757.          mov eax,[tcb_chain]                ;TCB表头指针
  758.          or eax,eax                         ;链表为空?
  759.          jz .notcb
  760.          
  761.   .searc:
  762.          mov edx,eax
  763.          mov eax,[es: edx+0x00]
  764.          or eax,eax               
  765.          jnz .searc
  766.          
  767.          mov [es: edx+0x00],ecx
  768.          jmp .retpc
  769.          
  770.   .notcb:      
  771.          mov [tcb_chain],ecx                ;若为空表,直接令表头指针指向TCB
  772.          
  773.   .retpc:
  774.          pop es
  775.          pop ds
  776.          pop edx
  777.          pop eax
  778.          
  779.          ret
  780.          
  781. ;-------------------------------------------------------------------------------
  782. start:
  783.          mov ecx,core_data_seg_sel          ;令DS指向核心数据段
  784.          mov ds,ecx

  785.          mov ecx,mem_0_4_gb_seg_sel         ;令ES指向4GB数据段
  786.          mov es,ecx

  787.          mov ebx,message_0                    
  788.          call sys_routine_seg_sel:put_string
  789.                                          
  790.          ;显示处理器品牌信息
  791.          mov eax,0x80000002
  792.          cpuid
  793.          mov [cpu_brand + 0x00],eax
  794.          mov [cpu_brand + 0x04],ebx
  795.          mov [cpu_brand + 0x08],ecx
  796.          mov [cpu_brand + 0x0c],edx
  797.       
  798.          mov eax,0x80000003
  799.          cpuid
  800.          mov [cpu_brand + 0x10],eax
  801.          mov [cpu_brand + 0x14],ebx
  802.          mov [cpu_brand + 0x18],ecx
  803.          mov [cpu_brand + 0x1c],edx

  804.          mov eax,0x80000004
  805.          cpuid
  806.          mov [cpu_brand + 0x20],eax
  807.          mov [cpu_brand + 0x24],ebx
  808.          mov [cpu_brand + 0x28],ecx
  809.          mov [cpu_brand + 0x2c],edx

  810.          mov ebx,cpu_brnd0                  ;显示处理器品牌信息
  811.          call sys_routine_seg_sel:put_string
  812.          mov ebx,cpu_brand
  813.          call sys_routine_seg_sel:put_string
  814.          mov ebx,cpu_brnd1
  815.          call sys_routine_seg_sel:put_string

  816.          ;准备打开分页机制
  817.          
  818.          ;创建系统内核的页目录表PDT
  819.          ;页目录表清零
  820.          mov ecx,1024                       ;1024个目录项
  821.          mov ebx,0x00020000                 ;页目录的物理地址
  822.          xor esi,esi
  823.   .b1:
  824.          mov dword [es:ebx+esi],0x00000000  ;页目录表项清零
  825.          add esi,4
  826.          loop .b1
  827.          
  828.          ;在页目录内创建指向页目录自己的目录项
  829.          mov dword [es:ebx+4092],0x00020003

  830.          ;在页目录内创建与线性地址0x00000000对应的目录项
  831.          mov dword [es:ebx+0],0x00021003    ;写入目录项(页表的物理地址和属性)      

  832.          ;创建与上面那个目录项相对应的页表,初始化页表项
  833.          mov ebx,0x00021000                 ;页表的物理地址
  834.          xor eax,eax                        ;起始页的物理地址
  835.          xor esi,esi
  836.   .b2:      
  837.          mov edx,eax
  838.          or edx,0x00000003                                                      
  839.          mov [es:ebx+esi*4],edx             ;登记页的物理地址
  840.          add eax,0x1000                     ;下一个相邻页的物理地址
  841.          inc esi
  842.          cmp esi,256                        ;仅低端1MB内存对应的页才是有效的
  843.          jl .b2
  844.          
  845.   .b3:                                      ;其余的页表项置为无效
  846.          mov dword [es:ebx+esi*4],0x00000000  
  847.          inc esi
  848.          cmp esi,1024
  849.          jl .b3

  850.          ;令CR3寄存器指向页目录,并正式开启页功能
  851.          mov eax,0x00020000                 ;PCD=PWT=0
  852.          mov cr3,eax

  853.          mov eax,cr0
  854.          or eax,0x80000000
  855.          mov cr0,eax                        ;开启分页机制

  856.          ;在页目录内创建与线性地址0x80000000对应的目录项
  857.          mov ebx,0xfffff000                 ;页目录自己的线性地址
  858.          mov esi,0x80000000                 ;映射的起始地址
  859.          shr esi,22                         ;线性地址的高10位是目录索引
  860.          shl esi,2
  861.          mov dword [es:ebx+esi],0x00021003  ;写入目录项(页表的物理地址和属性)
  862.                                             ;目标单元的线性地址为0xFFFFF200
  863.                                              
  864.          ;将GDT中的段描述符映射到线性地址0x80000000
  865.          sgdt [pgdt]
  866.          
  867.          mov ebx,[pgdt+2]
  868.          
  869.          or dword [es:ebx+0x10+4],0x80000000
  870.          or dword [es:ebx+0x18+4],0x80000000
  871.          or dword [es:ebx+0x20+4],0x80000000
  872.          or dword [es:ebx+0x28+4],0x80000000
  873.          or dword [es:ebx+0x30+4],0x80000000
  874.          or dword [es:ebx+0x38+4],0x80000000
  875.          
  876.          add dword [pgdt+2],0x80000000      ;GDTR也用的是线性地址
  877.          
  878.          lgdt [pgdt]
  879.         
  880.          jmp core_code_seg_sel:flush        ;刷新段寄存器CS,启用高端线性地址
  881.                                              
  882.    flush:
  883.          mov eax,core_stack_seg_sel
  884.          mov ss,eax
  885.          
  886.          mov eax,core_data_seg_sel
  887.          mov ds,eax
  888.          
  889.          mov ebx,message_1
  890.          call sys_routine_seg_sel:put_string

  891.          ;以下开始安装为整个系统服务的调用门。特权级之间的控制转移必须使用门
  892.          mov edi,salt                       ;C-SALT表的起始位置
  893.          mov ecx,salt_items                 ;C-SALT表的条目数量
  894.   .b4:
  895.          push ecx   
  896.          mov eax,[edi+256]                  ;该条目入口点的32位偏移地址
  897.          mov bx,[edi+260]                   ;该条目入口点的段选择子
  898.          mov cx,1_11_0_1100_000_00000B      ;特权级3的调用门(3以上的特权级才
  899.                                             ;允许访问),0个参数(因为用寄存器
  900.                                             ;传递参数,而没有用栈)
  901.          call sys_routine_seg_sel:make_gate_descriptor
  902.          call sys_routine_seg_sel:set_up_gdt_descriptor
  903.          mov [edi+260],cx                   ;将返回的门描述符选择子回填
  904.          add edi,salt_item_len              ;指向下一个C-SALT条目
  905.          pop ecx
  906.          loop .b4

  907.          ;对门进行测试
  908.          mov ebx,message_2
  909.          call far [salt_1+256]              ;通过门显示信息(偏移量将被忽略)
  910.       
  911.          ;为程序管理器的TSS分配内存空间
  912.          mov ebx,[core_next_laddr]
  913.          call sys_routine_seg_sel:alloc_inst_a_page
  914.          add dword [core_next_laddr],4096

  915.          ;在程序管理器的TSS中设置必要的项目
  916.          mov word [es:ebx+0],0              ;反向链=0

  917.          mov eax,cr3
  918.          mov dword [es:ebx+28],eax          ;登记CR3(PDBR)

  919.          mov word [es:ebx+96],0             ;没有LDT。处理器允许没有LDT的任务。
  920.          mov word [es:ebx+100],0            ;T=0
  921.          mov word [es:ebx+102],103          ;没有I/O位图。0特权级事实上不需要。
  922.          
  923.          ;创建程序管理器的TSS描述符,并安装到GDT中
  924.          mov eax,ebx                        ;TSS的起始线性地址
  925.          mov ebx,103                        ;段长度(界限)
  926.          mov ecx,0x00408900                 ;TSS描述符,特权级0
  927.          call sys_routine_seg_sel:make_seg_descriptor
  928.          call sys_routine_seg_sel:set_up_gdt_descriptor
  929.          mov [program_man_tss+4],cx         ;保存程序管理器的TSS描述符选择子

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

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

  934.          ;创建用户任务的任务控制块
  935.          mov ebx,[core_next_laddr]
  936.          call sys_routine_seg_sel:alloc_inst_a_page
  937.          add dword [core_next_laddr],4096
  938.          
  939.          mov dword [es:ebx+0x06],0          ;用户任务局部空间的分配从0开始。
  940.          mov word [es:ebx+0x0a],0xffff      ;登记LDT初始的界限到TCB中
  941.          mov ecx,ebx
  942.          call append_to_tcb_link            ;将此TCB添加到TCB链中
  943.       
  944.          push dword 50                      ;用户程序位于逻辑50扇区
  945.          push ecx                           ;压入任务控制块起始线性地址
  946.       
  947.          call load_relocate_program         
  948.       
  949.          mov ebx,message_4
  950.          call sys_routine_seg_sel:put_string
  951.          
  952.          call far [es:ecx+0x14]             ;执行任务切换。
  953.          
  954.          mov ebx,message_5
  955.          call sys_routine_seg_sel:put_string

  956.          hlt
  957.             
  958. core_code_end:

  959. ;-------------------------------------------------------------------------------
  960. SECTION core_trail
  961. ;-------------------------------------------------------------------------------
  962. core_end:
复制代码
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2022-10-3 00:09 , Processed in 0.035723 second(s), 17 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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