mirror of https://github.com/xemu-project/xemu.git
Merge branch 'ppc-for-upstream' of git://repo.or.cz/qemu/agraf
* 'ppc-for-upstream' of git://repo.or.cz/qemu/agraf: pseries: Fix reset of VIO network device pseries: Reset vscsi properly pseries: Correctly use the device model reset hooks pseries: Remove old hcalls hook stub pseries: Remove old debug leftovers from spapr_vscsi pseries: Fix RTAS based config access target-ppc/machine.c: Drop unnecessary ifdefs target-ppc: Init dcache and icache size for e500 user mode target-ppc: Fix type casts for w64 (uintptr_t) target-ppc: QOM'ify CPU reset target-ppc: Start QOM'ifying CPU init target-ppc: QOM'ify CPU target-ppc: Add hooks for handling tcg and kvm limitations target-ppc: Drop cpu_ppc_close() pseries: Consolidate hack for RTAS display-character usage pseries: Remove unused fields from VIOsPAPRBus structure pseries: Implement RTAS system-reboot call pseries: Fix bug with reset of VIO CRQs pseries: Clean up hcall_dprintf() debugging messages PPC: Fix TLB invalidation bug within the PPC interrupt handler.
This commit is contained in:
commit
4d0365165d
|
@ -272,7 +272,7 @@ extern sPAPREnvironment *spapr;
|
|||
|
||||
#ifdef DEBUG_SPAPR_HCALLS
|
||||
#define hcall_dprintf(fmt, ...) \
|
||||
do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
|
||||
do { fprintf(stderr, "%s: " fmt, __func__, ## __VA_ARGS__); } while (0)
|
||||
#else
|
||||
#define hcall_dprintf(fmt, ...) \
|
||||
do { } while (0)
|
||||
|
|
|
@ -182,6 +182,15 @@ static NetClientInfo net_spapr_vlan_info = {
|
|||
.receive = spapr_vlan_receive,
|
||||
};
|
||||
|
||||
static void spapr_vlan_reset(VIOsPAPRDevice *sdev)
|
||||
{
|
||||
VIOsPAPRVLANDevice *dev = DO_UPCAST(VIOsPAPRVLANDevice, sdev, sdev);
|
||||
|
||||
dev->buf_list = 0;
|
||||
dev->rx_bufs = 0;
|
||||
dev->isopen = 0;
|
||||
}
|
||||
|
||||
static int spapr_vlan_init(VIOsPAPRDevice *sdev)
|
||||
{
|
||||
VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
|
||||
|
@ -279,21 +288,19 @@ static target_ulong h_register_logical_lan(CPUPPCState *env,
|
|||
|
||||
if (check_bd(dev, VLAN_VALID_BD(buf_list, SPAPR_VIO_TCE_PAGE_SIZE),
|
||||
SPAPR_VIO_TCE_PAGE_SIZE) < 0) {
|
||||
hcall_dprintf("Bad buf_list 0x" TARGET_FMT_lx " for "
|
||||
"H_REGISTER_LOGICAL_LAN\n", buf_list);
|
||||
hcall_dprintf("Bad buf_list 0x" TARGET_FMT_lx "\n", buf_list);
|
||||
return H_PARAMETER;
|
||||
}
|
||||
|
||||
filter_list_bd = VLAN_VALID_BD(filter_list, SPAPR_VIO_TCE_PAGE_SIZE);
|
||||
if (check_bd(dev, filter_list_bd, SPAPR_VIO_TCE_PAGE_SIZE) < 0) {
|
||||
hcall_dprintf("Bad filter_list 0x" TARGET_FMT_lx " for "
|
||||
"H_REGISTER_LOGICAL_LAN\n", filter_list);
|
||||
hcall_dprintf("Bad filter_list 0x" TARGET_FMT_lx "\n", filter_list);
|
||||
return H_PARAMETER;
|
||||
}
|
||||
|
||||
if (!(rec_queue & VLAN_BD_VALID)
|
||||
|| (check_bd(dev, rec_queue, VLAN_RQ_ALIGNMENT) < 0)) {
|
||||
hcall_dprintf("Bad receive queue for H_REGISTER_LOGICAL_LAN\n");
|
||||
hcall_dprintf("Bad receive queue\n");
|
||||
return H_PARAMETER;
|
||||
}
|
||||
|
||||
|
@ -337,9 +344,7 @@ static target_ulong h_free_logical_lan(CPUPPCState *env, sPAPREnvironment *spapr
|
|||
return H_RESOURCE;
|
||||
}
|
||||
|
||||
dev->buf_list = 0;
|
||||
dev->rx_bufs = 0;
|
||||
dev->isopen = 0;
|
||||
spapr_vlan_reset(sdev);
|
||||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -358,13 +363,13 @@ static target_ulong h_add_logical_lan_buffer(CPUPPCState *env,
|
|||
", 0x" TARGET_FMT_lx ")\n", reg, buf);
|
||||
|
||||
if (!sdev) {
|
||||
hcall_dprintf("Wrong device in h_add_logical_lan_buffer\n");
|
||||
hcall_dprintf("Bad device\n");
|
||||
return H_PARAMETER;
|
||||
}
|
||||
|
||||
if ((check_bd(dev, buf, 4) < 0)
|
||||
|| (VLAN_BD_LEN(buf) < 16)) {
|
||||
hcall_dprintf("Bad buffer enqueued in h_add_logical_lan_buffer\n");
|
||||
hcall_dprintf("Bad buffer enqueued\n");
|
||||
return H_PARAMETER;
|
||||
}
|
||||
|
||||
|
@ -486,6 +491,7 @@ static void spapr_vlan_class_init(ObjectClass *klass, void *data)
|
|||
VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = spapr_vlan_init;
|
||||
k->reset = spapr_vlan_reset;
|
||||
k->devnode = spapr_vlan_devnode;
|
||||
k->dt_name = "l-lan";
|
||||
k->dt_type = "network";
|
||||
|
|
119
hw/spapr_pci.c
119
hw/spapr_pci.c
|
@ -57,26 +57,38 @@ static PCIDevice *find_dev(sPAPREnvironment *spapr,
|
|||
|
||||
static uint32_t rtas_pci_cfgaddr(uint32_t arg)
|
||||
{
|
||||
/* This handles the encoding of extended config space addresses */
|
||||
return ((arg >> 20) & 0xf00) | (arg & 0xff);
|
||||
}
|
||||
|
||||
static uint32_t rtas_read_pci_config_do(PCIDevice *pci_dev, uint32_t addr,
|
||||
uint32_t limit, uint32_t len)
|
||||
static void finish_read_pci_config(sPAPREnvironment *spapr, uint64_t buid,
|
||||
uint32_t addr, uint32_t size,
|
||||
target_ulong rets)
|
||||
{
|
||||
if ((addr + len) <= limit) {
|
||||
return pci_host_config_read_common(pci_dev, addr, limit, len);
|
||||
} else {
|
||||
return ~0x0;
|
||||
}
|
||||
}
|
||||
PCIDevice *pci_dev;
|
||||
uint32_t val;
|
||||
|
||||
static void rtas_write_pci_config_do(PCIDevice *pci_dev, uint32_t addr,
|
||||
uint32_t limit, uint32_t val,
|
||||
uint32_t len)
|
||||
{
|
||||
if ((addr + len) <= limit) {
|
||||
pci_host_config_write_common(pci_dev, addr, limit, val, len);
|
||||
if ((size != 1) && (size != 2) && (size != 4)) {
|
||||
/* access must be 1, 2 or 4 bytes */
|
||||
rtas_st(rets, 0, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
pci_dev = find_dev(spapr, buid, addr);
|
||||
addr = rtas_pci_cfgaddr(addr);
|
||||
|
||||
if (!pci_dev || (addr % size) || (addr >= pci_config_size(pci_dev))) {
|
||||
/* Access must be to a valid device, within bounds and
|
||||
* naturally aligned */
|
||||
rtas_st(rets, 0, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
val = pci_host_config_read_common(pci_dev, addr,
|
||||
pci_config_size(pci_dev), size);
|
||||
|
||||
rtas_st(rets, 0, 0);
|
||||
rtas_st(rets, 1, val);
|
||||
}
|
||||
|
||||
static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr,
|
||||
|
@ -84,19 +96,19 @@ static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr,
|
|||
target_ulong args,
|
||||
uint32_t nret, target_ulong rets)
|
||||
{
|
||||
uint32_t val, size, addr;
|
||||
uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
|
||||
PCIDevice *dev = find_dev(spapr, buid, rtas_ld(args, 0));
|
||||
uint64_t buid;
|
||||
uint32_t size, addr;
|
||||
|
||||
if (!dev) {
|
||||
if ((nargs != 4) || (nret != 2)) {
|
||||
rtas_st(rets, 0, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
|
||||
size = rtas_ld(args, 3);
|
||||
addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
|
||||
val = rtas_read_pci_config_do(dev, addr, pci_config_size(dev), size);
|
||||
rtas_st(rets, 0, 0);
|
||||
rtas_st(rets, 1, val);
|
||||
addr = rtas_ld(args, 0);
|
||||
|
||||
finish_read_pci_config(spapr, buid, addr, size, rets);
|
||||
}
|
||||
|
||||
static void rtas_read_pci_config(sPAPREnvironment *spapr,
|
||||
|
@ -104,18 +116,45 @@ static void rtas_read_pci_config(sPAPREnvironment *spapr,
|
|||
target_ulong args,
|
||||
uint32_t nret, target_ulong rets)
|
||||
{
|
||||
uint32_t val, size, addr;
|
||||
PCIDevice *dev = find_dev(spapr, 0, rtas_ld(args, 0));
|
||||
uint32_t size, addr;
|
||||
|
||||
if (!dev) {
|
||||
if ((nargs != 2) || (nret != 2)) {
|
||||
rtas_st(rets, 0, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
size = rtas_ld(args, 1);
|
||||
addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
|
||||
val = rtas_read_pci_config_do(dev, addr, pci_config_size(dev), size);
|
||||
addr = rtas_ld(args, 0);
|
||||
|
||||
finish_read_pci_config(spapr, 0, addr, size, rets);
|
||||
}
|
||||
|
||||
static void finish_write_pci_config(sPAPREnvironment *spapr, uint64_t buid,
|
||||
uint32_t addr, uint32_t size,
|
||||
uint32_t val, target_ulong rets)
|
||||
{
|
||||
PCIDevice *pci_dev;
|
||||
|
||||
if ((size != 1) && (size != 2) && (size != 4)) {
|
||||
/* access must be 1, 2 or 4 bytes */
|
||||
rtas_st(rets, 0, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
pci_dev = find_dev(spapr, buid, addr);
|
||||
addr = rtas_pci_cfgaddr(addr);
|
||||
|
||||
if (!pci_dev || (addr % size) || (addr >= pci_config_size(pci_dev))) {
|
||||
/* Access must be to a valid device, within bounds and
|
||||
* naturally aligned */
|
||||
rtas_st(rets, 0, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
pci_host_config_write_common(pci_dev, addr, pci_config_size(pci_dev),
|
||||
val, size);
|
||||
|
||||
rtas_st(rets, 0, 0);
|
||||
rtas_st(rets, 1, val);
|
||||
}
|
||||
|
||||
static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr,
|
||||
|
@ -123,19 +162,20 @@ static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr,
|
|||
target_ulong args,
|
||||
uint32_t nret, target_ulong rets)
|
||||
{
|
||||
uint64_t buid;
|
||||
uint32_t val, size, addr;
|
||||
uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
|
||||
PCIDevice *dev = find_dev(spapr, buid, rtas_ld(args, 0));
|
||||
|
||||
if (!dev) {
|
||||
if ((nargs != 5) || (nret != 1)) {
|
||||
rtas_st(rets, 0, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
|
||||
val = rtas_ld(args, 4);
|
||||
size = rtas_ld(args, 3);
|
||||
addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
|
||||
rtas_write_pci_config_do(dev, addr, pci_config_size(dev), val, size);
|
||||
rtas_st(rets, 0, 0);
|
||||
addr = rtas_ld(args, 0);
|
||||
|
||||
finish_write_pci_config(spapr, buid, addr, size, val, rets);
|
||||
}
|
||||
|
||||
static void rtas_write_pci_config(sPAPREnvironment *spapr,
|
||||
|
@ -144,17 +184,18 @@ static void rtas_write_pci_config(sPAPREnvironment *spapr,
|
|||
uint32_t nret, target_ulong rets)
|
||||
{
|
||||
uint32_t val, size, addr;
|
||||
PCIDevice *dev = find_dev(spapr, 0, rtas_ld(args, 0));
|
||||
|
||||
if (!dev) {
|
||||
if ((nargs != 3) || (nret != 1)) {
|
||||
rtas_st(rets, 0, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
val = rtas_ld(args, 2);
|
||||
size = rtas_ld(args, 1);
|
||||
addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
|
||||
rtas_write_pci_config_do(dev, addr, pci_config_size(dev), val, size);
|
||||
rtas_st(rets, 0, 0);
|
||||
addr = rtas_ld(args, 0);
|
||||
|
||||
finish_write_pci_config(spapr, 0, addr, size, val, rets);
|
||||
}
|
||||
|
||||
static int pci_spapr_map_irq(PCIDevice *pci_dev, int irq_num)
|
||||
|
|
|
@ -44,8 +44,7 @@ static void rtas_display_character(sPAPREnvironment *spapr,
|
|||
uint32_t nret, target_ulong rets)
|
||||
{
|
||||
uint8_t c = rtas_ld(args, 0);
|
||||
VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus,
|
||||
SPAPR_VTY_BASE_ADDRESS);
|
||||
VIOsPAPRDevice *sdev = vty_lookup(spapr, 0);
|
||||
|
||||
if (!sdev) {
|
||||
rtas_st(rets, 0, -1);
|
||||
|
@ -112,6 +111,19 @@ static void rtas_power_off(sPAPREnvironment *spapr,
|
|||
rtas_st(rets, 0, 0);
|
||||
}
|
||||
|
||||
static void rtas_system_reboot(sPAPREnvironment *spapr,
|
||||
uint32_t token, uint32_t nargs,
|
||||
target_ulong args,
|
||||
uint32_t nret, target_ulong rets)
|
||||
{
|
||||
if (nargs != 0 || nret != 1) {
|
||||
rtas_st(rets, 0, -3);
|
||||
return;
|
||||
}
|
||||
qemu_system_reset_request();
|
||||
rtas_st(rets, 0, 0);
|
||||
}
|
||||
|
||||
static void rtas_query_cpu_stopped_state(sPAPREnvironment *spapr,
|
||||
uint32_t token, uint32_t nargs,
|
||||
target_ulong args,
|
||||
|
@ -294,6 +306,7 @@ static void core_rtas_register_types(void)
|
|||
spapr_rtas_register("get-time-of-day", rtas_get_time_of_day);
|
||||
spapr_rtas_register("set-time-of-day", rtas_set_time_of_day);
|
||||
spapr_rtas_register("power-off", rtas_power_off);
|
||||
spapr_rtas_register("system-reboot", rtas_system_reboot);
|
||||
spapr_rtas_register("query-cpu-stopped-state",
|
||||
rtas_query_cpu_stopped_state);
|
||||
spapr_rtas_register("start-cpu", rtas_start_cpu);
|
||||
|
|
|
@ -204,8 +204,7 @@ static target_ulong h_put_tce(CPUPPCState *env, sPAPREnvironment *spapr,
|
|||
VIOsPAPR_RTCE *rtce;
|
||||
|
||||
if (!dev) {
|
||||
hcall_dprintf("spapr_vio_put_tce on non-existent LIOBN "
|
||||
TARGET_FMT_lx "\n", liobn);
|
||||
hcall_dprintf("LIOBN 0x" TARGET_FMT_lx " does not exist\n", liobn);
|
||||
return H_PARAMETER;
|
||||
}
|
||||
|
||||
|
@ -217,8 +216,7 @@ static target_ulong h_put_tce(CPUPPCState *env, sPAPREnvironment *spapr,
|
|||
#endif
|
||||
|
||||
if (ioba >= dev->rtce_window_size) {
|
||||
hcall_dprintf("spapr_vio_put_tce on out-of-boards IOBA 0x"
|
||||
TARGET_FMT_lx "\n", ioba);
|
||||
hcall_dprintf("Out-of-bounds IOBA 0x" TARGET_FMT_lx "\n", ioba);
|
||||
return H_PARAMETER;
|
||||
}
|
||||
|
||||
|
@ -414,33 +412,32 @@ static target_ulong h_reg_crq(CPUPPCState *env, sPAPREnvironment *spapr,
|
|||
VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
|
||||
|
||||
if (!dev) {
|
||||
hcall_dprintf("h_reg_crq on non-existent unit 0x"
|
||||
TARGET_FMT_lx "\n", reg);
|
||||
hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
|
||||
return H_PARAMETER;
|
||||
}
|
||||
|
||||
/* We can't grok a queue size bigger than 256M for now */
|
||||
if (queue_len < 0x1000 || queue_len > 0x10000000) {
|
||||
hcall_dprintf("h_reg_crq, queue size too small or too big (0x%llx)\n",
|
||||
(unsigned long long)queue_len);
|
||||
hcall_dprintf("Queue size too small or too big (0x" TARGET_FMT_lx
|
||||
")\n", queue_len);
|
||||
return H_PARAMETER;
|
||||
}
|
||||
|
||||
/* Check queue alignment */
|
||||
if (queue_addr & 0xfff) {
|
||||
hcall_dprintf("h_reg_crq, queue not aligned (0x%llx)\n",
|
||||
(unsigned long long)queue_addr);
|
||||
hcall_dprintf("Queue not aligned (0x" TARGET_FMT_lx ")\n", queue_addr);
|
||||
return H_PARAMETER;
|
||||
}
|
||||
|
||||
/* Check if device supports CRQs */
|
||||
if (!dev->crq.SendFunc) {
|
||||
hcall_dprintf("Device does not support CRQ\n");
|
||||
return H_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
/* Already a queue ? */
|
||||
if (dev->crq.qsize) {
|
||||
hcall_dprintf("CRQ already registered\n");
|
||||
return H_RESOURCE;
|
||||
}
|
||||
dev->crq.qladdr = queue_addr;
|
||||
|
@ -453,6 +450,17 @@ static target_ulong h_reg_crq(CPUPPCState *env, sPAPREnvironment *spapr,
|
|||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static target_ulong free_crq(VIOsPAPRDevice *dev)
|
||||
{
|
||||
dev->crq.qladdr = 0;
|
||||
dev->crq.qsize = 0;
|
||||
dev->crq.qnext = 0;
|
||||
|
||||
dprintf("CRQ for dev 0x%" PRIx32 " freed\n", dev->reg);
|
||||
|
||||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static target_ulong h_free_crq(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
|
@ -460,18 +468,11 @@ static target_ulong h_free_crq(CPUPPCState *env, sPAPREnvironment *spapr,
|
|||
VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
|
||||
|
||||
if (!dev) {
|
||||
hcall_dprintf("h_free_crq on non-existent unit 0x"
|
||||
TARGET_FMT_lx "\n", reg);
|
||||
hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
|
||||
return H_PARAMETER;
|
||||
}
|
||||
|
||||
dev->crq.qladdr = 0;
|
||||
dev->crq.qsize = 0;
|
||||
dev->crq.qnext = 0;
|
||||
|
||||
dprintf("CRQ for dev 0x" TARGET_FMT_lx " freed\n", reg);
|
||||
|
||||
return H_SUCCESS;
|
||||
return free_crq(dev);
|
||||
}
|
||||
|
||||
static target_ulong h_send_crq(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
|
@ -484,8 +485,7 @@ static target_ulong h_send_crq(CPUPPCState *env, sPAPREnvironment *spapr,
|
|||
uint64_t crq_mangle[2];
|
||||
|
||||
if (!dev) {
|
||||
hcall_dprintf("h_send_crq on non-existent unit 0x"
|
||||
TARGET_FMT_lx "\n", reg);
|
||||
hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
|
||||
return H_PARAMETER;
|
||||
}
|
||||
crq_mangle[0] = cpu_to_be64(msg_hi);
|
||||
|
@ -505,8 +505,7 @@ static target_ulong h_enable_crq(CPUPPCState *env, sPAPREnvironment *spapr,
|
|||
VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
|
||||
|
||||
if (!dev) {
|
||||
hcall_dprintf("h_enable_crq on non-existent unit 0x"
|
||||
TARGET_FMT_lx "\n", reg);
|
||||
hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
|
||||
return H_PARAMETER;
|
||||
}
|
||||
|
||||
|
@ -649,6 +648,20 @@ static int spapr_vio_check_reg(VIOsPAPRDevice *sdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void spapr_vio_busdev_reset(DeviceState *qdev)
|
||||
{
|
||||
VIOsPAPRDevice *dev = DO_UPCAST(VIOsPAPRDevice, qdev, qdev);
|
||||
VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
|
||||
|
||||
if (dev->crq.qsize) {
|
||||
free_crq(dev);
|
||||
}
|
||||
|
||||
if (pc->reset) {
|
||||
pc->reset(dev);
|
||||
}
|
||||
}
|
||||
|
||||
static int spapr_vio_busdev_init(DeviceState *qdev)
|
||||
{
|
||||
VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
|
||||
|
@ -766,6 +779,7 @@ static void vio_spapr_device_class_init(ObjectClass *klass, void *data)
|
|||
{
|
||||
DeviceClass *k = DEVICE_CLASS(klass);
|
||||
k->init = spapr_vio_busdev_init;
|
||||
k->reset = spapr_vio_busdev_reset;
|
||||
k->bus_info = &spapr_vio_bus_info;
|
||||
}
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ typedef struct VIOsPAPRDeviceClass {
|
|||
const char *dt_name, *dt_type, *dt_compatible;
|
||||
target_ulong signal_mask;
|
||||
int (*init)(VIOsPAPRDevice *dev);
|
||||
void (*hcalls)(VIOsPAPRBus *bus);
|
||||
void (*reset)(VIOsPAPRDevice *dev);
|
||||
int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
|
||||
} VIOsPAPRDeviceClass;
|
||||
|
||||
|
@ -89,8 +89,6 @@ struct VIOsPAPRDevice {
|
|||
|
||||
struct VIOsPAPRBus {
|
||||
BusState bus;
|
||||
const char *dt_name, *dt_type, *dt_compatible;
|
||||
target_ulong signal_mask;
|
||||
int (*init)(VIOsPAPRDevice *dev);
|
||||
int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
|
||||
};
|
||||
|
@ -119,6 +117,7 @@ uint64_t ldq_tce(VIOsPAPRDevice *dev, uint64_t taddr);
|
|||
|
||||
int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq);
|
||||
|
||||
VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg);
|
||||
void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len);
|
||||
void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev);
|
||||
void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd);
|
||||
|
|
|
@ -99,10 +99,6 @@ typedef struct {
|
|||
vscsi_req reqs[VSCSI_REQ_LIMIT];
|
||||
} VSCSIState;
|
||||
|
||||
/* XXX Debug only */
|
||||
static VSCSIState *dbg_vscsi_state;
|
||||
|
||||
|
||||
static struct vscsi_req *vscsi_get_req(VSCSIState *s)
|
||||
{
|
||||
vscsi_req *req;
|
||||
|
@ -897,18 +893,20 @@ static const struct SCSIBusInfo vscsi_scsi_info = {
|
|||
.cancel = vscsi_request_cancelled
|
||||
};
|
||||
|
||||
static int spapr_vscsi_init(VIOsPAPRDevice *dev)
|
||||
static void spapr_vscsi_reset(VIOsPAPRDevice *dev)
|
||||
{
|
||||
VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev);
|
||||
int i;
|
||||
|
||||
dbg_vscsi_state = s;
|
||||
|
||||
/* Initialize qemu request tags */
|
||||
memset(s->reqs, 0, sizeof(s->reqs));
|
||||
for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
|
||||
s->reqs[i].qtag = i;
|
||||
}
|
||||
}
|
||||
|
||||
static int spapr_vscsi_init(VIOsPAPRDevice *dev)
|
||||
{
|
||||
VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev);
|
||||
|
||||
dev->crq.SendFunc = vscsi_do_crq;
|
||||
|
||||
|
@ -958,6 +956,7 @@ static void spapr_vscsi_class_init(ObjectClass *klass, void *data)
|
|||
VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = spapr_vscsi_init;
|
||||
k->reset = spapr_vscsi_reset;
|
||||
k->devnode = spapr_vscsi_devnode;
|
||||
k->dt_name = "v-scsi";
|
||||
k->dt_type = "vscsi";
|
||||
|
|
|
@ -70,8 +70,6 @@ static int spapr_vty_init(VIOsPAPRDevice *sdev)
|
|||
}
|
||||
|
||||
/* Forward declaration */
|
||||
static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg);
|
||||
|
||||
static target_ulong h_put_term_char(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
|
@ -195,7 +193,7 @@ VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
|
|||
return selected;
|
||||
}
|
||||
|
||||
static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
|
||||
VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
|
||||
{
|
||||
VIOsPAPRDevice *sdev;
|
||||
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* QEMU PowerPC CPU
|
||||
*
|
||||
* Copyright (c) 2012 SUSE LINUX Products GmbH
|
||||
*
|
||||
* 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>
|
||||
*/
|
||||
#ifndef QEMU_PPC_CPU_QOM_H
|
||||
#define QEMU_PPC_CPU_QOM_H
|
||||
|
||||
#include "qemu/cpu.h"
|
||||
#include "cpu.h"
|
||||
|
||||
#ifdef TARGET_PPC64
|
||||
#define TYPE_POWERPC_CPU "powerpc64-cpu"
|
||||
#elif defined(TARGET_PPCEMB)
|
||||
#define TYPE_POWERPC_CPU "embedded-powerpc-cpu"
|
||||
#else
|
||||
#define TYPE_POWERPC_CPU "powerpc-cpu"
|
||||
#endif
|
||||
|
||||
#define POWERPC_CPU_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(PowerPCCPUClass, (klass), TYPE_POWERPC_CPU)
|
||||
#define POWERPC_CPU(obj) \
|
||||
OBJECT_CHECK(PowerPCCPU, (obj), TYPE_POWERPC_CPU)
|
||||
#define POWERPC_CPU_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(PowerPCCPUClass, (obj), TYPE_POWERPC_CPU)
|
||||
|
||||
/**
|
||||
* PowerPCCPUClass:
|
||||
* @parent_reset: The parent class' reset handler.
|
||||
*
|
||||
* A PowerPC CPU model.
|
||||
*/
|
||||
typedef struct PowerPCCPUClass {
|
||||
/*< private >*/
|
||||
CPUClass parent_class;
|
||||
/*< public >*/
|
||||
|
||||
void (*parent_reset)(CPUState *cpu);
|
||||
} PowerPCCPUClass;
|
||||
|
||||
/**
|
||||
* PowerPCCPU:
|
||||
* @env: #CPUPPCState
|
||||
*
|
||||
* A PowerPC CPU.
|
||||
*/
|
||||
typedef struct PowerPCCPU {
|
||||
/*< private >*/
|
||||
CPUState parent_obj;
|
||||
/*< public >*/
|
||||
|
||||
CPUPPCState env;
|
||||
} PowerPCCPU;
|
||||
|
||||
static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env)
|
||||
{
|
||||
return POWERPC_CPU(container_of(env, PowerPCCPU, env));
|
||||
}
|
||||
|
||||
#define ENV_GET_CPU(e) CPU(ppc_env_get_cpu(e))
|
||||
|
||||
|
||||
#endif
|
|
@ -1096,11 +1096,12 @@ struct mmu_ctx_t {
|
|||
};
|
||||
#endif
|
||||
|
||||
#include "cpu-qom.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
CPUPPCState *cpu_ppc_init (const char *cpu_model);
|
||||
void ppc_translate_init(void);
|
||||
int cpu_ppc_exec (CPUPPCState *s);
|
||||
void cpu_ppc_close (CPUPPCState *s);
|
||||
/* you can call this signal handler from your SIGBUS and SIGSEGV
|
||||
signal handlers to inform the virtual CPU of exceptions. non zero
|
||||
is returned if the signal was handled by the virtual CPU. */
|
||||
|
|
|
@ -2960,7 +2960,7 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp)
|
|||
if (asrr1 != -1)
|
||||
env->spr[asrr1] = env->spr[srr1];
|
||||
/* If we disactivated any translation, flush TLBs */
|
||||
if (new_msr & ((1 << MSR_IR) | (1 << MSR_DR)))
|
||||
if (msr & ((1 << MSR_IR) | (1 << MSR_DR)))
|
||||
tlb_flush(env, 1);
|
||||
|
||||
if (msr_ile) {
|
||||
|
@ -3138,54 +3138,12 @@ void cpu_dump_rfi (target_ulong RA, target_ulong msr)
|
|||
|
||||
void cpu_state_reset(CPUPPCState *env)
|
||||
{
|
||||
target_ulong msr;
|
||||
|
||||
if (qemu_loglevel_mask(CPU_LOG_RESET)) {
|
||||
qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
|
||||
log_cpu_state(env, 0);
|
||||
}
|
||||
|
||||
msr = (target_ulong)0;
|
||||
if (0) {
|
||||
/* XXX: find a suitable condition to enable the hypervisor mode */
|
||||
msr |= (target_ulong)MSR_HVB;
|
||||
}
|
||||
msr |= (target_ulong)0 << MSR_AP; /* TO BE CHECKED */
|
||||
msr |= (target_ulong)0 << MSR_SA; /* TO BE CHECKED */
|
||||
msr |= (target_ulong)1 << MSR_EP;
|
||||
#if defined (DO_SINGLE_STEP) && 0
|
||||
/* Single step trace mode */
|
||||
msr |= (target_ulong)1 << MSR_SE;
|
||||
msr |= (target_ulong)1 << MSR_BE;
|
||||
#endif
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */
|
||||
msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */
|
||||
msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */
|
||||
msr |= (target_ulong)1 << MSR_PR;
|
||||
#else
|
||||
env->excp_prefix = env->hreset_excp_prefix;
|
||||
env->nip = env->hreset_vector | env->excp_prefix;
|
||||
if (env->mmu_model != POWERPC_MMU_REAL)
|
||||
ppc_tlb_invalidate_all(env);
|
||||
#endif
|
||||
env->msr = msr & env->msr_mask;
|
||||
#if defined(TARGET_PPC64)
|
||||
if (env->mmu_model & POWERPC_MMU_64)
|
||||
env->msr |= (1ULL << MSR_SF);
|
||||
#endif
|
||||
hreg_compute_hflags(env);
|
||||
env->reserve_addr = (target_ulong)-1ULL;
|
||||
/* Be sure no exception or interrupt is pending */
|
||||
env->pending_interrupts = 0;
|
||||
env->exception_index = POWERPC_EXCP_NONE;
|
||||
env->error_code = 0;
|
||||
/* Flush all TLBs */
|
||||
tlb_flush(env, 1);
|
||||
cpu_reset(ENV_GET_CPU(env));
|
||||
}
|
||||
|
||||
CPUPPCState *cpu_ppc_init (const char *cpu_model)
|
||||
{
|
||||
PowerPCCPU *cpu;
|
||||
CPUPPCState *env;
|
||||
const ppc_def_t *def;
|
||||
|
||||
|
@ -3193,20 +3151,13 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model)
|
|||
if (!def)
|
||||
return NULL;
|
||||
|
||||
env = g_malloc0(sizeof(CPUPPCState));
|
||||
cpu_exec_init(env);
|
||||
cpu = POWERPC_CPU(object_new(TYPE_POWERPC_CPU));
|
||||
env = &cpu->env;
|
||||
|
||||
if (tcg_enabled()) {
|
||||
ppc_translate_init();
|
||||
}
|
||||
/* Adjust cpu index for SMT */
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (kvm_enabled()) {
|
||||
int smt = kvmppc_smt_threads();
|
||||
|
||||
env->cpu_index = (env->cpu_index / smp_threads)*smt
|
||||
+ (env->cpu_index % smp_threads);
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
env->cpu_model_str = cpu_model;
|
||||
cpu_ppc_register_internal(env, def);
|
||||
|
||||
|
@ -3214,9 +3165,3 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model)
|
|||
|
||||
return env;
|
||||
}
|
||||
|
||||
void cpu_ppc_close (CPUPPCState *env)
|
||||
{
|
||||
/* Should also remove all opcode tables... */
|
||||
g_free(env);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "kvm.h"
|
||||
#include "kvm_ppc.h"
|
||||
#include "cpu.h"
|
||||
#include "cpus.h"
|
||||
#include "device_tree.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/spapr.h"
|
||||
|
@ -938,6 +939,19 @@ const ppc_def_t *kvmppc_host_cpu_def(void)
|
|||
return spec;
|
||||
}
|
||||
|
||||
int kvmppc_fixup_cpu(CPUPPCState *env)
|
||||
{
|
||||
int smt;
|
||||
|
||||
/* Adjust cpu index for SMT */
|
||||
smt = kvmppc_smt_threads();
|
||||
env->cpu_index = (env->cpu_index / smp_threads) * smt
|
||||
+ (env->cpu_index % smp_threads);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool kvm_arch_stop_on_emulation_error(CPUPPCState *env)
|
||||
{
|
||||
return true;
|
||||
|
|
|
@ -29,6 +29,7 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd);
|
|||
int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size);
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
const ppc_def_t *kvmppc_host_cpu_def(void);
|
||||
int kvmppc_fixup_cpu(CPUPPCState *env);
|
||||
|
||||
#else
|
||||
|
||||
|
@ -95,6 +96,10 @@ static inline const ppc_def_t *kvmppc_host_cpu_def(void)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static inline int kvmppc_fixup_cpu(CPUPPCState *env)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_KVM
|
||||
|
|
|
@ -32,7 +32,6 @@ void cpu_save(QEMUFile *f, void *opaque)
|
|||
}
|
||||
qemu_put_be32s(f, &env->fpscr);
|
||||
qemu_put_sbe32s(f, &env->access_type);
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#if defined(TARGET_PPC64)
|
||||
qemu_put_betls(f, &env->asr);
|
||||
qemu_put_sbe32s(f, &env->slb_nr);
|
||||
|
@ -62,7 +61,6 @@ void cpu_save(QEMUFile *f, void *opaque)
|
|||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
qemu_put_betls(f, &env->pb[i]);
|
||||
#endif
|
||||
for (i = 0; i < 1024; i++)
|
||||
qemu_put_betls(f, &env->spr[i]);
|
||||
qemu_put_be32s(f, &env->vscr);
|
||||
|
@ -72,7 +70,6 @@ void cpu_save(QEMUFile *f, void *opaque)
|
|||
qemu_put_be32s(f, &env->flags);
|
||||
qemu_put_sbe32s(f, &env->error_code);
|
||||
qemu_put_be32s(f, &env->pending_interrupts);
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
qemu_put_be32s(f, &env->irq_input_state);
|
||||
for (i = 0; i < POWERPC_EXCP_NB; i++)
|
||||
qemu_put_betls(f, &env->excp_vectors[i]);
|
||||
|
@ -81,7 +78,6 @@ void cpu_save(QEMUFile *f, void *opaque)
|
|||
qemu_put_betls(f, &env->ivor_mask);
|
||||
qemu_put_betls(f, &env->ivpr_mask);
|
||||
qemu_put_betls(f, &env->hreset_vector);
|
||||
#endif
|
||||
qemu_put_betls(f, &env->nip);
|
||||
qemu_put_betls(f, &env->hflags);
|
||||
qemu_put_betls(f, &env->hflags_nmsr);
|
||||
|
@ -120,7 +116,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
|
|||
}
|
||||
qemu_get_be32s(f, &env->fpscr);
|
||||
qemu_get_sbe32s(f, &env->access_type);
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#if defined(TARGET_PPC64)
|
||||
qemu_get_betls(f, &env->asr);
|
||||
qemu_get_sbe32s(f, &env->slb_nr);
|
||||
|
@ -150,7 +145,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
|
|||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
qemu_get_betls(f, &env->pb[i]);
|
||||
#endif
|
||||
for (i = 0; i < 1024; i++)
|
||||
qemu_get_betls(f, &env->spr[i]);
|
||||
ppc_store_sdr1(env, sdr1);
|
||||
|
@ -161,7 +155,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
|
|||
qemu_get_be32s(f, &env->flags);
|
||||
qemu_get_sbe32s(f, &env->error_code);
|
||||
qemu_get_be32s(f, &env->pending_interrupts);
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
qemu_get_be32s(f, &env->irq_input_state);
|
||||
for (i = 0; i < POWERPC_EXCP_NB; i++)
|
||||
qemu_get_betls(f, &env->excp_vectors[i]);
|
||||
|
@ -170,7 +163,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
|
|||
qemu_get_betls(f, &env->ivor_mask);
|
||||
qemu_get_betls(f, &env->ivpr_mask);
|
||||
qemu_get_betls(f, &env->hreset_vector);
|
||||
#endif
|
||||
qemu_get_betls(f, &env->nip);
|
||||
qemu_get_betls(f, &env->hflags);
|
||||
qemu_get_betls(f, &env->hflags_nmsr);
|
||||
|
|
|
@ -9306,8 +9306,8 @@ GEN_SPEOP_LDST(evstwwe, 0x1C, 2),
|
|||
GEN_SPEOP_LDST(evstwwo, 0x1E, 2),
|
||||
};
|
||||
|
||||
#include "translate_init.c"
|
||||
#include "helper_regs.h"
|
||||
#include "translate_init.c"
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Misc PowerPC helpers */
|
||||
|
|
|
@ -4462,7 +4462,10 @@ static void init_proc_e500 (CPUPPCState *env, int version)
|
|||
&spr_read_spefscr, &spr_write_spefscr,
|
||||
0x00000000);
|
||||
/* Memory management */
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
env->dcache_line_size = 32;
|
||||
env->icache_line_size = 32;
|
||||
#else /* !defined(CONFIG_USER_ONLY) */
|
||||
env->nb_pids = 3;
|
||||
env->nb_ways = 2;
|
||||
env->id_tlbs = 0;
|
||||
|
@ -9504,12 +9507,12 @@ enum {
|
|||
|
||||
static inline int is_indirect_opcode (void *handler)
|
||||
{
|
||||
return ((unsigned long)handler & 0x03) == PPC_INDIRECT;
|
||||
return ((uintptr_t)handler & 0x03) == PPC_INDIRECT;
|
||||
}
|
||||
|
||||
static inline opc_handler_t **ind_table(void *handler)
|
||||
{
|
||||
return (opc_handler_t **)((unsigned long)handler & ~3);
|
||||
return (opc_handler_t **)((uintptr_t)handler & ~3);
|
||||
}
|
||||
|
||||
/* Instruction table creation */
|
||||
|
@ -9528,7 +9531,7 @@ static int create_new_table (opc_handler_t **table, unsigned char idx)
|
|||
|
||||
tmp = malloc(0x20 * sizeof(opc_handler_t));
|
||||
fill_new_table(tmp, 0x20);
|
||||
table[idx] = (opc_handler_t *)((unsigned long)tmp | PPC_INDIRECT);
|
||||
table[idx] = (opc_handler_t *)((uintptr_t)tmp | PPC_INDIRECT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -9889,6 +9892,28 @@ static int gdb_set_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ppc_fixup_cpu(CPUPPCState *env)
|
||||
{
|
||||
/* TCG doesn't (yet) emulate some groups of instructions that
|
||||
* are implemented on some otherwise supported CPUs (e.g. VSX
|
||||
* and decimal floating point instructions on POWER7). We
|
||||
* remove unsupported instruction groups from the cpu state's
|
||||
* instruction masks and hope the guest can cope. For at
|
||||
* least the pseries machine, the unavailability of these
|
||||
* instructions can be advertised to the guest via the device
|
||||
* tree. */
|
||||
if ((env->insns_flags & ~PPC_TCG_INSNS)
|
||||
|| (env->insns_flags2 & ~PPC_TCG_INSNS2)) {
|
||||
fprintf(stderr, "Warning: Disabling some instructions which are not "
|
||||
"emulated by TCG (0x%" PRIx64 ", 0x%" PRIx64 ")\n",
|
||||
env->insns_flags & ~PPC_TCG_INSNS,
|
||||
env->insns_flags2 & ~PPC_TCG_INSNS2);
|
||||
}
|
||||
env->insns_flags &= PPC_TCG_INSNS;
|
||||
env->insns_flags2 &= PPC_TCG_INSNS2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
|
||||
{
|
||||
env->msr_mask = def->msr_mask;
|
||||
|
@ -9897,25 +9922,22 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
|
|||
env->bus_model = def->bus_model;
|
||||
env->insns_flags = def->insns_flags;
|
||||
env->insns_flags2 = def->insns_flags2;
|
||||
if (!kvm_enabled()) {
|
||||
/* TCG doesn't (yet) emulate some groups of instructions that
|
||||
* are implemented on some otherwise supported CPUs (e.g. VSX
|
||||
* and decimal floating point instructions on POWER7). We
|
||||
* remove unsupported instruction groups from the cpu state's
|
||||
* instruction masks and hope the guest can cope. For at
|
||||
* least the pseries machine, the unavailability of these
|
||||
* instructions can be advertise to the guest via the device
|
||||
* tree.
|
||||
*
|
||||
* FIXME: we should have a similar masking for CPU features
|
||||
* not accessible under KVM, but so far, there aren't any of
|
||||
* those. */
|
||||
env->insns_flags &= PPC_TCG_INSNS;
|
||||
env->insns_flags2 &= PPC_TCG_INSNS2;
|
||||
}
|
||||
env->flags = def->flags;
|
||||
env->bfd_mach = def->bfd_mach;
|
||||
env->check_pow = def->check_pow;
|
||||
|
||||
if (kvm_enabled()) {
|
||||
if (kvmppc_fixup_cpu(env) != 0) {
|
||||
fprintf(stderr, "Unable to virtualize selected CPU with KVM\n");
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
if (ppc_fixup_cpu(env) != 0) {
|
||||
fprintf(stderr, "Unable to emulate selected CPU with TCG\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (create_ppc_opcodes(env, def) < 0)
|
||||
return -1;
|
||||
init_ppc_proc(env, def);
|
||||
|
@ -10185,3 +10207,93 @@ void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf)
|
|||
ppc_defs[i].name, ppc_defs[i].pvr);
|
||||
}
|
||||
}
|
||||
|
||||
/* CPUClass::reset() */
|
||||
static void ppc_cpu_reset(CPUState *s)
|
||||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(s);
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
target_ulong msr;
|
||||
|
||||
if (qemu_loglevel_mask(CPU_LOG_RESET)) {
|
||||
qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
|
||||
log_cpu_state(env, 0);
|
||||
}
|
||||
|
||||
pcc->parent_reset(s);
|
||||
|
||||
msr = (target_ulong)0;
|
||||
if (0) {
|
||||
/* XXX: find a suitable condition to enable the hypervisor mode */
|
||||
msr |= (target_ulong)MSR_HVB;
|
||||
}
|
||||
msr |= (target_ulong)0 << MSR_AP; /* TO BE CHECKED */
|
||||
msr |= (target_ulong)0 << MSR_SA; /* TO BE CHECKED */
|
||||
msr |= (target_ulong)1 << MSR_EP;
|
||||
#if defined(DO_SINGLE_STEP) && 0
|
||||
/* Single step trace mode */
|
||||
msr |= (target_ulong)1 << MSR_SE;
|
||||
msr |= (target_ulong)1 << MSR_BE;
|
||||
#endif
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */
|
||||
msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */
|
||||
msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */
|
||||
msr |= (target_ulong)1 << MSR_PR;
|
||||
#else
|
||||
env->excp_prefix = env->hreset_excp_prefix;
|
||||
env->nip = env->hreset_vector | env->excp_prefix;
|
||||
if (env->mmu_model != POWERPC_MMU_REAL) {
|
||||
ppc_tlb_invalidate_all(env);
|
||||
}
|
||||
#endif
|
||||
env->msr = msr & env->msr_mask;
|
||||
#if defined(TARGET_PPC64)
|
||||
if (env->mmu_model & POWERPC_MMU_64) {
|
||||
env->msr |= (1ULL << MSR_SF);
|
||||
}
|
||||
#endif
|
||||
hreg_compute_hflags(env);
|
||||
env->reserve_addr = (target_ulong)-1ULL;
|
||||
/* Be sure no exception or interrupt is pending */
|
||||
env->pending_interrupts = 0;
|
||||
env->exception_index = POWERPC_EXCP_NONE;
|
||||
env->error_code = 0;
|
||||
/* Flush all TLBs */
|
||||
tlb_flush(env, 1);
|
||||
}
|
||||
|
||||
static void ppc_cpu_initfn(Object *obj)
|
||||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(obj);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
cpu_exec_init(env);
|
||||
}
|
||||
|
||||
static void ppc_cpu_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
|
||||
CPUClass *cc = CPU_CLASS(oc);
|
||||
|
||||
pcc->parent_reset = cc->reset;
|
||||
cc->reset = ppc_cpu_reset;
|
||||
}
|
||||
|
||||
static const TypeInfo ppc_cpu_type_info = {
|
||||
.name = TYPE_POWERPC_CPU,
|
||||
.parent = TYPE_CPU,
|
||||
.instance_size = sizeof(PowerPCCPU),
|
||||
.instance_init = ppc_cpu_initfn,
|
||||
.abstract = false,
|
||||
.class_size = sizeof(PowerPCCPUClass),
|
||||
.class_init = ppc_cpu_class_init,
|
||||
};
|
||||
|
||||
static void ppc_cpu_register_types(void)
|
||||
{
|
||||
type_register_static(&ppc_cpu_type_info);
|
||||
}
|
||||
|
||||
type_init(ppc_cpu_register_types)
|
||||
|
|
Loading…
Reference in New Issue