virtio,acpi,pci: fixes, cleanups.

Fixes, cleanups in ACPI, PCI, virtio.
 
 Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQFDBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAl70SM8PHG1zdEByZWRo
 YXQuY29tAAoJECgfDbjSjVRpmlYIAMX7h46FSx8jXJPLMVHYjlOnzwSCZdFXnNt+
 qj6GZfIrLSDsnz+X7hRA5QlX23NBjhwDvcQC3ucvGwzFMmQRjGwCK8tJJSfFWYTB
 oL1/YpTU6qHxOtR8UynuZak/Rq822Ug6PSAazQDG39HbS2v5srHXC1aVNSbhiMIi
 7SdE8wBWae3R7Y7sVfIU4pMc3GeztPiqgXewAyOskVqrTQzuwuBhwQiK7kd6Md2Y
 fdTP+pZrXl7czMjnb9dM6Wq1griFrGDQVesSiggfGGI3rQ3W8Z24k5k+u81DKi+1
 fVXwXsebRokCpEYgWgmyK9D2SajNjmDWBdyCHvO64FClpAzZWlc=
 =J1qe
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging

virtio,acpi,pci: fixes, cleanups.

Fixes, cleanups in ACPI, PCI, virtio.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

# gpg: Signature made Thu 25 Jun 2020 07:48:47 BST
# gpg:                using RSA key 5D09FD0871C8F85B94CA8A0D281F0DB8D28D5469
# gpg:                issuer "mst@redhat.com"
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" [full]
# gpg:                 aka "Michael S. Tsirkin <mst@redhat.com>" [full]
# Primary key fingerprint: 0270 606B 6F3C DF3D 0B17  0970 C350 3912 AFBE 8E67
#      Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA  8A0D 281F 0DB8 D28D 5469

* remotes/mst/tags/for_upstream:
  Rename use_acpi_pci_hotplug to more appropriate use_acpi_hotplug_bridge
  Stop vhost-user sending uninitialized mmap_offsets
  docs/specs/tpm: ACPI boot now supported for TPM/ARM
  arm/acpi: Add the TPM2.0 device under the DSDT
  acpi: Some build_tpm2() code reshape
  tests/acpi: update expected data files
  acpi: q35: drop _SB.PCI0.ISA.LPCD opregion.
  acpi: drop build_piix4_pm()
  acpi: drop serial/parallel enable bits from dsdt
  acpi: simplify build_isa_devices_aml()
  acpi: factor out fw_cfg_add_acpi_dsdt()
  acpi: move aml builder code for i8042 (kbd+mouse) device
  floppy: move cmos_get_fd_drive_type() from pc
  floppy: make isa_fdc_get_drive_max_chs static
  acpi: move aml builder code for floppy device
  acpi: bios-tables-test: show more context on asl diffs
  qtest: allow DSDT acpi table changes

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2020-06-25 16:52:42 +01:00
commit 63d211993b
36 changed files with 286 additions and 290 deletions

View File

@ -346,8 +346,6 @@ In case an Arm virt machine is emulated, use the following command line:
-drive if=pflash,format=raw,file=flash0.img,readonly \ -drive if=pflash,format=raw,file=flash0.img,readonly \
-drive if=pflash,format=raw,file=flash1.img -drive if=pflash,format=raw,file=flash1.img
On Arm, ACPI boot with TPM is not yet supported.
In case SeaBIOS is used as firmware, it should show the TPM menu item In case SeaBIOS is used as firmware, it should show the TPM menu item
after entering the menu with 'ESC'. after entering the menu with 'ESC'.

View File

@ -1878,48 +1878,61 @@ build_hdr:
"FACP", tbl->len - fadt_start, f->rev, oem_id, oem_table_id); "FACP", tbl->len - fadt_start, f->rev, oem_id, oem_table_id);
} }
/*
* build_tpm2 - Build the TPM2 table as specified in
* table 7: TCG Hardware Interface Description Table Format for TPM 2.0
* of TCG ACPI Specification, Family 1.2 and 2.0, Version 1.2, Rev 8
*/
void build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog) void build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog)
{ {
Acpi20TPM2 *tpm2_ptr = acpi_data_push(table_data, sizeof(AcpiTableHeader));
unsigned log_addr_size = sizeof(tpm2_ptr->log_area_start_address);
unsigned log_addr_offset =
(char *)&tpm2_ptr->log_area_start_address - table_data->data;
uint8_t start_method_params[12] = {}; uint8_t start_method_params[12] = {};
unsigned log_addr_offset, tpm2_start;
uint64_t control_area_start_address;
TPMIf *tpmif = tpm_find(); TPMIf *tpmif = tpm_find();
uint32_t start_method;
void *tpm2_ptr;
/* platform class */ tpm2_start = table_data->len;
tpm2_ptr = acpi_data_push(table_data, sizeof(AcpiTableHeader));
/* Platform Class */
build_append_int_noprefix(table_data, TPM2_ACPI_CLASS_CLIENT, 2); build_append_int_noprefix(table_data, TPM2_ACPI_CLASS_CLIENT, 2);
/* reserved */ /* Reserved */
build_append_int_noprefix(table_data, 0, 2); build_append_int_noprefix(table_data, 0, 2);
if (TPM_IS_TIS_ISA(tpmif) || TPM_IS_TIS_SYSBUS(tpmif)) { if (TPM_IS_TIS_ISA(tpmif) || TPM_IS_TIS_SYSBUS(tpmif)) {
/* address of control area */ control_area_start_address = 0;
build_append_int_noprefix(table_data, 0, 8); start_method = TPM2_START_METHOD_MMIO;
/* start method */
build_append_int_noprefix(table_data, TPM2_START_METHOD_MMIO, 4);
} else if (TPM_IS_CRB(tpmif)) { } else if (TPM_IS_CRB(tpmif)) {
build_append_int_noprefix(table_data, TPM_CRB_ADDR_CTRL, 8); control_area_start_address = TPM_CRB_ADDR_CTRL;
build_append_int_noprefix(table_data, TPM2_START_METHOD_CRB, 4); start_method = TPM2_START_METHOD_CRB;
} else { } else {
g_warn_if_reached(); g_assert_not_reached();
} }
/* Address of Control Area */
build_append_int_noprefix(table_data, control_area_start_address, 8);
/* Start Method */
build_append_int_noprefix(table_data, start_method, 4);
/* platform specific parameters */ /* Platform Specific Parameters */
g_array_append_vals(table_data, &start_method_params, 12); g_array_append_vals(table_data, &start_method_params,
ARRAY_SIZE(start_method_params));
/* log area minimum length */ /* Log Area Minimum Length */
build_append_int_noprefix(table_data, TPM_LOG_AREA_MINIMUM_SIZE, 4); build_append_int_noprefix(table_data, TPM_LOG_AREA_MINIMUM_SIZE, 4);
acpi_data_push(tcpalog, TPM_LOG_AREA_MINIMUM_SIZE); acpi_data_push(tcpalog, TPM_LOG_AREA_MINIMUM_SIZE);
bios_linker_loader_alloc(linker, ACPI_BUILD_TPMLOG_FILE, tcpalog, 1, bios_linker_loader_alloc(linker, ACPI_BUILD_TPMLOG_FILE, tcpalog, 1,
false); false);
/* log area start address to be filled by Guest linker */ log_addr_offset = table_data->len;
/* Log Area Start Address to be filled by Guest linker */
build_append_int_noprefix(table_data, 0, 8); build_append_int_noprefix(table_data, 0, 8);
bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE,
log_addr_offset, log_addr_size, log_addr_offset, 8,
ACPI_BUILD_TPMLOG_FILE, 0); ACPI_BUILD_TPMLOG_FILE, 0);
build_header(linker, table_data, build_header(linker, table_data,
(void *)tpm2_ptr, "TPM2", sizeof(*tpm2_ptr), 4, NULL, NULL); tpm2_ptr, "TPM2", table_data->len - tpm2_start, 4, NULL, NULL);
} }
/* ACPI 5.0: 6.4.3.8.2 Serial Bus Connection Descriptors */ /* ACPI 5.0: 6.4.3.8.2 Serial Bus Connection Descriptors */

View File

@ -77,7 +77,7 @@ typedef struct PIIX4PMState {
Notifier powerdown_notifier; Notifier powerdown_notifier;
AcpiPciHpState acpi_pci_hotplug; AcpiPciHpState acpi_pci_hotplug;
bool use_acpi_pci_hotplug; bool use_acpi_hotplug_bridge;
uint8_t disable_s3; uint8_t disable_s3;
uint8_t disable_s4; uint8_t disable_s4;
@ -204,16 +204,17 @@ static const VMStateDescription vmstate_pci_status = {
} }
}; };
static bool vmstate_test_use_acpi_pci_hotplug(void *opaque, int version_id) static bool vmstate_test_use_acpi_hotplug_bridge(void *opaque, int version_id)
{ {
PIIX4PMState *s = opaque; PIIX4PMState *s = opaque;
return s->use_acpi_pci_hotplug; return s->use_acpi_hotplug_bridge;
} }
static bool vmstate_test_no_use_acpi_pci_hotplug(void *opaque, int version_id) static bool vmstate_test_no_use_acpi_hotplug_bridge(void *opaque,
int version_id)
{ {
PIIX4PMState *s = opaque; PIIX4PMState *s = opaque;
return !s->use_acpi_pci_hotplug; return !s->use_acpi_hotplug_bridge;
} }
static bool vmstate_test_use_memhp(void *opaque) static bool vmstate_test_use_memhp(void *opaque)
@ -290,11 +291,11 @@ static const VMStateDescription vmstate_acpi = {
VMSTATE_STRUCT_TEST( VMSTATE_STRUCT_TEST(
acpi_pci_hotplug.acpi_pcihp_pci_status[ACPI_PCIHP_BSEL_DEFAULT], acpi_pci_hotplug.acpi_pcihp_pci_status[ACPI_PCIHP_BSEL_DEFAULT],
PIIX4PMState, PIIX4PMState,
vmstate_test_no_use_acpi_pci_hotplug, vmstate_test_no_use_acpi_hotplug_bridge,
2, vmstate_pci_status, 2, vmstate_pci_status,
struct AcpiPciHpPciStatus), struct AcpiPciHpPciStatus),
VMSTATE_PCI_HOTPLUG(acpi_pci_hotplug, PIIX4PMState, VMSTATE_PCI_HOTPLUG(acpi_pci_hotplug, PIIX4PMState,
vmstate_test_use_acpi_pci_hotplug), vmstate_test_use_acpi_hotplug_bridge),
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
}, },
.subsections = (const VMStateDescription*[]) { .subsections = (const VMStateDescription*[]) {
@ -530,7 +531,7 @@ I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
s->smi_irq = smi_irq; s->smi_irq = smi_irq;
s->smm_enabled = smm_enabled; s->smm_enabled = smm_enabled;
if (xen_enabled()) { if (xen_enabled()) {
s->use_acpi_pci_hotplug = false; s->use_acpi_hotplug_bridge = false;
} }
pci_realize_and_unref(pci_dev, bus, &error_fatal); pci_realize_and_unref(pci_dev, bus, &error_fatal);
@ -595,7 +596,7 @@ static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
memory_region_add_subregion(parent, GPE_BASE, &s->io_gpe); memory_region_add_subregion(parent, GPE_BASE, &s->io_gpe);
acpi_pcihp_init(OBJECT(s), &s->acpi_pci_hotplug, bus, parent, acpi_pcihp_init(OBJECT(s), &s->acpi_pci_hotplug, bus, parent,
s->use_acpi_pci_hotplug); s->use_acpi_hotplug_bridge);
s->cpu_hotplug_legacy = true; s->cpu_hotplug_legacy = true;
object_property_add_bool(OBJECT(s), "cpu-hotplug-legacy", object_property_add_bool(OBJECT(s), "cpu-hotplug-legacy",
@ -633,7 +634,7 @@ static Property piix4_pm_properties[] = {
DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_DISABLED, PIIX4PMState, disable_s4, 0), DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_DISABLED, PIIX4PMState, disable_s4, 0),
DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_VAL, PIIX4PMState, s4_val, 2), DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_VAL, PIIX4PMState, s4_val, 2),
DEFINE_PROP_BOOL("acpi-pci-hotplug-with-bridge-support", PIIX4PMState, DEFINE_PROP_BOOL("acpi-pci-hotplug-with-bridge-support", PIIX4PMState,
use_acpi_pci_hotplug, true), use_acpi_hotplug_bridge, true),
DEFINE_PROP_BOOL("memory-hotplug-support", PIIX4PMState, DEFINE_PROP_BOOL("memory-hotplug-support", PIIX4PMState,
acpi_memory_hotplug.is_enabled, true), acpi_memory_hotplug.is_enabled, true),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),

