diff options
author | Toomas Soome <tsoome@me.com> | 2020-03-15 22:22:40 +0200 |
---|---|---|
committer | Toomas Soome <tsoome@me.com> | 2022-07-03 23:32:39 +0300 |
commit | ceb3ef192e9bccf08d1bcd0ae5ed520cecccff3d (patch) | |
tree | f24476f4ec6054433d380549e216564e7fc9847c | |
parent | 6446bd46ed1b4e9f69da153665f82181ccaedad5 (diff) | |
download | illumos-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.version | 2 | ||||
-rw-r--r-- | usr/src/boot/i386/gptzfsboot/sio.S | 19 | ||||
-rw-r--r-- | usr/src/boot/i386/gptzfsboot/zfsboot.c | 36 | ||||
-rw-r--r-- | usr/src/boot/i386/libi386/biosacpi.c | 185 | ||||
-rw-r--r-- | usr/src/boot/i386/libi386/comconsole.c | 43 | ||||
-rw-r--r-- | usr/src/boot/i386/libi386/libi386.h | 1 | ||||
-rw-r--r-- | usr/src/boot/i386/loader/main.c | 6 |
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); |