ucore lab1 bootloader学习笔记

---恢复内容开始---

 开机流程回忆

以Intel 80386为例,计算机加电后,CPU从物理地址0xFFFFFFF0(由初始化的CS:EIP确定,此时CS和IP的值分别是0xF000和0xFFF0))开始执行。在0xFFFFFFF0这里只是存放了一条跳转指令,通过跳转指令跳到BIOS例行程序起始点。BIOS做完计算机硬件自检和初始化后,会选择一个启动设备(例如软盘、硬盘、光盘等),并且读取该设备的第一扇区(即主引导扇区或启动扇区)到内存一个特定的地址0x7c00处,然后CPU控制权会转移到那个地址继续执行。至此BIOS的初始化工作做完了,进一步的工作交给了ucore的bootloader。

简单来说,就是

加电-->CPU执行内存地址为0xFFFFFFF0的指令(一条跳转指令)--->跳到BIOS程序起始点,执行BIOS程序(功能:计算机硬件自检和初始化),自检等完成后--->选择一启动设备,并读取第一扇区(主引导扇区)到内存的0x7c00处--->BIOS所有工作完成后, CPU执行内存的0x7c00中的程序,即bootloader。

bootloader启动过程

 BIOS将通过读取硬盘主引导扇区到内存,并转跳到对应内存中的位置执行bootloader。bootloader完成的工作包括:

  • 打开A20地址线,设置CR0,切换到保护模式,启用分段机制
  • 读磁盘中ELF执行文件格式的ucore操作系统到内存
  • 显示字符串信息
  • 把控制权交给ucore操作系统

对应其工作的实现文件在lab1中的boot目录下的三个文件asm.h、bootasm.S和bootmain.c。

 代码简单分析

bootasm.S

1 .code16                                             # Assemble for 16-bit mode
2     cli                                             # Disable interrupts
3     cld                                             # String operations increment
4
5     # Set up the important data segment registers (DS, ES, SS).
6     xorw %ax, %ax                                   # Segment number zero
7     movw %ax, %ds                                   # -> Data Segment
8     movw %ax, %es                                   # -> Extra Segment
9     movw %ax, %ss                                   # -> Stack Segment

注释:.code16表示为16位的实模式,cli表示屏蔽系统中断 6-9为清空ds , es , ss 等段寄存器内容。

 1     # Enable A20:
 2     #  For backwards compatibility with the earliest PCs, physical
 3     #  address line 20 is tied low, so that addresses higher than
 4     #  1MB wrap around to zero by default. This code undoes this.
 5 seta20.1:
 6     inb $0x64, %al                                  # Wait for not busy(8042 input buffer empty).
 7     testb $0x2, %al
 8     jnz seta20.1
 9
10     movb $0xd1, %al                                 # 0xd1 -> port 0x64
11     outb %al, $0x64                                 # 0xd1 means: write data to 8042‘s P2 port
12
13 seta20.2:
14     inb $0x64, %al                                  # Wait for not busy(8042 input buffer empty).
15     testb $0x2, %al
16     jnz seta20.2
17
18     movb $0xdf, %al                                 # 0xdf -> port 0x60
19     outb %al, $0x60                                 # 0xdf = 11011111, means set P2‘s A20 bit(the 1 bit) to 1

注释: 参考“百度文库 激活A20地址线详解

1    # Switch from real to protected mode, using a bootstrap GDT
2     # and segment translation that makes virtual addresses
3     # identical to physical addresses, so that the
4     # effective memory map does not change during the switch.
5     lgdt gdtdesc
6     movl %cr0, %eax
7     orl $CR0_PE_ON, %eax
8     movl %eax, %cr0

注释:通过将CR0寄存器第一位置1,开启保护模式。

1 # Set up the stack pointer and call into C. The stack region is from 0--start(0x7c00)
2     movl $0x0, %ebp
3     movl $start, %esp
4     call bootmain

注释:跳转到bootmain.c

bootmain.c

bootloader让CPU进入保护模式后,下一步的工作就是从硬盘上加载并运行OS。考虑到实现的简单性,bootloader的访问硬盘都是LBA模式的PIO(Program IO)方式,即所有的IO操作是通过CPU访问硬盘的IO地址寄存器完成。

一般主板有2个IDE通道,每个通道可以接2个IDE硬盘。访问第一个硬盘的扇区可设置IO地址寄存器0x1f0-0x1f7实现的,具体参数见下表。一般第一个IDE通道通过访问IO地址0x1f0-0x1f7来实现,第二个IDE通道通过访问0x170-0x17f实现。每个通道的主从盘的选择通过第6个IO偏移地址寄存器来设置。

表一 磁盘IO地址和对应功能

第6位:为1=LBA模式;0 = CHS模式 第7位和第5位必须为1

IO地址 功能
0x1f0 读数据,当0x1f7不为忙状态时,可以读。
0x1f2 要读写的扇区数,每次读写前,你需要表明你要读写几个扇区。最小是1个扇区
0x1f3 如果是LBA模式,就是LBA参数的0-7位
0x1f4 如果是LBA模式,就是LBA参数的8-15位
0x1f5 如果是LBA模式,就是LBA参数的16-23位
0x1f6 第0~3位:如果是LBA模式就是24-27位 第4位:为0主盘;为1从盘
0x1f7 状态和命令寄存器。操作时先给命令,再读取,如果不是忙状态就从0x1f0端口读数据

当前 硬盘数据是储存到硬盘扇区中,一个扇区大小为512字节。读一个扇区的流程(可参看boot/bootmain.c中的readsect函数实现)大致如下:

  1. 等待磁盘准备好
  2. 发出读取扇区的命令
  3. 等待磁盘准备好
  4. 把磁盘扇区数据读到指定内存
 1 /* waitdisk - wait for disk ready */
 2 static void
 3 waitdisk(void) {
 4     while ((inb(0x1F7) & 0xC0) != 0x40)
 5         /* do nothing */;
 6 }
 7
 8 /* readsect - read a single sector at @secno into @dst */
 9 static void
10 readsect(void *dst, uint32_t secno) {
11     // wait for disk to be ready
12     waitdisk();
13
14     outb(0x1F2, 1);                         // count = 1
15     outb(0x1F3, secno & 0xFF);
16     outb(0x1F4, (secno >> 8) & 0xFF);
17     outb(0x1F5, (secno >> 16) & 0xFF);
18     outb(0x1F6, ((secno >> 24) & 0xF) | 0xE0);
19     outb(0x1F7, 0x20);                      // cmd 0x20 - read sectors
20
21     // wait for disk to be ready
22     waitdisk();
23
24     // read a sector
25     insl(0x1F0, dst, SECTSIZE / 4);
26 }

---恢复内容结束---

时间: 2024-11-03 05:25:29

ucore lab1 bootloader学习笔记的相关文章

DSP - Bootloader学习笔记2

DSP - Bootloader学习笔记2 彭会锋 1 本文主要以F2812为例进行说明的: F28027内部资源 F28027内存映射

GRUB学习笔记(转自http://www.cnblogs.com/evilzy/archive/2008/03/30/1130173.html)

grub学习笔记1 首先要了解的几个概念 1.1 启动管理器 启动管理器是存储在磁盘开始扇区中的一段程序,例如,硬盘的MBR(Master Boot Record),在系统完成启动测试后,如果系统是从MBR启动,则BIOS(Basic Input/Output System)将控制传送给MBR.然后存储在MBR中的这段程序将运行.这段程序被称为启动管理器.它的任务就是将控制传送给操作系统,完成启动过程>有许多可用的启动管理器,包括GNU GRUB (Grand Unified Boot Load

linux系统构建基础学习笔记——操作

linux系统构建 ********************************************************                  ---交叉编译环境构建--- 安装arm-linux-gcc-4.3.2 (交叉编译器) tar xzvf arm-linux-gcc-4.3.2.tgz -C /cd /usr/local/arm/4.3.2/bin./arm-linux-gcc -v在/etc/bashrc文件的最后添加如下一行:   export PATH=

linux系统构建学习笔记

嵌入式系统构架:(硬件+软件)应用软件层: Application GNU C Library(glibc)文件系统: 系统层: API(Systern Call Interface) OS Core + Power Mannager+ File Manager + GUI Mannager TCP/IP HTTP WAP DataBase Browser DDI(Device Drver Interface) 板级支持:BSP:Board Support Package       OEM A

嵌入式学习笔记201-Linux kernel动起来

在前篇博文<嵌入式学习笔记200-Linux kernel初体验>在已经确保环境编译是ok的,接下来让kernel能够最基本的动起来,起码可以看到基本的启动打印! 修改外部输入时钟频率, 修改 linux-2.6.30.4\arch\arm\mach-s3c2440\mach-smdk2440.c 在大概163行将16934400改成12000000. static void __init smdk2440_map_io(void) { s3c24xx_init_io(smdk2440_iod

linux学习笔记二:linux文件系统

各大linux的版本都遵循着FHS(Filesystem Hierarchy Standard)文件系统目录标准,是一个树形结构的组织文件.在此简要记录各目录. linux下所有文件都处在/文件下. 树形结构图: /boot:  系统启动相关的文件 主要文件 1.vmliunx:内核    2.initramfs:磁盘映像文件   3.grub(bootloader) /dev:设备文件 块设备:随机访问设备. 字符设备:线性设备,顺序访问.按字符为单位.键盘.鼠标. 设备号:主设备号(majo

嵌入式学习笔记103-uboot_1.1.6移植(3)

经过之前对uboot的整体flow分析,现在开始针对2440移植,需要注意的是移植的code可能包含支持部分的2410code 不过并没有在s3c2410板子实测过. 主要概括:第一阶段的汇编code尽量短小,能用C实现的就用C,由于2440的board和头文件是从2410 copy过来的 里面会有很多信息或者宏关于2410,并且很多.c文件的头文件由于include的是2410,所以新增的一些关于2440的结构体也会一并放在2410.h,移植的思想与前文类似, 根据code的执行流程来移植.

vector 学习笔记

vector 使用练习: /**************************************** * File Name: vector.cpp * Author: sky0917 * Created Time: 2014年04月27日 11:07:33 ****************************************/ #include <iostream> #include <vector> using namespace std; int main

Caliburn.Micro学习笔记(一)----引导类和命名匹配规则

Caliburn.Micro学习笔记(一)----引导类和命名匹配规则 用了几天时间看了一下开源框架Caliburn.Micro 这是他源码的地址http://caliburnmicro.codeplex.com/ 文档也写的很详细,自己在看它的文档和代码时写了一些demo和笔记,还有它实现的原理记录一下 学习Caliburn.Micro要有MEF和MVVM的基础 先说一下他的命名规则和引导类 以后我会把Caliburn.Micro的 Actions IResult,IHandle ICondu