import Unicorn2

This commit is contained in:
Nguyen Anh Quynh
2021-10-03 22:14:44 +08:00
parent 772558119a
commit aaaea14214
837 changed files with 368717 additions and 200912 deletions

View File

@@ -1,4 +0,0 @@
devices-dirs-$(CONFIG_SOFTMMU) += intc/
devices-dirs-y += core/
common-obj-y += $(devices-dirs-y)
obj-y += $(devices-dirs-y)

View File

@@ -1,2 +0,0 @@
obj-y += tosa.o
obj-y += virt.o

View File

@@ -1,45 +0,0 @@
/* vim:set shiftwidth=4 ts=4 et: */
/*
* PXA255 Sharp Zaurus SL-6000 PDA platform
*
* Copyright (c) 2008 Dmitry Baryshkov
*
* Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org>
* This code is licensed under the GNU GPL v2.
*
* Contributions after 2012-01-13 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*/
#include "hw/hw.h"
#include "hw/arm/arm.h"
#include "hw/boards.h"
#include "exec/address-spaces.h"
static int tosa_init(struct uc_struct *uc, MachineState *machine)
{
if (uc->mode & UC_MODE_MCLASS)
uc->cpu = (CPUState *)cpu_arm_init(uc, "cortex-m3");
else if (uc->mode & UC_MODE_ARM926)
uc->cpu = (CPUState *)cpu_arm_init(uc, "arm926");
else if (uc->mode & UC_MODE_ARM946)
uc->cpu = (CPUState *)cpu_arm_init(uc, "arm946");
else if (uc->mode & UC_MODE_ARM1176)
uc->cpu = (CPUState *)cpu_arm_init(uc, "arm1176");
else
uc->cpu = (CPUState *)cpu_arm_init(uc, "cortex-a15");
return 0;
}
void tosa_machine_init(struct uc_struct *uc)
{
static QEMUMachine tosapda_machine = { 0 };
tosapda_machine.name = "tosa",
tosapda_machine.init = tosa_init,
tosapda_machine.is_default = 1,
tosapda_machine.arch = UC_ARCH_ARM,
qemu_register_machine(uc, &tosapda_machine, TYPE_MACHINE, NULL);
}

View File

@@ -1,74 +0,0 @@
/*
* ARM mach-virt emulation
*
* Copyright (c) 2013 Linaro Limited
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2 or later, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* Emulate a virtual board which works by passing Linux all the information
* it needs about what devices are present via the device tree.
* There are some restrictions about what we can do here:
* + we can only present devices whose Linux drivers will work based
* purely on the device tree with no platform data at all
* + we want to present a very stripped-down minimalist platform,
* both because this reduces the security attack surface from the guest
* and also because it reduces our exposure to being broken when
* the kernel updates its device tree bindings and requires further
* information in a device binding that we aren't providing.
* This is essentially the same approach kvmtool uses.
*/
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh, 2015 */
#include "hw/arm/arm.h"
#include "hw/boards.h"
#include "exec/address-spaces.h"
static int machvirt_init(struct uc_struct *uc, MachineState *machine)
{
const char *cpu_model = machine->cpu_model;
int n;
if (!cpu_model) {
cpu_model = "cortex-a57"; // ARM64
}
for (n = 0; n < smp_cpus; n++) {
Object *cpuobj;
ObjectClass *oc = cpu_class_by_name(uc, TYPE_ARM_CPU, cpu_model);
if (!oc) {
fprintf(stderr, "Unable to find CPU definition\n");
return -1;
}
cpuobj = object_new(uc, object_class_get_name(oc));
uc->cpu = (CPUState *)cpuobj;
object_property_set_bool(uc, cpuobj, true, "realized", NULL);
}
return 0;
}
void machvirt_machine_init(struct uc_struct *uc)
{
static QEMUMachine machvirt_a15_machine = { 0 };
machvirt_a15_machine.name = "virt",
machvirt_a15_machine.init = machvirt_init,
machvirt_a15_machine.is_default = 1,
machvirt_a15_machine.arch = UC_ARCH_ARM64,
qemu_register_machine(uc, &machvirt_a15_machine, TYPE_MACHINE, NULL);
}

View File

@@ -1,3 +0,0 @@
# core qdev-related obj files, also used by *-user:
common-obj-y += qdev.o
common-obj-$(CONFIG_SOFTMMU) += machine.o

154
qemu/hw/core/cpu.c Normal file
View File

@@ -0,0 +1,154 @@
/*
* QEMU CPU model
*
* Copyright (c) 2012-2014 SUSE LINUX Products GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see
* <http://www.gnu.org/licenses/gpl-2.0.html>
*/
#include "uc_priv.h"
#include "qemu/osdep.h"
#include "hw/core/cpu.h"
#include "sysemu/tcg.h"
bool cpu_paging_enabled(const CPUState *cpu)
{
CPUClass *cc = CPU_GET_CLASS(cpu);
return cc->get_paging_enabled(cpu);
}
static bool cpu_common_get_paging_enabled(const CPUState *cpu)
{
return false;
}
void cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list)
{
CPUClass *cc = CPU_GET_CLASS(cpu);
cc->get_memory_mapping(cpu, list);
}
static void cpu_common_get_memory_mapping(CPUState *cpu,
MemoryMappingList *list)
{
// error_setg(errp, "Obtaining memory mappings is unsupported on this CPU.");
}
/* Resetting the IRQ comes from across the code base so we take the
* BQL here if we need to. cpu_interrupt assumes it is held.*/
void cpu_reset_interrupt(CPUState *cpu, int mask)
{
cpu->interrupt_request &= ~mask;
}
void cpu_exit(CPUState *cpu)
{
cpu->exit_request = 1;
cpu->tcg_exit_req = 1;
cpu->icount_decr_ptr->u16.high = -1;
}
static void cpu_common_noop(CPUState *cpu)
{
}
static bool cpu_common_exec_interrupt(CPUState *cpu, int int_req)
{
return false;
}
void cpu_reset(CPUState *cpu)
{
CPUClass *klass = CPU_GET_CLASS(cpu);
if (klass->reset != NULL) {
(*klass->reset)(cpu);
}
}
static void cpu_common_reset(CPUState *dev)
{
CPUState *cpu = CPU(dev);
cpu->interrupt_request = 0;
cpu->halted = 0;
cpu->mem_io_pc = 0;
cpu->icount_extra = 0;
cpu->can_do_io = 1;
cpu->exception_index = -1;
cpu->crash_occurred = false;
cpu->cflags_next_tb = -1;
cpu_tb_jmp_cache_clear(cpu);
cpu->uc->tcg_flush_tlb(cpu->uc);
}
static bool cpu_common_has_work(CPUState *cs)
{
return false;
}
static int64_t cpu_common_get_arch_id(CPUState *cpu)
{
return cpu->cpu_index;
}
void cpu_class_init(struct uc_struct *uc, CPUClass *k)
{
k->get_arch_id = cpu_common_get_arch_id;
k->has_work = cpu_common_has_work;
k->get_paging_enabled = cpu_common_get_paging_enabled;
k->get_memory_mapping = cpu_common_get_memory_mapping;
k->debug_excp_handler = cpu_common_noop;
k->cpu_exec_enter = cpu_common_noop;
k->cpu_exec_exit = cpu_common_noop;
k->cpu_exec_interrupt = cpu_common_exec_interrupt;
/* instead of dc->reset. */
k->reset = cpu_common_reset;
return;
}
void cpu_common_initfn(struct uc_struct *uc, CPUState *cs)
{
CPUState *cpu = CPU(cs);
cpu->cpu_index = UNASSIGNED_CPU_INDEX;
cpu->cluster_index = UNASSIGNED_CLUSTER_INDEX;
/* *-user doesn't have configurable SMP topology */
/* the default value is changed by qemu_init_vcpu() for softmmu */
cpu->nr_cores = 1;
cpu->nr_threads = 1;
QTAILQ_INIT(&cpu->breakpoints);
QTAILQ_INIT(&cpu->watchpoints);
/* cpu_exec_initfn(cpu); */
cpu->num_ases = 1;
cpu->as = &(cpu->uc->address_space_memory);
cpu->memory = cpu->uc->system_memory;
}
void cpu_stop(struct uc_struct *uc)
{
if (uc->cpu) {
uc->cpu->stop = false;
uc->cpu->stopped = true;
cpu_exit(uc->cpu);
}
}

