e64f109f2f
Text driver is starting to work.
360 lines
9.2 KiB
C
360 lines
9.2 KiB
C
/*
|
|
* A logging utility
|
|
*/
|
|
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "interrupt.h"
|
|
#include "log.h"
|
|
#include "simpleio.h"
|
|
#include "syscalls.h"
|
|
|
|
#include "dev/uart.h"
|
|
#include "dev/txt_screen.h"
|
|
#include "gabe_reg.h"
|
|
|
|
|
|
/* Channel to which the logging output should go.
|
|
* Positive: screen number
|
|
* -1: UART.
|
|
*/
|
|
static short log_channel = -1;
|
|
short log_level;
|
|
|
|
// do_log either points to log_to_uart or log_to_screen.
|
|
static void (*do_log)(const char* message);
|
|
static void log_to_uart(const char* message);
|
|
static void log_to_screen(const char* message);
|
|
|
|
#define UART_COM1 0
|
|
|
|
/* Can use the buzzer as sound clues */
|
|
void buzzer_on(void) {
|
|
// TODO: *(GABE_CTRL_REG) = BUZZER_CONTROL;
|
|
}
|
|
|
|
|
|
void buzzer_off(void) {
|
|
// TODO: *(GABE_CTRL_REG) &= ~BUZZER_CONTROL;
|
|
}
|
|
|
|
|
|
void log_init(void) {
|
|
log_setlevel(DEFAULT_LOG_LEVEL);
|
|
|
|
// if (log_channel == LOG_CHANNEL_UART0) {
|
|
uart_init(UART_COM1);
|
|
do_log = log_to_uart;
|
|
log(LOG_INFO,"FOENIX DEBUG OUTPUT------------");
|
|
// }
|
|
// else {
|
|
// do_log = log_to_screen;
|
|
// }
|
|
}
|
|
|
|
unsigned short panic_number; /* The number of the kernel panic */
|
|
unsigned long panic_pc; /* The PC where the issue occurred */
|
|
unsigned long panic_address; /* The address that was accessed (for some exceptions) */
|
|
|
|
const char * err_messages[] = {
|
|
"OK",
|
|
"general error",
|
|
"bad device number",
|
|
"operation timed out",
|
|
"device could not be initialized",
|
|
"could not read from device",
|
|
"could not write to device",
|
|
"out of bounds",
|
|
"no media",
|
|
"device is write protected",
|
|
"bad channel number",
|
|
"out of handles",
|
|
"bad handle",
|
|
"unknown file type",
|
|
"out of memory",
|
|
"bad binary file",
|
|
"file is not executable",
|
|
"not found",
|
|
"low level disk error",
|
|
"file system assertion failed",
|
|
"device not ready",
|
|
"file not found",
|
|
"directory not found",
|
|
"invalid path name",
|
|
"access denied",
|
|
"prohibited access",
|
|
"invalid object",
|
|
"drive is write protected",
|
|
"invalid drive",
|
|
"volume has no work area",
|
|
"no file system found",
|
|
"creation of file system aborted",
|
|
"file system timeout",
|
|
"file locked",
|
|
"not enough core",
|
|
"too many open files",
|
|
"file system invalid parameter",
|
|
"not supported",
|
|
"bad argument",
|
|
"media changed"
|
|
};
|
|
|
|
/*
|
|
* Return human readable message for an error number
|
|
*/
|
|
const char * err_message(short err_number) {
|
|
short index = 0 - err_number;
|
|
|
|
if (index < 40) {
|
|
return err_messages[index];
|
|
} else {
|
|
return "unknown error";
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Print an error message
|
|
*
|
|
* Inputs:
|
|
* channel = the number of the channel to print to
|
|
* message = a message string to print before the error
|
|
* err_number = the number of the error
|
|
*/
|
|
void err_print(short channel, const char * message, short err_number) {
|
|
char buffer[80];
|
|
|
|
if ((err_number < 0) && (err_number > -40)) {
|
|
sprintf(buffer, "%s: %s\n", message, err_message(err_number));
|
|
} else {
|
|
sprintf(buffer, "%s: #%d\n", message, err_number);
|
|
}
|
|
|
|
// TODO: bring back
|
|
// sys_chan_write(channel, buffer, strlen(buffer));
|
|
|
|
// TODO: remove
|
|
sys_txt_print(channel, buffer);
|
|
}
|
|
|
|
/*
|
|
* Display a panic screen
|
|
*/
|
|
void panic(void) {
|
|
char buffer[80];
|
|
short column = 2;
|
|
short row = 2;
|
|
short address_expected = 0;
|
|
t_rect region;
|
|
TRACE("PANIC------------------------------------------");
|
|
/* Shut off all interrupts */
|
|
// TODO: int_disable_all();
|
|
|
|
/* Re-initialize the text screen */
|
|
txt_init_screen(0);
|
|
txt_set_border(0, 0, 0);
|
|
region.origin.x = 0;
|
|
region.origin.y = 0;
|
|
region.size.width = 0;
|
|
region.size.height = 0;
|
|
txt_set_region(0, ®ion);
|
|
txt_set_color(0, 15, 1);
|
|
txt_set_cursor(0, 0, 0, 0);
|
|
txt_clear(0, 2);
|
|
|
|
txt_set_xy(0, column, row++);
|
|
txt_print(0, "\xDA\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xBF");
|
|
|
|
txt_set_xy(0, column, row++);
|
|
txt_print(0, "\xB3 \xB3");
|
|
|
|
txt_set_xy(0, column, row++);
|
|
txt_print(0, "\xB3 Oh dear, something has gone wrong... \xB3");
|
|
|
|
txt_set_xy(0, column, row++);
|
|
txt_print(0, "\xB3 \xB3");
|
|
|
|
txt_set_xy(0, column, row++);
|
|
switch (panic_number) {
|
|
case 2:
|
|
txt_print(0, "\xB3 Bus Error \xB3");
|
|
address_expected = 1;
|
|
break;
|
|
case 3:
|
|
txt_print(0, "\xB3 Address Error \xB3");
|
|
address_expected = 1;
|
|
break;
|
|
case 4:
|
|
txt_print(0, "\xB3 Illegal Instruction Error \xB3");
|
|
break;
|
|
case 5:
|
|
txt_print(0, "\xB3 Division by Zero Error \xB3");
|
|
break;
|
|
case 6:
|
|
txt_print(0, "\xB3 Range Check Exception \xB3");
|
|
break;
|
|
case 7:
|
|
txt_print(0, "\xB3 Overflow Exception \xB3");
|
|
break;
|
|
case 8:
|
|
txt_print(0, "\xB3 Privilege Exception \xB3");
|
|
break;
|
|
case 24:
|
|
txt_print(0, "\xB3 Spurious Interrupt \xB3");
|
|
break;
|
|
|
|
default:
|
|
txt_print(0, "\xB3 Unknown Exception \xB3");
|
|
break;
|
|
}
|
|
|
|
txt_set_xy(0, column, row++);
|
|
txt_print(0, "\xB3 \xB3");
|
|
|
|
if (address_expected) {
|
|
txt_set_xy(0, column, row++);
|
|
sprintf(buffer, "\xB3 PC: %08X Address: %08X \xB3", (unsigned int)panic_pc, (unsigned int)panic_address);
|
|
txt_print(0, buffer);
|
|
} else {
|
|
txt_set_xy(0, column, row++);
|
|
sprintf(buffer, "\xB3 PC: %08X \xB3", (unsigned int)panic_pc);
|
|
txt_print(0, buffer);
|
|
}
|
|
|
|
txt_set_xy(0, column, row++);
|
|
txt_print(0, "\xB3 \xB3");
|
|
|
|
txt_set_xy(0, column, row++);
|
|
txt_print(0, "\xC0\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xC4\xD9");
|
|
|
|
/* Wait forever */
|
|
while (1) ;
|
|
}
|
|
|
|
/*
|
|
* Set the maximum level of verbosity in logging.
|
|
* To be printed, a message must have a level lower or equal to this level.
|
|
*
|
|
* Input:
|
|
* level = the maximum level of verbosity to log
|
|
*/
|
|
void log_setlevel(short level) {
|
|
log_level = level;
|
|
}
|
|
|
|
|
|
static void log_to_uart(const char *message) {
|
|
char *c = (char*)message;
|
|
while (*c) {
|
|
uart_put(UART_COM1, *c++);
|
|
}
|
|
uart_put(UART_COM1,'\r');
|
|
uart_put(UART_COM1,'\n');
|
|
}
|
|
|
|
static void log_to_screen(const char *message) {
|
|
txt_print(log_channel, message);
|
|
txt_print(log_channel, "\n");
|
|
}
|
|
|
|
/*
|
|
* Log a message to the console.
|
|
*
|
|
* Inputs:
|
|
* level = the severity of the message... the logging level will filter messages displayed
|
|
* message/args = like printf.
|
|
*
|
|
* Caveat:
|
|
* The total length should not exceed 512 chars.
|
|
*/
|
|
void log(short level, const char * message, ...) {
|
|
if (level > log_level)
|
|
return;
|
|
|
|
char buf[80]; // Should hopefully be long enough !
|
|
|
|
va_list args;
|
|
va_start(args, message);
|
|
vsprintf(buf, message, args);
|
|
va_end(args);
|
|
|
|
(*do_log)(buf);
|
|
// txt_print(0, buf);
|
|
// txt_print(0, "\n");
|
|
}
|
|
|
|
void trace(const char * message, ...) {
|
|
if (LOG_TRACE > log_level)
|
|
return;
|
|
|
|
char buf[80]; // Should hopefully be long enough !
|
|
|
|
va_list args;
|
|
va_start(args, message);
|
|
vsprintf(buf, message, args);
|
|
va_end(args);
|
|
|
|
(*do_log)(buf);
|
|
}
|
|
|
|
/*
|
|
* Log a message to the console
|
|
*
|
|
* Inputs:
|
|
* level = the severity of the message... the logging level will filter messages displayed
|
|
* message1 = the first part of the message to log
|
|
* message2 = the second part of the message to log
|
|
*/
|
|
void log2(short level, const char * message1, const char * message2) {
|
|
if (level <= log_level) {
|
|
char line[80];
|
|
sprintf(line, "%s%s\n", message1, message2);
|
|
log(level, line);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Log a message to the console
|
|
*
|
|
* Inputs:
|
|
* level = the severity of the message... the logging level will filter messages displayed
|
|
* message1 = the first part of the message to log
|
|
* message2 = the second part of the message to log
|
|
* message3 = the third part of the message to log
|
|
*/
|
|
void log3(short level, const char * message1, const char * message2, const char * message3) {
|
|
if (level <= log_level) {
|
|
char line[80];
|
|
sprintf(line, "%s%s%s\n", message1, message2, message3);
|
|
log(level, line);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Log a message with a number
|
|
*
|
|
* Inputs:
|
|
* level = the severity of the message... the logging level will filter messages displayed
|
|
* message1 = the first part of the message to log
|
|
* n = the number to log
|
|
*/
|
|
void log_num(short level, char * message, int n) {
|
|
char line[80];
|
|
|
|
if (level <= log_level) {
|
|
sprintf(line, "%s%08X", message, n);
|
|
log(level, line);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Send a single character to the debugging channel
|
|
*/
|
|
void log_c(short level, char c) {
|
|
char line[2];
|
|
line[0] = c;
|
|
line[1] = '\0';
|
|
log(level, line);
|
|
}
|