/* * x86_printf.c - A printf function for x86 (debug only). * * Copyright (c) 2017 Maxime Villard * * This file is part of ALMOS-MKH. * * ALMOS-MKH is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2.0 of the License. * * ALMOS-MKH is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ALMOS-MKH; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) #define CONS_X_SIZE 80 #define CONS_Y_SIZE 26 static char cons_buffer[CONS_X_SIZE * 2 * CONS_Y_SIZE] __in_kdata; extern intptr_t iom_base; size_t cons_ptr __in_kdata = 0; /* -------------------------------------------------------------------------- */ static uint32_t x86_lock_val __in_kdata = 0; void x86_lock() { while (!hal_atomic_cas(&x86_lock_val, 0, 1)) { /* wait */ } } void x86_unlock() { while (!hal_atomic_cas(&x86_lock_val, 1, 0)) { /* wait */ } } /* -------------------------------------------------------------------------- */ void x86_panic(char *msg) { x86_lock(); x86_printf("!!!!! PANIC !!!!!\n"); x86_printf("-> %s\n", msg); x86_printf("!!!!!!!!!!!!!!!!!\n"); x86_unlock(); while (1); } static void check_scroll() { char *base = (char *)iom_base + (0xB8000 - IOM_BEGIN); char *src, *dst; size_t i; if (cons_ptr < (CONS_X_SIZE * 2) * CONS_Y_SIZE) { return; } for (i = 0; i < CONS_Y_SIZE - 1; i++) { dst = (char *)&cons_buffer[0] + i * (CONS_X_SIZE * 2); src = (char *)&cons_buffer[0] + (i + 1) * (CONS_X_SIZE * 2); memcpy(dst, src, (CONS_X_SIZE * 2)); } memset(&cons_buffer[0] + (CONS_X_SIZE * 2) * (CONS_Y_SIZE - 1), 0, (CONS_X_SIZE * 2)); cons_ptr -= (CONS_X_SIZE * 2); memcpy(base, &cons_buffer[0], (CONS_X_SIZE * 2) * (CONS_Y_SIZE - 1)); } void x86_putc(char c) { hal_com_send(0, c); if (c == '\n') { cons_ptr = roundup(cons_ptr, CONS_X_SIZE * 2); check_scroll(); return; } char *video = (char *)iom_base + (0xB8000 - IOM_BEGIN) + cons_ptr; char *buf = &cons_buffer[cons_ptr]; *video = c; *buf = c; cons_ptr++, video++, buf++; *video = 0x7; *buf = 0x7; cons_ptr++, video++, buf++; check_scroll(); } static void x86_itoa(char *buf, unsigned long int n, int base) { unsigned long int tmp; int i, j; tmp = n; i = 0; do { tmp = n % base; buf[i++] = (tmp < 10) ? (tmp + '0') : (tmp + 'a' - 10); } while (n /= base); buf[i--] = 0; for (j = 0; j < i; j++, i--) { tmp = buf[j]; buf[j] = buf[i]; buf[i] = tmp; } } static void x86_ztoa(char *buf, uint64_t n, uint64_t base) { uint64_t tmp; int i, j; tmp = n; i = 0; do { tmp = n % base; buf[i++] = (tmp < 10) ? (tmp + '0') : (tmp + 'a' - 10); } while (n /= base); buf[i--] = 0; for (j = 0; j < i; j++, i--) { tmp = buf[j]; buf[j] = buf[i]; buf[i] = tmp; } } static char alphabet[] = "abcdefghijklmnopqrstuvwxyz"; void x86_printf(char *s, ...) { va_list ap; char buf[64]; int i, j, size, buflen, neg; unsigned char c; int ival; unsigned int uival; uint64_t zval; va_start(ap, s); while ((c = *s++)) { size = 0; neg = 0; if (c == 0) break; else if (c == '%') { c = *s++; if (c >= '0' && c <= '9') { size = c - '0'; c = *s++; } if (c == 'c') { ival = va_arg(ap, int); if ((ival - 97) > sizeof(alphabet)) { x86_printf("(unknown:%d)", ival); } else { x86_putc(alphabet[ival - 97]); } } else if (c == 'z') { zval = va_arg(ap, uint64_t); x86_ztoa(buf, zval, 10); buflen = strlen(buf); if (buflen < size) for (i = size, j = buflen; i >= 0; i--, j--) buf[i] = (j >= 0) ? buf[j] : '0'; x86_printf(buf); } else if (c == 'Z') { zval = va_arg(ap, uint64_t); x86_ztoa(buf, zval, 16); buflen = strlen(buf); if (buflen < size) for (i = size, j = buflen; i >= 0; i--, j--) buf[i] = (j >= 0) ? buf[j] : '0'; x86_printf("0x%s", buf); } else if (c == 'd') { ival = va_arg(ap, int); if (ival < 0) { uival = 0 - ival; neg++; } else uival = ival; x86_itoa(buf, uival, 10); buflen = strlen(buf); if (buflen < size) for (i = size, j = buflen; i >= 0; i--, j--) buf[i] = (j >= 0) ? buf[j] : '0'; if (neg) x86_printf("-%s", buf); else x86_printf(buf); } else if (c == 'u') { uival = va_arg(ap, int); x86_itoa(buf, uival, 10); buflen = strlen(buf); if (buflen < size) for (i = size, j = buflen; i >= 0; i--, j--) buf[i] = (j >= 0) ? buf[j] : '0'; x86_printf(buf); } else if (c == 'x' || c == 'X') { uival = va_arg(ap, int); x86_itoa(buf, uival, 16); buflen = strlen(buf); if (buflen < size) for (i = size, j = buflen; i >= 0; i--, j--) buf[i] = (j >= 0) ? buf[j] : '0'; x86_printf("0x%s", buf); } else if (c == 'p') { uival = va_arg(ap, int); x86_itoa(buf, uival, 16); size = 8; buflen = strlen(buf); if (buflen < size) for (i = size, j = buflen; i >= 0; i--, j--) buf[i] = (j >= 0) ? buf[j] : '0'; x86_printf("0x%s", buf); } else if (c == 's') { x86_printf((char *) va_arg(ap, uint64_t)); } } else x86_putc(c); } return; }