Linux-0.11源代码阅读二 实模式到保护模式

bootsect部分已经执行完成,程序也跳转到setup部分:

start:

! ok, the read went well so we get current cursor position and save it for
! posterity.

	mov	ax,#INITSEG	! this is done in bootsect already, but...
	mov	ds,ax
	mov	ah,#0x03	! read cursor pos
	xor	bh,bh
	int	0x10		! save it in known place, con_init fetches
	mov	[0],dx		! it from 0x90000.

首先读取光标的位置,然后存储在内存0x90000地址处,从前面来看,bootsect部分代码存储在内存地址0x90000处,但是现在已经没有什么用了,使用了这段内存来保存一些参数(并没有开辟新的内存空间,重复利用该段内存空间)。

! Get memory size (extended mem, kB)

	mov	ah,#0x88
	int	0x15
	mov	[2],ax

然后调用int 15h中断例程获取内存大小,单位kB。

! Get video-card data:

	mov	ah,#0x0f
	int	0x10
	mov	[4],bx		! bh = display page
	mov	[6],ax		! al = video mode, ah = window width

读取显卡数据。

! check for EGA/VGA and some config parameters

	mov	ah,#0x12
	mov	bl,#0x10
	int	0x10
	mov	[8],ax
	mov	[10],bx
	mov	[12],cx

检查显示方式和获取配置参数。

! Get hd0 data

	mov	ax,#0x0000
	mov	ds,ax
	lds	si,[4*0x41]
	mov	ax,#INITSEG
	mov	es,ax
	mov	di,#0x0080
	mov	cx,#0x10
	rep
	movsb

将第一个硬盘参数表复制到内存0x90080地址处,大小16个字节,存储在0x90080地址处。

! Get hd1 data

	mov	ax,#0x0000
	mov	ds,ax
	lds	si,[4*0x46]
	mov	ax,#INITSEG
	mov	es,ax
	mov	di,#0x0090
	mov	cx,#0x10
	rep
	movsb

将第二个硬盘参数表复制到内存0x90090地址处,大小16个字节,存储在0x90090地址处。

! Check that there IS a hd1 :-)

	mov	ax,#0x01500
	mov	dl,#0x81
	int	0x13
	jc	no_disk1
	cmp	ah,#3
	je	is_disk1
no_disk1:
	mov	ax,#INITSEG
	mov	es,ax
	mov	di,#0x0090
	mov	cx,#0x10
	mov	ax,#0x00
	rep
	stosb
is_disk1:

检查是否存在第二个硬盘(hd1),如果不存在,则将0x90090地址处的硬盘参数表清零。

! now we want to move to protected mode ...

	cli			! no interrupts allowed !

即将进入保护模式下工作,首先是关闭中断。

! first we move the system to it‘s rightful place

	mov	ax,#0x0000
	cld			! ‘direction‘=0, movs moves forward
do_move:
	mov	es,ax		! destination segment
	add	ax,#0x1000
	cmp	ax,#0x9000
	jz	end_move
	mov	ds,ax		! source segment
	sub	di,di
	sub	si,si
	mov 	cx,#0x8000
	rep
	movsw
	jmp	do_move

然后是将system部分从内存0x10000地址处移动到内存0x00000处,移动大小是0x80000,即512kB大小(即system部分不能超过512kB)。

! then we load the segment descriptors

end_move:
	mov	ax,#SETUPSEG	! right, forgot this at first. didn‘t work :-)
	mov	ds,ax
	lidt	idt_48		! load idt with 0,0
	lgdt	gdt_48		! load gdt with whatever appropriate

用于加载全局描述符(GDT)表和中断描述符表(IDT)。

! that was painless, now we enable A20

        call    empty_8042
	mov     al,#0xD1                ! command write
	out     #0x64,al
	call    empty_8042
	mov     al,#0xDF                ! A20 on
	out     #0x60,al
	call    empty_8042

empty_8042子函数用于测试8042控制器输入缓冲区是否为空,只有为空的情况下才能对其进行写命令操作。

