我想使用串口
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)
鉴于 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)。