16112cec5SJoshua M. Clulow /*
26112cec5SJoshua M. Clulow * This file and its contents are supplied under the terms of the
36112cec5SJoshua M. Clulow * Common Development and Distribution License ("CDDL"), version 1.0.
46112cec5SJoshua M. Clulow * You may only use this file in accordance with the terms of version
56112cec5SJoshua M. Clulow * 1.0 of the CDDL.
66112cec5SJoshua M. Clulow *
76112cec5SJoshua M. Clulow * A full copy of the text of the CDDL should have accompanied this
86112cec5SJoshua M. Clulow * source. A copy of the CDDL is also available via the Internet at
96112cec5SJoshua M. Clulow * http://www.illumos.org/license/CDDL.
106112cec5SJoshua M. Clulow */
116112cec5SJoshua M. Clulow
126112cec5SJoshua M. Clulow /*
13*b210e777SJoshua M. Clulow * Copyright 2023 Oxide Computer Company
146112cec5SJoshua M. Clulow */
156112cec5SJoshua M. Clulow
166112cec5SJoshua M. Clulow #ifdef _KERNEL
176112cec5SJoshua M. Clulow #include <sys/types.h>
186112cec5SJoshua M. Clulow #include <sys/sunddi.h>
196112cec5SJoshua M. Clulow #else
206112cec5SJoshua M. Clulow #include <stdio.h>
216112cec5SJoshua M. Clulow #include <stdlib.h>
226112cec5SJoshua M. Clulow #include <strings.h>
236112cec5SJoshua M. Clulow #include <sys/utsname.h>
246112cec5SJoshua M. Clulow #include <sys/systeminfo.h>
256112cec5SJoshua M. Clulow #endif
266112cec5SJoshua M. Clulow #include <sys/debug.h>
27*b210e777SJoshua M. Clulow #include <sys/ilstr.h>
286112cec5SJoshua M. Clulow
296112cec5SJoshua M. Clulow /*
306112cec5SJoshua M. Clulow * Rendering of the boot banner, used on the system and zone consoles.
316112cec5SJoshua M. Clulow */
326112cec5SJoshua M. Clulow
336112cec5SJoshua M. Clulow /*
346112cec5SJoshua M. Clulow * Expand a boot banner template string. The following expansion tokens
356112cec5SJoshua M. Clulow * are supported:
366112cec5SJoshua M. Clulow *
376112cec5SJoshua M. Clulow * ^^ a literal caret
386112cec5SJoshua M. Clulow * ^s the base kernel name (utsname.sysname)
396112cec5SJoshua M. Clulow * ^o the operating system name ("illumos")
406112cec5SJoshua M. Clulow * ^v the operating system version (utsname.version)
416112cec5SJoshua M. Clulow * ^r the operating system release (utsname.release)
426112cec5SJoshua M. Clulow * ^w the native address width in bits (e.g., "32" or "64")
436112cec5SJoshua M. Clulow */
446112cec5SJoshua M. Clulow static void
bootbanner_expand_template(const char * input,ilstr_t * output)456112cec5SJoshua M. Clulow bootbanner_expand_template(const char *input, ilstr_t *output)
466112cec5SJoshua M. Clulow {
476112cec5SJoshua M. Clulow size_t pos = 0;
486112cec5SJoshua M. Clulow enum {
496112cec5SJoshua M. Clulow ST_REST,
506112cec5SJoshua M. Clulow ST_CARET,
516112cec5SJoshua M. Clulow } state = ST_REST;
526112cec5SJoshua M. Clulow
536112cec5SJoshua M. Clulow #ifndef _KERNEL
546112cec5SJoshua M. Clulow struct utsname utsname;
556112cec5SJoshua M. Clulow bzero(&utsname, sizeof (utsname));
566112cec5SJoshua M. Clulow (void) uname(&utsname);
576112cec5SJoshua M. Clulow #endif
586112cec5SJoshua M. Clulow
596112cec5SJoshua M. Clulow for (;;) {
606112cec5SJoshua M. Clulow char c = input[pos];
616112cec5SJoshua M. Clulow
626112cec5SJoshua M. Clulow if (c == '\0') {
636112cec5SJoshua M. Clulow /*
646112cec5SJoshua M. Clulow * Even if the template came to an end mid way through
656112cec5SJoshua M. Clulow * a caret expansion, it seems best to just print what
666112cec5SJoshua M. Clulow * we have and drive on. The onus will be on the
676112cec5SJoshua M. Clulow * distributor to ensure their templates are
686112cec5SJoshua M. Clulow * well-formed at build time.
696112cec5SJoshua M. Clulow */
706112cec5SJoshua M. Clulow break;
716112cec5SJoshua M. Clulow }
726112cec5SJoshua M. Clulow
736112cec5SJoshua M. Clulow switch (state) {
746112cec5SJoshua M. Clulow case ST_REST:
756112cec5SJoshua M. Clulow if (c == '^') {
766112cec5SJoshua M. Clulow state = ST_CARET;
776112cec5SJoshua M. Clulow } else {
786112cec5SJoshua M. Clulow ilstr_append_char(output, c);
796112cec5SJoshua M. Clulow }
806112cec5SJoshua M. Clulow pos++;
816112cec5SJoshua M. Clulow continue;
826112cec5SJoshua M. Clulow
836112cec5SJoshua M. Clulow case ST_CARET:
846112cec5SJoshua M. Clulow if (c == '^') {
856112cec5SJoshua M. Clulow ilstr_append_char(output, c);
866112cec5SJoshua M. Clulow } else if (c == 's') {
876112cec5SJoshua M. Clulow ilstr_append_str(output, utsname.sysname);
886112cec5SJoshua M. Clulow } else if (c == 'o') {
896112cec5SJoshua M. Clulow ilstr_append_str(output, "illumos");
906112cec5SJoshua M. Clulow } else if (c == 'r') {
916112cec5SJoshua M. Clulow ilstr_append_str(output, utsname.release);
926112cec5SJoshua M. Clulow } else if (c == 'v') {
936112cec5SJoshua M. Clulow ilstr_append_str(output, utsname.version);
946112cec5SJoshua M. Clulow } else if (c == 'w') {
956112cec5SJoshua M. Clulow #ifdef _KERNEL
96*b210e777SJoshua M. Clulow ilstr_aprintf(output, "%u",
976112cec5SJoshua M. Clulow NBBY * (uint_t)sizeof (void *));
986112cec5SJoshua M. Clulow #else
996112cec5SJoshua M. Clulow char *bits;
1006112cec5SJoshua M. Clulow char buf[32];
1016112cec5SJoshua M. Clulow int r;
1026112cec5SJoshua M. Clulow
1036112cec5SJoshua M. Clulow if ((r = sysinfo(SI_ADDRESS_WIDTH, buf,
1046112cec5SJoshua M. Clulow sizeof (buf))) > 0 &&
1056112cec5SJoshua M. Clulow r < (int)sizeof (buf)) {
1066112cec5SJoshua M. Clulow bits = buf;
1076112cec5SJoshua M. Clulow } else {
1086112cec5SJoshua M. Clulow bits = "64";
1096112cec5SJoshua M. Clulow }
1106112cec5SJoshua M. Clulow
1116112cec5SJoshua M. Clulow ilstr_append_str(output, bits);
1126112cec5SJoshua M. Clulow #endif
1136112cec5SJoshua M. Clulow } else {
1146112cec5SJoshua M. Clulow /*
1156112cec5SJoshua M. Clulow * Try to make it obvious what went wrong:
1166112cec5SJoshua M. Clulow */
1176112cec5SJoshua M. Clulow ilstr_append_str(output, "!^");
1186112cec5SJoshua M. Clulow ilstr_append_char(output, c);
1196112cec5SJoshua M. Clulow ilstr_append_str(output, " UNKNOWN!");
1206112cec5SJoshua M. Clulow }
1216112cec5SJoshua M. Clulow state = ST_REST;
1226112cec5SJoshua M. Clulow pos++;
1236112cec5SJoshua M. Clulow continue;
1246112cec5SJoshua M. Clulow }
1256112cec5SJoshua M. Clulow }
1266112cec5SJoshua M. Clulow }
1276112cec5SJoshua M. Clulow
1286112cec5SJoshua M. Clulow static void
bootbanner_print_one(ilstr_t * s,void (* printfunc)(const char *,uint_t),const char * template,uint_t * nump)1296112cec5SJoshua M. Clulow bootbanner_print_one(ilstr_t *s, void (*printfunc)(const char *, uint_t),
1306112cec5SJoshua M. Clulow const char *template, uint_t *nump)
1316112cec5SJoshua M. Clulow {
1326112cec5SJoshua M. Clulow ilstr_reset(s);
1336112cec5SJoshua M. Clulow
1346112cec5SJoshua M. Clulow bootbanner_expand_template(template, s);
1356112cec5SJoshua M. Clulow
1366112cec5SJoshua M. Clulow if (ilstr_errno(s) == ILSTR_ERROR_OK) {
1376112cec5SJoshua M. Clulow if (ilstr_len(s) > 0) {
1386112cec5SJoshua M. Clulow printfunc(ilstr_cstr(s), *nump);
1396112cec5SJoshua M. Clulow *nump += 1;
1406112cec5SJoshua M. Clulow }
1416112cec5SJoshua M. Clulow } else {
1426112cec5SJoshua M. Clulow char ebuf[128];
1436112cec5SJoshua M. Clulow
1446112cec5SJoshua M. Clulow snprintf(ebuf, sizeof (ebuf), "boot banner error: %s",
1456112cec5SJoshua M. Clulow ilstr_errstr(s));
1466112cec5SJoshua M. Clulow
1476112cec5SJoshua M. Clulow printfunc(ebuf, *nump);
1486112cec5SJoshua M. Clulow *nump += 1;
1496112cec5SJoshua M. Clulow }
1506112cec5SJoshua M. Clulow }
1516112cec5SJoshua M. Clulow
1526112cec5SJoshua M. Clulow /*
1536112cec5SJoshua M. Clulow * This routine should be called during early system boot to render the boot
1546112cec5SJoshua M. Clulow * banner on the system console, and during zone boot to do so on the zone
1556112cec5SJoshua M. Clulow * console.
1566112cec5SJoshua M. Clulow *
1576112cec5SJoshua M. Clulow * The "printfunc" argument is a callback function. When passed a string, the
1586112cec5SJoshua M. Clulow * function must print it in a fashion appropriate for the context. The
1596112cec5SJoshua M. Clulow * callback will only be called while within the call to bootbanner_print().
1606112cec5SJoshua M. Clulow */
1616112cec5SJoshua M. Clulow void
bootbanner_print(void (* printfunc)(const char *,uint_t))162*b210e777SJoshua M. Clulow bootbanner_print(void (*printfunc)(const char *, uint_t))
1636112cec5SJoshua M. Clulow {
164*b210e777SJoshua M. Clulow /*
165*b210e777SJoshua M. Clulow * To avoid the need to allocate in early boot, we'll use a static
166*b210e777SJoshua M. Clulow * buffer four times the size of a tasteful terminal width. Note that
167*b210e777SJoshua M. Clulow * ilstr will allow us to produce diagnostic output if this buffer
168*b210e777SJoshua M. Clulow * would have been overrun.
169*b210e777SJoshua M. Clulow */
170*b210e777SJoshua M. Clulow char sbuf[80 * 4];
1716112cec5SJoshua M. Clulow ilstr_t s;
1726112cec5SJoshua M. Clulow uint_t num = 0;
1736112cec5SJoshua M. Clulow
174*b210e777SJoshua M. Clulow ilstr_init_prealloc(&s, sbuf, sizeof (sbuf));
1756112cec5SJoshua M. Clulow
1766112cec5SJoshua M. Clulow bootbanner_print_one(&s, printfunc, BOOTBANNER1, &num);
1776112cec5SJoshua M. Clulow bootbanner_print_one(&s, printfunc, BOOTBANNER2, &num);
1786112cec5SJoshua M. Clulow bootbanner_print_one(&s, printfunc, BOOTBANNER3, &num);
1796112cec5SJoshua M. Clulow bootbanner_print_one(&s, printfunc, BOOTBANNER4, &num);
1806112cec5SJoshua M. Clulow bootbanner_print_one(&s, printfunc, BOOTBANNER5, &num);
1816112cec5SJoshua M. Clulow
1826112cec5SJoshua M. Clulow ilstr_fini(&s);
1836112cec5SJoshua M. Clulow }
184