! This routine checks that the keyboard command queue is empty
! No timeout is used - if this hangs there is something wrong with
! the machine, and we probably couldn‘t proceed anyway.
empty_8042:
        .word   0x00eb,0x00eb
	in      al,#0x64        ! 8042 status port
	test    al,#2           ! is input buffer full?
	jnz     empty_8042      ! yes - loop
	ret

那么前面用于使能A20地址总线,寻址空间也就从1MB变成4GB。

! well, that went ok, I hope. Now we have to reprogram the interrupts :-(
! we put them right after the intel-reserved hardware interrupts, at
! int 0x20-0x2F. There they won‘t mess up anything. Sadly IBM really
! messed this up with the original PC, and they haven‘t been able to
! rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
! which is used for the internal hardware interrupts as well. We just
! have to reprogram the 8259‘s, and it isn‘t fun.

        mov     al,#0x11                ! initialization sequence
        out     #0x20,al                ! send it to 8259A-1
        .word   0x00eb,0x00eb           ! jmp $+2, jmp $+2
        out     #0xA0,al                ! and to 8259A-2
        .word   0x00eb,0x00eb
        mov     al,#0x20                ! start of hardware int‘s (0x20)
        out     #0x21,al
        .word   0x00eb,0x00eb
        mov     al,#0x28                ! start of hardware int‘s 2 (0x28)
        out     #0xA1,al
        .word   0x00eb,0x00eb
        mov     al,#0x04                ! 8259-1 is master
        out     #0x21,al
        .word   0x00eb,0x00eb
        mov     al,#0x02                ! 8259-2 is slave
        out     #0xA1,al
        .word   0x00eb,0x00eb
        mov     al,#0x01                ! 8086 mode for both
        out     #0x21,al
        .word   0x00eb,0x00eb
        out     #0xA1,al
        .word   0x00eb,0x00eb
        mov     al,#0xFF                ! mask off all interrupts for now
        out     #0x21,al
        .word   0x00eb,0x00eb
        out     #0xA1,al

上面这段代码用于初始化8259A中断控制器。

! well, that certainly wasn‘t fun :-(. Hopefully it works, and we don‘t
! need no steenking BIOS anyway (except for the initial loading :-).
! The BIOS-routine wants lots of unnecessary data, and it‘s less
! "interesting" anyway. This is how REAL programmers do it.
!
! Well, now‘s the time to actually move into protected mode. To make
! things as simple as possible, we do no register set-up or anything,
! we let the gnu-compiled 32-bit programs do that. We just jump to
! absolute address 0x00000, in 32-bit protected mode.

	mov     ax,#0x0001      ! protected mode (PE) bit
	lmsw    ax              ! This is it!
	jmpi    0,8             ! jmp offset 0 of segment 8 (cs)

最后真正的进入保护模式,跳转到0地址处,即system部分。

Linux-0.11源代码阅读二 实模式到保护模式

时间: 2025-01-02 09:08:54

Linux-0.11源代码阅读二 实模式到保护模式的相关文章

Linux-0.11源代码阅读一 加载操作系统

x86系列CPU可以在16位实模式和32位保护模式下运行,实模式的特点是地址总线只有20位,也就是只有1MB的寻址空间,为了兼容老的CPU,Intel x86系列CPU包括最新的CPU在上电时都运行在16位的实模式下,同时在硬件上强行将CS置成0xF000,IP置成0xFFF0,那么CS:IP就指向0xFFFF0这个地址,也就是上电瞬间代码从该处开始执行,而BIOS恰恰就存储在这个地方,可以想象一下,如果连BIOS都没有将会是一个什么结果. BIOS程序被存储在计算机主板上的一块ROM芯片里,首

Linux 0.11 中字符设备的使用

Linux 0.11 字符设备的使用 一.概述 本文自顶向下一步步探索字符设备的读写是怎么完成的.通常我们在Linux应用程序中用open.read.write对各种类型的文件进行操作.我们可以从键盘输入,然后命令行窗口会显示你的输入,有输出的话则命令行窗口会显示输出.为什么所有的设备在Linux中都被看成是一个个文件,可以通过统一的read.write直接进行读写?文件句柄与终端设备有什么关联?为什么Linux允许多个控制终端登录?tty又是什么东西?读写时将发生哪些硬件中断,驱动程序是怎么回

Linux 0.11中write实现

看了一下Linux 0.11版本write的实现,首先它在标准头文件unistd.h中有定义 int write(int fildes, const char * buf, off_t count); 接下来看write.c /* * linux/lib/write.c * * (C) 1991 Linus Torvalds */ #define __LIBRARY__ #include <unistd.h> //定义write的实现 _syscall3(int,write,int,fd,co

linux0.11 源代码阅读记录

*/--> pre.src {background-color: Black; color: White;} pre.src {background-color: Black; color: White;} pre.src {background-color: Black; color: White;} pre.src {background-color: Black; color: White;} pre.src {background-color: Black; color: White;}

Linux下的实模式和保护模式

实模式:(即实地址访问模式)它是Intel公司80286及以后的x86(80386,80486和80586等)兼容处理器(CPU)的一种操作模式.实模式被特殊定义为20位地址内存可访问空间上,这就意味着它的容量是2的20次幂(1M)的可访问内存空间(物理内存和BIOS-ROM),软件可通过这些地址直接访问BIOS程序和外围硬件.实模式下处理器没有硬件级的内存保护概念和多道任务的工作模式.但是为了向下兼容,所以80286及以后的x86系列兼容处理器仍然是开机启动时工作在实模式下.80186和早期的

Linux 0.11下信号量的实现和应用

Linux 011下信号量的实现和应用 生产者-消费者问题 实现信号量 信号量的代码实现 关于sem_wait和sem_post sem_wait和sem_post函数的代码实现 信号量的完整代码 实现信号量的系统调用 测试用的应用程序的实现 Linux 0.11下信号量的实现和应用 1.生产者-消费者问题 从一个实际的问题:生产者与消费者出发,谈一谈为什么要有信号量?信号量用来做什么? 问题描述:现在存在一个文件”.\buffer.txt”作为一个共享缓冲区,缓冲区同时最多只能保存10个数.现

Linux进程5——实模式和保护模式

早期的Inter芯片只支持1MB内存,采用实模式,采用16bit地址.后来随着技术进步,出现可以访问更多内存的 保护模式芯片,采用32bit地址.为了保持对前面芯片的兼容,Inter支持这两种模式.当芯片启动时,默认处于实模式, 然后OS控制进入保护模式. 实模式和保护模式的最大区别: 实模式下,程序地址为真实的物理地址,可以访问任意地址空间,这样不同进程可能访问到其它进程程序,造成 严重错误. 保护模式下,程序地址为虚拟地址,然后由OS系统管理内存访问权限,这样每个进程只能访问分配给自己的物理

基于 Docker 快速构建 Linux 0.11 实验环境

by Falcon of TinyLab.org 2015/05/02 简介 五分钟内搭建 Linux 0.11 的实验环境介绍了如何快速构建一个 Linux 0.11 实验环境. 本文介绍如何快速构建一个独立于宿主机的 Linux 0.11 实验环境,该实验环境可以用于任何操作系统的宿主开发机,将非常方便各类学生学习 Linux 0.11,本文只介绍 Ubuntu.在 Windows 和 Mac 下可以用 VirtualBox + Boot2Docker 来启动. 下文要求已经安装 git 和

Hadoop 2.2.0 Job源代码阅读笔记

本文所有涉及的内容均为2.2.0版本中呈现. 概述: Job在创建Job并且提交的人的眼中,可以在创建的时候通过配置Job的内容,控制Job的执行,以及查询Job的运行状态.一旦Job提交以后,将不能对其进行配置,否则将会出现IllegalStateException异常. 正常情况下用户通过Job类来创建.描述.提交Job,以及监控Job的处理过程.下面是一个简单的例子: // Create a new Job Job job = new Job(new Configuration()); j