LDLS: every MDIO read was RFLAGS; ACPI: an Embedded Controller
On the TUF A15 Linux's r8169 found its PHY and read its ID as 0x02460246. mdio-bus keeps the register it has just read in r11 across preempt_enable(), which on x86 is `decl %gs:__preempt_count; je` to a call that preserves every register. LDLS gave __preempt_count zeroes, so the count reached zero and the call was made -- to a logging stub, whose syscall left RFLAGS (0x246) in r11. __preempt_count now starts at PREEMPT_ENABLED (x86 keeps NEED_RESCHED inverted), and preempt_schedule and its notrace twin are a bare ret. The same laptop reported its battery full and on AC, unplugged. The EC owns both, and with no EmbeddedControl handler _REG never told the firmware the EC was usable, so _BST and _PSR answered their fallbacks. The EC is found by PNP0C09 or the ECDT and served by the ACPI 12.3 byte protocol, installed before _INI. SCI queries are not handled yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
parent
3676036762
commit
d437e42b49
3 changed files with 179 additions and 1 deletions
|
|
@ -835,6 +835,17 @@ static int kpi_system_state = 3; // SYSTEM_RUNNING
|
|||
// A list_head: empty means pointing at itself, not zero.
|
||||
static void *kpi_leds_list[2] = { kpi_leds_list, kpi_leds_list };
|
||||
|
||||
// --- calls that must not touch a register ---------------------------------------------
|
||||
//
|
||||
// preempt_schedule is reached through a thunk that saves every register, so
|
||||
// its callers keep live values in caller-saved ones across the call. A
|
||||
// logging stub makes a syscall, and `syscall` writes RFLAGS into r11: mdio-
|
||||
// bus kept the PHY register it had just read in r11, and every MDIO read on
|
||||
// the RTL8168H came back 0x0246 -- the PHY ID read as 0x02460246 and no
|
||||
// driver matched it. Nothing to schedule here anyway; a bare ret.
|
||||
__asm__(".text\n.globl kpi_ret\nkpi_ret:\n\tret\n");
|
||||
extern void kpi_ret(void);
|
||||
|
||||
// --- the table ------------------------------------------------------------------------------------
|
||||
|
||||
extern int kpi_queue_delayed_work_on(int cpu, void *q, void *dwork, unsigned long delay);
|
||||
|
|
@ -937,6 +948,12 @@ const struct kpi_sym kpi_base_table[] = {
|
|||
{ "request_firmware", (void *)kpi_request_firmware },
|
||||
{ "release_firmware", (void *)kpi_nop },
|
||||
|
||||
// must preserve every register
|
||||
{ "__SCT__preempt_schedule", (void *)kpi_ret },
|
||||
{ "__SCT__preempt_schedule_notrace", (void *)kpi_ret },
|
||||
{ "preempt_schedule_thunk", (void *)kpi_ret },
|
||||
{ "preempt_schedule_notrace_thunk", (void *)kpi_ret },
|
||||
|
||||
// must not be zero
|
||||
{ "__list_add_valid_or_report", (void *)kpi_true },
|
||||
{ "__list_del_entry_valid_or_report", (void *)kpi_true },
|
||||
|
|
|
|||
Loading…
Reference in a new issue