Assembly 在x86上简化GDT有困难

Assembly 在x86上简化GDT有困难,assembly,x86,kernel,gdt,Assembly,X86,Kernel,Gdt,我试图简化一个GDT表,其中包含6个段,但其中2个段是真正必要的(根据我收集的数据)。我不能让这些改变生效 代码来自Cromwell,一个Xbox(原始)引导加载程序。CPU是奔腾III . 没有用户空间的概念,因此所有内容都应该在特权级别为0的段上运行。我想从一个带有单个code32和单个data32段的平面模型开始 以下是相关的原始工作代码: .code32 .section .text, "ax" .org 0x00 jmp start_linux .

我试图简化一个GDT表,其中包含6个段,但其中2个段是真正必要的(根据我收集的数据)。我不能让这些改变生效

代码来自Cromwell,一个Xbox(原始)引导加载程序。CPU是奔腾III . 没有用户空间的概念,因此所有内容都应该在特权级别为0的段上运行。我想从一个带有单个code32和单个data32段的平面模型开始

以下是相关的原始工作代码:

    .code32

.section .text, "ax"
     .org 0x00
     jmp    start_linux

.global Cromwellconfig
Cromwellconfig:
    .org 0x0c
    // Space for the SHA1 checksum
    .org 0x20   

    // The Value positions are fixed, do not change them, used everywhere
    .long 0x0   // 0x20 if XBE, then this bit is 0, if Cromwell mode, the bit is set to 1 by the Startuploader
    .long 0x0   // 0x24 ImageRetryLoads
    .long 0x0   // 0x28 Bank, from where Loaded
    .long 0x0   // 0x2C 0 .. Bios = 256 k, 1 .. Bios = 1MB
    .long 0x0   // 0x30 free
    .long _end_complete_rom       // 0x34 free
    .long 0x0       // 0x38 free
    .long 0x0   // free

.align 16
tableGdt:
    .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // 0x00 dummy
    .byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00 // 0x08 code32
    .byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00 // 0x10 code32
    .byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00 // 0x18 data32
    .byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0x8f, 0x00 // 0x20 code16 (8f indicates 4K granularity, ie, huge limit)
    .byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0x8f, 0x00 // 0x28 data16

tableGdtDescriptor:
    // This is the GDT header having 8 bytes
    .word tableGdtDescriptor-tableGdt  // 0x30 byte GDT
    .long GDT_LOC                      // GDT located at 0xA0000
    .word 0                            // Padding
tableGdtEnd:

.align 16
tableIdtDescriptor:

    .word 2048
    .long IDT_LOC                      // IDT located at 0xB0000
    .word 0     // fill Word, so we get aligned again

        // We are dword aligned now

.align 16        
    .globl start_linux
start_linux:

    // Make SURE the IRQs are turned off
    cli

    // kill the cache  = Disable bit 30 + 29 = CD + NW
    // CD = Cache Disable (disable = 1)
    // NW Not write through (disable = 1)
    // Protected mode enabled
    mov     $0x60010033, %eax
    mov %eax, %cr0
    wbinvd

    // Flush the TLB
    xor %eax, %eax
    mov %eax, %cr3

    // We kill the Local Descriptor Table
    xor %eax, %eax
    lldt    %ax

    // DR6/DR7: Clear the debug registers
    xor %eax, %eax
    mov %eax, %dr6
    mov %eax, %dr7
    mov %eax, %dr0
    mov %eax, %dr1
    mov %eax, %dr2
    mov %eax, %dr3


    // IMPORTANT!  Linux expects the GDT located at a specific position,
    // 0xA0000, so we have to move it there.

    // Copy the GDT to its final location
    movl $GDT_LOC, %edi
    movl $tableGdt, %esi
    movl $(tableGdtEnd-tableGdt)/4, %ecx
    // Moving (tableGdtEnd-tableGdt)/4 DWORDS from &tableGdt to &GDT_LOC
    rep movsl

    // Load the new GDT (bits0-15: Table limit, bits16-47: Base address)
    lgdt GDT_LOC+(tableGdtDescriptor-tableGdt)

    // Kill the LDT, if any
    xor %eax, %eax
    lldt %ax

    // Reload CS as 0010 from the new GDT using a far jump
    jmp $0x010, $reload_cs

reload_cs:

    // CS is now a valid entry in the GDT.  Set SS, DS, and ES to valid
    // descriptors, but clear FS and GS as they are not necessary.

    // Set SS, DS, and ES to a data32 segment with maximum limit.
    movw $0x0018, %ax
    mov %eax, %ss
    mov %eax, %ds
    mov %eax, %es

    // Clear FS and GS
    xor %eax, %eax
    mov %eax, %fs
    mov %eax, %gs
