pull/107/merge
Faidon Liambotis 2025-04-05 17:37:45 +11:00 committed by GitHub
commit 655358198f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 186 additions and 59 deletions

View File

@ -5,27 +5,21 @@
*
* Serial port configuration
*
* These options affect the operation of the serial console. They
* take effect only if the serial console is included using the
* CONSOLE_SERIAL option.
* These options affect the operation of the serial console. They take effect
* only if the serial console is included using the CONSOLE_SERIAL option.
* These settings only the default settings, and can all be set (or overriden)
* at runtime.
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#define COMCONSOLE COM1 /* I/O port address */
/* Keep settings from a previous user of the serial port (e.g. lilo or
* LinuxBIOS), ignoring COMSPEED, COMDATA, COMPARITY and COMSTOP.
*/
#undef COMPRESERVE
#ifndef COMPRESERVE
#define COMSPEED 115200 /* Baud rate */
#define COMDATA 8 /* Data bits */
#define COMPARITY 0 /* Parity: 0=None, 1=Odd, 2=Even */
#define COMSTOP 1 /* Stop bits */
#endif
//#define COMCONSOLE COM1 /* I/O port address */
#define COMPRESERVE 0 /* Preserve settings by another bootloader */
#define COMSPEED 115200 /* Baud rate */
#define COMDATA 8 /* Data bits */
#define COMPARITY 0 /* Parity: 0=None, 1=Odd, 2=Even */
#define COMSTOP 1 /* Stop bits */
#include <config/named.h>
#include NAMED_CONFIG(serial.h)

View File

