mirror of
https://github.com/ipxe/ipxe
synced 2026-04-16 03:00:10 +03:00
[uart] Allow for the existence of non-16550 UARTs
Remove the assumption that all platforms use a fixed number of 16550 UARTs identifiable by a simple numeric index. Create an abstraction allowing for dynamic instantiation and registration of any number of arbitrary UART models. The common case of the serial console on x86 uses a single fixed UART specified at compile time. Avoid unnecessarily dragging in the dynamic instantiation code in this use case by allowing COMCONSOLE to refer to a single static UART object representing the relevant port. When selecting a UART by command-line argument (as used in the "gdbstub serial <port>" command), allow the UART to be specified as either a numeric index (to retain backwards compatiblity) or a case-insensitive port name such as "COM2". Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
* Copyright (C) 2025 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
@@ -29,41 +29,45 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <ipxe/uart.h>
|
||||
#include <string.h>
|
||||
#include <ipxe/serial.h>
|
||||
#include <ipxe/ns16550.h>
|
||||
|
||||
/** UART port bases */
|
||||
static uint16_t uart_base[] = {
|
||||
[COM1] = 0x3f8,
|
||||
[COM2] = 0x2f8,
|
||||
[COM3] = 0x3e8,
|
||||
[COM4] = 0x2e8,
|
||||
};
|
||||
/** Define a fixed ISA UART */
|
||||
#define ISA_UART( NAME, BASE ) \
|
||||
struct ns16550_uart NAME = { \
|
||||
.uart = { \
|
||||
.refcnt = REF_INIT ( ref_no_free ), \
|
||||
.name = #NAME, \
|
||||
.op = &ns16550_operations, \
|
||||
}, \
|
||||
.base = ( ( void * ) (BASE) ), \
|
||||
}
|
||||
|
||||
/* Fixed ISA UARTs */
|
||||
ISA_UART ( com1, COM1_BASE );
|
||||
ISA_UART ( com2, COM2_BASE );
|
||||
ISA_UART ( com3, COM3_BASE );
|
||||
ISA_UART ( com4, COM4_BASE );
|
||||
|
||||
/**
|
||||
* Select UART port
|
||||
* Register fixed ISA UARTs
|
||||
*
|
||||
* @v uart UART
|
||||
* @v port Port number, or 0 to disable
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int uart_select ( struct uart *uart, unsigned int port ) {
|
||||
int uart_register_fixed ( void ) {
|
||||
static struct uart *ports[] = { COM1, COM2, COM3, COM4 };
|
||||
unsigned int i;
|
||||
int rc;
|
||||
|
||||
/* Set new UART base */
|
||||
if ( port >= ( sizeof ( uart_base ) / sizeof ( uart_base[0] ) ) ) {
|
||||
rc = -ENODEV;
|
||||
goto err;
|
||||
/* Register all fixed ISA UARTs */
|
||||
for ( i = 0 ; i < ( sizeof ( ports ) / sizeof ( ports[0] ) ) ; i++ ) {
|
||||
if ( ( rc = uart_register ( ports[i] ) ) != 0 ) {
|
||||
DBGC ( ports[i], "UART could not register %s: %s\n",
|
||||
ports[i]->name, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
uart->base = ( ( void * ) ( intptr_t ) uart_base[port] );
|
||||
|
||||
/* Check that UART exists */
|
||||
if ( ( rc = uart_exists ( uart ) ) != 0 )
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
uart->base = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
#ifndef _BITS_NS16550_H
|
||||
#define _BITS_NS16550_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* 16550-compatible UART
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ipxe/io.h>
|
||||
|
||||
/**
|
||||
* Write to UART register
|
||||
*
|
||||
* @v ns16550 16550 UART
|
||||
* @v address Register address
|
||||
* @v data Data
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
ns16550_write ( struct ns16550_uart *ns16550, unsigned int address,
|
||||
uint8_t data ) {
|
||||
|
||||
outb ( data, ( ns16550->base + address ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read from UART register
|
||||
*
|
||||
* @v ns16550 16550 UART
|
||||
* @v address Register address
|
||||
* @ret data Data
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) uint8_t
|
||||
ns16550_read ( struct ns16550_uart *ns16550, unsigned int address ) {
|
||||
|
||||
return inb ( ns16550->base + address );
|
||||
}
|
||||
|
||||
/* Fixed ISA serial port base addresses */
|
||||
#define COM1_BASE 0x3f8
|
||||
#define COM2_BASE 0x2f8
|
||||
#define COM3_BASE 0x3e8
|
||||
#define COM4_BASE 0x2e8
|
||||
|
||||
/* Fixed ISA serial ports */
|
||||
extern struct ns16550_uart com1;
|
||||
extern struct ns16550_uart com2;
|
||||
extern struct ns16550_uart com3;
|
||||
extern struct ns16550_uart com4;
|
||||
|
||||
/* Fixed ISA serial port names */
|
||||
#define COM1 &com1.uart
|
||||
#define COM2 &com2.uart
|
||||
#define COM3 &com3.uart
|
||||
#define COM4 &com4.uart
|
||||
|
||||
#endif /* _BITS_NS16550_H */
|
||||
@@ -1,41 +0,0 @@
|
||||
#ifndef _BITS_UART_H
|
||||
#define _BITS_UART_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* 16550-compatible UART
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ipxe/io.h>
|
||||
|
||||
/**
|
||||
* Write to UART register
|
||||
*
|
||||
* @v uart UART
|
||||
* @v addr Register address
|
||||
* @v data Data
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
uart_write ( struct uart *uart, unsigned int addr, uint8_t data ) {
|
||||
outb ( data, ( uart->base + addr ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read from UART register
|
||||
*
|
||||
* @v uart UART
|
||||
* @v addr Register address
|
||||
* @ret data Data
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) uint8_t
|
||||
uart_read ( struct uart *uart, unsigned int addr ) {
|
||||
return inb ( uart->base + addr );
|
||||
}
|
||||
|
||||
extern int uart_select ( struct uart *uart, unsigned int port );
|
||||
|
||||
#endif /* _BITS_UART_H */
|
||||
@@ -37,6 +37,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#include <ipxe/posix_io.h>
|
||||
#include <ipxe/process.h>
|
||||
#include <ipxe/serial.h>
|
||||
#include <ipxe/ns16550.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/version.h>
|
||||
@@ -253,8 +254,8 @@ static __asmcall __used void int21 ( struct i386_all_regs *ix86 ) {
|
||||
break;
|
||||
|
||||
case 0x04: /* Write Character to Serial Port */
|
||||
if ( serial_console.base ) {
|
||||
uart_transmit ( &serial_console, ix86->regs.dl );
|
||||
if ( serial_console ) {
|
||||
uart_transmit ( serial_console, ix86->regs.dl );
|
||||
ix86->flags &= ~CF;
|
||||
}
|
||||
break;
|
||||
@@ -445,9 +446,13 @@ static __asmcall __used void int22 ( struct i386_all_regs *ix86 ) {
|
||||
break;
|
||||
|
||||
case 0x000B: /* Get Serial Console Configuration */
|
||||
if ( serial_console.base ) {
|
||||
ix86->regs.dx = ( ( intptr_t ) serial_console.base );
|
||||
ix86->regs.cx = serial_console.divisor;
|
||||
if ( serial_console ) {
|
||||
struct ns16550_uart *comport =
|
||||
container_of ( serial_console,
|
||||
struct ns16550_uart, uart );
|
||||
|
||||
ix86->regs.dx = ( ( intptr_t ) comport->base );
|
||||
ix86->regs.cx = comport->divisor;
|
||||
ix86->regs.bx = 0;
|
||||
ix86->flags &= ~CF;
|
||||
}
|
||||
@@ -685,4 +690,4 @@ void unhook_comboot_interrupts ( ) {
|
||||
}
|
||||
|
||||
/* Avoid dragging in serial console support unconditionally */
|
||||
struct uart serial_console __attribute__ (( weak ));
|
||||
struct uart *serial_console __attribute__ (( weak ));
|
||||
|
||||
Reference in New Issue
Block a user