Message ID | 1378472264-2320-1-git-send-email-paul.burton@imgtec.com |
---|---|
State | New |
Headers | show |
On Fri, Sep 06, 2013 at 01:57:44PM +0100, Paul Burton wrote: > A Malta board can support up to 2GiB of RAM. Since the unmapped kseg0/1 > regions are only 512MiB large & the latter 256MiB of those are taken up > by the IO region, access to RAM beyond 256MiB must be done through a > mapped region. In the case of a Linux guest this means we need to use > highmem. > > The mainline Linux kernel does not support highmem for Malta at this > time, however this can be tested using the linux-mti-3.8 kernel branch > available from: > > git://git.linux-mips.org/pub/scm/linux-mti.git > > You should be able to boot a Linux kernel built from the linux-mti-3.8 > branch, with CONFIG_HIGHMEM enabled, using 2GiB RAM by passing "-m 2G" > to QEMU and appending the following kernel parameters: > > mem=256m@0x0 mem=256m@0x90000000 mem=1536m@0x20000000 > > Note that the upper half of the physical address space of a Malta > mirrors the lower half (hence the 2GiB limit) except that the IO region > (0x10000000-0x1fffffff in the lower half) is not mirrored in the upper > half. That is, physical addresses 0x90000000-0x9fffffff access RAM > rather than the IO region, resulting in a physical address space > resembling the following: > > 0x00000000 -> 0x0fffffff RAM > 0x10000000 -> 0x1fffffff I/O > 0x20000000 -> 0x7fffffff RAM > 0x80000000 -> 0x8fffffff RAM (mirror of 0x00000000 -> 0x0fffffff) > 0x90000000 -> 0x9fffffff RAM > 0xa0000000 -> 0xffffffff RAM (mirror of 0x20000000 -> 0x7fffffff) > > The second mem parameter provided to the kernel above accesses the > second 256MiB of RAM through the upper half of the physical address > space, making use of the aliasing described above in order to avoid > the IO region and use the whole 2GiB RAM. > > The memory setup may be seen as 'backwards' in this commit since the > 'real' memory is mapped in the upper half of the physical address space > and the lower half contains the aliases. On real hardware it would be > typical to see the upper half of the physical address space as the alias > since the bus addresses generated match the lower half of the physical > address space. However since the memory accessible in the upper half of > the physical address space is uninterrupted by the IO region it is > easiest to map the RAM as a whole there, and functionally it makes no > difference to the target code. > > Due to the requirements of accessing the second 256MiB of RAM through > a mapping to the upper half of the physical address space it is usual > for the bootloader to indicate a maximum of 256MiB memory to a kernel. > This allows kernels which do not support such access to boot on systems > with more than 256MiB of RAM. It is also the behaviour assumed by Linux. > QEMUs small generated bootloader is modified to provide this behaviour. > > Signed-off-by: Paul Burton <paul.burton@imgtec.com> > Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com> > Reviewed-by: Aurelien Jarno <aurelien@aurel32.net> > --- > Changes in v2: > - Add a table describing the physical memory space to the commit > message, as suggested by Aurelien Jarno. > --- > hw/mips/mips_malta.c | 36 ++++++++++++++++++++++++++++-------- > 1 file changed, 28 insertions(+), 8 deletions(-) > > diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c > index ae0921c..05c8771 100644 > --- a/hw/mips/mips_malta.c > +++ b/hw/mips/mips_malta.c > @@ -827,7 +827,8 @@ static int64_t load_kernel (void) > } > > prom_set(prom_buf, prom_index++, "memsize"); > - prom_set(prom_buf, prom_index++, "%i", loaderparams.ram_size); > + prom_set(prom_buf, prom_index++, "%i", > + MIN(loaderparams.ram_size, 256 << 20)); > prom_set(prom_buf, prom_index++, "modetty0"); > prom_set(prom_buf, prom_index++, "38400n8r"); > prom_set(prom_buf, prom_index++, NULL); > @@ -884,7 +885,9 @@ void mips_malta_init(QEMUMachineInitArgs *args) > char *filename; > pflash_t *fl; > MemoryRegion *system_memory = get_system_memory(); > - MemoryRegion *ram = g_new(MemoryRegion, 1); > + MemoryRegion *ram_high = g_new(MemoryRegion, 1); > + MemoryRegion *ram_low_preio = g_new(MemoryRegion, 1); > + MemoryRegion *ram_low_postio; > MemoryRegion *bios, *bios_copy = g_new(MemoryRegion, 1); > target_long bios_size = FLASH_SIZE; > const size_t smbus_eeprom_size = 8 * 256; > @@ -951,15 +954,32 @@ void mips_malta_init(QEMUMachineInitArgs *args) > env = &cpu->env; > > /* allocate RAM */ > - if (ram_size > (256 << 20)) { > + if (ram_size > (2048u << 20)) { > fprintf(stderr, > - "qemu: Too much memory for this machine: %d MB, maximum 256 MB\n", > + "qemu: Too much memory for this machine: %d MB, maximum 2048 MB\n", > ((unsigned int)ram_size / (1 << 20))); > exit(1); > } > - memory_region_init_ram(ram, NULL, "mips_malta.ram", ram_size); > - vmstate_register_ram_global(ram); > - memory_region_add_subregion(system_memory, 0, ram); > + > + /* register RAM at high address where it is undisturbed by IO */ > + memory_region_init_ram(ram_high, NULL, "mips_malta.ram", ram_size); > + vmstate_register_ram_global(ram_high); > + memory_region_add_subregion(system_memory, 0x80000000, ram_high); > + > + /* alias for pre IO hole access */ > + memory_region_init_alias(ram_low_preio, NULL, "mips_malta_low_preio.ram", > + ram_high, 0, MIN(ram_size, (256 << 20))); > + memory_region_add_subregion(system_memory, 0, ram_low_preio); > + > + /* alias for post IO hole access, if there is enough RAM */ > + if (ram_size > (512 << 20)) { > + ram_low_postio = g_new(MemoryRegion, 1); > + memory_region_init_alias(ram_low_postio, NULL, > + "mips_malta_low_postio.ram", > + ram_high, 512 << 20, > + ram_size - (512 << 20)); > + memory_region_add_subregion(system_memory, 512 << 20, ram_low_postio); > + } > > /* generate SPD EEPROM data */ > generate_eeprom_spd(&smbus_eeprom_buf[0 * 256], ram_size); > @@ -992,7 +1012,7 @@ void mips_malta_init(QEMUMachineInitArgs *args) > fl_idx++; > if (kernel_filename) { > /* Write a small bootloader to the flash location. */ > - loaderparams.ram_size = ram_size; > + loaderparams.ram_size = MIN(ram_size, 256 << 20); > loaderparams.kernel_filename = kernel_filename; > loaderparams.kernel_cmdline = kernel_cmdline; > loaderparams.initrd_filename = initrd_filename; Thanks, applied.
diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index ae0921c..05c8771 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -827,7 +827,8 @@ static int64_t load_kernel (void) } prom_set(prom_buf, prom_index++, "memsize"); - prom_set(prom_buf, prom_index++, "%i", loaderparams.ram_size); + prom_set(prom_buf, prom_index++, "%i", + MIN(loaderparams.ram_size, 256 << 20)); prom_set(prom_buf, prom_index++, "modetty0"); prom_set(prom_buf, prom_index++, "38400n8r"); prom_set(prom_buf, prom_index++, NULL); @@ -884,7 +885,9 @@ void mips_malta_init(QEMUMachineInitArgs *args) char *filename; pflash_t *fl; MemoryRegion *system_memory = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); + MemoryRegion *ram_high = g_new(MemoryRegion, 1); + MemoryRegion *ram_low_preio = g_new(MemoryRegion, 1); + MemoryRegion *ram_low_postio; MemoryRegion *bios, *bios_copy = g_new(MemoryRegion, 1); target_long bios_size = FLASH_SIZE; const size_t smbus_eeprom_size = 8 * 256; @@ -951,15 +954,32 @@ void mips_malta_init(QEMUMachineInitArgs *args) env = &cpu->env; /* allocate RAM */ - if (ram_size > (256 << 20)) { + if (ram_size > (2048u << 20)) { fprintf(stderr, - "qemu: Too much memory for this machine: %d MB, maximum 256 MB\n", + "qemu: Too much memory for this machine: %d MB, maximum 2048 MB\n", ((unsigned int)ram_size / (1 << 20))); exit(1); } - memory_region_init_ram(ram, NULL, "mips_malta.ram", ram_size); - vmstate_register_ram_global(ram); - memory_region_add_subregion(system_memory, 0, ram); + + /* register RAM at high address where it is undisturbed by IO */ + memory_region_init_ram(ram_high, NULL, "mips_malta.ram", ram_size); + vmstate_register_ram_global(ram_high); + memory_region_add_subregion(system_memory, 0x80000000, ram_high); + + /* alias for pre IO hole access */ + memory_region_init_alias(ram_low_preio, NULL, "mips_malta_low_preio.ram", + ram_high, 0, MIN(ram_size, (256 << 20))); + memory_region_add_subregion(system_memory, 0, ram_low_preio); + + /* alias for post IO hole access, if there is enough RAM */ + if (ram_size > (512 << 20)) { + ram_low_postio = g_new(MemoryRegion, 1); + memory_region_init_alias(ram_low_postio, NULL, + "mips_malta_low_postio.ram", + ram_high, 512 << 20, + ram_size - (512 << 20)); + memory_region_add_subregion(system_memory, 512 << 20, ram_low_postio); + } /* generate SPD EEPROM data */ generate_eeprom_spd(&smbus_eeprom_buf[0 * 256], ram_size); @@ -992,7 +1012,7 @@ void mips_malta_init(QEMUMachineInitArgs *args) fl_idx++; if (kernel_filename) { /* Write a small bootloader to the flash location. */ - loaderparams.ram_size = ram_size; + loaderparams.ram_size = MIN(ram_size, 256 << 20); loaderparams.kernel_filename = kernel_filename; loaderparams.kernel_cmdline = kernel_cmdline; loaderparams.initrd_filename = initrd_filename;