Merge tag 'hppa-more-v11-fixes-pull-request' of https://github.com/hdeller/qemu-hppa into staging

HPPA patches for qemu-v11

A few late fixes for the HPPA architecture for QEMU v11:
- graphics support was broken for 64-bit machines. This series adds
  support for VGA graphics for Linux guests
- the various memory ranges were not correctly implemented
- TOC/NMI was not working on 64-bit machines
- minor 64-bit HP-UX boot fixes (but HP-UX 64-bit still crashes)

# -----BEGIN PGP SIGNATURE-----
#
# iHUEABYKAB0WIQS86RI+GtKfB8BJu973ErUQojoPXwUCacwXxAAKCRD3ErUQojoP
# X7NxAQCBszDUKsNX5KiB+cxW1AfT1Gyzo4q9T0NNULO5v2Fn7gD/YVzgtZ6F+crK
# 1eG1R0aVekPmx+NClsCLvy/dX1YmTww=
# =L+6i
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue Mar 31 19:51:48 2026 BST
# gpg:                using EDDSA key BCE9123E1AD29F07C049BBDEF712B510A23A0F5F
# gpg: Good signature from "Helge Deller <deller@gmx.de>" [unknown]
# gpg:                 aka "Helge Deller <deller@kernel.org>" [unknown]
# gpg:                 aka "Helge Deller <deller@debian.org>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 4544 8228 2CD9 10DB EF3D  25F8 3E5F 3D04 A7A2 4603
#      Subkey fingerprint: BCE9 123E 1AD2 9F07 C049  BBDE F712 B510 A23A 0F5F

* tag 'hppa-more-v11-fixes-pull-request' of https://github.com/hdeller/qemu-hppa:
  target/hppa: Update SeaBIOS-hppa to version 24
  hw/hppa: Implement memory ranges
  target/hppa: Fix TOC handler for 64-bit CPUs
  hw/pci-host/astro: Add GMMIO mapping
  hw/pci-host/astro: Fix LMMIO DIRECT mappings
  hw/pci-host/astro: Implement LMMIO registers
  hw/pci-host/astro: Fix initial addresses in IOC
  hw/pci-host/astro: Make astro address arrays accessible for other users

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell
2026-03-31 20:46:13 +01:00
8 changed files with 238 additions and 53 deletions

View File

@@ -8,7 +8,8 @@
#define FIRMWARE_END 0xf0100000
#define FIRMWARE_HIGH 0xfffffff0 /* upper 32-bits of 64-bit firmware address */
#define RAM_MAP_HIGH 0x0100000000 /* memory above 3.75 GB is mapped here */
#define RAM_MAP_HIGH1 0x0100000000 /* memory above 4 GB */
#define RAM_MAP_HIGH2 0x4040000000 /* memory between 1 G and 3.75 GB */
#define MEM_PDC_ENTRY 0x4800 /* PDC entry address */

View File

