Sony VAIO P series (VGN-P70H, Intel US15W Poulsbo Chipset)

Hey all,

I’ve been trying to get Haiku running on an old Sony VAIO P netbook (Intel

Atom Z520, Intel US15W “Poulsbo” chipset — yeah, I know, ancient and

extremely fringe hardware) and ran into a chain of boot/USB problems that

took a while to untangle. Figured I’d write up what I found in case any of

it rings a bell for other hardware, or is worth turning into proper tickets.

Quick context: with ACPI on and no safe mode, the machine would either hang

before the boot screen finished lighting up its icons, or panic partway

through boot, or boot but never get USB working (which also broke

installing from a USB stick, since it never enumerated). Chasing each of

these one at a time turned up five separate bugs, roughly in the order I

hit them:

1. Boot loader hangs forever if a CPU from ACPI’s MADT never wakes up

src/system/boot/platform/bios_ia32/smp.cpp

This one’s a plain hang — no panic, the boot screen just never finishes

lighting up its icons. Turns out this machine’s ACPI MADT reports two

Local APIC entries, but there’s only one real CPU (it’s a single-core

Atom). smp_boot_other_cpus() sends the usual INIT-SIPI-SIPI sequence to

wake up “CPU 1” and then spins waiting for each step to finish — and

none of those waits have a timeout. Since the second CPU obviously never

answers, the boot loader just sits there forever.

I added bounded timeouts to all four wait loops in that function (INIT

assert/deassert delivery, STARTUP IPI delivery, and the final “AP cleared

its handoff slot” wait). If a CPU doesn’t respond in time, it gets dropped

and boot continues with whatever CPU count did respond, instead of hanging.

Shouldn’t affect any machine where SMP actually works normally — those

waits already resolve near-instantly there.

2. ACPICA: NULL pointer deref if the Global Lock SCI fires while its handler is being installed

src/add-ons/kernel/bus_managers/acpi/acpica/components/events/evglock.c

Once #1 was out of the way, boot got further and then hit PANIC: page fault, but interrupts were disabled, stack trace through

AcpiOsAcquireLock → AcpiEvGlobalLockHandler → AcpiEvFixedEventDetect

→ AcpiEvSciXruptHandler, touching address 0.

AcpiEvInitGlobalLockHandler() installs the Global Lock’s fixed event

handler before it creates AcpiGbl_GlobalLockPendingLock (that only

happens on the next line, after the install call returns). Apparently on

this hardware the GBL_STATUS bit is already set at that point in boot, so

the SCI fires synchronously during the install call, the handler runs

immediately, and it tries to lock something that doesn’t exist yet →

crash. I just swapped the order — create the lock first, then install the

handler — and cleaned up the two failure paths after that so they don’t

leak the lock. Not sure if this is already fixed in a newer ACPICA snapshot

than what I was on; might be worth checking against upstream Intel ACPICA.

3. ACPI PCI IRQ routing trusts edge/high-active from a Link Device, which isn’t legal for PCI

src/system/kernel/arch/generic/acpi_irq_routing_table.cpp

This was the sneaky one. USB devices had the right GSI, right vector,

correctly unmasked — but I dumped the actual IO-APIC redirection entry

(added a small ioapic KDL command for this, see below) and it was

configured edge-triggered / active-high. PCI interrupts are always

level/low per spec, no exceptions — but this machine’s DSDT describes one

of its PCI Link Devices using a plain ACPI IRQ resource that claims

edge/high, and choose_link_device_configurations() just copied that

straight into the redirection entry, no questions asked.

Fix was to stop trusting the descriptor for polarity/trigger and just force

level/low whenever we’re programming an interrupt that came from a _PRT

entry (which is unconditionally true for everything flowing through this

function) — same as the sibling code path already does for hardwired GSIs.

Feels like a legit general bug rather than a quirk of this one DSDT, since

nothing in the PCI spec allows what that Link Device was claiming.

4. PCI config space read/write refuses non-dword-aligned 4-byte access, breaks EHCI’s legacy handoff

src/add-ons/kernel/bus_managers/pci/pci.cpp

Got past #3, USB still didn’t work — PCI: can't read config for domain 0, 0:29:7, offset 226, size 4, then the EHCI driver logs “extended

capability is not a legacy support register” and fails to reset the

controller. The EHCI driver locates its legacy-support capability via

HCCPARAMS’s EECP field, which per the EHCI spec can be any byte offset —

it landed on 0xE2 here, which is 2-aligned but not 4-aligned.

PCI::ReadConfig / WriteConfig reject any 4-byte access that isn’t

dword-aligned, which is correct for the standard PCI capability list

(always dword-aligned by spec) but wrong for capability mechanisms with

looser rules, like this one. So the read just failed, the driver never saw

a valid capability, and skipped asking the BIOS to hand over the

controller.

Fixed by having both functions split a 4-byte access into two word

accesses when the offset is 2-aligned but not 4-aligned, instead of

rejecting it outright — checked against the actual x86 0xCF8/0xCFC I/O

port mechanism to make sure two word reads at offset and offset+2 actually

land on the right bytes (they do, via the existing + (offset & 3)

handling on the data port). Byte-misaligned access is still rejected, since

nothing can do that one. This feels like a general bus-manager

correctness fix too, not something specific to my hardware.

5. This specific chipset’s EHCI controller has an unassigned BAR0 and Haiku doesn’t fill it in

src/add-ons/kernel/bus_managers/pci/pci_fixup.cpp

Last one, and this one is hardware-specific. Even with #4 fixed, EHCI

still failed to reset. Turned out the PCI dump showed its BAR0 (the 1KB

MMIO range holding all its registers) as host 00000000 — the BIOS never

assigned it a real address. Every register access the driver made was

therefore hitting physical address 0. The sibling UHCI controllers (I/O

port based) were completely unaffected, only the memory-BAR one.

Haiku’s PCI bus manager doesn’t currently reassign/fill in resources the

BIOS left blank — I noticed there’s already a // TODO(bga): disabled until the PCI manager can assign new resources. sitting in

intel_fixup_ahci() in the same file for basically the same reason. So as

a stopgap I added a fixup matched specifically to this device ID (Intel

0x8086:0x8117, the Poulsbo EHCI controller) that fills in a fixed address

(0xf0000000, inside this machine’s own ACPI-declared, otherwise-empty PCI

memory aperture) only if BAR0 reads back as exactly 0. Obviously not a

real general fix — that’d be giving the PCI bus manager actual resource

allocation, which is apparently already wanted for other devices too — but

wanted to flag it in case someone wants to tackle that properly at some

point, and to explain why this specific workaround exists if anyone

stumbles on it.

Two smaller things I added alongside all this, not bugs by themselves:

A ioapic [gsi] KDL command in ioapic.cpp that dumps IO-APIC

redirection table entries (mask/trigger/polarity/vector/IRR). This is

what let me actually find #3 without rebuilding a dozen times — figured

it’s generically useful enough to be worth keeping around.

A bounded retry (10s, 250ms steps) around get_boot_partitions() in

vfs_boot.cpp before it panics with “did not find any boot partitions!”

— my working theory going in was that a slow USB controller might not

have registered with the disk device manager yet by the time that check

runs. Turned out that wasn’t actually the root cause here (that was #4 /#5

— USB wasn’t coming up at all), but seems like reasonable defensive

hardening regardless, so I left it in.

I hope my trial and error will help you!

5 posts - 4 participantsRead full topic

添加评论
点赞收藏
点踩分享查看原文
评论
?
参与讨论