Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 44786880 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull parisc updates from Helge Deller:
 "Lots of small fixes and enhancements, most noteably:

   - Many TLB and cache flush optimizations (Dave)

   - Fixed HPMC/crash handler on 64-bit kernel (Dave and myself)

   - Added alternative infrastructre. The kernel now live-patches itself
     for various situations, e.g. replace SMP code when running on one
     CPU only or drop cache flushes when system has no cache installed.

   - vmlinuz now contains a full copy of the compressed vmlinux file.
     This simplifies debugging the currently booted kernel.

   - Unused driver removal (Christoph)

   - Reduced warnings of Dino PCI bridge when running in qemu

   - Removed gcc version check (Masahiro)"

* 'parisc-4.20-1' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux: (23 commits)
  parisc: Retrieve and display the PDC PAT capabilities
  parisc: Optimze cache flush algorithms
  parisc: Remove pte_inserted define
  parisc: Add PDC PAT cell_info() and pd_get_pdc_revisions() functions
  parisc: Drop two instructions from pte lookup code
  parisc: Use zdep for shlw macro on PA1.1 and PA2.0
  parisc: Add alternative coding infrastructure
  parisc: Include compressed vmlinux file in vmlinuz boot kernel
  extract-vmlinux: Check for uncompressed image as fallback
  parisc: Fix address in HPMC IVA
  parisc: Fix exported address of os_hpmc handler
  parisc: Fix map_pages() to not overwrite existing pte entries
  parisc: Purge TLB entries after updating page table entry and set page accessed flag in TLB handler
  parisc: Release spinlocks using ordered store
  parisc: Ratelimit dino stuck interrupt warnings
  parisc: dino: Utilize DINO_MASK_IRQ() macro
  parisc: Clean up crash header output
  parisc: Add SYSTEM_INFO and REGISTER TOC PAT functions
  parisc: Remove PTE load and fault check from L2_ptep macro
  parisc: Reorder TLB flush timing calculation
  ...
parents 07171da2 e543b3a6
Loading
Loading
Loading
Loading
+0 −9
Original line number Diff line number Diff line
@@ -156,12 +156,3 @@ define archhelp
	@echo  '		  copy to $$(INSTALL_PATH)'
	@echo  '  zinstall	- Install compressed vmlinuz kernel'
endef

# we require gcc 3.3 or above to compile the kernel
archprepare: checkbin
checkbin:
	@if test "$(cc-version)" -lt "0303"; then \
		echo -n "Sorry, GCC v3.3 or above is required to build " ; \
		echo "the kernel." ; \
		false ; \
	fi
+1 −3
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@ targets += misc.o piggy.o sizes.h head.o real2.o firmware.o

KBUILD_CFLAGS := -D__KERNEL__ -O2 -DBOOTLOADER
KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
KBUILD_CFLAGS += $(cflags-y) -fno-delete-null-pointer-checks
KBUILD_CFLAGS += $(cflags-y) -fno-delete-null-pointer-checks -fno-builtin-printf
KBUILD_CFLAGS += -fno-PIE -mno-space-regs -mdisable-fpregs -Os
ifndef CONFIG_64BIT
KBUILD_CFLAGS += -mfast-indirect-calls
@@ -22,7 +22,6 @@ endif

OBJECTS += $(obj)/head.o $(obj)/real2.o $(obj)/firmware.o $(obj)/misc.o $(obj)/piggy.o

# LDFLAGS_vmlinux := -X --whole-archive -e startup -T
LDFLAGS_vmlinux := -X -e startup --as-needed -T
$(obj)/vmlinux: $(obj)/vmlinux.lds $(OBJECTS) $(LIBGCC)
	$(call if_changed,ld)
@@ -55,7 +54,6 @@ $(obj)/misc.o: $(obj)/sizes.h
CPPFLAGS_vmlinux.lds += -I$(objtree)/$(obj) -DBOOTLOADER
$(obj)/vmlinux.lds: $(obj)/sizes.h

