VOGONS


Reply 20 of 47, by superfury

User metadata
Rank l33t++
Rank
l33t++
ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ0)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here)
fb2: IRET flags=3202h
fb0: bx=B3h
fae: cx=2h
fac: 3h
faa: 0h
fa8: 1h
fa6: dx=417h
fa4: ax=26BCh
fa2: ip=3D64h
fa0: bp=FB4 <- bp
f9e: si <- sp

At 0020:000036d2, CX becomes the calling segment(417h), DX becomes the calling offset(3D64h)?
AX becomes the user stack. Then it compares some parameter(FAA=0h), which matches, so it doesn't jump.
It then pops SI(seems sane).

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ0)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here)
fb2: IRET flags=3202h
fb0: bx=B3h
fae: cx=2h
fac: 3h
faa: 0h
fa8: 1h
fa6: dx=417h
fa4: ax=26BCh
fa2: ip=3D64h
fa0: bp=FB4 <- bp <- sp

But then it moves SI into SP? Although this has the same effect as POP SP in this case? But it leaves EBP(FA0) intact, even though SP>BP at that moment? That's kind of strange behaviour?

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ0)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here) <- sp
fb2: IRET flags=3202h
fb0: bx=B3h
fae: cx=2h
fac: 3h
faa: 0h
fa8: 1h
fa6: dx=417h
fa4: ax=26BCh
fa2: ip=3D64h
fa0: bp=FB4 <- bp

It then pushes 0h 7 times, destroying the return segment? This seems very strange?

So the weird kind of code starts at 0020:000036e1, with the mov sp,si instruction?

Edit: OK. So the kernel stack isn't directly affected by the overwrites. The kernel stack still contains the original values of the originally interrupted thread/application.

So, SP is moved to SI, which is the originating stack pointer. So the top of stack is moved back to the previous stack frame at FB4, then new data overwrites it:

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ0)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here)
fb2: 0
fb0: 0
fae: 0
fac: 0
faa: 0
fa8: 0
fa6: 0
fa4: ip=36F4h *done by call 0000131c at 0020:000036f1*
fa2: ip=3D64h
fa0: bp=FB4 <- bp
f9e: ???
f9c: ???
f9a: ???
f98: ??? <- sp

It then pushes DS and 98h.

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ0)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here)
fb2: 0
fb0: 0
fae: 0
fac: 0
faa: 0
fa8: 0
fa6: 0
fa4: ip=36F4h *done by call 0000131c at 0020:000036f1*
fa2: ip=3D64h
fa0: bp=FB4 <- bp
f9e: ???
f9c: ???
f9a: ???
f98: ???
f96: ds=18h
f94: 98h <- sp

It pops DS again for the 98h selector to be loaded. And push ES.

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ0)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here)
fb2: 0
fb0: 0
fae: 0
fac: 0
faa: 0
fa8: 0
fa6: 0
fa4: ip=36F4h *done by call 0000131c at 0020:000036f1*
fa2: ip=3D64h
fa0: bp=FB4 <- bp
f9e: ???
f9c: ???
f9a: ???
f98: ???
f96: ds=18h
f94: es=5Bh <- sp

It then pushes 0h and finds bit 2 of DS:[401] being set.

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ0)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here)
fb2: 0
fb0: 0
fae: 0
fac: 0
faa: 0
fa8: 0
fa6: 0
fa4: ip=36F4h *done by call 0000131c at 0020:000036f1*
fa2: ip=3D64h
fa0: bp=FB4 <- bp
f9e: ???
f9c: ???
f9a: ???
f98: ???
f96: ds=18h
f94: es=5Bh
f92: 0h <- sp

Said action pushes all registers again, at 0020:0000132F.

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

Reply 21 of 47, by superfury

User metadata
Rank l33t++
Rank
l33t++
ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ0)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here)
fb2: 0
fb0: 0
fae: 0
fac: 0
faa: 0
fa8: 0
fa6: 0
fa4: ip=36F4h *done by call 0000131c at 0020:000036f1*
fa2: ip=3D64h
fa0: bp=FB4 <- bp
f9e: ???
f9c: ???
f9a: ???
f98: ???
f96: ds=18h
f94: es=5Bh
f92: 0h
f8e: eax=
f8a: edx=
f86: ecx=
f82: ebx=
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h <- sp

It then jumps to 134C again. That pushes FB4 from DS:[63E] again.
It then sets up a stack frame(MOV BP,SP), which is at f70h, after which it pushes AX(which is 5B) at 0020:00001352.

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ0)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here)
fb2: 0
fb0: 0
fae: 0
fac: 0
faa: 0
fa8: 0
fa6: 0
fa4: ip=36F4h *done by call 0000131c at 0020:000036f1*
fa2: ip=3D64h
fa0: bp=FB4 <- bp
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=18h
f94: es=5Bh
f92: 0h
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h
f6e: ax <- sp

It tests 0098(DS):403 for bit 0 being set, finds that it's set, continues on to set the TSS:2(SS0) to FFFFh, checks DS:401h bit 4, finding it being set.

It then stores FS/GS at SS:BP+28 and SS:BP+2A, which is at offsets f98 and f9a.

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ0)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here)
fb2: 0
fb0: 0
fae: 0
fac: 0
faa: 0
fa8: 0
fa6: 0
fa4: ip=36F4h *done by call 0000131c at 0020:000036f1*
fa2: ip=3D64h
fa0: bp=FB4 <- bp
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=18h
f94: es=5Bh
f92: 0h
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h <- sp

It then pops AX(see previous) again to retore it's 5Bh value, then stores BP at DS(98h):63E, which seems to be the previous stack frame somehow?

It then jumps to BP+34h, which is SS:FA4h's value, which is 36F4h. That jumps to 0020:000036FE.
It moves AX(5Bh) to BP+42h, so FA4h, which was the previously the IP value that was ignored and skipped.
It moves EBX(FFAh) to BP+40h, so at FA2h, so at the old IP value.

So it's writing some stack and the original interrupted procedure to the stack.

So the stack then becomes like this:

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ0)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here)
fb2: ax=5Bh
fb0: bx=FFAh
fae: 0
fac: cx=417h
faa: dx=26BCh
fa8: 0
fa6: 0
fa4: ip=36F4h *done by call 0000131c at 0020:000036f1*
fa2: ip=3D64h
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=18h
f94: es=5Bh
f92: 0h
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h <- sp <- bp

It then sumps to 1386 to handle it.

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

Reply 22 of 47, by superfury

User metadata
Rank l33t++
Rank
l33t++
ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ0)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here)
fb2: ax=5Bh
fb0: bx=FFAh
fae: 0
fac: cx=417h
faa: dx=26BCh
fa8: 0
fa6: 0
fa4: ip=36F4h *done by call 0000131c at 0020:000036f1*
fa2: ip=3D64h
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=18h
f94: es=5Bh
f92: 0h
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h <- sp <- bp

Then some more interesting stuff happens. It's now at 0020:00001389.

It checks the interrupted code segment against being non-kernel mode? It doesn't find that, so it stores the task's data segment in BX and loads ES for it's data segment to access the TSS.

It retrieves BP(f70) and stores it in AX. It adds 44h to it and stores that in the TSS's SS0 register. So SS0 then becomes FB4h, which is the stored EBP value of ds:63E ?

It sets BP+3E bits 13-14, so setting the EFLAGS IOPL bits:

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ0)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here)
fb2: ax=5Bh
fb0: bx=FFAh
fae: 3000h
fac: cx=417h
faa: dx=26BCh
fa8: 0
fa6: 0
fa4: ip=36F4h *done by call 0000131c at 0020:000036f1*
fa2: ip=3D64h
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=18h
f94: es=5Bh
f92: 0h
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h <- sp <- bp

It then pops ds:63E, restoring it to FB4h.

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ0)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here)
fb2: ax=5Bh
fb0: bx=FFAh
fae: 3000h
fac: cx=417h
faa: dx=26BCh
fa8: 0
fa6: 0
fa4: ip=36F4h *done by call 0000131c at 0020:000036f1*
fa2: ip=3D64h
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=18h
f94: es=5Bh
f92: 0h
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h <- sp
f70: ds:63E=fB4h <- bp

It then checks DS:401 for bit 4, which is set, thus it reaches 0020:000013b2.
It the executes the equivalent of a POPA instruction and skips the 0h value.

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ0)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here)
fb2: ax=5Bh
fb0: bx=FFAh
fae: 3000h
fac: cx=417h
faa: dx=26BCh
fa8: 0
fa6: 0
fa4: ip=36F4h *done by call 0000131c at 0020:000036f1*
fa2: ip=3D64h
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=18h
f94: es=5Bh <- sp
f92: 0h
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h <- bp

It then jumps to 0020:000013e4.

It then pops es,ds,fs,gs and skips 0xE bytes.

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ0)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here)
fb2: ax=5Bh
fb0: bx=FFAh
fae: 3000h
fac: cx=417h
faa: dx=26BCh
fa8: 0
fa6: 0
fa4: ip=36F4h *done by call 0000131c at 0020:000036f1*
fa2: ip=3D64h
fa0: bp=FB4
f9e: ???
f9c: ??? <- sp
f9a: gs=0
f98: fs=0
f96: ds=18h
f94: es=5Bh
f92: 0h
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h <- bp
ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ0)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here) <- SS0 after the handler completes and returns to the user mode handler.
fb2: ax=5Bh
fb0: bx=FFAh
fae: 3000h
fac: cx=417h
faa: dx=26BCh <- sp
fa8: 0
fa6: 0
fa4: ip=36F4h *done by call 0000131c at 0020:000036f1*
fa2: ip=3D64h
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=18h
f94: es=5Bh
f92: 0h
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h <- bp

Having reached that point, it executes IRET back to the Sound Blaster driver, reaching 0417:000026bc.

So it seems to have completed the handling correctly?

So, So, 0417:000026bc seems to be the IRQ5(interrupt 0xD) handler for the sound blaster driver that Jazz Jackrabbit's SB 2.0 driver has hooked?

So, at this point, the interrupt handler has been started.

Last edited by superfury on 2020-02-17, 09:47. Edited 1 time in total.

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

Reply 23 of 47, by superfury

User metadata
Rank l33t++
Rank
l33t++

OK. The interrupt handler itself for IRQ5 does nothing special, just finds nothing to do, then IRETs back to B3:0002 with EFLAGS=3202. And of course that executes HLT, which traps back to segment 20h, which is supposed to handle the fault(which is a #GP(0) fault).

That should be this one(line 149629 on the segment B3 log):

00:20:13:11.09104: #GP fault(00000000)!
MMU: Reading from real(r): 000a7e58=7a (z)
Reading from RAM(r): 00107e58=7a (z)
Reading from physical memory(r): 00107e58=7a (z)
Reading from paged memory(r): 00107e58=7a (z)
MMU: Reading from real(r): 000a7e59=0c ()
Reading from RAM(r): 00107e59=0c ()
Reading from physical memory(r): 00107e59=0c ()
Reading from paged memory(r): 00107e59=0c ()
MMU: Reading from real(r): 000a7e5a=20 ( )
Reading from RAM(r): 00107e5a=20 ( )
Reading from physical memory(r): 00107e5a=20 ( )
Reading from paged memory(r): 00107e5a=20 ( )
MMU: Reading from real(r): 000a7e5b=00 ( )
Reading from RAM(r): 00107e5b=00 ( )
Reading from physical memory(r): 00107e5b=00 ( )
Reading from paged memory(r): 00107e5b=00 ( )
MMU: Reading from real(r): 000a7e5c=00 ( )
Reading from RAM(r): 00107e5c=00 ( )
Reading from physical memory(r): 00107e5c=00 ( )
Reading from paged memory(r): 00107e5c=00 ( )
MMU: Reading from real(r): 000a7e5d=e6 (æ)
Reading from RAM(r): 00107e5d=e6 (æ)
Reading from physical memory(r): 00107e5d=e6 (æ)
Reading from paged memory(r): 00107e5d=e6 (æ)
MMU: Reading from real(r): 000a7e5e=00 ( )
Reading from RAM(r): 00107e5e=00 ( )
Reading from physical memory(r): 00107e5e=00 ( )
Reading from paged memory(r): 00107e5e=00 ( )
MMU: Reading from real(r): 000a7e5f=00 ( )
Reading from RAM(r): 00107e5f=00 ( )
Reading from physical memory(r): 00107e5f=00 ( )
Reading from paged memory(r): 00107e5f=00 ( )
MMU: Reading from real(r): 00012800=ff (ÿ)
Reading from RAM(r): 00012800=ff (ÿ)
Reading from physical memory(r): 00012800=ff (ÿ)
Reading from paged memory(r): 00012800=ff (ÿ)
MMU: Reading from real(r): 00012801=ff (ÿ)
Reading from RAM(r): 00012801=ff (ÿ)
Reading from physical memory(r): 00012801=ff (ÿ)
Reading from paged memory(r): 00012801=ff (ÿ)
MMU: Reading from real(r): 00012802=00 ( )
Reading from RAM(r): 00012802=00 ( )
Reading from physical memory(r): 00012802=00 ( )
Reading from paged memory(r): 00012802=00 ( )
MMU: Reading from real(r): 00012803=10 ()
Reading from RAM(r): 00012803=10 ()
Reading from physical memory(r): 00012803=10 ()
Reading from paged memory(r): 00012803=10 ()
MMU: Reading from real(r): 00012804=10 ()
Reading from RAM(r): 00012804=10 ()
Reading from physical memory(r): 00012804=10 ()
Reading from paged memory(r): 00012804=10 ()
MMU: Reading from real(r): 00012805=9b (›)
Reading from RAM(r): 00012805=9b (›)
Reading from physical memory(r): 00012805=9b (›)
Reading from paged memory(r): 00012805=9b (›)
MMU: Reading from real(r): 00012806=00 ( )
Reading from RAM(r): 00012806=00 ( )
Reading from physical memory(r): 00012806=00 ( )
Show last 56 lines
Reading from paged memory(r): 00012806=00 ( )
MMU: Reading from real(r): 00012807=00 ( )
Reading from RAM(r): 00012807=00 ( )
Reading from physical memory(r): 00012807=00 ( )
Reading from paged memory(r): 00012807=00 ( )
MMU: Reading from real(r): 000127f8=ff (ÿ)
Reading from RAM(r): 000127f8=ff (ÿ)
Reading from physical memory(r): 000127f8=ff (ÿ)
Reading from paged memory(r): 000127f8=ff (ÿ)
MMU: Reading from real(r): 000127f9=ff (ÿ)
Reading from RAM(r): 000127f9=ff (ÿ)
Reading from physical memory(r): 000127f9=ff (ÿ)
Reading from paged memory(r): 000127f9=ff (ÿ)
MMU: Reading from real(r): 000127fa=50 (P)
Reading from RAM(r): 000127fa=50 (P)
Reading from physical memory(r): 000127fa=50 (P)
Reading from paged memory(r): 000127fa=50 (P)
MMU: Reading from real(r): 000127fb=4c (L)
Reading from RAM(r): 000127fb=4c (L)
Reading from physical memory(r): 000127fb=4c (L)
Reading from paged memory(r): 000127fb=4c (L)
MMU: Reading from real(r): 000127fc=01 ()
Reading from RAM(r): 000127fc=01 ()
Reading from physical memory(r): 000127fc=01 ()
Reading from paged memory(r): 000127fc=01 ()
MMU: Reading from real(r): 000127fd=93 (“)
Reading from RAM(r): 000127fd=93 (“)
Reading from physical memory(r): 000127fd=93 (“)
Reading from paged memory(r): 000127fd=93 (“)
MMU: Reading from real(r): 000127fe=00 ( )
Reading from RAM(r): 000127fe=00 ( )
Reading from physical memory(r): 000127fe=00 ( )
Reading from paged memory(r): 000127fe=00 ( )
MMU: Reading from real(r): 000127ff=00 ( )
Reading from RAM(r): 000127ff=00 ( )
Reading from physical memory(r): 000127ff=00 ( )
Reading from paged memory(r): 000127ff=00 ( )
00b3:00000002 F4 hlt RealRAM(p):000a85f2=f4(ô); RAM(p):001085f2=f4(ô); Physical(p):001085f2=f4(ô); Paged(p):001085f2=f4(ô); Normal(p):00000002=f4(ô); RealRAM(p):000a85f3=02(); RAM(p):001085f3=02(); Physical(p):001085f3=02(); Paged(p):001085f3=02(); Normal(p):00000003=02(); RealRAM(p):000a85f4=00( ); RAM(p):001085f4=00( ); Physical(p):001085f4=00( ); Paged(p):001085f4=00( ); Normal(p):00000004=00( ); RealRAM(p):000a85f5=00( ); RAM(p):001085f5=00( ); Physical(p):001085f5=00( ); Paged(p):001085f5=00( ); Normal(p):00000005=00( ); RealRAM(p):000a85f6=20( ); RAM(p):001085f6=20( ); Physical(p):001085f6=20( ); Paged(p):001085f6=20( ); Normal(p):00000006=20( ); RealRAM(p):000a85f7=00( ); RAM(p):001085f7=00( ); Physical(p):001085f7=00( ); Paged(p):001085f7=00( ); Normal(p):00000007=00( ); RealRAM(p):000a85f8=21(!); RAM(p):001085f8=21(!); Physical(p):001085f8=21(!); Paged(p):001085f8=21(!); Normal(p):00000008=21(!); RealRAM(p):000a85f9=3f(?); RAM(p):001085f9=3f(?); Physical(p):001085f9=3f(?); Paged(p):001085f9=3f(?); Normal(p):00000009=3f(?); RealRAM(p):000a85fa=00( ); RAM(p):001085fa=00( ); Physical(p):001085fa=00( ); Paged(p):001085fa=00( ); Normal(p):0000000a=00( ); RealRAM(p):000a85fb=00( ); RAM(p):001085fb=00( ); Physical(p):001085fb=00( ); Paged(p):001085fb=00( ); Normal(p):0000000b=00( ); RealRAM(p):000a85fc=f4(ô); RAM(p):001085fc=f4(ô); Physical(p):001085fc=f4(ô); Paged(p):001085fc=f4(ô); Normal(p):0000000c=f4(ô); RealRAM(p):000a85fd=02(); RAM(p):001085fd=02(); Physical(p):001085fd=02(); Paged(p):001085fd=02(); Normal(p):0000000d=02(); RealRAM(p):000a85fe=00( ); RAM(p):001085fe=00( ); Physical(p):001085fe=00( ); Paged(p):001085fe=00( ); Normal(p):0000000e=00( ); RealRAM(p):000a85ff=00( ); RAM(p):001085ff=00( ); Physical(p):001085ff=00( ); Paged(p):001085ff=00( ); Normal(p):0000000f=00( ); RealRAM(p):000a8600=20( ); RAM(p):00108600=20( ); Physical(p):00108600=20( ); Paged(p):00108600=20( ); Normal(p):00000010=20( ); RealRAM(p):000a8601=00( ); RAM(p):00108601=00( ); Physical(p):00108601=00( ); Paged(p):00108601=00( ); Normal(p):00000011=00( ); RealRAM(r):000aa5f2=b4(´); RAM(r):0010a5f2=b4(´); Physical(r):0010a5f2=b4(´); Paged(r):0010a5f2=b4(´); Normal(r):00000002=b4(´); RealRAM(r):000aa5f3=0f(); RAM(r):0010a5f3=0f(); Physical(r):0010a5f3=0f(); Paged(r):0010a5f3=0f(); Normal(r):00000003=0f(); RealRAM(r):000aa5f4=18(); RAM(r):0010a5f4=18(); Physical(r):0010a5f4=18(); Paged(r):0010a5f4=18(); Normal(r):00000004=18(); RealRAM(r):000aa5f5=00( ); RAM(r):0010a5f5=00( ); Physical(r):0010a5f5=00( ); Paged(r):0010a5f5=00( ); Normal(r):00000005=00( ); Normal(w):00000fb2=5b([); Paged(w):00015c02=5b([); Physical(w):00015c02=5b([); RAM(w):00015c02=5b([); RealRAM(w):00015c02=5b([); Normal(w):00000fb3=00( ); Paged(w):00015c03=00( ); Physical(w):00015c03=00( ); RAM(w):00015c03=00( ); RealRAM(w):00015c03=00( ); Normal(w):00000fb0=00( ); Paged(w):00015c00=00( ); Physical(w):00015c00=00( ); RAM(w):00015c00=00( ); RealRAM(w):00015c00=00( ); Normal(w):00000fb1=10(); Paged(w):00015c01=10(); Physical(w):00015c01=10(); RAM(w):00015c01=10(); RealRAM(w):00015c01=10(); Normal(w):00000fae=02(); Paged(w):00015bfe=02(); Physical(w):00015bfe=02(); RAM(w):00015bfe=02(); RealRAM(w):00015bfe=02(); Normal(w):00000faf=32(2); Paged(w):00015bff=32(2); Physical(w):00015bff=32(2); RAM(w):00015bff=32(2); RealRAM(w):00015bff=32(2); Normal(w):00000fac=b3(³); Paged(w):00015bfc=b3(³); Physical(w):00015bfc=b3(³); RAM(w):00015bfc=b3(³); RealRAM(w):00015bfc=b3(³); Normal(w):00000fad=00( ); Paged(w):00015bfd=00( ); Physical(w):00015bfd=00( ); RAM(w):00015bfd=00( ); RealRAM(w):00015bfd=00( ); Normal(w):00000faa=02(); Paged(w):00015bfa=02(); Physical(w):00015bfa=02(); RAM(w):00015bfa=02(); RealRAM(w):00015bfa=02(); Normal(w):00000fab=00( ); Paged(w):00015bfb=00( ); Physical(w):00015bfb=00( ); RAM(w):00015bfb=00( ); RealRAM(w):00015bfb=00( ); Normal(w):00000fa8=00( ); Paged(w):00015bf8=00( ); Physical(w):00015bf8=00( ); RAM(w):00015bf8=00( ); RealRAM(w):00015bf8=00( ); Normal(w):00000fa9=00( ); Paged(w):00015bf9=00( ); Physical(w):00015bf9=00( ); RAM(w):00015bf9=00( ); RealRAM(w):00015bf9=00( )
Registers:
EAX: 0000005b EBX: 00000ffa ECX: 00000417 EDX: 000026bc
ESP: 00001000 EBP: 00000fa0 ESI: 00000fb4 EDI: 00001000
CS: 00b3 DS: 0000 ES: 005b FS: 0000 GS: 0000 SS: 005b TR: 0158 LDTR: 0168
EIP: 00000002 EFLAGS: 00003202
CR0: 00000001 CR1: 00000000 CR2: 00000000 CR3: 00000000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000127e003ff IDTR: 000000107df007ff
CS descriptor: 0000FB1085F00FFF
DS descriptor: 00007303884026F0
ES descriptor: 0000F31095F00FFF
FS descriptor: 000073000000FFFF
GS descriptor: 000073000000FFFF
SS descriptor: 0000F31095F00FFF
TR descriptor: 00008310A5F00BF9
LDTR descriptor: 000082FCFF8007FF
FLAGSINFO: 00000000000000vr0n11odItsz0a0p1c

Edit: And so, it once again ends up at 0020:00000c7a for the second time, this time from within the interrupt handler itself causing a #GP(0) fault.

And because it's actually a fault handler in this case, it reads the correct byte in this case(B3, which is the cause CS segment of the fault). Although that doesn't change the code that's executing based on that fact.

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

Reply 24 of 47, by superfury

User metadata
Rank l33t++
Rank
l33t++

This time, SS0 is FB4, so a different decrease should be there. It once again substracts BP from AX, but this time it gets 0xE(error code pushed) instead of 0xC(no error code pushed)!
So this time it falls through the jump to CBCh, and continues on to 0020:00000c9e.

So at 0020:00000c9e, the kernel stack is as follows(mostly remainder from the previous one):

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ5)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here) <- SS0 when the interrupt handler completes and returns to kernel mode.
fb2: ss=5Bh
fb0: sp=1000h
fae: flags=3202
fac: cs=B3h
faa: ip=2h
fa8: errcode=0 <- sp
fa6: 0
fa4: ip=36F4h *done by call 0000131c at 0020:000036f1*
fa2: ip=3D64h
fa0: bp=FB4 <- bp
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=18h
f94: es=5Bh
f92: 0h
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h

It sets up the basic stack frame and starts executing:

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ5)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here) <- SS0 when the interrupt handler completes and returns to kernel mode.
fb2: ss=5Bh
fb0: sp=1000h
fae: flags=3202
fac: cs=B3h
faa: ip=2h
fa8: errcode=0
fa6: bp=FB4h <- sp <- bp
fa4: ip=36F4h *done by call 0000131c at 0020:000036f1*
fa2: ip=3D64h
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=18h
f94: es=5Bh
f92: 0h
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h

It then pushes ES and AX, and checks the privilege level, ending up at IP=C86.

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ5)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here) <- SS0 when the interrupt handler completes and returns to kernel mode.
fb2: ss=5Bh
fb0: sp=1000h
fae: flags=3202
fac: cs=B3h
faa: ip=2h
fa8: errcode=0
fa6: bp=FB4h<- bp
fa4: es=5Bh
fa2: ax=5Bh <- sp
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=18h
f94: es=5Bh
f92: 0h
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h

It checks the privilege level correctly this time, then ends up at 0020:00000c86.

It checks the TSS as always, but this time finds a decrease of 0xE instead of 0xC. Thus it pops AX, then ES, then BP. So it ends up at the interrupt error code again, but BP=FB4 again in this case(as it's popped at the end).

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ5)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here) <- SS0 when the interrupt handler completes and returns to kernel mode. <- bp
fb2: ss=5Bh
fb0: sp=1000h
fae: flags=3202
fac: cs=B3h
faa: ip=2h
fa8: errcode=0 <- sp
fa6: bp=FB4h
fa4: es=5Bh
fa2: ax=5Bh
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=18h
f94: es=5Bh
f92: 0h
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h

It then pushed 10Dh and calls IP=131Ch

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ5)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here) <- SS0 when the interrupt handler completes and returns to kernel mode. <- bp
fb2: ss=5Bh
fb0: sp=1000h
fae: flags=3202
fac: cs=B3h
faa: ip=2h
fa8: errcode=0
fa6: 010Dh
fa4: ip=CA7h <- sp
fa2: ax=5Bh
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=18h
f94: es=5Bh
f92: 0h
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h

That one allocates 12(0xC) bytes on the stack:

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ5)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here) <- SS0 when the interrupt handler completes and returns to kernel mode. <- bp
fb2: ss=5Bh
fb0: sp=1000h
fae: flags=3202
fac: cs=B3h
faa: ip=2h
fa8: errcode=0
fa6: 010Dh
fa4: ip=CA7h
fa2: ax=5Bh
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0 <- sp
f96: ds=18h
f94: es=5Bh
f92: 0h
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h

