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
  46        while (info->image_read < offset) {
  47                res = xyzModem_stream_read(buf, BUF_SIZE, &err);
  48                if (res <= 0)
  49                        break;
  50
  51                info->image_read += res;
  52        }
  53
  54        if (info->image_read > offset) {
  55                res = info->image_read - offset;
  56                if (info->image_read % BUF_SIZE)
  57                        buf_offset = (info->image_read % BUF_SIZE);
  58                else
  59                        buf_offset = BUF_SIZE;
  60                memcpy(addr, &buf[buf_offset - res], res);
  61                addr = addr + res;
  62        }
  63
  64        while (info->image_read < offset + size) {
  65                res = xyzModem_stream_read(buf, BUF_SIZE, &err);
  66                if (res <= 0)
  67                        break;
  68
  69                memcpy(addr, buf, res);
  70                info->image_read += res;
  71                addr += res;
  72        }
  73
  74        return size;
  75}
  76
  77int spl_ymodem_load_image(struct spl_image_info *spl_image,
  78                          struct spl_boot_device *bootdev)
  79{
  80        ulong size = 0;
  81        int err;
  82        int res;
  83        int ret;
  84        connection_info_t info;
  85        char buf[BUF_SIZE];
  86        struct image_header *ih = NULL;
  87        ulong addr = 0;
  88
  89        info.mode = xyzModem_ymodem;
  90        ret = xyzModem_stream_open(&info, &err);
  91        if (ret) {
  92                printf("spl: ymodem err - %s\n", xyzModem_error(err));
  93                return ret;
  94        }
  95
  96        res = xyzModem_stream_read(buf, BUF_SIZE, &err);
  97        if (res <= 0)
  98                goto end_stream;
  99
 100        if (IS_ENABLED(CONFIG_SPL_LOAD_FIT_FULL) &&
 101            image_get_magic((struct image_header *)buf) == FDT_MAGIC) {
 102                addr = CONFIG_SYS_LOAD_ADDR;
 103                ih = (struct image_header *)addr;
 104
 105                memcpy((void *)addr, buf, res);
 106                size += res;
 107                addr += res;
 108
 109                while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0) {
 110                        memcpy((void *)addr, buf, res);
 111                        size += res;
 112                        addr += res;
 113                }
 114
 115                ret = spl_parse_image_header(spl_image, ih);
 116                if (ret)
 117                        return ret;
 118        } else if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
 119            image_get_magic((struct image_header *)buf) == FDT_MAGIC) {
 120                struct spl_load_info load;
 121                struct ymodem_fit_info info;
 122
 123                debug("Found FIT\n");
 124                load.dev = NULL;
 125                load.priv = (void *)&info;
 126                load.filename = NULL;
 127                load.bl_len = 1;
 128                info.buf = buf;
 129                info.image_read = BUF_SIZE;
 130                load.read = ymodem_read_fit;
 131                ret = spl_load_simple_fit(spl_image, &load, 0, (void *)buf);
 132                size = info.image_read;
 133
 134                while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0)
 135                        size += res;
 136        } else {
 137                ih = (struct image_header *)buf;
 138                ret = spl_parse_image_header(spl_image, ih);
 139                if (ret)
 140                        goto end_stream;
 141#ifdef CONFIG_SPL_GZIP
 142                if (ih->ih_comp == IH_COMP_GZIP)
 143                        addr = CONFIG_SYS_LOAD_ADDR;
 144                else
 145#endif
 146                        addr = spl_image->load_addr;
 147                memcpy((void *)addr, buf, res);
 148                ih = (struct image_header *)addr;
 149                size += res;
 150                addr += res;
 151
 152                while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0) {
 153                        memcpy((void *)addr, buf, res);
 154                        size += res;
 155                        addr += res;
 156                }
 157        }
 158
 159end_stream:
 160        xyzModem_stream_close(&err);
 161        xyzModem_stream_terminate(false, &getcymodem);
 162
 163        printf("Loaded %lu bytes\n", size);
 164
 165#ifdef CONFIG_SPL_GZIP
 166        if (!(IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
 167              image_get_magic((struct image_header *)buf) == FDT_MAGIC) &&
 168            (ih->ih_comp == IH_COMP_GZIP)) {
 169                if (gunzip((void *)(spl_image->load_addr + sizeof(*ih)),
 170                           CONFIG_SYS_BOOTM_LEN,
 171                           (void *)(CONFIG_SYS_LOAD_ADDR + sizeof(*ih)),
 172                           &size)) {
 173                        puts("Uncompressing error\n");
 174                        return -EIO;
 175                }
 176        }
 177#endif
 178
 179        return ret;
 180}
 181SPL_LOAD_IMAGE_METHOD("UART", 0, BOOT_DEVICE_UART, spl_ymodem_load_image);
 182