cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

misc.c (7284B)


      1/*
      2 * Definitions and wrapper functions for kernel decompressor
      3 *
      4 *   (C) 2017 Helge Deller <deller@gmx.de>
      5 */
      6
      7#include <linux/uaccess.h>
      8#include <linux/elf.h>
      9#include <asm/unaligned.h>
     10#include <asm/page.h>
     11#include "sizes.h"
     12
     13/*
     14 * gzip declarations
     15 */
     16#define STATIC static
     17
     18#undef memmove
     19#define memmove memmove
     20#define memzero(s, n) memset((s), 0, (n))
     21
     22#define malloc	malloc_gzip
     23#define free	free_gzip
     24
     25/* Symbols defined by linker scripts */
     26extern char input_data[];
     27extern int input_len;
     28/* output_len is inserted by the linker possibly at an unaligned address */
     29extern char output_len;
     30extern char _text, _end;
     31extern char _bss, _ebss;
     32extern char _startcode_end;
     33extern void startup_continue(void *entry, unsigned long cmdline,
     34	unsigned long rd_start, unsigned long rd_end) __noreturn;
     35
     36void error(char *m) __noreturn;
     37
     38static unsigned long free_mem_ptr;
     39static unsigned long free_mem_end_ptr;
     40
     41#ifdef CONFIG_KERNEL_GZIP
     42#include "../../../../lib/decompress_inflate.c"
     43#endif
     44
     45#ifdef CONFIG_KERNEL_BZIP2
     46#include "../../../../lib/decompress_bunzip2.c"
     47#endif
     48
     49#ifdef CONFIG_KERNEL_LZ4
     50#include "../../../../lib/decompress_unlz4.c"
     51#endif
     52
     53#ifdef CONFIG_KERNEL_LZMA
     54#include "../../../../lib/decompress_unlzma.c"
     55#endif
     56
     57#ifdef CONFIG_KERNEL_LZO
     58#include "../../../../lib/decompress_unlzo.c"
     59#endif
     60
     61#ifdef CONFIG_KERNEL_XZ
     62#include "../../../../lib/decompress_unxz.c"
     63#endif
     64
     65void *memmove(void *dest, const void *src, size_t n)
     66{
     67	const char *s = src;
     68	char *d = dest;
     69
     70	if (d <= s) {
     71		while (n--)
     72			*d++ = *s++;
     73	} else {
     74		d += n;
     75		s += n;
     76		while (n--)
     77			*--d = *--s;
     78	}
     79	return dest;
     80}
     81
     82void *memset(void *s, int c, size_t count)
     83{
     84	char *xs = (char *)s;
     85
     86	while (count--)
     87		*xs++ = c;
     88	return s;
     89}
     90
     91void *memcpy(void *d, const void *s, size_t len)
     92{
     93	char *dest = (char *)d;
     94	const char *source = (const char *)s;
     95
     96	while (len--)
     97		*dest++ = *source++;
     98	return d;
     99}
    100
    101size_t strlen(const char *s)
    102{
    103	const char *sc;
    104
    105	for (sc = s; *sc != '\0'; ++sc)
    106		;
    107	return sc - s;
    108}
    109
    110char *strchr(const char *s, int c)
    111{
    112	while (*s) {
    113		if (*s == (char)c)
    114			return (char *)s;
    115		++s;
    116	}
    117	return NULL;
    118}
    119
    120int puts(const char *s)
    121{
    122	const char *nuline = s;
    123
    124	while ((nuline = strchr(s, '\n')) != NULL) {
    125		if (nuline != s)
    126			pdc_iodc_print(s, nuline - s);
    127		pdc_iodc_print("\r\n", 2);
    128		s = nuline + 1;
    129	}
    130	if (*s != '\0')
    131		pdc_iodc_print(s, strlen(s));
    132
    133	return 0;
    134}
    135
    136static int putchar(int c)
    137{
    138	char buf[2];
    139
    140	buf[0] = c;
    141	buf[1] = '\0';
    142	puts(buf);
    143	return c;
    144}
    145
    146void __noreturn error(char *x)
    147{
    148	if (x) puts(x);
    149	puts("\n -- System halted\n");
    150	while (1)	/* wait forever */
    151		;
    152}
    153
    154static int print_num(unsigned long num, int base)
    155{
    156	const char hex[] = "0123456789abcdef";
    157	char str[40];
    158	int i = sizeof(str)-1;
    159
    160	str[i--] = '\0';
    161	do {
    162		str[i--] = hex[num % base];
    163		num = num / base;
    164	} while (num);
    165
    166	if (base == 16) {
    167		str[i--] = 'x';
    168		str[i] = '0';
    169	} else i++;
    170	puts(&str[i]);
    171
    172	return 0;
    173}
    174
    175int printf(const char *fmt, ...)
    176{
    177	va_list args;
    178	int i = 0;
    179
    180	va_start(args, fmt);
    181
    182	while (fmt[i]) {
    183		if (fmt[i] != '%') {
    184put:
    185			putchar(fmt[i++]);
    186			continue;
    187		}
    188
    189		if (fmt[++i] == '%')
    190			goto put;
    191		print_num(va_arg(args, unsigned long),
    192			fmt[i] == 'x' ? 16:10);
    193		++i;
    194	}
    195
    196	va_end(args);
    197	return 0;
    198}
    199
    200/* helper functions for libgcc */
    201void abort(void)
    202{
    203	error("aborted.");
    204}
    205
    206#undef malloc
    207void *malloc(size_t size)
    208{
    209	return malloc_gzip(size);
    210}
    211
    212#undef free
    213void free(void *ptr)
    214{
    215	return free_gzip(ptr);
    216}
    217
    218
    219static void flush_data_cache(char *start, unsigned long length)
    220{
    221	char *end = start + length;
    222
    223	do {
    224		asm volatile("fdc 0(%0)" : : "r" (start));
    225		asm volatile("fic 0(%%sr0,%0)" : : "r" (start));
    226		start += 16;
    227	} while (start < end);
    228	asm volatile("fdc 0(%0)" : : "r" (end));
    229
    230	asm ("sync");
    231}
    232
    233static void parse_elf(void *output)
    234{
    235#ifdef CONFIG_64BIT
    236	Elf64_Ehdr ehdr;
    237	Elf64_Phdr *phdrs, *phdr;
    238#else
    239	Elf32_Ehdr ehdr;
    240	Elf32_Phdr *phdrs, *phdr;
    241#endif
    242	void *dest;
    243	int i;
    244
    245	memcpy(&ehdr, output, sizeof(ehdr));
    246	if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
    247	   ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
    248	   ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
    249	   ehdr.e_ident[EI_MAG3] != ELFMAG3) {
    250		error("Kernel is not a valid ELF file");
    251		return;
    252	}
    253
    254#ifdef DEBUG
    255	printf("Parsing ELF... ");
    256#endif
    257
    258	phdrs = malloc(sizeof(*phdrs) * ehdr.e_phnum);
    259	if (!phdrs)
    260		error("Failed to allocate space for phdrs");
    261
    262	memcpy(phdrs, output + ehdr.e_phoff, sizeof(*phdrs) * ehdr.e_phnum);
    263
    264	for (i = 0; i < ehdr.e_phnum; i++) {
    265		phdr = &phdrs[i];
    266
    267		switch (phdr->p_type) {
    268		case PT_LOAD:
    269			dest = (void *)((unsigned long) phdr->p_paddr &
    270					(__PAGE_OFFSET_DEFAULT-1));
    271			memmove(dest, output + phdr->p_offset, phdr->p_filesz);
    272			break;
    273		default:
    274			break;
    275		}
    276	}
    277
    278	free(phdrs);
    279}
    280
    281unsigned long decompress_kernel(unsigned int started_wide,
    282		unsigned int command_line,
    283		const unsigned int rd_start,
    284		const unsigned int rd_end)
    285{
    286	char *output;
    287	unsigned long vmlinux_addr, vmlinux_len;
    288	unsigned long kernel_addr, kernel_len;
    289
    290#ifdef CONFIG_64BIT
    291	parisc_narrow_firmware = 0;
    292#endif
    293
    294	set_firmware_width_unlocked();
    295
    296	putchar('D');	/* if you get this D and no more, string storage */
    297			/* in $GLOBAL$ is wrong or %dp is wrong */
    298	puts("ecompressing Linux... ");
    299
    300	/* where the final bits are stored */
    301	kernel_addr = KERNEL_BINARY_TEXT_START;
    302	kernel_len = __pa(SZ_end) - __pa(SZparisc_kernel_start);
    303	if ((unsigned long) &_startcode_end > kernel_addr)
    304		error("Bootcode overlaps kernel code");
    305
    306	/*
    307	 * Calculate addr to where the vmlinux ELF file shall be decompressed.
    308	 * Assembly code in head.S positioned the stack directly behind bss, so
    309	 * leave 2 MB for the stack.
    310	 */
    311	vmlinux_addr = (unsigned long) &_ebss + 2*1024*1024;
    312	vmlinux_len = get_unaligned_le32(&output_len);
    313	output = (char *) vmlinux_addr;
    314
    315	/*
    316	 * Initialize free_mem_ptr and free_mem_end_ptr.
    317	 */
    318	free_mem_ptr = vmlinux_addr + vmlinux_len;
    319
    320	/* Limit memory for bootoader to 1GB */
    321	#define ARTIFICIAL_LIMIT (1*1024*1024*1024)
    322	free_mem_end_ptr = PAGE0->imm_max_mem;
    323	if (free_mem_end_ptr > ARTIFICIAL_LIMIT)
    324		free_mem_end_ptr = ARTIFICIAL_LIMIT;
    325
    326#ifdef CONFIG_BLK_DEV_INITRD
    327	/* if we have ramdisk this is at end of memory */
    328	if (rd_start && rd_start < free_mem_end_ptr)
    329		free_mem_end_ptr = rd_start;
    330#endif
    331
    332	if (free_mem_ptr >= free_mem_end_ptr) {
    333		int free_ram;
    334		free_ram = (free_mem_ptr >> 20) + 1;
    335		if (free_ram < 32)
    336			free_ram = 32;
    337		printf("\nKernel requires at least %d MB RAM.\n",
    338			free_ram);
    339		error(NULL);
    340	}
    341
    342#ifdef DEBUG
    343	printf("\n");
    344	printf("startcode_end = %x\n", &_startcode_end);
    345	printf("commandline   = %x\n", command_line);
    346	printf("rd_start      = %x\n", rd_start);
    347	printf("rd_end        = %x\n", rd_end);
    348
    349	printf("free_ptr      = %x\n", free_mem_ptr);
    350	printf("free_ptr_end  = %x\n", free_mem_end_ptr);
    351
    352	printf("input_data    = %x\n", input_data);
    353	printf("input_len     = %x\n", input_len);
    354	printf("output        = %x\n", output);
    355	printf("output_len    = %x\n", vmlinux_len);
    356	printf("kernel_addr   = %x\n", kernel_addr);
    357	printf("kernel_len    = %x\n", kernel_len);
    358#endif
    359
    360	__decompress(input_data, input_len, NULL, NULL,
    361			output, 0, NULL, error);
    362	parse_elf(output);
    363
    364	output = (char *) kernel_addr;
    365	flush_data_cache(output, kernel_len);
    366
    367	printf("done.\nBooting the kernel.\n");
    368
    369	return (unsigned long) output;
    370}