1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2012 Gary Mills
  24  * Copyright 2020 Joyent, Inc.
  25  *
  26  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  27  * Use is subject to license terms.
  28  */
  29 
  30 #include <sys/types.h>
  31 #include <sys/param.h>
  32 #include <sys/machparam.h>
  33 #include <sys/archsystm.h>
  34 #include <sys/boot_console.h>
  35 #include <sys/varargs.h>
  36 #include "dboot_asm.h"
  37 #include "dboot_printf.h"
  38 #include "dboot_xboot.h"
  39 
  40 #ifdef __xpv
  41 #include <sys/hypervisor.h>
  42 #endif
  43 
  44 /*
  45  * This file provides simple output formatting via dboot_printf()
  46  */
  47 
  48 static void do_dboot_printf(char *fmt, va_list args);
  49 
  50 static char digits[] = "0123456789abcdef";
  51 
  52 /*
  53  * Primitive version of panic, prints a message then resets the system
  54  */
  55 void
  56 dboot_panic(char *fmt, ...)
  57 {
  58         va_list args;
  59 
  60         va_start(args, fmt);
  61         do_dboot_printf(fmt, args);
  62 
  63         if (boot_console_type(NULL) == CONS_SCREEN_TEXT) {
  64                 dboot_printf("Press any key to reboot\n");
  65                 (void) bcons_getchar();
  66         }
  67         outb(0x64, 0xfe);       /* this resets the system, see pc_reset() */
  68         dboot_halt();           /* just in case */
  69 }
  70 
  71 /*
  72  * printf for boot code
  73  */
  74 void
  75 dboot_printf(char *fmt, ...)
  76 {
  77         va_list args;
  78 
  79         va_start(args, fmt);
  80         do_dboot_printf(fmt, args);
  81 }
  82 
  83 
  84 /*
  85  * output a string
  86  */
  87 static void
  88 dboot_puts(char *s)
  89 {
  90         while (*s != 0) {
  91                 bcons_putchar(*s);
  92                 ++s;
  93         }
  94 }
  95 
  96 static void
  97 dboot_putnum(uint64_t x, boolean_t is_signed, uint8_t base)
  98 {
  99         char buffer[64];        /* digits in reverse order */
 100         int i;
 101 
 102         if (is_signed && (int64_t)x < 0) {
 103                 bcons_putchar('-');
 104                 x = -x;
 105         }
 106 
 107         for (i  = -1; x != 0 && i <= 63; x /= base)
 108                 buffer[++i] = digits[x - ((x / base) * base)];
 109 
 110         if (i < 0)
 111                 buffer[++i] = '0';
 112 
 113         while (i >= 0)
 114                 bcons_putchar(buffer[i--]);
 115 }
 116 
 117 /*
 118  * Very primitive printf - only does a subset of the standard format characters.
 119  */
 120 static void
 121 do_dboot_printf(char *fmt, va_list args)
 122 {
 123         char *s;
 124         uint64_t x;
 125         uint8_t base;
 126         uint8_t size;
 127 
 128         if (fmt == NULL) {
 129                 dboot_puts("dboot_printf(): 1st arg is NULL\n");
 130                 return;
 131         }
 132         for (; *fmt; ++fmt) {
 133                 if (*fmt != '%') {
 134                         bcons_putchar(*fmt);
 135                         continue;
 136                 }
 137 
 138                 size = 0;
 139 again:
 140                 ++fmt;
 141                 switch (*fmt) {
 142 
 143                 case '%':
 144                         bcons_putchar(*fmt);
 145                         break;
 146 
 147                 case 'c':
 148                         x = va_arg(args, int);
 149                         bcons_putchar(x);
 150                         break;
 151 
 152                 case 's':
 153                         s = va_arg(args, char *);
 154                         if (s == NULL)
 155                                 dboot_puts("*NULL*");
 156                         else
 157                                 dboot_puts(s);
 158                         break;
 159 
 160                 case 'p':
 161                         x = va_arg(args, ulong_t);
 162                         dboot_putnum(x, B_FALSE, 16);
 163                         break;
 164 
 165                 case 'l':
 166                         if (size == 0)
 167                                 size = sizeof (long);
 168                         else if (size == sizeof (long))
 169                                 size = sizeof (long long);
 170                         goto again;
 171 
 172                 case 'd':
 173                         if (size == 0)
 174                                 x = va_arg(args, int);
 175                         else if (size == sizeof (long))
 176                                 x = va_arg(args, long);
 177                         else
 178                                 x = va_arg(args, long long);
 179                         dboot_putnum(x, B_TRUE, 10);
 180                         break;
 181 
 182                 case 'u':
 183                         base = 10;
 184                         goto unsigned_num;
 185 
 186                 case 'b':
 187                         base = 2;
 188                         goto unsigned_num;
 189 
 190                 case 'o':
 191                         base = 8;
 192                         goto unsigned_num;
 193 
 194                 case 'x':
 195                         base = 16;
 196 unsigned_num:
 197                         if (size == 0)
 198                                 x = va_arg(args, uint_t);
 199                         else if (size == sizeof (ulong_t))
 200                                 x = va_arg(args, ulong_t);
 201                         else
 202                                 x = va_arg(args, unsigned long long);
 203                         dboot_putnum(x, B_FALSE, base);
 204                         break;
 205 
 206                 default:
 207                         dboot_puts("dboot_printf(): unknown % escape\n");
 208                 }
 209         }
 210 }