It then pushes DS and 98h, followed by a pop to DS:

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ5)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here) <- SS0 when the interrupt handler completes and returns to kernel mode. <- bp
fb2: ss=5Bh
fb0: sp=1000h
fae: flags=3202
fac: cs=B3h
faa: ip=2h
fa8: errcode=0
fa6: 010Dh
fa4: ip=CA7h
fa2: ax=5Bh
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=0 <- sp
f94: 98h
f92: 0h
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h

It then pushes ES and 0h:

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ5)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here) <- SS0 when the interrupt handler completes and returns to kernel mode. <- bp
fb2: ss=5Bh
fb0: sp=1000h
fae: flags=3202
fac: cs=B3h
faa: ip=2h
fa8: errcode=0
fa6: 010Dh
fa4: ip=CA7h
fa2: ax=5Bh
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=0
f94: es=5Bh
f92: 0h <- sp
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h

It once again checks bit 4 of DS(98):401, which is still set, thus not jumped, and executes a PUSHAD at 0020:0000132F.

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ5)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here) <- SS0 when the interrupt handler completes and returns to kernel mode. <- bp
fb2: ss=5Bh
fb0: sp=1000h
fae: flags=3202
fac: cs=B3h
faa: ip=2h
fa8: errcode=0
fa6: 010Dh
fa4: ip=CA7h
fa2: ax=5Bh
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=0
f94: es=5Bh
f92: 0h <- sp
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h

So after said push, it's like this:

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ5)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here) <- SS0 when the interrupt handler completes and returns to kernel mode. <- bp
fb2: ss=5Bh
fb0: sp=1000h
fae: flags=3202
fac: cs=B3h
faa: ip=2h
fa8: errcode=0
fa6: 010Dh
fa4: ip=CA7h
fa2: ax=5Bh
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=0
f94: es=5Bh
f92: 0h <- sp
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h <- sp
f70: ds:63E=fB4h

So although SP changes there(lowered by 0x20 because of the PUSHAD instruction), the memory content doesn't change(in this case).

It then jumps to 0020:0000134C and pushes DS:[063e] on the stack:

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ5)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here) <- SS0 when the interrupt handler completes and returns to kernel mode. <- bp
fb2: ss=5Bh
fb0: sp=1000h
fae: flags=3202
fac: cs=B3h
faa: ip=2h
fa8: errcode=0
fa6: 010Dh
fa4: ip=CA7h
fa2: ax=5Bh
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=0
f94: es=5Bh
f92: 0h <- sp
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h <- sp

It then sets bp to the new frame top(f70) and pushes ax.

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ5)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here) <- SS0 when the interrupt handler completes and returns to kernel mode.
fb2: ss=5Bh
fb0: sp=1000h
fae: flags=3202
fac: cs=B3h
faa: ip=2h
fa8: errcode=0
fa6: 010Dh
fa4: ip=CA7h
fa2: ax=5Bh
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=0
f94: es=5Bh
f92: 0h <- sp
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h <- bp
f6e: ax=5Bh <- sp

It then checks DS(98h):483 for bit 1 being set, which it is, thus not jumping. Thus reaching 0020:0000135b.

It then loads ES with the TSS, moves FFFFh to it's SP0 pointer, checks DS:[0401] for bit 4 being set(it still is), thus reaching 0020:00001372.

It then saves FS at BP+28(F98) and GS at BP+2A(F9A):

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ5)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here) <- SS0 when the interrupt handler completes and returns to kernel mode.
fb2: ss=5Bh
fb0: sp=1000h
fae: flags=3202
fac: cs=B3h
faa: ip=2h
fa8: errcode=0
fa6: 010Dh
fa4: ip=CA7h
fa2: ax=5Bh
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=0
f94: es=5Bh
f92: 0h <- sp
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h <- bp
f6e: ax=5Bh <- sp

That doesn't change memory, so still 0h.
It then clears FS and GS and pops AX:

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ5)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here) <- SS0 when the interrupt handler completes and returns to kernel mode.
fb2: ss=5Bh
fb0: sp=1000h
fae: flags=3202
fac: cs=B3h
faa: ip=2h
fa8: errcode=0
fa6: 010Dh
fa4: ip=CA7h
fa2: ax=5Bh
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=0
f94: es=5Bh
f92: 0h <- sp
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h <- bp <- sp
f6e: ax=5Bh

It then moves BP(f70) to ds:[063e] and jumps to the address at BP+34(at SS:FA4, thus address CA7).

It then checks BP+2E(FAE) for bit 9(the flags being 3202h). That doesn't jump because it's set.
It then enables interrupts(weird, in the middle of normal interrupt handling)?

The compare of BP+3C against B3 after that matches, but immediately after that instruction, I see IDT vector 68h being read, thus a INT 0xD.

OK... That can happen(in this case because the sound blaster has rendered another sample, which triggers an IRQ each sample read from DMA?). But for some weird reason, ESP is "f6a"? ...
Hmmm... That's probably because this time, it's an interrupt from kernel privilege, thus pushing 6 bytes on the stack(EFLAGS,CS,IP to be exact). So instead of decreasing ESP by C or E, another case happens, where it's only 6 bytes lower? Although SS0 is FFFFh in this case.

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

Reply 25 of 47, by superfury

User metadata
Rank l33t++
Rank
l33t++

So, the INT 0xD handler(that's triggering during the existing 0xD handler being terminated) starts as usual:

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ5)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here) <- SS0 when the interrupt handler completes and returns to kernel mode.
fb2: ss=5Bh
fb0: sp=1000h
fae: flags=3202
fac: cs=B3h
faa: ip=2h
fa8: errcode=0
fa6: 010Dh
fa4: ip=CA7h
fa2: ax=5Bh
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=0
f94: es=5Bh
f92: 0h <- sp
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h <- bp
f6e: flags=3206 with compare information added
f6c: cs=20h
f6a: ip=CB4h <- sp

It then pushes BP and MOV BP,SP for the stack frame:

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ5)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here) <- SS0 when the interrupt handler completes and returns to kernel mode.
fb2: ss=5Bh
fb0: sp=1000h
fae: flags=3202
fac: cs=B3h
faa: ip=2h
fa8: errcode=0
fa6: 010Dh
fa4: ip=CA7h
fa2: ax=5Bh
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=0
f94: es=5Bh
f92: 0h
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h
f6e: flags=3206 with compare information added
f6c: cs=20h
f6a: ip=CB4h
f68: bp=f70h <- sp <- bp

It then pushes AX and checks BP+6 for bit 1 being set or not.

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ5)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here) <- SS0 when the interrupt handler completes and returns to kernel mode.
fb2: ss=5Bh
fb0: sp=1000h
fae: flags=3202
fac: cs=B3h
faa: ip=2h
fa8: errcode=0
fa6: 010Dh
fa4: ip=CA7h
fa2: ax=5Bh
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=0
f94: es=5Bh
f92: 0h
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h
f6e: flags=3206 with compare information added
f6c: cs=20h
f6a: ip=CB4h
f68: bp=f70h <- bp
f66: es=160h
f64: ax=5Bh <- sp

It then checks BP+06h for bit 1 being set(which it is), thus falling through.

It then stores the TSS data segment into ES again for it's access.
It then loads AX with the SS0 value(which is FFFFh).

It then checks for FFFFh and finds that, thus jumping to CBCh, which pops AX and then ES from the stack.

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ5)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here) <- SS0 when the interrupt handler completes and returns to kernel mode.
fb2: ss=5Bh
fb0: sp=1000h
fae: flags=3202
fac: cs=B3h
faa: ip=2h
fa8: errcode=0
fa6: 010Dh
fa4: ip=CA7h
fa2: ax=5Bh
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=0
f94: es=5Bh
f92: 0h
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h
f6e: flags=3206 with compare information added
f6c: cs=20h
f6a: ip=CB4h
f68: bp=f70h <- bp <- sp
f66: es=160h
f64: ax=5Bh

It then pops BP from the stack, returning it to F70h.

It then pushes 0h and Dh on the stack(for handling the interrupt) and calls 0020:0000131c.

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ5)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here) <- SS0 when the interrupt handler completes and returns to kernel mode.
fb2: ss=5Bh
fb0: sp=1000h
fae: flags=3202
fac: cs=B3h
faa: ip=2h
fa8: errcode=0
fa6: 010Dh
fa4: ip=CA7h
fa2: ax=5Bh
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=0
f94: es=5Bh
f92: 0h
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h <- bp
f6e: flags=3206 with compare information added
f6c: cs=20h
f6a: ip=CB4h
f68: 0h
f66: Dh
f64: ip=CC6h <- sp

It then allocates 12 bytes on the stack:

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ5)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here) <- SS0 when the interrupt handler completes and returns to kernel mode.
fb2: ss=5Bh
fb0: sp=1000h
fae: flags=3202
fac: cs=B3h
faa: ip=2h
fa8: errcode=0
fa6: 010Dh
fa4: ip=CA7h
fa2: ax=5Bh
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=0
f94: es=5Bh
f92: 0h
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h <- bp
f6e: flags=3206 with compare information added
f6c: cs=20h
f6a: ip=CB4h
f68: 0h
f66: Dh
f64: ip=CC6h
f62: ???
Show last 5 lines
f60: ???
f5e: ???
f5c: ???
f5a: ???
f58: ??? <- sp

It then pushes DS, then 98h, popping it into DS.

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ5)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here) <- SS0 when the interrupt handler completes and returns to kernel mode.
fb2: ss=5Bh
fb0: sp=1000h
fae: flags=3202
fac: cs=B3h
faa: ip=2h
fa8: errcode=0
fa6: 010Dh
fa4: ip=CA7h
fa2: ax=5Bh
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=0
f94: es=5Bh
f92: 0h
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h <- bp
f6e: flags=3206 with compare information added
f6c: cs=20h
f6a: ip=CB4h
f68: 0h
f66: Dh
f64: ip=CC6h
f62: ???
Show last 7 lines
f60: ???
f5e: ???
f5c: ???
f5a: ???
f58: ???
f56: DS=98h <- sp
f54: 98h

It then pushes ES and 0h:

ff8: sp0 base for the original IRQ0 handler to return to the never returning code
ff6: IRET ss
ff4: IRET sp
ff2: IRET flags
ff0: IRET cs
fee: IRET ip (base frame for IRQ5)
fec: 0h
fea: Dh
fe8: call IP=cc6h
fe6: ???
fe4: ???
fe2: ???
fe0: ???
fde: gs
ffc: fs
fda: ds
fd8: es
fd6: 0h
fd2: eax=1Ch
fce: ecx=0
fca: edx=Ah
fc6: ebx=0
fc2: esp=FD6h
fbe: ebp=3EB4
fba: esi=2127h
fb6: edi=2174h
fb4: [ds:63E]=fb4h (check against 75h happened here) <- SS0 when the interrupt handler completes and returns to kernel mode.
fb2: ss=5Bh
fb0: sp=1000h
fae: flags=3202
fac: cs=B3h
faa: ip=2h
fa8: errcode=0
fa6: 010Dh
fa4: ip=CA7h
fa2: ax=5Bh
fa0: bp=FB4
f9e: ???
f9c: ???
f9a: gs=0
f98: fs=0
f96: ds=0
f94: es=5Bh
f92: 0h
f8e: eax=5Bh
f8a: edx=26BCh
f86: ecx=417h
f82: ebx=FFAh
f7e: esp=f92h
f7a: ebp=fa0h
f76: esi=fb4h
f72: edi=1000h
f70: ds:63E=fB4h <- bp
f6e: flags=3206 with compare information added
f6c: cs=20h
f6a: ip=CB4h
f68: 0h
f66: Dh
f64: ip=CC6h
f62: ???
Show last 8 lines
f60: ???
f5e: ???
f5c: ???
f5a: ???
f58: ???
f56: ds=98h
f54: es=160h
f52: 0h <- sp

It then checks DS:[401] bit 4(which of course is still set), thus continuing on to 0020:0000132F, executing the PUSHAD instruction.

This handles the normal interrupt?

