Patchwork linuxboot optionrom: do not jump into loaded kernel in a big real mode

login
register
mail settings
Submitter Gleb Natapov
Date Jan. 6, 2013, 12:36 p.m.
Message ID <20130106123635.GC3440@redhat.com>
Download mbox | patch
Permalink /patch/209750/
State New
Headers show

Comments

Gleb Natapov - Jan. 6, 2013, 12:36 p.m.
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.

Signed-off-by: Gleb Natapov <gleb@redhat.com>
--
			Gleb.
Alexander Graf - Jan. 6, 2013, 12:47 p.m.
On 06.01.2013, at 13:36, Gleb Natapov wrote:

> 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.
> 
> Signed-off-by: Gleb Natapov <gleb@redhat.com>

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

> diff --git a/pc-bios/optionrom/linuxboot.S b/pc-bios/optionrom/linuxboot.S
> index 748c831..afe39a5 100644
> --- a/pc-bios/optionrom/linuxboot.S
> +++ b/pc-bios/optionrom/linuxboot.S
> @@ -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.
Gleb Natapov - Jan. 6, 2013, 12:56 p.m.
On Sun, Jan 06, 2013 at 01:47:17PM +0100, Alexander Graf wrote:
> 
> On 06.01.2013, at 13:36, Gleb Natapov wrote:
> 
> > 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.
> > 
> > Signed-off-by: Gleb Natapov <gleb@redhat.com>
> 
> I assume you tested that things still work, so the changes look ok to me.
> 
Loaded kernel with kvm and tcg using -kernel/-initrd.

> 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
OK, something like this?:


diff --git a/pc-bios/linuxboot.bin b/pc-bios/linuxboot.bin
index e7c36694f997c3c34f7f4af3c2923bd2ef6094e7..435cac4ebff3fcd83cab4bf74de11f7071ab5aa6 100644
GIT binary patch
delta 72
zcmZqRXyBNj#oWTwIZ^izW6s78X^grY3=9l?2hw%`DF%L}13f4D4!pei7sLaB|Nnu+
PBpBVlxtghlk#QmbUy&EH

delta 68
zcmZqRXyBNj#azSGI8pZyW6H)4X^g52K)|nbpyx#2ftL^ef_NbC|38qJbsj=bI={J@
NsfKa#1||;1e*hia7ytkO



> 
> > diff --git a/pc-bios/optionrom/linuxboot.S b/pc-bios/optionrom/linuxboot.S
> > index 748c831..afe39a5 100644
> > --- a/pc-bios/optionrom/linuxboot.S
> > +++ b/pc-bios/optionrom/linuxboot.S
> > @@ -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.

--
			Gleb.
Alexander Graf - Jan. 6, 2013, 12:58 p.m.
On 06.01.2013, at 13:56, Gleb Natapov wrote:

> On Sun, Jan 06, 2013 at 01:47:17PM +0100, Alexander Graf wrote:
>> 
>> On 06.01.2013, at 13:36, Gleb Natapov wrote:
>> 
>>> 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.
>>> 
>>> Signed-off-by: Gleb Natapov <gleb@redhat.com>
>> 
>> 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.

>> 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
> OK, something like this?:

Looks like a binary patch, yes :).


Alex

Patch

diff --git a/pc-bios/optionrom/linuxboot.S b/pc-bios/optionrom/linuxboot.S
index 748c831..afe39a5 100644
--- a/pc-bios/optionrom/linuxboot.S
+++ b/pc-bios/optionrom/linuxboot.S
@@ -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