VOGONS


First post, by superfury

User metadata
Rank l33t++
Rank
l33t++

Would it be valid to add CR4 bit 4(PSE) only, CPUID bit 3(PSE) for identification and 4MB pages to the 80386 and/or 80486 emulation? I just added it to the 80486(even though it uses the same TLB as normal pages, although having an extra bit in the tag for seperating it from 4KB pages) in my emulator.

Would that be valid behaviour?

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

Reply 2 of 9, by superfury

User metadata
Rank l33t++
Rank
l33t++

Well, there are 80486 CPUs with the CPUID instruction in later revisions, which isn't fully 80486(Documentation says Pentium and up)? So could there be a 80486 with PSE(seeing as the 80486 already has the CR4 register defined, as well as the Debugger Exceptions bit in the CR4 register)?

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

Reply 3 of 9, by SarahWalker

User metadata
Rank Member
Rank
Member

Could someone have theoretically made a 486 with PSE? Yes. Did anyone actually make a 486 with PSE? No. Ergo, if you are trying to emulate a 486 then you shouldn't emulate PSE. Because such a chip does not exist.

Reply 4 of 9, by superfury

User metadata
Rank l33t++
Rank
l33t++

Just fixed a tiny bug in the PDE 4MB handling: when writing to such a page, it reads with D~1, but since it doesn't have a PTE, a junk PTE got written instead(this case being 0), thus causing an infinite loop trying to handle the dirty bit(it retries during execution phase(prefetching in this case, after the TLB is validly loaded(so it doesn't reload the TLB). Since the read and write to the TLB never match up(°read accesses any value of D, write only accepts reads from D~1 for proper dirty, rewalking the page table otherwise and rechecking when running the instruction until it's cached in the TLB again).mSince they never matched up, an infinite loop occurred(normally shouldn't happen, since it's cached once, it can be cached again in the same instruction executing).

Luckily the solution is simple: for 4MB PDE's, write the TLB as being dirty. Then everything runs as it should.

It's still 486-compatible, just with one Pentium extension(without Pentium instructions). The 486 still supports CPUID and CR4, which exist according to documentation(on the original and'or revisions of the chip).

Edit: Minix 3 crashes with a kernel panic(press any key to reboot) trying to execute #UD opcode 0F31 (Pentium instruction) on the 80486. But at least Paging and the 4MB handling doesn't page fault or hang anymore.

There's another open-source OS I've been following some OS development series on Youtube(OS Lectures Forall), which describes an OS(xv6), which is built for i386(although using 4MB pages as well for booting). Since it should have been compiled for i386(but with 4MB paging), it might be running fine on a 486 with PSE added?

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

Reply 5 of 9, by superfury

User metadata
Rank l33t++
Rank
l33t++

