UniPCemu Minix progress

Emulation of old PCs, PC hardware, or PC peripherals.

UniPCemu Minix progress

Postby superfury » 2019-2-08 @ 21:26

I've been testing with Minix 2.0.4 so far, and it seems to run without any problems rights now.

Now I've been using the Plop BIOS to boot the latest Minix 3.X CD-ROM (with 80486SX CPU emulated), which seems to run quite far, at least until reporting that it's loading the "init" (driver?).

Somewhere at/after that, it tries to execute code at 0008:00401A39. CS is loaded with a 4GB descriptor. Paging is enabled. But said offset seems to be unmapped(The PDE=00400087, the PTE=90909090). This triggers a page fault. This page fault tries to call a page fault handler. Said page fault handling IDT entry uses the IDTR to locate the interrupt, where the base of the IDTR is 0 and limit 0xFFFF. Said entry isn't in memory, according to the paging check of the page fault interrupt handler(it's the NULL page because IDTR.base==0). So that triggers another page fault on address 00000070. But the page fault triggering a page fault isn't allowed, so it triggers a double fault instead(according to documentation and in the emulator). But the double fault handler in the IDT also is in the zero page(at address 00000040). So that will also raise a Page fault. But the double fault handler, trying to execute, faulting isn't allowed according to CPU specs. So that will in turn trigger a triple fault:S

Anyone knows what the cause might be? Besides a faulty LIDT instruction somehow?
superfury
l33t
 
Posts: 3230
Joined: 2014-3-08 @ 11:25
Location: Netherlands

Re: UniPCemu Minix progress

Postby superfury » 2019-2-08 @ 22:01

Just ran it with a breakpoint on the 286+ and 386+ LIDT instructions. The last time it's called was before running the Plop BIOS and booting the CD-ROM. So Minix never calls LIDT before enabling Paging? That's very strange.

Edit: I've been reading https://wiki.minix3.org/doku.php?id=dev ... :earlyboot .
Since Paging is enabled, minix/kernel/arch/i386/head.S must have called pre_init.c:preinit before calling kmain.

Edit: I'm using Minix 3.3.0, so the entry point should be 400000 (F0400000 after paging is enabled).

But EIP is still in the low range when it triple faults, so why is it faulting?
Edit: Set a breakpoint for 0000:00400000PO(which is offset 400000, protected mode, ignore CS filter). It traps after the mod11_init module is loaded, with a JMP to 00400038(opcode EB) at 0008:00400000.

So head.S is actually reached correctly:D

Although the cd9660(//cd9660/cd9660.kmod) couldn't be loaded. All other modules(/mod01_ds to /mod11_init) were loaded.

It reaches calling pre_init, which is at 00400750, at 0008:004000049(after setting up the __cdecl parameters on the stack correctly).

It then calls 004000e0 for get_parameters.
It then calls the pg_clear function(essentially a memset).
It then calls pgidentity with &kinfo, which was set up before calling pg_clear. pgidentity is at 004013b0.
Then mapkernel at 00401190(from 40077E).
Then the interesting part: it calls something from 400783 to 401200)?
Then it loads CR3 on 40078D(to 401380). which is supposed to load CR3. Edit: The above was shifted by one call.
Then it's supposed to enable paging at 004012b0(according to the call).

It then reaches a first page fault when enabling paging at 401a39.
Edit: Then the PTE contains 90909090... Hmmm.... Do I smell an uninitialized page table(that the PDE is pointing to) somehow for the kernel/4MB block that's promised?
superfury
l33t
 
Posts: 3230
Joined: 2014-3-08 @ 11:25
Location: Netherlands

Re: UniPCemu Minix progress

Postby superfury » 2019-2-09 @ 01:44

Looking at the kernel sources again, it seems to be mapping Big pages, which aren't supported on a 80386/80486 that's emulated on UniPCemu... :S

Looking at the documentation again:
https://wiki.minix3.org/doku.php?id=rel ... quirements

[quote]MINIX 3 runs on Pentium-class hardware or later.[/code]

So even though it starts to boot on a 80386/80486, it can't EVER run on them, due to requiring a Pentium-class CPU to boot at all... Just when you thought you've found a nice OS to verify your CPU emulation with... :/

Edit: According to the repository, Minix 3.1.4 still supported 4K pages(thus 80386 compatible). But I can't find the ISO image? The official website has a dead link to it?
3.1.5 still supported it...
Edit: It looks like Minix has never supported PTEs for everything? It always has required a Pentium for 4GB PDEs?
superfury
l33t
 
Posts: 3230
Joined: 2014-3-08 @ 11:25
Location: Netherlands

Re: UniPCemu Minix progress

Postby superfury » 2019-2-15 @ 22:53

Well, interestingly enough, I just tried to run Minix 2.0.3 on UniPCemu's 80486 emulation and I noticed it detected the CPU as a 286 or 8086, depending on himem being loaded or not! So I took a look at the source code and found two candidates: getprocessor(which does a simple push sp check for detecting a 286, then if pushed sp is equal to sp(8086 if pushed sp!=sp before push(after popping it in AX), smsw to check for protected mode(else 8086 if real mode). Since I can see the CPU being in real mode at that point, it must jump to the wrapper calling and testing the 386+ CPUs(thus failing in _getcpumode).

