我正在尝试简化包含 6 个段的 GDT 表,但其中 2 个段是真正必要的(根据我收集的内容)。我无法使更改生效。
代码来自克伦威尔,一个 Xbox(原始)引导加载程序。CPU 是 Pentium 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
任何人都可以发现为什么它不起作用?
我自己无法找到答案的额外问题:
- 首先,在“tableGdtDescriptor:”处,限制值(第一个单词)不应该是表格的大小 - 1 吗?那么这里的值应该是“tableGdtDescriptor-tableGdt - 1”吗?如果是这样,为什么它在原始代码中工作?(我的假设是这个值是任何超过 47 字节(6 段 - 1 字节)的值都会恢复到 47 字节。
- 如果紧接着强制 16 位对齐,为什么“tableGdtDescriptor”字段在末尾有填充?似乎没有必要。纯粹是为了好习惯?
- 为什么 FS 和 GS 被清除,而不是设置为与 SS、DS 和 ES 相同的值?所有在线示例都将这些寄存器设置为相同的段偏移量。为什么这里做的不一样?