d302d955a65c8f01f95196d7aa10f9ff297fd359
[osmocom-bb.git] / src / host / osmocon / osmoload.c
1 /* control utility for the Calypso bootloader */
2
3 /* (C) 2010 by Ingo Albrecht <prom@berlin.ccc.de>
4  *
5  * All Rights Reserved
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  */
22
23 #include <errno.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <getopt.h>
29
30 #include <arpa/inet.h>
31
32 #include <sys/socket.h>
33 #include <sys/un.h>
34
35 #include <osmocore/msgb.h>
36 #include <osmocore/select.h>
37
38 #include <loader/protocol.h>
39
40 #define MSGB_MAX 256
41
42 #define DEFAULT_SOCKET "/tmp/osmocom_loader"
43
44 static struct bsc_fd connection;
45
46 static struct {
47         unsigned char quit;
48 } osmoload;
49
50 static int usage(const char *name)
51 {
52         printf("\nUsage: %s [ -v | -h ] [ -m {c123,c155} ] [ -l /tmp/osmocom_loader ] COMMAND\n", name);
53         exit(2);
54 }
55
56 static int version(const char *name)
57 {
58         //printf("\n%s version %s\n", name, VERSION);
59         exit(2);
60 }
61
62 static void hexdump(const uint8_t *data, unsigned int len)
63 {
64         const uint8_t *bufptr = data;
65         int n;
66
67         for (n=0; n < len; n++, bufptr++)
68                 printf("%02x ", *bufptr);
69         printf("\n");
70 }
71
72 static void
73 loader_send_request(struct msgb *msg) {
74         int rc;
75         u_int16_t len = htons(msg->len);
76
77         printf("Sending %d bytes ", msg->len);
78         hexdump(msg->data, msg->len);
79
80         rc = write(connection.fd, &len, sizeof(len));
81         if(rc != sizeof(len)) {
82                 fprintf(stderr, "Error writing.\n");
83                 exit(2);
84         }
85
86         rc = write(connection.fd, msg->data, msg->len);
87         if(rc != msg->len) {
88                 fprintf(stderr, "Error writing.\n");
89                 exit(2);
90         }
91 }
92
93 static void
94 loader_handle_reply(struct msgb *msg) {
95         uint8_t cmd = msgb_get_u8(msg);
96
97         uint8_t length;
98         uint32_t address;
99
100         switch(cmd) {
101         case LOADER_PING:
102                 printf("Received pong.\n");
103                 osmoload.quit = 1;
104                 break;
105         case LOADER_RESET:
106                 printf("Reset confirmed.\n");
107                 osmoload.quit = 1;
108                 break;
109         case LOADER_POWEROFF:
110                 printf("Poweroff confirmed.\n");
111                 osmoload.quit = 1;
112                 break;
113         case LOADER_ENTER_ROM_LOADER:
114                 printf("Jump to ROM loader confirmed.\n");
115                 osmoload.quit = 1;
116                 break;
117         case LOADER_ENTER_FLASH_LOADER:
118                 printf("Jump to flash loader confirmed.\n");
119                 osmoload.quit = 1;
120                 break;
121         case LOADER_MEM_READ:
122                 length = msgb_get_u8(msg);
123                 address = msgb_get_u32(msg);
124                 printf("Received memory dump of %d bytes at 0x%x:\n", length, address);
125                 hexdump(msgb_get(msg, length), length);
126                 osmoload.quit = 1;
127                 break;
128         case LOADER_MEM_WRITE:
129                 length = msgb_get_u8(msg);
130                 address = msgb_get_u32(msg);
131                 printf("Confirmed memory write of %d bytes at 0x%x.\n", length, address);
132                 osmoload.quit = 1;
133                 break;
134         default:
135                 printf("Received unknown reply for command %d:\n");
136                 hexdump(msg->data, msg->len);
137                 osmoload.quit = 1;
138                 break;
139         }
140 }
141
142 static int
143 loader_read_cb(struct bsc_fd *fd, unsigned int flags) {
144         struct msgb *msg;
145         u_int16_t len;
146         int rc;
147
148         msg = msgb_alloc(MSGB_MAX, "loader");
149         if (!msg) {
150                 fprintf(stderr, "Failed to allocate msg.\n");
151                 return -1;
152         }
153
154         rc = read(fd->fd, &len, sizeof(len));
155         if (rc < sizeof(len)) {
156                 fprintf(stderr, "Short read. Error.\n");
157                 exit(2);
158         }
159
160         if (ntohs(len) > MSGB_MAX) {
161                 fprintf(stderr, "Length is too big: %u\n", ntohs(len));
162                 msgb_free(msg);
163                 return -1;
164         }
165
166         /* blocking read for the poor... we can starve in here... */
167         msg->l2h = msgb_put(msg, ntohs(len));
168         rc = read(fd->fd, msg->l2h, msgb_l2len(msg));
169         if (rc != msgb_l2len(msg)) {
170                 fprintf(stderr, "Can not read data: rc: %d errno: %d\n", rc, errno);
171                 msgb_free(msg);
172                 return -1;
173         }
174
175         loader_handle_reply(msg);
176
177         msgb_free(msg);
178
179         return 0;
180 }
181
182 static void
183 loader_connect(const char *socket_path) {
184         int rc;
185         struct sockaddr_un local;
186         struct bsc_fd *conn = &connection;
187
188         local.sun_family = AF_UNIX;
189         strncpy(local.sun_path, socket_path, sizeof(local.sun_path));
190         local.sun_path[sizeof(local.sun_path) - 1] = '\0';
191
192         conn->fd = socket(AF_UNIX, SOCK_STREAM, 0);
193         if (conn->fd < 0) {
194                 fprintf(stderr, "Failed to create unix domain socket.\n");
195                 exit(1);
196         }
197
198         rc = connect(conn->fd, (struct sockaddr *) &local,
199                                  sizeof(local.sun_family) + strlen(local.sun_path));
200         if (rc < 0) {
201                 fprintf(stderr, "Failed to connect to '%s'.\n", local.sun_path);
202                 exit(1);
203         }
204
205         conn->when = BSC_FD_READ;
206         conn->cb = loader_read_cb;
207         conn->data = NULL;
208
209         if (bsc_register_fd(conn) != 0) {
210                 fprintf(stderr, "Failed to register fd.\n");
211                 exit(1);
212         }
213 }
214
215 static void
216 loader_send_simple(uint8_t command) {
217         struct msgb *msg = msgb_alloc(MSGB_MAX, "loader");
218         msgb_put_u8(msg, command);
219         loader_send_request(msg);
220         msgb_free(msg);
221 }
222
223 static void
224 loader_send_memread(uint8_t length, uint32_t address) {
225         struct msgb *msg = msgb_alloc(MSGB_MAX, "loader");
226         msgb_put_u8(msg, LOADER_MEM_READ);
227         msgb_put_u8(msg, 128);
228         msgb_put_u32(msg, 0x00810000);
229         loader_send_request(msg);
230         msgb_free(msg);
231 }
232
233 static void
234 loader_send_memwrite(uint8_t length, uint32_t address, void *data) {
235         struct msgb *msg = msgb_alloc(MSGB_MAX, "loader");
236         msgb_put_u8(msg, LOADER_MEM_WRITE);
237         msgb_put_u8(msg, length);
238         msgb_put_u32(msg, address);
239         memcpy(msgb_put(msg, 128), data, length);
240         loader_send_request(msg);
241         msgb_free(msg);
242 }
243
244 static void
245 loader_command(char *name, int cmdc, char **cmdv) {
246         if(!cmdc) {
247                 usage(name);
248         }
249
250         struct msgb *msg;
251         char *cmd = cmdv[0];
252
253         char buf[256];
254         memset(buf, 23, sizeof(buf));
255
256         printf("Command %s\n", cmd);
257
258         if(!strcmp(cmd, "ping")) {
259                 loader_send_simple(LOADER_PING);
260         } else if(!strcmp(cmd, "memread")) {
261                 loader_send_memread(128, 0x810000);
262         } else if(!strcmp(cmd, "memwrite")) {
263                 loader_send_memwrite(128, 0x810000, buf);
264         } else if(!strcmp(cmd, "off")) {
265                 loader_send_simple(LOADER_POWEROFF);
266         } else if(!strcmp(cmd, "reset")) {
267                 loader_send_simple(LOADER_RESET);
268         } else if(!strcmp(cmd, "romload")) {
269                 loader_send_simple(LOADER_ENTER_ROM_LOADER);
270         } else if(!strcmp(cmd, "flashload")) {
271                 loader_send_simple(LOADER_ENTER_FLASH_LOADER);
272         } else {
273                 printf("Unknown command '%s'\n", cmd);
274                 usage(name);
275         }
276 }
277
278 int
279 main(int argc, char **argv) {
280         int opt;
281         char *loader_un_path = "/tmp/osmocom_loader";
282
283         while((opt = getopt(argc, argv, "hl:m:v")) != -1) {
284                 switch(opt) {
285                 case 'l':
286                         loader_un_path = optarg;
287                         break;
288                 case 'm':
289                         puts("model selection not implemented");
290                         exit(2);
291                         break;
292                 case 'v':
293                         version(argv[0]);
294                         break;
295                 case 'h':
296                 default:
297                         usage(argv[0]);
298                         break;
299                 }
300         }
301
302         osmoload.quit = 0;
303
304         loader_connect(loader_un_path);
305
306         loader_command(argv[0], argc - optind, argv + optind);
307
308         while(!osmoload.quit) {
309                 bsc_select_main(0);
310         }
311
312         return 0;
313 }