首页 > 解决方案 > 64 位引导协议中的 Linux 引导循环

问题描述

我正在尝试为 Linux 创建一个引导加载程序作为 UEFI 应用程序。问题是在跳转到 64 位内核入口点后,QEMU 将重新启动而没有任何输出。我真的不知道发生了什么事。这是执行跳转的代码:

struct gdt {
    uint64_t padding: 48;
    uint64_t limit: 16;
    uint64_t *base;
};

__attribute__((noreturn))
static
void
start_kernel(
    uint32_t kernel,
    const struct boot_params *params,
    const struct gdt *gdt)
{
    // setup segment registers
    asm ("mov %0, %%rsi" : : "m" (params));
    asm ("mov %0, %%rbx" : : "m" (kernel));
    asm ("mov %0, %%rax" : : "m" (gdt));
    asm ("lgdt 6(%rax)");
    asm ("mov $0x18, %rax");
    asm ("mov %ax, %ds");
    asm ("mov %ax, %es");
    asm ("mov %ax, %fs");
    asm ("mov %ax, %gs");
    asm ("mov %ax, %ss");

    // jmp into the kernel
    asm ("add $0x200, %rbx");
    asm ("pushq $0x10");
    asm ("pushq %rbx");
    asm ("lretq");

    __builtin_unreachable();
}

如何params设置:

    CopyMem(&params->hdr, kernel + 0x01F1, (0x0202 + kernel[0x0201]) - 0x01F1);

    params->hdr.vid_mode = 0xFFFF; // normal
    params->hdr.type_of_loader = 0xFF;
    params->hdr.loadflags = QUIET_FLAG;
    params->hdr.ramdisk_image = (intptr_t)initrd;
    params->hdr.ramdisk_size = rdsize;

    if (params->hdr.version >= 0x0202) {
        // FIXME: ensure command_line is not above 4gb
        // FIXME: use "auto" in case of no command line in the configuration
        params->hdr.cmd_line_ptr = (intptr_t)conf->command_line;
    }

如何start_kernel被调用:

    // setup gdt
    gdt = AllocateZeroPool(sizeof(*gdt));

    if (!gdt) {
        Print(L"Failed to allocated %u bytes for GDT\n", sizeof(*gdt));
        goto fail_with_params;
    }

    gdt->limit = 8 * 4;
    gdt->base = AllocateZeroPool(gdt->limit);

    if (!gdt->base) {
        Print(L"Failed to allocated %u bytes for GDT entries\n", gdt->limit);
        goto fail_with_gdt;
    }

    gdt->base[2] = 0x00AF9A000000FFFF; // cs
    gdt->base[3] = 0x00CF92000000FFFF; // ds
    gdt->limit--;

    // terminate boot service
    map = LibMemoryMap(&count, &key, &size, &ver);

    if (!map) {
        Print(L"Failed to get system memory map\n");
        goto fail_with_gdt;
    }

    es = BS->ExitBootServices(tcg, key);

    if (EFI_ERROR(es)) {
        Print(L"Failed to terminate boot services: %r\n", es);
        goto fail_with_map;
    }

    // jump to the kernel
    start_kernel((intptr_t)kernel, params, gdt);

标签: linuxlinux-kernelx86-64bootloaderuefi

解决方案


推荐阅读