首页
社区
课程
招聘
[原创]Linux内核基础之boot
发表于: 2020-10-3 11:18 6889

[原创]Linux内核基础之boot

2020-10-3 11:18
6889

title: Linux内核基础学习笔记
date: 2020-07-16 14:57:02
tags:
categories: kernel

1.按下电源开关,主板发送信号到电源,电源准备合适的电量,向主板发送备妥信号,启动CPU。

2.CPU启动,寄存器复位。

3.CPU此时工作在实模式,采用分段管理内存,无分页, Cache、TLB(Translation Lookup Table)、BLB(Branch Target Buffer)这三个部件的内容被清空(Invalidate)。

4.根据复位后的cs:ip此时逻辑地址为:0xffff0000:0xfff0即4GB-16字节。指向第一条代码:reset vector。此时这个地址是被映射到ROM中的。

5.reset vector包括一个FAR jump跳到BIOS的入口。

6.BIOS做初始化与检查。然后寻找引导程序。对于硬盘,找MBR

7.BIOS将控制权交给引导程序。一般采用GRUB2引导

8.引导完成,调用grub_main初始化,置于normal模式。

9.grub_normal_execute显示可用操作系统

10.操作系统选定,grub_menu_execute_entry开始执行,它将调用 GRUB 的 boot 命令,来引导被选中的操作系统。

11.bootloader完毕,交还控制权给kernel,kernel代码从以下开始执行

1.内核设置的起点是arch/x86/boot/header.S中的_start函数开始

2._start函数做一个短跳转到start_of_setup - 1f

1.main.c首先调用copy_boot_params();拷贝启动参数到boot_params.hdr通过调用:memcpy(&boot_params.hdr, &hdr, sizeof(hdr));

2.接下来进行控制台初始化console_init();使用0x10中断输出一些字符。

3.接下来做堆初始化init_heap();计算堆的位置

4.然后调用validate_cpu()检查cpu类型是否与kernel相合适,是否可以正常启动。当不满足cpu等级或一些特定的feature时不许启动

5.告诉BIOS我们的cpu模式

6.内存布局探测:detect_memory();调用detect_memory_e820();循环探测,最终信息存在e820_entries;

7.键盘初始化:keyboard_init();用0x16中断获取键盘状态。

8.一系列系统参数查询:机器型号,BIOS版本,高级电源管理等

9.set_video();设置显示模式。

10.go_to_protected_mode();进入保护模式之前最后的准备(所有的x86 CPU都是在实模式下引导,来确保传统操作系统的兼容性。为了使用保护模式的特性,要由程序主动地切换到保护模式。在现今的电脑上,这种切换通常是操作系统在引导时候完成的第一件任务。当CPU在保护模式下运行时,可以使用虚拟86模式来运行为实模式设计的代码。)

首先调用realmode_switch_hook();如果发现real_mode的hook函数,那么调用他。else的话清楚中断标志IF(禁止外部中断),然后禁止NMI中断(非可屏蔽中断比如时钟中断)。最后调用io_delay等待操作完成

然后是enable_a20()激活A20总线,之后使用reset_coprocessor();mask_all_interrupts();复位数字协处理器、屏蔽中断控制器的所有中断、和主中断控制器上除IRQ2以外的所有中断(IRQ2是主中断控制器上的级联中断,所有从中断控制器的中断将通过这个级联中断报告给 CPU )
至此,所有进入保护模式之前的准备工作已经完成,给出整体的代码

1.首先是setup_idt();用来设置中断描述符表(IDT)

lidtl将为空的null_idt载入寄存器IDT

2.接下来setup_gdt();来设置全局描述符表即GDT表,其中,定义了boot_gdt[]数组,这个数组中的内容就是我们要传给GDTR的段描述符的信息。

其中GDT_ENTRY是一个宏定义,传入三个参数(标志,基地址,段长度):

标志字段二进制展开后每一位都有自己的含义。之后获取gdt长度,以及指针,最后载入GDTR寄存器。

