从开始到保护--系统开机引导

------没有一个文档能写的通俗易懂,我希望写出来。

开机引导和实模式:

两个星期加上假期吐血整理,所述为计算机的开机引导,其中包括一系列计算机内存设置等等,由于没有老师教,本人理解可能还是有点错误,希望错误的地方看的博友们能帮忙指出来,共同学习,谢谢!

目前正在看linux0.11内核源代码,参考资料极其环境配置后面会说出来。

我们的操作系统从计算机加电开始就开始运行,那么,爱思考的同学们会问计算机的运行最起码都是从内存运行的,运行的是内存的代码,那么在开机启动的时候计算机内存里面是不会有东西的,那么,到底操作系统是怎么启动的呢?

其实从计算机加电开始,操作系统首先进行一系列自检,这个自检是通过计算机加电然后发送一个信号给BIOS,BIOS进行一部分代码复制来初始化计算机(这里的代码复制的是一个固定ROM区里面的?),初始化完毕后计算机就开始自动读取磁盘,磁盘读取一个扇区,512字节,当独到某个磁盘第0磁道第一个扇区的最后两个字节为55和aa的时候计算机就自动认为其为引导程序,就会把此512字节读入内存绝对地址0x07c00处。此时,计算机的操作就完全交给程序设计者了。

那么,也就是说引导系统必须具备如下因素:

1、加载到0x7c00处

2、大小为512字节

3、最后两个字节为55和aa

满足这三个条件的程序都可以作为引导,只要将其写入磁盘的第0磁道第一扇区处即可成为引导。

说到这里,有一件比较有意思的事情,去年一学弟说自己写了个病毒,破坏磁盘,当时就想想这个是个硬件问题,前几天突然想了想,不能启动系统不就是引导坏了吗?这个是可以修的,只要将程序写入磁盘,不就OK了吗,遂要那个代码,可惜代码没了,貌似在现在的windows系统里面直接写汇编读写磁盘就是不行,保护太强了,不知道他是怎么实现的破坏磁盘。

这里说一点常识:这里说的写入磁盘的代码是二进制的代码,就是纯二进制,也就是机器码,那么在windows里面(由于目前我是在windows里面开发的,windows的批处理很好用,而Linux的GNU make现在还不会用)是一种.com文件,用masm汇编的话可以这样将exe文件转换成com文件:

Exe2bin a.exe a.com

而如果使用nasm汇编的话直接编译成.bin文件就行了:

nasm -o boot.bin boot.asm

编译好后的com文件可以直接双击执行,而bin文件可以使用二进制查看,也可以自己写程序打开查看,都可以使用debug调试,这两种文件区别是com在内存定位为0x0100处,而bin文件不确定,由于windows的保护,也可能是一致的。

在这里不得不提到:在最初计算机自检完成后将磁盘内容读入内存的时候,dl寄存器中存的是本磁盘的磁盘号,所以可以直接保存(???)。

看了这个你可可以写个引导程序试试哦~~~

学过汇编和机组的同学知道,我们老师讲的计算机8086是20根地址线,那么我们的通用寄存器和段寄存器什么的都是16位的,关于如何寻址汇编书上讲了,我想说的是:20根地址线,寻址能力是2^20=1MB,也就是说,cpu最多只能访问1MB内存,那么现在我们的计算机有的都4GB内存该怎么办呢?

计算机加电的时候其实就是按照8086的寻址方式来寻址,只能访问1MB内存,这个能访问1MB内存的状态我们称为实模式,而把能寻址更多的内存的模式称为保护模式,先看看计算机加电后能访问的这1MB内存中内容分布(来自《操作系统引导探究》 谢煜波):

很显然我们在实模式下有一部分内存是不可动的,我们能改变的只是自由内存区和引导程序加载区,比如你如果动了中断向量表区,那么调用BIOS中断将会出错。

关于中断向量表和显示内存曲读者可以参照齐志儒 高福祥《汇编语言程序设计》。

大家都知道,实模式下的内存寻址是直接在段寄存器里面设置段地址的高16位,即绝对内存的高16位,而后后面使用偏移地址定位内存,而在32位保护模式下则不行。

32位保护模式下的寻址:

在32位保护模式下cpu是通过内存分段来寻址的。首先我们来大体看一下分段的寻址:在分段机制中,将大内存分为很多个小的单位:段,段的首地址和长度是特定保存在一个索引中的,索引的首地址是特定保存的,当cpu想访问某一块内存的时候可以指明是哪个段比如说是第N个段,然后根据段的索引的首地址和N来确定是在索引中的哪个项,根据索引中的第N(这个权且当作第N项,其实是第N+1项,后面说明)保存的信息来找到特定的内存地址:

相信读者已经明白了分段了,就是用一块固定内存存储内存的段目录,将目录首地址保存,通过选择目录的第几项来选择段。那么这个在硬件是怎么实现的呢?

大体概括如下:

在Intel的计算机中是使用一个寄存器来保存段的目录的首地址:GDTR寄存器,称为全局描述符表寄存器,而那么段的目录(实际是一张表)称为全局描述符表,英文名叫GDT,用来描述全局的内存。

事实上,与全局描述符表寄存器对应的还有个局部描述符表寄存器。这里暂时不介绍。

另外,还有个寄存器用来选择使用目录里面的哪个段,这个寄存器我们称为“段选择子”。

那么先来看看第一个寄存器:GDTR,即全局描述符表寄存器:

GDTR是一个48位(6字节)寄存器,低16位用于存储段的索引长度,即全局描述符表长度,称为表限,以1字节为一单位(后面说到其实就是全局描述符的个数)。高32位用来存储描述符表的基址。具体如下(来自《操作系统引导探究》 谢煜波):

这里比如我们想设置全局描述符表的基址为0x10000000(记住这里是32位),描述符表共有0x7fff个字节长,那么,就设置GDTR为0x100000007fff即可。

这里,首先告诉你目录(即全局描述符表寄存器)里面的每个项,即每个全局描述符长为8字节。

再介绍段选择子:

段选择子也是一个寄存器,共16位,用来存储使用第几个段和这个段的部分属性。如下(来自《操作系统引导探究》 谢煜波):

这里的索引值就是指的第几个段,占这个16位寄存器的高13位,比如,我想使用第一个段,那么可以设置高13位为1,也是可以说,段的选择位只有13位,共可寻址2^13=8192个段,多了就寻址不到了,前面说过,每个描述符8个字节,那么可以知道,这个目录(全局描述符表)最大可以有8192*8=64KB。

TI是个标志,TI=0时表示此选择子是个全局描述符的选择子,为1时表示这是个局部描述符的选择子,此处可以知道,全局描述符的选择子和局部描述符的选择子其实是同一个寄存器。

RPL为特权级,共有四个特权级,最高特权级为00,表示最底层的操作。

最后来说说那个目录,即全局描述符表:

全局描述符表是由一个一个的全局描述符组成的,每个描述符8字节,共64位,这64位的作用和分布如下(来自《操作系统引导探究》 谢煜波):

这里首先来看看段限部分,段限顾名思义就是段的长度限制,也就是本描述符所描述的段最大可以有多长,从图上可以看出来,段限分为两部分,共20位,而段的长度的单位是由G标志来控制的,G=0表示长度的单位为1字节,G=1表示长度的单位为4KB。比如G=0而段限为100,那么,此段的大小为1B*100=100B,而如果G=1而段限为100,那么此段大小为4KB*100+4KB=404KB(注意,这里的段限是指向头的,需要加4KB)。

这里还可以看出来,段基址也被分为两部分,共32位基址,段的基址就是这个段在内存中的开始地址,这里需要指出的是,段的基址为此段可访问的开始地址,加上段限就是此段可访问的地址,那么如果段限为0的话此段还是可以访问开始地址的,这里不深究。

其他的位作用如下(来自《操作系统引导探究》 谢煜波):

TYPE:  表明此段的类型,4 位中的最高位被清 0 的时候表是它是数据段,相应的余下的三位,从左到右依次为 E、W、A,即数据段的 TYPE 为:0EWA。其中 E 表示向下增长位,置 1 时表示向下增长(这主要是在大小需要动态改变的堆栈段中使用,如果是向下增长的段,动态的改变段的大小限制,会让堆栈空间加到堆栈的底部。如果堆栈的大小不需要改变,那么这个段既可以是向下增长的段,也可以是非向下增长的段) ;W 表示可写位,置 1表示可写;A表示被访问位(如果 CPU访问了它,此位将会被置 1) 。

