《操作系统真象还原》第六章 ---- 开启c语言编写函数时代 首挑打印函数小试牛刀 费心讨力重回gcc降级 终尝多日调试之喜悦
文章目录
- 专栏博客链接
- 相关查阅博客链接
- 本书中错误勘误
- 部分缩写熟知
- 修改代码的小闲聊
- 编写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(测试打印字符串)
修改成这样 \b
和1
就抵消了 测试了空字符串
但其实我忽然想起来 退格如果在第二行行首退格
做的稍微好一点的会退到上一行的末尾
而我们没有实现 而是退到上一行的的末尾
但我们主要是实现操作系统 抓核心部分吧
我想了一下 如果要那样子实现的话 需要把每一行的末尾位置用一个数组记录下来 那确实我们是过来做打印函数 而不是做操作系统了
#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降级 终尝多日调试之喜悦相关推荐
- [书]操作系统真象还原 -- 第5章 开启保护模式、开启分页机制
mbr:加载loader,跳转 loader: 1)调用BIOS中断获取内存大小; 2)构建GDT.开启保护模式; 3)构建页目录表和页表.开启分页机制; FILE:loader.asm ; FIL ...
- 《操作系统真象还原》第九章
<操作系统真象还原>第九章 本篇对应书籍第九章的内容 本篇内容介绍了线程是什么,多线程的原理,多线程用到的核心数据结构,以及通过代码实现了内核多线程的调度 线程是什么? 执行流 过去,计算 ...
- 《操作系统真象还原》第二章
<操作系统真象还原>第二章 编写MBR主引导记录 载入内存 过程: (1)程序被加载器(软件或硬件)加载到内存某个区域. (2)CPU的cs:ip寄存器被指向这个程序的起始地址. 从按下主 ...
- 《操作系统真象还原》1-3章 学习记录
文章目录 前言 一.开始实验前的一些基本问题解答? section的含义? vstart的含义? $ 和 $$区别? 实模式的特点? CPU如何和硬盘进行交互? CPU和IO设备交互方式? 程序载入内 ...
- 操作系统真象还原——第5章 从保护模式到内核
目录 前言 5.1 获取物理内存容量 5.1.1 学习Linux获取内存的方法 5.1.2 实战内存容量检测 5.2 内存分页 为什么需要分页? 一级页表 二级页表 如何设计一个页表 分页机制的代码实 ...
- 《操作系统真象还原》第九章 ---- 终进入线程动斧开刀 豁然开朗拨云见日 还需解决同步机制才能长舒气
文章目录 专栏博客链接 相关查阅博客链接 本书中错误勘误 进程 线程的自我小理解 线程 进程的状态 内核级线程 & 用户级线程 初步实现内核级线程 浪费两三个小时调试的辛酸史 编写thread ...
- 操作系统真象还原第2章:编写MBR主引导记录
前言 这章的内容挺少的,也很简单,如果环境没配置错的话是没啥问题的.但是这章也很精彩,把引导的过程给说了出来,我也是看了几遍把这个过程给大致看懂了. 首先计算机一开机这个时cpu会自动把cs:ip指针 ...
- 《操作系统真象还原》第二章 ---- 编写MBR主引导记录 初尝编写的快乐 雏形已显!
文章目录 专栏博客链接 前引 相关术语 理清操作系统启动程序运行流程(部分) 编写MBR引导内容 编译并检验mbr.bin Linux dd 磁盘操作指令与参数 模拟操作试一试 结束语 专栏博客链接 ...
- 操作系统真象还原第3章:完善MBR
前言 这次我出现了一些BUG,导致我忙活了一阵子,还好的是解决了 老规矩还是把整个流程过一遍,当MBR忙活完后,就需要把自己手中的棒交给loader了,MBR的作用就是从硬盘中的内核加载器移动到内存中 ...
最新文章
- python使用heapq快速查找最大或最小的 N 个元素
- BZOJ3488 : [ONTAK2010]Highways
- .Net Remoting(分离服务程序实现) - Part.3
- loadrunner socket协议问题归纳(5)
- mysql还原数据mysqldump
- linux下模糊搜索命令,linux命令当前文件夹下面模糊搜索文件
- java技术栈_七天串起java技术栈-开篇
- java 链表插入排序,insertion Sort List (链表的插入排序) leecode java
- C++学习笔记(达内视频版)
- netstat 命令详解
- 0xc0000428 winload.exe无法验证其数字签名的解决方法
- ANDROID高仿京东分类_类似京东分类界面源代码下载
- Java用户管理系统
- Linux下LED灯驱动模板详解
- golang框架gin的日志处理和zap lumberjack日志使用
- ccflow表结构与运行机制(二次开发必看)
- Win7 IIS部署网站局域网内用户无法访问网站解决方案
- 二招搞定word文档中的乱码
- java扰码_TD中下行同步码和扰码的区别和作用
- matlab中elevation函数功能,Matlab的Demcmap的Python等价物(elevation+/appropriate colormap)...