Merge tag 's390-5.2-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Martin Schwidefsky: - Support for kernel address space layout randomization - Add support for kernel image signature verification - Convert s390 to the generic get_user_pages_fast code - Convert s390 to the stack unwind API analog to x86 - Add support for CPU directed interrupts for PCI devices - Provide support for MIO instructions to the PCI base layer, this will allow the use of direct PCI mappings in user space code - Add the basic KVM guest ultravisor interface for protected VMs - Add AT_HWCAP bits for several new hardware capabilities - Update the CPU measurement facility counter definitions to SVN 6 - Arnds cleanup patches for his quest to get LLVM compiles working - A vfio-ccw update with bug fixes and support for halt and clear - Improvements for the hardware TRNG code - Another round of cleanup for the QDIO layer - Numerous cleanups and bug fixes * tag 's390-5.2-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (98 commits) s390/vdso: drop unnecessary cc-ldoption s390: fix clang -Wpointer-sign warnigns in boot code s390: drop CONFIG_VIRT_TO_BUS s390: boot, purgatory: pass $(CLANG_FLAGS) where needed s390: only build for new CPUs with clang s390: simplify disabled_wait s390/ftrace: use HAVE_FUNCTION_GRAPH_RET_ADDR_PTR s390/unwind: introduce stack unwind API s390/opcodes: add missing instructions to the disassembler s390/bug: add entry size to the __bug_table section s390: use proper expoline sections for .dma code s390/nospec: rename assembler generated expoline thunks s390: add missing ENDPROC statements to assembler functions locking/lockdep: check for freed initmem in static_obj() s390/kernel: add support for kernel address space layout randomization (KASLR) s390/kernel: introduce .dma sections s390/sclp: do not use static sccbs s390/kprobes: use static buffer for insn_page s390/kernel: convert SYSCALL and PGM_CHECK handlers to .quad s390/kernel: build a relocatable kernel ...
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
|
||||
struct airq_struct {
|
||||
struct hlist_node list; /* Handler queueing. */
|
||||
void (*handler)(struct airq_struct *); /* Thin-interrupt handler */
|
||||
void (*handler)(struct airq_struct *airq, bool floating);
|
||||
u8 *lsi_ptr; /* Local-Summary-Indicator pointer */
|
||||
u8 lsi_mask; /* Local-Summary-Indicator mask */
|
||||
u8 isc; /* Interrupt-subclass */
|
||||
@@ -35,13 +35,15 @@ struct airq_iv {
|
||||
unsigned int *data; /* 32 bit value associated with each bit */
|
||||
unsigned long bits; /* Number of bits in the vector */
|
||||
unsigned long end; /* Number of highest allocated bit + 1 */
|
||||
unsigned long flags; /* Allocation flags */
|
||||
spinlock_t lock; /* Lock to protect alloc & free */
|
||||
};
|
||||
|
||||
#define AIRQ_IV_ALLOC 1 /* Use an allocation bit mask */
|
||||
#define AIRQ_IV_BITLOCK 2 /* Allocate the lock bit mask */
|
||||
#define AIRQ_IV_PTR 4 /* Allocate the ptr array */
|
||||
#define AIRQ_IV_DATA 8 /* Allocate the data array */
|
||||
#define AIRQ_IV_ALLOC 1 /* Use an allocation bit mask */
|
||||
#define AIRQ_IV_BITLOCK 2 /* Allocate the lock bit mask */
|
||||
#define AIRQ_IV_PTR 4 /* Allocate the ptr array */
|
||||
#define AIRQ_IV_DATA 8 /* Allocate the data array */
|
||||
#define AIRQ_IV_CACHELINE 16 /* Cacheline alignment for the vector */
|
||||
|
||||
struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags);
|
||||
void airq_iv_release(struct airq_iv *iv);
|
||||
|
@@ -73,7 +73,7 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *ptr)
|
||||
}
|
||||
#endif
|
||||
mask = 1UL << (nr & (BITS_PER_LONG - 1));
|
||||
__atomic64_or(mask, addr);
|
||||
__atomic64_or(mask, (long *)addr);
|
||||
}
|
||||
|
||||
static inline void clear_bit(unsigned long nr, volatile unsigned long *ptr)
|
||||
@@ -94,7 +94,7 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *ptr)
|
||||
}
|
||||
#endif
|
||||
mask = ~(1UL << (nr & (BITS_PER_LONG - 1)));
|
||||
__atomic64_and(mask, addr);
|
||||
__atomic64_and(mask, (long *)addr);
|
||||
}
|
||||
|
||||
static inline void change_bit(unsigned long nr, volatile unsigned long *ptr)
|
||||
@@ -115,7 +115,7 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *ptr)
|
||||
}
|
||||
#endif
|
||||
mask = 1UL << (nr & (BITS_PER_LONG - 1));
|
||||
__atomic64_xor(mask, addr);
|
||||
__atomic64_xor(mask, (long *)addr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
@@ -125,7 +125,7 @@ test_and_set_bit(unsigned long nr, volatile unsigned long *ptr)
|
||||
unsigned long old, mask;
|
||||
|
||||
mask = 1UL << (nr & (BITS_PER_LONG - 1));
|
||||
old = __atomic64_or_barrier(mask, addr);
|
||||
old = __atomic64_or_barrier(mask, (long *)addr);
|
||||
return (old & mask) != 0;
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ test_and_clear_bit(unsigned long nr, volatile unsigned long *ptr)
|
||||
unsigned long old, mask;
|
||||
|
||||
mask = ~(1UL << (nr & (BITS_PER_LONG - 1)));
|
||||
old = __atomic64_and_barrier(mask, addr);
|
||||
old = __atomic64_and_barrier(mask, (long *)addr);
|
||||
return (old & ~mask) != 0;
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ test_and_change_bit(unsigned long nr, volatile unsigned long *ptr)
|
||||
unsigned long old, mask;
|
||||
|
||||
mask = 1UL << (nr & (BITS_PER_LONG - 1));
|
||||
old = __atomic64_xor_barrier(mask, addr);
|
||||
old = __atomic64_xor_barrier(mask, (long *)addr);
|
||||
return (old & mask) != 0;
|
||||
}
|
||||
|
||||
|
@@ -5,7 +5,14 @@
|
||||
#include <asm/ipl.h>
|
||||
|
||||
extern char early_command_line[COMMAND_LINE_SIZE];
|
||||
extern struct ipl_parameter_block early_ipl_block;
|
||||
extern int early_ipl_block_valid;
|
||||
extern struct ipl_parameter_block ipl_block;
|
||||
extern int ipl_block_valid;
|
||||
extern int ipl_secure_flag;
|
||||
|
||||
extern unsigned long ipl_cert_list_addr;
|
||||
extern unsigned long ipl_cert_list_size;
|
||||
|
||||
extern unsigned long early_ipl_comp_list_addr;
|
||||
extern unsigned long early_ipl_comp_list_size;
|
||||
|
||||
#endif /* _ASM_S390_BOOT_DATA_H */
|
||||
|
@@ -15,7 +15,7 @@
|
||||
".section .rodata.str,\"aMS\",@progbits,1\n" \
|
||||
"2: .asciz \""__FILE__"\"\n" \
|
||||
".previous\n" \
|
||||
".section __bug_table,\"aw\"\n" \
|
||||
".section __bug_table,\"awM\",@progbits,%2\n" \
|
||||
"3: .long 1b-3b,2b-3b\n" \
|
||||
" .short %0,%1\n" \
|
||||
" .org 3b+%2\n" \
|
||||
@@ -27,17 +27,17 @@
|
||||
|
||||
#else /* CONFIG_DEBUG_BUGVERBOSE */
|
||||
|
||||
#define __EMIT_BUG(x) do { \
|
||||
asm volatile( \
|
||||
"0: j 0b+2\n" \
|
||||
"1:\n" \
|
||||
".section __bug_table,\"aw\"\n" \
|
||||
"2: .long 1b-2b\n" \
|
||||
" .short %0\n" \
|
||||
" .org 2b+%1\n" \
|
||||
".previous\n" \
|
||||
: : "i" (x), \
|
||||
"i" (sizeof(struct bug_entry))); \
|
||||
#define __EMIT_BUG(x) do { \
|
||||
asm volatile( \
|
||||
"0: j 0b+2\n" \
|
||||
"1:\n" \
|
||||
".section __bug_table,\"awM\",@progbits,%1\n" \
|
||||
"2: .long 1b-2b\n" \
|
||||
" .short %0\n" \
|
||||
" .org 2b+%1\n" \
|
||||
".previous\n" \
|
||||
: : "i" (x), \
|
||||
"i" (sizeof(struct bug_entry))); \
|
||||
} while (0)
|
||||
|
||||
#endif /* CONFIG_DEBUG_BUGVERBOSE */
|
||||
|
@@ -308,4 +308,17 @@ union diag318_info {
|
||||
int diag204(unsigned long subcode, unsigned long size, void *addr);
|
||||
int diag224(void *ptr);
|
||||
int diag26c(void *req, void *resp, enum diag26c_sc subcode);
|
||||
|
||||
struct hypfs_diag0c_entry;
|
||||
|
||||
struct diag_ops {
|
||||
int (*diag210)(struct diag210 *addr);
|
||||
int (*diag26c)(void *req, void *resp, enum diag26c_sc subcode);
|
||||
int (*diag14)(unsigned long rx, unsigned long ry1, unsigned long subcode);
|
||||
void (*diag0c)(struct hypfs_diag0c_entry *entry);
|
||||
void (*diag308_reset)(void);
|
||||
};
|
||||
|
||||
extern struct diag_ops diag_dma_ops;
|
||||
extern struct diag210 *__diag210_tmp_dma;
|
||||
#endif /* _ASM_S390_DIAG_H */
|
||||
|
@@ -20,7 +20,7 @@ extern __u8 _ebc_tolower[256]; /* EBCDIC -> lowercase */
|
||||
extern __u8 _ebc_toupper[256]; /* EBCDIC -> uppercase */
|
||||
|
||||
static inline void
|
||||
codepage_convert(const __u8 *codepage, volatile __u8 * addr, unsigned long nr)
|
||||
codepage_convert(const __u8 *codepage, volatile char *addr, unsigned long nr)
|
||||
{
|
||||
if (nr-- <= 0)
|
||||
return;
|
||||
|
@@ -107,6 +107,10 @@
|
||||
#define HWCAP_S390_VXRS_BCD 4096
|
||||
#define HWCAP_S390_VXRS_EXT 8192
|
||||
#define HWCAP_S390_GS 16384
|
||||
#define HWCAP_S390_VXRS_EXT2 32768
|
||||
#define HWCAP_S390_VXRS_PDE 65536
|
||||
#define HWCAP_S390_SORT 131072
|
||||
#define HWCAP_S390_DFLT 262144
|
||||
|
||||
/* Internal bits, not exposed via elf */
|
||||
#define HWCAP_INT_SIE 1UL
|
||||
|
@@ -19,6 +19,11 @@ struct exception_table_entry
|
||||
int insn, fixup;
|
||||
};
|
||||
|
||||
extern struct exception_table_entry *__start_dma_ex_table;
|
||||
extern struct exception_table_entry *__stop_dma_ex_table;
|
||||
|
||||
const struct exception_table_entry *s390_search_extables(unsigned long addr);
|
||||
|
||||
static inline unsigned long extable_fixup(const struct exception_table_entry *x)
|
||||
{
|
||||
return (unsigned long)&x->fixup + x->fixup;
|
||||
|
@@ -11,9 +11,16 @@
|
||||
#define MCOUNT_RETURN_FIXUP 18
|
||||
#endif
|
||||
|
||||
#define HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#ifdef CONFIG_CC_IS_CLANG
|
||||
/* https://bugs.llvm.org/show_bug.cgi?id=41424 */
|
||||
#define ftrace_return_address(n) 0UL
|
||||
#else
|
||||
#define ftrace_return_address(n) __builtin_return_address(n)
|
||||
#endif
|
||||
|
||||
void _mcount(void);
|
||||
void ftrace_caller(void);
|
||||
|
@@ -30,14 +30,8 @@ void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr);
|
||||
#define ioremap_wc ioremap_nocache
|
||||
#define ioremap_wt ioremap_nocache
|
||||
|
||||
static inline void __iomem *ioremap(unsigned long offset, unsigned long size)
|
||||
{
|
||||
return (void __iomem *) offset;
|
||||
}
|
||||
|
||||
static inline void iounmap(volatile void __iomem *addr)
|
||||
{
|
||||
}
|
||||
void __iomem *ioremap(unsigned long offset, unsigned long size);
|
||||
void iounmap(volatile void __iomem *addr);
|
||||
|
||||
static inline void __iomem *ioport_map(unsigned long port, unsigned int nr)
|
||||
{
|
||||
@@ -57,14 +51,17 @@ static inline void ioport_unmap(void __iomem *p)
|
||||
* the corresponding device and create the mapping cookie.
|
||||
*/
|
||||
#define pci_iomap pci_iomap
|
||||
#define pci_iomap_range pci_iomap_range
|
||||
#define pci_iounmap pci_iounmap
|
||||
#define pci_iomap_wc pci_iomap
|
||||
#define pci_iomap_wc_range pci_iomap_range
|
||||
#define pci_iomap_wc pci_iomap_wc
|
||||
#define pci_iomap_wc_range pci_iomap_wc_range
|
||||
|
||||
#define memcpy_fromio(dst, src, count) zpci_memcpy_fromio(dst, src, count)
|
||||
#define memcpy_toio(dst, src, count) zpci_memcpy_toio(dst, src, count)
|
||||
#define memset_io(dst, val, count) zpci_memset_io(dst, val, count)
|
||||
|
||||
#define mmiowb() zpci_barrier()
|
||||
|
||||
#define __raw_readb zpci_read_u8
|
||||
#define __raw_readw zpci_read_u16
|
||||
#define __raw_readl zpci_read_u32
|
||||
|
@@ -12,74 +12,36 @@
|
||||
#include <asm/types.h>
|
||||
#include <asm/cio.h>
|
||||
#include <asm/setup.h>
|
||||
#include <uapi/asm/ipl.h>
|
||||
|
||||
#define NSS_NAME_SIZE 8
|
||||
struct ipl_parameter_block {
|
||||
struct ipl_pl_hdr hdr;
|
||||
union {
|
||||
struct ipl_pb_hdr pb0_hdr;
|
||||
struct ipl_pb0_common common;
|
||||
struct ipl_pb0_fcp fcp;
|
||||
struct ipl_pb0_ccw ccw;
|
||||
char raw[PAGE_SIZE - sizeof(struct ipl_pl_hdr)];
|
||||
};
|
||||
} __packed __aligned(PAGE_SIZE);
|
||||
|
||||
#define IPL_PARM_BLK_FCP_LEN (sizeof(struct ipl_list_hdr) + \
|
||||
sizeof(struct ipl_block_fcp))
|
||||
#define NSS_NAME_SIZE 8
|
||||
|
||||
#define IPL_PARM_BLK0_FCP_LEN (sizeof(struct ipl_block_fcp) + 16)
|
||||
|
||||
#define IPL_PARM_BLK_CCW_LEN (sizeof(struct ipl_list_hdr) + \
|
||||
sizeof(struct ipl_block_ccw))
|
||||
|
||||
#define IPL_PARM_BLK0_CCW_LEN (sizeof(struct ipl_block_ccw) + 16)
|
||||
#define IPL_BP_FCP_LEN (sizeof(struct ipl_pl_hdr) + \
|
||||
sizeof(struct ipl_pb0_fcp))
|
||||
#define IPL_BP0_FCP_LEN (sizeof(struct ipl_pb0_fcp))
|
||||
#define IPL_BP_CCW_LEN (sizeof(struct ipl_pl_hdr) + \
|
||||
sizeof(struct ipl_pb0_ccw))
|
||||
#define IPL_BP0_CCW_LEN (sizeof(struct ipl_pb0_ccw))
|
||||
|
||||
#define IPL_MAX_SUPPORTED_VERSION (0)
|
||||
|
||||
struct ipl_list_hdr {
|
||||
u32 len;
|
||||
u8 reserved1[3];
|
||||
u8 version;
|
||||
u32 blk0_len;
|
||||
u8 pbt;
|
||||
u8 flags;
|
||||
u16 reserved2;
|
||||
u8 loadparm[8];
|
||||
} __attribute__((packed));
|
||||
#define IPL_RB_CERT_UNKNOWN ((unsigned short)-1)
|
||||
|
||||
struct ipl_block_fcp {
|
||||
u8 reserved1[305-1];
|
||||
u8 opt;
|
||||
u8 reserved2[3];
|
||||
u16 reserved3;
|
||||
u16 devno;
|
||||
u8 reserved4[4];
|
||||
u64 wwpn;
|
||||
u64 lun;
|
||||
u32 bootprog;
|
||||
u8 reserved5[12];
|
||||
u64 br_lba;
|
||||
u32 scp_data_len;
|
||||
u8 reserved6[260];
|
||||
u8 scp_data[];
|
||||
} __attribute__((packed));
|
||||
|
||||
#define DIAG308_VMPARM_SIZE 64
|
||||
#define DIAG308_SCPDATA_SIZE (PAGE_SIZE - (sizeof(struct ipl_list_hdr) + \
|
||||
offsetof(struct ipl_block_fcp, scp_data)))
|
||||
|
||||
struct ipl_block_ccw {
|
||||
u8 reserved1[84];
|
||||
u16 reserved2 : 13;
|
||||
u8 ssid : 3;
|
||||
u16 devno;
|
||||
u8 vm_flags;
|
||||
u8 reserved3[3];
|
||||
u32 vm_parm_len;
|
||||
u8 nss_name[8];
|
||||
u8 vm_parm[DIAG308_VMPARM_SIZE];
|
||||
u8 reserved4[8];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ipl_parameter_block {
|
||||
struct ipl_list_hdr hdr;
|
||||
union {
|
||||
struct ipl_block_fcp fcp;
|
||||
struct ipl_block_ccw ccw;
|
||||
char raw[PAGE_SIZE - sizeof(struct ipl_list_hdr)];
|
||||
} ipl_info;
|
||||
} __packed __aligned(PAGE_SIZE);
|
||||
#define DIAG308_VMPARM_SIZE (64)
|
||||
#define DIAG308_SCPDATA_OFFSET offsetof(struct ipl_parameter_block, \
|
||||
fcp.scp_data)
|
||||
#define DIAG308_SCPDATA_SIZE (PAGE_SIZE - DIAG308_SCPDATA_OFFSET)
|
||||
|
||||
struct save_area;
|
||||
struct save_area * __init save_area_alloc(bool is_boot_cpu);
|
||||
@@ -88,7 +50,6 @@ void __init save_area_add_regs(struct save_area *, void *regs);
|
||||
void __init save_area_add_vxrs(struct save_area *, __vector128 *vxrs);
|
||||
|
||||
extern void s390_reset_system(void);
|
||||
extern void ipl_store_parameters(void);
|
||||
extern size_t ipl_block_get_ascii_vmparm(char *dest, size_t size,
|
||||
const struct ipl_parameter_block *ipb);
|
||||
|
||||
@@ -122,6 +83,33 @@ extern struct ipl_info ipl_info;
|
||||
extern void setup_ipl(void);
|
||||
extern void set_os_info_reipl_block(void);
|
||||
|
||||
struct ipl_report {
|
||||
struct ipl_parameter_block *ipib;
|
||||
struct list_head components;
|
||||
struct list_head certificates;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct ipl_report_component {
|
||||
struct list_head list;
|
||||
struct ipl_rb_component_entry entry;
|
||||
};
|
||||
|
||||
struct ipl_report_certificate {
|
||||
struct list_head list;
|
||||
struct ipl_rb_certificate_entry entry;
|
||||
void *key;
|
||||
};
|
||||
|
||||
struct kexec_buf;
|
||||
struct ipl_report *ipl_report_init(struct ipl_parameter_block *ipib);
|
||||
void *ipl_report_finish(struct ipl_report *report);
|
||||
int ipl_report_free(struct ipl_report *report);
|
||||
int ipl_report_add_component(struct ipl_report *report, struct kexec_buf *kbuf,
|
||||
unsigned char flags, unsigned short cert);
|
||||
int ipl_report_add_certificate(struct ipl_report *report, void *key,
|
||||
unsigned long addr, unsigned long len);
|
||||
|
||||
/*
|
||||
* DIAG 308 support
|
||||
*/
|
||||
@@ -133,32 +121,12 @@ enum diag308_subcode {
|
||||
DIAG308_STORE = 6,
|
||||
};
|
||||
|
||||
enum diag308_ipl_type {
|
||||
DIAG308_IPL_TYPE_FCP = 0,
|
||||
DIAG308_IPL_TYPE_CCW = 2,
|
||||
};
|
||||
|
||||
enum diag308_opt {
|
||||
DIAG308_IPL_OPT_IPL = 0x10,
|
||||
DIAG308_IPL_OPT_DUMP = 0x20,
|
||||
};
|
||||
|
||||
enum diag308_flags {
|
||||
DIAG308_FLAGS_LP_VALID = 0x80,
|
||||
};
|
||||
|
||||
enum diag308_vm_flags {
|
||||
DIAG308_VM_FLAGS_NSS_VALID = 0x80,
|
||||
DIAG308_VM_FLAGS_VP_VALID = 0x40,
|
||||
};
|
||||
|
||||
enum diag308_rc {
|
||||
DIAG308_RC_OK = 0x0001,
|
||||
DIAG308_RC_NOCONFIG = 0x0102,
|
||||
};
|
||||
|
||||
extern int diag308(unsigned long subcode, void *addr);
|
||||
extern void diag308_reset(void);
|
||||
extern void store_status(void (*fn)(void *), void *data);
|
||||
extern void lgr_info_log(void);
|
||||
|
||||
|
@@ -47,7 +47,6 @@ enum interruption_class {
|
||||
IRQEXT_CMC,
|
||||
IRQEXT_FTP,
|
||||
IRQIO_CIO,
|
||||
IRQIO_QAI,
|
||||
IRQIO_DAS,
|
||||
IRQIO_C15,
|
||||
IRQIO_C70,
|
||||
@@ -55,12 +54,14 @@ enum interruption_class {
|
||||
IRQIO_VMR,
|
||||
IRQIO_LCS,
|
||||
IRQIO_CTC,
|
||||
IRQIO_APB,
|
||||
IRQIO_ADM,
|
||||
IRQIO_CSC,
|
||||
IRQIO_PCI,
|
||||
IRQIO_MSI,
|
||||
IRQIO_VIR,
|
||||
IRQIO_QAI,
|
||||
IRQIO_APB,
|
||||
IRQIO_PCF,
|
||||
IRQIO_PCD,
|
||||
IRQIO_MSI,
|
||||
IRQIO_VAI,
|
||||
IRQIO_GAL,
|
||||
NMI_NMI,
|
||||
|
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <asm/processor.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/setup.h>
|
||||
/*
|
||||
* KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return.
|
||||
* I.e. Maximum page that is mapped directly into kernel memory,
|
||||
@@ -42,6 +43,9 @@
|
||||
/* The native architecture */
|
||||
#define KEXEC_ARCH KEXEC_ARCH_S390
|
||||
|
||||
/* Allow kexec_file to load a segment to 0 */
|
||||
#define KEXEC_BUF_MEM_UNKNOWN -1
|
||||
|
||||
/* Provide a dummy definition to avoid build failures. */
|
||||
static inline void crash_setup_regs(struct pt_regs *newregs,
|
||||
struct pt_regs *oldregs) { }
|
||||
@@ -51,20 +55,24 @@ struct s390_load_data {
|
||||
/* Pointer to the kernel buffer. Used to register cmdline etc.. */
|
||||
void *kernel_buf;
|
||||
|
||||
/* Load address of the kernel_buf. */
|
||||
unsigned long kernel_mem;
|
||||
|
||||
/* Parmarea in the kernel buffer. */
|
||||
struct parmarea *parm;
|
||||
|
||||
/* Total size of loaded segments in memory. Used as an offset. */
|
||||
size_t memsz;
|
||||
|
||||
/* Load address of initrd. Used to register INITRD_START in kernel. */
|
||||
unsigned long initrd_load_addr;
|
||||
struct ipl_report *report;
|
||||
};
|
||||
|
||||
int kexec_file_add_purgatory(struct kimage *image,
|
||||
struct s390_load_data *data);
|
||||
int kexec_file_add_initrd(struct kimage *image,
|
||||
struct s390_load_data *data,
|
||||
char *initrd, unsigned long initrd_len);
|
||||
int *kexec_file_update_kernel(struct kimage *iamge,
|
||||
struct s390_load_data *data);
|
||||
int s390_verify_sig(const char *kernel, unsigned long kernel_len);
|
||||
void *kexec_file_add_components(struct kimage *image,
|
||||
int (*add_kernel)(struct kimage *image,
|
||||
struct s390_load_data *data));
|
||||
int arch_kexec_do_relocs(int r_type, void *loc, unsigned long val,
|
||||
unsigned long addr);
|
||||
|
||||
extern const struct kexec_file_ops s390_kexec_image_ops;
|
||||
extern const struct kexec_file_ops s390_kexec_elf_ops;
|
||||
|
@@ -28,5 +28,12 @@
|
||||
.long (_target) - . ; \
|
||||
.previous
|
||||
|
||||
#define EX_TABLE_DMA(_fault, _target) \
|
||||
.section .dma.ex_table, "a" ; \
|
||||
.align 4 ; \
|
||||
.long (_fault) - . ; \
|
||||
.long (_target) - . ; \
|
||||
.previous
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif
|
||||
|
@@ -129,7 +129,7 @@ struct lowcore {
|
||||
/* SMP info area */
|
||||
__u32 cpu_nr; /* 0x03a0 */
|
||||
__u32 softirq_pending; /* 0x03a4 */
|
||||
__u32 preempt_count; /* 0x03a8 */
|
||||
__s32 preempt_count; /* 0x03a8 */
|
||||
__u32 spinlock_lockval; /* 0x03ac */
|
||||
__u32 spinlock_index; /* 0x03b0 */
|
||||
__u32 fpu_flags; /* 0x03b4 */
|
||||
|
@@ -32,23 +32,23 @@ _LC_BR_R1 = __LC_BR_R1
|
||||
.endm
|
||||
|
||||
.macro __THUNK_PROLOG_BR r1,r2
|
||||
__THUNK_PROLOG_NAME __s390x_indirect_jump_r\r2\()use_r\r1
|
||||
__THUNK_PROLOG_NAME __s390_indirect_jump_r\r2\()use_r\r1
|
||||
.endm
|
||||
|
||||
.macro __THUNK_PROLOG_BC d0,r1,r2
|
||||
__THUNK_PROLOG_NAME __s390x_indirect_branch_\d0\()_\r2\()use_\r1
|
||||
__THUNK_PROLOG_NAME __s390_indirect_branch_\d0\()_\r2\()use_\r1
|
||||
.endm
|
||||
|
||||
.macro __THUNK_BR r1,r2
|
||||
jg __s390x_indirect_jump_r\r2\()use_r\r1
|
||||
jg __s390_indirect_jump_r\r2\()use_r\r1
|
||||
.endm
|
||||
|
||||
.macro __THUNK_BC d0,r1,r2
|
||||
jg __s390x_indirect_branch_\d0\()_\r2\()use_\r1
|
||||
jg __s390_indirect_branch_\d0\()_\r2\()use_\r1
|
||||
.endm
|
||||
|
||||
.macro __THUNK_BRASL r1,r2,r3
|
||||
brasl \r1,__s390x_indirect_jump_r\r3\()use_r\r2
|
||||
brasl \r1,__s390_indirect_jump_r\r3\()use_r\r2
|
||||
.endm
|
||||
|
||||
.macro __DECODE_RR expand,reg,ruse
|
||||
|
@@ -26,6 +26,9 @@ int pci_proc_domain(struct pci_bus *);
|
||||
#define ZPCI_BUS_NR 0 /* default bus number */
|
||||
#define ZPCI_DEVFN 0 /* default device number */
|
||||
|
||||
#define ZPCI_NR_DMA_SPACES 1
|
||||
#define ZPCI_NR_DEVICES CONFIG_PCI_NR_FUNCTIONS
|
||||
|
||||
/* PCI Function Controls */
|
||||
#define ZPCI_FC_FN_ENABLED 0x80
|
||||
#define ZPCI_FC_ERROR 0x40
|
||||
@@ -83,6 +86,8 @@ enum zpci_state {
|
||||
|
||||
struct zpci_bar_struct {
|
||||
struct resource *res; /* bus resource */
|
||||
void __iomem *mio_wb;
|
||||
void __iomem *mio_wt;
|
||||
u32 val; /* bar start & 3 flag bits */
|
||||
u16 map_idx; /* index into bar mapping array */
|
||||
u8 size; /* order 2 exponent */
|
||||
@@ -112,6 +117,8 @@ struct zpci_dev {
|
||||
/* IRQ stuff */
|
||||
u64 msi_addr; /* MSI address */
|
||||
unsigned int max_msi; /* maximum number of MSI's */
|
||||
unsigned int msi_first_bit;
|
||||
unsigned int msi_nr_irqs;
|
||||
struct airq_iv *aibv; /* adapter interrupt bit vector */
|
||||
unsigned long aisb; /* number of the summary bit */
|
||||
|
||||
@@ -130,6 +137,7 @@ struct zpci_dev {
|
||||
struct iommu_device iommu_dev; /* IOMMU core handle */
|
||||
|
||||
char res_name[16];
|
||||
bool mio_capable;
|
||||
struct zpci_bar_struct bars[PCI_BAR_COUNT];
|
||||
|
||||
u64 start_dma; /* Start of available DMA addresses */
|
||||
@@ -158,6 +166,7 @@ static inline bool zdev_enabled(struct zpci_dev *zdev)
|
||||
}
|
||||
|
||||
extern const struct attribute_group *zpci_attr_groups[];
|
||||
extern unsigned int s390_pci_force_floating __initdata;
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Prototypes
|
||||
@@ -219,6 +228,9 @@ struct zpci_dev *get_zdev_by_fid(u32);
|
||||
int zpci_dma_init(void);
|
||||
void zpci_dma_exit(void);
|
||||
|
||||
int __init zpci_irq_init(void);
|
||||
void __init zpci_irq_exit(void);
|
||||
|
||||
/* FMB */
|
||||
int zpci_fmb_enable_device(struct zpci_dev *);
|
||||
int zpci_fmb_disable_device(struct zpci_dev *);
|
||||
|
@@ -43,6 +43,8 @@ struct clp_fh_list_entry {
|
||||
|
||||
#define CLP_SET_ENABLE_PCI_FN 0 /* Yes, 0 enables it */
|
||||
#define CLP_SET_DISABLE_PCI_FN 1 /* Yes, 1 disables it */
|
||||
#define CLP_SET_ENABLE_MIO 2
|
||||
#define CLP_SET_DISABLE_MIO 3
|
||||
|
||||
#define CLP_UTIL_STR_LEN 64
|
||||
#define CLP_PFIP_NR_SEGMENTS 4
|
||||
@@ -80,7 +82,8 @@ struct clp_req_query_pci {
|
||||
struct clp_rsp_query_pci {
|
||||
struct clp_rsp_hdr hdr;
|
||||
u16 vfn; /* virtual fn number */
|
||||
u16 : 7;
|
||||
u16 : 6;
|
||||
u16 mio_addr_avail : 1;
|
||||
u16 util_str_avail : 1; /* utility string available? */
|
||||
u16 pfgid : 8; /* pci function group id */
|
||||
u32 fid; /* pci function id */
|
||||
@@ -96,6 +99,15 @@ struct clp_rsp_query_pci {
|
||||
u32 reserved[11];
|
||||
u32 uid; /* user defined id */
|
||||
u8 util_str[CLP_UTIL_STR_LEN]; /* utility string */
|
||||
u32 reserved2[16];
|
||||
u32 mio_valid : 6;
|
||||
u32 : 26;
|
||||
u32 : 32;
|
||||
struct {
|
||||
u64 wb;
|
||||
u64 wt;
|
||||
} addr[PCI_BAR_COUNT];
|
||||
u32 reserved3[6];
|
||||
} __packed;
|
||||
|
||||
/* Query PCI function group request */
|
||||
@@ -118,7 +130,11 @@ struct clp_rsp_query_pci_grp {
|
||||
u8 refresh : 1; /* TLB refresh mode */
|
||||
u16 reserved2;
|
||||
u16 mui;
|
||||
u64 reserved3;
|
||||
u16 : 16;
|
||||
u16 maxfaal;
|
||||
u16 : 4;
|
||||
u16 dnoi : 12;
|
||||
u16 maxcpu;
|
||||
u64 dasm; /* dma address space mask */
|
||||
u64 msia; /* MSI address */
|
||||
u64 reserved4;
|
||||
|
@@ -2,6 +2,8 @@
|
||||
#ifndef _ASM_S390_PCI_INSN_H
|
||||
#define _ASM_S390_PCI_INSN_H
|
||||
|
||||
#include <linux/jump_label.h>
|
||||
|
||||
/* Load/Store status codes */
|
||||
#define ZPCI_PCI_ST_FUNC_NOT_ENABLED 4
|
||||
#define ZPCI_PCI_ST_FUNC_IN_ERR 8
|
||||
@@ -38,6 +40,8 @@
|
||||
#define ZPCI_MOD_FC_RESET_ERROR 7
|
||||
#define ZPCI_MOD_FC_RESET_BLOCK 9
|
||||
#define ZPCI_MOD_FC_SET_MEASURE 10
|
||||
#define ZPCI_MOD_FC_REG_INT_D 16
|
||||
#define ZPCI_MOD_FC_DEREG_INT_D 17
|
||||
|
||||
/* FIB function controls */
|
||||
#define ZPCI_FIB_FC_ENABLED 0x80
|
||||
@@ -51,16 +55,7 @@
|
||||
#define ZPCI_FIB_FC_LS_BLOCKED 0x20
|
||||
#define ZPCI_FIB_FC_DMAAS_REG 0x10
|
||||
|
||||
/* Function Information Block */
|
||||
struct zpci_fib {
|
||||
u32 fmt : 8; /* format */
|
||||
u32 : 24;
|
||||
u32 : 32;
|
||||
u8 fc; /* function controls */
|
||||
u64 : 56;
|
||||
u64 pba; /* PCI base address */
|
||||
u64 pal; /* PCI address limit */
|
||||
u64 iota; /* I/O Translation Anchor */
|
||||
struct zpci_fib_fmt0 {
|
||||
u32 : 1;
|
||||
u32 isc : 3; /* Interrupt subclass */
|
||||
u32 noi : 12; /* Number of interrupts */
|
||||
@@ -72,16 +67,90 @@ struct zpci_fib {
|
||||
u32 : 32;
|
||||
u64 aibv; /* Adapter int bit vector address */
|
||||
u64 aisb; /* Adapter int summary bit address */
|
||||
};
|
||||
|
||||
struct zpci_fib_fmt1 {
|
||||
u32 : 4;
|
||||
u32 noi : 12;
|
||||
u32 : 16;
|
||||
u32 dibvo : 16;
|
||||
u32 : 16;
|
||||
u64 : 64;
|
||||
u64 : 64;
|
||||
};
|
||||
|
||||
/* Function Information Block */
|
||||
struct zpci_fib {
|
||||
u32 fmt : 8; /* format */
|
||||
u32 : 24;
|
||||
u32 : 32;
|
||||
u8 fc; /* function controls */
|
||||
u64 : 56;
|
||||
u64 pba; /* PCI base address */
|
||||
u64 pal; /* PCI address limit */
|
||||
u64 iota; /* I/O Translation Anchor */
|
||||
union {
|
||||
struct zpci_fib_fmt0 fmt0;
|
||||
struct zpci_fib_fmt1 fmt1;
|
||||
};
|
||||
u64 fmb_addr; /* Function measurement block address and key */
|
||||
u32 : 32;
|
||||
u32 gd;
|
||||
} __packed __aligned(8);
|
||||
|
||||
/* directed interruption information block */
|
||||
struct zpci_diib {
|
||||
u32 : 1;
|
||||
u32 isc : 3;
|
||||
u32 : 28;
|
||||
u16 : 16;
|
||||
u16 nr_cpus;
|
||||
u64 disb_addr;
|
||||
u64 : 64;
|
||||
u64 : 64;
|
||||
} __packed __aligned(8);
|
||||
|
||||
/* cpu directed interruption information block */
|
||||
struct zpci_cdiib {
|
||||
u64 : 64;
|
||||
u64 dibv_addr;
|
||||
u64 : 64;
|
||||
u64 : 64;
|
||||
u64 : 64;
|
||||
} __packed __aligned(8);
|
||||
|
||||
union zpci_sic_iib {
|
||||
struct zpci_diib diib;
|
||||
struct zpci_cdiib cdiib;
|
||||
};
|
||||
|
||||
DECLARE_STATIC_KEY_FALSE(have_mio);
|
||||
|
||||
u8 zpci_mod_fc(u64 req, struct zpci_fib *fib, u8 *status);
|
||||
int zpci_refresh_trans(u64 fn, u64 addr, u64 range);
|
||||
int zpci_load(u64 *data, u64 req, u64 offset);
|
||||
int zpci_store(u64 data, u64 req, u64 offset);
|
||||
int zpci_store_block(const u64 *data, u64 req, u64 offset);
|
||||
int zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc);
|
||||
int __zpci_load(u64 *data, u64 req, u64 offset);
|
||||
int zpci_load(u64 *data, const volatile void __iomem *addr, unsigned long len);
|
||||
int __zpci_store(u64 data, u64 req, u64 offset);
|
||||
int zpci_store(const volatile void __iomem *addr, u64 data, unsigned long len);
|
||||
int __zpci_store_block(const u64 *data, u64 req, u64 offset);
|
||||
void zpci_barrier(void);
|
||||
int __zpci_set_irq_ctrl(u16 ctl, u8 isc, union zpci_sic_iib *iib);
|
||||
|
||||
static inline int zpci_set_irq_ctrl(u16 ctl, u8 isc)
|
||||
{
|
||||
union zpci_sic_iib iib = {{0}};
|
||||
|
||||
return __zpci_set_irq_ctrl(ctl, isc, &iib);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
static inline void enable_mio_ctl(void)
|
||||
{
|
||||
if (static_branch_likely(&have_mio))
|
||||
__ctl_set_bit(2, 5);
|
||||
}
|
||||
#else /* CONFIG_PCI */
|
||||
static inline void enable_mio_ctl(void) {}
|
||||
#endif /* CONFIG_PCI */
|
||||
|
||||
#endif
|
||||
|
@@ -37,12 +37,10 @@ extern struct zpci_iomap_entry *zpci_iomap_start;
|
||||
#define zpci_read(LENGTH, RETTYPE) \
|
||||
static inline RETTYPE zpci_read_##RETTYPE(const volatile void __iomem *addr) \
|
||||
{ \
|
||||
struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(addr)]; \
|
||||
u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, LENGTH); \
|
||||
u64 data; \
|
||||
int rc; \
|
||||
\
|
||||
rc = zpci_load(&data, req, ZPCI_OFFSET(addr)); \
|
||||
rc = zpci_load(&data, addr, LENGTH); \
|
||||
if (rc) \
|
||||
data = -1ULL; \
|
||||
return (RETTYPE) data; \
|
||||
@@ -52,11 +50,9 @@ static inline RETTYPE zpci_read_##RETTYPE(const volatile void __iomem *addr) \
|
||||
static inline void zpci_write_##VALTYPE(VALTYPE val, \
|
||||
const volatile void __iomem *addr) \
|
||||
{ \
|
||||
struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(addr)]; \
|
||||
u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, LENGTH); \
|
||||
u64 data = (VALTYPE) val; \
|
||||
\
|
||||
zpci_store(data, req, ZPCI_OFFSET(addr)); \
|
||||
zpci_store(addr, data, LENGTH); \
|
||||
}
|
||||
|
||||
zpci_read(8, u64)
|
||||
@@ -68,36 +64,38 @@ zpci_write(4, u32)
|
||||
zpci_write(2, u16)
|
||||
zpci_write(1, u8)
|
||||
|
||||
static inline int zpci_write_single(u64 req, const u64 *data, u64 offset, u8 len)
|
||||
static inline int zpci_write_single(volatile void __iomem *dst, const void *src,
|
||||
unsigned long len)
|
||||
{
|
||||
u64 val;
|
||||
|
||||
switch (len) {
|
||||
case 1:
|
||||
val = (u64) *((u8 *) data);
|
||||
val = (u64) *((u8 *) src);
|
||||
break;
|
||||
case 2:
|
||||
val = (u64) *((u16 *) data);
|
||||
val = (u64) *((u16 *) src);
|
||||
break;
|
||||
case 4:
|
||||
val = (u64) *((u32 *) data);
|
||||
val = (u64) *((u32 *) src);
|
||||
break;
|
||||
case 8:
|
||||
val = (u64) *((u64 *) data);
|
||||
val = (u64) *((u64 *) src);
|
||||
break;
|
||||
default:
|
||||
val = 0; /* let FW report error */
|
||||
break;
|
||||
}
|
||||
return zpci_store(val, req, offset);
|
||||
return zpci_store(dst, val, len);
|
||||
}
|
||||
|
||||
static inline int zpci_read_single(u64 req, u64 *dst, u64 offset, u8 len)
|
||||
static inline int zpci_read_single(void *dst, const volatile void __iomem *src,
|
||||
unsigned long len)
|
||||
{
|
||||
u64 data;
|
||||
int cc;
|
||||
|
||||
cc = zpci_load(&data, req, offset);
|
||||
cc = zpci_load(&data, src, len);
|
||||
if (cc)
|
||||
goto out;
|
||||
|
||||
@@ -119,10 +117,8 @@ out:
|
||||
return cc;
|
||||
}
|
||||
|
||||
static inline int zpci_write_block(u64 req, const u64 *data, u64 offset)
|
||||
{
|
||||
return zpci_store_block(data, req, offset);
|
||||
}
|
||||
int zpci_write_block(volatile void __iomem *dst, const void *src,
|
||||
unsigned long len);
|
||||
|
||||
static inline u8 zpci_get_max_write_size(u64 src, u64 dst, int len, int max)
|
||||
{
|
||||
@@ -140,18 +136,15 @@ static inline int zpci_memcpy_fromio(void *dst,
|
||||
const volatile void __iomem *src,
|
||||
unsigned long n)
|
||||
{
|
||||
struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(src)];
|
||||
u64 req, offset = ZPCI_OFFSET(src);
|
||||
int size, rc = 0;
|
||||
|
||||
while (n > 0) {
|
||||
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);
|
||||
rc = zpci_read_single(dst, src, size);
|
||||
if (rc)
|
||||
break;
|
||||
offset += size;
|
||||
src += size;
|
||||
dst += size;
|
||||
n -= size;
|
||||
}
|
||||
@@ -161,8 +154,6 @@ static inline int zpci_memcpy_fromio(void *dst,
|
||||
static inline int zpci_memcpy_toio(volatile void __iomem *dst,
|
||||
const void *src, unsigned long n)
|
||||
{
|
||||
struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(dst)];
|
||||
u64 req, offset = ZPCI_OFFSET(dst);
|
||||
int size, rc = 0;
|
||||
|
||||
if (!src)
|
||||
@@ -171,16 +162,14 @@ static inline int zpci_memcpy_toio(volatile void __iomem *dst,
|
||||
while (n > 0) {
|
||||
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 */
|
||||
rc = zpci_write_block(req, src, offset);
|
||||
rc = zpci_write_block(dst, src, size);
|
||||
else
|
||||
rc = zpci_write_single(req, src, offset, size);
|
||||
rc = zpci_write_single(dst, src, size);
|
||||
if (rc)
|
||||
break;
|
||||
offset += size;
|
||||
src += size;
|
||||
dst += size;
|
||||
n -= size;
|
||||
}
|
||||
return rc;
|
||||
|
@@ -238,7 +238,7 @@ static inline int is_module_addr(void *addr)
|
||||
#define _REGION_ENTRY_NOEXEC 0x100 /* region no-execute bit */
|
||||
#define _REGION_ENTRY_OFFSET 0xc0 /* region table offset */
|
||||
#define _REGION_ENTRY_INVALID 0x20 /* invalid region table entry */
|
||||
#define _REGION_ENTRY_TYPE_MASK 0x0c /* region/segment table type mask */
|
||||
#define _REGION_ENTRY_TYPE_MASK 0x0c /* region table type mask */
|
||||
#define _REGION_ENTRY_TYPE_R1 0x0c /* region first table type */
|
||||
#define _REGION_ENTRY_TYPE_R2 0x08 /* region second table type */
|
||||
#define _REGION_ENTRY_TYPE_R3 0x04 /* region third table type */
|
||||
@@ -277,6 +277,7 @@ static inline int is_module_addr(void *addr)
|
||||
#define _SEGMENT_ENTRY_PROTECT 0x200 /* segment protection bit */
|
||||
#define _SEGMENT_ENTRY_NOEXEC 0x100 /* segment no-execute bit */
|
||||
#define _SEGMENT_ENTRY_INVALID 0x20 /* invalid segment table entry */
|
||||
#define _SEGMENT_ENTRY_TYPE_MASK 0x0c /* segment table type mask */
|
||||
|
||||
#define _SEGMENT_ENTRY (0)
|
||||
#define _SEGMENT_ENTRY_EMPTY (_SEGMENT_ENTRY_INVALID)
|
||||
@@ -614,15 +615,9 @@ static inline int pgd_none(pgd_t pgd)
|
||||
|
||||
static inline int pgd_bad(pgd_t pgd)
|
||||
{
|
||||
/*
|
||||
* With dynamic page table levels the pgd can be a region table
|
||||
* entry or a segment table entry. Check for the bit that are
|
||||
* invalid for either table entry.
|
||||
*/
|
||||
unsigned long mask =
|
||||
~_SEGMENT_ENTRY_ORIGIN & ~_REGION_ENTRY_INVALID &
|
||||
~_REGION_ENTRY_TYPE_MASK & ~_REGION_ENTRY_LENGTH;
|
||||
return (pgd_val(pgd) & mask) != 0;
|
||||
if ((pgd_val(pgd) & _REGION_ENTRY_TYPE_MASK) < _REGION_ENTRY_TYPE_R1)
|
||||
return 0;
|
||||
return (pgd_val(pgd) & ~_REGION_ENTRY_BITS) != 0;
|
||||
}
|
||||
|
||||
static inline unsigned long pgd_pfn(pgd_t pgd)
|
||||
@@ -703,6 +698,8 @@ static inline int pmd_large(pmd_t pmd)
|
||||
|
||||
static inline int pmd_bad(pmd_t pmd)
|
||||
{
|
||||
if ((pmd_val(pmd) & _SEGMENT_ENTRY_TYPE_MASK) > 0)
|
||||
return 1;
|
||||
if (pmd_large(pmd))
|
||||
return (pmd_val(pmd) & ~_SEGMENT_ENTRY_BITS_LARGE) != 0;
|
||||
return (pmd_val(pmd) & ~_SEGMENT_ENTRY_BITS) != 0;
|
||||
@@ -710,8 +707,12 @@ static inline int pmd_bad(pmd_t pmd)
|
||||
|
||||
static inline int pud_bad(pud_t pud)
|
||||
{
|
||||
if ((pud_val(pud) & _REGION_ENTRY_TYPE_MASK) < _REGION_ENTRY_TYPE_R3)
|
||||
return pmd_bad(__pmd(pud_val(pud)));
|
||||
unsigned long type = pud_val(pud) & _REGION_ENTRY_TYPE_MASK;
|
||||
|
||||
if (type > _REGION_ENTRY_TYPE_R3)
|
||||
return 1;
|
||||
if (type < _REGION_ENTRY_TYPE_R3)
|
||||
return 0;
|
||||
if (pud_large(pud))
|
||||
return (pud_val(pud) & ~_REGION_ENTRY_BITS_LARGE) != 0;
|
||||
return (pud_val(pud) & ~_REGION_ENTRY_BITS) != 0;
|
||||
@@ -719,8 +720,12 @@ static inline int pud_bad(pud_t pud)
|
||||
|
||||
static inline int p4d_bad(p4d_t p4d)
|
||||
{
|
||||
if ((p4d_val(p4d) & _REGION_ENTRY_TYPE_MASK) < _REGION_ENTRY_TYPE_R2)
|
||||
return pud_bad(__pud(p4d_val(p4d)));
|
||||
unsigned long type = p4d_val(p4d) & _REGION_ENTRY_TYPE_MASK;
|
||||
|
||||
if (type > _REGION_ENTRY_TYPE_R2)
|
||||
return 1;
|
||||
if (type < _REGION_ENTRY_TYPE_R2)
|
||||
return 0;
|
||||
return (p4d_val(p4d) & ~_REGION_ENTRY_BITS) != 0;
|
||||
}
|
||||
|
||||
@@ -1204,42 +1209,79 @@ static inline pte_t mk_pte(struct page *page, pgprot_t pgprot)
|
||||
#define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
|
||||
#define pte_index(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE-1))
|
||||
|
||||
#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address))
|
||||
#define pgd_offset_k(address) pgd_offset(&init_mm, address)
|
||||
#define pgd_offset_raw(pgd, addr) ((pgd) + pgd_index(addr))
|
||||
|
||||
#define pmd_deref(pmd) (pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN)
|
||||
#define pud_deref(pud) (pud_val(pud) & _REGION_ENTRY_ORIGIN)
|
||||
#define p4d_deref(pud) (p4d_val(pud) & _REGION_ENTRY_ORIGIN)
|
||||
#define pgd_deref(pgd) (pgd_val(pgd) & _REGION_ENTRY_ORIGIN)
|
||||
|
||||
/*
|
||||
* The pgd_offset function *always* adds the index for the top-level
|
||||
* region/segment table. This is done to get a sequence like the
|
||||
* following to work:
|
||||
* pgdp = pgd_offset(current->mm, addr);
|
||||
* pgd = READ_ONCE(*pgdp);
|
||||
* p4dp = p4d_offset(&pgd, addr);
|
||||
* ...
|
||||
* The subsequent p4d_offset, pud_offset and pmd_offset functions
|
||||
* only add an index if they dereferenced the pointer.
|
||||
*/
|
||||
static inline pgd_t *pgd_offset_raw(pgd_t *pgd, unsigned long address)
|
||||
{
|
||||
unsigned long rste;
|
||||
unsigned int shift;
|
||||
|
||||
/* Get the first entry of the top level table */
|
||||
rste = pgd_val(*pgd);
|
||||
/* Pick up the shift from the table type of the first entry */
|
||||
shift = ((rste & _REGION_ENTRY_TYPE_MASK) >> 2) * 11 + 20;
|
||||
return pgd + ((address >> shift) & (PTRS_PER_PGD - 1));
|
||||
}
|
||||
|
||||
#define pgd_offset(mm, address) pgd_offset_raw(READ_ONCE((mm)->pgd), address)
|
||||
#define pgd_offset_k(address) pgd_offset(&init_mm, address)
|
||||
|
||||
static inline p4d_t *p4d_offset(pgd_t *pgd, unsigned long address)
|
||||
{
|
||||
p4d_t *p4d = (p4d_t *) pgd;
|
||||
|
||||
if ((pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R1)
|
||||
p4d = (p4d_t *) pgd_deref(*pgd);
|
||||
return p4d + p4d_index(address);
|
||||
if ((pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) >= _REGION_ENTRY_TYPE_R1)
|
||||
return (p4d_t *) pgd_deref(*pgd) + p4d_index(address);
|
||||
return (p4d_t *) pgd;
|
||||
}
|
||||
|
||||
static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address)
|
||||
{
|
||||
pud_t *pud = (pud_t *) p4d;
|
||||
|
||||
if ((p4d_val(*p4d) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R2)
|
||||
pud = (pud_t *) p4d_deref(*p4d);
|
||||
return pud + pud_index(address);
|
||||
if ((p4d_val(*p4d) & _REGION_ENTRY_TYPE_MASK) >= _REGION_ENTRY_TYPE_R2)
|
||||
return (pud_t *) p4d_deref(*p4d) + pud_index(address);
|
||||
return (pud_t *) p4d;
|
||||
}
|
||||
|
||||
static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address)
|
||||
{
|
||||
pmd_t *pmd = (pmd_t *) pud;
|
||||
|
||||
if ((pud_val(*pud) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3)
|
||||
pmd = (pmd_t *) pud_deref(*pud);
|
||||
return pmd + pmd_index(address);
|
||||
if ((pud_val(*pud) & _REGION_ENTRY_TYPE_MASK) >= _REGION_ENTRY_TYPE_R3)
|
||||
return (pmd_t *) pud_deref(*pud) + pmd_index(address);
|
||||
return (pmd_t *) pud;
|
||||
}
|
||||
|
||||
static inline pte_t *pte_offset(pmd_t *pmd, unsigned long address)
|
||||
{
|
||||
return (pte_t *) pmd_deref(*pmd) + pte_index(address);
|
||||
}
|
||||
|
||||
#define pte_offset_kernel(pmd, address) pte_offset(pmd, address)
|
||||
#define pte_offset_map(pmd, address) pte_offset_kernel(pmd, address)
|
||||
#define pte_unmap(pte) do { } while (0)
|
||||
|
||||
static inline bool gup_fast_permitted(unsigned long start, int nr_pages)
|
||||
{
|
||||
unsigned long len, end;
|
||||
|
||||
len = (unsigned long) nr_pages << PAGE_SHIFT;
|
||||
end = start + len;
|
||||
if (end < start)
|
||||
return false;
|
||||
return end <= current->mm->context.asce_limit;
|
||||
}
|
||||
#define gup_fast_permitted gup_fast_permitted
|
||||
|
||||
#define pfn_pte(pfn,pgprot) mk_pte_phys(__pa((pfn) << PAGE_SHIFT),(pgprot))
|
||||
#define pte_pfn(x) (pte_val(x) >> PAGE_SHIFT)
|
||||
#define pte_page(x) pfn_to_page(pte_pfn(x))
|
||||
@@ -1249,12 +1291,6 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address)
|
||||
#define p4d_page(p4d) pfn_to_page(p4d_pfn(p4d))
|
||||
#define pgd_page(pgd) pfn_to_page(pgd_pfn(pgd))
|
||||
|
||||
/* Find an entry in the lowest level page table.. */
|
||||
#define pte_offset(pmd, addr) ((pte_t *) pmd_deref(*(pmd)) + pte_index(addr))
|
||||
#define pte_offset_kernel(pmd, address) pte_offset(pmd,address)
|
||||
#define pte_offset_map(pmd, address) pte_offset_kernel(pmd, address)
|
||||
#define pte_unmap(pte) do { } while (0)
|
||||
|
||||
static inline pmd_t pmd_wrprotect(pmd_t pmd)
|
||||
{
|
||||
pmd_val(pmd) &= ~_SEGMENT_ENTRY_WRITE;
|
||||
|
@@ -156,25 +156,6 @@ struct thread_struct {
|
||||
|
||||
typedef struct thread_struct thread_struct;
|
||||
|
||||
/*
|
||||
* Stack layout of a C stack frame.
|
||||
*/
|
||||
#ifndef __PACK_STACK
|
||||
struct stack_frame {
|
||||
unsigned long back_chain;
|
||||
unsigned long empty1[5];
|
||||
unsigned long gprs[10];
|
||||
unsigned int empty2[8];
|
||||
};
|
||||
#else
|
||||
struct stack_frame {
|
||||
unsigned long empty1[5];
|
||||
unsigned int empty2[8];
|
||||
unsigned long gprs[10];
|
||||
unsigned long back_chain;
|
||||
};
|
||||
#endif
|
||||
|
||||
#define ARCH_MIN_TASKALIGN 8
|
||||
|
||||
#define INIT_THREAD { \
|
||||
@@ -206,11 +187,7 @@ struct mm_struct;
|
||||
struct seq_file;
|
||||
struct pt_regs;
|
||||
|
||||
typedef int (*dump_trace_func_t)(void *data, unsigned long address, int reliable);
|
||||
void dump_trace(dump_trace_func_t func, void *data,
|
||||
struct task_struct *task, unsigned long sp);
|
||||
void show_registers(struct pt_regs *regs);
|
||||
|
||||
void show_cacheinfo(struct seq_file *m);
|
||||
|
||||
/* Free all resources held by a thread. */
|
||||
@@ -244,55 +221,6 @@ static __no_kasan_or_inline unsigned short stap(void)
|
||||
return cpu_address;
|
||||
}
|
||||
|
||||
#define CALL_ARGS_0() \
|
||||
register unsigned long r2 asm("2")
|
||||
#define CALL_ARGS_1(arg1) \
|
||||
register unsigned long r2 asm("2") = (unsigned long)(arg1)
|
||||
#define CALL_ARGS_2(arg1, arg2) \
|
||||
CALL_ARGS_1(arg1); \
|
||||
register unsigned long r3 asm("3") = (unsigned long)(arg2)
|
||||
#define CALL_ARGS_3(arg1, arg2, arg3) \
|
||||
CALL_ARGS_2(arg1, arg2); \
|
||||
register unsigned long r4 asm("4") = (unsigned long)(arg3)
|
||||
#define CALL_ARGS_4(arg1, arg2, arg3, arg4) \
|
||||
CALL_ARGS_3(arg1, arg2, arg3); \
|
||||
register unsigned long r4 asm("5") = (unsigned long)(arg4)
|
||||
#define CALL_ARGS_5(arg1, arg2, arg3, arg4, arg5) \
|
||||
CALL_ARGS_4(arg1, arg2, arg3, arg4); \
|
||||
register unsigned long r4 asm("6") = (unsigned long)(arg5)
|
||||
|
||||
#define CALL_FMT_0
|
||||
#define CALL_FMT_1 CALL_FMT_0, "0" (r2)
|
||||
#define CALL_FMT_2 CALL_FMT_1, "d" (r3)
|
||||
#define CALL_FMT_3 CALL_FMT_2, "d" (r4)
|
||||
#define CALL_FMT_4 CALL_FMT_3, "d" (r5)
|
||||
#define CALL_FMT_5 CALL_FMT_4, "d" (r6)
|
||||
|
||||
#define CALL_CLOBBER_5 "0", "1", "14", "cc", "memory"
|
||||
#define CALL_CLOBBER_4 CALL_CLOBBER_5
|
||||
#define CALL_CLOBBER_3 CALL_CLOBBER_4, "5"
|
||||
#define CALL_CLOBBER_2 CALL_CLOBBER_3, "4"
|
||||
#define CALL_CLOBBER_1 CALL_CLOBBER_2, "3"
|
||||
#define CALL_CLOBBER_0 CALL_CLOBBER_1
|
||||
|
||||
#define CALL_ON_STACK(fn, stack, nr, args...) \
|
||||
({ \
|
||||
CALL_ARGS_##nr(args); \
|
||||
unsigned long prev; \
|
||||
\
|
||||
asm volatile( \
|
||||
" la %[_prev],0(15)\n" \
|
||||
" la 15,0(%[_stack])\n" \
|
||||
" stg %[_prev],%[_bc](15)\n" \
|
||||
" brasl 14,%[_fn]\n" \
|
||||
" la 15,0(%[_prev])\n" \
|
||||
: "+&d" (r2), [_prev] "=&a" (prev) \
|
||||
: [_stack] "a" (stack), \
|
||||
[_bc] "i" (offsetof(struct stack_frame, back_chain)), \
|
||||
[_fn] "X" (fn) CALL_FMT_##nr : CALL_CLOBBER_##nr); \
|
||||
r2; \
|
||||
})
|
||||
|
||||
/*
|
||||
* Give up the time slice of the virtual PU.
|
||||
*/
|
||||
@@ -339,10 +267,10 @@ static __no_kasan_or_inline void __load_psw_mask(unsigned long mask)
|
||||
|
||||
asm volatile(
|
||||
" larl %0,1f\n"
|
||||
" stg %0,%O1+8(%R1)\n"
|
||||
" lpswe %1\n"
|
||||
" stg %0,%1\n"
|
||||
" lpswe %2\n"
|
||||
"1:"
|
||||
: "=&d" (addr), "=Q" (psw) : "Q" (psw) : "memory", "cc");
|
||||
: "=&d" (addr), "=Q" (psw.addr) : "Q" (psw) : "memory", "cc");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -387,12 +315,12 @@ void enabled_wait(void);
|
||||
/*
|
||||
* Function to drop a processor into disabled wait state
|
||||
*/
|
||||
static inline void __noreturn disabled_wait(unsigned long code)
|
||||
static inline void __noreturn disabled_wait(void)
|
||||
{
|
||||
psw_t psw;
|
||||
|
||||
psw.mask = PSW_MASK_BASE | PSW_MASK_WAIT | PSW_MASK_BA | PSW_MASK_EA;
|
||||
psw.addr = code;
|
||||
psw.addr = _THIS_IP_;
|
||||
__load_psw(psw);
|
||||
while (1);
|
||||
}
|
||||
|
@@ -79,6 +79,9 @@ struct sclp_info {
|
||||
unsigned char has_kss : 1;
|
||||
unsigned char has_gisaf : 1;
|
||||
unsigned char has_diag318 : 1;
|
||||
unsigned char has_sipl : 1;
|
||||
unsigned char has_sipl_g2 : 1;
|
||||
unsigned char has_dirq : 1;
|
||||
unsigned int ibc;
|
||||
unsigned int mtid;
|
||||
unsigned int mtid_cp;
|
||||
|
@@ -2,8 +2,20 @@
|
||||
#ifndef _S390_SECTIONS_H
|
||||
#define _S390_SECTIONS_H
|
||||
|
||||
#define arch_is_kernel_initmem_freed arch_is_kernel_initmem_freed
|
||||
|
||||
#include <asm-generic/sections.h>
|
||||
|
||||
extern bool initmem_freed;
|
||||
|
||||
static inline int arch_is_kernel_initmem_freed(unsigned long addr)
|
||||
{
|
||||
if (!initmem_freed)
|
||||
return 0;
|
||||
return addr >= (unsigned long)__init_begin &&
|
||||
addr < (unsigned long)__init_end;
|
||||
}
|
||||
|
||||
/*
|
||||
* .boot.data section contains variables "shared" between the decompressor and
|
||||
* the decompressed kernel. The decompressor will store values in them, and
|
||||
@@ -16,4 +28,14 @@
|
||||
*/
|
||||
#define __bootdata(var) __section(.boot.data.var) var
|
||||
|
||||
/*
|
||||
* .boot.preserved.data is similar to .boot.data, but it is not part of the
|
||||
* .init section and thus will be preserved for later use in the decompressed
|
||||
* kernel.
|
||||
*/
|
||||
#define __bootdata_preserved(var) __section(.boot.preserved.data.var) var
|
||||
|
||||
extern unsigned long __sdma, __edma;
|
||||
extern unsigned long __stext_dma, __etext_dma;
|
||||
|
||||
#endif
|
||||
|
@@ -12,7 +12,10 @@
|
||||
#define EP_OFFSET 0x10008
|
||||
#define EP_STRING "S390EP"
|
||||
#define PARMAREA 0x10400
|
||||
#define PARMAREA_END 0x11000
|
||||
#define EARLY_SCCB_OFFSET 0x11000
|
||||
#define HEAD_END 0x12000
|
||||
|
||||
#define EARLY_SCCB_SIZE PAGE_SIZE
|
||||
|
||||
/*
|
||||
* Machine features detected in early.c
|
||||
@@ -65,6 +68,16 @@
|
||||
#define OLDMEM_SIZE (*(unsigned long *) (OLDMEM_SIZE_OFFSET))
|
||||
#define COMMAND_LINE ((char *) (COMMAND_LINE_OFFSET))
|
||||
|
||||
struct parmarea {
|
||||
unsigned long ipl_device; /* 0x10400 */
|
||||
unsigned long initrd_start; /* 0x10408 */
|
||||
unsigned long initrd_size; /* 0x10410 */
|
||||
unsigned long oldmem_base; /* 0x10418 */
|
||||
unsigned long oldmem_size; /* 0x10420 */
|
||||
char pad1[0x10480 - 0x10428]; /* 0x10428 - 0x10480 */
|
||||
char command_line[ARCH_COMMAND_LINE_SIZE]; /* 0x10480 */
|
||||
};
|
||||
|
||||
extern int noexec_disabled;
|
||||
extern int memory_end_set;
|
||||
extern unsigned long memory_end;
|
||||
@@ -134,6 +147,12 @@ extern void (*_machine_restart)(char *command);
|
||||
extern void (*_machine_halt)(void);
|
||||
extern void (*_machine_power_off)(void);
|
||||
|
||||
extern unsigned long __kaslr_offset;
|
||||
static inline unsigned long kaslr_offset(void)
|
||||
{
|
||||
return __kaslr_offset;
|
||||
}
|
||||
|
||||
#else /* __ASSEMBLY__ */
|
||||
|
||||
#define IPL_DEVICE (IPL_DEVICE_OFFSET)
|
||||
|
114
arch/s390/include/asm/stacktrace.h
Normal file
114
arch/s390/include/asm/stacktrace.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_S390_STACKTRACE_H
|
||||
#define _ASM_S390_STACKTRACE_H
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <asm/switch_to.h>
|
||||
|
||||
enum stack_type {
|
||||
STACK_TYPE_UNKNOWN,
|
||||
STACK_TYPE_TASK,
|
||||
STACK_TYPE_IRQ,
|
||||
STACK_TYPE_NODAT,
|
||||
STACK_TYPE_RESTART,
|
||||
};
|
||||
|
||||
struct stack_info {
|
||||
enum stack_type type;
|
||||
unsigned long begin, end;
|
||||
};
|
||||
|
||||
const char *stack_type_name(enum stack_type type);
|
||||
int get_stack_info(unsigned long sp, struct task_struct *task,
|
||||
struct stack_info *info, unsigned long *visit_mask);
|
||||
|
||||
static inline bool on_stack(struct stack_info *info,
|
||||
unsigned long addr, size_t len)
|
||||
{
|
||||
if (info->type == STACK_TYPE_UNKNOWN)
|
||||
return false;
|
||||
if (addr + len < addr)
|
||||
return false;
|
||||
return addr >= info->begin && addr + len < info->end;
|
||||
}
|
||||
|
||||
static inline unsigned long get_stack_pointer(struct task_struct *task,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
if (regs)
|
||||
return (unsigned long) kernel_stack_pointer(regs);
|
||||
if (task == current)
|
||||
return current_stack_pointer();
|
||||
return (unsigned long) task->thread.ksp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stack layout of a C stack frame.
|
||||
*/
|
||||
#ifndef __PACK_STACK
|
||||
struct stack_frame {
|
||||
unsigned long back_chain;
|
||||
unsigned long empty1[5];
|
||||
unsigned long gprs[10];
|
||||
unsigned int empty2[8];
|
||||
};
|
||||
#else
|
||||
struct stack_frame {
|
||||
unsigned long empty1[5];
|
||||
unsigned int empty2[8];
|
||||
unsigned long gprs[10];
|
||||
unsigned long back_chain;
|
||||
};
|
||||
#endif
|
||||
|
||||
#define CALL_ARGS_0() \
|
||||
register unsigned long r2 asm("2")
|
||||
#define CALL_ARGS_1(arg1) \
|
||||
register unsigned long r2 asm("2") = (unsigned long)(arg1)
|
||||
#define CALL_ARGS_2(arg1, arg2) \
|
||||
CALL_ARGS_1(arg1); \
|
||||
register unsigned long r3 asm("3") = (unsigned long)(arg2)
|
||||
#define CALL_ARGS_3(arg1, arg2, arg3) \
|
||||
CALL_ARGS_2(arg1, arg2); \
|
||||
register unsigned long r4 asm("4") = (unsigned long)(arg3)
|
||||
#define CALL_ARGS_4(arg1, arg2, arg3, arg4) \
|
||||
CALL_ARGS_3(arg1, arg2, arg3); \
|
||||
register unsigned long r4 asm("5") = (unsigned long)(arg4)
|
||||
#define CALL_ARGS_5(arg1, arg2, arg3, arg4, arg5) \
|
||||
CALL_ARGS_4(arg1, arg2, arg3, arg4); \
|
||||
register unsigned long r4 asm("6") = (unsigned long)(arg5)
|
||||
|
||||
#define CALL_FMT_0 "=&d" (r2) :
|
||||
#define CALL_FMT_1 "+&d" (r2) :
|
||||
#define CALL_FMT_2 CALL_FMT_1 "d" (r3),
|
||||
#define CALL_FMT_3 CALL_FMT_2 "d" (r4),
|
||||
#define CALL_FMT_4 CALL_FMT_3 "d" (r5),
|
||||
#define CALL_FMT_5 CALL_FMT_4 "d" (r6),
|
||||
|
||||
#define CALL_CLOBBER_5 "0", "1", "14", "cc", "memory"
|
||||
#define CALL_CLOBBER_4 CALL_CLOBBER_5
|
||||
#define CALL_CLOBBER_3 CALL_CLOBBER_4, "5"
|
||||
#define CALL_CLOBBER_2 CALL_CLOBBER_3, "4"
|
||||
#define CALL_CLOBBER_1 CALL_CLOBBER_2, "3"
|
||||
#define CALL_CLOBBER_0 CALL_CLOBBER_1
|
||||
|
||||
#define CALL_ON_STACK(fn, stack, nr, args...) \
|
||||
({ \
|
||||
CALL_ARGS_##nr(args); \
|
||||
unsigned long prev; \
|
||||
\
|
||||
asm volatile( \
|
||||
" la %[_prev],0(15)\n" \
|
||||
" la 15,0(%[_stack])\n" \
|
||||
" stg %[_prev],%[_bc](15)\n" \
|
||||
" brasl 14,%[_fn]\n" \
|
||||
" la 15,0(%[_prev])\n" \
|
||||
: [_prev] "=&a" (prev), CALL_FMT_##nr \
|
||||
[_stack] "a" (stack), \
|
||||
[_bc] "i" (offsetof(struct stack_frame, back_chain)), \
|
||||
[_fn] "X" (fn) : CALL_CLOBBER_##nr); \
|
||||
r2; \
|
||||
})
|
||||
|
||||
#endif /* _ASM_S390_STACKTRACE_H */
|
@@ -14,13 +14,8 @@
|
||||
#include <linux/err.h>
|
||||
#include <asm/ptrace.h>
|
||||
|
||||
/*
|
||||
* The syscall table always contains 32 bit pointers since we know that the
|
||||
* address of the function to be called is (way) below 4GB. So the "int"
|
||||
* type here is what we want [need] for both 32 bit and 64 bit systems.
|
||||
*/
|
||||
extern const unsigned int sys_call_table[];
|
||||
extern const unsigned int sys_call_table_emu[];
|
||||
extern const unsigned long sys_call_table[];
|
||||
extern const unsigned long sys_call_table_emu[];
|
||||
|
||||
static inline long syscall_get_nr(struct task_struct *task,
|
||||
struct pt_regs *regs)
|
||||
|
@@ -119,8 +119,8 @@
|
||||
"Type aliasing is used to sanitize syscall arguments");\
|
||||
asmlinkage long __s390x_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) \
|
||||
__attribute__((alias(__stringify(__se_sys##name)))); \
|
||||
ALLOW_ERROR_INJECTION(__s390x_sys##name, ERRNO); \
|
||||
static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \
|
||||
ALLOW_ERROR_INJECTION(__s390x_sys##name, ERRNO); \
|
||||
long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \
|
||||
static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \
|
||||
__S390_SYS_STUBx(x, name, __VA_ARGS__) \
|
||||
asmlinkage long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \
|
||||
|
@@ -55,8 +55,10 @@ raw_copy_from_user(void *to, const void __user *from, unsigned long n);
|
||||
unsigned long __must_check
|
||||
raw_copy_to_user(void __user *to, const void *from, unsigned long n);
|
||||
|
||||
#ifndef CONFIG_KASAN
|
||||
#define INLINE_COPY_FROM_USER
|
||||
#define INLINE_COPY_TO_USER
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
|
||||
|
||||
|
101
arch/s390/include/asm/unwind.h
Normal file
101
arch/s390/include/asm/unwind.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_S390_UNWIND_H
|
||||
#define _ASM_S390_UNWIND_H
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/ftrace.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/stacktrace.h>
|
||||
|
||||
/*
|
||||
* To use the stack unwinder it has to be initialized with unwind_start.
|
||||
* There four combinations for task and regs:
|
||||
* 1) task==NULL, regs==NULL: the unwind starts for the task that is currently
|
||||
* running, sp/ip picked up from the CPU registers
|
||||
* 2) task==NULL, regs!=NULL: the unwind starts from the sp/ip found in
|
||||
* the struct pt_regs of an interrupt frame for the current task
|
||||
* 3) task!=NULL, regs==NULL: the unwind starts for an inactive task with
|
||||
* the sp picked up from task->thread.ksp and the ip picked up from the
|
||||
* return address stored by __switch_to
|
||||
* 4) task!=NULL, regs!=NULL: the sp/ip are picked up from the interrupt
|
||||
* frame 'regs' of a inactive task
|
||||
* If 'first_frame' is not zero unwind_start skips unwind frames until it
|
||||
* reaches the specified stack pointer.
|
||||
* The end of the unwinding is indicated with unwind_done, this can be true
|
||||
* right after unwind_start, e.g. with first_frame!=0 that can not be found.
|
||||
* unwind_next_frame skips to the next frame.
|
||||
* Once the unwind is completed unwind_error() can be used to check if there
|
||||
* has been a situation where the unwinder could not correctly understand
|
||||
* the tasks call chain.
|
||||
*/
|
||||
|
||||
struct unwind_state {
|
||||
struct stack_info stack_info;
|
||||
unsigned long stack_mask;
|
||||
struct task_struct *task;
|
||||
struct pt_regs *regs;
|
||||
unsigned long sp, ip;
|
||||
int graph_idx;
|
||||
bool reliable;
|
||||
bool error;
|
||||
};
|
||||
|
||||
void __unwind_start(struct unwind_state *state, struct task_struct *task,
|
||||
struct pt_regs *regs, unsigned long first_frame);
|
||||
bool unwind_next_frame(struct unwind_state *state);
|
||||
unsigned long unwind_get_return_address(struct unwind_state *state);
|
||||
|
||||
static inline bool unwind_done(struct unwind_state *state)
|
||||
{
|
||||
return state->stack_info.type == STACK_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
static inline bool unwind_error(struct unwind_state *state)
|
||||
{
|
||||
return state->error;
|
||||
}
|
||||
|
||||
static inline void unwind_start(struct unwind_state *state,
|
||||
struct task_struct *task,
|
||||
struct pt_regs *regs,
|
||||
unsigned long sp)
|
||||
{
|
||||
sp = sp ? : get_stack_pointer(task, regs);
|
||||
__unwind_start(state, task, regs, sp);
|
||||
}
|
||||
|
||||
static inline struct pt_regs *unwind_get_entry_regs(struct unwind_state *state)
|
||||
{
|
||||
return unwind_done(state) ? NULL : state->regs;
|
||||
}
|
||||
|
||||
#define unwind_for_each_frame(state, task, regs, first_frame) \
|
||||
for (unwind_start(state, task, regs, first_frame); \
|
||||
!unwind_done(state); \
|
||||
unwind_next_frame(state))
|
||||
|
||||
static inline void unwind_init(void) {}
|
||||
static inline void unwind_module_init(struct module *mod, void *orc_ip,
|
||||
size_t orc_ip_size, void *orc,
|
||||
size_t orc_size) {}
|
||||
|
||||
#ifdef CONFIG_KASAN
|
||||
/*
|
||||
* This disables KASAN checking when reading a value from another task's stack,
|
||||
* since the other task could be running on another CPU and could have poisoned
|
||||
* the stack in the meantime.
|
||||
*/
|
||||
#define READ_ONCE_TASK_STACK(task, x) \
|
||||
({ \
|
||||
unsigned long val; \
|
||||
if (task == current) \
|
||||
val = READ_ONCE(x); \
|
||||
else \
|
||||
val = READ_ONCE_NOCHECK(x); \
|
||||
val; \
|
||||
})
|
||||
#else
|
||||
#define READ_ONCE_TASK_STACK(task, x) READ_ONCE(x)
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_S390_UNWIND_H */
|
132
arch/s390/include/asm/uv.h
Normal file
132
arch/s390/include/asm/uv.h
Normal file
@@ -0,0 +1,132 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Ultravisor Interfaces
|
||||
*
|
||||
* Copyright IBM Corp. 2019
|
||||
*
|
||||
* Author(s):
|
||||
* Vasily Gorbik <gor@linux.ibm.com>
|
||||
* Janosch Frank <frankja@linux.ibm.com>
|
||||
*/
|
||||
#ifndef _ASM_S390_UV_H
|
||||
#define _ASM_S390_UV_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/bug.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
#define UVC_RC_EXECUTED 0x0001
|
||||
#define UVC_RC_INV_CMD 0x0002
|
||||
#define UVC_RC_INV_STATE 0x0003
|
||||
#define UVC_RC_INV_LEN 0x0005
|
||||
#define UVC_RC_NO_RESUME 0x0007
|
||||
|
||||
#define UVC_CMD_QUI 0x0001
|
||||
#define UVC_CMD_SET_SHARED_ACCESS 0x1000
|
||||
#define UVC_CMD_REMOVE_SHARED_ACCESS 0x1001
|
||||
|
||||
/* Bits in installed uv calls */
|
||||
enum uv_cmds_inst {
|
||||
BIT_UVC_CMD_QUI = 0,
|
||||
BIT_UVC_CMD_SET_SHARED_ACCESS = 8,
|
||||
BIT_UVC_CMD_REMOVE_SHARED_ACCESS = 9,
|
||||
};
|
||||
|
||||
struct uv_cb_header {
|
||||
u16 len;
|
||||
u16 cmd; /* Command Code */
|
||||
u16 rc; /* Response Code */
|
||||
u16 rrc; /* Return Reason Code */
|
||||
} __packed __aligned(8);
|
||||
|
||||
struct uv_cb_qui {
|
||||
struct uv_cb_header header;
|
||||
u64 reserved08;
|
||||
u64 inst_calls_list[4];
|
||||
u64 reserved30[15];
|
||||
} __packed __aligned(8);
|
||||
|
||||
struct uv_cb_share {
|
||||
struct uv_cb_header header;
|
||||
u64 reserved08[3];
|
||||
u64 paddr;
|
||||
u64 reserved28;
|
||||
} __packed __aligned(8);
|
||||
|
||||
static inline int uv_call(unsigned long r1, unsigned long r2)
|
||||
{
|
||||
int cc;
|
||||
|
||||
asm volatile(
|
||||
"0: .insn rrf,0xB9A40000,%[r1],%[r2],0,0\n"
|
||||
" brc 3,0b\n"
|
||||
" ipm %[cc]\n"
|
||||
" srl %[cc],28\n"
|
||||
: [cc] "=d" (cc)
|
||||
: [r1] "a" (r1), [r2] "a" (r2)
|
||||
: "memory", "cc");
|
||||
return cc;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROTECTED_VIRTUALIZATION_GUEST
|
||||
extern int prot_virt_guest;
|
||||
|
||||
static inline int is_prot_virt_guest(void)
|
||||
{
|
||||
return prot_virt_guest;
|
||||
}
|
||||
|
||||
static inline int share(unsigned long addr, u16 cmd)
|
||||
{
|
||||
struct uv_cb_share uvcb = {
|
||||
.header.cmd = cmd,
|
||||
.header.len = sizeof(uvcb),
|
||||
.paddr = addr
|
||||
};
|
||||
|
||||
if (!is_prot_virt_guest())
|
||||
return -ENOTSUPP;
|
||||
/*
|
||||
* Sharing is page wise, if we encounter addresses that are
|
||||
* not page aligned, we assume something went wrong. If
|
||||
* malloced structs are passed to this function, we could leak
|
||||
* data to the hypervisor.
|
||||
*/
|
||||
BUG_ON(addr & ~PAGE_MASK);
|
||||
|
||||
if (!uv_call(0, (u64)&uvcb))
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Guest 2 request to the Ultravisor to make a page shared with the
|
||||
* hypervisor for IO.
|
||||
*
|
||||
* @addr: Real or absolute address of the page to be shared
|
||||
*/
|
||||
static inline int uv_set_shared(unsigned long addr)
|
||||
{
|
||||
return share(addr, UVC_CMD_SET_SHARED_ACCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Guest 2 request to the Ultravisor to make a page unshared.
|
||||
*
|
||||
* @addr: Real or absolute address of the page to be unshared
|
||||
*/
|
||||
static inline int uv_remove_shared(unsigned long addr)
|
||||
{
|
||||
return share(addr, UVC_CMD_REMOVE_SHARED_ACCESS);
|
||||
}
|
||||
|
||||
void uv_query_info(void);
|
||||
#else
|
||||
#define is_prot_virt_guest() 0
|
||||
static inline int uv_set_shared(unsigned long addr) { return 0; }
|
||||
static inline int uv_remove_shared(unsigned long addr) { return 0; }
|
||||
static inline void uv_query_info(void) {}
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_S390_UV_H */
|
@@ -18,3 +18,16 @@
|
||||
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.boot.data*))) \
|
||||
__boot_data_end = .; \
|
||||
}
|
||||
|
||||
/*
|
||||
* .boot.preserved.data is similar to .boot.data, but it is not part of the
|
||||
* .init section and thus will be preserved for later use in the decompressed
|
||||
* kernel.
|
||||
*/
|
||||
#define BOOT_DATA_PRESERVED \
|
||||
. = ALIGN(PAGE_SIZE); \
|
||||
.boot.preserved.data : { \
|
||||
__boot_data_preserved_start = .; \
|
||||
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.boot.preserved.data*))) \
|
||||
__boot_data_preserved_end = .; \
|
||||
}
|
||||
|
Reference in New Issue
Block a user