blob: c363ee15588fcf40a4fcbe7800da81844f6d8fb5 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (c) 2015 Carlos Pizano-Uribe <cpu@chromium.org>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24
25#include <stdio.h>
26#include <string.h>
27#include <stdint.h>
28#include <stdlib.h>
29
30#include <lib/tftp.h>
31#include <lib/cksum.h>
32#include <lib/elf.h>
33
34#include <kernel/thread.h>
35
36#if defined(WITH_LIB_CONSOLE)
37#include <lib/console.h>
38#else
39#error "loader app needs a console"
40#endif
41
42#if defined(SDRAM_BASE)
43#define DOWNLOAD_BASE ((void*)SDRAM_BASE)
44#else
45#define DOWNLOAD_BASE ((void*)0)
46#endif
47
48#define FNAME_SIZE 64
49#define DOWNLOAD_SLOT_SIZE (512 * 1024)
50
51typedef enum {
52 DOWNLOAD_ANY,
53 DOWNLOAD_ELF,
54} download_type;
55
56typedef struct {
57 unsigned char* start;
58 unsigned char* end;
59 unsigned char* max;
60 char name[FNAME_SIZE];
61 download_type type;
62} download_t;
63
64static download_t* make_download(const char* name)
65{
66 download_t* d = malloc(sizeof(download_t));
67 memset(d, 0, sizeof(download_t));
68 strncpy(d->name, name, FNAME_SIZE);
69 return d;
70}
71
72static void set_ram_zone(download_t* d, int slot) {
73 d->start = DOWNLOAD_BASE + (DOWNLOAD_SLOT_SIZE * slot);
74 d->end = d->start;
75 d->max = d->end + DOWNLOAD_SLOT_SIZE;
76 memset(d->start, 0, DOWNLOAD_SLOT_SIZE);
77}
78
79static size_t output_result(const download_t* download)
80{
81 size_t len = download->end - download->start;
82 unsigned long crc = crc32(0, download->start, len);
83 printf("[%s] done, start at: %p - %zu bytes, crc32 = %lu\n",
84 download->name, download->start, len, crc);
85 return len;
86}
87
88static int run_elf(void* entry_point)
89{
90 void (*elf_start)(void) = (void*)entry_point;
91 printf("elf (%p) running ...\n", entry_point);
92 thread_sleep(10);
93 elf_start();
94 printf("elf (%p) finished\n", entry_point);
95 return 0;
96}
97
98static void process_elf_blob(const void* start, size_t len)
99{
100 void* entrypt;
101 elf_handle_t elf;
102
103 status_t st = elf_open_handle_memory(&elf, start, len);
104 if (st < 0) {
105 printf("unable to open elf handle\n");
106 return;
107 }
108
109 st = elf_load(&elf);
110 if (st < 0) {
111 printf("elf processing failed, status : %d\n", st);
112 goto exit;
113 }
114
115 entrypt = (void*)elf.entry;
116 if (entrypt < start || entrypt >= (void*)((char*)start + len)) {
117 printf("out of bounds entrypoint for elf : %p\n", entrypt);
118 goto exit;
119 }
120
121 printf("elf looks good\n");
122 thread_resume(thread_create("elf_runner", &run_elf, entrypt,
123 DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
124exit:
125 elf_close_handle(&elf);
126}
127
128int tftp_callback(void* data, size_t len, void* arg)
129{
130 download_t* download = arg;
131 size_t final_len;
132
133 if (!data) {
134 final_len = output_result(download);
135 if (download->type == DOWNLOAD_ELF) {
136 process_elf_blob(download->start, final_len);
137 }
138
139 download->end = download->start;
140 return 0;
141 }
142
143 if ((download->end + len) > download->max) {
144 printf("transfer too big, aborting\n");
145 return -1;
146 }
147 if (len) {
148 memcpy(download->end, data, len);
149 download->end += len;
150 }
151 return 0;
152}
153
154static int loader(int argc, const cmd_args *argv)
155{
156 static int any_slot = 0;
157 static int elf_slot = 1;
158
159 download_t* download;
160 int slot;
161
162 if (!DOWNLOAD_BASE) {
163 printf("loader not available. it needs sdram\n");
164 return 0;
165 }
166
167 if (argc < 3) {
168usage:
169 printf("load any [filename] <slot>\n"
170 "load elf [filename] <slot>\n"
171 "protocol is tftp and <slot> is optional\n");
172 return 0;
173 }
174
175 download = make_download(argv[2].str);
176
177 if (strcmp(argv[1].str, "any") == 0) {
178 download->type = DOWNLOAD_ANY;
179 slot = any_slot;
180 any_slot += 2;
181 } else if (strcmp(argv[1].str, "elf") == 0) {
182 download->type = DOWNLOAD_ELF;
183 slot = elf_slot;
184 elf_slot += 2;
185 } else {
186 goto usage;
187 }
188
189 if (argc == 4) {
190 slot = argv[3].i;
191 }
192
193 set_ram_zone(download, slot);
194 tftp_set_write_client(download->name, &tftp_callback, download);
195 printf("ready for %s over tftp (at %p)\n", argv[2].str, download->start);
196 return 0;
197}
198
199STATIC_COMMAND_START
200STATIC_COMMAND("load", "download and run via tftp", &loader)
201STATIC_COMMAND_END(loader);
202