263 lines
6.6 KiB
C
263 lines
6.6 KiB
C
/*
|
|
* plex86: run multiple x86 operating systems concurrently
|
|
* Copyright (C) 1999-2003 Kevin P. Lawton
|
|
*
|
|
* print-nexus.c: Monitor debug print facility
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
|
|
#include "plex86.h"
|
|
#define IN_MONITOR_SPACE
|
|
#include "monitor.h"
|
|
|
|
int mon_vprint(vm_t *vm, char *fmt, va_list args);
|
|
|
|
static unsigned int power_of_ten[] = {
|
|
1,
|
|
10,
|
|
100,
|
|
1000,
|
|
10000,
|
|
100000,
|
|
1000000,
|
|
10000000,
|
|
100000000,
|
|
1000000000,
|
|
};
|
|
|
|
int
|
|
monprint(vm_t *vm, char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
int ret;
|
|
|
|
va_start(args, fmt);
|
|
ret = mon_vprint(vm, fmt, args);
|
|
va_end(args);
|
|
return(ret);
|
|
}
|
|
|
|
int
|
|
mon_vprint(vm_t *vm, char *fmt, va_list args)
|
|
{
|
|
unsigned offset, size;
|
|
unsigned char *log_buff_p;
|
|
int ret;
|
|
|
|
if (vm->log_buffer_info.locked)
|
|
return 0;
|
|
|
|
vm->log_buffer_info.locked = 1;
|
|
vm->log_buffer_info.event = 1;
|
|
offset = vm->log_buffer_info.offset;
|
|
|
|
/* Sanity check */
|
|
if (offset >= LOG_BUFF_SIZE) {
|
|
vm->guest.addr.log_buffer[0] = 0; /* Null terminate. */
|
|
resetPrintBuf(vm);
|
|
return(0);
|
|
}
|
|
|
|
size = LOG_BUFF_SIZE - offset;
|
|
log_buff_p = &vm->guest.addr.log_buffer[offset];
|
|
|
|
ret = mon_vsnprintf(log_buff_p, size, fmt, args);
|
|
|
|
if (ret == -1) {
|
|
/* Terminate current contents since new print request did not work. */
|
|
*log_buff_p = 0;
|
|
/* If we are in the monitor space, then we can request that the
|
|
* current buffer contents be printed.
|
|
*/
|
|
resetPrintBuf(vm);
|
|
sysFlushPrintBuf(vm);
|
|
|
|
/* Print request did not fit. dump buffer contents and try again
|
|
* using whole buffer.
|
|
*/
|
|
size = LOG_BUFF_SIZE;
|
|
log_buff_p = &vm->guest.addr.log_buffer[0];
|
|
ret = mon_vsnprintf(log_buff_p, size, fmt, args);
|
|
if (ret == -1) {
|
|
/* We have serious problems. This print request will not even
|
|
* fit in the whole buffer.
|
|
*/
|
|
vm->guest.addr.log_buffer[0] = 0; /* Null terminate. */
|
|
resetPrintBuf(vm);
|
|
/* xxx Put error in buffer here. */
|
|
return(0);
|
|
}
|
|
}
|
|
vm->log_buffer_info.offset += ret;
|
|
vm->log_buffer_info.locked = 0;
|
|
#if 0 /* Fri Dec 27 21:43:05 EST 2002 */
|
|
resetPrintBuf(vm);
|
|
sysFlushPrintBuf(vm);
|
|
#endif
|
|
return(ret);
|
|
}
|
|
|
|
void
|
|
resetPrintBuf(vm_t *vm)
|
|
{
|
|
vm->log_buffer_info.event = 0;
|
|
vm->log_buffer_info.locked = 0;
|
|
vm->log_buffer_info.offset = 0;
|
|
vm->log_buffer_info.error = 0;
|
|
}
|
|
|
|
|
|
/* For now, this is a simple vsnprintf() type of function. We need
|
|
* to fill this out a little.
|
|
*/
|
|
|
|
int
|
|
mon_vsnprintf(char *str, unsigned size, const char *fmt, va_list args)
|
|
{
|
|
int count = 0;
|
|
unsigned format_width;
|
|
unsigned char c;
|
|
|
|
while (*fmt) {
|
|
switch (*fmt) {
|
|
|
|
case '%':
|
|
format_width = 0;
|
|
fmt++;
|
|
c = *fmt++;
|
|
/* Get optional field width */
|
|
if ( (c>='0') && (c<='9') ) {
|
|
do {
|
|
format_width = (format_width * 10) + (c - '0');
|
|
c = *fmt++;
|
|
} while ( (c>='0') && (c<='9') );
|
|
}
|
|
/* %x: hexadecimal */
|
|
if ( c == 'x' ) {
|
|
unsigned int val, leadin;
|
|
int j;
|
|
unsigned nibble;
|
|
|
|
val = va_arg(args, unsigned int);
|
|
leadin = 1;
|
|
|
|
for (j=7; j>=0; j--) {
|
|
nibble = (val >> (4 * j)) & 0x0f;
|
|
if (leadin && j && !format_width && !nibble)
|
|
continue;
|
|
if (leadin && j && format_width && ((j+1)>format_width) &&
|
|
!nibble)
|
|
continue;
|
|
leadin = 0;
|
|
if ( (count+2) >= size ) goto error;
|
|
if (nibble <= 9)
|
|
*str++ = nibble + '0';
|
|
else
|
|
*str++ = (nibble-10) + 'A';
|
|
count++;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* %c: character */
|
|
if ( c == 'c' ) {
|
|
unsigned char val;
|
|
val = va_arg(args, unsigned);
|
|
if ( (count+2) >= size ) goto error;
|
|
*str++ = val;
|
|
count++;
|
|
break;
|
|
}
|
|
|
|
/* %s: string */
|
|
if ( c == 's' ) {
|
|
unsigned char *s;
|
|
s = va_arg(args, unsigned char *);
|
|
if ( (count+2) >= size ) goto error;
|
|
count++;
|
|
while (*s) {
|
|
if ( (count+2) >= size ) goto error;
|
|
*str++ = *s++; /* Copy char from string to output buffer. */
|
|
count++;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* %u: unsigned int */
|
|
if ( c == 'u' ) {
|
|
unsigned int val, leadin;
|
|
int j;
|
|
unsigned digit;
|
|
|
|
val = va_arg(args, unsigned int);
|
|
leadin = 1;
|
|
|
|
for (j=9; j>=0; j--) {
|
|
if (leadin && j && !format_width && (val < power_of_ten[j]))
|
|
continue;
|
|
if (leadin && j && format_width && ((j+1)>format_width) &&
|
|
(val < power_of_ten[j]))
|
|
continue;
|
|
leadin = 0;
|
|
digit = (val / power_of_ten[j]);
|
|
if ( (count+2) >= size ) goto error;
|
|
*str++ = digit + '0';
|
|
count++;
|
|
val -= (digit * power_of_ten[j]);
|
|
}
|
|
break;
|
|
}
|
|
/* %b : binary (non-standard but useful) */
|
|
if ( c == 'b' ) {
|
|
unsigned int val, bit, leadin;
|
|
int j;
|
|
val = va_arg(args, unsigned int);
|
|
leadin = 1;
|
|
for (j=31; j>=0; j--) {
|
|
bit = (val >> j) & 1;
|
|
if (leadin && j && !format_width && !bit)
|
|
continue;
|
|
if (leadin && j && format_width && ((j+1)>format_width) && !bit)
|
|
continue;
|
|
leadin = 0;
|
|
if ( (count+2) >= size ) goto error;
|
|
*str++ = bit + '0';
|
|
count++;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* Error, unrecognized format char */
|
|
goto error;
|
|
break;
|
|
|
|
default:
|
|
/* pass char through */
|
|
if ( (count+2) >= size ) goto error;
|
|
*str++ = *fmt++;
|
|
count++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
*str = 0; /* Complete string with null char */
|
|
return(count);
|
|
|
|
error:
|
|
return(-1);
|
|
}
|