mirror of
https://github.com/suyu-emu/horinux.git
synced 2026-09-21 14:15:21 -07:00
Merge branch 'x86-asm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 asm updates from Ingo Molnar: - Introduce the ORC unwinder, which can be enabled via CONFIG_ORC_UNWINDER=y. The ORC unwinder is a lightweight, Linux kernel specific debuginfo implementation, which aims to be DWARF done right for unwinding. Objtool is used to generate the ORC unwinder tables during build, so the data format is flexible and kernel internal: there's no dependency on debuginfo created by an external toolchain. The ORC unwinder is almost two orders of magnitude faster than the (out of tree) DWARF unwinder - which is important for perf call graph profiling. It is also significantly simpler and is coded defensively: there has not been a single ORC related kernel crash so far, even with early versions. (knock on wood!) But the main advantage is that enabling the ORC unwinder allows CONFIG_FRAME_POINTERS to be turned off - which speeds up the kernel measurably: With frame pointers disabled, GCC does not have to add frame pointer instrumentation code to every function in the kernel. The kernel's .text size decreases by about 3.2%, resulting in better cache utilization and fewer instructions executed, resulting in a broad kernel-wide speedup. Average speedup of system calls should be roughly in the 1-3% range - measurements by Mel Gorman [1] have shown a speedup of 5-10% for some function execution intense workloads. The main cost of the unwinder is that the unwinder data has to be stored in RAM: the memory cost is 2-4MB of RAM, depending on kernel config - which is a modest cost on modern x86 systems. Given how young the ORC unwinder code is it's not enabled by default - but given the performance advantages the plan is to eventually make it the default unwinder on x86. See Documentation/x86/orc-unwinder.txt for more details. - Remove lguest support: its intended role was that of a temporary proof of concept for virtualization, plus its removal will enable the reduction (removal) of the paravirt API as well, so Rusty agreed to its removal. (Juergen Gross) - Clean up and fix FSGS related functionality (Andy Lutomirski) - Clean up IO access APIs (Andy Shevchenko) - Enhance the symbol namespace (Jiri Slaby) * 'x86-asm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (47 commits) objtool: Handle GCC stack pointer adjustment bug x86/entry/64: Use ENTRY() instead of ALIGN+GLOBAL for stub32_clone() x86/fpu/math-emu: Add ENDPROC to functions x86/boot/64: Extract efi_pe_entry() from startup_64() x86/boot/32: Extract efi_pe_entry() from startup_32() x86/lguest: Remove lguest support x86/paravirt/xen: Remove xen_patch() objtool: Fix objtool fallthrough detection with function padding x86/xen/64: Fix the reported SS and CS in SYSCALL objtool: Track DRAP separately from callee-saved registers objtool: Fix validate_branch() return codes x86: Clarify/fix no-op barriers for text_poke_bp() x86/switch_to/64: Rewrite FS/GS switching yet again to fix AMD CPUs selftests/x86/fsgsbase: Test selectors 1, 2, and 3 x86/fsgsbase/64: Report FSBASE and GSBASE correctly in core dumps x86/fsgsbase/64: Fully initialize FS and GS state in start_thread_common x86/asm: Fix UNWIND_HINT_REGS macro for older binutils x86/asm/32: Fix regs_get_register() on segment registers x86/xen/64: Rearrange the SYSCALL entries x86/asm/32: Remove a bunch of '& 0xffff' from pt_regs segment reads ...
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
ORC unwinder
|
||||
============
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The kernel CONFIG_ORC_UNWINDER option enables the ORC unwinder, which is
|
||||
similar in concept to a DWARF unwinder. The difference is that the
|
||||
format of the ORC data is much simpler than DWARF, which in turn allows
|
||||
the ORC unwinder to be much simpler and faster.
|
||||
|
||||
The ORC data consists of unwind tables which are generated by objtool.
|
||||
They contain out-of-band data which is used by the in-kernel ORC
|
||||
unwinder. Objtool generates the ORC data by first doing compile-time
|
||||
stack metadata validation (CONFIG_STACK_VALIDATION). After analyzing
|
||||
all the code paths of a .o file, it determines information about the
|
||||
stack state at each instruction address in the file and outputs that
|
||||
information to the .orc_unwind and .orc_unwind_ip sections.
|
||||
|
||||
The per-object ORC sections are combined at link time and are sorted and
|
||||
post-processed at boot time. The unwinder uses the resulting data to
|
||||
correlate instruction addresses with their stack states at run time.
|
||||
|
||||
|
||||
ORC vs frame pointers
|
||||
---------------------
|
||||
|
||||
With frame pointers enabled, GCC adds instrumentation code to every
|
||||
function in the kernel. The kernel's .text size increases by about
|
||||
3.2%, resulting in a broad kernel-wide slowdown. Measurements by Mel
|
||||
Gorman [1] have shown a slowdown of 5-10% for some workloads.
|
||||
|
||||
In contrast, the ORC unwinder has no effect on text size or runtime
|
||||
performance, because the debuginfo is out of band. So if you disable
|
||||
frame pointers and enable the ORC unwinder, you get a nice performance
|
||||
improvement across the board, and still have reliable stack traces.
|
||||
|
||||
Ingo Molnar says:
|
||||
|
||||
"Note that it's not just a performance improvement, but also an
|
||||
instruction cache locality improvement: 3.2% .text savings almost
|
||||
directly transform into a similarly sized reduction in cache
|
||||
footprint. That can transform to even higher speedups for workloads
|
||||
whose cache locality is borderline."
|
||||
|
||||
Another benefit of ORC compared to frame pointers is that it can
|
||||
reliably unwind across interrupts and exceptions. Frame pointer based
|
||||
unwinds can sometimes skip the caller of the interrupted function, if it
|
||||
was a leaf function or if the interrupt hit before the frame pointer was
|
||||
saved.
|
||||
|
||||
The main disadvantage of the ORC unwinder compared to frame pointers is
|
||||
that it needs more memory to store the ORC unwind tables: roughly 2-4MB
|
||||
depending on the kernel config.
|
||||
|
||||
|
||||
ORC vs DWARF
|
||||
------------
|
||||
|
||||
ORC debuginfo's advantage over DWARF itself is that it's much simpler.
|
||||
It gets rid of the complex DWARF CFI state machine and also gets rid of
|
||||
the tracking of unnecessary registers. This allows the unwinder to be
|
||||
much simpler, meaning fewer bugs, which is especially important for
|
||||
mission critical oops code.
|
||||
|
||||
The simpler debuginfo format also enables the unwinder to be much faster
|
||||
than DWARF, which is important for perf and lockdep. In a basic
|
||||
performance test by Jiri Slaby [2], the ORC unwinder was about 20x
|
||||
faster than an out-of-tree DWARF unwinder. (Note: That measurement was
|
||||
taken before some performance tweaks were added, which doubled
|
||||
performance, so the speedup over DWARF may be closer to 40x.)
|
||||
|
||||
The ORC data format does have a few downsides compared to DWARF. ORC
|
||||
unwind tables take up ~50% more RAM (+1.3MB on an x86 defconfig kernel)
|
||||
than DWARF-based eh_frame tables.
|
||||
|
||||
Another potential downside is that, as GCC evolves, it's conceivable
|
||||
that the ORC data may end up being *too* simple to describe the state of
|
||||
the stack for certain optimizations. But IMO this is unlikely because
|
||||
GCC saves the frame pointer for any unusual stack adjustments it does,
|
||||
so I suspect we'll really only ever need to keep track of the stack
|
||||
pointer and the frame pointer between call frames. But even if we do
|
||||
end up having to track all the registers DWARF tracks, at least we will
|
||||
still be able to control the format, e.g. no complex state machines.
|
||||
|
||||
|
||||
ORC unwind table generation
|
||||
---------------------------
|
||||
|
||||
The ORC data is generated by objtool. With the existing compile-time
|
||||
stack metadata validation feature, objtool already follows all code
|
||||
paths, and so it already has all the information it needs to be able to
|
||||
generate ORC data from scratch. So it's an easy step to go from stack
|
||||
validation to ORC data generation.
|
||||
|
||||
It should be possible to instead generate the ORC data with a simple
|
||||
tool which converts DWARF to ORC data. However, such a solution would
|
||||
be incomplete due to the kernel's extensive use of asm, inline asm, and
|
||||
special sections like exception tables.
|
||||
|
||||
That could be rectified by manually annotating those special code paths
|
||||
using GNU assembler .cfi annotations in .S files, and homegrown
|
||||
annotations for inline asm in .c files. But asm annotations were tried
|
||||
in the past and were found to be unmaintainable. They were often
|
||||
incorrect/incomplete and made the code harder to read and keep updated.
|
||||
And based on looking at glibc code, annotating inline asm in .c files
|
||||
might be even worse.
|
||||
|
||||
Objtool still needs a few annotations, but only in code which does
|
||||
unusual things to the stack like entry code. And even then, far fewer
|
||||
annotations are needed than what DWARF would need, so they're much more
|
||||
maintainable than DWARF CFI annotations.
|
||||
|
||||
So the advantages of using objtool to generate ORC data are that it
|
||||
gives more accurate debuginfo, with very few annotations. It also
|
||||
insulates the kernel from toolchain bugs which can be very painful to
|
||||
deal with in the kernel since we often have to workaround issues in
|
||||
older versions of the toolchain for years.
|
||||
|
||||
The downside is that the unwinder now becomes dependent on objtool's
|
||||
ability to reverse engineer GCC code flow. If GCC optimizations become
|
||||
too complicated for objtool to follow, the ORC data generation might
|
||||
stop working or become incomplete. (It's worth noting that livepatch
|
||||
already has such a dependency on objtool's ability to follow GCC code
|
||||
flow.)
|
||||
|
||||
If newer versions of GCC come up with some optimizations which break
|
||||
objtool, we may need to revisit the current implementation. Some
|
||||
possible solutions would be asking GCC to make the optimizations more
|
||||
palatable, or having objtool use DWARF as an additional input, or
|
||||
creating a GCC plugin to assist objtool with its analysis. But for now,
|
||||
objtool follows GCC code quite well.
|
||||
|
||||
|
||||
Unwinder implementation details
|
||||
-------------------------------
|
||||
|
||||
Objtool generates the ORC data by integrating with the compile-time
|
||||
stack metadata validation feature, which is described in detail in
|
||||
tools/objtool/Documentation/stack-validation.txt. After analyzing all
|
||||
the code paths of a .o file, it creates an array of orc_entry structs,
|
||||
and a parallel array of instruction addresses associated with those
|
||||
structs, and writes them to the .orc_unwind and .orc_unwind_ip sections
|
||||
respectively.
|
||||
|
||||
The ORC data is split into the two arrays for performance reasons, to
|
||||
make the searchable part of the data (.orc_unwind_ip) more compact. The
|
||||
arrays are sorted in parallel at boot time.
|
||||
|
||||
Performance is further improved by the use of a fast lookup table which
|
||||
is created at runtime. The fast lookup table associates a given address
|
||||
with a range of indices for the .orc_unwind table, so that only a small
|
||||
subset of the table needs to be searched.
|
||||
|
||||
|
||||
Etymology
|
||||
---------
|
||||
|
||||
Orcs, fearsome creatures of medieval folklore, are the Dwarves' natural
|
||||
enemies. Similarly, the ORC unwinder was created in opposition to the
|
||||
complexity and slowness of DWARF.
|
||||
|
||||
"Although Orcs rarely consider multiple solutions to a problem, they do
|
||||
excel at getting things done because they are creatures of action, not
|
||||
thought." [3] Similarly, unlike the esoteric DWARF unwinder, the
|
||||
veracious ORC unwinder wastes no time or siloconic effort decoding
|
||||
variable-length zero-extended unsigned-integer byte-coded
|
||||
state-machine-based debug information entries.
|
||||
|
||||
Similar to how Orcs frequently unravel the well-intentioned plans of
|
||||
their adversaries, the ORC unwinder frequently unravels stacks with
|
||||
brutal, unyielding efficiency.
|
||||
|
||||
ORC stands for Oops Rewind Capability.
|
||||
|
||||
|
||||
[1] https://lkml.kernel.org/r/20170602104048.jkkzssljsompjdwy@suse.de
|
||||
[2] https://lkml.kernel.org/r/d2ca5435-6386-29b8-db87-7f227c2b713a@suse.cz
|
||||
[3] http://dustin.wikidot.com/half-orcs-and-orcs
|
||||
-11
@@ -7660,17 +7660,6 @@ T: git git://linuxtv.org/mkrufky/tuners.git
|
||||
S: Maintained
|
||||
F: drivers/media/dvb-frontends/lgdt3305.*
|
||||
|
||||
LGUEST
|
||||
M: Rusty Russell <rusty@rustcorp.com.au>
|
||||
L: lguest@lists.ozlabs.org
|
||||
W: http://lguest.ozlabs.org/
|
||||
S: Odd Fixes
|
||||
F: arch/x86/include/asm/lguest*.h
|
||||
F: arch/x86/lguest/
|
||||
F: drivers/lguest/
|
||||
F: include/linux/lguest*.h
|
||||
F: tools/lguest/
|
||||
|
||||
LIBATA PATA ARASAN COMPACT FLASH CONTROLLER
|
||||
M: Viresh Kumar <vireshk@kernel.org>
|
||||
L: linux-ide@vger.kernel.org
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef _ASM_UML_UNWIND_H
|
||||
#define _ASM_UML_UNWIND_H
|
||||
|
||||
static inline void
|
||||
unwind_module_init(struct module *mod, void *orc_ip, size_t orc_ip_size,
|
||||
void *orc, size_t orc_size) {}
|
||||
|
||||
#endif /* _ASM_UML_UNWIND_H */
|
||||
@@ -10,9 +10,6 @@ obj-$(CONFIG_XEN) += xen/
|
||||
# Hyper-V paravirtualization support
|
||||
obj-$(CONFIG_HYPERVISOR_GUEST) += hyperv/
|
||||
|
||||
# lguest paravirtualization support
|
||||
obj-$(CONFIG_LGUEST_GUEST) += lguest/
|
||||
|
||||
obj-y += realmode/
|
||||
obj-y += kernel/
|
||||
obj-y += mm/
|
||||
|
||||
+2
-4
@@ -73,7 +73,6 @@ config X86
|
||||
select ARCH_USE_QUEUED_RWLOCKS
|
||||
select ARCH_USE_QUEUED_SPINLOCKS
|
||||
select ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
|
||||
select ARCH_WANT_FRAME_POINTERS
|
||||
select ARCH_WANTS_DYNAMIC_TASK_STRUCT
|
||||
select ARCH_WANTS_THP_SWAP if X86_64
|
||||
select BUILDTIME_EXTABLE_SORT
|
||||
@@ -158,6 +157,7 @@ config X86
|
||||
select HAVE_MEMBLOCK
|
||||
select HAVE_MEMBLOCK_NODE_MAP
|
||||
select HAVE_MIXED_BREAKPOINTS_REGS
|
||||
select HAVE_MOD_ARCH_SPECIFIC
|
||||
select HAVE_NMI
|
||||
select HAVE_OPROFILE
|
||||
select HAVE_OPTPROBES
|
||||
@@ -168,7 +168,7 @@ config X86
|
||||
select HAVE_PERF_REGS
|
||||
select HAVE_PERF_USER_STACK_DUMP
|
||||
select HAVE_REGS_AND_STACK_ACCESS_API
|
||||
select HAVE_RELIABLE_STACKTRACE if X86_64 && FRAME_POINTER && STACK_VALIDATION
|
||||
select HAVE_RELIABLE_STACKTRACE if X86_64 && FRAME_POINTER_UNWINDER && STACK_VALIDATION
|
||||
select HAVE_STACK_VALIDATION if X86_64
|
||||
select HAVE_SYSCALL_TRACEPOINTS
|
||||
select HAVE_UNSTABLE_SCHED_CLOCK
|
||||
@@ -778,8 +778,6 @@ config KVM_DEBUG_FS
|
||||
Statistics are displayed in debugfs filesystem. Enabling this option
|
||||
may incur significant overhead.
|
||||
|
||||
source "arch/x86/lguest/Kconfig"
|
||||
|
||||
config PARAVIRT_TIME_ACCOUNTING
|
||||
bool "Paravirtual steal time accounting"
|
||||
depends on PARAVIRT
|
||||
|
||||
+57
-2
@@ -305,8 +305,6 @@ config DEBUG_ENTRY
|
||||
Some of these sanity checks may slow down kernel entries and
|
||||
exits or otherwise impact performance.
|
||||
|
||||
This is currently used to help test NMI code.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config DEBUG_NMI_SELFTEST
|
||||
@@ -358,4 +356,61 @@ config PUNIT_ATOM_DEBUG
|
||||
The current power state can be read from
|
||||
/sys/kernel/debug/punit_atom/dev_power_state
|
||||
|
||||
choice
|
||||
prompt "Choose kernel unwinder"
|
||||
default FRAME_POINTER_UNWINDER
|
||||
---help---
|
||||
This determines which method will be used for unwinding kernel stack
|
||||
traces for panics, oopses, bugs, warnings, perf, /proc/<pid>/stack,
|
||||
livepatch, lockdep, and more.
|
||||
|
||||
config FRAME_POINTER_UNWINDER
|
||||
bool "Frame pointer unwinder"
|
||||
select FRAME_POINTER
|
||||
---help---
|
||||
This option enables the frame pointer unwinder for unwinding kernel
|
||||
stack traces.
|
||||
|
||||
The unwinder itself is fast and it uses less RAM than the ORC
|
||||
unwinder, but the kernel text size will grow by ~3% and the kernel's
|
||||
overall performance will degrade by roughly 5-10%.
|
||||
|
||||
This option is recommended if you want to use the livepatch
|
||||
consistency model, as this is currently the only way to get a
|
||||
reliable stack trace (CONFIG_HAVE_RELIABLE_STACKTRACE).
|
||||
|
||||
config ORC_UNWINDER
|
||||
bool "ORC unwinder"
|
||||
depends on X86_64
|
||||
select STACK_VALIDATION
|
||||
---help---
|
||||
This option enables the ORC (Oops Rewind Capability) unwinder for
|
||||
unwinding kernel stack traces. It uses a custom data format which is
|
||||
a simplified version of the DWARF Call Frame Information standard.
|
||||
|
||||
This unwinder is more accurate across interrupt entry frames than the
|
||||
frame pointer unwinder. It also enables a 5-10% performance
|
||||
improvement across the entire kernel compared to frame pointers.
|
||||
|
||||
Enabling this option will increase the kernel's runtime memory usage
|
||||
by roughly 2-4MB, depending on your kernel config.
|
||||
|
||||
config GUESS_UNWINDER
|
||||
bool "Guess unwinder"
|
||||
depends on EXPERT
|
||||
---help---
|
||||
This option enables the "guess" unwinder for unwinding kernel stack
|
||||
traces. It scans the stack and reports every kernel text address it
|
||||
finds. Some of the addresses it reports may be incorrect.
|
||||
|
||||
While this option often produces false positives, it can still be
|
||||
useful in many cases. Unlike the other unwinders, it has no runtime
|
||||
overhead.
|
||||
|
||||
endchoice
|
||||
|
||||
config FRAME_POINTER
|
||||
depends on !ORC_UNWINDER && !GUESS_UNWINDER
|
||||
bool
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -61,71 +61,6 @@
|
||||
|
||||
__HEAD
|
||||
ENTRY(startup_32)
|
||||
#ifdef CONFIG_EFI_STUB
|
||||
jmp preferred_addr
|
||||
|
||||
/*
|
||||
* We don't need the return address, so set up the stack so
|
||||
* efi_main() can find its arguments.
|
||||
*/
|
||||
ENTRY(efi_pe_entry)
|
||||
add $0x4, %esp
|
||||
|
||||
call 1f
|
||||
1: popl %esi
|
||||
subl $1b, %esi
|
||||
|
||||
popl %ecx
|
||||
movl %ecx, efi32_config(%esi) /* Handle */
|
||||
popl %ecx
|
||||
movl %ecx, efi32_config+8(%esi) /* EFI System table pointer */
|
||||
|
||||
/* Relocate efi_config->call() */
|
||||
leal efi32_config(%esi), %eax
|
||||
add %esi, 40(%eax)
|
||||
pushl %eax
|
||||
|
||||
call make_boot_params
|
||||
cmpl $0, %eax
|
||||
je fail
|
||||
movl %esi, BP_code32_start(%eax)
|
||||
popl %ecx
|
||||
pushl %eax
|
||||
pushl %ecx
|
||||
jmp 2f /* Skip efi_config initialization */
|
||||
|
||||
ENTRY(efi32_stub_entry)
|
||||
add $0x4, %esp
|
||||
popl %ecx
|
||||
popl %edx
|
||||
|
||||
call 1f
|
||||
1: popl %esi
|
||||
subl $1b, %esi
|
||||
|
||||
movl %ecx, efi32_config(%esi) /* Handle */
|
||||
movl %edx, efi32_config+8(%esi) /* EFI System table pointer */
|
||||
|
||||
/* Relocate efi_config->call() */
|
||||
leal efi32_config(%esi), %eax
|
||||
add %esi, 40(%eax)
|
||||
pushl %eax
|
||||
2:
|
||||
call efi_main
|
||||
cmpl $0, %eax
|
||||
movl %eax, %esi
|
||||
jne 2f
|
||||
fail:
|
||||
/* EFI init failed, so hang. */
|
||||
hlt
|
||||
jmp fail
|
||||
2:
|
||||
movl BP_code32_start(%esi), %eax
|
||||
leal preferred_addr(%eax), %eax
|
||||
jmp *%eax
|
||||
|
||||
preferred_addr:
|
||||
#endif
|
||||
cld
|
||||
/*
|
||||
* Test KEEP_SEGMENTS flag to see if the bootloader is asking
|
||||
@@ -208,6 +143,70 @@ preferred_addr:
|
||||
jmp *%eax
|
||||
ENDPROC(startup_32)
|
||||
|
||||
#ifdef CONFIG_EFI_STUB
|
||||
/*
|
||||
* We don't need the return address, so set up the stack so efi_main() can find
|
||||
* its arguments.
|
||||
*/
|
||||
ENTRY(efi_pe_entry)
|
||||
add $0x4, %esp
|
||||
|
||||
call 1f
|
||||
1: popl %esi
|
||||
subl $1b, %esi
|
||||
|
||||
popl %ecx
|
||||
movl %ecx, efi32_config(%esi) /* Handle */
|
||||
popl %ecx
|
||||
movl %ecx, efi32_config+8(%esi) /* EFI System table pointer */
|
||||
|
||||
/* Relocate efi_config->call() */
|
||||
leal efi32_config(%esi), %eax
|
||||
add %esi, 40(%eax)
|
||||
pushl %eax
|
||||
|
||||
call make_boot_params
|
||||
cmpl $0, %eax
|
||||
je fail
|
||||
movl %esi, BP_code32_start(%eax)
|
||||
popl %ecx
|
||||
pushl %eax
|
||||
pushl %ecx
|
||||
jmp 2f /* Skip efi_config initialization */
|
||||
ENDPROC(efi_pe_entry)
|
||||
|
||||
ENTRY(efi32_stub_entry)
|
||||
add $0x4, %esp
|
||||
popl %ecx
|
||||
popl %edx
|
||||
|
||||
call 1f
|
||||
1: popl %esi
|
||||
subl $1b, %esi
|
||||
|
||||
movl %ecx, efi32_config(%esi) /* Handle */
|
||||
movl %edx, efi32_config+8(%esi) /* EFI System table pointer */
|
||||
|
||||
/* Relocate efi_config->call() */
|
||||
leal efi32_config(%esi), %eax
|
||||
add %esi, 40(%eax)
|
||||
pushl %eax
|
||||
2:
|
||||
call efi_main
|
||||
cmpl $0, %eax
|
||||
movl %eax, %esi
|
||||
jne 2f
|
||||
fail:
|
||||
/* EFI init failed, so hang. */
|
||||
hlt
|
||||
jmp fail
|
||||
2:
|
||||
movl BP_code32_start(%esi), %eax
|
||||
leal startup_32(%eax), %eax
|
||||
jmp *%eax
|
||||
ENDPROC(efi32_stub_entry)
|
||||
#endif
|
||||
|
||||
.text
|
||||
relocated:
|
||||
|
||||
|
||||
@@ -243,65 +243,6 @@ ENTRY(startup_64)
|
||||
* that maps our entire kernel(text+data+bss+brk), zero page
|
||||
* and command line.
|
||||
*/
|
||||
#ifdef CONFIG_EFI_STUB
|
||||
/*
|
||||
* The entry point for the PE/COFF executable is efi_pe_entry, so
|
||||
* only legacy boot loaders will execute this jmp.
|
||||
*/
|
||||
jmp preferred_addr
|
||||
|
||||
ENTRY(efi_pe_entry)
|
||||
movq %rcx, efi64_config(%rip) /* Handle */
|
||||
movq %rdx, efi64_config+8(%rip) /* EFI System table pointer */
|
||||
|
||||
leaq efi64_config(%rip), %rax
|
||||
movq %rax, efi_config(%rip)
|
||||
|
||||
call 1f
|
||||
1: popq %rbp
|
||||
subq $1b, %rbp
|
||||
|
||||
/*
|
||||
* Relocate efi_config->call().
|
||||
*/
|
||||
addq %rbp, efi64_config+40(%rip)
|
||||
|
||||
movq %rax, %rdi
|
||||
call make_boot_params
|
||||
cmpq $0,%rax
|
||||
je fail
|
||||
mov %rax, %rsi
|
||||
leaq startup_32(%rip), %rax
|
||||
movl %eax, BP_code32_start(%rsi)
|
||||
jmp 2f /* Skip the relocation */
|
||||
|
||||
handover_entry:
|
||||
call 1f
|
||||
1: popq %rbp
|
||||
subq $1b, %rbp
|
||||
|
||||
/*
|
||||
* Relocate efi_config->call().
|
||||
*/
|
||||
movq efi_config(%rip), %rax
|
||||
addq %rbp, 40(%rax)
|
||||
2:
|
||||
movq efi_config(%rip), %rdi
|
||||
call efi_main
|
||||
movq %rax,%rsi
|
||||
cmpq $0,%rax
|
||||
jne 2f
|
||||
fail:
|
||||
/* EFI init failed, so hang. */
|
||||
hlt
|
||||
jmp fail
|
||||
2:
|
||||
movl BP_code32_start(%esi), %eax
|
||||
leaq preferred_addr(%rax), %rax
|
||||
jmp *%rax
|
||||
|
||||
preferred_addr:
|
||||
#endif
|
||||
|
||||
/* Setup data segments. */
|
||||
xorl %eax, %eax
|
||||
@@ -413,6 +354,59 @@ lvl5:
|
||||
jmp *%rax
|
||||
|
||||
#ifdef CONFIG_EFI_STUB
|
||||
|
||||
/* The entry point for the PE/COFF executable is efi_pe_entry. */
|
||||
ENTRY(efi_pe_entry)
|
||||
movq %rcx, efi64_config(%rip) /* Handle */
|
||||
movq %rdx, efi64_config+8(%rip) /* EFI System table pointer */
|
||||
|
||||
leaq efi64_config(%rip), %rax
|
||||
movq %rax, efi_config(%rip)
|
||||
|
||||
call 1f
|
||||
1: popq %rbp
|
||||
subq $1b, %rbp
|
||||
|
||||
/*
|
||||
* Relocate efi_config->call().
|
||||
*/
|
||||
addq %rbp, efi64_config+40(%rip)
|
||||
|
||||
movq %rax, %rdi
|
||||
call make_boot_params
|
||||
cmpq $0,%rax
|
||||
je fail
|
||||
mov %rax, %rsi
|
||||
leaq startup_32(%rip), %rax
|
||||
movl %eax, BP_code32_start(%rsi)
|
||||
jmp 2f /* Skip the relocation */
|
||||
|
||||
handover_entry:
|
||||
call 1f
|
||||
1: popq %rbp
|
||||
subq $1b, %rbp
|
||||
|
||||
/*
|
||||
* Relocate efi_config->call().
|
||||
*/
|
||||
movq efi_config(%rip), %rax
|
||||
addq %rbp, 40(%rax)
|
||||
2:
|
||||
movq efi_config(%rip), %rdi
|
||||
call efi_main
|
||||
movq %rax,%rsi
|
||||
cmpq $0,%rax
|
||||
jne 2f
|
||||
fail:
|
||||
/* EFI init failed, so hang. */
|
||||
hlt
|
||||
jmp fail
|
||||
2:
|
||||
movl BP_code32_start(%esi), %eax
|
||||
leaq startup_64(%rax), %rax
|
||||
jmp *%rax
|
||||
ENDPROC(efi_pe_entry)
|
||||
|
||||
.org 0x390
|
||||
ENTRY(efi64_stub_entry)
|
||||
movq %rdi, efi64_config(%rip) /* Handle */
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
CONFIG_NOHIGHMEM=y
|
||||
# CONFIG_HIGHMEM4G is not set
|
||||
# CONFIG_HIGHMEM64G is not set
|
||||
CONFIG_GUESS_UNWINDER=y
|
||||
# CONFIG_FRAME_POINTER_UNWINDER is not set
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
# Makefile for the x86 low level entry code
|
||||
#
|
||||
|
||||
OBJECT_FILES_NON_STANDARD_entry_$(BITS).o := y
|
||||
OBJECT_FILES_NON_STANDARD_entry_64_compat.o := y
|
||||
|
||||
CFLAGS_syscall_64.o += $(call cc-option,-Wno-override-init,)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <linux/jump_label.h>
|
||||
#include <asm/unwind_hints.h>
|
||||
|
||||
/*
|
||||
|
||||
@@ -112,6 +113,7 @@ For 32-bit we have the following conventions - kernel is built with
|
||||
movq %rdx, 12*8+\offset(%rsp)
|
||||
movq %rsi, 13*8+\offset(%rsp)
|
||||
movq %rdi, 14*8+\offset(%rsp)
|
||||
UNWIND_HINT_REGS offset=\offset extra=0
|
||||
.endm
|
||||
.macro SAVE_C_REGS offset=0
|
||||
SAVE_C_REGS_HELPER \offset, 1, 1, 1, 1
|
||||
@@ -136,6 +138,7 @@ For 32-bit we have the following conventions - kernel is built with
|
||||
movq %r12, 3*8+\offset(%rsp)
|
||||
movq %rbp, 4*8+\offset(%rsp)
|
||||
movq %rbx, 5*8+\offset(%rsp)
|
||||
UNWIND_HINT_REGS offset=\offset
|
||||
.endm
|
||||
|
||||
.macro RESTORE_EXTRA_REGS offset=0
|
||||
@@ -145,6 +148,7 @@ For 32-bit we have the following conventions - kernel is built with
|
||||
movq 3*8+\offset(%rsp), %r12
|
||||
movq 4*8+\offset(%rsp), %rbp
|
||||
movq 5*8+\offset(%rsp), %rbx
|
||||
UNWIND_HINT_REGS offset=\offset extra=0
|
||||
.endm
|
||||
|
||||
.macro RESTORE_C_REGS_HELPER rstor_rax=1, rstor_rcx=1, rstor_r11=1, rstor_r8910=1, rstor_rdx=1
|
||||
@@ -167,6 +171,7 @@ For 32-bit we have the following conventions - kernel is built with
|
||||
.endif
|
||||
movq 13*8(%rsp), %rsi
|
||||
movq 14*8(%rsp), %rdi
|
||||
UNWIND_HINT_IRET_REGS offset=16*8
|
||||
.endm
|
||||
.macro RESTORE_C_REGS
|
||||
RESTORE_C_REGS_HELPER 1,1,1,1,1
|
||||
|
||||
+142
-37
@@ -36,6 +36,7 @@
|
||||
#include <asm/smap.h>
|
||||
#include <asm/pgtable_types.h>
|
||||
#include <asm/export.h>
|
||||
#include <asm/frame.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
.code64
|
||||
@@ -43,9 +44,10 @@
|
||||
|
||||
#ifdef CONFIG_PARAVIRT
|
||||
ENTRY(native_usergs_sysret64)
|
||||
UNWIND_HINT_EMPTY
|
||||
swapgs
|
||||
sysretq
|
||||
ENDPROC(native_usergs_sysret64)
|
||||
END(native_usergs_sysret64)
|
||||
#endif /* CONFIG_PARAVIRT */
|
||||
|
||||
.macro TRACE_IRQS_IRETQ
|
||||
@@ -134,19 +136,14 @@ ENDPROC(native_usergs_sysret64)
|
||||
*/
|
||||
|
||||
ENTRY(entry_SYSCALL_64)
|
||||
UNWIND_HINT_EMPTY
|
||||
/*
|
||||
* Interrupts are off on entry.
|
||||
* We do not frame this tiny irq-off block with TRACE_IRQS_OFF/ON,
|
||||
* it is too small to ever cause noticeable irq latency.
|
||||
*/
|
||||
SWAPGS_UNSAFE_STACK
|
||||
/*
|
||||
* A hypervisor implementation might want to use a label
|
||||
* after the swapgs, so that it can do the swapgs
|
||||
* for the guest and jump here on syscall.
|
||||
*/
|
||||
GLOBAL(entry_SYSCALL_64_after_swapgs)
|
||||
|
||||
swapgs
|
||||
movq %rsp, PER_CPU_VAR(rsp_scratch)
|
||||
movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
|
||||
|
||||
@@ -158,6 +155,7 @@ GLOBAL(entry_SYSCALL_64_after_swapgs)
|
||||
pushq %r11 /* pt_regs->flags */
|
||||
pushq $__USER_CS /* pt_regs->cs */
|
||||
pushq %rcx /* pt_regs->ip */
|
||||
GLOBAL(entry_SYSCALL_64_after_hwframe)
|
||||
pushq %rax /* pt_regs->orig_ax */
|
||||
pushq %rdi /* pt_regs->di */
|
||||
pushq %rsi /* pt_regs->si */
|
||||
@@ -169,6 +167,7 @@ GLOBAL(entry_SYSCALL_64_after_swapgs)
|
||||
pushq %r10 /* pt_regs->r10 */
|
||||
pushq %r11 /* pt_regs->r11 */
|
||||
sub $(6*8), %rsp /* pt_regs->bp, bx, r12-15 not saved */
|
||||
UNWIND_HINT_REGS extra=0
|
||||
|
||||
/*
|
||||
* If we need to do entry work or if we guess we'll need to do
|
||||
@@ -223,6 +222,7 @@ entry_SYSCALL_64_fastpath:
|
||||
movq EFLAGS(%rsp), %r11
|
||||
RESTORE_C_REGS_EXCEPT_RCX_R11
|
||||
movq RSP(%rsp), %rsp
|
||||
UNWIND_HINT_EMPTY
|
||||
USERGS_SYSRET64
|
||||
|
||||
1:
|
||||
@@ -316,6 +316,7 @@ syscall_return_via_sysret:
|
||||
/* rcx and r11 are already restored (see code above) */
|
||||
RESTORE_C_REGS_EXCEPT_RCX_R11
|
||||
movq RSP(%rsp), %rsp
|
||||
UNWIND_HINT_EMPTY
|
||||
USERGS_SYSRET64
|
||||
|
||||
opportunistic_sysret_failed:
|
||||
@@ -343,6 +344,7 @@ ENTRY(stub_ptregs_64)
|
||||
DISABLE_INTERRUPTS(CLBR_ANY)
|
||||
TRACE_IRQS_OFF
|
||||
popq %rax
|
||||
UNWIND_HINT_REGS extra=0
|
||||
jmp entry_SYSCALL64_slow_path
|
||||
|
||||
1:
|
||||
@@ -351,6 +353,7 @@ END(stub_ptregs_64)
|
||||
|
||||
.macro ptregs_stub func
|
||||
ENTRY(ptregs_\func)
|
||||
UNWIND_HINT_FUNC
|
||||
leaq \func(%rip), %rax
|
||||
jmp stub_ptregs_64
|
||||
END(ptregs_\func)
|
||||
@@ -367,6 +370,7 @@ END(ptregs_\func)
|
||||
* %rsi: next task
|
||||
*/
|
||||
ENTRY(__switch_to_asm)
|
||||
UNWIND_HINT_FUNC
|
||||
/*
|
||||
* Save callee-saved registers
|
||||
* This must match the order in inactive_task_frame
|
||||
@@ -406,6 +410,7 @@ END(__switch_to_asm)
|
||||
* r12: kernel thread arg
|
||||
*/
|
||||
ENTRY(ret_from_fork)
|
||||
UNWIND_HINT_EMPTY
|
||||
movq %rax, %rdi
|
||||
call schedule_tail /* rdi: 'prev' task parameter */
|
||||
|
||||
@@ -413,6 +418,7 @@ ENTRY(ret_from_fork)
|
||||
jnz 1f /* kernel threads are uncommon */
|
||||
|
||||
2:
|
||||
UNWIND_HINT_REGS
|
||||
movq %rsp, %rdi
|
||||
call syscall_return_slowpath /* returns with IRQs disabled */
|
||||
TRACE_IRQS_ON /* user mode is traced as IRQS on */
|
||||
@@ -440,13 +446,102 @@ END(ret_from_fork)
|
||||
ENTRY(irq_entries_start)
|
||||
vector=FIRST_EXTERNAL_VECTOR
|
||||
.rept (FIRST_SYSTEM_VECTOR - FIRST_EXTERNAL_VECTOR)
|
||||
UNWIND_HINT_IRET_REGS
|
||||
pushq $(~vector+0x80) /* Note: always in signed byte range */
|
||||
vector=vector+1
|
||||
jmp common_interrupt
|
||||
.align 8
|
||||
vector=vector+1
|
||||
.endr
|
||||
END(irq_entries_start)
|
||||
|
||||
.macro DEBUG_ENTRY_ASSERT_IRQS_OFF
|
||||
#ifdef CONFIG_DEBUG_ENTRY
|
||||
pushfq
|
||||
testl $X86_EFLAGS_IF, (%rsp)
|
||||
jz .Lokay_\@
|
||||
ud2
|
||||
.Lokay_\@:
|
||||
addq $8, %rsp
|
||||
#endif
|
||||
.endm
|
||||
|
||||
/*
|
||||
* Enters the IRQ stack if we're not already using it. NMI-safe. Clobbers
|
||||
* flags and puts old RSP into old_rsp, and leaves all other GPRs alone.
|
||||
* Requires kernel GSBASE.
|
||||
*
|
||||
* The invariant is that, if irq_count != -1, then the IRQ stack is in use.
|
||||
*/
|
||||
.macro ENTER_IRQ_STACK regs=1 old_rsp
|
||||
DEBUG_ENTRY_ASSERT_IRQS_OFF
|
||||
movq %rsp, \old_rsp
|
||||
|
||||
.if \regs
|
||||
UNWIND_HINT_REGS base=\old_rsp
|
||||
.endif
|
||||
|
||||
incl PER_CPU_VAR(irq_count)
|
||||
jnz .Lirq_stack_push_old_rsp_\@
|
||||
|
||||
/*
|
||||
* Right now, if we just incremented irq_count to zero, we've
|
||||
* claimed the IRQ stack but we haven't switched to it yet.
|
||||
*
|
||||
* If anything is added that can interrupt us here without using IST,
|
||||
* it must be *extremely* careful to limit its stack usage. This
|
||||
* could include kprobes and a hypothetical future IST-less #DB
|
||||
* handler.
|
||||
*
|
||||
* The OOPS unwinder relies on the word at the top of the IRQ
|
||||
* stack linking back to the previous RSP for the entire time we're
|
||||
* on the IRQ stack. For this to work reliably, we need to write
|
||||
* it before we actually move ourselves to the IRQ stack.
|
||||
*/
|
||||
|
||||
movq \old_rsp, PER_CPU_VAR(irq_stack_union + IRQ_STACK_SIZE - 8)
|
||||
movq PER_CPU_VAR(irq_stack_ptr), %rsp
|
||||
|
||||
#ifdef CONFIG_DEBUG_ENTRY
|
||||
/*
|
||||
* If the first movq above becomes wrong due to IRQ stack layout
|
||||
* changes, the only way we'll notice is if we try to unwind right
|
||||
* here. Assert that we set up the stack right to catch this type
|
||||
* of bug quickly.
|
||||
*/
|
||||
cmpq -8(%rsp), \old_rsp
|
||||
je .Lirq_stack_okay\@
|
||||
ud2
|
||||
.Lirq_stack_okay\@:
|
||||
#endif
|
||||
|
||||
.Lirq_stack_push_old_rsp_\@:
|
||||
pushq \old_rsp
|
||||
|
||||
.if \regs
|
||||
UNWIND_HINT_REGS indirect=1
|
||||
.endif
|
||||
.endm
|
||||
|
||||
/*
|
||||
* Undoes ENTER_IRQ_STACK.
|
||||
*/
|
||||
.macro LEAVE_IRQ_STACK regs=1
|
||||
DEBUG_ENTRY_ASSERT_IRQS_OFF
|
||||
/* We need to be off the IRQ stack before decrementing irq_count. */
|
||||
popq %rsp
|
||||
|
||||
.if \regs
|
||||
UNWIND_HINT_REGS
|
||||
.endif
|
||||
|
||||
/*
|
||||
* As in ENTER_IRQ_STACK, irq_count == 0, we are still claiming
|
||||
* the irq stack but we're not on it.
|
||||
*/
|
||||
|
||||
decl PER_CPU_VAR(irq_count)
|
||||
.endm
|
||||
|
||||
/*
|
||||
* Interrupt entry/exit.
|
||||
*
|
||||
@@ -485,17 +580,7 @@ END(irq_entries_start)
|
||||
CALL_enter_from_user_mode
|
||||
|
||||
1:
|
||||
/*
|
||||
* Save previous stack pointer, optionally switch to interrupt stack.
|
||||
* irq_count is used to check if a CPU is already on an interrupt stack
|
||||
* or not. While this is essentially redundant with preempt_count it is
|
||||
* a little cheaper to use a separate counter in the PDA (short of
|
||||
* moving irq_enter into assembly, which would be too much work)
|
||||
*/
|
||||
movq %rsp, %rdi
|
||||
incl PER_CPU_VAR(irq_count)
|
||||
cmovzq PER_CPU_VAR(irq_stack_ptr), %rsp
|
||||
pushq %rdi
|
||||
ENTER_IRQ_STACK old_rsp=%rdi
|
||||
/* We entered an interrupt context - irqs are off: */
|
||||
TRACE_IRQS_OFF
|
||||
|
||||
@@ -515,10 +600,8 @@ common_interrupt:
|
||||
ret_from_intr:
|
||||
DISABLE_INTERRUPTS(CLBR_ANY)
|
||||
TRACE_IRQS_OFF
|
||||
decl PER_CPU_VAR(irq_count)
|
||||
|
||||
/* Restore saved previous stack */
|
||||
popq %rsp
|
||||
LEAVE_IRQ_STACK
|
||||
|
||||
testb $3, CS(%rsp)
|
||||
jz retint_kernel
|
||||
@@ -561,6 +644,7 @@ restore_c_regs_and_iret:
|
||||
INTERRUPT_RETURN
|
||||
|
||||
ENTRY(native_iret)
|
||||
UNWIND_HINT_IRET_REGS
|
||||
/*
|
||||
* Are we returning to a stack segment from the LDT? Note: in
|
||||
* 64-bit mode SS:RSP on the exception stack is always valid.
|
||||
@@ -633,6 +717,7 @@ native_irq_return_ldt:
|
||||
orq PER_CPU_VAR(espfix_stack), %rax
|
||||
SWAPGS
|
||||
movq %rax, %rsp
|
||||
UNWIND_HINT_IRET_REGS offset=8
|
||||
|
||||
/*
|
||||
* At this point, we cannot write to the stack any more, but we can
|
||||
@@ -654,6 +739,7 @@ END(common_interrupt)
|
||||
*/
|
||||
.macro apicinterrupt3 num sym do_sym
|
||||
ENTRY(\sym)
|
||||
UNWIND_HINT_IRET_REGS
|
||||
ASM_CLAC
|
||||
pushq $~(\num)
|
||||
.Lcommon_\sym:
|
||||
@@ -735,6 +821,8 @@ apicinterrupt IRQ_WORK_VECTOR irq_work_interrupt smp_irq_work_interrupt
|
||||
|
||||
.macro idtentry sym do_sym has_error_code:req paranoid=0 shift_ist=-1
|
||||
ENTRY(\sym)
|
||||
UNWIND_HINT_IRET_REGS offset=8
|
||||
|
||||
/* Sanity check */
|
||||
.if \shift_ist != -1 && \paranoid == 0
|
||||
.error "using shift_ist requires paranoid=1"
|
||||
@@ -758,6 +846,7 @@ ENTRY(\sym)
|
||||
.else
|
||||
call error_entry
|
||||
.endif
|
||||
UNWIND_HINT_REGS
|
||||
/* returned flag: ebx=0: need swapgs on exit, ebx=1: don't need it */
|
||||
|
||||
.if \paranoid
|
||||
@@ -855,6 +944,7 @@ idtentry simd_coprocessor_error do_simd_coprocessor_error has_error_code=0
|
||||
* edi: new selector
|
||||
*/
|
||||
ENTRY(native_load_gs_index)
|
||||
FRAME_BEGIN
|
||||
pushfq
|
||||
DISABLE_INTERRUPTS(CLBR_ANY & ~CLBR_RDI)
|
||||
SWAPGS
|
||||
@@ -863,8 +953,9 @@ ENTRY(native_load_gs_index)
|
||||
2: ALTERNATIVE "", "mfence", X86_BUG_SWAPGS_FENCE
|
||||
SWAPGS
|
||||
popfq
|
||||
FRAME_END
|
||||
ret
|
||||
END(native_load_gs_index)
|
||||
ENDPROC(native_load_gs_index)
|
||||
EXPORT_SYMBOL(native_load_gs_index)
|
||||
|
||||
_ASM_EXTABLE(.Lgs_change, bad_gs)
|
||||
@@ -887,14 +978,12 @@ bad_gs:
|
||||
ENTRY(do_softirq_own_stack)
|
||||
pushq %rbp
|
||||
mov %rsp, %rbp
|
||||
incl PER_CPU_VAR(irq_count)
|
||||
cmove PER_CPU_VAR(irq_stack_ptr), %rsp
|
||||
push %rbp /* frame pointer backlink */
|
||||
ENTER_IRQ_STACK regs=0 old_rsp=%r11
|
||||
call __do_softirq
|
||||
LEAVE_IRQ_STACK regs=0
|
||||
leaveq
|
||||
decl PER_CPU_VAR(irq_count)
|
||||
ret
|
||||
END(do_softirq_own_stack)
|
||||
ENDPROC(do_softirq_own_stack)
|
||||
|
||||
#ifdef CONFIG_XEN
|
||||
idtentry xen_hypervisor_callback xen_do_hypervisor_callback has_error_code=0
|
||||
@@ -918,14 +1007,14 @@ ENTRY(xen_do_hypervisor_callback) /* do_hypervisor_callback(struct *pt_regs) */
|
||||
* Since we don't modify %rdi, evtchn_do_upall(struct *pt_regs) will
|
||||
* see the correct pointer to the pt_regs
|
||||
*/
|
||||
UNWIND_HINT_FUNC
|
||||
movq %rdi, %rsp /* we don't return, adjust the stack frame */
|
||||
11: incl PER_CPU_VAR(irq_count)
|
||||
movq %rsp, %rbp
|
||||
cmovzq PER_CPU_VAR(irq_stack_ptr), %rsp
|
||||
pushq %rbp /* frame pointer backlink */
|
||||
UNWIND_HINT_REGS
|
||||
|
||||
ENTER_IRQ_STACK old_rsp=%r10
|
||||
call xen_evtchn_do_upcall
|
||||
popq %rsp
|
||||
decl PER_CPU_VAR(irq_count)
|
||||
LEAVE_IRQ_STACK
|
||||
|
||||
#ifndef CONFIG_PREEMPT
|
||||
call xen_maybe_preempt_hcall
|
||||
#endif
|
||||
@@ -946,6 +1035,7 @@ END(xen_do_hypervisor_callback)
|
||||
* with its current contents: any discrepancy means we in category 1.
|
||||
*/
|
||||
ENTRY(xen_failsafe_callback)
|
||||
UNWIND_HINT_EMPTY
|
||||
movl %ds, %ecx
|
||||
cmpw %cx, 0x10(%rsp)
|
||||
jne 1f
|
||||
@@ -965,11 +1055,13 @@ ENTRY(xen_failsafe_callback)
|
||||
pushq $0 /* RIP */
|
||||
pushq %r11
|
||||
pushq %rcx
|
||||
UNWIND_HINT_IRET_REGS offset=8
|
||||
jmp general_protection
|
||||
1: /* Segment mismatch => Category 1 (Bad segment). Retry the IRET. */
|
||||
movq (%rsp), %rcx
|
||||
movq 8(%rsp), %r11
|
||||
addq $0x30, %rsp
|
||||
UNWIND_HINT_IRET_REGS
|
||||
pushq $-1 /* orig_ax = -1 => not a system call */
|
||||
ALLOC_PT_GPREGS_ON_STACK
|
||||
SAVE_C_REGS
|
||||
@@ -1015,6 +1107,7 @@ idtentry machine_check has_error_code=0 paranoid=1 do_sym=*machine_check_vec
|
||||
* Return: ebx=0: need swapgs on exit, ebx=1: otherwise
|
||||
*/
|
||||
ENTRY(paranoid_entry)
|
||||
UNWIND_HINT_FUNC
|
||||
cld
|
||||
SAVE_C_REGS 8
|
||||
SAVE_EXTRA_REGS 8
|
||||
@@ -1042,6 +1135,7 @@ END(paranoid_entry)
|
||||
* On entry, ebx is "no swapgs" flag (1: don't need swapgs, 0: need it)
|
||||
*/
|
||||
ENTRY(paranoid_exit)
|
||||
UNWIND_HINT_REGS
|
||||
DISABLE_INTERRUPTS(CLBR_ANY)
|
||||
TRACE_IRQS_OFF_DEBUG
|
||||
testl %ebx, %ebx /* swapgs needed? */
|
||||
@@ -1063,6 +1157,7 @@ END(paranoid_exit)
|
||||
* Return: EBX=0: came from user mode; EBX=1: otherwise
|
||||
*/
|
||||
ENTRY(error_entry)
|
||||
UNWIND_HINT_FUNC
|
||||
cld
|
||||
SAVE_C_REGS 8
|
||||
SAVE_EXTRA_REGS 8
|
||||
@@ -1147,6 +1242,7 @@ END(error_entry)
|
||||
* 0: user gsbase is loaded, we need SWAPGS and standard preparation for return to usermode
|
||||
*/
|
||||
ENTRY(error_exit)
|
||||
UNWIND_HINT_REGS
|
||||
DISABLE_INTERRUPTS(CLBR_ANY)
|
||||
TRACE_IRQS_OFF
|
||||
testl %ebx, %ebx
|
||||
@@ -1156,6 +1252,7 @@ END(error_exit)
|
||||
|
||||
/* Runs on exception stack */
|
||||
ENTRY(nmi)
|
||||
UNWIND_HINT_IRET_REGS
|
||||
/*
|
||||
* Fix up the exception frame if we're on Xen.
|
||||
* PARAVIRT_ADJUST_EXCEPTION_FRAME is guaranteed to push at most
|
||||
@@ -1229,11 +1326,13 @@ ENTRY(nmi)
|
||||
cld
|
||||
movq %rsp, %rdx
|
||||
movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
|
||||
UNWIND_HINT_IRET_REGS base=%rdx offset=8
|
||||
pushq 5*8(%rdx) /* pt_regs->ss */
|
||||
pushq 4*8(%rdx) /* pt_regs->rsp */
|
||||
pushq 3*8(%rdx) /* pt_regs->flags */
|
||||
pushq 2*8(%rdx) /* pt_regs->cs */
|
||||
pushq 1*8(%rdx) /* pt_regs->rip */
|
||||
UNWIND_HINT_IRET_REGS
|
||||
pushq $-1 /* pt_regs->orig_ax */
|
||||
pushq %rdi /* pt_regs->di */
|
||||
pushq %rsi /* pt_regs->si */
|
||||
@@ -1250,6 +1349,7 @@ ENTRY(nmi)
|
||||
pushq %r13 /* pt_regs->r13 */
|
||||
pushq %r14 /* pt_regs->r14 */
|
||||
pushq %r15 /* pt_regs->r15 */
|
||||
UNWIND_HINT_REGS
|
||||
ENCODE_FRAME_POINTER
|
||||
|
||||
/*
|
||||
@@ -1404,6 +1504,7 @@ first_nmi:
|
||||
.rept 5
|
||||
pushq 11*8(%rsp)
|
||||
.endr
|
||||
UNWIND_HINT_IRET_REGS
|
||||
|
||||
/* Everything up to here is safe from nested NMIs */
|
||||
|
||||
@@ -1419,6 +1520,7 @@ first_nmi:
|
||||
pushq $__KERNEL_CS /* CS */
|
||||
pushq $1f /* RIP */
|
||||
INTERRUPT_RETURN /* continues at repeat_nmi below */
|
||||
UNWIND_HINT_IRET_REGS
|
||||
1:
|
||||
#endif
|
||||
|
||||
@@ -1468,6 +1570,7 @@ end_repeat_nmi:
|
||||
* exceptions might do.
|
||||
*/
|
||||
call paranoid_entry
|
||||
UNWIND_HINT_REGS
|
||||
|
||||
/* paranoidentry do_nmi, 0; without TRACE_IRQS_OFF */
|
||||
movq %rsp, %rdi
|
||||
@@ -1505,17 +1608,19 @@ nmi_restore:
|
||||
END(nmi)
|
||||
|
||||
ENTRY(ignore_sysret)
|
||||
UNWIND_HINT_EMPTY
|
||||
mov $-ENOSYS, %eax
|
||||
sysret
|
||||
END(ignore_sysret)
|
||||
|
||||
ENTRY(rewind_stack_do_exit)
|
||||
UNWIND_HINT_FUNC
|
||||
/* Prevent any naive code from trying to unwind to our caller. */
|
||||
xorl %ebp, %ebp
|
||||
|
||||
movq PER_CPU_VAR(cpu_current_top_of_stack), %rax
|
||||
leaq -TOP_OF_KERNEL_STACK_PADDING-PTREGS_SIZE(%rax), %rsp
|
||||
leaq -PTREGS_SIZE(%rax), %rsp
|
||||
UNWIND_HINT_FUNC sp_offset=PTREGS_SIZE
|
||||
|
||||
call do_exit
|
||||
1: jmp 1b
|
||||
END(rewind_stack_do_exit)
|
||||
|
||||
@@ -183,21 +183,20 @@ ENDPROC(entry_SYSENTER_compat)
|
||||
*/
|
||||
ENTRY(entry_SYSCALL_compat)
|
||||
/* Interrupts are off on entry. */
|
||||
SWAPGS_UNSAFE_STACK
|
||||
swapgs
|
||||
|
||||
/* Stash user ESP and switch to the kernel stack. */
|
||||
movl %esp, %r8d
|
||||
movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
|
||||
|
||||
/* Zero-extending 32-bit regs, do not remove */
|
||||
movl %eax, %eax
|
||||
|
||||
/* Construct struct pt_regs on stack */
|
||||
pushq $__USER32_DS /* pt_regs->ss */
|
||||
pushq %r8 /* pt_regs->sp */
|
||||
pushq %r11 /* pt_regs->flags */
|
||||
pushq $__USER32_CS /* pt_regs->cs */
|
||||
pushq %rcx /* pt_regs->ip */
|
||||
GLOBAL(entry_SYSCALL_compat_after_hwframe)
|
||||
movl %eax, %eax /* discard orig_ax high bits */
|
||||
pushq %rax /* pt_regs->orig_ax */
|
||||
pushq %rdi /* pt_regs->di */
|
||||
pushq %rsi /* pt_regs->si */
|
||||
@@ -342,8 +341,7 @@ ENTRY(entry_INT80_compat)
|
||||
jmp restore_regs_and_iret
|
||||
END(entry_INT80_compat)
|
||||
|
||||
ALIGN
|
||||
GLOBAL(stub32_clone)
|
||||
ENTRY(stub32_clone)
|
||||
/*
|
||||
* The 32-bit clone ABI is: clone(..., int tls_val, int *child_tidptr).
|
||||
* The 64-bit clone ABI is: clone(..., int *child_tidptr, int tls_val).
|
||||
@@ -353,3 +351,4 @@ GLOBAL(stub32_clone)
|
||||
*/
|
||||
xchg %r8, %rcx
|
||||
jmp sys_clone
|
||||
ENDPROC(stub32_clone)
|
||||
|
||||
@@ -226,7 +226,7 @@ static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs,
|
||||
if (ksig->ka.sa.sa_flags & SA_ONSTACK)
|
||||
sp = sigsp(sp, ksig);
|
||||
/* This is the legacy signal stack switching. */
|
||||
else if ((regs->ss & 0xffff) != __USER32_DS &&
|
||||
else if (regs->ss != __USER32_DS &&
|
||||
!(ksig->ka.sa.sa_flags & SA_RESTORER) &&
|
||||
ksig->ka.sa.sa_restorer)
|
||||
sp = (unsigned long) ksig->ka.sa.sa_restorer;
|
||||
|
||||
@@ -126,15 +126,15 @@ do { \
|
||||
pr_reg[4] = regs->di; \
|
||||
pr_reg[5] = regs->bp; \
|
||||
pr_reg[6] = regs->ax; \
|
||||
pr_reg[7] = regs->ds & 0xffff; \
|
||||
pr_reg[8] = regs->es & 0xffff; \
|
||||
pr_reg[9] = regs->fs & 0xffff; \
|
||||
pr_reg[7] = regs->ds; \
|
||||
pr_reg[8] = regs->es; \
|
||||
pr_reg[9] = regs->fs; \
|
||||
pr_reg[11] = regs->orig_ax; \
|
||||
pr_reg[12] = regs->ip; \
|
||||
pr_reg[13] = regs->cs & 0xffff; \
|
||||
pr_reg[13] = regs->cs; \
|
||||
pr_reg[14] = regs->flags; \
|
||||
pr_reg[15] = regs->sp; \
|
||||
pr_reg[16] = regs->ss & 0xffff; \
|
||||
pr_reg[16] = regs->ss; \
|
||||
} while (0);
|
||||
|
||||
#define ELF_CORE_COPY_REGS(pr_reg, regs) \
|
||||
@@ -204,6 +204,7 @@ void set_personality_ia32(bool);
|
||||
|
||||
#define ELF_CORE_COPY_REGS(pr_reg, regs) \
|
||||
do { \
|
||||
unsigned long base; \
|
||||
unsigned v; \
|
||||
(pr_reg)[0] = (regs)->r15; \
|
||||
(pr_reg)[1] = (regs)->r14; \
|
||||
@@ -226,8 +227,8 @@ do { \
|
||||
(pr_reg)[18] = (regs)->flags; \
|
||||
(pr_reg)[19] = (regs)->sp; \
|
||||
(pr_reg)[20] = (regs)->ss; \
|
||||
(pr_reg)[21] = current->thread.fsbase; \
|
||||
(pr_reg)[22] = current->thread.gsbase; \
|
||||
rdmsrl(MSR_FS_BASE, base); (pr_reg)[21] = base; \
|
||||
rdmsrl(MSR_KERNEL_GS_BASE, base); (pr_reg)[22] = base; \
|
||||
asm("movl %%ds,%0" : "=r" (v)); (pr_reg)[23] = v; \
|
||||
asm("movl %%es,%0" : "=r" (v)); (pr_reg)[24] = v; \
|
||||
asm("movl %%fs,%0" : "=r" (v)); (pr_reg)[25] = v; \
|
||||
|
||||
+47
-51
@@ -69,6 +69,9 @@ build_mmio_write(__writeb, "b", unsigned char, "q", )
|
||||
build_mmio_write(__writew, "w", unsigned short, "r", )
|
||||
build_mmio_write(__writel, "l", unsigned int, "r", )
|
||||
|
||||
#define readb readb
|
||||
#define readw readw
|
||||
#define readl readl
|
||||
#define readb_relaxed(a) __readb(a)
|
||||
#define readw_relaxed(a) __readw(a)
|
||||
#define readl_relaxed(a) __readl(a)
|
||||
@@ -76,6 +79,9 @@ build_mmio_write(__writel, "l", unsigned int, "r", )
|
||||
#define __raw_readw __readw
|
||||
#define __raw_readl __readl
|
||||
|
||||
#define writeb writeb
|
||||
#define writew writew
|
||||
#define writel writel
|
||||
#define writeb_relaxed(v, a) __writeb(v, a)
|
||||
#define writew_relaxed(v, a) __writew(v, a)
|
||||
#define writel_relaxed(v, a) __writel(v, a)
|
||||
@@ -88,13 +94,15 @@ build_mmio_write(__writel, "l", unsigned int, "r", )
|
||||
#ifdef CONFIG_X86_64
|
||||
|
||||
build_mmio_read(readq, "q", unsigned long, "=r", :"memory")
|
||||
build_mmio_read(__readq, "q", unsigned long, "=r", )
|
||||
build_mmio_write(writeq, "q", unsigned long, "r", :"memory")
|
||||
build_mmio_write(__writeq, "q", unsigned long, "r", )
|
||||
|
||||
#define readq_relaxed(a) readq(a)
|
||||
#define writeq_relaxed(v, a) writeq(v, a)
|
||||
#define readq_relaxed(a) __readq(a)
|
||||
#define writeq_relaxed(v, a) __writeq(v, a)
|
||||
|
||||
#define __raw_readq(a) readq(a)
|
||||
#define __raw_writeq(val, addr) writeq(val, addr)
|
||||
#define __raw_readq __readq
|
||||
#define __raw_writeq __writeq
|
||||
|
||||
/* Let people know that we have them */
|
||||
#define readq readq
|
||||
@@ -119,6 +127,7 @@ static inline phys_addr_t virt_to_phys(volatile void *address)
|
||||
{
|
||||
return __pa(address);
|
||||
}
|
||||
#define virt_to_phys virt_to_phys
|
||||
|
||||
/**
|
||||
* phys_to_virt - map physical address to virtual
|
||||
@@ -137,6 +146,7 @@ static inline void *phys_to_virt(phys_addr_t address)
|
||||
{
|
||||
return __va(address);
|
||||
}
|
||||
#define phys_to_virt phys_to_virt
|
||||
|
||||
/*
|
||||
* Change "struct page" to physical address.
|
||||
@@ -169,11 +179,14 @@ static inline unsigned int isa_virt_to_bus(volatile void *address)
|
||||
* else, you probably want one of the following.
|
||||
*/
|
||||
extern void __iomem *ioremap_nocache(resource_size_t offset, unsigned long size);
|
||||
#define ioremap_nocache ioremap_nocache
|
||||
extern void __iomem *ioremap_uc(resource_size_t offset, unsigned long size);
|
||||
#define ioremap_uc ioremap_uc
|
||||
|
||||
extern void __iomem *ioremap_cache(resource_size_t offset, unsigned long size);
|
||||
#define ioremap_cache ioremap_cache
|
||||
extern void __iomem *ioremap_prot(resource_size_t offset, unsigned long size, unsigned long prot_val);
|
||||
#define ioremap_prot ioremap_prot
|
||||
|
||||
/**
|
||||
* ioremap - map bus memory into CPU space
|
||||
@@ -193,8 +206,10 @@ static inline void __iomem *ioremap(resource_size_t offset, unsigned long size)
|
||||
{
|
||||
return ioremap_nocache(offset, size);
|
||||
}
|
||||
#define ioremap ioremap
|
||||
|
||||
extern void iounmap(volatile void __iomem *addr);
|
||||
#define iounmap iounmap
|
||||
|
||||
extern void set_iounmap_nonlazy(void);
|
||||
|
||||
@@ -202,53 +217,6 @@ extern void set_iounmap_nonlazy(void);
|
||||
|
||||
#include <asm-generic/iomap.h>
|
||||
|
||||
/*
|
||||
* Convert a virtual cached pointer to an uncached pointer
|
||||
*/
|
||||
#define xlate_dev_kmem_ptr(p) p
|
||||
|
||||
/**
|
||||
* memset_io Set a range of I/O memory to a constant value
|
||||
* @addr: The beginning of the I/O-memory range to set
|
||||
* @val: The value to set the memory to
|
||||
* @count: The number of bytes to set
|
||||
*
|
||||
* Set a range of I/O memory to a given value.
|
||||
*/
|
||||
static inline void
|
||||
memset_io(volatile void __iomem *addr, unsigned char val, size_t count)
|
||||
{
|
||||
memset((void __force *)addr, val, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* memcpy_fromio Copy a block of data from I/O memory
|
||||
* @dst: The (RAM) destination for the copy
|
||||
* @src: The (I/O memory) source for the data
|
||||
* @count: The number of bytes to copy
|
||||
*
|
||||
* Copy a block of data from I/O memory.
|
||||
*/
|
||||
static inline void
|
||||
memcpy_fromio(void *dst, const volatile void __iomem *src, size_t count)
|
||||
{
|
||||
memcpy(dst, (const void __force *)src, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* memcpy_toio Copy a block of data into I/O memory
|
||||
* @dst: The (I/O memory) destination for the copy
|
||||
* @src: The (RAM) source for the data
|
||||
* @count: The number of bytes to copy
|
||||
*
|
||||
* Copy a block of data to I/O memory.
|
||||
*/
|
||||
static inline void
|
||||
memcpy_toio(volatile void __iomem *dst, const void *src, size_t count)
|
||||
{
|
||||
memcpy((void __force *)dst, src, count);
|
||||
}
|
||||
|
||||
/*
|
||||
* ISA space is 'always mapped' on a typical x86 system, no need to
|
||||
* explicitly ioremap() it. The fact that the ISA IO space is mapped
|
||||
@@ -341,13 +309,38 @@ BUILDIO(b, b, char)
|
||||
BUILDIO(w, w, short)
|
||||
BUILDIO(l, , int)
|
||||
|
||||
#define inb inb
|
||||
#define inw inw
|
||||
#define inl inl
|
||||
#define inb_p inb_p
|
||||
#define inw_p inw_p
|
||||
#define inl_p inl_p
|
||||
#define insb insb
|
||||
#define insw insw
|
||||
#define insl insl
|
||||
|
||||
#define outb outb
|
||||
#define outw outw
|
||||
#define outl outl
|
||||
#define outb_p outb_p
|
||||
#define outw_p outw_p
|
||||
#define outl_p outl_p
|
||||
#define outsb outsb
|
||||
#define outsw outsw
|
||||
#define outsl outsl
|
||||
|
||||
extern void *xlate_dev_mem_ptr(phys_addr_t phys);
|
||||
extern void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr);
|
||||
|
||||
#define xlate_dev_mem_ptr xlate_dev_mem_ptr
|
||||
#define unxlate_dev_mem_ptr unxlate_dev_mem_ptr
|
||||
|
||||
extern int ioremap_change_attr(unsigned long vaddr, unsigned long size,
|
||||
enum page_cache_mode pcm);
|
||||
extern void __iomem *ioremap_wc(resource_size_t offset, unsigned long size);
|
||||
#define ioremap_wc ioremap_wc
|
||||
extern void __iomem *ioremap_wt(resource_size_t offset, unsigned long size);
|
||||
#define ioremap_wt ioremap_wt
|
||||
|
||||
extern bool is_early_ioremap_ptep(pte_t *ptep);
|
||||
|
||||
@@ -365,6 +358,9 @@ extern bool xen_biovec_phys_mergeable(const struct bio_vec *vec1,
|
||||
|
||||
#define IO_SPACE_LIMIT 0xffff
|
||||
|
||||
#include <asm-generic/io.h>
|
||||
#undef PCI_IOBASE
|
||||
|
||||
#ifdef CONFIG_MTRR
|
||||
extern int __must_check arch_phys_wc_index(int handle);
|
||||
#define arch_phys_wc_index arch_phys_wc_index
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
#ifndef _ASM_X86_LGUEST_H
|
||||
#define _ASM_X86_LGUEST_H
|
||||
|
||||
#define GDT_ENTRY_LGUEST_CS 10
|
||||
#define GDT_ENTRY_LGUEST_DS 11
|
||||
#define LGUEST_CS (GDT_ENTRY_LGUEST_CS * 8)
|
||||
#define LGUEST_DS (GDT_ENTRY_LGUEST_DS * 8)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#include <asm/desc.h>
|
||||
|
||||
#define GUEST_PL 1
|
||||
|
||||
/* Page for Switcher text itself, then two pages per cpu */
|
||||
#define SWITCHER_TEXT_PAGES (1)
|
||||
#define SWITCHER_STACK_PAGES (2 * nr_cpu_ids)
|
||||
#define TOTAL_SWITCHER_PAGES (SWITCHER_TEXT_PAGES + SWITCHER_STACK_PAGES)
|
||||
|
||||
/* Where we map the Switcher, in both Host and Guest. */
|
||||
extern unsigned long switcher_addr;
|
||||
|
||||
/* Found in switcher.S */
|
||||
extern unsigned long default_idt_entries[];
|
||||
|
||||
/* Declarations for definitions in arch/x86/lguest/head_32.S */
|
||||
extern char lguest_noirq_iret[];
|
||||
extern const char lgstart_cli[], lgend_cli[];
|
||||
extern const char lgstart_pushf[], lgend_pushf[];
|
||||
|
||||
extern void lguest_iret(void);
|
||||
extern void lguest_init(void);
|
||||
|
||||
struct lguest_regs {
|
||||
/* Manually saved part. */
|
||||
unsigned long eax, ebx, ecx, edx;
|
||||
unsigned long esi, edi, ebp;
|
||||
unsigned long gs;
|
||||
unsigned long fs, ds, es;
|
||||
unsigned long trapnum, errcode;
|
||||
/* Trap pushed part */
|
||||
unsigned long eip;
|
||||
unsigned long cs;
|
||||
unsigned long eflags;
|
||||
unsigned long esp;
|
||||
unsigned long ss;
|
||||
};
|
||||
|
||||
/* This is a guest-specific page (mapped ro) into the guest. */
|
||||
struct lguest_ro_state {
|
||||
/* Host information we need to restore when we switch back. */
|
||||
u32 host_cr3;
|
||||
struct desc_ptr host_idt_desc;
|
||||
struct desc_ptr host_gdt_desc;
|
||||
u32 host_sp;
|
||||
|
||||
/* Fields which are used when guest is running. */
|
||||
struct desc_ptr guest_idt_desc;
|
||||
struct desc_ptr guest_gdt_desc;
|
||||
struct x86_hw_tss guest_tss;
|
||||
struct desc_struct guest_idt[IDT_ENTRIES];
|
||||
struct desc_struct guest_gdt[GDT_ENTRIES];
|
||||
};
|
||||
|
||||
struct lg_cpu_arch {
|
||||
/* The GDT entries copied into lguest_ro_state when running. */
|
||||
struct desc_struct gdt[GDT_ENTRIES];
|
||||
|
||||
/* The IDT entries: some copied into lguest_ro_state when running. */
|
||||
struct desc_struct idt[IDT_ENTRIES];
|
||||
|
||||
/* The address of the last guest-visible pagefault (ie. cr2). */
|
||||
unsigned long last_pagefault;
|
||||
};
|
||||
|
||||
static inline void lguest_set_ts(void)
|
||||
{
|
||||
u32 cr0;
|
||||
|
||||
cr0 = read_cr0();
|
||||
if (!(cr0 & 8))
|
||||
write_cr0(cr0 | 8);
|
||||
}
|
||||
|
||||
/* Full 4G segment descriptors, suitable for CS and DS. */
|
||||
#define FULL_EXEC_SEGMENT \
|
||||
((struct desc_struct)GDT_ENTRY_INIT(0xc09b, 0, 0xfffff))
|
||||
#define FULL_SEGMENT ((struct desc_struct)GDT_ENTRY_INIT(0xc093, 0, 0xfffff))
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* _ASM_X86_LGUEST_H */
|
||||
@@ -1,74 +0,0 @@
|
||||
/* Architecture specific portion of the lguest hypercalls */
|
||||
#ifndef _ASM_X86_LGUEST_HCALL_H
|
||||
#define _ASM_X86_LGUEST_HCALL_H
|
||||
|
||||
#define LHCALL_FLUSH_ASYNC 0
|
||||
#define LHCALL_LGUEST_INIT 1
|
||||
#define LHCALL_SHUTDOWN 2
|
||||
#define LHCALL_NEW_PGTABLE 4
|
||||
#define LHCALL_FLUSH_TLB 5
|
||||
#define LHCALL_LOAD_IDT_ENTRY 6
|
||||
#define LHCALL_SET_STACK 7
|
||||
#define LHCALL_SET_CLOCKEVENT 9
|
||||
#define LHCALL_HALT 10
|
||||
#define LHCALL_SET_PMD 13
|
||||
#define LHCALL_SET_PTE 14
|
||||
#define LHCALL_SET_PGD 15
|
||||
#define LHCALL_LOAD_TLS 16
|
||||
#define LHCALL_LOAD_GDT_ENTRY 18
|
||||
#define LHCALL_SEND_INTERRUPTS 19
|
||||
|
||||
#define LGUEST_TRAP_ENTRY 0x1F
|
||||
|
||||
/* Argument number 3 to LHCALL_LGUEST_SHUTDOWN */
|
||||
#define LGUEST_SHUTDOWN_POWEROFF 1
|
||||
#define LGUEST_SHUTDOWN_RESTART 2
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#include <asm/hw_irq.h>
|
||||
|
||||
/*G:030
|
||||
* But first, how does our Guest contact the Host to ask for privileged
|
||||
* operations? There are two ways: the direct way is to make a "hypercall",
|
||||
* to make requests of the Host Itself.
|
||||
*
|
||||
* Our hypercall mechanism uses the highest unused trap code (traps 32 and
|
||||
* above are used by real hardware interrupts). Seventeen hypercalls are
|
||||
* available: the hypercall number is put in the %eax register, and the
|
||||
* arguments (when required) are placed in %ebx, %ecx, %edx and %esi.
|
||||
* If a return value makes sense, it's returned in %eax.
|
||||
*
|
||||
* Grossly invalid calls result in Sudden Death at the hands of the vengeful
|
||||
* Host, rather than returning failure. This reflects Winston Churchill's
|
||||
* definition of a gentleman: "someone who is only rude intentionally".
|
||||
*/
|
||||
static inline unsigned long
|
||||
hcall(unsigned long call,
|
||||
unsigned long arg1, unsigned long arg2, unsigned long arg3,
|
||||
unsigned long arg4)
|
||||
{
|
||||
/* "int" is the Intel instruction to trigger a trap. */
|
||||
asm volatile("int $" __stringify(LGUEST_TRAP_ENTRY)
|
||||
/* The call in %eax (aka "a") might be overwritten */
|
||||
: "=a"(call)
|
||||
/* The arguments are in %eax, %ebx, %ecx, %edx & %esi */
|
||||
: "a"(call), "b"(arg1), "c"(arg2), "d"(arg3), "S"(arg4)
|
||||
/* "memory" means this might write somewhere in memory.
|
||||
* This isn't true for all calls, but it's safe to tell
|
||||
* gcc that it might happen so it doesn't get clever. */
|
||||
: "memory");
|
||||
return call;
|
||||
}
|
||||
/*:*/
|
||||
|
||||
/* Can't use our min() macro here: needs to be a constant */
|
||||
#define LGUEST_IRQS (NR_IRQS < 32 ? NR_IRQS: 32)
|
||||
|
||||
#define LHCALL_RING_SIZE 64
|
||||
struct hcall_args {
|
||||
/* These map directly onto eax/ebx/ecx/edx/esi in struct lguest_regs */
|
||||
unsigned long arg0, arg1, arg2, arg3, arg4;
|
||||
};
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
#endif /* _ASM_X86_LGUEST_HCALL_H */
|
||||
@@ -2,6 +2,15 @@
|
||||
#define _ASM_X86_MODULE_H
|
||||
|
||||
#include <asm-generic/module.h>
|
||||
#include <asm/orc_types.h>
|
||||
|
||||
struct mod_arch_specific {
|
||||
#ifdef CONFIG_ORC_UNWINDER
|
||||
unsigned int num_orcs;
|
||||
int *orc_unwind_ip;
|
||||
struct orc_entry *orc_unwind;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
/* X86_64 does not define MODULE_PROC_FAMILY */
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef _ORC_LOOKUP_H
|
||||
#define _ORC_LOOKUP_H
|
||||
|
||||
/*
|
||||
* This is a lookup table for speeding up access to the .orc_unwind table.
|
||||
* Given an input address offset, the corresponding lookup table entry
|
||||
* specifies a subset of the .orc_unwind table to search.
|
||||
*
|
||||
* Each block represents the end of the previous range and the start of the
|
||||
* next range. An extra block is added to give the last range an end.
|
||||
*
|
||||
* The block size should be a power of 2 to avoid a costly 'div' instruction.
|
||||
*
|
||||
* A block size of 256 was chosen because it roughly doubles unwinder
|
||||
* performance while only adding ~5% to the ORC data footprint.
|
||||
*/
|
||||
#define LOOKUP_BLOCK_ORDER 8
|
||||
#define LOOKUP_BLOCK_SIZE (1 << LOOKUP_BLOCK_ORDER)
|
||||
|
||||
#ifndef LINKER_SCRIPT
|
||||
|
||||
extern unsigned int orc_lookup[];
|
||||
extern unsigned int orc_lookup_end[];
|
||||
|
||||
#define LOOKUP_START_IP (unsigned long)_stext
|
||||
#define LOOKUP_STOP_IP (unsigned long)_etext
|
||||
|
||||
#endif /* LINKER_SCRIPT */
|
||||
|
||||
#endif /* _ORC_LOOKUP_H */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user