diff mbox series

[for-5.0,2/4] spapr: Improve handling of fdt buffer size

Message ID 20191129053356.232413-3-david@gibson.dropbear.id.au
State New
Headers show
Series spapr: Improvements to CAS feature negotiation | expand

Commit Message

David Gibson Nov. 29, 2019, 5:33 a.m. UTC
Previously, spapr_build_fdt() constructed the device tree in a fixed
buffer of size FDT_MAX_SIZE.  This is a bit inflexible, but more
importantly it's awkward for the case where we use it during CAS.  In
that case the guest firmware supplies a buffer and we have to
awkwardly check that what we generated fits into it afterwards, after
doing a lot of size checks during spapr_build_fdt().

Simplify this by having spapr_build_fdt() take a 'space' parameter.
For the CAS case, we pass in the buffer size provided by SLOF, for the
machine init case, we continue to pass FDT_MAX_SIZE.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr.c | 33 +++++++++++----------------------
 1 file changed, 11 insertions(+), 22 deletions(-)

Comments

Cédric Le Goater Dec. 2, 2019, 7:04 a.m. UTC | #1
On 29/11/2019 06:33, David Gibson wrote:
> Previously, spapr_build_fdt() constructed the device tree in a fixed
> buffer of size FDT_MAX_SIZE.  This is a bit inflexible, but more
> importantly it's awkward for the case where we use it during CAS.  In
> that case the guest firmware supplies a buffer and we have to
> awkwardly check that what we generated fits into it afterwards, after
> doing a lot of size checks during spapr_build_fdt().
> 
> Simplify this by having spapr_build_fdt() take a 'space' parameter.
> For the CAS case, we pass in the buffer size provided by SLOF, for the
> machine init case, we continue to pass FDT_MAX_SIZE.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>

Reviewed-by: Cedric Le Goater <clg@fr.ibm.com>


> ---
>  hw/ppc/spapr.c | 33 +++++++++++----------------------
>  1 file changed, 11 insertions(+), 22 deletions(-)
> 
> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> index d9c9a2bcee..d34e317f48 100644
> --- a/hw/ppc/spapr.c
> +++ b/hw/ppc/spapr.c
> @@ -917,7 +917,8 @@ static bool spapr_hotplugged_dev_before_cas(void)
>      return false;
>  }
>  
> -static void *spapr_build_fdt(SpaprMachineState *spapr, bool reset);
> +static void *spapr_build_fdt(SpaprMachineState *spapr, bool reset,
> +                             size_t space);
>  
>  int spapr_h_cas_compose_response(SpaprMachineState *spapr,
>                                   target_ulong addr, target_ulong size,
> @@ -930,24 +931,17 @@ int spapr_h_cas_compose_response(SpaprMachineState *spapr,
>          return 1;
>      }
>  
> -    if (size < sizeof(hdr) || size > FW_MAX_SIZE) {
> -        error_report("SLOF provided an unexpected CAS buffer size "
> -                     TARGET_FMT_lu " (min: %zu, max: %u)",
> -                     size, sizeof(hdr), FW_MAX_SIZE);
> +    if (size < sizeof(hdr)) {
> +        error_report("SLOF provided insufficient CAS buffer "
> +                     TARGET_FMT_lu " (min: %zu)", size, sizeof(hdr));
>          exit(EXIT_FAILURE);
>      }
>  
>      size -= sizeof(hdr);
>  
> -    fdt = spapr_build_fdt(spapr, false);
> +    fdt = spapr_build_fdt(spapr, false, size);
>      _FDT((fdt_pack(fdt)));
>  
> -    if (fdt_totalsize(fdt) + sizeof(hdr) > size) {
> -        g_free(fdt);
> -        trace_spapr_cas_failed(size);
> -        return -1;
> -    }
> -
>      cpu_physical_memory_write(addr, &hdr, sizeof(hdr));
>      cpu_physical_memory_write(addr + sizeof(hdr), fdt, fdt_totalsize(fdt));
>      trace_spapr_cas_continue(fdt_totalsize(fdt) + sizeof(hdr));
> @@ -1197,7 +1191,8 @@ static void spapr_dt_hypervisor(SpaprMachineState *spapr, void *fdt)
>      }
>  }
>  
> -static void *spapr_build_fdt(SpaprMachineState *spapr, bool reset)
> +static void *spapr_build_fdt(SpaprMachineState *spapr, bool reset,
> +                             size_t space)
>  {
>      MachineState *machine = MACHINE(spapr);
>      MachineClass *mc = MACHINE_GET_CLASS(machine);
> @@ -1207,8 +1202,8 @@ static void *spapr_build_fdt(SpaprMachineState *spapr, bool reset)
>      SpaprPhbState *phb;
>      char *buf;
>  
> -    fdt = g_malloc0(FDT_MAX_SIZE);
> -    _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
> +    fdt = g_malloc0(space);
> +    _FDT((fdt_create_empty_tree(fdt, space)));
>  
>      /* Root node */
>      _FDT(fdt_setprop_string(fdt, 0, "device_type", "chrp"));
> @@ -1723,19 +1718,13 @@ static void spapr_machine_reset(MachineState *machine)
>       */
>      fdt_addr = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FDT_MAX_SIZE;
>  
> -    fdt = spapr_build_fdt(spapr, true);
> +    fdt = spapr_build_fdt(spapr, true, FDT_MAX_SIZE);
>  
>      rc = fdt_pack(fdt);
>  
>      /* Should only fail if we've built a corrupted tree */
>      assert(rc == 0);
>  
> -    if (fdt_totalsize(fdt) > FDT_MAX_SIZE) {
> -        error_report("FDT too big ! 0x%x bytes (max is 0x%x)",
> -                     fdt_totalsize(fdt), FDT_MAX_SIZE);
> -        exit(1);
> -    }
> -
>      /* Load the fdt */
>      qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
>      cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
>
Greg Kurz Dec. 2, 2019, 7:52 a.m. UTC | #2
On Fri, 29 Nov 2019 16:33:54 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:

> Previously, spapr_build_fdt() constructed the device tree in a fixed
> buffer of size FDT_MAX_SIZE.  This is a bit inflexible, but more
> importantly it's awkward for the case where we use it during CAS.  In
> that case the guest firmware supplies a buffer and we have to
> awkwardly check that what we generated fits into it afterwards, after
> doing a lot of size checks during spapr_build_fdt().
> 
> Simplify this by having spapr_build_fdt() take a 'space' parameter.
> For the CAS case, we pass in the buffer size provided by SLOF, for the
> machine init case, we continue to pass FDT_MAX_SIZE.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---

Reviewed-by: Greg Kurz <groug@kaod.org>

>  hw/ppc/spapr.c | 33 +++++++++++----------------------
>  1 file changed, 11 insertions(+), 22 deletions(-)
> 
> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> index d9c9a2bcee..d34e317f48 100644
> --- a/hw/ppc/spapr.c
> +++ b/hw/ppc/spapr.c
> @@ -917,7 +917,8 @@ static bool spapr_hotplugged_dev_before_cas(void)
>      return false;
>  }
>  
> -static void *spapr_build_fdt(SpaprMachineState *spapr, bool reset);
> +static void *spapr_build_fdt(SpaprMachineState *spapr, bool reset,
> +                             size_t space);
>  
>  int spapr_h_cas_compose_response(SpaprMachineState *spapr,
>                                   target_ulong addr, target_ulong size,
> @@ -930,24 +931,17 @@ int spapr_h_cas_compose_response(SpaprMachineState *spapr,
>          return 1;
>      }
>  
> -    if (size < sizeof(hdr) || size > FW_MAX_SIZE) {
> -        error_report("SLOF provided an unexpected CAS buffer size "
> -                     TARGET_FMT_lu " (min: %zu, max: %u)",
> -                     size, sizeof(hdr), FW_MAX_SIZE);
> +    if (size < sizeof(hdr)) {
> +        error_report("SLOF provided insufficient CAS buffer "
> +                     TARGET_FMT_lu " (min: %zu)", size, sizeof(hdr));
>          exit(EXIT_FAILURE);
>      }
>  
>      size -= sizeof(hdr);
>  
> -    fdt = spapr_build_fdt(spapr, false);
> +    fdt = spapr_build_fdt(spapr, false, size);
>      _FDT((fdt_pack(fdt)));
>  
> -    if (fdt_totalsize(fdt) + sizeof(hdr) > size) {
> -        g_free(fdt);
> -        trace_spapr_cas_failed(size);
> -        return -1;
> -    }
> -
>      cpu_physical_memory_write(addr, &hdr, sizeof(hdr));
>      cpu_physical_memory_write(addr + sizeof(hdr), fdt, fdt_totalsize(fdt));
>      trace_spapr_cas_continue(fdt_totalsize(fdt) + sizeof(hdr));
> @@ -1197,7 +1191,8 @@ static void spapr_dt_hypervisor(SpaprMachineState *spapr, void *fdt)
>      }
>  }
>  
> -static void *spapr_build_fdt(SpaprMachineState *spapr, bool reset)
> +static void *spapr_build_fdt(SpaprMachineState *spapr, bool reset,
> +                             size_t space)
>  {
>      MachineState *machine = MACHINE(spapr);
>      MachineClass *mc = MACHINE_GET_CLASS(machine);
> @@ -1207,8 +1202,8 @@ static void *spapr_build_fdt(SpaprMachineState *spapr, bool reset)
>      SpaprPhbState *phb;
>      char *buf;
>  
> -    fdt = g_malloc0(FDT_MAX_SIZE);
> -    _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
> +    fdt = g_malloc0(space);
> +    _FDT((fdt_create_empty_tree(fdt, space)));
>  
>      /* Root node */
>      _FDT(fdt_setprop_string(fdt, 0, "device_type", "chrp"));
> @@ -1723,19 +1718,13 @@ static void spapr_machine_reset(MachineState *machine)
>       */
>      fdt_addr = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FDT_MAX_SIZE;
>  
> -    fdt = spapr_build_fdt(spapr, true);
> +    fdt = spapr_build_fdt(spapr, true, FDT_MAX_SIZE);
>  
>      rc = fdt_pack(fdt);
>  
>      /* Should only fail if we've built a corrupted tree */
>      assert(rc == 0);
>  
> -    if (fdt_totalsize(fdt) > FDT_MAX_SIZE) {
> -        error_report("FDT too big ! 0x%x bytes (max is 0x%x)",
> -                     fdt_totalsize(fdt), FDT_MAX_SIZE);
> -        exit(1);
> -    }
> -
>      /* Load the fdt */
>      qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
>      cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
diff mbox series

Patch

diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index d9c9a2bcee..d34e317f48 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -917,7 +917,8 @@  static bool spapr_hotplugged_dev_before_cas(void)
     return false;
 }
 
-static void *spapr_build_fdt(SpaprMachineState *spapr, bool reset);
+static void *spapr_build_fdt(SpaprMachineState *spapr, bool reset,
+                             size_t space);
 
 int spapr_h_cas_compose_response(SpaprMachineState *spapr,
                                  target_ulong addr, target_ulong size,
@@ -930,24 +931,17 @@  int spapr_h_cas_compose_response(SpaprMachineState *spapr,
         return 1;
     }
 
-    if (size < sizeof(hdr) || size > FW_MAX_SIZE) {
-        error_report("SLOF provided an unexpected CAS buffer size "
-                     TARGET_FMT_lu " (min: %zu, max: %u)",
-                     size, sizeof(hdr), FW_MAX_SIZE);
+    if (size < sizeof(hdr)) {
+        error_report("SLOF provided insufficient CAS buffer "
+                     TARGET_FMT_lu " (min: %zu)", size, sizeof(hdr));
         exit(EXIT_FAILURE);
     }
 
     size -= sizeof(hdr);
 
-    fdt = spapr_build_fdt(spapr, false);
+    fdt = spapr_build_fdt(spapr, false, size);
     _FDT((fdt_pack(fdt)));
 
-    if (fdt_totalsize(fdt) + sizeof(hdr) > size) {
-        g_free(fdt);
-        trace_spapr_cas_failed(size);
-        return -1;
-    }
-
     cpu_physical_memory_write(addr, &hdr, sizeof(hdr));
     cpu_physical_memory_write(addr + sizeof(hdr), fdt, fdt_totalsize(fdt));
     trace_spapr_cas_continue(fdt_totalsize(fdt) + sizeof(hdr));
@@ -1197,7 +1191,8 @@  static void spapr_dt_hypervisor(SpaprMachineState *spapr, void *fdt)
     }
 }
 
-static void *spapr_build_fdt(SpaprMachineState *spapr, bool reset)
+static void *spapr_build_fdt(SpaprMachineState *spapr, bool reset,
+                             size_t space)
 {
     MachineState *machine = MACHINE(spapr);
     MachineClass *mc = MACHINE_GET_CLASS(machine);
@@ -1207,8 +1202,8 @@  static void *spapr_build_fdt(SpaprMachineState *spapr, bool reset)
     SpaprPhbState *phb;
     char *buf;
 
-    fdt = g_malloc0(FDT_MAX_SIZE);
-    _FDT((fdt_create_empty_tree(fdt, FDT_MAX_SIZE)));
+    fdt = g_malloc0(space);
+    _FDT((fdt_create_empty_tree(fdt, space)));
 
     /* Root node */
     _FDT(fdt_setprop_string(fdt, 0, "device_type", "chrp"));
@@ -1723,19 +1718,13 @@  static void spapr_machine_reset(MachineState *machine)
      */
     fdt_addr = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FDT_MAX_SIZE;
 
-    fdt = spapr_build_fdt(spapr, true);
+    fdt = spapr_build_fdt(spapr, true, FDT_MAX_SIZE);
 
     rc = fdt_pack(fdt);
 
     /* Should only fail if we've built a corrupted tree */
     assert(rc == 0);
 
-    if (fdt_totalsize(fdt) > FDT_MAX_SIZE) {
-        error_report("FDT too big ! 0x%x bytes (max is 0x%x)",
-                     fdt_totalsize(fdt), FDT_MAX_SIZE);
-        exit(1);
-    }
-
     /* Load the fdt */
     qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
     cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));