Page 3 of 4

Re: Debugging help for protected mode entry+exit experiment

Posted: Wed Sep 23, 2020 2:57 am
by awik
alexfru wrote:If you're still interested in virtual 8086 mode,
I am, but first I need to get the PM entry and exit right. In fact, I don't need only to get it right, I need to *understand* it as fully as I can. In addition, I need to understand how to reflect interrupts to real or V86 mode.
have a look at tut15.
I did. It is shorter than I expected. But I don't understand it as good as I need to.
It puts the CPU in it and launches COMMAND.COM. There's no 32-bit code, though, and it's a bit heavy on TSS use.
And there are a few things not entirely correct (the far jump after the mode switches isn't there, there's port 70h reading, etc), but it gives one an idea how to handle IRQs and the int instruction while in virtual 8086 mode.
In a debugger, I tried reading from port 0x70, and it came back with value 0x0C. If the port is not readable, shouldn't I get 0xFF (bus float?)?

-Albert.

Re: Debugging help for protected mode entry+exit experiment

Posted: Wed Sep 23, 2020 3:50 pm
by Octocontrabass
awik wrote:Returning to the environment from which the program was launched is part of the "specification" for this program, and maybe later versions.
Why? Writing a DOS extender seems excessive if you're only doing this to learn about VM86 mode.
awik wrote:Writing a boot sector, such as if writing my own operating system loader, is harder to debug, and is beyond the scope of the current program.
Harder to debug how? You can step through your program in a debugger with or without DOS, and it's usually easier without DOS (you can load your program at a fixed address).
awik wrote:Acknowledging an interrupt just signals that the system is ready for the next interrupt. Whether it is necessary to do more than just an EOI will depend on the specifics of the device. In the case of the timer interrupt, it is apparently sufficient to do just the EOI.
Most devices require you to acknowledge the IRQ before they will raise another, so sending the EOI without acknowledging the device will prevent any further IRQs. The timer is the exception here. And speaking of the timer, anything hooked into the timer IRQ won't be called when you're not running the installed handler.
awik wrote:It is a can of worms that would be easier not to open, but I'm afraid it is something I have to learn.
Again, why?
awik wrote:I read about this in the Intel IA-32 "System Programming" manual". The way I understood it, the bitness specification in the stack descriptor determines whether SP or ESP will be used by default. Is this the correct interpretation?
Mostly. There are some odd exceptions.
awik wrote:That is because the key requirement is to load CS with a new value, and RETF accomplishes that just fine.
Intel claims you must use a far JMP or CALL, and it must be immediately after the MOV to CR0 that changes PE. (Volume 3A section 9.9.1.) This requirement is intentionally strict so that Intel can change the behavior of MOV to CR0 without breaking software that follows the documented requirements.

Re: Debugging help for protected mode entry+exit experiment

Posted: Wed Sep 23, 2020 11:36 pm
by awik
Octocontrabass wrote:
awik wrote:Returning to the environment from which the program was launched is part of the "specification" for this program, and maybe later versions.
Why? Writing a DOS extender seems excessive if you're only doing this to learn about VM86 mode.
I want to learn about V86 because I want to implement a simple multitasker (if a multitasker can be simple).
awik wrote:Writing a boot sector, such as if writing my own operating system loader, is harder to debug, and is beyond the scope of the current program.
Harder to debug how? You can step through your program in a debugger with or without DOS, and it's usually easier without DOS (you can load your program at a fixed address).
How do I launch a debugger without a launch platform?
awik wrote:Most devices require you to acknowledge the IRQ before they will raise another, so sending the EOI without acknowledging the device will prevent any further IRQs. The timer is the exception here. And speaking of the timer, anything hooked into the timer IRQ won't be called when you're not running the installed handler.
One thing at a time. For a start, I intend to figure out how to "reflect" interrupts to real mode (later V86).

So far, I've only been receiving IRQ0s, and the occasional IRQ1. I once also got an invalid opcode exception, when I got the "BITS xx" wrong. Then only problem for now, is that the system time does not get updated.
awik wrote:It is a can of worms that would be easier not to open, but I'm afraid it is something I have to learn.
Again, why?
See above. Besides, it seems impossible to be a competent system programmer without knowing this stuff.
awik wrote:I read about this in the Intel IA-32 "System Programming" manual". The way I understood it, the bitness specification in the stack descriptor determines whether SP or ESP will be used by default. Is this the correct interpretation?
Mostly. There are some odd exceptions.
That is useful to know, because I've been considering using ENTER/LEAVE.
awik wrote:That is because the key requirement is to load CS with a new value, and RETF accomplishes that just fine.
Intel claims you must use a far JMP or CALL, and it must be immediately after the MOV to CR0 that changes PE. (Volume 3A section 9.9.1.) This requirement is intentionally strict so that Intel can change the behavior of MOV to CR0 without breaking software that follows the documented requirements.
I see.

-Albert.

Re: Debugging help for protected mode entry+exit experiment

Posted: Thu Sep 24, 2020 3:04 pm
by alexfru
awik wrote:
alexfru wrote:If you're still interested in virtual 8086 mode,
I am, but first I need to get the PM entry and exit right. In fact, I don't need only to get it right, I need to *understand* it as fully as I can.
It's not secret information. See sections "9.9.1 Switching to Protected Mode" and "9.9.2 Switching Back to Real-Address Mode" of "Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3 (3A & 3B): System Programming Guide".

I encourage you to read those sections and all relevant sections of the manual as well. Don't be shy to use your PDF reader's search function to find and learn more about each unfamiliar term or register.
awik wrote:In addition, I need to understand how to reflect interrupts to real or V86 mode.
See "CHAPTER 17 8086 Emulation" of the same manual.
awik wrote:
have a look at tut15.
I did. It is shorter than I expected. But I don't understand it as good as I need to.
I moved #GP and IRQ handling into separate tasks. They are invoked as nested/linked tasks, that is, they preempt whatever the current task happens to be (usually the v86 task) to handle #GP or an IRQ. It's a bit easier/cleaner to read/write fields in a TSS than somewhere on the stack. In particular, it's easier to set up virtual 8086 mode in a task than on the stack.

Even though these #GP and IRQ handler tasks "return" (with iretd), they are still tasks and their subsequent invocation starts them where they left off last time, that is, after iretd, which is why you can see loops in _isr_20_wrapper ... _isr_2F_wrapper and _isr_0D_wrapper.

gpf_handler() and irq_handler() reflect the various int instructions (int3, int n, into) and IRQs for handling back into the v86 task.

gpf_handler() also intercepts calls to BIOS int 15h function 87h to copy memory and handles them by itself. It makes himem.sys work (the original handler of int 15h function 87h would try to enter protected mode and fail).
awik wrote:In a debugger, I tried reading from port 0x70, and it came back with value 0x0C. If the port is not readable, shouldn't I get 0xFF (bus float?)?
I'm afraid, there's no guarantee for a port that's not supposed to be read to read as anything specific, even if you have reasonable expectations as to how it may be implemented. Much like undefined behavior in C/C++.

Re: Debugging help for protected mode entry+exit experiment

Posted: Thu Sep 24, 2020 7:08 pm
by Octocontrabass
awik wrote:I want to learn about V86 because I want to implement a simple multitasker (if a multitasker can be simple).
I don't think it can be simple, unless you forget about DOS and V86.
awik wrote:How do I launch a debugger without a launch platform?
Use a virtual machine that supports a built-in or external debugger. QEMU and Bochs both support connecting GDB as an external debugger. Bochs also has a built-in debugger.
awik wrote:Besides, it seems impossible to be a competent system programmer without knowing this stuff.
It's entirely possible to be a competent system programmer without learning how DOS works, since a good system should work nothing like DOS. :P (But digging into DOS internals does sound like a fun way to spend your time...)

Re: Debugging help for protected mode entry+exit experiment

Posted: Fri Sep 25, 2020 9:58 am
by awik
alexfru wrote:
awik wrote:I am, but first I need to get the PM entry and exit right. In fact, I don't need only to get it right, I need to *understand* it as fully as I can.
It's not secret information.
No, of course not, but there is a difference between reading about it and "getting the hang of it".
See sections "9.9.1 Switching to Protected Mode" and "9.9.2 Switching Back to Real-Address Mode" of "Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3 (3A & 3B): System Programming Guide".

I encourage you to read those sections and all relevant sections of the manual as well. Don't be shy to use your PDF reader's search function to find and learn more about each unfamiliar term or register.
I've been using this manual already, although it is not the latest version.

I had a look at the section you refer to today. It does not give me any insights as to why the (virtual) machine locks up rather than returning to DOS.
I moved #GP and IRQ handling into separate tasks. They are invoked as nested/linked tasks, that is, they preempt whatever the current task happens to be (usually the v86 task) to handle #GP or an IRQ. It's a bit easier/cleaner to read/write fields in a TSS than somewhere on the stack. In particular, it's easier to set up virtual 8086 mode in a task than on the stack.

