Merge branch 'master' of /home/trondmy/kernel/linux-2.6/ into merge_linus
This commit is contained in:
commit
21b4e73692
|
@ -77,7 +77,7 @@ To get this part of the dma_ API, you must #include <linux/dmapool.h>
|
|||
Many drivers need lots of small dma-coherent memory regions for DMA
|
||||
descriptors or I/O buffers. Rather than allocating in units of a page
|
||||
or more using dma_alloc_coherent(), you can use DMA pools. These work
|
||||
much like a kmem_cache_t, except that they use the dma-coherent allocator
|
||||
much like a struct kmem_cache, except that they use the dma-coherent allocator
|
||||
not __get_free_pages(). Also, they understand common hardware constraints
|
||||
for alignment, like queue heads needing to be aligned on N byte boundaries.
|
||||
|
||||
|
@ -94,7 +94,7 @@ The pool create() routines initialize a pool of dma-coherent buffers
|
|||
for use with a given device. It must be called in a context which
|
||||
can sleep.
|
||||
|
||||
The "name" is for diagnostics (like a kmem_cache_t name); dev and size
|
||||
The "name" is for diagnostics (like a struct kmem_cache name); dev and size
|
||||
are like what you'd pass to dma_alloc_coherent(). The device's hardware
|
||||
alignment requirement for this type of data is "align" (which is expressed
|
||||
in bytes, and must be a power of two). If your device has no boundary
|
||||
|
@ -431,10 +431,10 @@ be identical to those passed in (and returned by
|
|||
dma_alloc_noncoherent()).
|
||||
|
||||
int
|
||||
dma_is_consistent(dma_addr_t dma_handle)
|
||||
dma_is_consistent(struct device *dev, dma_addr_t dma_handle)
|
||||
|
||||
returns true if the memory pointed to by the dma_handle is actually
|
||||
consistent.
|
||||
returns true if the device dev is performing consistent DMA on the memory
|
||||
area pointed to by the dma_handle.
|
||||
|
||||
int
|
||||
dma_get_cache_alignment(void)
|
||||
|
@ -459,7 +459,7 @@ anything like this. You must also be extra careful about accessing
|
|||
memory you intend to sync partially.
|
||||
|
||||
void
|
||||
dma_cache_sync(void *vaddr, size_t size,
|
||||
dma_cache_sync(struct device *dev, void *vaddr, size_t size,
|
||||
enum dma_data_direction direction)
|
||||
|
||||
Do a partial sync of memory that was allocated by
|
||||
|
|
|
@ -418,9 +418,35 @@ X!Edrivers/pnp/system.c
|
|||
!Idrivers/parport/daisy.c
|
||||
</chapter>
|
||||
|
||||
<chapter id="viddev">
|
||||
<title>Video4Linux</title>
|
||||
!Edrivers/media/video/videodev.c
|
||||
<chapter id="message_devices">
|
||||
<title>Message-based devices</title>
|
||||
<sect1><title>Fusion message devices</title>
|
||||
!Edrivers/message/fusion/mptbase.c
|
||||
!Idrivers/message/fusion/mptbase.c
|
||||
!Edrivers/message/fusion/mptscsih.c
|
||||
!Idrivers/message/fusion/mptscsih.c
|
||||
!Idrivers/message/fusion/mptctl.c
|
||||
!Idrivers/message/fusion/mptspi.c
|
||||
!Idrivers/message/fusion/mptfc.c
|
||||
!Idrivers/message/fusion/mptlan.c
|
||||
</sect1>
|
||||
<sect1><title>I2O message devices</title>
|
||||
!Iinclude/linux/i2o.h
|
||||
!Idrivers/message/i2o/core.h
|
||||
!Edrivers/message/i2o/iop.c
|
||||
!Idrivers/message/i2o/iop.c
|
||||
!Idrivers/message/i2o/config-osm.c
|
||||
!Edrivers/message/i2o/exec-osm.c
|
||||
!Idrivers/message/i2o/exec-osm.c
|
||||
!Idrivers/message/i2o/bus-osm.c
|
||||
!Edrivers/message/i2o/device.c
|
||||
!Idrivers/message/i2o/device.c
|
||||
!Idrivers/message/i2o/driver.c
|
||||
!Idrivers/message/i2o/pci.c
|
||||
!Idrivers/message/i2o/i2o_block.c
|
||||
!Idrivers/message/i2o/i2o_scsi.c
|
||||
!Idrivers/message/i2o/i2o_proc.c
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
||||
<chapter id="snddev">
|
||||
|
|
|
@ -365,6 +365,7 @@ You can change this at module load time (for a module) with:
|
|||
regshifts=<shift1>,<shift2>,...
|
||||
slave_addrs=<addr1>,<addr2>,...
|
||||
force_kipmid=<enable1>,<enable2>,...
|
||||
unload_when_empty=[0|1]
|
||||
|
||||
Each of these except si_trydefaults is a list, the first item for the
|
||||
first interface, second item for the second interface, etc.
|
||||
|
@ -416,6 +417,11 @@ by the driver, but systems with broken interrupts might need an enable,
|
|||
or users that don't want the daemon (don't need the performance, don't
|
||||
want the CPU hit) can disable it.
|
||||
|
||||
If unload_when_empty is set to 1, the driver will be unloaded if it
|
||||
doesn't find any interfaces or all the interfaces fail to work. The
|
||||
default is one. Setting to 0 is useful with the hotmod, but is
|
||||
obviously only useful for modules.
|
||||
|
||||
When compiled into the kernel, the parameters can be specified on the
|
||||
kernel command line as:
|
||||
|
||||
|
@ -441,6 +447,25 @@ have high-res timers enabled in the kernel and you don't have
|
|||
interrupts enabled, the driver will run VERY slowly. Don't blame me,
|
||||
these interfaces suck.
|
||||
|
||||
The driver supports a hot add and remove of interfaces. This way,
|
||||
interfaces can be added or removed after the kernel is up and running.
|
||||
This is done using /sys/modules/ipmi_si/hotmod, which is a write-only
|
||||
parameter. You write a string to this interface. The string has the
|
||||
format:
|
||||
<op1>[:op2[:op3...]]
|
||||
The "op"s are:
|
||||
add|remove,kcs|bt|smic,mem|i/o,<address>[,<opt1>[,<opt2>[,...]]]
|
||||
You can specify more than one interface on the line. The "opt"s are:
|
||||
rsp=<regspacing>
|
||||
rsi=<regsize>
|
||||
rsh=<regshift>
|
||||
irq=<irq>
|
||||
ipmb=<ipmb slave addr>
|
||||
and these have the same meanings as discussed above. Note that you
|
||||
can also use this on the kernel command line for a more compact format
|
||||
for specifying an interface. Note that when removing an interface,
|
||||
only the first three parameters (si type, address type, and address)
|
||||
are used for the comparison. Any options are ignored for removing.
|
||||
|
||||
The SMBus Driver
|
||||
----------------
|
||||
|
@ -502,7 +527,10 @@ used to control it:
|
|||
|
||||
modprobe ipmi_watchdog timeout=<t> pretimeout=<t> action=<action type>
|
||||
preaction=<preaction type> preop=<preop type> start_now=x
|
||||
nowayout=x
|
||||
nowayout=x ifnum_to_use=n
|
||||
|
||||
ifnum_to_use specifies which interface the watchdog timer should use.
|
||||
The default is -1, which means to pick the first one registered.
|
||||
|
||||
The timeout is the number of seconds to the action, and the pretimeout
|
||||
is the amount of seconds before the reset that the pre-timeout panic will
|
||||
|
@ -624,5 +652,9 @@ command line. The parameter is also available via the proc filesystem
|
|||
in /proc/sys/dev/ipmi/poweroff_powercycle. Note that if the system
|
||||
does not support power cycling, it will always do the power off.
|
||||
|
||||
The "ifnum_to_use" parameter specifies which interface the poweroff
|
||||
code should use. The default is -1, which means to pick the first one
|
||||
registered.
|
||||
|
||||
Note that if you have ACPI enabled, the system will prefer using ACPI to
|
||||
power off.
|
||||
|
|
|
@ -24,8 +24,10 @@ very similar behavior to the deadline IO scheduler.
|
|||
Selecting IO schedulers
|
||||
-----------------------
|
||||
To choose IO schedulers at boot time, use the argument 'elevator=deadline'.
|
||||
'noop' and 'as' (the default) are also available. IO schedulers are assigned
|
||||
globally at boot time only presently.
|
||||
'noop', 'as' and 'cfq' (the default) are also available. IO schedulers are
|
||||
assigned globally at boot time only presently. It's also possible to change
|
||||
the IO scheduler for a determined device on the fly, as described in
|
||||
Documentation/block/switching-sched.txt.
|
||||
|
||||
|
||||
Anticipatory IO scheduler Policies
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
Maintained by Torben Mathiasen <device@lanana.org>
|
||||
|
||||
Last revised: 15 May 2006
|
||||
Last revised: 29 November 2006
|
||||
|
||||
This list is the Linux Device List, the official registry of allocated
|
||||
device numbers and /dev directory nodes for the Linux operating
|
||||
|
@ -94,6 +94,7 @@ Your cooperation is appreciated.
|
|||
9 = /dev/urandom Faster, less secure random number gen.
|
||||
10 = /dev/aio Asynchronous I/O notification interface
|
||||
11 = /dev/kmsg Writes to this come out as printk's
|
||||
|
||||
1 block RAM disk
|
||||
0 = /dev/ram0 First RAM disk
|
||||
1 = /dev/ram1 Second RAM disk
|
||||
|
@ -122,7 +123,7 @@ Your cooperation is appreciated.
|
|||
devices are on major 128 and above and use the PTY
|
||||
master multiplex (/dev/ptmx) to acquire a PTY on
|
||||
demand.
|
||||
|
||||
|
||||
2 block Floppy disks
|
||||
0 = /dev/fd0 Controller 0, drive 0, autodetect
|
||||
1 = /dev/fd1 Controller 0, drive 1, autodetect
|
||||
|
@ -257,7 +258,7 @@ Your cooperation is appreciated.
|
|||
129 = /dev/vcsa1 tty1 text/attribute contents
|
||||
...
|
||||
191 = /dev/vcsa63 tty63 text/attribute contents
|
||||
|
||||
|
||||
NOTE: These devices permit both read and write access.
|
||||
|
||||
7 block Loopback devices
|
||||
|
@ -411,7 +412,7 @@ Your cooperation is appreciated.
|
|||
207 = /dev/video/em8300_sp EM8300 DVD decoder subpicture
|
||||
208 = /dev/compaq/cpqphpc Compaq PCI Hot Plug Controller
|
||||
209 = /dev/compaq/cpqrid Compaq Remote Insight Driver
|
||||
210 = /dev/impi/bt IMPI coprocessor block transfer
|
||||
210 = /dev/impi/bt IMPI coprocessor block transfer
|
||||
211 = /dev/impi/smic IMPI coprocessor stream interface
|
||||
212 = /dev/watchdogs/0 First watchdog device
|
||||
213 = /dev/watchdogs/1 Second watchdog device
|
||||
|
@ -506,6 +507,7 @@ Your cooperation is appreciated.
|
|||
33 = /dev/patmgr1 Sequencer patch manager
|
||||
34 = /dev/midi02 Third MIDI port
|
||||
50 = /dev/midi03 Fourth MIDI port
|
||||
|
||||
14 block BIOS harddrive callback support {2.6}
|
||||
0 = /dev/dos_hda First BIOS harddrive whole disk
|
||||
64 = /dev/dos_hdb Second BIOS harddrive whole disk
|
||||
|
@ -527,6 +529,7 @@ Your cooperation is appreciated.
|
|||
|
||||
16 char Non-SCSI scanners
|
||||
0 = /dev/gs4500 Genius 4500 handheld scanner
|
||||
|
||||
16 block GoldStar CD-ROM
|
||||
0 = /dev/gscd GoldStar CD-ROM
|
||||
|
||||
|
@ -548,6 +551,7 @@ Your cooperation is appreciated.
|
|||
0 = /dev/ttyC0 First Cyclades port
|
||||
...
|
||||
31 = /dev/ttyC31 32nd Cyclades port
|
||||
|
||||
19 block "Double" compressed disk
|
||||
0 = /dev/double0 First compressed disk
|
||||
...
|
||||
|
@ -563,6 +567,7 @@ Your cooperation is appreciated.
|
|||
0 = /dev/cub0 Callout device for ttyC0
|
||||
...
|
||||
31 = /dev/cub31 Callout device for ttyC31
|
||||
|
||||
20 block Hitachi CD-ROM (under development)
|
||||
0 = /dev/hitcd Hitachi CD-ROM
|
||||
|
||||
|
@ -582,7 +587,7 @@ Your cooperation is appreciated.
|
|||
|
||||
This device is used on the ARM-based Acorn RiscPC.
|
||||
Partitions are handled the same way as for IDE disks
|
||||
(see major number 3).
|
||||
(see major number 3).
|
||||
|
||||
22 char Digiboard serial card
|
||||
0 = /dev/ttyD0 First Digiboard port
|
||||
|
@ -591,7 +596,7 @@ Your cooperation is appreciated.
|
|||
22 block Second IDE hard disk/CD-ROM interface
|
||||
0 = /dev/hdc Master: whole disk (or CD-ROM)
|
||||
64 = /dev/hdd Slave: whole disk (or CD-ROM)
|
||||
|
||||
|
||||
Partitions are handled the same way as for the first
|
||||
interface (see major number 3).
|
||||
|
||||
|
@ -639,6 +644,7 @@ Your cooperation is appreciated.
|
|||
|
||||
26 char Quanta WinVision frame grabber {2.6}
|
||||
0 = /dev/wvisfgrab Quanta WinVision frame grabber
|
||||
|
||||
26 block Second Matsushita (Panasonic/SoundBlaster) CD-ROM
|
||||
0 = /dev/sbpcd4 Panasonic CD-ROM controller 1 unit 0
|
||||
1 = /dev/sbpcd5 Panasonic CD-ROM controller 1 unit 1
|
||||
|
@ -670,6 +676,7 @@ Your cooperation is appreciated.
|
|||
37 = /dev/nrawqft1 Unit 1, no rewind-on-close, no file marks
|
||||
38 = /dev/nrawqft2 Unit 2, no rewind-on-close, no file marks
|
||||
39 = /dev/nrawqft3 Unit 3, no rewind-on-close, no file marks
|
||||
|
||||
27 block Third Matsushita (Panasonic/SoundBlaster) CD-ROM
|
||||
0 = /dev/sbpcd8 Panasonic CD-ROM controller 2 unit 0
|
||||
1 = /dev/sbpcd9 Panasonic CD-ROM controller 2 unit 1
|
||||
|
@ -681,6 +688,7 @@ Your cooperation is appreciated.
|
|||
1 = /dev/staliomem1 Second Stallion card I/O memory
|
||||
2 = /dev/staliomem2 Third Stallion card I/O memory
|
||||
3 = /dev/staliomem3 Fourth Stallion card I/O memory
|
||||
|
||||
28 char Atari SLM ACSI laser printer (68k/Atari)
|
||||
0 = /dev/slm0 First SLM laser printer
|
||||
1 = /dev/slm1 Second SLM laser printer
|
||||
|
@ -690,6 +698,7 @@ Your cooperation is appreciated.
|
|||
1 = /dev/sbpcd13 Panasonic CD-ROM controller 3 unit 1
|
||||
2 = /dev/sbpcd14 Panasonic CD-ROM controller 3 unit 2
|
||||
3 = /dev/sbpcd15 Panasonic CD-ROM controller 3 unit 3
|
||||
|
||||
28 block ACSI disk (68k/Atari)
|
||||
0 = /dev/ada First ACSI disk whole disk
|
||||
16 = /dev/adb Second ACSI disk whole disk
|
||||
|
@ -750,6 +759,7 @@ Your cooperation is appreciated.
|
|||
31 char MPU-401 MIDI
|
||||
0 = /dev/mpu401data MPU-401 data port
|
||||
1 = /dev/mpu401stat MPU-401 status port
|
||||
|
||||
31 block ROM/flash memory card
|
||||
0 = /dev/rom0 First ROM card (rw)
|
||||
...
|
||||
|
@ -801,7 +811,7 @@ Your cooperation is appreciated.
|
|||
34 block Fourth IDE hard disk/CD-ROM interface
|
||||
0 = /dev/hdg Master: whole disk (or CD-ROM)
|
||||
64 = /dev/hdh Slave: whole disk (or CD-ROM)
|
||||
|
||||
|
||||
Partitions are handled the same way as for the first
|
||||
interface (see major number 3).
|
||||
|
||||
|
@ -818,6 +828,7 @@ Your cooperation is appreciated.
|
|||
129 = /dev/smpte1 Second MIDI port, SMPTE timed
|
||||
130 = /dev/smpte2 Third MIDI port, SMPTE timed
|
||||
131 = /dev/smpte3 Fourth MIDI port, SMPTE timed
|
||||
|
||||
35 block Slow memory ramdisk
|
||||
0 = /dev/slram Slow memory ramdisk
|
||||
|
||||
|
@ -828,6 +839,7 @@ Your cooperation is appreciated.
|
|||
16 = /dev/tap0 First Ethertap device
|
||||
...
|
||||
31 = /dev/tap15 16th Ethertap device
|
||||
|
||||
36 block MCA ESDI hard disk
|
||||
0 = /dev/eda First ESDI disk whole disk
|
||||
64 = /dev/edb Second ESDI disk whole disk
|
||||
|
@ -882,6 +894,7 @@ Your cooperation is appreciated.
|
|||
|
||||
40 char Matrox Meteor frame grabber {2.6}
|
||||
0 = /dev/mmetfgrab Matrox Meteor frame grabber
|
||||
|
||||
40 block Syquest EZ135 parallel port removable drive
|
||||
0 = /dev/eza Parallel EZ135 drive, whole disk
|
||||
|
||||
|
@ -893,6 +906,7 @@ Your cooperation is appreciated.
|
|||
|
||||
41 char Yet Another Micro Monitor
|
||||
0 = /dev/yamm Yet Another Micro Monitor
|
||||
|
||||
41 block MicroSolutions BackPack parallel port CD-ROM
|
||||
0 = /dev/bpcd BackPack CD-ROM
|
||||
|
||||
|
@ -901,6 +915,7 @@ Your cooperation is appreciated.
|
|||
the parallel port ATAPI CD-ROM driver at major number 46.
|
||||
|
||||
42 char Demo/sample use
|
||||
|
||||
42 block Demo/sample use
|
||||
|
||||
This number is intended for use in sample code, as
|
||||
|
@ -918,6 +933,7 @@ Your cooperation is appreciated.
|
|||
0 = /dev/ttyI0 First virtual modem
|
||||
...
|
||||
63 = /dev/ttyI63 64th virtual modem
|
||||
|
||||
43 block Network block devices
|
||||
0 = /dev/nb0 First network block device
|
||||
1 = /dev/nb1 Second network block device
|
||||
|
@ -934,12 +950,13 @@ Your cooperation is appreciated.
|
|||
0 = /dev/cui0 Callout device for ttyI0
|
||||
...
|
||||
63 = /dev/cui63 Callout device for ttyI63
|
||||
|
||||
44 block Flash Translation Layer (FTL) filesystems
|
||||
0 = /dev/ftla FTL on first Memory Technology Device
|
||||
16 = /dev/ftlb FTL on second Memory Technology Device
|
||||
32 = /dev/ftlc FTL on third Memory Technology Device
|
||||
...
|
||||
240 = /dev/ftlp FTL on 16th Memory Technology Device
|
||||
240 = /dev/ftlp FTL on 16th Memory Technology Device
|
||||
|
||||
Partitions are handled in the same way as for IDE
|
||||
disks (see major number 3) except that the partition
|
||||
|
@ -958,6 +975,7 @@ Your cooperation is appreciated.
|
|||
191 = /dev/ippp63 64th SyncPPP device
|
||||
|
||||
255 = /dev/isdninfo ISDN monitor interface
|
||||
|
||||
45 block Parallel port IDE disk devices
|
||||
0 = /dev/pda First parallel port IDE disk
|
||||
16 = /dev/pdb Second parallel port IDE disk
|
||||
|
@ -1044,6 +1062,7 @@ Your cooperation is appreciated.
|
|||
1 = /dev/dcbri1 Second DataComm card
|
||||
2 = /dev/dcbri2 Third DataComm card
|
||||
3 = /dev/dcbri3 Fourth DataComm card
|
||||
|
||||
52 block Mylex DAC960 PCI RAID controller; fifth controller
|
||||
0 = /dev/rd/c4d0 First disk, whole disk
|
||||
8 = /dev/rd/c4d1 Second disk, whole disk
|
||||
|
@ -1093,6 +1112,7 @@ Your cooperation is appreciated.
|
|||
|
||||
55 char DSP56001 digital signal processor
|
||||
0 = /dev/dsp56k First DSP56001
|
||||
|
||||
55 block Mylex DAC960 PCI RAID controller; eighth controller
|
||||
0 = /dev/rd/c7d0 First disk, whole disk
|
||||
8 = /dev/rd/c7d1 Second disk, whole disk
|
||||
|
@ -1130,6 +1150,7 @@ Your cooperation is appreciated.
|
|||
0 = /dev/cup0 Callout device for ttyP0
|
||||
1 = /dev/cup1 Callout device for ttyP1
|
||||
...
|
||||
|
||||
58 block Reserved for logical volume manager
|
||||
|
||||
59 char sf firewall package
|
||||
|
@ -1149,6 +1170,7 @@ Your cooperation is appreciated.
|
|||
NAMING CONFLICT -- PROPOSED REVISED NAME /dev/rpda0 etc
|
||||
|
||||
60-63 char LOCAL/EXPERIMENTAL USE
|
||||
|
||||
60-63 block LOCAL/EXPERIMENTAL USE
|
||||
Allocated for local/experimental use. For devices not
|
||||
assigned official numbers, these ranges should be
|
||||
|
@ -1434,7 +1456,6 @@ Your cooperation is appreciated.
|
|||
DAC960 (see major number 48) except that the limit on
|
||||
partitions is 15.
|
||||
|
||||
|
||||
78 char PAM Software's multimodem boards
|
||||
0 = /dev/ttyM0 First PAM modem
|
||||
1 = /dev/ttyM1 Second PAM modem
|
||||
|
@ -1450,7 +1471,6 @@ Your cooperation is appreciated.
|
|||
DAC960 (see major number 48) except that the limit on
|
||||
partitions is 15.
|
||||
|
||||
|
||||
79 char PAM Software's multimodem boards - alternate devices
|
||||
0 = /dev/cum0 Callout device for ttyM0
|
||||
1 = /dev/cum1 Callout device for ttyM1
|
||||
|
@ -1466,7 +1486,6 @@ Your cooperation is appreciated.
|
|||
DAC960 (see major number 48) except that the limit on
|
||||
partitions is 15.
|
||||
|
||||
|
||||
80 char Photometrics AT200 CCD camera
|
||||
0 = /dev/at200 Photometrics AT200 CCD camera
|
||||
|
||||
|
@ -1679,7 +1698,7 @@ Your cooperation is appreciated.
|
|||
1 = /dev/dcxx1 Second capture card
|
||||
...
|
||||
|
||||
94 block IBM S/390 DASD block storage
|
||||
94 block IBM S/390 DASD block storage
|
||||
0 = /dev/dasda First DASD device, major
|
||||
1 = /dev/dasda1 First DASD device, block 1
|
||||
2 = /dev/dasda2 First DASD device, block 2
|
||||
|
@ -1695,7 +1714,7 @@ Your cooperation is appreciated.
|
|||
1 = /dev/ipnat NAT control device/log file
|
||||
2 = /dev/ipstate State information log file
|
||||
3 = /dev/ipauth Authentication control device/log file
|
||||
...
|
||||
...
|
||||
|
||||
96 char Parallel port ATAPI tape devices
|
||||
0 = /dev/pt0 First parallel port ATAPI tape
|
||||
|
@ -1705,7 +1724,7 @@ Your cooperation is appreciated.
|
|||
129 = /dev/npt1 Second p.p. ATAPI tape, no rewind
|
||||
...
|
||||
|
||||
96 block Inverse NAND Flash Translation Layer
|
||||
96 block Inverse NAND Flash Translation Layer
|
||||
0 = /dev/inftla First INFTL layer
|
||||
16 = /dev/inftlb Second INFTL layer
|
||||
...
|
||||
|
@ -1937,7 +1956,6 @@ Your cooperation is appreciated.
|
|||
...
|
||||
|
||||
113 block IBM iSeries virtual CD-ROM
|
||||
|
||||
0 = /dev/iseries/vcda First virtual CD-ROM
|
||||
1 = /dev/iseries/vcdb Second virtual CD-ROM
|
||||
...
|
||||
|
@ -2059,11 +2077,12 @@ Your cooperation is appreciated.
|
|||
...
|
||||
|
||||
119 char VMware virtual network control
|
||||
0 = /dev/vnet0 1st virtual network
|
||||
1 = /dev/vnet1 2nd virtual network
|
||||
0 = /dev/vmnet0 1st virtual network
|
||||
1 = /dev/vmnet1 2nd virtual network
|
||||
...
|
||||
|
||||
120-127 char LOCAL/EXPERIMENTAL USE
|
||||
|
||||
120-127 block LOCAL/EXPERIMENTAL USE
|
||||
Allocated for local/experimental use. For devices not
|
||||
assigned official numbers, these ranges should be
|
||||
|
@ -2075,7 +2094,6 @@ Your cooperation is appreciated.
|
|||
nodes; instead they should be accessed through the
|
||||
/dev/ptmx cloning interface.
|
||||
|
||||
|
||||
128 block SCSI disk devices (128-143)
|
||||
0 = /dev/sddy 129th SCSI disk whole disk
|
||||
16 = /dev/sddz 130th SCSI disk whole disk
|
||||
|
@ -2087,7 +2105,6 @@ Your cooperation is appreciated.
|
|||
disks (see major number 3) except that the limit on
|
||||
partitions is 15.
|
||||
|
||||
|
||||
129 block SCSI disk devices (144-159)
|
||||
0 = /dev/sdeo 145th SCSI disk whole disk
|
||||
16 = /dev/sdep 146th SCSI disk whole disk
|
||||
|
@ -2123,7 +2140,6 @@ Your cooperation is appreciated.
|
|||
disks (see major number 3) except that the limit on
|
||||
partitions is 15.
|
||||
|
||||
|
||||
132 block SCSI disk devices (192-207)
|
||||
0 = /dev/sdgk 193rd SCSI disk whole disk
|
||||
16 = /dev/sdgl 194th SCSI disk whole disk
|
||||
|
@ -2135,7 +2151,6 @@ Your cooperation is appreciated.
|
|||
disks (see major number 3) except that the limit on
|
||||
partitions is 15.
|
||||
|
||||
|
||||
133 block SCSI disk devices (208-223)
|
||||
0 = /dev/sdha 209th SCSI disk whole disk
|
||||
16 = /dev/sdhb 210th SCSI disk whole disk
|
||||
|
@ -2147,7 +2162,6 @@ Your cooperation is appreciated.
|
|||
disks (see major number 3) except that the limit on
|
||||
partitions is 15.
|
||||
|
||||
|
||||
134 block SCSI disk devices (224-239)
|
||||
0 = /dev/sdhq 225th SCSI disk whole disk
|
||||
16 = /dev/sdhr 226th SCSI disk whole disk
|
||||
|
@ -2159,7 +2173,6 @@ Your cooperation is appreciated.
|
|||
disks (see major number 3) except that the limit on
|
||||
partitions is 15.
|
||||
|
||||
|
||||
135 block SCSI disk devices (240-255)
|
||||
0 = /dev/sdig 241st SCSI disk whole disk
|
||||
16 = /dev/sdih 242nd SCSI disk whole disk
|
||||
|
@ -2171,7 +2184,6 @@ Your cooperation is appreciated.
|
|||
disks (see major number 3) except that the limit on
|
||||
partitions is 15.
|
||||
|
||||
|
||||
136-143 char Unix98 PTY slaves
|
||||
0 = /dev/pts/0 First Unix98 pseudo-TTY
|
||||
1 = /dev/pts/1 Second Unix98 pesudo-TTY
|
||||
|
@ -2384,6 +2396,7 @@ Your cooperation is appreciated.
|
|||
...
|
||||
|
||||
159 char RESERVED
|
||||
|
||||
159 block RESERVED
|
||||
|
||||
160 char General Purpose Instrument Bus (GPIB)
|
||||
|
@ -2427,7 +2440,7 @@ Your cooperation is appreciated.
|
|||
|
||||
Partitions are handled in the same way as for IDE
|
||||
disks (see major number 3) except that the limit on
|
||||
partitions is 31.
|
||||
partitions is 31.
|
||||
|
||||
162 char Raw block device interface
|
||||
0 = /dev/rawctl Raw I/O control device
|
||||
|
@ -2483,7 +2496,6 @@ Your cooperation is appreciated.
|
|||
|
||||
171 char Reserved for IEEE 1394 (Firewire)
|
||||
|
||||
|
||||
172 char Moxa Intellio serial card
|
||||
0 = /dev/ttyMX0 First Moxa port
|
||||
1 = /dev/ttyMX1 Second Moxa port
|
||||
|
@ -2543,9 +2555,6 @@ Your cooperation is appreciated.
|
|||
64 = /dev/usb/rio500 Diamond Rio 500
|
||||
65 = /dev/usb/usblcd USBLCD Interface (info@usblcd.de)
|
||||
66 = /dev/usb/cpad0 Synaptics cPad (mouse/LCD)
|
||||
67 = /dev/usb/adutux0 1st Ontrak ADU device
|
||||
...
|
||||
76 = /dev/usb/adutux10 10th Ontrak ADU device
|
||||
96 = /dev/usb/hiddev0 1st USB HID device
|
||||
...
|
||||
111 = /dev/usb/hiddev15 16th USB HID device
|
||||
|
@ -2558,7 +2567,7 @@ Your cooperation is appreciated.
|
|||
132 = /dev/usb/idmouse ID Mouse (fingerprint scanner) device
|
||||
133 = /dev/usb/sisusbvga1 First SiSUSB VGA device
|
||||
...
|
||||
140 = /dev/usb/sisusbvga8 Eigth SISUSB VGA device
|
||||
140 = /dev/usb/sisusbvga8 Eighth SISUSB VGA device
|
||||
144 = /dev/usb/lcd USB LCD device
|
||||
160 = /dev/usb/legousbtower0 1st USB Legotower device
|
||||
...
|
||||
|
@ -2571,7 +2580,7 @@ Your cooperation is appreciated.
|
|||
0 = /dev/uba First USB block device
|
||||
8 = /dev/ubb Second USB block device
|
||||
16 = /dev/ubc Third USB block device
|
||||
...
|
||||
...
|
||||
|
||||
181 char Conrad Electronic parallel port radio clocks
|
||||
0 = /dev/pcfclock0 First Conrad radio clock
|
||||
|
@ -2657,7 +2666,7 @@ Your cooperation is appreciated.
|
|||
32 = /dev/mvideo/status2 Third device
|
||||
...
|
||||
...
|
||||
240 = /dev/mvideo/status15 16th device
|
||||
240 = /dev/mvideo/status15 16th device
|
||||
...
|
||||
|
||||
195 char Nvidia graphics devices
|
||||
|
@ -2795,6 +2804,10 @@ Your cooperation is appreciated.
|
|||
...
|
||||
185 = /dev/ttyNX15 Hilscher netX serial port 15
|
||||
186 = /dev/ttyJ0 JTAG1 DCC protocol based serial port emulation
|
||||
187 = /dev/ttyUL0 Xilinx uartlite - port 0
|
||||
...
|
||||
190 = /dev/ttyUL3 Xilinx uartlite - port 3
|
||||
191 = /dev/xvc0 Xen virtual console - port 0
|
||||
|
||||
205 char Low-density serial ports (alternate device)
|
||||
0 = /dev/culu0 Callout device for ttyLU0
|
||||
|
@ -2832,7 +2845,6 @@ Your cooperation is appreciated.
|
|||
82 = /dev/cuvr0 Callout device for ttyVR0
|
||||
83 = /dev/cuvr1 Callout device for ttyVR1
|
||||
|
||||
|
||||
206 char OnStream SC-x0 tape devices
|
||||
0 = /dev/osst0 First OnStream SCSI tape, mode 0
|
||||
1 = /dev/osst1 Second OnStream SCSI tape, mode 0
|
||||
|
@ -2922,7 +2934,6 @@ Your cooperation is appreciated.
|
|||
...
|
||||
|
||||
212 char LinuxTV.org DVB driver subsystem
|
||||
|
||||
0 = /dev/dvb/adapter0/video0 first video decoder of first card
|
||||
1 = /dev/dvb/adapter0/audio0 first audio decoder of first card
|
||||
2 = /dev/dvb/adapter0/sec0 (obsolete/unused)
|
||||
|
@ -3008,9 +3019,9 @@ Your cooperation is appreciated.
|
|||
2 = /dev/3270/tub2 Second 3270 terminal
|
||||
...
|
||||
|
||||
229 char IBM iSeries virtual console
|
||||
0 = /dev/iseries/vtty0 First console port
|
||||
1 = /dev/iseries/vtty1 Second console port
|
||||
229 char IBM iSeries/pSeries virtual console
|
||||
0 = /dev/hvc0 First console port
|
||||
1 = /dev/hvc1 Second console port
|
||||
...
|
||||
|
||||
230 char IBM iSeries virtual tape
|
||||
|
@ -3083,12 +3094,14 @@ Your cooperation is appreciated.
|
|||
234-239 UNASSIGNED
|
||||
|
||||
240-254 char LOCAL/EXPERIMENTAL USE
|
||||
|
||||
240-254 block LOCAL/EXPERIMENTAL USE
|
||||
Allocated for local/experimental use. For devices not
|
||||
assigned official numbers, these ranges should be
|
||||
used in order to avoid conflicting with future assignments.
|
||||
|
||||
255 char RESERVED
|
||||
|
||||
255 block RESERVED
|
||||
|
||||
This major is reserved to assist the expansion to a
|
||||
|
@ -3115,7 +3128,20 @@ Your cooperation is appreciated.
|
|||
257 char Phoenix Technologies Cryptographic Services Driver
|
||||
0 = /dev/ptlsec Crypto Services Driver
|
||||
|
||||
257 block SSFDC Flash Translation Layer filesystem
|
||||
0 = /dev/ssfdca First SSFDC layer
|
||||
8 = /dev/ssfdcb Second SSFDC layer
|
||||
16 = /dev/ssfdcc Third SSFDC layer
|
||||
24 = /dev/ssfdcd 4th SSFDC layer
|
||||
32 = /dev/ssfdce 5th SSFDC layer
|
||||
40 = /dev/ssfdcf 6th SSFDC layer
|
||||
48 = /dev/ssfdcg 7th SSFDC layer
|
||||
56 = /dev/ssfdch 8th SSFDC layer
|
||||
|
||||
258 block ROM/Flash read-only translation layer
|
||||
0 = /dev/blockrom0 First ROM card's translation layer interface
|
||||
1 = /dev/blockrom1 Second ROM card's translation layer interface
|
||||
...
|
||||
|
||||
**** ADDITIONAL /dev DIRECTORY ENTRIES
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ sync_fs: no no read
|
|||
write_super_lockfs: ?
|
||||
unlockfs: ?
|
||||
statfs: no no no
|
||||
remount_fs: no yes maybe (see below)
|
||||
remount_fs: yes yes maybe (see below)
|
||||
clear_inode: no
|
||||
umount_begin: yes no no
|
||||
show_options: no (vfsmount->sem)
|
||||
|
|
|
@ -51,6 +51,22 @@ homepage:
|
|||
|
||||
http://fuse.sourceforge.net/
|
||||
|
||||
Filesystem type
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
The filesystem type given to mount(2) can be one of the following:
|
||||
|
||||
'fuse'
|
||||
|
||||
This is the usual way to mount a FUSE filesystem. The first
|
||||
argument of the mount system call may contain an arbitrary string,
|
||||
which is not interpreted by the kernel.
|
||||
|
||||
'fuseblk'
|
||||
|
||||
The filesystem is block device based. The first argument of the
|
||||
mount system call is interpreted as the name of the device.
|
||||
|
||||
Mount options
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
@ -94,6 +110,11 @@ Mount options
|
|||
The default is infinite. Note that the size of read requests is
|
||||
limited anyway to 32 pages (which is 128kbyte on i386).
|
||||
|
||||
'blksize=N'
|
||||
|
||||
Set the block size for the filesystem. The default is 512. This
|
||||
option is only valid for 'fuseblk' type mounts.
|
||||
|
||||
Control filesystem
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
This is the implementation of the SystemV/Coherent filesystem for Linux.
|
||||
It implements all of
|
||||
- Xenix FS,
|
||||
- SystemV/386 FS,
|
||||
- Coherent FS.
|
||||
|
||||
This is version beta 4.
|
||||
|
||||
To install:
|
||||
* Answer the 'System V and Coherent filesystem support' question with 'y'
|
||||
when configuring the kernel.
|
||||
|
@ -28,11 +25,173 @@ Bugs in the present implementation:
|
|||
for this FS on hard disk yet.
|
||||
|
||||
|
||||
Please report any bugs and suggestions to
|
||||
Bruno Haible <haible@ma2s2.mathematik.uni-karlsruhe.de>
|
||||
Pascal Haible <haible@izfm.uni-stuttgart.de>
|
||||
Krzysztof G. Baranowski <kgb@manjak.knm.org.pl>
|
||||
These filesystems are rather similar. Here is a comparison with Minix FS:
|
||||
|
||||
Bruno Haible
|
||||
<haible@ma2s2.mathematik.uni-karlsruhe.de>
|
||||
* Linux fdisk reports on partitions
|
||||
- Minix FS 0x81 Linux/Minix
|
||||
- Xenix FS ??
|
||||
- SystemV FS ??
|
||||
- Coherent FS 0x08 AIX bootable
|
||||
|
||||
* Size of a block or zone (data allocation unit on disk)
|
||||
- Minix FS 1024
|
||||
- Xenix FS 1024 (also 512 ??)
|
||||
- SystemV FS 1024 (also 512 and 2048)
|
||||
- Coherent FS 512
|
||||
|
||||
* General layout: all have one boot block, one super block and
|
||||
separate areas for inodes and for directories/data.
|
||||
On SystemV Release 2 FS (e.g. Microport) the first track is reserved and
|
||||
all the block numbers (including the super block) are offset by one track.
|
||||
|
||||
* Byte ordering of "short" (16 bit entities) on disk:
|
||||
- Minix FS little endian 0 1
|
||||
- Xenix FS little endian 0 1
|
||||
- SystemV FS little endian 0 1
|
||||
- Coherent FS little endian 0 1
|
||||
Of course, this affects only the file system, not the data of files on it!
|
||||
|
||||
* Byte ordering of "long" (32 bit entities) on disk:
|
||||
- Minix FS little endian 0 1 2 3
|
||||
- Xenix FS little endian 0 1 2 3
|
||||
- SystemV FS little endian 0 1 2 3
|
||||
- Coherent FS PDP-11 2 3 0 1
|
||||
Of course, this affects only the file system, not the data of files on it!
|
||||
|
||||
* Inode on disk: "short", 0 means non-existent, the root dir ino is:
|
||||
- Minix FS 1
|
||||
- Xenix FS, SystemV FS, Coherent FS 2
|
||||
|
||||
* Maximum number of hard links to a file:
|
||||
- Minix FS 250
|
||||
- Xenix FS ??
|
||||
- SystemV FS ??
|
||||
- Coherent FS >=10000
|
||||
|
||||
* Free inode management:
|
||||
- Minix FS a bitmap
|
||||
- Xenix FS, SystemV FS, Coherent FS
|
||||
There is a cache of a certain number of free inodes in the super-block.
|
||||
When it is exhausted, new free inodes are found using a linear search.
|
||||
|
||||
* Free block management:
|
||||
- Minix FS a bitmap
|
||||
- Xenix FS, SystemV FS, Coherent FS
|
||||
Free blocks are organized in a "free list". Maybe a misleading term,
|
||||
since it is not true that every free block contains a pointer to
|
||||
the next free block. Rather, the free blocks are organized in chunks
|
||||
of limited size, and every now and then a free block contains pointers
|
||||
to the free blocks pertaining to the next chunk; the first of these
|
||||
contains pointers and so on. The list terminates with a "block number"
|
||||
0 on Xenix FS and SystemV FS, with a block zeroed out on Coherent FS.
|
||||
|
||||
* Super-block location:
|
||||
- Minix FS block 1 = bytes 1024..2047
|
||||
- Xenix FS block 1 = bytes 1024..2047
|
||||
- SystemV FS bytes 512..1023
|
||||
- Coherent FS block 1 = bytes 512..1023
|
||||
|
||||
* Super-block layout:
|
||||
- Minix FS
|
||||
unsigned short s_ninodes;
|
||||
unsigned short s_nzones;
|
||||
unsigned short s_imap_blocks;
|
||||
unsigned short s_zmap_blocks;
|
||||
unsigned short s_firstdatazone;
|
||||
unsigned short s_log_zone_size;
|
||||
unsigned long s_max_size;
|
||||
unsigned short s_magic;
|
||||
- Xenix FS, SystemV FS, Coherent FS
|
||||
unsigned short s_firstdatazone;
|
||||
unsigned long s_nzones;
|
||||
unsigned short s_fzone_count;
|
||||
unsigned long s_fzones[NICFREE];
|
||||
unsigned short s_finode_count;
|
||||
unsigned short s_finodes[NICINOD];
|
||||
char s_flock;
|
||||
char s_ilock;
|
||||
char s_modified;
|
||||
char s_rdonly;
|
||||
unsigned long s_time;
|
||||
short s_dinfo[4]; -- SystemV FS only
|
||||
unsigned long s_free_zones;
|
||||
unsigned short s_free_inodes;
|
||||
short s_dinfo[4]; -- Xenix FS only
|
||||
unsigned short s_interleave_m,s_interleave_n; -- Coherent FS only
|
||||
char s_fname[6];
|
||||
char s_fpack[6];
|
||||
then they differ considerably:
|
||||
Xenix FS
|
||||
char s_clean;
|
||||
char s_fill[371];
|
||||
long s_magic;
|
||||
long s_type;
|
||||
SystemV FS
|
||||
long s_fill[12 or 14];
|
||||
long s_state;
|
||||
long s_magic;
|
||||
long s_type;
|
||||
Coherent FS
|
||||
unsigned long s_unique;
|
||||
Note that Coherent FS has no magic.
|
||||
|
||||
* Inode layout:
|
||||
- Minix FS
|
||||
unsigned short i_mode;
|
||||
unsigned short i_uid;
|
||||
unsigned long i_size;
|
||||
unsigned long i_time;
|
||||
unsigned char i_gid;
|
||||
unsigned char i_nlinks;
|
||||
unsigned short i_zone[7+1+1];
|
||||
- Xenix FS, SystemV FS, Coherent FS
|
||||
unsigned short i_mode;
|
||||
unsigned short i_nlink;
|
||||
unsigned short i_uid;
|
||||
unsigned short i_gid;
|
||||
unsigned long i_size;
|
||||
unsigned char i_zone[3*(10+1+1+1)];
|
||||
unsigned long i_atime;
|
||||
unsigned long i_mtime;
|
||||
unsigned long i_ctime;
|
||||
|
||||
* Regular file data blocks are organized as
|
||||
- Minix FS
|
||||
7 direct blocks
|
||||
1 indirect block (pointers to blocks)
|
||||
1 double-indirect block (pointer to pointers to blocks)
|
||||
- Xenix FS, SystemV FS, Coherent FS
|
||||
10 direct blocks
|
||||
1 indirect block (pointers to blocks)
|
||||
1 double-indirect block (pointer to pointers to blocks)
|
||||
1 triple-indirect block (pointer to pointers to pointers to blocks)
|
||||
|
||||
* Inode size, inodes per block
|
||||
- Minix FS 32 32
|
||||
- Xenix FS 64 16
|
||||
- SystemV FS 64 16
|
||||
- Coherent FS 64 8
|
||||
|
||||
* Directory entry on disk
|
||||
- Minix FS
|
||||
unsigned short inode;
|
||||
char name[14/30];
|
||||
- Xenix FS, SystemV FS, Coherent FS
|
||||
unsigned short inode;
|
||||
char name[14];
|
||||
|
||||
* Dir entry size, dir entries per block
|
||||
- Minix FS 16/32 64/32
|
||||
- Xenix FS 16 64
|
||||
- SystemV FS 16 64
|
||||
- Coherent FS 16 32
|
||||
|
||||
* How to implement symbolic links such that the host fsck doesn't scream:
|
||||
- Minix FS normal
|
||||
- Xenix FS kludge: as regular files with chmod 1000
|
||||
- SystemV FS ??
|
||||
- Coherent FS kludge: as regular files with chmod 1000
|
||||
|
||||
|
||||
Notation: We often speak of a "block" but mean a zone (the allocation unit)
|
||||
and not the disk driver's notion of "block".
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
----------------------------
|
||||
|
||||
H. Peter Anvin <hpa@zytor.com>
|
||||
Last update 2005-09-02
|
||||
Last update 2006-11-17
|
||||
|
||||
On the i386 platform, the Linux kernel uses a rather complicated boot
|
||||
convention. This has evolved partially due to historical aspects, as
|
||||
|
@ -35,6 +35,8 @@ Protocol 2.03: (Kernel 2.4.18-pre1) Explicitly makes the highest possible
|
|||
initrd address available to the bootloader.
|
||||
|
||||
Protocol 2.04: (Kernel 2.6.14) Extend the syssize field to four bytes.
|
||||
Protocol 2.05: (Kernel 2.6.20) Make protected mode kernel relocatable.
|
||||
Introduce relocatable_kernel and kernel_alignment fields.
|
||||
|
||||
|
||||
**** MEMORY LAYOUT
|
||||
|
@ -129,6 +131,8 @@ Offset Proto Name Meaning
|
|||
0226/2 N/A pad1 Unused
|
||||
0228/4 2.02+ cmd_line_ptr 32-bit pointer to the kernel command line
|
||||
022C/4 2.03+ initrd_addr_max Highest legal initrd address
|
||||
0230/4 2.05+ kernel_alignment Physical addr alignment required for kernel
|
||||
0234/1 2.05+ relocatable_kernel Whether kernel is relocatable or not
|
||||
|
||||
(1) For backwards compatibility, if the setup_sects field contains 0, the
|
||||
real value is 4.
|
||||
|
|
|
@ -599,8 +599,6 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
|
||||
hugepages= [HW,IA-32,IA-64] Maximal number of HugeTLB pages.
|
||||
|
||||
noirqbalance [IA-32,SMP,KNL] Disable kernel irq balancing
|
||||
|
||||
i8042.direct [HW] Put keyboard port into non-translated mode
|
||||
i8042.dumbkbd [HW] Pretend that controller can only read data from
|
||||
keyboard and cannot control its state
|
||||
|
@ -650,6 +648,10 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
idle= [HW]
|
||||
Format: idle=poll or idle=halt
|
||||
|
||||
ignore_loglevel [KNL]
|
||||
Ignore loglevel setting - this will print /all/
|
||||
kernel messages to the console. Useful for debugging.
|
||||
|
||||
ihash_entries= [KNL]
|
||||
Set number of hash buckets for inode cache.
|
||||
|
||||
|
@ -714,7 +716,12 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
Format: <RDP>,<reset>,<pci_scan>,<verbosity>
|
||||
|
||||
isolcpus= [KNL,SMP] Isolate CPUs from the general scheduler.
|
||||
Format: <cpu number>,...,<cpu number>
|
||||
Format:
|
||||
<cpu number>,...,<cpu number>
|
||||
or
|
||||
<cpu number>-<cpu number> (must be a positive range in ascending order)
|
||||
or a mixture
|
||||
<cpu number>,...,<cpu number>-<cpu number>
|
||||
This option can be used to specify one or more CPUs
|
||||
to isolate from the general SMP balancing and scheduling
|
||||
algorithms. The only way to move a process onto or off
|
||||
|
@ -1012,6 +1019,10 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
emulation library even if a 387 maths coprocessor
|
||||
is present.
|
||||
|
||||
noaliencache [MM, NUMA] Disables the allcoation of alien caches in
|
||||
the slab allocator. Saves per-node memory, but will
|
||||
impact performance on real NUMA hardware.
|
||||
|
||||
noalign [KNL,ARM]
|
||||
|
||||
noapic [SMP,APIC] Tells the kernel to not make use of any
|
||||
|
@ -1052,9 +1063,14 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
in certain environments such as networked servers or
|
||||
real-time systems.
|
||||
|
||||
noirqbalance [IA-32,SMP,KNL] Disable kernel irq balancing
|
||||
|
||||
noirqdebug [IA-32] Disables the code which attempts to detect and
|
||||
disable unhandled interrupt sources.
|
||||
|
||||
no_timer_check [IA-32,X86_64,APIC] Disables the code which tests for
|
||||
broken timer IRQ sources.
|
||||
|
||||
noisapnp [ISAPNP] Disables ISA PnP code.
|
||||
|
||||
noinitrd [RAM] Tells the kernel not to load any configured
|
||||
|
@ -1285,6 +1301,7 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
Param: "schedule" - profile schedule points.
|
||||
Param: <number> - step/bucket size as a power of 2 for
|
||||
statistical time based profiling.
|
||||
Param: "sleep" - profile D-state sleeping (millisecs)
|
||||
|
||||
processor.max_cstate= [HW,ACPI]
|
||||
Limit processor to maximum C-state
|
||||
|
@ -1366,6 +1383,12 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
resume= [SWSUSP]
|
||||
Specify the partition device for software suspend
|
||||
|
||||
resume_offset= [SWSUSP]
|
||||
Specify the offset from the beginning of the partition
|
||||
given by "resume=" at which the swap header is located,
|
||||
in <PAGE_SIZE> units (needed only for swap files).
|
||||
See Documentation/power/swsusp-and-swap-files.txt
|
||||
|
||||
rhash_entries= [KNL,NET]
|
||||
Set number of hash buckets for route cache
|
||||
|
||||
|
@ -1732,6 +1755,9 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
norandmaps Don't use address space randomization
|
||||
Equivalent to echo 0 > /proc/sys/kernel/randomize_va_space
|
||||
|
||||
unwind_debug=N N > 0 will enable dwarf2 unwinder debugging
|
||||
This is useful to get more information why
|
||||
you got a "dwarf2 unwinder stuck"
|
||||
|
||||
______________________________________________________________________
|
||||
|
||||
|
|
|
@ -58,6 +58,8 @@ fore200e.txt
|
|||
- FORE Systems PCA-200E/SBA-200E ATM NIC driver info.
|
||||
framerelay.txt
|
||||
- info on using Frame Relay/Data Link Connection Identifier (DLCI).
|
||||
generic_netlink.txt
|
||||
- info on Generic Netlink
|
||||
ip-sysctl.txt
|
||||
- /proc/sys/net/ipv4/* variables
|
||||
ip_dynaddr.txt
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
A wiki document on how to use Generic Netlink can be found here:
|
||||
|
||||
* http://linux-net.osdl.org/index.php/Generic_Netlink_HOWTO
|
|
@ -0,0 +1,56 @@
|
|||
How to get s2ram working
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
2006 Linus Torvalds
|
||||
2006 Pavel Machek
|
||||
|
||||
1) Check suspend.sf.net, program s2ram there has long whitelist of
|
||||
"known ok" machines, along with tricks to use on each one.
|
||||
|
||||
2) If that does not help, try reading tricks.txt and
|
||||
video.txt. Perhaps problem is as simple as broken module, and
|
||||
simple module unload can fix it.
|
||||
|
||||
3) You can use Linus' TRACE_RESUME infrastructure, described below.
|
||||
|
||||
Using TRACE_RESUME
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
I've been working at making the machines I have able to STR, and almost
|
||||
always it's a driver that is buggy. Thank God for the suspend/resume
|
||||
debugging - the thing that Chuck tried to disable. That's often the _only_
|
||||
way to debug these things, and it's actually pretty powerful (but
|
||||
time-consuming - having to insert TRACE_RESUME() markers into the device
|
||||
driver that doesn't resume and recompile and reboot).
|
||||
|
||||
Anyway, the way to debug this for people who are interested (have a
|
||||
machine that doesn't boot) is:
|
||||
|
||||
- enable PM_DEBUG, and PM_TRACE
|
||||
|
||||
- use a script like this:
|
||||
|
||||
#!/bin/sh
|
||||
sync
|
||||
echo 1 > /sys/power/pm_trace
|
||||
echo mem > /sys/power/state
|
||||
|
||||
to suspend
|
||||
|
||||
- if it doesn't come back up (which is usually the problem), reboot by
|
||||
holding the power button down, and look at the dmesg output for things
|
||||
like
|
||||
|
||||
Magic number: 4:156:725
|
||||
hash matches drivers/base/power/resume.c:28
|
||||
hash matches device 0000:01:00.0
|
||||
|
||||
which means that the last trace event was just before trying to resume
|
||||
device 0000:01:00.0. Then figure out what driver is controlling that
|
||||
device (lspci and /sys/devices/pci* is your friend), and see if you can
|
||||
fix it, disable it, or trace into its resume function.
|
||||
|
||||
For example, the above happens to be the VGA device on my EVO, which I
|
||||
used to run with "radeonfb" (it's an ATI Radeon mobility). It turns out
|
||||
that "radeonfb" simply cannot resume that device - it tries to set the
|
||||
PLL's, and it just _hangs_. Using the regular VGA console and letting X
|
||||
resume it instead works fine.
|
|
@ -0,0 +1,60 @@
|
|||
Using swap files with software suspend (swsusp)
|
||||
(C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
|
||||
|
||||
The Linux kernel handles swap files almost in the same way as it handles swap
|
||||
partitions and there are only two differences between these two types of swap
|
||||
areas:
|
||||
(1) swap files need not be contiguous,
|
||||
(2) the header of a swap file is not in the first block of the partition that
|
||||
holds it. From the swsusp's point of view (1) is not a problem, because it is
|
||||
already taken care of by the swap-handling code, but (2) has to be taken into
|
||||
consideration.
|
||||
|
||||
In principle the location of a swap file's header may be determined with the
|
||||
help of appropriate filesystem driver. Unfortunately, however, it requires the
|
||||
filesystem holding the swap file to be mounted, and if this filesystem is
|
||||
journaled, it cannot be mounted during resume from disk. For this reason to
|
||||
identify a swap file swsusp uses the name of the partition that holds the file
|
||||
and the offset from the beginning of the partition at which the swap file's
|
||||
header is located. For convenience, this offset is expressed in <PAGE_SIZE>
|
||||
units.
|
||||
|
||||
In order to use a swap file with swsusp, you need to:
|
||||
|
||||
1) Create the swap file and make it active, eg.
|
||||
|
||||
# dd if=/dev/zero of=<swap_file_path> bs=1024 count=<swap_file_size_in_k>
|
||||
# mkswap <swap_file_path>
|
||||
# swapon <swap_file_path>
|
||||
|
||||
2) Use an application that will bmap the swap file with the help of the
|
||||
FIBMAP ioctl and determine the location of the file's swap header, as the
|
||||
offset, in <PAGE_SIZE> units, from the beginning of the partition which
|
||||
holds the swap file.
|
||||
|
||||
3) Add the following parameters to the kernel command line:
|
||||
|
||||
resume=<swap_file_partition> resume_offset=<swap_file_offset>
|
||||
|
||||
where <swap_file_partition> is the partition on which the swap file is located
|
||||
and <swap_file_offset> is the offset of the swap header determined by the
|
||||
application in 2) (of course, this step may be carried out automatically
|
||||
by the same application that determies the swap file's header offset using the
|
||||
FIBMAP ioctl)
|
||||
|
||||
OR
|
||||
|
||||
Use a userland suspend application that will set the partition and offset
|
||||
with the help of the SNAPSHOT_SET_SWAP_AREA ioctl described in
|
||||
Documentation/power/userland-swsusp.txt (this is the only method to suspend
|
||||
to a swap file allowing the resume to be initiated from an initrd or initramfs
|
||||
image).
|
||||
|
||||
Now, swsusp will use the swap file in the same way in which it would use a swap
|
||||
partition. In particular, the swap file has to be active (ie. be present in
|
||||
/proc/swaps) so that it can be used for suspending.
|
||||
|
||||
Note that if the swap file used for suspending is deleted and recreated,
|
||||
the location of its header need not be the same as before. Thus every time
|
||||
this happens the value of the "resume_offset=" kernel command line parameter
|
||||
has to be updated.
|
|
@ -297,20 +297,12 @@ system is shut down or suspended. Additionally use the encrypted
|
|||
suspend image to prevent sensitive data from being stolen after
|
||||
resume.
|
||||
|
||||
Q: Why can't we suspend to a swap file?
|
||||
Q: Can I suspend to a swap file?
|
||||
|
||||
A: Because accessing swap file needs the filesystem mounted, and
|
||||
filesystem might do something wrong (like replaying the journal)
|
||||
during mount.
|
||||
|
||||
There are few ways to get that fixed:
|
||||
|
||||
1) Probably could be solved by modifying every filesystem to support
|
||||
some kind of "really read-only!" option. Patches welcome.
|
||||
|
||||
2) suspend2 gets around that by storing absolute positions in on-disk
|
||||
image (and blocksize), with resume parameter pointing directly to
|
||||
suspend header.
|
||||
A: Generally, yes, you can. However, it requires you to use the "resume=" and
|
||||
"resume_offset=" kernel command line parameters, so the resume from a swap file
|
||||
cannot be initiated from an initrd or initramfs image. See
|
||||
swsusp-and-swap-files.txt for details.
|
||||
|
||||
Q: Is there a maximum system RAM size that is supported by swsusp?
|
||||
|
||||
|
|
|
@ -9,9 +9,8 @@ done it already.
|
|||
Now, to use the userland interface for software suspend you need special
|
||||
utilities that will read/write the system memory snapshot from/to the
|
||||
kernel. Such utilities are available, for example, from
|
||||
<http://www.sisk.pl/kernel/utilities/suspend>. You may want to have
|
||||
a look at them if you are going to develop your own suspend/resume
|
||||
utilities.
|
||||
<http://suspend.sourceforge.net>. You may want to have a look at them if you
|
||||
are going to develop your own suspend/resume utilities.
|
||||
|
||||
The interface consists of a character device providing the open(),
|
||||
release(), read(), and write() operations as well as several ioctl()
|
||||
|
@ -21,9 +20,9 @@ be read from /sys/class/misc/snapshot/dev.
|
|||
|
||||
The device can be open either for reading or for writing. If open for
|
||||
reading, it is considered to be in the suspend mode. Otherwise it is
|
||||
assumed to be in the resume mode. The device cannot be open for reading
|
||||
and writing. It is also impossible to have the device open more than once
|
||||
at a time.
|
||||
assumed to be in the resume mode. The device cannot be open for simultaneous
|
||||
reading and writing. It is also impossible to have the device open more than
|
||||
once at a time.
|
||||
|
||||
The ioctl() commands recognized by the device are:
|
||||
|
||||
|
@ -69,9 +68,46 @@ SNAPSHOT_FREE_SWAP_PAGES - free all swap pages allocated with
|
|||
SNAPSHOT_SET_SWAP_FILE - set the resume partition (the last ioctl() argument
|
||||
should specify the device's major and minor numbers in the old
|
||||
two-byte format, as returned by the stat() function in the .st_rdev
|
||||
member of the stat structure); it is recommended to always use this
|
||||
call, because the code to set the resume partition could be removed from
|
||||
future kernels
|
||||
member of the stat structure)
|
||||
|
||||
SNAPSHOT_SET_SWAP_AREA - set the resume partition and the offset (in <PAGE_SIZE>
|
||||
units) from the beginning of the partition at which the swap header is
|
||||
located (the last ioctl() argument should point to a struct
|
||||
resume_swap_area, as defined in kernel/power/power.h, containing the
|
||||
resume device specification, as for the SNAPSHOT_SET_SWAP_FILE ioctl(),
|
||||
and the offset); for swap partitions the offset is always 0, but it is
|
||||
different to zero for swap files (please see
|
||||
Documentation/swsusp-and-swap-files.txt for details).
|
||||
The SNAPSHOT_SET_SWAP_AREA ioctl() is considered as a replacement for
|
||||
SNAPSHOT_SET_SWAP_FILE which is regarded as obsolete. It is
|
||||
recommended to always use this call, because the code to set the resume
|
||||
partition may be removed from future kernels
|
||||
|
||||
SNAPSHOT_S2RAM - suspend to RAM; using this call causes the kernel to
|
||||
immediately enter the suspend-to-RAM state, so this call must always
|
||||
be preceded by the SNAPSHOT_FREEZE call and it is also necessary
|
||||
to use the SNAPSHOT_UNFREEZE call after the system wakes up. This call
|
||||
is needed to implement the suspend-to-both mechanism in which the
|
||||
suspend image is first created, as though the system had been suspended
|
||||
to disk, and then the system is suspended to RAM (this makes it possible
|
||||
to resume the system from RAM if there's enough battery power or restore
|
||||
its state on the basis of the saved suspend image otherwise)
|
||||
|
||||
SNAPSHOT_PMOPS - enable the usage of the pmops->prepare, pmops->enter and
|
||||
pmops->finish methods (the in-kernel swsusp knows these as the "platform
|
||||
method") which are needed on many machines to (among others) speed up
|
||||
the resume by letting the BIOS skip some steps or to let the system
|
||||
recognise the correct state of the hardware after the resume (in
|
||||
particular on many machines this ensures that unplugged AC
|
||||
adapters get correctly detected and that kacpid does not run wild after
|
||||
the resume). The last ioctl() argument can take one of the three
|
||||
values, defined in kernel/power/power.h:
|
||||
PMOPS_PREPARE - make the kernel carry out the
|
||||
pm_ops->prepare(PM_SUSPEND_DISK) operation
|
||||
PMOPS_ENTER - make the kernel power off the system by calling
|
||||
pm_ops->enter(PM_SUSPEND_DISK)
|
||||
PMOPS_FINISH - make the kernel carry out the
|
||||
pm_ops->finish(PM_SUSPEND_DISK) operation
|
||||
|
||||
The device's read() operation can be used to transfer the snapshot image from
|
||||
the kernel. It has the following limitations:
|
||||
|
@ -91,10 +127,12 @@ unfreeze user space processes frozen by SNAPSHOT_UNFREEZE if they are
|
|||
still frozen when the device is being closed).
|
||||
|
||||
Currently it is assumed that the userland utilities reading/writing the
|
||||
snapshot image from/to the kernel will use a swap partition, called the resume
|
||||
partition, as storage space. However, this is not really required, as they
|
||||
can use, for example, a special (blank) suspend partition or a file on a partition
|
||||
that is unmounted before SNAPSHOT_ATOMIC_SNAPSHOT and mounted afterwards.
|
||||
snapshot image from/to the kernel will use a swap parition, called the resume
|
||||
partition, or a swap file as storage space (if a swap file is used, the resume
|
||||
partition is the partition that holds this file). However, this is not really
|
||||
required, as they can use, for example, a special (blank) suspend partition or
|
||||
a file on a partition that is unmounted before SNAPSHOT_ATOMIC_SNAPSHOT and
|
||||
mounted afterwards.
|
||||
|
||||
These utilities SHOULD NOT make any assumptions regarding the ordering of
|
||||
data within the snapshot image, except for the image header that MAY be
|
||||
|
|
|
@ -62,9 +62,6 @@ consider the following facts about the Linux kernel:
|
|||
- different structures can contain different fields
|
||||
- Some functions may not be implemented at all, (i.e. some locks
|
||||
compile away to nothing for non-SMP builds.)
|
||||
- Parameter passing of variables from function to function can be
|
||||
done in different ways (the CONFIG_REGPARM option controls
|
||||
this.)
|
||||
- Memory within the kernel can be aligned in different ways,
|
||||
depending on the build options.
|
||||
- Linux runs on a wide range of different processor architectures.
|
||||
|
|
|
@ -27,6 +27,7 @@ show up in /proc/sys/kernel:
|
|||
- hotplug
|
||||
- java-appletviewer [ binfmt_java, obsolete ]
|
||||
- java-interpreter [ binfmt_java, obsolete ]
|
||||
- kstack_depth_to_print [ X86 only ]
|
||||
- l2cr [ PPC only ]
|
||||
- modprobe ==> Documentation/kmod.txt
|
||||
- msgmax
|
||||
|
@ -170,6 +171,13 @@ This flag controls the L2 cache of G3 processor boards. If
|
|||
|
||||
==============================================================
|
||||
|
||||
kstack_depth_to_print: (X86 only)
|
||||
|
||||
Controls the number of words to print when dumping the raw
|
||||
kernel stack.
|
||||
|
||||
==============================================================
|
||||
|
||||
osrelease, ostype & version:
|
||||
|
||||
# cat osrelease
|
||||
|
|
|
@ -52,10 +52,6 @@ APICs
|
|||
apicmaintimer. Useful when your PIT timer is totally
|
||||
broken.
|
||||
|
||||
disable_8254_timer / enable_8254_timer
|
||||
Enable interrupt 0 timer routing over the 8254 in addition to over
|
||||
the IO-APIC. The kernel tries to set a sensible default.
|
||||
|
||||
Early Console
|
||||
|
||||
syntax: earlyprintk=vga
|
||||
|
@ -183,7 +179,7 @@ PCI
|
|||
IOMMU
|
||||
|
||||
iommu=[size][,noagp][,off][,force][,noforce][,leak][,memaper[=order]][,merge]
|
||||
[,forcesac][,fullflush][,nomerge][,noaperture]
|
||||
[,forcesac][,fullflush][,nomerge][,noaperture][,calgary]
|
||||
size set size of iommu (in bytes)
|
||||
noagp don't initialize the AGP driver and use full aperture.
|
||||
off don't use the IOMMU
|
||||
|
@ -204,6 +200,7 @@ IOMMU
|
|||
buffering.
|
||||
nodac Forbid DMA >4GB
|
||||
panic Always panic when IOMMU overflows
|
||||
calgary Use the Calgary IOMMU if it is available
|
||||
|
||||
swiotlb=pages[,force]
|
||||
|
||||
|
|
25
MAINTAINERS
25
MAINTAINERS
|
@ -1091,13 +1091,19 @@ M: miku@iki.fi
|
|||
S: Maintained
|
||||
|
||||
EXT2 FILE SYSTEM
|
||||
L: ext2-devel@lists.sourceforge.net
|
||||
L: linux-ext4@vger.kernel.org
|
||||
S: Maintained
|
||||
|
||||
EXT3 FILE SYSTEM
|
||||
P: Stephen Tweedie, Andrew Morton
|
||||
M: sct@redhat.com, akpm@osdl.org, adilger@clusterfs.com
|
||||
L: ext2-devel@lists.sourceforge.net
|
||||
L: linux-ext4@vger.kernel.org
|
||||
S: Maintained
|
||||
|
||||
EXT4 FILE SYSTEM
|
||||
P: Stephen Tweedie, Andrew Morton
|
||||
M: sct@redhat.com, akpm@osdl.org, adilger@clusterfs.com
|
||||
L: linux-ext4@vger.kernel.org
|
||||
S: Maintained
|
||||
|
||||
F71805F HARDWARE MONITORING DRIVER
|
||||
|
@ -1214,7 +1220,8 @@ HARDWARE MONITORING
|
|||
P: Jean Delvare
|
||||
M: khali@linux-fr.org
|
||||
L: lm-sensors@lm-sensors.org
|
||||
W: http://www.lm-sensors.nu/
|
||||
W: http://www.lm-sensors.org/
|
||||
T: quilt http://khali.linux-fr.org/devel/linux-2.6/jdelvare-hwmon/
|
||||
S: Maintained
|
||||
|
||||
HARDWARE RANDOM NUMBER GENERATOR CORE
|
||||
|
@ -1340,8 +1347,7 @@ I2C SUBSYSTEM
|
|||
P: Jean Delvare
|
||||
M: khali@linux-fr.org
|
||||
L: i2c@lm-sensors.org
|
||||
W: http://www.lm-sensors.nu/
|
||||
T: quilt kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
|
||||
T: quilt http://khali.linux-fr.org/devel/linux-2.6/jdelvare-i2c/
|
||||
S: Maintained
|
||||
|
||||
I2O
|
||||
|
@ -1673,7 +1679,7 @@ S: Supported
|
|||
JOURNALLING LAYER FOR BLOCK DEVICES (JBD)
|
||||
P: Stephen Tweedie, Andrew Morton
|
||||
M: sct@redhat.com, akpm@osdl.org
|
||||
L: ext2-devel@lists.sourceforge.net
|
||||
L: linux-ext4@vger.kernel.org
|
||||
S: Maintained
|
||||
|
||||
K8TEMP HARDWARE MONITORING DRIVER
|
||||
|
@ -2913,7 +2919,6 @@ S: Maintained
|
|||
SUN3/3X
|
||||
P: Sam Creasey
|
||||
M: sammy@sammy.net
|
||||
L: sun3-list@redhat.com
|
||||
W: http://sammy.net/sun3/
|
||||
S: Maintained
|
||||
|
||||
|
@ -3454,6 +3459,12 @@ W: http://oss.sgi.com/projects/xfs
|
|||
T: git git://oss.sgi.com:8090/xfs/xfs-2.6
|
||||
S: Supported
|
||||
|
||||
XILINX UARTLITE SERIAL DRIVER
|
||||
P: Peter Korsgaard
|
||||
M: jacmet@sunsite.dk
|
||||
L: linux-serial@vger.kernel.org
|
||||
S: Maintained
|
||||
|
||||
X86 3-LEVEL PAGING (PAE) SUPPORT
|
||||
P: Ingo Molnar
|
||||
M: mingo@redhat.com
|
||||
|
|
|
@ -40,7 +40,9 @@ summary from [1.]>" for easy identification by the developers.
|
|||
[1.] One line summary of the problem:
|
||||
[2.] Full description of the problem/report:
|
||||
[3.] Keywords (i.e., modules, networking, kernel):
|
||||
[4.] Kernel version (from /proc/version):
|
||||
[4.] Kernel information
|
||||
[4.1.] Kernel version (from /proc/version):
|
||||
[4.2.] Kernel .config file:
|
||||
[5.] Most recent kernel version which did not have the bug:
|
||||
[6.] Output of Oops.. message (if applicable) with symbolic information
|
||||
resolved (see Documentation/oops-tracing.txt)
|
||||
|
|
|
@ -516,10 +516,11 @@ sys_pciconfig_iobase(long which, unsigned long bus, unsigned long dfn)
|
|||
if (bus == 0 && dfn == 0) {
|
||||
hose = pci_isa_hose;
|
||||
} else {
|
||||
dev = pci_find_slot(bus, dfn);
|
||||
dev = pci_get_bus_and_slot(bus, dfn);
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
hose = dev->sysdata;
|
||||
pci_dev_put(dev);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -183,11 +183,15 @@ miata_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
|
|||
|
||||
if((slot == 7) && (PCI_FUNC(dev->devfn) == 3)) {
|
||||
u8 irq=0;
|
||||
|
||||
if(pci_read_config_byte(pci_find_slot(dev->bus->number, dev->devfn & ~(7)), 0x40,&irq)!=PCIBIOS_SUCCESSFUL)
|
||||
struct pci_dev *pdev = pci_get_slot(dev->bus, dev->devfn & ~7);
|
||||
if(pdev == NULL || pci_read_config_byte(pdev, 0x40,&irq) != PCIBIOS_SUCCESSFUL) {
|
||||
pci_dev_put(pdev);
|
||||
return -1;
|
||||
else
|
||||
}
|
||||
else {
|
||||
pci_dev_put(pdev);
|
||||
return irq;
|
||||
}
|
||||
}
|
||||
|
||||
return COMMON_TABLE_LOOKUP;
|
||||
|
|
|
@ -200,7 +200,7 @@ nautilus_init_pci(void)
|
|||
bus = pci_scan_bus(0, alpha_mv.pci_ops, hose);
|
||||
hose->bus = bus;
|
||||
|
||||
irongate = pci_find_slot(0, 0);
|
||||
irongate = pci_get_bus_and_slot(0, 0);
|
||||
bus->self = irongate;
|
||||
bus->resource[1] = &irongate_mem;
|
||||
|
||||
|
|
|
@ -108,7 +108,7 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
|
|||
|
||||
/* If we're in an interrupt context, or have no user context,
|
||||
we must not take the fault. */
|
||||
if (!mm || in_interrupt())
|
||||
if (!mm || in_atomic())
|
||||
goto no_context;
|
||||
|
||||
#ifdef CONFIG_ALPHA_LARGE_VMALLOC
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/signal.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/personality.h>
|
||||
#include <linux/freezer.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/ucontext.h>
|
||||
|
|
|
@ -55,7 +55,7 @@ static inline void omap_init_irda(void) {}
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#if defined(CONFIG_OMAP_RTC) || defined(CONFIG_OMAP_RTC)
|
||||
#if defined(CONFIG_RTC_DRV_OMAP) || defined(CONFIG_RTC_DRV_OMAP_MODULE)
|
||||
|
||||
#define OMAP_RTC_BASE 0xfffb4800
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
|
||||
/* io map for dma */
|
||||
static void __iomem *dma_base;
|
||||
static kmem_cache_t *dma_kmem;
|
||||
static struct kmem_cache *dma_kmem;
|
||||
|
||||
struct s3c24xx_dma_selection dma_sel;
|
||||
|
||||
|
@ -1271,7 +1271,7 @@ struct sysdev_class dma_sysclass = {
|
|||
|
||||
/* kmem cache implementation */
|
||||
|
||||
static void s3c2410_dma_cache_ctor(void *p, kmem_cache_t *c, unsigned long f)
|
||||
static void s3c2410_dma_cache_ctor(void *p, struct kmem_cache *c, unsigned long f)
|
||||
{
|
||||
memset(p, 0, sizeof(struct s3c2410_dma_buf));
|
||||
}
|
||||
|
|
|
@ -230,7 +230,7 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
|||
* If we're in an interrupt or have no user
|
||||
* context, we must not take the fault..
|
||||
*/
|
||||
if (in_interrupt() || !mm)
|
||||
if (in_atomic() || !mm)
|
||||
goto no_context;
|
||||
|
||||
/*
|
||||
|
|
|
@ -620,12 +620,10 @@ ecard_probe(int slot, card_type_t type)
|
|||
struct ex_ecid cid;
|
||||
int i, rc = -ENOMEM;
|
||||
|
||||
ec = kmalloc(sizeof(ecard_t), GFP_KERNEL);
|
||||
ec = kzalloc(sizeof(ecard_t), GFP_KERNEL);
|
||||
if (!ec)
|
||||
goto nomem;
|
||||
|
||||
memset(ec, 0, sizeof(ecard_t));
|
||||
|
||||
ec->slot_no = slot;
|
||||
ec->type = type;
|
||||
ec->irq = NO_IRQ;
|
||||
|
|
|
@ -215,7 +215,7 @@ int do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
|||
* If we're in an interrupt or have no user
|
||||
* context, we must not take the fault..
|
||||
*/
|
||||
if (in_interrupt() || !mm)
|
||||
if (in_atomic() || !mm)
|
||||
goto no_context;
|
||||
|
||||
down_read(&mm->mmap_sem);
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
#define MEMC_TABLE_SIZE (256*sizeof(unsigned long))
|
||||
|
||||
kmem_cache_t *pte_cache, *pgd_cache;
|
||||
struct kmem_cache *pte_cache, *pgd_cache;
|
||||
int page_nr;
|
||||
|
||||
/*
|
||||
|
@ -162,12 +162,12 @@ void __init create_memmap_holes(struct meminfo *mi)
|
|||
{
|
||||
}
|
||||
|
||||
static void pte_cache_ctor(void *pte, kmem_cache_t *cache, unsigned long flags)
|
||||
static void pte_cache_ctor(void *pte, struct kmem_cache *cache, unsigned long flags)
|
||||
{
|
||||
memzero(pte, sizeof(pte_t) * PTRS_PER_PTE);
|
||||
}
|
||||
|
||||
static void pgd_cache_ctor(void *pgd, kmem_cache_t *cache, unsigned long flags)
|
||||
static void pgd_cache_ctor(void *pgd, struct kmem_cache *cache, unsigned long flags)
|
||||
{
|
||||
memzero(pgd + MEMC_TABLE_SIZE, USER_PTRS_PER_PGD * sizeof(pgd_t));
|
||||
}
|
||||
|
|
|
@ -154,6 +154,7 @@ ss_probe:
|
|||
return 1;
|
||||
|
||||
no_kprobe:
|
||||
preempt_enable_no_resched();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <linux/errno.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/freezer.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/ucontext.h>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <asm/addrspace.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
void dma_cache_sync(void *vaddr, size_t size, int direction)
|
||||
void dma_cache_sync(struct device *dev, void *vaddr, size_t size, int direction)
|
||||
{
|
||||
/*
|
||||
* No need to sync an uncached area
|
||||
|
|
|
@ -232,7 +232,7 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
|
|||
* context, we must not take the fault..
|
||||
*/
|
||||
|
||||
if (in_interrupt() || !mm)
|
||||
if (in_atomic() || !mm)
|
||||
goto no_context;
|
||||
|
||||
down_read(&mm->mmap_sem);
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
*/
|
||||
|
||||
#include <linux/futex.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/futex.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
/*
|
||||
* the various futex operations; MMU fault checking is ignored under no-MMU
|
||||
|
@ -200,7 +200,7 @@ int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
|
|||
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
|
||||
return -EFAULT;
|
||||
|
||||
inc_preempt_count();
|
||||
pagefault_disable();
|
||||
|
||||
switch (op) {
|
||||
case FUTEX_OP_SET:
|
||||
|
@ -223,7 +223,7 @@ int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
|
|||
break;
|
||||
}
|
||||
|
||||
dec_preempt_count();
|
||||
pagefault_enable();
|
||||
|
||||
if (!ret) {
|
||||
switch (cmp) {
|
||||
|
|
|
@ -947,7 +947,7 @@ static void __init setup_linux_memory(void)
|
|||
if (LOADER_TYPE && INITRD_START) {
|
||||
if (INITRD_START + INITRD_SIZE <= (low_top_pfn << PAGE_SHIFT)) {
|
||||
reserve_bootmem(INITRD_START, INITRD_SIZE);
|
||||
initrd_start = INITRD_START ? INITRD_START + PAGE_OFFSET : 0;
|
||||
initrd_start = INITRD_START + PAGE_OFFSET;
|
||||
initrd_end = initrd_start + INITRD_SIZE;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include <linux/ptrace.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <linux/personality.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <asm/ucontext.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
|
|
@ -78,7 +78,7 @@ asmlinkage void do_page_fault(int datammu, unsigned long esr0, unsigned long ear
|
|||
* If we're in an interrupt or have no user
|
||||
* context, we must not take the fault..
|
||||
*/
|
||||
if (in_interrupt() || !mm)
|
||||
if (in_atomic() || !mm)
|
||||
goto no_context;
|
||||
|
||||
down_read(&mm->mmap_sem);
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include <asm/cacheflush.h>
|
||||
|
||||
pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((aligned(PAGE_SIZE)));
|
||||
kmem_cache_t *pgd_cache;
|
||||
struct kmem_cache *pgd_cache;
|
||||
|
||||
pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
|
||||
{
|
||||
|
@ -100,7 +100,7 @@ static inline void pgd_list_del(pgd_t *pgd)
|
|||
set_page_private(next, (unsigned long) pprev);
|
||||
}
|
||||
|
||||
void pgd_ctor(void *pgd, kmem_cache_t *cache, unsigned long unused)
|
||||
void pgd_ctor(void *pgd, struct kmem_cache *cache, unsigned long unused)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
|
@ -120,7 +120,7 @@ void pgd_ctor(void *pgd, kmem_cache_t *cache, unsigned long unused)
|
|||
}
|
||||
|
||||
/* never called when PTRS_PER_PMD > 1 */
|
||||
void pgd_dtor(void *pgd, kmem_cache_t *cache, unsigned long unused)
|
||||
void pgd_dtor(void *pgd, struct kmem_cache *cache, unsigned long unused)
|
||||
{
|
||||
unsigned long flags; /* can be called from interrupt context */
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ void __init setup_arch(char **cmdline_p)
|
|||
#endif
|
||||
#else
|
||||
if ((memory_end < CONFIG_BLKDEV_RESERVE_ADDRESS) &&
|
||||
(memory_end > CONFIG_BLKDEV_RESERVE_ADDRESS)
|
||||
(memory_end > CONFIG_BLKDEV_RESERVE_ADDRESS))
|
||||
/* overlap userarea */
|
||||
memory_end = CONFIG_BLKDEV_RESERVE_ADDRESS;
|
||||
#endif
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
#include <linux/personality.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/binfmts.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/freezer.h>
|
||||
|
||||
#include <asm/setup.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
|
|
@ -70,6 +70,7 @@ SECTIONS
|
|||
#endif
|
||||
.text :
|
||||
{
|
||||
_text = .;
|
||||
#if defined(CONFIG_ROMKERNEL)
|
||||
*(.int_redirect)
|
||||
#endif
|
||||
|
|
|
@ -182,6 +182,17 @@ config X86_ES7000
|
|||
|
||||
endchoice
|
||||
|
||||
config PARAVIRT
|
||||
bool "Paravirtualization support (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL
|
||||
help
|
||||
Paravirtualization is a way of running multiple instances of
|
||||
Linux on the same machine, under a hypervisor. This option
|
||||
changes the kernel so it can modify itself when it is run
|
||||
under a hypervisor, improving performance significantly.
|
||||
However, when run without a hypervisor the kernel is
|
||||
theoretically slower. If in doubt, say N.
|
||||
|
||||
config ACPI_SRAT
|
||||
bool
|
||||
default y
|
||||
|
@ -443,7 +454,8 @@ source "drivers/firmware/Kconfig"
|
|||
|
||||
choice
|
||||
prompt "High Memory Support"
|
||||
default NOHIGHMEM
|
||||
default HIGHMEM4G if !X86_NUMAQ
|
||||
default HIGHMEM64G if X86_NUMAQ
|
||||
|
||||
config NOHIGHMEM
|
||||
bool "off"
|
||||
|
@ -710,20 +722,6 @@ config BOOT_IOREMAP
|
|||
depends on (((X86_SUMMIT || X86_GENERICARCH) && NUMA) || (X86 && EFI))
|
||||
default y
|
||||
|
||||
config REGPARM
|
||||
bool "Use register arguments"
|
||||
default y
|
||||
help
|
||||
Compile the kernel with -mregparm=3. This instructs gcc to use
|
||||
a more efficient function call ABI which passes the first three
|
||||
arguments of a function call via registers, which results in denser
|
||||
and faster code.
|
||||
|
||||
If this option is disabled, then the default ABI of passing
|
||||
arguments via the stack is used.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config SECCOMP
|
||||
bool "Enable seccomp to safely compute untrusted bytecode"
|
||||
depends on PROC_FS
|
||||
|
@ -773,23 +771,39 @@ config CRASH_DUMP
|
|||
PHYSICAL_START.
|
||||
For more details see Documentation/kdump/kdump.txt
|
||||
|
||||
config PHYSICAL_START
|
||||
hex "Physical address where the kernel is loaded" if (EMBEDDED || CRASH_DUMP)
|
||||
|
||||
default "0x1000000" if CRASH_DUMP
|
||||
default "0x100000"
|
||||
config RELOCATABLE
|
||||
bool "Build a relocatable kernel(EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL
|
||||
help
|
||||
This gives the physical address where the kernel is loaded. Normally
|
||||
for regular kernels this value is 0x100000 (1MB). But in the case
|
||||
of kexec on panic the fail safe kernel needs to run at a different
|
||||
address than the panic-ed kernel. This option is used to set the load
|
||||
address for kernels used to capture crash dump on being kexec'ed
|
||||
after panic. The default value for crash dump kernels is
|
||||
0x1000000 (16MB). This can also be set based on the "X" value as
|
||||
specified in the "crashkernel=YM@XM" command line boot parameter
|
||||
passed to the panic-ed kernel. Typically this parameter is set as
|
||||
crashkernel=64M@16M. Please take a look at
|
||||
Documentation/kdump/kdump.txt for more details about crash dumps.
|
||||
This build a kernel image that retains relocation information
|
||||
so it can be loaded someplace besides the default 1MB.
|
||||
The relocations tend to the kernel binary about 10% larger,
|
||||
but are discarded at runtime.
|
||||
|
||||
One use is for the kexec on panic case where the recovery kernel
|
||||
must live at a different physical address than the primary
|
||||
kernel.
|
||||
|
||||
config PHYSICAL_ALIGN
|
||||
hex "Alignment value to which kernel should be aligned"
|
||||
default "0x100000"
|
||||
range 0x2000 0x400000
|
||||
help
|
||||
This value puts the alignment restrictions on physical address
|
||||
where kernel is loaded and run from. Kernel is compiled for an
|
||||
address which meets above alignment restriction.
|
||||
|
||||
If bootloader loads the kernel at a non-aligned address and
|
||||
CONFIG_RELOCATABLE is set, kernel will move itself to nearest
|
||||
address aligned to above value and run from there.
|
||||
|
||||
If bootloader loads the kernel at a non-aligned address and
|
||||
CONFIG_RELOCATABLE is not set, kernel will ignore the run time
|
||||
load address and decompress itself to the address it has been
|
||||
compiled for and run from there. The address for which kernel is
|
||||
compiled already meets above alignment restrictions. Hence the
|
||||
end result is that kernel runs from a physical address meeting
|
||||
above alignment restrictions.
|
||||
|
||||
Don't change this unless you know what you are doing.
|
||||
|
||||
|
|
|
@ -103,8 +103,15 @@ config MPENTIUMM
|
|||
Select this for Intel Pentium M (not Pentium-4 M)
|
||||
notebook chips.
|
||||
|
||||
config MCORE2
|
||||
bool "Core 2/newer Xeon"
|
||||
help
|
||||
Select this for Intel Core 2 and newer Core 2 Xeons (Xeon 51xx and 53xx)
|
||||
CPUs. You can distingush newer from older Xeons by the CPU family
|
||||
in /proc/cpuinfo. Newer ones have 6.
|
||||
|
||||
config MPENTIUM4
|
||||
bool "Pentium-4/Celeron(P4-based)/Pentium-4 M/Xeon"
|
||||
bool "Pentium-4/Celeron(P4-based)/Pentium-4 M/older Xeon"
|
||||
help
|
||||
Select this for Intel Pentium 4 chips. This includes the
|
||||
Pentium 4, P4-based Celeron and Xeon, and Pentium-4 M
|
||||
|
@ -229,7 +236,7 @@ config X86_L1_CACHE_SHIFT
|
|||
default "7" if MPENTIUM4 || X86_GENERIC
|
||||
default "4" if X86_ELAN || M486 || M386 || MGEODEGX1
|
||||
default "5" if MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX
|
||||
default "6" if MK7 || MK8 || MPENTIUMM
|
||||
default "6" if MK7 || MK8 || MPENTIUMM || MCORE2
|
||||
|
||||
config RWSEM_GENERIC_SPINLOCK
|
||||
bool
|
||||
|
@ -287,17 +294,17 @@ config X86_ALIGNMENT_16
|
|||
|
||||
config X86_GOOD_APIC
|
||||
bool
|
||||
depends on MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || MK8 || MEFFICEON
|
||||
depends on MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || MK8 || MEFFICEON || MCORE2
|
||||
default y
|
||||
|
||||
config X86_INTEL_USERCOPY
|
||||
bool
|
||||
depends on MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M586MMX || X86_GENERIC || MK8 || MK7 || MEFFICEON
|
||||
depends on MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M586MMX || X86_GENERIC || MK8 || MK7 || MEFFICEON || MCORE2
|
||||
default y
|
||||
|
||||
config X86_USE_PPRO_CHECKSUM
|
||||
bool
|
||||
depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MEFFICEON || MGEODE_LX
|
||||
depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MEFFICEON || MGEODE_LX || MCORE2
|
||||
default y
|
||||
|
||||
config X86_USE_3DNOW
|
||||
|
@ -312,5 +319,5 @@ config X86_OOSTORE
|
|||
|
||||
config X86_TSC
|
||||
bool
|
||||
depends on (MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MGEODEGX1 || MGEODE_LX) && !X86_NUMAQ
|
||||
depends on (MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MGEODEGX1 || MGEODE_LX || MCORE2) && !X86_NUMAQ
|
||||
default y
|
||||
|
|
|
@ -85,4 +85,14 @@ config DOUBLEFAULT
|
|||
option saves about 4k and might cause you much additional grey
|
||||
hair.
|
||||
|
||||
config DEBUG_PARAVIRT
|
||||
bool "Enable some paravirtualization debugging"
|
||||
default y
|
||||
depends on PARAVIRT && DEBUG_KERNEL
|
||||
help
|
||||
Currently deliberately clobbers regs which are allowed to be
|
||||
clobbered in inlined paravirt hooks, even in native mode.
|
||||
If turning this off solves a problem, then DISABLE_INTERRUPTS() or
|
||||
ENABLE_INTERRUPTS() is lying about what registers can be clobbered.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -26,10 +26,12 @@ endif
|
|||
|
||||
LDFLAGS := -m elf_i386
|
||||
OBJCOPYFLAGS := -O binary -R .note -R .comment -S
|
||||
LDFLAGS_vmlinux :=
|
||||
ifdef CONFIG_RELOCATABLE
|
||||
LDFLAGS_vmlinux := --emit-relocs
|
||||
endif
|
||||
CHECKFLAGS += -D__i386__
|
||||
|
||||
CFLAGS += -pipe -msoft-float
|
||||
CFLAGS += -pipe -msoft-float -mregparm=3
|
||||
|
||||
# prevent gcc from keeping the stack 16 byte aligned
|
||||
CFLAGS += $(call cc-option,-mpreferred-stack-boundary=2)
|
||||
|
@ -37,8 +39,6 @@ CFLAGS += $(call cc-option,-mpreferred-stack-boundary=2)
|
|||
# CPU-specific tuning. Anything which can be shared with UML should go here.
|
||||
include $(srctree)/arch/i386/Makefile.cpu
|
||||
|
||||
cflags-$(CONFIG_REGPARM) += -mregparm=3
|
||||
|
||||
# temporary until string.h is fixed
|
||||
cflags-y += -ffreestanding
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ cflags-$(CONFIG_MWINCHIP2) += $(call cc-option,-march=winchip2,-march=i586)
|
|||
cflags-$(CONFIG_MWINCHIP3D) += $(call cc-option,-march=winchip2,-march=i586)
|
||||
cflags-$(CONFIG_MCYRIXIII) += $(call cc-option,-march=c3,-march=i486) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0
|
||||
cflags-$(CONFIG_MVIAC3_2) += $(call cc-option,-march=c3-2,-march=i686)
|
||||
cflags-$(CONFIG_MCORE2) += -march=i686 $(call cc-option,-mtune=core2,$(call cc-option,-mtune=generic,-mtune=i686))
|
||||
|
||||
# AMD Elan support
|
||||
cflags-$(CONFIG_X86_ELAN) += -march=i486
|
||||
|
|
|
@ -4,22 +4,42 @@
|
|||
# create a compressed vmlinux image from the original vmlinux
|
||||
#
|
||||
|
||||
targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o
|
||||
targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o \
|
||||
vmlinux.bin.all vmlinux.relocs
|
||||
EXTRA_AFLAGS := -traditional
|
||||
|
||||
LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup_32
|
||||
LDFLAGS_vmlinux := -T
|
||||
CFLAGS_misc.o += -fPIC
|
||||
hostprogs-y := relocs
|
||||
|
||||
$(obj)/vmlinux: $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE
|
||||
$(obj)/vmlinux: $(src)/vmlinux.lds $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE
|
||||
$(call if_changed,ld)
|
||||
@:
|
||||
|
||||
$(obj)/vmlinux.bin: vmlinux FORCE
|
||||
$(call if_changed,objcopy)
|
||||
|
||||
quiet_cmd_relocs = RELOCS $@
|
||||
cmd_relocs = $(obj)/relocs $< > $@;$(obj)/relocs --abs-relocs $<
|
||||
$(obj)/vmlinux.relocs: vmlinux $(obj)/relocs FORCE
|
||||
$(call if_changed,relocs)
|
||||
|
||||
vmlinux.bin.all-y := $(obj)/vmlinux.bin
|
||||
vmlinux.bin.all-$(CONFIG_RELOCATABLE) += $(obj)/vmlinux.relocs
|
||||
quiet_cmd_relocbin = BUILD $@
|
||||
cmd_relocbin = cat $(filter-out FORCE,$^) > $@
|
||||
$(obj)/vmlinux.bin.all: $(vmlinux.bin.all-y) FORCE
|
||||
$(call if_changed,relocbin)
|
||||
|
||||
ifdef CONFIG_RELOCATABLE
|
||||
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin.all FORCE
|
||||
$(call if_changed,gzip)
|
||||
else
|
||||
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,gzip)
|
||||
endif
|
||||
|
||||
LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T
|
||||
|
||||
$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
|
||||
$(obj)/piggy.o: $(src)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
|
||||
$(call if_changed,ld)
|
||||
|
|
|
@ -26,9 +26,11 @@
|
|||
#include <linux/linkage.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/boot.h>
|
||||
|
||||
.section ".text.head"
|
||||
.globl startup_32
|
||||
|
||||
|
||||
startup_32:
|
||||
cld
|
||||
cli
|
||||
|
@ -37,93 +39,142 @@ startup_32:
|
|||
movl %eax,%es
|
||||
movl %eax,%fs
|
||||
movl %eax,%gs
|
||||
movl %eax,%ss
|
||||
|
||||
lss stack_start,%esp
|
||||
xorl %eax,%eax
|
||||
1: incl %eax # check that A20 really IS enabled
|
||||
movl %eax,0x000000 # loop forever if it isn't
|
||||
cmpl %eax,0x100000
|
||||
je 1b
|
||||
/* Calculate the delta between where we were compiled to run
|
||||
* at and where we were actually loaded at. This can only be done
|
||||
* with a short local call on x86. Nothing else will tell us what
|
||||
* address we are running at. The reserved chunk of the real-mode
|
||||
* data at 0x34-0x3f are used as the stack for this calculation.
|
||||
* Only 4 bytes are needed.
|
||||
*/
|
||||
leal 0x40(%esi), %esp
|
||||
call 1f
|
||||
1: popl %ebp
|
||||
subl $1b, %ebp
|
||||
|
||||
/* %ebp contains the address we are loaded at by the boot loader and %ebx
|
||||
* contains the address where we should move the kernel image temporarily
|
||||
* for safe in-place decompression.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_RELOCATABLE
|
||||
movl %ebp, %ebx
|
||||
addl $(CONFIG_PHYSICAL_ALIGN - 1), %ebx
|
||||
andl $(~(CONFIG_PHYSICAL_ALIGN - 1)), %ebx
|
||||
#else
|
||||
movl $LOAD_PHYSICAL_ADDR, %ebx
|
||||
#endif
|
||||
|
||||
/* Replace the compressed data size with the uncompressed size */
|
||||
subl input_len(%ebp), %ebx
|
||||
movl output_len(%ebp), %eax
|
||||
addl %eax, %ebx
|
||||
/* Add 8 bytes for every 32K input block */
|
||||
shrl $12, %eax
|
||||
addl %eax, %ebx
|
||||
/* Add 32K + 18 bytes of extra slack */
|
||||
addl $(32768 + 18), %ebx
|
||||
/* Align on a 4K boundary */
|
||||
addl $4095, %ebx
|
||||
andl $~4095, %ebx
|
||||
|
||||
/* Copy the compressed kernel to the end of our buffer
|
||||
* where decompression in place becomes safe.
|
||||
*/
|
||||
pushl %esi
|
||||
leal _end(%ebp), %esi
|
||||
leal _end(%ebx), %edi
|
||||
movl $(_end - startup_32), %ecx
|
||||
std
|
||||
rep
|
||||
movsb
|
||||
cld
|
||||
popl %esi
|
||||
|
||||
/* Compute the kernel start address.
|
||||
*/
|
||||
#ifdef CONFIG_RELOCATABLE
|
||||
addl $(CONFIG_PHYSICAL_ALIGN - 1), %ebp
|
||||
andl $(~(CONFIG_PHYSICAL_ALIGN - 1)), %ebp
|
||||
#else
|
||||
movl $LOAD_PHYSICAL_ADDR, %ebp
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialize eflags. Some BIOS's leave bits like NT set. This would
|
||||
* confuse the debugger if this code is traced.
|
||||
* XXX - best to initialize before switching to protected mode.
|
||||
* Jump to the relocated address.
|
||||
*/
|
||||
pushl $0
|
||||
popfl
|
||||
leal relocated(%ebx), %eax
|
||||
jmp *%eax
|
||||
.section ".text"
|
||||
relocated:
|
||||
|
||||
/*
|
||||
* Clear BSS
|
||||
*/
|
||||
xorl %eax,%eax
|
||||
movl $_edata,%edi
|
||||
movl $_end,%ecx
|
||||
leal _edata(%ebx),%edi
|
||||
leal _end(%ebx), %ecx
|
||||
subl %edi,%ecx
|
||||
cld
|
||||
rep
|
||||
stosb
|
||||
|
||||
/*
|
||||
* Setup the stack for the decompressor
|
||||
*/
|
||||
leal stack_end(%ebx), %esp
|
||||
|
||||
/*
|
||||
* Do the decompression, and jump to the new kernel..
|
||||
*/
|
||||
subl $16,%esp # place for structure on the stack
|
||||
movl %esp,%eax
|
||||
movl output_len(%ebx), %eax
|
||||
pushl %eax
|
||||
pushl %ebp # output address
|
||||
movl input_len(%ebx), %eax
|
||||
pushl %eax # input_len
|
||||
leal input_data(%ebx), %eax
|
||||
pushl %eax # input_data
|
||||
leal _end(%ebx), %eax
|
||||
pushl %eax # end of the image as third argument
|
||||
pushl %esi # real mode pointer as second arg
|
||||
pushl %eax # address of structure as first arg
|
||||
call decompress_kernel
|
||||
orl %eax,%eax
|
||||
jnz 3f
|
||||
popl %esi # discard address
|
||||
popl %esi # real mode pointer
|
||||
xorl %ebx,%ebx
|
||||
ljmp $(__BOOT_CS), $__PHYSICAL_START
|
||||
addl $20, %esp
|
||||
popl %ecx
|
||||
|
||||
#if CONFIG_RELOCATABLE
|
||||
/* Find the address of the relocations.
|
||||
*/
|
||||
movl %ebp, %edi
|
||||
addl %ecx, %edi
|
||||
|
||||
/* Calculate the delta between where vmlinux was compiled to run
|
||||
* and where it was actually loaded.
|
||||
*/
|
||||
movl %ebp, %ebx
|
||||
subl $LOAD_PHYSICAL_ADDR, %ebx
|
||||
jz 2f /* Nothing to be done if loaded at compiled addr. */
|
||||
/*
|
||||
* Process relocations.
|
||||
*/
|
||||
|
||||
1: subl $4, %edi
|
||||
movl 0(%edi), %ecx
|
||||
testl %ecx, %ecx
|
||||
jz 2f
|
||||
addl %ebx, -__PAGE_OFFSET(%ebx, %ecx)
|
||||
jmp 1b
|
||||
2:
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We come here, if we were loaded high.
|
||||
* We need to move the move-in-place routine down to 0x1000
|
||||
* and then start it with the buffer addresses in registers,
|
||||
* which we got from the stack.
|
||||
* Jump to the decompressed kernel.
|
||||
*/
|
||||
3:
|
||||
movl $move_routine_start,%esi
|
||||
movl $0x1000,%edi
|
||||
movl $move_routine_end,%ecx
|
||||
subl %esi,%ecx
|
||||
addl $3,%ecx
|
||||
shrl $2,%ecx
|
||||
cld
|
||||
rep
|
||||
movsl
|
||||
|
||||
popl %esi # discard the address
|
||||
popl %ebx # real mode pointer
|
||||
popl %esi # low_buffer_start
|
||||
popl %ecx # lcount
|
||||
popl %edx # high_buffer_start
|
||||
popl %eax # hcount
|
||||
movl $__PHYSICAL_START,%edi
|
||||
cli # make sure we don't get interrupted
|
||||
ljmp $(__BOOT_CS), $0x1000 # and jump to the move routine
|
||||
|
||||
/*
|
||||
* Routine (template) for moving the decompressed kernel in place,
|
||||
* if we were high loaded. This _must_ PIC-code !
|
||||
*/
|
||||
move_routine_start:
|
||||
movl %ecx,%ebp
|
||||
shrl $2,%ecx
|
||||
rep
|
||||
movsl
|
||||
movl %ebp,%ecx
|
||||
andl $3,%ecx
|
||||
rep
|
||||
movsb
|
||||
movl %edx,%esi
|
||||
movl %eax,%ecx # NOTE: rep movsb won't move if %ecx == 0
|
||||
addl $3,%ecx
|
||||
shrl $2,%ecx
|
||||
rep
|
||||
movsl
|
||||
movl %ebx,%esi # Restore setup pointer
|
||||
xorl %ebx,%ebx
|
||||
ljmp $(__BOOT_CS), $__PHYSICAL_START
|
||||
move_routine_end:
|
||||
jmp *%ebp
|
||||
|
||||
.bss
|
||||
.balign 4
|
||||
stack:
|
||||
.fill 4096, 1, 0
|
||||
stack_end:
|
||||
|
|
|
@ -9,11 +9,94 @@
|
|||
* High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
|
||||
*/
|
||||
|
||||
#undef CONFIG_PARAVIRT
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/screen_info.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/boot.h>
|
||||
|
||||
/* WARNING!!
|
||||
* This code is compiled with -fPIC and it is relocated dynamically
|
||||
* at run time, but no relocation processing is performed.
|
||||
* This means that it is not safe to place pointers in static structures.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Getting to provable safe in place decompression is hard.
|
||||
* Worst case behaviours need to be analized.
|
||||
* Background information:
|
||||
*
|
||||
* The file layout is:
|
||||
* magic[2]
|
||||
* method[1]
|
||||
* flags[1]
|
||||
* timestamp[4]
|
||||
* extraflags[1]
|
||||
* os[1]
|
||||
* compressed data blocks[N]
|
||||
* crc[4] orig_len[4]
|
||||
*
|
||||
* resulting in 18 bytes of non compressed data overhead.
|
||||
*
|
||||
* Files divided into blocks
|
||||
* 1 bit (last block flag)
|
||||
* 2 bits (block type)
|
||||
*
|
||||
* 1 block occurs every 32K -1 bytes or when there 50% compression has been achieved.
|
||||
* The smallest block type encoding is always used.
|
||||
*
|
||||
* stored:
|
||||
* 32 bits length in bytes.
|
||||
*
|
||||
* fixed:
|
||||
* magic fixed tree.
|
||||
* symbols.
|
||||
*
|
||||
* dynamic:
|
||||
* dynamic tree encoding.
|
||||
* symbols.
|
||||
*
|
||||
*
|
||||
* The buffer for decompression in place is the length of the
|
||||
* uncompressed data, plus a small amount extra to keep the algorithm safe.
|
||||
* The compressed data is placed at the end of the buffer. The output
|
||||
* pointer is placed at the start of the buffer and the input pointer
|
||||
* is placed where the compressed data starts. Problems will occur
|
||||
* when the output pointer overruns the input pointer.
|
||||
*
|
||||
* The output pointer can only overrun the input pointer if the input
|
||||
* pointer is moving faster than the output pointer. A condition only
|
||||
* triggered by data whose compressed form is larger than the uncompressed
|
||||
* form.
|
||||
*
|
||||
* The worst case at the block level is a growth of the compressed data
|
||||
* of 5 bytes per 32767 bytes.
|
||||
*
|
||||
* The worst case internal to a compressed block is very hard to figure.
|
||||
* The worst case can at least be boundined by having one bit that represents
|
||||
* 32764 bytes and then all of the rest of the bytes representing the very
|
||||
* very last byte.
|
||||
*
|
||||
* All of which is enough to compute an amount of extra data that is required
|
||||
* to be safe. To avoid problems at the block level allocating 5 extra bytes
|
||||
* per 32767 bytes of data is sufficient. To avoind problems internal to a block
|
||||
* adding an extra 32767 bytes (the worst case uncompressed block size) is
|
||||
* sufficient, to ensure that in the worst case the decompressed data for
|
||||
* block will stop the byte before the compressed data for a block begins.
|
||||
* To avoid problems with the compressed data's meta information an extra 18
|
||||
* bytes are needed. Leading to the formula:
|
||||
*
|
||||
* extra_bytes = (uncompressed_size >> 12) + 32768 + 18 + decompressor_size.
|
||||
*
|
||||
* Adding 8 bytes per 32K is a bit excessive but much easier to calculate.
|
||||
* Adding 32768 instead of 32767 just makes for round numbers.
|
||||
* Adding the decompressor_size is necessary as it musht live after all
|
||||
* of the data as well. Last I measured the decompressor is about 14K.
|
||||
* 10K of actuall data and 4K of bss.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* gzip declarations
|
||||
|
@ -30,15 +113,20 @@ typedef unsigned char uch;
|
|||
typedef unsigned short ush;
|
||||
typedef unsigned long ulg;
|
||||
|
||||
#define WSIZE 0x8000 /* Window size must be at least 32k, */
|
||||
/* and a power of two */
|
||||
#define WSIZE 0x80000000 /* Window size must be at least 32k,
|
||||
* and a power of two
|
||||
* We don't actually have a window just
|
||||
* a huge output buffer so I report
|
||||
* a 2G windows size, as that should
|
||||
* always be larger than our output buffer.
|
||||
*/
|
||||
|
||||
static uch *inbuf; /* input buffer */
|
||||
static uch window[WSIZE]; /* Sliding window buffer */
|
||||
static uch *inbuf; /* input buffer */
|
||||
static uch *window; /* Sliding window buffer, (and final output buffer) */
|
||||
|
||||
static unsigned insize = 0; /* valid bytes in inbuf */
|
||||
static unsigned inptr = 0; /* index of next byte to be processed in inbuf */
|
||||
static unsigned outcnt = 0; /* bytes in output buffer */
|
||||
static unsigned insize; /* valid bytes in inbuf */
|
||||
static unsigned inptr; /* index of next byte to be processed in inbuf */
|
||||
static unsigned outcnt; /* bytes in output buffer */
|
||||
|
||||
/* gzip flag byte */
|
||||
#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
|
||||
|
@ -89,8 +177,6 @@ extern unsigned char input_data[];
|
|||
extern int input_len;
|
||||
|
||||
static long bytes_out = 0;
|
||||
static uch *output_data;
|
||||
static unsigned long output_ptr = 0;
|
||||
|
||||
static void *malloc(int size);
|
||||
static void free(void *where);
|
||||
|
@ -100,24 +186,17 @@ static void *memcpy(void *dest, const void *src, unsigned n);
|
|||
|
||||
static void putstr(const char *);
|
||||
|
||||
extern int end;
|
||||
static long free_mem_ptr = (long)&end;
|
||||
static long free_mem_end_ptr;
|
||||
static unsigned long free_mem_ptr;
|
||||
static unsigned long free_mem_end_ptr;
|
||||
|
||||
#define INPLACE_MOVE_ROUTINE 0x1000
|
||||
#define LOW_BUFFER_START 0x2000
|
||||
#define LOW_BUFFER_MAX 0x90000
|
||||
#define HEAP_SIZE 0x3000
|
||||
static unsigned int low_buffer_end, low_buffer_size;
|
||||
static int high_loaded =0;
|
||||
static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/;
|
||||
|
||||
static char *vidmem = (char *)0xb8000;
|
||||
static int vidport;
|
||||
static int lines, cols;
|
||||
|
||||
#ifdef CONFIG_X86_NUMAQ
|
||||
static void * xquad_portio = NULL;
|
||||
void *xquad_portio;
|
||||
#endif
|
||||
|
||||
#include "../../../../lib/inflate.c"
|
||||
|
@ -151,7 +230,7 @@ static void gzip_mark(void **ptr)
|
|||
|
||||
static void gzip_release(void **ptr)
|
||||
{
|
||||
free_mem_ptr = (long) *ptr;
|
||||
free_mem_ptr = (unsigned long) *ptr;
|
||||
}
|
||||
|
||||
static void scroll(void)
|
||||
|
@ -179,7 +258,7 @@ static void putstr(const char *s)
|
|||
y--;
|
||||
}
|
||||
} else {
|
||||
vidmem [ ( x + cols * y ) * 2 ] = c;
|
||||
vidmem [ ( x + cols * y ) * 2 ] = c;
|
||||
if ( ++x >= cols ) {
|
||||
x = 0;
|
||||
if ( ++y >= lines ) {
|
||||
|
@ -224,58 +303,31 @@ static void* memcpy(void* dest, const void* src, unsigned n)
|
|||
*/
|
||||
static int fill_inbuf(void)
|
||||
{
|
||||
if (insize != 0) {
|
||||
error("ran out of input data");
|
||||
}
|
||||
|
||||
inbuf = input_data;
|
||||
insize = input_len;
|
||||
inptr = 1;
|
||||
return inbuf[0];
|
||||
error("ran out of input data");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ===========================================================================
|
||||
* Write the output window window[0..outcnt-1] and update crc and bytes_out.
|
||||
* (Used for the decompressed data only.)
|
||||
*/
|
||||
static void flush_window_low(void)
|
||||
{
|
||||
ulg c = crc; /* temporary variable */
|
||||
unsigned n;
|
||||
uch *in, *out, ch;
|
||||
|
||||
in = window;
|
||||
out = &output_data[output_ptr];
|
||||
for (n = 0; n < outcnt; n++) {
|
||||
ch = *out++ = *in++;
|
||||
c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
|
||||
}
|
||||
crc = c;
|
||||
bytes_out += (ulg)outcnt;
|
||||
output_ptr += (ulg)outcnt;
|
||||
outcnt = 0;
|
||||
}
|
||||
|
||||
static void flush_window_high(void)
|
||||
{
|
||||
ulg c = crc; /* temporary variable */
|
||||
unsigned n;
|
||||
uch *in, ch;
|
||||
in = window;
|
||||
for (n = 0; n < outcnt; n++) {
|
||||
ch = *output_data++ = *in++;
|
||||
if ((ulg)output_data == low_buffer_end) output_data=high_buffer_start;
|
||||
c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
|
||||
}
|
||||
crc = c;
|
||||
bytes_out += (ulg)outcnt;
|
||||
outcnt = 0;
|
||||
}
|
||||
|
||||
static void flush_window(void)
|
||||
{
|
||||
if (high_loaded) flush_window_high();
|
||||
else flush_window_low();
|
||||
/* With my window equal to my output buffer
|
||||
* I only need to compute the crc here.
|
||||
*/
|
||||
ulg c = crc; /* temporary variable */
|
||||
unsigned n;
|
||||
uch *in, ch;
|
||||
|
||||
in = window;
|
||||
for (n = 0; n < outcnt; n++) {
|
||||
ch = *in++;
|
||||
c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
|
||||
}
|
||||
crc = c;
|
||||
bytes_out += (ulg)outcnt;
|
||||
outcnt = 0;
|
||||
}
|
||||
|
||||
static void error(char *x)
|
||||
|
@ -287,66 +339,8 @@ static void error(char *x)
|
|||
while(1); /* Halt */
|
||||
}
|
||||
|
||||
#define STACK_SIZE (4096)
|
||||
|
||||
long user_stack [STACK_SIZE];
|
||||
|
||||
struct {
|
||||
long * a;
|
||||
short b;
|
||||
} stack_start = { & user_stack [STACK_SIZE] , __BOOT_DS };
|
||||
|
||||
static void setup_normal_output_buffer(void)
|
||||
{
|
||||
#ifdef STANDARD_MEMORY_BIOS_CALL
|
||||
if (RM_EXT_MEM_K < 1024) error("Less than 2MB of memory");
|
||||
#else
|
||||
if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < 1024) error("Less than 2MB of memory");
|
||||
#endif
|
||||
output_data = (unsigned char *)__PHYSICAL_START; /* Normally Points to 1M */
|
||||
free_mem_end_ptr = (long)real_mode;
|
||||
}
|
||||
|
||||
struct moveparams {
|
||||
uch *low_buffer_start; int lcount;
|
||||
uch *high_buffer_start; int hcount;
|
||||
};
|
||||
|
||||
static void setup_output_buffer_if_we_run_high(struct moveparams *mv)
|
||||
{
|
||||
high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE);
|
||||
#ifdef STANDARD_MEMORY_BIOS_CALL
|
||||
if (RM_EXT_MEM_K < (3*1024)) error("Less than 4MB of memory");
|
||||
#else
|
||||
if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < (3*1024)) error("Less than 4MB of memory");
|
||||
#endif
|
||||
mv->low_buffer_start = output_data = (unsigned char *)LOW_BUFFER_START;
|
||||
low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX
|
||||
? LOW_BUFFER_MAX : (unsigned int)real_mode) & ~0xfff;
|
||||
low_buffer_size = low_buffer_end - LOW_BUFFER_START;
|
||||
high_loaded = 1;
|
||||
free_mem_end_ptr = (long)high_buffer_start;
|
||||
if ( (__PHYSICAL_START + low_buffer_size) > ((ulg)high_buffer_start)) {
|
||||
high_buffer_start = (uch *)(__PHYSICAL_START + low_buffer_size);
|
||||
mv->hcount = 0; /* say: we need not to move high_buffer */
|
||||
}
|
||||
else mv->hcount = -1;
|
||||
mv->high_buffer_start = high_buffer_start;
|
||||
}
|
||||
|
||||
static void close_output_buffer_if_we_run_high(struct moveparams *mv)
|
||||
{
|
||||
if (bytes_out > low_buffer_size) {
|
||||
mv->lcount = low_buffer_size;
|
||||
if (mv->hcount)
|
||||
mv->hcount = bytes_out - low_buffer_size;
|
||||
} else {
|
||||
mv->lcount = bytes_out;
|
||||
mv->hcount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
asmlinkage int decompress_kernel(struct moveparams *mv, void *rmode)
|
||||
asmlinkage void decompress_kernel(void *rmode, unsigned long end,
|
||||
uch *input_data, unsigned long input_len, uch *output)
|
||||
{
|
||||
real_mode = rmode;
|
||||
|
||||
|
@ -361,13 +355,25 @@ asmlinkage int decompress_kernel(struct moveparams *mv, void *rmode)
|
|||
lines = RM_SCREEN_INFO.orig_video_lines;
|
||||
cols = RM_SCREEN_INFO.orig_video_cols;
|
||||
|
||||
if (free_mem_ptr < 0x100000) setup_normal_output_buffer();
|
||||
else setup_output_buffer_if_we_run_high(mv);
|
||||
window = output; /* Output buffer (Normally at 1M) */
|
||||
free_mem_ptr = end; /* Heap */
|
||||
free_mem_end_ptr = end + HEAP_SIZE;
|
||||
inbuf = input_data; /* Input buffer */
|
||||
insize = input_len;
|
||||
inptr = 0;
|
||||
|
||||
if ((u32)output & (CONFIG_PHYSICAL_ALIGN -1))
|
||||
error("Destination address not CONFIG_PHYSICAL_ALIGN aligned");
|
||||
if (end > ((-__PAGE_OFFSET-(512 <<20)-1) & 0x7fffffff))
|
||||
error("Destination address too large");
|
||||
#ifndef CONFIG_RELOCATABLE
|
||||
if ((u32)output != LOAD_PHYSICAL_ADDR)
|
||||
error("Wrong destination address");
|
||||
#endif
|
||||
|
||||
makecrc();
|
||||
putstr("Uncompressing Linux... ");
|
||||
gunzip();
|
||||
putstr("Ok, booting the kernel.\n");
|
||||
if (high_loaded) close_output_buffer_if_we_run_high(mv);
|
||||
return high_loaded;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,625 @@
|
|||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <elf.h>
|
||||
#include <byteswap.h>
|
||||
#define USE_BSD
|
||||
#include <endian.h>
|
||||
|
||||
#define MAX_SHDRS 100
|
||||
static Elf32_Ehdr ehdr;
|
||||
static Elf32_Shdr shdr[MAX_SHDRS];
|
||||
static Elf32_Sym *symtab[MAX_SHDRS];
|
||||
static Elf32_Rel *reltab[MAX_SHDRS];
|
||||
static char *strtab[MAX_SHDRS];
|
||||
static unsigned long reloc_count, reloc_idx;
|
||||
static unsigned long *relocs;
|
||||
|
||||
/*
|
||||
* Following symbols have been audited. There values are constant and do
|
||||
* not change if bzImage is loaded at a different physical address than
|
||||
* the address for which it has been compiled. Don't warn user about
|
||||
* absolute relocations present w.r.t these symbols.
|
||||
*/
|
||||
static const char* safe_abs_relocs[] = {
|
||||
"__kernel_vsyscall",
|
||||
"__kernel_rt_sigreturn",
|
||||
"__kernel_sigreturn",
|
||||
"SYSENTER_RETURN",
|
||||
};
|
||||
|
||||
static int is_safe_abs_reloc(const char* sym_name)
|
||||
{
|
||||
int i, array_size;
|
||||
|
||||
array_size = sizeof(safe_abs_relocs)/sizeof(char*);
|
||||
|
||||
for(i = 0; i < array_size; i++) {
|
||||
if (!strcmp(sym_name, safe_abs_relocs[i]))
|
||||
/* Match found */
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void die(char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static const char *sym_type(unsigned type)
|
||||
{
|
||||
static const char *type_name[] = {
|
||||
#define SYM_TYPE(X) [X] = #X
|
||||
SYM_TYPE(STT_NOTYPE),
|
||||
SYM_TYPE(STT_OBJECT),
|
||||
SYM_TYPE(STT_FUNC),
|
||||
SYM_TYPE(STT_SECTION),
|
||||
SYM_TYPE(STT_FILE),
|
||||
SYM_TYPE(STT_COMMON),
|
||||
SYM_TYPE(STT_TLS),
|
||||
#undef SYM_TYPE
|
||||
};
|
||||
const char *name = "unknown sym type name";
|
||||
if (type < sizeof(type_name)/sizeof(type_name[0])) {
|
||||
name = type_name[type];
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
static const char *sym_bind(unsigned bind)
|
||||
{
|
||||
static const char *bind_name[] = {
|
||||
#define SYM_BIND(X) [X] = #X
|
||||
SYM_BIND(STB_LOCAL),
|
||||
SYM_BIND(STB_GLOBAL),
|
||||
SYM_BIND(STB_WEAK),
|
||||
#undef SYM_BIND
|
||||
};
|
||||
const char *name = "unknown sym bind name";
|
||||
if (bind < sizeof(bind_name)/sizeof(bind_name[0])) {
|
||||
name = bind_name[bind];
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
static const char *sym_visibility(unsigned visibility)
|
||||
{
|
||||
static const char *visibility_name[] = {
|
||||
#define SYM_VISIBILITY(X) [X] = #X
|
||||
SYM_VISIBILITY(STV_DEFAULT),
|
||||
SYM_VISIBILITY(STV_INTERNAL),
|
||||
SYM_VISIBILITY(STV_HIDDEN),
|
||||
SYM_VISIBILITY(STV_PROTECTED),
|
||||
#undef SYM_VISIBILITY
|
||||
};
|
||||
const char *name = "unknown sym visibility name";
|
||||
if (visibility < sizeof(visibility_name)/sizeof(visibility_name[0])) {
|
||||
name = visibility_name[visibility];
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
static const char *rel_type(unsigned type)
|
||||
{
|
||||
static const char *type_name[] = {
|
||||
#define REL_TYPE(X) [X] = #X
|
||||
REL_TYPE(R_386_NONE),
|
||||
REL_TYPE(R_386_32),
|
||||
REL_TYPE(R_386_PC32),
|
||||
REL_TYPE(R_386_GOT32),
|
||||
REL_TYPE(R_386_PLT32),
|
||||
REL_TYPE(R_386_COPY),
|
||||
REL_TYPE(R_386_GLOB_DAT),
|
||||
REL_TYPE(R_386_JMP_SLOT),
|
||||
REL_TYPE(R_386_RELATIVE),
|
||||
REL_TYPE(R_386_GOTOFF),
|
||||
REL_TYPE(R_386_GOTPC),
|
||||
#undef REL_TYPE
|
||||
};
|
||||
const char *name = "unknown type rel type name";
|
||||
if (type < sizeof(type_name)/sizeof(type_name[0])) {
|
||||
name = type_name[type];
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
static const char *sec_name(unsigned shndx)
|
||||
{
|
||||
const char *sec_strtab;
|
||||
const char *name;
|
||||
sec_strtab = strtab[ehdr.e_shstrndx];
|
||||
name = "<noname>";
|
||||
if (shndx < ehdr.e_shnum) {
|
||||
name = sec_strtab + shdr[shndx].sh_name;
|
||||
}
|
||||
else if (shndx == SHN_ABS) {
|
||||
name = "ABSOLUTE";
|
||||
}
|
||||
else if (shndx == SHN_COMMON) {
|
||||
name = "COMMON";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym)
|
||||
{
|
||||
const char *name;
|
||||
name = "<noname>";
|
||||
if (sym->st_name) {
|
||||
name = sym_strtab + sym->st_name;
|
||||
}
|
||||
else {
|
||||
name = sec_name(shdr[sym->st_shndx].sh_name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
#define le16_to_cpu(val) (val)
|
||||
#define le32_to_cpu(val) (val)
|
||||
#endif
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
#define le16_to_cpu(val) bswap_16(val)
|
||||
#define le32_to_cpu(val) bswap_32(val)
|
||||
#endif
|
||||
|
||||
static uint16_t elf16_to_cpu(uint16_t val)
|
||||
{
|
||||
return le16_to_cpu(val);
|
||||
}
|
||||
|
||||
static uint32_t elf32_to_cpu(uint32_t val)
|
||||
{
|
||||
return le32_to_cpu(val);
|
||||
}
|
||||
|
||||
static void read_ehdr(FILE *fp)
|
||||
{
|
||||
if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) {
|
||||
die("Cannot read ELF header: %s\n",
|
||||
strerror(errno));
|
||||
}
|
||||
if (memcmp(ehdr.e_ident, ELFMAG, 4) != 0) {
|
||||
die("No ELF magic\n");
|
||||
}
|
||||
if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) {
|
||||
die("Not a 32 bit executable\n");
|
||||
}
|
||||
if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) {
|
||||
die("Not a LSB ELF executable\n");
|
||||
}
|
||||
if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
|
||||
die("Unknown ELF version\n");
|
||||
}
|
||||
/* Convert the fields to native endian */
|
||||
ehdr.e_type = elf16_to_cpu(ehdr.e_type);
|
||||
ehdr.e_machine = elf16_to_cpu(ehdr.e_machine);
|
||||
ehdr.e_version = elf32_to_cpu(ehdr.e_version);
|
||||
ehdr.e_entry = elf32_to_cpu(ehdr.e_entry);
|
||||
ehdr.e_phoff = elf32_to_cpu(ehdr.e_phoff);
|
||||
ehdr.e_shoff = elf32_to_cpu(ehdr.e_shoff);
|
||||
ehdr.e_flags = elf32_to_cpu(ehdr.e_flags);
|
||||
ehdr.e_ehsize = elf16_to_cpu(ehdr.e_ehsize);
|
||||
ehdr.e_phentsize = elf16_to_cpu(ehdr.e_phentsize);
|
||||
ehdr.e_phnum = elf16_to_cpu(ehdr.e_phnum);
|
||||
ehdr.e_shentsize = elf16_to_cpu(ehdr.e_shentsize);
|
||||
ehdr.e_shnum = elf16_to_cpu(ehdr.e_shnum);
|
||||
ehdr.e_shstrndx = elf16_to_cpu(ehdr.e_shstrndx);
|
||||
|
||||
if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) {
|
||||
die("Unsupported ELF header type\n");
|
||||
}
|
||||
if (ehdr.e_machine != EM_386) {
|
||||
die("Not for x86\n");
|
||||
}
|
||||
if (ehdr.e_version != EV_CURRENT) {
|
||||
die("Unknown ELF version\n");
|
||||
}
|
||||
if (ehdr.e_ehsize != sizeof(Elf32_Ehdr)) {
|
||||
die("Bad Elf header size\n");
|
||||
}
|
||||
if (ehdr.e_phentsize != sizeof(Elf32_Phdr)) {
|
||||
die("Bad program header entry\n");
|
||||
}
|
||||
if (ehdr.e_shentsize != sizeof(Elf32_Shdr)) {
|
||||
die("Bad section header entry\n");
|
||||
}
|
||||
if (ehdr.e_shstrndx >= ehdr.e_shnum) {
|
||||
die("String table index out of bounds\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void read_shdrs(FILE *fp)
|
||||
{
|
||||
int i;
|
||||
if (ehdr.e_shnum > MAX_SHDRS) {
|
||||
die("%d section headers supported: %d\n",
|
||||
ehdr.e_shnum, MAX_SHDRS);
|
||||
}
|
||||
if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) {
|
||||
die("Seek to %d failed: %s\n",
|
||||
ehdr.e_shoff, strerror(errno));
|
||||
}
|
||||
if (fread(&shdr, sizeof(shdr[0]), ehdr.e_shnum, fp) != ehdr.e_shnum) {
|
||||
die("Cannot read ELF section headers: %s\n",
|
||||
strerror(errno));
|
||||
}
|
||||
for(i = 0; i < ehdr.e_shnum; i++) {
|
||||
shdr[i].sh_name = elf32_to_cpu(shdr[i].sh_name);
|
||||
shdr[i].sh_type = elf32_to_cpu(shdr[i].sh_type);
|
||||
shdr[i].sh_flags = elf32_to_cpu(shdr[i].sh_flags);
|
||||
shdr[i].sh_addr = elf32_to_cpu(shdr[i].sh_addr);
|
||||
shdr[i].sh_offset = elf32_to_cpu(shdr[i].sh_offset);
|
||||
shdr[i].sh_size = elf32_to_cpu(shdr[i].sh_size);
|
||||
shdr[i].sh_link = elf32_to_cpu(shdr[i].sh_link);
|
||||
shdr[i].sh_info = elf32_to_cpu(shdr[i].sh_info);
|
||||
shdr[i].sh_addralign = elf32_to_cpu(shdr[i].sh_addralign);
|
||||
shdr[i].sh_entsize = elf32_to_cpu(shdr[i].sh_entsize);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void read_strtabs(FILE *fp)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < ehdr.e_shnum; i++) {
|
||||
if (shdr[i].sh_type != SHT_STRTAB) {
|
||||
continue;
|
||||
}
|
||||
strtab[i] = malloc(shdr[i].sh_size);
|
||||
if (!strtab[i]) {
|
||||
die("malloc of %d bytes for strtab failed\n",
|
||||
shdr[i].sh_size);
|
||||
}
|
||||
if (fseek(fp, shdr[i].sh_offset, SEEK_SET) < 0) {
|
||||
die("Seek to %d failed: %s\n",
|
||||
shdr[i].sh_offset, strerror(errno));
|
||||
}
|
||||
if (fread(strtab[i], 1, shdr[i].sh_size, fp) != shdr[i].sh_size) {
|
||||
die("Cannot read symbol table: %s\n",
|
||||
strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void read_symtabs(FILE *fp)
|
||||
{
|
||||
int i,j;
|
||||
for(i = 0; i < ehdr.e_shnum; i++) {
|
||||
if (shdr[i].sh_type != SHT_SYMTAB) {
|
||||
continue;
|
||||
}
|
||||
symtab[i] = malloc(shdr[i].sh_size);
|
||||
if (!symtab[i]) {
|
||||
die("malloc of %d bytes for symtab failed\n",
|
||||
shdr[i].sh_size);
|
||||
}
|
||||
if (fseek(fp, shdr[i].sh_offset, SEEK_SET) < 0) {
|
||||
die("Seek to %d failed: %s\n",
|
||||
shdr[i].sh_offset, strerror(errno));
|
||||
}
|
||||
if (fread(symtab[i], 1, shdr[i].sh_size, fp) != shdr[i].sh_size) {
|
||||
die("Cannot read symbol table: %s\n",
|
||||
strerror(errno));
|
||||
}
|
||||
for(j = 0; j < shdr[i].sh_size/sizeof(symtab[i][0]); j++) {
|
||||
symtab[i][j].st_name = elf32_to_cpu(symtab[i][j].st_name);
|
||||
symtab[i][j].st_value = elf32_to_cpu(symtab[i][j].st_value);
|
||||
symtab[i][j].st_size = elf32_to_cpu(symtab[i][j].st_size);
|
||||
symtab[i][j].st_shndx = elf16_to_cpu(symtab[i][j].st_shndx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void read_relocs(FILE *fp)
|
||||
{
|
||||
int i,j;
|
||||
for(i = 0; i < ehdr.e_shnum; i++) {
|
||||
if (shdr[i].sh_type != SHT_REL) {
|
||||
continue;
|
||||
}
|
||||
reltab[i] = malloc(shdr[i].sh_size);
|
||||
if (!reltab[i]) {
|
||||
die("malloc of %d bytes for relocs failed\n",
|
||||
shdr[i].sh_size);
|
||||
}
|
||||
if (fseek(fp, shdr[i].sh_offset, SEEK_SET) < 0) {
|
||||
die("Seek to %d failed: %s\n",
|
||||
shdr[i].sh_offset, strerror(errno));
|
||||
}
|
||||
if (fread(reltab[i], 1, shdr[i].sh_size, fp) != shdr[i].sh_size) {
|
||||
die("Cannot read symbol table: %s\n",
|
||||
strerror(errno));
|
||||
}
|
||||
for(j = 0; j < shdr[i].sh_size/sizeof(reltab[0][0]); j++) {
|
||||
reltab[i][j].r_offset = elf32_to_cpu(reltab[i][j].r_offset);
|
||||
reltab[i][j].r_info = elf32_to_cpu(reltab[i][j].r_info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void print_absolute_symbols(void)
|
||||
{
|
||||
int i;
|
||||
printf("Absolute symbols\n");
|
||||
printf(" Num: Value Size Type Bind Visibility Name\n");
|
||||
for(i = 0; i < ehdr.e_shnum; i++) {
|
||||
char *sym_strtab;
|
||||
Elf32_Sym *sh_symtab;
|
||||
int j;
|
||||
if (shdr[i].sh_type != SHT_SYMTAB) {
|
||||
continue;
|
||||
}
|
||||
sh_symtab = symtab[i];
|
||||
sym_strtab = strtab[shdr[i].sh_link];
|
||||
for(j = 0; j < shdr[i].sh_size/sizeof(symtab[0][0]); j++) {
|
||||
Elf32_Sym *sym;
|
||||
const char *name;
|
||||
sym = &symtab[i][j];
|
||||
name = sym_name(sym_strtab, sym);
|
||||
if (sym->st_shndx != SHN_ABS) {
|
||||
continue;
|
||||
}
|
||||
printf("%5d %08x %5d %10s %10s %12s %s\n",
|
||||
j, sym->st_value, sym->st_size,
|
||||
sym_type(ELF32_ST_TYPE(sym->st_info)),
|
||||
sym_bind(ELF32_ST_BIND(sym->st_info)),
|
||||
sym_visibility(ELF32_ST_VISIBILITY(sym->st_other)),
|
||||
name);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void print_absolute_relocs(void)
|
||||
{
|
||||
int i, printed = 0;
|
||||
|
||||
for(i = 0; i < ehdr.e_shnum; i++) {
|
||||
char *sym_strtab;
|
||||
Elf32_Sym *sh_symtab;
|
||||
unsigned sec_applies, sec_symtab;
|
||||
int j;
|
||||
if (shdr[i].sh_type != SHT_REL) {
|
||||
continue;
|
||||
}
|
||||
sec_symtab = shdr[i].sh_link;
|
||||
sec_applies = shdr[i].sh_info;
|
||||
if (!(shdr[sec_applies].sh_flags & SHF_ALLOC)) {
|
||||
continue;
|
||||
}
|
||||
sh_symtab = symtab[sec_symtab];
|
||||
sym_strtab = strtab[shdr[sec_symtab].sh_link];
|
||||
for(j = 0; j < shdr[i].sh_size/sizeof(reltab[0][0]); j++) {
|
||||
Elf32_Rel *rel;
|
||||
Elf32_Sym *sym;
|
||||
const char *name;
|
||||
rel = &reltab[i][j];
|
||||
sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
|
||||
name = sym_name(sym_strtab, sym);
|
||||
if (sym->st_shndx != SHN_ABS) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Absolute symbols are not relocated if bzImage is
|
||||
* loaded at a non-compiled address. Display a warning
|
||||
* to user at compile time about the absolute
|
||||
* relocations present.
|
||||
*
|
||||
* User need to audit the code to make sure
|
||||
* some symbols which should have been section
|
||||
* relative have not become absolute because of some
|
||||
* linker optimization or wrong programming usage.
|
||||
*
|
||||
* Before warning check if this absolute symbol
|
||||
* relocation is harmless.
|
||||
*/
|
||||
if (is_safe_abs_reloc(name))
|
||||
continue;
|
||||
|
||||
if (!printed) {
|
||||
printf("WARNING: Absolute relocations"
|
||||
" present\n");
|
||||
printf("Offset Info Type Sym.Value "
|
||||
"Sym.Name\n");
|
||||
printed = 1;
|
||||
}
|
||||
|
||||
printf("%08x %08x %10s %08x %s\n",
|
||||
rel->r_offset,
|
||||
rel->r_info,
|
||||
rel_type(ELF32_R_TYPE(rel->r_info)),
|
||||
sym->st_value,
|
||||
name);
|
||||
}
|
||||
}
|
||||
|
||||
if (printed)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym))
|
||||
{
|
||||
int i;
|
||||
/* Walk through the relocations */
|
||||
for(i = 0; i < ehdr.e_shnum; i++) {
|
||||
char *sym_strtab;
|
||||
Elf32_Sym *sh_symtab;
|
||||
unsigned sec_applies, sec_symtab;
|
||||
int j;
|
||||
if (shdr[i].sh_type != SHT_REL) {
|
||||
continue;
|
||||
}
|
||||
sec_symtab = shdr[i].sh_link;
|
||||
sec_applies = shdr[i].sh_info;
|
||||
if (!(shdr[sec_applies].sh_flags & SHF_ALLOC)) {
|
||||
continue;
|
||||
}
|
||||
sh_symtab = symtab[sec_symtab];
|
||||
sym_strtab = strtab[shdr[sec_symtab].sh_link];
|
||||
for(j = 0; j < shdr[i].sh_size/sizeof(reltab[0][0]); j++) {
|
||||
Elf32_Rel *rel;
|
||||
Elf32_Sym *sym;
|
||||
unsigned r_type;
|
||||
rel = &reltab[i][j];
|
||||
sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
|
||||
r_type = ELF32_R_TYPE(rel->r_info);
|
||||
/* Don't visit relocations to absolute symbols */
|
||||
if (sym->st_shndx == SHN_ABS) {
|
||||
continue;
|
||||
}
|
||||
if (r_type == R_386_PC32) {
|
||||
/* PC relative relocations don't need to be adjusted */
|
||||
}
|
||||
else if (r_type == R_386_32) {
|
||||
/* Visit relocations that need to be adjusted */
|
||||
visit(rel, sym);
|
||||
}
|
||||
else {
|
||||
die("Unsupported relocation type: %d\n", r_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
|
||||
{
|
||||
reloc_count += 1;
|
||||
}
|
||||
|
||||
static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
|
||||
{
|
||||
/* Remember the address that needs to be adjusted. */
|
||||
relocs[reloc_idx++] = rel->r_offset;
|
||||
}
|
||||
|
||||
static int cmp_relocs(const void *va, const void *vb)
|
||||
{
|
||||
const unsigned long *a, *b;
|
||||
a = va; b = vb;
|
||||
return (*a == *b)? 0 : (*a > *b)? 1 : -1;
|
||||
}
|
||||
|
||||
static void emit_relocs(int as_text)
|
||||
{
|
||||
int i;
|
||||
/* Count how many relocations I have and allocate space for them. */
|
||||
reloc_count = 0;
|
||||
walk_relocs(count_reloc);
|
||||
relocs = malloc(reloc_count * sizeof(relocs[0]));
|
||||
if (!relocs) {
|
||||
die("malloc of %d entries for relocs failed\n",
|
||||
reloc_count);
|
||||
}
|
||||
/* Collect up the relocations */
|
||||
reloc_idx = 0;
|
||||
walk_relocs(collect_reloc);
|
||||
|
||||
/* Order the relocations for more efficient processing */
|
||||
qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs);
|
||||
|
||||
/* Print the relocations */
|
||||
if (as_text) {
|
||||
/* Print the relocations in a form suitable that
|
||||
* gas will like.
|
||||
*/
|
||||
printf(".section \".data.reloc\",\"a\"\n");
|
||||
printf(".balign 4\n");
|
||||
for(i = 0; i < reloc_count; i++) {
|
||||
printf("\t .long 0x%08lx\n", relocs[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
else {
|
||||
unsigned char buf[4];
|
||||
buf[0] = buf[1] = buf[2] = buf[3] = 0;
|
||||
/* Print a stop */
|
||||
printf("%c%c%c%c", buf[0], buf[1], buf[2], buf[3]);
|
||||
/* Now print each relocation */
|
||||
for(i = 0; i < reloc_count; i++) {
|
||||
buf[0] = (relocs[i] >> 0) & 0xff;
|
||||
buf[1] = (relocs[i] >> 8) & 0xff;
|
||||
buf[2] = (relocs[i] >> 16) & 0xff;
|
||||
buf[3] = (relocs[i] >> 24) & 0xff;
|
||||
printf("%c%c%c%c", buf[0], buf[1], buf[2], buf[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
die("relocs [--abs-syms |--abs-relocs | --text] vmlinux\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int show_absolute_syms, show_absolute_relocs;
|
||||
int as_text;
|
||||
const char *fname;
|
||||
FILE *fp;
|
||||
int i;
|
||||
|
||||
show_absolute_syms = 0;
|
||||
show_absolute_relocs = 0;
|
||||
as_text = 0;
|
||||
fname = NULL;
|
||||
for(i = 1; i < argc; i++) {
|
||||
char *arg = argv[i];
|
||||
if (*arg == '-') {
|
||||
if (strcmp(argv[1], "--abs-syms") == 0) {
|
||||
show_absolute_syms = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "--abs-relocs") == 0) {
|
||||
show_absolute_relocs = 1;
|
||||
continue;
|
||||
}
|
||||
else if (strcmp(argv[1], "--text") == 0) {
|
||||
as_text = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (!fname) {
|
||||
fname = arg;
|
||||
continue;
|
||||
}
|
||||
usage();
|
||||
}
|
||||
if (!fname) {
|
||||
usage();
|
||||
}
|
||||
fp = fopen(fname, "r");
|
||||
if (!fp) {
|
||||
die("Cannot open %s: %s\n",
|
||||
fname, strerror(errno));
|
||||
}
|
||||
read_ehdr(fp);
|
||||
read_shdrs(fp);
|
||||
read_strtabs(fp);
|
||||
read_symtabs(fp);
|
||||
read_relocs(fp);
|
||||
if (show_absolute_syms) {
|
||||
print_absolute_symbols();
|
||||
return 0;
|
||||
}
|
||||
if (show_absolute_relocs) {
|
||||
print_absolute_relocs();
|
||||
return 0;
|
||||
}
|
||||
emit_relocs(as_text);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
||||
OUTPUT_ARCH(i386)
|
||||
ENTRY(startup_32)
|
||||
SECTIONS
|
||||
{
|
||||
/* Be careful parts of head.S assume startup_32 is at
|
||||
* address 0.
|
||||
*/
|
||||
. = 0 ;
|
||||
.text.head : {
|
||||
_head = . ;
|
||||
*(.text.head)
|
||||
_ehead = . ;
|
||||
}
|
||||
.data.compressed : {
|
||||
*(.data.compressed)
|
||||
}
|
||||
.text : {
|
||||
_text = .; /* Text */
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
_etext = . ;
|
||||
}
|
||||
.rodata : {
|
||||
_rodata = . ;
|
||||
*(.rodata) /* read-only data */
|
||||
*(.rodata.*)
|
||||
_erodata = . ;
|
||||
}
|
||||
.data : {
|
||||
_data = . ;
|
||||
*(.data)
|
||||
*(.data.*)
|
||||
_edata = . ;
|
||||
}
|
||||
.bss : {
|
||||
_bss = . ;
|
||||
*(.bss)
|
||||
*(.bss.*)
|
||||
*(COMMON)
|
||||
_end = . ;
|
||||
}
|
||||
}
|
|
@ -1,9 +1,10 @@
|
|||
SECTIONS
|
||||
{
|
||||
.data : {
|
||||
.data.compressed : {
|
||||
input_len = .;
|
||||
LONG(input_data_end - input_data) input_data = .;
|
||||
*(.data)
|
||||
output_len = . - 4;
|
||||
input_data_end = .;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ start:
|
|||
# This is the setup header, and it must start at %cs:2 (old 0x9020:2)
|
||||
|
||||
.ascii "HdrS" # header signature
|
||||
.word 0x0204 # header version number (>= 0x0105)
|
||||
.word 0x0205 # header version number (>= 0x0105)
|
||||
# or else old loadlin-1.5 will fail)
|
||||
realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
|
||||
start_sys_seg: .word SYSSEG
|
||||
|
@ -160,6 +160,17 @@ ramdisk_max: .long (-__PAGE_OFFSET-(512 << 20)-1) & 0x7fffffff
|
|||
# The highest safe address for
|
||||
# the contents of an initrd
|
||||
|
||||
kernel_alignment: .long CONFIG_PHYSICAL_ALIGN #physical addr alignment
|
||||
#required for protected mode
|
||||
#kernel
|
||||
#ifdef CONFIG_RELOCATABLE
|
||||
relocatable_kernel: .byte 1
|
||||
#else
|
||||
relocatable_kernel: .byte 0
|
||||
#endif
|
||||
pad2: .byte 0
|
||||
pad3: .word 0
|
||||
|
||||
trampoline: call start_of_setup
|
||||
.align 16
|
||||
# The offset at this point is 0x240
|
||||
|
@ -588,11 +599,6 @@ rmodeswtch_normal:
|
|||
call default_switch
|
||||
|
||||
rmodeswtch_end:
|
||||
# we get the code32 start address and modify the below 'jmpi'
|
||||
# (loader may have changed it)
|
||||
movl %cs:code32_start, %eax
|
||||
movl %eax, %cs:code32
|
||||
|
||||
# Now we move the system to its rightful place ... but we check if we have a
|
||||
# big-kernel. In that case we *must* not move it ...
|
||||
testb $LOADED_HIGH, %cs:loadflags
|
||||
|
@ -788,11 +794,12 @@ a20_err_msg:
|
|||
a20_done:
|
||||
|
||||
#endif /* CONFIG_X86_VOYAGER */
|
||||
# set up gdt and idt
|
||||
# set up gdt and idt and 32bit start address
|
||||
lidt idt_48 # load idt with 0,0
|
||||
xorl %eax, %eax # Compute gdt_base
|
||||
movw %ds, %ax # (Convert %ds:gdt to a linear ptr)
|
||||
shll $4, %eax
|
||||
addl %eax, code32
|
||||
addl $gdt, %eax
|
||||
movl %eax, (gdt_48+2)
|
||||
lgdt gdt_48 # load gdt with whatever is
|
||||
|
@ -851,9 +858,26 @@ flush_instr:
|
|||
# Manual, Mixing 16-bit and 32-bit code, page 16-6)
|
||||
|
||||
.byte 0x66, 0xea # prefix + jmpi-opcode
|
||||
code32: .long 0x1000 # will be set to 0x100000
|
||||
# for big kernels
|
||||
code32: .long startup_32 # will be set to %cs+startup_32
|
||||
.word __BOOT_CS
|
||||
.code32
|
||||
startup_32:
|
||||
movl $(__BOOT_DS), %eax
|
||||
movl %eax, %ds
|
||||
movl %eax, %es
|
||||
movl %eax, %fs
|
||||
movl %eax, %gs
|
||||
movl %eax, %ss
|
||||
|
||||
xorl %eax, %eax
|
||||
1: incl %eax # check that A20 really IS enabled
|
||||
movl %eax, 0x00000000 # loop forever if it isn't
|
||||
cmpl %eax, 0x00100000
|
||||
je 1b
|
||||
|
||||
# Jump to the 32bit entry point
|
||||
jmpl *(code32_start - start + (DELTA_INITSEG << 4))(%esi)
|
||||
.code16
|
||||
|
||||
# Here's a bunch of information about your current kernel..
|
||||
kernel_version: .ascii UTS_RELEASE
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
# Automatically generated make config: don't edit
|
||||
# Linux kernel version: 2.6.19-rc2-git4
|
||||
# Sat Oct 21 03:38:56 2006
|
||||
# Linux kernel version: 2.6.19-git7
|
||||
# Wed Dec 6 23:50:49 2006
|
||||
#
|
||||
CONFIG_X86_32=y
|
||||
CONFIG_GENERIC_TIME=y
|
||||
|
@ -40,13 +40,14 @@ CONFIG_POSIX_MQUEUE=y
|
|||
CONFIG_IKCONFIG=y
|
||||
CONFIG_IKCONFIG_PROC=y
|
||||
# CONFIG_CPUSETS is not set
|
||||
CONFIG_SYSFS_DEPRECATED=y
|
||||
# CONFIG_RELAY is not set
|
||||
CONFIG_INITRAMFS_SOURCE=""
|
||||
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
|
||||
CONFIG_SYSCTL=y
|
||||
# CONFIG_EMBEDDED is not set
|
||||
CONFIG_UID16=y
|
||||
# CONFIG_SYSCTL_SYSCALL is not set
|
||||
CONFIG_SYSCTL_SYSCALL=y
|
||||
CONFIG_KALLSYMS=y
|
||||
CONFIG_KALLSYMS_ALL=y
|
||||
# CONFIG_KALLSYMS_EXTRA_PASS is not set
|
||||
|
@ -110,6 +111,7 @@ CONFIG_SMP=y
|
|||
# CONFIG_X86_VISWS is not set
|
||||
CONFIG_X86_GENERICARCH=y
|
||||
# CONFIG_X86_ES7000 is not set
|
||||
# CONFIG_PARAVIRT is not set
|
||||
CONFIG_X86_CYCLONE_TIMER=y
|
||||
# CONFIG_M386 is not set
|
||||
# CONFIG_M486 is not set
|
||||
|
@ -120,6 +122,7 @@ CONFIG_X86_CYCLONE_TIMER=y
|
|||
# CONFIG_MPENTIUMII is not set
|
||||
CONFIG_MPENTIUMIII=y
|
||||
# CONFIG_MPENTIUMM is not set
|
||||
# CONFIG_MCORE2 is not set
|
||||
# CONFIG_MPENTIUM4 is not set
|
||||
# CONFIG_MK6 is not set
|
||||
# CONFIG_MK7 is not set
|
||||
|
@ -197,7 +200,6 @@ CONFIG_RESOURCES_64BIT=y
|
|||
CONFIG_MTRR=y
|
||||
# CONFIG_EFI is not set
|
||||
# CONFIG_IRQBALANCE is not set
|
||||
CONFIG_REGPARM=y
|
||||
CONFIG_SECCOMP=y
|
||||
# CONFIG_HZ_100 is not set
|
||||
CONFIG_HZ_250=y
|
||||
|
@ -205,7 +207,8 @@ CONFIG_HZ_250=y
|
|||
CONFIG_HZ=250
|
||||
# CONFIG_KEXEC is not set
|
||||
# CONFIG_CRASH_DUMP is not set
|
||||
CONFIG_PHYSICAL_START=0x100000
|
||||
# CONFIG_RELOCATABLE is not set
|
||||
CONFIG_PHYSICAL_ALIGN=0x100000
|
||||
# CONFIG_HOTPLUG_CPU is not set
|
||||
CONFIG_COMPAT_VDSO=y
|
||||
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
|
||||
|
@ -367,6 +370,7 @@ CONFIG_INET_TCP_DIAG=y
|
|||
# CONFIG_TCP_CONG_ADVANCED is not set
|
||||
CONFIG_TCP_CONG_CUBIC=y
|
||||
CONFIG_DEFAULT_TCP_CONG="cubic"
|
||||
# CONFIG_TCP_MD5SIG is not set
|
||||
CONFIG_IPV6=y
|
||||
# CONFIG_IPV6_PRIVACY is not set
|
||||
# CONFIG_IPV6_ROUTER_PREF is not set
|
||||
|
@ -677,6 +681,7 @@ CONFIG_SATA_INTEL_COMBINED=y
|
|||
# CONFIG_PATA_IT821X is not set
|
||||
# CONFIG_PATA_JMICRON is not set
|
||||
# CONFIG_PATA_TRIFLEX is not set
|
||||
# CONFIG_PATA_MARVELL is not set
|
||||
# CONFIG_PATA_MPIIX is not set
|
||||
# CONFIG_PATA_OLDPIIX is not set
|
||||
# CONFIG_PATA_NETCELL is not set
|
||||
|
@ -850,6 +855,7 @@ CONFIG_BNX2=y
|
|||
# CONFIG_IXGB is not set
|
||||
# CONFIG_S2IO is not set
|
||||
# CONFIG_MYRI10GE is not set
|
||||
# CONFIG_NETXEN_NIC is not set
|
||||
|
||||
#
|
||||
# Token Ring devices
|
||||
|
@ -984,10 +990,6 @@ CONFIG_RTC=y
|
|||
# CONFIG_R3964 is not set
|
||||
# CONFIG_APPLICOM is not set
|
||||
# CONFIG_SONYPI is not set
|
||||
|
||||
#
|
||||
# Ftape, the floppy tape device driver
|
||||
#
|
||||
CONFIG_AGP=y
|
||||
# CONFIG_AGP_ALI is not set
|
||||
# CONFIG_AGP_ATI is not set
|
||||
|
@ -1108,6 +1110,7 @@ CONFIG_USB_DEVICEFS=y
|
|||
# CONFIG_USB_BANDWIDTH is not set
|
||||
# CONFIG_USB_DYNAMIC_MINORS is not set
|
||||
# CONFIG_USB_SUSPEND is not set
|
||||
# CONFIG_USB_MULTITHREAD_PROBE is not set
|
||||
# CONFIG_USB_OTG is not set
|
||||
|
||||
#
|
||||
|
@ -1185,6 +1188,7 @@ CONFIG_USB_HIDINPUT=y
|
|||
# CONFIG_USB_KAWETH is not set
|
||||
# CONFIG_USB_PEGASUS is not set
|
||||
# CONFIG_USB_RTL8150 is not set
|
||||
# CONFIG_USB_USBNET_MII is not set
|
||||
# CONFIG_USB_USBNET is not set
|
||||
CONFIG_USB_MON=y
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ extra-y := head.o init_task.o vmlinux.lds
|
|||
|
||||
obj-y := process.o signal.o entry.o traps.o irq.o \
|
||||
ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_i386.o \
|
||||
pci-dma.o i386_ksyms.o i387.o bootflag.o \
|
||||
pci-dma.o i386_ksyms.o i387.o bootflag.o e820.o\
|
||||
quirks.o i8237.o topology.o alternative.o i8253.o tsc.o
|
||||
|
||||
obj-$(CONFIG_STACKTRACE) += stacktrace.o
|
||||
|
@ -40,6 +40,9 @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
|
|||
obj-$(CONFIG_HPET_TIMER) += hpet.o
|
||||
obj-$(CONFIG_K8_NB) += k8.o
|
||||
|
||||
# Make sure this is linked after any other paravirt_ops structs: see head.S
|
||||
obj-$(CONFIG_PARAVIRT) += paravirt.o
|
||||
|
||||
EXTRA_AFLAGS := -traditional
|
||||
|
||||
obj-$(CONFIG_SCx200) += scx200.o
|
||||
|
|
|
@ -156,10 +156,8 @@ static int __init ffh_cstate_init(void)
|
|||
|
||||
static void __exit ffh_cstate_exit(void)
|
||||
{
|
||||
if (cpu_cstate_entry) {
|
||||
free_percpu(cpu_cstate_entry);
|
||||
cpu_cstate_entry = NULL;
|
||||
}
|
||||
free_percpu(cpu_cstate_entry);
|
||||
cpu_cstate_entry = NULL;
|
||||
}
|
||||
|
||||
arch_initcall(ffh_cstate_init);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <asm/pci-direct.h>
|
||||
#include <asm/acpi.h>
|
||||
#include <asm/apic.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
|
||||
|
@ -49,6 +50,24 @@ static int __init check_bridge(int vendor, int device)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void check_intel(void)
|
||||
{
|
||||
u16 vendor, device;
|
||||
|
||||
vendor = read_pci_config_16(0, 0, 0, PCI_VENDOR_ID);
|
||||
|
||||
if (vendor != PCI_VENDOR_ID_INTEL)
|
||||
return;
|
||||
|
||||
device = read_pci_config_16(0, 0, 0, PCI_DEVICE_ID);
|
||||
#ifdef CONFIG_SMP
|
||||
if (device == PCI_DEVICE_ID_INTEL_E7320_MCH ||
|
||||
device == PCI_DEVICE_ID_INTEL_E7520_MCH ||
|
||||
device == PCI_DEVICE_ID_INTEL_E7525_MCH)
|
||||
quirk_intel_irqbalance();
|
||||
#endif
|
||||
}
|
||||
|
||||
void __init check_acpi_pci(void)
|
||||
{
|
||||
int num, slot, func;
|
||||
|
@ -60,6 +79,8 @@ void __init check_acpi_pci(void)
|
|||
if (!early_pci_allowed())
|
||||
return;
|
||||
|
||||
check_intel();
|
||||
|
||||
/* Poor man's PCI discovery */
|
||||
for (num = 0; num < 32; num++) {
|
||||
for (slot = 0; slot < 32; slot++) {
|
||||
|
|
|
@ -124,6 +124,20 @@ static unsigned char** find_nop_table(void)
|
|||
|
||||
#endif /* CONFIG_X86_64 */
|
||||
|
||||
static void nop_out(void *insns, unsigned int len)
|
||||
{
|
||||
unsigned char **noptable = find_nop_table();
|
||||
|
||||
while (len > 0) {
|
||||
unsigned int noplen = len;
|
||||
if (noplen > ASM_NOP_MAX)
|
||||
noplen = ASM_NOP_MAX;
|
||||
memcpy(insns, noptable[noplen], noplen);
|
||||
insns += noplen;
|
||||
len -= noplen;
|
||||
}
|
||||
}
|
||||
|
||||
extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
|
||||
extern struct alt_instr __smp_alt_instructions[], __smp_alt_instructions_end[];
|
||||
extern u8 *__smp_locks[], *__smp_locks_end[];
|
||||
|
@ -138,10 +152,9 @@ extern u8 __smp_alt_begin[], __smp_alt_end[];
|
|||
|
||||
void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
|
||||
{
|
||||
unsigned char **noptable = find_nop_table();
|
||||
struct alt_instr *a;
|
||||
u8 *instr;
|
||||
int diff, i, k;
|
||||
int diff;
|
||||
|
||||
DPRINTK("%s: alt table %p -> %p\n", __FUNCTION__, start, end);
|
||||
for (a = start; a < end; a++) {
|
||||
|
@ -159,13 +172,7 @@ void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
|
|||
#endif
|
||||
memcpy(instr, a->replacement, a->replacementlen);
|
||||
diff = a->instrlen - a->replacementlen;
|
||||
/* Pad the rest with nops */
|
||||
for (i = a->replacementlen; diff > 0; diff -= k, i += k) {
|
||||
k = diff;
|
||||
if (k > ASM_NOP_MAX)
|
||||
k = ASM_NOP_MAX;
|
||||
memcpy(a->instr + i, noptable[k], k);
|
||||
}
|
||||
nop_out(instr + a->replacementlen, diff);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -209,7 +216,6 @@ static void alternatives_smp_lock(u8 **start, u8 **end, u8 *text, u8 *text_end)
|
|||
|
||||
static void alternatives_smp_unlock(u8 **start, u8 **end, u8 *text, u8 *text_end)
|
||||
{
|
||||
unsigned char **noptable = find_nop_table();
|
||||
u8 **ptr;
|
||||
|
||||
for (ptr = start; ptr < end; ptr++) {
|
||||
|
@ -217,7 +223,7 @@ static void alternatives_smp_unlock(u8 **start, u8 **end, u8 *text, u8 *text_end
|
|||
continue;
|
||||
if (*ptr > text_end)
|
||||
continue;
|
||||
**ptr = noptable[1][0];
|
||||
nop_out(*ptr, 1);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -343,6 +349,40 @@ void alternatives_smp_switch(int smp)
|
|||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PARAVIRT
|
||||
void apply_paravirt(struct paravirt_patch *start, struct paravirt_patch *end)
|
||||
{
|
||||
struct paravirt_patch *p;
|
||||
|
||||
for (p = start; p < end; p++) {
|
||||
unsigned int used;
|
||||
|
||||
used = paravirt_ops.patch(p->instrtype, p->clobbers, p->instr,
|
||||
p->len);
|
||||
#ifdef CONFIG_DEBUG_PARAVIRT
|
||||
{
|
||||
int i;
|
||||
/* Deliberately clobber regs using "not %reg" to find bugs. */
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (p->len - used >= 2 && (p->clobbers & (1 << i))) {
|
||||
memcpy(p->instr + used, "\xf7\xd0", 2);
|
||||
p->instr[used+1] |= i;
|
||||
used += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Pad the rest with nops */
|
||||
nop_out(p->instr + used, p->len - used);
|
||||
}
|
||||
|
||||
/* Sync to be conservative, in case we patched following instructions */
|
||||
sync_core();
|
||||
}
|
||||
extern struct paravirt_patch __start_parainstructions[],
|
||||
__stop_parainstructions[];
|
||||
#endif /* CONFIG_PARAVIRT */
|
||||
|
||||
void __init alternative_instructions(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
@ -390,5 +430,6 @@ void __init alternative_instructions(void)
|
|||
alternatives_smp_switch(0);
|
||||
}
|
||||
#endif
|
||||
apply_paravirt(__start_parainstructions, __stop_parainstructions);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
|
|
@ -647,23 +647,30 @@ static struct {
|
|||
static int lapic_suspend(struct sys_device *dev, pm_message_t state)
|
||||
{
|
||||
unsigned long flags;
|
||||
int maxlvt;
|
||||
|
||||
if (!apic_pm_state.active)
|
||||
return 0;
|
||||
|
||||
maxlvt = get_maxlvt();
|
||||
|
||||
apic_pm_state.apic_id = apic_read(APIC_ID);
|
||||
apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI);
|
||||
apic_pm_state.apic_ldr = apic_read(APIC_LDR);
|
||||
apic_pm_state.apic_dfr = apic_read(APIC_DFR);
|
||||
apic_pm_state.apic_spiv = apic_read(APIC_SPIV);
|
||||
apic_pm_state.apic_lvtt = apic_read(APIC_LVTT);
|
||||
apic_pm_state.apic_lvtpc = apic_read(APIC_LVTPC);
|
||||
if (maxlvt >= 4)
|
||||
apic_pm_state.apic_lvtpc = apic_read(APIC_LVTPC);
|
||||
apic_pm_state.apic_lvt0 = apic_read(APIC_LVT0);
|
||||
apic_pm_state.apic_lvt1 = apic_read(APIC_LVT1);
|
||||
apic_pm_state.apic_lvterr = apic_read(APIC_LVTERR);
|
||||
apic_pm_state.apic_tmict = apic_read(APIC_TMICT);
|
||||
apic_pm_state.apic_tdcr = apic_read(APIC_TDCR);
|
||||
apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR);
|
||||
#ifdef CONFIG_X86_MCE_P4THERMAL
|
||||
if (maxlvt >= 5)
|
||||
apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR);
|
||||
#endif
|
||||
|
||||
local_irq_save(flags);
|
||||
disable_local_APIC();
|
||||
|
@ -675,10 +682,13 @@ static int lapic_resume(struct sys_device *dev)
|
|||
{
|
||||
unsigned int l, h;
|
||||
unsigned long flags;
|
||||
int maxlvt;
|
||||
|
||||
if (!apic_pm_state.active)
|
||||
return 0;
|
||||
|
||||
maxlvt = get_maxlvt();
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
/*
|
||||
|
@ -700,8 +710,12 @@ static int lapic_resume(struct sys_device *dev)
|
|||
apic_write(APIC_SPIV, apic_pm_state.apic_spiv);
|
||||
apic_write(APIC_LVT0, apic_pm_state.apic_lvt0);
|
||||
apic_write(APIC_LVT1, apic_pm_state.apic_lvt1);
|
||||
apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr);
|
||||
apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc);
|
||||
#ifdef CONFIG_X86_MCE_P4THERMAL
|
||||
if (maxlvt >= 5)
|
||||
apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr);
|
||||
#endif
|
||||
if (maxlvt >= 4)
|
||||
apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc);
|
||||
apic_write(APIC_LVTT, apic_pm_state.apic_lvtt);
|
||||
apic_write(APIC_TDCR, apic_pm_state.apic_tdcr);
|
||||
apic_write(APIC_TMICT, apic_pm_state.apic_tmict);
|
||||
|
|
|
@ -231,6 +231,7 @@
|
|||
#include <asm/uaccess.h>
|
||||
#include <asm/desc.h>
|
||||
#include <asm/i8253.h>
|
||||
#include <asm/paravirt.h>
|
||||
|
||||
#include "io_ports.h"
|
||||
|
||||
|
@ -2235,7 +2236,7 @@ static int __init apm_init(void)
|
|||
|
||||
dmi_check_system(apm_dmi_table);
|
||||
|
||||
if (apm_info.bios.version == 0) {
|
||||
if (apm_info.bios.version == 0 || paravirt_enabled()) {
|
||||
printk(KERN_INFO "apm: BIOS not found.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <asm/processor.h>
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/elf.h>
|
||||
#include <asm/pda.h>
|
||||
|
||||
#define DEFINE(sym, val) \
|
||||
asm volatile("\n->" #sym " %0 " #val : : "i" (val))
|
||||
|
@ -51,13 +52,35 @@ void foo(void)
|
|||
OFFSET(TI_exec_domain, thread_info, exec_domain);
|
||||
OFFSET(TI_flags, thread_info, flags);
|
||||
OFFSET(TI_status, thread_info, status);
|
||||
OFFSET(TI_cpu, thread_info, cpu);
|
||||
OFFSET(TI_preempt_count, thread_info, preempt_count);
|
||||
OFFSET(TI_addr_limit, thread_info, addr_limit);
|
||||
OFFSET(TI_restart_block, thread_info, restart_block);
|
||||
OFFSET(TI_sysenter_return, thread_info, sysenter_return);
|
||||
BLANK();
|
||||
|
||||
OFFSET(GDS_size, Xgt_desc_struct, size);
|
||||
OFFSET(GDS_address, Xgt_desc_struct, address);
|
||||
OFFSET(GDS_pad, Xgt_desc_struct, pad);
|
||||
BLANK();
|
||||
|
||||
OFFSET(PT_EBX, pt_regs, ebx);
|
||||
OFFSET(PT_ECX, pt_regs, ecx);
|
||||
OFFSET(PT_EDX, pt_regs, edx);
|
||||
OFFSET(PT_ESI, pt_regs, esi);
|
||||
OFFSET(PT_EDI, pt_regs, edi);
|
||||
OFFSET(PT_EBP, pt_regs, ebp);
|
||||
OFFSET(PT_EAX, pt_regs, eax);
|
||||
OFFSET(PT_DS, pt_regs, xds);
|
||||
OFFSET(PT_ES, pt_regs, xes);
|
||||
OFFSET(PT_GS, pt_regs, xgs);
|
||||
OFFSET(PT_ORIG_EAX, pt_regs, orig_eax);
|
||||
OFFSET(PT_EIP, pt_regs, eip);
|
||||
OFFSET(PT_CS, pt_regs, xcs);
|
||||
OFFSET(PT_EFLAGS, pt_regs, eflags);
|
||||
OFFSET(PT_OLDESP, pt_regs, esp);
|
||||
OFFSET(PT_OLDSS, pt_regs, xss);
|
||||
BLANK();
|
||||
|
||||
OFFSET(EXEC_DOMAIN_handler, exec_domain, handler);
|
||||
OFFSET(RT_SIGFRAME_sigcontext, rt_sigframe, uc.uc_mcontext);
|
||||
BLANK();
|
||||
|
@ -74,4 +97,18 @@ void foo(void)
|
|||
DEFINE(VDSO_PRELINK, VDSO_PRELINK);
|
||||
|
||||
OFFSET(crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx);
|
||||
|
||||
BLANK();
|
||||
OFFSET(PDA_cpu, i386_pda, cpu_number);
|
||||
OFFSET(PDA_pcurrent, i386_pda, pcurrent);
|
||||
|
||||
#ifdef CONFIG_PARAVIRT
|
||||
BLANK();
|
||||
OFFSET(PARAVIRT_enabled, paravirt_ops, paravirt_enabled);
|
||||
OFFSET(PARAVIRT_irq_disable, paravirt_ops, irq_disable);
|
||||
OFFSET(PARAVIRT_irq_enable, paravirt_ops, irq_enable);
|
||||
OFFSET(PARAVIRT_irq_enable_sysexit, paravirt_ops, irq_enable_sysexit);
|
||||
OFFSET(PARAVIRT_iret, paravirt_ops, iret);
|
||||
OFFSET(PARAVIRT_read_cr0, paravirt_ops, read_cr0);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -104,10 +104,7 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
|
|||
f_vide();
|
||||
rdtscl(d2);
|
||||
d = d2-d;
|
||||
|
||||
/* Knock these two lines out if it debugs out ok */
|
||||
printk(KERN_INFO "AMD K6 stepping B detected - ");
|
||||
/* -- cut here -- */
|
||||
|
||||
if (d > 20*K6_BUG_LOOP)
|
||||
printk("system stability may be impaired when more than 32 MB are used.\n");
|
||||
else
|
||||
|
|
|
@ -18,14 +18,15 @@
|
|||
#include <asm/apic.h>
|
||||
#include <mach_apic.h>
|
||||
#endif
|
||||
#include <asm/pda.h>
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
DEFINE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr);
|
||||
EXPORT_PER_CPU_SYMBOL(cpu_gdt_descr);
|
||||
|
||||
DEFINE_PER_CPU(unsigned char, cpu_16bit_stack[CPU_16BIT_STACK_SIZE]);
|
||||
EXPORT_PER_CPU_SYMBOL(cpu_16bit_stack);
|
||||
struct i386_pda *_cpu_pda[NR_CPUS] __read_mostly;
|
||||
EXPORT_SYMBOL(_cpu_pda);
|
||||
|
||||
static int cachesize_override __cpuinitdata = -1;
|
||||
static int disable_x86_fxsr __cpuinitdata;
|
||||
|
@ -235,29 +236,14 @@ static int __cpuinit have_cpuid_p(void)
|
|||
return flag_is_changeable_p(X86_EFLAGS_ID);
|
||||
}
|
||||
|
||||
/* Do minimum CPU detection early.
|
||||
Fields really needed: vendor, cpuid_level, family, model, mask, cache alignment.
|
||||
The others are not touched to avoid unwanted side effects.
|
||||
|
||||
WARNING: this function is only called on the BP. Don't add code here
|
||||
that is supposed to run on all CPUs. */
|
||||
static void __init early_cpu_detect(void)
|
||||
void __init cpu_detect(struct cpuinfo_x86 *c)
|
||||
{
|
||||
struct cpuinfo_x86 *c = &boot_cpu_data;
|
||||
|
||||
c->x86_cache_alignment = 32;
|
||||
|
||||
if (!have_cpuid_p())
|
||||
return;
|
||||
|
||||
/* Get vendor name */
|
||||
cpuid(0x00000000, &c->cpuid_level,
|
||||
(int *)&c->x86_vendor_id[0],
|
||||
(int *)&c->x86_vendor_id[8],
|
||||
(int *)&c->x86_vendor_id[4]);
|
||||
|
||||
get_cpu_vendor(c, 1);
|
||||
|
||||
c->x86 = 4;
|
||||
if (c->cpuid_level >= 0x00000001) {
|
||||
u32 junk, tfms, cap0, misc;
|
||||
|
@ -274,6 +260,26 @@ static void __init early_cpu_detect(void)
|
|||
}
|
||||
}
|
||||
|
||||
/* Do minimum CPU detection early.
|
||||
Fields really needed: vendor, cpuid_level, family, model, mask, cache alignment.
|
||||
The others are not touched to avoid unwanted side effects.
|
||||
|
||||
WARNING: this function is only called on the BP. Don't add code here
|
||||
that is supposed to run on all CPUs. */
|
||||
static void __init early_cpu_detect(void)
|
||||
{
|
||||
struct cpuinfo_x86 *c = &boot_cpu_data;
|
||||
|
||||
c->x86_cache_alignment = 32;
|
||||
|
||||
if (!have_cpuid_p())
|
||||
return;
|
||||
|
||||
cpu_detect(c);
|
||||
|
||||
get_cpu_vendor(c, 1);
|
||||
}
|
||||
|
||||
static void __cpuinit generic_identify(struct cpuinfo_x86 * c)
|
||||
{
|
||||
u32 tfms, xlvl;
|
||||
|
@ -308,6 +314,8 @@ static void __cpuinit generic_identify(struct cpuinfo_x86 * c)
|
|||
#else
|
||||
c->apicid = (ebx >> 24) & 0xFF;
|
||||
#endif
|
||||
if (c->x86_capability[0] & (1<<19))
|
||||
c->x86_clflush_size = ((ebx >> 8) & 0xff) * 8;
|
||||
} else {
|
||||
/* Have CPUID level 0 only - unheard of */
|
||||
c->x86 = 4;
|
||||
|
@ -372,6 +380,7 @@ void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
|
|||
c->x86_vendor_id[0] = '\0'; /* Unset */
|
||||
c->x86_model_id[0] = '\0'; /* Unset */
|
||||
c->x86_max_cores = 1;
|
||||
c->x86_clflush_size = 32;
|
||||
memset(&c->x86_capability, 0, sizeof c->x86_capability);
|
||||
|
||||
if (!have_cpuid_p()) {
|
||||
|
@ -591,25 +600,134 @@ void __init early_cpu_init(void)
|
|||
disable_pse = 1;
|
||||
#endif
|
||||
}
|
||||
/*
|
||||
* cpu_init() initializes state that is per-CPU. Some data is already
|
||||
* initialized (naturally) in the bootstrap process, such as the GDT
|
||||
* and IDT. We reload them nevertheless, this function acts as a
|
||||
* 'CPU state barrier', nothing should get across.
|
||||
*/
|
||||
void __cpuinit cpu_init(void)
|
||||
|
||||
/* Make sure %gs is initialized properly in idle threads */
|
||||
struct pt_regs * __devinit idle_regs(struct pt_regs *regs)
|
||||
{
|
||||
memset(regs, 0, sizeof(struct pt_regs));
|
||||
regs->xgs = __KERNEL_PDA;
|
||||
return regs;
|
||||
}
|
||||
|
||||
static __cpuinit int alloc_gdt(int cpu)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
struct tss_struct * t = &per_cpu(init_tss, cpu);
|
||||
struct thread_struct *thread = ¤t->thread;
|
||||
struct desc_struct *gdt;
|
||||
__u32 stk16_off = (__u32)&per_cpu(cpu_16bit_stack, cpu);
|
||||
struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
|
||||
struct desc_struct *gdt;
|
||||
struct i386_pda *pda;
|
||||
|
||||
gdt = (struct desc_struct *)cpu_gdt_descr->address;
|
||||
pda = cpu_pda(cpu);
|
||||
|
||||
/*
|
||||
* This is a horrible hack to allocate the GDT. The problem
|
||||
* is that cpu_init() is called really early for the boot CPU
|
||||
* (and hence needs bootmem) but much later for the secondary
|
||||
* CPUs, when bootmem will have gone away
|
||||
*/
|
||||
if (NODE_DATA(0)->bdata->node_bootmem_map) {
|
||||
BUG_ON(gdt != NULL || pda != NULL);
|
||||
|
||||
gdt = alloc_bootmem_pages(PAGE_SIZE);
|
||||
pda = alloc_bootmem(sizeof(*pda));
|
||||
/* alloc_bootmem(_pages) panics on failure, so no check */
|
||||
|
||||
memset(gdt, 0, PAGE_SIZE);
|
||||
memset(pda, 0, sizeof(*pda));
|
||||
} else {
|
||||
/* GDT and PDA might already have been allocated if
|
||||
this is a CPU hotplug re-insertion. */
|
||||
if (gdt == NULL)
|
||||
gdt = (struct desc_struct *)get_zeroed_page(GFP_KERNEL);
|
||||
|
||||
if (pda == NULL)
|
||||
pda = kmalloc_node(sizeof(*pda), GFP_KERNEL, cpu_to_node(cpu));
|
||||
|
||||
if (unlikely(!gdt || !pda)) {
|
||||
free_pages((unsigned long)gdt, 0);
|
||||
kfree(pda);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
cpu_gdt_descr->address = (unsigned long)gdt;
|
||||
cpu_pda(cpu) = pda;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Initial PDA used by boot CPU */
|
||||
struct i386_pda boot_pda = {
|
||||
._pda = &boot_pda,
|
||||
.cpu_number = 0,
|
||||
.pcurrent = &init_task,
|
||||
};
|
||||
|
||||
static inline void set_kernel_gs(void)
|
||||
{
|
||||
/* Set %gs for this CPU's PDA. Memory clobber is to create a
|
||||
barrier with respect to any PDA operations, so the compiler
|
||||
doesn't move any before here. */
|
||||
asm volatile ("mov %0, %%gs" : : "r" (__KERNEL_PDA) : "memory");
|
||||
}
|
||||
|
||||
/* Initialize the CPU's GDT and PDA. The boot CPU does this for
|
||||
itself, but secondaries find this done for them. */
|
||||
__cpuinit int init_gdt(int cpu, struct task_struct *idle)
|
||||
{
|
||||
struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
|
||||
struct desc_struct *gdt;
|
||||
struct i386_pda *pda;
|
||||
|
||||
/* For non-boot CPUs, the GDT and PDA should already have been
|
||||
allocated. */
|
||||
if (!alloc_gdt(cpu)) {
|
||||
printk(KERN_CRIT "CPU%d failed to allocate GDT or PDA\n", cpu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
gdt = (struct desc_struct *)cpu_gdt_descr->address;
|
||||
pda = cpu_pda(cpu);
|
||||
|
||||
BUG_ON(gdt == NULL || pda == NULL);
|
||||
|
||||
/*
|
||||
* Initialize the per-CPU GDT with the boot GDT,
|
||||
* and set up the GDT descriptor:
|
||||
*/
|
||||
memcpy(gdt, cpu_gdt_table, GDT_SIZE);
|
||||
cpu_gdt_descr->size = GDT_SIZE - 1;
|
||||
|
||||
pack_descriptor((u32 *)&gdt[GDT_ENTRY_PDA].a,
|
||||
(u32 *)&gdt[GDT_ENTRY_PDA].b,
|
||||
(unsigned long)pda, sizeof(*pda) - 1,
|
||||
0x80 | DESCTYPE_S | 0x2, 0); /* present read-write data segment */
|
||||
|
||||
memset(pda, 0, sizeof(*pda));
|
||||
pda->_pda = pda;
|
||||
pda->cpu_number = cpu;
|
||||
pda->pcurrent = idle;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Common CPU init for both boot and secondary CPUs */
|
||||
static void __cpuinit _cpu_init(int cpu, struct task_struct *curr)
|
||||
{
|
||||
struct tss_struct * t = &per_cpu(init_tss, cpu);
|
||||
struct thread_struct *thread = &curr->thread;
|
||||
struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
|
||||
|
||||
/* Reinit these anyway, even if they've already been done (on
|
||||
the boot CPU, this will transition from the boot gdt+pda to
|
||||
the real ones). */
|
||||
load_gdt(cpu_gdt_descr);
|
||||
set_kernel_gs();
|
||||
|
||||
if (cpu_test_and_set(cpu, cpu_initialized)) {
|
||||
printk(KERN_WARNING "CPU#%d already initialized!\n", cpu);
|
||||
for (;;) local_irq_enable();
|
||||
}
|
||||
|
||||
printk(KERN_INFO "Initializing CPU#%d\n", cpu);
|
||||
|
||||
if (cpu_has_vme || cpu_has_tsc || cpu_has_de)
|
||||
|
@ -621,56 +739,16 @@ void __cpuinit cpu_init(void)
|
|||
set_in_cr4(X86_CR4_TSD);
|
||||
}
|
||||
|
||||
/* The CPU hotplug case */
|
||||
if (cpu_gdt_descr->address) {
|
||||
gdt = (struct desc_struct *)cpu_gdt_descr->address;
|
||||
memset(gdt, 0, PAGE_SIZE);
|
||||
goto old_gdt;
|
||||
}
|
||||
/*
|
||||
* This is a horrible hack to allocate the GDT. The problem
|
||||
* is that cpu_init() is called really early for the boot CPU
|
||||
* (and hence needs bootmem) but much later for the secondary
|
||||
* CPUs, when bootmem will have gone away
|
||||
*/
|
||||
if (NODE_DATA(0)->bdata->node_bootmem_map) {
|
||||
gdt = (struct desc_struct *)alloc_bootmem_pages(PAGE_SIZE);
|
||||
/* alloc_bootmem_pages panics on failure, so no check */
|
||||
memset(gdt, 0, PAGE_SIZE);
|
||||
} else {
|
||||
gdt = (struct desc_struct *)get_zeroed_page(GFP_KERNEL);
|
||||
if (unlikely(!gdt)) {
|
||||
printk(KERN_CRIT "CPU%d failed to allocate GDT\n", cpu);
|
||||
for (;;)
|
||||
local_irq_enable();
|
||||
}
|
||||
}
|
||||
old_gdt:
|
||||
/*
|
||||
* Initialize the per-CPU GDT with the boot GDT,
|
||||
* and set up the GDT descriptor:
|
||||
*/
|
||||
memcpy(gdt, cpu_gdt_table, GDT_SIZE);
|
||||
|
||||
/* Set up GDT entry for 16bit stack */
|
||||
*(__u64 *)(&gdt[GDT_ENTRY_ESPFIX_SS]) |=
|
||||
((((__u64)stk16_off) << 16) & 0x000000ffffff0000ULL) |
|
||||
((((__u64)stk16_off) << 32) & 0xff00000000000000ULL) |
|
||||
(CPU_16BIT_STACK_SIZE - 1);
|
||||
|
||||
cpu_gdt_descr->size = GDT_SIZE - 1;
|
||||
cpu_gdt_descr->address = (unsigned long)gdt;
|
||||
|
||||
load_gdt(cpu_gdt_descr);
|
||||
load_idt(&idt_descr);
|
||||
|
||||
/*
|
||||
* Set up and load the per-CPU TSS and LDT
|
||||
*/
|
||||
atomic_inc(&init_mm.mm_count);
|
||||
current->active_mm = &init_mm;
|
||||
BUG_ON(current->mm);
|
||||
enter_lazy_tlb(&init_mm, current);
|
||||
curr->active_mm = &init_mm;
|
||||
if (curr->mm)
|
||||
BUG();
|
||||
enter_lazy_tlb(&init_mm, curr);
|
||||
|
||||
load_esp0(t, thread);
|
||||
set_tss_desc(cpu,t);
|
||||
|
@ -682,8 +760,8 @@ old_gdt:
|
|||
__set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss);
|
||||
#endif
|
||||
|
||||
/* Clear %fs and %gs. */
|
||||
asm volatile ("movl %0, %%fs; movl %0, %%gs" : : "r" (0));
|
||||
/* Clear %fs. */
|
||||
asm volatile ("mov %0, %%fs" : : "r" (0));
|
||||
|
||||
/* Clear all 6 debug registers: */
|
||||
set_debugreg(0, 0);
|
||||
|
@ -701,6 +779,37 @@ old_gdt:
|
|||
mxcsr_feature_mask_init();
|
||||
}
|
||||
|
||||
/* Entrypoint to initialize secondary CPU */
|
||||
void __cpuinit secondary_cpu_init(void)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
struct task_struct *curr = current;
|
||||
|
||||
_cpu_init(cpu, curr);
|
||||
}
|
||||
|
||||
/*
|
||||
* cpu_init() initializes state that is per-CPU. Some data is already
|
||||
* initialized (naturally) in the bootstrap process, such as the GDT
|
||||
* and IDT. We reload them nevertheless, this function acts as a
|
||||
* 'CPU state barrier', nothing should get across.
|
||||
*/
|
||||
void __cpuinit cpu_init(void)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
struct task_struct *curr = current;
|
||||
|
||||
/* Set up the real GDT and PDA, so we can transition from the
|
||||
boot versions. */
|
||||
if (!init_gdt(cpu, curr)) {
|
||||
/* failed to allocate something; not much we can do... */
|
||||
for (;;)
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
_cpu_init(cpu, curr);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
void __cpuinit cpu_uninit(void)
|
||||
{
|
||||
|
|
|
@ -107,7 +107,7 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c)
|
|||
* Note that the workaround only should be initialized once...
|
||||
*/
|
||||
c->f00f_bug = 0;
|
||||
if ( c->x86 == 5 ) {
|
||||
if (!paravirt_enabled() && c->x86 == 5) {
|
||||
static int f00f_workaround_enabled = 0;
|
||||
|
||||
c->f00f_bug = 1;
|
||||
|
@ -195,8 +195,16 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c)
|
|||
if ((c->x86 == 0xf && c->x86_model >= 0x03) ||
|
||||
(c->x86 == 0x6 && c->x86_model >= 0x0e))
|
||||
set_bit(X86_FEATURE_CONSTANT_TSC, c->x86_capability);
|
||||
}
|
||||
|
||||
if (cpu_has_ds) {
|
||||
unsigned int l1;
|
||||
rdmsr(MSR_IA32_MISC_ENABLE, l1, l2);
|
||||
if (!(l1 & (1<<11)))
|
||||
set_bit(X86_FEATURE_BTS, c->x86_capability);
|
||||
if (!(l1 & (1<<12)))
|
||||
set_bit(X86_FEATURE_PEBS, c->x86_capability);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int __cpuinit intel_size_cache(struct cpuinfo_x86 * c, unsigned int size)
|
||||
{
|
||||
|
|
|
@ -480,12 +480,10 @@ static int __cpuinit detect_cache_attributes(unsigned int cpu)
|
|||
if (num_cache_leaves == 0)
|
||||
return -ENOENT;
|
||||
|
||||
cpuid4_info[cpu] = kmalloc(
|
||||
cpuid4_info[cpu] = kzalloc(
|
||||
sizeof(struct _cpuid4_info) * num_cache_leaves, GFP_KERNEL);
|
||||
if (unlikely(cpuid4_info[cpu] == NULL))
|
||||
return -ENOMEM;
|
||||
memset(cpuid4_info[cpu], 0,
|
||||
sizeof(struct _cpuid4_info) * num_cache_leaves);
|
||||
|
||||
oldmask = current->cpus_allowed;
|
||||
retval = set_cpus_allowed(current, cpumask_of_cpu(cpu));
|
||||
|
@ -658,17 +656,14 @@ static int __cpuinit cpuid4_cache_sysfs_init(unsigned int cpu)
|
|||
return -ENOENT;
|
||||
|
||||
/* Allocate all required memory */
|
||||
cache_kobject[cpu] = kmalloc(sizeof(struct kobject), GFP_KERNEL);
|
||||
cache_kobject[cpu] = kzalloc(sizeof(struct kobject), GFP_KERNEL);
|
||||
if (unlikely(cache_kobject[cpu] == NULL))
|
||||
goto err_out;
|
||||
memset(cache_kobject[cpu], 0, sizeof(struct kobject));
|
||||
|
||||
index_kobject[cpu] = kmalloc(
|
||||
index_kobject[cpu] = kzalloc(
|
||||
sizeof(struct _index_kobject ) * num_cache_leaves, GFP_KERNEL);
|
||||
if (unlikely(index_kobject[cpu] == NULL))
|
||||
goto err_out;
|
||||
memset(index_kobject[cpu], 0,
|
||||
sizeof(struct _index_kobject) * num_cache_leaves);
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -116,7 +116,6 @@ static __cpuinit int thermal_throttle_add_dev(struct sys_device *sys_dev)
|
|||
return sysfs_create_group(&sys_dev->kobj, &thermal_throttle_attr_group);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
static __cpuinit void thermal_throttle_remove_dev(struct sys_device *sys_dev)
|
||||
{
|
||||
return sysfs_remove_group(&sys_dev->kobj, &thermal_throttle_attr_group);
|
||||
|
@ -153,7 +152,6 @@ static struct notifier_block thermal_throttle_cpu_notifier =
|
|||
{
|
||||
.notifier_call = thermal_throttle_cpu_callback,
|
||||
};
|
||||
#endif /* CONFIG_HOTPLUG_CPU */
|
||||
|
||||
static __init int thermal_throttle_init_device(void)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
obj-y := main.o if.o generic.o state.o
|
||||
obj-y += amd.o
|
||||
obj-y += cyrix.o
|
||||
obj-y += centaur.o
|
||||
obj-$(CONFIG_X86_32) += amd.o cyrix.o centaur.o
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
static void
|
||||
amd_get_mtrr(unsigned int reg, unsigned long *base,
|
||||
unsigned int *size, mtrr_type * type)
|
||||
unsigned long *size, mtrr_type * type)
|
||||
{
|
||||
unsigned long low, high;
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ static u8 centaur_mcr_type; /* 0 for winchip, 1 for winchip2 */
|
|||
*/
|
||||
|
||||
static int
|
||||
centaur_get_free_region(unsigned long base, unsigned long size)
|
||||
centaur_get_free_region(unsigned long base, unsigned long size, int replace_reg)
|
||||
/* [SUMMARY] Get a free MTRR.
|
||||
<base> The starting (base) address of the region.
|
||||
<size> The size (in bytes) of the region.
|
||||
|
@ -26,10 +26,11 @@ centaur_get_free_region(unsigned long base, unsigned long size)
|
|||
{
|
||||
int i, max;
|
||||
mtrr_type ltype;
|
||||
unsigned long lbase;
|
||||
unsigned int lsize;
|
||||
unsigned long lbase, lsize;
|
||||
|
||||
max = num_var_ranges;
|
||||
if (replace_reg >= 0 && replace_reg < max)
|
||||
return replace_reg;
|
||||
for (i = 0; i < max; ++i) {
|
||||
if (centaur_mcr_reserved & (1 << i))
|
||||
continue;
|
||||
|
@ -49,7 +50,7 @@ mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi)
|
|||
|
||||
static void
|
||||
centaur_get_mcr(unsigned int reg, unsigned long *base,
|
||||
unsigned int *size, mtrr_type * type)
|
||||
unsigned long *size, mtrr_type * type)
|
||||
{
|
||||
*base = centaur_mcr[reg].high >> PAGE_SHIFT;
|
||||
*size = -(centaur_mcr[reg].low & 0xfffff000) >> PAGE_SHIFT;
|
||||
|
|
|
@ -9,7 +9,7 @@ int arr3_protected;
|
|||
|
||||
static void
|
||||
cyrix_get_arr(unsigned int reg, unsigned long *base,
|
||||
unsigned int *size, mtrr_type * type)
|
||||
unsigned long *size, mtrr_type * type)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned char arr, ccr3, rcr, shift;
|
||||
|
@ -77,7 +77,7 @@ cyrix_get_arr(unsigned int reg, unsigned long *base,
|
|||
}
|
||||
|
||||
static int
|
||||
cyrix_get_free_region(unsigned long base, unsigned long size)
|
||||
cyrix_get_free_region(unsigned long base, unsigned long size, int replace_reg)
|
||||
/* [SUMMARY] Get a free ARR.
|
||||
<base> The starting (base) address of the region.
|
||||
<size> The size (in bytes) of the region.
|
||||
|
@ -86,9 +86,24 @@ cyrix_get_free_region(unsigned long base, unsigned long size)
|
|||
{
|
||||
int i;
|
||||
mtrr_type ltype;
|
||||
unsigned long lbase;
|
||||
unsigned int lsize;
|
||||
unsigned long lbase, lsize;
|
||||
|
||||
switch (replace_reg) {
|
||||
case 7:
|
||||
if (size < 0x40)
|
||||
break;
|
||||
case 6:
|
||||
case 5:
|
||||
case 4:
|
||||
return replace_reg;
|
||||
case 3:
|
||||
if (arr3_protected)
|
||||
break;
|
||||
case 2:
|
||||
case 1:
|
||||
case 0:
|
||||
return replace_reg;
|
||||
}
|
||||
/* If we are to set up a region >32M then look at ARR7 immediately */
|
||||
if (size > 0x2000) {
|
||||
cyrix_get_arr(7, &lbase, &lsize, <ype);
|
||||
|
@ -214,7 +229,7 @@ static void cyrix_set_arr(unsigned int reg, unsigned long base,
|
|||
|
||||
typedef struct {
|
||||
unsigned long base;
|
||||
unsigned int size;
|
||||
unsigned long size;
|
||||
mtrr_type type;
|
||||
} arr_state_t;
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/mtrr.h>
|
||||
#include <asm/msr.h>
|
||||
|
@ -15,12 +16,19 @@ struct mtrr_state {
|
|||
struct mtrr_var_range *var_ranges;
|
||||
mtrr_type fixed_ranges[NUM_FIXED_RANGES];
|
||||
unsigned char enabled;
|
||||
unsigned char have_fixed;
|
||||
mtrr_type def_type;
|
||||
};
|
||||
|
||||
static unsigned long smp_changes_mask;
|
||||
static struct mtrr_state mtrr_state = {};
|
||||
|
||||
#undef MODULE_PARAM_PREFIX
|
||||
#define MODULE_PARAM_PREFIX "mtrr."
|
||||
|
||||
static __initdata int mtrr_show;
|
||||
module_param_named(show, mtrr_show, bool, 0);
|
||||
|
||||
/* Get the MSR pair relating to a var range */
|
||||
static void __init
|
||||
get_mtrr_var_range(unsigned int index, struct mtrr_var_range *vr)
|
||||
|
@ -43,6 +51,14 @@ get_fixed_ranges(mtrr_type * frs)
|
|||
rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2], p[7 + i * 2]);
|
||||
}
|
||||
|
||||
static void __init print_fixed(unsigned base, unsigned step, const mtrr_type*types)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < 8; ++i, ++types, base += step)
|
||||
printk(KERN_INFO "MTRR %05X-%05X %s\n", base, base + step - 1, mtrr_attrib_to_str(*types));
|
||||
}
|
||||
|
||||
/* Grab all of the MTRR state for this CPU into *state */
|
||||
void __init get_mtrr_state(void)
|
||||
{
|
||||
|
@ -58,13 +74,49 @@ void __init get_mtrr_state(void)
|
|||
}
|
||||
vrs = mtrr_state.var_ranges;
|
||||
|
||||
rdmsr(MTRRcap_MSR, lo, dummy);
|
||||
mtrr_state.have_fixed = (lo >> 8) & 1;
|
||||
|
||||
for (i = 0; i < num_var_ranges; i++)
|
||||
get_mtrr_var_range(i, &vrs[i]);
|
||||
get_fixed_ranges(mtrr_state.fixed_ranges);
|
||||
if (mtrr_state.have_fixed)
|
||||
get_fixed_ranges(mtrr_state.fixed_ranges);
|
||||
|
||||
rdmsr(MTRRdefType_MSR, lo, dummy);
|
||||
mtrr_state.def_type = (lo & 0xff);
|
||||
mtrr_state.enabled = (lo & 0xc00) >> 10;
|
||||
|
||||
if (mtrr_show) {
|
||||
int high_width;
|
||||
|
||||
printk(KERN_INFO "MTRR default type: %s\n", mtrr_attrib_to_str(mtrr_state.def_type));
|
||||
if (mtrr_state.have_fixed) {
|
||||
printk(KERN_INFO "MTRR fixed ranges %sabled:\n",
|
||||
mtrr_state.enabled & 1 ? "en" : "dis");
|
||||
print_fixed(0x00000, 0x10000, mtrr_state.fixed_ranges + 0);
|
||||
for (i = 0; i < 2; ++i)
|
||||
print_fixed(0x80000 + i * 0x20000, 0x04000, mtrr_state.fixed_ranges + (i + 1) * 8);
|
||||
for (i = 0; i < 8; ++i)
|
||||
print_fixed(0xC0000 + i * 0x08000, 0x01000, mtrr_state.fixed_ranges + (i + 3) * 8);
|
||||
}
|
||||
printk(KERN_INFO "MTRR variable ranges %sabled:\n",
|
||||
mtrr_state.enabled & 2 ? "en" : "dis");
|
||||
high_width = ((size_or_mask ? ffs(size_or_mask) - 1 : 32) - (32 - PAGE_SHIFT) + 3) / 4;
|
||||
for (i = 0; i < num_var_ranges; ++i) {
|
||||
if (mtrr_state.var_ranges[i].mask_lo & (1 << 11))
|
||||
printk(KERN_INFO "MTRR %u base %0*X%05X000 mask %0*X%05X000 %s\n",
|
||||
i,
|
||||
high_width,
|
||||
mtrr_state.var_ranges[i].base_hi,
|
||||
mtrr_state.var_ranges[i].base_lo >> 12,
|
||||
high_width,
|
||||
mtrr_state.var_ranges[i].mask_hi,
|
||||
mtrr_state.var_ranges[i].mask_lo >> 12,
|
||||
mtrr_attrib_to_str(mtrr_state.var_ranges[i].base_lo & 0xff));
|
||||
else
|
||||
printk(KERN_INFO "MTRR %u disabled\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Some BIOS's are fucked and don't set all MTRRs the same! */
|
||||
|
@ -95,7 +147,7 @@ void mtrr_wrmsr(unsigned msr, unsigned a, unsigned b)
|
|||
smp_processor_id(), msr, a, b);
|
||||
}
|
||||
|
||||
int generic_get_free_region(unsigned long base, unsigned long size)
|
||||
int generic_get_free_region(unsigned long base, unsigned long size, int replace_reg)
|
||||
/* [SUMMARY] Get a free MTRR.
|
||||
<base> The starting (base) address of the region.
|
||||
<size> The size (in bytes) of the region.
|
||||
|
@ -104,10 +156,11 @@ int generic_get_free_region(unsigned long base, unsigned long size)
|
|||
{
|
||||
int i, max;
|
||||
mtrr_type ltype;
|
||||
unsigned long lbase;
|
||||
unsigned lsize;
|
||||
unsigned long lbase, lsize;
|
||||
|
||||
max = num_var_ranges;
|
||||
if (replace_reg >= 0 && replace_reg < max)
|
||||
return replace_reg;
|
||||
for (i = 0; i < max; ++i) {
|
||||
mtrr_if->get(i, &lbase, &lsize, <ype);
|
||||
if (lsize == 0)
|
||||
|
@ -117,7 +170,7 @@ int generic_get_free_region(unsigned long base, unsigned long size)
|
|||
}
|
||||
|
||||
static void generic_get_mtrr(unsigned int reg, unsigned long *base,
|
||||
unsigned int *size, mtrr_type * type)
|
||||
unsigned long *size, mtrr_type *type)
|
||||
{
|
||||
unsigned int mask_lo, mask_hi, base_lo, base_hi;
|
||||
|
||||
|
@ -202,7 +255,9 @@ static int set_mtrr_var_ranges(unsigned int index, struct mtrr_var_range *vr)
|
|||
return changed;
|
||||
}
|
||||
|
||||
static unsigned long set_mtrr_state(u32 deftype_lo, u32 deftype_hi)
|
||||
static u32 deftype_lo, deftype_hi;
|
||||
|
||||
static unsigned long set_mtrr_state(void)
|
||||
/* [SUMMARY] Set the MTRR state for this CPU.
|
||||
<state> The MTRR state information to read.
|
||||
<ctxt> Some relevant CPU context.
|
||||
|
@ -217,14 +272,14 @@ static unsigned long set_mtrr_state(u32 deftype_lo, u32 deftype_hi)
|
|||
if (set_mtrr_var_ranges(i, &mtrr_state.var_ranges[i]))
|
||||
change_mask |= MTRR_CHANGE_MASK_VARIABLE;
|
||||
|
||||
if (set_fixed_ranges(mtrr_state.fixed_ranges))
|
||||
if (mtrr_state.have_fixed && set_fixed_ranges(mtrr_state.fixed_ranges))
|
||||
change_mask |= MTRR_CHANGE_MASK_FIXED;
|
||||
|
||||
/* Set_mtrr_restore restores the old value of MTRRdefType,
|
||||
so to set it we fiddle with the saved value */
|
||||
if ((deftype_lo & 0xff) != mtrr_state.def_type
|
||||
|| ((deftype_lo & 0xc00) >> 10) != mtrr_state.enabled) {
|
||||
deftype_lo |= (mtrr_state.def_type | mtrr_state.enabled << 10);
|
||||
deftype_lo = (deftype_lo & ~0xcff) | mtrr_state.def_type | (mtrr_state.enabled << 10);
|
||||
change_mask |= MTRR_CHANGE_MASK_DEFTYPE;
|
||||
}
|
||||
|
||||
|
@ -233,7 +288,6 @@ static unsigned long set_mtrr_state(u32 deftype_lo, u32 deftype_hi)
|
|||
|
||||
|
||||
static unsigned long cr4 = 0;
|
||||
static u32 deftype_lo, deftype_hi;
|
||||
static DEFINE_SPINLOCK(set_atomicity_lock);
|
||||
|
||||
/*
|
||||
|
@ -271,7 +325,7 @@ static void prepare_set(void) __acquires(set_atomicity_lock)
|
|||
rdmsr(MTRRdefType_MSR, deftype_lo, deftype_hi);
|
||||
|
||||
/* Disable MTRRs, and set the default type to uncached */
|
||||
mtrr_wrmsr(MTRRdefType_MSR, deftype_lo & 0xf300UL, deftype_hi);
|
||||
mtrr_wrmsr(MTRRdefType_MSR, deftype_lo & ~0xcff, deftype_hi);
|
||||
}
|
||||
|
||||
static void post_set(void) __releases(set_atomicity_lock)
|
||||
|
@ -300,7 +354,7 @@ static void generic_set_all(void)
|
|||
prepare_set();
|
||||
|
||||
/* Actually set the state */
|
||||
mask = set_mtrr_state(deftype_lo,deftype_hi);
|
||||
mask = set_mtrr_state();
|
||||
|
||||
post_set();
|
||||
local_irq_restore(flags);
|
||||
|
@ -366,7 +420,7 @@ int generic_validate_add_page(unsigned long base, unsigned long size, unsigned i
|
|||
printk(KERN_WARNING "mtrr: base(0x%lx000) is not 4 MiB aligned\n", base);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!(base + size < 0x70000000 || base > 0x7003FFFF) &&
|
||||
if (!(base + size < 0x70000 || base > 0x7003F) &&
|
||||
(type == MTRR_TYPE_WRCOMB
|
||||
|| type == MTRR_TYPE_WRBACK)) {
|
||||
printk(KERN_WARNING "mtrr: writable mtrr between 0x70000000 and 0x7003FFFF may hang the CPU.\n");
|
||||
|
|
|
@ -17,7 +17,7 @@ extern unsigned int *usage_table;
|
|||
|
||||
#define FILE_FCOUNT(f) (((struct seq_file *)((f)->private_data))->private)
|
||||
|
||||
static char *mtrr_strings[MTRR_NUM_TYPES] =
|
||||
static const char *const mtrr_strings[MTRR_NUM_TYPES] =
|
||||
{
|
||||
"uncachable", /* 0 */
|
||||
"write-combining", /* 1 */
|
||||
|
@ -28,7 +28,7 @@ static char *mtrr_strings[MTRR_NUM_TYPES] =
|
|||
"write-back", /* 6 */
|
||||
};
|
||||
|
||||
char *mtrr_attrib_to_str(int x)
|
||||
const char *mtrr_attrib_to_str(int x)
|
||||
{
|
||||
return (x <= 6) ? mtrr_strings[x] : "?";
|
||||
}
|
||||
|
@ -44,10 +44,9 @@ mtrr_file_add(unsigned long base, unsigned long size,
|
|||
|
||||
max = num_var_ranges;
|
||||
if (fcount == NULL) {
|
||||
fcount = kmalloc(max * sizeof *fcount, GFP_KERNEL);
|
||||
fcount = kzalloc(max * sizeof *fcount, GFP_KERNEL);
|
||||
if (!fcount)
|
||||
return -ENOMEM;
|
||||
memset(fcount, 0, max * sizeof *fcount);
|
||||
FILE_FCOUNT(file) = fcount;
|
||||
}
|
||||
if (!page) {
|
||||
|
@ -155,6 +154,7 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg)
|
|||
{
|
||||
int err = 0;
|
||||
mtrr_type type;
|
||||
unsigned long size;
|
||||
struct mtrr_sentry sentry;
|
||||
struct mtrr_gentry gentry;
|
||||
void __user *arg = (void __user *) __arg;
|
||||
|
@ -235,15 +235,15 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg)
|
|||
case MTRRIOC_GET_ENTRY:
|
||||
if (gentry.regnum >= num_var_ranges)
|
||||
return -EINVAL;
|
||||
mtrr_if->get(gentry.regnum, &gentry.base, &gentry.size, &type);
|
||||
mtrr_if->get(gentry.regnum, &gentry.base, &size, &type);
|
||||
|
||||
/* Hide entries that go above 4GB */
|
||||
if (gentry.base + gentry.size > 0x100000
|
||||
|| gentry.size == 0x100000)
|
||||
if (gentry.base + size - 1 >= (1UL << (8 * sizeof(gentry.size) - PAGE_SHIFT))
|
||||
|| size >= (1UL << (8 * sizeof(gentry.size) - PAGE_SHIFT)))
|
||||
gentry.base = gentry.size = gentry.type = 0;
|
||||
else {
|
||||
gentry.base <<= PAGE_SHIFT;
|
||||
gentry.size <<= PAGE_SHIFT;
|
||||
gentry.size = size << PAGE_SHIFT;
|
||||
gentry.type = type;
|
||||
}
|
||||
|
||||
|
@ -273,8 +273,14 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg)
|
|||
case MTRRIOC_GET_PAGE_ENTRY:
|
||||
if (gentry.regnum >= num_var_ranges)
|
||||
return -EINVAL;
|
||||
mtrr_if->get(gentry.regnum, &gentry.base, &gentry.size, &type);
|
||||
gentry.type = type;
|
||||
mtrr_if->get(gentry.regnum, &gentry.base, &size, &type);
|
||||
/* Hide entries that would overflow */
|
||||
if (size != (__typeof__(gentry.size))size)
|
||||
gentry.base = gentry.size = gentry.type = 0;
|
||||
else {
|
||||
gentry.size = size;
|
||||
gentry.type = type;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -353,8 +359,7 @@ static int mtrr_seq_show(struct seq_file *seq, void *offset)
|
|||
char factor;
|
||||
int i, max, len;
|
||||
mtrr_type type;
|
||||
unsigned long base;
|
||||
unsigned int size;
|
||||
unsigned long base, size;
|
||||
|
||||
len = 0;
|
||||
max = num_var_ranges;
|
||||
|
@ -373,7 +378,7 @@ static int mtrr_seq_show(struct seq_file *seq, void *offset)
|
|||
}
|
||||
/* RED-PEN: base can be > 32bit */
|
||||
len += seq_printf(seq,
|
||||
"reg%02i: base=0x%05lx000 (%4liMB), size=%4i%cB: %s, count=%d\n",
|
||||
"reg%02i: base=0x%05lx000 (%4luMB), size=%4lu%cB: %s, count=%d\n",
|
||||
i, base, base >> (20 - PAGE_SHIFT), size, factor,
|
||||
mtrr_attrib_to_str(type), usage_table[i]);
|
||||
}
|
||||
|
|
|
@ -59,7 +59,11 @@ struct mtrr_ops * mtrr_if = NULL;
|
|||
static void set_mtrr(unsigned int reg, unsigned long base,
|
||||
unsigned long size, mtrr_type type);
|
||||
|
||||
#ifndef CONFIG_X86_64
|
||||
extern int arr3_protected;
|
||||
#else
|
||||
#define arr3_protected 0
|
||||
#endif
|
||||
|
||||
void set_mtrr_ops(struct mtrr_ops * ops)
|
||||
{
|
||||
|
@ -168,6 +172,13 @@ static void ipi_handler(void *info)
|
|||
|
||||
#endif
|
||||
|
||||
static inline int types_compatible(mtrr_type type1, mtrr_type type2) {
|
||||
return type1 == MTRR_TYPE_UNCACHABLE ||
|
||||
type2 == MTRR_TYPE_UNCACHABLE ||
|
||||
(type1 == MTRR_TYPE_WRTHROUGH && type2 == MTRR_TYPE_WRBACK) ||
|
||||
(type1 == MTRR_TYPE_WRBACK && type2 == MTRR_TYPE_WRTHROUGH);
|
||||
}
|
||||
|
||||
/**
|
||||
* set_mtrr - update mtrrs on all processors
|
||||
* @reg: mtrr in question
|
||||
|
@ -263,8 +274,8 @@ static void set_mtrr(unsigned int reg, unsigned long base,
|
|||
|
||||
/**
|
||||
* mtrr_add_page - Add a memory type region
|
||||
* @base: Physical base address of region in pages (4 KB)
|
||||
* @size: Physical size of region in pages (4 KB)
|
||||
* @base: Physical base address of region in pages (in units of 4 kB!)
|
||||
* @size: Physical size of region in pages (4 kB)
|
||||
* @type: Type of MTRR desired
|
||||
* @increment: If this is true do usage counting on the region
|
||||
*
|
||||
|
@ -300,11 +311,9 @@ static void set_mtrr(unsigned int reg, unsigned long base,
|
|||
int mtrr_add_page(unsigned long base, unsigned long size,
|
||||
unsigned int type, char increment)
|
||||
{
|
||||
int i;
|
||||
int i, replace, error;
|
||||
mtrr_type ltype;
|
||||
unsigned long lbase;
|
||||
unsigned int lsize;
|
||||
int error;
|
||||
unsigned long lbase, lsize;
|
||||
|
||||
if (!mtrr_if)
|
||||
return -ENXIO;
|
||||
|
@ -324,12 +333,18 @@ int mtrr_add_page(unsigned long base, unsigned long size,
|
|||
return -ENOSYS;
|
||||
}
|
||||
|
||||
if (!size) {
|
||||
printk(KERN_WARNING "mtrr: zero sized request\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (base & size_or_mask || size & size_or_mask) {
|
||||
printk(KERN_WARNING "mtrr: base or size exceeds the MTRR width\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
error = -EINVAL;
|
||||
replace = -1;
|
||||
|
||||
/* No CPU hotplug when we change MTRR entries */
|
||||
lock_cpu_hotplug();
|
||||
|
@ -337,21 +352,28 @@ int mtrr_add_page(unsigned long base, unsigned long size,
|
|||
mutex_lock(&mtrr_mutex);
|
||||
for (i = 0; i < num_var_ranges; ++i) {
|
||||
mtrr_if->get(i, &lbase, &lsize, <ype);
|
||||
if (base >= lbase + lsize)
|
||||
continue;
|
||||
if ((base < lbase) && (base + size <= lbase))
|
||||
if (!lsize || base > lbase + lsize - 1 || base + size - 1 < lbase)
|
||||
continue;
|
||||
/* At this point we know there is some kind of overlap/enclosure */
|
||||
if ((base < lbase) || (base + size > lbase + lsize)) {
|
||||
if (base < lbase || base + size - 1 > lbase + lsize - 1) {
|
||||
if (base <= lbase && base + size - 1 >= lbase + lsize - 1) {
|
||||
/* New region encloses an existing region */
|
||||
if (type == ltype) {
|
||||
replace = replace == -1 ? i : -2;
|
||||
continue;
|
||||
}
|
||||
else if (types_compatible(type, ltype))
|
||||
continue;
|
||||
}
|
||||
printk(KERN_WARNING
|
||||
"mtrr: 0x%lx000,0x%lx000 overlaps existing"
|
||||
" 0x%lx000,0x%x000\n", base, size, lbase,
|
||||
" 0x%lx000,0x%lx000\n", base, size, lbase,
|
||||
lsize);
|
||||
goto out;
|
||||
}
|
||||
/* New region is enclosed by an existing region */
|
||||
if (ltype != type) {
|
||||
if (type == MTRR_TYPE_UNCACHABLE)
|
||||
if (types_compatible(type, ltype))
|
||||
continue;
|
||||
printk (KERN_WARNING "mtrr: type mismatch for %lx000,%lx000 old: %s new: %s\n",
|
||||
base, size, mtrr_attrib_to_str(ltype),
|
||||
|
@ -364,10 +386,18 @@ int mtrr_add_page(unsigned long base, unsigned long size,
|
|||
goto out;
|
||||
}
|
||||
/* Search for an empty MTRR */
|
||||
i = mtrr_if->get_free_region(base, size);
|
||||
i = mtrr_if->get_free_region(base, size, replace);
|
||||
if (i >= 0) {
|
||||
set_mtrr(i, base, size, type);
|
||||
usage_table[i] = 1;
|
||||
if (likely(replace < 0))
|
||||
usage_table[i] = 1;
|
||||
else {
|
||||
usage_table[i] = usage_table[replace] + !!increment;
|
||||
if (unlikely(replace != i)) {
|
||||
set_mtrr(replace, 0, 0, 0);
|
||||
usage_table[replace] = 0;
|
||||
}
|
||||
}
|
||||
} else
|
||||
printk(KERN_INFO "mtrr: no more MTRRs available\n");
|
||||
error = i;
|
||||
|
@ -455,8 +485,7 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
|
|||
{
|
||||
int i, max;
|
||||
mtrr_type ltype;
|
||||
unsigned long lbase;
|
||||
unsigned int lsize;
|
||||
unsigned long lbase, lsize;
|
||||
int error = -EINVAL;
|
||||
|
||||
if (!mtrr_if)
|
||||
|
@ -544,9 +573,11 @@ extern void centaur_init_mtrr(void);
|
|||
|
||||
static void __init init_ifs(void)
|
||||
{
|
||||
#ifndef CONFIG_X86_64
|
||||
amd_init_mtrr();
|
||||
cyrix_init_mtrr();
|
||||
centaur_init_mtrr();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* The suspend/resume methods are only for CPU without MTRR. CPU using generic
|
||||
|
@ -555,7 +586,7 @@ static void __init init_ifs(void)
|
|||
struct mtrr_value {
|
||||
mtrr_type ltype;
|
||||
unsigned long lbase;
|
||||
unsigned int lsize;
|
||||
unsigned long lsize;
|
||||
};
|
||||
|
||||
static struct mtrr_value * mtrr_state;
|
||||
|
@ -565,10 +596,8 @@ static int mtrr_save(struct sys_device * sysdev, pm_message_t state)
|
|||
int i;
|
||||
int size = num_var_ranges * sizeof(struct mtrr_value);
|
||||
|
||||
mtrr_state = kmalloc(size,GFP_ATOMIC);
|
||||
if (mtrr_state)
|
||||
memset(mtrr_state,0,size);
|
||||
else
|
||||
mtrr_state = kzalloc(size,GFP_ATOMIC);
|
||||
if (!mtrr_state)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < num_var_ranges; i++) {
|
||||
|
|
|
@ -43,15 +43,16 @@ struct mtrr_ops {
|
|||
void (*set_all)(void);
|
||||
|
||||
void (*get)(unsigned int reg, unsigned long *base,
|
||||
unsigned int *size, mtrr_type * type);
|
||||
int (*get_free_region) (unsigned long base, unsigned long size);
|
||||
|
||||
unsigned long *size, mtrr_type * type);
|
||||
int (*get_free_region)(unsigned long base, unsigned long size,
|
||||
int replace_reg);
|
||||
int (*validate_add_page)(unsigned long base, unsigned long size,
|
||||
unsigned int type);
|
||||
int (*have_wrcomb)(void);
|
||||
};
|
||||
|
||||
extern int generic_get_free_region(unsigned long base, unsigned long size);
|
||||
extern int generic_get_free_region(unsigned long base, unsigned long size,
|
||||
int replace_reg);
|
||||
extern int generic_validate_add_page(unsigned long base, unsigned long size,
|
||||
unsigned int type);
|
||||
|
||||
|
@ -62,17 +63,17 @@ extern int positive_have_wrcomb(void);
|
|||
/* library functions for processor-specific routines */
|
||||
struct set_mtrr_context {
|
||||
unsigned long flags;
|
||||
unsigned long deftype_lo;
|
||||
unsigned long deftype_hi;
|
||||
unsigned long cr4val;
|
||||
unsigned long ccr3;
|
||||
u32 deftype_lo;
|
||||
u32 deftype_hi;
|
||||
u32 ccr3;
|
||||
};
|
||||
|
||||
struct mtrr_var_range {
|
||||
unsigned long base_lo;
|
||||
unsigned long base_hi;
|
||||
unsigned long mask_lo;
|
||||
unsigned long mask_hi;
|
||||
u32 base_lo;
|
||||
u32 base_hi;
|
||||
u32 mask_lo;
|
||||
u32 mask_hi;
|
||||
};
|
||||
|
||||
void set_mtrr_done(struct set_mtrr_context *ctxt);
|
||||
|
@ -92,6 +93,6 @@ extern struct mtrr_ops * mtrr_if;
|
|||
extern unsigned int num_var_ranges;
|
||||
|
||||
void mtrr_state_warn(void);
|
||||
char *mtrr_attrib_to_str(int x);
|
||||
const char *mtrr_attrib_to_str(int x);
|
||||
void mtrr_wrmsr(unsigned, unsigned, unsigned);
|
||||
|
||||
|
|
|
@ -152,9 +152,10 @@ static int show_cpuinfo(struct seq_file *m, void *v)
|
|||
seq_printf(m, " [%d]", i);
|
||||
}
|
||||
|
||||
seq_printf(m, "\nbogomips\t: %lu.%02lu\n\n",
|
||||
seq_printf(m, "\nbogomips\t: %lu.%02lu\n",
|
||||
c->loops_per_jiffy/(500000/HZ),
|
||||
(c->loops_per_jiffy/(5000/HZ)) % 100);
|
||||
seq_printf(m, "clflush size\t: %u\n\n", c->x86_clflush_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
#include <linux/major.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/notifier.h>
|
||||
|
@ -167,7 +166,6 @@ static int cpuid_device_create(int i)
|
|||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
static int cpuid_class_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
|
||||
{
|
||||
unsigned int cpu = (unsigned long)hcpu;
|
||||
|
@ -187,7 +185,6 @@ static struct notifier_block __cpuinitdata cpuid_class_cpu_notifier =
|
|||
{
|
||||
.notifier_call = cpuid_class_cpu_callback,
|
||||
};
|
||||
#endif /* !CONFIG_HOTPLUG_CPU */
|
||||
|
||||
static int __init cpuid_init(void)
|
||||
{
|
||||
|
|
|
@ -31,68 +31,6 @@
|
|||
/* This keeps a track of which one is crashing cpu. */
|
||||
static int crashing_cpu;
|
||||
|
||||
static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data,
|
||||
size_t data_len)
|
||||
{
|
||||
struct elf_note note;
|
||||
|
||||
note.n_namesz = strlen(name) + 1;
|
||||
note.n_descsz = data_len;
|
||||
note.n_type = type;
|
||||
memcpy(buf, ¬e, sizeof(note));
|
||||
buf += (sizeof(note) +3)/4;
|
||||
memcpy(buf, name, note.n_namesz);
|
||||
buf += (note.n_namesz + 3)/4;
|
||||
memcpy(buf, data, note.n_descsz);
|
||||
buf += (note.n_descsz + 3)/4;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void final_note(u32 *buf)
|
||||
{
|
||||
struct elf_note note;
|
||||
|
||||
note.n_namesz = 0;
|
||||
note.n_descsz = 0;
|
||||
note.n_type = 0;
|
||||
memcpy(buf, ¬e, sizeof(note));
|
||||
}
|
||||
|
||||
static void crash_save_this_cpu(struct pt_regs *regs, int cpu)
|
||||
{
|
||||
struct elf_prstatus prstatus;
|
||||
u32 *buf;
|
||||
|
||||
if ((cpu < 0) || (cpu >= NR_CPUS))
|
||||
return;
|
||||
|
||||
/* Using ELF notes here is opportunistic.
|
||||
* I need a well defined structure format
|
||||
* for the data I pass, and I need tags
|
||||
* on the data to indicate what information I have
|
||||
* squirrelled away. ELF notes happen to provide
|
||||
* all of that, so there is no need to invent something new.
|
||||
*/
|
||||
buf = (u32*)per_cpu_ptr(crash_notes, cpu);
|
||||
if (!buf)
|
||||
return;
|
||||
memset(&prstatus, 0, sizeof(prstatus));
|
||||
prstatus.pr_pid = current->pid;
|
||||
elf_core_copy_regs(&prstatus.pr_reg, regs);
|
||||
buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus,
|
||||
sizeof(prstatus));
|
||||
final_note(buf);
|
||||
}
|
||||
|
||||
static void crash_save_self(struct pt_regs *regs)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
cpu = safe_smp_processor_id();
|
||||
crash_save_this_cpu(regs, cpu);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC)
|
||||
static atomic_t waiting_for_crash_ipi;
|
||||
|
||||
|
@ -121,7 +59,7 @@ static int crash_nmi_callback(struct notifier_block *self,
|
|||
crash_fixup_ss_esp(&fixed_regs, regs);
|
||||
regs = &fixed_regs;
|
||||
}
|
||||
crash_save_this_cpu(regs, cpu);
|
||||
crash_save_cpu(regs, cpu);
|
||||
disable_local_APIC();
|
||||
atomic_dec(&waiting_for_crash_ipi);
|
||||
/* Assume hlt works */
|
||||
|
@ -195,5 +133,5 @@ void machine_crash_shutdown(struct pt_regs *regs)
|
|||
#if defined(CONFIG_X86_IO_APIC)
|
||||
disable_IO_APIC();
|
||||
#endif
|
||||
crash_save_self(regs);
|
||||
crash_save_cpu(regs, safe_smp_processor_id());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,894 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kexec.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/pfn.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/e820.h>
|
||||
|
||||
#ifdef CONFIG_EFI
|
||||
int efi_enabled = 0;
|
||||
EXPORT_SYMBOL(efi_enabled);
|
||||
#endif
|
||||
|
||||
struct e820map e820;
|
||||
struct change_member {
|
||||
struct e820entry *pbios; /* pointer to original bios entry */
|
||||
unsigned long long addr; /* address for this change point */
|
||||
};
|
||||
static struct change_member change_point_list[2*E820MAX] __initdata;
|
||||
static struct change_member *change_point[2*E820MAX] __initdata;
|
||||
static struct e820entry *overlap_list[E820MAX] __initdata;
|
||||
static struct e820entry new_bios[E820MAX] __initdata;
|
||||
/* For PCI or other memory-mapped resources */
|
||||
unsigned long pci_mem_start = 0x10000000;
|
||||
#ifdef CONFIG_PCI
|
||||
EXPORT_SYMBOL(pci_mem_start);
|
||||
#endif
|
||||
extern int user_defined_memmap;
|
||||
struct resource data_resource = {
|
||||
.name = "Kernel data",
|
||||
.start = 0,
|
||||
.end = 0,
|
||||
.flags = IORESOURCE_BUSY | IORESOURCE_MEM
|
||||
};
|
||||
|
||||
struct resource code_resource = {
|
||||
.name = "Kernel code",
|
||||
.start = 0,
|
||||
.end = 0,
|
||||
.flags = IORESOURCE_BUSY | IORESOURCE_MEM
|
||||
};
|
||||
|
||||
static struct resource system_rom_resource = {
|
||||
.name = "System ROM",
|
||||
.start = 0xf0000,
|
||||
.end = 0xfffff,
|
||||
.flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
|
||||
};
|
||||
|
||||
static struct resource extension_rom_resource = {
|
||||
.name = "Extension ROM",
|
||||
.start = 0xe0000,
|
||||
.end = 0xeffff,
|
||||
.flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
|
||||
};
|
||||
|
||||
static struct resource adapter_rom_resources[] = { {
|
||||
.name = "Adapter ROM",
|
||||
.start = 0xc8000,
|
||||
.end = 0,
|
||||
.flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
|
||||
}, {
|
||||
.name = "Adapter ROM",
|
||||
.start = 0,
|
||||
.end = 0,
|
||||
.flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
|
||||
}, {
|
||||
.name = "Adapter ROM",
|
||||
.start = 0,
|
||||
.end = 0,
|
||||
.flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
|
||||
}, {
|
||||
.name = "Adapter ROM",
|
||||
.start = 0,
|
||||
.end = 0,
|
||||
.flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
|
||||
}, {
|
||||
.name = "Adapter ROM",
|
||||
.start = 0,
|
||||
.end = 0,
|
||||
.flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
|
||||
}, {
|
||||
.name = "Adapter ROM",
|
||||
.start = 0,
|
||||
.end = 0,
|
||||
.flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
|
||||
} };
|
||||
|
||||
static struct resource video_rom_resource = {
|
||||
.name = "Video ROM",
|
||||
.start = 0xc0000,
|
||||
.end = 0xc7fff,
|
||||
.flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
|
||||
};
|
||||
|
||||
static struct resource video_ram_resource = {
|
||||
.name = "Video RAM area",
|
||||
.start = 0xa0000,
|
||||
.end = 0xbffff,
|
||||
.flags = IORESOURCE_BUSY | IORESOURCE_MEM
|
||||
};
|
||||
|
||||
static struct resource standard_io_resources[] = { {
|
||||
.name = "dma1",
|
||||
.start = 0x0000,
|
||||
.end = 0x001f,
|
||||
.flags = IORESOURCE_BUSY | IORESOURCE_IO
|
||||
}, {
|
||||
.name = "pic1",
|
||||
.start = 0x0020,
|
||||
.end = 0x0021,
|
||||
.flags = IORESOURCE_BUSY | IORESOURCE_IO
|
||||
}, {
|
||||
.name = "timer0",
|
||||
.start = 0x0040,
|
||||
.end = 0x0043,
|
||||
.flags = IORESOURCE_BUSY | IORESOURCE_IO
|
||||
}, {
|
||||
.name = "timer1",
|
||||
.start = 0x0050,
|
||||
.end = 0x0053,
|
||||
.flags = IORESOURCE_BUSY | IORESOURCE_IO
|
||||
}, {
|
||||
.name = "keyboard",
|
||||
.start = 0x0060,
|
||||
.end = 0x006f,
|
||||
.flags = IORESOURCE_BUSY | IORESOURCE_IO
|
||||
}, {
|
||||
.name = "dma page reg",
|
||||
.start = 0x0080,
|
||||
.end = 0x008f,
|
||||
.flags = IORESOURCE_BUSY | IORESOURCE_IO
|
||||
}, {
|
||||
.name = "pic2",
|
||||
.start = 0x00a0,
|
||||
.end = 0x00a1,
|
||||
.flags = IORESOURCE_BUSY | IORESOURCE_IO
|
||||
}, {
|
||||
.name = "dma2",
|
||||
.start = 0x00c0,
|
||||
.end = 0x00df,
|
||||
.flags = IORESOURCE_BUSY | IORESOURCE_IO
|
||||
}, {
|
||||
.name = "fpu",
|
||||
.start = 0x00f0,
|
||||
.end = 0x00ff,
|
||||
.flags = IORESOURCE_BUSY | IORESOURCE_IO
|
||||
} };
|
||||
|
||||
static int romsignature(const unsigned char *x)
|
||||
{
|
||||
unsigned short sig;
|
||||
int ret = 0;
|
||||
if (probe_kernel_address((const unsigned short *)x, sig) == 0)
|
||||
ret = (sig == 0xaa55);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __init romchecksum(unsigned char *rom, unsigned long length)
|
||||
{
|
||||
unsigned char *p, sum = 0;
|
||||
|
||||
for (p = rom; p < rom + length; p++)
|
||||
sum += *p;
|
||||
return sum == 0;
|
||||
}
|
||||
|
||||
static void __init probe_roms(void)
|
||||
{
|
||||
unsigned long start, length, upper;
|
||||
unsigned char *rom;
|
||||
int i;
|
||||
|
||||
/* video rom */
|
||||
upper = adapter_rom_resources[0].start;
|
||||
for (start = video_rom_resource.start; start < upper; start += 2048) {
|
||||
rom = isa_bus_to_virt(start);
|
||||
if (!romsignature(rom))
|
||||
continue;
|
||||
|
||||
video_rom_resource.start = start;
|
||||
|
||||
/* 0 < length <= 0x7f * 512, historically */
|
||||
length = rom[2] * 512;
|
||||
|
||||
/* if checksum okay, trust length byte */
|
||||
if (length && romchecksum(rom, length))
|
||||
video_rom_resource.end = start + length - 1;
|
||||
|
||||
request_resource(&iomem_resource, &video_rom_resource);
|
||||
break;
|
||||
}
|
||||
|
||||
start = (video_rom_resource.end + 1 + 2047) & ~2047UL;
|
||||
if (start < upper)
|
||||
start = upper;
|
||||
|
||||
/* system rom */
|
||||
request_resource(&iomem_resource, &system_rom_resource);
|
||||
upper = system_rom_resource.start;
|
||||
|
||||
/* check for extension rom (ignore length byte!) */
|
||||
rom = isa_bus_to_virt(extension_rom_resource.start);
|
||||
if (romsignature(rom)) {
|
||||
length = extension_rom_resource.end - extension_rom_resource.start + 1;
|
||||
if (romchecksum(rom, length)) {
|
||||
request_resource(&iomem_resource, &extension_rom_resource);
|
||||
upper = extension_rom_resource.start;
|
||||
}
|
||||
}
|
||||
|
||||
/* check for adapter roms on 2k boundaries */
|
||||
for (i = 0; i < ARRAY_SIZE(adapter_rom_resources) && start < upper; start += 2048) {
|
||||
rom = isa_bus_to_virt(start);
|
||||
if (!romsignature(rom))
|
||||
continue;
|
||||
|
||||
/* 0 < length <= 0x7f * 512, historically */
|
||||
length = rom[2] * 512;
|
||||
|
||||
/* but accept any length that fits if checksum okay */
|
||||
if (!length || start + length > upper || !romchecksum(rom, length))
|
||||
continue;
|
||||
|
||||
adapter_rom_resources[i].start = start;
|
||||
adapter_rom_resources[i].end = start + length - 1;
|
||||
request_resource(&iomem_resource, &adapter_rom_resources[i]);
|
||||
|
||||
start = adapter_rom_resources[i++].end & ~2047UL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Request address space for all standard RAM and ROM resources
|
||||
* and also for regions reported as reserved by the e820.
|
||||
*/
|
||||
static void __init
|
||||
legacy_init_iomem_resources(struct resource *code_resource, struct resource *data_resource)
|
||||
{
|
||||
int i;
|
||||
|
||||
probe_roms();
|
||||
for (i = 0; i < e820.nr_map; i++) {
|
||||
struct resource *res;
|
||||
#ifndef CONFIG_RESOURCES_64BIT
|
||||
if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL)
|
||||
continue;
|
||||
#endif
|
||||
res = kzalloc(sizeof(struct resource), GFP_ATOMIC);
|
||||
switch (e820.map[i].type) {
|
||||
case E820_RAM: res->name = "System RAM"; break;
|
||||
case E820_ACPI: res->name = "ACPI Tables"; break;
|
||||
case E820_NVS: res->name = "ACPI Non-volatile Storage"; break;
|
||||
default: res->name = "reserved";
|
||||
}
|
||||
res->start = e820.map[i].addr;
|
||||
res->end = res->start + e820.map[i].size - 1;
|
||||
res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
|
||||
if (request_resource(&iomem_resource, res)) {
|
||||
kfree(res);
|
||||
continue;
|
||||
}
|
||||
if (e820.map[i].type == E820_RAM) {
|
||||
/*
|
||||
* We don't know which RAM region contains kernel data,
|
||||
* so we try it repeatedly and let the resource manager
|
||||
* test it.
|
||||
*/
|
||||
request_resource(res, code_resource);
|
||||
request_resource(res, data_resource);
|
||||
#ifdef CONFIG_KEXEC
|
||||
request_resource(res, &crashk_res);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Request address space for all standard resources
|
||||
*
|
||||
* This is called just before pcibios_init(), which is also a
|
||||
* subsys_initcall, but is linked in later (in arch/i386/pci/common.c).
|
||||
*/
|
||||
static int __init request_standard_resources(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
printk("Setting up standard PCI resources\n");
|
||||
if (efi_enabled)
|
||||
efi_initialize_iomem_resources(&code_resource, &data_resource);
|
||||
else
|
||||
legacy_init_iomem_resources(&code_resource, &data_resource);
|
||||
|
||||
/* EFI systems may still have VGA */
|
||||
request_resource(&iomem_resource, &video_ram_resource);
|
||||
|
||||
/* request I/O space for devices used on all i[345]86 PCs */
|
||||
for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++)
|
||||
request_resource(&ioport_resource, &standard_io_resources[i]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
subsys_initcall(request_standard_resources);
|
||||
|
||||
void __init add_memory_region(unsigned long long start,
|
||||
unsigned long long size, int type)
|
||||
{
|
||||
int x;
|
||||
|
||||
if (!efi_enabled) {
|
||||
x = e820.nr_map;
|
||||
|
||||
if (x == E820MAX) {
|
||||
printk(KERN_ERR "Ooops! Too many entries in the memory map!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
e820.map[x].addr = start;
|
||||
e820.map[x].size = size;
|
||||
e820.map[x].type = type;
|
||||
e820.nr_map++;
|
||||
}
|
||||
} /* add_memory_region */
|
||||
|
||||
/*
|
||||
* Sanitize the BIOS e820 map.
|
||||
*
|
||||
* Some e820 responses include overlapping entries. The following
|
||||
* replaces the original e820 map with a new one, removing overlaps.
|
||||
*
|
||||
*/
|
||||
int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
|
||||
{
|
||||
struct change_member *change_tmp;
|
||||
unsigned long current_type, last_type;
|
||||
unsigned long long last_addr;
|
||||
int chgidx, still_changing;
|
||||
int overlap_entries;
|
||||
int new_bios_entry;
|
||||
int old_nr, new_nr, chg_nr;
|
||||
int i;
|
||||
|
||||
/*
|
||||
Visually we're performing the following (1,2,3,4 = memory types)...
|
||||
|
||||
Sample memory map (w/overlaps):
|
||||
____22__________________
|
||||
______________________4_
|
||||
____1111________________
|
||||
_44_____________________
|
||||
11111111________________
|
||||
____________________33__
|
||||
___________44___________
|
||||
__________33333_________
|
||||
______________22________
|
||||
___________________2222_
|
||||
_________111111111______
|
||||
_____________________11_
|
||||
_________________4______
|
||||
|
||||
Sanitized equivalent (no overlap):
|
||||
1_______________________
|
||||
_44_____________________
|
||||
___1____________________
|
||||
____22__________________
|
||||
______11________________
|
||||
_________1______________
|
||||
__________3_____________
|
||||
___________44___________
|
||||
_____________33_________
|
||||
_______________2________
|
||||
________________1_______
|
||||
_________________4______
|
||||
___________________2____
|
||||
____________________33__
|
||||
______________________4_
|
||||
*/
|
||||
printk("sanitize start\n");
|
||||
/* if there's only one memory region, don't bother */
|
||||
if (*pnr_map < 2) {
|
||||
printk("sanitize bail 0\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
old_nr = *pnr_map;
|
||||
|
||||
/* bail out if we find any unreasonable addresses in bios map */
|
||||
for (i=0; i<old_nr; i++)
|
||||
if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr) {
|
||||
printk("sanitize bail 1\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* create pointers for initial change-point information (for sorting) */
|
||||
for (i=0; i < 2*old_nr; i++)
|
||||
change_point[i] = &change_point_list[i];
|
||||
|
||||
/* record all known change-points (starting and ending addresses),
|
||||
omitting those that are for empty memory regions */
|
||||
chgidx = 0;
|
||||
for (i=0; i < old_nr; i++) {
|
||||
if (biosmap[i].size != 0) {
|
||||
change_point[chgidx]->addr = biosmap[i].addr;
|
||||
change_point[chgidx++]->pbios = &biosmap[i];
|
||||
change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size;
|
||||
change_point[chgidx++]->pbios = &biosmap[i];
|
||||
}
|
||||
}
|
||||
chg_nr = chgidx; /* true number of change-points */
|
||||
|
||||
/* sort change-point list by memory addresses (low -> high) */
|
||||
still_changing = 1;
|
||||
while (still_changing) {
|
||||
still_changing = 0;
|
||||
for (i=1; i < chg_nr; i++) {
|
||||
/* if <current_addr> > <last_addr>, swap */
|
||||
/* or, if current=<start_addr> & last=<end_addr>, swap */
|
||||
if ((change_point[i]->addr < change_point[i-1]->addr) ||
|
||||
((change_point[i]->addr == change_point[i-1]->addr) &&
|
||||
(change_point[i]->addr == change_point[i]->pbios->addr) &&
|
||||
(change_point[i-1]->addr != change_point[i-1]->pbios->addr))
|
||||
)
|
||||
{
|
||||
change_tmp = change_point[i];
|
||||
change_point[i] = change_point[i-1];
|
||||
change_point[i-1] = change_tmp;
|
||||
still_changing=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* create a new bios memory map, removing overlaps */
|
||||
overlap_entries=0; /* number of entries in the overlap table */
|
||||
new_bios_entry=0; /* index for creating new bios map entries */
|
||||
last_type = 0; /* start with undefined memory type */
|
||||
last_addr = 0; /* start with 0 as last starting address */
|
||||
/* loop through change-points, determining affect on the new bios map */
|
||||
for (chgidx=0; chgidx < chg_nr; chgidx++)
|
||||
{
|
||||
/* keep track of all overlapping bios entries */
|
||||
if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr)
|
||||
{
|
||||
/* add map entry to overlap list (> 1 entry implies an overlap) */
|
||||
overlap_list[overlap_entries++]=change_point[chgidx]->pbios;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* remove entry from list (order independent, so swap with last) */
|
||||
for (i=0; i<overlap_entries; i++)
|
||||
{
|
||||
if (overlap_list[i] == change_point[chgidx]->pbios)
|
||||
overlap_list[i] = overlap_list[overlap_entries-1];
|
||||
}
|
||||
overlap_entries--;
|
||||
}
|
||||
/* if there are overlapping entries, decide which "type" to use */
|
||||
/* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */
|
||||
current_type = 0;
|
||||
for (i=0; i<overlap_entries; i++)
|
||||
if (overlap_list[i]->type > current_type)
|
||||
current_type = overlap_list[i]->type;
|
||||
/* continue building up new bios map based on this information */
|
||||
if (current_type != last_type) {
|
||||
if (last_type != 0) {
|
||||
new_bios[new_bios_entry].size =
|
||||
change_point[chgidx]->addr - last_addr;
|
||||
/* move forward only if the new size was non-zero */
|
||||
if (new_bios[new_bios_entry].size != 0)
|
||||
if (++new_bios_entry >= E820MAX)
|
||||
break; /* no more space left for new bios entries */
|
||||
}
|
||||
if (current_type != 0) {
|
||||
new_bios[new_bios_entry].addr = change_point[chgidx]->addr;
|
||||
new_bios[new_bios_entry].type = current_type;
|
||||
last_addr=change_point[chgidx]->addr;
|
||||
}
|
||||
last_type = current_type;
|
||||
}
|
||||
}
|
||||
new_nr = new_bios_entry; /* retain count for new bios entries */
|
||||
|
||||
/* copy new bios mapping into original location */
|
||||
memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry));
|
||||
*pnr_map = new_nr;
|
||||
|
||||
printk("sanitize end\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the BIOS e820 map into a safe place.
|
||||
*
|
||||
* Sanity-check it while we're at it..
|
||||
*
|
||||
* If we're lucky and live on a modern system, the setup code
|
||||
* will have given us a memory map that we can use to properly
|
||||
* set up memory. If we aren't, we'll fake a memory map.
|
||||
*
|
||||
* We check to see that the memory map contains at least 2 elements
|
||||
* before we'll use it, because the detection code in setup.S may
|
||||
* not be perfect and most every PC known to man has two memory
|
||||
* regions: one from 0 to 640k, and one from 1mb up. (The IBM
|
||||
* thinkpad 560x, for example, does not cooperate with the memory
|
||||
* detection code.)
|
||||
*/
|
||||
int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
|
||||
{
|
||||
/* Only one memory region (or negative)? Ignore it */
|
||||
if (nr_map < 2)
|
||||
return -1;
|
||||
|
||||
do {
|
||||
unsigned long long start = biosmap->addr;
|
||||
unsigned long long size = biosmap->size;
|
||||
unsigned long long end = start + size;
|
||||
unsigned long type = biosmap->type;
|
||||
printk("copy_e820_map() start: %016Lx size: %016Lx end: %016Lx type: %ld\n", start, size, end, type);
|
||||
|
||||
/* Overflow in 64 bits? Ignore the memory map. */
|
||||
if (start > end)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Some BIOSes claim RAM in the 640k - 1M region.
|
||||
* Not right. Fix it up.
|
||||
*/
|
||||
if (type == E820_RAM) {
|
||||
printk("copy_e820_map() type is E820_RAM\n");
|
||||
if (start < 0x100000ULL && end > 0xA0000ULL) {
|
||||
printk("copy_e820_map() lies in range...\n");
|
||||
if (start < 0xA0000ULL) {
|
||||
printk("copy_e820_map() start < 0xA0000ULL\n");
|
||||
add_memory_region(start, 0xA0000ULL-start, type);
|
||||
}
|
||||
if (end <= 0x100000ULL) {
|
||||
printk("copy_e820_map() end <= 0x100000ULL\n");
|
||||
continue;
|
||||
}
|
||||
start = 0x100000ULL;
|
||||
size = end - start;
|
||||
}
|
||||
}
|
||||
add_memory_region(start, size, type);
|
||||
} while (biosmap++,--nr_map);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback for efi_memory_walk.
|
||||
*/
|
||||
static int __init
|
||||
efi_find_max_pfn(unsigned long start, unsigned long end, void *arg)
|
||||
{
|
||||
unsigned long *max_pfn = arg, pfn;
|
||||
|
||||
if (start < end) {
|
||||
pfn = PFN_UP(end -1);
|
||||
if (pfn > *max_pfn)
|
||||
*max_pfn = pfn;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init
|
||||
efi_memory_present_wrapper(unsigned long start, unsigned long end, void *arg)
|
||||
{
|
||||
memory_present(0, PFN_UP(start), PFN_DOWN(end));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the highest page frame number we have available
|
||||
*/
|
||||
void __init find_max_pfn(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
max_pfn = 0;
|
||||
if (efi_enabled) {
|
||||
efi_memmap_walk(efi_find_max_pfn, &max_pfn);
|
||||
efi_memmap_walk(efi_memory_present_wrapper, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < e820.nr_map; i++) {
|
||||
unsigned long start, end;
|
||||
/* RAM? */
|
||||
if (e820.map[i].type != E820_RAM)
|
||||
continue;
|
||||
start = PFN_UP(e820.map[i].addr);
|
||||
end = PFN_DOWN(e820.map[i].addr + e820.map[i].size);
|
||||
if (start >= end)
|
||||
continue;
|
||||
if (end > max_pfn)
|
||||
max_pfn = end;
|
||||
memory_present(0, start, end);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Free all available memory for boot time allocation. Used
|
||||
* as a callback function by efi_memory_walk()
|
||||
*/
|
||||
|
||||
static int __init
|
||||
free_available_memory(unsigned long start, unsigned long end, void *arg)
|
||||
{
|
||||
/* check max_low_pfn */
|
||||
if (start >= (max_low_pfn << PAGE_SHIFT))
|
||||
return 0;
|
||||
if (end >= (max_low_pfn << PAGE_SHIFT))
|
||||
end = max_low_pfn << PAGE_SHIFT;
|
||||
if (start < end)
|
||||
free_bootmem(start, end - start);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Register fully available low RAM pages with the bootmem allocator.
|
||||
*/
|
||||
void __init register_bootmem_low_pages(unsigned long max_low_pfn)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (efi_enabled) {
|
||||
efi_memmap_walk(free_available_memory, NULL);
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < e820.nr_map; i++) {
|
||||
unsigned long curr_pfn, last_pfn, size;
|
||||
/*
|
||||
* Reserve usable low memory
|
||||
*/
|
||||
if (e820.map[i].type != E820_RAM)
|
||||
continue;
|
||||
/*
|
||||
* We are rounding up the start address of usable memory:
|
||||
*/
|
||||
curr_pfn = PFN_UP(e820.map[i].addr);
|
||||
if (curr_pfn >= max_low_pfn)
|
||||
continue;
|
||||
/*
|
||||
* ... and at the end of the usable range downwards:
|
||||
*/
|
||||
last_pfn = PFN_DOWN(e820.map[i].addr + e820.map[i].size);
|
||||
|
||||
if (last_pfn > max_low_pfn)
|
||||
last_pfn = max_low_pfn;
|
||||
|
||||
/*
|
||||
* .. finally, did all the rounding and playing
|
||||
* around just make the area go away?
|
||||
*/
|
||||
if (last_pfn <= curr_pfn)
|
||||
continue;
|
||||
|
||||
size = last_pfn - curr_pfn;
|
||||
free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size));
|
||||
}
|
||||
}
|
||||
|
||||
void __init register_memory(void)
|
||||
{
|
||||
unsigned long gapstart, gapsize, round;
|
||||
unsigned long long last;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Search for the bigest gap in the low 32 bits of the e820
|
||||
* memory space.
|
||||
*/
|
||||
last = 0x100000000ull;
|
||||
gapstart = 0x10000000;
|
||||
gapsize = 0x400000;
|
||||
i = e820.nr_map;
|
||||
while (--i >= 0) {
|
||||
unsigned long long start = e820.map[i].addr;
|
||||
unsigned long long end = start + e820.map[i].size;
|
||||
|
||||
/*
|
||||
* Since "last" is at most 4GB, we know we'll
|
||||
* fit in 32 bits if this condition is true
|
||||
*/
|
||||
if (last > end) {
|
||||
unsigned long gap = last - end;
|
||||
|
||||
if (gap > gapsize) {
|
||||
gapsize = gap;
|
||||
gapstart = end;
|
||||
}
|
||||
}
|
||||
if (start < last)
|
||||
last = start;
|
||||
}
|
||||
|
||||
/*
|
||||
* See how much we want to round up: start off with
|
||||
* rounding to the next 1MB area.
|
||||
*/
|
||||
round = 0x100000;
|
||||
while ((gapsize >> 4) > round)
|
||||
round += round;
|
||||
/* Fun with two's complement */
|
||||
pci_mem_start = (gapstart + round) & -round;
|
||||
|
||||
printk("Allocating PCI resources starting at %08lx (gap: %08lx:%08lx)\n",
|
||||
pci_mem_start, gapstart, gapsize);
|
||||
}
|
||||
|
||||
void __init print_memory_map(char *who)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < e820.nr_map; i++) {
|
||||
printk(" %s: %016Lx - %016Lx ", who,
|
||||
e820.map[i].addr,
|
||||
e820.map[i].addr + e820.map[i].size);
|
||||
switch (e820.map[i].type) {
|
||||
case E820_RAM: printk("(usable)\n");
|
||||
break;
|
||||
case E820_RESERVED:
|
||||
printk("(reserved)\n");
|
||||
break;
|
||||
case E820_ACPI:
|
||||
printk("(ACPI data)\n");
|
||||
break;
|
||||
case E820_NVS:
|
||||
printk("(ACPI NVS)\n");
|
||||
break;
|
||||
default: printk("type %lu\n", e820.map[i].type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static __init __always_inline void efi_limit_regions(unsigned long long size)
|
||||
{
|
||||
unsigned long long current_addr = 0;
|
||||
efi_memory_desc_t *md, *next_md;
|
||||
void *p, *p1;
|
||||
int i, j;
|
||||
|
||||
j = 0;
|
||||
p1 = memmap.map;
|
||||
for (p = p1, i = 0; p < memmap.map_end; p += memmap.desc_size, i++) {
|
||||
md = p;
|
||||
next_md = p1;
|
||||
current_addr = md->phys_addr +
|
||||
PFN_PHYS(md->num_pages);
|
||||
if (is_available_memory(md)) {
|
||||
if (md->phys_addr >= size) continue;
|
||||
memcpy(next_md, md, memmap.desc_size);
|
||||
if (current_addr >= size) {
|
||||
next_md->num_pages -=
|
||||
PFN_UP(current_addr-size);
|
||||
}
|
||||
p1 += memmap.desc_size;
|
||||
next_md = p1;
|
||||
j++;
|
||||
} else if ((md->attribute & EFI_MEMORY_RUNTIME) ==
|
||||
EFI_MEMORY_RUNTIME) {
|
||||
/* In order to make runtime services
|
||||
* available we have to include runtime
|
||||
* memory regions in memory map */
|
||||
memcpy(next_md, md, memmap.desc_size);
|
||||
p1 += memmap.desc_size;
|
||||
next_md = p1;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
memmap.nr_map = j;
|
||||
memmap.map_end = memmap.map +
|
||||
(memmap.nr_map * memmap.desc_size);
|
||||
}
|
||||
|
||||
void __init limit_regions(unsigned long long size)
|
||||
{
|
||||
unsigned long long current_addr;
|
||||
int i;
|
||||
|
||||
print_memory_map("limit_regions start");
|
||||
if (efi_enabled) {
|
||||
efi_limit_regions(size);
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < e820.nr_map; i++) {
|
||||
current_addr = e820.map[i].addr + e820.map[i].size;
|
||||
if (current_addr < size)
|
||||
continue;
|
||||
|
||||
if (e820.map[i].type != E820_RAM)
|
||||
continue;
|
||||
|
||||
if (e820.map[i].addr >= size) {
|
||||
/*
|
||||
* This region starts past the end of the
|
||||
* requested size, skip it completely.
|
||||
*/
|
||||
e820.nr_map = i;
|
||||
} else {
|
||||
e820.nr_map = i + 1;
|
||||
e820.map[i].size -= current_addr - size;
|
||||
}
|
||||
print_memory_map("limit_regions endfor");
|
||||
return;
|
||||
}
|
||||
print_memory_map("limit_regions endfunc");
|
||||
}
|
||||
|
||||
/*
|
||||
* This function checks if the entire range <start,end> is mapped with type.
|
||||
*
|
||||
* Note: this function only works correct if the e820 table is sorted and
|
||||
* not-overlapping, which is the case
|
||||
*/
|
||||
int __init
|
||||
e820_all_mapped(unsigned long s, unsigned long e, unsigned type)
|
||||
{
|
||||
u64 start = s;
|
||||
u64 end = e;
|
||||
int i;
|
||||
for (i = 0; i < e820.nr_map; i++) {
|
||||
struct e820entry *ei = &e820.map[i];
|
||||
if (type && ei->type != type)
|
||||
continue;
|
||||
/* is the region (part) in overlap with the current region ?*/
|
||||
if (ei->addr >= end || ei->addr + ei->size <= start)
|
||||
continue;
|
||||
/* if the region is at the beginning of <start,end> we move
|
||||
* start to the end of the region since it's ok until there
|
||||
*/
|
||||
if (ei->addr <= start)
|
||||
start = ei->addr + ei->size;
|
||||
/* if start is now at or beyond end, we're done, full
|
||||
* coverage */
|
||||
if (start >= end)
|
||||
return 1; /* we're done */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init parse_memmap(char *arg)
|
||||
{
|
||||
if (!arg)
|
||||
return -EINVAL;
|
||||
|
||||
if (strcmp(arg, "exactmap") == 0) {
|
||||
#ifdef CONFIG_CRASH_DUMP
|
||||
/* If we are doing a crash dump, we
|
||||
* still need to know the real mem
|
||||
* size before original memory map is
|
||||
* reset.
|
||||
*/
|
||||
find_max_pfn();
|
||||
saved_max_pfn = max_pfn;
|
||||
#endif
|
||||
e820.nr_map = 0;
|
||||
user_defined_memmap = 1;
|
||||
} else {
|
||||
/* If the user specifies memory size, we
|
||||
* limit the BIOS-provided memory map to
|
||||
* that size. exactmap can be used to specify
|
||||
* the exact map. mem=number can be used to
|
||||
* trim the existing memory map.
|
||||
*/
|
||||
unsigned long long start_at, mem_size;
|
||||
|
||||
mem_size = memparse(arg, &arg);
|
||||
if (*arg == '@') {
|
||||
start_at = memparse(arg+1, &arg);
|
||||
add_memory_region(start_at, mem_size, E820_RAM);
|
||||
} else if (*arg == '#') {
|
||||
start_at = memparse(arg+1, &arg);
|
||||
add_memory_region(start_at, mem_size, E820_ACPI);
|
||||
} else if (*arg == '$') {
|
||||
start_at = memparse(arg+1, &arg);
|
||||
add_memory_region(start_at, mem_size, E820_RESERVED);
|
||||
} else {
|
||||
limit_regions(mem_size);
|
||||
user_defined_memmap = 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
early_param("memmap", parse_memmap);
|
|
@ -194,17 +194,24 @@ inline int efi_set_rtc_mmss(unsigned long nowtime)
|
|||
return 0;
|
||||
}
|
||||
/*
|
||||
* This should only be used during kernel init and before runtime
|
||||
* services have been remapped, therefore, we'll need to call in physical
|
||||
* mode. Note, this call isn't used later, so mark it __init.
|
||||
* This is used during kernel init before runtime
|
||||
* services have been remapped and also during suspend, therefore,
|
||||
* we'll need to call both in physical and virtual modes.
|
||||
*/
|
||||
inline unsigned long __init efi_get_time(void)
|
||||
inline unsigned long efi_get_time(void)
|
||||
{
|
||||
efi_status_t status;
|
||||
efi_time_t eft;
|
||||
efi_time_cap_t cap;
|
||||
|
||||
status = phys_efi_get_time(&eft, &cap);
|
||||
if (efi.get_time) {
|
||||
/* if we are in virtual mode use remapped function */
|
||||
status = efi.get_time(&eft, &cap);
|
||||
} else {
|
||||
/* we are in physical mode */
|
||||
status = phys_efi_get_time(&eft, &cap);
|
||||
}
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
printk("Oops: efitime: can't read time status: 0x%lx\n",status);
|
||||
|
||||
|
|
|
@ -30,12 +30,13 @@
|
|||
* 18(%esp) - %eax
|
||||
* 1C(%esp) - %ds
|
||||
* 20(%esp) - %es
|
||||
* 24(%esp) - orig_eax
|
||||
* 28(%esp) - %eip
|
||||
* 2C(%esp) - %cs
|
||||
* 30(%esp) - %eflags
|
||||
* 34(%esp) - %oldesp
|
||||
* 38(%esp) - %oldss
|
||||
* 24(%esp) - %gs
|
||||
* 28(%esp) - orig_eax
|
||||
* 2C(%esp) - %eip
|
||||
* 30(%esp) - %cs
|
||||
* 34(%esp) - %eflags
|
||||
* 38(%esp) - %oldesp
|
||||
* 3C(%esp) - %oldss
|
||||
*
|
||||
* "current" is in register %ebx during any slow entries.
|
||||
*/
|
||||
|
@ -48,26 +49,24 @@
|
|||
#include <asm/smp.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/desc.h>
|
||||
#include <asm/percpu.h>
|
||||
#include <asm/dwarf2.h>
|
||||
#include "irq_vectors.h"
|
||||
|
||||
#define nr_syscalls ((syscall_table_size)/4)
|
||||
/*
|
||||
* We use macros for low-level operations which need to be overridden
|
||||
* for paravirtualization. The following will never clobber any registers:
|
||||
* INTERRUPT_RETURN (aka. "iret")
|
||||
* GET_CR0_INTO_EAX (aka. "movl %cr0, %eax")
|
||||
* ENABLE_INTERRUPTS_SYSEXIT (aka "sti; sysexit").
|
||||
*
|
||||
* For DISABLE_INTERRUPTS/ENABLE_INTERRUPTS (aka "cli"/"sti"), you must
|
||||
* specify what registers can be overwritten (CLBR_NONE, CLBR_EAX/EDX/ECX/ANY).
|
||||
* Allowing a register to be clobbered can shrink the paravirt replacement
|
||||
* enough to patch inline, increasing performance.
|
||||
*/
|
||||
|
||||
EBX = 0x00
|
||||
ECX = 0x04
|
||||
EDX = 0x08
|
||||
ESI = 0x0C
|
||||
EDI = 0x10
|
||||
EBP = 0x14
|
||||
EAX = 0x18
|
||||
DS = 0x1C
|
||||
ES = 0x20
|
||||
ORIG_EAX = 0x24
|
||||
EIP = 0x28
|
||||
CS = 0x2C
|
||||
EFLAGS = 0x30
|
||||
OLDESP = 0x34
|
||||
OLDSS = 0x38
|
||||
#define nr_syscalls ((syscall_table_size)/4)
|
||||
|
||||
CF_MASK = 0x00000001
|
||||
TF_MASK = 0x00000100
|
||||
|
@ -76,23 +75,16 @@ DF_MASK = 0x00000400
|
|||
NT_MASK = 0x00004000
|
||||
VM_MASK = 0x00020000
|
||||
|
||||
/* These are replaces for paravirtualization */
|
||||
#define DISABLE_INTERRUPTS cli
|
||||
#define ENABLE_INTERRUPTS sti
|
||||
#define ENABLE_INTERRUPTS_SYSEXIT sti; sysexit
|
||||
#define INTERRUPT_RETURN iret
|
||||
#define GET_CR0_INTO_EAX movl %cr0, %eax
|
||||
|
||||
#ifdef CONFIG_PREEMPT
|
||||
#define preempt_stop DISABLE_INTERRUPTS; TRACE_IRQS_OFF
|
||||
#define preempt_stop(clobbers) DISABLE_INTERRUPTS(clobbers); TRACE_IRQS_OFF
|
||||
#else
|
||||
#define preempt_stop
|
||||
#define preempt_stop(clobbers)
|
||||
#define resume_kernel restore_nocheck
|
||||
#endif
|
||||
|
||||
.macro TRACE_IRQS_IRET
|
||||
#ifdef CONFIG_TRACE_IRQFLAGS
|
||||
testl $IF_MASK,EFLAGS(%esp) # interrupts off?
|
||||
testl $IF_MASK,PT_EFLAGS(%esp) # interrupts off?
|
||||
jz 1f
|
||||
TRACE_IRQS_ON
|
||||
1:
|
||||
|
@ -107,6 +99,9 @@ VM_MASK = 0x00020000
|
|||
|
||||
#define SAVE_ALL \
|
||||
cld; \
|
||||
pushl %gs; \
|
||||
CFI_ADJUST_CFA_OFFSET 4;\
|
||||
/*CFI_REL_OFFSET gs, 0;*/\
|
||||
pushl %es; \
|
||||
CFI_ADJUST_CFA_OFFSET 4;\
|
||||
/*CFI_REL_OFFSET es, 0;*/\
|
||||
|
@ -136,7 +131,9 @@ VM_MASK = 0x00020000
|
|||
CFI_REL_OFFSET ebx, 0;\
|
||||
movl $(__USER_DS), %edx; \
|
||||
movl %edx, %ds; \
|
||||
movl %edx, %es;
|
||||
movl %edx, %es; \
|
||||
movl $(__KERNEL_PDA), %edx; \
|
||||
movl %edx, %gs
|
||||
|
||||
#define RESTORE_INT_REGS \
|
||||
popl %ebx; \
|
||||
|
@ -169,17 +166,22 @@ VM_MASK = 0x00020000
|
|||
2: popl %es; \
|
||||
CFI_ADJUST_CFA_OFFSET -4;\
|
||||
/*CFI_RESTORE es;*/\
|
||||
.section .fixup,"ax"; \
|
||||
3: movl $0,(%esp); \
|
||||
jmp 1b; \
|
||||
3: popl %gs; \
|
||||
CFI_ADJUST_CFA_OFFSET -4;\
|
||||
/*CFI_RESTORE gs;*/\
|
||||
.pushsection .fixup,"ax"; \
|
||||
4: movl $0,(%esp); \
|
||||
jmp 1b; \
|
||||
5: movl $0,(%esp); \
|
||||
jmp 2b; \
|
||||
.previous; \
|
||||
6: movl $0,(%esp); \
|
||||
jmp 3b; \
|
||||
.section __ex_table,"a";\
|
||||
.align 4; \
|
||||
.long 1b,3b; \
|
||||
.long 2b,4b; \
|
||||
.previous
|
||||
.long 1b,4b; \
|
||||
.long 2b,5b; \
|
||||
.long 3b,6b; \
|
||||
.popsection
|
||||
|
||||
#define RING0_INT_FRAME \
|
||||
CFI_STARTPROC simple;\
|
||||
|
@ -198,18 +200,18 @@ VM_MASK = 0x00020000
|
|||
#define RING0_PTREGS_FRAME \
|
||||
CFI_STARTPROC simple;\
|
||||
CFI_SIGNAL_FRAME;\
|
||||
CFI_DEF_CFA esp, OLDESP-EBX;\
|
||||
/*CFI_OFFSET cs, CS-OLDESP;*/\
|
||||
CFI_OFFSET eip, EIP-OLDESP;\
|
||||
/*CFI_OFFSET es, ES-OLDESP;*/\
|
||||
/*CFI_OFFSET ds, DS-OLDESP;*/\
|
||||
CFI_OFFSET eax, EAX-OLDESP;\
|
||||
CFI_OFFSET ebp, EBP-OLDESP;\
|
||||
CFI_OFFSET edi, EDI-OLDESP;\
|
||||
CFI_OFFSET esi, ESI-OLDESP;\
|
||||
CFI_OFFSET edx, EDX-OLDESP;\
|
||||
CFI_OFFSET ecx, ECX-OLDESP;\
|
||||
CFI_OFFSET ebx, EBX-OLDESP
|
||||
CFI_DEF_CFA esp, PT_OLDESP-PT_EBX;\
|
||||
/*CFI_OFFSET cs, PT_CS-PT_OLDESP;*/\
|
||||
CFI_OFFSET eip, PT_EIP-PT_OLDESP;\
|
||||
/*CFI_OFFSET es, PT_ES-PT_OLDESP;*/\
|
||||
/*CFI_OFFSET ds, PT_DS-PT_OLDESP;*/\
|
||||
CFI_OFFSET eax, PT_EAX-PT_OLDESP;\
|
||||
CFI_OFFSET ebp, PT_EBP-PT_OLDESP;\
|
||||
CFI_OFFSET edi, PT_EDI-PT_OLDESP;\
|
||||
CFI_OFFSET esi, PT_ESI-PT_OLDESP;\
|
||||
CFI_OFFSET edx, PT_EDX-PT_OLDESP;\
|
||||
CFI_OFFSET ecx, PT_ECX-PT_OLDESP;\
|
||||
CFI_OFFSET ebx, PT_EBX-PT_OLDESP
|
||||
|
||||
ENTRY(ret_from_fork)
|
||||
CFI_STARTPROC
|
||||
|
@ -237,17 +239,18 @@ ENTRY(ret_from_fork)
|
|||
ALIGN
|
||||
RING0_PTREGS_FRAME
|
||||
ret_from_exception:
|
||||
preempt_stop
|
||||
preempt_stop(CLBR_ANY)
|
||||
ret_from_intr:
|
||||
GET_THREAD_INFO(%ebp)
|
||||
check_userspace:
|
||||
movl EFLAGS(%esp), %eax # mix EFLAGS and CS
|
||||
movb CS(%esp), %al
|
||||
movl PT_EFLAGS(%esp), %eax # mix EFLAGS and CS
|
||||
movb PT_CS(%esp), %al
|
||||
andl $(VM_MASK | SEGMENT_RPL_MASK), %eax
|
||||
cmpl $USER_RPL, %eax
|
||||
jb resume_kernel # not returning to v8086 or userspace
|
||||
|
||||
ENTRY(resume_userspace)
|
||||
DISABLE_INTERRUPTS # make sure we don't miss an interrupt
|
||||
DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt
|
||||
# setting need_resched or sigpending
|
||||
# between sampling and the iret
|
||||
movl TI_flags(%ebp), %ecx
|
||||
|
@ -258,14 +261,14 @@ ENTRY(resume_userspace)
|
|||
|
||||
#ifdef CONFIG_PREEMPT
|
||||
ENTRY(resume_kernel)
|
||||
DISABLE_INTERRUPTS
|
||||
DISABLE_INTERRUPTS(CLBR_ANY)
|
||||
cmpl $0,TI_preempt_count(%ebp) # non-zero preempt_count ?
|
||||
jnz restore_nocheck
|
||||
need_resched:
|
||||
movl TI_flags(%ebp), %ecx # need_resched set ?
|
||||
testb $_TIF_NEED_RESCHED, %cl
|
||||
jz restore_all
|
||||
testl $IF_MASK,EFLAGS(%esp) # interrupts off (exception path) ?
|
||||
testl $IF_MASK,PT_EFLAGS(%esp) # interrupts off (exception path) ?
|
||||
jz restore_all
|
||||
call preempt_schedule_irq
|
||||
jmp need_resched
|
||||
|
@ -287,7 +290,7 @@ sysenter_past_esp:
|
|||
* No need to follow this irqs on/off section: the syscall
|
||||
* disabled irqs and here we enable it straight after entry:
|
||||
*/
|
||||
ENABLE_INTERRUPTS
|
||||
ENABLE_INTERRUPTS(CLBR_NONE)
|
||||
pushl $(__USER_DS)
|
||||
CFI_ADJUST_CFA_OFFSET 4
|
||||
/*CFI_REL_OFFSET ss, 0*/
|
||||
|
@ -331,20 +334,27 @@ sysenter_past_esp:
|
|||
cmpl $(nr_syscalls), %eax
|
||||
jae syscall_badsys
|
||||
call *sys_call_table(,%eax,4)
|
||||
movl %eax,EAX(%esp)
|
||||
DISABLE_INTERRUPTS
|
||||
movl %eax,PT_EAX(%esp)
|
||||
DISABLE_INTERRUPTS(CLBR_ECX|CLBR_EDX)
|
||||
TRACE_IRQS_OFF
|
||||
movl TI_flags(%ebp), %ecx
|
||||
testw $_TIF_ALLWORK_MASK, %cx
|
||||
jne syscall_exit_work
|
||||
/* if something modifies registers it must also disable sysexit */
|
||||
movl EIP(%esp), %edx
|
||||
movl OLDESP(%esp), %ecx
|
||||
movl PT_EIP(%esp), %edx
|
||||
movl PT_OLDESP(%esp), %ecx
|
||||
xorl %ebp,%ebp
|
||||
TRACE_IRQS_ON
|
||||
1: mov PT_GS(%esp), %gs
|
||||
ENABLE_INTERRUPTS_SYSEXIT
|
||||
CFI_ENDPROC
|
||||
|
||||
.pushsection .fixup,"ax"
|
||||
2: movl $0,PT_GS(%esp)
|
||||
jmp 1b
|
||||
.section __ex_table,"a"
|
||||
.align 4
|
||||
.long 1b,2b
|
||||
.popsection
|
||||
|
||||
# system call handler stub
|
||||
ENTRY(system_call)
|
||||
|
@ -353,7 +363,7 @@ ENTRY(system_call)
|
|||
CFI_ADJUST_CFA_OFFSET 4
|
||||
SAVE_ALL
|
||||
GET_THREAD_INFO(%ebp)
|
||||
testl $TF_MASK,EFLAGS(%esp)
|
||||
testl $TF_MASK,PT_EFLAGS(%esp)
|
||||
jz no_singlestep
|
||||
orl $_TIF_SINGLESTEP,TI_flags(%ebp)
|
||||
no_singlestep:
|
||||
|
@ -365,9 +375,9 @@ no_singlestep:
|
|||
jae syscall_badsys
|
||||
syscall_call:
|
||||
call *sys_call_table(,%eax,4)
|
||||
movl %eax,EAX(%esp) # store the return value
|
||||
movl %eax,PT_EAX(%esp) # store the return value
|
||||
syscall_exit:
|
||||
DISABLE_INTERRUPTS # make sure we don't miss an interrupt
|
||||
DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt
|
||||
# setting need_resched or sigpending
|
||||
# between sampling and the iret
|
||||
TRACE_IRQS_OFF
|
||||
|
@ -376,12 +386,12 @@ syscall_exit:
|
|||
jne syscall_exit_work
|
||||
|
||||
restore_all:
|
||||
movl EFLAGS(%esp), %eax # mix EFLAGS, SS and CS
|
||||
# Warning: OLDSS(%esp) contains the wrong/random values if we
|
||||
movl PT_EFLAGS(%esp), %eax # mix EFLAGS, SS and CS
|
||||
# Warning: PT_OLDSS(%esp) contains the wrong/random values if we
|
||||
# are returning to the kernel.
|
||||
# See comments in process.c:copy_thread() for details.
|
||||
movb OLDSS(%esp), %ah
|
||||
movb CS(%esp), %al
|
||||
movb PT_OLDSS(%esp), %ah
|
||||
movb PT_CS(%esp), %al
|
||||
andl $(VM_MASK | (SEGMENT_TI_MASK << 8) | SEGMENT_RPL_MASK), %eax
|
||||
cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax
|
||||
CFI_REMEMBER_STATE
|
||||
|
@ -390,13 +400,13 @@ restore_nocheck:
|
|||
TRACE_IRQS_IRET
|
||||
restore_nocheck_notrace:
|
||||
RESTORE_REGS
|
||||
addl $4, %esp
|
||||
addl $4, %esp # skip orig_eax/error_code
|
||||
CFI_ADJUST_CFA_OFFSET -4
|
||||
1: INTERRUPT_RETURN
|
||||
.section .fixup,"ax"
|
||||
iret_exc:
|
||||
TRACE_IRQS_ON
|
||||
ENABLE_INTERRUPTS
|
||||
ENABLE_INTERRUPTS(CLBR_NONE)
|
||||
pushl $0 # no error code
|
||||
pushl $do_iret_error
|
||||
jmp error_code
|
||||
|
@ -408,33 +418,42 @@ iret_exc:
|
|||
|
||||
CFI_RESTORE_STATE
|
||||
ldt_ss:
|
||||
larl OLDSS(%esp), %eax
|
||||
larl PT_OLDSS(%esp), %eax
|
||||
jnz restore_nocheck
|
||||
testl $0x00400000, %eax # returning to 32bit stack?
|
||||
jnz restore_nocheck # allright, normal return
|
||||
|
||||
#ifdef CONFIG_PARAVIRT
|
||||
/*
|
||||
* The kernel can't run on a non-flat stack if paravirt mode
|
||||
* is active. Rather than try to fixup the high bits of
|
||||
* ESP, bypass this code entirely. This may break DOSemu
|
||||
* and/or Wine support in a paravirt VM, although the option
|
||||
* is still available to implement the setting of the high
|
||||
* 16-bits in the INTERRUPT_RETURN paravirt-op.
|
||||
*/
|
||||
cmpl $0, paravirt_ops+PARAVIRT_enabled
|
||||
jne restore_nocheck
|
||||
#endif
|
||||
|
||||
/* If returning to userspace with 16bit stack,
|
||||
* try to fix the higher word of ESP, as the CPU
|
||||
* won't restore it.
|
||||
* This is an "official" bug of all the x86-compatible
|
||||
* CPUs, which we can try to work around to make
|
||||
* dosemu and wine happy. */
|
||||
subl $8, %esp # reserve space for switch16 pointer
|
||||
CFI_ADJUST_CFA_OFFSET 8
|
||||
DISABLE_INTERRUPTS
|
||||
movl PT_OLDESP(%esp), %eax
|
||||
movl %esp, %edx
|
||||
call patch_espfix_desc
|
||||
pushl $__ESPFIX_SS
|
||||
CFI_ADJUST_CFA_OFFSET 4
|
||||
pushl %eax
|
||||
CFI_ADJUST_CFA_OFFSET 4
|
||||
DISABLE_INTERRUPTS(CLBR_EAX)
|
||||
TRACE_IRQS_OFF
|
||||
movl %esp, %eax
|
||||
/* Set up the 16bit stack frame with switch32 pointer on top,
|
||||
* and a switch16 pointer on top of the current frame. */
|
||||
call setup_x86_bogus_stack
|
||||
CFI_ADJUST_CFA_OFFSET -8 # frame has moved
|
||||
TRACE_IRQS_IRET
|
||||
RESTORE_REGS
|
||||
lss 20+4(%esp), %esp # switch to 16bit stack
|
||||
1: INTERRUPT_RETURN
|
||||
.section __ex_table,"a"
|
||||
.align 4
|
||||
.long 1b,iret_exc
|
||||
.previous
|
||||
lss (%esp), %esp
|
||||
CFI_ADJUST_CFA_OFFSET -8
|
||||
jmp restore_nocheck
|
||||
CFI_ENDPROC
|
||||
|
||||
# perform work that needs to be done immediately before resumption
|
||||
|
@ -445,7 +464,7 @@ work_pending:
|
|||
jz work_notifysig
|
||||
work_resched:
|
||||
call schedule
|
||||
DISABLE_INTERRUPTS # make sure we don't miss an interrupt
|
||||
DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt
|
||||
# setting need_resched or sigpending
|
||||
# between sampling and the iret
|
||||
TRACE_IRQS_OFF
|
||||
|
@ -458,7 +477,8 @@ work_resched:
|
|||
|
||||
work_notifysig: # deal with pending signals and
|
||||
# notify-resume requests
|
||||
testl $VM_MASK, EFLAGS(%esp)
|
||||
#ifdef CONFIG_VM86
|
||||
testl $VM_MASK, PT_EFLAGS(%esp)
|
||||
movl %esp, %eax
|
||||
jne work_notifysig_v86 # returning to kernel-space or
|
||||
# vm86-space
|
||||
|
@ -468,29 +488,30 @@ work_notifysig: # deal with pending signals and
|
|||
|
||||
ALIGN
|
||||
work_notifysig_v86:
|
||||
#ifdef CONFIG_VM86
|
||||
pushl %ecx # save ti_flags for do_notify_resume
|
||||
CFI_ADJUST_CFA_OFFSET 4
|
||||
call save_v86_state # %eax contains pt_regs pointer
|
||||
popl %ecx
|
||||
CFI_ADJUST_CFA_OFFSET -4
|
||||
movl %eax, %esp
|
||||
#else
|
||||
movl %esp, %eax
|
||||
#endif
|
||||
xorl %edx, %edx
|
||||
call do_notify_resume
|
||||
jmp resume_userspace_sig
|
||||
#endif
|
||||
|
||||
# perform syscall exit tracing
|
||||
ALIGN
|
||||
syscall_trace_entry:
|
||||
movl $-ENOSYS,EAX(%esp)
|
||||
movl $-ENOSYS,PT_EAX(%esp)
|
||||
movl %esp, %eax
|
||||
xorl %edx,%edx
|
||||
call do_syscall_trace
|
||||
cmpl $0, %eax
|
||||
jne resume_userspace # ret != 0 -> running under PTRACE_SYSEMU,
|
||||
# so must skip actual syscall
|
||||
movl ORIG_EAX(%esp), %eax
|
||||
movl PT_ORIG_EAX(%esp), %eax
|
||||
cmpl $(nr_syscalls), %eax
|
||||
jnae syscall_call
|
||||
jmp syscall_exit
|
||||
|
@ -501,7 +522,7 @@ syscall_exit_work:
|
|||
testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP), %cl
|
||||
jz work_pending
|
||||
TRACE_IRQS_ON
|
||||
ENABLE_INTERRUPTS # could let do_syscall_trace() call
|
||||
ENABLE_INTERRUPTS(CLBR_ANY) # could let do_syscall_trace() call
|
||||
# schedule() instead
|
||||
movl %esp, %eax
|
||||
movl $1, %edx
|
||||
|
@ -515,39 +536,38 @@ syscall_fault:
|
|||
CFI_ADJUST_CFA_OFFSET 4
|
||||
SAVE_ALL
|
||||
GET_THREAD_INFO(%ebp)
|
||||
movl $-EFAULT,EAX(%esp)
|
||||
movl $-EFAULT,PT_EAX(%esp)
|
||||
jmp resume_userspace
|
||||
|
||||
syscall_badsys:
|
||||
movl $-ENOSYS,EAX(%esp)
|
||||
movl $-ENOSYS,PT_EAX(%esp)
|
||||
jmp resume_userspace
|
||||
CFI_ENDPROC
|
||||
|
||||
#define FIXUP_ESPFIX_STACK \
|
||||
movl %esp, %eax; \
|
||||
/* switch to 32bit stack using the pointer on top of 16bit stack */ \
|
||||
lss %ss:CPU_16BIT_STACK_SIZE-8, %esp; \
|
||||
/* copy data from 16bit stack to 32bit stack */ \
|
||||
call fixup_x86_bogus_stack; \
|
||||
/* put ESP to the proper location */ \
|
||||
movl %eax, %esp;
|
||||
#define UNWIND_ESPFIX_STACK \
|
||||
/* since we are on a wrong stack, we cant make it a C code :( */ \
|
||||
movl %gs:PDA_cpu, %ebx; \
|
||||
PER_CPU(cpu_gdt_descr, %ebx); \
|
||||
movl GDS_address(%ebx), %ebx; \
|
||||
GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah); \
|
||||
addl %esp, %eax; \
|
||||
pushl $__KERNEL_DS; \
|
||||
CFI_ADJUST_CFA_OFFSET 4; \
|
||||
pushl %eax; \
|
||||
CFI_ADJUST_CFA_OFFSET 4; \
|
||||
lss (%esp), %esp; \
|
||||
CFI_ADJUST_CFA_OFFSET -8;
|
||||
#define UNWIND_ESPFIX_STACK \
|
||||
movl %ss, %eax; \
|
||||
/* see if on 16bit stack */ \
|
||||
/* see if on espfix stack */ \
|
||||
cmpw $__ESPFIX_SS, %ax; \
|
||||
je 28f; \
|
||||
27: popl %eax; \
|
||||
CFI_ADJUST_CFA_OFFSET -4; \
|
||||
.section .fixup,"ax"; \
|
||||
28: movl $__KERNEL_DS, %eax; \
|
||||
jne 27f; \
|
||||
movl $__KERNEL_DS, %eax; \
|
||||
movl %eax, %ds; \
|
||||
movl %eax, %es; \
|
||||
/* switch to 32bit stack */ \
|
||||
/* switch to normal stack */ \
|
||||
FIXUP_ESPFIX_STACK; \
|
||||
jmp 27b; \
|
||||
.previous
|
||||
27:;
|
||||
|
||||
/*
|
||||
* Build the entry stubs and pointer table with
|
||||
|
@ -608,13 +628,16 @@ KPROBE_ENTRY(page_fault)
|
|||
CFI_ADJUST_CFA_OFFSET 4
|
||||
ALIGN
|
||||
error_code:
|
||||
/* the function address is in %gs's slot on the stack */
|
||||
pushl %es
|
||||
CFI_ADJUST_CFA_OFFSET 4
|
||||
/*CFI_REL_OFFSET es, 0*/
|
||||
pushl %ds
|
||||
CFI_ADJUST_CFA_OFFSET 4
|
||||
/*CFI_REL_OFFSET ds, 0*/
|
||||
pushl %eax
|
||||
CFI_ADJUST_CFA_OFFSET 4
|
||||
CFI_REL_OFFSET eax, 0
|
||||
xorl %eax, %eax
|
||||
pushl %ebp
|
||||
CFI_ADJUST_CFA_OFFSET 4
|
||||
CFI_REL_OFFSET ebp, 0
|
||||
|
@ -627,7 +650,6 @@ error_code:
|
|||
pushl %edx
|
||||
CFI_ADJUST_CFA_OFFSET 4
|
||||
CFI_REL_OFFSET edx, 0
|
||||
decl %eax # eax = -1
|
||||
pushl %ecx
|
||||
CFI_ADJUST_CFA_OFFSET 4
|
||||
CFI_REL_OFFSET ecx, 0
|
||||
|
@ -635,18 +657,20 @@ error_code:
|
|||
CFI_ADJUST_CFA_OFFSET 4
|
||||
CFI_REL_OFFSET ebx, 0
|
||||
cld
|
||||
pushl %es
|
||||
pushl %gs
|
||||
CFI_ADJUST_CFA_OFFSET 4
|
||||
/*CFI_REL_OFFSET es, 0*/
|
||||
/*CFI_REL_OFFSET gs, 0*/
|
||||
movl $(__KERNEL_PDA), %ecx
|
||||
movl %ecx, %gs
|
||||
UNWIND_ESPFIX_STACK
|
||||
popl %ecx
|
||||
CFI_ADJUST_CFA_OFFSET -4
|
||||
/*CFI_REGISTER es, ecx*/
|
||||
movl ES(%esp), %edi # get the function address
|
||||
movl ORIG_EAX(%esp), %edx # get the error code
|
||||
movl %eax, ORIG_EAX(%esp)
|
||||
movl %ecx, ES(%esp)
|
||||
/*CFI_REL_OFFSET es, ES*/
|
||||
movl PT_GS(%esp), %edi # get the function address
|
||||
movl PT_ORIG_EAX(%esp), %edx # get the error code
|
||||
movl $-1, PT_ORIG_EAX(%esp) # no syscall to restart
|
||||
mov %ecx, PT_GS(%esp)
|
||||
/*CFI_REL_OFFSET gs, ES*/
|
||||
movl $(__USER_DS), %ecx
|
||||
movl %ecx, %ds
|
||||
movl %ecx, %es
|
||||
|
@ -682,7 +706,7 @@ ENTRY(device_not_available)
|
|||
GET_CR0_INTO_EAX
|
||||
testl $0x4, %eax # EM (math emulation bit)
|
||||
jne device_not_available_emulate
|
||||
preempt_stop
|
||||
preempt_stop(CLBR_ANY)
|
||||
call math_state_restore
|
||||
jmp ret_from_exception
|
||||
device_not_available_emulate:
|
||||
|
@ -754,7 +778,7 @@ KPROBE_ENTRY(nmi)
|
|||
cmpw $__ESPFIX_SS, %ax
|
||||
popl %eax
|
||||
CFI_ADJUST_CFA_OFFSET -4
|
||||
je nmi_16bit_stack
|
||||
je nmi_espfix_stack
|
||||
cmpl $sysenter_entry,(%esp)
|
||||
je nmi_stack_fixup
|
||||
pushl %eax
|
||||
|
@ -797,7 +821,7 @@ nmi_debug_stack_check:
|
|||
FIX_STACK(24,nmi_stack_correct, 1)
|
||||
jmp nmi_stack_correct
|
||||
|
||||
nmi_16bit_stack:
|
||||
nmi_espfix_stack:
|
||||
/* We have a RING0_INT_FRAME here.
|
||||
*
|
||||
* create the pointer to lss back
|
||||
|
@ -806,7 +830,6 @@ nmi_16bit_stack:
|
|||
CFI_ADJUST_CFA_OFFSET 4
|
||||
pushl %esp
|
||||
CFI_ADJUST_CFA_OFFSET 4
|
||||
movzwl %sp, %esp
|
||||
addw $4, (%esp)
|
||||
/* copy the iret frame of 12 bytes */
|
||||
.rept 3
|
||||
|
@ -817,11 +840,11 @@ nmi_16bit_stack:
|
|||
CFI_ADJUST_CFA_OFFSET 4
|
||||
SAVE_ALL
|
||||
FIXUP_ESPFIX_STACK # %eax == %esp
|
||||
CFI_ADJUST_CFA_OFFSET -20 # the frame has now moved
|
||||
xorl %edx,%edx # zero error code
|
||||
call do_nmi
|
||||
RESTORE_REGS
|
||||
lss 12+4(%esp), %esp # back to 16bit stack
|
||||
lss 12+4(%esp), %esp # back to espfix stack
|
||||
CFI_ADJUST_CFA_OFFSET -24
|
||||
1: INTERRUPT_RETURN
|
||||
CFI_ENDPROC
|
||||
.section __ex_table,"a"
|
||||
|
@ -830,6 +853,19 @@ nmi_16bit_stack:
|
|||
.previous
|
||||
KPROBE_END(nmi)
|
||||
|
||||
#ifdef CONFIG_PARAVIRT
|
||||
ENTRY(native_iret)
|
||||
1: iret
|
||||
.section __ex_table,"a"
|
||||
.align 4
|
||||
.long 1b,iret_exc
|
||||
.previous
|
||||
|
||||
ENTRY(native_irq_enable_sysexit)
|
||||
sti
|
||||
sysexit
|
||||
#endif
|
||||
|
||||
KPROBE_ENTRY(int3)
|
||||
RING0_INT_FRAME
|
||||
pushl $-1 # mark this as an int
|
||||
|
@ -949,26 +985,27 @@ ENTRY(arch_unwind_init_running)
|
|||
movl 4(%esp), %edx
|
||||
movl (%esp), %ecx
|
||||
leal 4(%esp), %eax
|
||||
movl %ebx, EBX(%edx)
|
||||
movl %ebx, PT_EBX(%edx)
|
||||
xorl %ebx, %ebx
|
||||
movl %ebx, ECX(%edx)
|
||||
movl %ebx, EDX(%edx)
|
||||
movl %esi, ESI(%edx)
|
||||
movl %edi, EDI(%edx)
|
||||
movl %ebp, EBP(%edx)
|
||||
movl %ebx, EAX(%edx)
|
||||
movl $__USER_DS, DS(%edx)
|
||||
movl $__USER_DS, ES(%edx)
|
||||
movl %ebx, ORIG_EAX(%edx)
|
||||
movl %ecx, EIP(%edx)
|
||||
movl %ebx, PT_ECX(%edx)
|
||||
movl %ebx, PT_EDX(%edx)
|
||||
movl %esi, PT_ESI(%edx)
|
||||
movl %edi, PT_EDI(%edx)
|
||||
movl %ebp, PT_EBP(%edx)
|
||||
movl %ebx, PT_EAX(%edx)
|
||||
movl $__USER_DS, PT_DS(%edx)
|
||||
movl $__USER_DS, PT_ES(%edx)
|
||||
movl $0, PT_GS(%edx)
|
||||
movl %ebx, PT_ORIG_EAX(%edx)
|
||||
movl %ecx, PT_EIP(%edx)
|
||||
movl 12(%esp), %ecx
|
||||
movl $__KERNEL_CS, CS(%edx)
|
||||
movl %ebx, EFLAGS(%edx)
|
||||
movl %eax, OLDESP(%edx)
|
||||
movl $__KERNEL_CS, PT_CS(%edx)
|
||||
movl %ebx, PT_EFLAGS(%edx)
|
||||
movl %eax, PT_OLDESP(%edx)
|
||||
movl 8(%esp), %eax
|
||||
movl %ecx, 8(%esp)
|
||||
movl EBX(%edx), %ebx
|
||||
movl $__KERNEL_DS, OLDSS(%edx)
|
||||
movl PT_EBX(%edx), %ebx
|
||||
movl $__KERNEL_DS, PT_OLDSS(%edx)
|
||||
jmpl *%eax
|
||||
CFI_ENDPROC
|
||||
ENDPROC(arch_unwind_init_running)
|
||||
|
|
|
@ -55,6 +55,12 @@
|
|||
*/
|
||||
ENTRY(startup_32)
|
||||
|
||||
#ifdef CONFIG_PARAVIRT
|
||||
movl %cs, %eax
|
||||
testl $0x3, %eax
|
||||
jnz startup_paravirt
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set segments to known values.
|
||||
*/
|
||||
|
@ -302,6 +308,7 @@ is386: movl $2,%ecx # set MP
|
|||
movl %eax,%cr0
|
||||
|
||||
call check_x87
|
||||
call setup_pda
|
||||
lgdt cpu_gdt_descr
|
||||
lidt idt_descr
|
||||
ljmp $(__KERNEL_CS),$1f
|
||||
|
@ -312,10 +319,13 @@ is386: movl $2,%ecx # set MP
|
|||
movl %eax,%ds
|
||||
movl %eax,%es
|
||||
|
||||
xorl %eax,%eax # Clear FS/GS and LDT
|
||||
xorl %eax,%eax # Clear FS and LDT
|
||||
movl %eax,%fs
|
||||
movl %eax,%gs
|
||||
lldt %ax
|
||||
|
||||
movl $(__KERNEL_PDA),%eax
|
||||
mov %eax,%gs
|
||||
|
||||
cld # gcc2 wants the direction flag cleared at all times
|
||||
pushl $0 # fake return address for unwinder
|
||||
#ifdef CONFIG_SMP
|
||||
|
@ -345,6 +355,23 @@ check_x87:
|
|||
.byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */
|
||||
ret
|
||||
|
||||
/*
|
||||
* Point the GDT at this CPU's PDA. On boot this will be
|
||||
* cpu_gdt_table and boot_pda; for secondary CPUs, these will be
|
||||
* that CPU's GDT and PDA.
|
||||
*/
|
||||
setup_pda:
|
||||
/* get the PDA pointer */
|
||||
movl start_pda, %eax
|
||||
|
||||
/* slot the PDA address into the GDT */
|
||||
mov cpu_gdt_descr+2, %ecx
|
||||
mov %ax, (__KERNEL_PDA+0+2)(%ecx) /* base & 0x0000ffff */
|
||||
shr $16, %eax
|
||||
mov %al, (__KERNEL_PDA+4+0)(%ecx) /* base & 0x00ff0000 */
|
||||
mov %ah, (__KERNEL_PDA+4+3)(%ecx) /* base & 0xff000000 */
|
||||
ret
|
||||
|
||||
/*
|
||||
* setup_idt
|
||||
*
|
||||
|
@ -465,6 +492,33 @@ ignore_int:
|
|||
#endif
|
||||
iret
|
||||
|
||||
#ifdef CONFIG_PARAVIRT
|
||||
startup_paravirt:
|
||||
cld
|
||||
movl $(init_thread_union+THREAD_SIZE),%esp
|
||||
|
||||
/* We take pains to preserve all the regs. */
|
||||
pushl %edx
|
||||
pushl %ecx
|
||||
pushl %eax
|
||||
|
||||
/* paravirt.o is last in link, and that probe fn never returns */
|
||||
pushl $__start_paravirtprobe
|
||||
1:
|
||||
movl 0(%esp), %eax
|
||||
pushl (%eax)
|
||||
movl 8(%esp), %eax
|
||||
call *(%esp)
|
||||
popl %eax
|
||||
|
||||
movl 4(%esp), %eax
|
||||
movl 8(%esp), %ecx
|
||||
movl 12(%esp), %edx
|
||||
|
||||
addl $4, (%esp)
|
||||
jmp 1b
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Real beginning of normal "text" segment
|
||||
*/
|
||||
|
@ -484,6 +538,8 @@ ENTRY(empty_zero_page)
|
|||
* This starts the data section.
|
||||
*/
|
||||
.data
|
||||
ENTRY(start_pda)
|
||||
.long boot_pda
|
||||
|
||||
ENTRY(stack_start)
|
||||
.long init_thread_union+THREAD_SIZE
|
||||
|
@ -525,7 +581,7 @@ idt_descr:
|
|||
|
||||
# boot GDT descriptor (later on used by CPU#0):
|
||||
.word 0 # 32 bit align gdt_desc.address
|
||||
cpu_gdt_descr:
|
||||
ENTRY(cpu_gdt_descr)
|
||||
.word GDT_ENTRIES*8-1
|
||||
.long cpu_gdt_table
|
||||
|
||||
|
@ -584,8 +640,8 @@ ENTRY(cpu_gdt_table)
|
|||
.quad 0x00009a000000ffff /* 0xc0 APM CS 16 code (16 bit) */
|
||||
.quad 0x004092000000ffff /* 0xc8 APM DS data */
|
||||
|
||||
.quad 0x0000920000000000 /* 0xd0 - ESPFIX 16-bit SS */
|
||||
.quad 0x0000000000000000 /* 0xd8 - unused */
|
||||
.quad 0x00c0920000000000 /* 0xd0 - ESPFIX SS */
|
||||
.quad 0x00cf92000000ffff /* 0xd8 - PDA */
|
||||
.quad 0x0000000000000000 /* 0xe0 - unused */
|
||||
.quad 0x0000000000000000 /* 0xe8 - unused */
|
||||
.quad 0x0000000000000000 /* 0xf0 - unused */
|
||||
|
|
|
@ -34,6 +34,7 @@ static int __init init_hpet_clocksource(void)
|
|||
unsigned long hpet_period;
|
||||
void __iomem* hpet_base;
|
||||
u64 tmp;
|
||||
int err;
|
||||
|
||||
if (!is_hpet_enabled())
|
||||
return -ENODEV;
|
||||
|
@ -61,7 +62,11 @@ static int __init init_hpet_clocksource(void)
|
|||
do_div(tmp, FSEC_PER_NSEC);
|
||||
clocksource_hpet.mult = (u32)tmp;
|
||||
|
||||
return clocksource_register(&clocksource_hpet);
|
||||
err = clocksource_register(&clocksource_hpet);
|
||||
if (err)
|
||||
iounmap(hpet_base);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
module_init(init_hpet_clocksource);
|
||||
|
|
|
@ -381,7 +381,10 @@ void __init init_ISA_irqs (void)
|
|||
}
|
||||
}
|
||||
|
||||
void __init init_IRQ(void)
|
||||
/* Overridden in paravirt.c */
|
||||
void init_IRQ(void) __attribute__((weak, alias("native_init_IRQ")));
|
||||
|
||||
void __init native_init_IRQ(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/htirq.h>
|
||||
#include <linux/freezer.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/smp.h>
|
||||
|
@ -153,14 +154,20 @@ static struct IO_APIC_route_entry ioapic_read_entry(int apic, int pin)
|
|||
* the interrupt, and we need to make sure the entry is fully populated
|
||||
* before that happens.
|
||||
*/
|
||||
static void
|
||||
__ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
|
||||
{
|
||||
union entry_union eu;
|
||||
eu.entry = e;
|
||||
io_apic_write(apic, 0x11 + 2*pin, eu.w2);
|
||||
io_apic_write(apic, 0x10 + 2*pin, eu.w1);
|
||||
}
|
||||
|
||||
static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
|
||||
{
|
||||
unsigned long flags;
|
||||
union entry_union eu;
|
||||
eu.entry = e;
|
||||
spin_lock_irqsave(&ioapic_lock, flags);
|
||||
io_apic_write(apic, 0x11 + 2*pin, eu.w2);
|
||||
io_apic_write(apic, 0x10 + 2*pin, eu.w1);
|
||||
__ioapic_write_entry(apic, pin, e);
|
||||
spin_unlock_irqrestore(&ioapic_lock, flags);
|
||||
}
|
||||
|
||||
|
@ -836,8 +843,7 @@ static int __init find_isa_irq_pin(int irq, int type)
|
|||
|
||||
if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA ||
|
||||
mp_bus_id_to_type[lbus] == MP_BUS_EISA ||
|
||||
mp_bus_id_to_type[lbus] == MP_BUS_MCA ||
|
||||
mp_bus_id_to_type[lbus] == MP_BUS_NEC98
|
||||
mp_bus_id_to_type[lbus] == MP_BUS_MCA
|
||||
) &&
|
||||
(mp_irqs[i].mpc_irqtype == type) &&
|
||||
(mp_irqs[i].mpc_srcbusirq == irq))
|
||||
|
@ -856,8 +862,7 @@ static int __init find_isa_irq_apic(int irq, int type)
|
|||
|
||||
if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA ||
|
||||
mp_bus_id_to_type[lbus] == MP_BUS_EISA ||
|
||||
mp_bus_id_to_type[lbus] == MP_BUS_MCA ||
|
||||
mp_bus_id_to_type[lbus] == MP_BUS_NEC98
|
||||
mp_bus_id_to_type[lbus] == MP_BUS_MCA
|
||||
) &&
|
||||
(mp_irqs[i].mpc_irqtype == type) &&
|
||||
(mp_irqs[i].mpc_srcbusirq == irq))
|
||||
|
@ -987,12 +992,6 @@ static int EISA_ELCR(unsigned int irq)
|
|||
#define default_MCA_trigger(idx) (1)
|
||||
#define default_MCA_polarity(idx) (0)
|
||||
|
||||
/* NEC98 interrupts are always polarity zero edge triggered,
|
||||
* when listed as conforming in the MP table. */
|
||||
|
||||
#define default_NEC98_trigger(idx) (0)
|
||||
#define default_NEC98_polarity(idx) (0)
|
||||
|
||||
static int __init MPBIOS_polarity(int idx)
|
||||
{
|
||||
int bus = mp_irqs[idx].mpc_srcbus;
|
||||
|
@ -1027,11 +1026,6 @@ static int __init MPBIOS_polarity(int idx)
|
|||
polarity = default_MCA_polarity(idx);
|
||||
break;
|
||||
}
|
||||
case MP_BUS_NEC98: /* NEC 98 pin */
|
||||
{
|
||||
polarity = default_NEC98_polarity(idx);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
printk(KERN_WARNING "broken BIOS!!\n");
|
||||
|
@ -1101,11 +1095,6 @@ static int MPBIOS_trigger(int idx)
|
|||
trigger = default_MCA_trigger(idx);
|
||||
break;
|
||||
}
|
||||
case MP_BUS_NEC98: /* NEC 98 pin */
|
||||
{
|
||||
trigger = default_NEC98_trigger(idx);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
printk(KERN_WARNING "broken BIOS!!\n");
|
||||
|
@ -1167,7 +1156,6 @@ static int pin_2_irq(int idx, int apic, int pin)
|
|||
case MP_BUS_ISA: /* ISA pin */
|
||||
case MP_BUS_EISA:
|
||||
case MP_BUS_MCA:
|
||||
case MP_BUS_NEC98:
|
||||
{
|
||||
irq = mp_irqs[idx].mpc_srcbusirq;
|
||||
break;
|
||||
|
@ -1235,7 +1223,7 @@ static inline int IO_APIC_irq_trigger(int irq)
|
|||
}
|
||||
|
||||
/* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
|
||||
u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 };
|
||||
static u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 };
|
||||
|
||||
static int __assign_irq_vector(int irq)
|
||||
{
|
||||
|
@ -1360,8 +1348,8 @@ static void __init setup_IO_APIC_irqs(void)
|
|||
if (!apic && (irq < 16))
|
||||
disable_8259A_irq(irq);
|
||||
}
|
||||
ioapic_write_entry(apic, pin, entry);
|
||||
spin_lock_irqsave(&ioapic_lock, flags);
|
||||
__ioapic_write_entry(apic, pin, entry);
|
||||
set_native_irq_info(irq, TARGET_CPUS);
|
||||
spin_unlock_irqrestore(&ioapic_lock, flags);
|
||||
}
|
||||
|
@ -1926,6 +1914,15 @@ static void __init setup_ioapic_ids_from_mpc(void)
|
|||
static void __init setup_ioapic_ids_from_mpc(void) { }
|
||||
#endif
|
||||
|
||||
static int no_timer_check __initdata;
|
||||
|
||||
static int __init notimercheck(char *s)
|
||||
{
|
||||
no_timer_check = 1;
|
||||
return 1;
|
||||
}
|
||||
__setup("no_timer_check", notimercheck);
|
||||
|
||||
/*
|
||||
* There is a nasty bug in some older SMP boards, their mptable lies
|
||||
* about the timer IRQ. We do the following to work around the situation:
|
||||
|
@ -1934,10 +1931,13 @@ static void __init setup_ioapic_ids_from_mpc(void) { }
|
|||
* - if this function detects that timer IRQs are defunct, then we fall
|
||||
* back to ISA timer IRQs
|
||||
*/
|
||||
static int __init timer_irq_works(void)
|
||||
int __init timer_irq_works(void)
|
||||
{
|
||||
unsigned long t1 = jiffies;
|
||||
|
||||
if (no_timer_check)
|
||||
return 1;
|
||||
|
||||
local_irq_enable();
|
||||
/* Let ten ticks pass... */
|
||||
mdelay((10 * 1000) / HZ);
|
||||
|
@ -2161,9 +2161,15 @@ static inline void unlock_ExtINT_logic(void)
|
|||
unsigned char save_control, save_freq_select;
|
||||
|
||||
pin = find_isa_irq_pin(8, mp_INT);
|
||||
apic = find_isa_irq_apic(8, mp_INT);
|
||||
if (pin == -1)
|
||||
if (pin == -1) {
|
||||
WARN_ON_ONCE(1);
|
||||
return;
|
||||
}
|
||||
apic = find_isa_irq_apic(8, mp_INT);
|
||||
if (apic == -1) {
|
||||
WARN_ON_ONCE(1);
|
||||
return;
|
||||
}
|
||||
|
||||
entry0 = ioapic_read_entry(apic, pin);
|
||||
clear_IO_APIC_pin(apic, pin);
|
||||
|
@ -2208,7 +2214,7 @@ int timer_uses_ioapic_pin_0;
|
|||
* is so screwy. Thanks to Brian Perkins for testing/hacking this beast
|
||||
* fanatically on his truly buggy board.
|
||||
*/
|
||||
static inline void check_timer(void)
|
||||
static inline void __init check_timer(void)
|
||||
{
|
||||
int apic1, pin1, apic2, pin2;
|
||||
int vector;
|
||||
|
@ -2856,8 +2862,8 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a
|
|||
if (!ioapic && (irq < 16))
|
||||
disable_8259A_irq(irq);
|
||||
|
||||
ioapic_write_entry(ioapic, pin, entry);
|
||||
spin_lock_irqsave(&ioapic_lock, flags);
|
||||
__ioapic_write_entry(ioapic, pin, entry);
|
||||
set_native_irq_info(irq, TARGET_CPUS);
|
||||
spin_unlock_irqrestore(&ioapic_lock, flags);
|
||||
|
||||
|
|
|
@ -184,7 +184,7 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p)
|
|||
void __kprobes arch_remove_kprobe(struct kprobe *p)
|
||||
{
|
||||
mutex_lock(&kprobe_mutex);
|
||||
free_insn_slot(p->ainsn.insn);
|
||||
free_insn_slot(p->ainsn.insn, (p->ainsn.boostable == 1));
|
||||
mutex_unlock(&kprobe_mutex);
|
||||
}
|
||||
|
||||
|
@ -333,7 +333,7 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
|
|||
return 1;
|
||||
|
||||
ss_probe:
|
||||
#ifndef CONFIG_PREEMPT
|
||||
#if !defined(CONFIG_PREEMPT) || defined(CONFIG_PM)
|
||||
if (p->ainsn.boostable == 1 && !p->post_handler){
|
||||
/* Boost up -- we can execute copied instructions directly */
|
||||
reset_current_kprobe();
|
||||
|
|
|
@ -160,16 +160,14 @@ static int read_default_ldt(void __user * ptr, unsigned long bytecount)
|
|||
{
|
||||
int err;
|
||||
unsigned long size;
|
||||
void *address;
|
||||
|
||||
err = 0;
|
||||
address = &default_ldt[0];
|
||||
size = 5*sizeof(struct desc_struct);
|
||||
if (size > bytecount)
|
||||
size = bytecount;
|
||||
|
||||
err = size;
|
||||
if (copy_to_user(ptr, address, size))
|
||||
if (clear_user(ptr, size))
|
||||
err = -EFAULT;
|
||||
|
||||
return err;
|
||||
|
|
|
@ -283,10 +283,9 @@ static int __init mca_init(void)
|
|||
bus->f.mca_transform_memory = mca_dummy_transform_memory;
|
||||
|
||||
/* get the motherboard device */
|
||||
mca_dev = kmalloc(sizeof(struct mca_device), GFP_KERNEL);
|
||||
mca_dev = kzalloc(sizeof(struct mca_device), GFP_KERNEL);
|
||||
if(unlikely(!mca_dev))
|
||||
goto out_nomem;
|
||||
memset(mca_dev, 0, sizeof(struct mca_device));
|
||||
|
||||
/*
|
||||
* We do not expect many MCA interrupts during initialization,
|
||||
|
@ -310,11 +309,9 @@ static int __init mca_init(void)
|
|||
mca_dev->slot = MCA_MOTHERBOARD;
|
||||
mca_register_device(MCA_PRIMARY_BUS, mca_dev);
|
||||
|
||||
mca_dev = kmalloc(sizeof(struct mca_device), GFP_ATOMIC);
|
||||
mca_dev = kzalloc(sizeof(struct mca_device), GFP_ATOMIC);
|
||||
if(unlikely(!mca_dev))
|
||||
goto out_unlock_nomem;
|
||||
memset(mca_dev, 0, sizeof(struct mca_device));
|
||||
|
||||
|
||||
/* Put motherboard into video setup mode, read integrated video
|
||||
* POS registers, and turn motherboard setup off.
|
||||
|
@ -349,10 +346,9 @@ static int __init mca_init(void)
|
|||
}
|
||||
if(which_scsi) {
|
||||
/* found a scsi card */
|
||||
mca_dev = kmalloc(sizeof(struct mca_device), GFP_ATOMIC);
|
||||
mca_dev = kzalloc(sizeof(struct mca_device), GFP_ATOMIC);
|
||||
if(unlikely(!mca_dev))
|
||||
goto out_unlock_nomem;
|
||||
memset(mca_dev, 0, sizeof(struct mca_device));
|
||||
|
||||
for(j = 0; j < 8; j++)
|
||||
mca_dev->pos[j] = pos[j];
|
||||
|
@ -378,10 +374,9 @@ static int __init mca_init(void)
|
|||
if(!mca_read_and_store_pos(pos))
|
||||
continue;
|
||||
|
||||
mca_dev = kmalloc(sizeof(struct mca_device), GFP_ATOMIC);
|
||||
mca_dev = kzalloc(sizeof(struct mca_device), GFP_ATOMIC);
|
||||
if(unlikely(!mca_dev))
|
||||
goto out_unlock_nomem;
|
||||
memset(mca_dev, 0, sizeof(struct mca_device));
|
||||
|
||||
for(j=0; j<8; j++)
|
||||
mca_dev->pos[j]=pos[j];
|
||||
|
|
|
@ -703,7 +703,6 @@ static struct sysdev_driver mc_sysdev_driver = {
|
|||
.resume = mc_sysdev_resume,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
static __cpuinit int
|
||||
mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
|
||||
{
|
||||
|
@ -726,7 +725,6 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
|
|||
static struct notifier_block mc_cpu_notifier = {
|
||||
.notifier_call = mc_cpu_callback,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int __init microcode_init (void)
|
||||
{
|
||||
|
|
|
@ -108,7 +108,8 @@ int module_finalize(const Elf_Ehdr *hdr,
|
|||
const Elf_Shdr *sechdrs,
|
||||
struct module *me)
|
||||
{
|
||||
const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL;
|
||||
const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL,
|
||||
*para = NULL;
|
||||
char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
|
||||
|
||||
for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
|
||||
|
@ -118,6 +119,8 @@ int module_finalize(const Elf_Ehdr *hdr,
|
|||
alt = s;
|
||||
if (!strcmp(".smp_locks", secstrings + s->sh_name))
|
||||
locks= s;
|
||||
if (!strcmp(".parainstructions", secstrings + s->sh_name))
|
||||
para = s;
|
||||
}
|
||||
|
||||
if (alt) {
|
||||
|
@ -132,6 +135,12 @@ int module_finalize(const Elf_Ehdr *hdr,
|
|||
lseg, lseg + locks->sh_size,
|
||||
tseg, tseg + text->sh_size);
|
||||
}
|
||||
|
||||
if (para) {
|
||||
void *pseg = (void *)para->sh_addr;
|
||||
apply_paravirt(pseg, pseg + para->sh_size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -249,8 +249,6 @@ static void __init MP_bus_info (struct mpc_config_bus *m)
|
|||
mp_current_pci_id++;
|
||||
} else if (strncmp(str, BUSTYPE_MCA, sizeof(BUSTYPE_MCA)-1) == 0) {
|
||||
mp_bus_id_to_type[m->mpc_busid] = MP_BUS_MCA;
|
||||
} else if (strncmp(str, BUSTYPE_NEC98, sizeof(BUSTYPE_NEC98)-1) == 0) {
|
||||
mp_bus_id_to_type[m->mpc_busid] = MP_BUS_NEC98;
|
||||
} else {
|
||||
printk(KERN_WARNING "Unknown bustype %s - ignoring\n", str);
|
||||
}
|
||||
|
|
|
@ -195,7 +195,6 @@ static ssize_t msr_write(struct file *file, const char __user *buf,
|
|||
{
|
||||
const u32 __user *tmp = (const u32 __user *)buf;
|
||||
u32 data[2];
|
||||
size_t rv;
|
||||
u32 reg = *ppos;
|
||||
int cpu = iminor(file->f_dentry->d_inode);
|
||||
int err;
|
||||
|
@ -203,7 +202,7 @@ static ssize_t msr_write(struct file *file, const char __user *buf,
|
|||
if (count % 8)
|
||||
return -EINVAL; /* Invalid chunk size */
|
||||
|
||||
for (rv = 0; count; count -= 8) {
|
||||
for (; count; count -= 8) {
|
||||
if (copy_from_user(&data, tmp, 8))
|
||||
return -EFAULT;
|
||||
err = do_wrmsr(cpu, reg, data[0], data[1]);
|
||||
|
@ -250,7 +249,6 @@ static int msr_device_create(int i)
|
|||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
static int msr_class_cpu_callback(struct notifier_block *nfb,
|
||||
unsigned long action, void *hcpu)
|
||||
{
|
||||
|
@ -271,7 +269,6 @@ static struct notifier_block __cpuinitdata msr_class_cpu_notifier =
|
|||
{
|
||||
.notifier_call = msr_class_cpu_callback,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int __init msr_init(void)
|
||||
{
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/percpu.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/kprobes.h>
|
||||
#include <linux/cpumask.h>
|
||||
|
||||
#include <asm/smp.h>
|
||||
#include <asm/nmi.h>
|
||||
|
@ -42,6 +43,8 @@ int nmi_watchdog_enabled;
|
|||
static DEFINE_PER_CPU(unsigned long, perfctr_nmi_owner);
|
||||
static DEFINE_PER_CPU(unsigned long, evntsel_nmi_owner[3]);
|
||||
|
||||
static cpumask_t backtrace_mask = CPU_MASK_NONE;
|
||||
|
||||
/* this number is calculated from Intel's MSR_P4_CRU_ESCR5 register and it's
|
||||
* offset from MSR_P4_BSU_ESCR0. It will be the max for all platforms (for now)
|
||||
*/
|
||||
|
@ -867,14 +870,16 @@ static unsigned int
|
|||
|
||||
void touch_nmi_watchdog (void)
|
||||
{
|
||||
int i;
|
||||
if (nmi_watchdog > 0) {
|
||||
unsigned cpu;
|
||||
|
||||
/*
|
||||
* Just reset the alert counters, (other CPUs might be
|
||||
* spinning on locks we hold):
|
||||
*/
|
||||
for_each_possible_cpu(i)
|
||||
alert_counter[i] = 0;
|
||||
/*
|
||||
* Just reset the alert counters, (other CPUs might be
|
||||
* spinning on locks we hold):
|
||||
*/
|
||||
for_each_present_cpu (cpu)
|
||||
alert_counter[cpu] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tickle the softlockup detector too:
|
||||
|
@ -907,6 +912,16 @@ __kprobes int nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
|
|||
touched = 1;
|
||||
}
|
||||
|
||||
if (cpu_isset(cpu, backtrace_mask)) {
|
||||
static DEFINE_SPINLOCK(lock); /* Serialise the printks */
|
||||
|
||||
spin_lock(&lock);
|
||||
printk("NMI backtrace for cpu %d\n", cpu);
|
||||
dump_stack();
|
||||
spin_unlock(&lock);
|
||||
cpu_clear(cpu, backtrace_mask);
|
||||
}
|
||||
|
||||
sum = per_cpu(irq_stat, cpu).apic_timer_irqs;
|
||||
|
||||
/* if the apic timer isn't firing, this cpu isn't doing much */
|
||||
|
@ -1033,6 +1048,19 @@ int proc_nmi_enabled(struct ctl_table *table, int write, struct file *file,
|
|||
|
||||
#endif
|
||||
|
||||
void __trigger_all_cpu_backtrace(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
backtrace_mask = cpu_online_map;
|
||||
/* Wait for up to 10 seconds for all CPUs to do the backtrace */
|
||||
for (i = 0; i < 10 * 1000; i++) {
|
||||
if (cpus_empty(backtrace_mask))
|
||||
break;
|
||||
mdelay(1);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(nmi_active);
|
||||
EXPORT_SYMBOL(nmi_watchdog);
|
||||
EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi);
|
||||
|
|
|
@ -0,0 +1,569 @@
|
|||
/* Paravirtualization interfaces
|
||||
Copyright (C) 2006 Rusty Russell IBM Corporation
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <linux/errno.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/start_kernel.h>
|
||||
|
||||
#include <asm/bug.h>
|
||||
#include <asm/paravirt.h>
|
||||
#include <asm/desc.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/arch_hooks.h>
|
||||
#include <asm/time.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/delay.h>
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/apic.h>
|
||||
#include <asm/tlbflush.h>
|
||||
|
||||
/* nop stub */
|
||||
static void native_nop(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void __init default_banner(void)
|
||||
{
|
||||
printk(KERN_INFO "Booting paravirtualized kernel on %s\n",
|
||||
paravirt_ops.name);
|
||||
}
|
||||
|
||||
char *memory_setup(void)
|
||||
{
|
||||
return paravirt_ops.memory_setup();
|
||||
}
|
||||
|
||||
/* Simple instruction patching code. */
|
||||
#define DEF_NATIVE(name, code) \
|
||||
extern const char start_##name[], end_##name[]; \
|
||||
asm("start_" #name ": " code "; end_" #name ":")
|
||||
DEF_NATIVE(cli, "cli");
|
||||
DEF_NATIVE(sti, "sti");
|
||||
DEF_NATIVE(popf, "push %eax; popf");
|
||||
DEF_NATIVE(pushf, "pushf; pop %eax");
|
||||
DEF_NATIVE(pushf_cli, "pushf; pop %eax; cli");
|
||||
DEF_NATIVE(iret, "iret");
|
||||
DEF_NATIVE(sti_sysexit, "sti; sysexit");
|
||||
|
||||
static const struct native_insns
|
||||
{
|
||||
const char *start, *end;
|
||||
} native_insns[] = {
|
||||
[PARAVIRT_IRQ_DISABLE] = { start_cli, end_cli },
|
||||
[PARAVIRT_IRQ_ENABLE] = { start_sti, end_sti },
|
||||
[PARAVIRT_RESTORE_FLAGS] = { start_popf, end_popf },
|
||||
[PARAVIRT_SAVE_FLAGS] = { start_pushf, end_pushf },
|
||||
[PARAVIRT_SAVE_FLAGS_IRQ_DISABLE] = { start_pushf_cli, end_pushf_cli },
|
||||
[PARAVIRT_INTERRUPT_RETURN] = { start_iret, end_iret },
|
||||
[PARAVIRT_STI_SYSEXIT] = { start_sti_sysexit, end_sti_sysexit },
|
||||
};
|
||||
|
||||
static unsigned native_patch(u8 type, u16 clobbers, void *insns, unsigned len)
|
||||
{
|
||||
unsigned int insn_len;
|
||||
|
||||
/* Don't touch it if we don't have a replacement */
|
||||
if (type >= ARRAY_SIZE(native_insns) || !native_insns[type].start)
|
||||
return len;
|
||||
|
||||
insn_len = native_insns[type].end - native_insns[type].start;
|
||||
|
||||
/* Similarly if we can't fit replacement. */
|
||||
if (len < insn_len)
|
||||
return len;
|
||||
|
||||
memcpy(insns, native_insns[type].start, insn_len);
|
||||
return insn_len;
|
||||
}
|
||||
|
||||
static fastcall unsigned long native_get_debugreg(int regno)
|
||||
{
|
||||
unsigned long val = 0; /* Damn you, gcc! */
|
||||
|
||||
switch (regno) {
|
||||
case 0:
|
||||
asm("movl %%db0, %0" :"=r" (val)); break;
|
||||
case 1:
|
||||
asm("movl %%db1, %0" :"=r" (val)); break;
|
||||
case 2:
|
||||
asm("movl %%db2, %0" :"=r" (val)); break;
|
||||
case 3:
|
||||
asm("movl %%db3, %0" :"=r" (val)); break;
|
||||
case 6:
|
||||
asm("movl %%db6, %0" :"=r" (val)); break;
|
||||
case 7:
|
||||
asm("movl %%db7, %0" :"=r" (val)); break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static fastcall void native_set_debugreg(int regno, unsigned long value)
|
||||
{
|
||||
switch (regno) {
|
||||
case 0:
|
||||
asm("movl %0,%%db0" : /* no output */ :"r" (value));
|
||||
break;
|
||||
case 1:
|
||||
asm("movl %0,%%db1" : /* no output */ :"r" (value));
|
||||
break;
|
||||
case 2:
|
||||
asm("movl %0,%%db2" : /* no output */ :"r" (value));
|
||||
break;
|
||||
case 3:
|
||||
asm("movl %0,%%db3" : /* no output */ :"r" (value));
|
||||
break;
|
||||
case 6:
|
||||
asm("movl %0,%%db6" : /* no output */ :"r" (value));
|
||||
break;
|
||||
case 7:
|
||||
asm("movl %0,%%db7" : /* no output */ :"r" (value));
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
void init_IRQ(void)
|
||||
{
|
||||
paravirt_ops.init_IRQ();
|
||||
}
|
||||
|
||||
static fastcall void native_clts(void)
|
||||
{
|
||||
asm volatile ("clts");
|
||||
}
|
||||
|
||||
static fastcall unsigned long native_read_cr0(void)
|
||||
{
|
||||
unsigned long val;
|
||||
asm volatile("movl %%cr0,%0\n\t" :"=r" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
static fastcall void native_write_cr0(unsigned long val)
|
||||
{
|
||||
asm volatile("movl %0,%%cr0": :"r" (val));
|
||||
}
|
||||
|
||||
static fastcall unsigned long native_read_cr2(void)
|
||||
{
|
||||
unsigned long val;
|
||||
asm volatile("movl %%cr2,%0\n\t" :"=r" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
static fastcall void native_write_cr2(unsigned long val)
|
||||
{
|
||||
asm volatile("movl %0,%%cr2": :"r" (val));
|
||||
}
|
||||
|
||||
static fastcall unsigned long native_read_cr3(void)
|
||||
{
|
||||
unsigned long val;
|
||||
asm volatile("movl %%cr3,%0\n\t" :"=r" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
static fastcall void native_write_cr3(unsigned long val)
|
||||
{
|
||||
asm volatile("movl %0,%%cr3": :"r" (val));
|
||||
}
|
||||
|
||||
static fastcall unsigned long native_read_cr4(void)
|
||||
{
|
||||
unsigned long val;
|
||||
asm volatile("movl %%cr4,%0\n\t" :"=r" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
static fastcall unsigned long native_read_cr4_safe(void)
|
||||
{
|
||||
unsigned long val;
|
||||
/* This could fault if %cr4 does not exist */
|
||||
asm("1: movl %%cr4, %0 \n"
|
||||
"2: \n"
|
||||
".section __ex_table,\"a\" \n"
|
||||
".long 1b,2b \n"
|
||||
".previous \n"
|
||||
: "=r" (val): "0" (0));
|
||||
return val;
|
||||
}
|
||||
|
||||
static fastcall void native_write_cr4(unsigned long val)
|
||||
{
|
||||
asm volatile("movl %0,%%cr4": :"r" (val));
|
||||
}
|
||||
|
||||
static fastcall unsigned long native_save_fl(void)
|
||||
{
|
||||
unsigned long f;
|
||||
asm volatile("pushfl ; popl %0":"=g" (f): /* no input */);
|
||||
return f;
|
||||
}
|
||||
|
||||
static fastcall void native_restore_fl(unsigned long f)
|
||||
{
|
||||
asm volatile("pushl %0 ; popfl": /* no output */
|
||||
:"g" (f)
|
||||
:"memory", "cc");
|
||||
}
|
||||
|
||||
static fastcall void native_irq_disable(void)
|
||||
{
|
||||
asm volatile("cli": : :"memory");
|
||||
}
|
||||
|
||||
static fastcall void native_irq_enable(void)
|
||||
{
|
||||
asm volatile("sti": : :"memory");
|
||||
}
|
||||
|
||||
static fastcall void native_safe_halt(void)
|
||||
{
|
||||
asm volatile("sti; hlt": : :"memory");
|
||||
}
|
||||
|
||||
static fastcall void native_halt(void)
|
||||
{
|
||||
asm volatile("hlt": : :"memory");
|
||||
}
|
||||
|
||||
static fastcall void native_wbinvd(void)
|
||||
{
|
||||
asm volatile("wbinvd": : :"memory");
|
||||
}
|
||||
|
||||
static fastcall unsigned long long native_read_msr(unsigned int msr, int *err)
|
||||
{
|
||||
unsigned long long val;
|
||||
|
||||
asm volatile("2: rdmsr ; xorl %0,%0\n"
|
||||
"1:\n\t"
|
||||
".section .fixup,\"ax\"\n\t"
|
||||
"3: movl %3,%0 ; jmp 1b\n\t"
|
||||
".previous\n\t"
|
||||
".section __ex_table,\"a\"\n"
|
||||
" .align 4\n\t"
|
||||
" .long 2b,3b\n\t"
|
||||
".previous"
|
||||
: "=r" (*err), "=A" (val)
|
||||
: "c" (msr), "i" (-EFAULT));
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static fastcall int native_write_msr(unsigned int msr, unsigned long long val)
|
||||
{
|
||||
int err;
|
||||
asm volatile("2: wrmsr ; xorl %0,%0\n"
|
||||
"1:\n\t"
|
||||
".section .fixup,\"ax\"\n\t"
|
||||
"3: movl %4,%0 ; jmp 1b\n\t"
|
||||
".previous\n\t"
|
||||
".section __ex_table,\"a\"\n"
|
||||
" .align 4\n\t"
|
||||
" .long 2b,3b\n\t"
|
||||
".previous"
|
||||
: "=a" (err)
|
||||
: "c" (msr), "0" ((u32)val), "d" ((u32)(val>>32)),
|
||||
"i" (-EFAULT));
|
||||
return err;
|
||||
}
|
||||
|
||||
static fastcall unsigned long long native_read_tsc(void)
|
||||
{
|
||||
unsigned long long val;
|
||||
asm volatile("rdtsc" : "=A" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
static fastcall unsigned long long native_read_pmc(void)
|
||||
{
|
||||
unsigned long long val;
|
||||
asm volatile("rdpmc" : "=A" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
static fastcall void native_load_tr_desc(void)
|
||||
{
|
||||
asm volatile("ltr %w0"::"q" (GDT_ENTRY_TSS*8));
|
||||
}
|
||||
|
||||
static fastcall void native_load_gdt(const struct Xgt_desc_struct *dtr)
|
||||
{
|
||||
asm volatile("lgdt %0"::"m" (*dtr));
|
||||
}
|
||||
|
||||
static fastcall void native_load_idt(const struct Xgt_desc_struct *dtr)
|
||||
{
|
||||
asm volatile("lidt %0"::"m" (*dtr));
|
||||
}
|
||||
|
||||
static fastcall void native_store_gdt(struct Xgt_desc_struct *dtr)
|
||||
{
|
||||
asm ("sgdt %0":"=m" (*dtr));
|
||||
}
|
||||
|
||||
static fastcall void native_store_idt(struct Xgt_desc_struct *dtr)
|
||||
{
|
||||
asm ("sidt %0":"=m" (*dtr));
|
||||
}
|
||||
|
||||
static fastcall unsigned long native_store_tr(void)
|
||||
{
|
||||
unsigned long tr;
|
||||
asm ("str %0":"=r" (tr));
|
||||
return tr;
|
||||
}
|
||||
|
||||
static fastcall void native_load_tls(struct thread_struct *t, unsigned int cpu)
|
||||
{
|
||||
#define C(i) get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i]
|
||||
C(0); C(1); C(2);
|
||||
#undef C
|
||||
}
|
||||
|
||||
static inline void native_write_dt_entry(void *dt, int entry, u32 entry_low, u32 entry_high)
|
||||
{
|
||||
u32 *lp = (u32 *)((char *)dt + entry*8);
|
||||
lp[0] = entry_low;
|
||||
lp[1] = entry_high;
|
||||
}
|
||||
|
||||
static fastcall void native_write_ldt_entry(void *dt, int entrynum, u32 low, u32 high)
|
||||
{
|
||||
native_write_dt_entry(dt, entrynum, low, high);
|
||||
}
|
||||
|
||||
static fastcall void native_write_gdt_entry(void *dt, int entrynum, u32 low, u32 high)
|
||||
{
|
||||
native_write_dt_entry(dt, entrynum, low, high);
|
||||
}
|
||||
|
||||
static fastcall void native_write_idt_entry(void *dt, int entrynum, u32 low, u32 high)
|
||||
{
|
||||
native_write_dt_entry(dt, entrynum, low, high);
|
||||
}
|
||||
|
||||
static fastcall void native_load_esp0(struct tss_struct *tss,
|
||||
struct thread_struct *thread)
|
||||
{
|
||||
tss->esp0 = thread->esp0;
|
||||
|
||||
/* This can only happen when SEP is enabled, no need to test "SEP"arately */
|
||||
if (unlikely(tss->ss1 != thread->sysenter_cs)) {
|
||||
tss->ss1 = thread->sysenter_cs;
|
||||
wrmsr(MSR_IA32_SYSENTER_CS, thread->sysenter_cs, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static fastcall void native_io_delay(void)
|
||||
{
|
||||
asm volatile("outb %al,$0x80");
|
||||
}
|
||||
|
||||
static fastcall void native_flush_tlb(void)
|
||||
{
|
||||
__native_flush_tlb();
|
||||
}
|
||||
|
||||
/*
|
||||
* Global pages have to be flushed a bit differently. Not a real
|
||||
* performance problem because this does not happen often.
|
||||
*/
|
||||
static fastcall void native_flush_tlb_global(void)
|
||||
{
|
||||
__native_flush_tlb_global();
|
||||
}
|
||||
|
||||
static fastcall void native_flush_tlb_single(u32 addr)
|
||||
{
|
||||
__native_flush_tlb_single(addr);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_X86_PAE
|
||||
static fastcall void native_set_pte(pte_t *ptep, pte_t pteval)
|
||||
{
|
||||
*ptep = pteval;
|
||||
}
|
||||
|
||||
static fastcall void native_set_pte_at(struct mm_struct *mm, u32 addr, pte_t *ptep, pte_t pteval)
|
||||
{
|
||||
*ptep = pteval;
|
||||
}
|
||||
|
||||
static fastcall void native_set_pmd(pmd_t *pmdp, pmd_t pmdval)
|
||||
{
|
||||
*pmdp = pmdval;
|
||||
}
|
||||
|
||||
#else /* CONFIG_X86_PAE */
|
||||
|
||||
static fastcall void native_set_pte(pte_t *ptep, pte_t pte)
|
||||
{
|
||||
ptep->pte_high = pte.pte_high;
|
||||
smp_wmb();
|
||||
ptep->pte_low = pte.pte_low;
|
||||
}
|
||||
|
||||
static fastcall void native_set_pte_at(struct mm_struct *mm, u32 addr, pte_t *ptep, pte_t pte)
|
||||
{
|
||||
ptep->pte_high = pte.pte_high;
|
||||
smp_wmb();
|
||||
ptep->pte_low = pte.pte_low;
|
||||
}
|
||||
|
||||
static fastcall void native_set_pte_present(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte)
|
||||
{
|
||||
ptep->pte_low = 0;
|
||||
smp_wmb();
|
||||
ptep->pte_high = pte.pte_high;
|
||||
smp_wmb();
|
||||
ptep->pte_low = pte.pte_low;
|
||||
}
|
||||
|
||||
static fastcall void native_set_pte_atomic(pte_t *ptep, pte_t pteval)
|
||||
{
|
||||
set_64bit((unsigned long long *)ptep,pte_val(pteval));
|
||||
}
|
||||
|
||||
static fastcall void native_set_pmd(pmd_t *pmdp, pmd_t pmdval)
|
||||
{
|
||||
set_64bit((unsigned long long *)pmdp,pmd_val(pmdval));
|
||||
}
|
||||
|
||||
static fastcall void native_set_pud(pud_t *pudp, pud_t pudval)
|
||||
{
|
||||
*pudp = pudval;
|
||||
}
|
||||
|
||||
static fastcall void native_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
|
||||
{
|
||||
ptep->pte_low = 0;
|
||||
smp_wmb();
|
||||
ptep->pte_high = 0;
|
||||
}
|
||||
|
||||
static fastcall void native_pmd_clear(pmd_t *pmd)
|
||||
{
|
||||
u32 *tmp = (u32 *)pmd;
|
||||
*tmp = 0;
|
||||
smp_wmb();
|
||||
*(tmp + 1) = 0;
|
||||
}
|
||||
#endif /* CONFIG_X86_PAE */
|
||||
|
||||
/* These are in entry.S */
|
||||
extern fastcall void native_iret(void);
|
||||
extern fastcall void native_irq_enable_sysexit(void);
|
||||
|
||||
static int __init print_banner(void)
|
||||
{
|
||||
paravirt_ops.banner();
|
||||
return 0;
|
||||
}
|
||||
core_initcall(print_banner);
|
||||
|
||||
/* We simply declare start_kernel to be the paravirt probe of last resort. */
|
||||
paravirt_probe(start_kernel);
|
||||
|
||||
struct paravirt_ops paravirt_ops = {
|
||||
.name = "bare hardware",
|
||||
.paravirt_enabled = 0,
|
||||
.kernel_rpl = 0,
|
||||
|
||||
.patch = native_patch,
|
||||
.banner = default_banner,
|
||||
.arch_setup = native_nop,
|
||||
.memory_setup = machine_specific_memory_setup,
|
||||
.get_wallclock = native_get_wallclock,
|
||||
.set_wallclock = native_set_wallclock,
|
||||
.time_init = time_init_hook,
|
||||
.init_IRQ = native_init_IRQ,
|
||||
|
||||
.cpuid = native_cpuid,
|
||||
.get_debugreg = native_get_debugreg,
|
||||
.set_debugreg = native_set_debugreg,
|
||||
.clts = native_clts,
|
||||
.read_cr0 = native_read_cr0,
|
||||
.write_cr0 = native_write_cr0,
|
||||
.read_cr2 = native_read_cr2,
|
||||
.write_cr2 = native_write_cr2,
|
||||
.read_cr3 = native_read_cr3,
|
||||
.write_cr3 = native_write_cr3,
|
||||
.read_cr4 = native_read_cr4,
|
||||
.read_cr4_safe = native_read_cr4_safe,
|
||||
.write_cr4 = native_write_cr4,
|
||||
.save_fl = native_save_fl,
|
||||
.restore_fl = native_restore_fl,
|
||||
.irq_disable = native_irq_disable,
|
||||
.irq_enable = native_irq_enable,
|
||||
.safe_halt = native_safe_halt,
|
||||
.halt = native_halt,
|
||||
.wbinvd = native_wbinvd,
|
||||
.read_msr = native_read_msr,
|
||||
.write_msr = native_write_msr,
|
||||
.read_tsc = native_read_tsc,
|
||||
.read_pmc = native_read_pmc,
|
||||
.load_tr_desc = native_load_tr_desc,
|
||||
.set_ldt = native_set_ldt,
|
||||
.load_gdt = native_load_gdt,
|
||||
.load_idt = native_load_idt,
|
||||
.store_gdt = native_store_gdt,
|
||||
.store_idt = native_store_idt,
|
||||
.store_tr = native_store_tr,
|
||||
.load_tls = native_load_tls,
|
||||
.write_ldt_entry = native_write_ldt_entry,
|
||||
.write_gdt_entry = native_write_gdt_entry,
|
||||
.write_idt_entry = native_write_idt_entry,
|
||||
.load_esp0 = native_load_esp0,
|
||||
|
||||
.set_iopl_mask = native_set_iopl_mask,
|
||||
.io_delay = native_io_delay,
|
||||
.const_udelay = __const_udelay,
|
||||
|
||||
#ifdef CONFIG_X86_LOCAL_APIC
|
||||
.apic_write = native_apic_write,
|
||||
.apic_write_atomic = native_apic_write_atomic,
|
||||
.apic_read = native_apic_read,
|
||||
#endif
|
||||
|
||||
.flush_tlb_user = native_flush_tlb,
|
||||
.flush_tlb_kernel = native_flush_tlb_global,
|
||||
.flush_tlb_single = native_flush_tlb_single,
|
||||
|
||||
.set_pte = native_set_pte,
|
||||
.set_pte_at = native_set_pte_at,
|
||||
.set_pmd = native_set_pmd,
|
||||
.pte_update = (void *)native_nop,
|
||||
.pte_update_defer = (void *)native_nop,
|
||||
#ifdef CONFIG_X86_PAE
|
||||
.set_pte_atomic = native_set_pte_atomic,
|
||||
.set_pte_present = native_set_pte_present,
|
||||
.set_pud = native_set_pud,
|
||||
.pte_clear = native_pte_clear,
|
||||
.pmd_clear = native_pmd_clear,
|
||||
#endif
|
||||
|
||||
.irq_enable_sysexit = native_irq_enable_sysexit,
|
||||
.iret = native_iret,
|
||||
};
|
||||
EXPORT_SYMBOL(paravirt_ops);
|
|
@ -92,14 +92,12 @@ int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
|
|||
if (!mem_base)
|
||||
goto out;
|
||||
|
||||
dev->dma_mem = kmalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
|
||||
dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
|
||||
if (!dev->dma_mem)
|
||||
goto out;
|
||||
memset(dev->dma_mem, 0, sizeof(struct dma_coherent_mem));
|
||||
dev->dma_mem->bitmap = kmalloc(bitmap_size, GFP_KERNEL);
|
||||
dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
|
||||
if (!dev->dma_mem->bitmap)
|
||||
goto free1_out;
|
||||
memset(dev->dma_mem->bitmap, 0, bitmap_size);
|
||||
|
||||
dev->dma_mem->virt_base = mem_base;
|
||||
dev->dma_mem->device_base = device_addr;
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/pda.h>
|
||||
|
||||
asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
|
||||
|
||||
|
@ -99,22 +100,18 @@ EXPORT_SYMBOL(enable_hlt);
|
|||
*/
|
||||
void default_idle(void)
|
||||
{
|
||||
local_irq_enable();
|
||||
|
||||
if (!hlt_counter && boot_cpu_data.hlt_works_ok) {
|
||||
current_thread_info()->status &= ~TS_POLLING;
|
||||
smp_mb__after_clear_bit();
|
||||
while (!need_resched()) {
|
||||
local_irq_disable();
|
||||
if (!need_resched())
|
||||
safe_halt();
|
||||
else
|
||||
local_irq_enable();
|
||||
}
|
||||
local_irq_disable();
|
||||
if (!need_resched())
|
||||
safe_halt(); /* enables interrupts racelessly */
|
||||
else
|
||||
local_irq_enable();
|
||||
current_thread_info()->status |= TS_POLLING;
|
||||
} else {
|
||||
while (!need_resched())
|
||||
cpu_relax();
|
||||
/* loop is done by the caller */
|
||||
cpu_relax();
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_APM_MODULE
|
||||
|
@ -128,14 +125,7 @@ EXPORT_SYMBOL(default_idle);
|
|||
*/
|
||||
static void poll_idle (void)
|
||||
{
|
||||
local_irq_enable();
|
||||
|
||||
asm volatile(
|
||||
"2:"
|
||||
"testl %0, %1;"
|
||||
"rep; nop;"
|
||||
"je 2b;"
|
||||
: : "i"(_TIF_NEED_RESCHED), "m" (current_thread_info()->flags));
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
|
@ -256,8 +246,7 @@ void mwait_idle_with_hints(unsigned long eax, unsigned long ecx)
|
|||
static void mwait_idle(void)
|
||||
{
|
||||
local_irq_enable();
|
||||
while (!need_resched())
|
||||
mwait_idle_with_hints(0, 0);
|
||||
mwait_idle_with_hints(0, 0);
|
||||
}
|
||||
|
||||
void __devinit select_idle_routine(const struct cpuinfo_x86 *c)
|
||||
|
@ -314,8 +303,8 @@ void show_regs(struct pt_regs * regs)
|
|||
regs->eax,regs->ebx,regs->ecx,regs->edx);
|
||||
printk("ESI: %08lx EDI: %08lx EBP: %08lx",
|
||||
regs->esi, regs->edi, regs->ebp);
|
||||
printk(" DS: %04x ES: %04x\n",
|
||||
0xffff & regs->xds,0xffff & regs->xes);
|
||||
printk(" DS: %04x ES: %04x GS: %04x\n",
|
||||
0xffff & regs->xds,0xffff & regs->xes, 0xffff & regs->xgs);
|
||||
|
||||
cr0 = read_cr0();
|
||||
cr2 = read_cr2();
|
||||
|
@ -346,6 +335,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
|
|||
|
||||
regs.xds = __USER_DS;
|
||||
regs.xes = __USER_DS;
|
||||
regs.xgs = __KERNEL_PDA;
|
||||
regs.orig_eax = -1;
|
||||
regs.eip = (unsigned long) kernel_thread_helper;
|
||||
regs.xcs = __KERNEL_CS | get_kernel_rpl();
|
||||
|
@ -431,7 +421,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
|
|||
p->thread.eip = (unsigned long) ret_from_fork;
|
||||
|
||||
savesegment(fs,p->thread.fs);
|
||||
savesegment(gs,p->thread.gs);
|
||||
|
||||
tsk = current;
|
||||
if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) {
|
||||
|
@ -508,7 +497,7 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
|
|||
dump->regs.ds = regs->xds;
|
||||
dump->regs.es = regs->xes;
|
||||
savesegment(fs,dump->regs.fs);
|
||||
savesegment(gs,dump->regs.gs);
|
||||
dump->regs.gs = regs->xgs;
|
||||
dump->regs.orig_eax = regs->orig_eax;
|
||||
dump->regs.eip = regs->eip;
|
||||
dump->regs.cs = regs->xcs;
|
||||
|
@ -648,22 +637,27 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas
|
|||
|
||||
__unlazy_fpu(prev_p);
|
||||
|
||||
|
||||
/* we're going to use this soon, after a few expensive things */
|
||||
if (next_p->fpu_counter > 5)
|
||||
prefetch(&next->i387.fxsave);
|
||||
|
||||
/*
|
||||
* Reload esp0.
|
||||
*/
|
||||
load_esp0(tss, next);
|
||||
|
||||
/*
|
||||
* Save away %fs and %gs. No need to save %es and %ds, as
|
||||
* those are always kernel segments while inside the kernel.
|
||||
* Doing this before setting the new TLS descriptors avoids
|
||||
* the situation where we temporarily have non-reloadable
|
||||
* segments in %fs and %gs. This could be an issue if the
|
||||
* NMI handler ever used %fs or %gs (it does not today), or
|
||||
* if the kernel is running inside of a hypervisor layer.
|
||||
* Save away %fs. No need to save %gs, as it was saved on the
|
||||
* stack on entry. No need to save %es and %ds, as those are
|
||||
* always kernel segments while inside the kernel. Doing this
|
||||
* before setting the new TLS descriptors avoids the situation
|
||||
* where we temporarily have non-reloadable segments in %fs
|
||||
* and %gs. This could be an issue if the NMI handler ever
|
||||
* used %fs or %gs (it does not today), or if the kernel is
|
||||
* running inside of a hypervisor layer.
|
||||
*/
|
||||
savesegment(fs, prev->fs);
|
||||
savesegment(gs, prev->gs);
|
||||
|
||||
/*
|
||||
* Load the per-thread Thread-Local Storage descriptor.
|
||||
|
@ -671,22 +665,14 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas
|
|||
load_TLS(next, cpu);
|
||||
|
||||
/*
|
||||
* Restore %fs and %gs if needed.
|
||||
* Restore %fs if needed.
|
||||
*
|
||||
* Glibc normally makes %fs be zero, and %gs is one of
|
||||
* the TLS segments.
|
||||
* Glibc normally makes %fs be zero.
|
||||
*/
|
||||
if (unlikely(prev->fs | next->fs))
|
||||
loadsegment(fs, next->fs);
|
||||
|
||||
if (prev->gs | next->gs)
|
||||
loadsegment(gs, next->gs);
|
||||
|
||||
/*
|
||||
* Restore IOPL if needed.
|
||||
*/
|
||||
if (unlikely(prev->iopl != next->iopl))
|
||||
set_iopl_mask(next->iopl);
|
||||
write_pda(pcurrent, next_p);
|
||||
|
||||
/*
|
||||
* Now maybe handle debug registers and/or IO bitmaps
|
||||
|
@ -697,6 +683,13 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas
|
|||
|
||||
disable_tsc(prev_p, next_p);
|
||||
|
||||
/* If the task has used fpu the last 5 timeslices, just do a full
|
||||
* restore of the math state immediately to avoid the trap; the
|
||||
* chances of needing FPU soon are obviously high now
|
||||
*/
|
||||
if (next_p->fpu_counter > 5)
|
||||
math_state_restore();
|
||||
|
||||
return prev_p;
|
||||
}
|
||||
|
||||
|
|
|
@ -94,13 +94,9 @@ static int putreg(struct task_struct *child,
|
|||
return -EIO;
|
||||
child->thread.fs = value;
|
||||
return 0;
|
||||
case GS:
|
||||
if (value && (value & 3) != 3)
|
||||
return -EIO;
|
||||
child->thread.gs = value;
|
||||
return 0;
|
||||
case DS:
|
||||
case ES:
|
||||
case GS:
|
||||
if (value && (value & 3) != 3)
|
||||
return -EIO;
|
||||
value &= 0xffff;
|
||||
|
@ -116,8 +112,8 @@ static int putreg(struct task_struct *child,
|
|||
value |= get_stack_long(child, EFL_OFFSET) & ~FLAG_MASK;
|
||||
break;
|
||||
}
|
||||
if (regno > GS*4)
|
||||
regno -= 2*4;
|
||||
if (regno > ES*4)
|
||||
regno -= 1*4;
|
||||
put_stack_long(child, regno - sizeof(struct pt_regs), value);
|
||||
return 0;
|
||||
}
|
||||
|
@ -131,18 +127,16 @@ static unsigned long getreg(struct task_struct *child,
|
|||
case FS:
|
||||
retval = child->thread.fs;
|
||||
break;
|
||||
case GS:
|
||||
retval = child->thread.gs;
|
||||
break;
|
||||
case DS:
|
||||
case ES:
|
||||
case GS:
|
||||
case SS:
|
||||
case CS:
|
||||
retval = 0xffff;
|
||||
/* fall through */
|
||||
default:
|
||||
if (regno > GS*4)
|
||||
regno -= 2*4;
|
||||
if (regno > ES*4)
|
||||
regno -= 1*4;
|
||||
regno = regno - sizeof(struct pt_regs);
|
||||
retval &= get_stack_long(child, regno);
|
||||
}
|
||||
|
|
|
@ -3,10 +3,23 @@
|
|||
*/
|
||||
#include <linux/pci.h>
|
||||
#include <linux/irq.h>
|
||||
#include <asm/pci-direct.h>
|
||||
#include <asm/genapic.h>
|
||||
#include <asm/cpu.h>
|
||||
|
||||
#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) && defined(CONFIG_PCI)
|
||||
static void __devinit verify_quirk_intel_irqbalance(struct pci_dev *dev)
|
||||
{
|
||||
#ifdef CONFIG_X86_64
|
||||
if (genapic != &apic_flat)
|
||||
panic("APIC mode must be flat on this system\n");
|
||||
#elif defined(CONFIG_X86_GENERICARCH)
|
||||
if (genapic != &apic_default)
|
||||
panic("APIC mode must be default(flat) on this system. Use apic=default\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __devinit quirk_intel_irqbalance(struct pci_dev *dev)
|
||||
void __init quirk_intel_irqbalance(void)
|
||||
{
|
||||
u8 config, rev;
|
||||
u32 word;
|
||||
|
@ -16,18 +29,18 @@ static void __devinit quirk_intel_irqbalance(struct pci_dev *dev)
|
|||
* based platforms.
|
||||
* Disable SW irqbalance/affinity on those platforms.
|
||||
*/
|
||||
pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev);
|
||||
rev = read_pci_config_byte(0, 0, 0, PCI_CLASS_REVISION);
|
||||
if (rev > 0x9)
|
||||
return;
|
||||
|
||||
printk(KERN_INFO "Intel E7520/7320/7525 detected.");
|
||||
|
||||
/* enable access to config space*/
|
||||
pci_read_config_byte(dev, 0xf4, &config);
|
||||
pci_write_config_byte(dev, 0xf4, config|0x2);
|
||||
/* enable access to config space */
|
||||
config = read_pci_config_byte(0, 0, 0, 0xf4);
|
||||
write_pci_config_byte(0, 0, 0, 0xf4, config|0x2);
|
||||
|
||||
/* read xTPR register */
|
||||
raw_pci_ops->read(0, 0, 0x40, 0x4c, 2, &word);
|
||||
word = read_pci_config_16(0, 0, 0x40, 0x4c);
|
||||
|
||||
if (!(word & (1 << 13))) {
|
||||
printk(KERN_INFO "Disabling irq balancing and affinity\n");
|
||||
|
@ -37,14 +50,25 @@ static void __devinit quirk_intel_irqbalance(struct pci_dev *dev)
|
|||
noirqdebug_setup("");
|
||||
#ifdef CONFIG_PROC_FS
|
||||
no_irq_affinity = 1;
|
||||
#endif
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
printk(KERN_INFO "Disabling cpu hotplug control\n");
|
||||
enable_cpu_hotplug = 0;
|
||||
#endif
|
||||
#ifdef CONFIG_X86_64
|
||||
/* force the genapic selection to flat mode so that
|
||||
* interrupts can be redirected to more than one CPU.
|
||||
*/
|
||||
genapic_force = &apic_flat;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* put back the original value for config space*/
|
||||
/* put back the original value for config space */
|
||||
if (!(config & 0x2))
|
||||
pci_write_config_byte(dev, 0xf4, config);
|
||||
write_pci_config_byte(0, 0, 0, 0xf4, config);
|
||||
}
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quirk_intel_irqbalance);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_intel_irqbalance);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_intel_irqbalance);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, verify_quirk_intel_irqbalance);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, verify_quirk_intel_irqbalance);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, verify_quirk_intel_irqbalance);
|
||||
|
||||
#endif
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue