18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci Simple utility to make a single-image install kernel with initial ramdisk 48c2ecf20Sopenharmony_ci for Sparc tftpbooting without need to set up nfs. 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) 78c2ecf20Sopenharmony_ci Pete Zaitcev <zaitcev@yahoo.com> endian fixes for cross-compiles, 2000. 88c2ecf20Sopenharmony_ci Copyright (C) 2011 Sam Ravnborg <sam@ravnborg.org> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <dirent.h> 138c2ecf20Sopenharmony_ci#include <stdlib.h> 148c2ecf20Sopenharmony_ci#include <string.h> 158c2ecf20Sopenharmony_ci#include <unistd.h> 168c2ecf20Sopenharmony_ci#include <ctype.h> 178c2ecf20Sopenharmony_ci#include <errno.h> 188c2ecf20Sopenharmony_ci#include <fcntl.h> 198c2ecf20Sopenharmony_ci#include <stdio.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <sys/types.h> 228c2ecf20Sopenharmony_ci#include <sys/stat.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci/* 258c2ecf20Sopenharmony_ci * Note: run this on an a.out kernel (use elftoaout for it), 268c2ecf20Sopenharmony_ci * as PROM looks for a.out image only. 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define AOUT_TEXT_OFFSET 32 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic int is64bit = 0; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* align to power-of-two size */ 348c2ecf20Sopenharmony_cistatic int align(int n) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci if (is64bit) 378c2ecf20Sopenharmony_ci return (n + 0x1fff) & ~0x1fff; 388c2ecf20Sopenharmony_ci else 398c2ecf20Sopenharmony_ci return (n + 0xfff) & ~0xfff; 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* read two bytes as big endian */ 438c2ecf20Sopenharmony_cistatic unsigned short ld2(char *p) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci return (p[0] << 8) | p[1]; 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* save 4 bytes as big endian */ 498c2ecf20Sopenharmony_cistatic void st4(char *p, unsigned int x) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci p[0] = x >> 24; 528c2ecf20Sopenharmony_ci p[1] = x >> 16; 538c2ecf20Sopenharmony_ci p[2] = x >> 8; 548c2ecf20Sopenharmony_ci p[3] = x; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic void die(const char *str) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci perror(str); 608c2ecf20Sopenharmony_ci exit(1); 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic void usage(void) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci /* fs_img.gz is an image of initial ramdisk. */ 668c2ecf20Sopenharmony_ci fprintf(stderr, "Usage: piggyback bits vmlinux.aout System.map fs_img.gz\n"); 678c2ecf20Sopenharmony_ci fprintf(stderr, "\tKernel image will be modified in place.\n"); 688c2ecf20Sopenharmony_ci exit(1); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic int start_line(const char *line) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci if (strcmp(line + 10, " _start\n") == 0) 748c2ecf20Sopenharmony_ci return 1; 758c2ecf20Sopenharmony_ci else if (strcmp(line + 18, " _start\n") == 0) 768c2ecf20Sopenharmony_ci return 1; 778c2ecf20Sopenharmony_ci return 0; 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic int end_line(const char *line) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci if (strcmp(line + 10, " _end\n") == 0) 838c2ecf20Sopenharmony_ci return 1; 848c2ecf20Sopenharmony_ci else if (strcmp (line + 18, " _end\n") == 0) 858c2ecf20Sopenharmony_ci return 1; 868c2ecf20Sopenharmony_ci return 0; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* 908c2ecf20Sopenharmony_ci * Find address for start and end in System.map. 918c2ecf20Sopenharmony_ci * The file looks like this: 928c2ecf20Sopenharmony_ci * f0004000 ... _start 938c2ecf20Sopenharmony_ci * f0379f79 ... _end 948c2ecf20Sopenharmony_ci * 1234567890123456 958c2ecf20Sopenharmony_ci * ^coloumn 1 968c2ecf20Sopenharmony_ci * There is support for 64 bit addresses too. 978c2ecf20Sopenharmony_ci * 988c2ecf20Sopenharmony_ci * Return 0 if either start or end is not found 998c2ecf20Sopenharmony_ci */ 1008c2ecf20Sopenharmony_cistatic int get_start_end(const char *filename, unsigned int *start, 1018c2ecf20Sopenharmony_ci unsigned int *end) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci FILE *map; 1048c2ecf20Sopenharmony_ci char buffer[1024]; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci *start = 0; 1078c2ecf20Sopenharmony_ci *end = 0; 1088c2ecf20Sopenharmony_ci map = fopen(filename, "r"); 1098c2ecf20Sopenharmony_ci if (!map) 1108c2ecf20Sopenharmony_ci die(filename); 1118c2ecf20Sopenharmony_ci while (fgets(buffer, 1024, map)) { 1128c2ecf20Sopenharmony_ci if (start_line(buffer)) 1138c2ecf20Sopenharmony_ci *start = strtoul(buffer, NULL, 16); 1148c2ecf20Sopenharmony_ci else if (end_line(buffer)) 1158c2ecf20Sopenharmony_ci *end = strtoul(buffer, NULL, 16); 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci fclose (map); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (*start == 0 || *end == 0) 1208c2ecf20Sopenharmony_ci return 0; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci return 1; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci#define LOOKBACK (128 * 4) 1268c2ecf20Sopenharmony_ci#define BUFSIZE 1024 1278c2ecf20Sopenharmony_ci/* 1288c2ecf20Sopenharmony_ci * Find the HdrS entry from head_32/head_64. 1298c2ecf20Sopenharmony_ci * We check if it is at the beginning of the file (sparc64 case) 1308c2ecf20Sopenharmony_ci * and if not we search for it. 1318c2ecf20Sopenharmony_ci * When we search do so in steps of 4 as HdrS is on a 4-byte aligned 1328c2ecf20Sopenharmony_ci * address (it is on same alignment as sparc instructions) 1338c2ecf20Sopenharmony_ci * Return the offset to the HdrS entry (as off_t) 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_cistatic off_t get_hdrs_offset(int kernelfd, const char *filename) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci char buffer[BUFSIZE]; 1388c2ecf20Sopenharmony_ci off_t offset; 1398c2ecf20Sopenharmony_ci int i; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (lseek(kernelfd, 0, SEEK_SET) < 0) 1428c2ecf20Sopenharmony_ci die("lseek"); 1438c2ecf20Sopenharmony_ci if (read(kernelfd, buffer, BUFSIZE) != BUFSIZE) 1448c2ecf20Sopenharmony_ci die(filename); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (buffer[40] == 'H' && buffer[41] == 'd' && 1478c2ecf20Sopenharmony_ci buffer[42] == 'r' && buffer[43] == 'S') { 1488c2ecf20Sopenharmony_ci return 40; 1498c2ecf20Sopenharmony_ci } else { 1508c2ecf20Sopenharmony_ci /* Find the gokernel label */ 1518c2ecf20Sopenharmony_ci /* Decode offset from branch instruction */ 1528c2ecf20Sopenharmony_ci offset = ld2(buffer + AOUT_TEXT_OFFSET + 2) << 2; 1538c2ecf20Sopenharmony_ci /* Go back 512 bytes so we do not miss HdrS */ 1548c2ecf20Sopenharmony_ci offset -= LOOKBACK; 1558c2ecf20Sopenharmony_ci /* skip a.out header */ 1568c2ecf20Sopenharmony_ci offset += AOUT_TEXT_OFFSET; 1578c2ecf20Sopenharmony_ci if (lseek(kernelfd, offset, SEEK_SET) < 0) 1588c2ecf20Sopenharmony_ci die("lseek"); 1598c2ecf20Sopenharmony_ci if (read(kernelfd, buffer, BUFSIZE) != BUFSIZE) 1608c2ecf20Sopenharmony_ci die(filename); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci for (i = 0; i < LOOKBACK; i += 4) { 1638c2ecf20Sopenharmony_ci if (buffer[i + 0] == 'H' && buffer[i + 1] == 'd' && 1648c2ecf20Sopenharmony_ci buffer[i + 2] == 'r' && buffer[i + 3] == 'S') { 1658c2ecf20Sopenharmony_ci return offset + i; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci fprintf (stderr, "Couldn't find headers signature in %s\n", filename); 1708c2ecf20Sopenharmony_ci exit(1); 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ciint main(int argc,char **argv) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci static char aout_magic[] = { 0x01, 0x03, 0x01, 0x07 }; 1768c2ecf20Sopenharmony_ci char buffer[1024]; 1778c2ecf20Sopenharmony_ci unsigned int i, start, end; 1788c2ecf20Sopenharmony_ci off_t offset; 1798c2ecf20Sopenharmony_ci struct stat s; 1808c2ecf20Sopenharmony_ci int image, tail; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci if (argc != 5) 1838c2ecf20Sopenharmony_ci usage(); 1848c2ecf20Sopenharmony_ci if (strcmp(argv[1], "64") == 0) 1858c2ecf20Sopenharmony_ci is64bit = 1; 1868c2ecf20Sopenharmony_ci if (stat (argv[4], &s) < 0) 1878c2ecf20Sopenharmony_ci die(argv[4]); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (!get_start_end(argv[3], &start, &end)) { 1908c2ecf20Sopenharmony_ci fprintf(stderr, "Could not determine start and end from %s\n", 1918c2ecf20Sopenharmony_ci argv[3]); 1928c2ecf20Sopenharmony_ci exit(1); 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci if ((image = open(argv[2], O_RDWR)) < 0) 1958c2ecf20Sopenharmony_ci die(argv[2]); 1968c2ecf20Sopenharmony_ci if (read(image, buffer, 512) != 512) 1978c2ecf20Sopenharmony_ci die(argv[2]); 1988c2ecf20Sopenharmony_ci if (memcmp(buffer, aout_magic, 4) != 0) { 1998c2ecf20Sopenharmony_ci fprintf (stderr, "Not a.out. Don't blame me.\n"); 2008c2ecf20Sopenharmony_ci exit(1); 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci /* 2038c2ecf20Sopenharmony_ci * We need to fill in values for 2048c2ecf20Sopenharmony_ci * sparc_ramdisk_image + sparc_ramdisk_size 2058c2ecf20Sopenharmony_ci * To locate these symbols search for the "HdrS" text which appear 2068c2ecf20Sopenharmony_ci * in the image a little before the gokernel symbol. 2078c2ecf20Sopenharmony_ci * See definition of these in init_32.S 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci offset = get_hdrs_offset(image, argv[2]); 2118c2ecf20Sopenharmony_ci /* skip HdrS + LINUX_VERSION_CODE + HdrS version */ 2128c2ecf20Sopenharmony_ci offset += 10; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci if (lseek(image, offset, 0) < 0) 2158c2ecf20Sopenharmony_ci die("lseek"); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci /* 2188c2ecf20Sopenharmony_ci * root_flags = 0 2198c2ecf20Sopenharmony_ci * root_dev = 1 (RAMDISK_MAJOR) 2208c2ecf20Sopenharmony_ci * ram_flags = 0 2218c2ecf20Sopenharmony_ci * sparc_ramdisk_image = "PAGE aligned address after _end") 2228c2ecf20Sopenharmony_ci * sparc_ramdisk_size = size of image 2238c2ecf20Sopenharmony_ci */ 2248c2ecf20Sopenharmony_ci st4(buffer, 0); 2258c2ecf20Sopenharmony_ci st4(buffer + 4, 0x01000000); 2268c2ecf20Sopenharmony_ci st4(buffer + 8, align(end + 32)); 2278c2ecf20Sopenharmony_ci st4(buffer + 12, s.st_size); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if (write(image, buffer + 2, 14) != 14) 2308c2ecf20Sopenharmony_ci die(argv[2]); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci /* For sparc64 update a_text and clear a_data + a_bss */ 2338c2ecf20Sopenharmony_ci if (is64bit) 2348c2ecf20Sopenharmony_ci { 2358c2ecf20Sopenharmony_ci if (lseek(image, 4, 0) < 0) 2368c2ecf20Sopenharmony_ci die("lseek"); 2378c2ecf20Sopenharmony_ci /* a_text */ 2388c2ecf20Sopenharmony_ci st4(buffer, align(end + 32 + 8191) - (start & ~0x3fffffUL) + 2398c2ecf20Sopenharmony_ci s.st_size); 2408c2ecf20Sopenharmony_ci /* a_data */ 2418c2ecf20Sopenharmony_ci st4(buffer + 4, 0); 2428c2ecf20Sopenharmony_ci /* a_bss */ 2438c2ecf20Sopenharmony_ci st4(buffer + 8, 0); 2448c2ecf20Sopenharmony_ci if (write(image, buffer, 12) != 12) 2458c2ecf20Sopenharmony_ci die(argv[2]); 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* seek page aligned boundary in the image file and add boot image */ 2498c2ecf20Sopenharmony_ci if (lseek(image, AOUT_TEXT_OFFSET - start + align(end + 32), 0) < 0) 2508c2ecf20Sopenharmony_ci die("lseek"); 2518c2ecf20Sopenharmony_ci if ((tail = open(argv[4], O_RDONLY)) < 0) 2528c2ecf20Sopenharmony_ci die(argv[4]); 2538c2ecf20Sopenharmony_ci while ((i = read(tail, buffer, 1024)) > 0) 2548c2ecf20Sopenharmony_ci if (write(image, buffer, i) != i) 2558c2ecf20Sopenharmony_ci die(argv[2]); 2568c2ecf20Sopenharmony_ci if (close(image) < 0) 2578c2ecf20Sopenharmony_ci die("close"); 2588c2ecf20Sopenharmony_ci if (close(tail) < 0) 2598c2ecf20Sopenharmony_ci die("close"); 2608c2ecf20Sopenharmony_ci return 0; 2618c2ecf20Sopenharmony_ci} 262