ucore-lab1实验报
Lab1 实验报告
任务4:Bootloader如何准备并进入保护模式的?
打开bootasm.S文件分析其中的代码
启动CPU,转至32位保护模式;BIOS从主加载分区中物理地址为0x7c00的位置加载以下代码并开始执行实模式代码,段寄存器cs值为0,ip值为7c00。
CLI屏蔽中断;CLD使DF复位,即DF=0,串操作方向控制。
设置寄存器 ax,ds,es,ss寄存器值清0;地址线20被封锁,高于1MB的地址都默认回卷到0。
从实模式转换到保护模式,用到了全局描述符表和段表,使得虚拟地址和物理地址匹配,保证转换时有效的内存映射不改变;lgdt汇编指令把GDTR描述符表的大小和起始位置存入gdtr寄存器中;将CR0的最后一位设置为1,进入保护模式;指令跳转由代码段选择子0x8跳到protcseg的起始位置。
设置保护模式下数据段寄存器;设置堆栈寄存器并调用main函数;对GDT作处理。
任务5:通过阅读bootmait.c,了解bootloader如何加载ELF文件;分析bootloader如何读取硬盘扇区以及bootloader如何加载ELF格式的OS
打开bootmain.c文件分析其中代码
1、加载ELF文件
void
bootmain(void) {
// read the 1st page off disk
readseg((uintptr_t)ELFHDR, SECTSIZE * 8, 0); #读取第一页
// is this a valid ELF?
if (ELFHDR->e_magic != ELF_MAGIC) {
goto bad;
} #判断魔数
struct proghdr *ph, *eph;
// load each program segment (ignores ph flags)
ph = (struct proghdr *)((uintptr_t)ELFHDR + ELFHDR->e_phoff);
eph = ph + ELFHDR->e_phnum;
注:ph表示ELF段表首地址;eph表示ELF段表末地址
for (; ph < eph; ph ++) {
readseg(ph->p_va & 0xFFFFFF, ph->p_memsz, ph->p_offset);
}
注:循环读每个段
// call the entry point from the ELF header
// note: does not return
((void (*)(void))(ELFHDR->e_entry & 0xFFFFFF))();
bad: #出现问题时的处理
outw(0x8A00, 0x8A00);
outw(0x8A00, 0x8E00);
/* do nothing */
while (1);
}
2、读取硬盘分区
static void
waitdisk(void) {
while ((inb(0x1F7) & 0xC0) != 0x40)
/* do nothing */;
注:检查0x1F7的最高两位,如果是01,则跳出循环;否则等待
}
static void
readsect(void *dst, uint32_t secno) {
// wait for disk to be ready #等待磁盘准备就绪
waitdisk();
outb(0x1F2, 1); #count = 1 #读取一个扇区
outb(0x1F3, secno & 0xFF); #要读取的扇区编号
outb(0x1F4, (secno >> 8) & 0xFF); #用来存放读写柱面的低 8位字节
outb(0x1F5, (secno >> 16) & 0xFF); #用来存放读写柱面的高 2位字节 outb(0x1F6, ((secno >> 24) & 0xF) | 0xE0);#用来存放要读/写的磁盘号及磁头号
outb(0x1F7, 0x20);// cmd 0x20 - read sectors
// wait for disk to be ready
waitdisk();
// read a sector
insl(0x1F0, dst, SECTSIZE / 4); //
本文发布于:2024-02-01 18:28:14,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170678329438600.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |