NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: port-arm/49299: earmv7hfeb kernels can not load modules



The following reply was made to PR port-arm/49299; it has been noted by GNATS.

From: Martin Husemann <martin%duskware.de@localhost>
To: Matt Thomas <matt%3am-software.com@localhost>
Cc: gnats-bugs%NetBSD.org@localhost
Subject: Re: port-arm/49299: earmv7hfeb kernels can not load modules
Date: Thu, 6 Nov 2014 23:13:23 +0100

 --5mCyUwZo2JvN/JJP
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
 
 Ok, this was easier than I expected: the patch attached fixes it for me.
 
 I couldn't find a proper #ifdef condition to enable it - shouldn't there
 be one for --eb8 ?
 
 I also don't like the hardcoding of ".text" in the section selection,
 but unfortunately we are called slightly too late and the section
 header has already been freed. This could be easily worked around by
 copying over the section header type to the progbits table and check
 for SHT_PROGBITS instead of strcmp against ".text" - or by adding a MD
 hook after relocations are done but before jetisoning.
 
 Martin
 
 --5mCyUwZo2JvN/JJP
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: attachment; filename=patch
 
 Index: kobj_machdep.c
 ===================================================================
 RCS file: /cvsroot/src/sys/arch/arm/arm32/kobj_machdep.c,v
 retrieving revision 1.9
 diff -u -p -r1.9 kobj_machdep.c
 --- kobj_machdep.c	27 Aug 2013 06:41:05 -0000	1.9
 +++ kobj_machdep.c	6 Nov 2014 21:58:24 -0000
 @@ -62,6 +62,16 @@ __KERNEL_RCSID(0, "$NetBSD: kobj_machdep
  #include <sys/exec.h>
  #include <sys/exec_elf.h>
  
 +#if __ARM_ARCH==7 && __ARM_BIG_ENDIAN
 +#define	ARM_8EB
 +#endif
 +
 +#ifdef ARM_8EB
 +#include <sys/ksyms.h>
 +#include <sys/kobj_impl.h>
 +#include <sys/kmem.h>
 +#endif
 +
  #include <arm/cpufunc.h>
  
  int
 @@ -203,6 +213,184 @@ kobj_reloc(kobj_t ko, uintptr_t relocbas
  	return -1;
  }
  
 +#ifdef ARM_8EB
 +
 +enum be8_magic_sym_type {
 +	Other, ArmStart, ThumbStart, DataStart
 +};
 +
 +struct be8_marker {
 +	enum be8_magic_sym_type type;
 +	void *addr;
 +};
 +
 +struct be8_marker_list {
 +	size_t cnt;
 +	struct be8_marker *markers;
 +};
 +
 +static enum be8_magic_sym_type
 +be8_sym_type(const char *name, int info)
 +{
 +	if (ELF_ST_BIND(info) != STB_LOCAL)
 +		return Other;
 +	if (ELF_ST_TYPE(info) != STT_NOTYPE)
 +		return Other;
 +	if (strcmp(name, "$a") == 0)
 +		return ArmStart;
 +	if (strncmp(name, "$a.", 3) == 0)
 +		return ArmStart;
 +	if (strcmp(name, "$t") == 0)
 +		return ThumbStart;
 +	if (strncmp(name, "$t.", 3) == 0)
 +		return ThumbStart;
 +	if (strcmp(name, "$d") == 0)
 +		return DataStart;
 +	if (strncmp(name, "$d.", 3) == 0)
 +		return DataStart;
 +	return Other;
 +}
 +
 +static int
 +be8_ksym_count(const char *name, int symindex, void *value, uint32_t size,
 +	int info, void *cookie)
 +{
 +	size_t *res = cookie;
 +	enum be8_magic_sym_type t = be8_sym_type(name, info);
 +
 +	if (t != Other)
 +		(*res)++;
 +	return 0;
 +}
 +
 +static int
 +be8_ksym_add(const char *name, int symindex, void *value, uint32_t size,
 +	int info, void *cookie)
 +{
 +	size_t ndx;
 +	struct be8_marker_list *list = cookie;
 +	enum be8_magic_sym_type t = be8_sym_type(name, info);
 +
 +	if (t == Other)
 +		return 0;
 +
 +	ndx = list->cnt++;
 +	list->markers[ndx].type = t;
 +	list->markers[ndx].addr = value;
 +
 +	return 0;
 +}
 +
 +static int
 +be8_ksym_comp(const void *a, const void *b)
 +{
 +	const struct be8_marker *ma = a, *mb = b;
 +	uintptr_t va = (uintptr_t)ma->addr, vb = (uintptr_t)mb->addr;
 +
 +	if (va == vb)
 +		return 0;
 +	if (va < vb)
 +		return -1;
 +	return 1;
 +}
 +
 +static void
 +be8_ksym_swap(void *start, size_t size, const struct be8_marker_list *list)
 +{
 +	uintptr_t va_end = (uintptr_t)start + size;
 +	size_t i;
 +	uint32_t *p32, *p32_end, v32;
 +	uint16_t *p16, *p16_end, v16;
 +
 +	/* find first relevant list entry */
 +	for (i = 0; i < list->cnt; i++)
 +		if (start <= list->markers[i].addr)
 +			break;
 +
 +	/* swap all arm and thumb code parts of this section */
 +	for ( ; i < list->cnt; i++) {
 +		switch (list->markers[i].type) {
 +		case ArmStart:
 +			p32 = (uint32_t*)list->markers[i].addr;
 +			p32_end = (uint32_t*)va_end;
 +			if (i+1 < list->cnt) {
 +				if ((uintptr_t)list->markers[i+1].addr
 +				    < va_end)
 +					p32_end = (uint32_t*)
 +						list->markers[i+1].addr;
 +			}
 +			while (p32 < p32_end) {
 +				v32 = bswap32(*p32);
 +				*p32++ = v32;
 +			}
 +			break;
 +		case ThumbStart:
 +			p16 = (uint16_t*)list->markers[i].addr;
 +			p16_end = (uint16_t*)va_end;
 +			if (i+1 < list->cnt) {
 +				if ((uintptr_t)list->markers[i+1].addr
 +				    < va_end)
 +					p16_end = (uint16_t*)
 +						list->markers[i+1].addr;
 +			}
 +			while (p16 < p16_end) {
 +				v16 = bswap16(*p16);
 +				*p16++ = v16;
 +			}
 +			break;
 +		default:
 +			break;
 +		}
 +	}
 +}
 + 
 +static void
 +kobj_be8_fixup(kobj_t ko)
 +{
 +	size_t relsym_cnt = 0, i;
 +	struct be8_marker_list list;
 +	struct be8_marker tmp;
 +
 +	/*
 +	 * Count all special relocations symbols
 +	 */
 +	ksyms_mod_foreach(ko->ko_name, be8_ksym_count, &relsym_cnt);
 +
 +	/*
 +	 * Provide storage for the address list and add the symbols
 +	 */
 +	list.cnt = 0;
 +	list.markers = kmem_alloc(relsym_cnt*sizeof(*list.markers), KM_SLEEP);
 +	ksyms_mod_foreach(ko->ko_name, be8_ksym_add, &list);
 +	KASSERT(list.cnt == relsym_cnt);
 +
 +	/*
 +	 * Sort symbols by ascending address
 +	 */
 +	if (kheapsort(list.markers, relsym_cnt, sizeof(*list.markers),
 +	    be8_ksym_comp, &tmp) != 0)
 +		panic("could not sort be8 marker symbols");
 +
 +	/*
 +	 * Apply swaps to the .text section (XXX we do not have the
 +	 * section header available any more, it has been jetisoned
 +	 * already, so we can not check for all PROGBIT sections).
 +	 */
 +	for (i = 0; i < ko->ko_nprogtab; i++) {
 +		if (strcmp(ko->ko_progtab[i].name, ".text") != 0)
 +			continue;
 +		be8_ksym_swap(ko->ko_progtab[i].addr,
 +		    (size_t)ko->ko_progtab[i].size,
 +		    &list);
 +	}
 +
 +	/*
 +	 * Done, free list
 +	 */
 +	kmem_free(list.markers, relsym_cnt*sizeof(*list.markers));
 +}
 +#endif
 +
  int
  kobj_machdep(kobj_t ko, void *base, size_t size, bool load)
  {
 @@ -212,6 +400,9 @@ kobj_machdep(kobj_t ko, void *base, size
  		cpu_idcache_wbinv_range((vaddr_t)base, size);
  		cpu_tlb_flushID();
  #endif
 +#ifdef ARM_8EB
 +		kobj_be8_fixup(ko);
 +#endif
  	}
  
  	return 0;
 
 --5mCyUwZo2JvN/JJP--
 


Home | Main Index | Thread Index | Old Index