4 位中的最高位被置 1 时表示它是代码段,相应的余下的三位,从左到右依次为 C、R、A,即代码段的 TYPE 为:1CRA。其中 C 是表明此代码段是否是一致代码段,如果 C 被置1,表明此是一致代码段。一致代码段主要是用于特权级访问控制,这在以后的实验报告中会详细论述;R 表明此段是否可读,置 1 表示可读;A表示被访问位,这与前述一样。

S:为 1 时表示这是一个代码段或数据段描述符,为 0 时表示这是一个系统段描述符。

系统段描述符又称为特殊段描述符, 包括: 局部描述符表 (LDT) 描述符, 任务状态段 (TSS)描述符,调用门描述符,中断门描述符,陷阱门及任务门描述符等。

DPL:表示特权级,从 00~11,共 0,1,2,3 四个特权级

P:为 0 是表示此描述符无效,不能被使用

AVL:留给程序员随便用的

D/B:为 0 的时候表示它是一个 16 位的段,为 1时表示它是一个 32 位的段

设置这些寄存器什么的在汇编里面都有特定的伪指令对应。

介绍完分段模式,不知道你是否已经了解了呢,如果还有疑问的话请直接留言或者发送邮件到qdtecwanli@sina.com,我们大家一起学习哦~

进入保护模式:

在由实模式到保护模式的最大的问题就是内存访问的问题了,现在内存访问问题解决了,那么怎么进入实模式呢?

很明显要设置GDTR,还有打开A20地址线,一般还要初始化8259A中断控制器,最后一步就是设置CR0控制寄存器,你可能不知道我在说什么,没关系,我一个个介绍。

进入保护模式下后,段寄存器内存的不是绝对地址,而是段选择子的值,例如,我的全局描述符表的第三项是数据段,那么我想将数据段装入DS寄存器,我只需要设置段选择子的高十三位为2(从0开始)即可,比如后三位为000,那么段选择子为0000 0000 0001 0000即0x0010。现在就是

Mov ax,0x0010

Mov ds,ax

即可设置数据段寄存器。

GDTR不介绍了。

A20地址线:

