提交 af44da87 编写于 作者: P Peter Maydell

Merge remote-tracking branch 'remotes/agraf/tags/signed-ppc-for-upstream' into staging

Patch queue for ppc - 2014-06-16

This pull request brings a lot of fun things. Among others we have

  - e500: u-boot firmware support
  - sPAPR: magic page enablement
  - sPAPR: add "compat" CPU option to support older guests
  - sPAPR: refactorings in preparation for VFIO
  - POWER8 live migration
  - mac99: expose bus frequency
  - little endian core dump, gdb and disas support
  - new ppc64le-linux-user target
  - DFP emulation
  - bug fixes

# gpg: Signature made Mon 16 Jun 2014 12:28:32 BST using RSA key ID 03FEDC60
# gpg: Can't check signature: public key not found

* remotes/agraf/tags/signed-ppc-for-upstream: (156 commits)
  spapr_pci: Advertise MSI quota
  PPC: KVM: Make pv hcall endian agnostic
  powerpc: use float64 for frsqrte
  spapr: Add kvm-type property
  spapr: Create SPAPRMachine struct
  linux-user: Tell guest about big host page sizes
  spapr_hcall: Add address-translation-mode-on-interrupt resource in H_SET_MODE
  spapr_hcall: Split h_set_mode()
  target-ppc: Enable DABRX SPR and limit it to <=POWER7
  target-ppc: Enable PPR and VRSAVE SPRs migration
  target-ppc: Add POWER8's Event Based Branch (EBB) control SPRs
  KVM: target-ppc: Enable TM state migration
  target-ppc: Add POWER8's TM SPRs
  target-ppc: Add POWER8's MMCR2/MMCRS SPRs
  target-ppc: Enable FSCR facility check for TAR
  target-ppc: Add POWER8's FSCR SPR
  target-ppc: Add POWER8's TIR SPR
  target-ppc: Refactor class init for POWER7/8
  target-ppc: Switch POWER7/8 classes to use correct PMU SPRs
  target-ppc: Make use of gen_spr_power5p_lpar() for POWER7/8
  ...
Signed-off-by: NPeter Maydell <peter.maydell@linaro.org>
......@@ -28,3 +28,6 @@
[submodule "dtc"]
path = dtc
url = git://git.qemu-project.org/dtc.git
[submodule "roms/u-boot"]
path = roms/u-boot
url = git://git.qemu-project.org/u-boot.git
......@@ -85,6 +85,12 @@ obj-y += disas.o
obj-$(call notempty,$(TARGET_XML_FILES)) += gdbstub-xml.o
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
obj-$(CONFIG_LIBDECNUMBER) += libdecnumber/decContext.o
obj-$(CONFIG_LIBDECNUMBER) += libdecnumber/decNumber.o
obj-$(CONFIG_LIBDECNUMBER) += libdecnumber/dpd/decimal32.o
obj-$(CONFIG_LIBDECNUMBER) += libdecnumber/dpd/decimal64.o
obj-$(CONFIG_LIBDECNUMBER) += libdecnumber/dpd/decimal128.o
#########################################################
# Linux user emulator target
......
......@@ -4955,6 +4955,12 @@ case "$target_name" in
TARGET_ABI_DIR=ppc
gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
;;
ppc64le)
TARGET_ARCH=ppc64
TARGET_BASE_ARCH=ppc
TARGET_ABI_DIR=ppc
gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
;;
ppc64abi32)
TARGET_ARCH=ppc64
TARGET_BASE_ARCH=ppc
......@@ -5222,6 +5228,7 @@ for bios_file in \
$source_path/pc-bios/*.dtb \
$source_path/pc-bios/*.img \
$source_path/pc-bios/openbios-* \
$source_path/pc-bios/u-boot.* \
$source_path/pc-bios/palcode-*
do
FILES="$FILES pc-bios/`basename $bios_file`"
......
# Default configuration for ppc-linux-user
CONFIG_LIBDECNUMBER=y
......@@ -49,3 +49,4 @@ CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM))
CONFIG_MC146818RTC=y
CONFIG_ETSEC=y
CONFIG_ISA_TESTDEV=y
CONFIG_LIBDECNUMBER=y
# Default configuration for ppc64-linux-user
CONFIG_LIBDECNUMBER=y
......@@ -58,3 +58,4 @@ CONFIG_I82374=y
CONFIG_I8257=y
CONFIG_MC146818RTC=y
CONFIG_ISA_TESTDEV=y
CONFIG_LIBDECNUMBER=y
# Default configuration for ppc64abi32-linux-user
CONFIG_LIBDECNUMBER=y
# Default configuration for ppc64le-linux-user
CONFIG_LIBDECNUMBER=y
......@@ -16,3 +16,4 @@ CONFIG_I8259=y
CONFIG_XILINX=y
CONFIG_XILINX_ETHLITE=y
CONFIG_OPENPIC=y
CONFIG_LIBDECNUMBER=y
......@@ -191,7 +191,8 @@ static int print_insn_od_target(bfd_vma pc, disassemble_info *info)
values:
i386 - 1 means 16 bit code, 2 means 64 bit code
arm - bit 0 = thumb, bit 1 = reverse endian, bit 2 = A64
ppc - nonzero means little endian
ppc - bits 0:15 specify (optionally) the machine instruction set;
bit 16 indicates little endian.
other targets - unused
*/
void target_disas(FILE *out, CPUArchState *env, target_ulong code,
......@@ -251,11 +252,11 @@ void target_disas(FILE *out, CPUArchState *env, target_ulong code,
s.info.mach = bfd_mach_sparc_v9b;
#endif
#elif defined(TARGET_PPC)
if (flags >> 16) {
if ((flags >> 16) & 1) {
s.info.endian = BFD_ENDIAN_LITTLE;
}
if (flags & 0xFFFF) {
/* If we have a precise definitions of the instructions set, use it */
/* If we have a precise definition of the instruction set, use it. */
s.info.mach = flags & 0xFFFF;
} else {
#ifdef TARGET_PPC64
......@@ -444,6 +445,8 @@ monitor_fprintf(FILE *stream, const char *fmt, ...)
return 0;
}
/* Disassembler for the monitor.
See target_disas for a description of flags. */
void monitor_disas(Monitor *mon, CPUArchState *env,
target_ulong pc, int nb_insn, int is_physical, int flags)
{
......@@ -484,11 +487,19 @@ void monitor_disas(Monitor *mon, CPUArchState *env,
s.info.mach = bfd_mach_sparc_v9b;
#endif
#elif defined(TARGET_PPC)
if (flags & 0xFFFF) {
/* If we have a precise definition of the instruction set, use it. */
s.info.mach = flags & 0xFFFF;
} else {
#ifdef TARGET_PPC64
s.info.mach = bfd_mach_ppc64;
s.info.mach = bfd_mach_ppc64;
#else
s.info.mach = bfd_mach_ppc;
s.info.mach = bfd_mach_ppc;
#endif
}
if ((flags >> 16) & 1) {
s.info.endian = BFD_ENDIAN_LITTLE;
}
print_insn = print_insn_ppc;
#elif defined(TARGET_M68K)
print_insn = print_insn_m68k;
......
此差异已折叠。
......@@ -193,6 +193,11 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
goto done;
}
if (--io->requests) {
/* More requests still in flight */
return;
}
if (!m->dma_active) {
MACIO_DPRINTF("waiting for data (%#x - %#x - %x)\n",
s->nsector, io->len, s->status);
......@@ -212,6 +217,13 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
s->nsector -= n;
}
if (io->finish_remain_read) {
/* Finish a stale read from the last iteration */
io->finish_remain_read = false;
cpu_physical_memory_write(io->finish_addr, io->remainder,
io->finish_len);
}
MACIO_DPRINTF("remainder: %d io->len: %d nsector: %d "
"sector_num: %" PRId64 "\n",
io->remainder_len, io->len, s->nsector, sector_num);
......@@ -229,7 +241,6 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
break;
case IDE_DMA_WRITE:
cpu_physical_memory_read(io->addr, p, remainder_len);
bdrv_write(s->bs, sector_num - 1, io->remainder, 1);
break;
case IDE_DMA_TRIM:
break;
......@@ -237,6 +248,15 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
io->addr += remainder_len;
io->len -= remainder_len;
io->remainder_len -= remainder_len;
if (s->dma_cmd == IDE_DMA_WRITE && !io->remainder_len) {
io->requests++;
qemu_iovec_reset(&io->iov);
qemu_iovec_add(&io->iov, io->remainder, 0x200);
m->aiocb = bdrv_aio_writev(s->bs, sector_num - 1, &io->iov, 1,
pmac_ide_transfer_cb, io);
}
}
if (s->nsector == 0 && !io->remainder_len) {
......@@ -267,20 +287,25 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
switch (s->dma_cmd) {
case IDE_DMA_READ:
bdrv_read(s->bs, sector_num + nsector, io->remainder, 1);
cpu_physical_memory_write(io->addr + io->len - unaligned,
io->remainder, unaligned);
io->requests++;
io->finish_addr = io->addr + io->len - unaligned;
io->finish_len = unaligned;
io->finish_remain_read = true;
qemu_iovec_reset(&io->iov);
qemu_iovec_add(&io->iov, io->remainder, 0x200);
m->aiocb = bdrv_aio_readv(s->bs, sector_num + nsector, &io->iov, 1,
pmac_ide_transfer_cb, io);
break;
case IDE_DMA_WRITE:
/* cache the contents in our io struct */
cpu_physical_memory_read(io->addr + io->len - unaligned,
io->remainder, unaligned);
io->remainder + io->remainder_len,
unaligned);
break;
case IDE_DMA_TRIM:
break;
}
io->len -= unaligned;
}
MACIO_DPRINTF("io->len = %#x\n", io->len);
......@@ -292,10 +317,12 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
io->remainder_len = (0x200 - unaligned) & 0x1ff;
MACIO_DPRINTF("set remainder to: %d\n", io->remainder_len);
/* We would read no data from the block layer, thus not get a callback.
Just fake completion manually. */
/* Only subsector reads happening */
if (!io->len) {
pmac_ide_transfer_cb(opaque, 0);
if (!io->requests) {
io->requests++;
pmac_ide_transfer_cb(opaque, ret);
}
return;
}
......@@ -319,6 +346,8 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
DMA_DIRECTION_TO_DEVICE);
break;
}
io->requests++;
return;
done:
......@@ -337,6 +366,27 @@ static void pmac_ide_transfer(DBDMA_io *io)
s->io_buffer_size = 0;
if (s->drive_kind == IDE_CD) {
/* Handle non-block ATAPI DMA transfers */
if (s->lba == -1) {
s->io_buffer_size = MIN(io->len, s->packet_transfer_size);
bdrv_acct_start(s->bs, &s->acct, s->io_buffer_size,
BDRV_ACCT_READ);
MACIO_DPRINTF("non-block ATAPI DMA transfer size: %d\n",
s->io_buffer_size);
/* Copy ATAPI buffer directly to RAM and finish */
cpu_physical_memory_write(io->addr, s->io_buffer,
s->io_buffer_size);
ide_atapi_cmd_ok(s);
m->dma_active = false;
MACIO_DPRINTF("end of non-block ATAPI DMA transfer\n");
bdrv_acct_done(s->bs, &s->acct);
io->dma_end(io);
return;
}
bdrv_acct_start(s->bs, &s->acct, io->len, BDRV_ACCT_READ);
pmac_ide_atapi_transfer_cb(io, 0);
return;
......@@ -353,6 +403,7 @@ static void pmac_ide_transfer(DBDMA_io *io)
break;
}
io->requests++;
pmac_ide_transfer_cb(io, 0);
}
......
......@@ -192,6 +192,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
int idx);
static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
uint32_t val, int idx);
static void openpic_reset(DeviceState *d);
typedef enum IRQType {
IRQ_TYPE_NORMAL = 0,
......@@ -529,55 +530,6 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level)
}
}
static void openpic_reset(DeviceState *d)
{
OpenPICState *opp = OPENPIC(d);
int i;
opp->gcr = GCR_RESET;
/* Initialise controller registers */
opp->frr = ((opp->nb_irqs - 1) << FRR_NIRQ_SHIFT) |
((opp->nb_cpus - 1) << FRR_NCPU_SHIFT) |
(opp->vid << FRR_VID_SHIFT);
opp->pir = 0;
opp->spve = -1 & opp->vector_mask;
opp->tfrr = opp->tfrr_reset;
/* Initialise IRQ sources */
for (i = 0; i < opp->max_irq; i++) {
opp->src[i].ivpr = opp->ivpr_reset;
opp->src[i].idr = opp->idr_reset;
switch (opp->src[i].type) {
case IRQ_TYPE_NORMAL:
opp->src[i].level = !!(opp->ivpr_reset & IVPR_SENSE_MASK);
break;
case IRQ_TYPE_FSLINT:
opp->src[i].ivpr |= IVPR_POLARITY_MASK;
break;
case IRQ_TYPE_FSLSPECIAL:
break;
}
}
/* Initialise IRQ destinations */
for (i = 0; i < MAX_CPU; i++) {
opp->dst[i].ctpr = 15;
memset(&opp->dst[i].raised, 0, sizeof(IRQQueue));
opp->dst[i].raised.next = -1;
memset(&opp->dst[i].servicing, 0, sizeof(IRQQueue));
opp->dst[i].servicing.next = -1;
}
/* Initialise timers */
for (i = 0; i < OPENPIC_MAX_TMR; i++) {
opp->timers[i].tccr = 0;
opp->timers[i].tbcr = TBCR_CI;
}
/* Go out of RESET state */
opp->gcr = 0;
}
static inline uint32_t read_IRQreg_idr(OpenPICState *opp, int n_IRQ)
{
return opp->src[n_IRQ].idr;
......@@ -1461,6 +1413,55 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id)
return 0;
}
static void openpic_reset(DeviceState *d)
{
OpenPICState *opp = OPENPIC(d);
int i;
opp->gcr = GCR_RESET;
/* Initialise controller registers */
opp->frr = ((opp->nb_irqs - 1) << FRR_NIRQ_SHIFT) |
((opp->nb_cpus - 1) << FRR_NCPU_SHIFT) |
(opp->vid << FRR_VID_SHIFT);
opp->pir = 0;
opp->spve = -1 & opp->vector_mask;
opp->tfrr = opp->tfrr_reset;
/* Initialise IRQ sources */
for (i = 0; i < opp->max_irq; i++) {
opp->src[i].ivpr = opp->ivpr_reset;
switch (opp->src[i].type) {
case IRQ_TYPE_NORMAL:
opp->src[i].level = !!(opp->ivpr_reset & IVPR_SENSE_MASK);
break;
case IRQ_TYPE_FSLINT:
opp->src[i].ivpr |= IVPR_POLARITY_MASK;
break;
case IRQ_TYPE_FSLSPECIAL:
break;
}
write_IRQreg_idr(opp, i, opp->idr_reset);
}
/* Initialise IRQ destinations */
for (i = 0; i < MAX_CPU; i++) {
opp->dst[i].ctpr = 15;
memset(&opp->dst[i].raised, 0, sizeof(IRQQueue));
opp->dst[i].raised.next = -1;
memset(&opp->dst[i].servicing, 0, sizeof(IRQQueue));
opp->dst[i].servicing.next = -1;
}
/* Initialise timers */
for (i = 0; i < OPENPIC_MAX_TMR; i++) {
opp->timers[i].tccr = 0;
opp->timers[i].tbcr = TBCR_CI;
}
/* Go out of RESET state */
opp->gcr = 0;
}
typedef struct MemReg {
const char *name;
MemoryRegionOps const *ops;
......
......@@ -31,6 +31,8 @@
#include "sysemu/kvm.h"
#include "qemu/log.h"
#define GCR_RESET 0x80000000
#define KVM_OPENPIC(obj) \
OBJECT_CHECK(KVMOpenPICState, (obj), TYPE_KVM_OPENPIC)
......@@ -50,11 +52,6 @@ static void kvm_openpic_set_irq(void *opaque, int n_IRQ, int level)
kvm_set_irq(kvm_state, n_IRQ, level);
}
static void kvm_openpic_reset(DeviceState *d)
{
qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
}
static void kvm_openpic_write(void *opaque, hwaddr addr, uint64_t val,
unsigned size)
{
......@@ -74,6 +71,14 @@ static void kvm_openpic_write(void *opaque, hwaddr addr, uint64_t val,
}
}
static void kvm_openpic_reset(DeviceState *d)
{
KVMOpenPICState *opp = KVM_OPENPIC(d);
/* Trigger the GCR.RESET bit to reset the PIC */
kvm_openpic_write(opp, 0x1020, GCR_RESET, sizeof(uint32_t));
}
static uint64_t kvm_openpic_read(void *opaque, hwaddr addr, unsigned size)
{
KVMOpenPICState *opp = opaque;
......
......@@ -748,9 +748,15 @@ static void dbdma_reset(void *opaque)
void* DBDMA_init (MemoryRegion **dbdma_mem)
{
DBDMAState *s;
int i;
s = g_malloc0(sizeof(DBDMAState));
for (i = 0; i < DBDMA_CHANNELS; i++) {
DBDMA_io *io = &s->channels[i].io;
qemu_iovec_init(&io->iov, 1);
}
memory_region_init_io(&s->mem, NULL, &dbdma_ops, s, "dbdma", 0x1000);
*dbdma_mem = &s->mem;
vmstate_register(NULL, -1, &vmstate_dbdma, s);
......
......@@ -259,7 +259,7 @@ static uint64_t timer_read(void *opaque, hwaddr addr, unsigned size)
static const MemoryRegionOps timer_ops = {
.read = timer_read,
.write = timer_write,
.endianness = DEVICE_NATIVE_ENDIAN,
.endianness = DEVICE_LITTLE_ENDIAN,
};
static int macio_newworld_initfn(PCIDevice *d)
......
......@@ -159,7 +159,7 @@ static void ievent_set(eTSEC *etsec,
if ((flags & IEVENT_RXB && etsec->regs[IMASK].value & IMASK_RXBEN)
|| (flags & IEVENT_RXF && etsec->regs[IMASK].value & IMASK_RXFEN)) {
qemu_irq_pulse(etsec->rx_irq);
qemu_irq_raise(etsec->rx_irq);
RING_DEBUG("%s Raise Rx IRQ\n", __func__);
}
}
......
......@@ -42,7 +42,7 @@ typedef struct sPAPRNVRAM {
#define MIN_NVRAM_SIZE 8192
#define DEFAULT_NVRAM_SIZE 65536
#define MAX_NVRAM_SIZE (UINT16_MAX * 16)
#define MAX_NVRAM_SIZE 1048576
static void rtas_nvram_fetch(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint32_t token, uint32_t nargs,
......
......@@ -87,8 +87,10 @@ struct PPCE500PCIState {
struct pci_outbound pob[PPCE500_PCI_NR_POBS];
struct pci_inbound pib[PPCE500_PCI_NR_PIBS];
uint32_t gasket_time;
qemu_irq irq[4];
qemu_irq irq[PCI_NUM_PINS];
uint32_t irq_num[PCI_NUM_PINS];
uint32_t first_slot;
uint32_t first_pin_irq;
/* mmio maps */
MemoryRegion container;
MemoryRegion iomem;
......@@ -252,26 +254,39 @@ static const MemoryRegionOps e500_pci_reg_ops = {
.endianness = DEVICE_BIG_ENDIAN,
};
static int mpc85xx_pci_map_irq(PCIDevice *pci_dev, int irq_num)
static int mpc85xx_pci_map_irq(PCIDevice *pci_dev, int pin)
{
int devno = pci_dev->devfn >> 3;
int ret;
ret = ppce500_pci_map_irq_slot(devno, irq_num);
ret = ppce500_pci_map_irq_slot(devno, pin);
pci_debug("%s: devfn %x irq %d -> %d devno:%x\n", __func__,
pci_dev->devfn, irq_num, ret, devno);
pci_dev->devfn, pin, ret, devno);
return ret;
}
static void mpc85xx_pci_set_irq(void *opaque, int irq_num, int level)
static void mpc85xx_pci_set_irq(void *opaque, int pin, int level)
{
qemu_irq *pic = opaque;
PPCE500PCIState *s = opaque;
qemu_irq *pic = s->irq;
pci_debug("%s: PCI irq %d, level:%d\n", __func__, irq_num, level);
pci_debug("%s: PCI irq %d, level:%d\n", __func__, pin , level);
qemu_set_irq(pic[irq_num], level);
qemu_set_irq(pic[pin], level);
}
static PCIINTxRoute e500_route_intx_pin_to_irq(void *opaque, int pin)
{
PCIINTxRoute route;
PPCE500PCIState *s = opaque;
route.mode = PCI_INTX_ENABLED;
route.irq = s->irq_num[pin];
pci_debug("%s: PCI irq-pin = %d, irq_num= %d\n", __func__, pin, route.irq);
return route;
}
static const VMStateDescription vmstate_pci_outbound = {
......@@ -308,7 +323,7 @@ static const VMStateDescription vmstate_ppce500_pci = {
VMSTATE_STRUCT_ARRAY(pob, PPCE500PCIState, PPCE500_PCI_NR_POBS, 1,
vmstate_pci_outbound, struct pci_outbound),
VMSTATE_STRUCT_ARRAY(pib, PPCE500PCIState, PPCE500_PCI_NR_PIBS, 1,
vmstate_pci_outbound, struct pci_inbound),
vmstate_pci_inbound, struct pci_inbound),
VMSTATE_UINT32(gasket_time, PPCE500PCIState),
VMSTATE_END_OF_LIST()
}
......@@ -349,10 +364,14 @@ static int e500_pcihost_initfn(SysBusDevice *dev)
sysbus_init_irq(dev, &s->irq[i]);
}
for (i = 0; i < PCI_NUM_PINS; i++) {
s->irq_num[i] = s->first_pin_irq + i;
}
memory_region_init(&s->pio, OBJECT(s), "pci-pio", PCIE500_PCI_IOLEN);
b = pci_register_bus(DEVICE(dev), NULL, mpc85xx_pci_set_irq,
mpc85xx_pci_map_irq, s->irq, address_space_mem,
mpc85xx_pci_map_irq, s, address_space_mem,
&s->pio, PCI_DEVFN(s->first_slot, 0), 4, TYPE_PCI_BUS);
h->bus = b;
......@@ -370,6 +389,7 @@ static int e500_pcihost_initfn(SysBusDevice *dev)
memory_region_add_subregion(&s->container, PCIE500_REG_BASE, &s->iomem);
sysbus_init_mmio(dev, &s->container);
sysbus_init_mmio(dev, &s->pio);
pci_bus_set_route_irq_fn(b, e500_route_intx_pin_to_irq);
return 0;
}
......@@ -400,6 +420,7 @@ static const TypeInfo e500_host_bridge_info = {
static Property pcihost_properties[] = {
DEFINE_PROP_UINT32("first_slot", PPCE500PCIState, first_slot, 0x11),
DEFINE_PROP_UINT32("first_pin_irq", PPCE500PCIState, first_pin_irq, 0x1),
DEFINE_PROP_END_OF_LIST(),
};
......
......@@ -39,7 +39,6 @@
#define EPAPR_MAGIC (0x45504150)
#define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb"
#define UIMAGE_LOAD_BASE 0
#define DTC_LOAD_PAD 0x1800000
#define DTC_PAD_MASK 0xFFFFF
#define DTB_MAX_SIZE (8 * 1024 * 1024)
......@@ -128,6 +127,8 @@ static int ppce500_load_device_tree(MachineState *machine,
hwaddr addr,
hwaddr initrd_base,
hwaddr initrd_size,
hwaddr kernel_base,
hwaddr kernel_size,
bool dry_run)
{
CPUPPCState *env = first_cpu->env_ptr;
......@@ -204,6 +205,13 @@ static int ppce500_load_device_tree(MachineState *machine,
if (ret < 0) {
fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
}
}
if (kernel_base != -1ULL) {
qemu_fdt_setprop_cells(fdt, "/chosen", "qemu,boot-kernel",
kernel_base >> 32, kernel_base,
kernel_size >> 32, kernel_size);
}
ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
......@@ -392,20 +400,25 @@ typedef struct DeviceTreeParams {
hwaddr addr;
hwaddr initrd_base;
hwaddr initrd_size;
hwaddr kernel_base;
hwaddr kernel_size;
} DeviceTreeParams;
static void ppce500_reset_device_tree(void *opaque)
{
DeviceTreeParams *p = opaque;
ppce500_load_device_tree(p->machine, &p->params, p->addr, p->initrd_base,
p->initrd_size, false);
p->initrd_size, p->kernel_base, p->kernel_size,
false);
}
static int ppce500_prep_device_tree(MachineState *machine,
PPCE500Params *params,
hwaddr addr,
hwaddr initrd_base,
hwaddr initrd_size)
hwaddr initrd_size,
hwaddr kernel_base,
hwaddr kernel_size)
{
DeviceTreeParams *p = g_new(DeviceTreeParams, 1);
p->machine = machine;
......@@ -413,12 +426,15 @@ static int ppce500_prep_device_tree(MachineState *machine,
p->addr = addr;
p->initrd_base = initrd_base;
p->initrd_size = initrd_size;
p->kernel_base = kernel_base;
p->kernel_size = kernel_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(machine, params, addr, initrd_base,
initrd_size, true);
initrd_size, kernel_base, kernel_size,
true);
}
/* Create -kernel TLB entries for BookE. */
......@@ -603,17 +619,22 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
MemoryRegion *ram = g_new(MemoryRegion, 1);
PCIBus *pci_bus;
CPUPPCState *env = NULL;
uint64_t elf_entry;
uint64_t elf_lowaddr;
hwaddr entry=0;
hwaddr loadaddr=UIMAGE_LOAD_BASE;
target_long kernel_size=0;
target_ulong dt_base = 0;
target_ulong initrd_base = 0;
target_long initrd_size = 0;
target_ulong cur_base = 0;
uint64_t loadaddr;
hwaddr kernel_base = -1LL;
int kernel_size = 0;
hwaddr dt_base = 0;
hwaddr initrd_base = 0;
int initrd_size = 0;
hwaddr cur_base = 0;
char *filename;
hwaddr bios_entry = 0;
target_long bios_size;
struct boot_info *boot_info;
int dt_size;
int i;
unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
/* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and
* 4 respectively */
unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4};
qemu_irq **irqs, *mpic;
DeviceState *dev;
CPUPPCState *firstenv = NULL;
......@@ -713,12 +734,13 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
/* PCI */
dev = qdev_create(NULL, "e500-pcihost");
qdev_prop_set_uint32(dev, "first_slot", params->pci_first_slot);
qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]);
qdev_init_nofail(dev);
s = SYS_BUS_DEVICE(dev);
sysbus_connect_irq(s, 0, mpic[pci_irq_nrs[0]]);
sysbus_connect_irq(s, 1, mpic[pci_irq_nrs[1]]);
sysbus_connect_irq(s, 2, mpic[pci_irq_nrs[2]]);
sysbus_connect_irq(s, 3, mpic[pci_irq_nrs[3]]);
for (i = 0; i < PCI_NUM_PINS; i++) {
sysbus_connect_irq(s, i, mpic[pci_irq_nrs[i]]);
}
memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET,
sysbus_mmio_get_region(s, 0));
......@@ -738,29 +760,24 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
/* Register spinning region */
sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
if (cur_base < (32 * 1024 * 1024)) {
/* u-boot occupies memory up to 32MB, so load blobs above */
cur_base = (32 * 1024 * 1024);
}
/* Load kernel. */
if (machine->kernel_filename) {
kernel_size = load_uimage(machine->kernel_filename, &entry,
&loadaddr, NULL);
if (kernel_size < 0) {
kernel_size = load_elf(machine->kernel_filename, NULL, NULL,
&elf_entry, &elf_lowaddr, NULL, 1,
ELF_MACHINE, 0);
entry = elf_entry;
loadaddr = elf_lowaddr;
}
/* XXX try again as binary */
kernel_base = cur_base;
kernel_size = load_image_targphys(machine->kernel_filename,
cur_base,
ram_size - cur_base);
if (kernel_size < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
machine->kernel_filename);
exit(1);
}
cur_base = loadaddr + kernel_size;
/* Reserve space for dtb */
dt_base = (cur_base + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
cur_base += DTB_MAX_SIZE;
cur_base += kernel_size;
}
/* Load initrd. */
......@@ -778,24 +795,60 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
cur_base = initrd_base + initrd_size;
}
/* If we're loading a kernel directly, we must load the device tree too. */
if (machine->kernel_filename) {
struct boot_info *boot_info;
int dt_size;
dt_size = ppce500_prep_device_tree(machine, params, dt_base,
initrd_base, initrd_size);
if (dt_size < 0) {
fprintf(stderr, "couldn't load device tree\n");
/*
* Smart firmware defaults ahead!
*
* We follow the following table to select which payload we execute.
*
* -kernel | -bios | payload
* ---------+-------+---------
* N | Y | u-boot
* N | N | u-boot
* Y | Y | u-boot
* Y | N | kernel
*
* This ensures backwards compatibility with how we used to expose
* -kernel to users but allows them to run through u-boot as well.
*/
if (bios_name == NULL) {
if (machine->kernel_filename) {
bios_name = machine->kernel_filename;
} else {
bios_name = "u-boot.e500";
}
}
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
bios_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
1, ELF_MACHINE, 0);
if (bios_size < 0) {
/*
* Hrm. No ELF image? Try a uImage, maybe someone is giving us an
* ePAPR compliant kernel
*/
kernel_size = load_uimage(filename, &bios_entry, &loadaddr, NULL);
if (kernel_size < 0) {
fprintf(stderr, "qemu: could not load firmware '%s'\n", filename);
exit(1);
}
assert(dt_size < DTB_MAX_SIZE);
}
boot_info = env->load_info;
boot_info->entry = entry;
boot_info->dt_base = dt_base;
boot_info->dt_size = dt_size;
/* Reserve space for dtb */
dt_base = (loadaddr + bios_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
dt_size = ppce500_prep_device_tree(machine, params, dt_base,
initrd_base, initrd_size,
kernel_base, kernel_size);
if (dt_size < 0) {
fprintf(stderr, "couldn't load device tree\n");
exit(1);
}
assert(dt_size < DTB_MAX_SIZE);
boot_info = env->load_info;
boot_info->entry = bios_entry;
boot_info->dt_base = dt_base;
boot_info->dt_size = dt_size;
if (kvm_enabled()) {
kvmppc_init();
......
......@@ -72,6 +72,8 @@
#define MAX_IDE_BUS 2
#define CFG_ADDR 0xf0000510
#define TBFREQ (100UL * 1000UL * 1000UL)
#define CLOCKFREQ (266UL * 1000UL * 1000UL)
#define BUSFREQ (100UL * 1000UL * 1000UL)
/* debug UniNorth */
//#define DEBUG_UNIN
......@@ -467,7 +469,8 @@ static void ppc_core99_init(MachineState *machine)
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, TBFREQ);
}
/* Mac OS X requires a "known good" clock-frequency value; pass it one. */
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_CLOCKFREQ, 266000000);
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_CLOCKFREQ, CLOCKFREQ);
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_BUSFREQ, BUSFREQ);
qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
}
......
......@@ -46,6 +46,8 @@
#define MAX_IDE_BUS 2
#define CFG_ADDR 0xf0000510
#define TBFREQ 16600000UL
#define CLOCKFREQ 266000000UL
#define BUSFREQ 66000000UL
static int fw_cfg_boot_set(void *opaque, const char *boot_device)
{
......@@ -337,7 +339,8 @@ static void ppc_heathrow_init(MachineState *machine)
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, TBFREQ);
}
/* Mac OS X requires a "known good" clock-frequency value; pass it one. */
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_CLOCKFREQ, 266000000);
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_CLOCKFREQ, CLOCKFREQ);
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_BUSFREQ, BUSFREQ);
qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
}
......
......@@ -29,9 +29,11 @@
#include "sysemu/cpus.h"
#include "hw/timer/m48t59.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
#include "hw/loader.h"
#include "sysemu/kvm.h"
#include "kvm_ppc.h"
#include "trace.h"
//#define PPC_DEBUG_IRQ
//#define PPC_DEBUG_TB
......@@ -49,6 +51,8 @@
# define LOG_TB(...) do { } while (0)
#endif
#define NSEC_PER_SEC 1000000000LL
static void cpu_ppc_tb_stop (CPUPPCState *env);
static void cpu_ppc_tb_start (CPUPPCState *env);
......@@ -829,6 +833,81 @@ static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
cpu_ppc_store_purr(cpu, 0x0000000000000000ULL);
}
static void timebase_pre_save(void *opaque)
{
PPCTimebase *tb = opaque;
uint64_t ticks = cpu_get_real_ticks();
PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
if (!first_ppc_cpu->env.tb_env) {
error_report("No timebase object");
return;
}
tb->time_of_the_day_ns = get_clock_realtime();
/*
* tb_offset is only expected to be changed by migration so
* there is no need to update it from KVM here
*/
tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset;
}
static int timebase_post_load(void *opaque, int version_id)
{
PPCTimebase *tb_remote = opaque;
CPUState *cpu;
PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
int64_t tb_off_adj, tb_off, ns_diff;
int64_t migration_duration_ns, migration_duration_tb, guest_tb, host_ns;
unsigned long freq;
if (!first_ppc_cpu->env.tb_env) {
error_report("No timebase object");
return -1;
}
freq = first_ppc_cpu->env.tb_env->tb_freq;
/*
* Calculate timebase on the destination side of migration.
* The destination timebase must be not less than the source timebase.
* We try to adjust timebase by downtime if host clocks are not
* too much out of sync (1 second for now).
*/
host_ns = get_clock_realtime();
ns_diff = MAX(0, host_ns - tb_remote->time_of_the_day_ns);
migration_duration_ns = MIN(NSEC_PER_SEC, ns_diff);
migration_duration_tb = muldiv64(migration_duration_ns, freq, NSEC_PER_SEC);
guest_tb = tb_remote->guest_timebase + MIN(0, migration_duration_tb);
tb_off_adj = guest_tb - cpu_get_real_ticks();
tb_off = first_ppc_cpu->env.tb_env->tb_offset;
trace_ppc_tb_adjust(tb_off, tb_off_adj, tb_off_adj - tb_off,
(tb_off_adj - tb_off) / freq);
/* Set new offset to all CPUs */
CPU_FOREACH(cpu) {
PowerPCCPU *pcpu = POWERPC_CPU(cpu);
pcpu->env.tb_env->tb_offset = tb_off_adj;
}
return 0;
}
const VMStateDescription vmstate_ppc_timebase = {
.name = "timebase",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.pre_save = timebase_pre_save,
.post_load = timebase_post_load,
.fields = (VMStateField []) {
VMSTATE_UINT64(guest_timebase, PPCTimebase),
VMSTATE_INT64(time_of_the_day_ns, PPCTimebase),
VMSTATE_END_OF_LIST()
},
};
/* Set up (once) timebase frequency (in Hz) */
clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq)
{
......
......@@ -34,6 +34,7 @@
#include "sysemu/kvm.h"
#include "kvm_ppc.h"
#include "mmu-hash64.h"
#include "qom/cpu.h"
#include "hw/boards.h"
#include "hw/ppc/ppc.h"
......@@ -53,6 +54,7 @@
#include "hw/usb.h"
#include "qemu/config-file.h"
#include "qemu/error-report.h"
#include "trace.h"
#include <libfdt.h>
......@@ -78,13 +80,28 @@
#define TIMEBASE_FREQ 512000000ULL
#define MAX_CPUS 256
#define XICS_IRQS 1024
#define PHANDLE_XICP 0x00001111
#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift))
typedef struct SPAPRMachine SPAPRMachine;
#define TYPE_SPAPR_MACHINE "spapr-machine"
#define SPAPR_MACHINE(obj) \
OBJECT_CHECK(SPAPRMachine, (obj), TYPE_SPAPR_MACHINE)
/**
* SPAPRMachine:
*/
struct SPAPRMachine {
/*< private >*/
MachineState parent_obj;
/*< public >*/
char *kvm_type;
};
sPAPREnvironment *spapr;
......@@ -202,34 +219,79 @@ static XICSState *xics_system_init(int nr_servers, int nr_irqs)
return icp;
}
static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
int smt_threads)
{
int i, ret = 0;
uint32_t servers_prop[smt_threads];
uint32_t gservers_prop[smt_threads * 2];
int index = ppc_get_vcpu_dt_id(cpu);
if (cpu->cpu_version) {
ret = fdt_setprop(fdt, offset, "cpu-version",
&cpu->cpu_version, sizeof(cpu->cpu_version));
if (ret < 0) {
return ret;
}
}
/* Build interrupt servers and gservers properties */
for (i = 0; i < smt_threads; i++) {
servers_prop[i] = cpu_to_be32(index + i);
/* Hack, direct the group queues back to cpu 0 */
gservers_prop[i*2] = cpu_to_be32(index + i);
gservers_prop[i*2 + 1] = 0;
}
ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
servers_prop, sizeof(servers_prop));
if (ret < 0) {
return ret;
}
ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-gserver#s",
gservers_prop, sizeof(gservers_prop));
return ret;
}
static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr)
{
int ret = 0, offset;
CPUState *cpu;
int ret = 0, offset, cpus_offset;
CPUState *cs;
char cpu_model[32];
int smt = kvmppc_smt_threads();
uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
CPU_FOREACH(cpu) {
DeviceClass *dc = DEVICE_GET_CLASS(cpu);
int index = ppc_get_vcpu_dt_id(POWERPC_CPU(cpu));
CPU_FOREACH(cs) {
PowerPCCPU *cpu = POWERPC_CPU(cs);
DeviceClass *dc = DEVICE_GET_CLASS(cs);
int index = ppc_get_vcpu_dt_id(cpu);
uint32_t associativity[] = {cpu_to_be32(0x5),
cpu_to_be32(0x0),
cpu_to_be32(0x0),
cpu_to_be32(0x0),
cpu_to_be32(cpu->numa_node),
cpu_to_be32(cs->numa_node),
cpu_to_be32(index)};
if ((index % smt) != 0) {
continue;
}
snprintf(cpu_model, 32, "/cpus/%s@%x", dc->fw_name,
index);
snprintf(cpu_model, 32, "%s@%x", dc->fw_name, index);
offset = fdt_path_offset(fdt, cpu_model);
cpus_offset = fdt_path_offset(fdt, "/cpus");
if (cpus_offset < 0) {
cpus_offset = fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"),
"cpus");
if (cpus_offset < 0) {
return cpus_offset;
}
}
offset = fdt_subnode_offset(fdt, cpus_offset, cpu_model);
if (offset < 0) {
return offset;
offset = fdt_add_subnode(fdt, cpus_offset, cpu_model);
if (offset < 0) {
return offset;
}
}
if (nb_numa_nodes > 1) {
......@@ -245,6 +307,12 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr)
if (ret < 0) {
return ret;
}
ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu,
ppc_get_compat_smt_threads(cpu));
if (ret < 0) {
return ret;
}
}
return ret;
}
......@@ -293,6 +361,10 @@ static size_t create_page_sizes_prop(CPUPPCState *env, uint32_t *prop,
} \
} while (0)
static void add_str(GString *s, const gchar *s1)
{
g_string_append_len(s, s1, strlen(s1) + 1);
}
static void *spapr_create_fdt_skel(hwaddr initrd_base,
hwaddr initrd_size,
......@@ -306,13 +378,26 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
CPUState *cs;
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-set-mode";
char qemu_hypertas_prop[] = "hcall-memop1";
GString *hypertas = g_string_sized_new(256);
GString *qemu_hypertas = g_string_sized_new(256);
uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)};
uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
int i, smt = kvmppc_smt_threads();
int smt = kvmppc_smt_threads();
unsigned char vec5[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x80};
QemuOpts *opts = qemu_opts_find(qemu_find_opts("smp-opts"), NULL);
unsigned sockets = opts ? qemu_opt_get_number(opts, "sockets", 0) : 0;
uint32_t cpus_per_socket = sockets ? (smp_cpus / sockets) : 1;
add_str(hypertas, "hcall-pft");
add_str(hypertas, "hcall-term");
add_str(hypertas, "hcall-dabr");
add_str(hypertas, "hcall-interrupt");
add_str(hypertas, "hcall-tce");
add_str(hypertas, "hcall-vio");
add_str(hypertas, "hcall-splpar");
add_str(hypertas, "hcall-bulk");
add_str(hypertas, "hcall-set-mode");
add_str(qemu_hypertas, "hcall-memop1");
fdt = g_malloc0(FDT_MAX_SIZE);
_FDT((fdt_create(fdt, FDT_MAX_SIZE)));
......@@ -375,8 +460,6 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
DeviceClass *dc = DEVICE_GET_CLASS(cs);
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
int index = ppc_get_vcpu_dt_id(cpu);
uint32_t servers_prop[smp_threads];
uint32_t gservers_prop[smp_threads * 2];
char *nodename;
uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
0xffffffff, 0xffffffff};
......@@ -425,18 +508,6 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
_FDT((fdt_property_string(fdt, "status", "okay")));
_FDT((fdt_property(fdt, "64-bit", NULL, 0)));
/* Build interrupt servers and gservers properties */
for (i = 0; i < smp_threads; i++) {
servers_prop[i] = cpu_to_be32(index + i);
/* Hack, direct the group queues back to cpu 0 */
gservers_prop[i*2] = cpu_to_be32(index + i);
gservers_prop[i*2 + 1] = 0;
}
_FDT((fdt_property(fdt, "ibm,ppc-interrupt-server#s",
servers_prop, sizeof(servers_prop))));
_FDT((fdt_property(fdt, "ibm,ppc-interrupt-gserver#s",
gservers_prop, sizeof(gservers_prop))));
if (env->spr_cb[SPR_PURR].oea_read) {
_FDT((fdt_property(fdt, "ibm,purr", NULL, 0)));
}
......@@ -470,6 +541,9 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
page_sizes_prop, page_sizes_prop_size)));
}
_FDT((fdt_property_cell(fdt, "ibm,chip-id",
cs->cpu_index / cpus_per_socket)));
_FDT((fdt_end_node(fdt)));
}
......@@ -478,10 +552,15 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
/* RTAS */
_FDT((fdt_begin_node(fdt, "rtas")));
_FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop,
sizeof(hypertas_prop))));
_FDT((fdt_property(fdt, "qemu,hypertas-functions", qemu_hypertas_prop,
sizeof(qemu_hypertas_prop))));
if (!kvm_enabled() || kvmppc_spapr_use_multitce()) {
add_str(hypertas, "hcall-multi-tce");
}
_FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas->str,
hypertas->len)));
g_string_free(hypertas, TRUE);
_FDT((fdt_property(fdt, "qemu,hypertas-functions", qemu_hypertas->str,
qemu_hypertas->len)));
g_string_free(qemu_hypertas, TRUE);
_FDT((fdt_property(fdt, "ibm,associativity-reference-points",
refpoints, sizeof(refpoints))));
......@@ -521,12 +600,68 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
/* event-sources */
spapr_events_fdt_skel(fdt, epow_irq);
/* /hypervisor node */
if (kvm_enabled()) {
uint8_t hypercall[16];
/* indicate KVM hypercall interface */
_FDT((fdt_begin_node(fdt, "hypervisor")));
_FDT((fdt_property_string(fdt, "compatible", "linux,kvm")));
if (kvmppc_has_cap_fixup_hcalls()) {
/*
* Older KVM versions with older guest kernels were broken with the
* magic page, don't allow the guest to map it.
*/
kvmppc_get_hypercall(first_cpu->env_ptr, hypercall,
sizeof(hypercall));
_FDT((fdt_property(fdt, "hcall-instructions", hypercall,
sizeof(hypercall))));
}
_FDT((fdt_end_node(fdt)));
}
_FDT((fdt_end_node(fdt))); /* close root node */
_FDT((fdt_finish(fdt)));
return fdt;
}
int spapr_h_cas_compose_response(target_ulong addr, target_ulong size)
{
void *fdt, *fdt_skel;
sPAPRDeviceTreeUpdateHeader hdr = { .version_id = 1 };
size -= sizeof(hdr);
/* Create sceleton */
fdt_skel = g_malloc0(size);
_FDT((fdt_create(fdt_skel, size)));
_FDT((fdt_begin_node(fdt_skel, "")));
_FDT((fdt_end_node(fdt_skel)));
_FDT((fdt_finish(fdt_skel)));
fdt = g_malloc0(size);
_FDT((fdt_open_into(fdt_skel, fdt, size)));
g_free(fdt_skel);
/* Fix skeleton up */
_FDT((spapr_fixup_cpu_dt(fdt, spapr)));
/* Pack resulting tree */
_FDT((fdt_pack(fdt)));
if (fdt_totalsize(fdt) + sizeof(hdr) > size) {
trace_spapr_cas_failed(size);
return -1;
}
cpu_physical_memory_write(addr, &hdr, sizeof(hdr));
cpu_physical_memory_write(addr + sizeof(hdr), fdt, fdt_totalsize(fdt));
trace_spapr_cas_continue(fdt_totalsize(fdt) + sizeof(hdr));
g_free(fdt);
return 0;
}
static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt)
{
uint32_t associativity[] = {cpu_to_be32(0x4), cpu_to_be32(0x0),
......@@ -817,14 +952,14 @@ static int spapr_vga_init(PCIBus *pci_bus)
static const VMStateDescription vmstate_spapr = {
.name = "spapr",
.version_id = 1,
.version_id = 2,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(next_irq, sPAPREnvironment),
/* RTC offset */
VMSTATE_UINT64(rtc_offset, sPAPREnvironment),
VMSTATE_PPC_TIMEBASE_V(tb, sPAPREnvironment, 2),
VMSTATE_END_OF_LIST()
},
};
......@@ -1251,6 +1386,12 @@ static void ppc_spapr_init(MachineState *machine)
kvmppc_set_papr(cpu);
}
if (cpu->max_compat) {
if (ppc_set_compat(cpu, cpu->max_compat) < 0) {
exit(1);
}
}
xics_cpu_setup(spapr->icp, cpu);
qemu_register_reset(spapr_cpu_reset, cpu);
......@@ -1475,6 +1616,27 @@ static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
return NULL;
}
static char *spapr_get_kvm_type(Object *obj, Error **errp)
{
SPAPRMachine *sm = SPAPR_MACHINE(obj);
return g_strdup(sm->kvm_type);
}
static void spapr_set_kvm_type(Object *obj, const char *value, Error **errp)
{
SPAPRMachine *sm = SPAPR_MACHINE(obj);
g_free(sm->kvm_type);
sm->kvm_type = g_strdup(value);
}
static void spapr_machine_initfn(Object *obj)
{
object_property_add_str(obj, "kvm-type",
spapr_get_kvm_type, spapr_set_kvm_type, NULL);
}
static void spapr_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
......@@ -1497,6 +1659,8 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
static const TypeInfo spapr_machine_info = {
.name = TYPE_SPAPR_MACHINE,
.parent = TYPE_MACHINE,
.instance_size = sizeof(SPAPRMachine),
.instance_init = spapr_machine_initfn,
.class_init = spapr_machine_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_FW_PATH_PROVIDER },
......
......@@ -3,6 +3,9 @@
#include "helper_regs.h"
#include "hw/ppc/spapr.h"
#include "mmu-hash64.h"
#include "cpu-models.h"
#include "trace.h"
#include "kvm_ppc.h"
struct SPRSyncState {
CPUState *cs;
......@@ -709,47 +712,218 @@ static target_ulong h_logical_dcbf(PowerPCCPU *cpu, sPAPREnvironment *spapr,
return H_SUCCESS;
}
static target_ulong h_set_mode_resouce_le(PowerPCCPU *cpu,
target_ulong mflags,
target_ulong value1,
target_ulong value2)
{
CPUState *cs;
if (value1) {
return H_P3;
}
if (value2) {
return H_P4;
}
switch (mflags) {
case H_SET_MODE_ENDIAN_BIG:
CPU_FOREACH(cs) {
set_spr(cs, SPR_LPCR, 0, LPCR_ILE);
}
return H_SUCCESS;
case H_SET_MODE_ENDIAN_LITTLE:
CPU_FOREACH(cs) {
set_spr(cs, SPR_LPCR, LPCR_ILE, LPCR_ILE);
}
return H_SUCCESS;
}
return H_UNSUPPORTED_FLAG;
}
static target_ulong h_set_mode_resouce_addr_trans_mode(PowerPCCPU *cpu,
target_ulong mflags,
target_ulong value1,
target_ulong value2)
{
CPUState *cs;
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
target_ulong prefix;
if (!(pcc->insns_flags2 & PPC2_ISA207S)) {
return H_P2;
}
if (value1) {
return H_P3;
}
if (value2) {
return H_P4;
}
switch (mflags) {
case H_SET_MODE_ADDR_TRANS_NONE:
prefix = 0;
break;
case H_SET_MODE_ADDR_TRANS_0001_8000:
prefix = 0x18000;
break;
case H_SET_MODE_ADDR_TRANS_C000_0000_0000_4000:
prefix = 0xC000000000004000;
break;
default:
return H_UNSUPPORTED_FLAG;
}
CPU_FOREACH(cs) {
CPUPPCState *env = &POWERPC_CPU(cpu)->env;
set_spr(cs, SPR_LPCR, mflags << LPCR_AIL_SHIFT, LPCR_AIL);
env->excp_prefix = prefix;
}
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_RESOURCE_LE) {
if (value1) {
ret = H_P3;
goto out;
}
if (value2) {
ret = H_P4;
goto out;
}
switch (mflags) {
case H_SET_MODE_ENDIAN_BIG:
CPU_FOREACH(cs) {
set_spr(cs, SPR_LPCR, 0, LPCR_ILE);
}
ret = H_SUCCESS;
break;
switch (resource) {
case H_SET_MODE_RESOURCE_LE:
ret = h_set_mode_resouce_le(cpu, args[0], args[2], args[3]);
break;
case H_SET_MODE_RESOURCE_ADDR_TRANS_MODE:
ret = h_set_mode_resouce_addr_trans_mode(cpu, args[0],
args[2], args[3]);
break;
}
return ret;
}
typedef struct {
PowerPCCPU *cpu;
uint32_t cpu_version;
int ret;
} SetCompatState;
case H_SET_MODE_ENDIAN_LITTLE:
CPU_FOREACH(cs) {
set_spr(cs, SPR_LPCR, LPCR_ILE, LPCR_ILE);
static void do_set_compat(void *arg)
{
SetCompatState *s = arg;
cpu_synchronize_state(CPU(s->cpu));
s->ret = ppc_set_compat(s->cpu, s->cpu_version);
}
#define get_compat_level(cpuver) ( \
((cpuver) == CPU_POWERPC_LOGICAL_2_05) ? 2050 : \
((cpuver) == CPU_POWERPC_LOGICAL_2_06) ? 2060 : \
((cpuver) == CPU_POWERPC_LOGICAL_2_06_PLUS) ? 2061 : \
((cpuver) == CPU_POWERPC_LOGICAL_2_07) ? 2070 : 0)
static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
sPAPREnvironment *spapr,
target_ulong opcode,
target_ulong *args)
{
target_ulong list = args[0];
PowerPCCPUClass *pcc_ = POWERPC_CPU_GET_CLASS(cpu_);
CPUState *cs;
bool cpu_match = false;
unsigned old_cpu_version = cpu_->cpu_version;
unsigned compat_lvl = 0, cpu_version = 0;
unsigned max_lvl = get_compat_level(cpu_->max_compat);
int counter;
/* Parse PVR list */
for (counter = 0; counter < 512; ++counter) {
uint32_t pvr, pvr_mask;
pvr_mask = rtas_ld(list, 0);
list += 4;
pvr = rtas_ld(list, 0);
list += 4;
trace_spapr_cas_pvr_try(pvr);
if (!max_lvl &&
((cpu_->env.spr[SPR_PVR] & pvr_mask) == (pvr & pvr_mask))) {
cpu_match = true;
cpu_version = 0;
} else if (pvr == cpu_->cpu_version) {
cpu_match = true;
cpu_version = cpu_->cpu_version;
} else if (!cpu_match) {
/* If it is a logical PVR, try to determine the highest level */
unsigned lvl = get_compat_level(pvr);
if (lvl) {
bool is205 = (pcc_->pcr_mask & PCR_COMPAT_2_05) &&
(lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_05));
bool is206 = (pcc_->pcr_mask & PCR_COMPAT_2_06) &&
((lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06)) ||
(lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06_PLUS)));
if (is205 || is206) {
if (!max_lvl) {
/* User did not set the level, choose the highest */
if (compat_lvl <= lvl) {
compat_lvl = lvl;
cpu_version = pvr;
}
} else if (max_lvl >= lvl) {
/* User chose the level, don't set higher than this */
compat_lvl = lvl;
cpu_version = pvr;
}
}
}
ret = H_SUCCESS;
}
/* Terminator record */
if (~pvr_mask & pvr) {
break;
}
}
default:
ret = H_UNSUPPORTED_FLAG;
/* For the future use: here @list points to the first capability */
/* Parsing finished */
trace_spapr_cas_pvr(cpu_->cpu_version, cpu_match,
cpu_version, pcc_->pcr_mask);
/* Update CPUs */
if (old_cpu_version != cpu_version) {
CPU_FOREACH(cs) {
SetCompatState s = {
.cpu = POWERPC_CPU(cs),
.cpu_version = cpu_version,
.ret = 0
};
run_on_cpu(cs, do_set_compat, &s);
if (s.ret < 0) {
fprintf(stderr, "Unable to set compatibility mode\n");
return H_HARDWARE;
}
}
}
out:
return ret;
if (!cpu_version) {
return H_SUCCESS;
}
if (!list) {
return H_SUCCESS;
}
if (spapr_h_cas_compose_response(args[1], args[2])) {
qemu_system_reset_request();
}
return H_SUCCESS;
}
static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
......@@ -831,6 +1005,9 @@ static void hypercall_register_types(void)
spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
spapr_register_hypercall(H_SET_MODE, h_set_mode);
/* ibm,client-architecture-support support */
spapr_register_hypercall(KVMPPC_H_CAS, h_client_architecture_support);
}
type_init(hypercall_register_types)
......@@ -35,6 +35,9 @@ enum sPAPRTCEAccess {
SPAPR_TCE_RW = 3,
};
#define IOMMU_PAGE_SIZE(shift) (1ULL << (shift))
#define IOMMU_PAGE_MASK(shift) (~(IOMMU_PAGE_SIZE(shift) - 1))
static QLIST_HEAD(spapr_tce_tables, sPAPRTCETable) spapr_tce_tables;
static sPAPRTCETable *spapr_tce_find_by_liobn(uint32_t liobn)
......@@ -70,12 +73,14 @@ static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr)
if (tcet->bypass) {
ret.perm = IOMMU_RW;
} else if (addr < tcet->window_size) {
} else if ((addr >> tcet->page_shift) < tcet->nb_table) {
/* 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;
hwaddr page_mask = IOMMU_PAGE_MASK(tcet->page_shift);
tce = tcet->table[addr >> tcet->page_shift];
ret.iova = addr & page_mask;
ret.translated_addr = tce & page_mask;
ret.addr_mask = ~page_mask;
ret.perm = tce;
}
trace_spapr_iommu_xlate(tcet->liobn, addr, ret.iova, ret.perm,
......@@ -84,24 +89,14 @@ static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr)
return ret;
}
static int spapr_tce_table_pre_load(void *opaque)
{
sPAPRTCETable *tcet = SPAPR_TCE_TABLE(opaque);
tcet->nb_table = tcet->window_size >> SPAPR_TCE_PAGE_SHIFT;
return 0;
}
static const VMStateDescription vmstate_spapr_tce_table = {
.name = "spapr_iommu",
.version_id = 1,
.minimum_version_id = 1,
.pre_load = spapr_tce_table_pre_load,
.fields = (VMStateField[]) {
.version_id = 2,
.minimum_version_id = 2,
.fields = (VMStateField []) {
/* Sanity check */
VMSTATE_UINT32_EQUAL(liobn, sPAPRTCETable),
VMSTATE_UINT32_EQUAL(window_size, sPAPRTCETable),
VMSTATE_UINT32_EQUAL(nb_table, sPAPRTCETable),
/* IOMMU state */
VMSTATE_BOOL(bypass, sPAPRTCETable),
......@@ -121,28 +116,33 @@ static int spapr_tce_table_realize(DeviceState *dev)
if (kvm_enabled()) {
tcet->table = kvmppc_create_spapr_tce(tcet->liobn,
tcet->window_size,
tcet->nb_table <<
tcet->page_shift,
&tcet->fd);
}
if (!tcet->table) {
size_t table_size = (tcet->window_size >> SPAPR_TCE_PAGE_SHIFT)
* sizeof(uint64_t);
size_t table_size = tcet->nb_table * sizeof(uint64_t);
tcet->table = g_malloc0(table_size);
}
tcet->nb_table = tcet->window_size >> SPAPR_TCE_PAGE_SHIFT;
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);
"iommu-spapr", ram_size);
QLIST_INSERT_HEAD(&spapr_tce_tables, tcet, list);
vmstate_register(DEVICE(tcet), tcet->liobn, &vmstate_spapr_tce_table,
tcet);
return 0;
}
sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn, size_t window_size)
sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn,
uint64_t bus_offset,
uint32_t page_shift,
uint32_t nb_table)
{
sPAPRTCETable *tcet;
......@@ -152,17 +152,19 @@ sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn, size_t wi
return NULL;
}
if (!window_size) {
if (!nb_table) {
return NULL;
}
tcet = SPAPR_TCE_TABLE(object_new(TYPE_SPAPR_TCE_TABLE));
tcet->liobn = liobn;
tcet->window_size = window_size;
tcet->bus_offset = bus_offset;
tcet->page_shift = page_shift;
tcet->nb_table = nb_table;
object_property_add_child(OBJECT(owner), "tce-table", OBJECT(tcet), NULL);
qdev_init_nofail(DEVICE(tcet));
object_property_set_bool(OBJECT(tcet), true, "realized", NULL);
return tcet;
}
......@@ -175,7 +177,7 @@ static void spapr_tce_table_finalize(Object *obj)
if (!kvm_enabled() ||
(kvmppc_remove_spapr_tce(tcet->table, tcet->fd,
tcet->window_size) != 0)) {
tcet->nb_table) != 0)) {
g_free(tcet->table);
}
}
......@@ -193,8 +195,7 @@ void spapr_tce_set_bypass(sPAPRTCETable *tcet, bool bypass)
static void spapr_tce_reset(DeviceState *dev)
{
sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev);
size_t table_size = (tcet->window_size >> SPAPR_TCE_PAGE_SHIFT)
* sizeof(uint64_t);
size_t table_size = tcet->nb_table * sizeof(uint64_t);
tcet->bypass = false;
memset(tcet->table, 0, table_size);
......@@ -204,25 +205,110 @@ static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
target_ulong tce)
{
IOMMUTLBEntry entry;
hwaddr page_mask = IOMMU_PAGE_MASK(tcet->page_shift);
unsigned long index = (ioba - tcet->bus_offset) >> tcet->page_shift;
if (ioba >= tcet->window_size) {
if (index >= tcet->nb_table) {
hcall_dprintf("spapr_vio_put_tce on out-of-bounds IOBA 0x"
TARGET_FMT_lx "\n", ioba);
return H_PARAMETER;
}
tcet->table[ioba >> SPAPR_TCE_PAGE_SHIFT] = tce;
tcet->table[index] = tce;
entry.target_as = &address_space_memory,
entry.iova = ioba & ~SPAPR_TCE_PAGE_MASK;
entry.translated_addr = tce & ~SPAPR_TCE_PAGE_MASK;
entry.addr_mask = SPAPR_TCE_PAGE_MASK;
entry.iova = ioba & page_mask;
entry.translated_addr = tce & page_mask;
entry.addr_mask = ~page_mask;
entry.perm = tce;
memory_region_notify_iommu(&tcet->iommu, entry);
return H_SUCCESS;
}
static target_ulong h_put_tce_indirect(PowerPCCPU *cpu,
sPAPREnvironment *spapr,
target_ulong opcode, target_ulong *args)
{
int i;
target_ulong liobn = args[0];
target_ulong ioba = args[1];
target_ulong ioba1 = ioba;
target_ulong tce_list = args[2];
target_ulong npages = args[3];
target_ulong ret = H_PARAMETER;
sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
CPUState *cs = CPU(cpu);
hwaddr page_mask, page_size;
if (!tcet) {
return H_PARAMETER;
}
if ((npages > 512) || (tce_list & SPAPR_TCE_PAGE_MASK)) {
return H_PARAMETER;
}
page_mask = IOMMU_PAGE_MASK(tcet->page_shift);
page_size = IOMMU_PAGE_SIZE(tcet->page_shift);
ioba &= page_mask;
for (i = 0; i < npages; ++i, ioba += page_size) {
target_ulong off = (tce_list & ~SPAPR_TCE_RW) +
i * sizeof(target_ulong);
target_ulong tce = ldq_phys(cs->as, off);
ret = put_tce_emu(tcet, ioba, tce);
if (ret) {
break;
}
}
/* Trace last successful or the first problematic entry */
i = i ? (i - 1) : 0;
trace_spapr_iommu_indirect(liobn, ioba1, tce_list, i,
ldq_phys(cs->as,
tce_list + i * sizeof(target_ulong)),
ret);
return ret;
}
static target_ulong h_stuff_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong opcode, target_ulong *args)
{
int i;
target_ulong liobn = args[0];
target_ulong ioba = args[1];
target_ulong tce_value = args[2];
target_ulong npages = args[3];
target_ulong ret = H_PARAMETER;
sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
hwaddr page_mask, page_size;
if (!tcet) {
return H_PARAMETER;
}
if (npages > tcet->nb_table) {
return H_PARAMETER;
}
page_mask = IOMMU_PAGE_MASK(tcet->page_shift);
page_size = IOMMU_PAGE_SIZE(tcet->page_shift);
ioba &= page_mask;
for (i = 0; i < npages; ++i, ioba += page_size) {
ret = put_tce_emu(tcet, ioba, tce_value);
if (ret) {
break;
}
}
trace_spapr_iommu_stuff(liobn, ioba, tce_value, npages, ret);
return ret;
}
static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong opcode, target_ulong *args)
{
......@@ -232,9 +318,11 @@ static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong ret = H_PARAMETER;
sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
ioba &= ~(SPAPR_TCE_PAGE_SIZE - 1);
if (tcet) {
hwaddr page_mask = IOMMU_PAGE_MASK(tcet->page_shift);
ioba &= page_mask;
ret = put_tce_emu(tcet, ioba, tce);
}
trace_spapr_iommu_put(liobn, ioba, tce, ret);
......@@ -245,13 +333,15 @@ static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
static target_ulong get_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
target_ulong *tce)
{
if (ioba >= tcet->window_size) {
unsigned long index = (ioba - tcet->bus_offset) >> tcet->page_shift;
if (index >= tcet->nb_table) {
hcall_dprintf("spapr_iommu_get_tce on out-of-bounds IOBA 0x"
TARGET_FMT_lx "\n", ioba);
return H_PARAMETER;
}
*tce = tcet->table[ioba >> SPAPR_TCE_PAGE_SHIFT];
*tce = tcet->table[index];
return H_SUCCESS;
}
......@@ -265,9 +355,11 @@ static target_ulong h_get_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong ret = H_PARAMETER;
sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
ioba &= ~(SPAPR_TCE_PAGE_SIZE - 1);
if (tcet) {
hwaddr page_mask = IOMMU_PAGE_MASK(tcet->page_shift);
ioba &= page_mask;
ret = get_tce_emu(tcet, ioba, &tce);
if (!ret) {
args[0] = tce;
......@@ -316,13 +408,12 @@ int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
}
return spapr_dma_dt(fdt, node_off, propname,
tcet->liobn, 0, tcet->window_size);
tcet->liobn, 0, tcet->nb_table << tcet->page_shift);
}
static void spapr_tce_table_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_spapr_tce_table;
dc->init = spapr_tce_table_realize;
dc->reset = spapr_tce_reset;
......@@ -331,6 +422,8 @@ static void spapr_tce_table_class_init(ObjectClass *klass, void *data)
/* hcall-tce */
spapr_register_hypercall(H_PUT_TCE, h_put_tce);
spapr_register_hypercall(H_GET_TCE, h_get_tce);
spapr_register_hypercall(H_PUT_TCE_INDIRECT, h_put_tce_indirect);
spapr_register_hypercall(H_STUFF_TCE, h_stuff_tce);
}
static TypeInfo spapr_tce_table_info = {
......
......@@ -280,7 +280,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
unsigned int req_num = rtas_ld(args, 4); /* 0 == remove all */
unsigned int seq_num = rtas_ld(args, 5);
unsigned int ret_intr_type;
int ndev, irq;
int ndev, irq, max_irqs = 0;
sPAPRPHBState *phb = NULL;
PCIDevice *pdev = NULL;
......@@ -333,6 +333,23 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
}
trace_spapr_pci_msi("Configuring MSI", ndev, config_addr);
/* Check if the device supports as many IRQs as requested */
if (ret_intr_type == RTAS_TYPE_MSI) {
max_irqs = msi_nr_vectors_allocated(pdev);
} else if (ret_intr_type == RTAS_TYPE_MSIX) {
max_irqs = pdev->msix_entries_nr;
}
if (!max_irqs) {
error_report("Requested interrupt type %d is not enabled for device#%d",
ret_intr_type, ndev);
rtas_st(rets, 0, -1); /* Hardware error */
return;
}
/* Correct the number if the guest asked for too many */
if (req_num > max_irqs) {
req_num = max_irqs;
}
/* Check if there is an old config and MSI number has not changed */
if (phb->msi_table[ndev].nvec && (req_num != phb->msi_table[ndev].nvec)) {
/* Unexpected behaviour */
......@@ -511,6 +528,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
SysBusDevice *s = SYS_BUS_DEVICE(dev);
sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s);
PCIHostState *phb = PCI_HOST_BRIDGE(s);
sPAPRPHBClass *info = SPAPR_PCI_HOST_BRIDGE_GET_CLASS(s);
char *namebuf;
int i;
PCIBus *bus;
......@@ -575,23 +593,14 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
memory_region_add_subregion(get_system_memory(), sphb->mem_win_addr,
&sphb->memwindow);
/* On ppc, we only have MMIO no specific IO space from the CPU
* perspective. In theory we ought to be able to embed the PCI IO
* memory region direction in the system memory space. However,
* if any of the IO BAR subregions use the old_portio mechanism,
* that won't be processed properly unless accessed from the
* system io address space. This hack to bounce things via
* system_io works around the problem until all the users of
* old_portion are updated */
/* Initialize IO regions */
sprintf(namebuf, "%s.io", sphb->dtbusname);
memory_region_init(&sphb->iospace, OBJECT(sphb),
namebuf, SPAPR_PCI_IO_WIN_SIZE);
/* FIXME: fix to support multiple PHBs */
memory_region_add_subregion(get_system_io(), 0, &sphb->iospace);
sprintf(namebuf, "%s.io-alias", sphb->dtbusname);
memory_region_init_alias(&sphb->iowindow, OBJECT(sphb), namebuf,
get_system_io(), 0, SPAPR_PCI_IO_WIN_SIZE);
&sphb->iospace, 0, SPAPR_PCI_IO_WIN_SIZE);
memory_region_add_subregion(get_system_memory(), sphb->io_win_addr,
&sphb->iowindow);
......@@ -601,16 +610,18 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
PCI_DEVFN(0, 0), PCI_NUM_PINS, TYPE_PCI_BUS);
phb->bus = bus;
sphb->dma_window_start = 0;
sphb->dma_window_size = 0x40000000;
sphb->tcet = spapr_tce_new_table(dev, sphb->dma_liobn,
sphb->dma_window_size);
if (!sphb->tcet) {
error_setg(errp, "Unable to create TCE table for %s",
sphb->dtbusname);
return;
}
address_space_init(&sphb->iommu_as, spapr_tce_get_iommu(sphb->tcet),
/*
* Initialize PHB address space.
* By default there will be at least one subregion for default
* 32bit DMA window.
* Later the guest might want to create another DMA window
* which will become another memory subregion.
*/
sprintf(namebuf, "%s.iommu-root", sphb->dtbusname);
memory_region_init(&sphb->iommu_root, OBJECT(sphb),
namebuf, UINT64_MAX);
address_space_init(&sphb->iommu_as, &sphb->iommu_root,
sphb->dtbusname);
pci_setup_iommu(bus, spapr_pci_dma_iommu, sphb);
......@@ -631,15 +642,49 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
sphb->lsi_table[i].irq = irq;
}
if (!info->finish_realize) {
error_setg(errp, "finish_realize not defined");
return;
}
info->finish_realize(sphb, errp);
}
static void spapr_phb_reset(DeviceState *qdev)
static void spapr_phb_finish_realize(sPAPRPHBState *sphb, Error **errp)
{
SysBusDevice *s = SYS_BUS_DEVICE(qdev);
sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s);
sPAPRTCETable *tcet;
tcet = spapr_tce_new_table(DEVICE(sphb), sphb->dma_liobn,
0,
SPAPR_TCE_PAGE_SHIFT,
0x40000000 >> SPAPR_TCE_PAGE_SHIFT);
if (!tcet) {
error_setg(errp, "Unable to create TCE table for %s",
sphb->dtbusname);
return ;
}
/* Register default 32bit DMA window */
memory_region_add_subregion(&sphb->iommu_root, 0,
spapr_tce_get_iommu(tcet));
}
static int spapr_phb_children_reset(Object *child, void *opaque)
{
DeviceState *dev = (DeviceState *) object_dynamic_cast(child, TYPE_DEVICE);
if (dev) {
device_reset(dev);
}
return 0;
}
static void spapr_phb_reset(DeviceState *qdev)
{
/* Reset the IOMMU state */
device_reset(DEVICE(sphb->tcet));
object_child_foreach(OBJECT(qdev), spapr_phb_children_reset, NULL);
}
static Property spapr_phb_properties[] = {
......@@ -711,6 +756,7 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data)
{
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
sPAPRPHBClass *spc = SPAPR_PCI_HOST_BRIDGE_CLASS(klass);
hc->root_bus_path = spapr_phb_root_bus_path;
dc->realize = spapr_phb_realize;
......@@ -719,6 +765,7 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_spapr_pci;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->cannot_instantiate_with_device_add_yet = false;
spc->finish_realize = spapr_phb_finish_realize;
}
static const TypeInfo spapr_phb_info = {
......@@ -726,6 +773,7 @@ static const TypeInfo spapr_phb_info = {
.parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(sPAPRPHBState),
.class_init = spapr_phb_class_init,
.class_size = sizeof(sPAPRPHBClass),
};
PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index)
......@@ -750,6 +798,29 @@ PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index)
#define b_fff(x) b_x((x), 8, 3) /* function number */
#define b_rrrrrrrr(x) b_x((x), 0, 8) /* register number */
typedef struct sPAPRTCEDT {
void *fdt;
int node_off;
} sPAPRTCEDT;
static int spapr_phb_children_dt(Object *child, void *opaque)
{
sPAPRTCEDT *p = opaque;
sPAPRTCETable *tcet;
tcet = (sPAPRTCETable *) object_dynamic_cast(child, TYPE_SPAPR_TCE_TABLE);
if (!tcet) {
return 0;
}
spapr_dma_dt(p->fdt, p->node_off, "ibm,dma-window",
tcet->liobn, tcet->bus_offset,
tcet->nb_table << tcet->page_shift);
/* Stop after the first window */
return 1;
}
int spapr_populate_pci_dt(sPAPRPHBState *phb,
uint32_t xics_phandle,
void *fdt)
......@@ -805,6 +876,7 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,
_FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof(ranges)));
_FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg)));
_FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pci-config-space-type", 0x1));
_FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pe-total-#msi", XICS_IRQS));
/* Build the interrupt-map, this must matches what is done
* in pci_spapr_map_irq
......@@ -829,9 +901,8 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,
_FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map,
sizeof(interrupt_map)));
spapr_dma_dt(fdt, bus_off, "ibm,dma-window",
phb->dma_liobn, phb->dma_window_start,
phb->dma_window_size);
object_child_foreach(OBJECT(phb), spapr_phb_children_dt,
&((sPAPRTCEDT){ .fdt = fdt, .node_off = bus_off }));
return 0;
}
......
......@@ -456,7 +456,11 @@ static int spapr_vio_busdev_init(DeviceState *qdev)
if (pc->rtce_window_size) {
uint32_t liobn = SPAPR_VIO_BASE_LIOBN | dev->reg;
dev->tcet = spapr_tce_new_table(qdev, liobn, pc->rtce_window_size);
dev->tcet = spapr_tce_new_table(qdev, liobn,
0,
SPAPR_TCE_PAGE_SHIFT,
pc->rtce_window_size >>
SPAPR_TCE_PAGE_SHIFT);
address_space_init(&dev->as, spapr_tce_get_iommu(dev->tcet), qdev->id);
}
......
......@@ -561,6 +561,11 @@ typedef struct {
#define SHF_ALPHA_GPREL 0x10000000
/* PowerPC specific definitions. */
/* Processor specific flags for the ELF header e_flags field. */
#define EF_PPC64_ABI 0x3
/* PowerPC relocations defined by the ABIs */
#define R_PPC_NONE 0
#define R_PPC_ADDR32 1 /* 32bit absolute address */
......
......@@ -34,7 +34,21 @@
#define SPAPR_PCI_HOST_BRIDGE(obj) \
OBJECT_CHECK(sPAPRPHBState, (obj), TYPE_SPAPR_PCI_HOST_BRIDGE)
typedef struct sPAPRPHBState {
#define SPAPR_PCI_HOST_BRIDGE_CLASS(klass) \
OBJECT_CLASS_CHECK(sPAPRPHBClass, (klass), TYPE_SPAPR_PCI_HOST_BRIDGE)
#define SPAPR_PCI_HOST_BRIDGE_GET_CLASS(obj) \
OBJECT_GET_CLASS(sPAPRPHBClass, (obj), TYPE_SPAPR_PCI_HOST_BRIDGE)
typedef struct sPAPRPHBClass sPAPRPHBClass;
typedef struct sPAPRPHBState sPAPRPHBState;
struct sPAPRPHBClass {
PCIHostBridgeClass parent_class;
void (*finish_realize)(sPAPRPHBState *sphb, Error **errp);
};
struct sPAPRPHBState {
PCIHostState parent_obj;
int32_t index;
......@@ -46,10 +60,8 @@ typedef struct sPAPRPHBState {
MemoryRegion memwindow, iowindow;
uint32_t dma_liobn;
uint64_t dma_window_start;
uint64_t dma_window_size;
sPAPRTCETable *tcet;
AddressSpace iommu_as;
MemoryRegion iommu_root;
struct spapr_pci_lsi {
uint32_t irq;
......@@ -62,7 +74,7 @@ typedef struct sPAPRPHBState {
} msi_table[SPAPR_MSIX_MAX_DEVS];
QLIST_ENTRY(sPAPRPHBState) list;
} sPAPRPHBState;
};
#define SPAPR_PCI_BASE_BUID 0x800000020000000ULL
......
......@@ -42,6 +42,11 @@ struct DBDMA_io {
/* unaligned last sector of a request */
uint8_t remainder[0x200];
int remainder_len;
QEMUIOVector iov;
bool finish_remain_read;
hwaddr finish_addr;
hwaddr finish_len;
int requests;
};
/*
......
......@@ -92,6 +92,8 @@ enum {
#define FW_CFG_PPC_IS_KVM (FW_CFG_ARCH_LOCAL + 0x05)
#define FW_CFG_PPC_KVM_HC (FW_CFG_ARCH_LOCAL + 0x06)
#define FW_CFG_PPC_KVM_PID (FW_CFG_ARCH_LOCAL + 0x07)
/* OpenBIOS has FW_CFG_PPC_NVRAM_ADDR as +0x08 */
#define FW_CFG_PPC_BUSFREQ (FW_CFG_ARCH_LOCAL + 0x09)
#define PPC_SERIAL_MM_BAUDBASE 399193
......
......@@ -29,6 +29,7 @@ typedef struct sPAPREnvironment {
target_ulong entry_point;
uint32_t next_irq;
uint64_t rtc_offset;
struct PPCTimebase tb;
bool has_graphics;
uint32_t epow_irq;
......@@ -163,6 +164,11 @@ typedef struct sPAPREnvironment {
#define H_SET_MODE_ENDIAN_BIG 0
#define H_SET_MODE_ENDIAN_LITTLE 1
/* Flags for H_SET_MODE_RESOURCE_ADDR_TRANS_MODE */
#define H_SET_MODE_ADDR_TRANS_NONE 0
#define H_SET_MODE_ADDR_TRANS_0001_8000 2
#define H_SET_MODE_ADDR_TRANS_C000_0000_0000_4000 3
/* VASI States */
#define H_VASI_INVALID 0
#define H_VASI_ENABLED 1
......@@ -302,10 +308,16 @@ typedef struct sPAPREnvironment {
#define KVMPPC_HCALL_BASE 0xf000
#define KVMPPC_H_RTAS (KVMPPC_HCALL_BASE + 0x0)
#define KVMPPC_H_LOGICAL_MEMOP (KVMPPC_HCALL_BASE + 0x1)
#define KVMPPC_HCALL_MAX KVMPPC_H_LOGICAL_MEMOP
/* Client Architecture support */
#define KVMPPC_H_CAS (KVMPPC_HCALL_BASE + 0x2)
#define KVMPPC_HCALL_MAX KVMPPC_H_CAS
extern sPAPREnvironment *spapr;
typedef struct sPAPRDeviceTreeUpdateHeader {
uint32_t version_id;
} sPAPRDeviceTreeUpdateHeader;
/*#define DEBUG_SPAPR_HCALLS*/
#ifdef DEBUG_SPAPR_HCALLS
......@@ -390,8 +402,9 @@ typedef struct sPAPRTCETable sPAPRTCETable;
struct sPAPRTCETable {
DeviceState parent;
uint32_t liobn;
uint32_t window_size;
uint32_t nb_table;
uint64_t bus_offset;
uint32_t page_shift;
uint64_t *table;
bool bypass;
int fd;
......@@ -401,8 +414,11 @@ struct sPAPRTCETable {
void spapr_events_init(sPAPREnvironment *spapr);
void spapr_events_fdt_skel(void *fdt, uint32_t epow_irq);
int spapr_h_cas_compose_response(target_ulong addr, target_ulong size);
sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn,
size_t window_size);
uint64_t bus_offset,
uint32_t page_shift,
uint32_t nb_table);
MemoryRegion *spapr_tce_get_iommu(sPAPRTCETable *tcet);
void spapr_tce_set_bypass(sPAPRTCETable *tcet, bool bypass);
int spapr_dma_dt(void *fdt, int node_off, const char *propname,
......
......@@ -152,6 +152,8 @@ struct ICSIRQState {
uint8_t status;
};
#define XICS_IRQS 1024
qemu_irq xics_get_qirq(XICSState *icp, int irq);
void xics_set_irq_type(XICSState *icp, int irq, bool lsi);
......
/* Configure decNumber for either host or target.
Copyright (C) 2008 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
In addition to the permissions in the GNU General Public License,
the Free Software Foundation gives you unlimited permission to link
the compiled version of this file into combinations with other
programs, and to distribute those combinations without any
restriction coming from the use of this file. (The General Public
License restrictions do apply in other respects; for example, they
cover modification of the file, and distribution when not linked
into a combine executable.)
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA. */
#include "config-host.h"
#if defined(HOST_WORDS_BIGENDIAN)
#define WORDS_BIGENDIAN 1
#else
#define WORDS_BIGENDIAN 0
#endif
#ifndef DECDPUN
#define DECDPUN 3
#endif
/* Decimal context header module for the decNumber C Library.
Copyright (C) 2005, 2007 Free Software Foundation, Inc.
Contributed by IBM Corporation. Author Mike Cowlishaw.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
In addition to the permissions in the GNU General Public License,
the Free Software Foundation gives you unlimited permission to link
the compiled version of this file into combinations with other
programs, and to distribute those combinations without any
restriction coming from the use of this file. (The General Public
License restrictions do apply in other respects; for example, they
cover modification of the file, and distribution when not linked
into a combine executable.)
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA. */
/* ------------------------------------------------------------------ */
/* Decimal Context module header */
/* ------------------------------------------------------------------ */
/* */
/* Context variables must always have valid values: */
/* */
/* status -- [any bits may be cleared, but not set, by user] */
/* round -- must be one of the enumerated rounding modes */
/* */
/* The following variables are implied for fixed size formats (i.e., */
/* they are ignored) but should still be set correctly in case used */
/* with decNumber functions: */
/* */
/* clamp -- must be either 0 or 1 */
/* digits -- must be in the range 1 through 999999999 */
/* emax -- must be in the range 0 through 999999999 */
/* emin -- must be in the range 0 through -999999999 */
/* extended -- must be either 0 or 1 [present only if DECSUBSET] */
/* traps -- only defined bits may be set */
/* */
/* ------------------------------------------------------------------ */
#if !defined(DECCONTEXT)
#define DECCONTEXT
#define DECCNAME "decContext" /* Short name */
#define DECCFULLNAME "Decimal Context Descriptor" /* Verbose name */
#define DECCAUTHOR "Mike Cowlishaw" /* Who to blame */
#include <stdint.h>
#include <stdio.h> /* for printf, etc. */
#include <signal.h> /* for traps */
/* Extended flags setting -- set this to 0 to use only IEEE flags */
#define DECEXTFLAG 1 /* 1=enable extended flags */
/* Conditional code flag -- set this to 0 for best performance */
#define DECSUBSET 0 /* 1=enable subset arithmetic */
/* Context for operations, with associated constants */
enum rounding {
DEC_ROUND_CEILING, /* round towards +infinity */
DEC_ROUND_UP, /* round away from 0 */
DEC_ROUND_HALF_UP, /* 0.5 rounds up */
DEC_ROUND_HALF_EVEN, /* 0.5 rounds to nearest even */
DEC_ROUND_HALF_DOWN, /* 0.5 rounds down */
DEC_ROUND_DOWN, /* round towards 0 (truncate) */
DEC_ROUND_FLOOR, /* round towards -infinity */
DEC_ROUND_05UP, /* round for reround */
DEC_ROUND_MAX /* enum must be less than this */
};
#define DEC_ROUND_DEFAULT DEC_ROUND_HALF_EVEN;
typedef struct {
int32_t digits; /* working precision */
int32_t emax; /* maximum positive exponent */
int32_t emin; /* minimum negative exponent */
enum rounding round; /* rounding mode */
uint32_t traps; /* trap-enabler flags */
uint32_t status; /* status flags */
uint8_t clamp; /* flag: apply IEEE exponent clamp */
#if DECSUBSET
uint8_t extended; /* flag: special-values allowed */
#endif
} decContext;
/* Maxima and Minima for context settings */
#define DEC_MAX_DIGITS 999999999
#define DEC_MIN_DIGITS 1
#define DEC_MAX_EMAX 999999999
#define DEC_MIN_EMAX 0
#define DEC_MAX_EMIN 0
#define DEC_MIN_EMIN -999999999
#define DEC_MAX_MATH 999999 /* max emax, etc., for math funcs. */
/* Classifications for decimal numbers, aligned with 754r (note */
/* that 'normal' and 'subnormal' are meaningful only with a */
/* decContext or a fixed size format). */
enum decClass {
DEC_CLASS_SNAN,
DEC_CLASS_QNAN,
DEC_CLASS_NEG_INF,
DEC_CLASS_NEG_NORMAL,
DEC_CLASS_NEG_SUBNORMAL,
DEC_CLASS_NEG_ZERO,
DEC_CLASS_POS_ZERO,
DEC_CLASS_POS_SUBNORMAL,
DEC_CLASS_POS_NORMAL,
DEC_CLASS_POS_INF
};
/* Strings for the decClasses */
#define DEC_ClassString_SN "sNaN"
#define DEC_ClassString_QN "NaN"
#define DEC_ClassString_NI "-Infinity"
#define DEC_ClassString_NN "-Normal"
#define DEC_ClassString_NS "-Subnormal"
#define DEC_ClassString_NZ "-Zero"
#define DEC_ClassString_PZ "+Zero"
#define DEC_ClassString_PS "+Subnormal"
#define DEC_ClassString_PN "+Normal"
#define DEC_ClassString_PI "+Infinity"
#define DEC_ClassString_UN "Invalid"
/* Trap-enabler and Status flags (exceptional conditions), and */
/* their names. The top byte is reserved for internal use */
#if DECEXTFLAG
/* Extended flags */
#define DEC_Conversion_syntax 0x00000001
#define DEC_Division_by_zero 0x00000002
#define DEC_Division_impossible 0x00000004
#define DEC_Division_undefined 0x00000008
#define DEC_Insufficient_storage 0x00000010 /* [when malloc fails] */
#define DEC_Inexact 0x00000020
#define DEC_Invalid_context 0x00000040
#define DEC_Invalid_operation 0x00000080
#if DECSUBSET
#define DEC_Lost_digits 0x00000100
#endif
#define DEC_Overflow 0x00000200
#define DEC_Clamped 0x00000400
#define DEC_Rounded 0x00000800
#define DEC_Subnormal 0x00001000
#define DEC_Underflow 0x00002000
#else
/* IEEE flags only */
#define DEC_Conversion_syntax 0x00000010
#define DEC_Division_by_zero 0x00000002
#define DEC_Division_impossible 0x00000010
#define DEC_Division_undefined 0x00000010
#define DEC_Insufficient_storage 0x00000010 /* [when malloc fails] */
#define DEC_Inexact 0x00000001
#define DEC_Invalid_context 0x00000010
#define DEC_Invalid_operation 0x00000010
#if DECSUBSET
#define DEC_Lost_digits 0x00000000
#endif
#define DEC_Overflow 0x00000008
#define DEC_Clamped 0x00000000
#define DEC_Rounded 0x00000000
#define DEC_Subnormal 0x00000000
#define DEC_Underflow 0x00000004
#endif
/* IEEE 854 groupings for the flags */
/* [DEC_Clamped, DEC_Lost_digits, DEC_Rounded, and DEC_Subnormal */
/* are not in IEEE 854] */
#define DEC_IEEE_854_Division_by_zero (DEC_Division_by_zero)
#if DECSUBSET
#define DEC_IEEE_854_Inexact (DEC_Inexact | DEC_Lost_digits)
#else
#define DEC_IEEE_854_Inexact (DEC_Inexact)
#endif
#define DEC_IEEE_854_Invalid_operation (DEC_Conversion_syntax | \
DEC_Division_impossible | \
DEC_Division_undefined | \
DEC_Insufficient_storage | \
DEC_Invalid_context | \
DEC_Invalid_operation)
#define DEC_IEEE_854_Overflow (DEC_Overflow)
#define DEC_IEEE_854_Underflow (DEC_Underflow)
/* flags which are normally errors (result is qNaN, infinite, or 0) */
#define DEC_Errors (DEC_IEEE_854_Division_by_zero | \
DEC_IEEE_854_Invalid_operation | \
DEC_IEEE_854_Overflow | DEC_IEEE_854_Underflow)
/* flags which cause a result to become qNaN */
#define DEC_NaNs DEC_IEEE_854_Invalid_operation
/* flags which are normally for information only (finite results) */
#if DECSUBSET
#define DEC_Information (DEC_Clamped | DEC_Rounded | DEC_Inexact \
| DEC_Lost_digits)
#else
#define DEC_Information (DEC_Clamped | DEC_Rounded | DEC_Inexact)
#endif
/* Name strings for the exceptional conditions */
#define DEC_Condition_CS "Conversion syntax"
#define DEC_Condition_DZ "Division by zero"
#define DEC_Condition_DI "Division impossible"
#define DEC_Condition_DU "Division undefined"
#define DEC_Condition_IE "Inexact"
#define DEC_Condition_IS "Insufficient storage"
#define DEC_Condition_IC "Invalid context"
#define DEC_Condition_IO "Invalid operation"
#if DECSUBSET
#define DEC_Condition_LD "Lost digits"
#endif
#define DEC_Condition_OV "Overflow"
#define DEC_Condition_PA "Clamped"
#define DEC_Condition_RO "Rounded"
#define DEC_Condition_SU "Subnormal"
#define DEC_Condition_UN "Underflow"
#define DEC_Condition_ZE "No status"
#define DEC_Condition_MU "Multiple status"
#define DEC_Condition_Length 21 /* length of the longest string, */
/* including terminator */
/* Initialization descriptors, used by decContextDefault */
#define DEC_INIT_BASE 0
#define DEC_INIT_DECIMAL32 32
#define DEC_INIT_DECIMAL64 64
#define DEC_INIT_DECIMAL128 128
/* Synonyms */
#define DEC_INIT_DECSINGLE DEC_INIT_DECIMAL32
#define DEC_INIT_DECDOUBLE DEC_INIT_DECIMAL64
#define DEC_INIT_DECQUAD DEC_INIT_DECIMAL128
/* decContext routines */
extern decContext * decContextClearStatus(decContext *, uint32_t);
extern decContext * decContextDefault(decContext *, int32_t);
extern enum rounding decContextGetRounding(decContext *);
extern uint32_t decContextGetStatus(decContext *);
extern decContext * decContextRestoreStatus(decContext *, uint32_t, uint32_t);
extern uint32_t decContextSaveStatus(decContext *, uint32_t);
extern decContext * decContextSetRounding(decContext *, enum rounding);
extern decContext * decContextSetStatus(decContext *, uint32_t);
extern decContext * decContextSetStatusFromString(decContext *, const char *);
extern decContext * decContextSetStatusFromStringQuiet(decContext *, const char *);
extern decContext * decContextSetStatusQuiet(decContext *, uint32_t);
extern const char * decContextStatusToString(const decContext *);
extern uint32_t decContextTestSavedStatus(uint32_t, uint32_t);
extern uint32_t decContextTestStatus(decContext *, uint32_t);
extern decContext * decContextZeroStatus(decContext *);
#endif
此差异已折叠。
/* Decimal number arithmetic module header for the decNumber C Library.
Copyright (C) 2005, 2007 Free Software Foundation, Inc.
Contributed by IBM Corporation. Author Mike Cowlishaw.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
In addition to the permissions in the GNU General Public License,
the Free Software Foundation gives you unlimited permission to link
the compiled version of this file into combinations with other
programs, and to distribute those combinations without any
restriction coming from the use of this file. (The General Public
License restrictions do apply in other respects; for example, they
cover modification of the file, and distribution when not linked
into a combine executable.)
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA. */
/* ------------------------------------------------------------------ */
/* Decimal Number arithmetic module header */
/* ------------------------------------------------------------------ */
#if !defined(DECNUMBER)
#define DECNUMBER
#define DECNAME "decNumber" /* Short name */
#define DECFULLNAME "Decimal Number Module" /* Verbose name */
#define DECAUTHOR "Mike Cowlishaw" /* Who to blame */
#if !defined(DECCONTEXT)
#include "libdecnumber/decContext.h"
#endif
/* Bit settings for decNumber.bits */
#define DECNEG 0x80 /* Sign; 1=negative, 0=positive or zero */
#define DECINF 0x40 /* 1=Infinity */
#define DECNAN 0x20 /* 1=NaN */
#define DECSNAN 0x10 /* 1=sNaN */
/* The remaining bits are reserved; they must be 0 */
#define DECSPECIAL (DECINF|DECNAN|DECSNAN) /* any special value */
/* Define the decNumber data structure. The size and shape of the */
/* units array in the structure is determined by the following */
/* constant. This must not be changed without recompiling the */
/* decNumber library modules. */
#define DECDPUN 3 /* DECimal Digits Per UNit [must be >0 */
/* and <10; 3 or powers of 2 are best]. */
/* DECNUMDIGITS is the default number of digits that can be held in */
/* the structure. If undefined, 1 is assumed and it is assumed */
/* that the structure will be immediately followed by extra space, */
/* as required. DECNUMDIGITS is always >0. */
#if !defined(DECNUMDIGITS)
#define DECNUMDIGITS 1
#endif
/* The size (integer data type) of each unit is determined by the */
/* number of digits it will hold. */
#if DECDPUN<=2
#define decNumberUnit uint8_t
#elif DECDPUN<=4
#define decNumberUnit uint16_t
#else
#define decNumberUnit uint32_t
#endif
/* The number of units needed is ceil(DECNUMDIGITS/DECDPUN) */
#define DECNUMUNITS ((DECNUMDIGITS+DECDPUN-1)/DECDPUN)
/* The data structure... */
typedef struct {
int32_t digits; /* Count of digits in the coefficient; >0 */
int32_t exponent; /* Unadjusted exponent, unbiased, in */
/* range: -1999999997 through 999999999 */
uint8_t bits; /* Indicator bits (see above) */
/* Coefficient, from least significant unit */
decNumberUnit lsu[DECNUMUNITS];
} decNumber;
/* Notes: */
/* 1. If digits is > DECDPUN then there will one or more */
/* decNumberUnits immediately following the first element of lsu.*/
/* These contain the remaining (more significant) digits of the */
/* number, and may be in the lsu array, or may be guaranteed by */
/* some other mechanism (such as being contained in another */
/* structure, or being overlaid on dynamically allocated */
/* storage). */
/* */
/* Each integer of the coefficient (except potentially the last) */
/* contains DECDPUN digits (e.g., a value in the range 0 through */
/* 99999999 if DECDPUN is 8, or 0 through 999 if DECDPUN is 3). */
/* */
/* 2. A decNumber converted to a string may need up to digits+14 */
/* characters. The worst cases (non-exponential and exponential */
/* formats) are -0.00000{9...}# and -9.{9...}E+999999999# */
/* (where # is '\0') */
/* ---------------------------------------------------------------- */
/* decNumber public functions and macros */
/* ---------------------------------------------------------------- */
/* Conversions */
decNumber * decNumberFromInt32(decNumber *, int32_t);
decNumber * decNumberFromUInt32(decNumber *, uint32_t);
decNumber *decNumberFromInt64(decNumber *, int64_t);
decNumber *decNumberFromUInt64(decNumber *, uint64_t);
decNumber * decNumberFromString(decNumber *, const char *, decContext *);
char * decNumberToString(const decNumber *, char *);
char * decNumberToEngString(const decNumber *, char *);
uint32_t decNumberToUInt32(const decNumber *, decContext *);
int32_t decNumberToInt32(const decNumber *, decContext *);
int64_t decNumberIntegralToInt64(const decNumber *dn, decContext *set);
uint8_t * decNumberGetBCD(const decNumber *, uint8_t *);
decNumber * decNumberSetBCD(decNumber *, const uint8_t *, uint32_t);
/* Operators and elementary functions */
decNumber * decNumberAbs(decNumber *, const decNumber *, decContext *);
decNumber * decNumberAdd(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * decNumberAnd(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * decNumberCompare(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * decNumberCompareSignal(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * decNumberCompareTotal(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * decNumberCompareTotalMag(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * decNumberDivide(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * decNumberDivideInteger(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * decNumberExp(decNumber *, const decNumber *, decContext *);
decNumber * decNumberFMA(decNumber *, const decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * decNumberInvert(decNumber *, const decNumber *, decContext *);
decNumber * decNumberLn(decNumber *, const decNumber *, decContext *);
decNumber * decNumberLogB(decNumber *, const decNumber *, decContext *);
decNumber * decNumberLog10(decNumber *, const decNumber *, decContext *);
decNumber * decNumberMax(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * decNumberMaxMag(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * decNumberMin(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * decNumberMinMag(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * decNumberMinus(decNumber *, const decNumber *, decContext *);
decNumber * decNumberMultiply(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * decNumberNormalize(decNumber *, const decNumber *, decContext *);
decNumber * decNumberOr(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * decNumberPlus(decNumber *, const decNumber *, decContext *);
decNumber * decNumberPower(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * decNumberQuantize(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * decNumberReduce(decNumber *, const decNumber *, decContext *);
decNumber * decNumberRemainder(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * decNumberRemainderNear(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * decNumberRescale(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * decNumberRotate(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * decNumberSameQuantum(decNumber *, const decNumber *, const decNumber *);
decNumber * decNumberScaleB(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * decNumberShift(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * decNumberSquareRoot(decNumber *, const decNumber *, decContext *);
decNumber * decNumberSubtract(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * decNumberToIntegralExact(decNumber *, const decNumber *, decContext *);
decNumber * decNumberToIntegralValue(decNumber *, const decNumber *, decContext *);
decNumber * decNumberXor(decNumber *, const decNumber *, const decNumber *, decContext *);
/* Utilities */
enum decClass decNumberClass(const decNumber *, decContext *);
const char * decNumberClassToString(enum decClass);
decNumber * decNumberCopy(decNumber *, const decNumber *);
decNumber * decNumberCopyAbs(decNumber *, const decNumber *);
decNumber * decNumberCopyNegate(decNumber *, const decNumber *);
decNumber * decNumberCopySign(decNumber *, const decNumber *, const decNumber *);
decNumber * decNumberNextMinus(decNumber *, const decNumber *, decContext *);
decNumber * decNumberNextPlus(decNumber *, const decNumber *, decContext *);
decNumber * decNumberNextToward(decNumber *, const decNumber *, const decNumber *, decContext *);
decNumber * decNumberTrim(decNumber *);
const char * decNumberVersion(void);
decNumber * decNumberZero(decNumber *);
/* Functions for testing decNumbers (normality depends on context) */
int32_t decNumberIsNormal(const decNumber *, decContext *);
int32_t decNumberIsSubnormal(const decNumber *, decContext *);
/* Macros for testing decNumber *dn */
#define decNumberIsCanonical(dn) (1) /* All decNumbers are saintly */
#define decNumberIsFinite(dn) (((dn)->bits&DECSPECIAL)==0)
#define decNumberIsInfinite(dn) (((dn)->bits&DECINF)!=0)
#define decNumberIsNaN(dn) (((dn)->bits&(DECNAN|DECSNAN))!=0)
#define decNumberIsNegative(dn) (((dn)->bits&DECNEG)!=0)
#define decNumberIsQNaN(dn) (((dn)->bits&(DECNAN))!=0)
#define decNumberIsSNaN(dn) (((dn)->bits&(DECSNAN))!=0)
#define decNumberIsSpecial(dn) (((dn)->bits&DECSPECIAL)!=0)
#define decNumberIsZero(dn) (*(dn)->lsu==0 \
&& (dn)->digits==1 \
&& (((dn)->bits&DECSPECIAL)==0))
#define decNumberRadix(dn) (10)
#endif
此差异已折叠。
/* Decimal 128-bit format module header for the decNumber C Library.
Copyright (C) 2005, 2007 Free Software Foundation, Inc.
Contributed by IBM Corporation. Author Mike Cowlishaw.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
In addition to the permissions in the GNU General Public License,
the Free Software Foundation gives you unlimited permission to link
the compiled version of this file into combinations with other
programs, and to distribute those combinations without any
restriction coming from the use of this file. (The General Public
License restrictions do apply in other respects; for example, they
cover modification of the file, and distribution when not linked
into a combine executable.)
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA. */
/* ------------------------------------------------------------------ */
/* Decimal 128-bit format module header */
/* ------------------------------------------------------------------ */
#if !defined(DECIMAL128)
#define DECIMAL128
#define DEC128NAME "decimal128" /* Short name */
#define DEC128FULLNAME "Decimal 128-bit Number" /* Verbose name */
#define DEC128AUTHOR "Mike Cowlishaw" /* Who to blame */
/* parameters for decimal128s */
#define DECIMAL128_Bytes 16 /* length */
#define DECIMAL128_Pmax 34 /* maximum precision (digits) */
#define DECIMAL128_Emax 6144 /* maximum adjusted exponent */
#define DECIMAL128_Emin -6143 /* minimum adjusted exponent */
#define DECIMAL128_Bias 6176 /* bias for the exponent */
#define DECIMAL128_String 43 /* maximum string length, +1 */
#define DECIMAL128_EconL 12 /* exp. continuation length */
/* highest biased exponent (Elimit-1) */
#define DECIMAL128_Ehigh (DECIMAL128_Emax+DECIMAL128_Bias-DECIMAL128_Pmax+1)
/* check enough digits, if pre-defined */
#if defined(DECNUMDIGITS)
#if (DECNUMDIGITS<DECIMAL128_Pmax)
#error decimal128.h needs pre-defined DECNUMDIGITS>=34 for safe use
#endif
#endif
#ifndef DECNUMDIGITS
#define DECNUMDIGITS DECIMAL128_Pmax /* size if not already defined*/
#endif
#ifndef DECNUMBER
#include "libdecnumber/decNumber.h"
#endif
/* Decimal 128-bit type, accessible by bytes */
typedef struct {
uint8_t bytes[DECIMAL128_Bytes]; /* decimal128: 1, 5, 12, 110 bits*/
} decimal128;
/* special values [top byte excluding sign bit; last two bits are */
/* don't-care for Infinity on input, last bit don't-care for NaN] */
#if !defined(DECIMAL_NaN)
#define DECIMAL_NaN 0x7c /* 0 11111 00 NaN */
#define DECIMAL_sNaN 0x7e /* 0 11111 10 sNaN */
#define DECIMAL_Inf 0x78 /* 0 11110 00 Infinity */
#endif
#include "decimal128Local.h"
/* ---------------------------------------------------------------- */
/* Routines */
/* ---------------------------------------------------------------- */
/* String conversions */
decimal128 * decimal128FromString(decimal128 *, const char *, decContext *);
char * decimal128ToString(const decimal128 *, char *);
char * decimal128ToEngString(const decimal128 *, char *);
/* decNumber conversions */
decimal128 * decimal128FromNumber(decimal128 *, const decNumber *,
decContext *);
decNumber * decimal128ToNumber(const decimal128 *, decNumber *);
/* Format-dependent utilities */
uint32_t decimal128IsCanonical(const decimal128 *);
decimal128 * decimal128Canonical(decimal128 *, const decimal128 *);
#endif
/* Local definitions for use with the decNumber C Library.
Copyright (C) 2007 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
In addition to the permissions in the GNU General Public License,
the Free Software Foundation gives you unlimited permission to link
the compiled version of this file into combinations with other
programs, and to distribute those combinations without any
restriction coming from the use of this file. (The General Public
License restrictions do apply in other respects; for example, they
cover modification of the file, and distribution when not linked
into a combine executable.)
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA. */
#if !defined(DECIMAL128LOCAL)
/* The compiler needs sign manipulation functions for decimal128 which
are not part of the decNumber package. */
/* Set sign; this assumes the sign was previously zero. */
#define decimal128SetSign(d,b) \
{ (d)->bytes[WORDS_BIGENDIAN ? 0 : 15] |= ((unsigned) (b) << 7); }
/* Clear sign. */
#define decimal128ClearSign(d) \
{ (d)->bytes[WORDS_BIGENDIAN ? 0 : 15] &= ~0x80; }
/* Flip sign. */
#define decimal128FlipSign(d) \
{ (d)->bytes[WORDS_BIGENDIAN ? 0 : 15] ^= 0x80; }
#endif
/* Decimal 32-bit format module header for the decNumber C Library.
Copyright (C) 2005, 2007 Free Software Foundation, Inc.
Contributed by IBM Corporation. Author Mike Cowlishaw.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
In addition to the permissions in the GNU General Public License,
the Free Software Foundation gives you unlimited permission to link
the compiled version of this file into combinations with other
programs, and to distribute those combinations without any
restriction coming from the use of this file. (The General Public
License restrictions do apply in other respects; for example, they
cover modification of the file, and distribution when not linked
into a combine executable.)
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA. */
/* ------------------------------------------------------------------ */
/* Decimal 32-bit format module header */
/* ------------------------------------------------------------------ */
#if !defined(DECIMAL32)
#define DECIMAL32
#define DEC32NAME "decimal32" /* Short name */
#define DEC32FULLNAME "Decimal 32-bit Number" /* Verbose name */
#define DEC32AUTHOR "Mike Cowlishaw" /* Who to blame */
/* parameters for decimal32s */
#define DECIMAL32_Bytes 4 /* length */
#define DECIMAL32_Pmax 7 /* maximum precision (digits) */
#define DECIMAL32_Emax 96 /* maximum adjusted exponent */
#define DECIMAL32_Emin -95 /* minimum adjusted exponent */
#define DECIMAL32_Bias 101 /* bias for the exponent */
#define DECIMAL32_String 15 /* maximum string length, +1 */
#define DECIMAL32_EconL 6 /* exp. continuation length */
/* highest biased exponent (Elimit-1) */
#define DECIMAL32_Ehigh (DECIMAL32_Emax+DECIMAL32_Bias-DECIMAL32_Pmax+1)
/* check enough digits, if pre-defined */
#if defined(DECNUMDIGITS)
#if (DECNUMDIGITS<DECIMAL32_Pmax)
#error decimal32.h needs pre-defined DECNUMDIGITS>=7 for safe use
#endif
#endif
#ifndef DECNUMDIGITS
#define DECNUMDIGITS DECIMAL32_Pmax /* size if not already defined*/
#endif
#ifndef DECNUMBER
#include "libdecnumber/decNumber.h"
#endif
/* Decimal 32-bit type, accessible by bytes */
typedef struct {
uint8_t bytes[DECIMAL32_Bytes]; /* decimal32: 1, 5, 6, 20 bits*/
} decimal32;
/* special values [top byte excluding sign bit; last two bits are */
/* don't-care for Infinity on input, last bit don't-care for NaN] */
#if !defined(DECIMAL_NaN)
#define DECIMAL_NaN 0x7c /* 0 11111 00 NaN */
#define DECIMAL_sNaN 0x7e /* 0 11111 10 sNaN */
#define DECIMAL_Inf 0x78 /* 0 11110 00 Infinity */
#endif
/* ---------------------------------------------------------------- */
/* Routines */
/* ---------------------------------------------------------------- */
/* String conversions */
decimal32 * decimal32FromString(decimal32 *, const char *, decContext *);
char * decimal32ToString(const decimal32 *, char *);
char * decimal32ToEngString(const decimal32 *, char *);
/* decNumber conversions */
decimal32 * decimal32FromNumber(decimal32 *, const decNumber *,
decContext *);
decNumber * decimal32ToNumber(const decimal32 *, decNumber *);
/* Format-dependent utilities */
uint32_t decimal32IsCanonical(const decimal32 *);
decimal32 * decimal32Canonical(decimal32 *, const decimal32 *);
#endif
/* Decimal 64-bit format module header for the decNumber C Library.
Copyright (C) 2005, 2007 Free Software Foundation, Inc.
Contributed by IBM Corporation. Author Mike Cowlishaw.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
In addition to the permissions in the GNU General Public License,
the Free Software Foundation gives you unlimited permission to link
the compiled version of this file into combinations with other
programs, and to distribute those combinations without any
restriction coming from the use of this file. (The General Public
License restrictions do apply in other respects; for example, they
cover modification of the file, and distribution when not linked
into a combine executable.)
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA. */
/* ------------------------------------------------------------------ */
/* Decimal 64-bit format module header */
/* ------------------------------------------------------------------ */
#if !defined(DECIMAL64)
#define DECIMAL64
#define DEC64NAME "decimal64" /* Short name */
#define DEC64FULLNAME "Decimal 64-bit Number" /* Verbose name */
#define DEC64AUTHOR "Mike Cowlishaw" /* Who to blame */
/* parameters for decimal64s */
#define DECIMAL64_Bytes 8 /* length */
#define DECIMAL64_Pmax 16 /* maximum precision (digits) */
#define DECIMAL64_Emax 384 /* maximum adjusted exponent */
#define DECIMAL64_Emin -383 /* minimum adjusted exponent */
#define DECIMAL64_Bias 398 /* bias for the exponent */
#define DECIMAL64_String 24 /* maximum string length, +1 */
#define DECIMAL64_EconL 8 /* exp. continuation length */
/* highest biased exponent (Elimit-1) */
#define DECIMAL64_Ehigh (DECIMAL64_Emax+DECIMAL64_Bias-DECIMAL64_Pmax+1)
/* check enough digits, if pre-defined */
#if defined(DECNUMDIGITS)
#if (DECNUMDIGITS<DECIMAL64_Pmax)
#error decimal64.h needs pre-defined DECNUMDIGITS>=16 for safe use
#endif
#endif
#ifndef DECNUMDIGITS
#define DECNUMDIGITS DECIMAL64_Pmax /* size if not already defined*/
#endif
#ifndef DECNUMBER
#include "libdecnumber/decNumber.h"
#endif
/* Decimal 64-bit type, accessible by bytes */
typedef struct {
uint8_t bytes[DECIMAL64_Bytes]; /* decimal64: 1, 5, 8, 50 bits*/
} decimal64;
/* special values [top byte excluding sign bit; last two bits are */
/* don't-care for Infinity on input, last bit don't-care for NaN] */
#if !defined(DECIMAL_NaN)
#define DECIMAL_NaN 0x7c /* 0 11111 00 NaN */
#define DECIMAL_sNaN 0x7e /* 0 11111 10 sNaN */
#define DECIMAL_Inf 0x78 /* 0 11110 00 Infinity */
#endif
/* ---------------------------------------------------------------- */
/* Routines */
/* ---------------------------------------------------------------- */
/* String conversions */
decimal64 * decimal64FromString(decimal64 *, const char *, decContext *);
char * decimal64ToString(const decimal64 *, char *);
char * decimal64ToEngString(const decimal64 *, char *);
/* decNumber conversions */
decimal64 * decimal64FromNumber(decimal64 *, const decNumber *,
decContext *);
decNumber * decimal64ToNumber(const decimal64 *, decNumber *);
/* Format-dependent utilities */
uint32_t decimal64IsCanonical(const decimal64 *);
decimal64 * decimal64Canonical(decimal64 *, const decimal64 *);
#endif
......@@ -23,6 +23,20 @@ void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
const unsigned long length, const AES_KEY *key,
unsigned char *ivec, const int enc);
extern const uint8_t AES_sbox[256];
extern const uint8_t AES_isbox[256];
/* AES ShiftRows and InvShiftRows */
extern const uint8_t AES_shifts[16];
extern const uint8_t AES_ishifts[16];
/* AES InvMixColumns */
/* AES_imc[x][0] = [x].[0e, 09, 0d, 0b]; */
/* AES_imc[x][1] = [x].[0b, 0e, 09, 0d]; */
/* AES_imc[x][2] = [x].[0d, 0b, 0e, 09]; */
/* AES_imc[x][3] = [x].[09, 0d, 0b, 0e]; */
extern const uint32_t AES_imc[256][4];
/*
AES_Te0[x] = S [x].[02, 01, 01, 03];
AES_Te1[x] = S [x].[03, 02, 01, 01];
......
/*
* QEMU dump
*
* Copyright Fujitsu, Corp. 2011, 2012
*
* Authors:
* Wen Congyang <wency@cn.fujitsu.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
*/
#ifndef DUMP_ARCH_H
#define DUMP_ARCH_H
typedef struct ArchDumpInfo {
int d_machine; /* Architecture */
int d_endian; /* ELFDATA2LSB or ELFDATA2MSB */
int d_class; /* ELFCLASS32 or ELFCLASS64 */
} ArchDumpInfo;
struct GuestPhysBlockList; /* memory_mapping.h */
int cpu_get_dump_info(ArchDumpInfo *info,
const struct GuestPhysBlockList *guest_phys_blocks);
ssize_t cpu_get_note_size(int class, int machine, int nr_cpus);
#endif
......@@ -43,11 +43,8 @@
#define PFN_BUFBITMAP (CHAR_BIT * BUFSIZE_BITMAP)
#define BUFSIZE_DATA_CACHE (TARGET_PAGE_SIZE * 4)
typedef struct ArchDumpInfo {
int d_machine; /* Architecture */
int d_endian; /* ELFDATA2LSB or ELFDATA2MSB */
int d_class; /* ELFCLASS32 or ELFCLASS64 */
} ArchDumpInfo;
#include "sysemu/dump-arch.h"
#include "sysemu/memory_mapping.h"
typedef struct QEMU_PACKED MakedumpfileHeader {
char signature[16]; /* = "makedumpfile" */
......@@ -158,9 +155,37 @@ typedef struct QEMU_PACKED PageDescriptor {
uint64_t page_flags; /* page flags */
} PageDescriptor;
struct GuestPhysBlockList; /* memory_mapping.h */
int cpu_get_dump_info(ArchDumpInfo *info,
const struct GuestPhysBlockList *guest_phys_blocks);
ssize_t cpu_get_note_size(int class, int machine, int nr_cpus);
typedef struct DumpState {
GuestPhysBlockList guest_phys_blocks;
ArchDumpInfo dump_info;
MemoryMappingList list;
uint16_t phdr_num;
uint32_t sh_info;
bool have_section;
bool resume;
ssize_t note_size;
hwaddr memory_offset;
int fd;
GuestPhysBlock *next_block;
ram_addr_t start;
bool has_filter;
int64_t begin;
int64_t length;
uint8_t *note_buf; /* buffer for notes */
size_t note_buf_offset; /* the writing place in note_buf */
uint32_t nr_cpus; /* number of guest's cpu */
uint64_t max_mapnr; /* the biggest guest's phys-mem's number */
size_t len_dump_bitmap; /* the size of the place used to store
dump_bitmap in vmcore */
off_t offset_dump_bitmap; /* offset of dump_bitmap part in vmcore */
off_t offset_page; /* offset of page part in vmcore */
size_t num_dumpable; /* number of page that can be dumped */
uint32_t flag_compress; /* indicate the compression format */
} DumpState;
uint16_t cpu_to_dump16(DumpState *s, uint16_t val);
uint32_t cpu_to_dump32(DumpState *s, uint32_t val);
uint64_t cpu_to_dump64(DumpState *s, uint64_t val);
#endif
此差异已折叠。
此差异已折叠。
此差异已折叠。
/* Local definitions for use with the decNumber C Library.
Copyright (C) 2007, 2009 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.
You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
#if !defined(DECIMAL128LOCAL)
/* The compiler needs sign manipulation functions for decimal128 which
are not part of the decNumber package. */
/* Set sign; this assumes the sign was previously zero. */
#define decimal128SetSign(d,b) \
{ (d)->bytes[WORDS_BIGENDIAN ? 0 : 15] |= ((unsigned) (b) << 7); }
/* Clear sign. */
#define decimal128ClearSign(d) \
{ (d)->bytes[WORDS_BIGENDIAN ? 0 : 15] &= ~0x80; }
/* Flip sign. */
#define decimal128FlipSign(d) \
{ (d)->bytes[WORDS_BIGENDIAN ? 0 : 15] ^= 0x80; }
#endif
此差异已折叠。
此差异已折叠。
......@@ -20,6 +20,7 @@
#define __ARM_KVM_H__
#include <linux/types.h>
#include <linux/psci.h>
#include <asm/ptrace.h>
#define __KVM_HAVE_GUEST_DEBUG
......@@ -83,6 +84,7 @@ struct kvm_regs {
#define KVM_VGIC_V2_CPU_SIZE 0x2000
#define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */
#define KVM_ARM_VCPU_PSCI_0_2 1 /* CPU uses PSCI v0.2 */
struct kvm_vcpu_init {
__u32 target;
......@@ -201,9 +203,9 @@ struct kvm_arch_memory_slot {
#define KVM_PSCI_FN_CPU_ON KVM_PSCI_FN(2)
#define KVM_PSCI_FN_MIGRATE KVM_PSCI_FN(3)
#define KVM_PSCI_RET_SUCCESS 0
#define KVM_PSCI_RET_NI ((unsigned long)-1)
#define KVM_PSCI_RET_INVAL ((unsigned long)-2)
#define KVM_PSCI_RET_DENIED ((unsigned long)-3)
#define KVM_PSCI_RET_SUCCESS PSCI_RET_SUCCESS
#define KVM_PSCI_RET_NI PSCI_RET_NOT_SUPPORTED
#define KVM_PSCI_RET_INVAL PSCI_RET_INVALID_PARAMS
#define KVM_PSCI_RET_DENIED PSCI_RET_DENIED
#endif /* __ARM_KVM_H__ */
......@@ -31,6 +31,7 @@
#define KVM_NR_SPSR 5
#ifndef __ASSEMBLY__
#include <linux/psci.h>
#include <asm/types.h>
#include <asm/ptrace.h>
......@@ -56,8 +57,9 @@ struct kvm_regs {
#define KVM_ARM_TARGET_FOUNDATION_V8 1
#define KVM_ARM_TARGET_CORTEX_A57 2
#define KVM_ARM_TARGET_XGENE_POTENZA 3
#define KVM_ARM_TARGET_CORTEX_A53 4
#define KVM_ARM_NUM_TARGETS 4
#define KVM_ARM_NUM_TARGETS 5
/* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */
#define KVM_ARM_DEVICE_TYPE_SHIFT 0
......@@ -77,6 +79,7 @@ struct kvm_regs {
#define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */
#define KVM_ARM_VCPU_EL1_32BIT 1 /* CPU running a 32bit VM */
#define KVM_ARM_VCPU_PSCI_0_2 2 /* CPU uses PSCI v0.2 */
struct kvm_vcpu_init {
__u32 target;
......@@ -186,10 +189,10 @@ struct kvm_arch_memory_slot {
#define KVM_PSCI_FN_CPU_ON KVM_PSCI_FN(2)
#define KVM_PSCI_FN_MIGRATE KVM_PSCI_FN(3)
#define KVM_PSCI_RET_SUCCESS 0
#define KVM_PSCI_RET_NI ((unsigned long)-1)
#define KVM_PSCI_RET_INVAL ((unsigned long)-2)
#define KVM_PSCI_RET_DENIED ((unsigned long)-3)
#define KVM_PSCI_RET_SUCCESS PSCI_RET_SUCCESS
#define KVM_PSCI_RET_NI PSCI_RET_NOT_SUPPORTED
#define KVM_PSCI_RET_INVAL PSCI_RET_INVALID_PARAMS
#define KVM_PSCI_RET_DENIED PSCI_RET_DENIED
#endif
......
......@@ -106,6 +106,41 @@ struct kvm_fpu {
#define KVM_REG_MIPS_LO (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 33)
#define KVM_REG_MIPS_PC (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 34)
/* KVM specific control registers */
/*
* CP0_Count control
* DC: Set 0: Master disable CP0_Count and set COUNT_RESUME to now
* Set 1: Master re-enable CP0_Count with unchanged bias, handling timer
* interrupts since COUNT_RESUME
* This can be used to freeze the timer to get a consistent snapshot of
* the CP0_Count and timer interrupt pending state, while also resuming
* safely without losing time or guest timer interrupts.
* Other: Reserved, do not change.
*/
#define KVM_REG_MIPS_COUNT_CTL (KVM_REG_MIPS | KVM_REG_SIZE_U64 | \
0x20000 | 0)
#define KVM_REG_MIPS_COUNT_CTL_DC 0x00000001
/*
* CP0_Count resume monotonic nanoseconds
* The monotonic nanosecond time of the last set of COUNT_CTL.DC (master
* disable). Any reads and writes of Count related registers while
* COUNT_CTL.DC=1 will appear to occur at this time. When COUNT_CTL.DC is
* cleared again (master enable) any timer interrupts since this time will be
* emulated.
* Modifications to times in the future are rejected.
*/
#define KVM_REG_MIPS_COUNT_RESUME (KVM_REG_MIPS | KVM_REG_SIZE_U64 | \
0x20000 | 1)
/*
* CP0_Count rate in Hz
* Specifies the rate of the CP0_Count timer in Hz. Modifications occur without
* discontinuities in CP0_Count.
*/
#define KVM_REG_MIPS_COUNT_HZ (KVM_REG_MIPS | KVM_REG_SIZE_U64 | \
0x20000 | 2)
/*
* KVM MIPS specific structures and definitions
*
......
......@@ -545,7 +545,6 @@ struct kvm_get_htab_header {
#define KVM_REG_PPC_TCSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb1)
#define KVM_REG_PPC_PID (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb2)
#define KVM_REG_PPC_ACOP (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb3)
#define KVM_REG_PPC_WORT (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb4)
#define KVM_REG_PPC_VRSAVE (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb4)
#define KVM_REG_PPC_LPCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb5)
......@@ -555,6 +554,7 @@ struct kvm_get_htab_header {
#define KVM_REG_PPC_ARCH_COMPAT (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb7)
#define KVM_REG_PPC_DABRX (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb8)
#define KVM_REG_PPC_WORT (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb9)
/* Transactional Memory checkpointed state:
* This is all GPRs, all VSX regs and a subset of SPRs
......
......@@ -82,10 +82,16 @@ struct kvm_vcpu_arch_shared {
#define KVM_FEATURE_MAGIC_PAGE 1
/* Magic page flags from host to guest */
#define KVM_MAGIC_FEAT_SR (1 << 0)
/* MASn, ESR, PIR, and high SPRGs */
#define KVM_MAGIC_FEAT_MAS0_TO_SPRG7 (1 << 1)
/* Magic page flags from guest to host */
#define MAGIC_PAGE_FLAG_NOT_MAPPED_NX (1 << 0)
#endif /* __POWERPC_KVM_PARA_H__ */
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -58,8 +58,12 @@ struct target_revectored_struct {
*/
#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
#ifdef TARGET_WORDS_BIGENDIAN
#define UNAME_MACHINE "ppc64"
#else
#define UNAME_MACHINE "ppc64le"
#endif
#else
#define UNAME_MACHINE "ppc"
#endif
#define UNAME_MINIMUM_RELEASE "2.6.32"
......
此差异已折叠。
此差异已折叠。
文件已添加
此差异已折叠。
u-boot @ 2072e726
Subproject commit 2072e7262965bb48d7fffb1e283101e6ed8b21a8
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册