VOGONS


i430fx/i440fx motherboard emulation issues?

Topic actions

Reply 40 of 71, by superfury

User metadata
Rank l33t++
Rank
l33t++

Weirdly enough, Windows NT 4.0 only seems to enable the IRQ8 handler on the APIC? There are various other IRQ handlers that actually try to fire, but are masked off?
Bit 16 of all other IRQ registers on the I/O APIC is set? So it's masking all other IRQs off for some weird reason?

All that weird behaviour makes me think about something...

How are IRQs autodetected with a APIC? Or is everything always assumed from the PIC configuration that's found(combined with the remainder of INTA/B/C/D)?
It doesn't seem to have any direct way of polling the IRQ lines(like the 8259 can do using it's IRR register)?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 41 of 71, by superfury

User metadata
Rank l33t++
Rank
l33t++

Just implemented a 8-bit version of the 86box's Intel flash ROM. That seems to at least fix the ESCD updating. 😁

Edit: Added to that most of the MultiProcessor specification(although with only 1 processor installed).
The only thing that isn't compatible yet is the NMI, which is still routed in it's own way, not notifying the Local APIC, connected to the emulated NMI 'pin' on the CPU, much in the same way as other interrupt sources(PIC&APIC), but with higher priority.
Edit: Just added the NMI to the IMCR register handling as well, causing it to be properly disconnected.

But seeing as the APIC doesn't allow throwing NMI etc.(everything but normal interrupts) yet, it can't handle the NMIs coming in this way yet(effectively disabling NMIs).

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 42 of 71, by superfury

User metadata
Rank l33t++
Rank
l33t++

Does Windows NT require the APIC high precision timer to be functional to boot?
Edit: Just tried Debian Jessie(8.11.1). It seems to enable most IRQs on the APIC.
But it asks to press enter or space for selecting a video mode(mode 314 isn't supported on the ET4000AX?).
But it can't receive it, since IRQs 0,1,D and 10-17h are disabled?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 43 of 71, by superfury

User metadata
Rank l33t++
Rank
l33t++

OK. How are IRQs detected on a APIC? For e.g. IRR 0 etc?
Are IRQs kept pending when masked in the I/O APIC? So are they send when raised while masked and unmasked afterwards? Or does the mask ignore any monitoring of the IR lines?
Edit: Bochs seems to imply that IRR is set pending until unmasked, but not cleared until serviced(or lowered during level mode) or the APIC is reset?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 44 of 71, by superfury

User metadata
Rank l33t++
Rank
l33t++

For now, I've added a shadow register IRR for the APIC, which is cleared when the APIC is disabled or enabled. Said shadow register is set when a IR is masked and it's raised(in edge mode). It's sent to the IRR for starting the IRQ when the IRQ is unmasked(clearing said shadow register bit as well).

Is this true for a real APIC as well? Or is the shadow register(IRQ Pending while masked) only cleared when the APIC is disabled?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 45 of 71, by superfury

User metadata
Rank l33t++
Rank
l33t++

Just implemented the APIC ID (both logical(not the IO APIC) and physical) and it's handling of the various types(3-bit value in the request).

The NMI is now also handled, as is the lowest priority(currently aliases to the normal interupt vector method).
Only SMI, SIPI and extInt isn't implemented yet(currenltly NOP commands).
Edit: Just implemented receiving of all available devices(IO APIC does nothing, Local APIC executes the requested vector).
No errors are reported yet by the Local APIC (the error interrupt and register).
Edit: Now implemented SIPI and the Arbitration ID register(together with it's Init Level De-assert request). Also implemented the LVT timer counting and LVT timer register(with interrupts), error interrupt and LVT error register(with interrupts). Lowest priority mode is mapped to normal mode/fixed mode.

That leaves just SMI, the LVT LINT0 and 1, extInt mode.
Edit: Just implemented extInt mode. That just leaves LINT0/1 and SMI itself.
Edit: Just implemented LINT0/1(connected to the master PIC(like the IO APIC's lowest pin) and NMI pins directly).
Edit: And fixed the extInt mode to properly inhibit all other requested interrupts until served by the CPU (by the Interrupt flag being set in the software).

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 46 of 71, by superfury

User metadata
Rank l33t++
Rank
l33t++

Just noticed that both Bochs and UniPCemu has its errors with the I/O APIC window register. Bochs doesn't mask it at all(full 32-bits), while masking the address for the window/address register to 8-bits. While actually, the address register should be 32-bits wide (and writable) with only 8-bits used for addressing the window register?
Just implemented that in UniPCemu (32-bit address register written, 8-bit address used for the window register being addressed).

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 47 of 71, by superfury

User metadata
Rank l33t++
Rank
l33t++

Managed to find a bug in the 8042 controller. Interrupts seem to be working correctly again now, with the APIC passing BIOS POST once again.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 48 of 71, by superfury

User metadata
Rank l33t++
Rank
l33t++

Just found a bug in the APIC interrupt handling when the CPU is in HLT state.
When it's in HLT state, the APIC would see that the 8259 has raised it's INTR line. When it would accept it(which happens in the HLT handler), it would move said interrupt handler to it's special interrupt pending variable. It would then restart the CPU and call said function again to find out if the normal interrupt handler is to fire.

Since the line was moved to the special interrupt pending variable(which expects the second level PIC INTA handler to fire immediately after the above function has returned), it didn't take into account that the special interrupt handler could be filled. So it didn't even looked at it(assumed it was supposed to fill it itself) and returned a status identifying no interrupt handler should fire. And when then checking the APIC interrupt requests, it would overwrite the special interrupt handler variable which was said with the acnowledged APIC interrupt(from the APIC IRR register) or clear it(setting it to -1) when no IRR was pending.

What it instead should have done was check said special variable to be set to a pending interrupt and immediately return the status to cause the second level interrupt handling to fire the interrupt and clear the special variable as it should.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 49 of 71, by superfury

User metadata
Rank l33t++
Rank
l33t++

Just managed to get a lot more working. The CPU is properly functioning again, but this time it's keeping all it's data on a per-CPU basis.
Then fixed CPU resets to become lockless(without locking by the hardware).

Now the i440fx BIOS actually sees both CPUs (if enabled through the emulator settings)! 😁 It actually communicates between both CPUs using IPI calls on the APIC when POSTing! 😁

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 50 of 71, by superfury

User metadata
Rank l33t++
Rank
l33t++

When booting Debian Jessie setup (in Expert mode), I actually see it setting up the SYSENTER MSRs! Although no SYSENTER/SYSLEAVE instruction is seen issued yet.

All it now took to get this far is to unreserve the MSR EVNTSEL(0x186) bit 21 to be writable(and not throwing a #GP(0) exception).
Edit: Just changed the clock speed on the APIC timer and CPU TSC to be 66MHz on the i440fx motherboard (previously 33MHz).

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 51 of 71, by superfury

User metadata
Rank l33t++
Rank
l33t++

Just fixed the two CPU's TSC and APIC to be properly running (instead of just running one CPU when it's sleeping or not doing anything).
Any CPU that ticks will set the maximum time passed(used by all hardware, the effective combined CPU timing). Said resulting timing is now also used to drive the TSC and APIC timing (for the Local APIC Timer).

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 52 of 71, by superfury

User metadata
Rank l33t++
Rank
l33t++

OK. Linux on the first processor seems to have interrupts fully enabled and is HLTing.
The second processor is in wait-for-SIPI state?

The first processor only seems to receive the EFh interupt from the APIC, which keeps bringing it out of HLT state? Other than that, no further activity is observed?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 53 of 71, by superfury

User metadata
Rank l33t++
Rank
l33t++

Just properly implemented the APIC ICR's Remote Read command(type 3). It's just a reading of an register of another APIC, with the interrupt number specified being the address as a 16-byte aligned address(so 0x02 is the register at address 0xFEE00020, 0xFF is address 0xFEE00FF0, essentially being address base+XX0, so the register number that's 16-byte aligned in memory). And it stores the result read into the Remote Read Register(RRR) of the APIC that's executing(sending) the command.

Bochs doesn't seem to actually implement this, even though it's emulating a i440fx motherboard?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 54 of 71, by superfury

User metadata
Rank l33t++
Rank
l33t++

Just tried NT 4 workstation again on the current APIC. It now eventually enables IRQ line 0xE (primary ATA) on the APIC! That's one more IR line enabled, so progress!
And eventually oxF(Secondary ATA: the ATAPI CD-ROM drives)! 😁

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 55 of 71, by superfury

User metadata
Rank l33t++
Rank
l33t++

Just adjusted the receiving process of the Local APIC Interrupt Command Register a bit. It will not keep the transfer pending until all receiving parties that have been specified have received the packet. It will also keep a status of which receivers have already received the packet, so it won't receive them there again (while all others are still pending until acnowledged by the destination APIC).

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 56 of 71, by superfury

User metadata
Rank l33t++
Rank
l33t++

With the latest version of UniPCemu, somehow, after entering protected mode and setting the PIC up for interrupts 30h-40h(both PICs in that range, in ascending order, master PIC first), it somehow receives an hardware interrupt with vector 0x08, which shouldn't be able to happen?

Windows NT reports this as STOP 0x0000007F with parameter 0x00000008(which means it thinks it's received a double fault). But it's actually somehow caused by an IRQ vector being fired for INT 08h. The PIC is actually reprogrammed at that point, so it shouldn't be the cause(the master PIC has last sent IR0 and the slave IR6). IR6 on the slave makes sense a bit(it's the hard disk it's booting from), but IR0 on the master shouldn't have fired with vector 0x08?

Edit: OK. Found part of the cause: The local APIC has performed an INTA before the PIC is programmed for said interrupts. Since the APIC performed an INTA on LINT0, it acnowledged the interrupt before the CPU had programmed the 8259 for it's new interrupt vectors. Said interrupt vector(the one before the PIC was programmed) then ends up at the CPU when interrupts are actually enabled once again(it was buffered by the APIC)!!!

How does this work with a real APIC? Does it actually buffer the interrupts? Or does it only process the INTA-type interrupts(type 7) once the interrupt pin is enabled and the CPU can actually receive said interrupt?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 57 of 71, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've just modified it as follows:
- The local APIC when setup for extInt mode handles it just like a normal PIC. So it acnowledges the interupt, sends INTA over the bus to receive the interrupt vector and receives the vector. This only happens when interrupts are unmasked and a new instruction is starting.
- The IO APIC IR line setup for extInt mode acts in much the same way. It stays pending, but only when a CPU can actually acnowledge said interrupt(by starting a new instruction with interrupts enabled), it will acnowledge said interrupt on the active APIC(the INTR input being acnowledged). Although all other CPUs won't receive the interrupt if a selected CPU(the actively processing CPU that's currently being handled) acnowledges it. So when multiple CPUs can receive the ExtInt from the IO APIC in ExtInt mode, the first CPU that can actually accept interrupts will accept the interrupt, while all other CPUs don't receive the interrupt(first serve(interrupt flag set and starting new instruction) is the winner).

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 58 of 71, by superfury

User metadata
Rank l33t++
Rank
l33t++

So with all the bugfixes to that in place, I now see the CPUs exchanging APIC packets and the second CPU is definitely being used by Windows NT 4.0 now! 😁

There's just a little locking problem now on one of the CPUs, which causes a deadlock in the emulator when in IPS clocking mode! Luckily the cycle-accurate clocking mode doesn't have that issue(as it handles it's BIU accesses broken up always, not using said function). The function that locked up was a wrapper around the BIU cycle-accurate handler. It just tried infinitely to obtain a lock if the bus was already locked by another CPU or device(e.g. DMA). I've adjusted the lock to then wait for the bus to once again be released, at which point the instruction will properly continue onwards (this is the only time that a bus lock causes a CPU instruction to halt).

Also just made the hardware tick(an exception to the normal ticking rule in IPS clocking mode) a IPS clocking cycle when not instructed by the other CPU as well. That way, when 2 CPUs wait for each other or the bus, the bus will always tick a cycle when one of the two is waiting for the bus lock to release.

That way, when both CPUs are waiting for the bus lock to release and DMA is holding the lock, the lock can properly be timed and released by the DMA controller. Otherwise both would infinitely wait for the DMA controller to release, which would never time because both CPUs essentially don't time anymore(since they're waiting for the BUS to be released, they're in a semi-HLT state, thus not executing any instructions, thus not timing the bus and driving the DMA to tick until it's completed it's job).

Windows NT 4.0:

2 System Processors [1024 MB Memory] MultiProcessor Kernel

It's actually using both CPUS using the APIC! 😁

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 59 of 71, by superfury

User metadata
Rank l33t++
Rank
l33t++

It eventually tries to convert the filesystem to NTFS(as I specified in the setup's first phase). This caused it to eventually trigger a CPU reset through the 8042?

Although since the reset only affected the first CPU and not others, it wasn't properly emulated in this case(as multiple CPUs were running (2) at that time).
I moved the whole CPU reset triggering by hardware to the emulator core(as a function).
Then I added support for the reset line to be broadcast to all emulated CPUs(as the documentation requires, which wasn't emulated yet).
Finally added support to reset the I/O APIC when the reset line is triggered. That should happen as well afaik?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io