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
|
#ifdef DEBUG_SPAPR_HCALLS
|
||||||
#define hcall_dprintf(fmt, ...) \
|
#define hcall_dprintf(fmt, ...) \
|
||||||
do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
|
do { fprintf(stderr, "%s: " fmt, __func__, ## __VA_ARGS__); } while (0)
|
||||||
#else
|
#else
|
||||||
#define hcall_dprintf(fmt, ...) \
|
#define hcall_dprintf(fmt, ...) \
|
||||||
do { } while (0)
|
do { } while (0)
|
||||||
|
@ -182,6 +182,15 @@ static NetClientInfo net_spapr_vlan_info = {
|
|||||||
.receive = spapr_vlan_receive,
|
.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)
|
static int spapr_vlan_init(VIOsPAPRDevice *sdev)
|
||||||
{
|
{
|
||||||
VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)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),
|
if (check_bd(dev, VLAN_VALID_BD(buf_list, SPAPR_VIO_TCE_PAGE_SIZE),
|
||||||
SPAPR_VIO_TCE_PAGE_SIZE) < 0) {
|
SPAPR_VIO_TCE_PAGE_SIZE) < 0) {
|
||||||
hcall_dprintf("Bad buf_list 0x" TARGET_FMT_lx " for "
|
hcall_dprintf("Bad buf_list 0x" TARGET_FMT_lx "\n", buf_list);
|
||||||
"H_REGISTER_LOGICAL_LAN\n", buf_list);
|
|
||||||
return H_PARAMETER;
|
return H_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
filter_list_bd = VLAN_VALID_BD(filter_list, SPAPR_VIO_TCE_PAGE_SIZE);
|
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) {
|
if (check_bd(dev, filter_list_bd, SPAPR_VIO_TCE_PAGE_SIZE) < 0) {
|
||||||
hcall_dprintf("Bad filter_list 0x" TARGET_FMT_lx " for "
|
hcall_dprintf("Bad filter_list 0x" TARGET_FMT_lx "\n", filter_list);
|
||||||
"H_REGISTER_LOGICAL_LAN\n", filter_list);
|
|
||||||
return H_PARAMETER;
|
return H_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(rec_queue & VLAN_BD_VALID)
|
if (!(rec_queue & VLAN_BD_VALID)
|
||||||
|| (check_bd(dev, rec_queue, VLAN_RQ_ALIGNMENT) < 0)) {
|
|| (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;
|
return H_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,9 +344,7 @@ static target_ulong h_free_logical_lan(CPUPPCState *env, sPAPREnvironment *spapr
|
|||||||
return H_RESOURCE;
|
return H_RESOURCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->buf_list = 0;
|
spapr_vlan_reset(sdev);
|
||||||
dev->rx_bufs = 0;
|
|
||||||
dev->isopen = 0;
|
|
||||||
return H_SUCCESS;
|
return H_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,13 +363,13 @@ static target_ulong h_add_logical_lan_buffer(CPUPPCState *env,
|
|||||||
", 0x" TARGET_FMT_lx ")\n", reg, buf);
|
", 0x" TARGET_FMT_lx ")\n", reg, buf);
|
||||||
|
|
||||||
if (!sdev) {
|
if (!sdev) {
|
||||||
hcall_dprintf("Wrong device in h_add_logical_lan_buffer\n");
|
hcall_dprintf("Bad device\n");
|
||||||
return H_PARAMETER;
|
return H_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((check_bd(dev, buf, 4) < 0)
|
if ((check_bd(dev, buf, 4) < 0)
|
||||||
|| (VLAN_BD_LEN(buf) < 16)) {
|
|| (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;
|
return H_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -486,6 +491,7 @@ static void spapr_vlan_class_init(ObjectClass *klass, void *data)
|
|||||||
VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
|
VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
|
||||||
|
|
||||||
k->init = spapr_vlan_init;
|
k->init = spapr_vlan_init;
|
||||||
|
k->reset = spapr_vlan_reset;
|
||||||
k->devnode = spapr_vlan_devnode;
|
k->devnode = spapr_vlan_devnode;
|
||||||
k->dt_name = "l-lan";
|
k->dt_name = "l-lan";
|
||||||
k->dt_type = "network";
|
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)
|
static uint32_t rtas_pci_cfgaddr(uint32_t arg)
|
||||||
{
|
{
|
||||||
|
/* This handles the encoding of extended config space addresses */
|
||||||
return ((arg >> 20) & 0xf00) | (arg & 0xff);
|
return ((arg >> 20) & 0xf00) | (arg & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t rtas_read_pci_config_do(PCIDevice *pci_dev, uint32_t addr,
|
static void finish_read_pci_config(sPAPREnvironment *spapr, uint64_t buid,
|
||||||
uint32_t limit, uint32_t len)
|
uint32_t addr, uint32_t size,
|
||||||
|
target_ulong rets)
|
||||||
{
|
{
|
||||||
if ((addr + len) <= limit) {
|
PCIDevice *pci_dev;
|
||||||
return pci_host_config_read_common(pci_dev, addr, limit, len);
|
uint32_t val;
|
||||||
} else {
|
|
||||||
return ~0x0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rtas_write_pci_config_do(PCIDevice *pci_dev, uint32_t addr,
|
if ((size != 1) && (size != 2) && (size != 4)) {
|
||||||
uint32_t limit, uint32_t val,
|
/* access must be 1, 2 or 4 bytes */
|
||||||
uint32_t len)
|
rtas_st(rets, 0, -1);
|
||||||
{
|
return;
|
||||||
if ((addr + len) <= limit) {
|
|
||||||
pci_host_config_write_common(pci_dev, addr, limit, val, len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
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,
|
target_ulong args,
|
||||||
uint32_t nret, target_ulong rets)
|
uint32_t nret, target_ulong rets)
|
||||||
{
|
{
|
||||||
uint32_t val, size, addr;
|
uint64_t buid;
|
||||||
uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
|
uint32_t size, addr;
|
||||||
PCIDevice *dev = find_dev(spapr, buid, rtas_ld(args, 0));
|
|
||||||
|
|
||||||
if (!dev) {
|
if ((nargs != 4) || (nret != 2)) {
|
||||||
rtas_st(rets, 0, -1);
|
rtas_st(rets, 0, -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
|
||||||
size = rtas_ld(args, 3);
|
size = rtas_ld(args, 3);
|
||||||
addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
|
addr = rtas_ld(args, 0);
|
||||||
val = rtas_read_pci_config_do(dev, addr, pci_config_size(dev), size);
|
|
||||||
rtas_st(rets, 0, 0);
|
finish_read_pci_config(spapr, buid, addr, size, rets);
|
||||||
rtas_st(rets, 1, val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtas_read_pci_config(sPAPREnvironment *spapr,
|
static void rtas_read_pci_config(sPAPREnvironment *spapr,
|
||||||
@ -104,18 +116,45 @@ static void rtas_read_pci_config(sPAPREnvironment *spapr,
|
|||||||
target_ulong args,
|
target_ulong args,
|
||||||
uint32_t nret, target_ulong rets)
|
uint32_t nret, target_ulong rets)
|
||||||
{
|
{
|
||||||
uint32_t val, size, addr;
|
uint32_t size, addr;
|
||||||
PCIDevice *dev = find_dev(spapr, 0, rtas_ld(args, 0));
|
|
||||||
|
|
||||||
if (!dev) {
|
if ((nargs != 2) || (nret != 2)) {
|
||||||
rtas_st(rets, 0, -1);
|
rtas_st(rets, 0, -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size = rtas_ld(args, 1);
|
size = rtas_ld(args, 1);
|
||||||
addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
|
addr = rtas_ld(args, 0);
|
||||||
val = rtas_read_pci_config_do(dev, addr, pci_config_size(dev), size);
|
|
||||||
|
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, 0, 0);
|
||||||
rtas_st(rets, 1, val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr,
|
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,
|
target_ulong args,
|
||||||
uint32_t nret, target_ulong rets)
|
uint32_t nret, target_ulong rets)
|
||||||
{
|
{
|
||||||
|
uint64_t buid;
|
||||||
uint32_t val, size, addr;
|
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);
|
rtas_st(rets, 0, -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
|
||||||
val = rtas_ld(args, 4);
|
val = rtas_ld(args, 4);
|
||||||
size = rtas_ld(args, 3);
|
size = rtas_ld(args, 3);
|
||||||
addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
|
addr = rtas_ld(args, 0);
|
||||||
rtas_write_pci_config_do(dev, addr, pci_config_size(dev), val, size);
|
|
||||||
rtas_st(rets, 0, 0);
|
finish_write_pci_config(spapr, buid, addr, size, val, rets);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtas_write_pci_config(sPAPREnvironment *spapr,
|
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 nret, target_ulong rets)
|
||||||
{
|
{
|
||||||
uint32_t val, size, addr;
|
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);
|
rtas_st(rets, 0, -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val = rtas_ld(args, 2);
|
val = rtas_ld(args, 2);
|
||||||
size = rtas_ld(args, 1);
|
size = rtas_ld(args, 1);
|
||||||
addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
|
addr = rtas_ld(args, 0);
|
||||||
rtas_write_pci_config_do(dev, addr, pci_config_size(dev), val, size);
|
|
||||||
rtas_st(rets, 0, 0);
|
finish_write_pci_config(spapr, 0, addr, size, val, rets);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pci_spapr_map_irq(PCIDevice *pci_dev, int irq_num)
|
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)
|
uint32_t nret, target_ulong rets)
|
||||||
{
|
{
|
||||||
uint8_t c = rtas_ld(args, 0);
|
uint8_t c = rtas_ld(args, 0);
|
||||||
VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus,
|
VIOsPAPRDevice *sdev = vty_lookup(spapr, 0);
|
||||||
SPAPR_VTY_BASE_ADDRESS);
|
|
||||||
|
|
||||||
if (!sdev) {
|
if (!sdev) {
|
||||||
rtas_st(rets, 0, -1);
|
rtas_st(rets, 0, -1);
|
||||||
@ -112,6 +111,19 @@ static void rtas_power_off(sPAPREnvironment *spapr,
|
|||||||
rtas_st(rets, 0, 0);
|
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,
|
static void rtas_query_cpu_stopped_state(sPAPREnvironment *spapr,
|
||||||
uint32_t token, uint32_t nargs,
|
uint32_t token, uint32_t nargs,
|
||||||
target_ulong args,
|
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("get-time-of-day", rtas_get_time_of_day);
|
||||||
spapr_rtas_register("set-time-of-day", rtas_set_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("power-off", rtas_power_off);
|
||||||
|
spapr_rtas_register("system-reboot", rtas_system_reboot);
|
||||||
spapr_rtas_register("query-cpu-stopped-state",
|
spapr_rtas_register("query-cpu-stopped-state",
|
||||||
rtas_query_cpu_stopped_state);
|
rtas_query_cpu_stopped_state);
|
||||||
spapr_rtas_register("start-cpu", rtas_start_cpu);
|
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;
|
VIOsPAPR_RTCE *rtce;
|
||||||
|
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
hcall_dprintf("spapr_vio_put_tce on non-existent LIOBN "
|
hcall_dprintf("LIOBN 0x" TARGET_FMT_lx " does not exist\n", liobn);
|
||||||
TARGET_FMT_lx "\n", liobn);
|
|
||||||
return H_PARAMETER;
|
return H_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,8 +216,7 @@ static target_ulong h_put_tce(CPUPPCState *env, sPAPREnvironment *spapr,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ioba >= dev->rtce_window_size) {
|
if (ioba >= dev->rtce_window_size) {
|
||||||
hcall_dprintf("spapr_vio_put_tce on out-of-boards IOBA 0x"
|
hcall_dprintf("Out-of-bounds IOBA 0x" TARGET_FMT_lx "\n", ioba);
|
||||||
TARGET_FMT_lx "\n", ioba);
|
|
||||||
return H_PARAMETER;
|
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);
|
VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
|
||||||
|
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
hcall_dprintf("h_reg_crq on non-existent unit 0x"
|
hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
|
||||||
TARGET_FMT_lx "\n", reg);
|
|
||||||
return H_PARAMETER;
|
return H_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We can't grok a queue size bigger than 256M for now */
|
/* We can't grok a queue size bigger than 256M for now */
|
||||||
if (queue_len < 0x1000 || queue_len > 0x10000000) {
|
if (queue_len < 0x1000 || queue_len > 0x10000000) {
|
||||||
hcall_dprintf("h_reg_crq, queue size too small or too big (0x%llx)\n",
|
hcall_dprintf("Queue size too small or too big (0x" TARGET_FMT_lx
|
||||||
(unsigned long long)queue_len);
|
")\n", queue_len);
|
||||||
return H_PARAMETER;
|
return H_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check queue alignment */
|
/* Check queue alignment */
|
||||||
if (queue_addr & 0xfff) {
|
if (queue_addr & 0xfff) {
|
||||||
hcall_dprintf("h_reg_crq, queue not aligned (0x%llx)\n",
|
hcall_dprintf("Queue not aligned (0x" TARGET_FMT_lx ")\n", queue_addr);
|
||||||
(unsigned long long)queue_addr);
|
|
||||||
return H_PARAMETER;
|
return H_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if device supports CRQs */
|
/* Check if device supports CRQs */
|
||||||
if (!dev->crq.SendFunc) {
|
if (!dev->crq.SendFunc) {
|
||||||
|
hcall_dprintf("Device does not support CRQ\n");
|
||||||
return H_NOT_FOUND;
|
return H_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Already a queue ? */
|
/* Already a queue ? */
|
||||||
if (dev->crq.qsize) {
|
if (dev->crq.qsize) {
|
||||||
|
hcall_dprintf("CRQ already registered\n");
|
||||||
return H_RESOURCE;
|
return H_RESOURCE;
|
||||||
}
|
}
|
||||||
dev->crq.qladdr = queue_addr;
|
dev->crq.qladdr = queue_addr;
|
||||||
@ -453,6 +450,17 @@ static target_ulong h_reg_crq(CPUPPCState *env, sPAPREnvironment *spapr,
|
|||||||
return H_SUCCESS;
|
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,
|
static target_ulong h_free_crq(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||||
target_ulong opcode, target_ulong *args)
|
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);
|
VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
|
||||||
|
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
hcall_dprintf("h_free_crq on non-existent unit 0x"
|
hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
|
||||||
TARGET_FMT_lx "\n", reg);
|
|
||||||
return H_PARAMETER;
|
return H_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->crq.qladdr = 0;
|
return free_crq(dev);
|
||||||
dev->crq.qsize = 0;
|
|
||||||
dev->crq.qnext = 0;
|
|
||||||
|
|
||||||
dprintf("CRQ for dev 0x" TARGET_FMT_lx " freed\n", reg);
|
|
||||||
|
|
||||||
return H_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static target_ulong h_send_crq(CPUPPCState *env, sPAPREnvironment *spapr,
|
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];
|
uint64_t crq_mangle[2];
|
||||||
|
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
hcall_dprintf("h_send_crq on non-existent unit 0x"
|
hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
|
||||||
TARGET_FMT_lx "\n", reg);
|
|
||||||
return H_PARAMETER;
|
return H_PARAMETER;
|
||||||
}
|
}
|
||||||
crq_mangle[0] = cpu_to_be64(msg_hi);
|
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);
|
VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
|
||||||
|
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
hcall_dprintf("h_enable_crq on non-existent unit 0x"
|
hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
|
||||||
TARGET_FMT_lx "\n", reg);
|
|
||||||
return H_PARAMETER;
|
return H_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -649,6 +648,20 @@ static int spapr_vio_check_reg(VIOsPAPRDevice *sdev)
|
|||||||
return 0;
|
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)
|
static int spapr_vio_busdev_init(DeviceState *qdev)
|
||||||
{
|
{
|
||||||
VIOsPAPRDevice *dev = (VIOsPAPRDevice *)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);
|
DeviceClass *k = DEVICE_CLASS(klass);
|
||||||
k->init = spapr_vio_busdev_init;
|
k->init = spapr_vio_busdev_init;
|
||||||
|
k->reset = spapr_vio_busdev_reset;
|
||||||
k->bus_info = &spapr_vio_bus_info;
|
k->bus_info = &spapr_vio_bus_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ typedef struct VIOsPAPRDeviceClass {
|
|||||||
const char *dt_name, *dt_type, *dt_compatible;
|
const char *dt_name, *dt_type, *dt_compatible;
|
||||||
target_ulong signal_mask;
|
target_ulong signal_mask;
|
||||||
int (*init)(VIOsPAPRDevice *dev);
|
int (*init)(VIOsPAPRDevice *dev);
|
||||||
void (*hcalls)(VIOsPAPRBus *bus);
|
void (*reset)(VIOsPAPRDevice *dev);
|
||||||
int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
|
int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
|
||||||
} VIOsPAPRDeviceClass;
|
} VIOsPAPRDeviceClass;
|
||||||
|
|
||||||
@ -89,8 +89,6 @@ struct VIOsPAPRDevice {
|
|||||||
|
|
||||||
struct VIOsPAPRBus {
|
struct VIOsPAPRBus {
|
||||||
BusState bus;
|
BusState bus;
|
||||||
const char *dt_name, *dt_type, *dt_compatible;
|
|
||||||
target_ulong signal_mask;
|
|
||||||
int (*init)(VIOsPAPRDevice *dev);
|
int (*init)(VIOsPAPRDevice *dev);
|
||||||
int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
|
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);
|
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 vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len);
|
||||||
void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev);
|
void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev);
|
||||||
void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd);
|
void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd);
|
||||||
|
@ -99,10 +99,6 @@ typedef struct {
|
|||||||
vscsi_req reqs[VSCSI_REQ_LIMIT];
|
vscsi_req reqs[VSCSI_REQ_LIMIT];
|
||||||
} VSCSIState;
|
} VSCSIState;
|
||||||
|
|
||||||
/* XXX Debug only */
|
|
||||||
static VSCSIState *dbg_vscsi_state;
|
|
||||||
|
|
||||||
|
|
||||||
static struct vscsi_req *vscsi_get_req(VSCSIState *s)
|
static struct vscsi_req *vscsi_get_req(VSCSIState *s)
|
||||||
{
|
{
|
||||||
vscsi_req *req;
|
vscsi_req *req;
|
||||||
@ -897,18 +893,20 @@ static const struct SCSIBusInfo vscsi_scsi_info = {
|
|||||||
.cancel = vscsi_request_cancelled
|
.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);
|
VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
dbg_vscsi_state = s;
|
|
||||||
|
|
||||||
/* Initialize qemu request tags */
|
|
||||||
memset(s->reqs, 0, sizeof(s->reqs));
|
memset(s->reqs, 0, sizeof(s->reqs));
|
||||||
for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
|
for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
|
||||||
s->reqs[i].qtag = 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;
|
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);
|
VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
|
||||||
|
|
||||||
k->init = spapr_vscsi_init;
|
k->init = spapr_vscsi_init;
|
||||||
|
k->reset = spapr_vscsi_reset;
|
||||||
k->devnode = spapr_vscsi_devnode;
|
k->devnode = spapr_vscsi_devnode;
|
||||||
k->dt_name = "v-scsi";
|
k->dt_name = "v-scsi";
|
||||||
k->dt_type = "vscsi";
|
k->dt_type = "vscsi";
|
||||||
|
@ -70,8 +70,6 @@ static int spapr_vty_init(VIOsPAPRDevice *sdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Forward declaration */
|
/* Forward declaration */
|
||||||
static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg);
|
|
||||||
|
|
||||||
static target_ulong h_put_term_char(CPUPPCState *env, sPAPREnvironment *spapr,
|
static target_ulong h_put_term_char(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||||
target_ulong opcode, target_ulong *args)
|
target_ulong opcode, target_ulong *args)
|
||||||
{
|
{
|
||||||
@ -195,7 +193,7 @@ VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
|
|||||||
return selected;
|
return selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
|
VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
|
||||||
{
|
{
|
||||||
VIOsPAPRDevice *sdev;
|
VIOsPAPRDevice *sdev;
|
||||||
|
|
||||||
|
77
target-ppc/cpu-qom.h
Normal file
77
target-ppc/cpu-qom.h
Normal file
@ -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
|
#endif
|
||||||
|
|
||||||
|
#include "cpu-qom.h"
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
CPUPPCState *cpu_ppc_init (const char *cpu_model);
|
CPUPPCState *cpu_ppc_init (const char *cpu_model);
|
||||||
void ppc_translate_init(void);
|
void ppc_translate_init(void);
|
||||||
int cpu_ppc_exec (CPUPPCState *s);
|
int cpu_ppc_exec (CPUPPCState *s);
|
||||||
void cpu_ppc_close (CPUPPCState *s);
|
|
||||||
/* you can call this signal handler from your SIGBUS and SIGSEGV
|
/* you can call this signal handler from your SIGBUS and SIGSEGV
|
||||||
signal handlers to inform the virtual CPU of exceptions. non zero
|
signal handlers to inform the virtual CPU of exceptions. non zero
|
||||||
is returned if the signal was handled by the virtual CPU. */
|
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)
|
if (asrr1 != -1)
|
||||||
env->spr[asrr1] = env->spr[srr1];
|
env->spr[asrr1] = env->spr[srr1];
|
||||||
/* If we disactivated any translation, flush TLBs */
|
/* 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);
|
tlb_flush(env, 1);
|
||||||
|
|
||||||
if (msr_ile) {
|
if (msr_ile) {
|
||||||
@ -3138,54 +3138,12 @@ void cpu_dump_rfi (target_ulong RA, target_ulong msr)
|
|||||||
|
|
||||||
void cpu_state_reset(CPUPPCState *env)
|
void cpu_state_reset(CPUPPCState *env)
|
||||||
{
|
{
|
||||||
target_ulong msr;
|
cpu_reset(ENV_GET_CPU(env));
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CPUPPCState *cpu_ppc_init (const char *cpu_model)
|
CPUPPCState *cpu_ppc_init (const char *cpu_model)
|
||||||
{
|
{
|
||||||
|
PowerPCCPU *cpu;
|
||||||
CPUPPCState *env;
|
CPUPPCState *env;
|
||||||
const ppc_def_t *def;
|
const ppc_def_t *def;
|
||||||
|
|
||||||
@ -3193,20 +3151,13 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model)
|
|||||||
if (!def)
|
if (!def)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
env = g_malloc0(sizeof(CPUPPCState));
|
cpu = POWERPC_CPU(object_new(TYPE_POWERPC_CPU));
|
||||||
cpu_exec_init(env);
|
env = &cpu->env;
|
||||||
|
|
||||||
if (tcg_enabled()) {
|
if (tcg_enabled()) {
|
||||||
ppc_translate_init();
|
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;
|
env->cpu_model_str = cpu_model;
|
||||||
cpu_ppc_register_internal(env, def);
|
cpu_ppc_register_internal(env, def);
|
||||||
|
|
||||||
@ -3214,9 +3165,3 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model)
|
|||||||
|
|
||||||
return env;
|
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.h"
|
||||||
#include "kvm_ppc.h"
|
#include "kvm_ppc.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
#include "cpus.h"
|
||||||
#include "device_tree.h"
|
#include "device_tree.h"
|
||||||
#include "hw/sysbus.h"
|
#include "hw/sysbus.h"
|
||||||
#include "hw/spapr.h"
|
#include "hw/spapr.h"
|
||||||
@ -938,6 +939,19 @@ const ppc_def_t *kvmppc_host_cpu_def(void)
|
|||||||
return spec;
|
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)
|
bool kvm_arch_stop_on_emulation_error(CPUPPCState *env)
|
||||||
{
|
{
|
||||||
return true;
|
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);
|
int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size);
|
||||||
#endif /* !CONFIG_USER_ONLY */
|
#endif /* !CONFIG_USER_ONLY */
|
||||||
const ppc_def_t *kvmppc_host_cpu_def(void);
|
const ppc_def_t *kvmppc_host_cpu_def(void);
|
||||||
|
int kvmppc_fixup_cpu(CPUPPCState *env);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
@ -95,6 +96,10 @@ static inline const ppc_def_t *kvmppc_host_cpu_def(void)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int kvmppc_fixup_cpu(CPUPPCState *env)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef CONFIG_KVM
|
#ifndef CONFIG_KVM
|
||||||
|
@ -32,7 +32,6 @@ void cpu_save(QEMUFile *f, void *opaque)
|
|||||||
}
|
}
|
||||||
qemu_put_be32s(f, &env->fpscr);
|
qemu_put_be32s(f, &env->fpscr);
|
||||||
qemu_put_sbe32s(f, &env->access_type);
|
qemu_put_sbe32s(f, &env->access_type);
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
|
||||||
#if defined(TARGET_PPC64)
|
#if defined(TARGET_PPC64)
|
||||||
qemu_put_betls(f, &env->asr);
|
qemu_put_betls(f, &env->asr);
|
||||||
qemu_put_sbe32s(f, &env->slb_nr);
|
qemu_put_sbe32s(f, &env->slb_nr);
|
||||||
@ -62,7 +61,6 @@ void cpu_save(QEMUFile *f, void *opaque)
|
|||||||
}
|
}
|
||||||
for (i = 0; i < 4; i++)
|
for (i = 0; i < 4; i++)
|
||||||
qemu_put_betls(f, &env->pb[i]);
|
qemu_put_betls(f, &env->pb[i]);
|
||||||
#endif
|
|
||||||
for (i = 0; i < 1024; i++)
|
for (i = 0; i < 1024; i++)
|
||||||
qemu_put_betls(f, &env->spr[i]);
|
qemu_put_betls(f, &env->spr[i]);
|
||||||
qemu_put_be32s(f, &env->vscr);
|
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_be32s(f, &env->flags);
|
||||||
qemu_put_sbe32s(f, &env->error_code);
|
qemu_put_sbe32s(f, &env->error_code);
|
||||||
qemu_put_be32s(f, &env->pending_interrupts);
|
qemu_put_be32s(f, &env->pending_interrupts);
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
|
||||||
qemu_put_be32s(f, &env->irq_input_state);
|
qemu_put_be32s(f, &env->irq_input_state);
|
||||||
for (i = 0; i < POWERPC_EXCP_NB; i++)
|
for (i = 0; i < POWERPC_EXCP_NB; i++)
|
||||||
qemu_put_betls(f, &env->excp_vectors[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->ivor_mask);
|
||||||
qemu_put_betls(f, &env->ivpr_mask);
|
qemu_put_betls(f, &env->ivpr_mask);
|
||||||
qemu_put_betls(f, &env->hreset_vector);
|
qemu_put_betls(f, &env->hreset_vector);
|
||||||
#endif
|
|
||||||
qemu_put_betls(f, &env->nip);
|
qemu_put_betls(f, &env->nip);
|
||||||
qemu_put_betls(f, &env->hflags);
|
qemu_put_betls(f, &env->hflags);
|
||||||
qemu_put_betls(f, &env->hflags_nmsr);
|
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_be32s(f, &env->fpscr);
|
||||||
qemu_get_sbe32s(f, &env->access_type);
|
qemu_get_sbe32s(f, &env->access_type);
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
|
||||||
#if defined(TARGET_PPC64)
|
#if defined(TARGET_PPC64)
|
||||||
qemu_get_betls(f, &env->asr);
|
qemu_get_betls(f, &env->asr);
|
||||||
qemu_get_sbe32s(f, &env->slb_nr);
|
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++)
|
for (i = 0; i < 4; i++)
|
||||||
qemu_get_betls(f, &env->pb[i]);
|
qemu_get_betls(f, &env->pb[i]);
|
||||||
#endif
|
|
||||||
for (i = 0; i < 1024; i++)
|
for (i = 0; i < 1024; i++)
|
||||||
qemu_get_betls(f, &env->spr[i]);
|
qemu_get_betls(f, &env->spr[i]);
|
||||||
ppc_store_sdr1(env, sdr1);
|
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_be32s(f, &env->flags);
|
||||||
qemu_get_sbe32s(f, &env->error_code);
|
qemu_get_sbe32s(f, &env->error_code);
|
||||||
qemu_get_be32s(f, &env->pending_interrupts);
|
qemu_get_be32s(f, &env->pending_interrupts);
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
|
||||||
qemu_get_be32s(f, &env->irq_input_state);
|
qemu_get_be32s(f, &env->irq_input_state);
|
||||||
for (i = 0; i < POWERPC_EXCP_NB; i++)
|
for (i = 0; i < POWERPC_EXCP_NB; i++)
|
||||||
qemu_get_betls(f, &env->excp_vectors[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->ivor_mask);
|
||||||
qemu_get_betls(f, &env->ivpr_mask);
|
qemu_get_betls(f, &env->ivpr_mask);
|
||||||
qemu_get_betls(f, &env->hreset_vector);
|
qemu_get_betls(f, &env->hreset_vector);
|
||||||
#endif
|
|
||||||
qemu_get_betls(f, &env->nip);
|
qemu_get_betls(f, &env->nip);
|
||||||
qemu_get_betls(f, &env->hflags);
|
qemu_get_betls(f, &env->hflags);
|
||||||
qemu_get_betls(f, &env->hflags_nmsr);
|
qemu_get_betls(f, &env->hflags_nmsr);
|
||||||
|
@ -9306,8 +9306,8 @@ GEN_SPEOP_LDST(evstwwe, 0x1C, 2),
|
|||||||
GEN_SPEOP_LDST(evstwwo, 0x1E, 2),
|
GEN_SPEOP_LDST(evstwwo, 0x1E, 2),
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "translate_init.c"
|
|
||||||
#include "helper_regs.h"
|
#include "helper_regs.h"
|
||||||
|
#include "translate_init.c"
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Misc PowerPC helpers */
|
/* Misc PowerPC helpers */
|
||||||
|
@ -4462,7 +4462,10 @@ static void init_proc_e500 (CPUPPCState *env, int version)
|
|||||||
&spr_read_spefscr, &spr_write_spefscr,
|
&spr_read_spefscr, &spr_write_spefscr,
|
||||||
0x00000000);
|
0x00000000);
|
||||||
/* Memory management */
|
/* 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_pids = 3;
|
||||||
env->nb_ways = 2;
|
env->nb_ways = 2;
|
||||||
env->id_tlbs = 0;
|
env->id_tlbs = 0;
|
||||||
@ -9504,12 +9507,12 @@ enum {
|
|||||||
|
|
||||||
static inline int is_indirect_opcode (void *handler)
|
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)
|
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 */
|
/* 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));
|
tmp = malloc(0x20 * sizeof(opc_handler_t));
|
||||||
fill_new_table(tmp, 0x20);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -9889,6 +9892,28 @@ static int gdb_set_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
|
|||||||
return 0;
|
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)
|
int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
|
||||||
{
|
{
|
||||||
env->msr_mask = def->msr_mask;
|
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->bus_model = def->bus_model;
|
||||||
env->insns_flags = def->insns_flags;
|
env->insns_flags = def->insns_flags;
|
||||||
env->insns_flags2 = def->insns_flags2;
|
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->flags = def->flags;
|
||||||
env->bfd_mach = def->bfd_mach;
|
env->bfd_mach = def->bfd_mach;
|
||||||
env->check_pow = def->check_pow;
|
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)
|
if (create_ppc_opcodes(env, def) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
init_ppc_proc(env, def);
|
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);
|
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…
x
Reference in New Issue
Block a user