VOGONS


UniPCemu's 80286 emulation bug help?

Topic actions

Reply 20 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've just found and fixed a bug in the IDTR and GDTR entry limits: I've found out that the limit set in the IDTR and GDTR registers is actually the last byte that's addressable. My emulation always took the value that's set as the limit as the first byte that's unaddressable(e.g. everything smaller than it is invalid). After having fixed this, CheckIt! Diagnostics now completes the system board protected mode tests and continues on with the other tests. No failures are reported in the System Board tests. 😁

One strange thing I'm seeing is that CheckIt! Diagnostics reports Extended memory: None and EXPANDed Memory: 0K at segment 0000h. The 640K base memory is correctly detected though:D

Edit: Just tried to run Day of the Tentacle in the new improved 80286 emulation. It still hangs the application. It's reading segment B000, which is calculated or loaded into BX, then loaded into ES and repeated. I see AX keeps being loaded with 0x0123, then later in the process 0x0234, after which the process seems to repeat itself. It might be waiting for the zero flag to set at a certain point, which it never does. It's still executing in real mode. Anyone knows what might be going wrong?

Edit: Also, the limit of the GDTR and IDTR is the last ACCESSABLE byte of the respective table. So setting the IDTR limit to 0 to generate a #GP fault on any interrupt(including the interrupts themselves) causing a shutdown cycle is simply because offset 1 and higher are out of range, not because offset 0 is illegal(It should still be able to access offset 0, if it would only need that byte. Luckily the entire descriptor is more than 1 byte(which is the meaning of the value '0': it tells the CPU that offset 0 is the last VALID byte to address, thus making offsets 1 and higher illegal), thus always triggering the exception).

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

Reply 22 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++

Although I don't find any documentation on it, without using a seperate delta instead of modifying BP directly, the ENTER instruction would not be restartable, as a simple page fault would crash running virtual 8086 process made with Pascal on a 80386+? So for compatibility, it would need to be supported using a delta? Stack faults would, of course, still be a problem, as SP would be invalid afterwards.

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

Reply 23 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've just found and fixed some little bugs in the protected mode segment descriptor handling:
- TSS loading on Big-Endian machines are now fixed(these would have reversed values loaded into the registers from the TSS previously).
- The first segment on the GDT is invalid. The first segment on the LDT is valid to load into any register(The GDT's first entry is reserved and invalid. The LDT isn't(UniPCemu was counting that one as invalid too, raising a #GP exception)).
- UniPCemu was checking CS loading and required even TSS loaded for task switches as invalid, as they're not code segments. This check has been moved to allow those segments to be loaded and used for task switching properly.
- The LDT segment descriptor loading during Task Switching was loading the first entry from the GDT instead of the specified entry from the GDT(forgot to add the index into the table to the base address). It now loads the correct address and loads the LDT descriptor from the GDT.

Although the checks still fail, the basic task switching triggered by the jump to segment 0x0004 now works correctly, triggering a task switch and switching to the correct task. 😀

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

Reply 24 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++

After looking at the current running version of the SuperSoft BIOS on the AT:
- First it switches to task 0x48(CALL).
- Then it jumps to task 0x58 with TR=0x48(JMP).
- Then it #GP faults because it's trying to jump to task 0x58(JMP), which is marked busy.

Is this correct? It thinks the #GP fault is incorrect, but switching from task 0x58 to task 0x58 shouldn't be allowed(switching to it's own task)?

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

Reply 25 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++

This is what currently happens when logging the protected mode of the SuperSoft BIOS:

Filename
debugger_protectedmode_diagnostics.zip
File size
19.89 KiB
Downloads
71 downloads
File comment
Protected mode SuperSoft Diagnostics logs.
File license
Fair use/fair dealing exception

Anyone can see what's going wrong here? The RAM entries are made when RAM is directly accessed(Normal segmented access and direct access). The memory accesses are only used to identify CPU access(which includes memory-mapped hardware RAM). When no corresponding memory&RAM access is made after each other, this either means:
Memory without RAM entry following: Memory is mapped to hardware I/O(VGA VRAM, BIOS etc.)
RAM without memory entry above it: Memory is accessed directly by the CPU(For retrieving GDT/IDT/LDT entries instead of mapped through hardware RAM(Video VRAM)/ROM(BIOS ROMs)/paging).

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

Reply 26 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++

One little question about 80386+ paging: is the GDT itself paged as well? What happens when a task switch results in a non-paged GDT/GDT? Triple faulting?(Task switch -> GDT CS loading #GP fault -> task switch leading to #PF when loading CS from GDT, which is paged out, causing a double fault -> IDT not in memory because paged out #PF -> Triple fault reset)?

Or is the paging OS code required to never be paged out, nor it's GDT?

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

Reply 27 of 69, by peterferrie

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:

Anyone can see what's going wrong here?

00:00:35:96.04192: 0018:0000A4AC (9A00007800)CALL 0078:0000
...
00:00:35:96.04300: 0004:00000000 (33DB)XORW BX,BX

Why is it 0004 and not 0078?

Reply 28 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++
peterferrie wrote:
00:00:35:96.04192: 0018:0000A4AC (9A00007800)CALL 0078:0000 ... 00:00:35:96.04300: 0004:00000000 (33DB)XORW BX,BX […]
Show full quote
superfury wrote:

Anyone can see what's going wrong here?

00:00:35:96.04192: 0018:0000A4AC (9A00007800)CALL 0078:0000
...
00:00:35:96.04300: 0004:00000000 (33DB)XORW BX,BX

Why is it 0004 and not 0078?

00:00:35:96.01548: Switching task to task 0048

Apparently a task switch is being executed at that instruction, caused by calling a Task Gate or TSS segment descriptor.

Edit: Like all other debugging stuff: all information, in the order it happens while executing the instruction, is logged first, followed by the instruction debugger states captured at the start of the instruction(disassembly, register dump, simple VGA&interrupt status).

A successfull task switch, in memory accesses, you'll see the following, currently:
0. Logging task switch text.
1. Loading of the TSS from Memory&RAM, using the TR register.
2. Writing the updated TSS to Memory&RAM, using the TR register.
3. Loading of the TR segment descriptor from direct RAM, and writing it back as busy.
4. Loading register states from the TSS from memory&RAM.
5. Loading CS segment descriptor like normal read, from GDT direct RAM.
6. Loading SS the same way.
7. Loading DS.
8. Loading ES.
9. Ready.

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

Reply 29 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've improved the log a bit, with LDTR, TR, GDTR and IDTR registers being added to the log.

Filename
debugger_protectedmode_diagnostics_20170119_1725.zip
File size
13.01 KiB
Downloads
71 downloads
File comment
Logging protected mode BIOS with LDTR, TR, GDTR and IDTR registers being logged in protected mode.
File license
Fair use/fair dealing exception

- One thing has changed: instead of loading all data always, it now just loads when reading the task after the switch, while writing only the registers and addresses that need to be updated(non-readonly or undefined registers and memory).

Anyone can see what's going wrong here? Why is it trying to start the same task twice(which is forbidden by x86 specs)?

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

Reply 30 of 69, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie

Is it possible that it is intentional and that it checks for GPF occurring (via the GPF handler)? If it gives up protected mode checks after this task switch it means that maybe this is the error after all but if it keeps going with PM stuff then maybe the error is somewhere else.

YouTube channel: https://www.youtube.com/channel/UC7HbC_nq8t1S9l7qGYL0mTA
Collection: http://www.digiloguemuseum.com/index.html
Emulator: https://sites.google.com/site/capex86/
Raytracer: https://sites.google.com/site/opaqueraytracer/

Reply 31 of 69, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie

Looking at the log I also see this (I get same value when I run that with my emulator)

00:00:41:60.09416: 0018:A4AC (9A00007800)CALL 0078:0000

but inside that you say (which is actually higher up the log, but same instruction)

00:00:41:60.06708: Switching task to task 0048

All this is after executing LTR AX where AX is 0x68.

So where is the 0x48 coming from?

EDIT:

0x68 should be current task (the descriptor) where we save current TSS info to and 0x78 should be the descriptor for the new TSS to load all the registers from. Unless I understand this wrong?

YouTube channel: https://www.youtube.com/channel/UC7HbC_nq8t1S9l7qGYL0mTA
Collection: http://www.digiloguemuseum.com/index.html
Emulator: https://sites.google.com/site/capex86/
Raytracer: https://sites.google.com/site/opaqueraytracer/

Reply 32 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++
vladstamate wrote:
Looking at the log I also see this (I get same value when I run that with my emulator) […]
Show full quote

Looking at the log I also see this (I get same value when I run that with my emulator)

00:00:41:60.09416: 0018:A4AC (9A00007800)CALL 0078:0000

but inside that you say (which is actually higher up the log, but same instruction)

00:00:41:60.06708: Switching task to task 0048

All this is after executing LTR AX where AX is 0x68.

So where is the 0x48 coming from?

EDIT:

0x68 should be current task (the descriptor) where we save current TSS info to and 0x78 should be the descriptor for the new TSS to load all the registers from. Unless I understand this wrong?

00:00:41:60.06628: Reading from RAM: 0000051C=00 ( )
00:00:41:60.06632: Reading from RAM: 0000051D=00 ( )
00:00:41:60.06636: Reading from RAM: 0000051E=48 (H)
00:00:41:60.06644: Reading from RAM: 0000051F=00 ( )
00:00:41:60.06648: Reading from RAM: 00000520=00 ( )
00:00:41:60.06652: Reading from RAM: 00000521=85 (…)
00:00:41:60.06656: Reading from RAM: 00000522=00 ( )
00:00:41:60.06660: Reading from RAM: 00000523=00 ( )

http://css.csail.mit.edu/6.858/2014/readings/i386/s05_01.htm

This is the descriptor 0x0078 in the GDT being read. The limit 0:15 field contains 0x0000, Base low contains 4800h, Base mid 0x00, Access byte 0x85, Limit high 0x0, Flags 0x0, Base high 0x00. So that creates a system segment, present, type 5(which is a Task Gate Descriptor: http://css.csail.mit.edu/6.858/2014/readings/i386/s07_04.htm), where the bits of the base mid(0x0048) field selects the destination task. Thus a task switch(after privilege checks etc.) is performed to task 0x0048 in the GDT. First it stores the current state(which is task 0x0068, according to the TR register), then it loads the state from task 0x0048.

This is the TSS descriptor of task 0x0048 being loaded for checking:

00:00:41:60.06668: Reading from RAM: 000004EC=68 (h)
00:00:41:60.06676: Reading from RAM: 000004ED=00 ( )
00:00:41:60.06680: Reading from RAM: 000004EE=20 ( )
00:00:41:60.06684: Reading from RAM: 000004EF=04 ()
00:00:41:60.06688: Reading from RAM: 000004F0=00 ( )
00:00:41:60.06692: Reading from RAM: 000004F1=81 ()
00:00:41:60.06696: Reading from RAM: 000004F2=00 ( )
00:00:41:60.06704: Reading from RAM: 000004F3=00 ( )

After that, a task switch is executed to task 0x0048.

Something strange seems to be happening there:
1. It seems to read the segment decriptor 0x0048 from memory.

00:00:41:60.06724: Reading from RAM: 000004EC=68 (h)
00:00:41:60.06732: Reading from RAM: 000004ED=00 ( )
00:00:41:60.06740: Reading from RAM: 000004EE=20 ( )
00:00:41:60.06744: Reading from RAM: 000004EF=04 ()
00:00:41:60.06748: Reading from RAM: 000004F0=00 ( )
00:00:41:60.06752: Reading from RAM: 000004F1=81 ()
00:00:41:60.06756: Reading from RAM: 000004F2=00 ( )
00:00:41:60.06764: Reading from RAM: 000004F3=00 ( )

2. Then, it loads it again?

00:00:41:60.06768: Reading from RAM: 000004EC=68 (h)
00:00:41:60.06772: Reading from RAM: 000004ED=00 ( )
00:00:41:60.06776: Reading from RAM: 000004EE=20 ( )
00:00:41:60.06780: Reading from RAM: 000004EF=04 ()
00:00:41:60.06788: Reading from RAM: 000004F0=00 ( )
00:00:41:60.06792: Reading from RAM: 000004F1=81 ()
00:00:41:60.06796: Reading from RAM: 000004F2=00 ( )
00:00:41:60.06800: Reading from RAM: 000004F3=00 ( )

3. Then again? Why would it keep reloading the same segment selector?

00:00:41:60.06804: Reading from RAM: 000004EC=68 (h)
00:00:41:60.06812: Reading from RAM: 000004ED=00 ( )
00:00:41:60.06816: Reading from RAM: 000004EE=20 ( )
00:00:41:60.06820: Reading from RAM: 000004EF=04 ()
00:00:41:60.06824: Reading from RAM: 000004F0=00 ( )
00:00:41:60.06828: Reading from RAM: 000004F1=81 ()
00:00:41:60.06840: Reading from RAM: 000004F2=00 ( )
00:00:41:60.06844: Reading from RAM: 000004F3=00 ( )

4. Then, it stores the segment descriptor, marked as busy, to memory. This is the actual start of the Task Switch.

00:00:41:60.06848: Writing to RAM: 000004EC=68 (h)
00:00:41:60.06852: Writing to RAM: 000004ED=00 ( )
00:00:41:60.06856: Writing to RAM: 000004EE=20 ( )
00:00:41:60.06864: Writing to RAM: 000004EF=04 ()
00:00:41:60.06868: Writing to RAM: 000004F0=00 ( )
00:00:41:60.06872: Writing to RAM: 000004F1=83 (ƒ)
00:00:41:60.06876: Writing to RAM: 000004F2=00 ( )
00:00:41:60.06880: Writing to RAM: 000004F3=00 ( )

5. Then, it seems to load the new task's state from memory:

00:00:41:60.06884: Reading from RAM: 00000420=00 ( )
00:00:41:60.06888: Read from memory: 00000420=00 ( )
00:00:41:60.06896: Reading from RAM: 00000421=00 ( )
00:00:41:60.06900: Read from memory: 00000421=00 ( )
00:00:41:60.06904: Reading from RAM: 00000422=00 ( )
00:00:41:60.06908: Read from memory: 00000422=00 ( )
00:00:41:60.06912: Reading from RAM: 00000423=08 ()
00:00:41:60.06916: Read from memory: 00000423=08 ()
00:00:41:60.06924: Reading from RAM: 00000424=20 ( )
00:00:41:60.06928: Read from memory: 00000424=20 ( )
00:00:41:60.06932: Reading from RAM: 00000425=00 ( )
00:00:41:60.06936: Read from memory: 00000425=00 ( )
00:00:41:60.06940: Reading from RAM: 00000426=00 ( )
00:00:41:60.06944: Read from memory: 00000426=00 ( )
00:00:41:60.06952: Reading from RAM: 00000427=00 ( )
00:00:41:60.06956: Read from memory: 00000427=00 ( )
00:00:41:60.06960: Reading from RAM: 00000428=00 ( )
00:00:41:60.06964: Read from memory: 00000428=00 ( )
00:00:41:60.06968: Reading from RAM: 00000429=00 ( )
00:00:41:60.06972: Read from memory: 00000429=00 ( )
00:00:41:60.06976: Reading from RAM: 0000042A=00 ( )
00:00:41:60.06984: Read from memory: 0000042A=00 ( )
00:00:41:60.06988: Reading from RAM: 0000042B=00 ( )
00:00:41:60.06992: Read from memory: 0000042B=00 ( )
00:00:41:60.06996: Reading from RAM: 0000042C=00 ( )
00:00:41:60.07000: Read from memory: 0000042C=00 ( )
00:00:41:60.07008: Reading from RAM: 0000042D=00 ( )
00:00:41:60.07012: Read from memory: 0000042D=00 ( )
00:00:41:60.07020: Reading from RAM: 0000042E=00 ( )
00:00:41:60.07024: Read from memory: 0000042E=00 ( )
00:00:41:60.07028: Reading from RAM: 0000042F=00 ( )
00:00:41:60.07032: Read from memory: 0000042F=00 ( )
00:00:41:60.07036: Reading from RAM: 00000430=00 ( )
00:00:41:60.07044: Read from memory: 00000430=00 ( )
00:00:41:60.07048: Reading from RAM: 00000431=00 ( )
00:00:41:60.07052: Read from memory: 00000431=00 ( )
00:00:41:60.07056: Reading from RAM: 00000432=00 ( )
00:00:41:60.07060: Read from memory: 00000432=00 ( )
00:00:41:60.07064: Reading from RAM: 00000433=00 ( )
00:00:41:60.07068: Read from memory: 00000433=00 ( )
00:00:41:60.07076: Reading from RAM: 00000434=00 ( )
00:00:41:60.07080: Read from memory: 00000434=00 ( )
00:00:41:60.07084: Reading from RAM: 00000435=00 ( )
00:00:41:60.07088: Read from memory: 00000435=00 ( )
00:00:41:60.07092: Reading from RAM: 00000436=00 ( )
00:00:41:60.07096: Read from memory: 00000436=00 ( )
00:00:41:60.07104: Reading from RAM: 00000437=00 ( )
00:00:41:60.07108: Read from memory: 00000437=00 ( )
00:00:41:60.07112: Reading from RAM: 00000438=00 ( )
00:00:41:60.07116: Read from memory: 00000438=00 ( )
00:00:41:60.07120: Reading from RAM: 00000439=00 ( )
00:00:41:60.07124: Read from memory: 00000439=00 ( )
00:00:41:60.07132: Reading from RAM: 0000043A=00 ( )
00:00:41:60.07136: Read from memory: 0000043A=00 ( )
00:00:41:60.07140: Reading from RAM: 0000043B=08 ()
00:00:41:60.07144: Read from memory: 0000043B=08 ()
00:00:41:60.07148: Reading from RAM: 0000043C=00 ( )
00:00:41:60.07152: Read from memory: 0000043C=00 ( )
00:00:41:60.07160: Reading from RAM: 0000043D=10 ()
00:00:41:60.07164: Read from memory: 0000043D=10 ()
Show last 116 lines
00:00:41:60.07168: Reading from RAM: 0000043E=00 ( )
00:00:41:60.07172: Read from memory: 0000043E=00 ( )
00:00:41:60.07180: Reading from RAM: 0000043F=00 ( )
00:00:41:60.07184: Read from memory: 0000043F=00 ( )
00:00:41:60.07192: Reading from RAM: 00000440=00 ( )
00:00:41:60.07196: Read from memory: 00000440=00 ( )
00:00:41:60.07200: Reading from RAM: 00000441=00 ( )
00:00:41:60.07204: Read from memory: 00000441=00 ( )
00:00:41:60.07208: Reading from RAM: 00000442=20 ( )
00:00:41:60.07212: Read from memory: 00000442=20 ( )
00:00:41:60.07216: Reading from RAM: 00000443=00 ( )
00:00:41:60.07224: Read from memory: 00000443=00 ( )
00:00:41:60.07228: Reading from RAM: 00000444=04 ()
00:00:41:60.07264: Read from memory: 00000444=04 ()
00:00:41:60.07268: Reading from RAM: 00000445=00 ( )
00:00:41:60.07276: Read from memory: 00000445=00 ( )
00:00:41:60.07288: Reading from RAM: 00000446=20 ( )
00:00:41:60.07296: Read from memory: 00000446=20 ( )
00:00:41:60.07300: Reading from RAM: 00000447=00 ( )
00:00:41:60.07312: Read from memory: 00000447=00 ( )
00:00:41:60.07316: Reading from RAM: 00000448=0C ()
00:00:41:60.07320: Read from memory: 00000448=0C ()
00:00:41:60.07328: Reading from RAM: 00000449=00 ( )
00:00:41:60.07332: Read from memory: 00000449=00 ( )
00:00:41:60.07336: Reading from RAM: 0000044A=38 (8)
00:00:41:60.07340: Read from memory: 0000044A=38 (8)
00:00:41:60.07348: Reading from RAM: 0000044B=00 ( )
00:00:41:60.07352: Read from memory: 0000044B=00 ( )
00:00:41:60.07356: Reading from RAM: 0000044C=00 ( )
00:00:41:60.07364: Read from memory: 0000044C=00 ( )
00:00:41:60.07368: Reading from RAM: 0000044D=00 ( )
00:00:41:60.07372: Read from memory: 0000044D=00 ( )
00:00:41:60.07376: Reading from RAM: 0000044E=00 ( )
00:00:41:60.07380: Read from memory: 0000044E=00 ( )
00:00:41:60.07384: Reading from RAM: 0000044F=06 ()
00:00:41:60.07392: Read from memory: 0000044F=06 ()
00:00:41:60.07396: Reading from RAM: 00000450=20 ( )
00:00:41:60.07400: Read from memory: 00000450=20 ( )
00:00:41:60.07404: Reading from RAM: 00000451=00 ( )
00:00:41:60.07408: Read from memory: 00000451=00 ( )
00:00:41:60.07412: Reading from RAM: 00000452=00 ( )
00:00:41:60.07420: Read from memory: 00000452=00 ( )
00:00:41:60.07424: Reading from RAM: 00000453=00 ( )
00:00:41:60.07428: Read from memory: 00000453=00 ( )
00:00:41:60.07432: Reading from RAM: 00000454=00 ( )
00:00:41:60.07436: Read from memory: 00000454=00 ( )
00:00:41:60.07440: Reading from RAM: 00000455=00 ( )
00:00:41:60.07448: Read from memory: 00000455=00 ( )
00:00:41:60.07452: Reading from RAM: 00000456=00 ( )
00:00:41:60.07456: Read from memory: 00000456=00 ( )
00:00:41:60.07460: Reading from RAM: 00000457=00 ( )
00:00:41:60.07464: Read from memory: 00000457=00 ( )
00:00:41:60.07468: Reading from RAM: 00000458=00 ( )
00:00:41:60.07476: Read from memory: 00000458=00 ( )
00:00:41:60.07480: Reading from RAM: 00000459=00 ( )
00:00:41:60.07484: Read from memory: 00000459=00 ( )
00:00:41:60.07488: Reading from RAM: 0000045A=00 ( )
00:00:41:60.07492: Read from memory: 0000045A=00 ( )
00:00:41:60.07496: Reading from RAM: 0000045B=00 ( )
00:00:41:60.07504: Read from memory: 0000045B=00 ( )
00:00:41:60.07508: Reading from RAM: 0000045C=00 ( )
00:00:41:60.07512: Read from memory: 0000045C=00 ( )
00:00:41:60.07520: Reading from RAM: 0000045D=00 ( )
00:00:41:60.07524: Read from memory: 0000045D=00 ( )
00:00:41:60.07528: Reading from RAM: 0000045E=00 ( )
00:00:41:60.07536: Read from memory: 0000045E=00 ( )
00:00:41:60.07540: Reading from RAM: 0000045F=00 ( )
00:00:41:60.07544: Read from memory: 0000045F=00 ( )
00:00:41:60.07548: Reading from RAM: 00000460=00 ( )
00:00:41:60.07552: Read from memory: 00000460=00 ( )
00:00:41:60.07556: Reading from RAM: 00000461=00 ( )
00:00:41:60.07560: Read from memory: 00000461=00 ( )
00:00:41:60.07568: Reading from RAM: 00000462=00 ( )
00:00:41:60.07572: Read from memory: 00000462=00 ( )
00:00:41:60.07576: Reading from RAM: 00000463=00 ( )
00:00:41:60.07580: Read from memory: 00000463=00 ( )
00:00:41:60.07584: Reading from RAM: 00000464=00 ( )
00:00:41:60.07588: Read from memory: 00000464=00 ( )
00:00:41:60.07596: Reading from RAM: 00000465=00 ( )
00:00:41:60.07600: Read from memory: 00000465=00 ( )
00:00:41:60.07604: Reading from RAM: 00000466=00 ( )
00:00:41:60.07608: Read from memory: 00000466=00 ( )
00:00:41:60.07612: Reading from RAM: 00000467=06 ()
00:00:41:60.07616: Read from memory: 00000467=06 ()
00:00:41:60.07624: Reading from RAM: 00000468=00 ( )
00:00:41:60.07628: Read from memory: 00000468=00 ( )
00:00:41:60.07632: Reading from RAM: 00000469=10 ()
00:00:41:60.07636: Read from memory: 00000469=10 ()
00:00:41:60.07640: Reading from RAM: 0000046A=00 ( )
00:00:41:60.07644: Read from memory: 0000046A=00 ( )
00:00:41:60.07652: Reading from RAM: 0000046B=00 ( )
00:00:41:60.07656: Read from memory: 0000046B=00 ( )
00:00:41:60.07660: Reading from RAM: 0000046C=00 ( )
00:00:41:60.07664: Read from memory: 0000046C=00 ( )
00:00:41:60.07668: Reading from RAM: 0000046D=00 ( )
00:00:41:60.07672: Read from memory: 0000046D=00 ( )
00:00:41:60.07680: Reading from RAM: 0000046E=20 ( )
00:00:41:60.07684: Read from memory: 0000046E=20 ( )
00:00:41:60.07700: Reading from RAM: 0000046F=00 ( )
00:00:41:60.07708: Read from memory: 0000046F=00 ( )
00:00:41:60.07724: Reading from RAM: 00000470=04 ()
00:00:41:60.07728: Read from memory: 00000470=04 ()
00:00:41:60.07744: Reading from RAM: 00000471=00 ( )
00:00:41:60.07756: Read from memory: 00000471=00 ( )
00:00:41:60.07764: Reading from RAM: 00000472=20 ( )
00:00:41:60.07768: Read from memory: 00000472=20 ( )
00:00:41:60.07772: Reading from RAM: 00000473=00 ( )
00:00:41:60.07776: Read from memory: 00000473=00 ( )
00:00:41:60.07792: Reading from RAM: 00000474=0C ()
00:00:41:60.07796: Read from memory: 00000474=0C ()
00:00:41:60.07800: Reading from RAM: 00000475=00 ( )
00:00:41:60.07804: Read from memory: 00000475=00 ( )
00:00:41:60.07808: Reading from RAM: 00000476=40 (@)
00:00:41:60.07816: Read from memory: 00000476=40 (@)
00:00:41:60.07820: Reading from RAM: 00000477=00 ( )
00:00:41:60.07824: Read from memory: 00000477=00 ( )

After that I lose it. I don't have a clue anymore as to what's it's doing...

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

Reply 33 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've added some information about what it's doing during the task switch. It seems like it's correct? No errors are being thrown at the end?

Filename
debugger_protectedmode_diagnostics_20170119_1954.zip
File size
19.26 KiB
Downloads
72 downloads
File comment
Resulting log of the latest commit running the SuperSoft BIOS.
File license
Fair use/fair dealing exception

Although the BIOS still counts it as being incorrect. The task switching seems to work partially. The data being written to memory after the task switch is complete, is probably the MMU clearing it's cache into memory.

Edit: I've modified the task switching algorithm to disable MMU buffering of output to memory in order for not affecting switching active tasks to incorrect self tasks when this is done using two different TSS segment descriptors pointing to the same TSS.

Filename
debugger_protectedmode_diagnostics_MMUbufferdisabledduringTaskSwitch.zip
File size
19.22 KiB
Downloads
68 downloads
File comment
Same log, but with MMU buffering disabled during task switching.
File license
Fair use/fair dealing exception

Can you see what's going wrong(remember, it's in protected mode, so the segment registers don't point to real-mode segmented memory(value times 16))?

Edit: The current source code can be found at: https://bitbucket.org/superfury/unipcemu/src/ … ing.c?at=master
I've based the new NT/busy information on http://css.csail.mit.edu/6.858/2014/readings/i386/s07_06.htm

segmentWritten loads the TR segment with the selector, checks for a busy task(busy raising #GP) and marks the task as busy(Setting bit 1 of the Access Rights byte).

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

Reply 34 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've just looked at my system descriptor definitions:

#define AVL_SYSTEM_RESERVED_0 0
#define AVL_SYSTEM_TSS16BIT 1
#define AVL_SYSTEM_LDT 2
#define AVL_SYSTEM_BUSY_TSS16BIT 3
#define AVL_SYSTEM_CALLGATE16BIT 4
#define AVL_SYSTEM_TASKGATE 5
#define AVL_SYSTEM_INTERRUPTGATE16BIT 6
#define AVL_SYSTEM_TRAPGATE16BIT 7
#define AVL_SYSTEM_RESERVED_1 8
#define AVL_SYSTEM_TSS32BIT 9
#define AVL_SYSTEM_RESERVED_2 0xA
#define AVL_SYSTEM_BUSY_TSS32BIT 0xB
#define AVL_SYSTEM_CALLGATE32BIT 0xC
#define AVL_SYSTEM_RESERVED_3 0xD
#define AVL_SYSTEM_INTERRUPTGATE32BIT 0xE
#define AVL_SYSTEM_TRAPGATE32BIT 0xF

This doesn't seem to match the i386 documentation?

Edit: Looking at the 80386 documentation again, it seems it is correct: The article on the TSS segment descriptor describes a 32-bit TSS segment only, which I didn't saw.

Edit: Looking at the first task executed shows something strange:

00:00:35:31.04788: 0004:0010 (BB0200)MOVW BX, 0002
00:00:35:31.04816: EU&BIU cycles: 14, Operation cycles: 4, HW interrupt cycles: 0, Prefix cycles: 0, Exception cycles: 0, MMU read cycles: 0, MMU write cycles: 0, I/O bus cycles: 0, Prefetching cycles: 12, BIU prefetching cycles: 3
00:00:35:31.04820: Registers:
00:00:35:31.04824: AX: 0000, BX: 0000, CX: 0000, DX: 0000
00:00:35:31.04832: CS: 0004, DS: 000C, ES: 0020, SS: 0020, TR: 0058, LDTR:0038
00:00:35:31.04836: SP: 0600, BP: 1000, SI: 0000, DI: 0000
00:00:35:31.04840: IP: 0010, FLAGS: 0003
00:00:35:31.04844: CR0: FFF9
00:00:35:31.04848: GDTR: 0000000004A40098, IDTR: 00000000053C0180
00:00:35:31.04856: FLAGSINFO:C1p0a0zstido00n0
00:00:35:31.04860: Interrupt status: 0000000000000000
00:00:35:31.04864: VGA@137,46(CRT:249,68)
00:00:35:31.04868: Display=832,246

00:00:35:31.04876: 0004:0013 (33C9)XORW CX,CX
00:00:35:31.04904: EU&BIU cycles: 6, Operation cycles: 3, HW interrupt cycles: 0, Prefix cycles: 0, Exception cycles: 0, MMU read cycles: 0, MMU write cycles: 0, I/O bus cycles: 0, Prefetching cycles: 6, BIU prefetching cycles: 3
00:00:35:31.04908: Registers:
00:00:35:31.04912: AX: 0000, BX: 0002, CX: 0000, DX: 0000
00:00:35:31.04920: CS: 0004, DS: 000C, ES: 0020, SS: 0020, TR: 0058, LDTR:0038
00:00:35:31.04924: SP: 0600, BP: 1000, SI: 0000, DI: 0000
00:00:35:31.04928: IP: 0013, FLAGS: 0003
00:00:35:31.04932: CR0: FFF9
00:00:35:31.04936: GDTR: 0000000004A40098, IDTR: 00000000053C0180
00:00:35:31.04944: FLAGSINFO:C1p0a0zstido00n0
00:00:35:31.04948: Interrupt status: 0000000000000000
00:00:35:31.04952: VGA@170,46(CRT:282,68)
00:00:35:31.04956: Display=832,246

00:00:35:43.00320: 0004:0015 (E2FE)LOOP 0015
00:00:35:43.00348: EU&BIU cycles: 4, Operation cycles: 5, HW interrupt cycles: 0, Prefix cycles: 0, Exception cycles: 0, MMU read cycles: 0, MMU write cycles: 0, I/O bus cycles: 0, Prefetching cycles: 3, BIU prefetching cycles: 3
00:00:35:43.00348: Registers:
00:00:35:43.00356: AX: 0000, BX: 0002, CX: 0001, DX: 0000
00:00:35:43.00364: CS: 0004, DS: 000C, ES: 0020, SS: 0020, TR: 0058, LDTR:0038
00:00:35:43.00368: SP: 0600, BP: 1000, SI: 0000, DI: 0000
00:00:35:43.00372: IP: 0015, FLAGS: 0046
00:00:35:43.00376: CR0: FFF9
00:00:35:43.00380: GDTR: 0000000004A40098, IDTR: 00000000053C0180
00:00:35:43.00388: FLAGSINFO:c1P0a0Zstido00n0
00:00:35:43.00396: Interrupt status: 0000000000000000
00:00:35:43.00400: VGA@56,108(CRT:168,130)
00:00:35:43.00400: Display=832,246

How is it possible that a XOR CX,CX results in CX turning from 0 into 1? That shouldn't be possible?

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

Reply 35 of 69, by peterferrie

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:
After looking at the current running version of the SuperSoft BIOS on the AT: - First it switches to task 0x48(CALL). - Then it […]
Show full quote

After looking at the current running version of the SuperSoft BIOS on the AT:
- First it switches to task 0x48(CALL).
- Then it jumps to task 0x58 with TR=0x48(JMP).
- Then it #GP faults because it's trying to jump to task 0x58(JMP), which is marked busy.

Is this correct? It thinks the #GP fault is incorrect, but switching from task 0x58 to task 0x58 shouldn't be allowed(switching to it's own task)?

Jumps clear the busy bit in the task that is being left, before checking the busy bit in the task being entered.
For a jump to the same task, it should see the clear bit.

Reply 36 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've modified the task switching to first mark a task not busy and store the status&TSS, only checking busy(raising #GP) when the TR register is reloaded by the equivalent of a LTR instruction to switch to the other task(although this one doesn't check for modr/m parameters and CPL needing to be zero, thus raising a #GP on busy task, that's not itself, while reloading the TR register and continuing to load the registers when a valid TSS descriptor(which is non-busy, marked busy due to LTR) is used. Thus tasks switching to themselves using JMP will store state and restore, continuing past the JMP instruction.

Also, the moment the task switch starts reloading TR, it also lowers the current fault flag, allowing instructions to access memory again(for loading all values from the TSS).

What about fault levels(normal, double, triple fault)? When are they reset during the task switching process? At the first instruction fetch from the new task? Before loading TR? Also, how are double/triple faults detected in a x86 CPU? I'm currently using a simple counter, which is reset at each new instruction. It increases for each fault(So when it increases to 1, the fault is tried to handle. When it increases to 2, double fault is invoked instead. When it increases to 3, the CPU resets and aborts the current CPU instruction(Or any other CPU emulation) processing and returns straight to the main CPU emulation function for the CPU(CPU_exec), which finishes up and returns to the main emulation loop to process hardware and then(after any delay, depending on cycles spent, CPU speed and current real-time(high res timer) to synchronize with realtime and hardware) executes the first reset CPU instruction(at F000:0000 in this case).

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

Reply 37 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've just tested the latest commit. It now displays "int #10" and executes an 8042 CPU reset, leaving protected mode, when getting past the reentrant jmp 0078:0000.

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

Reply 38 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've made it so that:
- Stored tasks write to the correct location in memory(7th word (IP) and up instead of 7th dword).
- New TSS limit check is dependant on the TSS size(16-bit vs 32-bit task) instead of emulated CPU(80286 or 80386+).
- LDTR is always checked against the GDT limit, with the limit being the last byte addressable instead of the first unaddressable byte.
- NULL GDT entry(first entry of the GDT) now raises a #TS fault instead of a #GP fault.

For some reason, the BIOS still complains about interrupt #10? What's wrong with the #TS fault? An error code is pushed to indicate the new task being invalid.

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

Reply 39 of 69, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've just allowed the NULL GDT descriptor(segment selector bits 15 to 2 being zeroed, bits 1-0 ignored during checking) to be loaded into the GDT both during LLDT and task switching. Now the SuperSoft BIOS no longer complains about an interrupt #10, but instead on a interrupt #11(Segment not Present)? Is this maybe because it's excepecting a #NP exception because of the NULL LDTR, but it receives a #GP instead because of invalid segment loading?

Protected(With real mode support for segment selectors vs segment) mode handling: https://bitbucket.org/superfury/unipcemu/src/ … ion.c?at=master
Task switching handling: https://bitbucket.org/superfury/unipcemu/src/ … ing.c?at=master

Filename
debugger_protectedmode_diagnostics_20170122_1720.zip
File size
21.47 KiB
Downloads
67 downloads
File comment
Protected mode log of the latest UniPCemu commit for loading the LDTR with a NULL selector. Non-present LDTR descriptors loaded make LDT segment loading raise a #GP fault.
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