Commit 88c3cdfd authored by Tony Luck's avatar Tony Luck

Auto merge with /home/aegl/GIT/linus

parents 2b2c3750 a92b7b80
...@@ -13,14 +13,17 @@ different way: With the help of a dvb-usb-framework. ...@@ -13,14 +13,17 @@ different way: With the help of a dvb-usb-framework.
The framework provides generic functions (mostly kernel API calls), such as: The framework provides generic functions (mostly kernel API calls), such as:
- Transport Stream URB handling in conjunction with dvb-demux-feed-control - Transport Stream URB handling in conjunction with dvb-demux-feed-control
(bulk and isoc (TODO) are supported) (bulk and isoc are supported)
- registering the device for the DVB-API - registering the device for the DVB-API
- registering an I2C-adapter if applicable - registering an I2C-adapter if applicable
- remote-control/input-device handling - remote-control/input-device handling
- firmware requesting and loading (currently just for the Cypress USB - firmware requesting and loading (currently just for the Cypress USB
controller) controllers)
- other functions/methods which can be shared by several drivers (such as - other functions/methods which can be shared by several drivers (such as
functions for bulk-control-commands) functions for bulk-control-commands)
- TODO: a I2C-chunker. It creates device-specific chunks of register-accesses
depending on length of a register and the number of values that can be
multi-written and multi-read.
The source code of the particular DVB USB devices does just the communication The source code of the particular DVB USB devices does just the communication
with the device via the bus. The connection between the DVB-API-functionality with the device via the bus. The connection between the DVB-API-functionality
...@@ -36,93 +39,18 @@ the dvb-usb-lib. ...@@ -36,93 +39,18 @@ the dvb-usb-lib.
TODO: dynamic enabling and disabling of the pid-filter in regard to number of TODO: dynamic enabling and disabling of the pid-filter in regard to number of
feeds requested. feeds requested.
Supported devices USB1.1 Supported devices
======================== ========================
Produced and reselled by Twinhan: See the LinuxTV DVB Wiki at www.linuxtv.org for a complete list of
--------------------------------- cards/drivers/firmwares:
- TwinhanDTV USB-Ter DVB-T Device (VP7041)
http://www.twinhan.com/product_terrestrial_3.asp
- TwinhanDTV Magic Box (VP7041e) http://www.linuxtv.org/wiki/index.php/DVB_USB
http://www.twinhan.com/product_terrestrial_4.asp
- HAMA DVB-T USB device
http://www.hama.de/portal/articleId*110620/action*2598
- CTS Portable (Chinese Television System) (2)
http://www.2cts.tv/ctsportable/
- Unknown USB DVB-T device with vendor ID Hyper-Paltek
Produced and reselled by KWorld:
--------------------------------
- KWorld V-Stream XPERT DTV DVB-T USB
http://www.kworld.com.tw/en/product/DVBT-USB/DVBT-USB.html
- JetWay DTV DVB-T USB
http://www.jetway.com.tw/evisn/product/lcd-tv/DVT-USB/dtv-usb.htm
- ADSTech Instant TV DVB-T USB
http://www.adstech.com/products/PTV-333/intro/PTV-333_intro.asp?pid=PTV-333
Others:
-------
- Ultima Electronic/Artec T1 USB TVBOX (AN2135, AN2235, AN2235 with Panasonic Tuner)
http://82.161.246.249/products-tvbox.html
- Compro Videomate DVB-U2000 - DVB-T USB (2)
http://www.comprousa.com/products/vmu2000.htm
- Grandtec USB DVB-T
http://www.grand.com.tw/
- AVerMedia AverTV DVBT USB
http://www.avermedia.com/
- DiBcom USB DVB-T reference device (non-public)
Supported devices USB2.0-only
=============================
- Twinhan MagicBox II
http://www.twinhan.com/product_terrestrial_7.asp
- TwinhanDTV Alpha
http://www.twinhan.com/product_terrestrial_8.asp
- DigitalNow TinyUSB 2 DVB-t Receiver
http://www.digitalnow.com.au/DigitalNow%20tinyUSB2%20Specifications.html
- Hanftek UMT-010
http://www.globalsources.com/si/6008819757082/ProductDetail/Digital-TV/product_id-100046529
Supported devices USB2.0 and USB1.1
=============================
- Typhoon/Yakumo/HAMA/Yuan DVB-T mobile USB2.0
http://www.yakumo.de/produkte/index.php?pid=1&ag=DVB-T
http://www.yuan.com.tw/en/products/vdo_ub300.html
http://www.hama.de/portal/articleId*114663/action*2563
http://www.anubisline.com/english/articlec.asp?id=50502&catid=002
- Artec T1 USB TVBOX (FX2) (2)
- Hauppauge WinTV NOVA-T USB2
http://www.hauppauge.com/
- KWorld/ADSTech Instant DVB-T USB2.0 (DiB3000M-B)
- DiBcom USB2.0 DVB-T reference device (non-public)
- AVerMedia AverTV A800 DVB-T USB2.0
1) It is working almost - work-in-progress.
2) No test reports received yet.
0. History & News: 0. History & News:
2005-06-30 - added support for WideView WT-220U (Thanks to Steve Chang)
2005-05-30 - added basic isochronous support to the dvb-usb-framework
added support for Conexant Hybrid reference design and Nebula DigiTV USB
2005-04-17 - all dibusb devices ported to make use of the dvb-usb-framework 2005-04-17 - all dibusb devices ported to make use of the dvb-usb-framework
2005-04-02 - re-enabled and improved remote control code. 2005-04-02 - re-enabled and improved remote control code.
2005-03-31 - ported the Yakumo/Hama/Typhoon DVB-T USB2.0 device to dvb-usb. 2005-03-31 - ported the Yakumo/Hama/Typhoon DVB-T USB2.0 device to dvb-usb.
...@@ -137,7 +65,7 @@ Supported devices USB2.0 and USB1.1 ...@@ -137,7 +65,7 @@ Supported devices USB2.0 and USB1.1
2005-01-31 - distorted streaming is gone for USB1.1 devices 2005-01-31 - distorted streaming is gone for USB1.1 devices
2005-01-13 - moved the mirrored pid_filter_table back to dvb-dibusb 2005-01-13 - moved the mirrored pid_filter_table back to dvb-dibusb
- first almost working version for HanfTek UMT-010 - first almost working version for HanfTek UMT-010
- found out, that Yakumo/HAMA/Typhoon are predessors of the HanfTek UMT-010 - found out, that Yakumo/HAMA/Typhoon are predecessors of the HanfTek UMT-010
2005-01-10 - refactoring completed, now everything is very delightful 2005-01-10 - refactoring completed, now everything is very delightful
- tuner quirks for some weird devices (Artec T1 AN2235 device has sometimes a - tuner quirks for some weird devices (Artec T1 AN2235 device has sometimes a
Panasonic Tuner assembled). Tunerprobing implemented. Thanks a lot to Gunnar Wittich. Panasonic Tuner assembled). Tunerprobing implemented. Thanks a lot to Gunnar Wittich.
...@@ -187,25 +115,13 @@ Supported devices USB2.0 and USB1.1 ...@@ -187,25 +115,13 @@ Supported devices USB2.0 and USB1.1
1. How to use? 1. How to use?
1.1. Firmware 1.1. Firmware
Most of the USB drivers need to download a firmware to start working. Most of the USB drivers need to download a firmware to the device before start
working.
for USB1.1 (AN2135) you need: dvb-usb-dibusb-5.0.0.11.fw
for USB2.0 HanfTek: dvb-usb-umt-010-02.fw
for USB2.0 DiBcom: dvb-usb-dibusb-6.0.0.8.fw
for USB2.0 AVerMedia AverTV DVB-T USB2: dvb-usb-avertv-a800-01.fw
for USB2.0 TwinhanDTV Alpha/MagicBox II: dvb-usb-vp7045-01.fw
The files can be found on http://www.linuxtv.org/download/firmware/ .
We do not have the permission (yet) to publish the following firmware-files. Have a look at the Wikipage for the DVB-USB-drivers to find out, which firmware
You'll need to extract them from the windows drivers. you need for your device:
You should be able to use "get_dvb_firmware dvb-usb" to get the firmware: http://www.linuxtv.org/wiki/index.php/DVB_USB
for USB1.1 (AN2235) (a few Artec T1 devices): dvb-usb-dibusb-an2235-01.fw
for USB2.0 Hauppauge: dvb-usb-nova-t-usb2-01.fw
for USB2.0 ADSTech/Kworld USB2.0: dvb-usb-adstech-usb2-01.fw
for USB2.0 Yakumo/Typhoon/Hama: dvb-usb-dtt200u-01.fw
1.2. Compiling 1.2. Compiling
...@@ -289,6 +205,9 @@ Patches, comments and suggestions are very very welcome. ...@@ -289,6 +205,9 @@ Patches, comments and suggestions are very very welcome.
Gunnar Wittich and Joachim von Caron for their trust for providing Gunnar Wittich and Joachim von Caron for their trust for providing
root-shells on their machines to implement support for new devices. root-shells on their machines to implement support for new devices.
Allan Third and Michael Hutchinson for their help to write the Nebula
digitv-driver.
Glen Harris for bringing up, that there is a new dibusb-device and Jiun-Kuei Glen Harris for bringing up, that there is a new dibusb-device and Jiun-Kuei
Jung from AVerMedia who kindly provided a special firmware to get the device Jung from AVerMedia who kindly provided a special firmware to get the device
up and running in Linux. up and running in Linux.
...@@ -296,7 +215,12 @@ Patches, comments and suggestions are very very welcome. ...@@ -296,7 +215,12 @@ Patches, comments and suggestions are very very welcome.
Jennifer Chen, Jeff and Jack from Twinhan for kindly supporting by Jennifer Chen, Jeff and Jack from Twinhan for kindly supporting by
writing the vp7045-driver. writing the vp7045-driver.
Some guys on the linux-dvb mailing list for encouraging me Steve Chang from WideView for providing information for new devices and
firmware files.
Michael Paxton for submitting remote control keymaps.
Some guys on the linux-dvb mailing list for encouraging me.
Peter Schildmann >peter.schildmann-nospam-at-web.de< for his Peter Schildmann >peter.schildmann-nospam-at-web.de< for his
user-level firmware loader, which saves a lot of time user-level firmware loader, which saves a lot of time
...@@ -305,4 +229,4 @@ Patches, comments and suggestions are very very welcome. ...@@ -305,4 +229,4 @@ Patches, comments and suggestions are very very welcome.
Ulf Hermenau for helping me out with traditional chinese. Ulf Hermenau for helping me out with traditional chinese.
André Smoktun and Christian Frömmel for supporting me with André Smoktun and Christian Frömmel for supporting me with
hardware and listening to my problems very patient. hardware and listening to my problems very patiently.
How to get the Nebula, PCTV and Twinhan DST cards working How to get the Nebula Electronics DigiTV, Pinnacle PCTV Sat, Twinhan DST + clones working
========================================================= =========================================================================================
This class of cards has a bt878a as the PCI interface, and 1) General information
require the bttv driver. ======================
Please pay close attention to the warning about the bttv module This class of cards has a bt878a chip as the PCI interface.
options below for the DST card. The different card drivers require the bttv driver to provide the means
to access the i2c bus and the gpio pins of the bt8xx chipset.
1) General informations 2) Compilation rules for Kernel >= 2.6.12
======================= =========================================
These drivers require the bttv driver to provide the means to access Enable the following options:
the i2c bus and the gpio pins of the bt8xx chipset.
Because of this, you need to enable
"Device drivers" => "Multimedia devices" "Device drivers" => "Multimedia devices"
=> "Video For Linux" => "BT848 Video For Linux" => "Video For Linux" => "BT848 Video For Linux"
Furthermore you need to enable
"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices" "Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
=> "DVB for Linux" "DVB Core Support" "Nebula/Pinnacle PCTV/TwinHan PCI Cards" => "DVB for Linux" "DVB Core Support" "Nebula/Pinnacle PCTV/TwinHan PCI Cards"
2) Loading Modules 3) Loading Modules, described by two approaches
================== ===============================================
In general you need to load the bttv driver, which will handle the gpio and In general you need to load the bttv driver, which will handle the gpio and
i2c communication for us, plus the common dvb-bt8xx device driver. i2c communication for us, plus the common dvb-bt8xx device driver,
The frontends for Nebula (nxt6000), Pinnacle PCTV (cx24110) and which is called the backend.
TwinHan (dst) are loaded automatically by the dvb-bt8xx device driver. The frontends for Nebula DigiTV (nxt6000), Pinnacle PCTV Sat (cx24110),
TwinHan DST + clones (dst and dst-ca) are loaded automatically by the backend.
For further details about TwinHan DST + clones see /Documentation/dvb/ci.txt.
3a) Nebula / Pinnacle PCTV 3a) The manual approach
-------------------------- -----------------------
$ modprobe bttv (normally bttv is being loaded automatically by kmod) Loading modules:
$ modprobe dvb-bt8xx (or just place dvb-bt8xx in /etc/modules for automatic loading) modprobe bttv
modprobe dvb-bt8xx
Unloading modules:
modprobe -r dvb-bt8xx
modprobe -r bttv
3b) TwinHan and Clones 3b) The automatic approach
-------------------------- --------------------------
$ modprobe bttv i2c_hw=1 card=0x71 If not already done by installation, place a line either in
$ modprobe dvb-bt8xx /etc/modules.conf or in /etc/modprobe.conf containing this text:
$ modprobe dst alias char-major-81 bttv
The value 0x71 will override the PCI type detection for dvb-bt8xx,
which is necessary for TwinHan cards.
If you're having an older card (blue color circuit) and card=0x71 locks
your machine, try using 0x68, too. If that does not work, ask on the
mailing list.
The DST module takes a couple of useful parameters:
a. verbose takes values 0 to 5. These values control the verbosity level. Then place a line in /etc/modules containing this text:
b. debug takes values 0 and 1. You can either disable or enable debugging. dvb-bt8xx
c. dst_addons takes values 0 and 0x20:
- A value of 0 means it is a FTA card.
- A value of 0x20 means it has a Conditional Access slot.
The autodetected values are determined by the "response string" Reboot your system and have fun!
of the card, which you can see in your logs:
e.g.: dst_get_device_id: Recognize [DSTMCI]
-- --
Authors: Richard Walker, Jamie Honan, Michael Hunold, Manu Abraham, Uwe Bugla Authors: Richard Walker, Jamie Honan, Michael Hunold, Manu Abraham, Uwe Bugla
...@@ -119,3 +119,19 @@ Why: Match the other drivers' name for the same function, duplicate names ...@@ -119,3 +119,19 @@ Why: Match the other drivers' name for the same function, duplicate names
will be available until removal of old names. will be available until removal of old names.
Who: Grant Coady <gcoady@gmail.com> Who: Grant Coady <gcoady@gmail.com>
---------------------------
What: PCMCIA control ioctl (needed for pcmcia-cs [cardmgr, cardctl])
When: November 2005
Files: drivers/pcmcia/: pcmcia_ioctl.c
Why: With the 16-bit PCMCIA subsystem now behaving (almost) like a
normal hotpluggable bus, and with it using the default kernel
infrastructure (hotplug, driver core, sysfs) keeping the PCMCIA
control ioctl needed by cardmgr and cardctl from pcmcia-cs is
unnecessary, and makes further cleanups and integration of the
PCMCIA subsystem into the Linux kernel device driver model more
difficult. The features provided by cardmgr and cardctl are either
handled by the kernel itself now or are available in the new
pcmciautils package available at
http://kernel.org/pub/linux/utils/kernel/pcmcia/
Who: Dominik Brodowski <linux@brodo.de>
USERSPACE VERBS ACCESS
The ib_uverbs module, built by enabling CONFIG_INFINIBAND_USER_VERBS,
enables direct userspace access to IB hardware via "verbs," as
described in chapter 11 of the InfiniBand Architecture Specification.
To use the verbs, the libibverbs library, available from
<http://openib.org/>, is required. libibverbs contains a
device-independent API for using the ib_uverbs interface.
libibverbs also requires appropriate device-dependent kernel and
userspace driver for your InfiniBand hardware. For example, to use
a Mellanox HCA, you will need the ib_mthca kernel module and the
libmthca userspace driver be installed.
User-kernel communication
Userspace communicates with the kernel for slow path, resource
management operations via the /dev/infiniband/uverbsN character
devices. Fast path operations are typically performed by writing
directly to hardware registers mmap()ed into userspace, with no
system call or context switch into the kernel.
Commands are sent to the kernel via write()s on these device files.
The ABI is defined in drivers/infiniband/include/ib_user_verbs.h.
The structs for commands that require a response from the kernel
contain a 64-bit field used to pass a pointer to an output buffer.
Status is returned to userspace as the return value of the write()
system call.
Resource management
Since creation and destruction of all IB resources is done by
commands passed through a file descriptor, the kernel can keep track
of which resources are attached to a given userspace context. The
ib_uverbs module maintains idr tables that are used to translate
between kernel pointers and opaque userspace handles, so that kernel
pointers are never exposed to userspace and userspace cannot trick
the kernel into following a bogus pointer.
This also allows the kernel to clean up when a process exits and
prevent one process from touching another process's resources.
Memory pinning
Direct userspace I/O requires that memory regions that are potential
I/O targets be kept resident at the same physical address. The
ib_uverbs module manages pinning and unpinning memory regions via
get_user_pages() and put_page() calls. It also accounts for the
amount of memory pinned in the process's locked_vm, and checks that
unprivileged processes do not exceed their RLIMIT_MEMLOCK limit.
Pages that are pinned multiple times are counted each time they are
pinned, so the value of locked_vm may be an overestimate of the
number of pages pinned by a process.
/dev files
To create the appropriate character device files automatically with
udev, a rule like
KERNEL="uverbs*", NAME="infiniband/%k"
can be used. This will create device nodes named
/dev/infiniband/uverbs0
and so on. Since the InfiniBand userspace verbs should be safe for
use by non-privileged processes, it may be useful to add an
appropriate MODE or GROUP to the udev rule.
...@@ -117,6 +117,7 @@ IBM Thinkpad X40 Type 2371-7JG s3_bios,s3_mode (4) ...@@ -117,6 +117,7 @@ IBM Thinkpad X40 Type 2371-7JG s3_bios,s3_mode (4)
Medion MD4220 ??? (*) Medion MD4220 ??? (*)
Samsung P35 vbetool needed (6) Samsung P35 vbetool needed (6)
Sharp PC-AR10 (ATI rage) none (1) Sharp PC-AR10 (ATI rage) none (1)
Sony Vaio PCG-C1VRX/K s3_bios (2)
Sony Vaio PCG-F403 ??? (*) Sony Vaio PCG-F403 ??? (*)
Sony Vaio PCG-N505SN ??? (*) Sony Vaio PCG-N505SN ??? (*)
Sony Vaio vgn-s260 X or boot-radeon can init it (5) Sony Vaio vgn-s260 X or boot-radeon can init it (5)
......
...@@ -370,6 +370,10 @@ W: http://www.thekelleys.org.uk/atmel ...@@ -370,6 +370,10 @@ W: http://www.thekelleys.org.uk/atmel
W: http://atmelwlandriver.sourceforge.net/ W: http://atmelwlandriver.sourceforge.net/
S: Maintained S: Maintained
AUDIT SUBSYSTEM
L: linux-audit@redhat.com (subscribers-only)
S: Maintained
AX.25 NETWORK LAYER AX.25 NETWORK LAYER
P: Ralf Baechle P: Ralf Baechle
M: ralf@linux-mips.org M: ralf@linux-mips.org
...@@ -1803,8 +1807,9 @@ M: greg@kroah.com ...@@ -1803,8 +1807,9 @@ M: greg@kroah.com
S: Maintained S: Maintained
PCMCIA SUBSYSTEM PCMCIA SUBSYSTEM
P: Linux PCMCIA Team
L: http://lists.infradead.org/mailman/listinfo/linux-pcmcia L: http://lists.infradead.org/mailman/listinfo/linux-pcmcia
S: Unmaintained S: Maintained
PCNET32 NETWORK DRIVER PCNET32 NETWORK DRIVER
P: Thomas Bogendrfer P: Thomas Bogendrfer
......
...@@ -792,6 +792,9 @@ export CPPFLAGS_vmlinux.lds += -P -C -U$(ARCH) ...@@ -792,6 +792,9 @@ export CPPFLAGS_vmlinux.lds += -P -C -U$(ARCH)
$(Q)$(MAKE) $(build)=$(@D) $@ $(Q)$(MAKE) $(build)=$(@D) $@
%.o: %.c scripts FORCE %.o: %.c scripts FORCE
$(Q)$(MAKE) $(build)=$(@D) $@ $(Q)$(MAKE) $(build)=$(@D) $@
%.ko: scripts FORCE
$(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) $(build)=$(@D) $(@:.ko=.o)
$(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modpost
%/: scripts prepare FORCE %/: scripts prepare FORCE
$(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) $(build)=$(@D) $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) $(build)=$(@D)
%.lst: %.c scripts FORCE %.lst: %.c scripts FORCE
...@@ -1033,6 +1036,7 @@ help: ...@@ -1033,6 +1036,7 @@ help:
@echo ' modules_install - Install all modules' @echo ' modules_install - Install all modules'
@echo ' dir/ - Build all files in dir and below' @echo ' dir/ - Build all files in dir and below'
@echo ' dir/file.[ois] - Build specified target only' @echo ' dir/file.[ois] - Build specified target only'
@echo ' dir/file.ko - Build module including final link'
@echo ' rpm - Build a kernel as an RPM package' @echo ' rpm - Build a kernel as an RPM package'
@echo ' tags/TAGS - Generate tags file for editors' @echo ' tags/TAGS - Generate tags file for editors'
@echo ' cscope - Generate cscope index' @echo ' cscope - Generate cscope index'
...@@ -1149,7 +1153,7 @@ endif # KBUILD_EXTMOD ...@@ -1149,7 +1153,7 @@ endif # KBUILD_EXTMOD
#(which is the most common case IMHO) to avoid unneeded clutter in the big tags file. #(which is the most common case IMHO) to avoid unneeded clutter in the big tags file.
#Adding $(srctree) adds about 20M on i386 to the size of the output file! #Adding $(srctree) adds about 20M on i386 to the size of the output file!
ifeq ($(KBUILD_OUTPUT),) ifeq ($(src),$(obj))
__srctree = __srctree =
else else
__srctree = $(srctree)/ __srctree = $(srctree)/
......
This diff is collapsed.
...@@ -435,6 +435,11 @@ void __devinit identify_cpu(struct cpuinfo_x86 *c) ...@@ -435,6 +435,11 @@ void __devinit identify_cpu(struct cpuinfo_x86 *c)
if (c == &boot_cpu_data) if (c == &boot_cpu_data)
sysenter_setup(); sysenter_setup();
enable_sep_cpu(); enable_sep_cpu();
if (c == &boot_cpu_data)
mtrr_bp_init();
else
mtrr_ap_init();
} }
#ifdef CONFIG_X86_HT #ifdef CONFIG_X86_HT
......
...@@ -25,7 +25,7 @@ extern int trap_init_f00f_bug(void); ...@@ -25,7 +25,7 @@ extern int trap_init_f00f_bug(void);
/* /*
* Alignment at which movsl is preferred for bulk memory copies. * Alignment at which movsl is preferred for bulk memory copies.
*/ */
struct movsl_mask movsl_mask; struct movsl_mask movsl_mask __read_mostly;
#endif #endif
void __devinit early_intel_workaround(struct cpuinfo_x86 *c) void __devinit early_intel_workaround(struct cpuinfo_x86 *c)
......
...@@ -67,13 +67,6 @@ void __init get_mtrr_state(void) ...@@ -67,13 +67,6 @@ void __init get_mtrr_state(void)
mtrr_state.enabled = (lo & 0xc00) >> 10; mtrr_state.enabled = (lo & 0xc00) >> 10;
} }
/* Free resources associated with a struct mtrr_state */
void __init finalize_mtrr_state(void)
{
kfree(mtrr_state.var_ranges);
mtrr_state.var_ranges = NULL;
}
/* Some BIOS's are fucked and don't set all MTRRs the same! */ /* Some BIOS's are fucked and don't set all MTRRs the same! */
void __init mtrr_state_warn(void) void __init mtrr_state_warn(void)
{ {
...@@ -334,6 +327,9 @@ static void generic_set_mtrr(unsigned int reg, unsigned long base, ...@@ -334,6 +327,9 @@ static void generic_set_mtrr(unsigned int reg, unsigned long base,
*/ */
{ {
unsigned long flags; unsigned long flags;
struct mtrr_var_range *vr;
vr = &mtrr_state.var_ranges[reg];
local_irq_save(flags); local_irq_save(flags);
prepare_set(); prepare_set();
...@@ -342,11 +338,15 @@ static void generic_set_mtrr(unsigned int reg, unsigned long base, ...@@ -342,11 +338,15 @@ static void generic_set_mtrr(unsigned int reg, unsigned long base,
/* The invalid bit is kept in the mask, so we simply clear the /* The invalid bit is kept in the mask, so we simply clear the
relevant mask register to disable a range. */ relevant mask register to disable a range. */
mtrr_wrmsr(MTRRphysMask_MSR(reg), 0, 0); mtrr_wrmsr(MTRRphysMask_MSR(reg), 0, 0);
memset(vr, 0, sizeof(struct mtrr_var_range));
} else { } else {
mtrr_wrmsr(MTRRphysBase_MSR(reg), base << PAGE_SHIFT | type, vr->base_lo = base << PAGE_SHIFT | type;
(base & size_and_mask) >> (32 - PAGE_SHIFT)); vr->base_hi = (base & size_and_mask) >> (32 - PAGE_SHIFT);
mtrr_wrmsr(MTRRphysMask_MSR(reg), -size << PAGE_SHIFT | 0x800, vr->mask_lo = -size << PAGE_SHIFT | 0x800;
(-size & size_and_mask) >> (32 - PAGE_SHIFT)); vr->mask_hi = (-size & size_and_mask) >> (32 - PAGE_SHIFT);
mtrr_wrmsr(MTRRphysBase_MSR(reg), vr->base_lo, vr->base_hi);
mtrr_wrmsr(MTRRphysMask_MSR(reg), vr->mask_lo, vr->mask_hi);
} }
post_set(); post_set();
......
...@@ -332,6 +332,8 @@ int mtrr_add_page(unsigned long base, unsigned long size, ...@@ -332,6 +332,8 @@ int mtrr_add_page(unsigned long base, unsigned long size,
error = -EINVAL; error = -EINVAL;
/* No CPU hotplug when we change MTRR entries */
lock_cpu_hotplug();
/* Search for existing MTRR */ /* Search for existing MTRR */
down(&main_lock); down(&main_lock);
for (i = 0; i < num_var_ranges; ++i) { for (i = 0; i < num_var_ranges; ++i) {
...@@ -372,6 +374,7 @@ int mtrr_add_page(unsigned long base, unsigned long size, ...@@ -372,6 +374,7 @@ int mtrr_add_page(unsigned long base, unsigned long size,
error = i; error = i;
out: out:
up(&main_lock); up(&main_lock);
unlock_cpu_hotplug();
return error; return error;
} }
...@@ -461,6 +464,8 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size) ...@@ -461,6 +464,8 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
return -ENXIO; return -ENXIO;
max = num_var_ranges; max = num_var_ranges;
/* No CPU hotplug when we change MTRR entries */
lock_cpu_hotplug();
down(&main_lock); down(&main_lock);
if (reg < 0) { if (reg < 0) {
/* Search for existing MTRR */ /* Search for existing MTRR */
...@@ -501,6 +506,7 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size) ...@@ -501,6 +506,7 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
error = reg; error = reg;
out: out:
up(&main_lock); up(&main_lock);
unlock_cpu_hotplug();
return error; return error;
} }
/** /**
...@@ -544,21 +550,9 @@ static void __init init_ifs(void) ...@@ -544,21 +550,9 @@ static void __init init_ifs(void)
centaur_init_mtrr(); centaur_init_mtrr();
} }
static void __init init_other_cpus(void) /* The suspend/resume methods are only for CPU without MTRR. CPU using generic
{ * MTRR driver doesn't require this
if (use_intel()) */
get_mtrr_state();
/* bring up the other processors */
set_mtrr(~0U,0,0,0);
if (use_intel()) {
finalize_mtrr_state();
mtrr_state_warn();
}
}
struct mtrr_value { struct mtrr_value {
mtrr_type ltype; mtrr_type ltype;
unsigned long lbase; unsigned long lbase;
...@@ -611,13 +605,13 @@ static struct sysdev_driver mtrr_sysdev_driver = { ...@@ -611,13 +605,13 @@ static struct sysdev_driver mtrr_sysdev_driver = {
/** /**
* mtrr_init - initialize mtrrs on the boot CPU * mtrr_bp_init - initialize mtrrs on the boot CPU
* *
* This needs to be called early; before any of the other CPUs are * This needs to be called early; before any of the other CPUs are
* initialized (i.e. before smp_init()). * initialized (i.e. before smp_init()).
* *
*/ */
static int __init mtrr_init(void) void __init mtrr_bp_init(void)
{ {
init_ifs(); init_ifs();
...@@ -674,12 +668,48 @@ static int __init mtrr_init(void) ...@@ -674,12 +668,48 @@ static int __init mtrr_init(void)
if (mtrr_if) { if (mtrr_if) {
set_num_var_ranges(); set_num_var_ranges();
init_table(); init_table();
init_other_cpus(); if (use_intel())
get_mtrr_state();
return sysdev_driver_register(&cpu_sysdev_class,
&mtrr_sysdev_driver);
} }
return -ENXIO;
} }
subsys_initcall(mtrr_init); void mtrr_ap_init(void)
{
unsigned long flags;
if (!mtrr_if || !use_intel())
return;
/*
* Ideally we should hold main_lock here to avoid mtrr entries changed,
* but this routine will be called in cpu boot time, holding the lock
* breaks it. This routine is called in two cases: 1.very earily time
* of software resume, when there absolutely isn't mtrr entry changes;
* 2.cpu hotadd time. We let mtrr_add/del_page hold cpuhotplug lock to
* prevent mtrr entry changes
*/
local_irq_save(flags);
mtrr_if->set_all();
local_irq_restore(flags);
}
static int __init mtrr_init_finialize(void)
{
if (!mtrr_if)
return 0;
if (use_intel())
mtrr_state_warn();
else {
/* The CPUs haven't MTRR and seemes not support SMP. They have
* specific drivers, we use a tricky method to support
* suspend/resume for them.
* TBD: is there any system with such CPU which supports
* suspend/resume? if no, we should remove the code.
*/
sysdev_driver_register(&cpu_sysdev_class,
&mtrr_sysdev_driver);
}
return 0;
}
subsys_initcall(mtrr_init_finialize);
...@@ -91,7 +91,6 @@ extern struct mtrr_ops * mtrr_if; ...@@ -91,7 +91,6 @@ extern struct mtrr_ops * mtrr_if;
extern unsigned int num_var_ranges; extern unsigned int num_var_ranges;
void finalize_mtrr_state(void);
void mtrr_state_warn(void); void mtrr_state_warn(void);
char *mtrr_attrib_to_str(int x); char *mtrr_attrib_to_str(int x);
void mtrr_wrmsr(unsigned, unsigned, unsigned); void mtrr_wrmsr(unsigned, unsigned, unsigned);
......
...@@ -68,21 +68,21 @@ EXPORT_SYMBOL(smp_num_siblings); ...@@ -68,21 +68,21 @@ EXPORT_SYMBOL(smp_num_siblings);
#endif #endif
/* Package ID of each logical CPU */ /* Package ID of each logical CPU */
int phys_proc_id[NR_CPUS] = {[0 ... NR_CPUS-1] = BAD_APICID}; int phys_proc_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID};
EXPORT_SYMBOL(phys_proc_id); EXPORT_SYMBOL(phys_proc_id);
/* Core ID of each logical CPU */ /* Core ID of each logical CPU */
int cpu_core_id[NR_CPUS] = {[0 ... NR_CPUS-1] = BAD_APICID}; int cpu_core_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID};
EXPORT_SYMBOL(cpu_core_id); EXPORT_SYMBOL(cpu_core_id);
cpumask_t cpu_sibling_map[NR_CPUS]; cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly;
EXPORT_SYMBOL(cpu_sibling_map); EXPORT_SYMBOL(cpu_sibling_map);
cpumask_t cpu_core_map[NR_CPUS]; cpumask_t cpu_core_map[NR_CPUS] __read_mostly;
EXPORT_SYMBOL(cpu_core_map); EXPORT_SYMBOL(cpu_core_map);
/* bitmap of online cpus */ /* bitmap of online cpus */
cpumask_t cpu_online_map; cpumask_t cpu_online_map __read_mostly;
EXPORT_SYMBOL(cpu_online_map); EXPORT_SYMBOL(cpu_online_map);
cpumask_t cpu_callin_map; cpumask_t cpu_callin_map;
...@@ -100,7 +100,7 @@ static int __devinitdata tsc_sync_disabled; ...@@ -100,7 +100,7 @@ static int __devinitdata tsc_sync_disabled;
struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned; struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
EXPORT_SYMBOL(cpu_data); EXPORT_SYMBOL(cpu_data);
u8 x86_cpu_to_apicid[NR_CPUS] = u8 x86_cpu_to_apicid[NR_CPUS] __read_mostly =
{ [0 ... NR_CPUS-1] = 0xff }; { [0 ... NR_CPUS-1] = 0xff };
EXPORT_SYMBOL(x86_cpu_to_apicid); EXPORT_SYMBOL(x86_cpu_to_apicid);
...@@ -550,10 +550,10 @@ extern struct { ...@@ -550,10 +550,10 @@ extern struct {
#ifdef CONFIG_NUMA #ifdef CONFIG_NUMA
/* which logical CPUs are on which nodes */ /* which logical CPUs are on which nodes */
cpumask_t node_2_cpu_mask[MAX_NUMNODES] = cpumask_t node_2_cpu_mask[MAX_NUMNODES] __read_mostly =
{ [0 ... MAX_NUMNODES-1] = CPU_MASK_NONE }; { [0 ... MAX_NUMNODES-1] = CPU_MASK_NONE };
/* which node each logical CPU is on */ /* which node each logical CPU is on */
int cpu_2_node[NR_CPUS] = { [0 ... NR_CPUS-1] = 0 }; int cpu_2_node[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = 0 };
EXPORT_SYMBOL(cpu_2_node); EXPORT_SYMBOL(cpu_2_node);
/* set up a mapping between cpu and node. */ /* set up a mapping between cpu and node. */
...@@ -581,7 +581,7 @@ static inline void unmap_cpu_to_node(int cpu) ...@@ -581,7 +581,7 @@ static inline void unmap_cpu_to_node(int cpu)
#endif /* CONFIG_NUMA */ #endif /* CONFIG_NUMA */
u8 cpu_2_logical_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID }; u8 cpu_2_logical_apicid[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID };
static void map_cpu_to_logical_apicid(void) static void map_cpu_to_logical_apicid(void)
{ {
......
...@@ -91,7 +91,7 @@ EXPORT_SYMBOL(rtc_lock); ...@@ -91,7 +91,7 @@ EXPORT_SYMBOL(rtc_lock);
DEFINE_SPINLOCK(i8253_lock); DEFINE_SPINLOCK(i8253_lock);
EXPORT_SYMBOL(i8253_lock); EXPORT_SYMBOL(i8253_lock);
struct timer_opts *cur_timer = &timer_none; struct timer_opts *cur_timer __read_mostly = &timer_none;
/* /*
* This is a special lock that is owned by the CPU and holds the index * This is a special lock that is owned by the CPU and holds the index
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include "mach_timer.h" #include "mach_timer.h"
#include <asm/hpet.h> #include <asm/hpet.h>
static unsigned long hpet_usec_quotient; /* convert hpet clks to usec */ static unsigned long __read_mostly hpet_usec_quotient; /* convert hpet clks to usec */
static unsigned long tsc_hpet_quotient; /* convert tsc to hpet clks */ static unsigned long tsc_hpet_quotient; /* convert tsc to hpet clks */
static unsigned long hpet_last; /* hpet counter value at last tick*/ static unsigned long hpet_last; /* hpet counter value at last tick*/
static unsigned long last_tsc_low; /* lsb 32 bits of Time Stamp Counter */ static unsigned long last_tsc_low; /* lsb 32 bits of Time Stamp Counter */
...@@ -180,7 +180,7 @@ static int __init init_hpet(char* override) ...@@ -180,7 +180,7 @@ static int __init init_hpet(char* override)
/************************************************************/ /************************************************************/
/* tsc timer_opts struct */ /* tsc timer_opts struct */
static struct timer_opts timer_hpet = { static struct timer_opts timer_hpet __read_mostly = {
.name = "hpet", .name = "hpet",
.mark_offset = mark_offset_hpet, .mark_offset = mark_offset_hpet,
.get_offset = get_offset_hpet, .get_offset = get_offset_hpet,
......
...@@ -57,6 +57,9 @@ SECTIONS ...@@ -57,6 +57,9 @@ SECTIONS
*(.data.cacheline_aligned) *(.data.cacheline_aligned)
} }
/* rarely changed data like cpu maps */
. = ALIGN(32);
.data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) { *(.data.read_mostly) }
_edata = .; /* End of data section */ _edata = .; /* End of data section */
. = ALIGN(THREAD_SIZE); /* init_task */ . = ALIGN(THREAD_SIZE); /* init_task */
......
...@@ -228,7 +228,8 @@ EXPORT_SYMBOL(ioremap_nocache); ...@@ -228,7 +228,8 @@ EXPORT_SYMBOL(ioremap_nocache);
void iounmap(volatile void __iomem *addr) void iounmap(volatile void __iomem *addr)
{ {
struct vm_struct *p; struct vm_struct *p;
if ((void __force *) addr <= high_memory)
if ((void __force *)addr <= high_memory)
return; return;
/* /*
...@@ -241,9 +242,10 @@ void iounmap(volatile void __iomem *addr) ...@@ -241,9 +242,10 @@ void iounmap(volatile void __iomem *addr)
return; return;
write_lock(&vmlist_lock); write_lock(&vmlist_lock);
p = __remove_vm_area((void *) (PAGE_MASK & (unsigned long __force) addr)); p = __remove_vm_area((void *)(PAGE_MASK & (unsigned long __force)addr));
if (!p) { if (!p) {
printk(KERN_WARNING "iounmap: bad address %p\n", addr); printk(KERN_WARNING "iounmap: bad address %p\n", addr);
dump_stack();
goto out_unlock; goto out_unlock;
} }
......
...@@ -137,6 +137,7 @@ void __restore_processor_state(struct saved_context *ctxt) ...@@ -137,6 +137,7 @@ void __restore_processor_state(struct saved_context *ctxt)
fix_processor_context(); fix_processor_context();
do_fpu_end(); do_fpu_end();
mtrr_ap_init();
} }
void restore_processor_state(void) void restore_processor_state(void)
......
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
* *
* Setup routines for Renesas M32700UT Board * Setup routines for Renesas M32700UT Board
* *
* Copyright (c) 2002 Hiroyuki Kondo, Hirokazu Takata, * Copyright (c) 2002-2005 Hiroyuki Kondo, Hirokazu Takata,
* Hitoshi Yamamoto, Takeo Takahashi * Hitoshi Yamamoto, Takeo Takahashi
* *
* This file is subject to the terms and conditions of the GNU General * This file is subject to the terms and conditions of the GNU General
* Public License. See the file "COPYING" in the main directory of this * Public License. See the file "COPYING" in the main directory of this
...@@ -435,7 +435,7 @@ void __init init_IRQ(void) ...@@ -435,7 +435,7 @@ void __init init_IRQ(void)
icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01; icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
enable_m32700ut_irq(M32R_IRQ_INT2); enable_m32700ut_irq(M32R_IRQ_INT2);
//#if defined(CONFIG_VIDEO_M32R_AR) #if defined(CONFIG_VIDEO_M32R_AR)
/* /*
* INT3# is used for AR * INT3# is used for AR
*/ */
...@@ -445,9 +445,11 @@ void __init init_IRQ(void) ...@@ -445,9 +445,11 @@ void __init init_IRQ(void)
irq_desc[M32R_IRQ_INT3].depth = 1; irq_desc[M32R_IRQ_INT3].depth = 1;
icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
disable_m32700ut_irq(M32R_IRQ_INT3); disable_m32700ut_irq(M32R_IRQ_INT3);
//#endif /* CONFIG_VIDEO_M32R_AR */ #endif /* CONFIG_VIDEO_M32R_AR */
} }
#if defined(CONFIG_SMC91X)
#define LAN_IOSTART 0x300 #define LAN_IOSTART 0x300
#define LAN_IOEND 0x320 #define LAN_IOEND 0x320
static struct resource smc91x_resources[] = { static struct resource smc91x_resources[] = {
...@@ -469,10 +471,55 @@ static struct platform_device smc91x_device = { ...@@ -469,10 +471,55 @@ static struct platform_device smc91x_device = {
.num_resources = ARRAY_SIZE(smc91x_resources), .num_resources = ARRAY_SIZE(smc91x_resources),
.resource = smc91x_resources, .resource = smc91x_resources,
}; };
#endif
#if defined(CONFIG_FB_S1D13XXX)
#include <video/s1d13xxxfb.h>
#include <asm/s1d13806.h>
static struct s1d13xxxfb_pdata s1d13xxxfb_data = {
.initregs = s1d13xxxfb_initregs,
.initregssize = ARRAY_SIZE(s1d13xxxfb_initregs),
.platform_init_video = NULL,
#ifdef CONFIG_PM
.platform_suspend_video = NULL,
.platform_resume_video = NULL,
#endif
};
static struct resource s1d13xxxfb_resources[] = {
[0] = {
.start = 0x10600000UL,
.end = 0x1073FFFFUL,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 0x10400000UL,
.end = 0x104001FFUL,
.flags = IORESOURCE_MEM,
}
};
static struct platform_device s1d13xxxfb_device = {
.name = S1D_DEVICENAME,
.id = 0,
.dev = {
.platform_data = &s1d13xxxfb_data,
},
.num_resources = ARRAY_SIZE(s1d13xxxfb_resources),
.resource = s1d13xxxfb_resources,
};
#endif
static int __init platform_init(void) static int __init platform_init(void)
{ {
#if defined(CONFIG_SMC91X)
platform_device_register(&smc91x_device); platform_device_register(&smc91x_device);
#endif
#if defined(CONFIG_FB_S1D13XXX)
platform_device_register(&s1d13xxxfb_device);
#endif
return 0; return 0;
} }
arch_initcall(platform_init); arch_initcall(platform_init);
...@@ -3,14 +3,15 @@ ...@@ -3,14 +3,15 @@
* *
* Setup routines for Renesas MAPPI Board * Setup routines for Renesas MAPPI Board
* *
* Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata,
* Hitoshi Yamamoto * Hitoshi Yamamoto
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/device.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/m32r.h> #include <asm/m32r.h>
...@@ -158,3 +159,49 @@ void __init init_IRQ(void) ...@@ -158,3 +159,49 @@ void __init init_IRQ(void)
disable_mappi_irq(M32R_IRQ_INT2); disable_mappi_irq(M32R_IRQ_INT2);
#endif /* CONFIG_M32RPCC */ #endif /* CONFIG_M32RPCC */
} }
#if defined(CONFIG_FB_S1D13XXX)
#include <video/s1d13xxxfb.h>
#include <asm/s1d13806.h>
static struct s1d13xxxfb_pdata s1d13xxxfb_data = {
.initregs = s1d13xxxfb_initregs,
.initregssize = ARRAY_SIZE(s1d13xxxfb_initregs),
.platform_init_video = NULL,
#ifdef CONFIG_PM
.platform_suspend_video = NULL,
.platform_resume_video = NULL,
#endif
};
static struct resource s1d13xxxfb_resources[] = {
[0] = {
.start = 0x10200000UL,
.end = 0x1033FFFFUL,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 0x10000000UL,
.end = 0x100001FFUL,
.flags = IORESOURCE_MEM,
}
};
static struct platform_device s1d13xxxfb_device = {
.name = S1D_DEVICENAME,
.id = 0,
.dev = {
.platform_data = &s1d13xxxfb_data,
},
.num_resources = ARRAY_SIZE(s1d13xxxfb_resources),
.resource = s1d13xxxfb_resources,
};
static int __init platform_init(void)
{
platform_device_register(&s1d13xxxfb_device);
return 0;
}
arch_initcall(platform_init);
#endif
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
* *
* Setup routines for Renesas MAPPI-II(M3A-ZA36) Board * Setup routines for Renesas MAPPI-II(M3A-ZA36) Board
* *
* Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata,
* Hitoshi Yamamoto, Mamoru Sakugawa * Hitoshi Yamamoto, Mamoru Sakugawa
*/ */
#include <linux/config.h> #include <linux/config.h>
......
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
* *
* Setup routines for Renesas MAPPI-III(M3A-2170) Board * Setup routines for Renesas MAPPI-III(M3A-2170) Board
* *
* Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata, * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata,
* Hitoshi Yamamoto, Mamoru Sakugawa * Hitoshi Yamamoto, Mamoru Sakugawa
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -178,6 +178,8 @@ void __init init_IRQ(void) ...@@ -178,6 +178,8 @@ void __init init_IRQ(void)
#endif /* CONFIG_M32R_CFC */ #endif /* CONFIG_M32R_CFC */
} }
#if defined(CONFIG_SMC91X)
#define LAN_IOSTART 0x300 #define LAN_IOSTART 0x300
#define LAN_IOEND 0x320 #define LAN_IOEND 0x320
static struct resource smc91x_resources[] = { static struct resource smc91x_resources[] = {
...@@ -200,9 +202,55 @@ static struct platform_device smc91x_device = { ...@@ -200,9 +202,55 @@ static struct platform_device smc91x_device = {
.resource = smc91x_resources, .resource = smc91x_resources,
}; };
#endif
#if defined(CONFIG_FB_S1D13XXX)
#include <video/s1d13xxxfb.h>
#include <asm/s1d13806.h>
static struct s1d13xxxfb_pdata s1d13xxxfb_data = {
.initregs = s1d13xxxfb_initregs,
.initregssize = ARRAY_SIZE(s1d13xxxfb_initregs),
.platform_init_video = NULL,
#ifdef CONFIG_PM
.platform_suspend_video = NULL,
.platform_resume_video = NULL,
#endif
};
static struct resource s1d13xxxfb_resources[] = {
[0] = {
.start = 0x1d600000UL,
.end = 0x1d73FFFFUL,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 0x1d400000UL,
.end = 0x1d4001FFUL,
.flags = IORESOURCE_MEM,
}
};
static struct platform_device s1d13xxxfb_device = {
.name = S1D_DEVICENAME,
.id = 0,
.dev = {
.platform_data = &s1d13xxxfb_data,
},
.num_resources = ARRAY_SIZE(s1d13xxxfb_resources),
.resource = s1d13xxxfb_resources,
};
#endif
static int __init platform_init(void) static int __init platform_init(void)
{ {
#if defined(CONFIG_SMC91X)
platform_device_register(&smc91x_device); platform_device_register(&smc91x_device);
#endif
#if defined(CONFIG_FB_S1D13XXX)
platform_device_register(&s1d13xxxfb_device);
#endif
return 0; return 0;
} }
arch_initcall(platform_init); arch_initcall(platform_init);
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
* *
* Setup routines for OAKS32R Board * Setup routines for OAKS32R Board
* *
* Copyright (c) 2002-2004 Hiroyuki Kondo, Hirokazu Takata, * Copyright (c) 2002-2005 Hiroyuki Kondo, Hirokazu Takata,
* Hitoshi Yamamoto, Mamoru Sakugawa * Hitoshi Yamamoto, Mamoru Sakugawa
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -139,5 +139,4 @@ void __init init_IRQ(void) ...@@ -139,5 +139,4 @@ void __init init_IRQ(void)
icu_data[M32R_IRQ_SIO1_S].icucr = 0; icu_data[M32R_IRQ_SIO1_S].icucr = 0;
disable_oaks32r_irq(M32R_IRQ_SIO1_S); disable_oaks32r_irq(M32R_IRQ_SIO1_S);
#endif /* CONFIG_SERIAL_M32R_SIO */ #endif /* CONFIG_SERIAL_M32R_SIO */
} }
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Setup routines for Renesas OPSPUT Board * Setup routines for Renesas OPSPUT Board
* *
* Copyright (c) 2002-2004 * Copyright (c) 2002-2005
* Hiroyuki Kondo, Hirokazu Takata, * Hiroyuki Kondo, Hirokazu Takata,
* Hitoshi Yamamoto, Takeo Takahashi, Mamoru Sakugawa * Hitoshi Yamamoto, Takeo Takahashi, Mamoru Sakugawa
* *
...@@ -439,7 +439,7 @@ void __init init_IRQ(void) ...@@ -439,7 +439,7 @@ void __init init_IRQ(void)
icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01; icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
enable_opsput_irq(M32R_IRQ_INT2); enable_opsput_irq(M32R_IRQ_INT2);
//#if defined(CONFIG_VIDEO_M32R_AR) #if defined(CONFIG_VIDEO_M32R_AR)
/* /*
* INT3# is used for AR * INT3# is used for AR
*/ */
...@@ -449,9 +449,11 @@ void __init init_IRQ(void) ...@@ -449,9 +449,11 @@ void __init init_IRQ(void)
irq_desc[M32R_IRQ_INT3].depth = 1; irq_desc[M32R_IRQ_INT3].depth = 1;
icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
disable_opsput_irq(M32R_IRQ_INT3); disable_opsput_irq(M32R_IRQ_INT3);
//#endif /* CONFIG_VIDEO_M32R_AR */ #endif /* CONFIG_VIDEO_M32R_AR */
} }
#if defined(CONFIG_SMC91X)
#define LAN_IOSTART 0x300 #define LAN_IOSTART 0x300
#define LAN_IOEND 0x320 #define LAN_IOEND 0x320
static struct resource smc91x_resources[] = { static struct resource smc91x_resources[] = {
...@@ -473,10 +475,55 @@ static struct platform_device smc91x_device = { ...@@ -473,10 +475,55 @@ static struct platform_device smc91x_device = {
.num_resources = ARRAY_SIZE(smc91x_resources), .num_resources = ARRAY_SIZE(smc91x_resources),
.resource = smc91x_resources, .resource = smc91x_resources,
}; };
#endif
#if defined(CONFIG_FB_S1D13XXX)
#include <video/s1d13xxxfb.h>
#include <asm/s1d13806.h>
static struct s1d13xxxfb_pdata s1d13xxxfb_data = {
.initregs = s1d13xxxfb_initregs,
.initregssize = ARRAY_SIZE(s1d13xxxfb_initregs),
.platform_init_video = NULL,
#ifdef CONFIG_PM
.platform_suspend_video = NULL,
.platform_resume_video = NULL,
#endif
};
static struct resource s1d13xxxfb_resources[] = {
[0] = {
.start = 0x10600000UL,
.end = 0x1073FFFFUL,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 0x10400000UL,
.end = 0x104001FFUL,
.flags = IORESOURCE_MEM,
}
};
static struct platform_device s1d13xxxfb_device = {
.name = S1D_DEVICENAME,
.id = 0,
.dev = {
.platform_data = &s1d13xxxfb_data,
},
.num_resources = ARRAY_SIZE(s1d13xxxfb_resources),
.resource = s1d13xxxfb_resources,
};
#endif
static int __init platform_init(void) static int __init platform_init(void)
{ {
#if defined(CONFIG_SMC91X)
platform_device_register(&smc91x_device); platform_device_register(&smc91x_device);
#endif
#if defined(CONFIG_FB_S1D13XXX)
platform_device_register(&s1d13xxxfb_device);
#endif
return 0; return 0;
} }
arch_initcall(platform_init); arch_initcall(platform_init);
...@@ -452,7 +452,7 @@ static u32 __pmac read_gpio(struct device_node *np) ...@@ -452,7 +452,7 @@ static u32 __pmac read_gpio(struct device_node *np)
return offset; return offset;
} }
static int __pmac pmac_cpufreq_suspend(struct cpufreq_policy *policy, u32 state) static int __pmac pmac_cpufreq_suspend(struct cpufreq_policy *policy, pm_message_t pmsg)
{ {
/* Ok, this could be made a bit smarter, but let's be robust for now. We /* Ok, this could be made a bit smarter, but let's be robust for now. We
* always force a speed change to high speed before sleep, to make sure * always force a speed change to high speed before sleep, to make sure
......
This diff is collapsed.
...@@ -308,6 +308,7 @@ exception_marker: ...@@ -308,6 +308,7 @@ exception_marker:
label##_pSeries: \ label##_pSeries: \
HMT_MEDIUM; \ HMT_MEDIUM; \
mtspr SPRG1,r13; /* save r13 */ \ mtspr SPRG1,r13; /* save r13 */ \
RUNLATCH_ON(r13); \
EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common)
#define STD_EXCEPTION_ISERIES(n, label, area) \ #define STD_EXCEPTION_ISERIES(n, label, area) \
...@@ -315,6 +316,7 @@ label##_pSeries: \ ...@@ -315,6 +316,7 @@ label##_pSeries: \
label##_iSeries: \ label##_iSeries: \
HMT_MEDIUM; \ HMT_MEDIUM; \
mtspr SPRG1,r13; /* save r13 */ \ mtspr SPRG1,r13; /* save r13 */ \
RUNLATCH_ON(r13); \
EXCEPTION_PROLOG_ISERIES_1(area); \ EXCEPTION_PROLOG_ISERIES_1(area); \
EXCEPTION_PROLOG_ISERIES_2; \ EXCEPTION_PROLOG_ISERIES_2; \
b label##_common b label##_common
...@@ -324,6 +326,7 @@ label##_iSeries: \ ...@@ -324,6 +326,7 @@ label##_iSeries: \
label##_iSeries: \ label##_iSeries: \
HMT_MEDIUM; \ HMT_MEDIUM; \
mtspr SPRG1,r13; /* save r13 */ \ mtspr SPRG1,r13; /* save r13 */ \
RUNLATCH_ON(r13); \
EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN); \ EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN); \
lbz r10,PACAPROCENABLED(r13); \ lbz r10,PACAPROCENABLED(r13); \
cmpwi 0,r10,0; \ cmpwi 0,r10,0; \
...@@ -393,6 +396,7 @@ __start_interrupts: ...@@ -393,6 +396,7 @@ __start_interrupts:
_machine_check_pSeries: _machine_check_pSeries:
HMT_MEDIUM HMT_MEDIUM
mtspr SPRG1,r13 /* save r13 */ mtspr SPRG1,r13 /* save r13 */
RUNLATCH_ON(r13)
EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)
. = 0x300 . = 0x300
...@@ -419,6 +423,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB) ...@@ -419,6 +423,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
data_access_slb_pSeries: data_access_slb_pSeries:
HMT_MEDIUM HMT_MEDIUM
mtspr SPRG1,r13 mtspr SPRG1,r13
RUNLATCH_ON(r13)
mfspr r13,SPRG3 /* get paca address into r13 */ mfspr r13,SPRG3 /* get paca address into r13 */
std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */ std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */
std r10,PACA_EXSLB+EX_R10(r13) std r10,PACA_EXSLB+EX_R10(r13)
...@@ -439,6 +444,7 @@ data_access_slb_pSeries: ...@@ -439,6 +444,7 @@ data_access_slb_pSeries:
instruction_access_slb_pSeries: instruction_access_slb_pSeries:
HMT_MEDIUM HMT_MEDIUM
mtspr SPRG1,r13 mtspr SPRG1,r13
RUNLATCH_ON(r13)
mfspr r13,SPRG3 /* get paca address into r13 */ mfspr r13,SPRG3 /* get paca address into r13 */
std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */ std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */
std r10,PACA_EXSLB+EX_R10(r13) std r10,PACA_EXSLB+EX_R10(r13)
...@@ -464,6 +470,7 @@ instruction_access_slb_pSeries: ...@@ -464,6 +470,7 @@ instruction_access_slb_pSeries:
.globl system_call_pSeries .globl system_call_pSeries
system_call_pSeries: system_call_pSeries:
HMT_MEDIUM HMT_MEDIUM
RUNLATCH_ON(r9)
mr r9,r13 mr r9,r13
mfmsr r10 mfmsr r10
mfspr r13,SPRG3 mfspr r13,SPRG3
...@@ -707,11 +714,13 @@ fwnmi_data_area: ...@@ -707,11 +714,13 @@ fwnmi_data_area:
system_reset_fwnmi: system_reset_fwnmi:
HMT_MEDIUM HMT_MEDIUM
mtspr SPRG1,r13 /* save r13 */ mtspr SPRG1,r13 /* save r13 */
RUNLATCH_ON(r13)
EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common) EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common)
.globl machine_check_fwnmi .globl machine_check_fwnmi
machine_check_fwnmi: machine_check_fwnmi:
HMT_MEDIUM HMT_MEDIUM
mtspr SPRG1,r13 /* save r13 */ mtspr SPRG1,r13 /* save r13 */
RUNLATCH_ON(r13)
EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)
/* /*
...@@ -848,6 +857,7 @@ unrecov_fer: ...@@ -848,6 +857,7 @@ unrecov_fer:
.align 7 .align 7
.globl data_access_common .globl data_access_common
data_access_common: data_access_common:
RUNLATCH_ON(r10) /* It wont fit in the 0x300 handler */
mfspr r10,DAR mfspr r10,DAR
std r10,PACA_EXGEN+EX_DAR(r13) std r10,PACA_EXGEN+EX_DAR(r13)
mfspr r10,DSISR mfspr r10,DSISR
......
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <asm/hvcall.h> #include <asm/hvcall.h>
#include <asm/hvconsole.h> #include <asm/hvconsole.h>
#include <asm/prom.h>
/** /**
* hvc_get_chars - retrieve characters from firmware for denoted vterm adatper * hvc_get_chars - retrieve characters from firmware for denoted vterm adatper
...@@ -42,29 +41,14 @@ int hvc_get_chars(uint32_t vtermno, char *buf, int count) ...@@ -42,29 +41,14 @@ int hvc_get_chars(uint32_t vtermno, char *buf, int count)
unsigned long got; unsigned long got;
if (plpar_hcall(H_GET_TERM_CHAR, vtermno, 0, 0, 0, &got, if (plpar_hcall(H_GET_TERM_CHAR, vtermno, 0, 0, 0, &got,
(unsigned long *)buf, (unsigned long *)buf+1) == H_Success) { (unsigned long *)buf, (unsigned long *)buf+1) == H_Success)
/*
* Work around a HV bug where it gives us a null
* after every \r. -- paulus
*/
if (got > 0) {
int i;
for (i = 1; i < got; ++i) {
if (buf[i] == 0 && buf[i-1] == '\r') {
--got;
if (i < got)
memmove(&buf[i], &buf[i+1],
got - i);
}
}
}
return got; return got;
}
return 0; return 0;
} }
EXPORT_SYMBOL(hvc_get_chars); EXPORT_SYMBOL(hvc_get_chars);
/** /**
* hvc_put_chars: send characters to firmware for denoted vterm adapter * hvc_put_chars: send characters to firmware for denoted vterm adapter
* @vtermno: The vtermno or unit_address of the adapter from which the data * @vtermno: The vtermno or unit_address of the adapter from which the data
...@@ -88,34 +72,3 @@ int hvc_put_chars(uint32_t vtermno, const char *buf, int count) ...@@ -88,34 +72,3 @@ int hvc_put_chars(uint32_t vtermno, const char *buf, int count)
} }
EXPORT_SYMBOL(hvc_put_chars); EXPORT_SYMBOL(hvc_put_chars);
/*
* We hope/assume that the first vty found corresponds to the first console
* device.
*/
int hvc_find_vtys(void)
{
struct device_node *vty;
int num_found = 0;
for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL;
vty = of_find_node_by_name(vty, "vty")) {
uint32_t *vtermno;
/* We have statically defined space for only a certain number of
* console adapters. */
if (num_found >= MAX_NR_HVC_CONSOLES)
break;
vtermno = (uint32_t *)get_property(vty, "reg", NULL);
if (!vtermno)
continue;
if (device_is_compatible(vty, "hvterm1")) {
hvc_instantiate(*vtermno, num_found);
++num_found;
}
}
return num_found;
}
...@@ -834,6 +834,92 @@ static int __init iSeries_src_init(void) ...@@ -834,6 +834,92 @@ static int __init iSeries_src_init(void)
late_initcall(iSeries_src_init); late_initcall(iSeries_src_init);
static inline void process_iSeries_events(void)
{
asm volatile ("li 0,0x5555; sc" : : : "r0", "r3");
}
static void yield_shared_processor(void)
{
unsigned long tb;
HvCall_setEnabledInterrupts(HvCall_MaskIPI |
HvCall_MaskLpEvent |
HvCall_MaskLpProd |
HvCall_MaskTimeout);
tb = get_tb();
/* Compute future tb value when yield should expire */
HvCall_yieldProcessor(HvCall_YieldTimed, tb+tb_ticks_per_jiffy);
/*
* The decrementer stops during the yield. Force a fake decrementer
* here and let the timer_interrupt code sort out the actual time.
*/
get_paca()->lppaca.int_dword.fields.decr_int = 1;
process_iSeries_events();
}
static int iseries_shared_idle(void)
{
while (1) {
while (!need_resched() && !hvlpevent_is_pending()) {
local_irq_disable();
ppc64_runlatch_off();
/* Recheck with irqs off */
if (!need_resched() && !hvlpevent_is_pending())
yield_shared_processor();
HMT_medium();
local_irq_enable();
}
ppc64_runlatch_on();
if (hvlpevent_is_pending())
process_iSeries_events();
schedule();
}
return 0;
}
static int iseries_dedicated_idle(void)
{
long oldval;
while (1) {
oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
if (!oldval) {
set_thread_flag(TIF_POLLING_NRFLAG);
while (!need_resched()) {
ppc64_runlatch_off();
HMT_low();
if (hvlpevent_is_pending()) {
HMT_medium();
ppc64_runlatch_on();
process_iSeries_events();
}
}
HMT_medium();
clear_thread_flag(TIF_POLLING_NRFLAG);
} else {
set_need_resched();
}
ppc64_runlatch_on();
schedule();
}
return 0;
}
#ifndef CONFIG_PCI #ifndef CONFIG_PCI
void __init iSeries_init_IRQ(void) { } void __init iSeries_init_IRQ(void) { }
#endif #endif
...@@ -859,5 +945,13 @@ void __init iSeries_early_setup(void) ...@@ -859,5 +945,13 @@ void __init iSeries_early_setup(void)
ppc_md.get_rtc_time = iSeries_get_rtc_time; ppc_md.get_rtc_time = iSeries_get_rtc_time;
ppc_md.calibrate_decr = iSeries_calibrate_decr; ppc_md.calibrate_decr = iSeries_calibrate_decr;
ppc_md.progress = iSeries_progress; ppc_md.progress = iSeries_progress;
if (get_paca()->lppaca.shared_proc) {
ppc_md.idle_loop = iseries_shared_idle;
printk(KERN_INFO "Using shared processor idle loop\n");
} else {
ppc_md.idle_loop = iseries_dedicated_idle;
printk(KERN_INFO "Using dedicated idle loop\n");
}
} }
...@@ -20,109 +20,18 @@ ...@@ -20,109 +20,18 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/module.h>
#include <linux/sysctl.h> #include <linux/sysctl.h>
#include <linux/smp.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/mmu.h>
#include <asm/cputable.h> #include <asm/cputable.h>
#include <asm/time.h> #include <asm/time.h>
#include <asm/iSeries/HvCall.h>
#include <asm/iSeries/ItLpQueue.h>
#include <asm/plpar_wrappers.h>
#include <asm/systemcfg.h> #include <asm/systemcfg.h>
#include <asm/machdep.h>
extern void power4_idle(void); extern void power4_idle(void);
static int (*idle_loop)(void); int default_idle(void)
#ifdef CONFIG_PPC_ISERIES
static unsigned long maxYieldTime = 0;
static unsigned long minYieldTime = 0xffffffffffffffffUL;
static inline void process_iSeries_events(void)
{
asm volatile ("li 0,0x5555; sc" : : : "r0", "r3");
}
static void yield_shared_processor(void)
{
unsigned long tb;
unsigned long yieldTime;
HvCall_setEnabledInterrupts(HvCall_MaskIPI |
HvCall_MaskLpEvent |
HvCall_MaskLpProd |
HvCall_MaskTimeout);
tb = get_tb();
/* Compute future tb value when yield should expire */
HvCall_yieldProcessor(HvCall_YieldTimed, tb+tb_ticks_per_jiffy);
yieldTime = get_tb() - tb;
if (yieldTime > maxYieldTime)
maxYieldTime = yieldTime;
if (yieldTime < minYieldTime)
minYieldTime = yieldTime;
/*
* The decrementer stops during the yield. Force a fake decrementer
* here and let the timer_interrupt code sort out the actual time.
*/
get_paca()->lppaca.int_dword.fields.decr_int = 1;
process_iSeries_events();
}
static int iSeries_idle(void)
{
struct paca_struct *lpaca;
long oldval;
/* ensure iSeries run light will be out when idle */
ppc64_runlatch_off();
lpaca = get_paca();
while (1) {
if (lpaca->lppaca.shared_proc) {
if (hvlpevent_is_pending())
process_iSeries_events();
if (!need_resched())
yield_shared_processor();
} else {
oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
if (!oldval) {
set_thread_flag(TIF_POLLING_NRFLAG);
while (!need_resched()) {
HMT_medium();
if (hvlpevent_is_pending())
process_iSeries_events();
HMT_low();
}
HMT_medium();
clear_thread_flag(TIF_POLLING_NRFLAG);
} else {
set_need_resched();
}
}
ppc64_runlatch_on();
schedule();
ppc64_runlatch_off();
}
return 0;
}
#else
static int default_idle(void)
{ {
long oldval; long oldval;
unsigned int cpu = smp_processor_id(); unsigned int cpu = smp_processor_id();
...@@ -134,7 +43,8 @@ static int default_idle(void) ...@@ -134,7 +43,8 @@ static int default_idle(void)
set_thread_flag(TIF_POLLING_NRFLAG); set_thread_flag(TIF_POLLING_NRFLAG);
while (!need_resched() && !cpu_is_offline(cpu)) { while (!need_resched() && !cpu_is_offline(cpu)) {
barrier(); ppc64_runlatch_off();
/* /*
* Go into low thread priority and possibly * Go into low thread priority and possibly
* low power mode. * low power mode.
...@@ -149,6 +59,7 @@ static int default_idle(void) ...@@ -149,6 +59,7 @@ static int default_idle(void)
set_need_resched(); set_need_resched();
} }
ppc64_runlatch_on();
schedule(); schedule();
if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
cpu_die(); cpu_die();
...@@ -157,127 +68,19 @@ static int default_idle(void) ...@@ -157,127 +68,19 @@ static int default_idle(void)
return 0; return 0;
} }
#ifdef CONFIG_PPC_PSERIES int native_idle(void)
DECLARE_PER_CPU(unsigned long, smt_snooze_delay);
int dedicated_idle(void)
{ {
long oldval;
struct paca_struct *lpaca = get_paca(), *ppaca;
unsigned long start_snooze;
unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay);
unsigned int cpu = smp_processor_id();
ppaca = &paca[cpu ^ 1];
while (1) { while (1) {
/* ppc64_runlatch_off();
* Indicate to the HV that we are idle. Now would be
* a good time to find other work to dispatch.
*/
lpaca->lppaca.idle = 1;
oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
if (!oldval) {
set_thread_flag(TIF_POLLING_NRFLAG);
start_snooze = __get_tb() +
*smt_snooze_delay * tb_ticks_per_usec;
while (!need_resched() && !cpu_is_offline(cpu)) {
/*
* Go into low thread priority and possibly
* low power mode.
*/
HMT_low();
HMT_very_low();
if (*smt_snooze_delay == 0 ||
__get_tb() < start_snooze)
continue;
HMT_medium();
if (!(ppaca->lppaca.idle)) {
local_irq_disable();
/*
* We are about to sleep the thread
* and so wont be polling any
* more.
*/
clear_thread_flag(TIF_POLLING_NRFLAG);
/*
* SMT dynamic mode. Cede will result
* in this thread going dormant, if the
* partner thread is still doing work.
* Thread wakes up if partner goes idle,
* an interrupt is presented, or a prod
* occurs. Returning from the cede
* enables external interrupts.
*/
if (!need_resched())
cede_processor();
else
local_irq_enable();
} else {
/*
* Give the HV an opportunity at the
* processor, since we are not doing
* any work.
*/
poll_pending();
}
}
clear_thread_flag(TIF_POLLING_NRFLAG);
} else {
set_need_resched();
}
HMT_medium();
lpaca->lppaca.idle = 0;
schedule();
if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
cpu_die();
}
return 0;
}
static int shared_idle(void)
{
struct paca_struct *lpaca = get_paca();
unsigned int cpu = smp_processor_id();
while (1) {
/*
* Indicate to the HV that we are idle. Now would be
* a good time to find other work to dispatch.
*/
lpaca->lppaca.idle = 1;
while (!need_resched() && !cpu_is_offline(cpu)) { if (!need_resched())
local_irq_disable(); power4_idle();
/* if (need_resched()) {
* Yield the processor to the hypervisor. We return if ppc64_runlatch_on();
* an external interrupt occurs (which are driven prior schedule();
* to returning here) or if a prod occurs from another
* processor. When returning here, external interrupts
* are enabled.
*
* Check need_resched() again with interrupts disabled
* to avoid a race.
*/
if (!need_resched())
cede_processor();
else
local_irq_enable();
} }
HMT_medium();
lpaca->lppaca.idle = 0;
schedule();
if (cpu_is_offline(smp_processor_id()) && if (cpu_is_offline(smp_processor_id()) &&
system_state == SYSTEM_RUNNING) system_state == SYSTEM_RUNNING)
cpu_die(); cpu_die();
...@@ -286,29 +89,10 @@ static int shared_idle(void) ...@@ -286,29 +89,10 @@ static int shared_idle(void)
return 0; return 0;
} }
#endif /* CONFIG_PPC_PSERIES */
static int native_idle(void)
{
while(1) {
/* check CPU type here */
if (!need_resched())
power4_idle();
if (need_resched())
schedule();
if (cpu_is_offline(raw_smp_processor_id()) &&
system_state == SYSTEM_RUNNING)
cpu_die();
}
return 0;
}
#endif /* CONFIG_PPC_ISERIES */
void cpu_idle(void) void cpu_idle(void)
{ {
idle_loop(); BUG_ON(NULL == ppc_md.idle_loop);
ppc_md.idle_loop();
} }
int powersave_nap; int powersave_nap;
...@@ -342,42 +126,3 @@ register_powersave_nap_sysctl(void) ...@@ -342,42 +126,3 @@ register_powersave_nap_sysctl(void)
} }
__initcall(register_powersave_nap_sysctl); __initcall(register_powersave_nap_sysctl);
#endif #endif
int idle_setup(void)
{
/*
* Move that junk to each platform specific file, eventually define
* a pSeries_idle for shared processor stuff
*/
#ifdef CONFIG_PPC_ISERIES
idle_loop = iSeries_idle;
return 1;
#else
idle_loop = default_idle;
#endif
#ifdef CONFIG_PPC_PSERIES
if (systemcfg->platform & PLATFORM_PSERIES) {
if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
if (get_paca()->lppaca.shared_proc) {
printk(KERN_INFO "Using shared processor idle loop\n");
idle_loop = shared_idle;
} else {
printk(KERN_INFO "Using dedicated idle loop\n");
idle_loop = dedicated_idle;
}
} else {
printk(KERN_INFO "Using default idle loop\n");
idle_loop = default_idle;
}
}
#endif /* CONFIG_PPC_PSERIES */
#ifndef CONFIG_PPC_ISERIES
if (systemcfg->platform == PLATFORM_POWERMAC ||
systemcfg->platform == PLATFORM_MAPLE) {
printk(KERN_INFO "Using native/NAP idle loop\n");
idle_loop = native_idle;
}
#endif /* CONFIG_PPC_ISERIES */
return 1;
}
...@@ -177,6 +177,8 @@ void __init maple_setup_arch(void) ...@@ -177,6 +177,8 @@ void __init maple_setup_arch(void)
#ifdef CONFIG_DUMMY_CONSOLE #ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con; conswitchp = &dummy_con;
#endif #endif
printk(KERN_INFO "Using native/NAP idle loop\n");
} }
/* /*
...@@ -297,4 +299,5 @@ struct machdep_calls __initdata maple_md = { ...@@ -297,4 +299,5 @@ struct machdep_calls __initdata maple_md = {
.get_rtc_time = maple_get_rtc_time, .get_rtc_time = maple_get_rtc_time,
.calibrate_decr = generic_calibrate_decr, .calibrate_decr = generic_calibrate_decr,
.progress = maple_progress, .progress = maple_progress,
.idle_loop = native_idle,
}; };
...@@ -1124,9 +1124,11 @@ _GLOBAL(sys_call_table32) ...@@ -1124,9 +1124,11 @@ _GLOBAL(sys_call_table32)
.llong .compat_sys_mq_getsetattr .llong .compat_sys_mq_getsetattr
.llong .compat_sys_kexec_load .llong .compat_sys_kexec_load
.llong .sys32_add_key .llong .sys32_add_key
.llong .sys32_request_key .llong .sys32_request_key /* 270 */
.llong .compat_sys_keyctl .llong .compat_sys_keyctl
.llong .compat_sys_waitid .llong .compat_sys_waitid
.llong .sys32_ioprio_set
.llong .sys32_ioprio_get
.balign 8 .balign 8
_GLOBAL(sys_call_table) _GLOBAL(sys_call_table)
...@@ -1403,3 +1405,5 @@ _GLOBAL(sys_call_table) ...@@ -1403,3 +1405,5 @@ _GLOBAL(sys_call_table)
.llong .sys_request_key /* 270 */ .llong .sys_request_key /* 270 */
.llong .sys_keyctl .llong .sys_keyctl
.llong .sys_waitid .llong .sys_waitid
.llong .sys_ioprio_set
.llong .sys_ioprio_get
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#undef DEBUG #undef DEBUG
#include <linux/config.h> #include <linux/config.h>
#include <linux/cpu.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -82,6 +83,9 @@ int fwnmi_active; /* TRUE if an FWNMI handler is present */ ...@@ -82,6 +83,9 @@ int fwnmi_active; /* TRUE if an FWNMI handler is present */
extern void pSeries_system_reset_exception(struct pt_regs *regs); extern void pSeries_system_reset_exception(struct pt_regs *regs);
extern int pSeries_machine_check_exception(struct pt_regs *regs); extern int pSeries_machine_check_exception(struct pt_regs *regs);
static int pseries_shared_idle(void);
static int pseries_dedicated_idle(void);
static volatile void __iomem * chrp_int_ack_special; static volatile void __iomem * chrp_int_ack_special;
struct mpic *pSeries_mpic; struct mpic *pSeries_mpic;
...@@ -229,6 +233,20 @@ static void __init pSeries_setup_arch(void) ...@@ -229,6 +233,20 @@ static void __init pSeries_setup_arch(void)
if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR)
vpa_init(boot_cpuid); vpa_init(boot_cpuid);
/* Choose an idle loop */
if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
if (get_paca()->lppaca.shared_proc) {
printk(KERN_INFO "Using shared processor idle loop\n");
ppc_md.idle_loop = pseries_shared_idle;
} else {
printk(KERN_INFO "Using dedicated idle loop\n");
ppc_md.idle_loop = pseries_dedicated_idle;
}
} else {
printk(KERN_INFO "Using default idle loop\n");
ppc_md.idle_loop = default_idle;
}
} }
static int __init pSeries_init_panel(void) static int __init pSeries_init_panel(void)
...@@ -418,6 +436,144 @@ static int __init pSeries_probe(int platform) ...@@ -418,6 +436,144 @@ static int __init pSeries_probe(int platform)
return 1; return 1;
} }
DECLARE_PER_CPU(unsigned long, smt_snooze_delay);
static inline void dedicated_idle_sleep(unsigned int cpu)
{
struct paca_struct *ppaca = &paca[cpu ^ 1];
/* Only sleep if the other thread is not idle */
if (!(ppaca->lppaca.idle)) {
local_irq_disable();
/*
* We are about to sleep the thread and so wont be polling any
* more.
*/
clear_thread_flag(TIF_POLLING_NRFLAG);
/*
* SMT dynamic mode. Cede will result in this thread going
* dormant, if the partner thread is still doing work. Thread
* wakes up if partner goes idle, an interrupt is presented, or
* a prod occurs. Returning from the cede enables external
* interrupts.
*/
if (!need_resched())
cede_processor();
else
local_irq_enable();
} else {
/*
* Give the HV an opportunity at the processor, since we are
* not doing any work.
*/
poll_pending();
}
}
static int pseries_dedicated_idle(void)
{
long oldval;
struct paca_struct *lpaca = get_paca();
unsigned int cpu = smp_processor_id();
unsigned long start_snooze;
unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay);
while (1) {
/*
* Indicate to the HV that we are idle. Now would be
* a good time to find other work to dispatch.
*/
lpaca->lppaca.idle = 1;
oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
if (!oldval) {
set_thread_flag(TIF_POLLING_NRFLAG);
start_snooze = __get_tb() +
*smt_snooze_delay * tb_ticks_per_usec;
while (!need_resched() && !cpu_is_offline(cpu)) {
ppc64_runlatch_off();
/*
* Go into low thread priority and possibly
* low power mode.
*/
HMT_low();
HMT_very_low();
if (*smt_snooze_delay != 0 &&
__get_tb() > start_snooze) {
HMT_medium();
dedicated_idle_sleep(cpu);
}
}
HMT_medium();
clear_thread_flag(TIF_POLLING_NRFLAG);
} else {
set_need_resched();
}
lpaca->lppaca.idle = 0;
ppc64_runlatch_on();
schedule();
if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
cpu_die();
}
}
static int pseries_shared_idle(void)
{
struct paca_struct *lpaca = get_paca();
unsigned int cpu = smp_processor_id();
while (1) {
/*
* Indicate to the HV that we are idle. Now would be
* a good time to find other work to dispatch.
*/
lpaca->lppaca.idle = 1;
while (!need_resched() && !cpu_is_offline(cpu)) {
local_irq_disable();
ppc64_runlatch_off();
/*
* Yield the processor to the hypervisor. We return if
* an external interrupt occurs (which are driven prior
* to returning here) or if a prod occurs from another
* processor. When returning here, external interrupts
* are enabled.
*
* Check need_resched() again with interrupts disabled
* to avoid a race.
*/
if (!need_resched())
cede_processor();
else
local_irq_enable();
HMT_medium();
}
lpaca->lppaca.idle = 0;
ppc64_runlatch_on();
schedule();
if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
cpu_die();
}
return 0;
}
struct machdep_calls __initdata pSeries_md = { struct machdep_calls __initdata pSeries_md = {
.probe = pSeries_probe, .probe = pSeries_probe,
.setup_arch = pSeries_setup_arch, .setup_arch = pSeries_setup_arch,
......
...@@ -186,6 +186,8 @@ void __init pmac_setup_arch(void) ...@@ -186,6 +186,8 @@ void __init pmac_setup_arch(void)
#ifdef CONFIG_DUMMY_CONSOLE #ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con; conswitchp = &dummy_con;
#endif #endif
printk(KERN_INFO "Using native/NAP idle loop\n");
} }
#ifdef CONFIG_SCSI #ifdef CONFIG_SCSI
...@@ -507,5 +509,6 @@ struct machdep_calls __initdata pmac_md = { ...@@ -507,5 +509,6 @@ struct machdep_calls __initdata pmac_md = {
.calibrate_decr = pmac_calibrate_decr, .calibrate_decr = pmac_calibrate_decr,
.feature_call = pmac_do_feature_call, .feature_call = pmac_do_feature_call,
.progress = pmac_progress, .progress = pmac_progress,
.check_legacy_ioport = pmac_check_legacy_ioport .check_legacy_ioport = pmac_check_legacy_ioport,
.idle_loop = native_idle,
}; };
...@@ -96,7 +96,6 @@ extern void udbg_init_maple_realmode(void); ...@@ -96,7 +96,6 @@ extern void udbg_init_maple_realmode(void);
extern unsigned long klimit; extern unsigned long klimit;
extern void mm_init_ppc64(void); extern void mm_init_ppc64(void);
extern int idle_setup(void);
extern void stab_initialize(unsigned long stab); extern void stab_initialize(unsigned long stab);
extern void htab_initialize(void); extern void htab_initialize(void);
extern void early_init_devtree(void *flat_dt); extern void early_init_devtree(void *flat_dt);
...@@ -1081,8 +1080,11 @@ void __init setup_arch(char **cmdline_p) ...@@ -1081,8 +1080,11 @@ void __init setup_arch(char **cmdline_p)
ppc_md.setup_arch(); ppc_md.setup_arch();
/* Select the correct idle loop for the platform. */ /* Use the default idle loop if the platform hasn't provided one. */
idle_setup(); if (NULL == ppc_md.idle_loop) {
ppc_md.idle_loop = default_idle;
printk(KERN_INFO "Using default idle loop\n");
}
paging_init(); paging_init();
ppc64_boot_msg(0x15, "Setup Done"); ppc64_boot_msg(0x15, "Setup Done");
......
...@@ -30,47 +30,26 @@ ...@@ -30,47 +30,26 @@
#include <linux/sem.h> #include <linux/sem.h>
#include <linux/msg.h> #include <linux/msg.h>
#include <linux/shm.h> #include <linux/shm.h>
#include <linux/slab.h>
#include <linux/uio.h>
#include <linux/aio.h>
#include <linux/nfs_fs.h>
#include <linux/module.h>
#include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h>
#include <linux/nfsd/cache.h>
#include <linux/nfsd/xdr.h>
#include <linux/nfsd/syscall.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/personality.h> #include <linux/personality.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/filter.h>
#include <linux/highmem.h>
#include <linux/highuid.h>
#include <linux/mman.h> #include <linux/mman.h>
#include <linux/ipv6.h>
#include <linux/in.h> #include <linux/in.h>
#include <linux/icmpv6.h>
#include <linux/syscalls.h> #include <linux/syscalls.h>
#include <linux/unistd.h> #include <linux/unistd.h>
#include <linux/sysctl.h> #include <linux/sysctl.h>
#include <linux/binfmts.h> #include <linux/binfmts.h>
#include <linux/dnotify.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/ptrace.h> #include <linux/ptrace.h>
#include <linux/aio_abi.h>
#include <linux/elf.h> #include <linux/elf.h>
#include <net/scm.h>
#include <net/sock.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/types.h> #include <asm/types.h>
#include <asm/ipc.h> #include <asm/ipc.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/unistd.h> #include <asm/unistd.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include <asm/ppcdebug.h>
#include <asm/time.h> #include <asm/time.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#include <asm/systemcfg.h> #include <asm/systemcfg.h>
...@@ -350,8 +329,6 @@ asmlinkage long sys32_adjtimex(struct timex32 __user *utp) ...@@ -350,8 +329,6 @@ asmlinkage long sys32_adjtimex(struct timex32 __user *utp)
return ret; return ret;
} }
/* These are here just in case some old sparc32 binary calls it. */
asmlinkage long sys32_pause(void) asmlinkage long sys32_pause(void)
{ {
current->state = TASK_INTERRUPTIBLE; current->state = TASK_INTERRUPTIBLE;
...@@ -360,8 +337,6 @@ asmlinkage long sys32_pause(void) ...@@ -360,8 +337,6 @@ asmlinkage long sys32_pause(void)
return -ERESTARTNOHAND; return -ERESTARTNOHAND;
} }
static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i) static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i)
{ {
long usec; long usec;
...@@ -847,16 +822,6 @@ asmlinkage long sys32_getpgid(u32 pid) ...@@ -847,16 +822,6 @@ asmlinkage long sys32_getpgid(u32 pid)
} }
/* Note: it is necessary to treat which and who as unsigned ints,
* with the corresponding cast to a signed int to insure that the
* proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
* and the register representation of a signed int (msr in 64-bit mode) is performed.
*/
asmlinkage long sys32_getpriority(u32 which, u32 who)
{
return sys_getpriority((int)which, (int)who);
}
/* Note: it is necessary to treat pid as an unsigned int, /* Note: it is necessary to treat pid as an unsigned int,
* with the corresponding cast to a signed int to insure that the * with the corresponding cast to a signed int to insure that the
...@@ -1048,6 +1013,11 @@ asmlinkage long sys32_setpgid(u32 pid, u32 pgid) ...@@ -1048,6 +1013,11 @@ asmlinkage long sys32_setpgid(u32 pid, u32 pgid)
return sys_setpgid((int)pid, (int)pgid); return sys_setpgid((int)pid, (int)pgid);
} }
long sys32_getpriority(u32 which, u32 who)
{
/* sign extend which and who */
return sys_getpriority((int)which, (int)who);
}
long sys32_setpriority(u32 which, u32 who, u32 niceval) long sys32_setpriority(u32 which, u32 who, u32 niceval)
{ {
...@@ -1055,6 +1025,18 @@ long sys32_setpriority(u32 which, u32 who, u32 niceval) ...@@ -1055,6 +1025,18 @@ long sys32_setpriority(u32 which, u32 who, u32 niceval)
return sys_setpriority((int)which, (int)who, (int)niceval); return sys_setpriority((int)which, (int)who, (int)niceval);
} }
long sys32_ioprio_get(u32 which, u32 who)
{
/* sign extend which and who */
return sys_ioprio_get((int)which, (int)who);
}
long sys32_ioprio_set(u32 which, u32 who, u32 ioprio)
{
/* sign extend which, who and ioprio */
return sys_ioprio_set((int)which, (int)who, (int)ioprio);
}
/* Note: it is necessary to treat newmask as an unsigned int, /* Note: it is necessary to treat newmask as an unsigned int,
* with the corresponding cast to a signed int to insure that the * with the corresponding cast to a signed int to insure that the
* proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
...@@ -1273,8 +1255,6 @@ long ppc32_fadvise64_64(int fd, int advice, u32 offset_high, u32 offset_low, ...@@ -1273,8 +1255,6 @@ long ppc32_fadvise64_64(int fd, int advice, u32 offset_high, u32 offset_low,
(u64)len_high << 32 | len_low, advice); (u64)len_high << 32 | len_low, advice);
} }
extern asmlinkage long sys_timer_create(clockid_t, sigevent_t __user *, timer_t __user *);
long ppc32_timer_create(clockid_t clock, long ppc32_timer_create(clockid_t clock,
struct compat_sigevent __user *ev32, struct compat_sigevent __user *ev32,
timer_t __user *timer_id) timer_t __user *timer_id)
......
...@@ -112,7 +112,6 @@ void ppc64_enable_pmcs(void) ...@@ -112,7 +112,6 @@ void ppc64_enable_pmcs(void)
unsigned long hid0; unsigned long hid0;
#ifdef CONFIG_PPC_PSERIES #ifdef CONFIG_PPC_PSERIES
unsigned long set, reset; unsigned long set, reset;
int ret;
#endif /* CONFIG_PPC_PSERIES */ #endif /* CONFIG_PPC_PSERIES */
/* Only need to enable them once */ /* Only need to enable them once */
...@@ -145,11 +144,7 @@ void ppc64_enable_pmcs(void) ...@@ -145,11 +144,7 @@ void ppc64_enable_pmcs(void)
case PLATFORM_PSERIES_LPAR: case PLATFORM_PSERIES_LPAR:
set = 1UL << 63; set = 1UL << 63;
reset = 0; reset = 0;
ret = plpar_hcall_norets(H_PERFMON, set, reset); plpar_hcall_norets(H_PERFMON, set, reset);
if (ret)
printk(KERN_ERR "H_PERFMON call on cpu %u "
"returned %d\n",
smp_processor_id(), ret);
break; break;
#endif /* CONFIG_PPC_PSERIES */ #endif /* CONFIG_PPC_PSERIES */
...@@ -161,13 +156,6 @@ void ppc64_enable_pmcs(void) ...@@ -161,13 +156,6 @@ void ppc64_enable_pmcs(void)
/* instruct hypervisor to maintain PMCs */ /* instruct hypervisor to maintain PMCs */
if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR)
get_paca()->lppaca.pmcregs_in_use = 1; get_paca()->lppaca.pmcregs_in_use = 1;
/*
* On SMT machines we have to set the run latch in the ctrl register
* in order to make PMC6 spin.
*/
if (cpu_has_feature(CPU_FTR_SMT))
ppc64_runlatch_on();
#endif /* CONFIG_PPC_PSERIES */ #endif /* CONFIG_PPC_PSERIES */
} }
......
...@@ -40,9 +40,9 @@ SECTIONS ...@@ -40,9 +40,9 @@ SECTIONS
.gcc_except_table : { *(.gcc_except_table) } .gcc_except_table : { *(.gcc_except_table) }
.fixup : { *(.fixup) } .fixup : { *(.fixup) }
.got ALIGN(4) : { *(.got.plt) *(.got) }
.dynamic : { *(.dynamic) } :text :dynamic .dynamic : { *(.dynamic) } :text :dynamic
.got : { *(.got) }
.plt : { *(.plt) }
_end = .; _end = .;
__end = .; __end = .;
......
...@@ -128,7 +128,6 @@ config HOSTFS ...@@ -128,7 +128,6 @@ config HOSTFS
config HPPFS config HPPFS
tristate "HoneyPot ProcFS (EXPERIMENTAL)" tristate "HoneyPot ProcFS (EXPERIMENTAL)"
depends on BROKEN
help help
hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc
entries to be overridden, removed, or fabricated from the host. entries to be overridden, removed, or fabricated from the host.
...@@ -141,8 +140,9 @@ config HPPFS ...@@ -141,8 +140,9 @@ config HPPFS
You only need this if you are setting up a UML honeypot. Otherwise, You only need this if you are setting up a UML honeypot. Otherwise,
it is safe to say 'N' here. it is safe to say 'N' here.
If you are actively using it, please ask for it to be fixed. In this If you are actively using it, please report any problems, since it's
moment, it does not work on 2.6 (it works somehow on 2.4). getting fixed. In this moment, it is experimental on 2.6 (it works on
2.4).
config MCONSOLE config MCONSOLE
bool "Management console" bool "Management console"
......
...@@ -19,6 +19,18 @@ config 3_LEVEL_PGTABLES ...@@ -19,6 +19,18 @@ config 3_LEVEL_PGTABLES
memory. All the memory that can't be mapped directly will be treated memory. All the memory that can't be mapped directly will be treated
as high memory. as high memory.
config STUB_CODE
hex
default 0xbfffe000
config STUB_DATA
hex
default 0xbffff000
config STUB_START
hex
default STUB_CODE
config ARCH_HAS_SC_SIGNALS config ARCH_HAS_SC_SIGNALS
bool bool
default y default y
......
...@@ -14,6 +14,18 @@ config 3_LEVEL_PGTABLES ...@@ -14,6 +14,18 @@ config 3_LEVEL_PGTABLES
bool bool
default y default y
config STUB_CODE
hex
default 0x7fbfffe000
config STUB_DATA
hex
default 0x7fbffff000
config STUB_START
hex
default STUB_CODE
config ARCH_HAS_SC_SIGNALS config ARCH_HAS_SC_SIGNALS
bool bool
default n default n
......
...@@ -8,7 +8,7 @@ ifeq ($(CONFIG_MODE_SKAS),y) ...@@ -8,7 +8,7 @@ ifeq ($(CONFIG_MODE_SKAS),y)
endif endif
endif endif
CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH) CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH) $(STUB_CFLAGS)
ARCH_USER_CFLAGS := ARCH_USER_CFLAGS :=
ifneq ($(CONFIG_GPROF),y) ifneq ($(CONFIG_GPROF),y)
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
SUBARCH_LIBS := arch/um/sys-x86_64/ SUBARCH_LIBS := arch/um/sys-x86_64/
START := 0x60000000 START := 0x60000000
CFLAGS += -U__$(SUBARCH)__ -fno-builtin CFLAGS += -U__$(SUBARCH)__ -fno-builtin $(STUB_CFLAGS)
ARCH_USER_CFLAGS := -D__x86_64__ ARCH_USER_CFLAGS := -D__x86_64__
ELF_ARCH := i386:x86-64 ELF_ARCH := i386:x86-64
......
# #
# Automatically generated make config: don't edit # Automatically generated make config: don't edit
# Linux kernel version: 2.6.12-rc3-skas3-v9-pre2 # Linux kernel version: 2.6.12-rc6-mm1
# Sun Apr 24 19:46:10 2005 # Tue Jun 14 18:22:21 2005
# #
CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_HARDIRQS=y
CONFIG_UML=y CONFIG_UML=y
...@@ -13,23 +13,32 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y ...@@ -13,23 +13,32 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y
# #
# UML-specific options # UML-specific options
# #
CONFIG_MODE_TT=y # CONFIG_MODE_TT is not set
# CONFIG_STATIC_LINK is not set
CONFIG_MODE_SKAS=y CONFIG_MODE_SKAS=y
CONFIG_UML_X86=y CONFIG_UML_X86=y
# CONFIG_64BIT is not set # CONFIG_64BIT is not set
CONFIG_TOP_ADDR=0xc0000000 CONFIG_TOP_ADDR=0xc0000000
# CONFIG_3_LEVEL_PGTABLES is not set # CONFIG_3_LEVEL_PGTABLES is not set
CONFIG_STUB_CODE=0xbfffe000
CONFIG_STUB_DATA=0xbffff000
CONFIG_STUB_START=0xbfffe000
CONFIG_ARCH_HAS_SC_SIGNALS=y CONFIG_ARCH_HAS_SC_SIGNALS=y
CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA=y CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA=y
CONFIG_LD_SCRIPT_STATIC=y CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
# CONFIG_SPARSEMEM_MANUAL is not set
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
CONFIG_LD_SCRIPT_DYN=y
CONFIG_NET=y CONFIG_NET=y
CONFIG_BINFMT_ELF=y CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=m CONFIG_BINFMT_MISC=m
CONFIG_HOSTFS=y # CONFIG_HOSTFS is not set
CONFIG_MCONSOLE=y CONFIG_MCONSOLE=y
# CONFIG_MAGIC_SYSRQ is not set # CONFIG_MAGIC_SYSRQ is not set
# CONFIG_HOST_2G_2G is not set # CONFIG_HOST_2G_2G is not set
# CONFIG_SMP is not set
CONFIG_NEST_LEVEL=0 CONFIG_NEST_LEVEL=0
CONFIG_KERNEL_HALF_GIGS=1 CONFIG_KERNEL_HALF_GIGS=1
# CONFIG_HIGHMEM is not set # CONFIG_HIGHMEM is not set
...@@ -63,6 +72,8 @@ CONFIG_IKCONFIG_PROC=y ...@@ -63,6 +72,8 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_KALLSYMS=y CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_ALL is not set
CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_BASE_FULL=y CONFIG_BASE_FULL=y
CONFIG_FUTEX=y CONFIG_FUTEX=y
CONFIG_EPOLL=y CONFIG_EPOLL=y
...@@ -81,6 +92,7 @@ CONFIG_MODULES=y ...@@ -81,6 +92,7 @@ CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set # CONFIG_MODULE_FORCE_UNLOAD is not set
CONFIG_OBSOLETE_MODPARM=y CONFIG_OBSOLETE_MODPARM=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set # CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y CONFIG_KMOD=y
...@@ -115,6 +127,7 @@ CONFIG_UML_SOUND=m ...@@ -115,6 +127,7 @@ CONFIG_UML_SOUND=m
CONFIG_SOUND=m CONFIG_SOUND=m
CONFIG_HOSTAUDIO=m CONFIG_HOSTAUDIO=m
CONFIG_UML_RANDOM=y CONFIG_UML_RANDOM=y
# CONFIG_MMAPPER is not set
# #
# Block devices # Block devices
...@@ -176,6 +189,17 @@ CONFIG_INET=y ...@@ -176,6 +189,17 @@ CONFIG_INET=y
# CONFIG_INET_TUNNEL is not set # CONFIG_INET_TUNNEL is not set
CONFIG_IP_TCPDIAG=y CONFIG_IP_TCPDIAG=y
# CONFIG_IP_TCPDIAG_IPV6 is not set # CONFIG_IP_TCPDIAG_IPV6 is not set
#
# TCP congestion control
#
CONFIG_TCP_CONG_BIC=y
CONFIG_TCP_CONG_WESTWOOD=y
CONFIG_TCP_CONG_HTCP=y
# CONFIG_TCP_CONG_HSTCP is not set
# CONFIG_TCP_CONG_HYBLA is not set
# CONFIG_TCP_CONG_VEGAS is not set
# CONFIG_TCP_CONG_SCALABLE is not set
# CONFIG_IPV6 is not set # CONFIG_IPV6 is not set
# CONFIG_NETFILTER is not set # CONFIG_NETFILTER is not set
...@@ -206,11 +230,15 @@ CONFIG_IP_TCPDIAG=y ...@@ -206,11 +230,15 @@ CONFIG_IP_TCPDIAG=y
# Network testing # Network testing
# #
# CONFIG_NET_PKTGEN is not set # CONFIG_NET_PKTGEN is not set
# CONFIG_KGDBOE is not set
# CONFIG_NETPOLL is not set # CONFIG_NETPOLL is not set
# CONFIG_NETPOLL_RX is not set
# CONFIG_NETPOLL_TRAP is not set
# CONFIG_NET_POLL_CONTROLLER is not set # CONFIG_NET_POLL_CONTROLLER is not set
# CONFIG_HAMRADIO is not set # CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set # CONFIG_IRDA is not set
# CONFIG_BT is not set # CONFIG_BT is not set
# CONFIG_IEEE80211 is not set
CONFIG_DUMMY=m CONFIG_DUMMY=m
# CONFIG_BONDING is not set # CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set # CONFIG_EQUALIZER is not set
...@@ -227,6 +255,7 @@ CONFIG_PPP=m ...@@ -227,6 +255,7 @@ CONFIG_PPP=m
# CONFIG_PPP_SYNC_TTY is not set # CONFIG_PPP_SYNC_TTY is not set
# CONFIG_PPP_DEFLATE is not set # CONFIG_PPP_DEFLATE is not set
# CONFIG_PPP_BSDCOMP is not set # CONFIG_PPP_BSDCOMP is not set
# CONFIG_PPP_MPPE is not set
# CONFIG_PPPOE is not set # CONFIG_PPPOE is not set
CONFIG_SLIP=m CONFIG_SLIP=m
# CONFIG_SLIP_COMPRESSED is not set # CONFIG_SLIP_COMPRESSED is not set
...@@ -240,10 +269,12 @@ CONFIG_SLIP=m ...@@ -240,10 +269,12 @@ CONFIG_SLIP=m
# #
CONFIG_EXT2_FS=y CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set # CONFIG_EXT2_FS_XATTR is not set
# CONFIG_EXT2_FS_XIP is not set
CONFIG_EXT3_FS=y CONFIG_EXT3_FS=y
# CONFIG_EXT3_FS_XATTR is not set # CONFIG_EXT3_FS_XATTR is not set
CONFIG_JBD=y CONFIG_JBD=y
# CONFIG_JBD_DEBUG is not set # CONFIG_JBD_DEBUG is not set
# CONFIG_REISER4_FS is not set
CONFIG_REISERFS_FS=y CONFIG_REISERFS_FS=y
# CONFIG_REISERFS_CHECK is not set # CONFIG_REISERFS_CHECK is not set
# CONFIG_REISERFS_PROC_INFO is not set # CONFIG_REISERFS_PROC_INFO is not set
...@@ -256,6 +287,7 @@ CONFIG_REISERFS_FS=y ...@@ -256,6 +287,7 @@ CONFIG_REISERFS_FS=y
# CONFIG_XFS_FS is not set # CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set # CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set # CONFIG_ROMFS_FS is not set
CONFIG_INOTIFY=y
CONFIG_QUOTA=y CONFIG_QUOTA=y
# CONFIG_QFMT_V1 is not set # CONFIG_QFMT_V1 is not set
# CONFIG_QFMT_V2 is not set # CONFIG_QFMT_V2 is not set
...@@ -264,6 +296,12 @@ CONFIG_DNOTIFY=y ...@@ -264,6 +296,12 @@ CONFIG_DNOTIFY=y
CONFIG_AUTOFS_FS=m CONFIG_AUTOFS_FS=m
CONFIG_AUTOFS4_FS=m CONFIG_AUTOFS4_FS=m
#
# Caches
#
# CONFIG_FSCACHE is not set
# CONFIG_FUSE_FS is not set
# #
# CD-ROM/DVD Filesystems # CD-ROM/DVD Filesystems
# #
...@@ -291,6 +329,8 @@ CONFIG_TMPFS=y ...@@ -291,6 +329,8 @@ CONFIG_TMPFS=y
# CONFIG_TMPFS_XATTR is not set # CONFIG_TMPFS_XATTR is not set
# CONFIG_HUGETLB_PAGE is not set # CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
# CONFIG_RELAYFS_FS is not set
# #
# Miscellaneous filesystems # Miscellaneous filesystems
...@@ -319,6 +359,7 @@ CONFIG_RAMFS=y ...@@ -319,6 +359,7 @@ CONFIG_RAMFS=y
# CONFIG_NCP_FS is not set # CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set # CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set # CONFIG_AFS_FS is not set
# CONFIG_9P_FS is not set
# #
# Partition Types # Partition Types
...@@ -404,14 +445,15 @@ CONFIG_CRC32=m ...@@ -404,14 +445,15 @@ CONFIG_CRC32=m
# CONFIG_PRINTK_TIME is not set # CONFIG_PRINTK_TIME is not set
CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=14 CONFIG_LOG_BUF_SHIFT=14
CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_SCHEDSTATS is not set # CONFIG_SCHEDSTATS is not set
# CONFIG_DEBUG_SLAB is not set CONFIG_DEBUG_SLAB=y
# CONFIG_DEBUG_SPINLOCK is not set # CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_KOBJECT is not set # CONFIG_DEBUG_KOBJECT is not set
CONFIG_DEBUG_INFO=y CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_FS is not set # CONFIG_DEBUG_FS is not set
CONFIG_FRAME_POINTER=y CONFIG_FRAME_POINTER=y
CONFIG_PT_PROXY=y # CONFIG_GPROF is not set
# CONFIG_GCOV is not set # CONFIG_GCOV is not set
# CONFIG_SYSCALL_DEBUG is not set # CONFIG_SYSCALL_DEBUG is not set
...@@ -663,11 +663,15 @@ struct tty_driver *line_register_devfs(struct lines *set, ...@@ -663,11 +663,15 @@ struct tty_driver *line_register_devfs(struct lines *set,
return driver; return driver;
} }
static spinlock_t winch_handler_lock;
LIST_HEAD(winch_handlers);
void lines_init(struct line *lines, int nlines) void lines_init(struct line *lines, int nlines)
{ {
struct line *line; struct line *line;
int i; int i;
spin_lock_init(&winch_handler_lock);
for(i = 0; i < nlines; i++){ for(i = 0; i < nlines; i++){
line = &lines[i]; line = &lines[i];
INIT_LIST_HEAD(&line->chan_list); INIT_LIST_HEAD(&line->chan_list);
...@@ -724,31 +728,30 @@ irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused) ...@@ -724,31 +728,30 @@ irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
DECLARE_MUTEX(winch_handler_sem);
LIST_HEAD(winch_handlers);
void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty) void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty)
{ {
struct winch *winch; struct winch *winch;
down(&winch_handler_sem);
winch = kmalloc(sizeof(*winch), GFP_KERNEL); winch = kmalloc(sizeof(*winch), GFP_KERNEL);
if (winch == NULL) { if (winch == NULL) {
printk("register_winch_irq - kmalloc failed\n"); printk("register_winch_irq - kmalloc failed\n");
goto out; return;
} }
*winch = ((struct winch) { .list = LIST_HEAD_INIT(winch->list), *winch = ((struct winch) { .list = LIST_HEAD_INIT(winch->list),
.fd = fd, .fd = fd,
.tty_fd = tty_fd, .tty_fd = tty_fd,
.pid = pid, .pid = pid,
.tty = tty }); .tty = tty });
spin_lock(&winch_handler_lock);
list_add(&winch->list, &winch_handlers); list_add(&winch->list, &winch_handlers);
spin_unlock(&winch_handler_lock);
if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt,
SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
"winch", winch) < 0) "winch", winch) < 0)
printk("register_winch_irq - failed to register IRQ\n"); printk("register_winch_irq - failed to register IRQ\n");
out:
up(&winch_handler_sem);
} }
static void unregister_winch(struct tty_struct *tty) static void unregister_winch(struct tty_struct *tty)
...@@ -756,7 +759,7 @@ static void unregister_winch(struct tty_struct *tty) ...@@ -756,7 +759,7 @@ static void unregister_winch(struct tty_struct *tty)
struct list_head *ele; struct list_head *ele;
struct winch *winch, *found = NULL; struct winch *winch, *found = NULL;
down(&winch_handler_sem); spin_lock(&winch_handler_lock);
list_for_each(ele, &winch_handlers){ list_for_each(ele, &winch_handlers){
winch = list_entry(ele, struct winch, list); winch = list_entry(ele, struct winch, list);
if(winch->tty == tty){ if(winch->tty == tty){
...@@ -764,20 +767,25 @@ static void unregister_winch(struct tty_struct *tty) ...@@ -764,20 +767,25 @@ static void unregister_winch(struct tty_struct *tty)
break; break;
} }
} }
if(found == NULL) if(found == NULL)
goto out; goto err;
list_del(&winch->list);
spin_unlock(&winch_handler_lock);
if(winch->pid != -1) if(winch->pid != -1)
os_kill_process(winch->pid, 1); os_kill_process(winch->pid, 1);
free_irq(WINCH_IRQ, winch); free_irq(WINCH_IRQ, winch);
list_del(&winch->list);
kfree(winch); kfree(winch);
out:
up(&winch_handler_sem); return;
err:
spin_unlock(&winch_handler_lock);
} }
/* XXX: No lock as it's an exitcall... is this valid? Depending on cleanup
* order... are we sure that nothing else is done on the list? */
static void winch_cleanup(void) static void winch_cleanup(void)
{ {
struct list_head *ele; struct list_head *ele;
...@@ -786,6 +794,9 @@ static void winch_cleanup(void) ...@@ -786,6 +794,9 @@ static void winch_cleanup(void)
list_for_each(ele, &winch_handlers){ list_for_each(ele, &winch_handlers){
winch = list_entry(ele, struct winch, list); winch = list_entry(ele, struct winch, list);
if(winch->fd != -1){ if(winch->fd != -1){
/* Why is this different from the above free_irq(),
* which deactivates SIGIO? This searches the FD
* somewhere else and removes it from the list... */
deactivate_fd(winch->fd, WINCH_IRQ); deactivate_fd(winch->fd, WINCH_IRQ);
os_close_file(winch->fd); os_close_file(winch->fd);
} }
......
...@@ -13,6 +13,7 @@ extern int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w); ...@@ -13,6 +13,7 @@ extern int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w);
extern int is_remapped(void *virt); extern int is_remapped(void *virt);
extern int physmem_remove_mapping(void *virt); extern int physmem_remove_mapping(void *virt);
extern void physmem_forget_descriptor(int fd); extern void physmem_forget_descriptor(int fd);
extern unsigned long to_phys(void *virt);
#endif #endif
......
...@@ -14,6 +14,7 @@ extern int restore_fp_registers(int pid, unsigned long *fp_regs); ...@@ -14,6 +14,7 @@ extern int restore_fp_registers(int pid, unsigned long *fp_regs);
extern void save_registers(int pid, union uml_pt_regs *regs); extern void save_registers(int pid, union uml_pt_regs *regs);
extern void restore_registers(int pid, union uml_pt_regs *regs); extern void restore_registers(int pid, union uml_pt_regs *regs);
extern void init_registers(int pid); extern void init_registers(int pid);
extern void get_safe_registers(unsigned long * regs);
#endif #endif
......
...@@ -20,11 +20,24 @@ ...@@ -20,11 +20,24 @@
#define PT_SYSCALL_ARG3_OFFSET PT_OFFSET(EDX) #define PT_SYSCALL_ARG3_OFFSET PT_OFFSET(EDX)
#define PT_SYSCALL_ARG4_OFFSET PT_OFFSET(ESI) #define PT_SYSCALL_ARG4_OFFSET PT_OFFSET(ESI)
#define PT_SYSCALL_ARG5_OFFSET PT_OFFSET(EDI) #define PT_SYSCALL_ARG5_OFFSET PT_OFFSET(EDI)
#define PT_SYSCALL_ARG6_OFFSET PT_OFFSET(EBP)
#define PT_SYSCALL_RET_OFFSET PT_OFFSET(EAX) #define PT_SYSCALL_RET_OFFSET PT_OFFSET(EAX)
#define REGS_SYSCALL_NR EAX /* This is used before a system call */
#define REGS_SYSCALL_ARG1 EBX
#define REGS_SYSCALL_ARG2 ECX
#define REGS_SYSCALL_ARG3 EDX
#define REGS_SYSCALL_ARG4 ESI
#define REGS_SYSCALL_ARG5 EDI
#define REGS_SYSCALL_ARG6 EBP
#define REGS_IP_INDEX EIP
#define REGS_SP_INDEX UESP
#define PT_IP_OFFSET PT_OFFSET(EIP) #define PT_IP_OFFSET PT_OFFSET(EIP)
#define PT_IP(regs) ((regs)[EIP]) #define PT_IP(regs) ((regs)[EIP])
#define PT_SP_OFFSET PT_OFFSET(UESP)
#define PT_SP(regs) ((regs)[UESP]) #define PT_SP(regs) ((regs)[UESP])
#ifndef FRAME_SIZE #ifndef FRAME_SIZE
......
/*
* Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL
*/
#ifndef __SYSDEP_STUB_H
#define __SYSDEP_STUB_H
#include <asm/ptrace.h>
#include <asm/unistd.h>
extern void stub_segv_handler(int sig);
extern void stub_clone_handler(void);
#define STUB_SYSCALL_RET EAX
#define STUB_MMAP_NR __NR_mmap2
#define MMAP_OFFSET(o) ((o) >> PAGE_SHIFT)
static inline long stub_syscall2(long syscall, long arg1, long arg2)
{
long ret;
__asm__("movl %0, %%ecx; " : : "g" (arg2) : "%ecx");
__asm__("movl %0, %%ebx; " : : "g" (arg1) : "%ebx");
__asm__("movl %0, %%eax; " : : "g" (syscall) : "%eax");
__asm__("int $0x80;" : : : "%eax");
__asm__ __volatile__("movl %%eax, %0; " : "=g" (ret) :);
return(ret);
}
static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3)
{
__asm__("movl %0, %%edx; " : : "g" (arg3) : "%edx");
return(stub_syscall2(syscall, arg1, arg2));
}
static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3,
long arg4)
{
__asm__("movl %0, %%esi; " : : "g" (arg4) : "%esi");
return(stub_syscall3(syscall, arg1, arg2, arg3));
}
static inline long stub_syscall6(long syscall, long arg1, long arg2, long arg3,
long arg4, long arg5, long arg6)
{
long ret;
__asm__("movl %0, %%eax; " : : "g" (syscall) : "%eax");
__asm__("movl %0, %%ebx; " : : "g" (arg1) : "%ebx");
__asm__("movl %0, %%ecx; " : : "g" (arg2) : "%ecx");
__asm__("movl %0, %%edx; " : : "g" (arg3) : "%edx");
__asm__("movl %0, %%esi; " : : "g" (arg4) : "%esi");
__asm__("movl %0, %%edi; " : : "g" (arg5) : "%edi");
__asm__ __volatile__("pushl %%ebp ; movl %1, %%ebp; "
"int $0x80; popl %%ebp ; "
"movl %%eax, %0; " : "=g" (ret) : "g" (arg6) : "%eax");
return(ret);
}
static inline void trap_myself(void)
{
__asm("int3");
}
#endif
...@@ -55,6 +55,20 @@ ...@@ -55,6 +55,20 @@
#define PTRACE_OLDSETOPTIONS 21 #define PTRACE_OLDSETOPTIONS 21
#endif #endif
/* These are before the system call, so the the system call number is RAX
* rather than ORIG_RAX, and arg4 is R10 rather than RCX
*/
#define REGS_SYSCALL_NR PT_INDEX(RAX)
#define REGS_SYSCALL_ARG1 PT_INDEX(RDI)
#define REGS_SYSCALL_ARG2 PT_INDEX(RSI)
#define REGS_SYSCALL_ARG3 PT_INDEX(RDX)
#define REGS_SYSCALL_ARG4 PT_INDEX(R10)
#define REGS_SYSCALL_ARG5 PT_INDEX(R8)
#define REGS_SYSCALL_ARG6 PT_INDEX(R9)
#define REGS_IP_INDEX PT_INDEX(RIP)
#define REGS_SP_INDEX PT_INDEX(RSP)
#endif #endif
/* /*
......
/*
* Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL
*/
#ifndef __SYSDEP_STUB_H
#define __SYSDEP_STUB_H
#include <asm/ptrace.h>
#include <asm/unistd.h>
#include <sysdep/ptrace_user.h>
extern void stub_segv_handler(int sig);
extern void stub_clone_handler(void);
#define STUB_SYSCALL_RET PT_INDEX(RAX)
#define STUB_MMAP_NR __NR_mmap
#define MMAP_OFFSET(o) (o)
static inline long stub_syscall2(long syscall, long arg1, long arg2)
{
long ret;
__asm__("movq %0, %%rsi; " : : "g" (arg2) : "%rsi");
__asm__("movq %0, %%rdi; " : : "g" (arg1) : "%rdi");
__asm__("movq %0, %%rax; " : : "g" (syscall) : "%rax");
__asm__("syscall;" : : : "%rax", "%r11", "%rcx");
__asm__ __volatile__("movq %%rax, %0; " : "=g" (ret) :);
return(ret);
}
static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3)
{
__asm__("movq %0, %%rdx; " : : "g" (arg3) : "%rdx");
return(stub_syscall2(syscall, arg1, arg2));
}
static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3,
long arg4)
{
__asm__("movq %0, %%r10; " : : "g" (arg4) : "%r10");
return(stub_syscall3(syscall, arg1, arg2, arg3));
}
static inline long stub_syscall6(long syscall, long arg1, long arg2, long arg3,
long arg4, long arg5, long arg6)
{
__asm__("movq %0, %%r9; " : : "g" (arg6) : "%r9");
__asm__("movq %0, %%r8; " : : "g" (arg5) : "%r8");
return(stub_syscall4(syscall, arg1, arg2, arg3, arg4));
}
static inline void trap_myself(void)
{
__asm("int3");
}
#endif
...@@ -10,6 +10,7 @@ extern void timer(void); ...@@ -10,6 +10,7 @@ extern void timer(void);
extern void switch_timers(int to_real); extern void switch_timers(int to_real);
extern void idle_sleep(int secs); extern void idle_sleep(int secs);
extern void enable_timer(void); extern void enable_timer(void);
extern void prepare_timer(void * ptr);
extern void disable_timer(void); extern void disable_timer(void);
extern unsigned long time_lock(void); extern unsigned long time_lock(void);
extern void time_unlock(unsigned long); extern void time_unlock(unsigned long);
......
...@@ -37,31 +37,25 @@ struct host_vm_op { ...@@ -37,31 +37,25 @@ struct host_vm_op {
extern void mprotect_kernel_vm(int w); extern void mprotect_kernel_vm(int w);
extern void force_flush_all(void); extern void force_flush_all(void);
extern void fix_range_common(struct mm_struct *mm, unsigned long start_addr, extern void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
unsigned long end_addr, int force, int data, unsigned long end_addr, int force,
void (*do_ops)(int, struct host_vm_op *, int)); void (*do_ops)(union mm_context *,
struct host_vm_op *, int));
extern int flush_tlb_kernel_range_common(unsigned long start, extern int flush_tlb_kernel_range_common(unsigned long start,
unsigned long end); unsigned long end);
extern int add_mmap(unsigned long virt, unsigned long phys, unsigned long len, extern int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
int r, int w, int x, struct host_vm_op *ops, int index, int r, int w, int x, struct host_vm_op *ops, int index,
int last_filled, int data, int last_filled, union mm_context *mmu,
void (*do_ops)(int, struct host_vm_op *, int)); void (*do_ops)(union mm_context *, struct host_vm_op *,
int));
extern int add_munmap(unsigned long addr, unsigned long len, extern int add_munmap(unsigned long addr, unsigned long len,
struct host_vm_op *ops, int index, int last_filled, struct host_vm_op *ops, int index, int last_filled,
int data, void (*do_ops)(int, struct host_vm_op *, int)); union mm_context *mmu,
void (*do_ops)(union mm_context *, struct host_vm_op *,
int));
extern int add_mprotect(unsigned long addr, unsigned long len, int r, int w, extern int add_mprotect(unsigned long addr, unsigned long len, int r, int w,
int x, struct host_vm_op *ops, int index, int x, struct host_vm_op *ops, int index,
int last_filled, int data, int last_filled, union mm_context *mmu,
void (*do_ops)(int, struct host_vm_op *, int)); void (*do_ops)(union mm_context *, struct host_vm_op *,
int));
#endif #endif
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/
...@@ -67,6 +67,12 @@ SECTIONS ...@@ -67,6 +67,12 @@ SECTIONS
*(.stub .text.* .gnu.linkonce.t.*) *(.stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf32.em. */ /* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning) *(.gnu.warning)
. = ALIGN(4096);
__syscall_stub_start = .;
*(.__syscall_stub*)
__syscall_stub_end = .;
. = ALIGN(4096);
} =0x90909090 } =0x90909090
.fini : { .fini : {
KEEP (*(.fini)) KEEP (*(.fini))
......
...@@ -353,6 +353,8 @@ void map_memory(unsigned long virt, unsigned long phys, unsigned long len, ...@@ -353,6 +353,8 @@ void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
extern int __syscall_stub_start, __binary_start;
void setup_physmem(unsigned long start, unsigned long reserve_end, void setup_physmem(unsigned long start, unsigned long reserve_end,
unsigned long len, unsigned long highmem) unsigned long len, unsigned long highmem)
{ {
...@@ -371,6 +373,12 @@ void setup_physmem(unsigned long start, unsigned long reserve_end, ...@@ -371,6 +373,12 @@ void setup_physmem(unsigned long start, unsigned long reserve_end,
exit(1); exit(1);
} }
/* Special kludge - This page will be mapped in to userspace processes
* from physmem_fd, so it needs to be written out there.
*/
os_seek_file(physmem_fd, __pa(&__syscall_stub_start));
os_write_file(physmem_fd, &__syscall_stub_start, PAGE_SIZE);
bootmap_size = init_bootmem(pfn, pfn + delta); bootmap_size = init_bootmem(pfn, pfn + delta);
free_bootmem(__pa(reserve_end) + bootmap_size, free_bootmem(__pa(reserve_end) + bootmap_size,
len - bootmap_size - reserve); len - bootmap_size - reserve);
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "uml-config.h" #include "uml-config.h"
#include "choose-mode.h" #include "choose-mode.h"
#include "mode.h" #include "mode.h"
#include "tempfile.h"
#ifdef UML_CONFIG_MODE_SKAS #ifdef UML_CONFIG_MODE_SKAS
#include "skas.h" #include "skas.h"
#include "skas_ptrace.h" #include "skas_ptrace.h"
...@@ -358,11 +359,16 @@ void forward_pending_sigio(int target) ...@@ -358,11 +359,16 @@ void forward_pending_sigio(int target)
kill(target, SIGIO); kill(target, SIGIO);
} }
int ptrace_faultinfo = 0;
int proc_mm = 1;
extern void *__syscall_stub_start, __syscall_stub_end;
#ifdef UML_CONFIG_MODE_SKAS #ifdef UML_CONFIG_MODE_SKAS
static inline int check_skas3_ptrace_support(void) static inline void check_skas3_ptrace_support(void)
{ {
struct ptrace_faultinfo fi; struct ptrace_faultinfo fi;
int pid, n, ret = 1; int pid, n;
printf("Checking for the skas3 patch in the host..."); printf("Checking for the skas3 patch in the host...");
pid = start_ptraced_child(); pid = start_ptraced_child();
...@@ -374,33 +380,31 @@ static inline int check_skas3_ptrace_support(void) ...@@ -374,33 +380,31 @@ static inline int check_skas3_ptrace_support(void)
else { else {
perror("not found"); perror("not found");
} }
ret = 0; }
} else { else {
ptrace_faultinfo = 1;
printf("found\n"); printf("found\n");
} }
init_registers(pid); init_registers(pid);
stop_ptraced_child(pid, 1, 1); stop_ptraced_child(pid, 1, 1);
return(ret);
} }
int can_do_skas(void) int can_do_skas(void)
{ {
int ret = 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) {
proc_mm = 0;
printf("not found\n"); printf("not found\n");
ret = 0;
goto out; goto out;
} else { }
else {
printf("found\n"); printf("found\n");
} }
ret = check_skas3_ptrace_support();
out: out:
return ret; check_skas3_ptrace_support();
return 1;
} }
#else #else
int can_do_skas(void) int can_do_skas(void)
......
...@@ -3,11 +3,14 @@ ...@@ -3,11 +3,14 @@
# Licensed under the GPL # Licensed under the GPL
# #
obj-y := exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \ obj-y := clone.o exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \
syscall_kern.o syscall_user.o tlb.o trap_user.o uaccess.o \ syscall_kern.o syscall_user.o tlb.o trap_user.o uaccess.o \
subdir- := util subdir- := util
USER_OBJS := process.o USER_OBJS := process.o clone.o
include arch/um/scripts/Makefile.rules include arch/um/scripts/Makefile.rules
# clone.o is in the stub, so it can't be built with profiling
$(obj)/clone.o : c_flags = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS))
#include <sched.h>
#include <signal.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <asm/unistd.h>
#include <asm/page.h>
#include "ptrace_user.h"
#include "skas.h"
#include "stub-data.h"
#include "uml-config.h"
#include "sysdep/stub.h"
/* This is in a separate file because it needs to be compiled with any
* extraneous gcc flags (-pg, -fprofile-arcs, -ftest-coverage) disabled
*/
void __attribute__ ((__section__ (".__syscall_stub")))
stub_clone_handler(void)
{
long err;
struct stub_data *from = (struct stub_data *) UML_CONFIG_STUB_DATA;
err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD,
UML_CONFIG_STUB_DATA + PAGE_SIZE / 2 -
sizeof(void *));
if(err != 0)
goto out;
err = stub_syscall4(__NR_ptrace, PTRACE_TRACEME, 0, 0, 0);
if(err)
goto out;
err = stub_syscall3(__NR_setitimer, ITIMER_VIRTUAL,
(long) &from->timer, 0);
if(err)
goto out;
err = stub_syscall6(STUB_MMAP_NR, UML_CONFIG_STUB_DATA, PAGE_SIZE,
PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED,
from->fd, from->offset);
out:
/* save current result. Parent: pid; child: retcode of mmap */
from->err = err;
trap_myself();
}
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
void flush_thread_skas(void) void flush_thread_skas(void)
{ {
force_flush_all(); force_flush_all();
switch_mm_skas(current->mm->context.skas.mm_fd); switch_mm_skas(&current->mm->context.skas.id);
} }
void start_thread_skas(struct pt_regs *regs, unsigned long eip, void start_thread_skas(struct pt_regs *regs, unsigned long eip,
......
/*
* Copyright (C) 2005 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __MM_ID_H
#define __MM_ID_H
struct mm_id {
union {
int mm_fd;
int pid;
} u;
unsigned long stack;
};
#endif
...@@ -6,10 +6,15 @@ ...@@ -6,10 +6,15 @@
#ifndef __SKAS_MMU_H #ifndef __SKAS_MMU_H
#define __SKAS_MMU_H #define __SKAS_MMU_H
#include "mm_id.h"
struct mmu_context_skas { struct mmu_context_skas {
int mm_fd; struct mm_id id;
unsigned long last_page_table;
}; };
extern void switch_mm_skas(struct mm_id * mm_idp);
#endif #endif
/* /*
......
...@@ -6,9 +6,11 @@ ...@@ -6,9 +6,11 @@
#ifndef __SKAS_H #ifndef __SKAS_H
#define __SKAS_H #define __SKAS_H
#include "mm_id.h"
#include "sysdep/ptrace.h" #include "sysdep/ptrace.h"
extern int userspace_pid[]; extern int userspace_pid[];
extern int proc_mm, ptrace_faultinfo;
extern void switch_threads(void *me, void *next); extern void switch_threads(void *me, void *next);
extern void thread_wait(void *sw, void *fb); extern void thread_wait(void *sw, void *fb);
...@@ -22,16 +24,18 @@ extern void new_thread_proc(void *stack, void (*handler)(int sig)); ...@@ -22,16 +24,18 @@ extern void new_thread_proc(void *stack, void (*handler)(int sig));
extern void remove_sigstack(void); extern void remove_sigstack(void);
extern void new_thread_handler(int sig); extern void new_thread_handler(int sig);
extern void handle_syscall(union uml_pt_regs *regs); extern void handle_syscall(union uml_pt_regs *regs);
extern void map(int fd, unsigned long virt, unsigned long len, int r, int w, extern int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len,
int x, int phys_fd, unsigned long long offset); int r, int w, int x, int phys_fd, unsigned long long offset);
extern int unmap(int fd, void *addr, unsigned long len); extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len);
extern int protect(int fd, unsigned long addr, unsigned long len, extern int protect(struct mm_id * mm_idp, unsigned long addr,
int r, int w, int x); unsigned long len, int r, int w, int x);
extern void user_signal(int sig, union uml_pt_regs *regs, int pid); extern void user_signal(int sig, union uml_pt_regs *regs, int pid);
extern int new_mm(int from); extern int new_mm(int from);
extern void start_userspace(int cpu); extern int start_userspace(unsigned long stub_stack);
extern int copy_context_skas0(unsigned long stack, int pid);
extern void get_skas_faultinfo(int pid, struct faultinfo * fi); extern void get_skas_faultinfo(int pid, struct faultinfo * fi);
extern long execute_syscall_skas(void *r); extern long execute_syscall_skas(void *r);
extern unsigned long current_stub_stack(void);
#endif #endif
......
/*
* Copyright (C) 2005 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __STUB_DATA_H
#define __STUB_DATA_H
#include <sys/time.h>
struct stub_data {
long offset;
int fd;
struct itimerval timer;
long err;
};
#endif
...@@ -5,7 +5,9 @@ ...@@ -5,7 +5,9 @@
#include "linux/config.h" #include "linux/config.h"
#include "linux/mm.h" #include "linux/mm.h"
#include "asm/pgtable.h"
#include "mem_user.h" #include "mem_user.h"
#include "skas.h"
unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out, unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
unsigned long *task_size_out) unsigned long *task_size_out)
...@@ -18,7 +20,9 @@ unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out, ...@@ -18,7 +20,9 @@ unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
*task_size_out = CONFIG_HOST_TASK_SIZE; *task_size_out = CONFIG_HOST_TASK_SIZE;
#else #else
*host_size_out = top; *host_size_out = top;
*task_size_out = top; if (proc_mm && ptrace_faultinfo)
*task_size_out = top;
else *task_size_out = CONFIG_STUB_START & PGDIR_MASK;
#endif #endif
return(((unsigned long) set_task_sizes_skas) & ~0xffffff); return(((unsigned long) set_task_sizes_skas) & ~0xffffff);
} }
......
...@@ -3,100 +3,171 @@ ...@@ -3,100 +3,171 @@
* Licensed under the GPL * Licensed under the GPL
*/ */
#include <signal.h>
#include <errno.h> #include <errno.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/wait.h>
#include <asm/page.h>
#include <asm/unistd.h>
#include "mem_user.h" #include "mem_user.h"
#include "mem.h" #include "mem.h"
#include "mm_id.h"
#include "user.h" #include "user.h"
#include "os.h" #include "os.h"
#include "proc_mm.h" #include "proc_mm.h"
#include "ptrace_user.h"
void map(int fd, unsigned long virt, unsigned long len, int r, int w, #include "user_util.h"
int x, int phys_fd, unsigned long long offset) #include "kern_util.h"
#include "task.h"
#include "registers.h"
#include "uml-config.h"
#include "sysdep/ptrace.h"
#include "sysdep/stub.h"
#include "skas.h"
extern unsigned long syscall_stub, __syscall_stub_start;
extern void wait_stub_done(int pid, int sig, char * fname);
static long run_syscall_stub(struct mm_id * mm_idp, int syscall,
unsigned long *args)
{ {
struct proc_mm_op map; int n, pid = mm_idp->u.pid;
int prot, n; unsigned long regs[MAX_REG_NR];
prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | get_safe_registers(regs);
(x ? PROT_EXEC : 0); regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
((unsigned long) &syscall_stub -
map = ((struct proc_mm_op) { .op = MM_MMAP, (unsigned long) &__syscall_stub_start);
.u = /* XXX Don't have a define for starting a syscall */
{ .mmap = regs[REGS_SYSCALL_NR] = syscall;
{ .addr = virt, regs[REGS_SYSCALL_ARG1] = args[0];
.len = len, regs[REGS_SYSCALL_ARG2] = args[1];
.prot = prot, regs[REGS_SYSCALL_ARG3] = args[2];
.flags = MAP_SHARED | regs[REGS_SYSCALL_ARG4] = args[3];
MAP_FIXED, regs[REGS_SYSCALL_ARG5] = args[4];
.fd = phys_fd, regs[REGS_SYSCALL_ARG6] = args[5];
.offset = offset n = ptrace_setregs(pid, regs);
} } } ); if(n < 0){
n = os_write_file(fd, &map, sizeof(map)); printk("run_syscall_stub : PTRACE_SETREGS failed, "
if(n != sizeof(map)) "errno = %d\n", n);
printk("map : /proc/mm map failed, err = %d\n", -n); return(n);
}
wait_stub_done(pid, 0, "run_syscall_stub");
return(*((unsigned long *) mm_idp->stack));
} }
int unmap(int fd, void *addr, unsigned long len) int map(struct mm_id *mm_idp, unsigned long virt, unsigned long len,
int r, int w, int x, int phys_fd, unsigned long long offset)
{ {
struct proc_mm_op unmap; int prot, n;
int n;
prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
unmap = ((struct proc_mm_op) { .op = MM_MUNMAP, (x ? PROT_EXEC : 0);
.u =
{ .munmap = if(proc_mm){
{ .addr = (unsigned long) addr, struct proc_mm_op map;
.len = len } } } ); int fd = mm_idp->u.mm_fd;
n = os_write_file(fd, &unmap, sizeof(unmap)); map = ((struct proc_mm_op) { .op = MM_MMAP,
if(n != sizeof(unmap)) { .u =
if(n < 0) { .mmap =
return(n); { .addr = virt,
else if(n > 0) .len = len,
return(-EIO); .prot = prot,
} .flags = MAP_SHARED |
MAP_FIXED,
return(0); .fd = phys_fd,
.offset= offset
} } } );
n = os_write_file(fd, &map, sizeof(map));
if(n != sizeof(map))
printk("map : /proc/mm map failed, err = %d\n", -n);
}
else {
long res;
unsigned long args[] = { virt, len, prot,
MAP_SHARED | MAP_FIXED, phys_fd,
MMAP_OFFSET(offset) };
res = run_syscall_stub(mm_idp, STUB_MMAP_NR, args);
if((void *) res == MAP_FAILED)
printk("mmap stub failed, errno = %d\n", res);
}
return 0;
} }
int protect(int fd, unsigned long addr, unsigned long len, int r, int w, int unmap(struct mm_id *mm_idp, void *addr, unsigned long len)
int x, int must_succeed)
{ {
struct proc_mm_op protect; int n;
int prot, n;
if(proc_mm){
prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | struct proc_mm_op unmap;
(x ? PROT_EXEC : 0); int fd = mm_idp->u.mm_fd;
unmap = ((struct proc_mm_op) { .op = MM_MUNMAP,
protect = ((struct proc_mm_op) { .op = MM_MPROTECT, .u =
.u = { .munmap =
{ .mprotect = { .addr =
{ .addr = (unsigned long) addr, (unsigned long) addr,
.len = len, .len = len } } } );
.prot = prot } } } ); n = os_write_file(fd, &unmap, sizeof(unmap));
if(n != sizeof(unmap)) {
n = os_write_file(fd, &protect, sizeof(protect)); if(n < 0)
if(n != sizeof(protect)) { return(n);
if(n == 0) return(0); else if(n > 0)
return(-EIO);
if(must_succeed) }
panic("protect failed, err = %d", -n); }
else {
return(-EIO); int res;
} unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0,
0 };
res = run_syscall_stub(mm_idp, __NR_munmap, args);
if(res < 0)
printk("munmap stub failed, errno = %d\n", res);
}
return(0);
}
return(0); int protect(struct mm_id *mm_idp, unsigned long addr, unsigned long len,
int r, int w, int x)
{
struct proc_mm_op protect;
int prot, n;
prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
(x ? PROT_EXEC : 0);
if(proc_mm){
int fd = mm_idp->u.mm_fd;
protect = ((struct proc_mm_op) { .op = MM_MPROTECT,
.u =
{ .mprotect =
{ .addr =
(unsigned long) addr,
.len = len,
.prot = prot } } } );
n = os_write_file(fd, &protect, sizeof(protect));
if(n != sizeof(protect))
panic("protect failed, err = %d", -n);
}
else {
int res;
unsigned long args[] = { addr, len, prot, 0, 0, 0 };
res = run_syscall_stub(mm_idp, __NR_mprotect, args);
if(res < 0)
panic("mprotect stub failed, errno = %d\n", res);
}
return(0);
} }
void before_mem_skas(unsigned long unused) void before_mem_skas(unsigned long unused)
{ {
} }
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/
...@@ -3,46 +3,143 @@ ...@@ -3,46 +3,143 @@
* Licensed under the GPL * Licensed under the GPL
*/ */
#include "linux/config.h"
#include "linux/sched.h" #include "linux/sched.h"
#include "linux/list.h" #include "linux/list.h"
#include "linux/spinlock.h" #include "linux/spinlock.h"
#include "linux/slab.h" #include "linux/slab.h"
#include "linux/errno.h"
#include "linux/mm.h"
#include "asm/current.h" #include "asm/current.h"
#include "asm/segment.h" #include "asm/segment.h"
#include "asm/mmu.h" #include "asm/mmu.h"
#include "asm/pgalloc.h"
#include "asm/pgtable.h"
#include "os.h" #include "os.h"
#include "skas.h" #include "skas.h"
extern int __syscall_stub_start;
static int init_stub_pte(struct mm_struct *mm, unsigned long proc,
unsigned long kernel)
{
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
pte_t *pte;
spin_lock(&mm->page_table_lock);
pgd = pgd_offset(mm, proc);
pud = pud_alloc(mm, pgd, proc);
if (!pud)
goto out;
pmd = pmd_alloc(mm, pud, proc);
if (!pmd)
goto out_pmd;
pte = pte_alloc_map(mm, pmd, proc);
if (!pte)
goto out_pte;
/* There's an interaction between the skas0 stub pages, stack
* randomization, and the BUG at the end of exit_mmap. exit_mmap
* checks that the number of page tables freed is the same as had
* been allocated. If the stack is on the last page table page,
* then the stack pte page will be freed, and if not, it won't. To
* avoid having to know where the stack is, or if the process mapped
* something at the top of its address space for some other reason,
* we set TASK_SIZE to end at the start of the last page table.
* This keeps exit_mmap off the last page, but introduces a leak
* of that page. So, we hang onto it here and free it in
* destroy_context_skas.
*/
mm->context.skas.last_page_table = pmd_page_kernel(*pmd);
*pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT));
*pte = pte_mkexec(*pte);
*pte = pte_wrprotect(*pte);
spin_unlock(&mm->page_table_lock);
return(0);
out_pmd:
pud_free(pud);
out_pte:
pmd_free(pmd);
out:
spin_unlock(&mm->page_table_lock);
return(-ENOMEM);
}
int init_new_context_skas(struct task_struct *task, struct mm_struct *mm) int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
{ {
int from; struct mm_struct *cur_mm = current->mm;
struct mm_id *cur_mm_id = &cur_mm->context.skas.id;
struct mm_id *mm_id = &mm->context.skas.id;
unsigned long stack;
int from, ret;
if((current->mm != NULL) && (current->mm != &init_mm)) if(proc_mm){
from = current->mm->context.skas.mm_fd; if((cur_mm != NULL) && (cur_mm != &init_mm))
else from = -1; from = cur_mm->context.skas.id.u.mm_fd;
else from = -1;
mm->context.skas.mm_fd = new_mm(from); ret = new_mm(from);
if(mm->context.skas.mm_fd < 0){ if(ret < 0){
printk("init_new_context_skas - new_mm failed, errno = %d\n", printk("init_new_context_skas - new_mm failed, "
mm->context.skas.mm_fd); "errno = %d\n", ret);
return(mm->context.skas.mm_fd); return ret;
}
mm_id->u.mm_fd = ret;
} }
else {
/* This zeros the entry that pgd_alloc didn't, needed since
* we are about to reinitialize it, and want mm.nr_ptes to
* be accurate.
*/
mm->pgd[USER_PTRS_PER_PGD] = __pgd(0);
return(0); ret = init_stub_pte(mm, CONFIG_STUB_CODE,
(unsigned long) &__syscall_stub_start);
if(ret)
goto out;
ret = -ENOMEM;
stack = get_zeroed_page(GFP_KERNEL);
if(stack == 0)
goto out;
mm_id->stack = stack;
ret = init_stub_pte(mm, CONFIG_STUB_DATA, stack);
if(ret)
goto out_free;
mm->nr_ptes--;
if((cur_mm != NULL) && (cur_mm != &init_mm))
mm_id->u.pid = copy_context_skas0(stack,
cur_mm_id->u.pid);
else mm_id->u.pid = start_userspace(stack);
}
return 0;
out_free:
free_page(mm_id->stack);
out:
return ret;
} }
void destroy_context_skas(struct mm_struct *mm) void destroy_context_skas(struct mm_struct *mm)
{ {
os_close_file(mm->context.skas.mm_fd); struct mmu_context_skas *mmu = &mm->context.skas;
}
/* if(proc_mm)
* Overrides for Emacs so that we follow Linus's tabbing style. os_close_file(mmu->id.u.mm_fd);
* Emacs will notice this stuff at the end of the file and automatically else {
* adjust the settings for this buffer only. This must remain at the end os_kill_ptraced_process(mmu->id.u.pid, 1);
* of the file. free_page(mmu->id.stack);
* --------------------------------------------------------------------------- free_page(mmu->last_page_table);
* Local variables: }
* c-file-style: "linux" }
* End:
*/
/* /*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Copyright (C) 2002- 2004 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL * Licensed under the GPL
*/ */
...@@ -13,7 +13,9 @@ ...@@ -13,7 +13,9 @@
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/user.h> #include <sys/user.h>
#include <sys/time.h>
#include <asm/unistd.h> #include <asm/unistd.h>
#include <asm/types.h>
#include "user.h" #include "user.h"
#include "ptrace_user.h" #include "ptrace_user.h"
#include "time_user.h" #include "time_user.h"
...@@ -21,13 +23,18 @@ ...@@ -21,13 +23,18 @@
#include "user_util.h" #include "user_util.h"
#include "kern_util.h" #include "kern_util.h"
#include "skas.h" #include "skas.h"
#include "stub-data.h"
#include "mm_id.h"
#include "sysdep/sigcontext.h" #include "sysdep/sigcontext.h"
#include "sysdep/stub.h"
#include "os.h" #include "os.h"
#include "proc_mm.h" #include "proc_mm.h"
#include "skas_ptrace.h" #include "skas_ptrace.h"
#include "chan_user.h" #include "chan_user.h"
#include "signal_user.h" #include "signal_user.h"
#include "registers.h" #include "registers.h"
#include "mem.h"
#include "uml-config.h"
#include "process.h" #include "process.h"
int is_skas_winch(int pid, int fd, void *data) int is_skas_winch(int pid, int fd, void *data)
...@@ -39,20 +46,55 @@ int is_skas_winch(int pid, int fd, void *data) ...@@ -39,20 +46,55 @@ int is_skas_winch(int pid, int fd, void *data)
return(1); return(1);
} }
void get_skas_faultinfo(int pid, struct faultinfo * fi) void wait_stub_done(int pid, int sig, char * fname)
{ {
int err; int n, status, err;
err = ptrace(PTRACE_FAULTINFO, pid, 0, fi); do {
if(err) if ( sig != -1 ) {
panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, " err = ptrace(PTRACE_CONT, pid, 0, sig);
"errno = %d\n", errno); if(err)
panic("%s : continue failed, errno = %d\n",
fname, errno);
}
sig = 0;
CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
} while((n >= 0) && WIFSTOPPED(status) &&
(WSTOPSIG(status) == SIGVTALRM));
if((n < 0) || !WIFSTOPPED(status) ||
(WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status != SIGTRAP))){
panic("%s : failed to wait for SIGUSR1/SIGTRAP, "
"pid = %d, n = %d, errno = %d, status = 0x%x\n",
fname, pid, n, errno, status);
}
}
/* Special handling for i386, which has different structs */ void get_skas_faultinfo(int pid, struct faultinfo * fi)
if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo)) {
memset((char *)fi + sizeof(struct ptrace_faultinfo), 0, int err;
sizeof(struct faultinfo) -
sizeof(struct ptrace_faultinfo)); if(ptrace_faultinfo){
err = ptrace(PTRACE_FAULTINFO, pid, 0, fi);
if(err)
panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, "
"errno = %d\n", errno);
/* Special handling for i386, which has different structs */
if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo))
memset((char *)fi + sizeof(struct ptrace_faultinfo), 0,
sizeof(struct faultinfo) -
sizeof(struct ptrace_faultinfo));
}
else {
wait_stub_done(pid, SIGSEGV, "get_skas_faultinfo");
/* faultinfo is prepared by the stub-segv-handler at start of
* the stub stack page. We just have to copy it.
*/
memcpy(fi, (void *)current_stub_stack(), sizeof(*fi));
}
} }
static void handle_segv(int pid, union uml_pt_regs * regs) static void handle_segv(int pid, union uml_pt_regs * regs)
...@@ -91,11 +133,56 @@ static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu ...@@ -91,11 +133,56 @@ static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu
handle_syscall(regs); handle_syscall(regs);
} }
static int userspace_tramp(void *arg) extern int __syscall_stub_start;
static int userspace_tramp(void *stack)
{ {
init_new_thread_signals(0); void *addr;
enable_timer();
ptrace(PTRACE_TRACEME, 0, 0, 0); ptrace(PTRACE_TRACEME, 0, 0, 0);
init_new_thread_signals(1);
enable_timer();
if(!proc_mm){
/* This has a pte, but it can't be mapped in with the usual
* tlb_flush mechanism because this is part of that mechanism
*/
int fd;
__u64 offset;
fd = phys_mapping(to_phys(&__syscall_stub_start), &offset);
addr = mmap64((void *) UML_CONFIG_STUB_CODE, page_size(),
PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset);
if(addr == MAP_FAILED){
printk("mapping mmap stub failed, errno = %d\n",
errno);
exit(1);
}
if(stack != NULL){
fd = phys_mapping(to_phys(stack), &offset);
addr = mmap((void *) UML_CONFIG_STUB_DATA, page_size(),
PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_SHARED, fd, offset);
if(addr == MAP_FAILED){
printk("mapping segfault stack failed, "
"errno = %d\n", errno);
exit(1);
}
}
}
if(!ptrace_faultinfo && (stack != NULL)){
unsigned long v = UML_CONFIG_STUB_CODE +
(unsigned long) stub_segv_handler -
(unsigned long) &__syscall_stub_start;
set_sigstack((void *) UML_CONFIG_STUB_DATA, page_size());
set_handler(SIGSEGV, (void *) v, SA_ONSTACK,
SIGIO, SIGWINCH, SIGALRM, SIGVTALRM,
SIGUSR1, -1);
}
os_stop_process(os_getpid()); os_stop_process(os_getpid());
return(0); return(0);
} }
...@@ -105,11 +192,11 @@ static int userspace_tramp(void *arg) ...@@ -105,11 +192,11 @@ static int userspace_tramp(void *arg)
#define NR_CPUS 1 #define NR_CPUS 1
int userspace_pid[NR_CPUS]; int userspace_pid[NR_CPUS];
void start_userspace(int cpu) int start_userspace(unsigned long stub_stack)
{ {
void *stack; void *stack;
unsigned long sp; unsigned long sp;
int pid, status, n; int pid, status, n, flags;
stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
...@@ -117,8 +204,9 @@ void start_userspace(int cpu) ...@@ -117,8 +204,9 @@ void start_userspace(int cpu)
panic("start_userspace : mmap failed, errno = %d", errno); panic("start_userspace : mmap failed, errno = %d", errno);
sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *); sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
pid = clone(userspace_tramp, (void *) sp, flags = CLONE_FILES | SIGCHLD;
CLONE_FILES | CLONE_VM | SIGCHLD, NULL); if(proc_mm) flags |= CLONE_VM;
pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack);
if(pid < 0) if(pid < 0)
panic("start_userspace : clone failed, errno = %d", errno); panic("start_userspace : clone failed, errno = %d", errno);
...@@ -140,7 +228,7 @@ void start_userspace(int cpu) ...@@ -140,7 +228,7 @@ void start_userspace(int cpu)
if(munmap(stack, PAGE_SIZE) < 0) if(munmap(stack, PAGE_SIZE) < 0)
panic("start_userspace : munmap failed, errno = %d\n", errno); panic("start_userspace : munmap failed, errno = %d\n", errno);
userspace_pid[cpu] = pid; return(pid);
} }
void userspace(union uml_pt_regs *regs) void userspace(union uml_pt_regs *regs)
...@@ -174,7 +262,9 @@ void userspace(union uml_pt_regs *regs) ...@@ -174,7 +262,9 @@ void userspace(union uml_pt_regs *regs)
if(WIFSTOPPED(status)){ if(WIFSTOPPED(status)){
switch(WSTOPSIG(status)){ switch(WSTOPSIG(status)){
case SIGSEGV: case SIGSEGV:
handle_segv(pid, regs); if(PTRACE_FULL_FAULTINFO || !ptrace_faultinfo)
user_signal(SIGSEGV, regs, pid);
else handle_segv(pid, regs);
break; break;
case SIGTRAP + 0x80: case SIGTRAP + 0x80:
handle_trap(pid, regs, local_using_sysemu); handle_trap(pid, regs, local_using_sysemu);
...@@ -194,6 +284,7 @@ void userspace(union uml_pt_regs *regs) ...@@ -194,6 +284,7 @@ void userspace(union uml_pt_regs *regs)
printk("userspace - child stopped with signal " printk("userspace - child stopped with signal "
"%d\n", WSTOPSIG(status)); "%d\n", WSTOPSIG(status));
} }
pid = userspace_pid[0];
interrupt_end(); interrupt_end();
/* Avoid -ERESTARTSYS handling in host */ /* Avoid -ERESTARTSYS handling in host */
...@@ -207,6 +298,67 @@ void userspace(union uml_pt_regs *regs) ...@@ -207,6 +298,67 @@ void userspace(union uml_pt_regs *regs)
#define INIT_JMP_HALT 3 #define INIT_JMP_HALT 3
#define INIT_JMP_REBOOT 4 #define INIT_JMP_REBOOT 4
int copy_context_skas0(unsigned long new_stack, int pid)
{
int err;
unsigned long regs[MAX_REG_NR];
unsigned long current_stack = current_stub_stack();
struct stub_data *data = (struct stub_data *) current_stack;
struct stub_data *child_data = (struct stub_data *) new_stack;
__u64 new_offset;
int new_fd = phys_mapping(to_phys((void *)new_stack), &new_offset);
/* prepare offset and fd of child's stack as argument for parent's
* and child's mmap2 calls
*/
*data = ((struct stub_data) { .offset = MMAP_OFFSET(new_offset),
.fd = new_fd,
.timer = ((struct itimerval)
{ { 0, 1000000 / hz() },
{ 0, 1000000 / hz() }})});
get_safe_registers(regs);
/* Set parent's instruction pointer to start of clone-stub */
regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
(unsigned long) stub_clone_handler -
(unsigned long) &__syscall_stub_start;
regs[REGS_SP_INDEX] = UML_CONFIG_STUB_DATA + PAGE_SIZE -
sizeof(void *);
err = ptrace_setregs(pid, regs);
if(err < 0)
panic("copy_context_skas0 : PTRACE_SETREGS failed, "
"pid = %d, errno = %d\n", pid, errno);
/* set a well known return code for detection of child write failure */
child_data->err = 12345678;
/* Wait, until parent has finished its work: read child's pid from
* parent's stack, and check, if bad result.
*/
wait_stub_done(pid, 0, "copy_context_skas0");
pid = data->err;
if(pid < 0)
panic("copy_context_skas0 - stub-parent reports error %d\n",
pid);
/* Wait, until child has finished too: read child's result from
* child's stack and check it.
*/
wait_stub_done(pid, -1, "copy_context_skas0");
if (child_data->err != UML_CONFIG_STUB_DATA)
panic("copy_context_skas0 - stub-child reports error %d\n",
child_data->err);
if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL,
(void *)PTRACE_O_TRACESYSGOOD) < 0)
panic("copy_context_skas0 : PTRACE_SETOPTIONS failed, "
"errno = %d\n", errno);
return pid;
}
void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
void (*handler)(int)) void (*handler)(int))
{ {
...@@ -334,21 +486,19 @@ void reboot_skas(void) ...@@ -334,21 +486,19 @@ void reboot_skas(void)
siglongjmp(initial_jmpbuf, INIT_JMP_REBOOT); siglongjmp(initial_jmpbuf, INIT_JMP_REBOOT);
} }
void switch_mm_skas(int mm_fd) void switch_mm_skas(struct mm_id *mm_idp)
{ {
int err; int err;
#warning need cpu pid in switch_mm_skas #warning need cpu pid in switch_mm_skas
err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, mm_fd); if(proc_mm){
if(err) err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0,
panic("switch_mm_skas - PTRACE_SWITCH_MM failed, errno = %d\n", mm_idp->u.mm_fd);
errno); if(err)
} panic("switch_mm_skas - PTRACE_SWITCH_MM failed, "
"errno = %d\n", errno);
void kill_off_processes_skas(void) }
{ else userspace_pid[0] = mm_idp->u.pid;
#warning need to loop over userspace_pids in kill_off_processes_skas
os_kill_ptraced_process(userspace_pid[0], 1);
} }
/* /*
......
...@@ -175,9 +175,12 @@ static int start_kernel_proc(void *unused) ...@@ -175,9 +175,12 @@ static int start_kernel_proc(void *unused)
return(0); return(0);
} }
extern int userspace_pid[];
int start_uml_skas(void) int start_uml_skas(void)
{ {
start_userspace(0); if(proc_mm)
userspace_pid[0] = start_userspace(0);
init_new_thread_signals(1); init_new_thread_signals(1);
...@@ -199,3 +202,31 @@ int thread_pid_skas(struct task_struct *task) ...@@ -199,3 +202,31 @@ int thread_pid_skas(struct task_struct *task)
#warning Need to look up userspace_pid by cpu #warning Need to look up userspace_pid by cpu
return(userspace_pid[0]); return(userspace_pid[0]);
} }
void kill_off_processes_skas(void)
{
if(proc_mm)
#warning need to loop over userspace_pids in kill_off_processes_skas
os_kill_ptraced_process(userspace_pid[0], 1);
else {
struct task_struct *p;
int pid, me;
me = os_getpid();
for_each_process(p){
if(p->mm == NULL)
continue;
pid = p->mm->context.skas.id.u.pid;
os_kill_ptraced_process(pid, 1);
}
}
}
unsigned long current_stub_stack(void)
{
if(current->mm == NULL)
return(0);
return(current->mm->context.skas.id.stack);
}
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "linux/stddef.h" #include "linux/stddef.h"
#include "linux/sched.h" #include "linux/sched.h"
#include "linux/config.h"
#include "linux/mm.h" #include "linux/mm.h"
#include "asm/page.h" #include "asm/page.h"
#include "asm/pgtable.h" #include "asm/pgtable.h"
...@@ -17,7 +18,7 @@ ...@@ -17,7 +18,7 @@
#include "os.h" #include "os.h"
#include "tlb.h" #include "tlb.h"
static void do_ops(int fd, struct host_vm_op *ops, int last) static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last)
{ {
struct host_vm_op *op; struct host_vm_op *op;
int i; int i;
...@@ -26,18 +27,18 @@ static void do_ops(int fd, struct host_vm_op *ops, int last) ...@@ -26,18 +27,18 @@ static void do_ops(int fd, struct host_vm_op *ops, int last)
op = &ops[i]; op = &ops[i];
switch(op->type){ switch(op->type){
case MMAP: case MMAP:
map(fd, op->u.mmap.addr, op->u.mmap.len, map(&mmu->skas.id, op->u.mmap.addr, op->u.mmap.len,
op->u.mmap.r, op->u.mmap.w, op->u.mmap.x, op->u.mmap.r, op->u.mmap.w, op->u.mmap.x,
op->u.mmap.fd, op->u.mmap.offset); op->u.mmap.fd, op->u.mmap.offset);
break; break;
case MUNMAP: case MUNMAP:
unmap(fd, (void *) op->u.munmap.addr, unmap(&mmu->skas.id, (void *) op->u.munmap.addr,
op->u.munmap.len); op->u.munmap.len);
break; break;
case MPROTECT: case MPROTECT:
protect(fd, op->u.mprotect.addr, op->u.mprotect.len, protect(&mmu->skas.id, op->u.mprotect.addr,
op->u.mprotect.r, op->u.mprotect.w, op->u.mprotect.len, op->u.mprotect.r,
op->u.mprotect.x); op->u.mprotect.w, op->u.mprotect.x);
break; break;
default: default:
printk("Unknown op type %d in do_ops\n", op->type); printk("Unknown op type %d in do_ops\n", op->type);
...@@ -46,12 +47,15 @@ static void do_ops(int fd, struct host_vm_op *ops, int last) ...@@ -46,12 +47,15 @@ static void do_ops(int fd, struct host_vm_op *ops, int last)
} }
} }
extern int proc_mm;
static void fix_range(struct mm_struct *mm, unsigned long start_addr, static void fix_range(struct mm_struct *mm, unsigned long start_addr,
unsigned long end_addr, int force) unsigned long end_addr, int force)
{ {
int fd = mm->context.skas.mm_fd; if(!proc_mm && (end_addr > CONFIG_STUB_START))
end_addr = CONFIG_STUB_START;
fix_range_common(mm, start_addr, end_addr, force, fd, do_ops); fix_range_common(mm, start_addr, end_addr, force, do_ops);
} }
void __flush_tlb_one_skas(unsigned long addr) void __flush_tlb_one_skas(unsigned long addr)
...@@ -69,17 +73,20 @@ void flush_tlb_range_skas(struct vm_area_struct *vma, unsigned long start, ...@@ -69,17 +73,20 @@ void flush_tlb_range_skas(struct vm_area_struct *vma, unsigned long start,
void flush_tlb_mm_skas(struct mm_struct *mm) void flush_tlb_mm_skas(struct mm_struct *mm)
{ {
unsigned long end;
/* Don't bother flushing if this address space is about to be /* Don't bother flushing if this address space is about to be
* destroyed. * destroyed.
*/ */
if(atomic_read(&mm->mm_users) == 0) if(atomic_read(&mm->mm_users) == 0)
return; return;
fix_range(mm, 0, host_task_size, 0); end = proc_mm ? task_size : CONFIG_STUB_START;
flush_tlb_kernel_range_common(start_vm, end_vm); fix_range(mm, 0, end, 0);
} }
void force_flush_all_skas(void) void force_flush_all_skas(void)
{ {
fix_range(current->mm, 0, host_task_size, 1); unsigned long end = proc_mm ? task_size : CONFIG_STUB_START;
fix_range(current->mm, 0, end, 1);
} }
...@@ -48,6 +48,13 @@ void enable_timer(void) ...@@ -48,6 +48,13 @@ void enable_timer(void)
set_interval(ITIMER_VIRTUAL); set_interval(ITIMER_VIRTUAL);
} }
void prepare_timer(void * ptr)
{
int usec = 1000000/hz();
*(struct itimerval *)ptr = ((struct itimerval) { { 0, usec },
{ 0, usec }});
}
void disable_timer(void) void disable_timer(void)
{ {
struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
......
...@@ -18,13 +18,15 @@ ...@@ -18,13 +18,15 @@
#define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1)) #define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1))
void fix_range_common(struct mm_struct *mm, unsigned long start_addr, void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
unsigned long end_addr, int force, int data, unsigned long end_addr, int force,
void (*do_ops)(int, struct host_vm_op *, int)) void (*do_ops)(union mm_context *, struct host_vm_op *,
int))
{ {
pgd_t *npgd; pgd_t *npgd;
pud_t *npud; pud_t *npud;
pmd_t *npmd; pmd_t *npmd;
pte_t *npte; pte_t *npte;
union mm_context *mmu = &mm->context;
unsigned long addr, end; unsigned long addr, end;
int r, w, x; int r, w, x;
struct host_vm_op ops[16]; struct host_vm_op ops[16];
...@@ -40,7 +42,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr, ...@@ -40,7 +42,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
end = end_addr; end = end_addr;
if(force || pgd_newpage(*npgd)){ if(force || pgd_newpage(*npgd)){
op_index = add_munmap(addr, end - addr, ops, op_index = add_munmap(addr, end - addr, ops,
op_index, last_op, data, op_index, last_op, mmu,
do_ops); do_ops);
pgd_mkuptodate(*npgd); pgd_mkuptodate(*npgd);
} }
...@@ -55,7 +57,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr, ...@@ -55,7 +57,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
end = end_addr; end = end_addr;
if(force || pud_newpage(*npud)){ if(force || pud_newpage(*npud)){
op_index = add_munmap(addr, end - addr, ops, op_index = add_munmap(addr, end - addr, ops,
op_index, last_op, data, op_index, last_op, mmu,
do_ops); do_ops);
pud_mkuptodate(*npud); pud_mkuptodate(*npud);
} }
...@@ -70,7 +72,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr, ...@@ -70,7 +72,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
end = end_addr; end = end_addr;
if(force || pmd_newpage(*npmd)){ if(force || pmd_newpage(*npmd)){
op_index = add_munmap(addr, end - addr, ops, op_index = add_munmap(addr, end - addr, ops,
op_index, last_op, data, op_index, last_op, mmu,
do_ops); do_ops);
pmd_mkuptodate(*npmd); pmd_mkuptodate(*npmd);
} }
...@@ -93,21 +95,21 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr, ...@@ -93,21 +95,21 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
op_index = add_mmap(addr, op_index = add_mmap(addr,
pte_val(*npte) & PAGE_MASK, pte_val(*npte) & PAGE_MASK,
PAGE_SIZE, r, w, x, ops, PAGE_SIZE, r, w, x, ops,
op_index, last_op, data, op_index, last_op, mmu,
do_ops); do_ops);
else op_index = add_munmap(addr, PAGE_SIZE, ops, else op_index = add_munmap(addr, PAGE_SIZE, ops,
op_index, last_op, data, op_index, last_op, mmu,
do_ops); do_ops);
} }
else if(pte_newprot(*npte)) else if(pte_newprot(*npte))
op_index = add_mprotect(addr, PAGE_SIZE, r, w, x, ops, op_index = add_mprotect(addr, PAGE_SIZE, r, w, x, ops,
op_index, last_op, data, op_index, last_op, mmu,
do_ops); do_ops);
*npte = pte_mkuptodate(*npte); *npte = pte_mkuptodate(*npte);
addr += PAGE_SIZE; addr += PAGE_SIZE;
} }
(*do_ops)(data, ops, op_index); (*do_ops)(mmu, ops, op_index);
} }
int flush_tlb_kernel_range_common(unsigned long start, unsigned long end) int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
...@@ -195,51 +197,6 @@ int flush_tlb_kernel_range_common(unsigned long start, unsigned long end) ...@@ -195,51 +197,6 @@ int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
return(updated); return(updated);
} }
void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
{
address &= PAGE_MASK;
flush_tlb_range(vma, address, address + PAGE_SIZE);
}
void flush_tlb_all(void)
{
flush_tlb_mm(current->mm);
}
void flush_tlb_kernel_range(unsigned long start, unsigned long end)
{
CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt,
flush_tlb_kernel_range_common, start, end);
}
void flush_tlb_kernel_vm(void)
{
CHOOSE_MODE(flush_tlb_kernel_vm_tt(),
flush_tlb_kernel_range_common(start_vm, end_vm));
}
void __flush_tlb_one(unsigned long addr)
{
CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr);
}
void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
unsigned long end)
{
CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start,
end);
}
void flush_tlb_mm(struct mm_struct *mm)
{
CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm);
}
void force_flush_all(void)
{
CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas());
}
pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address) pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address)
{ {
return(pgd_offset(mm, address)); return(pgd_offset(mm, address));
...@@ -270,9 +227,9 @@ pte_t *addr_pte(struct task_struct *task, unsigned long addr) ...@@ -270,9 +227,9 @@ pte_t *addr_pte(struct task_struct *task, unsigned long addr)
} }
int add_mmap(unsigned long virt, unsigned long phys, unsigned long len, int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
int r, int w, int x, struct host_vm_op *ops, int index, int r, int w, int x, struct host_vm_op *ops, int index,
int last_filled, int data, int last_filled, union mm_context *mmu,
void (*do_ops)(int, struct host_vm_op *, int)) void (*do_ops)(union mm_context *, struct host_vm_op *, int))
{ {
__u64 offset; __u64 offset;
struct host_vm_op *last; struct host_vm_op *last;
...@@ -292,7 +249,7 @@ int add_mmap(unsigned long virt, unsigned long phys, unsigned long len, ...@@ -292,7 +249,7 @@ int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
} }
if(index == last_filled){ if(index == last_filled){
(*do_ops)(data, ops, last_filled); (*do_ops)(mmu, ops, last_filled);
index = -1; index = -1;
} }
...@@ -310,8 +267,8 @@ int add_mmap(unsigned long virt, unsigned long phys, unsigned long len, ...@@ -310,8 +267,8 @@ int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
} }
int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops, int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops,
int index, int last_filled, int data, int index, int last_filled, union mm_context *mmu,
void (*do_ops)(int, struct host_vm_op *, int)) void (*do_ops)(union mm_context *, struct host_vm_op *, int))
{ {
struct host_vm_op *last; struct host_vm_op *last;
...@@ -325,7 +282,7 @@ int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops, ...@@ -325,7 +282,7 @@ int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops,
} }
if(index == last_filled){ if(index == last_filled){
(*do_ops)(data, ops, last_filled); (*do_ops)(mmu, ops, last_filled);
index = -1; index = -1;
} }
...@@ -337,8 +294,9 @@ int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops, ...@@ -337,8 +294,9 @@ int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops,
} }
int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x, int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x,
struct host_vm_op *ops, int index, int last_filled, int data, struct host_vm_op *ops, int index, int last_filled,
void (*do_ops)(int, struct host_vm_op *, int)) union mm_context *mmu,
void (*do_ops)(union mm_context *, struct host_vm_op *, int))
{ {
struct host_vm_op *last; struct host_vm_op *last;
...@@ -354,7 +312,7 @@ int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x, ...@@ -354,7 +312,7 @@ int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x,
} }
if(index == last_filled){ if(index == last_filled){
(*do_ops)(data, ops, last_filled); (*do_ops)(mmu, ops, last_filled);
index = -1; index = -1;
} }
...@@ -367,3 +325,49 @@ int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x, ...@@ -367,3 +325,49 @@ int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x,
.x = x } } }); .x = x } } });
return(index); return(index);
} }
void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
{
address &= PAGE_MASK;
flush_tlb_range(vma, address, address + PAGE_SIZE);
}
void flush_tlb_all(void)
{
flush_tlb_mm(current->mm);
}
void flush_tlb_kernel_range(unsigned long start, unsigned long end)
{
CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt,
flush_tlb_kernel_range_common, start, end);
}
void flush_tlb_kernel_vm(void)
{
CHOOSE_MODE(flush_tlb_kernel_vm_tt(),
flush_tlb_kernel_range_common(start_vm, end_vm));
}
void __flush_tlb_one(unsigned long addr)
{
CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr);
}
void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
unsigned long end)
{
CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start,
end);
}
void flush_tlb_mm(struct mm_struct *mm)
{
CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm);
}
void force_flush_all(void)
{
CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas());
}
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#include "os.h" #include "os.h"
#include "tlb.h" #include "tlb.h"
static void do_ops(int unused, struct host_vm_op *ops, int last) static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last)
{ {
struct host_vm_op *op; struct host_vm_op *op;
int i; int i;
...@@ -55,7 +55,7 @@ static void fix_range(struct mm_struct *mm, unsigned long start_addr, ...@@ -55,7 +55,7 @@ static void fix_range(struct mm_struct *mm, unsigned long start_addr,
panic("fix_range fixing wrong address space, current = 0x%p", panic("fix_range fixing wrong address space, current = 0x%p",
current); current);
fix_range_common(mm, start_addr, end_addr, force, 0, do_ops); fix_range_common(mm, start_addr, end_addr, force, do_ops);
} }
atomic_t vmchange_seq = ATOMIC_INIT(1); atomic_t vmchange_seq = ATOMIC_INIT(1);
......
This diff is collapsed.
...@@ -121,6 +121,11 @@ void init_registers(int pid) ...@@ -121,6 +121,11 @@ void init_registers(int pid)
err); err);
} }
void get_safe_registers(unsigned long *regs)
{
memcpy(regs, exec_regs, HOST_FRAME_SIZE * sizeof(unsigned long));
}
/* /*
* 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
......
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.
...@@ -119,6 +119,7 @@ void __restore_processor_state(struct saved_context *ctxt) ...@@ -119,6 +119,7 @@ void __restore_processor_state(struct saved_context *ctxt)
fix_processor_context(); fix_processor_context();
do_fpu_end(); do_fpu_end();
mtrr_ap_init();
} }
void restore_processor_state(void) void restore_processor_state(void)
......
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.
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