static void write_boot_rom(DriveInfo *dinfo, hwaddr addr, size_t rom_size, Error **errp) { BlockBackend *blk = blk_by_legacy_dinfo(dinfo); uint8_t *storage; int64_t size; /* The block backend size should have already been 'validated' by * the creation of the m25p80 object. */ size = blk_getlength(blk); if (size <= 0) { error_setg(errp, "failed to get flash size"); return; } if (rom_size > size) { rom_size = size; } storage = g_new0(uint8_t, rom_size); if (blk_pread(blk, 0, storage, rom_size) < 0) { error_setg(errp, "failed to read the initial flash content"); return; } rom_add_blob_fixed("aspeed.boot_rom", storage, rom_size, addr); g_free(storage); }
void exynos4210_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info) { int n; uint32_t smpboot[] = { 0xe59f3034, /* ldr r3, External gic_cpu_if */ 0xe59f2034, /* ldr r2, Internal gic_cpu_if */ 0xe59f0034, /* ldr r0, startaddr */ 0xe3a01001, /* mov r1, #1 */ 0xe5821000, /* str r1, [r2] */ 0xe5831000, /* str r1, [r3] */ 0xe3a010ff, /* mov r1, #0xff */ 0xe5821004, /* str r1, [r2, #4] */ 0xe5831004, /* str r1, [r3, #4] */ 0xf57ff04f, /* dsb */ 0xe320f003, /* wfi */ 0xe5901000, /* ldr r1, [r0] */ 0xe1110001, /* tst r1, r1 */ 0x0afffffb, /* beq <wfi> */ 0xe12fff11, /* bx r1 */ EXYNOS4210_EXT_GIC_CPU_BASE_ADDR, 0, /* gic_cpu_if: base address of Internal GIC CPU interface */ 0 /* bootreg: Boot register address is held here */ }; smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr; smpboot[ARRAY_SIZE(smpboot) - 2] = info->gic_cpu_if_addr; for (n = 0; n < ARRAY_SIZE(smpboot); n++) { smpboot[n] = tswap32(smpboot[n]); } rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), info->smp_loader_start); }
static void hb_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info) { int n; uint32_t smpboot[] = { 0xee100fb0, /* mrc p15, 0, r0, c0, c0, 5 - read current core id */ 0xe210000f, /* ands r0, r0, #0x0f */ 0xe3a03040, /* mov r3, #0x40 - jump address is 0x40 + 0x10 * core id */ 0xe0830200, /* add r0, r3, r0, lsl #4 */ 0xe59f2024, /* ldr r2, privbase */ 0xe3a01001, /* mov r1, #1 */ 0xe5821100, /* str r1, [r2, #256] - set GICC_CTLR.Enable */ 0xe3a010ff, /* mov r1, #0xff */ 0xe5821104, /* str r1, [r2, #260] - set GICC_PMR.Priority to 0xff */ 0xf57ff04f, /* dsb */ 0xe320f003, /* wfi */ 0xe5901000, /* ldr r1, [r0] */ 0xe1110001, /* tst r1, r1 */ 0x0afffffb, /* beq <wfi> */ 0xe12fff11, /* bx r1 */ MPCORE_PERIPHBASE /* privbase: MPCore peripheral base address. */ }; for (n = 0; n < ARRAY_SIZE(smpboot); n++) { smpboot[n] = tswap32(smpboot[n]); } rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), SMP_BOOT_ADDR); }
static void hb_write_board_setup(ARMCPU *cpu, const struct arm_boot_info *info) { int n; uint32_t board_setup_blob[] = { /* MVBAR_ADDR */ /* Default unimplemented and unused vectors to spin. Makes it * easier to debug (as opposed to the CPU running away). */ 0xeafffffe, /* notused1: b notused */ 0xeafffffe, /* notused2: b notused */ 0xe1b0f00e, /* smc: movs pc, lr - exception return */ 0xeafffffe, /* prefetch_abort: b prefetch_abort */ 0xeafffffe, /* data_abort: b data_abort */ 0xeafffffe, /* notused3: b notused3 */ 0xeafffffe, /* irq: b irq */ 0xeafffffe, /* fiq: b fiq */ #define BOARD_SETUP_ADDR (MVBAR_ADDR + 8 * sizeof(uint32_t)) 0xe3000000 + ARMV7_IMM16(MVBAR_ADDR), /* movw r0, MVBAR_ADDR */ 0xee0c0f30, /* mcr p15, 0, r0, c12, c0, 1 - set MVBAR */ 0xee110f11, /* mrc p15, 0, r0, c1 , c1, 0 - get SCR */ 0xe3810001, /* orr r0, #1 - set NS */ 0xee010f11, /* mcr p15, 0, r0, c1 , c1, 0 - set SCR */ 0xe1600070, /* smc - go to monitor mode to flush NS change */ 0xe12fff1e, /* bx lr - return to caller */ }; for (n = 0; n < ARRAY_SIZE(board_setup_blob); n++) { board_setup_blob[n] = tswap32(board_setup_blob[n]); } rom_add_blob_fixed("board-setup", board_setup_blob, sizeof(board_setup_blob), MVBAR_ADDR); }
static int fit_load_kernel(const struct fit_loader *ldr, const void *itb, int cfg, void *opaque, hwaddr *pend) { const char *name; const void *data; const void *load_data; hwaddr load_addr, entry_addr; int img_off, err; size_t sz; int ret; name = fdt_getprop(itb, cfg, "kernel", NULL); if (!name) { error_printf("no kernel specified by FIT configuration\n"); return -EINVAL; } load_data = data = fit_load_image_alloc(itb, name, &img_off, &sz); if (!data) { error_printf("unable to load kernel image from FIT\n"); return -EINVAL; } err = fit_image_addr(itb, img_off, "load", &load_addr); if (err) { error_printf("unable to read kernel load address from FIT\n"); ret = err; goto out; } err = fit_image_addr(itb, img_off, "entry", &entry_addr); if (err) { error_printf("unable to read kernel entry address from FIT\n"); ret = err; goto out; } if (ldr->kernel_filter) { load_data = ldr->kernel_filter(opaque, data, &load_addr, &entry_addr); } if (pend) { *pend = load_addr + sz; } load_addr = ldr->addr_to_phys(opaque, load_addr); rom_add_blob_fixed(name, load_data, sz, load_addr); ret = 0; out: g_free((void *) data); if (data != load_data) { g_free((void *) load_data); } return ret; }
static int bamboo_load_device_tree(target_phys_addr_t addr, uint32_t ramsize, target_phys_addr_t initrd_base, target_phys_addr_t initrd_size, const char *kernel_cmdline) { int ret = -1; #ifdef CONFIG_FDT uint32_t mem_reg_property[] = { 0, 0, ramsize }; char *filename; int fdt_size; void *fdt; filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); if (!filename) { goto out; } fdt = load_device_tree(filename, &fdt_size); g_free(filename); if (fdt == NULL) { goto out; } /* Manipulate device tree in memory. */ ret = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property, sizeof(mem_reg_property)); if (ret < 0) fprintf(stderr, "couldn't set /memory/reg\n"); ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start", initrd_base); if (ret < 0) fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end", (initrd_base + initrd_size)); if (ret < 0) fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline); if (ret < 0) fprintf(stderr, "couldn't set /chosen/bootargs\n"); if (kvm_enabled()) kvmppc_fdt_update(fdt); ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); g_free(fdt); out: #endif return ret; }
static void zynq_write_secondary_boot(ARMCPU *cpu, const struct arm_boot_info *info) { int n; for (n = 0; n < ARRAY_SIZE(zynq_smpboot); n++) { zynq_smpboot[n] = tswap32(zynq_smpboot[n]); } rom_add_blob_fixed("smpboot", zynq_smpboot, sizeof(zynq_smpboot), SMP_BOOT_ADDR); }
static int fit_load_fdt(const struct fit_loader *ldr, const void *itb, int cfg, void *opaque, const void *match_data, hwaddr kernel_end) { const char *name; const void *data; const void *load_data; hwaddr load_addr; int img_off, err; size_t sz; int ret; name = fdt_getprop(itb, cfg, "fdt", NULL); if (!name) { return 0; } load_data = data = fit_load_image_alloc(itb, name, &img_off, &sz); if (!data) { error_printf("unable to load FDT image from FIT\n"); return -EINVAL; } err = fit_image_addr(itb, img_off, "load", &load_addr); if (err == -ENOENT) { load_addr = ROUND_UP(kernel_end, 64 * K_BYTE) + (10 * M_BYTE); } else if (err) { ret = err; goto out; } if (ldr->fdt_filter) { load_data = ldr->fdt_filter(opaque, data, match_data, &load_addr); } load_addr = ldr->addr_to_phys(opaque, load_addr); sz = fdt_totalsize(load_data); rom_add_blob_fixed(name, load_data, sz, load_addr); ret = 0; out: g_free((void *) data); if (data != load_data) { g_free((void *) load_data); } return ret; }
static void zynq_write_board_setup(ARMCPU *cpu, const struct arm_boot_info *info) { int n; uint32_t board_setup_blob[] = { 0xe3a004f8, /* mov r0, #0xf8000000 */ SLCR_WRITE(SLCR_UNLOCK_OFFSET, SLCR_XILINX_UNLOCK_KEY), SLCR_WRITE(SLCR_ARM_PLL_OFFSET, 0x00014008), SLCR_WRITE(SLCR_LOCK_OFFSET, SLCR_XILINX_LOCK_KEY), 0xe12fff1e, /* bx lr */ }; for (n = 0; n < ARRAY_SIZE(board_setup_blob); n++) { board_setup_blob[n] = tswap32(board_setup_blob[n]); } rom_add_blob_fixed("board-setup", board_setup_blob, sizeof(board_setup_blob), BOARD_SETUP_ADDR); }
static void hb_write_secondary(CPUARMState *env, const struct arm_boot_info *info) { int n; uint32_t smpboot[] = { 0xee100fb0, /* mrc p15, 0, r0, c0, c0, 5 - read current core id */ 0xe210000f, /* ands r0, r0, #0x0f */ 0xe3a03040, /* mov r3, #0x40 - jump address is 0x40 + 0x10 * core id */ 0xe0830200, /* add r0, r3, r0, lsl #4 */ 0xe59f2018, /* ldr r2, privbase */ 0xe3a01001, /* mov r1, #1 */ 0xe5821100, /* str r1, [r2, #256] */ 0xe320f003, /* wfi */ 0xe5901000, /* ldr r1, [r0] */ 0xe1110001, /* tst r1, r1 */ 0x0afffffb, /* beq <wfi> */ 0xe12fff11, /* bx r1 */ GIC_BASE_ADDR /* privbase: gic address. */ }; for (n = 0; n < ARRAY_SIZE(smpboot); n++) { smpboot[n] = tswap32(smpboot[n]); } rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), SMP_BOOT_ADDR); }
static int mpc8544_load_device_tree(CPUPPCState *env, target_phys_addr_t addr, uint32_t ramsize, target_phys_addr_t initrd_base, target_phys_addr_t initrd_size, const char *kernel_cmdline) { int ret = -1; #ifdef CONFIG_FDT uint32_t mem_reg_property[] = {0, cpu_to_be32(ramsize)}; char *filename; int fdt_size; void *fdt; uint8_t hypercall[16]; uint32_t clock_freq = 400000000; uint32_t tb_freq = 400000000; int i; filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); if (!filename) { goto out; } fdt = load_device_tree(filename, &fdt_size); g_free(filename); if (fdt == NULL) { goto out; } /* Manipulate device tree in memory. */ ret = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property, sizeof(mem_reg_property)); if (ret < 0) fprintf(stderr, "couldn't set /memory/reg\n"); if (initrd_size) { ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start", initrd_base); if (ret < 0) { fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); } ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end", (initrd_base + initrd_size)); if (ret < 0) { fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); } } ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline); if (ret < 0) fprintf(stderr, "couldn't set /chosen/bootargs\n"); if (kvm_enabled()) { /* Read out host's frequencies */ clock_freq = kvmppc_get_clockfreq(); tb_freq = kvmppc_get_tbfreq(); /* indicate KVM hypercall interface */ qemu_devtree_setprop_string(fdt, "/hypervisor", "compatible", "linux,kvm"); kvmppc_get_hypercall(env, hypercall, sizeof(hypercall)); qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions", hypercall, sizeof(hypercall)); } /* We need to generate the cpu nodes in reverse order, so Linux can pick the first node as boot node and be happy */ for (i = smp_cpus - 1; i >= 0; i--) { char cpu_name[128]; uint64_t cpu_release_addr = cpu_to_be64(MPC8544_SPIN_BASE + (i * 0x20)); for (env = first_cpu; env != NULL; env = env->next_cpu) { if (env->cpu_index == i) { break; } } if (!env) { continue; } snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", env->cpu_index); qemu_devtree_add_subnode(fdt, cpu_name); qemu_devtree_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq); qemu_devtree_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq); qemu_devtree_setprop_string(fdt, cpu_name, "device_type", "cpu"); qemu_devtree_setprop_cell(fdt, cpu_name, "reg", env->cpu_index); qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-line-size", env->dcache_line_size); qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-line-size", env->icache_line_size); qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000); qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000); qemu_devtree_setprop_cell(fdt, cpu_name, "bus-frequency", 0); if (env->cpu_index) { qemu_devtree_setprop_string(fdt, cpu_name, "status", "disabled"); qemu_devtree_setprop_string(fdt, cpu_name, "enable-method", "spin-table"); qemu_devtree_setprop(fdt, cpu_name, "cpu-release-addr", &cpu_release_addr, sizeof(cpu_release_addr)); } else { qemu_devtree_setprop_string(fdt, cpu_name, "status", "okay"); } } ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); g_free(fdt); out: #endif return ret; }
static void xbox_flash_init(MemoryRegion *rom_memory) { char *filename; int bios_size; int bootrom_size; MemoryRegion *bios; MemoryRegion *map_bios; uint32_t map_loc; int rc, fd = -1; char *bios_data; /* Locate BIOS ROM image */ if (bios_name == NULL) { bios_name = "bios.bin"; } filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); if (filename) { bios_size = get_image_size(filename); } else { bios_size = -1; } if (bios_size <= 0 || (bios_size % 65536) != 0) { goto bios_error; } /* Read BIOS ROM into memory */ bios_data = g_malloc(bios_size); assert(bios_data != NULL); fd = open(filename, O_RDONLY | O_BINARY); assert(fd >= 0); rc = read(fd, bios_data, bios_size); assert(rc == bios_size); close(fd); g_free(filename); /* XBOX_FIXME: What follows is a big hack to overlay the MCPX ROM on the * top 512 bytes of the ROM region. This differs from original XQEMU * sources which copied it in at lpc init; new QEMU seems to be different * now in that the BIOS images supplied to rom_add_file_fixed will be * loaded *after* lpc init is called, so the MCPX ROM would get * overwritten. Instead, let's just map it in right here while we map in * BIOS. * * Anyway it behaves the same as before--that is, wrongly. Really, we * should let the CPU execute from MMIO emulating the TSOP access with * bootrom overlay being controlled by the magic bit..but this is "good * enough" for now ;). */ /* Locate and overlay MCPX ROM image into new copy of BIOS if provided */ const char *bootrom_file = object_property_get_str(qdev_get_machine(), "bootrom", NULL); if ((bootrom_file != NULL) && *bootrom_file) { filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bootrom_file); assert(filename); bootrom_size = get_image_size(filename); if (bootrom_size != 512) { fprintf(stderr, "MCPX bootrom should be 512 bytes, got %d\n", bootrom_size); exit(1); return; } /* Read in MCPX ROM over last 512 bytes of BIOS data */ fd = open(filename, O_RDONLY | O_BINARY); assert(fd >= 0); rc = read(fd, &bios_data[bios_size - bootrom_size], bootrom_size); assert(rc == bootrom_size); close(fd); g_free(filename); } /* Create BIOS region */ bios = g_malloc(sizeof(*bios)); assert(bios != NULL); memory_region_init_ram(bios, NULL, "xbox.bios", bios_size, &error_fatal); memory_region_set_readonly(bios, true); rom_add_blob_fixed("xbox.bios", bios_data, bios_size, (uint32_t)(-2 * bios_size)); /* Assuming bios_data will be needed for duration of execution * so no free(bios) here. */ /* Mirror ROM from 0xff000000 - 0xffffffff */ for (map_loc = (uint32_t)(-bios_size); map_loc >= 0xff000000; map_loc -= bios_size) { map_bios = g_malloc(sizeof(*map_bios)); memory_region_init_alias(map_bios, NULL, "pci-bios", bios, 0, bios_size); memory_region_add_subregion(rom_memory, map_loc, map_bios); memory_region_set_readonly(map_bios, true); } return; bios_error: fprintf(stderr, "qemu: could not load xbox BIOS '%s'\n", bios_name); exit(1); }
static int64_t load_kernel(void) { int64_t entry, kernel_high; long kernel_size, initrd_size, params_size; ram_addr_t initrd_offset; uint32_t *params_buf; int big_endian; #ifdef TARGET_WORDS_BIGENDIAN big_endian = 1; #else big_endian = 0; #endif kernel_size = load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, NULL, (uint64_t *)&entry, NULL, (uint64_t *)&kernel_high, big_endian, ELF_MACHINE, 1); if (kernel_size >= 0) { if ((entry & ~0x7fffffffULL) == 0x80000000) entry = (int32_t)entry; } else { fprintf(stderr, "qemu: could not load kernel '%s'\n", loaderparams.kernel_filename); exit(1); } /* load initrd */ initrd_size = 0; initrd_offset = 0; if (loaderparams.initrd_filename) { initrd_size = get_image_size (loaderparams.initrd_filename); if (initrd_size > 0) { initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK; if (initrd_offset + initrd_size > ram_size) { fprintf(stderr, "qemu: memory too small for initial ram disk '%s'\n", loaderparams.initrd_filename); exit(1); } initrd_size = load_image_targphys(loaderparams.initrd_filename, initrd_offset, ram_size - initrd_offset); } if (initrd_size == (target_ulong) -1) { fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", loaderparams.initrd_filename); exit(1); } } /* Store command line. */ params_size = 264; params_buf = qemu_malloc(params_size); params_buf[0] = tswap32(ram_size); params_buf[1] = tswap32(0x12345678); if (initrd_size > 0) { snprintf((char *)params_buf + 8, 256, "rd_start=0x%" PRIx64 " rd_size=%li %s", cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size, loaderparams.kernel_cmdline); } else { snprintf((char *)params_buf + 8, 256, "%s", loaderparams.kernel_cmdline); } rom_add_blob_fixed("params", params_buf, params_size, (16 << 20) - 264); return entry; }
static int ppce500_load_device_tree(CPUPPCState *env, PPCE500Params *params, hwaddr addr, hwaddr initrd_base, hwaddr initrd_size) { int ret = -1; uint64_t mem_reg_property[] = { 0, cpu_to_be64(params->ram_size) }; int fdt_size; void *fdt; uint8_t hypercall[16]; uint32_t clock_freq = 400000000; uint32_t tb_freq = 400000000; int i; const char *toplevel_compat = NULL; /* user override */ char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus"; char soc[128]; char mpic[128]; uint32_t mpic_ph; uint32_t msi_ph; char gutil[128]; char pci[128]; char msi[128]; uint32_t *pci_map = NULL; int len; uint32_t pci_ranges[14] = { 0x2000000, 0x0, 0xc0000000, 0x0, 0xc0000000, 0x0, 0x20000000, 0x1000000, 0x0, 0x0, 0x0, 0xe1000000, 0x0, 0x10000, }; QemuOpts *machine_opts; const char *dtb_file = NULL; machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); if (machine_opts) { dtb_file = qemu_opt_get(machine_opts, "dtb"); toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible"); } if (dtb_file) { char *filename; filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file); if (!filename) { goto out; } fdt = load_device_tree(filename, &fdt_size); if (!fdt) { goto out; } goto done; } fdt = create_device_tree(&fdt_size); if (fdt == NULL) { goto out; } /* Manipulate device tree in memory. */ qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 2); qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 2); qemu_devtree_add_subnode(fdt, "/memory"); qemu_devtree_setprop_string(fdt, "/memory", "device_type", "memory"); qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property, sizeof(mem_reg_property)); qemu_devtree_add_subnode(fdt, "/chosen"); if (initrd_size) { ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start", initrd_base); if (ret < 0) { fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); } ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end", (initrd_base + initrd_size)); if (ret < 0) { fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); } } ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", params->kernel_cmdline); if (ret < 0) fprintf(stderr, "couldn't set /chosen/bootargs\n"); if (kvm_enabled()) { /* Read out host's frequencies */ clock_freq = kvmppc_get_clockfreq(); tb_freq = kvmppc_get_tbfreq(); /* indicate KVM hypercall interface */ qemu_devtree_add_subnode(fdt, "/hypervisor"); qemu_devtree_setprop_string(fdt, "/hypervisor", "compatible", "linux,kvm"); kvmppc_get_hypercall(env, hypercall, sizeof(hypercall)); qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions", hypercall, sizeof(hypercall)); } /* Create CPU nodes */ qemu_devtree_add_subnode(fdt, "/cpus"); qemu_devtree_setprop_cell(fdt, "/cpus", "#address-cells", 1); qemu_devtree_setprop_cell(fdt, "/cpus", "#size-cells", 0); /* We need to generate the cpu nodes in reverse order, so Linux can pick the first node as boot node and be happy */ for (i = smp_cpus - 1; i >= 0; i--) { char cpu_name[128]; uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20); for (env = first_cpu; env != NULL; env = env->next_cpu) { if (env->cpu_index == i) { break; } } if (!env) { continue; } snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", env->cpu_index); qemu_devtree_add_subnode(fdt, cpu_name); qemu_devtree_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq); qemu_devtree_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq); qemu_devtree_setprop_string(fdt, cpu_name, "device_type", "cpu"); qemu_devtree_setprop_cell(fdt, cpu_name, "reg", env->cpu_index); qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-line-size", env->dcache_line_size); qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-line-size", env->icache_line_size); qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000); qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000); qemu_devtree_setprop_cell(fdt, cpu_name, "bus-frequency", 0); if (env->cpu_index) { qemu_devtree_setprop_string(fdt, cpu_name, "status", "disabled"); qemu_devtree_setprop_string(fdt, cpu_name, "enable-method", "spin-table"); qemu_devtree_setprop_u64(fdt, cpu_name, "cpu-release-addr", cpu_release_addr); } else { qemu_devtree_setprop_string(fdt, cpu_name, "status", "okay"); } } qemu_devtree_add_subnode(fdt, "/aliases"); /* XXX These should go into their respective devices' code */ snprintf(soc, sizeof(soc), "/soc@%llx", MPC8544_CCSRBAR_BASE); qemu_devtree_add_subnode(fdt, soc); qemu_devtree_setprop_string(fdt, soc, "device_type", "soc"); qemu_devtree_setprop(fdt, soc, "compatible", compatible_sb, sizeof(compatible_sb)); qemu_devtree_setprop_cell(fdt, soc, "#address-cells", 1); qemu_devtree_setprop_cell(fdt, soc, "#size-cells", 1); qemu_devtree_setprop_cells(fdt, soc, "ranges", 0x0, MPC8544_CCSRBAR_BASE >> 32, MPC8544_CCSRBAR_BASE, MPC8544_CCSRBAR_SIZE); /* XXX should contain a reasonable value */ qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0); snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET); qemu_devtree_add_subnode(fdt, mpic); qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic"); qemu_devtree_setprop_string(fdt, mpic, "compatible", "chrp,open-pic"); qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET, 0x40000); qemu_devtree_setprop_cell(fdt, mpic, "#address-cells", 0); qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 2); mpic_ph = qemu_devtree_alloc_phandle(fdt); qemu_devtree_setprop_cell(fdt, mpic, "phandle", mpic_ph); qemu_devtree_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph); qemu_devtree_setprop(fdt, mpic, "interrupt-controller", NULL, 0); /* * We have to generate ser1 first, because Linux takes the first * device it finds in the dt as serial output device. And we generate * devices in reverse order to the dt. */ dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET, soc, mpic, "serial1", 1, false); dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET, soc, mpic, "serial0", 0, true); snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc, MPC8544_UTIL_OFFSET); qemu_devtree_add_subnode(fdt, gutil); qemu_devtree_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts"); qemu_devtree_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000); qemu_devtree_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0); snprintf(msi, sizeof(msi), "/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET); qemu_devtree_add_subnode(fdt, msi); qemu_devtree_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi"); qemu_devtree_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200); msi_ph = qemu_devtree_alloc_phandle(fdt); qemu_devtree_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100); qemu_devtree_setprop_phandle(fdt, msi, "interrupt-parent", mpic); qemu_devtree_setprop_cells(fdt, msi, "interrupts", 0xe0, 0x0, 0xe1, 0x0, 0xe2, 0x0, 0xe3, 0x0, 0xe4, 0x0, 0xe5, 0x0, 0xe6, 0x0, 0xe7, 0x0); qemu_devtree_setprop_cell(fdt, msi, "phandle", msi_ph); qemu_devtree_setprop_cell(fdt, msi, "linux,phandle", msi_ph); snprintf(pci, sizeof(pci), "/pci@%llx", MPC8544_PCI_REGS_BASE); qemu_devtree_add_subnode(fdt, pci); qemu_devtree_setprop_cell(fdt, pci, "cell-index", 0); qemu_devtree_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci"); qemu_devtree_setprop_string(fdt, pci, "device_type", "pci"); qemu_devtree_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0, 0x0, 0x7); pci_map = pci_map_create(fdt, qemu_devtree_get_phandle(fdt, mpic), params->pci_first_slot, params->pci_nr_slots, &len); qemu_devtree_setprop(fdt, pci, "interrupt-map", pci_map, len); qemu_devtree_setprop_phandle(fdt, pci, "interrupt-parent", mpic); qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2); qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255); for (i = 0; i < 14; i++) { pci_ranges[i] = cpu_to_be32(pci_ranges[i]); } qemu_devtree_setprop_cell(fdt, pci, "fsl,msi", msi_ph); qemu_devtree_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges)); qemu_devtree_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32, MPC8544_PCI_REGS_BASE, 0, 0x1000); qemu_devtree_setprop_cell(fdt, pci, "clock-frequency", 66666666); qemu_devtree_setprop_cell(fdt, pci, "#interrupt-cells", 1); qemu_devtree_setprop_cell(fdt, pci, "#size-cells", 2); qemu_devtree_setprop_cell(fdt, pci, "#address-cells", 3); qemu_devtree_setprop_string(fdt, "/aliases", "pci0", pci); params->fixup_devtree(params, fdt); if (toplevel_compat) { qemu_devtree_setprop(fdt, "/", "compatible", toplevel_compat, strlen(toplevel_compat) + 1); } done: qemu_devtree_dumpdtb(fdt, fdt_size); ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); if (ret < 0) { goto out; } g_free(fdt); ret = fdt_size; out: g_free(pci_map); return ret; }
static int mpc8544_load_device_tree(target_phys_addr_t addr, uint32_t ramsize, target_phys_addr_t initrd_base, target_phys_addr_t initrd_size, const char *kernel_cmdline) { int ret = -1; #ifdef CONFIG_FDT uint32_t mem_reg_property[] = {0, ramsize}; char *filename; int fdt_size; void *fdt; filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); if (!filename) { goto out; } fdt = load_device_tree(filename, &fdt_size); qemu_free(filename); if (fdt == NULL) { goto out; } /* Manipulate device tree in memory. */ ret = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property, sizeof(mem_reg_property)); if (ret < 0) fprintf(stderr, "couldn't set /memory/reg\n"); ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start", initrd_base); if (ret < 0) fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end", (initrd_base + initrd_size)); if (ret < 0) fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline); if (ret < 0) fprintf(stderr, "couldn't set /chosen/bootargs\n"); if (kvm_enabled()) { struct dirent *dirp; DIR *dp; char buf[128]; if ((dp = opendir("/proc/device-tree/cpus/")) == NULL) { printf("Can't open directory /proc/device-tree/cpus/\n"); ret = -1; goto out; } buf[0] = '\0'; while ((dirp = readdir(dp)) != NULL) { if (strncmp(dirp->d_name, "PowerPC", 7) == 0) { snprintf(buf, 128, "/cpus/%s", dirp->d_name); break; } } closedir(dp); if (buf[0] == '\0') { printf("Unknow host!\n"); ret = -1; goto out; } mpc8544_copy_soc_cell(fdt, buf, "clock-frequency"); mpc8544_copy_soc_cell(fdt, buf, "timebase-frequency"); } ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); qemu_free(fdt); out: #endif return ret; }
static int bamboo_load_device_tree(hwaddr addr, uint32_t ramsize, hwaddr initrd_base, hwaddr initrd_size, const char *kernel_cmdline) { int ret = -1; uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(ramsize) }; char *filename; int fdt_size; void *fdt; uint32_t tb_freq = 400000000; uint32_t clock_freq = 400000000; filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); if (!filename) { goto out; } fdt = load_device_tree(filename, &fdt_size); g_free(filename); if (fdt == NULL) { goto out; } /* Manipulate device tree in memory. */ ret = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property, sizeof(mem_reg_property)); if (ret < 0) fprintf(stderr, "couldn't set /memory/reg\n"); ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start", initrd_base); if (ret < 0) fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end", (initrd_base + initrd_size)); if (ret < 0) fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline); if (ret < 0) fprintf(stderr, "couldn't set /chosen/bootargs\n"); /* Copy data from the host device tree into the guest. Since the guest can * directly access the timebase without host involvement, we must expose * the correct frequencies. */ if (kvm_enabled()) { tb_freq = kvmppc_get_tbfreq(); clock_freq = kvmppc_get_clockfreq(); } qemu_devtree_setprop_cell(fdt, "/cpus/cpu@0", "clock-frequency", clock_freq); qemu_devtree_setprop_cell(fdt, "/cpus/cpu@0", "timebase-frequency", tb_freq); rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); g_free(fdt); return 0; out: return ret; }
static void r2d_init(ram_addr_t ram_size, const char *boot_device, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { CPUState *env; struct SH7750State *s; ram_addr_t sdram_addr; qemu_irq *irq; DriveInfo *dinfo; int i; if (!cpu_model) cpu_model = "SH7751R"; env = cpu_init(cpu_model); if (!env) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } /* Allocate memory space */ sdram_addr = qemu_ram_alloc(NULL, "r2d.sdram", SDRAM_SIZE); cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE, sdram_addr); /* Register peripherals */ s = sh7750_init(env); irq = r2d_fpga_init(0x04000000, sh7750_irl(s)); sh_pci_register_bus(r2d_pci_set_irq, r2d_pci_map_irq, irq, 0, 4); sm501_init(0x10000000, SM501_VRAM_SIZE, irq[SM501], serial_hds[2]); /* onboard CF (True IDE mode, Master only). */ dinfo = drive_get(IF_IDE, 0, 0); mmio_ide_init(0x14001000, 0x1400080c, irq[CF_IDE], 1, dinfo, NULL); /* onboard flash memory */ dinfo = drive_get(IF_PFLASH, 0, 0); pflash_cfi02_register(0x0, qemu_ram_alloc(NULL, "r2d.flash", FLASH_SIZE), dinfo ? dinfo->bdrv : NULL, (16 * 1024), FLASH_SIZE >> 16, 1, 4, 0x0000, 0x0000, 0x0000, 0x0000, 0x555, 0x2aa, 0); /* NIC: rtl8139 on-board, and 2 slots. */ for (i = 0; i < nb_nics; i++) pci_nic_init_nofail(&nd_table[i], "rtl8139", i==0 ? "2" : NULL); /* USB keyboard */ usbdevice_create("keyboard"); /* Todo: register on board registers */ memset(&boot_params, 0, sizeof(boot_params)); if (kernel_filename) { int kernel_size; kernel_size = load_image_targphys(kernel_filename, SDRAM_BASE + LINUX_LOAD_OFFSET, INITRD_LOAD_OFFSET - LINUX_LOAD_OFFSET); if (kernel_size < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); exit(1); } /* initialization which should be done by firmware */ stl_phys(SH7750_BCR1, 1<<3); /* cs3 SDRAM */ stw_phys(SH7750_BCR2, 3<<(3*2)); /* cs3 32bit */ env->pc = (SDRAM_BASE + LINUX_LOAD_OFFSET) | 0xa0000000; /* Start from P2 area */ } if (initrd_filename) { int initrd_size; initrd_size = load_image_targphys(initrd_filename, SDRAM_BASE + INITRD_LOAD_OFFSET, SDRAM_SIZE - INITRD_LOAD_OFFSET); if (initrd_size < 0) { fprintf(stderr, "qemu: could not load initrd '%s'\n", initrd_filename); exit(1); } /* initialization which should be done by firmware */ boot_params.loader_type = 1; boot_params.initrd_start = INITRD_LOAD_OFFSET; boot_params.initrd_size = initrd_size; } if (kernel_cmdline) { strncpy(boot_params.kernel_cmdline, kernel_cmdline, sizeof(boot_params.kernel_cmdline)); } rom_add_blob_fixed("boot_params", &boot_params, sizeof(boot_params), SDRAM_BASE + BOOT_PARAMS_OFFSET); }