diff mbox series

[v5,3/7] xen/arm: keep track of reserved-memory regions

Message ID 20190812222844.9636-3-sstabellini@kernel.org (mailing list archive)
State Superseded
Headers show
Series [v5,1/7] xen/arm: pass node to device_tree_for_each_node | expand

Commit Message

Stefano Stabellini Aug. 12, 2019, 10:28 p.m. UTC
As we parse the device tree in Xen, keep track of the reserved-memory
regions as they need special treatment (follow-up patches will make use
of the stored information.)

Reuse process_memory_node to add reserved-memory regions to the
bootinfo.reserved_mem array.

Refuse to continue once we reach the max number of reserved memory
regions to avoid accidentally mapping any portions of them into a VM.

Signed-off-by: Stefano Stabellini <stefanos@xilinx.com>

---
Changes in v5:
- remove unneeded cast
- remove unneeded strlen check
- don't pass address_cells, size_cells, depth to device_tree_for_each_node

Changes in v4:
- depth + 1 in process_reserved_memory_node
- pass address_cells and size_cells to device_tree_for_each_node
- pass struct meminfo * instead of a boolean to process_memory_node
- improve in-code comment
- use a separate process_reserved_memory_node (separate from
  process_memory_node) function wrapper to have different error handling

Changes in v3:
- match only /reserved-memory
- put the warning back in place for reg not present on a normal memory
  region
- refuse to continue once we reach the max number of reserved memory
  regions

Changes in v2:
- call process_memory_node from process_reserved_memory_node to avoid
  duplication
---
 xen/arch/arm/bootfdt.c      | 41 +++++++++++++++++++++++++++++++------
 xen/include/asm-arm/setup.h |  1 +
 2 files changed, 36 insertions(+), 6 deletions(-)

Comments

Volodymyr Babchuk Aug. 13, 2019, 2:23 p.m. UTC | #1
Stefano Stabellini writes:

> As we parse the device tree in Xen, keep track of the reserved-memory
> regions as they need special treatment (follow-up patches will make use
> of the stored information.)
>
> Reuse process_memory_node to add reserved-memory regions to the
> bootinfo.reserved_mem array.
>
> Refuse to continue once we reach the max number of reserved memory
> regions to avoid accidentally mapping any portions of them into a VM.
>
> Signed-off-by: Stefano Stabellini <stefanos@xilinx.com>
>
> ---
> Changes in v5:
> - remove unneeded cast
> - remove unneeded strlen check
> - don't pass address_cells, size_cells, depth to device_tree_for_each_node
>
> Changes in v4:
> - depth + 1 in process_reserved_memory_node
> - pass address_cells and size_cells to device_tree_for_each_node
> - pass struct meminfo * instead of a boolean to process_memory_node
> - improve in-code comment
> - use a separate process_reserved_memory_node (separate from
>   process_memory_node) function wrapper to have different error handling
>
> Changes in v3:
> - match only /reserved-memory
> - put the warning back in place for reg not present on a normal memory
>   region
> - refuse to continue once we reach the max number of reserved memory
>   regions
>
> Changes in v2:
> - call process_memory_node from process_reserved_memory_node to avoid
>   duplication
> ---
>  xen/arch/arm/bootfdt.c      | 41 +++++++++++++++++++++++++++++++------
>  xen/include/asm-arm/setup.h |  1 +
>  2 files changed, 36 insertions(+), 6 deletions(-)
>
> diff --git a/xen/arch/arm/bootfdt.c b/xen/arch/arm/bootfdt.c
> index 590b14304c..0b0e22a3d0 100644
> --- a/xen/arch/arm/bootfdt.c
> +++ b/xen/arch/arm/bootfdt.c
> @@ -136,6 +136,7 @@ static int __init process_memory_node(const void *fdt, int node,
>      const __be32 *cell;
>      paddr_t start, size;
>      u32 reg_cells = address_cells + size_cells;
> +    struct meminfo *mem = data;
>
>      if ( address_cells < 1 || size_cells < 1 )
>          return -ENOENT;
> @@ -147,21 +148,46 @@ static int __init process_memory_node(const void *fdt, int node,
>      cell = (const __be32 *)prop->data;
>      banks = fdt32_to_cpu(prop->len) / (reg_cells * sizeof (u32));
>
> -    for ( i = 0; i < banks && bootinfo.mem.nr_banks < NR_MEM_BANKS; i++ )
> +    for ( i = 0; i < banks && mem->nr_banks < NR_MEM_BANKS; i++ )
What is logic behind the second part of the loop condition?

You know that if (banks > NR_MEM_BANKS) then you will exit with error. Do
you really need to iterate over loop in this case?

>      {
>          device_tree_get_reg(&cell, address_cells, size_cells, &start, &size);
>          if ( !size )
>              continue;
> -        bootinfo.mem.bank[bootinfo.mem.nr_banks].start = start;
> -        bootinfo.mem.bank[bootinfo.mem.nr_banks].size = size;
> -        bootinfo.mem.nr_banks++;
> +        mem->bank[mem->nr_banks].start = start;
> +        mem->bank[mem->nr_banks].size = size;
> +        mem->nr_banks++;
>      }
>
> -    if ( bootinfo.mem.nr_banks == NR_MEM_BANKS )
> +    if ( mem->nr_banks == NR_MEM_BANKS )
Looks like you have the same off-by-one error, as in previous patch.
I can see that it was there earlier. But it is good time to fix it.

>          return -ENOSPC;
>      return 0;
>  }
>
> +static int __init process_reserved_memory_node(const void *fdt, int node,
> +                                               const char *name, int depth,
> +                                               u32 address_cells,
> +                                               u32 size_cells,
> +                                               void *data)
> +{
> +    int rc = process_memory_node(fdt, node, name, depth, address_cells,
> +                                 size_cells, data);
> +
> +    if ( rc == -ENOSPC )
> +        panic("Max number of supported reserved-memory regions reached.");
> +    else if ( rc != -ENOENT )
> +        return rc;
> +    return 0;
> +}
> +
> +static int __init process_reserved_memory(const void *fdt, int node,
> +                                          const char *name, int depth,
> +                                          u32 address_cells, u32 size_cells)
> +{
> +    return device_tree_for_each_node(fdt, node,
> +                                     process_reserved_memory_node,
> +                                     &bootinfo.reserved_mem);
> +}
> +
>  static void __init process_multiboot_node(const void *fdt, int node,
>                                            const char *name,
>                                            u32 address_cells, u32 size_cells)
> @@ -295,7 +321,10 @@ static int __init early_scan_node(const void *fdt,
>
>      if ( device_tree_node_matches(fdt, node, "memory") )
>          rc = process_memory_node(fdt, node, name, depth,
> -                                 address_cells, size_cells, NULL);
> +                                 address_cells, size_cells, &bootinfo.mem);
> +    else if ( depth == 1 && !strcmp(name, "reserved-memory") )
I believe you want to use dt_node_cmp() there.

> +        rc = process_reserved_memory(fdt, node, name, depth,
> +                                     address_cells, size_cells);
>      else if ( depth <= 3 && (device_tree_node_compatible(fdt, node, "xen,multiboot-module" ) ||
>                device_tree_node_compatible(fdt, node, "multiboot,module" )))
>          process_multiboot_node(fdt, node, name, address_cells, size_cells);
> diff --git a/xen/include/asm-arm/setup.h b/xen/include/asm-arm/setup.h
> index 8bf3d5910a..efcba545c2 100644
> --- a/xen/include/asm-arm/setup.h
> +++ b/xen/include/asm-arm/setup.h
> @@ -66,6 +66,7 @@ struct bootcmdlines {
>
>  struct bootinfo {
>      struct meminfo mem;
> +    struct meminfo reserved_mem;
>      struct bootmodules modules;
>      struct bootcmdlines cmdlines;
>  #ifdef CONFIG_ACPI


--
Volodymyr Babchuk at EPAM
Julien Grall Aug. 13, 2019, 2:46 p.m. UTC | #2
Hi,

On 8/13/19 3:23 PM, Volodymyr Babchuk wrote:
> 
> Stefano Stabellini writes:
> 
>> As we parse the device tree in Xen, keep track of the reserved-memory
>> regions as they need special treatment (follow-up patches will make use
>> of the stored information.)
>>
>> Reuse process_memory_node to add reserved-memory regions to the
>> bootinfo.reserved_mem array.
>>
>> Refuse to continue once we reach the max number of reserved memory
>> regions to avoid accidentally mapping any portions of them into a VM.
>>
>> Signed-off-by: Stefano Stabellini <stefanos@xilinx.com>
>>
>> ---
>> Changes in v5:
>> - remove unneeded cast
>> - remove unneeded strlen check
>> - don't pass address_cells, size_cells, depth to device_tree_for_each_node
>>
>> Changes in v4:
>> - depth + 1 in process_reserved_memory_node
>> - pass address_cells and size_cells to device_tree_for_each_node
>> - pass struct meminfo * instead of a boolean to process_memory_node
>> - improve in-code comment
>> - use a separate process_reserved_memory_node (separate from
>>    process_memory_node) function wrapper to have different error handling
>>
>> Changes in v3:
>> - match only /reserved-memory
>> - put the warning back in place for reg not present on a normal memory
>>    region
>> - refuse to continue once we reach the max number of reserved memory
>>    regions
>>
>> Changes in v2:
>> - call process_memory_node from process_reserved_memory_node to avoid
>>    duplication
>> ---
>>   xen/arch/arm/bootfdt.c      | 41 +++++++++++++++++++++++++++++++------
>>   xen/include/asm-arm/setup.h |  1 +
>>   2 files changed, 36 insertions(+), 6 deletions(-)
>>
>> diff --git a/xen/arch/arm/bootfdt.c b/xen/arch/arm/bootfdt.c
>> index 590b14304c..0b0e22a3d0 100644
>> --- a/xen/arch/arm/bootfdt.c
>> +++ b/xen/arch/arm/bootfdt.c
>> @@ -136,6 +136,7 @@ static int __init process_memory_node(const void *fdt, int node,
>>       const __be32 *cell;
>>       paddr_t start, size;
>>       u32 reg_cells = address_cells + size_cells;
>> +    struct meminfo *mem = data;
>>
>>       if ( address_cells < 1 || size_cells < 1 )
>>           return -ENOENT;
>> @@ -147,21 +148,46 @@ static int __init process_memory_node(const void *fdt, int node,
>>       cell = (const __be32 *)prop->data;
>>       banks = fdt32_to_cpu(prop->len) / (reg_cells * sizeof (u32));
>>
>> -    for ( i = 0; i < banks && bootinfo.mem.nr_banks < NR_MEM_BANKS; i++ )
>> +    for ( i = 0; i < banks && mem->nr_banks < NR_MEM_BANKS; i++ )
> What is logic behind the second part of the loop condition?
> 
> You know that if (banks > NR_MEM_BANKS) then you will exit with error. Do
> you really need to iterate over loop in this case?

Well, the error is ignored in the case of memory banks. So iterating 
over the first banks allows you to fill up bootinfo with as much as 
possible as RAM. The rest of the RAM will not be used by Xen.

> 
>>       {
>>           device_tree_get_reg(&cell, address_cells, size_cells, &start, &size);
>>           if ( !size )
>>               continue;
>> -        bootinfo.mem.bank[bootinfo.mem.nr_banks].start = start;
>> -        bootinfo.mem.bank[bootinfo.mem.nr_banks].size = size;
>> -        bootinfo.mem.nr_banks++;
>> +        mem->bank[mem->nr_banks].start = start;
>> +        mem->bank[mem->nr_banks].size = size;
>> +        mem->nr_banks++;
>>       }
>>
>> -    if ( bootinfo.mem.nr_banks == NR_MEM_BANKS )
>> +    if ( mem->nr_banks == NR_MEM_BANKS )
> Looks like you have the same off-by-one error, as in previous patch.
> I can see that it was there earlier. But it is good time to fix it.

I don't think there was an off-by-one error before this series. So what 
do you mean?

Cheers,
Volodymyr Babchuk Aug. 13, 2019, 3:14 p.m. UTC | #3
Hi Julien,

Julien Grall writes:

> Hi,
>
> On 8/13/19 3:23 PM, Volodymyr Babchuk wrote:
>>
>> Stefano Stabellini writes:
>>
>>> As we parse the device tree in Xen, keep track of the reserved-memory
>>> regions as they need special treatment (follow-up patches will make use
>>> of the stored information.)
>>>
>>> Reuse process_memory_node to add reserved-memory regions to the
>>> bootinfo.reserved_mem array.
>>>
>>> Refuse to continue once we reach the max number of reserved memory
>>> regions to avoid accidentally mapping any portions of them into a VM.
>>>
>>> Signed-off-by: Stefano Stabellini <stefanos@xilinx.com>
>>>
>>> ---
>>> Changes in v5:
>>> - remove unneeded cast
>>> - remove unneeded strlen check
>>> - don't pass address_cells, size_cells, depth to device_tree_for_each_node
>>>
>>> Changes in v4:
>>> - depth + 1 in process_reserved_memory_node
>>> - pass address_cells and size_cells to device_tree_for_each_node
>>> - pass struct meminfo * instead of a boolean to process_memory_node
>>> - improve in-code comment
>>> - use a separate process_reserved_memory_node (separate from
>>>    process_memory_node) function wrapper to have different error handling
>>>
>>> Changes in v3:
>>> - match only /reserved-memory
>>> - put the warning back in place for reg not present on a normal memory
>>>    region
>>> - refuse to continue once we reach the max number of reserved memory
>>>    regions
>>>
>>> Changes in v2:
>>> - call process_memory_node from process_reserved_memory_node to avoid
>>>    duplication
>>> ---
>>>   xen/arch/arm/bootfdt.c      | 41 +++++++++++++++++++++++++++++++------
>>>   xen/include/asm-arm/setup.h |  1 +
>>>   2 files changed, 36 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/xen/arch/arm/bootfdt.c b/xen/arch/arm/bootfdt.c
>>> index 590b14304c..0b0e22a3d0 100644
>>> --- a/xen/arch/arm/bootfdt.c
>>> +++ b/xen/arch/arm/bootfdt.c
>>> @@ -136,6 +136,7 @@ static int __init process_memory_node(const void *fdt, int node,
>>>       const __be32 *cell;
>>>       paddr_t start, size;
>>>       u32 reg_cells = address_cells + size_cells;
>>> +    struct meminfo *mem = data;
>>>
>>>       if ( address_cells < 1 || size_cells < 1 )
>>>           return -ENOENT;
>>> @@ -147,21 +148,46 @@ static int __init process_memory_node(const void *fdt, int node,
>>>       cell = (const __be32 *)prop->data;
>>>       banks = fdt32_to_cpu(prop->len) / (reg_cells * sizeof (u32));
>>>
>>> -    for ( i = 0; i < banks && bootinfo.mem.nr_banks < NR_MEM_BANKS; i++ )
>>> +    for ( i = 0; i < banks && mem->nr_banks < NR_MEM_BANKS; i++ )
>> What is logic behind the second part of the loop condition?
>>
>> You know that if (banks > NR_MEM_BANKS) then you will exit with error. Do
>> you really need to iterate over loop in this case?
>
> Well, the error is ignored in the case of memory banks. So iterating
> over the first banks allows you to fill up bootinfo with as much as
> possible as RAM. The rest of the RAM will not be used by Xen.
Fair enough.

>>
>>>       {
>>>           device_tree_get_reg(&cell, address_cells, size_cells, &start, &size);
>>>           if ( !size )
>>>               continue;
>>> -        bootinfo.mem.bank[bootinfo.mem.nr_banks].start = start;
>>> -        bootinfo.mem.bank[bootinfo.mem.nr_banks].size = size;
>>> -        bootinfo.mem.nr_banks++;
>>> +        mem->bank[mem->nr_banks].start = start;
>>> +        mem->bank[mem->nr_banks].size = size;
>>> +        mem->nr_banks++;
>>>       }
>>>
>>> -    if ( bootinfo.mem.nr_banks == NR_MEM_BANKS )
>>> +    if ( mem->nr_banks == NR_MEM_BANKS )
>> Looks like you have the same off-by-one error, as in previous patch.
>> I can see that it was there earlier. But it is good time to fix it.
>
> I don't think there was an off-by-one error before this series. So
> what do you mean?
I explained this in patch #2. Imagine that NR_MEM_BANKS = 1 and you have
one memory node in the dtb. You'll fill the first element of the array
and mem->nr_banks will become 1. This is absolutely normal. But check
above will fail, which is not right.
Julien Grall Aug. 13, 2019, 3:15 p.m. UTC | #4
Hi,

On 8/13/19 4:14 PM, Volodymyr Babchuk wrote:
> Julien Grall writes:
>> On 8/13/19 3:23 PM, Volodymyr Babchuk wrote:
>>> Stefano Stabellini writes:
>>>
>>>>        {
>>>>            device_tree_get_reg(&cell, address_cells, size_cells, &start, &size);
>>>>            if ( !size )
>>>>                continue;
>>>> -        bootinfo.mem.bank[bootinfo.mem.nr_banks].start = start;
>>>> -        bootinfo.mem.bank[bootinfo.mem.nr_banks].size = size;
>>>> -        bootinfo.mem.nr_banks++;
>>>> +        mem->bank[mem->nr_banks].start = start;
>>>> +        mem->bank[mem->nr_banks].size = size;
>>>> +        mem->nr_banks++;
>>>>        }
>>>>
>>>> -    if ( bootinfo.mem.nr_banks == NR_MEM_BANKS )
>>>> +    if ( mem->nr_banks == NR_MEM_BANKS )
>>> Looks like you have the same off-by-one error, as in previous patch.
>>> I can see that it was there earlier. But it is good time to fix it.
>>
>> I don't think there was an off-by-one error before this series. So
>> what do you mean?
> I explained this in patch #2. Imagine that NR_MEM_BANKS = 1 and you have
> one memory node in the dtb. You'll fill the first element of the array
> and mem->nr_banks will become 1. This is absolutely normal. But check
> above will fail, which is not right.

Ok. So the off-by-one error has been introduced by this series. So this 
should be fixed in patch #2 not here.

Cheers,
Volodymyr Babchuk Aug. 13, 2019, 3:39 p.m. UTC | #5
Julien Grall writes:

> Hi,
>
> On 8/13/19 4:14 PM, Volodymyr Babchuk wrote:
>> Julien Grall writes:
>>> On 8/13/19 3:23 PM, Volodymyr Babchuk wrote:
>>>> Stefano Stabellini writes:
>>>>
>>>>>        {
>>>>>            device_tree_get_reg(&cell, address_cells, size_cells, &start, &size);
>>>>>            if ( !size )
>>>>>                continue;
>>>>> -        bootinfo.mem.bank[bootinfo.mem.nr_banks].start = start;
>>>>> -        bootinfo.mem.bank[bootinfo.mem.nr_banks].size = size;
>>>>> -        bootinfo.mem.nr_banks++;
>>>>> +        mem->bank[mem->nr_banks].start = start;
>>>>> +        mem->bank[mem->nr_banks].size = size;
>>>>> +        mem->nr_banks++;
>>>>>        }
>>>>>
>>>>> -    if ( bootinfo.mem.nr_banks == NR_MEM_BANKS )
>>>>> +    if ( mem->nr_banks == NR_MEM_BANKS )
>>>> Looks like you have the same off-by-one error, as in previous patch.
>>>> I can see that it was there earlier. But it is good time to fix it.
>>>
>>> I don't think there was an off-by-one error before this series. So
>>> what do you mean?
>> I explained this in patch #2. Imagine that NR_MEM_BANKS = 1 and you have
>> one memory node in the dtb. You'll fill the first element of the array
>> and mem->nr_banks will become 1. This is absolutely normal. But check
>> above will fail, which is not right.
>
> Ok. So the off-by-one error has been introduced by this series. So
> this should be fixed in patch #2 not here.
Yes, sorry. I got lost in the code.
Julien Grall Aug. 14, 2019, 12:48 p.m. UTC | #6
Hi Stefano,

On 12/08/2019 23:28, Stefano Stabellini wrote:
> As we parse the device tree in Xen, keep track of the reserved-memory
> regions as they need special treatment (follow-up patches will make use
> of the stored information.)
> 
> Reuse process_memory_node to add reserved-memory regions to the
> bootinfo.reserved_mem array.
> 
> Refuse to continue once we reach the max number of reserved memory
> regions to avoid accidentally mapping any portions of them into a VM.
> 
> Signed-off-by: Stefano Stabellini <stefanos@xilinx.com>
> 
> ---
> Changes in v5:
> - remove unneeded cast
> - remove unneeded strlen check
> - don't pass address_cells, size_cells, depth to device_tree_for_each_node
> 
> Changes in v4:
> - depth + 1 in process_reserved_memory_node
> - pass address_cells and size_cells to device_tree_for_each_node
> - pass struct meminfo * instead of a boolean to process_memory_node
> - improve in-code comment
> - use a separate process_reserved_memory_node (separate from
>    process_memory_node) function wrapper to have different error handling
> 
> Changes in v3:
> - match only /reserved-memory
> - put the warning back in place for reg not present on a normal memory
>    region
> - refuse to continue once we reach the max number of reserved memory
>    regions
> 
> Changes in v2:
> - call process_memory_node from process_reserved_memory_node to avoid
>    duplication
> ---
>   xen/arch/arm/bootfdt.c      | 41 +++++++++++++++++++++++++++++++------
>   xen/include/asm-arm/setup.h |  1 +
>   2 files changed, 36 insertions(+), 6 deletions(-)
> 
> diff --git a/xen/arch/arm/bootfdt.c b/xen/arch/arm/bootfdt.c
> index 590b14304c..0b0e22a3d0 100644
> --- a/xen/arch/arm/bootfdt.c
> +++ b/xen/arch/arm/bootfdt.c
> @@ -136,6 +136,7 @@ static int __init process_memory_node(const void *fdt, int node,
>       const __be32 *cell;
>       paddr_t start, size;
>       u32 reg_cells = address_cells + size_cells;
> +    struct meminfo *mem = data;
>   
>       if ( address_cells < 1 || size_cells < 1 )
>           return -ENOENT;
> @@ -147,21 +148,46 @@ static int __init process_memory_node(const void *fdt, int node,
>       cell = (const __be32 *)prop->data;
>       banks = fdt32_to_cpu(prop->len) / (reg_cells * sizeof (u32));
>   
> -    for ( i = 0; i < banks && bootinfo.mem.nr_banks < NR_MEM_BANKS; i++ )
> +    for ( i = 0; i < banks && mem->nr_banks < NR_MEM_BANKS; i++ )
>       {
>           device_tree_get_reg(&cell, address_cells, size_cells, &start, &size);
>           if ( !size )
>               continue;
> -        bootinfo.mem.bank[bootinfo.mem.nr_banks].start = start;
> -        bootinfo.mem.bank[bootinfo.mem.nr_banks].size = size;
> -        bootinfo.mem.nr_banks++;
> +        mem->bank[mem->nr_banks].start = start;
> +        mem->bank[mem->nr_banks].size = size;
> +        mem->nr_banks++;
>       }
>   
> -    if ( bootinfo.mem.nr_banks == NR_MEM_BANKS )
> +    if ( mem->nr_banks == NR_MEM_BANKS )

Assuming the off-by-one is going to be fixed in patch #2:

Acked-by: Julien Grall <julien.grall@arm.com>

Cheers,
diff mbox series

Patch

diff --git a/xen/arch/arm/bootfdt.c b/xen/arch/arm/bootfdt.c
index 590b14304c..0b0e22a3d0 100644
--- a/xen/arch/arm/bootfdt.c
+++ b/xen/arch/arm/bootfdt.c
@@ -136,6 +136,7 @@  static int __init process_memory_node(const void *fdt, int node,
     const __be32 *cell;
     paddr_t start, size;
     u32 reg_cells = address_cells + size_cells;
+    struct meminfo *mem = data;
 
     if ( address_cells < 1 || size_cells < 1 )
         return -ENOENT;
@@ -147,21 +148,46 @@  static int __init process_memory_node(const void *fdt, int node,
     cell = (const __be32 *)prop->data;
     banks = fdt32_to_cpu(prop->len) / (reg_cells * sizeof (u32));
 
-    for ( i = 0; i < banks && bootinfo.mem.nr_banks < NR_MEM_BANKS; i++ )
+    for ( i = 0; i < banks && mem->nr_banks < NR_MEM_BANKS; i++ )
     {
         device_tree_get_reg(&cell, address_cells, size_cells, &start, &size);
         if ( !size )
             continue;
-        bootinfo.mem.bank[bootinfo.mem.nr_banks].start = start;
-        bootinfo.mem.bank[bootinfo.mem.nr_banks].size = size;
-        bootinfo.mem.nr_banks++;
+        mem->bank[mem->nr_banks].start = start;
+        mem->bank[mem->nr_banks].size = size;
+        mem->nr_banks++;
     }
 
-    if ( bootinfo.mem.nr_banks == NR_MEM_BANKS )
+    if ( mem->nr_banks == NR_MEM_BANKS )
         return -ENOSPC;
     return 0;
 }
 
+static int __init process_reserved_memory_node(const void *fdt, int node,
+                                               const char *name, int depth,
+                                               u32 address_cells,
+                                               u32 size_cells,
+                                               void *data)
+{
+    int rc = process_memory_node(fdt, node, name, depth, address_cells,
+                                 size_cells, data);
+
+    if ( rc == -ENOSPC )
+        panic("Max number of supported reserved-memory regions reached.");
+    else if ( rc != -ENOENT )
+        return rc;
+    return 0;
+}
+
+static int __init process_reserved_memory(const void *fdt, int node,
+                                          const char *name, int depth,
+                                          u32 address_cells, u32 size_cells)
+{
+    return device_tree_for_each_node(fdt, node,
+                                     process_reserved_memory_node,
+                                     &bootinfo.reserved_mem);
+}
+
 static void __init process_multiboot_node(const void *fdt, int node,
                                           const char *name,
                                           u32 address_cells, u32 size_cells)
@@ -295,7 +321,10 @@  static int __init early_scan_node(const void *fdt,
 
     if ( device_tree_node_matches(fdt, node, "memory") )
         rc = process_memory_node(fdt, node, name, depth,
-                                 address_cells, size_cells, NULL);
+                                 address_cells, size_cells, &bootinfo.mem);
+    else if ( depth == 1 && !strcmp(name, "reserved-memory") )
+        rc = process_reserved_memory(fdt, node, name, depth,
+                                     address_cells, size_cells);
     else if ( depth <= 3 && (device_tree_node_compatible(fdt, node, "xen,multiboot-module" ) ||
               device_tree_node_compatible(fdt, node, "multiboot,module" )))
         process_multiboot_node(fdt, node, name, address_cells, size_cells);
diff --git a/xen/include/asm-arm/setup.h b/xen/include/asm-arm/setup.h
index 8bf3d5910a..efcba545c2 100644
--- a/xen/include/asm-arm/setup.h
+++ b/xen/include/asm-arm/setup.h
@@ -66,6 +66,7 @@  struct bootcmdlines {
 
 struct bootinfo {
     struct meminfo mem;
+    struct meminfo reserved_mem;
     struct bootmodules modules;
     struct bootcmdlines cmdlines;
 #ifdef CONFIG_ACPI