3.最后调用protected_mode_jump(boot_params.hdr.code32_start, (u32)&boot_params + (ds() << 4));完成从实模式到保护模式的跳转。

接受两个参数:保护模式进入地址,bootparams结构的地址。

跳转之后我们就在保护模式下执行以下代码了

1.jmpl *%eax # Jump to the 32-bit entrypoint时eax存储的是32位的入口点。

2.到达32位入口点,我们可以看到此时的目录:arch/x86/boot/compressed/head_64.S其中的compressed,因为bzimage 是由 vmlinux + 头文件 + 内核启动代码 被 gzip 压缩之后获得的。之前的属于内核启动代码。而head_64.S做内核解压前的准备。

其中HEAD代表```#define HEAD .section ".head.text","ax"```也就是说这个段是可执行的。

3.首先调用cld清空DF DF与串操作

4.通过KEEP_SEGMENTS标记来给段寄存器做正确的赋值。

5.计算我们代码和编译运行之间的位置偏差。通过:定义一个标签并且跳转到它,然后把栈顶抛出到一个寄存器中。

esi指向bootparams结构体,把结构体中scratch+4的地址放进esp制造出一个4字节临时栈。然后通过call 1f。此时1f标签的地址在栈顶,再把他pop到ebp然后ebp-1b就得到了startup_32的加载地址。

6.先找到boot_stack_end的实际地址,然后通过call verify_cpu之后test eax中的返回值,验证cpu是否支持长模式和SSE。如果不支持,就hlt掉。

7.计算内核解压缩地址,此时ebp中的是startup_32的实际物理地址,当CONFIG_RELOCATABLE打开时,我们将ebp放在ebx中,然后做对齐(2M)然后与$LOAD_PHYSICAL_ADDR(对齐后内核加载位置的物理地址)比较,最后给startup_32加上偏移获得解压缩地址。结束后,ebp包含了加载时的地址,ebx包含了内核解压缩的目标地址。

8.更新全局描述符表。全局描述符表 保存在 48位 GDTR-全局描述符表寄存器 中,由两个部分组成:

GDT基地址(32位)

gdt偏移量整体结构如下

9.打开PAE模式

10.初期页表初始化,建立初期的4G启动页表。linux内核使用4级页表,一般建立六个页表,每张表4k

其中pgtable定义如下,大小24k

开始构建4级页表

其中0x1007是四级页表的大小4096+7(页表项标记PRESENT+RW+USER)最后我们把第一个PDP(页目录指针)项地址写入PML4

11.在PDP表(页目录指针表、三级页表)建立4个2级页表(Page Directory)他们都带有PRESENT+RW+USE 标记

12.建立2048个2M页表项

最终我们拥有了一个4G表,映射了4G大小的内存。

13.最后将PML4的地址放入cr3


14.设置MSR中的EFER.LME(Extended Feature Enable Register)标记为 0xC0000080
15.切换向长模式

之后打开分页与保护模式

最后执行lret,因为startup_64已经入栈,这里就跳向了64位模式的起始位置。

至此正式从32位保护模式进入64位长模式

1.进入64位长模式后首先设置段寄存器的值,然后是计算内核编译时的位置和它被加载的位置的差(类似32位)rbp最后包含解压后内核的起始地址。rbx包含用于解压的重定位内核代码的地址。

2.设置栈指针与标志寄存器重置

3.复制压缩的内核到buffer

压缩了的代码镜像存放在这份复制了的代码(从startup_32到当前的代码)和解压了的代码之间。

最后跳转到.text解压

4.进入.text中首先清空bss节,然后调用:

进行内核的解压。

5.在解压函数中会初始化控制台,然后拿heap的位置。下一步调用:

6.choose_kernel_location分析如下:

通过调用find_random_addr(choice, output_size);查找一个随机地址。

7.返回找到满足要求的随机地址。并且验证地址合法性。然后调用decompress(input_data, input_len, NULL, NULL, output, NULL, error);进行解压,其具体实现取决于选择什么算法。

