Commit 92cabbc2 authored by Anton Altaparmakov's avatar Anton Altaparmakov

Merge cantab.net:/home/src/bklinux-2.6

into cantab.net:/home/src/ntfs-2.6-devel
parents ae3d2a18 f199195e
...@@ -100,8 +100,8 @@ ...@@ -100,8 +100,8 @@
<para> <para>
I'd like to thank Jeff Garzik I'd like to thank Jeff Garzik
<email>jgarzik@pobox.com</email> and Alexander Viro <email>jgarzik@pobox.com</email> and Alexander Viro
<email>viro@math.psu.edu</email> for their input, Tim Waugh <email>viro@parcelfarce.linux.theplanet.co.uk</email> for their input,
<email>twaugh@redhat.com</email> for his <ulink Tim Waugh <email>twaugh@redhat.com</email> for his <ulink
url="http://people.redhat.com/twaugh/docbook/selfdocbook/">Selfdocbook</ulink>, url="http://people.redhat.com/twaugh/docbook/selfdocbook/">Selfdocbook</ulink>,
and Marc Joosen <email>marcj@historia.et.tudelft.nl</email> for and Marc Joosen <email>marcj@historia.et.tudelft.nl</email> for
proofreading. proofreading.
......
...@@ -82,7 +82,7 @@ lock might be used as follows for deletion and insertion: ...@@ -82,7 +82,7 @@ lock might be used as follows for deletion and insertion:
list_for_each_entry(e, list, list) { list_for_each_entry(e, list, list) {
if (!audit_compare_rule(rule, &e->rule)) { if (!audit_compare_rule(rule, &e->rule)) {
list_del(&e->list); list_del(&e->list);
call_rcu(&e->rcu, audit_free_rule, e); write_unlock(&auditsc_lock);
return 0; return 0;
} }
} }
......
...@@ -1632,7 +1632,7 @@ Changes for patch v177 ...@@ -1632,7 +1632,7 @@ Changes for patch v177
- Fixed bugs in handling symlinks: could leak or cause Oops - Fixed bugs in handling symlinks: could leak or cause Oops
- Cleaned up directory handling by separating fops - Cleaned up directory handling by separating fops
Thanks to Alexander Viro <viro@math.psu.edu> Thanks to Alexander Viro <viro@parcelfarce.linux.theplanet.co.uk>
=============================================================================== ===============================================================================
Changes for patch v178 Changes for patch v178
......
...@@ -701,7 +701,7 @@ running once the system is up. ...@@ -701,7 +701,7 @@ running once the system is up.
[KNL,ACPI] Mark specific memory as reserved. [KNL,ACPI] Mark specific memory as reserved.
Region of memory to be used, from ss to ss+nn. Region of memory to be used, from ss to ss+nn.
meye= [HW] Set MotionEye Camera parameters meye.*= [HW] Set MotionEye Camera parameters
See Documentation/video4linux/meye.txt. See Documentation/video4linux/meye.txt.
mga= [HW,DRM] mga= [HW,DRM]
...@@ -866,6 +866,16 @@ running once the system is up. ...@@ -866,6 +866,16 @@ running once the system is up.
order they are specified on the command order they are specified on the command
line, starting with parport0. line, starting with parport0.
parport_init_mode=
[HW,PPT] Configure VIA parallel port to
operate in specific mode. This is
necessary on Pegasos computer where
firmware has no options for setting up
parallel port mode and sets it to
spp. Currently this function knows
686a and 8231 chips.
Format: [spp|ps2|epp|ecp|ecpepp]
pas2= [HW,OSS] pas2= [HW,OSS]
Format: <io>,<irq>,<dma>,<dma16>,<sb_io>,<sb_irq>,<sb_dma>,<sb_dma16> Format: <io>,<irq>,<dma>,<dma16>,<sb_io>,<sb_irq>,<sb_dma>,<sb_dma16>
...@@ -1015,10 +1025,6 @@ running once the system is up. ...@@ -1015,10 +1025,6 @@ running once the system is up.
New name for the ramdisk parameter. New name for the ramdisk parameter.
See Documentation/ramdisk.txt. See Documentation/ramdisk.txt.
ramdisk_start= [RAM] Starting block of RAM disk image (so you can
place it after the kernel image on a boot floppy).
See Documentation/ramdisk.txt.
reboot= [BUGS=IA-32,BUGS=ARM,BUGS=IA-64] Rebooting mode reboot= [BUGS=IA-32,BUGS=ARM,BUGS=IA-64] Rebooting mode
Format: <reboot_mode>[,<reboot_mode2>[,...]] Format: <reboot_mode>[,<reboot_mode2>[,...]]
See arch/*/kernel/reboot.c. See arch/*/kernel/reboot.c.
......
The prio_tree.c code indexes vmas using 3 different indexes:
* heap_index = vm_pgoff + vm_size_in_pages : end_vm_pgoff
* radix_index = vm_pgoff : start_vm_pgoff
* size_index = vm_size_in_pages
A regular radix-priority-search-tree indexes vmas using only heap_index and
radix_index. The conditions for indexing are:
* ->heap_index >= ->left->heap_index &&
->heap_index >= ->right->heap_index
* if (->heap_index == ->left->heap_index)
then ->radix_index < ->left->radix_index;
* if (->heap_index == ->right->heap_index)
then ->radix_index < ->right->radix_index;
* nodes are hashed to left or right subtree using radix_index
similar to a pure binary radix tree.
A regular radix-priority-search-tree helps to store and query
intervals (vmas). However, a regular radix-priority-search-tree is only
suitable for storing vmas with different radix indices (vm_pgoff).
Therefore, the prio_tree.c extends the regular radix-priority-search-tree
to handle many vmas with the same vm_pgoff. Such vmas are handled in
2 different ways: 1) All vmas with the same radix _and_ heap indices are
linked using vm_set.list, 2) if there are many vmas with the same radix
index, but different heap indices and if the regular radix-priority-search
tree cannot index them all, we build an overflow-sub-tree that indexes such
vmas using heap and size indices instead of heap and radix indices. For
example, in the figure below some vmas with vm_pgoff = 0 (zero) are
indexed by regular radix-priority-search-tree whereas others are pushed
into an overflow-subtree. Note that all vmas in an overflow-sub-tree have
the same vm_pgoff (radix_index) and if necessary we build different
overflow-sub-trees to handle each possible radix_index. For example,
in figure we have 3 overflow-sub-trees corresponding to radix indices
0, 2, and 4.
In the final tree the first few (prio_tree_root->index_bits) levels
are indexed using heap and radix indices whereas the overflow-sub-trees below
those levels (i.e. levels prio_tree_root->index_bits + 1 and higher) are
indexed using heap and size indices. In overflow-sub-trees the size_index
is used for hashing the nodes to appropriate places.
Now, an example prio_tree:
vmas are represented [radix_index, size_index, heap_index]
i.e., [start_vm_pgoff, vm_size_in_pages, end_vm_pgoff]
level prio_tree_root->index_bits = 3
-----
_
0 [0,7,7] |
/ \ |
------------------ ------------ | Regular
/ \ | radix priority
1 [1,6,7] [4,3,7] | search tree
/ \ / \ |
------- ----- ------ ----- | heap-and-radix
/ \ / \ | indexed
2 [0,6,6] [2,5,7] [5,2,7] [6,1,7] |
/ \ / \ / \ / \ |
3 [0,5,5] [1,5,6] [2,4,6] [3,4,7] [4,2,6] [5,1,6] [6,0,6] [7,0,7] |
/ / / _
/ / / _
4 [0,4,4] [2,3,5] [4,1,5] |
/ / / |
5 [0,3,3] [2,2,4] [4,0,4] | Overflow-sub-trees
/ / |
6 [0,2,2] [2,1,3] | heap-and-size
/ / | indexed
7 [0,1,1] [2,0,2] |
/ |
8 [0,0,0] |
_
Note that we use prio_tree_root->index_bits to optimize the height
of the heap-and-radix indexed tree. Since prio_tree_root->index_bits is
set according to the maximum end_vm_pgoff mapped, we are sure that all
bits (in vm_pgoff) above prio_tree_root->index_bits are 0 (zero). Therefore,
we only use the first prio_tree_root->index_bits as radix_index.
Whenever index_bits is increased in prio_tree_expand, we shuffle the tree
to make sure that the first prio_tree_root->index_bits levels of the tree
is indexed properly using heap and radix indices.
We do not optimize the height of overflow-sub-trees using index_bits.
The reason is: there can be many such overflow-sub-trees and all of
them have to be suffled whenever the index_bits increases. This may involve
walking the whole prio_tree in prio_tree_insert->prio_tree_expand code
path which is not desirable. Hence, we do not optimize the height of the
heap-and-size indexed overflow-sub-trees using prio_tree->index_bits.
Instead the overflow sub-trees are indexed using full BITS_PER_LONG bits
of size_index. This may lead to skewed sub-trees because most of the
higher significant bits of the size_index are likely to be be 0 (zero). In
the example above, all 3 overflow-sub-trees are skewed. This may marginally
affect the performance. However, processes rarely map many vmas with the
same start_vm_pgoff but different end_vm_pgoffs. Therefore, we normally
do not require overflow-sub-trees to index all vmas.
From the above discussion it is clear that the maximum height of
a prio_tree can be prio_tree_root->index_bits + BITS_PER_LONG.
However, in most of the common cases we do not need overflow-sub-trees,
so the tree height in the common cases will be prio_tree_root->index_bits.
It is fair to mention here that the prio_tree_root->index_bits
is increased on demand, however, the index_bits is not decreased when
vmas are removed from the prio_tree. That's tricky to do. Hence, it's
left as a home work problem.
Sony Programmable I/O Control Device Driver Readme Sony Programmable I/O Control Device Driver Readme
-------------------------------------------------- --------------------------------------------------
Copyright (C) 2001-2003 Stelian Pop <stelian@popies.net> Copyright (C) 2001-2004 Stelian Pop <stelian@popies.net>
Copyright (C) 2001-2002 Alcôve <www.alcove.com> Copyright (C) 2001-2002 Alcôve <www.alcove.com>
Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au> Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp> Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
...@@ -23,16 +23,18 @@ generate, like: ...@@ -23,16 +23,18 @@ generate, like:
Those events (see linux/sonypi.h) can be polled using the character device node Those events (see linux/sonypi.h) can be polled using the character device node
/dev/sonypi (major 10, minor auto allocated or specified as a option). /dev/sonypi (major 10, minor auto allocated or specified as a option).
A simple daemon which translates the jogdial movements into mouse wheel events A simple daemon which translates the jogdial movements into mouse wheel events
can be downloaded at: <http://popies.net/sonypi/> can be downloaded at: <http://popies.net/sonypi/>
Another option to intercept the events is to get them directly through the
input layer.
This driver supports also some ioctl commands for setting the LCD screen This driver supports also some ioctl commands for setting the LCD screen
brightness and querying the batteries charge information (some more brightness and querying the batteries charge information (some more
commands may be added in the future). commands may be added in the future).
This driver can also be used to set the camera controls on Picturebook series This driver can also be used to set the camera controls on Picturebook series
(brightness, contrast etc), and is used by the video4linux driver for the (brightness, contrast etc), and is used by the video4linux driver for the
Motion Eye camera. Motion Eye camera.
Please note that this driver was created by reverse engineering the Windows Please note that this driver was created by reverse engineering the Windows
...@@ -47,7 +49,7 @@ module argument syntax (<param>=<value> when passing the option to the ...@@ -47,7 +49,7 @@ module argument syntax (<param>=<value> when passing the option to the
module or sonypi.<param>=<value> on the kernel boot line when sonypi is module or sonypi.<param>=<value> on the kernel boot line when sonypi is
statically linked into the kernel). Those options are: statically linked into the kernel). Those options are:
minor: minor number of the misc device /dev/sonypi, minor: minor number of the misc device /dev/sonypi,
default is -1 (automatic allocation, see /proc/misc default is -1 (automatic allocation, see /proc/misc
or kernel logs) or kernel logs)
...@@ -59,14 +61,14 @@ statically linked into the kernel). Those options are: ...@@ -59,14 +61,14 @@ statically linked into the kernel). Those options are:
get enabled unless you set this parameter to 1. get enabled unless you set this parameter to 1.
Do not use this option unless it's actually necessary, Do not use this option unless it's actually necessary,
some Vaio models don't deal well with this option. some Vaio models don't deal well with this option.
This option is available only if the kernel is This option is available only if the kernel is
compiled without ACPI support (since it conflicts compiled without ACPI support (since it conflicts
with it and it shouldn't be required anyway if with it and it shouldn't be required anyway if
ACPI is already enabled). ACPI is already enabled).
verbose: set to 1 to print unknown events received from the verbose: set to 1 to print unknown events received from the
sonypi device. sonypi device.
set to 2 to print all events received from the set to 2 to print all events received from the
sonypi device. sonypi device.
compat: uses some compatibility code for enabling the sonypi compat: uses some compatibility code for enabling the sonypi
...@@ -75,14 +77,15 @@ statically linked into the kernel). Those options are: ...@@ -75,14 +77,15 @@ statically linked into the kernel). Those options are:
add this option and report to the author. add this option and report to the author.
mask: event mask telling the driver what events will be mask: event mask telling the driver what events will be
reported to the user. This parameter is required for some reported to the user. This parameter is required for
Vaio models where the hardware reuses values used in some Vaio models where the hardware reuses values
other Vaio models (like the FX series who does not used in other Vaio models (like the FX series who does
have a jogdial but reuses the jogdial events for not have a jogdial but reuses the jogdial events for
programmable keys events). The default event mask is programmable keys events). The default event mask is
set to 0xffffffff, meaning that all possible events will be set to 0xffffffff, meaning that all possible events
tried. You can use the following bits to construct will be tried. You can use the following bits to
your own event mask (from drivers/char/sonypi.h): construct your own event mask (from
drivers/char/sonypi.h):
SONYPI_JOGGER_MASK 0x0001 SONYPI_JOGGER_MASK 0x0001
SONYPI_CAPTURE_MASK 0x0002 SONYPI_CAPTURE_MASK 0x0002
SONYPI_FNKEY_MASK 0x0004 SONYPI_FNKEY_MASK 0x0004
...@@ -97,10 +100,10 @@ statically linked into the kernel). Those options are: ...@@ -97,10 +100,10 @@ statically linked into the kernel). Those options are:
SONYPI_MEMORYSTICK_MASK 0x0800 SONYPI_MEMORYSTICK_MASK 0x0800
SONYPI_BATTERY_MASK 0x1000 SONYPI_BATTERY_MASK 0x1000
useinput: if set (which is the default) jogdial events are useinput: if set (which is the default) two input devices are
forwarded to the input subsystem as mouse wheel created, one which interprets the jogdial events as
events. mouse events, the other one which acts like a
keyboard reporting the pressing of the special keys.
Module use: Module use:
----------- -----------
...@@ -123,17 +126,17 @@ Bugs: ...@@ -123,17 +126,17 @@ Bugs:
external monitor on/off. There is no workaround yet, since this external monitor on/off. There is no workaround yet, since this
driver disables all APM management for those keys, by enabling the driver disables all APM management for those keys, by enabling the
ACPI management (and the ACPI core stuff is not complete yet). If ACPI management (and the ACPI core stuff is not complete yet). If
you have one of those laptops with working Fn keys and want to you have one of those laptops with working Fn keys and want to
continue to use them, don't use this driver. continue to use them, don't use this driver.
- some users reported that the laptop speed is lower (dhrystone - some users reported that the laptop speed is lower (dhrystone
tested) when using the driver with the fnkeyinit parameter. I cannot tested) when using the driver with the fnkeyinit parameter. I cannot
reproduce it on my laptop and not all users have this problem. reproduce it on my laptop and not all users have this problem.
This happens because the fnkeyinit parameter enables the ACPI This happens because the fnkeyinit parameter enables the ACPI
mode (but without additional ACPI control, like processor mode (but without additional ACPI control, like processor
speed handling etc). Use ACPI instead of APM if it works on your speed handling etc). Use ACPI instead of APM if it works on your
laptop. laptop.
- since all development was done by reverse engineering, there is - since all development was done by reverse engineering, there is
_absolutely no guarantee_ that this driver will not crash your _absolutely no guarantee_ that this driver will not crash your
laptop. Permanently. laptop. Permanently.
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
Author: Romain Lievin Author: Romain Lievin
Homepage: http://lpg.ticalc.org/prj_dev Homepage: http://lpg.ticalc.org/prj_tidev/index.html
INTRODUCTION: INTRODUCTION:
...@@ -12,31 +12,30 @@ INTRODUCTION: ...@@ -12,31 +12,30 @@ INTRODUCTION:
This is a driver for the very common home-made parallel link cable, a cable This is a driver for the very common home-made parallel link cable, a cable
designed for connecting TI8x/9x graphing calculators (handhelds) to a computer designed for connecting TI8x/9x graphing calculators (handhelds) to a computer
or workstation (Alpha, Sparc). Given that driver is built on parport, the or workstation (Alpha, Sparc). Given that driver is built on parport, the
parallel port abstraction layer, this driver is independent of the platform. parallel port abstraction layer, this driver is architecture-independent.
It can also be used with another device plugged on the same port (such as a It can also be used with another device plugged on the same port (such as a
ZIP drive). I have a 100MB ZIP and both of them work fine ! ZIP drive). I have a 100MB ZIP and both of them work fine!
If you need more information, please visit the 'TI drivers' homepage at the URL If you need more information, please visit the 'TI drivers' homepage at the URL
above. above.
WHAT YOU NEED: WHAT YOU NEED:
A TI calculator of course and a program capable to communicate with your A TI calculator and a program capable of communicating with your calculator.
calculator.
TiLP will work for sure (since I am his developer !). yal92 may be able to use TiLP will work for sure (since I am its developer!). yal92 may be able to use
it by changing tidev for tipar (may require some hacking...). it by changing tidev for tipar (may require some hacking...).
HOW TO USE IT: HOW TO USE IT:
You must have first compiled parport support (CONFIG_PARPORT_DEV): either You must have first compiled parport support (CONFIG_PARPORT_DEV): either
compiled in your kernel, either as a module. compiled in your kernel, either as a module.
This driver supports the new device hierarchy (devfs).
Next, (as root) from your appropriate modules directory (lib/modules/2.5.XX): Next, (as root):
modprobe parport modprobe parport
insmod tipar.o modprobe tipar
If it is not already there (it usually is), create the device: If it is not already there (it usually is), create the device:
...@@ -47,14 +46,14 @@ If it is not already there (it usually is), create the device: ...@@ -47,14 +46,14 @@ If it is not already there (it usually is), create the device:
You will have to set permissions on this device to allow you to read/write You will have to set permissions on this device to allow you to read/write
from it: from it:
chmod 666 /dev/tipar? chmod 666 /dev/tipar[0..2]
Now you are ready to run a linking program such as TiLP. Be sure to configure Now you are ready to run a linking program such as TiLP. Be sure to configure
it properly (RTFM). it properly (RTFM).
MODULE PARAMETERS: MODULE PARAMETERS:
You can set these with: insmod tipar NAME=VALUE You can set these with: modprobe tipar NAME=VALUE
There is currently no way to set these on a per-cable basis. There is currently no way to set these on a per-cable basis.
NAME: timeout NAME: timeout
...@@ -66,11 +65,12 @@ MODULE PARAMETERS: ...@@ -66,11 +65,12 @@ MODULE PARAMETERS:
NAME: delay NAME: delay
TYPE: integer TYPE: integer
DEFAULT: 10 DEFAULT: 10
DESC: Inter-bit delay in micro-seconds. An lower value gives an higher data DESC: Inter-bit delay in micro-seconds. A lower value gives an higher data
rate but makes transmission less reliable. rate but makes transmission less reliable.
These parameters can be changed at run time by any program via ioctl(2) calls These parameters can be changed at run time by any program via ioctl(2) calls
as listed in ./include/linux/ticable.h as listed in ./include/linux/ticable.h.
Rather than write 50 pages describing the ioctl() and so on, it is Rather than write 50 pages describing the ioctl() and so on, it is
perhaps more useful you look at ticables library (dev_link.c) that demonstrates perhaps more useful you look at ticables library (dev_link.c) that demonstrates
how to use them, and demonstrates the features of the driver. This is how to use them, and demonstrates the features of the driver. This is
......
Vaio Picturebook Motion Eye Camera Driver Readme Vaio Picturebook Motion Eye Camera Driver Readme
------------------------------------------------ ------------------------------------------------
Copyright (C) 2001-2003 Stelian Pop <stelian@popies.net> Copyright (C) 2001-2004 Stelian Pop <stelian@popies.net>
Copyright (C) 2001-2002 Alcôve <www.alcove.com> Copyright (C) 2001-2002 Alcôve <www.alcove.com>
Copyright (C) 2000 Andrew Tridgell <tridge@samba.org> Copyright (C) 2000 Andrew Tridgell <tridge@samba.org>
This driver enable the use of video4linux compatible applications with the This driver enable the use of video4linux compatible applications with the
Motion Eye camera. This driver requires the "Sony Vaio Programmable I/O Motion Eye camera. This driver requires the "Sony Vaio Programmable I/O
Control Device" driver (which can be found in the "Character drivers" Control Device" driver (which can be found in the "Character drivers"
section of the kernel configuration utility) to be compiled and installed section of the kernel configuration utility) to be compiled and installed
(using its "camera=1" parameter). (using its "camera=1" parameter).
...@@ -24,7 +24,7 @@ This driver supports the 'second' version of the MotionEye camera :) ...@@ -24,7 +24,7 @@ This driver supports the 'second' version of the MotionEye camera :)
The first version was connected directly on the video bus of the Neomagic The first version was connected directly on the video bus of the Neomagic
video card and is unsupported. video card and is unsupported.
The second one, made by Kawasaki Steel is fully supported by this The second one, made by Kawasaki Steel is fully supported by this
driver (PCI vendor/device is 0x136b/0xff01) driver (PCI vendor/device is 0x136b/0xff01)
The third one, present in recent (more or less last year) Picturebooks The third one, present in recent (more or less last year) Picturebooks
...@@ -41,13 +41,12 @@ little information if any is available for this camera ...@@ -41,13 +41,12 @@ little information if any is available for this camera
Driver options: Driver options:
--------------- ---------------
Several options can be passed to the meye driver, either by adding them Several options can be passed to the meye driver using the standard
to /etc/modprobe.conf file, when the driver is compiled as a module, or module argument syntax (<param>=<value> when passing the option to the
by adding the following to the kernel command line (in your bootloader): module or meye.<param>=<value> on the kernel boot line when meye is
statically linked into the kernel). Those options are:
meye=gbuffers[,gbufsize[,video_nr]] forcev4l1: force use of V4L1 API instead of V4L2
where:
gbuffers: number of capture buffers, default is 2 (32 max) gbuffers: number of capture buffers, default is 2 (32 max)
...@@ -81,8 +80,9 @@ Usage: ...@@ -81,8 +80,9 @@ Usage:
Private API: Private API:
------------ ------------
The driver supports frame grabbing with the video4linux API, so The driver supports frame grabbing with the video4linux API
all video4linux tools (like xawtv) should work with this driver. (either v4l1 or v4l2), so all video4linux tools (like xawtv)
should work with this driver.
Besides the video4linux interface, the driver has a private interface Besides the video4linux interface, the driver has a private interface
for accessing the Motion Eye extended parameters (camera sharpness, for accessing the Motion Eye extended parameters (camera sharpness,
...@@ -116,7 +116,7 @@ Private API: ...@@ -116,7 +116,7 @@ Private API:
MEYEIOC_STILLJCAPT MEYEIOC_STILLJCAPT
Takes a snapshot in an uncompressed or compressed jpeg format. Takes a snapshot in an uncompressed or compressed jpeg format.
This ioctl blocks until the snapshot is done and returns (for This ioctl blocks until the snapshot is done and returns (for
jpeg snapshot) the size of the image. The image data is jpeg snapshot) the size of the image. The image data is
available from the first mmap'ed buffer. available from the first mmap'ed buffer.
Look at the 'motioneye' application code for an actual example. Look at the 'motioneye' application code for an actual example.
...@@ -124,13 +124,7 @@ Private API: ...@@ -124,13 +124,7 @@ Private API:
Bugs / Todo: Bugs / Todo:
------------ ------------
- overlay output is not supported (although the camera is capable of). - the driver could be much cleaned up by removing the v4l1 support.
(it should not be too hard to to it, provided we found how...) However, this means all v4l1-only applications will stop working.
- mjpeg hardware playback doesn't work (depends on overlay...)
- rewrite the driver to use some common video4linux API for snapshot - 'motioneye' still uses the meye private v4l1 API extensions.
and mjpeg capture. Unfortunately, video4linux1 does not permit it,
the BUZ API seems to be targeted to TV cards only. The video4linux 2
API may be an option, if it goes into the kernel (maybe 2.5
material ?).
...@@ -831,7 +831,7 @@ S: Maintained ...@@ -831,7 +831,7 @@ S: Maintained
FILESYSTEMS (VFS and infrastructure) FILESYSTEMS (VFS and infrastructure)
P: Alexander Viro P: Alexander Viro
M: viro@math.psu.edu M: viro@parcelfarce.linux.theplanet.co.uk
S: Maintained S: Maintained
FIRMWARE LOADER (request_firmware) FIRMWARE LOADER (request_firmware)
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/serial_8250.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/mach/map.h> #include <asm/mach/map.h>
...@@ -313,6 +314,55 @@ static struct clps7500_timer = { ...@@ -313,6 +314,55 @@ static struct clps7500_timer = {
.offset = ioc_timer_gettimeoffset, .offset = ioc_timer_gettimeoffset,
}; };
static struct plat_serial8250_port serial_platform_data[] = {
{
.mapbase = 0x03010fe0,
.irq = 10,
.uartclk = 1843200,
.regshift = 2,
.iotype = UPIO_MEM,
.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_SKIP_TEST,
},
{
.mapbase = 0x03010be0,
.irq = 0,
.uartclk = 1843200,
.regshift = 2,
.iotype = UPIO_MEM,
.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_SKIP_TEST,
},
{
.iobase = ISASLOT_IO + 0x2e8,
.irq = 41,
.uartclk = 1843200,
.regshift = 0,
.iotype = UPIO_PORT,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
},
{
.iobase = ISASLOT_IO + 0x3e8,
.irq = 40,
.uartclk = 1843200,
.regshift = 0,
.iotype = UPIO_PORT,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
},
{ },
};
static struct platform_device serial_device = {
.name = "serial8250",
.id = 0,
.dev = {
.platform_data = serial_platform_data,
},
};
static int __init clps7500_init(void)
{
return platform_register_device(&serial_device);
}
MACHINE_START(CLPS7500, "CL-PS7500") MACHINE_START(CLPS7500, "CL-PS7500")
MAINTAINER("Philip Blundell") MAINTAINER("Philip Blundell")
BOOT_MEM(0x10000000, 0x03000000, 0xe0000000) BOOT_MEM(0x10000000, 0x03000000, 0xe0000000)
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/serial_8250.h>
#include <linux/init.h> #include <linux/init.h>
#include <asm/hardware.h> #include <asm/hardware.h>
...@@ -196,6 +197,41 @@ static struct sys_timer ebsa110_timer = { ...@@ -196,6 +197,41 @@ static struct sys_timer ebsa110_timer = {
.offset = ebsa110_gettimeoffset, .offset = ebsa110_gettimeoffset,
}; };
static struct plat_serial8250_port serial_platform_data[] = {
{
.iobase = 0x3f8,
.irq = 1,
.uartclk = 1843200,
.regshift = 0,
.iotype = UPIO_PORT,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
},
{
.iobase = 0x2f8,
.irq = 2,
.uartclk = 1843200,
.regshift = 0,
.iotype = UPIO_PORT,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
},
{ },
};
static struct platform_device serial_device = {
.name = "serial8250",
.id = 0,
.dev = {
.platform_data = serial_platform_data,
},
};
static int __init ebsa110_init(void)
{
return platform_device_register(&serial_device);
}
arch_initcall(ebsa110_init);
MACHINE_START(EBSA110, "EBSA110") MACHINE_START(EBSA110, "EBSA110")
MAINTAINER("Russell King") MAINTAINER("Russell King")
BOOT_MEM(0x00000000, 0xe0000000, 0xe0000000) BOOT_MEM(0x00000000, 0xe0000000, 0xe0000000)
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
*/ */
#include <linux/types.h> #include <linux/types.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/serial_8250.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/setup.h> #include <asm/setup.h>
...@@ -27,6 +28,36 @@ ...@@ -27,6 +28,36 @@
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
static struct plat_serial8250_port serial_platform_data[] = {
{
.iobase = 0x3f8,
.irq = IRQ_UARTINT0,
#error FIXME
.uartclk = 0,
.regshift = 0,
.iotype = UPIO_PORT,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
},
{
.iobase = 0x2f8,
.irq = IRQ_UARTINT1,
#error FIXME
.uartclk = 0,
.regshift = 0,
.iotype = UPIO_PORT,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
},
{ },
};
static struct platform_device serial_device = {
.name = "serial8250",
.id = 0,
.dev = {
.platform_data = serial_platform_data,
},
};
extern void epxa10db_map_io(void); extern void epxa10db_map_io(void);
extern void epxa10db_init_irq(void); extern void epxa10db_init_irq(void);
extern struct sys_timer epxa10db_timer; extern struct sys_timer epxa10db_timer;
......
...@@ -26,3 +26,5 @@ obj-$(CONFIG_ARCH_PERSONAL_SERVER) += personal.o dc21285-timer.o ...@@ -26,3 +26,5 @@ obj-$(CONFIG_ARCH_PERSONAL_SERVER) += personal.o dc21285-timer.o
obj-$(CONFIG_PCI) +=$(pci-y) obj-$(CONFIG_PCI) +=$(pci-y)
obj-$(CONFIG_LEDS) +=$(leds-y) obj-$(CONFIG_LEDS) +=$(leds-y)
obj-$(CONFIG_ISA) += isa.o
/*
* linux/arch/arm/mach-footbridge/isa.c
*
* Copyright (C) 2004 Russell King.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/serial_8250.h>
#include <asm/irq.h>
static struct plat_serial8250_port serial_platform_data[] = {
{
.iobase = 0x3f8,
.irq = IRQ_ISA_UART,
.uartclk = 1843200,
.regshift = 0,
.iotype = UPIO_PORT,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
},
{
.iobase = 0x2f8,
.irq = IRQ_ISA_UART2,
.uartclk = 1843200,
.regshift = 0,
.iotype = UPIO_PORT,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
},
{ },
};
static struct platform_device serial_device = {
.name = "serial8250",
.id = 0,
.dev = {
.platform_data = serial_platform_data,
},
};
static int __init footbridge_isa_init(void)
{
return platform_device_register(&serial_device);
}
arch_initcall(footbridge_isa_init);
/*
* linux/arch/arm/mach-h720x/common.h
*
* Copyright (C) 2003 Thomas Gleixner <tglx@linutronix.de>
* 2003 Robert Schwebel <r.schwebel@pengutronix.de>
* 2004 Sascha Hauer <s.hauer@pengutronix.de>
*
* Architecture specific stuff for Hynix GMS30C7201 development board
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
extern unsigned long h720x_gettimeoffset(void);
extern void __init h720x_init_irq (void);
extern void __init h720x_map_io(void);
#ifdef CONFIG_ARCH_H7202
extern struct sys_timer h7202_timer;
extern void __init init_hw_h7202(void);
extern void __init h7202_init_irq (void);
extern void __init h7202_init_time(void);
#endif
#ifdef CONFIG_ARCH_H7201
extern struct sys_timer h7201_timer;
#endif
...@@ -22,10 +22,7 @@ ...@@ -22,10 +22,7 @@
#include <asm/arch/irqs.h> #include <asm/arch/irqs.h>
#include <asm/mach/irq.h> #include <asm/mach/irq.h>
#include <asm/mach/time.h> #include <asm/mach/time.h>
#include "common.h"
extern unsigned long h720x_gettimeoffset(void);
extern void __init h720x_init_irq (void);
/* /*
* Timer interrupt handler * Timer interrupt handler
*/ */
...@@ -53,8 +50,6 @@ static struct irqaction h7201_timer_irq = { ...@@ -53,8 +50,6 @@ static struct irqaction h7201_timer_irq = {
*/ */
void __init h7201_init_time(void) void __init h7201_init_time(void)
{ {
gettimeoffset = h720x_gettimeoffset;
CPU_REG (TIMER_VIRT, TM0_PERIOD) = LATCH; CPU_REG (TIMER_VIRT, TM0_PERIOD) = LATCH;
CPU_REG (TIMER_VIRT, TM0_CTRL) = TM_RESET; CPU_REG (TIMER_VIRT, TM0_CTRL) = TM_RESET;
CPU_REG (TIMER_VIRT, TM0_CTRL) = TM_REPEAT | TM_START; CPU_REG (TIMER_VIRT, TM0_CTRL) = TM_REPEAT | TM_START;
...@@ -62,3 +57,8 @@ void __init h7201_init_time(void) ...@@ -62,3 +57,8 @@ void __init h7201_init_time(void)
setup_irq(IRQ_TIMER0, &h7201_timer_irq); setup_irq(IRQ_TIMER0, &h7201_timer_irq);
} }
struct sys_timer h7201_timer = {
.init = h7201_init_time,
.offset = h720x_gettimeoffset,
};
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#include <asm/mach/irq.h> #include <asm/mach/irq.h>
#include <asm/mach/time.h> #include <asm/mach/time.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/serial_8250.h>
#include "common.h"
static struct resource h7202ps2_resources[] = { static struct resource h7202ps2_resources[] = {
[0] = { [0] = {
...@@ -44,13 +46,55 @@ static struct platform_device h7202ps2_device = { ...@@ -44,13 +46,55 @@ static struct platform_device h7202ps2_device = {
.resource = h7202ps2_resources, .resource = h7202ps2_resources,
}; };
static struct plat_serial8250_port serial_platform_data[] = {
{
.membase = SERIAL0_BASE,
.irq = IRQ_UART0,
.uartclk = 2*1843200,
.regshift = 2,
.iotype = UPIO_MEM,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
},
{
.membase = SERIAL1_BASE,
.irq = IRQ_UART1,
.uartclk = 2*1843200,
.regshift = 2,
.iotype = UPIO_MEM,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
},
{
.membase = SERIAL2_BASE,
.irq = IRQ_UART2,
.uartclk = 2*1843200,
.regshift = 2,
.iotype = UPIO_MEM,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
},
{
.membase = SERIAL3_BASE,
.irq = IRQ_UART3,
.uartclk = 2*1843200,
.regshift = 2,
.iotype = UPIO_MEM,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
},
{ },
};
static struct platform_device serial_device = {
.name = "serial8250",
.id = 0,
.dev = {
.platform_data = serial_platform_data,
},
};
static struct platform_device *devices[] __initdata = { static struct platform_device *devices[] __initdata = {
&h7202ps2_device, &h7202ps2_device,
&serial_device,
}; };
extern unsigned long h720x_gettimeoffset(void);
extern void __init h720x_init_irq (void);
/* Although we have two interrupt lines for the timers, we only have one /* Although we have two interrupt lines for the timers, we only have one
* status register which clears all pending timer interrupts on reading. So * status register which clears all pending timer interrupts on reading. So
* we have to handle all timer interrupts in one place. * we have to handle all timer interrupts in one place.
...@@ -130,8 +174,6 @@ static struct irqaction h7202_timer_irq = { ...@@ -130,8 +174,6 @@ static struct irqaction h7202_timer_irq = {
*/ */
void __init h7202_init_time(void) void __init h7202_init_time(void)
{ {
gettimeoffset = h720x_gettimeoffset;
CPU_REG (TIMER_VIRT, TM0_PERIOD) = LATCH; CPU_REG (TIMER_VIRT, TM0_PERIOD) = LATCH;
CPU_REG (TIMER_VIRT, TM0_CTRL) = TM_RESET; CPU_REG (TIMER_VIRT, TM0_CTRL) = TM_RESET;
CPU_REG (TIMER_VIRT, TM0_CTRL) = TM_REPEAT | TM_START; CPU_REG (TIMER_VIRT, TM0_CTRL) = TM_REPEAT | TM_START;
...@@ -140,6 +182,11 @@ void __init h7202_init_time(void) ...@@ -140,6 +182,11 @@ void __init h7202_init_time(void)
setup_irq(IRQ_TIMER0, &h7202_timer_irq); setup_irq(IRQ_TIMER0, &h7202_timer_irq);
} }
struct sys_timer h7202_timer = {
.init = h7202_init_time,
.offset = h720x_gettimeoffset,
};
void __init h7202_init_irq (void) void __init h7202_init_irq (void)
{ {
int irq; int irq;
......
...@@ -27,10 +27,7 @@ ...@@ -27,10 +27,7 @@
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include "common.h"
extern void h720x_init_irq (void);
extern void h7201_init_time(void);
extern void __init h720x_map_io(void);
MACHINE_START(H7201, "Hynix GMS30C7201") MACHINE_START(H7201, "Hynix GMS30C7201")
MAINTAINER("Robert Schwebel, Pengutronix") MAINTAINER("Robert Schwebel, Pengutronix")
...@@ -38,5 +35,5 @@ MACHINE_START(H7201, "Hynix GMS30C7201") ...@@ -38,5 +35,5 @@ MACHINE_START(H7201, "Hynix GMS30C7201")
BOOT_PARAMS(0xc0001000) BOOT_PARAMS(0xc0001000)
MAPIO(h720x_map_io) MAPIO(h720x_map_io)
INITIRQ(h720x_init_irq) INITIRQ(h720x_init_irq)
INITTIME(h7201_init_time) .timer = &h7201_timer,
MACHINE_END MACHINE_END
...@@ -27,11 +27,7 @@ ...@@ -27,11 +27,7 @@
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include "common.h"
extern void __init init_hw_h7202(void);
extern void __init h7202_init_irq (void);
extern void __init h7202_init_time(void);
extern void __init h720x_map_io(void);
static struct resource cirrus_resources[] = { static struct resource cirrus_resources[] = {
[0] = { [0] = {
...@@ -80,6 +76,6 @@ MACHINE_START(H7202, "Hynix HMS30C7202") ...@@ -80,6 +76,6 @@ MACHINE_START(H7202, "Hynix HMS30C7202")
BOOT_PARAMS(0x40000100) BOOT_PARAMS(0x40000100)
MAPIO(h720x_map_io) MAPIO(h720x_map_io)
INITIRQ(h7202_init_irq) INITIRQ(h7202_init_irq)
INITTIME(h7202_init_time) .timer = &h7202_timer,
INIT_MACHINE(init_eval_h7202) INIT_MACHINE(init_eval_h7202)
MACHINE_END MACHINE_END
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
#include <linux/console.h> #include <linux/console.h>
#include <linux/serial.h> #include <linux/serial.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/serial_core.h> #include <linux/serial_8250.h>
#include <linux/serial_reg.h> #include <linux/serial_reg.h>
#include <asm/hardware.h> #include <asm/hardware.h>
...@@ -307,34 +307,36 @@ void omap_map_io(void) ...@@ -307,34 +307,36 @@ void omap_map_io(void)
_omap_map_io(); _omap_map_io();
} }
static inline unsigned int omap_serial_in(struct uart_port *up, int offset) static inline unsigned int omap_serial_in(struct plat_serial8250_port *up,
int offset)
{ {
offset <<= up->regshift; offset <<= up->regshift;
return (unsigned int)__raw_readb(up->membase + offset); return (unsigned int)__raw_readb(up->membase + offset);
} }
static inline void omap_serial_outp(struct uart_port *up, int offset, int value) static inline void omap_serial_outp(struct plat_serial8250_port *p, int offset,
int value)
{ {
offset <<= up->regshift; offset <<= p->regshift;
__raw_writeb(value, up->membase + offset); __raw_writeb(value, p->membase + offset);
} }
/* /*
* Internal UARTs need to be initialized for the 8250 autoconfig to work * Internal UARTs need to be initialized for the 8250 autoconfig to work
* properly. * properly.
*/ */
static void __init omap_serial_reset(struct uart_port *up) static void __init omap_serial_reset(struct plat_serial8250_port *p)
{ {
omap_serial_outp(up, UART_OMAP_MDR1, 0x07); /* disable UART */ omap_serial_outp(p, UART_OMAP_MDR1, 0x07); /* disable UART */
omap_serial_outp(up, UART_OMAP_MDR1, 0x00); /* enable UART */ omap_serial_outp(p, UART_OMAP_MDR1, 0x00); /* enable UART */
if (!cpu_is_omap1510()) { if (!cpu_is_omap1510()) {
omap_serial_outp(up, UART_OMAP_SYSC, 0x01); omap_serial_outp(p, UART_OMAP_SYSC, 0x01);
while (!(omap_serial_in(up, UART_OMAP_SYSC) & 0x01)); while (!(omap_serial_in(p, UART_OMAP_SYSC) & 0x01));
} }
} }
static struct uart_port omap_serial_ports[] = { static struct plat_serial8250_port serial_platform_data[] = {
{ {
.membase = (char*)IO_ADDRESS(OMAP_UART1_BASE), .membase = (char*)IO_ADDRESS(OMAP_UART1_BASE),
.mapbase = (unsigned long)OMAP_UART1_BASE, .mapbase = (unsigned long)OMAP_UART1_BASE,
...@@ -343,10 +345,8 @@ static struct uart_port omap_serial_ports[] = { ...@@ -343,10 +345,8 @@ static struct uart_port omap_serial_ports[] = {
.iotype = UPIO_MEM, .iotype = UPIO_MEM,
.regshift = 2, .regshift = 2,
.uartclk = OMAP16XX_BASE_BAUD * 16, .uartclk = OMAP16XX_BASE_BAUD * 16,
.line = 0, },
.type = PORT_16654, {
.fifosize = 64
} , {
.membase = (char*)IO_ADDRESS(OMAP_UART2_BASE), .membase = (char*)IO_ADDRESS(OMAP_UART2_BASE),
.mapbase = (unsigned long)OMAP_UART2_BASE, .mapbase = (unsigned long)OMAP_UART2_BASE,
.irq = INT_UART2, .irq = INT_UART2,
...@@ -354,10 +354,8 @@ static struct uart_port omap_serial_ports[] = { ...@@ -354,10 +354,8 @@ static struct uart_port omap_serial_ports[] = {
.iotype = UPIO_MEM, .iotype = UPIO_MEM,
.regshift = 2, .regshift = 2,
.uartclk = OMAP16XX_BASE_BAUD * 16, .uartclk = OMAP16XX_BASE_BAUD * 16,
.line = 1, },
.type = PORT_16654, {
.fifosize = 64
} , {
.membase = (char*)IO_ADDRESS(OMAP_UART3_BASE), .membase = (char*)IO_ADDRESS(OMAP_UART3_BASE),
.mapbase = (unsigned long)OMAP_UART3_BASE, .mapbase = (unsigned long)OMAP_UART3_BASE,
.irq = INT_UART3, .irq = INT_UART3,
...@@ -365,10 +363,16 @@ static struct uart_port omap_serial_ports[] = { ...@@ -365,10 +363,16 @@ static struct uart_port omap_serial_ports[] = {
.iotype = UPIO_MEM, .iotype = UPIO_MEM,
.regshift = 2, .regshift = 2,
.uartclk = OMAP16XX_BASE_BAUD * 16, .uartclk = OMAP16XX_BASE_BAUD * 16,
.line = 2, },
.type = PORT_16654, { },
.fifosize = 64 };
}
static struct platform_device serial_device = {
.name = "serial8250",
.id = 0,
.dev = {
.platform_data = serial_platform_data,
},
}; };
/* /*
...@@ -381,23 +385,26 @@ void __init omap_serial_init(int ports[OMAP_MAX_NR_PORTS]) ...@@ -381,23 +385,26 @@ void __init omap_serial_init(int ports[OMAP_MAX_NR_PORTS])
int i; int i;
if (cpu_is_omap730()) { if (cpu_is_omap730()) {
omap_serial_ports[0].regshift = 0; serial_platform_data[0].regshift = 0;
omap_serial_ports[1].regshift = 0; serial_platform_data[1].regshift = 0;
omap_serial_ports[0].irq = INT_730_UART_MODEM_1; serial_platform_data[0].irq = INT_730_UART_MODEM_1;
omap_serial_ports[1].irq = INT_730_UART_MODEM_IRDA_2; serial_platform_data[1].irq = INT_730_UART_MODEM_IRDA_2;
} }
if (cpu_is_omap1510()) { if (cpu_is_omap1510()) {
omap_serial_ports[0].uartclk = OMAP1510_BASE_BAUD * 16; serial_platform_data[0].uartclk = OMAP1510_BASE_BAUD * 16;
omap_serial_ports[1].uartclk = OMAP1510_BASE_BAUD * 16; serial_platform_data[1].uartclk = OMAP1510_BASE_BAUD * 16;
omap_serial_ports[2].uartclk = OMAP1510_BASE_BAUD * 16; serial_platform_data[2].uartclk = OMAP1510_BASE_BAUD * 16;
} }
for (i = 0; i < OMAP_MAX_NR_PORTS; i++) { for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
unsigned char reg; unsigned char reg;
if (ports[i] != 1) if (ports[i] == 0) {
serial_platform_data[i].membase = 0;
serial_platform_data[i].mapbase = 0;
continue; continue;
}
switch (i) { switch (i) {
case 0: case 0:
...@@ -431,11 +438,16 @@ void __init omap_serial_init(int ports[OMAP_MAX_NR_PORTS]) ...@@ -431,11 +438,16 @@ void __init omap_serial_init(int ports[OMAP_MAX_NR_PORTS])
} }
break; break;
} }
omap_serial_reset(&omap_serial_ports[i]); omap_serial_reset(&serial_platform_data[i]);
early_serial_setup(&omap_serial_ports[i]);
} }
} }
static int __init omap_init(void)
{
return platform_device_register(&serial_device);
}
arch_initcall(omap_init);
#define NO_LENGTH_CHECK 0xffffffff #define NO_LENGTH_CHECK 0xffffffff
extern int omap_bootloader_tag_len; extern int omap_bootloader_tag_len;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/serial_8250.h>
#include <asm/elf.h> #include <asm/elf.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -130,9 +131,30 @@ static struct platform_device kbd_device = { ...@@ -130,9 +131,30 @@ static struct platform_device kbd_device = {
}, },
}; };
static struct plat_serial8250_port serial_platform_data[] = {
{
.mapbase = 0x03010fe0,
.irq = 10,
.uartclk = 1843200,
.regshift = 2,
.iotype = UPIO_MEM,
.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_SKIP_TEST,
},
{ },
};
static struct platform_device serial_device = {
.name = "serial8250",
.id = 0,
.dev = {
.platform_data = serial_platform_data,
},
};
static struct platform_device *devs[] __initdata = { static struct platform_device *devs[] __initdata = {
&iomd_device, &iomd_device,
&kbd_device, &kbd_device,
&serial_device,
&acornfb_device, &acornfb_device,
}; };
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/serial_8250.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/hardware.h> #include <asm/hardware.h>
...@@ -32,9 +33,6 @@ ...@@ -32,9 +33,6 @@
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include <asm/mach/irq.h> #include <asm/mach/irq.h>
#include <asm/mach/serial_sa1100.h> #include <asm/mach/serial_sa1100.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <asm/arch/serial.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -178,6 +176,34 @@ static void trizeps_power_off(void) ...@@ -178,6 +176,34 @@ static void trizeps_power_off(void)
PMCR = PMCR_SF; PMCR = PMCR_SF;
} }
static struct plat_serial8250_port serial_platform_data[] = {
{
.mapbase = TRIZEPS_UART5,
.irq = IRQ_GPIO16,
.uartclk = 24000000,
.regshift = 0,
.iotype = UPIO_PORT,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
},
{
.mapbase = TRIZEPS_UART6,
.irq = IRQ_GPIO17,
.uartclk = 24000000,
.regshift = 0,
.iotype = UPIO_PORT,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
},
{ },
};
static struct platform_device serial_device = {
.name = "serial8250",
.id = 0,
.dev = {
.platform_data = serial_platform_data,
},
};
static int __init trizeps_init(void) static int __init trizeps_init(void)
{ {
if (!machine_is_trizeps()) if (!machine_is_trizeps())
...@@ -201,6 +227,8 @@ static int __init trizeps_init(void) ...@@ -201,6 +227,8 @@ static int __init trizeps_init(void)
set_irq_type(IRQ_GPIO16, IRQT_RISING); set_irq_type(IRQ_GPIO16, IRQT_RISING);
set_irq_type(IRQ_GPIO17, IRQT_RISING); set_irq_type(IRQ_GPIO17, IRQT_RISING);
platform_device_register(&serial_device);
return 0; return 0;
} }
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/serial_8250.h>
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
...@@ -18,6 +19,46 @@ ...@@ -18,6 +19,46 @@
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/mach/time.h> #include <asm/mach/time.h>
static struct plat_serial8250_port serial_platform_data[] = {
{
.iobase = 0x3f8,
.irq = 4,
.uartclk = 1843200,
.regshift = 2,
.iotype = UPIO_PORT,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
},
{
.iobase = 0x2f8,
.irq = 3,
.uartclk = 1843200,
.regshift = 2,
.iotype = UPIO_PORT,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
},
{ },
};
static struct platform_device serial_device = {
.name = "serial8250",
.id = 0,
.dev = {
.platform_data = serial_platform_data,
},
};
static int __init shark_init(void)
{
int ret;
if (machine_is_shark())
ret = platform_device_register(&serial_device);
return ret;
}
arch_initcall(shark_init);
extern void shark_init_irq(void); extern void shark_init_irq(void);
static struct map_desc shark_io_desc[] __initdata = { static struct map_desc shark_io_desc[] __initdata = {
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
# To add an entry into this database, please see Documentation/arm/README, # To add an entry into this database, please see Documentation/arm/README,
# or contact rmk@arm.linux.org.uk # or contact rmk@arm.linux.org.uk
# #
# Last update: Thu Sep 30 15:23:21 2004 # Last update: Sun Nov 7 13:20:41 2004
# #
# machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number
# #
...@@ -595,8 +595,8 @@ pxa_dnp2110 MACH_PXA_DNP2110 PXA_DNP2110 584 ...@@ -595,8 +595,8 @@ pxa_dnp2110 MACH_PXA_DNP2110 PXA_DNP2110 584
xaeniax MACH_XAENIAX XAENIAX 585 xaeniax MACH_XAENIAX XAENIAX 585
somn4250 MACH_SOMN4250 SOMN4250 586 somn4250 MACH_SOMN4250 SOMN4250 586
pleb2 MACH_PLEB2 PLEB2 587 pleb2 MACH_PLEB2 PLEB2 587
cwl MACH_CWL CWL 588 cornwallis MACH_CORNWALLIS CORNWALLIS 588
gd MACH_GD GD 589 gurney_drv MACH_GURNEY_DRV GURNEY_DRV 589
chaffee MACH_CHAFFEE CHAFFEE 590 chaffee MACH_CHAFFEE CHAFFEE 590
rms101 MACH_RMS101 RMS101 591 rms101 MACH_RMS101 RMS101 591
rx3715 MACH_RX3715 RX3715 592 rx3715 MACH_RX3715 RX3715 592
...@@ -615,3 +615,22 @@ ixdpg425 MACH_IXDPG425 IXDPG425 604 ...@@ -615,3 +615,22 @@ ixdpg425 MACH_IXDPG425 IXDPG425 604
tomtomgo MACH_TOMTOMGO TOMTOMGO 605 tomtomgo MACH_TOMTOMGO TOMTOMGO 605
versatile_ab MACH_VERSATILE_AB VERSATILE_AB 606 versatile_ab MACH_VERSATILE_AB VERSATILE_AB 606
edb9307 MACH_EDB9307 EDB9307 607 edb9307 MACH_EDB9307 EDB9307 607
sg565 MACH_SG565 SG565 608
lpd79524 MACH_LPD79524 LPD79524 609
lpd79525 MACH_LPD79525 LPD79525 610
rms100 MACH_RMS100 RMS100 611
kb9200 MACH_KB9200 KB9200 612
sx1 MACH_SX1 SX1 613
hms39c7092 MACH_HMS39C7092 HMS39C7092 614
armadillo MACH_ARMADILLO ARMADILLO 615
ipcu MACH_IPCU IPCU 616
loox720 MACH_LOOX720 LOOX720 617
ixdp465 MACH_IXDP465 IXDP465 618
ixdp2351 MACH_IXDP2351 IXDP2351 619
adsvix MACH_ADSVIX ADSVIX 620
dm270 MACH_DM270 DM270 621
socltplus MACH_SOCLTPLUS SOCLTPLUS 622
ecia MACH_ECIA ECIA 623
cm4008 MACH_CM4008 CM4008 624
p2001 MACH_P2001 P2001 625
twister MACH_TWISTER TWISTER 626
...@@ -689,7 +689,7 @@ static int __init detect_init_APIC (void) ...@@ -689,7 +689,7 @@ static int __init detect_init_APIC (void)
u32 h, l, features; u32 h, l, features;
extern void get_cpu_vendor(struct cpuinfo_x86*); extern void get_cpu_vendor(struct cpuinfo_x86*);
/* Disabled by DMI scan or kernel option? */ /* Disabled by kernel option? */
if (enable_local_apic < 0) if (enable_local_apic < 0)
return -1; return -1;
...@@ -703,8 +703,7 @@ static int __init detect_init_APIC (void) ...@@ -703,8 +703,7 @@ static int __init detect_init_APIC (void)
break; break;
goto no_apic; goto no_apic;
case X86_VENDOR_INTEL: case X86_VENDOR_INTEL:
if (boot_cpu_data.x86 == 6 || if (boot_cpu_data.x86 == 6 || boot_cpu_data.x86 == 15 ||
(boot_cpu_data.x86 == 15 && (cpu_has_apic || enable_local_apic > 0)) ||
(boot_cpu_data.x86 == 5 && cpu_has_apic)) (boot_cpu_data.x86 == 5 && cpu_has_apic))
break; break;
goto no_apic; goto no_apic;
...@@ -714,15 +713,20 @@ static int __init detect_init_APIC (void) ...@@ -714,15 +713,20 @@ static int __init detect_init_APIC (void)
if (!cpu_has_apic) { if (!cpu_has_apic) {
/* /*
* Over-ride BIOS and try to enable LAPIC * Over-ride BIOS and try to enable the local
* only if "lapic" specified * APIC only if "lapic" specified.
*/ */
if (enable_local_apic != 1) if (enable_local_apic <= 0) {
goto no_apic; apic_printk(APIC_VERBOSE,
"Local APIC disabled by BIOS -- "
"you can enable it with \"lapic\"\n");
return -1;
}
/* /*
* Some BIOSes disable the local APIC in the * Some BIOSes disable the local APIC in the
* APIC_BASE MSR. This can only be done in * APIC_BASE MSR. This can only be done in
* software for Intel P6 and AMD K7 (Model > 1). * software for Intel P6 or later and AMD K7
* (Model > 1) or later.
*/ */
rdmsr(MSR_IA32_APICBASE, l, h); rdmsr(MSR_IA32_APICBASE, l, h);
if (!(l & MSR_IA32_APICBASE_ENABLE)) { if (!(l & MSR_IA32_APICBASE_ENABLE)) {
......
...@@ -42,6 +42,7 @@ static struct pt_regs jprobe_saved_regs; ...@@ -42,6 +42,7 @@ static struct pt_regs jprobe_saved_regs;
static long *jprobe_saved_esp; static long *jprobe_saved_esp;
/* copy of the kernel stack at the probe fire time */ /* copy of the kernel stack at the probe fire time */
static kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE]; static kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE];
void jprobe_return_end(void);
/* /*
* returns non-zero if opcode modifies the interrupt flag. * returns non-zero if opcode modifies the interrupt flag.
...@@ -58,9 +59,14 @@ static inline int is_IF_modifier(kprobe_opcode_t opcode) ...@@ -58,9 +59,14 @@ static inline int is_IF_modifier(kprobe_opcode_t opcode)
return 0; return 0;
} }
void arch_prepare_kprobe(struct kprobe *p) int arch_prepare_kprobe(struct kprobe *p)
{
memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
return 0;
}
void arch_remove_kprobe(struct kprobe *p)
{ {
memcpy(p->insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
} }
static inline void disarm_kprobe(struct kprobe *p, struct pt_regs *regs) static inline void disarm_kprobe(struct kprobe *p, struct pt_regs *regs)
...@@ -73,7 +79,7 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) ...@@ -73,7 +79,7 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
{ {
regs->eflags |= TF_MASK; regs->eflags |= TF_MASK;
regs->eflags &= ~IF_MASK; regs->eflags &= ~IF_MASK;
regs->eip = (unsigned long)&p->insn; regs->eip = (unsigned long)&p->ainsn.insn;
} }
/* /*
...@@ -153,7 +159,7 @@ static inline int kprobe_handler(struct pt_regs *regs) ...@@ -153,7 +159,7 @@ static inline int kprobe_handler(struct pt_regs *regs)
* instruction. To avoid the SMP problems that can occur when we * instruction. To avoid the SMP problems that can occur when we
* temporarily put back the original opcode to single-step, we * temporarily put back the original opcode to single-step, we
* single-stepped a copy of the instruction. The address of this * single-stepped a copy of the instruction. The address of this
* copy is p->insn. * copy is p->ainsn.insn.
* *
* This function prepares to return from the post-single-step * This function prepares to return from the post-single-step
* interrupt. We have to fix up the stack as follows: * interrupt. We have to fix up the stack as follows:
...@@ -173,10 +179,10 @@ static void resume_execution(struct kprobe *p, struct pt_regs *regs) ...@@ -173,10 +179,10 @@ static void resume_execution(struct kprobe *p, struct pt_regs *regs)
{ {
unsigned long *tos = (unsigned long *)&regs->esp; unsigned long *tos = (unsigned long *)&regs->esp;
unsigned long next_eip = 0; unsigned long next_eip = 0;
unsigned long copy_eip = (unsigned long)&p->insn; unsigned long copy_eip = (unsigned long)&p->ainsn.insn;
unsigned long orig_eip = (unsigned long)p->addr; unsigned long orig_eip = (unsigned long)p->addr;
switch (p->insn[0]) { switch (p->ainsn.insn[0]) {
case 0x9c: /* pushfl */ case 0x9c: /* pushfl */
*tos &= ~(TF_MASK | IF_MASK); *tos &= ~(TF_MASK | IF_MASK);
*tos |= kprobe_old_eflags; *tos |= kprobe_old_eflags;
...@@ -185,13 +191,13 @@ static void resume_execution(struct kprobe *p, struct pt_regs *regs) ...@@ -185,13 +191,13 @@ static void resume_execution(struct kprobe *p, struct pt_regs *regs)
*tos = orig_eip + (*tos - copy_eip); *tos = orig_eip + (*tos - copy_eip);
break; break;
case 0xff: case 0xff:
if ((p->insn[1] & 0x30) == 0x10) { if ((p->ainsn.insn[1] & 0x30) == 0x10) {
/* call absolute, indirect */ /* call absolute, indirect */
/* Fix return addr; eip is correct. */ /* Fix return addr; eip is correct. */
next_eip = regs->eip; next_eip = regs->eip;
*tos = orig_eip + (*tos - copy_eip); *tos = orig_eip + (*tos - copy_eip);
} else if (((p->insn[1] & 0x31) == 0x20) || /* jmp near, absolute indirect */ } else if (((p->ainsn.insn[1] & 0x31) == 0x20) || /* jmp near, absolute indirect */
((p->insn[1] & 0x31) == 0x21)) { /* jmp far, absolute indirect */ ((p->ainsn.insn[1] & 0x31) == 0x21)) { /* jmp far, absolute indirect */
/* eip is correct. */ /* eip is correct. */
next_eip = regs->eip; next_eip = regs->eip;
} }
...@@ -315,12 +321,12 @@ void jprobe_return(void) ...@@ -315,12 +321,12 @@ void jprobe_return(void)
{ {
preempt_enable_no_resched(); preempt_enable_no_resched();
asm volatile (" xchgl %%ebx,%%esp \n" asm volatile (" xchgl %%ebx,%%esp \n"
" int3 \n"::"b" " int3 \n"
" .globl jprobe_return_end \n"
" jprobe_return_end: \n"
" nop \n"::"b"
(jprobe_saved_esp):"memory"); (jprobe_saved_esp):"memory");
} }
void jprobe_return_end(void)
{
};
int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
{ {
......
...@@ -344,6 +344,36 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ...@@ -344,6 +344,36 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
if(addr < (long) &dummy->u_debugreg[4] && if(addr < (long) &dummy->u_debugreg[4] &&
((unsigned long) data) >= TASK_SIZE-3) break; ((unsigned long) data) >= TASK_SIZE-3) break;
/* Sanity-check data. Take one half-byte at once with
* check = (val >> (16 + 4*i)) & 0xf. It contains the
* R/Wi and LENi bits; bits 0 and 1 are R/Wi, and bits
* 2 and 3 are LENi. Given a list of invalid values,
* we do mask |= 1 << invalid_value, so that
* (mask >> check) & 1 is a correct test for invalid
* values.
*
* R/Wi contains the type of the breakpoint /
* watchpoint, LENi contains the length of the watched
* data in the watchpoint case.
*
* The invalid values are:
* - LENi == 0x10 (undefined), so mask |= 0x0f00.
* - R/Wi == 0x10 (break on I/O reads or writes), so
* mask |= 0x4444.
* - R/Wi == 0x00 && LENi != 0x00, so we have mask |=
* 0x1110.
*
* Finally, mask = 0x0f00 | 0x4444 | 0x1110 == 0x5f54.
*
* See the Intel Manual "System Programming Guide",
* 15.2.4
*
* Note that LENi == 0x10 is defined on x86_64 in long
* mode (i.e. even for 32-bit userspace software, but
* 64-bit kernel), so the x86_64 mask value is 0x5454.
* See the AMD manual no. 24593 (AMD64 System
* Programming)*/
if(addr == (long) &dummy->u_debugreg[7]) { if(addr == (long) &dummy->u_debugreg[7]) {
data &= ~DR_CONTROL_RESERVED; data &= ~DR_CONTROL_RESERVED;
for(i=0; i<4; i++) for(i=0; i<4; i++)
......
...@@ -583,7 +583,11 @@ void die_nmi (struct pt_regs *regs, const char *msg) ...@@ -583,7 +583,11 @@ void die_nmi (struct pt_regs *regs, const char *msg)
static void default_do_nmi(struct pt_regs * regs) static void default_do_nmi(struct pt_regs * regs)
{ {
unsigned char reason = get_nmi_reason(); unsigned char reason = 0;
/* Only the BSP gets external NMIs from the system. */
if (!smp_processor_id())
reason = get_nmi_reason();
if (!(reason & 0xc0)) { if (!(reason & 0xc0)) {
if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 0, SIGINT) if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 0, SIGINT)
......
...@@ -208,7 +208,6 @@ void kernel_map_pages(struct page *page, int numpages, int enable) ...@@ -208,7 +208,6 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
*/ */
__flush_tlb_all(); __flush_tlb_all();
} }
EXPORT_SYMBOL(kernel_map_pages);
#endif #endif
EXPORT_SYMBOL(change_page_attr); EXPORT_SYMBOL(change_page_attr);
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#include <asm/io.h> #include <asm/io.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
#include <linux/types.h> #include <linux/types.h>
#define M32R_PCC_IOMAP_SIZE 0x1000 #define M32R_PCC_IOMAP_SIZE 0x1000
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
extern void pcc_ioread(int, unsigned long, void *, size_t, size_t, int); extern void pcc_ioread(int, unsigned long, void *, size_t, size_t, int);
extern void pcc_iowrite(int, unsigned long, void *, size_t, size_t, int); extern void pcc_iowrite(int, unsigned long, void *, size_t, size_t, int);
#endif /* CONFIG_PCMCIA && CONFIG_M32RPCC */ #endif /* CONFIG_PCMCIA && CONFIG_M32R_PCC */
#define PORT2ADDR(port) _port2addr(port) #define PORT2ADDR(port) _port2addr(port)
...@@ -80,7 +80,7 @@ unsigned char _inb(unsigned long port) ...@@ -80,7 +80,7 @@ unsigned char _inb(unsigned long port)
if (port >= 0x300 && port < 0x320) if (port >= 0x300 && port < 0x320)
return _ne_inb(PORT2ADDR_NE(port)); return _ne_inb(PORT2ADDR_NE(port));
else else
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
unsigned char b; unsigned char b;
pcc_ioread(0, port, &b, sizeof(b), 1, 0); pcc_ioread(0, port, &b, sizeof(b), 1, 0);
...@@ -100,7 +100,7 @@ unsigned short _inw(unsigned long port) ...@@ -100,7 +100,7 @@ unsigned short _inw(unsigned long port)
if (port >= 0x300 && port < 0x320) if (port >= 0x300 && port < 0x320)
return _ne_inw(PORT2ADDR_NE(port)); return _ne_inw(PORT2ADDR_NE(port));
else else
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
unsigned short w; unsigned short w;
pcc_ioread(0, port, &w, sizeof(w), 1, 0); pcc_ioread(0, port, &w, sizeof(w), 1, 0);
...@@ -116,7 +116,7 @@ unsigned short _inw(unsigned long port) ...@@ -116,7 +116,7 @@ unsigned short _inw(unsigned long port)
unsigned long _inl(unsigned long port) unsigned long _inl(unsigned long port)
{ {
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
unsigned long l; unsigned long l;
pcc_ioread(0, port, &l, sizeof(l), 1, 0); pcc_ioread(0, port, &l, sizeof(l), 1, 0);
...@@ -137,7 +137,7 @@ unsigned char _inb_p(unsigned long port) ...@@ -137,7 +137,7 @@ unsigned char _inb_p(unsigned long port)
if (port >= 0x300 && port < 0x320) if (port >= 0x300 && port < 0x320)
v = _ne_inb(PORT2ADDR_NE(port)); v = _ne_inb(PORT2ADDR_NE(port));
else else
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
unsigned char b; unsigned char b;
pcc_ioread(0, port, &b, sizeof(b), 1, 0); pcc_ioread(0, port, &b, sizeof(b), 1, 0);
...@@ -161,7 +161,7 @@ unsigned short _inw_p(unsigned long port) ...@@ -161,7 +161,7 @@ unsigned short _inw_p(unsigned long port)
if (port >= 0x300 && port < 0x320) if (port >= 0x300 && port < 0x320)
v = _ne_inw(PORT2ADDR_NE(port)); v = _ne_inw(PORT2ADDR_NE(port));
else else
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
unsigned short w; unsigned short w;
pcc_ioread(0, port, &w, sizeof(w), 1, 0); pcc_ioread(0, port, &w, sizeof(w), 1, 0);
...@@ -192,7 +192,7 @@ void _outb(unsigned char b, unsigned long port) ...@@ -192,7 +192,7 @@ void _outb(unsigned char b, unsigned long port)
if (port >= 0x300 && port < 0x320) if (port >= 0x300 && port < 0x320)
_ne_outb(b, PORT2ADDR_NE(port)); _ne_outb(b, PORT2ADDR_NE(port));
else else
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
pcc_iowrite(0, port, &b, sizeof(b), 1, 0); pcc_iowrite(0, port, &b, sizeof(b), 1, 0);
} else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
...@@ -207,7 +207,7 @@ void _outw(unsigned short w, unsigned long port) ...@@ -207,7 +207,7 @@ void _outw(unsigned short w, unsigned long port)
if (port >= 0x300 && port < 0x320) if (port >= 0x300 && port < 0x320)
_ne_outw(w, PORT2ADDR_NE(port)); _ne_outw(w, PORT2ADDR_NE(port));
else else
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
pcc_iowrite(0, port, &w, sizeof(w), 1, 0); pcc_iowrite(0, port, &w, sizeof(w), 1, 0);
} else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
...@@ -219,7 +219,7 @@ void _outw(unsigned short w, unsigned long port) ...@@ -219,7 +219,7 @@ void _outw(unsigned short w, unsigned long port)
void _outl(unsigned long l, unsigned long port) void _outl(unsigned long l, unsigned long port)
{ {
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
pcc_iowrite(0, port, &l, sizeof(l), 1, 0); pcc_iowrite(0, port, &l, sizeof(l), 1, 0);
} else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
...@@ -234,7 +234,7 @@ void _outb_p(unsigned char b, unsigned long port) ...@@ -234,7 +234,7 @@ void _outb_p(unsigned char b, unsigned long port)
if (port >= 0x300 && port < 0x320) if (port >= 0x300 && port < 0x320)
_ne_outb(b, PORT2ADDR_NE(port)); _ne_outb(b, PORT2ADDR_NE(port));
else else
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
pcc_iowrite(0, port, &b, sizeof(b), 1, 0); pcc_iowrite(0, port, &b, sizeof(b), 1, 0);
} else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
...@@ -251,7 +251,7 @@ void _outw_p(unsigned short w, unsigned long port) ...@@ -251,7 +251,7 @@ void _outw_p(unsigned short w, unsigned long port)
if (port >= 0x300 && port < 0x320) if (port >= 0x300 && port < 0x320)
_ne_outw(w, PORT2ADDR_NE(port)); _ne_outw(w, PORT2ADDR_NE(port));
else else
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
pcc_iowrite(0, port, &w, sizeof(w), 1, 0); pcc_iowrite(0, port, &w, sizeof(w), 1, 0);
} else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
...@@ -277,7 +277,7 @@ void _insb(unsigned int port, void * addr, unsigned long count) ...@@ -277,7 +277,7 @@ void _insb(unsigned int port, void * addr, unsigned long count)
if (port >= 0x300 && port < 0x320){ if (port >= 0x300 && port < 0x320){
portp = PORT2ADDR_NE(port); portp = PORT2ADDR_NE(port);
while(count--) *buf++ = *(volatile unsigned char *)portp; while(count--) *buf++ = *(volatile unsigned char *)portp;
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
} else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
pcc_ioread(0, port, (void *)addr, sizeof(unsigned char), count, 1); pcc_ioread(0, port, (void *)addr, sizeof(unsigned char), count, 1);
} else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
...@@ -297,7 +297,7 @@ void _insw(unsigned int port, void * addr, unsigned long count) ...@@ -297,7 +297,7 @@ void _insw(unsigned int port, void * addr, unsigned long count)
if (port >= 0x300 && port < 0x320) { if (port >= 0x300 && port < 0x320) {
portp = PORT2ADDR_NE(port); portp = PORT2ADDR_NE(port);
while (count--) *buf++ = _ne_inw(portp); while (count--) *buf++ = _ne_inw(portp);
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
} else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
pcc_ioread(0, port, (void *)addr, sizeof(unsigned short), count, 1); pcc_ioread(0, port, (void *)addr, sizeof(unsigned short), count, 1);
} else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
...@@ -326,7 +326,7 @@ void _outsb(unsigned int port, const void * addr, unsigned long count) ...@@ -326,7 +326,7 @@ void _outsb(unsigned int port, const void * addr, unsigned long count)
if (port >= 0x300 && port < 0x320) { if (port >= 0x300 && port < 0x320) {
portp = PORT2ADDR_NE(port); portp = PORT2ADDR_NE(port);
while (count--) _ne_outb(*buf++, portp); while (count--) _ne_outb(*buf++, portp);
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
} else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
pcc_iowrite(0, port, (void *)addr, sizeof(unsigned char), count, 1); pcc_iowrite(0, port, (void *)addr, sizeof(unsigned char), count, 1);
} else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
...@@ -346,7 +346,7 @@ void _outsw(unsigned int port, const void * addr, unsigned long count) ...@@ -346,7 +346,7 @@ void _outsw(unsigned int port, const void * addr, unsigned long count)
if (port >= 0x300 && port < 0x320) { if (port >= 0x300 && port < 0x320) {
portp = PORT2ADDR_NE(port); portp = PORT2ADDR_NE(port);
while (count--) _ne_outw(*buf++, portp); while (count--) _ne_outw(*buf++, portp);
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC) #if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_PCC)
} else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) { } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
pcc_iowrite(0, port, (void *)addr, sizeof(unsigned short), count, 1); pcc_iowrite(0, port, (void *)addr, sizeof(unsigned short), count, 1);
} else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) { } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
......
...@@ -140,7 +140,7 @@ void __init init_IRQ(void) ...@@ -140,7 +140,7 @@ void __init init_IRQ(void)
disable_mappi_irq(M32R_IRQ_SIO1_S); disable_mappi_irq(M32R_IRQ_SIO1_S);
#endif /* CONFIG_SERIAL_M32R_SIO */ #endif /* CONFIG_SERIAL_M32R_SIO */
#if defined(CONFIG_M32RPCC) #if defined(CONFIG_M32R_PCC)
/* INT1 : pccard0 interrupt */ /* INT1 : pccard0 interrupt */
irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED; irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED;
irq_desc[M32R_IRQ_INT1].handler = &mappi_irq_type; irq_desc[M32R_IRQ_INT1].handler = &mappi_irq_type;
......
...@@ -70,16 +70,18 @@ qword_set_loop: ...@@ -70,16 +70,18 @@ qword_set_loop:
st r1, @+r4 st r1, @+r4
bnc qword_set_loop || cmpz r2 bnc qword_set_loop || cmpz r2
jc r14 jc r14
word_set_wrap: set_remainder:
cmpui r2, #4 cmpui r2, #4
bc byte_set bc byte_set_wrap1
addi r2, #-4 addi r2, #-4
bra word_set_loop bra word_set_loop
byte_set_wrap: byte_set_wrap:
addi r2, #4 addi r2, #4
addi r4, #4 || cmpz r2 cmpz r2
jc r14 jc r14
byte_set_wrap1:
addi r4, #4
#if defined(CONFIG_ISA_M32R2) #if defined(CONFIG_ISA_M32R2)
byte_set: byte_set:
addi r2, #-1 || stb r1, @r4+ addi r2, #-1 || stb r1, @r4+
...@@ -153,18 +155,19 @@ qword_set_loop: ...@@ -153,18 +155,19 @@ qword_set_loop:
st r1, @+r4 st r1, @+r4
st r1, @+r4 st r1, @+r4
bnc qword_set_loop bnc qword_set_loop
bnez r2, word_set_wrap bnez r2, set_remainder
jmp r14 jmp r14
word_set_wrap: set_remainder:
cmpui r2, #4 cmpui r2, #4
bc byte_set bc byte_set_wrap1
addi r2, #-4 addi r2, #-4
bra word_set_loop bra word_set_loop
byte_set_wrap: byte_set_wrap:
addi r2, #4 addi r2, #4
addi r4, #4
beqz r2, end_memset beqz r2, end_memset
byte_set_wrap1:
addi r4, #4
byte_set: byte_set:
addi r2, #-1 addi r2, #-1
stb r1, @r4 stb r1, @r4
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <asm/mpc52xx.h> #include <asm/mpc52xx.h>
#include <asm/mpc52xx_psc.h> #include <asm/mpc52xx_psc.h>
#include <asm/serial.h> #include <asm/serial.h>
#include <asm/io.h>
#include <asm/time.h> #include <asm/time.h>
#if MPC52xx_PF_CONSOLE_PORT == 0 #if MPC52xx_PF_CONSOLE_PORT == 0
......
...@@ -145,13 +145,13 @@ static void __init ocotea_set_emacdata(void) ...@@ -145,13 +145,13 @@ static void __init ocotea_set_emacdata(void)
} }
#define PCIX_READW(offset) \ #define PCIX_READW(offset) \
(readw((u32)pcix_reg_base+offset)) (readw(pcix_reg_base+offset))
#define PCIX_WRITEW(value, offset) \ #define PCIX_WRITEW(value, offset) \
(writew(value, (u32)pcix_reg_base+offset)) (writew(value, pcix_reg_base+offset))
#define PCIX_WRITEL(value, offset) \ #define PCIX_WRITEL(value, offset) \
(writel(value, (u32)pcix_reg_base+offset)) (writel(value, pcix_reg_base+offset))
/* /*
* FIXME: This is only here to "make it work". This will move * FIXME: This is only here to "make it work". This will move
...@@ -321,6 +321,11 @@ ocotea_setup_arch(void) ...@@ -321,6 +321,11 @@ ocotea_setup_arch(void)
printk("IBM Ocotea port (MontaVista Software, Inc. <source@mvista.com>)\n"); printk("IBM Ocotea port (MontaVista Software, Inc. <source@mvista.com>)\n");
} }
static void __init ocotea_init(void)
{
ibm440gx_l2c_setup(&clocks);
}
void __init platform_init(unsigned long r3, unsigned long r4, void __init platform_init(unsigned long r3, unsigned long r4,
unsigned long r5, unsigned long r6, unsigned long r7) unsigned long r5, unsigned long r6, unsigned long r7)
{ {
...@@ -342,12 +347,11 @@ void __init platform_init(unsigned long r3, unsigned long r4, ...@@ -342,12 +347,11 @@ void __init platform_init(unsigned long r3, unsigned long r4,
ibm440gx_get_clocks(&clocks, 33333333, 6 * 1843200); ibm440gx_get_clocks(&clocks, 33333333, 6 * 1843200);
ocp_sys_info.opb_bus_freq = clocks.opb; ocp_sys_info.opb_bus_freq = clocks.opb;
/* /* XXX Fix L2C IRQ triggerring setting (edge-sensitive).
* Always disable L2 cache. All revs/speeds of silicon * Firmware (at least PIBS v1.72 OCT/28/2003) sets it incorrectly
* have parity error problems despite errata claims to * --ebs
* the contrary.
*/ */
ibm440gx_l2c_disable(); mtdcr(DCRN_UIC_TR(UIC2), mfdcr(DCRN_UIC_TR(UIC2)) | 0x00000100);
ibm44x_platform_init(); ibm44x_platform_init();
...@@ -365,4 +369,5 @@ void __init platform_init(unsigned long r3, unsigned long r4, ...@@ -365,4 +369,5 @@ void __init platform_init(unsigned long r3, unsigned long r4,
#ifdef CONFIG_KGDB #ifdef CONFIG_KGDB
ppc_md.early_serial_map = ocotea_early_serial_map; ppc_md.early_serial_map = ocotea_early_serial_map;
#endif #endif
ppc_md.init = ocotea_init;
} }
...@@ -60,11 +60,6 @@ ...@@ -60,11 +60,6 @@
* of the amount of memory in the system. Once a method of determining * of the amount of memory in the system. Once a method of determining
* what version of DINK initializes the system for us, if applicable, is * what version of DINK initializes the system for us, if applicable, is
* found, we can hopefully stop hardcoding 32MB of RAM. * found, we can hopefully stop hardcoding 32MB of RAM.
*
* It is important to note that this code only supports the Sandpoint X3
* (all flavors) platform, and it does not support the X2 anymore. Code
* that at one time worked on the X2 can be found at:
* ftp://source.mvista.com/pub/linuxppc/obsolete/sandpoint/
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -107,9 +102,13 @@ ...@@ -107,9 +102,13 @@
#include "sandpoint.h" #include "sandpoint.h"
/* Set non-zero if an X2 Sandpoint detected. */
static int sandpoint_is_x2;
unsigned char __res[sizeof(bd_t)]; unsigned char __res[sizeof(bd_t)];
static void sandpoint_halt(void); static void sandpoint_halt(void);
static void sandpoint_probe_type(void);
/* /*
* Define all of the IRQ senses and polarities. Taken from the * Define all of the IRQ senses and polarities. Taken from the
...@@ -129,7 +128,7 @@ static u_char sandpoint_openpic_initsenses[] __initdata = { ...@@ -129,7 +128,7 @@ static u_char sandpoint_openpic_initsenses[] __initdata = {
* Motorola SPS Sandpoint interrupt routing. * Motorola SPS Sandpoint interrupt routing.
*/ */
static inline int static inline int
sandpoint_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) x3_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
{ {
static char pci_irq_table[][4] = static char pci_irq_table[][4] =
/* /*
...@@ -149,6 +148,27 @@ sandpoint_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) ...@@ -149,6 +148,27 @@ sandpoint_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
return PCI_IRQ_TABLE_LOOKUP; return PCI_IRQ_TABLE_LOOKUP;
} }
static inline int
x2_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
{
static char pci_irq_table[][4] =
/*
* PCI IDSEL/INTPIN->INTLINE
* A B C D
*/
{
{ 18, 0, 0, 0 }, /* IDSEL 11 - i8259 on Windbond */
{ 0, 0, 0, 0 }, /* IDSEL 12 - unused */
{ 16, 17, 18, 19 }, /* IDSEL 13 - PCI slot 1 */
{ 17, 18, 19, 16 }, /* IDSEL 14 - PCI slot 2 */
{ 18, 19, 16, 17 }, /* IDSEL 15 - PCI slot 3 */
{ 19, 16, 17, 18 }, /* IDSEL 16 - PCI slot 4 */
};
const long min_idsel = 11, max_idsel = 16, irqs_per_slot = 4;
return PCI_IRQ_TABLE_LOOKUP;
}
static void __init static void __init
sandpoint_setup_winbond_83553(struct pci_controller *hose) sandpoint_setup_winbond_83553(struct pci_controller *hose)
{ {
...@@ -216,6 +236,18 @@ sandpoint_setup_winbond_83553(struct pci_controller *hose) ...@@ -216,6 +236,18 @@ sandpoint_setup_winbond_83553(struct pci_controller *hose)
return; return;
} }
/* On the sandpoint X2, we must avoid sending configuration cycles to
* device #12 (IDSEL addr = AD12).
*/
static int
x2_exclude_device(u_char bus, u_char devfn)
{
if ((bus == 0) && (PCI_SLOT(devfn) == SANDPOINT_HOST_BRIDGE_IDSEL))
return PCIBIOS_DEVICE_NOT_FOUND;
else
return PCIBIOS_SUCCESSFUL;
}
static void __init static void __init
sandpoint_find_bridges(void) sandpoint_find_bridges(void)
{ {
...@@ -241,7 +273,11 @@ sandpoint_find_bridges(void) ...@@ -241,7 +273,11 @@ sandpoint_find_bridges(void)
ppc_md.pcibios_fixup = NULL; ppc_md.pcibios_fixup = NULL;
ppc_md.pcibios_fixup_bus = NULL; ppc_md.pcibios_fixup_bus = NULL;
ppc_md.pci_swizzle = common_swizzle; ppc_md.pci_swizzle = common_swizzle;
ppc_md.pci_map_irq = sandpoint_map_irq; if (sandpoint_is_x2) {
ppc_md.pci_map_irq = x2_map_irq;
ppc_md.pci_exclude_device = x2_exclude_device;
} else
ppc_md.pci_map_irq = x3_map_irq;
} }
else { else {
if (ppc_md.progress) if (ppc_md.progress)
...@@ -255,6 +291,11 @@ sandpoint_find_bridges(void) ...@@ -255,6 +291,11 @@ sandpoint_find_bridges(void)
static void __init static void __init
sandpoint_setup_arch(void) sandpoint_setup_arch(void)
{ {
/* Probe for Sandpoint model */
sandpoint_probe_type();
if (sandpoint_is_x2)
epic_serial_mode = 0;
loops_per_jiffy = 100000000 / HZ; loops_per_jiffy = 100000000 / HZ;
#ifdef CONFIG_BLK_DEV_INITRD #ifdef CONFIG_BLK_DEV_INITRD
...@@ -318,14 +359,49 @@ sandpoint_setup_arch(void) ...@@ -318,14 +359,49 @@ sandpoint_setup_arch(void)
SANDPOINT_87308_CFG_OUTB(0x30, 0x01); \ SANDPOINT_87308_CFG_OUTB(0x30, 0x01); \
} }
/*
* To probe the Sandpoint type, we need to check for a connection between GPIO
* pins 6 and 7 on the NS87308 SuperIO.
*/
static void __init sandpoint_probe_type(void)
{
u8 x;
/* First, ensure that the GPIO pins are enabled. */
SANDPOINT_87308_SELECT_DEV(0x07); /* Select GPIO logical device */
SANDPOINT_87308_CFG_OUTB(0x60, 0x07); /* Base address 0x700 */
SANDPOINT_87308_CFG_OUTB(0x61, 0x00);
SANDPOINT_87308_CFG_OUTB(0x30, 0x01); /* Enable */
/* Now, set pin 7 to output and pin 6 to input. */
outb((inb(0x701) | 0x80) & 0xbf, 0x701);
/* Set push-pull output */
outb(inb(0x702) | 0x80, 0x702);
/* Set pull-up on input */
outb(inb(0x703) | 0x40, 0x703);
/* Set output high and check */
x = inb(0x700);
outb(x | 0x80, 0x700);
x = inb(0x700);
sandpoint_is_x2 = ! (x & 0x40);
if (ppc_md.progress && sandpoint_is_x2)
ppc_md.progress("High output says X2", 0);
/* Set output low and check */
outb(x & 0x7f, 0x700);
sandpoint_is_x2 |= inb(0x700) & 0x40;
if (ppc_md.progress && sandpoint_is_x2)
ppc_md.progress("Low output says X2", 0);
if (ppc_md.progress && ! sandpoint_is_x2)
ppc_md.progress("Sandpoint is X3", 0);
}
/* /*
* Fix IDE interrupts. * Fix IDE interrupts.
*/ */
static int __init static int __init
sandpoint_fix_winbond_83553(void) sandpoint_fix_winbond_83553(void)
{ {
/* Make all 8259 interrupt level sensitive */ /* Make some 8259 interrupt level sensitive */
outb(0xf8, 0x4d0); outb(0xe0, 0x4d0);
outb(0xde, 0x4d1); outb(0xde, 0x4d1);
return 0; return 0;
...@@ -398,7 +474,7 @@ sandpoint_init_IRQ(void) ...@@ -398,7 +474,7 @@ sandpoint_init_IRQ(void)
OpenPIC_NumInitSenses = sizeof(sandpoint_openpic_initsenses); OpenPIC_NumInitSenses = sizeof(sandpoint_openpic_initsenses);
mpc10x_set_openpic(); mpc10x_set_openpic();
openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade", openpic_hookup_cascade(sandpoint_is_x2 ? 17 : NUM_8259_INTERRUPTS, "82c59 cascade",
i8259_irq); i8259_irq);
/* /*
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* PPC440GX system library * PPC440GX system library
* *
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
* Copyright (c) 2003 Zultys Technologies * Copyright (c) 2003, 2004 Zultys Technologies
* *
* This program is free software; you can redistribute it and/or modify it * 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 * under the terms of the GNU General Public License as published by the
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/interrupt.h>
#include <asm/ibm44x.h> #include <asm/ibm44x.h>
#include <asm/mmu.h> #include <asm/mmu.h>
#include <asm/processor.h> #include <asm/processor.h>
...@@ -97,10 +98,51 @@ void __init ibm440gx_get_clocks(struct ibm44x_clocks* p, unsigned int sys_clk, ...@@ -97,10 +98,51 @@ void __init ibm440gx_get_clocks(struct ibm44x_clocks* p, unsigned int sys_clk,
p->uart1 = p->plb / __fix_zero(uart1 & 0xff, 256); p->uart1 = p->plb / __fix_zero(uart1 & 0xff, 256);
} }
/* Enable L2 cache (call with IRQs disabled) */ /* Issue L2C diagnostic command */
static inline u32 l2c_diag(u32 addr)
{
mtdcr(DCRN_L2C0_ADDR, addr);
mtdcr(DCRN_L2C0_CMD, L2C_CMD_DIAG);
while (!(mfdcr(DCRN_L2C0_SR) & L2C_SR_CC)) ;
return mfdcr(DCRN_L2C0_DATA);
}
static irqreturn_t l2c_error_handler(int irq, void* dev, struct pt_regs* regs)
{
u32 sr = mfdcr(DCRN_L2C0_SR);
if (sr & L2C_SR_CPE){
/* Read cache trapped address */
u32 addr = l2c_diag(0x42000000);
printk(KERN_EMERG "L2C: Cache Parity Error, addr[16:26] = 0x%08x\n", addr);
}
if (sr & L2C_SR_TPE){
/* Read tag trapped address */
u32 addr = l2c_diag(0x82000000) >> 16;
printk(KERN_EMERG "L2C: Tag Parity Error, addr[16:26] = 0x%08x\n", addr);
}
/* Clear parity errors */
if (sr & (L2C_SR_CPE | L2C_SR_TPE)){
mtdcr(DCRN_L2C0_ADDR, 0);
mtdcr(DCRN_L2C0_CMD, L2C_CMD_CCP | L2C_CMD_CTE);
} else
printk(KERN_EMERG "L2C: LRU error\n");
return IRQ_HANDLED;
}
/* Enable L2 cache */
void __init ibm440gx_l2c_enable(void){ void __init ibm440gx_l2c_enable(void){
u32 r; u32 r;
unsigned long flags;
/* Install error handler */
if (request_irq(87, l2c_error_handler, SA_INTERRUPT, "L2C", 0) < 0){
printk(KERN_ERR "Cannot install L2C error handler, cache is not enabled\n");
return;
}
local_irq_save(flags);
asm volatile ("sync" ::: "memory"); asm volatile ("sync" ::: "memory");
/* Disable SRAM */ /* Disable SRAM */
...@@ -137,20 +179,22 @@ void __init ibm440gx_l2c_enable(void){ ...@@ -137,20 +179,22 @@ void __init ibm440gx_l2c_enable(void){
/* Enable ICU/DCU ports */ /* Enable ICU/DCU ports */
r = mfdcr(DCRN_L2C0_CFG); r = mfdcr(DCRN_L2C0_CFG);
r &= ~(L2C_CFG_DCW_MASK | L2C_CFG_CPIM | L2C_CFG_TPIM | L2C_CFG_LIM r &= ~(L2C_CFG_DCW_MASK | L2C_CFG_PMUX_MASK | L2C_CFG_PMIM | L2C_CFG_TPEI
| L2C_CFG_PMUX_MASK | L2C_CFG_PMIM | L2C_CFG_TPEI | L2C_CFG_CPEI | L2C_CFG_CPEI | L2C_CFG_NAM | L2C_CFG_NBRM);
| L2C_CFG_NAM | L2C_CFG_NBRM);
r |= L2C_CFG_ICU | L2C_CFG_DCU | L2C_CFG_TPC | L2C_CFG_CPC | L2C_CFG_FRAN r |= L2C_CFG_ICU | L2C_CFG_DCU | L2C_CFG_TPC | L2C_CFG_CPC | L2C_CFG_FRAN
| L2C_CFG_SMCM; | L2C_CFG_CPIM | L2C_CFG_TPIM | L2C_CFG_LIM | L2C_CFG_SMCM;
mtdcr(DCRN_L2C0_CFG, r); mtdcr(DCRN_L2C0_CFG, r);
asm volatile ("sync; isync" ::: "memory"); asm volatile ("sync; isync" ::: "memory");
local_irq_restore(flags);
} }
/* Disable L2 cache (call with IRQs disabled) */ /* Disable L2 cache */
void __init ibm440gx_l2c_disable(void){ void __init ibm440gx_l2c_disable(void){
u32 r; u32 r;
unsigned long flags;
local_irq_save(flags);
asm volatile ("sync" ::: "memory"); asm volatile ("sync" ::: "memory");
/* Disable L2C mode */ /* Disable L2C mode */
...@@ -169,6 +213,7 @@ void __init ibm440gx_l2c_disable(void){ ...@@ -169,6 +213,7 @@ void __init ibm440gx_l2c_disable(void){
SRAM_SBCR_BAS3 | SRAM_SBCR_BS_64KB | SRAM_SBCR_BU_RW); SRAM_SBCR_BAS3 | SRAM_SBCR_BS_64KB | SRAM_SBCR_BU_RW);
asm volatile ("sync; isync" ::: "memory"); asm volatile ("sync; isync" ::: "memory");
local_irq_restore(flags);
} }
void __init ibm440gx_l2c_setup(struct ibm44x_clocks* p) void __init ibm440gx_l2c_setup(struct ibm44x_clocks* p)
......
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
#ifdef CONFIG_MPC10X_OPENPIC #ifdef CONFIG_MPC10X_OPENPIC
#ifdef CONFIG_EPIC_SERIAL_MODE #ifdef CONFIG_EPIC_SERIAL_MODE
#define EPIC_IRQ_BASE 16 #define EPIC_IRQ_BASE (epic_serial_mode ? 16 : 5)
#else #else
#define EPIC_IRQ_BASE 5 #define EPIC_IRQ_BASE 5
#endif #endif
...@@ -69,20 +69,16 @@ static struct ocp_def mpc10x_i2c_ocp = { ...@@ -69,20 +69,16 @@ static struct ocp_def mpc10x_i2c_ocp = {
.vendor = OCP_VENDOR_MOTOROLA, .vendor = OCP_VENDOR_MOTOROLA,
.function = OCP_FUNC_IIC, .function = OCP_FUNC_IIC,
.index = 0, .index = 0,
.irq = MPC10X_I2C_IRQ,
.additions = &mpc10x_i2c_data .additions = &mpc10x_i2c_data
}; };
static struct ocp_def mpc10x_dma_ocp[2] = { static struct ocp_def mpc10x_dma_ocp[2] = {
{ .vendor = OCP_VENDOR_MOTOROLA, { .vendor = OCP_VENDOR_MOTOROLA,
.function = OCP_FUNC_DMA, .function = OCP_FUNC_DMA,
.index = 0, .index = 0 },
.irq = MPC10X_DMA0_IRQ
},
{ .vendor = OCP_VENDOR_MOTOROLA, { .vendor = OCP_VENDOR_MOTOROLA,
.function = OCP_FUNC_DMA, .function = OCP_FUNC_DMA,
.index = 1, .index = 1 }
.irq = MPC10X_DMA1_IRQ }
}; };
/* Set resources to match bridge memory map */ /* Set resources to match bridge memory map */
...@@ -292,12 +288,15 @@ mpc10x_bridge_init(struct pci_controller *hose, ...@@ -292,12 +288,15 @@ mpc10x_bridge_init(struct pci_controller *hose,
MPC10X_EUMB_EPIC_SIZE); MPC10X_EUMB_EPIC_SIZE);
#endif #endif
mpc10x_i2c_ocp.paddr = phys_eumb_base + MPC10X_EUMB_I2C_OFFSET; mpc10x_i2c_ocp.paddr = phys_eumb_base + MPC10X_EUMB_I2C_OFFSET;
mpc10x_i2c_ocp.irq = MPC10X_I2C_IRQ;
ocp_add_one_device(&mpc10x_i2c_ocp); ocp_add_one_device(&mpc10x_i2c_ocp);
mpc10x_dma_ocp[0].paddr = phys_eumb_base + mpc10x_dma_ocp[0].paddr = phys_eumb_base +
MPC10X_EUMB_DMA_OFFSET + 0x100; MPC10X_EUMB_DMA_OFFSET + 0x100;
mpc10x_dma_ocp[0].irq = MPC10X_DMA0_IRQ;
ocp_add_one_device(&mpc10x_dma_ocp[0]); ocp_add_one_device(&mpc10x_dma_ocp[0]);
mpc10x_dma_ocp[1].paddr = phys_eumb_base + mpc10x_dma_ocp[1].paddr = phys_eumb_base +
MPC10X_EUMB_DMA_OFFSET + 0x200; MPC10X_EUMB_DMA_OFFSET + 0x200;
mpc10x_dma_ocp[1].irq = MPC10X_DMA1_IRQ;
ocp_add_one_device(&mpc10x_dma_ocp[1]); ocp_add_one_device(&mpc10x_dma_ocp[1]);
} }
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/config.h> #include <linux/config.h>
#include <asm/io.h>
#include <asm/time.h> #include <asm/time.h>
#include <asm/mpc52xx.h> #include <asm/mpc52xx.h>
#include <asm/mpc52xx_psc.h> #include <asm/mpc52xx_psc.h>
......
...@@ -261,6 +261,9 @@ static void openpic_safe_writefield_IPI(volatile u_int *addr, u_int mask, u_int ...@@ -261,6 +261,9 @@ static void openpic_safe_writefield_IPI(volatile u_int *addr, u_int mask, u_int
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
#ifdef CONFIG_EPIC_SERIAL_MODE #ifdef CONFIG_EPIC_SERIAL_MODE
/* On platforms that may use EPIC serial mode, the default is enabled. */
int epic_serial_mode = 1;
static void __init openpic_eicr_set_clk(u_int clkval) static void __init openpic_eicr_set_clk(u_int clkval)
{ {
openpic_writefield(&OpenPIC->Global.Global_Configuration1, openpic_writefield(&OpenPIC->Global.Global_Configuration1,
...@@ -415,8 +418,10 @@ void __init openpic_init(int offset) ...@@ -415,8 +418,10 @@ void __init openpic_init(int offset)
openpic_set_spurious(OPENPIC_VEC_SPURIOUS); openpic_set_spurious(OPENPIC_VEC_SPURIOUS);
openpic_disable_8259_pass_through(); openpic_disable_8259_pass_through();
#ifdef CONFIG_EPIC_SERIAL_MODE #ifdef CONFIG_EPIC_SERIAL_MODE
openpic_eicr_set_clk(7); /* Slowest value until we know better */ if (epic_serial_mode) {
openpic_enable_sie(); openpic_eicr_set_clk(7); /* Slowest value until we know better */
openpic_enable_sie();
}
#endif #endif
openpic_set_priority(0); openpic_set_priority(0);
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/time.h> #include <linux/time.h>
#include <linux/timex.h> #include <linux/timex.h>
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/mc146818rtc.h>
#include <asm/machdep.h> #include <asm/machdep.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -48,8 +49,6 @@ ...@@ -48,8 +49,6 @@
* --MAG * --MAG
*/ */
extern spinlock_t rtc_lock;
/* /*
* 'todc_info' should be initialized in your *_setup.c file to * 'todc_info' should be initialized in your *_setup.c file to
* point to a fully initialized 'todc_info_t' structure. * point to a fully initialized 'todc_info_t' structure.
......
...@@ -25,30 +25,14 @@ ...@@ -25,30 +25,14 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <linux/config.h>
#include <linux/init.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <asm/io.h> #include <linux/list.h>
#include <asm/prom.h>
#include <asm/rtas.h>
#include <asm/ppcdebug.h>
#include <asm/iSeries/HvCallXm.h>
#include <asm/iSeries/LparData.h>
#include <asm/iommu.h> #include <asm/iommu.h>
#include <asm/pci-bridge.h>
#include <asm/iSeries/iSeries_pci.h>
#include <asm/machdep.h> #include <asm/machdep.h>
#include <asm/iSeries/HvCallXm.h>
#include "pci.h" #include <asm/iSeries/iSeries_pci.h>
extern struct list_head iSeries_Global_Device_List; extern struct list_head iSeries_Global_Device_List;
...@@ -76,12 +60,11 @@ static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages, ...@@ -76,12 +60,11 @@ static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages,
tce.te_bits.tb_pciwr = 1; tce.te_bits.tb_pciwr = 1;
} }
rc = HvCallXm_setTce((u64)tbl->it_index, rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index,
(u64)index, tce.te_word);
tce.te_word);
if (rc) if (rc)
panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n", rc); panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n",
rc);
index++; index++;
uaddr += PAGE_SIZE; uaddr += PAGE_SIZE;
} }
...@@ -90,20 +73,14 @@ static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages, ...@@ -90,20 +73,14 @@ static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages,
static void tce_free_iSeries(struct iommu_table *tbl, long index, long npages) static void tce_free_iSeries(struct iommu_table *tbl, long index, long npages)
{ {
u64 rc; u64 rc;
union tce_entry tce;
while (npages--) { while (npages--) {
tce.te_word = 0; rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, 0);
rc = HvCallXm_setTce((u64)tbl->it_index,
(u64)index,
tce.te_word);
if (rc) if (rc)
panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n", rc); panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n",
rc);
index++; index++;
} }
} }
...@@ -115,17 +92,14 @@ static struct iommu_table *iommu_table_find(struct iommu_table * tbl) ...@@ -115,17 +92,14 @@ static struct iommu_table *iommu_table_find(struct iommu_table * tbl)
{ {
struct iSeries_Device_Node *dp; struct iSeries_Device_Node *dp;
for (dp = (struct iSeries_Device_Node *)iSeries_Global_Device_List.next; list_for_each_entry(dp, &iSeries_Global_Device_List, Device_List) {
dp != (struct iSeries_Device_Node *)&iSeries_Global_Device_List; if ((dp->iommu_table != NULL) &&
dp = (struct iSeries_Device_Node *)dp->Device_List.next) (dp->iommu_table->it_type == TCE_PCI) &&
if (dp->iommu_table != NULL && (dp->iommu_table->it_offset == tbl->it_offset) &&
dp->iommu_table->it_type == TCE_PCI && (dp->iommu_table->it_index == tbl->it_index) &&
dp->iommu_table->it_offset == tbl->it_offset && (dp->iommu_table->it_size == tbl->it_size))
dp->iommu_table->it_index == tbl->it_index &&
dp->iommu_table->it_size == tbl->it_size)
return dp->iommu_table; return dp->iommu_table;
}
return NULL; return NULL;
} }
...@@ -143,15 +117,14 @@ static void iommu_table_getparms(struct iSeries_Device_Node* dn, ...@@ -143,15 +117,14 @@ static void iommu_table_getparms(struct iSeries_Device_Node* dn,
{ {
struct iommu_table_cb *parms; struct iommu_table_cb *parms;
parms = (struct iommu_table_cb*)kmalloc(sizeof(*parms), GFP_KERNEL); parms = kmalloc(sizeof(*parms), GFP_KERNEL);
if (parms == NULL) if (parms == NULL)
panic("PCI_DMA: TCE Table Allocation failed."); panic("PCI_DMA: TCE Table Allocation failed.");
memset(parms, 0, sizeof(*parms)); memset(parms, 0, sizeof(*parms));
parms->itc_busno = ISERIES_BUS(dn); parms->itc_busno = ISERIES_BUS(dn);
parms->itc_slotno = dn->LogicalSlot; parms->itc_slotno = dn->LogicalSlot;
parms->itc_virtbus = 0; parms->itc_virtbus = 0;
HvCallXm_getTceTableParms(ISERIES_HV_ADDR(parms)); HvCallXm_getTceTableParms(ISERIES_HV_ADDR(parms));
...@@ -159,34 +132,32 @@ static void iommu_table_getparms(struct iSeries_Device_Node* dn, ...@@ -159,34 +132,32 @@ static void iommu_table_getparms(struct iSeries_Device_Node* dn,
if (parms->itc_size == 0) if (parms->itc_size == 0)
panic("PCI_DMA: parms->size is zero, parms is 0x%p", parms); panic("PCI_DMA: parms->size is zero, parms is 0x%p", parms);
tbl->it_size = parms->itc_size; tbl->it_size = parms->itc_size;
tbl->it_busno = parms->itc_busno; tbl->it_busno = parms->itc_busno;
tbl->it_offset = parms->itc_offset; tbl->it_offset = parms->itc_offset;
tbl->it_index = parms->itc_index; tbl->it_index = parms->itc_index;
tbl->it_entrysize = sizeof(union tce_entry); tbl->it_entrysize = sizeof(union tce_entry);
tbl->it_blocksize = 1; tbl->it_blocksize = 1;
tbl->it_type = TCE_PCI; tbl->it_type = TCE_PCI;
kfree(parms); kfree(parms);
} }
void iommu_devnode_init(struct iSeries_Device_Node *dn) { void iommu_devnode_init_iSeries(struct iSeries_Device_Node *dn)
{
struct iommu_table *tbl; struct iommu_table *tbl;
tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table), GFP_KERNEL); tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
iommu_table_getparms(dn, tbl); iommu_table_getparms(dn, tbl);
/* Look for existing tce table */ /* Look for existing tce table */
dn->iommu_table = iommu_table_find(tbl); dn->iommu_table = iommu_table_find(tbl);
if (dn->iommu_table == NULL) if (dn->iommu_table == NULL)
dn->iommu_table = iommu_init_table(tbl); dn->iommu_table = iommu_init_table(tbl);
else else
kfree(tbl); kfree(tbl);
return;
} }
......
...@@ -312,8 +312,7 @@ void __init iSeries_pci_final_fixup(void) ...@@ -312,8 +312,7 @@ void __init iSeries_pci_final_fixup(void)
mf_displaySrc(0xC9000100); mf_displaySrc(0xC9000100);
printk("pcibios_final_fixup\n"); printk("pcibios_final_fixup\n");
while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) for_each_pci_dev(pdev) {
!= NULL) {
node = find_Device_Node(pdev->bus->number, pdev->devfn); node = find_Device_Node(pdev->bus->number, pdev->devfn);
printk("pci dev %p (%x.%x), node %p\n", pdev, printk("pci dev %p (%x.%x), node %p\n", pdev,
pdev->bus->number, pdev->devfn, node); pdev->bus->number, pdev->devfn, node);
...@@ -329,7 +328,7 @@ void __init iSeries_pci_final_fixup(void) ...@@ -329,7 +328,7 @@ void __init iSeries_pci_final_fixup(void)
iSeries_Device_Information(pdev, Buffer, iSeries_Device_Information(pdev, Buffer,
sizeof(Buffer)); sizeof(Buffer));
printk("%d. %s\n", DeviceCount, Buffer); printk("%d. %s\n", DeviceCount, Buffer);
iommu_devnode_init(node); iommu_devnode_init_iSeries(node);
} else } else
printk("PCI: Device Tree not found for 0x%016lX\n", printk("PCI: Device Tree not found for 0x%016lX\n",
(unsigned long)pdev); (unsigned long)pdev);
......
...@@ -425,6 +425,39 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl) ...@@ -425,6 +425,39 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl)
return tbl; return tbl;
} }
void iommu_free_table(struct device_node *dn)
{
struct iommu_table *tbl = dn->iommu_table;
unsigned long bitmap_sz, i;
unsigned int order;
if (!tbl || !tbl->it_map) {
printk(KERN_ERR "%s: expected TCE map for %s\n", __FUNCTION__,
dn->full_name);
return;
}
/* verify that table contains no entries */
/* it_mapsize is in entries, and we're examining 64 at a time */
for (i = 0; i < (tbl->it_mapsize/64); i++) {
if (tbl->it_map[i] != 0) {
printk(KERN_WARNING "%s: Unexpected TCEs for %s\n",
__FUNCTION__, dn->full_name);
break;
}
}
/* calculate bitmap size in bytes */
bitmap_sz = (tbl->it_mapsize + 7) / 8;
/* free bitmap */
order = get_order(bitmap_sz);
free_pages((unsigned long) tbl->it_map, order);
/* free table */
kfree(tbl);
}
/* Creates TCEs for a user provided buffer. The user buffer must be /* Creates TCEs for a user provided buffer. The user buffer must be
* contiguous real kernel storage (not vmalloc). The address of the buffer * contiguous real kernel storage (not vmalloc). The address of the buffer
* passed here is the kernel (virtual) address of the buffer. The buffer * passed here is the kernel (virtual) address of the buffer. The buffer
......
...@@ -276,7 +276,7 @@ static void iommu_buses_init(void) ...@@ -276,7 +276,7 @@ static void iommu_buses_init(void)
first_phb = 0; first_phb = 0;
for (dn = first_dn; dn != NULL; dn = dn->sibling) for (dn = first_dn; dn != NULL; dn = dn->sibling)
iommu_devnode_init(dn); iommu_devnode_init_pSeries(dn);
} }
} }
...@@ -298,7 +298,7 @@ static void iommu_buses_init_lpar(struct list_head *bus_list) ...@@ -298,7 +298,7 @@ static void iommu_buses_init_lpar(struct list_head *bus_list)
* Do it now because iommu_table_setparms_lpar needs it. * Do it now because iommu_table_setparms_lpar needs it.
*/ */
busdn->bussubno = bus->number; busdn->bussubno = bus->number;
iommu_devnode_init(busdn); iommu_devnode_init_pSeries(busdn);
} }
/* look for a window on a bridge even if the PHB had one */ /* look for a window on a bridge even if the PHB had one */
...@@ -397,7 +397,7 @@ static void iommu_table_setparms_lpar(struct pci_controller *phb, ...@@ -397,7 +397,7 @@ static void iommu_table_setparms_lpar(struct pci_controller *phb,
} }
void iommu_devnode_init(struct device_node *dn) void iommu_devnode_init_pSeries(struct device_node *dn)
{ {
struct iommu_table *tbl; struct iommu_table *tbl;
...@@ -412,39 +412,6 @@ void iommu_devnode_init(struct device_node *dn) ...@@ -412,39 +412,6 @@ void iommu_devnode_init(struct device_node *dn)
dn->iommu_table = iommu_init_table(tbl); dn->iommu_table = iommu_init_table(tbl);
} }
void iommu_free_table(struct device_node *dn)
{
struct iommu_table *tbl = dn->iommu_table;
unsigned long bitmap_sz, i;
unsigned int order;
if (!tbl || !tbl->it_map) {
printk(KERN_ERR "%s: expected TCE map for %s\n", __FUNCTION__,
dn->full_name);
return;
}
/* verify that table contains no entries */
/* it_mapsize is in entries, and we're examining 64 at a time */
for (i = 0; i < (tbl->it_mapsize/64); i++) {
if (tbl->it_map[i] != 0) {
printk(KERN_WARNING "%s: Unexpected TCEs for %s\n",
__FUNCTION__, dn->full_name);
break;
}
}
/* calculate bitmap size in bytes */
bitmap_sz = (tbl->it_mapsize + 7) / 8;
/* free bitmap */
order = get_order(bitmap_sz);
free_pages((unsigned long) tbl->it_map, order);
/* free table */
kfree(tbl);
}
void iommu_setup_pSeries(void) void iommu_setup_pSeries(void)
{ {
struct pci_dev *dev = NULL; struct pci_dev *dev = NULL;
...@@ -459,7 +426,7 @@ void iommu_setup_pSeries(void) ...@@ -459,7 +426,7 @@ void iommu_setup_pSeries(void)
* pci device_node. This means get_iommu_table() won't need to search * pci device_node. This means get_iommu_table() won't need to search
* up the device tree to find it. * up the device tree to find it.
*/ */
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { for_each_pci_dev(dev) {
mydn = dn = PCI_GET_DN(dev); mydn = dn = PCI_GET_DN(dev);
while (dn && dn->iommu_table == NULL) while (dn && dn->iommu_table == NULL)
...@@ -469,7 +436,6 @@ void iommu_setup_pSeries(void) ...@@ -469,7 +436,6 @@ void iommu_setup_pSeries(void)
} }
} }
/* These are called very early. */ /* These are called very early. */
void tce_init_pSeries(void) void tce_init_pSeries(void)
{ {
......
...@@ -548,7 +548,7 @@ void __init pSeries_final_fixup(void) ...@@ -548,7 +548,7 @@ void __init pSeries_final_fixup(void)
check_s7a(); check_s7a();
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { for_each_pci_dev(dev) {
pci_read_irq_line(dev); pci_read_irq_line(dev);
if (s7a_workaround) { if (s7a_workaround) {
if (dev->irq > 16) { if (dev->irq > 16) {
......
...@@ -663,7 +663,7 @@ void __init pmac_pcibios_fixup(void) ...@@ -663,7 +663,7 @@ void __init pmac_pcibios_fixup(void)
{ {
struct pci_dev *dev = NULL; struct pci_dev *dev = NULL;
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) for_each_pci_dev(dev)
pci_read_irq_line(dev); pci_read_irq_line(dev);
pci_fix_bus_sysdata(); pci_fix_bus_sysdata();
......
...@@ -1740,7 +1740,7 @@ static int of_finish_dynamic_node(struct device_node *node) ...@@ -1740,7 +1740,7 @@ static int of_finish_dynamic_node(struct device_node *node)
if (strcmp(node->name, "pci") == 0 && if (strcmp(node->name, "pci") == 0 &&
get_property(node, "ibm,dma-window", NULL)) { get_property(node, "ibm,dma-window", NULL)) {
node->bussubno = node->busno; node->bussubno = node->busno;
iommu_devnode_init(node); iommu_devnode_init_pSeries(node);
} else } else
node->iommu_table = parent->iommu_table; node->iommu_table = parent->iommu_table;
#endif /* CONFIG_PPC_PSERIES */ #endif /* CONFIG_PPC_PSERIES */
...@@ -1801,6 +1801,15 @@ int of_add_node(const char *path, struct property *proplist) ...@@ -1801,6 +1801,15 @@ int of_add_node(const char *path, struct property *proplist)
return 0; return 0;
} }
/*
* Prepare an OF node for removal from system
*/
static void of_cleanup_node(struct device_node *np)
{
if (np->iommu_table && get_property(np, "ibm,dma-window", NULL))
iommu_free_table(np);
}
/* /*
* Remove an OF device node from the system. * Remove an OF device node from the system.
* Caller should have already "gotten" np. * Caller should have already "gotten" np.
...@@ -1818,13 +1827,7 @@ int of_remove_node(struct device_node *np) ...@@ -1818,13 +1827,7 @@ int of_remove_node(struct device_node *np)
return -EBUSY; return -EBUSY;
} }
/* XXX This is a layering violation, should be moved to the caller of_cleanup_node(np);
* --BenH.
*/
#ifdef CONFIG_PPC_PSERIES
if (np->iommu_table)
iommu_free_table(np);
#endif /* CONFIG_PPC_PSERIES */
write_lock(&devtree_lock); write_lock(&devtree_lock);
OF_MARK_STALE(np); OF_MARK_STALE(np);
......
...@@ -291,7 +291,7 @@ void iommu_setup_u3(void) ...@@ -291,7 +291,7 @@ void iommu_setup_u3(void)
/* We only have one iommu table on the mac for now, which makes /* We only have one iommu table on the mac for now, which makes
* things simple. Setup all PCI devices to point to this table * things simple. Setup all PCI devices to point to this table
*/ */
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { for_each_pci_dev(dev) {
/* We must use pci_device_to_OF_node() to make sure that /* We must use pci_device_to_OF_node() to make sure that
* we get the real "final" pointer to the device in the * we get the real "final" pointer to the device in the
* pci_dev sysdata and not the temporary PHB one * pci_dev sysdata and not the temporary PHB one
......
...@@ -521,24 +521,7 @@ static struct iommu_table * vio_build_iommu_table(struct vio_dev *dev) ...@@ -521,24 +521,7 @@ static struct iommu_table * vio_build_iommu_table(struct vio_dev *dev)
newTceTable = (struct iommu_table *) kmalloc(sizeof(struct iommu_table), GFP_KERNEL); newTceTable = (struct iommu_table *) kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
/* RPA docs say that #address-cells is always 1 for virtual size = ((dma_window[4] >> PAGE_SHIFT) << 3) >> PAGE_SHIFT;
devices, but some older boxes' OF returns 2. This should
be removed by GA, unless there is legacy OFs that still
have 2 for #address-cells */
size = ((dma_window[1+vio_num_address_cells] >> PAGE_SHIFT) << 3)
>> PAGE_SHIFT;
/* This is just an ugly kludge. Remove as soon as the OF for all
machines actually follow the spec and encodes the offset field
as phys-encode (that is, #address-cells wide)*/
if (dma_window_property_size == 12) {
size = ((dma_window[1] >> PAGE_SHIFT) << 3) >> PAGE_SHIFT;
} else if (dma_window_property_size == 20) {
size = ((dma_window[4] >> PAGE_SHIFT) << 3) >> PAGE_SHIFT;
} else {
printk(KERN_WARNING "vio_build_iommu_table: Invalid size of ibm,my-dma-window=%i, using 0x80 for size\n", dma_window_property_size);
size = 0x80;
}
/* There should be some code to extract the phys-encoded offset /* There should be some code to extract the phys-encoded offset
using prom_n_addr_cells(). However, according to a comment using prom_n_addr_cells(). However, according to a comment
......
...@@ -112,11 +112,16 @@ static int op_ppc64_create_files(struct super_block *sb, struct dentry *root) ...@@ -112,11 +112,16 @@ static int op_ppc64_create_files(struct super_block *sb, struct dentry *root)
oprofilefs_create_ulong(sb, root, "enable_kernel", &sys.enable_kernel); oprofilefs_create_ulong(sb, root, "enable_kernel", &sys.enable_kernel);
oprofilefs_create_ulong(sb, root, "enable_user", &sys.enable_user); oprofilefs_create_ulong(sb, root, "enable_user", &sys.enable_user);
oprofilefs_create_ulong(sb, root, "backtrace_spinlocks",
&sys.backtrace_spinlocks);
/* Default to tracing both kernel and user */ /* Default to tracing both kernel and user */
sys.enable_kernel = 1; sys.enable_kernel = 1;
sys.enable_user = 1; sys.enable_user = 1;
/* Turn on backtracing through spinlocks by default */
sys.backtrace_spinlocks = 1;
return 0; return 0;
} }
......
...@@ -71,6 +71,7 @@ struct op_system_config { ...@@ -71,6 +71,7 @@ struct op_system_config {
unsigned long mmcra; unsigned long mmcra;
unsigned long enable_kernel; unsigned long enable_kernel;
unsigned long enable_user; unsigned long enable_user;
unsigned long backtrace_spinlocks;
}; };
/* Per-arch configuration */ /* Per-arch configuration */
......
...@@ -32,6 +32,13 @@ static u32 mmcr0_val; ...@@ -32,6 +32,13 @@ static u32 mmcr0_val;
static u64 mmcr1_val; static u64 mmcr1_val;
static u32 mmcra_val; static u32 mmcra_val;
/*
* Since we do not have an NMI, backtracing through spinlocks is
* only a best guess. In light of this, allow it to be disabled at
* runtime.
*/
static int backtrace_spinlocks;
static void power4_reg_setup(struct op_counter_config *ctr, static void power4_reg_setup(struct op_counter_config *ctr,
struct op_system_config *sys, struct op_system_config *sys,
int num_ctrs) int num_ctrs)
...@@ -59,6 +66,8 @@ static void power4_reg_setup(struct op_counter_config *ctr, ...@@ -59,6 +66,8 @@ static void power4_reg_setup(struct op_counter_config *ctr,
mmcr1_val = sys->mmcr1; mmcr1_val = sys->mmcr1;
mmcra_val = sys->mmcra; mmcra_val = sys->mmcra;
backtrace_spinlocks = sys->backtrace_spinlocks;
for (i = 0; i < num_counters; ++i) for (i = 0; i < num_counters; ++i)
reset_value[i] = 0x80000000UL - ctr[i].count; reset_value[i] = 0x80000000UL - ctr[i].count;
...@@ -170,19 +179,38 @@ static void __attribute_used__ kernel_unknown_bucket(void) ...@@ -170,19 +179,38 @@ static void __attribute_used__ kernel_unknown_bucket(void)
{ {
} }
static unsigned long check_spinlock_pc(struct pt_regs *regs,
unsigned long profile_pc)
{
unsigned long pc = instruction_pointer(regs);
/*
* If both the SIAR (sampled instruction) and the perfmon exception
* occurred in a spinlock region then we account the sample to the
* calling function. This isnt 100% correct, we really need soft
* IRQ disable so we always get the perfmon exception at the
* point at which the SIAR is set.
*/
if (backtrace_spinlocks && in_lock_functions(pc) &&
in_lock_functions(profile_pc))
return regs->link;
else
return profile_pc;
}
/* /*
* On GQ and newer the MMCRA stores the HV and PR bits at the time * On GQ and newer the MMCRA stores the HV and PR bits at the time
* the SIAR was sampled. We use that to work out if the SIAR was sampled in * the SIAR was sampled. We use that to work out if the SIAR was sampled in
* the hypervisor, our exception vectors or RTAS. * the hypervisor, our exception vectors or RTAS.
*/ */
static unsigned long get_pc(void) static unsigned long get_pc(struct pt_regs *regs)
{ {
unsigned long pc = mfspr(SPRN_SIAR); unsigned long pc = mfspr(SPRN_SIAR);
unsigned long mmcra; unsigned long mmcra;
/* Cant do much about it */ /* Cant do much about it */
if (!mmcra_has_sihv) if (!mmcra_has_sihv)
return pc; return check_spinlock_pc(regs, pc);
mmcra = mfspr(SPRN_MMCRA); mmcra = mfspr(SPRN_MMCRA);
...@@ -196,10 +224,6 @@ static unsigned long get_pc(void) ...@@ -196,10 +224,6 @@ static unsigned long get_pc(void)
if (mmcra & MMCRA_SIPR) if (mmcra & MMCRA_SIPR)
return pc; return pc;
/* Were we in our exception vectors? */
if (pc < 0x4000UL)
return (unsigned long)__va(pc);
#ifdef CONFIG_PPC_PSERIES #ifdef CONFIG_PPC_PSERIES
/* Were we in RTAS? */ /* Were we in RTAS? */
if (pc >= rtas.base && pc < (rtas.base + rtas.size)) if (pc >= rtas.base && pc < (rtas.base + rtas.size))
...@@ -207,12 +231,16 @@ static unsigned long get_pc(void) ...@@ -207,12 +231,16 @@ static unsigned long get_pc(void)
return *((unsigned long *)rtas_bucket); return *((unsigned long *)rtas_bucket);
#endif #endif
/* Were we in our exception vectors or SLB real mode miss handler? */
if (pc < 0x1000000UL)
return (unsigned long)__va(pc);
/* Not sure where we were */ /* Not sure where we were */
if (pc < KERNELBASE) if (pc < KERNELBASE)
/* function descriptor madness */ /* function descriptor madness */
return *((unsigned long *)kernel_unknown_bucket); return *((unsigned long *)kernel_unknown_bucket);
return pc; return check_spinlock_pc(regs, pc);
} }
static int get_kernel(unsigned long pc) static int get_kernel(unsigned long pc)
...@@ -239,7 +267,7 @@ static void power4_handle_interrupt(struct pt_regs *regs, ...@@ -239,7 +267,7 @@ static void power4_handle_interrupt(struct pt_regs *regs,
unsigned int cpu = smp_processor_id(); unsigned int cpu = smp_processor_id();
unsigned int mmcr0; unsigned int mmcr0;
pc = get_pc(); pc = get_pc(regs);
is_kernel = get_kernel(pc); is_kernel = get_kernel(pc);
/* set the PMM bit (see comment below) */ /* set the PMM bit (see comment below) */
......
...@@ -75,7 +75,7 @@ sys_call_table: ...@@ -75,7 +75,7 @@ sys_call_table:
/*265*/ .long sys_timer_delete, sys_timer_create, sys_nis_syscall, sys_io_setup, sys_io_destroy /*265*/ .long sys_timer_delete, sys_timer_create, sys_nis_syscall, sys_io_setup, sys_io_destroy
/*270*/ .long sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink /*270*/ .long sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink
/*275*/ .long sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_waitid /*275*/ .long sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_waitid
/*280*/ .long sys_setaltroot, sys_add_key, sys_request_key, sys_keyctl /*280*/ .long sys_ni_syscall, sys_add_key, sys_request_key, sys_keyctl
#ifdef CONFIG_SUNOS_EMUL #ifdef CONFIG_SUNOS_EMUL
/* Now the SunOS syscall table. */ /* Now the SunOS syscall table. */
......
...@@ -5,7 +5,8 @@ ...@@ -5,7 +5,8 @@
ARCH_DIR = arch/um ARCH_DIR = arch/um
OS := $(shell uname -s) OS := $(shell uname -s)
#We require it or things break. # We require bash because the vmlinux link and loader script cpp use bash
# features.
SHELL := /bin/bash SHELL := /bin/bash
filechk_gen_header = $< filechk_gen_header = $<
...@@ -62,16 +63,18 @@ ifeq ($(CONFIG_MODE_SKAS), y) ...@@ -62,16 +63,18 @@ ifeq ($(CONFIG_MODE_SKAS), y)
$(SYS_HEADERS) : $(ARCH_DIR)/include/skas_ptregs.h $(SYS_HEADERS) : $(ARCH_DIR)/include/skas_ptregs.h
endif endif
.PHONY: linux
all: linux all: linux
linux: vmlinux linux: vmlinux
$(RM) $@ ln -f $< $@
ln $< $@
define archhelp define archhelp
echo '* linux - Binary kernel image (./linux) - for backward' echo '* linux - Binary kernel image (./linux) - for backward'
echo ' compatibility only: now you can simply run' echo ' compatibility only, this creates a hard link to the'
echo ' the vmlinux binary you find in the kernel root.' echo ' real kernel binary, the the "vmlinux" binary you'
echo ' find in the kernel root.'
endef endef
prepare: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS) \ prepare: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS) \
...@@ -117,7 +120,8 @@ define cmd_vmlinux__ ...@@ -117,7 +120,8 @@ define cmd_vmlinux__
-Wl,-T,$(vmlinux-lds) $(vmlinux-init) \ -Wl,-T,$(vmlinux-lds) $(vmlinux-init) \
-Wl,--start-group $(vmlinux-main) -Wl,--end-group \ -Wl,--start-group $(vmlinux-main) -Wl,--end-group \
-L/usr/lib -lutil \ -L/usr/lib -lutil \
$(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) FORCE ,$^) $(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) \
FORCE ,$^) ; rm -f linux
endef endef
USER_CFLAGS := $(patsubst -I%,,$(CFLAGS)) USER_CFLAGS := $(patsubst -I%,,$(CFLAGS))
......
...@@ -27,14 +27,26 @@ int generic_console_write(int fd, const char *buf, int n, void *unused) ...@@ -27,14 +27,26 @@ int generic_console_write(int fd, const char *buf, int n, void *unused)
int err; int err;
if(isatty(fd)){ if(isatty(fd)){
tcgetattr(fd, &save); CATCH_EINTR(err = tcgetattr(fd, &save));
if (err)
goto error;
new = save; new = save;
/* The terminal becomes a bit less raw, to handle \n also as
* "Carriage Return", not only as "New Line". Otherwise, the new
* line won't start at the first column.*/
new.c_oflag |= OPOST; new.c_oflag |= OPOST;
tcsetattr(fd, TCSAFLUSH, &new); CATCH_EINTR(err = tcsetattr(fd, TCSAFLUSH, &new));
if (err)
goto error;
} }
err = generic_write(fd, buf, n, NULL); err = generic_write(fd, buf, n, NULL);
if(isatty(fd)) tcsetattr(fd, TCSAFLUSH, &save); /* Restore raw mode, in any case; we *must* ignore any error apart
* EINTR, except for debug.*/
if(isatty(fd))
CATCH_EINTR(tcsetattr(fd, TCSAFLUSH, &save));
return(err); return(err);
error:
return(-errno);
} }
static void winch_handler(int sig) static void winch_handler(int sig)
......
...@@ -119,12 +119,98 @@ void mconsole_log(struct mc_request *req) ...@@ -119,12 +119,98 @@ void mconsole_log(struct mc_request *req)
mconsole_reply(req, "", 0, 0); mconsole_reply(req, "", 0, 0);
} }
/* This is a more convoluted version of mconsole_proc, which has some stability
* problems; however, we need it fixed, because it is expected that UML users
* mount HPPFS instead of procfs on /proc. And we want mconsole_proc to still
* show the real procfs content, not the ones from hppfs.*/
#if 0
void mconsole_proc(struct mc_request *req)
{
struct nameidata nd;
struct file_system_type *proc;
struct super_block *super;
struct file *file;
int n, err;
char *ptr = req->request.data, *buf;
ptr += strlen("proc");
while(isspace(*ptr)) ptr++;
proc = get_fs_type("proc");
if(proc == NULL){
mconsole_reply(req, "procfs not registered", 1, 0);
goto out;
}
super = (*proc->get_sb)(proc, 0, NULL, NULL);
put_filesystem(proc);
if(super == NULL){
mconsole_reply(req, "Failed to get procfs superblock", 1, 0);
goto out;
}
up_write(&super->s_umount);
nd.dentry = super->s_root;
nd.mnt = NULL;
nd.flags = O_RDONLY + 1;
nd.last_type = LAST_ROOT;
/* START: it was experienced that the stability problems are closed
* if commenting out these two calls + the below read cycle. To
* make UML crash again, it was enough to readd either one.*/
err = link_path_walk(ptr, &nd);
if(err){
mconsole_reply(req, "Failed to look up file", 1, 0);
goto out_kill;
}
file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
if(IS_ERR(file)){
mconsole_reply(req, "Failed to open file", 1, 0);
goto out_kill;
}
/*END*/
buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if(buf == NULL){
mconsole_reply(req, "Failed to allocate buffer", 1, 0);
goto out_fput;
}
if((file->f_op != NULL) && (file->f_op->read != NULL)){
do {
n = (*file->f_op->read)(file, buf, PAGE_SIZE - 1,
&file->f_pos);
if(n >= 0){
buf[n] = '\0';
mconsole_reply(req, buf, 0, (n > 0));
}
else {
mconsole_reply(req, "Read of file failed",
1, 0);
goto out_free;
}
} while(n > 0);
}
else mconsole_reply(req, "", 0, 0);
out_free:
kfree(buf);
out_fput:
fput(file);
out_kill:
deactivate_super(super);
out: ;
}
#endif
void mconsole_proc(struct mc_request *req) void mconsole_proc(struct mc_request *req)
{ {
char path[64]; char path[64];
char *buf; char *buf;
int len; int len;
int fd; int fd;
int first_chunk = 1;
char *ptr = req->request.data; char *ptr = req->request.data;
ptr += strlen("proc"); ptr += strlen("proc");
...@@ -149,7 +235,13 @@ void mconsole_proc(struct mc_request *req) ...@@ -149,7 +235,13 @@ void mconsole_proc(struct mc_request *req)
if (len < 0) { if (len < 0) {
mconsole_reply(req, "Read of file failed", 1, 0); mconsole_reply(req, "Read of file failed", 1, 0);
goto out_free; goto out_free;
} else if (len == PAGE_SIZE-1) { }
/*Begin the file content on his own line.*/
if (first_chunk) {
mconsole_reply(req, "\n", 0, 1);
first_chunk = 0;
}
if (len == PAGE_SIZE-1) {
buf[len] = '\0'; buf[len] = '\0';
mconsole_reply(req, buf, 0, 1); mconsole_reply(req, buf, 0, 1);
} else { } else {
......
...@@ -123,12 +123,18 @@ struct chan_ops port_ops = { ...@@ -123,12 +123,18 @@ struct chan_ops port_ops = {
int port_listen_fd(int port) int port_listen_fd(int port)
{ {
struct sockaddr_in addr; struct sockaddr_in addr;
int fd, err; int fd, err, arg;
fd = socket(PF_INET, SOCK_STREAM, 0); fd = socket(PF_INET, SOCK_STREAM, 0);
if(fd == -1) if(fd == -1)
return(-errno); return(-errno);
arg = 1;
if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) < 0){
err = -errno;
goto out;
}
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
addr.sin_port = htons(port); addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_addr.s_addr = htonl(INADDR_ANY);
......
...@@ -67,6 +67,7 @@ extern void map_memory(unsigned long virt, unsigned long phys, ...@@ -67,6 +67,7 @@ extern void map_memory(unsigned long virt, unsigned long phys,
extern int protect_memory(unsigned long addr, unsigned long len, extern int protect_memory(unsigned long addr, unsigned long len,
int r, int w, int x, int must_succeed); int r, int w, int x, int must_succeed);
extern unsigned long get_kmem_end(void); extern unsigned long get_kmem_end(void);
extern void check_tmpexec(void);
#endif #endif
......
...@@ -9,11 +9,11 @@ ...@@ -9,11 +9,11 @@
#include "uml-config.h" #include "uml-config.h"
#ifdef UML_CONFIG_MODE_TT #ifdef UML_CONFIG_MODE_TT
#include "../kernel/tt/include/mode.h" #include "mode-tt.h"
#endif #endif
#ifdef UML_CONFIG_MODE_SKAS #ifdef UML_CONFIG_MODE_SKAS
#include "../kernel/skas/include/mode.h" #include "mode-skas.h"
#endif #endif
#endif #endif
......
...@@ -9,11 +9,11 @@ ...@@ -9,11 +9,11 @@
#include "linux/config.h" #include "linux/config.h"
#ifdef CONFIG_MODE_TT #ifdef CONFIG_MODE_TT
#include "../kernel/tt/include/mode_kern.h" #include "mode_kern-tt.h"
#endif #endif
#ifdef CONFIG_MODE_SKAS #ifdef CONFIG_MODE_SKAS
#include "../kernel/skas/include/mode_kern.h" #include "mode_kern-skas.h"
#endif #endif
#endif #endif
......
...@@ -157,6 +157,7 @@ extern unsigned long os_process_pc(int pid); ...@@ -157,6 +157,7 @@ extern unsigned long os_process_pc(int pid);
extern int os_process_parent(int pid); extern int os_process_parent(int pid);
extern void os_stop_process(int pid); extern void os_stop_process(int pid);
extern void os_kill_process(int pid, int reap_child); extern void os_kill_process(int pid, int reap_child);
extern void os_kill_ptraced_process(int pid, int reap_child);
extern void os_usr1_process(int pid); extern void os_usr1_process(int pid);
extern int os_getpid(void); extern int os_getpid(void);
......
...@@ -15,4 +15,15 @@ extern void arch_enter_kernel(void *task, int pid); ...@@ -15,4 +15,15 @@ extern void arch_enter_kernel(void *task, int pid);
extern void arch_leave_kernel(void *task, int pid); extern void arch_leave_kernel(void *task, int pid);
extern void ptrace_pokeuser(unsigned long addr, unsigned long data); extern void ptrace_pokeuser(unsigned long addr, unsigned long data);
/* syscall emulation path in ptrace */
#ifndef PTRACE_SYSEMU
#define PTRACE_SYSEMU 31
#endif
void set_using_sysemu(int value);
int get_using_sysemu(void);
extern int sysemu_supported;
#endif #endif
...@@ -10,11 +10,11 @@ ...@@ -10,11 +10,11 @@
#include "choose-mode.h" #include "choose-mode.h"
#ifdef CONFIG_MODE_TT #ifdef CONFIG_MODE_TT
#include "../kernel/tt/include/mmu.h" #include "mmu-tt.h"
#endif #endif
#ifdef CONFIG_MODE_SKAS #ifdef CONFIG_MODE_SKAS
#include "../kernel/skas/include/mmu.h" #include "mmu-skas.h"
#endif #endif
typedef union { typedef union {
......
...@@ -10,11 +10,11 @@ ...@@ -10,11 +10,11 @@
#include "choose-mode.h" #include "choose-mode.h"
#ifdef CONFIG_MODE_TT #ifdef CONFIG_MODE_TT
#include "../kernel/tt/include/uaccess.h" #include "uaccess-tt.h"
#endif #endif
#ifdef CONFIG_MODE_SKAS #ifdef CONFIG_MODE_SKAS
#include "../kernel/skas/include/uaccess.h" #include "uaccess-skas.h"
#endif #endif
#define access_ok(type, addr, size) \ #define access_ok(type, addr, size) \
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
#include "sysdep/ptrace.h" #include "sysdep/ptrace.h"
#define CATCH_EINTR(expr) while (((expr) < 0) && (errno == EINTR)) #define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR))
extern int mode_tt; extern int mode_tt;
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#include "kern_util.h" #include "kern_util.h"
#include "mem_user.h" #include "mem_user.h"
#include "signal_user.h" #include "signal_user.h"
#include "time_user.h"
#include "irq_user.h"
#include "user.h" #include "user.h"
#include "init.h" #include "init.h"
#include "mode.h" #include "mode.h"
......
...@@ -83,6 +83,26 @@ static int create_tmp_file(unsigned long len) ...@@ -83,6 +83,26 @@ static int create_tmp_file(unsigned long len)
return(fd); return(fd);
} }
void check_tmpexec(void)
{
void *addr;
int err, fd = create_tmp_file(UM_KERN_PAGE_SIZE);
addr = mmap(NULL, UM_KERN_PAGE_SIZE,
PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0);
printf("Checking PROT_EXEC mmap in /tmp...");
fflush(stdout);
if(addr == MAP_FAILED){
err = errno;
perror("failed");
if(err == EPERM)
printf("/tmp must be not mounted noexec\n");
exit(1);
}
printf("OK\n");
munmap(addr, UM_KERN_PAGE_SIZE);
}
static int have_devanon = 0; static int have_devanon = 0;
void check_devanon(void) void check_devanon(void)
...@@ -111,7 +131,7 @@ static int create_anon_file(unsigned long len) ...@@ -111,7 +131,7 @@ static int create_anon_file(unsigned long len)
exit(1); exit(1);
} }
addr = mmap(NULL, len, PROT_READ | PROT_WRITE , MAP_PRIVATE, fd, 0); addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
if(addr == MAP_FAILED){ if(addr == MAP_FAILED){
os_print_error((int) addr, "mapping physmem file"); os_print_error((int) addr, "mapping physmem file");
exit(1); exit(1);
...@@ -208,6 +228,39 @@ int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x, ...@@ -208,6 +228,39 @@ int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x,
return(0); return(0);
} }
#if 0
/* Debugging facility for dumping stuff out to the host, avoiding the timing
* problems that come with printf and breakpoints.
* Enable in case of emergency.
*/
int logging = 1;
int logging_fd = -1;
int logging_line = 0;
char logging_buf[512];
void log(char *fmt, ...)
{
va_list ap;
struct timeval tv;
struct openflags flags;
if(logging == 0) return;
if(logging_fd < 0){
flags = of_create(of_trunc(of_rdwr(OPENFLAGS())));
logging_fd = os_open_file("log", flags, 0644);
}
gettimeofday(&tv, NULL);
sprintf(logging_buf, "%d\t %u.%u ", logging_line++, tv.tv_sec,
tv.tv_usec);
va_start(ap, fmt);
vsprintf(&logging_buf[strlen(logging_buf)], fmt, ap);
va_end(ap);
write(logging_fd, logging_buf, strlen(logging_buf));
}
#endif
/* /*
* Overrides for Emacs so that we follow Linus's tabbing style. * Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically * Emacs will notice this stuff at the end of the file and automatically
......
...@@ -137,14 +137,31 @@ int start_fork_tramp(void *thread_arg, unsigned long temp_stack, ...@@ -137,14 +137,31 @@ int start_fork_tramp(void *thread_arg, unsigned long temp_stack,
static int ptrace_child(void *arg) static int ptrace_child(void *arg)
{ {
int pid = os_getpid(); int ret;
int pid = os_getpid(), ppid = getppid();
int sc_result;
if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){ if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
perror("ptrace"); perror("ptrace");
os_kill_process(pid, 0); os_kill_process(pid, 0);
} }
os_stop_process(pid); os_stop_process(pid);
_exit(os_getpid() == pid);
/*This syscall will be intercepted by the parent. Don't call more than
* once, please.*/
sc_result = os_getpid();
if (sc_result == pid)
ret = 1; /*Nothing modified by the parent, we are running
normally.*/
else if (sc_result == ppid)
ret = 0; /*Expected in check_ptrace and check_sysemu when they
succeed in modifying the stack frame*/
else
ret = 2; /*Serious trouble! This could be caused by a bug in
host 2.6 SKAS3/2.6 patch before release -V6, together
with a bug in the UML code itself.*/
_exit(ret);
} }
static int start_ptraced_child(void **stack_out) static int start_ptraced_child(void **stack_out)
...@@ -172,18 +189,36 @@ static int start_ptraced_child(void **stack_out) ...@@ -172,18 +189,36 @@ static int start_ptraced_child(void **stack_out)
return(pid); return(pid);
} }
static void stop_ptraced_child(int pid, void *stack, int exitcode) /* When testing for SYSEMU support, if it is one of the broken versions, we must
* just avoid using sysemu, not panic, but only if SYSEMU features are broken.
* So only for SYSEMU features we test mustpanic, while normal host features
* must work anyway!*/
static int stop_ptraced_child(int pid, void *stack, int exitcode, int mustpanic)
{ {
int status, n; int status, n, ret = 0;
if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
panic("check_ptrace : ptrace failed, errno = %d", errno); panic("check_ptrace : ptrace failed, errno = %d", errno);
CATCH_EINTR(n = waitpid(pid, &status, 0)); CATCH_EINTR(n = waitpid(pid, &status, 0));
if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) {
panic("check_ptrace : child exited with status 0x%x", status); int exit_with = WEXITSTATUS(status);
if (exit_with == 2)
printk("check_ptrace : child exited with status 2. "
"Serious trouble happening! Try updating your "
"host skas patch!\nDisabling SYSEMU support.");
printk("check_ptrace : child exited with exitcode %d, while "
"expecting %d; status 0x%x", exit_with,
exitcode, status);
if (mustpanic)
panic("\n");
else
printk("\n");
ret = -1;
}
if(munmap(stack, PAGE_SIZE) < 0) if(munmap(stack, PAGE_SIZE) < 0)
panic("check_ptrace : munmap failed, errno = %d", errno); panic("check_ptrace : munmap failed, errno = %d", errno);
return ret;
} }
static int force_sysemu_disabled = 0; static int force_sysemu_disabled = 0;
...@@ -200,63 +235,46 @@ __uml_setup("nosysemu", nosysemu_cmd_param, ...@@ -200,63 +235,46 @@ __uml_setup("nosysemu", nosysemu_cmd_param,
" SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n" " SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n"
" behaviour of ptrace() and helps reducing host context switch rate.\n" " behaviour of ptrace() and helps reducing host context switch rate.\n"
" To make it working, you need a kernel patch for your host, too.\n" " To make it working, you need a kernel patch for your host, too.\n"
" See http://perso.wanadoo.fr/laurent.vivier/UML/ for further information.\n"); " See http://perso.wanadoo.fr/laurent.vivier/UML/ for further information.\n\n");
/* Ugly hack for now... --cw */
#ifndef PTRACE_SYSEMU
#define PTRACE_SYSEMU 31
#endif
static void __init check_sysemu(void) static void __init check_sysemu(void)
{ {
void *stack; void *stack;
int pid, n, status; int pid, n, status;
if (mode_tt)
return;
printk("Checking syscall emulation patch for ptrace..."); printk("Checking syscall emulation patch for ptrace...");
#ifdef CONFIG_MODE_SKAS
sysemu_supported = 0; sysemu_supported = 0;
#endif /* CONFIG_MODE_SKAS */
pid = start_ptraced_child(&stack); pid = start_ptraced_child(&stack);
if(ptrace(PTRACE_SYSEMU, pid, 0, 0) >= 0) {
struct user_regs_struct regs;
CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
if (n < 0)
panic("check_ptrace : wait failed, errno = %d", errno);
if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
panic("check_ptrace : expected SIGTRAP, "
"got status = %d", status);
if (ptrace(PTRACE_GETREGS, pid, 0, &regs) < 0) if(ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0)
panic("check_ptrace : failed to read child " goto fail;
"registers, errno = %d", errno);
regs.orig_eax = pid;
if (ptrace(PTRACE_SETREGS, pid, 0, &regs) < 0)
panic("check_ptrace : failed to modify child "
"registers, errno = %d", errno);
stop_ptraced_child(pid, stack, 0); CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
if (n < 0)
panic("check_sysemu : wait failed, errno = %d", errno);
if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
panic("check_sysemu : expected SIGTRAP, "
"got status = %d", status);
n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET,
os_getpid());
if(n < 0)
panic("check_sysemu : failed to modify system "
"call return, errno = %d", errno);
#ifdef CONFIG_MODE_SKAS if (stop_ptraced_child(pid, stack, 0, 0) < 0)
sysemu_supported = 1; goto fail_stopped;
#endif /* CONFIG_MODE_SKAS */
printk("found\n");
}
else
{
stop_ptraced_child(pid, stack, 1);
#ifdef CONFIG_MODE_SKAS
sysemu_supported = 0;
#endif /* CONFIG_MODE_SKAS */
printk("missing\n");
}
#ifdef CONFIG_MODE_SKAS sysemu_supported = 1;
printk("OK\n");
set_using_sysemu(!force_sysemu_disabled); set_using_sysemu(!force_sysemu_disabled);
#endif return;
fail:
stop_ptraced_child(pid, stack, 1, 0);
fail_stopped:
sysemu_supported = 0;
printk("missing\n");
} }
void __init check_ptrace(void) void __init check_ptrace(void)
...@@ -289,7 +307,7 @@ void __init check_ptrace(void) ...@@ -289,7 +307,7 @@ void __init check_ptrace(void)
break; break;
} }
} }
stop_ptraced_child(pid, stack, 0); stop_ptraced_child(pid, stack, 0, 1);
printk("OK\n"); printk("OK\n");
check_sysemu(); check_sysemu();
} }
...@@ -337,7 +355,7 @@ int can_do_skas(void) ...@@ -337,7 +355,7 @@ int can_do_skas(void)
else printf("found\n"); else printf("found\n");
init_registers(pid); init_registers(pid);
stop_ptraced_child(pid, stack, 1); stop_ptraced_child(pid, stack, 1, 1);
printf("Checking for /proc/mm..."); printf("Checking for /proc/mm...");
if(os_access("/proc/mm", OS_ACC_W_OK) < 0){ if(os_access("/proc/mm", OS_ACC_W_OK) < 0){
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#include "linux/capability.h" #include "linux/capability.h"
#include "linux/vmalloc.h" #include "linux/vmalloc.h"
#include "linux/spinlock.h" #include "linux/spinlock.h"
#include "linux/proc_fs.h"
#include "linux/ptrace.h"
#include "asm/unistd.h" #include "asm/unistd.h"
#include "asm/mman.h" #include "asm/mman.h"
#include "asm/segment.h" #include "asm/segment.h"
...@@ -398,6 +400,74 @@ int cpu(void) ...@@ -398,6 +400,74 @@ int cpu(void)
return(current_thread->cpu); return(current_thread->cpu);
} }
static atomic_t using_sysemu = ATOMIC_INIT(0);
int sysemu_supported;
void set_using_sysemu(int value)
{
atomic_set(&using_sysemu, sysemu_supported && value);
}
int get_using_sysemu(void)
{
return atomic_read(&using_sysemu);
}
static int proc_read_sysemu(char *buf, char **start, off_t offset, int size,int *eof, void *data)
{
if (snprintf(buf, size, "%d\n", get_using_sysemu()) < size) /*No overflow*/
*eof = 1;
return strlen(buf);
}
static int proc_write_sysemu(struct file *file,const char *buf, unsigned long count,void *data)
{
char tmp[2];
if (copy_from_user(tmp, buf, 1))
return -EFAULT;
if (tmp[0] == '0' || tmp[0] == '1')
set_using_sysemu(tmp[0] - '0');
return count; /*We use the first char, but pretend to write everything*/
}
int __init make_proc_sysemu(void)
{
struct proc_dir_entry *ent;
if (!sysemu_supported)
return 0;
ent = create_proc_entry("sysemu", 0600, &proc_root);
if (ent == NULL)
{
printk("Failed to register /proc/sysemu\n");
return(0);
}
ent->read_proc = proc_read_sysemu;
ent->write_proc = proc_write_sysemu;
return 0;
}
late_initcall(make_proc_sysemu);
int singlestepping(void * t)
{
struct task_struct *task = t ? t : current;
if ( ! (task->ptrace & PT_DTRACE) )
return(0);
if (task->thread.singlestep_syscall)
return(0);
return 1;
}
/* /*
* Overrides for Emacs so that we follow Linus's tabbing style. * Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically * Emacs will notice this stuff at the end of the file and automatically
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
*/ */
void ptrace_disable(struct task_struct *child) void ptrace_disable(struct task_struct *child)
{ {
child->ptrace &= ~PT_DTRACE;
child->thread.singlestep_syscall = 0;
} }
int sys_ptrace(long request, long pid, long addr, long data) int sys_ptrace(long request, long pid, long addr, long data)
...@@ -139,6 +141,9 @@ int sys_ptrace(long request, long pid, long addr, long data) ...@@ -139,6 +141,9 @@ int sys_ptrace(long request, long pid, long addr, long data)
ret = -EIO; ret = -EIO;
if ((unsigned long) data > _NSIG) if ((unsigned long) data > _NSIG)
break; break;
child->ptrace &= ~PT_DTRACE;
child->thread.singlestep_syscall = 0;
if (request == PTRACE_SYSCALL) { if (request == PTRACE_SYSCALL) {
set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
} }
...@@ -160,6 +165,9 @@ int sys_ptrace(long request, long pid, long addr, long data) ...@@ -160,6 +165,9 @@ int sys_ptrace(long request, long pid, long addr, long data)
ret = 0; ret = 0;
if (child->exit_state == EXIT_ZOMBIE) /* already dead */ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break; break;
child->ptrace &= ~PT_DTRACE;
child->thread.singlestep_syscall = 0;
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
wake_up_process(child); wake_up_process(child);
break; break;
...@@ -171,6 +179,7 @@ int sys_ptrace(long request, long pid, long addr, long data) ...@@ -171,6 +179,7 @@ int sys_ptrace(long request, long pid, long addr, long data)
break; break;
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
child->ptrace |= PT_DTRACE; child->ptrace |= PT_DTRACE;
child->thread.singlestep_syscall = 0;
child->exit_code = data; child->exit_code = data;
/* give it a chance to run. */ /* give it a chance to run. */
wake_up_process(child); wake_up_process(child);
...@@ -299,6 +308,9 @@ int sys_ptrace(long request, long pid, long addr, long data) ...@@ -299,6 +308,9 @@ int sys_ptrace(long request, long pid, long addr, long data)
void syscall_trace(union uml_pt_regs *regs, int entryexit) void syscall_trace(union uml_pt_regs *regs, int entryexit)
{ {
int is_singlestep = (current->ptrace & PT_DTRACE) && entryexit;
int tracesysgood;
if (unlikely(current->audit_context)) { if (unlikely(current->audit_context)) {
if (!entryexit) if (!entryexit)
audit_syscall_entry(current, regs->orig_eax, audit_syscall_entry(current, regs->orig_eax,
...@@ -308,18 +320,20 @@ void syscall_trace(union uml_pt_regs *regs, int entryexit) ...@@ -308,18 +320,20 @@ void syscall_trace(union uml_pt_regs *regs, int entryexit)
audit_syscall_exit(current, regs->eax); audit_syscall_exit(current, regs->eax);
} }
if (!test_thread_flag(TIF_SYSCALL_TRACE)) if (!test_thread_flag(TIF_SYSCALL_TRACE) && !is_singlestep)
return; return;
if (!(current->ptrace & PT_PTRACED)) if (!(current->ptrace & PT_PTRACED))
return; return;
/* the 0x80 provides a way for the tracing parent to distinguish /* the 0x80 provides a way for the tracing parent to distinguish
between a syscall stop and SIGTRAP delivery */ between a syscall stop and SIGTRAP delivery */
ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) tracesysgood = (current->ptrace & PT_TRACESYSGOOD) && !is_singlestep;
? 0x80 : 0)); ptrace_notify(SIGTRAP | (tracesysgood ? 0x80 : 0));
/* force do_signal() --> is_syscall() */
set_thread_flag(TIF_SIGPENDING);
/* /* this isn't the same as continuing with a signal, but it will do
* this isn't the same as continuing with a signal, but it will do
* for normal use. strace only continues with a signal if the * for normal use. strace only continues with a signal if the
* stopping signal is not SIGTRAP. -brl * stopping signal is not SIGTRAP. -brl
*/ */
......
...@@ -28,7 +28,7 @@ int write_sigio_irq(int fd) ...@@ -28,7 +28,7 @@ int write_sigio_irq(int fd)
int err; int err;
err = um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt, err = um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt,
SA_INTERRUPT | SA_SAMPLE_RANDOM, "write sigio", SA_INTERRUPT | SA_SAMPLE_RANDOM, "write sigio",
NULL); NULL);
if(err){ if(err){
printk("write_sigio_irq : um_request_irq failed, err = %d\n", printk("write_sigio_irq : um_request_irq failed, err = %d\n",
......
...@@ -38,16 +38,17 @@ EXPORT_SYMBOL(unblock_signals); ...@@ -38,16 +38,17 @@ EXPORT_SYMBOL(unblock_signals);
/* /*
* OK, we're invoking a handler * OK, we're invoking a handler
*/ */
static int handle_signal(struct pt_regs *regs, unsigned long signr, static void handle_signal(struct pt_regs *regs, unsigned long signr,
struct k_sigaction *ka, siginfo_t *info, struct k_sigaction *ka, siginfo_t *info,
sigset_t *oldset, int error) sigset_t *oldset)
{ {
__sighandler_t handler; __sighandler_t handler;
void (*restorer)(void); void (*restorer)(void);
unsigned long sp; unsigned long sp;
sigset_t save; sigset_t save;
int err, ret; int error, err, ret;
error = PT_REGS_SYSCALL_RET(&current->thread.regs);
ret = 0; ret = 0;
/* Always make any pending restarted system calls return -EINTR */ /* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall; current_thread_info()->restart_block.fn = do_no_restart_syscall;
...@@ -109,31 +110,25 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr, ...@@ -109,31 +110,25 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr,
else else
err = setup_signal_stack_sc(sp, signr, (unsigned long) handler, err = setup_signal_stack_sc(sp, signr, (unsigned long) handler,
restorer, regs, &save); restorer, regs, &save);
if(err) goto segv; if(err)
force_sigsegv(signr, current);
return(0);
segv:
force_sigsegv(signr, current);
return(1);
} }
static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset, int error) static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset)
{ {
struct k_sigaction ka_copy; struct k_sigaction ka_copy;
siginfo_t info; siginfo_t info;
int err, sig; int sig;
if (!oldset) if (!oldset)
oldset = &current->blocked; oldset = &current->blocked;
sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL); sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL);
if(sig == 0) if(sig > 0){
return(0); /* Whee! Actually deliver the signal. */
handle_signal(regs, sig, &ka_copy, &info, oldset);
/* Whee! Actually deliver the signal. */
err = handle_signal(regs, sig, &ka_copy, &info, oldset, error);
if(!err)
return(1); return(1);
}
/* Did we come from a system call? */ /* Did we come from a system call? */
if(PT_REGS_SYSCALL_NR(regs) >= 0){ if(PT_REGS_SYSCALL_NR(regs) >= 0){
...@@ -157,15 +152,15 @@ static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset, int error) ...@@ -157,15 +152,15 @@ static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset, int error)
* on the host. The tracing thread will check this flag and * on the host. The tracing thread will check this flag and
* PTRACE_SYSCALL if necessary. * PTRACE_SYSCALL if necessary.
*/ */
if((current->ptrace & PT_DTRACE) && if(current->ptrace & PT_DTRACE)
is_syscall(PT_REGS_IP(&current->thread.regs))) current->thread.singlestep_syscall =
(void) CHOOSE_MODE(current->thread.mode.tt.singlestep_syscall = 1, 0); is_syscall(PT_REGS_IP(&current->thread.regs));
return(0); return(0);
} }
int do_signal(int error) int do_signal(int error)
{ {
return(kern_do_signal(&current->thread.regs, NULL, error)); return(kern_do_signal(&current->thread.regs, NULL));
} }
/* /*
...@@ -182,10 +177,11 @@ int sys_sigsuspend(int history0, int history1, old_sigset_t mask) ...@@ -182,10 +177,11 @@ int sys_sigsuspend(int history0, int history1, old_sigset_t mask)
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock); spin_unlock_irq(&current->sighand->siglock);
PT_REGS_SYSCALL_RET(&current->thread.regs) = -EINTR;
while (1) { while (1) {
current->state = TASK_INTERRUPTIBLE; current->state = TASK_INTERRUPTIBLE;
schedule(); schedule();
if(kern_do_signal(&current->thread.regs, &saveset, -EINTR)) if(kern_do_signal(&current->thread.regs, &saveset))
return(-EINTR); return(-EINTR);
} }
} }
...@@ -208,10 +204,11 @@ int sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize) ...@@ -208,10 +204,11 @@ int sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize)
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock); spin_unlock_irq(&current->sighand->siglock);
PT_REGS_SYSCALL_RET(&current->thread.regs) = -EINTR;
while (1) { while (1) {
current->state = TASK_INTERRUPTIBLE; current->state = TASK_INTERRUPTIBLE;
schedule(); schedule();
if (kern_do_signal(&current->thread.regs, &saveset, -EINTR)) if (kern_do_signal(&current->thread.regs, &saveset))
return(-EINTR); return(-EINTR);
} }
} }
......
...@@ -57,6 +57,10 @@ int change_sig(int signal, int on) ...@@ -57,6 +57,10 @@ int change_sig(int signal, int on)
return(!sigismember(&old, signal)); return(!sigismember(&old, signal));
} }
/* Both here and in set/get_signal we don't touch SIGPROF, because we must not
* disable profiling; it's safe because the profiling code does not interact
* with the kernel code at all.*/
static void change_signals(int type) static void change_signals(int type)
{ {
sigset_t mask; sigset_t mask;
...@@ -65,7 +69,6 @@ static void change_signals(int type) ...@@ -65,7 +69,6 @@ static void change_signals(int type)
sigaddset(&mask, SIGVTALRM); sigaddset(&mask, SIGVTALRM);
sigaddset(&mask, SIGALRM); sigaddset(&mask, SIGALRM);
sigaddset(&mask, SIGIO); sigaddset(&mask, SIGIO);
sigaddset(&mask, SIGPROF);
if(sigprocmask(type, &mask, NULL) < 0) if(sigprocmask(type, &mask, NULL) < 0)
panic("Failed to change signal mask - errno = %d", errno); panic("Failed to change signal mask - errno = %d", errno);
} }
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
#include "asm/mmu_context.h" #include "asm/mmu_context.h"
#include "tlb.h" #include "tlb.h"
#include "skas.h" #include "skas.h"
#include "mmu.h" #include "um_mmu.h"
#include "os.h" #include "os.h"
void flush_thread_skas(void) void flush_thread_skas(void)
......
/* /*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL * Licensed under the GPL
*/ */
...@@ -6,9 +6,6 @@ ...@@ -6,9 +6,6 @@
#ifndef __SKAS_MMU_H #ifndef __SKAS_MMU_H
#define __SKAS_MMU_H #define __SKAS_MMU_H
#include "linux/list.h"
#include "linux/spinlock.h"
struct mmu_context_skas { struct mmu_context_skas {
int mm_fd; int mm_fd;
}; };
......
/* /*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL * Licensed under the GPL
*/ */
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#ifndef __MODE_SKAS_H__ #ifndef __MODE_SKAS_H__
#define __MODE_SKAS_H__ #define __MODE_SKAS_H__
#include <sysdep/ptrace.h>
extern unsigned long exec_regs[]; extern unsigned long exec_regs[];
extern unsigned long exec_fp_regs[]; extern unsigned long exec_fp_regs[];
extern unsigned long exec_fpx_regs[]; extern unsigned long exec_fpx_regs[];
...@@ -15,7 +17,7 @@ extern void user_time_init_skas(void); ...@@ -15,7 +17,7 @@ extern void user_time_init_skas(void);
extern int copy_sc_from_user_skas(int pid, union uml_pt_regs *regs, extern int copy_sc_from_user_skas(int pid, union uml_pt_regs *regs,
void *from_ptr); void *from_ptr);
extern int copy_sc_to_user_skas(int pid, void *to_ptr, void *fp, extern int copy_sc_to_user_skas(int pid, void *to_ptr, void *fp,
union uml_pt_regs *regs, union uml_pt_regs *regs,
unsigned long fault_addr, int fault_type); unsigned long fault_addr, int fault_type);
extern void sig_handler_common_skas(int sig, void *sc_ptr); extern void sig_handler_common_skas(int sig, void *sc_ptr);
extern void halt_skas(void); extern void halt_skas(void);
......
/* /*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL * Licensed under the GPL
*/ */
...@@ -12,20 +12,20 @@ ...@@ -12,20 +12,20 @@
extern void flush_thread_skas(void); extern void flush_thread_skas(void);
extern void *switch_to_skas(void *prev, void *next); extern void *switch_to_skas(void *prev, void *next);
extern void start_thread_skas(struct pt_regs *regs, unsigned long eip, extern void start_thread_skas(struct pt_regs *regs, unsigned long eip,
unsigned long esp); unsigned long esp);
extern int copy_thread_skas(int nr, unsigned long clone_flags, extern int copy_thread_skas(int nr, unsigned long clone_flags,
unsigned long sp, unsigned long stack_top, unsigned long sp, unsigned long stack_top,
struct task_struct *p, struct pt_regs *regs); struct task_struct *p, struct pt_regs *regs);
extern void release_thread_skas(struct task_struct *task); extern void release_thread_skas(struct task_struct *task);
extern void exit_thread_skas(void); extern void exit_thread_skas(void);
extern void initial_thread_cb_skas(void (*proc)(void *), void *arg); extern void initial_thread_cb_skas(void (*proc)(void *), void *arg);
extern void init_idle_skas(void); extern void init_idle_skas(void);
extern void flush_tlb_kernel_range_skas(unsigned long start, extern void flush_tlb_kernel_range_skas(unsigned long start,
unsigned long end); unsigned long end);
extern void flush_tlb_kernel_vm_skas(void); extern void flush_tlb_kernel_vm_skas(void);
extern void __flush_tlb_one_skas(unsigned long addr); extern void __flush_tlb_one_skas(unsigned long addr);
extern void flush_tlb_range_skas(struct vm_area_struct *vma, extern void flush_tlb_range_skas(struct vm_area_struct *vma,
unsigned long start, unsigned long end); unsigned long start, unsigned long end);
extern void flush_tlb_mm_skas(struct mm_struct *mm); extern void flush_tlb_mm_skas(struct mm_struct *mm);
extern void force_flush_all_skas(void); extern void force_flush_all_skas(void);
......
...@@ -10,16 +10,6 @@ ...@@ -10,16 +10,6 @@
#ifdef UML_CONFIG_MODE_SKAS #ifdef UML_CONFIG_MODE_SKAS
/* syscall emulation path in ptrace */
#ifndef PTRACE_SYSEMU
#define PTRACE_SYSEMU 31
#endif
void set_using_sysemu(int value);
int get_using_sysemu(void);
extern int sysemu_supported;
#include "skas_ptregs.h" #include "skas_ptregs.h"
#define HOST_FRAME_SIZE 17 #define HOST_FRAME_SIZE 17
......
...@@ -28,7 +28,6 @@ extern int unmap(int fd, void *addr, int len); ...@@ -28,7 +28,6 @@ extern int unmap(int fd, void *addr, int len);
extern int protect(int fd, unsigned long addr, unsigned long len, extern int protect(int fd, unsigned long addr, unsigned long len,
int r, int w, int x, int must_succeed); int r, int w, int x, int must_succeed);
extern void user_signal(int sig, union uml_pt_regs *regs); extern void user_signal(int sig, union uml_pt_regs *regs);
extern int singlestepping_skas(void);
extern int new_mm(int from); extern int new_mm(int from);
extern void save_registers(union uml_pt_regs *regs); extern void save_registers(union uml_pt_regs *regs);
extern void restore_registers(union uml_pt_regs *regs); extern void restore_registers(union uml_pt_regs *regs);
......
/* /*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL * Licensed under the GPL
*/ */
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
(((unsigned long) (addr) < TASK_SIZE) && \ (((unsigned long) (addr) < TASK_SIZE) && \
((unsigned long) (addr) + (size) <= TASK_SIZE))) ((unsigned long) (addr) + (size) <= TASK_SIZE)))
static inline int verify_area_skas(int type, const void * addr, static inline int verify_area_skas(int type, const void * addr,
unsigned long size) unsigned long size)
{ {
return(access_ok_skas(type, addr, size) ? 0 : -EFAULT); return(access_ok_skas(type, addr, size) ? 0 : -EFAULT);
......
...@@ -139,17 +139,16 @@ void start_userspace(int cpu) ...@@ -139,17 +139,16 @@ void start_userspace(int cpu)
void userspace(union uml_pt_regs *regs) void userspace(union uml_pt_regs *regs)
{ {
int err, status, op, pid = userspace_pid[0]; int err, status, op, pt_syscall_parm, pid = userspace_pid[0];
int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/ int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/
restore_registers(regs); restore_registers(regs);
local_using_sysemu = get_using_sysemu(); local_using_sysemu = get_using_sysemu();
if (local_using_sysemu) pt_syscall_parm = local_using_sysemu ? PTRACE_SYSEMU : PTRACE_SYSCALL;
err = ptrace(PTRACE_SYSEMU, pid, 0, 0); err = ptrace(pt_syscall_parm, pid, 0, 0);
else
err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
if(err) if(err)
panic("userspace - PTRACE_%s failed, errno = %d\n", panic("userspace - PTRACE_%s failed, errno = %d\n",
local_using_sysemu ? "SYSEMU" : "SYSCALL", errno); local_using_sysemu ? "SYSEMU" : "SYSCALL", errno);
...@@ -189,13 +188,10 @@ void userspace(union uml_pt_regs *regs) ...@@ -189,13 +188,10 @@ void userspace(union uml_pt_regs *regs)
/*Now we ended the syscall, so re-read local_using_sysemu.*/ /*Now we ended the syscall, so re-read local_using_sysemu.*/
local_using_sysemu = get_using_sysemu(); local_using_sysemu = get_using_sysemu();
pt_syscall_parm = local_using_sysemu ? PTRACE_SYSEMU : PTRACE_SYSCALL;
if (local_using_sysemu) op = singlestepping(NULL) ? PTRACE_SINGLESTEP :
op = singlestepping_skas() ? PTRACE_SINGLESTEP : pt_syscall_parm;
PTRACE_SYSEMU;
else
op = singlestepping_skas() ? PTRACE_SINGLESTEP :
PTRACE_SYSCALL;
err = ptrace(op, pid, 0, 0); err = ptrace(op, pid, 0, 0);
if(err) if(err)
...@@ -389,7 +385,7 @@ void switch_mm_skas(int mm_fd) ...@@ -389,7 +385,7 @@ void switch_mm_skas(int mm_fd)
void kill_off_processes_skas(void) void kill_off_processes_skas(void)
{ {
#warning need to loop over userspace_pids in kill_off_processes_skas #warning need to loop over userspace_pids in kill_off_processes_skas
os_kill_process(userspace_pid[0], 1); os_kill_ptraced_process(userspace_pid[0], 1);
} }
void init_registers(int pid) void init_registers(int pid)
......
...@@ -24,69 +24,6 @@ ...@@ -24,69 +24,6 @@
#include "mode.h" #include "mode.h"
#include "proc_mm.h" #include "proc_mm.h"
static atomic_t using_sysemu;
int sysemu_supported;
void set_using_sysemu(int value)
{
atomic_set(&using_sysemu, sysemu_supported && value);
}
int get_using_sysemu(void)
{
return atomic_read(&using_sysemu);
}
int proc_read_sysemu(char *buf, char **start, off_t offset, int size,int *eof, void *data)
{
if (snprintf(buf, size, "%d\n", get_using_sysemu()) < size) /*No overflow*/
*eof = 1;
return strlen(buf);
}
int proc_write_sysemu(struct file *file,const char *buf, unsigned long count,void *data)
{
char tmp[2];
if (copy_from_user(tmp, buf, 1))
return -EFAULT;
if (tmp[0] == '0' || tmp[0] == '1')
set_using_sysemu(tmp[0] - '0');
return count; /*We use the first char, but pretend to write everything*/
}
int __init make_proc_sysemu(void)
{
struct proc_dir_entry *ent;
if (mode_tt || !sysemu_supported)
return 0;
ent = create_proc_entry("sysemu", 0600, &proc_root);
if (ent == NULL)
{
printk("Failed to register /proc/sysemu\n");
return(0);
}
ent->read_proc = proc_read_sysemu;
ent->write_proc = proc_write_sysemu;
return 0;
}
late_initcall(make_proc_sysemu);
int singlestepping_skas(void)
{
int ret = current->ptrace & PT_DTRACE;
current->ptrace &= ~PT_DTRACE;
return(ret);
}
void *switch_to_skas(void *prev, void *next) void *switch_to_skas(void *prev, void *next)
{ {
struct task_struct *from, *to; struct task_struct *from, *to;
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
*/ */
#include "linux/sys.h" #include "linux/sys.h"
#include "linux/ptrace.h"
#include "asm/errno.h" #include "asm/errno.h"
#include "asm/unistd.h" #include "asm/unistd.h"
#include "asm/ptrace.h" #include "asm/ptrace.h"
......
...@@ -22,7 +22,7 @@ void handle_syscall(union uml_pt_regs *regs) ...@@ -22,7 +22,7 @@ void handle_syscall(union uml_pt_regs *regs)
index = record_syscall_start(UPT_SYSCALL_NR(regs)); index = record_syscall_start(UPT_SYSCALL_NR(regs));
syscall_trace(regs, 1); syscall_trace(regs, 0);
result = execute_syscall(regs); result = execute_syscall(regs);
REGS_SET_SYSCALL_RETURN(regs->skas.regs, result); REGS_SET_SYSCALL_RETURN(regs->skas.regs, result);
...@@ -30,7 +30,7 @@ void handle_syscall(union uml_pt_regs *regs) ...@@ -30,7 +30,7 @@ void handle_syscall(union uml_pt_regs *regs)
(result == -ERESTARTNOINTR)) (result == -ERESTARTNOINTR))
do_signal(result); do_signal(result);
syscall_trace(regs, 0); syscall_trace(regs, 1);
record_syscall_end(index, result); record_syscall_end(index, result);
} }
......
...@@ -14,23 +14,23 @@ ...@@ -14,23 +14,23 @@
void show_trace(unsigned long * stack) void show_trace(unsigned long * stack)
{ {
int i; /* XXX: Copy the CONFIG_FRAME_POINTER stack-walking backtrace from
* arch/i386/kernel/traps.c. */
unsigned long addr; unsigned long addr;
if (!stack) if (!stack)
stack = (unsigned long*) &stack; stack = (unsigned long*) &stack;
printk("Call Trace:\n"); printk("Call Trace: \n");
i = 1;
while (((long) stack & (THREAD_SIZE-1)) != 0) { while (((long) stack & (THREAD_SIZE-1)) != 0) {
addr = *stack++; addr = *stack++;
if (__kernel_text_address(addr)) { if (__kernel_text_address(addr)) {
printk("[<%08lx>] ", addr); printk(" [<%08lx>]", addr);
print_symbol("%s", addr); print_symbol(" %s", addr);
printk("\n"); printk("\n");
i++;
} }
} }
printk("\n");
} }
/* /*
...@@ -48,4 +48,3 @@ void show_stack(struct task_struct *task, unsigned long *sp) ...@@ -48,4 +48,3 @@ void show_stack(struct task_struct *task, unsigned long *sp)
{ {
show_trace(sp); show_trace(sp);
} }
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
# #
extra-y := unmap_fin.o extra-y := unmap_fin.o
clean-files := unmap_tmp.o
obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \ obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \
syscall_kern.o syscall_user.o time.o tlb.o tracer.o trap_user.o \ syscall_kern.o syscall_user.o time.o tlb.o tracer.o trap_user.o \
...@@ -20,10 +21,9 @@ UNMAP_CFLAGS := $(patsubst -fprofile-arcs -ftest-coverage,,$(UNMAP_CFLAGS)) ...@@ -20,10 +21,9 @@ UNMAP_CFLAGS := $(patsubst -fprofile-arcs -ftest-coverage,,$(UNMAP_CFLAGS))
$(USER_OBJS) : %.o: %.c $(USER_OBJS) : %.o: %.c
$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
$(O_TARGET) : $(obj)/unmap_fin.o
$(obj)/unmap.o: $(src)/unmap.c $(obj)/unmap.o: $(src)/unmap.c
$(CC) $(UNMAP_CFLAGS) -c -o $@ $< $(CC) $(UNMAP_CFLAGS) -c -o $@ $<
$(obj)/unmap_fin.o : $(src)/unmap.o $(obj)/unmap_fin.o : $(obj)/unmap.o
ld -r -o $@ $< -lc -L/usr/lib ld -r -o $(obj)/unmap_tmp.o $< -lc -L/usr/lib
objcopy $(obj)/unmap_tmp.o $@ -G switcheroo
/* /*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL * Licensed under the GPL
*/ */
......
/* /*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL * Licensed under the GPL
*/ */
...@@ -15,7 +15,7 @@ extern int tracing_pid; ...@@ -15,7 +15,7 @@ extern int tracing_pid;
extern int tracer(int (*init_proc)(void *), void *sp); extern int tracer(int (*init_proc)(void *), void *sp);
extern void user_time_init_tt(void); extern void user_time_init_tt(void);
extern int copy_sc_from_user_tt(void *to_ptr, void *from_ptr, void *data); extern int copy_sc_from_user_tt(void *to_ptr, void *from_ptr, void *data);
extern int copy_sc_to_user_tt(void *to_ptr, void *fp, void *from_ptr, extern int copy_sc_to_user_tt(void *to_ptr, void *fp, void *from_ptr,
void *data); void *data);
extern void sig_handler_common_tt(int sig, void *sc); extern void sig_handler_common_tt(int sig, void *sc);
extern void syscall_handler_tt(int sig, union uml_pt_regs *regs); extern void syscall_handler_tt(int sig, union uml_pt_regs *regs);
......
/* /*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL * Licensed under the GPL
*/ */
...@@ -13,10 +13,10 @@ ...@@ -13,10 +13,10 @@
extern void *switch_to_tt(void *prev, void *next); extern void *switch_to_tt(void *prev, void *next);
extern void flush_thread_tt(void); extern void flush_thread_tt(void);
extern void start_thread_tt(struct pt_regs *regs, unsigned long eip, extern void start_thread_tt(struct pt_regs *regs, unsigned long eip,
unsigned long esp); unsigned long esp);
extern int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp, extern int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
unsigned long stack_top, struct task_struct *p, unsigned long stack_top, struct task_struct *p,
struct pt_regs *regs); struct pt_regs *regs);
extern void release_thread_tt(struct task_struct *task); extern void release_thread_tt(struct task_struct *task);
extern void exit_thread_tt(void); extern void exit_thread_tt(void);
...@@ -25,13 +25,13 @@ extern void init_idle_tt(void); ...@@ -25,13 +25,13 @@ extern void init_idle_tt(void);
extern void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end); extern void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end);
extern void flush_tlb_kernel_vm_tt(void); extern void flush_tlb_kernel_vm_tt(void);
extern void __flush_tlb_one_tt(unsigned long addr); extern void __flush_tlb_one_tt(unsigned long addr);
extern void flush_tlb_range_tt(struct vm_area_struct *vma, extern void flush_tlb_range_tt(struct vm_area_struct *vma,
unsigned long start, unsigned long end); unsigned long start, unsigned long end);
extern void flush_tlb_mm_tt(struct mm_struct *mm); extern void flush_tlb_mm_tt(struct mm_struct *mm);
extern void force_flush_all_tt(void); extern void force_flush_all_tt(void);
extern long execute_syscall_tt(void *r); extern long execute_syscall_tt(void *r);
extern void before_mem_tt(unsigned long brk_start); extern void before_mem_tt(unsigned long brk_start);
extern unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out, extern unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out,
unsigned long *task_size_out); unsigned long *task_size_out);
extern int start_uml_tt(void); extern int start_uml_tt(void);
extern int external_pid_tt(struct task_struct *task); extern int external_pid_tt(struct task_struct *task);
......
...@@ -24,11 +24,9 @@ extern void set_init_pid(int pid); ...@@ -24,11 +24,9 @@ extern void set_init_pid(int pid);
extern int set_user_mode(void *task); extern int set_user_mode(void *task);
extern void set_tracing(void *t, int tracing); extern void set_tracing(void *t, int tracing);
extern int is_tracing(void *task); extern int is_tracing(void *task);
extern int singlestepping_tt(void *t);
extern void clear_singlestep(void *t);
extern void syscall_handler(int sig, union uml_pt_regs *regs); extern void syscall_handler(int sig, union uml_pt_regs *regs);
extern void exit_kernel(int pid, void *task); extern void exit_kernel(int pid, void *task);
extern int do_syscall(void *task, int pid); extern int do_syscall(void *task, int pid, int local_using_sysemu);
extern int is_valid_pid(int pid); extern int is_valid_pid(int pid);
extern void remap_data(void *segment_start, void *segment_end, int w); extern void remap_data(void *segment_start, void *segment_end, int w);
......
/* /*
* Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL * Licensed under the GPL
*/ */
...@@ -33,7 +33,7 @@ extern unsigned long uml_physmem; ...@@ -33,7 +33,7 @@ extern unsigned long uml_physmem;
(((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \ (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \
(under_task_size(addr, size) || is_stack(addr, size)))) (under_task_size(addr, size) || is_stack(addr, size))))
static inline int verify_area_tt(int type, const void * addr, static inline int verify_area_tt(int type, const void * addr,
unsigned long size) unsigned long size)
{ {
return(access_ok_tt(type, addr, size) ? 0 : -EFAULT); return(access_ok_tt(type, addr, size) ? 0 : -EFAULT);
......
...@@ -82,7 +82,7 @@ void *switch_to_tt(void *prev, void *next, void *last) ...@@ -82,7 +82,7 @@ void *switch_to_tt(void *prev, void *next, void *last)
prev_sched = current->thread.prev_sched; prev_sched = current->thread.prev_sched;
if((prev_sched->exit_state == EXIT_ZOMBIE) || if((prev_sched->exit_state == EXIT_ZOMBIE) ||
(prev_sched->exit_state == EXIT_DEAD)) (prev_sched->exit_state == EXIT_DEAD))
os_kill_process(prev_sched->thread.mode.tt.extern_pid, 1); os_kill_ptraced_process(prev_sched->thread.mode.tt.extern_pid, 1);
/* This works around a nasty race with 'jail'. If we are switching /* This works around a nasty race with 'jail'. If we are switching
* between two threads of a threaded app and the incoming process * between two threads of a threaded app and the incoming process
...@@ -523,22 +523,6 @@ void set_init_pid(int pid) ...@@ -523,22 +523,6 @@ void set_init_pid(int pid)
-err); -err);
} }
int singlestepping_tt(void *t)
{
struct task_struct *task = t;
if(task->thread.mode.tt.singlestep_syscall)
return(0);
return(task->ptrace & PT_DTRACE);
}
void clear_singlestep(void *t)
{
struct task_struct *task = t;
task->ptrace &= ~PT_DTRACE;
}
int start_uml_tt(void) int start_uml_tt(void)
{ {
void *sp; void *sp;
......
...@@ -123,12 +123,6 @@ long execute_syscall_tt(void *r) ...@@ -123,12 +123,6 @@ long execute_syscall_tt(void *r)
set_fs(USER_DS); set_fs(USER_DS);
if(current->thread.mode.tt.singlestep_syscall){
current->thread.mode.tt.singlestep_syscall = 0;
current->ptrace &= ~PT_DTRACE;
force_sig(SIGTRAP, current);
}
return(res); return(res);
} }
......
...@@ -33,7 +33,7 @@ void syscall_handler_tt(int sig, union uml_pt_regs *regs) ...@@ -33,7 +33,7 @@ void syscall_handler_tt(int sig, union uml_pt_regs *regs)
SC_START_SYSCALL(sc); SC_START_SYSCALL(sc);
index = record_syscall_start(syscall); index = record_syscall_start(syscall);
syscall_trace(regs, 1); syscall_trace(regs, 0);
result = execute_syscall(regs); result = execute_syscall(regs);
/* regs->sc may have changed while the system call ran (there may /* regs->sc may have changed while the system call ran (there may
...@@ -46,11 +46,11 @@ void syscall_handler_tt(int sig, union uml_pt_regs *regs) ...@@ -46,11 +46,11 @@ void syscall_handler_tt(int sig, union uml_pt_regs *regs)
(result == -ERESTARTNOINTR)) (result == -ERESTARTNOINTR))
do_signal(result); do_signal(result);
syscall_trace(regs, 0); syscall_trace(regs, 1);
record_syscall_end(index, result); record_syscall_end(index, result);
} }
int do_syscall(void *task, int pid) int do_syscall(void *task, int pid, int local_using_sysemu)
{ {
unsigned long proc_regs[FRAME_SIZE]; unsigned long proc_regs[FRAME_SIZE];
union uml_pt_regs *regs; union uml_pt_regs *regs;
...@@ -70,6 +70,9 @@ int do_syscall(void *task, int pid) ...@@ -70,6 +70,9 @@ int do_syscall(void *task, int pid)
((unsigned long *) PT_IP(proc_regs) <= &_etext)) ((unsigned long *) PT_IP(proc_regs) <= &_etext))
tracer_panic("I'm tracing myself and I can't get out"); tracer_panic("I'm tracing myself and I can't get out");
if(local_using_sysemu)
return(1);
if(ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, if(ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
__NR_getpid) < 0) __NR_getpid) < 0)
tracer_panic("do_syscall : Nullifying syscall failed, " tracer_panic("do_syscall : Nullifying syscall failed, "
......
...@@ -184,6 +184,7 @@ int tracer(int (*init_proc)(void *), void *sp) ...@@ -184,6 +184,7 @@ int tracer(int (*init_proc)(void *), void *sp)
unsigned long eip = 0; unsigned long eip = 0;
int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0; int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0;
int last_index, proc_id = 0, n, err, old_tracing = 0, strace = 0; int last_index, proc_id = 0, n, err, old_tracing = 0, strace = 0;
int pt_syscall_parm, local_using_sysemu;
capture_signal_stack(); capture_signal_stack();
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
...@@ -297,6 +298,9 @@ int tracer(int (*init_proc)(void *), void *sp) ...@@ -297,6 +298,9 @@ int tracer(int (*init_proc)(void *), void *sp)
tracing = is_tracing(task); tracing = is_tracing(task);
old_tracing = tracing; old_tracing = tracing;
local_using_sysemu = get_using_sysemu();
pt_syscall_parm = local_using_sysemu ? PTRACE_SYSEMU : PTRACE_SYSCALL;
switch(sig){ switch(sig){
case SIGUSR1: case SIGUSR1:
sig = 0; sig = 0;
...@@ -330,9 +334,8 @@ int tracer(int (*init_proc)(void *), void *sp) ...@@ -330,9 +334,8 @@ int tracer(int (*init_proc)(void *), void *sp)
continue; continue;
} }
tracing = 0; tracing = 0;
if(do_syscall(task, pid)) if(do_syscall(task, pid, local_using_sysemu))
sig = SIGUSR2; sig = SIGUSR2;
else clear_singlestep(task);
break; break;
case SIGPROF: case SIGPROF:
if(tracing) sig = 0; if(tracing) sig = 0;
...@@ -349,6 +352,7 @@ int tracer(int (*init_proc)(void *), void *sp) ...@@ -349,6 +352,7 @@ int tracer(int (*init_proc)(void *), void *sp)
case SIGBUS: case SIGBUS:
case SIGILL: case SIGILL:
case SIGWINCH: case SIGWINCH:
default: default:
tracing = 0; tracing = 0;
break; break;
...@@ -368,9 +372,9 @@ int tracer(int (*init_proc)(void *), void *sp) ...@@ -368,9 +372,9 @@ int tracer(int (*init_proc)(void *), void *sp)
} }
if(tracing){ if(tracing){
if(singlestepping_tt(task)) if(singlestepping(task))
cont_type = PTRACE_SINGLESTEP; cont_type = PTRACE_SINGLESTEP;
else cont_type = PTRACE_SYSCALL; else cont_type = pt_syscall_parm;
} }
else cont_type = PTRACE_CONT; else cont_type = PTRACE_CONT;
......
...@@ -23,6 +23,13 @@ void sig_handler_common_tt(int sig, void *sc_ptr) ...@@ -23,6 +23,13 @@ void sig_handler_common_tt(int sig, void *sc_ptr)
unprotect_kernel_mem(); unprotect_kernel_mem();
/* This is done because to allow SIGSEGV to be delivered inside a SEGV
* handler. This can happen in copy_user, and if SEGV is disabled,
* the process will die.
*/
if(sig == SIGSEGV)
change_sig(SIGSEGV, 1);
/* This is done because to allow SIGSEGV to be delivered inside a SEGV /* This is done because to allow SIGSEGV to be delivered inside a SEGV
* handler. This can happen in copy_user, and if SEGV is disabled, * handler. This can happen in copy_user, and if SEGV is disabled,
* the process will die. * the process will die.
......
...@@ -205,6 +205,8 @@ static int __init set_tty_log_fd(char *name, int *add) ...@@ -205,6 +205,8 @@ static int __init set_tty_log_fd(char *name, int *add)
printf("set_tty_log_fd - strtoul failed on '%s'\n", name); printf("set_tty_log_fd - strtoul failed on '%s'\n", name);
tty_log_fd = -1; tty_log_fd = -1;
} }
*add = 0;
return 0; return 0;
} }
......
...@@ -321,6 +321,11 @@ int linux_main(int argc, char **argv) ...@@ -321,6 +321,11 @@ int linux_main(int argc, char **argv)
uml_start = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, 0, uml_start = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, 0,
&host_task_size, &task_size); &host_task_size, &task_size);
/* Need to check this early because mmapping happens before the
* kernel is running.
*/
check_tmpexec();
brk_start = (unsigned long) sbrk(0); brk_start = (unsigned long) sbrk(0);
CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start); CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start);
/* Increase physical memory size for exec-shield users /* Increase physical memory size for exec-shield users
...@@ -400,9 +405,9 @@ extern int uml_exitcode; ...@@ -400,9 +405,9 @@ extern int uml_exitcode;
static int panic_exit(struct notifier_block *self, unsigned long unused1, static int panic_exit(struct notifier_block *self, unsigned long unused1,
void *unused2) void *unused2)
{ {
#ifdef CONFIG_MAGIC_SYSRQ bust_spinlocks(1);
handle_sysrq('p', &current->thread.regs, NULL); show_regs(&(current->thread.regs));
#endif bust_spinlocks(0);
uml_exitcode = 1; uml_exitcode = 1;
machine_halt(); machine_halt();
return(0); return(0);
......
...@@ -54,6 +54,7 @@ static int __init set_umid(char *name, int is_random, ...@@ -54,6 +54,7 @@ static int __init set_umid(char *name, int is_random,
static int __init set_umid_arg(char *name, int *add) static int __init set_umid_arg(char *name, int *add)
{ {
*add = 0;
return(set_umid(name, 0, printf)); return(set_umid(name, 0, printf));
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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