forked from Minki/linux
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()
This commit is contained in:
commit
9732b61123
@ -9,7 +9,7 @@
|
||||
DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \
|
||||
kernel-hacking.xml kernel-locking.xml deviceiobook.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 \
|
||||
genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml
|
||||
|
||||
|
447
Documentation/DocBook/kgdb.tmpl
Normal file
447
Documentation/DocBook/kgdb.tmpl
Normal file
@ -0,0 +1,447 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
|
||||
|
||||
<book id="kgdbOnLinux">
|
||||
<bookinfo>
|
||||
<title>Using kgdb and the kgdb Internals</title>
|
||||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Jason</firstname>
|
||||
<surname>Wessel</surname>
|
||||
<affiliation>
|
||||
<address>
|
||||
<email>jason.wessel@windriver.com</email>
|
||||
</address>
|
||||
</affiliation>
|
||||
</author>
|
||||
</authorgroup>
|
||||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Tom</firstname>
|
||||
<surname>Rini</surname>
|
||||
<affiliation>
|
||||
<address>
|
||||
<email>trini@kernel.crashing.org</email>
|
||||
</address>
|
||||
</affiliation>
|
||||
</author>
|
||||
</authorgroup>
|
||||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Amit S.</firstname>
|
||||
<surname>Kale</surname>
|
||||
<affiliation>
|
||||
<address>
|
||||
<email>amitkale@linsyssoft.com</email>
|
||||
</address>
|
||||
</affiliation>
|
||||
</author>
|
||||
</authorgroup>
|
||||
|
||||
<copyright>
|
||||
<year>2008</year>
|
||||
<holder>Wind River Systems, Inc.</holder>
|
||||
</copyright>
|
||||
<copyright>
|
||||
<year>2004-2005</year>
|
||||
<holder>MontaVista Software, Inc.</holder>
|
||||
</copyright>
|
||||
<copyright>
|
||||
<year>2004</year>
|
||||
<holder>Amit S. Kale</holder>
|
||||
</copyright>
|
||||
|
||||
<legalnotice>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
|
||||
</legalnotice>
|
||||
</bookinfo>
|
||||
|
||||
<toc></toc>
|
||||
<chapter id="Introduction">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
kgdb is a source level debugger for linux kernel. It is used along
|
||||
with gdb to debug a linux kernel. The expectation is that gdb can
|
||||
be used to "break in" to the kernel to inspect memory, variables
|
||||
and look through a cal stack information similar to what an
|
||||
application developer would use gdb for. It is possible to place
|
||||
breakpoints in kernel code and perform some limited execution
|
||||
stepping.
|
||||
</para>
|
||||
<para>
|
||||
Two machines are required for using kgdb. One of these machines is a
|
||||
development machine and the other is a test machine. The kernel
|
||||
to be debugged runs on the test machine. The development machine
|
||||
runs an instance of gdb against the vmlinux file which contains
|
||||
the symbols (not boot image such as bzImage, zImage, uImage...).
|
||||
In gdb the developer specifies the connection parameters and
|
||||
connects to kgdb. Depending on which kgdb I/O modules exist in
|
||||
the kernel for a given architecture, it may be possible to debug
|
||||
the test machine's kernel with the development machine using a
|
||||
rs232 or ethernet connection.
|
||||
</para>
|
||||
</chapter>
|
||||
<chapter id="CompilingAKernel">
|
||||
<title>Compiling a kernel</title>
|
||||
<para>
|
||||
To enable <symbol>CONFIG_KGDB</symbol>, look under the "Kernel debugging"
|
||||
and then select "KGDB: kernel debugging with remote gdb".
|
||||
</para>
|
||||
<para>
|
||||
Next you should choose one of more I/O drivers to interconnect debugging
|
||||
host and debugged target. Early boot debugging requires a KGDB
|
||||
I/O driver that supports early debugging and the driver must be
|
||||
built into the kernel directly. Kgdb I/O driver configuration
|
||||
takes place via kernel or module parameters, see following
|
||||
chapter.
|
||||
</para>
|
||||
<para>
|
||||
The kgdb test compile options are described in the kgdb test suite chapter.
|
||||
</para>
|
||||
|
||||
</chapter>
|
||||
<chapter id="EnableKGDB">
|
||||
<title>Enable kgdb for debugging</title>
|
||||
<para>
|
||||
In order to use kgdb you must activate it by passing configuration
|
||||
information to one of the kgdb I/O drivers. If you do not pass any
|
||||
configuration information kgdb will not do anything at all. Kgdb
|
||||
will only actively hook up to the kernel trap hooks if a kgdb I/O
|
||||
driver is loaded and configured. If you unconfigure a kgdb I/O
|
||||
driver, kgdb will unregister all the kernel hook points.
|
||||
</para>
|
||||
<para>
|
||||
All drivers can be reconfigured at run time, if
|
||||
<symbol>CONFIG_SYSFS</symbol> and <symbol>CONFIG_MODULES</symbol>
|
||||
are enabled, by echo'ing a new config string to
|
||||
<constant>/sys/module/<driver>/parameter/<option></constant>.
|
||||
The driver can be unconfigured by passing an empty string. You cannot
|
||||
change the configuration while the debugger is attached. Make sure
|
||||
to detach the debugger with the <constant>detach</constant> command
|
||||
prior to trying unconfigure a kgdb I/O driver.
|
||||
</para>
|
||||
<sect1 id="kgdbwait">
|
||||
<title>Kernel parameter: kgdbwait</title>
|
||||
<para>
|
||||
The Kernel command line option <constant>kgdbwait</constant> makes
|
||||
kgdb wait for a debugger connection during booting of a kernel. You
|
||||
can only use this option you compiled a kgdb I/O driver into the
|
||||
kernel and you specified the I/O driver configuration as a kernel
|
||||
command line option. The kgdbwait parameter should always follow the
|
||||
configuration parameter for the kgdb I/O driver in the kernel
|
||||
command line else the I/O driver will not be configured prior to
|
||||
asking the kernel to use it to wait.
|
||||
</para>
|
||||
<para>
|
||||
The kernel will stop and wait as early as the I/O driver and
|
||||
architecture will allow when you use this option. If you build the
|
||||
kgdb I/O driver as a kernel module kgdbwait will not do anything.
|
||||
</para>
|
||||
</sect1>
|
||||
<sect1 id="kgdboc">
|
||||
<title>Kernel parameter: kgdboc</title>
|
||||
<para>
|
||||
The kgdboc driver was originally an abbreviation meant to stand for
|
||||
"kgdb over console". Kgdboc is designed to work with a single
|
||||
serial port. It was meant to cover the circumstance
|
||||
where you wanted to use a serial console as your primary console as
|
||||
well as using it to perform kernel debugging. Of course you can
|
||||
also use kgdboc without assigning a console to the same port.
|
||||
</para>
|
||||
<sect2 id="UsingKgdboc">
|
||||
<title>Using kgdboc</title>
|
||||
<para>
|
||||
You can configure kgdboc via sysfs or a module or kernel boot line
|
||||
parameter depending on if you build with CONFIG_KGDBOC as a module
|
||||
or built-in.
|
||||
<orderedlist>
|
||||
<listitem><para>From the module load or build-in</para>
|
||||
<para><constant>kgdboc=<tty-device>,[baud]</constant></para>
|
||||
<para>
|
||||
The example here would be if your console port was typically ttyS0, you would use something like <constant>kgdboc=ttyS0,115200</constant> or on the ARM Versatile AB you would likely use <constant>kgdboc=ttyAMA0,115200</constant>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem><para>From sysfs</para>
|
||||
<para><constant>echo ttyS0 > /sys/module/kgdboc/parameters/kgdboc</constant></para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
</para>
|
||||
<para>
|
||||
NOTE: Kgdboc does not support interrupting the target via the
|
||||
gdb remote protocol. You must manually send a sysrq-g unless you
|
||||
have a proxy that splits console output to a terminal problem and
|
||||
has a separate port for the debugger to connect to that sends the
|
||||
sysrq-g for you.
|
||||
</para>
|
||||
<para>When using kgdboc with no debugger proxy, you can end up
|
||||
connecting the debugger for one of two entry points. If an
|
||||
exception occurs after you have loaded kgdboc a message should print
|
||||
on the console stating it is waiting for the debugger. In case you
|
||||
disconnect your terminal program and then connect the debugger in
|
||||
its place. If you want to interrupt the target system and forcibly
|
||||
enter a debug session you have to issue a Sysrq sequence and then
|
||||
type the letter <constant>g</constant>. Then you disconnect the
|
||||
terminal session and connect gdb. Your options if you don't like
|
||||
this are to hack gdb to send the sysrq-g for you as well as on the
|
||||
initial connect, or to use a debugger proxy that allows an
|
||||
unmodified gdb to do the debugging.
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
<sect1 id="kgdbcon">
|
||||
<title>Kernel parameter: kgdbcon</title>
|
||||
<para>
|
||||
Kgdb supports using the gdb serial protocol to send console messages
|
||||
to the debugger when the debugger is connected and running. There
|
||||
are two ways to activate this feature.
|
||||
<orderedlist>
|
||||
<listitem><para>Activate with the kernel command line option:</para>
|
||||
<para><constant>kgdbcon</constant></para>
|
||||
</listitem>
|
||||
<listitem><para>Use sysfs before configuring an io driver</para>
|
||||
<para>
|
||||
<constant>echo 1 > /sys/module/kgdb/parameters/kgdb_use_con</constant>
|
||||
</para>
|
||||
<para>
|
||||
NOTE: If you do this after you configure the kgdb I/O driver, the
|
||||
setting will not take effect until the next point the I/O is
|
||||
reconfigured.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
</para>
|
||||
<para>
|
||||
IMPORTANT NOTE: Using this option with kgdb over the console
|
||||
(kgdboc) or kgdb over ethernet (kgdboe) is not supported.
|
||||
</para>
|
||||
</sect1>
|
||||
</chapter>
|
||||
<chapter id="ConnectingGDB">
|
||||
<title>Connecting gdb</title>
|
||||
<para>
|
||||
If you are using kgdboc, you need to have used kgdbwait as a boot
|
||||
argument, issued a sysrq-g, or the system you are going to debug
|
||||
has already taken an exception and is waiting for the debugger to
|
||||
attach before you can connect gdb.
|
||||
</para>
|
||||
<para>
|
||||
If you are not using different kgdb I/O driver other than kgdboc,
|
||||
you should be able to connect and the target will automatically
|
||||
respond.
|
||||
</para>
|
||||
<para>
|
||||
Example (using a serial port):
|
||||
</para>
|
||||
<programlisting>
|
||||
% gdb ./vmlinux
|
||||
(gdb) set remotebaud 115200
|
||||
(gdb) target remote /dev/ttyS0
|
||||
</programlisting>
|
||||
<para>
|
||||
Example (kgdb to a terminal server):
|
||||
</para>
|
||||
<programlisting>
|
||||
% gdb ./vmlinux
|
||||
(gdb) target remote udp:192.168.2.2:6443
|
||||
</programlisting>
|
||||
<para>
|
||||
Example (kgdb over ethernet):
|
||||
</para>
|
||||
<programlisting>
|
||||
% gdb ./vmlinux
|
||||
(gdb) target remote udp:192.168.2.2:6443
|
||||
</programlisting>
|
||||
<para>
|
||||
Once connected, you can debug a kernel the way you would debug an
|
||||
application program.
|
||||
</para>
|
||||
<para>
|
||||
If you are having problems connecting or something is going
|
||||
seriously wrong while debugging, it will most often be the case
|
||||
that you want to enable gdb to be verbose about its target
|
||||
communications. You do this prior to issuing the <constant>target
|
||||
remote</constant> command by typing in: <constant>set remote debug 1</constant>
|
||||
</para>
|
||||
</chapter>
|
||||
<chapter id="KGDBTestSuite">
|
||||
<title>kgdb Test Suite</title>
|
||||
<para>
|
||||
When kgdb is enabled in the kernel config you can also elect to
|
||||
enable the config parameter KGDB_TESTS. Turning this on will
|
||||
enable a special kgdb I/O module which is designed to test the
|
||||
kgdb internal functions.
|
||||
</para>
|
||||
<para>
|
||||
The kgdb tests are mainly intended for developers to test the kgdb
|
||||
internals as well as a tool for developing a new kgdb architecture
|
||||
specific implementation. These tests are not really for end users
|
||||
of the Linux kernel. The primary source of documentation would be
|
||||
to look in the drivers/misc/kgdbts.c file.
|
||||
</para>
|
||||
<para>
|
||||
The kgdb test suite can also be configured at compile time to run
|
||||
the core set of tests by setting the kernel config parameter
|
||||
KGDB_TESTS_ON_BOOT. This particular option is aimed at automated
|
||||
regression testing and does not require modifying the kernel boot
|
||||
config arguments. If this is turned on, the kgdb test suite can
|
||||
be disabled by specifying "kgdbts=" as a kernel boot argument.
|
||||
</para>
|
||||
</chapter>
|
||||
<chapter id="CommonBackEndReq">
|
||||
<title>KGDB Internals</title>
|
||||
<sect1 id="kgdbArchitecture">
|
||||
<title>Architecture Specifics</title>
|
||||
<para>
|
||||
Kgdb is organized into three basic components:
|
||||
<orderedlist>
|
||||
<listitem><para>kgdb core</para>
|
||||
<para>
|
||||
The kgdb core is found in kernel/kgdb.c. It contains:
|
||||
<itemizedlist>
|
||||
<listitem><para>All the logic to implement the gdb serial protocol</para></listitem>
|
||||
<listitem><para>A generic OS exception handler which includes sync'ing the processors into a stopped state on an multi cpu system.</para></listitem>
|
||||
<listitem><para>The API to talk to the kgdb I/O drivers</para></listitem>
|
||||
<listitem><para>The API to make calls to the arch specific kgdb implementation</para></listitem>
|
||||
<listitem><para>The logic to perform safe memory reads and writes to memory while using the debugger</para></listitem>
|
||||
<listitem><para>A full implementation for software breakpoints unless overridden by the arch</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem><para>kgdb arch specific implementation</para>
|
||||
<para>
|
||||
This implementation is generally found in arch/*/kernel/kgdb.c.
|
||||
As an example, arch/x86/kernel/kgdb.c contains the specifics to
|
||||
implement HW breakpoint as well as the initialization to
|
||||
dynamically register and unregister for the trap handlers on
|
||||
this architecture. The arch specific portion implements:
|
||||
<itemizedlist>
|
||||
<listitem><para>contains an arch specific trap catcher which
|
||||
invokes kgdb_handle_exception() to start kgdb about doing its
|
||||
work</para></listitem>
|
||||
<listitem><para>translation to and from gdb specific packet format to pt_regs</para></listitem>
|
||||
<listitem><para>Registration and unregistration of architecture specific trap hooks</para></listitem>
|
||||
<listitem><para>Any special exception handling and cleanup</para></listitem>
|
||||
<listitem><para>NMI exception handling and cleanup</para></listitem>
|
||||
<listitem><para>(optional)HW breakpoints</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem><para>kgdb I/O driver</para>
|
||||
<para>
|
||||
Each kgdb I/O driver has to provide an implemenation for the following:
|
||||
<itemizedlist>
|
||||
<listitem><para>configuration via builtin or module</para></listitem>
|
||||
<listitem><para>dynamic configuration and kgdb hook registration calls</para></listitem>
|
||||
<listitem><para>read and write character interface</para></listitem>
|
||||
<listitem><para>A cleanup handler for unconfiguring from the kgdb core</para></listitem>
|
||||
<listitem><para>(optional) Early debug methodology</para></listitem>
|
||||
</itemizedlist>
|
||||
Any given kgdb I/O driver has to operate very closely with the
|
||||
hardware and must do it in such a way that does not enable
|
||||
interrupts or change other parts of the system context without
|
||||
completely restoring them. The kgdb core will repeatedly "poll"
|
||||
a kgdb I/O driver for characters when it needs input. The I/O
|
||||
driver is expected to return immediately if there is no data
|
||||
available. Doing so allows for the future possibility to touch
|
||||
watch dog hardware in such a way as to have a target system not
|
||||
reset when these are enabled.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
</para>
|
||||
<para>
|
||||
If you are intent on adding kgdb architecture specific support
|
||||
for a new architecture, the architecture should define
|
||||
<constant>HAVE_ARCH_KGDB</constant> in the architecture specific
|
||||
Kconfig file. This will enable kgdb for the architecture, and
|
||||
at that point you must create an architecture specific kgdb
|
||||
implementation.
|
||||
</para>
|
||||
<para>
|
||||
There are a few flags which must be set on every architecture in
|
||||
their <asm/kgdb.h> file. These are:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
NUMREGBYTES: The size in bytes of all of the registers, so
|
||||
that we can ensure they will all fit into a packet.
|
||||
</para>
|
||||
<para>
|
||||
BUFMAX: The size in bytes of the buffer GDB will read into.
|
||||
This must be larger than NUMREGBYTES.
|
||||
</para>
|
||||
<para>
|
||||
CACHE_FLUSH_IS_SAFE: Set to 1 if it is always safe to call
|
||||
flush_cache_range or flush_icache_range. On some architectures,
|
||||
these functions may not be safe to call on SMP since we keep other
|
||||
CPUs in a holding pattern.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
There are also the following functions for the common backend,
|
||||
found in kernel/kgdb.c, that must be supplied by the
|
||||
architecture-specific backend unless marked as (optional), in
|
||||
which case a default function maybe used if the architecture
|
||||
does not need to provide a specific implementation.
|
||||
</para>
|
||||
!Iinclude/linux/kgdb.h
|
||||
</sect1>
|
||||
<sect1 id="kgdbocDesign">
|
||||
<title>kgdboc internals</title>
|
||||
<para>
|
||||
The kgdboc driver is actually a very thin driver that relies on the
|
||||
underlying low level to the hardware driver having "polling hooks"
|
||||
which the to which the tty driver is attached. In the initial
|
||||
implementation of kgdboc it the serial_core was changed to expose a
|
||||
low level uart hook for doing polled mode reading and writing of a
|
||||
single character while in an atomic context. When kgdb makes an I/O
|
||||
request to the debugger, kgdboc invokes a call back in the serial
|
||||
core which in turn uses the call back in the uart driver. It is
|
||||
certainly possible to extend kgdboc to work with non-uart based
|
||||
consoles in the future.
|
||||
</para>
|
||||
<para>
|
||||
When using kgdboc with a uart, the uart driver must implement two callbacks in the <constant>struct uart_ops</constant>. Example from drivers/8250.c:<programlisting>
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
.poll_get_char = serial8250_get_poll_char,
|
||||
.poll_put_char = serial8250_put_poll_char,
|
||||
#endif
|
||||
</programlisting>
|
||||
Any implementation specifics around creating a polling driver use the
|
||||
<constant>#ifdef CONFIG_CONSOLE_POLL</constant>, as shown above.
|
||||
Keep in mind that polling hooks have to be implemented in such a way
|
||||
that they can be called from an atomic context and have to restore
|
||||
the state of the uart chip on return such that the system can return
|
||||
to normal when the debugger detaches. You need to be very careful
|
||||
with any kind of lock you consider, because failing here is most
|
||||
going to mean pressing the reset button.
|
||||
</para>
|
||||
</sect1>
|
||||
</chapter>
|
||||
<chapter id="credits">
|
||||
<title>Credits</title>
|
||||
<para>
|
||||
The following people have contributed to this document:
|
||||
<orderedlist>
|
||||
<listitem><para>Amit Kale<email>amitkale@linsyssoft.com</email></para></listitem>
|
||||
<listitem><para>Tom Rini<email>trini@kernel.crashing.org</email></para></listitem>
|
||||
</orderedlist>
|
||||
In March 2008 this document was completely rewritten by:
|
||||
<itemizedlist>
|
||||
<listitem><para>Jason Wessel<email>jason.wessel@windriver.com</email></para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</chapter>
|
||||
</book>
|
||||
|
@ -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
|
||||
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]
|
||||
|
||||
lapic [X86-32,APIC] Enable the local APIC even if BIOS
|
||||
|
@ -2319,6 +2319,12 @@ L: linux-kernel@vger.kernel.org
|
||||
L: kexec@lists.infradead.org
|
||||
S: Maintained
|
||||
|
||||
KGDB
|
||||
P: Jason Wessel
|
||||
M: jason.wessel@windriver.com
|
||||
L: kgdb-bugreport@lists.sourceforge.net
|
||||
S: Maintained
|
||||
|
||||
KPROBES
|
||||
P: Ananth N Mavinakayanahalli
|
||||
M: ananth@in.ibm.com
|
||||
|
@ -23,6 +23,7 @@ config X86
|
||||
select HAVE_KPROBES
|
||||
select HAVE_KRETPROBES
|
||||
select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64)
|
||||
select HAVE_ARCH_KGDB
|
||||
|
||||
|
||||
config GENERIC_LOCKBREAK
|
||||
|
@ -67,6 +67,7 @@ obj-$(CONFIG_MODULES) += module_$(BITS).o
|
||||
obj-$(CONFIG_ACPI_SRAT) += srat_32.o
|
||||
obj-$(CONFIG_EFI) += efi.o efi_$(BITS).o efi_stub_$(BITS).o
|
||||
obj-$(CONFIG_DOUBLEFAULT) += doublefault_32.o
|
||||
obj-$(CONFIG_KGDB) += kgdb.o
|
||||
obj-$(CONFIG_VM86) += vm86_32.o
|
||||
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
|
||||
|
||||
|
571
arch/x86/kernel/kgdb.c
Normal file
571
arch/x86/kernel/kgdb.c
Normal file
@ -0,0 +1,571 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2004 Amit S. Kale <amitkale@linsyssoft.com>
|
||||
* Copyright (C) 2000-2001 VERITAS Software Corporation.
|
||||
* Copyright (C) 2002 Andi Kleen, SuSE Labs
|
||||
* Copyright (C) 2004 LinSysSoft Technologies Pvt. Ltd.
|
||||
* Copyright (C) 2007 MontaVista Software, Inc.
|
||||
* Copyright (C) 2007-2008 Jason Wessel, Wind River Systems, Inc.
|
||||
*/
|
||||
/****************************************************************************
|
||||
* Contributor: Lake Stevens Instrument Division$
|
||||
* Written by: Glenn Engel $
|
||||
* Updated by: Amit Kale<akale@veritas.com>
|
||||
* Updated by: Tom Rini <trini@kernel.crashing.org>
|
||||
* Updated by: Jason Wessel <jason.wessel@windriver.com>
|
||||
* Modified for 386 by Jim Kingdon, Cygnus Support.
|
||||
* Origianl kgdb, compatibility with 2.1.xx kernel by
|
||||
* David Grothe <dave@gcom.com>
|
||||
* Integrated into 2.2.5 kernel by Tigran Aivazian <tigran@sco.com>
|
||||
* X86_64 changes from Andi Kleen's patch merged by Jim Houston
|
||||
*/
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/kdebug.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kgdb.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/nmi.h>
|
||||
|
||||
#include <asm/apicdef.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
# include <mach_ipi.h>
|
||||
#else
|
||||
# include <asm/mach_apic.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Put the error code here just in case the user cares:
|
||||
*/
|
||||
static int gdb_x86errcode;
|
||||
|
||||
/*
|
||||
* Likewise, the vector number here (since GDB only gets the signal
|
||||
* number through the usual means, and that's not very specific):
|
||||
*/
|
||||
static int gdb_x86vector = -1;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
|
||||
{
|
||||
gdb_regs[GDB_AX] = regs->ax;
|
||||
gdb_regs[GDB_BX] = regs->bx;
|
||||
gdb_regs[GDB_CX] = regs->cx;
|
||||
gdb_regs[GDB_DX] = regs->dx;
|
||||
gdb_regs[GDB_SI] = regs->si;
|
||||
gdb_regs[GDB_DI] = regs->di;
|
||||
gdb_regs[GDB_BP] = regs->bp;
|
||||
gdb_regs[GDB_PS] = regs->flags;
|
||||
gdb_regs[GDB_PC] = regs->ip;
|
||||
#ifdef CONFIG_X86_32
|
||||
gdb_regs[GDB_DS] = regs->ds;
|
||||
gdb_regs[GDB_ES] = regs->es;
|
||||
gdb_regs[GDB_CS] = regs->cs;
|
||||
gdb_regs[GDB_SS] = __KERNEL_DS;
|
||||
gdb_regs[GDB_FS] = 0xFFFF;
|
||||
gdb_regs[GDB_GS] = 0xFFFF;
|
||||
#else
|
||||
gdb_regs[GDB_R8] = regs->r8;
|
||||
gdb_regs[GDB_R9] = regs->r9;
|
||||
gdb_regs[GDB_R10] = regs->r10;
|
||||
gdb_regs[GDB_R11] = regs->r11;
|
||||
gdb_regs[GDB_R12] = regs->r12;
|
||||
gdb_regs[GDB_R13] = regs->r13;
|
||||
gdb_regs[GDB_R14] = regs->r14;
|
||||
gdb_regs[GDB_R15] = regs->r15;
|
||||
#endif
|
||||
gdb_regs[GDB_SP] = regs->sp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
|
||||
{
|
||||
gdb_regs[GDB_AX] = 0;
|
||||
gdb_regs[GDB_BX] = 0;
|
||||
gdb_regs[GDB_CX] = 0;
|
||||
gdb_regs[GDB_DX] = 0;
|
||||
gdb_regs[GDB_SI] = 0;
|
||||
gdb_regs[GDB_DI] = 0;
|
||||
gdb_regs[GDB_BP] = *(unsigned long *)p->thread.sp;
|
||||
#ifdef CONFIG_X86_32
|
||||
gdb_regs[GDB_DS] = __KERNEL_DS;
|
||||
gdb_regs[GDB_ES] = __KERNEL_DS;
|
||||
gdb_regs[GDB_PS] = 0;
|
||||
gdb_regs[GDB_CS] = __KERNEL_CS;
|
||||
gdb_regs[GDB_PC] = p->thread.ip;
|
||||
gdb_regs[GDB_SS] = __KERNEL_DS;
|
||||
gdb_regs[GDB_FS] = 0xFFFF;
|
||||
gdb_regs[GDB_GS] = 0xFFFF;
|
||||
#else
|
||||
gdb_regs[GDB_PS] = *(unsigned long *)(p->thread.sp + 8);
|
||||
gdb_regs[GDB_PC] = 0;
|
||||
gdb_regs[GDB_R8] = 0;
|
||||
gdb_regs[GDB_R9] = 0;
|
||||
gdb_regs[GDB_R10] = 0;
|
||||
gdb_regs[GDB_R11] = 0;
|
||||
gdb_regs[GDB_R12] = 0;
|
||||
gdb_regs[GDB_R13] = 0;
|
||||
gdb_regs[GDB_R14] = 0;
|
||||
gdb_regs[GDB_R15] = 0;
|
||||
#endif
|
||||
gdb_regs[GDB_SP] = p->thread.sp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
|
||||
{
|
||||
regs->ax = gdb_regs[GDB_AX];
|
||||
regs->bx = gdb_regs[GDB_BX];
|
||||
regs->cx = gdb_regs[GDB_CX];
|
||||
regs->dx = gdb_regs[GDB_DX];
|
||||
regs->si = gdb_regs[GDB_SI];
|
||||
regs->di = gdb_regs[GDB_DI];
|
||||
regs->bp = gdb_regs[GDB_BP];
|
||||
regs->flags = gdb_regs[GDB_PS];
|
||||
regs->ip = gdb_regs[GDB_PC];
|
||||
#ifdef CONFIG_X86_32
|
||||
regs->ds = gdb_regs[GDB_DS];
|
||||
regs->es = gdb_regs[GDB_ES];
|
||||
regs->cs = gdb_regs[GDB_CS];
|
||||
#else
|
||||
regs->r8 = gdb_regs[GDB_R8];
|
||||
regs->r9 = gdb_regs[GDB_R9];
|
||||
regs->r10 = gdb_regs[GDB_R10];
|
||||
regs->r11 = gdb_regs[GDB_R11];
|
||||
regs->r12 = gdb_regs[GDB_R12];
|
||||
regs->r13 = gdb_regs[GDB_R13];
|
||||
regs->r14 = gdb_regs[GDB_R14];
|
||||
regs->r15 = gdb_regs[GDB_R15];
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct hw_breakpoint {
|
||||
unsigned enabled;
|
||||
unsigned type;
|
||||
unsigned len;
|
||||
unsigned long addr;
|
||||
} breakinfo[4];
|
||||
|
||||
static void kgdb_correct_hw_break(void)
|
||||
{
|
||||
unsigned long dr7;
|
||||
int correctit = 0;
|
||||
int breakbit;
|
||||
int breakno;
|
||||
|
||||
get_debugreg(dr7, 7);
|
||||
for (breakno = 0; breakno < 4; breakno++) {
|
||||
breakbit = 2 << (breakno << 1);
|
||||
if (!(dr7 & breakbit) && breakinfo[breakno].enabled) {
|
||||
correctit = 1;
|
||||
dr7 |= breakbit;
|
||||
dr7 &= ~(0xf0000 << (breakno << 2));
|
||||
dr7 |= ((breakinfo[breakno].len << 2) |
|
||||
breakinfo[breakno].type) <<
|
||||
((breakno << 2) + 16);
|
||||
if (breakno >= 0 && breakno <= 3)
|
||||
set_debugreg(breakinfo[breakno].addr, breakno);
|
||||
|
||||
} else {
|
||||
if ((dr7 & breakbit) && !breakinfo[breakno].enabled) {
|
||||
correctit = 1;
|
||||
dr7 &= ~breakbit;
|
||||
dr7 &= ~(0xf0000 << (breakno << 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (correctit)
|
||||
set_debugreg(dr7, 7);
|
||||
}
|
||||
|
||||
static int
|
||||
kgdb_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
if (breakinfo[i].addr == addr && breakinfo[i].enabled)
|
||||
break;
|
||||
if (i == 4)
|
||||
return -1;
|
||||
|
||||
breakinfo[i].enabled = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kgdb_remove_all_hw_break(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
memset(&breakinfo[i], 0, sizeof(struct hw_breakpoint));
|
||||
}
|
||||
|
||||
static int
|
||||
kgdb_set_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype)
|
||||
{
|
||||
unsigned type;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
if (!breakinfo[i].enabled)
|
||||
break;
|
||||
if (i == 4)
|
||||
return -1;
|
||||
|
||||
switch (bptype) {
|
||||
case BP_HARDWARE_BREAKPOINT:
|
||||
type = 0;
|
||||
len = 1;
|
||||
break;
|
||||
case BP_WRITE_WATCHPOINT:
|
||||
type = 1;
|
||||
break;
|
||||
case BP_ACCESS_WATCHPOINT:
|
||||
type = 3;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len == 1 || len == 2 || len == 4)
|
||||
breakinfo[i].len = len - 1;
|
||||
else
|
||||
return -1;
|
||||
|
||||
breakinfo[i].enabled = 1;
|
||||
breakinfo[i].addr = addr;
|
||||
breakinfo[i].type = type;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* kgdb_disable_hw_debug - Disable hardware debugging while we in kgdb.
|
||||
* @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.
|
||||
*/
|
||||
void kgdb_disable_hw_debug(struct pt_regs *regs)
|
||||
{
|
||||
/* Disable hardware debugging while we are in kgdb: */
|
||||
set_debugreg(0UL, 7);
|
||||
}
|
||||
|
||||
/**
|
||||
* kgdb_post_primary_code - Save error vector/code numbers.
|
||||
* @regs: Original pt_regs.
|
||||
* @e_vector: Original error vector.
|
||||
* @err_code: Original error code.
|
||||
*
|
||||
* This is needed on architectures which support SMP and KGDB.
|
||||
* This function is called after all the slave cpus have been put
|
||||
* to a know spin state and the primary CPU has control over KGDB.
|
||||
*/
|
||||
void kgdb_post_primary_code(struct pt_regs *regs, int e_vector, int err_code)
|
||||
{
|
||||
/* primary processor is completely in the debugger */
|
||||
gdb_x86vector = e_vector;
|
||||
gdb_x86errcode = err_code;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
void kgdb_roundup_cpus(unsigned long flags)
|
||||
{
|
||||
send_IPI_allbutself(APIC_DM_NMI);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
|
||||
char *remcomInBuffer, char *remcomOutBuffer,
|
||||
struct pt_regs *linux_regs)
|
||||
{
|
||||
unsigned long addr;
|
||||
unsigned long dr6;
|
||||
char *ptr;
|
||||
int newPC;
|
||||
|
||||
switch (remcomInBuffer[0]) {
|
||||
case 'c':
|
||||
case 's':
|
||||
/* try to read optional parameter, pc unchanged if no parm */
|
||||
ptr = &remcomInBuffer[1];
|
||||
if (kgdb_hex2long(&ptr, &addr))
|
||||
linux_regs->ip = addr;
|
||||
case 'D':
|
||||
case 'k':
|
||||
newPC = linux_regs->ip;
|
||||
|
||||
/* clear the trace bit */
|
||||
linux_regs->flags &= ~TF_MASK;
|
||||
atomic_set(&kgdb_cpu_doing_single_step, -1);
|
||||
|
||||
/* set the trace bit if we're stepping */
|
||||
if (remcomInBuffer[0] == 's') {
|
||||
linux_regs->flags |= TF_MASK;
|
||||
kgdb_single_step = 1;
|
||||
if (kgdb_contthread) {
|
||||
atomic_set(&kgdb_cpu_doing_single_step,
|
||||
raw_smp_processor_id());
|
||||
}
|
||||
}
|
||||
|
||||
get_debugreg(dr6, 6);
|
||||
if (!(dr6 & 0x4000)) {
|
||||
int breakno;
|
||||
|
||||
for (breakno = 0; breakno < 4; breakno++) {
|
||||
if (dr6 & (1 << breakno) &&
|
||||
breakinfo[breakno].type == 0) {
|
||||
/* Set restore flag: */
|
||||
linux_regs->flags |= X86_EFLAGS_RF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
set_debugreg(0UL, 6);
|
||||
kgdb_correct_hw_break();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* this means that we do not want to exit from the handler: */
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int
|
||||
single_step_cont(struct pt_regs *regs, struct die_args *args)
|
||||
{
|
||||
/*
|
||||
* Single step exception from kernel space to user space so
|
||||
* eat the exception and continue the process:
|
||||
*/
|
||||
printk(KERN_ERR "KGDB: trap/step from kernel to user space, "
|
||||
"resuming...\n");
|
||||
kgdb_arch_handle_exception(args->trapnr, args->signr,
|
||||
args->err, "c", "", regs);
|
||||
|
||||
return NOTIFY_STOP;
|
||||
}
|
||||
|
||||
static int was_in_debug_nmi[NR_CPUS];
|
||||
|
||||
static int __kgdb_notify(struct die_args *args, unsigned long cmd)
|
||||
{
|
||||
struct pt_regs *regs = args->regs;
|
||||
|
||||
switch (cmd) {
|
||||
case DIE_NMI:
|
||||
if (atomic_read(&kgdb_active) != -1) {
|
||||
/* KGDB CPU roundup */
|
||||
kgdb_nmicallback(raw_smp_processor_id(), regs);
|
||||
was_in_debug_nmi[raw_smp_processor_id()] = 1;
|
||||
touch_nmi_watchdog();
|
||||
return NOTIFY_STOP;
|
||||
}
|
||||
return NOTIFY_DONE;
|
||||
|
||||
case DIE_NMI_IPI:
|
||||
if (atomic_read(&kgdb_active) != -1) {
|
||||
/* KGDB CPU roundup */
|
||||
kgdb_nmicallback(raw_smp_processor_id(), regs);
|
||||
was_in_debug_nmi[raw_smp_processor_id()] = 1;
|
||||
touch_nmi_watchdog();
|
||||
}
|
||||
return NOTIFY_DONE;
|
||||
|
||||
case DIE_NMIUNKNOWN:
|
||||
if (was_in_debug_nmi[raw_smp_processor_id()]) {
|
||||
was_in_debug_nmi[raw_smp_processor_id()] = 0;
|
||||
return NOTIFY_STOP;
|
||||
}
|
||||
return NOTIFY_DONE;
|
||||
|
||||
case DIE_NMIWATCHDOG:
|
||||
if (atomic_read(&kgdb_active) != -1) {
|
||||
/* KGDB CPU roundup: */
|
||||
kgdb_nmicallback(raw_smp_processor_id(), regs);
|
||||
return NOTIFY_STOP;
|
||||
}
|
||||
/* Enter debugger: */
|
||||
break;
|
||||
|
||||
case DIE_DEBUG:
|
||||
if (atomic_read(&kgdb_cpu_doing_single_step) ==
|
||||
raw_smp_processor_id() &&
|
||||
user_mode(regs))
|
||||
return single_step_cont(regs, args);
|
||||
/* fall through */
|
||||
default:
|
||||
if (user_mode(regs))
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
if (kgdb_handle_exception(args->trapnr, args->signr, args->err, regs))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
/* Must touch watchdog before return to normal operation */
|
||||
touch_nmi_watchdog();
|
||||
return NOTIFY_STOP;
|
||||
}
|
||||
|
||||
static int
|
||||
kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
local_irq_save(flags);
|
||||
ret = __kgdb_notify(ptr, cmd);
|
||||
local_irq_restore(flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct notifier_block kgdb_notifier = {
|
||||
.notifier_call = kgdb_notify,
|
||||
|
||||
/*
|
||||
* Lowest-prio notifier priority, we want to be notified last:
|
||||
*/
|
||||
.priority = -INT_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
* kgdb_arch_init - Perform any architecture specific initalization.
|
||||
*
|
||||
* This function will handle the initalization of any architecture
|
||||
* specific callbacks.
|
||||
*/
|
||||
int kgdb_arch_init(void)
|
||||
{
|
||||
return register_die_notifier(&kgdb_notifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* kgdb_arch_exit - Perform any architecture specific uninitalization.
|
||||
*
|
||||
* This function will handle the uninitalization of any architecture
|
||||
* specific callbacks, for dynamic registration and unregistration.
|
||||
*/
|
||||
void kgdb_arch_exit(void)
|
||||
{
|
||||
unregister_die_notifier(&kgdb_notifier);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* kgdb_skipexception - Bail out of KGDB when we've been triggered.
|
||||
* @exception: Exception vector number
|
||||
* @regs: Current &struct pt_regs.
|
||||
*
|
||||
* On some architectures we need to skip a breakpoint exception when
|
||||
* it occurs after a breakpoint has been removed.
|
||||
*
|
||||
* Skip an int3 exception when it occurs after a breakpoint has been
|
||||
* removed. Backtrack eip by 1 since the int3 would have caused it to
|
||||
* increment by 1.
|
||||
*/
|
||||
int kgdb_skipexception(int exception, struct pt_regs *regs)
|
||||
{
|
||||
if (exception == 3 && kgdb_isremovedbreak(regs->ip - 1)) {
|
||||
regs->ip -= 1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long kgdb_arch_pc(int exception, struct pt_regs *regs)
|
||||
{
|
||||
if (exception == 3)
|
||||
return instruction_pointer(regs) - 1;
|
||||
return instruction_pointer(regs);
|
||||
}
|
||||
|
||||
struct kgdb_arch arch_kgdb_ops = {
|
||||
/* Breakpoint instruction: */
|
||||
.gdb_bpt_instr = { 0xcc },
|
||||
.flags = KGDB_HW_BREAKPOINT,
|
||||
.set_hw_breakpoint = kgdb_set_hw_break,
|
||||
.remove_hw_breakpoint = kgdb_remove_hw_break,
|
||||
.remove_all_hw_break = kgdb_remove_all_hw_break,
|
||||
.correct_hw_break = kgdb_correct_hw_break,
|
||||
};
|
@ -11,6 +11,7 @@
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kgdb.h>
|
||||
#include <asm/pda.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/processor.h>
|
||||
@ -251,6 +252,17 @@ void __cpuinit cpu_init (void)
|
||||
load_TR_desc();
|
||||
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:
|
||||
*/
|
||||
@ -261,6 +273,10 @@ void __cpuinit cpu_init (void)
|
||||
set_debugreg(0UL, 3);
|
||||
set_debugreg(0UL, 6);
|
||||
set_debugreg(0UL, 7);
|
||||
#ifdef CONFIG_KGDB
|
||||
/* If the kgdb is connected no debug regs should be altered. */
|
||||
}
|
||||
#endif
|
||||
|
||||
fpu_init();
|
||||
|
||||
|
@ -730,6 +730,8 @@ io_check_error(unsigned char reason, struct pt_regs *regs)
|
||||
static __kprobes void
|
||||
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
|
||||
/*
|
||||
* 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)
|
||||
|
||||
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
|
||||
* to get a message out.
|
||||
@ -808,6 +813,8 @@ io_check_error(unsigned char reason, struct pt_regs * regs)
|
||||
static __kprobes void
|
||||
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",
|
||||
reason);
|
||||
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)
|
||||
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: tty to check
|
||||
@ -3850,6 +3892,11 @@ void tty_set_operations(struct tty_driver *driver,
|
||||
driver->write_proc = op->write_proc;
|
||||
driver->tiocmget = op->tiocmget;
|
||||
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
|
||||
obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
|
||||
obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
|
||||
obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
|
||||
obj-$(CONFIG_KGDB_TESTS) += kgdbts.o
|
||||
|
1090
drivers/misc/kgdbts.c
Normal file
1090
drivers/misc/kgdbts.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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)
|
||||
{
|
||||
struct uart_8250_port *up = (struct uart_8250_port *)port;
|
||||
@ -2386,6 +2440,10 @@ static struct uart_ops serial8250_pops = {
|
||||
.request_port = serial8250_request_port,
|
||||
.config_port = serial8250_config_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];
|
||||
|
@ -961,6 +961,9 @@ config SERIAL_CORE
|
||||
config SERIAL_CORE_CONSOLE
|
||||
bool
|
||||
|
||||
config CONSOLE_POLL
|
||||
bool
|
||||
|
||||
config SERIAL_68328
|
||||
bool "68328 serial support"
|
||||
depends on M68328 || M68EZ328 || M68VZ328
|
||||
|
@ -66,4 +66,5 @@ obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
|
||||
obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
|
||||
obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
|
||||
obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
|
||||
obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
|
||||
obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
|
||||
|
@ -314,6 +314,32 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
|
||||
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)
|
||||
{
|
||||
struct uart_amba_port *uap = (struct uart_amba_port *)port;
|
||||
@ -572,6 +598,10 @@ static struct uart_ops amba_pl011_pops = {
|
||||
.request_port = pl010_request_port,
|
||||
.config_port = pl010_config_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];
|
||||
|
168
drivers/serial/kgdboc.c
Normal file
168
drivers/serial/kgdboc.c
Normal file
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* 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,
|
||||
}
|
||||
#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
|
||||
* @port: the port to write the message
|
||||
@ -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>,
|
||||
* eg: 115200n8r
|
||||
*/
|
||||
void __init
|
||||
void
|
||||
uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow)
|
||||
{
|
||||
char *s = options;
|
||||
@ -1842,6 +1842,7 @@ uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow)
|
||||
if (*s)
|
||||
*flow = *s;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uart_parse_options);
|
||||
|
||||
struct baud_rates {
|
||||
unsigned int rate;
|
||||
@ -1872,7 +1873,7 @@ static const struct baud_rates baud_rates[] = {
|
||||
* @bits: number of data bits
|
||||
* @flow: flow control character - 'r' (rts)
|
||||
*/
|
||||
int __init
|
||||
int
|
||||
uart_set_options(struct uart_port *port, struct console *co,
|
||||
int baud, int parity, int bits, int flow)
|
||||
{
|
||||
@ -1924,10 +1925,16 @@ uart_set_options(struct uart_port *port, struct console *co,
|
||||
port->mctrl |= TIOCM_DTR;
|
||||
|
||||
port->ops->set_termios(port, &termios, &dummy);
|
||||
co->cflag = termios.c_cflag;
|
||||
/*
|
||||
* Allow the setting of the UART parameters with a NULL console
|
||||
* too:
|
||||
*/
|
||||
if (co)
|
||||
co->cflag = termios.c_cflag;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uart_set_options);
|
||||
#endif /* CONFIG_SERIAL_CORE_CONSOLE */
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
#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 = {
|
||||
.open = uart_open,
|
||||
.close = uart_close,
|
||||
@ -2206,6 +2267,11 @@ static const struct tty_operations uart_ops = {
|
||||
#endif
|
||||
.tiocmget = uart_tiocmget,
|
||||
.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 {
|
||||
DIE_CALL,
|
||||
DIE_NMI_IPI,
|
||||
DIE_PAGE_FAULT,
|
||||
DIE_NMIUNKNOWN,
|
||||
};
|
||||
|
||||
extern void printk_address(unsigned long address, int reliable);
|
||||
|
81
include/asm-x86/kgdb.h
Normal file
81
include/asm-x86/kgdb.h
Normal file
@ -0,0 +1,81 @@
|
||||
#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,
|
||||
/* used to install a new clocksource */
|
||||
extern int clocksource_register(struct clocksource*);
|
||||
extern void clocksource_unregister(struct clocksource*);
|
||||
extern void clocksource_touch_watchdog(void);
|
||||
extern struct clocksource* clocksource_get_next(void);
|
||||
extern void clocksource_change_rating(struct clocksource *cs, int rating);
|
||||
extern void clocksource_resume(void);
|
||||
|
281
include/linux/kgdb.h
Normal file
281
include/linux/kgdb.h
Normal file
@ -0,0 +1,281 @@
|
||||
/*
|
||||
* 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 {
|
||||
void (*config_port)(struct uart_port *, int);
|
||||
int (*verify_port)(struct uart_port *, struct serial_struct *);
|
||||
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)
|
||||
|
@ -125,6 +125,7 @@
|
||||
#include <linux/cdev.h>
|
||||
|
||||
struct tty_struct;
|
||||
struct tty_driver;
|
||||
|
||||
struct tty_operations {
|
||||
int (*open)(struct tty_struct * tty, struct file * filp);
|
||||
@ -157,6 +158,11 @@ struct tty_operations {
|
||||
int (*tiocmget)(struct tty_struct *tty, struct file *file);
|
||||
int (*tiocmset)(struct tty_struct *tty, struct file *file,
|
||||
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 {
|
||||
@ -220,6 +226,11 @@ struct tty_driver {
|
||||
int (*tiocmget)(struct tty_struct *tty, struct file *file);
|
||||
int (*tiocmset)(struct tty_struct *tty, struct file *file,
|
||||
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;
|
||||
};
|
||||
@ -230,6 +241,7 @@ struct tty_driver *alloc_tty_driver(int lines);
|
||||
void put_tty_driver(struct tty_driver *driver);
|
||||
void tty_set_operations(struct tty_driver *driver,
|
||||
const struct tty_operations *op);
|
||||
extern struct tty_driver *tty_find_polling_driver(char *name, int *line);
|
||||
|
||||
/* tty driver magic number */
|
||||
#define TTY_DRIVER_MAGIC 0x5402
|
||||
|
@ -84,4 +84,26 @@ static inline unsigned long __copy_from_user_nocache(void *to,
|
||||
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__ */
|
||||
|
@ -53,6 +53,7 @@ obj-$(CONFIG_AUDIT) += audit.o auditfilter.o
|
||||
obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
|
||||
obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
|
||||
obj-$(CONFIG_KPROBES) += kprobes.o
|
||||
obj-$(CONFIG_KGDB) += kgdb.o
|
||||
obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o
|
||||
obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
|
||||
obj-$(CONFIG_SECCOMP) += seccomp.o
|
||||
|
1700
kernel/kgdb.c
Normal file
1700
kernel/kgdb.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -221,6 +221,18 @@ void clocksource_resume(void)
|
||||
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
|
||||
*
|
||||
|
@ -612,3 +612,5 @@ config PROVIDE_OHCI1394_DMA_INIT
|
||||
See Documentation/debugging-via-ohci1394.txt for more information.
|
||||
|
||||
source "samples/Kconfig"
|
||||
|
||||
source "lib/Kconfig.kgdb"
|
||||
|
58
lib/Kconfig.kgdb
Normal file
58
lib/Kconfig.kgdb
Normal file
@ -0,0 +1,58 @@
|
||||
|
||||
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 \
|
||||
vmalloc.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 \
|
||||
prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \
|
||||
page_isolation.o $(mmu-y)
|
||||
|
55
mm/maccess.c
Normal file
55
mm/maccess.c
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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);
|
Loading…
Reference in New Issue
Block a user