Re: [PATCHv2] x86: EFI stub support for large memory maps

2013-09-22 Thread Linn Crosetto
On Tue, Sep 17, 2013 at 09:14:52PM +0100, Matt Fleming wrote:
> > +static efi_status_t alloc_e820ext(u32 nr_desc, struct setup_data **e820ext,
> > + u32 *e820ext_size)
> > +{
> > +   efi_status_t status;
> > +   unsigned long size;
> > +
> > +   size = sizeof(struct setup_data) +
> > +   sizeof(struct e820entry) * nr_desc;
> > +
> > +   if (*e820ext && size <= *e820ext_size)
> > +   return EFI_SUCCESS; /* Already allocated */
> 
> Do we actually need this check? I thought the 'prev_nr_desc' below
> ensures we only allocate 'e820ext' if we need more memory.

I am okay with removing the check. There is another bug in exit_boot, when
jumping to get_map the call to get the memory map is passed the previous map
size instead of the size of the allocated buffer. I'll make the changes and
resend.

> 
> [...]
> 
> > @@ -1016,6 +1157,19 @@ get_map:
> > if (status != EFI_SUCCESS)
> > goto free_mem_map;
> >  
> > +   prev_nr_desc = nr_desc;
> > +   nr_desc = size / desc_size;
> > +   if (nr_desc > prev_nr_desc &&
> > +   nr_desc > ARRAY_SIZE(boot_params->e820_map)) {
> > +   u32 nr_e820ext = nr_desc - ARRAY_SIZE(boot_params->e820_map);
> > +
> > +   status = alloc_e820ext(nr_e820ext, , _size);
> > +   if (status != EFI_SUCCESS)
> > +   goto free_mem_map;
> > +
> > +   goto get_map; /* Allocated memory, get map again */
> > +   }
> > +
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCHv2] x86: EFI stub support for large memory maps

2013-09-22 Thread Linn Crosetto
On Tue, Sep 17, 2013 at 09:14:52PM +0100, Matt Fleming wrote:
  +static efi_status_t alloc_e820ext(u32 nr_desc, struct setup_data **e820ext,
  + u32 *e820ext_size)
  +{
  +   efi_status_t status;
  +   unsigned long size;
  +
  +   size = sizeof(struct setup_data) +
  +   sizeof(struct e820entry) * nr_desc;
  +
  +   if (*e820ext  size = *e820ext_size)
  +   return EFI_SUCCESS; /* Already allocated */
 
 Do we actually need this check? I thought the 'prev_nr_desc' below
 ensures we only allocate 'e820ext' if we need more memory.

I am okay with removing the check. There is another bug in exit_boot, when
jumping to get_map the call to get the memory map is passed the previous map
size instead of the size of the allocated buffer. I'll make the changes and
resend.

 
 [...]
 
  @@ -1016,6 +1157,19 @@ get_map:
  if (status != EFI_SUCCESS)
  goto free_mem_map;
   
  +   prev_nr_desc = nr_desc;
  +   nr_desc = size / desc_size;
  +   if (nr_desc  prev_nr_desc 
  +   nr_desc  ARRAY_SIZE(boot_params-e820_map)) {
  +   u32 nr_e820ext = nr_desc - ARRAY_SIZE(boot_params-e820_map);
  +
  +   status = alloc_e820ext(nr_e820ext, e820ext, e820ext_size);
  +   if (status != EFI_SUCCESS)
  +   goto free_mem_map;
  +
  +   goto get_map; /* Allocated memory, get map again */
  +   }
  +
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCHv2] x86: EFI stub support for large memory maps

2013-09-17 Thread Matt Fleming
On Fri, 06 Sep, at 11:04:16AM, Linn Crosetto wrote:
> This patch fixes a problem with EFI memory maps larger than 128 entries
> when booting using the EFI stub, which results in overflowing e820_map
> in boot_params and an eventual halt when checking the map size in
> sanitize_e820_map().
> 
> If the number of map entries is greater than what can fit in e820_map,
> add the extra entries to the setup_data list using type SETUP_E820_EXT.
> These extra entries are then picked up when the setup_data list is
> parsed in parse_e820_ext().
> 
> Signed-off-by: Linn Crosetto 
> ---
> Changes in v2:
> * Free memory when error is returned from alloc_e820ext() as suggested by Matt
>   Fleming
> * Set pointer to NULL and size to 0 after freeing memory in alloc_e820ext()
> 
>  arch/x86/boot/compressed/eboot.c | 223 
> ---
>  1 file changed, 160 insertions(+), 63 deletions(-)

