Merge "Change requested in launchpad bug #1288352" into 5.0
[packages/centos6/qemu.git] / 0802-arm_boot-Change-initrd-load-address-to-halfway-throu.patch
1 From d3a43fe4b870154032db4651824bc88e3cb81dc5 Mon Sep 17 00:00:00 2001
2 From: Peter Maydell <peter.maydell@linaro.org>
3 Date: Fri, 26 Oct 2012 16:29:38 +0100
4 Subject: [PATCH] arm_boot: Change initrd load address to "halfway through
5  RAM"
6
7 To avoid continually having to bump the initrd load address
8 to account for larger kernel images, put the initrd halfway
9 through RAM. This allows large kernels on new boards with lots
10 of RAM to work OK, without breaking existing usecases for
11 boards with only 32MB of RAM.
12
13 Note that this change fixes in passing a bug where we were
14 passing an overly large max_size to load_image_targphys()
15 for the initrd, which meant that we wouldn't correctly refuse
16 to load an enormous initrd that didn't actually fit into RAM.
17
18 Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
19 ---
20  hw/arm-misc.h |  1 +
21  hw/arm_boot.c | 41 ++++++++++++++++++++++++++---------------
22  2 files changed, 27 insertions(+), 15 deletions(-)
23
24 diff --git a/hw/arm-misc.h b/hw/arm-misc.h
25 index bdd8fec..0f7deb5 100644
26 --- a/hw/arm-misc.h
27 +++ b/hw/arm-misc.h
28 @@ -56,6 +56,7 @@ struct arm_boot_info {
29                                       const struct arm_boot_info *info);
30      /* Used internally by arm_boot.c */
31      int is_linux;
32 +    target_phys_addr_t initrd_start;
33      target_phys_addr_t initrd_size;
34      target_phys_addr_t entry;
35  };
36 diff --git a/hw/arm_boot.c b/hw/arm_boot.c
37 index a6e9143..920c337 100644
38 --- a/hw/arm_boot.c
39 +++ b/hw/arm_boot.c
40 @@ -18,7 +18,6 @@
41  
42  #define KERNEL_ARGS_ADDR 0x100
43  #define KERNEL_LOAD_ADDR 0x00010000
44 -#define INITRD_LOAD_ADDR 0x00d00000
45  
46  /* The worlds second smallest bootloader.  Set r0-r2, then jump to kernel.  */
47  static uint32_t bootloader[] = {
48 @@ -109,7 +108,7 @@ static void set_kernel_args(const struct arm_boot_info *info)
49          /* ATAG_INITRD2 */
50          WRITE_WORD(p, 4);
51          WRITE_WORD(p, 0x54420005);
52 -        WRITE_WORD(p, info->loader_start + INITRD_LOAD_ADDR);
53 +        WRITE_WORD(p, info->initrd_start);
54          WRITE_WORD(p, initrd_size);
55      }
56      if (info->kernel_cmdline && *info->kernel_cmdline) {
57 @@ -185,10 +184,11 @@ static void set_kernel_args_old(const struct arm_boot_info *info)
58      /* pages_in_vram */
59      WRITE_WORD(p, 0);
60      /* initrd_start */
61 -    if (initrd_size)
62 -        WRITE_WORD(p, info->loader_start + INITRD_LOAD_ADDR);
63 -    else
64 +    if (initrd_size) {
65 +        WRITE_WORD(p, info->initrd_start);
66 +    } else {
67          WRITE_WORD(p, 0);
68 +    }
69      /* initrd_size */
70      WRITE_WORD(p, initrd_size);
71      /* rd_start */
72 @@ -281,14 +281,13 @@ static int load_dtb(target_phys_addr_t addr, const struct arm_boot_info *binfo)
73  
74      if (binfo->initrd_size) {
75          rc = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
76 -                binfo->loader_start + INITRD_LOAD_ADDR);
77 +                binfo->initrd_start);
78          if (rc < 0) {
79              fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
80          }
81  
82          rc = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
83 -                    binfo->loader_start + INITRD_LOAD_ADDR +
84 -                    binfo->initrd_size);
85 +                    binfo->initrd_start + binfo->initrd_size);
86          if (rc < 0) {
87              fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
88          }
89 @@ -375,6 +374,19 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
90      big_endian = 0;
91  #endif
92  
93 +    /* We want to put the initrd far enough into RAM that when the
94 +     * kernel is uncompressed it will not clobber the initrd. However
95 +     * on boards without much RAM we must ensure that we still leave
96 +     * enough room for a decent sized initrd, and on boards with large
97 +     * amounts of RAM we must avoid the initrd being so far up in RAM
98 +     * that it is outside lowmem and inaccessible to the kernel.
99 +     * So for boards with less  than 256MB of RAM we put the initrd
100 +     * halfway into RAM, and for boards with 256MB of RAM or more we put
101 +     * the initrd at 128MB.
102 +     */
103 +    info->initrd_start = info->loader_start +
104 +        MIN(info->ram_size / 2, 128 * 1024 * 1024);
105 +
106      /* Assume that raw images are linux kernels, and ELF images are not.  */
107      kernel_size = load_elf(info->kernel_filename, NULL, NULL, &elf_entry,
108                             NULL, NULL, big_endian, ELF_MACHINE, 1);
109 @@ -398,10 +410,9 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
110      if (is_linux) {
111          if (info->initrd_filename) {
112              initrd_size = load_image_targphys(info->initrd_filename,
113 -                                              info->loader_start
114 -                                              + INITRD_LOAD_ADDR,
115 -                                              info->ram_size
116 -                                              - INITRD_LOAD_ADDR);
117 +                                              info->initrd_start,
118 +                                              info->ram_size -
119 +                                              info->initrd_start);
120              if (initrd_size < 0) {
121                  fprintf(stderr, "qemu: could not load initrd '%s'\n",
122                          info->initrd_filename);
123 @@ -419,9 +430,9 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
124           */
125          if (info->dtb_filename) {
126              /* Place the DTB after the initrd in memory */
127 -            target_phys_addr_t dtb_start = TARGET_PAGE_ALIGN(info->loader_start
128 -                                                             + INITRD_LOAD_ADDR
129 -                                                             + initrd_size);
130 +            target_phys_addr_t dtb_start = TARGET_PAGE_ALIGN(
131 +                                                        info->initrd_start +
132 +                                                        initrd_size);
133              if (load_dtb(dtb_start, info)) {
134                  exit(1);
135              }
136 -- 
137 1.7.12.1
138