View File

@ -46,6 +46,7 @@
#include "hw/pci/pci.h" #include "hw/pci/pci.h"
#include "hw/arm/virt.h" #include "hw/arm/virt.h"
#include "hw/mem/nvdimm.h" #include "hw/mem/nvdimm.h"
#include "hw/platform-bus.h"
#include "sysemu/numa.h" #include "sysemu/numa.h"
#include "sysemu/reset.h" #include "sysemu/reset.h"
#include "sysemu/tpm.h" #include "sysemu/tpm.h"
@ -364,6 +365,38 @@ static void acpi_dsdt_add_power_button(Aml *scope)
aml_append(scope, dev); aml_append(scope, dev);
} }
static void acpi_dsdt_add_tpm(Aml *scope, VirtMachineState *vms)
{
PlatformBusDevice *pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev);
hwaddr pbus_base = vms->memmap[VIRT_PLATFORM_BUS].base;
SysBusDevice *sbdev = SYS_BUS_DEVICE(tpm_find());
MemoryRegion *sbdev_mr;
hwaddr tpm_base;
if (!sbdev) {
return;
}
tpm_base = platform_bus_get_mmio_addr(pbus, sbdev, 0);
assert(tpm_base != -1);
tpm_base += pbus_base;
sbdev_mr = sysbus_mmio_get_region(sbdev, 0);
Aml *dev = aml_device("TPM0");
aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101")));
aml_append(dev, aml_name_decl("_UID", aml_int(0)));
Aml *crs = aml_resource_template();
aml_append(crs,
aml_memory32_fixed(tpm_base,
(uint32_t)memory_region_size(sbdev_mr),
AML_READ_WRITE));
aml_append(dev, aml_name_decl("_CRS", crs));
aml_append(scope, dev);
}
static void static void
build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
{ {
@ -762,6 +795,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
} }
acpi_dsdt_add_power_button(scope); acpi_dsdt_add_power_button(scope);
acpi_dsdt_add_tpm(scope, vms);
aml_append(dsdt, scope); aml_append(dsdt, scope);

View File