[...]

> +static efi_status_t alloc_e820ext(u32 nr_desc, struct setup_data **e820ext,
> +   u32 *e820ext_size)
> +{
> + efi_status_t status;
> + unsigned long size;
> +
> + size = sizeof(struct setup_data) +
> + sizeof(struct e820entry) * nr_desc;
> +
> + if (*e820ext && size <= *e820ext_size)
> + return EFI_SUCCESS; /* Already allocated */

Do we actually need this check? I thought the 'prev_nr_desc' below
ensures we only allocate 'e820ext' if we need more memory.

[...]

> @@ -1016,6 +1157,19 @@ get_map:
>   if (status != EFI_SUCCESS)
>   goto free_mem_map;
>  
> + prev_nr_desc = nr_desc;
> + nr_desc = size / desc_size;
> + if (nr_desc > prev_nr_desc &&
> + nr_desc > ARRAY_SIZE(boot_params->e820_map)) {
> + u32 nr_e820ext = nr_desc - ARRAY_SIZE(boot_params->e820_map);
> +
> + status = alloc_e820ext(nr_e820ext, , _size);
> + if (status != EFI_SUCCESS)
> + goto free_mem_map;
> +
> + goto get_map; /* Allocated memory, get map again */
> + }
> +

-- 
Matt Fleming, Intel Open Source Technology Center
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCHv2] x86: EFI stub support for large memory maps

2013-09-17 Thread Matt Fleming
On Fri, 06 Sep, at 11:04:16AM, Linn Crosetto wrote:
 This patch fixes a problem with EFI memory maps larger than 128 entries
 when booting using the EFI stub, which results in overflowing e820_map
 in boot_params and an eventual halt when checking the map size in
 sanitize_e820_map().
 
 If the number of map entries is greater than what can fit in e820_map,
 add the extra entries to the setup_data list using type SETUP_E820_EXT.
 These extra entries are then picked up when the setup_data list is
 parsed in parse_e820_ext().
 
 Signed-off-by: Linn Crosetto l...@hp.com
 ---
 Changes in v2:
 * Free memory when error is returned from alloc_e820ext() as suggested by Matt
   Fleming
 * Set pointer to NULL and size to 0 after freeing memory in alloc_e820ext()
 
  arch/x86/boot/compressed/eboot.c | 223 
 ---
  1 file changed, 160 insertions(+), 63 deletions(-)

[...]

 +static efi_status_t alloc_e820ext(u32 nr_desc, struct setup_data **e820ext,
 +   u32 *e820ext_size)
 +{
 + efi_status_t status;
 + unsigned long size;
 +
 + size = sizeof(struct setup_data) +
 + sizeof(struct e820entry) * nr_desc;
 +
 + if (*e820ext  size = *e820ext_size)
 + return EFI_SUCCESS; /* Already allocated */

Do we actually need this check? I thought the 'prev_nr_desc' below
ensures we only allocate 'e820ext' if we need more memory.

[...]

 @@ -1016,6 +1157,19 @@ get_map:
   if (status != EFI_SUCCESS)
   goto free_mem_map;
  
 + prev_nr_desc = nr_desc;
 + nr_desc = size / desc_size;
 + if (nr_desc  prev_nr_desc 
 + nr_desc  ARRAY_SIZE(boot_params-e820_map)) {
 + u32 nr_e820ext = nr_desc - ARRAY_SIZE(boot_params-e820_map);
 +
 + status = alloc_e820ext(nr_e820ext, e820ext, e820ext_size);
 + if (status != EFI_SUCCESS)
 + goto free_mem_map;
 +
 + goto get_map; /* Allocated memory, get map again */
 + }
 +

-- 
Matt Fleming, Intel Open Source Technology Center
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCHv2] x86: EFI stub support for large memory maps

2013-09-06 Thread Linn Crosetto
This patch fixes a problem with EFI memory maps larger than 128 entries
when booting using the EFI stub, which results in overflowing e820_map
in boot_params and an eventual halt when checking the map size in
sanitize_e820_map().

If the number of map entries is greater than what can fit in e820_map,
add the extra entries to the setup_data list using type SETUP_E820_EXT.
These extra entries are then picked up when the setup_data list is
parsed in parse_e820_ext().

Signed-off-by: Linn Crosetto 
---
Changes in v2:
* Free memory when error is returned from alloc_e820ext() as suggested by Matt
  Fleming
* Set pointer to NULL and size to 0 after freeing memory in alloc_e820ext()

 arch/x86/boot/compressed/eboot.c | 223 ---
 1 file changed, 160 insertions(+), 63 deletions(-)

diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index b7388a4..2ac395e 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -982,20 +982,161 @@ fail:
return NULL;
 }
 
+static void add_e820ext(struct boot_params *params,
+   struct setup_data *e820ext, u32 nr_entries)
+{
+   struct setup_data *data;
+   efi_status_t status;
+   unsigned long size;
+
+   e820ext->type = SETUP_E820_EXT;
+   e820ext->len = nr_entries * sizeof(struct e820entry);
+   e820ext->next = 0;
+
+   data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
+
+   while (data && data->next)
+   data = (struct setup_data *)(unsigned long)data->next;
+
+   if (data)
+   data->next = (unsigned long)e820ext;
+   else
+   params->hdr.setup_data = (unsigned long)e820ext;
+}
+
+static efi_status_t setup_e820(struct boot_params *params,
+  struct setup_data *e820ext, u32 e820ext_size)
+{
+   struct e820entry *e820_map = >e820_map[0];
+   struct efi_info *efi = >efi_info;
+   struct e820entry *prev = NULL;
+   u32 nr_entries;
+   u32 nr_desc;
+   int i;
+
+   nr_entries = 0;
+   nr_desc = efi->efi_memmap_size / efi->efi_memdesc_size;
+
+   for (i = 0; i < nr_desc; i++) {
+   efi_memory_desc_t *d;
+   unsigned int e820_type = 0;
+   unsigned long m = efi->efi_memmap;
+
+   d = (efi_memory_desc_t *)(m + (i * efi->efi_memdesc_size));
+   switch (d->type) {
+   case EFI_RESERVED_TYPE:
+   case EFI_RUNTIME_SERVICES_CODE:
+   case EFI_RUNTIME_SERVICES_DATA:
+   case EFI_MEMORY_MAPPED_IO:
+   case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
+   case EFI_PAL_CODE:
+   e820_type = E820_RESERVED;
+   break;
+
+   case EFI_UNUSABLE_MEMORY:
+   e820_type = E820_UNUSABLE;
+   break;
+
+   case EFI_ACPI_RECLAIM_MEMORY:
+   e820_type = E820_ACPI;
+   break;
+
+   case EFI_LOADER_CODE:
+   case EFI_LOADER_DATA:
+   case EFI_BOOT_SERVICES_CODE:
+   case EFI_BOOT_SERVICES_DATA:
+   case EFI_CONVENTIONAL_MEMORY:
+   e820_type = E820_RAM;
+   break;
+
+   case EFI_ACPI_MEMORY_NVS:
+   e820_type = E820_NVS;
+   break;
+
+   default:
+   continue;
+   }
+
+   /* Merge adjacent mappings */
+   if (prev && prev->type == e820_type &&
+   (prev->addr + prev->size) == d->phys_addr) {
+   prev->size += d->num_pages << 12;
+   continue;
+   }
+
+   if (nr_entries == ARRAY_SIZE(params->e820_map)) {
+   u32 need = (nr_desc - i) * sizeof(struct e820entry) +
+  sizeof(struct setup_data);
+
+   if (!e820ext || e820ext_size < need)
+   return EFI_BUFFER_TOO_SMALL;
+
+   /* boot_params map full, switch to e820 extended */
+   e820_map = (struct e820entry *)e820ext->data;
+   }
+
+   e820_map->addr = d->phys_addr;
+   e820_map->size = d->num_pages << PAGE_SHIFT;
+   e820_map->type = e820_type;
+   prev = e820_map++;
+   nr_entries++;
+   }
+
+   if (nr_entries > ARRAY_SIZE(params->e820_map)) {
+   u32 nr_e820ext = nr_entries - ARRAY_SIZE(params->e820_map);
+
+   add_e820ext(params, e820ext, nr_e820ext);
+   nr_entries -= nr_e820ext;
+   }
+
+   params->e820_entries = (u8)nr_entries;
+
+   return EFI_SUCCESS;
+}
+
+static efi_status_t alloc_e820ext(u32 nr_desc, struct setup_data **e820ext,
+ 

[PATCHv2] x86: EFI stub support for large memory maps

2013-09-06 Thread Linn Crosetto
This patch fixes a problem with EFI memory maps larger than 128 entries
when booting using the EFI stub, which results in overflowing e820_map
in boot_params and an eventual halt when checking the map size in
sanitize_e820_map().

If the number of map entries is greater than what can fit in e820_map,
add the extra entries to the setup_data list using type SETUP_E820_EXT.
These extra entries are then picked up when the setup_data list is
parsed in parse_e820_ext().

Signed-off-by: Linn Crosetto l...@hp.com
---
Changes in v2:
* Free memory when error is returned from alloc_e820ext() as suggested by Matt
  Fleming
* Set pointer to NULL and size to 0 after freeing memory in alloc_e820ext()

 arch/x86/boot/compressed/eboot.c | 223 ---
 1 file changed, 160 insertions(+), 63 deletions(-)

diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index b7388a4..2ac395e 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -982,20 +982,161 @@ fail:
return NULL;
 }
 
