├── .gitignore ├── Cpt2.MBR sourcecode ├── README.md └── mbr.s ├── Cpt3.Improve MBR ├── README.md ├── include │ └── boot.inc ├── loader.s └── mbr.s ├── Cpt4.Rudiment of Protect Mode ├── README.md ├── include │ └── boot.inc ├── loader.s ├── mbr.s └── run_bochs.sh ├── Cpt5.A Step Close to Kernel ├── README.md ├── include │ └── boot.inc ├── kernel │ └── main.c ├── loader.s ├── mbr.s └── run_bochs.sh ├── Cpt6.Improve Kernel ├── README.md ├── include │ └── boot.inc ├── kernel │ └── main.c ├── lib │ ├── kernel │ │ ├── print.h │ │ └── print.s │ └── stdint.h ├── loader.s ├── mbr.s └── run_bochs.sh ├── Cpt7. Interrupt ├── README.md ├── boot │ ├── include │ │ └── boot.inc │ ├── loader.s │ └── mbr.s ├── kernel │ └── main.c ├── lib │ ├── kernel │ │ ├── print.h │ │ └── print.s │ └── stdint.h └── run_bochs.sh ├── LICENSE ├── README.md └── bochs ├── bin ├── bochs ├── bochsrc.disk └── bximage └── share ├── bochs ├── BIOS-bochs-latest ├── BIOS-bochs-legacy ├── SeaBIOS-README ├── VGABIOS-elpin-2.40 ├── VGABIOS-elpin-LICENSE ├── VGABIOS-lgpl-README ├── VGABIOS-lgpl-latest ├── VGABIOS-lgpl-latest-cirrus ├── VGABIOS-lgpl-latest-cirrus-debug ├── VGABIOS-lgpl-latest-debug ├── bios.bin-1.13.0 ├── keymaps │ ├── sdl-pc-de.map │ ├── sdl-pc-us.map │ ├── sdl2-pc-de.map │ ├── sdl2-pc-us.map │ ├── x11-pc-be.map │ ├── x11-pc-da.map │ ├── x11-pc-de.map │ ├── x11-pc-es.map │ ├── x11-pc-fr.map │ ├── x11-pc-it.map │ ├── x11-pc-ru.map │ ├── x11-pc-se.map │ ├── x11-pc-si.map │ ├── x11-pc-uk.map │ └── x11-pc-us.map └── vgabios-cirrus.bin-1.13.0 ├── doc └── bochs │ ├── CHANGES │ ├── COPYING │ ├── LICENSE │ ├── README │ ├── TODO │ ├── bochsrc-sample.txt │ └── slirp.conf └── man ├── man1 ├── bochs-dlx.1.gz ├── bochs.1.gz └── bximage.1.gz └── man5 └── bochsrc.5.gz /.gitignore: -------------------------------------------------------------------------------- 1 | *.img 2 | *.bin 3 | *.out 4 | -------------------------------------------------------------------------------- /Cpt2.MBR sourcecode/README.md: -------------------------------------------------------------------------------- 1 | # Cpt2.编写MBR,掌握主动权 2 | 3 | ## 使用nasm编译汇编文件 4 | 5 | ```shell 6 | nasm -f [-o ] 7 | ``` 8 | 9 | -------------------------------------------------------------------------------- /Cpt2.MBR sourcecode/mbr.s: -------------------------------------------------------------------------------- 1 | SECTION MBR vstart=0x7c00 2 | mov ax,cs 3 | mov ds,ax 4 | mov es,ax 5 | mov ss,ax 6 | mov fs,ax 7 | mov sp,0x7c00 8 | ;清屏功能 9 | mov ax,0x600 10 | mov bx,0x700 11 | mov cx,0 12 | mov dx,0x184f 13 | int 0x10 14 | 15 | ;获取光标未知 16 | ;输出:cl:光标开始行,cl:光标结束行 17 | ; dl:光标所在行号,dl:光标所在列号 18 | 19 | ; 打印字符串 20 | mov ax,message 21 | mov bp,ax 22 | mov cx,5 23 | mov ax,0x1301 24 | mov bx,0x2 25 | int 0x10 26 | 27 | sleep: 28 | times 50 nop 29 | jmp sleep 30 | 31 | message db "1 MBR" 32 | times 510-($-$$) db 0 33 | db 0x55,0xaa 34 | -------------------------------------------------------------------------------- /Cpt3.Improve MBR/README.md: -------------------------------------------------------------------------------- 1 | # Kernel学习之路 2 | 3 | 《操作系统真象还原》 4 | 5 | ## 第一章 6 | 7 | 配环境 8 | 9 | ## 第二章 10 | 11 | 继续配环境+初步测试环境 12 | 13 | 这里需要注意的几个点: 14 | 15 | 1. bochsrc.disk中关于虚拟硬盘的路径得是绝对路径(从根目录开始全部梭哈) 16 | 2. 多找资料多尝试 17 | 18 | ## 第三章 19 | 20 | ### 3.1 有关nasm 21 | 22 | **section**:nasm定义的section和pe/elf文件中的段是两个不同的定义。 23 | 24 | **vstart**:偏移量定义,定义后边写的代码的基准偏移,不是在文件中的偏移 25 | 26 | ### 3.2 CPU的实模式 27 | 28 | #### 3.2.1 复习计算机组成原理——CPU的组成和运行模式 29 | 30 | #### 3.2.2 实模式下的寄存器 & 8086汇编基础 31 | 32 | 实模式下,默认用到的寄存器都是16bits的。 33 | 34 | CPU中寄存器分为两类: 35 | 36 | - 内部寄存器,用户不可见:这一部分寄存器用于为CPU的运行提供支持 37 | 38 | 虽然内部寄存器不可见,不可直接使用,但仍然有一部分寄存器需要我们手动为其初始化 39 | 40 | - 用户寄存器,用户可见:这一部分寄存器用于为用户程序的运行提供支持 41 | 42 | 然后讲了一些8086汇编基础 43 | 44 | 这里得讲俩指令,之前没学过的。 45 | 46 | **in指令**:格式: `in al,dx`或者`in ax,dx` 47 | 48 | - in指令用于从端口中读取数据。dx为端口号,ax/al用来储存获取的数据。 49 | - 使用al还是ax来储存储存数据,取决于端口指代的寄存器长度是8bits还是16bits 50 | 51 | **out指令**: 52 | 53 | - 格式: 54 | 1. `out dx,al` 55 | 2. `out dx,ax` 56 | 3. `out 立即数,al` 57 | 4. `out 立即数,ax` 58 | - 端口号是dx或者立即数。写入的数据是al/ax 59 | - 使用ax还是al的规则同in指令。 60 | 61 | 挖一个有点历史的东西。cpu对外的数据接口通过**南桥、北桥**统一管理。北桥管理高速设备,南桥管理低速设备。 62 | 63 | 这时候就不得不说AMD,YES! 64 | 65 | 细数amd的功绩: 66 | 67 | 1. 推进cpu与北桥一体化 68 | 2. 推进64位cpu发展 69 | 3. 推进cpu模块化核心 70 | 4. 率先量产7nm 71 | 72 | **Intel,NO!** 73 | 74 | ### 3.3 直接对屏幕写点东西呗 75 | 76 | (小声BB,写在开始看之前)我觉得这个肯定是在讲25*80彩色缓冲区 77 | 78 | hmmm,害 79 | 80 | 显存开始地址:0x0b800,25行,80列 81 | 82 | 一个字符分为ascii码和颜色代码两个部分,长度为16bits 83 | 84 | 低字节(AL)是ascii码部分,高字节(AH)是颜色代码部分 85 | 86 | ### 3.4 bochs调试手段 87 | 88 | 在开始讲这段之前,有一点需要先说明的。bochs中的关键字WORD不是两个字节,而是四个字节。 89 | 90 | 熟悉gdb的应该可以很快上手这一套调试工具 91 | 92 | #### 输入“h”获取bochs的调试指令集 93 | 94 | #### 输入“h 其他指令”获取关于该调试指令的详细内容 95 | 96 | ``` h 97 | h|help - show list of debugger commands 98 | h|help command - show short command description 99 | -*- Debugger control -*- 100 | help, q|quit|exit, set, instrument, show, trace, trace-reg, 101 | trace-mem, u|disasm, ldsym, slist 102 | ``` 103 | 104 | #### debuger控制指令 105 | 106 | **q**:退出bochs 107 | 108 | **set**:set是一个指令族,可以使用set来设定寄存器,或者是反汇编相关的事情 109 | 110 | - `set (regname) = (expr)`:设定指定寄存器的值 111 | - 112 | 113 | **instrument**: 114 | 115 | **show**:show是一个指令族,可以用来做很多东西 116 | 117 | - `show` 显实当前的展示模式 118 | - `show mode` : 每次CPU变换模式的时候就提示,模式是保护模式、实模式,比如从实模式进入到保护模式的时候会有提示 119 | - `show int`: 每次终端的时候会有提示,同时显示3种中断类型(sofrint,extint,iret)。可以单独显示某类中断,如执行 `show softint` 只显示软件主动触发的中断, `show extint` 则只显示来自 外部设备的中断, `show iret` 只显示 iretd 指令有关的信息。 120 | - `show call` : 每次有函数调用发生的时候就会提示 121 | - `show off`: 关闭提示信息 122 | - `show all` : 提示所有信息 123 | 124 | **trace**:`trace on`/`off`,打开此选项的时候,每次执行一条指令,都会把执行的指令打印到控制台。 125 | 126 | **trace-reg**: 127 | 128 | **trace-mem**: 129 | 130 | **u**: u [/count] (start) (end) ,反汇编指令 131 | 132 | - /count是可选选项,指定翻译多少条指令 133 | - 例子:`u /10`:按顺序翻译eip所在地址往下的10条指令 134 | - u (start):翻译地址位于start处的一条指令 135 | - u (start) (end): 翻译地址位于start和end之间的指令 136 | - 例子:`u /5 0x70000 0x70020` 翻译在0x70000和0x70020之间代码块中从0x70000开始的5条指令 137 | - 例子:`u 0x70000 0x70020` 翻译在0x70000和0x70020之间代码块中的所有指令 138 | - u switch-mode 切换反汇编模式(AT&T和Intel两种模式来回切换) 139 | - u hex on/off 原文:control disasm offsets and displacements format 140 | - u size = n ,n可以是16位,32位或者64位。设定反汇编器的反汇编字长 141 | 142 | **ldsym**: 143 | 144 | **slist**: 145 | 146 | #### 执行控制指令 147 | 148 | ```c 149 | -*- Execution control -*- 150 | c|cont|continue, s|step, p|n|next, modebp, vmexitbp 151 | ``` 152 | 153 | **c**:运行到下一个断点(如果没有,那就等于放弃控制权了) 154 | 155 | **s**:单步执行,call指令会进入被call函数 156 | 157 | **n**:单步执行,call指令不会进入被call函数 158 | 159 | **modebp**: 160 | 161 | **vmexitbp**: 162 | 163 | #### CPU & 内存状态查看 164 | 165 | ```c 166 | -*- CPU and memory contents -*- 167 | x, xp, setpmem, writemem, crc, info, 168 | r|reg|regs|registers, fp|fpu, mmx, sse, sreg, dreg, creg, 169 | page, set, ptime, print-stack, ?|calc 170 | ``` 171 | 172 | **x**:查看内存,根据线性地址查看。实模式中不可用。格式同指令`xp`,参数同`xp` 173 | 174 | **xp /nuf (addr)**:查看内存,根据物理地址查看。 175 | 176 | - 例子:`xp /20xg` 0x7fff,以十六进制的形式查看0x7fff开始的20个double word 177 | 178 | - /nuf: "/"+数据数量+数据格式+数据字长 179 | 180 | - 数据格式: 181 | 182 | | 符号 | 含义 | 符号 | 含义 | 183 | | ---- | ------------ | ---- | -------------- | 184 | | x | 十六进制 | t | 二进制 | 185 | | d | 有符号十进制 | c | 字符 | 186 | | u | 无符号十进制 | s | asciiz | 187 | | o | 八进制 | i | instr(啥意思?) | 188 | 189 | - 数据字长 190 | 191 | | 符号 | 含义 | 符号 | 含义 | 192 | | ---- | ------------------ | ---- | ------------------- | 193 | | b | 1字节(byte) | w | 4字节(word) | 194 | | h | 2字节(half-word) | g | 8字节(giant word) | 195 | 196 | 197 | 198 | **setpmem**: 199 | 200 | **writemem**: 201 | 202 | **crc**: 203 | 204 | **info**: 205 | 206 | **r**:查看普通寄存器数据 207 | 208 | **fp**:查看浮点寄存器数据 209 | 210 | **mmx**: 211 | 212 | **sse**: 213 | 214 | **sreg**: 215 | 216 | **dreg**: 217 | 218 | **creg**: 219 | 220 | **page**: 221 | 222 | **set**: 223 | 224 | **ptime**: 225 | 226 | **print-stack**: 227 | 228 | **calc**: 229 | 230 | #### 断点控制指令 231 | 232 | ```c 233 | -*- Breakpoint management -*- 234 | vb|vbreak, lb|lbreak, pb|pbreak|b|break, sb, sba, blist, 235 | bpe, bpd, d|del|delete, watch, unwatch 236 | -*- Working with bochs param tree -*- 237 | show "param", restore 238 | ``` 239 | 240 | **vb**: 241 | 242 | **lb**: 243 | 244 | **b**: 245 | 246 | **sb**: 247 | 248 | **sba**: 249 | 250 | **blist**: 251 | 252 | **bpe**: 253 | 254 | **bpd**: 255 | 256 | **d**: 257 | **watch**: 258 | 259 | **unwatch**: 260 | 261 | 262 | 263 | -------------------------------------------------------------------------------- /Cpt3.Improve MBR/include/boot.inc: -------------------------------------------------------------------------------- 1 | ;________loader & kernel________ 2 | LOADER_BASE_ADDR equ 0x900 3 | LOADER_START_SECTOR equ 0x2 -------------------------------------------------------------------------------- /Cpt3.Improve MBR/loader.s: -------------------------------------------------------------------------------- 1 | %include "boot.inc" 2 | 3 | mov byte [gs:80*2+0x00],'2' 4 | mov byte [gs:80*2+0x01],'0xA4' 5 | 6 | mov byte [gs:80*2+0x02],' ' 7 | mov byte [gs:80*2+0x03],'0xA4' 8 | 9 | mov byte [gs:80*2+0x04],'L' 10 | mov byte [gs:80*2+0x05],'0xA4' 11 | 12 | mov byte [gs:80*2+0x06],'O' 13 | mov byte [gs:80*2+0x07],'0xA4' 14 | 15 | mov byte [gs:80*2+0x08],'A' 16 | mov byte [gs:80*2+0x09],'0xA4' 17 | 18 | mov byte [gs:80*2+0x0a],'D' 19 | mov byte [gs:80*2+0x0b],'0xA4' 20 | 21 | mov byte [gs:80*2+0x0c],'E' 22 | mov byte [gs:80*2+0x0d],'0xA4' 23 | 24 | mov byte [gs:80*2+0x0e],'R' 25 | mov byte [gs:80*2+0x0f],'0xA4' 26 | 27 | mov byte [gs:80*2+0x10],'!' 28 | mov byte [gs:80*2+0x11],'0xA4' 29 | 30 | sleep: 31 | 32 | times 50 nop 33 | jmp sleep -------------------------------------------------------------------------------- /Cpt3.Improve MBR/mbr.s: -------------------------------------------------------------------------------- 1 | %include "boot.inc" 2 | SECTION MBR vstart=0x7c00 3 | mov ax,cs 4 | mov ds,ax 5 | mov es,ax 6 | mov ss,ax 7 | mov fs,ax 8 | mov sp,0x7c00 9 | mov ax,0xb800 10 | mov gs,ax 11 | 12 | ;清屏功能 13 | mov ax,0x600 14 | mov bx,0x700 15 | mov cx,0 16 | mov dx,0x184f 17 | int 0x10 18 | 19 | ;获取光标未知 20 | ;输出:cl:光标开始行,cl:光标结束行 21 | ; dl:光标所在行号,dl:光标所在列号 22 | 23 | ; 打印字符串 24 | mov byte [gs:0x00],'l' 25 | mov byte [gs:0x01],0xA4 26 | 27 | mov byte [gs:0x02],' ' 28 | mov byte [gs:0x03],0xA4 29 | 30 | mov byte [gs:0x04],'M' 31 | mov byte [gs:0x05],0xA4 32 | 33 | mov byte [gs:0x06],'B' 34 | mov byte [gs:0x07],0xA4 35 | 36 | mov byte [gs:0x08],'R' 37 | mov byte [gs:0x09],0xA4 38 | 39 | 40 | ;读取一个扇区(loader所在)道指定位置的内存中 41 | mov eax,LOADER_START_SECTOR ;硬盘中的lba地址 42 | mov bx,LOADER_BASE_ADDR ;写入的地址 43 | mov cx,1 ;读入的扇区数 44 | call rd_disk_m_16 45 | 46 | jmp LOADER_BASE_ADDR 47 | 48 | ; 函数rd_disk_m_16 49 | ; 功能:读取硬盘n个扇区 50 | ; eax = LBA硬盘号 51 | ; bx = 将数据写入的内存地址 52 | ; cx = 读入的扇区数 53 | rd_disk_m_16: 54 | mov esi,eax ;备份eax 55 | mov di,cx ;备份cx 56 | ;读写硬盘 57 | ;第一步:设置要读取的扇区数 58 | mov dx,0x1f2 ;指定读取的扇区数 59 | mov al,cl 60 | out dx,al 61 | mov eax,esi ;恢复ax 62 | 63 | ;第二部:将LBA地址存入0x1f3~0x1f6 64 | mov dx,0x1f3 65 | out dx,al 66 | 67 | mov cl,8 68 | shr eax,cl 69 | inc dx 70 | out dx,al 71 | 72 | shr eax,cl 73 | inc dx 74 | out dx,al 75 | 76 | shr eax,cl 77 | and al,0x0f 78 | or al,0xe0 79 | mov dx,0x1f6 80 | out dx,al 81 | ;第三步:向0x1f7端口写入读命令,0x20 82 | mov dx,0x1f7 83 | mov al,0x20 84 | out dx,al 85 | 86 | ;第四步:检测硬盘状态 87 | .not_ready: 88 | nop 89 | in al,dx 90 | and al,0x88 91 | cmp al,0x08 92 | jnz .not_ready 93 | ;第五步:0x1f0端口读取数据 94 | mov ax,di 95 | ;一次读取一个字,所以是512/2*di 96 | mov dx,256 97 | mul dx 98 | mov cx,ax 99 | mov dx,0x1f0 100 | .go_on_read: 101 | in ax,dx 102 | mov [bx],ax 103 | add bx,2 104 | loop .go_on_read 105 | ret 106 | 107 | times 510-($-$$) db 0 108 | db 0x55,0xaa 109 | -------------------------------------------------------------------------------- /Cpt4.Rudiment of Protect Mode/README.md: -------------------------------------------------------------------------------- 1 | # Cpt4.Rudiment of Protect Mode 2 | 3 | > 保护模式入门 4 | 5 | ## 什么是保护模式? 6 | 7 | > CPU的发展,就是寄存器变长,运算速度变快,Intel 14nm+++++++++++++的过程 8 | 9 | 在先前的两个章节中,我们通过写MBR和Loader实现了从硬盘中读取程序代码到内存中并执行这段代码 10 | 11 | 可是细心观察的话可以发现,我们的MBR和Loader好像能直接对内存中任意地址进行操作,从显存,栈区到中断向量表。这种行为是十分危险的 12 | 13 | 加之随着计算机硬件设备的发展,我们的计算机的内存越来越大,段地址+偏移地址的寻址方式太过复杂,且20条地址线怎么都不够用。 14 | 15 | 以及最为糟糕的一点,CPU一次只能执行一个程序。 16 | 17 | 在这些种种需求和缺点的背景之下,32bit CPU和保护模式就呼之欲出了 18 | 19 | ## 实模式是什么? 20 | 21 | > 就像中学生做小学生的题一样,可以用小学生的知识方法来做,但并不要求自己退化成小学生的知识水平。 22 | > 如果不强调方法,甚至可以用中学知识来解小学生问题。 23 | 24 | 只是32位(以上)的CPU工作在16位(8086)工作模式下的情况,并不是说这种情况下CPU就只有16位可用 25 | 26 | ## 初见保护模式 27 | 28 | - AX,BX,CX,DX,SI,DI,BP,SP,FLAGS,IP扩展为32位 29 | 30 | > 80286这种中间产物不在这里的讨论范畴内。 31 | 32 | 命名方式为在原寄存器名前加上一个E 33 | 34 | 高16位的部分只能在32位模式下使用 35 | 36 | - 寻址方式改变 37 | 38 | **依旧使用段地址+偏移地址**,但是方式不是之前的((段寄存器<<4)+寻址寄存器)的方法 39 | 40 | 新增一个数据结构——全局描述符表,储存在内存中,其大小位64字节,其中的表项称为段描述符,用于描述各个内存段内的起始地址,大小,权限等信息 41 | 42 | 新增GDTR寄存器,指向全局描述符表 43 | 44 | 段寄存器保存的不再是段基址,而是全局描述符表的选择子,"sector",用于索引杜全局描述符表中的段描述符 45 | 46 | - 寻址寄存器不再局限于bx,dx,si,di 47 | 48 | 几乎所有通用寄存器都可以用于寻址,就像我们今天所看到的那样 49 | 50 | 51 | - 总结如下: 52 | 53 | 1. 段描述符是在内存中,访问内存对 CPU 来说是比较慢的动作,效率不高。 54 | 2. 段描述符的格式很奇怪,一个数据要分三个地方存,所以CPU要把这些七零八落的数拼合成一个完整数据也是要花时间的。 55 | 56 | 全局描述符表将在后面的章节中讨论。 57 | 58 | ## 保护模式的指令问题 59 | 60 | > 稍微了解过一些微软、Intel发家史的同学,都知道这两家公司最大的特点: 61 | > 62 | > 新产品对旧产品的兼容 63 | 64 | 在保护模式中,010代表edx寄存器 65 | 66 | 在实模式中,010代表dx寄存器 67 | 68 | 汇编编译器并不知道什么时候该生成16位指令,什么时候该生成32位指令。这个时候就得我们**手动来指定**。 69 | 70 | ```assembly 71 | [bits 16] 告诉编译器,到下一个[bits]标签为止,下面的代码编译成16位机器码 72 | [bits 32] 告诉编译器,到下一个[bits]标签为止,下面的代码编译成32位机器码 73 | ``` 74 | 75 | **保护模式需要手动打开**。分为三个步骤。下面这三个步骤可以不连续,也可以不顺序 76 | 77 | 1. 打开A20 78 | 2. 加载gdt 79 | 3. 将cr0的pe位置一 80 | 81 | ### 实模式下到底能不能用32位寄存器? 82 | 83 | 答案:可以。 84 | 85 | 注意下面这个表中被标黑的指令前缀 0x66。 86 | 87 | | 指令 | 机器码 | 88 | | -------------- | ---------------- | 89 | | **[bits 16]** | 伪指令,无机器码 | 90 | | mov ax,0x1234 | B83412 | 91 | | mov eax,0x1234 | **66**B834120000 | 92 | | **[bits 32]** | 伪指令,无机器码 | 93 | | mov ax,0x1234 | **66**B83412 | 94 | | mov eax,0x1234 | B834120000 | 95 | 96 | - 前缀0x66 :反转操作数大小 97 | 98 | 在32bits模式下时,将操作数大小指定为16位(保护模式下使用实模式的指令) 99 | 100 | 在16bits模式下时,将操作数大小指定为32位(实模式下使用保护模式的指令) 101 | 102 | - 前缀0x67:反转寻址方式 103 | 104 | | 指令 | 机器码 | 反转效果 | 105 | | ----------------------- | -------------------- | --------------------- | 106 | | **[bits 16]** | 伪指令,无机器码 | | 107 | | mov word [bx], 0x1234 | C7073412 | 无 | 108 | | mov word [eax], 0x1234 | **67**C7003412 | 在实模式使用eax寻址 | 109 | | mov dword [eax],0x1234 | **6667**C70034120000 | 在实模式使用eax写入dw | 110 | | **[bits 32]** | 伪指令,无机器码 | | 111 | | mov dword [eax], 0x1234 | C70034120000 | 无 | 112 | | mov word [eax], 0x1234 | **66**C7003412 | 操作数大小改变 | 113 | | mov dword [bx], 0x1234 | **67**C70734120000 | 寻址方式改变 | 114 | 115 | ### 保护模式之指令扩展 116 | 117 | - 原先实模式下的CPU操作数仅为16位,而保护模式却到了32位。 118 | 119 | 因此,操作数变化的指令也要跟着扩展 120 | 121 | 例: 122 | 123 | ```assembly 124 | ;实模式指令 125 | add al,cl 126 | add ax,cx 127 | ;保护模式指令扩展 128 | add eax,ecx 129 | ``` 130 | 131 | - 注意,mul,div这一类多寄存器指令相比实模式有变化 132 | 133 | - mul指令: 134 | 135 | mul 指令是无符号数相乘指令,指令格式是 mul 寄存器/内存。 136 | 137 | 其中“寄存器/内存”是乘数。 138 | 139 | 如果乘数是8位,则把寄存器 al 当作另一个乘数,结果便是16位,存入寄存ax。 140 | 141 | 如果乘数是16位,则把寄存器ax当作另一个乘数,结果便是32 位,存入寄存器 142 | 143 | 如果乘数是32位,则把寄存器eax当作另一个乘数,结果便是64位,存入edx: eax ,其中 edx 是积的高 32 位, eax是积的低 32 位。 144 | 145 | 有符号数相乘指令 imul 也是一样,不再说明。 146 | 147 | - div指令 148 | 149 | 对于无符号数除法指令div ,其格式是 div 寄存器/内存,其中的“寄存器/内存”是除法计算中的除数。 150 | 151 | 如果除数是8位,被除数就是 16 位,位于寄存器ax。所得的结果,商在寄存器 al ,余数在寄存器ah。 152 | 153 | 如果除数是 16 位,被除数就是 32 位,被除数的高 16 位则位于寄存器 dx ,被除数的低 16 位则位于寄存器 ax 。所得的结果,商在寄存器ax,余数在寄存器 dx 154 | 155 | 如果除数是 32 位,被除数就是64位,被除数的高 32 位则位于寄存器edx ,被除数的低 32 位则位于寄存器 eax,所得的结果,商在寄存器eax,余数在寄存器 edx 156 | 157 | - push指令push的数据长度是固定长度 158 | 159 | - 实模式下:push 16bits数据 160 | 161 | 如果在实模式下使用 push 0x12340000之类的指令,则像保护模式那样push进去32bits,**使用数据长度反转前缀** 162 | 163 | - 保护模式下:push 32bits数据 164 | 165 | 如果在实模式下使用push 0x1234之类的指令,则像保护模式那样push进去16bits。**使用数据长度反转前缀** 166 | 167 | - push 段寄存器 168 | 169 | **长度对齐**当前模式的机器字长 170 | 171 | - push 通用寄存器和内存 172 | 173 | 长度对其当前模式的机器字长 174 | 175 | ## 全局描述符表(GDT) 176 | 177 | > 就像家庭成员需要上户口一样,在户口簿上登记过才算合法 178 | 179 | 全局描述符表( Global Descriptor Table, GDT )是保护模式下内存段的登记表,这是不同于实模式的显著特征之一 180 | 181 | 注意!我们只讨论x86架构下的GDT。 182 | 183 | ### 段描述符 184 | 185 | x86架构下的描述符,长度8个字节。 186 | 187 | 为了表述方便,这里按四个字节为一个表格展示段描述符 188 | 189 | 段描述符**在内存中是连续储存的** 190 | 191 | | 31\~24 | 23 | 22 | 21 | 20 | 19\~16 | 15 | 14\~13 | 12 | 11\~8 | 7\~0 | | 192 | | ------------------ | ---- | ---- | ---- | ---- | ------------------ | ---- | ------ | ---- | ----- | ------------------ | ------- | 193 | | 段基址
31\~24 | G | D/B | L | AVL | 段界限
19\~16 | P | DPL | S | TYPE | 段基址
23\~16 | 高4字节 | 194 | 195 | | 31\~16 | 15\~0 | | 196 | | ------------ | ----------- | ------- | 197 | | 段基址 15\~0 | 段界限15\~0 | 低4字节 | 198 | 199 | - **段基址** 200 | 201 | - **长度**:32bits 202 | 203 | - **功能**:描述段的基址 204 | 205 | - **段界限** 和 **G** 206 | 207 | - **长度**:**20bits** = 16 + 4(bits) 208 | 209 | - **单位**(粒度):由段描述符字段 **G** 定义,仅存在两种情况 210 | 211 | - G = 1 时,单位为字节,段最大大小为$2^{20} bytes = 1MB$ 212 | - G = 0 时,单位为4KB,段最大大小为$2^{32} bytes = 4GB$ 213 | 214 | - **作用**:表示段的边界、大小、范围 215 | 216 | - **实际段边界值**: 217 | 218 | 由于描述符中的**段界限是从0起**的,所以左边第1个括号中要加个1,表示 4KB 或1bytes 的实际数量。 219 | 220 | 它与第二个括号中的段粒度大小相乘后**得到的乘积是以1为起始的段的实际大小** 由于**地址是以0为起始的**,所以公式的最后又减了1 221 | 222 | $(描述符中段界限 + 1) * ( 段界限的粒度大小 ) - 1$ 223 | 224 | - 为什么**段界限被拆分为**16bits+4bits的两部分? 225 | 226 | 你问80286去 227 | 228 | - **TYPE**字段 和 **S** 229 | 230 | - **长度**:4bits(TYPE),1bit(S) 231 | 232 | - **作用**:TYPE 和 S 共同作用,指定本描述符的类型 233 | 234 | - S = 1:数据段 235 | 236 | - S = 0:系统段 237 | 238 | 只有S的值确定之后,TYPE字段才有意义 239 | 240 | - **系统段是什么?** 241 | 242 | 各种门,硬件系统需要的结构,而非软件使用的。比如如调用门,任务门。 243 | 244 | 门,换言之就是个入口,通往一段程序。 245 | 246 | | 系统段类型 | 3 | 2 | 1 | 0 | 说明 | 247 | | -------------------- | ---- | ---- | ---- | ---- | ------------------------------------------------------------ | 248 | | 未定义 | 0 | 0 | 0 | 0 | 保留 | 249 | | 可用的80286 TSS | 0 | 0 | 0 | 1 | 仅限80286的任务状态段 | 250 | | **LDT** | 0 | 0 | 1 | 0 | 局部描述符表 | 251 | | 忙碌的80286 TSS | 0 | 0 | 1 | 1 | 仅限80286,type中的第一位称为B位,若为1,则表示当前任务忙碌,由CPU将此位置一 | 252 | | 80286调用门 | 0 | 1 | 0 | 0 | 仅限80286 | 253 | | 任务门 | 0 | 1 | 0 | 1 | 现代操作系统很少用到这个 | 254 | | 80286中断门 | 0 | 1 | 1 | 0 | 仅限286 | 255 | | 80286陷阱门 | 0 | 1 | 1 | 1 | 仅限286 | 256 | | 未定义 | 1 | 0 | 0 | 0 | 保留 | 257 | | **可用的80386 TSS** | 1 | 0 | 0 | 1 | 80386以上的CPU的TSS,type第3位为1 | 258 | | 未定义 | 1 | 0 | 1 | 0 | 保留 | 259 | | **忙碌的 80386 TSS** | 1 | 0 | 1 | 1 | 80386以上的CPU的调用门,type第3位为1 | 260 | | 未定义 | 1 | 1 | 0 | 1 | 保留 | 261 | | **中断门** | 1 | 1 | 1 | 0 | 386以上的中断门 | 262 | | **陷阱门** | 1 | 1 | 1 | 1 | 386以上的陷阱门 | 263 | 264 | - 非系统段 265 | 266 | 非系统段的TYPE字段分为两种,对**代码段**的描述和对**数据段**的描述 267 | - **代码段描述** 268 | 269 | | 代码段 | X | R | C | A | 说明 | 270 | | ------ | ---- | ---- | ---- | ---- | -------------------------- | 271 | | | 1 | 0 | 0 | * | 只执行代码段 | 272 | | | 1 | 1 | 0 | * | 可执行、可读代码段 | 273 | | | 1 | 0 | 1 | * | 可执行、一致性代码段 | 274 | | | 1 | 1 | 1 | * | 可执行,一致性,可读代码段 | 275 | 276 | - **A位标识Accessed位**:这一位-由CPU设置,每当该段被CPU访问过后,CPU就将此位设置为1。A为0时,说明该段还没被CPU访问过。换言之,这个段描述符可能刚刚被创立 277 | 278 | - **C位标识**Conforming:一致性代码段 279 | 280 | 一致性代码段是指如果自己是转移的目标段,并且自己是一致性代码段,自己的特权级一定要高于当前特权级,转移后的特权级不与自己的 DPL 为主,而是与转移前的低特权级一致,也就是听从、依从转移前的低特权级。 281 | 282 | C = 1时则表示该段是一致性代码段 283 | 284 | C = 0时则表示该段为非一致性代码段 285 | 286 | - **数据段描述** 287 | 288 | | 数据段 | X | W | E | A | 说明 | 289 | | ------ | ---- | ---- | ---- | ---- | ------------------------ | 290 | | | 0 | 0 | 0 | * | 只读数据段 | 291 | | | 0 | 1 | 0 | * | 可读写数据段 | 292 | | | 0 | 0 | 1 | * | 只读,向下扩展的数据段 | 293 | | | 0 | 1 | 1 | * | 可读写,向下扩展的数据段 | 294 | 295 | - **E位标识**Extend:用来标识段的扩展方向。 296 | 297 | E = 0,段向上扩展 298 | 299 | E = 1,段向下扩展 300 | 301 | - **DPL字段**:Descriptor Privilege Level 302 | 303 | - **长度**:2bits 304 | 305 | - **功能**:描述段的特权级别,0~3级。 306 | 307 | 最高级为0级,最低级为3级(用户态)。通常只使用0级和3级这两层。 308 | 309 | 有些代码得在0级下运行才能保证安全 310 | 311 | - **P字段**:Present 312 | 313 | - **长度**:1bit 314 | 315 | - **功能**:判断段是否在内存中 316 | 317 | - P = 1,段在内存中 318 | - P = 0,段不存在于内存中 319 | 320 | CPU只负责检查P字段,不负责赋值。如果CPU检测到它访问了P = 0的段,则会抛出异常。 321 | 322 | - **AVL字段**:Available 323 | 324 | - **长度**:4bits 325 | - **功能**:标志这个段是可用的。0级权限无视这个字段。用户态需要更具这个字段的值确定该段是否可用 326 | 327 | - **L字段** 328 | 329 | - **长度**:1bit 330 | 331 | - **功能**:标志当前代码段是否为64位代码 332 | 333 | - L = 1:当前代码段为64bits代码 334 | 335 | - L = 0:当前代码段为32bits代码 336 | 337 | 因为这本教材套路的是x86架构,所以L = 0 338 | 339 | - **D/B字段** 340 | 341 | - **长度**:1bit 342 | 343 | - **功能**:用来指示有效地址(段内偏移地址)及操作数的大小。 344 | 345 | 对于代码段而言,这一位是D字段 346 | 347 | - D = 1,指令中的有效地址和操作数是32bits 348 | - D = 0,指令中的有效地址和操作数是16bits 349 | 350 | 对于栈段而言,这一位是B字段 351 | 352 | - B = 1,使用的是esp寄存器 353 | - B = 0,使用的是sp寄存器 354 | 355 | 356 | ### GDTR寄存器,与操作它的指令 357 | 358 | GDTR寄存器的**长度为48bits** 359 | 360 | | 47\~16 | 15\~0 | 361 | | --------------- | --------------------- | 362 | | GDT内存起始地址 | GDT界限(字节为单位) | 363 | 364 | GDTR寄存器保存了GDT的地址,和GDT表的长度信息。 365 | 366 | 通过GDTR寄存器的信息结构,我们可以推算出,GDT表的长度最大值是1MB,也就是8192个段描述符表。 367 | 368 | 不能用`mov gdtr,xxx`的方式初始化GDTR寄存器。需要用指令`lgdt` 369 | 370 | - lgdt指令 371 | - **格式**:`lgdt 48bits内存数据` 372 | - 可在实模式和保护模式中使用 373 | - 需要设置GDTR寄存器后,才能进入保护模式。但是进入保护模式后,可访问的内存空间增大为4GB,需要重新安放GDT表,所以允许保护模式下使用lgdt指令 374 | 375 | ### 段寄存器与选择子(selector) 376 | 377 | 保护模式下,段寄存器储存的不再是段基址,而是GDT的选择子。 378 | 379 | 段寄存器有16bits长,和选择子长度一致。选择子并非单纯的一个数组索引,它具有一个特定的数据结构。 380 | 381 | | 15\~3 | 2 | 1\~0 | 382 | | ------------------ | ---- | ---- | 383 | | 索引描述符(13bits) | TI | RPL | 384 | 385 | - **RPL** 386 | 387 | - **长度**:2bits 388 | 389 | - **功能**:描述当前请求者的特权级,分为0,1,2,3共四级,同系统特权级 390 | 391 | - **TI**:Table Indicator 392 | 393 | - **长度**:1bit 394 | - **功能**:用来指示选择子是在GDT中,还是LDT中的索引描述符 395 | - TI = 0:选择子在GDT中 396 | - TI = 1:选择子在LDT中 397 | 398 | - **索引描述符**: 399 | 400 | - **长度**:13bits ,$2 ^ {13} = 8192$ 401 | - **功能**:描述符的索引值,GDT数组索引。 402 | 403 | ### 内存分段机制在IA32下的实现 404 | 405 | 由于寄存器位数的增加,任意一个通用寄存器都可以直接访问到全部4GB的内存地址。所以段基址不再需要左右移动。 406 | 407 | 要访问的内存地址 = 段内偏移 + 段描述符中的段基址。 408 | 409 | ### GDT数组的0号位为何不使用 410 | 411 | 因为段寄存器未初始化的时候,索引值为0。这时候访问了GDT,就会出现大问题。因此GDT[0]不作为段选择子的储存使用。 412 | 413 | ## 打开A20地址线 414 | 415 | 在8086/8088cpu中,超过0xFFFFF的高位数据会被直接舍去。因此,利用这一特性搞出来的地址回绕成为了那一时代程序员的编程技巧之一。 416 | 417 | 然而80286之后,这个地址线啊,多了几条。为了保留这个技巧,Intel搞了个A20Gate 418 | 419 | 实模式下,这个A20Gate是关闭。关闭时,按早8086的地址回绕特性进行寻址 420 | 421 | 进入保护模式前,需要先打开A20Gate,解放高位地址线的开关 422 | 423 | ```assembly 424 | in al,0x92 425 | or al,0000_0010B 426 | out 0x92,al 427 | ``` 428 | 429 | 上述指令可以打开A20Gate 430 | 431 | ## 保护模式的开关,CR0寄存器的PE位 432 | 433 | CRx寄存器,Control Register,用于控制CPU的运行机制,或者用于展示CPU的内部状态。 434 | 435 | 想要进入保护模式,就得将CR0的PE位设置为1 436 | 437 | - CR0寄存器的长度:32bits 438 | 439 | | 31 | 30 | 29 | 28\~19 | 18 | 17 | 16 | 15\~6 | 5 | 4 | 3 | 2 | 1 | 0 | 440 | | ---- | ---- | ---- | ------ | ---- | ---- | ---- | ----- | ---- | ---- | ---- | ---- | ---- | ---- | 441 | | PG | CD | NW | 保留 | AM | 保留 | WP | 保留 | NE | ET | TS | EM | MP | PE | 442 | 443 | | 标志位 | 描述 | 444 | | ------ | -------------------------------- | 445 | | PE | Protection Enable | 446 | | MP | Monitor coProcessor/Math Present | 447 | | EM | Emulation | 448 | | TS | Task Switched | 449 | | ET | Extention Type | 450 | | NE | Numeric Error | 451 | | WP | Write Protect | 452 | | AM | Alignment Mask | 453 | | NW | Not Writethrough | 454 | | CD | Cache Disable | 455 | | PG | Paging | 456 | 457 | - PE = 0,表示在实模式下运行 458 | - PE = 1,表示在保护模式下运行 459 | 460 | ```assembly 461 | mov eax,cr0 462 | or eax,0x00000001 463 | mov cr0,eax 464 | ``` 465 | 466 | ## 进入保护模式 467 | 468 | 看代码咯,没啥好说的了。 469 | 470 | 更新了`./include/boot.inc`和`./loader.s` 471 | 472 | ## 保护模式之内存段的保护 473 | 474 | ### 通用策略 475 | 476 | 1. 首先根据选择子的值来验证段段描述符是否越界 477 | 478 | 其实就是GDT数组的长度检测。越界访问了自然要报错 479 | 480 | 描述符表基址 + 选择子中的索引值*+7 <= 描述符表基址 + 描述符表界限值 481 | 482 | 以及0号选择子不可用 483 | 484 | 2. type检查 485 | 486 | 检查段寄存器的用途和类型是否和段类型匹配 487 | 488 | - 只有具备可执行属性的段(代码段)**才能加载到 cs 段寄存器**中。 489 | - 只具备执行属性的段(代码段)**不允许加载到除 cs 外的段寄存器**中。 490 | - 只有具备可写属性的段(数据段)**才能加载到 SS 栈段寄存器**中。 491 | - 至少具备可读属性的段**才能加载到 DS、ES 、FS、 GS 段寄存器**中。 492 | 493 | 如果 CPU 发现有任意上述规则不符,检查就不会通过。 494 | 495 | 3. 状态检查 496 | 497 | 检查P位以确认内存段是否存在。 498 | 499 | 如果P = 1,则说明段存在,可以将选择子载入段寄存器。将A 置为 1 500 | 501 | P值由软件检查(程序员撰写逻辑),A位由CPU自动检查 502 | 503 | ### 代码段和数据段的数据越界检查 504 | 505 | > 实在没办法才插入一张图。 506 | > 回头整理博客的时候会把这张图重新放进去的。github就只能sorry了 507 | 508 | ![image-20200625171352185](C:\Users\23719\AppData\Roaming\Typora\typora-user-images\image-20200625171352185.png) 509 | 510 | 如图所示。不管是数据段还是代码段,如果出现了访问上述的这种越界数据,CPU会抛出异常。 511 | 512 | 代码,数据,**应当完整的存放在段内**,不得越界。 513 | 514 | ### 栈段的保护策略 515 | 516 | (待补充) 517 | 518 | ## 编译、虚拟硬盘读写,运行虚拟机 519 | 520 | 下面这些代码已经写成shell文件放在Cpt4文件夹里头了 521 | 522 | ```shell 523 | cd Kernel-Learning/ 524 | cd Cpt4.Rudiment\ of\ Protect\ Mode/ 525 | nasm -o ./mbr.bin ./mbr.s 526 | nasm -o ./loader.bin ./loader.s 527 | cd .. 528 | dd if=./Cpt4.Rudiment\ of\ Protect\ Mode/mbr.bin of=./bochs/bin/hd60M.img bs=512 count=1 conv=notrunc 529 | dd if=./Cpt4.Rudiment\ of\ Protect\ Mode/loader.bin of=./bochs/bin/hd60M.img bs=512 count=4 conv=notrunc seek=2 530 | cd ./bochs/bin 531 | ./bochs -f ./bochsrc.disk 532 | ``` 533 | 534 | ## 书本勘误 535 | 536 | 160页,代码boot.inc,下面是原文代码 537 | 538 | ```assembly 539 | DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 +\ 540 | DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + DESC_P + \ 541 | DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00 542 | ``` 543 | 544 | 最后的0x00得改成0x0b,否则后边儿loader.bin运行的时候写入的字符'P'就不在显存里头了。原理请结合GDT的结构理解。 545 | 546 | 修改后的代码 547 | 548 | ```assembly 549 | DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 +\ 550 | DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + DESC_P + \ 551 | DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x0b 552 | ``` 553 | 554 | 555 | 556 | # FIN 557 | 558 | 178页 559 | 560 | -------------------------------------------------------------------------------- /Cpt4.Rudiment of Protect Mode/include/boot.inc: -------------------------------------------------------------------------------- 1 | ;________loader & kernel________ 2 | LOADER_BASE_ADDR equ 0x900 3 | LOADER_START_SECTOR equ 0x2 4 | 5 | ;________gdt描述符属性________ 6 | DESC_G_4K EQU 1_00000000000000000000000b 7 | DESC_D_32 EQU 1_0000000000000000000000b 8 | DESC_L EQU 0_000000000000000000000b 9 | ;64位代码标记,此处标记为0即可 10 | DESC_AVL EQU 0_00000000000000000000b 11 | DESC_LIMIT_CODE2 EQU 1111_0000000000000000b 12 | DESC_LIMIT_DATA2 EQU DESC_LIMIT_CODE2 13 | DESC_LIMIT_VIDEO2 EQU 0000_000000000000000b 14 | DESC_P EQU 1_000000000000000b 15 | DESC_DPL_0 EQU 00_0000000000000b 16 | DESC_DPL_1 EQU 01_0000000000000b 17 | DESC_DPL_2 EQU 10_0000000000000b 18 | DESC_DPL_3 EQU 11_0000000000000b 19 | DESC_S_CODE equ 1_000000000000b 20 | DESC_S_DATA equ DESC_S_CODE 21 | DESC_S_sys equ 0_000000000000b 22 | DESC_TYPE_CODE equ 1000_00000000b 23 | ;x=1,c=O,r=O,a=O 代码段是可执行的,非一致性,不可读,已访问位a清0。 24 | DESC_TYPE_DATA equ 0010_00000000b 25 | ;x=O,e=O,w=1,a=O 数据段是不可执行的,向上扩展的,可写,己访问位a清0。 26 | DESC_CODE_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 27 | DESC_L + DESC_AVL + DESC_LIMIT_CODE2 + \ 28 | DESC_P+DESC_DPL_0 + DESC_S_CODE +\ 29 | DESC_TYPE_CODE + 0x00 30 | DESC_DATA_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 +\ 31 | DESC_L + DESC_AVL + DESC_LIMIT_DATA2 + \ 32 | DESC_P + DESC_DPL_0 + DESC_S_DATA + \ 33 | DESC_TYPE_DATA + 0x00 34 | DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 +\ 35 | DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + DESC_P + \ 36 | DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x0b 37 | ;选择子属性 38 | RPL0 EQU 00b 39 | RPL1 EQU 01b 40 | RPL2 EQU 10b 41 | RPL3 EQU 11b 42 | TI_GDT EQU 000b 43 | TI_LDT EQU 100b -------------------------------------------------------------------------------- /Cpt4.Rudiment of Protect Mode/loader.s: -------------------------------------------------------------------------------- 1 | %include "./include/boot.inc" 2 | SECTION LOADER vstart=LOADER_BASE_ADDR 3 | LOADER_STACK_TOP equ LOADER_BASE_ADDR 4 | 5 | jmp loader_start 6 | 7 | ;构建gdt及其内部的描述符 8 | GDT_BASE: 9 | dd 0x00000000 10 | dd 0x00000000 11 | CODE_DESC: 12 | dd 0x0000ffff 13 | dd DESC_CODE_HIGH4 14 | DATA_STACK_DESC: 15 | dd 0x0000ffff 16 | dd DESC_DATA_HIGH4 17 | VIDEO_DESC: 18 | dd 0x8000_0007;limit = (0xbffff - b8000)/4k = 0x7 19 | dd DESC_VIDEO_HIGH4 ;此时DPL为0 20 | GDT_SIZE equ $ - GDT_BASE 21 | GDT_LIMIT equ GDT_SIZE - 1 22 | times 60 dq 0 ;此处预留60个描述符空位 23 | 24 | ;选择子 25 | SELECTOR_CODE equ (0x0001<<3) + TI_GDT + RPL0 26 | SELECTOR_DATA equ (0x0002<<3) + TI_GDT + RPL0 27 | SELECTOR_VIDEO equ (0x003<<3) + TI_GDT + RPL0 28 | 29 | ;以下是gdt的指针,前2字节是gdt界限,后4字节是gdt起始地址 30 | gdt_ptr dw GDT_LIMIT 31 | dd GDT_BASE 32 | 33 | loadermsg db '2 loader in real' 34 | 35 | loader_start: 36 | mov sp,LOADER_BASE_ADDR 37 | mov bp,loadermsg 38 | mov cx,17 39 | mov ax,0x1301 40 | mov bx,0x001f 41 | mov dx,0x1800 42 | int 0x10 43 | ;_________准备进入保护模式___________ 44 | ;1.打开A20Gate 45 | ;2.加载gdt 46 | ;3.将cr0的PE位置1 47 | ;-------------打开A20Gate------------- 48 | in al,0x92 49 | or al,0000_0010B 50 | out 0x92,al 51 | ;------------ 加载GDT ------------ 52 | lgdt [gdt_ptr] 53 | ;------------cr0的PE位置为1------------ 54 | mov eax,cr0 55 | or eax,0x0000_0001 56 | mov cr0,eax 57 | 58 | jmp dword SELECTOR_CODE:p_mode_start;刷新流水线 59 | 60 | ;进入保护模式 61 | [bits 32] 62 | p_mode_start: 63 | mov ax,SELECTOR_DATA 64 | mov ds,ax 65 | mov es,ax 66 | mov ss,ax 67 | mov esp,LOADER_STACK_TOP 68 | mov ax,SELECTOR_VIDEO 69 | mov gs,ax 70 | 71 | mov byte [gs:160],'P' 72 | jmp $ -------------------------------------------------------------------------------- /Cpt4.Rudiment of Protect Mode/mbr.s: -------------------------------------------------------------------------------- 1 | %include "./include/boot.inc" 2 | SECTION MBR vstart=0x7c00 3 | mov ax,cs 4 | mov ds,ax 5 | mov es,ax 6 | mov ss,ax 7 | mov fs,ax 8 | mov sp,0x7c00 9 | mov ax,0xb800 10 | mov gs,ax 11 | 12 | ;清屏功能 13 | mov ax,0x600 14 | mov bx,0x700 15 | mov cx,0 16 | mov dx,0x184f 17 | int 0x10 18 | 19 | ;获取光标未知 20 | ;输出:cl:光标开始行,cl:光标结束行 21 | ; dl:光标所在行号,dl:光标所在列号 22 | 23 | ; 打印字符串 24 | mov byte [gs:0x00],'l' 25 | mov byte [gs:0x01],0xA4 26 | 27 | mov byte [gs:0x02],' ' 28 | mov byte [gs:0x03],0xA4 29 | 30 | mov byte [gs:0x04],'M' 31 | mov byte [gs:0x05],0xA4 32 | 33 | mov byte [gs:0x06],'B' 34 | mov byte [gs:0x07],0xA4 35 | 36 | mov byte [gs:0x08],'R' 37 | mov byte [gs:0x09],0xA4 38 | 39 | 40 | ;读取一个扇区(loader所在)道指定位置的内存中 41 | mov eax,LOADER_START_SECTOR ;硬盘中的lba地址 42 | mov bx,LOADER_BASE_ADDR ;写入的地址 43 | mov cx,4 ;读入的扇区数 44 | call rd_disk_m_16 45 | 46 | jmp LOADER_BASE_ADDR 47 | 48 | ; 函数rd_disk_m_16 49 | ; 功能:读取硬盘n个扇区 50 | ; eax = LBA硬盘号 51 | ; bx = 将数据写入的内存地址 52 | ; cx = 读入的扇区数 53 | rd_disk_m_16: 54 | mov esi,eax ;备份eax 55 | mov di,cx ;备份cx 56 | ;读写硬盘 57 | ;第一步:设置要读取的扇区数 58 | mov dx,0x1f2 ;指定读取的扇区数 59 | mov al,cl 60 | out dx,al 61 | mov eax,esi ;恢复ax 62 | 63 | ;第二部:将LBA地址存入0x1f3~0x1f6 64 | mov dx,0x1f3 65 | out dx,al 66 | 67 | mov cl,8 68 | shr eax,cl 69 | inc dx 70 | out dx,al 71 | 72 | shr eax,cl 73 | inc dx 74 | out dx,al 75 | 76 | shr eax,cl 77 | and al,0x0f 78 | or al,0xe0 79 | mov dx,0x1f6 80 | out dx,al 81 | ;第三步:向0x1f7端口写入读命令,0x20 82 | mov dx,0x1f7 83 | mov al,0x20 84 | out dx,al 85 | 86 | ;第四步:检测硬盘状态 87 | .not_ready: 88 | nop 89 | in al,dx 90 | and al,0x88 91 | cmp al,0x08 92 | jnz .not_ready 93 | ;第五步:0x1f0端口读取数据 94 | mov ax,di 95 | ;一次读取一个字,所以是512/2*di 96 | mov dx,256 97 | mul dx 98 | mov cx,ax 99 | mov dx,0x1f0 100 | .go_on_read: 101 | in ax,dx 102 | mov [bx],ax 103 | add bx,2 104 | loop .go_on_read 105 | ret 106 | 107 | times 510-($-$$) db 0 108 | db 0x55,0xaa 109 | -------------------------------------------------------------------------------- /Cpt4.Rudiment of Protect Mode/run_bochs.sh: -------------------------------------------------------------------------------- 1 | nasm -o ./mbr.bin ./mbr.s 2 | nasm -o ./loader.bin ./loader.s 3 | cd .. 4 | ./bochs/bin/bximage -mode=create -hd=60M -imgmode="flat" -q ./bochs/bin/hd60M.img 5 | dd if=./Cpt4.Rudiment\ of\ Protect\ Mode/mbr.bin of=./bochs/bin/hd60M.img bs=512 count=1 conv=notrunc 6 | dd if=./Cpt4.Rudiment\ of\ Protect\ Mode/loader.bin of=./bochs/bin/hd60M.img bs=512 count=4 conv=notrunc seek=2 7 | cd ./bochs/bin 8 | ./bochs -f ./bochsrc.disk 9 | rm ./hd60M.img 10 | -------------------------------------------------------------------------------- /Cpt5.A Step Close to Kernel/README.md: -------------------------------------------------------------------------------- 1 | # Cpt5.A Step Close to Kernel 2 | 3 | ## 获取物理内存容量 4 | 5 | linux系统使用`int 0x15`的三个子功能实现获取物理内存的总大小 6 | 7 | 注意:BIOS种端 8 | 9 | - 0xE820:遍历主机上全部内存 10 | - 0xE801:分别检测低15MB和16MB~4GB的内存,最大支持4GB 11 | - 0x88:最多检测64MB,实际内存超过64MB也按64MB返回 12 | 13 | ### 0xE820 14 | 15 | ```assembly 16 | ;第一次调用该功能时需要设置ebx为0 17 | mov ebx,0x00000000 18 | 19 | ;储存20字节内存段信息的缓冲区 20 | mov ax,data 21 | mov es,ax 22 | mov dx,0 23 | 24 | ;固定值,向缓冲区写入的数据 25 | mov cx,20 26 | ;固定值,校验码 27 | mov edx,0x534d4150 28 | ;子功能号 29 | mov eax,0x0000E820 30 | int 0x15 31 | ``` 32 | 33 | - **功能**:遍历主机上全部内存,并返回这一块内存的相关信息 34 | 35 | - **调用方法**: 36 | 37 | - 调用前输入 38 | 39 | **注**:若多次调用后的某一次ebx为0且cf不为1,则说明ARDS全部返回 40 | 41 | | 寄存器/状态位 | 参数用途 | 42 | | ------------- | ------------------------------------------------------------ | 43 | | EAX | 子功能号,0xE820 | 44 | | EBX | ARDS后续值:内存信息需要按类型分多次返回,由于每次执行一次中断都只返回一种类型内存的 ARDS 结构,所以要记录下一个待返回的内存 ARDS ,在下一次中断调用时通过 此值告诉 BIOS 该返回哪个 ARDS ,这就是后续值的作用.第一次调用时一定要置为 0,EBX 具体值我们不用关注,字取决于具体 BIOS 的实现.每次中断返回后, BIOS 会更新此值 | 45 | | ES:DI | ARDS缓冲区,BIOS将获取到的内存信息写入此寄存器指向的内存,每次都已ARDS格式返回 | 46 | | ECX | ARDS结构的字节大小:用来指示BIOS写入的字节数。调用者和BIOS都同时支持的大小是20字节,将来也许会扩展这个参数
换言之,调用前将它设置为20就对了 | 47 | | EDX | 固定为签名标记0x534d4150 ,此十六进制数是字符串SMAP的ASCII码,BIOS 将调用者正在请求的内存信息写入 ES: DI 寄存器所指向的ARDS缓冲区后,再用此签名校验其中的信息
换言之,调用中断前将其设置为0x534d4150即可 | 48 | 49 | - 调用后输出 50 | 51 | | 寄存器/状态位 | 参数用途 | 52 | | ------------- | ------------------------------------------------------------ | 53 | | CF位 | CF =0表示调用未出错, CF = 1表示调用出错 | 54 | | EAX | 字符串SMAP的ASCII码0x534d4150 | 55 | | ES:DI | ARDS 缓冲区地址,同输入值是一样的,返回时此结构中己经被 BIOS 填充了内存信息 | 56 | | ECX | 同调用前 | 57 | | EBX | 见调用前 | 58 | 59 | 60 | 61 | - **返回信息**(ARDS格式): 62 | 63 | 每次调用这个功能,顺序遍历一块内存,并返回这块内存的信息。信息共5个字段20字节 64 | 65 | | 字节偏移量 | 属性名称 | 描述 | 66 | | ---------- | ------------ | ------------------------------ | 67 | | 0 | BaseAddrLow | 基址的低32位 | 68 | | 4 | BaseAddrHigh | 基址的高32位 | 69 | | 8 | LengthLow | 内存长度的低32位,以字节为单位 | 70 | | 12 | LengthHigh | 内存长度的高32位,以字节为单位 | 71 | | 16 | Type | 本段内存的类型 | 72 | 73 | 其中,Type字段有三种类型 74 | 75 | | Type值 | 名称 | 描述 | 76 | | ------ | -------------------- | ------------------------------------------------------------ | 77 | | 1 | AddressRangeMemory | 这段内存可以被操作系统使用 | 78 | | 2 | AddressRangeReserved | 内存使用中或者被系统保留,操作系统不可以使用这一块内存 | 79 | | 其它 | 未定义 | 未定义,以后可能用到,目前保留。但是需要操作系统一样将其视为AddressRangeReserved | 80 | 81 | ### 0xE801 82 | 83 | - **功能**:分别检测低15MB和16MB~4GB的内存,最大支持4GB 84 | 85 | 两组检测分别储存在两组寄存器中 86 | 87 | 这个子程序是为了支持ISA服务而定义的。关于ISA服务导致的内存空洞,在后面的章节中有提到。 88 | 89 | - **调用方法**: 90 | 91 | ```assembly 92 | mov ax,0xE801 93 | int 0x15 94 | ``` 95 | 96 | 返回数据如下表 97 | 98 | | 寄存器/状态位 | 用途 | 说明 | 99 | | ------------- | ----------- | ------------------------------------------------------------ | 100 | | CF | Carry Flag | CF =0表示调用未出错, CF = 1表示调用出错 | 101 | | AX | Extended1 | 以1KB 为单位,只显示 15MB 以下的内存容量,故最大值为0x3c00,即 AX 表示的最大内存为 0x3c00\*1024= 15MB | 102 | | BX | Extended2 | 以64KB为单位,内存空间16MB\~4GB中连续的单位数量,即内存大小为 BX\*64\*1024 字节 | 103 | | CX | Configured1 | 同AX | 104 | | DX | Configured2 | 同BX | 105 | 106 | ### 0x88 107 | 108 | - **功能**:最多检测64MB,实际内存超过64MB也按64MB返回 109 | 110 | - **调用方式**: 111 | 112 | ```assembly 113 | mov ax,0x8800 114 | int 0x15 115 | ``` 116 | 117 | 返回数据如下表: 118 | 119 | | 寄存器/状态位 | 参数用途 | 120 | | ------------- | ------------------------------------------------------------ | 121 | | CF | CF =0表示调用未出错, CF = 1表示调用出错 | 122 | | AX | 以1KB 为单位,内存空间1MB以上连续的单位数量,不包括低端1MB内存,故内存大小位AX\*1024字节 + 1MB | 123 | 124 | ## 内存空洞 125 | 126 | 修改bochsrc.disk内的megs词条 127 | 128 | 使用int 15的0xE801获取内存信息的时候,会出现一些有趣的事情 129 | 130 | | megs词条 | AX | BX | 检测到的内存大小 | 131 | | -------- | ------ | ---- | -------------------------- | 132 | | 14MB | 0x3400 | 0 | AX\*1024+BX\*64\*1024=13MB | 133 | | 15MB | 0x3800 | 0 | AX\*1024+BX\*64\*1024=14MB | 134 | | 16MB | 0x3c00 | 0 | AX\*1024+BX\*64\*1024=15MB | 135 | | 17MB | 0x3c00 | 0x10 | AX\*1024+BX\*64\*1024=16MB | 136 | | 18MB | 0x3c00 | 0x20 | AX\*1024+BX\*64\*1024=17MB | 137 | 138 | 嗯?为什么检测到的内存大小始终比我们在megs词条里头写的分配给bochs的内存要小1MB? 139 | 140 | ### 历史遗留问题:ISA设备 141 | 142 | 80286时期,有些ISA设备要用15MB~16MB的这段内存空间作为缓冲,也就是内存中有1MB作为缓冲区使用了 143 | 144 | 嗯,还是为了向下兼容。之后386的时代,这块内存就像个黑洞一样被保留下来了,成为了一个Memory hole。 145 | 146 | 有一些BIOS中可以设定开启或关闭ISA设备兼容。选项为: 147 | 148 | `memory hole at address 15m~16m` 149 | 150 | ## 内存分页与虚拟内存 151 | 152 | > 为什么每个程序都能把代码放在0x401000这个位置? 153 | > 154 | > 逆向工程逆用户程序逆的多了,就会想着进系统看看里头是些什么 155 | 156 | ### 内存为什么要分页 157 | 158 | 老生常谈的问题。引入部分就不再记录在笔记中。 159 | 160 | ### 分段机制和分页机制的关系 161 | 162 | 内存分段机制是IA32架构刻在DNA里头的东西,想寻址,就必须先经过分段访问内存。 163 | 164 | 所以,分页机制是建立在内存分段机制之上的。 165 | 166 | **在CPU没有打开分页机制的情况下**,是按默认的分段方式进行内存寻址的,段基址和段内偏移地址经过段部件处理后所输出的线性地址,CPU就认为是物理地址 167 | 168 | **如果打开了分页机制**,段部件输出的线性地址就不再等同于物理地址了,我们称之为虚拟地址。**虚拟地址只是逻辑上的地址,不能等同于物理地址**。CPU必须拿到物理地址才能进行物理内存寻址,**虚拟地址对应的物理地址需要在页表中查找**,这项查找工作是由**页部件自动完成**的。 169 | 170 | 要搞清楚页部件的工作原理,需要用清楚下面两个点 171 | 172 | 1. 分页机制的原理 173 | 2. 页表的结构 174 | 175 | ### 从进程的角度:分段与分页 176 | 177 | > 有过一些逆向工程或者PWN功底的同学都知道,一个二进制程序,其代码、数据被统一的储存在硬盘中。但是加载到内存中时,这些数据、代码又被分成不同的部分加载进了不同的内存段中。 178 | 179 | 对于一个正在运行的程序而言,其所有数据都在**属于他自己的虚拟内存空间中**,这些数据和代码通过分段机制分成了若干不同的内存段。对于这个进程而言,想要访问这些代码(数据),只需要使用线性地址即可。 180 | 181 | 但是,前面提到过,虚拟地址不能直接用于寻址。 182 | 183 | 这个进程的**各个段被分成了若干大小相同的内存页**,**分散的储存**在内存的不同位置。 184 | 185 | CPU拿到虚拟内存的线性地址后,**通过查询页表**,获取将要访问的内存页在物理内存中的实际位置。 186 | 187 | **总结**:计算机系统没有什么问题是不能多加一个中间层解决的。 188 | 189 | ## 一级页表 190 | 191 | 页表本身是一个映射表。高位用于指示其对应的物理内存的实际地址,低位用于指示该物理页的大小 192 | 193 | 页表项结构: 194 | 195 | | 31\~12 | 11\~0 | 196 | | -------------------------------------- | ---------- | 197 | | 内存页的物理地址($2^{20}$=1048576个) | 内存块信息 | 198 | 199 | ### 有关分页机制的两个注意点 200 | 201 | - 打开分页机制前,需要将页表的物理地址加载到控制寄存器cr3中,这是启动分页机制的先决条件之一。 202 | 203 | - 在利用分页机制将虚拟地址转化成物理地址的这一过程中,所有的计算都是在物理地址模式下进行的。要不就产生递归了 204 | 205 | ### 一级页表地址转换原理 206 | 207 | 1. 一个页表项对应一个页,用线性地址的高20位*4作为页表数组的索引获取内存页的物理地址 208 | 2. 内存页的物理地址 + 线性地址的低20位 = 需要访问的物理地址 209 | 3. 该算法通过CPU的页部件自动计算,无需操作系统担心。 210 | 211 | ## 二级页表 212 | 213 | ### 为什么需要二级页表 214 | 215 | - 一级页表最多容纳1048576个表项,每个表项是4字节。如果表全满,则页表需要占用4MB大小 216 | 现在别以为4MB没多大,要知道,我们给虚拟机配置的内存也就32MB 217 | - 一级页表必须在操作系统启动的时候就建立好。因为操作系统要占用4GB虚拟地址的1GB空间,用户进程要占用3GB空间。 218 | - 每个进程都有自己的页表,进程一多,光是页表占用的空间就很大很大了。 219 | 220 | 因此,我们需要动态的创建页表项。并且要做到每个进程都有自己的页表 221 | 222 | ### 二级页表的结构: 223 | 224 | 二级map映射 225 | 226 | - **页目录表**: 227 | 228 | **数量**:1024个 229 | 230 | **大小**:4kb(刚好一个内存页大小) 231 | 232 | **内容**:1024个页表的物理地址 233 | 234 | | 31\~12 | 11\~9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 235 | | ---------------------- | ----- | ---- | ----- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | 236 | | 页表物理页地址31\~12位 | AVL | G | **O** | D | A | PCD | PWT | US | RW | P | 237 | 238 | - **页表** 239 | 240 | **数量**:1个 241 | 242 | **大小**:4kb 243 | 244 | **内容**:1024个表项--实际的物理地址 245 | 246 | | 31\~12 | 11\~9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 247 | | ------------------ | ----- | ---- | ------- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | 248 | | 物理页地址31\~12位 | AVL | G | **PAT** | D | A | PCD | PWT | US | RW | P | 249 | 250 | - 各个位的含义: 251 | 252 | - **P**:Present ,存在位,若为1说明该页存在于物理内存中,为0说明不再物理内存中。操作系统的页式虚存管理概念是通过P位和相应的pagefault来实现的 253 | - **RW**: Read/write,若为1表示可读可写,若为0表示可读不可写 254 | - **US**:User/Supervisor,普通用户/超级用户位。若为1时,表示处于User级,特权0,1,2,3级都可以访问该页面。若为0时,Tier 3不允许访问该物理页。 255 | - **PWT**:Page-level Write-Through,意为页级通写位,也称页级写透位。若为1表示此项采用通写方式,表示该页不仅是普通内存,还是高速缓存。此项和高速缓存有关,”通写“高速缓存的一种工作方式,本位用来简介决定是否用此方式改善该页的访问效率。我们设置它为0 256 | - **PCD**:Page-level Cache Disable,意为页级高速缓存禁止位,若为1表示该页启用高速缓存,0表示禁止讲该页缓存。我们设置它为0 257 | - **A**:Accessed,若为1,说明CPU访问过这个页。由操作系统置0,用于统计访问次数,以做到外存交换。 258 | - **D**:Dirty ,意为脏页位。当CPU对一个页面执行写操作时,就会设置对应表项为1.此项仅对页表想有效,并且不会修该页目录项中的D位。 259 | - **PAT**:Page Attribute Table ,意为页属性位表,能够在页面一级的粒度上设置内存属性,比较复杂,这里我们设置为0 260 | - **G**:Global,意为全局位。由于内存地址转换颇费周折,先得拆分虚拟地址,又要查页目录,又要查页表,所以为了提高获取物理地址的速度,将虚拟地址与物理地址的转换结果储存在TLB中。TLB用来缓存转换结果的高速缓存。 261 | - **AVL**,Available,表示可用。CPU不理会这个位,软件/操作系统可用这个位。 262 | 263 | ### 二级页表的寻址方式 264 | 265 | - 线性地址的结构 266 | 267 | | 31\~22 | 21\~12 | 11\~0 | 268 | | ------------------------------------- | ------------------ | ------ | 269 | | 作为页目录表数组的索引$2^{10}$ = 1024 | 作为页表数组的索引 | offset | 270 | 271 | 1. 高10位\*4作为页目录表的索引,找到页表的物理地址 272 | 2. 中间10位*4作为页表的索引,找到物理页的物理地址 273 | 3. 物理页地址 + offset = 需要访问的物理地址,直接送上总线 274 | 275 | ## 启动分页机制需要做的事情 276 | 277 | 1. 准备好页目录表和页表 278 | 2. 将页表地址写入cr3 279 | 3. 寄存器cr0的PG位置为1 280 | 281 | ### 将页目录表地址写入cr3 282 | 283 | cr3的结构: 284 | 285 | | 31\~12 | 11\~5 | 4 | 3 | 2 | 1 | 0 | 286 | | ---------------- | ----- | ---- | ---- | ---- | ---- | ---- | 287 | | 页目录表物理地址 | | PCD | PWT | | | | 288 | 289 | 我们只需要把上表中写出来的东西放进去就好。PCD,PWT置0 290 | 291 | ```assembly 292 | mov eax,cr3 293 | mov eax,ADDR_OF_PDE 294 | mov cr3,eax 295 | ``` 296 | 297 | ### 将cr0的PG位置0 298 | 299 | ```assembly 300 | mov eax,cr0 301 | or eax,0x80000000 302 | mov cr0,eax 303 | ``` 304 | 305 | ## 规划页表:操作系统与用户进程的关系 306 | 307 | 操作系统必须共享给所有用户进程。但是用户能用哪些功能,由操作系统决定,不是用户想用什么就用什么。 308 | 309 | 如何规划:操作系统属于用户进程的虚拟地址空间。 310 | 311 | 我们决定这样来做: 312 | 313 | | 3~4GB | 操作系统空间 | 314 | | ----- | ------------ | 315 | | 0~3GB | 用户进程空间 | 316 | 317 | 我们的操作系统内核比较简单,所以占用内存量少,最终大小在70kb左右。我们选择把操作系统加载在0\~0xfffff这个区间的物理内存内,然后把这块物理内存映射到虚拟内存的高位地址。 318 | 319 | ## 加载内核 320 | 321 | ### 用C写内核:记得设置编译器参数 322 | 323 | C语言是最贴近底层的语言,一方面出于其设计,另一方面便是其编译过程的高度可定制性。 324 | 325 | 我们在学习C语言过程中使用的DEV-CPP,VS等IDE生成的PE文件/ELF文件,都是打包好的二进制文件。我们所写的代码只是这些文件中的一部分。 326 | 327 | 这些打包好的二进制文件,其中的代码运行时或多或少**要依赖其操作系统。** 328 | 329 | 现在我们自己写操作系统,自然就不能有这些依赖项。所有的功能都得从0开始写。 330 | 331 | ```bash 332 | gee -c -o main.o main.c 333 | ld main.o -Ttext Oxc0001500 -e main -o kernel.bin 334 | rm ./main.o 335 | dd if=kernel.bin of=/yourpath/hd60M.img bs=512 count=200 seek=9 conv=notrunc 336 | ``` 337 | 338 | gcc -c参数:生成文件不进行链接 339 | 340 | ld:连接器。 341 | 342 | - -Ttext :指定起始虚拟地址 343 | - -e:entry ADDRESS,设置程序起始的地址。可以用符号名代替 344 | - -o:output,最终的输出文件 345 | 346 | ### 测试用的短代码 347 | 348 | ```c 349 | int main(void){ 350 | while(1); 351 | return 0; 352 | } 353 | ``` 354 | 355 | 如果前面列出的ld指令不加入 -e参数指定程序起始位置,则可能报错。因为缺少_start符号。 356 | 357 | 我们也可以换一种写法 358 | 359 | ```c 360 | //ld main.o -Ttext Oxc0001500 -o kernel.bin 361 | int _start(void){ 362 | while(1); 363 | return 0; 364 | } 365 | ``` 366 | 367 | ### 解析ELF文件 368 | 369 | linux下连接器最终生成的是一个ELF文件。类似WINDOWS的PE文件,ELF文件的结构大致可以描述如下 370 | 371 | | 结构体 | 含义 | 372 | | ---------- | ------------------------------------------------------------ | 373 | | ELF header | 描述elf文件的基本信息
描述elf文件主体的分段信息和段偏移等内容
程序入口地址
…… | 374 | | 代码段 | …… | 375 | | 若干数据段 | …… | 376 | | ………… | …… | 377 | 378 | 有关elf头,可以在`/usr/include/elf.h`中找到。这里不再赘述其中各个变量的作用。 379 | 380 | (反正比PE头简洁) 381 | 382 | ```c 383 | #define EI_NIDENT (16) 384 | typedef struct 385 | { 386 | unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ 387 | Elf32_Half e_type; /* Object file type */ 388 | Elf32_Half e_machine; /* Architecture */ 389 | Elf32_Word e_version; /* Object file version */ 390 | Elf32_Addr e_entry; /* Entry point virtual address */ 391 | Elf32_Off e_phoff; /* Program header table file offset */ 392 | Elf32_Off e_shoff; /* Section header table file offset */ 393 | Elf32_Word e_flags; /* Processor-specific flags */ 394 | Elf32_Half e_ehsize; /* ELF header size in bytes */ 395 | Elf32_Half e_phentsize; /* Program header table entry size */ 396 | Elf32_Half e_phnum; /* Program header table entry count */ 397 | Elf32_Half e_shentsize; /* Section header table entry size */ 398 | Elf32_Half e_shnum; /* Section header table entry count */ 399 | Elf32_Half e_shstrndx; /* Section header string table index */ 400 | } Elf32_Ehdr;。 401 | ``` 402 | 403 | 然后下边这个是section头结构体 404 | 405 | ```c 406 | typedef struct 407 | { 408 | Elf64_Word p_type; /* Segment type */ 409 | Elf64_Word p_flags; /* Segment flags */ 410 | Elf64_Off p_offset; /* Segment file offset */ 411 | Elf64_Addr p_vaddr; /* Segment virtual address */ 412 | Elf64_Addr p_paddr; /* Segment physical address */ 413 | Elf64_Xword p_filesz; /* Segment size in file */ 414 | Elf64_Xword p_memsz; /* Segment size in memory */ 415 | Elf64_Xword p_align; /* Segment alignment */ 416 | } Elf64_Phdr; 417 | ``` 418 | 419 | ### 将内核加载进内存 420 | 421 | Loader.s的任务即将完成,不过还有两个功能需要写进去: 422 | 423 | 1. 将内核文件读取进内存 424 | 2. 分析内存中的elf文件并加载入相应的虚拟地址。 425 | 426 | 想要完成第一个任务,我们先得搞定内存布局先。到现在为止,我们的系统的布局如下: 427 | 428 | | 物理地址起点 | 物理地址终点 | 内存空间大小 | 用途 | 429 | | ------------ | ------------ | ------------ | ------------------- | 430 | | 0x9fc00 | 0x9ffff | 1K | EBDA扩展bios数据区 | 431 | | 0x7e00 | 0x9fbff | 约608k | 可用区域 | 432 | | 0x7c00 | 0x7dff | 512B | MBR被BIOS加载到此处 | 433 | | 0x500 | 0x7bff | 约30K | 可用区域 | 434 | | 0x400 | 0x4ff | 256B | BIOS Data Area | 435 | | 0x000 | 0x3ff | 1k | 中断向量表 | 436 | 437 | 我们这里就按照课本的步骤来,将内核加载到0x70000这个位置。 438 | 439 | 0x70000~0x9fbff有190kb的大小。对于一个纯代码+少量数据构成的简易内核,这190kb是足够大的了。 440 | 441 | 内核栈选取在物理地址0x900,虚拟地址0xc0000900的位置。 442 | 443 | 加载完内核之后,mbr+loader的任务就都结束了。接下来正式进入内核阶段。 444 | 445 | ## 特权级 446 | 447 | > 未完待续 448 | > 449 | > 这个坑也许不会填?先立个flag -------------------------------------------------------------------------------- /Cpt5.A Step Close to Kernel/include/boot.inc: -------------------------------------------------------------------------------- 1 | ;________loader & kernel________ 2 | LOADER_BASE_ADDR equ 0x900 3 | LOADER_START_SECTOR equ 0x2 4 | PAGE_DIR_TABLE_POS equ 0x100000 5 | KERNEL_BIN_BASE_ADDR equ 0x70000 6 | KERNEL_START_SECTOR equ 0x9 7 | KERNEL_ENTRY_POINT equ 0xc0001500 8 | 9 | ;________gdt描述符属性________ 10 | DESC_G_4K EQU 1_00000000000000000000000b 11 | DESC_D_32 EQU 1_0000000000000000000000b 12 | DESC_L EQU 0_000000000000000000000b 13 | ;64位代码标记,此处标记为0即可 14 | DESC_AVL EQU 0_00000000000000000000b 15 | DESC_LIMIT_CODE2 EQU 1111_0000000000000000b 16 | DESC_LIMIT_DATA2 EQU DESC_LIMIT_CODE2 17 | DESC_LIMIT_VIDEO2 EQU 0000_000000000000000b 18 | DESC_P EQU 1_000000000000000b 19 | DESC_DPL_0 EQU 00_0000000000000b 20 | DESC_DPL_1 EQU 01_0000000000000b 21 | DESC_DPL_2 EQU 10_0000000000000b 22 | DESC_DPL_3 EQU 11_0000000000000b 23 | DESC_S_CODE equ 1_000000000000b 24 | DESC_S_DATA equ DESC_S_CODE 25 | DESC_S_sys equ 0_000000000000b 26 | DESC_TYPE_CODE equ 1000_00000000b 27 | ;x=1,c=O,r=O,a=O 代码段是可执行的,非一致性,不可读,已访问位a清0。 28 | DESC_TYPE_DATA equ 0010_00000000b 29 | ;x=O,e=O,w=1,a=O 数据段是不可执行的,向上扩展的,可写,己访问位a清0。 30 | DESC_CODE_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 31 | DESC_L + DESC_AVL + DESC_LIMIT_CODE2 + \ 32 | DESC_P+DESC_DPL_0 + DESC_S_CODE +\ 33 | DESC_TYPE_CODE + 0x00 34 | DESC_DATA_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 +\ 35 | DESC_L + DESC_AVL + DESC_LIMIT_DATA2 + \ 36 | DESC_P + DESC_DPL_0 + DESC_S_DATA + \ 37 | DESC_TYPE_DATA + 0x00 38 | DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 +\ 39 | DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + DESC_P + \ 40 | DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x0b 41 | ;选择子属性 42 | RPL0 EQU 00b 43 | RPL1 EQU 01b 44 | RPL2 EQU 10b 45 | RPL3 EQU 11b 46 | TI_GDT EQU 000b 47 | TI_LDT EQU 100b 48 | 49 | ;__________ 页表相关属性 ___________ 50 | 51 | PG_P equ 1b 52 | PG_RW_R EQU 00b 53 | PG_RW_W EQU 10b 54 | PG_US_S EQU 000b 55 | PG_US_U EQU 100b 56 | 57 | ;------------- program type 定义 -------------- 58 | PT_NULL equ 0 59 | -------------------------------------------------------------------------------- /Cpt5.A Step Close to Kernel/kernel/main.c: -------------------------------------------------------------------------------- 1 | int main(void){ 2 | while(1); 3 | return 0; 4 | } -------------------------------------------------------------------------------- /Cpt5.A Step Close to Kernel/loader.s: -------------------------------------------------------------------------------- 1 | %include "./include/boot.inc" 2 | SECTION LOADER vstart=LOADER_BASE_ADDR 3 | LOADER_STACK_TOP equ LOADER_BASE_ADDR 4 | jmp loader_start 5 | ;构建gdt及其内部的描述符 6 | GDT_BASE: 7 | dd 0x00000000 8 | dd 0x00000000 9 | CODE_DESC: 10 | dd 0x0000ffff 11 | dd DESC_CODE_HIGH4 12 | DATA_STACK_DESC: 13 | dd 0x0000ffff 14 | dd DESC_DATA_HIGH4 15 | VIDEO_DESC: 16 | dd 0x8000_0007;limit = (0xbffff - b8000)/4k = 0x7 17 | dd DESC_VIDEO_HIGH4 ;此时DPL为0 18 | GDT_SIZE equ $ - GDT_BASE 19 | GDT_LIMIT equ GDT_SIZE - 1 20 | times 60 dq 0 ;此处预留60个描述符空位 21 | ;选择子 22 | SELECTOR_CODE equ (0x0001<<3) + TI_GDT + RPL0 23 | SELECTOR_DATA equ (0x0002<<3) + TI_GDT + RPL0 24 | SELECTOR_VIDEO equ (0x003<<3) + TI_GDT + RPL0 25 | ;total_mem_bytes 用于保存用户的内存容量,以字节为单位,此位置比较好标记 26 | ;当前偏移loader.bin文件头0x200字节;loader.bin的加载地址是0x900 27 | ;故total_mem_bytes内存中的地址是0xb00;将来内核会引用这个地址。 28 | total_mem_bytes dd 0 29 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 30 | ;以下是gdt的指针,前2字节是gdt界限,后4字节是gdt起始地址 31 | gdt_ptr dw GDT_LIMIT 32 | dd GDT_BASE 33 | 34 | 35 | ;人工对齐:total_mem_bytes4+gdt_ptr6+ards_buf244+ards_nr2,共256字节 36 | ards_buf times 244 db 0 ;用于记录ARDS结构体数量 37 | ards_nr dw 0 38 | loadermsg db '2 loader in real' 39 | loader_start: 40 | 41 | ;获取内存布局 42 | 43 | xor ebx,ebx ;第一次执行时。ebx需要为0 44 | mov edx,0x534d4150 ;edx在调用中断前后不会改变 45 | mov di,ards_buf ;ards结构缓冲区 46 | .e820_mem_get_loop: 47 | mov eax,0x0000e820 ;执行 int 0x15后,eax的直会发生变化,需要重置 48 | mov ecx,20 ;ards的大小是20字节 49 | int 0x15 50 | jc .e820_failed_so_try_e801 51 | add di,cx 52 | inc word [ards_nr] ;记录ards数量 53 | cmp ebx,0 ;若ebx为0且cf不为1,说明ards全部返回 54 | jnz .e820_mem_get_loop 55 | 56 | ;在所有ards结构中,找出(base_add_low + length_low)的最大值,即内存的容量 57 | mov cx,[ards_nr] 58 | mov ebx,ards_buf 59 | xor edx,edx ;用edx记录最大内存容量,进入循环前先清0 60 | .find_max_mem_area: ;无需判断type是否为1,最大的内存块是一定可被使用的 61 | mov eax,[ebx] ;base_add_low 62 | add eax,[ebx+8] ;length_low 63 | add ebx,20 ;👈向下一个ARDS结构 64 | cmp edx,eax ;冒泡排序,找出最大,edx寄存器始终是最大的内存容量 65 | jge .next_ards 66 | mov edx,eax 67 | .next_ards: 68 | loop .find_max_mem_area 69 | jmp .mem_get_ok 70 | 71 | ;----- int 0x15h ax = E801H,获取内存大小---- 72 | ;返回后,ax,cx的值一样,以KB为单位,bx,dx值一样,以64KB为单位 73 | ;在ax和cx寄存器中为低16MB,在bx和dx寄存器中为16MB到4GB 74 | .e820_failed_so_try_e801: 75 | mov ax,0xe801 76 | int 0x15 77 | jc .e801_failed_so_try_88 ;还是失败,尝试0x88方法 78 | 79 | ;先算出低15MB的内存 ;ax和cx中是以KB为的单位的内存数量,将其转换为以byte为单位 80 | mov cx,0x400 ;cx和ax值一样 81 | mul cx 82 | shl edx,16 83 | and eax,0x0000FFFF 84 | or edx,eax 85 | add edx,0x100000 ;ax只是15MB,所以要加1MB 86 | mov esi,edx ;先把低15MB的内存存入esi寄存器备份 87 | 88 | ;再算出16MB以上的内存转换为byte为单位,寄存器bx和dx中是以64KB为单位的内存数量 89 | xor eax,eax 90 | mov ax,bx 91 | mov ecx,0x10000 ;0x10000十进制为64KB 92 | mul ecx 93 | add esi,eax 94 | mov edx,esi 95 | jmp .mem_get_ok 96 | 97 | ;-------- int 0x15h ah = 0x88 ------- 98 | .e801_failed_so_try_88: 99 | ;int 0x15后,ax存入的是以KB为单位的内存容量 100 | mov ah,0x88 101 | int 0x15 102 | jc .error_hlt 103 | and eax,0x0000FFFF 104 | mov cx, 0x400 105 | mul cx 106 | shl edx,0x16 107 | or edx,eax 108 | add edx,0x100000 ;0x88子功能指挥调用1MB以上的内存,故实际内存要加上1MB 109 | .mem_get_ok: ; 0xcb9 110 | mov [total_mem_bytes],edx 111 | jmp .done 112 | .error_hlt: 113 | mov byte [gs:0x160+0],'F' 114 | mov byte [gs:0x160+2],'a' 115 | mov byte [gs:0x160+4],'i' 116 | mov byte [gs:0x160+6],'l' 117 | jmp $ 118 | .done: 119 | mov byte [gs:0x160+0],'S' 120 | mov byte [gs:0x160+2],'u' 121 | mov byte [gs:0x160+4],'c' 122 | mov byte [gs:0x160+6],'c' ;0xcec 123 | ; 进入保护模式 124 | mov sp,LOADER_BASE_ADDR 125 | mov bp,loadermsg 126 | mov cx,17 127 | mov ax,0x1301 128 | mov bx,0x001f 129 | mov dx,0x1800 130 | int 0x10 131 | ;_________准备进入保护模式___________ 132 | ;1.打开A20Gate 133 | ;2.加载gdt 134 | ;3.将cr0的PE位置1 135 | ;-------------打开A20Gate------------- 136 | in al,0x92 137 | or al,0000_0010B 138 | out 0x92,al 139 | ;------------ 加载GDT ------------ 140 | lgdt [gdt_ptr] 141 | ;------------cr0的PE位置为1------------ 142 | mov eax,cr0 143 | or eax,0x0000_0001 144 | mov cr0,eax 145 | 146 | jmp dword SELECTOR_CODE:p_mode_start;刷新流水线 147 | 148 | ;进入保护模式 149 | [bits 32] 150 | p_mode_start: 151 | mov ax,SELECTOR_DATA ;0xd23 152 | mov ds,ax 153 | mov es,ax 154 | mov ss,ax 155 | mov esp,LOADER_STACK_TOP 156 | mov ax,SELECTOR_VIDEO 157 | mov gs,ax 158 | 159 | mov byte [gs:320],'P' 160 | ; ------------------------- 加载kernel ---------------------- 161 | mov eax, KERNEL_START_SECTOR ; kernel.bin所在的扇区号 162 | mov ebx, KERNEL_BIN_BASE_ADDR ; 从磁盘读出后,写入到ebx指定的地址 163 | mov ecx, 200 ; 读入的扇区数 164 | call rd_disk_m_32 ;0xd54 165 | ;----------初始化页内存图 ----------- 166 | call setup_page ;0xd8d 167 | 168 | ;将描述符表地址及偏移量写入内存gdt_ptr,一会儿用新地址重新加载 169 | sgdt [gdt_ptr] 170 | ;将gdt描述符中显存段描述符中的段基址增加0xc0000000 171 | mov ebx,[gdt_ptr + 2] 172 | or dword [ebx + 0x18 +4],0xc0000000 173 | ;视频段是第三个段描述符,每个描述符是8个字节,故0x18 174 | ;段描述符的高4字节的最高为是段基址的第31~24位 175 | 176 | ;将gdt的基址加上0xc0000000使其成为内核所在的高地址 177 | add dword [gdt_ptr +2],0xc0000000 178 | add esp,0xc0000000 179 | 180 | ;把页目录储存于cr3 181 | mov eax, PAGE_DIR_TABLE_POS 182 | mov cr3, eax 183 | 184 | ;打开cr0的pg位 185 | mov eax,cr0 186 | or eax, 0x80000000 187 | mov cr0,eax 188 | 189 | ;在开启分页后,用gdt新的地址重新加载 190 | lgdt [gdt_ptr] 191 | mov byte[gs:160],'V' 192 | jmp SELECTOR_CODE:enter_kernel 193 | enter_kernel: 194 | call kernel_init ;addr:0xda6 195 | mov esp,0xc009f000 196 | jmp KERNEL_ENTRY_POINT 197 | 198 | 199 | ;----------创建页目录及页表 ----------- 200 | setup_page: 201 | ;先把页目录占用的空间逐字节清0 202 | mov ecx,4096 203 | mov esi,0 204 | .clear_page_dir: 205 | mov byte [PAGE_DIR_TABLE_POS + esi],0 206 | inc esi 207 | loop .clear_page_dir 208 | ;开始创建页目录项(PDE) 209 | .create_pde: 210 | mov eax,PAGE_DIR_TABLE_POS 211 | add eax,0x10000 ;第一个页表的位置及属性 212 | mov ebx,eax ;为.create_pte做准备,ebx为基址 213 | 214 | ; 下面将页目录项0和0xc00都存为第一个页表的地址,每个页表示4MB内存 215 | ; 这样0xc03ffffff以下的地址和0x003fffff以下的地址都指向相同的页表 216 | ; 这是为了将地址映射为内核地址做准备 217 | or eax,PG_US_U | PG_RW_W | PG_P 218 | mov [PAGE_DIR_TABLE_POS + 0x0],eax 219 | mov [PAGE_DIR_TABLE_POS + 0x0c00],eax ;第768个页表,之后属于内核空间 220 | ;0xc0000000 ~ 0xffffffff共计1G属于内核 221 | sub eax,0x1000 222 | mov [PAGE_DIR_TABLE_POS + 4092],eax;使用最后一个目录👈向页目录表自己 223 | 224 | ;创建 PTE 225 | mov ecx,256 226 | mov esi,0 227 | mov edx, PG_US_U|PG_RW_W|PG_P 228 | .create_pte: 229 | mov [ebx+esi*4],edx 230 | add edx,4096 231 | inc esi 232 | loop .create_pte 233 | 234 | ;创建内核其他页表的PTE 235 | mov eax,PAGE_DIR_TABLE_POS 236 | add eax,0x2000 ;eax为第二个页表的位置 237 | mov eax, PG_US_U|PG_RW_W|PG_P 238 | mov ebx,PAGE_DIR_TABLE_POS 239 | mov ecx,254 ;范围769~1022的所有的目录项数量 240 | mov esi,769 241 | .create_kernel_pde: 242 | mov [ebx+esi*4],eax 243 | inc esi 244 | add eax,0x1000 245 | loop .create_kernel_pde 246 | ret 247 | 248 | ;----------------- 将kernel.bin中的segment拷贝到编译的地址 ----------- 249 | kernel_init: 250 | xor eax, eax 251 | xor ebx, ebx ;ebx记录程序头表地址 252 | xor ecx, ecx ;cx记录程序头表中的program header数量 253 | xor edx, edx ;dx 记录program header尺寸,即e_phentsize 254 | 255 | mov dx, [KERNEL_BIN_BASE_ADDR + 42] ; 偏移文件42字节处的属性是e_phentsize,表示program header大小 256 | mov ebx, [KERNEL_BIN_BASE_ADDR + 28] ; 偏移文件开始部分28字节的地方是e_phoff,表示第1 个program header在文件中的偏移量 257 | ; 其实该值是0x34,不过还是谨慎一点,这里来读取实际值 258 | add ebx, KERNEL_BIN_BASE_ADDR 259 | mov cx, [KERNEL_BIN_BASE_ADDR + 44] ; 偏移文件开始部分44字节的地方是e_phnum,表示有几个program header 260 | .each_segment: 261 | cmp byte [ebx + 0], PT_NULL ; 若p_type等于 PT_NULL,说明此program header未使用。 262 | je .PTNULL 263 | 264 | ;为函数memcpy压入参数,参数是从右往左依然压入.函数原型类似于 memcpy(dst,src,size) 265 | push dword [ebx + 16] ; program header中偏移16字节的地方是p_filesz,压入函数memcpy的第三个参数:size 266 | mov eax, [ebx + 4] ; 距程序头偏移量为4字节的位置是p_offset 267 | add eax, KERNEL_BIN_BASE_ADDR ; 加上kernel.bin被加载到的物理地址,eax为该段的物理地址 268 | push eax ; 压入函数memcpy的第二个参数:源地址 269 | push dword [ebx + 8] ; 压入函数memcpy的第一个参数:目的地址,偏移程序头8字节的位置是p_vaddr,这就是目的地址 270 | call mem_cpy ; 调用mem_cpy完成段复制 271 | add esp,12 ; 清理栈中压入的三个参数 272 | .PTNULL: 273 | add ebx, edx ; edx为program header大小,即e_phentsize,在此ebx指向下一个program header 274 | loop .each_segment 275 | ret 276 | 277 | ;---------- 逐字节拷贝 mem_cpy(dst,src,size) ------------ 278 | ;输入:栈中三个参数(dst,src,size) 279 | ;输出:无 280 | ;--------------------------------------------------------- 281 | mem_cpy: 282 | push ebp 283 | mov ebp, esp 284 | push ecx ; rep指令用到了ecx,但ecx对于外层段的循环还有用,故先入栈备份 285 | mov edi, [ebp + 8] ; dst 286 | mov esi, [ebp + 12] ; src 287 | mov ecx, [ebp + 16] ; size 288 | cld 289 | rep movsb ; 逐字节拷贝 290 | ;恢复环境 291 | pop ecx 292 | pop ebp 293 | ret 294 | 295 | ;------------------------------------------------------------------------------- 296 | ;功能:读取硬盘n个扇区 297 | rd_disk_m_32: 298 | ;------------------------------------------------------------------------------- 299 | ; eax=LBA扇区号 300 | ; ebx=将数据写入的内存地址 301 | ; ecx=读入的扇区数 302 | mov esi,eax ; 备份eax 303 | mov di,cx ; 备份扇区数到di 304 | ;读写硬盘: 305 | ;第1步:设置要读取的扇区数 306 | mov dx,0x1f2 307 | mov al,cl 308 | out dx,al ;读取的扇区数 309 | 310 | mov eax,esi ;恢复ax 311 | 312 | ;第2步:将LBA地址存入0x1f3 ~ 0x1f6 313 | 314 | ;LBA地址7~0位写入端口0x1f3 315 | mov dx,0x1f3 316 | out dx,al 317 | 318 | ;LBA地址15~8位写入端口0x1f4 319 | mov cl,8 320 | shr eax,cl 321 | mov dx,0x1f4 322 | out dx,al 323 | 324 | ;LBA地址23~16位写入端口0x1f5 325 | shr eax,cl 326 | mov dx,0x1f5 327 | out dx,al 328 | 329 | shr eax,cl 330 | and al,0x0f ;lba第24~27位 331 | or al,0xe0 ; 设置7~4位为1110,表示lba模式 332 | mov dx,0x1f6 333 | out dx,al 334 | 335 | ;第3步:向0x1f7端口写入读命令,0x20 336 | mov dx,0x1f7 337 | mov al,0x20 338 | out dx,al 339 | 340 | ;;;;;;; 至此,硬盘控制器便从指定的lba地址(eax)处,读出连续的cx个扇区,下面检查硬盘状态,不忙就能把这cx个扇区的数据读出来 341 | 342 | ;第4步:检测硬盘状态 343 | .not_ready: ;测试0x1f7端口(status寄存器)的的BSY位 344 | ;同一端口,写时表示写入命令字,读时表示读入硬盘状态 345 | nop 346 | in al,dx 347 | and al,0x88 ;第4位为1表示硬盘控制器已准备好数据传输,第7位为1表示硬盘忙 348 | cmp al,0x08 349 | jnz .not_ready ;若未准备好,继续等。 350 | 351 | ;第5步:从0x1f0端口读数据 352 | mov ax, di ;以下从硬盘端口读数据用insw指令更快捷,不过尽可能多的演示命令使用, 353 | ;在此先用这种方法,在后面内容会用到insw和outsw等 354 | 355 | mov dx, 256 ;di为要读取的扇区数,一个扇区有512字节,每次读入一个字,共需di*512/2次,所以di*256 356 | mul dx 357 | mov cx, ax 358 | mov dx, 0x1f0 359 | .go_on_read: 360 | in ax,dx 361 | mov [ebx], ax 362 | add ebx, 2 363 | ; 由于在实模式下偏移地址为16位,所以用bx只会访问到0~FFFFh的偏移。 364 | ; loader的栈指针为0x900,bx为指向的数据输出缓冲区,且为16位, 365 | ; 超过0xffff后,bx部分会从0开始,所以当要读取的扇区数过大,待写入的地址超过bx的范围时, 366 | ; 从硬盘上读出的数据会把0x0000~0xffff的覆盖, 367 | ; 造成栈被破坏,所以ret返回时,返回地址被破坏了,已经不是之前正确的地址, 368 | ; 故程序出会错,不知道会跑到哪里去。 369 | ; 所以改为ebx代替bx指向缓冲区,这样生成的机器码前面会有0x66和0x67来反转。 370 | ; 0X66用于反转默认的操作数大小! 0X67用于反转默认的寻址方式. 371 | ; cpu处于16位模式时,会理所当然的认为操作数和寻址都是16位,处于32位模式时, 372 | ; 也会认为要执行的指令是32位. 373 | ; 当我们在其中任意模式下用了另外模式的寻址方式或操作数大小(姑且认为16位模式用16位字节操作数, 374 | ; 32位模式下用32字节的操作数)时,编译器会在指令前帮我们加上0x66或0x67, 375 | ; 临时改变当前cpu模式到另外的模式下. 376 | ; 假设当前运行在16位模式,遇到0X66时,操作数大小变为32位. 377 | ; 假设当前运行在32位模式,遇到0X66时,操作数大小变为16位. 378 | ; 假设当前运行在16位模式,遇到0X67时,寻址方式变为32位寻址 379 | ; 假设当前运行在32位模式,遇到0X67时,寻址方式变为16位寻址. 380 | 381 | loop .go_on_read 382 | ret -------------------------------------------------------------------------------- /Cpt5.A Step Close to Kernel/mbr.s: -------------------------------------------------------------------------------- 1 | %include "./include/boot.inc" 2 | SECTION MBR vstart=0x7c00 3 | mov ax,cs 4 | mov ds,ax 5 | mov es,ax 6 | mov ss,ax 7 | mov fs,ax 8 | mov sp,0x7c00 9 | mov ax,0xb800 10 | mov gs,ax 11 | 12 | ;清屏功能 13 | mov ax,0x600 14 | mov bx,0x700 15 | mov cx,0 16 | mov dx,0x184f 17 | int 0x10 18 | 19 | ;获取光标未知 20 | ;输出:cl:光标开始行,cl:光标结束行 21 | ; dl:光标所在行号,dl:光标所在列号 22 | 23 | ; 打印字符串 24 | mov byte [gs:0x00],'l' 25 | mov byte [gs:0x01],0xA4 26 | 27 | mov byte [gs:0x02],' ' 28 | mov byte [gs:0x03],0xA4 29 | 30 | mov byte [gs:0x04],'M' 31 | mov byte [gs:0x05],0xA4 32 | 33 | mov byte [gs:0x06],'B' 34 | mov byte [gs:0x07],0xA4 35 | 36 | mov byte [gs:0x08],'R' 37 | mov byte [gs:0x09],0xA4 38 | 39 | 40 | ;读取一个扇区(loader所在)道指定位置的内存中 41 | mov eax,LOADER_START_SECTOR ;硬盘中的lba地址 42 | mov bx,LOADER_BASE_ADDR ;写入的地址 43 | mov cx,4 ;读入的扇区数 44 | call rd_disk_m_16 45 | 46 | jmp LOADER_BASE_ADDR 47 | 48 | ; 函数rd_disk_m_16 49 | ; 功能:读取硬盘n个扇区 50 | ; eax = LBA硬盘号 51 | ; bx = 将数据写入的内存地址 52 | ; cx = 读入的扇区数 53 | rd_disk_m_16: 54 | mov esi,eax ;备份eax 55 | mov di,cx ;备份cx 56 | ;读写硬盘 57 | ;第一步:设置要读取的扇区数 58 | mov dx,0x1f2 ;指定读取的扇区数 59 | mov al,cl 60 | out dx,al 61 | mov eax,esi ;恢复ax 62 | 63 | ;第二部:将LBA地址存入0x1f3~0x1f6 64 | mov dx,0x1f3 65 | out dx,al 66 | 67 | mov cl,8 68 | shr eax,cl 69 | inc dx 70 | out dx,al 71 | 72 | shr eax,cl 73 | inc dx 74 | out dx,al 75 | 76 | shr eax,cl 77 | and al,0x0f 78 | or al,0xe0 79 | mov dx,0x1f6 80 | out dx,al 81 | ;第三步:向0x1f7端口写入读命令,0x20 82 | mov dx,0x1f7 83 | mov al,0x20 84 | out dx,al 85 | 86 | ;第四步:检测硬盘状态 87 | .not_ready: 88 | nop 89 | in al,dx 90 | and al,0x88 91 | cmp al,0x08 92 | jnz .not_ready 93 | ;第五步:0x1f0端口读取数据 94 | mov ax,di 95 | ;一次读取一个字,所以是512/2*di 96 | mov dx,256 97 | mul dx 98 | mov cx,ax 99 | mov dx,0x1f0 100 | .go_on_read: 101 | in ax,dx 102 | mov [bx],ax 103 | add bx,2 104 | loop .go_on_read 105 | ret 106 | 107 | times 510-($-$$) db 0 108 | db 0x55,0xaa 109 | -------------------------------------------------------------------------------- /Cpt5.A Step Close to Kernel/run_bochs.sh: -------------------------------------------------------------------------------- 1 | nasm -o ./mbr.bin ./mbr.s 2 | nasm -o ./loader.bin ./loader.s 3 | cd ./kernel 4 | gcc -m32 -c -o main.o main.c && ld -m elf_i386 main.o -Ttext 0xc0001500 -e main -o kernel.bin 5 | rm ./main.o 6 | cd .. 7 | cd .. 8 | ./bochs/bin/bximage -mode=create -hd=60M -imgmode="flat" -q ./bochs/bin/hd60M.img 9 | dd if=./Cpt5.A\ Step\ Close\ to\ Kernel/mbr.bin of=./bochs/bin/hd60M.img bs=512 count=1 conv=notrunc 10 | dd if=./Cpt5.A\ Step\ Close\ to\ Kernel/loader.bin of=./bochs/bin/hd60M.img bs=512 count=4 conv=notrunc seek=2 11 | dd if=./Cpt5.A\ Step\ Close\ to\ Kernel/kernel/kernel.bin of=./bochs/bin/hd60M.img bs=512 count=200 conv=notrunc seek=9 12 | cd ./bochs/bin 13 | rm ./hd60M.img.lock 14 | ./bochs -f ./bochsrc.disk 15 | rm ./hd60M.img 16 | -------------------------------------------------------------------------------- /Cpt6.Improve Kernel/README.md: -------------------------------------------------------------------------------- 1 | # Cpt6. Improve Kernel 2 | 3 | ## 32位系统下的函数调用约定 4 | 5 | > 我们在后续的编程中使用cdecl调用约定 6 | 7 | 64位系统中C语言大多使用fastcall(x64)。这个表格描述的是**x86架构**下的函数调用约定。 8 | 9 | | 栈清理负责人 | 类别 | 描述 | 10 | | ------------------------ | -------- | ------------------------------------------------------------ | 11 | | 调用者清理 | cdecl | C语言的函数调用约定,多用于32位cpu。函数参数从右到左入栈,EAX,ECX和EDX由调用者保存,返回值在EAX | 12 | | 调用者清理 | syscall | 与cdecl类似, 参数从左到右入栈,参数列表的大小放在al中。
syscall是32位OS/2 API的标准 | 13 | | 被调用者清理 | stdcall | 和cdecl基本一致,只是栈清理由被调用函数清理,使用指令:
retn xxxx | 14 | | 被调用者清理 | fastcall | x86架构下的fastcall还没有标准化,但是GUN和MSF已经达成一致。**从左到右**的前两个参数放在ECX和EDX,其余的**从右到左入栈** | 15 | | 调用者或者
被调用者 | thiscall | 老生常谈的thiscall,C++非静态成员函数使用。ecx作为对象指针传入被调用者,其余和cdecl一致。 | 16 | 17 | ## 实现基本的屏幕输出 18 | 19 | 这一块直接抄了代码,没什么特别需要注意的地方 20 | 21 | ## gcc扩展内联汇编 22 | 23 | ### 模板: 24 | 25 | ```c 26 | asm( 27 | "addl %%ebx,%%eax" \ 28 | :"=a"(input) \ 29 | :"a"(output) \ 30 | ) 31 | ``` 32 | 33 | ### 寄存器约束 34 | 35 | a:表示寄存器 eax,ax,al 36 | 37 | b:表示寄存器ebx,bx,bl 38 | 39 | c,d同上 40 | 41 | D:表示寄存器edi 42 | 43 | S:表示寄存器esi 44 | 45 | q:表示四个通用寄存器之一(eax,ebx,ecx,edx) 46 | 47 | r:表示6个统用寄存器之一(eax,ebx,ecx,edx,esi,edi) 48 | 49 | g:表示可以存放到任意地点(寄存器和内存)。相当于除了同q一样以外,还可以让gcc安排在内存中 50 | 51 | A:把eax和edx组合成64位整数 52 | 53 | f:表示浮点寄存器 54 | 55 | t:表示第一个浮点寄存器 56 | 57 | u:表示第二个浮点寄存器 58 | 59 | ### 内存约束 60 | 61 | m:表示操作数可以使用任意一种内存形式 62 | 63 | o:操作数为内存变量,但访问它是通过偏移量的形式访问,即包含offset_address的格式 64 | 65 | ### 立即数约束 66 | 67 | 这一类约束只能放在input中 68 | 69 | i:表示操作数为整数立即数 70 | 71 | F:表示操作数为浮点数立即数 72 | 73 | I:表示操作数为0~31之间的立即数 74 | 75 | J:表示操作数为0~63之间的立即数 76 | 77 | N:表示操作数为0~255之间的立即数 78 | 79 | O:表示操作数为0~32之间的立即数 80 | 81 | X:表示操作数为任何类型立即数 82 | 83 | ### 通用约束 84 | 85 | 0~9:此约束只用在input部分,但表示可与output和input中第n个操作数用象通的寄存器或内存。 86 | 87 | ### 序号占用符 88 | 89 | 序号占位符是对在 output input 中的操作数,按照它们从左到右出现的次序从0 开始编号,一直到 9,也就是说最多支持 10 个序号占位符。 90 | 91 | 操作数用在 assembly code 中,引用它的格式是%0~9 92 | 93 | 94 | 95 | ### 名称占位符 96 | 97 | 看代码,还是模板 98 | 99 | ```c 100 | #include 101 | int main(){ 102 | int in_a = 18,in_b = 3,out = 0; 103 | asm( 104 | "divb %[divisor];"\ 105 | "movb %%al,%[result]"\ 106 | :[result]"=m"(out)\ 107 | :"a"(in_a),[divisor]"m"(in_b)\ 108 | ); 109 | printf("result is %d\n,out"); 110 | } 111 | ``` 112 | 113 | ### output约束 114 | 115 | =:表示操作数是只写的 116 | 117 | +:表示操作数是可读写的 118 | 119 | &:表示此ouput中的操作数要独占所约束的寄存器,只供output使用,input中的约束不能出现使用了这个约束的寄存器 120 | 121 | ### input约束 122 | 123 | %:该操作数可以和下一个输入操作数互换 124 | 125 | ## 内联汇编之机器模式 126 | 127 | 暂时略,等到用到了再回来补充 -------------------------------------------------------------------------------- /Cpt6.Improve Kernel/include/boot.inc: -------------------------------------------------------------------------------- 1 | ;________loader & kernel________ 2 | LOADER_BASE_ADDR equ 0x900 3 | LOADER_START_SECTOR equ 0x2 4 | PAGE_DIR_TABLE_POS equ 0x100000 5 | KERNEL_BIN_BASE_ADDR equ 0x70000 6 | KERNEL_START_SECTOR equ 0x9 7 | KERNEL_ENTRY_POINT equ 0xc0001500 8 | 9 | ;________gdt描述符属性________ 10 | DESC_G_4K EQU 1_00000000000000000000000b 11 | DESC_D_32 EQU 1_0000000000000000000000b 12 | DESC_L EQU 0_000000000000000000000b 13 | ;64位代码标记,此处标记为0即可 14 | DESC_AVL EQU 0_00000000000000000000b 15 | DESC_LIMIT_CODE2 EQU 1111_0000000000000000b 16 | DESC_LIMIT_DATA2 EQU DESC_LIMIT_CODE2 17 | DESC_LIMIT_VIDEO2 EQU 0000_000000000000000b 18 | DESC_P EQU 1_000000000000000b 19 | DESC_DPL_0 EQU 00_0000000000000b 20 | DESC_DPL_1 EQU 01_0000000000000b 21 | DESC_DPL_2 EQU 10_0000000000000b 22 | DESC_DPL_3 EQU 11_0000000000000b 23 | DESC_S_CODE equ 1_000000000000b 24 | DESC_S_DATA equ DESC_S_CODE 25 | DESC_S_sys equ 0_000000000000b 26 | DESC_TYPE_CODE equ 1000_00000000b 27 | ;x=1,c=O,r=O,a=O 代码段是可执行的,非一致性,不可读,已访问位a清0。 28 | DESC_TYPE_DATA equ 0010_00000000b 29 | ;x=O,e=O,w=1,a=O 数据段是不可执行的,向上扩展的,可写,己访问位a清0。 30 | DESC_CODE_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 31 | DESC_L + DESC_AVL + DESC_LIMIT_CODE2 + \ 32 | DESC_P+DESC_DPL_0 + DESC_S_CODE +\ 33 | DESC_TYPE_CODE + 0x00 34 | DESC_DATA_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 +\ 35 | DESC_L + DESC_AVL + DESC_LIMIT_DATA2 + \ 36 | DESC_P + DESC_DPL_0 + DESC_S_DATA + \ 37 | DESC_TYPE_DATA + 0x00 38 | DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 +\ 39 | DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + DESC_P + \ 40 | DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x0b 41 | ;选择子属性 42 | RPL0 EQU 00b 43 | RPL1 EQU 01b 44 | RPL2 EQU 10b 45 | RPL3 EQU 11b 46 | TI_GDT EQU 000b 47 | TI_LDT EQU 100b 48 | 49 | ;__________ 页表相关属性 ___________ 50 | 51 | PG_P equ 1b 52 | PG_RW_R EQU 00b 53 | PG_RW_W EQU 10b 54 | PG_US_S EQU 000b 55 | PG_US_U EQU 100b 56 | 57 | ;------------- program type 定义 -------------- 58 | PT_NULL equ 0 59 | -------------------------------------------------------------------------------- /Cpt6.Improve Kernel/kernel/main.c: -------------------------------------------------------------------------------- 1 | #include "print.h" 2 | 3 | int main(void){ 4 | put_str("I am kernel\n"); 5 | put_int(0); 6 | put_char('\n'); 7 | put_int(9); 8 | put_char('\n'); 9 | put_int(0x00021a3f); 10 | put_char('\n'); 11 | put_int(0x12345678); 12 | put_char('\n'); 13 | put_int(0x00000000); 14 | while(1); 15 | return 0; 16 | } -------------------------------------------------------------------------------- /Cpt6.Improve Kernel/lib/kernel/print.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIB_KERNEL_PRINT_H 2 | #define __LIB_KERNEL_PRINT_H 3 | #include "../stdint.h" 4 | void put_char(uint8_t char_asci); 5 | void put_str(char* message); 6 | void put_int(uint32_t num); 7 | #endif -------------------------------------------------------------------------------- /Cpt6.Improve Kernel/lib/kernel/print.s: -------------------------------------------------------------------------------- 1 | TI_GDT equ 0 2 | RPL0 equ 0 3 | SELECTOR_VIDEO equ (0x0003<<3) + TI_GDT + RPL0 4 | 5 | section .data 6 | put_int_buffer dq 0 ; 定义8字节缓冲区用于数字到字符的转换 7 | 8 | [bits 32] 9 | section .text 10 | ;-------------------------------------------- 11 | ;put_str 通过put_char来打印以0字符结尾的字符串 12 | ;-------------------------------------------- 13 | ;输入:栈中参数为打印的字符串 14 | ;输出:无 15 | 16 | global put_str 17 | put_str: 18 | ;由于本函数中只用到了ebx和ecx,只备份这两个寄存器 19 | push ebx 20 | push ecx 21 | xor ecx, ecx ; 准备用ecx存储参数,清空 22 | mov ebx, [esp + 12] ; 从栈中得到待打印的字符串地址 23 | .goon: 24 | mov cl, [ebx] 25 | cmp cl, 0 ; 如果处理到了字符串尾,跳到结束处返回 26 | jz .str_over 27 | push ecx ; 为put_char函数传递参数 28 | call put_char 29 | add esp, 4 ; 回收参数所占的栈空间 30 | inc ebx ; 使ebx指向下一个字符 31 | jmp .goon 32 | .str_over: 33 | pop ecx 34 | pop ebx 35 | ret 36 | 37 | ;------------------------ put_char ----------------------------- 38 | ;功能描述:把栈中的1个字符写入光标所在处 39 | ;------------------------------------------------------------------- 40 | global put_char 41 | put_char: 42 | pushad ;备份32位寄存器环境 43 | ;需要保证gs中为正确的视频段选择子,为保险起见,每次打印时都为gs赋值 44 | mov ax, SELECTOR_VIDEO ; 不能直接把立即数送入段寄存器 45 | mov gs, ax 46 | 47 | ;;;;;;;;; 获取当前光标位置 ;;;;;;;;; 48 | ;先获得高8位 49 | mov dx, 0x03d4 ;索引寄存器 50 | mov al, 0x0e ;用于提供光标位置的高8位 51 | out dx, al 52 | mov dx, 0x03d5 ;通过读写数据端口0x3d5来获得或设置光标位置 53 | in al, dx ;得到了光标位置的高8位 54 | mov ah, al 55 | 56 | ;再获取低8位 57 | mov dx, 0x03d4 58 | mov al, 0x0f 59 | out dx, al 60 | mov dx, 0x03d5 61 | in al, dx 62 | 63 | ;将光标存入bx 64 | mov bx, ax 65 | ;下面这行是在栈中获取待打印的字符 66 | mov ecx, [esp + 36] ;pushad压入4×8=32字节,加上主调函数的返回地址4字节,故esp+36字节 67 | cmp cl, 0xd ;CR是0x0d,LF是0x0a 68 | jz .is_carriage_return 69 | cmp cl, 0xa 70 | jz .is_line_feed 71 | 72 | cmp cl, 0x8 ;BS(backspace)的asc码是8 73 | jz .is_backspace 74 | jmp .put_other 75 | ;;;;;;;;;;;;;;;;;; 76 | 77 | .is_backspace: 78 | ;;;;;;;;;;;; backspace的一点说明 ;;;;;;;;;; 79 | ; 当为backspace时,本质上只要将光标移向前一个显存位置即可.后面再输入的字符自然会覆盖此处的字符 80 | ; 但有可能在键入backspace后并不再键入新的字符,这时在光标已经向前移动到待删除的字符位置,但字符还在原处, 81 | ; 这就显得好怪异,所以此处添加了空格或空字符0 82 | dec bx 83 | shl bx,1 84 | mov byte [gs:bx], 0x20 ;将待删除的字节补为0或空格皆可 85 | inc bx 86 | mov byte [gs:bx], 0x07 87 | shr bx,1 88 | jmp .set_cursor 89 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 90 | 91 | .put_other: 92 | shl bx, 1 ; 光标位置是用2字节表示,将光标值乘2,表示对应显存中的偏移字节 93 | mov [gs:bx], cl ; ascii字符本身 94 | inc bx 95 | mov byte [gs:bx],0x07 ; 字符属性 96 | shr bx, 1 ; 恢复老的光标值 97 | inc bx ; 下一个光标值 98 | cmp bx, 2000 99 | jl .set_cursor ; 若光标值小于2000,表示未写到显存的最后,则去设置新的光标值 100 | ; 若超出屏幕字符数大小(2000)则换行处理 101 | .is_line_feed: ; 是换行符LF(\n) 102 | .is_carriage_return: ; 是回车符CR(\r) 103 | ; 如果是CR(\r),只要把光标移到行首就行了。 104 | xor dx, dx ; dx是被除数的高16位,清0. 105 | mov ax, bx ; ax是被除数的低16位. 106 | mov si, 80 ; 由于是效仿linux,linux中\n便表示下一行的行首,所以本系统中, 107 | div si ; 把\n和\r都处理为linux中\n的意思,也就是下一行的行首。 108 | sub bx, dx ; 光标值减去除80的余数便是取整 109 | ; 以上4行处理\r的代码 110 | 111 | .is_carriage_return_end: ; 回车符CR处理结束 112 | add bx, 80 113 | cmp bx, 2000 114 | .is_line_feed_end: ; 若是LF(\n),将光标移+80便可。 115 | jl .set_cursor 116 | 117 | ;屏幕行范围是0~24,滚屏的原理是将屏幕的1~24行搬运到0~23行,再将第24行用空格填充 118 | .roll_screen: ; 若超出屏幕大小,开始滚屏 119 | cld 120 | mov ecx, 960 ; 一共有2000-80=1920个字符要搬运,共1920*2=3840字节.一次搬4字节,共3840/4=960次 121 | mov esi, 0xb80a0 ; 第1行行首 122 | mov edi, 0xb8000 ; 第0行行首 123 | rep movsd 124 | 125 | ;;;;;;;将最后一行填充为空白 126 | mov ebx, 3840 ; 最后一行首字符的第一个字节偏移= 1920 * 2 127 | mov ecx, 80 ;一行是80字符(160字节),每次清空1字符(2字节),一行需要移动80次 128 | .cls: 129 | mov word [gs:ebx], 0x0720 ;0x0720是黑底白字的空格键 130 | add ebx, 2 131 | loop .cls 132 | mov bx,1920 ;将光标值重置为1920,最后一行的首字符. 133 | 134 | .set_cursor: 135 | ;将光标设为bx值 136 | ;;;;;;; 1 先设置高8位 ;;;;;;;; 137 | mov dx, 0x03d4 ;索引寄存器 138 | mov al, 0x0e ;用于提供光标位置的高8位 139 | out dx, al 140 | mov dx, 0x03d5 ;通过读写数据端口0x3d5来获得或设置光标位置 141 | mov al, bh 142 | out dx, al 143 | 144 | ;;;;;;; 2 再设置低8位 ;;;;;;;;; 145 | mov dx, 0x03d4 146 | mov al, 0x0f 147 | out dx, al 148 | mov dx, 0x03d5 149 | mov al, bl 150 | out dx, al 151 | .put_char_done: 152 | popad 153 | ret 154 | 155 | ;-------------------- 将小端字节序的数字变成对应的ascii后,倒置 ----------------------- 156 | ;输入:栈中参数为待打印的数字 157 | ;输出:在屏幕上打印16进制数字,并不会打印前缀0x,如打印10进制15时,只会直接打印f,不会是0xf 158 | ;------------------------------------------------------------------------------------------ 159 | global put_int 160 | put_int: 161 | pushad 162 | mov ebp, esp 163 | mov eax, [ebp+4*9] ; call的返回地址占4字节+pushad的8个4字节 164 | mov edx, eax 165 | mov edi, 7 ; 指定在put_int_buffer中初始的偏移量 166 | mov ecx, 8 ; 32位数字中,16进制数字的位数是8个 167 | mov ebx, put_int_buffer 168 | 169 | ;将32位数字按照16进制的形式从低位到高位逐个处理,共处理8个16进制数字 170 | .16based_4bits: ; 每4位二进制是16进制数字的1位,遍历每一位16进制数字 171 | and edx, 0x0000000F ; 解析16进制数字的每一位。and与操作后,edx只有低4位有效 172 | cmp edx, 9 ; 数字0~9和a~f需要分别处理成对应的字符 173 | jg .is_A2F 174 | add edx, '0' ; ascii码是8位大小。add求和操作后,edx低8位有效。 175 | jmp .store 176 | .is_A2F: 177 | sub edx, 10 ; A~F 减去10 所得到的差,再加上字符A的ascii码,便是A~F对应的ascii码 178 | add edx, 'A' 179 | 180 | ;将每一位数字转换成对应的字符后,按照类似“大端”的顺序存储到缓冲区put_int_buffer 181 | ;高位字符放在低地址,低位字符要放在高地址,这样和大端字节序类似,只不过咱们这里是字符序. 182 | .store: 183 | ; 此时dl中应该是数字对应的字符的ascii码 184 | mov [ebx+edi], dl 185 | dec edi 186 | shr eax, 4 187 | mov edx, eax 188 | loop .16based_4bits 189 | 190 | ;现在put_int_buffer中已全是字符,打印之前, 191 | ;把高位连续的字符去掉,比如把字符000123变成123 192 | .ready_to_print: 193 | inc edi ; 此时edi退减为-1(0xffffffff),加1使其为0 194 | .skip_prefix_0: 195 | cmp edi,8 ; 若已经比较第9个字符了,表示待打印的字符串为全0 196 | je .full0 197 | ;找出连续的0字符, edi做为非0的最高位字符的偏移 198 | .go_on_skip: 199 | mov cl, [put_int_buffer+edi] 200 | inc edi 201 | cmp cl, '0' 202 | je .skip_prefix_0 ; 继续判断下一位字符是否为字符0(不是数字0) 203 | dec edi ;edi在上面的inc操作中指向了下一个字符,若当前字符不为'0',要恢复edi指向当前字符 204 | jmp .put_each_num 205 | 206 | .full0: 207 | mov cl,'0' ; 输入的数字为全0时,则只打印0 208 | .put_each_num: 209 | push ecx ; 此时cl中为可打印的字符 210 | call put_char 211 | add esp, 4 212 | inc edi ; 使edi指向下一个字符 213 | mov cl, [put_int_buffer+edi] ; 获取下一个字符到cl寄存器 214 | cmp edi,8 215 | jl .put_each_num 216 | popad 217 | ret 218 | -------------------------------------------------------------------------------- /Cpt6.Improve Kernel/lib/stdint.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIB_STDINT_H 2 | #define __LIB_STDINT_H 3 | typedef signed char int8_t; 4 | typedef signed short int int16_t; 5 | typedef signed int int32_t; 6 | typedef signed long long int int64_t; 7 | typedef unsigned char uint8_t; 8 | typedef unsigned short int uint16_t; 9 | typedef unsigned int uint32_t; 10 | typedef unsigned long long int uint64_t; 11 | #endif -------------------------------------------------------------------------------- /Cpt6.Improve Kernel/loader.s: -------------------------------------------------------------------------------- 1 | %include "./include/boot.inc" 2 | SECTION LOADER vstart=LOADER_BASE_ADDR 3 | LOADER_STACK_TOP equ LOADER_BASE_ADDR 4 | jmp loader_start 5 | ;构建gdt及其内部的描述符 6 | GDT_BASE: 7 | dd 0x00000000 8 | dd 0x00000000 9 | CODE_DESC: 10 | dd 0x0000ffff 11 | dd DESC_CODE_HIGH4 12 | DATA_STACK_DESC: 13 | dd 0x0000ffff 14 | dd DESC_DATA_HIGH4 15 | VIDEO_DESC: 16 | dd 0x8000_0007;limit = (0xbffff - b8000)/4k = 0x7 17 | dd DESC_VIDEO_HIGH4 ;此时DPL为0 18 | GDT_SIZE equ $ - GDT_BASE 19 | GDT_LIMIT equ GDT_SIZE - 1 20 | times 60 dq 0 ;此处预留60个描述符空位 21 | ;选择子 22 | SELECTOR_CODE equ (0x0001<<3) + TI_GDT + RPL0 23 | SELECTOR_DATA equ (0x0002<<3) + TI_GDT + RPL0 24 | SELECTOR_VIDEO equ (0x003<<3) + TI_GDT + RPL0 25 | ;total_mem_bytes 用于保存用户的内存容量,以字节为单位,此位置比较好标记 26 | ;当前偏移loader.bin文件头0x200字节;loader.bin的加载地址是0x900 27 | ;故total_mem_bytes内存中的地址是0xb00;将来内核会引用这个地址。 28 | total_mem_bytes dd 0 29 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 30 | ;以下是gdt的指针,前2字节是gdt界限,后4字节是gdt起始地址 31 | gdt_ptr dw GDT_LIMIT 32 | dd GDT_BASE 33 | 34 | 35 | ;人工对齐:total_mem_bytes4+gdt_ptr6+ards_buf244+ards_nr2,共256字节 36 | ards_buf times 244 db 0 ;用于记录ARDS结构体数量 37 | ards_nr dw 0 38 | loadermsg db '2 loader in real' 39 | loader_start: 40 | 41 | ;获取内存布局 42 | 43 | xor ebx,ebx ;第一次执行时。ebx需要为0 44 | mov edx,0x534d4150 ;edx在调用中断前后不会改变 45 | mov di,ards_buf ;ards结构缓冲区 46 | .e820_mem_get_loop: 47 | mov eax,0x0000e820 ;执行 int 0x15后,eax的直会发生变化,需要重置 48 | mov ecx,20 ;ards的大小是20字节 49 | int 0x15 50 | jc .e820_failed_so_try_e801 51 | add di,cx 52 | inc word [ards_nr] ;记录ards数量 53 | cmp ebx,0 ;若ebx为0且cf不为1,说明ards全部返回 54 | jnz .e820_mem_get_loop 55 | 56 | ;在所有ards结构中,找出(base_add_low + length_low)的最大值,即内存的容量 57 | mov cx,[ards_nr] 58 | mov ebx,ards_buf 59 | xor edx,edx ;用edx记录最大内存容量,进入循环前先清0 60 | .find_max_mem_area: ;无需判断type是否为1,最大的内存块是一定可被使用的 61 | mov eax,[ebx] ;base_add_low 62 | add eax,[ebx+8] ;length_low 63 | add ebx,20 ;👈向下一个ARDS结构 64 | cmp edx,eax ;冒泡排序,找出最大,edx寄存器始终是最大的内存容量 65 | jge .next_ards 66 | mov edx,eax 67 | .next_ards: 68 | loop .find_max_mem_area 69 | jmp .mem_get_ok 70 | 71 | ;----- int 0x15h ax = E801H,获取内存大小---- 72 | ;返回后,ax,cx的值一样,以KB为单位,bx,dx值一样,以64KB为单位 73 | ;在ax和cx寄存器中为低16MB,在bx和dx寄存器中为16MB到4GB 74 | .e820_failed_so_try_e801: 75 | mov ax,0xe801 76 | int 0x15 77 | jc .e801_failed_so_try_88 ;还是失败,尝试0x88方法 78 | 79 | ;先算出低15MB的内存 ;ax和cx中是以KB为的单位的内存数量,将其转换为以byte为单位 80 | mov cx,0x400 ;cx和ax值一样 81 | mul cx 82 | shl edx,16 83 | and eax,0x0000FFFF 84 | or edx,eax 85 | add edx,0x100000 ;ax只是15MB,所以要加1MB 86 | mov esi,edx ;先把低15MB的内存存入esi寄存器备份 87 | 88 | ;再算出16MB以上的内存转换为byte为单位,寄存器bx和dx中是以64KB为单位的内存数量 89 | xor eax,eax 90 | mov ax,bx 91 | mov ecx,0x10000 ;0x10000十进制为64KB 92 | mul ecx 93 | add esi,eax 94 | mov edx,esi 95 | jmp .mem_get_ok 96 | 97 | ;-------- int 0x15h ah = 0x88 ------- 98 | .e801_failed_so_try_88: 99 | ;int 0x15后,ax存入的是以KB为单位的内存容量 100 | mov ah,0x88 101 | int 0x15 102 | jc .error_hlt 103 | and eax,0x0000FFFF 104 | mov cx, 0x400 105 | mul cx 106 | shl edx,0x16 107 | or edx,eax 108 | add edx,0x100000 ;0x88子功能指挥调用1MB以上的内存,故实际内存要加上1MB 109 | .mem_get_ok: ; 0xcb9 110 | mov [total_mem_bytes],edx 111 | jmp .done 112 | .error_hlt: 113 | mov byte [gs:0x160+0],'F' 114 | mov byte [gs:0x160+2],'a' 115 | mov byte [gs:0x160+4],'i' 116 | mov byte [gs:0x160+6],'l' 117 | jmp $ 118 | .done: 119 | mov byte [gs:0x160+0],'S' 120 | mov byte [gs:0x160+2],'u' 121 | mov byte [gs:0x160+4],'c' 122 | mov byte [gs:0x160+6],'c' ;0xcec 123 | ; 进入保护模式 124 | mov sp,LOADER_BASE_ADDR 125 | mov bp,loadermsg 126 | mov cx,17 127 | mov ax,0x1301 128 | mov bx,0x001f 129 | mov dx,0x1800 130 | int 0x10 131 | ;_________准备进入保护模式___________ 132 | ;1.打开A20Gate 133 | ;2.加载gdt 134 | ;3.将cr0的PE位置1 135 | ;-------------打开A20Gate------------- 136 | in al,0x92 137 | or al,0000_0010B 138 | out 0x92,al 139 | ;------------ 加载GDT ------------ 140 | lgdt [gdt_ptr] 141 | ;------------cr0的PE位置为1------------ 142 | mov eax,cr0 143 | or eax,0x0000_0001 144 | mov cr0,eax 145 | 146 | jmp dword SELECTOR_CODE:p_mode_start;刷新流水线 147 | 148 | ;进入保护模式 149 | [bits 32] 150 | p_mode_start: 151 | mov ax,SELECTOR_DATA ;0xd23 152 | mov ds,ax 153 | mov es,ax 154 | mov ss,ax 155 | mov esp,LOADER_STACK_TOP 156 | mov ax,SELECTOR_VIDEO 157 | mov gs,ax 158 | 159 | mov byte [gs:320],'P' 160 | ; ------------------------- 加载kernel ---------------------- 161 | mov eax, KERNEL_START_SECTOR ; kernel.bin所在的扇区号 162 | mov ebx, KERNEL_BIN_BASE_ADDR ; 从磁盘读出后,写入到ebx指定的地址 163 | mov ecx, 200 ; 读入的扇区数 164 | call rd_disk_m_32 ;0xd54 165 | ;----------初始化页内存图 ----------- 166 | call setup_page ;0xd8d 167 | 168 | ;将描述符表地址及偏移量写入内存gdt_ptr,一会儿用新地址重新加载 169 | sgdt [gdt_ptr] 170 | ;将gdt描述符中显存段描述符中的段基址增加0xc0000000 171 | mov ebx,[gdt_ptr + 2] 172 | or dword [ebx + 0x18 +4],0xc0000000 173 | ;视频段是第三个段描述符,每个描述符是8个字节,故0x18 174 | ;段描述符的高4字节的最高为是段基址的第31~24位 175 | 176 | ;将gdt的基址加上0xc0000000使其成为内核所在的高地址 177 | add dword [gdt_ptr +2],0xc0000000 178 | add esp,0xc0000000 179 | 180 | ;把页目录储存于cr3 181 | mov eax, PAGE_DIR_TABLE_POS 182 | mov cr3, eax 183 | 184 | ;打开cr0的pg位 185 | mov eax,cr0 186 | or eax, 0x80000000 187 | mov cr0,eax 188 | 189 | ;在开启分页后,用gdt新的地址重新加载 190 | lgdt [gdt_ptr] 191 | mov byte[gs:160],'V' 192 | jmp SELECTOR_CODE:enter_kernel 193 | enter_kernel: 194 | call kernel_init ;addr:0xda6 195 | mov esp,0xc009f000 196 | jmp KERNEL_ENTRY_POINT 197 | 198 | 199 | ;----------创建页目录及页表 ----------- 200 | setup_page: 201 | ;先把页目录占用的空间逐字节清0 202 | mov ecx,4096 203 | mov esi,0 204 | .clear_page_dir: 205 | mov byte [PAGE_DIR_TABLE_POS + esi],0 206 | inc esi 207 | loop .clear_page_dir 208 | ;开始创建页目录项(PDE) 209 | .create_pde: 210 | mov eax,PAGE_DIR_TABLE_POS 211 | add eax,0x10000 ;第一个页表的位置及属性 212 | mov ebx,eax ;为.create_pte做准备,ebx为基址 213 | 214 | ; 下面将页目录项0和0xc00都存为第一个页表的地址,每个页表示4MB内存 215 | ; 这样0xc03ffffff以下的地址和0x003fffff以下的地址都指向相同的页表 216 | ; 这是为了将地址映射为内核地址做准备 217 | or eax,PG_US_U | PG_RW_W | PG_P 218 | mov [PAGE_DIR_TABLE_POS + 0x0],eax 219 | mov [PAGE_DIR_TABLE_POS + 0x0c00],eax ;第768个页表,之后属于内核空间 220 | ;0xc0000000 ~ 0xffffffff共计1G属于内核 221 | sub eax,0x1000 222 | mov [PAGE_DIR_TABLE_POS + 4092],eax;使用最后一个目录👈向页目录表自己 223 | 224 | ;创建 PTE 225 | mov ecx,256 226 | mov esi,0 227 | mov edx, PG_US_U|PG_RW_W|PG_P 228 | .create_pte: 229 | mov [ebx+esi*4],edx 230 | add edx,4096 231 | inc esi 232 | loop .create_pte 233 | 234 | ;创建内核其他页表的PTE 235 | mov eax,PAGE_DIR_TABLE_POS 236 | add eax,0x2000 ;eax为第二个页表的位置 237 | mov eax, PG_US_U|PG_RW_W|PG_P 238 | mov ebx,PAGE_DIR_TABLE_POS 239 | mov ecx,254 ;范围769~1022的所有的目录项数量 240 | mov esi,769 241 | .create_kernel_pde: 242 | mov [ebx+esi*4],eax 243 | inc esi 244 | add eax,0x1000 245 | loop .create_kernel_pde 246 | ret 247 | 248 | ;----------------- 将kernel.bin中的segment拷贝到编译的地址 ----------- 249 | kernel_init: 250 | xor eax, eax 251 | xor ebx, ebx ;ebx记录程序头表地址 252 | xor ecx, ecx ;cx记录程序头表中的program header数量 253 | xor edx, edx ;dx 记录program header尺寸,即e_phentsize 254 | 255 | mov dx, [KERNEL_BIN_BASE_ADDR + 42] ; 偏移文件42字节处的属性是e_phentsize,表示program header大小 256 | mov ebx, [KERNEL_BIN_BASE_ADDR + 28] ; 偏移文件开始部分28字节的地方是e_phoff,表示第1 个program header在文件中的偏移量 257 | ; 其实该值是0x34,不过还是谨慎一点,这里来读取实际值 258 | add ebx, KERNEL_BIN_BASE_ADDR 259 | mov cx, [KERNEL_BIN_BASE_ADDR + 44] ; 偏移文件开始部分44字节的地方是e_phnum,表示有几个program header 260 | .each_segment: 261 | cmp byte [ebx + 0], PT_NULL ; 若p_type等于 PT_NULL,说明此program header未使用。 262 | je .PTNULL 263 | 264 | ;为函数memcpy压入参数,参数是从右往左依然压入.函数原型类似于 memcpy(dst,src,size) 265 | push dword [ebx + 16] ; program header中偏移16字节的地方是p_filesz,压入函数memcpy的第三个参数:size 266 | mov eax, [ebx + 4] ; 距程序头偏移量为4字节的位置是p_offset 267 | add eax, KERNEL_BIN_BASE_ADDR ; 加上kernel.bin被加载到的物理地址,eax为该段的物理地址 268 | push eax ; 压入函数memcpy的第二个参数:源地址 269 | push dword [ebx + 8] ; 压入函数memcpy的第一个参数:目的地址,偏移程序头8字节的位置是p_vaddr,这就是目的地址 270 | call mem_cpy ; 调用mem_cpy完成段复制 271 | add esp,12 ; 清理栈中压入的三个参数 272 | .PTNULL: 273 | add ebx, edx ; edx为program header大小,即e_phentsize,在此ebx指向下一个program header 274 | loop .each_segment 275 | ret 276 | 277 | ;---------- 逐字节拷贝 mem_cpy(dst,src,size) ------------ 278 | ;输入:栈中三个参数(dst,src,size) 279 | ;输出:无 280 | ;--------------------------------------------------------- 281 | mem_cpy: 282 | push ebp 283 | mov ebp, esp 284 | push ecx ; rep指令用到了ecx,但ecx对于外层段的循环还有用,故先入栈备份 285 | mov edi, [ebp + 8] ; dst 286 | mov esi, [ebp + 12] ; src 287 | mov ecx, [ebp + 16] ; size 288 | cld 289 | rep movsb ; 逐字节拷贝 290 | ;恢复环境 291 | pop ecx 292 | pop ebp 293 | ret 294 | 295 | ;------------------------------------------------------------------------------- 296 | ;功能:读取硬盘n个扇区 297 | rd_disk_m_32: 298 | ;------------------------------------------------------------------------------- 299 | ; eax=LBA扇区号 300 | ; ebx=将数据写入的内存地址 301 | ; ecx=读入的扇区数 302 | mov esi,eax ; 备份eax 303 | mov di,cx ; 备份扇区数到di 304 | ;读写硬盘: 305 | ;第1步:设置要读取的扇区数 306 | mov dx,0x1f2 307 | mov al,cl 308 | out dx,al ;读取的扇区数 309 | 310 | mov eax,esi ;恢复ax 311 | 312 | ;第2步:将LBA地址存入0x1f3 ~ 0x1f6 313 | 314 | ;LBA地址7~0位写入端口0x1f3 315 | mov dx,0x1f3 316 | out dx,al 317 | 318 | ;LBA地址15~8位写入端口0x1f4 319 | mov cl,8 320 | shr eax,cl 321 | mov dx,0x1f4 322 | out dx,al 323 | 324 | ;LBA地址23~16位写入端口0x1f5 325 | shr eax,cl 326 | mov dx,0x1f5 327 | out dx,al 328 | 329 | shr eax,cl 330 | and al,0x0f ;lba第24~27位 331 | or al,0xe0 ; 设置7~4位为1110,表示lba模式 332 | mov dx,0x1f6 333 | out dx,al 334 | 335 | ;第3步:向0x1f7端口写入读命令,0x20 336 | mov dx,0x1f7 337 | mov al,0x20 338 | out dx,al 339 | 340 | ;;;;;;; 至此,硬盘控制器便从指定的lba地址(eax)处,读出连续的cx个扇区,下面检查硬盘状态,不忙就能把这cx个扇区的数据读出来 341 | 342 | ;第4步:检测硬盘状态 343 | .not_ready: ;测试0x1f7端口(status寄存器)的的BSY位 344 | ;同一端口,写时表示写入命令字,读时表示读入硬盘状态 345 | nop 346 | in al,dx 347 | and al,0x88 ;第4位为1表示硬盘控制器已准备好数据传输,第7位为1表示硬盘忙 348 | cmp al,0x08 349 | jnz .not_ready ;若未准备好,继续等。 350 | 351 | ;第5步:从0x1f0端口读数据 352 | mov ax, di ;以下从硬盘端口读数据用insw指令更快捷,不过尽可能多的演示命令使用, 353 | ;在此先用这种方法,在后面内容会用到insw和outsw等 354 | 355 | mov dx, 256 ;di为要读取的扇区数,一个扇区有512字节,每次读入一个字,共需di*512/2次,所以di*256 356 | mul dx 357 | mov cx, ax 358 | mov dx, 0x1f0 359 | .go_on_read: 360 | in ax,dx 361 | mov [ebx], ax 362 | add ebx, 2 363 | ; 由于在实模式下偏移地址为16位,所以用bx只会访问到0~FFFFh的偏移。 364 | ; loader的栈指针为0x900,bx为指向的数据输出缓冲区,且为16位, 365 | ; 超过0xffff后,bx部分会从0开始,所以当要读取的扇区数过大,待写入的地址超过bx的范围时, 366 | ; 从硬盘上读出的数据会把0x0000~0xffff的覆盖, 367 | ; 造成栈被破坏,所以ret返回时,返回地址被破坏了,已经不是之前正确的地址, 368 | ; 故程序出会错,不知道会跑到哪里去。 369 | ; 所以改为ebx代替bx指向缓冲区,这样生成的机器码前面会有0x66和0x67来反转。 370 | ; 0X66用于反转默认的操作数大小! 0X67用于反转默认的寻址方式. 371 | ; cpu处于16位模式时,会理所当然的认为操作数和寻址都是16位,处于32位模式时, 372 | ; 也会认为要执行的指令是32位. 373 | ; 当我们在其中任意模式下用了另外模式的寻址方式或操作数大小(姑且认为16位模式用16位字节操作数, 374 | ; 32位模式下用32字节的操作数)时,编译器会在指令前帮我们加上0x66或0x67, 375 | ; 临时改变当前cpu模式到另外的模式下. 376 | ; 假设当前运行在16位模式,遇到0X66时,操作数大小变为32位. 377 | ; 假设当前运行在32位模式,遇到0X66时,操作数大小变为16位. 378 | ; 假设当前运行在16位模式,遇到0X67时,寻址方式变为32位寻址 379 | ; 假设当前运行在32位模式,遇到0X67时,寻址方式变为16位寻址. 380 | 381 | loop .go_on_read 382 | ret -------------------------------------------------------------------------------- /Cpt6.Improve Kernel/mbr.s: -------------------------------------------------------------------------------- 1 | %include "./include/boot.inc" 2 | SECTION MBR vstart=0x7c00 3 | mov ax,cs 4 | mov ds,ax 5 | mov es,ax 6 | mov ss,ax 7 | mov fs,ax 8 | mov sp,0x7c00 9 | mov ax,0xb800 10 | mov gs,ax 11 | 12 | ;清屏功能 13 | mov ax,0x600 14 | mov bx,0x700 15 | mov cx,0 16 | mov dx,0x184f 17 | int 0x10 18 | 19 | ;获取光标未知 20 | ;输出:cl:光标开始行,cl:光标结束行 21 | ; dl:光标所在行号,dl:光标所在列号 22 | 23 | ; 打印字符串 24 | mov byte [gs:0x00],'l' 25 | mov byte [gs:0x01],0xA4 26 | 27 | mov byte [gs:0x02],' ' 28 | mov byte [gs:0x03],0xA4 29 | 30 | mov byte [gs:0x04],'M' 31 | mov byte [gs:0x05],0xA4 32 | 33 | mov byte [gs:0x06],'B' 34 | mov byte [gs:0x07],0xA4 35 | 36 | mov byte [gs:0x08],'R' 37 | mov byte [gs:0x09],0xA4 38 | 39 | 40 | ;读取一个扇区(loader所在)道指定位置的内存中 41 | mov eax,LOADER_START_SECTOR ;硬盘中的lba地址 42 | mov bx,LOADER_BASE_ADDR ;写入的地址 43 | mov cx,4 ;读入的扇区数 44 | call rd_disk_m_16 45 | 46 | jmp LOADER_BASE_ADDR 47 | 48 | ; 函数rd_disk_m_16 49 | ; 功能:读取硬盘n个扇区 50 | ; eax = LBA硬盘号 51 | ; bx = 将数据写入的内存地址 52 | ; cx = 读入的扇区数 53 | rd_disk_m_16: 54 | mov esi,eax ;备份eax 55 | mov di,cx ;备份cx 56 | ;读写硬盘 57 | ;第一步:设置要读取的扇区数 58 | mov dx,0x1f2 ;指定读取的扇区数 59 | mov al,cl 60 | out dx,al 61 | mov eax,esi ;恢复ax 62 | 63 | ;第二部:将LBA地址存入0x1f3~0x1f6 64 | mov dx,0x1f3 65 | out dx,al 66 | 67 | mov cl,8 68 | shr eax,cl 69 | inc dx 70 | out dx,al 71 | 72 | shr eax,cl 73 | inc dx 74 | out dx,al 75 | 76 | shr eax,cl 77 | and al,0x0f 78 | or al,0xe0 79 | mov dx,0x1f6 80 | out dx,al 81 | ;第三步:向0x1f7端口写入读命令,0x20 82 | mov dx,0x1f7 83 | mov al,0x20 84 | out dx,al 85 | 86 | ;第四步:检测硬盘状态 87 | .not_ready: 88 | nop 89 | in al,dx 90 | and al,0x88 91 | cmp al,0x08 92 | jnz .not_ready 93 | ;第五步:0x1f0端口读取数据 94 | mov ax,di 95 | ;一次读取一个字,所以是512/2*di 96 | mov dx,256 97 | mul dx 98 | mov cx,ax 99 | mov dx,0x1f0 100 | .go_on_read: 101 | in ax,dx 102 | mov [bx],ax 103 | add bx,2 104 | loop .go_on_read 105 | ret 106 | 107 | times 510-($-$$) db 0 108 | db 0x55,0xaa 109 | -------------------------------------------------------------------------------- /Cpt6.Improve Kernel/run_bochs.sh: -------------------------------------------------------------------------------- 1 | nasm -o ./mbr.bin ./mbr.s 2 | nasm -o ./loader.bin ./loader.s 3 | nasm -f elf -o ./lib/kernel/print.o ./lib/kernel/print.s 4 | 5 | gcc -m32 -I ./lib/kernel/ -c -o ./kernel/main.o ./kernel/main.c 6 | 7 | ld -m elf_i386 -Ttext 0xc0001500 -e main -o kernel.bin kernel/main.o lib/kernel/print.o 8 | 9 | rm ./lib/kernel/print.o 10 | rm ./kernel/main.o 11 | 12 | cd .. 13 | ./bochs/bin/bximage -mode=create -hd=60M -imgmode="flat" -q ./bochs/bin/hd60M.img 14 | dd if=./Cpt6.Improve\ Kernel/mbr.bin of=./bochs/bin/hd60M.img bs=512 count=1 conv=notrunc 15 | dd if=./Cpt6.Improve\ Kernel/loader.bin of=./bochs/bin/hd60M.img bs=512 count=4 conv=notrunc seek=2 16 | dd if=./Cpt6.Improve\ Kernel/kernel.bin of=./bochs/bin/hd60M.img bs=512 count=200 conv=notrunc seek=9 17 | cd ./bochs/bin 18 | rm ./hd60M.img.lock 19 | ./bochs -f ./bochsrc.disk 20 | rm ./hd60M.img 21 | 22 | 23 | cd ../../Cpt6.Improve\ Kernel/ 24 | rm ./mbr.bin 25 | rm ./loader.bin 26 | rm ./kernel.bin -------------------------------------------------------------------------------- /Cpt7. Interrupt/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/Cpt7. Interrupt/README.md -------------------------------------------------------------------------------- /Cpt7. Interrupt/boot/include/boot.inc: -------------------------------------------------------------------------------- 1 | ;________loader & kernel________ 2 | LOADER_BASE_ADDR equ 0x900 3 | LOADER_START_SECTOR equ 0x2 4 | PAGE_DIR_TABLE_POS equ 0x100000 5 | KERNEL_BIN_BASE_ADDR equ 0x70000 6 | KERNEL_START_SECTOR equ 0x9 7 | KERNEL_ENTRY_POINT equ 0xc0001500 8 | 9 | ;________gdt描述符属性________ 10 | DESC_G_4K EQU 1_00000000000000000000000b 11 | DESC_D_32 EQU 1_0000000000000000000000b 12 | DESC_L EQU 0_000000000000000000000b 13 | ;64位代码标记,此处标记为0即可 14 | DESC_AVL EQU 0_00000000000000000000b 15 | DESC_LIMIT_CODE2 EQU 1111_0000000000000000b 16 | DESC_LIMIT_DATA2 EQU DESC_LIMIT_CODE2 17 | DESC_LIMIT_VIDEO2 EQU 0000_000000000000000b 18 | DESC_P EQU 1_000000000000000b 19 | DESC_DPL_0 EQU 00_0000000000000b 20 | DESC_DPL_1 EQU 01_0000000000000b 21 | DESC_DPL_2 EQU 10_0000000000000b 22 | DESC_DPL_3 EQU 11_0000000000000b 23 | DESC_S_CODE equ 1_000000000000b 24 | DESC_S_DATA equ DESC_S_CODE 25 | DESC_S_sys equ 0_000000000000b 26 | DESC_TYPE_CODE equ 1000_00000000b 27 | ;x=1,c=O,r=O,a=O 代码段是可执行的,非一致性,不可读,已访问位a清0。 28 | DESC_TYPE_DATA equ 0010_00000000b 29 | ;x=O,e=O,w=1,a=O 数据段是不可执行的,向上扩展的,可写,己访问位a清0。 30 | DESC_CODE_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + \ 31 | DESC_L + DESC_AVL + DESC_LIMIT_CODE2 + \ 32 | DESC_P+DESC_DPL_0 + DESC_S_CODE +\ 33 | DESC_TYPE_CODE + 0x00 34 | DESC_DATA_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 +\ 35 | DESC_L + DESC_AVL + DESC_LIMIT_DATA2 + \ 36 | DESC_P + DESC_DPL_0 + DESC_S_DATA + \ 37 | DESC_TYPE_DATA + 0x00 38 | DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 +\ 39 | DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + DESC_P + \ 40 | DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x0b 41 | ;选择子属性 42 | RPL0 EQU 00b 43 | RPL1 EQU 01b 44 | RPL2 EQU 10b 45 | RPL3 EQU 11b 46 | TI_GDT EQU 000b 47 | TI_LDT EQU 100b 48 | 49 | ;__________ 页表相关属性 ___________ 50 | 51 | PG_P equ 1b 52 | PG_RW_R EQU 00b 53 | PG_RW_W EQU 10b 54 | PG_US_S EQU 000b 55 | PG_US_U EQU 100b 56 | 57 | ;------------- program type 定义 -------------- 58 | PT_NULL equ 0 59 | -------------------------------------------------------------------------------- /Cpt7. Interrupt/boot/loader.s: -------------------------------------------------------------------------------- 1 | %include "./include/boot.inc" 2 | SECTION LOADER vstart=LOADER_BASE_ADDR 3 | LOADER_STACK_TOP equ LOADER_BASE_ADDR 4 | jmp loader_start 5 | ;构建gdt及其内部的描述符 6 | GDT_BASE: 7 | dd 0x00000000 8 | dd 0x00000000 9 | CODE_DESC: 10 | dd 0x0000ffff 11 | dd DESC_CODE_HIGH4 12 | DATA_STACK_DESC: 13 | dd 0x0000ffff 14 | dd DESC_DATA_HIGH4 15 | VIDEO_DESC: 16 | dd 0x8000_0007;limit = (0xbffff - b8000)/4k = 0x7 17 | dd DESC_VIDEO_HIGH4 ;此时DPL为0 18 | GDT_SIZE equ $ - GDT_BASE 19 | GDT_LIMIT equ GDT_SIZE - 1 20 | times 60 dq 0 ;此处预留60个描述符空位 21 | ;选择子 22 | SELECTOR_CODE equ (0x0001<<3) + TI_GDT + RPL0 23 | SELECTOR_DATA equ (0x0002<<3) + TI_GDT + RPL0 24 | SELECTOR_VIDEO equ (0x003<<3) + TI_GDT + RPL0 25 | ;total_mem_bytes 用于保存用户的内存容量,以字节为单位,此位置比较好标记 26 | ;当前偏移loader.bin文件头0x200字节;loader.bin的加载地址是0x900 27 | ;故total_mem_bytes内存中的地址是0xb00;将来内核会引用这个地址。 28 | total_mem_bytes dd 0 29 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 30 | ;以下是gdt的指针,前2字节是gdt界限,后4字节是gdt起始地址 31 | gdt_ptr dw GDT_LIMIT 32 | dd GDT_BASE 33 | 34 | 35 | ;人工对齐:total_mem_bytes4+gdt_ptr6+ards_buf244+ards_nr2,共256字节 36 | ards_buf times 244 db 0 ;用于记录ARDS结构体数量 37 | ards_nr dw 0 38 | loadermsg db '2 loader in real' 39 | loader_start: 40 | 41 | ;获取内存布局 42 | 43 | xor ebx,ebx ;第一次执行时。ebx需要为0 44 | mov edx,0x534d4150 ;edx在调用中断前后不会改变 45 | mov di,ards_buf ;ards结构缓冲区 46 | .e820_mem_get_loop: 47 | mov eax,0x0000e820 ;执行 int 0x15后,eax的直会发生变化,需要重置 48 | mov ecx,20 ;ards的大小是20字节 49 | int 0x15 50 | jc .e820_failed_so_try_e801 51 | add di,cx 52 | inc word [ards_nr] ;记录ards数量 53 | cmp ebx,0 ;若ebx为0且cf不为1,说明ards全部返回 54 | jnz .e820_mem_get_loop 55 | 56 | ;在所有ards结构中,找出(base_add_low + length_low)的最大值,即内存的容量 57 | mov cx,[ards_nr] 58 | mov ebx,ards_buf 59 | xor edx,edx ;用edx记录最大内存容量,进入循环前先清0 60 | .find_max_mem_area: ;无需判断type是否为1,最大的内存块是一定可被使用的 61 | mov eax,[ebx] ;base_add_low 62 | add eax,[ebx+8] ;length_low 63 | add ebx,20 ;👈向下一个ARDS结构 64 | cmp edx,eax ;冒泡排序,找出最大,edx寄存器始终是最大的内存容量 65 | jge .next_ards 66 | mov edx,eax 67 | .next_ards: 68 | loop .find_max_mem_area 69 | jmp .mem_get_ok 70 | 71 | ;----- int 0x15h ax = E801H,获取内存大小---- 72 | ;返回后,ax,cx的值一样,以KB为单位,bx,dx值一样,以64KB为单位 73 | ;在ax和cx寄存器中为低16MB,在bx和dx寄存器中为16MB到4GB 74 | .e820_failed_so_try_e801: 75 | mov ax,0xe801 76 | int 0x15 77 | jc .e801_failed_so_try_88 ;还是失败,尝试0x88方法 78 | 79 | ;先算出低15MB的内存 ;ax和cx中是以KB为的单位的内存数量,将其转换为以byte为单位 80 | mov cx,0x400 ;cx和ax值一样 81 | mul cx 82 | shl edx,16 83 | and eax,0x0000FFFF 84 | or edx,eax 85 | add edx,0x100000 ;ax只是15MB,所以要加1MB 86 | mov esi,edx ;先把低15MB的内存存入esi寄存器备份 87 | 88 | ;再算出16MB以上的内存转换为byte为单位,寄存器bx和dx中是以64KB为单位的内存数量 89 | xor eax,eax 90 | mov ax,bx 91 | mov ecx,0x10000 ;0x10000十进制为64KB 92 | mul ecx 93 | add esi,eax 94 | mov edx,esi 95 | jmp .mem_get_ok 96 | 97 | ;-------- int 0x15h ah = 0x88 ------- 98 | .e801_failed_so_try_88: 99 | ;int 0x15后,ax存入的是以KB为单位的内存容量 100 | mov ah,0x88 101 | int 0x15 102 | jc .error_hlt 103 | and eax,0x0000FFFF 104 | mov cx, 0x400 105 | mul cx 106 | shl edx,0x16 107 | or edx,eax 108 | add edx,0x100000 ;0x88子功能指挥调用1MB以上的内存,故实际内存要加上1MB 109 | .mem_get_ok: ; 0xcb9 110 | mov [total_mem_bytes],edx 111 | jmp .done 112 | .error_hlt: 113 | mov byte [gs:0x160+0],'F' 114 | mov byte [gs:0x160+2],'a' 115 | mov byte [gs:0x160+4],'i' 116 | mov byte [gs:0x160+6],'l' 117 | jmp $ 118 | .done: 119 | mov byte [gs:0x160+0],'S' 120 | mov byte [gs:0x160+2],'u' 121 | mov byte [gs:0x160+4],'c' 122 | mov byte [gs:0x160+6],'c' ;0xcec 123 | ; 进入保护模式 124 | mov sp,LOADER_BASE_ADDR 125 | mov bp,loadermsg 126 | mov cx,17 127 | mov ax,0x1301 128 | mov bx,0x001f 129 | mov dx,0x1800 130 | int 0x10 131 | ;_________准备进入保护模式___________ 132 | ;1.打开A20Gate 133 | ;2.加载gdt 134 | ;3.将cr0的PE位置1 135 | ;-------------打开A20Gate------------- 136 | in al,0x92 137 | or al,0000_0010B 138 | out 0x92,al 139 | ;------------ 加载GDT ------------ 140 | lgdt [gdt_ptr] 141 | ;------------cr0的PE位置为1------------ 142 | mov eax,cr0 143 | or eax,0x0000_0001 144 | mov cr0,eax 145 | 146 | jmp dword SELECTOR_CODE:p_mode_start;刷新流水线 147 | 148 | ;进入保护模式 149 | [bits 32] 150 | p_mode_start: 151 | mov ax,SELECTOR_DATA ;0xd23 152 | mov ds,ax 153 | mov es,ax 154 | mov ss,ax 155 | mov esp,LOADER_STACK_TOP 156 | mov ax,SELECTOR_VIDEO 157 | mov gs,ax 158 | 159 | mov byte [gs:320],'P' 160 | ; ------------------------- 加载kernel ---------------------- 161 | mov eax, KERNEL_START_SECTOR ; kernel.bin所在的扇区号 162 | mov ebx, KERNEL_BIN_BASE_ADDR ; 从磁盘读出后,写入到ebx指定的地址 163 | mov ecx, 200 ; 读入的扇区数 164 | call rd_disk_m_32 ;0xd54 165 | ;----------初始化页内存图 ----------- 166 | call setup_page ;0xd8d 167 | 168 | ;将描述符表地址及偏移量写入内存gdt_ptr,一会儿用新地址重新加载 169 | sgdt [gdt_ptr] 170 | ;将gdt描述符中显存段描述符中的段基址增加0xc0000000 171 | mov ebx,[gdt_ptr + 2] 172 | or dword [ebx + 0x18 +4],0xc0000000 173 | ;视频段是第三个段描述符,每个描述符是8个字节,故0x18 174 | ;段描述符的高4字节的最高为是段基址的第31~24位 175 | 176 | ;将gdt的基址加上0xc0000000使其成为内核所在的高地址 177 | add dword [gdt_ptr +2],0xc0000000 178 | add esp,0xc0000000 179 | 180 | ;把页目录储存于cr3 181 | mov eax, PAGE_DIR_TABLE_POS 182 | mov cr3, eax 183 | 184 | ;打开cr0的pg位 185 | mov eax,cr0 186 | or eax, 0x80000000 187 | mov cr0,eax 188 | 189 | ;在开启分页后,用gdt新的地址重新加载 190 | lgdt [gdt_ptr] 191 | mov byte[gs:160],'V' 192 | jmp SELECTOR_CODE:enter_kernel 193 | enter_kernel: 194 | call kernel_init ;addr:0xda6 195 | mov esp,0xc009f000 196 | jmp KERNEL_ENTRY_POINT 197 | 198 | 199 | ;----------创建页目录及页表 ----------- 200 | setup_page: 201 | ;先把页目录占用的空间逐字节清0 202 | mov ecx,4096 203 | mov esi,0 204 | .clear_page_dir: 205 | mov byte [PAGE_DIR_TABLE_POS + esi],0 206 | inc esi 207 | loop .clear_page_dir 208 | ;开始创建页目录项(PDE) 209 | .create_pde: 210 | mov eax,PAGE_DIR_TABLE_POS 211 | add eax,0x10000 ;第一个页表的位置及属性 212 | mov ebx,eax ;为.create_pte做准备,ebx为基址 213 | 214 | ; 下面将页目录项0和0xc00都存为第一个页表的地址,每个页表示4MB内存 215 | ; 这样0xc03ffffff以下的地址和0x003fffff以下的地址都指向相同的页表 216 | ; 这是为了将地址映射为内核地址做准备 217 | or eax,PG_US_U | PG_RW_W | PG_P 218 | mov [PAGE_DIR_TABLE_POS + 0x0],eax 219 | mov [PAGE_DIR_TABLE_POS + 0x0c00],eax ;第768个页表,之后属于内核空间 220 | ;0xc0000000 ~ 0xffffffff共计1G属于内核 221 | sub eax,0x1000 222 | mov [PAGE_DIR_TABLE_POS + 4092],eax;使用最后一个目录👈向页目录表自己 223 | 224 | ;创建 PTE 225 | mov ecx,256 226 | mov esi,0 227 | mov edx, PG_US_U|PG_RW_W|PG_P 228 | .create_pte: 229 | mov [ebx+esi*4],edx 230 | add edx,4096 231 | inc esi 232 | loop .create_pte 233 | 234 | ;创建内核其他页表的PTE 235 | mov eax,PAGE_DIR_TABLE_POS 236 | add eax,0x2000 ;eax为第二个页表的位置 237 | mov eax, PG_US_U|PG_RW_W|PG_P 238 | mov ebx,PAGE_DIR_TABLE_POS 239 | mov ecx,254 ;范围769~1022的所有的目录项数量 240 | mov esi,769 241 | .create_kernel_pde: 242 | mov [ebx+esi*4],eax 243 | inc esi 244 | add eax,0x1000 245 | loop .create_kernel_pde 246 | ret 247 | 248 | ;----------------- 将kernel.bin中的segment拷贝到编译的地址 ----------- 249 | kernel_init: 250 | xor eax, eax 251 | xor ebx, ebx ;ebx记录程序头表地址 252 | xor ecx, ecx ;cx记录程序头表中的program header数量 253 | xor edx, edx ;dx 记录program header尺寸,即e_phentsize 254 | 255 | mov dx, [KERNEL_BIN_BASE_ADDR + 42] ; 偏移文件42字节处的属性是e_phentsize,表示program header大小 256 | mov ebx, [KERNEL_BIN_BASE_ADDR + 28] ; 偏移文件开始部分28字节的地方是e_phoff,表示第1 个program header在文件中的偏移量 257 | ; 其实该值是0x34,不过还是谨慎一点,这里来读取实际值 258 | add ebx, KERNEL_BIN_BASE_ADDR 259 | mov cx, [KERNEL_BIN_BASE_ADDR + 44] ; 偏移文件开始部分44字节的地方是e_phnum,表示有几个program header 260 | .each_segment: 261 | cmp byte [ebx + 0], PT_NULL ; 若p_type等于 PT_NULL,说明此program header未使用。 262 | je .PTNULL 263 | 264 | ;为函数memcpy压入参数,参数是从右往左依然压入.函数原型类似于 memcpy(dst,src,size) 265 | push dword [ebx + 16] ; program header中偏移16字节的地方是p_filesz,压入函数memcpy的第三个参数:size 266 | mov eax, [ebx + 4] ; 距程序头偏移量为4字节的位置是p_offset 267 | add eax, KERNEL_BIN_BASE_ADDR ; 加上kernel.bin被加载到的物理地址,eax为该段的物理地址 268 | push eax ; 压入函数memcpy的第二个参数:源地址 269 | push dword [ebx + 8] ; 压入函数memcpy的第一个参数:目的地址,偏移程序头8字节的位置是p_vaddr,这就是目的地址 270 | call mem_cpy ; 调用mem_cpy完成段复制 271 | add esp,12 ; 清理栈中压入的三个参数 272 | .PTNULL: 273 | add ebx, edx ; edx为program header大小,即e_phentsize,在此ebx指向下一个program header 274 | loop .each_segment 275 | ret 276 | 277 | ;---------- 逐字节拷贝 mem_cpy(dst,src,size) ------------ 278 | ;输入:栈中三个参数(dst,src,size) 279 | ;输出:无 280 | ;--------------------------------------------------------- 281 | mem_cpy: 282 | push ebp 283 | mov ebp, esp 284 | push ecx ; rep指令用到了ecx,但ecx对于外层段的循环还有用,故先入栈备份 285 | mov edi, [ebp + 8] ; dst 286 | mov esi, [ebp + 12] ; src 287 | mov ecx, [ebp + 16] ; size 288 | cld 289 | rep movsb ; 逐字节拷贝 290 | ;恢复环境 291 | pop ecx 292 | pop ebp 293 | ret 294 | 295 | ;------------------------------------------------------------------------------- 296 | ;功能:读取硬盘n个扇区 297 | rd_disk_m_32: 298 | ;------------------------------------------------------------------------------- 299 | ; eax=LBA扇区号 300 | ; ebx=将数据写入的内存地址 301 | ; ecx=读入的扇区数 302 | mov esi,eax ; 备份eax 303 | mov di,cx ; 备份扇区数到di 304 | ;读写硬盘: 305 | ;第1步:设置要读取的扇区数 306 | mov dx,0x1f2 307 | mov al,cl 308 | out dx,al ;读取的扇区数 309 | 310 | mov eax,esi ;恢复ax 311 | 312 | ;第2步:将LBA地址存入0x1f3 ~ 0x1f6 313 | 314 | ;LBA地址7~0位写入端口0x1f3 315 | mov dx,0x1f3 316 | out dx,al 317 | 318 | ;LBA地址15~8位写入端口0x1f4 319 | mov cl,8 320 | shr eax,cl 321 | mov dx,0x1f4 322 | out dx,al 323 | 324 | ;LBA地址23~16位写入端口0x1f5 325 | shr eax,cl 326 | mov dx,0x1f5 327 | out dx,al 328 | 329 | shr eax,cl 330 | and al,0x0f ;lba第24~27位 331 | or al,0xe0 ; 设置7~4位为1110,表示lba模式 332 | mov dx,0x1f6 333 | out dx,al 334 | 335 | ;第3步:向0x1f7端口写入读命令,0x20 336 | mov dx,0x1f7 337 | mov al,0x20 338 | out dx,al 339 | 340 | ;;;;;;; 至此,硬盘控制器便从指定的lba地址(eax)处,读出连续的cx个扇区,下面检查硬盘状态,不忙就能把这cx个扇区的数据读出来 341 | 342 | ;第4步:检测硬盘状态 343 | .not_ready: ;测试0x1f7端口(status寄存器)的的BSY位 344 | ;同一端口,写时表示写入命令字,读时表示读入硬盘状态 345 | nop 346 | in al,dx 347 | and al,0x88 ;第4位为1表示硬盘控制器已准备好数据传输,第7位为1表示硬盘忙 348 | cmp al,0x08 349 | jnz .not_ready ;若未准备好,继续等。 350 | 351 | ;第5步:从0x1f0端口读数据 352 | mov ax, di ;以下从硬盘端口读数据用insw指令更快捷,不过尽可能多的演示命令使用, 353 | ;在此先用这种方法,在后面内容会用到insw和outsw等 354 | 355 | mov dx, 256 ;di为要读取的扇区数,一个扇区有512字节,每次读入一个字,共需di*512/2次,所以di*256 356 | mul dx 357 | mov cx, ax 358 | mov dx, 0x1f0 359 | .go_on_read: 360 | in ax,dx 361 | mov [ebx], ax 362 | add ebx, 2 363 | ; 由于在实模式下偏移地址为16位,所以用bx只会访问到0~FFFFh的偏移。 364 | ; loader的栈指针为0x900,bx为指向的数据输出缓冲区,且为16位, 365 | ; 超过0xffff后,bx部分会从0开始,所以当要读取的扇区数过大,待写入的地址超过bx的范围时, 366 | ; 从硬盘上读出的数据会把0x0000~0xffff的覆盖, 367 | ; 造成栈被破坏,所以ret返回时,返回地址被破坏了,已经不是之前正确的地址, 368 | ; 故程序出会错,不知道会跑到哪里去。 369 | ; 所以改为ebx代替bx指向缓冲区,这样生成的机器码前面会有0x66和0x67来反转。 370 | ; 0X66用于反转默认的操作数大小! 0X67用于反转默认的寻址方式. 371 | ; cpu处于16位模式时,会理所当然的认为操作数和寻址都是16位,处于32位模式时, 372 | ; 也会认为要执行的指令是32位. 373 | ; 当我们在其中任意模式下用了另外模式的寻址方式或操作数大小(姑且认为16位模式用16位字节操作数, 374 | ; 32位模式下用32字节的操作数)时,编译器会在指令前帮我们加上0x66或0x67, 375 | ; 临时改变当前cpu模式到另外的模式下. 376 | ; 假设当前运行在16位模式,遇到0X66时,操作数大小变为32位. 377 | ; 假设当前运行在32位模式,遇到0X66时,操作数大小变为16位. 378 | ; 假设当前运行在16位模式,遇到0X67时,寻址方式变为32位寻址 379 | ; 假设当前运行在32位模式,遇到0X67时,寻址方式变为16位寻址. 380 | 381 | loop .go_on_read 382 | ret -------------------------------------------------------------------------------- /Cpt7. Interrupt/boot/mbr.s: -------------------------------------------------------------------------------- 1 | %include "./include/boot.inc" 2 | SECTION MBR vstart=0x7c00 3 | mov ax,cs 4 | mov ds,ax 5 | mov es,ax 6 | mov ss,ax 7 | mov fs,ax 8 | mov sp,0x7c00 9 | mov ax,0xb800 10 | mov gs,ax 11 | 12 | ;清屏功能 13 | mov ax,0x600 14 | mov bx,0x700 15 | mov cx,0 16 | mov dx,0x184f 17 | int 0x10 18 | 19 | ;获取光标未知 20 | ;输出:cl:光标开始行,cl:光标结束行 21 | ; dl:光标所在行号,dl:光标所在列号 22 | 23 | ; 打印字符串 24 | mov byte [gs:0x00],'l' 25 | mov byte [gs:0x01],0xA4 26 | 27 | mov byte [gs:0x02],' ' 28 | mov byte [gs:0x03],0xA4 29 | 30 | mov byte [gs:0x04],'M' 31 | mov byte [gs:0x05],0xA4 32 | 33 | mov byte [gs:0x06],'B' 34 | mov byte [gs:0x07],0xA4 35 | 36 | mov byte [gs:0x08],'R' 37 | mov byte [gs:0x09],0xA4 38 | 39 | 40 | ;读取一个扇区(loader所在)道指定位置的内存中 41 | mov eax,LOADER_START_SECTOR ;硬盘中的lba地址 42 | mov bx,LOADER_BASE_ADDR ;写入的地址 43 | mov cx,4 ;读入的扇区数 44 | call rd_disk_m_16 45 | 46 | jmp LOADER_BASE_ADDR 47 | 48 | ; 函数rd_disk_m_16 49 | ; 功能:读取硬盘n个扇区 50 | ; eax = LBA硬盘号 51 | ; bx = 将数据写入的内存地址 52 | ; cx = 读入的扇区数 53 | rd_disk_m_16: 54 | mov esi,eax ;备份eax 55 | mov di,cx ;备份cx 56 | ;读写硬盘 57 | ;第一步:设置要读取的扇区数 58 | mov dx,0x1f2 ;指定读取的扇区数 59 | mov al,cl 60 | out dx,al 61 | mov eax,esi ;恢复ax 62 | 63 | ;第二部:将LBA地址存入0x1f3~0x1f6 64 | mov dx,0x1f3 65 | out dx,al 66 | 67 | mov cl,8 68 | shr eax,cl 69 | inc dx 70 | out dx,al 71 | 72 | shr eax,cl 73 | inc dx 74 | out dx,al 75 | 76 | shr eax,cl 77 | and al,0x0f 78 | or al,0xe0 79 | mov dx,0x1f6 80 | out dx,al 81 | ;第三步:向0x1f7端口写入读命令,0x20 82 | mov dx,0x1f7 83 | mov al,0x20 84 | out dx,al 85 | 86 | ;第四步:检测硬盘状态 87 | .not_ready: 88 | nop 89 | in al,dx 90 | and al,0x88 91 | cmp al,0x08 92 | jnz .not_ready 93 | ;第五步:0x1f0端口读取数据 94 | mov ax,di 95 | ;一次读取一个字,所以是512/2*di 96 | mov dx,256 97 | mul dx 98 | mov cx,ax 99 | mov dx,0x1f0 100 | .go_on_read: 101 | in ax,dx 102 | mov [bx],ax 103 | add bx,2 104 | loop .go_on_read 105 | ret 106 | 107 | times 510-($-$$) db 0 108 | db 0x55,0xaa 109 | -------------------------------------------------------------------------------- /Cpt7. Interrupt/kernel/main.c: -------------------------------------------------------------------------------- 1 | #include "print.h" 2 | 3 | int main(void){ 4 | put_str("I am kernel\n"); 5 | put_int(0); 6 | put_char('\n'); 7 | put_int(9); 8 | put_char('\n'); 9 | put_int(0x00021a3f); 10 | put_char('\n'); 11 | put_int(0x12345678); 12 | put_char('\n'); 13 | put_int(0x00000000); 14 | while(1); 15 | return 0; 16 | } -------------------------------------------------------------------------------- /Cpt7. Interrupt/lib/kernel/print.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIB_KERNEL_PRINT_H 2 | #define __LIB_KERNEL_PRINT_H 3 | #include "../stdint.h" 4 | void put_char(uint8_t char_asci); 5 | void put_str(char* message); 6 | void put_int(uint32_t num); 7 | #endif -------------------------------------------------------------------------------- /Cpt7. Interrupt/lib/kernel/print.s: -------------------------------------------------------------------------------- 1 | TI_GDT equ 0 2 | RPL0 equ 0 3 | SELECTOR_VIDEO equ (0x0003<<3) + TI_GDT + RPL0 4 | 5 | section .data 6 | put_int_buffer dq 0 ; 定义8字节缓冲区用于数字到字符的转换 7 | 8 | [bits 32] 9 | section .text 10 | ;-------------------------------------------- 11 | ;put_str 通过put_char来打印以0字符结尾的字符串 12 | ;-------------------------------------------- 13 | ;输入:栈中参数为打印的字符串 14 | ;输出:无 15 | 16 | global put_str 17 | put_str: 18 | ;由于本函数中只用到了ebx和ecx,只备份这两个寄存器 19 | push ebx 20 | push ecx 21 | xor ecx, ecx ; 准备用ecx存储参数,清空 22 | mov ebx, [esp + 12] ; 从栈中得到待打印的字符串地址 23 | .goon: 24 | mov cl, [ebx] 25 | cmp cl, 0 ; 如果处理到了字符串尾,跳到结束处返回 26 | jz .str_over 27 | push ecx ; 为put_char函数传递参数 28 | call put_char 29 | add esp, 4 ; 回收参数所占的栈空间 30 | inc ebx ; 使ebx指向下一个字符 31 | jmp .goon 32 | .str_over: 33 | pop ecx 34 | pop ebx 35 | ret 36 | 37 | ;------------------------ put_char ----------------------------- 38 | ;功能描述:把栈中的1个字符写入光标所在处 39 | ;------------------------------------------------------------------- 40 | global put_char 41 | put_char: 42 | pushad ;备份32位寄存器环境 43 | ;需要保证gs中为正确的视频段选择子,为保险起见,每次打印时都为gs赋值 44 | mov ax, SELECTOR_VIDEO ; 不能直接把立即数送入段寄存器 45 | mov gs, ax 46 | 47 | ;;;;;;;;; 获取当前光标位置 ;;;;;;;;; 48 | ;先获得高8位 49 | mov dx, 0x03d4 ;索引寄存器 50 | mov al, 0x0e ;用于提供光标位置的高8位 51 | out dx, al 52 | mov dx, 0x03d5 ;通过读写数据端口0x3d5来获得或设置光标位置 53 | in al, dx ;得到了光标位置的高8位 54 | mov ah, al 55 | 56 | ;再获取低8位 57 | mov dx, 0x03d4 58 | mov al, 0x0f 59 | out dx, al 60 | mov dx, 0x03d5 61 | in al, dx 62 | 63 | ;将光标存入bx 64 | mov bx, ax 65 | ;下面这行是在栈中获取待打印的字符 66 | mov ecx, [esp + 36] ;pushad压入4×8=32字节,加上主调函数的返回地址4字节,故esp+36字节 67 | cmp cl, 0xd ;CR是0x0d,LF是0x0a 68 | jz .is_carriage_return 69 | cmp cl, 0xa 70 | jz .is_line_feed 71 | 72 | cmp cl, 0x8 ;BS(backspace)的asc码是8 73 | jz .is_backspace 74 | jmp .put_other 75 | ;;;;;;;;;;;;;;;;;; 76 | 77 | .is_backspace: 78 | ;;;;;;;;;;;; backspace的一点说明 ;;;;;;;;;; 79 | ; 当为backspace时,本质上只要将光标移向前一个显存位置即可.后面再输入的字符自然会覆盖此处的字符 80 | ; 但有可能在键入backspace后并不再键入新的字符,这时在光标已经向前移动到待删除的字符位置,但字符还在原处, 81 | ; 这就显得好怪异,所以此处添加了空格或空字符0 82 | dec bx 83 | shl bx,1 84 | mov byte [gs:bx], 0x20 ;将待删除的字节补为0或空格皆可 85 | inc bx 86 | mov byte [gs:bx], 0x07 87 | shr bx,1 88 | jmp .set_cursor 89 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 90 | 91 | .put_other: 92 | shl bx, 1 ; 光标位置是用2字节表示,将光标值乘2,表示对应显存中的偏移字节 93 | mov [gs:bx], cl ; ascii字符本身 94 | inc bx 95 | mov byte [gs:bx],0x07 ; 字符属性 96 | shr bx, 1 ; 恢复老的光标值 97 | inc bx ; 下一个光标值 98 | cmp bx, 2000 99 | jl .set_cursor ; 若光标值小于2000,表示未写到显存的最后,则去设置新的光标值 100 | ; 若超出屏幕字符数大小(2000)则换行处理 101 | .is_line_feed: ; 是换行符LF(\n) 102 | .is_carriage_return: ; 是回车符CR(\r) 103 | ; 如果是CR(\r),只要把光标移到行首就行了。 104 | xor dx, dx ; dx是被除数的高16位,清0. 105 | mov ax, bx ; ax是被除数的低16位. 106 | mov si, 80 ; 由于是效仿linux,linux中\n便表示下一行的行首,所以本系统中, 107 | div si ; 把\n和\r都处理为linux中\n的意思,也就是下一行的行首。 108 | sub bx, dx ; 光标值减去除80的余数便是取整 109 | ; 以上4行处理\r的代码 110 | 111 | .is_carriage_return_end: ; 回车符CR处理结束 112 | add bx, 80 113 | cmp bx, 2000 114 | .is_line_feed_end: ; 若是LF(\n),将光标移+80便可。 115 | jl .set_cursor 116 | 117 | ;屏幕行范围是0~24,滚屏的原理是将屏幕的1~24行搬运到0~23行,再将第24行用空格填充 118 | .roll_screen: ; 若超出屏幕大小,开始滚屏 119 | cld 120 | mov ecx, 960 ; 一共有2000-80=1920个字符要搬运,共1920*2=3840字节.一次搬4字节,共3840/4=960次 121 | mov esi, 0xb80a0 ; 第1行行首 122 | mov edi, 0xb8000 ; 第0行行首 123 | rep movsd 124 | 125 | ;;;;;;;将最后一行填充为空白 126 | mov ebx, 3840 ; 最后一行首字符的第一个字节偏移= 1920 * 2 127 | mov ecx, 80 ;一行是80字符(160字节),每次清空1字符(2字节),一行需要移动80次 128 | .cls: 129 | mov word [gs:ebx], 0x0720 ;0x0720是黑底白字的空格键 130 | add ebx, 2 131 | loop .cls 132 | mov bx,1920 ;将光标值重置为1920,最后一行的首字符. 133 | 134 | .set_cursor: 135 | ;将光标设为bx值 136 | ;;;;;;; 1 先设置高8位 ;;;;;;;; 137 | mov dx, 0x03d4 ;索引寄存器 138 | mov al, 0x0e ;用于提供光标位置的高8位 139 | out dx, al 140 | mov dx, 0x03d5 ;通过读写数据端口0x3d5来获得或设置光标位置 141 | mov al, bh 142 | out dx, al 143 | 144 | ;;;;;;; 2 再设置低8位 ;;;;;;;;; 145 | mov dx, 0x03d4 146 | mov al, 0x0f 147 | out dx, al 148 | mov dx, 0x03d5 149 | mov al, bl 150 | out dx, al 151 | .put_char_done: 152 | popad 153 | ret 154 | 155 | ;-------------------- 将小端字节序的数字变成对应的ascii后,倒置 ----------------------- 156 | ;输入:栈中参数为待打印的数字 157 | ;输出:在屏幕上打印16进制数字,并不会打印前缀0x,如打印10进制15时,只会直接打印f,不会是0xf 158 | ;------------------------------------------------------------------------------------------ 159 | global put_int 160 | put_int: 161 | pushad 162 | mov ebp, esp 163 | mov eax, [ebp+4*9] ; call的返回地址占4字节+pushad的8个4字节 164 | mov edx, eax 165 | mov edi, 7 ; 指定在put_int_buffer中初始的偏移量 166 | mov ecx, 8 ; 32位数字中,16进制数字的位数是8个 167 | mov ebx, put_int_buffer 168 | 169 | ;将32位数字按照16进制的形式从低位到高位逐个处理,共处理8个16进制数字 170 | .16based_4bits: ; 每4位二进制是16进制数字的1位,遍历每一位16进制数字 171 | and edx, 0x0000000F ; 解析16进制数字的每一位。and与操作后,edx只有低4位有效 172 | cmp edx, 9 ; 数字0~9和a~f需要分别处理成对应的字符 173 | jg .is_A2F 174 | add edx, '0' ; ascii码是8位大小。add求和操作后,edx低8位有效。 175 | jmp .store 176 | .is_A2F: 177 | sub edx, 10 ; A~F 减去10 所得到的差,再加上字符A的ascii码,便是A~F对应的ascii码 178 | add edx, 'A' 179 | 180 | ;将每一位数字转换成对应的字符后,按照类似“大端”的顺序存储到缓冲区put_int_buffer 181 | ;高位字符放在低地址,低位字符要放在高地址,这样和大端字节序类似,只不过咱们这里是字符序. 182 | .store: 183 | ; 此时dl中应该是数字对应的字符的ascii码 184 | mov [ebx+edi], dl 185 | dec edi 186 | shr eax, 4 187 | mov edx, eax 188 | loop .16based_4bits 189 | 190 | ;现在put_int_buffer中已全是字符,打印之前, 191 | ;把高位连续的字符去掉,比如把字符000123变成123 192 | .ready_to_print: 193 | inc edi ; 此时edi退减为-1(0xffffffff),加1使其为0 194 | .skip_prefix_0: 195 | cmp edi,8 ; 若已经比较第9个字符了,表示待打印的字符串为全0 196 | je .full0 197 | ;找出连续的0字符, edi做为非0的最高位字符的偏移 198 | .go_on_skip: 199 | mov cl, [put_int_buffer+edi] 200 | inc edi 201 | cmp cl, '0' 202 | je .skip_prefix_0 ; 继续判断下一位字符是否为字符0(不是数字0) 203 | dec edi ;edi在上面的inc操作中指向了下一个字符,若当前字符不为'0',要恢复edi指向当前字符 204 | jmp .put_each_num 205 | 206 | .full0: 207 | mov cl,'0' ; 输入的数字为全0时,则只打印0 208 | .put_each_num: 209 | push ecx ; 此时cl中为可打印的字符 210 | call put_char 211 | add esp, 4 212 | inc edi ; 使edi指向下一个字符 213 | mov cl, [put_int_buffer+edi] ; 获取下一个字符到cl寄存器 214 | cmp edi,8 215 | jl .put_each_num 216 | popad 217 | ret 218 | -------------------------------------------------------------------------------- /Cpt7. Interrupt/lib/stdint.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIB_STDINT_H 2 | #define __LIB_STDINT_H 3 | typedef signed char int8_t; 4 | typedef signed short int int16_t; 5 | typedef signed int int32_t; 6 | typedef signed long long int int64_t; 7 | typedef unsigned char uint8_t; 8 | typedef unsigned short int uint16_t; 9 | typedef unsigned int uint32_t; 10 | typedef unsigned long long int uint64_t; 11 | #endif -------------------------------------------------------------------------------- /Cpt7. Interrupt/run_bochs.sh: -------------------------------------------------------------------------------- 1 | cd ./boot 2 | nasm -o ./mbr.bin ./mbr.s 3 | nasm -o ./loader.bin ./loader.s 4 | cd .. 5 | 6 | nasm -f elf -o ./lib/kernel/print.o ./lib/kernel/print.s 7 | 8 | gcc -m32 -I ./lib/kernel/ -c -o ./kernel/main.o ./kernel/main.c 9 | 10 | ld -m elf_i386 -Ttext 0xc0001500 -e main -o kernel.bin kernel/main.o lib/kernel/print.o 11 | 12 | rm ./lib/kernel/print.o 13 | rm ./kernel/main.o 14 | 15 | 16 | ../bochs/bin/bximage -mode=create -hd=60M -imgmode="flat" -q ../bochs/bin/hd60M.img 17 | dd if=./boot/mbr.bin of=../bochs/bin/hd60M.img bs=512 count=1 conv=notrunc 18 | dd if=./boot/loader.bin of=../bochs/bin/hd60M.img bs=512 count=4 conv=notrunc seek=2 19 | dd if=./kernel.bin of=../bochs/bin/hd60M.img bs=512 count=200 conv=notrunc seek=9 20 | 21 | cd ../bochs/bin 22 | rm ./hd60M.img.lock 23 | ./bochs -f ./bochsrc.disk 24 | rm ./hd60M.img 25 | 26 | 27 | cd ../../Cpt7.\ Interrupt 28 | rm ./boot/mbr.bin 29 | rm ./boot/loader.bin 30 | rm ./kernel.bin -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kernel-Learning 2 | 从0开始写一个操作系统——《操作系统真象还原》 3 | 4 | bochs运行方式: 5 | 6 | `git clone https://github.com/Gstalker/Kernel-Learning.git` 7 | 8 | 然后打开对应章节的文件夹 9 | 10 | `./run_bochs.sh` 11 | 12 | -------------------------------------------------------------------------------- /bochs/bin/bochs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/bin/bochs -------------------------------------------------------------------------------- /bochs/bin/bximage: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/bin/bximage -------------------------------------------------------------------------------- /bochs/share/bochs/BIOS-bochs-latest: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/share/bochs/BIOS-bochs-latest -------------------------------------------------------------------------------- /bochs/share/bochs/BIOS-bochs-legacy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/share/bochs/BIOS-bochs-legacy -------------------------------------------------------------------------------- /bochs/share/bochs/SeaBIOS-README: -------------------------------------------------------------------------------- 1 | SeaBIOS is an open source implementation of a 16bit X86 BIOS. SeaBIOS 2 | can run in an emulator or it can run natively on X86 hardware with the 3 | use of coreboot (http://www.coreboot.org/). 4 | 5 | SeaBIOS is the default BIOS for qemu (http://www.qemu.org/) and 6 | kvm (http://www.linux-kvm.org/). 7 | 8 | The coreboot SeaBIOS (http://www.coreboot.org/SeaBIOS) page has 9 | information on using SeaBIOS in coreboot. Please see the 10 | releases page for information on recent releases. See the 11 | download page to obtain SeaBIOS. 12 | 13 | SeaVGABIOS is a sub-project of SeaBIOS. 14 | 15 | Please join the mailing list to contribute to SeaBIOS. Information on 16 | the internals of SeaBIOS is available on the Developer Documentation page. 17 | -------------------------------------------------------------------------------- /bochs/share/bochs/VGABIOS-elpin-2.40: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/share/bochs/VGABIOS-elpin-2.40 -------------------------------------------------------------------------------- /bochs/share/bochs/VGABIOS-elpin-LICENSE: -------------------------------------------------------------------------------- 1 | The VGA BIOS from Elpin Systems, Inc. (http://www.elpin.com/) 2 | is now permanently licensed for use with bochs, courtesy 3 | of MandrakeSoft, creators of the leading "Linux-Mandrake" 4 | distribution (http://www.linux-mandrake.com/). You may 5 | freely use/distribute it with bochs, as long as it is used 6 | in bochs for the intended use as a VGA BIOS. 7 | 8 | Please check out Elpin Systems. They make cool software games, 9 | educational software, and VGA development products. 10 | -------------------------------------------------------------------------------- /bochs/share/bochs/VGABIOS-lgpl-README: -------------------------------------------------------------------------------- 1 | Plex86/Bochs VGABios 2 | -------------------- 3 | 4 | The goal of this project is to have a LGPL'd Video Bios in plex86, 5 | Bochs and qemu. 6 | This VGA Bios is very specific to the emulated VGA card. 7 | It is NOT meant to drive a physical vga card. 8 | 9 | 10 | Cirrus SVGA extension 11 | --------------------- 12 | 13 | The Cirrus SVGA extension is designed for the Cirrus emulation in Bochs and 14 | qemu. The initial patch for the Cirrus extension has been written by Makoto 15 | Suzuki (suzu). 16 | 17 | 18 | Install 19 | ------- 20 | To compile the VGA Bios you will need the following packages: 21 | - make 22 | - gcc (for 'biossums', 'vbetables-gen' and VGABIOS preprocessing) 23 | - dev86 (bcc, as86) 24 | 25 | Untar the archive, and type 'make'. You should get this set of binary files: 26 | "VGABIOS-lgpl-latest.bin", "VGABIOS-lgpl-latest.debug.bin", 27 | "VGABIOS-lgpl-latest.cirrus.bin" and "VGABIOS-lgpl-latest.cirrus.debug.bin". 28 | Alternatively, you can use one of the precompiled binary files present in 29 | the archive. 30 | 31 | Edit your bochs config file, and modify the 'vgaromimage' directive to point 32 | it to the VGABIOS image you want to use. 33 | 34 | 35 | Debugging 36 | --------- 37 | You can get a very basic debugging system: the VGABIOS sends messages to a 38 | usually unused ISA i/o port. The emulator prints the received characters to 39 | log file or console. In Bochs the "unmapped" device plugin must be loaded. 40 | It registers the VGABIOS info port 0x500. 41 | 42 | VGABIOS images compiled with the DEBUG symbol set, will use the "printf" 43 | function to write the messages to the info port. 44 | 45 | 46 | Testing 47 | ------- 48 | Look at the "testvga.c" file in the archive. This is a minimal Turbo C 2.0 49 | source file that calls a few int10 functions. Feel free to modify it to suit 50 | your needs. 51 | 52 | 53 | Copyright and License 54 | --------------------- 55 | The original version of this program has been written by Christophe Bothamy. 56 | It is protected by the GNU Lesser Public License, which you should 57 | have received a copy of along with this package. 58 | 59 | 60 | Reverse Engineering 61 | ------------------- 62 | The VGA Bios has been written without reverse-engineering any existing Bios. 63 | 64 | 65 | Acknowledgment 66 | -------------- 67 | The source code contains code ripped from rombios.c of plex86, written 68 | by Kevin Lawton 69 | 70 | The source code contains fonts from fntcol16.zip (c) by Joseph Gil avalable at : 71 | ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip 72 | These fonts are public domain 73 | 74 | The source code is based on information taken from : 75 | - Kevin Lawton's vga card emulation for bochs/plex86 76 | - Ralf Brown's interrupts list avalaible at 77 | http://www.cs.cmu.edu/afs/cs/user/ralf/pub/WWW/files.html 78 | - Finn Thogersons' VGADOC4b available at http://home.worldonline.dk/~finth/ 79 | - Michael Abrash's Graphics Programming Black Book 80 | - Francois Gervais' book "programmation des cartes graphiques cga-ega-vga" 81 | edited by sybex 82 | - DOSEMU 1.0.1 source code for several tables values and formulas 83 | 84 | 85 | Feedback 86 | -------- 87 | Please report any bugs, comments, patches for this VGA Bios 88 | on savannah pages at: http://savannah.nongnu.org/projects/vgabios/ 89 | You can find the latest release at : http://www.nongnu.org/vgabios/ 90 | For any information on bochs, visit the website http://bochs.sourceforge.net/ 91 | For any information on Qemu, visit the website http://wiki.qemu.org/ 92 | 93 | 94 | History 95 | ------- 96 | vgabios-0.7b : Jan 03 2020 97 | - Volker 98 | - added VESA BIOS function 0x4f09 (set/get palette data) to the Bochs VBE 99 | version 100 | - added VESA BIOS function 0x4f15 (get EDID) to both the Bochs VBE and 101 | the Cirrus version 102 | - fixed building VBE modes list (check maximum y resolution) 103 | - ensure PCIR is aligned to 4 bytes (patch by David Woodhouse) 104 | 105 | vgabios-0.7a : Oct 30 2011 106 | - Volker 107 | . added HDTV resolutions (patch by Tristan Schmelcher) 108 | . added PCI ROM support to the VBE-specific images 109 | . implemented vgabios functions with AX=0x112x (patch by Hugo Mercier) 110 | . fixed DAC palette in 8 bpp VBE and Cirrus modes (using the same palette 111 | as VGA mode 0x13) 112 | . Makefile cleanup (patch by Gerd Hoffmann) 113 | 114 | vgabios-0.6c : Apr 08 2009 115 | - Volker 116 | . added DPMS support to cirrus vgabios (patch from Gleb Natapov) 117 | . use VBE LFB address from PCI base address if present 118 | . added support for a lot more non-standard VBE modes (e.g. widescreen modes) 119 | . minor bugfixes 120 | 121 | vgabios-0.6b : May 30 2008 122 | - Volker 123 | . added PCI data structure for the Cirrus VGABIOS images 124 | . minor bugfixes in biossums utility, VBE support and makefile 125 | 126 | vgabios-0.6a : Aug 19 2006 127 | - Volker 128 | . added minimal support for the video parameter table (VPT) 129 | . Cirrus SVGA now supports the "no clear" bit in Cirrus and VESA mode 130 | . Bochs VBE protected mode interface improved 131 | . save/restore video state support for Bochs VBE and standard VGA added 132 | . generate vbetables.h dynamicly 133 | . VBE video memory increased to 8 MB (VBE dispi ID changed to B0C4) 134 | . lots of 4bpp VBE fixes (all 4bpp VBE modes now enabled) 135 | . VGA compatible setup for VBE modes added 136 | 137 | vgabios-0.5d : Dec 29 2005 138 | - Volker 139 | . Bochs VBE protected mode interface added (based on a patch by malc@pulsesoft.com) 140 | . biossums utility now supports VGABIOS sizes up to 64 kBytes 141 | . VGA mode 0x11: all color planes must be enabled in this 2-color VGA mode 142 | 143 | vgabios-0.5c : Jul 07 2005 144 | - Volker 145 | . BIOS configuration word usually reports initial mode 80x25 color text 146 | . vgabios function 0x0e (write teletype): linefeed (0x0a) only increments the 147 | cursor row value 148 | 149 | vgabios-0.5b : May 24 2005 150 | - Volker 151 | . fixed return value for the default case in the VBE section (non-debug mode) 152 | . removed unused stuff 153 | 154 | vgabios-0.5a : Mar 07 2005 155 | - Volker 156 | . Cirrus SVGA extension (initial patches from Makoto Suzuki, improvements 157 | from Fabrice Bellard) 158 | . vgabios image size is now exactly 32k with a checksum 159 | . a lot of vgabios and vbe functions rewritten in assembler 160 | . dynamicly generated VBE mode info list 161 | . write character function for CGA and LINEAR8 modes 162 | . read/write graphics pixel for some graphics modes 163 | . text scroll feature for some graphics modes 164 | . VBE 8-bit DAC support 165 | 166 | vgabios-0.4c : Nov 06 2003 167 | - Christophe 168 | . fix font problem on initial screen of NT4 Loader 169 | 170 | vgabios-0.4b : Nov 04 2003 171 | - Volker 172 | . fix offset of character tables 173 | . optimizations of CRT controller accesses 174 | . VBE i/o registers changed to 0x01CE/CF 175 | (suggestion from Daniel Gimpelevich) 176 | . "noclear" flag stored in BIOS area 177 | . fix character height returned by get_font_info function 178 | 179 | vgabios-0.4a : Aug 17 2003 180 | - Volker 181 | . VBE mode search rewritten (VBE modes with LFB bit removed) 182 | . many bugfixes and optimizations 183 | . write character function implemented for graphics modes 184 | . support for 15bpp, 16bpp, 24bpp and 32bpp VBE modes added 185 | . SVGA mode 0x6A added 186 | . VBE modes 0x102, 0x117, 0x118 and 0x142 (Bochs specific) 187 | 188 | vgabios-0.3b : Nov 23 2002 189 | - Christophe 190 | . added lfb-mode numbers (patch from mathis) 191 | . updated the Makefile 192 | . removed display of copyrights. 193 | . changed the Copyright string to "LGPL VGABios developers" 194 | - Volker 195 | . set the cursor shape depending on the current font height 196 | . clear BL before calling int 0x10 function 0x1103 in vgabios_init_func 197 | . added some text font functions 198 | - Jeroen 199 | . Forced to new DISPI (0xb0c1) interface (requires latest bochs vbe code) 200 | . Added multibuffering support 201 | . Added new DISPI interface for: virt width, height, x offset, y offset 202 | . Added LFB modes (to be used with the vbe-lfb patch in bochs) 203 | see VBE_HAVE_LFB in vbe.c (currently default enabled) 204 | . updated TODO & docs for changes after bochs 1.4 205 | 206 | vgabios-0.3a : Mar 10 2002 207 | - Christophe 208 | . Fixed bug in function ah=13 209 | - Jeroen 210 | . updated vbebios implementation to new api 211 | . added vbe_display_api documentation 212 | . added 640x400x8, 640x480x8, 800x600x8, 1024x768 213 | (>640x480 needs a special bochs patch atm) 214 | . added 320x200x8 vbe support (uses the standard 320x200x8 vga mode to 215 | display, this allows for testing & having something on screen as well, 216 | at least until bochs host side display is up & running) 217 | . adding lfbprof (vbe) testprogram (+some small fixes to it) 218 | . merging with vbebios 0.2 219 | 220 | vgabios-0.2b : Nov 19 2001 221 | - Christophe 222 | . Fixed bug in function ah=13 223 | 224 | vgabios-0.2a : Nov 09 2001 225 | - Christophe 226 | . Included bugfix from techt@pikeonline.net about grayscale summing 227 | . Added the "IBM" string at org 0x1e as Bart Oldeman suggested 228 | . Fixed DS and ES that where inverted in the int10 parameters list! 229 | . The following have been implemented : 230 | - function ax=1a00, ax=1a01, ah=1b 231 | - function ax=1130 232 | . Added debug messages for unimplemented/unknown functions 233 | Must be compiled with DEBUG defined. The output is trapped 234 | by the unknown-ioport driver of plex/bochs (port 0xfff0 is used) 235 | 236 | vgabios-0.1a : May 8 2001 237 | - Christophe 238 | . First release. The work has been focused only on text mode. 239 | . The following have been implemented : 240 | - inits 241 | - int 10 handler 242 | - functions ah=00, ah=01, ah=02, ah=03, ah=05, ah=06, ah=07, ah=08 243 | ah=09, ah=0a, ah=0e, ah=0f, ax=1000, ax=1001, ax=1002, ax=1003 244 | ax=1007, ax=1008, ax=1009, ax=1010, ax=1012, ax=1013, ax=1015 245 | ax=1017, ax=1018, ax=1019, ax=101a, ax=101b, ah=12 bl=10, 246 | ah=12 bl=30, ah=12 bl=31, ah=12 bl=32, ah=12 bl=33, ah=12 bl=34 247 | ah=13 248 | -------------------------------------------------------------------------------- /bochs/share/bochs/VGABIOS-lgpl-latest: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/share/bochs/VGABIOS-lgpl-latest -------------------------------------------------------------------------------- /bochs/share/bochs/VGABIOS-lgpl-latest-cirrus: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/share/bochs/VGABIOS-lgpl-latest-cirrus -------------------------------------------------------------------------------- /bochs/share/bochs/VGABIOS-lgpl-latest-cirrus-debug: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/share/bochs/VGABIOS-lgpl-latest-cirrus-debug -------------------------------------------------------------------------------- /bochs/share/bochs/VGABIOS-lgpl-latest-debug: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/share/bochs/VGABIOS-lgpl-latest-debug -------------------------------------------------------------------------------- /bochs/share/bochs/bios.bin-1.13.0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/share/bochs/bios.bin-1.13.0 -------------------------------------------------------------------------------- /bochs/share/bochs/keymaps/sdl-pc-de.map: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/share/bochs/keymaps/sdl-pc-de.map -------------------------------------------------------------------------------- /bochs/share/bochs/keymaps/sdl-pc-us.map: -------------------------------------------------------------------------------- 1 | # Bochs Keymap file 2 | # $Id: sdl-pc-us.map 12400 2014-07-06 18:29:06Z vruppert $ 3 | # Target: PC(x86) keyboard, US keymap, SDL gui 4 | # Author: Bryce Denney 5 | # 6 | # The keymap file describes the layout of a keyboard, and how it translates 7 | # into Bochs key codes. 8 | # 9 | # Format: 10 | # BX_Keysym ASCII_equivalent Host_key_name 11 | # 12 | # Or, for keys that require modifiers: 13 | # BX_Keysym+BX_Modifier ASCII_equivalent Host_key_name 14 | # 15 | # BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in 16 | # gui/keymap.cc. The BX_Modifier is usually a shift key press, but it 17 | # could be any key. Presently a maximum of one modifier is supported, but this 18 | # could be changed in keymap.h (structure def has only one slot for modifier), 19 | # keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1 20 | # modifier). 21 | # 22 | # The ASCII_equivalent must be either apostrophe + one character + apostrophe, 23 | # or one of these keywords: space, return, tab, backslash, apostrophe, none. 24 | # This format is designed to look like a char constant in C, but it's a very 25 | # simple parser. There's no concept of backslash being an escape char. The 26 | # backslash and apostrophe entries are provided for aesthetic purposes only: no 27 | # C++ programmer wants to see '\' or '''. The parser doesn't care, but they are 28 | # ugly. 29 | # 30 | # Host_key_name is the name of the key combination according to the gui library 31 | # (X windows, SDL, etc). Each GUI module must provide a function that converts 32 | # these host key names into numbers. A pointer to the conversion function is 33 | # passed to loadKeymap(), and it is used when parsing the keymap file. As the 34 | # keymap file is parsed, the conversion function is called for each host key 35 | # name, to convert it into a number. Only the number is stored. If the host 36 | # key name is not found, the conversion function returns BX_KEYMAP_UNKNOWN, and 37 | # the keymap code will panic, like this: 38 | # 39 | # [KMAP ] line 51: unknown host key name 'SDLK_PAREN_RIGHT' 40 | # 41 | # If this happens, you must edit the keymap file, and either correct the host 42 | # key name or comment out that line. 43 | # 44 | 45 | BX_KEY_0 '0' SDLK_0 46 | BX_KEY_0+BX_KEY_SHIFT_L ')' SDLK_RIGHTPAREN 47 | BX_KEY_1 '1' SDLK_1 48 | BX_KEY_1+BX_KEY_SHIFT_L '!' SDLK_EXCLAIM 49 | BX_KEY_2 '2' SDLK_2 50 | BX_KEY_2+BX_KEY_SHIFT_L '@' SDLK_AT 51 | BX_KEY_3 '3' SDLK_3 52 | BX_KEY_3+BX_KEY_SHIFT_L '#' SDLK_HASH 53 | BX_KEY_4 '4' SDLK_4 54 | BX_KEY_4+BX_KEY_SHIFT_L '$' SDLK_DOLLAR 55 | BX_KEY_5 '5' SDLK_5 56 | #BX_KEY_5+BX_KEY_SHIFT_L '%' SDLK_PERCENT 57 | BX_KEY_6 '6' SDLK_6 58 | BX_KEY_6+BX_KEY_SHIFT_L '^' SDLK_CARET 59 | BX_KEY_7 '7' SDLK_7 60 | BX_KEY_7+BX_KEY_SHIFT_L '&' SDLK_AMPERSAND 61 | BX_KEY_8 '8' SDLK_8 62 | BX_KEY_8+BX_KEY_SHIFT_L '*' SDLK_ASTERISK 63 | BX_KEY_9 '9' SDLK_9 64 | BX_KEY_9+BX_KEY_SHIFT_L '(' SDLK_LEFTPAREN 65 | BX_KEY_A+BX_KEY_SHIFT_L 'A' SDLK_a 66 | BX_KEY_A 'a' SDLK_a 67 | BX_KEY_B+BX_KEY_SHIFT_L 'B' SDLK_b 68 | BX_KEY_B 'b' SDLK_b 69 | BX_KEY_C+BX_KEY_SHIFT_L 'C' SDLK_c 70 | BX_KEY_C 'c' SDLK_c 71 | BX_KEY_D+BX_KEY_SHIFT_L 'D' SDLK_d 72 | BX_KEY_D 'd' SDLK_d 73 | BX_KEY_E+BX_KEY_SHIFT_L 'E' SDLK_e 74 | BX_KEY_E 'e' SDLK_e 75 | BX_KEY_F+BX_KEY_SHIFT_L 'F' SDLK_f 76 | BX_KEY_F 'f' SDLK_f 77 | BX_KEY_G+BX_KEY_SHIFT_L 'G' SDLK_g 78 | BX_KEY_G 'g' SDLK_g 79 | BX_KEY_H+BX_KEY_SHIFT_L 'H' SDLK_h 80 | BX_KEY_H 'h' SDLK_h 81 | BX_KEY_I+BX_KEY_SHIFT_L 'I' SDLK_i 82 | BX_KEY_I 'i' SDLK_i 83 | BX_KEY_J+BX_KEY_SHIFT_L 'J' SDLK_j 84 | BX_KEY_J 'j' SDLK_j 85 | BX_KEY_K+BX_KEY_SHIFT_L 'K' SDLK_k 86 | BX_KEY_K 'k' SDLK_k 87 | BX_KEY_L+BX_KEY_SHIFT_L 'L' SDLK_l 88 | BX_KEY_L 'l' SDLK_l 89 | BX_KEY_M+BX_KEY_SHIFT_L 'M' SDLK_m 90 | BX_KEY_M 'm' SDLK_m 91 | BX_KEY_N+BX_KEY_SHIFT_L 'N' SDLK_n 92 | BX_KEY_N 'n' SDLK_n 93 | BX_KEY_O+BX_KEY_SHIFT_L 'O' SDLK_o 94 | BX_KEY_O 'o' SDLK_o 95 | BX_KEY_P+BX_KEY_SHIFT_L 'P' SDLK_p 96 | BX_KEY_P 'p' SDLK_p 97 | BX_KEY_Q+BX_KEY_SHIFT_L 'Q' SDLK_q 98 | BX_KEY_Q 'q' SDLK_q 99 | BX_KEY_R+BX_KEY_SHIFT_L 'R' SDLK_r 100 | BX_KEY_R 'r' SDLK_r 101 | BX_KEY_S+BX_KEY_SHIFT_L 'S' SDLK_s 102 | BX_KEY_S 's' SDLK_s 103 | BX_KEY_T+BX_KEY_SHIFT_L 'T' SDLK_t 104 | BX_KEY_T 't' SDLK_t 105 | BX_KEY_U+BX_KEY_SHIFT_L 'U' SDLK_u 106 | BX_KEY_U 'u' SDLK_u 107 | BX_KEY_V+BX_KEY_SHIFT_L 'V' SDLK_v 108 | BX_KEY_V 'v' SDLK_v 109 | BX_KEY_W+BX_KEY_SHIFT_L 'W' SDLK_w 110 | BX_KEY_W 'w' SDLK_w 111 | BX_KEY_X+BX_KEY_SHIFT_L 'X' SDLK_x 112 | BX_KEY_X 'x' SDLK_x 113 | BX_KEY_Y+BX_KEY_SHIFT_L 'Y' SDLK_y 114 | BX_KEY_Y 'y' SDLK_y 115 | BX_KEY_Z+BX_KEY_SHIFT_L 'Z' SDLK_z 116 | BX_KEY_Z 'z' SDLK_z 117 | BX_KEY_F1 none SDLK_F1 118 | BX_KEY_F2 none SDLK_F2 119 | BX_KEY_F3 none SDLK_F3 120 | BX_KEY_F4 none SDLK_F4 121 | BX_KEY_F5 none SDLK_F5 122 | BX_KEY_F6 none SDLK_F6 123 | BX_KEY_F7 none SDLK_F7 124 | BX_KEY_F8 none SDLK_F8 125 | BX_KEY_F9 none SDLK_F9 126 | BX_KEY_F10 none SDLK_F10 127 | BX_KEY_F11 none SDLK_F11 128 | BX_KEY_F12 none SDLK_F12 129 | BX_KEY_ALT_L none SDLK_LALT 130 | BX_KEY_ALT_L none SDLK_LMETA 131 | BX_KEY_ALT_R none SDLK_MODE 132 | #BX_KEY_ALT_R none SDLK_Multi_key 133 | BX_KEY_BACKSLASH backslash SDLK_BACKSLASH 134 | #BX_KEY_BACKSLASH+BX_KEY_SHIFT_L '|' SDLK_bar 135 | BX_KEY_BACKSPACE none SDLK_BACKSPACE 136 | BX_KEY_CAPS_LOCK none SDLK_CAPSLOCK 137 | BX_KEY_COMMA ',' SDLK_COMMA 138 | BX_KEY_COMMA+BX_KEY_SHIFT_L '<' SDLK_LESS 139 | BX_KEY_CTRL_L none SDLK_LCTRL 140 | BX_KEY_CTRL_R none SDLK_RCTRL 141 | BX_KEY_DELETE none SDLK_DELETE 142 | BX_KEY_DOWN none SDLK_DOWN 143 | BX_KEY_END none SDLK_END 144 | BX_KEY_ENTER return SDLK_RETURN 145 | BX_KEY_EQUALS '=' SDLK_EQUALS 146 | BX_KEY_EQUALS+BX_KEY_SHIFT_L '+' SDLK_PLUS 147 | BX_KEY_ESC none SDLK_ESCAPE 148 | #BX_KEY_GRAVE+BX_KEY_SHIFT_L '~' SDLK_asciitilde 149 | BX_KEY_GRAVE '`' SDLK_BACKQUOTE 150 | BX_KEY_HOME none SDLK_HOME 151 | BX_KEY_INSERT none SDLK_INSERT 152 | BX_KEY_KP_5 none SDLK_KP5 153 | #BX_KEY_KP_5 none SDLK_KP_BEGIN 154 | BX_KEY_KP_ADD none SDLK_KP_PLUS 155 | BX_KEY_KP_DELETE none SDLK_KP_PERIOD 156 | #BX_KEY_KP_DELETE none SDLK_KP_DELETE 157 | BX_KEY_KP_DIVIDE none SDLK_KP_DIVIDE 158 | BX_KEY_KP_DOWN none SDLK_KP2 159 | #BX_KEY_KP_DOWN none SDLK_KP_DOWN 160 | BX_KEY_KP_END none SDLK_KP1 161 | #BX_KEY_KP_END none SDLK_KP_END 162 | BX_KEY_KP_ENTER none SDLK_KP_ENTER 163 | BX_KEY_KP_HOME none SDLK_KP7 164 | #BX_KEY_KP_HOME none SDLK_KP_HOME 165 | BX_KEY_KP_INSERT none SDLK_KP0 166 | #BX_KEY_KP_INSERT none SDLK_KP_INSERT 167 | BX_KEY_KP_LEFT none SDLK_KP4 168 | #BX_KEY_KP_LEFT none SDLK_KP_LEFT 169 | BX_KEY_KP_MULTIPLY none SDLK_KP_MULTIPLY 170 | BX_KEY_KP_PAGE_DOWN none SDLK_KP3 171 | #BX_KEY_KP_PAGE_DOWN none SDLK_KP_PAGE_DOWN 172 | BX_KEY_KP_PAGE_UP none SDLK_KP9 173 | #BX_KEY_KP_PAGE_UP none SDLK_KP_PAGE_UP 174 | BX_KEY_KP_RIGHT none SDLK_KP6 175 | #BX_KEY_KP_RIGHT none SDLK_KP_Right 176 | BX_KEY_KP_SUBTRACT none SDLK_KP_MINUS 177 | BX_KEY_KP_UP none SDLK_KP8 178 | #BX_KEY_KP_UP none SDLK_KP_Up 179 | BX_KEY_LEFT none SDLK_LEFT 180 | #BX_KEY_LEFT_BRACKET+BX_KEY_SHIFT_L '{' SDLK_BRACELEFT 181 | BX_KEY_LEFT_BRACKET '[' SDLK_LEFTBRACKET 182 | BX_KEY_MENU none SDLK_MENU 183 | BX_KEY_MINUS '-' SDLK_MINUS 184 | BX_KEY_MINUS+BX_KEY_SHIFT_L '_' SDLK_UNDERSCORE 185 | BX_KEY_NUM_LOCK none SDLK_NUMLOCK 186 | BX_KEY_PAGE_DOWN none SDLK_PAGEDOWN 187 | BX_KEY_PAGE_UP none SDLK_PAGEUP 188 | BX_KEY_PAUSE none SDLK_BREAK 189 | BX_KEY_PAUSE none SDLK_PAUSE 190 | BX_KEY_PERIOD+BX_KEY_SHIFT_L '>' SDLK_GREATER 191 | BX_KEY_PERIOD '.' SDLK_PERIOD 192 | BX_KEY_PRINT none SDLK_PRINT 193 | BX_KEY_PRINT none SDLK_SYSREQ 194 | BX_KEY_RIGHT none SDLK_RIGHT 195 | #BX_KEY_RIGHT_BRACKET+BX_KEY_SHIFT_L '}' SDLK_BRACERIGHT 196 | BX_KEY_RIGHT_BRACKET ']' SDLK_RIGHTBRACKET 197 | BX_KEY_SCRL_LOCK none SDLK_SCROLLOCK 198 | BX_KEY_SEMICOLON+BX_KEY_SHIFT_L ':' SDLK_COLON 199 | BX_KEY_SEMICOLON ';' SDLK_SEMICOLON 200 | BX_KEY_SHIFT_L none SDLK_LSHIFT 201 | BX_KEY_SHIFT_R none SDLK_RSHIFT 202 | BX_KEY_SINGLE_QUOTE apostrophe SDLK_QUOTE 203 | BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L '"' SDLK_QUOTEDBL 204 | BX_KEY_SLASH+BX_KEY_SHIFT_L '?' SDLK_QUESTION 205 | BX_KEY_SLASH '/' SDLK_SLASH 206 | BX_KEY_SPACE space SDLK_SPACE 207 | #BX_KEY_TAB none SDLK_ISO_LEFT_TAB 208 | BX_KEY_TAB tab SDLK_TAB 209 | BX_KEY_UP none SDLK_UP 210 | BX_KEY_WIN_L none SDLK_LSUPER 211 | BX_KEY_WIN_R none SDLK_LSUPER 212 | -------------------------------------------------------------------------------- /bochs/share/bochs/keymaps/sdl2-pc-de.map: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/share/bochs/keymaps/sdl2-pc-de.map -------------------------------------------------------------------------------- /bochs/share/bochs/keymaps/sdl2-pc-us.map: -------------------------------------------------------------------------------- 1 | # Bochs Keymap file 2 | # $Id: sdl2-pc-us.map 12400 2014-07-06 18:29:06Z vruppert $ 3 | # Target: PC(x86) keyboard, US keymap, SDL2 gui 4 | # Author: Volker Ruppert (based on SDL keymap by Bryce Denney) 5 | # 6 | # The keymap file describes the layout of a keyboard, and how it translates 7 | # into Bochs key codes. 8 | # 9 | # Format: 10 | # BX_Keysym ASCII_equivalent Host_key_name 11 | # 12 | # Or, for keys that require modifiers: 13 | # BX_Keysym+BX_Modifier ASCII_equivalent Host_key_name 14 | # 15 | # BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in 16 | # gui/keymap.cc. The BX_Modifier is usually a shift key press, but it 17 | # could be any key. Presently a maximum of one modifier is supported, but this 18 | # could be changed in keymap.h (structure def has only one slot for modifier), 19 | # keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1 20 | # modifier). 21 | # 22 | # The ASCII_equivalent must be either apostrophe + one character + apostrophe, 23 | # or one of these keywords: space, return, tab, backslash, apostrophe, none. 24 | # This format is designed to look like a char constant in C, but it's a very 25 | # simple parser. There's no concept of backslash being an escape char. The 26 | # backslash and apostrophe entries are provided for aesthetic purposes only: no 27 | # C++ programmer wants to see '\' or '''. The parser doesn't care, but they are 28 | # ugly. 29 | # 30 | # Host_key_name is the name of the key combination according to the gui library 31 | # (X windows, SDL, etc). Each GUI module must provide a function that converts 32 | # these host key names into numbers. A pointer to the conversion function is 33 | # passed to loadKeymap(), and it is used when parsing the keymap file. As the 34 | # keymap file is parsed, the conversion function is called for each host key 35 | # name, to convert it into a number. Only the number is stored. If the host 36 | # key name is not found, the conversion function returns BX_KEYMAP_UNKNOWN, and 37 | # the keymap code will panic, like this: 38 | # 39 | # [KMAP ] line 51: unknown host key name 'SDLK_PAREN_RIGHT' 40 | # 41 | # If this happens, you must edit the keymap file, and either correct the host 42 | # key name or comment out that line. 43 | # 44 | 45 | BX_KEY_0 '0' SDLK_0 46 | BX_KEY_0+BX_KEY_SHIFT_L ')' SDLK_RIGHTPAREN 47 | BX_KEY_1 '1' SDLK_1 48 | BX_KEY_1+BX_KEY_SHIFT_L '!' SDLK_EXCLAIM 49 | BX_KEY_2 '2' SDLK_2 50 | BX_KEY_2+BX_KEY_SHIFT_L '@' SDLK_AT 51 | BX_KEY_3 '3' SDLK_3 52 | BX_KEY_3+BX_KEY_SHIFT_L '#' SDLK_HASH 53 | BX_KEY_4 '4' SDLK_4 54 | BX_KEY_4+BX_KEY_SHIFT_L '$' SDLK_DOLLAR 55 | BX_KEY_5 '5' SDLK_5 56 | BX_KEY_6 '6' SDLK_6 57 | BX_KEY_6+BX_KEY_SHIFT_L '^' SDLK_CARET 58 | BX_KEY_7 '7' SDLK_7 59 | BX_KEY_7+BX_KEY_SHIFT_L '&' SDLK_AMPERSAND 60 | BX_KEY_8 '8' SDLK_8 61 | BX_KEY_8+BX_KEY_SHIFT_L '*' SDLK_ASTERISK 62 | BX_KEY_9 '9' SDLK_9 63 | BX_KEY_9+BX_KEY_SHIFT_L '(' SDLK_LEFTPAREN 64 | BX_KEY_A+BX_KEY_SHIFT_L 'A' SDLK_a 65 | BX_KEY_A 'a' SDLK_a 66 | BX_KEY_B+BX_KEY_SHIFT_L 'B' SDLK_b 67 | BX_KEY_B 'b' SDLK_b 68 | BX_KEY_C+BX_KEY_SHIFT_L 'C' SDLK_c 69 | BX_KEY_C 'c' SDLK_c 70 | BX_KEY_D+BX_KEY_SHIFT_L 'D' SDLK_d 71 | BX_KEY_D 'd' SDLK_d 72 | BX_KEY_E+BX_KEY_SHIFT_L 'E' SDLK_e 73 | BX_KEY_E 'e' SDLK_e 74 | BX_KEY_F+BX_KEY_SHIFT_L 'F' SDLK_f 75 | BX_KEY_F 'f' SDLK_f 76 | BX_KEY_G+BX_KEY_SHIFT_L 'G' SDLK_g 77 | BX_KEY_G 'g' SDLK_g 78 | BX_KEY_H+BX_KEY_SHIFT_L 'H' SDLK_h 79 | BX_KEY_H 'h' SDLK_h 80 | BX_KEY_I+BX_KEY_SHIFT_L 'I' SDLK_i 81 | BX_KEY_I 'i' SDLK_i 82 | BX_KEY_J+BX_KEY_SHIFT_L 'J' SDLK_j 83 | BX_KEY_J 'j' SDLK_j 84 | BX_KEY_K+BX_KEY_SHIFT_L 'K' SDLK_k 85 | BX_KEY_K 'k' SDLK_k 86 | BX_KEY_L+BX_KEY_SHIFT_L 'L' SDLK_l 87 | BX_KEY_L 'l' SDLK_l 88 | BX_KEY_M+BX_KEY_SHIFT_L 'M' SDLK_m 89 | BX_KEY_M 'm' SDLK_m 90 | BX_KEY_N+BX_KEY_SHIFT_L 'N' SDLK_n 91 | BX_KEY_N 'n' SDLK_n 92 | BX_KEY_O+BX_KEY_SHIFT_L 'O' SDLK_o 93 | BX_KEY_O 'o' SDLK_o 94 | BX_KEY_P+BX_KEY_SHIFT_L 'P' SDLK_p 95 | BX_KEY_P 'p' SDLK_p 96 | BX_KEY_Q+BX_KEY_SHIFT_L 'Q' SDLK_q 97 | BX_KEY_Q 'q' SDLK_q 98 | BX_KEY_R+BX_KEY_SHIFT_L 'R' SDLK_r 99 | BX_KEY_R 'r' SDLK_r 100 | BX_KEY_S+BX_KEY_SHIFT_L 'S' SDLK_s 101 | BX_KEY_S 's' SDLK_s 102 | BX_KEY_T+BX_KEY_SHIFT_L 'T' SDLK_t 103 | BX_KEY_T 't' SDLK_t 104 | BX_KEY_U+BX_KEY_SHIFT_L 'U' SDLK_u 105 | BX_KEY_U 'u' SDLK_u 106 | BX_KEY_V+BX_KEY_SHIFT_L 'V' SDLK_v 107 | BX_KEY_V 'v' SDLK_v 108 | BX_KEY_W+BX_KEY_SHIFT_L 'W' SDLK_w 109 | BX_KEY_W 'w' SDLK_w 110 | BX_KEY_X+BX_KEY_SHIFT_L 'X' SDLK_x 111 | BX_KEY_X 'x' SDLK_x 112 | BX_KEY_Y+BX_KEY_SHIFT_L 'Y' SDLK_y 113 | BX_KEY_Y 'y' SDLK_y 114 | BX_KEY_Z+BX_KEY_SHIFT_L 'Z' SDLK_z 115 | BX_KEY_Z 'z' SDLK_z 116 | BX_KEY_F1 none SDLK_F1 117 | BX_KEY_F2 none SDLK_F2 118 | BX_KEY_F3 none SDLK_F3 119 | BX_KEY_F4 none SDLK_F4 120 | BX_KEY_F5 none SDLK_F5 121 | BX_KEY_F6 none SDLK_F6 122 | BX_KEY_F7 none SDLK_F7 123 | BX_KEY_F8 none SDLK_F8 124 | BX_KEY_F9 none SDLK_F9 125 | BX_KEY_F10 none SDLK_F10 126 | BX_KEY_F11 none SDLK_F11 127 | BX_KEY_F12 none SDLK_F12 128 | BX_KEY_ALT_L none SDLK_LALT 129 | BX_KEY_ALT_R none SDLK_MODE 130 | BX_KEY_BACKSLASH backslash SDLK_BACKSLASH 131 | BX_KEY_BACKSPACE none SDLK_BACKSPACE 132 | BX_KEY_CAPS_LOCK none SDLK_CAPSLOCK 133 | BX_KEY_COMMA ',' SDLK_COMMA 134 | BX_KEY_COMMA+BX_KEY_SHIFT_L '<' SDLK_LESS 135 | BX_KEY_CTRL_L none SDLK_LCTRL 136 | BX_KEY_CTRL_R none SDLK_RCTRL 137 | BX_KEY_DELETE none SDLK_DELETE 138 | BX_KEY_DOWN none SDLK_DOWN 139 | BX_KEY_END none SDLK_END 140 | BX_KEY_ENTER return SDLK_RETURN 141 | BX_KEY_EQUALS '=' SDLK_EQUALS 142 | BX_KEY_EQUALS+BX_KEY_SHIFT_L '+' SDLK_PLUS 143 | BX_KEY_ESC none SDLK_ESCAPE 144 | BX_KEY_GRAVE '`' SDLK_BACKQUOTE 145 | BX_KEY_HOME none SDLK_HOME 146 | BX_KEY_INSERT none SDLK_INSERT 147 | BX_KEY_KP_5 none SDLK_KP_5 148 | BX_KEY_KP_ADD none SDLK_KP_PLUS 149 | BX_KEY_KP_DELETE none SDLK_KP_PERIOD 150 | BX_KEY_KP_DIVIDE none SDLK_KP_DIVIDE 151 | BX_KEY_KP_DOWN none SDLK_KP_2 152 | BX_KEY_KP_END none SDLK_KP_1 153 | BX_KEY_KP_ENTER none SDLK_KP_ENTER 154 | BX_KEY_KP_HOME none SDLK_KP_7 155 | BX_KEY_KP_INSERT none SDLK_KP_0 156 | BX_KEY_KP_LEFT none SDLK_KP_4 157 | BX_KEY_KP_MULTIPLY none SDLK_KP_MULTIPLY 158 | BX_KEY_KP_PAGE_DOWN none SDLK_KP_3 159 | BX_KEY_KP_PAGE_UP none SDLK_KP_9 160 | BX_KEY_KP_RIGHT none SDLK_KP_6 161 | BX_KEY_KP_SUBTRACT none SDLK_KP_MINUS 162 | BX_KEY_KP_UP none SDLK_KP_8 163 | BX_KEY_LEFT none SDLK_LEFT 164 | BX_KEY_LEFT_BRACKET '[' SDLK_LEFTBRACKET 165 | BX_KEY_MENU none SDLK_MENU 166 | BX_KEY_MINUS '-' SDLK_MINUS 167 | BX_KEY_MINUS+BX_KEY_SHIFT_L '_' SDLK_UNDERSCORE 168 | BX_KEY_NUM_LOCK none SDLK_NUMLOCKCLEAR 169 | BX_KEY_PAGE_DOWN none SDLK_PAGEDOWN 170 | BX_KEY_PAGE_UP none SDLK_PAGEUP 171 | BX_KEY_PAUSE none SDLK_PAUSE 172 | BX_KEY_PERIOD+BX_KEY_SHIFT_L '>' SDLK_GREATER 173 | BX_KEY_PERIOD '.' SDLK_PERIOD 174 | BX_KEY_PRINT none SDLK_PRINTSCREEN 175 | BX_KEY_PRINT none SDLK_SYSREQ 176 | BX_KEY_RIGHT none SDLK_RIGHT 177 | BX_KEY_RIGHT_BRACKET ']' SDLK_RIGHTBRACKET 178 | BX_KEY_SCRL_LOCK none SDLK_SCROLLLOCK 179 | BX_KEY_SEMICOLON+BX_KEY_SHIFT_L ':' SDLK_COLON 180 | BX_KEY_SEMICOLON ';' SDLK_SEMICOLON 181 | BX_KEY_SHIFT_L none SDLK_LSHIFT 182 | BX_KEY_SHIFT_R none SDLK_RSHIFT 183 | BX_KEY_SINGLE_QUOTE apostrophe SDLK_QUOTE 184 | BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L '"' SDLK_QUOTEDBL 185 | BX_KEY_SLASH+BX_KEY_SHIFT_L '?' SDLK_QUESTION 186 | BX_KEY_SLASH '/' SDLK_SLASH 187 | BX_KEY_SPACE space SDLK_SPACE 188 | BX_KEY_TAB tab SDLK_TAB 189 | BX_KEY_UP none SDLK_UP 190 | BX_KEY_WIN_L none SDLK_LGUI 191 | BX_KEY_WIN_R none SDLK_RGUI 192 | -------------------------------------------------------------------------------- /bochs/share/bochs/keymaps/x11-pc-be.map: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/share/bochs/keymaps/x11-pc-be.map -------------------------------------------------------------------------------- /bochs/share/bochs/keymaps/x11-pc-da.map: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/share/bochs/keymaps/x11-pc-da.map -------------------------------------------------------------------------------- /bochs/share/bochs/keymaps/x11-pc-de.map: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/share/bochs/keymaps/x11-pc-de.map -------------------------------------------------------------------------------- /bochs/share/bochs/keymaps/x11-pc-es.map: -------------------------------------------------------------------------------- 1 | # Bochs Keymap file 2 | # $Id: x11-pc-es.map 12400 2014-07-06 18:29:06Z vruppert $ 3 | # Target: PC(x86) keyboard, ES keymap 4 | # Author: Vicente Hernando Ara 5 | # 6 | # The keymap file describes the layout of a keyboard, and how it translates 7 | # into Bochs key codes. 8 | # 9 | # Format: 10 | # BX_Keysym ASCII_equivalent Xwin_Keysym 11 | # 12 | # Or, for keys that require modifiers: 13 | # BX_Keysym+BX_Modifier ASCII_equivalent Xwin_Keysym 14 | # 15 | # BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in 16 | # gui/keymap.cc. The BX_Modifier is usually a shift key press, but it 17 | # could be any key. Presently a maximum of one modifier is supported, but this 18 | # could be changed in keymap.h (structure def has only one slot for modifier), 19 | # keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1 20 | # modifier). 21 | # 22 | # The ASCII_equivalent must be either apostrophe + one character + apostrophe, 23 | # or one of these keywords: space, return, tab, backslash, apostrophe, none. 24 | # This format is designed to look like a char constant in C, but it's a very 25 | # simple parser. There's no concept of backslash being an escape char. The 26 | # backslash and apostrophe entries are provided for aesthetic purposes only: no 27 | # C++ programmer wants to see '\' or '''. The parser doesn't care, but they are 28 | # ugly. 29 | # 30 | # Xwin_Keysym is the X windows equivalent of the key combination. These 31 | # codes should match whatever you find in /usr/X11R6/include/X11/keysymdef.h. 32 | # If you're running X windows, Bochs will take each of these Xwin_Keysyms, 33 | # pull off the XK_ in front, and use XStringToKeysym() to change them into 34 | # numerical codes. If this lookup fails, you will get a panic and you need 35 | # to edit the keymap file. 36 | # 37 | BX_KEY_0 none XK_0 38 | BX_KEY_0 none XK_equal 39 | BX_KEY_1 none XK_1 40 | BX_KEY_1 none XK_bar 41 | BX_KEY_1 none XK_exclam 42 | BX_KEY_2 none XK_2 43 | BX_KEY_2 none XK_at 44 | BX_KEY_2 none XK_quotedbl 45 | BX_KEY_3 none XK_3 46 | BX_KEY_3 none XK_numbersign 47 | BX_KEY_3 none XK_periodcentered 48 | BX_KEY_4 none XK_4 49 | BX_KEY_4 none XK_dollar 50 | BX_KEY_5 none XK_5 51 | BX_KEY_5 none XK_percent 52 | BX_KEY_6 none XK_6 53 | BX_KEY_6 none XK_ampersand 54 | BX_KEY_7 none XK_7 55 | BX_KEY_7 none XK_slash 56 | BX_KEY_8 none XK_8 57 | BX_KEY_8 none XK_parenleft 58 | BX_KEY_9 none XK_9 59 | BX_KEY_9 none XK_parenright 60 | BX_KEY_A none XK_A 61 | BX_KEY_A none XK_a 62 | BX_KEY_B none XK_B 63 | BX_KEY_B none XK_b 64 | BX_KEY_C none XK_C 65 | BX_KEY_C none XK_c 66 | BX_KEY_D none XK_D 67 | BX_KEY_D none XK_d 68 | BX_KEY_E none XK_E 69 | BX_KEY_E none XK_EuroSign 70 | BX_KEY_E none XK_e 71 | BX_KEY_F none XK_F 72 | BX_KEY_F none XK_f 73 | BX_KEY_G none XK_G 74 | BX_KEY_G none XK_g 75 | BX_KEY_H none XK_H 76 | BX_KEY_H none XK_h 77 | BX_KEY_I none XK_I 78 | BX_KEY_I none XK_i 79 | BX_KEY_J none XK_J 80 | BX_KEY_J none XK_j 81 | BX_KEY_K none XK_K 82 | BX_KEY_K none XK_k 83 | BX_KEY_L none XK_L 84 | BX_KEY_L none XK_l 85 | BX_KEY_M none XK_M 86 | BX_KEY_M none XK_m 87 | BX_KEY_N none XK_N 88 | BX_KEY_N none XK_n 89 | BX_KEY_O none XK_O 90 | BX_KEY_O none XK_o 91 | BX_KEY_P none XK_P 92 | BX_KEY_P none XK_p 93 | BX_KEY_Q none XK_Q 94 | BX_KEY_Q none XK_q 95 | BX_KEY_R none XK_R 96 | BX_KEY_R none XK_r 97 | BX_KEY_S none XK_S 98 | BX_KEY_S none XK_s 99 | BX_KEY_T none XK_T 100 | BX_KEY_T none XK_t 101 | BX_KEY_U none XK_U 102 | BX_KEY_U none XK_u 103 | BX_KEY_V none XK_V 104 | BX_KEY_V none XK_v 105 | BX_KEY_W none XK_W 106 | BX_KEY_W none XK_w 107 | BX_KEY_X none XK_X 108 | BX_KEY_X none XK_x 109 | BX_KEY_Y none XK_Y 110 | BX_KEY_Y none XK_y 111 | BX_KEY_Z none XK_Z 112 | BX_KEY_Z none XK_z 113 | BX_KEY_F1 none XK_F1 114 | BX_KEY_F2 none XK_F2 115 | BX_KEY_F3 none XK_F3 116 | BX_KEY_F4 none XK_F4 117 | BX_KEY_F5 none XK_F5 118 | BX_KEY_F6 none XK_F6 119 | BX_KEY_F7 none XK_F7 120 | BX_KEY_F8 none XK_F8 121 | BX_KEY_F9 none XK_F9 122 | BX_KEY_F10 none XK_F10 123 | BX_KEY_F11 none XK_F11 124 | BX_KEY_F12 none XK_F12 125 | BX_KEY_ALT_L none XK_Alt_L 126 | BX_KEY_ALT_L none XK_Meta_L 127 | BX_KEY_ALT_R none XK_Alt_R 128 | BX_KEY_ALT_R none XK_Mode_switch 129 | BX_KEY_ALT_R none XK_Multi_key 130 | BX_KEY_BACKSLASH none XK_Ccedilla 131 | BX_KEY_BACKSLASH none XK_ccedilla 132 | BX_KEY_BACKSPACE none XK_BackSpace 133 | BX_KEY_CAPS_LOCK none XK_Caps_Lock 134 | BX_KEY_COMMA none XK_comma 135 | BX_KEY_COMMA none XK_semicolon 136 | BX_KEY_CTRL_L none XK_Control_L 137 | BX_KEY_CTRL_R none XK_Control_R 138 | BX_KEY_DELETE none XK_Delete 139 | BX_KEY_DOWN none XK_Down 140 | BX_KEY_END none XK_End 141 | BX_KEY_ENTER none XK_Return 142 | BX_KEY_EQUALS none XK_exclamdown 143 | BX_KEY_EQUALS none XK_questiondown 144 | BX_KEY_ESC none XK_Escape 145 | BX_KEY_GRAVE none XK_asciitilde 146 | BX_KEY_GRAVE none XK_backslash 147 | BX_KEY_GRAVE none XK_grave 148 | BX_KEY_GRAVE none XK_masculine 149 | BX_KEY_GRAVE none XK_ordfeminine 150 | BX_KEY_HOME none XK_Home 151 | BX_KEY_INSERT none XK_Insert 152 | BX_KEY_KP_5 none XK_KP_5 153 | BX_KEY_KP_5 none XK_KP_Begin 154 | BX_KEY_KP_ADD none XK_KP_Add 155 | BX_KEY_KP_DELETE none XK_KP_Decimal 156 | BX_KEY_KP_DELETE none XK_KP_Delete 157 | BX_KEY_KP_DIVIDE none XK_KP_Divide 158 | BX_KEY_KP_DOWN none XK_KP_2 159 | BX_KEY_KP_DOWN none XK_KP_Down 160 | BX_KEY_KP_END none XK_KP_1 161 | BX_KEY_KP_END none XK_KP_End 162 | BX_KEY_KP_ENTER none XK_KP_Enter 163 | BX_KEY_KP_HOME none XK_KP_7 164 | BX_KEY_KP_HOME none XK_KP_Home 165 | BX_KEY_KP_INSERT none XK_KP_0 166 | BX_KEY_KP_INSERT none XK_KP_Insert 167 | BX_KEY_KP_LEFT none XK_KP_4 168 | BX_KEY_KP_LEFT none XK_KP_Left 169 | BX_KEY_KP_MULTIPLY none XK_KP_Multiply 170 | BX_KEY_KP_PAGE_DOWN none XK_KP_3 171 | BX_KEY_KP_PAGE_DOWN none XK_KP_Page_Down 172 | BX_KEY_KP_PAGE_UP none XK_KP_9 173 | BX_KEY_KP_PAGE_UP none XK_KP_Page_Up 174 | BX_KEY_KP_RIGHT none XK_KP_6 175 | BX_KEY_KP_RIGHT none XK_KP_Right 176 | BX_KEY_KP_SUBTRACT none XK_KP_Subtract 177 | BX_KEY_KP_UP none XK_KP_8 178 | BX_KEY_KP_UP none XK_KP_Up 179 | BX_KEY_LEFT none XK_Left 180 | BX_KEY_LEFT_BACKSLASH none XK_greater 181 | BX_KEY_LEFT_BACKSLASH none XK_less 182 | BX_KEY_LEFT_BRACKET none XK_braceleft 183 | BX_KEY_LEFT_BRACKET none XK_bracketleft 184 | BX_KEY_LEFT_BRACKET none XK_dead_circumflex 185 | BX_KEY_LEFT_BRACKET none XK_dead_grave 186 | BX_KEY_MENU none XK_Menu 187 | BX_KEY_MINUS none XK_apostrophe 188 | BX_KEY_MINUS none XK_question 189 | BX_KEY_NUM_LOCK none XK_Num_Lock 190 | BX_KEY_PAGE_DOWN none XK_Page_Down 191 | BX_KEY_PAGE_UP none XK_Page_Up 192 | BX_KEY_PAUSE none XK_Break 193 | BX_KEY_PAUSE none XK_Pause 194 | BX_KEY_PERIOD none XK_colon 195 | BX_KEY_PERIOD none XK_period 196 | BX_KEY_PRINT none XK_Print 197 | BX_KEY_PRINT none XK_Sys_Req 198 | BX_KEY_RIGHT none XK_Right 199 | BX_KEY_RIGHT_BRACKET none XK_asterisk 200 | BX_KEY_RIGHT_BRACKET none XK_braceright 201 | BX_KEY_RIGHT_BRACKET none XK_bracketright 202 | BX_KEY_RIGHT_BRACKET none XK_plus 203 | BX_KEY_SCRL_LOCK none XK_Scroll_Lock 204 | BX_KEY_SEMICOLON none XK_Ntilde 205 | BX_KEY_SEMICOLON none XK_ntilde 206 | BX_KEY_SHIFT_L none XK_Shift_L 207 | BX_KEY_SHIFT_R none XK_Shift_R 208 | BX_KEY_SINGLE_QUOTE none XK_dead_acute 209 | BX_KEY_SINGLE_QUOTE none XK_dead_diaeresis 210 | BX_KEY_SLASH none XK_minus 211 | BX_KEY_SLASH none XK_underscore 212 | BX_KEY_SPACE none XK_space 213 | BX_KEY_TAB none XK_ISO_Left_Tab 214 | BX_KEY_TAB none XK_Tab 215 | BX_KEY_UP none XK_Up 216 | BX_KEY_WIN_L none XK_Super_L 217 | BX_KEY_WIN_R none XK_Super_R 218 | -------------------------------------------------------------------------------- /bochs/share/bochs/keymaps/x11-pc-fr.map: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/share/bochs/keymaps/x11-pc-fr.map -------------------------------------------------------------------------------- /bochs/share/bochs/keymaps/x11-pc-it.map: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/share/bochs/keymaps/x11-pc-it.map -------------------------------------------------------------------------------- /bochs/share/bochs/keymaps/x11-pc-ru.map: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/share/bochs/keymaps/x11-pc-ru.map -------------------------------------------------------------------------------- /bochs/share/bochs/keymaps/x11-pc-se.map: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/share/bochs/keymaps/x11-pc-se.map -------------------------------------------------------------------------------- /bochs/share/bochs/keymaps/x11-pc-si.map: -------------------------------------------------------------------------------- 1 | # Bochs Keymap file 2 | # $Id: x11-pc-si.map 12400 2014-07-06 18:29:06Z vruppert $ 3 | # Target: PC(x86) keyboard, SI keymap 4 | # Author: Mitja Ursic 5 | # 6 | # The keymap file describes the layout of a keyboard, and how it translates 7 | # into Bochs key codes. 8 | # 9 | # Format: 10 | # BX_Keysym ASCII_equivalent Xwin_Keysym 11 | # 12 | # Or, for keys that require modifiers: 13 | # BX_Keysym+BX_Modifier ASCII_equivalent Xwin_Keysym 14 | # 15 | # BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in 16 | # gui/keymap.cc. The BX_Modifier is usually a shift key press, but it 17 | # could be any key. Presently a maximum of one modifier is supported, but this 18 | # could be changed in keymap.h (structure def has only one slot for modifier), 19 | # keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1 20 | # modifier). 21 | # 22 | # The ASCII_equivalent must be either apostrophe + one character + apostrophe, 23 | # or one of these keywords: space, return, tab, backslash, apostrophe, none. 24 | # This format is designed to look like a char constant in C, but it's a very 25 | # simple parser. There's no concept of backslash being an escape char. The 26 | # backslash and apostrophe entries are provided for aesthetic purposes only: no 27 | # C++ programmer wants to see '\' or '''. The parser doesn't care, but they are 28 | # ugly. 29 | # 30 | # Xwin_Keysym is the X windows equivalent of the key combination. These 31 | # codes should match whatever you find in /usr/X11R6/include/X11/keysymdef.h. 32 | # If you're running X windows, Bochs will take each of these Xwin_Keysyms, 33 | # pull off the XK_ in front, and use XStringToKeysym() to change them into 34 | # numerical codes. If this lookup fails, you will get a panic and you need 35 | # to edit the keymap file. 36 | # 37 | 38 | BX_KEY_0 '0' XK_0 39 | BX_KEY_0+BX_KEY_SHIFT_L ')' XK_parenright 40 | BX_KEY_1 '1' XK_1 41 | BX_KEY_1+BX_KEY_SHIFT_L '!' XK_exclam 42 | BX_KEY_2 '2' XK_2 43 | BX_KEY_2+BX_KEY_SHIFT_L '@' XK_at 44 | BX_KEY_3 '3' XK_3 45 | BX_KEY_3+BX_KEY_SHIFT_L '#' XK_numbersign 46 | BX_KEY_4 '4' XK_4 47 | BX_KEY_4+BX_KEY_SHIFT_L '$' XK_dollar 48 | BX_KEY_5 '5' XK_5 49 | BX_KEY_5+BX_KEY_SHIFT_L '%' XK_percent 50 | BX_KEY_6 '6' XK_6 51 | BX_KEY_7+BX_KEY_SHIFT_L '&' XK_ampersand 52 | BX_KEY_7 '7' XK_7 53 | BX_KEY_SLASH none XK_cacute 54 | BX_KEY_8 '8' XK_8 55 | BX_KEY_KP_MULTIPLY '*' XK_asterisk 56 | BX_KEY_9 '9' XK_9 57 | BX_KEY_9+BX_KEY_SHIFT_L '(' XK_parenleft 58 | BX_KEY_A+BX_KEY_SHIFT_L 'a' XK_A 59 | BX_KEY_A 'a' XK_a 60 | BX_KEY_B+BX_KEY_SHIFT_L 'B' XK_B 61 | BX_KEY_B 'b' XK_b 62 | BX_KEY_C+BX_KEY_SHIFT_L 'C' XK_C 63 | BX_KEY_C 'c' XK_c 64 | BX_KEY_D+BX_KEY_SHIFT_L 'D' XK_D 65 | BX_KEY_D 'd' XK_d 66 | BX_KEY_E+BX_KEY_SHIFT_L 'E' XK_E 67 | BX_KEY_E 'e' XK_e 68 | BX_KEY_F+BX_KEY_SHIFT_L 'F' XK_F 69 | BX_KEY_F 'f' XK_f 70 | BX_KEY_G+BX_KEY_SHIFT_L 'G' XK_G 71 | BX_KEY_G 'g' XK_g 72 | BX_KEY_H+BX_KEY_SHIFT_L 'H' XK_H 73 | BX_KEY_H 'h' XK_h 74 | BX_KEY_I+BX_KEY_SHIFT_L 'I' XK_I 75 | BX_KEY_I 'i' XK_i 76 | BX_KEY_J+BX_KEY_SHIFT_L 'J' XK_J 77 | BX_KEY_J 'j' XK_j 78 | BX_KEY_K+BX_KEY_SHIFT_L 'K' XK_K 79 | BX_KEY_K 'k' XK_k 80 | BX_KEY_L+BX_KEY_SHIFT_L 'L' XK_L 81 | BX_KEY_L 'l' XK_l 82 | BX_KEY_M+BX_KEY_SHIFT_L 'M' XK_M 83 | BX_KEY_M 'm' XK_m 84 | BX_KEY_N+BX_KEY_SHIFT_L 'N' XK_N 85 | BX_KEY_N 'n' XK_n 86 | BX_KEY_O+BX_KEY_SHIFT_L 'O' XK_O 87 | BX_KEY_O 'o' XK_o 88 | BX_KEY_P+BX_KEY_SHIFT_L 'P' XK_P 89 | BX_KEY_P 'p' XK_p 90 | BX_KEY_Q+BX_KEY_SHIFT_L 'Q' XK_Q 91 | BX_KEY_Q 'q' XK_q 92 | BX_KEY_R+BX_KEY_SHIFT_L 'R' XK_R 93 | BX_KEY_R 'r' XK_r 94 | BX_KEY_S+BX_KEY_SHIFT_L 'S' XK_S 95 | BX_KEY_S 's' XK_s 96 | BX_KEY_T+BX_KEY_SHIFT_L 'T' XK_T 97 | BX_KEY_T 't' XK_t 98 | BX_KEY_U+BX_KEY_SHIFT_L 'U' XK_U 99 | BX_KEY_U 'u' XK_u 100 | BX_KEY_V+BX_KEY_SHIFT_L 'V' XK_V 101 | BX_KEY_V 'v' XK_v 102 | BX_KEY_W+BX_KEY_SHIFT_L 'W' XK_W 103 | BX_KEY_W 'w' XK_w 104 | BX_KEY_X+BX_KEY_SHIFT_L 'X' XK_X 105 | BX_KEY_X 'x' XK_x 106 | BX_KEY_Y+BX_KEY_SHIFT_L 'Y' XK_Y 107 | BX_KEY_Y 'y' XK_y 108 | BX_KEY_Z+BX_KEY_SHIFT_L 'Z' XK_Z 109 | BX_KEY_Z 'z' XK_z 110 | BX_KEY_F1 none XK_F1 111 | BX_KEY_F2 none XK_F2 112 | BX_KEY_F3 none XK_F3 113 | BX_KEY_F4 none XK_F4 114 | BX_KEY_F5 none XK_F5 115 | BX_KEY_F6 none XK_F6 116 | BX_KEY_F7 none XK_F7 117 | BX_KEY_F8 none XK_F8 118 | BX_KEY_F9 none XK_F9 119 | BX_KEY_F10 none XK_F10 120 | BX_KEY_F11 none XK_F11 121 | BX_KEY_F12 none XK_F12 122 | BX_KEY_ALT_L none XK_Alt_L 123 | BX_KEY_ALT_L none XK_Meta_L 124 | BX_KEY_ALT_R none XK_Alt_R 125 | BX_KEY_ALT_R none XK_Mode_switch 126 | BX_KEY_ALT_R none XK_Multi_key 127 | BX_KEY_BACKSLASH backslash XK_backslash 128 | BX_KEY_BACKSLASH+BX_KEY_SHIFT_L '|' XK_bar 129 | BX_KEY_BACKSPACE none XK_BackSpace 130 | BX_KEY_CAPS_LOCK none XK_Caps_Lock 131 | BX_KEY_COMMA ',' XK_comma 132 | BX_KEY_COMMA+BX_KEY_SHIFT_L ';' XK_semicolon 133 | BX_KEY_CTRL_L none XK_Control_L 134 | BX_KEY_CTRL_R none XK_Control_R 135 | BX_KEY_DELETE none XK_Delete 136 | BX_KEY_DOWN none XK_Down 137 | BX_KEY_END none XK_End 138 | BX_KEY_ENTER return XK_Return 139 | BX_KEY_EQUALS '=' XK_zcaron 140 | BX_KEY_KP_ADD '+' XK_plus 141 | BX_KEY_ESC none XK_Escape 142 | BX_KEY_GRAVE+BX_KEY_SHIFT_L '~' XK_asciitilde 143 | BX_KEY_GRAVE '`' XK_grave 144 | BX_KEY_HOME none XK_Home 145 | BX_KEY_INSERT none XK_Insert 146 | BX_KEY_KP_5 none XK_KP_5 147 | BX_KEY_KP_5 none XK_KP_Begin 148 | BX_KEY_KP_ADD none XK_KP_Add 149 | BX_KEY_KP_DELETE none XK_KP_Decimal 150 | BX_KEY_KP_DELETE none XK_KP_Delete 151 | BX_KEY_KP_DIVIDE none XK_KP_Divide 152 | BX_KEY_KP_DOWN none XK_KP_2 153 | BX_KEY_KP_DOWN none XK_KP_Down 154 | BX_KEY_KP_END none XK_KP_1 155 | BX_KEY_KP_END none XK_KP_End 156 | BX_KEY_KP_ENTER none XK_KP_Enter 157 | BX_KEY_KP_HOME none XK_KP_7 158 | BX_KEY_KP_HOME none XK_KP_Home 159 | BX_KEY_KP_INSERT none XK_KP_0 160 | BX_KEY_KP_INSERT none XK_KP_Insert 161 | BX_KEY_KP_LEFT none XK_KP_4 162 | BX_KEY_KP_LEFT none XK_KP_Left 163 | BX_KEY_KP_MULTIPLY none XK_KP_Multiply 164 | BX_KEY_KP_PAGE_DOWN none XK_KP_3 165 | BX_KEY_KP_PAGE_DOWN none XK_KP_Page_Down 166 | BX_KEY_KP_PAGE_UP none XK_KP_9 167 | BX_KEY_KP_PAGE_UP none XK_KP_Page_Up 168 | BX_KEY_KP_RIGHT none XK_KP_6 169 | BX_KEY_KP_RIGHT none XK_KP_Right 170 | BX_KEY_KP_SUBTRACT none XK_KP_Subtract 171 | BX_KEY_KP_UP none XK_KP_8 172 | BX_KEY_KP_UP none XK_KP_Up 173 | BX_KEY_LEFT none XK_Left 174 | BX_KEY_LEFT_BRACKET+BX_KEY_SHIFT_L '{' XK_Scaron 175 | BX_KEY_LEFT_BRACKET '[' XK_bracketleft 176 | BX_KEY_MENU none XK_Menu 177 | BX_KEY_MINUS '-' XK_minus 178 | BX_KEY_MINUS+BX_KEY_SHIFT_L '_' XK_underscore 179 | BX_KEY_NUM_LOCK none XK_Num_Lock 180 | BX_KEY_PAGE_DOWN none XK_Page_Down 181 | BX_KEY_PAGE_UP none XK_Page_Up 182 | BX_KEY_PAUSE none XK_Break 183 | BX_KEY_PAUSE none XK_Pause 184 | BX_KEY_COMMA ',' XK_comma 185 | BX_KEY_PERIOD '.' XK_period 186 | BX_KEY_PERIOD+BX_KEY_SHIFT_L ':' XK_colon #more > 187 | BX_KEY_PRINT none XK_Print 188 | BX_KEY_PRINT none XK_Sys_Req 189 | BX_KEY_RIGHT none XK_Right 190 | BX_KEY_RIGHT_BRACKET+BX_KEY_SHIFT_L '}' XK_Dstroke 191 | BX_KEY_RIGHT_BRACKET ']' XK_bracketright 192 | BX_KEY_SCRL_LOCK none XK_Scroll_Lock 193 | BX_KEY_COMMA+BX_KEY_SHIFT_L ';' XK_semicolon #less < 194 | BX_KEY_SEMICOLON ';' XK_ccaron 195 | BX_KEY_SEMICOLON+BX_KEY_SHIFT_L ':' XK_Ccaron 196 | BX_KEY_SHIFT_L none XK_Shift_L 197 | BX_KEY_SHIFT_R none XK_Shift_R 198 | BX_KEY_SINGLE_QUOTE apostrophe XK_apostrophe 199 | BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L '"' XK_quotedbl 200 | BX_KEY_SLASH+BX_KEY_SHIFT_L '?' XK_question 201 | BX_KEY_SPACE space XK_space 202 | BX_KEY_TAB none XK_ISO_Left_Tab 203 | BX_KEY_TAB tab XK_Tab 204 | BX_KEY_UP none XK_Up 205 | BX_KEY_WIN_L none XK_Super_L 206 | BX_KEY_WIN_R none XK_Super_R 207 | -------------------------------------------------------------------------------- /bochs/share/bochs/keymaps/x11-pc-uk.map: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/share/bochs/keymaps/x11-pc-uk.map -------------------------------------------------------------------------------- /bochs/share/bochs/keymaps/x11-pc-us.map: -------------------------------------------------------------------------------- 1 | # Bochs Keymap file 2 | # $Id: x11-pc-us.map 12400 2014-07-06 18:29:06Z vruppert $ 3 | # Target: PC(x86) keyboard, US keymap 4 | # Author: Christophe Bothamy, Bryce Denney 5 | # 6 | # The keymap file describes the layout of a keyboard, and how it translates 7 | # into Bochs key codes. 8 | # 9 | # Format: 10 | # BX_Keysym ASCII_equivalent Xwin_Keysym 11 | # 12 | # Or, for keys that require modifiers: 13 | # BX_Keysym+BX_Modifier ASCII_equivalent Xwin_Keysym 14 | # 15 | # BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in 16 | # gui/keymap.cc. The BX_Modifier is usually a shift key press, but it 17 | # could be any key. Presently a maximum of one modifier is supported, but this 18 | # could be changed in keymap.h (structure def has only one slot for modifier), 19 | # keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1 20 | # modifier). 21 | # 22 | # The ASCII_equivalent must be either apostrophe + one character + apostrophe, 23 | # or one of these keywords: space, return, tab, backslash, apostrophe, none. 24 | # This format is designed to look like a char constant in C, but it's a very 25 | # simple parser. There's no concept of backslash being an escape char. The 26 | # backslash and apostrophe entries are provided for aesthetic purposes only: no 27 | # C++ programmer wants to see '\' or '''. The parser doesn't care, but they are 28 | # ugly. 29 | # 30 | # Xwin_Keysym is the X windows equivalent of the key combination. These 31 | # codes should match whatever you find in /usr/X11R6/include/X11/keysymdef.h. 32 | # If you're running X windows, Bochs will take each of these Xwin_Keysyms, 33 | # pull off the XK_ in front, and use XStringToKeysym() to change them into 34 | # numerical codes. If this lookup fails, you will get a panic and you need 35 | # to edit the keymap file. 36 | # 37 | 38 | BX_KEY_0 '0' XK_0 39 | BX_KEY_0+BX_KEY_SHIFT_L ')' XK_parenright 40 | BX_KEY_1 '1' XK_1 41 | BX_KEY_1+BX_KEY_SHIFT_L '!' XK_exclam 42 | BX_KEY_2 '2' XK_2 43 | BX_KEY_2+BX_KEY_SHIFT_L '@' XK_at 44 | BX_KEY_3 '3' XK_3 45 | BX_KEY_3+BX_KEY_SHIFT_L '#' XK_numbersign 46 | BX_KEY_4 '4' XK_4 47 | BX_KEY_4+BX_KEY_SHIFT_L '$' XK_dollar 48 | BX_KEY_5 '5' XK_5 49 | BX_KEY_5+BX_KEY_SHIFT_L '%' XK_percent 50 | BX_KEY_6 '6' XK_6 51 | BX_KEY_6+BX_KEY_SHIFT_L '^' XK_asciicircum 52 | BX_KEY_7 '7' XK_7 53 | BX_KEY_7+BX_KEY_SHIFT_L '&' XK_ampersand 54 | BX_KEY_8 '8' XK_8 55 | BX_KEY_8+BX_KEY_SHIFT_L '*' XK_asterisk 56 | BX_KEY_9 '9' XK_9 57 | BX_KEY_9+BX_KEY_SHIFT_L '(' XK_parenleft 58 | BX_KEY_A+BX_KEY_SHIFT_L 'A' XK_A 59 | BX_KEY_A 'a' XK_a 60 | BX_KEY_B+BX_KEY_SHIFT_L 'B' XK_B 61 | BX_KEY_B 'b' XK_b 62 | BX_KEY_C+BX_KEY_SHIFT_L 'C' XK_C 63 | BX_KEY_C 'c' XK_c 64 | BX_KEY_D+BX_KEY_SHIFT_L 'D' XK_D 65 | BX_KEY_D 'd' XK_d 66 | BX_KEY_E+BX_KEY_SHIFT_L 'E' XK_E 67 | BX_KEY_E 'e' XK_e 68 | BX_KEY_F+BX_KEY_SHIFT_L 'F' XK_F 69 | BX_KEY_F 'f' XK_f 70 | BX_KEY_G+BX_KEY_SHIFT_L 'G' XK_G 71 | BX_KEY_G 'g' XK_g 72 | BX_KEY_H+BX_KEY_SHIFT_L 'H' XK_H 73 | BX_KEY_H 'h' XK_h 74 | BX_KEY_I+BX_KEY_SHIFT_L 'I' XK_I 75 | BX_KEY_I 'i' XK_i 76 | BX_KEY_J+BX_KEY_SHIFT_L 'J' XK_J 77 | BX_KEY_J 'j' XK_j 78 | BX_KEY_K+BX_KEY_SHIFT_L 'K' XK_K 79 | BX_KEY_K 'k' XK_k 80 | BX_KEY_L+BX_KEY_SHIFT_L 'L' XK_L 81 | BX_KEY_L 'l' XK_l 82 | BX_KEY_M+BX_KEY_SHIFT_L 'M' XK_M 83 | BX_KEY_M 'm' XK_m 84 | BX_KEY_N+BX_KEY_SHIFT_L 'N' XK_N 85 | BX_KEY_N 'n' XK_n 86 | BX_KEY_O+BX_KEY_SHIFT_L 'O' XK_O 87 | BX_KEY_O 'o' XK_o 88 | BX_KEY_P+BX_KEY_SHIFT_L 'P' XK_P 89 | BX_KEY_P 'p' XK_p 90 | BX_KEY_Q+BX_KEY_SHIFT_L 'Q' XK_Q 91 | BX_KEY_Q 'q' XK_q 92 | BX_KEY_R+BX_KEY_SHIFT_L 'R' XK_R 93 | BX_KEY_R 'r' XK_r 94 | BX_KEY_S+BX_KEY_SHIFT_L 'S' XK_S 95 | BX_KEY_S 's' XK_s 96 | BX_KEY_T+BX_KEY_SHIFT_L 'T' XK_T 97 | BX_KEY_T 't' XK_t 98 | BX_KEY_U+BX_KEY_SHIFT_L 'U' XK_U 99 | BX_KEY_U 'u' XK_u 100 | BX_KEY_V+BX_KEY_SHIFT_L 'V' XK_V 101 | BX_KEY_V 'v' XK_v 102 | BX_KEY_W+BX_KEY_SHIFT_L 'W' XK_W 103 | BX_KEY_W 'w' XK_w 104 | BX_KEY_X+BX_KEY_SHIFT_L 'X' XK_X 105 | BX_KEY_X 'x' XK_x 106 | BX_KEY_Y+BX_KEY_SHIFT_L 'Y' XK_Y 107 | BX_KEY_Y 'y' XK_y 108 | BX_KEY_Z+BX_KEY_SHIFT_L 'Z' XK_Z 109 | BX_KEY_Z 'z' XK_z 110 | BX_KEY_F1 none XK_F1 111 | BX_KEY_F2 none XK_F2 112 | BX_KEY_F3 none XK_F3 113 | BX_KEY_F4 none XK_F4 114 | BX_KEY_F5 none XK_F5 115 | BX_KEY_F6 none XK_F6 116 | BX_KEY_F7 none XK_F7 117 | BX_KEY_F8 none XK_F8 118 | BX_KEY_F9 none XK_F9 119 | BX_KEY_F10 none XK_F10 120 | BX_KEY_F11 none XK_F11 121 | BX_KEY_F12 none XK_F12 122 | BX_KEY_ALT_L none XK_Alt_L 123 | BX_KEY_ALT_L none XK_Meta_L 124 | BX_KEY_ALT_R none XK_Alt_R 125 | BX_KEY_ALT_R none XK_Mode_switch 126 | BX_KEY_ALT_R none XK_Multi_key 127 | BX_KEY_BACKSLASH backslash XK_backslash 128 | BX_KEY_BACKSLASH+BX_KEY_SHIFT_L '|' XK_bar 129 | BX_KEY_BACKSPACE none XK_BackSpace 130 | BX_KEY_CAPS_LOCK none XK_Caps_Lock 131 | BX_KEY_COMMA ',' XK_comma 132 | BX_KEY_COMMA+BX_KEY_SHIFT_L '<' XK_less 133 | BX_KEY_CTRL_L none XK_Control_L 134 | BX_KEY_CTRL_R none XK_Control_R 135 | BX_KEY_DELETE none XK_Delete 136 | BX_KEY_DOWN none XK_Down 137 | BX_KEY_END none XK_End 138 | BX_KEY_ENTER return XK_Return 139 | BX_KEY_EQUALS '=' XK_equal 140 | BX_KEY_EQUALS+BX_KEY_SHIFT_L '+' XK_plus 141 | BX_KEY_ESC none XK_Escape 142 | BX_KEY_GRAVE+BX_KEY_SHIFT_L '~' XK_asciitilde 143 | BX_KEY_GRAVE '`' XK_grave 144 | BX_KEY_HOME none XK_Home 145 | BX_KEY_INSERT none XK_Insert 146 | BX_KEY_KP_5 none XK_KP_5 147 | BX_KEY_KP_5 none XK_KP_Begin 148 | BX_KEY_KP_ADD none XK_KP_Add 149 | BX_KEY_KP_DELETE none XK_KP_Decimal 150 | BX_KEY_KP_DELETE none XK_KP_Delete 151 | BX_KEY_KP_DIVIDE none XK_KP_Divide 152 | BX_KEY_KP_DOWN none XK_KP_2 153 | BX_KEY_KP_DOWN none XK_KP_Down 154 | BX_KEY_KP_END none XK_KP_1 155 | BX_KEY_KP_END none XK_KP_End 156 | BX_KEY_KP_ENTER none XK_KP_Enter 157 | BX_KEY_KP_HOME none XK_KP_7 158 | BX_KEY_KP_HOME none XK_KP_Home 159 | BX_KEY_KP_INSERT none XK_KP_0 160 | BX_KEY_KP_INSERT none XK_KP_Insert 161 | BX_KEY_KP_LEFT none XK_KP_4 162 | BX_KEY_KP_LEFT none XK_KP_Left 163 | BX_KEY_KP_MULTIPLY none XK_KP_Multiply 164 | BX_KEY_KP_PAGE_DOWN none XK_KP_3 165 | BX_KEY_KP_PAGE_DOWN none XK_KP_Page_Down 166 | BX_KEY_KP_PAGE_UP none XK_KP_9 167 | BX_KEY_KP_PAGE_UP none XK_KP_Page_Up 168 | BX_KEY_KP_RIGHT none XK_KP_6 169 | BX_KEY_KP_RIGHT none XK_KP_Right 170 | BX_KEY_KP_SUBTRACT none XK_KP_Subtract 171 | BX_KEY_KP_UP none XK_KP_8 172 | BX_KEY_KP_UP none XK_KP_Up 173 | BX_KEY_LEFT none XK_Left 174 | BX_KEY_LEFT_BRACKET+BX_KEY_SHIFT_L '{' XK_braceleft 175 | BX_KEY_LEFT_BRACKET '[' XK_bracketleft 176 | BX_KEY_MENU none XK_Menu 177 | BX_KEY_MINUS '-' XK_minus 178 | BX_KEY_MINUS+BX_KEY_SHIFT_L '_' XK_underscore 179 | BX_KEY_NUM_LOCK none XK_Num_Lock 180 | BX_KEY_PAGE_DOWN none XK_Page_Down 181 | BX_KEY_PAGE_UP none XK_Page_Up 182 | BX_KEY_PAUSE none XK_Break 183 | BX_KEY_PAUSE none XK_Pause 184 | BX_KEY_PERIOD+BX_KEY_SHIFT_L '>' XK_greater 185 | BX_KEY_PERIOD '.' XK_period 186 | BX_KEY_PRINT none XK_Print 187 | BX_KEY_PRINT none XK_Sys_Req 188 | BX_KEY_RIGHT none XK_Right 189 | BX_KEY_RIGHT_BRACKET+BX_KEY_SHIFT_L '}' XK_braceright 190 | BX_KEY_RIGHT_BRACKET ']' XK_bracketright 191 | BX_KEY_SCRL_LOCK none XK_Scroll_Lock 192 | BX_KEY_SEMICOLON+BX_KEY_SHIFT_L ':' XK_colon 193 | BX_KEY_SEMICOLON ';' XK_semicolon 194 | BX_KEY_SHIFT_L none XK_Shift_L 195 | BX_KEY_SHIFT_R none XK_Shift_R 196 | BX_KEY_SINGLE_QUOTE apostrophe XK_apostrophe 197 | BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L '"' XK_quotedbl 198 | BX_KEY_SLASH+BX_KEY_SHIFT_L '?' XK_question 199 | BX_KEY_SLASH '/' XK_slash 200 | BX_KEY_SPACE space XK_space 201 | BX_KEY_TAB none XK_ISO_Left_Tab 202 | BX_KEY_TAB tab XK_Tab 203 | BX_KEY_UP none XK_Up 204 | BX_KEY_WIN_L none XK_Super_L 205 | BX_KEY_WIN_R none XK_Super_R 206 | -------------------------------------------------------------------------------- /bochs/share/bochs/vgabios-cirrus.bin-1.13.0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/share/bochs/vgabios-cirrus.bin-1.13.0 -------------------------------------------------------------------------------- /bochs/share/doc/bochs/CHANGES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/share/doc/bochs/CHANGES -------------------------------------------------------------------------------- /bochs/share/doc/bochs/LICENSE: -------------------------------------------------------------------------------- 1 | The following points clarify the Bochs license: 2 | 3 | 1) Bochs as a whole is released under the GNU Lesser General Public License 4 | 5 | 2) Parts of Bochs have specific licenses which are compatible with the 6 | GNU Lesser General Public License. Hence each source file contains its 7 | own licensing information. 8 | -------------------------------------------------------------------------------- /bochs/share/doc/bochs/README: -------------------------------------------------------------------------------- 1 | Bochs - The cross platform IA-32 (x86) emulator 2 | Updated: Sun Jan 5 08:36:00 CET 2020 3 | Version: 2.6.11 4 | 5 | WHAT IS BOCHS? 6 | 7 | Bochs is a highly portable open source IA-32 (x86) PC emulator 8 | written in C++, that runs on most popular platforms. It includes 9 | emulation of the Intel x86 CPU, common I/O devices, and a custom 10 | BIOS. Bochs can be compiled to emulate many different x86 CPUs, 11 | from early 386 to the most recent x86-64 Intel and AMD processors 12 | which may even not reached the market yet. Bochs is capable of running 13 | most Operating Systems inside the emulation, for example DOS, 14 | Linux or Windows. Bochs was written by Kevin Lawton and is currently 15 | maintained by the Bochs project at "http://bochs.sourceforge.net". 16 | 17 | Bochs can be compiled and used in a variety of modes, some which are 18 | still in development. The 'typical' use of bochs is to provide 19 | complete x86 PC emulation, including the x86 processor, hardware 20 | devices, and memory. This allows you to run OS's and software within 21 | the emulator on your workstation, much like you have a machine 22 | inside of a machine. Bochs will allow you to run Windows 23 | applications on a Solaris machine with X11, for example. 24 | 25 | Bochs is distributed under the GNU LGPL. See LICENSE and COPYING for details. 26 | 27 | GETTING CURRENT SOURCE CODE 28 | 29 | Source code for Bochs is available from the Bochs home page at 30 | http://bochs.sourceforge.net. You can download the most recent 31 | release, use SVN to get the latest sources, or grab a SVN 32 | snapshot which is updated frequently. The releases contain the most 33 | stable code, but if you want the very newest features try the 34 | SVN version instead. 35 | 36 | WHERE ARE THE DOCS? 37 | 38 | The Bochs documentation is written in Docbook. Docbook is a text 39 | format that can be rendered to many popular browser formats such 40 | as HTML, PDF, and Postscript. Each binary release contains the 41 | HTML rendering of the documentation. Also, you can view the 42 | latest documentation on the web at 43 | http://bochs.sf.net/doc/docbook/index.html 44 | 45 | WHERE CAN I GET MORE INFORMATION? HOW DO I REPORT PROBLEMS? 46 | 47 | Both the documentation and the Bochs website have instructions on how 48 | to join the bochs-developers mailing list, which is the primary 49 | forum for discussion of Bochs. The main page of the website also 50 | has links to bug reports and feature requests. You can browse and 51 | add to the content in these areas even if you do not have a (free) 52 | SourceForge account. We need your feedback so that we know what 53 | parts of Bochs to improve. 54 | 55 | There is a patches section on the web site too, if you have made 56 | some changes to Bochs that you want to share. 57 | 58 | HOW CAN I HELP? 59 | 60 | If you would like contribute to the Bochs project, a good first step 61 | is to join the bochs-developers mailing list, and read the archive 62 | of recent messages to see what's going on. 63 | 64 | If you are a technical person (can follow hardware specs, can write 65 | C/C++) take a look at the list of open bug reports and feature 66 | requests to see if you are interested in working on any of the 67 | problems that are mentioned in them. If you check out the SVN 68 | sources, make some changes, and create a patch, one of the 69 | developers will be very happy to apply it for you. Developers who 70 | frequently submit patches, or who embark on major changes in the 71 | source can get write access to SVN. Be sure to communicate with the 72 | bochs-developers list to avoid several people working on the same 73 | thing without realizing it. 74 | 75 | If you are a Bochs user, not a hardware/C++ guru, there are still 76 | many ways you could help out. For example: 77 | - write instructions on how to install a particular operating system 78 | - writing/cleaning up documentation 79 | - testing out Bochs on every imaginable operating system and 80 | reporting how it goes. 81 | 82 | CHANGES 83 | 84 | Summary of changes in 2.6.11: 85 | - General 86 | - Added 64-bit support to the NSIS installer script 87 | - Several fixes in the build system based on Debian patches 88 | - CPU / CPUDB 89 | - Bugfixes for CPU emulation correctness 90 | - Many critical bugfixes for Protection Keys, AVX512*, VMX/SVM, SHA, GFNI emulation 91 | ! Implemented CET (Control Flow Enforcement Technology) emulation according to Intel SDM rev071 92 | - I/O Devices 93 | - Added missing Cirrus SVGA bitblt feature "transparent color compare" 94 | - Some fixes in HPET emulation (patch by Oleg) 95 | - Fixed disk image lock mechanism in the USB MSD case 96 | - BIOS / VGABIOS 97 | - LGPL'd VGABIOS updated to version 0.7b (Fixed VESA extension 'read EDID' 98 | for Bochs VBE and Cirrus) 99 | - Updated SeaBIOS ROM image to current version 1.13.0 100 | - Added SeaVGABIOS ROM image for the Cirrus adapter 101 | - Bochs BIOS built to work with CPU level 5 again 102 | 103 | See CHANGES file for more information! 104 | -------------------------------------------------------------------------------- /bochs/share/doc/bochs/TODO: -------------------------------------------------------------------------------- 1 | This is the "roadmap" posted in the mailing list, augmented by 2 | comments from the mailing list and the irc chat. 3 | Anybody is welcome to work on any of these issues. Some of 4 | these items are rather simple and can be implemented by single 5 | individuals. Other items are quite complex and development needs 6 | to be coordinated. So, if you want to contribute, please drop 7 | us a note in the mailing list, so you can get help or exchange 8 | ideas. 9 | Christophe Bothamy. 10 | 11 | 0. Donations 12 | Source Forge recently set up a donation system for hosted projects. 13 | Should we accept donations ? What could we do with the money ? 14 | - give to EFF, FSF or other 15 | - fund Kevin to continue the work on plex86 so we can use it 16 | - bounties for somebody write optimized win9x/NT/XFree/linux/*BSD 17 | drivers for our vga/net/ide cards 18 | - other ? 19 | Status in Bochs 2.6.5: 20 | No decisions about this yet. 21 | 22 | 1. Speed 23 | Speed (well lack of) is one of the biggest criticism made by users 24 | who'd like to see Bochs run as fast as Virtual PC. 25 | Paths we can explore to get more speed : 26 | 1.1 virtualization : plex86 27 | 1.2 dynamic translation : qemu 28 | Status: 29 | Some work has been done for Bochs 2.5 and 2.6 but still long way is ahead. 30 | 31 | 2 multithreading. Conn Clark wrote : 32 | Threading might be nice too, for those of us who have SMP/SMT machines. 33 | I have a patch from Mathis (who hangs out on the IRC channel all the 34 | time) that puts the video card interface in its own thread. It has 35 | troubles though that I have not resolved. It may also be easier to debug 36 | a threaded peripheral. 37 | I also think that it might be possible to thread a chunk of the CPU 38 | emulation to improve performance on a SMP/SMT machine. Specifically 39 | write_virtual_dword, write_virtual_word, write_virtual_byte, etc... 40 | might just be able to be threaded. I think the threading overhead might 41 | be less than the protection and address translation code. We would have 42 | to try it to find out. I'm also sure there can be some nasty hurdles to 43 | overcome. 44 | Status: 45 | Third party group started a para-Bochs project exactly to reach above goals, 46 | some beta version is already released. 47 | The home page of the project: http://grid.hust.edu.cn/cluster/VirtualMachine/main.html 48 | 49 | 3. Plugin architecture 50 | 3.1 The plugin architecture can be reworked if we want to support 51 | multiple similar devices like serial, net or vga cards. 52 | We currently have two "types" of plugins: "core" and "optional". 53 | Maybe we could add "classes" of plugins. The current version of 54 | Bochs supports the classes "display_library" and "io_device". 55 | New classes can be "config_interface", "net_lowlevel" and 56 | "sound_lowlevel" 57 | 3.2 Stanislav wrote : 58 | Plugin architecture should be rewritten like real plugin architecture s.t. 59 | Bochs VGA plugin for example will be real plugin. I mean that replacement 60 | of plugin dll in already compiled Bochs will replace Bochs VGA card and 61 | the new card will be detected automatically. 62 | This will allow for example developing of plugins separately from Bochs. 63 | 3.3 Michael Brown wrote : 64 | If the configuration interface is to be reworked, could we also make it so 65 | that plugins are self-contained, rather than needing to pollute config.cc 66 | with code for defining and parsing plugin-specific options 67 | Status: 68 | Some of the basic work is done now: The config parameter handling has 69 | been rewritten to a parameter tree and user-defined bochsrc options are now 70 | supported. For most of the optional plugins the config parameter creation and 71 | bochsrc parsing has been moved to the plugin code. Unknown bochsrc options are 72 | now treated as plugin names and Bochs tries to load them. The network and 73 | sound modules are now separate plugins. 74 | 75 | 4. PCI host<->guest proxy 76 | Being able to use a real pci device from inside Bochs would be a 77 | great feature of Bochs. It would ease reverse engineering of non 78 | documented cards, or one could even use a real spare vga card. 79 | Frank Cornellis has done a great job on this subject, and we began 80 | integrating his changes. 81 | Status: 82 | The pcidev device is present in SVN and it has been updated for the new PCI 83 | infrastructure, but the new code is untested yet. 84 | 85 | 5. VGA 86 | For SVGA emulation we have Bochs VBE and the Cirrus adapter. We should have 87 | a look at the voodoo3 (specs http://v3tv.sourceforge.net/docs.php). 88 | Status: 89 | Voodoo1 emulation has been added in Bochs 2.6.1, initial Voodoo2 support is 90 | present in Bochs 2.6.5, but the performance is still low. 91 | 92 | 6. Random thoughts on disk emulation improvements : 93 | 6.1 support more disk image types 94 | 6.2 compressed disk image support 95 | Status: 96 | VPC disk image support has been added in Bochs 2.6. The bximage utility has been 97 | rewritten in C++ for image creation, conversion and resize in Bochs 2.6.5. 98 | 99 | 7. net 100 | 7.1 bootable ethernet rom ? 101 | 7.2 user mode networking ? 102 | see etherboot, Micheal Brown wrote : 103 | This already works; you can build an Etherboot rom image with the pnic 104 | driver, specify it as an option ROM in bochsrc and it will boot. I'm 105 | using this extensively at the moment in Etherboot development. 106 | In the Etherboot project's CVS, in the contrib/bochs directory, you can 107 | find a working bochsrc file and an up-to-date README with step-by-step 108 | instructions on getting this working. 109 | Status: 110 | The pnic device is present in SVN, but the status is unknown. PCI boot ROM support 111 | has been added for Bochs 2.6. Built-in 'slirp' support for user mode networking 112 | has been added in Bochs 2.6.5. The 'socket' networking module has been added 113 | in Bochs 2.6.9. It allows interconnecting Bochs instances with multi-port 114 | ethernet hub. 115 | 116 | 8. Bios 117 | 8.1 add "jump table placeholder" and log missing function calls in the bios. 118 | Check completness with Ralf Brown interrupt list. 119 | Status: 120 | Not done yet. 121 | 8.2 use Coreboot or SeaBios as possible alternatives/extensions to 122 | Bochs Bios ROM we have. 123 | Status: 124 | Starting from Bochs 2.5 SeaBIOS is usable. 125 | 126 | 9. LGPL VGABios 127 | 9.1 Video parameters table 128 | There is a very nice parameter table in 3dfx banshee document 129 | http://www2.lm-sensors.nu/~lm78/pdfs/Banshee_2d_spec.PDF 130 | see also http://www.xyzzy.claranet.de/dos/vgacrt.c 131 | Status: 132 | Version 0.7a of the LGPL'd VGABIOS has minimal support for the video 133 | parameter table. 134 | 135 | 10. Optimized Guest drivers still needed : VGA, IDE, NET 136 | We have a specific VGA driver for winNT/2K, but still 137 | lack drivers for other OSes. 138 | Status: 139 | Not done yet. 140 | 141 | 11. USB support 142 | Ben Lunt has been working on USB support. The USB mouse and keypad code 143 | is present in Bochs and almost stable. USB flash disk support has been 144 | started and the runtime device change support should be completed. 145 | Status: 146 | OHCI and UHCI host controller and 8 devices are known to work in Bochs. 147 | USB EHCI and xHCI support is now also present. 148 | 149 | 12. Config file 150 | Benjamen R. Meyer wrote : 151 | I think we should rework the .bochsrc file to be more standard across all 152 | devices. I like how the USB configuration is done in it, and think we should 153 | put something similar together for everything else. In other words, create 154 | something that can be easily used for everything, and make it easier to 155 | configure in the process. 156 | From what I can tell right now, most of the configuration lines are randomly 157 | thrown together as each gets implemented or added, instead of having 158 | something that is based on a standard approach to the configuration. 159 | The result should be something that would be able to easily auto-configured 160 | by another program (a configuration editor?) with minimal changes necessary 161 | when new devices/features are added. 162 | Status: Some work to unify parsing and saving config options has been done 163 | in Bochs 2.6.1. 164 | 165 | 13. lowlevel serial support for Windows. 166 | Volker has been working on this. 167 | Status: 168 | Not yet complete (transmit works, receive is losing data). 169 | 170 | 14. Parallel port 171 | Conn Clark wrote : 172 | I would like to see better parallel port support so I can use a dongle. 173 | This is something I would find very useful as it would mean I wouldn't 174 | have to boot back into windows ever again. I also recognize that this 175 | may require a kernel module be written, which is beyond my current 176 | skills. I know others will find this useful as I have had to tell a 177 | few people that their parallel port driven peripherals that require a 178 | bidirectional parallel port won't work. 179 | Status: 180 | Not done yet. 181 | 182 | 15. Guest-To-Host Communication 183 | Try to adapt VirtualBox guest-to-host communication methods into Bochs. 184 | Having VirtualBox Shared Folders or VNAT support in Bochs could very 185 | simplify its usage. 186 | 187 | 16. Patches / Bug reports 188 | There are dozens of patches floating around. Some are outdated, 189 | don't apply cleanly, are obsolete/unneeded. We could try to do 190 | some clean-up, and keep only relevant ones. 191 | We should also clean up the SF bug tracker. Some bugreports are 192 | very old and we asked for more information with no response. 193 | Status: 194 | There is some progress, but still a lot of work to do. 195 | 196 | 17. Positions 197 | If you want to help without coding, here are available positions : 198 | 19.1 Webmaster : update website (Jan Bruun Andersen offered to help) 199 | 19.2 patch coordinator : look at incoming patches (sourceforge and 200 | mailing list) and upload / update in the SVN patches directory. 201 | 19.3 platform maintainers for macos / win32 202 | 19.4 disk image maintainer : create and maintain our collection 203 | of disk images. Usually, only the configuration file needs to be 204 | updated, and old bios files have to be removed. Some packages 205 | still contain very old bios files, they should definitely have 206 | to be removed. 207 | Status: 208 | More active developers are needed to do the things described above. 209 | 210 | 18. Bochs demo cd/dvd 211 | With version 2.1, it is now technically possible to use disk images 212 | on a read-only media, with a journal files on a read/write media. 213 | It would be great to create a demo cd/dvd with executables for 214 | supported platforms, configuration files and read-only disk 215 | images, the journal files would be written in a temporary 216 | directory on the harddisk. 217 | Status: 218 | Not done yet. 219 | 220 | 19. Other CPU architectures : arm, ppc 221 | This has been asked in the mailing list. I'm not really 222 | interested, but other people might be. Should we propose to 223 | host the new CPUs code in our source tree, or should we let 224 | people fork ? 225 | Status: 226 | Not done yet. 227 | -------------------------------------------------------------------------------- /bochs/share/doc/bochs/slirp.conf: -------------------------------------------------------------------------------- 1 | # slirp config 2 | # The line above is mandatory 3 | 4 | # Supported options: 5 | # 6 | # RESTRICTED if set to 1, only built-in services are available 7 | # NET base IP address of the virtual network 8 | # MASK netmask of the virtual network 9 | # HOST IP address of the DHCP and TFTP server 10 | # HOSTNAME DHCP client hostname 11 | # DHCPSTART start address of DHCP pool 12 | # DNS IP address of the virtual DNS server 13 | # BOOTFILE boot filename returned by DHCP 14 | # DNSSEARCH comma-separated list of DNS suffixes to search (DHCP extension) 15 | # SMB_EXPORT absolute path to the shared folder (non-Windows SMB support) 16 | # SMB_SRV alternative IP address of the SMB server (default is 10.0.2.4) 17 | # HOSTFWD map guest port to host port for host-to-guest access 18 | # (format: protocol:hostaddr:hostport-guestaddr:guestport) 19 | 20 | # This is the default (classic slirp) setup 21 | # restricted = 0 22 | # net = 10.0.2.0 23 | # mask = 255.255.255.0 24 | # host = 10.0.2.2 25 | # dhcpstart = 10.0.2.15 26 | # dns = 10.0.2.3 27 | 28 | # This is the vnet setup 29 | # restricted = 1 30 | # net = 192.168.10.0 31 | # mask = 255.255.255.0 32 | # host = 192.168.10.1 33 | # dhcpstart = 192.168.10.2 34 | # dns = 0.0.0.0 35 | # bootfile = pxelinux.0 36 | 37 | # Host forwarding example (access guest SSH server from host port 12345) 38 | # hostfwd = tcp::12345-:22 39 | -------------------------------------------------------------------------------- /bochs/share/man/man1/bochs-dlx.1.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/share/man/man1/bochs-dlx.1.gz -------------------------------------------------------------------------------- /bochs/share/man/man1/bochs.1.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/share/man/man1/bochs.1.gz -------------------------------------------------------------------------------- /bochs/share/man/man1/bximage.1.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/share/man/man1/bximage.1.gz -------------------------------------------------------------------------------- /bochs/share/man/man5/bochsrc.5.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gstalker/Kernel-Learning/220187efe45af8702bfc1a76696b6d62a46b52fa/bochs/share/man/man5/bochsrc.5.gz --------------------------------------------------------------------------------