OBJCOPYFLAGS_vmlinux.bin := -O binary -R .comment -S
$(obj)/vmlinux.bin: vmlinux
	$(call if_changed,objcopy)

+77 −18
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
 */

#include <linux/uaccess.h>
#include <linux/elf.h>
#include <asm/unaligned.h>
#include <asm/page.h>
#include "sizes.h"
@@ -227,13 +228,62 @@ static void flush_data_cache(char *start, unsigned long length)
	asm ("sync");
}

static void parse_elf(void *output)
{
#ifdef CONFIG_64BIT
	Elf64_Ehdr ehdr;
	Elf64_Phdr *phdrs, *phdr;
#else
	Elf32_Ehdr ehdr;
	Elf32_Phdr *phdrs, *phdr;
#endif
	void *dest;
	int i;

	memcpy(&ehdr, output, sizeof(ehdr));
	if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
	   ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
	   ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
	   ehdr.e_ident[EI_MAG3] != ELFMAG3) {
		error("Kernel is not a valid ELF file");
		return;
	}

#ifdef DEBUG
	printf("Parsing ELF... ");
#endif

	phdrs = malloc(sizeof(*phdrs) * ehdr.e_phnum);
	if (!phdrs)
		error("Failed to allocate space for phdrs");

	memcpy(phdrs, output + ehdr.e_phoff, sizeof(*phdrs) * ehdr.e_phnum);

	for (i = 0; i < ehdr.e_phnum; i++) {
		phdr = &phdrs[i];

		switch (phdr->p_type) {
		case PT_LOAD:
			dest = (void *)((unsigned long) phdr->p_paddr &
					(__PAGE_OFFSET_DEFAULT-1));
			memmove(dest, output + phdr->p_offset, phdr->p_filesz);
			break;
		default:
			break;
		}
	}

	free(phdrs);
}