(来自http://hi.baidu.com/yvoilee/blog/item/901476ee40a7a12badafd5e3.html ):

1981 年8 月,IBM 公司最初推出的个人计算机IBM PC 使用的CPU 是Intel 8088。在该微机中地址线只有20 根(A0 – A19)。在当时内存RAM 只有几百KB 或不到1MB 时,20 根地址线已足够用来寻址这些内存。所以寻址范围是2^20 = 1M,但8086/8088是16位的地址模式,即只能表示FFFFH(64K)的范围。为了能访问1M的内存采取了分段的模式。

16位段基址:16位偏移,0XFFFF:0XFFFF达到了0X10FFEF,因为8086/8088的内存不可能超过1MB,所以当时的程序超过1MB时会自动回卷至0X0FFEF。

但是到了80286地址线达到24跟。而386达到32根。芯片也达到32-bit。寻址能力达到4GB。但是为了向后兼容IBM采用了一个控制方法。使用一个开关来开启或禁止0x100000 地址比特位。由于在当时的8042键盘控制器上(注意是键盘控制器上的控制线,而不是地址线的第20根)恰好有空闲的端口引脚(输出端口P2,引脚P21),于是便使用了该引脚来作为与门控制这个地址比特位。该信号即被称为A20。如果它为零,则20-31的地址线全部被清除,从而实现了兼容性。操作系统从实模式进入保护模式之前要打开A20地址线。

所以,如果A20被禁止,可访问的内存只能是奇数段(2N+1)M,只有当A20被打开的时候才能访问连续的内存。

只有A20打开才能进入保护模式。
下面讨论一下如何打开A20地址线:
从理论上讲,打开A20 Gate的方法是通过设置8042芯片输出端口(64h)的2nd-bit,但事实上,当你向8042芯片输出端口进行写操作的时候,在键盘缓冲区中,或许还有别的数据尚未处理,因此你必须首先处理这些数据。
所以,激活A20地址线的流程为:
    1.关闭中断;
    2.等待8042 Input buffer为空;
    3.发送禁止键盘操作命令;
    4.等待8042 Input buffer为空;
    5.发送读取8042 Output Port命令;
    6.等待8042 Output buffer有数据;
    7.读取8042 Output buffer,并保存得到的字节;
    8.等待8042 Input buffer为空;
    9.发送Write 8042 Output Port命令到8042 Input buffer;
    10.等待8042 Input buffer为空;
    11.将从8042 Output Port得到的字节的第2位置1(或清0),然后写入8042 Input buffer;
    12.等待,直到8042 Input buffer为空为止;
    13.发送允许键盘操作命令到8042 Input buffer;
    14. 打开中断。

下面是完成打开A20 Gate的代码:

A20Enable:
                cli                     ;1.关闭中断
                call WaitInbufEmpty    ;2.等待8042 Input buffer为空;
                mov al, 0adh
                mov dx, 64h
                out dx, al              ;3.发送禁止键盘操作命令
                call WaitInbufEmpty    ;4.等待8042 Input buffer为空;
                mov al, 0d0h
                mov dx, 64h
                out dx, al              ;5.发送读取8042 Output Port命令;
                call WaitOutbufFull     ;6.等待8042 Output buffer有数据;
                mov dx, 60h
                in al, dx               ;7.读取8042 Output buffer
                push ax                 ;保存读取的数据
                call WaitInbufEmpty     ;8.等待8042 Input buffer为空;
                mov al, 0d1h
                mov dx, 64h
                out dx, al              ;9.发送写 8042 Output Port命令
                call WaitInbufEmpty     ;10.等待8042 Input buffer为空
                pop ax
                or al, 02h              ;11.将从8042 Output Port得到的字节的bit 1置1
                mov dx, 60h
                out dx, al              ;写入Output Port
                call WaitInbufEmpty    ;12.等待8042 Input buffer为空
                mov al, 0aeh
                mov dx, 64h
                out dx, al              ;13.发送允许键盘操作命令
                sti                     ;开中断
                ret    WaitInbufEmpty:
                mov dx, 64h
                in al, dx               ;读取Status Register
                test al, 02h
                jnz WaitInbufEmpty
                retWaitOutbufFull:
                mov dx, 64h
                in al, dx
                test al, 01             ;读取Status Register
                jz WaitOutbufFull
                ret

后来,由于感觉使用8042控制A20运行太慢了(确实,那么长的代码,中间还要若干次的wait),所以后来又出现了所谓的Fast A20,实际上,现在的大多数机器都是Fast A20,Fast A20使用92h端口控制A20,同时BIOS里提供了一个软中断来控制A20:

入口:ah=24h

al=0    关闭A20

1    打开A20

2    读取A20状态

int 15h

返回:如果BIOS支持此功能,CF=0,否则CF=1

CF=0时,AX返回当前A20状态,1=打开,0=关闭

像8042中的Output Port中的定义一样,92h端口的bit 1控制着A20,为1时打开,为0时关闭,从92h中读一个byte可以看a20的当前状态,所以对92h的操作如下:

读A20状态

mov dx, 92h

in al, dx

如果al的bit 1为1表示a20打开,否则为0

打开A20

mov dx, 92h

mov al, 02

out dx, al

关闭A20

mov dx, 92h

mov al, 0

out dx, al

8259A中断控制器:

有关8259A可以参看齐志儒、高福祥《汇编语言程序设计》第240页,特别是端口的设置,初始化等。

CR0控制寄存器:

关于控制寄存器,其实是有4个,分别为CR0~CR3,结构如下:

其中,要想开启保护模式,需要将CR0的PE位。当真正置位时,cpu才会真正运行在保护模式下。

为了配合实践,特意使用了下面引导程序来说明(语言:nasm):

boot.asm:

org 0x7c00 ;;定位到0x7c00处

jmp start

SETUPSEG equ 0x9000 ;;将setup程序读到内存的绝对地址

DATASEG equ 0x8000 ;;一般数据的保存地址

ROOT_DEV db 0 ;;启动设备号

start:

mov ax,cs

mov ds,ax

mov es,ax

mov ss,ax

mov [ROOT_DEV],dl ;;保存启动设备号

call load_msg ;;显示启动信息

mov ax,DATASEG

mov ds,ax

mov [0],dl ;;将设备号保存至0x8000:0x0000处

mov ax,cs

mov ds,ax

load_setup: ;;从磁盘的第二扇区读取1KB至0x9000:0x0000处

mov ax,SETUPSEG

mov es,ax

xor bx,bx

mov ax,0x0202

mov dl,[ROOT_DEV]

mov dh,0

mov cx,0x0002

int 0x13 ;;磁盘读取

jnc ok_load_setup

mov ax,0

mov dx,0

int 0x13 ;;磁盘复位

jmp load_setup

ok_load_setup:

jmp SETUPSEG:0x0000

load_msg:

call load_curser

mov ax,loadmessage

mov cx,18

mov bp,ax

mov ax,0x1301

mov bx,0x000c

int 0x10

ret

load_curser:

mov ah,0x03

xor bh,bh

int 0x10

ret

loadmessage db "Booting diers..."

db 13,10

times 510-($-$$) db 0 ;;保证512字节

dw 0xaa55 ;;设置引导标志

set.asm:

org 0x0000

jmp start

SETUPSEG equ 0x9000

DATASEG equ 0x8000

SETSEG equ 0x0400 ;;set程序读入0x9000:0x0400处

gdtaddr: ;;GDTR寄存器的值

dw 0x7fff

dw gdt

dw 0x0009

gdt:

gdtnull:

dw 0,0,0,0 ;;第一个描述符没用,但是需要存在

gdtsyscode: ;;第一个代码段

dw 0x07ff

dw 0x0000

dw 0x9a00

dw 0x00c0

gdtsysdata: ;;第一个数据段

dw 0x07ff

dw 0x0000

dw 0x9200

dw 0x00c0

idtaddr: ;;IDTR的值,暂时设置为空

dw 0x000

dw 0x000

dw 0x000

start:

call load_msg ;;显示信息

mov ax,DATASEG

mov ds,ax

mov dl,[0]

mov bx,SETSEG

mov ax,0x0208

mov dh,0

mov cx,0x0004

int 0x13 ;;读取set程序员

jnc ok_load_set

mov ax,0

mov dx,0

int 0x13 ;;磁盘复位

jmp start

ok_load_set:

;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;; 此处可以自由添加代码,硬件检测等

;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

call open_a20 ;;打开A20地址线

cli ;;关闭全部中断

call move_set ;;将set程序移动到0x0000:0x0000处

lgdt [gdtaddr] ;;设置GDTR的值

lidt [idtaddr] ;;设置IDTR的值

call init_8259a ;;初始化8259A

call set_cr0 ;;设置CR0的值

jmp 0x8:0x0 ;;跳到第一个代码段

load_msg:

call load_curser

mov ax,cs

mov es,ax

mov ax,loadmessage

mov cx,16

mov bp,ax

mov ax,0x1301

mov bx,0x000c

int 0x10

ret

load_curser:

mov ah,0x03

xor bh,bh

int 0x10

ret

open_a20:

mov ah,0x24

mov al,1

int 0x15

ret

move_set:

cld

mov ax,SETUPSEG

mov ds,ax

mov si,SETSEG

mov ax,0x0000

mov es,ax

xor di,di

mov cx,2048

rep movsw

ret

init_8259a:

mov al,0x11

out 0x20,al

call io_delay

out 0xa0,al

call io_delay

mov al,0x20

out 0x21,al

call io_delay

mov al,0x28

out 0xa1,al

call io_delay

mov al,0x04

out 0x21,al

call io_delay

mov al,0x02

out 0xa1,al

call io_delay

mov al,0x01

out 0x21,al

call io_delay

out 0xa1,al

call io_delay

mov al,0xff

out 0x21,al

call io_delay

out 0xa1,al

call io_delay

ret

io_delay:

mov bx,bx

mov bx,bx

mov bx,bx

ret

set_cr0:

mov eax,cr0

or eax,1

mov cr0,eax

ret

loadmessage:

db "Setup diers..."

db 13,10

times 1024-($-$$) db 0

set.asm:

[BITS 32]

org 0x0

jmp start

start:

mov ax,0x10

mov ds,ax

xor esi,esi

mov cl,'a'

mov dl,0x04

show: ;;设置显存直接设置显示字符

mov [0xb8000+esi],cl

mov [0xb8001+esi],dl

inc  dl

inc esi

inc esi

inc cl

cmp si,10000

je end_show

jmp show

end_show:

jmp $

编译为:

nasm -o boot.bin boot.asm

nasm -o setup.bin setup.asm

nasm -o set.bin set.asm

运行的时候可以使用软盘映像,你可以使用C语言创建一个1.44MB的二进制文件,里面可以直接全部写0,然后下面程序可以写入:

write.c:

#include<stdio.h>

#include<stdlib.h>

int main()

{

FILE *fp=NULL;

FILE *fp1=NULL;

char s[100];

char s1[100];

char c;

int mark=0;

long pos;

printf("please enter the name of file:");

scanf("%s",s);

fp=fopen(s,"rb");

if(NULL==fp)

{

printf("Have no such file!\n");

return 0;

}

printf("please enter the image file name:");

scanf("%s",s1);

fp1=fopen(s1,"rb+");

if(NULL==fp1)

{

printf("Have no such file!\n");

return 0;

}

printf("please input the position of the file you want to write:");

scanf("%ld",&pos);

fseek(fp1,pos,0);

while(!feof(fp))

{

if(mark)

{

fputc(c,fp1);

// printf("%x  ",c);

}

c=fgetc(fp);

mark=1;

}

c=240;

fputc(c,fp1);

c=255;

fputc(c,fp1);

fputc(c,fp1);

fclose(fp);

fclose(fp1);

printf("write ok!\n");

system("pause");

return 0;

}

程序使用bochs调试,关于bochs可以直接去百度搜,也可以直接使用虚拟机运行img文件。

编译一下:gcc write.c(在windows下使用MinGW的gcc编译)

可以使用批处理来编译等。比如我的汇编源程序保存在F:\huibian\Diers里面,而write.c保存在桌面上OS test\imagewriter里面,里面还有Diers.img软盘映像文件,里面还有文件如下:

in1.txt:

boot.bin

Diers.img

0

in2.txt:

setup.bin

Diers.img

512

in3.txt:

set.bin

Diers.img

1536

我的bochs调试文件放在桌面上OS test\bochs里面,里面还放了一个set.bat批处理文件,内容如下:

F:

cd huibian\Diers

nasm -o boot.bin boot.asm

nasm -o setup.bin setup.asm

nasm -o set.bin set.asm

xcopy boot.bin C:\Users\Administrator\Desktop"OS test"\imagewriter\boot.bin /Y

xcopy setup.bin C:\Users\Administrator\Desktop"OS test"\imagewriter\setup.bin /Y

xcopy set.bin C:\Users\Administrator\Desktop"OS test"\imagewriter\set.bin /Y

C:

cd C:\Users\Administrator\Desktop"OS test"\imagewriter

a.exe <in1.txt

a.exe <in2.txt

a.exe <in3.txt

xcopy Diers.img C:\Users\Administrator\Desktop"OS test"\bochs\Diers.img /Y

Pause

需要调试运行的时候直接双击set.bat文件,会在bochs文件夹出现Diers.img文件,使用bochs运行或者使用虚拟机运行都可。

运行效果图:

参考文献:

《操作系统引导探究》(Version 0.02) 谢煜波

《Linux内核完全注释》修正版V1.9.5 赵炯

《Linux0.11源码分析》Version0.1 潘晓雷

《自己动手写操作系统》 于渊 编著, 尤晋元 审校

《微机原理与接口技术》第2版 周明德 主编,周明德、蒋本珊 著

《汇编语言程序设计》 齐志儒、高福祥 主编

百度空间:http://hi.baidu.com/yvoilee/blog/item/901476ee40a7a12badafd5e3.html

文章更正篇:http://blog.sina.com.cn/s/blog_6730a3aa01010xrc.html

操作系统引导--从实模式到保护模式相关推荐

  1. 操作系统学习:实模式进入保护模式

    本文参考书籍 1.操作系统真相还原 2.Linux内核完全剖析:基于0.12内核 3.x86汇编语言 从实模式到保护模式 ps:基于x86硬件的pc系统 保护模式相关介绍 从实模式进入保护模式其实经历 ...

  2. x86从实模式到保护模式 pdf_【自制操作系统04】从实模式到保护模式

    通过前三章的努力,我们成功将控制权转交给了 loader.asm 这个程序.具体说就是 bios 通过加载并跳转到 0x7c00(IMB大叔们定的) 把控制权转交给了我们操作系统的第一个汇编程序 mb ...

  3. 3.操作系统——CPU的实模式、保护模式和长模式

    有实模式.保护模式.长模式 实模式16(实地址模式) 真实分为两个方面: 运行真实指令.不区分指令动作,只是直接执行指令的真实功能 发往内存的地址是真实.不加限制的. 总结来说就是,这个模式下直接往物 ...

  4. (操作系统开发)从实模式---->保护模式---->IA-32e模式( 64位模式)

    实模式和保护模式都是CPU的工作模式. 实模式与保护模式介绍 在实模式下,程序可以操作任何地址空间,而且无法限制程序的执行权限.尽管这种模式给设置硬件功能带来许多方便,但却给程序执行的安全性和稳定性带 ...

  5. 【操作系统 3.了解实模式与保护模式的区别】

    一.实模式与保护模式鸟瞰 我这人喜欢直面问题,其实本章只需要搞明白三个主要问题就行了, 什么是实模式和保护模式, 实模式与保护模式的区别是什么, 怎么进入保护模式. 我先来简单阐述下这三个问题 什么是 ...

  6. 操作系统:浅谈实模式,保护模式与长模式

    学习了操作系统的实模式.保护模式与长模式,此文作为回顾. x86 CPU 在第一次加电和每次 reset 后,都会自动进入实模式,要想进入保护模式,就需要程序员写代码实现从实模式切换到保护模式. 一. ...

  7. 【OS修炼指南目录】----《X86汇编语言-从实模式到保护模式》读书笔记目录表

    学习交流加(可免费帮忙下载CSDN资源): 个人微信: liu1126137994 学习交流资源分享qq群1(已满): 962535112 学习交流资源分享qq群2: 780902027 本文是将个人 ...

  8. Linux文件解hgc,Linux从实模式到保护模式.pdf

    Linux从实模式到保护模式 Linux 内核源码学习 (1)- 从实模式到保护模式 notishell 发布于 3 年前 在查找资料的过程发现了一份关于 linux 内核启动的课件,在这里附上.(本 ...

  9. 深入理解计算机系统-之-内存寻址(二)--存储保护机制(CPU实模式与保护模式)

    cpu的保护模式由来 分段机制 8086的诞生,标志着Intel 正式进入了x86时代,这是个多么具有纪念意义的日子:1978-6-8.同时,8086的诞生也是处理器内存寻址技术的第一次飞跃. 对于一 ...

最新文章

  1. IJCAI 2019精选论文一览,从底层到应用都有了
  2. 图像的大小计算 位深和色深
  3. AI赌神升级!无惧bluff,6人局德扑完胜世界冠军,训练只用了8天
  4. spring bean 小记
  5. Java String类型转换成Date日期类型
  6. 只用一套解决方案,就可解决80%的交通物流行业信息难题
  7. mac json工具_工具类封装的思路 | 钉钉群机器人为例
  8. Spring 事务传播原理及数据库事务操作原理
  9. BZOJ 2679 [Usaco2012 Open]Balanced Cow Subsets
  10. 跳出框架iframe的操作语句
  11. 轻松学习分布式|系列2|负载均衡算法。
  12. 深度学习之图像分类(七)--ResNet网络结构
  13. linux下addr2line详解
  14. shell之BASH_SOURCE
  15. 两条纵坐标折线图绘制
  16. 【css】i标签icon图标旋转样式
  17. 在外行人眼中的程序员
  18. 手牵手教你写 Vue 插件
  19. CSS3餐厅酒店网站模板是一款基于HTML5+CSS3实现的酒店预订模板下载。
  20. 【ArcGIS微课1000例】0055:根据图层创建自定义图例符号案例教程

热门文章

  1. hdu4115 2sat 石头剪刀布
  2. 【错误记录】Ubuntu 安装软件报错 ( Could not get lock /var/lib/dpkg/lock-frontend - open (11: Resource tempora )
  3. 【Groovy】Groovy 脚本调用 ( Java 类中调用 Groovy 脚本 )
  4. 【Android 应用开发】Activity 返回堆栈管理 ( 栈内复用模式 singleTask | 单实例模式 singleInstance )
  5. 【Android 应用开发】Android 返回堆栈管理 ( 默认启动模式 | 栈顶复用启动模式 | 栈内复用启动模式 | 单实例启动模式 | CLEAR_TOP 标识 )
  6. 基于SignalR的消息推送与二维码描登录实现
  7. .NET泛型解析(上)
  8. ODBC连接到400
  9. 使用Nginx的proxy_cache缓存功能取代Squid[原创]
  10. x86标志位符号表示(PF奇偶位)