• 【日拱一卒行而不辍20220919】自制操作系统


    打开A20地址线-初次运行

    参照《ORANGE’S:一个操作系统的实现》

    以下是pm.inc

    1. 1 DA_32 EQU 4000h ; 32 位段
    2. 2
    3. 3 DA_DPL0 EQU 00h ; DPL = 0
    4. 4 DA_DPL1 EQU 20h ; DPL = 1
    5. 5 DA_DPL2 EQU 40h ; DPL = 2
    6. 6 DA_DPL3 EQU 60h ; DPL = 3
    7. 7
    8. 8 ; 存储段描述符类型
    9. 9 DA_DR EQU 90h ; 存在的只读数据段类型值
    10. 10 DA_DRW EQU 92h ; 存在的可读写数据段属性值
    11. 11 DA_DRWA EQU 93h ; 存在的已访问可读写数据段类型值
    12. 12 DA_C EQU 98h ; 存在的只执行代码段属性值
    13. 13 DA_CR EQU 9Ah ; 存在的可执行可读代码段属性值
    14. 14 DA_CCO EQU 9Ch ; 存在的只执行一致代码段属性值
    15. 15 DA_CCOR EQU 9Eh ; 存在的可执行可读一致代码段属性值
    16. 16
    17. 17 ; 系统段描述符类型
    18. 18 DA_LDT EQU 82h ; 局部描述符表段类型值
    19. 19 DA_TaskGate EQU 85h ; 任务门类型值
    20. 20 DA_386TSS EQU 89h ; 可用 386 任务状态段类型值
    21. 21 DA_386CGate EQU 8Ch ; 386 调用门类型值
    22. 22 DA_386IGate EQU 8Eh ; 386 中断门类型值
    23. 23 DA_386TGate EQU 8Fh ; 386 陷阱门类型值
    24. 24
    25. 25 SA_RPL0 EQU 0 ; ┓
    26. 26 SA_RPL1 EQU 1 ; ┣ RPL
    27. 27 SA_RPL2 EQU 2 ; ┃
    28. 28 SA_RPL3 EQU 3 ; ┛
    29. 29
    30. 30 SA_TIG EQU 0 ; ┓TI
    31. 31 SA_TIL EQU 4 ; ┛
    32. 32
    33. 33 %macro Descriptor 3
    34. 34 dw %2 & 0FFFFh ; 段界限1
    35. 35 dw %1 & 0FFFFh ; 段基址1
    36. 36 db (%1 >> 16) & 0FFh ; 段基址2
    37. 37 dw ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh) ; 属性1 + 段界限2 + 属性2
    38. 38 db (%1 >> 24) & 0FFh ; 段基址3
    39. 39 %endmacro ; 共 8 字节
    40. 40 ;
    41. 41 ; 门
    42. 42 ; usage: Gate Selector, Offset, DCount, Attr
    43. 43 ; Selector: dw
    44. 44 ; Offset: dd
    45. 45 ; DCount: db
    46. 46 ; Attr: db
    47. 47 %macro Gate 4
    48. 48 dw (%2 & 0FFFFh) ; 偏移1
    49. 49 dw %1 ; 选择子
    50. 50 dw (%3 & 1Fh) | ((%4 << 8) & 0FF00h) ; 属性
    51. 51 dw ((%2 >> 16) & 0FFFFh) ; 偏移2
    52. 52 %endmacro ; 共 8 字节

    以下是pmtest1.S

    1. 1 ; ==========================================
    2. 2 ; pmtest1.asm
    3. 3 ; 编译方法:nasm pmtest1.asm -o pmtest1.bin
    4. 4 ; ==========================================
    5. 5
    6. 6 %include "pm.inc" ; 常量, 宏, 以及一些说明
    7. 7
    8. 8 org 07c00h
    9. 9 jmp LABEL_BEGIN
    10. 10
    11. 11 [SECTION .gdt]
    12. 12 ; GDT
    13. 13 ; 段基址, 段界限 , 属性
    14. 14 LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符
    15. 15 LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_C + DA_32; 非一致代码段
    16. 16 LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW ; 显存首地址
    17. 17 ; GDT 结束
    18. 18
    19. 19 GdtLen equ $ - LABEL_GDT ; GDT长度
    20. 20 GdtPtr dw GdtLen - 1 ; GDT界限
    21. 21 dd 0 ; GDT基地址
    22. 22
    23. 23 ; GDT 选择子
    24. 24 SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
    25. 25 SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT
    26. 26 ; END of [SECTION .gdt]
    27. 27
    28. 28 [SECTION .s16]
    29. 29 [BITS 16]
    30. 30 LABEL_BEGIN:
    31. 31 mov ax, cs
    32. 32 mov ds, ax
    33. 33 mov es, ax
    34. 34 mov ss, ax
    35. 35 mov sp, 0100h
    36. 36
    37. 37 ; 初始化 32 位代码段描述符
    38. 38 xor eax, eax
    39. 39 mov ax, cs
    40. 40 shl eax, 4
    41. 41 add eax, LABEL_SEG_CODE32
    42. 42 mov word [LABEL_DESC_CODE32 + 2], ax
    43. 43 shr eax, 16
    44. 44 mov byte [LABEL_DESC_CODE32 + 4], al
    45. 45 mov byte [LABEL_DESC_CODE32 + 7], ah
    46. 46
    47. 47 ; 为加载 GDTR 作准备
    48. 48 xor eax, eax
    49. 49 mov ax, ds
    50. 50 shl eax, 4
    51. 51 add eax, LABEL_GDT ; eax <- gdt 基地址
    52. 52 mov dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址
    53. 53
    54. 54 ; 加载 GDTR
    55. 55 lgdt [GdtPtr]
    56. 56
    57. 57 ; 关中断
    58. 58 cli
    59. 59
    60. 60 ; 打开地址线A20
    61. 61 in al, 92h
    62. 62 or al, 00000010b
    63. 63 out 92h, al
    64. 64
    65. 65 ; 准备切换到保护模式
    66. 66 mov eax, cr0
    67. 67 or eax, 1
    68. 68 mov cr0, eax
    69. 69
    70. 70 ; 真正进入保护模式
    71. 71 jmp dword SelectorCode32:0 ; 执行这一句会把 SelectorCode32 装入 cs,
    72. 72 ; 并跳转到 Code32Selector:0
    73. 73 ; END of [SECTION .s16]
    74. 74
    75. 75
    76. 76 [SECTION .s32]; 32 位代码段. 由实模式跳入.
    77. 77 [BITS 32]
    78. 78
    79. 79 LABEL_SEG_CODE32:
    80. 80 mov ax, SelectorVideo
    81. 81 mov gs, ax ; 视频段选择子(目的)
    82. 82
    83. 83 mov edi, (80 * 11 + 79) * 2 ; 屏幕第 11 行, 第 79 列。
    84. 84 mov ah, 0Ch ; 0000: 黑底 1100: 红字
    85. 85 mov al, 'P'
    86. 86 mov [gs:edi], ax
    87. 87
    88. 88 ; 到此停止
    89. 89 jmp $
    90. 90
    91. 91 SegCode32Len equ $ - LABEL_SEG_CODE32
    92. 92 ; END of [SECTION .s32]
    93. 93

    执行之后效果如下No bootable device.

     初步分析认为是初次接触此类代码,没有理解关键变量的含义,囫囵运行之后无法达到预期目的。

    详细分析

    第一感觉是以下的标签代码怎么不见了?

    dw 	0xaa55				; boot record signature

    查看对应的os.raw二进制文件,也不足512字节

    正常的第一扇区应该是标准的512字节,如第一章的最简单OS的二进制内容如下

    再次测试

    经过对第一扇区的补齐之后,奇迹般地,显示出了书中预想的红色的P 

     

     补齐后的pmtest2.S文件如下

    1. ; ==========================================
    2. ; pmtest1.asm
    3. ; 编译方法:nasm pmtest1.asm -o pmtest1.bin
    4. ; ==========================================
    5. %include "pm.inc" ; 常量, 宏, 以及一些说明
    6. org 07c00h
    7. jmp LABEL_BEGIN
    8. [SECTION .gdt]
    9. ; GDT
    10. ; 段基址, 段界限 , 属性
    11. LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符
    12. LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_C + DA_32; 非一致代码段
    13. LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW ; 显存首地址
    14. ; GDT 结束
    15. GdtLen equ $ - LABEL_GDT ; GDT长度
    16. GdtPtr dw GdtLen - 1 ; GDT界限
    17. dd 0 ; GDT基地址
    18. ; GDT 选择子
    19. SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
    20. SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT
    21. ; END of [SECTION .gdt]
    22. [SECTION .s16]
    23. [BITS 16]
    24. LABEL_BEGIN:
    25. mov ax, cs
    26. mov ds, ax
    27. mov es, ax
    28. mov ss, ax
    29. mov sp, 0100h
    30. ; 初始化 32 位代码段描述符
    31. xor eax, eax
    32. mov ax, cs
    33. shl eax, 4
    34. add eax, LABEL_SEG_CODE32
    35. mov word [LABEL_DESC_CODE32 + 2], ax
    36. shr eax, 16
    37. mov byte [LABEL_DESC_CODE32 + 4], al
    38. mov byte [LABEL_DESC_CODE32 + 7], ah
    39. ; 为加载 GDTR 作准备
    40. xor eax, eax
    41. mov ax, ds
    42. shl eax, 4
    43. add eax, LABEL_GDT ; eax <- gdt 基地址
    44. mov dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址
    45. ; 加载 GDTR
    46. lgdt [GdtPtr]
    47. ; 关中断
    48. cli
    49. ; 打开地址线A20
    50. in al, 92h
    51. or al, 00000010b
    52. out 92h, al
    53. ; 准备切换到保护模式
    54. mov eax, cr0
    55. or eax, 1
    56. mov cr0, eax
    57. ; 真正进入保护模式
    58. jmp dword SelectorCode32:0 ; 执行这一句会把 SelectorCode32 装入 cs,
    59. ; 并跳转到 Code32Selector:0
    60. ; END of [SECTION .s16]
    61. [SECTION .s32]; 32 位代码段. 由实模式跳入.
    62. [BITS 32]
    63. LABEL_SEG_CODE32:
    64. mov ax, SelectorVideo
    65. mov gs, ax ; 视频段选择子(目的)
    66. mov edi, (80 * 11 + 79) * 2 ; 屏幕第 11 行, 第 79 列。
    67. mov ah, 0Ch ; 0000: 黑底 1100: 红字
    68. mov al, 'P'
    69. mov [gs:edi], ax
    70. ; 到此停止
    71. jmp $
    72. times 22 db 0
    73. times 64 db 0
    74. times 64 db 0
    75. times 64 db 0
    76. times 64 db 0
    77. times 83 db 0
    78. dw 0xaa55
    79. SegCode32Len equ $ - LABEL_SEG_CODE32
    80. ; END of [SECTION .s32]

     补齐后的二进制文件如下

     

     

  • 相关阅读:
    Cent OS安装中文字体
    Wpf 使用 Prism 实战开发Day02
    科技图表AE
    Flutter组件--OverflowBox、SizedOverflowBox(子组件超出父组件裁剪)
    java中对象的比较
    干货 | 一改测试步骤代码就全写?为什么不试试用 Yaml实现数据驱动?
    2023山东建筑大学考研介绍
    输入输出系统
    方法递归详解
    【Mysql】——索引的深度理解
  • 原文地址:https://blog.csdn.net/bear_miao/article/details/126931632