8.最后调用的两个函数是:parse_elf(output);handle_relocations(output, output_len);他们的作用是把解压后的内核移动到正确的位置。Linux内核就像是一个ELF可执行文件,我们进行原地解压,然后移动可加载段到正确的地址。

9.parse_elf(output);核心如下:

取内核的头,检查ELF签名标志。

12.解压后的内核部分定义在:arch/x86/kernel/head_64.S注意与arch/x86/boot/compressed/head_64.S是不一样的。

最终的startup_64就是__START_KERNEL;

即(不考虑kaslr):

至此:我们进入了64位长模式,内核解压与重定位完成,正式启动,进入内核!

Linux 内核揭密
Linux下的lds链接脚本详解
ELF文件格式分析
e820与kernel物理内存映射
Linux四级页表(x64)

 
 
```
IP          0xfff0
CS selector 0xf000
CS base     0xffff0000
```
```
IP          0xfff0
CS selector 0xf000
CS base     0xffff0000
```
 
 
 
 
 
 
 
 
0x1000 + X + sizeof(KernelBootSector) + 1 //X 是 kernel bootsector 被引导入内存的位置
0x1000 + X + sizeof(KernelBootSector) + 1 //X 是 kernel bootsector 被引导入内存的位置
    .globl    _start
_start:
        # Explicitly enter this as bytes, or the assembler
        # tries to generate a 3-byte jump here, which causes
        # everything else to push off to the wrong offset.
        .byte    0xeb        # short (2-byte) jump
        .byte    start_of_setup-1f
    .globl    _start
_start:
        # Explicitly enter this as bytes, or the assembler
        # tries to generate a 3-byte jump here, which causes
        # everything else to push off to the wrong offset.
        .byte    0xeb        # short (2-byte) jump
        .byte    start_of_setup-1f
    .section ".entrytext", "ax"
start_of_setup:
# Force %es = %ds
    movw    %ds, %ax
    movw    %ax, %es
    cld
 
    movw    %ss, %dx
    cmpw    %ax, %dx    # %ds == %ss?
    movw    %sp, %dx
    je    2f        # -> assume %sp is reasonably set
 
    # Invalid %ss, make up a new stack
    movw    $_end, %dx
    testb    $CAN_USE_HEAP, loadflags
    jz    1f
    movw    heap_end_ptr, %dx
1:    addw    $STACK_SIZE, %dx
    jnc    2f
    xorw    %dx, %dx    # Prevent wraparound
 
2:    # Now %dx should point to the end of our stack space
    andw    $~3, %dx    # dword align (might as well...)
    jnz    3f
    movw    $0xfffc, %dx    # Make sure we're not zero
3:    movw    %ax, %ss
    movzwl    %dx, %esp    # Clear upper half of %esp
    sti            # Now we should have a working stack
 
# We will have entered with %cs = %ds+0x20, normalize %cs so
# it is on par with the other segments.
    pushw    %ds
    pushw    $6f
    lretw
6:
 
# Check signature at end of setup
    cmpl    $0x5a5aaa55, setup_sig
    jne    setup_bad
 
# Zero the bss
    movw    $__bss_start, %di
    movw    $_end+3, %cx
    xorl    %eax, %eax
    subw    %di, %cx
    shrw    $2, %cx
    rep; stosl
 
# Jump to C code (should not return)
    calll    main
    .section ".entrytext", "ax"
start_of_setup:
# Force %es = %ds
    movw    %ds, %ax
    movw    %ax, %es
    cld
 
    movw    %ss, %dx
    cmpw    %ax, %dx    # %ds == %ss?
    movw    %sp, %dx
    je    2f        # -> assume %sp is reasonably set
 
    # Invalid %ss, make up a new stack
    movw    $_end, %dx
    testb    $CAN_USE_HEAP, loadflags
    jz    1f
    movw    heap_end_ptr, %dx
1:    addw    $STACK_SIZE, %dx
    jnc    2f
    xorw    %dx, %dx    # Prevent wraparound
 
2:    # Now %dx should point to the end of our stack space
    andw    $~3, %dx    # dword align (might as well...)
    jnz    3f
    movw    $0xfffc, %dx    # Make sure we're not zero
3:    movw    %ax, %ss
    movzwl    %dx, %esp    # Clear upper half of %esp
    sti            # Now we should have a working stack
 
# We will have entered with %cs = %ds+0x20, normalize %cs so
# it is on par with the other segments.
    pushw    %ds
    pushw    $6f
    lretw
6:
 
# Check signature at end of setup
    cmpl    $0x5a5aaa55, setup_sig
    jne    setup_bad
 
# Zero the bss
    movw    $__bss_start, %di
    movw    $_end+3, %cx
    xorl    %eax, %eax
    subw    %di, %cx
    shrw    $2, %cx
    rep; stosl
 
# Jump to C code (should not return)
    calll    main
    .globl    hdr
hdr:
setup_sects:    .byte 0            /* Filled in by build.c */
root_flags:    .word ROOT_RDONLY
syssize:    .long 0            /* Filled in by build.c */
ram_size:    .word 0            /* Obsolete */
vid_mode:    .word SVGA_MODE
root_dev:    .word 0            /* Filled in by build.c */
boot_flag:    .word 0xAA55
    .globl    hdr
hdr:
setup_sects:    .byte 0            /* Filled in by build.c */
root_flags:    .word ROOT_RDONLY
syssize:    .long 0            /* Filled in by build.c */
ram_size:    .word 0            /* Obsolete */
vid_mode:    .word SVGA_MODE
root_dev:    .word 0            /* Filled in by build.c */
boot_flag:    .word 0xAA55
 
static void init_heap(void)
{
    char *stack_end;
 
    if (boot_params.hdr.loadflags & CAN_USE_HEAP) {
        asm("leal %P1(%%esp),%0"
            : "=r" (stack_end) : "i" (-STACK_SIZE));
 
        heap_end = (char *)
            ((size_t)boot_params.hdr.heap_end_ptr + 0x200);
        if (heap_end > stack_end)
            heap_end = stack_end;
    } else {
        /* Boot protocol 2.00 only, no heap available */
        puts("WARNING: Ancient bootloader, some functionality "
             "may be limited!\n");
    }
}
static void init_heap(void)
{
    char *stack_end;
 
    if (boot_params.hdr.loadflags & CAN_USE_HEAP) {
        asm("leal %P1(%%esp),%0"
            : "=r" (stack_end) : "i" (-STACK_SIZE));
 
        heap_end = (char *)
            ((size_t)boot_params.hdr.heap_end_ptr + 0x200);
        if (heap_end > stack_end)
            heap_end = stack_end;
    } else {
        /* Boot protocol 2.00 only, no heap available */
        puts("WARNING: Ancient bootloader, some functionality "
             "may be limited!\n");
    }
}
int validate_cpu(void)
{
    u32 *err_flags;
    int cpu_level, req_level;
 
    check_cpu(&cpu_level, &req_level, &err_flags);
 
    if (cpu_level < req_level) {
        printf("This kernel requires an %s CPU, ",
               cpu_name(req_level));
        printf("but only detected an %s CPU.\n",
               cpu_name(cpu_level));
        return -1;
    }
 
    if (err_flags) {
        puts("This kernel requires the following features "
             "not present on the CPU:\n");
        show_cap_strs(err_flags);
        putchar('\n');
        return -1;
    } else if (check_knl_erratum()) {
        return -1;
    } else {
        return 0;
    }
}
int validate_cpu(void)
{
    u32 *err_flags;
    int cpu_level, req_level;
 
    check_cpu(&cpu_level, &req_level, &err_flags);
 
    if (cpu_level < req_level) {
        printf("This kernel requires an %s CPU, ",
               cpu_name(req_level));
        printf("but only detected an %s CPU.\n",
               cpu_name(cpu_level));
        return -1;
    }
 
    if (err_flags) {
        puts("This kernel requires the following features "
             "not present on the CPU:\n");
        show_cap_strs(err_flags);
        putchar('\n');
        return -1;
    } else if (check_knl_erratum()) {
        return -1;
    } else {
        return 0;
    }
}
if (test_bit(X86_FEATURE_LM, cpu.flags))
    cpu.level = 64;
