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:
Axel Dörfler
2005-04-13 13:22:10 +00:00
parent 5af32e7526
commit 2d690920ac
212 changed files with 0 additions and 0 deletions
+13
View File
@@ -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
;
+75
View File
@@ -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;
}
+569
View File
@@ -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));
}
+160
View File
@@ -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;
}
+504
View File
@@ -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