View File

@@ -1,47 +0,0 @@
/*
* QEMU Machine
*
* Copyright (C) 2014 Red Hat Inc
*
* Authors:
* Marcel Apfelbaum <marcel.a@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "hw/boards.h"
static void machine_initfn(struct uc_struct *uc, Object *obj, void *opaque)
{
}
static void machine_finalize(struct uc_struct *uc, Object *obj, void *opaque)
{
}
static const TypeInfo machine_info = {
TYPE_MACHINE,
TYPE_OBJECT,
sizeof(MachineClass),
sizeof(MachineState),
NULL,
machine_initfn,
NULL,
machine_finalize,
NULL,
NULL,
NULL,
NULL,
true,
};
void machine_register_types(struct uc_struct *uc)
{
type_register_static(uc, &machine_info);
}

View File

@@ -1,344 +0,0 @@
/*
* Dynamic device configuration and creation.
*
* Copyright (c) 2009 CodeSourcery
*
* 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 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/>.
*/
/* The theory here is that it should be possible to create a machine without
knowledge of specific devices. Historically board init routines have
passed a bunch of arguments to each device, requiring the board know
exactly which device it is dealing with. This file provides an abstract
API for device configuration and initialization. Devices will generally
inherit from a particular bus (e.g. PCI or I2C) rather than
this API directly. */
#include "hw/qdev.h"
#include "qapi/error.h"
#include "qapi/qmp/qerror.h"
static void bus_add_child(BusState *bus, DeviceState *child)
{
char name[32];
BusChild *kid = g_malloc0(sizeof(*kid));
kid->index = bus->max_index++;
kid->child = child;
object_ref(OBJECT(kid->child));
QTAILQ_INSERT_HEAD(&bus->children, kid, sibling);
/* This transfers ownership of kid->child to the property. */
snprintf(name, sizeof(name), "child[%d]", kid->index);
object_property_add_link(OBJECT(bus), name,
object_get_typename(OBJECT(child)),
(Object **)&kid->child,
NULL, /* read-only property */
0, /* return ownership on prop deletion */
NULL);
}
void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
{
dev->parent_bus = bus;
object_ref(OBJECT(bus));
bus_add_child(bus, dev);
}
/* Create a new device. This only initializes the device state structure
and allows properties to be set. qdev_init should be called to
initialize the actual device emulation. */
DeviceState *qdev_create(BusState *bus, const char *name)
{
DeviceState *dev;
dev = qdev_try_create(bus, name);
if (!dev) {
abort();
}
return dev;
}
DeviceState *qdev_try_create(BusState *bus, const char *type)
{
#if 0
DeviceState *dev;
if (object_class_by_name(NULL, type) == NULL) { // no need to fix. aq
return NULL;
}
dev = DEVICE(object_new(NULL, type)); // no need to fix. aq
if (!dev) {
return NULL;
}
if (!bus) {
bus = sysbus_get_default();
}
qdev_set_parent_bus(dev, bus);
object_unref(OBJECT(dev));
return dev;
#endif
return NULL;
}
/* Initialize a device. Device properties should be set before calling
this function. IRQs and MMIO regions should be connected/mapped after
calling this function.
On failure, destroy the device and return negative value.
Return 0 on success. */
int qdev_init(DeviceState *dev)
{
return 0;
}
BusState *qdev_get_parent_bus(DeviceState *dev)
{
return dev->parent_bus;
}
static void qbus_realize(BusState *bus, DeviceState *parent, const char *name)
{
}
static void bus_unparent(struct uc_struct *uc, Object *obj)
{
BusState *bus = BUS(uc, obj);
BusChild *kid;
while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) {
DeviceState *dev = kid->child;
object_unparent(uc, OBJECT(dev));
}
if (bus->parent) {
QLIST_REMOVE(bus, sibling);
bus->parent->num_child_bus--;
bus->parent = NULL;
}
}
void qbus_create_inplace(void *bus, size_t size, const char *typename,
DeviceState *parent, const char *name)
{
object_initialize(NULL, bus, size, typename); // unused, so no need to fix. aq
qbus_realize(bus, parent, name);
}
BusState *qbus_create(const char *typename, DeviceState *parent, const char *name)
{
BusState *bus;
bus = BUS(NULL, object_new(NULL, typename)); // no need to fix. aq
qbus_realize(bus, parent, name);
return bus;
}
static bool device_get_realized(struct uc_struct *uc, Object *obj, Error **errp)
{
DeviceState *dev = DEVICE(uc, obj);
return dev->realized;
}
static int device_set_realized(struct uc_struct *uc, Object *obj, bool value, Error **errp)
{
DeviceState *dev = DEVICE(uc, obj);
DeviceClass *dc = DEVICE_GET_CLASS(uc, dev);
BusState *bus;
Error *local_err = NULL;
if (dev->hotplugged && !dc->hotpluggable) {
error_set(errp, QERR_DEVICE_NO_HOTPLUG, object_get_typename(obj));
return -1;
}
if (value && !dev->realized) {
#if 0
if (!obj->parent) {
static int unattached_count;
gchar *name = g_strdup_printf("device[%d]", unattached_count++);
object_property_add_child(container_get(qdev_get_machine(),
"/unattached"),
name, obj, &error_abort);
g_free(name);
}
#endif
if (dc->realize) {
if (dc->realize(uc, dev, &local_err))
return -1;
}
if (local_err != NULL) {
goto fail;
}
if (local_err != NULL) {
goto post_realize_fail;
}
QLIST_FOREACH(bus, &dev->child_bus, sibling) {
object_property_set_bool(uc, OBJECT(bus), true, "realized",
&local_err);
if (local_err != NULL) {
goto child_realize_fail;
}
}
if (dev->hotplugged) {
device_reset(dev);
}
dev->pending_deleted_event = false;
} else if (!value && dev->realized) {
Error **local_errp = NULL;
QLIST_FOREACH(bus, &dev->child_bus, sibling) {
local_errp = local_err ? NULL : &local_err;
object_property_set_bool(uc, OBJECT(bus), false, "realized",
local_errp);
}
if (dc->unrealize) {
local_errp = local_err ? NULL : &local_err;
dc->unrealize(dev, local_errp);
}
dev->pending_deleted_event = true;
}
if (local_err != NULL) {
goto fail;
}
dev->realized = value;
return 0;
child_realize_fail:
QLIST_FOREACH(bus, &dev->child_bus, sibling) {
object_property_set_bool(uc, OBJECT(bus), false, "realized",
NULL);
}
post_realize_fail:
if (dc->unrealize) {
dc->unrealize(dev, NULL);
}
fail:
error_propagate(errp, local_err);
return -1;
}
static void device_initfn(struct uc_struct *uc, Object *obj, void *opaque)
{
DeviceState *dev = DEVICE(uc, obj);
dev->instance_id_alias = -1;
dev->realized = false;
object_property_add_bool(uc, obj, "realized",
device_get_realized, device_set_realized, NULL);
}
static void device_post_init(struct uc_struct *uc, Object *obj)
{
}
/* Unlink device from bus and free the structure. */
static void device_finalize(struct uc_struct *uc, Object *obj, void *opaque)
{
}
static void device_class_base_init(ObjectClass *class, void *data)
{
}
static void device_class_init(struct uc_struct *uc, ObjectClass *class, void *data)
{
}
void device_reset(DeviceState *dev)
{
}
Object *qdev_get_machine(struct uc_struct *uc)
{
return container_get(uc, object_get_root(uc), "/machine");
}
static const TypeInfo device_type_info = {
TYPE_DEVICE,
TYPE_OBJECT,
sizeof(DeviceClass),
sizeof(DeviceState),
NULL,
device_initfn,
device_post_init,
device_finalize,
NULL,
device_class_init,
device_class_base_init,
NULL,
true,
};
static void qbus_initfn(struct uc_struct *uc, Object *obj, void *opaque)
{
}
static void bus_class_init(struct uc_struct *uc, ObjectClass *class, void *data)
{
class->unparent = bus_unparent;
}
static void qbus_finalize(struct uc_struct *uc, Object *obj, void *opaque)
{
BusState *bus = BUS(uc, obj);
g_free((char *)bus->name);
}
static const TypeInfo bus_info = {
TYPE_BUS,
TYPE_OBJECT,
sizeof(BusClass),
sizeof(BusState),
NULL,
qbus_initfn,
NULL,
qbus_finalize,
NULL,
bus_class_init,
NULL,
NULL,
true,
};
void qdev_register_types(struct uc_struct *uc)
{
type_register_static(uc, &bus_info);
type_register_static(uc, &device_type_info);
}

