On 09/10/2025 06:55, Damien Zammit wrote:
It will be necessary to make acpi server call the \_PIC method since
it has access to the acpi low level functions.
I've attached a patch to libapcica to set the \_PIC ACPI method. To
function it requires the support of Damien's recent patch to gnumach to
provide the status of IRQGETPICMODE of the irq device
(https://lists.gnu.org/archive/html/bug-hurd/2025-10/msg00061.html). In
the event that IRQGETPICMODE is not available then the code still
operates like currently.
I initially added this code to the acpi server itself but there is an
interrupt handler installed during the ACPI initialisation and I felt it
was safer to configure \_PIC before that point. That required moving the
code into libacpica.
Application of this patch permits the ACPI tables to return correct GSIs
for when PIC or IOAPIC is in use. The patch does alter the GSIs that are
used for interrupts in Qemu as well so it is likely to make adjustments
to many system installations. I can appreciate that you might prefer
additional successful testing before wide spread deployment.
The whole PIC/IOAPIC concept is architecture specific so I suppose at
some point it would have to be factored out accordingly.
Cheers,
Mike.
diff -ur libacpica.orig/acpi_init.c libacpica/acpi_init.c
--- libacpica.orig/acpi_init.c 2025-10-11 11:20:29.000000000 +0100
+++ libacpica/acpi_init.c 2025-10-11 11:51:48.972990987 +0100
@@ -697,6 +697,98 @@
return -EIO;
}
+#define IRQGETPICMODE 0
+# define ACPI_PICMODE_PIC 0
+# define ACPI_PICMODE_APIC 1
+# define ACPI_PICMODE_SAPIC 2
+
+/* Fetch the active interrupt mode from GNU mach */
+static error_t
+acpi_required_pic_mode (int* pic_mode)
+{
+ mach_port_t devices, irq;
+ mach_msg_type_number_t cnt = 0;
+
+ error_t err = get_privileged_ports(NULL, &devices);
+ if (err)
+ return err;
+
+ if (devices == MACH_PORT_NULL)
+ return ENODEV;
+
+ err = device_open(devices, D_READ, "irq", &irq);
+ if (!err)
+ {
+ /* Determine if the IRQGETPICMODE feature is available in the
+ running kernel by specifying a NULL array for 'status'. If
+ the feature is available then MIG_ARRAY_TOO_LARGE is returned
+ as the returned status cannot fit in the result.
+ */
+ if (device_get_status(irq, IRQGETPICMODE, NULL, &cnt)
+ != MIG_ARRAY_TOO_LARGE)
+ {
+ err = ENOSYS;
+ }
+ else
+ {
+ cnt = 1;
+ err = device_get_status(irq, IRQGETPICMODE, pic_mode, &cnt);
+ }
+
+ device_close(irq);
+ }
+
+ mach_port_deallocate (mach_task_self (), devices);
+
+ return err;
+}
+
+static error_t
+acpi_set_pic_mode (int pic_mode)
+{
+ struct acpi_object_list arg;
+ union acpi_object obj;
+
+ if (pic_mode < ACPI_PICMODE_PIC || pic_mode > ACPI_PICMODE_SAPIC)
+ return EINVAL;
+
+ obj.type = ACPI_TYPE_INTEGER;
+ obj.integer.value = pic_mode;
+
+ arg.count = 1;
+ arg.pointer = &obj;
+
+ acpi_handle handle = ACPI_ROOT_OBJECT;
+ acpi_status rv = acpi_evaluate_object(handle, "\\_PIC", &arg, NULL);
+
+ /* A failure of AE_NOT_FOUND means the \_PIC method is not supported.
+ The default for the system in this case is ACPI_PICMODE_PIC, so
+ it is only a concern if an attempt is made to set a different mode.
+ */
+ return (ACPI_FAILURE(rv)
+ && (rv != AE_NOT_FOUND || (pic_mode != ACPI_PICMODE_PIC))
+ ? EIO
+ : 0);
+}
+
+/* Configuration errors treated as warnings rather than being fatal */
+static void
+acpi_configure_pic_mode (void)
+{
+ int pic_mode;
+ error_t err = acpi_required_pic_mode (&pic_mode);
+
+ if (err)
+ acpi_os_printf("Cannot determine PIC mode: %s\n", strerror(err));
+ else
+ {
+ err = acpi_set_pic_mode (pic_mode);
+
+ if (err)
+ acpi_os_printf("Failed to set ACPI PIC mode: %s\n", strerror(err));
+ }
+}
+
void acpi_init(void)
{
acpi_status err;
@@ -720,6 +812,8 @@
if (ACPI_FAILURE (err))
goto die;
+ acpi_configure_pic_mode();
+
err = acpi_enable_subsystem (ACPI_FULL_INITIALIZATION);
if (ACPI_FAILURE (err))
goto die;