Merge branch 'ppc-for-upstream' of git://github.com/agraf/qemu

* 'ppc-for-upstream' of git://github.com/agraf/qemu:
  PPC: spapr: iommu: rework traces
  spapr: add "stop-self" RTAS call required to support hot CPU unplug
  PPC: KVM: Compile fix for qemu_notify_event
  pseries: Add H_SET_MODE hcall to change guest exception endianness
  xics: move registration of global state to realize()
  spapr-pci: rework MSI/MSIX
  target-ppc: Use #define instead of opencoding SLB valid bit
  spapr-pci: fix config space access to support bridges
  target-ppc: fix bit extraction for FPBF and FPL
  ppc405_boards: Don't enforce presence of firmware for qtest
  ppc405_uc: Disable debug output
  ppc405_boards: Disable debug output
  ppc: virtex_ml507: QEMU_OPTION_dtb support for this machine.
  disas/ppc.c: Fix little endian disassembly
  target-ppc: POWER7 supports the MSR_LE bit
  target-ppc: USE LPCR_ILE to control exception endian on POWER7
  pseries: Fix stalls on hypervisor virtual console
  PPC: E500: Generate device tree on reset
This commit is contained in:
Aurelien Jarno 2013-09-03 01:35:25 +02:00
commit 32f3bd6d4d
21 changed files with 306 additions and 161 deletions

View File

@ -5157,7 +5157,8 @@ int
print_insn_ppc (bfd_vma memaddr, struct disassemble_info *info)
{
int dialect = (char *) info->private_data - (char *) 0;
return print_insn_powerpc (memaddr, info, 1, dialect);
return print_insn_powerpc (memaddr, info, info->endian == BFD_ENDIAN_BIG,
dialect);
}
/* Print a big endian PowerPC instruction. */

View File

@ -47,6 +47,8 @@ static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max)
buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE];
}
qemu_chr_accept_input(dev->chardev);
return n;
}

View File