View File

@@ -1 +0,0 @@
obj-y += pc.o pc_piix.o

View File

@@ -1,181 +0,0 @@
/*
* QEMU PC System Emulator
*
* Copyright (c) 2003-2004 Fabrice Bellard
*
* 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.
*/
/* Modified for Unicorn Engine by Nguyen Anh Quynh, 2015 */
#include "hw/hw.h"
#include "hw/i386/pc.h"
#include "sysemu/sysemu.h"
#include "qapi-visit.h"
/* XXX: add IGNNE support */
void cpu_set_ferr(CPUX86State *s)
{
// qemu_irq_raise(ferr_irq);
}
/* TSC handling */
uint64_t cpu_get_tsc(CPUX86State *env)
{
return cpu_get_ticks();
}
/* SMM support */
static cpu_set_smm_t smm_set;
static void *smm_arg;
void cpu_smm_register(cpu_set_smm_t callback, void *arg)
{
assert(smm_set == NULL);
assert(smm_arg == NULL);
smm_set = callback;
smm_arg = arg;
}
void cpu_smm_update(CPUX86State *env)
{
struct uc_struct *uc = x86_env_get_cpu(env)->parent_obj.uc;
if (smm_set && smm_arg && CPU(x86_env_get_cpu(env)) == uc->cpu) {
smm_set(!!(env->hflags & HF_SMM_MASK), smm_arg);
}
}
/* IRQ handling */
int cpu_get_pic_interrupt(CPUX86State *env)
{
X86CPU *cpu = x86_env_get_cpu(env);
int intno;
intno = apic_get_interrupt(cpu->apic_state);
if (intno >= 0) {
return intno;
}
/* read the irq from the PIC */
if (!apic_accept_pic_intr(cpu->apic_state)) {
return -1;
}
return 0;
}
DeviceState *cpu_get_current_apic(struct uc_struct *uc)
{
if (uc->current_cpu) {
X86CPU *cpu = X86_CPU(uc, uc->current_cpu);
return cpu->apic_state;
} else {
return NULL;
}
}
static X86CPU *pc_new_cpu(struct uc_struct *uc, const char *cpu_model, int64_t apic_id,
Error **errp)
{
X86CPU *cpu;
Error *local_err = NULL;
cpu = cpu_x86_create(uc, cpu_model, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
return NULL;
}
object_property_set_int(uc, OBJECT(cpu), apic_id, "apic-id", &local_err);
object_property_set_bool(uc, OBJECT(cpu), true, "realized", &local_err);
if (local_err) {
error_propagate(errp, local_err);
object_unref(uc, OBJECT(cpu));
cpu = NULL;
}
return cpu;
}
int pc_cpus_init(struct uc_struct *uc, const char *cpu_model)
{
int i;
Error *error = NULL;
/* init CPUs */
if (cpu_model == NULL) {
#ifdef TARGET_X86_64
cpu_model = "qemu64";
#else
cpu_model = "qemu32";
#endif
}
for (i = 0; i < smp_cpus; i++) {
uc->cpu = (CPUState *)pc_new_cpu(uc, cpu_model, x86_cpu_apic_id_from_index(i), &error);
if (error) {
//error_report("%s", error_get_pretty(error));
error_free(error);
return -1;
}
}
return 0;
}
static void pc_machine_initfn(struct uc_struct *uc, Object *obj, void *opaque)
{
}
static void pc_machine_class_init(struct uc_struct *uc, ObjectClass *oc, void *data)
{
}
static const TypeInfo pc_machine_info = {
TYPE_PC_MACHINE,
TYPE_MACHINE,
sizeof(PCMachineClass),
sizeof(PCMachineState),
NULL,
pc_machine_initfn,
NULL,
NULL,
NULL,
pc_machine_class_init,
NULL,
NULL,
true,
NULL,
NULL,
// should this be added somehow?
//.interfaces = (InterfaceInfo[]) { { } },
};
void pc_machine_register_types(struct uc_struct *uc)
{
type_register_static(uc, &pc_machine_info);
}

View File

