^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * This file reads all the special sections which have alternate instructions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * which can be patched in or redirected to at runtime.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <stdlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "builtin.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include "special.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "warn.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include "arch_special.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) struct special_entry {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) const char *sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) bool group, jump_or_nop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) unsigned char size, orig, new;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) unsigned char orig_len, new_len; /* group only */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) unsigned char feature; /* ALTERNATIVE macro CPU feature */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct special_entry entries[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) .sec = ".altinstructions",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) .group = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) .size = ALT_ENTRY_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) .orig = ALT_ORIG_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) .orig_len = ALT_ORIG_LEN_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) .new = ALT_NEW_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) .new_len = ALT_NEW_LEN_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) .feature = ALT_FEATURE_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) .sec = "__jump_table",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) .jump_or_nop = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) .size = JUMP_ENTRY_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) .orig = JUMP_ORIG_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) .new = JUMP_NEW_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) .sec = "__ex_table",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) .size = EX_ENTRY_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) .orig = EX_ORIG_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) .new = EX_NEW_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) void __weak arch_handle_alternative(unsigned short feature, struct special_alt *alt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) static int get_alt_entry(struct elf *elf, struct special_entry *entry,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) struct section *sec, int idx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) struct special_alt *alt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct reloc *orig_reloc, *new_reloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) unsigned long offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) offset = idx * entry->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) alt->group = entry->group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) alt->jump_or_nop = entry->jump_or_nop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) if (alt->group) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) alt->orig_len = *(unsigned char *)(sec->data->d_buf + offset +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) entry->orig_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) alt->new_len = *(unsigned char *)(sec->data->d_buf + offset +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) entry->new_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) if (entry->feature) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) unsigned short feature;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) feature = *(unsigned short *)(sec->data->d_buf + offset +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) entry->feature);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) arch_handle_alternative(feature, alt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) orig_reloc = find_reloc_by_dest(elf, sec, offset + entry->orig);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (!orig_reloc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) WARN_FUNC("can't find orig reloc", sec, offset + entry->orig);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (orig_reloc->sym->type != STT_SECTION) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) WARN_FUNC("don't know how to handle non-section reloc symbol %s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) sec, offset + entry->orig, orig_reloc->sym->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) alt->orig_sec = orig_reloc->sym->sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) alt->orig_off = orig_reloc->addend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (!entry->group || alt->new_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) new_reloc = find_reloc_by_dest(elf, sec, offset + entry->new);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) if (!new_reloc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) WARN_FUNC("can't find new reloc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) sec, offset + entry->new);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) alt->new_sec = new_reloc->sym->sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) alt->new_off = (unsigned int)new_reloc->addend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) /* _ASM_EXTABLE_EX hack */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (alt->new_off >= 0x7ffffff0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) alt->new_off -= 0x7ffffff0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) * Read all the special sections and create a list of special_alt structs which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) * describe all the alternate instructions which can be patched in or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) * redirected to at runtime.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) int special_get_alts(struct elf *elf, struct list_head *alts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) struct special_entry *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) struct section *sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) unsigned int nr_entries;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) struct special_alt *alt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) int idx, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) INIT_LIST_HEAD(alts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) for (entry = entries; entry->sec; entry++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) sec = find_section_by_name(elf, entry->sec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (!sec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (sec->len % entry->size != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) WARN("%s size not a multiple of %d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) sec->name, entry->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) nr_entries = sec->len / entry->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) for (idx = 0; idx < nr_entries; idx++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) alt = malloc(sizeof(*alt));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if (!alt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) WARN("malloc failed");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) memset(alt, 0, sizeof(*alt));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) ret = get_alt_entry(elf, entry, sec, idx, alt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) list_add_tail(&alt->list, alts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }