我正在尝试简化包含 6 个段但其中 2 个确实需要的 GDT 表(从我收集的信息来看(。我无法使更改起作用。
代码来自Xbox(原始(引导加载程序Cromwell。CPU是奔腾III型 .没有用户空间的概念,因此所有内容都应在权限级别为 0 的段上运行。我想从一个具有单个代码32和单个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 处有一个代码 32 段,在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
谁能发现为什么它不起作用?
奖励问题我自己找不到答案:
- 首先,在"tableGdtDescriptor:",不应该限制值 (第一个词(是表的大小 - 1?这里的值也应该如此 是"tableGdtDescriptor-tableGdt - 1"?如果是这样,为什么它在 原始代码?(我的假设是这个值是任何 超过 47 字节(6 段 - 1 字节(的值刚刚被带回 47 字节。
- 为什么"tableGdtDescriptor"字段末尾有填充,如果 之后有强制 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 个字节(。此外,GDT 不再以内存中的偏移0xA0000复制。GDT 寄存器现在指向 GDT 的原始位置。
现在,每个 IDT 条目都将其选择器设置为 0x08 以匹配唯一的 code32 段位置。