@@ -1,78 +0,0 @@
/*
* QEMU PC System Emulator
*
* Copyright (c) 2003-2004 Fabrice Bellard
*
* 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.
*/
/* Modified for Unicorn Engine by Nguyen Anh Quynh, 2015 */
#include "hw/i386/pc.h"
#include "hw/boards.h"
#include "exec/address-spaces.h"
#include "uc_priv.h"
/* Make sure that guest addresses aligned at 1Gbyte boundaries get mapped to
* host addresses aligned at 1Gbyte boundaries. This way we can use 1GByte
* pages in the host.
*/
#define GIGABYTE_ALIGN true
/* PC hardware initialisation */
static int pc_init1(struct uc_struct *uc, MachineState *machine)
{
return pc_cpus_init(uc, machine->cpu_model);
}
static int pc_init_pci(struct uc_struct *uc, MachineState *machine)
{
return pc_init1(uc, machine);
}
static QEMUMachine pc_i440fx_machine_v2_2 = {
"pc_piix",
"pc-i440fx-2.2",
pc_init_pci,
NULL,
255,
1,
UC_ARCH_X86, // X86
};
static void pc_generic_machine_class_init(struct uc_struct *uc, ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(uc, oc);
QEMUMachine *qm = data;
mc->family = qm->family;
mc->name = qm->name;
mc->init = qm->init;
mc->reset = qm->reset;
mc->max_cpus = qm->max_cpus;
mc->is_default = qm->is_default;
mc->arch = qm->arch;
}
void pc_machine_init(struct uc_struct *uc);
void pc_machine_init(struct uc_struct *uc)
{
qemu_register_machine(uc, &pc_i440fx_machine_v2_2,
TYPE_PC_MACHINE, pc_generic_machine_class_init);
}

View File

@@ -1,5 +1,7 @@
/*
* QEMU MIPS address translation support
* QEMU PC System Emulator
*
* Copyright (c) 2003-2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -19,21 +21,17 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/* Modified for Unicorn Engine by Nguyen Anh Quynh, 2015 */
/* Modified for Unicorn Engine by Chen Huitao<chenhuitao@hfmrit.com>, 2020 */
#include "hw/hw.h"
#include "hw/mips/cpudevs.h"
#include "qemu/compiler.h"
#include "sysemu/sysemu.h"
#include "target/i386/cpu.h"
uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr)
/* TSC handling */
uint64_t cpu_get_tsc(CPUX86State *env)
{
return addr & 0x1fffffffll;
return cpu_get_ticks();
}
uint64_t cpu_mips_phys_to_kseg0(void *opaque, uint64_t addr)
{
return addr | ~0x7fffffffll;
}
uint64_t cpu_mips_kvm_um_phys_to_kseg0(void *opaque, uint64_t addr)
{
return addr | 0x40000000ll;
}

View File

@@ -1 +0,0 @@
obj-$(CONFIG_APIC) += apic.o apic_common.o

View File

