Я пытаюсь упростить таблицу GDT, содержащую 6 сегментов, но в которых 2 действительно необходимы (из того, что я собираю). Я не могу заставить изменения работать.
Код взят из Cromwell, начального загрузчика Xbox. Процессор Pentium III
, Понятие пользовательского пространства отсутствует, поэтому все должно выполняться в сегментах с уровнем привилегий 0. Я хочу начать с плоской модели с одним кодом 32 и одним сегментом данных 32.
Вот соответствующий оригинальный рабочий код:
.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, чтобы иметь сегмент code32 в 0x08 и сегмент data32 в 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, 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? Все примеры в сети устанавливают эти регистры одинаковыми
Смещение сегмента. Почему здесь было сделано иначе?