uboot/common/spl/spl_ymodem.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2000-2004
   4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   5 *
   6 * (C) Copyright 2011
   7 * Texas Instruments, <www.ti.com>
   8 *
   9 * Matt Porter <mporter@ti.com>
  10 */
  11#include <common.h>
  12#include <gzip.h>
  13#include <image.h>
  14#include <log.h>
  15#include <spl.h>
  16#include <xyzModem.h>
  17#include <asm/u-boot.h>
  18#include <linux/libfdt.h>
  19
  20#define BUF_SIZE 1024
  21
  22/*
  23 * Information required to load image using ymodem.
  24 *
  25 * @image_read: Now of bytes read from the image.
  26 * @buf: pointer to the previous read block.
  27 */
  28struct ymodem_fit_info {
  29        int image_read;
  30        char *buf;
  31};
  32
  33static int getcymodem(void) {
  34        if (tstc())
  35                return (getchar());
  36        return -1;
  37}
  38
  39static ulong ymodem_read_fit(struct spl_load_info *load, ulong offset,
  40                             ulong size, void *addr)
  41{
  42        int res, err, buf_offset;
  43        struct ymodem_fit_info *info = load->priv;
  44        char *buf = info->buf;
  45        ulong copy_size = size;
  46
  47        while (info->image_read < offset) {
  48                res = xyzModem_stream_read(buf, BUF_SIZE, &err);
  49                if (res <= 0)
  50                        break;
  51
  52                info->image_read += res;
  53        }
  54
  55        if (info->image_read > offset) {
  56                res = info->image_read - offset;
  57                if (info->image_read % BUF_SIZE)
  58                        buf_offset = (info->image_read % BUF_SIZE);
  59                else
  60                        buf_offset = BUF_SIZE;
  61
  62                if (res > copy_size) {
  63                        memcpy(addr, &buf[buf_offset - res], copy_size);
  64                        goto done;
  65                }
  66                memcpy(addr, &buf[buf_offset - res], res);
  67                addr = addr + res;
  68                copy_size -= res;
  69        }
  70
  71        while (info->image_read < offset + size) {
  72                res = xyzModem_stream_read(buf, BUF_SIZE, &err);
  73                if (res <= 0)
  74                        break;
  75
  76                info->image_read += res;
  77                if (res > copy_size) {
  78                        memcpy(addr, buf, copy_size);
  79                        goto done;
  80                }
  81                memcpy(addr, buf, res);
  82                addr += res;
  83                copy_size -= res;
  84        }
  85
  86done:
  87        return size;
  88}
  89
  90int spl_ymodem_load_image(struct spl_image_info *spl_image,
  91                          struct spl_boot_device *bootdev)
  92{
  93        ulong size = 0;
  94        int err;
  95        int res;
  96        int ret;
  97        connection_info_t info;
  98        char buf[BUF_SIZE];
  99        struct image_header *ih = NULL;
 100        ulong addr = 0;
 101
 102        info.mode = xyzModem_ymodem;
 103        ret = xyzModem_stream_open(&info, &err);
 104        if (ret) {
 105                printf("spl: ymodem err - %s\n", xyzModem_error(err));
 106                return ret;
 107        }
 108
 109        res = xyzModem_stream_read(buf, BUF_SIZE, &err);
 110        if (res <= 0)
 111                goto end_stream;
 112
 113        if (IS_ENABLED(CONFIG_SPL_LOAD_FIT_FULL) &&
 114            image_get_magic((struct image_header *)buf) == FDT_MAGIC) {
 115                addr = CONFIG_SYS_LOAD_ADDR;
 116                ih = (struct image_header *)addr;
 117
 118                memcpy((void *)addr, buf, res);
 119                size += res;
 120                addr += res;
 121
 122                while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0) {
 123                        memcpy((void *)addr, buf, res);
 124                        size += res;
 125                        addr += res;
 126                }
 127
 128                ret = spl_parse_image_header(spl_image, bootdev, ih);
 129                if (ret)
 130                        return ret;
 131        } else if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
 132            image_get_magic((struct image_header *)buf) == FDT_MAGIC) {
 133                struct spl_load_info load;
 134                struct ymodem_fit_info info;
 135
 136                debug("Found FIT\n");
 137                load.dev = NULL;
 138                load.priv = (void *)&info;
 139                load.filename = NULL;
 140                load.bl_len = 1;
 141                info.buf = buf;
 142                info.image_read = BUF_SIZE;
 143                load.read = ymodem_read_fit;
 144                ret = spl_load_simple_fit(spl_image, &load, 0, (void *)buf);
 145                size = info.image_read;
 146
 147                while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0)
 148                        size += res;
 149        } else {
 150                ih = (struct image_header *)buf;
 151                ret = spl_parse_image_header(spl_image, bootdev, ih);
 152                if (ret)
 153                        goto end_stream;
 154#ifdef CONFIG_SPL_GZIP
 155                if (ih->ih_comp == IH_COMP_GZIP)
 156                        addr = CONFIG_SYS_LOAD_ADDR;
 157                else
 158#endif
 159                        addr = spl_image->load_addr;
 160                memcpy((void *)addr, buf, res);
 161                ih = (struct image_header *)addr;
 162                size += res;
 163                addr += res;
 164
 165                while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0) {
 166                        memcpy((void *)addr, buf, res);
 167                        size += res;
 168                        addr += res;
 169                }
 170        }
 171
 172end_stream:
 173        xyzModem_stream_close(&err);
 174        xyzModem_stream_terminate(false, &getcymodem);
 175
 176        printf("Loaded %lu bytes\n", size);
 177
 178#ifdef CONFIG_SPL_GZIP
 179        if (!(IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
 180              image_get_magic((struct image_header *)buf) == FDT_MAGIC) &&
 181            (ih->ih_comp == IH_COMP_GZIP)) {
 182                if (gunzip((void *)(spl_image->load_addr + sizeof(*ih)),
 183                           CONFIG_SYS_BOOTM_LEN,
 184                           (void *)(CONFIG_SYS_LOAD_ADDR + sizeof(*ih)),
 185                           &size)) {
 186                        puts("Uncompressing error\n");
 187                        return -EIO;
 188                }
 189        }
 190#endif
 191
 192        return ret;
 193}
 194SPL_LOAD_IMAGE_METHOD("UART", 0, BOOT_DEVICE_UART, spl_ymodem_load_image);
 195