You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Martin Schwidefsky: "The most notable change for this pull request is the ftrace rework from Heiko. It brings a small performance improvement and the ground work to support a new gcc option to replace the mcount blocks with a single nop. Two new s390 specific system calls are added to emulate user space mmio for PCI, an artifact of the how PCI memory is accessed. Two patches for the memory management with changes to common code. For KVM mm_forbids_zeropage is added which disables the empty zero page for an mm that is used by a KVM process. And an optimization, pmdp_get_and_clear_full is added analog to ptep_get_and_clear_full. Some micro optimization for the cmpxchg and the spinlock code. And as usual bug fixes and cleanups" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (46 commits) s390/cputime: fix 31-bit compile s390/scm_block: make the number of reqs per HW req configurable s390/scm_block: handle multiple requests in one HW request s390/scm_block: allocate aidaw pages only when necessary s390/scm_block: use mempool to manage aidaw requests s390/eadm: change timeout value s390/mm: fix memory leak of ptlock in pmd_free_tlb s390: use local symbol names in entry[64].S s390/ptrace: always include vector registers in core files s390/simd: clear vector register pointer on fork/clone s390: translate cputime magic constants to macros s390/idle: convert open coded idle time seqcount s390/idle: add missing irq off lockdep annotation s390/debug: avoid function call for debug_sprintf_* s390/kprobes: fix instruction copy for out of line execution s390: remove diag 44 calls from cpu_relax() s390/dasd: retry partition detection s390/dasd: fix list corruption for sleep_on requests s390/dasd: fix infinite term I/O loop s390/dasd: remove unused code ...
This commit is contained in:
@@ -26,11 +26,6 @@ The Linux for s/390 & z/Architecture Kernel Task Structure
|
||||
Register Usage & Stackframes on Linux for s/390 & z/Architecture
|
||||
A sample program with comments
|
||||
Compiling programs for debugging on Linux for s/390 & z/Architecture
|
||||
Figuring out gcc compile errors
|
||||
Debugging Tools
|
||||
objdump
|
||||
strace
|
||||
Performance Debugging
|
||||
Debugging under VM
|
||||
s/390 & z/Architecture IO Overview
|
||||
Debugging IO on s/390 & z/Architecture under VM
|
||||
@@ -114,28 +109,25 @@ s/390 z/Architecture
|
||||
|
||||
16-17 16-17 Address Space Control
|
||||
|
||||
00 Primary Space Mode when DAT on
|
||||
The linux kernel currently runs in this mode, CR1 is affiliated with
|
||||
this mode & points to the primary segment table origin etc.
|
||||
00 Primary Space Mode:
|
||||
The register CR1 contains the primary address-space control ele-
|
||||
ment (PASCE), which points to the primary space region/segment
|
||||
table origin.
|
||||
|
||||
01 Access register mode this mode is used in functions to
|
||||
copy data between kernel & user space.
|
||||
01 Access register mode
|
||||
|
||||
10 Secondary space mode not used in linux however CR7 the
|
||||
register affiliated with this mode is & this & normally
|
||||
CR13=CR7 to allow us to copy data between kernel & user space.
|
||||
We do this as follows:
|
||||
We set ar2 to 0 to designate its
|
||||
affiliated gpr ( gpr2 )to point to primary=kernel space.
|
||||
We set ar4 to 1 to designate its
|
||||
affiliated gpr ( gpr4 ) to point to secondary=home=user space
|
||||
& then essentially do a memcopy(gpr2,gpr4,size) to
|
||||
copy data between the address spaces, the reason we use home space for the
|
||||
kernel & don't keep secondary space free is that code will not run in
|
||||
secondary space.
|
||||
10 Secondary Space Mode:
|
||||
The register CR7 contains the secondary address-space control
|
||||
element (SASCE), which points to the secondary space region or
|
||||
segment table origin.
|
||||
|
||||
11 Home Space Mode all user programs run in this mode.
|
||||
it is affiliated with CR13.
|
||||
11 Home Space Mode:
|
||||
The register CR13 contains the home space address-space control
|
||||
element (HASCE), which points to the home space region/segment
|
||||
table origin.
|
||||
|
||||
See "Address Spaces on Linux for s/390 & z/Architecture" below
|
||||
for more information about address space usage in Linux.
|
||||
|
||||
18-19 18-19 Condition codes (CC)
|
||||
|
||||
@@ -249,9 +241,9 @@ currently 4TB of physical memory currently on z/Architecture.
|
||||
Address Spaces on Linux for s/390 & z/Architecture
|
||||
==================================================
|
||||
|
||||
Our addressing scheme is as follows
|
||||
|
||||
Our addressing scheme is basically as follows:
|
||||
|
||||
Primary Space Home Space
|
||||
Himem 0x7fffffff 2GB on s/390 ***************** ****************
|
||||
currently 0x3ffffffffff (2^42)-1 * User Stack * * *
|
||||
on z/Architecture. ***************** * *
|
||||
@@ -264,9 +256,46 @@ on z/Architecture. ***************** * *
|
||||
* Sections * * *
|
||||
0x00000000 ***************** ****************
|
||||
|
||||
This also means that we need to look at the PSW problem state bit
|
||||
or the addressing mode to decide whether we are looking at
|
||||
user or kernel space.
|
||||
This also means that we need to look at the PSW problem state bit and the
|
||||
addressing mode to decide whether we are looking at user or kernel space.
|
||||
|
||||
User space runs in primary address mode (or access register mode within
|
||||
the vdso code).
|
||||
|
||||
The kernel usually also runs in home space mode, however when accessing
|
||||
user space the kernel switches to primary or secondary address mode if
|
||||
the mvcos instruction is not available or if a compare-and-swap (futex)
|
||||
instruction on a user space address is performed.
|
||||
|
||||
When also looking at the ASCE control registers, this means:
|
||||
|
||||
User space:
|
||||
- runs in primary or access register mode
|
||||
- cr1 contains the user asce
|
||||
- cr7 contains the user asce
|
||||
- cr13 contains the kernel asce
|
||||
|
||||
Kernel space:
|
||||
- runs in home space mode
|
||||
- cr1 contains the user or kernel asce
|
||||
-> the kernel asce is loaded when a uaccess requires primary or
|
||||
secondary address mode
|
||||
- cr7 contains the user or kernel asce, (changed with set_fs())
|
||||
- cr13 contains the kernel asce
|
||||
|
||||
In case of uaccess the kernel changes to:
|
||||
- primary space mode in case of a uaccess (copy_to_user) and uses
|
||||
e.g. the mvcp instruction to access user space. However the kernel
|
||||
will stay in home space mode if the mvcos instruction is available
|
||||
- secondary space mode in case of futex atomic operations, so that the
|
||||
instructions come from primary address space and data from secondary
|
||||
space
|
||||
|
||||
In case of KVM, the kernel runs in home space mode, but cr1 gets switched
|
||||
to contain the gmap asce before the SIE instruction gets executed. When
|
||||
the SIE instruction is finished, cr1 will be switched back to contain the
|
||||
user asce.
|
||||
|
||||
|
||||
Virtual Addresses on s/390 & z/Architecture
|
||||
===========================================
|
||||
@@ -706,376 +735,7 @@ Debugging with optimisation has since much improved after fixing
|
||||
some bugs, please make sure you are using gdb-5.0 or later developed
|
||||
after Nov'2000.
|
||||
|
||||
Figuring out gcc compile errors
|
||||
===============================
|
||||
If you are getting a lot of syntax errors compiling a program & the problem
|
||||
isn't blatantly obvious from the source.
|
||||
It often helps to just preprocess the file, this is done with the -E
|
||||
option in gcc.
|
||||
What this does is that it runs through the very first phase of compilation
|
||||
( compilation in gcc is done in several stages & gcc calls many programs to
|
||||
achieve its end result ) with the -E option gcc just calls the gcc preprocessor (cpp).
|
||||
The c preprocessor does the following, it joins all the files #included together
|
||||
recursively ( #include files can #include other files ) & also the c file you wish to compile.
|
||||
It puts a fully qualified path of the #included files in a comment & it
|
||||
does macro expansion.
|
||||
This is useful for debugging because
|
||||
1) You can double check whether the files you expect to be included are the ones
|
||||
that are being included ( e.g. double check that you aren't going to the i386 asm directory ).
|
||||
2) Check that macro definitions aren't clashing with typedefs,
|
||||
3) Check that definitions aren't being used before they are being included.
|
||||
4) Helps put the line emitting the error under the microscope if it contains macros.
|
||||
|
||||
For convenience the Linux kernel's makefile will do preprocessing automatically for you
|
||||
by suffixing the file you want built with .i ( instead of .o )
|
||||
|
||||
e.g.
|
||||
from the linux directory type
|
||||
make arch/s390/kernel/signal.i
|
||||
this will build
|
||||
|
||||
s390-gcc -D__KERNEL__ -I/home1/barrow/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
|
||||
-fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -E arch/s390/kernel/signal.c
|
||||
> arch/s390/kernel/signal.i
|
||||
|
||||
Now look at signal.i you should see something like.
|
||||
|
||||
|
||||
# 1 "/home1/barrow/linux/include/asm/types.h" 1
|
||||
typedef unsigned short umode_t;
|
||||
typedef __signed__ char __s8;
|
||||
typedef unsigned char __u8;
|
||||
typedef __signed__ short __s16;
|
||||
typedef unsigned short __u16;
|
||||
|
||||
If instead you are getting errors further down e.g.
|
||||
unknown instruction:2515 "move.l" or better still unknown instruction:2515
|
||||
"Fixme not implemented yet, call Martin" you are probably are attempting to compile some code
|
||||
meant for another architecture or code that is simply not implemented, with a fixme statement
|
||||
stuck into the inline assembly code so that the author of the file now knows he has work to do.
|
||||
To look at the assembly emitted by gcc just before it is about to call gas ( the gnu assembler )
|
||||
use the -S option.
|
||||
Again for your convenience the Linux kernel's Makefile will hold your hand &
|
||||
do all this donkey work for you also by building the file with the .s suffix.
|
||||
e.g.
|
||||
from the Linux directory type
|
||||
make arch/s390/kernel/signal.s
|
||||
|
||||
s390-gcc -D__KERNEL__ -I/home1/barrow/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
|
||||
-fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -S arch/s390/kernel/signal.c
|
||||
-o arch/s390/kernel/signal.s
|
||||
|
||||
|
||||
This will output something like, ( please note the constant pool & the useful comments
|
||||
in the prologue to give you a hand at interpreting it ).
|
||||
|
||||
.LC54:
|
||||
.string "misaligned (__u16 *) in __xchg\n"
|
||||
.LC57:
|
||||
.string "misaligned (__u32 *) in __xchg\n"
|
||||
.L$PG1: # Pool sys_sigsuspend
|
||||
.LC192:
|
||||
.long -262401
|
||||
.LC193:
|
||||
.long -1
|
||||
.LC194:
|
||||
.long schedule-.L$PG1
|
||||
.LC195:
|
||||
.long do_signal-.L$PG1
|
||||
.align 4
|
||||
.globl sys_sigsuspend
|
||||
.type sys_sigsuspend,@function
|
||||
sys_sigsuspend:
|
||||
# leaf function 0
|
||||
# automatics 16
|
||||
# outgoing args 0
|
||||
# need frame pointer 0
|
||||
# call alloca 0
|
||||
# has varargs 0
|
||||
# incoming args (stack) 0
|
||||
# function length 168
|
||||
STM 8,15,32(15)
|
||||
LR 0,15
|
||||
AHI 15,-112
|
||||
BASR 13,0
|
||||
.L$CO1: AHI 13,.L$PG1-.L$CO1
|
||||
ST 0,0(15)
|
||||
LR 8,2
|
||||
N 5,.LC192-.L$PG1(13)
|
||||
|
||||
Adding -g to the above output makes the output even more useful
|
||||
e.g. typing
|
||||
make CC:="s390-gcc -g" kernel/sched.s
|
||||
|
||||
which compiles.
|
||||
s390-gcc -g -D__KERNEL__ -I/home/barrow/linux-2.3/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce -S kernel/sched.c -o kernel/sched.s
|
||||
|
||||
also outputs stabs ( debugger ) info, from this info you can find out the
|
||||
offsets & sizes of various elements in structures.
|
||||
e.g. the stab for the structure
|
||||
struct rlimit {
|
||||
unsigned long rlim_cur;
|
||||
unsigned long rlim_max;
|
||||
};
|
||||
is
|
||||
.stabs "rlimit:T(151,2)=s8rlim_cur:(0,5),0,32;rlim_max:(0,5),32,32;;",128,0,0,0
|
||||
from this stab you can see that
|
||||
rlimit_cur starts at bit offset 0 & is 32 bits in size
|
||||
rlimit_max starts at bit offset 32 & is 32 bits in size.
|
||||
|
||||
|
||||
Debugging Tools:
|
||||
================
|
||||
|
||||
objdump
|
||||
=======
|
||||
This is a tool with many options the most useful being ( if compiled with -g).
|
||||
objdump --source <victim program or object file> > <victims debug listing >
|
||||
|
||||
|
||||
The whole kernel can be compiled like this ( Doing this will make a 17MB kernel
|
||||
& a 200 MB listing ) however you have to strip it before building the image
|
||||
using the strip command to make it a more reasonable size to boot it.
|
||||
|
||||
A source/assembly mixed dump of the kernel can be done with the line
|
||||
objdump --source vmlinux > vmlinux.lst
|
||||
Also, if the file isn't compiled -g, this will output as much debugging information
|
||||
as it can (e.g. function names). This is very slow as it spends lots
|
||||
of time searching for debugging info. The following self explanatory line should be used
|
||||
instead if the code isn't compiled -g, as it is much faster:
|
||||
objdump --disassemble-all --syms vmlinux > vmlinux.lst
|
||||
|
||||
As hard drive space is valuable most of us use the following approach.
|
||||
1) Look at the emitted psw on the console to find the crash address in the kernel.
|
||||
2) Look at the file System.map ( in the linux directory ) produced when building
|
||||
the kernel to find the closest address less than the current PSW to find the
|
||||
offending function.
|
||||
3) use grep or similar to search the source tree looking for the source file
|
||||
with this function if you don't know where it is.
|
||||
4) rebuild this object file with -g on, as an example suppose the file was
|
||||
( /arch/s390/kernel/signal.o )
|
||||
5) Assuming the file with the erroneous function is signal.c Move to the base of the
|
||||
Linux source tree.
|
||||
6) rm /arch/s390/kernel/signal.o
|
||||
7) make /arch/s390/kernel/signal.o
|
||||
8) watch the gcc command line emitted
|
||||
9) type it in again or alternatively cut & paste it on the console adding the -g option.
|
||||
10) objdump --source arch/s390/kernel/signal.o > signal.lst
|
||||
This will output the source & the assembly intermixed, as the snippet below shows
|
||||
This will unfortunately output addresses which aren't the same
|
||||
as the kernel ones you should be able to get around the mental arithmetic
|
||||
by playing with the --adjust-vma parameter to objdump.
|
||||
|
||||
|
||||
|
||||
|
||||
static inline void spin_lock(spinlock_t *lp)
|
||||
{
|
||||
a0: 18 34 lr %r3,%r4
|
||||
a2: a7 3a 03 bc ahi %r3,956
|
||||
__asm__ __volatile(" lhi 1,-1\n"
|
||||
a6: a7 18 ff ff lhi %r1,-1
|
||||
aa: 1f 00 slr %r0,%r0
|
||||
ac: ba 01 30 00 cs %r0,%r1,0(%r3)
|
||||
b0: a7 44 ff fd jm aa <sys_sigsuspend+0x2e>
|
||||
saveset = current->blocked;
|
||||
b4: d2 07 f0 68 mvc 104(8,%r15),972(%r4)
|
||||
b8: 43 cc
|
||||
return (set->sig[0] & mask) != 0;
|
||||
}
|
||||
|
||||
6) If debugging under VM go down to that section in the document for more info.
|
||||
|
||||
|
||||
I now have a tool which takes the pain out of --adjust-vma
|
||||
& you are able to do something like
|
||||
make /arch/s390/kernel/traps.lst
|
||||
& it automatically generates the correctly relocated entries for
|
||||
the text segment in traps.lst.
|
||||
This tool is now standard in linux distro's in scripts/makelst
|
||||
|
||||
strace:
|
||||
-------
|
||||
Q. What is it ?
|
||||
A. It is a tool for intercepting calls to the kernel & logging them
|
||||
to a file & on the screen.
|
||||
|
||||
Q. What use is it ?
|
||||
A. You can use it to find out what files a particular program opens.
|
||||
|
||||
|
||||
|
||||
Example 1
|
||||
---------
|
||||
If you wanted to know does ping work but didn't have the source
|
||||
strace ping -c 1 127.0.0.1
|
||||
& then look at the man pages for each of the syscalls below,
|
||||
( In fact this is sometimes easier than looking at some spaghetti
|
||||
source which conditionally compiles for several architectures ).
|
||||
Not everything that it throws out needs to make sense immediately.
|
||||
|
||||
Just looking quickly you can see that it is making up a RAW socket
|
||||
for the ICMP protocol.
|
||||
Doing an alarm(10) for a 10 second timeout
|
||||
& doing a gettimeofday call before & after each read to see
|
||||
how long the replies took, & writing some text to stdout so the user
|
||||
has an idea what is going on.
|
||||
|
||||
socket(PF_INET, SOCK_RAW, IPPROTO_ICMP) = 3
|
||||
getuid() = 0
|
||||
setuid(0) = 0
|
||||
stat("/usr/share/locale/C/libc.cat", 0xbffff134) = -1 ENOENT (No such file or directory)
|
||||
stat("/usr/share/locale/libc/C", 0xbffff134) = -1 ENOENT (No such file or directory)
|
||||
stat("/usr/local/share/locale/C/libc.cat", 0xbffff134) = -1 ENOENT (No such file or directory)
|
||||
getpid() = 353
|
||||
setsockopt(3, SOL_SOCKET, SO_BROADCAST, [1], 4) = 0
|
||||
setsockopt(3, SOL_SOCKET, SO_RCVBUF, [49152], 4) = 0
|
||||
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(3, 1), ...}) = 0
|
||||
mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40008000
|
||||
ioctl(1, TCGETS, {B9600 opost isig icanon echo ...}) = 0
|
||||
write(1, "PING 127.0.0.1 (127.0.0.1): 56 d"..., 42PING 127.0.0.1 (127.0.0.1): 56 data bytes
|
||||
) = 42
|
||||
sigaction(SIGINT, {0x8049ba0, [], SA_RESTART}, {SIG_DFL}) = 0
|
||||
sigaction(SIGALRM, {0x8049600, [], SA_RESTART}, {SIG_DFL}) = 0
|
||||
gettimeofday({948904719, 138951}, NULL) = 0
|
||||
sendto(3, "\10\0D\201a\1\0\0\17#\2178\307\36"..., 64, 0, {sin_family=AF_INET,
|
||||
sin_port=htons(0), sin_addr=inet_addr("127.0.0.1")}, 16) = 64
|
||||
sigaction(SIGALRM, {0x8049600, [], SA_RESTART}, {0x8049600, [], SA_RESTART}) = 0
|
||||
sigaction(SIGALRM, {0x8049ba0, [], SA_RESTART}, {0x8049600, [], SA_RESTART}) = 0
|
||||
alarm(10) = 0
|
||||
recvfrom(3, "E\0\0T\0005\0\0@\1|r\177\0\0\1\177"..., 192, 0,
|
||||
{sin_family=AF_INET, sin_port=htons(50882), sin_addr=inet_addr("127.0.0.1")}, [16]) = 84
|
||||
gettimeofday({948904719, 160224}, NULL) = 0
|
||||
recvfrom(3, "E\0\0T\0006\0\0\377\1\275p\177\0"..., 192, 0,
|
||||
{sin_family=AF_INET, sin_port=htons(50882), sin_addr=inet_addr("127.0.0.1")}, [16]) = 84
|
||||
gettimeofday({948904719, 166952}, NULL) = 0
|
||||
write(1, "64 bytes from 127.0.0.1: icmp_se"...,
|
||||
5764 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=28.0 ms
|
||||
|
||||
Example 2
|
||||
---------
|
||||
strace passwd 2>&1 | grep open
|
||||
produces the following output
|
||||
open("/etc/ld.so.cache", O_RDONLY) = 3
|
||||
open("/opt/kde/lib/libc.so.5", O_RDONLY) = -1 ENOENT (No such file or directory)
|
||||
open("/lib/libc.so.5", O_RDONLY) = 3
|
||||
open("/dev", O_RDONLY) = 3
|
||||
open("/var/run/utmp", O_RDONLY) = 3
|
||||
open("/etc/passwd", O_RDONLY) = 3
|
||||
open("/etc/shadow", O_RDONLY) = 3
|
||||
open("/etc/login.defs", O_RDONLY) = 4
|
||||
open("/dev/tty", O_RDONLY) = 4
|
||||
|
||||
The 2>&1 is done to redirect stderr to stdout & grep is then filtering this input
|
||||
through the pipe for each line containing the string open.
|
||||
|
||||
|
||||
Example 3
|
||||
---------
|
||||
Getting sophisticated
|
||||
telnetd crashes & I don't know why
|
||||
|
||||
Steps
|
||||
-----
|
||||
1) Replace the following line in /etc/inetd.conf
|
||||
telnet stream tcp nowait root /usr/sbin/in.telnetd -h
|
||||
with
|
||||
telnet stream tcp nowait root /blah
|
||||
|
||||
2) Create the file /blah with the following contents to start tracing telnetd
|
||||
#!/bin/bash
|
||||
/usr/bin/strace -o/t1 -f /usr/sbin/in.telnetd -h
|
||||
3) chmod 700 /blah to make it executable only to root
|
||||
4)
|
||||
killall -HUP inetd
|
||||
or ps aux | grep inetd
|
||||
get inetd's process id
|
||||
& kill -HUP inetd to restart it.
|
||||
|
||||
Important options
|
||||
-----------------
|
||||
-o is used to tell strace to output to a file in our case t1 in the root directory
|
||||
-f is to follow children i.e.
|
||||
e.g in our case above telnetd will start the login process & subsequently a shell like bash.
|
||||
You will be able to tell which is which from the process ID's listed on the left hand side
|
||||
of the strace output.
|
||||
-p<pid> will tell strace to attach to a running process, yup this can be done provided
|
||||
it isn't being traced or debugged already & you have enough privileges,
|
||||
the reason 2 processes cannot trace or debug the same program is that strace
|
||||
becomes the parent process of the one being debugged & processes ( unlike people )
|
||||
can have only one parent.
|
||||
|
||||
|
||||
However the file /t1 will get big quite quickly
|
||||
to test it telnet 127.0.0.1
|
||||
|
||||
now look at what files in.telnetd execve'd
|
||||
413 execve("/usr/sbin/in.telnetd", ["/usr/sbin/in.telnetd", "-h"], [/* 17 vars */]) = 0
|
||||
414 execve("/bin/login", ["/bin/login", "-h", "localhost", "-p"], [/* 2 vars */]) = 0
|
||||
|
||||
Whey it worked!.
|
||||
|
||||
|
||||
Other hints:
|
||||
------------
|
||||
If the program is not very interactive ( i.e. not much keyboard input )
|
||||
& is crashing in one architecture but not in another you can do
|
||||
an strace of both programs under as identical a scenario as you can
|
||||
on both architectures outputting to a file then.
|
||||
do a diff of the two traces using the diff program
|
||||
i.e.
|
||||
diff output1 output2
|
||||
& maybe you'll be able to see where the call paths differed, this
|
||||
is possibly near the cause of the crash.
|
||||
|
||||
More info
|
||||
---------
|
||||
Look at man pages for strace & the various syscalls
|
||||
e.g. man strace, man alarm, man socket.
|
||||
|
||||
|
||||
Performance Debugging
|
||||
=====================
|
||||
gcc is capable of compiling in profiling code just add the -p option
|
||||
to the CFLAGS, this obviously affects program size & performance.
|
||||
This can be used by the gprof gnu profiling tool or the
|
||||
gcov the gnu code coverage tool ( code coverage is a means of testing
|
||||
code quality by checking if all the code in an executable in exercised by
|
||||
a tester ).
|
||||
|
||||
|
||||
Using top to find out where processes are sleeping in the kernel
|
||||
----------------------------------------------------------------
|
||||
To do this copy the System.map from the root directory where
|
||||
the linux kernel was built to the /boot directory on your
|
||||
linux machine.
|
||||
Start top
|
||||
Now type fU<return>
|
||||
You should see a new field called WCHAN which
|
||||
tells you where each process is sleeping here is a typical output.
|
||||
|
||||
6:59pm up 41 min, 1 user, load average: 0.00, 0.00, 0.00
|
||||
28 processes: 27 sleeping, 1 running, 0 zombie, 0 stopped
|
||||
CPU states: 0.0% user, 0.1% system, 0.0% nice, 99.8% idle
|
||||
Mem: 254900K av, 45976K used, 208924K free, 0K shrd, 28636K buff
|
||||
Swap: 0K av, 0K used, 0K free 8620K cached
|
||||
|
||||
PID USER PRI NI SIZE RSS SHARE WCHAN STAT LIB %CPU %MEM TIME COMMAND
|
||||
750 root 12 0 848 848 700 do_select S 0 0.1 0.3 0:00 in.telnetd
|
||||
767 root 16 0 1140 1140 964 R 0 0.1 0.4 0:00 top
|
||||
1 root 8 0 212 212 180 do_select S 0 0.0 0.0 0:00 init
|
||||
2 root 9 0 0 0 0 down_inte SW 0 0.0 0.0 0:00 kmcheck
|
||||
|
||||
The time command
|
||||
----------------
|
||||
Another related command is the time command which gives you an indication
|
||||
of where a process is spending the majority of its time.
|
||||
e.g.
|
||||
time ping -c 5 nc
|
||||
outputs
|
||||
real 0m4.054s
|
||||
user 0m0.010s
|
||||
sys 0m0.010s
|
||||
|
||||
Debugging under VM
|
||||
==================
|
||||
|
||||
+18
-226
@@ -11,201 +11,29 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/bug.h>
|
||||
|
||||
extern void __xchg_called_with_bad_pointer(void);
|
||||
|
||||
static inline unsigned long __xchg(unsigned long x, void *ptr, int size)
|
||||
{
|
||||
unsigned long addr, old;
|
||||
int shift;
|
||||
|
||||
switch (size) {
|
||||
case 1:
|
||||
addr = (unsigned long) ptr;
|
||||
shift = (3 ^ (addr & 3)) << 3;
|
||||
addr ^= addr & 3;
|
||||
asm volatile(
|
||||
" l %0,%4\n"
|
||||
"0: lr 0,%0\n"
|
||||
" nr 0,%3\n"
|
||||
" or 0,%2\n"
|
||||
" cs %0,0,%4\n"
|
||||
" jl 0b\n"
|
||||
: "=&d" (old), "=Q" (*(int *) addr)
|
||||
: "d" ((x & 0xff) << shift), "d" (~(0xff << shift)),
|
||||
"Q" (*(int *) addr) : "memory", "cc", "0");
|
||||
return old >> shift;
|
||||
case 2:
|
||||
addr = (unsigned long) ptr;
|
||||
shift = (2 ^ (addr & 2)) << 3;
|
||||
addr ^= addr & 2;
|
||||
asm volatile(
|
||||
" l %0,%4\n"
|
||||
"0: lr 0,%0\n"
|
||||
" nr 0,%3\n"
|
||||
" or 0,%2\n"
|
||||
" cs %0,0,%4\n"
|
||||
" jl 0b\n"
|
||||
: "=&d" (old), "=Q" (*(int *) addr)
|
||||
: "d" ((x & 0xffff) << shift), "d" (~(0xffff << shift)),
|
||||
"Q" (*(int *) addr) : "memory", "cc", "0");
|
||||
return old >> shift;
|
||||
case 4:
|
||||
asm volatile(
|
||||
" l %0,%3\n"
|
||||
"0: cs %0,%2,%3\n"
|
||||
" jl 0b\n"
|
||||
: "=&d" (old), "=Q" (*(int *) ptr)
|
||||
: "d" (x), "Q" (*(int *) ptr)
|
||||
: "memory", "cc");
|
||||
return old;
|
||||
#ifdef CONFIG_64BIT
|
||||
case 8:
|
||||
asm volatile(
|
||||
" lg %0,%3\n"
|
||||
"0: csg %0,%2,%3\n"
|
||||
" jl 0b\n"
|
||||
: "=&d" (old), "=m" (*(long *) ptr)
|
||||
: "d" (x), "Q" (*(long *) ptr)
|
||||
: "memory", "cc");
|
||||
return old;
|
||||
#endif /* CONFIG_64BIT */
|
||||
}
|
||||
__xchg_called_with_bad_pointer();
|
||||
return x;
|
||||
}
|
||||
|
||||
#define xchg(ptr, x) \
|
||||
({ \
|
||||
__typeof__(*(ptr)) __ret; \
|
||||
__ret = (__typeof__(*(ptr))) \
|
||||
__xchg((unsigned long)(x), (void *)(ptr), sizeof(*(ptr)));\
|
||||
__ret; \
|
||||
#define cmpxchg(ptr, o, n) \
|
||||
({ \
|
||||
__typeof__(*(ptr)) __o = (o); \
|
||||
__typeof__(*(ptr)) __n = (n); \
|
||||
(__typeof__(*(ptr))) __sync_val_compare_and_swap((ptr),__o,__n);\
|
||||
})
|
||||
|
||||
/*
|
||||
* Atomic compare and exchange. Compare OLD with MEM, if identical,
|
||||
* store NEW in MEM. Return the initial value in MEM. Success is
|
||||
* indicated by comparing RETURN with OLD.
|
||||
*/
|
||||
#define cmpxchg64 cmpxchg
|
||||
#define cmpxchg_local cmpxchg
|
||||
#define cmpxchg64_local cmpxchg
|
||||
|
||||
#define xchg(ptr, x) \
|
||||
({ \
|
||||
__typeof__(ptr) __ptr = (ptr); \
|
||||
__typeof__(*(ptr)) __old; \
|
||||
do { \
|
||||
__old = *__ptr; \
|
||||
} while (!__sync_bool_compare_and_swap(__ptr, __old, x)); \
|
||||
__old; \
|
||||
})
|
||||
|
||||
#define __HAVE_ARCH_CMPXCHG
|
||||
|
||||
extern void __cmpxchg_called_with_bad_pointer(void);
|
||||
|
||||
static inline unsigned long __cmpxchg(void *ptr, unsigned long old,
|
||||
unsigned long new, int size)
|
||||
{
|
||||
unsigned long addr, prev, tmp;
|
||||
int shift;
|
||||
|
||||
switch (size) {
|
||||
case 1:
|
||||
addr = (unsigned long) ptr;
|
||||
shift = (3 ^ (addr & 3)) << 3;
|
||||
addr ^= addr & 3;
|
||||
asm volatile(
|
||||
" l %0,%2\n"
|
||||
"0: nr %0,%5\n"
|
||||
" lr %1,%0\n"
|
||||
" or %0,%3\n"
|
||||
" or %1,%4\n"
|
||||
" cs %0,%1,%2\n"
|
||||
" jnl 1f\n"
|
||||
" xr %1,%0\n"
|
||||
" nr %1,%5\n"
|
||||
" jnz 0b\n"
|
||||
"1:"
|
||||
: "=&d" (prev), "=&d" (tmp), "+Q" (*(int *) addr)
|
||||
: "d" ((old & 0xff) << shift),
|
||||
"d" ((new & 0xff) << shift),
|
||||
"d" (~(0xff << shift))
|
||||
: "memory", "cc");
|
||||
return prev >> shift;
|
||||
case 2:
|
||||
addr = (unsigned long) ptr;
|
||||
shift = (2 ^ (addr & 2)) << 3;
|
||||
addr ^= addr & 2;
|
||||
asm volatile(
|
||||
" l %0,%2\n"
|
||||
"0: nr %0,%5\n"
|
||||
" lr %1,%0\n"
|
||||
" or %0,%3\n"
|
||||
" or %1,%4\n"
|
||||
" cs %0,%1,%2\n"
|
||||
" jnl 1f\n"
|
||||
" xr %1,%0\n"
|
||||
" nr %1,%5\n"
|
||||
" jnz 0b\n"
|
||||
"1:"
|
||||
: "=&d" (prev), "=&d" (tmp), "+Q" (*(int *) addr)
|
||||
: "d" ((old & 0xffff) << shift),
|
||||
"d" ((new & 0xffff) << shift),
|
||||
"d" (~(0xffff << shift))
|
||||
: "memory", "cc");
|
||||
return prev >> shift;
|
||||
case 4:
|
||||
asm volatile(
|
||||
" cs %0,%3,%1\n"
|
||||
: "=&d" (prev), "=Q" (*(int *) ptr)
|
||||
: "0" (old), "d" (new), "Q" (*(int *) ptr)
|
||||
: "memory", "cc");
|
||||
return prev;
|
||||
#ifdef CONFIG_64BIT
|
||||
case 8:
|
||||
asm volatile(
|
||||
" csg %0,%3,%1\n"
|
||||
: "=&d" (prev), "=Q" (*(long *) ptr)
|
||||
: "0" (old), "d" (new), "Q" (*(long *) ptr)
|
||||
: "memory", "cc");
|
||||
return prev;
|
||||
#endif /* CONFIG_64BIT */
|
||||
}
|
||||
__cmpxchg_called_with_bad_pointer();
|
||||
return old;
|
||||
}
|
||||
|
||||
#define cmpxchg(ptr, o, n) \
|
||||
({ \
|
||||
__typeof__(*(ptr)) __ret; \
|
||||
__ret = (__typeof__(*(ptr))) \
|
||||
__cmpxchg((ptr), (unsigned long)(o), (unsigned long)(n), \
|
||||
sizeof(*(ptr))); \
|
||||
__ret; \
|
||||
})
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
#define cmpxchg64(ptr, o, n) \
|
||||
({ \
|
||||
cmpxchg((ptr), (o), (n)); \
|
||||
})
|
||||
#else /* CONFIG_64BIT */
|
||||
static inline unsigned long long __cmpxchg64(void *ptr,
|
||||
unsigned long long old,
|
||||
unsigned long long new)
|
||||
{
|
||||
register_pair rp_old = {.pair = old};
|
||||
register_pair rp_new = {.pair = new};
|
||||
unsigned long long *ullptr = ptr;
|
||||
|
||||
asm volatile(
|
||||
" cds %0,%2,%1"
|
||||
: "+d" (rp_old), "+Q" (*ullptr)
|
||||
: "d" (rp_new)
|
||||
: "memory", "cc");
|
||||
return rp_old.pair;
|
||||
}
|
||||
|
||||
#define cmpxchg64(ptr, o, n) \
|
||||
({ \
|
||||
__typeof__(*(ptr)) __ret; \
|
||||
__ret = (__typeof__(*(ptr))) \
|
||||
__cmpxchg64((ptr), \
|
||||
(unsigned long long)(o), \
|
||||
(unsigned long long)(n)); \
|
||||
__ret; \
|
||||
})
|
||||
#endif /* CONFIG_64BIT */
|
||||
|
||||
#define __cmpxchg_double_op(p1, p2, o1, o2, n1, n2, insn) \
|
||||
({ \
|
||||
register __typeof__(*(p1)) __old1 asm("2") = (o1); \
|
||||
@@ -265,40 +93,4 @@ extern void __cmpxchg_double_called_with_bad_pointer(void);
|
||||
|
||||
#define system_has_cmpxchg_double() 1
|
||||
|
||||
#include <asm-generic/cmpxchg-local.h>
|
||||
|
||||
static inline unsigned long __cmpxchg_local(void *ptr,
|
||||
unsigned long old,
|
||||
unsigned long new, int size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
#ifdef CONFIG_64BIT
|
||||
case 8:
|
||||
#endif
|
||||
return __cmpxchg(ptr, old, new, size);
|
||||
default:
|
||||
return __cmpxchg_local_generic(ptr, old, new, size);
|
||||
}
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
/*
|
||||
* cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
|
||||
* them available.
|
||||
*/
|
||||
#define cmpxchg_local(ptr, o, n) \
|
||||
({ \
|
||||
__typeof__(*(ptr)) __ret; \
|
||||
__ret = (__typeof__(*(ptr))) \
|
||||
__cmpxchg_local((ptr), (unsigned long)(o), \
|
||||
(unsigned long)(n), sizeof(*(ptr))); \
|
||||
__ret; \
|
||||
})
|
||||
|
||||
#define cmpxchg64_local(ptr, o, n) cmpxchg64((ptr), (o), (n))
|
||||
|
||||
#endif /* __ASM_CMPXCHG_H */
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <linux/types.h>
|
||||
#include <asm/div64.h>
|
||||
|
||||
#define CPUTIME_PER_USEC 4096ULL
|
||||
#define CPUTIME_PER_SEC (CPUTIME_PER_USEC * USEC_PER_SEC)
|
||||
|
||||
/* We want to use full resolution of the CPU timer: 2**-12 micro-seconds. */
|
||||
|
||||
@@ -38,24 +40,24 @@ static inline unsigned long __div(unsigned long long n, unsigned long base)
|
||||
*/
|
||||
static inline unsigned long cputime_to_jiffies(const cputime_t cputime)
|
||||
{
|
||||
return __div((__force unsigned long long) cputime, 4096000000ULL / HZ);
|
||||
return __div((__force unsigned long long) cputime, CPUTIME_PER_SEC / HZ);
|
||||
}
|
||||
|
||||
static inline cputime_t jiffies_to_cputime(const unsigned int jif)
|
||||
{
|
||||
return (__force cputime_t)(jif * (4096000000ULL / HZ));
|
||||
return (__force cputime_t)(jif * (CPUTIME_PER_SEC / HZ));
|
||||
}
|
||||
|
||||
static inline u64 cputime64_to_jiffies64(cputime64_t cputime)
|
||||
{
|
||||
unsigned long long jif = (__force unsigned long long) cputime;
|
||||
do_div(jif, 4096000000ULL / HZ);
|
||||
do_div(jif, CPUTIME_PER_SEC / HZ);
|
||||
return jif;
|
||||
}
|
||||
|
||||
static inline cputime64_t jiffies64_to_cputime64(const u64 jif)
|
||||
{
|
||||
return (__force cputime64_t)(jif * (4096000000ULL / HZ));
|
||||
return (__force cputime64_t)(jif * (CPUTIME_PER_SEC / HZ));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -68,7 +70,7 @@ static inline unsigned int cputime_to_usecs(const cputime_t cputime)
|
||||
|
||||
static inline cputime_t usecs_to_cputime(const unsigned int m)
|
||||
{
|
||||
return (__force cputime_t)(m * 4096ULL);
|
||||
return (__force cputime_t)(m * CPUTIME_PER_USEC);
|
||||
}
|
||||
|
||||
#define usecs_to_cputime64(m) usecs_to_cputime(m)
|
||||
@@ -78,12 +80,12 @@ static inline cputime_t usecs_to_cputime(const unsigned int m)
|
||||
*/
|
||||
static inline unsigned int cputime_to_secs(const cputime_t cputime)
|
||||
{
|
||||
return __div((__force unsigned long long) cputime, 2048000000) >> 1;
|
||||
return __div((__force unsigned long long) cputime, CPUTIME_PER_SEC / 2) >> 1;
|
||||
}
|
||||
|
||||
static inline cputime_t secs_to_cputime(const unsigned int s)
|
||||
{
|
||||
return (__force cputime_t)(s * 4096000000ULL);
|
||||
return (__force cputime_t)(s * CPUTIME_PER_SEC);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -91,8 +93,8 @@ static inline cputime_t secs_to_cputime(const unsigned int s)
|
||||
*/
|
||||
static inline cputime_t timespec_to_cputime(const struct timespec *value)
|
||||
{
|
||||
unsigned long long ret = value->tv_sec * 4096000000ULL;
|
||||
return (__force cputime_t)(ret + value->tv_nsec * 4096 / 1000);
|
||||
unsigned long long ret = value->tv_sec * CPUTIME_PER_SEC;
|
||||
return (__force cputime_t)(ret + __div(value->tv_nsec * CPUTIME_PER_USEC, NSEC_PER_USEC));
|
||||
}
|
||||
|
||||
static inline void cputime_to_timespec(const cputime_t cputime,
|
||||
@@ -103,12 +105,12 @@ static inline void cputime_to_timespec(const cputime_t cputime,
|
||||
register_pair rp;
|
||||
|
||||
rp.pair = __cputime >> 1;
|
||||
asm ("dr %0,%1" : "+d" (rp) : "d" (2048000000UL));
|
||||
value->tv_nsec = rp.subreg.even * 1000 / 4096;
|
||||
asm ("dr %0,%1" : "+d" (rp) : "d" (CPUTIME_PER_SEC / 2));
|
||||
value->tv_nsec = rp.subreg.even * NSEC_PER_USEC / CPUTIME_PER_USEC;
|
||||
value->tv_sec = rp.subreg.odd;
|
||||
#else
|
||||
value->tv_nsec = (__cputime % 4096000000ULL) * 1000 / 4096;
|
||||
value->tv_sec = __cputime / 4096000000ULL;
|
||||
value->tv_nsec = (__cputime % CPUTIME_PER_SEC) * NSEC_PER_USEC / CPUTIME_PER_USEC;
|
||||
value->tv_sec = __cputime / CPUTIME_PER_SEC;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -119,8 +121,8 @@ static inline void cputime_to_timespec(const cputime_t cputime,
|
||||
*/
|
||||
static inline cputime_t timeval_to_cputime(const struct timeval *value)
|
||||
{
|
||||
unsigned long long ret = value->tv_sec * 4096000000ULL;
|
||||
return (__force cputime_t)(ret + value->tv_usec * 4096ULL);
|
||||
unsigned long long ret = value->tv_sec * CPUTIME_PER_SEC;
|
||||
return (__force cputime_t)(ret + value->tv_usec * CPUTIME_PER_USEC);
|
||||
}
|
||||
|
||||
static inline void cputime_to_timeval(const cputime_t cputime,
|
||||
@@ -131,12 +133,12 @@ static inline void cputime_to_timeval(const cputime_t cputime,
|
||||
register_pair rp;
|
||||
|
||||
rp.pair = __cputime >> 1;
|
||||
asm ("dr %0,%1" : "+d" (rp) : "d" (2048000000UL));
|
||||
value->tv_usec = rp.subreg.even / 4096;
|
||||
asm ("dr %0,%1" : "+d" (rp) : "d" (CPUTIME_PER_USEC / 2));
|
||||
value->tv_usec = rp.subreg.even / CPUTIME_PER_USEC;
|
||||
value->tv_sec = rp.subreg.odd;
|
||||
#else
|
||||
value->tv_usec = (__cputime % 4096000000ULL) / 4096;
|
||||
value->tv_sec = __cputime / 4096000000ULL;
|
||||
value->tv_usec = (__cputime % CPUTIME_PER_SEC) / CPUTIME_PER_USEC;
|
||||
value->tv_sec = __cputime / CPUTIME_PER_SEC;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -146,13 +148,13 @@ static inline void cputime_to_timeval(const cputime_t cputime,
|
||||
static inline clock_t cputime_to_clock_t(cputime_t cputime)
|
||||
{
|
||||
unsigned long long clock = (__force unsigned long long) cputime;
|
||||
do_div(clock, 4096000000ULL / USER_HZ);
|
||||
do_div(clock, CPUTIME_PER_SEC / USER_HZ);
|
||||
return clock;
|
||||
}
|
||||
|
||||
static inline cputime_t clock_t_to_cputime(unsigned long x)
|
||||
{
|
||||
return (__force cputime_t)(x * (4096000000ULL / USER_HZ));
|
||||
return (__force cputime_t)(x * (CPUTIME_PER_SEC / USER_HZ));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -161,7 +163,7 @@ static inline cputime_t clock_t_to_cputime(unsigned long x)
|
||||
static inline clock_t cputime64_to_clock_t(cputime64_t cputime)
|
||||
{
|
||||
unsigned long long clock = (__force unsigned long long) cputime;
|
||||
do_div(clock, 4096000000ULL / USER_HZ);
|
||||
do_div(clock, CPUTIME_PER_SEC / USER_HZ);
|
||||
return clock;
|
||||
}
|
||||
|
||||
|
||||
@@ -151,9 +151,21 @@ debug_text_event(debug_info_t* id, int level, const char* txt)
|
||||
* stored in the s390dbf. See Documentation/s390/s390dbf.txt for more details!
|
||||
*/
|
||||
extern debug_entry_t *
|
||||
debug_sprintf_event(debug_info_t* id,int level,char *string,...)
|
||||
__debug_sprintf_event(debug_info_t *id, int level, char *string, ...)
|
||||
__attribute__ ((format(printf, 3, 4)));
|
||||
|
||||
#define debug_sprintf_event(_id, _level, _fmt, ...) \
|
||||
({ \
|
||||
debug_entry_t *__ret; \
|
||||
debug_info_t *__id = _id; \
|
||||
int __level = _level; \
|
||||
if ((!__id) || (__level > __id->level)) \
|
||||
__ret = NULL; \
|
||||
else \
|
||||
__ret = __debug_sprintf_event(__id, __level, \
|
||||
_fmt, ## __VA_ARGS__); \
|
||||
__ret; \
|
||||
})
|
||||
|
||||
static inline debug_entry_t*
|
||||
debug_exception(debug_info_t* id, int level, void* data, int length)
|
||||
@@ -194,9 +206,22 @@ debug_text_exception(debug_info_t* id, int level, const char* txt)
|
||||
* stored in the s390dbf. See Documentation/s390/s390dbf.txt for more details!
|
||||
*/
|
||||
extern debug_entry_t *
|
||||
debug_sprintf_exception(debug_info_t* id,int level,char *string,...)
|
||||
__debug_sprintf_exception(debug_info_t *id, int level, char *string, ...)
|
||||
__attribute__ ((format(printf, 3, 4)));
|
||||
|
||||
#define debug_sprintf_exception(_id, _level, _fmt, ...) \
|
||||
({ \
|
||||
debug_entry_t *__ret; \
|
||||
debug_info_t *__id = _id; \
|
||||
int __level = _level; \
|
||||
if ((!__id) || (__level > __id->level)) \
|
||||
__ret = NULL; \
|
||||
else \
|
||||
__ret = __debug_sprintf_exception(__id, __level, \
|
||||
_fmt, ## __VA_ARGS__);\
|
||||
__ret; \
|
||||
})
|
||||
|
||||
int debug_register_view(debug_info_t* id, struct debug_view* view);
|
||||
int debug_unregister_view(debug_info_t* id, struct debug_view* view);
|
||||
|
||||
|
||||
@@ -1,25 +1,69 @@
|
||||
#ifndef _ASM_S390_FTRACE_H
|
||||
#define _ASM_S390_FTRACE_H
|
||||
|
||||
#define ARCH_SUPPORTS_FTRACE_OPS 1
|
||||
|
||||
#define MCOUNT_INSN_SIZE 24
|
||||
#define MCOUNT_RETURN_FIXUP 18
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
extern void _mcount(void);
|
||||
#define ftrace_return_address(n) __builtin_return_address(n)
|
||||
|
||||
void _mcount(void);
|
||||
void ftrace_caller(void);
|
||||
|
||||
extern char ftrace_graph_caller_end;
|
||||
extern unsigned long ftrace_plt;
|
||||
|
||||
struct dyn_arch_ftrace { };
|
||||
|
||||
#define MCOUNT_ADDR ((long)_mcount)
|
||||
#define MCOUNT_ADDR ((unsigned long)_mcount)
|
||||
#define FTRACE_ADDR ((unsigned long)ftrace_caller)
|
||||
|
||||
#define KPROBE_ON_FTRACE_NOP 0
|
||||
#define KPROBE_ON_FTRACE_CALL 1
|
||||
|
||||
static inline unsigned long ftrace_call_adjust(unsigned long addr)
|
||||
{
|
||||
return addr;
|
||||
}
|
||||
|
||||
struct ftrace_insn {
|
||||
u16 opc;
|
||||
s32 disp;
|
||||
} __packed;
|
||||
|
||||
static inline void ftrace_generate_nop_insn(struct ftrace_insn *insn)
|
||||
{
|
||||
#ifdef CONFIG_FUNCTION_TRACER
|
||||
/* jg .+24 */
|
||||
insn->opc = 0xc0f4;
|
||||
insn->disp = MCOUNT_INSN_SIZE / 2;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int is_ftrace_nop(struct ftrace_insn *insn)
|
||||
{
|
||||
#ifdef CONFIG_FUNCTION_TRACER
|
||||
if (insn->disp == MCOUNT_INSN_SIZE / 2)
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ftrace_generate_call_insn(struct ftrace_insn *insn,
|
||||
unsigned long ip)
|
||||
{
|
||||
#ifdef CONFIG_FUNCTION_TRACER
|
||||
unsigned long target;
|
||||
|
||||
/* brasl r0,ftrace_caller */
|
||||
target = is_module_addr((void *) ip) ? ftrace_plt : FTRACE_ADDR;
|
||||
insn->opc = 0xc005;
|
||||
insn->disp = (target - ip) / 2;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#define MCOUNT_INSN_SIZE 18
|
||||
|
||||
#define ARCH_SUPPORTS_FTRACE_OPS 1
|
||||
|
||||
#endif /* _ASM_S390_FTRACE_H */
|
||||
|
||||
@@ -9,9 +9,10 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/seqlock.h>
|
||||
|
||||
struct s390_idle_data {
|
||||
unsigned int sequence;
|
||||
seqcount_t seqcount;
|
||||
unsigned long long idle_count;
|
||||
unsigned long long idle_time;
|
||||
unsigned long long clock_idle_enter;
|
||||
|
||||
@@ -39,6 +39,15 @@ static inline void iounmap(volatile void __iomem *addr)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void __iomem *ioport_map(unsigned long port, unsigned int nr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void ioport_unmap(void __iomem *p)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* s390 needs a private implementation of pci_iomap since ioremap with its
|
||||
* offset parameter isn't sufficient. That's because BAR spaces are not
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#ifndef _ASM_IRQ_H
|
||||
#define _ASM_IRQ_H
|
||||
|
||||
#define EXT_INTERRUPT 1
|
||||
#define IO_INTERRUPT 2
|
||||
#define THIN_INTERRUPT 3
|
||||
#define EXT_INTERRUPT 0
|
||||
#define IO_INTERRUPT 1
|
||||
#define THIN_INTERRUPT 2
|
||||
|
||||
#define NR_IRQS_BASE 4
|
||||
#define NR_IRQS_BASE 3
|
||||
|
||||
#ifdef CONFIG_PCI_NR_MSI
|
||||
# define NR_IRQS (NR_IRQS_BASE + CONFIG_PCI_NR_MSI)
|
||||
@@ -13,9 +13,6 @@
|
||||
# define NR_IRQS NR_IRQS_BASE
|
||||
#endif
|
||||
|
||||
/* This number is used when no interrupt has been assigned */
|
||||
#define NO_IRQ 0
|
||||
|
||||
/* External interruption codes */
|
||||
#define EXT_IRQ_INTERRUPT_KEY 0x0040
|
||||
#define EXT_IRQ_CLK_COMP 0x1004
|
||||
|
||||
@@ -60,6 +60,7 @@ typedef u16 kprobe_opcode_t;
|
||||
struct arch_specific_insn {
|
||||
/* copy of original instruction */
|
||||
kprobe_opcode_t *insn;
|
||||
unsigned int is_ftrace_insn : 1;
|
||||
};
|
||||
|
||||
struct prev_kprobe {
|
||||
|
||||
@@ -147,7 +147,7 @@ struct _lowcore {
|
||||
__u32 softirq_pending; /* 0x02ec */
|
||||
__u32 percpu_offset; /* 0x02f0 */
|
||||
__u32 machine_flags; /* 0x02f4 */
|
||||
__u32 ftrace_func; /* 0x02f8 */
|
||||
__u8 pad_0x02f8[0x02fc-0x02f8]; /* 0x02f8 */
|
||||
__u32 spinlock_lockval; /* 0x02fc */
|
||||
|
||||
__u8 pad_0x0300[0x0e00-0x0300]; /* 0x0300 */
|
||||
@@ -297,7 +297,7 @@ struct _lowcore {
|
||||
__u64 percpu_offset; /* 0x0378 */
|
||||
__u64 vdso_per_cpu_data; /* 0x0380 */
|
||||
__u64 machine_flags; /* 0x0388 */
|
||||
__u64 ftrace_func; /* 0x0390 */
|
||||
__u8 pad_0x0390[0x0398-0x0390]; /* 0x0390 */
|
||||
__u64 gmap; /* 0x0398 */
|
||||
__u32 spinlock_lockval; /* 0x03a0 */
|
||||
__u8 pad_0x03a0[0x0400-0x03a4]; /* 0x03a4 */
|
||||
|
||||
@@ -50,10 +50,6 @@ struct zpci_fmb {
|
||||
atomic64_t unmapped_pages;
|
||||
} __packed __aligned(16);
|
||||
|
||||
#define ZPCI_MSI_VEC_BITS 11
|
||||
#define ZPCI_MSI_VEC_MAX (1 << ZPCI_MSI_VEC_BITS)
|
||||
#define ZPCI_MSI_VEC_MASK (ZPCI_MSI_VEC_MAX - 1)
|
||||
|
||||
enum zpci_state {
|
||||
ZPCI_FN_STATE_RESERVED,
|
||||
ZPCI_FN_STATE_STANDBY,
|
||||
@@ -90,6 +86,7 @@ struct zpci_dev {
|
||||
|
||||
/* IRQ stuff */
|
||||
u64 msi_addr; /* MSI address */
|
||||
unsigned int max_msi; /* maximum number of MSI's */
|
||||
struct airq_iv *aibv; /* adapter interrupt bit vector */
|
||||
unsigned int aisb; /* number of the summary bit */
|
||||
|
||||
|
||||
@@ -139,7 +139,8 @@ static inline int zpci_memcpy_fromio(void *dst,
|
||||
int size, rc = 0;
|
||||
|
||||
while (n > 0) {
|
||||
size = zpci_get_max_write_size((u64) src, (u64) dst, n, 8);
|
||||
size = zpci_get_max_write_size((u64 __force) src,
|
||||
(u64) dst, n, 8);
|
||||
req = ZPCI_CREATE_REQ(entry->fh, entry->bar, size);
|
||||
rc = zpci_read_single(req, dst, offset, size);
|
||||
if (rc)
|
||||
@@ -162,7 +163,8 @@ static inline int zpci_memcpy_toio(volatile void __iomem *dst,
|
||||
return -EINVAL;
|
||||
|
||||
while (n > 0) {
|
||||
size = zpci_get_max_write_size((u64) dst, (u64) src, n, 128);
|
||||
size = zpci_get_max_write_size((u64 __force) dst,
|
||||
(u64) src, n, 128);
|
||||
req = ZPCI_CREATE_REQ(entry->fh, entry->bar, size);
|
||||
|
||||
if (size > 8) /* main path */
|
||||
|
||||
@@ -22,8 +22,6 @@ unsigned long *page_table_alloc(struct mm_struct *);
|
||||
void page_table_free(struct mm_struct *, unsigned long *);
|
||||
void page_table_free_rcu(struct mmu_gather *, unsigned long *, unsigned long);
|
||||
|
||||
void page_table_reset_pgste(struct mm_struct *, unsigned long, unsigned long,
|
||||
bool init_skey);
|
||||
int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
|
||||
unsigned long key, bool nq);
|
||||
|
||||
|
||||
@@ -133,6 +133,18 @@ extern unsigned long MODULES_END;
|
||||
#define MODULES_LEN (1UL << 31)
|
||||
#endif
|
||||
|
||||
static inline int is_module_addr(void *addr)
|
||||
{
|
||||
#ifdef CONFIG_64BIT
|
||||
BUILD_BUG_ON(MODULES_LEN > (1UL << 31));
|
||||
if (addr < (void *)MODULES_VADDR)
|
||||
return 0;
|
||||
if (addr > (void *)MODULES_END)
|
||||
return 0;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* A 31 bit pagetable entry of S390 has following format:
|
||||
* | PFRA | | OS |
|
||||
@@ -479,6 +491,11 @@ static inline int mm_has_pgste(struct mm_struct *mm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* In the case that a guest uses storage keys
|
||||
* faults should no longer be backed by zero pages
|
||||
*/
|
||||
#define mm_forbids_zeropage mm_use_skey
|
||||
static inline int mm_use_skey(struct mm_struct *mm)
|
||||
{
|
||||
#ifdef CONFIG_PGSTE
|
||||
@@ -1634,6 +1651,19 @@ static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm,
|
||||
return pmd;
|
||||
}
|
||||
|
||||
#define __HAVE_ARCH_PMDP_GET_AND_CLEAR_FULL
|
||||
static inline pmd_t pmdp_get_and_clear_full(struct mm_struct *mm,
|
||||
unsigned long address,
|
||||
pmd_t *pmdp, int full)
|
||||
{
|
||||
pmd_t pmd = *pmdp;
|
||||
|
||||
if (!full)
|
||||
pmdp_flush_lazy(mm, address, pmdp);
|
||||
pmd_clear(pmdp);
|
||||
return pmd;
|
||||
}
|
||||
|
||||
#define __HAVE_ARCH_PMDP_CLEAR_FLUSH
|
||||
static inline pmd_t pmdp_clear_flush(struct vm_area_struct *vma,
|
||||
unsigned long address, pmd_t *pmdp)
|
||||
@@ -1746,7 +1776,8 @@ static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
|
||||
extern int vmem_add_mapping(unsigned long start, unsigned long size);
|
||||
extern int vmem_remove_mapping(unsigned long start, unsigned long size);
|
||||
extern int s390_enable_sie(void);
|
||||
extern void s390_enable_skey(void);
|
||||
extern int s390_enable_skey(void);
|
||||
extern void s390_reset_cmma(struct mm_struct *mm);
|
||||
|
||||
/*
|
||||
* No page table caches to initialise
|
||||
|
||||
@@ -217,8 +217,6 @@ static inline unsigned short stap(void)
|
||||
*/
|
||||
static inline void cpu_relax(void)
|
||||
{
|
||||
if (MACHINE_HAS_DIAG44)
|
||||
asm volatile("diag 0,0,68");
|
||||
barrier();
|
||||
}
|
||||
|
||||
|
||||
@@ -18,14 +18,7 @@ extern int spin_retry;
|
||||
static inline int
|
||||
_raw_compare_and_swap(unsigned int *lock, unsigned int old, unsigned int new)
|
||||
{
|
||||
unsigned int old_expected = old;
|
||||
|
||||
asm volatile(
|
||||
" cs %0,%3,%1"
|
||||
: "=d" (old), "=Q" (*lock)
|
||||
: "0" (old), "d" (new), "Q" (*lock)
|
||||
: "cc", "memory" );
|
||||
return old == old_expected;
|
||||
return __sync_bool_compare_and_swap(lock, old, new);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -121,6 +121,7 @@ static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd,
|
||||
#ifdef CONFIG_64BIT
|
||||
if (tlb->mm->context.asce_limit <= (1UL << 31))
|
||||
return;
|
||||
pgtable_pmd_page_dtor(virt_to_page(pmd));
|
||||
tlb_remove_table(tlb, pmd);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -287,7 +287,9 @@
|
||||
#define __NR_getrandom 349
|
||||
#define __NR_memfd_create 350
|
||||
#define __NR_bpf 351
|
||||
#define NR_syscalls 352
|
||||
#define __NR_s390_pci_mmio_write 352
|
||||
#define __NR_s390_pci_mmio_read 353
|
||||
#define NR_syscalls 354
|
||||
|
||||
/*
|
||||
* There are some system calls that are not present on 64 bit, some
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
* Make sure that the compiler is new enough. We want a compiler that
|
||||
* is known to work with the "Q" assembler constraint.
|
||||
*/
|
||||
#if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 3)
|
||||
#error Your compiler is too old; please use version 3.3.3 or newer
|
||||
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3)
|
||||
#error Your compiler is too old; please use version 4.3 or newer
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
@@ -156,7 +156,6 @@ int main(void)
|
||||
DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock));
|
||||
DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock));
|
||||
DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags));
|
||||
DEFINE(__LC_FTRACE_FUNC, offsetof(struct _lowcore, ftrace_func));
|
||||
DEFINE(__LC_DUMP_REIPL, offsetof(struct _lowcore, ipib));
|
||||
BLANK();
|
||||
DEFINE(__LC_CPU_TIMER_SAVE_AREA, offsetof(struct _lowcore, cpu_timer_save_area));
|
||||
|
||||
@@ -434,7 +434,7 @@ static int setup_frame32(struct ksignal *ksig, sigset_t *set,
|
||||
ksig->ka.sa.sa_restorer | PSW32_ADDR_AMODE;
|
||||
} else {
|
||||
/* Signal frames without vectors registers are short ! */
|
||||
__u16 __user *svc = (void *) frame + frame_size - 2;
|
||||
__u16 __user *svc = (void __user *) frame + frame_size - 2;
|
||||
if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, svc))
|
||||
return -EFAULT;
|
||||
restorer = (unsigned long __force) svc | PSW32_ADDR_AMODE;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user