Said function does some simple things(src/lib/i386/misc/getprocessor.s):
1. Try and flip AC bit. If not flipping, it's a 386(works on the 386, passthrough on 486).
2. Try and flip ID bit. My emulated 486 has a CPUID implemented, so it flips. It knows it's at least a 486, but continues on(for CPUID results).
3. It calls CPUID. Said instruction sets the low 4 bits of AH to 4(since it's a 80486SX).
4. It ANDs AH with 0xF, then extends it into EAX using MOVZXB EAX,AH(this might be failing. As to why, see below).
5. It multiplies EAX by 100(to obtain 400 in this case) and adds 86 for the result(486).

AND should work, so the issue is probably in step 4 or 5?
Edit: No CPUID on the 80486, nor 386 reported. So the code must still abort before getprocessor passes to _getprocessor, because the result is a 286(it becomes 386 before _getprocessor starts doing anything).

Edit: SMSW stores 10h into EAX.

Edit: It does seem to reach the _getprocessor function call by means of a E9 near JMP instruction, so the problem is somewhere within the _getprocessor function call?
Edit: And of course, Visual Studio craps out(starts hanging) while I'm single-stepping through my emulator's code... Yay! :/

Edit: The AC/ID bit toggling routine looks very wrong(according to the source code):
Code: Select all
flip:
   pushf         ! Push eflags
   pop   eax      ! eax = eflags
   mov   edx, eax   ! Save original eflags
   xor   eax, ecx   ! Flip the bit to test
   push   eax      ! Push modified eflags value
   popf         ! Load modified eflags register
   pushf
   pop   eax      ! Get it again
   push   edx
   popf         ! Restore original eflags register
   xor   eax, edx   ! See if the bit changed
   test   eax, ecx
   ret


I understand pushing and popping 32-bit registers. But why would you use 16-bit flag push/pops, which don't modify the high parts of the EFLAGS register(what you're trying to test)?
Even if the code is running in 32-bit mode, the PUSH and POP of EFLAGS would be 32-bit, but the corresponding registers push/pop would be 16-bit, thus still having not a single effect on the result? Lol. XD

The code starts at 0556:40b5, which is the start of the _getprocessor function(the AND ESP,FFFFFFFC).
The code is running in 16-bit mode.
Edit: Once again, VC++ hangs while stepping through the start of the emulated cache flush(flushPIQ triggering a full PIQ reload in IPS cycle mode).

Edit: Minix 2.0.3 seems more sane:
Code: Select all
!   getprocessor() - determine processor type   Author: Kees J. Bot
!                        26 Jan 1994

.text

   o32 = 0x66      ! 32 bit operand size prefix

! int getprocessor(void);
!   Return 86, 186, 286, 386, 486, 586, ...

.define   _getprocessor

_getprocessor:
   push   bp
   mov   bp, sp
   push   sp      ! see if pushed sp == sp
   pop   ax
   cmp   ax, sp
   jz   new_processor
   mov   cx, #0x0120   ! see if shifts are mod 32
   shlb   ch, cl      ! zero tells if 86
   mov   ax, #86
   jz   got_processor
   mov   ax, #186
   jmp   got_processor

new_processor:         ! see if high bits are set in saved IDT
   sub   sp, #6      ! space for IDT ptr
   sidt   -6(bp)      ! save 3 word IDT ptr
   cmpb   -1(bp), #0xFF   ! top byte of IDT ptr is always FF on 286
   mov   ax, #286
   je   got_processor

! 386, 486, 586
   and   sp, #0xFFFC   ! Align stack to avoid AC fault (needed?)
   mov   cx, #0x0004   ! Try to flip the AC bit introduced on the 486
   call   flip
   mov   ax, #386   ! 386 if it didn't react to "flipping"
   jz   got_processor
   mov   cx, #0x0020   ! Try to flip the ID bit introduced on the 586
   call   flip
   mov   ax, #486   ! 486 if it didn't react
   jz   got_processor
   .data1   o32
   pushf
   .data1   o32
   pusha         ! Save the world
   .data1   o32
   xor   ax, ax
   inc   ax      ! eax = 1
   .data1   0x0F, 0xA2   ! CPUID instruction tells the processor type
   andb   ah, #0x0F   ! Extract the family (5, 6, ...)
   movb   al, ah
   movb   ah, #100
   mulb   ah      ! 500, 600, ...
   add   ax, #86      ! 586, 686, ...
   mov   bx, sp
   mov   7*4(bx), ax   ! Pass ax through
   .data1   o32
   popa
   .data1   o32
   popf

got_processor:
   mov   sp, bp
   pop   bp
   ret

flip:
   push   bx      ! Save bx and realign stack to multiple of 4
   .data1   o32      ! About to operate on a 32 bit object
   pushf         ! Push eflags
   pop   ax
   pop   dx      ! dx:ax = eflags
   mov   bx, dx      ! Save original eflags (high word only)
   xor   dx, cx      ! Flip the bit to test
   push   dx
   push   ax      ! Push modified eflags value
   .data1   o32
   popf         ! Load modified eflags register
   .data1   o32
   pushf
   pop   ax
   pop   dx      ! Get it again
   push   bx
   push   ax
   .data1   o32
   popf         ! Restore original eflags register
   xor   dx, bx      ! See if the bit changed
   test   dx, cx
   pop   bx      ! Restore bx
   ret


It at least checks the flags correctly. It seems 2.0.4 might have been a bit too quick a release to make(according to the source code. It DID say it was slapped together in a hurry as a new base for building Minix). It essentially destroyed any detection of 80486 processors and up!

Edit: Maybe use the 2.0.3 boot.com with 2.0.4 minix.mnx disk image?
superfury
l33t
 
Posts: 3230
Joined: 2014-3-08 @ 11:25
Location: Netherlands


Return to PC Emulation

Who is online

Users browsing this forum: knowledge [bot] and 1 guest