@@ -1,230 +0,0 @@
/*
* APIC support
*
* Copyright (c) 2004-2005 Fabrice Bellard
*
* 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 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/>
*/
#include "qemu/thread.h"
#include "hw/i386/apic_internal.h"
#include "hw/i386/apic.h"
#include "qemu/host-utils.h"
#include "hw/i386/pc.h"
#include "exec/address-spaces.h"
#define MAX_APIC_WORDS 8
#define SYNC_FROM_VAPIC 0x1
#define SYNC_TO_VAPIC 0x2
#define SYNC_ISR_IRR_TO_VAPIC 0x4
static void apic_update_irq(APICCommonState *s);
/* Find first bit starting from msb */
static int apic_fls_bit(uint32_t value)
{
return 31 - clz32(value);
}
/* return -1 if no bit is set */
static int get_highest_priority_int(uint32_t *tab)
{
int i;
for (i = 7; i >= 0; i--) {
if (tab[i] != 0) {
return i * 32 + apic_fls_bit(tab[i]);
}
}
return -1;
}
static void apic_sync_vapic(APICCommonState *s, int sync_type)
{
VAPICState vapic_state;
//size_t length;
//off_t start;
int vector;
if (!s->vapic_paddr) {
return;
}
if (sync_type & SYNC_FROM_VAPIC) {
cpu_physical_memory_read(NULL, s->vapic_paddr, &vapic_state,
sizeof(vapic_state));
s->tpr = vapic_state.tpr;
}
if (sync_type & (SYNC_TO_VAPIC | SYNC_ISR_IRR_TO_VAPIC)) {
//start = offsetof(VAPICState, isr);
//length = offsetof(VAPICState, enabled) - offsetof(VAPICState, isr);
if (sync_type & SYNC_TO_VAPIC) {
vapic_state.tpr = s->tpr;
vapic_state.enabled = 1;
//start = 0;
//length = sizeof(VAPICState);
}
vector = get_highest_priority_int(s->isr);
if (vector < 0) {
vector = 0;
}
vapic_state.isr = vector & 0xf0;
vapic_state.zero = 0;
vector = get_highest_priority_int(s->irr);
if (vector < 0) {
vector = 0;
}
vapic_state.irr = vector & 0xff;
//cpu_physical_memory_write_rom(&address_space_memory,
// s->vapic_paddr + start,
// ((void *)&vapic_state) + start, length);
// FIXME qq
}
}
static void apic_vapic_base_update(APICCommonState *s)
{
apic_sync_vapic(s, SYNC_TO_VAPIC);
}
#define foreach_apic(apic, deliver_bitmask, code) \
{\
int __i, __j;\
for(__i = 0; __i < MAX_APIC_WORDS; __i++) {\
uint32_t __mask = deliver_bitmask[__i];\
if (__mask) {\
for(__j = 0; __j < 32; __j++) {\
if (__mask & (1U << __j)) {\
apic = local_apics[__i * 32 + __j];\
if (apic) {\
code;\
}\
}\
}\
}\
}\
}
static void apic_set_base(APICCommonState *s, uint64_t val)
{
s->apicbase = (val & 0xfffff000) |
(s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
/* if disabled, cannot be enabled again */
if (!(val & MSR_IA32_APICBASE_ENABLE)) {
s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
cpu_clear_apic_feature(&s->cpu->env);
s->spurious_vec &= ~APIC_SV_ENABLE;
}
}
static void apic_set_tpr(APICCommonState *s, uint8_t val)
{
/* Updates from cr8 are ignored while the VAPIC is active */
if (!s->vapic_paddr) {
s->tpr = val << 4;
apic_update_irq(s);
}
}
static uint8_t apic_get_tpr(APICCommonState *s)
{
apic_sync_vapic(s, SYNC_FROM_VAPIC);
return s->tpr >> 4;
}
/* signal the CPU if an irq is pending */
static void apic_update_irq(APICCommonState *s)
{
}
void apic_poll_irq(DeviceState *dev)
{
}
void apic_sipi(DeviceState *dev)
{
}
int apic_get_interrupt(DeviceState *dev)
{
return 0;
}
int apic_accept_pic_intr(DeviceState *dev)
{
return 0;
}
static void apic_pre_save(APICCommonState *s)
{
apic_sync_vapic(s, SYNC_FROM_VAPIC);
}
static void apic_post_load(APICCommonState *s)
{
#if 0
if (s->timer_expiry != -1) {
timer_mod(s->timer, s->timer_expiry);
} else {
timer_del(s->timer);
}
#endif
}
static int apic_realize(struct uc_struct *uc, DeviceState *dev, Error **errp)
{
return 0;
}
static void apic_class_init(struct uc_struct *uc, ObjectClass *klass, void *data)
{
APICCommonClass *k = APIC_COMMON_CLASS(uc, klass);
k->realize = apic_realize;
k->set_base = apic_set_base;
k->set_tpr = apic_set_tpr;
k->get_tpr = apic_get_tpr;
k->vapic_base_update = apic_vapic_base_update;
k->pre_save = apic_pre_save;
k->post_load = apic_post_load;
//printf("... init apic class\n");
}
static const TypeInfo apic_info = {
"apic",
TYPE_APIC_COMMON,
0,
sizeof(APICCommonState),
NULL,
NULL,
NULL,
NULL,
NULL,
apic_class_init,
};
void apic_register_types(struct uc_struct *uc)
{
//printf("... register apic types\n");
type_register_static(uc, &apic_info);
}

View File

@@ -1,274 +0,0 @@
/*
* APIC support - common bits of emulated and KVM kernel model
*
* Copyright (c) 2004-2005 Fabrice Bellard
* Copyright (c) 2011 Jan Kiszka, Siemens AG
*
* 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 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/>
*/
#include "hw/i386/apic.h"
#include "hw/i386/apic_internal.h"
#include "hw/qdev.h"
#include "uc_priv.h"
void cpu_set_apic_base(struct uc_struct *uc, DeviceState *dev, uint64_t val)
{
if (dev) {
APICCommonState *s = APIC_COMMON(uc, dev);
APICCommonClass *info = APIC_COMMON_GET_CLASS(uc, s);
info->set_base(s, val);
}
}
uint64_t cpu_get_apic_base(struct uc_struct *uc, DeviceState *dev)
{
if (dev) {
APICCommonState *s = APIC_COMMON(uc, dev);
return s->apicbase;
} else {
return MSR_IA32_APICBASE_BSP;
}
}
void cpu_set_apic_tpr(struct uc_struct *uc, DeviceState *dev, uint8_t val)
{
APICCommonState *s;
APICCommonClass *info;
if (!dev) {
return;
}
s = APIC_COMMON(uc, dev);
info = APIC_COMMON_GET_CLASS(uc, s);
info->set_tpr(s, val);
}
uint8_t cpu_get_apic_tpr(struct uc_struct *uc, DeviceState *dev)
{
APICCommonState *s;
APICCommonClass *info;
if (!dev) {
return 0;
}
s = APIC_COMMON(uc, dev);
info = APIC_COMMON_GET_CLASS(uc, s);
return info->get_tpr(s);
}
void apic_enable_vapic(struct uc_struct *uc, DeviceState *dev, hwaddr paddr)
{
APICCommonState *s = APIC_COMMON(uc, dev);
APICCommonClass *info = APIC_COMMON_GET_CLASS(uc, s);
s->vapic_paddr = paddr;
info->vapic_base_update(s);
}
void apic_handle_tpr_access_report(DeviceState *dev, target_ulong ip,
TPRAccess access)
{
//APICCommonState *s = APIC_COMMON(NULL, dev);
//vapic_report_tpr_access(s->vapic, CPU(s->cpu), ip, access);
}
bool apic_next_timer(APICCommonState *s, int64_t current_time)
{
int64_t d;
/* We need to store the timer state separately to support APIC
* implementations that maintain a non-QEMU timer, e.g. inside the
* host kernel. This open-coded state allows us to migrate between
* both models. */
s->timer_expiry = -1;
if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED) {
return false;
}
d = (current_time - s->initial_count_load_time) >> s->count_shift;
if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
if (!s->initial_count) {
return false;
}
d = ((d / ((uint64_t)s->initial_count + 1)) + 1) *
((uint64_t)s->initial_count + 1);
} else {
if (d >= s->initial_count) {
return false;
}
d = (uint64_t)s->initial_count + 1;
}
s->next_time = s->initial_count_load_time + (d << s->count_shift);
s->timer_expiry = s->next_time;
return true;
}
void apic_init_reset(struct uc_struct *uc, DeviceState *dev)
{
APICCommonState *s = APIC_COMMON(uc, dev);
APICCommonClass *info = APIC_COMMON_GET_CLASS(uc, s);
int i;
if (!s) {
return;
}
s->tpr = 0;
s->spurious_vec = 0xff;
s->log_dest = 0;
s->dest_mode = 0xf;
memset(s->isr, 0, sizeof(s->isr));
memset(s->tmr, 0, sizeof(s->tmr));
memset(s->irr, 0, sizeof(s->irr));
for (i = 0; i < APIC_LVT_NB; i++) {
s->lvt[i] = APIC_LVT_MASKED;
}
s->esr = 0;
memset(s->icr, 0, sizeof(s->icr));
s->divide_conf = 0;
s->count_shift = 0;
s->initial_count = 0;
s->initial_count_load_time = 0;
s->next_time = 0;
s->wait_for_sipi = !cpu_is_bsp(s->cpu);
if (s->timer) {
// timer_del(s->timer);
}
s->timer_expiry = -1;
if (info->reset) {
info->reset(s);
}
}
void apic_designate_bsp(struct uc_struct *uc, DeviceState *dev)
{
APICCommonState *s;
if (dev == NULL) {
return;
}
s = APIC_COMMON(uc, dev);
s->apicbase |= MSR_IA32_APICBASE_BSP;
}
static void apic_reset_common(struct uc_struct *uc, DeviceState *dev)
{
APICCommonState *s = APIC_COMMON(uc, dev);
APICCommonClass *info = APIC_COMMON_GET_CLASS(uc, s);
bool bsp;
bsp = cpu_is_bsp(s->cpu);
s->apicbase = APIC_DEFAULT_ADDRESS |
(bsp ? MSR_IA32_APICBASE_BSP : 0) | MSR_IA32_APICBASE_ENABLE;
s->vapic_paddr = 0;
info->vapic_base_update(s);
apic_init_reset(uc, dev);
if (bsp) {
/*
* LINT0 delivery mode on CPU #0 is set to ExtInt at initialization
* time typically by BIOS, so PIC interrupt can be delivered to the
* processor when local APIC is enabled.
*/
s->lvt[APIC_LVT_LINT0] = 0x700;
}
}
static int apic_common_realize(struct uc_struct *uc, DeviceState *dev, Error **errp)
{
APICCommonState *s = APIC_COMMON(uc, dev);
APICCommonClass *info;
if (uc->apic_no >= MAX_APICS) {
error_setg(errp, "%s initialization failed.",
object_get_typename(OBJECT(dev)));
return -1;
}
s->idx = uc->apic_no++;
info = APIC_COMMON_GET_CLASS(uc, s);
info->realize(uc, dev, errp);
if (!uc->mmio_registered) {
ICCBus *b = ICC_BUS(uc, qdev_get_parent_bus(dev));
memory_region_add_subregion(b->apic_address_space, 0, &s->io_memory);
uc->mmio_registered = true;
}
/* Note: We need at least 1M to map the VAPIC option ROM */
if (!uc->vapic && s->vapic_control & VAPIC_ENABLE_MASK) {
// ram_size >= 1024 * 1024) { // FIXME
uc->vapic = NULL;
}
s->vapic = uc->vapic;
if (uc->apic_report_tpr_access && info->enable_tpr_reporting) {
info->enable_tpr_reporting(s, true);
}
return 0;
}
static void apic_common_class_init(struct uc_struct *uc, ObjectClass *klass, void *data)
{
ICCDeviceClass *idc = ICC_DEVICE_CLASS(uc, klass);
DeviceClass *dc = DEVICE_CLASS(uc, klass);
dc->reset = apic_reset_common;
idc->realize = apic_common_realize;
/*
* Reason: APIC and CPU need to be wired up by
* x86_cpu_apic_create()
*/
dc->cannot_instantiate_with_device_add_yet = true;
//printf("... init apic common class\n");
}
static const TypeInfo apic_common_type = {
TYPE_APIC_COMMON,
TYPE_DEVICE,
sizeof(APICCommonClass),
sizeof(APICCommonState),
NULL,
NULL,
NULL,
NULL,
NULL,
apic_common_class_init,
NULL,
NULL,
true,
};
void apic_common_register_types(struct uc_struct *uc)
{
//printf("... register apic common\n");
type_register_static(uc, &apic_common_type);
}

