1261d2760SDarwin Rambo /* 2261d2760SDarwin Rambo * Copyright 2014 Broadcom Corporation 3261d2760SDarwin Rambo * 4261d2760SDarwin Rambo * SPDX-License-Identifier: GPL-2.0+ 5261d2760SDarwin Rambo */ 6261d2760SDarwin Rambo 7261d2760SDarwin Rambo /* 8261d2760SDarwin Rambo * Minimal semihosting implementation for reading files into memory. If more 9261d2760SDarwin Rambo * features like writing files or console output are required they can be 10261d2760SDarwin Rambo * added later. This code has been tested on arm64/aarch64 fastmodel only. 11261d2760SDarwin Rambo * An untested placeholder exists for armv7 architectures, but since they 12261d2760SDarwin Rambo * are commonly available in silicon now, fastmodel usage makes less sense 13261d2760SDarwin Rambo * for them. 14261d2760SDarwin Rambo */ 15261d2760SDarwin Rambo #include <common.h> 16261d2760SDarwin Rambo #include <asm/semihosting.h> 17261d2760SDarwin Rambo 18261d2760SDarwin Rambo #define SYSOPEN 0x01 19261d2760SDarwin Rambo #define SYSCLOSE 0x02 20261d2760SDarwin Rambo #define SYSREAD 0x06 21261d2760SDarwin Rambo #define SYSFLEN 0x0C 22261d2760SDarwin Rambo 23261d2760SDarwin Rambo #define MODE_READ 0x0 24261d2760SDarwin Rambo #define MODE_READBIN 0x1 25261d2760SDarwin Rambo 26261d2760SDarwin Rambo /* 27261d2760SDarwin Rambo * Call the handler 28261d2760SDarwin Rambo */ 294e1ef150SLinus Walleij static long smh_trap(unsigned int sysnum, void *addr) 30261d2760SDarwin Rambo { 314e1ef150SLinus Walleij register long result asm("r0"); 32261d2760SDarwin Rambo #if defined(CONFIG_ARM64) 33261d2760SDarwin Rambo asm volatile ("hlt #0xf000" : "=r" (result) : "0"(sysnum), "r"(addr)); 34261d2760SDarwin Rambo #else 35261d2760SDarwin Rambo /* Note - untested placeholder */ 36261d2760SDarwin Rambo asm volatile ("svc #0x123456" : "=r" (result) : "0"(sysnum), "r"(addr)); 37261d2760SDarwin Rambo #endif 38261d2760SDarwin Rambo return result; 39261d2760SDarwin Rambo } 40261d2760SDarwin Rambo 41261d2760SDarwin Rambo /* 42*9be5c661SLinus Walleij * Open a file on the host. Mode is "r" or "rb" currently. Returns a file 43*9be5c661SLinus Walleij * descriptor or -1 on error. 44*9be5c661SLinus Walleij */ 45*9be5c661SLinus Walleij static long smh_open(const char *fname, char *modestr) 46*9be5c661SLinus Walleij { 47*9be5c661SLinus Walleij long fd; 48*9be5c661SLinus Walleij unsigned long mode; 49*9be5c661SLinus Walleij struct smh_open_s { 50*9be5c661SLinus Walleij const char *fname; 51*9be5c661SLinus Walleij unsigned long mode; 52*9be5c661SLinus Walleij size_t len; 53*9be5c661SLinus Walleij } open; 54*9be5c661SLinus Walleij 55*9be5c661SLinus Walleij debug("%s: file \'%s\', mode \'%s\'\n", __func__, fname, modestr); 56*9be5c661SLinus Walleij 57*9be5c661SLinus Walleij /* Check the file mode */ 58*9be5c661SLinus Walleij if (!(strcmp(modestr, "r"))) { 59*9be5c661SLinus Walleij mode = MODE_READ; 60*9be5c661SLinus Walleij } else if (!(strcmp(modestr, "rb"))) { 61*9be5c661SLinus Walleij mode = MODE_READBIN; 62*9be5c661SLinus Walleij } else { 63*9be5c661SLinus Walleij printf("%s: ERROR mode \'%s\' not supported\n", __func__, 64*9be5c661SLinus Walleij modestr); 65*9be5c661SLinus Walleij return -1; 66*9be5c661SLinus Walleij } 67*9be5c661SLinus Walleij 68*9be5c661SLinus Walleij open.fname = fname; 69*9be5c661SLinus Walleij open.len = strlen(fname); 70*9be5c661SLinus Walleij open.mode = mode; 71*9be5c661SLinus Walleij 72*9be5c661SLinus Walleij /* Open the file on the host */ 73*9be5c661SLinus Walleij fd = smh_trap(SYSOPEN, &open); 74*9be5c661SLinus Walleij if (fd == -1) 75*9be5c661SLinus Walleij printf("%s: ERROR fd %ld for file \'%s\'\n", __func__, fd, 76*9be5c661SLinus Walleij fname); 77*9be5c661SLinus Walleij 78*9be5c661SLinus Walleij return fd; 79*9be5c661SLinus Walleij } 80*9be5c661SLinus Walleij 81*9be5c661SLinus Walleij /* 82*9be5c661SLinus Walleij * Read 'len' bytes of file into 'memp'. Returns 0 on success, else failure 83*9be5c661SLinus Walleij */ 84*9be5c661SLinus Walleij static long smh_read(long fd, void *memp, size_t len) 85*9be5c661SLinus Walleij { 86*9be5c661SLinus Walleij long ret; 87*9be5c661SLinus Walleij struct smh_read_s { 88*9be5c661SLinus Walleij long fd; 89*9be5c661SLinus Walleij void *memp; 90*9be5c661SLinus Walleij size_t len; 91*9be5c661SLinus Walleij } read; 92*9be5c661SLinus Walleij 93*9be5c661SLinus Walleij debug("%s: fd %ld, memp %p, len %lu\n", __func__, fd, memp, len); 94*9be5c661SLinus Walleij 95*9be5c661SLinus Walleij read.fd = fd; 96*9be5c661SLinus Walleij read.memp = memp; 97*9be5c661SLinus Walleij read.len = len; 98*9be5c661SLinus Walleij 99*9be5c661SLinus Walleij ret = smh_trap(SYSREAD, &read); 100*9be5c661SLinus Walleij if (ret < 0) { 101*9be5c661SLinus Walleij /* 102*9be5c661SLinus Walleij * The ARM handler allows for returning partial lengths, 103*9be5c661SLinus Walleij * but in practice this never happens so rather than create 104*9be5c661SLinus Walleij * hard to maintain partial read loops and such, just fail 105*9be5c661SLinus Walleij * with an error message. 106*9be5c661SLinus Walleij */ 107*9be5c661SLinus Walleij printf("%s: ERROR ret %ld, fd %ld, len %lu memp %p\n", 108*9be5c661SLinus Walleij __func__, ret, fd, len, memp); 109*9be5c661SLinus Walleij return -1; 110*9be5c661SLinus Walleij } 111*9be5c661SLinus Walleij 112*9be5c661SLinus Walleij return 0; 113*9be5c661SLinus Walleij } 114*9be5c661SLinus Walleij 115*9be5c661SLinus Walleij /* 116*9be5c661SLinus Walleij * Close the file using the file descriptor 117*9be5c661SLinus Walleij */ 118*9be5c661SLinus Walleij static long smh_close(long fd) 119*9be5c661SLinus Walleij { 120*9be5c661SLinus Walleij long ret; 121*9be5c661SLinus Walleij 122*9be5c661SLinus Walleij debug("%s: fd %ld\n", __func__, fd); 123*9be5c661SLinus Walleij 124*9be5c661SLinus Walleij ret = smh_trap(SYSCLOSE, &fd); 125*9be5c661SLinus Walleij if (ret == -1) 126*9be5c661SLinus Walleij printf("%s: ERROR fd %ld\n", __func__, fd); 127*9be5c661SLinus Walleij 128*9be5c661SLinus Walleij return ret; 129*9be5c661SLinus Walleij } 130*9be5c661SLinus Walleij 131*9be5c661SLinus Walleij /* 132*9be5c661SLinus Walleij * Get the file length from the file descriptor 133*9be5c661SLinus Walleij */ 134*9be5c661SLinus Walleij static long smh_len_fd(long fd) 135*9be5c661SLinus Walleij { 136*9be5c661SLinus Walleij long ret; 137*9be5c661SLinus Walleij 138*9be5c661SLinus Walleij debug("%s: fd %ld\n", __func__, fd); 139*9be5c661SLinus Walleij 140*9be5c661SLinus Walleij ret = smh_trap(SYSFLEN, &fd); 141*9be5c661SLinus Walleij if (ret == -1) 142*9be5c661SLinus Walleij printf("%s: ERROR ret %ld, fd %ld\n", __func__, ret, fd); 143*9be5c661SLinus Walleij 144*9be5c661SLinus Walleij return ret; 145*9be5c661SLinus Walleij } 146*9be5c661SLinus Walleij 147*9be5c661SLinus Walleij /* 148261d2760SDarwin Rambo * Open, load a file into memory, and close it. Check that the available space 149261d2760SDarwin Rambo * is sufficient to store the entire file. Return the bytes actually read from 150261d2760SDarwin Rambo * the file as seen by the read function. The verbose flag enables some extra 151261d2760SDarwin Rambo * printing of successful read status. 152261d2760SDarwin Rambo */ 153261d2760SDarwin Rambo int smh_load(const char *fname, void *memp, int avail, int verbose) 154261d2760SDarwin Rambo { 1554e1ef150SLinus Walleij long ret; 1564e1ef150SLinus Walleij long fd; 1574e1ef150SLinus Walleij size_t len; 158261d2760SDarwin Rambo 159261d2760SDarwin Rambo ret = -1; 160261d2760SDarwin Rambo 161261d2760SDarwin Rambo debug("%s: fname \'%s\', avail %u, memp %p\n", __func__, fname, 162261d2760SDarwin Rambo avail, memp); 163261d2760SDarwin Rambo 164261d2760SDarwin Rambo /* Open the file */ 165261d2760SDarwin Rambo fd = smh_open(fname, "rb"); 166261d2760SDarwin Rambo if (fd == -1) 1674e1ef150SLinus Walleij return -1; 168261d2760SDarwin Rambo 169261d2760SDarwin Rambo /* Get the file length */ 170261d2760SDarwin Rambo ret = smh_len_fd(fd); 171261d2760SDarwin Rambo if (ret == -1) { 172261d2760SDarwin Rambo smh_close(fd); 1734e1ef150SLinus Walleij return -1; 174261d2760SDarwin Rambo } 175261d2760SDarwin Rambo 176261d2760SDarwin Rambo /* Check that the file will fit in the supplied buffer */ 177261d2760SDarwin Rambo if (ret > avail) { 1784e1ef150SLinus Walleij printf("%s: ERROR ret %ld, avail %u\n", __func__, ret, 179261d2760SDarwin Rambo avail); 180261d2760SDarwin Rambo smh_close(fd); 1814e1ef150SLinus Walleij return -1; 182261d2760SDarwin Rambo } 183261d2760SDarwin Rambo 184261d2760SDarwin Rambo len = ret; 185261d2760SDarwin Rambo 186261d2760SDarwin Rambo /* Read the file into the buffer */ 187261d2760SDarwin Rambo ret = smh_read(fd, memp, len); 188261d2760SDarwin Rambo if (ret == 0) { 189261d2760SDarwin Rambo /* Print successful load information if requested */ 190261d2760SDarwin Rambo if (verbose) { 191261d2760SDarwin Rambo printf("\n%s\n", fname); 192261d2760SDarwin Rambo printf(" 0x%8p dest\n", memp); 1934e1ef150SLinus Walleij printf(" 0x%08lx size\n", len); 194261d2760SDarwin Rambo printf(" 0x%08x avail\n", avail); 195261d2760SDarwin Rambo } 196261d2760SDarwin Rambo } 197261d2760SDarwin Rambo 198261d2760SDarwin Rambo /* Close the file */ 199261d2760SDarwin Rambo smh_close(fd); 200261d2760SDarwin Rambo 201261d2760SDarwin Rambo return ret; 202261d2760SDarwin Rambo } 203261d2760SDarwin Rambo 204261d2760SDarwin Rambo /* 205261d2760SDarwin Rambo * Get the file length from the filename 206261d2760SDarwin Rambo */ 2074e1ef150SLinus Walleij long smh_len(const char *fname) 208261d2760SDarwin Rambo { 2094e1ef150SLinus Walleij long ret; 2104e1ef150SLinus Walleij long fd; 2114e1ef150SLinus Walleij long len; 212261d2760SDarwin Rambo 213261d2760SDarwin Rambo debug("%s: file \'%s\'\n", __func__, fname); 214261d2760SDarwin Rambo 215261d2760SDarwin Rambo /* Open the file */ 216261d2760SDarwin Rambo fd = smh_open(fname, "rb"); 2174e1ef150SLinus Walleij if (fd < 0) 218261d2760SDarwin Rambo return fd; 219261d2760SDarwin Rambo 220261d2760SDarwin Rambo /* Get the file length */ 221261d2760SDarwin Rambo len = smh_len_fd(fd); 2224e1ef150SLinus Walleij if (len < 0) { 2234e1ef150SLinus Walleij smh_close(fd); 2244e1ef150SLinus Walleij return len; 2254e1ef150SLinus Walleij } 226261d2760SDarwin Rambo 227261d2760SDarwin Rambo /* Close the file */ 228261d2760SDarwin Rambo ret = smh_close(fd); 2294e1ef150SLinus Walleij if (ret < 0) 230261d2760SDarwin Rambo return ret; 231261d2760SDarwin Rambo 2324e1ef150SLinus Walleij debug("%s: returning len %ld\n", __func__, len); 233261d2760SDarwin Rambo 234261d2760SDarwin Rambo /* Return the file length (or -1 error indication) */ 235261d2760SDarwin Rambo return len; 236261d2760SDarwin Rambo } 237