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
> + 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;
> +}
> +
This sequence of strcmps can be made a lot more efficient with specialized code (and smaller)
> +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;
> +
I think a default and break here is better
> }
> + 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