View File

@@ -1 +0,0 @@
obj-y += dummy_m68k.o

View File

@@ -1,50 +0,0 @@
/*
* Dummy board with just RAM and CPU for use as an ISS.
*
* Copyright (c) 2007 CodeSourcery.
*
* This code is licensed under the GPL
*/
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh, 2015 */
#include "hw/hw.h"
#include "hw/m68k/m68k.h"
#include "hw/boards.h"
#include "exec/address-spaces.h"
/* Board init. */
static int dummy_m68k_init(struct uc_struct *uc, MachineState *machine)
{
const char *cpu_model = machine->cpu_model;
CPUM68KState *env;
if (!cpu_model)
cpu_model = "cfv4e";
env = cpu_init(uc, cpu_model);
if (!env) {
fprintf(stderr, "Unable to find m68k CPU definition\n");
return -1;
}
/* Initialize CPU registers. */
env->vbr = 0;
env->pc = 0;
return 0;
}
void dummy_m68k_machine_init(struct uc_struct *uc)
{
static QEMUMachine dummy_m68k_machine = { 0 };
dummy_m68k_machine.name = "dummy",
dummy_m68k_machine.init = dummy_m68k_init,
dummy_m68k_machine.is_default = 1,
dummy_m68k_machine.arch = UC_ARCH_M68K,
//printf(">>> dummy_m68k_machine_init\n");
qemu_register_machine(uc, &dummy_m68k_machine, TYPE_MACHINE, NULL);
}

View File

@@ -1,2 +0,0 @@
obj-y += mips_r4k.o
obj-y += addr.o cputimer.o

View File

@@ -1,131 +0,0 @@
/*
* QEMU MIPS timer support
*
* 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 "hw/hw.h"
#include "hw/mips/cpudevs.h"
#include "qemu/timer.h"
#define TIMER_FREQ 100 * 1000 * 1000
/* XXX: do not use a global */
uint32_t cpu_mips_get_random (CPUMIPSState *env)
{
static uint32_t lfsr = 1;
static uint32_t prev_idx = 0;
uint32_t idx;
/* Don't return same value twice, so get another value */
do {
lfsr = (lfsr >> 1) ^ ((0-(lfsr & 1u)) & 0xd0000001u);
idx = lfsr % (env->tlb->nb_tlb - env->CP0_Wired) + env->CP0_Wired;
} while (idx == prev_idx);
prev_idx = idx;
return idx;
}
/* MIPS R4K timer */
static void cpu_mips_timer_update(CPUMIPSState *env)
{
#if 0
uint64_t now, next;
uint32_t wait;
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
wait = env->CP0_Compare - env->CP0_Count -
(uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec());
next = now + muldiv64(wait, get_ticks_per_sec(), TIMER_FREQ);
timer_mod(env->timer, next);
#endif
}
#if 0
/* Expire the timer. */
static void cpu_mips_timer_expire(CPUMIPSState *env)
{
cpu_mips_timer_update(env);
if (env->insn_flags & ISA_MIPS32R2) {
env->CP0_Cause |= 1 << CP0Ca_TI;
}
//qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
}
#endif
uint32_t cpu_mips_get_count (CPUMIPSState *env)
{
if (env->CP0_Cause & (1 << CP0Ca_DC)) {
return env->CP0_Count;
} else {
uint64_t now;
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
//if (timer_pending(env->timer)
// && timer_expired(env->timer, now)) {
// /* The timer has already expired. */
// cpu_mips_timer_expire(env);
//}
return env->CP0_Count +
(uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec());
}
}
void cpu_mips_store_count (CPUMIPSState *env, uint32_t count)
{
#if 0
/*
* This gets called from cpu_state_reset(), potentially before timer init.
* So env->timer may be NULL, which is also the case with KVM enabled so
* treat timer as disabled in that case.
*/
if (env->CP0_Cause & (1 << CP0Ca_DC) || !env->timer)
env->CP0_Count = count;
else {
/* Store new count register */
env->CP0_Count =
count - (uint32_t)muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
TIMER_FREQ, get_ticks_per_sec());
/* Update timer timer */
cpu_mips_timer_update(env);
}
#endif
}
void cpu_mips_store_compare (CPUMIPSState *env, uint32_t value)
{
env->CP0_Compare = value;
if (!(env->CP0_Cause & (1 << CP0Ca_DC)))
cpu_mips_timer_update(env);
if (env->insn_flags & ISA_MIPS32R2)
env->CP0_Cause &= ~(1 << CP0Ca_TI);
//qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
}
void cpu_mips_start_count(CPUMIPSState *env)
{
cpu_mips_store_count(env, env->CP0_Count);
}
void cpu_mips_stop_count(CPUMIPSState *env)
{
/* Store the current value */
env->CP0_Count += (uint32_t)muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
TIMER_FREQ, get_ticks_per_sec());
}

View File

@@ -1,57 +0,0 @@
/*
* QEMU/MIPS pseudo-board
*
* emulates a simple machine with ISA-like bus.
* ISA IO space mapped to the 0x14000000 (PHYS) and
* ISA memory at the 0x10000000 (PHYS, 16Mb in size).
* All peripherial devices are attached to this "bus" with
* the standard PC ISA addresses.
*/
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh, 2015 */
#include "hw/hw.h"
#include "hw/mips/mips.h"
#include "hw/mips/cpudevs.h"
#include "sysemu/sysemu.h"
#include "hw/boards.h"
#include "exec/address-spaces.h"
static int mips_r4k_init(struct uc_struct *uc, MachineState *machine)
{
const char *cpu_model = machine->cpu_model;
/* init CPUs */
if (cpu_model == NULL) {
#ifdef TARGET_MIPS64
cpu_model = "R4000";
#else
cpu_model = "24Kf";
#endif
}
uc->cpu = (void*) cpu_mips_init(uc, cpu_model);
if (uc->cpu == NULL) {
fprintf(stderr, "Unable to find CPU definition\n");
return -1;
}
return 0;
}
void mips_machine_init(struct uc_struct *uc)
{
static QEMUMachine mips_machine = {
NULL,
"mips",
mips_r4k_init,
NULL,
0,
1,
UC_ARCH_MIPS,
};
qemu_register_machine(uc, &mips_machine, TYPE_MACHINE, NULL);
}

1569
qemu/hw/ppc/ppc.c Normal file

File diff suppressed because it is too large Load Diff

373
qemu/hw/ppc/ppc_booke.c Normal file
View File

@@ -0,0 +1,373 @@
/*
* QEMU PowerPC Booke hardware System Emulator
*
* Copyright (c) 2011 AdaCore
*
* 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 "cpu.h"
#include "hw/ppc/ppc.h"
#include "qemu/timer.h"
#include "qemu/log.h"
// #include "kvm_ppc.h"
/* Timer Control Register */
#define TCR_WP_SHIFT 30 /* Watchdog Timer Period */
#define TCR_WP_MASK (0x3U << TCR_WP_SHIFT)
#define TCR_WRC_SHIFT 28 /* Watchdog Timer Reset Control */
#define TCR_WRC_MASK (0x3U << TCR_WRC_SHIFT)
#define TCR_WIE (1U << 27) /* Watchdog Timer Interrupt Enable */
#define TCR_DIE (1U << 26) /* Decrementer Interrupt Enable */
#define TCR_FP_SHIFT 24 /* Fixed-Interval Timer Period */
#define TCR_FP_MASK (0x3U << TCR_FP_SHIFT)
#define TCR_FIE (1U << 23) /* Fixed-Interval Timer Interrupt Enable */
#define TCR_ARE (1U << 22) /* Auto-Reload Enable */
/* Timer Control Register (e500 specific fields) */
#define TCR_E500_FPEXT_SHIFT 13 /* Fixed-Interval Timer Period Extension */
#define TCR_E500_FPEXT_MASK (0xf << TCR_E500_FPEXT_SHIFT)
#define TCR_E500_WPEXT_SHIFT 17 /* Watchdog Timer Period Extension */
#define TCR_E500_WPEXT_MASK (0xf << TCR_E500_WPEXT_SHIFT)
/* Timer Status Register */
#define TSR_FIS (1U << 26) /* Fixed-Interval Timer Interrupt Status */
#define TSR_DIS (1U << 27) /* Decrementer Interrupt Status */
#define TSR_WRS_SHIFT 28 /* Watchdog Timer Reset Status */
#define TSR_WRS_MASK (0x3U << TSR_WRS_SHIFT)
#define TSR_WIS (1U << 30) /* Watchdog Timer Interrupt Status */
#define TSR_ENW (1U << 31) /* Enable Next Watchdog Timer */
typedef struct booke_timer_t booke_timer_t;
struct booke_timer_t {
uint64_t fit_next;
QEMUTimer *fit_timer;
uint64_t wdt_next;
QEMUTimer *wdt_timer;
uint32_t flags;
};
static void booke_update_irq(PowerPCCPU *cpu)
{
CPUPPCState *env = &cpu->env;
ppc_set_irq(cpu, PPC_INTERRUPT_DECR,
(env->spr[SPR_BOOKE_TSR] & TSR_DIS
&& env->spr[SPR_BOOKE_TCR] & TCR_DIE));
ppc_set_irq(cpu, PPC_INTERRUPT_WDT,
(env->spr[SPR_BOOKE_TSR] & TSR_WIS
&& env->spr[SPR_BOOKE_TCR] & TCR_WIE));
ppc_set_irq(cpu, PPC_INTERRUPT_FIT,
(env->spr[SPR_BOOKE_TSR] & TSR_FIS
&& env->spr[SPR_BOOKE_TCR] & TCR_FIE));
}
/* Return the location of the bit of time base at which the FIT will raise an
interrupt */
static uint8_t booke_get_fit_target(CPUPPCState *env, ppc_tb_t *tb_env)
{
uint8_t fp = (env->spr[SPR_BOOKE_TCR] & TCR_FP_MASK) >> TCR_FP_SHIFT;
if (tb_env->flags & PPC_TIMER_E500) {
/* e500 Fixed-interval timer period extension */
uint32_t fpext = (env->spr[SPR_BOOKE_TCR] & TCR_E500_FPEXT_MASK)
>> TCR_E500_FPEXT_SHIFT;
fp = 63 - (fp | fpext << 2);
} else {
fp = env->fit_period[fp];
}
return fp;
}
/* Return the location of the bit of time base at which the WDT will raise an
interrupt */
static uint8_t booke_get_wdt_target(CPUPPCState *env, ppc_tb_t *tb_env)
{
uint8_t wp = (env->spr[SPR_BOOKE_TCR] & TCR_WP_MASK) >> TCR_WP_SHIFT;
if (tb_env->flags & PPC_TIMER_E500) {
/* e500 Watchdog timer period extension */
uint32_t wpext = (env->spr[SPR_BOOKE_TCR] & TCR_E500_WPEXT_MASK)
>> TCR_E500_WPEXT_SHIFT;
wp = 63 - (wp | wpext << 2);
} else {
wp = env->wdt_period[wp];
}
return wp;
}
static void booke_update_fixed_timer(CPUPPCState *env,
uint8_t target_bit,
uint64_t *next,
QEMUTimer *timer,
int tsr_bit)
{
#if 0
ppc_tb_t *tb_env = env->tb_env;
uint64_t delta_tick, ticks = 0;
uint64_t tb;
uint64_t period;
uint64_t now;
if (!(env->spr[SPR_BOOKE_TSR] & tsr_bit)) {
/*
* Don't arm the timer again when the guest has the current
* interrupt still pending. Wait for it to ack it.
*/
return;
}
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
tb = cpu_ppc_get_tb(tb_env, now, tb_env->tb_offset);
period = 1ULL << target_bit;
delta_tick = period - (tb & (period - 1));
/* the timer triggers only when the selected bit toggles from 0 to 1 */
if (tb & period) {
ticks = period;
}
if (ticks + delta_tick < ticks) {
/* Overflow, so assume the biggest number we can express. */
ticks = UINT64_MAX;
} else {
ticks += delta_tick;
}
*next = now + muldiv64(ticks, NANOSECONDS_PER_SECOND, tb_env->tb_freq);
if ((*next < now) || (*next > INT64_MAX)) {
/* Overflow, so assume the biggest number the qemu timer supports. */
*next = INT64_MAX;
}
/* XXX: If expire time is now. We can't run the callback because we don't
* have access to it. So we just set the timer one nanosecond later.
*/
if (*next == now) {
(*next)++;
} else {
/*
* There's no point to fake any granularity that's more fine grained
* than milliseconds. Anything beyond that just overloads the system.
*/
*next = MAX(*next, now + SCALE_MS);
}
/* Fire the next timer */
timer_mod(timer, *next);
#endif
}
static void booke_decr_cb(void *opaque)
{
PowerPCCPU *cpu = opaque;
CPUPPCState *env = &cpu->env;
env->spr[SPR_BOOKE_TSR] |= TSR_DIS;
booke_update_irq(cpu);
if (env->spr[SPR_BOOKE_TCR] & TCR_ARE) {
/* Do not reload 0, it is already there. It would just trigger
* the timer again and lead to infinite loop */
if (env->spr[SPR_BOOKE_DECAR] != 0) {
/* Auto Reload */
cpu_ppc_store_decr(env, env->spr[SPR_BOOKE_DECAR]);
}
}
}
static void booke_fit_cb(void *opaque)
{
PowerPCCPU *cpu = opaque;
CPUPPCState *env = &cpu->env;
ppc_tb_t *tb_env;
booke_timer_t *booke_timer;
tb_env = env->tb_env;
booke_timer = tb_env->opaque;
env->spr[SPR_BOOKE_TSR] |= TSR_FIS;
booke_update_irq(cpu);
booke_update_fixed_timer(env,
booke_get_fit_target(env, tb_env),
&booke_timer->fit_next,
booke_timer->fit_timer,
TSR_FIS);
}
static void booke_wdt_cb(void *opaque)
{
PowerPCCPU *cpu = opaque;
CPUPPCState *env = &cpu->env;
ppc_tb_t *tb_env;
booke_timer_t *booke_timer;
tb_env = env->tb_env;
booke_timer = tb_env->opaque;
/* TODO: There's lots of complicated stuff to do here */
booke_update_irq(cpu);
booke_update_fixed_timer(env,
booke_get_wdt_target(env, tb_env),
&booke_timer->wdt_next,
booke_timer->wdt_timer,
TSR_WIS);
}
void store_booke_tsr(CPUPPCState *env, target_ulong val)
{
PowerPCCPU *cpu = env_archcpu(env);
ppc_tb_t *tb_env = env->tb_env;
booke_timer_t *booke_timer = tb_env->opaque;
env->spr[SPR_BOOKE_TSR] &= ~val;
// kvmppc_clear_tsr_bits(cpu, val);
if (val & TSR_FIS) {
booke_update_fixed_timer(env,
booke_get_fit_target(env, tb_env),
&booke_timer->fit_next,
booke_timer->fit_timer,
TSR_FIS);
}
if (val & TSR_WIS) {
booke_update_fixed_timer(env,
booke_get_wdt_target(env, tb_env),
&booke_timer->wdt_next,
booke_timer->wdt_timer,
TSR_WIS);
}
booke_update_irq(cpu);
}
void store_booke_tcr(CPUPPCState *env, target_ulong val)
{
PowerPCCPU *cpu = env_archcpu(env);
ppc_tb_t *tb_env = env->tb_env;
booke_timer_t *booke_timer = tb_env->opaque;
env->spr[SPR_BOOKE_TCR] = val;
// kvmppc_set_tcr(cpu);
booke_update_irq(cpu);
booke_update_fixed_timer(env,
booke_get_fit_target(env, tb_env),
&booke_timer->fit_next,
booke_timer->fit_timer,
TSR_FIS);
booke_update_fixed_timer(env,
booke_get_wdt_target(env, tb_env),
&booke_timer->wdt_next,
booke_timer->wdt_timer,
TSR_WIS);
}
#if 0
static void ppc_booke_timer_reset_handle(void *opaque)
{
PowerPCCPU *cpu = opaque;
CPUPPCState *env = &cpu->env;
store_booke_tcr(env, 0);
store_booke_tsr(env, -1);
}
/*
* This function will be called whenever the CPU state changes.
* CPU states are defined "typedef enum RunState".
* Regarding timer, When CPU state changes to running after debug halt
* or similar cases which takes time then in between final watchdog
* expiry happenes. This will cause exit to QEMU and configured watchdog
* action will be taken. To avoid this we always clear the watchdog state when
* state changes to running.
*/
static void cpu_state_change_handler(void *opaque, int running, RunState state)
{
PowerPCCPU *cpu = opaque;
CPUPPCState *env = &cpu->env;
if (!running) {
return;
}
/*
* Clear watchdog interrupt condition by clearing TSR.
*/
store_booke_tsr(env, TSR_ENW | TSR_WIS | TSR_WRS_MASK);
}
#endif
void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags)
{
ppc_tb_t *tb_env;
booke_timer_t *booke_timer;
tb_env = g_malloc0(sizeof(ppc_tb_t));
booke_timer = g_malloc0(sizeof(booke_timer_t));
cpu->env.tb_env = tb_env;
tb_env->flags = flags | PPC_TIMER_BOOKE | PPC_DECR_ZERO_TRIGGERED;
tb_env->tb_freq = freq;
tb_env->decr_freq = freq;
tb_env->opaque = booke_timer;
tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &booke_decr_cb, cpu);
booke_timer->fit_timer =
timer_new_ns(QEMU_CLOCK_VIRTUAL, &booke_fit_cb, cpu);
booke_timer->wdt_timer =
timer_new_ns(QEMU_CLOCK_VIRTUAL, &booke_wdt_cb, cpu);
#if 0
int ret = 0;
ret = kvmppc_booke_watchdog_enable(cpu);
if (ret) {
/* TODO: Start the QEMU emulated watchdog if not running on KVM.
* Also start the QEMU emulated watchdog if KVM does not support
* emulated watchdog or somehow it is not enabled (supported but
* not enabled is though some bug and requires debugging :)).
*/
}
qemu_add_vm_change_state_handler(cpu_state_change_handler, cpu);
qemu_register_reset(ppc_booke_timer_reset_handle, cpu);
#endif
}

