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