mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
Recent Clang complains about the "debug" static variable only ever being
written to. Drop it and the command line option controlling it.
Fixes: 19ab8356ab ("tools: remove support for running a guest with qemu-traditional")
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
Acked-by: Roger Pau Monné <roger@xenproject.org>
440 lines
13 KiB
C
440 lines
13 KiB
C
/* SPDX-License-Identifier: LGPL-2.1-only */
|
|
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <getopt.h>
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#if defined(CONFIG_X86)
|
|
#include <xen/arch-x86/guest-acpi.h>
|
|
#include <xen/hvm/hvm_info_table.h>
|
|
#elif defined(CONFIG_ARM_64)
|
|
#include <xen/arch-arm.h>
|
|
#endif
|
|
|
|
static unsigned int indent_level;
|
|
|
|
typedef enum dm_version {
|
|
QEMU_NONE,
|
|
QEMU_XEN,
|
|
QEMU_INVALID
|
|
} dm_version;
|
|
|
|
static void indent(void)
|
|
{
|
|
unsigned int i;
|
|
for ( i = 0; i < indent_level; i++ )
|
|
printf(" ");
|
|
}
|
|
|
|
static __attribute__((format(printf, 2, 3)))
|
|
void _stmt(const char *name, const char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
|
|
indent();
|
|
printf("%s", name);
|
|
|
|
if ( !fmt )
|
|
return;
|
|
|
|
printf(" ( ");
|
|
va_start(args, fmt);
|
|
vprintf(fmt, args);
|
|
va_end(args);
|
|
printf(" )");
|
|
}
|
|
|
|
#define stmt(n, f, a...) \
|
|
do { \
|
|
_stmt(n, f , ## a ); \
|
|
printf("\n"); \
|
|
} while (0)
|
|
|
|
#define push_block(n, f, a...) \
|
|
do { \
|
|
_stmt(n, f , ## a ); \
|
|
printf(" {\n"); \
|
|
indent_level++; \
|
|
} while (0)
|
|
|
|
static void pop_block(void)
|
|
{
|
|
indent_level--;
|
|
indent();
|
|
printf("}\n");
|
|
}
|
|
|
|
static struct option options[] = {
|
|
{ "maxcpu", 1, 0, 'c' },
|
|
#ifdef CONFIG_X86
|
|
{ "dm-version", 1, 0, 'q' },
|
|
#endif
|
|
{ 0, 0, 0, 0 }
|
|
};
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
unsigned int cpu, max_cpus;
|
|
#if defined(CONFIG_X86)
|
|
dm_version dm_version = QEMU_INVALID;
|
|
unsigned int slot, dev, intx, link;
|
|
|
|
max_cpus = HVM_MAX_VCPUS;
|
|
#elif defined(CONFIG_ARM_64)
|
|
max_cpus = GUEST_MAX_VCPUS;
|
|
#endif
|
|
|
|
for ( ; ; )
|
|
{
|
|
int opt = getopt_long(argc, argv, "", options, NULL);
|
|
if ( opt == -1 )
|
|
break;
|
|
|
|
switch ( opt )
|
|
{
|
|
case 'c': {
|
|
long i = 0;
|
|
char *endptr;
|
|
|
|
i = strtol(optarg, &endptr, 10);
|
|
if ( (*optarg != '\0') && (*endptr == '\0') && (i >= 0) )
|
|
{
|
|
max_cpus = i;
|
|
}
|
|
else if ( !(strcmp(optarg, "any") == 0) )
|
|
{
|
|
fprintf(stderr, "`%s' is not a number or is < 0.\n", optarg);
|
|
return -1;
|
|
}
|
|
break;
|
|
}
|
|
#ifdef CONFIG_X86
|
|
case 'q':
|
|
if (strcmp(optarg, "qemu-xen") == 0) {
|
|
dm_version = QEMU_XEN;
|
|
} else if (strcmp(optarg, "none") == 0) {
|
|
dm_version = QEMU_NONE;
|
|
} else {
|
|
fprintf(stderr, "Unknown device model version `%s'.\n", optarg);
|
|
return -1;
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_X86
|
|
if (dm_version == QEMU_INVALID) {
|
|
fprintf(stderr, "--dm_version is a mandatory parameter.\n");
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
/**** DSDT DefinitionBlock start ****/
|
|
/* (we append to existing DSDT definition block) */
|
|
indent_level++;
|
|
|
|
/**** Processor start ****/
|
|
push_block("Scope", "\\_SB");
|
|
|
|
#ifdef CONFIG_X86
|
|
/* MADT checksum */
|
|
stmt("OperationRegion", "MSUM, SystemMemory, \\_SB.MSUA, 1");
|
|
push_block("Field", "MSUM, ByteAcc, NoLock, Preserve");
|
|
indent(); printf("MSU, 8\n");
|
|
pop_block();
|
|
|
|
/* Processor object helpers. */
|
|
push_block("Method", "PMAT, 2");
|
|
push_block("If", "LLess(Arg0, NCPU)");
|
|
stmt("Return", "ToBuffer(Arg1)");
|
|
pop_block();
|
|
stmt("Return", "Buffer() {0, 8, 0xff, 0xff, 0, 0, 0, 0}");
|
|
pop_block();
|
|
#endif
|
|
|
|
/* Define processor objects and control methods. */
|
|
for ( cpu = 0; cpu < max_cpus; cpu++)
|
|
{
|
|
push_block("Processor", "PR%02X, %d, 0x0000b010, 0x06", cpu, cpu);
|
|
|
|
stmt("Name", "_HID, \"ACPI0007\"");
|
|
|
|
stmt("Name", "_UID, %d", cpu);
|
|
#ifdef CONFIG_ARM_64
|
|
pop_block();
|
|
continue;
|
|
#endif
|
|
/* Name this processor's MADT LAPIC descriptor. */
|
|
stmt("OperationRegion",
|
|
"MATR, SystemMemory, Add(\\_SB.MAPA, %d), 8", cpu*8);
|
|
|
|
push_block("Field", "MATR, ByteAcc, NoLock, Preserve");
|
|
indent(); printf("MAT, 64\n");
|
|
pop_block();
|
|
|
|
push_block("Field", "MATR, ByteAcc, NoLock, Preserve");
|
|
indent(); printf("Offset(4),\n");
|
|
indent(); printf("FLG, 1\n");
|
|
pop_block();
|
|
|
|
push_block("Method", "_MAT, 0");
|
|
if ( cpu )
|
|
stmt("Return", "PMAT (%d, MAT)", cpu);
|
|
else
|
|
stmt("Return", "ToBuffer(MAT)");
|
|
pop_block();
|
|
|
|
push_block("Method", "_STA");
|
|
if ( cpu )
|
|
push_block("If", "LLess(%d, \\_SB.NCPU)", cpu);
|
|
push_block("If", "FLG");
|
|
stmt("Return", "0xF");
|
|
pop_block();
|
|
if ( cpu )
|
|
pop_block();
|
|
stmt("Return", "0x0");
|
|
pop_block();
|
|
|
|
push_block("Method", "_EJ0, 1, NotSerialized");
|
|
stmt("Sleep", "0xC8");
|
|
pop_block();
|
|
|
|
pop_block();
|
|
}
|
|
|
|
#ifdef CONFIG_ARM_64
|
|
pop_block();
|
|
/**** Processor end ****/
|
|
#else
|
|
if (dm_version == QEMU_NONE) {
|
|
pop_block();
|
|
pop_block();
|
|
return 0;
|
|
}
|
|
|
|
/* Operation Region 'PRST': bitmask of online CPUs. */
|
|
stmt("OperationRegion", "PRST, SystemIO, %#x, %d",
|
|
XEN_ACPI_CPU_MAP, XEN_ACPI_CPU_MAP_LEN);
|
|
push_block("Field", "PRST, ByteAcc, NoLock, Preserve");
|
|
indent(); printf("PRS, %u\n", max_cpus);
|
|
pop_block();
|
|
|
|
/* Control method 'PRSC': CPU hotplug GPE handler. */
|
|
push_block("Method", "PRSC, 0");
|
|
stmt("Store", "ToBuffer(PRS), Local0");
|
|
for ( cpu = 0; cpu < max_cpus; cpu++ )
|
|
{
|
|
/* Read a byte at a time from the PRST online-CPU bitmask. */
|
|
if ( (cpu & 7) == 0 )
|
|
stmt("Store", "DerefOf(Index(Local0, %u)), Local1", cpu/8);
|
|
else
|
|
stmt("ShiftRight", "Local1, 1, Local1");
|
|
/* Extract current CPU's status: 0=offline; 1=online. */
|
|
stmt("And", "Local1, 1, Local2");
|
|
/* Check if status is up-to-date in the relevant MADT LAPIC entry... */
|
|
push_block("If", "LNotEqual(Local2, \\_SB.PR%02X.FLG)", cpu);
|
|
/* ...If not, update it and the MADT checksum, and notify OSPM. */
|
|
stmt("Store", "Local2, \\_SB.PR%02X.FLG", cpu);
|
|
push_block("If", "LEqual(Local2, 1)");
|
|
stmt("Notify", "PR%02X, 1", cpu); /* Notify: Device Check */
|
|
stmt("Subtract", "\\_SB.MSU, 1, \\_SB.MSU"); /* Adjust MADT csum */
|
|
pop_block();
|
|
push_block("Else", NULL);
|
|
stmt("Notify", "PR%02X, 3", cpu); /* Notify: Eject Request */
|
|
stmt("Add", "\\_SB.MSU, 1, \\_SB.MSU"); /* Adjust MADT csum */
|
|
pop_block();
|
|
pop_block();
|
|
}
|
|
stmt("Return", "One");
|
|
pop_block();
|
|
|
|
pop_block();
|
|
|
|
/* Define GPE control method. */
|
|
push_block("Scope", "\\_GPE");
|
|
push_block("Method", "_E%02d", XEN_ACPI_GPE0_CPUHP_BIT);
|
|
stmt("\\_SB.PRSC ()", NULL);
|
|
pop_block();
|
|
pop_block();
|
|
|
|
/**** Processor end ****/
|
|
|
|
|
|
/**** PCI0 start ****/
|
|
push_block("Scope", "\\_SB.PCI0");
|
|
|
|
/*
|
|
* Reserve the IO port ranges [0x10c0, 0x1101] and [0xb044, 0xb047].
|
|
* Or else, for a hotplugged-in device, the port IO BAR assigned
|
|
* by guest OS may conflict with the ranges here.
|
|
*/
|
|
push_block("Device", "HP0"); {
|
|
stmt("Name", "_HID, EISAID(\"PNP0C02\")");
|
|
stmt("Name", "_CRS, ResourceTemplate() {"
|
|
" IO (Decode16, 0xae00, 0xae00, 0x00, 0x10)"
|
|
" IO (Decode16, 0xb044, 0xb044, 0x00, 0x04)"
|
|
"}");
|
|
} pop_block();
|
|
|
|
/*** PCI-ISA link definitions ***/
|
|
/* BUFA: List of ISA IRQs available for linking to PCI INTx. */
|
|
stmt("Name", "BUFA, ResourceTemplate() { "
|
|
"IRQ(Level, ActiveLow, Shared) { 5, 10, 11 } }");
|
|
/* BUFB: IRQ descriptor for returning from link-device _CRS methods. */
|
|
stmt("Name", "BUFB, Buffer() { "
|
|
"0x23, 0x00, 0x00, 0x18, " /* IRQ descriptor */
|
|
"0x79, 0 }"); /* End tag, null checksum */
|
|
stmt("CreateWordField", "BUFB, 0x01, IRQV");
|
|
/* Create four PCI-ISA link devices: LNKA, LNKB, LNKC, LNKD. */
|
|
for ( link = 0; link < 4; link++ )
|
|
{
|
|
push_block("Device", "LNK%c", 'A'+link);
|
|
stmt("Name", "_HID, EISAID(\"PNP0C0F\")"); /* PCI interrupt link */
|
|
stmt("Name", "_UID, %u", link+1);
|
|
push_block("Method", "_STA, 0");
|
|
push_block("If", "And(PIR%c, 0x80)", 'A'+link);
|
|
stmt("Return", "0x09");
|
|
pop_block();
|
|
push_block("Else", NULL);
|
|
stmt("Return", "0x0B");
|
|
pop_block();
|
|
pop_block();
|
|
push_block("Method", "_PRS");
|
|
stmt("Return", "BUFA");
|
|
pop_block();
|
|
push_block("Method", "_DIS");
|
|
stmt("Or", "PIR%c, 0x80, PIR%c", 'A'+link, 'A'+link);
|
|
pop_block();
|
|
push_block("Method", "_CRS");
|
|
stmt("And", "PIR%c, 0x0f, Local0", 'A'+link);
|
|
stmt("ShiftLeft", "0x1, Local0, IRQV");
|
|
stmt("Return", "BUFB");
|
|
pop_block();
|
|
push_block("Method", "_SRS, 1");
|
|
stmt("CreateWordField", "ARG0, 0x01, IRQ1");
|
|
stmt("FindSetRightBit", "IRQ1, Local0");
|
|
stmt("Decrement", "Local0");
|
|
stmt("Store", "Local0, PIR%c", 'A'+link);
|
|
pop_block();
|
|
pop_block();
|
|
}
|
|
|
|
/*** PCI interrupt routing definitions***/
|
|
/* _PRT: Method to return routing table. */
|
|
push_block("Method", "_PRT, 0");
|
|
push_block("If", "PICD");
|
|
stmt("Return", "PRTA");
|
|
pop_block();
|
|
stmt("Return", "PRTP");
|
|
pop_block();
|
|
/* PRTP: PIC routing table (via ISA links). */
|
|
printf("Name(PRTP, Package() {\n");
|
|
for ( dev = 1; dev < 32; dev++ )
|
|
for ( intx = 0; intx < 4; intx++ ) /* INTA-D */
|
|
printf("Package(){0x%04xffff, %u, \\_SB.PCI0.LNK%c, 0},\n",
|
|
dev, intx, 'A'+((dev+intx)&3));
|
|
printf("})\n");
|
|
/* PRTA: APIC routing table (via non-legacy IOAPIC GSIs). */
|
|
printf("Name(PRTA, Package() {\n");
|
|
for ( dev = 1; dev < 32; dev++ )
|
|
for ( intx = 0; intx < 4; intx++ ) /* INTA-D */
|
|
printf("Package(){0x%04xffff, %u, 0, %u},\n",
|
|
dev, intx, ((dev*4+dev/8+intx)&31)+16);
|
|
printf("})\n");
|
|
|
|
/*
|
|
* Each PCI hotplug slot needs at least two methods to handle
|
|
* the ACPI event:
|
|
* _EJ0: eject a device
|
|
* _STA: return a device's status, e.g. enabled or removed
|
|
*
|
|
* Eject button would generate a general-purpose event, then the
|
|
* control method for this event uses Notify() to inform OSPM which
|
|
* action happened and on which device.
|
|
*
|
|
* Pls. refer "6.3 Device Insertion, Removal, and Status Objects"
|
|
* in ACPI spec 3.0b for details.
|
|
*
|
|
* QEMU provides a simple hotplug controller with some I/O to handle
|
|
* the hotplug action and status, which is beyond the ACPI scope.
|
|
*/
|
|
stmt("OperationRegion", "SEJ, SystemIO, 0xae08, 0x08");
|
|
push_block("Field", "SEJ, DWordAcc, NoLock, WriteAsZeros");
|
|
indent(); printf("B0EJ, 32,\n");
|
|
indent(); printf("B0RM, 32,\n");
|
|
pop_block();
|
|
|
|
/* hotplug_slot */
|
|
for (slot = 1; slot <= 31; slot++) {
|
|
push_block("Device", "S%i", slot); {
|
|
stmt("Name", "_ADR, %#06x0000", slot);
|
|
push_block("Method", "_EJ0,1"); {
|
|
stmt("Store", "%#010x, B0EJ", 1 << slot);
|
|
} pop_block();
|
|
stmt("Name", "_SUN, %i", slot);
|
|
push_block("Method", "_STA, 0"); {
|
|
push_block("If", "And(B0RM, ShiftLeft(1, %i))", slot);
|
|
stmt("Return", "0xF");
|
|
pop_block();
|
|
stmt("Return", "0x0");
|
|
} pop_block();
|
|
} pop_block();
|
|
}
|
|
|
|
pop_block();
|
|
/**** PCI0 end ****/
|
|
|
|
|
|
/**** GPE start ****/
|
|
push_block("Scope", "\\_GPE");
|
|
|
|
stmt("OperationRegion", "PCST, SystemIO, 0xae00, 0x08");
|
|
push_block("Field", "PCST, DWordAcc, NoLock, WriteAsZeros");
|
|
indent(); printf("PCIU, 32,\n");
|
|
indent(); printf("PCID, 32,\n");
|
|
pop_block();
|
|
|
|
stmt("OperationRegion", "DG1, SystemIO, 0xb044, 0x04");
|
|
|
|
push_block("Field", "DG1, ByteAcc, NoLock, Preserve");
|
|
indent(); printf("DPT1, 8, DPT2, 8\n");
|
|
pop_block();
|
|
|
|
push_block("Method", "_E01");
|
|
for (slot = 1; slot <= 31; slot++) {
|
|
push_block("If", "And(PCIU, ShiftLeft(1, %i))", slot);
|
|
stmt("Notify", "\\_SB.PCI0.S%i, 1", slot);
|
|
pop_block();
|
|
push_block("If", "And(PCID, ShiftLeft(1, %i))", slot);
|
|
stmt("Notify", "\\_SB.PCI0.S%i, 3", slot);
|
|
pop_block();
|
|
}
|
|
pop_block();
|
|
|
|
pop_block();
|
|
/**** GPE end ****/
|
|
#endif
|
|
|
|
pop_block();
|
|
/**** DSDT DefinitionBlock end ****/
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Local variables:
|
|
* mode: C
|
|
* c-file-style: "BSD"
|
|
* c-basic-offset: 4
|
|
* tab-width: 4
|
|
* indent-tabs-mode: nil
|
|
* End:
|
|
*/
|