0020:0000132f 66 60 pushad	RealRAM(p):000a233d=00( ); RAM(p):0010233d=00( ); Physical(p):0010233d=00( ); Paged(p):0010233d=00( ); Normal(p):0000133d=00( ); RealRAM(p):000a233e=53(S); RAM(p):0010233e=53(S); Physical(p):0010233e=53(S); Paged(p):0010233e=53(S); Normal(p):0000133e=53(S); Paged(w):00015b9e=5b([); Physical(w):00015b9e=5b([); RAM(w):00015b9e=5b([); RealRAM(w):00015b9e=5b([); Paged(w):00015b9f=00( ); Physical(w):00015b9f=00( ); RAM(w):00015b9f=00( ); RealRAM(w):00015b9f=00( ); Paged(w):00015ba0=00( ); Physical(w):00015ba0=00( ); RAM(w):00015ba0=00( ); RealRAM(w):00015ba0=00( ); Paged(w):00015ba1=00( ); Physical(w):00015ba1=00( ); RAM(w):00015ba1=00( ); RealRAM(w):00015ba1=00( ); Paged(w):00015b9a=17(); Physical(w):00015b9a=17(); RAM(w):00015b9a=17(); RealRAM(w):00015b9a=17(); Paged(w):00015b9b=04(); Physical(w):00015b9b=04(); RAM(w):00015b9b=04(); RealRAM(w):00015b9b=04(); Paged(w):00015b9c=00( ); Physical(w):00015b9c=00( ); RAM(w):00015b9c=00( ); RealRAM(w):00015b9c=00( ); Paged(w):00015b9d=00( ); Physical(w):00015b9d=00( ); RAM(w):00015b9d=00( ); RealRAM(w):00015b9d=00( ); Paged(w):00015b96=bc(?); Physical(w):00015b96=bc(?); RAM(w):00015b96=bc(?); RealRAM(w):00015b96=bc(?); Paged(w):00015b97=26(&); Physical(w):00015b97=26(&); RAM(w):00015b97=26(&); RealRAM(w):00015b97=26(&); Paged(w):00015b98=00( ); Physical(w):00015b98=00( ); RAM(w):00015b98=00( ); RealRAM(w):00015b98=00( ); Paged(w):00015b99=00( ); Physical(w):00015b99=00( ); RAM(w):00015b99=00( ); RealRAM(w):00015b99=00( ); Paged(w):00015b92=fa(?); Physical(w):00015b92=fa(?); RAM(w):00015b92=fa(?); RealRAM(w):00015b92=fa(?); Paged(w):00015b93=0f(); Physical(w):00015b93=0f(); RAM(w):00015b93=0f(); RealRAM(w):00015b93=0f(); Paged(w):00015b94=00( ); Physical(w):00015b94=00( ); RAM(w):00015b94=00( ); RealRAM(w):00015b94=00( ); Paged(w):00015b95=00( ); Physical(w):00015b95=00( ); RAM(w):00015b95=00( ); RealRAM(w):00015b95=00( ); Paged(w):00015b8e=52(R); Physical(w):00015b8e=52(R); RAM(w):00015b8e=52(R); RealRAM(w):00015b8e=52(R); Paged(w):00015b8f=0f(); Physical(w):00015b8f=0f(); RAM(w):00015b8f=0f(); RealRAM(w):00015b8f=0f(); Paged(w):00015b90=00( ); Physical(w):00015b90=00( ); RAM(w):00015b90=00( ); RealRAM(w):00015b90=00( ); Paged(w):00015b91=00( ); Physical(w):00015b91=00( ); RAM(w):00015b91=00( ); RealRAM(w):00015b91=00( ); Paged(w):00015b8a=70(p); Physical(w):00015b8a=70(p); RAM(w):00015b8a=70(p); RealRAM(w):00015b8a=70(p); Paged(w):00015b8b=0f(); Physical(w):00015b8b=0f(); RAM(w):00015b8b=0f(); RealRAM(w):00015b8b=0f(); Paged(w):00015b8c=00( ); Physical(w):00015b8c=00( ); RAM(w):00015b8c=00( ); RealRAM(w):00015b8c=00( ); Paged(w):00015b8d=00( ); Physical(w):00015b8d=00( ); RAM(w):00015b8d=00( ); RealRAM(w):00015b8d=00( ); Paged(w):00015b86=b4(?); Physical(w):00015b86=b4(?); RAM(w):00015b86=b4(?); RealRAM(w):00015b86=b4(?); Paged(w):00015b87=0f(); Physical(w):00015b87=0f(); RAM(w):00015b87=0f(); RealRAM(w):00015b87=0f(); Paged(w):00015b88=00( ); Physical(w):00015b88=00( ); RAM(w):00015b88=00( ); RealRAM(w):00015b88=00( ); Paged(w):00015b89=00( ); Physical(w):00015b89=00( ); RAM(w):00015b89=00( ); RealRAM(w):00015b89=00( ); Paged(w):00015b82=00( ); Physical(w):00015b82=00( ); RAM(w):00015b82=00( ); RealRAM(w):00015b82=00( ); Paged(w):00015b83=10(); Physical(w):00015b83=10(); RAM(w):00015b83=10(); RealRAM(w):00015b83=10(); Paged(w):00015b84=00( ); Physical(w):00015b84=00( ); RAM(w):00015b84=00( ); RealRAM(w):00015b84=00( ); Paged(w):00015b85=00( ); Physical(w):00015b85=00( ); RAM(w):00015b85=00( ); RealRAM(w):00015b85=00( )
Registers:
EAX: 0000005b EBX: 00000ffa ECX: 00000417 EDX: 000026bc
ESP: 00000f52 EBP: 00000f70 ESI: 00000fb4 EDI: 00001000
CS: 0020 DS: 0098 ES: 0160 FS: 0000 GS: 0000 SS: 0018 TR: 0158 LDTR: 0168
EIP: 0000132f EFLAGS: 00003002
CR0: 00000001 CR1: 00000000 CR2: 00000000 CR3: 00000000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000127e003ff IDTR: 000000107df007ff
CS descriptor: 00009B101000FFFF
DS descriptor: 0000930127E00C6F
ES descriptor: 00009310A5F00BF9
FS descriptor: 000073000000FFFF
GS descriptor: 000073000000FFFF
SS descriptor: 000093014C50FFFF
TR descriptor: 00008310A5F00BF9
LDTR descriptor: 000082FCFF8007FF
FLAGSINFO: 00000000000000vr0n11oditsz0a0p1c

Well, eventually, it ends up at exactly the same IDT handler(except that EBP=F1C this time around) and SS0=F30 in this case?

And of course, said story keeps repeating infinitely, until the stack space runs out?

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

Reply 26 of 47, by superfury

User metadata
Rank l33t++
Rank
l33t++

So, the issue here is that Jazz Jackrabbit seems to execute an auto-initialize DMA DAC command without ever setting up the DMA transfer properly(it doesn't set the DMA Block Count in the SB2.0).

So each interrupt will be executed after only 0xAE(the set samplerate) 1MHz ticks, so after 174us.

Since the CPU is running at 3 MIPS, it's triggering each IRQ(from the SB2.0) each 58 instructions(13.51kHz sound, 1/3us for each instruction)!

Since it's only having 58 instructions to handle the interrupt, when having handled such an interrupt and it's busy returning(which executes STI in the kernel while it's busy returning), the instruction after the instruction following that(due to the STI delaying interrupts by 1 instruction) will receive the very next SB 2.0 interrupt due to the timer having ticked from 0xAF to 0! So that will get handled(with the SS0 still lowered, because the interrupt return to the originating task still didn't complete!), lowering the stack infinitely in such a way!!!

Unless there's some weird, undocumented, behaviour with regards to not setting up the Set DMA Block Size command on the Sound Blaster 2.0 when executing Auto-Init DMA?

Edit: Looking at https://sourceforge.net/p/bochs/code/HEAD/tre … v/sound/sb16.cc , I see something interesting there: it looks like that starting any DMA transfer on the Sound Blaster 16(at least), the DMA Block Size it automatically loaded with the last transferred block, even when executing a normal DMA transfer(not even just Auto-Init)!

Edit: Although that doesn't fix the issue with the Sound Blaster 2.0 cards! So Bochs should theoretically have the very same issue, as do Dosbox and any others I've looked at so far?
Edit: Just modified the DMA transfer to simply set a flag when a DMA transfer with Auto-Init finishes. When it's started up, the flag is cleared(signalling a new transfer). When the last sample is buffered to be rendered during Auto-Init, the flag is set(instead of triggering an IRQ immediately), then when the sample is actually rendered to the output(in this case, setting the output voltage of the rendering routine) it's triggering the IRQ instead.

So then, when triggering the IRQ, the timer of the sample has been actually cleared(ran out it's full time, instead of the earlier time that was setup). So 0xAE in this case meaning 0xAE clock ticks have passed before the IRQ is encountered(leaving 0xAF 1MHz ticks until receiving the next interrupt, so a lot more instructions can run that way(525 in this case, the CPU running at 3MIPS)).
Edit: The timer originally had 82 ticks left when triggering the very first interrupt in the old way. So 82us wasted.
Edit: After that, fixed a slight created bug with IRQs holding the DMA hostage pretty much by setting a bit during Auto-Init(preventing DMA transfers while the IRQ isn't fired), but the IRQ wasn't firing and clearing at the DMA transfer location yet, so it wasn't clearing said flag in time.

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

Reply 27 of 47, by superfury

User metadata
Rank l33t++
Rank
l33t++

OK. Although that seems to have fixed the IRQ crash problem(with recursive Sound Blaster IRQs), now the sound from the sound blaster sounds way too low?

The time constant is loaded reversed(256 minus timeconstant) into the counter. Each 1MHz clock cycle, said constant is checked. If it's 0(finished), the clock is discarded. Otherwise, it substracts 1 from it. If the result is 0(in other words: the timer has expired), it's reloaded(by default) with 256-timecontant and a sample is rendered.

Samples from DMA writes are done when said timer is reloaded during rendering a sample from the buffer. While this happens, DREQ is lowered(no transaction requested). Then, after such an event is handled with DMA having finished the transfer, an IRQ is raised(when rendering the sample from the buffer). When the sample buffer is empty(all decoded samples(more than 1 in ADPCM modes, just 1 in PCM mode), the DMA transfer is acnowledged and DMA is changed so that a new request can be made by the DMA controller(and the Sound Blaster will raise DREQ when it can again).
Although, after that, IRQ5 is needed to be acnowledged before DREQ is actually raised again. Otherwise, it'll stay lowered until the IRQ5(Sound Blaster IRQ) is acnowledged by reading the status port.

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

Reply 28 of 47, by superfury

User metadata
Rank l33t++
Rank
l33t++

OK. Somehow, the samples for the Sound Blaster 2.0 seems real slow, with even some latency issues(as in repeating buffers in the recordings once in a while(each few seconds))?

Edit: Also, the game starts very slowly in that case(Sound Blaster 2.0 with Sound Blaster driver enabled).

Perhaps that's due to lots of IRQ5 handling during the 1-byte DMA transfers to the Sound Blaster?

Edit: OK. I see it switching display modes and clearing the display for graphics mode, but effectively in slow motion?

That's probably mostly due to the 1-byte Sound Blaster auto-init DMA causing severe interrupt latency issues?

That of course includes stuff like hard drive access etc.

Edit: E.g. about 1 full second(of emulated time) to render the "When crisis strikes, the universe turns to one superhero..." text, painting it yellow in 1 second of emulated time?

Is that normal behaviour?

So it's running successfully without crashing now, but with severe lag because of inproperly programmed Sound Blaster DSP(missing DMA block size, which is effectively 0).

This makes me think: what happens on a real Sound Blaster 2.0 with Jazz Jackrabbit using the Sound Blaster option(instead of Sound Blaster Compatible), where it uses Auto-Init DMA of the DSP(command 1Ch)?

Edit: Increasing the CPU clock from 3 MIPS to 6 MIPS seems to solve that lag issue.
It's still 'better' than Dosbox through. Dosbox doesn't output any sound at all(probably doesn't throw interrupts or renders at all?).

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

Reply 29 of 47, by superfury

User metadata
Rank l33t++
Rank
l33t++

OK. At 6MIPS it changed again when starting it: this time an exception 0xD in kernel(segment 0x20) mode?

Edit: OK. I see a MOVSW instruction crashing on address DS:F6E to ES:36C6.

DS=18h, so a full 16-bit range, no problems there.

The other one(ES) is at offset 36C6h. It uses descriptor 5Bh. It's at 1095F0 and has a limit of FFFh, so that's illegal behaviour right there in the kernel?

Said issue happens at 0020:36D0.

One thing that tells me is that the dump of the error code by the software is indeed correct: a #GP(0) fault happens at said location in the kernel now.

This time, it's quite a big log: 6.98GB worth of logging now!
Edit: Said log: https://www.dropbox.com/s/ps7gojg9layz0od/deb … 18_1505.7z?dl=0

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

Reply 30 of 47, by superfury

User metadata
Rank l33t++
Rank
l33t++

OK. Looking upwards, I see the 0020:00000c7a being triggered normally, which is the normal #GP fault handler? ESP=FA8 when it starts. Seeing as ES=5B when it's gotten there, it was originally handling an interrupt when the issue occurs.

The base of the GP(0) fault was FB4, so that's a normal Sound Blaster IRQ5 it was handling in this case, or something comparable.

There's the usual substract, which returns 0xE, so it's actually a GP(0) fault or #GP(whatever) error code being pushed.

I see it pushing 0x10D to the stack, so it's indeed the ending of the Sound Blaster IRQ it's handling there.

OK, it gets to 0020:0000132f, so everything's good so far.

Then it pushes the EBP backup at DS(98):63Eh, which was 0xFB4 at that location.

So SP=F70 once again.
It pushes AX and stores the task for the TSS descriptor(adding 😎 in ES using that.

It sets the TSS.SS0 to FFFFh as usual.

Then stores FS and GS and clears them... Then restores AX.

Then saves BP at 63E as usual.

Then jumps to CA7(BP+34h), which also is correct.

It checks the set Interrupt flag on the stack at FAEh, which is correctly set.

And it sets the interrupt flag like usual. It then compares against B3, which matches(so far so good)...

It then jmps to 3e80h.

That code that starts there loads ES from BP+3C(location FACh on the stack), so it loads the CS register from the user mode into ES? That's kind of weird behaviour? It's opcode bytes "8E 46 3C".
It also loads DI from BP+3A, which is the IP value instead?
Then it loads BL from ES:DI+01, which is the next opcode byte. It finds 02h there.

It finds that it isn't 0 or 1, so jumps to 3e97h.
It checks against 3, finds it isn't so jumps to 3e9fh.
Then compares against 2(match), thus progresses to jump at 0020:00003ea4, jumping to the pointer 6 bytes after the opcode. So it reads 3F21h there.

It compares SS:FB2h against 5Bh. It finds that(it's the user's stack after all), so doesn't jump after that.
It compares SS:FB0h(the SP value of the user interrupt handler) against 1000h, where it finds F92h?

So since it isn't completing a fully empty stack interrupt handler(somehow), it loads the FLAGS from the user thread into AX(3202h), shifts BP up to it's parent frame(loading it from [BP+00]), thus becoming FB4h.

It then saves BP at DS(98h):[63E] at 0020:00003f39.

It reaches 0020:00003f3d, where it checks BP+3C against having it's lower 2 bits set. So it checks SS:FF0 against 3h.
Said segment is segment E7h, so it's in user mode.

So it filters the trap flag in AX and clears it on the stack, then adds it back in. That seems kind of redundant(except leaving TF flag in AX bit 😎?

It then jumps to 0020:00001386.

It finds out it wants to return to segment E7, so it prepares the TSS pointer using BX at 0020:00001390 and loads the TSS in ES again.

It loads BP into AX, adds 44h for the originating stack of the cause of the IRQ5(which is FF8h), then restores that into SS0.

It then changes the user's PL to PL3 and restores BP's save point to it's originating value at DS(98h):[63E], which FB4.

It checks against 32-bit, then starts popping the interupted registers from the stack.

It then executes the manual POPAD to reach 0020:000013c3.

It then skips the 10Dh parameter that was on the stack(or whatever during the original interrupt call) to reach 0020:000013C6 with ESP=FD8.

It then pops ES(fine so far), which is 19F. Checks against 32-bits(bit 4 of DS:401, which still is.

It then pops DS,FS,GS. Then it reaches 0020:000013f2.

It then adds 0xE to SP to reach the stack frame and jumps to 0020:000013FB.

It then executes an IRET, which returns to user mode! 😁

But somewhere after that, it crashes?
Edit: OK, then a 0020:00000c7a with SP being lowered by 2, so with an error code, this time from segment E7?

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

Reply 31 of 47, by superfury

User metadata
Rank l33t++
Rank
l33t++

OK. So the cause of the issue seems to be a fault where ESP=FECh, location 0020:00000c7a.
The last setup of the TSS.SP0 seems to be FF8h(according to the last write to ES:[0002]). So it's at the top of the used stack at that point(perhaps having pushed only 8 bytes there somehow?).

There's apparently a #GP(x) fault when executing segment E7h.
It starts out with ESP=FECh. So 12 bytes are on the stack. So the basic interrupt frame with error code it seems?

The #GP(x) starts normally, pushing BP.

Details

FF8: SS0 of the kernel
FF6: IRET SS
FF4: IRET SP
FF2: IRET EFLAGS
FF0: IRET CS
FEE: IRET IP
FEC: error code <- SP

Nothing weird so far.

The descriptors are as follows:

Details

CS: 0020 DS: 00ef ES: 019f FS: 0000 GS: 0000 SS: 0018 TR: 0158 LDTR: 0168
EIP: 00000c7a EFLAGS: 00003002
CS descriptor: 00009B101000FFFF
DS descriptor: 0000F31189C0C5CF
ES descriptor: 0000F3FCCBC0111F
FS descriptor: 0000730005C0FFFF
GS descriptor: 000073002700FFFF
SS descriptor: 000093014C50FFFF
TR descriptor: 00008310A5F00BF9
LDTR descriptor: 000082FCFF8007FF

That might provide a clue as to what's going wrong? But perhaps not.

It starts out normally, setting up a stack frame.

Details

FF8: SS0 of the kernel
FF6: IRET SS
FF4: IRET SP
FF2: IRET EFLAGS
FF0: IRET CS
FEE: IRET IP
FEC: error code
FEA: BP=36DCh<- SP <- BP

It then pushes ES and AX.

Details

FF8: SS0 of the kernel
FF6: IRET SS
FF4: IRET SP
FF2: IRET EFLAGS
FF0: IRET CS
FEE: IRET IP
FEC: error code
FEA: BP=36DCh <- BP
FE8: ES=19Fh
FE6: AX=0 <- SP

It then checks CS for user mode? CS is B3 in this case.

Details

FF8: SS0 of the kernel
FF6: IRET SS
FF4: IRET SP
FF2: IRET EFLAGS
FF0: IRET CS=B3
FEE: IRET IP
FEC: error code
FEA: BP=36DCh <- BP
FE8: ES=19Fh
FE6: AX=0 <- SP

It doesn't jump because it's user mode(as it's supposed to).

It then sets up the ES to the TSS for accessing the TSS.

It then load AX from the SS0 of the TSS and compares it to FFFFh(which it isn't).
It then calculates the difference(0xE), which isn't 0xC, so it falls through and pops AX and ES to restore them.

Details

FF8: SS0 of the kernel
FF6: IRET SS
FF4: IRET SP
FF2: IRET EFLAGS
FF0: IRET CS=B3
FEE: IRET IP
FEC: error code
FEA: BP=36DCh <- BP <- SP

It then pops BP to restore that as well. BP=36DCh now.

Details

FF8: SS0 of the kernel
FF6: IRET SS
FF4: IRET SP
FF2: IRET EFLAGS
FF0: IRET CS=B3
FEE: IRET IP
FEC: error code <- SP
FEA: BP=36DCh

Then it calls pushes 10Dh and calls 131Ch as usual to handle the apparent return from interrupt?

Details

FF8: SS0 of the kernel
FF6: IRET SS
FF4: IRET SP
FF2: IRET EFLAGS
FF0: IRET CS=B3
FEE: IRET IP
FEC: error code
FEA: 10Dh
FE8: ip=CA7h<- SP

It allocates the stack frame to use.

Details

FF8: SS0 of the kernel
FF6: IRET SS
FF4: IRET SP
FF2: IRET EFLAGS
FF0: IRET CS=B3
FEE: IRET IP
FEC: error code
FEA: 10Dh
FE8: ip=CA7h
FE6: ???
FE4: ???
FE2: ???
FE0: ???
FDE: ???
FDC: ??? <- SP

It then pushes DS and 98h and pops it in DS.

Details

FF8: SS0 of the kernel
FF6: IRET SS
FF4: IRET SP
FF2: IRET EFLAGS
FF0: IRET CS=B3
FEE: IRET IP
FEC: error code
FEA: 10Dh
FE8: ip=CA7h
FE6: ???
FE4: ???
FE2: ???
FE0: ???
FDE: ???
FDC: ???
FDA: DS=EFh <- SP
FD8: 98h

It then pushes ES and 0h.

Details

FF8: SS0 of the kernel
FF6: IRET SS
FF4: IRET SP
FF2: IRET EFLAGS
FF0: IRET CS=B3
FEE: IRET IP
FEC: error code
FEA: 10Dh
FE8: ip=CA7h
FE6: ???
FE4: ???
FE2: ???
FE0: ???
FDE: ???
FDC: ???
FDA: DS=EFh
FD8: ES=19Fh
FD6: 0 <- SP

It then checks for 32-bit, which it still is as usually, so at 0020:0000132f executes a PUSHAD.

Details

FF8: SS0 of the kernel
FF6: IRET SS
FF4: IRET SP
FF2: IRET EFLAGS
FF0: IRET CS=B3
FEE: IRET IP
FEC: error code
FEA: 10Dh
FE8: ip=CA7h
FE6: ???
FE4: ???
FE2: ???
FE0: ???
FDE: ???
FDC: ???
FDA: DS=EFh
FD8: ES=19Fh
FD6: 0
FD2: EAX=0
FCE: ECX=19Fh
FCA: EDX=FFFFh
FC6: EBX=2860B3Ah
FC2: ESP=FD6h
FBE: EBP=36DCh
FBA: ESI=2
FB6: EDI=390Bh <- SP

It then pushes DS:[63E]'s copy of the old BP and sets BP to that for a new frame.

Details

FF8: SS0 of the kernel
FF6: IRET SS
FF4: IRET SP
FF2: IRET EFLAGS
FF0: IRET CS=B3
FEE: IRET IP
FEC: error code
FEA: 10Dh
FE8: ip=CA7h
FE6: ???
FE4: ???
FE2: ???
FE0: ???
FDE: ???
FDC: ???
FDA: DS=EFh
FD8: ES=19Fh
FD6: 0
FD2: EAX=0
FCE: ECX=19Fh
FCA: EDX=FFFFh
FC6: EBX=2860B3Ah
FC2: ESP=FD6h
FBE: EBP=36DCh
FBA: ESI=2
FB6: EDI=390Bh
FB4: DS:[FB6]=FB4h <- SP <- BP

It then pushes AX.

Details

FF8: SS0 of the kernel
FF6: IRET SS
FF4: IRET SP
FF2: IRET EFLAGS
FF0: IRET CS=B3
FEE: IRET IP
FEC: error code
FEA: 10Dh
FE8: ip=CA7h
FE6: ???
FE4: ???
FE2: ???
FE0: ???
FDE: ???
FDC: ???
FDA: DS=EFh
FD8: ES=19Fh
FD6: 0
FD2: EAX=0
FCE: ECX=19Fh
FCA: EDX=FFFFh
FC6: EBX=2860B3Ah
FC2: ESP=FD6h
FBE: EBP=36DCh
FBA: ESI=2
FB6: EDI=390Bh
FB4: DS:[FB6]=FB4h <- BP
FB2: AX=0 <- SP

It tests DS:[403] for bit 0 set, which it is, so it doesn't jump.

It then does the AX to ES for the TSS thing again.

It sets TSS.SS0 to FFFFh, checks for 32-bit(should be obvious by now), then continues on.

It then writes FS,GS to BP+28,BP+2A and clears them.

Details

FF8: SS0 of the kernel
FF6: IRET SS
FF4: IRET SP
FF2: IRET EFLAGS
FF0: IRET CS=B3
FEE: IRET IP
FEC: error code
FEA: 10Dh
FE8: ip=CA7h
FE6: ???
FE4: ???
FE2: ???
FE0: ???
FDE: GS=0
FDC: FS=0
FDA: DS=EFh
FD8: ES=19Fh
FD6: 0
FD2: EAX=0
FCE: ECX=19Fh
FCA: EDX=FFFFh
FC6: EBX=2860B3Ah
FC2: ESP=FD6h
FBE: EBP=36DCh
FBA: ESI=2
FB6: EDI=390Bh
FB4: DS:[FB6]=FB4h <- BP
FB2: AX=0 <- SP

It then pops AX and moves BP(FB4) to DS:[63E].

Details

FF8: SS0 of the kernel
FF6: IRET SS
FF4: IRET SP
FF2: IRET EFLAGS
FF0: IRET CS=B3
FEE: IRET IP
FEC: error code
FEA: 10Dh
FE8: ip=CA7h
FE6: ???
FE4: ???
FE2: ???
FE0: ???
FDE: GS=0
FDC: FS=0
FDA: DS=EFh
FD8: ES=19Fh
FD6: 0
FD2: EAX=0
FCE: ECX=19Fh
FCA: EDX=FFFFh
FC6: EBX=2860B3Ah
FC2: ESP=FD6h
FBE: EBP=36DCh
FBA: ESI=2
FB6: EDI=390Bh
FB4: DS:[FB6]=FB4h <- BP <- SP
FB2: AX=0

It then jumps to the caller(CA7h).

That tests BP+3E(FF2h=IRET EFLAGS)'s bit 9, thus the originating tasks interrupt flag.

Details

FF8: SS0 of the kernel
FF6: IRET SS
FF4: IRET SP
FF2: IRET EFLAGS=3202h
FF0: IRET CS=B3
FEE: IRET IP
FEC: error code
FEA: 10Dh
FE8: ip=CA7h
FE6: ???
FE4: ???
FE2: ???
FE0: ???
FDE: GS=0
FDC: FS=0
FDA: DS=EFh
FD8: ES=19Fh
FD6: 0
FD2: EAX=0
FCE: ECX=19Fh
FCA: EDX=FFFFh
FC6: EBX=2860B3Ah
FC2: ESP=FD6h
FBE: EBP=36DCh
FBA: ESI=2
FB6: EDI=390Bh
FB4: DS:[FB6]=FB4h <- BP <- SP
FB2: AX=0

It doesn't take the jump to CAFh, because it isn't cleared.
It then sets the interrupt flag using STI.

It then checks BP+3C against B3, which matches. So it ends up at 0020:00000cb6 jumping to 0020:00003e80.

Then it moves BP+3C(FF0=B3) to ES. So ES is now pointing to the interrupted code segment(segment B3).

It then moves BP+3A(FEE=Ch) to DI. So DI is now IP of the interrupted task(so the interrupted task was at 00B3:000C)!

It then moves the next opcode(ES:[DI+01]) to BL. That's 02h.

It finds it's 02h, so it reaches 0020:00003ea4.

That jumps to the 16-bit address at B3:C+6, so at 00B3:0012. So 0020:00003DD5.

That moves [BP+42] to BX, so that's FF6=IRET SS=5Bh.

Then it moves that into DS. So DS contains the user stack's SS, with a limit of FFFh.

Then it moves [BP+40] into SI, so that's FF4=IRET SP=FBCh.

Details

FF8: SS0 of the kernel
FF6: IRET SS=5Bh
FF4: IRET SP=FBCh
FF2: IRET EFLAGS=3202h
FF0: IRET CS=B3
FEE: IRET IP
FEC: error code
FEA: 10Dh
FE8: ip=CA7h
FE6: ???
FE4: ???
FE2: ???
FE0: ???
FDE: GS=0
FDC: FS=0
FDA: DS=EFh
FD8: ES=19Fh
FD6: 0
FD2: EAX=0
FCE: ECX=19Fh
FCA: EDX=FFFFh
FC6: EBX=2860B3Ah
FC2: ESP=FD6h
FBE: EBP=36DCh
FBA: ESI=2
FB6: EDI=390Bh
FB4: DS:[FB6]=FB4h <- BP <- SP
FB2: AX=0

It clears the direction flag, so addresses are increasing.
Then it executes LODSW, to copy user stack 5B's FBCh=46Ch to [BP+38], which is FEC, the error code field using AX.

It then loads another one(from FBEh=951Bh) to [BP+3A], which is FEE, the IRET IP field.

It then loads another one(from FC0h=E7h) to [BP+3C], which is FF0, the IRET CS field.

It then moves that field into CX at 0020:00003dea.

Details

FF8: SS0 of the kernel
FF6: IRET SS=5Bh
FF4: IRET SP=FBCh
FF2: IRET EFLAGS=3202h
FF0: IRET CS=E7h
FEE: IRET IP=951Bh
FEC: 46Ch
FEA: 10Dh
FE8: ip=CA7h
FE6: ???
FE4: ???
FE2: ???
FE0: ???
FDE: GS=0
FDC: FS=0
FDA: DS=EFh
FD8: ES=19Fh
FD6: 0
FD2: EAX=0
FCE: ECX=19Fh
FCA: EDX=FFFFh
FC6: EBX=2860B3Ah
FC2: ESP=FD6h
FBE: EBP=36DCh
FBA: ESI=2
FB6: EDI=390Bh
FB4: DS:[FB6]=FB4h <- BP <- SP
FB2: AX=0

It then loads another one(FC2=3246h) to [BP+3E], which is FF2.

Details

FF8: SS0 of the kernel
FF6: IRET SS=5Bh
FF4: IRET SP=FBCh
FF2: IRET EFLAGS=3246h
FF0: IRET CS=E7h
FEE: IRET IP=951Bh
FEC: 46Ch
FEA: 10Dh
FE8: ip=CA7h
FE6: ???
FE4: ???
FE2: ???
FE0: ???
FDE: GS=0
FDC: FS=0
FDA: DS=EFh
FD8: ES=19Fh
FD6: 0
FD2: EAX=0
FCE: ECX=19Fh
FCA: EDX=FFFFh
FC6: EBX=2860B3Ah
FC2: ESP=FD6h
FBE: EBP=36DCh
FBA: ESI=2
FB6: EDI=390Bh
FB4: DS:[FB6]=FB4h <- BP <- SP
FB2: AX=0

Then another one from FC4(=36CCh) to [BP+40], which is FF4.

Details

FF8: SS0 of the kernel
FF6: IRET SS=5Bh
FF4: IRET SP=36CCh
FF2: IRET EFLAGS=3246h
FF0: IRET CS=E7h
FEE: IRET IP=951Bh
FEC: 46Ch
FEA: 10Dh
FE8: ip=CA7h
FE6: ???
FE4: ???
FE2: ???
FE0: ???
FDE: GS=0
FDC: FS=0
FDA: DS=EFh
FD8: ES=19Fh
FD6: 0
FD2: EAX=0
FCE: ECX=19Fh
FCA: EDX=FFFFh
FC6: EBX=2860B3Ah
FC2: ESP=FD6h
FBE: EBP=36DCh
FBA: ESI=2
FB6: EDI=390Bh
FB4: DS:[FB6]=FB4h <- BP <- SP
FB2: AX=0

Then, an interrupt occurs! ESP=FAE there, so 6 bytes are pushed due to it being a kernel level interrupt to 0020:00000c7a.

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

Reply 32 of 47, by superfury

User metadata
Rank l33t++
Rank
l33t++

OK. The interrupt handler sees that it's from segment 0x20. So it detects that it's a kernel interrupt and starts handling it like that.

I see it loading a risky pointer, to the user-mode stack of the interrupted handler, with the IP? That's from FF4h and FF6h on the kernel's stack.

That's pointing to 5B:36CC, which is an illegal pointer(which was stored as SS:SP on the original interrupt handler's stack(from segment E7h))! It then reaches 0020:0000365e, which jumps to 0020:0000366d.

So, it's trying to copy from F6E on the stack handler, it's interrupt data to 36C6h on the 5Bh stack(which has a limit of FFFh), thus faulting where the kernel's trying to setup the IRQ5 handler's stack frame on the user's stack!

So the main issue here is that the E7's stack(the 5Bh stack) pointer is corrupted!

So although the kernel is crashing, it's the segment E7 code that has somehow set up a invalid stack pointer to use?
Just been thinking: could it be that interrupts should have been inhabited while the issue occurs?

Edit: So perhaps, an IRQ occurred while it was setting up a SS:SP pointer load?

UniPCemu should (theoretically) prevent interrupts after loading SS, but could it be that this doesn't always happen?

Segment E7 log: https://www.dropbox.com/s/9m0jbhslgeairl0/deb … gmentE7.7z?dl=0

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

Reply 33 of 47, by superfury

User metadata
Rank l33t++
Rank
l33t++

OK. Just found something weird while inspecting the SS and SP changes:

MMU: Reading from real(r): 000ab480=e4 (?)
Reading from RAM(r): 0010b480=e4 (?)
Reading from physical memory(r): 0010b480=e4 (?)
Reading from paged memory(r): 0010b480=e4 (?)
MMU: Reading from real(r): 000ab481=06 ()
Reading from RAM(r): 0010b481=06 ()
Reading from physical memory(r): 0010b481=06 ()
Reading from paged memory(r): 0010b481=06 ()
MMU: Reading from real(r): 000ab482=e4 (?)
Reading from RAM(r): 0010b482=e4 (?)
Reading from physical memory(r): 0010b482=e4 (?)
Reading from paged memory(r): 0010b482=e4 (?)
MMU: Reading from real(r): 000ab483=06 ()
Reading from RAM(r): 0010b483=06 ()
Reading from physical memory(r): 0010b483=06 ()
Reading from paged memory(r): 0010b483=06 ()
MMU: Reading from real(r): 000ab484=54 (T)
Reading from RAM(r): 0010b484=54 (T)
Reading from physical memory(r): 0010b484=54 (T)
Reading from paged memory(r): 0010b484=54 (T)
MMU: Reading from real(r): 000ab485=72 (r)
Reading from RAM(r): 0010b485=72 (r)
Reading from physical memory(r): 0010b485=72 (r)
Reading from paged memory(r): 0010b485=72 (r)
MMU: Reading from real(r): 000ab486=00 ( )
Reading from RAM(r): 0010b486=00 ( )
Reading from physical memory(r): 0010b486=00 ( )
Reading from paged memory(r): 0010b486=00 ( )
MMU: Reading from real(r): 000ab487=54 (T)
Reading from RAM(r): 0010b487=54 (T)
Reading from physical memory(r): 0010b487=54 (T)
Reading from paged memory(r): 0010b487=54 (T)
00:11:18:91.04240: #NP fault(00000294)!
MMU: Reading from real(r): 000a7e48=f0 (?)
Reading from RAM(r): 00107e48=f0 (?)
Reading from physical memory(r): 00107e48=f0 (?)
Reading from paged memory(r): 00107e48=f0 (?)
MMU: Reading from real(r): 000a7e49=0b ()
Reading from RAM(r): 00107e49=0b ()
Reading from physical memory(r): 00107e49=0b ()
Reading from paged memory(r): 00107e49=0b ()
MMU: Reading from real(r): 000a7e4a=20 ( )
Reading from RAM(r): 00107e4a=20 ( )
Reading from physical memory(r): 00107e4a=20 ( )
Reading from paged memory(r): 00107e4a=20 ( )
MMU: Reading from real(r): 000a7e4b=00 ( )
Reading from RAM(r): 00107e4b=00 ( )
Reading from physical memory(r): 00107e4b=00 ( )
Reading from paged memory(r): 00107e4b=00 ( )
MMU: Reading from real(r): 000a7e4c=00 ( )
Reading from RAM(r): 00107e4c=00 ( )
Reading from physical memory(r): 00107e4c=00 ( )
Reading from paged memory(r): 00107e4c=00 ( )
MMU: Reading from real(r): 000a7e4d=e6 (?)
Reading from RAM(r): 00107e4d=e6 (?)
Reading from physical memory(r): 00107e4d=e6 (?)
Reading from paged memory(r): 00107e4d=e6 (?)
MMU: Reading from real(r): 000a7e4e=00 ( )
Reading from RAM(r): 00107e4e=00 ( )
Reading from physical memory(r): 00107e4e=00 ( )
Show last 108 lines
Reading from paged memory(r): 00107e4e=00 ( )
MMU: Reading from real(r): 000a7e4f=00 ( )
Reading from RAM(r): 00107e4f=00 ( )
Reading from physical memory(r): 00107e4f=00 ( )
Reading from paged memory(r): 00107e4f=00 ( )
MMU: Reading from real(r): 00012800=ff (?)
Reading from RAM(r): 00012800=ff (?)
Reading from physical memory(r): 00012800=ff (?)
Reading from paged memory(r): 00012800=ff (?)
MMU: Reading from real(r): 00012801=ff (?)
Reading from RAM(r): 00012801=ff (?)
Reading from physical memory(r): 00012801=ff (?)
Reading from paged memory(r): 00012801=ff (?)
MMU: Reading from real(r): 00012802=00 ( )
Reading from RAM(r): 00012802=00 ( )
Reading from physical memory(r): 00012802=00 ( )
Reading from paged memory(r): 00012802=00 ( )
MMU: Reading from real(r): 00012803=10 ()
Reading from RAM(r): 00012803=10 ()
Reading from physical memory(r): 00012803=10 ()
Reading from paged memory(r): 00012803=10 ()
MMU: Reading from real(r): 00012804=10 ()
Reading from RAM(r): 00012804=10 ()
Reading from physical memory(r): 00012804=10 ()
Reading from paged memory(r): 00012804=10 ()
MMU: Reading from real(r): 00012805=9b (?)
Reading from RAM(r): 00012805=9b (?)
Reading from physical memory(r): 00012805=9b (?)
Reading from paged memory(r): 00012805=9b (?)
MMU: Reading from real(r): 00012806=00 ( )
Reading from RAM(r): 00012806=00 ( )
Reading from physical memory(r): 00012806=00 ( )
Reading from paged memory(r): 00012806=00 ( )
MMU: Reading from real(r): 00012807=00 ( )
Reading from RAM(r): 00012807=00 ( )
Reading from physical memory(r): 00012807=00 ( )
Reading from paged memory(r): 00012807=00 ( )
MMU: Reading from real(r): 000127f8=ff (?)
Reading from RAM(r): 000127f8=ff (?)
Reading from physical memory(r): 000127f8=ff (?)
Reading from paged memory(r): 000127f8=ff (?)
MMU: Reading from real(r): 000127f9=ff (?)
Reading from RAM(r): 000127f9=ff (?)
Reading from physical memory(r): 000127f9=ff (?)
Reading from paged memory(r): 000127f9=ff (?)
MMU: Reading from real(r): 000127fa=50 (P)
Reading from RAM(r): 000127fa=50 (P)
Reading from physical memory(r): 000127fa=50 (P)
Reading from paged memory(r): 000127fa=50 (P)
MMU: Reading from real(r): 000127fb=4c (L)
Reading from RAM(r): 000127fb=4c (L)
Reading from physical memory(r): 000127fb=4c (L)
Reading from paged memory(r): 000127fb=4c (L)
MMU: Reading from real(r): 000127fc=01 ()
Reading from RAM(r): 000127fc=01 ()
Reading from physical memory(r): 000127fc=01 ()
Reading from paged memory(r): 000127fc=01 ()
MMU: Reading from real(r): 000127fd=93 (?)
Reading from RAM(r): 000127fd=93 (?)
Reading from physical memory(r): 000127fd=93 (?)
Reading from paged memory(r): 000127fd=93 (?)
MMU: Reading from real(r): 000127fe=00 ( )
Reading from RAM(r): 000127fe=00 ( )
Reading from physical memory(r): 000127fe=00 ( )
Reading from paged memory(r): 000127fe=00 ( )
MMU: Reading from real(r): 000127ff=00 ( )
Reading from RAM(r): 000127ff=00 ( )
Reading from physical memory(r): 000127ff=00 ( )
Reading from paged memory(r): 000127ff=00 ( )
00e7:000036cc C4 76 04 les si,word ss:[bp+04] RealRAM(p):000afcc9=57(W); RAM(p):0010fcc9=57(W); Physical(p):0010fcc9=57(W); Paged(p):0010fcc9=57(W); Normal(p):000036d9=57(W); RealRAM(p):000afcca=e8(?); RAM(p):0010fcca=e8(?); Physical(p):0010fcca=e8(?); Paged(p):0010fcca=e8(?); Normal(p):000036da=e8(?); RealRAM(p):000afccb=83(?); RAM(p):0010fccb=83(?); Physical(p):0010fccb=83(?); Paged(p):0010fccb=83(?); Normal(p):000036db=83(?); RealRAM(r):000da2a0=00( ); RAM(r):0013a2a0=00( ); Physical(r):0013a2a0=00( ); Paged(r):0013a2a0=00( ); RealRAM(r):000da2a1=00( ); RAM(r):0013a2a1=00( ); Physical(r):0013a2a1=00( ); Paged(r):0013a2a1=00( ); RealRAM(r):000da2a2=97(?); RAM(r):0013a2a2=97(?); Physical(r):0013a2a2=97(?); Paged(r):0013a2a2=97(?); RealRAM(r):000da2a3=02(); RAM(r):0013a2a3=02(); Physical(r):0013a2a3=02(); Paged(r):0013a2a3=02(); RealRAM(r):000aa5f2=f8(?); RAM(r):0010a5f2=f8(?); Physical(r):0010a5f2=f8(?); Paged(r):0010a5f2=f8(?); Normal(r):00000002=f8(?); RealRAM(r):000aa5f3=0f(); RAM(r):0010a5f3=0f(); Physical(r):0010a5f3=0f(); Paged(r):0010a5f3=0f(); Normal(r):00000003=0f(); RealRAM(r):000aa5f4=18(); RAM(r):0010a5f4=18(); Physical(r):0010a5f4=18(); Paged(r):0010a5f4=18(); Normal(r):00000004=18(); RealRAM(r):000aa5f5=00( ); RAM(r):0010a5f5=00( ); Physical(r):0010a5f5=00( ); Paged(r):0010a5f5=00( ); Normal(r):00000005=00( ); Normal(w):00000ff6=8f(?); Paged(w):00015c46=8f(?); Physical(w):00015c46=8f(?); RAM(w):00015c46=8f(?); RealRAM(w):00015c46=8f(?); Normal(w):00000ff7=02(); Paged(w):00015c47=02(); Physical(w):00015c47=02(); RAM(w):00015c47=02(); RealRAM(w):00015c47=02(); Normal(w):00000ff4=d8(?); Paged(w):00015c44=d8(?); Physical(w):00015c44=d8(?); RAM(w):00015c44=d8(?); RealRAM(w):00015c44=d8(?); Normal(w):00000ff5=3f(?); Paged(w):00015c45=3f(?); Physical(w):00015c45=3f(?); RAM(w):00015c45=3f(?); RealRAM(w):00015c45=3f(?); Normal(w):00000ff2=56(V); Paged(w):00015c42=56(V); Physical(w):00015c42=56(V); RAM(w):00015c42=56(V); RealRAM(w):00015c42=56(V); Normal(w):00000ff3=32(2); Paged(w):00015c43=32(2); Physical(w):00015c43=32(2); RAM(w):00015c43=32(2); RealRAM(w):00015c43=32(2); Normal(w):00000ff0=e7(?); Paged(w):00015c40=e7(?); Physical(w):00015c40=e7(?); RAM(w):00015c40=e7(?); RealRAM(w):00015c40=e7(?); Normal(w):00000ff1=00( ); Paged(w):00015c41=00( ); Physical(w):00015c41=00( ); RAM(w):00015c41=00( ); RealRAM(w):00015c41=00( ); Normal(w):00000fee=cc(?); Paged(w):00015c3e=cc(?); Physical(w):00015c3e=cc(?); RAM(w):00015c3e=cc(?); RealRAM(w):00015c3e=cc(?); Normal(w):00000fef=36(6); Paged(w):00015c3f=36(6); Physical(w):00015c3f=36(6); RAM(w):00015c3f=36(6); RealRAM(w):00015c3f=36(6); Normal(w):00000fec=94(?); Paged(w):00015c3c=94(?); Physical(w):00015c3c=94(?); RAM(w):00015c3c=94(?); RealRAM(w):00015c3c=94(?); Normal(w):00000fed=02(); Paged(w):00015c3d=02(); Physical(w):00015c3d=02(); RAM(w):00015c3d=02(); RealRAM(w):00015c3d=02()
Registers:
EAX: 00009257 EBX: 00000000 ECX: 00000000 EDX: 00000023
ESP: 00003fd8 EBP: 00003fdc ESI: 000038ac EDI: 00000000
CS: 00e7 DS: 00ef ES: 028f FS: 0000 GS: 0000 SS: 028f TR: 0158 LDTR: 0168
EIP: 000036cc EFLAGS: 00003256
CR0: 00000001 CR1: 00000000 CR2: 00000000 CR3: 00000000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000127e003ff IDTR: 000000107df007ff
CS descriptor: 0000FB10C5F0C3DF
DS descriptor: 0000F31189C0C5CF
ES descriptor: 0000F31362C03FFF
FS descriptor: 000073000010FFFF
GS descriptor: 00007302E4D0FFFF
SS descriptor: 0000F31362C03FFF
TR descriptor: 00008310A5F00BF9
LDTR descriptor: 00008210B1F003FF
FLAGSINFO: 00000000000000vr0n11odItsZ0A0P1c
00e7:00009576 50 push ax RealRAM(p):000b5b66=50(P); RAM(p):00115b66=50(P); Physical(p):00115b66=50(P); Paged(p):00115b66=50(P); Normal(p):00009576=50(P); RealRAM(p):000b5b67=51(Q); RAM(p):00115b67=51(Q); Physical(p):00115b67=51(Q); Paged(p):00115b67=51(Q); Normal(p):00009577=51(Q); RealRAM(p):000b5b68=52(R); RAM(p):00115b68=52(R); Physical(p):00115b68=52(R); Paged(p):00115b68=52(R); Normal(p):00009578=52(R); RealRAM(p):000b5b69=53(S); RAM(p):00115b69=53(S); Physical(p):00115b69=53(S); Paged(p):00115b69=53(S); Normal(p):00009579=53(S); RealRAM(p):000b5b6a=54(T); RAM(p):00115b6a=54(T); Physical(p):00115b6a=54(T); Paged(p):00115b6a=54(T); Normal(p):0000957a=54(T); RealRAM(p):000b5b6b=55(U); RAM(p):00115b6b=55(U); Physical(p):00115b6b=55(U); Paged(p):00115b6b=55(U); Normal(p):0000957b=55(U); RealRAM(p):000b5b6c=56(V); RAM(p):00115b6c=56(V); Physical(p):00115b6c=56(V); Paged(p):00115b6c=56(V); Normal(p):0000957c=56(V); RealRAM(p):000b5b6d=57(W); RAM(p):00115b6d=57(W); Physical(p):00115b6d=57(W); Paged(p):00115b6d=57(W); Normal(p):0000957d=57(W); RealRAM(p):000b5b6e=1e(); RAM(p):00115b6e=1e(); Physical(p):00115b6e=1e(); Paged(p):00115b6e=1e(); Normal(p):0000957e=1e(); RealRAM(p):000b5b6f=06(); RAM(p):00115b6f=06(); Physical(p):00115b6f=06(); Paged(p):00115b6f=06(); Normal(p):0000957f=06(); RealRAM(p):000b5b70=8b(?); RAM(p):00115b70=8b(?); Physical(p):00115b70=8b(?); Paged(p):00115b70=8b(?); Normal(p):00009580=8b(?); RealRAM(p):000b5b71=ec(?); RAM(p):00115b71=ec(?); Physical(p):00115b71=ec(?); Paged(p):00115b71=ec(?); Normal(p):00009581=ec(?); RealRAM(p):000b5b72=83(?); RAM(p):00115b72=83(?); Physical(p):00115b72=83(?); Paged(p):00115b72=83(?); Normal(p):00009582=83(?); RealRAM(p):000b5b73=ec(?); RAM(p):00115b73=ec(?); Physical(p):00115b73=ec(?); Paged(p):00115b73=ec(?); Normal(p):00009583=ec(?); RealRAM(p):000b5b74=06(); RAM(p):00115b74=06(); Physical(p):00115b74=06(); Paged(p):00115b74=06(); Normal(p):00009584=06(); RealRAM(p):000b5b75=8d(?); RAM(p):00115b75=8d(?); Physical(p):00115b75=8d(?); Paged(p):00115b75=8d(?); Normal(p):00009585=8d(?); Paged(w):0010a5a6=57(W); Physical(w):0010a5a6=57(W); RAM(w):0010a5a6=57(W); RealRAM(w):000aa5a6=57(W); Paged(w):0010a5a7=92(?); Physical(w):0010a5a7=92(?); RAM(w):0010a5a7=92(?); RealRAM(w):000aa5a7=92(?)
Registers:
EAX: 00009257 EBX: 00000000 ECX: 00000000 EDX: 00000023
ESP: 00000fb8 EBP: 00003fdc ESI: 000038ac EDI: 00000000
CS: 00e7 DS: 00ef ES: 028f FS: 0000 GS: 0000 SS: 005b TR: 0158 LDTR: 0168
EIP: 00009576 EFLAGS: 00003256
CR0: 00000001 CR1: 00000000 CR2: 00000000 CR3: 00000000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000127e003ff IDTR: 000000107df007ff
CS descriptor: 0000FB10C5F0C3DF
DS descriptor: 0000F31189C0C5CF
ES descriptor: 0000F31362C03FFF
FS descriptor: 000073000010FFFF
GS descriptor: 00007302E4D0FFFF
SS descriptor: 0000F31095F00FFF
TR descriptor: 00008310A5F00BF9
LDTR descriptor: 00008210B1F003FF
FLAGSINFO: 00000000000000vr0n11odItsZ0A0P1c

That's CS and IP completely changing, but no interrupt triggering or is there? Is that a #GP or #NP exception? Hmmm...
Edit: Yup, a #NP fault for address 294h!
Why would segment E7 be handling that?

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

Reply 34 of 47, by superfury

User metadata
Rank l33t++
Rank
l33t++

OK. Weird. Having the logging adjusted to add previous CS:EIP information(only when the previous opcode was using a different code segment index/table/rpl value), suddenly the game starts like normally on the Sound Blaster 2.0?

It's running at extremely slow speeds in that case...

Hmmm... Each time it runs at extremely(0% realtime) slow speeds it runs, but at ~20% it crashes...
The only thing that might have any influence on that timing is the RTC interrupt, assuming the normal setting is used(in which it's running at the specified clock cycle(e.g. up to 64KHz), but the RTC time is at real-time instead)...

So only when the RTC ticks time way faster(multiple seconds/minutes for each RTC clock cycle) than the CPU(usually it's reversed) the Sound Blaster 2.0 option runs without issues?
Edit: Putting the RTC in cycle-accurate mode makes it run properly it seems?
So perhaps Jazz Jackrabbit can't handle the RTC's fast refresh that's out of sync with the rest of the timings?
Edit: So far 2 tries on the RTC in cycle-accurate mode. Both seem to run the game on the Sound Blaster 2.0 emulation without issues?
Of course, 6MIPS is still needed to run the game at a somewhat decent speed at all?
So the weird interrupt latency issue is still there somehow?
Edit: Although it's fixed somehow in this way, the RTC interrupts doesn't seem to be enabled?
Although clearing the time to 1-1-1970 00:00:00 seems to make Jazz Jackrabbit(perhaps due to the MS-DOS time) show the christmas menu 🤣

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

Reply 35 of 47, by superfury

User metadata
Rank l33t++
Rank
l33t++

OK. It after restarting the game still crashes with the fatal exception 0xD.

So the issue isn't time-related (or at least not the CMOS RTC-related one)?

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

Reply 36 of 47, by superfury

User metadata
Rank l33t++
Rank
l33t++

So as far as I can see, the main issue that's causing the crash is that a normal kernel level interrupt(because of an IRQ probably, not an exception) occurs(probably interrupt 0xD) while SS:SP isn't canonical(SS=5Bh, SP is out of the descriptor's range, which is 36CCh). That happens at E7:3246 apparently(at least in the example).

And because that isn't canonical, when returning from the interrupt, the kernel fault handler(which is reversing it's actions and moving data to the destination stack for compatibility) tries to push data on that invalid stack, thus crashing itself.

Aren't non-canonical stack pointers usually prevented by the hardware mechanisms itself? Because popping a stack segment selector to SS causes the next instruction to inhibit interrupts?
And of course erroring out loads of SS shouldn't cause this as well, seeing as they don't change SS, thus keeping the stack pointer canonical?

Anyone? Is there perhaps some instruction that I'm missing that's requiring interrupt inhibition?
UniPCemu currently does that on:
- Opcode 8F POP SS.
- Opcode 17 POP SS.
- Opcode 8E MOV SS,r/m16
- Opcode FB STI (when affecting the actual interrupt flag and not the Virtual Interrupt Flag(VIF) or faulting)

Are there any other opcodes where interrupts should be inhibited?

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

Reply 37 of 47, by superfury

User metadata
Rank l33t++
Rank
l33t++

Managed to make a log of segment 20h and E7h together, crashing at 0020:36D0(#GP(0) fault due to some weird interrupt in user mode with an invalid SS:SP combination that's out of SS's range(above it's 0xFFF limit)).

https://www.dropbox.com/s/w1tmeyhg176zc8c/deb … 19_2309.7z?dl=0

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

Reply 38 of 47, by superfury

User metadata
Rank l33t++
Rank
l33t++

OK. Searching upwards for it's SS selector, I find this writing to address FF6h(which should be SS, taking into account a SS0 of FF8):

Details

MMU: Reading from real(r): 000a7e58=7a (z)
Reading from RAM(r): 00107e58=7a (z)
Reading from physical memory(r): 00107e58=7a (z)
Reading from paged memory(r): 00107e58=7a (z)
MMU: Reading from real(r): 000a7e59=0c ()
Reading from RAM(r): 00107e59=0c ()
Reading from physical memory(r): 00107e59=0c ()
Reading from paged memory(r): 00107e59=0c ()
MMU: Reading from real(r): 000a7e5a=20 ( )
Reading from RAM(r): 00107e5a=20 ( )
Reading from physical memory(r): 00107e5a=20 ( )
Reading from paged memory(r): 00107e5a=20 ( )
MMU: Reading from real(r): 000a7e5b=00 ( )
Reading from RAM(r): 00107e5b=00 ( )
Reading from physical memory(r): 00107e5b=00 ( )
Reading from paged memory(r): 00107e5b=00 ( )
MMU: Reading from real(r): 000a7e5c=00 ( )
Reading from RAM(r): 00107e5c=00 ( )
Reading from physical memory(r): 00107e5c=00 ( )
Reading from paged memory(r): 00107e5c=00 ( )
MMU: Reading from real(r): 000a7e5d=e6 (�)
Reading from RAM(r): 00107e5d=e6 (�)
Reading from physical memory(r): 00107e5d=e6 (�)
Reading from paged memory(r): 00107e5d=e6 (�)
MMU: Reading from real(r): 000a7e5e=00 ( )
Reading from RAM(r): 00107e5e=00 ( )
Reading from physical memory(r): 00107e5e=00 ( )
Reading from paged memory(r): 00107e5e=00 ( )
MMU: Reading from real(r): 000a7e5f=00 ( )
Reading from RAM(r): 00107e5f=00 ( )
Reading from physical memory(r): 00107e5f=00 ( )
Reading from paged memory(r): 00107e5f=00 ( )
MMU: Reading from real(r): 00012800=ff (�)
Reading from RAM(r): 00012800=ff (�)
Reading from physical memory(r): 00012800=ff (�)
Reading from paged memory(r): 00012800=ff (�)
MMU: Reading from real(r): 00012801=ff (�)
Reading from RAM(r): 00012801=ff (�)
Reading from physical memory(r): 00012801=ff (�)
Reading from paged memory(r): 00012801=ff (�)
MMU: Reading from real(r): 00012802=00 ( )
Reading from RAM(r): 00012802=00 ( )
Reading from physical memory(r): 00012802=00 ( )
Reading from paged memory(r): 00012802=00 ( )
MMU: Reading from real(r): 00012803=10 ()
Reading from RAM(r): 00012803=10 ()
Reading from physical memory(r): 00012803=10 ()
Reading from paged memory(r): 00012803=10 ()
MMU: Reading from real(r): 00012804=10 ()
Reading from RAM(r): 00012804=10 ()
Reading from physical memory(r): 00012804=10 ()
Reading from paged memory(r): 00012804=10 ()
MMU: Reading from real(r): 00012805=9b (�)
Reading from RAM(r): 00012805=9b (�)
Reading from physical memory(r): 00012805=9b (�)
Reading from paged memory(r): 00012805=9b (�)
MMU: Reading from real(r): 00012806=00 ( )
Reading from RAM(r): 00012806=00 ( )
Reading from physical memory(r): 00012806=00 ( )
Reading from paged memory(r): 00012806=00 ( )
MMU: Reading from real(r): 00012807=00 ( )
Reading from RAM(r): 00012807=00 ( )
Reading from physical memory(r): 00012807=00 ( )
Reading from paged memory(r): 00012807=00 ( )
MMU: Reading from real(r): 000127f8=ff (�)
Reading from RAM(r): 000127f8=ff (�)
Reading from physical memory(r): 000127f8=ff (�)
Reading from paged memory(r): 000127f8=ff (�)
MMU: Reading from real(r): 000127f9=ff (�)
Reading from RAM(r): 000127f9=ff (�)
Reading from physical memory(r): 000127f9=ff (�)
Reading from paged memory(r): 000127f9=ff (�)
MMU: Reading from real(r): 000127fa=50 (P)
Reading from RAM(r): 000127fa=50 (P)
Reading from physical memory(r): 000127fa=50 (P)
Reading from paged memory(r): 000127fa=50 (P)
MMU: Reading from real(r): 000127fb=4c (L)
Reading from RAM(r): 000127fb=4c (L)
Reading from physical memory(r): 000127fb=4c (L)
Reading from paged memory(r): 000127fb=4c (L)
MMU: Reading from real(r): 000127fc=01 ()
Reading from RAM(r): 000127fc=01 ()
Reading from physical memory(r): 000127fc=01 ()
Reading from paged memory(r): 000127fc=01 ()
MMU: Reading from real(r): 000127fd=93 (�)
Reading from RAM(r): 000127fd=93 (�)
Reading from physical memory(r): 000127fd=93 (�)
Reading from paged memory(r): 000127fd=93 (�)
MMU: Reading from real(r): 000127fe=00 ( )
Reading from RAM(r): 000127fe=00 ( )
Reading from physical memory(r): 000127fe=00 ( )
Reading from paged memory(r): 000127fe=00 ( )
MMU: Reading from real(r): 000127ff=00 ( )
Reading from RAM(r): 000127ff=00 ( )
Reading from physical memory(r): 000127ff=00 ( )
Reading from paged memory(r): 000127ff=00 ( )
0020:00000c7a 55 push bp RealRAM(r):000aa5f2=f8(�); RAM(r):0010a5f2=f8(�); Physical(r):0010a5f2=f8(�); Paged(r):0010a5f2=f8(�); Normal(r):00000002=f8(�); RealRAM(r):000aa5f3=0f(); RAM(r):0010a5f3=0f(); Physical(r):0010a5f3=0f(); Paged(r):0010a5f3=0f(); Normal(r):00000003=0f(); RealRAM(r):000aa5f4=18(); RAM(r):0010a5f4=18(); Physical(r):0010a5f4=18(); Paged(r):0010a5f4=18(); Normal(r):00000004=18(); RealRAM(r):000aa5f5=00( ); RAM(r):0010a5f5=00( ); Physical(r):0010a5f5=00( ); Paged(r):0010a5f5=00( ); Normal(r):00000005=00( ); Normal(w):00000ff6=5b([); Paged(w):00015c46=5b([); Physical(w):00015c46=5b([); RAM(w):00015c46=5b([); RealRAM(w):00015c46=5b([); Normal(w):00000ff7=00( ); Paged(w):00015c47=00( ); Physical(w):00015c47=00( ); RAM(w):00015c47=00( ); RealRAM(w):00015c47=00( ); Normal(w):00000ff4=92(�); Paged(w):00015c44=92(�); Physical(w):00015c44=92(�); RAM(w):00015c44=92(�); RealRAM(w):00015c44=92(�); Normal(w):00000ff5=0f(); Paged(w):00015c45=0f(); Physical(w):00015c45=0f(); RAM(w):00015c45=0f(); RealRAM(w):00015c45=0f(); Normal(w):00000ff2=02(); Paged(w):00015c42=02(); Physical(w):00015c42=02(); RAM(w):00015c42=02(); RealRAM(w):00015c42=02(); Normal(w):00000ff3=32(2); Paged(w):00015c43=32(2); Physical(w):00015c43=32(2); RAM(w):00015c43=32(2); RealRAM(w):00015c43=32(2); Normal(w):00000ff0=e7(�); Paged(w):00015c40=e7(�); Physical(w):00015c40=e7(�); RAM(w):00015c40=e7(�); RealRAM(w):00015c40=e7(�); Normal(w):00000ff1=00( ); Paged(w):00015c41=00( ); Physical(w):00015c41=00( ); RAM(w):00015c41=00( ); RealRAM(w):00015c41=00( ); Normal(w):00000fee=9b(�); Paged(w):00015c3e=9b(�); Physical(w):00015c3e=9b(�); RAM(w):00015c3e=9b(�); RealRAM(w):00015c3e=9b(�); Normal(w):00000fef=1c(); Paged(w):00015c3f=1c(); Physical(w):00015c3f=1c(); RAM(w):00015c3f=1c(); RealRAM(w):00015c3f=1c(); RealRAM(p):000a1c7a=55(U); RAM(p):00101c7a=55(U); Physical(p):00101c7a=55(U); Paged(p):00101c7a=55(U); Normal(p):00000c7a=55(U); RealRAM(p):000a1c7b=8b(�); RAM(p):00101c7b=8b(�); Physical(p):00101c7b=8b(�); Paged(p):00101c7b=8b(�); Normal(p):00000c7b=8b(�); RealRAM(p):000a1c7c=ec(�); RAM(p):00101c7c=ec(�); Physical(p):00101c7c=ec(�); Paged(p):00101c7c=ec(�); Normal(p):00000c7c=ec(�); RealRAM(p):000a1c7d=06(); RAM(p):00101c7d=06(); Physical(p):00101c7d=06(); Paged(p):00101c7d=06(); Normal(p):00000c7d=06(); RealRAM(p):000a1c7e=50(P); RAM(p):00101c7e=50(P); Physical(p):00101c7e=50(P); Paged(p):00101c7e=50(P); Normal(p):00000c7e=50(P); RealRAM(p):000a1c7f=f7(�); RAM(p):00101c7f=f7(�); Physical(p):00101c7f=f7(�); Paged(p):00101c7f=f7(�); Normal(p):00000c7f=f7(�); RealRAM(p):000a1c80=46(F); RAM(p):00101c80=46(F); Physical(p):00101c80=46(F); Paged(p):00101c80=46(F); Normal(p):00000c80=46(F); RealRAM(p):000a1c81=06(); RAM(p):00101c81=06(); Physical(p):00101c81=06(); Paged(p):00101c81=06(); Normal(p):00000c81=06(); RealRAM(p):000a1c82=02(); RAM(p):00101c82=02(); Physical(p):00101c82=02(); Paged(p):00101c82=02(); Normal(p):00000c82=02(); RealRAM(p):000a1c83=00( ); RAM(p):00101c83=00( ); Physical(p):00101c83=00( ); Paged(p):00101c83=00( ); Normal(p):00000c83=00( ); RealRAM(p):000a1c84=74(t); RAM(p):00101c84=74(t); Physical(p):00101c84=74(t); Paged(p):00101c84=74(t); Normal(p):00000c84=74(t); RealRAM(p):000a1c85=18(); RAM(p):00101c85=18(); Physical(p):00101c85=18(); Paged(p):00101c85=18(); Normal(p):00000c85=18(); RealRAM(p):000a1c86=0f(); RAM(p):00101c86=0f(); Physical(p):00101c86=0f(); Paged(p):00101c86=0f(); Normal(p):00000c86=0f(); RealRAM(p):000a1c87=00( ); RAM(p):00101c87=00( ); Physical(p):00101c87=00( ); Paged(p):00101c87=00( ); Normal(p):00000c87=00( ); RealRAM(p):000a1c88=c8(�); RAM(p):00101c88=c8(�); Physical(p):00101c88=c8(�); Paged(p):00101c88=c8(�); Normal(p):00000c88=c8(�); RealRAM(p):000a1c89=05(); RAM(p):00101c89=05(); Physical(p):00101c89=05(); Paged(p):00101c89=05(); Normal(p):00000c89=05(); Paged(w):00015c3c=98(�); Physical(w):00015c3c=98(�); RAM(w):00015c3c=98(�); RealRAM(w):00015c3c=98(�); Paged(w):00015c3d=0f(); Physical(w):00015c3d=0f(); RAM(w):00015c3d=0f(); RealRAM(w):00015c3d=0f()
Registers:
EAX: 00000006 EBX: 028704bf ECX: 00005454 EDX: 00000c66
ESP: 00000fee EBP: 00000f98 ESI: 00000002 EDI: 0000390b
CS: 0020 DS: 00ef ES: 019f FS: 0000 GS: 0000 SS: 0018 TR: 0158 LDTR: 0168
EIP: 00000c7a EFLAGS: 00003002
CR0: 00000001 CR1: 00000000 CR2: 00000000 CR3: 00000000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000127e003ff IDTR: 000000107df007ff
CS descriptor: 00009B101000FFFF
DS descriptor: 0000F31189C0C5CF
ES descriptor: 0000F3FCCBC0111F
FS descriptor: 0000730005C0FFFF
GS descriptor: 000073002700FFFF
SS descriptor: 000093014C50FFFF
TR descriptor: 00008310A5F00BF9
LDTR descriptor: 000082FCFF8007FF
FLAGSINFO: 00000000000000vr0n11oditsz0a0p1c

OK, so the stack is:
FF8: <- SS0
FF6: 5bh
FF4: F92h
FF2: 3202h
FF0: E7h
FEE: 1C9Bh

That's not what's read at the second location?

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

Reply 39 of 47, by superfury

User metadata
Rank l33t++
Rank
l33t++

OK. Searching up, I see the invalid value coming from location FC4 at 0020:00003DF1, which got it's AX value from the LODSW before it at 0020:00003DF0, which got it from 5B:FC4.

That value was from 00e7:000095f2 ("00e7:000095f2 26 83 6F 08 04 sub word es:[bx+08],0004")...

Edit: Further up, there's:

	RealRAM(r):00015bb4=d2(�); RAM(r):00015bb4=d2(�); Physical(r):00015bb4=d2(�); Paged(r):00015bb4=d2(�); RealRAM(r):00015bb5=36(6); RAM(r):00015bb5=36(6); Physical(r):00015bb5=36(6); Paged(r):00015bb5=36(6)
0020:000036cf FC cld Paged(w):0010a5b4=d2(�); Physical(w):0010a5b4=d2(�); RAM(w):0010a5b4=d2(�); RealRAM(w):000aa5b4=d2(�); Paged(w):0010a5b5=36(6); Physical(w):0010a5b5=36(6); RAM(w):0010a5b5=36(6); RealRAM(w):000aa5b5=36(6)

Which is:

0020:000036d0 F3 A5 rep movsw
Registers:
EAX: 00000048 EBX: 02870fb8 ECX: 00000024 EDX: 000000e7
ESP: 00000f48 EBP: 00000f4a ESI: 00000f58 EDI: 00000fb8
CS: 0020 DS: 0018 ES: 005b FS: 0000 GS: 0000 SS: 0018 TR: 0158 LDTR: 0168
EIP: 000036d0 EFLAGS: 00003012
CR0: 00000001 CR1: 00000000 CR2: 00000000 CR3: 00000000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000000127e003ff IDTR: 000000107df007ff

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