Commit 9732b611 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/mingo/linux-2.6-kgdb

* git://git.kernel.org/pub/scm/linux/kernel/git/mingo/linux-2.6-kgdb:
  kgdb: always use icache flush for sw breakpoints
  kgdb: fix SMP NMI kgdb_handle_exception exit race
  kgdb: documentation fixes
  kgdb: allow static kgdbts boot configuration
  kgdb: add documentation
  kgdb: Kconfig fix
  kgdb: add kgdb internal test suite
  kgdb: fix several kgdb regressions
  kgdb: kgdboc pl011 I/O module
  kgdb: fix optional arch functions and probe_kernel_*
  kgdb: add x86 HW breakpoints
  kgdb: print breakpoint removed on exception
  kgdb: clocksource watchdog
  kgdb: fix NMI hangs
  kgdb: fix kgdboc dynamic module configuration
  kgdb: document parameters
  x86: kgdb support
  consoles: polling support, kgdboc
  kgdb: core
  uaccess: add probe_kernel_write()
parents 9e9abecf 1a9a3e76
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \ DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \
kernel-hacking.xml kernel-locking.xml deviceiobook.xml \ kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
procfs-guide.xml writing_usb_driver.xml networking.xml \ procfs-guide.xml writing_usb_driver.xml networking.xml \
kernel-api.xml filesystems.xml lsm.xml usb.xml \ kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \
gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \ gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml
......
This diff is collapsed.
...@@ -941,6 +941,11 @@ and is between 256 and 4096 characters. It is defined in the file ...@@ -941,6 +941,11 @@ and is between 256 and 4096 characters. It is defined in the file
kstack=N [X86-32,X86-64] Print N words from the kernel stack kstack=N [X86-32,X86-64] Print N words from the kernel stack
in oops dumps. in oops dumps.
kgdboc= [HW] kgdb over consoles.
Requires a tty driver that supports console polling.
(only serial suported for now)
Format: <serial_device>[,baud]
l2cr= [PPC] l2cr= [PPC]
lapic [X86-32,APIC] Enable the local APIC even if BIOS lapic [X86-32,APIC] Enable the local APIC even if BIOS
......
...@@ -2319,6 +2319,12 @@ L: linux-kernel@vger.kernel.org ...@@ -2319,6 +2319,12 @@ L: linux-kernel@vger.kernel.org
L: kexec@lists.infradead.org L: kexec@lists.infradead.org
S: Maintained S: Maintained
KGDB
P: Jason Wessel
M: jason.wessel@windriver.com
L: kgdb-bugreport@lists.sourceforge.net
S: Maintained
KPROBES KPROBES
P: Ananth N Mavinakayanahalli P: Ananth N Mavinakayanahalli
M: ananth@in.ibm.com M: ananth@in.ibm.com
......
...@@ -23,6 +23,7 @@ config X86 ...@@ -23,6 +23,7 @@ config X86
select HAVE_KPROBES select HAVE_KPROBES
select HAVE_KRETPROBES select HAVE_KRETPROBES
select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64) select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64)
select HAVE_ARCH_KGDB
config GENERIC_LOCKBREAK config GENERIC_LOCKBREAK
......
...@@ -67,6 +67,7 @@ obj-$(CONFIG_MODULES) += module_$(BITS).o ...@@ -67,6 +67,7 @@ obj-$(CONFIG_MODULES) += module_$(BITS).o
obj-$(CONFIG_ACPI_SRAT) += srat_32.o obj-$(CONFIG_ACPI_SRAT) += srat_32.o
obj-$(CONFIG_EFI) += efi.o efi_$(BITS).o efi_stub_$(BITS).o obj-$(CONFIG_EFI) += efi.o efi_$(BITS).o efi_stub_$(BITS).o
obj-$(CONFIG_DOUBLEFAULT) += doublefault_32.o obj-$(CONFIG_DOUBLEFAULT) += doublefault_32.o
obj-$(CONFIG_KGDB) += kgdb.o
obj-$(CONFIG_VM86) += vm86_32.o obj-$(CONFIG_VM86) += vm86_32.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
......
This diff is collapsed.
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kgdb.h>
#include <asm/pda.h> #include <asm/pda.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/processor.h> #include <asm/processor.h>
...@@ -251,6 +252,17 @@ void __cpuinit cpu_init (void) ...@@ -251,6 +252,17 @@ void __cpuinit cpu_init (void)
load_TR_desc(); load_TR_desc();
load_LDT(&init_mm.context); load_LDT(&init_mm.context);
#ifdef CONFIG_KGDB
/*
* If the kgdb is connected no debug regs should be altered. This
* is only applicable when KGDB and a KGDB I/O module are built
* into the kernel and you are using early debugging with
* kgdbwait. KGDB will control the kernel HW breakpoint registers.
*/
if (kgdb_connected && arch_kgdb_ops.correct_hw_break)
arch_kgdb_ops.correct_hw_break();
else {
#endif
/* /*
* Clear all 6 debug registers: * Clear all 6 debug registers:
*/ */
...@@ -261,6 +273,10 @@ void __cpuinit cpu_init (void) ...@@ -261,6 +273,10 @@ void __cpuinit cpu_init (void)
set_debugreg(0UL, 3); set_debugreg(0UL, 3);
set_debugreg(0UL, 6); set_debugreg(0UL, 6);
set_debugreg(0UL, 7); set_debugreg(0UL, 7);
#ifdef CONFIG_KGDB
/* If the kgdb is connected no debug regs should be altered. */
}
#endif
fpu_init(); fpu_init();
......
...@@ -730,6 +730,8 @@ io_check_error(unsigned char reason, struct pt_regs *regs) ...@@ -730,6 +730,8 @@ io_check_error(unsigned char reason, struct pt_regs *regs)
static __kprobes void static __kprobes void
unknown_nmi_error(unsigned char reason, struct pt_regs *regs) unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
{ {
if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
return;
#ifdef CONFIG_MCA #ifdef CONFIG_MCA
/* /*
* Might actually be able to figure out what the guilty party * Might actually be able to figure out what the guilty party
......
...@@ -602,8 +602,13 @@ void die(const char * str, struct pt_regs * regs, long err) ...@@ -602,8 +602,13 @@ void die(const char * str, struct pt_regs * regs, long err)
void __kprobes die_nmi(char *str, struct pt_regs *regs, int do_panic) void __kprobes die_nmi(char *str, struct pt_regs *regs, int do_panic)
{ {
unsigned long flags = oops_begin(); unsigned long flags;
if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) ==
NOTIFY_STOP)
return;
flags = oops_begin();
/* /*
* We are in trouble anyway, lets at least try * We are in trouble anyway, lets at least try
* to get a message out. * to get a message out.
...@@ -808,6 +813,8 @@ io_check_error(unsigned char reason, struct pt_regs * regs) ...@@ -808,6 +813,8 @@ io_check_error(unsigned char reason, struct pt_regs * regs)
static __kprobes void static __kprobes void
unknown_nmi_error(unsigned char reason, struct pt_regs * regs) unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
{ {
if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
return;
printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n", printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n",
reason); reason);
printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n"); printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n");
......
...@@ -1155,6 +1155,48 @@ static struct tty_driver *get_tty_driver(dev_t device, int *index) ...@@ -1155,6 +1155,48 @@ static struct tty_driver *get_tty_driver(dev_t device, int *index)
return NULL; return NULL;
} }
#ifdef CONFIG_CONSOLE_POLL
/**
* tty_find_polling_driver - find device of a polled tty
* @name: name string to match
* @line: pointer to resulting tty line nr
*
* This routine returns a tty driver structure, given a name
* and the condition that the tty driver is capable of polled
* operation.
*/
struct tty_driver *tty_find_polling_driver(char *name, int *line)
{
struct tty_driver *p, *res = NULL;
int tty_line = 0;
char *str;
mutex_lock(&tty_mutex);
/* Search through the tty devices to look for a match */
list_for_each_entry(p, &tty_drivers, tty_drivers) {
str = name + strlen(p->name);
tty_line = simple_strtoul(str, &str, 10);
if (*str == ',')
str++;
if (*str == '\0')
str = 0;
if (tty_line >= 0 && tty_line <= p->num && p->poll_init &&
!p->poll_init(p, tty_line, str)) {
res = p;
*line = tty_line;
break;
}
}
mutex_unlock(&tty_mutex);
return res;
}
EXPORT_SYMBOL_GPL(tty_find_polling_driver);
#endif
/** /**
* tty_check_change - check for POSIX terminal changes * tty_check_change - check for POSIX terminal changes
* @tty: tty to check * @tty: tty to check
...@@ -3850,6 +3892,11 @@ void tty_set_operations(struct tty_driver *driver, ...@@ -3850,6 +3892,11 @@ void tty_set_operations(struct tty_driver *driver,
driver->write_proc = op->write_proc; driver->write_proc = op->write_proc;
driver->tiocmget = op->tiocmget; driver->tiocmget = op->tiocmget;
driver->tiocmset = op->tiocmset; driver->tiocmset = op->tiocmset;
#ifdef CONFIG_CONSOLE_POLL
driver->poll_init = op->poll_init;
driver->poll_get_char = op->poll_get_char;
driver->poll_put_char = op->poll_put_char;
#endif
} }
......
...@@ -22,3 +22,4 @@ obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o ...@@ -22,3 +22,4 @@ obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o
obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
obj-$(CONFIG_KGDB_TESTS) += kgdbts.o
This diff is collapsed.
...@@ -1740,6 +1740,60 @@ static inline void wait_for_xmitr(struct uart_8250_port *up, int bits) ...@@ -1740,6 +1740,60 @@ static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
} }
} }
#ifdef CONFIG_CONSOLE_POLL
/*
* Console polling routines for writing and reading from the uart while
* in an interrupt or debug context.
*/
static int serial8250_get_poll_char(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
unsigned char lsr = serial_inp(up, UART_LSR);
while (!(lsr & UART_LSR_DR))
lsr = serial_inp(up, UART_LSR);
return serial_inp(up, UART_RX);
}
static void serial8250_put_poll_char(struct uart_port *port,
unsigned char c)
{
unsigned int ier;
struct uart_8250_port *up = (struct uart_8250_port *)port;
/*
* First save the IER then disable the interrupts
*/
ier = serial_in(up, UART_IER);
if (up->capabilities & UART_CAP_UUE)
serial_out(up, UART_IER, UART_IER_UUE);
else
serial_out(up, UART_IER, 0);
wait_for_xmitr(up, BOTH_EMPTY);
/*
* Send the character out.
* If a LF, also do CR...
*/
serial_out(up, UART_TX, c);
if (c == 10) {
wait_for_xmitr(up, BOTH_EMPTY);
serial_out(up, UART_TX, 13);
}
/*
* Finally, wait for transmitter to become empty
* and restore the IER
*/
wait_for_xmitr(up, BOTH_EMPTY);
serial_out(up, UART_IER, ier);
}
#endif /* CONFIG_CONSOLE_POLL */
static int serial8250_startup(struct uart_port *port) static int serial8250_startup(struct uart_port *port)
{ {
struct uart_8250_port *up = (struct uart_8250_port *)port; struct uart_8250_port *up = (struct uart_8250_port *)port;
...@@ -2386,6 +2440,10 @@ static struct uart_ops serial8250_pops = { ...@@ -2386,6 +2440,10 @@ static struct uart_ops serial8250_pops = {
.request_port = serial8250_request_port, .request_port = serial8250_request_port,
.config_port = serial8250_config_port, .config_port = serial8250_config_port,
.verify_port = serial8250_verify_port, .verify_port = serial8250_verify_port,
#ifdef CONFIG_CONSOLE_POLL
.poll_get_char = serial8250_get_poll_char,
.poll_put_char = serial8250_put_poll_char,
#endif
}; };
static struct uart_8250_port serial8250_ports[UART_NR]; static struct uart_8250_port serial8250_ports[UART_NR];
......
...@@ -961,6 +961,9 @@ config SERIAL_CORE ...@@ -961,6 +961,9 @@ config SERIAL_CORE
config SERIAL_CORE_CONSOLE config SERIAL_CORE_CONSOLE
bool bool
config CONSOLE_POLL
bool
config SERIAL_68328 config SERIAL_68328
bool "68328 serial support" bool "68328 serial support"
depends on M68328 || M68EZ328 || M68VZ328 depends on M68328 || M68EZ328 || M68VZ328
......
...@@ -66,4 +66,5 @@ obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o ...@@ -66,4 +66,5 @@ obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
obj-$(CONFIG_SERIAL_NETX) += netx-serial.o obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
obj-$(CONFIG_SERIAL_QE) += ucc_uart.o obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
...@@ -314,6 +314,32 @@ static void pl011_break_ctl(struct uart_port *port, int break_state) ...@@ -314,6 +314,32 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
spin_unlock_irqrestore(&uap->port.lock, flags); spin_unlock_irqrestore(&uap->port.lock, flags);
} }
#ifdef CONFIG_CONSOLE_POLL
static int pl010_get_poll_char(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int status;
do {
status = readw(uap->port.membase + UART01x_FR);
} while (status & UART01x_FR_RXFE);
return readw(uap->port.membase + UART01x_DR);
}
static void pl010_put_poll_char(struct uart_port *port,
unsigned char ch)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
barrier();
writew(ch, uap->port.membase + UART01x_DR);
}
#endif /* CONFIG_CONSOLE_POLL */
static int pl011_startup(struct uart_port *port) static int pl011_startup(struct uart_port *port)
{ {
struct uart_amba_port *uap = (struct uart_amba_port *)port; struct uart_amba_port *uap = (struct uart_amba_port *)port;
...@@ -572,6 +598,10 @@ static struct uart_ops amba_pl011_pops = { ...@@ -572,6 +598,10 @@ static struct uart_ops amba_pl011_pops = {
.request_port = pl010_request_port, .request_port = pl010_request_port,
.config_port = pl010_config_port, .config_port = pl010_config_port,
.verify_port = pl010_verify_port, .verify_port = pl010_verify_port,
#ifdef CONFIG_CONSOLE_POLL
.poll_get_char = pl010_get_poll_char,
.poll_put_char = pl010_put_poll_char,
#endif
}; };
static struct uart_amba_port *amba_ports[UART_NR]; static struct uart_amba_port *amba_ports[UART_NR];
......
/*
* Based on the same principle as kgdboe using the NETPOLL api, this
* driver uses a console polling api to implement a gdb serial inteface
* which is multiplexed on a console port.
*
* Maintainer: Jason Wessel <jason.wessel@windriver.com>
*
* 2007-2008 (c) Jason Wessel - Wind River Systems, Inc.
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>
#include <linux/ctype.h>
#include <linux/kgdb.h>
#include <linux/tty.h>
#define MAX_CONFIG_LEN 40
static struct kgdb_io kgdboc_io_ops;
/* -1 = init not run yet, 0 = unconfigured, 1 = configured. */
static int configured = -1;
static char config[MAX_CONFIG_LEN];
static struct kparam_string kps = {
.string = config,
.maxlen = MAX_CONFIG_LEN,
};
static struct tty_driver *kgdb_tty_driver;
static int kgdb_tty_line;
static int kgdboc_option_setup(char *opt)
{
if (strlen(opt) > MAX_CONFIG_LEN) {
printk(KERN_ERR "kgdboc: config string too long\n");
return -ENOSPC;
}
strcpy(config, opt);
return 0;
}
__setup("kgdboc=", kgdboc_option_setup);
static int configure_kgdboc(void)
{
struct tty_driver *p;
int tty_line = 0;
int err;
err = kgdboc_option_setup(config);
if (err || !strlen(config) || isspace(config[0]))
goto noconfig;
err = -ENODEV;
p = tty_find_polling_driver(config, &tty_line);
if (!p)
goto noconfig;
kgdb_tty_driver = p;
kgdb_tty_line = tty_line;
err = kgdb_register_io_module(&kgdboc_io_ops);
if (err)
goto noconfig;
configured = 1;
return 0;
noconfig:
config[0] = 0;
configured = 0;
return err;
}
static int __init init_kgdboc(void)
{
/* Already configured? */
if (configured == 1)
return 0;
return configure_kgdboc();
}
static void cleanup_kgdboc(void)
{
if (configured == 1)
kgdb_unregister_io_module(&kgdboc_io_ops);
}
static int kgdboc_get_char(void)
{
return kgdb_tty_driver->poll_get_char(kgdb_tty_driver, kgdb_tty_line);
}
static void kgdboc_put_char(u8 chr)
{
kgdb_tty_driver->poll_put_char(kgdb_tty_driver, kgdb_tty_line, chr);
}
static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp)
{
int len = strlen(kmessage);
if (len >= MAX_CONFIG_LEN) {
printk(KERN_ERR "kgdboc: config string too long\n");
return -ENOSPC;
}
/* Only copy in the string if the init function has not run yet */
if (configured < 0) {
strcpy(config, kmessage);
return 0;
}
if (kgdb_connected) {
printk(KERN_ERR
"kgdboc: Cannot reconfigure while KGDB is connected.\n");
return -EBUSY;
}
strcpy(config, kmessage);
/* Chop out \n char as a result of echo */
if (config[len - 1] == '\n')
config[len - 1] = '\0';
if (configured == 1)
cleanup_kgdboc();
/* Go and configure with the new params. */
return configure_kgdboc();
}
static void kgdboc_pre_exp_handler(void)
{
/* Increment the module count when the debugger is active */
if (!kgdb_connected)
try_module_get(THIS_MODULE);
}
static void kgdboc_post_exp_handler(void)
{
/* decrement the module count when the debugger detaches */
if (!kgdb_connected)
module_put(THIS_MODULE);
}
static struct kgdb_io kgdboc_io_ops = {
.name = "kgdboc",
.read_char = kgdboc_get_char,
.write_char = kgdboc_put_char,
.pre_exception = kgdboc_pre_exp_handler,
.post_exception = kgdboc_post_exp_handler,
};
module_init(init_kgdboc);
module_exit(cleanup_kgdboc);
module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644);
MODULE_PARM_DESC(kgdboc, "<serial_device>[,baud]");
MODULE_DESCRIPTION("KGDB Console TTY Driver");
MODULE_LICENSE("GPL");
...@@ -1771,7 +1771,7 @@ static int uart_read_proc(char *page, char **start, off_t off, ...@@ -1771,7 +1771,7 @@ static int uart_read_proc(char *page, char **start, off_t off,
} }
#endif #endif
#ifdef CONFIG_SERIAL_CORE_CONSOLE #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
/* /*
* uart_console_write - write a console message to a serial port * uart_console_write - write a console message to a serial port
* @port: the port to write the message * @port: the port to write the message
...@@ -1827,7 +1827,7 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co) ...@@ -1827,7 +1827,7 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)
* options. The format of the string is <baud><parity><bits><flow>, * options. The format of the string is <baud><parity><bits><flow>,
* eg: 115200n8r * eg: 115200n8r
*/ */
void __init void
uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow) uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow)
{ {
char *s = options; char *s = options;
...@@ -1842,6 +1842,7 @@ uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow) ...@@ -1842,6 +1842,7 @@ uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow)
if (*s) if (*s)
*flow = *s; *flow = *s;
} }
EXPORT_SYMBOL_GPL(uart_parse_options);
struct baud_rates { struct baud_rates {
unsigned int rate; unsigned int rate;
...@@ -1872,7 +1873,7 @@ static const struct baud_rates baud_rates[] = { ...@@ -1872,7 +1873,7 @@ static const struct baud_rates baud_rates[] = {
* @bits: number of data bits * @bits: number of data bits
* @flow: flow control character - 'r' (rts) * @flow: flow control character - 'r' (rts)
*/ */
int __init int
uart_set_options(struct uart_port *port, struct console *co, uart_set_options(struct uart_port *port, struct console *co,
int baud, int parity, int bits, int flow) int baud, int parity, int bits, int flow)
{ {
...@@ -1924,10 +1925,16 @@ uart_set_options(struct uart_port *port, struct console *co, ...@@ -1924,10 +1925,16 @@ uart_set_options(struct uart_port *port, struct console *co,
port->mctrl |= TIOCM_DTR; port->mctrl |= TIOCM_DTR;
port->ops->set_termios(port, &termios, &dummy); port->ops->set_termios(port, &termios, &dummy);
/*
* Allow the setting of the UART parameters with a NULL console
* too:
*/
if (co)
co->cflag = termios.c_cflag; co->cflag = termios.c_cflag;
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(uart_set_options);
#endif /* CONFIG_SERIAL_CORE_CONSOLE */ #endif /* CONFIG_SERIAL_CORE_CONSOLE */
static void uart_change_pm(struct uart_state *state, int pm_state) static void uart_change_pm(struct uart_state *state, int pm_state)
...@@ -2182,6 +2189,60 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, ...@@ -2182,6 +2189,60 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
} }
} }
#ifdef CONFIG_CONSOLE_POLL
static int uart_poll_init(struct tty_driver *driver, int line, char *options)
{
struct uart_driver *drv = driver->driver_state;
struct uart_state *state = drv->state + line;
struct uart_port *port;
int baud = 9600;
int bits = 8;
int parity = 'n';
int flow = 'n';
if (!state || !state->port)
return -1;
port = state->port;
if (!(port->ops->poll_get_char && port->ops->poll_put_char))
return -1;
if (options) {
uart_parse_options(options, &baud, &parity, &bits, &flow);
return uart_set_options(port, NULL, baud, parity, bits, flow);
}
return 0;
}
static int uart_poll_get_char(struct tty_driver *driver, int line)
{
struct uart_driver *drv = driver->driver_state;
struct uart_state *state = drv->state + line;
struct uart_port *port;
if (!state || !state->port)
return -1;
port = state->port;
return port->ops->poll_get_char(port);
}
static void uart_poll_put_char(struct tty_driver *driver, int line, char ch)
{
struct uart_driver *drv = driver->driver_state;
struct uart_state *state = drv->state + line;
struct uart_port *port;
if (!state || !state->port)
return;
port = state->port;
port->ops->poll_put_char(port, ch);
}
#endif
static const struct tty_operations uart_ops = { static const struct tty_operations uart_ops = {
.open = uart_open, .open = uart_open,
.close = uart_close, .close = uart_close,
...@@ -2206,6 +2267,11 @@ static const struct tty_operations uart_ops = { ...@@ -2206,6 +2267,11 @@ static const struct tty_operations uart_ops = {
#endif #endif
.tiocmget = uart_tiocmget, .tiocmget = uart_tiocmget,
.tiocmset = uart_tiocmset, .tiocmset = uart_tiocmset,
#ifdef CONFIG_CONSOLE_POLL
.poll_init = uart_poll_init,
.poll_get_char = uart_poll_get_char,
.poll_put_char = uart_poll_put_char,
#endif
}; };
/** /**
......
...@@ -20,6 +20,7 @@ enum die_val { ...@@ -20,6 +20,7 @@ enum die_val {
DIE_CALL, DIE_CALL,
DIE_NMI_IPI, DIE_NMI_IPI,
DIE_PAGE_FAULT, DIE_PAGE_FAULT,
DIE_NMIUNKNOWN,
}; };
extern void printk_address(unsigned long address, int reliable); extern void printk_address(unsigned long address, int reliable);
......
#ifndef _ASM_KGDB_H_
#define _ASM_KGDB_H_
/*
* Copyright (C) 2001-2004 Amit S. Kale
* Copyright (C) 2008 Wind River Systems, Inc.
*/
/*
* BUFMAX defines the maximum number of characters in inbound/outbound
* buffers at least NUMREGBYTES*2 are needed for register packets
* Longer buffer is needed to list all threads
*/
#define BUFMAX 1024
/*
* Note that this register image is in a different order than
* the register image that Linux produces at interrupt time.
*
* Linux's register image is defined by struct pt_regs in ptrace.h.
* Just why GDB uses a different order is a historical mystery.
*/
#ifdef CONFIG_X86_32
enum regnames {
GDB_AX, /* 0 */
GDB_CX, /* 1 */
GDB_DX, /* 2 */
GDB_BX, /* 3 */
GDB_SP, /* 4 */
GDB_BP, /* 5 */
GDB_SI, /* 6 */
GDB_DI, /* 7 */
GDB_PC, /* 8 also known as eip */
GDB_PS, /* 9 also known as eflags */
GDB_CS, /* 10 */
GDB_SS, /* 11 */
GDB_DS, /* 12 */
GDB_ES, /* 13 */
GDB_FS, /* 14 */
GDB_GS, /* 15 */
};
#else /* ! CONFIG_X86_32 */
enum regnames {
GDB_AX, /* 0 */
GDB_DX, /* 1 */
GDB_CX, /* 2 */
GDB_BX, /* 3 */
GDB_SI, /* 4 */
GDB_DI, /* 5 */
GDB_BP, /* 6 */
GDB_SP, /* 7 */
GDB_R8, /* 8 */
GDB_R9, /* 9 */
GDB_R10, /* 10 */
GDB_R11, /* 11 */
GDB_R12, /* 12 */
GDB_R13, /* 13 */
GDB_R14, /* 14 */
GDB_R15, /* 15 */
GDB_PC, /* 16 */
GDB_PS, /* 17 */
};
#endif /* CONFIG_X86_32 */
/*
* Number of bytes of registers:
*/
#ifdef CONFIG_X86_32
# define NUMREGBYTES 64
#else
# define NUMREGBYTES ((GDB_PS+1)*8)
#endif
static inline void arch_kgdb_breakpoint(void)
{
asm(" int $3");
}
#define BREAK_INSTR_SIZE 1
#define CACHE_FLUSH_IS_SAFE 1
#endif /* _ASM_KGDB_H_ */
...@@ -216,6 +216,7 @@ static inline void clocksource_calculate_interval(struct clocksource *c, ...@@ -216,6 +216,7 @@ static inline void clocksource_calculate_interval(struct clocksource *c,
/* used to install a new clocksource */ /* used to install a new clocksource */
extern int clocksource_register(struct clocksource*); extern int clocksource_register(struct clocksource*);
extern void clocksource_unregister(struct clocksource*); extern void clocksource_unregister(struct clocksource*);
extern void clocksource_touch_watchdog(void);
extern struct clocksource* clocksource_get_next(void); extern struct clocksource* clocksource_get_next(void);
extern void clocksource_change_rating(struct clocksource *cs, int rating); extern void clocksource_change_rating(struct clocksource *cs, int rating);
extern void clocksource_resume(void); extern void clocksource_resume(void);
......
/*
* This provides the callbacks and functions that KGDB needs to share between
* the core, I/O and arch-specific portions.
*
* Author: Amit Kale <amitkale@linsyssoft.com> and
* Tom Rini <trini@kernel.crashing.org>
*
* 2001-2004 (c) Amit S. Kale and 2003-2005 (c) MontaVista Software, Inc.
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#ifndef _KGDB_H_
#define _KGDB_H_
#include <linux/serial_8250.h>
#include <linux/linkage.h>
#include <linux/init.h>
#include <asm/atomic.h>
#include <asm/kgdb.h>
struct pt_regs;
/**
* kgdb_skipexception - (optional) exit kgdb_handle_exception early
* @exception: Exception vector number
* @regs: Current &struct pt_regs.
*
* On some architectures it is required to skip a breakpoint
* exception when it occurs after a breakpoint has been removed.
* This can be implemented in the architecture specific portion of
* for kgdb.
*/
extern int kgdb_skipexception(int exception, struct pt_regs *regs);
/**
* kgdb_post_primary_code - (optional) Save error vector/code numbers.
* @regs: Original pt_regs.
* @e_vector: Original error vector.
* @err_code: Original error code.
*
* This is usually needed on architectures which support SMP and
* KGDB. This function is called after all the secondary cpus have
* been put to a know spin state and the primary CPU has control over
* KGDB.
*/
extern void kgdb_post_primary_code(struct pt_regs *regs, int e_vector,
int err_code);
/**
* kgdb_disable_hw_debug - (optional) Disable hardware debugging hook
* @regs: Current &struct pt_regs.
*
* This function will be called if the particular architecture must
* disable hardware debugging while it is processing gdb packets or
* handling exception.
*/
extern void kgdb_disable_hw_debug(struct pt_regs *regs);
struct tasklet_struct;
struct task_struct;
struct uart_port;
/**
* kgdb_breakpoint - compiled in breakpoint
*
* This will be impelmented a static inline per architecture. This
* function is called by the kgdb core to execute an architecture
* specific trap to cause kgdb to enter the exception processing.
*
*/
void kgdb_breakpoint(void);
extern int kgdb_connected;
extern atomic_t kgdb_setting_breakpoint;
extern atomic_t kgdb_cpu_doing_single_step;
extern struct task_struct *kgdb_usethread;
extern struct task_struct *kgdb_contthread;
enum kgdb_bptype {
BP_BREAKPOINT = 0,
BP_HARDWARE_BREAKPOINT,
BP_WRITE_WATCHPOINT,
BP_READ_WATCHPOINT,
BP_ACCESS_WATCHPOINT
};
enum kgdb_bpstate {
BP_UNDEFINED = 0,
BP_REMOVED,
BP_SET,
BP_ACTIVE
};
struct kgdb_bkpt {
unsigned long bpt_addr;
unsigned char saved_instr[BREAK_INSTR_SIZE];
enum kgdb_bptype type;
enum kgdb_bpstate state;
};
#ifndef KGDB_MAX_BREAKPOINTS
# define KGDB_MAX_BREAKPOINTS 1000
#endif
#define KGDB_HW_BREAKPOINT 1
/*
* Functions each KGDB-supporting architecture must provide:
*/
/**
* kgdb_arch_init - Perform any architecture specific initalization.
*
* This function will handle the initalization of any architecture
* specific callbacks.
*/
extern int kgdb_arch_init(void);
/**
* kgdb_arch_exit - Perform any architecture specific uninitalization.
*
* This function will handle the uninitalization of any architecture
* specific callbacks, for dynamic registration and unregistration.
*/
extern void kgdb_arch_exit(void);
/**
* pt_regs_to_gdb_regs - Convert ptrace regs to GDB regs
* @gdb_regs: A pointer to hold the registers in the order GDB wants.
* @regs: The &struct pt_regs of the current process.
*
* Convert the pt_regs in @regs into the format for registers that
* GDB expects, stored in @gdb_regs.
*/
extern void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs);
/**
* sleeping_thread_to_gdb_regs - Convert ptrace regs to GDB regs
* @gdb_regs: A pointer to hold the registers in the order GDB wants.
* @p: The &struct task_struct of the desired process.
*
* Convert the register values of the sleeping process in @p to
* the format that GDB expects.
* This function is called when kgdb does not have access to the
* &struct pt_regs and therefore it should fill the gdb registers
* @gdb_regs with what has been saved in &struct thread_struct
* thread field during switch_to.
*/
extern void
sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p);
/**
* gdb_regs_to_pt_regs - Convert GDB regs to ptrace regs.
* @gdb_regs: A pointer to hold the registers we've received from GDB.
* @regs: A pointer to a &struct pt_regs to hold these values in.
*
* Convert the GDB regs in @gdb_regs into the pt_regs, and store them
* in @regs.
*/
extern void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs);
/**
* kgdb_arch_handle_exception - Handle architecture specific GDB packets.
* @vector: The error vector of the exception that happened.
* @signo: The signal number of the exception that happened.
* @err_code: The error code of the exception that happened.
* @remcom_in_buffer: The buffer of the packet we have read.
* @remcom_out_buffer: The buffer of %BUFMAX bytes to write a packet into.
* @regs: The &struct pt_regs of the current process.
*
* This function MUST handle the 'c' and 's' command packets,
* as well packets to set / remove a hardware breakpoint, if used.
* If there are additional packets which the hardware needs to handle,
* they are handled here. The code should return -1 if it wants to
* process more packets, and a %0 or %1 if it wants to exit from the
* kgdb callback.
*/
extern int
kgdb_arch_handle_exception(int vector, int signo, int err_code,
char *remcom_in_buffer,
char *remcom_out_buffer,
struct pt_regs *regs);
/**
* kgdb_roundup_cpus - Get other CPUs into a holding pattern
* @flags: Current IRQ state
*
* On SMP systems, we need to get the attention of the other CPUs
* and get them be in a known state. This should do what is needed
* to get the other CPUs to call kgdb_wait(). Note that on some arches,
* the NMI approach is not used for rounding up all the CPUs. For example,
* in case of MIPS, smp_call_function() is used to roundup CPUs. In
* this case, we have to make sure that interrupts are enabled before
* calling smp_call_function(). The argument to this function is
* the flags that will be used when restoring the interrupts. There is
* local_irq_save() call before kgdb_roundup_cpus().
*
* On non-SMP systems, this is not called.
*/
extern void kgdb_roundup_cpus(unsigned long flags);
/* Optional functions. */
extern int kgdb_validate_break_address(unsigned long addr);
extern int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr);
extern int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle);
/**
* struct kgdb_arch - Describe architecture specific values.
* @gdb_bpt_instr: The instruction to trigger a breakpoint.
* @flags: Flags for the breakpoint, currently just %KGDB_HW_BREAKPOINT.
* @set_breakpoint: Allow an architecture to specify how to set a software
* breakpoint.
* @remove_breakpoint: Allow an architecture to specify how to remove a
* software breakpoint.
* @set_hw_breakpoint: Allow an architecture to specify how to set a hardware
* breakpoint.
* @remove_hw_breakpoint: Allow an architecture to specify how to remove a
* hardware breakpoint.
* @remove_all_hw_break: Allow an architecture to specify how to remove all
* hardware breakpoints.
* @correct_hw_break: Allow an architecture to specify how to correct the
* hardware debug registers.
*/
struct kgdb_arch {
unsigned char gdb_bpt_instr[BREAK_INSTR_SIZE];
unsigned long flags;
int (*set_breakpoint)(unsigned long, char *);
int (*remove_breakpoint)(unsigned long, char *);
int (*set_hw_breakpoint)(unsigned long, int, enum kgdb_bptype);
int (*remove_hw_breakpoint)(unsigned long, int, enum kgdb_bptype);
void (*remove_all_hw_break)(void);
void (*correct_hw_break)(void);
};
/**
* struct kgdb_io - Describe the interface for an I/O driver to talk with KGDB.
* @name: Name of the I/O driver.
* @read_char: Pointer to a function that will return one char.
* @write_char: Pointer to a function that will write one char.
* @flush: Pointer to a function that will flush any pending writes.
* @init: Pointer to a function that will initialize the device.
* @pre_exception: Pointer to a function that will do any prep work for
* the I/O driver.
* @post_exception: Pointer to a function that will do any cleanup work
* for the I/O driver.
*/
struct kgdb_io {
const char *name;
int (*read_char) (void);
void (*write_char) (u8);
void (*flush) (void);
int (*init) (void);
void (*pre_exception) (void);
void (*post_exception) (void);
};
extern struct kgdb_arch arch_kgdb_ops;
extern int kgdb_register_io_module(struct kgdb_io *local_kgdb_io_ops);
extern void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops);
extern int kgdb_hex2long(char **ptr, long *long_val);
extern int kgdb_mem2hex(char *mem, char *buf, int count);
extern int kgdb_hex2mem(char *buf, char *mem, int count);
extern int kgdb_isremovedbreak(unsigned long addr);
extern int
kgdb_handle_exception(int ex_vector, int signo, int err_code,
struct pt_regs *regs);
extern int kgdb_nmicallback(int cpu, void *regs);
extern int kgdb_single_step;
extern atomic_t kgdb_active;
#endif /* _KGDB_H_ */
...@@ -213,6 +213,10 @@ struct uart_ops { ...@@ -213,6 +213,10 @@ struct uart_ops {
void (*config_port)(struct uart_port *, int); void (*config_port)(struct uart_port *, int);
int (*verify_port)(struct uart_port *, struct serial_struct *); int (*verify_port)(struct uart_port *, struct serial_struct *);
int (*ioctl)(struct uart_port *, unsigned int, unsigned long); int (*ioctl)(struct uart_port *, unsigned int, unsigned long);
#ifdef CONFIG_CONSOLE_POLL
void (*poll_put_char)(struct uart_port *, unsigned char);
int (*poll_get_char)(struct uart_port *);
#endif
}; };
#define UART_CONFIG_TYPE (1 << 0) #define UART_CONFIG_TYPE (1 << 0)
......
...@@ -125,6 +125,7 @@ ...@@ -125,6 +125,7 @@
#include <linux/cdev.h> #include <linux/cdev.h>
struct tty_struct; struct tty_struct;
struct tty_driver;
struct tty_operations { struct tty_operations {
int (*open)(struct tty_struct * tty, struct file * filp); int (*open)(struct tty_struct * tty, struct file * filp);
...@@ -157,6 +158,11 @@ struct tty_operations { ...@@ -157,6 +158,11 @@ struct tty_operations {
int (*tiocmget)(struct tty_struct *tty, struct file *file); int (*tiocmget)(struct tty_struct *tty, struct file *file);
int (*tiocmset)(struct tty_struct *tty, struct file *file, int (*tiocmset)(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear); unsigned int set, unsigned int clear);
#ifdef CONFIG_CONSOLE_POLL
int (*poll_init)(struct tty_driver *driver, int line, char *options);
int (*poll_get_char)(struct tty_driver *driver, int line);
void (*poll_put_char)(struct tty_driver *driver, int line, char ch);
#endif
}; };
struct tty_driver { struct tty_driver {
...@@ -220,6 +226,11 @@ struct tty_driver { ...@@ -220,6 +226,11 @@ struct tty_driver {
int (*tiocmget)(struct tty_struct *tty, struct file *file); int (*tiocmget)(struct tty_struct *tty, struct file *file);
int (*tiocmset)(struct tty_struct *tty, struct file *file, int (*tiocmset)(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear); unsigned int set, unsigned int clear);
#ifdef CONFIG_CONSOLE_POLL
int (*poll_init)(struct tty_driver *driver, int line, char *options);
int (*poll_get_char)(struct tty_driver *driver, int line);
void (*poll_put_char)(struct tty_driver *driver, int line, char ch);
#endif
struct list_head tty_drivers; struct list_head tty_drivers;
}; };
...@@ -230,6 +241,7 @@ struct tty_driver *alloc_tty_driver(int lines); ...@@ -230,6 +241,7 @@ struct tty_driver *alloc_tty_driver(int lines);
void put_tty_driver(struct tty_driver *driver); void put_tty_driver(struct tty_driver *driver);
void tty_set_operations(struct tty_driver *driver, void tty_set_operations(struct tty_driver *driver,
const struct tty_operations *op); const struct tty_operations *op);
extern struct tty_driver *tty_find_polling_driver(char *name, int *line);
/* tty driver magic number */ /* tty driver magic number */
#define TTY_DRIVER_MAGIC 0x5402 #define TTY_DRIVER_MAGIC 0x5402
......
...@@ -84,4 +84,26 @@ static inline unsigned long __copy_from_user_nocache(void *to, ...@@ -84,4 +84,26 @@ static inline unsigned long __copy_from_user_nocache(void *to,
ret; \ ret; \
}) })
/*
* probe_kernel_read(): safely attempt to read from a location
* @dst: pointer to the buffer that shall take the data
* @src: address to read from
* @size: size of the data chunk
*
* Safely read from address @src to the buffer at @dst. If a kernel fault
* happens, handle that and return -EFAULT.
*/
extern long probe_kernel_read(void *dst, void *src, size_t size);
/*
* probe_kernel_write(): safely attempt to write to a location
* @dst: address to write to
* @src: pointer to the data that shall be written
* @size: size of the data chunk
*
* Safely write to address @dst from the buffer at @src. If a kernel fault
* happens, handle that and return -EFAULT.
*/
extern long probe_kernel_write(void *dst, void *src, size_t size);
#endif /* __LINUX_UACCESS_H__ */ #endif /* __LINUX_UACCESS_H__ */
...@@ -53,6 +53,7 @@ obj-$(CONFIG_AUDIT) += audit.o auditfilter.o ...@@ -53,6 +53,7 @@ obj-$(CONFIG_AUDIT) += audit.o auditfilter.o
obj-$(CONFIG_AUDITSYSCALL) += auditsc.o obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
obj-$(CONFIG_AUDIT_TREE) += audit_tree.o obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_KGDB) += kgdb.o
obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o
obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
obj-$(CONFIG_SECCOMP) += seccomp.o obj-$(CONFIG_SECCOMP) += seccomp.o
......
This diff is collapsed.
...@@ -221,6 +221,18 @@ void clocksource_resume(void) ...@@ -221,6 +221,18 @@ void clocksource_resume(void)
spin_unlock_irqrestore(&clocksource_lock, flags); spin_unlock_irqrestore(&clocksource_lock, flags);
} }
/**
* clocksource_touch_watchdog - Update watchdog
*
* Update the watchdog after exception contexts such as kgdb so as not
* to incorrectly trip the watchdog.
*
*/
void clocksource_touch_watchdog(void)
{
clocksource_resume_watchdog();
}
/** /**
* clocksource_get_next - Returns the selected clocksource * clocksource_get_next - Returns the selected clocksource
* *
......
...@@ -612,3 +612,5 @@ config PROVIDE_OHCI1394_DMA_INIT ...@@ -612,3 +612,5 @@ config PROVIDE_OHCI1394_DMA_INIT
See Documentation/debugging-via-ohci1394.txt for more information. See Documentation/debugging-via-ohci1394.txt for more information.
source "samples/Kconfig" source "samples/Kconfig"
source "lib/Kconfig.kgdb"
menuconfig KGDB
bool "KGDB: kernel debugging with remote gdb"
select FRAME_POINTER
depends on HAVE_ARCH_KGDB
depends on DEBUG_KERNEL && EXPERIMENTAL
help
If you say Y here, it will be possible to remotely debug the
kernel using gdb. Documentation of kernel debugger is available
at http://kgdb.sourceforge.net as well as in DocBook form
in Documentation/DocBook/. If unsure, say N.
config HAVE_ARCH_KGDB_SHADOW_INFO
bool
config HAVE_ARCH_KGDB
bool
config KGDB_SERIAL_CONSOLE
tristate "KGDB: use kgdb over the serial console"
depends on KGDB
select CONSOLE_POLL
select MAGIC_SYSRQ
default y
help
Share a serial console with kgdb. Sysrq-g must be used
to break in initially.
config KGDB_TESTS
bool "KGDB: internal test suite"
depends on KGDB
default n
help
This is a kgdb I/O module specifically designed to test
kgdb's internal functions. This kgdb I/O module is
intended to for the development of new kgdb stubs
as well as regression testing the kgdb internals.
See the drivers/misc/kgdbts.c for the details about
the tests. The most basic of this I/O module is to boot
a kernel boot arguments "kgdbwait kgdbts=V1F100"
config KGDB_TESTS_ON_BOOT
bool "KGDB: Run tests on boot"
depends on KGDB_TESTS
default n
help
Run the kgdb tests on boot up automatically without the need
to pass in a kernel parameter
config KGDB_TESTS_BOOT_STRING
string "KGDB: which internal kgdb tests to run"
depends on KGDB_TESTS_ON_BOOT
default "V1F100"
help
This is the command string to send the kgdb test suite on
boot. See the drivers/misc/kgdbts.c for detailed
information about other strings you could use beyond the
default of V1F100.
...@@ -8,7 +8,7 @@ mmu-$(CONFIG_MMU) := fremap.o highmem.o madvise.o memory.o mincore.o \ ...@@ -8,7 +8,7 @@ mmu-$(CONFIG_MMU) := fremap.o highmem.o madvise.o memory.o mincore.o \
vmalloc.o vmalloc.o
obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \ obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \
page_alloc.o page-writeback.o pdflush.o \ maccess.o page_alloc.o page-writeback.o pdflush.o \
readahead.o swap.o truncate.o vmscan.o \ readahead.o swap.o truncate.o vmscan.o \
prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \ prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \
page_isolation.o $(mmu-y) page_isolation.o $(mmu-y)
......
/*
* Access kernel memory without faulting.
*/
#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/mm.h>
/**
* probe_kernel_read(): safely attempt to read from a location
* @dst: pointer to the buffer that shall take the data
* @src: address to read from
* @size: size of the data chunk
*
* Safely read from address @src to the buffer at @dst. If a kernel fault
* happens, handle that and return -EFAULT.
*/
long probe_kernel_read(void *dst, void *src, size_t size)
{
long ret;
mm_segment_t old_fs = get_fs();
set_fs(KERNEL_DS);
pagefault_disable();
ret = __copy_from_user_inatomic(dst,
(__force const void __user *)src, size);
pagefault_enable();
set_fs(old_fs);
return ret ? -EFAULT : 0;
}
EXPORT_SYMBOL_GPL(probe_kernel_read);
/**
* probe_kernel_write(): safely attempt to write to a location
* @dst: address to write to
* @src: pointer to the data that shall be written
* @size: size of the data chunk
*
* Safely write to address @dst from the buffer at @src. If a kernel fault
* happens, handle that and return -EFAULT.
*/
long probe_kernel_write(void *dst, void *src, size_t size)
{
long ret;
mm_segment_t old_fs = get_fs();
set_fs(KERNEL_DS);
pagefault_disable();
ret = __copy_to_user_inatomic((__force void __user *)dst, src, size);
pagefault_enable();
set_fs(old_fs);
return ret ? -EFAULT : 0;
}
EXPORT_SYMBOL_GPL(probe_kernel_write);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment