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 -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.19 (GNU/Linux) iQIcBAABAgAGBQJTntTgAAoJECszeR4D/txgvNoP/R9HooeweYnZYQxuTTxCIyPZ if1KRWj6S3jaZ74RwY7kjqYiBUKzNhqpA068v1QS/8ETjPc44V5RMKVOYoGeLNZz DiZ+BGIp6OSAW3zILFejdi2h7H86qESu7ZFSHZli7eUVg58JUVcnsrFrqMo5ojhY ICDbeDTitHkBESx7d93bUpecA535433FFylX1ueSj4FFeIpdhlCQsSZbal4FhxqY 74ra4phwAfHlh28K286ZCduLKih77V5dZlroT89apI2eammD+jvXeewvmYtflcQu j/0FScSVOAplf0wqlPYM0+JAqbaX9o8ZLfzrMV+80ODdDKSFyGKeMo/PrOKJPtpk EibFNt67nJ30yGhmVsylsQxHVsmWFumcomA0kDdGLmj4A6mqLWM/7w3PGB1pJTPS bMvMz6O3B/ebk3wXZaMklcjLCLxCBqdYDG0/h7d+gpBLwqnF1Qgi4vv7g+MeKWtf Z5qJvUMzaAK6LJbDqOIqYhLCtvv2eYHNqvvjkaSRD5SkRzWnzzmmB+3xfjkLllbM C9DmcQVL4mh7SL3ELjcX7NT4rC+TWRu/el1eAreMjZT8pUyAbjyOkNGbLMqthaM7 kzrSPc9QMzLmIJPrbH9unCuTf9NP5cUndtCL3kEAkl3FPm4kqiwVvh2WSeYCa0uw 1PvTu0HNT/5NcvOkq/5L =hi5L -----END PGP SIGNATURE----- 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: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
af44da87e9
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -28,3 +28,6 @@
|
||||||
[submodule "dtc"]
|
[submodule "dtc"]
|
||||||
path = dtc
|
path = dtc
|
||||||
url = git://git.qemu-project.org/dtc.git
|
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 notempty,$(TARGET_XML_FILES)) += gdbstub-xml.o
|
||||||
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.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
|
# Linux user emulator target
|
||||||
|
|
||||||
|
|
7
configure
vendored
7
configure
vendored
|
@ -4955,6 +4955,12 @@ case "$target_name" in
|
||||||
TARGET_ABI_DIR=ppc
|
TARGET_ABI_DIR=ppc
|
||||||
gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
|
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)
|
ppc64abi32)
|
||||||
TARGET_ARCH=ppc64
|
TARGET_ARCH=ppc64
|
||||||
TARGET_BASE_ARCH=ppc
|
TARGET_BASE_ARCH=ppc
|
||||||
|
@ -5222,6 +5228,7 @@ for bios_file in \
|
||||||
$source_path/pc-bios/*.dtb \
|
$source_path/pc-bios/*.dtb \
|
||||||
$source_path/pc-bios/*.img \
|
$source_path/pc-bios/*.img \
|
||||||
$source_path/pc-bios/openbios-* \
|
$source_path/pc-bios/openbios-* \
|
||||||
|
$source_path/pc-bios/u-boot.* \
|
||||||
$source_path/pc-bios/palcode-*
|
$source_path/pc-bios/palcode-*
|
||||||
do
|
do
|
||||||
FILES="$FILES pc-bios/`basename $bios_file`"
|
FILES="$FILES pc-bios/`basename $bios_file`"
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
# Default configuration for ppc-linux-user
|
# 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_MC146818RTC=y
|
||||||
CONFIG_ETSEC=y
|
CONFIG_ETSEC=y
|
||||||
CONFIG_ISA_TESTDEV=y
|
CONFIG_ISA_TESTDEV=y
|
||||||
|
CONFIG_LIBDECNUMBER=y
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
# Default configuration for ppc64-linux-user
|
# Default configuration for ppc64-linux-user
|
||||||
|
CONFIG_LIBDECNUMBER=y
|
||||||
|
|
|
@ -58,3 +58,4 @@ CONFIG_I82374=y
|
||||||
CONFIG_I8257=y
|
CONFIG_I8257=y
|
||||||
CONFIG_MC146818RTC=y
|
CONFIG_MC146818RTC=y
|
||||||
CONFIG_ISA_TESTDEV=y
|
CONFIG_ISA_TESTDEV=y
|
||||||
|
CONFIG_LIBDECNUMBER=y
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
# Default configuration for ppc64abi32-linux-user
|
# Default configuration for ppc64abi32-linux-user
|
||||||
|
CONFIG_LIBDECNUMBER=y
|
||||||
|
|
2
default-configs/ppc64le-linux-user.mak
Normal file
2
default-configs/ppc64le-linux-user.mak
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# Default configuration for ppc64le-linux-user
|
||||||
|
CONFIG_LIBDECNUMBER=y
|
|
@ -16,3 +16,4 @@ CONFIG_I8259=y
|
||||||
CONFIG_XILINX=y
|
CONFIG_XILINX=y
|
||||||
CONFIG_XILINX_ETHLITE=y
|
CONFIG_XILINX_ETHLITE=y
|
||||||
CONFIG_OPENPIC=y
|
CONFIG_OPENPIC=y
|
||||||
|
CONFIG_LIBDECNUMBER=y
|
||||||
|
|
17
disas.c
17
disas.c
|
@ -191,7 +191,8 @@ static int print_insn_od_target(bfd_vma pc, disassemble_info *info)
|
||||||
values:
|
values:
|
||||||
i386 - 1 means 16 bit code, 2 means 64 bit code
|
i386 - 1 means 16 bit code, 2 means 64 bit code
|
||||||
arm - bit 0 = thumb, bit 1 = reverse endian, bit 2 = A64
|
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
|
other targets - unused
|
||||||
*/
|
*/
|
||||||
void target_disas(FILE *out, CPUArchState *env, target_ulong code,
|
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;
|
s.info.mach = bfd_mach_sparc_v9b;
|
||||||
#endif
|
#endif
|
||||||
#elif defined(TARGET_PPC)
|
#elif defined(TARGET_PPC)
|
||||||
if (flags >> 16) {
|
if ((flags >> 16) & 1) {
|
||||||
s.info.endian = BFD_ENDIAN_LITTLE;
|
s.info.endian = BFD_ENDIAN_LITTLE;
|
||||||
}
|
}
|
||||||
if (flags & 0xFFFF) {
|
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;
|
s.info.mach = flags & 0xFFFF;
|
||||||
} else {
|
} else {
|
||||||
#ifdef TARGET_PPC64
|
#ifdef TARGET_PPC64
|
||||||
|
@ -444,6 +445,8 @@ monitor_fprintf(FILE *stream, const char *fmt, ...)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Disassembler for the monitor.
|
||||||
|
See target_disas for a description of flags. */
|
||||||
void monitor_disas(Monitor *mon, CPUArchState *env,
|
void monitor_disas(Monitor *mon, CPUArchState *env,
|
||||||
target_ulong pc, int nb_insn, int is_physical, int flags)
|
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;
|
s.info.mach = bfd_mach_sparc_v9b;
|
||||||
#endif
|
#endif
|
||||||
#elif defined(TARGET_PPC)
|
#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
|
#ifdef TARGET_PPC64
|
||||||
s.info.mach = bfd_mach_ppc64;
|
s.info.mach = bfd_mach_ppc64;
|
||||||
#else
|
#else
|
||||||
s.info.mach = bfd_mach_ppc;
|
s.info.mach = bfd_mach_ppc;
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
if ((flags >> 16) & 1) {
|
||||||
|
s.info.endian = BFD_ENDIAN_LITTLE;
|
||||||
|
}
|
||||||
print_insn = print_insn_ppc;
|
print_insn = print_insn_ppc;
|
||||||
#elif defined(TARGET_M68K)
|
#elif defined(TARGET_M68K)
|
||||||
print_insn = print_insn_m68k;
|
print_insn = print_insn_m68k;
|
||||||
|
|
225
dump.c
225
dump.c
|
@ -36,9 +36,9 @@
|
||||||
#define ELF_MACHINE_UNAME "Unknown"
|
#define ELF_MACHINE_UNAME "Unknown"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static uint16_t cpu_convert_to_target16(uint16_t val, int endian)
|
uint16_t cpu_to_dump16(DumpState *s, uint16_t val)
|
||||||
{
|
{
|
||||||
if (endian == ELFDATA2LSB) {
|
if (s->dump_info.d_endian == ELFDATA2LSB) {
|
||||||
val = cpu_to_le16(val);
|
val = cpu_to_le16(val);
|
||||||
} else {
|
} else {
|
||||||
val = cpu_to_be16(val);
|
val = cpu_to_be16(val);
|
||||||
|
@ -47,9 +47,9 @@ static uint16_t cpu_convert_to_target16(uint16_t val, int endian)
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t cpu_convert_to_target32(uint32_t val, int endian)
|
uint32_t cpu_to_dump32(DumpState *s, uint32_t val)
|
||||||
{
|
{
|
||||||
if (endian == ELFDATA2LSB) {
|
if (s->dump_info.d_endian == ELFDATA2LSB) {
|
||||||
val = cpu_to_le32(val);
|
val = cpu_to_le32(val);
|
||||||
} else {
|
} else {
|
||||||
val = cpu_to_be32(val);
|
val = cpu_to_be32(val);
|
||||||
|
@ -58,9 +58,9 @@ static uint32_t cpu_convert_to_target32(uint32_t val, int endian)
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t cpu_convert_to_target64(uint64_t val, int endian)
|
uint64_t cpu_to_dump64(DumpState *s, uint64_t val)
|
||||||
{
|
{
|
||||||
if (endian == ELFDATA2LSB) {
|
if (s->dump_info.d_endian == ELFDATA2LSB) {
|
||||||
val = cpu_to_le64(val);
|
val = cpu_to_le64(val);
|
||||||
} else {
|
} else {
|
||||||
val = cpu_to_be64(val);
|
val = cpu_to_be64(val);
|
||||||
|
@ -69,36 +69,6 @@ static uint64_t cpu_convert_to_target64(uint64_t val, int endian)
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
static int dump_cleanup(DumpState *s)
|
static int dump_cleanup(DumpState *s)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -137,29 +107,25 @@ static int write_elf64_header(DumpState *s)
|
||||||
{
|
{
|
||||||
Elf64_Ehdr elf_header;
|
Elf64_Ehdr elf_header;
|
||||||
int ret;
|
int ret;
|
||||||
int endian = s->dump_info.d_endian;
|
|
||||||
|
|
||||||
memset(&elf_header, 0, sizeof(Elf64_Ehdr));
|
memset(&elf_header, 0, sizeof(Elf64_Ehdr));
|
||||||
memcpy(&elf_header, ELFMAG, SELFMAG);
|
memcpy(&elf_header, ELFMAG, SELFMAG);
|
||||||
elf_header.e_ident[EI_CLASS] = ELFCLASS64;
|
elf_header.e_ident[EI_CLASS] = ELFCLASS64;
|
||||||
elf_header.e_ident[EI_DATA] = s->dump_info.d_endian;
|
elf_header.e_ident[EI_DATA] = s->dump_info.d_endian;
|
||||||
elf_header.e_ident[EI_VERSION] = EV_CURRENT;
|
elf_header.e_ident[EI_VERSION] = EV_CURRENT;
|
||||||
elf_header.e_type = cpu_convert_to_target16(ET_CORE, endian);
|
elf_header.e_type = cpu_to_dump16(s, ET_CORE);
|
||||||
elf_header.e_machine = cpu_convert_to_target16(s->dump_info.d_machine,
|
elf_header.e_machine = cpu_to_dump16(s, s->dump_info.d_machine);
|
||||||
endian);
|
elf_header.e_version = cpu_to_dump32(s, EV_CURRENT);
|
||||||
elf_header.e_version = cpu_convert_to_target32(EV_CURRENT, endian);
|
elf_header.e_ehsize = cpu_to_dump16(s, sizeof(elf_header));
|
||||||
elf_header.e_ehsize = cpu_convert_to_target16(sizeof(elf_header), endian);
|
elf_header.e_phoff = cpu_to_dump64(s, sizeof(Elf64_Ehdr));
|
||||||
elf_header.e_phoff = cpu_convert_to_target64(sizeof(Elf64_Ehdr), endian);
|
elf_header.e_phentsize = cpu_to_dump16(s, sizeof(Elf64_Phdr));
|
||||||
elf_header.e_phentsize = cpu_convert_to_target16(sizeof(Elf64_Phdr),
|
elf_header.e_phnum = cpu_to_dump16(s, s->phdr_num);
|
||||||
endian);
|
|
||||||
elf_header.e_phnum = cpu_convert_to_target16(s->phdr_num, endian);
|
|
||||||
if (s->have_section) {
|
if (s->have_section) {
|
||||||
uint64_t shoff = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) * s->sh_info;
|
uint64_t shoff = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) * s->sh_info;
|
||||||
|
|
||||||
elf_header.e_shoff = cpu_convert_to_target64(shoff, endian);
|
elf_header.e_shoff = cpu_to_dump64(s, shoff);
|
||||||
elf_header.e_shentsize = cpu_convert_to_target16(sizeof(Elf64_Shdr),
|
elf_header.e_shentsize = cpu_to_dump16(s, sizeof(Elf64_Shdr));
|
||||||
endian);
|
elf_header.e_shnum = cpu_to_dump16(s, 1);
|
||||||
elf_header.e_shnum = cpu_convert_to_target16(1, endian);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s);
|
ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s);
|
||||||
|
@ -175,29 +141,25 @@ static int write_elf32_header(DumpState *s)
|
||||||
{
|
{
|
||||||
Elf32_Ehdr elf_header;
|
Elf32_Ehdr elf_header;
|
||||||
int ret;
|
int ret;
|
||||||
int endian = s->dump_info.d_endian;
|
|
||||||
|
|
||||||
memset(&elf_header, 0, sizeof(Elf32_Ehdr));
|
memset(&elf_header, 0, sizeof(Elf32_Ehdr));
|
||||||
memcpy(&elf_header, ELFMAG, SELFMAG);
|
memcpy(&elf_header, ELFMAG, SELFMAG);
|
||||||
elf_header.e_ident[EI_CLASS] = ELFCLASS32;
|
elf_header.e_ident[EI_CLASS] = ELFCLASS32;
|
||||||
elf_header.e_ident[EI_DATA] = endian;
|
elf_header.e_ident[EI_DATA] = s->dump_info.d_endian;
|
||||||
elf_header.e_ident[EI_VERSION] = EV_CURRENT;
|
elf_header.e_ident[EI_VERSION] = EV_CURRENT;
|
||||||
elf_header.e_type = cpu_convert_to_target16(ET_CORE, endian);
|
elf_header.e_type = cpu_to_dump16(s, ET_CORE);
|
||||||
elf_header.e_machine = cpu_convert_to_target16(s->dump_info.d_machine,
|
elf_header.e_machine = cpu_to_dump16(s, s->dump_info.d_machine);
|
||||||
endian);
|
elf_header.e_version = cpu_to_dump32(s, EV_CURRENT);
|
||||||
elf_header.e_version = cpu_convert_to_target32(EV_CURRENT, endian);
|
elf_header.e_ehsize = cpu_to_dump16(s, sizeof(elf_header));
|
||||||
elf_header.e_ehsize = cpu_convert_to_target16(sizeof(elf_header), endian);
|
elf_header.e_phoff = cpu_to_dump32(s, sizeof(Elf32_Ehdr));
|
||||||
elf_header.e_phoff = cpu_convert_to_target32(sizeof(Elf32_Ehdr), endian);
|
elf_header.e_phentsize = cpu_to_dump16(s, sizeof(Elf32_Phdr));
|
||||||
elf_header.e_phentsize = cpu_convert_to_target16(sizeof(Elf32_Phdr),
|
elf_header.e_phnum = cpu_to_dump16(s, s->phdr_num);
|
||||||
endian);
|
|
||||||
elf_header.e_phnum = cpu_convert_to_target16(s->phdr_num, endian);
|
|
||||||
if (s->have_section) {
|
if (s->have_section) {
|
||||||
uint32_t shoff = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) * s->sh_info;
|
uint32_t shoff = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) * s->sh_info;
|
||||||
|
|
||||||
elf_header.e_shoff = cpu_convert_to_target32(shoff, endian);
|
elf_header.e_shoff = cpu_to_dump32(s, shoff);
|
||||||
elf_header.e_shentsize = cpu_convert_to_target16(sizeof(Elf32_Shdr),
|
elf_header.e_shentsize = cpu_to_dump16(s, sizeof(Elf32_Shdr));
|
||||||
endian);
|
elf_header.e_shnum = cpu_to_dump16(s, 1);
|
||||||
elf_header.e_shnum = cpu_convert_to_target16(1, endian);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s);
|
ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s);
|
||||||
|
@ -215,15 +177,14 @@ static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping,
|
||||||
{
|
{
|
||||||
Elf64_Phdr phdr;
|
Elf64_Phdr phdr;
|
||||||
int ret;
|
int ret;
|
||||||
int endian = s->dump_info.d_endian;
|
|
||||||
|
|
||||||
memset(&phdr, 0, sizeof(Elf64_Phdr));
|
memset(&phdr, 0, sizeof(Elf64_Phdr));
|
||||||
phdr.p_type = cpu_convert_to_target32(PT_LOAD, endian);
|
phdr.p_type = cpu_to_dump32(s, PT_LOAD);
|
||||||
phdr.p_offset = cpu_convert_to_target64(offset, endian);
|
phdr.p_offset = cpu_to_dump64(s, offset);
|
||||||
phdr.p_paddr = cpu_convert_to_target64(memory_mapping->phys_addr, endian);
|
phdr.p_paddr = cpu_to_dump64(s, memory_mapping->phys_addr);
|
||||||
phdr.p_filesz = cpu_convert_to_target64(filesz, endian);
|
phdr.p_filesz = cpu_to_dump64(s, filesz);
|
||||||
phdr.p_memsz = cpu_convert_to_target64(memory_mapping->length, endian);
|
phdr.p_memsz = cpu_to_dump64(s, memory_mapping->length);
|
||||||
phdr.p_vaddr = cpu_convert_to_target64(memory_mapping->virt_addr, endian);
|
phdr.p_vaddr = cpu_to_dump64(s, memory_mapping->virt_addr);
|
||||||
|
|
||||||
assert(memory_mapping->length >= filesz);
|
assert(memory_mapping->length >= filesz);
|
||||||
|
|
||||||
|
@ -242,15 +203,14 @@ static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping,
|
||||||
{
|
{
|
||||||
Elf32_Phdr phdr;
|
Elf32_Phdr phdr;
|
||||||
int ret;
|
int ret;
|
||||||
int endian = s->dump_info.d_endian;
|
|
||||||
|
|
||||||
memset(&phdr, 0, sizeof(Elf32_Phdr));
|
memset(&phdr, 0, sizeof(Elf32_Phdr));
|
||||||
phdr.p_type = cpu_convert_to_target32(PT_LOAD, endian);
|
phdr.p_type = cpu_to_dump32(s, PT_LOAD);
|
||||||
phdr.p_offset = cpu_convert_to_target32(offset, endian);
|
phdr.p_offset = cpu_to_dump32(s, offset);
|
||||||
phdr.p_paddr = cpu_convert_to_target32(memory_mapping->phys_addr, endian);
|
phdr.p_paddr = cpu_to_dump32(s, memory_mapping->phys_addr);
|
||||||
phdr.p_filesz = cpu_convert_to_target32(filesz, endian);
|
phdr.p_filesz = cpu_to_dump32(s, filesz);
|
||||||
phdr.p_memsz = cpu_convert_to_target32(memory_mapping->length, endian);
|
phdr.p_memsz = cpu_to_dump32(s, memory_mapping->length);
|
||||||
phdr.p_vaddr = cpu_convert_to_target32(memory_mapping->virt_addr, endian);
|
phdr.p_vaddr = cpu_to_dump32(s, memory_mapping->virt_addr);
|
||||||
|
|
||||||
assert(memory_mapping->length >= filesz);
|
assert(memory_mapping->length >= filesz);
|
||||||
|
|
||||||
|
@ -266,16 +226,15 @@ static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping,
|
||||||
static int write_elf64_note(DumpState *s)
|
static int write_elf64_note(DumpState *s)
|
||||||
{
|
{
|
||||||
Elf64_Phdr phdr;
|
Elf64_Phdr phdr;
|
||||||
int endian = s->dump_info.d_endian;
|
|
||||||
hwaddr begin = s->memory_offset - s->note_size;
|
hwaddr begin = s->memory_offset - s->note_size;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
memset(&phdr, 0, sizeof(Elf64_Phdr));
|
memset(&phdr, 0, sizeof(Elf64_Phdr));
|
||||||
phdr.p_type = cpu_convert_to_target32(PT_NOTE, endian);
|
phdr.p_type = cpu_to_dump32(s, PT_NOTE);
|
||||||
phdr.p_offset = cpu_convert_to_target64(begin, endian);
|
phdr.p_offset = cpu_to_dump64(s, begin);
|
||||||
phdr.p_paddr = 0;
|
phdr.p_paddr = 0;
|
||||||
phdr.p_filesz = cpu_convert_to_target64(s->note_size, endian);
|
phdr.p_filesz = cpu_to_dump64(s, s->note_size);
|
||||||
phdr.p_memsz = cpu_convert_to_target64(s->note_size, endian);
|
phdr.p_memsz = cpu_to_dump64(s, s->note_size);
|
||||||
phdr.p_vaddr = 0;
|
phdr.p_vaddr = 0;
|
||||||
|
|
||||||
ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s);
|
ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s);
|
||||||
|
@ -322,15 +281,14 @@ static int write_elf32_note(DumpState *s)
|
||||||
{
|
{
|
||||||
hwaddr begin = s->memory_offset - s->note_size;
|
hwaddr begin = s->memory_offset - s->note_size;
|
||||||
Elf32_Phdr phdr;
|
Elf32_Phdr phdr;
|
||||||
int endian = s->dump_info.d_endian;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
memset(&phdr, 0, sizeof(Elf32_Phdr));
|
memset(&phdr, 0, sizeof(Elf32_Phdr));
|
||||||
phdr.p_type = cpu_convert_to_target32(PT_NOTE, endian);
|
phdr.p_type = cpu_to_dump32(s, PT_NOTE);
|
||||||
phdr.p_offset = cpu_convert_to_target32(begin, endian);
|
phdr.p_offset = cpu_to_dump32(s, begin);
|
||||||
phdr.p_paddr = 0;
|
phdr.p_paddr = 0;
|
||||||
phdr.p_filesz = cpu_convert_to_target32(s->note_size, endian);
|
phdr.p_filesz = cpu_to_dump32(s, s->note_size);
|
||||||
phdr.p_memsz = cpu_convert_to_target32(s->note_size, endian);
|
phdr.p_memsz = cpu_to_dump32(s, s->note_size);
|
||||||
phdr.p_vaddr = 0;
|
phdr.p_vaddr = 0;
|
||||||
|
|
||||||
ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s);
|
ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s);
|
||||||
|
@ -372,7 +330,6 @@ static int write_elf_section(DumpState *s, int type)
|
||||||
{
|
{
|
||||||
Elf32_Shdr shdr32;
|
Elf32_Shdr shdr32;
|
||||||
Elf64_Shdr shdr64;
|
Elf64_Shdr shdr64;
|
||||||
int endian = s->dump_info.d_endian;
|
|
||||||
int shdr_size;
|
int shdr_size;
|
||||||
void *shdr;
|
void *shdr;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -380,12 +337,12 @@ static int write_elf_section(DumpState *s, int type)
|
||||||
if (type == 0) {
|
if (type == 0) {
|
||||||
shdr_size = sizeof(Elf32_Shdr);
|
shdr_size = sizeof(Elf32_Shdr);
|
||||||
memset(&shdr32, 0, shdr_size);
|
memset(&shdr32, 0, shdr_size);
|
||||||
shdr32.sh_info = cpu_convert_to_target32(s->sh_info, endian);
|
shdr32.sh_info = cpu_to_dump32(s, s->sh_info);
|
||||||
shdr = &shdr32;
|
shdr = &shdr32;
|
||||||
} else {
|
} else {
|
||||||
shdr_size = sizeof(Elf64_Shdr);
|
shdr_size = sizeof(Elf64_Shdr);
|
||||||
memset(&shdr64, 0, shdr_size);
|
memset(&shdr64, 0, shdr_size);
|
||||||
shdr64.sh_info = cpu_convert_to_target32(s->sh_info, endian);
|
shdr64.sh_info = cpu_to_dump32(s, s->sh_info);
|
||||||
shdr = &shdr64;
|
shdr = &shdr64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -791,7 +748,6 @@ static int create_header32(DumpState *s)
|
||||||
DiskDumpHeader32 *dh = NULL;
|
DiskDumpHeader32 *dh = NULL;
|
||||||
KdumpSubHeader32 *kh = NULL;
|
KdumpSubHeader32 *kh = NULL;
|
||||||
size_t size;
|
size_t size;
|
||||||
int endian = s->dump_info.d_endian;
|
|
||||||
uint32_t block_size;
|
uint32_t block_size;
|
||||||
uint32_t sub_hdr_size;
|
uint32_t sub_hdr_size;
|
||||||
uint32_t bitmap_blocks;
|
uint32_t bitmap_blocks;
|
||||||
|
@ -803,18 +759,17 @@ static int create_header32(DumpState *s)
|
||||||
dh = g_malloc0(size);
|
dh = g_malloc0(size);
|
||||||
|
|
||||||
strncpy(dh->signature, KDUMP_SIGNATURE, strlen(KDUMP_SIGNATURE));
|
strncpy(dh->signature, KDUMP_SIGNATURE, strlen(KDUMP_SIGNATURE));
|
||||||
dh->header_version = cpu_convert_to_target32(6, endian);
|
dh->header_version = cpu_to_dump32(s, 6);
|
||||||
block_size = TARGET_PAGE_SIZE;
|
block_size = TARGET_PAGE_SIZE;
|
||||||
dh->block_size = cpu_convert_to_target32(block_size, endian);
|
dh->block_size = cpu_to_dump32(s, block_size);
|
||||||
sub_hdr_size = sizeof(struct KdumpSubHeader32) + s->note_size;
|
sub_hdr_size = sizeof(struct KdumpSubHeader32) + s->note_size;
|
||||||
sub_hdr_size = DIV_ROUND_UP(sub_hdr_size, block_size);
|
sub_hdr_size = DIV_ROUND_UP(sub_hdr_size, block_size);
|
||||||
dh->sub_hdr_size = cpu_convert_to_target32(sub_hdr_size, endian);
|
dh->sub_hdr_size = cpu_to_dump32(s, sub_hdr_size);
|
||||||
/* dh->max_mapnr may be truncated, full 64bit is in kh.max_mapnr_64 */
|
/* dh->max_mapnr may be truncated, full 64bit is in kh.max_mapnr_64 */
|
||||||
dh->max_mapnr = cpu_convert_to_target32(MIN(s->max_mapnr, UINT_MAX),
|
dh->max_mapnr = cpu_to_dump32(s, MIN(s->max_mapnr, UINT_MAX));
|
||||||
endian);
|
dh->nr_cpus = cpu_to_dump32(s, s->nr_cpus);
|
||||||
dh->nr_cpus = cpu_convert_to_target32(s->nr_cpus, endian);
|
|
||||||
bitmap_blocks = DIV_ROUND_UP(s->len_dump_bitmap, block_size) * 2;
|
bitmap_blocks = DIV_ROUND_UP(s->len_dump_bitmap, block_size) * 2;
|
||||||
dh->bitmap_blocks = cpu_convert_to_target32(bitmap_blocks, endian);
|
dh->bitmap_blocks = cpu_to_dump32(s, bitmap_blocks);
|
||||||
strncpy(dh->utsname.machine, ELF_MACHINE_UNAME, sizeof(dh->utsname.machine));
|
strncpy(dh->utsname.machine, ELF_MACHINE_UNAME, sizeof(dh->utsname.machine));
|
||||||
|
|
||||||
if (s->flag_compress & DUMP_DH_COMPRESSED_ZLIB) {
|
if (s->flag_compress & DUMP_DH_COMPRESSED_ZLIB) {
|
||||||
|
@ -830,7 +785,7 @@ static int create_header32(DumpState *s)
|
||||||
status |= DUMP_DH_COMPRESSED_SNAPPY;
|
status |= DUMP_DH_COMPRESSED_SNAPPY;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
dh->status = cpu_convert_to_target32(status, endian);
|
dh->status = cpu_to_dump32(s, status);
|
||||||
|
|
||||||
if (write_buffer(s->fd, 0, dh, size) < 0) {
|
if (write_buffer(s->fd, 0, dh, size) < 0) {
|
||||||
dump_error(s, "dump: failed to write disk dump header.\n");
|
dump_error(s, "dump: failed to write disk dump header.\n");
|
||||||
|
@ -843,13 +798,13 @@ static int create_header32(DumpState *s)
|
||||||
kh = g_malloc0(size);
|
kh = g_malloc0(size);
|
||||||
|
|
||||||
/* 64bit max_mapnr_64 */
|
/* 64bit max_mapnr_64 */
|
||||||
kh->max_mapnr_64 = cpu_convert_to_target64(s->max_mapnr, endian);
|
kh->max_mapnr_64 = cpu_to_dump64(s, s->max_mapnr);
|
||||||
kh->phys_base = cpu_convert_to_target32(PHYS_BASE, endian);
|
kh->phys_base = cpu_to_dump32(s, PHYS_BASE);
|
||||||
kh->dump_level = cpu_convert_to_target32(DUMP_LEVEL, endian);
|
kh->dump_level = cpu_to_dump32(s, DUMP_LEVEL);
|
||||||
|
|
||||||
offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size;
|
offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size;
|
||||||
kh->offset_note = cpu_convert_to_target64(offset_note, endian);
|
kh->offset_note = cpu_to_dump64(s, offset_note);
|
||||||
kh->note_size = cpu_convert_to_target32(s->note_size, endian);
|
kh->note_size = cpu_to_dump32(s, s->note_size);
|
||||||
|
|
||||||
if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS *
|
if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS *
|
||||||
block_size, kh, size) < 0) {
|
block_size, kh, size) < 0) {
|
||||||
|
@ -898,7 +853,6 @@ static int create_header64(DumpState *s)
|
||||||
DiskDumpHeader64 *dh = NULL;
|
DiskDumpHeader64 *dh = NULL;
|
||||||
KdumpSubHeader64 *kh = NULL;
|
KdumpSubHeader64 *kh = NULL;
|
||||||
size_t size;
|
size_t size;
|
||||||
int endian = s->dump_info.d_endian;
|
|
||||||
uint32_t block_size;
|
uint32_t block_size;
|
||||||
uint32_t sub_hdr_size;
|
uint32_t sub_hdr_size;
|
||||||
uint32_t bitmap_blocks;
|
uint32_t bitmap_blocks;
|
||||||
|
@ -910,18 +864,17 @@ static int create_header64(DumpState *s)
|
||||||
dh = g_malloc0(size);
|
dh = g_malloc0(size);
|
||||||
|
|
||||||
strncpy(dh->signature, KDUMP_SIGNATURE, strlen(KDUMP_SIGNATURE));
|
strncpy(dh->signature, KDUMP_SIGNATURE, strlen(KDUMP_SIGNATURE));
|
||||||
dh->header_version = cpu_convert_to_target32(6, endian);
|
dh->header_version = cpu_to_dump32(s, 6);
|
||||||
block_size = TARGET_PAGE_SIZE;
|
block_size = TARGET_PAGE_SIZE;
|
||||||
dh->block_size = cpu_convert_to_target32(block_size, endian);
|
dh->block_size = cpu_to_dump32(s, block_size);
|
||||||
sub_hdr_size = sizeof(struct KdumpSubHeader64) + s->note_size;
|
sub_hdr_size = sizeof(struct KdumpSubHeader64) + s->note_size;
|
||||||
sub_hdr_size = DIV_ROUND_UP(sub_hdr_size, block_size);
|
sub_hdr_size = DIV_ROUND_UP(sub_hdr_size, block_size);
|
||||||
dh->sub_hdr_size = cpu_convert_to_target32(sub_hdr_size, endian);
|
dh->sub_hdr_size = cpu_to_dump32(s, sub_hdr_size);
|
||||||
/* dh->max_mapnr may be truncated, full 64bit is in kh.max_mapnr_64 */
|
/* dh->max_mapnr may be truncated, full 64bit is in kh.max_mapnr_64 */
|
||||||
dh->max_mapnr = cpu_convert_to_target32(MIN(s->max_mapnr, UINT_MAX),
|
dh->max_mapnr = cpu_to_dump32(s, MIN(s->max_mapnr, UINT_MAX));
|
||||||
endian);
|
dh->nr_cpus = cpu_to_dump32(s, s->nr_cpus);
|
||||||
dh->nr_cpus = cpu_convert_to_target32(s->nr_cpus, endian);
|
|
||||||
bitmap_blocks = DIV_ROUND_UP(s->len_dump_bitmap, block_size) * 2;
|
bitmap_blocks = DIV_ROUND_UP(s->len_dump_bitmap, block_size) * 2;
|
||||||
dh->bitmap_blocks = cpu_convert_to_target32(bitmap_blocks, endian);
|
dh->bitmap_blocks = cpu_to_dump32(s, bitmap_blocks);
|
||||||
strncpy(dh->utsname.machine, ELF_MACHINE_UNAME, sizeof(dh->utsname.machine));
|
strncpy(dh->utsname.machine, ELF_MACHINE_UNAME, sizeof(dh->utsname.machine));
|
||||||
|
|
||||||
if (s->flag_compress & DUMP_DH_COMPRESSED_ZLIB) {
|
if (s->flag_compress & DUMP_DH_COMPRESSED_ZLIB) {
|
||||||
|
@ -937,7 +890,7 @@ static int create_header64(DumpState *s)
|
||||||
status |= DUMP_DH_COMPRESSED_SNAPPY;
|
status |= DUMP_DH_COMPRESSED_SNAPPY;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
dh->status = cpu_convert_to_target32(status, endian);
|
dh->status = cpu_to_dump32(s, status);
|
||||||
|
|
||||||
if (write_buffer(s->fd, 0, dh, size) < 0) {
|
if (write_buffer(s->fd, 0, dh, size) < 0) {
|
||||||
dump_error(s, "dump: failed to write disk dump header.\n");
|
dump_error(s, "dump: failed to write disk dump header.\n");
|
||||||
|
@ -950,13 +903,13 @@ static int create_header64(DumpState *s)
|
||||||
kh = g_malloc0(size);
|
kh = g_malloc0(size);
|
||||||
|
|
||||||
/* 64bit max_mapnr_64 */
|
/* 64bit max_mapnr_64 */
|
||||||
kh->max_mapnr_64 = cpu_convert_to_target64(s->max_mapnr, endian);
|
kh->max_mapnr_64 = cpu_to_dump64(s, s->max_mapnr);
|
||||||
kh->phys_base = cpu_convert_to_target64(PHYS_BASE, endian);
|
kh->phys_base = cpu_to_dump64(s, PHYS_BASE);
|
||||||
kh->dump_level = cpu_convert_to_target32(DUMP_LEVEL, endian);
|
kh->dump_level = cpu_to_dump32(s, DUMP_LEVEL);
|
||||||
|
|
||||||
offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size;
|
offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size;
|
||||||
kh->offset_note = cpu_convert_to_target64(offset_note, endian);
|
kh->offset_note = cpu_to_dump64(s, offset_note);
|
||||||
kh->note_size = cpu_convert_to_target64(s->note_size, endian);
|
kh->note_size = cpu_to_dump64(s, s->note_size);
|
||||||
|
|
||||||
if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS *
|
if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS *
|
||||||
block_size, kh, size) < 0) {
|
block_size, kh, size) < 0) {
|
||||||
|
@ -1260,7 +1213,6 @@ static int write_dump_pages(DumpState *s)
|
||||||
off_t offset_desc, offset_data;
|
off_t offset_desc, offset_data;
|
||||||
PageDescriptor pd, pd_zero;
|
PageDescriptor pd, pd_zero;
|
||||||
uint8_t *buf;
|
uint8_t *buf;
|
||||||
int endian = s->dump_info.d_endian;
|
|
||||||
GuestPhysBlock *block_iter = NULL;
|
GuestPhysBlock *block_iter = NULL;
|
||||||
uint64_t pfn_iter;
|
uint64_t pfn_iter;
|
||||||
|
|
||||||
|
@ -1285,10 +1237,10 @@ static int write_dump_pages(DumpState *s)
|
||||||
* init zero page's page_desc and page_data, because every zero page
|
* init zero page's page_desc and page_data, because every zero page
|
||||||
* uses the same page_data
|
* uses the same page_data
|
||||||
*/
|
*/
|
||||||
pd_zero.size = cpu_convert_to_target32(TARGET_PAGE_SIZE, endian);
|
pd_zero.size = cpu_to_dump32(s, TARGET_PAGE_SIZE);
|
||||||
pd_zero.flags = cpu_convert_to_target32(0, endian);
|
pd_zero.flags = cpu_to_dump32(s, 0);
|
||||||
pd_zero.offset = cpu_convert_to_target64(offset_data, endian);
|
pd_zero.offset = cpu_to_dump64(s, offset_data);
|
||||||
pd_zero.page_flags = cpu_convert_to_target64(0, endian);
|
pd_zero.page_flags = cpu_to_dump64(s, 0);
|
||||||
buf = g_malloc0(TARGET_PAGE_SIZE);
|
buf = g_malloc0(TARGET_PAGE_SIZE);
|
||||||
ret = write_cache(&page_data, buf, TARGET_PAGE_SIZE, false);
|
ret = write_cache(&page_data, buf, TARGET_PAGE_SIZE, false);
|
||||||
g_free(buf);
|
g_free(buf);
|
||||||
|
@ -1329,9 +1281,8 @@ static int write_dump_pages(DumpState *s)
|
||||||
(compress2(buf_out, (uLongf *)&size_out, buf,
|
(compress2(buf_out, (uLongf *)&size_out, buf,
|
||||||
TARGET_PAGE_SIZE, Z_BEST_SPEED) == Z_OK) &&
|
TARGET_PAGE_SIZE, Z_BEST_SPEED) == Z_OK) &&
|
||||||
(size_out < TARGET_PAGE_SIZE)) {
|
(size_out < TARGET_PAGE_SIZE)) {
|
||||||
pd.flags = cpu_convert_to_target32(DUMP_DH_COMPRESSED_ZLIB,
|
pd.flags = cpu_to_dump32(s, DUMP_DH_COMPRESSED_ZLIB);
|
||||||
endian);
|
pd.size = cpu_to_dump32(s, size_out);
|
||||||
pd.size = cpu_convert_to_target32(size_out, endian);
|
|
||||||
|
|
||||||
ret = write_cache(&page_data, buf_out, size_out, false);
|
ret = write_cache(&page_data, buf_out, size_out, false);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -1343,9 +1294,8 @@ static int write_dump_pages(DumpState *s)
|
||||||
(lzo1x_1_compress(buf, TARGET_PAGE_SIZE, buf_out,
|
(lzo1x_1_compress(buf, TARGET_PAGE_SIZE, buf_out,
|
||||||
(lzo_uint *)&size_out, wrkmem) == LZO_E_OK) &&
|
(lzo_uint *)&size_out, wrkmem) == LZO_E_OK) &&
|
||||||
(size_out < TARGET_PAGE_SIZE)) {
|
(size_out < TARGET_PAGE_SIZE)) {
|
||||||
pd.flags = cpu_convert_to_target32(DUMP_DH_COMPRESSED_LZO,
|
pd.flags = cpu_to_dump32(s, DUMP_DH_COMPRESSED_LZO);
|
||||||
endian);
|
pd.size = cpu_to_dump32(s, size_out);
|
||||||
pd.size = cpu_convert_to_target32(size_out, endian);
|
|
||||||
|
|
||||||
ret = write_cache(&page_data, buf_out, size_out, false);
|
ret = write_cache(&page_data, buf_out, size_out, false);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -1358,9 +1308,8 @@ static int write_dump_pages(DumpState *s)
|
||||||
(snappy_compress((char *)buf, TARGET_PAGE_SIZE,
|
(snappy_compress((char *)buf, TARGET_PAGE_SIZE,
|
||||||
(char *)buf_out, &size_out) == SNAPPY_OK) &&
|
(char *)buf_out, &size_out) == SNAPPY_OK) &&
|
||||||
(size_out < TARGET_PAGE_SIZE)) {
|
(size_out < TARGET_PAGE_SIZE)) {
|
||||||
pd.flags = cpu_convert_to_target32(
|
pd.flags = cpu_to_dump32(s, DUMP_DH_COMPRESSED_SNAPPY);
|
||||||
DUMP_DH_COMPRESSED_SNAPPY, endian);
|
pd.size = cpu_to_dump32(s, size_out);
|
||||||
pd.size = cpu_convert_to_target32(size_out, endian);
|
|
||||||
|
|
||||||
ret = write_cache(&page_data, buf_out, size_out, false);
|
ret = write_cache(&page_data, buf_out, size_out, false);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -1373,9 +1322,9 @@ static int write_dump_pages(DumpState *s)
|
||||||
* fall back to save in plaintext, size_out should be
|
* fall back to save in plaintext, size_out should be
|
||||||
* assigned TARGET_PAGE_SIZE
|
* assigned TARGET_PAGE_SIZE
|
||||||
*/
|
*/
|
||||||
pd.flags = cpu_convert_to_target32(0, endian);
|
pd.flags = cpu_to_dump32(s, 0);
|
||||||
size_out = TARGET_PAGE_SIZE;
|
size_out = TARGET_PAGE_SIZE;
|
||||||
pd.size = cpu_convert_to_target32(size_out, endian);
|
pd.size = cpu_to_dump32(s, size_out);
|
||||||
|
|
||||||
ret = write_cache(&page_data, buf, TARGET_PAGE_SIZE, false);
|
ret = write_cache(&page_data, buf, TARGET_PAGE_SIZE, false);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -1385,8 +1334,8 @@ static int write_dump_pages(DumpState *s)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get and write page desc here */
|
/* get and write page desc here */
|
||||||
pd.page_flags = cpu_convert_to_target64(0, endian);
|
pd.page_flags = cpu_to_dump64(s, 0);
|
||||||
pd.offset = cpu_convert_to_target64(offset_data, endian);
|
pd.offset = cpu_to_dump64(s, offset_data);
|
||||||
offset_data += size_out;
|
offset_data += size_out;
|
||||||
|
|
||||||
ret = write_cache(&page_desc, &pd, sizeof(PageDescriptor), false);
|
ret = write_cache(&page_desc, &pd, sizeof(PageDescriptor), false);
|
||||||
|
|
|
@ -193,6 +193,11 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (--io->requests) {
|
||||||
|
/* More requests still in flight */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!m->dma_active) {
|
if (!m->dma_active) {
|
||||||
MACIO_DPRINTF("waiting for data (%#x - %#x - %x)\n",
|
MACIO_DPRINTF("waiting for data (%#x - %#x - %x)\n",
|
||||||
s->nsector, io->len, s->status);
|
s->nsector, io->len, s->status);
|
||||||
|
@ -212,6 +217,13 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
|
||||||
s->nsector -= n;
|
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 "
|
MACIO_DPRINTF("remainder: %d io->len: %d nsector: %d "
|
||||||
"sector_num: %" PRId64 "\n",
|
"sector_num: %" PRId64 "\n",
|
||||||
io->remainder_len, io->len, s->nsector, sector_num);
|
io->remainder_len, io->len, s->nsector, sector_num);
|
||||||
|
@ -229,7 +241,6 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
|
||||||
break;
|
break;
|
||||||
case IDE_DMA_WRITE:
|
case IDE_DMA_WRITE:
|
||||||
cpu_physical_memory_read(io->addr, p, remainder_len);
|
cpu_physical_memory_read(io->addr, p, remainder_len);
|
||||||
bdrv_write(s->bs, sector_num - 1, io->remainder, 1);
|
|
||||||
break;
|
break;
|
||||||
case IDE_DMA_TRIM:
|
case IDE_DMA_TRIM:
|
||||||
break;
|
break;
|
||||||
|
@ -237,6 +248,15 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
|
||||||
io->addr += remainder_len;
|
io->addr += remainder_len;
|
||||||
io->len -= remainder_len;
|
io->len -= remainder_len;
|
||||||
io->remainder_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) {
|
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) {
|
switch (s->dma_cmd) {
|
||||||
case IDE_DMA_READ:
|
case IDE_DMA_READ:
|
||||||
bdrv_read(s->bs, sector_num + nsector, io->remainder, 1);
|
io->requests++;
|
||||||
cpu_physical_memory_write(io->addr + io->len - unaligned,
|
io->finish_addr = io->addr + io->len - unaligned;
|
||||||
io->remainder, 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;
|
break;
|
||||||
case IDE_DMA_WRITE:
|
case IDE_DMA_WRITE:
|
||||||
/* cache the contents in our io struct */
|
/* cache the contents in our io struct */
|
||||||
cpu_physical_memory_read(io->addr + io->len - unaligned,
|
cpu_physical_memory_read(io->addr + io->len - unaligned,
|
||||||
io->remainder, unaligned);
|
io->remainder + io->remainder_len,
|
||||||
|
unaligned);
|
||||||
break;
|
break;
|
||||||
case IDE_DMA_TRIM:
|
case IDE_DMA_TRIM:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
io->len -= unaligned;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MACIO_DPRINTF("io->len = %#x\n", io->len);
|
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;
|
io->remainder_len = (0x200 - unaligned) & 0x1ff;
|
||||||
MACIO_DPRINTF("set remainder to: %d\n", io->remainder_len);
|
MACIO_DPRINTF("set remainder to: %d\n", io->remainder_len);
|
||||||
|
|
||||||
/* We would read no data from the block layer, thus not get a callback.
|
/* Only subsector reads happening */
|
||||||
Just fake completion manually. */
|
|
||||||
if (!io->len) {
|
if (!io->len) {
|
||||||
pmac_ide_transfer_cb(opaque, 0);
|
if (!io->requests) {
|
||||||
|
io->requests++;
|
||||||
|
pmac_ide_transfer_cb(opaque, ret);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,6 +346,8 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
|
||||||
DMA_DIRECTION_TO_DEVICE);
|
DMA_DIRECTION_TO_DEVICE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
io->requests++;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
@ -337,6 +366,27 @@ static void pmac_ide_transfer(DBDMA_io *io)
|
||||||
|
|
||||||
s->io_buffer_size = 0;
|
s->io_buffer_size = 0;
|
||||||
if (s->drive_kind == IDE_CD) {
|
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);
|
bdrv_acct_start(s->bs, &s->acct, io->len, BDRV_ACCT_READ);
|
||||||
pmac_ide_atapi_transfer_cb(io, 0);
|
pmac_ide_atapi_transfer_cb(io, 0);
|
||||||
return;
|
return;
|
||||||
|
@ -353,6 +403,7 @@ static void pmac_ide_transfer(DBDMA_io *io)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
io->requests++;
|
||||||
pmac_ide_transfer_cb(io, 0);
|
pmac_ide_transfer_cb(io, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -192,6 +192,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
|
||||||
int idx);
|
int idx);
|
||||||
static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
|
static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
|
||||||
uint32_t val, int idx);
|
uint32_t val, int idx);
|
||||||
|
static void openpic_reset(DeviceState *d);
|
||||||
|
|
||||||
typedef enum IRQType {
|
typedef enum IRQType {
|
||||||
IRQ_TYPE_NORMAL = 0,
|
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)
|
static inline uint32_t read_IRQreg_idr(OpenPICState *opp, int n_IRQ)
|
||||||
{
|
{
|
||||||
return opp->src[n_IRQ].idr;
|
return opp->src[n_IRQ].idr;
|
||||||
|
@ -1461,6 +1413,55 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id)
|
||||||
return 0;
|
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 {
|
typedef struct MemReg {
|
||||||
const char *name;
|
const char *name;
|
||||||
MemoryRegionOps const *ops;
|
MemoryRegionOps const *ops;
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
#include "sysemu/kvm.h"
|
#include "sysemu/kvm.h"
|
||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
|
|
||||||
|
#define GCR_RESET 0x80000000
|
||||||
|
|
||||||
#define KVM_OPENPIC(obj) \
|
#define KVM_OPENPIC(obj) \
|
||||||
OBJECT_CHECK(KVMOpenPICState, (obj), TYPE_KVM_OPENPIC)
|
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);
|
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,
|
static void kvm_openpic_write(void *opaque, hwaddr addr, uint64_t val,
|
||||||
unsigned size)
|
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)
|
static uint64_t kvm_openpic_read(void *opaque, hwaddr addr, unsigned size)
|
||||||
{
|
{
|
||||||
KVMOpenPICState *opp = opaque;
|
KVMOpenPICState *opp = opaque;
|
||||||
|
|
|
@ -748,9 +748,15 @@ static void dbdma_reset(void *opaque)
|
||||||
void* DBDMA_init (MemoryRegion **dbdma_mem)
|
void* DBDMA_init (MemoryRegion **dbdma_mem)
|
||||||
{
|
{
|
||||||
DBDMAState *s;
|
DBDMAState *s;
|
||||||
|
int i;
|
||||||
|
|
||||||
s = g_malloc0(sizeof(DBDMAState));
|
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);
|
memory_region_init_io(&s->mem, NULL, &dbdma_ops, s, "dbdma", 0x1000);
|
||||||
*dbdma_mem = &s->mem;
|
*dbdma_mem = &s->mem;
|
||||||
vmstate_register(NULL, -1, &vmstate_dbdma, s);
|
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 = {
|
static const MemoryRegionOps timer_ops = {
|
||||||
.read = timer_read,
|
.read = timer_read,
|
||||||
.write = timer_write,
|
.write = timer_write,
|
||||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int macio_newworld_initfn(PCIDevice *d)
|
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)
|
if ((flags & IEVENT_RXB && etsec->regs[IMASK].value & IMASK_RXBEN)
|
||||||
|| (flags & IEVENT_RXF && etsec->regs[IMASK].value & IMASK_RXFEN)) {
|
|| (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__);
|
RING_DEBUG("%s Raise Rx IRQ\n", __func__);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ typedef struct sPAPRNVRAM {
|
||||||
|
|
||||||
#define MIN_NVRAM_SIZE 8192
|
#define MIN_NVRAM_SIZE 8192
|
||||||
#define DEFAULT_NVRAM_SIZE 65536
|
#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,
|
static void rtas_nvram_fetch(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||||
uint32_t token, uint32_t nargs,
|
uint32_t token, uint32_t nargs,
|
||||||
|
|
|
@ -87,8 +87,10 @@ struct PPCE500PCIState {
|
||||||
struct pci_outbound pob[PPCE500_PCI_NR_POBS];
|
struct pci_outbound pob[PPCE500_PCI_NR_POBS];
|
||||||
struct pci_inbound pib[PPCE500_PCI_NR_PIBS];
|
struct pci_inbound pib[PPCE500_PCI_NR_PIBS];
|
||||||
uint32_t gasket_time;
|
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_slot;
|
||||||
|
uint32_t first_pin_irq;
|
||||||
/* mmio maps */
|
/* mmio maps */
|
||||||
MemoryRegion container;
|
MemoryRegion container;
|
||||||
MemoryRegion iomem;
|
MemoryRegion iomem;
|
||||||
|
@ -252,26 +254,39 @@ static const MemoryRegionOps e500_pci_reg_ops = {
|
||||||
.endianness = DEVICE_BIG_ENDIAN,
|
.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 devno = pci_dev->devfn >> 3;
|
||||||
int ret;
|
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_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;
|
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 = {
|
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_STRUCT_ARRAY(pob, PPCE500PCIState, PPCE500_PCI_NR_POBS, 1,
|
||||||
vmstate_pci_outbound, struct pci_outbound),
|
vmstate_pci_outbound, struct pci_outbound),
|
||||||
VMSTATE_STRUCT_ARRAY(pib, PPCE500PCIState, PPCE500_PCI_NR_PIBS, 1,
|
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_UINT32(gasket_time, PPCE500PCIState),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
}
|
}
|
||||||
|
@ -349,10 +364,14 @@ static int e500_pcihost_initfn(SysBusDevice *dev)
|
||||||
sysbus_init_irq(dev, &s->irq[i]);
|
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);
|
memory_region_init(&s->pio, OBJECT(s), "pci-pio", PCIE500_PCI_IOLEN);
|
||||||
|
|
||||||
b = pci_register_bus(DEVICE(dev), NULL, mpc85xx_pci_set_irq,
|
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);
|
&s->pio, PCI_DEVFN(s->first_slot, 0), 4, TYPE_PCI_BUS);
|
||||||
h->bus = b;
|
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);
|
memory_region_add_subregion(&s->container, PCIE500_REG_BASE, &s->iomem);
|
||||||
sysbus_init_mmio(dev, &s->container);
|
sysbus_init_mmio(dev, &s->container);
|
||||||
sysbus_init_mmio(dev, &s->pio);
|
sysbus_init_mmio(dev, &s->pio);
|
||||||
|
pci_bus_set_route_irq_fn(b, e500_route_intx_pin_to_irq);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -400,6 +420,7 @@ static const TypeInfo e500_host_bridge_info = {
|
||||||
|
|
||||||
static Property pcihost_properties[] = {
|
static Property pcihost_properties[] = {
|
||||||
DEFINE_PROP_UINT32("first_slot", PPCE500PCIState, first_slot, 0x11),
|
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(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
131
hw/ppc/e500.c
131
hw/ppc/e500.c
|
@ -39,7 +39,6 @@
|
||||||
|
|
||||||
#define EPAPR_MAGIC (0x45504150)
|
#define EPAPR_MAGIC (0x45504150)
|
||||||
#define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb"
|
#define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb"
|
||||||
#define UIMAGE_LOAD_BASE 0
|
|
||||||
#define DTC_LOAD_PAD 0x1800000
|
#define DTC_LOAD_PAD 0x1800000
|
||||||
#define DTC_PAD_MASK 0xFFFFF
|
#define DTC_PAD_MASK 0xFFFFF
|
||||||
#define DTB_MAX_SIZE (8 * 1024 * 1024)
|
#define DTB_MAX_SIZE (8 * 1024 * 1024)
|
||||||
|
@ -128,6 +127,8 @@ static int ppce500_load_device_tree(MachineState *machine,
|
||||||
hwaddr addr,
|
hwaddr addr,
|
||||||
hwaddr initrd_base,
|
hwaddr initrd_base,
|
||||||
hwaddr initrd_size,
|
hwaddr initrd_size,
|
||||||
|
hwaddr kernel_base,
|
||||||
|
hwaddr kernel_size,
|
||||||
bool dry_run)
|
bool dry_run)
|
||||||
{
|
{
|
||||||
CPUPPCState *env = first_cpu->env_ptr;
|
CPUPPCState *env = first_cpu->env_ptr;
|
||||||
|
@ -204,6 +205,13 @@ static int ppce500_load_device_tree(MachineState *machine,
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
|
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",
|
ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
|
||||||
|
@ -392,20 +400,25 @@ typedef struct DeviceTreeParams {
|
||||||
hwaddr addr;
|
hwaddr addr;
|
||||||
hwaddr initrd_base;
|
hwaddr initrd_base;
|
||||||
hwaddr initrd_size;
|
hwaddr initrd_size;
|
||||||
|
hwaddr kernel_base;
|
||||||
|
hwaddr kernel_size;
|
||||||
} DeviceTreeParams;
|
} DeviceTreeParams;
|
||||||
|
|
||||||
static void ppce500_reset_device_tree(void *opaque)
|
static void ppce500_reset_device_tree(void *opaque)
|
||||||
{
|
{
|
||||||
DeviceTreeParams *p = opaque;
|
DeviceTreeParams *p = opaque;
|
||||||
ppce500_load_device_tree(p->machine, &p->params, p->addr, p->initrd_base,
|
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,
|
static int ppce500_prep_device_tree(MachineState *machine,
|
||||||
PPCE500Params *params,
|
PPCE500Params *params,
|
||||||
hwaddr addr,
|
hwaddr addr,
|
||||||
hwaddr initrd_base,
|
hwaddr initrd_base,
|
||||||
hwaddr initrd_size)
|
hwaddr initrd_size,
|
||||||
|
hwaddr kernel_base,
|
||||||
|
hwaddr kernel_size)
|
||||||
{
|
{
|
||||||
DeviceTreeParams *p = g_new(DeviceTreeParams, 1);
|
DeviceTreeParams *p = g_new(DeviceTreeParams, 1);
|
||||||
p->machine = machine;
|
p->machine = machine;
|
||||||
|
@ -413,12 +426,15 @@ static int ppce500_prep_device_tree(MachineState *machine,
|
||||||
p->addr = addr;
|
p->addr = addr;
|
||||||
p->initrd_base = initrd_base;
|
p->initrd_base = initrd_base;
|
||||||
p->initrd_size = initrd_size;
|
p->initrd_size = initrd_size;
|
||||||
|
p->kernel_base = kernel_base;
|
||||||
|
p->kernel_size = kernel_size;
|
||||||
|
|
||||||
qemu_register_reset(ppce500_reset_device_tree, p);
|
qemu_register_reset(ppce500_reset_device_tree, p);
|
||||||
|
|
||||||
/* Issue the device tree loader once, so that we get the size of the blob */
|
/* 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,
|
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. */
|
/* Create -kernel TLB entries for BookE. */
|
||||||
|
@ -603,17 +619,22 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
|
||||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||||
PCIBus *pci_bus;
|
PCIBus *pci_bus;
|
||||||
CPUPPCState *env = NULL;
|
CPUPPCState *env = NULL;
|
||||||
uint64_t elf_entry;
|
uint64_t loadaddr;
|
||||||
uint64_t elf_lowaddr;
|
hwaddr kernel_base = -1LL;
|
||||||
hwaddr entry=0;
|
int kernel_size = 0;
|
||||||
hwaddr loadaddr=UIMAGE_LOAD_BASE;
|
hwaddr dt_base = 0;
|
||||||
target_long kernel_size=0;
|
hwaddr initrd_base = 0;
|
||||||
target_ulong dt_base = 0;
|
int initrd_size = 0;
|
||||||
target_ulong initrd_base = 0;
|
hwaddr cur_base = 0;
|
||||||
target_long initrd_size = 0;
|
char *filename;
|
||||||
target_ulong cur_base = 0;
|
hwaddr bios_entry = 0;
|
||||||
|
target_long bios_size;
|
||||||
|
struct boot_info *boot_info;
|
||||||
|
int dt_size;
|
||||||
int i;
|
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;
|
qemu_irq **irqs, *mpic;
|
||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
CPUPPCState *firstenv = NULL;
|
CPUPPCState *firstenv = NULL;
|
||||||
|
@ -713,12 +734,13 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
|
||||||
/* PCI */
|
/* PCI */
|
||||||
dev = qdev_create(NULL, "e500-pcihost");
|
dev = qdev_create(NULL, "e500-pcihost");
|
||||||
qdev_prop_set_uint32(dev, "first_slot", params->pci_first_slot);
|
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);
|
qdev_init_nofail(dev);
|
||||||
s = SYS_BUS_DEVICE(dev);
|
s = SYS_BUS_DEVICE(dev);
|
||||||
sysbus_connect_irq(s, 0, mpic[pci_irq_nrs[0]]);
|
for (i = 0; i < PCI_NUM_PINS; i++) {
|
||||||
sysbus_connect_irq(s, 1, mpic[pci_irq_nrs[1]]);
|
sysbus_connect_irq(s, i, mpic[pci_irq_nrs[i]]);
|
||||||
sysbus_connect_irq(s, 2, mpic[pci_irq_nrs[2]]);
|
}
|
||||||
sysbus_connect_irq(s, 3, mpic[pci_irq_nrs[3]]);
|
|
||||||
memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET,
|
memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET,
|
||||||
sysbus_mmio_get_region(s, 0));
|
sysbus_mmio_get_region(s, 0));
|
||||||
|
|
||||||
|
@ -738,29 +760,24 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
|
||||||
/* Register spinning region */
|
/* Register spinning region */
|
||||||
sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
|
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. */
|
/* Load kernel. */
|
||||||
if (machine->kernel_filename) {
|
if (machine->kernel_filename) {
|
||||||
kernel_size = load_uimage(machine->kernel_filename, &entry,
|
kernel_base = cur_base;
|
||||||
&loadaddr, NULL);
|
kernel_size = load_image_targphys(machine->kernel_filename,
|
||||||
if (kernel_size < 0) {
|
cur_base,
|
||||||
kernel_size = load_elf(machine->kernel_filename, NULL, NULL,
|
ram_size - cur_base);
|
||||||
&elf_entry, &elf_lowaddr, NULL, 1,
|
|
||||||
ELF_MACHINE, 0);
|
|
||||||
entry = elf_entry;
|
|
||||||
loadaddr = elf_lowaddr;
|
|
||||||
}
|
|
||||||
/* XXX try again as binary */
|
|
||||||
if (kernel_size < 0) {
|
if (kernel_size < 0) {
|
||||||
fprintf(stderr, "qemu: could not load kernel '%s'\n",
|
fprintf(stderr, "qemu: could not load kernel '%s'\n",
|
||||||
machine->kernel_filename);
|
machine->kernel_filename);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_base = loadaddr + kernel_size;
|
cur_base += kernel_size;
|
||||||
|
|
||||||
/* Reserve space for dtb */
|
|
||||||
dt_base = (cur_base + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
|
|
||||||
cur_base += DTB_MAX_SIZE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load initrd. */
|
/* Load initrd. */
|
||||||
|
@ -778,13 +795,50 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
|
||||||
cur_base = initrd_base + initrd_size;
|
cur_base = initrd_base + initrd_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we're loading a kernel directly, we must load the device tree too. */
|
/*
|
||||||
|
* 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) {
|
if (machine->kernel_filename) {
|
||||||
struct boot_info *boot_info;
|
bios_name = machine->kernel_filename;
|
||||||
int dt_size;
|
} 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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,
|
dt_size = ppce500_prep_device_tree(machine, params, dt_base,
|
||||||
initrd_base, initrd_size);
|
initrd_base, initrd_size,
|
||||||
|
kernel_base, kernel_size);
|
||||||
if (dt_size < 0) {
|
if (dt_size < 0) {
|
||||||
fprintf(stderr, "couldn't load device tree\n");
|
fprintf(stderr, "couldn't load device tree\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -792,10 +846,9 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
|
||||||
assert(dt_size < DTB_MAX_SIZE);
|
assert(dt_size < DTB_MAX_SIZE);
|
||||||
|
|
||||||
boot_info = env->load_info;
|
boot_info = env->load_info;
|
||||||
boot_info->entry = entry;
|
boot_info->entry = bios_entry;
|
||||||
boot_info->dt_base = dt_base;
|
boot_info->dt_base = dt_base;
|
||||||
boot_info->dt_size = dt_size;
|
boot_info->dt_size = dt_size;
|
||||||
}
|
|
||||||
|
|
||||||
if (kvm_enabled()) {
|
if (kvm_enabled()) {
|
||||||
kvmppc_init();
|
kvmppc_init();
|
||||||
|
|
|
@ -72,6 +72,8 @@
|
||||||
#define MAX_IDE_BUS 2
|
#define MAX_IDE_BUS 2
|
||||||
#define CFG_ADDR 0xf0000510
|
#define CFG_ADDR 0xf0000510
|
||||||
#define TBFREQ (100UL * 1000UL * 1000UL)
|
#define TBFREQ (100UL * 1000UL * 1000UL)
|
||||||
|
#define CLOCKFREQ (266UL * 1000UL * 1000UL)
|
||||||
|
#define BUSFREQ (100UL * 1000UL * 1000UL)
|
||||||
|
|
||||||
/* debug UniNorth */
|
/* debug UniNorth */
|
||||||
//#define DEBUG_UNIN
|
//#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);
|
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, TBFREQ);
|
||||||
}
|
}
|
||||||
/* Mac OS X requires a "known good" clock-frequency value; pass it one. */
|
/* 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);
|
qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,8 @@
|
||||||
#define MAX_IDE_BUS 2
|
#define MAX_IDE_BUS 2
|
||||||
#define CFG_ADDR 0xf0000510
|
#define CFG_ADDR 0xf0000510
|
||||||
#define TBFREQ 16600000UL
|
#define TBFREQ 16600000UL
|
||||||
|
#define CLOCKFREQ 266000000UL
|
||||||
|
#define BUSFREQ 66000000UL
|
||||||
|
|
||||||
static int fw_cfg_boot_set(void *opaque, const char *boot_device)
|
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);
|
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, TBFREQ);
|
||||||
}
|
}
|
||||||
/* Mac OS X requires a "known good" clock-frequency value; pass it one. */
|
/* 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);
|
qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
|
||||||
}
|
}
|
||||||
|
|
79
hw/ppc/ppc.c
79
hw/ppc/ppc.c
|
@ -29,9 +29,11 @@
|
||||||
#include "sysemu/cpus.h"
|
#include "sysemu/cpus.h"
|
||||||
#include "hw/timer/m48t59.h"
|
#include "hw/timer/m48t59.h"
|
||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
#include "hw/loader.h"
|
#include "hw/loader.h"
|
||||||
#include "sysemu/kvm.h"
|
#include "sysemu/kvm.h"
|
||||||
#include "kvm_ppc.h"
|
#include "kvm_ppc.h"
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
//#define PPC_DEBUG_IRQ
|
//#define PPC_DEBUG_IRQ
|
||||||
//#define PPC_DEBUG_TB
|
//#define PPC_DEBUG_TB
|
||||||
|
@ -49,6 +51,8 @@
|
||||||
# define LOG_TB(...) do { } while (0)
|
# define LOG_TB(...) do { } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define NSEC_PER_SEC 1000000000LL
|
||||||
|
|
||||||
static void cpu_ppc_tb_stop (CPUPPCState *env);
|
static void cpu_ppc_tb_stop (CPUPPCState *env);
|
||||||
static void cpu_ppc_tb_start (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);
|
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) */
|
/* Set up (once) timebase frequency (in Hz) */
|
||||||
clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq)
|
clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq)
|
||||||
{
|
{
|
||||||
|
|
232
hw/ppc/spapr.c
232
hw/ppc/spapr.c
|
@ -34,6 +34,7 @@
|
||||||
#include "sysemu/kvm.h"
|
#include "sysemu/kvm.h"
|
||||||
#include "kvm_ppc.h"
|
#include "kvm_ppc.h"
|
||||||
#include "mmu-hash64.h"
|
#include "mmu-hash64.h"
|
||||||
|
#include "qom/cpu.h"
|
||||||
|
|
||||||
#include "hw/boards.h"
|
#include "hw/boards.h"
|
||||||
#include "hw/ppc/ppc.h"
|
#include "hw/ppc/ppc.h"
|
||||||
|
@ -53,6 +54,7 @@
|
||||||
#include "hw/usb.h"
|
#include "hw/usb.h"
|
||||||
#include "qemu/config-file.h"
|
#include "qemu/config-file.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
#include <libfdt.h>
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
@ -78,13 +80,28 @@
|
||||||
#define TIMEBASE_FREQ 512000000ULL
|
#define TIMEBASE_FREQ 512000000ULL
|
||||||
|
|
||||||
#define MAX_CPUS 256
|
#define MAX_CPUS 256
|
||||||
#define XICS_IRQS 1024
|
|
||||||
|
|
||||||
#define PHANDLE_XICP 0x00001111
|
#define PHANDLE_XICP 0x00001111
|
||||||
|
|
||||||
#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift))
|
#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift))
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct SPAPRMachine SPAPRMachine;
|
||||||
#define TYPE_SPAPR_MACHINE "spapr-machine"
|
#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;
|
sPAPREnvironment *spapr;
|
||||||
|
|
||||||
|
@ -202,35 +219,80 @@ static XICSState *xics_system_init(int nr_servers, int nr_irqs)
|
||||||
return icp;
|
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)
|
static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr)
|
||||||
{
|
{
|
||||||
int ret = 0, offset;
|
int ret = 0, offset, cpus_offset;
|
||||||
CPUState *cpu;
|
CPUState *cs;
|
||||||
char cpu_model[32];
|
char cpu_model[32];
|
||||||
int smt = kvmppc_smt_threads();
|
int smt = kvmppc_smt_threads();
|
||||||
uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
|
uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
|
||||||
|
|
||||||
CPU_FOREACH(cpu) {
|
CPU_FOREACH(cs) {
|
||||||
DeviceClass *dc = DEVICE_GET_CLASS(cpu);
|
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||||
int index = ppc_get_vcpu_dt_id(POWERPC_CPU(cpu));
|
DeviceClass *dc = DEVICE_GET_CLASS(cs);
|
||||||
|
int index = ppc_get_vcpu_dt_id(cpu);
|
||||||
uint32_t associativity[] = {cpu_to_be32(0x5),
|
uint32_t associativity[] = {cpu_to_be32(0x5),
|
||||||
cpu_to_be32(0x0),
|
cpu_to_be32(0x0),
|
||||||
cpu_to_be32(0x0),
|
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)};
|
cpu_to_be32(index)};
|
||||||
|
|
||||||
if ((index % smt) != 0) {
|
if ((index % smt) != 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(cpu_model, 32, "/cpus/%s@%x", dc->fw_name,
|
snprintf(cpu_model, 32, "%s@%x", dc->fw_name, index);
|
||||||
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) {
|
||||||
|
offset = fdt_add_subnode(fdt, cpus_offset, cpu_model);
|
||||||
if (offset < 0) {
|
if (offset < 0) {
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (nb_numa_nodes > 1) {
|
if (nb_numa_nodes > 1) {
|
||||||
ret = fdt_setprop(fdt, offset, "ibm,associativity", associativity,
|
ret = fdt_setprop(fdt, offset, "ibm,associativity", associativity,
|
||||||
|
@ -245,6 +307,12 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr)
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu,
|
||||||
|
ppc_get_compat_smt_threads(cpu));
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -293,6 +361,10 @@ static size_t create_page_sizes_prop(CPUPPCState *env, uint32_t *prop,
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} 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,
|
static void *spapr_create_fdt_skel(hwaddr initrd_base,
|
||||||
hwaddr initrd_size,
|
hwaddr initrd_size,
|
||||||
|
@ -306,13 +378,26 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
|
||||||
CPUState *cs;
|
CPUState *cs;
|
||||||
uint32_t start_prop = cpu_to_be32(initrd_base);
|
uint32_t start_prop = cpu_to_be32(initrd_base);
|
||||||
uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
|
uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
|
||||||
char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt"
|
GString *hypertas = g_string_sized_new(256);
|
||||||
"\0hcall-tce\0hcall-vio\0hcall-splpar\0hcall-bulk\0hcall-set-mode";
|
GString *qemu_hypertas = g_string_sized_new(256);
|
||||||
char qemu_hypertas_prop[] = "hcall-memop1";
|
|
||||||
uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)};
|
uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)};
|
||||||
uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
|
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};
|
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 = g_malloc0(FDT_MAX_SIZE);
|
||||||
_FDT((fdt_create(fdt, 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);
|
DeviceClass *dc = DEVICE_GET_CLASS(cs);
|
||||||
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
|
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
|
||||||
int index = ppc_get_vcpu_dt_id(cpu);
|
int index = ppc_get_vcpu_dt_id(cpu);
|
||||||
uint32_t servers_prop[smp_threads];
|
|
||||||
uint32_t gservers_prop[smp_threads * 2];
|
|
||||||
char *nodename;
|
char *nodename;
|
||||||
uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
|
uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
|
||||||
0xffffffff, 0xffffffff};
|
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_string(fdt, "status", "okay")));
|
||||||
_FDT((fdt_property(fdt, "64-bit", NULL, 0)));
|
_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) {
|
if (env->spr_cb[SPR_PURR].oea_read) {
|
||||||
_FDT((fdt_property(fdt, "ibm,purr", NULL, 0)));
|
_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)));
|
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)));
|
_FDT((fdt_end_node(fdt)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -478,10 +552,15 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
|
||||||
/* RTAS */
|
/* RTAS */
|
||||||
_FDT((fdt_begin_node(fdt, "rtas")));
|
_FDT((fdt_begin_node(fdt, "rtas")));
|
||||||
|
|
||||||
_FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop,
|
if (!kvm_enabled() || kvmppc_spapr_use_multitce()) {
|
||||||
sizeof(hypertas_prop))));
|
add_str(hypertas, "hcall-multi-tce");
|
||||||
_FDT((fdt_property(fdt, "qemu,hypertas-functions", qemu_hypertas_prop,
|
}
|
||||||
sizeof(qemu_hypertas_prop))));
|
_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",
|
_FDT((fdt_property(fdt, "ibm,associativity-reference-points",
|
||||||
refpoints, sizeof(refpoints))));
|
refpoints, sizeof(refpoints))));
|
||||||
|
@ -521,12 +600,68 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
|
||||||
/* event-sources */
|
/* event-sources */
|
||||||
spapr_events_fdt_skel(fdt, epow_irq);
|
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_end_node(fdt))); /* close root node */
|
||||||
_FDT((fdt_finish(fdt)));
|
_FDT((fdt_finish(fdt)));
|
||||||
|
|
||||||
return 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)
|
static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt)
|
||||||
{
|
{
|
||||||
uint32_t associativity[] = {cpu_to_be32(0x4), cpu_to_be32(0x0),
|
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 = {
|
static const VMStateDescription vmstate_spapr = {
|
||||||
.name = "spapr",
|
.name = "spapr",
|
||||||
.version_id = 1,
|
.version_id = 2,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT32(next_irq, sPAPREnvironment),
|
VMSTATE_UINT32(next_irq, sPAPREnvironment),
|
||||||
|
|
||||||
/* RTC offset */
|
/* RTC offset */
|
||||||
VMSTATE_UINT64(rtc_offset, sPAPREnvironment),
|
VMSTATE_UINT64(rtc_offset, sPAPREnvironment),
|
||||||
|
VMSTATE_PPC_TIMEBASE_V(tb, sPAPREnvironment, 2),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1251,6 +1386,12 @@ static void ppc_spapr_init(MachineState *machine)
|
||||||
kvmppc_set_papr(cpu);
|
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);
|
xics_cpu_setup(spapr->icp, cpu);
|
||||||
|
|
||||||
qemu_register_reset(spapr_cpu_reset, 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;
|
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)
|
static void spapr_machine_class_init(ObjectClass *oc, void *data)
|
||||||
{
|
{
|
||||||
MachineClass *mc = MACHINE_CLASS(oc);
|
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 = {
|
static const TypeInfo spapr_machine_info = {
|
||||||
.name = TYPE_SPAPR_MACHINE,
|
.name = TYPE_SPAPR_MACHINE,
|
||||||
.parent = TYPE_MACHINE,
|
.parent = TYPE_MACHINE,
|
||||||
|
.instance_size = sizeof(SPAPRMachine),
|
||||||
|
.instance_init = spapr_machine_initfn,
|
||||||
.class_init = spapr_machine_class_init,
|
.class_init = spapr_machine_class_init,
|
||||||
.interfaces = (InterfaceInfo[]) {
|
.interfaces = (InterfaceInfo[]) {
|
||||||
{ TYPE_FW_PATH_PROVIDER },
|
{ TYPE_FW_PATH_PROVIDER },
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
#include "helper_regs.h"
|
#include "helper_regs.h"
|
||||||
#include "hw/ppc/spapr.h"
|
#include "hw/ppc/spapr.h"
|
||||||
#include "mmu-hash64.h"
|
#include "mmu-hash64.h"
|
||||||
|
#include "cpu-models.h"
|
||||||
|
#include "trace.h"
|
||||||
|
#include "kvm_ppc.h"
|
||||||
|
|
||||||
struct SPRSyncState {
|
struct SPRSyncState {
|
||||||
CPUState *cs;
|
CPUState *cs;
|
||||||
|
@ -709,47 +712,218 @@ static target_ulong h_logical_dcbf(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||||
return H_SUCCESS;
|
return H_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
static target_ulong h_set_mode_resouce_le(PowerPCCPU *cpu,
|
||||||
target_ulong opcode, target_ulong *args)
|
target_ulong mflags,
|
||||||
|
target_ulong value1,
|
||||||
|
target_ulong value2)
|
||||||
{
|
{
|
||||||
CPUState *cs;
|
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) {
|
if (value1) {
|
||||||
ret = H_P3;
|
return H_P3;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
if (value2) {
|
if (value2) {
|
||||||
ret = H_P4;
|
return H_P4;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (mflags) {
|
switch (mflags) {
|
||||||
case H_SET_MODE_ENDIAN_BIG:
|
case H_SET_MODE_ENDIAN_BIG:
|
||||||
CPU_FOREACH(cs) {
|
CPU_FOREACH(cs) {
|
||||||
set_spr(cs, SPR_LPCR, 0, LPCR_ILE);
|
set_spr(cs, SPR_LPCR, 0, LPCR_ILE);
|
||||||
}
|
}
|
||||||
ret = H_SUCCESS;
|
return H_SUCCESS;
|
||||||
break;
|
|
||||||
|
|
||||||
case H_SET_MODE_ENDIAN_LITTLE:
|
case H_SET_MODE_ENDIAN_LITTLE:
|
||||||
CPU_FOREACH(cs) {
|
CPU_FOREACH(cs) {
|
||||||
set_spr(cs, SPR_LPCR, LPCR_ILE, LPCR_ILE);
|
set_spr(cs, SPR_LPCR, LPCR_ILE, LPCR_ILE);
|
||||||
}
|
}
|
||||||
ret = H_SUCCESS;
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ret = H_UNSUPPORTED_FLAG;
|
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)
|
||||||
|
{
|
||||||
|
target_ulong resource = args[1];
|
||||||
|
target_ulong ret = H_P2;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Terminator record */
|
||||||
|
if (~pvr_mask & pvr) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
/* For the future use: here @list points to the first capability */
|
||||||
return ret;
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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];
|
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(KVMPPC_H_RTAS, h_rtas);
|
||||||
|
|
||||||
spapr_register_hypercall(H_SET_MODE, h_set_mode);
|
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)
|
type_init(hypercall_register_types)
|
||||||
|
|
|
@ -35,6 +35,9 @@ enum sPAPRTCEAccess {
|
||||||
SPAPR_TCE_RW = 3,
|
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 QLIST_HEAD(spapr_tce_tables, sPAPRTCETable) spapr_tce_tables;
|
||||||
|
|
||||||
static sPAPRTCETable *spapr_tce_find_by_liobn(uint32_t liobn)
|
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) {
|
if (tcet->bypass) {
|
||||||
ret.perm = IOMMU_RW;
|
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 */
|
/* Check if we are in bound */
|
||||||
tce = tcet->table[addr >> SPAPR_TCE_PAGE_SHIFT];
|
hwaddr page_mask = IOMMU_PAGE_MASK(tcet->page_shift);
|
||||||
ret.iova = addr & ~SPAPR_TCE_PAGE_MASK;
|
|
||||||
ret.translated_addr = tce & ~SPAPR_TCE_PAGE_MASK;
|
tce = tcet->table[addr >> tcet->page_shift];
|
||||||
ret.addr_mask = SPAPR_TCE_PAGE_MASK;
|
ret.iova = addr & page_mask;
|
||||||
|
ret.translated_addr = tce & page_mask;
|
||||||
|
ret.addr_mask = ~page_mask;
|
||||||
ret.perm = tce;
|
ret.perm = tce;
|
||||||
}
|
}
|
||||||
trace_spapr_iommu_xlate(tcet->liobn, addr, ret.iova, ret.perm,
|
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;
|
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 = {
|
static const VMStateDescription vmstate_spapr_tce_table = {
|
||||||
.name = "spapr_iommu",
|
.name = "spapr_iommu",
|
||||||
.version_id = 1,
|
.version_id = 2,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 2,
|
||||||
.pre_load = spapr_tce_table_pre_load,
|
.fields = (VMStateField []) {
|
||||||
.fields = (VMStateField[]) {
|
|
||||||
/* Sanity check */
|
/* Sanity check */
|
||||||
VMSTATE_UINT32_EQUAL(liobn, sPAPRTCETable),
|
VMSTATE_UINT32_EQUAL(liobn, sPAPRTCETable),
|
||||||
VMSTATE_UINT32_EQUAL(window_size, sPAPRTCETable),
|
VMSTATE_UINT32_EQUAL(nb_table, sPAPRTCETable),
|
||||||
|
|
||||||
/* IOMMU state */
|
/* IOMMU state */
|
||||||
VMSTATE_BOOL(bypass, sPAPRTCETable),
|
VMSTATE_BOOL(bypass, sPAPRTCETable),
|
||||||
|
@ -121,28 +116,33 @@ static int spapr_tce_table_realize(DeviceState *dev)
|
||||||
|
|
||||||
if (kvm_enabled()) {
|
if (kvm_enabled()) {
|
||||||
tcet->table = kvmppc_create_spapr_tce(tcet->liobn,
|
tcet->table = kvmppc_create_spapr_tce(tcet->liobn,
|
||||||
tcet->window_size,
|
tcet->nb_table <<
|
||||||
|
tcet->page_shift,
|
||||||
&tcet->fd);
|
&tcet->fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tcet->table) {
|
if (!tcet->table) {
|
||||||
size_t table_size = (tcet->window_size >> SPAPR_TCE_PAGE_SHIFT)
|
size_t table_size = tcet->nb_table * sizeof(uint64_t);
|
||||||
* sizeof(uint64_t);
|
|
||||||
tcet->table = g_malloc0(table_size);
|
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);
|
trace_spapr_iommu_new_table(tcet->liobn, tcet, tcet->table, tcet->fd);
|
||||||
|
|
||||||
memory_region_init_iommu(&tcet->iommu, OBJECT(dev), &spapr_iommu_ops,
|
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);
|
QLIST_INSERT_HEAD(&spapr_tce_tables, tcet, list);
|
||||||
|
|
||||||
|
vmstate_register(DEVICE(tcet), tcet->liobn, &vmstate_spapr_tce_table,
|
||||||
|
tcet);
|
||||||
|
|
||||||
return 0;
|
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;
|
sPAPRTCETable *tcet;
|
||||||
|
|
||||||
|
@ -152,17 +152,19 @@ sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn, size_t wi
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!window_size) {
|
if (!nb_table) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
tcet = SPAPR_TCE_TABLE(object_new(TYPE_SPAPR_TCE_TABLE));
|
tcet = SPAPR_TCE_TABLE(object_new(TYPE_SPAPR_TCE_TABLE));
|
||||||
tcet->liobn = liobn;
|
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);
|
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;
|
return tcet;
|
||||||
}
|
}
|
||||||
|
@ -175,7 +177,7 @@ static void spapr_tce_table_finalize(Object *obj)
|
||||||
|
|
||||||
if (!kvm_enabled() ||
|
if (!kvm_enabled() ||
|
||||||
(kvmppc_remove_spapr_tce(tcet->table, tcet->fd,
|
(kvmppc_remove_spapr_tce(tcet->table, tcet->fd,
|
||||||
tcet->window_size) != 0)) {
|
tcet->nb_table) != 0)) {
|
||||||
g_free(tcet->table);
|
g_free(tcet->table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,8 +195,7 @@ void spapr_tce_set_bypass(sPAPRTCETable *tcet, bool bypass)
|
||||||
static void spapr_tce_reset(DeviceState *dev)
|
static void spapr_tce_reset(DeviceState *dev)
|
||||||
{
|
{
|
||||||
sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev);
|
sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev);
|
||||||
size_t table_size = (tcet->window_size >> SPAPR_TCE_PAGE_SHIFT)
|
size_t table_size = tcet->nb_table * sizeof(uint64_t);
|
||||||
* sizeof(uint64_t);
|
|
||||||
|
|
||||||
tcet->bypass = false;
|
tcet->bypass = false;
|
||||||
memset(tcet->table, 0, table_size);
|
memset(tcet->table, 0, table_size);
|
||||||
|
@ -204,25 +205,110 @@ static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
|
||||||
target_ulong tce)
|
target_ulong tce)
|
||||||
{
|
{
|
||||||
IOMMUTLBEntry entry;
|
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"
|
hcall_dprintf("spapr_vio_put_tce on out-of-bounds IOBA 0x"
|
||||||
TARGET_FMT_lx "\n", ioba);
|
TARGET_FMT_lx "\n", ioba);
|
||||||
return H_PARAMETER;
|
return H_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
tcet->table[ioba >> SPAPR_TCE_PAGE_SHIFT] = tce;
|
tcet->table[index] = tce;
|
||||||
|
|
||||||
entry.target_as = &address_space_memory,
|
entry.target_as = &address_space_memory,
|
||||||
entry.iova = ioba & ~SPAPR_TCE_PAGE_MASK;
|
entry.iova = ioba & page_mask;
|
||||||
entry.translated_addr = tce & ~SPAPR_TCE_PAGE_MASK;
|
entry.translated_addr = tce & page_mask;
|
||||||
entry.addr_mask = SPAPR_TCE_PAGE_MASK;
|
entry.addr_mask = ~page_mask;
|
||||||
entry.perm = tce;
|
entry.perm = tce;
|
||||||
memory_region_notify_iommu(&tcet->iommu, entry);
|
memory_region_notify_iommu(&tcet->iommu, entry);
|
||||||
|
|
||||||
return H_SUCCESS;
|
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,
|
static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||||
target_ulong opcode, target_ulong *args)
|
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;
|
target_ulong ret = H_PARAMETER;
|
||||||
sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
|
sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
|
||||||
|
|
||||||
ioba &= ~(SPAPR_TCE_PAGE_SIZE - 1);
|
|
||||||
|
|
||||||
if (tcet) {
|
if (tcet) {
|
||||||
|
hwaddr page_mask = IOMMU_PAGE_MASK(tcet->page_shift);
|
||||||
|
|
||||||
|
ioba &= page_mask;
|
||||||
|
|
||||||
ret = put_tce_emu(tcet, ioba, tce);
|
ret = put_tce_emu(tcet, ioba, tce);
|
||||||
}
|
}
|
||||||
trace_spapr_iommu_put(liobn, ioba, tce, ret);
|
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,
|
static target_ulong get_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
|
||||||
target_ulong *tce)
|
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"
|
hcall_dprintf("spapr_iommu_get_tce on out-of-bounds IOBA 0x"
|
||||||
TARGET_FMT_lx "\n", ioba);
|
TARGET_FMT_lx "\n", ioba);
|
||||||
return H_PARAMETER;
|
return H_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
*tce = tcet->table[ioba >> SPAPR_TCE_PAGE_SHIFT];
|
*tce = tcet->table[index];
|
||||||
|
|
||||||
return H_SUCCESS;
|
return H_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -265,9 +355,11 @@ static target_ulong h_get_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||||
target_ulong ret = H_PARAMETER;
|
target_ulong ret = H_PARAMETER;
|
||||||
sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
|
sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
|
||||||
|
|
||||||
ioba &= ~(SPAPR_TCE_PAGE_SIZE - 1);
|
|
||||||
|
|
||||||
if (tcet) {
|
if (tcet) {
|
||||||
|
hwaddr page_mask = IOMMU_PAGE_MASK(tcet->page_shift);
|
||||||
|
|
||||||
|
ioba &= page_mask;
|
||||||
|
|
||||||
ret = get_tce_emu(tcet, ioba, &tce);
|
ret = get_tce_emu(tcet, ioba, &tce);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
args[0] = tce;
|
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,
|
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)
|
static void spapr_tce_table_class_init(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
dc->vmsd = &vmstate_spapr_tce_table;
|
|
||||||
dc->init = spapr_tce_table_realize;
|
dc->init = spapr_tce_table_realize;
|
||||||
dc->reset = spapr_tce_reset;
|
dc->reset = spapr_tce_reset;
|
||||||
|
|
||||||
|
@ -331,6 +422,8 @@ static void spapr_tce_table_class_init(ObjectClass *klass, void *data)
|
||||||
/* hcall-tce */
|
/* hcall-tce */
|
||||||
spapr_register_hypercall(H_PUT_TCE, h_put_tce);
|
spapr_register_hypercall(H_PUT_TCE, h_put_tce);
|
||||||
spapr_register_hypercall(H_GET_TCE, h_get_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 = {
|
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 req_num = rtas_ld(args, 4); /* 0 == remove all */
|
||||||
unsigned int seq_num = rtas_ld(args, 5);
|
unsigned int seq_num = rtas_ld(args, 5);
|
||||||
unsigned int ret_intr_type;
|
unsigned int ret_intr_type;
|
||||||
int ndev, irq;
|
int ndev, irq, max_irqs = 0;
|
||||||
sPAPRPHBState *phb = NULL;
|
sPAPRPHBState *phb = NULL;
|
||||||
PCIDevice *pdev = 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);
|
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 */
|
/* 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)) {
|
if (phb->msi_table[ndev].nvec && (req_num != phb->msi_table[ndev].nvec)) {
|
||||||
/* Unexpected behaviour */
|
/* Unexpected behaviour */
|
||||||
|
@ -511,6 +528,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
|
||||||
SysBusDevice *s = SYS_BUS_DEVICE(dev);
|
SysBusDevice *s = SYS_BUS_DEVICE(dev);
|
||||||
sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s);
|
sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s);
|
||||||
PCIHostState *phb = PCI_HOST_BRIDGE(s);
|
PCIHostState *phb = PCI_HOST_BRIDGE(s);
|
||||||
|
sPAPRPHBClass *info = SPAPR_PCI_HOST_BRIDGE_GET_CLASS(s);
|
||||||
char *namebuf;
|
char *namebuf;
|
||||||
int i;
|
int i;
|
||||||
PCIBus *bus;
|
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,
|
memory_region_add_subregion(get_system_memory(), sphb->mem_win_addr,
|
||||||
&sphb->memwindow);
|
&sphb->memwindow);
|
||||||
|
|
||||||
/* On ppc, we only have MMIO no specific IO space from the CPU
|
/* Initialize IO regions */
|
||||||
* 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 */
|
|
||||||
sprintf(namebuf, "%s.io", sphb->dtbusname);
|
sprintf(namebuf, "%s.io", sphb->dtbusname);
|
||||||
memory_region_init(&sphb->iospace, OBJECT(sphb),
|
memory_region_init(&sphb->iospace, OBJECT(sphb),
|
||||||
namebuf, SPAPR_PCI_IO_WIN_SIZE);
|
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);
|
sprintf(namebuf, "%s.io-alias", sphb->dtbusname);
|
||||||
memory_region_init_alias(&sphb->iowindow, OBJECT(sphb), namebuf,
|
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,
|
memory_region_add_subregion(get_system_memory(), sphb->io_win_addr,
|
||||||
&sphb->iowindow);
|
&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);
|
PCI_DEVFN(0, 0), PCI_NUM_PINS, TYPE_PCI_BUS);
|
||||||
phb->bus = bus;
|
phb->bus = bus;
|
||||||
|
|
||||||
sphb->dma_window_start = 0;
|
/*
|
||||||
sphb->dma_window_size = 0x40000000;
|
* Initialize PHB address space.
|
||||||
sphb->tcet = spapr_tce_new_table(dev, sphb->dma_liobn,
|
* By default there will be at least one subregion for default
|
||||||
sphb->dma_window_size);
|
* 32bit DMA window.
|
||||||
if (!sphb->tcet) {
|
* Later the guest might want to create another DMA window
|
||||||
error_setg(errp, "Unable to create TCE table for %s",
|
* which will become another memory subregion.
|
||||||
sphb->dtbusname);
|
*/
|
||||||
return;
|
sprintf(namebuf, "%s.iommu-root", sphb->dtbusname);
|
||||||
}
|
|
||||||
address_space_init(&sphb->iommu_as, spapr_tce_get_iommu(sphb->tcet),
|
memory_region_init(&sphb->iommu_root, OBJECT(sphb),
|
||||||
|
namebuf, UINT64_MAX);
|
||||||
|
address_space_init(&sphb->iommu_as, &sphb->iommu_root,
|
||||||
sphb->dtbusname);
|
sphb->dtbusname);
|
||||||
|
|
||||||
pci_setup_iommu(bus, spapr_pci_dma_iommu, sphb);
|
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;
|
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_finish_realize(sPAPRPHBState *sphb, Error **errp)
|
||||||
|
{
|
||||||
|
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)
|
static void spapr_phb_reset(DeviceState *qdev)
|
||||||
{
|
{
|
||||||
SysBusDevice *s = SYS_BUS_DEVICE(qdev);
|
|
||||||
sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s);
|
|
||||||
|
|
||||||
/* Reset the IOMMU state */
|
/* Reset the IOMMU state */
|
||||||
device_reset(DEVICE(sphb->tcet));
|
object_child_foreach(OBJECT(qdev), spapr_phb_children_reset, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Property spapr_phb_properties[] = {
|
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);
|
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
sPAPRPHBClass *spc = SPAPR_PCI_HOST_BRIDGE_CLASS(klass);
|
||||||
|
|
||||||
hc->root_bus_path = spapr_phb_root_bus_path;
|
hc->root_bus_path = spapr_phb_root_bus_path;
|
||||||
dc->realize = spapr_phb_realize;
|
dc->realize = spapr_phb_realize;
|
||||||
|
@ -719,6 +765,7 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data)
|
||||||
dc->vmsd = &vmstate_spapr_pci;
|
dc->vmsd = &vmstate_spapr_pci;
|
||||||
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
|
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
|
||||||
dc->cannot_instantiate_with_device_add_yet = false;
|
dc->cannot_instantiate_with_device_add_yet = false;
|
||||||
|
spc->finish_realize = spapr_phb_finish_realize;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo spapr_phb_info = {
|
static const TypeInfo spapr_phb_info = {
|
||||||
|
@ -726,6 +773,7 @@ static const TypeInfo spapr_phb_info = {
|
||||||
.parent = TYPE_PCI_HOST_BRIDGE,
|
.parent = TYPE_PCI_HOST_BRIDGE,
|
||||||
.instance_size = sizeof(sPAPRPHBState),
|
.instance_size = sizeof(sPAPRPHBState),
|
||||||
.class_init = spapr_phb_class_init,
|
.class_init = spapr_phb_class_init,
|
||||||
|
.class_size = sizeof(sPAPRPHBClass),
|
||||||
};
|
};
|
||||||
|
|
||||||
PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index)
|
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_fff(x) b_x((x), 8, 3) /* function number */
|
||||||
#define b_rrrrrrrr(x) b_x((x), 0, 8) /* register 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,
|
int spapr_populate_pci_dt(sPAPRPHBState *phb,
|
||||||
uint32_t xics_phandle,
|
uint32_t xics_phandle,
|
||||||
void *fdt)
|
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, "ranges", &ranges, sizeof(ranges)));
|
||||||
_FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg)));
|
_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,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
|
/* Build the interrupt-map, this must matches what is done
|
||||||
* in pci_spapr_map_irq
|
* 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,
|
_FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map,
|
||||||
sizeof(interrupt_map)));
|
sizeof(interrupt_map)));
|
||||||
|
|
||||||
spapr_dma_dt(fdt, bus_off, "ibm,dma-window",
|
object_child_foreach(OBJECT(phb), spapr_phb_children_dt,
|
||||||
phb->dma_liobn, phb->dma_window_start,
|
&((sPAPRTCEDT){ .fdt = fdt, .node_off = bus_off }));
|
||||||
phb->dma_window_size);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -456,7 +456,11 @@ static int spapr_vio_busdev_init(DeviceState *qdev)
|
||||||
|
|
||||||
if (pc->rtce_window_size) {
|
if (pc->rtce_window_size) {
|
||||||
uint32_t liobn = SPAPR_VIO_BASE_LIOBN | dev->reg;
|
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);
|
address_space_init(&dev->as, spapr_tce_get_iommu(dev->tcet), qdev->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -561,6 +561,11 @@ typedef struct {
|
||||||
#define SHF_ALPHA_GPREL 0x10000000
|
#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 */
|
/* PowerPC relocations defined by the ABIs */
|
||||||
#define R_PPC_NONE 0
|
#define R_PPC_NONE 0
|
||||||
#define R_PPC_ADDR32 1 /* 32bit absolute address */
|
#define R_PPC_ADDR32 1 /* 32bit absolute address */
|
||||||
|
|
|
@ -34,7 +34,21 @@
|
||||||
#define SPAPR_PCI_HOST_BRIDGE(obj) \
|
#define SPAPR_PCI_HOST_BRIDGE(obj) \
|
||||||
OBJECT_CHECK(sPAPRPHBState, (obj), TYPE_SPAPR_PCI_HOST_BRIDGE)
|
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;
|
PCIHostState parent_obj;
|
||||||
|
|
||||||
int32_t index;
|
int32_t index;
|
||||||
|
@ -46,10 +60,8 @@ typedef struct sPAPRPHBState {
|
||||||
MemoryRegion memwindow, iowindow;
|
MemoryRegion memwindow, iowindow;
|
||||||
|
|
||||||
uint32_t dma_liobn;
|
uint32_t dma_liobn;
|
||||||
uint64_t dma_window_start;
|
|
||||||
uint64_t dma_window_size;
|
|
||||||
sPAPRTCETable *tcet;
|
|
||||||
AddressSpace iommu_as;
|
AddressSpace iommu_as;
|
||||||
|
MemoryRegion iommu_root;
|
||||||
|
|
||||||
struct spapr_pci_lsi {
|
struct spapr_pci_lsi {
|
||||||
uint32_t irq;
|
uint32_t irq;
|
||||||
|
@ -62,7 +74,7 @@ typedef struct sPAPRPHBState {
|
||||||
} msi_table[SPAPR_MSIX_MAX_DEVS];
|
} msi_table[SPAPR_MSIX_MAX_DEVS];
|
||||||
|
|
||||||
QLIST_ENTRY(sPAPRPHBState) list;
|
QLIST_ENTRY(sPAPRPHBState) list;
|
||||||
} sPAPRPHBState;
|
};
|
||||||
|
|
||||||
#define SPAPR_PCI_BASE_BUID 0x800000020000000ULL
|
#define SPAPR_PCI_BASE_BUID 0x800000020000000ULL
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,11 @@ struct DBDMA_io {
|
||||||
/* unaligned last sector of a request */
|
/* unaligned last sector of a request */
|
||||||
uint8_t remainder[0x200];
|
uint8_t remainder[0x200];
|
||||||
int remainder_len;
|
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_IS_KVM (FW_CFG_ARCH_LOCAL + 0x05)
|
||||||
#define FW_CFG_PPC_KVM_HC (FW_CFG_ARCH_LOCAL + 0x06)
|
#define FW_CFG_PPC_KVM_HC (FW_CFG_ARCH_LOCAL + 0x06)
|
||||||
#define FW_CFG_PPC_KVM_PID (FW_CFG_ARCH_LOCAL + 0x07)
|
#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
|
#define PPC_SERIAL_MM_BAUDBASE 399193
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ typedef struct sPAPREnvironment {
|
||||||
target_ulong entry_point;
|
target_ulong entry_point;
|
||||||
uint32_t next_irq;
|
uint32_t next_irq;
|
||||||
uint64_t rtc_offset;
|
uint64_t rtc_offset;
|
||||||
|
struct PPCTimebase tb;
|
||||||
bool has_graphics;
|
bool has_graphics;
|
||||||
|
|
||||||
uint32_t epow_irq;
|
uint32_t epow_irq;
|
||||||
|
@ -163,6 +164,11 @@ typedef struct sPAPREnvironment {
|
||||||
#define H_SET_MODE_ENDIAN_BIG 0
|
#define H_SET_MODE_ENDIAN_BIG 0
|
||||||
#define H_SET_MODE_ENDIAN_LITTLE 1
|
#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 */
|
/* VASI States */
|
||||||
#define H_VASI_INVALID 0
|
#define H_VASI_INVALID 0
|
||||||
#define H_VASI_ENABLED 1
|
#define H_VASI_ENABLED 1
|
||||||
|
@ -302,10 +308,16 @@ typedef struct sPAPREnvironment {
|
||||||
#define KVMPPC_HCALL_BASE 0xf000
|
#define KVMPPC_HCALL_BASE 0xf000
|
||||||
#define KVMPPC_H_RTAS (KVMPPC_HCALL_BASE + 0x0)
|
#define KVMPPC_H_RTAS (KVMPPC_HCALL_BASE + 0x0)
|
||||||
#define KVMPPC_H_LOGICAL_MEMOP (KVMPPC_HCALL_BASE + 0x1)
|
#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;
|
extern sPAPREnvironment *spapr;
|
||||||
|
|
||||||
|
typedef struct sPAPRDeviceTreeUpdateHeader {
|
||||||
|
uint32_t version_id;
|
||||||
|
} sPAPRDeviceTreeUpdateHeader;
|
||||||
|
|
||||||
/*#define DEBUG_SPAPR_HCALLS*/
|
/*#define DEBUG_SPAPR_HCALLS*/
|
||||||
|
|
||||||
#ifdef DEBUG_SPAPR_HCALLS
|
#ifdef DEBUG_SPAPR_HCALLS
|
||||||
|
@ -390,8 +402,9 @@ typedef struct sPAPRTCETable sPAPRTCETable;
|
||||||
struct sPAPRTCETable {
|
struct sPAPRTCETable {
|
||||||
DeviceState parent;
|
DeviceState parent;
|
||||||
uint32_t liobn;
|
uint32_t liobn;
|
||||||
uint32_t window_size;
|
|
||||||
uint32_t nb_table;
|
uint32_t nb_table;
|
||||||
|
uint64_t bus_offset;
|
||||||
|
uint32_t page_shift;
|
||||||
uint64_t *table;
|
uint64_t *table;
|
||||||
bool bypass;
|
bool bypass;
|
||||||
int fd;
|
int fd;
|
||||||
|
@ -401,8 +414,11 @@ struct sPAPRTCETable {
|
||||||
|
|
||||||
void spapr_events_init(sPAPREnvironment *spapr);
|
void spapr_events_init(sPAPREnvironment *spapr);
|
||||||
void spapr_events_fdt_skel(void *fdt, uint32_t epow_irq);
|
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,
|
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);
|
MemoryRegion *spapr_tce_get_iommu(sPAPRTCETable *tcet);
|
||||||
void spapr_tce_set_bypass(sPAPRTCETable *tcet, bool bypass);
|
void spapr_tce_set_bypass(sPAPRTCETable *tcet, bool bypass);
|
||||||
int spapr_dma_dt(void *fdt, int node_off, const char *propname,
|
int spapr_dma_dt(void *fdt, int node_off, const char *propname,
|
||||||
|
|
|
@ -152,6 +152,8 @@ struct ICSIRQState {
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define XICS_IRQS 1024
|
||||||
|
|
||||||
qemu_irq xics_get_qirq(XICSState *icp, int irq);
|
qemu_irq xics_get_qirq(XICSState *icp, int irq);
|
||||||
void xics_set_irq_type(XICSState *icp, int irq, bool lsi);
|
void xics_set_irq_type(XICSState *icp, int irq, bool lsi);
|
||||||
|
|
||||||
|
|
40
include/libdecnumber/dconfig.h
Normal file
40
include/libdecnumber/dconfig.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/* 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
|
257
include/libdecnumber/decContext.h
Normal file
257
include/libdecnumber/decContext.h
Normal file
|
@ -0,0 +1,257 @@
|
||||||
|
/* 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
|
1214
include/libdecnumber/decDPD.h
Normal file
1214
include/libdecnumber/decDPD.h
Normal file
File diff suppressed because it is too large
Load diff
202
include/libdecnumber/decNumber.h
Normal file
202
include/libdecnumber/decNumber.h
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
/* 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
|
665
include/libdecnumber/decNumberLocal.h
Normal file
665
include/libdecnumber/decNumberLocal.h
Normal file
|
@ -0,0 +1,665 @@
|
||||||
|
/* Local definitions for the decNumber C Library.
|
||||||
|
Copyright (C) 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. */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decNumber package local type, tuning, and macro definitions */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* This header file is included by all modules in the decNumber */
|
||||||
|
/* library, and contains local type definitions, tuning parameters, */
|
||||||
|
/* etc. It should not need to be used by application programs. */
|
||||||
|
/* decNumber.h or one of decDouble (etc.) must be included first. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
#if !defined(DECNUMBERLOC)
|
||||||
|
#define DECNUMBERLOC
|
||||||
|
#define DECVERSION "decNumber 3.53" /* Package Version [16 max.] */
|
||||||
|
#define DECNLAUTHOR "Mike Cowlishaw" /* Who to blame */
|
||||||
|
|
||||||
|
#include <stdlib.h> /* for abs */
|
||||||
|
#include <string.h> /* for memset, strcpy */
|
||||||
|
#include "libdecnumber/dconfig.h"
|
||||||
|
|
||||||
|
/* Conditional code flag -- set this to match hardware platform */
|
||||||
|
/* 1=little-endian, 0=big-endian */
|
||||||
|
#if WORDS_BIGENDIAN
|
||||||
|
#define DECLITEND 0
|
||||||
|
#else
|
||||||
|
#define DECLITEND 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Conditional code flag -- set this to 1 for best performance */
|
||||||
|
#define DECUSE64 1 /* 1=use int64s, 0=int32 & smaller only */
|
||||||
|
|
||||||
|
/* Conditional check flags -- set these to 0 for best performance */
|
||||||
|
#define DECCHECK 0 /* 1 to enable robust checking */
|
||||||
|
#define DECALLOC 0 /* 1 to enable memory accounting */
|
||||||
|
#define DECTRACE 0 /* 1 to trace certain internals, etc. */
|
||||||
|
|
||||||
|
/* Tuning parameter for decNumber (arbitrary precision) module */
|
||||||
|
#define DECBUFFER 36 /* Size basis for local buffers. This */
|
||||||
|
/* should be a common maximum precision */
|
||||||
|
/* rounded up to a multiple of 4; must */
|
||||||
|
/* be zero or positive. */
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------- */
|
||||||
|
/* Definitions for all modules (general-purpose) */
|
||||||
|
/* ---------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* Local names for common types -- for safety, decNumber modules do */
|
||||||
|
/* not use int or long directly. */
|
||||||
|
#define Flag uint8_t
|
||||||
|
#define Byte int8_t
|
||||||
|
#define uByte uint8_t
|
||||||
|
#define Short int16_t
|
||||||
|
#define uShort uint16_t
|
||||||
|
#define Int int32_t
|
||||||
|
#define uInt uint32_t
|
||||||
|
#define Unit decNumberUnit
|
||||||
|
#if DECUSE64
|
||||||
|
#define Long int64_t
|
||||||
|
#define uLong uint64_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Development-use definitions */
|
||||||
|
typedef long int LI; /* for printf arguments only */
|
||||||
|
#define DECNOINT 0 /* 1 to check no internal use of 'int' */
|
||||||
|
#if DECNOINT
|
||||||
|
/* if these interfere with your C includes, do not set DECNOINT */
|
||||||
|
#define int ? /* enable to ensure that plain C 'int' */
|
||||||
|
#define long ?? /* .. or 'long' types are not used */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Shared lookup tables */
|
||||||
|
extern const uByte DECSTICKYTAB[10]; /* re-round digits if sticky */
|
||||||
|
extern const uLong DECPOWERS[19]; /* powers of ten table */
|
||||||
|
/* The following are included from decDPD.h */
|
||||||
|
extern const uShort DPD2BIN[1024]; /* DPD -> 0-999 */
|
||||||
|
extern const uShort BIN2DPD[1000]; /* 0-999 -> DPD */
|
||||||
|
extern const uInt DPD2BINK[1024]; /* DPD -> 0-999000 */
|
||||||
|
extern const uInt DPD2BINM[1024]; /* DPD -> 0-999000000 */
|
||||||
|
extern const uByte DPD2BCD8[4096]; /* DPD -> ddd + len */
|
||||||
|
extern const uByte BIN2BCD8[4000]; /* 0-999 -> ddd + len */
|
||||||
|
extern const uShort BCD2DPD[2458]; /* 0-0x999 -> DPD (0x999=2457)*/
|
||||||
|
|
||||||
|
/* LONGMUL32HI -- set w=(u*v)>>32, where w, u, and v are uInts */
|
||||||
|
/* (that is, sets w to be the high-order word of the 64-bit result; */
|
||||||
|
/* the low-order word is simply u*v.) */
|
||||||
|
/* This version is derived from Knuth via Hacker's Delight; */
|
||||||
|
/* it seems to optimize better than some others tried */
|
||||||
|
#define LONGMUL32HI(w, u, v) { \
|
||||||
|
uInt u0, u1, v0, v1, w0, w1, w2, t; \
|
||||||
|
u0=u & 0xffff; u1=u>>16; \
|
||||||
|
v0=v & 0xffff; v1=v>>16; \
|
||||||
|
w0=u0*v0; \
|
||||||
|
t=u1*v0 + (w0>>16); \
|
||||||
|
w1=t & 0xffff; w2=t>>16; \
|
||||||
|
w1=u0*v1 + w1; \
|
||||||
|
(w)=u1*v1 + w2 + (w1>>16);}
|
||||||
|
|
||||||
|
/* ROUNDUP -- round an integer up to a multiple of n */
|
||||||
|
#define ROUNDUP(i, n) ((((i)+(n)-1)/n)*n)
|
||||||
|
|
||||||
|
/* ROUNDDOWN -- round an integer down to a multiple of n */
|
||||||
|
#define ROUNDDOWN(i, n) (((i)/n)*n)
|
||||||
|
#define ROUNDDOWN4(i) ((i)&~3) /* special for n=4 */
|
||||||
|
|
||||||
|
/* References to multi-byte sequences under different sizes */
|
||||||
|
/* Refer to a uInt from four bytes starting at a char* or uByte*, */
|
||||||
|
/* etc. */
|
||||||
|
#define UINTAT(b) (*((uInt *)(b)))
|
||||||
|
#define USHORTAT(b) (*((uShort *)(b)))
|
||||||
|
#define UBYTEAT(b) (*((uByte *)(b)))
|
||||||
|
|
||||||
|
/* X10 and X100 -- multiply integer i by 10 or 100 */
|
||||||
|
/* [shifts are usually faster than multiply; could be conditional] */
|
||||||
|
#define X10(i) (((i)<<1)+((i)<<3))
|
||||||
|
#define X100(i) (((i)<<2)+((i)<<5)+((i)<<6))
|
||||||
|
|
||||||
|
/* MAXI and MINI -- general max & min (not in ANSI) for integers */
|
||||||
|
#define MAXI(x,y) ((x)<(y)?(y):(x))
|
||||||
|
#define MINI(x,y) ((x)>(y)?(y):(x))
|
||||||
|
|
||||||
|
/* Useful constants */
|
||||||
|
#define BILLION 1000000000 /* 10**9 */
|
||||||
|
/* CHARMASK: 0x30303030 for ASCII/UTF8; 0xF0F0F0F0 for EBCDIC */
|
||||||
|
#define CHARMASK ((((((((uInt)'0')<<8)+'0')<<8)+'0')<<8)+'0')
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------- */
|
||||||
|
/* Definitions for arbitary-precision modules (only valid after */
|
||||||
|
/* decNumber.h has been included) */
|
||||||
|
/* ---------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* Limits and constants */
|
||||||
|
#define DECNUMMAXP 999999999 /* maximum precision code can handle */
|
||||||
|
#define DECNUMMAXE 999999999 /* maximum adjusted exponent ditto */
|
||||||
|
#define DECNUMMINE -999999999 /* minimum adjusted exponent ditto */
|
||||||
|
#if (DECNUMMAXP != DEC_MAX_DIGITS)
|
||||||
|
#error Maximum digits mismatch
|
||||||
|
#endif
|
||||||
|
#if (DECNUMMAXE != DEC_MAX_EMAX)
|
||||||
|
#error Maximum exponent mismatch
|
||||||
|
#endif
|
||||||
|
#if (DECNUMMINE != DEC_MIN_EMIN)
|
||||||
|
#error Minimum exponent mismatch
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Set DECDPUNMAX -- the maximum integer that fits in DECDPUN */
|
||||||
|
/* digits, and D2UTABLE -- the initializer for the D2U table */
|
||||||
|
#if DECDPUN==1
|
||||||
|
#define DECDPUNMAX 9
|
||||||
|
#define D2UTABLE {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17, \
|
||||||
|
18,19,20,21,22,23,24,25,26,27,28,29,30,31,32, \
|
||||||
|
33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, \
|
||||||
|
48,49}
|
||||||
|
#elif DECDPUN==2
|
||||||
|
#define DECDPUNMAX 99
|
||||||
|
#define D2UTABLE {0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10, \
|
||||||
|
11,11,12,12,13,13,14,14,15,15,16,16,17,17,18, \
|
||||||
|
18,19,19,20,20,21,21,22,22,23,23,24,24,25}
|
||||||
|
#elif DECDPUN==3
|
||||||
|
#define DECDPUNMAX 999
|
||||||
|
#define D2UTABLE {0,1,1,1,2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,7,7, \
|
||||||
|
8,8,8,9,9,9,10,10,10,11,11,11,12,12,12,13,13, \
|
||||||
|
13,14,14,14,15,15,15,16,16,16,17}
|
||||||
|
#elif DECDPUN==4
|
||||||
|
#define DECDPUNMAX 9999
|
||||||
|
#define D2UTABLE {0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6, \
|
||||||
|
6,6,6,7,7,7,7,8,8,8,8,9,9,9,9,10,10,10,10,11, \
|
||||||
|
11,11,11,12,12,12,12,13}
|
||||||
|
#elif DECDPUN==5
|
||||||
|
#define DECDPUNMAX 99999
|
||||||
|
#define D2UTABLE {0,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4,5, \
|
||||||
|
5,5,5,5,6,6,6,6,6,7,7,7,7,7,8,8,8,8,8,9,9,9, \
|
||||||
|
9,9,10,10,10,10}
|
||||||
|
#elif DECDPUN==6
|
||||||
|
#define DECDPUNMAX 999999
|
||||||
|
#define D2UTABLE {0,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,4,4,4, \
|
||||||
|
4,4,4,5,5,5,5,5,5,6,6,6,6,6,6,7,7,7,7,7,7,8, \
|
||||||
|
8,8,8,8,8,9}
|
||||||
|
#elif DECDPUN==7
|
||||||
|
#define DECDPUNMAX 9999999
|
||||||
|
#define D2UTABLE {0,1,1,1,1,1,1,1,2,2,2,2,2,2,2,3,3,3,3,3,3,3, \
|
||||||
|
4,4,4,4,4,4,4,5,5,5,5,5,5,5,6,6,6,6,6,6,6,7, \
|
||||||
|
7,7,7,7,7,7}
|
||||||
|
#elif DECDPUN==8
|
||||||
|
#define DECDPUNMAX 99999999
|
||||||
|
#define D2UTABLE {0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3, \
|
||||||
|
3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,6,6,6, \
|
||||||
|
6,6,6,6,6,7}
|
||||||
|
#elif DECDPUN==9
|
||||||
|
#define DECDPUNMAX 999999999
|
||||||
|
#define D2UTABLE {0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,3,3,3, \
|
||||||
|
3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5, \
|
||||||
|
5,5,6,6,6,6}
|
||||||
|
#elif defined(DECDPUN)
|
||||||
|
#error DECDPUN must be in the range 1-9
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ----- Shared data (in decNumber.c) ----- */
|
||||||
|
/* Public lookup table used by the D2U macro (see below) */
|
||||||
|
#define DECMAXD2U 49
|
||||||
|
extern const uByte d2utable[DECMAXD2U+1];
|
||||||
|
|
||||||
|
/* ----- Macros ----- */
|
||||||
|
/* ISZERO -- return true if decNumber dn is a zero */
|
||||||
|
/* [performance-critical in some situations] */
|
||||||
|
#define ISZERO(dn) decNumberIsZero(dn) /* now just a local name */
|
||||||
|
|
||||||
|
/* D2U -- return the number of Units needed to hold d digits */
|
||||||
|
/* (runtime version, with table lookaside for small d) */
|
||||||
|
#if DECDPUN==8
|
||||||
|
#define D2U(d) ((unsigned)((d)<=DECMAXD2U?d2utable[d]:((d)+7)>>3))
|
||||||
|
#elif DECDPUN==4
|
||||||
|
#define D2U(d) ((unsigned)((d)<=DECMAXD2U?d2utable[d]:((d)+3)>>2))
|
||||||
|
#else
|
||||||
|
#define D2U(d) ((d)<=DECMAXD2U?d2utable[d]:((d)+DECDPUN-1)/DECDPUN)
|
||||||
|
#endif
|
||||||
|
/* SD2U -- static D2U macro (for compile-time calculation) */
|
||||||
|
#define SD2U(d) (((d)+DECDPUN-1)/DECDPUN)
|
||||||
|
|
||||||
|
/* MSUDIGITS -- returns digits in msu, from digits, calculated */
|
||||||
|
/* using D2U */
|
||||||
|
#define MSUDIGITS(d) ((d)-(D2U(d)-1)*DECDPUN)
|
||||||
|
|
||||||
|
/* D2N -- return the number of decNumber structs that would be */
|
||||||
|
/* needed to contain that number of digits (and the initial */
|
||||||
|
/* decNumber struct) safely. Note that one Unit is included in the */
|
||||||
|
/* initial structure. Used for allocating space that is aligned on */
|
||||||
|
/* a decNumber struct boundary. */
|
||||||
|
#define D2N(d) \
|
||||||
|
((((SD2U(d)-1)*sizeof(Unit))+sizeof(decNumber)*2-1)/sizeof(decNumber))
|
||||||
|
|
||||||
|
/* TODIGIT -- macro to remove the leading digit from the unsigned */
|
||||||
|
/* integer u at column cut (counting from the right, LSD=0) and */
|
||||||
|
/* place it as an ASCII character into the character pointed to by */
|
||||||
|
/* c. Note that cut must be <= 9, and the maximum value for u is */
|
||||||
|
/* 2,000,000,000 (as is needed for negative exponents of */
|
||||||
|
/* subnormals). The unsigned integer pow is used as a temporary */
|
||||||
|
/* variable. */
|
||||||
|
#define TODIGIT(u, cut, c, pow) { \
|
||||||
|
*(c)='0'; \
|
||||||
|
pow=DECPOWERS[cut]*2; \
|
||||||
|
if ((u)>pow) { \
|
||||||
|
pow*=4; \
|
||||||
|
if ((u)>=pow) {(u)-=pow; *(c)+=8;} \
|
||||||
|
pow/=2; \
|
||||||
|
if ((u)>=pow) {(u)-=pow; *(c)+=4;} \
|
||||||
|
pow/=2; \
|
||||||
|
} \
|
||||||
|
if ((u)>=pow) {(u)-=pow; *(c)+=2;} \
|
||||||
|
pow/=2; \
|
||||||
|
if ((u)>=pow) {(u)-=pow; *(c)+=1;} \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------- */
|
||||||
|
/* Definitions for fixed-precision modules (only valid after */
|
||||||
|
/* decSingle.h, decDouble.h, or decQuad.h has been included) */
|
||||||
|
/* ---------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* bcdnum -- a structure describing a format-independent finite */
|
||||||
|
/* number, whose coefficient is a string of bcd8 uBytes */
|
||||||
|
typedef struct {
|
||||||
|
uByte *msd; /* -> most significant digit */
|
||||||
|
uByte *lsd; /* -> least ditto */
|
||||||
|
uInt sign; /* 0=positive, DECFLOAT_Sign=negative */
|
||||||
|
Int exponent; /* Unadjusted signed exponent (q), or */
|
||||||
|
/* DECFLOAT_NaN etc. for a special */
|
||||||
|
} bcdnum;
|
||||||
|
|
||||||
|
/* Test if exponent or bcdnum exponent must be a special, etc. */
|
||||||
|
#define EXPISSPECIAL(exp) ((exp)>=DECFLOAT_MinSp)
|
||||||
|
#define EXPISINF(exp) (exp==DECFLOAT_Inf)
|
||||||
|
#define EXPISNAN(exp) (exp==DECFLOAT_qNaN || exp==DECFLOAT_sNaN)
|
||||||
|
#define NUMISSPECIAL(num) (EXPISSPECIAL((num)->exponent))
|
||||||
|
|
||||||
|
/* Refer to a 32-bit word or byte in a decFloat (df) by big-endian */
|
||||||
|
/* (array) notation (the 0 word or byte contains the sign bit), */
|
||||||
|
/* automatically adjusting for endianness; similarly address a word */
|
||||||
|
/* in the next-wider format (decFloatWider, or dfw) */
|
||||||
|
#define DECWORDS (DECBYTES/4)
|
||||||
|
#define DECWWORDS (DECWBYTES/4)
|
||||||
|
#if DECLITEND
|
||||||
|
#define DFWORD(df, off) ((df)->words[DECWORDS-1-(off)])
|
||||||
|
#define DFBYTE(df, off) ((df)->bytes[DECBYTES-1-(off)])
|
||||||
|
#define DFWWORD(dfw, off) ((dfw)->words[DECWWORDS-1-(off)])
|
||||||
|
#else
|
||||||
|
#define DFWORD(df, off) ((df)->words[off])
|
||||||
|
#define DFBYTE(df, off) ((df)->bytes[off])
|
||||||
|
#define DFWWORD(dfw, off) ((dfw)->words[off])
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Tests for sign or specials, directly on DECFLOATs */
|
||||||
|
#define DFISSIGNED(df) (DFWORD(df, 0)&0x80000000)
|
||||||
|
#define DFISSPECIAL(df) ((DFWORD(df, 0)&0x78000000)==0x78000000)
|
||||||
|
#define DFISINF(df) ((DFWORD(df, 0)&0x7c000000)==0x78000000)
|
||||||
|
#define DFISNAN(df) ((DFWORD(df, 0)&0x7c000000)==0x7c000000)
|
||||||
|
#define DFISQNAN(df) ((DFWORD(df, 0)&0x7e000000)==0x7c000000)
|
||||||
|
#define DFISSNAN(df) ((DFWORD(df, 0)&0x7e000000)==0x7e000000)
|
||||||
|
|
||||||
|
/* Shared lookup tables */
|
||||||
|
extern const uInt DECCOMBMSD[64]; /* Combination field -> MSD */
|
||||||
|
extern const uInt DECCOMBFROM[48]; /* exp+msd -> Combination */
|
||||||
|
|
||||||
|
/* Private generic (utility) routine */
|
||||||
|
#if DECCHECK || DECTRACE
|
||||||
|
extern void decShowNum(const bcdnum *, const char *);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Format-dependent macros and constants */
|
||||||
|
#if defined(DECPMAX)
|
||||||
|
|
||||||
|
/* Useful constants */
|
||||||
|
#define DECPMAX9 (ROUNDUP(DECPMAX, 9)/9) /* 'Pmax' in 10**9s */
|
||||||
|
/* Top words for a zero */
|
||||||
|
#define SINGLEZERO 0x22500000
|
||||||
|
#define DOUBLEZERO 0x22380000
|
||||||
|
#define QUADZERO 0x22080000
|
||||||
|
/* [ZEROWORD is defined to be one of these in the DFISZERO macro] */
|
||||||
|
|
||||||
|
/* Format-dependent common tests: */
|
||||||
|
/* DFISZERO -- test for (any) zero */
|
||||||
|
/* DFISCCZERO -- test for coefficient continuation being zero */
|
||||||
|
/* DFISCC01 -- test for coefficient contains only 0s and 1s */
|
||||||
|
/* DFISINT -- test for finite and exponent q=0 */
|
||||||
|
/* DFISUINT01 -- test for sign=0, finite, exponent q=0, and */
|
||||||
|
/* MSD=0 or 1 */
|
||||||
|
/* ZEROWORD is also defined here. */
|
||||||
|
/* In DFISZERO the first test checks the least-significant word */
|
||||||
|
/* (most likely to be non-zero); the penultimate tests MSD and */
|
||||||
|
/* DPDs in the signword, and the final test excludes specials and */
|
||||||
|
/* MSD>7. DFISINT similarly has to allow for the two forms of */
|
||||||
|
/* MSD codes. DFISUINT01 only has to allow for one form of MSD */
|
||||||
|
/* code. */
|
||||||
|
#if DECPMAX==7
|
||||||
|
#define ZEROWORD SINGLEZERO
|
||||||
|
/* [test macros not needed except for Zero] */
|
||||||
|
#define DFISZERO(df) ((DFWORD(df, 0)&0x1c0fffff)==0 \
|
||||||
|
&& (DFWORD(df, 0)&0x60000000)!=0x60000000)
|
||||||
|
#elif DECPMAX==16
|
||||||
|
#define ZEROWORD DOUBLEZERO
|
||||||
|
#define DFISZERO(df) ((DFWORD(df, 1)==0 \
|
||||||
|
&& (DFWORD(df, 0)&0x1c03ffff)==0 \
|
||||||
|
&& (DFWORD(df, 0)&0x60000000)!=0x60000000))
|
||||||
|
#define DFISINT(df) ((DFWORD(df, 0)&0x63fc0000)==0x22380000 \
|
||||||
|
||(DFWORD(df, 0)&0x7bfc0000)==0x6a380000)
|
||||||
|
#define DFISUINT01(df) ((DFWORD(df, 0)&0xfbfc0000)==0x22380000)
|
||||||
|
#define DFISCCZERO(df) (DFWORD(df, 1)==0 \
|
||||||
|
&& (DFWORD(df, 0)&0x0003ffff)==0)
|
||||||
|
#define DFISCC01(df) ((DFWORD(df, 0)&~0xfffc9124)==0 \
|
||||||
|
&& (DFWORD(df, 1)&~0x49124491)==0)
|
||||||
|
#elif DECPMAX==34
|
||||||
|
#define ZEROWORD QUADZERO
|
||||||
|
#define DFISZERO(df) ((DFWORD(df, 3)==0 \
|
||||||
|
&& DFWORD(df, 2)==0 \
|
||||||
|
&& DFWORD(df, 1)==0 \
|
||||||
|
&& (DFWORD(df, 0)&0x1c003fff)==0 \
|
||||||
|
&& (DFWORD(df, 0)&0x60000000)!=0x60000000))
|
||||||
|
#define DFISINT(df) ((DFWORD(df, 0)&0x63ffc000)==0x22080000 \
|
||||||
|
||(DFWORD(df, 0)&0x7bffc000)==0x6a080000)
|
||||||
|
#define DFISUINT01(df) ((DFWORD(df, 0)&0xfbffc000)==0x22080000)
|
||||||
|
#define DFISCCZERO(df) (DFWORD(df, 3)==0 \
|
||||||
|
&& DFWORD(df, 2)==0 \
|
||||||
|
&& DFWORD(df, 1)==0 \
|
||||||
|
&& (DFWORD(df, 0)&0x00003fff)==0)
|
||||||
|
|
||||||
|
#define DFISCC01(df) ((DFWORD(df, 0)&~0xffffc912)==0 \
|
||||||
|
&& (DFWORD(df, 1)&~0x44912449)==0 \
|
||||||
|
&& (DFWORD(df, 2)&~0x12449124)==0 \
|
||||||
|
&& (DFWORD(df, 3)&~0x49124491)==0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Macros to test if a certain 10 bits of a uInt or pair of uInts */
|
||||||
|
/* are a canonical declet [higher or lower bits are ignored]. */
|
||||||
|
/* declet is at offset 0 (from the right) in a uInt: */
|
||||||
|
#define CANONDPD(dpd) (((dpd)&0x300)==0 || ((dpd)&0x6e)!=0x6e)
|
||||||
|
/* declet is at offset k (a multiple of 2) in a uInt: */
|
||||||
|
#define CANONDPDOFF(dpd, k) (((dpd)&(0x300<<(k)))==0 \
|
||||||
|
|| ((dpd)&(((uInt)0x6e)<<(k)))!=(((uInt)0x6e)<<(k)))
|
||||||
|
/* declet is at offset k (a multiple of 2) in a pair of uInts: */
|
||||||
|
/* [the top 2 bits will always be in the more-significant uInt] */
|
||||||
|
#define CANONDPDTWO(hi, lo, k) (((hi)&(0x300>>(32-(k))))==0 \
|
||||||
|
|| ((hi)&(0x6e>>(32-(k))))!=(0x6e>>(32-(k))) \
|
||||||
|
|| ((lo)&(((uInt)0x6e)<<(k)))!=(((uInt)0x6e)<<(k)))
|
||||||
|
|
||||||
|
/* Macro to test whether a full-length (length DECPMAX) BCD8 */
|
||||||
|
/* coefficient is zero */
|
||||||
|
/* test just the LSWord first, then the remainder */
|
||||||
|
#if DECPMAX==7
|
||||||
|
#define ISCOEFFZERO(u) (UINTAT((u)+DECPMAX-4)==0 \
|
||||||
|
&& UINTAT((u)+DECPMAX-7)==0)
|
||||||
|
#elif DECPMAX==16
|
||||||
|
#define ISCOEFFZERO(u) (UINTAT((u)+DECPMAX-4)==0 \
|
||||||
|
&& (UINTAT((u)+DECPMAX-8)+UINTAT((u)+DECPMAX-12) \
|
||||||
|
+UINTAT((u)+DECPMAX-16))==0)
|
||||||
|
#elif DECPMAX==34
|
||||||
|
#define ISCOEFFZERO(u) (UINTAT((u)+DECPMAX-4)==0 \
|
||||||
|
&& (UINTAT((u)+DECPMAX-8) +UINTAT((u)+DECPMAX-12) \
|
||||||
|
+UINTAT((u)+DECPMAX-16)+UINTAT((u)+DECPMAX-20) \
|
||||||
|
+UINTAT((u)+DECPMAX-24)+UINTAT((u)+DECPMAX-28) \
|
||||||
|
+UINTAT((u)+DECPMAX-32)+USHORTAT((u)+DECPMAX-34))==0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Macros and masks for the exponent continuation field and MSD */
|
||||||
|
/* Get the exponent continuation from a decFloat *df as an Int */
|
||||||
|
#define GETECON(df) ((Int)((DFWORD((df), 0)&0x03ffffff)>>(32-6-DECECONL)))
|
||||||
|
/* Ditto, from the next-wider format */
|
||||||
|
#define GETWECON(df) ((Int)((DFWWORD((df), 0)&0x03ffffff)>>(32-6-DECWECONL)))
|
||||||
|
/* Get the biased exponent similarly */
|
||||||
|
#define GETEXP(df) ((Int)(DECCOMBEXP[DFWORD((df), 0)>>26]+GETECON(df)))
|
||||||
|
/* Get the unbiased exponent similarly */
|
||||||
|
#define GETEXPUN(df) ((Int)GETEXP(df)-DECBIAS)
|
||||||
|
/* Get the MSD similarly (as uInt) */
|
||||||
|
#define GETMSD(df) (DECCOMBMSD[DFWORD((df), 0)>>26])
|
||||||
|
|
||||||
|
/* Compile-time computes of the exponent continuation field masks */
|
||||||
|
/* full exponent continuation field: */
|
||||||
|
#define ECONMASK ((0x03ffffff>>(32-6-DECECONL))<<(32-6-DECECONL))
|
||||||
|
/* same, not including its first digit (the qNaN/sNaN selector): */
|
||||||
|
#define ECONNANMASK ((0x01ffffff>>(32-6-DECECONL))<<(32-6-DECECONL))
|
||||||
|
|
||||||
|
/* Macros to decode the coefficient in a finite decFloat *df into */
|
||||||
|
/* a BCD string (uByte *bcdin) of length DECPMAX uBytes */
|
||||||
|
|
||||||
|
/* In-line sequence to convert 10 bits at right end of uInt dpd */
|
||||||
|
/* to three BCD8 digits starting at uByte u. Note that an extra */
|
||||||
|
/* byte is written to the right of the three digits because this */
|
||||||
|
/* moves four at a time for speed; the alternative macro moves */
|
||||||
|
/* exactly three bytes */
|
||||||
|
#define dpd2bcd8(u, dpd) { \
|
||||||
|
UINTAT(u)=UINTAT(&DPD2BCD8[((dpd)&0x3ff)*4]);}
|
||||||
|
|
||||||
|
#define dpd2bcd83(u, dpd) { \
|
||||||
|
*(u)=DPD2BCD8[((dpd)&0x3ff)*4]; \
|
||||||
|
*(u+1)=DPD2BCD8[((dpd)&0x3ff)*4+1]; \
|
||||||
|
*(u+2)=DPD2BCD8[((dpd)&0x3ff)*4+2];}
|
||||||
|
|
||||||
|
/* Decode the declets. After extracting each one, it is decoded */
|
||||||
|
/* to BCD8 using a table lookup (also used for variable-length */
|
||||||
|
/* decode). Each DPD decode is 3 bytes BCD8 plus a one-byte */
|
||||||
|
/* length which is not used, here). Fixed-length 4-byte moves */
|
||||||
|
/* are fast, however, almost everywhere, and so are used except */
|
||||||
|
/* for the final three bytes (to avoid overrun). The code below */
|
||||||
|
/* is 36 instructions for Doubles and about 70 for Quads, even */
|
||||||
|
/* on IA32. */
|
||||||
|
|
||||||
|
/* Two macros are defined for each format: */
|
||||||
|
/* GETCOEFF extracts the coefficient of the current format */
|
||||||
|
/* GETWCOEFF extracts the coefficient of the next-wider format. */
|
||||||
|
/* The latter is a copy of the next-wider GETCOEFF using DFWWORD. */
|
||||||
|
|
||||||
|
#if DECPMAX==7
|
||||||
|
#define GETCOEFF(df, bcd) { \
|
||||||
|
uInt sourhi=DFWORD(df, 0); \
|
||||||
|
*(bcd)=(uByte)DECCOMBMSD[sourhi>>26]; \
|
||||||
|
dpd2bcd8(bcd+1, sourhi>>10); \
|
||||||
|
dpd2bcd83(bcd+4, sourhi);}
|
||||||
|
#define GETWCOEFF(df, bcd) { \
|
||||||
|
uInt sourhi=DFWWORD(df, 0); \
|
||||||
|
uInt sourlo=DFWWORD(df, 1); \
|
||||||
|
*(bcd)=(uByte)DECCOMBMSD[sourhi>>26]; \
|
||||||
|
dpd2bcd8(bcd+1, sourhi>>8); \
|
||||||
|
dpd2bcd8(bcd+4, (sourhi<<2) | (sourlo>>30)); \
|
||||||
|
dpd2bcd8(bcd+7, sourlo>>20); \
|
||||||
|
dpd2bcd8(bcd+10, sourlo>>10); \
|
||||||
|
dpd2bcd83(bcd+13, sourlo);}
|
||||||
|
|
||||||
|
#elif DECPMAX==16
|
||||||
|
#define GETCOEFF(df, bcd) { \
|
||||||
|
uInt sourhi=DFWORD(df, 0); \
|
||||||
|
uInt sourlo=DFWORD(df, 1); \
|
||||||
|
*(bcd)=(uByte)DECCOMBMSD[sourhi>>26]; \
|
||||||
|
dpd2bcd8(bcd+1, sourhi>>8); \
|
||||||
|
dpd2bcd8(bcd+4, (sourhi<<2) | (sourlo>>30)); \
|
||||||
|
dpd2bcd8(bcd+7, sourlo>>20); \
|
||||||
|
dpd2bcd8(bcd+10, sourlo>>10); \
|
||||||
|
dpd2bcd83(bcd+13, sourlo);}
|
||||||
|
#define GETWCOEFF(df, bcd) { \
|
||||||
|
uInt sourhi=DFWWORD(df, 0); \
|
||||||
|
uInt sourmh=DFWWORD(df, 1); \
|
||||||
|
uInt sourml=DFWWORD(df, 2); \
|
||||||
|
uInt sourlo=DFWWORD(df, 3); \
|
||||||
|
*(bcd)=(uByte)DECCOMBMSD[sourhi>>26]; \
|
||||||
|
dpd2bcd8(bcd+1, sourhi>>4); \
|
||||||
|
dpd2bcd8(bcd+4, ((sourhi)<<6) | (sourmh>>26)); \
|
||||||
|
dpd2bcd8(bcd+7, sourmh>>16); \
|
||||||
|
dpd2bcd8(bcd+10, sourmh>>6); \
|
||||||
|
dpd2bcd8(bcd+13, ((sourmh)<<4) | (sourml>>28)); \
|
||||||
|
dpd2bcd8(bcd+16, sourml>>18); \
|
||||||
|
dpd2bcd8(bcd+19, sourml>>8); \
|
||||||
|
dpd2bcd8(bcd+22, ((sourml)<<2) | (sourlo>>30)); \
|
||||||
|
dpd2bcd8(bcd+25, sourlo>>20); \
|
||||||
|
dpd2bcd8(bcd+28, sourlo>>10); \
|
||||||
|
dpd2bcd83(bcd+31, sourlo);}
|
||||||
|
|
||||||
|
#elif DECPMAX==34
|
||||||
|
#define GETCOEFF(df, bcd) { \
|
||||||
|
uInt sourhi=DFWORD(df, 0); \
|
||||||
|
uInt sourmh=DFWORD(df, 1); \
|
||||||
|
uInt sourml=DFWORD(df, 2); \
|
||||||
|
uInt sourlo=DFWORD(df, 3); \
|
||||||
|
*(bcd)=(uByte)DECCOMBMSD[sourhi>>26]; \
|
||||||
|
dpd2bcd8(bcd+1, sourhi>>4); \
|
||||||
|
dpd2bcd8(bcd+4, ((sourhi)<<6) | (sourmh>>26)); \
|
||||||
|
dpd2bcd8(bcd+7, sourmh>>16); \
|
||||||
|
dpd2bcd8(bcd+10, sourmh>>6); \
|
||||||
|
dpd2bcd8(bcd+13, ((sourmh)<<4) | (sourml>>28)); \
|
||||||
|
dpd2bcd8(bcd+16, sourml>>18); \
|
||||||
|
dpd2bcd8(bcd+19, sourml>>8); \
|
||||||
|
dpd2bcd8(bcd+22, ((sourml)<<2) | (sourlo>>30)); \
|
||||||
|
dpd2bcd8(bcd+25, sourlo>>20); \
|
||||||
|
dpd2bcd8(bcd+28, sourlo>>10); \
|
||||||
|
dpd2bcd83(bcd+31, sourlo);}
|
||||||
|
|
||||||
|
#define GETWCOEFF(df, bcd) {??} /* [should never be used] */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Macros to decode the coefficient in a finite decFloat *df into */
|
||||||
|
/* a base-billion uInt array, with the least-significant */
|
||||||
|
/* 0-999999999 'digit' at offset 0. */
|
||||||
|
|
||||||
|
/* Decode the declets. After extracting each one, it is decoded */
|
||||||
|
/* to binary using a table lookup. Three tables are used; one */
|
||||||
|
/* the usual DPD to binary, the other two pre-multiplied by 1000 */
|
||||||
|
/* and 1000000 to avoid multiplication during decode. These */
|
||||||
|
/* tables can also be used for multiplying up the MSD as the DPD */
|
||||||
|
/* code for 0 through 9 is the identity. */
|
||||||
|
#define DPD2BIN0 DPD2BIN /* for prettier code */
|
||||||
|
|
||||||
|
#if DECPMAX==7
|
||||||
|
#define GETCOEFFBILL(df, buf) { \
|
||||||
|
uInt sourhi=DFWORD(df, 0); \
|
||||||
|
(buf)[0]=DPD2BIN0[sourhi&0x3ff] \
|
||||||
|
+DPD2BINK[(sourhi>>10)&0x3ff] \
|
||||||
|
+DPD2BINM[DECCOMBMSD[sourhi>>26]];}
|
||||||
|
|
||||||
|
#elif DECPMAX==16
|
||||||
|
#define GETCOEFFBILL(df, buf) { \
|
||||||
|
uInt sourhi, sourlo; \
|
||||||
|
sourlo=DFWORD(df, 1); \
|
||||||
|
(buf)[0]=DPD2BIN0[sourlo&0x3ff] \
|
||||||
|
+DPD2BINK[(sourlo>>10)&0x3ff] \
|
||||||
|
+DPD2BINM[(sourlo>>20)&0x3ff]; \
|
||||||
|
sourhi=DFWORD(df, 0); \
|
||||||
|
(buf)[1]=DPD2BIN0[((sourhi<<2) | (sourlo>>30))&0x3ff] \
|
||||||
|
+DPD2BINK[(sourhi>>8)&0x3ff] \
|
||||||
|
+DPD2BINM[DECCOMBMSD[sourhi>>26]];}
|
||||||
|
|
||||||
|
#elif DECPMAX==34
|
||||||
|
#define GETCOEFFBILL(df, buf) { \
|
||||||
|
uInt sourhi, sourmh, sourml, sourlo; \
|
||||||
|
sourlo=DFWORD(df, 3); \
|
||||||
|
(buf)[0]=DPD2BIN0[sourlo&0x3ff] \
|
||||||
|
+DPD2BINK[(sourlo>>10)&0x3ff] \
|
||||||
|
+DPD2BINM[(sourlo>>20)&0x3ff]; \
|
||||||
|
sourml=DFWORD(df, 2); \
|
||||||
|
(buf)[1]=DPD2BIN0[((sourml<<2) | (sourlo>>30))&0x3ff] \
|
||||||
|
+DPD2BINK[(sourml>>8)&0x3ff] \
|
||||||
|
+DPD2BINM[(sourml>>18)&0x3ff]; \
|
||||||
|
sourmh=DFWORD(df, 1); \
|
||||||
|
(buf)[2]=DPD2BIN0[((sourmh<<4) | (sourml>>28))&0x3ff] \
|
||||||
|
+DPD2BINK[(sourmh>>6)&0x3ff] \
|
||||||
|
+DPD2BINM[(sourmh>>16)&0x3ff]; \
|
||||||
|
sourhi=DFWORD(df, 0); \
|
||||||
|
(buf)[3]=DPD2BIN0[((sourhi<<6) | (sourmh>>26))&0x3ff] \
|
||||||
|
+DPD2BINK[(sourhi>>4)&0x3ff] \
|
||||||
|
+DPD2BINM[DECCOMBMSD[sourhi>>26]];}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Macros to decode the coefficient in a finite decFloat *df into */
|
||||||
|
/* a base-thousand uInt array, with the least-significant 0-999 */
|
||||||
|
/* 'digit' at offset 0. */
|
||||||
|
|
||||||
|
/* Decode the declets. After extracting each one, it is decoded */
|
||||||
|
/* to binary using a table lookup. */
|
||||||
|
#if DECPMAX==7
|
||||||
|
#define GETCOEFFTHOU(df, buf) { \
|
||||||
|
uInt sourhi=DFWORD(df, 0); \
|
||||||
|
(buf)[0]=DPD2BIN[sourhi&0x3ff]; \
|
||||||
|
(buf)[1]=DPD2BIN[(sourhi>>10)&0x3ff]; \
|
||||||
|
(buf)[2]=DECCOMBMSD[sourhi>>26];}
|
||||||
|
|
||||||
|
#elif DECPMAX==16
|
||||||
|
#define GETCOEFFTHOU(df, buf) { \
|
||||||
|
uInt sourhi, sourlo; \
|
||||||
|
sourlo=DFWORD(df, 1); \
|
||||||
|
(buf)[0]=DPD2BIN[sourlo&0x3ff]; \
|
||||||
|
(buf)[1]=DPD2BIN[(sourlo>>10)&0x3ff]; \
|
||||||
|
(buf)[2]=DPD2BIN[(sourlo>>20)&0x3ff]; \
|
||||||
|
sourhi=DFWORD(df, 0); \
|
||||||
|
(buf)[3]=DPD2BIN[((sourhi<<2) | (sourlo>>30))&0x3ff]; \
|
||||||
|
(buf)[4]=DPD2BIN[(sourhi>>8)&0x3ff]; \
|
||||||
|
(buf)[5]=DECCOMBMSD[sourhi>>26];}
|
||||||
|
|
||||||
|
#elif DECPMAX==34
|
||||||
|
#define GETCOEFFTHOU(df, buf) { \
|
||||||
|
uInt sourhi, sourmh, sourml, sourlo; \
|
||||||
|
sourlo=DFWORD(df, 3); \
|
||||||
|
(buf)[0]=DPD2BIN[sourlo&0x3ff]; \
|
||||||
|
(buf)[1]=DPD2BIN[(sourlo>>10)&0x3ff]; \
|
||||||
|
(buf)[2]=DPD2BIN[(sourlo>>20)&0x3ff]; \
|
||||||
|
sourml=DFWORD(df, 2); \
|
||||||
|
(buf)[3]=DPD2BIN[((sourml<<2) | (sourlo>>30))&0x3ff]; \
|
||||||
|
(buf)[4]=DPD2BIN[(sourml>>8)&0x3ff]; \
|
||||||
|
(buf)[5]=DPD2BIN[(sourml>>18)&0x3ff]; \
|
||||||
|
sourmh=DFWORD(df, 1); \
|
||||||
|
(buf)[6]=DPD2BIN[((sourmh<<4) | (sourml>>28))&0x3ff]; \
|
||||||
|
(buf)[7]=DPD2BIN[(sourmh>>6)&0x3ff]; \
|
||||||
|
(buf)[8]=DPD2BIN[(sourmh>>16)&0x3ff]; \
|
||||||
|
sourhi=DFWORD(df, 0); \
|
||||||
|
(buf)[9]=DPD2BIN[((sourhi<<6) | (sourmh>>26))&0x3ff]; \
|
||||||
|
(buf)[10]=DPD2BIN[(sourhi>>4)&0x3ff]; \
|
||||||
|
(buf)[11]=DECCOMBMSD[sourhi>>26];}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Set a decFloat to the maximum positive finite number (Nmax) */
|
||||||
|
#if DECPMAX==7
|
||||||
|
#define DFSETNMAX(df) \
|
||||||
|
{DFWORD(df, 0)=0x77f3fcff;}
|
||||||
|
#elif DECPMAX==16
|
||||||
|
#define DFSETNMAX(df) \
|
||||||
|
{DFWORD(df, 0)=0x77fcff3f; \
|
||||||
|
DFWORD(df, 1)=0xcff3fcff;}
|
||||||
|
#elif DECPMAX==34
|
||||||
|
#define DFSETNMAX(df) \
|
||||||
|
{DFWORD(df, 0)=0x77ffcff3; \
|
||||||
|
DFWORD(df, 1)=0xfcff3fcf; \
|
||||||
|
DFWORD(df, 2)=0xf3fcff3f; \
|
||||||
|
DFWORD(df, 3)=0xcff3fcff;}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* [end of format-dependent macros and constants] */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error decNumberLocal included more than once
|
||||||
|
#endif
|
100
include/libdecnumber/dpd/decimal128.h
Normal file
100
include/libdecnumber/dpd/decimal128.h
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
/* 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
|
47
include/libdecnumber/dpd/decimal128Local.h
Normal file
47
include/libdecnumber/dpd/decimal128Local.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/* 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
|
98
include/libdecnumber/dpd/decimal32.h
Normal file
98
include/libdecnumber/dpd/decimal32.h
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
/* 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
|
100
include/libdecnumber/dpd/decimal64.h
Normal file
100
include/libdecnumber/dpd/decimal64.h
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
/* 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,
|
const unsigned long length, const AES_KEY *key,
|
||||||
unsigned char *ivec, const int enc);
|
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_Te0[x] = S [x].[02, 01, 01, 03];
|
||||||
AES_Te1[x] = S [x].[03, 02, 01, 01];
|
AES_Te1[x] = S [x].[03, 02, 01, 01];
|
||||||
|
|
28
include/sysemu/dump-arch.h
Normal file
28
include/sysemu/dump-arch.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* 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 PFN_BUFBITMAP (CHAR_BIT * BUFSIZE_BITMAP)
|
||||||
#define BUFSIZE_DATA_CACHE (TARGET_PAGE_SIZE * 4)
|
#define BUFSIZE_DATA_CACHE (TARGET_PAGE_SIZE * 4)
|
||||||
|
|
||||||
typedef struct ArchDumpInfo {
|
#include "sysemu/dump-arch.h"
|
||||||
int d_machine; /* Architecture */
|
#include "sysemu/memory_mapping.h"
|
||||||
int d_endian; /* ELFDATA2LSB or ELFDATA2MSB */
|
|
||||||
int d_class; /* ELFCLASS32 or ELFCLASS64 */
|
|
||||||
} ArchDumpInfo;
|
|
||||||
|
|
||||||
typedef struct QEMU_PACKED MakedumpfileHeader {
|
typedef struct QEMU_PACKED MakedumpfileHeader {
|
||||||
char signature[16]; /* = "makedumpfile" */
|
char signature[16]; /* = "makedumpfile" */
|
||||||
|
@ -158,9 +155,37 @@ typedef struct QEMU_PACKED PageDescriptor {
|
||||||
uint64_t page_flags; /* page flags */
|
uint64_t page_flags; /* page flags */
|
||||||
} PageDescriptor;
|
} PageDescriptor;
|
||||||
|
|
||||||
struct GuestPhysBlockList; /* memory_mapping.h */
|
typedef struct DumpState {
|
||||||
int cpu_get_dump_info(ArchDumpInfo *info,
|
GuestPhysBlockList guest_phys_blocks;
|
||||||
const struct GuestPhysBlockList *guest_phys_blocks);
|
ArchDumpInfo dump_info;
|
||||||
ssize_t cpu_get_note_size(int class, int machine, int nr_cpus);
|
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
|
#endif
|
||||||
|
|
433
libdecnumber/decContext.c
Normal file
433
libdecnumber/decContext.c
Normal file
|
@ -0,0 +1,433 @@
|
||||||
|
/* Decimal context 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 */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* This module comprises the routines for handling arithmetic */
|
||||||
|
/* context structures. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
#include <string.h> /* for strcmp */
|
||||||
|
#include <stdio.h> /* for printf if DECCHECK */
|
||||||
|
#include "libdecnumber/dconfig.h"
|
||||||
|
#include "libdecnumber/decContext.h"
|
||||||
|
#include "libdecnumber/decNumberLocal.h"
|
||||||
|
|
||||||
|
#if DECCHECK
|
||||||
|
/* compile-time endian tester [assumes sizeof(Int)>1] */
|
||||||
|
static const Int mfcone=1; /* constant 1 */
|
||||||
|
static const Flag *mfctop=(Flag *)&mfcone; /* -> top byte */
|
||||||
|
#define LITEND *mfctop /* named flag; 1=little-endian */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* round-for-reround digits */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
const uByte DECSTICKYTAB[10]={1,1,2,3,4,6,6,7,8,9}; /* used if sticky */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* Powers of ten (powers[n]==10**n, 0<=n<=9) */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
const uLong DECPOWERS[19] = {1, 10, 100, 1000, 10000, 100000, 1000000,
|
||||||
|
10000000, 100000000, 1000000000, 10000000000ULL, 100000000000ULL,
|
||||||
|
1000000000000ULL, 10000000000000ULL, 100000000000000ULL, 1000000000000000ULL,
|
||||||
|
10000000000000000ULL, 100000000000000000ULL, 1000000000000000000ULL, };
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decContextClearStatus -- clear bits in current status */
|
||||||
|
/* */
|
||||||
|
/* context is the context structure to be queried */
|
||||||
|
/* mask indicates the bits to be cleared (the status bit that */
|
||||||
|
/* corresponds to each 1 bit in the mask is cleared) */
|
||||||
|
/* returns context */
|
||||||
|
/* */
|
||||||
|
/* No error is possible. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
decContext *decContextClearStatus(decContext *context, uInt mask) {
|
||||||
|
context->status&=~mask;
|
||||||
|
return context;
|
||||||
|
} /* decContextClearStatus */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decContextDefault -- initialize a context structure */
|
||||||
|
/* */
|
||||||
|
/* context is the structure to be initialized */
|
||||||
|
/* kind selects the required set of default values, one of: */
|
||||||
|
/* DEC_INIT_BASE -- select ANSI X3-274 defaults */
|
||||||
|
/* DEC_INIT_DECIMAL32 -- select IEEE 754r defaults, 32-bit */
|
||||||
|
/* DEC_INIT_DECIMAL64 -- select IEEE 754r defaults, 64-bit */
|
||||||
|
/* DEC_INIT_DECIMAL128 -- select IEEE 754r defaults, 128-bit */
|
||||||
|
/* For any other value a valid context is returned, but with */
|
||||||
|
/* Invalid_operation set in the status field. */
|
||||||
|
/* returns a context structure with the appropriate initial values. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
decContext * decContextDefault(decContext *context, Int kind) {
|
||||||
|
/* set defaults... */
|
||||||
|
context->digits=9; /* 9 digits */
|
||||||
|
context->emax=DEC_MAX_EMAX; /* 9-digit exponents */
|
||||||
|
context->emin=DEC_MIN_EMIN; /* .. balanced */
|
||||||
|
context->round=DEC_ROUND_HALF_UP; /* 0.5 rises */
|
||||||
|
context->traps=DEC_Errors; /* all but informational */
|
||||||
|
context->status=0; /* cleared */
|
||||||
|
context->clamp=0; /* no clamping */
|
||||||
|
#if DECSUBSET
|
||||||
|
context->extended=0; /* cleared */
|
||||||
|
#endif
|
||||||
|
switch (kind) {
|
||||||
|
case DEC_INIT_BASE:
|
||||||
|
/* [use defaults] */
|
||||||
|
break;
|
||||||
|
case DEC_INIT_DECIMAL32:
|
||||||
|
context->digits=7; /* digits */
|
||||||
|
context->emax=96; /* Emax */
|
||||||
|
context->emin=-95; /* Emin */
|
||||||
|
context->round=DEC_ROUND_HALF_EVEN; /* 0.5 to nearest even */
|
||||||
|
context->traps=0; /* no traps set */
|
||||||
|
context->clamp=1; /* clamp exponents */
|
||||||
|
#if DECSUBSET
|
||||||
|
context->extended=1; /* set */
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case DEC_INIT_DECIMAL64:
|
||||||
|
context->digits=16; /* digits */
|
||||||
|
context->emax=384; /* Emax */
|
||||||
|
context->emin=-383; /* Emin */
|
||||||
|
context->round=DEC_ROUND_HALF_EVEN; /* 0.5 to nearest even */
|
||||||
|
context->traps=0; /* no traps set */
|
||||||
|
context->clamp=1; /* clamp exponents */
|
||||||
|
#if DECSUBSET
|
||||||
|
context->extended=1; /* set */
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case DEC_INIT_DECIMAL128:
|
||||||
|
context->digits=34; /* digits */
|
||||||
|
context->emax=6144; /* Emax */
|
||||||
|
context->emin=-6143; /* Emin */
|
||||||
|
context->round=DEC_ROUND_HALF_EVEN; /* 0.5 to nearest even */
|
||||||
|
context->traps=0; /* no traps set */
|
||||||
|
context->clamp=1; /* clamp exponents */
|
||||||
|
#if DECSUBSET
|
||||||
|
context->extended=1; /* set */
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: /* invalid Kind */
|
||||||
|
/* use defaults, and .. */
|
||||||
|
decContextSetStatus(context, DEC_Invalid_operation); /* trap */
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DECCHECK
|
||||||
|
if (LITEND!=DECLITEND) {
|
||||||
|
const char *adj;
|
||||||
|
if (LITEND) adj="little";
|
||||||
|
else adj="big";
|
||||||
|
printf("Warning: DECLITEND is set to %d, but this computer appears to be %s-endian\n",
|
||||||
|
DECLITEND, adj);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return context;} /* decContextDefault */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decContextGetRounding -- return current rounding mode */
|
||||||
|
/* */
|
||||||
|
/* context is the context structure to be queried */
|
||||||
|
/* returns the rounding mode */
|
||||||
|
/* */
|
||||||
|
/* No error is possible. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
enum rounding decContextGetRounding(decContext *context) {
|
||||||
|
return context->round;
|
||||||
|
} /* decContextGetRounding */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decContextGetStatus -- return current status */
|
||||||
|
/* */
|
||||||
|
/* context is the context structure to be queried */
|
||||||
|
/* returns status */
|
||||||
|
/* */
|
||||||
|
/* No error is possible. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
uInt decContextGetStatus(decContext *context) {
|
||||||
|
return context->status;
|
||||||
|
} /* decContextGetStatus */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decContextRestoreStatus -- restore bits in current status */
|
||||||
|
/* */
|
||||||
|
/* context is the context structure to be updated */
|
||||||
|
/* newstatus is the source for the bits to be restored */
|
||||||
|
/* mask indicates the bits to be restored (the status bit that */
|
||||||
|
/* corresponds to each 1 bit in the mask is set to the value of */
|
||||||
|
/* the correspnding bit in newstatus) */
|
||||||
|
/* returns context */
|
||||||
|
/* */
|
||||||
|
/* No error is possible. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
decContext *decContextRestoreStatus(decContext *context,
|
||||||
|
uInt newstatus, uInt mask) {
|
||||||
|
context->status&=~mask; /* clear the selected bits */
|
||||||
|
context->status|=(mask&newstatus); /* or in the new bits */
|
||||||
|
return context;
|
||||||
|
} /* decContextRestoreStatus */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decContextSaveStatus -- save bits in current status */
|
||||||
|
/* */
|
||||||
|
/* context is the context structure to be queried */
|
||||||
|
/* mask indicates the bits to be saved (the status bits that */
|
||||||
|
/* correspond to each 1 bit in the mask are saved) */
|
||||||
|
/* returns the AND of the mask and the current status */
|
||||||
|
/* */
|
||||||
|
/* No error is possible. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
uInt decContextSaveStatus(decContext *context, uInt mask) {
|
||||||
|
return context->status&mask;
|
||||||
|
} /* decContextSaveStatus */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decContextSetRounding -- set current rounding mode */
|
||||||
|
/* */
|
||||||
|
/* context is the context structure to be updated */
|
||||||
|
/* newround is the value which will replace the current mode */
|
||||||
|
/* returns context */
|
||||||
|
/* */
|
||||||
|
/* No error is possible. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
decContext *decContextSetRounding(decContext *context,
|
||||||
|
enum rounding newround) {
|
||||||
|
context->round=newround;
|
||||||
|
return context;
|
||||||
|
} /* decContextSetRounding */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decContextSetStatus -- set status and raise trap if appropriate */
|
||||||
|
/* */
|
||||||
|
/* context is the context structure to be updated */
|
||||||
|
/* status is the DEC_ exception code */
|
||||||
|
/* returns the context structure */
|
||||||
|
/* */
|
||||||
|
/* Control may never return from this routine, if there is a signal */
|
||||||
|
/* handler and it takes a long jump. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
decContext * decContextSetStatus(decContext *context, uInt status) {
|
||||||
|
context->status|=status;
|
||||||
|
if (status & context->traps) raise(SIGFPE);
|
||||||
|
return context;} /* decContextSetStatus */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decContextSetStatusFromString -- set status from a string + trap */
|
||||||
|
/* */
|
||||||
|
/* context is the context structure to be updated */
|
||||||
|
/* string is a string exactly equal to one that might be returned */
|
||||||
|
/* by decContextStatusToString */
|
||||||
|
/* */
|
||||||
|
/* The status bit corresponding to the string is set, and a trap */
|
||||||
|
/* is raised if appropriate. */
|
||||||
|
/* */
|
||||||
|
/* returns the context structure, unless the string is equal to */
|
||||||
|
/* DEC_Condition_MU or is not recognized. In these cases NULL is */
|
||||||
|
/* returned. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
decContext * decContextSetStatusFromString(decContext *context,
|
||||||
|
const char *string) {
|
||||||
|
if (strcmp(string, DEC_Condition_CS)==0)
|
||||||
|
return decContextSetStatus(context, DEC_Conversion_syntax);
|
||||||
|
if (strcmp(string, DEC_Condition_DZ)==0)
|
||||||
|
return decContextSetStatus(context, DEC_Division_by_zero);
|
||||||
|
if (strcmp(string, DEC_Condition_DI)==0)
|
||||||
|
return decContextSetStatus(context, DEC_Division_impossible);
|
||||||
|
if (strcmp(string, DEC_Condition_DU)==0)
|
||||||
|
return decContextSetStatus(context, DEC_Division_undefined);
|
||||||
|
if (strcmp(string, DEC_Condition_IE)==0)
|
||||||
|
return decContextSetStatus(context, DEC_Inexact);
|
||||||
|
if (strcmp(string, DEC_Condition_IS)==0)
|
||||||
|
return decContextSetStatus(context, DEC_Insufficient_storage);
|
||||||
|
if (strcmp(string, DEC_Condition_IC)==0)
|
||||||
|
return decContextSetStatus(context, DEC_Invalid_context);
|
||||||
|
if (strcmp(string, DEC_Condition_IO)==0)
|
||||||
|
return decContextSetStatus(context, DEC_Invalid_operation);
|
||||||
|
#if DECSUBSET
|
||||||
|
if (strcmp(string, DEC_Condition_LD)==0)
|
||||||
|
return decContextSetStatus(context, DEC_Lost_digits);
|
||||||
|
#endif
|
||||||
|
if (strcmp(string, DEC_Condition_OV)==0)
|
||||||
|
return decContextSetStatus(context, DEC_Overflow);
|
||||||
|
if (strcmp(string, DEC_Condition_PA)==0)
|
||||||
|
return decContextSetStatus(context, DEC_Clamped);
|
||||||
|
if (strcmp(string, DEC_Condition_RO)==0)
|
||||||
|
return decContextSetStatus(context, DEC_Rounded);
|
||||||
|
if (strcmp(string, DEC_Condition_SU)==0)
|
||||||
|
return decContextSetStatus(context, DEC_Subnormal);
|
||||||
|
if (strcmp(string, DEC_Condition_UN)==0)
|
||||||
|
return decContextSetStatus(context, DEC_Underflow);
|
||||||
|
if (strcmp(string, DEC_Condition_ZE)==0)
|
||||||
|
return context;
|
||||||
|
return NULL; /* Multiple status, or unknown */
|
||||||
|
} /* decContextSetStatusFromString */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decContextSetStatusFromStringQuiet -- set status from a string */
|
||||||
|
/* */
|
||||||
|
/* context is the context structure to be updated */
|
||||||
|
/* string is a string exactly equal to one that might be returned */
|
||||||
|
/* by decContextStatusToString */
|
||||||
|
/* */
|
||||||
|
/* The status bit corresponding to the string is set; no trap is */
|
||||||
|
/* raised. */
|
||||||
|
/* */
|
||||||
|
/* returns the context structure, unless the string is equal to */
|
||||||
|
/* DEC_Condition_MU or is not recognized. In these cases NULL is */
|
||||||
|
/* returned. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
decContext * decContextSetStatusFromStringQuiet(decContext *context,
|
||||||
|
const char *string) {
|
||||||
|
if (strcmp(string, DEC_Condition_CS)==0)
|
||||||
|
return decContextSetStatusQuiet(context, DEC_Conversion_syntax);
|
||||||
|
if (strcmp(string, DEC_Condition_DZ)==0)
|
||||||
|
return decContextSetStatusQuiet(context, DEC_Division_by_zero);
|
||||||
|
if (strcmp(string, DEC_Condition_DI)==0)
|
||||||
|
return decContextSetStatusQuiet(context, DEC_Division_impossible);
|
||||||
|
if (strcmp(string, DEC_Condition_DU)==0)
|
||||||
|
return decContextSetStatusQuiet(context, DEC_Division_undefined);
|
||||||
|
if (strcmp(string, DEC_Condition_IE)==0)
|
||||||
|
return decContextSetStatusQuiet(context, DEC_Inexact);
|
||||||
|
if (strcmp(string, DEC_Condition_IS)==0)
|
||||||
|
return decContextSetStatusQuiet(context, DEC_Insufficient_storage);
|
||||||
|
if (strcmp(string, DEC_Condition_IC)==0)
|
||||||
|
return decContextSetStatusQuiet(context, DEC_Invalid_context);
|
||||||
|
if (strcmp(string, DEC_Condition_IO)==0)
|
||||||
|
return decContextSetStatusQuiet(context, DEC_Invalid_operation);
|
||||||
|
#if DECSUBSET
|
||||||
|
if (strcmp(string, DEC_Condition_LD)==0)
|
||||||
|
return decContextSetStatusQuiet(context, DEC_Lost_digits);
|
||||||
|
#endif
|
||||||
|
if (strcmp(string, DEC_Condition_OV)==0)
|
||||||
|
return decContextSetStatusQuiet(context, DEC_Overflow);
|
||||||
|
if (strcmp(string, DEC_Condition_PA)==0)
|
||||||
|
return decContextSetStatusQuiet(context, DEC_Clamped);
|
||||||
|
if (strcmp(string, DEC_Condition_RO)==0)
|
||||||
|
return decContextSetStatusQuiet(context, DEC_Rounded);
|
||||||
|
if (strcmp(string, DEC_Condition_SU)==0)
|
||||||
|
return decContextSetStatusQuiet(context, DEC_Subnormal);
|
||||||
|
if (strcmp(string, DEC_Condition_UN)==0)
|
||||||
|
return decContextSetStatusQuiet(context, DEC_Underflow);
|
||||||
|
if (strcmp(string, DEC_Condition_ZE)==0)
|
||||||
|
return context;
|
||||||
|
return NULL; /* Multiple status, or unknown */
|
||||||
|
} /* decContextSetStatusFromStringQuiet */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decContextSetStatusQuiet -- set status without trap */
|
||||||
|
/* */
|
||||||
|
/* context is the context structure to be updated */
|
||||||
|
/* status is the DEC_ exception code */
|
||||||
|
/* returns the context structure */
|
||||||
|
/* */
|
||||||
|
/* No error is possible. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
decContext * decContextSetStatusQuiet(decContext *context, uInt status) {
|
||||||
|
context->status|=status;
|
||||||
|
return context;} /* decContextSetStatusQuiet */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decContextStatusToString -- convert status flags to a string */
|
||||||
|
/* */
|
||||||
|
/* context is a context with valid status field */
|
||||||
|
/* */
|
||||||
|
/* returns a constant string describing the condition. If multiple */
|
||||||
|
/* (or no) flags are set, a generic constant message is returned. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
const char *decContextStatusToString(const decContext *context) {
|
||||||
|
Int status=context->status;
|
||||||
|
|
||||||
|
/* test the five IEEE first, as some of the others are ambiguous when */
|
||||||
|
/* DECEXTFLAG=0 */
|
||||||
|
if (status==DEC_Invalid_operation ) return DEC_Condition_IO;
|
||||||
|
if (status==DEC_Division_by_zero ) return DEC_Condition_DZ;
|
||||||
|
if (status==DEC_Overflow ) return DEC_Condition_OV;
|
||||||
|
if (status==DEC_Underflow ) return DEC_Condition_UN;
|
||||||
|
if (status==DEC_Inexact ) return DEC_Condition_IE;
|
||||||
|
|
||||||
|
if (status==DEC_Division_impossible ) return DEC_Condition_DI;
|
||||||
|
if (status==DEC_Division_undefined ) return DEC_Condition_DU;
|
||||||
|
if (status==DEC_Rounded ) return DEC_Condition_RO;
|
||||||
|
if (status==DEC_Clamped ) return DEC_Condition_PA;
|
||||||
|
if (status==DEC_Subnormal ) return DEC_Condition_SU;
|
||||||
|
if (status==DEC_Conversion_syntax ) return DEC_Condition_CS;
|
||||||
|
if (status==DEC_Insufficient_storage ) return DEC_Condition_IS;
|
||||||
|
if (status==DEC_Invalid_context ) return DEC_Condition_IC;
|
||||||
|
#if DECSUBSET
|
||||||
|
if (status==DEC_Lost_digits ) return DEC_Condition_LD;
|
||||||
|
#endif
|
||||||
|
if (status==0 ) return DEC_Condition_ZE;
|
||||||
|
return DEC_Condition_MU; /* Multiple errors */
|
||||||
|
} /* decContextStatusToString */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decContextTestSavedStatus -- test bits in saved status */
|
||||||
|
/* */
|
||||||
|
/* oldstatus is the status word to be tested */
|
||||||
|
/* mask indicates the bits to be tested (the oldstatus bits that */
|
||||||
|
/* correspond to each 1 bit in the mask are tested) */
|
||||||
|
/* returns 1 if any of the tested bits are 1, or 0 otherwise */
|
||||||
|
/* */
|
||||||
|
/* No error is possible. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
uInt decContextTestSavedStatus(uInt oldstatus, uInt mask) {
|
||||||
|
return (oldstatus&mask)!=0;
|
||||||
|
} /* decContextTestSavedStatus */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decContextTestStatus -- test bits in current status */
|
||||||
|
/* */
|
||||||
|
/* context is the context structure to be updated */
|
||||||
|
/* mask indicates the bits to be tested (the status bits that */
|
||||||
|
/* correspond to each 1 bit in the mask are tested) */
|
||||||
|
/* returns 1 if any of the tested bits are 1, or 0 otherwise */
|
||||||
|
/* */
|
||||||
|
/* No error is possible. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
uInt decContextTestStatus(decContext *context, uInt mask) {
|
||||||
|
return (context->status&mask)!=0;
|
||||||
|
} /* decContextTestStatus */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decContextZeroStatus -- clear all status bits */
|
||||||
|
/* */
|
||||||
|
/* context is the context structure to be updated */
|
||||||
|
/* returns context */
|
||||||
|
/* */
|
||||||
|
/* No error is possible. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
decContext *decContextZeroStatus(decContext *context) {
|
||||||
|
context->status=0;
|
||||||
|
return context;
|
||||||
|
} /* decContextZeroStatus */
|
8194
libdecnumber/decNumber.c
Normal file
8194
libdecnumber/decNumber.c
Normal file
File diff suppressed because it is too large
Load diff
564
libdecnumber/dpd/decimal128.c
Normal file
564
libdecnumber/dpd/decimal128.c
Normal file
|
@ -0,0 +1,564 @@
|
||||||
|
/* Decimal 128-bit format 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 128-bit format module */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* This module comprises the routines for decimal128 format numbers. */
|
||||||
|
/* Conversions are supplied to and from decNumber and String. */
|
||||||
|
/* */
|
||||||
|
/* This is used when decNumber provides operations, either for all */
|
||||||
|
/* operations or as a proxy between decNumber and decSingle. */
|
||||||
|
/* */
|
||||||
|
/* Error handling is the same as decNumber (qv.). */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
#include <string.h> /* [for memset/memcpy] */
|
||||||
|
#include <stdio.h> /* [for printf] */
|
||||||
|
|
||||||
|
#include "libdecnumber/dconfig.h"
|
||||||
|
#define DECNUMDIGITS 34 /* make decNumbers with space for 34 */
|
||||||
|
#include "libdecnumber/decNumber.h"
|
||||||
|
#include "libdecnumber/decNumberLocal.h"
|
||||||
|
#include "libdecnumber/dpd/decimal128.h"
|
||||||
|
|
||||||
|
/* Utility routines and tables [in decimal64.c] */
|
||||||
|
extern const uInt COMBEXP[32], COMBMSD[32];
|
||||||
|
extern const uByte BIN2CHAR[4001];
|
||||||
|
|
||||||
|
extern void decDigitsFromDPD(decNumber *, const uInt *, Int);
|
||||||
|
extern void decDigitsToDPD(const decNumber *, uInt *, Int);
|
||||||
|
|
||||||
|
#if DECTRACE || DECCHECK
|
||||||
|
void decimal128Show(const decimal128 *); /* for debug */
|
||||||
|
extern void decNumberShow(const decNumber *); /* .. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Useful macro */
|
||||||
|
/* Clear a structure (e.g., a decNumber) */
|
||||||
|
#define DEC_clear(d) memset(d, 0, sizeof(*d))
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decimal128FromNumber -- convert decNumber to decimal128 */
|
||||||
|
/* */
|
||||||
|
/* ds is the target decimal128 */
|
||||||
|
/* dn is the source number (assumed valid) */
|
||||||
|
/* set is the context, used only for reporting errors */
|
||||||
|
/* */
|
||||||
|
/* The set argument is used only for status reporting and for the */
|
||||||
|
/* rounding mode (used if the coefficient is more than DECIMAL128_Pmax*/
|
||||||
|
/* digits or an overflow is detected). If the exponent is out of the */
|
||||||
|
/* valid range then Overflow or Underflow will be raised. */
|
||||||
|
/* After Underflow a subnormal result is possible. */
|
||||||
|
/* */
|
||||||
|
/* DEC_Clamped is set if the number has to be 'folded down' to fit, */
|
||||||
|
/* by reducing its exponent and multiplying the coefficient by a */
|
||||||
|
/* power of ten, or if the exponent on a zero had to be clamped. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
decimal128 * decimal128FromNumber(decimal128 *d128, const decNumber *dn,
|
||||||
|
decContext *set) {
|
||||||
|
uInt status=0; /* status accumulator */
|
||||||
|
Int ae; /* adjusted exponent */
|
||||||
|
decNumber dw; /* work */
|
||||||
|
decContext dc; /* .. */
|
||||||
|
uInt *pu; /* .. */
|
||||||
|
uInt comb, exp; /* .. */
|
||||||
|
uInt targar[4]={0,0,0,0}; /* target 128-bit */
|
||||||
|
#define targhi targar[3] /* name the word with the sign */
|
||||||
|
#define targmh targar[2] /* name the words */
|
||||||
|
#define targml targar[1] /* .. */
|
||||||
|
#define targlo targar[0] /* .. */
|
||||||
|
|
||||||
|
/* If the number has too many digits, or the exponent could be */
|
||||||
|
/* out of range then reduce the number under the appropriate */
|
||||||
|
/* constraints. This could push the number to Infinity or zero, */
|
||||||
|
/* so this check and rounding must be done before generating the */
|
||||||
|
/* decimal128] */
|
||||||
|
ae=dn->exponent+dn->digits-1; /* [0 if special] */
|
||||||
|
if (dn->digits>DECIMAL128_Pmax /* too many digits */
|
||||||
|
|| ae>DECIMAL128_Emax /* likely overflow */
|
||||||
|
|| ae<DECIMAL128_Emin) { /* likely underflow */
|
||||||
|
decContextDefault(&dc, DEC_INIT_DECIMAL128); /* [no traps] */
|
||||||
|
dc.round=set->round; /* use supplied rounding */
|
||||||
|
decNumberPlus(&dw, dn, &dc); /* (round and check) */
|
||||||
|
/* [this changes -0 to 0, so enforce the sign...] */
|
||||||
|
dw.bits|=dn->bits&DECNEG;
|
||||||
|
status=dc.status; /* save status */
|
||||||
|
dn=&dw; /* use the work number */
|
||||||
|
} /* maybe out of range */
|
||||||
|
|
||||||
|
if (dn->bits&DECSPECIAL) { /* a special value */
|
||||||
|
if (dn->bits&DECINF) targhi=DECIMAL_Inf<<24;
|
||||||
|
else { /* sNaN or qNaN */
|
||||||
|
if ((*dn->lsu!=0 || dn->digits>1) /* non-zero coefficient */
|
||||||
|
&& (dn->digits<DECIMAL128_Pmax)) { /* coefficient fits */
|
||||||
|
decDigitsToDPD(dn, targar, 0);
|
||||||
|
}
|
||||||
|
if (dn->bits&DECNAN) targhi|=DECIMAL_NaN<<24;
|
||||||
|
else targhi|=DECIMAL_sNaN<<24;
|
||||||
|
} /* a NaN */
|
||||||
|
} /* special */
|
||||||
|
|
||||||
|
else { /* is finite */
|
||||||
|
if (decNumberIsZero(dn)) { /* is a zero */
|
||||||
|
/* set and clamp exponent */
|
||||||
|
if (dn->exponent<-DECIMAL128_Bias) {
|
||||||
|
exp=0; /* low clamp */
|
||||||
|
status|=DEC_Clamped;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
exp=dn->exponent+DECIMAL128_Bias; /* bias exponent */
|
||||||
|
if (exp>DECIMAL128_Ehigh) { /* top clamp */
|
||||||
|
exp=DECIMAL128_Ehigh;
|
||||||
|
status|=DEC_Clamped;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
comb=(exp>>9) & 0x18; /* msd=0, exp top 2 bits .. */
|
||||||
|
}
|
||||||
|
else { /* non-zero finite number */
|
||||||
|
uInt msd; /* work */
|
||||||
|
Int pad=0; /* coefficient pad digits */
|
||||||
|
|
||||||
|
/* the dn is known to fit, but it may need to be padded */
|
||||||
|
exp=(uInt)(dn->exponent+DECIMAL128_Bias); /* bias exponent */
|
||||||
|
if (exp>DECIMAL128_Ehigh) { /* fold-down case */
|
||||||
|
pad=exp-DECIMAL128_Ehigh;
|
||||||
|
exp=DECIMAL128_Ehigh; /* [to maximum] */
|
||||||
|
status|=DEC_Clamped;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* [fastpath for common case is not a win, here] */
|
||||||
|
decDigitsToDPD(dn, targar, pad);
|
||||||
|
/* save and clear the top digit */
|
||||||
|
msd=targhi>>14;
|
||||||
|
targhi&=0x00003fff;
|
||||||
|
|
||||||
|
/* create the combination field */
|
||||||
|
if (msd>=8) comb=0x18 | ((exp>>11) & 0x06) | (msd & 0x01);
|
||||||
|
else comb=((exp>>9) & 0x18) | msd;
|
||||||
|
}
|
||||||
|
targhi|=comb<<26; /* add combination field .. */
|
||||||
|
targhi|=(exp&0xfff)<<14; /* .. and exponent continuation */
|
||||||
|
} /* finite */
|
||||||
|
|
||||||
|
if (dn->bits&DECNEG) targhi|=0x80000000; /* add sign bit */
|
||||||
|
|
||||||
|
/* now write to storage; this is endian */
|
||||||
|
pu=(uInt *)d128->bytes; /* overlay */
|
||||||
|
if (DECLITEND) {
|
||||||
|
pu[0]=targlo; /* directly store the low int */
|
||||||
|
pu[1]=targml; /* then the mid-low */
|
||||||
|
pu[2]=targmh; /* then the mid-high */
|
||||||
|
pu[3]=targhi; /* then the high int */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pu[0]=targhi; /* directly store the high int */
|
||||||
|
pu[1]=targmh; /* then the mid-high */
|
||||||
|
pu[2]=targml; /* then the mid-low */
|
||||||
|
pu[3]=targlo; /* then the low int */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status!=0) decContextSetStatus(set, status); /* pass on status */
|
||||||
|
/* decimal128Show(d128); */
|
||||||
|
return d128;
|
||||||
|
} /* decimal128FromNumber */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decimal128ToNumber -- convert decimal128 to decNumber */
|
||||||
|
/* d128 is the source decimal128 */
|
||||||
|
/* dn is the target number, with appropriate space */
|
||||||
|
/* No error is possible. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
decNumber * decimal128ToNumber(const decimal128 *d128, decNumber *dn) {
|
||||||
|
uInt msd; /* coefficient MSD */
|
||||||
|
uInt exp; /* exponent top two bits */
|
||||||
|
uInt comb; /* combination field */
|
||||||
|
const uInt *pu; /* work */
|
||||||
|
Int need; /* .. */
|
||||||
|
uInt sourar[4]; /* source 128-bit */
|
||||||
|
#define sourhi sourar[3] /* name the word with the sign */
|
||||||
|
#define sourmh sourar[2] /* and the mid-high word */
|
||||||
|
#define sourml sourar[1] /* and the mod-low word */
|
||||||
|
#define sourlo sourar[0] /* and the lowest word */
|
||||||
|
|
||||||
|
/* load source from storage; this is endian */
|
||||||
|
pu=(const uInt *)d128->bytes; /* overlay */
|
||||||
|
if (DECLITEND) {
|
||||||
|
sourlo=pu[0]; /* directly load the low int */
|
||||||
|
sourml=pu[1]; /* then the mid-low */
|
||||||
|
sourmh=pu[2]; /* then the mid-high */
|
||||||
|
sourhi=pu[3]; /* then the high int */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sourhi=pu[0]; /* directly load the high int */
|
||||||
|
sourmh=pu[1]; /* then the mid-high */
|
||||||
|
sourml=pu[2]; /* then the mid-low */
|
||||||
|
sourlo=pu[3]; /* then the low int */
|
||||||
|
}
|
||||||
|
|
||||||
|
comb=(sourhi>>26)&0x1f; /* combination field */
|
||||||
|
|
||||||
|
decNumberZero(dn); /* clean number */
|
||||||
|
if (sourhi&0x80000000) dn->bits=DECNEG; /* set sign if negative */
|
||||||
|
|
||||||
|
msd=COMBMSD[comb]; /* decode the combination field */
|
||||||
|
exp=COMBEXP[comb]; /* .. */
|
||||||
|
|
||||||
|
if (exp==3) { /* is a special */
|
||||||
|
if (msd==0) {
|
||||||
|
dn->bits|=DECINF;
|
||||||
|
return dn; /* no coefficient needed */
|
||||||
|
}
|
||||||
|
else if (sourhi&0x02000000) dn->bits|=DECSNAN;
|
||||||
|
else dn->bits|=DECNAN;
|
||||||
|
msd=0; /* no top digit */
|
||||||
|
}
|
||||||
|
else { /* is a finite number */
|
||||||
|
dn->exponent=(exp<<12)+((sourhi>>14)&0xfff)-DECIMAL128_Bias; /* unbiased */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the coefficient */
|
||||||
|
sourhi&=0x00003fff; /* clean coefficient continuation */
|
||||||
|
if (msd) { /* non-zero msd */
|
||||||
|
sourhi|=msd<<14; /* prefix to coefficient */
|
||||||
|
need=12; /* process 12 declets */
|
||||||
|
}
|
||||||
|
else { /* msd=0 */
|
||||||
|
if (sourhi) need=11; /* declets to process */
|
||||||
|
else if (sourmh) need=10;
|
||||||
|
else if (sourml) need=7;
|
||||||
|
else if (sourlo) need=4;
|
||||||
|
else return dn; /* easy: coefficient is 0 */
|
||||||
|
} /*msd=0 */
|
||||||
|
|
||||||
|
decDigitsFromDPD(dn, sourar, need); /* process declets */
|
||||||
|
/* decNumberShow(dn); */
|
||||||
|
return dn;
|
||||||
|
} /* decimal128ToNumber */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* to-scientific-string -- conversion to numeric string */
|
||||||
|
/* to-engineering-string -- conversion to numeric string */
|
||||||
|
/* */
|
||||||
|
/* decimal128ToString(d128, string); */
|
||||||
|
/* decimal128ToEngString(d128, string); */
|
||||||
|
/* */
|
||||||
|
/* d128 is the decimal128 format number to convert */
|
||||||
|
/* string is the string where the result will be laid out */
|
||||||
|
/* */
|
||||||
|
/* string must be at least 24 characters */
|
||||||
|
/* */
|
||||||
|
/* No error is possible, and no status can be set. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
char * decimal128ToEngString(const decimal128 *d128, char *string){
|
||||||
|
decNumber dn; /* work */
|
||||||
|
decimal128ToNumber(d128, &dn);
|
||||||
|
decNumberToEngString(&dn, string);
|
||||||
|
return string;
|
||||||
|
} /* decimal128ToEngString */
|
||||||
|
|
||||||
|
char * decimal128ToString(const decimal128 *d128, char *string){
|
||||||
|
uInt msd; /* coefficient MSD */
|
||||||
|
Int exp; /* exponent top two bits or full */
|
||||||
|
uInt comb; /* combination field */
|
||||||
|
char *cstart; /* coefficient start */
|
||||||
|
char *c; /* output pointer in string */
|
||||||
|
const uInt *pu; /* work */
|
||||||
|
char *s, *t; /* .. (source, target) */
|
||||||
|
Int dpd; /* .. */
|
||||||
|
Int pre, e; /* .. */
|
||||||
|
const uByte *u; /* .. */
|
||||||
|
|
||||||
|
uInt sourar[4]; /* source 128-bit */
|
||||||
|
#define sourhi sourar[3] /* name the word with the sign */
|
||||||
|
#define sourmh sourar[2] /* and the mid-high word */
|
||||||
|
#define sourml sourar[1] /* and the mod-low word */
|
||||||
|
#define sourlo sourar[0] /* and the lowest word */
|
||||||
|
|
||||||
|
/* load source from storage; this is endian */
|
||||||
|
pu=(const uInt *)d128->bytes; /* overlay */
|
||||||
|
if (DECLITEND) {
|
||||||
|
sourlo=pu[0]; /* directly load the low int */
|
||||||
|
sourml=pu[1]; /* then the mid-low */
|
||||||
|
sourmh=pu[2]; /* then the mid-high */
|
||||||
|
sourhi=pu[3]; /* then the high int */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sourhi=pu[0]; /* directly load the high int */
|
||||||
|
sourmh=pu[1]; /* then the mid-high */
|
||||||
|
sourml=pu[2]; /* then the mid-low */
|
||||||
|
sourlo=pu[3]; /* then the low int */
|
||||||
|
}
|
||||||
|
|
||||||
|
c=string; /* where result will go */
|
||||||
|
if (((Int)sourhi)<0) *c++='-'; /* handle sign */
|
||||||
|
|
||||||
|
comb=(sourhi>>26)&0x1f; /* combination field */
|
||||||
|
msd=COMBMSD[comb]; /* decode the combination field */
|
||||||
|
exp=COMBEXP[comb]; /* .. */
|
||||||
|
|
||||||
|
if (exp==3) {
|
||||||
|
if (msd==0) { /* infinity */
|
||||||
|
strcpy(c, "Inf");
|
||||||
|
strcpy(c+3, "inity");
|
||||||
|
return string; /* easy */
|
||||||
|
}
|
||||||
|
if (sourhi&0x02000000) *c++='s'; /* sNaN */
|
||||||
|
strcpy(c, "NaN"); /* complete word */
|
||||||
|
c+=3; /* step past */
|
||||||
|
if (sourlo==0 && sourml==0 && sourmh==0
|
||||||
|
&& (sourhi&0x0003ffff)==0) return string; /* zero payload */
|
||||||
|
/* otherwise drop through to add integer; set correct exp */
|
||||||
|
exp=0; msd=0; /* setup for following code */
|
||||||
|
}
|
||||||
|
else exp=(exp<<12)+((sourhi>>14)&0xfff)-DECIMAL128_Bias; /* unbiased */
|
||||||
|
|
||||||
|
/* convert 34 digits of significand to characters */
|
||||||
|
cstart=c; /* save start of coefficient */
|
||||||
|
if (msd) *c++='0'+(char)msd; /* non-zero most significant digit */
|
||||||
|
|
||||||
|
/* Now decode the declets. After extracting each one, it is */
|
||||||
|
/* decoded to binary and then to a 4-char sequence by table lookup; */
|
||||||
|
/* the 4-chars are a 1-char length (significant digits, except 000 */
|
||||||
|
/* has length 0). This allows us to left-align the first declet */
|
||||||
|
/* with non-zero content, then remaining ones are full 3-char */
|
||||||
|
/* length. We use fixed-length memcpys because variable-length */
|
||||||
|
/* causes a subroutine call in GCC. (These are length 4 for speed */
|
||||||
|
/* and are safe because the array has an extra terminator byte.) */
|
||||||
|
#define dpd2char u=&BIN2CHAR[DPD2BIN[dpd]*4]; \
|
||||||
|
if (c!=cstart) {memcpy(c, u+1, 4); c+=3;} \
|
||||||
|
else if (*u) {memcpy(c, u+4-*u, 4); c+=*u;}
|
||||||
|
dpd=(sourhi>>4)&0x3ff; /* declet 1 */
|
||||||
|
dpd2char;
|
||||||
|
dpd=((sourhi&0xf)<<6) | (sourmh>>26); /* declet 2 */
|
||||||
|
dpd2char;
|
||||||
|
dpd=(sourmh>>16)&0x3ff; /* declet 3 */
|
||||||
|
dpd2char;
|
||||||
|
dpd=(sourmh>>6)&0x3ff; /* declet 4 */
|
||||||
|
dpd2char;
|
||||||
|
dpd=((sourmh&0x3f)<<4) | (sourml>>28); /* declet 5 */
|
||||||
|
dpd2char;
|
||||||
|
dpd=(sourml>>18)&0x3ff; /* declet 6 */
|
||||||
|
dpd2char;
|
||||||
|
dpd=(sourml>>8)&0x3ff; /* declet 7 */
|
||||||
|
dpd2char;
|
||||||
|
dpd=((sourml&0xff)<<2) | (sourlo>>30); /* declet 8 */
|
||||||
|
dpd2char;
|
||||||
|
dpd=(sourlo>>20)&0x3ff; /* declet 9 */
|
||||||
|
dpd2char;
|
||||||
|
dpd=(sourlo>>10)&0x3ff; /* declet 10 */
|
||||||
|
dpd2char;
|
||||||
|
dpd=(sourlo)&0x3ff; /* declet 11 */
|
||||||
|
dpd2char;
|
||||||
|
|
||||||
|
if (c==cstart) *c++='0'; /* all zeros -- make 0 */
|
||||||
|
|
||||||
|
if (exp==0) { /* integer or NaN case -- easy */
|
||||||
|
*c='\0'; /* terminate */
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* non-0 exponent */
|
||||||
|
e=0; /* assume no E */
|
||||||
|
pre=c-cstart+exp;
|
||||||
|
/* [here, pre-exp is the digits count (==1 for zero)] */
|
||||||
|
if (exp>0 || pre<-5) { /* need exponential form */
|
||||||
|
e=pre-1; /* calculate E value */
|
||||||
|
pre=1; /* assume one digit before '.' */
|
||||||
|
} /* exponential form */
|
||||||
|
|
||||||
|
/* modify the coefficient, adding 0s, '.', and E+nn as needed */
|
||||||
|
s=c-1; /* source (LSD) */
|
||||||
|
if (pre>0) { /* ddd.ddd (plain), perhaps with E */
|
||||||
|
char *dotat=cstart+pre;
|
||||||
|
if (dotat<c) { /* if embedded dot needed... */
|
||||||
|
t=c; /* target */
|
||||||
|
for (; s>=dotat; s--, t--) *t=*s; /* open the gap; leave t at gap */
|
||||||
|
*t='.'; /* insert the dot */
|
||||||
|
c++; /* length increased by one */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* finally add the E-part, if needed; it will never be 0, and has */
|
||||||
|
/* a maximum length of 4 digits */
|
||||||
|
if (e!=0) {
|
||||||
|
*c++='E'; /* starts with E */
|
||||||
|
*c++='+'; /* assume positive */
|
||||||
|
if (e<0) {
|
||||||
|
*(c-1)='-'; /* oops, need '-' */
|
||||||
|
e=-e; /* uInt, please */
|
||||||
|
}
|
||||||
|
if (e<1000) { /* 3 (or fewer) digits case */
|
||||||
|
u=&BIN2CHAR[e*4]; /* -> length byte */
|
||||||
|
memcpy(c, u+4-*u, 4); /* copy fixed 4 characters [is safe] */
|
||||||
|
c+=*u; /* bump pointer appropriately */
|
||||||
|
}
|
||||||
|
else { /* 4-digits */
|
||||||
|
Int thou=((e>>3)*1049)>>17; /* e/1000 */
|
||||||
|
Int rem=e-(1000*thou); /* e%1000 */
|
||||||
|
*c++='0'+(char)thou;
|
||||||
|
u=&BIN2CHAR[rem*4]; /* -> length byte */
|
||||||
|
memcpy(c, u+1, 4); /* copy fixed 3+1 characters [is safe] */
|
||||||
|
c+=3; /* bump pointer, always 3 digits */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*c='\0'; /* add terminator */
|
||||||
|
/*printf("res %s\n", string); */
|
||||||
|
return string;
|
||||||
|
} /* pre>0 */
|
||||||
|
|
||||||
|
/* -5<=pre<=0: here for plain 0.ddd or 0.000ddd forms (can never have E) */
|
||||||
|
t=c+1-pre;
|
||||||
|
*(t+1)='\0'; /* can add terminator now */
|
||||||
|
for (; s>=cstart; s--, t--) *t=*s; /* shift whole coefficient right */
|
||||||
|
c=cstart;
|
||||||
|
*c++='0'; /* always starts with 0. */
|
||||||
|
*c++='.';
|
||||||
|
for (; pre<0; pre++) *c++='0'; /* add any 0's after '.' */
|
||||||
|
/*printf("res %s\n", string); */
|
||||||
|
return string;
|
||||||
|
} /* decimal128ToString */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* to-number -- conversion from numeric string */
|
||||||
|
/* */
|
||||||
|
/* decimal128FromString(result, string, set); */
|
||||||
|
/* */
|
||||||
|
/* result is the decimal128 format number which gets the result of */
|
||||||
|
/* the conversion */
|
||||||
|
/* *string is the character string which should contain a valid */
|
||||||
|
/* number (which may be a special value) */
|
||||||
|
/* set is the context */
|
||||||
|
/* */
|
||||||
|
/* The context is supplied to this routine is used for error handling */
|
||||||
|
/* (setting of status and traps) and for the rounding mode, only. */
|
||||||
|
/* If an error occurs, the result will be a valid decimal128 NaN. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
decimal128 * decimal128FromString(decimal128 *result, const char *string,
|
||||||
|
decContext *set) {
|
||||||
|
decContext dc; /* work */
|
||||||
|
decNumber dn; /* .. */
|
||||||
|
|
||||||
|
decContextDefault(&dc, DEC_INIT_DECIMAL128); /* no traps, please */
|
||||||
|
dc.round=set->round; /* use supplied rounding */
|
||||||
|
|
||||||
|
decNumberFromString(&dn, string, &dc); /* will round if needed */
|
||||||
|
decimal128FromNumber(result, &dn, &dc);
|
||||||
|
if (dc.status!=0) { /* something happened */
|
||||||
|
decContextSetStatus(set, dc.status); /* .. pass it on */
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} /* decimal128FromString */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decimal128IsCanonical -- test whether encoding is canonical */
|
||||||
|
/* d128 is the source decimal128 */
|
||||||
|
/* returns 1 if the encoding of d128 is canonical, 0 otherwise */
|
||||||
|
/* No error is possible. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
uint32_t decimal128IsCanonical(const decimal128 *d128) {
|
||||||
|
decNumber dn; /* work */
|
||||||
|
decimal128 canon; /* .. */
|
||||||
|
decContext dc; /* .. */
|
||||||
|
decContextDefault(&dc, DEC_INIT_DECIMAL128);
|
||||||
|
decimal128ToNumber(d128, &dn);
|
||||||
|
decimal128FromNumber(&canon, &dn, &dc);/* canon will now be canonical */
|
||||||
|
return memcmp(d128, &canon, DECIMAL128_Bytes)==0;
|
||||||
|
} /* decimal128IsCanonical */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decimal128Canonical -- copy an encoding, ensuring it is canonical */
|
||||||
|
/* d128 is the source decimal128 */
|
||||||
|
/* result is the target (may be the same decimal128) */
|
||||||
|
/* returns result */
|
||||||
|
/* No error is possible. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
decimal128 * decimal128Canonical(decimal128 *result, const decimal128 *d128) {
|
||||||
|
decNumber dn; /* work */
|
||||||
|
decContext dc; /* .. */
|
||||||
|
decContextDefault(&dc, DEC_INIT_DECIMAL128);
|
||||||
|
decimal128ToNumber(d128, &dn);
|
||||||
|
decimal128FromNumber(result, &dn, &dc);/* result will now be canonical */
|
||||||
|
return result;
|
||||||
|
} /* decimal128Canonical */
|
||||||
|
|
||||||
|
#if DECTRACE || DECCHECK
|
||||||
|
/* Macros for accessing decimal128 fields. These assume the argument
|
||||||
|
is a reference (pointer) to the decimal128 structure, and the
|
||||||
|
decimal128 is in network byte order (big-endian) */
|
||||||
|
/* Get sign */
|
||||||
|
#define decimal128Sign(d) ((unsigned)(d)->bytes[0]>>7)
|
||||||
|
|
||||||
|
/* Get combination field */
|
||||||
|
#define decimal128Comb(d) (((d)->bytes[0] & 0x7c)>>2)
|
||||||
|
|
||||||
|
/* Get exponent continuation [does not remove bias] */
|
||||||
|
#define decimal128ExpCon(d) ((((d)->bytes[0] & 0x03)<<10) \
|
||||||
|
| ((unsigned)(d)->bytes[1]<<2) \
|
||||||
|
| ((unsigned)(d)->bytes[2]>>6))
|
||||||
|
|
||||||
|
/* Set sign [this assumes sign previously 0] */
|
||||||
|
#define decimal128SetSign(d, b) { \
|
||||||
|
(d)->bytes[0]|=((unsigned)(b)<<7);}
|
||||||
|
|
||||||
|
/* Set exponent continuation [does not apply bias] */
|
||||||
|
/* This assumes range has been checked and exponent previously 0; */
|
||||||
|
/* type of exponent must be unsigned */
|
||||||
|
#define decimal128SetExpCon(d, e) { \
|
||||||
|
(d)->bytes[0]|=(uint8_t)((e)>>10); \
|
||||||
|
(d)->bytes[1] =(uint8_t)(((e)&0x3fc)>>2); \
|
||||||
|
(d)->bytes[2]|=(uint8_t)(((e)&0x03)<<6);}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decimal128Show -- display a decimal128 in hexadecimal [debug aid] */
|
||||||
|
/* d128 -- the number to show */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* Also shows sign/cob/expconfields extracted */
|
||||||
|
void decimal128Show(const decimal128 *d128) {
|
||||||
|
char buf[DECIMAL128_Bytes*2+1];
|
||||||
|
Int i, j=0;
|
||||||
|
|
||||||
|
if (DECLITEND) {
|
||||||
|
for (i=0; i<DECIMAL128_Bytes; i++, j+=2) {
|
||||||
|
sprintf(&buf[j], "%02x", d128->bytes[15-i]);
|
||||||
|
}
|
||||||
|
printf(" D128> %s [S:%d Cb:%02x Ec:%02x] LittleEndian\n", buf,
|
||||||
|
d128->bytes[15]>>7, (d128->bytes[15]>>2)&0x1f,
|
||||||
|
((d128->bytes[15]&0x3)<<10)|(d128->bytes[14]<<2)|
|
||||||
|
(d128->bytes[13]>>6));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (i=0; i<DECIMAL128_Bytes; i++, j+=2) {
|
||||||
|
sprintf(&buf[j], "%02x", d128->bytes[i]);
|
||||||
|
}
|
||||||
|
printf(" D128> %s [S:%d Cb:%02x Ec:%02x] BigEndian\n", buf,
|
||||||
|
decimal128Sign(d128), decimal128Comb(d128),
|
||||||
|
decimal128ExpCon(d128));
|
||||||
|
}
|
||||||
|
} /* decimal128Show */
|
||||||
|
#endif
|
42
libdecnumber/dpd/decimal128Local.h
Normal file
42
libdecnumber/dpd/decimal128Local.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/* 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
|
489
libdecnumber/dpd/decimal32.c
Normal file
489
libdecnumber/dpd/decimal32.c
Normal file
|
@ -0,0 +1,489 @@
|
||||||
|
/* Decimal 32-bit format 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 32-bit format module */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* This module comprises the routines for decimal32 format numbers. */
|
||||||
|
/* Conversions are supplied to and from decNumber and String. */
|
||||||
|
/* */
|
||||||
|
/* This is used when decNumber provides operations, either for all */
|
||||||
|
/* operations or as a proxy between decNumber and decSingle. */
|
||||||
|
/* */
|
||||||
|
/* Error handling is the same as decNumber (qv.). */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
#include <string.h> /* [for memset/memcpy] */
|
||||||
|
#include <stdio.h> /* [for printf] */
|
||||||
|
|
||||||
|
#include "libdecnumber/dconfig.h"
|
||||||
|
#define DECNUMDIGITS 7 /* make decNumbers with space for 7 */
|
||||||
|
#include "libdecnumber/decNumber.h"
|
||||||
|
#include "libdecnumber/decNumberLocal.h"
|
||||||
|
#include "libdecnumber/dpd/decimal32.h"
|
||||||
|
|
||||||
|
/* Utility tables and routines [in decimal64.c] */
|
||||||
|
extern const uInt COMBEXP[32], COMBMSD[32];
|
||||||
|
extern const uByte BIN2CHAR[4001];
|
||||||
|
|
||||||
|
extern void decDigitsToDPD(const decNumber *, uInt *, Int);
|
||||||
|
extern void decDigitsFromDPD(decNumber *, const uInt *, Int);
|
||||||
|
|
||||||
|
#if DECTRACE || DECCHECK
|
||||||
|
void decimal32Show(const decimal32 *); /* for debug */
|
||||||
|
extern void decNumberShow(const decNumber *); /* .. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Useful macro */
|
||||||
|
/* Clear a structure (e.g., a decNumber) */
|
||||||
|
#define DEC_clear(d) memset(d, 0, sizeof(*d))
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decimal32FromNumber -- convert decNumber to decimal32 */
|
||||||
|
/* */
|
||||||
|
/* ds is the target decimal32 */
|
||||||
|
/* dn is the source number (assumed valid) */
|
||||||
|
/* set is the context, used only for reporting errors */
|
||||||
|
/* */
|
||||||
|
/* The set argument is used only for status reporting and for the */
|
||||||
|
/* rounding mode (used if the coefficient is more than DECIMAL32_Pmax */
|
||||||
|
/* digits or an overflow is detected). If the exponent is out of the */
|
||||||
|
/* valid range then Overflow or Underflow will be raised. */
|
||||||
|
/* After Underflow a subnormal result is possible. */
|
||||||
|
/* */
|
||||||
|
/* DEC_Clamped is set if the number has to be 'folded down' to fit, */
|
||||||
|
/* by reducing its exponent and multiplying the coefficient by a */
|
||||||
|
/* power of ten, or if the exponent on a zero had to be clamped. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
decimal32 * decimal32FromNumber(decimal32 *d32, const decNumber *dn,
|
||||||
|
decContext *set) {
|
||||||
|
uInt status=0; /* status accumulator */
|
||||||
|
Int ae; /* adjusted exponent */
|
||||||
|
decNumber dw; /* work */
|
||||||
|
decContext dc; /* .. */
|
||||||
|
uInt *pu; /* .. */
|
||||||
|
uInt comb, exp; /* .. */
|
||||||
|
uInt targ=0; /* target 32-bit */
|
||||||
|
|
||||||
|
/* If the number has too many digits, or the exponent could be */
|
||||||
|
/* out of range then reduce the number under the appropriate */
|
||||||
|
/* constraints. This could push the number to Infinity or zero, */
|
||||||
|
/* so this check and rounding must be done before generating the */
|
||||||
|
/* decimal32] */
|
||||||
|
ae=dn->exponent+dn->digits-1; /* [0 if special] */
|
||||||
|
if (dn->digits>DECIMAL32_Pmax /* too many digits */
|
||||||
|
|| ae>DECIMAL32_Emax /* likely overflow */
|
||||||
|
|| ae<DECIMAL32_Emin) { /* likely underflow */
|
||||||
|
decContextDefault(&dc, DEC_INIT_DECIMAL32); /* [no traps] */
|
||||||
|
dc.round=set->round; /* use supplied rounding */
|
||||||
|
decNumberPlus(&dw, dn, &dc); /* (round and check) */
|
||||||
|
/* [this changes -0 to 0, so enforce the sign...] */
|
||||||
|
dw.bits|=dn->bits&DECNEG;
|
||||||
|
status=dc.status; /* save status */
|
||||||
|
dn=&dw; /* use the work number */
|
||||||
|
} /* maybe out of range */
|
||||||
|
|
||||||
|
if (dn->bits&DECSPECIAL) { /* a special value */
|
||||||
|
if (dn->bits&DECINF) targ=DECIMAL_Inf<<24;
|
||||||
|
else { /* sNaN or qNaN */
|
||||||
|
if ((*dn->lsu!=0 || dn->digits>1) /* non-zero coefficient */
|
||||||
|
&& (dn->digits<DECIMAL32_Pmax)) { /* coefficient fits */
|
||||||
|
decDigitsToDPD(dn, &targ, 0);
|
||||||
|
}
|
||||||
|
if (dn->bits&DECNAN) targ|=DECIMAL_NaN<<24;
|
||||||
|
else targ|=DECIMAL_sNaN<<24;
|
||||||
|
} /* a NaN */
|
||||||
|
} /* special */
|
||||||
|
|
||||||
|
else { /* is finite */
|
||||||
|
if (decNumberIsZero(dn)) { /* is a zero */
|
||||||
|
/* set and clamp exponent */
|
||||||
|
if (dn->exponent<-DECIMAL32_Bias) {
|
||||||
|
exp=0; /* low clamp */
|
||||||
|
status|=DEC_Clamped;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
exp=dn->exponent+DECIMAL32_Bias; /* bias exponent */
|
||||||
|
if (exp>DECIMAL32_Ehigh) { /* top clamp */
|
||||||
|
exp=DECIMAL32_Ehigh;
|
||||||
|
status|=DEC_Clamped;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
comb=(exp>>3) & 0x18; /* msd=0, exp top 2 bits .. */
|
||||||
|
}
|
||||||
|
else { /* non-zero finite number */
|
||||||
|
uInt msd; /* work */
|
||||||
|
Int pad=0; /* coefficient pad digits */
|
||||||
|
|
||||||
|
/* the dn is known to fit, but it may need to be padded */
|
||||||
|
exp=(uInt)(dn->exponent+DECIMAL32_Bias); /* bias exponent */
|
||||||
|
if (exp>DECIMAL32_Ehigh) { /* fold-down case */
|
||||||
|
pad=exp-DECIMAL32_Ehigh;
|
||||||
|
exp=DECIMAL32_Ehigh; /* [to maximum] */
|
||||||
|
status|=DEC_Clamped;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fastpath common case */
|
||||||
|
if (DECDPUN==3 && pad==0) {
|
||||||
|
targ=BIN2DPD[dn->lsu[0]];
|
||||||
|
if (dn->digits>3) targ|=(uInt)(BIN2DPD[dn->lsu[1]])<<10;
|
||||||
|
msd=(dn->digits==7 ? dn->lsu[2] : 0);
|
||||||
|
}
|
||||||
|
else { /* general case */
|
||||||
|
decDigitsToDPD(dn, &targ, pad);
|
||||||
|
/* save and clear the top digit */
|
||||||
|
msd=targ>>20;
|
||||||
|
targ&=0x000fffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create the combination field */
|
||||||
|
if (msd>=8) comb=0x18 | ((exp>>5) & 0x06) | (msd & 0x01);
|
||||||
|
else comb=((exp>>3) & 0x18) | msd;
|
||||||
|
}
|
||||||
|
targ|=comb<<26; /* add combination field .. */
|
||||||
|
targ|=(exp&0x3f)<<20; /* .. and exponent continuation */
|
||||||
|
} /* finite */
|
||||||
|
|
||||||
|
if (dn->bits&DECNEG) targ|=0x80000000; /* add sign bit */
|
||||||
|
|
||||||
|
/* now write to storage; this is endian */
|
||||||
|
pu=(uInt *)d32->bytes; /* overlay */
|
||||||
|
*pu=targ; /* directly store the int */
|
||||||
|
|
||||||
|
if (status!=0) decContextSetStatus(set, status); /* pass on status */
|
||||||
|
/* decimal32Show(d32); */
|
||||||
|
return d32;
|
||||||
|
} /* decimal32FromNumber */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decimal32ToNumber -- convert decimal32 to decNumber */
|
||||||
|
/* d32 is the source decimal32 */
|
||||||
|
/* dn is the target number, with appropriate space */
|
||||||
|
/* No error is possible. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
decNumber * decimal32ToNumber(const decimal32 *d32, decNumber *dn) {
|
||||||
|
uInt msd; /* coefficient MSD */
|
||||||
|
uInt exp; /* exponent top two bits */
|
||||||
|
uInt comb; /* combination field */
|
||||||
|
uInt sour; /* source 32-bit */
|
||||||
|
const uInt *pu; /* work */
|
||||||
|
|
||||||
|
/* load source from storage; this is endian */
|
||||||
|
pu=(const uInt *)d32->bytes; /* overlay */
|
||||||
|
sour=*pu; /* directly load the int */
|
||||||
|
|
||||||
|
comb=(sour>>26)&0x1f; /* combination field */
|
||||||
|
|
||||||
|
decNumberZero(dn); /* clean number */
|
||||||
|
if (sour&0x80000000) dn->bits=DECNEG; /* set sign if negative */
|
||||||
|
|
||||||
|
msd=COMBMSD[comb]; /* decode the combination field */
|
||||||
|
exp=COMBEXP[comb]; /* .. */
|
||||||
|
|
||||||
|
if (exp==3) { /* is a special */
|
||||||
|
if (msd==0) {
|
||||||
|
dn->bits|=DECINF;
|
||||||
|
return dn; /* no coefficient needed */
|
||||||
|
}
|
||||||
|
else if (sour&0x02000000) dn->bits|=DECSNAN;
|
||||||
|
else dn->bits|=DECNAN;
|
||||||
|
msd=0; /* no top digit */
|
||||||
|
}
|
||||||
|
else { /* is a finite number */
|
||||||
|
dn->exponent=(exp<<6)+((sour>>20)&0x3f)-DECIMAL32_Bias; /* unbiased */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the coefficient */
|
||||||
|
sour&=0x000fffff; /* clean coefficient continuation */
|
||||||
|
if (msd) { /* non-zero msd */
|
||||||
|
sour|=msd<<20; /* prefix to coefficient */
|
||||||
|
decDigitsFromDPD(dn, &sour, 3); /* process 3 declets */
|
||||||
|
return dn;
|
||||||
|
}
|
||||||
|
/* msd=0 */
|
||||||
|
if (!sour) return dn; /* easy: coefficient is 0 */
|
||||||
|
if (sour&0x000ffc00) /* need 2 declets? */
|
||||||
|
decDigitsFromDPD(dn, &sour, 2); /* process 2 declets */
|
||||||
|
else
|
||||||
|
decDigitsFromDPD(dn, &sour, 1); /* process 1 declet */
|
||||||
|
return dn;
|
||||||
|
} /* decimal32ToNumber */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* to-scientific-string -- conversion to numeric string */
|
||||||
|
/* to-engineering-string -- conversion to numeric string */
|
||||||
|
/* */
|
||||||
|
/* decimal32ToString(d32, string); */
|
||||||
|
/* decimal32ToEngString(d32, string); */
|
||||||
|
/* */
|
||||||
|
/* d32 is the decimal32 format number to convert */
|
||||||
|
/* string is the string where the result will be laid out */
|
||||||
|
/* */
|
||||||
|
/* string must be at least 24 characters */
|
||||||
|
/* */
|
||||||
|
/* No error is possible, and no status can be set. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
char * decimal32ToEngString(const decimal32 *d32, char *string){
|
||||||
|
decNumber dn; /* work */
|
||||||
|
decimal32ToNumber(d32, &dn);
|
||||||
|
decNumberToEngString(&dn, string);
|
||||||
|
return string;
|
||||||
|
} /* decimal32ToEngString */
|
||||||
|
|
||||||
|
char * decimal32ToString(const decimal32 *d32, char *string){
|
||||||
|
uInt msd; /* coefficient MSD */
|
||||||
|
Int exp; /* exponent top two bits or full */
|
||||||
|
uInt comb; /* combination field */
|
||||||
|
char *cstart; /* coefficient start */
|
||||||
|
char *c; /* output pointer in string */
|
||||||
|
const uInt *pu; /* work */
|
||||||
|
const uByte *u; /* .. */
|
||||||
|
char *s, *t; /* .. (source, target) */
|
||||||
|
Int dpd; /* .. */
|
||||||
|
Int pre, e; /* .. */
|
||||||
|
uInt sour; /* source 32-bit */
|
||||||
|
|
||||||
|
/* load source from storage; this is endian */
|
||||||
|
pu=(const uInt *)d32->bytes; /* overlay */
|
||||||
|
sour=*pu; /* directly load the int */
|
||||||
|
|
||||||
|
c=string; /* where result will go */
|
||||||
|
if (((Int)sour)<0) *c++='-'; /* handle sign */
|
||||||
|
|
||||||
|
comb=(sour>>26)&0x1f; /* combination field */
|
||||||
|
msd=COMBMSD[comb]; /* decode the combination field */
|
||||||
|
exp=COMBEXP[comb]; /* .. */
|
||||||
|
|
||||||
|
if (exp==3) {
|
||||||
|
if (msd==0) { /* infinity */
|
||||||
|
strcpy(c, "Inf");
|
||||||
|
strcpy(c+3, "inity");
|
||||||
|
return string; /* easy */
|
||||||
|
}
|
||||||
|
if (sour&0x02000000) *c++='s'; /* sNaN */
|
||||||
|
strcpy(c, "NaN"); /* complete word */
|
||||||
|
c+=3; /* step past */
|
||||||
|
if ((sour&0x000fffff)==0) return string; /* zero payload */
|
||||||
|
/* otherwise drop through to add integer; set correct exp */
|
||||||
|
exp=0; msd=0; /* setup for following code */
|
||||||
|
}
|
||||||
|
else exp=(exp<<6)+((sour>>20)&0x3f)-DECIMAL32_Bias; /* unbiased */
|
||||||
|
|
||||||
|
/* convert 7 digits of significand to characters */
|
||||||
|
cstart=c; /* save start of coefficient */
|
||||||
|
if (msd) *c++='0'+(char)msd; /* non-zero most significant digit */
|
||||||
|
|
||||||
|
/* Now decode the declets. After extracting each one, it is */
|
||||||
|
/* decoded to binary and then to a 4-char sequence by table lookup; */
|
||||||
|
/* the 4-chars are a 1-char length (significant digits, except 000 */
|
||||||
|
/* has length 0). This allows us to left-align the first declet */
|
||||||
|
/* with non-zero content, then remaining ones are full 3-char */
|
||||||
|
/* length. We use fixed-length memcpys because variable-length */
|
||||||
|
/* causes a subroutine call in GCC. (These are length 4 for speed */
|
||||||
|
/* and are safe because the array has an extra terminator byte.) */
|
||||||
|
#define dpd2char u=&BIN2CHAR[DPD2BIN[dpd]*4]; \
|
||||||
|
if (c!=cstart) {memcpy(c, u+1, 4); c+=3;} \
|
||||||
|
else if (*u) {memcpy(c, u+4-*u, 4); c+=*u;}
|
||||||
|
|
||||||
|
dpd=(sour>>10)&0x3ff; /* declet 1 */
|
||||||
|
dpd2char;
|
||||||
|
dpd=(sour)&0x3ff; /* declet 2 */
|
||||||
|
dpd2char;
|
||||||
|
|
||||||
|
if (c==cstart) *c++='0'; /* all zeros -- make 0 */
|
||||||
|
|
||||||
|
if (exp==0) { /* integer or NaN case -- easy */
|
||||||
|
*c='\0'; /* terminate */
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* non-0 exponent */
|
||||||
|
e=0; /* assume no E */
|
||||||
|
pre=c-cstart+exp;
|
||||||
|
/* [here, pre-exp is the digits count (==1 for zero)] */
|
||||||
|
if (exp>0 || pre<-5) { /* need exponential form */
|
||||||
|
e=pre-1; /* calculate E value */
|
||||||
|
pre=1; /* assume one digit before '.' */
|
||||||
|
} /* exponential form */
|
||||||
|
|
||||||
|
/* modify the coefficient, adding 0s, '.', and E+nn as needed */
|
||||||
|
s=c-1; /* source (LSD) */
|
||||||
|
if (pre>0) { /* ddd.ddd (plain), perhaps with E */
|
||||||
|
char *dotat=cstart+pre;
|
||||||
|
if (dotat<c) { /* if embedded dot needed... */
|
||||||
|
t=c; /* target */
|
||||||
|
for (; s>=dotat; s--, t--) *t=*s; /* open the gap; leave t at gap */
|
||||||
|
*t='.'; /* insert the dot */
|
||||||
|
c++; /* length increased by one */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* finally add the E-part, if needed; it will never be 0, and has */
|
||||||
|
/* a maximum length of 3 digits (E-101 case) */
|
||||||
|
if (e!=0) {
|
||||||
|
*c++='E'; /* starts with E */
|
||||||
|
*c++='+'; /* assume positive */
|
||||||
|
if (e<0) {
|
||||||
|
*(c-1)='-'; /* oops, need '-' */
|
||||||
|
e=-e; /* uInt, please */
|
||||||
|
}
|
||||||
|
u=&BIN2CHAR[e*4]; /* -> length byte */
|
||||||
|
memcpy(c, u+4-*u, 4); /* copy fixed 4 characters [is safe] */
|
||||||
|
c+=*u; /* bump pointer appropriately */
|
||||||
|
}
|
||||||
|
*c='\0'; /* add terminator */
|
||||||
|
/*printf("res %s\n", string); */
|
||||||
|
return string;
|
||||||
|
} /* pre>0 */
|
||||||
|
|
||||||
|
/* -5<=pre<=0: here for plain 0.ddd or 0.000ddd forms (can never have E) */
|
||||||
|
t=c+1-pre;
|
||||||
|
*(t+1)='\0'; /* can add terminator now */
|
||||||
|
for (; s>=cstart; s--, t--) *t=*s; /* shift whole coefficient right */
|
||||||
|
c=cstart;
|
||||||
|
*c++='0'; /* always starts with 0. */
|
||||||
|
*c++='.';
|
||||||
|
for (; pre<0; pre++) *c++='0'; /* add any 0's after '.' */
|
||||||
|
/*printf("res %s\n", string); */
|
||||||
|
return string;
|
||||||
|
} /* decimal32ToString */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* to-number -- conversion from numeric string */
|
||||||
|
/* */
|
||||||
|
/* decimal32FromString(result, string, set); */
|
||||||
|
/* */
|
||||||
|
/* result is the decimal32 format number which gets the result of */
|
||||||
|
/* the conversion */
|
||||||
|
/* *string is the character string which should contain a valid */
|
||||||
|
/* number (which may be a special value) */
|
||||||
|
/* set is the context */
|
||||||
|
/* */
|
||||||
|
/* The context is supplied to this routine is used for error handling */
|
||||||
|
/* (setting of status and traps) and for the rounding mode, only. */
|
||||||
|
/* If an error occurs, the result will be a valid decimal32 NaN. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
decimal32 * decimal32FromString(decimal32 *result, const char *string,
|
||||||
|
decContext *set) {
|
||||||
|
decContext dc; /* work */
|
||||||
|
decNumber dn; /* .. */
|
||||||
|
|
||||||
|
decContextDefault(&dc, DEC_INIT_DECIMAL32); /* no traps, please */
|
||||||
|
dc.round=set->round; /* use supplied rounding */
|
||||||
|
|
||||||
|
decNumberFromString(&dn, string, &dc); /* will round if needed */
|
||||||
|
decimal32FromNumber(result, &dn, &dc);
|
||||||
|
if (dc.status!=0) { /* something happened */
|
||||||
|
decContextSetStatus(set, dc.status); /* .. pass it on */
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} /* decimal32FromString */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decimal32IsCanonical -- test whether encoding is canonical */
|
||||||
|
/* d32 is the source decimal32 */
|
||||||
|
/* returns 1 if the encoding of d32 is canonical, 0 otherwise */
|
||||||
|
/* No error is possible. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
uint32_t decimal32IsCanonical(const decimal32 *d32) {
|
||||||
|
decNumber dn; /* work */
|
||||||
|
decimal32 canon; /* .. */
|
||||||
|
decContext dc; /* .. */
|
||||||
|
decContextDefault(&dc, DEC_INIT_DECIMAL32);
|
||||||
|
decimal32ToNumber(d32, &dn);
|
||||||
|
decimal32FromNumber(&canon, &dn, &dc);/* canon will now be canonical */
|
||||||
|
return memcmp(d32, &canon, DECIMAL32_Bytes)==0;
|
||||||
|
} /* decimal32IsCanonical */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decimal32Canonical -- copy an encoding, ensuring it is canonical */
|
||||||
|
/* d32 is the source decimal32 */
|
||||||
|
/* result is the target (may be the same decimal32) */
|
||||||
|
/* returns result */
|
||||||
|
/* No error is possible. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
decimal32 * decimal32Canonical(decimal32 *result, const decimal32 *d32) {
|
||||||
|
decNumber dn; /* work */
|
||||||
|
decContext dc; /* .. */
|
||||||
|
decContextDefault(&dc, DEC_INIT_DECIMAL32);
|
||||||
|
decimal32ToNumber(d32, &dn);
|
||||||
|
decimal32FromNumber(result, &dn, &dc);/* result will now be canonical */
|
||||||
|
return result;
|
||||||
|
} /* decimal32Canonical */
|
||||||
|
|
||||||
|
#if DECTRACE || DECCHECK
|
||||||
|
/* Macros for accessing decimal32 fields. These assume the argument
|
||||||
|
is a reference (pointer) to the decimal32 structure, and the
|
||||||
|
decimal32 is in network byte order (big-endian) */
|
||||||
|
/* Get sign */
|
||||||
|
#define decimal32Sign(d) ((unsigned)(d)->bytes[0]>>7)
|
||||||
|
|
||||||
|
/* Get combination field */
|
||||||
|
#define decimal32Comb(d) (((d)->bytes[0] & 0x7c)>>2)
|
||||||
|
|
||||||
|
/* Get exponent continuation [does not remove bias] */
|
||||||
|
#define decimal32ExpCon(d) ((((d)->bytes[0] & 0x03)<<4) \
|
||||||
|
| ((unsigned)(d)->bytes[1]>>4))
|
||||||
|
|
||||||
|
/* Set sign [this assumes sign previously 0] */
|
||||||
|
#define decimal32SetSign(d, b) { \
|
||||||
|
(d)->bytes[0]|=((unsigned)(b)<<7);}
|
||||||
|
|
||||||
|
/* Set exponent continuation [does not apply bias] */
|
||||||
|
/* This assumes range has been checked and exponent previously 0; */
|
||||||
|
/* type of exponent must be unsigned */
|
||||||
|
#define decimal32SetExpCon(d, e) { \
|
||||||
|
(d)->bytes[0]|=(uint8_t)((e)>>4); \
|
||||||
|
(d)->bytes[1]|=(uint8_t)(((e)&0x0F)<<4);}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decimal32Show -- display a decimal32 in hexadecimal [debug aid] */
|
||||||
|
/* d32 -- the number to show */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* Also shows sign/cob/expconfields extracted - valid bigendian only */
|
||||||
|
void decimal32Show(const decimal32 *d32) {
|
||||||
|
char buf[DECIMAL32_Bytes*2+1];
|
||||||
|
Int i, j=0;
|
||||||
|
|
||||||
|
if (DECLITEND) {
|
||||||
|
for (i=0; i<DECIMAL32_Bytes; i++, j+=2) {
|
||||||
|
sprintf(&buf[j], "%02x", d32->bytes[3-i]);
|
||||||
|
}
|
||||||
|
printf(" D32> %s [S:%d Cb:%02x Ec:%02x] LittleEndian\n", buf,
|
||||||
|
d32->bytes[3]>>7, (d32->bytes[3]>>2)&0x1f,
|
||||||
|
((d32->bytes[3]&0x3)<<4)| (d32->bytes[2]>>4));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (i=0; i<DECIMAL32_Bytes; i++, j+=2) {
|
||||||
|
sprintf(&buf[j], "%02x", d32->bytes[i]);
|
||||||
|
}
|
||||||
|
printf(" D32> %s [S:%d Cb:%02x Ec:%02x] BigEndian\n", buf,
|
||||||
|
decimal32Sign(d32), decimal32Comb(d32), decimal32ExpCon(d32));
|
||||||
|
}
|
||||||
|
} /* decimal32Show */
|
||||||
|
#endif
|
850
libdecnumber/dpd/decimal64.c
Normal file
850
libdecnumber/dpd/decimal64.c
Normal file
|
@ -0,0 +1,850 @@
|
||||||
|
/* Decimal 64-bit format 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 64-bit format module */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* This module comprises the routines for decimal64 format numbers. */
|
||||||
|
/* Conversions are supplied to and from decNumber and String. */
|
||||||
|
/* */
|
||||||
|
/* This is used when decNumber provides operations, either for all */
|
||||||
|
/* operations or as a proxy between decNumber and decSingle. */
|
||||||
|
/* */
|
||||||
|
/* Error handling is the same as decNumber (qv.). */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
#include <string.h> /* [for memset/memcpy] */
|
||||||
|
#include <stdio.h> /* [for printf] */
|
||||||
|
|
||||||
|
#include "libdecnumber/dconfig.h"
|
||||||
|
#define DECNUMDIGITS 16 /* make decNumbers with space for 16 */
|
||||||
|
#include "libdecnumber/decNumber.h"
|
||||||
|
#include "libdecnumber/decNumberLocal.h"
|
||||||
|
#include "libdecnumber/dpd/decimal64.h"
|
||||||
|
|
||||||
|
/* Utility routines and tables [in decimal64.c]; externs for C++ */
|
||||||
|
extern const uInt COMBEXP[32], COMBMSD[32];
|
||||||
|
extern const uByte BIN2CHAR[4001];
|
||||||
|
|
||||||
|
extern void decDigitsFromDPD(decNumber *, const uInt *, Int);
|
||||||
|
extern void decDigitsToDPD(const decNumber *, uInt *, Int);
|
||||||
|
|
||||||
|
#if DECTRACE || DECCHECK
|
||||||
|
void decimal64Show(const decimal64 *); /* for debug */
|
||||||
|
extern void decNumberShow(const decNumber *); /* .. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Useful macro */
|
||||||
|
/* Clear a structure (e.g., a decNumber) */
|
||||||
|
#define DEC_clear(d) memset(d, 0, sizeof(*d))
|
||||||
|
|
||||||
|
/* define and include the tables to use for conversions */
|
||||||
|
#define DEC_BIN2CHAR 1
|
||||||
|
#define DEC_DPD2BIN 1
|
||||||
|
#define DEC_BIN2DPD 1 /* used for all sizes */
|
||||||
|
#include "libdecnumber/decDPD.h"
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decimal64FromNumber -- convert decNumber to decimal64 */
|
||||||
|
/* */
|
||||||
|
/* ds is the target decimal64 */
|
||||||
|
/* dn is the source number (assumed valid) */
|
||||||
|
/* set is the context, used only for reporting errors */
|
||||||
|
/* */
|
||||||
|
/* The set argument is used only for status reporting and for the */
|
||||||
|
/* rounding mode (used if the coefficient is more than DECIMAL64_Pmax */
|
||||||
|
/* digits or an overflow is detected). If the exponent is out of the */
|
||||||
|
/* valid range then Overflow or Underflow will be raised. */
|
||||||
|
/* After Underflow a subnormal result is possible. */
|
||||||
|
/* */
|
||||||
|
/* DEC_Clamped is set if the number has to be 'folded down' to fit, */
|
||||||
|
/* by reducing its exponent and multiplying the coefficient by a */
|
||||||
|
/* power of ten, or if the exponent on a zero had to be clamped. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
decimal64 * decimal64FromNumber(decimal64 *d64, const decNumber *dn,
|
||||||
|
decContext *set) {
|
||||||
|
uInt status=0; /* status accumulator */
|
||||||
|
Int ae; /* adjusted exponent */
|
||||||
|
decNumber dw; /* work */
|
||||||
|
decContext dc; /* .. */
|
||||||
|
uInt *pu; /* .. */
|
||||||
|
uInt comb, exp; /* .. */
|
||||||
|
uInt targar[2]={0, 0}; /* target 64-bit */
|
||||||
|
#define targhi targar[1] /* name the word with the sign */
|
||||||
|
#define targlo targar[0] /* and the other */
|
||||||
|
|
||||||
|
/* If the number has too many digits, or the exponent could be */
|
||||||
|
/* out of range then reduce the number under the appropriate */
|
||||||
|
/* constraints. This could push the number to Infinity or zero, */
|
||||||
|
/* so this check and rounding must be done before generating the */
|
||||||
|
/* decimal64] */
|
||||||
|
ae=dn->exponent+dn->digits-1; /* [0 if special] */
|
||||||
|
if (dn->digits>DECIMAL64_Pmax /* too many digits */
|
||||||
|
|| ae>DECIMAL64_Emax /* likely overflow */
|
||||||
|
|| ae<DECIMAL64_Emin) { /* likely underflow */
|
||||||
|
decContextDefault(&dc, DEC_INIT_DECIMAL64); /* [no traps] */
|
||||||
|
dc.round=set->round; /* use supplied rounding */
|
||||||
|
decNumberPlus(&dw, dn, &dc); /* (round and check) */
|
||||||
|
/* [this changes -0 to 0, so enforce the sign...] */
|
||||||
|
dw.bits|=dn->bits&DECNEG;
|
||||||
|
status=dc.status; /* save status */
|
||||||
|
dn=&dw; /* use the work number */
|
||||||
|
} /* maybe out of range */
|
||||||
|
|
||||||
|
if (dn->bits&DECSPECIAL) { /* a special value */
|
||||||
|
if (dn->bits&DECINF) targhi=DECIMAL_Inf<<24;
|
||||||
|
else { /* sNaN or qNaN */
|
||||||
|
if ((*dn->lsu!=0 || dn->digits>1) /* non-zero coefficient */
|
||||||
|
&& (dn->digits<DECIMAL64_Pmax)) { /* coefficient fits */
|
||||||
|
decDigitsToDPD(dn, targar, 0);
|
||||||
|
}
|
||||||
|
if (dn->bits&DECNAN) targhi|=DECIMAL_NaN<<24;
|
||||||
|
else targhi|=DECIMAL_sNaN<<24;
|
||||||
|
} /* a NaN */
|
||||||
|
} /* special */
|
||||||
|
|
||||||
|
else { /* is finite */
|
||||||
|
if (decNumberIsZero(dn)) { /* is a zero */
|
||||||
|
/* set and clamp exponent */
|
||||||
|
if (dn->exponent<-DECIMAL64_Bias) {
|
||||||
|
exp=0; /* low clamp */
|
||||||
|
status|=DEC_Clamped;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
exp=dn->exponent+DECIMAL64_Bias; /* bias exponent */
|
||||||
|
if (exp>DECIMAL64_Ehigh) { /* top clamp */
|
||||||
|
exp=DECIMAL64_Ehigh;
|
||||||
|
status|=DEC_Clamped;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
comb=(exp>>5) & 0x18; /* msd=0, exp top 2 bits .. */
|
||||||
|
}
|
||||||
|
else { /* non-zero finite number */
|
||||||
|
uInt msd; /* work */
|
||||||
|
Int pad=0; /* coefficient pad digits */
|
||||||
|
|
||||||
|
/* the dn is known to fit, but it may need to be padded */
|
||||||
|
exp=(uInt)(dn->exponent+DECIMAL64_Bias); /* bias exponent */
|
||||||
|
if (exp>DECIMAL64_Ehigh) { /* fold-down case */
|
||||||
|
pad=exp-DECIMAL64_Ehigh;
|
||||||
|
exp=DECIMAL64_Ehigh; /* [to maximum] */
|
||||||
|
status|=DEC_Clamped;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fastpath common case */
|
||||||
|
if (DECDPUN==3 && pad==0) {
|
||||||
|
uInt dpd[6]={0,0,0,0,0,0};
|
||||||
|
uInt i;
|
||||||
|
Int d=dn->digits;
|
||||||
|
for (i=0; d>0; i++, d-=3) dpd[i]=BIN2DPD[dn->lsu[i]];
|
||||||
|
targlo =dpd[0];
|
||||||
|
targlo|=dpd[1]<<10;
|
||||||
|
targlo|=dpd[2]<<20;
|
||||||
|
if (dn->digits>6) {
|
||||||
|
targlo|=dpd[3]<<30;
|
||||||
|
targhi =dpd[3]>>2;
|
||||||
|
targhi|=dpd[4]<<8;
|
||||||
|
}
|
||||||
|
msd=dpd[5]; /* [did not really need conversion] */
|
||||||
|
}
|
||||||
|
else { /* general case */
|
||||||
|
decDigitsToDPD(dn, targar, pad);
|
||||||
|
/* save and clear the top digit */
|
||||||
|
msd=targhi>>18;
|
||||||
|
targhi&=0x0003ffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create the combination field */
|
||||||
|
if (msd>=8) comb=0x18 | ((exp>>7) & 0x06) | (msd & 0x01);
|
||||||
|
else comb=((exp>>5) & 0x18) | msd;
|
||||||
|
}
|
||||||
|
targhi|=comb<<26; /* add combination field .. */
|
||||||
|
targhi|=(exp&0xff)<<18; /* .. and exponent continuation */
|
||||||
|
} /* finite */
|
||||||
|
|
||||||
|
if (dn->bits&DECNEG) targhi|=0x80000000; /* add sign bit */
|
||||||
|
|
||||||
|
/* now write to storage; this is now always endian */
|
||||||
|
pu=(uInt *)d64->bytes; /* overlay */
|
||||||
|
if (DECLITEND) {
|
||||||
|
pu[0]=targar[0]; /* directly store the low int */
|
||||||
|
pu[1]=targar[1]; /* then the high int */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pu[0]=targar[1]; /* directly store the high int */
|
||||||
|
pu[1]=targar[0]; /* then the low int */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status!=0) decContextSetStatus(set, status); /* pass on status */
|
||||||
|
/* decimal64Show(d64); */
|
||||||
|
return d64;
|
||||||
|
} /* decimal64FromNumber */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decimal64ToNumber -- convert decimal64 to decNumber */
|
||||||
|
/* d64 is the source decimal64 */
|
||||||
|
/* dn is the target number, with appropriate space */
|
||||||
|
/* No error is possible. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
decNumber * decimal64ToNumber(const decimal64 *d64, decNumber *dn) {
|
||||||
|
uInt msd; /* coefficient MSD */
|
||||||
|
uInt exp; /* exponent top two bits */
|
||||||
|
uInt comb; /* combination field */
|
||||||
|
const uInt *pu; /* work */
|
||||||
|
Int need; /* .. */
|
||||||
|
uInt sourar[2]; /* source 64-bit */
|
||||||
|
#define sourhi sourar[1] /* name the word with the sign */
|
||||||
|
#define sourlo sourar[0] /* and the lower word */
|
||||||
|
|
||||||
|
/* load source from storage; this is endian */
|
||||||
|
pu=(const uInt *)d64->bytes; /* overlay */
|
||||||
|
if (DECLITEND) {
|
||||||
|
sourlo=pu[0]; /* directly load the low int */
|
||||||
|
sourhi=pu[1]; /* then the high int */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sourhi=pu[0]; /* directly load the high int */
|
||||||
|
sourlo=pu[1]; /* then the low int */
|
||||||
|
}
|
||||||
|
|
||||||
|
comb=(sourhi>>26)&0x1f; /* combination field */
|
||||||
|
|
||||||
|
decNumberZero(dn); /* clean number */
|
||||||
|
if (sourhi&0x80000000) dn->bits=DECNEG; /* set sign if negative */
|
||||||
|
|
||||||
|
msd=COMBMSD[comb]; /* decode the combination field */
|
||||||
|
exp=COMBEXP[comb]; /* .. */
|
||||||
|
|
||||||
|
if (exp==3) { /* is a special */
|
||||||
|
if (msd==0) {
|
||||||
|
dn->bits|=DECINF;
|
||||||
|
return dn; /* no coefficient needed */
|
||||||
|
}
|
||||||
|
else if (sourhi&0x02000000) dn->bits|=DECSNAN;
|
||||||
|
else dn->bits|=DECNAN;
|
||||||
|
msd=0; /* no top digit */
|
||||||
|
}
|
||||||
|
else { /* is a finite number */
|
||||||
|
dn->exponent=(exp<<8)+((sourhi>>18)&0xff)-DECIMAL64_Bias; /* unbiased */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the coefficient */
|
||||||
|
sourhi&=0x0003ffff; /* clean coefficient continuation */
|
||||||
|
if (msd) { /* non-zero msd */
|
||||||
|
sourhi|=msd<<18; /* prefix to coefficient */
|
||||||
|
need=6; /* process 6 declets */
|
||||||
|
}
|
||||||
|
else { /* msd=0 */
|
||||||
|
if (!sourhi) { /* top word 0 */
|
||||||
|
if (!sourlo) return dn; /* easy: coefficient is 0 */
|
||||||
|
need=3; /* process at least 3 declets */
|
||||||
|
if (sourlo&0xc0000000) need++; /* process 4 declets */
|
||||||
|
/* [could reduce some more, here] */
|
||||||
|
}
|
||||||
|
else { /* some bits in top word, msd=0 */
|
||||||
|
need=4; /* process at least 4 declets */
|
||||||
|
if (sourhi&0x0003ff00) need++; /* top declet!=0, process 5 */
|
||||||
|
}
|
||||||
|
} /*msd=0 */
|
||||||
|
|
||||||
|
decDigitsFromDPD(dn, sourar, need); /* process declets */
|
||||||
|
return dn;
|
||||||
|
} /* decimal64ToNumber */
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* to-scientific-string -- conversion to numeric string */
|
||||||
|
/* to-engineering-string -- conversion to numeric string */
|
||||||
|
/* */
|
||||||
|
/* decimal64ToString(d64, string); */
|
||||||
|
/* decimal64ToEngString(d64, string); */
|
||||||
|
/* */
|
||||||
|
/* d64 is the decimal64 format number to convert */
|
||||||
|
/* string is the string where the result will be laid out */
|
||||||
|
/* */
|
||||||
|
/* string must be at least 24 characters */
|
||||||
|
/* */
|
||||||
|
/* No error is possible, and no status can be set. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
char * decimal64ToEngString(const decimal64 *d64, char *string){
|
||||||
|
decNumber dn; /* work */
|
||||||
|
decimal64ToNumber(d64, &dn);
|
||||||
|
decNumberToEngString(&dn, string);
|
||||||
|
return string;
|
||||||
|
} /* decimal64ToEngString */
|
||||||
|
|
||||||
|
char * decimal64ToString(const decimal64 *d64, char *string){
|
||||||
|
uInt msd; /* coefficient MSD */
|
||||||
|
Int exp; /* exponent top two bits or full */
|
||||||
|
uInt comb; /* combination field */
|
||||||
|
char *cstart; /* coefficient start */
|
||||||
|
char *c; /* output pointer in string */
|
||||||
|
const uInt *pu; /* work */
|
||||||
|
char *s, *t; /* .. (source, target) */
|
||||||
|
Int dpd; /* .. */
|
||||||
|
Int pre, e; /* .. */
|
||||||
|
const uByte *u; /* .. */
|
||||||
|
|
||||||
|
uInt sourar[2]; /* source 64-bit */
|
||||||
|
#define sourhi sourar[1] /* name the word with the sign */
|
||||||
|
#define sourlo sourar[0] /* and the lower word */
|
||||||
|
|
||||||
|
/* load source from storage; this is endian */
|
||||||
|
pu=(const uInt *)d64->bytes; /* overlay */
|
||||||
|
if (DECLITEND) {
|
||||||
|
sourlo=pu[0]; /* directly load the low int */
|
||||||
|
sourhi=pu[1]; /* then the high int */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sourhi=pu[0]; /* directly load the high int */
|
||||||
|
sourlo=pu[1]; /* then the low int */
|
||||||
|
}
|
||||||
|
|
||||||
|
c=string; /* where result will go */
|
||||||
|
if (((Int)sourhi)<0) *c++='-'; /* handle sign */
|
||||||
|
|
||||||
|
comb=(sourhi>>26)&0x1f; /* combination field */
|
||||||
|
msd=COMBMSD[comb]; /* decode the combination field */
|
||||||
|
exp=COMBEXP[comb]; /* .. */
|
||||||
|
|
||||||
|
if (exp==3) {
|
||||||
|
if (msd==0) { /* infinity */
|
||||||
|
strcpy(c, "Inf");
|
||||||
|
strcpy(c+3, "inity");
|
||||||
|
return string; /* easy */
|
||||||
|
}
|
||||||
|
if (sourhi&0x02000000) *c++='s'; /* sNaN */
|
||||||
|
strcpy(c, "NaN"); /* complete word */
|
||||||
|
c+=3; /* step past */
|
||||||
|
if (sourlo==0 && (sourhi&0x0003ffff)==0) return string; /* zero payload */
|
||||||
|
/* otherwise drop through to add integer; set correct exp */
|
||||||
|
exp=0; msd=0; /* setup for following code */
|
||||||
|
}
|
||||||
|
else exp=(exp<<8)+((sourhi>>18)&0xff)-DECIMAL64_Bias;
|
||||||
|
|
||||||
|
/* convert 16 digits of significand to characters */
|
||||||
|
cstart=c; /* save start of coefficient */
|
||||||
|
if (msd) *c++='0'+(char)msd; /* non-zero most significant digit */
|
||||||
|
|
||||||
|
/* Now decode the declets. After extracting each one, it is */
|
||||||
|
/* decoded to binary and then to a 4-char sequence by table lookup; */
|
||||||
|
/* the 4-chars are a 1-char length (significant digits, except 000 */
|
||||||
|
/* has length 0). This allows us to left-align the first declet */
|
||||||
|
/* with non-zero content, then remaining ones are full 3-char */
|
||||||
|
/* length. We use fixed-length memcpys because variable-length */
|
||||||
|
/* causes a subroutine call in GCC. (These are length 4 for speed */
|
||||||
|
/* and are safe because the array has an extra terminator byte.) */
|
||||||
|
#define dpd2char u=&BIN2CHAR[DPD2BIN[dpd]*4]; \
|
||||||
|
if (c!=cstart) {memcpy(c, u+1, 4); c+=3;} \
|
||||||
|
else if (*u) {memcpy(c, u+4-*u, 4); c+=*u;}
|
||||||
|
|
||||||
|
dpd=(sourhi>>8)&0x3ff; /* declet 1 */
|
||||||
|
dpd2char;
|
||||||
|
dpd=((sourhi&0xff)<<2) | (sourlo>>30); /* declet 2 */
|
||||||
|
dpd2char;
|
||||||
|
dpd=(sourlo>>20)&0x3ff; /* declet 3 */
|
||||||
|
dpd2char;
|
||||||
|
dpd=(sourlo>>10)&0x3ff; /* declet 4 */
|
||||||
|
dpd2char;
|
||||||
|
dpd=(sourlo)&0x3ff; /* declet 5 */
|
||||||
|
dpd2char;
|
||||||
|
|
||||||
|
if (c==cstart) *c++='0'; /* all zeros -- make 0 */
|
||||||
|
|
||||||
|
if (exp==0) { /* integer or NaN case -- easy */
|
||||||
|
*c='\0'; /* terminate */
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* non-0 exponent */
|
||||||
|
e=0; /* assume no E */
|
||||||
|
pre=c-cstart+exp;
|
||||||
|
/* [here, pre-exp is the digits count (==1 for zero)] */
|
||||||
|
if (exp>0 || pre<-5) { /* need exponential form */
|
||||||
|
e=pre-1; /* calculate E value */
|
||||||
|
pre=1; /* assume one digit before '.' */
|
||||||
|
} /* exponential form */
|
||||||
|
|
||||||
|
/* modify the coefficient, adding 0s, '.', and E+nn as needed */
|
||||||
|
s=c-1; /* source (LSD) */
|
||||||
|
if (pre>0) { /* ddd.ddd (plain), perhaps with E */
|
||||||
|
char *dotat=cstart+pre;
|
||||||
|
if (dotat<c) { /* if embedded dot needed... */
|
||||||
|
t=c; /* target */
|
||||||
|
for (; s>=dotat; s--, t--) *t=*s; /* open the gap; leave t at gap */
|
||||||
|
*t='.'; /* insert the dot */
|
||||||
|
c++; /* length increased by one */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* finally add the E-part, if needed; it will never be 0, and has */
|
||||||
|
/* a maximum length of 3 digits */
|
||||||
|
if (e!=0) {
|
||||||
|
*c++='E'; /* starts with E */
|
||||||
|
*c++='+'; /* assume positive */
|
||||||
|
if (e<0) {
|
||||||
|
*(c-1)='-'; /* oops, need '-' */
|
||||||
|
e=-e; /* uInt, please */
|
||||||
|
}
|
||||||
|
u=&BIN2CHAR[e*4]; /* -> length byte */
|
||||||
|
memcpy(c, u+4-*u, 4); /* copy fixed 4 characters [is safe] */
|
||||||
|
c+=*u; /* bump pointer appropriately */
|
||||||
|
}
|
||||||
|
*c='\0'; /* add terminator */
|
||||||
|
/*printf("res %s\n", string); */
|
||||||
|
return string;
|
||||||
|
} /* pre>0 */
|
||||||
|
|
||||||
|
/* -5<=pre<=0: here for plain 0.ddd or 0.000ddd forms (can never have E) */
|
||||||
|
t=c+1-pre;
|
||||||
|
*(t+1)='\0'; /* can add terminator now */
|
||||||
|
for (; s>=cstart; s--, t--) *t=*s; /* shift whole coefficient right */
|
||||||
|
c=cstart;
|
||||||
|
*c++='0'; /* always starts with 0. */
|
||||||
|
*c++='.';
|
||||||
|
for (; pre<0; pre++) *c++='0'; /* add any 0's after '.' */
|
||||||
|
/*printf("res %s\n", string); */
|
||||||
|
return string;
|
||||||
|
} /* decimal64ToString */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* to-number -- conversion from numeric string */
|
||||||
|
/* */
|
||||||
|
/* decimal64FromString(result, string, set); */
|
||||||
|
/* */
|
||||||
|
/* result is the decimal64 format number which gets the result of */
|
||||||
|
/* the conversion */
|
||||||
|
/* *string is the character string which should contain a valid */
|
||||||
|
/* number (which may be a special value) */
|
||||||
|
/* set is the context */
|
||||||
|
/* */
|
||||||
|
/* The context is supplied to this routine is used for error handling */
|
||||||
|
/* (setting of status and traps) and for the rounding mode, only. */
|
||||||
|
/* If an error occurs, the result will be a valid decimal64 NaN. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
decimal64 * decimal64FromString(decimal64 *result, const char *string,
|
||||||
|
decContext *set) {
|
||||||
|
decContext dc; /* work */
|
||||||
|
decNumber dn; /* .. */
|
||||||
|
|
||||||
|
decContextDefault(&dc, DEC_INIT_DECIMAL64); /* no traps, please */
|
||||||
|
dc.round=set->round; /* use supplied rounding */
|
||||||
|
|
||||||
|
decNumberFromString(&dn, string, &dc); /* will round if needed */
|
||||||
|
|
||||||
|
decimal64FromNumber(result, &dn, &dc);
|
||||||
|
if (dc.status!=0) { /* something happened */
|
||||||
|
decContextSetStatus(set, dc.status); /* .. pass it on */
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} /* decimal64FromString */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decimal64IsCanonical -- test whether encoding is canonical */
|
||||||
|
/* d64 is the source decimal64 */
|
||||||
|
/* returns 1 if the encoding of d64 is canonical, 0 otherwise */
|
||||||
|
/* No error is possible. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
uint32_t decimal64IsCanonical(const decimal64 *d64) {
|
||||||
|
decNumber dn; /* work */
|
||||||
|
decimal64 canon; /* .. */
|
||||||
|
decContext dc; /* .. */
|
||||||
|
decContextDefault(&dc, DEC_INIT_DECIMAL64);
|
||||||
|
decimal64ToNumber(d64, &dn);
|
||||||
|
decimal64FromNumber(&canon, &dn, &dc);/* canon will now be canonical */
|
||||||
|
return memcmp(d64, &canon, DECIMAL64_Bytes)==0;
|
||||||
|
} /* decimal64IsCanonical */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decimal64Canonical -- copy an encoding, ensuring it is canonical */
|
||||||
|
/* d64 is the source decimal64 */
|
||||||
|
/* result is the target (may be the same decimal64) */
|
||||||
|
/* returns result */
|
||||||
|
/* No error is possible. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
decimal64 * decimal64Canonical(decimal64 *result, const decimal64 *d64) {
|
||||||
|
decNumber dn; /* work */
|
||||||
|
decContext dc; /* .. */
|
||||||
|
decContextDefault(&dc, DEC_INIT_DECIMAL64);
|
||||||
|
decimal64ToNumber(d64, &dn);
|
||||||
|
decimal64FromNumber(result, &dn, &dc);/* result will now be canonical */
|
||||||
|
return result;
|
||||||
|
} /* decimal64Canonical */
|
||||||
|
|
||||||
|
#if DECTRACE || DECCHECK
|
||||||
|
/* Macros for accessing decimal64 fields. These assume the
|
||||||
|
argument is a reference (pointer) to the decimal64 structure,
|
||||||
|
and the decimal64 is in network byte order (big-endian) */
|
||||||
|
/* Get sign */
|
||||||
|
#define decimal64Sign(d) ((unsigned)(d)->bytes[0]>>7)
|
||||||
|
|
||||||
|
/* Get combination field */
|
||||||
|
#define decimal64Comb(d) (((d)->bytes[0] & 0x7c)>>2)
|
||||||
|
|
||||||
|
/* Get exponent continuation [does not remove bias] */
|
||||||
|
#define decimal64ExpCon(d) ((((d)->bytes[0] & 0x03)<<6) \
|
||||||
|
| ((unsigned)(d)->bytes[1]>>2))
|
||||||
|
|
||||||
|
/* Set sign [this assumes sign previously 0] */
|
||||||
|
#define decimal64SetSign(d, b) { \
|
||||||
|
(d)->bytes[0]|=((unsigned)(b)<<7);}
|
||||||
|
|
||||||
|
/* Set exponent continuation [does not apply bias] */
|
||||||
|
/* This assumes range has been checked and exponent previously 0; */
|
||||||
|
/* type of exponent must be unsigned */
|
||||||
|
#define decimal64SetExpCon(d, e) { \
|
||||||
|
(d)->bytes[0]|=(uint8_t)((e)>>6); \
|
||||||
|
(d)->bytes[1]|=(uint8_t)(((e)&0x3F)<<2);}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decimal64Show -- display a decimal64 in hexadecimal [debug aid] */
|
||||||
|
/* d64 -- the number to show */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* Also shows sign/cob/expconfields extracted */
|
||||||
|
void decimal64Show(const decimal64 *d64) {
|
||||||
|
char buf[DECIMAL64_Bytes*2+1];
|
||||||
|
Int i, j=0;
|
||||||
|
|
||||||
|
if (DECLITEND) {
|
||||||
|
for (i=0; i<DECIMAL64_Bytes; i++, j+=2) {
|
||||||
|
sprintf(&buf[j], "%02x", d64->bytes[7-i]);
|
||||||
|
}
|
||||||
|
printf(" D64> %s [S:%d Cb:%02x Ec:%02x] LittleEndian\n", buf,
|
||||||
|
d64->bytes[7]>>7, (d64->bytes[7]>>2)&0x1f,
|
||||||
|
((d64->bytes[7]&0x3)<<6)| (d64->bytes[6]>>2));
|
||||||
|
}
|
||||||
|
else { /* big-endian */
|
||||||
|
for (i=0; i<DECIMAL64_Bytes; i++, j+=2) {
|
||||||
|
sprintf(&buf[j], "%02x", d64->bytes[i]);
|
||||||
|
}
|
||||||
|
printf(" D64> %s [S:%d Cb:%02x Ec:%02x] BigEndian\n", buf,
|
||||||
|
decimal64Sign(d64), decimal64Comb(d64), decimal64ExpCon(d64));
|
||||||
|
}
|
||||||
|
} /* decimal64Show */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ================================================================== */
|
||||||
|
/* Shared utility routines and tables */
|
||||||
|
/* ================================================================== */
|
||||||
|
/* define and include the conversion tables to use for shared code */
|
||||||
|
#if DECDPUN==3
|
||||||
|
#define DEC_DPD2BIN 1
|
||||||
|
#else
|
||||||
|
#define DEC_DPD2BCD 1
|
||||||
|
#endif
|
||||||
|
#include "libdecnumber/decDPD.h"
|
||||||
|
|
||||||
|
/* The maximum number of decNumberUnits needed for a working copy of */
|
||||||
|
/* the units array is the ceiling of digits/DECDPUN, where digits is */
|
||||||
|
/* the maximum number of digits in any of the formats for which this */
|
||||||
|
/* is used. decimal128.h must not be included in this module, so, as */
|
||||||
|
/* a very special case, that number is defined as a literal here. */
|
||||||
|
#define DECMAX754 34
|
||||||
|
#define DECMAXUNITS ((DECMAX754+DECDPUN-1)/DECDPUN)
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* Combination field lookup tables (uInts to save measurable work) */
|
||||||
|
/* */
|
||||||
|
/* COMBEXP - 2-bit most-significant-bits of exponent */
|
||||||
|
/* [11 if an Infinity or NaN] */
|
||||||
|
/* COMBMSD - 4-bit most-significant-digit */
|
||||||
|
/* [0=Infinity, 1=NaN if COMBEXP=11] */
|
||||||
|
/* */
|
||||||
|
/* Both are indexed by the 5-bit combination field (0-31) */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
const uInt COMBEXP[32]={0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
0, 0, 1, 1, 2, 2, 3, 3};
|
||||||
|
const uInt COMBMSD[32]={0, 1, 2, 3, 4, 5, 6, 7,
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7,
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7,
|
||||||
|
8, 9, 8, 9, 8, 9, 0, 1};
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decDigitsToDPD -- pack coefficient into DPD form */
|
||||||
|
/* */
|
||||||
|
/* dn is the source number (assumed valid, max DECMAX754 digits) */
|
||||||
|
/* targ is 1, 2, or 4-element uInt array, which the caller must */
|
||||||
|
/* have cleared to zeros */
|
||||||
|
/* shift is the number of 0 digits to add on the right (normally 0) */
|
||||||
|
/* */
|
||||||
|
/* The coefficient must be known small enough to fit. The full */
|
||||||
|
/* coefficient is copied, including the leading 'odd' digit. This */
|
||||||
|
/* digit is retrieved and packed into the combination field by the */
|
||||||
|
/* caller. */
|
||||||
|
/* */
|
||||||
|
/* The target uInts are altered only as necessary to receive the */
|
||||||
|
/* digits of the decNumber. When more than one uInt is needed, they */
|
||||||
|
/* are filled from left to right (that is, the uInt at offset 0 will */
|
||||||
|
/* end up with the least-significant digits). */
|
||||||
|
/* */
|
||||||
|
/* shift is used for 'fold-down' padding. */
|
||||||
|
/* */
|
||||||
|
/* No error is possible. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
#if DECDPUN<=4
|
||||||
|
/* Constant multipliers for divide-by-power-of five using reciprocal */
|
||||||
|
/* multiply, after removing powers of 2 by shifting, and final shift */
|
||||||
|
/* of 17 [we only need up to **4] */
|
||||||
|
static const uInt multies[]={131073, 26215, 5243, 1049, 210};
|
||||||
|
/* QUOT10 -- macro to return the quotient of unit u divided by 10**n */
|
||||||
|
#define QUOT10(u, n) ((((uInt)(u)>>(n))*multies[n])>>17)
|
||||||
|
#endif
|
||||||
|
void decDigitsToDPD(const decNumber *dn, uInt *targ, Int shift) {
|
||||||
|
Int cut; /* work */
|
||||||
|
Int n; /* output bunch counter */
|
||||||
|
Int digits=dn->digits; /* digit countdown */
|
||||||
|
uInt dpd; /* densely packed decimal value */
|
||||||
|
uInt bin; /* binary value 0-999 */
|
||||||
|
uInt *uout=targ; /* -> current output uInt */
|
||||||
|
uInt uoff=0; /* -> current output offset [from right] */
|
||||||
|
const Unit *inu=dn->lsu; /* -> current input unit */
|
||||||
|
Unit uar[DECMAXUNITS]; /* working copy of units, iff shifted */
|
||||||
|
#if DECDPUN!=3 /* not fast path */
|
||||||
|
Unit in; /* current unit */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (shift!=0) { /* shift towards most significant required */
|
||||||
|
/* shift the units array to the left by pad digits and copy */
|
||||||
|
/* [this code is a special case of decShiftToMost, which could */
|
||||||
|
/* be used instead if exposed and the array were copied first] */
|
||||||
|
const Unit *source; /* .. */
|
||||||
|
Unit *target, *first; /* .. */
|
||||||
|
uInt next=0; /* work */
|
||||||
|
|
||||||
|
source=dn->lsu+D2U(digits)-1; /* where msu comes from */
|
||||||
|
target=uar+D2U(digits)-1+D2U(shift);/* where upper part of first cut goes */
|
||||||
|
cut=DECDPUN-MSUDIGITS(shift); /* where to slice */
|
||||||
|
if (cut==0) { /* unit-boundary case */
|
||||||
|
for (; source>=dn->lsu; source--, target--) *target=*source;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
first=uar+D2U(digits+shift)-1; /* where msu will end up */
|
||||||
|
for (; source>=dn->lsu; source--, target--) {
|
||||||
|
/* split the source Unit and accumulate remainder for next */
|
||||||
|
#if DECDPUN<=4
|
||||||
|
uInt quot=QUOT10(*source, cut);
|
||||||
|
uInt rem=*source-quot*DECPOWERS[cut];
|
||||||
|
next+=quot;
|
||||||
|
#else
|
||||||
|
uInt rem=*source%DECPOWERS[cut];
|
||||||
|
next+=*source/DECPOWERS[cut];
|
||||||
|
#endif
|
||||||
|
if (target<=first) *target=(Unit)next; /* write to target iff valid */
|
||||||
|
next=rem*DECPOWERS[DECDPUN-cut]; /* save remainder for next Unit */
|
||||||
|
}
|
||||||
|
} /* shift-move */
|
||||||
|
/* propagate remainder to one below and clear the rest */
|
||||||
|
for (; target>=uar; target--) {
|
||||||
|
*target=(Unit)next;
|
||||||
|
next=0;
|
||||||
|
}
|
||||||
|
digits+=shift; /* add count (shift) of zeros added */
|
||||||
|
inu=uar; /* use units in working array */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now densely pack the coefficient into DPD declets */
|
||||||
|
|
||||||
|
#if DECDPUN!=3 /* not fast path */
|
||||||
|
in=*inu; /* current unit */
|
||||||
|
cut=0; /* at lowest digit */
|
||||||
|
bin=0; /* [keep compiler quiet] */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for(n=0; digits>0; n++) { /* each output bunch */
|
||||||
|
#if DECDPUN==3 /* fast path, 3-at-a-time */
|
||||||
|
bin=*inu; /* 3 digits ready for convert */
|
||||||
|
digits-=3; /* [may go negative] */
|
||||||
|
inu++; /* may need another */
|
||||||
|
|
||||||
|
#else /* must collect digit-by-digit */
|
||||||
|
Unit dig; /* current digit */
|
||||||
|
Int j; /* digit-in-declet count */
|
||||||
|
for (j=0; j<3; j++) {
|
||||||
|
#if DECDPUN<=4
|
||||||
|
Unit temp=(Unit)((uInt)(in*6554)>>16);
|
||||||
|
dig=(Unit)(in-X10(temp));
|
||||||
|
in=temp;
|
||||||
|
#else
|
||||||
|
dig=in%10;
|
||||||
|
in=in/10;
|
||||||
|
#endif
|
||||||
|
if (j==0) bin=dig;
|
||||||
|
else if (j==1) bin+=X10(dig);
|
||||||
|
else /* j==2 */ bin+=X100(dig);
|
||||||
|
digits--;
|
||||||
|
if (digits==0) break; /* [also protects *inu below] */
|
||||||
|
cut++;
|
||||||
|
if (cut==DECDPUN) {inu++; in=*inu; cut=0;}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/* here there are 3 digits in bin, or have used all input digits */
|
||||||
|
|
||||||
|
dpd=BIN2DPD[bin];
|
||||||
|
|
||||||
|
/* write declet to uInt array */
|
||||||
|
*uout|=dpd<<uoff;
|
||||||
|
uoff+=10;
|
||||||
|
if (uoff<32) continue; /* no uInt boundary cross */
|
||||||
|
uout++;
|
||||||
|
uoff-=32;
|
||||||
|
*uout|=dpd>>(10-uoff); /* collect top bits */
|
||||||
|
} /* n declets */
|
||||||
|
return;
|
||||||
|
} /* decDigitsToDPD */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* decDigitsFromDPD -- unpack a format's coefficient */
|
||||||
|
/* */
|
||||||
|
/* dn is the target number, with 7, 16, or 34-digit space. */
|
||||||
|
/* sour is a 1, 2, or 4-element uInt array containing only declets */
|
||||||
|
/* declets is the number of (right-aligned) declets in sour to */
|
||||||
|
/* be processed. This may be 1 more than the obvious number in */
|
||||||
|
/* a format, as any top digit is prefixed to the coefficient */
|
||||||
|
/* continuation field. It also may be as small as 1, as the */
|
||||||
|
/* caller may pre-process leading zero declets. */
|
||||||
|
/* */
|
||||||
|
/* When doing the 'extra declet' case care is taken to avoid writing */
|
||||||
|
/* extra digits when there are leading zeros, as these could overflow */
|
||||||
|
/* the units array when DECDPUN is not 3. */
|
||||||
|
/* */
|
||||||
|
/* The target uInts are used only as necessary to process declets */
|
||||||
|
/* declets into the decNumber. When more than one uInt is needed, */
|
||||||
|
/* they are used from left to right (that is, the uInt at offset 0 */
|
||||||
|
/* provides the least-significant digits). */
|
||||||
|
/* */
|
||||||
|
/* dn->digits is set, but not the sign or exponent. */
|
||||||
|
/* No error is possible [the redundant 888 codes are allowed]. */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
void decDigitsFromDPD(decNumber *dn, const uInt *sour, Int declets) {
|
||||||
|
|
||||||
|
uInt dpd; /* collector for 10 bits */
|
||||||
|
Int n; /* counter */
|
||||||
|
Unit *uout=dn->lsu; /* -> current output unit */
|
||||||
|
Unit *last=uout; /* will be unit containing msd */
|
||||||
|
const uInt *uin=sour; /* -> current input uInt */
|
||||||
|
uInt uoff=0; /* -> current input offset [from right] */
|
||||||
|
|
||||||
|
#if DECDPUN!=3
|
||||||
|
uInt bcd; /* BCD result */
|
||||||
|
uInt nibble; /* work */
|
||||||
|
Unit out=0; /* accumulator */
|
||||||
|
Int cut=0; /* power of ten in current unit */
|
||||||
|
#endif
|
||||||
|
#if DECDPUN>4
|
||||||
|
uInt const *pow; /* work */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Expand the densely-packed integer, right to left */
|
||||||
|
for (n=declets-1; n>=0; n--) { /* count down declets of 10 bits */
|
||||||
|
dpd=*uin>>uoff;
|
||||||
|
uoff+=10;
|
||||||
|
if (uoff>32) { /* crossed uInt boundary */
|
||||||
|
uin++;
|
||||||
|
uoff-=32;
|
||||||
|
dpd|=*uin<<(10-uoff); /* get waiting bits */
|
||||||
|
}
|
||||||
|
dpd&=0x3ff; /* clear uninteresting bits */
|
||||||
|
|
||||||
|
#if DECDPUN==3
|
||||||
|
if (dpd==0) *uout=0;
|
||||||
|
else {
|
||||||
|
*uout=DPD2BIN[dpd]; /* convert 10 bits to binary 0-999 */
|
||||||
|
last=uout; /* record most significant unit */
|
||||||
|
}
|
||||||
|
uout++;
|
||||||
|
} /* n */
|
||||||
|
|
||||||
|
#else /* DECDPUN!=3 */
|
||||||
|
if (dpd==0) { /* fastpath [e.g., leading zeros] */
|
||||||
|
/* write out three 0 digits (nibbles); out may have digit(s) */
|
||||||
|
cut++;
|
||||||
|
if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;}
|
||||||
|
if (n==0) break; /* [as below, works even if MSD=0] */
|
||||||
|
cut++;
|
||||||
|
if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;}
|
||||||
|
cut++;
|
||||||
|
if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bcd=DPD2BCD[dpd]; /* convert 10 bits to 12 bits BCD */
|
||||||
|
|
||||||
|
/* now accumulate the 3 BCD nibbles into units */
|
||||||
|
nibble=bcd & 0x00f;
|
||||||
|
if (nibble) out=(Unit)(out+nibble*DECPOWERS[cut]);
|
||||||
|
cut++;
|
||||||
|
if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;}
|
||||||
|
bcd>>=4;
|
||||||
|
|
||||||
|
/* if this is the last declet and the remaining nibbles in bcd */
|
||||||
|
/* are 00 then process no more nibbles, because this could be */
|
||||||
|
/* the 'odd' MSD declet and writing any more Units would then */
|
||||||
|
/* overflow the unit array */
|
||||||
|
if (n==0 && !bcd) break;
|
||||||
|
|
||||||
|
nibble=bcd & 0x00f;
|
||||||
|
if (nibble) out=(Unit)(out+nibble*DECPOWERS[cut]);
|
||||||
|
cut++;
|
||||||
|
if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;}
|
||||||
|
bcd>>=4;
|
||||||
|
|
||||||
|
nibble=bcd & 0x00f;
|
||||||
|
if (nibble) out=(Unit)(out+nibble*DECPOWERS[cut]);
|
||||||
|
cut++;
|
||||||
|
if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;}
|
||||||
|
} /* n */
|
||||||
|
if (cut!=0) { /* some more left over */
|
||||||
|
*uout=out; /* write out final unit */
|
||||||
|
if (out) last=uout; /* and note if non-zero */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* here, last points to the most significant unit with digits; */
|
||||||
|
/* inspect it to get the final digits count -- this is essentially */
|
||||||
|
/* the same code as decGetDigits in decNumber.c */
|
||||||
|
dn->digits=(last-dn->lsu)*DECDPUN+1; /* floor of digits, plus */
|
||||||
|
/* must be at least 1 digit */
|
||||||
|
#if DECDPUN>1
|
||||||
|
if (*last<10) return; /* common odd digit or 0 */
|
||||||
|
dn->digits++; /* must be 2 at least */
|
||||||
|
#if DECDPUN>2
|
||||||
|
if (*last<100) return; /* 10-99 */
|
||||||
|
dn->digits++; /* must be 3 at least */
|
||||||
|
#if DECDPUN>3
|
||||||
|
if (*last<1000) return; /* 100-999 */
|
||||||
|
dn->digits++; /* must be 4 at least */
|
||||||
|
#if DECDPUN>4
|
||||||
|
for (pow=&DECPOWERS[4]; *last>=*pow; pow++) dn->digits++;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
} /*decDigitsFromDPD */
|
|
@ -20,6 +20,7 @@
|
||||||
#define __ARM_KVM_H__
|
#define __ARM_KVM_H__
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
#include <linux/psci.h>
|
||||||
#include <asm/ptrace.h>
|
#include <asm/ptrace.h>
|
||||||
|
|
||||||
#define __KVM_HAVE_GUEST_DEBUG
|
#define __KVM_HAVE_GUEST_DEBUG
|
||||||
|
@ -83,6 +84,7 @@ struct kvm_regs {
|
||||||
#define KVM_VGIC_V2_CPU_SIZE 0x2000
|
#define KVM_VGIC_V2_CPU_SIZE 0x2000
|
||||||
|
|
||||||
#define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */
|
#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 {
|
struct kvm_vcpu_init {
|
||||||
__u32 target;
|
__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_CPU_ON KVM_PSCI_FN(2)
|
||||||
#define KVM_PSCI_FN_MIGRATE KVM_PSCI_FN(3)
|
#define KVM_PSCI_FN_MIGRATE KVM_PSCI_FN(3)
|
||||||
|
|
||||||
#define KVM_PSCI_RET_SUCCESS 0
|
#define KVM_PSCI_RET_SUCCESS PSCI_RET_SUCCESS
|
||||||
#define KVM_PSCI_RET_NI ((unsigned long)-1)
|
#define KVM_PSCI_RET_NI PSCI_RET_NOT_SUPPORTED
|
||||||
#define KVM_PSCI_RET_INVAL ((unsigned long)-2)
|
#define KVM_PSCI_RET_INVAL PSCI_RET_INVALID_PARAMS
|
||||||
#define KVM_PSCI_RET_DENIED ((unsigned long)-3)
|
#define KVM_PSCI_RET_DENIED PSCI_RET_DENIED
|
||||||
|
|
||||||
#endif /* __ARM_KVM_H__ */
|
#endif /* __ARM_KVM_H__ */
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#define KVM_NR_SPSR 5
|
#define KVM_NR_SPSR 5
|
||||||
|
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
|
#include <linux/psci.h>
|
||||||
#include <asm/types.h>
|
#include <asm/types.h>
|
||||||
#include <asm/ptrace.h>
|
#include <asm/ptrace.h>
|
||||||
|
|
||||||
|
@ -56,8 +57,9 @@ struct kvm_regs {
|
||||||
#define KVM_ARM_TARGET_FOUNDATION_V8 1
|
#define KVM_ARM_TARGET_FOUNDATION_V8 1
|
||||||
#define KVM_ARM_TARGET_CORTEX_A57 2
|
#define KVM_ARM_TARGET_CORTEX_A57 2
|
||||||
#define KVM_ARM_TARGET_XGENE_POTENZA 3
|
#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 */
|
/* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */
|
||||||
#define KVM_ARM_DEVICE_TYPE_SHIFT 0
|
#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_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_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 {
|
struct kvm_vcpu_init {
|
||||||
__u32 target;
|
__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_CPU_ON KVM_PSCI_FN(2)
|
||||||
#define KVM_PSCI_FN_MIGRATE KVM_PSCI_FN(3)
|
#define KVM_PSCI_FN_MIGRATE KVM_PSCI_FN(3)
|
||||||
|
|
||||||
#define KVM_PSCI_RET_SUCCESS 0
|
#define KVM_PSCI_RET_SUCCESS PSCI_RET_SUCCESS
|
||||||
#define KVM_PSCI_RET_NI ((unsigned long)-1)
|
#define KVM_PSCI_RET_NI PSCI_RET_NOT_SUPPORTED
|
||||||
#define KVM_PSCI_RET_INVAL ((unsigned long)-2)
|
#define KVM_PSCI_RET_INVAL PSCI_RET_INVALID_PARAMS
|
||||||
#define KVM_PSCI_RET_DENIED ((unsigned long)-3)
|
#define KVM_PSCI_RET_DENIED PSCI_RET_DENIED
|
||||||
|
|
||||||
#endif
|
#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_LO (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 33)
|
||||||
#define KVM_REG_MIPS_PC (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 34)
|
#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
|
* 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_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_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_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_VRSAVE (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb4)
|
||||||
#define KVM_REG_PPC_LPCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb5)
|
#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_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_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:
|
/* Transactional Memory checkpointed state:
|
||||||
* This is all GPRs, all VSX regs and a subset of SPRs
|
* 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
|
#define KVM_FEATURE_MAGIC_PAGE 1
|
||||||
|
|
||||||
|
/* Magic page flags from host to guest */
|
||||||
|
|
||||||
#define KVM_MAGIC_FEAT_SR (1 << 0)
|
#define KVM_MAGIC_FEAT_SR (1 << 0)
|
||||||
|
|
||||||
/* MASn, ESR, PIR, and high SPRGs */
|
/* MASn, ESR, PIR, and high SPRGs */
|
||||||
#define KVM_MAGIC_FEAT_MAS0_TO_SPRG7 (1 << 1)
|
#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__ */
|
#endif /* __POWERPC_KVM_PARA_H__ */
|
||||||
|
|
|
@ -171,6 +171,7 @@ struct kvm_pit_config {
|
||||||
#define KVM_EXIT_WATCHDOG 21
|
#define KVM_EXIT_WATCHDOG 21
|
||||||
#define KVM_EXIT_S390_TSCH 22
|
#define KVM_EXIT_S390_TSCH 22
|
||||||
#define KVM_EXIT_EPR 23
|
#define KVM_EXIT_EPR 23
|
||||||
|
#define KVM_EXIT_SYSTEM_EVENT 24
|
||||||
|
|
||||||
/* For KVM_EXIT_INTERNAL_ERROR */
|
/* For KVM_EXIT_INTERNAL_ERROR */
|
||||||
/* Emulate instruction failed. */
|
/* Emulate instruction failed. */
|
||||||
|
@ -301,6 +302,13 @@ struct kvm_run {
|
||||||
struct {
|
struct {
|
||||||
__u32 epr;
|
__u32 epr;
|
||||||
} epr;
|
} epr;
|
||||||
|
/* KVM_EXIT_SYSTEM_EVENT */
|
||||||
|
struct {
|
||||||
|
#define KVM_SYSTEM_EVENT_SHUTDOWN 1
|
||||||
|
#define KVM_SYSTEM_EVENT_RESET 2
|
||||||
|
__u32 type;
|
||||||
|
__u64 flags;
|
||||||
|
} system_event;
|
||||||
/* Fix the size of the union. */
|
/* Fix the size of the union. */
|
||||||
char padding[256];
|
char padding[256];
|
||||||
};
|
};
|
||||||
|
@ -748,6 +756,8 @@ struct kvm_ppc_smmu_info {
|
||||||
#define KVM_CAP_S390_IRQCHIP 99
|
#define KVM_CAP_S390_IRQCHIP 99
|
||||||
#define KVM_CAP_IOEVENTFD_NO_LENGTH 100
|
#define KVM_CAP_IOEVENTFD_NO_LENGTH 100
|
||||||
#define KVM_CAP_VM_ATTRIBUTES 101
|
#define KVM_CAP_VM_ATTRIBUTES 101
|
||||||
|
#define KVM_CAP_ARM_PSCI_0_2 102
|
||||||
|
#define KVM_CAP_PPC_FIXUP_HCALL 103
|
||||||
|
|
||||||
#ifdef KVM_CAP_IRQ_ROUTING
|
#ifdef KVM_CAP_IRQ_ROUTING
|
||||||
|
|
||||||
|
|
90
linux-headers/linux/psci.h
Normal file
90
linux-headers/linux/psci.h
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* ARM Power State and Coordination Interface (PSCI) header
|
||||||
|
*
|
||||||
|
* This header holds common PSCI defines and macros shared
|
||||||
|
* by: ARM kernel, ARM64 kernel, KVM ARM/ARM64 and user space.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Linaro Ltd.
|
||||||
|
* Author: Anup Patel <anup.patel@linaro.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LINUX_PSCI_H
|
||||||
|
#define _LINUX_PSCI_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PSCI v0.1 interface
|
||||||
|
*
|
||||||
|
* The PSCI v0.1 function numbers are implementation defined.
|
||||||
|
*
|
||||||
|
* Only PSCI return values such as: SUCCESS, NOT_SUPPORTED,
|
||||||
|
* INVALID_PARAMS, and DENIED defined below are applicable
|
||||||
|
* to PSCI v0.1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* PSCI v0.2 interface */
|
||||||
|
#define PSCI_0_2_FN_BASE 0x84000000
|
||||||
|
#define PSCI_0_2_FN(n) (PSCI_0_2_FN_BASE + (n))
|
||||||
|
#define PSCI_0_2_64BIT 0x40000000
|
||||||
|
#define PSCI_0_2_FN64_BASE \
|
||||||
|
(PSCI_0_2_FN_BASE + PSCI_0_2_64BIT)
|
||||||
|
#define PSCI_0_2_FN64(n) (PSCI_0_2_FN64_BASE + (n))
|
||||||
|
|
||||||
|
#define PSCI_0_2_FN_PSCI_VERSION PSCI_0_2_FN(0)
|
||||||
|
#define PSCI_0_2_FN_CPU_SUSPEND PSCI_0_2_FN(1)
|
||||||
|
#define PSCI_0_2_FN_CPU_OFF PSCI_0_2_FN(2)
|
||||||
|
#define PSCI_0_2_FN_CPU_ON PSCI_0_2_FN(3)
|
||||||
|
#define PSCI_0_2_FN_AFFINITY_INFO PSCI_0_2_FN(4)
|
||||||
|
#define PSCI_0_2_FN_MIGRATE PSCI_0_2_FN(5)
|
||||||
|
#define PSCI_0_2_FN_MIGRATE_INFO_TYPE PSCI_0_2_FN(6)
|
||||||
|
#define PSCI_0_2_FN_MIGRATE_INFO_UP_CPU PSCI_0_2_FN(7)
|
||||||
|
#define PSCI_0_2_FN_SYSTEM_OFF PSCI_0_2_FN(8)
|
||||||
|
#define PSCI_0_2_FN_SYSTEM_RESET PSCI_0_2_FN(9)
|
||||||
|
|
||||||
|
#define PSCI_0_2_FN64_CPU_SUSPEND PSCI_0_2_FN64(1)
|
||||||
|
#define PSCI_0_2_FN64_CPU_ON PSCI_0_2_FN64(3)
|
||||||
|
#define PSCI_0_2_FN64_AFFINITY_INFO PSCI_0_2_FN64(4)
|
||||||
|
#define PSCI_0_2_FN64_MIGRATE PSCI_0_2_FN64(5)
|
||||||
|
#define PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU PSCI_0_2_FN64(7)
|
||||||
|
|
||||||
|
/* PSCI v0.2 power state encoding for CPU_SUSPEND function */
|
||||||
|
#define PSCI_0_2_POWER_STATE_ID_MASK 0xffff
|
||||||
|
#define PSCI_0_2_POWER_STATE_ID_SHIFT 0
|
||||||
|
#define PSCI_0_2_POWER_STATE_TYPE_SHIFT 16
|
||||||
|
#define PSCI_0_2_POWER_STATE_TYPE_MASK \
|
||||||
|
(0x1 << PSCI_0_2_POWER_STATE_TYPE_SHIFT)
|
||||||
|
#define PSCI_0_2_POWER_STATE_AFFL_SHIFT 24
|
||||||
|
#define PSCI_0_2_POWER_STATE_AFFL_MASK \
|
||||||
|
(0x3 << PSCI_0_2_POWER_STATE_AFFL_SHIFT)
|
||||||
|
|
||||||
|
/* PSCI v0.2 affinity level state returned by AFFINITY_INFO */
|
||||||
|
#define PSCI_0_2_AFFINITY_LEVEL_ON 0
|
||||||
|
#define PSCI_0_2_AFFINITY_LEVEL_OFF 1
|
||||||
|
#define PSCI_0_2_AFFINITY_LEVEL_ON_PENDING 2
|
||||||
|
|
||||||
|
/* PSCI v0.2 multicore support in Trusted OS returned by MIGRATE_INFO_TYPE */
|
||||||
|
#define PSCI_0_2_TOS_UP_MIGRATE 0
|
||||||
|
#define PSCI_0_2_TOS_UP_NO_MIGRATE 1
|
||||||
|
#define PSCI_0_2_TOS_MP 2
|
||||||
|
|
||||||
|
/* PSCI version decoding (independent of PSCI version) */
|
||||||
|
#define PSCI_VERSION_MAJOR_SHIFT 16
|
||||||
|
#define PSCI_VERSION_MINOR_MASK \
|
||||||
|
((1U << PSCI_VERSION_MAJOR_SHIFT) - 1)
|
||||||
|
#define PSCI_VERSION_MAJOR_MASK ~PSCI_VERSION_MINOR_MASK
|
||||||
|
#define PSCI_VERSION_MAJOR(ver) \
|
||||||
|
(((ver) & PSCI_VERSION_MAJOR_MASK) >> PSCI_VERSION_MAJOR_SHIFT)
|
||||||
|
#define PSCI_VERSION_MINOR(ver) \
|
||||||
|
((ver) & PSCI_VERSION_MINOR_MASK)
|
||||||
|
|
||||||
|
/* PSCI return values (inclusive of all PSCI versions) */
|
||||||
|
#define PSCI_RET_SUCCESS 0
|
||||||
|
#define PSCI_RET_NOT_SUPPORTED -1
|
||||||
|
#define PSCI_RET_INVALID_PARAMS -2
|
||||||
|
#define PSCI_RET_DENIED -3
|
||||||
|
#define PSCI_RET_ALREADY_ON -4
|
||||||
|
#define PSCI_RET_ON_PENDING -5
|
||||||
|
#define PSCI_RET_INTERNAL_FAILURE -6
|
||||||
|
#define PSCI_RET_NOT_PRESENT -7
|
||||||
|
#define PSCI_RET_DISABLED -8
|
||||||
|
|
||||||
|
#endif /* _LINUX_PSCI_H */
|
|
@ -784,12 +784,18 @@ static uint32_t get_elf_hwcap(void)
|
||||||
NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \
|
NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
static inline uint32_t get_ppc64_abi(struct image_info *infop);
|
||||||
|
|
||||||
static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
|
static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
|
||||||
{
|
{
|
||||||
_regs->gpr[1] = infop->start_stack;
|
_regs->gpr[1] = infop->start_stack;
|
||||||
#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
|
#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
|
||||||
|
if (get_ppc64_abi(infop) < 2) {
|
||||||
_regs->gpr[2] = ldq_raw(infop->entry + 8) + infop->load_bias;
|
_regs->gpr[2] = ldq_raw(infop->entry + 8) + infop->load_bias;
|
||||||
infop->entry = ldq_raw(infop->entry) + infop->load_bias;
|
infop->entry = ldq_raw(infop->entry) + infop->load_bias;
|
||||||
|
} else {
|
||||||
|
_regs->gpr[12] = infop->entry; /* r12 set to global entry address */
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
_regs->nip = infop->entry;
|
_regs->nip = infop->entry;
|
||||||
}
|
}
|
||||||
|
@ -1159,6 +1165,13 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
|
||||||
|
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
|
|
||||||
|
#ifdef TARGET_PPC
|
||||||
|
static inline uint32_t get_ppc64_abi(struct image_info *infop)
|
||||||
|
{
|
||||||
|
return infop->elf_flags & EF_PPC64_ABI;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
struct exec
|
struct exec
|
||||||
{
|
{
|
||||||
unsigned int a_info; /* Use macros N_MAGIC, etc for access */
|
unsigned int a_info; /* Use macros N_MAGIC, etc for access */
|
||||||
|
@ -1412,10 +1425,11 @@ static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot)
|
||||||
perror("cannot mmap brk");
|
perror("cannot mmap brk");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Since we didn't use target_mmap, make sure to record
|
/* Ensure that the bss page(s) are valid */
|
||||||
the validity of the pages with qemu. */
|
if ((page_get_flags(last_bss-1) & prot) != prot) {
|
||||||
page_set_flags(elf_bss & TARGET_PAGE_MASK, last_bss, prot|PAGE_VALID);
|
page_set_flags(elf_bss & TARGET_PAGE_MASK, last_bss, prot | PAGE_VALID);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (host_start < host_map_start) {
|
if (host_start < host_map_start) {
|
||||||
|
@ -1538,7 +1552,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
|
||||||
NEW_AUX_ENT(AT_PHDR, (abi_ulong)(info->load_addr + exec->e_phoff));
|
NEW_AUX_ENT(AT_PHDR, (abi_ulong)(info->load_addr + exec->e_phoff));
|
||||||
NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
|
NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
|
||||||
NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
|
NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
|
||||||
NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
|
NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(MAX(TARGET_PAGE_SIZE, getpagesize())));
|
||||||
NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_info ? interp_info->load_addr : 0));
|
NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_info ? interp_info->load_addr : 0));
|
||||||
NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
|
NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
|
||||||
NEW_AUX_ENT(AT_ENTRY, info->entry);
|
NEW_AUX_ENT(AT_ENTRY, info->entry);
|
||||||
|
|
|
@ -1484,7 +1484,7 @@ static int do_store_exclusive(CPUPPCState *env)
|
||||||
{
|
{
|
||||||
target_ulong addr;
|
target_ulong addr;
|
||||||
target_ulong page_addr;
|
target_ulong page_addr;
|
||||||
target_ulong val, val2 __attribute__((unused));
|
target_ulong val, val2 __attribute__((unused)) = 0;
|
||||||
int flags;
|
int flags;
|
||||||
int segv = 0;
|
int segv = 0;
|
||||||
|
|
||||||
|
@ -1497,7 +1497,7 @@ static int do_store_exclusive(CPUPPCState *env)
|
||||||
segv = 1;
|
segv = 1;
|
||||||
} else {
|
} else {
|
||||||
int reg = env->reserve_info & 0x1f;
|
int reg = env->reserve_info & 0x1f;
|
||||||
int size = (env->reserve_info >> 5) & 0xf;
|
int size = env->reserve_info >> 5;
|
||||||
int stored = 0;
|
int stored = 0;
|
||||||
|
|
||||||
if (addr == env->reserve_addr) {
|
if (addr == env->reserve_addr) {
|
||||||
|
@ -1527,6 +1527,12 @@ static int do_store_exclusive(CPUPPCState *env)
|
||||||
case 8: segv = put_user_u64(val, addr); break;
|
case 8: segv = put_user_u64(val, addr); break;
|
||||||
case 16: {
|
case 16: {
|
||||||
if (val2 == env->reserve_val2) {
|
if (val2 == env->reserve_val2) {
|
||||||
|
if (msr_le) {
|
||||||
|
val2 = val;
|
||||||
|
val = env->gpr[reg+1];
|
||||||
|
} else {
|
||||||
|
val2 = env->gpr[reg+1];
|
||||||
|
}
|
||||||
segv = put_user_u64(val, addr);
|
segv = put_user_u64(val, addr);
|
||||||
if (!segv) {
|
if (!segv) {
|
||||||
segv = put_user_u64(val2, addr + 8);
|
segv = put_user_u64(val2, addr + 8);
|
||||||
|
|
|
@ -58,8 +58,12 @@ struct target_revectored_struct {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
|
#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
|
||||||
|
#ifdef TARGET_WORDS_BIGENDIAN
|
||||||
#define UNAME_MACHINE "ppc64"
|
#define UNAME_MACHINE "ppc64"
|
||||||
#else
|
#else
|
||||||
|
#define UNAME_MACHINE "ppc64le"
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
#define UNAME_MACHINE "ppc"
|
#define UNAME_MACHINE "ppc"
|
||||||
#endif
|
#endif
|
||||||
#define UNAME_MINIMUM_RELEASE "2.6.32"
|
#define UNAME_MINIMUM_RELEASE "2.6.32"
|
||||||
|
|
|
@ -1284,6 +1284,10 @@ static void memory_dump(Monitor *mon, int count, int format, int wsize,
|
||||||
flags = 1;
|
flags = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef TARGET_PPC
|
||||||
|
flags = msr_le << 16;
|
||||||
|
flags |= env->bfd_mach;
|
||||||
#endif
|
#endif
|
||||||
monitor_disas(mon, env, addr, count, is_physical, flags);
|
monitor_disas(mon, env, addr, count, is_physical, flags);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -41,3 +41,8 @@
|
||||||
|
|
||||||
- The sources for the Alpha palcode image is available from:
|
- The sources for the Alpha palcode image is available from:
|
||||||
git://github.com/rth7680/qemu-palcode.git
|
git://github.com/rth7680/qemu-palcode.git
|
||||||
|
|
||||||
|
- The u-boot binary for e500 comes from the upstream denx u-boot project where
|
||||||
|
it was compiled using the qemu-ppce500 target.
|
||||||
|
A git mirror is available at: git://git.qemu-project.org/u-boot.git
|
||||||
|
The hash used to compile the current version is: 2072e72
|
||||||
|
|
BIN
pc-bios/u-boot.e500
Executable file
BIN
pc-bios/u-boot.e500
Executable file
Binary file not shown.
|
@ -31,6 +31,7 @@ find-cross-gcc = $(firstword $(wildcard $(patsubst %ld,%gcc,$(call find-cross-ld
|
||||||
find-cross-prefix = $(subst gcc,,$(notdir $(call find-cross-gcc,$(1))))
|
find-cross-prefix = $(subst gcc,,$(notdir $(call find-cross-gcc,$(1))))
|
||||||
|
|
||||||
powerpc64_cross_prefix := $(call find-cross-prefix,powerpc64)
|
powerpc64_cross_prefix := $(call find-cross-prefix,powerpc64)
|
||||||
|
powerpc_cross_prefix := $(call find-cross-prefix,powerpc)
|
||||||
x86_64_cross_prefix := $(call find-cross-prefix,x86_64)
|
x86_64_cross_prefix := $(call find-cross-prefix,x86_64)
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -55,6 +56,7 @@ default:
|
||||||
@echo " efirom -- update nic roms (bios+efi, this needs"
|
@echo " efirom -- update nic roms (bios+efi, this needs"
|
||||||
@echo " the EfiRom utility from edk2 / tianocore)"
|
@echo " the EfiRom utility from edk2 / tianocore)"
|
||||||
@echo " slof -- update slof.bin"
|
@echo " slof -- update slof.bin"
|
||||||
|
@echo " u-boot.e500 -- update u-boot.e500"
|
||||||
|
|
||||||
bios: build-seabios-config-seabios-128k build-seabios-config-seabios-256k
|
bios: build-seabios-config-seabios-128k build-seabios-config-seabios-256k
|
||||||
cp seabios/builds/seabios-128k/bios.bin ../pc-bios/bios.bin
|
cp seabios/builds/seabios-128k/bios.bin ../pc-bios/bios.bin
|
||||||
|
@ -132,6 +134,12 @@ slof:
|
||||||
$(MAKE) -C SLOF CROSS=$(powerpc64_cross_prefix) qemu
|
$(MAKE) -C SLOF CROSS=$(powerpc64_cross_prefix) qemu
|
||||||
cp SLOF/boot_rom.bin ../pc-bios/slof.bin
|
cp SLOF/boot_rom.bin ../pc-bios/slof.bin
|
||||||
|
|
||||||
|
u-boot.e500:
|
||||||
|
$(MAKE) -C u-boot O=build.e500 qemu-ppce500_config
|
||||||
|
$(MAKE) -C u-boot CROSS_COMPILE=$(powerpc_cross_prefix) \
|
||||||
|
O=build.e500
|
||||||
|
$(powerpc_cross_prefix)strip u-boot/build.e500/u-boot -o \
|
||||||
|
../pc-bios/u-boot.e500
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf seabios/.config seabios/out seabios/builds
|
rm -rf seabios/.config seabios/out seabios/builds
|
||||||
|
@ -141,3 +149,4 @@ clean:
|
||||||
rm -f sgabios/.depend
|
rm -f sgabios/.depend
|
||||||
$(MAKE) -C ipxe/src veryclean
|
$(MAKE) -C ipxe/src veryclean
|
||||||
$(MAKE) -C SLOF clean
|
$(MAKE) -C SLOF clean
|
||||||
|
rm -rf u-boot/build.e500
|
||||||
|
|
1
roms/u-boot
Submodule
1
roms/u-boot
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 2072e7262965bb48d7fffb1e283101e6ed8b21a8
|
|
@ -61,7 +61,8 @@ done
|
||||||
|
|
||||||
rm -rf "$output/linux-headers/linux"
|
rm -rf "$output/linux-headers/linux"
|
||||||
mkdir -p "$output/linux-headers/linux"
|
mkdir -p "$output/linux-headers/linux"
|
||||||
for header in kvm.h kvm_para.h vfio.h vhost.h virtio_config.h virtio_ring.h; do
|
for header in kvm.h kvm_para.h vfio.h vhost.h virtio_config.h virtio_ring.h \
|
||||||
|
psci.h; do
|
||||||
cp "$tmpdir/include/linux/$header" "$output/linux-headers/linux"
|
cp "$tmpdir/include/linux/$header" "$output/linux-headers/linux"
|
||||||
done
|
done
|
||||||
rm -rf "$output/linux-headers/asm-generic"
|
rm -rf "$output/linux-headers/asm-generic"
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
#include "sysemu/dump.h"
|
#include "sysemu/dump-arch.h"
|
||||||
#include "qapi/qmp/qerror.h"
|
#include "qapi/qmp/qerror.h"
|
||||||
#include "qmp-commands.h"
|
#include "qmp-commands.h"
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "exec/helper-proto.h"
|
#include "exec/helper-proto.h"
|
||||||
|
#include "qemu/aes.h"
|
||||||
|
|
||||||
union CRYPTO_STATE {
|
union CRYPTO_STATE {
|
||||||
uint8_t bytes[16];
|
uint8_t bytes[16];
|
||||||
|
@ -24,81 +25,9 @@ union CRYPTO_STATE {
|
||||||
void HELPER(crypto_aese)(CPUARMState *env, uint32_t rd, uint32_t rm,
|
void HELPER(crypto_aese)(CPUARMState *env, uint32_t rd, uint32_t rm,
|
||||||
uint32_t decrypt)
|
uint32_t decrypt)
|
||||||
{
|
{
|
||||||
static uint8_t const sbox[][256] = { {
|
static uint8_t const * const sbox[2] = { AES_sbox, AES_isbox };
|
||||||
/* S-box for encryption */
|
static uint8_t const * const shift[2] = { AES_shifts, AES_ishifts };
|
||||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
|
|
||||||
0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
|
||||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
|
|
||||||
0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
|
||||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
|
|
||||||
0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
|
||||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
|
|
||||||
0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
|
||||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
|
|
||||||
0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
|
||||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
|
|
||||||
0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
|
||||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
|
|
||||||
0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
|
||||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
|
|
||||||
0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
|
||||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
|
|
||||||
0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
|
||||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
|
|
||||||
0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
|
||||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
|
|
||||||
0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
|
||||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
|
|
||||||
0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
|
||||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
|
|
||||||
0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
|
||||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
|
|
||||||
0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
|
||||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
|
|
||||||
0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
|
||||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
|
|
||||||
0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
|
|
||||||
}, {
|
|
||||||
/* S-box for decryption */
|
|
||||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38,
|
|
||||||
0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
|
||||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
|
|
||||||
0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
|
||||||
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d,
|
|
||||||
0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
|
||||||
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2,
|
|
||||||
0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
|
|
||||||
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
|
|
||||||
0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
|
|
||||||
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda,
|
|
||||||
0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
|
||||||
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a,
|
|
||||||
0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
|
|
||||||
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
|
|
||||||
0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
|
|
||||||
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea,
|
|
||||||
0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
|
||||||
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85,
|
|
||||||
0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
|
|
||||||
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
|
|
||||||
0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
|
||||||
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20,
|
|
||||||
0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
|
||||||
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31,
|
|
||||||
0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
|
||||||
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
|
|
||||||
0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
|
|
||||||
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0,
|
|
||||||
0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
|
||||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26,
|
|
||||||
0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
|
|
||||||
} };
|
|
||||||
static uint8_t const shift[][16] = {
|
|
||||||
/* ShiftRows permutation vector for encryption */
|
|
||||||
{ 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11 },
|
|
||||||
/* ShiftRows permutation vector for decryption */
|
|
||||||
{ 0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3 },
|
|
||||||
};
|
|
||||||
union CRYPTO_STATE rk = { .l = {
|
union CRYPTO_STATE rk = { .l = {
|
||||||
float64_val(env->vfp.regs[rm]),
|
float64_val(env->vfp.regs[rm]),
|
||||||
float64_val(env->vfp.regs[rm + 1])
|
float64_val(env->vfp.regs[rm + 1])
|
||||||
|
|
|
@ -17,6 +17,9 @@
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "qemu/aes.h"
|
||||||
|
|
||||||
#if SHIFT == 0
|
#if SHIFT == 0
|
||||||
#define Reg MMXReg
|
#define Reg MMXReg
|
||||||
#define XMM_ONLY(...)
|
#define XMM_ONLY(...)
|
||||||
|
@ -2204,15 +2207,6 @@ void glue(helper_pclmulqdq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s,
|
||||||
d->Q(1) = resh;
|
d->Q(1) = resh;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* AES-NI op helpers */
|
|
||||||
static const uint8_t aes_shifts[16] = {
|
|
||||||
0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t aes_ishifts[16] = {
|
|
||||||
0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3
|
|
||||||
};
|
|
||||||
|
|
||||||
void glue(helper_aesdec, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
|
void glue(helper_aesdec, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -2220,10 +2214,10 @@ void glue(helper_aesdec, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
|
||||||
Reg rk = *s;
|
Reg rk = *s;
|
||||||
|
|
||||||
for (i = 0 ; i < 4 ; i++) {
|
for (i = 0 ; i < 4 ; i++) {
|
||||||
d->L(i) = rk.L(i) ^ bswap32(AES_Td0[st.B(aes_ishifts[4*i+0])] ^
|
d->L(i) = rk.L(i) ^ bswap32(AES_Td0[st.B(AES_ishifts[4*i+0])] ^
|
||||||
AES_Td1[st.B(aes_ishifts[4*i+1])] ^
|
AES_Td1[st.B(AES_ishifts[4*i+1])] ^
|
||||||
AES_Td2[st.B(aes_ishifts[4*i+2])] ^
|
AES_Td2[st.B(AES_ishifts[4*i+2])] ^
|
||||||
AES_Td3[st.B(aes_ishifts[4*i+3])]);
|
AES_Td3[st.B(AES_ishifts[4*i+3])]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2234,7 +2228,7 @@ void glue(helper_aesdeclast, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
|
||||||
Reg rk = *s;
|
Reg rk = *s;
|
||||||
|
|
||||||
for (i = 0; i < 16; i++) {
|
for (i = 0; i < 16; i++) {
|
||||||
d->B(i) = rk.B(i) ^ (AES_Td4[st.B(aes_ishifts[i])] & 0xff);
|
d->B(i) = rk.B(i) ^ (AES_Td4[st.B(AES_ishifts[i])] & 0xff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2245,10 +2239,10 @@ void glue(helper_aesenc, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
|
||||||
Reg rk = *s;
|
Reg rk = *s;
|
||||||
|
|
||||||
for (i = 0 ; i < 4 ; i++) {
|
for (i = 0 ; i < 4 ; i++) {
|
||||||
d->L(i) = rk.L(i) ^ bswap32(AES_Te0[st.B(aes_shifts[4*i+0])] ^
|
d->L(i) = rk.L(i) ^ bswap32(AES_Te0[st.B(AES_shifts[4*i+0])] ^
|
||||||
AES_Te1[st.B(aes_shifts[4*i+1])] ^
|
AES_Te1[st.B(AES_shifts[4*i+1])] ^
|
||||||
AES_Te2[st.B(aes_shifts[4*i+2])] ^
|
AES_Te2[st.B(AES_shifts[4*i+2])] ^
|
||||||
AES_Te3[st.B(aes_shifts[4*i+3])]);
|
AES_Te3[st.B(AES_shifts[4*i+3])]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2259,7 +2253,7 @@ void glue(helper_aesenclast, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
|
||||||
Reg rk = *s;
|
Reg rk = *s;
|
||||||
|
|
||||||
for (i = 0; i < 16; i++) {
|
for (i = 0; i < 16; i++) {
|
||||||
d->B(i) = rk.B(i) ^ (AES_Te4[st.B(aes_shifts[i])] & 0xff);
|
d->B(i) = rk.B(i) ^ (AES_Te4[st.B(AES_shifts[i])] & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ obj-$(TARGET_PPC64) += mmu-hash64.o arch_dump.o
|
||||||
endif
|
endif
|
||||||
obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o
|
obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o
|
||||||
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
|
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
|
||||||
|
obj-y += dfp_helper.o
|
||||||
obj-y += excp_helper.o
|
obj-y += excp_helper.o
|
||||||
obj-y += fpu_helper.o
|
obj-y += fpu_helper.o
|
||||||
obj-y += int_helper.o
|
obj-y += int_helper.o
|
||||||
|
|
|
@ -79,94 +79,122 @@ typedef struct noteStruct {
|
||||||
} contents;
|
} contents;
|
||||||
} QEMU_PACKED Note;
|
} QEMU_PACKED Note;
|
||||||
|
|
||||||
|
typedef struct NoteFuncArg {
|
||||||
|
Note note;
|
||||||
|
DumpState *state;
|
||||||
|
} NoteFuncArg;
|
||||||
|
|
||||||
static void ppc64_write_elf64_prstatus(Note *note, PowerPCCPU *cpu)
|
static void ppc64_write_elf64_prstatus(NoteFuncArg *arg, PowerPCCPU *cpu)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
uint64_t cr;
|
uint64_t cr;
|
||||||
struct PPC64ElfPrstatus *prstatus;
|
struct PPC64ElfPrstatus *prstatus;
|
||||||
struct PPC64UserRegStruct *reg;
|
struct PPC64UserRegStruct *reg;
|
||||||
|
Note *note = &arg->note;
|
||||||
|
DumpState *s = arg->state;
|
||||||
|
|
||||||
note->hdr.n_type = cpu_to_be32(NT_PRSTATUS);
|
note->hdr.n_type = cpu_to_dump32(s, NT_PRSTATUS);
|
||||||
|
|
||||||
prstatus = ¬e->contents.prstatus;
|
prstatus = ¬e->contents.prstatus;
|
||||||
memset(prstatus, 0, sizeof(*prstatus));
|
memset(prstatus, 0, sizeof(*prstatus));
|
||||||
reg = &prstatus->pr_reg;
|
reg = &prstatus->pr_reg;
|
||||||
|
|
||||||
for (i = 0; i < 32; i++) {
|
for (i = 0; i < 32; i++) {
|
||||||
reg->gpr[i] = cpu_to_be64(cpu->env.gpr[i]);
|
reg->gpr[i] = cpu_to_dump64(s, cpu->env.gpr[i]);
|
||||||
}
|
}
|
||||||
reg->nip = cpu_to_be64(cpu->env.nip);
|
reg->nip = cpu_to_dump64(s, cpu->env.nip);
|
||||||
reg->msr = cpu_to_be64(cpu->env.msr);
|
reg->msr = cpu_to_dump64(s, cpu->env.msr);
|
||||||
reg->ctr = cpu_to_be64(cpu->env.ctr);
|
reg->ctr = cpu_to_dump64(s, cpu->env.ctr);
|
||||||
reg->link = cpu_to_be64(cpu->env.lr);
|
reg->link = cpu_to_dump64(s, cpu->env.lr);
|
||||||
reg->xer = cpu_to_be64(cpu_read_xer(&cpu->env));
|
reg->xer = cpu_to_dump64(s, cpu_read_xer(&cpu->env));
|
||||||
|
|
||||||
cr = 0;
|
cr = 0;
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
cr |= (cpu->env.crf[i] & 15) << (4 * (7 - i));
|
cr |= (cpu->env.crf[i] & 15) << (4 * (7 - i));
|
||||||
}
|
}
|
||||||
reg->ccr = cpu_to_be64(cr);
|
reg->ccr = cpu_to_dump64(s, cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ppc64_write_elf64_fpregset(Note *note, PowerPCCPU *cpu)
|
static void ppc64_write_elf64_fpregset(NoteFuncArg *arg, PowerPCCPU *cpu)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct PPC64ElfFpregset *fpregset;
|
struct PPC64ElfFpregset *fpregset;
|
||||||
|
Note *note = &arg->note;
|
||||||
|
DumpState *s = arg->state;
|
||||||
|
|
||||||
note->hdr.n_type = cpu_to_be32(NT_PRFPREG);
|
note->hdr.n_type = cpu_to_dump32(s, NT_PRFPREG);
|
||||||
|
|
||||||
fpregset = ¬e->contents.fpregset;
|
fpregset = ¬e->contents.fpregset;
|
||||||
memset(fpregset, 0, sizeof(*fpregset));
|
memset(fpregset, 0, sizeof(*fpregset));
|
||||||
|
|
||||||
for (i = 0; i < 32; i++) {
|
for (i = 0; i < 32; i++) {
|
||||||
fpregset->fpr[i] = cpu_to_be64(cpu->env.fpr[i]);
|
fpregset->fpr[i] = cpu_to_dump64(s, cpu->env.fpr[i]);
|
||||||
}
|
}
|
||||||
fpregset->fpscr = cpu_to_be64(cpu->env.fpscr);
|
fpregset->fpscr = cpu_to_dump64(s, cpu->env.fpscr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ppc64_write_elf64_vmxregset(Note *note, PowerPCCPU *cpu)
|
static void ppc64_write_elf64_vmxregset(NoteFuncArg *arg, PowerPCCPU *cpu)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct PPC64ElfVmxregset *vmxregset;
|
struct PPC64ElfVmxregset *vmxregset;
|
||||||
|
Note *note = &arg->note;
|
||||||
|
DumpState *s = arg->state;
|
||||||
|
|
||||||
note->hdr.n_type = cpu_to_be32(NT_PPC_VMX);
|
note->hdr.n_type = cpu_to_dump32(s, NT_PPC_VMX);
|
||||||
vmxregset = ¬e->contents.vmxregset;
|
vmxregset = ¬e->contents.vmxregset;
|
||||||
memset(vmxregset, 0, sizeof(*vmxregset));
|
memset(vmxregset, 0, sizeof(*vmxregset));
|
||||||
|
|
||||||
for (i = 0; i < 32; i++) {
|
for (i = 0; i < 32; i++) {
|
||||||
vmxregset->avr[i].u64[0] = cpu_to_be64(cpu->env.avr[i].u64[0]);
|
bool needs_byteswap;
|
||||||
vmxregset->avr[i].u64[1] = cpu_to_be64(cpu->env.avr[i].u64[1]);
|
|
||||||
|
#ifdef HOST_WORDS_BIGENDIAN
|
||||||
|
needs_byteswap = s->dump_info.d_endian == ELFDATA2LSB;
|
||||||
|
#else
|
||||||
|
needs_byteswap = s->dump_info.d_endian == ELFDATA2MSB;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (needs_byteswap) {
|
||||||
|
vmxregset->avr[i].u64[0] = bswap64(cpu->env.avr[i].u64[1]);
|
||||||
|
vmxregset->avr[i].u64[1] = bswap64(cpu->env.avr[i].u64[0]);
|
||||||
|
} else {
|
||||||
|
vmxregset->avr[i].u64[0] = cpu->env.avr[i].u64[0];
|
||||||
|
vmxregset->avr[i].u64[1] = cpu->env.avr[i].u64[1];
|
||||||
}
|
}
|
||||||
vmxregset->vscr.u32[3] = cpu_to_be32(cpu->env.vscr);
|
}
|
||||||
|
vmxregset->vscr.u32[3] = cpu_to_dump32(s, cpu->env.vscr);
|
||||||
}
|
}
|
||||||
static void ppc64_write_elf64_vsxregset(Note *note, PowerPCCPU *cpu)
|
static void ppc64_write_elf64_vsxregset(NoteFuncArg *arg, PowerPCCPU *cpu)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct PPC64ElfVsxregset *vsxregset;
|
struct PPC64ElfVsxregset *vsxregset;
|
||||||
|
Note *note = &arg->note;
|
||||||
|
DumpState *s = arg->state;
|
||||||
|
|
||||||
note->hdr.n_type = cpu_to_be32(NT_PPC_VSX);
|
note->hdr.n_type = cpu_to_dump32(s, NT_PPC_VSX);
|
||||||
vsxregset = ¬e->contents.vsxregset;
|
vsxregset = ¬e->contents.vsxregset;
|
||||||
memset(vsxregset, 0, sizeof(*vsxregset));
|
memset(vsxregset, 0, sizeof(*vsxregset));
|
||||||
|
|
||||||
for (i = 0; i < 32; i++) {
|
for (i = 0; i < 32; i++) {
|
||||||
vsxregset->vsr[i] = cpu_to_be64(cpu->env.vsr[i]);
|
vsxregset->vsr[i] = cpu_to_dump64(s, cpu->env.vsr[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static void ppc64_write_elf64_speregset(Note *note, PowerPCCPU *cpu)
|
static void ppc64_write_elf64_speregset(NoteFuncArg *arg, PowerPCCPU *cpu)
|
||||||
{
|
{
|
||||||
struct PPC64ElfSperegset *speregset;
|
struct PPC64ElfSperegset *speregset;
|
||||||
note->hdr.n_type = cpu_to_be32(NT_PPC_SPE);
|
Note *note = &arg->note;
|
||||||
|
DumpState *s = arg->state;
|
||||||
|
|
||||||
|
note->hdr.n_type = cpu_to_dump32(s, NT_PPC_SPE);
|
||||||
speregset = ¬e->contents.speregset;
|
speregset = ¬e->contents.speregset;
|
||||||
memset(speregset, 0, sizeof(*speregset));
|
memset(speregset, 0, sizeof(*speregset));
|
||||||
|
|
||||||
speregset->spe_acc = cpu_to_be64(cpu->env.spe_acc);
|
speregset->spe_acc = cpu_to_dump64(s, cpu->env.spe_acc);
|
||||||
speregset->spe_fscr = cpu_to_be32(cpu->env.spe_fscr);
|
speregset->spe_fscr = cpu_to_dump32(s, cpu->env.spe_fscr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct NoteFuncDescStruct {
|
static const struct NoteFuncDescStruct {
|
||||||
int contents_size;
|
int contents_size;
|
||||||
void (*note_contents_func)(Note *note, PowerPCCPU *cpu);
|
void (*note_contents_func)(NoteFuncArg *arg, PowerPCCPU *cpu);
|
||||||
} note_func[] = {
|
} note_func[] = {
|
||||||
{sizeof(((Note *)0)->contents.prstatus), ppc64_write_elf64_prstatus},
|
{sizeof(((Note *)0)->contents.prstatus), ppc64_write_elf64_prstatus},
|
||||||
{sizeof(((Note *)0)->contents.fpregset), ppc64_write_elf64_fpregset},
|
{sizeof(((Note *)0)->contents.fpregset), ppc64_write_elf64_fpregset},
|
||||||
|
@ -181,12 +209,16 @@ typedef struct NoteFuncDescStruct NoteFuncDesc;
|
||||||
int cpu_get_dump_info(ArchDumpInfo *info,
|
int cpu_get_dump_info(ArchDumpInfo *info,
|
||||||
const struct GuestPhysBlockList *guest_phys_blocks)
|
const struct GuestPhysBlockList *guest_phys_blocks)
|
||||||
{
|
{
|
||||||
/*
|
PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
|
||||||
* Currently only handling PPC64 big endian.
|
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
|
||||||
*/
|
|
||||||
info->d_machine = EM_PPC64;
|
info->d_machine = EM_PPC64;
|
||||||
info->d_endian = ELFDATA2MSB;
|
|
||||||
info->d_class = ELFCLASS64;
|
info->d_class = ELFCLASS64;
|
||||||
|
if ((*pcc->interrupts_big_endian)(cpu)) {
|
||||||
|
info->d_endian = ELFDATA2MSB;
|
||||||
|
} else {
|
||||||
|
info->d_endian = ELFDATA2LSB;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -218,20 +250,21 @@ static int ppc64_write_all_elf64_notes(const char *note_name,
|
||||||
PowerPCCPU *cpu, int id,
|
PowerPCCPU *cpu, int id,
|
||||||
void *opaque)
|
void *opaque)
|
||||||
{
|
{
|
||||||
Note note;
|
NoteFuncArg arg = { .state = opaque };
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
int note_size;
|
int note_size;
|
||||||
const NoteFuncDesc *nf;
|
const NoteFuncDesc *nf;
|
||||||
|
|
||||||
for (nf = note_func; nf->note_contents_func; nf++) {
|
for (nf = note_func; nf->note_contents_func; nf++) {
|
||||||
note.hdr.n_namesz = cpu_to_be32(sizeof(note.name));
|
arg.note.hdr.n_namesz = cpu_to_dump32(opaque, sizeof(arg.note.name));
|
||||||
note.hdr.n_descsz = cpu_to_be32(nf->contents_size);
|
arg.note.hdr.n_descsz = cpu_to_dump32(opaque, nf->contents_size);
|
||||||
strncpy(note.name, note_name, sizeof(note.name));
|
strncpy(arg.note.name, note_name, sizeof(arg.note.name));
|
||||||
|
|
||||||
(*nf->note_contents_func)(¬e, cpu);
|
(*nf->note_contents_func)(&arg, cpu);
|
||||||
|
|
||||||
note_size = sizeof(note) - sizeof(note.contents) + nf->contents_size;
|
note_size =
|
||||||
ret = f(¬e, note_size, opaque);
|
sizeof(arg.note) - sizeof(arg.note.contents) + nf->contents_size;
|
||||||
|
ret = f(&arg.note, note_size, opaque);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -671,20 +671,20 @@
|
||||||
POWERPC_DEF_SVR("MPC8379E", "MPC8379E",
|
POWERPC_DEF_SVR("MPC8379E", "MPC8379E",
|
||||||
CPU_POWERPC_MPC837x, POWERPC_SVR_8379E, e300)
|
CPU_POWERPC_MPC837x, POWERPC_SVR_8379E, e300)
|
||||||
/* e500 family */
|
/* e500 family */
|
||||||
POWERPC_DEF("e500_v10", CPU_POWERPC_e500v1_v10, e500v1,
|
POWERPC_DEF_SVR("e500_v10", "PowerPC e500 v1.0 core",
|
||||||
"PowerPC e500 v1.0 core")
|
CPU_POWERPC_e500v1_v10, POWERPC_SVR_E500, e500v1);
|
||||||
POWERPC_DEF("e500_v20", CPU_POWERPC_e500v1_v20, e500v1,
|
POWERPC_DEF_SVR("e500_v20", "PowerPC e500 v2.0 core",
|
||||||
"PowerPC e500 v2.0 core")
|
CPU_POWERPC_e500v1_v20, POWERPC_SVR_E500, e500v1);
|
||||||
POWERPC_DEF("e500v2_v10", CPU_POWERPC_e500v2_v10, e500v2,
|
POWERPC_DEF_SVR("e500v2_v10", "PowerPC e500v2 v1.0 core",
|
||||||
"PowerPC e500v2 v1.0 core")
|
CPU_POWERPC_e500v2_v10, POWERPC_SVR_E500, e500v2);
|
||||||
POWERPC_DEF("e500v2_v20", CPU_POWERPC_e500v2_v20, e500v2,
|
POWERPC_DEF_SVR("e500v2_v20", "PowerPC e500v2 v2.0 core",
|
||||||
"PowerPC e500v2 v2.0 core")
|
CPU_POWERPC_e500v2_v20, POWERPC_SVR_E500, e500v2);
|
||||||
POWERPC_DEF("e500v2_v21", CPU_POWERPC_e500v2_v21, e500v2,
|
POWERPC_DEF_SVR("e500v2_v21", "PowerPC e500v2 v2.1 core",
|
||||||
"PowerPC e500v2 v2.1 core")
|
CPU_POWERPC_e500v2_v21, POWERPC_SVR_E500, e500v2);
|
||||||
POWERPC_DEF("e500v2_v22", CPU_POWERPC_e500v2_v22, e500v2,
|
POWERPC_DEF_SVR("e500v2_v22", "PowerPC e500v2 v2.2 core",
|
||||||
"PowerPC e500v2 v2.2 core")
|
CPU_POWERPC_e500v2_v22, POWERPC_SVR_E500, e500v2);
|
||||||
POWERPC_DEF("e500v2_v30", CPU_POWERPC_e500v2_v30, e500v2,
|
POWERPC_DEF_SVR("e500v2_v30", "PowerPC e500v2 v3.0 core",
|
||||||
"PowerPC e500v2 v3.0 core")
|
CPU_POWERPC_e500v2_v30, POWERPC_SVR_E500, e500v2);
|
||||||
POWERPC_DEF_SVR("e500mc", "e500mc",
|
POWERPC_DEF_SVR("e500mc", "e500mc",
|
||||||
CPU_POWERPC_e500mc, POWERPC_SVR_E500, e500mc)
|
CPU_POWERPC_e500mc, POWERPC_SVR_E500, e500mc)
|
||||||
#ifdef TARGET_PPC64
|
#ifdef TARGET_PPC64
|
||||||
|
@ -1134,10 +1134,6 @@
|
||||||
POWERPC_DEF("POWER6A", CPU_POWERPC_POWER6A, POWER6,
|
POWERPC_DEF("POWER6A", CPU_POWERPC_POWER6A, POWER6,
|
||||||
"POWER6A")
|
"POWER6A")
|
||||||
#endif
|
#endif
|
||||||
POWERPC_DEF("POWER7_v2.0", CPU_POWERPC_POWER7_v20, POWER7,
|
|
||||||
"POWER7 v2.0")
|
|
||||||
POWERPC_DEF("POWER7_v2.1", CPU_POWERPC_POWER7_v21, POWER7,
|
|
||||||
"POWER7 v2.1")
|
|
||||||
POWERPC_DEF("POWER7_v2.3", CPU_POWERPC_POWER7_v23, POWER7,
|
POWERPC_DEF("POWER7_v2.3", CPU_POWERPC_POWER7_v23, POWER7,
|
||||||
"POWER7 v2.3")
|
"POWER7 v2.3")
|
||||||
POWERPC_DEF("POWER7+_v2.1", CPU_POWERPC_POWER7P_v21, POWER7P,
|
POWERPC_DEF("POWER7+_v2.1", CPU_POWERPC_POWER7P_v21, POWER7P,
|
||||||
|
@ -1146,19 +1142,19 @@
|
||||||
"POWER8 v1.0")
|
"POWER8 v1.0")
|
||||||
POWERPC_DEF("970", CPU_POWERPC_970, 970,
|
POWERPC_DEF("970", CPU_POWERPC_970, 970,
|
||||||
"PowerPC 970")
|
"PowerPC 970")
|
||||||
POWERPC_DEF("970fx_v1.0", CPU_POWERPC_970FX_v10, 970FX,
|
POWERPC_DEF("970fx_v1.0", CPU_POWERPC_970FX_v10, 970,
|
||||||
"PowerPC 970FX v1.0 (G5)")
|
"PowerPC 970FX v1.0 (G5)")
|
||||||
POWERPC_DEF("970fx_v2.0", CPU_POWERPC_970FX_v20, 970FX,
|
POWERPC_DEF("970fx_v2.0", CPU_POWERPC_970FX_v20, 970,
|
||||||
"PowerPC 970FX v2.0 (G5)")
|
"PowerPC 970FX v2.0 (G5)")
|
||||||
POWERPC_DEF("970fx_v2.1", CPU_POWERPC_970FX_v21, 970FX,
|
POWERPC_DEF("970fx_v2.1", CPU_POWERPC_970FX_v21, 970,
|
||||||
"PowerPC 970FX v2.1 (G5)")
|
"PowerPC 970FX v2.1 (G5)")
|
||||||
POWERPC_DEF("970fx_v3.0", CPU_POWERPC_970FX_v30, 970FX,
|
POWERPC_DEF("970fx_v3.0", CPU_POWERPC_970FX_v30, 970,
|
||||||
"PowerPC 970FX v3.0 (G5)")
|
"PowerPC 970FX v3.0 (G5)")
|
||||||
POWERPC_DEF("970fx_v3.1", CPU_POWERPC_970FX_v31, 970FX,
|
POWERPC_DEF("970fx_v3.1", CPU_POWERPC_970FX_v31, 970,
|
||||||
"PowerPC 970FX v3.1 (G5)")
|
"PowerPC 970FX v3.1 (G5)")
|
||||||
POWERPC_DEF("970mp_v1.0", CPU_POWERPC_970MP_v10, 970MP,
|
POWERPC_DEF("970mp_v1.0", CPU_POWERPC_970MP_v10, 970,
|
||||||
"PowerPC 970MP v1.0")
|
"PowerPC 970MP v1.0")
|
||||||
POWERPC_DEF("970mp_v1.1", CPU_POWERPC_970MP_v11, 970MP,
|
POWERPC_DEF("970mp_v1.1", CPU_POWERPC_970MP_v11, 970,
|
||||||
"PowerPC 970MP v1.1")
|
"PowerPC 970MP v1.1")
|
||||||
#if defined(TODO)
|
#if defined(TODO)
|
||||||
POWERPC_DEF("Cell", CPU_POWERPC_CELL, 970,
|
POWERPC_DEF("Cell", CPU_POWERPC_CELL, 970,
|
||||||
|
|
|
@ -555,8 +555,6 @@ enum {
|
||||||
CPU_POWERPC_POWER6A = 0x0F000002,
|
CPU_POWERPC_POWER6A = 0x0F000002,
|
||||||
CPU_POWERPC_POWER7_BASE = 0x003F0000,
|
CPU_POWERPC_POWER7_BASE = 0x003F0000,
|
||||||
CPU_POWERPC_POWER7_MASK = 0xFFFF0000,
|
CPU_POWERPC_POWER7_MASK = 0xFFFF0000,
|
||||||
CPU_POWERPC_POWER7_v20 = 0x003F0200,
|
|
||||||
CPU_POWERPC_POWER7_v21 = 0x003F0201,
|
|
||||||
CPU_POWERPC_POWER7_v23 = 0x003F0203,
|
CPU_POWERPC_POWER7_v23 = 0x003F0203,
|
||||||
CPU_POWERPC_POWER7P_BASE = 0x004A0000,
|
CPU_POWERPC_POWER7P_BASE = 0x004A0000,
|
||||||
CPU_POWERPC_POWER7P_MASK = 0xFFFF0000,
|
CPU_POWERPC_POWER7P_MASK = 0xFFFF0000,
|
||||||
|
@ -597,6 +595,16 @@ enum {
|
||||||
CPU_POWERPC_PA6T = 0x00900000,
|
CPU_POWERPC_PA6T = 0x00900000,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Logical PVR definitions for sPAPR */
|
||||||
|
enum {
|
||||||
|
CPU_POWERPC_LOGICAL_2_04 = 0x0F000001,
|
||||||
|
CPU_POWERPC_LOGICAL_2_05 = 0x0F000002,
|
||||||
|
CPU_POWERPC_LOGICAL_2_06 = 0x0F000003,
|
||||||
|
CPU_POWERPC_LOGICAL_2_06_PLUS = 0x0F100003,
|
||||||
|
CPU_POWERPC_LOGICAL_2_07 = 0x0F000004,
|
||||||
|
CPU_POWERPC_LOGICAL_2_08 = 0x0F000005,
|
||||||
|
};
|
||||||
|
|
||||||
/* System version register (used on MPC 8xxx) */
|
/* System version register (used on MPC 8xxx) */
|
||||||
enum {
|
enum {
|
||||||
POWERPC_SVR_NONE = 0x00000000,
|
POWERPC_SVR_NONE = 0x00000000,
|
||||||
|
|
|
@ -57,6 +57,7 @@ typedef struct PowerPCCPUClass {
|
||||||
|
|
||||||
uint32_t pvr;
|
uint32_t pvr;
|
||||||
uint32_t pvr_mask;
|
uint32_t pvr_mask;
|
||||||
|
uint64_t pcr_mask;
|
||||||
uint32_t svr;
|
uint32_t svr;
|
||||||
uint64_t insns_flags;
|
uint64_t insns_flags;
|
||||||
uint64_t insns_flags2;
|
uint64_t insns_flags2;
|
||||||
|
@ -76,12 +77,15 @@ typedef struct PowerPCCPUClass {
|
||||||
int (*handle_mmu_fault)(PowerPCCPU *cpu, target_ulong eaddr, int rwx,
|
int (*handle_mmu_fault)(PowerPCCPU *cpu, target_ulong eaddr, int rwx,
|
||||||
int mmu_idx);
|
int mmu_idx);
|
||||||
#endif
|
#endif
|
||||||
|
bool (*interrupts_big_endian)(PowerPCCPU *cpu);
|
||||||
} PowerPCCPUClass;
|
} PowerPCCPUClass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PowerPCCPU:
|
* PowerPCCPU:
|
||||||
* @env: #CPUPPCState
|
* @env: #CPUPPCState
|
||||||
* @cpu_dt_id: CPU index used in the device tree. KVM uses this index too
|
* @cpu_dt_id: CPU index used in the device tree. KVM uses this index too
|
||||||
|
* @max_compat: Maximal supported logical PVR from the command line
|
||||||
|
* @cpu_version: Current logical PVR, zero if in "raw" mode
|
||||||
*
|
*
|
||||||
* A PowerPC CPU.
|
* A PowerPC CPU.
|
||||||
*/
|
*/
|
||||||
|
@ -92,6 +96,8 @@ struct PowerPCCPU {
|
||||||
|
|
||||||
CPUPPCState env;
|
CPUPPCState env;
|
||||||
int cpu_dt_id;
|
int cpu_dt_id;
|
||||||
|
uint32_t max_compat;
|
||||||
|
uint32_t cpu_version;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env)
|
static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env)
|
||||||
|
@ -120,6 +126,22 @@ int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
|
||||||
int cpuid, void *opaque);
|
int cpuid, void *opaque);
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
extern const struct VMStateDescription vmstate_ppc_cpu;
|
extern const struct VMStateDescription vmstate_ppc_cpu;
|
||||||
|
|
||||||
|
typedef struct PPCTimebase {
|
||||||
|
uint64_t guest_timebase;
|
||||||
|
int64_t time_of_the_day_ns;
|
||||||
|
} PPCTimebase;
|
||||||
|
|
||||||
|
extern const struct VMStateDescription vmstate_ppc_timebase;
|
||||||
|
|
||||||
|
#define VMSTATE_PPC_TIMEBASE_V(_field, _state, _version) { \
|
||||||
|
.name = (stringify(_field)), \
|
||||||
|
.version_id = (_version), \
|
||||||
|
.size = sizeof(PPCTimebase), \
|
||||||
|
.vmsd = &vmstate_ppc_timebase, \
|
||||||
|
.flags = VMS_STRUCT, \
|
||||||
|
.offset = vmstate_offset_value(_state, _field, PPCTimebase), \
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
163
target-ppc/cpu.h
163
target-ppc/cpu.h
|
@ -238,6 +238,7 @@ enum {
|
||||||
POWERPC_EXCP_DTLBE = 93, /* Data TLB error */
|
POWERPC_EXCP_DTLBE = 93, /* Data TLB error */
|
||||||
/* VSX Unavailable (Power ISA 2.06 and later) */
|
/* VSX Unavailable (Power ISA 2.06 and later) */
|
||||||
POWERPC_EXCP_VSXU = 94, /* VSX Unavailable */
|
POWERPC_EXCP_VSXU = 94, /* VSX Unavailable */
|
||||||
|
POWERPC_EXCP_FU = 95, /* Facility Unavailable */
|
||||||
/* EOL */
|
/* EOL */
|
||||||
POWERPC_EXCP_NB = 96,
|
POWERPC_EXCP_NB = 96,
|
||||||
/* QEMU exceptions: used internally during code translation */
|
/* QEMU exceptions: used internally during code translation */
|
||||||
|
@ -426,6 +427,9 @@ struct ppc_slb_t {
|
||||||
#define MSR_TAG 62 /* Tag-active mode (POWERx ?) */
|
#define MSR_TAG 62 /* Tag-active mode (POWERx ?) */
|
||||||
#define MSR_ISF 61 /* Sixty-four-bit interrupt mode on 630 */
|
#define MSR_ISF 61 /* Sixty-four-bit interrupt mode on 630 */
|
||||||
#define MSR_SHV 60 /* hypervisor state hflags */
|
#define MSR_SHV 60 /* hypervisor state hflags */
|
||||||
|
#define MSR_TS0 34 /* Transactional state, 2 bits (Book3s) */
|
||||||
|
#define MSR_TS1 33
|
||||||
|
#define MSR_TM 32 /* Transactional Memory Available (Book3s) */
|
||||||
#define MSR_CM 31 /* Computation mode for BookE hflags */
|
#define MSR_CM 31 /* Computation mode for BookE hflags */
|
||||||
#define MSR_ICM 30 /* Interrupt computation mode for BookE */
|
#define MSR_ICM 30 /* Interrupt computation mode for BookE */
|
||||||
#define MSR_THV 29 /* hypervisor state for 32 bits PowerPC hflags */
|
#define MSR_THV 29 /* hypervisor state for 32 bits PowerPC hflags */
|
||||||
|
@ -463,6 +467,8 @@ struct ppc_slb_t {
|
||||||
#define MSR_LE 0 /* Little-endian mode 1 hflags */
|
#define MSR_LE 0 /* Little-endian mode 1 hflags */
|
||||||
|
|
||||||
#define LPCR_ILE (1 << (63-38))
|
#define LPCR_ILE (1 << (63-38))
|
||||||
|
#define LPCR_AIL_SHIFT (63-40) /* Alternate interrupt location */
|
||||||
|
#define LPCR_AIL (3 << LPCR_AIL_SHIFT)
|
||||||
|
|
||||||
#define msr_sf ((env->msr >> MSR_SF) & 1)
|
#define msr_sf ((env->msr >> MSR_SF) & 1)
|
||||||
#define msr_isf ((env->msr >> MSR_ISF) & 1)
|
#define msr_isf ((env->msr >> MSR_ISF) & 1)
|
||||||
|
@ -502,6 +508,9 @@ struct ppc_slb_t {
|
||||||
#define msr_pmm ((env->msr >> MSR_PMM) & 1)
|
#define msr_pmm ((env->msr >> MSR_PMM) & 1)
|
||||||
#define msr_ri ((env->msr >> MSR_RI) & 1)
|
#define msr_ri ((env->msr >> MSR_RI) & 1)
|
||||||
#define msr_le ((env->msr >> MSR_LE) & 1)
|
#define msr_le ((env->msr >> MSR_LE) & 1)
|
||||||
|
#define msr_ts ((env->msr >> MSR_TS1) & 3)
|
||||||
|
#define msr_tm ((env->msr >> MSR_TM) & 1)
|
||||||
|
|
||||||
/* Hypervisor bit is more specific */
|
/* Hypervisor bit is more specific */
|
||||||
#if defined(TARGET_PPC64)
|
#if defined(TARGET_PPC64)
|
||||||
#define MSR_HVB (1ULL << MSR_SHV)
|
#define MSR_HVB (1ULL << MSR_SHV)
|
||||||
|
@ -516,6 +525,19 @@ struct ppc_slb_t {
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Facility Status and Control (FSCR) bits */
|
||||||
|
#define FSCR_EBB (63 - 56) /* Event-Based Branch Facility */
|
||||||
|
#define FSCR_TAR (63 - 55) /* Target Address Register */
|
||||||
|
/* Interrupt cause mask and position in FSCR. HFSCR has the same format */
|
||||||
|
#define FSCR_IC_MASK (0xFFULL)
|
||||||
|
#define FSCR_IC_POS (63 - 7)
|
||||||
|
#define FSCR_IC_DSCR_SPR3 2
|
||||||
|
#define FSCR_IC_PMU 3
|
||||||
|
#define FSCR_IC_BHRB 4
|
||||||
|
#define FSCR_IC_TM 5
|
||||||
|
#define FSCR_IC_EBB 7
|
||||||
|
#define FSCR_IC_TAR 8
|
||||||
|
|
||||||
/* Exception state register bits definition */
|
/* Exception state register bits definition */
|
||||||
#define ESR_PIL (1 << (63 - 36)) /* Illegal Instruction */
|
#define ESR_PIL (1 << (63 - 36)) /* Illegal Instruction */
|
||||||
#define ESR_PPR (1 << (63 - 37)) /* Privileged Instruction */
|
#define ESR_PPR (1 << (63 - 37)) /* Privileged Instruction */
|
||||||
|
@ -908,10 +930,8 @@ struct CPUPPCState {
|
||||||
*/
|
*/
|
||||||
/* general purpose registers */
|
/* general purpose registers */
|
||||||
target_ulong gpr[32];
|
target_ulong gpr[32];
|
||||||
#if !defined(TARGET_PPC64)
|
|
||||||
/* Storage for GPR MSB, used by the SPE extension */
|
/* Storage for GPR MSB, used by the SPE extension */
|
||||||
target_ulong gprh[32];
|
target_ulong gprh[32];
|
||||||
#endif
|
|
||||||
/* LR */
|
/* LR */
|
||||||
target_ulong lr;
|
target_ulong lr;
|
||||||
/* CTR */
|
/* CTR */
|
||||||
|
@ -1081,6 +1101,20 @@ struct CPUPPCState {
|
||||||
*/
|
*/
|
||||||
uint8_t fit_period[4];
|
uint8_t fit_period[4];
|
||||||
uint8_t wdt_period[4];
|
uint8_t wdt_period[4];
|
||||||
|
|
||||||
|
/* Transactional memory state */
|
||||||
|
target_ulong tm_gpr[32];
|
||||||
|
ppc_avr_t tm_vsr[64];
|
||||||
|
uint64_t tm_cr;
|
||||||
|
uint64_t tm_lr;
|
||||||
|
uint64_t tm_ctr;
|
||||||
|
uint64_t tm_fpscr;
|
||||||
|
uint64_t tm_amr;
|
||||||
|
uint64_t tm_ppr;
|
||||||
|
uint64_t tm_vrsave;
|
||||||
|
uint32_t tm_vscr;
|
||||||
|
uint64_t tm_dscr;
|
||||||
|
uint64_t tm_tar;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SET_FIT_PERIOD(a_, b_, c_, d_) \
|
#define SET_FIT_PERIOD(a_, b_, c_, d_) \
|
||||||
|
@ -1104,6 +1138,7 @@ do { \
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
PowerPCCPU *cpu_ppc_init(const char *cpu_model);
|
PowerPCCPU *cpu_ppc_init(const char *cpu_model);
|
||||||
void ppc_translate_init(void);
|
void ppc_translate_init(void);
|
||||||
|
void gen_update_current_nip(void *opaque);
|
||||||
int cpu_ppc_exec (CPUPPCState *s);
|
int cpu_ppc_exec (CPUPPCState *s);
|
||||||
/* you can call this signal handler from your SIGBUS and SIGSEGV
|
/* you can call this signal handler from your SIGBUS and SIGSEGV
|
||||||
signal handlers to inform the virtual CPU of exceptions. non zero
|
signal handlers to inform the virtual CPU of exceptions. non zero
|
||||||
|
@ -1122,6 +1157,8 @@ void ppc_store_sdr1 (CPUPPCState *env, target_ulong value);
|
||||||
void ppc_store_msr (CPUPPCState *env, target_ulong value);
|
void ppc_store_msr (CPUPPCState *env, target_ulong value);
|
||||||
|
|
||||||
void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf);
|
void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf);
|
||||||
|
int ppc_get_compat_smt_threads(PowerPCCPU *cpu);
|
||||||
|
int ppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version);
|
||||||
|
|
||||||
/* Time-base and decrementer management */
|
/* Time-base and decrementer management */
|
||||||
#ifndef NO_CPU_IO_DEFS
|
#ifndef NO_CPU_IO_DEFS
|
||||||
|
@ -1162,7 +1199,6 @@ static inline uint64_t ppc_dump_gpr(CPUPPCState *env, int gprn)
|
||||||
uint64_t gprv;
|
uint64_t gprv;
|
||||||
|
|
||||||
gprv = env->gpr[gprn];
|
gprv = env->gpr[gprn];
|
||||||
#if !defined(TARGET_PPC64)
|
|
||||||
if (env->flags & POWERPC_FLAG_SPE) {
|
if (env->flags & POWERPC_FLAG_SPE) {
|
||||||
/* If the CPU implements the SPE extension, we have to get the
|
/* If the CPU implements the SPE extension, we have to get the
|
||||||
* high bits of the GPR from the gprh storage area
|
* high bits of the GPR from the gprh storage area
|
||||||
|
@ -1170,7 +1206,6 @@ static inline uint64_t ppc_dump_gpr(CPUPPCState *env, int gprn)
|
||||||
gprv &= 0xFFFFFFFFULL;
|
gprv &= 0xFFFFFFFFULL;
|
||||||
gprv |= (uint64_t)env->gprh[gprn] << 32;
|
gprv |= (uint64_t)env->gprh[gprn] << 32;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
return gprv;
|
return gprv;
|
||||||
}
|
}
|
||||||
|
@ -1258,6 +1293,10 @@ static inline int cpu_mmu_index (CPUPPCState *env)
|
||||||
#define SPR_MPC_EIE (0x050)
|
#define SPR_MPC_EIE (0x050)
|
||||||
#define SPR_MPC_EID (0x051)
|
#define SPR_MPC_EID (0x051)
|
||||||
#define SPR_MPC_NRI (0x052)
|
#define SPR_MPC_NRI (0x052)
|
||||||
|
#define SPR_TFHAR (0x080)
|
||||||
|
#define SPR_TFIAR (0x081)
|
||||||
|
#define SPR_TEXASR (0x082)
|
||||||
|
#define SPR_TEXASRU (0x083)
|
||||||
#define SPR_UCTRL (0x088)
|
#define SPR_UCTRL (0x088)
|
||||||
#define SPR_MPC_CMPA (0x090)
|
#define SPR_MPC_CMPA (0x090)
|
||||||
#define SPR_MPC_CMPB (0x091)
|
#define SPR_MPC_CMPB (0x091)
|
||||||
|
@ -1270,6 +1309,7 @@ static inline int cpu_mmu_index (CPUPPCState *env)
|
||||||
#define SPR_CTRL (0x098)
|
#define SPR_CTRL (0x098)
|
||||||
#define SPR_MPC_CMPE (0x098)
|
#define SPR_MPC_CMPE (0x098)
|
||||||
#define SPR_MPC_CMPF (0x099)
|
#define SPR_MPC_CMPF (0x099)
|
||||||
|
#define SPR_FSCR (0x099)
|
||||||
#define SPR_MPC_CMPG (0x09A)
|
#define SPR_MPC_CMPG (0x09A)
|
||||||
#define SPR_MPC_CMPH (0x09B)
|
#define SPR_MPC_CMPH (0x09B)
|
||||||
#define SPR_MPC_LCTRL1 (0x09C)
|
#define SPR_MPC_LCTRL1 (0x09C)
|
||||||
|
@ -1338,6 +1378,7 @@ static inline int cpu_mmu_index (CPUPPCState *env)
|
||||||
#define SPR_LPCR (0x13E)
|
#define SPR_LPCR (0x13E)
|
||||||
#define SPR_BOOKE_DVC2 (0x13F)
|
#define SPR_BOOKE_DVC2 (0x13F)
|
||||||
#define SPR_BOOKE_TSR (0x150)
|
#define SPR_BOOKE_TSR (0x150)
|
||||||
|
#define SPR_PCR (0x152)
|
||||||
#define SPR_BOOKE_TCR (0x154)
|
#define SPR_BOOKE_TCR (0x154)
|
||||||
#define SPR_BOOKE_TLB0PS (0x158)
|
#define SPR_BOOKE_TLB0PS (0x158)
|
||||||
#define SPR_BOOKE_TLB1PS (0x159)
|
#define SPR_BOOKE_TLB1PS (0x159)
|
||||||
|
@ -1365,10 +1406,18 @@ static inline int cpu_mmu_index (CPUPPCState *env)
|
||||||
#define SPR_BOOKE_IVOR40 (0x1B2)
|
#define SPR_BOOKE_IVOR40 (0x1B2)
|
||||||
#define SPR_BOOKE_IVOR41 (0x1B3)
|
#define SPR_BOOKE_IVOR41 (0x1B3)
|
||||||
#define SPR_BOOKE_IVOR42 (0x1B4)
|
#define SPR_BOOKE_IVOR42 (0x1B4)
|
||||||
|
#define SPR_BOOKE_GIVOR2 (0x1B8)
|
||||||
|
#define SPR_BOOKE_GIVOR3 (0x1B9)
|
||||||
|
#define SPR_BOOKE_GIVOR4 (0x1BA)
|
||||||
|
#define SPR_BOOKE_GIVOR8 (0x1BB)
|
||||||
|
#define SPR_BOOKE_GIVOR13 (0x1BC)
|
||||||
|
#define SPR_BOOKE_GIVOR14 (0x1BD)
|
||||||
|
#define SPR_TIR (0x1BE)
|
||||||
#define SPR_BOOKE_SPEFSCR (0x200)
|
#define SPR_BOOKE_SPEFSCR (0x200)
|
||||||
#define SPR_Exxx_BBEAR (0x201)
|
#define SPR_Exxx_BBEAR (0x201)
|
||||||
#define SPR_Exxx_BBTAR (0x202)
|
#define SPR_Exxx_BBTAR (0x202)
|
||||||
#define SPR_Exxx_L1CFG0 (0x203)
|
#define SPR_Exxx_L1CFG0 (0x203)
|
||||||
|
#define SPR_Exxx_L1CFG1 (0x204)
|
||||||
#define SPR_Exxx_NPIDR (0x205)
|
#define SPR_Exxx_NPIDR (0x205)
|
||||||
#define SPR_ATBL (0x20E)
|
#define SPR_ATBL (0x20E)
|
||||||
#define SPR_ATBU (0x20F)
|
#define SPR_ATBU (0x20F)
|
||||||
|
@ -1453,62 +1502,96 @@ static inline int cpu_mmu_index (CPUPPCState *env)
|
||||||
#define SPR_MPC_MI_CTR (0x300)
|
#define SPR_MPC_MI_CTR (0x300)
|
||||||
#define SPR_PERF1 (0x301)
|
#define SPR_PERF1 (0x301)
|
||||||
#define SPR_RCPU_MI_RBA1 (0x301)
|
#define SPR_RCPU_MI_RBA1 (0x301)
|
||||||
|
#define SPR_POWER_UMMCR2 (0x301)
|
||||||
#define SPR_PERF2 (0x302)
|
#define SPR_PERF2 (0x302)
|
||||||
#define SPR_RCPU_MI_RBA2 (0x302)
|
#define SPR_RCPU_MI_RBA2 (0x302)
|
||||||
#define SPR_MPC_MI_AP (0x302)
|
#define SPR_MPC_MI_AP (0x302)
|
||||||
#define SPR_MMCRA (0x302)
|
#define SPR_POWER_UMMCRA (0x302)
|
||||||
#define SPR_PERF3 (0x303)
|
#define SPR_PERF3 (0x303)
|
||||||
#define SPR_RCPU_MI_RBA3 (0x303)
|
#define SPR_RCPU_MI_RBA3 (0x303)
|
||||||
#define SPR_MPC_MI_EPN (0x303)
|
#define SPR_MPC_MI_EPN (0x303)
|
||||||
|
#define SPR_POWER_UPMC1 (0x303)
|
||||||
#define SPR_PERF4 (0x304)
|
#define SPR_PERF4 (0x304)
|
||||||
|
#define SPR_POWER_UPMC2 (0x304)
|
||||||
#define SPR_PERF5 (0x305)
|
#define SPR_PERF5 (0x305)
|
||||||
#define SPR_MPC_MI_TWC (0x305)
|
#define SPR_MPC_MI_TWC (0x305)
|
||||||
|
#define SPR_POWER_UPMC3 (0x305)
|
||||||
#define SPR_PERF6 (0x306)
|
#define SPR_PERF6 (0x306)
|
||||||
#define SPR_MPC_MI_RPN (0x306)
|
#define SPR_MPC_MI_RPN (0x306)
|
||||||
|
#define SPR_POWER_UPMC4 (0x306)
|
||||||
#define SPR_PERF7 (0x307)
|
#define SPR_PERF7 (0x307)
|
||||||
|
#define SPR_POWER_UPMC5 (0x307)
|
||||||
#define SPR_PERF8 (0x308)
|
#define SPR_PERF8 (0x308)
|
||||||
#define SPR_RCPU_L2U_RBA0 (0x308)
|
#define SPR_RCPU_L2U_RBA0 (0x308)
|
||||||
#define SPR_MPC_MD_CTR (0x308)
|
#define SPR_MPC_MD_CTR (0x308)
|
||||||
|
#define SPR_POWER_UPMC6 (0x308)
|
||||||
#define SPR_PERF9 (0x309)
|
#define SPR_PERF9 (0x309)
|
||||||
#define SPR_RCPU_L2U_RBA1 (0x309)
|
#define SPR_RCPU_L2U_RBA1 (0x309)
|
||||||
#define SPR_MPC_MD_CASID (0x309)
|
#define SPR_MPC_MD_CASID (0x309)
|
||||||
|
#define SPR_970_UPMC7 (0X309)
|
||||||
#define SPR_PERFA (0x30A)
|
#define SPR_PERFA (0x30A)
|
||||||
#define SPR_RCPU_L2U_RBA2 (0x30A)
|
#define SPR_RCPU_L2U_RBA2 (0x30A)
|
||||||
#define SPR_MPC_MD_AP (0x30A)
|
#define SPR_MPC_MD_AP (0x30A)
|
||||||
|
#define SPR_970_UPMC8 (0X30A)
|
||||||
#define SPR_PERFB (0x30B)
|
#define SPR_PERFB (0x30B)
|
||||||
#define SPR_RCPU_L2U_RBA3 (0x30B)
|
#define SPR_RCPU_L2U_RBA3 (0x30B)
|
||||||
#define SPR_MPC_MD_EPN (0x30B)
|
#define SPR_MPC_MD_EPN (0x30B)
|
||||||
|
#define SPR_POWER_UMMCR0 (0X30B)
|
||||||
#define SPR_PERFC (0x30C)
|
#define SPR_PERFC (0x30C)
|
||||||
#define SPR_MPC_MD_TWB (0x30C)
|
#define SPR_MPC_MD_TWB (0x30C)
|
||||||
|
#define SPR_POWER_USIAR (0X30C)
|
||||||
#define SPR_PERFD (0x30D)
|
#define SPR_PERFD (0x30D)
|
||||||
#define SPR_MPC_MD_TWC (0x30D)
|
#define SPR_MPC_MD_TWC (0x30D)
|
||||||
|
#define SPR_POWER_USDAR (0X30D)
|
||||||
#define SPR_PERFE (0x30E)
|
#define SPR_PERFE (0x30E)
|
||||||
#define SPR_MPC_MD_RPN (0x30E)
|
#define SPR_MPC_MD_RPN (0x30E)
|
||||||
|
#define SPR_POWER_UMMCR1 (0X30E)
|
||||||
#define SPR_PERFF (0x30F)
|
#define SPR_PERFF (0x30F)
|
||||||
#define SPR_MPC_MD_TW (0x30F)
|
#define SPR_MPC_MD_TW (0x30F)
|
||||||
#define SPR_UPERF0 (0x310)
|
#define SPR_UPERF0 (0x310)
|
||||||
#define SPR_UPERF1 (0x311)
|
#define SPR_UPERF1 (0x311)
|
||||||
|
#define SPR_POWER_MMCR2 (0x311)
|
||||||
#define SPR_UPERF2 (0x312)
|
#define SPR_UPERF2 (0x312)
|
||||||
|
#define SPR_POWER_MMCRA (0X312)
|
||||||
#define SPR_UPERF3 (0x313)
|
#define SPR_UPERF3 (0x313)
|
||||||
|
#define SPR_POWER_PMC1 (0X313)
|
||||||
#define SPR_UPERF4 (0x314)
|
#define SPR_UPERF4 (0x314)
|
||||||
|
#define SPR_POWER_PMC2 (0X314)
|
||||||
#define SPR_UPERF5 (0x315)
|
#define SPR_UPERF5 (0x315)
|
||||||
|
#define SPR_POWER_PMC3 (0X315)
|
||||||
#define SPR_UPERF6 (0x316)
|
#define SPR_UPERF6 (0x316)
|
||||||
|
#define SPR_POWER_PMC4 (0X316)
|
||||||
#define SPR_UPERF7 (0x317)
|
#define SPR_UPERF7 (0x317)
|
||||||
|
#define SPR_POWER_PMC5 (0X317)
|
||||||
#define SPR_UPERF8 (0x318)
|
#define SPR_UPERF8 (0x318)
|
||||||
|
#define SPR_POWER_PMC6 (0X318)
|
||||||
#define SPR_UPERF9 (0x319)
|
#define SPR_UPERF9 (0x319)
|
||||||
|
#define SPR_970_PMC7 (0X319)
|
||||||
#define SPR_UPERFA (0x31A)
|
#define SPR_UPERFA (0x31A)
|
||||||
|
#define SPR_970_PMC8 (0X31A)
|
||||||
#define SPR_UPERFB (0x31B)
|
#define SPR_UPERFB (0x31B)
|
||||||
|
#define SPR_POWER_MMCR0 (0X31B)
|
||||||
#define SPR_UPERFC (0x31C)
|
#define SPR_UPERFC (0x31C)
|
||||||
|
#define SPR_POWER_SIAR (0X31C)
|
||||||
#define SPR_UPERFD (0x31D)
|
#define SPR_UPERFD (0x31D)
|
||||||
|
#define SPR_POWER_SDAR (0X31D)
|
||||||
#define SPR_UPERFE (0x31E)
|
#define SPR_UPERFE (0x31E)
|
||||||
|
#define SPR_POWER_MMCR1 (0X31E)
|
||||||
#define SPR_UPERFF (0x31F)
|
#define SPR_UPERFF (0x31F)
|
||||||
#define SPR_RCPU_MI_RA0 (0x320)
|
#define SPR_RCPU_MI_RA0 (0x320)
|
||||||
#define SPR_MPC_MI_DBCAM (0x320)
|
#define SPR_MPC_MI_DBCAM (0x320)
|
||||||
|
#define SPR_BESCRS (0x320)
|
||||||
#define SPR_RCPU_MI_RA1 (0x321)
|
#define SPR_RCPU_MI_RA1 (0x321)
|
||||||
#define SPR_MPC_MI_DBRAM0 (0x321)
|
#define SPR_MPC_MI_DBRAM0 (0x321)
|
||||||
|
#define SPR_BESCRSU (0x321)
|
||||||
#define SPR_RCPU_MI_RA2 (0x322)
|
#define SPR_RCPU_MI_RA2 (0x322)
|
||||||
#define SPR_MPC_MI_DBRAM1 (0x322)
|
#define SPR_MPC_MI_DBRAM1 (0x322)
|
||||||
|
#define SPR_BESCRR (0x322)
|
||||||
#define SPR_RCPU_MI_RA3 (0x323)
|
#define SPR_RCPU_MI_RA3 (0x323)
|
||||||
|
#define SPR_BESCRRU (0x323)
|
||||||
|
#define SPR_EBBHR (0x324)
|
||||||
|
#define SPR_EBBRR (0x325)
|
||||||
|
#define SPR_BESCR (0x326)
|
||||||
#define SPR_RCPU_L2U_RA0 (0x328)
|
#define SPR_RCPU_L2U_RA0 (0x328)
|
||||||
#define SPR_MPC_MD_DBCAM (0x328)
|
#define SPR_MPC_MD_DBCAM (0x328)
|
||||||
#define SPR_RCPU_L2U_RA1 (0x329)
|
#define SPR_RCPU_L2U_RA1 (0x329)
|
||||||
|
@ -1527,6 +1610,7 @@ static inline int cpu_mmu_index (CPUPPCState *env)
|
||||||
#define SPR_440_ITV3 (0x377)
|
#define SPR_440_ITV3 (0x377)
|
||||||
#define SPR_440_CCR1 (0x378)
|
#define SPR_440_CCR1 (0x378)
|
||||||
#define SPR_DCRIPR (0x37B)
|
#define SPR_DCRIPR (0x37B)
|
||||||
|
#define SPR_POWER_MMCRS (0x37E)
|
||||||
#define SPR_PPR (0x380)
|
#define SPR_PPR (0x380)
|
||||||
#define SPR_750_GQR0 (0x390)
|
#define SPR_750_GQR0 (0x390)
|
||||||
#define SPR_440_DNV0 (0x390)
|
#define SPR_440_DNV0 (0x390)
|
||||||
|
@ -1556,24 +1640,24 @@ static inline int cpu_mmu_index (CPUPPCState *env)
|
||||||
#define SPR_BOOKE_DCDBTRH (0x39D)
|
#define SPR_BOOKE_DCDBTRH (0x39D)
|
||||||
#define SPR_BOOKE_ICDBTRL (0x39E)
|
#define SPR_BOOKE_ICDBTRL (0x39E)
|
||||||
#define SPR_BOOKE_ICDBTRH (0x39F)
|
#define SPR_BOOKE_ICDBTRH (0x39F)
|
||||||
#define SPR_UMMCR2 (0x3A0)
|
#define SPR_74XX_UMMCR2 (0x3A0)
|
||||||
#define SPR_UPMC5 (0x3A1)
|
#define SPR_7XX_UPMC5 (0x3A1)
|
||||||
#define SPR_UPMC6 (0x3A2)
|
#define SPR_7XX_UPMC6 (0x3A2)
|
||||||
#define SPR_UBAMR (0x3A7)
|
#define SPR_UBAMR (0x3A7)
|
||||||
#define SPR_UMMCR0 (0x3A8)
|
#define SPR_7XX_UMMCR0 (0x3A8)
|
||||||
#define SPR_UPMC1 (0x3A9)
|
#define SPR_7XX_UPMC1 (0x3A9)
|
||||||
#define SPR_UPMC2 (0x3AA)
|
#define SPR_7XX_UPMC2 (0x3AA)
|
||||||
#define SPR_USIAR (0x3AB)
|
#define SPR_7XX_USIAR (0x3AB)
|
||||||
#define SPR_UMMCR1 (0x3AC)
|
#define SPR_7XX_UMMCR1 (0x3AC)
|
||||||
#define SPR_UPMC3 (0x3AD)
|
#define SPR_7XX_UPMC3 (0x3AD)
|
||||||
#define SPR_UPMC4 (0x3AE)
|
#define SPR_7XX_UPMC4 (0x3AE)
|
||||||
#define SPR_USDA (0x3AF)
|
#define SPR_USDA (0x3AF)
|
||||||
#define SPR_40x_ZPR (0x3B0)
|
#define SPR_40x_ZPR (0x3B0)
|
||||||
#define SPR_BOOKE_MAS7 (0x3B0)
|
#define SPR_BOOKE_MAS7 (0x3B0)
|
||||||
#define SPR_MMCR2 (0x3B0)
|
#define SPR_74XX_MMCR2 (0x3B0)
|
||||||
#define SPR_PMC5 (0x3B1)
|
#define SPR_7XX_PMC5 (0x3B1)
|
||||||
#define SPR_40x_PID (0x3B1)
|
#define SPR_40x_PID (0x3B1)
|
||||||
#define SPR_PMC6 (0x3B2)
|
#define SPR_7XX_PMC6 (0x3B2)
|
||||||
#define SPR_440_MMUCR (0x3B2)
|
#define SPR_440_MMUCR (0x3B2)
|
||||||
#define SPR_4xx_CCR0 (0x3B3)
|
#define SPR_4xx_CCR0 (0x3B3)
|
||||||
#define SPR_BOOKE_EPLC (0x3B3)
|
#define SPR_BOOKE_EPLC (0x3B3)
|
||||||
|
@ -1583,19 +1667,19 @@ static inline int cpu_mmu_index (CPUPPCState *env)
|
||||||
#define SPR_405_DVC1 (0x3B6)
|
#define SPR_405_DVC1 (0x3B6)
|
||||||
#define SPR_405_DVC2 (0x3B7)
|
#define SPR_405_DVC2 (0x3B7)
|
||||||
#define SPR_BAMR (0x3B7)
|
#define SPR_BAMR (0x3B7)
|
||||||
#define SPR_MMCR0 (0x3B8)
|
#define SPR_7XX_MMCR0 (0x3B8)
|
||||||
#define SPR_PMC1 (0x3B9)
|
#define SPR_7XX_PMC1 (0x3B9)
|
||||||
#define SPR_40x_SGR (0x3B9)
|
#define SPR_40x_SGR (0x3B9)
|
||||||
#define SPR_PMC2 (0x3BA)
|
#define SPR_7XX_PMC2 (0x3BA)
|
||||||
#define SPR_40x_DCWR (0x3BA)
|
#define SPR_40x_DCWR (0x3BA)
|
||||||
#define SPR_SIAR (0x3BB)
|
#define SPR_7XX_SIAR (0x3BB)
|
||||||
#define SPR_405_SLER (0x3BB)
|
#define SPR_405_SLER (0x3BB)
|
||||||
#define SPR_MMCR1 (0x3BC)
|
#define SPR_7XX_MMCR1 (0x3BC)
|
||||||
#define SPR_405_SU0R (0x3BC)
|
#define SPR_405_SU0R (0x3BC)
|
||||||
#define SPR_401_SKR (0x3BC)
|
#define SPR_401_SKR (0x3BC)
|
||||||
#define SPR_PMC3 (0x3BD)
|
#define SPR_7XX_PMC3 (0x3BD)
|
||||||
#define SPR_405_DBCR1 (0x3BD)
|
#define SPR_405_DBCR1 (0x3BD)
|
||||||
#define SPR_PMC4 (0x3BE)
|
#define SPR_7XX_PMC4 (0x3BE)
|
||||||
#define SPR_SDA (0x3BF)
|
#define SPR_SDA (0x3BF)
|
||||||
#define SPR_403_VTBL (0x3CC)
|
#define SPR_403_VTBL (0x3CC)
|
||||||
#define SPR_403_VTBU (0x3CD)
|
#define SPR_403_VTBU (0x3CD)
|
||||||
|
@ -1648,6 +1732,7 @@ static inline int cpu_mmu_index (CPUPPCState *env)
|
||||||
#define SPR_750_TDCL (0x3F4)
|
#define SPR_750_TDCL (0x3F4)
|
||||||
#define SPR_40x_IAC1 (0x3F4)
|
#define SPR_40x_IAC1 (0x3F4)
|
||||||
#define SPR_MMUCSR0 (0x3F4)
|
#define SPR_MMUCSR0 (0x3F4)
|
||||||
|
#define SPR_970_HID4 (0x3F4)
|
||||||
#define SPR_DABR (0x3F5)
|
#define SPR_DABR (0x3F5)
|
||||||
#define DABR_MASK (~(target_ulong)0x7)
|
#define DABR_MASK (~(target_ulong)0x7)
|
||||||
#define SPR_Exxx_BUCSR (0x3F5)
|
#define SPR_Exxx_BUCSR (0x3F5)
|
||||||
|
@ -1709,6 +1794,23 @@ static inline int cpu_mmu_index (CPUPPCState *env)
|
||||||
/* External Input Interrupt Directed to Guest State */
|
/* External Input Interrupt Directed to Guest State */
|
||||||
#define EPCR_EXTGS (1 << 31)
|
#define EPCR_EXTGS (1 << 31)
|
||||||
|
|
||||||
|
#define L1CSR0_CPE 0x00010000 /* Data Cache Parity Enable */
|
||||||
|
#define L1CSR0_CUL 0x00000400 /* (D-)Cache Unable to Lock */
|
||||||
|
#define L1CSR0_DCLFR 0x00000100 /* D-Cache Lock Flash Reset */
|
||||||
|
#define L1CSR0_DCFI 0x00000002 /* Data Cache Flash Invalidate */
|
||||||
|
#define L1CSR0_DCE 0x00000001 /* Data Cache Enable */
|
||||||
|
|
||||||
|
#define L1CSR1_CPE 0x00010000 /* Instruction Cache Parity Enable */
|
||||||
|
#define L1CSR1_ICUL 0x00000400 /* I-Cache Unable to Lock */
|
||||||
|
#define L1CSR1_ICLFR 0x00000100 /* I-Cache Lock Flash Reset */
|
||||||
|
#define L1CSR1_ICFI 0x00000002 /* Instruction Cache Flash Invalidate */
|
||||||
|
#define L1CSR1_ICE 0x00000001 /* Instruction Cache Enable */
|
||||||
|
|
||||||
|
/* HID0 bits */
|
||||||
|
#define HID0_DEEPNAP (1 << 24)
|
||||||
|
#define HID0_DOZE (1 << 23)
|
||||||
|
#define HID0_NAP (1 << 22)
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* PowerPC Instructions types definitions */
|
/* PowerPC Instructions types definitions */
|
||||||
enum {
|
enum {
|
||||||
|
@ -1910,7 +2012,7 @@ enum {
|
||||||
PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 | \
|
PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 | \
|
||||||
PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | \
|
PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | \
|
||||||
PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | \
|
PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | \
|
||||||
PPC2_ALTIVEC_207)
|
PPC2_ALTIVEC_207 | PPC2_ISA207S)
|
||||||
};
|
};
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@ -2042,6 +2144,15 @@ enum {
|
||||||
PPC_INTERRUPT_PERFM, /* Performance monitor interrupt */
|
PPC_INTERRUPT_PERFM, /* Performance monitor interrupt */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Processor Compatibility mask (PCR) */
|
||||||
|
enum {
|
||||||
|
PCR_COMPAT_2_05 = 1ull << (63-62),
|
||||||
|
PCR_COMPAT_2_06 = 1ull << (63-61),
|
||||||
|
PCR_VEC_DIS = 1ull << (63-0), /* Vec. disable (bit NA since POWER8) */
|
||||||
|
PCR_VSX_DIS = 1ull << (63-1), /* VSX disable (bit NA since POWER8) */
|
||||||
|
PCR_TM_DIS = 1ull << (63-2), /* Trans. memory disable (POWER8) */
|
||||||
|
};
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
static inline target_ulong cpu_read_xer(CPUPPCState *env)
|
static inline target_ulong cpu_read_xer(CPUPPCState *env)
|
||||||
|
|
1317
target-ppc/dfp_helper.c
Normal file
1317
target-ppc/dfp_helper.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -399,6 +399,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||||
new_msr |= (target_ulong)MSR_HVB;
|
new_msr |= (target_ulong)MSR_HVB;
|
||||||
}
|
}
|
||||||
goto store_current;
|
goto store_current;
|
||||||
|
case POWERPC_EXCP_FU: /* Facility unavailable exception */
|
||||||
|
if (lpes1 == 0) {
|
||||||
|
new_msr |= (target_ulong)MSR_HVB;
|
||||||
|
}
|
||||||
|
goto store_current;
|
||||||
case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
|
case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
|
||||||
LOG_EXCP("PIT exception\n");
|
LOG_EXCP("PIT exception\n");
|
||||||
goto store_next;
|
goto store_next;
|
||||||
|
@ -615,8 +620,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||||
if (asrr1 != -1) {
|
if (asrr1 != -1) {
|
||||||
env->spr[asrr1] = env->spr[srr1];
|
env->spr[asrr1] = env->spr[srr1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (env->spr[SPR_LPCR] & LPCR_AIL) {
|
||||||
|
new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
|
||||||
|
} else if (msr & ((1 << MSR_IR) | (1 << MSR_DR))) {
|
||||||
/* If we disactivated any translation, flush TLBs */
|
/* If we disactivated any translation, flush TLBs */
|
||||||
if (msr & ((1 << MSR_IR) | (1 << MSR_DR))) {
|
|
||||||
tlb_flush(cs, 1);
|
tlb_flush(cs, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -977,7 +977,6 @@ uint64_t helper_fres(CPUPPCState *env, uint64_t arg)
|
||||||
uint64_t helper_frsqrte(CPUPPCState *env, uint64_t arg)
|
uint64_t helper_frsqrte(CPUPPCState *env, uint64_t arg)
|
||||||
{
|
{
|
||||||
CPU_DoubleU farg;
|
CPU_DoubleU farg;
|
||||||
float32 f32;
|
|
||||||
|
|
||||||
farg.ll = arg;
|
farg.ll = arg;
|
||||||
|
|
||||||
|
@ -991,8 +990,6 @@ uint64_t helper_frsqrte(CPUPPCState *env, uint64_t arg)
|
||||||
}
|
}
|
||||||
farg.d = float64_sqrt(farg.d, &env->fp_status);
|
farg.d = float64_sqrt(farg.d, &env->fp_status);
|
||||||
farg.d = float64_div(float64_one, farg.d, &env->fp_status);
|
farg.d = float64_div(float64_one, farg.d, &env->fp_status);
|
||||||
f32 = float64_to_float32(farg.d, &env->fp_status);
|
|
||||||
farg.d = float32_to_float64(f32, &env->fp_status);
|
|
||||||
}
|
}
|
||||||
return farg.ll;
|
return farg.ll;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,55 @@
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
#include "exec/gdbstub.h"
|
#include "exec/gdbstub.h"
|
||||||
|
|
||||||
|
static int ppc_gdb_register_len(int n)
|
||||||
|
{
|
||||||
|
switch (n) {
|
||||||
|
case 0 ... 31:
|
||||||
|
/* gprs */
|
||||||
|
return sizeof(target_ulong);
|
||||||
|
case 32 ... 63:
|
||||||
|
/* fprs */
|
||||||
|
if (gdb_has_xml) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 8;
|
||||||
|
case 66:
|
||||||
|
/* cr */
|
||||||
|
return 4;
|
||||||
|
case 64:
|
||||||
|
/* nip */
|
||||||
|
case 65:
|
||||||
|
/* msr */
|
||||||
|
case 67:
|
||||||
|
/* lr */
|
||||||
|
case 68:
|
||||||
|
/* ctr */
|
||||||
|
case 69:
|
||||||
|
/* xer */
|
||||||
|
return sizeof(target_ulong);
|
||||||
|
case 70:
|
||||||
|
/* fpscr */
|
||||||
|
if (gdb_has_xml) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return sizeof(target_ulong);
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ppc_gdb_swap_register(uint8_t *mem_buf, int n, int len)
|
||||||
|
{
|
||||||
|
if (len == 4) {
|
||||||
|
bswap32s((uint32_t *)mem_buf);
|
||||||
|
} else if (len == 8) {
|
||||||
|
bswap64s((uint64_t *)mem_buf);
|
||||||
|
} else {
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Old gdb always expects FP registers. Newer (xml-aware) gdb only
|
/* Old gdb always expects FP registers. Newer (xml-aware) gdb only
|
||||||
* expects whatever the target description contains. Due to a
|
* expects whatever the target description contains. Due to a
|
||||||
* historical mishap the FP registers appear in between core integer
|
* historical mishap the FP registers appear in between core integer
|
||||||
|
@ -32,23 +81,26 @@ int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
{
|
{
|
||||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||||
CPUPPCState *env = &cpu->env;
|
CPUPPCState *env = &cpu->env;
|
||||||
|
int r = ppc_gdb_register_len(n);
|
||||||
|
|
||||||
|
if (!r) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
if (n < 32) {
|
if (n < 32) {
|
||||||
/* gprs */
|
/* gprs */
|
||||||
return gdb_get_regl(mem_buf, env->gpr[n]);
|
gdb_get_regl(mem_buf, env->gpr[n]);
|
||||||
} else if (n < 64) {
|
} else if (n < 64) {
|
||||||
/* fprs */
|
/* fprs */
|
||||||
if (gdb_has_xml) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
stfq_p(mem_buf, env->fpr[n-32]);
|
stfq_p(mem_buf, env->fpr[n-32]);
|
||||||
return 8;
|
|
||||||
} else {
|
} else {
|
||||||
switch (n) {
|
switch (n) {
|
||||||
case 64:
|
case 64:
|
||||||
return gdb_get_regl(mem_buf, env->nip);
|
gdb_get_regl(mem_buf, env->nip);
|
||||||
|
break;
|
||||||
case 65:
|
case 65:
|
||||||
return gdb_get_regl(mem_buf, env->msr);
|
gdb_get_regl(mem_buf, env->msr);
|
||||||
|
break;
|
||||||
case 66:
|
case 66:
|
||||||
{
|
{
|
||||||
uint32_t cr = 0;
|
uint32_t cr = 0;
|
||||||
|
@ -56,50 +108,57 @@ int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
cr |= env->crf[i] << (32 - ((i + 1) * 4));
|
cr |= env->crf[i] << (32 - ((i + 1) * 4));
|
||||||
}
|
}
|
||||||
return gdb_get_reg32(mem_buf, cr);
|
gdb_get_reg32(mem_buf, cr);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case 67:
|
case 67:
|
||||||
return gdb_get_regl(mem_buf, env->lr);
|
gdb_get_regl(mem_buf, env->lr);
|
||||||
|
break;
|
||||||
case 68:
|
case 68:
|
||||||
return gdb_get_regl(mem_buf, env->ctr);
|
gdb_get_regl(mem_buf, env->ctr);
|
||||||
|
break;
|
||||||
case 69:
|
case 69:
|
||||||
return gdb_get_regl(mem_buf, env->xer);
|
gdb_get_regl(mem_buf, env->xer);
|
||||||
|
break;
|
||||||
case 70:
|
case 70:
|
||||||
{
|
gdb_get_reg32(mem_buf, env->fpscr);
|
||||||
if (gdb_has_xml) {
|
break;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return gdb_get_reg32(mem_buf, env->fpscr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (msr_le) {
|
||||||
|
/* If cpu is in LE mode, convert memory contents to LE. */
|
||||||
|
ppc_gdb_swap_register(mem_buf, n, r);
|
||||||
}
|
}
|
||||||
return 0;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ppc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
int ppc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
{
|
{
|
||||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||||
CPUPPCState *env = &cpu->env;
|
CPUPPCState *env = &cpu->env;
|
||||||
|
int r = ppc_gdb_register_len(n);
|
||||||
|
|
||||||
|
if (!r) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if (msr_le) {
|
||||||
|
/* If cpu is in LE mode, convert memory contents to LE. */
|
||||||
|
ppc_gdb_swap_register(mem_buf, n, r);
|
||||||
|
}
|
||||||
if (n < 32) {
|
if (n < 32) {
|
||||||
/* gprs */
|
/* gprs */
|
||||||
env->gpr[n] = ldtul_p(mem_buf);
|
env->gpr[n] = ldtul_p(mem_buf);
|
||||||
return sizeof(target_ulong);
|
|
||||||
} else if (n < 64) {
|
} else if (n < 64) {
|
||||||
/* fprs */
|
/* fprs */
|
||||||
if (gdb_has_xml) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
env->fpr[n-32] = ldfq_p(mem_buf);
|
env->fpr[n-32] = ldfq_p(mem_buf);
|
||||||
return 8;
|
|
||||||
} else {
|
} else {
|
||||||
switch (n) {
|
switch (n) {
|
||||||
case 64:
|
case 64:
|
||||||
env->nip = ldtul_p(mem_buf);
|
env->nip = ldtul_p(mem_buf);
|
||||||
return sizeof(target_ulong);
|
break;
|
||||||
case 65:
|
case 65:
|
||||||
ppc_store_msr(env, ldtul_p(mem_buf));
|
ppc_store_msr(env, ldtul_p(mem_buf));
|
||||||
return sizeof(target_ulong);
|
break;
|
||||||
case 66:
|
case 66:
|
||||||
{
|
{
|
||||||
uint32_t cr = ldl_p(mem_buf);
|
uint32_t cr = ldl_p(mem_buf);
|
||||||
|
@ -107,25 +166,22 @@ int ppc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
env->crf[i] = (cr >> (32 - ((i + 1) * 4))) & 0xF;
|
env->crf[i] = (cr >> (32 - ((i + 1) * 4))) & 0xF;
|
||||||
}
|
}
|
||||||
return 4;
|
break;
|
||||||
}
|
}
|
||||||
case 67:
|
case 67:
|
||||||
env->lr = ldtul_p(mem_buf);
|
env->lr = ldtul_p(mem_buf);
|
||||||
return sizeof(target_ulong);
|
break;
|
||||||
case 68:
|
case 68:
|
||||||
env->ctr = ldtul_p(mem_buf);
|
env->ctr = ldtul_p(mem_buf);
|
||||||
return sizeof(target_ulong);
|
break;
|
||||||
case 69:
|
case 69:
|
||||||
env->xer = ldtul_p(mem_buf);
|
env->xer = ldtul_p(mem_buf);
|
||||||
return sizeof(target_ulong);
|
break;
|
||||||
case 70:
|
case 70:
|
||||||
/* fpscr */
|
/* fpscr */
|
||||||
if (gdb_has_xml) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
store_fpscr(env, ldtul_p(mem_buf), 0xffffffff);
|
store_fpscr(env, ldtul_p(mem_buf), 0xffffffff);
|
||||||
return sizeof(target_ulong);
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
|
@ -539,7 +539,7 @@ DEF_HELPER_2(booke206_tlbivax, void, env, tl)
|
||||||
DEF_HELPER_2(booke206_tlbilx0, void, env, tl)
|
DEF_HELPER_2(booke206_tlbilx0, void, env, tl)
|
||||||
DEF_HELPER_2(booke206_tlbilx1, void, env, tl)
|
DEF_HELPER_2(booke206_tlbilx1, void, env, tl)
|
||||||
DEF_HELPER_2(booke206_tlbilx3, void, env, tl)
|
DEF_HELPER_2(booke206_tlbilx3, void, env, tl)
|
||||||
DEF_HELPER_2(booke206_tlbflush, void, env, i32)
|
DEF_HELPER_2(booke206_tlbflush, void, env, tl)
|
||||||
DEF_HELPER_3(booke_setpid, void, env, i32, tl)
|
DEF_HELPER_3(booke_setpid, void, env, i32, tl)
|
||||||
DEF_HELPER_2(6xx_tlbd, void, env, tl)
|
DEF_HELPER_2(6xx_tlbd, void, env, tl)
|
||||||
DEF_HELPER_2(6xx_tlbi, void, env, tl)
|
DEF_HELPER_2(6xx_tlbi, void, env, tl)
|
||||||
|
@ -577,6 +577,8 @@ DEF_HELPER_3(store_dcr, void, env, tl, tl)
|
||||||
|
|
||||||
DEF_HELPER_2(load_dump_spr, void, env, i32)
|
DEF_HELPER_2(load_dump_spr, void, env, i32)
|
||||||
DEF_HELPER_2(store_dump_spr, void, env, i32)
|
DEF_HELPER_2(store_dump_spr, void, env, i32)
|
||||||
|
DEF_HELPER_4(fscr_facility_check, void, env, i32, i32, i32)
|
||||||
|
DEF_HELPER_4(msr_facility_check, void, env, i32, i32, i32)
|
||||||
DEF_HELPER_1(load_tbl, tl, env)
|
DEF_HELPER_1(load_tbl, tl, env)
|
||||||
DEF_HELPER_1(load_tbu, tl, env)
|
DEF_HELPER_1(load_tbu, tl, env)
|
||||||
DEF_HELPER_1(load_atbl, tl, env)
|
DEF_HELPER_1(load_atbl, tl, env)
|
||||||
|
@ -611,3 +613,58 @@ DEF_HELPER_3(store_dbatu, void, env, i32, tl)
|
||||||
DEF_HELPER_3(store_601_batl, void, env, i32, tl)
|
DEF_HELPER_3(store_601_batl, void, env, i32, tl)
|
||||||
DEF_HELPER_3(store_601_batu, void, env, i32, tl)
|
DEF_HELPER_3(store_601_batu, void, env, i32, tl)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define dh_alias_fprp ptr
|
||||||
|
#define dh_ctype_fprp uint64_t *
|
||||||
|
#define dh_is_signed_fprp dh_is_signed_ptr
|
||||||
|
|
||||||
|
DEF_HELPER_4(dadd, void, env, fprp, fprp, fprp)
|
||||||
|
DEF_HELPER_4(daddq, void, env, fprp, fprp, fprp)
|
||||||
|
DEF_HELPER_4(dsub, void, env, fprp, fprp, fprp)
|
||||||
|
DEF_HELPER_4(dsubq, void, env, fprp, fprp, fprp)
|
||||||
|
DEF_HELPER_4(dmul, void, env, fprp, fprp, fprp)
|
||||||
|
DEF_HELPER_4(dmulq, void, env, fprp, fprp, fprp)
|
||||||
|
DEF_HELPER_4(ddiv, void, env, fprp, fprp, fprp)
|
||||||
|
DEF_HELPER_4(ddivq, void, env, fprp, fprp, fprp)
|
||||||
|
DEF_HELPER_3(dcmpo, i32, env, fprp, fprp)
|
||||||
|
DEF_HELPER_3(dcmpoq, i32, env, fprp, fprp)
|
||||||
|
DEF_HELPER_3(dcmpu, i32, env, fprp, fprp)
|
||||||
|
DEF_HELPER_3(dcmpuq, i32, env, fprp, fprp)
|
||||||
|
DEF_HELPER_3(dtstdc, i32, env, fprp, i32)
|
||||||
|
DEF_HELPER_3(dtstdcq, i32, env, fprp, i32)
|
||||||
|
DEF_HELPER_3(dtstdg, i32, env, fprp, i32)
|
||||||
|
DEF_HELPER_3(dtstdgq, i32, env, fprp, i32)
|
||||||
|
DEF_HELPER_3(dtstex, i32, env, fprp, fprp)
|
||||||
|
DEF_HELPER_3(dtstexq, i32, env, fprp, fprp)
|
||||||
|
DEF_HELPER_3(dtstsf, i32, env, fprp, fprp)
|
||||||
|
DEF_HELPER_3(dtstsfq, i32, env, fprp, fprp)
|
||||||
|
DEF_HELPER_5(dquai, void, env, fprp, fprp, i32, i32)
|
||||||
|
DEF_HELPER_5(dquaiq, void, env, fprp, fprp, i32, i32)
|
||||||
|
DEF_HELPER_5(dqua, void, env, fprp, fprp, fprp, i32)
|
||||||
|
DEF_HELPER_5(dquaq, void, env, fprp, fprp, fprp, i32)
|
||||||
|
DEF_HELPER_5(drrnd, void, env, fprp, fprp, fprp, i32)
|
||||||
|
DEF_HELPER_5(drrndq, void, env, fprp, fprp, fprp, i32)
|
||||||
|
DEF_HELPER_5(drintx, void, env, fprp, fprp, i32, i32)
|
||||||
|
DEF_HELPER_5(drintxq, void, env, fprp, fprp, i32, i32)
|
||||||
|
DEF_HELPER_5(drintn, void, env, fprp, fprp, i32, i32)
|
||||||
|
DEF_HELPER_5(drintnq, void, env, fprp, fprp, i32, i32)
|
||||||
|
DEF_HELPER_3(dctdp, void, env, fprp, fprp)
|
||||||
|
DEF_HELPER_3(dctqpq, void, env, fprp, fprp)
|
||||||
|
DEF_HELPER_3(drsp, void, env, fprp, fprp)
|
||||||
|
DEF_HELPER_3(drdpq, void, env, fprp, fprp)
|
||||||
|
DEF_HELPER_3(dcffix, void, env, fprp, fprp)
|
||||||
|
DEF_HELPER_3(dcffixq, void, env, fprp, fprp)
|
||||||
|
DEF_HELPER_3(dctfix, void, env, fprp, fprp)
|
||||||
|
DEF_HELPER_3(dctfixq, void, env, fprp, fprp)
|
||||||
|
DEF_HELPER_4(ddedpd, void, env, fprp, fprp, i32)
|
||||||
|
DEF_HELPER_4(ddedpdq, void, env, fprp, fprp, i32)
|
||||||
|
DEF_HELPER_4(denbcd, void, env, fprp, fprp, i32)
|
||||||
|
DEF_HELPER_4(denbcdq, void, env, fprp, fprp, i32)
|
||||||
|
DEF_HELPER_3(dxex, void, env, fprp, fprp)
|
||||||
|
DEF_HELPER_3(dxexq, void, env, fprp, fprp)
|
||||||
|
DEF_HELPER_4(diex, void, env, fprp, fprp, fprp)
|
||||||
|
DEF_HELPER_4(diexq, void, env, fprp, fprp, fprp)
|
||||||
|
DEF_HELPER_4(dscri, void, env, fprp, fprp, i32)
|
||||||
|
DEF_HELPER_4(dscriq, void, env, fprp, fprp, i32)
|
||||||
|
DEF_HELPER_4(dscli, void, env, fprp, fprp, i32)
|
||||||
|
DEF_HELPER_4(dscliq, void, env, fprp, fprp, i32)
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "qemu/host-utils.h"
|
#include "qemu/host-utils.h"
|
||||||
#include "exec/helper-proto.h"
|
#include "exec/helper-proto.h"
|
||||||
|
#include "qemu/aes.h"
|
||||||
|
|
||||||
#include "helper_regs.h"
|
#include "helper_regs.h"
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@ -396,9 +397,13 @@ target_ulong helper_602_mfrom(target_ulong arg)
|
||||||
#if defined(HOST_WORDS_BIGENDIAN)
|
#if defined(HOST_WORDS_BIGENDIAN)
|
||||||
#define HI_IDX 0
|
#define HI_IDX 0
|
||||||
#define LO_IDX 1
|
#define LO_IDX 1
|
||||||
|
#define AVRB(i) u8[i]
|
||||||
|
#define AVRW(i) u32[i]
|
||||||
#else
|
#else
|
||||||
#define HI_IDX 1
|
#define HI_IDX 1
|
||||||
#define LO_IDX 0
|
#define LO_IDX 0
|
||||||
|
#define AVRB(i) u8[15-(i)]
|
||||||
|
#define AVRW(i) u32[3-(i)]
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HOST_WORDS_BIGENDIAN)
|
#if defined(HOST_WORDS_BIGENDIAN)
|
||||||
|
@ -2338,284 +2343,63 @@ uint32_t helper_bcdsub(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
|
||||||
return helper_bcdadd(r, a, &bcopy, ps);
|
return helper_bcdadd(r, a, &bcopy, ps);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t SBOX[256] = {
|
|
||||||
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5,
|
|
||||||
0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
|
|
||||||
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0,
|
|
||||||
0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
|
|
||||||
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC,
|
|
||||||
0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
|
|
||||||
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A,
|
|
||||||
0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
|
|
||||||
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0,
|
|
||||||
0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
|
|
||||||
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B,
|
|
||||||
0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
|
|
||||||
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85,
|
|
||||||
0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
|
|
||||||
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5,
|
|
||||||
0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
|
|
||||||
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17,
|
|
||||||
0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
|
|
||||||
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88,
|
|
||||||
0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
|
|
||||||
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C,
|
|
||||||
0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
|
|
||||||
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9,
|
|
||||||
0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
|
|
||||||
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6,
|
|
||||||
0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
|
|
||||||
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E,
|
|
||||||
0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
|
|
||||||
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94,
|
|
||||||
0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
|
|
||||||
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68,
|
|
||||||
0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void SubBytes(ppc_avr_t *r, ppc_avr_t *a)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
VECTOR_FOR_INORDER_I(i, u8) {
|
|
||||||
r->u8[i] = SBOX[a->u8[i]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t InvSBOX[256] = {
|
|
||||||
0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38,
|
|
||||||
0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
|
|
||||||
0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87,
|
|
||||||
0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
|
|
||||||
0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D,
|
|
||||||
0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
|
|
||||||
0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2,
|
|
||||||
0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
|
|
||||||
0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16,
|
|
||||||
0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
|
|
||||||
0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA,
|
|
||||||
0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
|
|
||||||
0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A,
|
|
||||||
0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
|
|
||||||
0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02,
|
|
||||||
0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
|
|
||||||
0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA,
|
|
||||||
0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
|
|
||||||
0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85,
|
|
||||||
0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
|
|
||||||
0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89,
|
|
||||||
0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
|
|
||||||
0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20,
|
|
||||||
0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
|
|
||||||
0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31,
|
|
||||||
0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
|
|
||||||
0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D,
|
|
||||||
0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
|
|
||||||
0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0,
|
|
||||||
0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
|
|
||||||
0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26,
|
|
||||||
0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void InvSubBytes(ppc_avr_t *r, ppc_avr_t *a)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
VECTOR_FOR_INORDER_I(i, u8) {
|
|
||||||
r->u8[i] = InvSBOX[a->u8[i]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t ROTL8(uint8_t x, int n)
|
|
||||||
{
|
|
||||||
return (x << n) | (x >> (8-n));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int BIT8(uint8_t x, int n)
|
|
||||||
{
|
|
||||||
return (x & (0x80 >> n)) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t GFx02(uint8_t x)
|
|
||||||
{
|
|
||||||
return ROTL8(x, 1) ^ (BIT8(x, 0) ? 0x1A : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t GFx03(uint8_t x)
|
|
||||||
{
|
|
||||||
return x ^ ROTL8(x, 1) ^ (BIT8(x, 0) ? 0x1A : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t GFx09(uint8_t x)
|
|
||||||
{
|
|
||||||
uint8_t term2 = ROTL8(x, 3);
|
|
||||||
uint8_t term3 = (BIT8(x, 0) ? 0x68 : 0) | (BIT8(x, 1) ? 0x14 : 0) |
|
|
||||||
(BIT8(x, 2) ? 0x02 : 0);
|
|
||||||
uint8_t term4 = (BIT8(x, 1) ? 0x20 : 0) | (BIT8(x, 2) ? 0x18 : 0);
|
|
||||||
return x ^ term2 ^ term3 ^ term4;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t GFx0B(uint8_t x)
|
|
||||||
{
|
|
||||||
uint8_t term2 = ROTL8(x, 1);
|
|
||||||
uint8_t term3 = (x << 3) | (BIT8(x, 0) ? 0x06 : 0) |
|
|
||||||
(BIT8(x, 2) ? 0x01 : 0);
|
|
||||||
uint8_t term4 = (BIT8(x, 0) ? 0x70 : 0) | (BIT8(x, 1) ? 0x06 : 0) |
|
|
||||||
(BIT8(x, 2) ? 0x08 : 0);
|
|
||||||
uint8_t term5 = (BIT8(x, 1) ? 0x30 : 0) | (BIT8(x, 2) ? 0x02 : 0);
|
|
||||||
uint8_t term6 = BIT8(x, 2) ? 0x10 : 0;
|
|
||||||
return x ^ term2 ^ term3 ^ term4 ^ term5 ^ term6;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t GFx0D(uint8_t x)
|
|
||||||
{
|
|
||||||
uint8_t term2 = ROTL8(x, 2);
|
|
||||||
uint8_t term3 = (x << 3) | (BIT8(x, 1) ? 0x04 : 0) |
|
|
||||||
(BIT8(x, 2) ? 0x03 : 0);
|
|
||||||
uint8_t term4 = (BIT8(x, 0) ? 0x58 : 0) | (BIT8(x, 1) ? 0x20 : 0);
|
|
||||||
uint8_t term5 = (BIT8(x, 1) ? 0x08 : 0) | (BIT8(x, 2) ? 0x10 : 0);
|
|
||||||
uint8_t term6 = BIT8(x, 2) ? 0x08 : 0;
|
|
||||||
return x ^ term2 ^ term3 ^ term4 ^ term5 ^ term6;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t GFx0E(uint8_t x)
|
|
||||||
{
|
|
||||||
uint8_t term1 = ROTL8(x, 1);
|
|
||||||
uint8_t term2 = (x << 2) | (BIT8(x, 2) ? 0x02 : 0) |
|
|
||||||
(BIT8(x, 1) ? 0x01 : 0);
|
|
||||||
uint8_t term3 = (x << 3) | (BIT8(x, 1) ? 0x04 : 0) |
|
|
||||||
(BIT8(x, 2) ? 0x01 : 0);
|
|
||||||
uint8_t term4 = (BIT8(x, 0) ? 0x40 : 0) | (BIT8(x, 1) ? 0x28 : 0) |
|
|
||||||
(BIT8(x, 2) ? 0x10 : 0);
|
|
||||||
uint8_t term5 = (BIT8(x, 2) ? 0x08 : 0);
|
|
||||||
return term1 ^ term2 ^ term3 ^ term4 ^ term5;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(HOST_WORDS_BIGENDIAN)
|
|
||||||
#define MCB(x, i, b) ((x)->u8[(i)*4 + (b)])
|
|
||||||
#else
|
|
||||||
#define MCB(x, i, b) ((x)->u8[15 - ((i)*4 + (b))])
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void MixColumns(ppc_avr_t *r, ppc_avr_t *x)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
MCB(r, i, 0) = GFx02(MCB(x, i, 0)) ^ GFx03(MCB(x, i, 1)) ^
|
|
||||||
MCB(x, i, 2) ^ MCB(x, i, 3);
|
|
||||||
MCB(r, i, 1) = MCB(x, i, 0) ^ GFx02(MCB(x, i, 1)) ^
|
|
||||||
GFx03(MCB(x, i, 2)) ^ MCB(x, i, 3);
|
|
||||||
MCB(r, i, 2) = MCB(x, i, 0) ^ MCB(x, i, 1) ^
|
|
||||||
GFx02(MCB(x, i, 2)) ^ GFx03(MCB(x, i, 3));
|
|
||||||
MCB(r, i, 3) = GFx03(MCB(x, i, 0)) ^ MCB(x, i, 1) ^
|
|
||||||
MCB(x, i, 2) ^ GFx02(MCB(x, i, 3));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void InvMixColumns(ppc_avr_t *r, ppc_avr_t *x)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
MCB(r, i, 0) = GFx0E(MCB(x, i, 0)) ^ GFx0B(MCB(x, i, 1)) ^
|
|
||||||
GFx0D(MCB(x, i, 2)) ^ GFx09(MCB(x, i, 3));
|
|
||||||
MCB(r, i, 1) = GFx09(MCB(x, i, 0)) ^ GFx0E(MCB(x, i, 1)) ^
|
|
||||||
GFx0B(MCB(x, i, 2)) ^ GFx0D(MCB(x, i, 3));
|
|
||||||
MCB(r, i, 2) = GFx0D(MCB(x, i, 0)) ^ GFx09(MCB(x, i, 1)) ^
|
|
||||||
GFx0E(MCB(x, i, 2)) ^ GFx0B(MCB(x, i, 3));
|
|
||||||
MCB(r, i, 3) = GFx0B(MCB(x, i, 0)) ^ GFx0D(MCB(x, i, 1)) ^
|
|
||||||
GFx09(MCB(x, i, 2)) ^ GFx0E(MCB(x, i, 3));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ShiftRows(ppc_avr_t *r, ppc_avr_t *x)
|
|
||||||
{
|
|
||||||
MCB(r, 0, 0) = MCB(x, 0, 0);
|
|
||||||
MCB(r, 1, 0) = MCB(x, 1, 0);
|
|
||||||
MCB(r, 2, 0) = MCB(x, 2, 0);
|
|
||||||
MCB(r, 3, 0) = MCB(x, 3, 0);
|
|
||||||
|
|
||||||
MCB(r, 0, 1) = MCB(x, 1, 1);
|
|
||||||
MCB(r, 1, 1) = MCB(x, 2, 1);
|
|
||||||
MCB(r, 2, 1) = MCB(x, 3, 1);
|
|
||||||
MCB(r, 3, 1) = MCB(x, 0, 1);
|
|
||||||
|
|
||||||
MCB(r, 0, 2) = MCB(x, 2, 2);
|
|
||||||
MCB(r, 1, 2) = MCB(x, 3, 2);
|
|
||||||
MCB(r, 2, 2) = MCB(x, 0, 2);
|
|
||||||
MCB(r, 3, 2) = MCB(x, 1, 2);
|
|
||||||
|
|
||||||
MCB(r, 0, 3) = MCB(x, 3, 3);
|
|
||||||
MCB(r, 1, 3) = MCB(x, 0, 3);
|
|
||||||
MCB(r, 2, 3) = MCB(x, 1, 3);
|
|
||||||
MCB(r, 3, 3) = MCB(x, 2, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void InvShiftRows(ppc_avr_t *r, ppc_avr_t *x)
|
|
||||||
{
|
|
||||||
MCB(r, 0, 0) = MCB(x, 0, 0);
|
|
||||||
MCB(r, 1, 0) = MCB(x, 1, 0);
|
|
||||||
MCB(r, 2, 0) = MCB(x, 2, 0);
|
|
||||||
MCB(r, 3, 0) = MCB(x, 3, 0);
|
|
||||||
|
|
||||||
MCB(r, 0, 1) = MCB(x, 3, 1);
|
|
||||||
MCB(r, 1, 1) = MCB(x, 0, 1);
|
|
||||||
MCB(r, 2, 1) = MCB(x, 1, 1);
|
|
||||||
MCB(r, 3, 1) = MCB(x, 2, 1);
|
|
||||||
|
|
||||||
MCB(r, 0, 2) = MCB(x, 2, 2);
|
|
||||||
MCB(r, 1, 2) = MCB(x, 3, 2);
|
|
||||||
MCB(r, 2, 2) = MCB(x, 0, 2);
|
|
||||||
MCB(r, 3, 2) = MCB(x, 1, 2);
|
|
||||||
|
|
||||||
MCB(r, 0, 3) = MCB(x, 1, 3);
|
|
||||||
MCB(r, 1, 3) = MCB(x, 2, 3);
|
|
||||||
MCB(r, 2, 3) = MCB(x, 3, 3);
|
|
||||||
MCB(r, 3, 3) = MCB(x, 0, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef MCB
|
|
||||||
|
|
||||||
void helper_vsbox(ppc_avr_t *r, ppc_avr_t *a)
|
void helper_vsbox(ppc_avr_t *r, ppc_avr_t *a)
|
||||||
{
|
{
|
||||||
SubBytes(r, a);
|
int i;
|
||||||
|
VECTOR_FOR_INORDER_I(i, u8) {
|
||||||
|
r->u8[i] = AES_sbox[a->u8[i]];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_vcipher(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
|
void helper_vcipher(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
|
||||||
{
|
{
|
||||||
ppc_avr_t vtemp1, vtemp2, vtemp3;
|
int i;
|
||||||
SubBytes(&vtemp1, a);
|
|
||||||
ShiftRows(&vtemp2, &vtemp1);
|
VECTOR_FOR_INORDER_I(i, u32) {
|
||||||
MixColumns(&vtemp3, &vtemp2);
|
r->AVRW(i) = b->AVRW(i) ^
|
||||||
r->u64[0] = vtemp3.u64[0] ^ b->u64[0];
|
(AES_Te0[a->AVRB(AES_shifts[4*i + 0])] ^
|
||||||
r->u64[1] = vtemp3.u64[1] ^ b->u64[1];
|
AES_Te1[a->AVRB(AES_shifts[4*i + 1])] ^
|
||||||
|
AES_Te2[a->AVRB(AES_shifts[4*i + 2])] ^
|
||||||
|
AES_Te3[a->AVRB(AES_shifts[4*i + 3])]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_vcipherlast(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
|
void helper_vcipherlast(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
|
||||||
{
|
{
|
||||||
ppc_avr_t vtemp1, vtemp2;
|
int i;
|
||||||
SubBytes(&vtemp1, a);
|
|
||||||
ShiftRows(&vtemp2, &vtemp1);
|
VECTOR_FOR_INORDER_I(i, u8) {
|
||||||
r->u64[0] = vtemp2.u64[0] ^ b->u64[0];
|
r->AVRB(i) = b->AVRB(i) ^ (AES_Te4[a->AVRB(AES_shifts[i])] & 0xFF);
|
||||||
r->u64[1] = vtemp2.u64[1] ^ b->u64[1];
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_vncipher(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
|
void helper_vncipher(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
|
||||||
{
|
{
|
||||||
/* This differs from what is written in ISA V2.07. The RTL is */
|
/* This differs from what is written in ISA V2.07. The RTL is */
|
||||||
/* incorrect and will be fixed in V2.07B. */
|
/* incorrect and will be fixed in V2.07B. */
|
||||||
ppc_avr_t vtemp1, vtemp2, vtemp3;
|
int i;
|
||||||
InvShiftRows(&vtemp1, a);
|
ppc_avr_t tmp;
|
||||||
InvSubBytes(&vtemp2, &vtemp1);
|
|
||||||
vtemp3.u64[0] = vtemp2.u64[0] ^ b->u64[0];
|
VECTOR_FOR_INORDER_I(i, u8) {
|
||||||
vtemp3.u64[1] = vtemp2.u64[1] ^ b->u64[1];
|
tmp.AVRB(i) = b->AVRB(i) ^ AES_isbox[a->AVRB(AES_ishifts[i])];
|
||||||
InvMixColumns(r, &vtemp3);
|
}
|
||||||
|
|
||||||
|
VECTOR_FOR_INORDER_I(i, u32) {
|
||||||
|
r->AVRW(i) =
|
||||||
|
AES_imc[tmp.AVRB(4*i + 0)][0] ^
|
||||||
|
AES_imc[tmp.AVRB(4*i + 1)][1] ^
|
||||||
|
AES_imc[tmp.AVRB(4*i + 2)][2] ^
|
||||||
|
AES_imc[tmp.AVRB(4*i + 3)][3];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_vncipherlast(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
|
void helper_vncipherlast(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
|
||||||
{
|
{
|
||||||
ppc_avr_t vtemp1, vtemp2;
|
int i;
|
||||||
InvShiftRows(&vtemp1, a);
|
|
||||||
InvSubBytes(&vtemp2, &vtemp1);
|
VECTOR_FOR_INORDER_I(i, u8) {
|
||||||
r->u64[0] = vtemp2.u64[0] ^ b->u64[0];
|
r->AVRB(i) = b->AVRB(i) ^ (AES_Td4[a->AVRB(AES_ishifts[i])] & 0xFF);
|
||||||
r->u64[1] = vtemp2.u64[1] ^ b->u64[1];
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ROTRu32(v, n) (((v) >> (n)) | ((v) << (32-n)))
|
#define ROTRu32(v, n) (((v) >> (n)) | ((v) << (32-n)))
|
||||||
|
|
111
target-ppc/kvm.c
111
target-ppc/kvm.c
|
@ -35,6 +35,7 @@
|
||||||
#include "hw/sysbus.h"
|
#include "hw/sysbus.h"
|
||||||
#include "hw/ppc/spapr.h"
|
#include "hw/ppc/spapr.h"
|
||||||
#include "hw/ppc/spapr_vio.h"
|
#include "hw/ppc/spapr_vio.h"
|
||||||
|
#include "hw/ppc/ppc.h"
|
||||||
#include "sysemu/watchdog.h"
|
#include "sysemu/watchdog.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
|
||||||
|
@ -61,12 +62,14 @@ static int cap_booke_sregs;
|
||||||
static int cap_ppc_smt;
|
static int cap_ppc_smt;
|
||||||
static int cap_ppc_rma;
|
static int cap_ppc_rma;
|
||||||
static int cap_spapr_tce;
|
static int cap_spapr_tce;
|
||||||
|
static int cap_spapr_multitce;
|
||||||
static int cap_hior;
|
static int cap_hior;
|
||||||
static int cap_one_reg;
|
static int cap_one_reg;
|
||||||
static int cap_epr;
|
static int cap_epr;
|
||||||
static int cap_ppc_watchdog;
|
static int cap_ppc_watchdog;
|
||||||
static int cap_papr;
|
static int cap_papr;
|
||||||
static int cap_htab_fd;
|
static int cap_htab_fd;
|
||||||
|
static int cap_fixup_hcalls;
|
||||||
|
|
||||||
/* XXX We have a race condition where we actually have a level triggered
|
/* XXX We have a race condition where we actually have a level triggered
|
||||||
* interrupt, but the infrastructure can't expose that yet, so the guest
|
* interrupt, but the infrastructure can't expose that yet, so the guest
|
||||||
|
@ -97,6 +100,7 @@ int kvm_arch_init(KVMState *s)
|
||||||
cap_ppc_smt = kvm_check_extension(s, KVM_CAP_PPC_SMT);
|
cap_ppc_smt = kvm_check_extension(s, KVM_CAP_PPC_SMT);
|
||||||
cap_ppc_rma = kvm_check_extension(s, KVM_CAP_PPC_RMA);
|
cap_ppc_rma = kvm_check_extension(s, KVM_CAP_PPC_RMA);
|
||||||
cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE);
|
cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE);
|
||||||
|
cap_spapr_multitce = kvm_check_extension(s, KVM_CAP_SPAPR_MULTITCE);
|
||||||
cap_one_reg = kvm_check_extension(s, KVM_CAP_ONE_REG);
|
cap_one_reg = kvm_check_extension(s, KVM_CAP_ONE_REG);
|
||||||
cap_hior = kvm_check_extension(s, KVM_CAP_PPC_HIOR);
|
cap_hior = kvm_check_extension(s, KVM_CAP_PPC_HIOR);
|
||||||
cap_epr = kvm_check_extension(s, KVM_CAP_PPC_EPR);
|
cap_epr = kvm_check_extension(s, KVM_CAP_PPC_EPR);
|
||||||
|
@ -104,6 +108,7 @@ int kvm_arch_init(KVMState *s)
|
||||||
/* Note: we don't set cap_papr here, because this capability is
|
/* Note: we don't set cap_papr here, because this capability is
|
||||||
* only activated after this by kvmppc_set_papr() */
|
* only activated after this by kvmppc_set_papr() */
|
||||||
cap_htab_fd = kvm_check_extension(s, KVM_CAP_PPC_HTAB_FD);
|
cap_htab_fd = kvm_check_extension(s, KVM_CAP_PPC_HTAB_FD);
|
||||||
|
cap_fixup_hcalls = kvm_check_extension(s, KVM_CAP_PPC_FIXUP_HCALL);
|
||||||
|
|
||||||
if (!cap_interrupt_level) {
|
if (!cap_interrupt_level) {
|
||||||
fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the "
|
fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the "
|
||||||
|
@ -356,6 +361,10 @@ static void kvm_fixup_page_sizes(PowerPCCPU *cpu)
|
||||||
/* Convert to QEMU form */
|
/* Convert to QEMU form */
|
||||||
memset(&env->sps, 0, sizeof(env->sps));
|
memset(&env->sps, 0, sizeof(env->sps));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX This loop should be an entry wide AND of the capabilities that
|
||||||
|
* the selected CPU has with the capabilities that KVM supports.
|
||||||
|
*/
|
||||||
for (ik = iq = 0; ik < KVM_PPC_PAGE_SIZES_MAX_SZ; ik++) {
|
for (ik = iq = 0; ik < KVM_PPC_PAGE_SIZES_MAX_SZ; ik++) {
|
||||||
struct ppc_one_seg_page_size *qsps = &env->sps.sps[iq];
|
struct ppc_one_seg_page_size *qsps = &env->sps.sps[iq];
|
||||||
struct kvm_ppc_one_seg_page_size *ksps = &smmu_info.sps[ik];
|
struct kvm_ppc_one_seg_page_size *ksps = &smmu_info.sps[ik];
|
||||||
|
@ -382,9 +391,7 @@ static void kvm_fixup_page_sizes(PowerPCCPU *cpu)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
env->slb_nr = smmu_info.slb_size;
|
env->slb_nr = smmu_info.slb_size;
|
||||||
if (smmu_info.flags & KVM_PPC_1T_SEGMENTS) {
|
if (!(smmu_info.flags & KVM_PPC_1T_SEGMENTS)) {
|
||||||
env->mmu_model |= POWERPC_MMU_1TSEG;
|
|
||||||
} else {
|
|
||||||
env->mmu_model &= ~POWERPC_MMU_1TSEG;
|
env->mmu_model &= ~POWERPC_MMU_1TSEG;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -858,11 +865,32 @@ int kvm_arch_put_registers(CPUState *cs, int level)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TARGET_PPC64
|
#ifdef TARGET_PPC64
|
||||||
|
if (msr_ts) {
|
||||||
|
for (i = 0; i < ARRAY_SIZE(env->tm_gpr); i++) {
|
||||||
|
kvm_set_one_reg(cs, KVM_REG_PPC_TM_GPR(i), &env->tm_gpr[i]);
|
||||||
|
}
|
||||||
|
for (i = 0; i < ARRAY_SIZE(env->tm_vsr); i++) {
|
||||||
|
kvm_set_one_reg(cs, KVM_REG_PPC_TM_VSR(i), &env->tm_vsr[i]);
|
||||||
|
}
|
||||||
|
kvm_set_one_reg(cs, KVM_REG_PPC_TM_CR, &env->tm_cr);
|
||||||
|
kvm_set_one_reg(cs, KVM_REG_PPC_TM_LR, &env->tm_lr);
|
||||||
|
kvm_set_one_reg(cs, KVM_REG_PPC_TM_CTR, &env->tm_ctr);
|
||||||
|
kvm_set_one_reg(cs, KVM_REG_PPC_TM_FPSCR, &env->tm_fpscr);
|
||||||
|
kvm_set_one_reg(cs, KVM_REG_PPC_TM_AMR, &env->tm_amr);
|
||||||
|
kvm_set_one_reg(cs, KVM_REG_PPC_TM_PPR, &env->tm_ppr);
|
||||||
|
kvm_set_one_reg(cs, KVM_REG_PPC_TM_VRSAVE, &env->tm_vrsave);
|
||||||
|
kvm_set_one_reg(cs, KVM_REG_PPC_TM_VSCR, &env->tm_vscr);
|
||||||
|
kvm_set_one_reg(cs, KVM_REG_PPC_TM_DSCR, &env->tm_dscr);
|
||||||
|
kvm_set_one_reg(cs, KVM_REG_PPC_TM_TAR, &env->tm_tar);
|
||||||
|
}
|
||||||
|
|
||||||
if (cap_papr) {
|
if (cap_papr) {
|
||||||
if (kvm_put_vpa(cs) < 0) {
|
if (kvm_put_vpa(cs) < 0) {
|
||||||
DPRINTF("Warning: Unable to set VPA information to KVM\n");
|
DPRINTF("Warning: Unable to set VPA information to KVM\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kvm_set_one_reg(cs, KVM_REG_PPC_TB_OFFSET, &env->tb_env->tb_offset);
|
||||||
#endif /* TARGET_PPC64 */
|
#endif /* TARGET_PPC64 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1082,11 +1110,32 @@ int kvm_arch_get_registers(CPUState *cs)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TARGET_PPC64
|
#ifdef TARGET_PPC64
|
||||||
|
if (msr_ts) {
|
||||||
|
for (i = 0; i < ARRAY_SIZE(env->tm_gpr); i++) {
|
||||||
|
kvm_get_one_reg(cs, KVM_REG_PPC_TM_GPR(i), &env->tm_gpr[i]);
|
||||||
|
}
|
||||||
|
for (i = 0; i < ARRAY_SIZE(env->tm_vsr); i++) {
|
||||||
|
kvm_get_one_reg(cs, KVM_REG_PPC_TM_VSR(i), &env->tm_vsr[i]);
|
||||||
|
}
|
||||||
|
kvm_get_one_reg(cs, KVM_REG_PPC_TM_CR, &env->tm_cr);
|
||||||
|
kvm_get_one_reg(cs, KVM_REG_PPC_TM_LR, &env->tm_lr);
|
||||||
|
kvm_get_one_reg(cs, KVM_REG_PPC_TM_CTR, &env->tm_ctr);
|
||||||
|
kvm_get_one_reg(cs, KVM_REG_PPC_TM_FPSCR, &env->tm_fpscr);
|
||||||
|
kvm_get_one_reg(cs, KVM_REG_PPC_TM_AMR, &env->tm_amr);
|
||||||
|
kvm_get_one_reg(cs, KVM_REG_PPC_TM_PPR, &env->tm_ppr);
|
||||||
|
kvm_get_one_reg(cs, KVM_REG_PPC_TM_VRSAVE, &env->tm_vrsave);
|
||||||
|
kvm_get_one_reg(cs, KVM_REG_PPC_TM_VSCR, &env->tm_vscr);
|
||||||
|
kvm_get_one_reg(cs, KVM_REG_PPC_TM_DSCR, &env->tm_dscr);
|
||||||
|
kvm_get_one_reg(cs, KVM_REG_PPC_TM_TAR, &env->tm_tar);
|
||||||
|
}
|
||||||
|
|
||||||
if (cap_papr) {
|
if (cap_papr) {
|
||||||
if (kvm_get_vpa(cs) < 0) {
|
if (kvm_get_vpa(cs) < 0) {
|
||||||
DPRINTF("Warning: Unable to get VPA information from KVM\n");
|
DPRINTF("Warning: Unable to get VPA information from KVM\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kvm_get_one_reg(cs, KVM_REG_PPC_TB_OFFSET, &env->tb_env->tb_offset);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1476,18 +1525,18 @@ int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fallback to always fail hypercalls:
|
* Fallback to always fail hypercalls regardless of endianness:
|
||||||
*
|
*
|
||||||
|
* tdi 0,r0,72 (becomes b .+8 in wrong endian, nop in good endian)
|
||||||
* li r3, -1
|
* li r3, -1
|
||||||
* nop
|
* b .+8 (becomes nop in wrong endian)
|
||||||
* nop
|
* bswap32(li r3, -1)
|
||||||
* nop
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
hc[0] = 0x3860ffff;
|
hc[0] = cpu_to_be32(0x08000048);
|
||||||
hc[1] = 0x60000000;
|
hc[1] = cpu_to_be32(0x3860ffff);
|
||||||
hc[2] = 0x60000000;
|
hc[2] = cpu_to_be32(0x48000008);
|
||||||
hc[3] = 0x60000000;
|
hc[3] = cpu_to_be32(bswap32(0x3860ffff));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1507,6 +1556,11 @@ void kvmppc_set_papr(PowerPCCPU *cpu)
|
||||||
cap_papr = 1;
|
cap_papr = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version)
|
||||||
|
{
|
||||||
|
return kvm_set_one_reg(CPU(cpu), KVM_REG_PPC_ARCH_COMPAT, &cpu_version);
|
||||||
|
}
|
||||||
|
|
||||||
void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy)
|
void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy)
|
||||||
{
|
{
|
||||||
CPUState *cs = CPU(cpu);
|
CPUState *cs = CPU(cpu);
|
||||||
|
@ -1601,6 +1655,11 @@ uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool kvmppc_spapr_use_multitce(void)
|
||||||
|
{
|
||||||
|
return cap_spapr_multitce;
|
||||||
|
}
|
||||||
|
|
||||||
void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd)
|
void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd)
|
||||||
{
|
{
|
||||||
struct kvm_create_spapr_tce args = {
|
struct kvm_create_spapr_tce args = {
|
||||||
|
@ -1641,7 +1700,7 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd)
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
int kvmppc_remove_spapr_tce(void *table, int fd, uint32_t window_size)
|
int kvmppc_remove_spapr_tce(void *table, int fd, uint32_t nb_table)
|
||||||
{
|
{
|
||||||
long len;
|
long len;
|
||||||
|
|
||||||
|
@ -1649,7 +1708,7 @@ int kvmppc_remove_spapr_tce(void *table, int fd, uint32_t window_size)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = (window_size / SPAPR_TCE_PAGE_SIZE)*sizeof(uint64_t);
|
len = nb_table * sizeof(uint64_t);
|
||||||
if ((munmap(table, len) < 0) ||
|
if ((munmap(table, len) < 0) ||
|
||||||
(close(fd) < 0)) {
|
(close(fd) < 0)) {
|
||||||
fprintf(stderr, "KVM: Unexpected error removing TCE table: %s",
|
fprintf(stderr, "KVM: Unexpected error removing TCE table: %s",
|
||||||
|
@ -1761,6 +1820,23 @@ bool kvmppc_has_cap_htab_fd(void)
|
||||||
return cap_htab_fd;
|
return cap_htab_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool kvmppc_has_cap_fixup_hcalls(void)
|
||||||
|
{
|
||||||
|
return cap_fixup_hcalls;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PowerPCCPUClass *ppc_cpu_get_family_class(PowerPCCPUClass *pcc)
|
||||||
|
{
|
||||||
|
ObjectClass *oc = OBJECT_CLASS(pcc);
|
||||||
|
|
||||||
|
while (oc && !object_class_is_abstract(oc)) {
|
||||||
|
oc = object_class_get_parent(oc);
|
||||||
|
}
|
||||||
|
assert(oc);
|
||||||
|
|
||||||
|
return POWERPC_CPU_CLASS(oc);
|
||||||
|
}
|
||||||
|
|
||||||
static int kvm_ppc_register_host_cpu_type(void)
|
static int kvm_ppc_register_host_cpu_type(void)
|
||||||
{
|
{
|
||||||
TypeInfo type_info = {
|
TypeInfo type_info = {
|
||||||
|
@ -1770,6 +1846,7 @@ static int kvm_ppc_register_host_cpu_type(void)
|
||||||
};
|
};
|
||||||
uint32_t host_pvr = mfpvr();
|
uint32_t host_pvr = mfpvr();
|
||||||
PowerPCCPUClass *pvr_pcc;
|
PowerPCCPUClass *pvr_pcc;
|
||||||
|
DeviceClass *dc;
|
||||||
|
|
||||||
pvr_pcc = ppc_cpu_class_by_pvr(host_pvr);
|
pvr_pcc = ppc_cpu_class_by_pvr(host_pvr);
|
||||||
if (pvr_pcc == NULL) {
|
if (pvr_pcc == NULL) {
|
||||||
|
@ -1780,6 +1857,14 @@ static int kvm_ppc_register_host_cpu_type(void)
|
||||||
}
|
}
|
||||||
type_info.parent = object_class_get_name(OBJECT_CLASS(pvr_pcc));
|
type_info.parent = object_class_get_name(OBJECT_CLASS(pvr_pcc));
|
||||||
type_register(&type_info);
|
type_register(&type_info);
|
||||||
|
|
||||||
|
/* Register generic family CPU class for a family */
|
||||||
|
pvr_pcc = ppc_cpu_get_family_class(pvr_pcc);
|
||||||
|
dc = DEVICE_CLASS(pvr_pcc);
|
||||||
|
type_info.parent = object_class_get_name(OBJECT_CLASS(pvr_pcc));
|
||||||
|
type_info.name = g_strdup_printf("%s-"TYPE_POWERPC_CPU, dc->desc);
|
||||||
|
type_register(&type_info);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ int kvmppc_get_hasidle(CPUPPCState *env);
|
||||||
int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len);
|
int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len);
|
||||||
int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level);
|
int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level);
|
||||||
void kvmppc_set_papr(PowerPCCPU *cpu);
|
void kvmppc_set_papr(PowerPCCPU *cpu);
|
||||||
|
int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version);
|
||||||
void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy);
|
void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy);
|
||||||
int kvmppc_smt_threads(void);
|
int kvmppc_smt_threads(void);
|
||||||
int kvmppc_clear_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits);
|
int kvmppc_clear_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits);
|
||||||
|
@ -31,6 +32,7 @@ int kvmppc_set_tcr(PowerPCCPU *cpu);
|
||||||
int kvmppc_booke_watchdog_enable(PowerPCCPU *cpu);
|
int kvmppc_booke_watchdog_enable(PowerPCCPU *cpu);
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem);
|
off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem);
|
||||||
|
bool kvmppc_spapr_use_multitce(void);
|
||||||
void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd);
|
void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd);
|
||||||
int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size);
|
int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size);
|
||||||
int kvmppc_reset_htab(int shift_hint);
|
int kvmppc_reset_htab(int shift_hint);
|
||||||
|
@ -48,6 +50,7 @@ void kvmppc_hash64_free_pteg(uint64_t token);
|
||||||
|
|
||||||
void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index,
|
void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index,
|
||||||
target_ulong pte0, target_ulong pte1);
|
target_ulong pte0, target_ulong pte1);
|
||||||
|
bool kvmppc_has_cap_fixup_hcalls(void);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
@ -95,6 +98,11 @@ static inline void kvmppc_set_papr(PowerPCCPU *cpu)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy)
|
static inline void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -130,6 +138,11 @@ static inline off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool kvmppc_spapr_use_multitce(void)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void *kvmppc_create_spapr_tce(uint32_t liobn,
|
static inline void *kvmppc_create_spapr_tce(uint32_t liobn,
|
||||||
uint32_t window_size, int *fd)
|
uint32_t window_size, int *fd)
|
||||||
{
|
{
|
||||||
|
@ -137,7 +150,7 @@ static inline void *kvmppc_create_spapr_tce(uint32_t liobn,
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int kvmppc_remove_spapr_tce(void *table, int pfd,
|
static inline int kvmppc_remove_spapr_tce(void *table, int pfd,
|
||||||
uint32_t window_size)
|
uint32_t nb_table)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -211,6 +224,11 @@ static inline void kvmppc_hash64_write_pte(CPUPPCState *env,
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool kvmppc_has_cap_fixup_hcalls(void)
|
||||||
|
{
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef CONFIG_KVM
|
#ifndef CONFIG_KVM
|
||||||
|
|
|
@ -160,6 +160,11 @@ static int cpu_post_load(void *opaque, int version_id)
|
||||||
CPUPPCState *env = &cpu->env;
|
CPUPPCState *env = &cpu->env;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We always ignore the source PVR. The user or management
|
||||||
|
* software has to take care of running QEMU in a compatible mode.
|
||||||
|
*/
|
||||||
|
env->spr[SPR_PVR] = env->spr_cb[SPR_PVR].default_value;
|
||||||
env->lr = env->spr[SPR_LR];
|
env->lr = env->spr[SPR_LR];
|
||||||
env->ctr = env->spr[SPR_CTR];
|
env->ctr = env->spr[SPR_CTR];
|
||||||
env->xer = env->spr[SPR_XER];
|
env->xer = env->spr[SPR_XER];
|
||||||
|
@ -244,6 +249,38 @@ static const VMStateDescription vmstate_vsx = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef TARGET_PPC64
|
||||||
|
/* Transactional memory state */
|
||||||
|
static bool tm_needed(void *opaque)
|
||||||
|
{
|
||||||
|
PowerPCCPU *cpu = opaque;
|
||||||
|
CPUPPCState *env = &cpu->env;
|
||||||
|
return msr_ts;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_tm = {
|
||||||
|
.name = "cpu/tm",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.minimum_version_id_old = 1,
|
||||||
|
.fields = (VMStateField []) {
|
||||||
|
VMSTATE_UINTTL_ARRAY(env.tm_gpr, PowerPCCPU, 32),
|
||||||
|
VMSTATE_AVR_ARRAY(env.tm_vsr, PowerPCCPU, 64),
|
||||||
|
VMSTATE_UINT64(env.tm_cr, PowerPCCPU),
|
||||||
|
VMSTATE_UINT64(env.tm_lr, PowerPCCPU),
|
||||||
|
VMSTATE_UINT64(env.tm_ctr, PowerPCCPU),
|
||||||
|
VMSTATE_UINT64(env.tm_fpscr, PowerPCCPU),
|
||||||
|
VMSTATE_UINT64(env.tm_amr, PowerPCCPU),
|
||||||
|
VMSTATE_UINT64(env.tm_ppr, PowerPCCPU),
|
||||||
|
VMSTATE_UINT64(env.tm_vrsave, PowerPCCPU),
|
||||||
|
VMSTATE_UINT32(env.tm_vscr, PowerPCCPU),
|
||||||
|
VMSTATE_UINT64(env.tm_dscr, PowerPCCPU),
|
||||||
|
VMSTATE_UINT64(env.tm_tar, PowerPCCPU),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
static bool sr_needed(void *opaque)
|
static bool sr_needed(void *opaque)
|
||||||
{
|
{
|
||||||
#ifdef TARGET_PPC64
|
#ifdef TARGET_PPC64
|
||||||
|
@ -459,8 +496,7 @@ const VMStateDescription vmstate_ppc_cpu = {
|
||||||
.pre_save = cpu_pre_save,
|
.pre_save = cpu_pre_save,
|
||||||
.post_load = cpu_post_load,
|
.post_load = cpu_post_load,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
/* Verify we haven't changed the pvr */
|
VMSTATE_UNUSED(sizeof(target_ulong)), /* was _EQUAL(env.spr[SPR_PVR]) */
|
||||||
VMSTATE_UINTTL_EQUAL(env.spr[SPR_PVR], PowerPCCPU),
|
|
||||||
|
|
||||||
/* User mode architected state */
|
/* User mode architected state */
|
||||||
VMSTATE_UINTTL_ARRAY(env.gpr, PowerPCCPU, 32),
|
VMSTATE_UINTTL_ARRAY(env.gpr, PowerPCCPU, 32),
|
||||||
|
@ -506,6 +542,9 @@ const VMStateDescription vmstate_ppc_cpu = {
|
||||||
.needed = sr_needed,
|
.needed = sr_needed,
|
||||||
} , {
|
} , {
|
||||||
#ifdef TARGET_PPC64
|
#ifdef TARGET_PPC64
|
||||||
|
.vmsd = &vmstate_tm,
|
||||||
|
.needed = tm_needed,
|
||||||
|
} , {
|
||||||
.vmsd = &vmstate_slb,
|
.vmsd = &vmstate_slb,
|
||||||
.needed = slb_needed,
|
.needed = slb_needed,
|
||||||
} , {
|
} , {
|
||||||
|
|
|
@ -25,6 +25,15 @@
|
||||||
|
|
||||||
//#define DEBUG_OP
|
//#define DEBUG_OP
|
||||||
|
|
||||||
|
static inline bool needs_byteswap(const CPUPPCState *env)
|
||||||
|
{
|
||||||
|
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||||
|
return msr_le;
|
||||||
|
#else
|
||||||
|
return !msr_le;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Memory load and stores */
|
/* Memory load and stores */
|
||||||
|
|
||||||
|
@ -44,7 +53,7 @@ static inline target_ulong addr_add(CPUPPCState *env, target_ulong addr,
|
||||||
void helper_lmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
|
void helper_lmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
|
||||||
{
|
{
|
||||||
for (; reg < 32; reg++) {
|
for (; reg < 32; reg++) {
|
||||||
if (msr_le) {
|
if (needs_byteswap(env)) {
|
||||||
env->gpr[reg] = bswap32(cpu_ldl_data(env, addr));
|
env->gpr[reg] = bswap32(cpu_ldl_data(env, addr));
|
||||||
} else {
|
} else {
|
||||||
env->gpr[reg] = cpu_ldl_data(env, addr);
|
env->gpr[reg] = cpu_ldl_data(env, addr);
|
||||||
|
@ -56,7 +65,7 @@ void helper_lmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
|
||||||
void helper_stmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
|
void helper_stmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
|
||||||
{
|
{
|
||||||
for (; reg < 32; reg++) {
|
for (; reg < 32; reg++) {
|
||||||
if (msr_le) {
|
if (needs_byteswap(env)) {
|
||||||
cpu_stl_data(env, addr, bswap32((uint32_t)env->gpr[reg]));
|
cpu_stl_data(env, addr, bswap32((uint32_t)env->gpr[reg]));
|
||||||
} else {
|
} else {
|
||||||
cpu_stl_data(env, addr, (uint32_t)env->gpr[reg]);
|
cpu_stl_data(env, addr, (uint32_t)env->gpr[reg]);
|
||||||
|
@ -199,6 +208,11 @@ target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg,
|
||||||
#define LO_IDX 0
|
#define LO_IDX 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* We use msr_le to determine index ordering in a vector. However,
|
||||||
|
byteswapping is not simply controlled by msr_le. We also need to take
|
||||||
|
into account endianness of the target. This is done for the little-endian
|
||||||
|
PPC64 user-mode target. */
|
||||||
|
|
||||||
#define LVE(name, access, swap, element) \
|
#define LVE(name, access, swap, element) \
|
||||||
void helper_##name(CPUPPCState *env, ppc_avr_t *r, \
|
void helper_##name(CPUPPCState *env, ppc_avr_t *r, \
|
||||||
target_ulong addr) \
|
target_ulong addr) \
|
||||||
|
@ -207,9 +221,11 @@ target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg,
|
||||||
int adjust = HI_IDX*(n_elems - 1); \
|
int adjust = HI_IDX*(n_elems - 1); \
|
||||||
int sh = sizeof(r->element[0]) >> 1; \
|
int sh = sizeof(r->element[0]) >> 1; \
|
||||||
int index = (addr & 0xf) >> sh; \
|
int index = (addr & 0xf) >> sh; \
|
||||||
\
|
|
||||||
if (msr_le) { \
|
if (msr_le) { \
|
||||||
index = n_elems - index - 1; \
|
index = n_elems - index - 1; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
if (needs_byteswap(env)) { \
|
||||||
r->element[LO_IDX ? index : (adjust - index)] = \
|
r->element[LO_IDX ? index : (adjust - index)] = \
|
||||||
swap(access(env, addr)); \
|
swap(access(env, addr)); \
|
||||||
} else { \
|
} else { \
|
||||||
|
@ -232,9 +248,11 @@ LVE(lvewx, cpu_ldl_data, bswap32, u32)
|
||||||
int adjust = HI_IDX * (n_elems - 1); \
|
int adjust = HI_IDX * (n_elems - 1); \
|
||||||
int sh = sizeof(r->element[0]) >> 1; \
|
int sh = sizeof(r->element[0]) >> 1; \
|
||||||
int index = (addr & 0xf) >> sh; \
|
int index = (addr & 0xf) >> sh; \
|
||||||
\
|
|
||||||
if (msr_le) { \
|
if (msr_le) { \
|
||||||
index = n_elems - index - 1; \
|
index = n_elems - index - 1; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
if (needs_byteswap(env)) { \
|
||||||
access(env, addr, swap(r->element[LO_IDX ? index : \
|
access(env, addr, swap(r->element[LO_IDX ? index : \
|
||||||
(adjust - index)])); \
|
(adjust - index)])); \
|
||||||
} else { \
|
} else { \
|
||||||
|
|
|
@ -34,6 +34,45 @@ void helper_store_dump_spr(CPUPPCState *env, uint32_t sprn)
|
||||||
qemu_log("Write SPR %d %03x <= " TARGET_FMT_lx "\n", sprn, sprn,
|
qemu_log("Write SPR %d %03x <= " TARGET_FMT_lx "\n", sprn, sprn,
|
||||||
env->spr[sprn]);
|
env->spr[sprn]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TARGET_PPC64
|
||||||
|
static void raise_fu_exception(CPUPPCState *env, uint32_t bit,
|
||||||
|
uint32_t sprn, uint32_t cause)
|
||||||
|
{
|
||||||
|
qemu_log("Facility SPR %d is unavailable (SPR FSCR:%d)\n", sprn, bit);
|
||||||
|
|
||||||
|
env->spr[SPR_FSCR] &= ~((target_ulong)FSCR_IC_MASK << FSCR_IC_POS);
|
||||||
|
cause &= FSCR_IC_MASK;
|
||||||
|
env->spr[SPR_FSCR] |= (target_ulong)cause << FSCR_IC_POS;
|
||||||
|
|
||||||
|
helper_raise_exception_err(env, POWERPC_EXCP_FU, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void helper_fscr_facility_check(CPUPPCState *env, uint32_t bit,
|
||||||
|
uint32_t sprn, uint32_t cause)
|
||||||
|
{
|
||||||
|
#ifdef TARGET_PPC64
|
||||||
|
if (env->spr[SPR_FSCR] & (1ULL << bit)) {
|
||||||
|
/* Facility is enabled, continue */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
raise_fu_exception(env, bit, sprn, cause);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void helper_msr_facility_check(CPUPPCState *env, uint32_t bit,
|
||||||
|
uint32_t sprn, uint32_t cause)
|
||||||
|
{
|
||||||
|
#ifdef TARGET_PPC64
|
||||||
|
if (env->msr & (1ULL << bit)) {
|
||||||
|
/* Facility is enabled, continue */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
raise_fu_exception(env, bit, sprn, cause);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
|
|
||||||
void helper_store_sdr1(CPUPPCState *env, target_ulong val)
|
void helper_store_sdr1(CPUPPCState *env, target_ulong val)
|
||||||
|
|
|
@ -903,6 +903,11 @@ static int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
|
||||||
target_ulong mask;
|
target_ulong mask;
|
||||||
uint32_t tlb_pid;
|
uint32_t tlb_pid;
|
||||||
|
|
||||||
|
if (!msr_cm) {
|
||||||
|
/* In 32bit mode we can only address 32bit EAs */
|
||||||
|
address = (uint32_t)address;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check valid flag */
|
/* Check valid flag */
|
||||||
if (!(tlb->mas1 & MAS1_VALID)) {
|
if (!(tlb->mas1 & MAS1_VALID)) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -2886,7 +2891,7 @@ void helper_booke206_tlbilx3(CPUPPCState *env, target_ulong address)
|
||||||
tlb_flush(CPU(cpu), 1);
|
tlb_flush(CPU(cpu), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_booke206_tlbflush(CPUPPCState *env, uint32_t type)
|
void helper_booke206_tlbflush(CPUPPCState *env, target_ulong type)
|
||||||
{
|
{
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
13
trace-events
13
trace-events
|
@ -1189,12 +1189,25 @@ xics_ics_write_xive(int nr, int srcno, int server, uint8_t priority) "ics_write_
|
||||||
xics_ics_reject(int nr, int srcno) "reject irq %#x [src %d]"
|
xics_ics_reject(int nr, int srcno) "reject irq %#x [src %d]"
|
||||||
xics_ics_eoi(int nr) "ics_eoi: irq %#x"
|
xics_ics_eoi(int nr) "ics_eoi: irq %#x"
|
||||||
|
|
||||||
|
# hw/ppc/spapr.c
|
||||||
|
spapr_cas_failed(unsigned long n) "DT diff buffer is too small: %ld bytes"
|
||||||
|
spapr_cas_continue(unsigned long n) "Copy changes to the guest: %ld bytes"
|
||||||
|
|
||||||
|
# hw/ppc/spapr_hcall.c
|
||||||
|
spapr_cas_pvr_try(uint32_t pvr) "%x"
|
||||||
|
spapr_cas_pvr(uint32_t cur_pvr, bool cpu_match, uint32_t new_pvr, uint64_t pcr) "current=%x, cpu_match=%u, new=%x, compat flags=%"PRIx64
|
||||||
|
|
||||||
# hw/ppc/spapr_iommu.c
|
# hw/ppc/spapr_iommu.c
|
||||||
spapr_iommu_put(uint64_t liobn, uint64_t ioba, uint64_t tce, uint64_t ret) "liobn=%"PRIx64" ioba=0x%"PRIx64" tce=0x%"PRIx64" ret=%"PRId64
|
spapr_iommu_put(uint64_t liobn, uint64_t ioba, uint64_t tce, uint64_t ret) "liobn=%"PRIx64" ioba=0x%"PRIx64" tce=0x%"PRIx64" ret=%"PRId64
|
||||||
spapr_iommu_get(uint64_t liobn, uint64_t ioba, uint64_t ret, uint64_t tce) "liobn=%"PRIx64" ioba=0x%"PRIx64" ret=%"PRId64" tce=0x%"PRIx64
|
spapr_iommu_get(uint64_t liobn, uint64_t ioba, uint64_t ret, uint64_t tce) "liobn=%"PRIx64" ioba=0x%"PRIx64" ret=%"PRId64" tce=0x%"PRIx64
|
||||||
|
spapr_iommu_indirect(uint64_t liobn, uint64_t ioba, uint64_t tce, uint64_t iobaN, uint64_t tceN, uint64_t ret) "liobn=%"PRIx64" ioba=0x%"PRIx64" tcelist=0x%"PRIx64" iobaN=0x%"PRIx64" tceN=0x%"PRIx64" ret=%"PRId64
|
||||||
|
spapr_iommu_stuff(uint64_t liobn, uint64_t ioba, uint64_t tce_value, uint64_t npages, uint64_t ret) "liobn=%"PRIx64" ioba=0x%"PRIx64" tcevalue=0x%"PRIx64" npages=%"PRId64" ret=%"PRId64
|
||||||
spapr_iommu_xlate(uint64_t liobn, uint64_t ioba, uint64_t tce, unsigned perm, unsigned pgsize) "liobn=%"PRIx64" 0x%"PRIx64" -> 0x%"PRIx64" perm=%u mask=%x"
|
spapr_iommu_xlate(uint64_t liobn, uint64_t ioba, uint64_t tce, unsigned perm, unsigned pgsize) "liobn=%"PRIx64" 0x%"PRIx64" -> 0x%"PRIx64" perm=%u mask=%x"
|
||||||
spapr_iommu_new_table(uint64_t liobn, void *tcet, void *table, int fd) "liobn=%"PRIx64" tcet=%p table=%p fd=%d"
|
spapr_iommu_new_table(uint64_t liobn, void *tcet, void *table, int fd) "liobn=%"PRIx64" tcet=%p table=%p fd=%d"
|
||||||
|
|
||||||
|
# hw/ppc/ppc.c
|
||||||
|
ppc_tb_adjust(uint64_t offs1, uint64_t offs2, int64_t diff, int64_t seconds) "adjusted from 0x%"PRIx64" to 0x%"PRIx64", diff %"PRId64" (%"PRId64"s)"
|
||||||
|
|
||||||
# util/hbitmap.c
|
# util/hbitmap.c
|
||||||
hbitmap_iter_skip_words(const void *hb, void *hbi, uint64_t pos, unsigned long cur) "hb %p hbi %p pos %"PRId64" cur 0x%lx"
|
hbitmap_iter_skip_words(const void *hb, void *hbi, uint64_t pos, unsigned long cur) "hb %p hbi %p pos %"PRId64" cur 0x%lx"
|
||||||
hbitmap_reset(void *hb, uint64_t start, uint64_t count, uint64_t sbit, uint64_t ebit) "hb %p items %"PRIu64",%"PRIu64" bits %"PRIu64"..%"PRIu64
|
hbitmap_reset(void *hb, uint64_t start, uint64_t count, uint64_t sbit, uint64_t ebit) "hb %p items %"PRIu64",%"PRIu64" bits %"PRIu64"..%"PRIu64
|
||||||
|
|
343
util/aes.c
343
util/aes.c
|
@ -38,6 +38,349 @@ typedef uint8_t u8;
|
||||||
# define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3]))
|
# define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3]))
|
||||||
# define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); }
|
# define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); }
|
||||||
|
|
||||||
|
const uint8_t AES_sbox[256] = {
|
||||||
|
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5,
|
||||||
|
0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
|
||||||
|
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0,
|
||||||
|
0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
|
||||||
|
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC,
|
||||||
|
0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
|
||||||
|
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A,
|
||||||
|
0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
|
||||||
|
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0,
|
||||||
|
0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
|
||||||
|
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B,
|
||||||
|
0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
|
||||||
|
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85,
|
||||||
|
0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
|
||||||
|
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5,
|
||||||
|
0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
|
||||||
|
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17,
|
||||||
|
0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
|
||||||
|
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88,
|
||||||
|
0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
|
||||||
|
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C,
|
||||||
|
0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
|
||||||
|
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9,
|
||||||
|
0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
|
||||||
|
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6,
|
||||||
|
0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
|
||||||
|
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E,
|
||||||
|
0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
|
||||||
|
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94,
|
||||||
|
0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
|
||||||
|
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68,
|
||||||
|
0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16,
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t AES_isbox[256] = {
|
||||||
|
0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38,
|
||||||
|
0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
|
||||||
|
0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87,
|
||||||
|
0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
|
||||||
|
0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D,
|
||||||
|
0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
|
||||||
|
0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2,
|
||||||
|
0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
|
||||||
|
0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16,
|
||||||
|
0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
|
||||||
|
0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA,
|
||||||
|
0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
|
||||||
|
0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A,
|
||||||
|
0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
|
||||||
|
0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02,
|
||||||
|
0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
|
||||||
|
0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA,
|
||||||
|
0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
|
||||||
|
0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85,
|
||||||
|
0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
|
||||||
|
0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89,
|
||||||
|
0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
|
||||||
|
0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20,
|
||||||
|
0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
|
||||||
|
0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31,
|
||||||
|
0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
|
||||||
|
0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D,
|
||||||
|
0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
|
||||||
|
0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0,
|
||||||
|
0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
|
||||||
|
0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26,
|
||||||
|
0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D,
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t AES_shifts[16] = {
|
||||||
|
0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t AES_ishifts[16] = {
|
||||||
|
0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 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]; */
|
||||||
|
const uint32_t AES_imc[256][4] = {
|
||||||
|
{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, /* x=00 */
|
||||||
|
{ 0x0E090D0B, 0x0B0E090D, 0x0D0B0E09, 0x090D0B0E, }, /* x=01 */
|
||||||
|
{ 0x1C121A16, 0x161C121A, 0x1A161C12, 0x121A161C, }, /* x=02 */
|
||||||
|
{ 0x121B171D, 0x1D121B17, 0x171D121B, 0x1B171D12, }, /* x=03 */
|
||||||
|
{ 0x3824342C, 0x2C382434, 0x342C3824, 0x24342C38, }, /* x=04 */
|
||||||
|
{ 0x362D3927, 0x27362D39, 0x3927362D, 0x2D392736, }, /* x=05 */
|
||||||
|
{ 0x24362E3A, 0x3A24362E, 0x2E3A2436, 0x362E3A24, }, /* x=06 */
|
||||||
|
{ 0x2A3F2331, 0x312A3F23, 0x23312A3F, 0x3F23312A, }, /* x=07 */
|
||||||
|
{ 0x70486858, 0x58704868, 0x68587048, 0x48685870, }, /* x=08 */
|
||||||
|
{ 0x7E416553, 0x537E4165, 0x65537E41, 0x4165537E, }, /* x=09 */
|
||||||
|
{ 0x6C5A724E, 0x4E6C5A72, 0x724E6C5A, 0x5A724E6C, }, /* x=0A */
|
||||||
|
{ 0x62537F45, 0x4562537F, 0x7F456253, 0x537F4562, }, /* x=0B */
|
||||||
|
{ 0x486C5C74, 0x74486C5C, 0x5C74486C, 0x6C5C7448, }, /* x=0C */
|
||||||
|
{ 0x4665517F, 0x7F466551, 0x517F4665, 0x65517F46, }, /* x=0D */
|
||||||
|
{ 0x547E4662, 0x62547E46, 0x4662547E, 0x7E466254, }, /* x=0E */
|
||||||
|
{ 0x5A774B69, 0x695A774B, 0x4B695A77, 0x774B695A, }, /* x=0F */
|
||||||
|
{ 0xE090D0B0, 0xB0E090D0, 0xD0B0E090, 0x90D0B0E0, }, /* x=10 */
|
||||||
|
{ 0xEE99DDBB, 0xBBEE99DD, 0xDDBBEE99, 0x99DDBBEE, }, /* x=11 */
|
||||||
|
{ 0xFC82CAA6, 0xA6FC82CA, 0xCAA6FC82, 0x82CAA6FC, }, /* x=12 */
|
||||||
|
{ 0xF28BC7AD, 0xADF28BC7, 0xC7ADF28B, 0x8BC7ADF2, }, /* x=13 */
|
||||||
|
{ 0xD8B4E49C, 0x9CD8B4E4, 0xE49CD8B4, 0xB4E49CD8, }, /* x=14 */
|
||||||
|
{ 0xD6BDE997, 0x97D6BDE9, 0xE997D6BD, 0xBDE997D6, }, /* x=15 */
|
||||||
|
{ 0xC4A6FE8A, 0x8AC4A6FE, 0xFE8AC4A6, 0xA6FE8AC4, }, /* x=16 */
|
||||||
|
{ 0xCAAFF381, 0x81CAAFF3, 0xF381CAAF, 0xAFF381CA, }, /* x=17 */
|
||||||
|
{ 0x90D8B8E8, 0xE890D8B8, 0xB8E890D8, 0xD8B8E890, }, /* x=18 */
|
||||||
|
{ 0x9ED1B5E3, 0xE39ED1B5, 0xB5E39ED1, 0xD1B5E39E, }, /* x=19 */
|
||||||
|
{ 0x8CCAA2FE, 0xFE8CCAA2, 0xA2FE8CCA, 0xCAA2FE8C, }, /* x=1A */
|
||||||
|
{ 0x82C3AFF5, 0xF582C3AF, 0xAFF582C3, 0xC3AFF582, }, /* x=1B */
|
||||||
|
{ 0xA8FC8CC4, 0xC4A8FC8C, 0x8CC4A8FC, 0xFC8CC4A8, }, /* x=1C */
|
||||||
|
{ 0xA6F581CF, 0xCFA6F581, 0x81CFA6F5, 0xF581CFA6, }, /* x=1D */
|
||||||
|
{ 0xB4EE96D2, 0xD2B4EE96, 0x96D2B4EE, 0xEE96D2B4, }, /* x=1E */
|
||||||
|
{ 0xBAE79BD9, 0xD9BAE79B, 0x9BD9BAE7, 0xE79BD9BA, }, /* x=1F */
|
||||||
|
{ 0xDB3BBB7B, 0x7BDB3BBB, 0xBB7BDB3B, 0x3BBB7BDB, }, /* x=20 */
|
||||||
|
{ 0xD532B670, 0x70D532B6, 0xB670D532, 0x32B670D5, }, /* x=21 */
|
||||||
|
{ 0xC729A16D, 0x6DC729A1, 0xA16DC729, 0x29A16DC7, }, /* x=22 */
|
||||||
|
{ 0xC920AC66, 0x66C920AC, 0xAC66C920, 0x20AC66C9, }, /* x=23 */
|
||||||
|
{ 0xE31F8F57, 0x57E31F8F, 0x8F57E31F, 0x1F8F57E3, }, /* x=24 */
|
||||||
|
{ 0xED16825C, 0x5CED1682, 0x825CED16, 0x16825CED, }, /* x=25 */
|
||||||
|
{ 0xFF0D9541, 0x41FF0D95, 0x9541FF0D, 0x0D9541FF, }, /* x=26 */
|
||||||
|
{ 0xF104984A, 0x4AF10498, 0x984AF104, 0x04984AF1, }, /* x=27 */
|
||||||
|
{ 0xAB73D323, 0x23AB73D3, 0xD323AB73, 0x73D323AB, }, /* x=28 */
|
||||||
|
{ 0xA57ADE28, 0x28A57ADE, 0xDE28A57A, 0x7ADE28A5, }, /* x=29 */
|
||||||
|
{ 0xB761C935, 0x35B761C9, 0xC935B761, 0x61C935B7, }, /* x=2A */
|
||||||
|
{ 0xB968C43E, 0x3EB968C4, 0xC43EB968, 0x68C43EB9, }, /* x=2B */
|
||||||
|
{ 0x9357E70F, 0x0F9357E7, 0xE70F9357, 0x57E70F93, }, /* x=2C */
|
||||||
|
{ 0x9D5EEA04, 0x049D5EEA, 0xEA049D5E, 0x5EEA049D, }, /* x=2D */
|
||||||
|
{ 0x8F45FD19, 0x198F45FD, 0xFD198F45, 0x45FD198F, }, /* x=2E */
|
||||||
|
{ 0x814CF012, 0x12814CF0, 0xF012814C, 0x4CF01281, }, /* x=2F */
|
||||||
|
{ 0x3BAB6BCB, 0xCB3BAB6B, 0x6BCB3BAB, 0xAB6BCB3B, }, /* x=30 */
|
||||||
|
{ 0x35A266C0, 0xC035A266, 0x66C035A2, 0xA266C035, }, /* x=31 */
|
||||||
|
{ 0x27B971DD, 0xDD27B971, 0x71DD27B9, 0xB971DD27, }, /* x=32 */
|
||||||
|
{ 0x29B07CD6, 0xD629B07C, 0x7CD629B0, 0xB07CD629, }, /* x=33 */
|
||||||
|
{ 0x038F5FE7, 0xE7038F5F, 0x5FE7038F, 0x8F5FE703, }, /* x=34 */
|
||||||
|
{ 0x0D8652EC, 0xEC0D8652, 0x52EC0D86, 0x8652EC0D, }, /* x=35 */
|
||||||
|
{ 0x1F9D45F1, 0xF11F9D45, 0x45F11F9D, 0x9D45F11F, }, /* x=36 */
|
||||||
|
{ 0x119448FA, 0xFA119448, 0x48FA1194, 0x9448FA11, }, /* x=37 */
|
||||||
|
{ 0x4BE30393, 0x934BE303, 0x03934BE3, 0xE303934B, }, /* x=38 */
|
||||||
|
{ 0x45EA0E98, 0x9845EA0E, 0x0E9845EA, 0xEA0E9845, }, /* x=39 */
|
||||||
|
{ 0x57F11985, 0x8557F119, 0x198557F1, 0xF1198557, }, /* x=3A */
|
||||||
|
{ 0x59F8148E, 0x8E59F814, 0x148E59F8, 0xF8148E59, }, /* x=3B */
|
||||||
|
{ 0x73C737BF, 0xBF73C737, 0x37BF73C7, 0xC737BF73, }, /* x=3C */
|
||||||
|
{ 0x7DCE3AB4, 0xB47DCE3A, 0x3AB47DCE, 0xCE3AB47D, }, /* x=3D */
|
||||||
|
{ 0x6FD52DA9, 0xA96FD52D, 0x2DA96FD5, 0xD52DA96F, }, /* x=3E */
|
||||||
|
{ 0x61DC20A2, 0xA261DC20, 0x20A261DC, 0xDC20A261, }, /* x=3F */
|
||||||
|
{ 0xAD766DF6, 0xF6AD766D, 0x6DF6AD76, 0x766DF6AD, }, /* x=40 */
|
||||||
|
{ 0xA37F60FD, 0xFDA37F60, 0x60FDA37F, 0x7F60FDA3, }, /* x=41 */
|
||||||
|
{ 0xB16477E0, 0xE0B16477, 0x77E0B164, 0x6477E0B1, }, /* x=42 */
|
||||||
|
{ 0xBF6D7AEB, 0xEBBF6D7A, 0x7AEBBF6D, 0x6D7AEBBF, }, /* x=43 */
|
||||||
|
{ 0x955259DA, 0xDA955259, 0x59DA9552, 0x5259DA95, }, /* x=44 */
|
||||||
|
{ 0x9B5B54D1, 0xD19B5B54, 0x54D19B5B, 0x5B54D19B, }, /* x=45 */
|
||||||
|
{ 0x894043CC, 0xCC894043, 0x43CC8940, 0x4043CC89, }, /* x=46 */
|
||||||
|
{ 0x87494EC7, 0xC787494E, 0x4EC78749, 0x494EC787, }, /* x=47 */
|
||||||
|
{ 0xDD3E05AE, 0xAEDD3E05, 0x05AEDD3E, 0x3E05AEDD, }, /* x=48 */
|
||||||
|
{ 0xD33708A5, 0xA5D33708, 0x08A5D337, 0x3708A5D3, }, /* x=49 */
|
||||||
|
{ 0xC12C1FB8, 0xB8C12C1F, 0x1FB8C12C, 0x2C1FB8C1, }, /* x=4A */
|
||||||
|
{ 0xCF2512B3, 0xB3CF2512, 0x12B3CF25, 0x2512B3CF, }, /* x=4B */
|
||||||
|
{ 0xE51A3182, 0x82E51A31, 0x3182E51A, 0x1A3182E5, }, /* x=4C */
|
||||||
|
{ 0xEB133C89, 0x89EB133C, 0x3C89EB13, 0x133C89EB, }, /* x=4D */
|
||||||
|
{ 0xF9082B94, 0x94F9082B, 0x2B94F908, 0x082B94F9, }, /* x=4E */
|
||||||
|
{ 0xF701269F, 0x9FF70126, 0x269FF701, 0x01269FF7, }, /* x=4F */
|
||||||
|
{ 0x4DE6BD46, 0x464DE6BD, 0xBD464DE6, 0xE6BD464D, }, /* x=50 */
|
||||||
|
{ 0x43EFB04D, 0x4D43EFB0, 0xB04D43EF, 0xEFB04D43, }, /* x=51 */
|
||||||
|
{ 0x51F4A750, 0x5051F4A7, 0xA75051F4, 0xF4A75051, }, /* x=52 */
|
||||||
|
{ 0x5FFDAA5B, 0x5B5FFDAA, 0xAA5B5FFD, 0xFDAA5B5F, }, /* x=53 */
|
||||||
|
{ 0x75C2896A, 0x6A75C289, 0x896A75C2, 0xC2896A75, }, /* x=54 */
|
||||||
|
{ 0x7BCB8461, 0x617BCB84, 0x84617BCB, 0xCB84617B, }, /* x=55 */
|
||||||
|
{ 0x69D0937C, 0x7C69D093, 0x937C69D0, 0xD0937C69, }, /* x=56 */
|
||||||
|
{ 0x67D99E77, 0x7767D99E, 0x9E7767D9, 0xD99E7767, }, /* x=57 */
|
||||||
|
{ 0x3DAED51E, 0x1E3DAED5, 0xD51E3DAE, 0xAED51E3D, }, /* x=58 */
|
||||||
|
{ 0x33A7D815, 0x1533A7D8, 0xD81533A7, 0xA7D81533, }, /* x=59 */
|
||||||
|
{ 0x21BCCF08, 0x0821BCCF, 0xCF0821BC, 0xBCCF0821, }, /* x=5A */
|
||||||
|
{ 0x2FB5C203, 0x032FB5C2, 0xC2032FB5, 0xB5C2032F, }, /* x=5B */
|
||||||
|
{ 0x058AE132, 0x32058AE1, 0xE132058A, 0x8AE13205, }, /* x=5C */
|
||||||
|
{ 0x0B83EC39, 0x390B83EC, 0xEC390B83, 0x83EC390B, }, /* x=5D */
|
||||||
|
{ 0x1998FB24, 0x241998FB, 0xFB241998, 0x98FB2419, }, /* x=5E */
|
||||||
|
{ 0x1791F62F, 0x2F1791F6, 0xF62F1791, 0x91F62F17, }, /* x=5F */
|
||||||
|
{ 0x764DD68D, 0x8D764DD6, 0xD68D764D, 0x4DD68D76, }, /* x=60 */
|
||||||
|
{ 0x7844DB86, 0x867844DB, 0xDB867844, 0x44DB8678, }, /* x=61 */
|
||||||
|
{ 0x6A5FCC9B, 0x9B6A5FCC, 0xCC9B6A5F, 0x5FCC9B6A, }, /* x=62 */
|
||||||
|
{ 0x6456C190, 0x906456C1, 0xC1906456, 0x56C19064, }, /* x=63 */
|
||||||
|
{ 0x4E69E2A1, 0xA14E69E2, 0xE2A14E69, 0x69E2A14E, }, /* x=64 */
|
||||||
|
{ 0x4060EFAA, 0xAA4060EF, 0xEFAA4060, 0x60EFAA40, }, /* x=65 */
|
||||||
|
{ 0x527BF8B7, 0xB7527BF8, 0xF8B7527B, 0x7BF8B752, }, /* x=66 */
|
||||||
|
{ 0x5C72F5BC, 0xBC5C72F5, 0xF5BC5C72, 0x72F5BC5C, }, /* x=67 */
|
||||||
|
{ 0x0605BED5, 0xD50605BE, 0xBED50605, 0x05BED506, }, /* x=68 */
|
||||||
|
{ 0x080CB3DE, 0xDE080CB3, 0xB3DE080C, 0x0CB3DE08, }, /* x=69 */
|
||||||
|
{ 0x1A17A4C3, 0xC31A17A4, 0xA4C31A17, 0x17A4C31A, }, /* x=6A */
|
||||||
|
{ 0x141EA9C8, 0xC8141EA9, 0xA9C8141E, 0x1EA9C814, }, /* x=6B */
|
||||||
|
{ 0x3E218AF9, 0xF93E218A, 0x8AF93E21, 0x218AF93E, }, /* x=6C */
|
||||||
|
{ 0x302887F2, 0xF2302887, 0x87F23028, 0x2887F230, }, /* x=6D */
|
||||||
|
{ 0x223390EF, 0xEF223390, 0x90EF2233, 0x3390EF22, }, /* x=6E */
|
||||||
|
{ 0x2C3A9DE4, 0xE42C3A9D, 0x9DE42C3A, 0x3A9DE42C, }, /* x=6F */
|
||||||
|
{ 0x96DD063D, 0x3D96DD06, 0x063D96DD, 0xDD063D96, }, /* x=70 */
|
||||||
|
{ 0x98D40B36, 0x3698D40B, 0x0B3698D4, 0xD40B3698, }, /* x=71 */
|
||||||
|
{ 0x8ACF1C2B, 0x2B8ACF1C, 0x1C2B8ACF, 0xCF1C2B8A, }, /* x=72 */
|
||||||
|
{ 0x84C61120, 0x2084C611, 0x112084C6, 0xC6112084, }, /* x=73 */
|
||||||
|
{ 0xAEF93211, 0x11AEF932, 0x3211AEF9, 0xF93211AE, }, /* x=74 */
|
||||||
|
{ 0xA0F03F1A, 0x1AA0F03F, 0x3F1AA0F0, 0xF03F1AA0, }, /* x=75 */
|
||||||
|
{ 0xB2EB2807, 0x07B2EB28, 0x2807B2EB, 0xEB2807B2, }, /* x=76 */
|
||||||
|
{ 0xBCE2250C, 0x0CBCE225, 0x250CBCE2, 0xE2250CBC, }, /* x=77 */
|
||||||
|
{ 0xE6956E65, 0x65E6956E, 0x6E65E695, 0x956E65E6, }, /* x=78 */
|
||||||
|
{ 0xE89C636E, 0x6EE89C63, 0x636EE89C, 0x9C636EE8, }, /* x=79 */
|
||||||
|
{ 0xFA877473, 0x73FA8774, 0x7473FA87, 0x877473FA, }, /* x=7A */
|
||||||
|
{ 0xF48E7978, 0x78F48E79, 0x7978F48E, 0x8E7978F4, }, /* x=7B */
|
||||||
|
{ 0xDEB15A49, 0x49DEB15A, 0x5A49DEB1, 0xB15A49DE, }, /* x=7C */
|
||||||
|
{ 0xD0B85742, 0x42D0B857, 0x5742D0B8, 0xB85742D0, }, /* x=7D */
|
||||||
|
{ 0xC2A3405F, 0x5FC2A340, 0x405FC2A3, 0xA3405FC2, }, /* x=7E */
|
||||||
|
{ 0xCCAA4D54, 0x54CCAA4D, 0x4D54CCAA, 0xAA4D54CC, }, /* x=7F */
|
||||||
|
{ 0x41ECDAF7, 0xF741ECDA, 0xDAF741EC, 0xECDAF741, }, /* x=80 */
|
||||||
|
{ 0x4FE5D7FC, 0xFC4FE5D7, 0xD7FC4FE5, 0xE5D7FC4F, }, /* x=81 */
|
||||||
|
{ 0x5DFEC0E1, 0xE15DFEC0, 0xC0E15DFE, 0xFEC0E15D, }, /* x=82 */
|
||||||
|
{ 0x53F7CDEA, 0xEA53F7CD, 0xCDEA53F7, 0xF7CDEA53, }, /* x=83 */
|
||||||
|
{ 0x79C8EEDB, 0xDB79C8EE, 0xEEDB79C8, 0xC8EEDB79, }, /* x=84 */
|
||||||
|
{ 0x77C1E3D0, 0xD077C1E3, 0xE3D077C1, 0xC1E3D077, }, /* x=85 */
|
||||||
|
{ 0x65DAF4CD, 0xCD65DAF4, 0xF4CD65DA, 0xDAF4CD65, }, /* x=86 */
|
||||||
|
{ 0x6BD3F9C6, 0xC66BD3F9, 0xF9C66BD3, 0xD3F9C66B, }, /* x=87 */
|
||||||
|
{ 0x31A4B2AF, 0xAF31A4B2, 0xB2AF31A4, 0xA4B2AF31, }, /* x=88 */
|
||||||
|
{ 0x3FADBFA4, 0xA43FADBF, 0xBFA43FAD, 0xADBFA43F, }, /* x=89 */
|
||||||
|
{ 0x2DB6A8B9, 0xB92DB6A8, 0xA8B92DB6, 0xB6A8B92D, }, /* x=8A */
|
||||||
|
{ 0x23BFA5B2, 0xB223BFA5, 0xA5B223BF, 0xBFA5B223, }, /* x=8B */
|
||||||
|
{ 0x09808683, 0x83098086, 0x86830980, 0x80868309, }, /* x=8C */
|
||||||
|
{ 0x07898B88, 0x8807898B, 0x8B880789, 0x898B8807, }, /* x=8D */
|
||||||
|
{ 0x15929C95, 0x9515929C, 0x9C951592, 0x929C9515, }, /* x=8E */
|
||||||
|
{ 0x1B9B919E, 0x9E1B9B91, 0x919E1B9B, 0x9B919E1B, }, /* x=8F */
|
||||||
|
{ 0xA17C0A47, 0x47A17C0A, 0x0A47A17C, 0x7C0A47A1, }, /* x=90 */
|
||||||
|
{ 0xAF75074C, 0x4CAF7507, 0x074CAF75, 0x75074CAF, }, /* x=91 */
|
||||||
|
{ 0xBD6E1051, 0x51BD6E10, 0x1051BD6E, 0x6E1051BD, }, /* x=92 */
|
||||||
|
{ 0xB3671D5A, 0x5AB3671D, 0x1D5AB367, 0x671D5AB3, }, /* x=93 */
|
||||||
|
{ 0x99583E6B, 0x6B99583E, 0x3E6B9958, 0x583E6B99, }, /* x=94 */
|
||||||
|
{ 0x97513360, 0x60975133, 0x33609751, 0x51336097, }, /* x=95 */
|
||||||
|
{ 0x854A247D, 0x7D854A24, 0x247D854A, 0x4A247D85, }, /* x=96 */
|
||||||
|
{ 0x8B432976, 0x768B4329, 0x29768B43, 0x4329768B, }, /* x=97 */
|
||||||
|
{ 0xD134621F, 0x1FD13462, 0x621FD134, 0x34621FD1, }, /* x=98 */
|
||||||
|
{ 0xDF3D6F14, 0x14DF3D6F, 0x6F14DF3D, 0x3D6F14DF, }, /* x=99 */
|
||||||
|
{ 0xCD267809, 0x09CD2678, 0x7809CD26, 0x267809CD, }, /* x=9A */
|
||||||
|
{ 0xC32F7502, 0x02C32F75, 0x7502C32F, 0x2F7502C3, }, /* x=9B */
|
||||||
|
{ 0xE9105633, 0x33E91056, 0x5633E910, 0x105633E9, }, /* x=9C */
|
||||||
|
{ 0xE7195B38, 0x38E7195B, 0x5B38E719, 0x195B38E7, }, /* x=9D */
|
||||||
|
{ 0xF5024C25, 0x25F5024C, 0x4C25F502, 0x024C25F5, }, /* x=9E */
|
||||||
|
{ 0xFB0B412E, 0x2EFB0B41, 0x412EFB0B, 0x0B412EFB, }, /* x=9F */
|
||||||
|
{ 0x9AD7618C, 0x8C9AD761, 0x618C9AD7, 0xD7618C9A, }, /* x=A0 */
|
||||||
|
{ 0x94DE6C87, 0x8794DE6C, 0x6C8794DE, 0xDE6C8794, }, /* x=A1 */
|
||||||
|
{ 0x86C57B9A, 0x9A86C57B, 0x7B9A86C5, 0xC57B9A86, }, /* x=A2 */
|
||||||
|
{ 0x88CC7691, 0x9188CC76, 0x769188CC, 0xCC769188, }, /* x=A3 */
|
||||||
|
{ 0xA2F355A0, 0xA0A2F355, 0x55A0A2F3, 0xF355A0A2, }, /* x=A4 */
|
||||||
|
{ 0xACFA58AB, 0xABACFA58, 0x58ABACFA, 0xFA58ABAC, }, /* x=A5 */
|
||||||
|
{ 0xBEE14FB6, 0xB6BEE14F, 0x4FB6BEE1, 0xE14FB6BE, }, /* x=A6 */
|
||||||
|
{ 0xB0E842BD, 0xBDB0E842, 0x42BDB0E8, 0xE842BDB0, }, /* x=A7 */
|
||||||
|
{ 0xEA9F09D4, 0xD4EA9F09, 0x09D4EA9F, 0x9F09D4EA, }, /* x=A8 */
|
||||||
|
{ 0xE49604DF, 0xDFE49604, 0x04DFE496, 0x9604DFE4, }, /* x=A9 */
|
||||||
|
{ 0xF68D13C2, 0xC2F68D13, 0x13C2F68D, 0x8D13C2F6, }, /* x=AA */
|
||||||
|
{ 0xF8841EC9, 0xC9F8841E, 0x1EC9F884, 0x841EC9F8, }, /* x=AB */
|
||||||
|
{ 0xD2BB3DF8, 0xF8D2BB3D, 0x3DF8D2BB, 0xBB3DF8D2, }, /* x=AC */
|
||||||
|
{ 0xDCB230F3, 0xF3DCB230, 0x30F3DCB2, 0xB230F3DC, }, /* x=AD */
|
||||||
|
{ 0xCEA927EE, 0xEECEA927, 0x27EECEA9, 0xA927EECE, }, /* x=AE */
|
||||||
|
{ 0xC0A02AE5, 0xE5C0A02A, 0x2AE5C0A0, 0xA02AE5C0, }, /* x=AF */
|
||||||
|
{ 0x7A47B13C, 0x3C7A47B1, 0xB13C7A47, 0x47B13C7A, }, /* x=B0 */
|
||||||
|
{ 0x744EBC37, 0x37744EBC, 0xBC37744E, 0x4EBC3774, }, /* x=B1 */
|
||||||
|
{ 0x6655AB2A, 0x2A6655AB, 0xAB2A6655, 0x55AB2A66, }, /* x=B2 */
|
||||||
|
{ 0x685CA621, 0x21685CA6, 0xA621685C, 0x5CA62168, }, /* x=B3 */
|
||||||
|
{ 0x42638510, 0x10426385, 0x85104263, 0x63851042, }, /* x=B4 */
|
||||||
|
{ 0x4C6A881B, 0x1B4C6A88, 0x881B4C6A, 0x6A881B4C, }, /* x=B5 */
|
||||||
|
{ 0x5E719F06, 0x065E719F, 0x9F065E71, 0x719F065E, }, /* x=B6 */
|
||||||
|
{ 0x5078920D, 0x0D507892, 0x920D5078, 0x78920D50, }, /* x=B7 */
|
||||||
|
{ 0x0A0FD964, 0x640A0FD9, 0xD9640A0F, 0x0FD9640A, }, /* x=B8 */
|
||||||
|
{ 0x0406D46F, 0x6F0406D4, 0xD46F0406, 0x06D46F04, }, /* x=B9 */
|
||||||
|
{ 0x161DC372, 0x72161DC3, 0xC372161D, 0x1DC37216, }, /* x=BA */
|
||||||
|
{ 0x1814CE79, 0x791814CE, 0xCE791814, 0x14CE7918, }, /* x=BB */
|
||||||
|
{ 0x322BED48, 0x48322BED, 0xED48322B, 0x2BED4832, }, /* x=BC */
|
||||||
|
{ 0x3C22E043, 0x433C22E0, 0xE0433C22, 0x22E0433C, }, /* x=BD */
|
||||||
|
{ 0x2E39F75E, 0x5E2E39F7, 0xF75E2E39, 0x39F75E2E, }, /* x=BE */
|
||||||
|
{ 0x2030FA55, 0x552030FA, 0xFA552030, 0x30FA5520, }, /* x=BF */
|
||||||
|
{ 0xEC9AB701, 0x01EC9AB7, 0xB701EC9A, 0x9AB701EC, }, /* x=C0 */
|
||||||
|
{ 0xE293BA0A, 0x0AE293BA, 0xBA0AE293, 0x93BA0AE2, }, /* x=C1 */
|
||||||
|
{ 0xF088AD17, 0x17F088AD, 0xAD17F088, 0x88AD17F0, }, /* x=C2 */
|
||||||
|
{ 0xFE81A01C, 0x1CFE81A0, 0xA01CFE81, 0x81A01CFE, }, /* x=C3 */
|
||||||
|
{ 0xD4BE832D, 0x2DD4BE83, 0x832DD4BE, 0xBE832DD4, }, /* x=C4 */
|
||||||
|
{ 0xDAB78E26, 0x26DAB78E, 0x8E26DAB7, 0xB78E26DA, }, /* x=C5 */
|
||||||
|
{ 0xC8AC993B, 0x3BC8AC99, 0x993BC8AC, 0xAC993BC8, }, /* x=C6 */
|
||||||
|
{ 0xC6A59430, 0x30C6A594, 0x9430C6A5, 0xA59430C6, }, /* x=C7 */
|
||||||
|
{ 0x9CD2DF59, 0x599CD2DF, 0xDF599CD2, 0xD2DF599C, }, /* x=C8 */
|
||||||
|
{ 0x92DBD252, 0x5292DBD2, 0xD25292DB, 0xDBD25292, }, /* x=C9 */
|
||||||
|
{ 0x80C0C54F, 0x4F80C0C5, 0xC54F80C0, 0xC0C54F80, }, /* x=CA */
|
||||||
|
{ 0x8EC9C844, 0x448EC9C8, 0xC8448EC9, 0xC9C8448E, }, /* x=CB */
|
||||||
|
{ 0xA4F6EB75, 0x75A4F6EB, 0xEB75A4F6, 0xF6EB75A4, }, /* x=CC */
|
||||||
|
{ 0xAAFFE67E, 0x7EAAFFE6, 0xE67EAAFF, 0xFFE67EAA, }, /* x=CD */
|
||||||
|
{ 0xB8E4F163, 0x63B8E4F1, 0xF163B8E4, 0xE4F163B8, }, /* x=CE */
|
||||||
|
{ 0xB6EDFC68, 0x68B6EDFC, 0xFC68B6ED, 0xEDFC68B6, }, /* x=CF */
|
||||||
|
{ 0x0C0A67B1, 0xB10C0A67, 0x67B10C0A, 0x0A67B10C, }, /* x=D0 */
|
||||||
|
{ 0x02036ABA, 0xBA02036A, 0x6ABA0203, 0x036ABA02, }, /* x=D1 */
|
||||||
|
{ 0x10187DA7, 0xA710187D, 0x7DA71018, 0x187DA710, }, /* x=D2 */
|
||||||
|
{ 0x1E1170AC, 0xAC1E1170, 0x70AC1E11, 0x1170AC1E, }, /* x=D3 */
|
||||||
|
{ 0x342E539D, 0x9D342E53, 0x539D342E, 0x2E539D34, }, /* x=D4 */
|
||||||
|
{ 0x3A275E96, 0x963A275E, 0x5E963A27, 0x275E963A, }, /* x=D5 */
|
||||||
|
{ 0x283C498B, 0x8B283C49, 0x498B283C, 0x3C498B28, }, /* x=D6 */
|
||||||
|
{ 0x26354480, 0x80263544, 0x44802635, 0x35448026, }, /* x=D7 */
|
||||||
|
{ 0x7C420FE9, 0xE97C420F, 0x0FE97C42, 0x420FE97C, }, /* x=D8 */
|
||||||
|
{ 0x724B02E2, 0xE2724B02, 0x02E2724B, 0x4B02E272, }, /* x=D9 */
|
||||||
|
{ 0x605015FF, 0xFF605015, 0x15FF6050, 0x5015FF60, }, /* x=DA */
|
||||||
|
{ 0x6E5918F4, 0xF46E5918, 0x18F46E59, 0x5918F46E, }, /* x=DB */
|
||||||
|
{ 0x44663BC5, 0xC544663B, 0x3BC54466, 0x663BC544, }, /* x=DC */
|
||||||
|
{ 0x4A6F36CE, 0xCE4A6F36, 0x36CE4A6F, 0x6F36CE4A, }, /* x=DD */
|
||||||
|
{ 0x587421D3, 0xD3587421, 0x21D35874, 0x7421D358, }, /* x=DE */
|
||||||
|
{ 0x567D2CD8, 0xD8567D2C, 0x2CD8567D, 0x7D2CD856, }, /* x=DF */
|
||||||
|
{ 0x37A10C7A, 0x7A37A10C, 0x0C7A37A1, 0xA10C7A37, }, /* x=E0 */
|
||||||
|
{ 0x39A80171, 0x7139A801, 0x017139A8, 0xA8017139, }, /* x=E1 */
|
||||||
|
{ 0x2BB3166C, 0x6C2BB316, 0x166C2BB3, 0xB3166C2B, }, /* x=E2 */
|
||||||
|
{ 0x25BA1B67, 0x6725BA1B, 0x1B6725BA, 0xBA1B6725, }, /* x=E3 */
|
||||||
|
{ 0x0F853856, 0x560F8538, 0x38560F85, 0x8538560F, }, /* x=E4 */
|
||||||
|
{ 0x018C355D, 0x5D018C35, 0x355D018C, 0x8C355D01, }, /* x=E5 */
|
||||||
|
{ 0x13972240, 0x40139722, 0x22401397, 0x97224013, }, /* x=E6 */
|
||||||
|
{ 0x1D9E2F4B, 0x4B1D9E2F, 0x2F4B1D9E, 0x9E2F4B1D, }, /* x=E7 */
|
||||||
|
{ 0x47E96422, 0x2247E964, 0x642247E9, 0xE9642247, }, /* x=E8 */
|
||||||
|
{ 0x49E06929, 0x2949E069, 0x692949E0, 0xE0692949, }, /* x=E9 */
|
||||||
|
{ 0x5BFB7E34, 0x345BFB7E, 0x7E345BFB, 0xFB7E345B, }, /* x=EA */
|
||||||
|
{ 0x55F2733F, 0x3F55F273, 0x733F55F2, 0xF2733F55, }, /* x=EB */
|
||||||
|
{ 0x7FCD500E, 0x0E7FCD50, 0x500E7FCD, 0xCD500E7F, }, /* x=EC */
|
||||||
|
{ 0x71C45D05, 0x0571C45D, 0x5D0571C4, 0xC45D0571, }, /* x=ED */
|
||||||
|
{ 0x63DF4A18, 0x1863DF4A, 0x4A1863DF, 0xDF4A1863, }, /* x=EE */
|
||||||
|
{ 0x6DD64713, 0x136DD647, 0x47136DD6, 0xD647136D, }, /* x=EF */
|
||||||
|
{ 0xD731DCCA, 0xCAD731DC, 0xDCCAD731, 0x31DCCAD7, }, /* x=F0 */
|
||||||
|
{ 0xD938D1C1, 0xC1D938D1, 0xD1C1D938, 0x38D1C1D9, }, /* x=F1 */
|
||||||
|
{ 0xCB23C6DC, 0xDCCB23C6, 0xC6DCCB23, 0x23C6DCCB, }, /* x=F2 */
|
||||||
|
{ 0xC52ACBD7, 0xD7C52ACB, 0xCBD7C52A, 0x2ACBD7C5, }, /* x=F3 */
|
||||||
|
{ 0xEF15E8E6, 0xE6EF15E8, 0xE8E6EF15, 0x15E8E6EF, }, /* x=F4 */
|
||||||
|
{ 0xE11CE5ED, 0xEDE11CE5, 0xE5EDE11C, 0x1CE5EDE1, }, /* x=F5 */
|
||||||
|
{ 0xF307F2F0, 0xF0F307F2, 0xF2F0F307, 0x07F2F0F3, }, /* x=F6 */
|
||||||
|
{ 0xFD0EFFFB, 0xFBFD0EFF, 0xFFFBFD0E, 0x0EFFFBFD, }, /* x=F7 */
|
||||||
|
{ 0xA779B492, 0x92A779B4, 0xB492A779, 0x79B492A7, }, /* x=F8 */
|
||||||
|
{ 0xA970B999, 0x99A970B9, 0xB999A970, 0x70B999A9, }, /* x=F9 */
|
||||||
|
{ 0xBB6BAE84, 0x84BB6BAE, 0xAE84BB6B, 0x6BAE84BB, }, /* x=FA */
|
||||||
|
{ 0xB562A38F, 0x8FB562A3, 0xA38FB562, 0x62A38FB5, }, /* x=FB */
|
||||||
|
{ 0x9F5D80BE, 0xBE9F5D80, 0x80BE9F5D, 0x5D80BE9F, }, /* x=FC */
|
||||||
|
{ 0x91548DB5, 0xB591548D, 0x8DB59154, 0x548DB591, }, /* x=FD */
|
||||||
|
{ 0x834F9AA8, 0xA8834F9A, 0x9AA8834F, 0x4F9AA883, }, /* x=FE */
|
||||||
|
{ 0x8D4697A3, 0xA38D4697, 0x97A38D46, 0x4697A38D, }, /* x=FF */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
AES_Te0[x] = S [x].[02, 01, 01, 03];
|
AES_Te0[x] = S [x].[02, 01, 01, 03];
|
||||||
AES_Te1[x] = S [x].[03, 02, 01, 01];
|
AES_Te1[x] = S [x].[03, 02, 01, 01];
|
||||||
|
|
Loading…
Reference in a new issue