1 /* 2 * Program to hack in a PT_NOTE program header entry in an ELF file. 3 * This is needed for OF on RS/6000s to load an image correctly. 4 * Note that OF needs a program header entry for the note, not an 5 * ELF section. 6 * 7 * Copyright 2000 Paul Mackerras. 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License 11 * as published by the Free Software Foundation; either version 12 * 2 of the License, or (at your option) any later version. 13 * 14 * Usage: addnote [-r realbase] zImage [note.elf] 15 * 16 * If note.elf is supplied, it is the name of an ELF file that contains 17 * an RPA note to use instead of the built-in one. Alternatively, the 18 * note.elf file may be empty, in which case the built-in RPA note is 19 * used (this is to simplify how this is invoked from the wrapper script). 20 */ 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <fcntl.h> 24 #include <unistd.h> 25 #include <string.h> 26 27 /* CHRP note section */ 28 char arch[] = "PowerPC"; 29 30 #define N_DESCR 6 31 unsigned int descr[N_DESCR] = { 32 0xffffffff, /* real-mode = true */ 33 0x02000000, /* real-base, i.e. where we expect OF to be */ 34 0xffffffff, /* real-size */ 35 0xffffffff, /* virt-base */ 36 0xffffffff, /* virt-size */ 37 0x4000, /* load-base */ 38 }; 39 40 /* RPA note section */ 41 char rpaname[] = "IBM,RPA-Client-Config"; 42 43 /* 44 * Note: setting ignore_my_client_config *should* mean that OF ignores 45 * all the other fields, but there is a firmware bug which means that 46 * it looks at the splpar field at least. So these values need to be 47 * reasonable. 48 */ 49 #define N_RPA_DESCR 8 50 unsigned int rpanote[N_RPA_DESCR] = { 51 1, /* lparaffinity */ 52 128, /* min_rmo_size */ 53 0, /* min_rmo_percent */ 54 46, /* max_pft_size */ 55 1, /* splpar */ 56 -1, /* min_load */ 57 1, /* new_mem_def */ 58 0, /* ignore_my_client_config */ 59 }; 60 61 #define ROUNDUP(len) (((len) + 3) & ~3) 62 63 unsigned char buf[512]; 64 unsigned char notebuf[512]; 65 66 #define GET_16BE(b, off) (((b)[off] << 8) + ((b)[(off)+1])) 67 #define GET_32BE(b, off) ((GET_16BE((b), (off)) << 16) + \ 68 GET_16BE((b), (off)+2)) 69 70 #define PUT_16BE(b, off, v) ((b)[off] = ((v) >> 8) & 0xff, \ 71 (b)[(off) + 1] = (v) & 0xff) 72 #define PUT_32BE(b, off, v) (PUT_16BE((b), (off), (v) >> 16), \ 73 PUT_16BE((b), (off) + 2, (v))) 74 75 /* Structure of an ELF file */ 76 #define E_IDENT 0 /* ELF header */ 77 #define E_PHOFF 28 78 #define E_PHENTSIZE 42 79 #define E_PHNUM 44 80 #define E_HSIZE 52 /* size of ELF header */ 81 82 #define EI_MAGIC 0 /* offsets in E_IDENT area */ 83 #define EI_CLASS 4 84 #define EI_DATA 5 85 86 #define PH_TYPE 0 /* ELF program header */ 87 #define PH_OFFSET 4 88 #define PH_FILESZ 16 89 #define PH_HSIZE 32 /* size of program header */ 90 91 #define PT_NOTE 4 /* Program header type = note */ 92 93 #define ELFCLASS32 1 94 #define ELFDATA2MSB 2 95 96 unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' }; 97 98 unsigned char *read_rpanote(const char *fname, int *nnp) 99 { 100 int notefd, nr, i; 101 int ph, ps, np; 102 int note, notesize; 103 104 notefd = open(fname, O_RDONLY); 105 if (notefd < 0) { 106 perror(fname); 107 exit(1); 108 } 109 nr = read(notefd, notebuf, sizeof(notebuf)); 110 if (nr < 0) { 111 perror("read note"); 112 exit(1); 113 } 114 if (nr == 0) /* empty file */ 115 return NULL; 116 if (nr < E_HSIZE || 117 memcmp(¬ebuf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0 || 118 notebuf[E_IDENT+EI_CLASS] != ELFCLASS32 || 119 notebuf[E_IDENT+EI_DATA] != ELFDATA2MSB) 120 goto notelf; 121 close(notefd); 122 123 /* now look for the RPA-note */ 124 ph = GET_32BE(notebuf, E_PHOFF); 125 ps = GET_16BE(notebuf, E_PHENTSIZE); 126 np = GET_16BE(notebuf, E_PHNUM); 127 if (ph < E_HSIZE || ps < PH_HSIZE || np < 1) 128 goto notelf; 129 130 for (i = 0; i < np; ++i, ph += ps) { 131 if (GET_32BE(notebuf, ph + PH_TYPE) != PT_NOTE) 132 continue; 133 note = GET_32BE(notebuf, ph + PH_OFFSET); 134 notesize = GET_32BE(notebuf, ph + PH_FILESZ); 135 if (notesize < 34 || note + notesize > nr) 136 continue; 137 if (GET_32BE(notebuf, note) != strlen(rpaname) + 1 || 138 GET_32BE(notebuf, note + 8) != 0x12759999 || 139 strcmp((char *)¬ebuf[note + 12], rpaname) != 0) 140 continue; 141 /* looks like an RPA note, return it */ 142 *nnp = notesize; 143 return ¬ebuf[note]; 144 } 145 /* no RPA note found */ 146 return NULL; 147 148 notelf: 149 fprintf(stderr, "%s is not a big-endian 32-bit ELF image\n", fname); 150 exit(1); 151 } 152 153 int 154 main(int ac, char **av) 155 { 156 int fd, n, i, ai; 157 int ph, ps, np; 158 int nnote, nnote2, ns; 159 unsigned char *rpap; 160 char *p, *endp; 161 162 ai = 1; 163 if (ac >= ai + 2 && strcmp(av[ai], "-r") == 0) { 164 /* process -r realbase */ 165 p = av[ai + 1]; 166 descr[1] = strtol(p, &endp, 16); 167 if (endp == p || *endp != 0) { 168 fprintf(stderr, "Can't parse -r argument '%s' as hex\n", 169 p); 170 exit(1); 171 } 172 ai += 2; 173 } 174 if (ac != ai + 1 && ac != ai + 2) { 175 fprintf(stderr, "Usage: %s [-r realbase] elf-file [rpanote.elf]\n", av[0]); 176 exit(1); 177 } 178 fd = open(av[ai], O_RDWR); 179 if (fd < 0) { 180 perror(av[ai]); 181 exit(1); 182 } 183 184 nnote = 12 + ROUNDUP(strlen(arch) + 1) + sizeof(descr); 185 nnote2 = 12 + ROUNDUP(strlen(rpaname) + 1) + sizeof(rpanote); 186 rpap = NULL; 187 188 n = read(fd, buf, sizeof(buf)); 189 if (n < 0) { 190 perror("read"); 191 exit(1); 192 } 193 194 if (n < E_HSIZE || memcmp(&buf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0) 195 goto notelf; 196 197 if (buf[E_IDENT+EI_CLASS] != ELFCLASS32 198 || buf[E_IDENT+EI_DATA] != ELFDATA2MSB) { 199 fprintf(stderr, "%s is not a big-endian 32-bit ELF image\n", 200 av[ai]); 201 exit(1); 202 } 203 204 if (ac == ai + 2) 205 rpap = read_rpanote(av[ai + 1], &nnote2); 206 207 ph = GET_32BE(buf, E_PHOFF); 208 ps = GET_16BE(buf, E_PHENTSIZE); 209 np = GET_16BE(buf, E_PHNUM); 210 if (ph < E_HSIZE || ps < PH_HSIZE || np < 1) 211 goto notelf; 212 if (ph + (np + 2) * ps + nnote + nnote2 > n) 213 goto nospace; 214 215 for (i = 0; i < np; ++i) { 216 if (GET_32BE(buf, ph + PH_TYPE) == PT_NOTE) { 217 fprintf(stderr, "%s already has a note entry\n", 218 av[ai]); 219 exit(0); 220 } 221 ph += ps; 222 } 223 224 /* XXX check that the area we want to use is all zeroes */ 225 for (i = 0; i < 2 * ps + nnote + nnote2; ++i) 226 if (buf[ph + i] != 0) 227 goto nospace; 228 229 /* fill in the program header entry */ 230 ns = ph + 2 * ps; 231 PUT_32BE(buf, ph + PH_TYPE, PT_NOTE); 232 PUT_32BE(buf, ph + PH_OFFSET, ns); 233 PUT_32BE(buf, ph + PH_FILESZ, nnote); 234 235 /* fill in the note area we point to */ 236 /* XXX we should probably make this a proper section */ 237 PUT_32BE(buf, ns, strlen(arch) + 1); 238 PUT_32BE(buf, ns + 4, N_DESCR * 4); 239 PUT_32BE(buf, ns + 8, 0x1275); 240 strcpy((char *) &buf[ns + 12], arch); 241 ns += 12 + strlen(arch) + 1; 242 for (i = 0; i < N_DESCR; ++i, ns += 4) 243 PUT_32BE(buf, ns, descr[i]); 244 245 /* fill in the second program header entry and the RPA note area */ 246 ph += ps; 247 PUT_32BE(buf, ph + PH_TYPE, PT_NOTE); 248 PUT_32BE(buf, ph + PH_OFFSET, ns); 249 PUT_32BE(buf, ph + PH_FILESZ, nnote2); 250 251 /* fill in the note area we point to */ 252 if (rpap) { 253 /* RPA note supplied in file, just copy the whole thing over */ 254 memcpy(buf + ns, rpap, nnote2); 255 } else { 256 PUT_32BE(buf, ns, strlen(rpaname) + 1); 257 PUT_32BE(buf, ns + 4, sizeof(rpanote)); 258 PUT_32BE(buf, ns + 8, 0x12759999); 259 strcpy((char *) &buf[ns + 12], rpaname); 260 ns += 12 + ROUNDUP(strlen(rpaname) + 1); 261 for (i = 0; i < N_RPA_DESCR; ++i, ns += 4) 262 PUT_32BE(buf, ns, rpanote[i]); 263 } 264 265 /* Update the number of program headers */ 266 PUT_16BE(buf, E_PHNUM, np + 2); 267 268 /* write back */ 269 lseek(fd, (long) 0, SEEK_SET); 270 i = write(fd, buf, n); 271 if (i < 0) { 272 perror("write"); 273 exit(1); 274 } 275 if (i < n) { 276 fprintf(stderr, "%s: write truncated\n", av[ai]); 277 exit(1); 278 } 279 280 exit(0); 281 282 notelf: 283 fprintf(stderr, "%s does not appear to be an ELF file\n", av[ai]); 284 exit(1); 285 286 nospace: 287 fprintf(stderr, "sorry, I can't find space in %s to put the note\n", 288 av[ai]); 289 exit(1); 290 } 291