diff mbox

[v2] multiboot: Fix bss segment support

Message ID 874o2bhdv5.fsf@industria.weinholt.se
State New
Headers show

Commit Message

Göran Weinholt July 24, 2011, 3:55 p.m. UTC
Multiboot images can specify a bss segment. The boot loader must clear
the memory of the bss and ensure that no modules or structures are
allocated inside it. Several fields are provided in the Multiboot
header that were previously not used properly. The header is now used
to determine how much data should be read from the image and how much
memory should be reserved to the bss segment.

Signed-off-by: Göran Weinholt <goran@weinholt.se>
---
 hw/multiboot.c |   14 +++++++++-----
 1 files changed, 9 insertions(+), 5 deletions(-)

Comments

malc July 24, 2011, 4:20 p.m. UTC | #1
On Sun, 24 Jul 2011, G?ran Weinholt wrote:

> Multiboot images can specify a bss segment. The boot loader must clear
> the memory of the bss and ensure that no modules or structures are
> allocated inside it. Several fields are provided in the Multiboot
> header that were previously not used properly. The header is now used
> to determine how much data should be read from the image and how much
> memory should be reserved to the bss segment.
> 
> Signed-off-by: G?ran Weinholt <goran@weinholt.se>
> ---
>  hw/multiboot.c |   14 +++++++++-----
>  1 files changed, 9 insertions(+), 5 deletions(-)
> 
> diff --git a/hw/multiboot.c b/hw/multiboot.c
> index 2426e84..a1d3f41 100644
> --- a/hw/multiboot.c
> +++ b/hw/multiboot.c
> @@ -198,11 +198,14 @@ int load_multiboot(void *fw_cfg,
>      } else {
>          /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
>          uint32_t mh_header_addr = ldl_p(header+i+12);
> +        uint32_t mh_load_end_addr = ldl_p(header+i+20);
> +        uint32_t mh_bss_end_addr = ldl_p(header+i+24);
>          mh_load_addr = ldl_p(header+i+16);
>          uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
> +        uint32_t mb_load_size = mh_load_end_addr - mh_load_addr;
>  
>          mh_entry_addr = ldl_p(header+i+28);
> -        mb_kernel_size = kernel_file_size - mb_kernel_text_offset;
> +        mb_kernel_size = mh_bss_end_addr - mh_load_addr;
>  
>          /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE.
>          uint32_t mh_mode_type = ldl_p(header+i+32);
> @@ -212,17 +215,18 @@ int load_multiboot(void *fw_cfg,
>  
>          mb_debug("multiboot: mh_header_addr = %#x\n", mh_header_addr);
>          mb_debug("multiboot: mh_load_addr = %#x\n", mh_load_addr);
> -        mb_debug("multiboot: mh_load_end_addr = %#x\n", ldl_p(header+i+20));
> -        mb_debug("multiboot: mh_bss_end_addr = %#x\n", ldl_p(header+i+24));
> +        mb_debug("multiboot: mh_load_end_addr = %#x\n", mh_load_end_addr);
> +        mb_debug("multiboot: mh_bss_end_addr = %#x\n", mh_bss_end_addr);
>          mb_debug("qemu: loading multiboot kernel (%#x bytes) at %#x\n",
> -                 mb_kernel_size, mh_load_addr);
> +                 mb_load_size, mh_load_addr);
>  
>          mbs.mb_buf = qemu_malloc(mb_kernel_size);
>          fseek(f, mb_kernel_text_offset, SEEK_SET);
> -        if (fread(mbs.mb_buf, 1, mb_kernel_size, f) != mb_kernel_size) {
> +        if (fread(mbs.mb_buf, 1, mb_load_size, f) != mb_load_size) {

Not that it matters, but.. you are asking to read mb_load_size records of
1 byte each, it's simple to ask for one record of mb_load_size as a bonus
check becomes != 1 thus saving 11 bytes making the earth that much
greener.

>              fprintf(stderr, "fread() failed\n");
>              exit(1);
>          }
> +        memset(mbs.mb_buf + mb_load_size, 0, mb_kernel_size - mb_load_size);
>          fclose(f);
>      }
>  
>
Anthony Liguori July 29, 2011, 2:36 p.m. UTC | #2
On 07/24/2011 10:55 AM, Göran Weinholt wrote:
> Multiboot images can specify a bss segment. The boot loader must clear
> the memory of the bss and ensure that no modules or structures are
> allocated inside it. Several fields are provided in the Multiboot
> header that were previously not used properly. The header is now used
> to determine how much data should be read from the image and how much
> memory should be reserved to the bss segment.
>
> Signed-off-by: Göran Weinholt<goran@weinholt.se>

Applied.  Thanks.

Regards,

Anthony Liguori

> ---
>   hw/multiboot.c |   14 +++++++++-----
>   1 files changed, 9 insertions(+), 5 deletions(-)
>
> diff --git a/hw/multiboot.c b/hw/multiboot.c
> index 2426e84..a1d3f41 100644
> --- a/hw/multiboot.c
> +++ b/hw/multiboot.c
> @@ -198,11 +198,14 @@ int load_multiboot(void *fw_cfg,
>       } else {
>           /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
>           uint32_t mh_header_addr = ldl_p(header+i+12);
> +        uint32_t mh_load_end_addr = ldl_p(header+i+20);
> +        uint32_t mh_bss_end_addr = ldl_p(header+i+24);
>           mh_load_addr = ldl_p(header+i+16);
>           uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
> +        uint32_t mb_load_size = mh_load_end_addr - mh_load_addr;
>
>           mh_entry_addr = ldl_p(header+i+28);
> -        mb_kernel_size = kernel_file_size - mb_kernel_text_offset;
> +        mb_kernel_size = mh_bss_end_addr - mh_load_addr;
>
>           /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE.
>           uint32_t mh_mode_type = ldl_p(header+i+32);
> @@ -212,17 +215,18 @@ int load_multiboot(void *fw_cfg,
>
>           mb_debug("multiboot: mh_header_addr = %#x\n", mh_header_addr);
>           mb_debug("multiboot: mh_load_addr = %#x\n", mh_load_addr);
> -        mb_debug("multiboot: mh_load_end_addr = %#x\n", ldl_p(header+i+20));
> -        mb_debug("multiboot: mh_bss_end_addr = %#x\n", ldl_p(header+i+24));
> +        mb_debug("multiboot: mh_load_end_addr = %#x\n", mh_load_end_addr);
> +        mb_debug("multiboot: mh_bss_end_addr = %#x\n", mh_bss_end_addr);
>           mb_debug("qemu: loading multiboot kernel (%#x bytes) at %#x\n",
> -                 mb_kernel_size, mh_load_addr);
> +                 mb_load_size, mh_load_addr);
>
>           mbs.mb_buf = qemu_malloc(mb_kernel_size);
>           fseek(f, mb_kernel_text_offset, SEEK_SET);
> -        if (fread(mbs.mb_buf, 1, mb_kernel_size, f) != mb_kernel_size) {
> +        if (fread(mbs.mb_buf, 1, mb_load_size, f) != mb_load_size) {
>               fprintf(stderr, "fread() failed\n");
>               exit(1);
>           }
> +        memset(mbs.mb_buf + mb_load_size, 0, mb_kernel_size - mb_load_size);
>           fclose(f);
>       }
>
Alexander Graf Dec. 19, 2011, 5:35 p.m. UTC | #3
On 24.07.2011, at 17:55, Göran Weinholt wrote:

> Multiboot images can specify a bss segment. The boot loader must clear
> the memory of the bss and ensure that no modules or structures are
> allocated inside it. Several fields are provided in the Multiboot
> header that were previously not used properly. The header is now used
> to determine how much data should be read from the image and how much
> memory should be reserved to the bss segment.

This patch breaks the OSX booter:

  http://people.exactcode.de/~rene/mac/boot

It now fails in fread(). Please revert this change for 1.0.1 and/or provide a timely fix.


Alex

> 
> Signed-off-by: Göran Weinholt <goran@weinholt.se>
> ---
> hw/multiboot.c |   14 +++++++++-----
> 1 files changed, 9 insertions(+), 5 deletions(-)
> 
> diff --git a/hw/multiboot.c b/hw/multiboot.c
> index 2426e84..a1d3f41 100644
> --- a/hw/multiboot.c
> +++ b/hw/multiboot.c
> @@ -198,11 +198,14 @@ int load_multiboot(void *fw_cfg,
>     } else {
>         /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
>         uint32_t mh_header_addr = ldl_p(header+i+12);
> +        uint32_t mh_load_end_addr = ldl_p(header+i+20);
> +        uint32_t mh_bss_end_addr = ldl_p(header+i+24);
>         mh_load_addr = ldl_p(header+i+16);
>         uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
> +        uint32_t mb_load_size = mh_load_end_addr - mh_load_addr;
> 
>         mh_entry_addr = ldl_p(header+i+28);
> -        mb_kernel_size = kernel_file_size - mb_kernel_text_offset;
> +        mb_kernel_size = mh_bss_end_addr - mh_load_addr;
> 
>         /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE.
>         uint32_t mh_mode_type = ldl_p(header+i+32);
> @@ -212,17 +215,18 @@ int load_multiboot(void *fw_cfg,
> 
>         mb_debug("multiboot: mh_header_addr = %#x\n", mh_header_addr);
>         mb_debug("multiboot: mh_load_addr = %#x\n", mh_load_addr);
> -        mb_debug("multiboot: mh_load_end_addr = %#x\n", ldl_p(header+i+20));
> -        mb_debug("multiboot: mh_bss_end_addr = %#x\n", ldl_p(header+i+24));
> +        mb_debug("multiboot: mh_load_end_addr = %#x\n", mh_load_end_addr);
> +        mb_debug("multiboot: mh_bss_end_addr = %#x\n", mh_bss_end_addr);
>         mb_debug("qemu: loading multiboot kernel (%#x bytes) at %#x\n",
> -                 mb_kernel_size, mh_load_addr);
> +                 mb_load_size, mh_load_addr);
> 
>         mbs.mb_buf = qemu_malloc(mb_kernel_size);
>         fseek(f, mb_kernel_text_offset, SEEK_SET);
> -        if (fread(mbs.mb_buf, 1, mb_kernel_size, f) != mb_kernel_size) {
> +        if (fread(mbs.mb_buf, 1, mb_load_size, f) != mb_load_size) {
>             fprintf(stderr, "fread() failed\n");
>             exit(1);
>         }
> +        memset(mbs.mb_buf + mb_load_size, 0, mb_kernel_size - mb_load_size);
>         fclose(f);
>     }
> 
> -- 
> 1.7.2.5
> 
>
Anthony Liguori Dec. 19, 2011, 10:01 p.m. UTC | #4
On 12/19/2011 11:35 AM, Alexander Graf wrote:
>
> On 24.07.2011, at 17:55, Göran Weinholt wrote:
>
>> Multiboot images can specify a bss segment. The boot loader must clear
>> the memory of the bss and ensure that no modules or structures are
>> allocated inside it. Several fields are provided in the Multiboot
>> header that were previously not used properly. The header is now used
>> to determine how much data should be read from the image and how much
>> memory should be reserved to the bss segment.
>
> This patch breaks the OSX booter:
>
>    http://people.exactcode.de/~rene/mac/boot

How is this licensed?  Is there source available?

>
> It now fails in fread(). Please revert this change for 1.0.1 and/or provide a timely fix.

Is the patch incorrect in some way?  I don't see how it's reasonable to expect 
someone to fix a guest that cannot be legally run under QEMU.

If the patch is obviously incorrect, I'm all for reverting it, but I don't think 
we can reasonably ask people to debug OS X guest failures since OS X is clearly 
not allowed to run under QEMU.

Regards,

Anthony Liguori

>
> Alex
>
>>
>> Signed-off-by: Göran Weinholt<goran@weinholt.se>
>> ---
>> hw/multiboot.c |   14 +++++++++-----
>> 1 files changed, 9 insertions(+), 5 deletions(-)
>>
>> diff --git a/hw/multiboot.c b/hw/multiboot.c
>> index 2426e84..a1d3f41 100644
>> --- a/hw/multiboot.c
>> +++ b/hw/multiboot.c
>> @@ -198,11 +198,14 @@ int load_multiboot(void *fw_cfg,
>>      } else {
>>          /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
>>          uint32_t mh_header_addr = ldl_p(header+i+12);
>> +        uint32_t mh_load_end_addr = ldl_p(header+i+20);
>> +        uint32_t mh_bss_end_addr = ldl_p(header+i+24);
>>          mh_load_addr = ldl_p(header+i+16);
>>          uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
>> +        uint32_t mb_load_size = mh_load_end_addr - mh_load_addr;
>>
>>          mh_entry_addr = ldl_p(header+i+28);
>> -        mb_kernel_size = kernel_file_size - mb_kernel_text_offset;
>> +        mb_kernel_size = mh_bss_end_addr - mh_load_addr;
>>
>>          /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE.
>>          uint32_t mh_mode_type = ldl_p(header+i+32);
>> @@ -212,17 +215,18 @@ int load_multiboot(void *fw_cfg,
>>
>>          mb_debug("multiboot: mh_header_addr = %#x\n", mh_header_addr);
>>          mb_debug("multiboot: mh_load_addr = %#x\n", mh_load_addr);
>> -        mb_debug("multiboot: mh_load_end_addr = %#x\n", ldl_p(header+i+20));
>> -        mb_debug("multiboot: mh_bss_end_addr = %#x\n", ldl_p(header+i+24));
>> +        mb_debug("multiboot: mh_load_end_addr = %#x\n", mh_load_end_addr);
>> +        mb_debug("multiboot: mh_bss_end_addr = %#x\n", mh_bss_end_addr);
>>          mb_debug("qemu: loading multiboot kernel (%#x bytes) at %#x\n",
>> -                 mb_kernel_size, mh_load_addr);
>> +                 mb_load_size, mh_load_addr);
>>
>>          mbs.mb_buf = qemu_malloc(mb_kernel_size);
>>          fseek(f, mb_kernel_text_offset, SEEK_SET);
>> -        if (fread(mbs.mb_buf, 1, mb_kernel_size, f) != mb_kernel_size) {
>> +        if (fread(mbs.mb_buf, 1, mb_load_size, f) != mb_load_size) {
>>              fprintf(stderr, "fread() failed\n");
>>              exit(1);
>>          }
>> +        memset(mbs.mb_buf + mb_load_size, 0, mb_kernel_size - mb_load_size);
>>          fclose(f);
>>      }
>>
>> --
>> 1.7.2.5
>>
>>
>
>
Alexander Graf Dec. 19, 2011, 10:26 p.m. UTC | #5
On 19.12.2011, at 23:01, Anthony Liguori wrote:

> On 12/19/2011 11:35 AM, Alexander Graf wrote:
>> 
>> On 24.07.2011, at 17:55, Göran Weinholt wrote:
>> 
>>> Multiboot images can specify a bss segment. The boot loader must clear
>>> the memory of the bss and ensure that no modules or structures are
>>> allocated inside it. Several fields are provided in the Multiboot
>>> header that were previously not used properly. The header is now used
>>> to determine how much data should be read from the image and how much
>>> memory should be reserved to the bss segment.
>> 
>> This patch breaks the OSX booter:
>> 
>>   http://people.exactcode.de/~rene/mac/boot
> 
> How is this licensed?  Is there source available?

Yes, it's the XNU booter, but binaries are easier to debug when it comes to reading out the bootloader info:

  http://tgwbd.org/darwin/boot.html

I don't know if the binary above is 1:1 built from those sources, but it's definitely close enough.

> 
>> 
>> It now fails in fread(). Please revert this change for 1.0.1 and/or provide a timely fix.
> 
> Is the patch incorrect in some way?  I don't see how it's reasonable to expect someone to fix a guest that cannot be legally run under QEMU.

The guest is the bootloader which is an open source multiboot binary. The fact that it bootstraps OSX is a detail. It's a kernel that worked with -kernel before and is now broken. It also works with grub. I'd go as far as guessing that there are more kernels experiencing the same breakage.

> If the patch is obviously incorrect, I'm all for reverting it, but I don't think we can reasonably ask people to debug OS X guest failures since OS X is clearly not allowed to run under QEMU.

I think we can reasonably argue that multiboot kernels (especially the one kernel this whole thing was written for) that worked before shouldn't be broken, as that's clearly a regression. And usually regressions warrant reverts IMHO.

But either way, I'd rather have this fixed. And once I'm through my pile of other patches to review and commit I'll gladly take a look at it. Until then, I'd rather have a 1.0.1 that works with what worked before, so behaves the same as 0.15 rather than a version that regresses.


Alex
diff mbox

Patch

diff --git a/hw/multiboot.c b/hw/multiboot.c
index 2426e84..a1d3f41 100644
--- a/hw/multiboot.c
+++ b/hw/multiboot.c
@@ -198,11 +198,14 @@  int load_multiboot(void *fw_cfg,
     } else {
         /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
         uint32_t mh_header_addr = ldl_p(header+i+12);
+        uint32_t mh_load_end_addr = ldl_p(header+i+20);
+        uint32_t mh_bss_end_addr = ldl_p(header+i+24);
         mh_load_addr = ldl_p(header+i+16);
         uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
+        uint32_t mb_load_size = mh_load_end_addr - mh_load_addr;
 
         mh_entry_addr = ldl_p(header+i+28);
-        mb_kernel_size = kernel_file_size - mb_kernel_text_offset;
+        mb_kernel_size = mh_bss_end_addr - mh_load_addr;
 
         /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE.
         uint32_t mh_mode_type = ldl_p(header+i+32);
@@ -212,17 +215,18 @@  int load_multiboot(void *fw_cfg,
 
         mb_debug("multiboot: mh_header_addr = %#x\n", mh_header_addr);
         mb_debug("multiboot: mh_load_addr = %#x\n", mh_load_addr);
-        mb_debug("multiboot: mh_load_end_addr = %#x\n", ldl_p(header+i+20));
-        mb_debug("multiboot: mh_bss_end_addr = %#x\n", ldl_p(header+i+24));
+        mb_debug("multiboot: mh_load_end_addr = %#x\n", mh_load_end_addr);
+        mb_debug("multiboot: mh_bss_end_addr = %#x\n", mh_bss_end_addr);
         mb_debug("qemu: loading multiboot kernel (%#x bytes) at %#x\n",
-                 mb_kernel_size, mh_load_addr);
+                 mb_load_size, mh_load_addr);
 
         mbs.mb_buf = qemu_malloc(mb_kernel_size);
         fseek(f, mb_kernel_text_offset, SEEK_SET);
-        if (fread(mbs.mb_buf, 1, mb_kernel_size, f) != mb_kernel_size) {
+        if (fread(mbs.mb_buf, 1, mb_load_size, f) != mb_load_size) {
             fprintf(stderr, "fread() failed\n");
             exit(1);
         }
+        memset(mbs.mb_buf + mb_load_size, 0, mb_kernel_size - mb_load_size);
         fclose(f);
     }