将上面代码中的跳远更改为

jmp $0x008, $reload_cs
顺便说一下,它也很好用

如您所见,保护模式在启动时启用

我想修剪GDT,使其在0x08处有一个code32段,在0x10处有一个data32段。以下是我对这一点的看法;这不起作用:

    .code32

.section .text, "ax"
     .org 0x00
     jmp    start_linux

.global Cromwellconfig
Cromwellconfig:
    .org 0x0c
    // Space for the SHA1 checksum
    .org 0x20   

    // The Value positions are fixed, do not change them, used everywhere
    .long 0x0   // 0x20 if XBE, then this bit is 0, if Cromwell mode, the bit is set to 1 by the Startuploader
    .long 0x0   // 0x24 ImageRetryLoads
    .long 0x0   // 0x28 Bank, from where Loaded
    .long 0x0   // 0x2C 0 .. Bios = 256 k, 1 .. Bios = 1MB
    .long 0x0   // 0x30 free
    .long _end_complete_rom       // 0x34 free
    .long 0x0       // 0x38 free
    .long 0x0   // free

.align 16
tableGdt:
    .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // 0x00 dummy
    .byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00 // 0x08 code32
    .byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00 // 0x10 data32

tableGdtDescriptor:
    // This is the GDT header having 8 bytes
    .word tableGdtDescriptor-tableGdt  // 0x18 byte GDT
    .long GDT_LOC                      // GDT located at 0xA0000
    .word 0                            // Padding
tableGdtEnd:

.align 16
tableIdtDescriptor:

    .word 2048
    .long IDT_LOC                      // IDT located at 0xB0000
    .word 0     // fill Word, so we get aligned again

        // We are dword aligned now

.align 16        
    .globl start_linux
start_linux:

    // Make SURE the IRQs are turned off
    cli

    // kill the cache  = Disable bit 30 + 29 = CD + NW
    // CD = Cache Disable (disable = 1)
    // NW Not write through (disable = 1)
    // Protected mode enabled
    mov     $0x60010033, %eax
    mov %eax, %cr0
    wbinvd

    // Flush the TLB
    xor %eax, %eax
    mov %eax, %cr3

    // We kill the Local Descriptor Table
    xor %eax, %eax
    lldt    %ax

    // DR6/DR7: Clear the debug registers
    xor %eax, %eax
    mov %eax, %dr6
    mov %eax, %dr7
    mov %eax, %dr0
    mov %eax, %dr1
    mov %eax, %dr2
    mov %eax, %dr3


    // IMPORTANT!  Linux expects the GDT located at a specific position,
    // 0xA0000, so we have to move it there.

    // Copy the GDT to its final location
    movl $GDT_LOC, %edi
    movl $tableGdt, %esi
    movl $(tableGdtEnd-tableGdt)/4, %ecx
    // Moving (tableGdtEnd-tableGdt)/4 DWORDS from &tableGdt to &GDT_LOC
    rep movsl

    // Load the new GDT (bits0-15: Table limit, bits16-47: Base address)
    lgdt GDT_LOC+(tableGdtDescriptor-tableGdt)

    // Kill the LDT, if any
    xor %eax, %eax
    lldt %ax

    // Reload CS as 0008 from the new GDT using a far jump
    jmp $0x008, $reload_cs

reload_cs:

    // CS is now a valid entry in the GDT.  Set SS, DS, and ES to valid
    // descriptors, but clear FS and GS as they are not necessary.

    // Set SS, DS, and ES to a data32 segment with maximum limit.
    movw $0x0010, %ax
    mov %eax, %ss
    mov %eax, %ds
    mov %eax, %es

    // Clear FS and GS
    xor %eax, %eax
    mov %eax, %fs
    mov %eax, %gs
有人能看出它为什么不起作用吗