@ -642,6 +642,17 @@ static void xics_realize(DeviceState *dev, Error **errp)
ICSState *ics = icp->ics;
int i;
/* Registration of global state belongs into realize */
spapr_rtas_register("ibm,set-xive", rtas_set_xive);
spapr_rtas_register("ibm,get-xive", rtas_get_xive);
spapr_rtas_register("ibm,int-off", rtas_int_off);
spapr_rtas_register("ibm,int-on", rtas_int_on);
spapr_register_hypercall(H_CPPR, h_cppr);
spapr_register_hypercall(H_IPI, h_ipi);
spapr_register_hypercall(H_XIRR, h_xirr);
spapr_register_hypercall(H_EOI, h_eoi);
ics->nr_irqs = icp->nr_irqs;
ics->offset = XICS_IRQ_BASE;
ics->icp = icp;
@ -678,16 +689,6 @@ static void xics_class_init(ObjectClass *oc, void *data)
dc->realize = xics_realize;
dc->props = xics_properties;
dc->reset = xics_reset;
spapr_rtas_register("ibm,set-xive", rtas_set_xive);
spapr_rtas_register("ibm,get-xive", rtas_get_xive);
spapr_rtas_register("ibm,int-off", rtas_int_off);
spapr_rtas_register("ibm,int-on", rtas_int_on);
spapr_register_hypercall(H_CPPR, h_cppr);
spapr_register_hypercall(H_IPI, h_ipi);
spapr_register_hypercall(H_XIRR, h_xirr);
spapr_register_hypercall(H_EOI, h_eoi);
}
static const TypeInfo xics_info = {

View File

@ -123,13 +123,14 @@ static void dt_serial_create(void *fdt, unsigned long long offset,
}
}
static int ppce500_load_device_tree(CPUPPCState *env,
QEMUMachineInitArgs *args,
static int ppce500_load_device_tree(QEMUMachineInitArgs *args,
PPCE500Params *params,
hwaddr addr,
hwaddr initrd_base,
hwaddr initrd_size)
hwaddr initrd_size,
bool dry_run)
{
CPUPPCState *env = first_cpu->env_ptr;
int ret = -1;
uint64_t mem_reg_property[] = { 0, cpu_to_be64(args->ram_size) };
int fdt_size;
@ -369,12 +370,10 @@ static int ppce500_load_device_tree(CPUPPCState *env,
}
done:
qemu_devtree_dumpdtb(fdt, fdt_size);
ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
if (ret < 0) {
goto out;
if (!dry_run) {
qemu_devtree_dumpdtb(fdt, fdt_size);
cpu_physical_memory_write(addr, fdt, fdt_size);
}
g_free(fdt);
ret = fdt_size;
out:
@ -383,6 +382,41 @@ out:
return ret;
}
typedef struct DeviceTreeParams {
QEMUMachineInitArgs args;
PPCE500Params params;
hwaddr addr;
hwaddr initrd_base;
hwaddr initrd_size;
} DeviceTreeParams;
static void ppce500_reset_device_tree(void *opaque)
{
DeviceTreeParams *p = opaque;
ppce500_load_device_tree(&p->args, &p->params, p->addr, p->initrd_base,
p->initrd_size, false);
}
static int ppce500_prep_device_tree(QEMUMachineInitArgs *args,
PPCE500Params *params,
hwaddr addr,
hwaddr initrd_base,
hwaddr initrd_size)
{
DeviceTreeParams *p = g_new(DeviceTreeParams, 1);
p->args = *args;
p->params = *params;
p->addr = addr;
p->initrd_base = initrd_base;
p->initrd_size = initrd_size;
qemu_register_reset(ppce500_reset_device_tree, p);
/* Issue the device tree loader once, so that we get the size of the blob */
return ppce500_load_device_tree(args, params, addr, initrd_base,
initrd_size, true);
}
/* Create -kernel TLB entries for BookE. */
static inline hwaddr booke206_page_size_to_tlb(uint64_t size)
{
@ -746,7 +780,7 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params)
struct boot_info *boot_info;
int dt_size;
dt_size = ppce500_load_device_tree(env, args, params, dt_base,
dt_size = ppce500_prep_device_tree(args, params, dt_base,
initrd_base, initrd_size);
if (dt_size < 0) {
fprintf(stderr, "couldn't load device tree\n");

View File

@ -27,9 +27,11 @@
#include "hw/timer/m48t59.h"
#include "hw/block/flash.h"
#include "sysemu/sysemu.h"
#include "sysemu/qtest.h"
#include "block/block.h"
#include "hw/boards.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
#include "hw/loader.h"
#include "sysemu/blockdev.h"
#include "exec/address-spaces.h"
@ -42,7 +44,7 @@
#define USE_FLASH_BIOS
#define DEBUG_BOARD_INIT
//#define DEBUG_BOARD_INIT
/*****************************************************************************/
/* PPC405EP reference board (IBM) */
@ -252,17 +254,20 @@ static void ref405ep_init(QEMUMachineInitArgs *args)
if (filename) {
bios_size = load_image(filename, memory_region_get_ram_ptr(bios));
g_free(filename);
if (bios_size < 0 || bios_size > BIOS_SIZE) {
error_report("Could not load PowerPC BIOS '%s'", bios_name);
exit(1);
}
bios_size = (bios_size + 0xfff) & ~0xfff;
memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
} else if (!qtest_enabled() || kernel_filename != NULL) {
error_report("Could not load PowerPC BIOS '%s'", bios_name);
exit(1);
} else {
/* Avoid an uninitialized variable warning */
bios_size = -1;
}
if (bios_size < 0 || bios_size > BIOS_SIZE) {
fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n",
bios_name);
exit(1);
}
bios_size = (bios_size + 0xfff) & ~0xfff;
memory_region_set_readonly(bios, true);
memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
}
/* Register FPGA */
#ifdef DEBUG_BOARD_INIT
@ -353,9 +358,9 @@ static void ref405ep_init(QEMUMachineInitArgs *args)
bdloc = 0;
}
#ifdef DEBUG_BOARD_INIT
printf("bdloc " RAM_ADDR_FMT "\n", bdloc);
printf("%s: Done\n", __func__);
#endif
printf("bdloc " RAM_ADDR_FMT "\n", bdloc);
}
static QEMUMachine ref405ep_machine = {
@ -569,17 +574,17 @@ static void taihu_405ep_init(QEMUMachineInitArgs *args)
if (filename) {
bios_size = load_image(filename, memory_region_get_ram_ptr(bios));
g_free(filename);
} else {
bios_size = -1;
}
if (bios_size < 0 || bios_size > BIOS_SIZE) {
fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n",
bios_name);
if (bios_size < 0 || bios_size > BIOS_SIZE) {
error_report("Could not load PowerPC BIOS '%s'", bios_name);
exit(1);
}
bios_size = (bios_size + 0xfff) & ~0xfff;
memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
} else if (!qtest_enabled()) {
error_report("Could not load PowerPC BIOS '%s'", bios_name);
exit(1);
}
bios_size = (bios_size + 0xfff) & ~0xfff;
memory_region_set_readonly(bios, true);
memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
}
/* Register Linux flash */
dinfo = drive_get(IF_PFLASH, 0, fl_idx);

View File

@ -30,15 +30,15 @@
#include "qemu/log.h"
#include "exec/address-spaces.h"
#define DEBUG_OPBA
#define DEBUG_SDRAM
#define DEBUG_GPIO
#define DEBUG_SERIAL
#define DEBUG_OCM
//#define DEBUG_OPBA
//#define DEBUG_SDRAM
//#define DEBUG_GPIO
//#define DEBUG_SERIAL
//#define DEBUG_OCM
//#define DEBUG_I2C
#define DEBUG_GPT
#define DEBUG_MAL
#define DEBUG_CLOCKS
//#define DEBUG_GPT
//#define DEBUG_MAL
//#define DEBUG_CLOCKS
//#define DEBUG_CLOCKS_LL
ram_addr_t ppc405_set_bootinfo (CPUPPCState *env, ppc4xx_bd_info_t *bd,

View File

@ -88,6 +88,9 @@ int spapr_allocate_irq(int hint, bool lsi)
if (hint) {
irq = hint;
if (hint >= spapr->next_irq) {
spapr->next_irq = hint + 1;
}
/* FIXME: we should probably check for collisions somehow */
} else {
irq = spapr->next_irq++;
@ -103,22 +106,39 @@ int spapr_allocate_irq(int hint, bool lsi)
return irq;
}
/* Allocate block of consequtive IRQs, returns a number of the first */
int spapr_allocate_irq_block(int num, bool lsi)
/*
* Allocate block of consequtive IRQs, returns a number of the first.
* If msi==true, aligns the first IRQ number to num.
*/
int spapr_allocate_irq_block(int num, bool lsi, bool msi)
{
int first = -1;
int i;
int i, hint = 0;
/*
* MSIMesage::data is used for storing VIRQ so
* it has to be aligned to num to support multiple
* MSI vectors. MSI-X is not affected by this.
* The hint is used for the first IRQ, the rest should
* be allocated continously.
*/
if (msi) {
assert((num == 1) || (num == 2) || (num == 4) ||
(num == 8) || (num == 16) || (num == 32));
hint = (spapr->next_irq + num - 1) & ~(num - 1);
}
for (i = 0; i < num; ++i) {
int irq;
irq = spapr_allocate_irq(0, lsi);
irq = spapr_allocate_irq(hint, lsi);
if (!irq) {
return -1;
}
if (0 == i) {
first = irq;
hint = 0;
}
/* If the above doesn't create a consecutive block then that's
@ -262,7 +282,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
uint32_t start_prop = cpu_to_be32(initrd_base);
uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt"
"\0hcall-tce\0hcall-vio\0hcall-splpar\0hcall-bulk";
"\0hcall-tce\0hcall-vio\0hcall-splpar\0hcall-bulk\0hcall-set-mode";
char qemu_hypertas_prop[] = "hcall-memop1";
uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)};
uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
@ -1214,6 +1234,7 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
spapr_create_nvram(spapr);
/* Set up PCI */
spapr_pci_msi_init(spapr, SPAPR_PCI_MSI_WINDOW);
spapr_pci_rtas_init();
phb = spapr_create_phb(spapr, 0);

View File

@ -657,6 +657,54 @@ static target_ulong h_logical_dcbf(PowerPCCPU *cpu, sPAPREnvironment *spapr,
return H_SUCCESS;
}
static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong opcode, target_ulong *args)
{
CPUState *cs;
target_ulong mflags = args[0];
target_ulong resource = args[1];
target_ulong value1 = args[2];
target_ulong value2 = args[3];
target_ulong ret = H_P2;
if (resource == H_SET_MODE_ENDIAN) {
if (value1) {
ret = H_P3;
goto out;
}
if (value2) {
ret = H_P4;
goto out;
}
switch (mflags) {
case H_SET_MODE_ENDIAN_BIG:
for (cs = first_cpu; cs != NULL; cs = cs->next_cpu) {
PowerPCCPU *cp = POWERPC_CPU(cs);
CPUPPCState *env = &cp->env;
env->spr[SPR_LPCR] &= ~LPCR_ILE;
}
ret = H_SUCCESS;
break;
case H_SET_MODE_ENDIAN_LITTLE:
for (cs = first_cpu; cs != NULL; cs = cs->next_cpu) {
PowerPCCPU *cp = POWERPC_CPU(cs);
CPUPPCState *env = &cp->env;
env->spr[SPR_LPCR] |= LPCR_ILE;
}
ret = H_SUCCESS;
break;
default:
ret = H_UNSUPPORTED_FLAG;
}
}
out:
return ret;
}
static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1];
@ -734,6 +782,8 @@ static void hypercall_register_types(void)
/* qemu/KVM-PPC specific hcalls */
spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
spapr_register_hypercall(H_SET_MODE, h_set_mode);
}
type_init(hypercall_register_types)

View File

@ -22,13 +22,12 @@
#include "kvm_ppc.h"
#include "sysemu/dma.h"
#include "exec/address-spaces.h"
#include "trace.h"
#include "hw/ppc/spapr.h"
#include <libfdt.h>
/* #define DEBUG_TCE */
enum sPAPRTCEAccess {
SPAPR_TCE_FAULT = 0,
SPAPR_TCE_RO = 1,
@ -61,44 +60,28 @@ static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr)
{
sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu);
uint64_t tce;
#ifdef DEBUG_TCE
fprintf(stderr, "spapr_tce_translate liobn=0x%" PRIx32 " addr=0x"
DMA_ADDR_FMT "\n", tcet->liobn, addr);
#endif
IOMMUTLBEntry ret = {
.target_as = &address_space_memory,
.iova = 0,
.translated_addr = 0,
.addr_mask = ~(hwaddr)0,
.perm = IOMMU_NONE,
};
if (tcet->bypass) {
return (IOMMUTLBEntry) {
.target_as = &address_space_memory,
.iova = 0,
.translated_addr = 0,
.addr_mask = ~(hwaddr)0,
.perm = IOMMU_RW,
};
ret.perm = IOMMU_RW;
} else if (addr < tcet->window_size) {
/* Check if we are in bound */
tce = tcet->table[addr >> SPAPR_TCE_PAGE_SHIFT];
ret.iova = addr & ~SPAPR_TCE_PAGE_MASK;
ret.translated_addr = tce & ~SPAPR_TCE_PAGE_MASK;
ret.addr_mask = SPAPR_TCE_PAGE_MASK;
ret.perm = tce;
}
trace_spapr_iommu_xlate(tcet->liobn, addr, ret.iova, ret.perm,
ret.addr_mask);
/* Check if we are in bound */
if (addr >= tcet->window_size) {
#ifdef DEBUG_TCE
fprintf(stderr, "spapr_tce_translate out of bounds\n");
#endif
return (IOMMUTLBEntry) { .perm = IOMMU_NONE };
}
tce = tcet->table[addr >> SPAPR_TCE_PAGE_SHIFT];
#ifdef DEBUG_TCE
fprintf(stderr, " -> *paddr=0x%llx, *len=0x%llx\n",
(tce & ~SPAPR_TCE_PAGE_MASK), SPAPR_TCE_PAGE_MASK + 1);
#endif
return (IOMMUTLBEntry) {
.target_as = &address_space_memory,
.iova = addr & ~SPAPR_TCE_PAGE_MASK,
.translated_addr = tce & ~SPAPR_TCE_PAGE_MASK,
.addr_mask = SPAPR_TCE_PAGE_MASK,
.perm = tce,
};
return ret;
}
static int spapr_tce_table_pre_load(void *opaque)
@ -150,10 +133,7 @@ static int spapr_tce_table_realize(DeviceState *dev)
}
tcet->nb_table = tcet->window_size >> SPAPR_TCE_PAGE_SHIFT;
#ifdef DEBUG_TCE
fprintf(stderr, "spapr_iommu: New TCE table @ %p, liobn=0x%x, "
"table @ %p, fd=%d\n", tcet, liobn, tcet->table, tcet->fd);
#endif
trace_spapr_iommu_new_table(tcet->liobn, tcet, tcet->table, tcet->fd);
memory_region_init_iommu(&tcet->iommu, OBJECT(dev), &spapr_iommu_ops,
"iommu-spapr", UINT64_MAX);
@ -250,20 +230,17 @@ static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong liobn = args[0];
target_ulong ioba = args[1];
target_ulong tce = args[2];
target_ulong ret = H_PARAMETER;
sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
ioba &= ~(SPAPR_TCE_PAGE_SIZE - 1);
if (tcet) {
return put_tce_emu(tcet, ioba, tce);
ret = put_tce_emu(tcet, ioba, tce);
}
#ifdef DEBUG_TCE
fprintf(stderr, "%s on liobn=" TARGET_FMT_lx /*%s*/
" ioba 0x" TARGET_FMT_lx " TCE 0x" TARGET_FMT_lx "\n",
__func__, liobn, /*dev->qdev.id, */ioba, tce);
#endif
trace_spapr_iommu_put(liobn, ioba, tce, ret);
return H_PARAMETER;
return ret;
}
int spapr_dma_dt(void *fdt, int node_off, const char *propname,

View File

@ -65,22 +65,14 @@ static PCIDevice *find_dev(sPAPREnvironment *spapr, uint64_t buid,
{
sPAPRPHBState *sphb = find_phb(spapr, buid);
PCIHostState *phb = PCI_HOST_BRIDGE(sphb);
BusState *bus = BUS(phb->bus);
BusChild *kid;
int bus_num = (config_addr >> 16) & 0xFF;
int devfn = (config_addr >> 8) & 0xFF;
if (!phb) {
return NULL;
}
QTAILQ_FOREACH(kid, &bus->children, sibling) {
PCIDevice *dev = (PCIDevice *)kid->child;
if (dev->devfn == devfn) {
return dev;
}
}
return NULL;
return pci_find_device(phb->bus, bus_num, devfn);
}
static uint32_t rtas_pci_cfgaddr(uint32_t arg)
@ -258,11 +250,11 @@ static int spapr_msicfg_find(sPAPRPHBState *phb, uint32_t config_addr,
* This is required for msi_notify()/msix_notify() which
* will write at the addresses via spapr_msi_write().
*/
static void spapr_msi_setmsg(PCIDevice *pdev, hwaddr addr,
bool msix, unsigned req_num)
static void spapr_msi_setmsg(PCIDevice *pdev, hwaddr addr, bool msix,
unsigned first_irq, unsigned req_num)
{
unsigned i;
MSIMessage msg = { .address = addr, .data = 0 };
MSIMessage msg = { .address = addr, .data = first_irq };
if (!msix) {
msi_set_message(pdev, msg);
@ -270,8 +262,7 @@ static void spapr_msi_setmsg(PCIDevice *pdev, hwaddr addr,
return;
}
for (i = 0; i < req_num; ++i) {
msg.address = addr | (i << 2);
for (i = 0; i < req_num; ++i, ++msg.data) {
msix_set_message(pdev, i, msg);
trace_spapr_pci_msi_setup(pdev->name, i, msg.address);
}
@ -351,7 +342,8 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
/* There is no cached config, allocate MSIs */
if (!phb->msi_table[ndev].nvec) {
irq = spapr_allocate_irq_block(req_num, false);
irq = spapr_allocate_irq_block(req_num, false,
ret_intr_type == RTAS_TYPE_MSI);
if (irq < 0) {
fprintf(stderr, "Cannot allocate MSIs for device#%d", ndev);
rtas_st(rets, 0, -1); /* Hardware error */
@ -363,8 +355,8 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
}
/* Setup MSI/MSIX vectors in the device (via cfgspace or MSIX BAR) */
spapr_msi_setmsg(pdev, phb->msi_win_addr | (ndev << 16),
ret_intr_type == RTAS_TYPE_MSIX, req_num);
spapr_msi_setmsg(pdev, spapr->msi_win_addr, ret_intr_type == RTAS_TYPE_MSIX,
phb->msi_table[ndev].irq, req_num);
rtas_st(rets, 0, 0);
rtas_st(rets, 1, req_num);
@ -450,10 +442,7 @@ static void pci_spapr_set_irq(void *opaque, int irq_num, int level)
static void spapr_msi_write(void *opaque, hwaddr addr,
uint64_t data, unsigned size)
{
sPAPRPHBState *phb = opaque;
int ndev = addr >> 16;
int vec = ((addr & 0xFFFF) >> 2) | data;
uint32_t irq = phb->msi_table[ndev].irq + vec;
uint32_t irq = data;
trace_spapr_pci_msi_write(addr, data, irq);
@ -467,6 +456,23 @@ static const MemoryRegionOps spapr_msi_ops = {
.endianness = DEVICE_LITTLE_ENDIAN
};
void spapr_pci_msi_init(sPAPREnvironment *spapr, hwaddr addr)
{
/*
* As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors,
* we need to allocate some memory to catch those writes coming
* from msi_notify()/msix_notify().
* As MSIMessage:addr is going to be the same and MSIMessage:data
* is going to be a VIRQ number, 4 bytes of the MSI MR will only
* be used.
*/
spapr->msi_win_addr = addr;
memory_region_init_io(&spapr->msiwindow, NULL, &spapr_msi_ops, spapr,
"msi", getpagesize());
memory_region_add_subregion(get_system_memory(), spapr->msi_win_addr,
&spapr->msiwindow);
}
/*
* PHB PCI device
*/
@ -492,8 +498,7 @@ static int spapr_phb_init(SysBusDevice *s)
if ((sphb->buid != -1) || (sphb->dma_liobn != -1)
|| (sphb->mem_win_addr != -1)
|| (sphb->io_win_addr != -1)
|| (sphb->msi_win_addr != -1)) {
|| (sphb->io_win_addr != -1)) {
fprintf(stderr, "Either \"index\" or other parameters must"
" be specified for PAPR PHB, not both\n");
return -1;
@ -506,7 +511,6 @@ static int spapr_phb_init(SysBusDevice *s)
+ sphb->index * SPAPR_PCI_WINDOW_SPACING;
sphb->mem_win_addr = windows_base + SPAPR_PCI_MMIO_WIN_OFF;
sphb->io_win_addr = windows_base + SPAPR_PCI_IO_WIN_OFF;
sphb->msi_win_addr = windows_base + SPAPR_PCI_MSI_WIN_OFF;
}
if (sphb->buid == -1) {
@ -529,11 +533,6 @@ static int spapr_phb_init(SysBusDevice *s)
return -1;
}
if (sphb->msi_win_addr == -1) {
fprintf(stderr, "MSI window address not specified for PHB\n");
return -1;
}
if (find_phb(spapr, sphb->buid)) {
fprintf(stderr, "PCI host bridges must have unique BUIDs\n");
return -1;
@ -573,18 +572,6 @@ static int spapr_phb_init(SysBusDevice *s)
get_system_io(), 0, SPAPR_PCI_IO_WIN_SIZE);
memory_region_add_subregion(get_system_memory(), sphb->io_win_addr,
&sphb->iowindow);
/* As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors,
* we need to allocate some memory to catch those writes coming
* from msi_notify()/msix_notify() */
if (msi_supported) {
sprintf(namebuf, "%s.msi", sphb->dtbusname);
memory_region_init_io(&sphb->msiwindow, OBJECT(sphb), &spapr_msi_ops, sphb,
namebuf, SPAPR_MSIX_MAX_DEVS * 0x10000);
memory_region_add_subregion(get_system_memory(), sphb->msi_win_addr,
&sphb->msiwindow);
}
/*
* Selecting a busname is more complex than you'd think, due to
* interacting constraints. If the user has specified an id
@ -659,7 +646,6 @@ static Property spapr_phb_properties[] = {
DEFINE_PROP_HEX64("io_win_addr", sPAPRPHBState, io_win_addr, -1),
DEFINE_PROP_HEX64("io_win_size", sPAPRPHBState, io_win_size,
SPAPR_PCI_IO_WIN_SIZE),
DEFINE_PROP_HEX64("msi_win_addr", sPAPRPHBState, msi_win_addr, -1),
DEFINE_PROP_END_OF_LIST(),
};
@ -701,7 +687,6 @@ static const VMStateDescription vmstate_spapr_pci = {
VMSTATE_UINT64_EQUAL(mem_win_size, sPAPRPHBState),
VMSTATE_UINT64_EQUAL(io_win_addr, sPAPRPHBState),
VMSTATE_UINT64_EQUAL(io_win_size, sPAPRPHBState),
VMSTATE_UINT64_EQUAL(msi_win_addr, sPAPRPHBState),
VMSTATE_STRUCT_ARRAY(lsi_table, sPAPRPHBState, PCI_NUM_PINS, 0,
vmstate_spapr_pci_lsi, struct spapr_pci_lsi),
VMSTATE_STRUCT_ARRAY(msi_table, sPAPRPHBState, SPAPR_MSIX_MAX_DEVS, 0,

View File

@ -202,6 +202,28 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPREnvironment *spapr,
rtas_st(rets, 0, -3);
}
static void rtas_stop_self(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
cs->halted = 1;
cpu_exit(cs);
/*
* While stopping a CPU, the guest calls H_CPPR which
* effectively disables interrupts on XICS level.
* However decrementer interrupts in TCG can still
* wake the CPU up so here we disable interrupts in MSR
* as well.
* As rtas_start_cpu() resets the whole MSR anyway, there is
* no need to bother with specific bits, we just clear it.
*/
env->msr = 0;
}
static struct rtas_call {
const char *name;
spapr_rtas_fn fn;
@ -322,6 +344,7 @@ static void core_rtas_register_types(void)
spapr_rtas_register("query-cpu-stopped-state",
rtas_query_cpu_stopped_state);
spapr_rtas_register("start-cpu", rtas_start_cpu);
spapr_rtas_register("stop-self", rtas_stop_self);
}
type_init(core_rtas_register_types)

View File

@ -141,22 +141,31 @@ static int xilinx_load_device_tree(hwaddr addr,
{
char *path;
int fdt_size;
void *fdt;
void *fdt = NULL;
int r;
const char *dtb_filename;
/* Try the local "ppc.dtb" override. */
fdt = load_device_tree("ppc.dtb", &fdt_size);
if (!fdt) {
path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
if (path) {
fdt = load_device_tree(path, &fdt_size);
g_free(path);
}
dtb_filename = qemu_opt_get(qemu_get_machine_opts(), "dtb");
if (dtb_filename) {
fdt = load_device_tree(dtb_filename, &fdt_size);
if (!fdt) {
return 0;
error_report("Error while loading device tree file '%s'",
dtb_filename);
}
} else {
/* Try the local "ppc.dtb" override. */
fdt = load_device_tree("ppc.dtb", &fdt_size);
if (!fdt) {
path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
if (path) {
fdt = load_device_tree(path, &fdt_size);
g_free(path);
}
}
}
if (!fdt) {
return 0;
}
r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline);
if (r < 0)
fprintf(stderr, "couldn't set /chosen/bootargs\n");

View File

@ -43,8 +43,7 @@ typedef struct sPAPRPHBState {
MemoryRegion memspace, iospace;
hwaddr mem_win_addr, mem_win_size, io_win_addr, io_win_size;
hwaddr msi_win_addr;
MemoryRegion memwindow, iowindow, msiwindow;
MemoryRegion memwindow, iowindow;
uint32_t dma_liobn;
uint64_t dma_window_start;
@ -73,7 +72,8 @@ typedef struct sPAPRPHBState {
#define SPAPR_PCI_MMIO_WIN_SIZE 0x20000000
#define SPAPR_PCI_IO_WIN_OFF 0x80000000
#define SPAPR_PCI_IO_WIN_SIZE 0x10000
#define SPAPR_PCI_MSI_WIN_OFF 0x90000000
#define SPAPR_PCI_MSI_WINDOW 0x40000000000ULL
#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL
@ -88,6 +88,8 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,
uint32_t xics_phandle,
void *fdt);
void spapr_pci_msi_init(sPAPREnvironment *spapr, hwaddr addr);
void spapr_pci_rtas_init(void);
#endif /* __HW_SPAPR_PCI_H__ */

View File

@ -13,6 +13,8 @@ struct sPAPRNVRAM;
typedef struct sPAPREnvironment {
struct VIOsPAPRBus *vio_bus;
QLIST_HEAD(, sPAPRPHBState) phbs;
hwaddr msi_win_addr;
MemoryRegion msiwindow;
struct sPAPRNVRAM *nvram;
XICSState *icp;
@ -109,6 +111,15 @@ typedef struct sPAPREnvironment {
#define H_NOT_ENOUGH_RESOURCES -44
#define H_R_STATE -45
#define H_RESCINDEND -46
#define H_P2 -55
#define H_P3 -56
#define H_P4 -57
#define H_P5 -58
#define H_P6 -59
#define H_P7 -60
#define H_P8 -61
#define H_P9 -62
#define H_UNSUPPORTED_FLAG -256
#define H_MULTI_THREADS_ACTIVE -9005
@ -143,6 +154,11 @@ typedef struct sPAPREnvironment {
#define H_PP1 (1ULL<<(63-62))
#define H_PP2 (1ULL<<(63-63))
/* H_SET_MODE flags */
#define H_SET_MODE_ENDIAN 4
#define H_SET_MODE_ENDIAN_BIG 0
#define H_SET_MODE_ENDIAN_LITTLE 1
/* VASI States */
#define H_VASI_INVALID 0
#define H_VASI_ENABLED 1
@ -267,7 +283,8 @@ typedef struct sPAPREnvironment {
#define H_GET_EM_PARMS 0x2B8
#define H_SET_MPP 0x2D0
#define H_GET_MPP 0x2D4
#define MAX_HCALL_OPCODE H_GET_MPP
#define H_SET_MODE 0x31C
#define MAX_HCALL_OPCODE H_SET_MODE
/* The hcalls above are standardized in PAPR and implemented by pHyp
* as well.
@ -303,7 +320,7 @@ target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
target_ulong *args);
int spapr_allocate_irq(int hint, bool lsi);
int spapr_allocate_irq_block(int num, bool lsi);
int spapr_allocate_irq_block(int num, bool lsi, bool msi);
static inline int spapr_allocate_msi(int hint)
{

View File

@ -453,6 +453,8 @@ struct ppc_slb_t {
#define MSR_RI 1 /* Recoverable interrupt 1 */
#define MSR_LE 0 /* Little-endian mode 1 hflags */
#define LPCR_ILE (1 << (63-38))
#define msr_sf ((env->msr >> MSR_SF) & 1)
#define msr_isf ((env->msr >> MSR_ISF) & 1)
#define msr_shv ((env->msr >> MSR_SHV) & 1)

View File

@ -611,9 +611,19 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
tlb_flush(env, 1);
}
#ifdef TARGET_PPC64
if (excp_model == POWERPC_EXCP_POWER7) {
if (env->spr[SPR_LPCR] & LPCR_ILE) {
new_msr |= (target_ulong)1 << MSR_LE;
}
} else if (msr_ile) {
new_msr |= (target_ulong)1 << MSR_LE;
}
#else
if (msr_ile) {
new_msr |= (target_ulong)1 << MSR_LE;
}
#endif
/* Jump to handler */
vector = env->excp_vectors[excp];

View File

@ -15,6 +15,7 @@
#include "qemu/timer.h"
#include "kvm_ppc.h"
#include "sysemu/device_tree.h"
#include "qemu/main-loop.h"
#define PROC_DEVTREE_PATH "/proc/device-tree"

View File

@ -2061,7 +2061,7 @@ void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value)
/* ESID = srnum */
rb |= ((uint32_t)srnum & 0xf) << 28;
/* Set the valid bit */
rb |= 1 << 27;
rb |= SLB_ESID_V;
/* Index = ESID */
rb |= (uint32_t)srnum;

View File

@ -428,9 +428,9 @@ EXTRACT_HELPER(CRM, 12, 8);
EXTRACT_HELPER(SR, 16, 4);
/* mtfsf/mtfsfi */
EXTRACT_HELPER(FPBF, 19, 3);
EXTRACT_HELPER(FPBF, 23, 3);
EXTRACT_HELPER(FPIMM, 12, 4);
EXTRACT_HELPER(FPL, 21, 1);
EXTRACT_HELPER(FPL, 25, 1);
EXTRACT_HELPER(FPFLM, 17, 8);
EXTRACT_HELPER(FPW, 16, 1);

View File

@ -7227,7 +7227,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
PPC_SEGMENT_64B | PPC_SLBI |
PPC_POPCNTB | PPC_POPCNTWD;
pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX | PPC2_ISA205;
pcc->msr_mask = 0x800000000204FF36ULL;
pcc->msr_mask = 0x800000000204FF37ULL;
pcc->mmu_model = POWERPC_MMU_2_06;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;

View File

@ -1133,6 +1133,11 @@ xics_ics_write_xive(int nr, int srcno, int server, uint8_t priority) "ics_write_
xics_ics_reject(int nr, int srcno) "reject irq %#x [src %d]"
xics_ics_eoi(int nr) "ics_eoi: irq %#x"
# hw/ppc/spapr_iommu.c
spapr_iommu_put(uint64_t liobn, uint64_t ioba, uint64_t tce, uint64_t ret) "liobn=%"PRIx64" ioba=0x%"PRIx64" tce=0x%"PRIx64" ret=%"PRId64
spapr_iommu_xlate(uint64_t liobn, uint64_t ioba, uint64_t tce, unsigned perm, unsigned pgsize) "liobn=%"PRIx64" 0x%"PRIx64" -> 0x%"PRIx64" perm=%u mask=%x"
spapr_iommu_new_table(uint64_t liobn, void *tcet, void *table, int fd) "liobn=%"PRIx64" tcet=%p table=%p fd=%d"
# util/hbitmap.c
hbitmap_iter_skip_words(const void *hb, void *hbi, uint64_t pos, unsigned long cur) "hb %p hbi %p pos %"PRId64" cur 0x%lx"
hbitmap_reset(void *hb, uint64_t start, uint64_t count, uint64_t sbit, uint64_t ebit) "hb %p items %"PRIu64",%"PRIu64" bits %"PRIu64"..%"PRIu64