View File

@@ -1 +0,0 @@
obj-y += leon3.o

View File

@@ -1,72 +0,0 @@
/*
* QEMU Leon3 System Emulator
*
* Copyright (c) 2010-2011 AdaCore
*
* 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.
*/
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh, 2015 */
#include "hw/hw.h"
#include "hw/sparc/sparc.h"
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
#include "hw/boards.h"
#include "exec/address-spaces.h"
static int leon3_generic_hw_init(struct uc_struct *uc, MachineState *machine)
{
const char *cpu_model = machine->cpu_model;
SPARCCPU *cpu;
/* Init CPU */
if (!cpu_model) {
cpu_model = "LEON3";
}
cpu = cpu_sparc_init(uc, cpu_model);
uc->cpu = CPU(cpu);
if (cpu == NULL) {
fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n");
return -1;
}
cpu_sparc_set_id(&cpu->env, 0);
return 0;
}
void leon3_machine_init(struct uc_struct *uc)
{
static QEMUMachine leon3_generic_machine = {
NULL,
"leon3_generic",
leon3_generic_hw_init,
NULL,
0,
1,
UC_ARCH_SPARC,
};
//printf(">>> leon3_machine_init\n");
qemu_register_machine(uc, &leon3_generic_machine, TYPE_MACHINE, NULL);
}

View File

@@ -1 +0,0 @@
obj-y += sun4u.o

View File

@@ -1,63 +0,0 @@
/*
* QEMU Sun4u/Sun4v System Emulator
*
* Copyright (c) 2005 Fabrice Bellard
*
* 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 "hw/hw.h"
#include "hw/sparc/sparc.h"
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
#include "hw/boards.h"
#include "exec/address-spaces.h"
/* Sun4u hardware initialisation */
static int sun4u_init(struct uc_struct *uc, MachineState *machine)
{
const char *cpu_model = machine->cpu_model;
SPARCCPU *cpu;
if (cpu_model == NULL)
cpu_model = "Sun UltraSparc IV";
cpu = cpu_sparc_init(uc, cpu_model);
if (cpu == NULL) {
fprintf(stderr, "Unable to find Sparc CPU definition\n");
return -1;
}
return 0;
}
void sun4u_machine_init(struct uc_struct *uc)
{
static QEMUMachine sun4u_machine = {
NULL,
"sun4u",
sun4u_init,
NULL,
1, // XXX for now
1,
UC_ARCH_SPARC,
};
qemu_register_machine(uc, &sun4u_machine, TYPE_MACHINE, NULL);
}