zoukankan      html  css  js  c++  java
  • ucore操作系统实验学习笔记2

    1.实验一

    实验一主要是关注操bootloader的作用,同时练习QEMU和gdb的联合调试。

    1.1练习1

    1. 操作系统镜像ucore.img是如何一步一步生成的?
      通过分析 Makefile的指令可以看出,ucore.img 里面包含了两部分内容:第一部分是 bootloader, 这部分的大小是512bytes,这部分内容就是 bin/bootblock 文件; 主要由三个源文件文件编译链接而成:asm.h, bootasm.S, bootmain.c。第二部分是 kernel, 这部分大小是74868 bytes.这部分就是ucore的内容,主要由源文件 kern/ 下面的文件编译连接而成(分别将每个子目录下的文件生成.o文件,然后将所有.o文件使用 ld 命令链接起来形成kernel文件), 生成的二进制文件是 /bin/kernel。 ucore.img 的大小是 512 X 10000 bytes. 初始时里面全部填充为 0. 使用 dd 命令分别将 bootblock 和 kernel 这个两个文件复制进入 ucore.img 中。

    2. 一个被系统认为是符合规范的硬盘主引导扇区的特征是什么?
      首先一个主引导扇区的大小只能是512 bytes. 其次,这512字节的最后两个bytes 分别是 0x55, 0xaa。

    1.2练习2

    1. 从CPU加电后执行的第一条指令开始,单步跟踪BIOS的执行。
      BIOS是固化在系统ROM中的一段固件,早期的系统使用是的BIOS,现代计算机早已经用UEFI取代了BIOS。BIOS完成了系统硬件初始化和加载主引导扇区的功能,BIOS(UEFI)是由厂商的提供的,在系统一上电就开始执行,因此我们操作系统课程里面的编写的代码和BIOS没有关系。查阅资料可知,QEMU使用的是一个叫 seabios 的项目中的代码,可以在 github 中查看seabios 的源码: https://github.com/qemu/seabios , 同时 seabios 的项目主页上也提供调试seabios的方法: https://www.seabios.org/Debugging

    想要单步执行 seabios 的话,可以先从在一个命令行中输入:

    $qemu-system-i386 -fda ./myimage.img -S -s

    此时可以观察到qemu 启动了一个窗口,但是处于等待状态,没有任何输出。可以在另外一个终端输入:
    $gdb

    $set architecture i8086

    $target remote localhost:1234

    此时便可以在gdb中打印和查看BIOS的指令了。

    1.3练习3

    1. 为何开启A20,以及如何开启A20
      由于在保护模式下需要访问4GB的内存空间,所以需要将A20地址线enable。
      在bootasm.S 代码中,使能A20的代码段如下:
      seta20.1
      inb $0x64, %al #从port 64读取状态寄存器信息到 al
      testb $0x2, %al #测试input bufffer 是否有数据
      jnz seta20.1
      movb $0xd1, %al
      outb %al, $0x64
      seta20.2
      inb $0x64,%al
      testb $0x2, %al
      jnz seta20.2
      movb $0xdf, %al
      outb %al, $0x60

    2. 如何初始化GDT表
      建立GDT的函数如下(在 asm.h 中):

    #define SEG_ASM(type,base,lim)
    .word (((lim) >> 12) & 0xffff), ((base) & 0xffff);
    .byte (((base) >> 16) & 0xff), (0x90 | (type)),
    (0xC0 | (((lim) >> 28) & 0xf)), (((base) >> 24) & 0xff)

    在bootasm.S中调用上述函数建立GDT:

    gdt:
    SEG_NULLASM # null seg
    SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff) # code seg for bootloader and kernel
    SEG_ASM(STA_W, 0x0, 0xffffffff) # data seg for bootloader and kernel

    1. 如何使能和进入保护模式
      进入保护模式即为将CR0寄存器的 bit0 设置为 1.

    1.4练习4

    1. bootloader如何读取硬盘扇区的?
      对硬盘扇区的读取主要由 bootmain.c 文件中的2个函数实现: readsect 和 readseg
      readsect 每次读一个扇区
      readseg 则指定了要读取的字节数

    2. bootloader是如何加载ELF格式的OS?
      bootloader通过验证ELFHDR->e_magic来确认读取的是否为elf格式文件。

    1.5练习5

    1.6练习6

    1. 中断描述符表(也可简称为保护模式下的中断向量表)中一个表项占多少字节?其中哪几位代表中断处理代码的入口?
      中断描述符表(Interrupt Descriptor Table, IDT)中的每个表项占据 8-byte (according to Intel i386 programmer manual).
      根据中断描述符的定义:最低16位 和 最高的16位组成的 offset 是指向中断处理函数的地址。

    2. 请编程完善kern/trap/trap.c中对中断向量表进行初始化的函数idt_init。在idt_init函数中,依次对所有中断入口进行初始化。使用mmu.h中的SETGATE宏,填充idt数组内容。每个中断的入口由tools/vectors.c生成,使用trap.c中声明的vectors数组即可。

    extern uintptr_t __vectors[];
    int i;
    for (i = 0; i < 256; i++) {
    SETGATE(idt[i], 0, GD_KTEXT, __vectors[i], 0);

    SETGATE(idt[T_SWITCH_TOK], 0, GD_KTEXT, __vectors[T_SWITCH_TOK], 0);

    lidt(&idt_pd);

    1. 请编程完善trap.c中的中断处理函数trap,在对时钟中断进行处理的部分填写trap函数中处理时钟中断的部分,使操作系统每遇到100次时钟中断后,调用print_ticks子程序,向屏幕上打印一行文字”100 ticks”。

    只需要在函数 trap_dispatch() 中添加以下语句即可:
    ticks++;
    if (ticks % TICK_NUM == 0)
    print_ticks();

  • 相关阅读:
    MQTT TLS 加密传输
    python多进程并发redis
    各种消息队列的特点
    mqtt异步publish方法
    Numpy API Analysis
    Karma install steps for unit test of Angular JS app
    reinstall bower command
    Simulate getter in JavaScript by valueOf and toString method
    How to: Raise and Consume Events
    获取对象的类型信息 (JavaScript)
  • 原文地址:https://www.cnblogs.com/wangxiaoyong/p/12568349.html
Copyright © 2011-2022 走看看