@@ -43,6 +43,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(HppaMachineState, HPPA_COMMON_MACHINE)
struct HppaMachineState {
MachineState parent_obj;
uint64_t memsplit_addr;
};
#define MIN_SEABIOS_HPPA_VERSION 22 /* require at least this fw version */
@@ -208,6 +210,7 @@ static FWCfgState *create_fw_cfg(MachineState *ms, PCIBus *pci_bus,
const char qemu_version[] = QEMU_VERSION;
MachineClass *mc = MACHINE_GET_CLASS(ms);
int btlb_entries = HPPA_BTLB_ENTRIES(&cpu[0]->env);
struct HppaMachineState *hpm = HPPA_COMMON_MACHINE(ms);
int len;
fw_cfg = fw_cfg_init_mem_nodma(addr, addr + 4, 1);
@@ -231,6 +234,10 @@ static FWCfgState *create_fw_cfg(MachineState *ms, PCIBus *pci_bus,
fw_cfg_add_file(fw_cfg, "/etc/hppa/machine",
g_memdup2(mc->name, len), len);
val = cpu_to_le64(hpm->memsplit_addr);
fw_cfg_add_file(fw_cfg, "/etc/hppa/memsplit-addr",
g_memdup2(&val, sizeof(val)), sizeof(val));
val = cpu_to_le64(soft_power_reg);
fw_cfg_add_file(fw_cfg, "/etc/hppa/power-button-addr",
g_memdup2(&val, sizeof(val)), sizeof(val));
@@ -287,6 +294,8 @@ static TranslateFn *machine_HP_common_init_cpus(MachineState *machine)
TranslateFn *translate;
MemoryRegion *cpu_region;
uint64_t ram_max;
struct HppaMachineState *hpm;
hwaddr splitaddr;
/* Create CPUs. */
for (unsigned int i = 0; i < smp_cpus; i++) {
@@ -347,21 +356,36 @@ static TranslateFn *machine_HP_common_init_cpus(MachineState *machine)
info_report("Max RAM size limited to %" PRIu64 " MB", ram_max / MiB);
machine->ram_size = ram_max;
}
if (machine->ram_size <= FIRMWARE_START) {
/* contiguous memory up to 3.75 GB RAM */
memory_region_add_subregion_overlap(addr_space, 0, machine->ram, -1);
} else {
hpm = HPPA_COMMON_MACHINE(machine);
if (!hpm->memsplit_addr) {
/* non-contiguous: Memory above 3.75 GB is mapped at RAM_MAP_HIGH */
MemoryRegion *mem_region;
mem_region = g_new(MemoryRegion, 2);
memory_region_init_alias(&mem_region[0], &addr_space->parent_obj,
"LowMem", machine->ram, 0, FIRMWARE_START);
memory_region_init_alias(&mem_region[1], &addr_space->parent_obj,
"HighMem", machine->ram, FIRMWARE_START,
machine->ram_size - FIRMWARE_START);
memory_region_add_subregion_overlap(addr_space, 0, &mem_region[0], -1);
memory_region_add_subregion_overlap(addr_space, RAM_MAP_HIGH,
&mem_region[1], -1);
hpm->memsplit_addr = FIRMWARE_START;
}
splitaddr = hpm->memsplit_addr;
MemoryRegion *mem_region;
mem_region = g_new(MemoryRegion, 1);
memory_region_init_alias(&mem_region[0], &addr_space->parent_obj,
"memory0", machine->ram, 0, splitaddr);
memory_region_add_subregion_overlap(addr_space, 0, &mem_region[0], -1);
if (hppa_is_pa20(&cpu[0]->env)) {
if (machine->ram_size > 4 * GiB) {
mem_region = g_new(MemoryRegion, 1);
memory_region_init_alias(&mem_region[0], &addr_space->parent_obj,
"memory1", machine->ram, 4 * GiB,
machine->ram_size - 4 * GiB);
memory_region_add_subregion_overlap(addr_space, RAM_MAP_HIGH1,
&mem_region[0], -1);
}
if (machine->ram_size > splitaddr) {
mem_region = g_new(MemoryRegion, 1);
memory_region_init_alias(&mem_region[0], &addr_space->parent_obj,
"memory2", machine->ram, splitaddr,
4 * GiB - splitaddr);
memory_region_add_subregion_overlap(addr_space, RAM_MAP_HIGH2,
&mem_region[0], -1);
}
}
return translate;
@@ -757,6 +781,10 @@ static void machine_HP_C3700_init(MachineState *machine)
*/
static void machine_HP_A400_init(MachineState *machine)
{
struct HppaMachineState *hpm;
hpm = HPPA_COMMON_MACHINE(machine);
hpm->memsplit_addr = 1 * GiB;
machine_HP_C3700_init(machine);
}
@@ -815,7 +843,7 @@ static void hppa_machine_common_class_init(ObjectClass *oc, const void *data)
mc->default_cpus = 1;
mc->max_cpus = HPPA_MAX_CPUS;
mc->default_boot_order = "cd";
mc->default_ram_id = "ram";
mc->default_ram_id = "hppa.ram";
mc->default_nic = "tulip";
nc->nmi_monitor_handler = hppa_nmi;

View File

@@ -14,7 +14,6 @@
* - All user-added devices are currently attached to the first
* Elroy (PCI bus) only for now. To fix this additional work in
* SeaBIOS and this driver is needed. See "user_creatable" flag below.
* - GMMIO (Greater than 4 GB MMIO) register
*/
#define TYPE_ASTRO_IOMMU_MEMORY_REGION "astro-iommu-memory-region"
@@ -37,6 +36,11 @@
#include "qom/object.h"
#include "exec/target_page.h"
static const int elroy_hpa_offsets[ELROY_NUM] = {
0x30000, 0x32000, 0x38000, 0x3c000 };
static const char elroy_rope_nr[ELROY_NUM] = {
0, 1, 4, 6 }; /* busnum path, e.g. [10:6] */
/*
* Helper functions
*/
@@ -525,14 +529,90 @@ static ElroyState *elroy_init(int num)
* Astro Runway chip.
*/
static void adjust_LMMIO_mapping(AstroState *s)
{
MemoryRegion *lmmio;
uint64_t map_addr, map_size, align_mask;
uint32_t map_route, map_enabled, i;
lmmio = &s->lmmio;
/* read LMMIO distributed route and calculate size */
map_route = s->ioc_ranges[(0x370 - 0x300) / 8] >> 58;
map_route = MIN(MAX(map_route, 20), 23);
/* calculate size of each mapping, sum of all is 8-64 MB */
map_size = 1ULL << map_route;
align_mask = ~(map_size - 1);
/* read LMMIO_DIST_BASE for mapping address */
map_addr = s->ioc_ranges[(0x360 - 0x300) / 8];
map_enabled = map_addr & 1;
map_addr &= MAKE_64BIT_MASK(24, 5);
map_addr |= MAKE_64BIT_MASK(29, 36);
map_addr &= align_mask;
s->ioc_ranges[(0x360 - 0x300) / 8] = map_addr | map_enabled;
/* make sure the lmmio region is initially turned off */
if (lmmio->enabled) {
memory_region_set_enabled(lmmio, false);
}
/* exit if range is not enabled */
if (!map_enabled) {
return;
}
if (!lmmio->name) {
memory_region_init_io(lmmio, OBJECT(s), &unassigned_io_ops, s,
"LMMIO", ROPES_PER_IOC * map_size);
memory_region_add_subregion_overlap(get_system_memory(),
map_addr, lmmio, 1);
}
memory_region_set_address(lmmio, map_addr);
memory_region_set_size(lmmio, ROPES_PER_IOC * map_size);
memory_region_set_enabled(lmmio, true);
for (i = 0; i < ELROY_NUM; i++) {
MemoryRegion *alias;
ElroyState *elroy;
int rope;
elroy = s->elroy[i];
alias = &elroy->lmmio_alias;
rope = elroy_rope_nr[i];
if (alias->enabled) {
memory_region_set_enabled(alias, false);
}
if (!alias->name) {
memory_region_init_alias(alias, OBJECT(elroy),
"lmmio-alias", &elroy->pci_mmio, 0, map_size);
memory_region_add_subregion_overlap(lmmio, rope * map_size,
alias, 2);
}
memory_region_set_address(alias, rope * map_size);
memory_region_set_alias_offset(alias,
(uint32_t) (map_addr + rope * map_size));
memory_region_set_size(alias, map_size);
memory_region_set_enabled(alias, true);
}
}
static void adjust_LMMIO_DIRECT_mapping(AstroState *s, unsigned int reg_index)
{
MemoryRegion *lmmio_alias;
unsigned int lmmio_index, map_route;
hwaddr map_addr;
uint32_t map_size;
uint32_t map_size, map_enabled;
struct ElroyState *elroy;
/* each LMMIO may access from 1 MB up to 64 MB */
const unsigned int lmmio_mask = ~(1 * MiB - 1);
const unsigned int lmmio_max_size = 64 * MiB;
/* pointer to LMMIO_DIRECT entry */
lmmio_index = reg_index / 3;
lmmio_alias = &s->lmmio_direct[lmmio_index];
@@ -545,30 +625,104 @@ static void adjust_LMMIO_DIRECT_mapping(AstroState *s, unsigned int reg_index)
map_route &= (ELROY_NUM - 1);
elroy = s->elroy[map_route];
/* make sure the lmmio region is initially turned off */
if (lmmio_alias->enabled) {
memory_region_set_enabled(lmmio_alias, false);
}
/* do sanity checks and calculate mmio size */
map_enabled = map_addr & 1;
map_addr &= lmmio_mask;
map_size &= lmmio_mask;
map_size = MIN(map_size, lmmio_max_size);
map_addr = F_EXTEND(map_addr);
map_addr &= TARGET_PAGE_MASK;
map_size = (~map_size) + 1;
map_size &= TARGET_PAGE_MASK;
/* exit if disabled or zero map size */
if (!(map_addr & 1) || !map_size) {
/* exit if disabled or has zero size. */
if (!map_enabled || !map_size) {
return;
}
if (!memory_region_size(lmmio_alias)) {
if (!lmmio_alias->name) {
char lmmio_name[32];
snprintf(lmmio_name, sizeof(lmmio_name),
"LMMIO-DIRECT-%u", lmmio_index);
memory_region_init_alias(lmmio_alias, OBJECT(elroy),
"pci-lmmmio-alias", &elroy->pci_mmio,
lmmio_name, &elroy->pci_mmio,
(uint32_t) map_addr, map_size);
memory_region_add_subregion(get_system_memory(), map_addr,
lmmio_alias);
} else {
memory_region_set_alias_offset(lmmio_alias, map_addr);
memory_region_set_size(lmmio_alias, map_size);
memory_region_set_enabled(lmmio_alias, true);
memory_region_add_subregion_overlap(get_system_memory(),
map_addr, lmmio_alias, 3);
}
memory_region_set_address(lmmio_alias, map_addr);
memory_region_set_alias_offset(lmmio_alias, (uint32_t) map_addr);
memory_region_set_size(lmmio_alias, map_size);
memory_region_set_enabled(lmmio_alias, true);
}
static void adjust_GMMIO_mapping(AstroState *s)
{
MemoryRegion *gmmio;
uint64_t map_addr, map_size, align_mask;
uint32_t map_route, map_enabled, i;
gmmio = &s->gmmio;
map_addr = s->ioc_ranges[(0x378 - 0x300) / 8]; /* GMMIO_DIST_BASE */
map_enabled = map_addr & 1;
map_addr &= MAKE_64BIT_MASK(32, 8);
s->ioc_ranges[(0x378 - 0x300) / 8] = map_addr | map_enabled;
map_route = s->ioc_ranges[(0x388 - 0x300) / 8] >> 58; /* GMMIO_DIST_ROUTE */
map_route = MIN(MAX(map_route, 29), 33); /* between 4-16 GB total */
map_size = 1ULL << map_route; /* size of each mapping */
align_mask = ~(map_size - 1);
/* make sure the lmmio region is initially turned off */
if (gmmio->enabled) {
memory_region_set_enabled(gmmio, false);
}
/* do sanity checks and calculate mmio size */
map_addr &= align_mask;
/* exit if disabled */
if (!map_enabled) {
return;
}
if (!gmmio->name) {
memory_region_init_io(gmmio, OBJECT(s), &unassigned_io_ops, s,
"GMMIO", ROPES_PER_IOC * map_size);
memory_region_add_subregion_overlap(get_system_memory(),
map_addr, gmmio, 1);
}
memory_region_set_address(gmmio, map_addr);
memory_region_set_size(gmmio, ROPES_PER_IOC * map_size);
memory_region_set_enabled(gmmio, true);
for (i = 0; i < ELROY_NUM; i++) {
MemoryRegion *alias;
ElroyState *elroy;
int rope;
elroy = s->elroy[i];
alias = &elroy->gmmio_alias;
rope = elroy_rope_nr[i];
if (alias->enabled) {
memory_region_set_enabled(alias, false);
}
if (!alias->name) {
memory_region_init_alias(alias, OBJECT(elroy),
"gmmio-alias", &elroy->pci_mmio, 0, map_size);
memory_region_add_subregion_overlap(gmmio, rope * map_size,
alias, 2);
}
memory_region_set_address(alias, rope * map_size);
memory_region_set_alias_offset(alias, map_addr + rope * map_size);
memory_region_set_size(alias, map_size);
memory_region_set_enabled(alias, true);
}
}
@@ -684,6 +838,12 @@ static MemTxResult astro_chip_write_with_attrs(void *opaque, hwaddr addr,
if (index < LMMIO_DIRECT_RANGES * 3) {
adjust_LMMIO_DIRECT_mapping(s, index);
}
if (addr >= 0x360 && addr <= 0x370 + 7) {
adjust_LMMIO_mapping(s);
}
if (addr >= 0x378 && addr <= 0x388 + 7) {
adjust_GMMIO_mapping(s);
}
break;
case 0x10200:
case 0x10220:
@@ -799,13 +959,13 @@ static void astro_reset(DeviceState *dev)
* The LBA BASE/MASK registers control IO -> System routing (in Elroy)
*/
memset(&s->ioc_ranges, 0, sizeof(s->ioc_ranges));
s->ioc_ranges[(0x360 - 0x300) / 8] = LMMIO_DIST_BASE_ADDR | 0x01; /* LMMIO_DIST_BASE (SBA) */
s->ioc_ranges[(0x360 - 0x300) / 8] = F_EXTEND(LMMIO_DIST_BASE_ADDR) | 0x01;
s->ioc_ranges[(0x368 - 0x300) / 8] = 0xfc000000; /* LMMIO_DIST_MASK */
s->ioc_ranges[(0x370 - 0x300) / 8] = 0; /* LMMIO_DIST_ROUTE */
s->ioc_ranges[(0x390 - 0x300) / 8] = IOS_DIST_BASE_ADDR | 0x01; /* IOS_DIST_BASE */
s->ioc_ranges[(0x390 - 0x300) / 8] = F_EXTEND(IOS_DIST_BASE_ADDR) | 0x01;
s->ioc_ranges[(0x398 - 0x300) / 8] = 0xffffff0000; /* IOS_DIST_MASK */
s->ioc_ranges[(0x3a0 - 0x300) / 8] = 0x3400000000000000ULL; /* IOS_DIST_ROUTE */
s->ioc_ranges[(0x3c0 - 0x300) / 8] = 0xfffee00000; /* IOS_DIRECT_BASE */
s->ioc_ranges[(0x3c0 - 0x300) / 8] = IOS_DIST_BASE_ADDR; /* IOS_DIRECT_BASE */
s->ioc_ranges[(0x3c8 - 0x300) / 8] = 0xffffff0000; /* IOS_DIRECT_MASK */
s->ioc_ranges[(0x3d0 - 0x300) / 8] = 0x0; /* IOS_DIRECT_ROUTE */
@@ -843,10 +1003,6 @@ static void astro_realize(DeviceState *obj, Error **errp)
/* Create Elroys (PCI host bus chips). */
for (i = 0; i < ELROY_NUM; i++) {
static const int elroy_hpa_offsets[ELROY_NUM] = {
0x30000, 0x32000, 0x38000, 0x3c000 };
static const char elroy_rope_nr[ELROY_NUM] = {
0, 1, 4, 6 }; /* busnum path, e.g. [10:6] */
int addr_offset;
ElroyState *elroy;
hwaddr map_addr;
@@ -891,15 +1047,6 @@ static void astro_realize(DeviceState *obj, Error **errp)
elroy->mmio_base[(0x0240 - 0x200) / 8] = rope * map_size | 0x01;
elroy->mmio_base[(0x0248 - 0x200) / 8] = 0x0000e000;
/* map elroys mmio */
map_size = LMMIO_DIST_BASE_SIZE / ROPES_PER_IOC;
map_addr = F_EXTEND(LMMIO_DIST_BASE_ADDR + rope * map_size);
memory_region_init_alias(&elroy->pci_mmio_alias, OBJECT(elroy),
"pci-mmio-alias",
&elroy->pci_mmio, (uint32_t) map_addr, map_size);
memory_region_add_subregion(get_system_memory(), map_addr,
&elroy->pci_mmio_alias);
/* map elroys io */
map_size = IOS_DIST_BASE_SIZE / ROPES_PER_IOC;
map_addr = F_EXTEND(IOS_DIST_BASE_ADDR + rope * map_size);

View File

@@ -26,8 +26,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(ElroyState, ELROY_PCI_HOST_BRIDGE)
#define LMMIO_DIRECT_RANGES 4
#define IOS_DIST_BASE_ADDR 0xfffee00000ULL
#define IOS_DIST_BASE_SIZE 0x10000ULL
#define IOS_DIST_BASE_ADDR 0xffffee00000ULL
#define IOS_DIST_BASE_SIZE 0x10000ULL
#define HF_ENABLE 0x40 /* enable HF mode (default is -1 mode) */
@@ -61,9 +61,10 @@ struct ElroyState {
MemoryRegion this_mem;
MemoryRegion pci_mmio;
MemoryRegion pci_mmio_alias;
MemoryRegion pci_hole;
MemoryRegion pci_io;
MemoryRegion gmmio_alias;
MemoryRegion lmmio_alias;
};
struct AstroState {
@@ -89,6 +90,9 @@ struct AstroState {
MemoryRegion this_mem;
MemoryRegion lmmio_direct[LMMIO_DIRECT_RANGES];
MemoryRegion lmmio;
MemoryRegion gmmio;
IOMMUMemoryRegion iommu;
AddressSpace iommu_as;
};

Binary file not shown.

Binary file not shown.

View File

@@ -203,7 +203,12 @@ void hppa_cpu_do_interrupt(CPUState *cs)
/* step 7 */
if (i == EXCP_TOC) {
env->iaoq_f = hppa_form_gva(env, 0, FIRMWARE_START);
hwaddr pdc_toc_addr = FIRMWARE_START;
/* for 64-bit include the high bits of PDC */
pdc_toc_addr |= ((uint64_t) FIRMWARE_HIGH) << 32;
env->iaoq_f = hppa_form_gva(env, 0, pdc_toc_addr);
/* help SeaBIOS and provide iaoq_b and iasq_back in shadow regs */
env->gr[24] = env->cr_back[0];
env->gr[25] = env->cr_back[1];