奖金问题我自己找不到答案:

  • 首先,在“TableGDTDDescriptor:”,不应该限制值吗 (第一个单词)是表的大小-1?那么这里的值应该是多少 是否为“tableGdt描述器tableGdt-1”?如果是这样的话,为什么它在 原始代码?(我的假设是,该值为 大于47字节的值(6段-1字节)将返回到 47字节
  • 为什么“TableGDTDDescriptor”字段的末尾有填充 后面有一个强制16位对齐?看起来不是 必要的。纯粹为了良好的实践
  • 为什么FS和GS被清除,并且没有设置为与SS相同的值, DS和ES?所有联机示例都将这些寄存器设置为相同 段偏移。为什么在这里做得不同

  • 事实证明,问题在于填充IDT。我将每个IDT条目指向GDT中偏移量0x10处的代码段,因此我需要偏移量0x10处的代码段

    下面是我简化了一点的固定代码:

        .code32
    
    .section .text, "ax"
             .org 0x00
             jmp    start_linux
    
    .global Cromwellconfig
    Cromwellconfig:
        .org 0x0c
            // Space for the SHA1 checksum
            .org 0x20   
    
            // The Value positions are fixed, do not change them, used everywhere
            .long 0x0   // 0x20 if XBE, then this bit is 0, if Cromwell mode, the bit is set to 1 by the Startuploader
            .long 0x0   // 0x24 ImageRetryLoads
            .long 0x0   // 0x28 Bank, from where Loaded
            .long 0x0   // 0x2C 0 .. Bios = 256 k, 1 .. Bios = 1MB
            .long 0x0   // 0x30 free
            .long _end_complete_rom       // 0x34 free
            .long 0x0       // 0x38 free
            .long 0x0   // free
    
    .align 16
    tableGdt:
        .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // 0x00 dummy
        .byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9b, 0xcf, 0x00 // 0x08 code32
        .byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x93, 0xcf, 0x00 // 0x10 data32
    
    tableGdtDescriptor:
        // This is the GDT header having 8 bytes
        .word tableGdtDescriptor-tableGdt - 1  // Size - 1byte
        .long tableGdt                      // GDT location
        .word 0                            // Padding
    tableGdtEnd:
    
    .align 16
    tableIdtDescriptor:
    
        .word 2048
        .long IDT_LOC                      // IDT located at 0xB0000
        .word 0     // fill Word, so we get aligned again
    
            // We are dword aligned now
    
    .align 16        
        .globl start_linux
    start_linux:
    
            //Make SURE the IRQs are turned off
        cli
    
        // kill the cache  = Disable bit 30 + 29 = CD + NW
        // CD = Cache Disable (disable = 1)
        // NW Not write through (disable = 1)
           //   mov     %cr0, %eax
        //orl   $0x60000000, %eax
        mov     $0x60010033, %eax
        mov %eax, %cr0
        wbinvd
    
        // Flush the TLB
        xor %eax, %eax
        mov %eax, %cr3
    
        // We kill the Local Descriptor Table
        xor %eax, %eax
        lldt    %ax
    
        // DR6/DR7: Clear the debug registers
        xor %eax, %eax
        mov %eax, %dr6
        mov %eax, %dr7
        mov %eax, %dr0
        mov %eax, %dr1
        mov %eax, %dr2
        mov %eax, %dr3
    
        // Load the new GDT
        lgdt tableGdtDescriptor
    
        // Kill the LDT, if any
        xor %eax, %eax
        lldt %ax
    
        // Reload CS as 0008 from the new GDT using a far jump
        jmp $0x0008, $reload_cs
    
    reload_cs:
    
        // CS is now a valid entry in the GDT.  Set SS, DS, and ES to valid
        // descriptors, but clear FS and GS as they are not necessary.
    
        // Set SS, DS, and ES to a data32 segment with maximum limit.
        movw $0x0010, %ax
        mov %eax, %ss
        mov %eax, %ds
        mov %eax, %es
    
        // Clear FS and GS
        xor %eax, %eax
        mov %eax, %fs
        mov %eax, %gs
    
    上面修改的代码现在在描述符中设置正确的GDT大小(总大小减去1字节)。此外,不再在内存中的偏移量0xA0000处复制GDT。GDT寄存器现在指向GDT的原始位置


    现在,每个IDT条目都将其选择器设置为0x08,以匹配唯一的code32段位置。

    运行代码时会发生什么情况?至于次要问题,是的,大小由1字节递减,因此应该为-1(CPU显然不关心无效长度)。之所以有填充,是因为大小为2+4=6,这是一个“奇数”CS中的数字。
    fs
    gs
    可以随意使用,但如果需要符合操作系统的ABI,则需要正确设置。修改后的代码肯定会停止。我不能更具体地说,这是在缺少JTAG接口(TRST永久绑定到GND)的目标本身(Xbox控制台)上运行的。忽略GDT长度值是否是此体系结构的“正常”行为?我想这就是为什么存在空条目的原因…当选择器加载到选择器寄存器时,会检查GDT长度(未指定长度不是8的倍数的行为)。我之所以这么问是因为首先要做的是检查失败的代码是您的还是之后加载的内核(在这种情况下,您可能会通过更改GDT违反某些假设)。之后没有内核加载。代码只是继续初始化(IDT、MTRR等)在上面的ocde代码片段中提到Linux,这仅仅是因为克伦威尔基本上是一个手动选择Linux内核加载的前端。