mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/rth/tags/pull-nios-20170124' into staging
nios2 target support # gpg: Signature made Tue 24 Jan 2017 21:11:47 GMT # gpg: using RSA key 0xAD1270CC4DD0279B # gpg: Good signature from "Richard Henderson <rth7680@gmail.com>" # gpg: aka "Richard Henderson <rth@redhat.com>" # gpg: aka "Richard Henderson <rth@twiddle.net>" # Primary key fingerprint: 9CB1 8DDA F8E8 49AD 2AFC 16A4 AD12 70CC 4DD0 279B * remotes/rth/tags/pull-nios-20170124: nios2: Add support for Nios-II R1 nios2: Add Altera 10M50 GHRD emulation nios2: Add periodic timer emulation nios2: Add IIC interrupt controller emulation nios2: Add usermode binaries emulation nios2: Add disas entries nios2: Add architecture emulation support Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -187,6 +187,14 @@ F: disas/moxie.c
|
||||
F: hw/moxie/
|
||||
F: default-configs/moxie-softmmu.mak
|
||||
|
||||
NiosII
|
||||
M: Chris Wulff <crwulff@gmail.com>
|
||||
M: Marek Vasut <marex@denx.de>
|
||||
S: Maintained
|
||||
F: target/nios2/
|
||||
F: hw/nios2/
|
||||
F: disas/nios2.c
|
||||
|
||||
OpenRISC
|
||||
M: Jia Liu <proljc@gmail.com>
|
||||
S: Maintained
|
||||
|
||||
@@ -63,6 +63,8 @@ int graphic_depth = 32;
|
||||
#define QEMU_ARCH QEMU_ARCH_MIPS
|
||||
#elif defined(TARGET_MOXIE)
|
||||
#define QEMU_ARCH QEMU_ARCH_MOXIE
|
||||
#elif defined(TARGET_NIOS2)
|
||||
#define QEMU_ARCH QEMU_ARCH_NIOS2
|
||||
#elif defined(TARGET_OPENRISC)
|
||||
#define QEMU_ARCH QEMU_ARCH_OPENRISC
|
||||
#elif defined(TARGET_PPC)
|
||||
|
||||
@@ -5935,6 +5935,8 @@ case "$target_name" in
|
||||
;;
|
||||
moxie)
|
||||
;;
|
||||
nios2)
|
||||
;;
|
||||
or32)
|
||||
TARGET_ARCH=openrisc
|
||||
TARGET_BASE_ARCH=openrisc
|
||||
@@ -6140,6 +6142,9 @@ for i in $ARCH $TARGET_BASE_ARCH ; do
|
||||
moxie*)
|
||||
disas_config "MOXIE"
|
||||
;;
|
||||
nios2)
|
||||
disas_config "NIOS2"
|
||||
;;
|
||||
or32)
|
||||
disas_config "OPENRISC"
|
||||
;;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
# Default configuration for nios2-linux-user
|
||||
@@ -0,0 +1,6 @@
|
||||
# Default configuration for nios2-softmmu
|
||||
|
||||
CONFIG_NIOS2=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_ALTERA_TIMER=y
|
||||
@@ -15,6 +15,7 @@ common-obj-$(CONFIG_IA64_DIS) += ia64.o
|
||||
common-obj-$(CONFIG_M68K_DIS) += m68k.o
|
||||
common-obj-$(CONFIG_MICROBLAZE_DIS) += microblaze.o
|
||||
common-obj-$(CONFIG_MIPS_DIS) += mips.o
|
||||
common-obj-$(CONFIG_NIOS2_DIS) += nios2.o
|
||||
common-obj-$(CONFIG_MOXIE_DIS) += moxie.o
|
||||
common-obj-$(CONFIG_PPC_DIS) += ppc.o
|
||||
common-obj-$(CONFIG_S390_DIS) += s390.o
|
||||
|
||||
+3534
File diff suppressed because it is too large
Load Diff
@@ -41,3 +41,4 @@ obj-$(CONFIG_S390_FLIC_KVM) += s390_flic_kvm.o
|
||||
obj-$(CONFIG_ASPEED_SOC) += aspeed_vic.o
|
||||
obj-$(CONFIG_ARM_GIC) += arm_gicv3_cpuif.o
|
||||
obj-$(CONFIG_MIPS_CPS) += mips_gic.o
|
||||
obj-$(CONFIG_NIOS2) += nios2_iic.o
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* QEMU Altera Internal Interrupt Controller.
|
||||
*
|
||||
* Copyright (c) 2012 Chris Wulff <crwulff@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-2.1.html>
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "cpu.h"
|
||||
|
||||
#define TYPE_ALTERA_IIC "altera,iic"
|
||||
#define ALTERA_IIC(obj) \
|
||||
OBJECT_CHECK(AlteraIIC, (obj), TYPE_ALTERA_IIC)
|
||||
|
||||
typedef struct AlteraIIC {
|
||||
SysBusDevice parent_obj;
|
||||
void *cpu;
|
||||
qemu_irq parent_irq;
|
||||
} AlteraIIC;
|
||||
|
||||
static void update_irq(AlteraIIC *pv)
|
||||
{
|
||||
CPUNios2State *env = &((Nios2CPU *)(pv->cpu))->env;
|
||||
|
||||
qemu_set_irq(pv->parent_irq,
|
||||
env->regs[CR_IPENDING] & env->regs[CR_IENABLE]);
|
||||
}
|
||||
|
||||
static void irq_handler(void *opaque, int irq, int level)
|
||||
{
|
||||
AlteraIIC *pv = opaque;
|
||||
CPUNios2State *env = &((Nios2CPU *)(pv->cpu))->env;
|
||||
|
||||
env->regs[CR_IPENDING] &= ~(1 << irq);
|
||||
env->regs[CR_IPENDING] |= !!level << irq;
|
||||
|
||||
update_irq(pv);
|
||||
}
|
||||
|
||||
static void altera_iic_init(Object *obj)
|
||||
{
|
||||
AlteraIIC *pv = ALTERA_IIC(obj);
|
||||
|
||||
qdev_init_gpio_in(DEVICE(pv), irq_handler, 32);
|
||||
sysbus_init_irq(SYS_BUS_DEVICE(obj), &pv->parent_irq);
|
||||
}
|
||||
|
||||
static Property altera_iic_properties[] = {
|
||||
DEFINE_PROP_PTR("cpu", AlteraIIC, cpu),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void altera_iic_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
struct AlteraIIC *pv = ALTERA_IIC(dev);
|
||||
|
||||
if (!pv->cpu) {
|
||||
error_setg(errp, "altera,iic: CPU not connected");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void altera_iic_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->props = altera_iic_properties;
|
||||
/* Reason: pointer property "cpu" */
|
||||
dc->cannot_instantiate_with_device_add_yet = true;
|
||||
dc->realize = altera_iic_realize;
|
||||
}
|
||||
|
||||
static TypeInfo altera_iic_info = {
|
||||
.name = "altera,iic",
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(AlteraIIC),
|
||||
.instance_init = altera_iic_init,
|
||||
.class_init = altera_iic_class_init,
|
||||
};
|
||||
|
||||
static void altera_iic_register(void)
|
||||
{
|
||||
type_register_static(&altera_iic_info);
|
||||
}
|
||||
|
||||
type_init(altera_iic_register)
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Altera 10M50 Nios2 GHRD
|
||||
*
|
||||
* Copyright (c) 2016 Marek Vasut <marek.vasut@gmail.com>
|
||||
*
|
||||
* Based on LabX device code
|
||||
*
|
||||
* Copyright (c) 2012 Chris Wulff <crwulff@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-2.1.html>
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu-common.h"
|
||||
#include "cpu.h"
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/boards.h"
|
||||
#include "exec/memory.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "qemu/config-file.h"
|
||||
|
||||
#include "boot.h"
|
||||
|
||||
#define BINARY_DEVICE_TREE_FILE "10m50-devboard.dtb"
|
||||
|
||||
static void nios2_10m50_ghrd_init(MachineState *machine)
|
||||
{
|
||||
Nios2CPU *cpu;
|
||||
DeviceState *dev;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
MemoryRegion *phys_tcm = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *phys_tcm_alias = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *phys_ram_alias = g_new(MemoryRegion, 1);
|
||||
ram_addr_t tcm_base = 0x0;
|
||||
ram_addr_t tcm_size = 0x1000; /* 1 kiB, but QEMU limit is 4 kiB */
|
||||
ram_addr_t ram_base = 0x08000000;
|
||||
ram_addr_t ram_size = 0x08000000;
|
||||
qemu_irq *cpu_irq, irq[32];
|
||||
int i;
|
||||
|
||||
/* Physical TCM (tb_ram_1k) with alias at 0xc0000000 */
|
||||
memory_region_init_ram(phys_tcm, NULL, "nios2.tcm", tcm_size, &error_abort);
|
||||
memory_region_init_alias(phys_tcm_alias, NULL, "nios2.tcm.alias",
|
||||
phys_tcm, 0, tcm_size);
|
||||
vmstate_register_ram_global(phys_tcm);
|
||||
memory_region_add_subregion(address_space_mem, tcm_base, phys_tcm);
|
||||
memory_region_add_subregion(address_space_mem, 0xc0000000 + tcm_base,
|
||||
phys_tcm_alias);
|
||||
|
||||
/* Physical DRAM with alias at 0xc0000000 */
|
||||
memory_region_init_ram(phys_ram, NULL, "nios2.ram", ram_size, &error_abort);
|
||||
memory_region_init_alias(phys_ram_alias, NULL, "nios2.ram.alias",
|
||||
phys_ram, 0, ram_size);
|
||||
vmstate_register_ram_global(phys_ram);
|
||||
memory_region_add_subregion(address_space_mem, ram_base, phys_ram);
|
||||
memory_region_add_subregion(address_space_mem, 0xc0000000 + ram_base,
|
||||
phys_ram_alias);
|
||||
|
||||
/* Create CPU -- FIXME */
|
||||
cpu = cpu_nios2_init("nios2");
|
||||
|
||||
/* Register: CPU interrupt controller (PIC) */
|
||||
cpu_irq = nios2_cpu_pic_init(cpu);
|
||||
|
||||
/* Register: Internal Interrupt Controller (IIC) */
|
||||
dev = qdev_create(NULL, "altera,iic");
|
||||
qdev_prop_set_ptr(dev, "cpu", cpu);
|
||||
qdev_init_nofail(dev);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irq[0]);
|
||||
for (i = 0; i < 32; i++) {
|
||||
irq[i] = qdev_get_gpio_in(dev, i);
|
||||
}
|
||||
|
||||
/* Register: Altera 16550 UART */
|
||||
serial_mm_init(address_space_mem, 0xf8001600, 2, irq[1], 115200,
|
||||
serial_hds[0], DEVICE_NATIVE_ENDIAN);
|
||||
|
||||
/* Register: Timer sys_clk_timer */
|
||||
dev = qdev_create(NULL, "ALTR.timer");
|
||||
qdev_prop_set_uint32(dev, "clock-frequency", 75 * 1000000);
|
||||
qdev_init_nofail(dev);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xf8001440);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[0]);
|
||||
|
||||
/* Register: Timer sys_clk_timer_1 */
|
||||
dev = qdev_create(NULL, "ALTR.timer");
|
||||
qdev_prop_set_uint32(dev, "clock-frequency", 75 * 1000000);
|
||||
qdev_init_nofail(dev);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xe0000880);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[5]);
|
||||
|
||||
/* Configure new exception vectors and reset CPU for it to take effect. */
|
||||
cpu->reset_addr = 0xd4000000;
|
||||
cpu->exception_addr = 0xc8000120;
|
||||
cpu->fast_tlb_miss_addr = 0xc0000100;
|
||||
|
||||
nios2_load_kernel(cpu, ram_base, ram_size, machine->initrd_filename,
|
||||
BINARY_DEVICE_TREE_FILE, NULL);
|
||||
}
|
||||
|
||||
static void nios2_10m50_ghrd_machine_init(struct MachineClass *mc)
|
||||
{
|
||||
mc->desc = "Altera 10M50 GHRD Nios II design";
|
||||
mc->init = nios2_10m50_ghrd_init;
|
||||
mc->is_default = 1;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("10m50-ghrd", nios2_10m50_ghrd_machine_init);
|
||||
@@ -0,0 +1 @@
|
||||
obj-y = boot.o cpu_pic.o 10m50_devboard.o
|
||||
+223
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Nios2 kernel loader
|
||||
*
|
||||
* Copyright (c) 2016 Marek Vasut <marek.vasut@gmail.com>
|
||||
*
|
||||
* Based on microblaze kernel loader
|
||||
*
|
||||
* Copyright (c) 2012 Peter Crosthwaite <peter.crosthwaite@petalogix.com>
|
||||
* Copyright (c) 2012 PetaLogix
|
||||
* Copyright (c) 2009 Edgar E. Iglesias.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "cpu.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu-common.h"
|
||||
#include "sysemu/device_tree.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/loader.h"
|
||||
#include "elf.h"
|
||||
#include "qemu/cutils.h"
|
||||
|
||||
#include "boot.h"
|
||||
|
||||
#define NIOS2_MAGIC 0x534f494e
|
||||
|
||||
static struct nios2_boot_info {
|
||||
void (*machine_cpu_reset)(Nios2CPU *);
|
||||
uint32_t bootstrap_pc;
|
||||
uint32_t cmdline;
|
||||
uint32_t initrd_start;
|
||||
uint32_t initrd_end;
|
||||
uint32_t fdt;
|
||||
} boot_info;
|
||||
|
||||
static void main_cpu_reset(void *opaque)
|
||||
{
|
||||
Nios2CPU *cpu = opaque;
|
||||
CPUState *cs = CPU(cpu);
|
||||
CPUNios2State *env = &cpu->env;
|
||||
|
||||
cpu_reset(CPU(cpu));
|
||||
|
||||
env->regs[R_ARG0] = NIOS2_MAGIC;
|
||||
env->regs[R_ARG1] = boot_info.initrd_start;
|
||||
env->regs[R_ARG2] = boot_info.fdt;
|
||||
env->regs[R_ARG3] = boot_info.cmdline;
|
||||
|
||||
cpu_set_pc(cs, boot_info.bootstrap_pc);
|
||||
if (boot_info.machine_cpu_reset) {
|
||||
boot_info.machine_cpu_reset(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
|
||||
{
|
||||
return addr - 0xc0000000LL;
|
||||
}
|
||||
|
||||
static int nios2_load_dtb(struct nios2_boot_info bi, const uint32_t ramsize,
|
||||
const char *kernel_cmdline, const char *dtb_filename)
|
||||
{
|
||||
int fdt_size;
|
||||
void *fdt = NULL;
|
||||
int r;
|
||||
|
||||
if (dtb_filename) {
|
||||
fdt = load_device_tree(dtb_filename, &fdt_size);
|
||||
}
|
||||
if (!fdt) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (kernel_cmdline) {
|
||||
r = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
|
||||
kernel_cmdline);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "couldn't set /chosen/bootargs\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (bi.initrd_start) {
|
||||
qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
|
||||
translate_kernel_address(NULL, bi.initrd_start));
|
||||
|
||||
qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
|
||||
translate_kernel_address(NULL, bi.initrd_end));
|
||||
}
|
||||
|
||||
cpu_physical_memory_write(bi.fdt, fdt, fdt_size);
|
||||
return fdt_size;
|
||||
}
|
||||
|
||||
void nios2_load_kernel(Nios2CPU *cpu, hwaddr ddr_base,
|
||||
uint32_t ramsize,
|
||||
const char *initrd_filename,
|
||||
const char *dtb_filename,
|
||||
void (*machine_cpu_reset)(Nios2CPU *))
|
||||
{
|
||||
QemuOpts *machine_opts;
|
||||
const char *kernel_filename;
|
||||
const char *kernel_cmdline;
|
||||
const char *dtb_arg;
|
||||
char *filename = NULL;
|
||||
|
||||
machine_opts = qemu_get_machine_opts();
|
||||
kernel_filename = qemu_opt_get(machine_opts, "kernel");
|
||||
kernel_cmdline = qemu_opt_get(machine_opts, "append");
|
||||
dtb_arg = qemu_opt_get(machine_opts, "dtb");
|
||||
/* default to pcbios dtb as passed by machine_init */
|
||||
if (!dtb_arg) {
|
||||
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_filename);
|
||||
}
|
||||
|
||||
boot_info.machine_cpu_reset = machine_cpu_reset;
|
||||
qemu_register_reset(main_cpu_reset, cpu);
|
||||
|
||||
if (kernel_filename) {
|
||||
int kernel_size, fdt_size;
|
||||
uint64_t entry, low, high;
|
||||
uint32_t base32;
|
||||
int big_endian = 0;
|
||||
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
big_endian = 1;
|
||||
#endif
|
||||
|
||||
/* Boots a kernel elf binary. */
|
||||
kernel_size = load_elf(kernel_filename, NULL, NULL,
|
||||
&entry, &low, &high,
|
||||
big_endian, EM_ALTERA_NIOS2, 0, 0);
|
||||
base32 = entry;
|
||||
if (base32 == 0xc0000000) {
|
||||
kernel_size = load_elf(kernel_filename, translate_kernel_address,
|
||||
NULL, &entry, NULL, NULL,
|
||||
big_endian, EM_ALTERA_NIOS2, 0, 0);
|
||||
}
|
||||
|
||||
/* Always boot into physical ram. */
|
||||
boot_info.bootstrap_pc = ddr_base + 0xc0000000 + (entry & 0x07ffffff);
|
||||
|
||||
/* If it wasn't an ELF image, try an u-boot image. */
|
||||
if (kernel_size < 0) {
|
||||
hwaddr uentry, loadaddr;
|
||||
|
||||
kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0,
|
||||
NULL, NULL);
|
||||
boot_info.bootstrap_pc = uentry;
|
||||
high = loadaddr + kernel_size;
|
||||
}
|
||||
|
||||
/* Not an ELF image nor an u-boot image, try a RAW image. */
|
||||
if (kernel_size < 0) {
|
||||
kernel_size = load_image_targphys(kernel_filename, ddr_base,
|
||||
ram_size);
|
||||
boot_info.bootstrap_pc = ddr_base;
|
||||
high = ddr_base + kernel_size;
|
||||
}
|
||||
|
||||
high = ROUND_UP(high, 1024 * 1024);
|
||||
|
||||
/* If initrd is available, it goes after the kernel, aligned to 1M. */
|
||||
if (initrd_filename) {
|
||||
int initrd_size;
|
||||
uint32_t initrd_offset;
|
||||
|
||||
boot_info.initrd_start = high;
|
||||
initrd_offset = boot_info.initrd_start - ddr_base;
|
||||
|
||||
initrd_size = load_ramdisk(initrd_filename,
|
||||
boot_info.initrd_start,
|
||||
ram_size - initrd_offset);
|
||||
if (initrd_size < 0) {
|
||||
initrd_size = load_image_targphys(initrd_filename,
|
||||
boot_info.initrd_start,
|
||||
ram_size - initrd_offset);
|
||||
}
|
||||
if (initrd_size < 0) {
|
||||
error_report("qemu: could not load initrd '%s'",
|
||||
initrd_filename);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
high += initrd_size;
|
||||
}
|
||||
high = ROUND_UP(high, 4);
|
||||
boot_info.initrd_end = high;
|
||||
|
||||
/* Device tree must be placed right after initrd (if available) */
|
||||
boot_info.fdt = high;
|
||||
fdt_size = nios2_load_dtb(boot_info, ram_size, kernel_cmdline,
|
||||
/* Preference a -dtb argument */
|
||||
dtb_arg ? dtb_arg : filename);
|
||||
high += fdt_size;
|
||||
|
||||
/* Kernel command is at the end, 4k aligned. */
|
||||
boot_info.cmdline = ROUND_UP(high, 4096);
|
||||
if (kernel_cmdline && strlen(kernel_cmdline)) {
|
||||
pstrcpy_targphys("cmdline", boot_info.cmdline, 256, kernel_cmdline);
|
||||
}
|
||||
}
|
||||
g_free(filename);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#ifndef NIOS2_BOOT_H
|
||||
#define NIOS2_BOOT_H
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "cpu.h"
|
||||
|
||||
void nios2_load_kernel(Nios2CPU *cpu, hwaddr ddr_base, uint32_t ramsize,
|
||||
const char *initrd_filename, const char *dtb_filename,
|
||||
void (*machine_cpu_reset)(Nios2CPU *));
|
||||
|
||||
#endif /* NIOS2_BOOT_H */
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Altera Nios2 CPU PIC
|
||||
*
|
||||
* Copyright (c) 2016 Marek Vasut <marek.vasut@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-2.1.html>
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu-common.h"
|
||||
#include "cpu.h"
|
||||
|
||||
#include "qemu/config-file.h"
|
||||
|
||||
#include "boot.h"
|
||||
|
||||
static void nios2_pic_cpu_handler(void *opaque, int irq, int level)
|
||||
{
|
||||
Nios2CPU *cpu = opaque;
|
||||
CPUNios2State *env = &cpu->env;
|
||||
CPUState *cs = CPU(cpu);
|
||||
int type = irq ? CPU_INTERRUPT_NMI : CPU_INTERRUPT_HARD;
|
||||
|
||||
if (type == CPU_INTERRUPT_HARD) {
|
||||
env->irq_pending = level;
|
||||
|
||||
if (level && (env->regs[CR_STATUS] & CR_STATUS_PIE)) {
|
||||
env->irq_pending = 0;
|
||||
cpu_interrupt(cs, type);
|
||||
} else if (!level) {
|
||||
env->irq_pending = 0;
|
||||
cpu_reset_interrupt(cs, type);
|
||||
}
|
||||
} else {
|
||||
if (level) {
|
||||
cpu_interrupt(cs, type);
|
||||
} else {
|
||||
cpu_reset_interrupt(cs, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nios2_check_interrupts(CPUNios2State *env)
|
||||
{
|
||||
Nios2CPU *cpu = nios2_env_get_cpu(env);
|
||||
CPUState *cs = CPU(cpu);
|
||||
|
||||
if (env->irq_pending) {
|
||||
env->irq_pending = 0;
|
||||
cpu_interrupt(cs, CPU_INTERRUPT_HARD);
|
||||
}
|
||||
}
|
||||
|
||||
qemu_irq *nios2_cpu_pic_init(Nios2CPU *cpu)
|
||||
{
|
||||
return qemu_allocate_irqs(nios2_pic_cpu_handler, cpu, 2);
|
||||
}
|
||||
@@ -18,6 +18,7 @@ common-obj-$(CONFIG_IMX) += imx_gpt.o
|
||||
common-obj-$(CONFIG_LM32) += lm32_timer.o
|
||||
common-obj-$(CONFIG_MILKYMIST) += milkymist-sysctl.o
|
||||
|
||||
obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o
|
||||
obj-$(CONFIG_EXYNOS4) += exynos4210_mct.o
|
||||
obj-$(CONFIG_EXYNOS4) += exynos4210_pwm.o
|
||||
obj-$(CONFIG_EXYNOS4) += exynos4210_rtc.o
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* QEMU model of the Altera timer.
|
||||
*
|
||||
* Copyright (c) 2012 Chris Wulff <crwulff@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-2.1.html>
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/ptimer.h"
|
||||
|
||||
#define R_STATUS 0
|
||||
#define R_CONTROL 1
|
||||
#define R_PERIODL 2
|
||||
#define R_PERIODH 3
|
||||
#define R_SNAPL 4
|
||||
#define R_SNAPH 5
|
||||
#define R_MAX 6
|
||||
|
||||
#define STATUS_TO 0x0001
|
||||
#define STATUS_RUN 0x0002
|
||||
|
||||
#define CONTROL_ITO 0x0001
|
||||
#define CONTROL_CONT 0x0002
|
||||
#define CONTROL_START 0x0004
|
||||
#define CONTROL_STOP 0x0008
|
||||
|
||||
#define TYPE_ALTERA_TIMER "ALTR.timer"
|
||||
#define ALTERA_TIMER(obj) \
|
||||
OBJECT_CHECK(AlteraTimer, (obj), TYPE_ALTERA_TIMER)
|
||||
|
||||
typedef struct AlteraTimer {
|
||||
SysBusDevice busdev;
|
||||
MemoryRegion mmio;
|
||||
qemu_irq irq;
|
||||
uint32_t freq_hz;
|
||||
QEMUBH *bh;
|
||||
ptimer_state *ptimer;
|
||||
uint32_t regs[R_MAX];
|
||||
} AlteraTimer;
|
||||
|
||||
static int timer_irq_state(AlteraTimer *t)
|
||||
{
|
||||
bool irq = (t->regs[R_STATUS] & STATUS_TO) &&
|
||||
(t->regs[R_CONTROL] & CONTROL_ITO);
|
||||
return irq;
|
||||
}
|
||||
|
||||
static uint64_t timer_read(void *opaque, hwaddr addr,
|
||||
unsigned int size)
|
||||
{
|
||||
AlteraTimer *t = opaque;
|
||||
uint64_t r = 0;
|
||||
|
||||
addr >>= 2;
|
||||
|
||||
switch (addr) {
|
||||
case R_CONTROL:
|
||||
r = t->regs[R_CONTROL] & (CONTROL_ITO | CONTROL_CONT);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (addr < ARRAY_SIZE(t->regs)) {
|
||||
r = t->regs[addr];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void timer_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned int size)
|
||||
{
|
||||
AlteraTimer *t = opaque;
|
||||
uint64_t tvalue;
|
||||
uint32_t count = 0;
|
||||
int irqState = timer_irq_state(t);
|
||||
|
||||
addr >>= 2;
|
||||
|
||||
switch (addr) {
|
||||
case R_STATUS:
|
||||
/* The timeout bit is cleared by writing the status register. */
|
||||
t->regs[R_STATUS] &= ~STATUS_TO;
|
||||
break;
|
||||
|
||||
case R_CONTROL:
|
||||
t->regs[R_CONTROL] = value & (CONTROL_ITO | CONTROL_CONT);
|
||||
if ((value & CONTROL_START) &&
|
||||
!(t->regs[R_STATUS] & STATUS_RUN)) {
|
||||
ptimer_run(t->ptimer, 1);
|
||||
t->regs[R_STATUS] |= STATUS_RUN;
|
||||
}
|
||||
if ((value & CONTROL_STOP) && (t->regs[R_STATUS] & STATUS_RUN)) {
|
||||
ptimer_stop(t->ptimer);
|
||||
t->regs[R_STATUS] &= ~STATUS_RUN;
|
||||
}
|
||||
break;
|
||||
|
||||
case R_PERIODL:
|
||||
case R_PERIODH:
|
||||
t->regs[addr] = value & 0xFFFF;
|
||||
if (t->regs[R_STATUS] & STATUS_RUN) {
|
||||
ptimer_stop(t->ptimer);
|
||||
t->regs[R_STATUS] &= ~STATUS_RUN;
|
||||
}
|
||||
tvalue = (t->regs[R_PERIODH] << 16) | t->regs[R_PERIODL];
|
||||
ptimer_set_limit(t->ptimer, tvalue + 1, 1);
|
||||
break;
|
||||
|
||||
case R_SNAPL:
|
||||
case R_SNAPH:
|
||||
count = ptimer_get_count(t->ptimer);
|
||||
t->regs[R_SNAPL] = count & 0xFFFF;
|
||||
t->regs[R_SNAPH] = count >> 16;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (irqState != timer_irq_state(t)) {
|
||||
qemu_set_irq(t->irq, timer_irq_state(t));
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps timer_ops = {
|
||||
.read = timer_read,
|
||||
.write = timer_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 4
|
||||
}
|
||||
};
|
||||
|
||||
static void timer_hit(void *opaque)
|
||||
{
|
||||
AlteraTimer *t = opaque;
|
||||
const uint64_t tvalue = (t->regs[R_PERIODH] << 16) | t->regs[R_PERIODL];
|
||||
|
||||
t->regs[R_STATUS] |= STATUS_TO;
|
||||
|
||||
ptimer_set_limit(t->ptimer, tvalue + 1, 1);
|
||||
|
||||
if (!(t->regs[R_CONTROL] & CONTROL_CONT)) {
|
||||
t->regs[R_STATUS] &= ~STATUS_RUN;
|
||||
ptimer_set_count(t->ptimer, tvalue);
|
||||
} else {
|
||||
ptimer_run(t->ptimer, 1);
|
||||
}
|
||||
|
||||
qemu_set_irq(t->irq, timer_irq_state(t));
|
||||
}
|
||||
|
||||
static void altera_timer_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
AlteraTimer *t = ALTERA_TIMER(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
|
||||
if (t->freq_hz == 0) {
|
||||
error_setg(errp, "\"clock-frequency\" property must be provided.");
|
||||
return;
|
||||
}
|
||||
|
||||
t->bh = qemu_bh_new(timer_hit, t);
|
||||
t->ptimer = ptimer_init(t->bh, PTIMER_POLICY_DEFAULT);
|
||||
ptimer_set_freq(t->ptimer, t->freq_hz);
|
||||
|
||||
memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t,
|
||||
TYPE_ALTERA_TIMER, R_MAX * sizeof(uint32_t));
|
||||
sysbus_init_mmio(sbd, &t->mmio);
|
||||
}
|
||||
|
||||
static void altera_timer_init(Object *obj)
|
||||
{
|
||||
AlteraTimer *t = ALTERA_TIMER(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
sysbus_init_irq(sbd, &t->irq);
|
||||
}
|
||||
|
||||
static void altera_timer_reset(DeviceState *dev)
|
||||
{
|
||||
AlteraTimer *t = ALTERA_TIMER(dev);
|
||||
|
||||
ptimer_stop(t->ptimer);
|
||||
ptimer_set_limit(t->ptimer, 0xffffffff, 1);
|
||||
memset(t->regs, 0, ARRAY_SIZE(t->regs));
|
||||
}
|
||||
|
||||
static Property altera_timer_properties[] = {
|
||||
DEFINE_PROP_UINT32("clock-frequency", AlteraTimer, freq_hz, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void altera_timer_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = altera_timer_realize;
|
||||
dc->props = altera_timer_properties;
|
||||
dc->reset = altera_timer_reset;
|
||||
}
|
||||
|
||||
static const TypeInfo altera_timer_info = {
|
||||
.name = TYPE_ALTERA_TIMER,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(AlteraTimer),
|
||||
.instance_init = altera_timer_init,
|
||||
.class_init = altera_timer_class_init,
|
||||
};
|
||||
|
||||
static void altera_timer_register(void)
|
||||
{
|
||||
type_register_static(&altera_timer_info);
|
||||
}
|
||||
|
||||
type_init(altera_timer_register)
|
||||
@@ -222,6 +222,10 @@ enum bfd_architecture
|
||||
bfd_arch_ia64, /* HP/Intel ia64 */
|
||||
#define bfd_mach_ia64_elf64 64
|
||||
#define bfd_mach_ia64_elf32 32
|
||||
bfd_arch_nios2, /* Nios II */
|
||||
#define bfd_mach_nios2 0
|
||||
#define bfd_mach_nios2r1 1
|
||||
#define bfd_mach_nios2r2 2
|
||||
bfd_arch_lm32, /* Lattice Mico32 */
|
||||
#define bfd_mach_lm32 1
|
||||
bfd_arch_last
|
||||
@@ -415,6 +419,8 @@ int print_insn_crisv10 (bfd_vma, disassemble_info*);
|
||||
int print_insn_microblaze (bfd_vma, disassemble_info*);
|
||||
int print_insn_ia64 (bfd_vma, disassemble_info*);
|
||||
int print_insn_lm32 (bfd_vma, disassemble_info*);
|
||||
int print_insn_big_nios2 (bfd_vma, disassemble_info*);
|
||||
int print_insn_little_nios2 (bfd_vma, disassemble_info*);
|
||||
|
||||
#if 0
|
||||
/* Fetch the disassembler for a given BFD, if that support is available. */
|
||||
|
||||
@@ -126,6 +126,8 @@ typedef int64_t Elf64_Sxword;
|
||||
*/
|
||||
#define EM_S390_OLD 0xA390
|
||||
|
||||
#define EM_ALTERA_NIOS2 113 /* Altera Nios II soft-core processor */
|
||||
|
||||
#define EM_MICROBLAZE 189
|
||||
#define EM_MICROBLAZE_OLD 0xBAAB
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ enum {
|
||||
QEMU_ARCH_UNICORE32 = (1 << 14),
|
||||
QEMU_ARCH_MOXIE = (1 << 15),
|
||||
QEMU_ARCH_TRICORE = (1 << 16),
|
||||
QEMU_ARCH_NIOS2 = (1 << 17),
|
||||
};
|
||||
|
||||
extern const uint32_t arch_type;
|
||||
|
||||
@@ -967,6 +967,63 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMBState *env
|
||||
|
||||
#endif /* TARGET_MICROBLAZE */
|
||||
|
||||
#ifdef TARGET_NIOS2
|
||||
|
||||
#define ELF_START_MMAP 0x80000000
|
||||
|
||||
#define elf_check_arch(x) ((x) == EM_ALTERA_NIOS2)
|
||||
|
||||
#define ELF_CLASS ELFCLASS32
|
||||
#define ELF_ARCH EM_ALTERA_NIOS2
|
||||
|
||||
static void init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||
{
|
||||
regs->ea = infop->entry;
|
||||
regs->sp = infop->start_stack;
|
||||
regs->estatus = 0x3;
|
||||
}
|
||||
|
||||
#define ELF_EXEC_PAGESIZE 4096
|
||||
|
||||
#define USE_ELF_CORE_DUMP
|
||||
#define ELF_NREG 49
|
||||
typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
|
||||
|
||||
/* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs. */
|
||||
static void elf_core_copy_regs(target_elf_gregset_t *regs,
|
||||
const CPUNios2State *env)
|
||||
{
|
||||
int i;
|
||||
|
||||
(*regs)[0] = -1;
|
||||
for (i = 1; i < 8; i++) /* r0-r7 */
|
||||
(*regs)[i] = tswapreg(env->regs[i + 7]);
|
||||
|
||||
for (i = 8; i < 16; i++) /* r8-r15 */
|
||||
(*regs)[i] = tswapreg(env->regs[i - 8]);
|
||||
|
||||
for (i = 16; i < 24; i++) /* r16-r23 */
|
||||
(*regs)[i] = tswapreg(env->regs[i + 7]);
|
||||
(*regs)[24] = -1; /* R_ET */
|
||||
(*regs)[25] = -1; /* R_BT */
|
||||
(*regs)[26] = tswapreg(env->regs[R_GP]);
|
||||
(*regs)[27] = tswapreg(env->regs[R_SP]);
|
||||
(*regs)[28] = tswapreg(env->regs[R_FP]);
|
||||
(*regs)[29] = tswapreg(env->regs[R_EA]);
|
||||
(*regs)[30] = -1; /* R_SSTATUS */
|
||||
(*regs)[31] = tswapreg(env->regs[R_RA]);
|
||||
|
||||
(*regs)[32] = tswapreg(env->regs[R_PC]);
|
||||
|
||||
(*regs)[33] = -1; /* R_STATUS */
|
||||
(*regs)[34] = tswapreg(env->regs[CR_ESTATUS]);
|
||||
|
||||
for (i = 35; i < 49; i++) /* ... */
|
||||
(*regs)[i] = -1;
|
||||
}
|
||||
|
||||
#endif /* TARGET_NIOS2 */
|
||||
|
||||
#ifdef TARGET_OPENRISC
|
||||
|
||||
#define ELF_START_MMAP 0x08000000
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user