summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorToomas Soome <tsoome@me.com>2020-03-15 22:22:40 +0200
committerToomas Soome <tsoome@me.com>2022-07-03 23:32:39 +0300
commitceb3ef192e9bccf08d1bcd0ae5ed520cecccff3d (patch)
treef24476f4ec6054433d380549e216564e7fc9847c
parent6446bd46ed1b4e9f69da153665f82181ccaedad5 (diff)
downloadillumos-joyent-ceb3ef192e9bccf08d1bcd0ae5ed520cecccff3d.tar.gz
12389 loader should consult with ACPI SPCR table for serial console
Reviewed by: Garrett D'Amore <garrett@damore.org> Approved by: Robert Mustacchi <rm@fingolfin.org>
-rw-r--r--usr/src/boot/Makefile.version2
-rw-r--r--usr/src/boot/i386/gptzfsboot/sio.S19
-rw-r--r--usr/src/boot/i386/gptzfsboot/zfsboot.c36
-rw-r--r--usr/src/boot/i386/libi386/biosacpi.c185
-rw-r--r--usr/src/boot/i386/libi386/comconsole.c43
-rw-r--r--usr/src/boot/i386/libi386/libi386.h1
-rw-r--r--usr/src/boot/i386/loader/main.c6
7 files changed, 230 insertions, 62 deletions
diff --git a/usr/src/boot/Makefile.version b/usr/src/boot/Makefile.version
index ee48155eb7..6ec72af057 100644
--- a/usr/src/boot/Makefile.version
+++ b/usr/src/boot/Makefile.version
@@ -34,4 +34,4 @@ LOADER_VERSION = 1.1
# Use date like formatting here, YYYY.MM.DD.XX, without leading zeroes.
# The version is processed from left to right, the version number can only
# be increased.
-BOOT_VERSION = $(LOADER_VERSION)-2022.05.27.1
+BOOT_VERSION = $(LOADER_VERSION)-2022.06.27.1
diff --git a/usr/src/boot/i386/gptzfsboot/sio.S b/usr/src/boot/i386/gptzfsboot/sio.S
index ca9d0a2406..27c25006b2 100644
--- a/usr/src/boot/i386/gptzfsboot/sio.S
+++ b/usr/src/boot/i386/gptzfsboot/sio.S
@@ -11,13 +11,14 @@
* implied warranties, including, without limitation, the implied
* warranties of merchantability and fitness for a particular
* purpose.
- *
- * $FreeBSD$
*/
- .set SIO_PRT,SIOPRT # Base port
.set SIO_FMT,SIOFMT # 8N1
+/* int sio_port */
+sio_port: .long SIOPRT # Base port
+
+ .globl sio_port
.globl sio_init
.globl sio_flush
.globl sio_putc
@@ -27,13 +28,15 @@
/* int sio_init(int div) */
sio_init: pushl %eax
- movw $SIO_PRT+0x3,%dx # Data format reg
+ movl (sio_port),%edx
+ addl $0x3,%edx # Data format reg
movb $SIO_FMT|0x80,%al # Set format
outb %al,(%dx) # and DLAB
subb $0x3,%dl # Divisor latch reg
popl %eax
outw %ax,(%dx) # BPS
- movw $SIO_PRT+0x3,%dx # Data format reg
+ movl (sio_port),%edx
+ addl $0x3,%edx # Data format reg
movb $SIO_FMT,%al # Clear
outb %al,(%dx) # DLAB
incl %edx # Modem control reg
@@ -55,7 +58,8 @@ sio_flush.2: ret # To caller
/* void sio_putc(int c) */
sio_putc: pushl %eax
- movw $SIO_PRT+0x5,%dx # Line status reg
+ movl (sio_port),%edx
+ addl $0x5,%edx # Line status reg
xor %ecx,%ecx # Timeout
movb $0x40,%ch # counter
sio_putc.1: inb (%dx),%al # Transmitter
@@ -77,7 +81,8 @@ sio_getc.1: subb $0x5,%dl # Receiver buffer reg
/* int sio_ischar(void) */
-sio_ischar: movw $SIO_PRT+0x5,%dx # Line status register
+sio_ischar: movl (sio_port),%edx
+ addl $0x5,%edx # Line status register
xorl %eax,%eax # Zero
inb (%dx),%al # Received data
andb $0x1,%al # ready?
diff --git a/usr/src/boot/i386/gptzfsboot/zfsboot.c b/usr/src/boot/i386/gptzfsboot/zfsboot.c
index 37ab14ccd9..aa2f2ef341 100644
--- a/usr/src/boot/i386/gptzfsboot/zfsboot.c
+++ b/usr/src/boot/i386/gptzfsboot/zfsboot.c
@@ -105,6 +105,7 @@ static const struct string {
};
static const unsigned char dev_maj[NDEV] = {30, 4, 2};
+extern int sio_port;
static struct i386_devdesc *bdev;
static char cmd[512];
@@ -155,6 +156,7 @@ main(void)
bool auto_boot;
bool nextboot = false;
struct disk_devdesc devdesc;
+ char *ptr;
bios_getmem();
@@ -169,6 +171,40 @@ main(void)
setheap(heap_bottom, heap_top);
/*
+ * detect ACPI for future reference. This may set console to comconsole
+ * if we do have ACPI SPCR table.
+ */
+ biosacpi_detect();
+ ptr = getenv("console");
+ if (ptr != NULL && strcmp(ptr, "text") != 0) {
+ char mode[10];
+
+ ioctrl = IO_SERIAL;
+ snprintf(mode, sizeof (mode), "%s-mode", ptr);
+
+ switch (ptr[3]) {
+ case 'a':
+ sio_port = 0x3F8;
+ break;
+ case 'b':
+ sio_port = 0x2F8;
+ break;
+ case 'c':
+ sio_port = 0x3E8;
+ break;
+ case 'd':
+ sio_port = 0x2E8;
+ break;
+ }
+ ptr = getenv(mode);
+ if (ptr != NULL) {
+ comspeed = strtoul(ptr, NULL, 0);
+ if (sio_init(115200 / comspeed) != 0)
+ ioctrl |= IO_KEYBOARD;
+ }
+ }
+
+ /*
* Initialise the block cache. Set the upper limit.
*/
bcache_init(32768, 512);
diff --git a/usr/src/boot/i386/libi386/biosacpi.c b/usr/src/boot/i386/libi386/biosacpi.c
index a82862dd3f..8de99f0c95 100644
--- a/usr/src/boot/i386/libi386/biosacpi.c
+++ b/usr/src/boot/i386/libi386/biosacpi.c
@@ -37,6 +37,7 @@
#define ACPI_SYSTEM_XFACE
#include "actypes.h"
#include "actbl.h"
+#include "actbl3.h"
/*
* Detect ACPI and export information about the ACPI BIOS into the
@@ -49,37 +50,165 @@ static ACPI_TABLE_RSDP *biosacpi_search_rsdp(char *base, int length);
#define RSDP_CHECKSUM_LENGTH 20
+static ACPI_TABLE_SPCR *
+find_spcr(ACPI_TABLE_RSDP *rsdp)
+{
+ unsigned count, i;
+ ACPI_TABLE_XSDT *xsdt;
+ ACPI_TABLE_RSDT *rsdt;
+ void *ptr;
+
+ if (rsdp->Revision >= 2 && rsdp->XsdtPhysicalAddress != 0) {
+ xsdt = (ACPI_TABLE_XSDT *)
+ PTOV((uintptr_t)rsdp->XsdtPhysicalAddress);
+
+ count = xsdt->Header.Length - sizeof (ACPI_TABLE_HEADER);
+ count /= sizeof (xsdt->TableOffsetEntry[0]);
+ for (i = 0; i < count; i++) {
+ ptr = PTOV((uintptr_t)xsdt->TableOffsetEntry[i]);
+ if (memcmp(ptr, ACPI_SIG_SPCR,
+ sizeof (ACPI_SIG_SPCR) - 1) == 0) {
+ return (ptr);
+ }
+ }
+ }
+ if (rsdp->RsdtPhysicalAddress != 0) {
+ rsdt = (ACPI_TABLE_RSDT *)PTOV(rsdp->RsdtPhysicalAddress);
+
+ count = rsdt->Header.Length - sizeof (ACPI_TABLE_HEADER);
+ count /= sizeof (rsdt->TableOffsetEntry[0]);
+ for (i = 0; i < count; i++) {
+ ptr = PTOV(rsdt->TableOffsetEntry[i]);
+ if (memcmp(ptr, ACPI_SIG_SPCR,
+ sizeof (ACPI_SIG_SPCR) - 1) == 0) {
+ return (ptr);
+ }
+ }
+ }
+ return (NULL);
+}
+
+/*
+ * Find and parse SPCR table to set up serial console.
+ */
+static void
+biosacpi_setup_spcr(ACPI_TABLE_SPCR *spcr)
+{
+ unsigned baudrate;
+ const char *port;
+ char *name, *value;
+
+ if (spcr == NULL)
+ return;
+
+ switch (spcr->BaudRate) {
+ case 0:
+ /* Use current port setting. */
+ baudrate = 0;
+ break;
+ case 3:
+ baudrate = 9600;
+ break;
+ case 4:
+ baudrate = 19200;
+ break;
+ case 6:
+ baudrate = 57600;
+ break;
+ case 7:
+ baudrate = 115200;
+ break;
+ default:
+ return;
+ }
+
+ port = NULL;
+ name = NULL;
+ value = NULL;
+
+ switch (spcr->SerialPort.SpaceId) {
+ case ACPI_ADR_SPACE_SYSTEM_IO:
+ if (baudrate == 0)
+ baudrate = comc_getspeed(spcr->SerialPort.Address);
+
+ if (asprintf(&value, "%u,8,N,1,-", baudrate) < 0)
+ return;
+
+ switch (spcr->SerialPort.Address) {
+ case 0x3F8:
+ port = "ttya";
+ break;
+ case 0x2F8:
+ port = "ttyb";
+ break;
+ case 0x3E8:
+ port = "ttyc";
+ break;
+ case 0x2E8:
+ port = "ttyd";
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ /* XXX not implemented. */
+ break;
+ }
+
+ /*
+ * We want to set console according to SPCR. Also
+ * we need to store the SPCR reference value.
+ */
+ if (port != NULL) {
+ if (asprintf(&name, "%s,text", port) > 0) {
+ setenv("console", name, 1);
+ free(name);
+ }
+ if (asprintf(&name, "%s-mode", port) > 0) {
+ setenv(name, value, 1);
+ free(name);
+ }
+ if (asprintf(&name, "%s-spcr-mode", port) > 0) {
+ setenv(name, value, 1);
+ free(name);
+ }
+ }
+ free(value);
+}
+
void
biosacpi_detect(void)
{
- char buf[24];
- int revision;
-
- /* locate and validate the RSDP */
- if ((rsdp = biosacpi_find_rsdp()) == NULL)
- return;
-
- /* export values from the RSDP */
- sprintf(buf, "0x%08x", (unsigned int)VTOP(rsdp));
- setenv("acpi.rsdp", buf, 1);
- revision = rsdp->Revision;
- if (revision == 0)
- revision = 1;
- sprintf(buf, "%d", revision);
- setenv("acpi.revision", buf, 1);
- strncpy(buf, rsdp->OemId, sizeof(rsdp->OemId));
- buf[sizeof(rsdp->OemId)] = '\0';
- setenv("acpi.oem", buf, 1);
- sprintf(buf, "0x%08x", rsdp->RsdtPhysicalAddress);
- setenv("acpi.rsdt", buf, 1);
- if (revision >= 2) {
- /* XXX extended checksum? */
- sprintf(buf, "0x%016llx",
- (unsigned long long)rsdp->XsdtPhysicalAddress);
- setenv("acpi.xsdt", buf, 1);
- sprintf(buf, "%d", rsdp->Length);
- setenv("acpi.xsdt_length", buf, 1);
- }
+ char buf[24];
+ int revision;
+
+ /* locate and validate the RSDP */
+ if ((rsdp = biosacpi_find_rsdp()) == NULL)
+ return;
+
+ /* export values from the RSDP */
+ sprintf(buf, "0x%08x", (unsigned int)VTOP(rsdp));
+ setenv("acpi.rsdp", buf, 1);
+ revision = rsdp->Revision;
+ if (revision == 0)
+ revision = 1;
+ snprintf(buf, sizeof (buf), "%d", revision);
+ setenv("acpi.revision", buf, 1);
+ strncpy(buf, rsdp->OemId, sizeof(rsdp->OemId));
+ buf[sizeof (rsdp->OemId)] = '\0';
+ setenv("acpi.oem", buf, 1);
+ snprintf(buf, sizeof (buf), "0x%08x", rsdp->RsdtPhysicalAddress);
+ setenv("acpi.rsdt", buf, 1);
+ if (revision >= 2) {
+ /* XXX extended checksum? */
+ snprintf(buf, sizeof (buf), "0x%016llx",
+ (unsigned long long)rsdp->XsdtPhysicalAddress);
+ setenv("acpi.xsdt", buf, 1);
+ sprintf(buf, "%d", rsdp->Length);
+ setenv("acpi.xsdt_length", buf, 1);
+ }
+ biosacpi_setup_spcr(find_spcr(rsdp));
}
/*
diff --git a/usr/src/boot/i386/libi386/comconsole.c b/usr/src/boot/i386/libi386/comconsole.c
index 4c351d16bf..1a9e788e88 100644
--- a/usr/src/boot/i386/libi386/comconsole.c
+++ b/usr/src/boot/i386/libi386/comconsole.c
@@ -77,7 +77,7 @@ static void comc_probe(struct console *);
static int comc_init(struct console *, int);
static void comc_putchar(struct console *, int);
static int comc_getchar(struct console *);
-static int comc_getspeed(struct serial *);
+int comc_getspeed(int);
static int comc_ischar(struct console *);
static int comc_ioctl(struct console *, int, void *);
static uint32_t comc_parse_pcidev(const char *);
@@ -164,7 +164,7 @@ comc_probe(struct console *cp)
struct serial *port;
char name[20];
char value[20];
- char *cons, *env;
+ char *env;
if (cp->c_private != NULL)
return;
@@ -190,17 +190,11 @@ comc_probe(struct console *cp)
* Assume that the speed was set by an earlier boot loader if
* comconsole is already the preferred console.
*/
- cons = getenv("console");
- if ((cons != NULL && strcmp(cons, cp->c_name) == 0) ||
- getenv("boot_multicons") != NULL) {
- port->speed = comc_getspeed(port);
- }
-
snprintf(name, sizeof (name), "%s-mode", cp->c_name);
env = getenv(name);
-
if (env != NULL) {
- (void) comc_parse_mode(port, env);
+ /* (void) comc_parse_mode(port, env);*/
+ port->speed = comc_getspeed(port->ioaddr);
}
env = comc_asprint_mode(port);
@@ -422,6 +416,7 @@ static int
comc_mode_set(struct env_var *ev, int flags, const void *value)
{
struct console *cp;
+ char name[15];
if (value == NULL)
return (CMD_ERROR);
@@ -429,12 +424,14 @@ comc_mode_set(struct env_var *ev, int flags, const void *value)
if ((cp = get_console(ev->ev_name)) == NULL)
return (CMD_ERROR);
- if (comc_parse_mode(cp->c_private, value) == CMD_ERROR)
- return (CMD_ERROR);
-
- (void) comc_setup(cp);
-
- env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
+ /* Do not override serial setup from SPCR */
+ snprintf(name, sizeof (name), "%s-spcr-mode", cp->c_name);
+ if (getenv(name) == NULL) {
+ if (comc_parse_mode(cp->c_private, value) == CMD_ERROR)
+ return (CMD_ERROR);
+ (void) comc_setup(cp);
+ env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
+ }
return (CMD_OK);
}
@@ -635,21 +632,21 @@ comc_setup(struct console *cp)
return (true);
}
-static int
-comc_getspeed(struct serial *sp)
+int
+comc_getspeed(int ioaddr)
{
uint_t divisor;
uchar_t dlbh;
uchar_t dlbl;
uchar_t cfcr;
- cfcr = inb(sp->ioaddr + com_cfcr);
- outb(sp->ioaddr + com_cfcr, CFCR_DLAB | cfcr);
+ cfcr = inb(ioaddr + com_cfcr);
+ outb(ioaddr + com_cfcr, CFCR_DLAB | cfcr);
- dlbl = inb(sp->ioaddr + com_dlbl);
- dlbh = inb(sp->ioaddr + com_dlbh);
+ dlbl = inb(ioaddr + com_dlbl);
+ dlbh = inb(ioaddr + com_dlbh);
- outb(sp->ioaddr + com_cfcr, cfcr);
+ outb(ioaddr + com_cfcr, cfcr);
divisor = dlbh << 8 | dlbl;
diff --git a/usr/src/boot/i386/libi386/libi386.h b/usr/src/boot/i386/libi386/libi386.h
index 3f769ee688..866a6590b8 100644
--- a/usr/src/boot/i386/libi386/libi386.h
+++ b/usr/src/boot/i386/libi386/libi386.h
@@ -130,6 +130,7 @@ uint32_t biospci_locator(int8_t bus, uint8_t device, uint8_t function);
int biospci_write_config(uint32_t locator, int offset, int width, uint32_t val);
void biosacpi_detect(void);
+int comc_getspeed(int);
int i386_autoload(void);
vm_offset_t i386_loadaddr(u_int type, void *data, vm_offset_t addr);
diff --git a/usr/src/boot/i386/loader/main.c b/usr/src/boot/i386/loader/main.c
index dc21e0d2b3..8fba0e1a04 100644
--- a/usr/src/boot/i386/loader/main.c
+++ b/usr/src/boot/i386/loader/main.c
@@ -115,6 +115,9 @@ main(void)
}
setheap(heap_bottom, heap_top);
+ /* detect ACPI for future reference */
+ biosacpi_detect();
+
/*
* XXX Chicken-and-egg problem; we want to have console output early,
* but some console attributes may depend on reading from eg. the boot
@@ -182,9 +185,6 @@ main(void)
initial_bootinfo->bi_extmem = bios_extmem / 1024;
}
- /* detect ACPI for future reference */
- biosacpi_detect();
-
/* detect SMBIOS for future reference */
smbios_detect(NULL);