*/
#include "qemu/osdep.h"
+#include "qemu/units.h"
#include "qemu-common.h"
#include "cpu.h"
#include "hw/hw.h"
int i;
/* work in terms of MB */
- ram_size >>= 20;
+ ram_size /= MiB;
while ((ram_size >= 4) && (nbanks <= 2)) {
int sz_log2 = MIN(31 - clz32(ram_size), 14);
}
}
+static void write_bootloader_nanomips(uint8_t *base, int64_t run_addr,
+ int64_t kernel_entry)
+{
+ uint16_t *p;
+
+ /* Small bootloader */
+ p = (uint16_t *)base;
+
+#define NM_HI1(VAL) (((VAL) >> 16) & 0x1f)
+#define NM_HI2(VAL) \
+ (((VAL) & 0xf000) | (((VAL) >> 19) & 0xffc) | (((VAL) >> 31) & 0x1))
+#define NM_LO(VAL) ((VAL) & 0xfff)
+
+ stw_p(p++, 0x2800); stw_p(p++, 0x001c);
+ /* bc to_here */
+ stw_p(p++, 0x8000); stw_p(p++, 0xc000);
+ /* nop */
+ stw_p(p++, 0x8000); stw_p(p++, 0xc000);
+ /* nop */
+ stw_p(p++, 0x8000); stw_p(p++, 0xc000);
+ /* nop */
+ stw_p(p++, 0x8000); stw_p(p++, 0xc000);
+ /* nop */
+ stw_p(p++, 0x8000); stw_p(p++, 0xc000);
+ /* nop */
+ stw_p(p++, 0x8000); stw_p(p++, 0xc000);
+ /* nop */
+ stw_p(p++, 0x8000); stw_p(p++, 0xc000);
+ /* nop */
+
+ /* to_here: */
+ if (semihosting_get_argc()) {
+ /* Preserve a0 content as arguments have been passed */
+ stw_p(p++, 0x8000); stw_p(p++, 0xc000);
+ /* nop */
+ } else {
+ stw_p(p++, 0x0080); stw_p(p++, 0x0002);
+ /* li a0,2 */
+ }
+
+ stw_p(p++, 0xe3a0 | NM_HI1(ENVP_ADDR - 64));
+
+ stw_p(p++, NM_HI2(ENVP_ADDR - 64));
+ /* lui sp,%hi(ENVP_ADDR - 64) */
+
+ stw_p(p++, 0x83bd); stw_p(p++, NM_LO(ENVP_ADDR - 64));
+ /* ori sp,sp,%lo(ENVP_ADDR - 64) */
+
+ stw_p(p++, 0xe0a0 | NM_HI1(ENVP_ADDR));
+
+ stw_p(p++, NM_HI2(ENVP_ADDR));
+ /* lui a1,%hi(ENVP_ADDR) */
+
+ stw_p(p++, 0x80a5); stw_p(p++, NM_LO(ENVP_ADDR));
+ /* ori a1,a1,%lo(ENVP_ADDR) */
+
+ stw_p(p++, 0xe0c0 | NM_HI1(ENVP_ADDR + 8));
+
+ stw_p(p++, NM_HI2(ENVP_ADDR + 8));
+ /* lui a2,%hi(ENVP_ADDR + 8) */
+
+ stw_p(p++, 0x80c6); stw_p(p++, NM_LO(ENVP_ADDR + 8));
+ /* ori a2,a2,%lo(ENVP_ADDR + 8) */
+
+ stw_p(p++, 0xe0e0 | NM_HI1(loaderparams.ram_low_size));
+
+ stw_p(p++, NM_HI2(loaderparams.ram_low_size));
+ /* lui a3,%hi(loaderparams.ram_low_size) */
+
+ stw_p(p++, 0x80e7); stw_p(p++, NM_LO(loaderparams.ram_low_size));
+ /* ori a3,a3,%lo(loaderparams.ram_low_size) */
+
+ /*
+ * Load BAR registers as done by YAMON:
+ *
+ * - set up PCI0 I/O BARs from 0x18000000 to 0x181fffff
+ * - set up PCI0 MEM0 at 0x10000000, size 0x8000000
+ * - set up PCI0 MEM1 at 0x18200000, size 0xbe00000
+ *
+ */
+ stw_p(p++, 0xe040); stw_p(p++, 0x0681);
+ /* lui t1, %hi(0xb4000000) */
+
+#ifdef TARGET_WORDS_BIGENDIAN
+
+ stw_p(p++, 0xe020); stw_p(p++, 0x0be1);
+ /* lui t0, %hi(0xdf000000) */
+
+ /* 0x68 corresponds to GT_ISD (from hw/mips/gt64xxx_pci.c) */
+ stw_p(p++, 0x8422); stw_p(p++, 0x9068);
+ /* sw t0, 0x68(t1) */
+
+ stw_p(p++, 0xe040); stw_p(p++, 0x077d);
+ /* lui t1, %hi(0xbbe00000) */
+
+ stw_p(p++, 0xe020); stw_p(p++, 0x0801);
+ /* lui t0, %hi(0xc0000000) */
+
+ /* 0x48 corresponds to GT_PCI0IOLD */
+ stw_p(p++, 0x8422); stw_p(p++, 0x9048);
+ /* sw t0, 0x48(t1) */
+
+ stw_p(p++, 0xe020); stw_p(p++, 0x0800);
+ /* lui t0, %hi(0x40000000) */
+
+ /* 0x50 corresponds to GT_PCI0IOHD */
+ stw_p(p++, 0x8422); stw_p(p++, 0x9050);
+ /* sw t0, 0x50(t1) */
+
+ stw_p(p++, 0xe020); stw_p(p++, 0x0001);
+ /* lui t0, %hi(0x80000000) */
+
+ /* 0x58 corresponds to GT_PCI0M0LD */
+ stw_p(p++, 0x8422); stw_p(p++, 0x9058);
+ /* sw t0, 0x58(t1) */
+
+ stw_p(p++, 0xe020); stw_p(p++, 0x07e0);
+ /* lui t0, %hi(0x3f000000) */
+
+ /* 0x60 corresponds to GT_PCI0M0HD */
+ stw_p(p++, 0x8422); stw_p(p++, 0x9060);
+ /* sw t0, 0x60(t1) */
+
+ stw_p(p++, 0xe020); stw_p(p++, 0x0821);
+ /* lui t0, %hi(0xc1000000) */
+
+ /* 0x80 corresponds to GT_PCI0M1LD */
+ stw_p(p++, 0x8422); stw_p(p++, 0x9080);
+ /* sw t0, 0x80(t1) */
+
+ stw_p(p++, 0xe020); stw_p(p++, 0x0bc0);
+ /* lui t0, %hi(0x5e000000) */
+
+#else
+
+ stw_p(p++, 0x0020); stw_p(p++, 0x00df);
+ /* addiu[32] t0, $0, 0xdf */
+
+ /* 0x68 corresponds to GT_ISD */
+ stw_p(p++, 0x8422); stw_p(p++, 0x9068);
+ /* sw t0, 0x68(t1) */
+
+ /* Use kseg2 remapped address 0x1be00000 */
+ stw_p(p++, 0xe040); stw_p(p++, 0x077d);
+ /* lui t1, %hi(0xbbe00000) */
+
+ stw_p(p++, 0x0020); stw_p(p++, 0x00c0);
+ /* addiu[32] t0, $0, 0xc0 */
+
+ /* 0x48 corresponds to GT_PCI0IOLD */
+ stw_p(p++, 0x8422); stw_p(p++, 0x9048);
+ /* sw t0, 0x48(t1) */
+
+ stw_p(p++, 0x0020); stw_p(p++, 0x0040);
+ /* addiu[32] t0, $0, 0x40 */
+
+ /* 0x50 corresponds to GT_PCI0IOHD */
+ stw_p(p++, 0x8422); stw_p(p++, 0x9050);
+ /* sw t0, 0x50(t1) */
+
+ stw_p(p++, 0x0020); stw_p(p++, 0x0080);
+ /* addiu[32] t0, $0, 0x80 */
+
+ /* 0x58 corresponds to GT_PCI0M0LD */
+ stw_p(p++, 0x8422); stw_p(p++, 0x9058);
+ /* sw t0, 0x58(t1) */
+
+ stw_p(p++, 0x0020); stw_p(p++, 0x003f);
+ /* addiu[32] t0, $0, 0x3f */
+
+ /* 0x60 corresponds to GT_PCI0M0HD */
+ stw_p(p++, 0x8422); stw_p(p++, 0x9060);
+ /* sw t0, 0x60(t1) */
+
+ stw_p(p++, 0x0020); stw_p(p++, 0x00c1);
+ /* addiu[32] t0, $0, 0xc1 */
+
+ /* 0x80 corresponds to GT_PCI0M1LD */
+ stw_p(p++, 0x8422); stw_p(p++, 0x9080);
+ /* sw t0, 0x80(t1) */
+
+ stw_p(p++, 0x0020); stw_p(p++, 0x005e);
+ /* addiu[32] t0, $0, 0x5e */
+
+#endif
+
+ /* 0x88 corresponds to GT_PCI0M1HD */
+ stw_p(p++, 0x8422); stw_p(p++, 0x9088);
+ /* sw t0, 0x88(t1) */
+
+ stw_p(p++, 0xe320 | NM_HI1(kernel_entry));
+
+ stw_p(p++, NM_HI2(kernel_entry));
+ /* lui t9,%hi(kernel_entry) */
+
+ stw_p(p++, 0x8339); stw_p(p++, NM_LO(kernel_entry));
+ /* ori t9,t9,%lo(kernel_entry) */
+
+ stw_p(p++, 0x4bf9); stw_p(p++, 0x0000);
+ /* jalrc t8 */
+}
+
/* ROM and pseudo bootloader
The following code implements a very very simple bootloader. It first
a2 - 32-bit address of the environment variables table
a3 - RAM size in bytes
*/
-
static void write_bootloader(uint8_t *base, int64_t run_addr,
int64_t kernel_entry)
{
/* The kernel allocates the bootmap memory in the low memory after
the initrd. It takes at most 128kiB for 2GB RAM and 4kiB
pages. */
- initrd_offset = (loaderparams.ram_low_size - initrd_size - 131072
+ initrd_offset = (loaderparams.ram_low_size - initrd_size
+ - (128 * KiB)
- ~INITRD_PAGE_MASK) & INITRD_PAGE_MASK;
if (kernel_high >= initrd_offset) {
error_report("memory too small for initial ram disk '%s'",
mips_create_cpu(s, machine->cpu_type, &cbus_irq, &i8259_irq);
/* allocate RAM */
- if (ram_size > (2048u << 20)) {
- error_report("Too much memory for this machine: %dMB, maximum 2048MB",
- ((unsigned int)ram_size / (1 << 20)));
+ if (ram_size > 2 * GiB) {
+ error_report("Too much memory for this machine: %" PRId64 "MB,"
+ " maximum 2048MB", ram_size / MiB);
exit(1);
}
/* 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)));
+ ram_high, 0, MIN(ram_size, 256 * MiB));
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)) {
+ if (ram_size > 512 * MiB) {
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);
+ ram_high, 512 * MiB,
+ ram_size - 512 * MiB);
+ memory_region_add_subregion(system_memory, 512 * MiB,
+ ram_low_postio);
}
#ifdef TARGET_WORDS_BIGENDIAN
bios = pflash_cfi01_get_memory(fl);
fl_idx++;
if (kernel_filename) {
- ram_low_size = MIN(ram_size, 256 << 20);
+ ram_low_size = MIN(ram_size, 256 * MiB);
/* For KVM we reserve 1MB of RAM for running bootloader */
if (kvm_enabled()) {
ram_low_size -= 0x100000;
loaderparams.initrd_filename = initrd_filename;
kernel_entry = load_kernel();
- write_bootloader(memory_region_get_ram_ptr(bios),
- bootloader_run_addr, kernel_entry);
+ if (!cpu_supports_isa(machine->cpu_type, ISA_NANOMIPS32)) {
+ write_bootloader(memory_region_get_ram_ptr(bios),
+ bootloader_run_addr, kernel_entry);
+ } else {
+ write_bootloader_nanomips(memory_region_get_ram_ptr(bios),
+ bootloader_run_addr, kernel_entry);
+ }
if (kvm_enabled()) {
/* Write the bootloader code @ the end of RAM, 1MB reserved */
write_bootloader(memory_region_get_ram_ptr(ram_low_preio) +
a neat trick which allows bi-endian firmware. */
#ifndef TARGET_WORDS_BIGENDIAN
{
- uint32_t *end, *addr = rom_ptr(FLASH_ADDRESS);
+ uint32_t *end, *addr;
+ const size_t swapsize = MIN(bios_size, 0x3e0000);
+ addr = rom_ptr(FLASH_ADDRESS, swapsize);
if (!addr) {
addr = memory_region_get_ram_ptr(bios);
}
- end = (void *)addr + MIN(bios_size, 0x3e0000);
+ end = (void *)addr + swapsize;
while (addr < end) {
bswap32s(addr);
addr++;