OSDev.org

The Place to Start for Operating System Developers
It is currently Mon Apr 29, 2024 11:05 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 4 posts ] 
Author Message
 Post subject: x86 QEMU BIOS COM Interrupt supported?
PostPosted: Tue Apr 02, 2024 5:28 pm 
Offline

Joined: Wed Jan 10, 2024 9:32 am
Posts: 5
Hi all, I hopping someone can help me out. I have created what I thought would be a trivial test for a fun bare metal implementation, but I seem to have hit a limit wall, which I can't seem to figure out if it's a qemu limitation or my own :D :D :D

Inspiration came from https://pages.cs.wisc.edu/~bolo/shipyard/3ins4th.html and the goal was to use this to created some hand crafted machine code and execute in bare metal for low level benchmarking. Things like latency for different calls, register access times, memory pipeline performance ect...

Ok, I have this simple code, it's just a bios that does the following, initiates UART on com1, it listens on com1, and do some storing and fetching of bytes. I have been looking at the code for some time now, and the send of the data through qemu seems to fail. I don't have HW to test this on to connect a real serial on it, here is my original code in FASAM. The other two files, are iteration of me testing different areas of the code to see if this was an issue with my com1 setup.

when I was trying to setup the code to simply revert back what I was sending, I could not get it to properly print on the VGA screen what was been sent via the serial console, I have run the code with QEMU -serial stdio and without, but it seems that either way, I can type a character, hit return, CR will trigger, but the value is not correctly printed or submitted.


Attachment:
File comment: FASM code
Original_3word.asm [2.8 KiB]
Downloaded 1 time


Code:
org 0x7c00                  ; BIOS load address

start:
    ; Initialize the processor (not explicitly done in the code, usually BIOS job)
    ; Initialize the serial port
    mov ah, 0x00            ; Set COM port initialization function
    mov al, 0x03            ; Baud rate divisor for 9600 baud
    mov dx, 0               ; COM1 port number (0 for COM1)
    int 0x14                ; Call BIOS COM interrupt

    ; Clear the screen
    mov ax, 0x0003          ; Set video mode to 80x25 text mode
    int 0x10

main_loop:
    call read_byte          ; Read a byte from the serial port
    cmp al, 0x01            ; Check if byte = 01 [fetch]
    je fetch_byte
    cmp al, 0x02            ; Check if byte = 02 [store]
    je store_byte
    cmp al, 0x03            ; Check if byte = 03 [call]
    je call_subroutine
    jmp main_loop           ; Loop back if none of the above

fetch_byte:
    call read_address       ; Get address from the serial port
    mov al, [bx]            ; Fetch the byte from that address
    call send_byte          ; Send the byte to the serial port
    jmp main_loop

store_byte:
    call read_address       ; Get address from the serial port
    call read_byte          ; Get a byte from the serial port
    mov [bx], al            ; Store the byte at that address
    jmp main_loop

call_subroutine:
    call read_address       ; Get address from the serial port
    call far [bx]           ; Call the subroutine at that address
    jmp main_loop           ; Return to the main loop after subroutine

read_address:               ; Function to read an address from the serial port
    call read_byte          ; Read low byte
    mov bl, al
    call read_byte          ; Read high byte
    mov bh, al
    ret

read_byte:                  ; Function to read a byte from the serial port
    mov dx, 0x3f8           ; COM1 base address
wait_for_data:
    in al, dx               ; Read line status register
    test al, 1              ; Test if data available (bit 0)
    jz wait_for_data        ; If not, loop until data is available
    mov dx, 0x3f8           ; Reset dx to point to the data register
    in al, dx               ; Read received byte from data register
    ret

send_byte:                  ; Function to send a byte to the serial port
    push ax                 ; Save AX register
    mov ah, al              ; Move byte to AH for sending
    mov dx, 0               ; COM1 port number (0 for COM1)
    int 0x14                ; Call BIOS COM interrupt
    pop ax                  ; Restore AX register
    ret

; The print_byte and nibble_to_ascii functions are not necessary for the goals
; and have been removed to simplify the code.

times 510-($-$$) db 0       ; Pad remaining bytes with zeros
dw 0xaa55                   ; Boot signature


Start here, this was the original code I started with, the two others it's just me testing things see if I would find something broken.

Thank you all,


Attachments:
com1.asm [3 KiB]
Downloaded 1 time
3words.asm [5.22 KiB]
Downloaded 1 time
Top
 Profile  
 
 Post subject: Re: x86 QEMU BIOS COM Interrupt supported?
PostPosted: Tue Apr 02, 2024 6:41 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5146
jemo07 wrote:
Code:
    mov al, 0x03            ; Baud rate divisor for 9600 baud

No, that's 110 baud. If you want 9600 baud, set AL to 0xE3.

jemo07 wrote:
Code:
    mov al, [bx]            ; Fetch the byte from that address
    mov [bx], al            ; Store the byte at that address
    call far [bx]           ; Call the subroutine at that address

You never set DS, so you have no idea what addresses these instructions are actually using.