Even though these #GP and IRQ handler tasks "return" (with iretd), they are still tasks and their subsequent invocation starts them where they left off last time, that is, after iretd, which is why you can see loops in _isr_20_wrapper ... _isr_2F_wrapper and _isr_0D_wrapper.

gpf_handler() and irq_handler() reflect the various int instructions (int3, int n, into) and IRQs for handling back into the v86 task.
Thanks for the attempt at clarification.

One idea I took from it was to generate the IDT on the fly dynamically using a loop rather than attempting a static implementation, as did my first sample program above.
gpf_handler() also intercepts calls to BIOS int 15h function 87h to copy memory and handles them by itself. It makes himem.sys work (the original handler of int 15h function 87h would try to enter protected mode and fail).
Interesting. Windows (the DOS-based one) replaces the whole XMS driver!

-Albert.

Re: Debugging help for protected mode entry+exit experiment

Posted: Fri Sep 25, 2020 10:07 am
by sj95126
awik wrote:
See sections "9.9.1 Switching to Protected Mode" and "9.9.2 Switching Back to Real-Address Mode" of "Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3 (3A & 3B): System Programming Guide".

I encourage you to read those sections and all relevant sections of the manual as well. Don't be shy to use your PDF reader's search function to find and learn more about each unfamiliar term or register.
I've been using this manual already, although it is not the latest version.

I had a look at the section you refer to today. It does not give me any insights as to why the (virtual) machine locks up rather than returning to DOS.
As a general suggestion, you might try reading the AMD version of the documentation. It's infinitely more readable and straightforward than the Intel docs. There have been a few times where I read something and said "Ah, NOW I understand!" and would have earlier if Intel had been clearer.

Re: Debugging help for protected mode entry+exit experiment

Posted: Fri Sep 25, 2020 10:36 am
by awik
Octocontrabass wrote:
awik wrote:How do I launch a debugger without a launch platform?
Use a virtual machine that supports a built-in or external debugger. QEMU and Bochs both support connecting GDB as an external debugger. Bochs also has a built-in debugger.
I already had QEMU installed, and I added Bochs today. Bochs fails to boot with an IDE timeout.

As for QEMU, I can run the same code as I've been using on VMware, but haven't figured out how to use it for debugging. As it is, it is even harder with QEMU because it reboots immediately rather than pausing.
awik wrote:(But digging into DOS internals does sound like a fun way to spend your time...)
I'm currently reading "Undocumented DOS (2nd ed.)" by Andrew Schulman et al. Before that, I read his "Unauthorized Windows 95", which actually provides nice insights into both of these systems, and which is directly relevant (eg. the "instance data" of Win9x/3.x) to the projects I have in mind. Next, I intend to read "DOS Internals" by Geoff Chappell -- now there's a guy who can read code! Schulman refers repeatedly to Chappell's work.

-Albert.

Re: Debugging help for protected mode entry+exit experiment

Posted: Fri Sep 25, 2020 10:37 am
by awik
sj95126 wrote:As a general suggestion, you might try reading the AMD version of the documentation. It's infinitely more readable and straightforward than the Intel docs. There have been a few times where I read something and said "Ah, NOW I understand!" and would have earlier if Intel had been clearer.
I will have a look.

-Albert.

Re: Debugging help for protected mode entry+exit experiment

Posted: Fri Sep 25, 2020 5:42 pm
by Octocontrabass
awik wrote:Bochs fails to boot with an IDE timeout.
It sounds like you've missed a required configuration option somewhere.
awik wrote:As for QEMU, I can run the same code as I've been using on VMware, but haven't figured out how to use it for debugging. As it is, it is even harder with QEMU because it reboots immediately rather than pausing.
There are some instructions for setting up QEMU and GDB on the wiki. You can stop it from rebooting using the "-no-reboot" option.

Re: Debugging help for protected mode entry+exit experiment

Posted: Fri Sep 25, 2020 6:38 pm
by alexfru
awik wrote:
alexfru wrote:
awik wrote:I am, but first I need to get the PM entry and exit right. In fact, I don't need only to get it right, I need to *understand* it as fully as I can.
It's not secret information.
No, of course not, but there is a difference between reading about it and "getting the hang of it".
One could say there's a certain learning curve.
awik wrote:
See sections "9.9.1 Switching to Protected Mode" and "9.9.2 Switching Back to Real-Address Mode" of "Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3 (3A & 3B): System Programming Guide".

I encourage you to read those sections and all relevant sections of the manual as well. Don't be shy to use your PDF reader's search function to find and learn more about each unfamiliar term or register.
I've been using this manual already, although it is not the latest version.
I have a stale version. From 2011. :) But there's unlikely something very new w.r.t. mode changes.
awik wrote:I had a look at the section you refer to today. It does not give me any insights as to why the (virtual) machine locks up rather than returning to DOS.
It normally shouldn't mention anything specific to DOS (however, the manual does mention some DOS-related things like the A20 gate and external x87 FPUs of the days long gone).

But there are some things you find out about by trial and error. For example, I noticed that when my protected mode programs switched between TSS', DPMI programs wouldn't run subsequently. I don't remember exactly how I figured it out, but all I had to do is execute CLTS to clear CR0.TS. What was likely happening was DPMI hosts / DOS extenders would (re)init the FPU with F(N)INIT and fail to handle #NM.

Re: Debugging help for protected mode entry+exit experiment

Posted: Sat Sep 26, 2020 12:35 am
by awik
I am wondering why ...

... this fails:

Code: Select all

mov	ax, [bp+BSS_OLD_SEG]
mov [.sel3], ax
jmp .cp  ; clear prefetch
.cp:
db 0eah  ; JMP FAR
dw .rm
.sel3:
dw 0
... and this works:

Code: Select all

...
push	ax
push	.rm
retf
Both are trying to return to load a real-mode CS by jumping to this address:

Code: Select all

ALIGN 2
.rm:	;

Re: Debugging help for protected mode entry+exit experiment

Posted: Sat Sep 26, 2020 1:04 am
by nullplan
Self-modifying code? Why not just far jump with a memory operand?

Code: Select all

dst: dw .rm, 0
...
mov [dst + 2],ax
jmp far [dst]
Self-modifying code is a bit hard. You need a context-synchronizing instruction (like CPUID) between modification and use on the Pentium(?) and up, a jump is no longer enough. Thankfully the conditional jump over the CPUID instruction itself counts as the jump necessary to clear the prefetch-queue on the older systems.

Re: Debugging help for protected mode entry+exit experiment

Posted: Sat Sep 26, 2020 9:38 am
by awik
After days of intense debugging, I found that the bug preventing a return to DOS is probably a VMware bug.

The following was the offending code:

Code: Select all

	mov	ax, 18h		; video memory selector
	mov	es, ax
What's so special about that? Well, it turned out to be the descriptor:

Code: Select all

ze_gdt:
	dd 0, 0		; entry 0: unused
....
.sel18: ; text mode VGA memory
	dw 0xFFF   ; +0  limit 4095  <--------------------------- look here! XXX
	dw 0x8000  ; +2  low 16 bits of base addr.
	db 0x0B    ; +4  bits 16-23 of base addr.
	db 0x93    ; +5  PDdSType, *P=present, D=DPL, S=0=sys.desc, d.seg+w
	db 0x00    ; +6  GBLALimt, G=gran., B=16bit*, L=64bit-, A=avail.
	db 0x00    ; +7  base addr. 24-31
Apparently the attributes of a protected mode segment in VMware are "sticky": they won't go away even after a return to real-mode and reloading the segment register with a real mode value. It's the same thing with a 32-bit code segment -- you remain in 32-bit mode, even after a return to real mode, unless you first load a 16-bit code segment while still in protected mode.

Therefore, the 0xFFF (4095) limit on the ES segment would remain in effect, preventing DOS and other real-mode software from working properly, resulting in a freeze.

It appears that DOSbox and QEMU do not share this VMware behaviour. Therefore, it would seem to be a VMware bug.

This ought to be documented somewhere, so that others won't have to go through the same ordeal as I have.

Cheers!
Albert.

Re: Debugging help for protected mode entry+exit experiment

Posted: Sat Sep 26, 2020 9:46 am
by Octocontrabass
awik wrote:I am wondering why ...
No reason. Neither one follows the Intel requirements (you must put the far JMP or far CALL immediately after the instruction that changes CR0.PE, with no other instructions between) so there is no guarantee that either will work.
awik wrote:Apparently the attributes of a protected mode segment in VMware are "sticky": they won't go away even after a return to real-mode and reloading the segment register with a real mode value.
This is true of bare metal as well, and the Intel manual says as much in the section about returning to real mode.
awik wrote:It appears that DOSbox and QEMU do not share this VMware behaviour. Therefore, it would seem to be a VMware bug.
It's a DOSBox and QEMU bug.