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  *
  25  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  26  * Use is subject to license terms.
  27  */
  28 
  29 #include <sys/types.h>
  30 #include <sys/param.h>
  31 #include <sys/machparam.h>
  32 #include <sys/archsystm.h>
  33 #include <sys/boot_console.h>
  34 #include <sys/varargs.h>
  35 #include "dboot_asm.h"
  36 #include "dboot_printf.h"
  37 #include "dboot_xboot.h"
  38 
  39 #ifdef __xpv
  40 #include <sys/hypervisor.h>
  41 #endif
  42 
  43 /*
  44  * This file provides simple output formatting via dboot_printf()
  45  */
  46 
  47 static void do_dboot_printf(char *fmt, va_list args);
  48 
  49 static char digits[] = "0123456789abcdef";
  50 
  51 /*
  52  * Primitive version of panic, prints a message then resets the system
  53  */
  54 void
  55 dboot_panic(char *fmt, ...)
  56 {
  57         va_list args;
  58 
  59         va_start(args, fmt);
  60         do_dboot_printf(fmt, args);
  61 
  62         if (boot_console_type(NULL) == CONS_SCREEN_TEXT) {
  63                 dboot_printf("Press any key to reboot\n");
  64                 (void) bcons_getchar();
  65         }
  66         outb(0x64, 0xfe);       /* this resets the system, see pc_reset() */
  67         dboot_halt();           /* just in case */
  68 }
  69 
  70 /*
  71  * printf for boot code
  72  */
  73 void
  74 dboot_printf(char *fmt, ...)
  75 {
  76         va_list args;
  77 
  78         va_start(args, fmt);
  79         do_dboot_printf(fmt, args);
  80 }
  81 
  82 
  83 /*
  84  * output a string
  85  */
  86 static void
  87 dboot_puts(char *s)
  88 {
  89         while (*s != 0) {
  90                 bcons_putchar(*s);
  91                 ++s;
  92         }
  93 }
  94 
  95 static void
  96 dboot_putnum(uint64_t x, uint_t is_signed, uint8_t base)
  97 {
  98         char buffer[64];        /* digits in reverse order */
  99         int i;
 100 
 101         if (is_signed && (int64_t)x < 0) {
 102                 bcons_putchar('-');
 103                 x = -x;
 104         }
 105 
 106         for (i  = -1; x != 0 && i <= 63; x /= base)
 107                 buffer[++i] = digits[x - ((x / base) * base)];
 108 
 109         if (i < 0)
 110                 buffer[++i] = '0';
 111 
 112         while (i >= 0)
 113                 bcons_putchar(buffer[i--]);
 114 }
 115 
 116 /*
 117  * very primitive printf - only does %s, %d, %x, %lx, or %%
 118  */
 119 static void
 120 do_dboot_printf(char *fmt, va_list args)
 121 {
 122         char *s;
 123         uint64_t x;
 124         uint8_t base;
 125         uint8_t size;
 126         uint_t is_signed = 1;
 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, !is_signed, 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, is_signed, 10);
 180                         break;
 181 
 182                 case 'b':
 183                         base = 2;
 184                         goto unsigned_num;
 185 
 186                 case 'o':
 187                         base = 8;
 188                         goto unsigned_num;
 189 
 190                 case 'x':
 191                         base = 16;
 192 unsigned_num:
 193                         if (size == 0)
 194                                 x = va_arg(args, uint_t);
 195                         else if (size == sizeof (long))
 196                                 x = va_arg(args, ulong_t);
 197                         else
 198                                 x = va_arg(args, unsigned long long);
 199                         dboot_putnum(x, !is_signed, base);
 200                         break;
 201 
 202                 default:
 203                         dboot_puts("dboot_printf(): unknown % escape\n");
 204                 }
 205         }
 206 }