Managed to compile xv6 using a Ubuntu virtual machine and adding the flags -m32 -march=i386 to the CFLAGS. Looking at bootblock.S, it returns from the bootmain function(which it shouldn't, according to documentaation, triggering a non-existent Bochs breakpoint(in UniPCemu at least), then performs an infinite JMP $-2 to effectively HLT the CPU.

Now, why does bootmain return? Hmmm...
Edit: Looks like the EKF header it read from disk had an invalid signature(0101457F instead of 464c457f)?
Edit: Looking at sector 1 of the disk image, it contains the valid signature. So something goes wrong during reading of sectors from disk into memory somewhere.
Edit: Found the bug: the boot sector code us using insl/outsl to transfer data of sectors. But, the hard disk only has a 16-bit data register at port 1f0. So it's reading 2 bytes of disk data and the next two ports(1f1 and 1f2) instead of 4 bytes of on-disk data. Thus reading the sector incorrectly.

Edit: Having implemented proper 32-bit disk access, it now reaches main.c's kinit1 call(at 0008:80102ac0). I don't see it returning to the address after said instruction, so it's going wrong somewhere in there.

kinit calls initlock at 0008:80102111. That one returns.
It then set kmem.use_lock(at 80111674) to 0.
It seems to call kfree at 0008:80102146?
Then at 0008:80102056 kfree() calls memset to fill the release block with ones(01h).

Edit: It seems to update it's bookkeeping of the free list:

0008:80102068 A1 78 16 11 80 mov eax,dword ds:[80111678]	RealRAM(p):000a2086=08(); RAM(p):00102086=08(); Physical(p):00102086=08(); Paged(p):80102086=08(); Normal(p):80102086=08(); RealRAM(p):000a2087=40(@); RAM(p):00102087=40(@); Physical(p):00102087=40(@); Paged(p):80102087=40(@); Normal(p):80102087=40(@); RealRAM(r):000b1678=00( ); RAM(r):00111678=00( ); Physical(r):00111678=00( ); Paged(r):80111678=00( ); RealRAM(r):000b1679=00( ); RAM(r):00111679=00( ); Physical(r):00111679=00( ); Paged(r):80111679=00( ); RealRAM(r):000b167a=00( ); RAM(r):0011167a=00( ); Physical(r):0011167a=00( ); Paged(r):8011167a=00( ); RealRAM(r):000b167b=00( ); RAM(r):0011167b=00( ); Physical(r):0011167b=00( ); Paged(r):8011167b=00( )
Registers:
EAX: 80115000 EBX: 80115000 ECX: 00000000 EDX: 00000100
ESP: 8010a570 EBP: 8010a578 ESI: 80400000 EDI: 00000000
CS: 0008 DS: 0010 ES: 0010 FS: 0000 GS: 0000 SS: 0010 TR: 0000 LDTR: 0000
EIP: 80102068 EFLAGS: 00000046
CR0: e0010011 CR1: 00000000 CR2: 00000000 CR3: 00108000
CR4: 00000010
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 000000007c600017 IDTR: 000000000000ffff
FLAGSINFO: 0000000000i00avr0n00oditsZ0a0P1c
RealRAM(p):000a2088=16(); RAM(p):00102088=16(); Physical(p):00102088=16(); Paged(p):80102088=16(); Normal(p):80102088=16(); RealRAM(p):000a2089=11(); RAM(p):00102089=11(); Physical(p):00102089=11(); Paged(p):80102089=11(); Normal(p):80102089=11(); RealRAM(p):000a208a=80(?); RAM(p):0010208a=80(?); Physical(p):0010208a=80(?); Paged(p):8010208a=80(?); Normal(p):8010208a=80(?); RealRAM(p):000a208b=8b(?); RAM(p):0010208b=8b(?); Physical(p):0010208b=8b(?); Paged(p):8010208b=8b(?); Normal(p):8010208b=8b(?); RealRAM(p):000a208c=5d(]); RAM(p):0010208c=5d(]); Physical(p):0010208c=5d(]); Paged(p):8010208c=5d(]); Normal(p):8010208c=5d(])
0008:8010206d 89 03 mov dword ds:[ebx],eax Paged(w):80115000=00( ); Physical(w):00115000=00( ); RAM(w):00115000=00( ); RealRAM(w):000b5000=00( ); Paged(w):80115001=00( ); Physical(w):00115001=00( ); RAM(w):00115001=00( ); RealRAM(w):000b5001=00( ); Paged(w):80115002=00( ); Physical(w):00115002=00( ); RAM(w):00115002=00( ); RealRAM(w):000b5002=00( ); Paged(w):80115003=00( ); Physical(w):00115003=00( ); RAM(w):00115003=00( ); RealRAM(w):000b5003=00( )
Registers:
EAX: 00000000 EBX: 80115000 ECX: 00000000 EDX: 00000100
ESP: 8010a570 EBP: 8010a578 ESI: 80400000 EDI: 00000000
CS: 0008 DS: 0010 ES: 0010 FS: 0000 GS: 0000 SS: 0010 TR: 0000 LDTR: 0000
EIP: 8010206d EFLAGS: 00000046
CR0: e0010011 CR1: 00000000 CR2: 00000000 CR3: 00108000
CR4: 00000010
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 000000007c600017 IDTR: 000000000000ffff
FLAGSINFO: 0000000000i00avr0n00oditsZ0a0P1c
RealRAM(p):000a208d=fc(?); RAM(p):0010208d=fc(?); Physical(p):0010208d=fc(?); Paged(p):8010208d=fc(?); Normal(p):8010208d=fc(?); RealRAM(p):000a208e=c9(?); RAM(p):0010208e=c9(?); Physical(p):0010208e=c9(?); Paged(p):8010208e=c9(?); Normal(p):8010208e=c9(?)
0008:8010206f 89 1D 78 16 11 80 mov dword ds:[80111678],ebx Paged(w):80111678=00( ); Physical(w):00111678=00( ); RAM(w):00111678=00( ); RealRAM(w):000b1678=00( ); Paged(w):80111679=50(P); Physical(w):00111679=50(P); RAM(w):00111679=50(P); RealRAM(w):000b1679=50(P); Paged(w):8011167a=11(); Physical(w):0011167a=11(); RAM(w):0011167a=11(); RealRAM(w):000b167a=11(); Paged(w):8011167b=80(?); Physical(w):0011167b=80(?); RAM(w):0011167b=80(?); RealRAM(w):000b167b=80(?)
Registers:
EAX: 00000000 EBX: 80115000 ECX: 00000000 EDX: 00000100
ESP: 8010a570 EBP: 8010a578 ESI: 80400000 EDI: 00000000
CS: 0008 DS: 0010 ES: 0010 FS: 0000 GS: 0000 SS: 0010 TR: 0000 LDTR: 0000
EIP: 8010206f EFLAGS: 00000046
CR0: e0010011 CR1: 00000000 CR2: 00000000 CR3: 00108000
CR4: 00000010
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 000000007c600017 IDTR: 000000000000ffff
FLAGSINFO: 0000000000i00avr0n00oditsZ0a0P1c

