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 }