使用 x86 程序集初始化串口
Initialize serial port with x86 assembly
我想在不使用 BIOS 中断 14h 的情况下使用串行端口 COM1
,为此我正在按照 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 的下一个字节组成。
在你的辩护中,wiki 文章 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;
}
if I read the line control register [com1+5]
...
准确性将是对该硬件进行编程的关键。对于一般的编程来说也是如此。
线路控制寄存器 (LCR) 位于 03FB (PORT + 3)。
线路状态寄存器 (LSR) 位于 03FD (PORT + 5)。
我想在不使用 BIOS 中断 14h 的情况下使用串行端口 COM1
,为此我正在按照 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 的下一个字节组成。
在你的辩护中,wiki 文章 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;
}
if I read the line control register
[com1+5]
...
准确性将是对该硬件进行编程的关键。对于一般的编程来说也是如此。
线路控制寄存器 (LCR) 位于 03FB (PORT + 3)。
线路状态寄存器 (LSR) 位于 03FD (PORT + 5)。