linuxboot optionrom: do not jump into loaded kernel in a big real mode
PATCH 1/1 linuxboot optionrom: do not jump into loaded kernel in a big real mode
Big real mode is fully emulated by KVM now, so if control is passed to the loaded kernel while one of the segment registers is in big real mode all the real mode part of the Linux start up is emulated. This slows boot process down. Fix that by resetting ES limit to 0xffff before jumping into the kernel.
The patch also removes unused code segment definition from GDT and changes ES register to be 16bit in protected mode since CS stays 16bit too and it is CS segment that determines effective operands and addresses length.
pc-bios/optionrom/linuxboot.S +9 -7
@@ -101,18 +101,20 @@ copy_kernel: mov $1, %eax mov %eax, %cr0 - /* So we can set ES to a 32-bit segment */ + /* So we can enlarge ES segment limit */ mov $0x10, %eax mov %eax, %es - /* We're now running in 16-bit CS, but 32-bit ES! */ - /* Load kernel and initrd */ read_fw_blob_addr32(FW_CFG_KERNEL) read_fw_blob_addr32(FW_CFG_INITRD) read_fw_blob_addr32(FW_CFG_CMDLINE) read_fw_blob_addr32(FW_CFG_SETUP) + /* Do not leave ES in big real mode */ + mov $0x08, %eax + mov %eax, %es + /* And now jump into Linux! */ mov $0, %eax mov %eax, %cr0
@@ -130,10 +132,10 @@ gdt: /* 0x00 */ .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - /* 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k) */ -.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00 + /* 0x08: data segment (base=0, limit=0xffff, type=16bit data read/write, DPL=0, 4k) */ +.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00 - /* 0x10: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k) */ -.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00 + /* 0x10: data segment (base=0, limit=0xfffff, type=16bit data read/write, DPL=0, 4k) */ +.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0x8f, 0x00 BOOT_ROM_END
--
Gleb.
Quoted 11 lines · Gleb Natapov
Big real mode is fully emulated by KVM now, so if control is passed to the loaded kernel while one of the segment registers is in big real mode all the real mode part of the Linux start up is emulated. This slows boot process down. Fix that by resetting ES limit to
0xffffbefore jumping into the kernel.The patch also removes unused code segment definition from GDT and changes ES register to be 16bit in protected mode since CS stays 16bit too and it is CS segment that determines effective operands and addresses length.
Signed-off-by Gleb Natapov <[email protected]>
I assume you tested that things still work, so the changes look ok to me.
However, this patch should also include a binary patch to pc-bios/linuxboot.bin, since linuxboot.S doesn't get compiled into the .bin form on every machine.
Alex
Quoted 45 lines
pc-bios/optionrom/linuxboot.S +5
-3@@ -101,18 +101,20 @@ copy_kernel: mov $1, %eax mov %eax, %cr0 - /* So we can set ES to a 32-bit segment */ + /* So we can enlarge ES segment limit */ mov $0x10, %eax mov %eax, %es - /* We're now running in 16-bit CS, but 32-bit ES! */ - /* Load kernel and initrd */ read_fw_blob_addr32(FW_CFG_KERNEL) read_fw_blob_addr32(FW_CFG_INITRD) read_fw_blob_addr32(FW_CFG_CMDLINE) read_fw_blob_addr32(FW_CFG_SETUP) + /* Do not leave ES in big real mode */ + mov $0x08, %eax + mov %eax, %es + /* And now jump into Linux! */ mov $0, %eax mov %eax, %cr0@@ -130,10 +132,10 @@ gdt: /* 0x00 */.byte
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00pc-bios/optionrom/linuxboot.S +4
-4- /* 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k) */ -.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00 + /* 0x08: data segment (base=0, limit=0xffff, type=16bit data read/write, DPL=0, 4k) */ +.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00 - /* 0x10: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k) */ -.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00 + /* 0x10: data segment (base=0, limit=0xfffff, type=16bit data read/write, DPL=0, 4k) */ +.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0x8f, 0x00
BOOT_ROM_END
--
Gleb.
Quoted 9 lines · Alexander Graf
Quoted 6 lines · Gleb Natapov
Big real mode is fully emulated by KVM now, so if control is passed to the loaded kernel while one of the segment registers is in big real mode all the real mode part of the Linux start up is emulated. This slows boot process down. Fix that by resetting ES limit to
0xffffbefore jumping into the kernel.
Quoted 8 lines
Quoted 5 lines
The patch also removes unused code segment definition from GDT and changes ES register to be 16bit in protected mode since CS stays 16bit too and it is CS segment that determines effective operands and addresses length.
Signed-off-by Gleb Natapov <[email protected]>I assume you tested that things still work, so the changes look ok to me.
Loaded kernel with kvm and tcg using -kernel/-initrd.
Quoted 4 lines
However, this patch should also include a binary patch to pc-bios/linuxboot.bin, since
linuxboot.Sdoesn't get compiled into the .bin form on every machine.Alex
OK, something like this?:
pc-bios/linuxboot.bin binary +0 -0
Quoted 38 lines
Quoted 38 lines
pc-bios/optionrom/linuxboot.S +5
-3@@ -101,18 +101,20 @@ copy_kernel: mov $1, %eax mov %eax, %cr0 - /* So we can set ES to a 32-bit segment */ + /* So we can enlarge ES segment limit */ mov $0x10, %eax mov %eax, %es - /* We're now running in 16-bit CS, but 32-bit ES! */ - /* Load kernel and initrd */ read_fw_blob_addr32(FW_CFG_KERNEL) read_fw_blob_addr32(FW_CFG_INITRD) read_fw_blob_addr32(FW_CFG_CMDLINE) read_fw_blob_addr32(FW_CFG_SETUP) + /* Do not leave ES in big real mode */ + mov $0x08, %eax + mov %eax, %es + /* And now jump into Linux! */ mov $0, %eax mov %eax, %cr0@@ -130,10 +132,10 @@ gdt: /* 0x00 */.byte
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00pc-bios/optionrom/linuxboot.S +2
-2- /* 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k) */ -.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00 + /* 0x08: data segment (base=0, limit=0xffff, type=16bit data read/write, DPL=0, 4k) */ +.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00
Quoted 8 lines
Quoted 8 lines
pc-bios/optionrom/linuxboot.S +2
-2- /* 0x10: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k) */ -.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00 + /* 0x10: data segment (base=0, limit=0xfffff, type=16bit data read/write, DPL=0, 4k) */ +.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0x8f, 0x00
BOOT_ROM_END
--
Gleb.
--
Gleb.
Quoted 14 lines · Gleb Natapov
Quoted 13 lines · Alexander Graf
Quoted 10 lines · Gleb Natapov
Big real mode is fully emulated by KVM now, so if control is passed to the loaded kernel while one of the segment registers is in big real mode all the real mode part of the Linux start up is emulated. This slows boot process down. Fix that by resetting ES limit to
0xffffbefore jumping into the kernel.The patch also removes unused code segment definition from GDT and changes ES register to be 16bit in protected mode since CS stays 16bit too and it is CS segment that determines effective operands and addresses length.
Quoted 5 lines
Quoted 4 lines
Quoted 1 line
Signed-off-by Gleb Natapov <[email protected]>I assume you tested that things still work, so the changes look ok to me.
Loaded kernel with kvm and tcg using -kernel/-initrd.
Good. No objections from my side then.
Quoted 5 lines
Quoted 4 lines
However, this patch should also include a binary patch to pc-bios/linuxboot.bin, since
linuxboot.Sdoesn't get compiled into the .bin form on every machine.Alex
OK, something like this?:
Looks like a binary patch, yes :).
Alex