@ -32,6 +32,7 @@
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qemu/timer.h" #include "qemu/timer.h"
#include "hw/acpi/aml-build.h"
#include "hw/irq.h" #include "hw/irq.h"
#include "hw/isa/isa.h" #include "hw/isa/isa.h"
#include "hw/qdev-properties.h" #include "hw/qdev-properties.h"
@ -2753,8 +2754,8 @@ FloppyDriveType isa_fdc_get_drive_type(ISADevice *fdc, int i)
return isa->state.drives[i].drive; return isa->state.drives[i].drive;
} }
void isa_fdc_get_drive_max_chs(FloppyDriveType type, static void isa_fdc_get_drive_max_chs(FloppyDriveType type, uint8_t *maxc,
uint8_t *maxc, uint8_t *maxh, uint8_t *maxs) uint8_t *maxh, uint8_t *maxs)
{ {
const FDFormat *fdf; const FDFormat *fdf;
@ -2776,6 +2777,110 @@ void isa_fdc_get_drive_max_chs(FloppyDriveType type,
(*maxc)--; (*maxc)--;
} }
static Aml *build_fdinfo_aml(int idx, FloppyDriveType type)
{
Aml *dev, *fdi;
uint8_t maxc, maxh, maxs;
isa_fdc_get_drive_max_chs(type, &maxc, &maxh, &maxs);
dev = aml_device("FLP%c", 'A' + idx);
aml_append(dev, aml_name_decl("_ADR", aml_int(idx)));
fdi = aml_package(16);
aml_append(fdi, aml_int(idx)); /* Drive Number */
aml_append(fdi,
aml_int(cmos_get_fd_drive_type(type))); /* Device Type */
/*
* the values below are the limits of the drive, and are thus independent
* of the inserted media
*/
aml_append(fdi, aml_int(maxc)); /* Maximum Cylinder Number */
aml_append(fdi, aml_int(maxs)); /* Maximum Sector Number */
aml_append(fdi, aml_int(maxh)); /* Maximum Head Number */
/*
* SeaBIOS returns the below values for int 0x13 func 0x08 regardless of
* the drive type, so shall we
*/
aml_append(fdi, aml_int(0xAF)); /* disk_specify_1 */
aml_append(fdi, aml_int(0x02)); /* disk_specify_2 */
aml_append(fdi, aml_int(0x25)); /* disk_motor_wait */
aml_append(fdi, aml_int(0x02)); /* disk_sector_siz */
aml_append(fdi, aml_int(0x12)); /* disk_eot */
aml_append(fdi, aml_int(0x1B)); /* disk_rw_gap */
aml_append(fdi, aml_int(0xFF)); /* disk_dtl */
aml_append(fdi, aml_int(0x6C)); /* disk_formt_gap */
aml_append(fdi, aml_int(0xF6)); /* disk_fill */
aml_append(fdi, aml_int(0x0F)); /* disk_head_sttl */
aml_append(fdi, aml_int(0x08)); /* disk_motor_strt */
aml_append(dev, aml_name_decl("_FDI", fdi));
return dev;
}
int cmos_get_fd_drive_type(FloppyDriveType fd0)
{
int val;
switch (fd0) {
case FLOPPY_DRIVE_TYPE_144:
/* 1.44 Mb 3"5 drive */
val = 4;
break;
case FLOPPY_DRIVE_TYPE_288:
/* 2.88 Mb 3"5 drive */
val = 5;
break;
case FLOPPY_DRIVE_TYPE_120:
/* 1.2 Mb 5"5 drive */
val = 2;
break;
case FLOPPY_DRIVE_TYPE_NONE:
default:
val = 0;
break;
}
return val;
}
static void fdc_isa_build_aml(ISADevice *isadev, Aml *scope)
{
Aml *dev;
Aml *crs;
int i;
#define ACPI_FDE_MAX_FD 4
uint32_t fde_buf[5] = {
0, 0, 0, 0, /* presence of floppy drives #0 - #3 */
cpu_to_le32(2) /* tape presence (2 == never present) */
};
crs = aml_resource_template();
aml_append(crs, aml_io(AML_DECODE16, 0x03F2, 0x03F2, 0x00, 0x04));
aml_append(crs, aml_io(AML_DECODE16, 0x03F7, 0x03F7, 0x00, 0x01));
aml_append(crs, aml_irq_no_flags(6));
aml_append(crs,
aml_dma(AML_COMPATIBILITY, AML_NOTBUSMASTER, AML_TRANSFER8, 2));
dev = aml_device("FDC0");
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0700")));
aml_append(dev, aml_name_decl("_CRS", crs));
for (i = 0; i < MIN(MAX_FD, ACPI_FDE_MAX_FD); i++) {
FloppyDriveType type = isa_fdc_get_drive_type(isadev, i);
if (type < FLOPPY_DRIVE_TYPE_NONE) {
fde_buf[i] = cpu_to_le32(1); /* drive present */
aml_append(dev, build_fdinfo_aml(i, type));
}
}
aml_append(dev, aml_name_decl("_FDE",
aml_buffer(sizeof(fde_buf), (uint8_t *)fde_buf)));
aml_append(scope, dev);
}
static const VMStateDescription vmstate_isa_fdc ={ static const VMStateDescription vmstate_isa_fdc ={
.name = "fdc", .name = "fdc",
.version_id = 2, .version_id = 2,
@ -2809,11 +2914,13 @@ static Property isa_fdc_properties[] = {
static void isabus_fdc_class_init(ObjectClass *klass, void *data) static void isabus_fdc_class_init(ObjectClass *klass, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
ISADeviceClass *isa = ISA_DEVICE_CLASS(klass);
dc->realize = isabus_fdc_realize; dc->realize = isabus_fdc_realize;
dc->fw_name = "fdc"; dc->fw_name = "fdc";
dc->reset = fdctrl_external_reset_isa; dc->reset = fdctrl_external_reset_isa;
dc->vmsd = &vmstate_isa_fdc; dc->vmsd = &vmstate_isa_fdc;
isa->build_aml = fdc_isa_build_aml;
device_class_set_props(dc, isa_fdc_properties); device_class_set_props(dc, isa_fdc_properties);
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
} }

View File

@ -938,121 +938,6 @@ static void build_hpet_aml(Aml *table)
aml_append(table, scope); aml_append(table, scope);
} }
static Aml *build_fdinfo_aml(int idx, FloppyDriveType type)
{
Aml *dev, *fdi;
uint8_t maxc, maxh, maxs;
isa_fdc_get_drive_max_chs(type, &maxc, &maxh, &maxs);
dev = aml_device("FLP%c", 'A' + idx);
aml_append(dev, aml_name_decl("_ADR", aml_int(idx)));
fdi = aml_package(16);
aml_append(fdi, aml_int(idx)); /* Drive Number */
aml_append(fdi,
aml_int(cmos_get_fd_drive_type(type))); /* Device Type */
/*
* the values below are the limits of the drive, and are thus independent
* of the inserted media
*/
aml_append(fdi, aml_int(maxc)); /* Maximum Cylinder Number */
aml_append(fdi, aml_int(maxs)); /* Maximum Sector Number */
aml_append(fdi, aml_int(maxh)); /* Maximum Head Number */
/*
* SeaBIOS returns the below values for int 0x13 func 0x08 regardless of
* the drive type, so shall we
*/
aml_append(fdi, aml_int(0xAF)); /* disk_specify_1 */
aml_append(fdi, aml_int(0x02)); /* disk_specify_2 */
aml_append(fdi, aml_int(0x25)); /* disk_motor_wait */
aml_append(fdi, aml_int(0x02)); /* disk_sector_siz */
aml_append(fdi, aml_int(0x12)); /* disk_eot */
aml_append(fdi, aml_int(0x1B)); /* disk_rw_gap */
aml_append(fdi, aml_int(0xFF)); /* disk_dtl */
aml_append(fdi, aml_int(0x6C)); /* disk_formt_gap */
aml_append(fdi, aml_int(0xF6)); /* disk_fill */
aml_append(fdi, aml_int(0x0F)); /* disk_head_sttl */
aml_append(fdi, aml_int(0x08)); /* disk_motor_strt */
aml_append(dev, aml_name_decl("_FDI", fdi));
return dev;
}
static Aml *build_fdc_device_aml(ISADevice *fdc)
{
int i;
Aml *dev;
Aml *crs;
#define ACPI_FDE_MAX_FD 4
uint32_t fde_buf[5] = {
0, 0, 0, 0, /* presence of floppy drives #0 - #3 */
cpu_to_le32(2) /* tape presence (2 == never present) */
};
dev = aml_device("FDC0");
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0700")));
crs = aml_resource_template();
aml_append(crs, aml_io(AML_DECODE16, 0x03F2, 0x03F2, 0x00, 0x04));
aml_append(crs, aml_io(AML_DECODE16, 0x03F7, 0x03F7, 0x00, 0x01));
aml_append(crs, aml_irq_no_flags(6));
aml_append(crs,
aml_dma(AML_COMPATIBILITY, AML_NOTBUSMASTER, AML_TRANSFER8, 2));
aml_append(dev, aml_name_decl("_CRS", crs));
for (i = 0; i < MIN(MAX_FD, ACPI_FDE_MAX_FD); i++) {
FloppyDriveType type = isa_fdc_get_drive_type(fdc, i);
if (type < FLOPPY_DRIVE_TYPE_NONE) {
fde_buf[i] = cpu_to_le32(1); /* drive present */
aml_append(dev, build_fdinfo_aml(i, type));
}
}
aml_append(dev, aml_name_decl("_FDE",
aml_buffer(sizeof(fde_buf), (uint8_t *)fde_buf)));
return dev;
}
static Aml *build_kbd_device_aml(void)
{
Aml *dev;
Aml *crs;
dev = aml_device("KBD");
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0303")));
aml_append(dev, aml_name_decl("_STA", aml_int(0xf)));
crs = aml_resource_template();
aml_append(crs, aml_io(AML_DECODE16, 0x0060, 0x0060, 0x01, 0x01));
aml_append(crs, aml_io(AML_DECODE16, 0x0064, 0x0064, 0x01, 0x01));
aml_append(crs, aml_irq_no_flags(1));
aml_append(dev, aml_name_decl("_CRS", crs));
return dev;
}
static Aml *build_mouse_device_aml(void)
{
Aml *dev;
Aml *crs;
dev = aml_device("MOU");
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0F13")));
aml_append(dev, aml_name_decl("_STA", aml_int(0xf)));
crs = aml_resource_template();
aml_append(crs, aml_irq_no_flags(12));
aml_append(dev, aml_name_decl("_CRS", crs));
return dev;
}
static Aml *build_vmbus_device_aml(VMBusBridge *vmbus_bridge) static Aml *build_vmbus_device_aml(VMBusBridge *vmbus_bridge)
{ {
Aml *dev; Aml *dev;
@ -1092,27 +977,16 @@ static Aml *build_vmbus_device_aml(VMBusBridge *vmbus_bridge)
static void build_isa_devices_aml(Aml *table) static void build_isa_devices_aml(Aml *table)
{ {
ISADevice *fdc = pc_find_fdc0();
VMBusBridge *vmbus_bridge = vmbus_bridge_find(); VMBusBridge *vmbus_bridge = vmbus_bridge_find();
bool ambiguous; bool ambiguous;
Aml *scope = aml_scope("_SB.PCI0.ISA");
Object *obj = object_resolve_path_type("", TYPE_ISA_BUS, &ambiguous); Object *obj = object_resolve_path_type("", TYPE_ISA_BUS, &ambiguous);
Aml *scope;
aml_append(scope, build_kbd_device_aml()); assert(obj && !ambiguous);
aml_append(scope, build_mouse_device_aml());
if (fdc) {
aml_append(scope, build_fdc_device_aml(fdc));
}
if (ambiguous) { scope = aml_scope("_SB.PCI0.ISA");
error_report("Multiple ISA busses, unable to define IPMI ACPI data"); build_acpi_ipmi_devices(scope, BUS(obj), "\\_SB.PCI0.ISA");
} else if (!obj) { isa_build_aml(ISA_BUS(obj), scope);
error_report("No ISA bus, unable to define IPMI ACPI data");
} else {
build_acpi_ipmi_devices(scope, BUS(obj), "\\_SB.PCI0.ISA");
isa_build_aml(ISA_BUS(obj), scope);
}
if (vmbus_bridge) { if (vmbus_bridge) {
aml_append(scope, build_vmbus_device_aml(vmbus_bridge)); aml_append(scope, build_vmbus_device_aml(vmbus_bridge));
@ -1466,7 +1340,6 @@ static void build_q35_isa_bridge(Aml *table)
{ {
Aml *dev; Aml *dev;
Aml *scope; Aml *scope;
Aml *field;
scope = aml_scope("_SB.PCI0"); scope = aml_scope("_SB.PCI0");
dev = aml_device("ISA"); dev = aml_device("ISA");
@ -1476,40 +1349,6 @@ static void build_q35_isa_bridge(Aml *table)
aml_append(dev, aml_operation_region("PIRQ", AML_PCI_CONFIG, aml_append(dev, aml_operation_region("PIRQ", AML_PCI_CONFIG,
aml_int(0x60), 0x0C)); aml_int(0x60), 0x0C));
aml_append(dev, aml_operation_region("LPCD", AML_PCI_CONFIG,
aml_int(0x80), 0x02));
field = aml_field("LPCD", AML_ANY_ACC, AML_NOLOCK, AML_PRESERVE);
aml_append(field, aml_named_field("COMA", 3));
aml_append(field, aml_reserved_field(1));
aml_append(field, aml_named_field("COMB", 3));
aml_append(field, aml_reserved_field(1));
aml_append(field, aml_named_field("LPTD", 2));
aml_append(dev, field);
aml_append(dev, aml_operation_region("LPCE", AML_PCI_CONFIG,
aml_int(0x82), 0x02));
/* enable bits */
field = aml_field("LPCE", AML_ANY_ACC, AML_NOLOCK, AML_PRESERVE);
aml_append(field, aml_named_field("CAEN", 1));
aml_append(field, aml_named_field("CBEN", 1));
aml_append(field, aml_named_field("LPEN", 1));
aml_append(dev, field);
aml_append(scope, dev);
aml_append(table, scope);
}
static void build_piix4_pm(Aml *table)
{
Aml *dev;
Aml *scope;
scope = aml_scope("_SB.PCI0");
dev = aml_device("PX13");
aml_append(dev, aml_name_decl("_ADR", aml_int(0x00010003)));
aml_append(dev, aml_operation_region("P13C", AML_PCI_CONFIG,
aml_int(0x00), 0xff));
aml_append(scope, dev); aml_append(scope, dev);
aml_append(table, scope); aml_append(table, scope);
} }
@ -1518,7 +1357,6 @@ static void build_piix4_isa_bridge(Aml *table)
{ {
Aml *dev; Aml *dev;
Aml *scope; Aml *scope;
Aml *field;
scope = aml_scope("_SB.PCI0"); scope = aml_scope("_SB.PCI0");
dev = aml_device("ISA"); dev = aml_device("ISA");
@ -1527,19 +1365,6 @@ static void build_piix4_isa_bridge(Aml *table)
/* PIIX PCI to ISA irq remapping */ /* PIIX PCI to ISA irq remapping */
aml_append(dev, aml_operation_region("P40C", AML_PCI_CONFIG, aml_append(dev, aml_operation_region("P40C", AML_PCI_CONFIG,
aml_int(0x60), 0x04)); aml_int(0x60), 0x04));
/* enable bits */
field = aml_field("^PX13.P13C", AML_ANY_ACC, AML_NOLOCK, AML_PRESERVE);
/* Offset(0x5f),, 7, */
aml_append(field, aml_reserved_field(0x2f8));
aml_append(field, aml_reserved_field(7));
aml_append(field, aml_named_field("LPEN", 1));
/* Offset(0x67),, 3, */
aml_append(field, aml_reserved_field(0x38));
aml_append(field, aml_reserved_field(3));
aml_append(field, aml_named_field("CAEN", 1));
aml_append(field, aml_reserved_field(3));
aml_append(field, aml_named_field("CBEN", 1));
aml_append(dev, field);
aml_append(scope, dev); aml_append(scope, dev);
aml_append(table, scope); aml_append(table, scope);
@ -1679,7 +1504,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
aml_append(dsdt, sb_scope); aml_append(dsdt, sb_scope);
build_hpet_aml(dsdt); build_hpet_aml(dsdt);
build_piix4_pm(dsdt);
build_piix4_isa_bridge(dsdt); build_piix4_isa_bridge(dsdt);
build_isa_devices_aml(dsdt); build_isa_devices_aml(dsdt);
build_piix4_pci_hotplug(dsdt); build_piix4_pci_hotplug(dsdt);
@ -1924,30 +1748,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
/* create fw_cfg node, unconditionally */ /* create fw_cfg node, unconditionally */
{ {
/* when using port i/o, the 8-bit data register *always* overlaps
* with half of the 16-bit control register. Hence, the total size
* of the i/o region used is FW_CFG_CTL_SIZE; when using DMA, the
* DMA control register is located at FW_CFG_DMA_IO_BASE + 4 */
uint8_t io_size = object_property_get_bool(OBJECT(x86ms->fw_cfg),
"dma_enabled", NULL) ?
ROUND_UP(FW_CFG_CTL_SIZE, 4) + sizeof(dma_addr_t) :
FW_CFG_CTL_SIZE;
scope = aml_scope("\\_SB.PCI0"); scope = aml_scope("\\_SB.PCI0");
dev = aml_device("FWCF"); fw_cfg_add_acpi_dsdt(scope, x86ms->fw_cfg);
aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0002")));
/* device present, functioning, decoding, not shown in UI */
aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
crs = aml_resource_template();
aml_append(crs,
aml_io(AML_DECODE16, FW_CFG_IO_BASE, FW_CFG_IO_BASE, 0x01, io_size)
);
aml_append(dev, aml_name_decl("_CRS", crs));
aml_append(scope, dev);
aml_append(dsdt, scope); aml_append(dsdt, scope);
} }

View File

@ -15,6 +15,7 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "sysemu/numa.h" #include "sysemu/numa.h"
#include "hw/acpi/acpi.h" #include "hw/acpi/acpi.h"
#include "hw/acpi/aml-build.h"
#include "hw/firmware/smbios.h" #include "hw/firmware/smbios.h"
#include "hw/i386/fw_cfg.h" #include "hw/i386/fw_cfg.h"
#include "hw/timer/hpet.h" #include "hw/timer/hpet.h"
@ -179,3 +180,30 @@ void fw_cfg_build_feature_control(MachineState *ms, FWCfgState *fw_cfg)
*val = cpu_to_le64(feature_control_bits | FEATURE_CONTROL_LOCKED); *val = cpu_to_le64(feature_control_bits | FEATURE_CONTROL_LOCKED);
fw_cfg_add_file(fw_cfg, "etc/msr_feature_control", val, sizeof(*val)); fw_cfg_add_file(fw_cfg, "etc/msr_feature_control", val, sizeof(*val));
} }
void fw_cfg_add_acpi_dsdt(Aml *scope, FWCfgState *fw_cfg)
{
/*
* when using port i/o, the 8-bit data register *always* overlaps
* with half of the 16-bit control register. Hence, the total size
* of the i/o region used is FW_CFG_CTL_SIZE; when using DMA, the
* DMA control register is located at FW_CFG_DMA_IO_BASE + 4
*/
Object *obj = OBJECT(fw_cfg);
uint8_t io_size = object_property_get_bool(obj, "dma_enabled", NULL) ?
ROUND_UP(FW_CFG_CTL_SIZE, 4) + sizeof(dma_addr_t) :
FW_CFG_CTL_SIZE;
Aml *dev = aml_device("FWCF");
Aml *crs = aml_resource_template();
aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0002")));
/* device present, functioning, decoding, not shown in UI */
aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
aml_append(crs,
aml_io(AML_DECODE16, FW_CFG_IO_BASE, FW_CFG_IO_BASE, 0x01, io_size));
aml_append(dev, aml_name_decl("_CRS", crs));
aml_append(scope, dev);
}

View File

@ -25,5 +25,6 @@ FWCfgState *fw_cfg_arch_create(MachineState *ms,
uint16_t apic_id_limit); uint16_t apic_id_limit);
void fw_cfg_build_smbios(MachineState *ms, FWCfgState *fw_cfg); void fw_cfg_build_smbios(MachineState *ms, FWCfgState *fw_cfg);
void fw_cfg_build_feature_control(MachineState *ms, FWCfgState *fw_cfg); void fw_cfg_build_feature_control(MachineState *ms, FWCfgState *fw_cfg);
void fw_cfg_add_acpi_dsdt(Aml *scope, FWCfgState *fw_cfg);
#endif #endif

View File

@ -386,31 +386,6 @@ static uint64_t ioportF0_read(void *opaque, hwaddr addr, unsigned size)
#define REG_EQUIPMENT_BYTE 0x14 #define REG_EQUIPMENT_BYTE 0x14
int cmos_get_fd_drive_type(FloppyDriveType fd0)
{
int val;
switch (fd0) {
case FLOPPY_DRIVE_TYPE_144:
/* 1.44 Mb 3"5 drive */
val = 4;
break;
case FLOPPY_DRIVE_TYPE_288:
/* 2.88 Mb 3"5 drive */
val = 5;
break;
case FLOPPY_DRIVE_TYPE_120:
/* 1.2 Mb 5"5 drive */
val = 2;
break;
case FLOPPY_DRIVE_TYPE_NONE:
default:
val = 0;
break;
}
return val;
}
static void cmos_init_hd(ISADevice *s, int type_ofs, int info_ofs, static void cmos_init_hd(ISADevice *s, int type_ofs, int info_ofs,
int16_t cylinders, int8_t heads, int8_t sectors) int16_t cylinders, int8_t heads, int8_t sectors)
{ {

View File

@ -26,6 +26,7 @@
#include "qemu/log.h" #include "qemu/log.h"
#include "hw/isa/isa.h" #include "hw/isa/isa.h"
#include "migration/vmstate.h" #include "migration/vmstate.h"
#include "hw/acpi/aml-build.h"
#include "hw/input/ps2.h" #include "hw/input/ps2.h"
#include "hw/irq.h" #include "hw/irq.h"
#include "hw/input/i8042.h" #include "hw/input/i8042.h"
@ -561,12 +562,42 @@ static void i8042_realizefn(DeviceState *dev, Error **errp)
qemu_register_reset(kbd_reset, s); qemu_register_reset(kbd_reset, s);
} }
static void i8042_build_aml(ISADevice *isadev, Aml *scope)
{
Aml *kbd;
Aml *mou;
Aml *crs;
crs = aml_resource_template();
aml_append(crs, aml_io(AML_DECODE16, 0x0060, 0x0060, 0x01, 0x01));
aml_append(crs, aml_io(AML_DECODE16, 0x0064, 0x0064, 0x01, 0x01));
aml_append(crs, aml_irq_no_flags(1));
kbd = aml_device("KBD");
aml_append(kbd, aml_name_decl("_HID", aml_eisaid("PNP0303")));
aml_append(kbd, aml_name_decl("_STA", aml_int(0xf)));
aml_append(kbd, aml_name_decl("_CRS", crs));
crs = aml_resource_template();
aml_append(crs, aml_irq_no_flags(12));
mou = aml_device("MOU");
aml_append(mou, aml_name_decl("_HID", aml_eisaid("PNP0F13")));
aml_append(mou, aml_name_decl("_STA", aml_int(0xf)));
aml_append(mou, aml_name_decl("_CRS", crs));
aml_append(scope, kbd);
aml_append(scope, mou);
}
static void i8042_class_initfn(ObjectClass *klass, void *data) static void i8042_class_initfn(ObjectClass *klass, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
ISADeviceClass *isa = ISA_DEVICE_CLASS(klass);
dc->realize = i8042_realizefn; dc->realize = i8042_realizefn;
dc->vmsd = &vmstate_kbd_isa; dc->vmsd = &vmstate_kbd_isa;
isa->build_aml = i8042_build_aml;
set_bit(DEVICE_CATEGORY_INPUT, dc->categories); set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
} }

View File

@ -460,12 +460,14 @@ static MemoryRegion *vhost_user_get_mr_data(uint64_t addr, ram_addr_t *offset,
} }
static void vhost_user_fill_msg_region(VhostUserMemoryRegion *dst, static void vhost_user_fill_msg_region(VhostUserMemoryRegion *dst,
struct vhost_memory_region *src) struct vhost_memory_region *src,
uint64_t mmap_offset)
{ {
assert(src != NULL && dst != NULL); assert(src != NULL && dst != NULL);
dst->userspace_addr = src->userspace_addr; dst->userspace_addr = src->userspace_addr;
dst->memory_size = src->memory_size; dst->memory_size = src->memory_size;
dst->guest_phys_addr = src->guest_phys_addr; dst->guest_phys_addr = src->guest_phys_addr;
dst->mmap_offset = mmap_offset;
} }
static int vhost_user_fill_set_mem_table_msg(struct vhost_user *u, static int vhost_user_fill_set_mem_table_msg(struct vhost_user *u,
@ -500,9 +502,8 @@ static int vhost_user_fill_set_mem_table_msg(struct vhost_user *u,
error_report("Failed preparing vhost-user memory table msg"); error_report("Failed preparing vhost-user memory table msg");
return -1; return -1;
} }
vhost_user_fill_msg_region(&region_buffer, reg); vhost_user_fill_msg_region(&region_buffer, reg, offset);
msg->payload.memory.regions[*fd_num] = region_buffer; msg->payload.memory.regions[*fd_num] = region_buffer;
msg->payload.memory.regions[*fd_num].mmap_offset = offset;
fds[(*fd_num)++] = fd; fds[(*fd_num)++] = fd;
} else if (track_ramblocks) { } else if (track_ramblocks) {
u->region_rb_offset[i] = 0; u->region_rb_offset[i] = 0;
@ -649,7 +650,7 @@ static int send_remove_regions(struct vhost_dev *dev,
if (fd > 0) { if (fd > 0) {
msg->hdr.request = VHOST_USER_REM_MEM_REG; msg->hdr.request = VHOST_USER_REM_MEM_REG;
vhost_user_fill_msg_region(&region_buffer, shadow_reg); vhost_user_fill_msg_region(&region_buffer, shadow_reg, 0);
msg->payload.mem_reg.region = region_buffer; msg->payload.mem_reg.region = region_buffer;
if (vhost_user_write(dev, msg, &fd, 1) < 0) { if (vhost_user_write(dev, msg, &fd, 1) < 0) {
@ -709,9 +710,8 @@ static int send_add_regions(struct vhost_dev *dev,
u->region_rb[reg_idx] = mr->ram_block; u->region_rb[reg_idx] = mr->ram_block;
} }
msg->hdr.request = VHOST_USER_ADD_MEM_REG; msg->hdr.request = VHOST_USER_ADD_MEM_REG;
vhost_user_fill_msg_region(&region_buffer, reg); vhost_user_fill_msg_region(&region_buffer, reg, offset);
msg->payload.mem_reg.region = region_buffer; msg->payload.mem_reg.region = region_buffer;
msg->payload.mem_reg.region.mmap_offset = offset;
if (vhost_user_write(dev, msg, &fd, 1) < 0) { if (vhost_user_write(dev, msg, &fd, 1) < 0) {
return -1; return -1;

View File

@ -465,24 +465,6 @@ struct Acpi20Tcpa {
} QEMU_PACKED; } QEMU_PACKED;
typedef struct Acpi20Tcpa Acpi20Tcpa; typedef struct Acpi20Tcpa Acpi20Tcpa;
/*
* TPM2
*
* Following Version 1.2, Revision 8 of specs:
* https://trustedcomputinggroup.org/tcg-acpi-specification/
*/
struct Acpi20TPM2 {
ACPI_TABLE_HEADER_DEF
uint16_t platform_class;
uint16_t reserved;
uint64_t control_area_address;
uint32_t start_method;
uint8_t start_method_params[12];
uint32_t log_area_minimum_length;
uint64_t log_area_start_address;
} QEMU_PACKED;
typedef struct Acpi20TPM2 Acpi20TPM2;
/* DMAR - DMA Remapping table r2.2 */ /* DMAR - DMA Remapping table r2.2 */
struct AcpiTableDmar { struct AcpiTableDmar {
ACPI_TABLE_HEADER_DEF ACPI_TABLE_HEADER_DEF

View File

@ -16,7 +16,6 @@ void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base,
DriveInfo **fds, qemu_irq *fdc_tc); DriveInfo **fds, qemu_irq *fdc_tc);
FloppyDriveType isa_fdc_get_drive_type(ISADevice *fdc, int i); FloppyDriveType isa_fdc_get_drive_type(ISADevice *fdc, int i);
void isa_fdc_get_drive_max_chs(FloppyDriveType type, int cmos_get_fd_drive_type(FloppyDriveType fd0);
uint8_t *maxc, uint8_t *maxh, uint8_t *maxs);
#endif #endif

View File

@ -178,7 +178,6 @@ typedef void (*cpu_set_smm_t)(int smm, void *arg);
void pc_i8259_create(ISABus *isa_bus, qemu_irq *i8259_irqs); void pc_i8259_create(ISABus *isa_bus, qemu_irq *i8259_irqs);
ISADevice *pc_find_fdc0(void); ISADevice *pc_find_fdc0(void);
int cmos_get_fd_drive_type(FloppyDriveType fd0);
/* port92.c */ /* port92.c */
#define PORT92_A20_LINE "a20" #define PORT92_A20_LINE "a20"

View File

@ -1,4 +1,5 @@
stub-obj-y += blk-commit-all.o stub-obj-y += blk-commit-all.o
stub-obj-y += cmos.o
stub-obj-y += cpu-get-clock.o stub-obj-y += cpu-get-clock.o
stub-obj-y += cpu-get-icount.o stub-obj-y += cpu-get-icount.o
stub-obj-y += dump.o stub-obj-y += dump.o

7
stubs/cmos.c Normal file
View File

@ -0,0 +1,7 @@
#include "qemu/osdep.h"
#include "hw/i386/pc.h"
int cmos_get_fd_drive_type(FloppyDriveType fd0)
{
return 0;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1 +1,19 @@
/* List of comma-separated changed AML files to ignore */ /* List of comma-separated changed AML files to ignore */
"tests/data/acpi/pc/DSDT",
"tests/data/acpi/pc/DSDT.acpihmat",
"tests/data/acpi/pc/DSDT.bridge",
"tests/data/acpi/pc/DSDT.cphp",
"tests/data/acpi/pc/DSDT.dimmpxm",
"tests/data/acpi/pc/DSDT.ipmikcs",
"tests/data/acpi/pc/DSDT.memhp",
"tests/data/acpi/pc/DSDT.numamem",
"tests/data/acpi/q35/DSDT",
"tests/data/acpi/q35/DSDT.acpihmat",
"tests/data/acpi/q35/DSDT.bridge",
"tests/data/acpi/q35/DSDT.cphp",
"tests/data/acpi/q35/DSDT.dimmpxm",
"tests/data/acpi/q35/DSDT.ipmibt",
"tests/data/acpi/q35/DSDT.memhp",
"tests/data/acpi/q35/DSDT.mmio64",
"tests/data/acpi/q35/DSDT.numamem",
"tests/data/acpi/q35/DSDT.tis",

View File

@ -469,7 +469,7 @@ static void test_acpi_asl(test_data *data)
fflush(stderr); fflush(stderr);
if (getenv("V")) { if (getenv("V")) {
const char *diff_env = getenv("DIFF"); const char *diff_env = getenv("DIFF");
const char *diff_cmd = diff_env ? diff_env : "diff -u"; const char *diff_cmd = diff_env ? diff_env : "diff -U 16";
char *diff = g_strdup_printf("%s %s %s", diff_cmd, char *diff = g_strdup_printf("%s %s %s", diff_cmd,
exp_sdt->asl_file, sdt->asl_file); exp_sdt->asl_file, sdt->asl_file);
int out = dup(STDOUT_FILENO); int out = dup(STDOUT_FILENO);