Page 1 of 1

QEMU Port 0xE9 Output?

Posted: Fri May 25, 2018 4:57 pm
by rwosdev
How do you get port 0xE9 output in QEMU as in Bochs? I've written a function to enable redirecting all kernel output to 0xE9 (or elsewhere) which works fine in Bochs.

Would be extremely helpful if I could have the same in QEMU for graphics debugging.

The command-line option "-debugcon stdio" produces no output in the command line when QEMU is launched in it.

Re: QEMU Port 0xE9 Output?

Posted: Fri May 25, 2018 5:27 pm
by BenLunt
Write to the parallel port.

Doing this is almost as easy as writing to port 0xE9 and as long as the emulator supports a parallel port, you can direct any text to a specific file.

0) Read port 0x379, polling bit 7.
1) Write the char to port 0x378
2) "toggle" bit 0 in port 0x37A
3) Read port 0x379, polling bit 6.

You might want to "catch" CRLF's if your guest uses CRLF instead of LF. The text file may not look quite right with CRLF's or LF alone depending on the platform you are using.

Ben
- http://www.fysnet.net/osdesign_book_series.htm

Update: Since the OP has had a chance to write up his/her own code (as it should be), here is an example: http://www.fysnet.net/blog/2018/06/

Re: QEMU Port 0xE9 Output?

Posted: Fri May 25, 2018 8:12 pm
by rwosdev
Hey, thanks for the suggestion.

I tried it but polling for BUSY results in an infinite loop and ignoring it causes only one character to be written on the parallel output.

Code: Select all

PollParallelBusy:
	push ax
	push dx
	
	mov dx, 0x379
.loop:
	in al, dx
	and al, 10000000b
	cmp al, 0
	jnz .loop
	
	pop dx
	pop ax
	ret

StringOut:
...
.debugOutLoop:
	lodsb
	inc edx
	
	; For Bochs
	out 0xE9, al
	
	; For QEMU:
	push dx
	
	;call PollParallelBusy

	; Write character
	mov dx, 0x378
	out dx, al
	
	; Toggle bit 0 (STROBE) of 0x37A to say data is ready
	mov dx, 0x37A
	in al, dx
	or al, 00000001b
	out dx, al
	
	; ... Left out polling 0x379 acknowledge for now
	
.next:
	pop dx
	
	cmp edx, ecx
	jl .debugOutLoop

Re: QEMU Port 0xE9 Output?

Posted: Fri May 25, 2018 9:01 pm
by BenLunt
rwosdev wrote:Hey, thanks for the suggestion.

I tried it but polling for BUSY results in an infinite loop and ignoring it causes only one character to be written on the parallel output.

Code: Select all

PollParallelBusy:
	push ax
	push dx
	
	mov dx, 0x379
.loop:
	in al, dx
	and al, 10000000b
	cmp al, 0
	jnz .loop
No need for the "cmp al,0" instruction. The "and" sets the flags identical to the "cmp". In fact, the "cmp" is an "and" instruction, disregarding the results.

In my first reply, I tried to point you in the right direction, which it seems I did, though I tried not to do it for you.

Please search a little more and find out what value to watch for in bit 7. A lot of places say that it is the busy bit, which is correct, but is it set or clear to indicate busy?
rwosdev wrote:

Code: Select all

	pop dx
	pop ax
	ret

StringOut:
...
.debugOutLoop:
	lodsb
	inc edx
	
	; For Bochs
	out 0xE9, al
	
	; For QEMU:
	push dx
	
	;call PollParallelBusy

	; Write character
	mov dx, 0x378
	out dx, al
	
	; Toggle bit 0 (STROBE) of 0x37A to say data is ready
	mov dx, 0x37A
	in al, dx
	or al, 00000001b
	out dx, al
	
	; ... Left out polling 0x379 acknowledge for now
The reason it only outputs one char, is that you never turn off the strobe to be able to turn it back on, indicating another character. An on bit only indicates to the other side to read the parallel lines for the char. Only when the bit goes low (drops the power on that line), does the hardware indicate that it needs to be ready for the next char. This is where timing comes into play. How fast can I toggle (strobe) the strobe line and the "other side" will receive all my characters intact? For a simple thing as outputting to a file using an emulator, the fact that the line goes high, then low is enough. No need for timing. However, my code pauses for a slight bit, while the line is high, before dropping the strobe, just to be sure.
rwosdev wrote:

Code: Select all

.next:
	pop dx
	
	cmp edx, ecx
	jl .debugOutLoop
Side note: The Parallel Port hardware, in the standard form, has little or no circuitry. It simply is a bit representation of the status of each of the pins. If a pin is high (has power), the bit will be set (or clear), period. Writing a value to the data port, simply sets high all lines (pins) that have a bit set, dropping the power (setting to low) all the pins that have a zero bit. It is the closest you can come to actually physically manipulating the hardware without any firmware getting in the way. Long live the Parall....oh, ya, its dead...

Hope this helps,
Ben

Re: QEMU Port 0xE9 Output?

Posted: Fri May 25, 2018 9:46 pm
by rwosdev
Took everything you said into consideration, here's the new code which seems to work nicely.

I've never used the parallel port before so if there's something not quite right here please let me know.

In my OS, I only send newlines in strings ('\n') so this code catches them as you said and sends an additional carriage return byte to the parallel port so each string starts on a new line when requested.

Screenshot of result attached, showing correct text sent from two different drivers being routed through the parallel port.

Many thanks

Code: Select all

ParallelPollStatus:
; bl = mask
	push ax
	push dx
	
	mov dx, 0x379
.loop:
	in al, dx
	and al, bl
	jz .loop ; Function is only used for BUSY and ACK, and them being 0 means they're set.
	; https://wiki.osdev.org/Parallel_port says: The ERROR, ACK and BUSY signals are active low when reading from the IO port.
	
	pop dx
	pop ax
	ret
	
ParallelWriteByte:
; al = character
	push ax
	push bx
	push dx
	
	mov bl, 10000000b ; Wait until not busy
	call ParallelPollStatus

	mov dx, 0x378
	out dx, al	; Write character
	
	mov dx, 0x37A
	in al, dx
	or al, 00000001b
	out dx, al ; Set STROBE to say 'data is ready'
	
	mov bl, 01000000b ; Wait until acknowledgement
	call ParallelPollStatus
	
	and al, 11111110b  ; Clear STROBE so device is ready for next character
	out dx, al
	
	mov bl, 01000000b ; Wait until acknowledgement
	call ParallelPollStatus
		
	pop dx
	pop bx
	pop ax
	
	ret

StringOut:
...
.debugOutLoop:
	lodsb
	mov ah, al
	inc edx
	
	; For Bochs
	out 0xE9, al
	
	; For QEMU:
	call ParallelWriteByte
	
	cmp al, 10 ; Catch newline
	jne .next
	
.addCR:		; If newline, add carriage return
	mov al, 13
	call ParallelWriteByte
	
.next:
	cmp edx, ecx
	jl .debugOutLoop

.done:
	...
	ret

Re: QEMU Port 0xE9 Output?

Posted: Sat May 26, 2018 2:15 am
by Korona
"-debugcon stdio" certainly works. If it does not, maybe it was deactivated during configure-time (?). Of course, this also only works if you run qemu from a terminal.

If you want to write to a real device, I would suggest serial over parallel ports as modern PCs actually have serial ports but no parallel ports.

Use "-serial stdio" or the equivalent option for the parallel port to redirect output to the terminal qemu is running in.

Re: QEMU Port 0xE9 Output?

Posted: Sat May 26, 2018 9:30 am
by rwosdev
I just discovered I was using qemu-system-i386w.exe - I switched to qemu-system-i386.exe and port 0xE9 output in the command line (with -debugcon stdio) worked, as did parallel output using -parallel stdio

Still keeping the parallel code and learned some new things as well so nothing's in vain.

Cheers guys

Re: QEMU Port 0xE9 Output?

Posted: Mon May 28, 2018 10:15 am
by Wukl

Slightly off topic:

BenLunt wrote: In fact, the "cmp" is an "and" instruction, disregarding the results.


You're confusing cmp with test :wink:

cmp compares by subtracting (so, sub), while test does the bitwise and

Re: QEMU Port 0xE9 Output?

Posted: Mon May 28, 2018 4:20 pm
by BenLunt
Wukl wrote:
BenLunt wrote: In fact, the "cmp" is an "and" instruction, disregarding the results.
You're confusing cmp with test :wink:

cmp compares by subtracting (so, sub), while test does the bitwise and
Oh ya, you're right. Sorry. I don't know why I thought that. Long day probably.

Thanks,
Ben