> From: Theo de Raadt <dera...@cvs.openbsd.org> > Date: Sat, 22 Feb 2014 09:55:41 -0700 > > This menas the acpitz bug must be found, and fixed. You need to reach > out to an acpi hacker, like pirofti, to help diagnose the AML issue > which underlies this.
I had a quick look at the AML and it looks is if the embedded controller is involved in reading the temperature. Perhaps SMM is touching it behind our back, so I looked at the global lock code again that is supposed to protect against that happening. Noticed that acpiec(4) tries to acquire the global lock, but doesn't actually check whether it got it. The diff below fixes this by unifying the code that checks for recursion and does the spinning. Might fix things, or might lock up the machine solidly. Only one way to find out... If this doesn't help, you should check whether memory at the following addresses: 0xDAF7CE18 0xDAF9EF18 0xDAF7ADC0 0xDAF79F98 isn't actually marked as available by the BIOS. ACPI apparently stored important data at those addresses, but if OpenBSD thinks that memory is available and overwrites things, bad things will happen. I believe the easiest way to find out is to type "machine memory" at the boot> prompt. Index: dsdt.c =================================================================== RCS file: /cvs/src/sys/dev/acpi/dsdt.c,v retrieving revision 1.205 diff -u -p -r1.205 dsdt.c --- dsdt.c 12 Dec 2013 20:56:01 -0000 1.205 +++ dsdt.c 22 Feb 2014 18:03:16 -0000 @@ -736,72 +736,58 @@ static long global_lock_count = 0; void acpi_glk_enter(void) { - acpi_acquire_glk(&acpi_softc->sc_facs->global_lock); -} - -void -acpi_glk_leave(void) -{ - int x; - - if (acpi_release_glk(&acpi_softc->sc_facs->global_lock)) { - /* - * If pending, notify the BIOS that the lock was released - * by the OSPM. No locking is needed because nobody outside - * the ACPI thread is touching this register. - */ - x = acpi_read_pmreg(acpi_softc, ACPIREG_PM1_CNT, 0); - x |= ACPI_PM1_GBL_RLS; - acpi_write_pmreg(acpi_softc, ACPIREG_PM1_CNT, 0, x); - } -} - -void -aml_lockfield(struct aml_scope *scope, struct aml_value *field) -{ int st = 0; - if (AML_FIELD_LOCK(field->v_field.flags) != AML_FIELD_LOCK_ON) - return; - - /* If lock is already ours, just continue */ + /* If lock is already ours, just continue. */ if (global_lock_count++) return; - /* Spin to acquire lock */ + /* Spin to acquire the lock. */ while (!st) { st = acpi_acquire_glk(&acpi_softc->sc_facs->global_lock); /* XXX - yield/delay? */ } - - return; } void -aml_unlockfield(struct aml_scope *scope, struct aml_value *field) +acpi_glk_leave(void) { - int st, x, s; + int st, x; - if (AML_FIELD_LOCK(field->v_field.flags) != AML_FIELD_LOCK_ON) - return; - - /* If we are the last ones, turn out the lights */ + /* If we are the last one, turn out the lights. */ if (--global_lock_count) return; - /* Release lock */ st = acpi_release_glk(&acpi_softc->sc_facs->global_lock); if (!st) return; - /* Signal others if someone waiting */ - s = spltty(); + /* + * If pending, notify the BIOS that the lock was released by + * OSPM. No locking is needed because nobody outside the ACPI + * thread is supposed to touch this register. + */ x = acpi_read_pmreg(acpi_softc, ACPIREG_PM1_CNT, 0); x |= ACPI_PM1_GBL_RLS; acpi_write_pmreg(acpi_softc, ACPIREG_PM1_CNT, 0, x); - splx(s); +} + +void +aml_lockfield(struct aml_scope *scope, struct aml_value *field) +{ + if (AML_FIELD_LOCK(field->v_field.flags) != AML_FIELD_LOCK_ON) + return; + + acpi_glk_enter(); +} + +void +aml_unlockfield(struct aml_scope *scope, struct aml_value *field) +{ + if (AML_FIELD_LOCK(field->v_field.flags) != AML_FIELD_LOCK_ON) + return; - return; + acpi_glk_leave(); } /*