if (test_bit(X86_FEATURE_LM, cpu.flags))
    cpu.level = 64;
#define X86_FEATURE_LM            ( 1*32+29) /* Long Mode (x86-64, 64-bit support) */
#define X86_FEATURE_LM            ( 1*32+29) /* Long Mode (x86-64, 64-bit support) */
/* Tell the BIOS what CPU mode we intend to run in. */
    set_bios_mode();
/* Tell the BIOS what CPU mode we intend to run in. */
    set_bios_mode();
 
 
 
 
void go_to_protected_mode(void)
{
    /* Hook before leaving real mode, also disables interrupts */
    realmode_switch_hook();
 
    /* Enable the A20 gate */
    if (enable_a20()) {
        puts("A20 gate not responding, unable to boot...\n");
        die();
    }
 
    /* Reset coprocessor (IGNNE#) */
    reset_coprocessor();
 
    /* Mask all interrupts in the PIC */
    mask_all_interrupts();
 
    /* Actual transition to protected mode... */
    setup_idt();
    setup_gdt();
    protected_mode_jump(boot_params.hdr.code32_start,
                (u32)&boot_params + (ds() << 4));
}
void go_to_protected_mode(void)
{
    /* Hook before leaving real mode, also disables interrupts */
    realmode_switch_hook();
 
    /* Enable the A20 gate */
    if (enable_a20()) {
        puts("A20 gate not responding, unable to boot...\n");
        die();
    }
 
    /* Reset coprocessor (IGNNE#) */
    reset_coprocessor();
 
    /* Mask all interrupts in the PIC */
    mask_all_interrupts();
 
    /* Actual transition to protected mode... */
    setup_idt();
    setup_gdt();
    protected_mode_jump(boot_params.hdr.code32_start,
                (u32)&boot_params + (ds() << 4));
}
static void realmode_switch_hook(void)
{
    if (boot_params.hdr.realmode_swtch) {
        asm volatile("lcallw *%0"
                 : : "m" (boot_params.hdr.realmode_swtch)
                 : "eax", "ebx", "ecx", "edx");
    } else {
        asm volatile("cli");
        outb(0x80, 0x70); /* Disable NMI */
        io_delay();
    }
}
static void realmode_switch_hook(void)
{
    if (boot_params.hdr.realmode_swtch) {
        asm volatile("lcallw *%0"
                 : : "m" (boot_params.hdr.realmode_swtch)
                 : "eax", "ebx", "ecx", "edx");
    } else {
        asm volatile("cli");
        outb(0x80, 0x70); /* Disable NMI */
        io_delay();
    }
}
void main(void)
{
    /* First, copy the boot header into the "zeropage" */
    copy_boot_params();
 
    /* Initialize the early-boot console */
    console_init();
    if (cmdline_find_option_bool("debug"))
        puts("early console in setup code\n");
 
    /* End of heap check */
    init_heap();
 
    /* Make sure we have all the proper CPU support */
    if (validate_cpu()) {
        puts("Unable to boot - please use a kernel appropriate "
             "for your CPU.\n");
        die();
    }
 
    /* Tell the BIOS what CPU mode we intend to run in. */
    set_bios_mode();
 
    /* Detect memory layout */
    detect_memory();
 
    /* Set keyboard repeat rate (why?) and query the lock flags */
    keyboard_init();
 
    /* Query Intel SpeedStep (IST) information */
    query_ist();
 
    /* Query APM information */
#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
    query_apm_bios();
#endif
 
    /* Query EDD information */
#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
    query_edd();
#endif
 
    /* Set the video mode */
    set_video();
 
    /* Do the last things and invoke protected mode */
    go_to_protected_mode();
}
void main(void)
{
    /* First, copy the boot header into the "zeropage" */
    copy_boot_params();
 
    /* Initialize the early-boot console */
    console_init();
    if (cmdline_find_option_bool("debug"))
        puts("early console in setup code\n");
 
    /* End of heap check */
    init_heap();
 
    /* Make sure we have all the proper CPU support */
    if (validate_cpu()) {
        puts("Unable to boot - please use a kernel appropriate "
             "for your CPU.\n");
        die();
    }
 
    /* Tell the BIOS what CPU mode we intend to run in. */
    set_bios_mode();
 
    /* Detect memory layout */
    detect_memory();
 
    /* Set keyboard repeat rate (why?) and query the lock flags */
    keyboard_init();
 
    /* Query Intel SpeedStep (IST) information */
    query_ist();
 
    /* Query APM information */
#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
    query_apm_bios();
#endif
 
    /* Query EDD information */
#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
    query_edd();
#endif
 
    /* Set the video mode */
    set_video();
 
    /* Do the last things and invoke protected mode */
    go_to_protected_mode();
}
/* Actual transition to protected mode... */
    setup_idt();
    setup_gdt();
    protected_mode_jump(boot_params.hdr.code32_start,
                (u32)&boot_params + (ds() << 4));
/* Actual transition to protected mode... */
    setup_idt();
    setup_gdt();
    protected_mode_jump(boot_params.hdr.code32_start,
                (u32)&boot_params + (ds() << 4));
/*
 * Set up the IDT
 */
static void setup_idt(void)
{
    static const struct gdt_ptr null_idt = {0, 0};
    asm volatile("lidtl %0" : : "m" (null_idt));
}
/*
 * Set up the IDT
 */
static void setup_idt(void)
{
    static const struct gdt_ptr null_idt = {0, 0};
    asm volatile("lidtl %0" : : "m" (null_idt));
}
 
static void setup_gdt(void)
{
    static const u64 boot_gdt[] __attribute__((aligned(16))) = {
        /* CS: code, read/execute, 4 GB, base 0 */
        [GDT_ENTRY_BOOT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff),
        /* DS: data, read/write, 4 GB, base 0 */
        [GDT_ENTRY_BOOT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff),
        /* TSS: 32-bit tss, 104 bytes, base 4096 */
        /* We only have a TSS here to keep Intel VT happy;
           we don't actually use it for anything. */
        [GDT_ENTRY_BOOT_TSS] = GDT_ENTRY(0x0089, 4096, 103),
    };
    /* Xen HVM incorrectly stores a pointer to the gdt_ptr, instead
       of the gdt_ptr contents.  Thus, make it static so it will
       stay in memory, at least long enough that we switch to the
       proper kernel GDT. */
    static struct gdt_ptr gdt;
 
    gdt.len = sizeof(boot_gdt)-1;
    gdt.ptr = (u32)&boot_gdt + (ds() << 4);
 
    asm volatile("lgdtl %0" : : "m" (gdt));
}
static void setup_gdt(void)
{
    static const u64 boot_gdt[] __attribute__((aligned(16))) = {
        /* CS: code, read/execute, 4 GB, base 0 */
        [GDT_ENTRY_BOOT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff),
        /* DS: data, read/write, 4 GB, base 0 */
        [GDT_ENTRY_BOOT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff),
        /* TSS: 32-bit tss, 104 bytes, base 4096 */
        /* We only have a TSS here to keep Intel VT happy;
           we don't actually use it for anything. */
        [GDT_ENTRY_BOOT_TSS] = GDT_ENTRY(0x0089, 4096, 103),
    };
    /* Xen HVM incorrectly stores a pointer to the gdt_ptr, instead
       of the gdt_ptr contents.  Thus, make it static so it will
       stay in memory, at least long enough that we switch to the
       proper kernel GDT. */
    static struct gdt_ptr gdt;
 
    gdt.len = sizeof(boot_gdt)-1;
    gdt.ptr = (u32)&boot_gdt + (ds() << 4);
 
    asm volatile("lgdtl %0" : : "m" (gdt));
}
#define GDT_ENTRY(flags, base, limit)            \
    ((((base)  & _AC(0xff000000,ULL)) << (56-24)) |    \
     (((flags) & _AC(0x0000f0ff,ULL)) << 40) |    \
     (((limit) & _AC(0x000f0000,ULL)) << (48-16)) |    \
     (((base)  & _AC(0x00ffffff,ULL)) << 16) |    \
     (((limit) & _AC(0x0000ffff,ULL))))
