Commit d0a16fe9 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'parisc-5.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux

Pull parisc updates from Helge Deller:

 - Make the powerpc implementation to read elf files available as a
   public kexec interface so it can be re-used on other architectures
   (Sven)

 - Implement kexec on parisc (Sven)

 - Add kprobes on ftrace on parisc (Sven)

 - Fix kernel crash with HSC-PCI cards based on card-mode Dino

 - Add assembly implementations for memset, strlen, strcpy, strncpy and
   strcat

 - Some cleanups, documentation updates, warning fixes, ...

* 'parisc-5.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux: (25 commits)
  parisc: Have git ignore generated real2.S and firmware.c
  parisc: Disable HP HSC-PCI Cards to prevent kernel crash
  parisc: add support for kexec_file_load() syscall
  parisc: wire up kexec_file_load syscall
  parisc: add kexec syscall support
  parisc: add __pdc_cpu_rendezvous()
  kprobes/parisc: remove arch_kprobe_on_func_entry()
  kexec_elf: support 32 bit ELF files
  kexec_elf: remove unused variable in kexec_elf_load()
  kexec_elf: remove Elf_Rel macro
  kexec_elf: remove PURGATORY_STACK_SIZE
  kexec_elf: remove parsing of section headers
  kexec_elf: change order of elf_*_to_cpu() functions
  kexec: add KEXEC_ELF
  parisc: Save some bytes in dino driver
  parisc: Drop comments which are already in pci.h
  parisc: Convert eisa_enumerator to use pr_cont()
  parisc: Avoid warning when loading hppb driver
  parisc: speed up flush_tlb_all_local with qemu
  parisc: Add ALTERNATIVE_CODE() and ALT_COND_RUN_ON_QEMU
  ...