jemo07 wrote:
Code:
    mov dx, 0x3f8           ; COM1 base address
    in al, dx               ; Read line status register

That's not the line status register, that's the data register.

jemo07 wrote:
Code:
    mov ah, al              ; Move byte to AH for sending

That's not what you need to put in AH before calling INT 0x14. What are you using as your reference for BIOS calls?


Top
 Profile  
 
 Post subject: Re: x86 QEMU BIOS COM Interrupt supported?
PostPosted: Wed Apr 03, 2024 6:04 am 
Offline

Joined: Wed Jan 10, 2024 9:32 am
Posts: 5
Thank you that was most helpful, I had missed some of the suggestions you made... however, I'm thinking that before I get to the fetch/store/jump functions, I need to ensure that my serial communications is correct. For this, I have overly simplified this to see if I can catch some of my errors.

Currently, when I assemble the code, I get a "00" for every entry when running qemu with -serial: stdio or with -serial tcp::9600,server,nowait connected through tera term, telnet. Any key sent now produces a "30" hex or "0" in ascii. #-o #-o #-o #-o

I have created two files:

boot.fasm:

Code:
; boot.fasm

use16
org 0x7C00

start:
    cli             ; Disable interrupts
    mov ax, 0x07C0  ; Set up the stack
    mov ss, ax
    mov sp, 0x1000
    sti             ; Enable interrupts

    call init_uart  ; Initialize UART for serial communication

    ; Set video mode to 80x25 text mode
    mov ah, 0x00
    mov al, 0x03
    int 0x10

    ; Main loop to echo characters
main_loop:
    call read_byte_from_com1  ; Read a byte from COM1
    call print_char           ; Print the received character
    jmp main_loop             ; Repeat indefinitely

; Include the serial communication routines
include 'com.fasm'

; Print a character to the screen
print_char:
    mov ah, 0x0E   ; BIOS teletype output
    mov bh, 0x00   ; Page number
    mov bl, 0x07   ; Attribute (light grey on black)
    int 0x10       ; Call BIOS
    ret

times 510-($-$$) db 0  ; Pad the bootloader to 510 bytes
dw 0xAA55              ; Boot signature


And com.fasm:

Code:
; com.fasm
use16

PORT equ 0x3F8  ; COM1 Base Port

; Initialize UART for serial communication
init_uart:
    pusha                      ; Save all general-purpose registers

    ; Disable all UART interrupts
    mov dx, PORT + 1           ; Interrupt Enable Register
    mov al, 0x00               ; Disable all interrupts
    out dx, al

    ; Set baud rate to 9600
    mov dx, PORT + 3           ; Line Control Register
    mov al, 0x80               ; Enable DLAB (Divisor Latch Access Bit)
    out dx, al
    mov ax, 0x000C             ; Divisor for 9600 baud rate (12)
    mov dx, PORT               ; Divisor latch low byte
    out dx, al
    mov dx, PORT + 1           ; Divisor latch high byte
    mov al, ah
    out dx, al

    ; Set line control register: 8 bits, no parity, 1 stop bit
    mov dx, PORT + 3
    mov al, 0x03               ; 8 bits, no parity, one stop bit
    out dx, al

    ; Enable FIFO, clear them, with 1-byte threshold (optional, for simplicity)
    ;mov dx, PORT + 2
    ;mov al, 0x01               ; Enable FIFO & set 1-byte threshold
    ;out dx, al

    popa                       ; Restore all general-purpose registers
    ret

; Send a byte to COM1
send_byte_to_com1:
    push ax
    push dx

    mov dx, PORT + 5           ; Line Status Register
wait_for_transmit_empty:
    in al, dx
    test al, 0x20              ; Wait for the transmitter to be empty
    jz wait_for_transmit_empty

    pop dx
    mov dx, PORT
    pop ax
    out dx, al
    ret

; Read a byte from COM1
read_byte_from_com1:
    push ax
    push dx

    mov dx, PORT + 5           ; Line Status Register
wait_for_data_ready:
    in al, dx
    test al, 0x01              ; Check if data is available
    jz wait_for_data_ready

    mov dx, PORT
    in al, dx
    pop dx
    pop ax
    ret


Top
 Profile  
 
 Post subject: Re: x86 QEMU BIOS COM Interrupt supported?
PostPosted: Wed Apr 03, 2024 11:31 am 
Offline

Joined: Wed Jan 10, 2024 9:32 am
Posts: 5
here is the problem, kept saving AX on the read_byte_from_com1... that left AL untouched :oops: #-o

Was pointed out on the FASM forum... :D !
Here is the corrected code:
Code:
; Read a byte from COM1
read_byte_from_com1:
    ; push ax
    push dx

    mov dx, PORT + 5           ; Line Status Register
wait_for_data_ready:
    in al, dx
    test al, 0x01              ; Check if data is available
    jz wait_for_data_ready

    mov dx, PORT
    in al, dx                  ; Read the byte
    ; pop ax
    pop dx
    ret



Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 4 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Majestic-12 [Bot] and 17 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group