#define GDT_ENTRY(flags, base, limit)            \
    ((((base)  & _AC(0xff000000,ULL)) << (56-24)) |    \
     (((flags) & _AC(0x0000f0ff,ULL)) << 40) |    \
     (((limit) & _AC(0x000f0000,ULL)) << (48-16)) |    \
     (((base)  & _AC(0x00ffffff,ULL)) << 16) |    \
     (((limit) & _AC(0x0000ffff,ULL))))
 
/* pmjump.S */
void __attribute__((noreturn))
    protected_mode_jump(u32 entrypoint, u32 bootparams);
/* pmjump.S */
void __attribute__((noreturn))
    protected_mode_jump(u32 entrypoint, u32 bootparams);
GLOBAL(protected_mode_jump)
    movl    %edx, %esi        # bootparams地址放入esi
 
    xorl    %ebx, %ebx
    movw    %cs, %bx        # cs放入bx
    shll    $4, %ebx
    addl    %ebx, 2f
    jmp    1f            # Short jump to serialize on 386/486
1:
 
    movw    $__BOOT_DS, %cx
    movw    $__BOOT_TSS, %di
 
    movl    %cr0, %edx        #
    orb    $X86_CR0_PE, %dl    # 设置 CR0 寄存器相应的位使 CPU 进入保护模式:
    movl    %edx, %cr0
 
    # Transition to 32-bit mode
    .byte    0x66, 0xea        # ljmpl opcode
2:    .long    in_pm32            # offset
    .word    __BOOT_CS        # segment
    # 执行长跳转到代码段
ENDPROC(protected_mode_jump)
GLOBAL(protected_mode_jump)
    movl    %edx, %esi        # bootparams地址放入esi
 
    xorl    %ebx, %ebx
    movw    %cs, %bx        # cs放入bx
    shll    $4, %ebx
    addl    %ebx, 2f
    jmp    1f            # Short jump to serialize on 386/486
1:
 
    movw    $__BOOT_DS, %cx
    movw    $__BOOT_TSS, %di
 
    movl    %cr0, %edx        #
    orb    $X86_CR0_PE, %dl    # 设置 CR0 寄存器相应的位使 CPU 进入保护模式:
    movl    %edx, %cr0
 
    # Transition to 32-bit mode
    .byte    0x66, 0xea        # ljmpl opcode
2:    .long    in_pm32            # offset
    .word    __BOOT_CS        # segment
    # 执行长跳转到代码段
ENDPROC(protected_mode_jump)
    .code32
    .section ".text32","ax"
GLOBAL(in_pm32)
    # 进入32位保护模式首先重置段寄存器
    movl    %ecx, %ds
    movl    %ecx, %es
    movl    %ecx, %fs
    movl    %ecx, %gs
    movl    %ecx, %ss
    # The 32-bit code sets up its own stack, but this way we do have
    # a valid stack if some debugging hack wants to use it.
    addl    %ebx, %esp
 
    # Set up TR to make Intel VT happy
    ltr    %di
 
    # 清空通用寄存器
    # 32-bit boot protocol
    xorl    %ecx, %ecx
    xorl    %edx, %edx
    xorl    %ebx, %ebx
    xorl    %ebp, %ebp
    xorl    %edi, %edi
 
    # Set up LDTR to make Intel VT happy
    lldt    %cx
 
    jmpl    *%eax            # Jump to the 32-bit entrypoint
ENDPROC(in_pm32)
    .code32
    .section ".text32","ax"
GLOBAL(in_pm32)
    # 进入32位保护模式首先重置段寄存器
    movl    %ecx, %ds
    movl    %ecx, %es
    movl    %ecx, %fs
    movl    %ecx, %gs
    movl    %ecx, %ss

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 2
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//