1 /*
2 * Copyright (c) 2015 Carlos Pizano-Uribe <cpu@chromium.org>
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8
9
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdint.h>
13 #include <stdlib.h>
14
15 #include <lib/tftp.h>
16 #include <lib/cksum.h>
17 #include <lib/elf.h>
18
19 #include <kernel/thread.h>
20
21 #include <lk/console_cmd.h>
22
23 #if defined(SDRAM_BASE)
24 #define DOWNLOAD_BASE ((unsigned char*)SDRAM_BASE)
25 #else
26 #define DOWNLOAD_BASE ((unsigned char*)0)
27 #endif
28
29 #define FNAME_SIZE 64
30 #define DOWNLOAD_SLOT_SIZE (512 * 1024)
31
32 typedef enum {
33 DOWNLOAD_ANY,
34 DOWNLOAD_ELF,
35 } download_type;
36
37 typedef struct {
38 unsigned char *start;
39 unsigned char *end;
40 unsigned char *max;
41 char name[FNAME_SIZE];
42 download_type type;
43 } download_t;
44
make_download(const char * name)45 static download_t *make_download(const char *name) {
46 download_t *d = malloc(sizeof(download_t));
47 memset(d, 0, sizeof(download_t));
48 strncpy(d->name, name, FNAME_SIZE);
49 return d;
50 }
51
set_ram_zone(download_t * d,unsigned char * spot,int slot)52 static void set_ram_zone(download_t *d, unsigned char *spot, int slot) {
53 d->start = spot + (DOWNLOAD_SLOT_SIZE * slot);
54 d->end = d->start;
55 d->max = d->end + DOWNLOAD_SLOT_SIZE;
56 memset(spot, 0, DOWNLOAD_SLOT_SIZE);
57 }
58
output_result(const download_t * download)59 static size_t output_result(const download_t *download) {
60 size_t len = download->end - download->start;
61 unsigned long crc = crc32(0, download->start, len);
62 printf("[%s] done, start at: %p - %zu bytes, crc32 = %lu\n",
63 download->name, download->start, len, crc);
64 return len;
65 }
66
run_elf(void * entry_point)67 static int run_elf(void *entry_point) {
68 void (*elf_start)(void) = (void *)entry_point;
69 printf("elf (%p) running ...\n", entry_point);
70 thread_sleep(10);
71 elf_start();
72 printf("elf (%p) finished\n", entry_point);
73 return 0;
74 }
75
process_elf_blob(const void * start,size_t len)76 static void process_elf_blob(const void *start, size_t len) {
77 void *entrypt;
78 elf_handle_t elf;
79
80 status_t st = elf_open_handle_memory(&elf, start, len);
81 if (st < 0) {
82 printf("unable to open elf handle\n");
83 return;
84 }
85
86 st = elf_load(&elf);
87 if (st < 0) {
88 printf("elf processing failed, status : %d\n", st);
89 goto exit;
90 }
91
92 entrypt = (void *)elf.entry;
93 if (entrypt < start || entrypt >= (void *)((char *)start + len)) {
94 printf("out of bounds entrypoint for elf : %p\n", entrypt);
95 goto exit;
96 }
97
98 printf("elf looks good\n");
99 thread_resume(thread_create("elf_runner", &run_elf, entrypt,
100 DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
101 exit:
102 elf_close_handle(&elf);
103 }
104
tftp_callback(void * data,size_t len,void * arg)105 static int tftp_callback(void *data, size_t len, void *arg) {
106 download_t *download = arg;
107 size_t final_len;
108
109 if (!data) {
110 final_len = output_result(download);
111 if (download->type == DOWNLOAD_ELF) {
112 process_elf_blob(download->start, final_len);
113 }
114
115 download->end = download->start;
116 return 0;
117 }
118
119 if ((download->end + len) > download->max) {
120 printf("transfer too big, aborting\n");
121 return -1;
122 }
123 if (len) {
124 memcpy(download->end, data, len);
125 download->end += len;
126 }
127 return 0;
128 }
129
loader(int argc,const console_cmd_args * argv)130 static int loader(int argc, const console_cmd_args *argv) {
131 static int any_slot = 0;
132 static int elf_slot = 1;
133
134 download_t *download;
135 int slot;
136
137 if (!DOWNLOAD_BASE) {
138 printf("loader not available. it needs sdram\n");
139 return 0;
140 }
141
142 if (argc < 3) {
143 usage:
144 printf("load any [filename] <slot>\n"
145 "load elf [filename] <slot>\n"
146 "protocol is tftp and <slot> is optional\n");
147 return 0;
148 }
149
150 download = make_download(argv[2].str);
151
152 if (strcmp(argv[1].str, "any") == 0) {
153 download->type = DOWNLOAD_ANY;
154 slot = any_slot;
155 any_slot += 2;
156 } else if (strcmp(argv[1].str, "elf") == 0) {
157 download->type = DOWNLOAD_ELF;
158 slot = elf_slot;
159 elf_slot += 2;
160 } else {
161 goto usage;
162 }
163
164 if (argc == 4) {
165 slot = argv[3].i;
166 }
167
168 set_ram_zone(download, DOWNLOAD_BASE, slot);
169 tftp_set_write_client(download->name, &tftp_callback, download);
170 printf("ready for %s over tftp (at %p)\n", argv[2].str, download->start);
171 return 0;
172 }
173
174 STATIC_COMMAND_START
175 STATIC_COMMAND("load", "download and run via tftp", &loader)
176 STATIC_COMMAND_END(loader);
177
178