parents 76f0f227 fcc16a9e
......@@ -21,7 +21,7 @@
| nds32: | TODO |
| nios2: | TODO |
| openrisc: | TODO |
| parisc: | TODO |
| parisc: | ok |
| powerpc: | ok |
| riscv: | TODO |
| s390: | ok |
......
......@@ -21,7 +21,7 @@
| nds32: | TODO |
| nios2: | TODO |
| openrisc: | TODO |
| parisc: | TODO |
| parisc: | ok |
| powerpc: | ok |
| riscv: | TODO |
| s390: | TODO |
......
......@@ -18,6 +18,9 @@ config KEXEC_CORE
select CRASH_CORE
bool
config KEXEC_ELF
bool
config HAVE_IMA_KEXEC
bool
......
......@@ -61,6 +61,8 @@ config PARISC
select HAVE_KRETPROBES
select HAVE_DYNAMIC_FTRACE if $(cc-option,-fpatchable-function-entry=1,1)
select HAVE_FTRACE_MCOUNT_RECORD if HAVE_DYNAMIC_FTRACE
select HAVE_KPROBES_ON_FTRACE
select HAVE_DYNAMIC_FTRACE_WITH_REGS
help
The PA-RISC microprocessor is designed by Hewlett-Packard and used
......@@ -344,6 +346,29 @@ config NR_CPUS
depends on SMP
default "4"
config KEXEC
bool "Kexec system call"
select KEXEC_CORE
help
kexec is a system call that implements the ability to shutdown your
current kernel, and to start another kernel. It is like a reboot
but it is independent of the system firmware. And like a reboot
you can start any kernel with it, not just Linux.
It is an ongoing process to be certain the hardware in a machine
shutdown, so do not be surprised if this code does not
initially work for you.
config KEXEC_FILE
bool "kexec file based system call"
select KEXEC_CORE
select KEXEC_ELF
help
This enables the kexec_file_load() System call. This is
file based and takes file descriptors as system call argument
for kernel and initramfs as opposed to list of segments as
accepted by previous system call.
endmenu
......
firmware.c
real2.S
sizes.h
vmlinux
vmlinux.lds
......@@ -8,6 +8,7 @@
#define ALT_COND_NO_ICACHE 0x04 /* if system has no i-cache */
#define ALT_COND_NO_SPLIT_TLB 0x08 /* if split_tlb == 0 */
#define ALT_COND_NO_IOC_FDC 0x10 /* if I/O cache does not need flushes */
#define ALT_COND_RUN_ON_QEMU 0x20 /* if running on QEMU */
#define INSN_PxTLB 0x02 /* modify pdtlb, pitlb */
#define INSN_NOP 0x08000240 /* nop */
......@@ -21,7 +22,7 @@
struct alt_instr {
s32 orig_offset; /* offset to original instructions */
u32 len; /* end of original instructions */
s32 len; /* end of original instructions */
u32 cond; /* see ALT_COND_XXX */
u32 replacement; /* replacement instruction or code */
};
......@@ -40,12 +41,20 @@ void apply_alternatives(struct alt_instr *start, struct alt_instr *end,
#else
/* to replace one single instructions by a new instruction */
#define ALTERNATIVE(from, to, cond, replacement)\
.section .altinstructions, "aw" ! \
.word (from - .), (to - from)/4 ! \
.word cond, replacement ! \
.previous
/* to replace multiple instructions by new code */
#define ALTERNATIVE_CODE(from, num_instructions, cond, new_instr_ptr)\
.section .altinstructions, "aw" ! \
.word (from - .), -num_instructions ! \
.word cond, (new_instr_ptr - .) ! \
.previous
#endif /* __ASSEMBLY__ */
#endif /* __ASM_PARISC_ALTERNATIVE_H */
......@@ -30,6 +30,7 @@
enum fixed_addresses {
/* Support writing RO kernel text via kprobes, jump labels, etc. */
FIX_TEXT_POKE0,
FIX_TEXT_KEXEC,
FIX_BITMAP_COUNT
};
......
......@@ -8,6 +8,7 @@ extern void mcount(void);
#define MCOUNT_ADDR ((unsigned long)mcount)
#define MCOUNT_INSN_SIZE 4
#define CC_USING_NOP_MCOUNT
#define ARCH_SUPPORTS_FTRACE_OPS 1
extern unsigned long sys_call_table[];
extern unsigned long return_address(unsigned int);
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_PARISC_KEXEC_H
#define _ASM_PARISC_KEXEC_H
#ifdef CONFIG_KEXEC
/* Maximum physical address we can use pages from */
#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
/* Maximum address we can reach in physical address mode */
#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL)
/* Maximum address we can use for the control code buffer */
#define KEXEC_CONTROL_MEMORY_LIMIT (-1UL)
#define KEXEC_CONTROL_PAGE_SIZE 4096
#define KEXEC_ARCH KEXEC_ARCH_PARISC
#define ARCH_HAS_KIMAGE_ARCH
#ifndef __ASSEMBLY__
struct kimage_arch {
unsigned long initrd_start;
unsigned long initrd_end;
unsigned long cmdline;
};
static inline void crash_setup_regs(struct pt_regs *newregs,
struct pt_regs *oldregs)
{
/* Dummy implementation for now */
}
#endif /* __ASSEMBLY__ */
#endif /* CONFIG_KEXEC */
#endif /* _ASM_PARISC_KEXEC_H */
......@@ -91,6 +91,7 @@ int pdc_sti_call(unsigned long func, unsigned long flags,
unsigned long inptr, unsigned long outputr,
unsigned long glob_cfg);
int __pdc_cpu_rendezvous(void);
static inline char * os_id_to_string(u16 os_id) {
switch(os_id) {
case OS_ID_NONE: return "No OS";
......
......@@ -8,4 +8,19 @@ extern void * memset(void *, int, size_t);
#define __HAVE_ARCH_MEMCPY
void * memcpy(void * dest,const void *src,size_t count);
#define __HAVE_ARCH_STRLEN
extern size_t strlen(const char *s);
#define __HAVE_ARCH_STRCPY
extern char *strcpy(char *dest, const char *src);
#define __HAVE_ARCH_STRNCPY
extern char *strncpy(char *dest, const char *src, size_t count);
#define __HAVE_ARCH_STRCAT
extern char *strcat(char *dest, const char *src);
#define __HAVE_ARCH_MEMSET
extern void *memset(void *, int, size_t);
#endif
......@@ -37,3 +37,5 @@ obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
obj-$(CONFIG_KGDB) += kgdb.o
obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_KEXEC) += kexec.o relocate_kernel.o
obj-$(CONFIG_KEXEC_FILE) += kexec_file.o
......@@ -28,7 +28,8 @@ void __init_or_module apply_alternatives(struct alt_instr *start,
for (entry = start; entry < end; entry++, index++) {
u32 *from, len, cond, replacement;
u32 *from, cond, replacement;
s32 len;
from = (u32 *)((ulong)&entry->orig_offset + entry->orig_offset);
len = entry->len;
......@@ -49,6 +50,8 @@ void __init_or_module apply_alternatives(struct alt_instr *start,
continue;
if ((cond & ALT_COND_NO_ICACHE) && (cache_info.ic_size != 0))
continue;
if ((cond & ALT_COND_RUN_ON_QEMU) && !running_on_qemu)
continue;
/*
* If the PDC_MODEL capabilities has Non-coherent IO-PDIR bit
......@@ -74,11 +77,19 @@ void __init_or_module apply_alternatives(struct alt_instr *start,
if (replacement == INSN_NOP && len > 1)
replacement = 0xe8000002 + (len-2)*8; /* "b,n .+8" */
pr_debug("Do %d: Cond 0x%x, Replace %02d instructions @ 0x%px with 0x%08x\n",
index, cond, len, from, replacement);
/* Replace instruction */
*from = replacement;
pr_debug("ALTERNATIVE %3d: Cond %2x, Replace %2d instructions to 0x%08x @ 0x%px (%pS)\n",
index, cond, len, replacement, from, from);
if (len < 0) {
/* Replace multiple instruction by new code */
u32 *source;
len = -len;
source = (u32 *)((ulong)&entry->replacement + entry->replacement);
memcpy(from, source, 4 * len);
} else {
/* Replace by one instruction */
*from = replacement;
}
applied++;
}
......
......@@ -1996,6 +1996,7 @@ _mcount:
* calling mcount(), and 2 instructions for ftrace_stub(). That way we
* have all on one L1 cacheline.
*/
ldi 0, %arg3
b ftrace_function_trampoline
copy %r3, %arg2 /* caller original %sp */
ftrace_stub:
......@@ -2048,6 +2049,7 @@ ftrace_caller:
LDREG 0(%r3), %r25
copy %rp, %r26
ldo -8(%r25), %r25
ldi 0, %r23 /* no pt_regs */
b,l ftrace_function_trampoline, %rp
copy %r3, %r24
......@@ -2075,6 +2077,103 @@ ftrace_caller:
ENDPROC_CFI(ftrace_caller)
#ifdef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS
ENTRY_CFI(ftrace_regs_caller,caller,frame=FTRACE_FRAME_SIZE+PT_SZ_ALGN,
CALLS,SAVE_RP,SAVE_SP)
ftrace_regs_caller:
.global ftrace_regs_caller
ldo -FTRACE_FRAME_SIZE(%sp), %r1
STREG %rp, -RP_OFFSET(%r1)
copy %sp, %r1
ldo PT_SZ_ALGN(%sp), %sp
STREG %rp, PT_GR2(%r1)
STREG %r3, PT_GR3(%r1)
STREG %r4, PT_GR4(%r1)
STREG %r5, PT_GR5(%r1)
STREG %r6, PT_GR6(%r1)
STREG %r7, PT_GR7(%r1)
STREG %r8, PT_GR8(%r1)
STREG %r9, PT_GR9(%r1)
STREG %r10, PT_GR10(%r1)
STREG %r11, PT_GR11(%r1)
STREG %r12, PT_GR12(%r1)
STREG %r13, PT_GR13(%r1)
STREG %r14, PT_GR14(%r1)
STREG %r15, PT_GR15(%r1)
STREG %r16, PT_GR16(%r1)
STREG %r17, PT_GR17(%r1)
STREG %r18, PT_GR18(%r1)
STREG %r19, PT_GR19(%r1)
STREG %r20, PT_GR20(%r1)
STREG %r21, PT_GR21(%r1)
STREG %r22, PT_GR22(%r1)
STREG %r23, PT_GR23(%r1)
STREG %r24, PT_GR24(%r1)
STREG %r25, PT_GR25(%r1)
STREG %r26, PT_GR26(%r1)
STREG %r27, PT_GR27(%r1)
STREG %r28, PT_GR28(%r1)
STREG %r29, PT_GR29(%r1)
STREG %r30, PT_GR30(%r1)
STREG %r31, PT_GR31(%r1)
mfctl %cr11, %r26
STREG %r26, PT_SAR(%r1)
copy %rp, %r26
LDREG -FTRACE_FRAME_SIZE-PT_SZ_ALGN(%sp), %r25
ldo -8(%r25), %r25
copy %r3, %arg2
b,l ftrace_function_trampoline, %rp
copy %r1, %arg3 /* struct pt_regs */
ldo -PT_SZ_ALGN(%sp), %r1
LDREG PT_SAR(%r1), %rp
mtctl %rp, %cr11
LDREG PT_GR2(%r1), %rp
LDREG PT_GR3(%r1), %r3
LDREG PT_GR4(%r1), %r4
LDREG PT_GR5(%r1), %r5
LDREG PT_GR6(%r1), %r6
LDREG PT_GR7(%r1), %r7
LDREG PT_GR8(%r1), %r8
LDREG PT_GR9(%r1), %r9
LDREG PT_GR10(%r1),%r10
LDREG PT_GR11(%r1),%r11
LDREG PT_GR12(%r1),%r12
LDREG PT_GR13(%r1),%r13
LDREG PT_GR14(%r1),%r14
LDREG PT_GR15(%r1),%r15
LDREG PT_GR16(%r1),%r16
LDREG PT_GR17(%r1),%r17
LDREG PT_GR18(%r1),%r18
LDREG PT_GR19(%r1),%r19
LDREG PT_GR20(%r1),%r20
LDREG PT_GR21(%r1),%r21
LDREG PT_GR22(%r1),%r22
LDREG PT_GR23(%r1),%r23
LDREG PT_GR24(%r1),%r24
LDREG PT_GR25(%r1),%r25
LDREG PT_GR26(%r1),%r26
LDREG PT_GR27(%r1),%r27
LDREG PT_GR28(%r1),%r28
LDREG PT_GR29(%r1),%r29
LDREG PT_GR30(%r1),%r30
LDREG PT_GR31(%r1),%r31
ldo -PT_SZ_ALGN(%sp), %sp
LDREGM -FTRACE_FRAME_SIZE(%sp), %r1
/* Adjust return point to jump back to beginning of traced function */
ldo -4(%r1), %r1
bv,n (%r1)
ENDPROC_CFI(ftrace_regs_caller)
#endif
#endif
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
......
......@@ -311,6 +311,19 @@ int pdc_chassis_disp(unsigned long disp)
return retval;
}
/**
* pdc_cpu_rendenzvous - Stop currently executing CPU
* @retval: -1 on error, 0 on success
*/
int __pdc_cpu_rendezvous(void)
{
if (is_pdc_pat())
return mem_pdc_call(PDC_PAT_CPU, PDC_PAT_CPU_RENDEZVOUS);
else
return mem_pdc_call(PDC_PROC, 1, 0);
}
/**
* pdc_chassis_warn - Fetches chassis warnings
* @retval: -1 on error, 0 on success
......
......@@ -13,6 +13,8 @@
#include <linux/init.h>
#include <linux/ftrace.h>
#include <linux/uaccess.h>
#include <linux/kprobes.h>
#include <linux/ptrace.h>
#include <asm/assembly.h>
#include <asm/sections.h>
......@@ -48,17 +50,22 @@ static void __hot prepare_ftrace_return(unsigned long *parent,
void notrace __hot ftrace_function_trampoline(unsigned long parent,
unsigned long self_addr,
unsigned long org_sp_gr3)
unsigned long org_sp_gr3,
struct pt_regs *regs)
{
#ifndef CONFIG_DYNAMIC_FTRACE
extern ftrace_func_t ftrace_trace_function;
#endif
if (ftrace_trace_function != ftrace_stub)
ftrace_trace_function(self_addr, parent, NULL, NULL);
extern struct ftrace_ops *function_trace_op;
if (function_trace_op->flags & FTRACE_OPS_FL_ENABLED &&
ftrace_trace_function != ftrace_stub)
ftrace_trace_function(self_addr, parent,
function_trace_op, regs);
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
if (ftrace_graph_return != (trace_func_graph_ret_t) ftrace_stub ||
ftrace_graph_entry != ftrace_graph_entry_stub) {
ftrace_graph_entry != ftrace_graph_entry_stub) {
unsigned long *parent_rp;
/* calculate pointer to %rp in stack */
......@@ -96,6 +103,12 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
return 0;
}
int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
unsigned long addr)
{
return 0;
}
unsigned long ftrace_call_adjust(unsigned long addr)
{
return addr+(FTRACE_PATCHABLE_FUNCTION_SIZE-1)*4;
......@@ -187,3 +200,46 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
return 0;
}
#endif
#ifdef CONFIG_KPROBES_ON_FTRACE
void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
struct ftrace_ops *ops, struct pt_regs *regs)
{
struct kprobe_ctlblk *kcb;
struct kprobe *p = get_kprobe((kprobe_opcode_t *)ip);
if (unlikely(!p) || kprobe_disabled(p))
return;
if (kprobe_running()) {
kprobes_inc_nmissed_count(p);
return;
}
__this_cpu_write(current_kprobe, p);
kcb = get_kprobe_ctlblk();
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
regs->iaoq[0] = ip;
regs->iaoq[1] = ip + 4;
if (!p->pre_handler || !p->pre_handler(p, regs)) {
regs->iaoq[0] = ip + 4;
regs->iaoq[1] = ip + 8;
if (unlikely(p->post_handler)) {
kcb->kprobe_status = KPROBE_HIT_SSDONE;
p->post_handler(p, regs, 0);
}
}
__this_cpu_write(current_kprobe, NULL);
}
NOKPROBE_SYMBOL(kprobe_ftrace_handler);
int arch_prepare_kprobe_ftrace(struct kprobe *p)
{
p->ainsn.insn = NULL;
return 0;
}
#endif
// SPDX-License-Identifier: GPL-2.0
#include <linux/kernel.h>
#include <linux/console.h>
#include <linux/kexec.h>
#include <linux/delay.h>
#include <asm/cacheflush.h>
#include <asm/sections.h>
extern void relocate_new_kernel(unsigned long head,
unsigned long start,
unsigned long phys);
extern const unsigned int relocate_new_kernel_size;
extern unsigned int kexec_initrd_start_offset;
extern unsigned int kexec_initrd_end_offset;
extern unsigned int kexec_cmdline_offset;
extern unsigned int kexec_free_mem_offset;
static void kexec_show_segment_info(const struct kimage *kimage,
unsigned long n)
{
pr_debug(" segment[%lu]: %016lx - %016lx, 0x%lx bytes, %lu pages\n",
n,
kimage->segment[n].mem,
kimage->segment[n].mem + kimage->segment[n].memsz,
(unsigned long)kimage->segment[n].memsz,
(unsigned long)kimage->segment[n].memsz / PAGE_SIZE);
}
static void kexec_image_info(const struct kimage *kimage)
{
unsigned long i;
pr_debug("kexec kimage info:\n");
pr_debug(" type: %d\n", kimage->type);
pr_debug(" start: %lx\n", kimage->start);
pr_debug(" head: %lx\n", kimage->head);
pr_debug(" nr_segments: %lu\n", kimage->nr_segments);
for (i = 0; i < kimage->nr_segments; i++)
kexec_show_segment_info(kimage, i);
#ifdef CONFIG_KEXEC_FILE
if (kimage->file_mode) {
pr_debug("cmdline: %.*s\n", (int)kimage->cmdline_buf_len,
kimage->cmdline_buf);
}
#endif
}
void machine_kexec_cleanup(struct kimage *kimage)
{
}
void machine_crash_shutdown(struct pt_regs *regs)
{
}
void machine_shutdown(void)
{
smp_send_stop();
while (num_online_cpus() > 1) {
cpu_relax();
mdelay(1);
}
}
void machine_kexec(struct kimage *image)
{
#ifdef CONFIG_64BIT
Elf64_Fdesc desc;
#endif
void (*reloc)(unsigned long head,
unsigned long start,
unsigned long phys);
unsigned long phys = page_to_phys(image->control_code_page);
void *virt = (void *)__fix_to_virt(FIX_TEXT_KEXEC);
struct kimage_arch *arch = &image->arch;
set_fixmap(FIX_TEXT_KEXEC, phys);
flush_cache_all();
#ifdef CONFIG_64BIT
reloc = (void *)&desc;
desc.addr = (long long)virt;
#else
reloc = (void *)virt;
#endif
memcpy(virt, dereference_function_descriptor(relocate_new_kernel),
relocate_new_kernel_size);
*(unsigned long *)(virt + kexec_cmdline_offset) = arch->cmdline;
*(unsigned long *)(virt + kexec_initrd_start_offset) = arch->initrd_start;
*(unsigned long *)(virt + kexec_initrd_end_offset) = arch->initrd_end;
*(unsigned long *)(virt + kexec_free_mem_offset) = PAGE0->mem_free;
flush_cache_all();
flush_tlb_all();
local_irq_disable();
reloc(image->head & PAGE_MASK, image->start, phys);
}
int machine_kexec_prepare(struct kimage *image)
{
kexec_image_info(image);
return 0;
}
// SPDX-License-Identifier: GPL-2.0
/*
* Load ELF vmlinux file for the kexec_file_load syscall.
*
* Copyright (c) 2019 Sven Schnelle <svens@stackframe.org>
*
*/
#include <linux/elf.h>
#include <linux/kexec.h>
#include <linux/libfdt.h>
#include <linux/module.h>
#include <linux/of_fdt.h>
#include <linux/slab.h>
#include <linux/types.h>
static void *elf_load(struct kimage *image, char *kernel_buf,
unsigned long kernel_len, char *initrd,
unsigned long initrd_len, char *cmdline,
unsigned long cmdline_len)
{
int ret, i;
unsigned long kernel_load_addr;
struct elfhdr ehdr;
struct kexec_elf_info elf_info;
struct kexec_buf kbuf = { .image = image, .buf_min = 0,
.buf_max = -1UL, };
ret = kexec_build_elf_info(kernel_buf, kernel_len, &ehdr, &elf_info);
if (ret)
goto out;
ret = kexec_elf_load(image, &ehdr, &elf_info, &kbuf, &kernel_load_addr);
if (ret)
goto out;
image->start = __pa(elf_info.ehdr->e_entry);
for (i = 0; i < image->nr_segments; i++)
image->segment[i].mem = __pa(image->segment[i].mem);
pr_debug("Loaded the kernel at 0x%lx, entry at 0x%lx\n",
kernel_load_addr, image->start);
if (initrd != NULL) {
kbuf.buffer = initrd;
kbuf.bufsz = kbuf.memsz = initrd_len;
kbuf.buf_align = PAGE_SIZE;
kbuf.top_down = false;
kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
ret = kexec_add_buffer(&kbuf);
if (ret)
goto out;
pr_debug("Loaded initrd at 0x%lx\n", kbuf.mem);
image->arch.initrd_start = kbuf.mem;
image->arch.initrd_end = kbuf.mem + initrd_len;
}
if (cmdline != NULL) {
kbuf.buffer = cmdline;
kbuf.bufsz = kbuf.memsz = ALIGN(cmdline_len, 8);
kbuf.buf_align = PAGE_SIZE;
kbuf.top_down = false;
kbuf.buf_min = PAGE0->mem_free + PAGE_SIZE;
kbuf.buf_max = kernel_load_addr;
kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
ret = kexec_add_buffer(&kbuf);
if (ret)
goto out;
pr_debug("Loaded cmdline at 0x%lx\n", kbuf.mem);
image->arch.cmdline = kbuf.mem;
}
out:
return NULL;
}
const struct kexec_file_ops kexec_elf_ops = {
.probe = kexec_elf_probe,
.load = elf_load,
};
const struct kexec_file_ops * const kexec_file_loaders[] = {
&kexec_elf_ops,
NULL
};
......@@ -281,10 +281,6 @@ int __kprobes arch_trampoline_kprobe(struct kprobe *p)
{
return p->addr == trampoline_p.addr;
}
bool arch_kprobe_on_func_entry(unsigned long offset)
{
return !offset;
}
int __init arch_init_kprobes(void)
{
......
......@@ -174,6 +174,15 @@ fdtdone:
2: bv %r0(%r2)
nop
/*
* When running in qemu, drop whole flush_tlb_all_local function and
* replace by one pdtlbe instruction, for which QEMU will drop all
* local TLB entries.
*/
3: pdtlbe %r0(%sr1,%r0)
bv,n %r0(%r2)
ALTERNATIVE_CODE(flush_tlb_all_local, 2, ALT_COND_RUN_ON_QEMU, 3b)
ENDPROC_CFI(flush_tlb_all_local)
.import cache_info,data
......
......@@ -17,6 +17,10 @@
#include <linux/string.h>
EXPORT_SYMBOL(memset);
EXPORT_SYMBOL(strlen);
EXPORT_SYMBOL(strcpy);
EXPORT_SYMBOL(strncpy);
EXPORT_SYMBOL(strcat);
#include <linux/atomic.h>
EXPORT_SYMBOL(__xchg8);
......
......@@ -34,17 +34,6 @@
#define DBG_RES(x...)
#endif
/* To be used as: mdelay(pci_post_reset_delay);
*
* post_reset is the time the kernel should stall to prevent anyone from
* accessing the PCI bus once #RESET is de-asserted.
* PCI spec somewhere says 1 second but with multi-PCI bus systems,
* this makes the boot time much longer than necessary.
* 20ms seems to work for all the HP PCI implementations to date.
*
* #define pci_post_reset_delay 50
*/
struct pci_port_ops *pci_port __ro_after_init;
struct pci_bios_ops *pci_bios __ro_after_init;
......
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/linkage.h>
#include <linux/kexec.h>
#include <asm/assembly.h>
#include <asm/asm-offsets.h>
#include <asm/page.h>
#include <asm/setup.h>
#include <asm/psw.h>
.level PA_ASM_LEVEL
.macro kexec_param name
.align 8
ENTRY(kexec\()_\name)
#ifdef CONFIG_64BIT
.dword 0
#else
.word 0
#endif
ENTRY(kexec\()_\name\()_offset)
.word kexec\()_\name - relocate_new_kernel
.endm
.text
/* args:
* r26 - kimage->head
* r25 - start address of kernel
* r24 - physical address of relocate code
*/
ENTRY_CFI(relocate_new_kernel)
0: copy %arg1, %rp
/* disable I and Q bit, so we are allowed to execute RFI */
rsm PSW_SM_I, %r0
nop
nop
nop
nop
nop
nop
nop
rsm PSW_SM_Q, %r0
nop
nop
nop
nop
nop
nop
nop
/*
* After return-from-interrupt, we want to run without Code/Data
* translation enabled just like on a normal boot.
*/
/* calculate new physical execution address */
ldo 1f-0b(%arg2), %r1
mtctl %r0, %cr17 /* IIASQ */
mtctl %r0, %cr17 /* IIASQ */
mtctl %r1, %cr18 /* IIAOQ */
ldo 4(%r1),%r1
mtctl %r1, %cr18 /* IIAOQ */
#ifdef CONFIG_64BIT
depdi,z 1, PSW_W_BIT, 1, %r1
mtctl %r1, %cr22 /* IPSW */
#else
mtctl %r0, %cr22 /* IPSW */
#endif
/* lets go... */
rfi
1: nop
nop
.Lloop:
LDREG,ma REG_SZ(%arg0), %r3
/* If crash kernel, no copy needed */
cmpib,COND(=),n 0,%r3,boot
bb,<,n %r3, 31 - IND_DONE_BIT, boot
bb,>=,n %r3, 31 - IND_INDIRECTION_BIT, .Lnotind
/* indirection, load and restart */
movb %r3, %arg0, .Lloop
depi 0, 31, PAGE_SHIFT, %arg0
.Lnotind:
bb,>=,n %r3, 31 - IND_DESTINATION_BIT, .Lnotdest
b .Lloop
copy %r3, %r20
.Lnotdest:
bb,>= %r3, 31 - IND_SOURCE_BIT, .Lloop
depi 0, 31, PAGE_SHIFT, %r3
copy %r3, %r21
/* copy page */
copy %r0, %r18
zdepi 1, 31 - PAGE_SHIFT, 1, %r18
add %r20, %r18, %r17
depi 0, 31, PAGE_SHIFT, %r20
.Lcopy:
copy %r20, %r12
LDREG,ma REG_SZ(%r21), %r8
LDREG,ma REG_SZ(%r21), %r9
LDREG,ma REG_SZ(%r21), %r10
LDREG,ma REG_SZ(%r21), %r11
STREG,ma %r8, REG_SZ(%r20)
STREG,ma %r9, REG_SZ(%r20)
STREG,ma %r10, REG_SZ(%r20)
STREG,ma %r11, REG_SZ(%r20)
#ifndef CONFIG_64BIT
LDREG,ma REG_SZ(%r21), %r8
LDREG,ma REG_SZ(%r21), %r9
LDREG,ma REG_SZ(%r21), %r10
LDREG,ma REG_SZ(%r21), %r11
STREG,ma %r8, REG_SZ(%r20)
STREG,ma %r9, REG_SZ(%r20)
STREG,ma %r10, REG_SZ(%r20)
STREG,ma %r11, REG_SZ(%r20)
#endif
fdc %r0(%r12)
cmpb,COND(<<) %r20,%r17,.Lcopy
fic (%sr4, %r12)
b,n .Lloop
boot:
mtctl %r0, %cr15
LDREG kexec_free_mem-0b(%arg2), %arg0
LDREG kexec_cmdline-0b(%arg2), %arg1
LDREG kexec_initrd_end-0b(%arg2), %arg3
LDREG kexec_initrd_start-0b(%arg2), %arg2
bv,n %r0(%rp)
ENDPROC_CFI(relocate_new_kernel);
ENTRY(relocate_new_kernel_size)
.word relocate_new_kernel_size - relocate_new_kernel
kexec_param cmdline
kexec_param initrd_start
kexec_param initrd_end
kexec_param free_mem
......@@ -109,6 +109,7 @@ halt_processor(void)
/* REVISIT : does PM *know* this CPU isn't available? */
set_cpu_online(smp_processor_id(), false);
local_irq_disable();
__pdc_cpu_rendezvous();
for (;;)
;
}
......
......@@ -399,7 +399,8 @@
352 common pkey_alloc sys_pkey_alloc
353 common pkey_free sys_pkey_free
354 common rseq sys_rseq
# 355 through 402 are unassigned to sync up with generic numbers
355 common kexec_file_load sys_kexec_file_load sys_kexec_file_load
# up to 402 is unassigned and reserved for arch specific syscalls
403 32 clock_gettime64 sys_clock_gettime sys_clock_gettime
404 32 clock_settime64 sys_clock_settime sys_clock_settime
405 32 clock_adjtime64 sys_clock_adjtime sys_clock_adjtime
......
......@@ -29,6 +29,7 @@
#include <linux/bug.h>
#include <linux/ratelimit.h>
#include <linux/uaccess.h>
#include <linux/kdebug.h>
#include <asm/assembly.h>
#include <asm/io.h>
......@@ -414,6 +415,7 @@ void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long o
{
static DEFINE_SPINLOCK(terminate_lock);
(void)notify_die(DIE_OOPS, msg, regs, 0, code, SIGTRAP);
bust_spinlocks(1);
set_eiem(0);
......
......@@ -3,7 +3,7 @@
# Makefile for parisc-specific library files
#
lib-y := lusercopy.o bitops.o checksum.o io.o memset.o memcpy.o \
ucmpdi2.o delay.o
lib-y := lusercopy.o bitops.o checksum.o io.o memcpy.o \
ucmpdi2.o delay.o string.o
obj-y := iomap.o
/* Copyright (C) 1991, 1997 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
/* Slight modifications for pa-risc linux - Paul Bame <bame@debian.org> */
#include <linux/types.h>
#include <asm/string.h>
#define OPSIZ (BITS_PER_LONG/8)
typedef unsigned long op_t;
void *
memset (void *dstpp, int sc, size_t len)
{
unsigned int c = sc;
long int dstp = (long int) dstpp;
if (len >= 8)
{
size_t xlen;
op_t cccc;
cccc = (unsigned char) c;
cccc |= cccc << 8;
cccc |= cccc << 16;
if (OPSIZ > 4)
/* Do the shift in two steps to avoid warning if long has 32 bits. */
cccc |= (cccc << 16) << 16;
/* There are at least some bytes to set.
No need to test for LEN == 0 in this alignment loop. */
while (dstp % OPSIZ != 0)
{
((unsigned char *) dstp)[0] = c;
dstp += 1;
len -= 1;
}
/* Write 8 `op_t' per iteration until less than 8 `op_t' remain. */
xlen = len / (OPSIZ * 8);
while (xlen > 0)
{
((op_t *) dstp)[0] = cccc;
((op_t *) dstp)[1] = cccc;
((op_t *) dstp)[2] = cccc;
((op_t *) dstp)[3] = cccc;
((op_t *) dstp)[4] = cccc;
((op_t *) dstp)[5] = cccc;
((op_t *) dstp)[6] = cccc;
((op_t *) dstp)[7] = cccc;
dstp += 8 * OPSIZ;
xlen -= 1;
}
len %= OPSIZ * 8;
/* Write 1 `op_t' per iteration until less than OPSIZ bytes remain. */
xlen = len / OPSIZ;
while (xlen > 0)
{
((op_t *) dstp)[0] = cccc;
dstp += OPSIZ;
xlen -= 1;
}
len %= OPSIZ;
}
/* Write the last few bytes. */
while (len > 0)
{
((unsigned char *) dstp)[0] = c;
dstp += 1;
len -= 1;
}
return dstpp;
}
// SPDX-License-Identifier: GPL-2.0
/*
* PA-RISC assembly string functions
*
* Copyright (C) 2019 Helge Deller <deller@gmx.de>
*/
#include <asm/assembly.h>
#include <linux/linkage.h>
.section .text.hot
.level PA_ASM_LEVEL
t0 = r20
t1 = r21
t2 = r22
ENTRY_CFI(strlen, frame=0,no_calls)
or,COND(<>) arg0,r0,ret0
b,l,n .Lstrlen_null_ptr,r0
depwi 0,31,2,ret0
cmpb,COND(<>) arg0,ret0,.Lstrlen_not_aligned
ldw,ma 4(ret0),t0
cmpib,tr 0,r0,.Lstrlen_loop
uxor,nbz r0,t0,r0
.Lstrlen_not_aligned:
uaddcm arg0,ret0,t1
shladd t1,3,r0,t1
mtsar t1
depwi -1,%sar,32,t0
uxor,nbz r0,t0,r0
.Lstrlen_loop:
b,l,n .Lstrlen_end_loop,r0
ldw,ma 4(ret0),t0
cmpib,tr 0,r0,.Lstrlen_loop
uxor,nbz r0,t0,r0
.Lstrlen_end_loop:
extrw,u,<> t0,7,8,r0
addib,tr,n -3,ret0,.Lstrlen_out
extrw,u,<> t0,15,8,r0
addib,tr,n -2,ret0,.Lstrlen_out
extrw,u,<> t0,23,8,r0
addi -1,ret0,ret0
.Lstrlen_out:
bv r0(rp)
uaddcm ret0,arg0,ret0
.Lstrlen_null_ptr:
bv,n r0(rp)
ENDPROC_CFI(strlen)
ENTRY_CFI(strcpy, frame=0,no_calls)
ldb 0(arg1),t0
stb t0,0(arg0)
ldo 0(arg0),ret0
ldo 1(arg1),t1
cmpb,= r0,t0,2f
ldo 1(arg0),t2
1: ldb 0(t1),arg1
stb arg1,0(t2)
ldo 1(t1),t1
cmpb,<> r0,arg1,1b
ldo 1(t2),t2
2: bv,n r0(rp)
ENDPROC_CFI(strcpy)
ENTRY_CFI(strncpy, frame=0,no_calls)
ldb 0(arg1),t0
stb t0,0(arg0)
ldo 1(arg1),t1
ldo 0(arg0),ret0
cmpb,= r0,t0,2f
ldo 1(arg0),arg1
1: ldo -1(arg2),arg2
cmpb,COND(=),n r0,arg2,2f
ldb 0(t1),arg0
stb arg0,0(arg1)
ldo 1(t1),t1
cmpb,<> r0,arg0,1b
ldo 1(arg1),arg1
2: bv,n r0(rp)
ENDPROC_CFI(strncpy)
ENTRY_CFI(strcat, frame=0,no_calls)
ldb 0(arg0),t0
cmpb,= t0,r0,2f
ldo 0(arg0),ret0
ldo 1(arg0),arg0
1: ldb 0(arg0),t1
cmpb,<>,n r0,t1,1b
ldo 1(arg0),arg0
2: ldb 0(arg1),t2
stb t2,0(arg0)
ldo 1(arg0),arg0
ldb 0(arg1),t0
cmpb,<> r0,t0,2b
ldo 1(arg1),arg1
bv,n r0(rp)
ENDPROC_CFI(strcat)
ENTRY_CFI(memset, frame=0,no_calls)
copy arg0,ret0
cmpb,COND(=) r0,arg0,4f
copy arg0,t2
cmpb,COND(=) r0,arg2,4f
ldo -1(arg2),arg3
subi -1,arg3,t0
subi 0,t0,t1
cmpiclr,COND(>=) 0,t1,arg2
ldo -1(t1),arg2
extru arg2,31,2,arg0
2: stb arg1,0(t2)
ldo 1(t2),t2
addib,>= -1,arg0,2b
ldo -1(arg3),arg3
cmpiclr,COND(<=) 4,arg2,r0
b,l,n 4f,r0
#ifdef CONFIG_64BIT
depd,* r0,63,2,arg2
#else
depw r0,31,2,arg2
#endif
ldo 1(t2),t2
3: stb arg1,-1(t2)
stb arg1,0(t2)
stb arg1,1(t2)
stb arg1,2(t2)
addib,COND(>) -4,arg2,3b
ldo 4(t2),t2
4: bv,n r0(rp)
ENDPROC_CFI(memset)
.end
......@@ -511,6 +511,7 @@ config KEXEC_FILE
select KEXEC_CORE
select HAVE_IMA_KEXEC
select BUILD_BIN2C
select KEXEC_ELF
depends on PPC64
depends on CRYPTO=y
depends on CRYPTO_SHA256=y
......
This diff is collapsed.
......@@ -6,7 +6,7 @@
** (c) Copyright 1999 SuSE GmbH
** (c) Copyright 1999,2000 Hewlett-Packard Company
** (c) Copyright 2000 Grant Grundler
** (c) Copyright 2006 Helge Deller
** (c) Copyright 2006-2019 Helge Deller
**
**
** This module provides access to Dino PCI bus (config/IOport spaces)
......@@ -156,6 +156,15 @@ static inline struct dino_device *DINO_DEV(struct pci_hba_data *hba)
return container_of(hba, struct dino_device, hba);
}
/* Check if PCI device is behind a Card-mode Dino. */
static int pci_dev_is_behind_card_dino(struct pci_dev *dev)
{
struct dino_device *dino_dev;
dino_dev = DINO_DEV(parisc_walk_tree(dev->bus->bridge));
return is_card_dino(&dino_dev->hba.dev->id);
}
/*
* Dino Configuration Space Accessor Functions
*/
......@@ -437,6 +446,21 @@ static void quirk_cirrus_cardbus(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6832, quirk_cirrus_cardbus );
#ifdef CONFIG_TULIP
static void pci_fixup_tulip(struct pci_dev *dev)
{
if (!pci_dev_is_behind_card_dino(dev))
return;
if (!(pci_resource_flags(dev, 1) & IORESOURCE_MEM))
return;
pr_warn("%s: HP HSC-PCI Cards with card-mode Dino not yet supported.\n",
pci_name(dev));
/* Disable this card by zeroing the PCI resources */
memset(&dev->resource[0], 0, sizeof(dev->resource[0]));
memset(&dev->resource[1], 0, sizeof(dev->resource[1]));
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_DEC, PCI_ANY_ID, pci_fixup_tulip);
#endif /* CONFIG_TULIP */
static void __init
dino_bios_init(void)
......@@ -863,14 +887,14 @@ static int __init dino_common_init(struct parisc_device *dev,
#define CUJO_RAVEN_BADPAGE 0x01003000UL
#define CUJO_FIREHAWK_BADPAGE 0x01607000UL
static const char *dino_vers[] = {
static const char dino_vers[][4] = {
"2.0",
"2.1",
"3.0",
"3.1"
};
static const char *cujo_vers[] = {
static const char cujo_vers[][4] = {
"1.0",
"2.0"
};
......
......@@ -93,7 +93,7 @@ static int configure_memory(const unsigned char *buf,
res->start = mem_parent->start + get_24(buf+len+2);
res->end = res->start + get_16(buf+len+5)*1024;
res->flags = IORESOURCE_MEM;
printk("memory %lx-%lx ", (unsigned long)res->start, (unsigned long)res->end);
pr_cont("memory %pR ", res);
result = request_resource(mem_parent, res);
if (result < 0) {
printk(KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n");
......@@ -123,7 +123,7 @@ static int configure_irq(const unsigned char *buf)
for (i=0;i<HPEE_IRQ_MAX_ENT;i++) {
c = get_8(buf+len);
printk("IRQ %d ", c & HPEE_IRQ_CHANNEL_MASK);
pr_cont("IRQ %d ", c & HPEE_IRQ_CHANNEL_MASK);
if (c & HPEE_IRQ_TRIG_LEVEL) {
eisa_make_irq_level(c & HPEE_IRQ_CHANNEL_MASK);
} else {
......@@ -153,7 +153,7 @@ static int configure_dma(const unsigned char *buf)
for (i=0;i<HPEE_DMA_MAX_ENT;i++) {
c = get_8(buf+len);
printk("DMA %d ", c&HPEE_DMA_CHANNEL_MASK);
pr_cont("DMA %d ", c&HPEE_DMA_CHANNEL_MASK);
/* fixme: maybe initialize the dma channel withthe timing ? */
len+=2;
if (!(c & HPEE_DMA_MORE)) {
......@@ -183,7 +183,7 @@ static int configure_port(const unsigned char *buf, struct resource *io_parent,
res->start = get_16(buf+len+1);
res->end = get_16(buf+len+1)+(c&HPEE_PORT_SIZE_MASK)+1;
res->flags = IORESOURCE_IO;
printk("ioports %lx-%lx ", (unsigned long)res->start, (unsigned long)res->end);
pr_cont("ioports %pR ", res);
result = request_resource(io_parent, res);
if (result < 0) {
printk(KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n");
......@@ -401,7 +401,7 @@ static int parse_slot_config(int slot,
}
pos = p0 + function_len;
}
printk("\n");
pr_cont("\n");
if (!id_string_used) {
kfree(board);
}
......
......@@ -61,8 +61,6 @@ static int __init hppb_probe(struct parisc_device *dev)
}
card = card->next;
}
printk(KERN_INFO "Found GeckoBoa at 0x%llx\n",
(unsigned long long) dev->hpa.start);
card->hpa = dev->hpa.start;
card->mmio_region.name = "HP-PB Bus";
......@@ -72,10 +70,11 @@ static int __init hppb_probe(struct parisc_device *dev)
card->mmio_region.end = gsc_readl(dev->hpa.start + IO_IO_HIGH) - 1;
status = ccio_request_resource(dev, &card->mmio_region);
if(status < 0) {
printk(KERN_ERR "%s: failed to claim HP-PB bus space (%pR)\n",
__FILE__, &card->mmio_region);
}
pr_info("Found GeckoBoa at %pap, bus space %pR,%s claimed.\n",
&dev->hpa.start,
&card->mmio_region,
(status < 0) ? " not":"" );
return 0;
}
......
......@@ -216,6 +216,29 @@ extern int crash_prepare_elf64_headers(struct crash_mem *mem, int kernel_map,
void **addr, unsigned long *sz);
#endif /* CONFIG_KEXEC_FILE */
#ifdef CONFIG_KEXEC_ELF
struct kexec_elf_info {
/*
* Where the ELF binary contents are kept.
* Memory managed by the user of the struct.
*/
const char *buffer;
const struct elfhdr *ehdr;
const struct elf_phdr *proghdrs;
};
int kexec_build_elf_info(const char *buf, size_t len, struct elfhdr *ehdr,
struct kexec_elf_info *elf_info);
int kexec_elf_load(struct kimage *image, struct elfhdr *ehdr,
struct kexec_elf_info *elf_info,
struct kexec_buf *kbuf,
unsigned long *lowest_load_addr);
void kexec_free_elf_info(struct kexec_elf_info *elf_info);
int kexec_elf_probe(const char *buf, unsigned long len);
#endif
struct kimage {
kimage_entry_t head;
kimage_entry_t *entry;
......
......@@ -31,6 +31,7 @@
#define KEXEC_ARCH_DEFAULT ( 0 << 16)
#define KEXEC_ARCH_386 ( 3 << 16)
#define KEXEC_ARCH_68K ( 4 << 16)
#define KEXEC_ARCH_PARISC (15 << 16)
#define KEXEC_ARCH_X86_64 (62 << 16)
#define KEXEC_ARCH_PPC (20 << 16)
#define KEXEC_ARCH_PPC64 (21 << 16)
......
......@@ -64,6 +64,7 @@ obj-$(CONFIG_CRASH_CORE) += crash_core.o
obj-$(CONFIG_KEXEC_CORE) += kexec_core.o
obj-$(CONFIG_KEXEC) += kexec.o
obj-$(CONFIG_KEXEC_FILE) += kexec_file.o
obj-$(CONFIG_KEXEC_ELF) += kexec_elf.o
obj-$(CONFIG_BACKTRACE_SELF_TEST) += backtracetest.o
obj-$(CONFIG_COMPAT) += compat.o
obj-$(CONFIG_CGROUPS) += cgroup/
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment