文章目录

  • 专栏博客链接
  • 相关查阅博客链接
  • 本书中错误勘误
  • 部分缩写熟知
  • 修改代码的小闲聊
  • 编写print.S(实现打印函数)
    • print.S代码
    • print.h代码和stdint.h代码
    • 修改main.c(检测put_char是否生效)
  • 编译kernel.bin 链接print.o main.o 测试put_char函数
    • 目前为止常用编译链接代码
    • 编译链接 测试函数
  • 修改print.S(实现打印字符串)
    • 修改main.c(测试打印字符串)
  • 修改print.S(打印数字)
    • 修改main.c(测试打印数字)
  • print.S最终代码+print.h头文件定义+stdint.h定义
    • print.S代码
    • print.h头文件
    • stdint.h定义
  • 结束语(第六章完结撒花*★,°*:.☆( ̄▽ ̄)/$:*.°★* 。)

专栏博客链接


《操作系统真象还原》从零开始自制操作系统 全章节博客链接


相关查阅博客链接


汇编除法运算
movsb movsw movsd 指令详解


本书中错误勘误


因为写习惯错误勘误了 其实应该写本章节注意事项 但是习惯了 就这样写了 刚哥无意冒犯 哈哈哈哈

1、ld architecture of input file `lib/kernel/print.o’ is incompatible with i386:x86-64 output

如果出现了这个事项 请先用下面的代码先试试能不能成功运行
注意把其中的文件目录修改成读者自己编写的目录
第二行多了一个-m32 在32位下编辑
第三行多了一个-m elf_i386

如果依然无法运行的话 那就很抱歉了 可能要重新把编译器变成gcc 4.x.x
详情请移步 我写的在第五章 处理elf文件头部分gcc编译器降级部分

因为我们现在处于Ubuntu 20.02 64版本 编译默认就是64位的
就会导致和32位的编译链接出错

《操作系统真象还原》第五章 ---- 轻取物理内存容量 启用分页畅游虚拟空间 力斧直斩内核先劈一角 闲庭信步摸谈特权级

nasm -f elf -o lib/kernel/print.o lib/kernel/print.S
gcc -m32 -I lib/kernel/ -c -o kernel/main.o kernel/main.c*
ld -m elf_i386 -Ttext 0xc0001500 -e main -o kernel/kernel.bin \
kernel/main.o lib/kernel/print.o**
dd if=/home/cooiboi/bochs/kernel/kernel.bin of=/home/cooiboi/bochs/hd60M.img bs=512 count=200 seek=9 conv=notrunc

部分缩写熟知


cr carriage return 回车
lf line feed 换行
bs back space 退格


修改代码的小闲聊


现在是6/17 差不多我也连续编写操作系统到了8天了
接近6/30的期末考试 还有10多天了 由于这学期的高数大物的难度上去了
我也不能只花3天左右复习了 所以打算在6/20号就先结束操作系统编写
然后在考完试之后 暑假期间再继续把之后的部分给编写了

其实编写这个就是应该一次性给编写完 而中间休息这么久
期末考试完还有一个15天的军训 啊 实属折磨

一次性 一口气连续的编写完其实是最好的 但是没有办法 总是因为这样那样的事情耽误 那就顺其天意 先把大一下顺利过渡了 不要挂高数和大物 英语也千万不能挂科 只要顺利度过大一下 其实之后什么也就好起来了 好吧 废话少说 开始编写内核程序了


编写print.S(实现打印函数)


为了方便起见 也是为了文件能够分门叠类 后面还有好多好多的程序需要来弄 也是按照书上给的新建了一个文件夹lib
如下图

对于print.S 我是把它放到了lib/kernel里面 在lib里面专门又放了一个kernel文件夹 把以后内核需要用的程序文件都放了进去

大家可能看书也看得差不多了 然后关于这部分我也没有什么好说的
直接还是给代码吧


print.S代码


RPL0    equ 00b
TI_GDT  equ 000b
SELECTOR_VIDEO       equ (0X0003<<3) + TI_GDT + RPL0
SELECTOR_DATA     equ (0X0002<<3) + TI_GDT + RPL0[bits 32]
section .text
global put_char
;------------------- put_char 函数实现 -------------------------------------------
;把字符写到光标位置
;---------------------------------------------------------------------------------put_char:pushad                   ;push all double寄存器mov ax,SELECTOR_VIDEOmov gs,ax                  ;gs寄存器赋值段选择子mov dx,0x3D4               ;默认CRT 寄存器索引mov al,0xE                 ;这里用al 不用ax 是因为 此处索引寄存器是一个8字节的寄存器out dx,al                  ;看光标高位值寄存器 为什么用al 可以推算一下 光标0~1999 2^(8+8)字节完全够用mov dx,0x3D5               ;光标高位值寄存器窗口in  al,dx                  ;移入ax shl ax,0x8                 ;左移动8位 移动向ah部分 光标位置为8字节mov dx,0x3D4mov al,0xFout dx,almov dx,0x3D5in  al,dxmov bx,ax                  ;光标位置转移给bx  mov byte cl,[esp+36]       ;4字节返回 只需要把push eip 4字节 + pushad 8*4 32字节算进去即可;回车0xd 换行0xa 退格0x8 cmp cl,0xd                 ;比较cl与0xd是否相等je .is_carriage_return     ;回车处理函数cmp cl,0xa                 ;比较cl与0xa是否相等 je .is_line_feed           ;换行处理函数cmp cl,0x8                 ;比较cl与0x8是否相等je .is_backspace           ;退格处理函数jmp .put_other_char.is_backspace:cmp bx,0                   ;如果bx = 0 则没有办法退格了 这是我除书上之外额外加的条件je  .set_cursor              dec bx                     ;光标位置退1shl bx,1                   ;一个字符占两个字节 一个字节是属性 一个字节ascii mov word [gs:bx],0x0720    ;低字节ascii 32 ascii表示空字符 7 高字符属性空shr bx,1                   ;退回原来的位置jmp .set_cursor            ;交给硬件去处理光标位置 到时候在那几个老端口把字符信息还回去就完事了.put_other_char:shl bx,1                   mov [gs:bx],cl             inc bx                     mov byte [gs:bx],0x7inc bxshr bx,1cmp bx,2000                ;没到边界2000即跳转jl  .set_cursor            ;没有的话 继续往下进行 都2000了其实下面的操作也是不能跳转走的;只能等下面继续处理滚动屏幕了.is_carriage_return:.is_line_feed:xor dx,dxmov ax,bx                  ;32位除以16位 被除数高位dx 被除数低位ax div之后余数放在dx 商放在axmov si,80div sisub bx,dx.is_carrige_return_end:add bx,80                  ;一共一页2000 共25行 2000/25=80 则向bx增加80cmp bx,2000jl .set_cursor             .roll_screen:cld                        ;从低到高移动mov ax,SELECTOR_DATA    ;我不放心 就初始化了一下mov es,ax      mov di,es                  mov ecx,920mov esi,0xc00b80a0          ;忘了的这里写一下 ds:si -> es:di (s->d) 源地址si 目的地址di  mov edi,0xc00b8000rep movsd                  ;movs doubleword 双子mov ebx,3840               ;最后一行80*2 = 160 4000-160 = 3840 最后一行清除了mov ecx,80mov esi,0                  .clean_last_row:   mov word [ebx+esi*2],0x720 ;0x07 0x20 属性 空字符inc esi     loop .clean_last_rowmov ebx,1920.set_cursor:mov dx,0x3D4mov al,0xEout dx,almov dx,0X3D5mov al,bhout dx,almov dx,0x3D4mov al,0XFout dx,almov dx,0x3D5mov al,blout dx,alpopad                        ;把之前全部储存的给pop出来 还原现场ret

print.h代码和stdint.h代码


stdint.h 路径lib/

#ifndef __LIB_STDINT_H
#define __LIB_STDINT_H
typedef signed char int8_t;
typedef signed short int int16_t;
typedef signed int int32_t;
typedef signed long long int int64_t;
typedef signed unsigned char uint8_t;
typedef signed unsigned short int uint16_t;
typedef signed unsigned int uint32_t;
typedef signed unsigned long long int uint64_t;
#endif

print.h 路径lib/kernel

#ifndef __LIB_KERNEL_PRINT_H
#define __LIB_KERNEL_PRINT_H
#include "stdint.h"void put_char(uint8_t char_asci);
#endif

修改main.c(检测put_char是否生效)


当然这里测试 你想里面测试写什么就写什么
其实我还试了一下不停的put_char('\n') 测试了一下滚屏是否生效
想要测试功能的话自己编写即可

#include "print.h"
int main()
{   put_char('k');put_char('e');put_char('r');put_char('n');put_char('e');put_char('l');put_char('!');put_char('\n');put_char('i');put_char('m');put_char(' ');put_char('c');put_char('o');put_char('m');put_char('1'); //这里的1是看退格是否生效 //输出时只要是kernel! im coming!即可put_char('\b');put_char('i');put_char('n');put_char('g');put_char('!');while(1);return 0;
}

编译kernel.bin 链接print.o main.o 测试put_char函数


指令如下图 我是把我比较常用的指令放在了一个文档中
每次要用的话就打开复制粘贴就行了 非常方便


目前为止常用编译链接代码


记得要用的时候把代码路径给修改成你自己的路径

nasm -I include/ -o boot/loader.bin boot/loader.S
dd if=/home/cooiboi/bochs/boot/loader.bin of=/home/cooiboi/bochs/hd60M.img bs=512 count=3 seek=2 conv=notrunc
bin/bochs -f bochsrc.diskgcc -m32 -c -o kernel/main.o kernel/main.c
ld -m elf_i386 kernel/main.o -Ttext 0xc0001500 -e main -o kernel/kernel.bin
dd if=/home/cooiboi/bochs/kernel/kernel.bin of=/home/cooiboi/bochs/hd60M.img bs=512 count=200 seek=9 conv=notruncnasm -I include/ -o boot/loader.bin boot/loader.S
dd if=/home/cooiboi/bochs/boot/loader.bin of=/home/cooiboi/bochs/hd60M.img bs=512 count=3 seek=2 conv=notrunc
nasm -f elf -o lib/kernel/print.o lib/kernel/print.S
gcc -m32 -I lib/kernel/ -c -o kernel/main.o kernel/main.c
ld -m elf_i386 -Ttext 0xc0001500 -e main -o kernel/kernel.bin \
kernel/main.o lib/kernel/print.o
dd if=/home/cooiboi/bochs/kernel/kernel.bin of=/home/cooiboi/bochs/hd60M.img bs=512 count=200 seek=9 conv=notrunc
bin/bochs -f bochsrc.disk

编译链接 测试函数


我们就用最底下的代码 运行bochs看看效果

nasm -f elf -o lib/kernel/print.o lib/kernel/print.S
gcc -m32 -I lib/kernel/ -c -o kernel/main.o kernel/main.c
ld -m elf_i386 -Ttext 0xc0001500 -e main -o kernel/kernel.bin \
kernel/main.o lib/kernel/print.o
dd if=/home/cooiboi/bochs/kernel/kernel.bin of=/home/cooiboi/bochs/hd60M.img bs=512 count=200 seek=9 conv=notrunc
bin/bochs -f bochsrc.disk

输出正如预期
因为在跳转后 光标位置本来就在偏下方的位置
所以就在那里输出了两排
并且在之后滚屏测试中也发现生效 则从效果上看删除 回车 换行均编写正确


修改print.S(实现打印字符串)


因为其实我是比较喜欢自己独立写代码的那种类型
所以这部分我自己有思路就自己写了

下面部分是我按照自己思路实现的

;先自己尝试写一下
global put_str
put_str:push eaxpush ebxpush ebpxor  eax,eaxmov  ebp,esp                 ;一般用ebp来寻值 esp上面有个4字节的返回地址 就没有了mov  ebx,[ebp+16]            ;指针4字节+12字节寄存器.put_char_loop:    mov byte al,[ebx]cmp  al,0je  .str_endpush axcall put_charadd  esp,2inc  ebxjmp .put_char_loop.str_end:pop ebppop ebxpop eaxret

修改main.c(测试打印字符串)


修改成这样 \b1就抵消了 测试了空字符串
但其实我忽然想起来 退格如果在第二行行首退格
做的稍微好一点的会退到上一行的末尾
而我们没有实现 而是退到上一行的的末尾
但我们主要是实现操作系统 抓核心部分吧

我想了一下 如果要那样子实现的话 需要把每一行的末尾位置用一个数组记录下来 那确实我们是过来做打印函数 而不是做操作系统了

#include "print.h"
int main()
{   put_str("kernel!\nim com1\bing!");put_str("\n");put_str("");put_str("g");put_char('g');while(1);return 0;
}

下面是测试效果图
从实现效果来看 函数应该是调用成功了


修改print.S(打印数字)


小弟技艺不精 在尝试半小时后 要不就卡死 要不就因为小端序而错位
实属不才 只能按照书上的思路走了

再跟着书上敲完代码的时候 其实思路一点都不难
但是真的刚哥写的太简洁 格式写的真的很优雅 真的很令人佩服
就是我忽然想起来我力扣刷了几百道之后 我不再仅仅追求AC了 而是每道题都会写的很干净优雅 代码行数越来越少越来越少

真的很佩服 上代码吧

put_int:pushadmov ebp,espmov eax,[esp+36]        ;32字节+4返回地址mov edx,eaxmov edi,7               ;put_int_buffer偏移量mov ecx,8               ;循环八次mov ebx,put_int_buffer.16based_4bits:and edx,0xFcmp edx,0x9             jg  .is_A2F             ;进入A~F ASCII码处理add edx,'0'             ;得0~9的asciijmp .store    .is_A2F:sub edx,10add edx,'A'             ;减去10等于A~F的字符序 + 'A'得ascii   .store:mov [ebx+edi],dl        ;偏移量 倒序储存在bufdec edi                 ;-1shr eax,4mov edx,eaxloop .16based_4bits    ;8个16进制ascii入账 且还是大端序 妙.ready_to_print:inc edi                 ;减去8次成-1了 先循环+1次.skip_prefix_0:            ;处理前缀0cmp edi,8               ;edi偏移量 8的时候表示第九个字符je  .full0              ;全是0.go_on_skip:   mov cl,[put_int_buffer+edi]inc edicmp cl,'0'je  .skip_prefix_0      ;跳转回去看看是不是最后一个数字了dec edi                 ;不是的0的话 就到下面打印字符时间jmp .put_each_num.full0:mov  cl,'0'.put_each_num:mov  cl,[put_int_buffer+edi]push ecxcall put_charadd  esp,4inc  edicmp  edi,8jge .endjmp .put_each_num.end:popad ret

修改main.c(测试打印数字)


#include "print.h"
int main()
{   put_str("kernel!\nim com1\bing!\n");put_str("gg\n");put_int(0x11111111);put_char(' ');put_int(32);put_char(' ');put_int(999);while(1);return 0;
}

测试效果如下 没有问题的


print.S最终代码+print.h头文件定义+stdint.h定义


print.S代码


TI_GDT equ  0
RPL0  equ   0
SELECTOR_VIDEO equ (0x0003<<3) + TI_GDT + RPL0section .data
put_int_buffer    dq    0     ; 定义8字节缓冲区用于数字到字符的转换[bits 32]
section .text
;--------------------------------------------
;put_str 通过put_char来打印以0字符结尾的字符串
;--------------------------------------------
global put_str
put_str:
;由于本函数中只用到了ebx和ecx,只备份这两个寄存器push ebxpush ecxxor ecx, ecx              ; 准备用ecx存储参数,清空mov ebx, [esp + 12]         ; 从栈中得到待打印的字符串地址
.goon:mov cl, [ebx]cmp cl, 0              ; 如果处理到了字符串尾,跳到结束处返回jz .str_overpush ecx            ; 为put_char函数传递参数call put_charadd esp, 4            ; 回收参数所占的栈空间inc ebx             ; 使ebx指向下一个字符jmp .goon
.str_over:pop ecxpop ebxret;--------------------   将小端字节序的数字变成对应的ascii后,倒置   -----------------------
;输入:栈中参数为待打印的数字
;输出:在屏幕上打印16进制数字,并不会打印前缀0x,如打印10进制15时,只会直接打印f,不会是0xf
;------------------------------------------------------------------------------------------
global put_int
put_int:pushadmov ebp, espmov eax, [ebp+4*9]              ; call的返回地址占4字节+pushad的8个4字节mov edx, eaxmov edi, 7                          ; 指定在put_int_buffer中初始的偏移量mov ecx, 8                   ; 32位数字中,16进制数字的位数是8个mov ebx, put_int_buffer;将32位数字按照16进制的形式从低位到高位逐个处理,共处理8个16进制数字
.16based_4bits:                ; 每4位二进制是16进制数字的1位,遍历每一位16进制数字and edx, 0x0000000F               ; 解析16进制数字的每一位。and与操作后,edx只有低4位有效cmp edx, 9                 ; 数字0~9和a~f需要分别处理成对应的字符jg .is_A2F add edx, '0'                 ; ascii码是8位大小。add求和操作后,edx低8位有效。jmp .store
.is_A2F:sub edx, 10                ; A~F 减去10 所得到的差,再加上字符A的ascii码,便是A~F对应的ascii码add edx, 'A';将每一位数字转换成对应的字符后,按照类似“大端”的顺序存储到缓冲区put_int_buffer
;高位字符放在低地址,低位字符要放在高地址,这样和大端字节序类似,只不过咱们这里是字符序.
.store:
; 此时dl中应该是数字对应的字符的ascii码mov [ebx+edi], dl             dec edishr eax, 4mov edx, eax loop .16based_4bits;现在put_int_buffer中已全是字符,打印之前,
;把高位连续的字符去掉,比如把字符000123变成123
.ready_to_print:inc edi                ; 此时edi退减为-1(0xffffffff),加1使其为0
.skip_prefix_0:  cmp edi,8                 ; 若已经比较第9个字符了,表示待打印的字符串为全0 je .full0
;找出连续的0字符, edi做为非0的最高位字符的偏移
.go_on_skip:   mov cl, [put_int_buffer+edi]inc edicmp cl, '0' je .skip_prefix_0             ; 继续判断下一位字符是否为字符0(不是数字0)dec edi                 ;edi在上面的inc操作中指向了下一个字符,若当前字符不为'0',要恢复edi指向当前字符            jmp .put_each_num.full0:mov cl,'0'                ; 输入的数字为全0时,则只打印0
.put_each_num:push ecx                 ; 此时cl中为可打印的字符call put_charadd esp, 4inc edi                ; 使edi指向下一个字符mov cl, [put_int_buffer+edi]          ; 获取下一个字符到cl寄存器cmp edi,8jl .put_each_numpopadret;------------------------   put_char   -----------------------------
;功能描述:把栈中的1个字符写入光标所在处
;-------------------------------------------------------------------
global put_char
put_char:pushad    ;备份32位寄存器环境;需要保证gs中为正确的视频段选择子,为保险起见,每次打印时都为gs赋值mov ax, SELECTOR_VIDEO           ; 不能直接把立即数送入段寄存器mov gs, ax;;;;;;;;;  获取当前光标位置 ;;;;;;;;;;先获得高8位mov dx, 0x03d4  ;索引寄存器mov al, 0x0e    ;用于提供光标位置的高8位out dx, almov dx, 0x03d5  ;通过读写数据端口0x3d5来获得或设置光标位置 in al, dx       ;得到了光标位置的高8位mov ah, al;再获取低8位mov dx, 0x03d4mov al, 0x0fout dx, almov dx, 0x03d5 in al, dx;将光标存入bxmov bx, ax    ;下面这行是在栈中获取待打印的字符mov ecx, [esp + 36]       ;pushad压入4×8=32字节,加上主调函数的返回地址4字节,故esp+36字节cmp cl, 0xd               ;CR是0x0d,LF是0x0ajz .is_carriage_returncmp cl, 0xajz .is_line_feedcmp cl, 0x8                ;BS(backspace)的asc码是8jz .is_backspacejmp .put_other
;;;;;;;;;;;;;;;;;;.is_backspace:
;;;;;;;;;;;;       backspace的一点说明        ;;;;;;;;;;
; 当为backspace时,本质上只要将光标移向前一个显存位置即可.后面再输入的字符自然会覆盖此处的字符
; 但有可能在键入backspace后并不再键入新的字符,这时在光标已经向前移动到待删除的字符位置,但字符还在原处,
; 这就显得好怪异,所以此处添加了空格或空字符0dec bxshl bx,1mov byte [gs:bx], 0x20          ;将待删除的字节补为0或空格皆可inc bxmov byte [gs:bx], 0x07shr bx,1jmp .set_cursor
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;.put_other:shl bx, 1                  ; 光标位置是用2字节表示,将光标值乘2,表示对应显存中的偏移字节mov [gs:bx], cl            ; ascii字符本身inc bxmov byte [gs:bx],0x07          ; 字符属性shr bx, 1                 ; 恢复老的光标值inc bx                 ; 下一个光标值cmp bx, 2000         jl .set_cursor             ; 若光标值小于2000,表示未写到显存的最后,则去设置新的光标值; 若超出屏幕字符数大小(2000)则换行处理.is_line_feed:                  ; 是换行符LF(\n).is_carriage_return:            ; 是回车符CR(\r); 如果是CR(\r),只要把光标移到行首就行了。xor dx, dx                 ; dx是被除数的高16位,清0.mov ax, bx                 ; ax是被除数的低16位.mov si, 80                ; 由于是效仿linux,linux中\n便表示下一行的行首,所以本系统中,div si               ; 把\n和\r都处理为linux中\n的意思,也就是下一行的行首。sub bx, dx                 ; 光标值减去除80的余数便是取整; 以上4行处理\r的代码.is_carriage_return_end:                 ; 回车符CR处理结束add bx, 80cmp bx, 2000.is_line_feed_end:              ; 若是LF(\n),将光标移+80便可。  jl .set_cursor;屏幕行范围是0~24,滚屏的原理是将屏幕的1~24行搬运到0~23行,再将第24行用空格填充.roll_screen:                  ; 若超出屏幕大小,开始滚屏cld  mov ecx, 960                  ; 一共有2000-80=1920个字符要搬运,共1920*2=3840字节.一次搬4字节,共3840/4=960次 mov esi, 0xc00b80a0           ; 第1行行首mov edi, 0xc00b8000              ; 第0行行首rep movsd                ;;;;;;;将最后一行填充为空白mov ebx, 3840              ; 最后一行首字符的第一个字节偏移= 1920 * 2mov ecx, 80                 ;一行是80字符(160字节),每次清理1字符(2字节),一行需要移动80次.cls:mov word [gs:ebx], 0x0720        ;0x0720是黑底白字的空格键add ebx, 2loop .cls mov bx,1920                 ;将光标值重置为1920,最后一行的首字符..set_cursor:   ;将光标设为bx值
;;;;;;; 1 先设置高8位 ;;;;;;;;mov dx, 0x03d4           ;索引寄存器mov al, 0x0e                  ;用于提供光标位置的高8位out dx, almov dx, 0x03d5           ;通过读写数据端口0x3d5来获得或设置光标位置 mov al, bhout dx, al;;;;;;; 2 再设置低8位 ;;;;;;;;;mov dx, 0x03d4mov al, 0x0fout dx, almov dx, 0x03d5 mov al, blout dx, al.put_char_done: popadret

print.h头文件


#ifndef __LIB_KERNEL_PRINT_H
#define __LIB_KERNEL_PRINT_H
#include "stdint.h"void put_char(uint8_t char_asci);
void put_str (char* str);
void put_int (uint32_t num);
#endif

stdint.h定义


#ifndef __LIB_STDINT_H
#define __LIB_STDINT_H
typedef signed char int8_t;
typedef signed short int int16_t;
typedef signed int int32_t;
typedef signed long long int int64_t;
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long int uint64_t;
#endif

结束语(第六章完结撒花★,°:.☆( ̄▽ ̄)/$:.°★ 。)


加上今晚上把第六章的内联汇编看了
这本书就已经看完了300页了 到现在是我开始做自制操作系统的第八天
啊 要是如果如果如果后面能够再给我两个星期 我相信一定可以把整本书看完+操作系统做完
啊 只可惜后面要军训+期末考试 我的高数大物到现在也一点不会
20号就要开始期末总复习了 还有几天时间 争取多做几章节多看几页书
后面就完完全全要认真复习了 :) 期末一定不挂科!

后补 第二天做第七章的时候 明显感觉可能是连续8天没有休息 做六章的内容有点力不从心了 于是第七章之后的内容只能交给暑假来做了 这两天需要休息一下 为后面的期末备考做准备了

《操作系统真象还原》第六章 ---- 开启c语言编写函数时代 首挑打印函数小试牛刀 费心讨力重回gcc降级 终尝多日调试之喜悦相关推荐

  1. [书]操作系统真象还原 -- 第5章 开启保护模式、开启分页机制

    mbr:加载loader,跳转 loader: 1)调用BIOS中断获取内存大小; 2)构建GDT.开启保护模式;  3)构建页目录表和页表.开启分页机制; FILE:loader.asm ; FIL ...

  2. 《操作系统真象还原》第九章

    <操作系统真象还原>第九章 本篇对应书籍第九章的内容 本篇内容介绍了线程是什么,多线程的原理,多线程用到的核心数据结构,以及通过代码实现了内核多线程的调度 线程是什么? 执行流 过去,计算 ...

  3. 《操作系统真象还原》第二章

    <操作系统真象还原>第二章 编写MBR主引导记录 载入内存 过程: (1)程序被加载器(软件或硬件)加载到内存某个区域. (2)CPU的cs:ip寄存器被指向这个程序的起始地址. 从按下主 ...

  4. 《操作系统真象还原》1-3章 学习记录

    文章目录 前言 一.开始实验前的一些基本问题解答? section的含义? vstart的含义? $ 和 $$区别? 实模式的特点? CPU如何和硬盘进行交互? CPU和IO设备交互方式? 程序载入内 ...

  5. 操作系统真象还原——第5章 从保护模式到内核

    目录 前言 5.1 获取物理内存容量 5.1.1 学习Linux获取内存的方法 5.1.2 实战内存容量检测 5.2 内存分页 为什么需要分页? 一级页表 二级页表 如何设计一个页表 分页机制的代码实 ...

  6. 《操作系统真象还原》第九章 ---- 终进入线程动斧开刀 豁然开朗拨云见日 还需解决同步机制才能长舒气

    文章目录 专栏博客链接 相关查阅博客链接 本书中错误勘误 进程 线程的自我小理解 线程 进程的状态 内核级线程 & 用户级线程 初步实现内核级线程 浪费两三个小时调试的辛酸史 编写thread ...

  7. 操作系统真象还原第2章:编写MBR主引导记录

    前言 这章的内容挺少的,也很简单,如果环境没配置错的话是没啥问题的.但是这章也很精彩,把引导的过程给说了出来,我也是看了几遍把这个过程给大致看懂了. 首先计算机一开机这个时cpu会自动把cs:ip指针 ...

  8. 《操作系统真象还原》第二章 ---- 编写MBR主引导记录 初尝编写的快乐 雏形已显!

    文章目录 专栏博客链接 前引 相关术语 理清操作系统启动程序运行流程(部分) 编写MBR引导内容 编译并检验mbr.bin Linux dd 磁盘操作指令与参数 模拟操作试一试 结束语 专栏博客链接 ...

  9. 操作系统真象还原第3章:完善MBR

    前言 这次我出现了一些BUG,导致我忙活了一阵子,还好的是解决了 老规矩还是把整个流程过一遍,当MBR忙活完后,就需要把自己手中的棒交给loader了,MBR的作用就是从硬盘中的内核加载器移动到内存中 ...

最新文章

  1. python使用heapq快速查找最大或最小的 N 个元素
  2. BZOJ3488 : [ONTAK2010]Highways
  3. .Net Remoting(分离服务程序实现) - Part.3
  4. loadrunner socket协议问题归纳(5)
  5. mysql还原数据mysqldump
  6. linux下模糊搜索命令,linux命令当前文件夹下面模糊搜索文件
  7. java技术栈_七天串起java技术栈-开篇
  8. java 链表插入排序,insertion Sort List (链表的插入排序) leecode java
  9. C++学习笔记(达内视频版)
  10. netstat 命令详解
  11. 0xc0000428 winload.exe无法验证其数字签名的解决方法
  12. ANDROID高仿京东分类_类似京东分类界面源代码下载
  13. Java用户管理系统
  14. Linux下LED灯驱动模板详解
  15. golang框架gin的日志处理和zap lumberjack日志使用
  16. ccflow表结构与运行机制(二次开发必看)
  17. Win7 IIS部署网站局域网内用户无法访问网站解决方案
  18. 二招搞定word文档中的乱码
  19. java扰码_TD中下行同步码和扰码的区别和作用
  20. matlab中elevation函数功能,Matlab的Demcmap的Python等价物(elevation+/appropriate colormap)...

热门文章

  1. HTTP1 HTTP1.1 HTTP2主要区别及 HTTP3
  2. python一行代码实现动态爱心
  3. 《你不知道的JavaScript(上卷)》——[美]凯尔辛普森
  4. Aspose.Words for .NET使用表格教程之水平和垂直合并表格中单元格
  5. Windows下我个人感觉比较好的一些软件
  6. c语言随机数教学成果与反思,教学成果报告-渤海大学.pdf
  7. 用生成模型来做图像恢复的介绍和回顾:上下文编码器
  8. 诗经 - 小雅 - 吉日
  9. 去广告神器——李跳跳
  10. 今夜,整个中国零售业集体失眠!