【问题标题】:What does this hvmloader.c bootloader code do?这个 hvmloader.c 引导加载程序代码有什么作用?
【发布时间】:2012-12-21 20:55:16
【问题描述】:

我阅读了xen的代码并找到了下面的代码。但我不知道它的含义。是初始化idtgdt 的代码吗?是从实模式跳转到保护模式的代码吗?如果是,gdtidt的物理地址在哪里? Hvmloader.c:

asm (
    "    .text                       \n"
    "    .globl _start               \n"
    "_start:                         \n"
    /* C runtime kickoff. */
    "    cld                         \n"
    "    cli                         \n"
    "    lgdt gdt_desr               \n"
    "    mov  $"STR(SEL_DATA32)",%ax \n"
    "    mov  %ax,%ds                \n"
    "    mov  %ax,%es                \n"
    "    mov  %ax,%fs                \n"
    "    mov  %ax,%gs                \n"
    "    mov  %ax,%ss                \n"
    "    ljmp $"STR(SEL_CODE32)",$1f \n"
    "1:  movl $stack_top,%esp        \n"
    "    movl %esp,%ebp              \n"
    "    call main                   \n"
    /* Relocate real-mode trampoline to 0x0. */
    "    mov  $trampoline_start,%esi \n"
    "    xor  %edi,%edi              \n"
    "    mov  $trampoline_end,%ecx   \n"
    "    sub  %esi,%ecx              \n"
    "    rep  movsb                  \n"
    /* Load real-mode compatible segment state (base 0x0000, limit 0xffff). */
    "    mov  $"STR(SEL_DATA16)",%ax \n"
    "    mov  %ax,%ds                \n"
    "    mov  %ax,%es                \n"
    "    mov  %ax,%fs                \n"
    "    mov  %ax,%gs                \n"
    "    mov  %ax,%ss                \n"
    /* Initialise all 32-bit GPRs to zero. */
    "    xor  %eax,%eax              \n"
    "    xor  %ebx,%ebx              \n"
    "    xor  %ecx,%ecx              \n"
    "    xor  %edx,%edx              \n"
    "    xor  %esp,%esp              \n"
    "    xor  %ebp,%ebp              \n"
    "    xor  %esi,%esi              \n"
    "    xor  %edi,%edi              \n"
    /* Enter real mode, reload all segment registers and IDT. */
    "    ljmp $"STR(SEL_CODE16)",$0x0\n"
    "trampoline_start: .code16       \n"
    "    mov  %eax,%cr0              \n"
    "    ljmp $0,$1f-trampoline_start\n"
    "1:  mov  %ax,%ds                \n"
    "    mov  %ax,%es                \n"
    "    mov  %ax,%fs                \n"
    "    mov  %ax,%gs                \n"
    "    mov  %ax,%ss                \n"
    "    lidt 1f-trampoline_start    \n"
    "    ljmp $0xf000,$0xfff0        \n"
    "1:  .word 0x3ff,0,0             \n"
    "trampoline_end:   .code32       \n"
    "                                \n"
    "gdt_desr:                       \n"
    "    .word gdt_end - gdt - 1     \n"
    "    .long gdt                   \n"
    "                                \n"
    "    .align 8                    \n"
    "gdt:                            \n"
    "    .quad 0x0000000000000000    \n"
    "    .quad 0x008f9a000000ffff    \n" /* Ring 0 16b code, base 0 limit 4G */
    "    .quad 0x008f92000000ffff    \n" /* Ring 0 16b data, base 0 limit 4G */
    "    .quad 0x00cf9a000000ffff    \n" /* Ring 0 32b code, base 0 limit 4G */
    "    .quad 0x00cf92000000ffff    \n" /* Ring 0 32b data, base 0 limit 4G */
    "    .quad 0x00af9a000000ffff    \n" /* Ring 0 64b code */
    "gdt_end:                        \n"
    "                                \n"
    "    .bss                        \n"
    "    .align    8                 \n"
    "stack:                          \n"
    "    .skip    0x4000             \n"
    "stack_top:                      \n"
    "    .text                       \n"
    );

谢谢。

【问题讨论】:

  • 在我看来,大部分工作是将 CPU 设置回实模式以跳转到 BIOS 重新启动地址(实模式内存结束前的 16 个字节 = 0xFFFF0)。真正的工作是在 main 中完成的,这被称为 down 的大约三分之一。至于其他细节,我会留给对这类东西有所了解的人。
  • 对于那些感兴趣的人,这里是来自 Xen 的包含此代码的源文件:svn.openfoundry.org/xenids/xen-4.0.0/tools/firmware/hvmloader/…

标签: assembly x86 bootloader real-mode


【解决方案1】:

从代码开始:

cld - 清除方向标志。

cli - 清除中断标志以屏蔽中断。

lgdt gdt_desr - 将gdt_desr 的值加载到gdt 中。在源代码中查找gdt_desr,找出加载到gdt的值。

"    mov  $"STR(SEL_DATA32)",%ax \n"
"    mov  %ax,%ds                \n"
"    mov  %ax,%es                \n"
"    mov  %ax,%fs                \n"
"    mov  %ax,%gs                \n"
"    mov  %ax,%ss                \n"

将值STR(SEL_DATA32) 存储到ax,然后从axdsesfsgsss(到除cs 之外的所有段寄存器) .

"    ljmp $"STR(SEL_CODE32)",$1f \n"

跳远/远跳到STR(SEL_CODE32):0x1f,实际上将cs 设置为STR(SEL_CODE32),将eip 设置为0x1f

如果这是一个 32 位代码段,处理器将进入 32 位保护模式。见Stackoverflow question: bootloader - switching processor to protected mode。但是,我在这里看不到用于设置cr0 寄存器的PE 位的代码,如上例和Wikipedia article on protected mode 中的代码。

在那行代码cs:eip 移动到这段代码中没有显示的那个地址(STR(SEL_CODE32):0x1f)之后,所以我不能说接下来会发生什么。如果cs:eip 指向那里(如果那是跳转地址),它也可能在下一行继续。不管怎样,其余的代码和 cmets 看起来就像是用来从保护模式切换回实模式的代码。

指令lidt 1f-trampoline_start1f-trampoline_start的值加载到idt中,因此要了解实际使用的值,请搜索if-trampoline_start的来源。

【讨论】:

    猜你喜欢
    • 2011-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-19
    • 1970-01-01
    • 2015-07-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多