Renamed system/core to system/kernel.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@12360 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
SubDir OBOS_TOP src kernel core debug ;
|
||||
|
||||
UsePrivateHeaders [ FDirName kernel debug ] ;
|
||||
|
||||
KernelMergeObject kernel_debug.o :
|
||||
console.c
|
||||
debug.c
|
||||
frame_buffer_console.cpp
|
||||
gdb.c
|
||||
user_debugger.cpp
|
||||
|
||||
: -fno-pic -Wno-unused
|
||||
;
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2005, Axel Dörfler, [email protected]. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||
* Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
|
||||
/* This file contains the kprintf stuff and console init */
|
||||
|
||||
|
||||
#include <OS.h>
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include <boot/kernel_args.h>
|
||||
#include <console.h>
|
||||
#include <frame_buffer_console.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
|
||||
struct console_op_xy_struct {
|
||||
int x;
|
||||
int y;
|
||||
char buf[256];
|
||||
};
|
||||
|
||||
static int console_fd = -1;
|
||||
|
||||
|
||||
void
|
||||
kprintf(const char *fmt, ...)
|
||||
{
|
||||
int ret = 0;
|
||||
va_list args;
|
||||
char temp[256];
|
||||
|
||||
if (console_fd >= 0) {
|
||||
va_start(args, fmt);
|
||||
ret = vsprintf(temp,fmt,args);
|
||||
va_end(args);
|
||||
|
||||
write_pos(console_fd, 0, temp, ret);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
void
|
||||
kprintf_xy(int x, int y, const char *fmt, ...)
|
||||
{
|
||||
int ret = 0;
|
||||
va_list args;
|
||||
struct console_op_xy_struct buf;
|
||||
|
||||
if (console_fd >= 0) {
|
||||
va_start(args, fmt);
|
||||
ret = vsprintf(buf.buf,fmt,args);
|
||||
va_end(args);
|
||||
|
||||
buf.x = x;
|
||||
buf.y = y;
|
||||
ioctl(console_fd, CONSOLE_OP_WRITEXY, &buf, ret + sizeof(buf.x) + sizeof(buf.y));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
con_init(kernel_args *args)
|
||||
{
|
||||
frame_buffer_console_init(args);
|
||||
return B_OK;
|
||||
}
|
||||
@@ -0,0 +1,569 @@
|
||||
/* This file contains the debugger */
|
||||
|
||||
/*
|
||||
** Copyright 2002-2004, The Haiku Team. All rights reserved.
|
||||
** Distributed under the terms of the Haiku License.
|
||||
**
|
||||
** Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
||||
** Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
|
||||
#include <debug.h>
|
||||
#include <arch/int.h>
|
||||
#include <smp.h>
|
||||
#include <console.h>
|
||||
#include <gdb.h>
|
||||
#include <int.h>
|
||||
#include <vm.h>
|
||||
|
||||
#include <arch/dbg_console.h>
|
||||
#include <arch/debug.h>
|
||||
#include <arch/cpu.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
typedef struct debugger_command {
|
||||
struct debugger_command *next;
|
||||
int (*func)(int, char **);
|
||||
const char *name;
|
||||
const char *description;
|
||||
} debugger_command;
|
||||
|
||||
int dbg_register_file[B_MAX_CPU_COUNT][14];
|
||||
/* XXXmpetit -- must be made generic */
|
||||
|
||||
static bool sSerialDebugEnabled = false;
|
||||
static spinlock dbg_spinlock = 0;
|
||||
static int debugger_on_cpu = -1;
|
||||
|
||||
static struct debugger_command *sCommands;
|
||||
|
||||
#define OUTPUT_BUFFER_SIZE 1024
|
||||
static char sOutputBuffer[OUTPUT_BUFFER_SIZE];
|
||||
|
||||
#define LINE_BUF_SIZE 1024
|
||||
#define MAX_ARGS 16
|
||||
#define HISTORY_SIZE 16
|
||||
|
||||
static char line_buf[HISTORY_SIZE][LINE_BUF_SIZE] = { "", };
|
||||
static char parse_line[LINE_BUF_SIZE] = "";
|
||||
static int cur_line = 0;
|
||||
static char *args[MAX_ARGS] = { NULL, };
|
||||
|
||||
#define distance(a, b) ((a) < (b) ? (b) - (a) : (a) - (b))
|
||||
|
||||
|
||||
static debugger_command *
|
||||
find_command(char *name)
|
||||
{
|
||||
debugger_command *command;
|
||||
int length;
|
||||
|
||||
// search command by full name
|
||||
|
||||
for (command = sCommands; command != NULL; command = command->next) {
|
||||
if (strcmp(name, command->name) == 0)
|
||||
return command;
|
||||
}
|
||||
|
||||
// if it couldn't be found, search for a partial match
|
||||
|
||||
length = strlen(name);
|
||||
|
||||
for (command = sCommands; command != NULL; command = command->next) {
|
||||
if (strncmp(name, command->name, length) == 0)
|
||||
return command;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
debug_read_line(char *buf, int max_len)
|
||||
{
|
||||
char c;
|
||||
int ptr = 0;
|
||||
bool done = false;
|
||||
int cur_history_spot = cur_line;
|
||||
|
||||
while (!done) {
|
||||
c = arch_dbg_con_read();
|
||||
switch (c) {
|
||||
case '\n':
|
||||
case '\r':
|
||||
buf[ptr++] = '\0';
|
||||
dbg_puts("\n");
|
||||
done = true;
|
||||
break;
|
||||
case 8: // backspace
|
||||
if (ptr > 0) {
|
||||
dbg_puts("\x1b[1D"); // move to the left one
|
||||
dbg_putch(' ');
|
||||
dbg_puts("\x1b[1D"); // move to the left one
|
||||
ptr--;
|
||||
}
|
||||
break;
|
||||
case 27: // escape sequence
|
||||
c = arch_dbg_con_read(); // should be '['
|
||||
c = arch_dbg_con_read();
|
||||
switch (c) {
|
||||
case 67: // right arrow acts like space
|
||||
buf[ptr++] = ' ';
|
||||
dbg_putch(' ');
|
||||
break;
|
||||
case 68: // left arrow acts like backspace
|
||||
if (ptr > 0) {
|
||||
dbg_puts("\x1b[1D"); // move to the left one
|
||||
dbg_putch(' ');
|
||||
dbg_puts("\x1b[1D"); // move to the left one
|
||||
ptr--;
|
||||
}
|
||||
break;
|
||||
case 65: // up arrow
|
||||
case 66: // down arrow
|
||||
{
|
||||
int history_line = 0;
|
||||
|
||||
// dprintf("1c %d h %d ch %d\n", cur_line, history_line, cur_history_spot);
|
||||
|
||||
if (c == 65) {
|
||||
// up arrow
|
||||
history_line = cur_history_spot - 1;
|
||||
if (history_line < 0)
|
||||
history_line = HISTORY_SIZE - 1;
|
||||
} else {
|
||||
// down arrow
|
||||
if (cur_history_spot != cur_line) {
|
||||
history_line = cur_history_spot + 1;
|
||||
if(history_line >= HISTORY_SIZE)
|
||||
history_line = 0;
|
||||
} else
|
||||
break; // nothing to do here
|
||||
}
|
||||
|
||||
// dprintf("2c %d h %d ch %d\n", cur_line, history_line, cur_history_spot);
|
||||
|
||||
// swap the current line with something from the history
|
||||
if(ptr > 0)
|
||||
dprintf("\x1b[%dD", ptr); // move to beginning of line
|
||||
|
||||
strcpy(buf, line_buf[history_line]);
|
||||
ptr = strlen(buf);
|
||||
dprintf("%s\x1b[K", buf); // print the line and clear the rest
|
||||
cur_history_spot = history_line;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case '$':
|
||||
case '+':
|
||||
/* HACK ALERT!!!
|
||||
*
|
||||
* If we get a $ at the beginning of the line
|
||||
* we assume we are talking with GDB
|
||||
*/
|
||||
if (ptr == 0) {
|
||||
strcpy(buf, "gdb");
|
||||
ptr= 4;
|
||||
done= true;
|
||||
break;
|
||||
} else {
|
||||
/* fall thru */
|
||||
}
|
||||
default:
|
||||
buf[ptr++] = c;
|
||||
dbg_putch(c);
|
||||
}
|
||||
if (ptr >= max_len - 2) {
|
||||
buf[ptr++] = '\0';
|
||||
dbg_puts("\n");
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
debug_parse_line(char *buf, char **argv, int *argc, int max_args)
|
||||
{
|
||||
int pos = 0;
|
||||
|
||||
strcpy(parse_line, buf);
|
||||
|
||||
if (!isspace(parse_line[0])) {
|
||||
argv[0] = parse_line;
|
||||
*argc = 1;
|
||||
} else
|
||||
*argc = 0;
|
||||
|
||||
while (parse_line[pos] != '\0') {
|
||||
if (isspace(parse_line[pos])) {
|
||||
parse_line[pos] = '\0';
|
||||
// scan all of the whitespace out of this
|
||||
while (isspace(parse_line[++pos]))
|
||||
;
|
||||
if (parse_line[pos] == '\0')
|
||||
break;
|
||||
argv[*argc] = &parse_line[pos];
|
||||
(*argc)++;
|
||||
|
||||
if (*argc >= max_args - 1)
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
||||
return *argc;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
kernel_debugger_loop(void)
|
||||
{
|
||||
int argc;
|
||||
struct debugger_command *cmd;
|
||||
cpu_status state;
|
||||
|
||||
state = disable_interrupts();
|
||||
|
||||
dprintf("kernel debugger on cpu %d\n", smp_get_current_cpu());
|
||||
debugger_on_cpu = smp_get_current_cpu();
|
||||
|
||||
cmd = NULL;
|
||||
|
||||
for (;;) {
|
||||
dprintf("kdebug> ");
|
||||
debug_read_line(line_buf[cur_line], LINE_BUF_SIZE);
|
||||
debug_parse_line(line_buf[cur_line], args, &argc, MAX_ARGS);
|
||||
|
||||
// We support calling last executed command again if
|
||||
// B_KDEDUG_CONT was returned last time, so cmd != NULL
|
||||
if (argc <= 0 && cmd == NULL)
|
||||
continue;
|
||||
|
||||
debugger_on_cpu = smp_get_current_cpu();
|
||||
|
||||
if (argc > 0)
|
||||
cmd = find_command(args[0]);
|
||||
|
||||
if (cmd == NULL)
|
||||
dprintf("unknown command, enter \"help\" to get a list of all supported commands\n");
|
||||
else {
|
||||
int rc = cmd->func(argc, args);
|
||||
|
||||
if (rc == B_KDEBUG_QUIT)
|
||||
break; // okay, exit now.
|
||||
|
||||
if (rc != B_KDEBUG_CONT)
|
||||
cmd = NULL; // forget last command executed...
|
||||
}
|
||||
|
||||
cur_line++;
|
||||
if (cur_line >= HISTORY_SIZE)
|
||||
cur_line = 0;
|
||||
}
|
||||
|
||||
restore_interrupts(state);
|
||||
}
|
||||
|
||||
|
||||
char
|
||||
dbg_putch(char c)
|
||||
{
|
||||
char ret;
|
||||
cpu_status state = disable_interrupts();
|
||||
acquire_spinlock(&dbg_spinlock);
|
||||
|
||||
if (sSerialDebugEnabled)
|
||||
ret = arch_dbg_con_putch(c);
|
||||
else
|
||||
ret = c;
|
||||
|
||||
release_spinlock(&dbg_spinlock);
|
||||
restore_interrupts(state);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
dbg_puts(const char *s)
|
||||
{
|
||||
cpu_status state = disable_interrupts();
|
||||
acquire_spinlock(&dbg_spinlock);
|
||||
|
||||
if (sSerialDebugEnabled)
|
||||
arch_dbg_con_puts(s);
|
||||
|
||||
release_spinlock(&dbg_spinlock);
|
||||
restore_interrupts(state);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
cmd_reboot(int argc, char **argv)
|
||||
{
|
||||
arch_cpu_shutdown(true);
|
||||
return 0;
|
||||
// I'll be really suprised if this line ever runs! ;-)
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
cmd_help(int argc, char **argv)
|
||||
{
|
||||
debugger_command *command, *specified = NULL;
|
||||
|
||||
if (argc > 1)
|
||||
specified = find_command(argv[1]);
|
||||
|
||||
if (specified != NULL) {
|
||||
// only print out the help of the specified command (and all of its aliases)
|
||||
dprintf("debugger command for \"%s\" and aliases:\n", specified->name);
|
||||
} else
|
||||
dprintf("debugger commands:\n");
|
||||
|
||||
for (command = sCommands; command != NULL; command = command->next) {
|
||||
if (specified && command->func != specified->func)
|
||||
continue;
|
||||
|
||||
dprintf(" %-20s\t\t%s\n", command->name, command->description ? command->description : "-");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
cmd_continue(int argc, char **argv)
|
||||
{
|
||||
return B_KDEBUG_QUIT;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
debug_init(kernel_args *args)
|
||||
{
|
||||
return arch_dbg_con_init(args);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
debug_init_post_vm(kernel_args *args)
|
||||
{
|
||||
add_debugger_command("help", &cmd_help, "List all debugger commands");
|
||||
add_debugger_command("reboot", &cmd_reboot, "Reboot the system");
|
||||
add_debugger_command("gdb", &cmd_gdb, "Connect to remote gdb");
|
||||
add_debugger_command("continue", &cmd_continue, "Leave kernel debugger");
|
||||
add_debugger_command("exit", &cmd_continue, NULL);
|
||||
add_debugger_command("es", &cmd_continue, NULL);
|
||||
|
||||
arch_dbg_con_init_settings(args);
|
||||
return arch_dbg_init(args);
|
||||
}
|
||||
|
||||
// ToDo: this one is probably not needed
|
||||
#if 0
|
||||
bool
|
||||
dbg_get_serial_debug()
|
||||
{
|
||||
return sSerialDebugEnabled;
|
||||
}
|
||||
#endif
|
||||
|
||||
// #pragma mark -
|
||||
// public API
|
||||
|
||||
|
||||
int
|
||||
add_debugger_command(char *name, int (*func)(int, char **), char *desc)
|
||||
{
|
||||
cpu_status state;
|
||||
struct debugger_command *cmd;
|
||||
|
||||
cmd = (struct debugger_command *)malloc(sizeof(struct debugger_command));
|
||||
if (cmd == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
cmd->func = func;
|
||||
cmd->name = name;
|
||||
cmd->description = desc;
|
||||
|
||||
state = disable_interrupts();
|
||||
acquire_spinlock(&dbg_spinlock);
|
||||
|
||||
cmd->next = sCommands;
|
||||
sCommands = cmd;
|
||||
|
||||
release_spinlock(&dbg_spinlock);
|
||||
restore_interrupts(state);
|
||||
|
||||
return B_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
remove_debugger_command(char * name, int (*func)(int, char **))
|
||||
{
|
||||
struct debugger_command *cmd = sCommands;
|
||||
struct debugger_command *prev = NULL;
|
||||
cpu_status state;
|
||||
|
||||
state = disable_interrupts();
|
||||
acquire_spinlock(&dbg_spinlock);
|
||||
|
||||
while (cmd) {
|
||||
if (!strcmp(cmd->name, name) && cmd->func == func)
|
||||
break;
|
||||
|
||||
prev = cmd;
|
||||
cmd = cmd->next;
|
||||
}
|
||||
|
||||
if (cmd) {
|
||||
if (cmd == sCommands)
|
||||
sCommands = cmd->next;
|
||||
else
|
||||
prev->next = cmd->next;
|
||||
}
|
||||
|
||||
release_spinlock(&dbg_spinlock);
|
||||
restore_interrupts(state);
|
||||
|
||||
if (cmd) {
|
||||
free(cmd);
|
||||
return B_NO_ERROR;
|
||||
}
|
||||
|
||||
return B_NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
parse_expression(const char *expression)
|
||||
{
|
||||
return strtoul(expression, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
panic(const char *fmt, ...)
|
||||
{
|
||||
int ret = 0;
|
||||
va_list args;
|
||||
char temp[128];
|
||||
cpu_status state;
|
||||
|
||||
// XXX by setting kernel_startup = true, we disable
|
||||
// XXX the interrupt check in semaphore code etc.
|
||||
// XXX should be renamed?
|
||||
kernel_startup = true;
|
||||
|
||||
set_dprintf_enabled(true);
|
||||
|
||||
state = disable_interrupts();
|
||||
|
||||
va_start(args, fmt);
|
||||
ret = vsprintf(temp, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
dprintf("PANIC%d: %s", smp_get_current_cpu(), temp);
|
||||
|
||||
if (debugger_on_cpu != smp_get_current_cpu()) {
|
||||
// halt all of the other cpus
|
||||
|
||||
// XXX need to flush current smp mailbox to make sure this goes
|
||||
// through. Otherwise it'll hang
|
||||
smp_send_broadcast_ici(SMP_MSG_CPU_HALT, 0, 0, 0, NULL, SMP_MSG_FLAG_SYNC);
|
||||
}
|
||||
|
||||
kernel_debugger(NULL);
|
||||
|
||||
restore_interrupts(state);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
kernel_debugger(const char * message)
|
||||
{
|
||||
arch_dbg_save_registers(&(dbg_register_file[smp_get_current_cpu()][0]));
|
||||
|
||||
if (message) {
|
||||
dprintf(message);
|
||||
dprintf("\n");
|
||||
};
|
||||
|
||||
dprintf("Welcome to Kernel Debugging Land...\n");
|
||||
kernel_debugger_loop();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
set_dprintf_enabled(bool newState)
|
||||
{
|
||||
bool oldState = sSerialDebugEnabled;
|
||||
sSerialDebugEnabled = newState;
|
||||
|
||||
return oldState;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
dprintf(const char *fmt, ...)
|
||||
{
|
||||
cpu_status state;
|
||||
va_list args;
|
||||
|
||||
if (!sSerialDebugEnabled)
|
||||
return;
|
||||
|
||||
// ToDo: maybe add a non-interrupt buffer and path that only
|
||||
// needs to acquire a semaphore instead of needing to disable
|
||||
// interrupts?
|
||||
|
||||
state = disable_interrupts();
|
||||
acquire_spinlock(&dbg_spinlock);
|
||||
|
||||
va_start(args, fmt);
|
||||
vsnprintf(sOutputBuffer, OUTPUT_BUFFER_SIZE, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
arch_dbg_con_puts(sOutputBuffer);
|
||||
|
||||
release_spinlock(&dbg_spinlock);
|
||||
restore_interrupts(state);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// userland syscalls
|
||||
|
||||
|
||||
void
|
||||
_user_debug_output(const char *userString)
|
||||
{
|
||||
char string[512];
|
||||
int32 length;
|
||||
|
||||
if (!sSerialDebugEnabled)
|
||||
return;
|
||||
|
||||
if (!IS_USER_ADDRESS(userString))
|
||||
return;
|
||||
|
||||
do {
|
||||
length = user_strlcpy(string, userString, sizeof(string));
|
||||
dbg_puts(string);
|
||||
userString += sizeof(string) - 1;
|
||||
} while (length >= (ssize_t)sizeof(string));
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
** Copyright 2001 Brian J. Swetland
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions, and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions, and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define CHAR_WIDTH 6
|
||||
#define CHAR_HEIGHT 12
|
||||
|
||||
static unsigned char FONT[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
|
||||
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, /* '!' */
|
||||
0x00, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '"' */
|
||||
0x00, 0x00, 0x14, 0x14, 0x3e, 0x14, 0x3e, 0x14, 0x14, 0x00, 0x00, 0x00, /* '#' */
|
||||
0x00, 0x00, 0x08, 0x3c, 0x0a, 0x1c, 0x28, 0x1e, 0x08, 0x00, 0x00, 0x00, /* '$' */
|
||||
0x00, 0x00, 0x06, 0x26, 0x10, 0x08, 0x04, 0x32, 0x30, 0x00, 0x00, 0x00, /* '%' */
|
||||
0x00, 0x00, 0x1c, 0x02, 0x02, 0x04, 0x2a, 0x12, 0x2c, 0x00, 0x00, 0x00, /* '&' */
|
||||
0x00, 0x18, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ''' */
|
||||
0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0x20, 0x00, /* '(' */
|
||||
0x02, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x02, 0x00, /* ')' */
|
||||
0x00, 0x00, 0x00, 0x08, 0x2a, 0x1c, 0x2a, 0x08, 0x00, 0x00, 0x00, 0x00, /* '*' */
|
||||
0x00, 0x00, 0x00, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* '+' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x08, 0x04, 0x00, /* ',' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '-' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, /* '.' */
|
||||
0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x04, 0x02, 0x02, 0x00, 0x00, /* '/' */
|
||||
0x00, 0x1c, 0x22, 0x32, 0x2a, 0x26, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '0' */
|
||||
0x00, 0x08, 0x0c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, /* '1' */
|
||||
0x00, 0x1c, 0x22, 0x20, 0x10, 0x08, 0x04, 0x02, 0x3e, 0x00, 0x00, 0x00, /* '2' */
|
||||
0x00, 0x1c, 0x22, 0x20, 0x18, 0x20, 0x20, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '3' */
|
||||
0x00, 0x20, 0x30, 0x28, 0x24, 0x22, 0x3e, 0x20, 0x20, 0x00, 0x00, 0x00, /* '4' */
|
||||
0x00, 0x3e, 0x02, 0x02, 0x1e, 0x20, 0x20, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '5' */
|
||||
0x00, 0x18, 0x04, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '6' */
|
||||
0x00, 0x3e, 0x22, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x00, 0x00, 0x00, /* '7' */
|
||||
0x00, 0x1c, 0x22, 0x22, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '8' */
|
||||
0x00, 0x1c, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x10, 0x0c, 0x00, 0x00, 0x00, /* '9' */
|
||||
0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, /* ':' */
|
||||
0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x08, 0x04, 0x00, /* ';' */
|
||||
0x00, 0x00, 0x00, 0x30, 0x0c, 0x03, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, /* '<' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, /* '=' */
|
||||
0x00, 0x00, 0x00, 0x03, 0x0c, 0x30, 0x0c, 0x03, 0x00, 0x00, 0x00, 0x00, /* '>' */
|
||||
0x00, 0x1c, 0x22, 0x20, 0x10, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, /* '?' */
|
||||
0x00, 0x00, 0x1c, 0x22, 0x3a, 0x3a, 0x1a, 0x02, 0x1c, 0x00, 0x00, 0x00, /* '@' */
|
||||
0x00, 0x00, 0x08, 0x14, 0x22, 0x22, 0x3e, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'A' */
|
||||
0x00, 0x00, 0x1e, 0x22, 0x22, 0x1e, 0x22, 0x22, 0x1e, 0x00, 0x00, 0x00, /* 'B' */
|
||||
0x00, 0x00, 0x1c, 0x22, 0x02, 0x02, 0x02, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'C' */
|
||||
0x00, 0x00, 0x0e, 0x12, 0x22, 0x22, 0x22, 0x12, 0x0e, 0x00, 0x00, 0x00, /* 'D' */
|
||||
0x00, 0x00, 0x3e, 0x02, 0x02, 0x1e, 0x02, 0x02, 0x3e, 0x00, 0x00, 0x00, /* 'E' */
|
||||
0x00, 0x00, 0x3e, 0x02, 0x02, 0x1e, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, /* 'F' */
|
||||
0x00, 0x00, 0x1c, 0x22, 0x02, 0x32, 0x22, 0x22, 0x3c, 0x00, 0x00, 0x00, /* 'G' */
|
||||
0x00, 0x00, 0x22, 0x22, 0x22, 0x3e, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'H' */
|
||||
0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, /* 'I' */
|
||||
0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'J' */
|
||||
0x00, 0x00, 0x22, 0x12, 0x0a, 0x06, 0x0a, 0x12, 0x22, 0x00, 0x00, 0x00, /* 'K' */
|
||||
0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x3e, 0x00, 0x00, 0x00, /* 'L' */
|
||||
0x00, 0x00, 0x22, 0x36, 0x2a, 0x2a, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'M' */
|
||||
0x00, 0x00, 0x22, 0x26, 0x26, 0x2a, 0x32, 0x32, 0x22, 0x00, 0x00, 0x00, /* 'N' */
|
||||
0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'O' */
|
||||
0x00, 0x00, 0x1e, 0x22, 0x22, 0x1e, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, /* 'P' */
|
||||
0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x30, 0x00, 0x00, /* 'Q' */
|
||||
0x00, 0x00, 0x1e, 0x22, 0x22, 0x1e, 0x0a, 0x12, 0x22, 0x00, 0x00, 0x00, /* 'R' */
|
||||
0x00, 0x00, 0x1c, 0x22, 0x02, 0x1c, 0x20, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'S' */
|
||||
0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, /* 'T' */
|
||||
0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'U' */
|
||||
0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, 0x00, /* 'V' */
|
||||
0x00, 0x00, 0x22, 0x22, 0x22, 0x2a, 0x2a, 0x36, 0x22, 0x00, 0x00, 0x00, /* 'W' */
|
||||
0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'X' */
|
||||
0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, /* 'Y' */
|
||||
0x00, 0x00, 0x3e, 0x20, 0x10, 0x08, 0x04, 0x02, 0x3e, 0x00, 0x00, 0x00, /* 'Z' */
|
||||
0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, /* '[' */
|
||||
0x02, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x00, 0x00, /* '\' */
|
||||
0x0e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0e, 0x00, /* ']' */
|
||||
0x00, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '^' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, /* '_' */
|
||||
0x00, 0x0c, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '`' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x3c, 0x22, 0x22, 0x32, 0x2c, 0x00, 0x00, 0x00, /* 'a' */
|
||||
0x00, 0x02, 0x02, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x1e, 0x00, 0x00, 0x00, /* 'b' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x02, 0x02, 0x3c, 0x00, 0x00, 0x00, /* 'c' */
|
||||
0x00, 0x20, 0x20, 0x20, 0x3c, 0x22, 0x22, 0x22, 0x3c, 0x00, 0x00, 0x00, /* 'd' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x3e, 0x02, 0x1c, 0x00, 0x00, 0x00, /* 'e' */
|
||||
0x00, 0x38, 0x04, 0x04, 0x1e, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, /* 'f' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x3c, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x20, 0x1c, /* 'g' */
|
||||
0x00, 0x02, 0x02, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'h' */
|
||||
0x00, 0x08, 0x08, 0x00, 0x0c, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, /* 'i' */
|
||||
0x00, 0x10, 0x10, 0x00, 0x1c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0e, /* 'j' */
|
||||
0x00, 0x02, 0x02, 0x02, 0x12, 0x0a, 0x06, 0x0a, 0x12, 0x00, 0x00, 0x00, /* 'k' */
|
||||
0x00, 0x0c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, /* 'l' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x16, 0x2a, 0x2a, 0x2a, 0x22, 0x00, 0x00, 0x00, /* 'm' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x1a, 0x26, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'n' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'o' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x1e, 0x22, 0x22, 0x22, 0x1e, 0x02, 0x02, 0x02, /* 'p' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x3c, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x20, 0x20, /* 'q' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x1a, 0x06, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, /* 'r' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x1c, 0x20, 0x1e, 0x00, 0x00, 0x00, /* 's' */
|
||||
0x00, 0x08, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x08, 0x30, 0x00, 0x00, 0x00, /* 't' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x32, 0x2c, 0x00, 0x00, 0x00, /* 'u' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x36, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, 0x00, /* 'v' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x22, 0x2a, 0x2a, 0x2a, 0x14, 0x00, 0x00, 0x00, /* 'w' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, /* 'x' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x20, 0x1c, /* 'y' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x3e, 0x10, 0x08, 0x04, 0x3e, 0x00, 0x00, 0x00, /* 'z' */
|
||||
0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x10, 0x10, 0x10, 0x10, 0x20, 0x00, /* '{' */
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, /* '|' */
|
||||
0x02, 0x04, 0x04, 0x04, 0x04, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x00, /* '}' */
|
||||
0x00, 0x04, 0x2a, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '~' */
|
||||
0x00, 0x00, 0x00, 0x08, 0x08, 0x14, 0x14, 0x22, 0x3e, 0x00, 0x00, 0x00, /* '' */
|
||||
};
|
||||
@@ -0,0 +1,404 @@
|
||||
/*
|
||||
* Copyright 2005, Axel Dörfler, [email protected]. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <lock.h>
|
||||
#include <boot_item.h>
|
||||
#include <fs/devfs.h>
|
||||
#include <boot/kernel_args.h>
|
||||
|
||||
#include <frame_buffer_console.h>
|
||||
#include "font.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
//#define TRACE_FB_CONSOLE
|
||||
#ifdef TRACE_FB_CONSOLE
|
||||
# define TRACE(x) dprintf x
|
||||
#else
|
||||
# define TRACE(x) ;
|
||||
#endif
|
||||
|
||||
|
||||
struct console_info {
|
||||
mutex lock;
|
||||
area_id area;
|
||||
|
||||
addr_t frame_buffer;
|
||||
int32 width;
|
||||
int32 height;
|
||||
int32 depth;
|
||||
int32 bytes_per_pixel;
|
||||
int32 bytes_per_row;
|
||||
|
||||
int32 columns;
|
||||
int32 rows;
|
||||
int32 cursor_x;
|
||||
int32 cursor_y;
|
||||
};
|
||||
|
||||
// Palette is (white and black are exchanged):
|
||||
// 0 - white, 1 - blue, 2 - green, 3 - cyan, 4 - red, 5 - magenta, 6 - yellow, 7 - black
|
||||
// 8-15 - same but bright (we're ignoring those)
|
||||
|
||||
static uint8 sPalette8[] = {
|
||||
63, 32, 52, 70, 42, 88, 67, 0,
|
||||
};
|
||||
static uint16 sPalette15[] = {
|
||||
// 0bbbbbgggggrrrrr (5-5-5)
|
||||
0x7fff, 0x001f, 0x03e0, 0x03ff, 0x7c00, 0x7c1f, 0x7fe0, 0x0000,
|
||||
};
|
||||
static uint16 sPalette16[] = {
|
||||
// bbbbbggggggrrrrr (5-6-5)
|
||||
0xffff, 0x001f, 0x07e0, 0x07ff, 0xf800, 0xf81f, 0xffe0, 0x0000,
|
||||
};
|
||||
static uint32 sPalette32[] = {
|
||||
// is also used by 24 bit modes
|
||||
0xffffff, 0x0000ff, 0x00ff00, 0x00ffff, 0xff0000, 0xff00ff, 0xffff00, 0x000000,
|
||||
};
|
||||
|
||||
static struct console_info sConsole;
|
||||
static struct frame_buffer_boot_info sBootInfo;
|
||||
|
||||
|
||||
static inline uint8
|
||||
foreground_color(uint8 attr)
|
||||
{
|
||||
return attr & 0x7;
|
||||
}
|
||||
|
||||
|
||||
static inline uint8
|
||||
background_color(uint8 attr)
|
||||
{
|
||||
return (attr >> 4) & 0x7;
|
||||
}
|
||||
|
||||
|
||||
static uint8 *
|
||||
get_palette_entry(uint8 index)
|
||||
{
|
||||
switch (sConsole.depth) {
|
||||
case 8:
|
||||
return &sPalette8[index];
|
||||
case 15:
|
||||
return (uint8 *)&sPalette15[index];
|
||||
case 16:
|
||||
return (uint8 *)&sPalette16[index];
|
||||
default:
|
||||
return (uint8 *)&sPalette32[index];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
render_glyph(int32 x, int32 y, uint8 glyph, uint8 attr)
|
||||
{
|
||||
if (sConsole.depth >= 8) {
|
||||
uint8 *base = (uint8 *)(sConsole.frame_buffer + sConsole.bytes_per_row * y * CHAR_HEIGHT
|
||||
+ x * CHAR_WIDTH * sConsole.bytes_per_pixel);
|
||||
uint8 *color = get_palette_entry(foreground_color(attr));
|
||||
uint8 *backgroundColor = get_palette_entry(background_color(attr));
|
||||
|
||||
for (y = 0; y < CHAR_HEIGHT; y++) {
|
||||
uint8 bits = FONT[CHAR_HEIGHT * glyph + y];
|
||||
for (x = 0; x < CHAR_WIDTH; x++) {
|
||||
for (int32 i = 0; i < sConsole.bytes_per_pixel; i++) {
|
||||
if (bits & 1)
|
||||
base[x * sConsole.bytes_per_pixel + i] = color[i];
|
||||
else
|
||||
base[x * sConsole.bytes_per_pixel + i] = backgroundColor[i];
|
||||
}
|
||||
bits >>= 1;
|
||||
}
|
||||
|
||||
base += sConsole.bytes_per_row;
|
||||
}
|
||||
} else {
|
||||
// monochrome mode
|
||||
|
||||
uint8 *base = (uint8 *)(sConsole.frame_buffer + sConsole.bytes_per_row * y * CHAR_HEIGHT
|
||||
+ x * CHAR_WIDTH / 8);
|
||||
uint8 baseOffset = (x * CHAR_WIDTH) & 0x7;
|
||||
|
||||
for (y = 0; y < CHAR_HEIGHT; y++) {
|
||||
uint8 bits = FONT[CHAR_HEIGHT * glyph + y];
|
||||
uint8 offset = baseOffset;
|
||||
uint8 mask = 1 << (7 - baseOffset);
|
||||
|
||||
for (x = 0; x < CHAR_WIDTH; x++) {
|
||||
if (mask == 0)
|
||||
mask = 128;
|
||||
|
||||
// black on white
|
||||
if (bits & 1)
|
||||
base[offset / 8] &= ~mask;
|
||||
else
|
||||
base[offset / 8] |= mask;
|
||||
|
||||
bits >>= 1;
|
||||
mask >>= 1;
|
||||
offset += 1;
|
||||
}
|
||||
|
||||
base += sConsole.bytes_per_row;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
draw_cursor(int32 x, int32 y)
|
||||
{
|
||||
if (x < 0 || y < 0)
|
||||
return;
|
||||
|
||||
x *= CHAR_WIDTH * sConsole.bytes_per_pixel;
|
||||
y *= CHAR_HEIGHT;
|
||||
int32 endX = x + CHAR_WIDTH * sConsole.bytes_per_pixel;
|
||||
int32 endY = y + CHAR_HEIGHT;
|
||||
uint8 *base = (uint8 *)(sConsole.frame_buffer + y * sConsole.bytes_per_row);
|
||||
|
||||
if (sConsole.depth < 8) {
|
||||
x /= 8;
|
||||
endY /= 8;
|
||||
}
|
||||
|
||||
for (; y < endY; y++) {
|
||||
for (int32 x2 = x; x2 < endX; x2++)
|
||||
base[x2] = ~base[x2];
|
||||
|
||||
base += sConsole.bytes_per_row;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
console_get_size(int32 *_width, int32 *_height)
|
||||
{
|
||||
*_width = sConsole.columns;
|
||||
*_height = sConsole.rows;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
console_move_cursor(int32 x, int32 y)
|
||||
{
|
||||
draw_cursor(sConsole.cursor_x, sConsole.cursor_y);
|
||||
draw_cursor(x, y);
|
||||
|
||||
sConsole.cursor_x = x;
|
||||
sConsole.cursor_y = y;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
console_put_glyph(int32 x, int32 y, uint8 glyph, uint8 attr)
|
||||
{
|
||||
if (x >= sConsole.columns || y >= sConsole.rows)
|
||||
return;
|
||||
|
||||
render_glyph(x, y, glyph, attr);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
console_fill_glyph(int32 x, int32 y, int32 width, int32 height, uint8 glyph, uint8 attr)
|
||||
{
|
||||
if (x >= sConsole.columns || y >= sConsole.rows)
|
||||
return;
|
||||
|
||||
int32 left = x + width;
|
||||
if (left > sConsole.columns)
|
||||
left = sConsole.columns;
|
||||
|
||||
int32 bottom = y + height;
|
||||
if (bottom > sConsole.rows)
|
||||
bottom = sConsole.rows;
|
||||
|
||||
for (; y < bottom; y++) {
|
||||
for (int32 x2 = x; x2 < left; x2++) {
|
||||
render_glyph(x2, y, glyph, attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
console_blit(int32 srcx, int32 srcy, int32 width, int32 height, int32 destx, int32 desty)
|
||||
{
|
||||
height *= CHAR_HEIGHT;
|
||||
srcy *= CHAR_HEIGHT;
|
||||
desty *= CHAR_HEIGHT;
|
||||
|
||||
if (sConsole.depth >= 8) {
|
||||
width *= CHAR_WIDTH * sConsole.bytes_per_pixel;
|
||||
srcx *= CHAR_WIDTH * sConsole.bytes_per_pixel;
|
||||
destx *= CHAR_WIDTH * sConsole.bytes_per_pixel;
|
||||
} else {
|
||||
// monochrome mode
|
||||
width = width * CHAR_WIDTH / 8;
|
||||
srcx = srcx * CHAR_WIDTH / 8;
|
||||
destx = destx * CHAR_WIDTH / 8;
|
||||
}
|
||||
|
||||
for (int32 y = 0; y < height; y++) {
|
||||
memmove((void *)(sConsole.frame_buffer + (desty + y) * sConsole.bytes_per_row + destx),
|
||||
(void *)(sConsole.frame_buffer + (srcy + y) * sConsole.bytes_per_row + srcx), width);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
console_clear(uint8 attr)
|
||||
{
|
||||
switch (sConsole.bytes_per_pixel) {
|
||||
case 1:
|
||||
if (sConsole.depth >= 8) {
|
||||
memset((void *)sConsole.frame_buffer, sPalette8[background_color(attr)],
|
||||
sConsole.height * sConsole.bytes_per_row);
|
||||
} else {
|
||||
// special case for VGA mode
|
||||
memset((void *)sConsole.frame_buffer, 0xff,
|
||||
sConsole.height * sConsole.bytes_per_row);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
uint8 *base = (uint8 *)sConsole.frame_buffer;
|
||||
uint8 *color = get_palette_entry(background_color(attr));
|
||||
|
||||
for (int32 y = 0; y < sConsole.height; y++) {
|
||||
for (int32 x = 0; x < sConsole.width; x++) {
|
||||
for (int32 i = 0; i < sConsole.bytes_per_pixel; i++) {
|
||||
base[x * sConsole.bytes_per_pixel + i] = color[i];
|
||||
}
|
||||
}
|
||||
base += sConsole.bytes_per_row;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sConsole.cursor_x = -1;
|
||||
sConsole.cursor_y = -1;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
console_std_ops(int32 op, ...)
|
||||
{
|
||||
switch (op) {
|
||||
case B_MODULE_INIT:
|
||||
return sConsole.frame_buffer != NULL ? B_OK : B_ERROR;
|
||||
case B_MODULE_UNINIT:
|
||||
return B_OK;
|
||||
|
||||
default:
|
||||
return B_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
console_module_info gFrameBufferConsoleModule = {
|
||||
{
|
||||
FRAME_BUFFER_CONSOLE_MODULE_NAME,
|
||||
0,
|
||||
console_std_ops
|
||||
},
|
||||
&console_get_size,
|
||||
&console_move_cursor,
|
||||
&console_put_glyph,
|
||||
&console_fill_glyph,
|
||||
&console_blit,
|
||||
&console_clear,
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
status_t
|
||||
frame_buffer_update(addr_t baseAddress, int32 width, int32 height, int32 depth, int32 bytesPerRow)
|
||||
{
|
||||
TRACE(("frame_buffer_update(buffer = %p, width = %ld, height = %ld, depth = %ld, bytesPerRow = %ld)\n",
|
||||
(void *)baseAddress, width, height, depth, bytesPerRow));
|
||||
|
||||
mutex_lock(&sConsole.lock);
|
||||
|
||||
sConsole.frame_buffer = baseAddress;
|
||||
sConsole.width = width;
|
||||
sConsole.height = height;
|
||||
sConsole.depth = depth;
|
||||
sConsole.bytes_per_pixel = (depth + 7) / 8;
|
||||
sConsole.bytes_per_row = bytesPerRow;
|
||||
sConsole.columns = sConsole.width / CHAR_WIDTH;
|
||||
sConsole.rows = sConsole.height / CHAR_HEIGHT;
|
||||
|
||||
// initially, the cursor is hidden
|
||||
sConsole.cursor_x = -1;
|
||||
sConsole.cursor_y = -1;
|
||||
|
||||
TRACE(("framebuffer mapped at %p, %ld columns, %ld rows\n",
|
||||
(void *)sConsole.frame_buffer, sConsole.columns, sConsole.rows));
|
||||
|
||||
mutex_unlock(&sConsole.lock);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
frame_buffer_console_init(kernel_args *args)
|
||||
{
|
||||
if (!args->frame_buffer.enabled)
|
||||
return B_OK;
|
||||
|
||||
void *frameBuffer;
|
||||
sConsole.area = map_physical_memory("vesa_fb",
|
||||
(void *)args->frame_buffer.physical_buffer.start,
|
||||
args->frame_buffer.physical_buffer.size, B_ANY_KERNEL_ADDRESS,
|
||||
B_READ_AREA | B_WRITE_AREA | B_USER_CLONEABLE_AREA, &frameBuffer);
|
||||
if (sConsole.area < B_OK)
|
||||
return sConsole.area;
|
||||
|
||||
mutex_init(&sConsole.lock, "console_lock");
|
||||
|
||||
int32 bytesPerRow = args->frame_buffer.width;
|
||||
switch (args->frame_buffer.depth) {
|
||||
case 1:
|
||||
case 4:
|
||||
// special VGA mode (will always be treated as monochrome)
|
||||
bytesPerRow /= 8;
|
||||
break;
|
||||
case 15:
|
||||
case 16:
|
||||
bytesPerRow *= 2;
|
||||
break;
|
||||
case 24:
|
||||
bytesPerRow *= 3;
|
||||
break;
|
||||
case 32:
|
||||
bytesPerRow *= 4;
|
||||
break;
|
||||
}
|
||||
frame_buffer_update((addr_t)frameBuffer, args->frame_buffer.width, args->frame_buffer.height,
|
||||
args->frame_buffer.depth, bytesPerRow);
|
||||
|
||||
sBootInfo.frame_buffer = (addr_t)frameBuffer;
|
||||
sBootInfo.width = args->frame_buffer.width;
|
||||
sBootInfo.height = args->frame_buffer.height;
|
||||
sBootInfo.depth = args->frame_buffer.depth;
|
||||
sBootInfo.bytes_per_row = bytesPerRow;
|
||||
add_boot_item(FRAME_BUFFER_BOOT_INFO, &sBootInfo, sizeof(frame_buffer_boot_info));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,504 @@
|
||||
/* Contains the code to interface with a remote GDB */
|
||||
|
||||
/*
|
||||
** Copyright 2002, Manuel J. Petit. All rights reserved.
|
||||
** Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <vm.h>
|
||||
#include <smp.h>
|
||||
#include <debug.h>
|
||||
#include <gdb.h>
|
||||
#include <arch/dbg_console.h>
|
||||
|
||||
|
||||
enum { INIT= 0, CMDREAD, CKSUM1, CKSUM2, WAITACK, QUIT, GDBSTATES };
|
||||
|
||||
|
||||
static char cmd[512];
|
||||
static int cmd_ptr;
|
||||
static int checksum;
|
||||
|
||||
static char reply[512];
|
||||
|
||||
static char safe_mem[512];
|
||||
|
||||
|
||||
/*
|
||||
* utility functions
|
||||
*/
|
||||
|
||||
static int
|
||||
parse_nibble(int input)
|
||||
{
|
||||
int nibble = 0xff;
|
||||
|
||||
if (input >= '0' && input <= '9')
|
||||
nibble = input - '0';
|
||||
|
||||
if (input >= 'A' && input <= 'F')
|
||||
nibble = 0x0a + input - 'A';
|
||||
|
||||
if (input >= 'a' && input <= 'f')
|
||||
nibble = 0x0a + input - 'a';
|
||||
|
||||
return nibble;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* GDB protocol ACK & NAK & Reply
|
||||
*
|
||||
*/
|
||||
|
||||
static void
|
||||
gdb_ack(void)
|
||||
{
|
||||
dbg_putch('+');
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gdb_nak(void)
|
||||
{
|
||||
dbg_putch('-');
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gdb_resend_reply(void)
|
||||
{
|
||||
dbg_puts(reply);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gdb_reply(char const *fmt, ...)
|
||||
{
|
||||
int i;
|
||||
int len;
|
||||
int sum;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
reply[0] = '$';
|
||||
vsprintf(reply + 1, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
len = strlen(reply);
|
||||
sum = 0;
|
||||
for (i = 1; i < len; i++) {
|
||||
sum += reply[i];
|
||||
}
|
||||
sum %= 256;
|
||||
|
||||
sprintf(reply + len, "#%02x", sum);
|
||||
|
||||
gdb_resend_reply();
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gdb_regreply(int const *regs, int numregs)
|
||||
{
|
||||
int i;
|
||||
int len;
|
||||
int sum;
|
||||
|
||||
reply[0] = '$';
|
||||
for (i = 0; i < numregs; i++) {
|
||||
sprintf(reply+1+8*i, "%08lx", B_HOST_TO_BENDIAN_INT32(regs[i]));
|
||||
}
|
||||
|
||||
len = strlen(reply);
|
||||
sum = 0;
|
||||
for (i = 1; i < len; i++) {
|
||||
sum += reply[i];
|
||||
}
|
||||
sum %= 256;
|
||||
|
||||
sprintf(reply + len, "#%02x", sum);
|
||||
|
||||
gdb_resend_reply();
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gdb_memreply(char const *bytes, int numbytes)
|
||||
{
|
||||
int i;
|
||||
int len;
|
||||
int sum;
|
||||
|
||||
reply[0] = '$';
|
||||
for (i = 0; i < numbytes; i++) {
|
||||
sprintf(reply+1+2*i, "%02x", (uint8)bytes[i]);
|
||||
}
|
||||
|
||||
len = strlen(reply);
|
||||
sum = 0;
|
||||
for (i = 1; i < len; i++) {
|
||||
sum += reply[i];
|
||||
}
|
||||
sum %= 256;
|
||||
|
||||
sprintf(reply + len, "#%02x", sum);
|
||||
|
||||
gdb_resend_reply();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* checksum verification
|
||||
*/
|
||||
|
||||
static int
|
||||
gdb_verify_checksum(void)
|
||||
{
|
||||
int i;
|
||||
int len;
|
||||
int sum;
|
||||
|
||||
len = strlen(cmd);
|
||||
sum = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
sum += cmd[i];
|
||||
}
|
||||
sum %= 256;
|
||||
|
||||
return (sum == checksum) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* command parsing an dispatching
|
||||
*/
|
||||
|
||||
static int
|
||||
gdb_parse_command(void)
|
||||
{
|
||||
if (!gdb_verify_checksum()) {
|
||||
gdb_nak();
|
||||
return INIT;
|
||||
} else
|
||||
gdb_ack();
|
||||
|
||||
switch (cmd[0]) {
|
||||
case 'H':
|
||||
/*
|
||||
* Command H (actually Hct) is used to select
|
||||
* the current thread (-1 meaning all threads)
|
||||
* We just fake we recognize the the command
|
||||
* and send an 'OK' response.
|
||||
*/
|
||||
gdb_reply("OK");
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
{
|
||||
extern unsigned __data_start;
|
||||
extern unsigned __bss_start;
|
||||
|
||||
/*
|
||||
* There are several q commands:
|
||||
*
|
||||
* qXXXX Request info about XXXX.
|
||||
* QXXXX=yyyy Set value of XXXX to yyyy.
|
||||
* qOffsets Get segment offsets
|
||||
*
|
||||
* Currently we only support the 'qOffsets'
|
||||
* form.
|
||||
*
|
||||
* *Note* that we actually have to lie,
|
||||
* At first thought looks like we should
|
||||
* return '_start', '__data_start' &
|
||||
* '__bss_start', however gdb gets
|
||||
* confused because the kernel link script
|
||||
* pre-links at 0x80000000. To keep gdb
|
||||
* gdb happy we just substract that amount.
|
||||
*/
|
||||
if (strcmp(cmd+1, "Offsets") == 0) {
|
||||
gdb_reply("Text=%x;Data=%x;Bss=%x", 0,
|
||||
((unsigned)(&__data_start))-0x80000000,
|
||||
((unsigned)(&__bss_start))-0x80000000);
|
||||
} else
|
||||
gdb_reply("ENS");
|
||||
}
|
||||
break;
|
||||
|
||||
case '?':
|
||||
/*
|
||||
* command '?' is used for retrieving the signal
|
||||
* that stopped the program. Fully implemeting
|
||||
* this command requires help from the debugger,
|
||||
* by now we just fake a SIGKILL
|
||||
*/
|
||||
gdb_reply("S09"); /* SIGKILL = 9 */
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
{
|
||||
int cpu;
|
||||
|
||||
/*
|
||||
* command 'g' is used for reading the register
|
||||
* file. Faked by now.
|
||||
*
|
||||
* For x86 the register order is:
|
||||
*
|
||||
* eax, ebx, ecx, edx,
|
||||
* esp, ebp, esi, edi,
|
||||
* eip, eflags,
|
||||
* cs, ss, ds, es
|
||||
*
|
||||
* Note that even thought the segment descriptors
|
||||
* are actually 16 bits wide, gdb requires them
|
||||
* as 32 bit integers. Note also that for some
|
||||
* reason (unknown to me) gdb wants the register
|
||||
* dump in *big endian* format.
|
||||
*/
|
||||
cpu = smp_get_current_cpu();
|
||||
gdb_regreply(dbg_register_file[cpu], 14);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
{
|
||||
char *ptr;
|
||||
unsigned address;
|
||||
unsigned len;
|
||||
|
||||
/*
|
||||
* The 'm' command has the form mAAA,LLL
|
||||
* where AAA is the address and LLL is the
|
||||
* number of bytes.
|
||||
*/
|
||||
ptr = cmd+1;
|
||||
address = 0;
|
||||
len = 0;
|
||||
while (ptr && *ptr && (*ptr != ',')) {
|
||||
address <<= 4;
|
||||
address += parse_nibble(*ptr);
|
||||
ptr += 1;
|
||||
}
|
||||
if (*ptr == ',')
|
||||
ptr+= 1;
|
||||
|
||||
while (ptr && *ptr) {
|
||||
len <<= 4;
|
||||
len += parse_nibble(*ptr);
|
||||
ptr += 1;
|
||||
}
|
||||
|
||||
if (len> 128)
|
||||
len = 128;
|
||||
|
||||
/*
|
||||
* We cannot directly access the requested memory
|
||||
* for gdb may be trying to access an stray pointer
|
||||
* We copy the memory to a safe buffer using
|
||||
* the bulletproof user_memcpy().
|
||||
*/
|
||||
if (user_memcpy(safe_mem, (char *)address, len) < 0)
|
||||
gdb_reply("E02");
|
||||
else
|
||||
gdb_memreply(safe_mem, len);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
/*
|
||||
* Command 'k' actual semantics is 'kill the damn thing'.
|
||||
* However gdb sends that command when you disconnect
|
||||
* from a debug session. I guess that 'kill' for the
|
||||
* kernel would map to reboot... however that's a
|
||||
* a very mean thing to do, instead we just quit
|
||||
* the gdb state machine and fallback to the regular
|
||||
* kernel debugger command prompt.
|
||||
*/
|
||||
return QUIT;
|
||||
|
||||
default:
|
||||
gdb_reply("E01");
|
||||
break;
|
||||
}
|
||||
|
||||
return WAITACK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* GDB protocol state machine
|
||||
*/
|
||||
|
||||
static int
|
||||
gdb_init_handler(int input)
|
||||
{
|
||||
switch (input) {
|
||||
case '$':
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
cmd_ptr = 0;
|
||||
return CMDREAD;
|
||||
|
||||
default:
|
||||
#if 0
|
||||
gdb_nak();
|
||||
#else
|
||||
/*
|
||||
* looks to me like we should send
|
||||
* a NAK here but it kinda works
|
||||
* better if we just gobble all
|
||||
* junk chars silently
|
||||
*/
|
||||
#endif
|
||||
return INIT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
gdb_cmdread_handler(int input)
|
||||
{
|
||||
switch (input) {
|
||||
case '#':
|
||||
return CKSUM1;
|
||||
|
||||
default:
|
||||
cmd[cmd_ptr] = input;
|
||||
cmd_ptr += 1;
|
||||
return CMDREAD;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
gdb_cksum1_handler(int input)
|
||||
{
|
||||
int nibble = parse_nibble(input);
|
||||
|
||||
if (nibble == 0xff) {
|
||||
#if 0
|
||||
gdb_nak();
|
||||
return INIT;
|
||||
#else
|
||||
/*
|
||||
* looks to me like we should send
|
||||
* a NAK here but it kinda works
|
||||
* better if we just gobble all
|
||||
* junk chars silently
|
||||
*/
|
||||
#endif
|
||||
}
|
||||
|
||||
checksum = nibble << 4;
|
||||
|
||||
return CKSUM2;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
gdb_cksum2_handler(int input)
|
||||
{
|
||||
int nibble = parse_nibble(input);
|
||||
|
||||
if (nibble == 0xff) {
|
||||
#if 0
|
||||
gdb_nak();
|
||||
return INIT;
|
||||
#else
|
||||
/*
|
||||
* looks to me like we should send
|
||||
* a NAK here but it kinda works
|
||||
* better if we just gobble all
|
||||
* junk chars silently
|
||||
*/
|
||||
#endif
|
||||
}
|
||||
|
||||
checksum += nibble;
|
||||
|
||||
return gdb_parse_command();
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
gdb_waitack_handler(int input)
|
||||
{
|
||||
switch (input) {
|
||||
case '+':
|
||||
return INIT;
|
||||
case '-':
|
||||
gdb_resend_reply();
|
||||
return WAITACK;
|
||||
|
||||
default:
|
||||
/*
|
||||
* looks like gdb and us are out of synch,
|
||||
* send a NAK and retry from INIT state.
|
||||
*/
|
||||
gdb_nak();
|
||||
return INIT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
gdb_quit_handler(int input)
|
||||
{
|
||||
(void)(input);
|
||||
|
||||
/*
|
||||
* actually we should never be here
|
||||
*/
|
||||
return QUIT;
|
||||
}
|
||||
|
||||
|
||||
static int (*dispatch_table[GDBSTATES])(int) = {
|
||||
&gdb_init_handler,
|
||||
&gdb_cmdread_handler,
|
||||
&gdb_cksum1_handler,
|
||||
&gdb_cksum2_handler,
|
||||
&gdb_waitack_handler,
|
||||
&gdb_quit_handler
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
gdb_state_dispatch(int curr, int input)
|
||||
{
|
||||
if (curr < INIT || curr >= GDBSTATES)
|
||||
return QUIT;
|
||||
|
||||
return dispatch_table[curr](input);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
gdb_state_machine(void)
|
||||
{
|
||||
int state = INIT;
|
||||
int c;
|
||||
|
||||
while (state != QUIT) {
|
||||
c = arch_dbg_con_read();
|
||||
state = gdb_state_dispatch(state, c);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cmd_gdb(int argc, char **argv)
|
||||
{
|
||||
(void)(argc);
|
||||
(void)(argv);
|
||||
|
||||
return gdb_state_machine();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user