It then restores EBX, cleans up the stack frame and returns to freerange at 0008:80102082.

The main kfree loop checks for it's next value to be within range at 0008:80102156. At 0008:80102158, the loops should have ended.
Edit: I don't see EBX reaching 400000, so it's still freeing the kernel memory for initial allocation(and I've stopped the debugger from continuing and logging it before it reached said point).

Edit: It seems to return to the main function, now to be working/hanging/crashing on the initialization of the page tables within kvmalloc()?

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

Reply 6 of 9, by superfury

User metadata
Rank l33t++
Rank
l33t++

It doesn't crash, but it complains that it's not running on a SMP, after initializing and activating the page tables.

So, that confirms paging is running properly(even with 4MB pages on a 80486 with bits 3&4 of the CR4 register implemented(as well as their full functions)).

The OS just doesn't like it's being ran on a non-SMP(multiple core or non-FPU?) system. That seems to be the same case as with Linux?

1023-Running XV6 on UniPCemu.jpg
Filename
1023-Running XV6 on UniPCemu.jpg
File size
36.56 KiB
Views
878 views
File comment
XV6 on UniPCemu.
File license
Fair use/fair dealing exception

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

Reply 7 of 9, by superfury

User metadata
Rank l33t++
Rank
l33t++

Just modified said feature to only be available on the (disabled due to being too complex to fully implement atm on the accuracy side and FPU) Pentium emulation instead of the 80486.

In this case, using PSE will just triple fault said OSes(both Minix and xv6) on the 80486 again.

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

Reply 8 of 9, by superfury

User metadata
Rank l33t++
Rank
l33t++

@sarahwalker: Look what I've found:
http://datasheets.chipdb.org/Intel/x86/486/ma … ls/27302101.PDF

Looking at page 107(4-17). That clearly defines VME, PVI and PSE in CR4 and it's associated functions.
So there actually are 80486 processors with said features!

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