使用x86组件初始化串口

问题描述 投票:0回答:1

我想使用串口

COM1
而不使用BIOS中断14h,为此我遵循osdev的教程,但在初始化过程中遇到了一些问题。 (我对 asm 和 BIOS 相关的东西还很陌生,所以我的代码可能非常错误,或者可能需要在初始化串行端口之前初始化其他东西)

我当前的代码如下所示,应该是他们的 C 代码的直接翻译。

%macro outb 2
    mov dx, %1
    mov al, %2
    out dx, al
%endmacro

%macro inb 1
    mov dx, %1
    in al, dx
%endmacro

    bits 16
    org 0x7c00 ;; set the origin at the start of the bootloader address space

    xor ax, ax
    mov dx, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

serial_init:
    outb [com1+1], 0x00 ;; disable all interrupts
    outb [com1+3], 0x80 ;; enable DLAB (set baud rate divisor)
    outb [com1+0], 0x03 ;; Set divisor to 3 (lo byte) 38440 baud
    outb [com1+1], 0x00 ;;                  (hi byte)
    outb [com1+3], 0x03 ;; 8 bits, no parity, one stop bit
    outb [com1+2], 0xc7 ;; enable fifo, clear them, with 14-byte threshold
    outb [com1+4], 0x0b ;; IRQs enabled, RTS/DSR set
    outb [com1+4], 0x1e ;; set in loopback mode, test the serial chip
    outb [com1+0], 0xae ;; test serial chip

hang:
    jmp hang

com1:
    dw 0x3f8

    times 510-($-$$) db 0
    dw 0xaa55

我有一些调试原语和一切,似乎进展顺利,直到行

outb [com1+0], 0x03
之后,如果我读取行控制寄存器
[com1+5]
我得到一个错误,但我不知道如何解释它(它似乎是与停止位相关的错误,错误 3)

assembly serial-port nasm x86-16 bios
1个回答
3
投票

鉴于 outb 宏定义,NASM 会将您的

outb [com1+1], 0x00
宏调用扩展为:

mov dx, [com1+1]
mov al, 0x00
out dx, al

由于方括号的存在,第一条指令将从内存中加载

DX
,遗憾的是它不包含预期的端口地址(0x03F9)!您得到的是 0x0003,由存储在 com1 的字的高字节和内存中由于
times
零填充而恰好为 0 的下一个字节组成。

为你辩护,维基文章https://wiki.osdev.org/Serial_Ports在说你应该将数据发送到例如

[PORT + 1]
。然而,这些括号与汇编编程语言中使用的相同括号无关。

C代码片段更清晰。它有

define PORT 0x3f8
,组装后变成
PORT equ 0x03F8
。并且
outb(PORT + 1, 0x00)
指令在汇编中变成了
outb PORT + 1, 0x00
。这次 NASM 会将您的 outb 宏扩展为以下 3 条指令:

mov  dx, PORT + 1    ; Same as `mov dx, 0x03F9`
mov  al, 0x00
out  dx, al

给出供参考的C代码:

#define PORT 0x3f8          // COM1
 
static int init_serial() {
   outb(PORT + 1, 0x00);    // Disable all interrupts
   outb(PORT + 3, 0x80);    // Enable DLAB (set baud rate divisor)
   outb(PORT + 0, 0x03);    // Set divisor to 3 (lo byte) 38400 baud
   outb(PORT + 1, 0x00);    //                  (hi byte)
   outb(PORT + 3, 0x03);    // 8 bits, no parity, one stop bit
   outb(PORT + 2, 0xC7);    // Enable FIFO, clear them, with 14-byte threshold
   outb(PORT + 4, 0x0B);    // IRQs enabled, RTS/DSR set
   outb(PORT + 4, 0x1E);    // Set in loopback mode, test the serial chip
   outb(PORT + 0, 0xAE);    // Test serial chip (send byte 0xAE and check if serial returns same byte)
 
   // Check if serial is faulty (i.e: not same byte as sent)
   if(inb(PORT + 0) != 0xAE) {
      return 1;
   }
 
   // If serial is not faulty set it in normal operation mode
   // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled)
   outb(PORT + 4, 0x0F);
   return 0;
}

如果我读取线路控制寄存器

[com1+5]
...

准确性将是对该硬件进行编程的关键。对于一般编程来说也是如此。
线路控制寄存器 (LCR) 位于 03FB (PORT + 3)。
线路状态寄存器 (LSR) 位于 03FD (PORT + 5)。

© www.soinside.com 2019 - 2024. All rights reserved.