+static void add_e820ext(struct boot_params *params,
+   struct setup_data *e820ext, u32 nr_entries)
+{
+   struct setup_data *data;
+   efi_status_t status;
+   unsigned long size;
+
+   e820ext-type = SETUP_E820_EXT;
+   e820ext-len = nr_entries * sizeof(struct e820entry);
+   e820ext-next = 0;
+
+   data = (struct setup_data *)(unsigned long)params-hdr.setup_data;
+
+   while (data  data-next)
+   data = (struct setup_data *)(unsigned long)data-next;
+
+   if (data)
+   data-next = (unsigned long)e820ext;
+   else
+   params-hdr.setup_data = (unsigned long)e820ext;
+}
+
+static efi_status_t setup_e820(struct boot_params *params,
+  struct setup_data *e820ext, u32 e820ext_size)
+{
+   struct e820entry *e820_map = params-e820_map[0];
+   struct efi_info *efi = params-efi_info;
+   struct e820entry *prev = NULL;
+   u32 nr_entries;
+   u32 nr_desc;
+   int i;
+
+   nr_entries = 0;
+   nr_desc = efi-efi_memmap_size / efi-efi_memdesc_size;
+
+   for (i = 0; i  nr_desc; i++) {
+   efi_memory_desc_t *d;
+   unsigned int e820_type = 0;
+   unsigned long m = efi-efi_memmap;
+
+   d = (efi_memory_desc_t *)(m + (i * efi-efi_memdesc_size));
+   switch (d-type) {
+   case EFI_RESERVED_TYPE:
+   case EFI_RUNTIME_SERVICES_CODE:
+   case EFI_RUNTIME_SERVICES_DATA:
+   case EFI_MEMORY_MAPPED_IO:
+   case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
+   case EFI_PAL_CODE:
+   e820_type = E820_RESERVED;
+   break;
+
+   case EFI_UNUSABLE_MEMORY:
+   e820_type = E820_UNUSABLE;
+   break;
+
+   case EFI_ACPI_RECLAIM_MEMORY:
+   e820_type = E820_ACPI;
+   break;
+
+   case EFI_LOADER_CODE:
+   case EFI_LOADER_DATA:
+   case EFI_BOOT_SERVICES_CODE:
+   case EFI_BOOT_SERVICES_DATA:
+   case EFI_CONVENTIONAL_MEMORY:
+   e820_type = E820_RAM;
+   break;
+
+   case EFI_ACPI_MEMORY_NVS:
+   e820_type = E820_NVS;
+   break;
+
+   default:
+   continue;
+   }
+
+   /* Merge adjacent mappings */
+   if (prev  prev-type == e820_type 
+   (prev-addr + prev-size) == d-phys_addr) {
+   prev-size += d-num_pages  12;
+   continue;
+   }
+
+   if (nr_entries == ARRAY_SIZE(params-e820_map)) {
+   u32 need = (nr_desc - i) * sizeof(struct e820entry) +
+  sizeof(struct setup_data);
+
+   if (!e820ext || e820ext_size  need)
+   return EFI_BUFFER_TOO_SMALL;
+
+   /* boot_params map full, switch to e820 extended */
+   e820_map = (struct e820entry *)e820ext-data;
+   }
+
+   e820_map-addr = d-phys_addr;
+   e820_map-size = d-num_pages  PAGE_SHIFT;
+   e820_map-type = e820_type;
+   prev = e820_map++;
+   nr_entries++;
+   }
+
+   if (nr_entries  ARRAY_SIZE(params-e820_map)) {
+   u32 nr_e820ext = nr_entries - ARRAY_SIZE(params-e820_map);
+
+   add_e820ext(params, e820ext, nr_e820ext);
+   nr_entries -= nr_e820ext;
+   }
+
+   params-e820_entries = (u8)nr_entries;
+
+   return EFI_SUCCESS;
+}
+
+static efi_status_t alloc_e820ext(u32 nr_desc, struct setup_data **e820ext,
+ u32 *e820ext_size)