@ -30,8 +30,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ipxe/init.h>
#include <ipxe/dhcp.h>
#include <ipxe/settings.h>
#include <ipxe/uart.h>
#include <ipxe/console.h>
#include <ipxe/serial.h>
@ -51,20 +55,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define CONSOLE_PORT 0
#endif
/* UART baud rate */
#ifdef COMPRESERVE
#define CONSOLE_BAUD 0
#else
#define CONSOLE_BAUD COMSPEED
#endif
/* UART line control register value */
#ifdef COMPRESERVE
#define CONSOLE_LCR 0
#else
#define CONSOLE_LCR UART_LCR_WPS ( COMDATA, COMPARITY, COMSTOP )
#endif
/** Serial console UART */
struct uart serial_console;
@ -133,30 +123,6 @@ struct console_driver serial_console_driver __console_driver = {
.usage = CONSOLE_SERIAL,
};
/** Initialise serial console */
static void serial_init ( void ) {
int rc;
/* Do nothing if we have no default port */
if ( ! CONSOLE_PORT )
return;
/* Select UART */
if ( ( rc = uart_select ( &serial_console, CONSOLE_PORT ) ) != 0 ) {
DBG ( "Could not select UART %d: %s\n",
CONSOLE_PORT, strerror ( rc ) );
return;
}
/* Initialise UART */
if ( ( rc = uart_init ( &serial_console, CONSOLE_BAUD,
CONSOLE_LCR ) ) != 0 ) {
DBG ( "Could not initialise UART %d baud %d LCR %#02x: %s\n",
CONSOLE_PORT, CONSOLE_BAUD, CONSOLE_LCR, strerror ( rc ));
return;
}
}
/**
* Shut down serial console
*
@ -174,13 +140,175 @@ static void serial_shutdown ( int flags __unused ) {
/* Leave console enabled; it's still usable */
}
/** Serial console initialisation function */
struct init_fn serial_console_init_fn __init_fn ( INIT_CONSOLE ) = {
.initialise = serial_init,
};
/** Serial console startup function */
struct startup_fn serial_startup_fn __startup_fn ( STARTUP_EARLY ) = {
.name = "serial",
.shutdown = serial_shutdown,
};
/** Serial console port setting */
const struct setting serial_port_setting __setting ( SETTING_MISC, serial-port ) = {
.name = "serial-port",
.description = "Serial port",
.tag = DHCP_EB_SERIAL_PORT,
.type = &setting_type_uint8,
};
const struct setting serial_options_setting __setting ( SETTING_MISC, serial-options ) = {
.name = "serial-options",
.description = "Serial port options",
.tag = DHCP_EB_SERIAL_OPTIONS,
.type = &setting_type_string,
};
/**
* Parse a string with options in the format of BBBBPDS where:
* - BBBB is the baud rate
* - P is parity ("n" for none, "o" for odd, "e" for even)
* - D is data bits
* - S is stop bits
*
* @c rc Return status code
* @v baud Pointer to an integer for baud rate
* @v lcr Pointer to an integer for the line control register
*/
static int serial_parse_options ( const char *options,
uint32_t *baud, uint8_t *lcr ) {
int rc = 0;
char *endp;
uint32_t speed;
uint8_t data, parity, stop, preserve;
/* Initialise to default values; any of these can be overriden later */
speed = COMSPEED;
data = COMDATA;
parity = COMPARITY;
stop = COMSTOP;
preserve = COMPRESERVE;
if ( !options || strlen ( options ) == 0 )
goto out;
if ( strcmp ( options, "preserve" ) == 0 ) {
preserve = 1;
goto out;
}
speed = strtoul( options, &endp, 10 );
/* No baud rate found */
if ( endp == options ) {
rc = -EINVAL;
goto out;
}
/* Next character is parity */
if ( *endp ) {
switch( *endp++ ) {
case 'n':
parity = 0;
break;
case 'o':
parity = 1;
break;
case 'e':
parity = 3;
break;
default:
rc = -EINVAL;
goto out;
}
}
/* Data & stop bits follow, single numbers in ASCII */
if ( *endp )
data = *endp++ - '0';
if ( *endp )
stop = *endp++ - '0';
out:
if ( !preserve ) {
/* UART line control register */
*baud = speed;
*lcr = UART_LCR_WPS ( data, parity, stop );
} else {
/* Preserve the settings set by e.g. a previous bootloader */
*baud = 0;
*lcr = 0;
}
return rc;
}
/**
* Apply serial console settings
*
* @ret rc Return status code
*/
static int apply_serial_settings ( void ) {
int rc = 0;
char *options;
unsigned long port;
uint32_t baud;
uint8_t lcr;
static unsigned long old_port;
static uint32_t old_baud;
static uint8_t old_lcr;
if ( fetch_uint_setting ( NULL, &serial_port_setting, &port ) < 0 )
port = CONSOLE_PORT;
fetch_string_setting_copy ( NULL, &serial_options_setting, &options );
if ( ( rc = serial_parse_options ( options, &baud, &lcr ) ) != 0 ) {
goto err_parse_options;
}
/* Avoid reconfiguring the port if no changes are being made */
if ( port == old_port && baud == old_baud && lcr == old_lcr )
goto out_no_change;
/* Flush the old port, if configured */
if ( serial_console.base )
uart_flush ( &serial_console );
/* Disable port if we are not about to configure a new one */
if ( ! port ) {
serial_console.base = NULL;
goto out_no_port;
}
/* Select UART */
if ( ( rc = uart_select ( &serial_console, port ) ) != 0 ) {
DBG ( "Could not select UART %ld: %s\n", port, strerror ( rc ) );
goto err_port_select;
}
/* Initialise UART */
if ( ( rc = uart_init ( &serial_console, baud, lcr ) ) != 0 ) {
DBG ( "Could not initialise UART %ld baud %u LCR %#02x: %s\n",
port, baud, lcr, strerror ( rc ));
goto err_port_init;
}
DBG ( "Serial config using port %ld\n", port );
/* Record settings */
old_port = port;
old_baud = baud;
old_lcr = lcr;
/* Success */
rc = 0;
err_parse_options:
err_port_select:
err_port_init:
out_no_port:
out_no_change:
free ( options );
return rc;
}
/** Serial console port settings applicator */
struct settings_applicator serial_port_applicator __settings_applicator = {
.apply = apply_serial_settings,
};

View File

@ -422,6 +422,10 @@ struct dhcp_client_uuid {
/** Cross-signed certificate source */
#define DHCP_EB_CROSS_CERT DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x5d )
/** Serial port configuration */
#define DHCP_EB_SERIAL_PORT DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x60 )
#define DHCP_EB_SERIAL_OPTIONS DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x61 )
/** Skip PXE DHCP protocol extensions such as ProxyDHCP
*
* If set to a non-zero value, iPXE will not wait for ProxyDHCP offers

View File

@ -109,6 +109,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define ERRFILE_spi_bit ( ERRFILE_DRIVER | 0x00130000 )
#define ERRFILE_nvsvpd ( ERRFILE_DRIVER | 0x00140000 )
#define ERRFILE_uart ( ERRFILE_DRIVER | 0x00150000 )
#define ERRFILE_serial ( ERRFILE_DRIVER | 0x00160000 )
#define ERRFILE_3c509 ( ERRFILE_DRIVER | 0x00200000 )
#define ERRFILE_bnx2 ( ERRFILE_DRIVER | 0x00210000 )