unsigned long decompress_kernel(unsigned int started_wide,
		unsigned int command_line,
		const unsigned int rd_start,
		const unsigned int rd_end)
{
	char *output;
	unsigned long len, len_all;
	unsigned long vmlinux_addr, vmlinux_len;
	unsigned long kernel_addr, kernel_len;

#ifdef CONFIG_64BIT
	parisc_narrow_firmware = 0;
@@ -241,27 +291,29 @@ unsigned long decompress_kernel(unsigned int started_wide,

	set_firmware_width_unlocked();

	putchar('U');	/* if you get this p and no more, string storage */
	putchar('D');	/* if you get this D and no more, string storage */
			/* in $GLOBAL$ is wrong or %dp is wrong */
	puts("ncompressing ...\n");

	output = (char *) KERNEL_BINARY_TEXT_START;
	len_all = __pa(SZ_end) - __pa(SZparisc_kernel_start);
	puts("ecompressing Linux... ");

	if ((unsigned long) &_startcode_end > (unsigned long) output)
	/* where the final bits are stored */
	kernel_addr = KERNEL_BINARY_TEXT_START;
	kernel_len = __pa(SZ_end) - __pa(SZparisc_kernel_start);
	if ((unsigned long) &_startcode_end > kernel_addr)
		error("Bootcode overlaps kernel code");

	len = get_unaligned_le32(&output_len);
	if (len > len_all)
		error("Output len too big.");
	else
		memset(&output[len], 0, len_all - len);
	/*
	 * Calculate addr to where the vmlinux ELF file shall be decompressed.
	 * Assembly code in head.S positioned the stack directly behind bss, so
	 * leave 2 MB for the stack.
	 */
	vmlinux_addr = (unsigned long) &_ebss + 2*1024*1024;
	vmlinux_len = get_unaligned_le32(&output_len);
	output = (char *) vmlinux_addr;

	/*
	 * Initialize free_mem_ptr and free_mem_end_ptr.
	 */
	free_mem_ptr = (unsigned long) &_ebss;
	free_mem_ptr += 2*1024*1024;	/* leave 2 MB for stack */
	free_mem_ptr = vmlinux_addr + vmlinux_len;

	/* Limit memory for bootoader to 1GB */
	#define ARTIFICIAL_LIMIT (1*1024*1024*1024)
@@ -275,7 +327,11 @@ unsigned long decompress_kernel(unsigned int started_wide,
		free_mem_end_ptr = rd_start;
#endif

	if (free_mem_ptr >= free_mem_end_ptr)
		error("Kernel too big for machine.");

#ifdef DEBUG
	printf("\n");
	printf("startcode_end = %x\n", &_startcode_end);
	printf("commandline   = %x\n", command_line);
	printf("rd_start      = %x\n", rd_start);
@@ -287,16 +343,19 @@ unsigned long decompress_kernel(unsigned int started_wide,
	printf("input_data    = %x\n", input_data);
	printf("input_len     = %x\n", input_len);
	printf("output        = %x\n", output);
	printf("output_len    = %x\n", len);
	printf("output_max    = %x\n", len_all);
	printf("output_len    = %x\n", vmlinux_len);
	printf("kernel_addr   = %x\n", kernel_addr);
	printf("kernel_len    = %x\n", kernel_len);
#endif

	__decompress(input_data, input_len, NULL, NULL,
			output, 0, NULL, error);
	parse_elf(output);

	flush_data_cache(output, len);
	output = (char *) kernel_addr;
	flush_data_cache(output, kernel_len);

	printf("Booting kernel ...\n\n");
	printf("done.\nBooting the kernel.\n");

	return (unsigned long) output;
}
+6 −4
Original line number Diff line number Diff line
@@ -42,6 +42,12 @@ SECTIONS
#endif
	_startcode_end = .;

	/* vmlinux.bin.gz is here */
	. = ALIGN(8);
	.rodata.compressed : {
		*(.rodata.compressed)
	}

	/* bootloader code and data starts behind area of extracted kernel */
	. = (SZ_end - SZparisc_kernel_start + KERNEL_BINARY_TEXT_START);

@@ -68,10 +74,6 @@ SECTIONS
		_erodata = . ;
	}
	. = ALIGN(8);
	.rodata.compressed : {
		*(.rodata.compressed)
	}
	. = ALIGN(8);
	.bss : {
		_bss = . ;
		*(.bss)
+47 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_PARISC_ALTERNATIVE_H
#define __ASM_PARISC_ALTERNATIVE_H

#define ALT_COND_NO_SMP		0x01	/* when running UP instead of SMP */
#define ALT_COND_NO_DCACHE	0x02	/* if system has no d-cache  */
#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 INSN_PxTLB	0x02		/* modify pdtlb, pitlb */
#define INSN_NOP	0x08000240	/* nop */

#ifndef __ASSEMBLY__

#include <linux/init.h>
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/stringify.h>

struct alt_instr {
	s32 orig_offset;	/* offset to original instructions */
	u32 len;		/* end of original instructions */
	u32 cond;		/* see ALT_COND_XXX */
	u32 replacement;	/* replacement instruction or code */
};

void set_kernel_text_rw(int enable_read_write);

/* Alternative SMP implementation. */
#define ALTERNATIVE(cond, replacement)		"!0:"	\
	".section .altinstructions, \"aw\"	!"	\
	".word (0b-4-.), 1, " __stringify(cond) ","	\
		__stringify(replacement) "	!"	\
	".previous"

#else

#define ALTERNATIVE(from, to, cond, replacement)\
	.section .altinstructions, "aw"	!	\
	.word (from - .), (to - from)/4	!	\
	.word cond, replacement		!	\
	.previous

#endif  /*  __ASSEMBLY__  */

#endif /* __ASM_PARISC_ALTERNATIVE_H */
Loading