diff options
| -rw-r--r-- | ao-tools/ao-stmload/Makefile.am | 9 | ||||
| -rw-r--r-- | ao-tools/ao-stmload/ao-elf.c | 303 | ||||
| -rw-r--r-- | ao-tools/ao-stmload/ao-elf.h | 24 | ||||
| -rw-r--r-- | ao-tools/ao-stmload/ao-selfload.c | 118 | ||||
| -rw-r--r-- | ao-tools/ao-stmload/ao-stmload.c | 653 | ||||
| -rw-r--r-- | ao-tools/ao-stmload/ao-stmload.h | 45 | 
6 files changed, 750 insertions, 402 deletions
| diff --git a/ao-tools/ao-stmload/Makefile.am b/ao-tools/ao-stmload/Makefile.am index 5aea7db4..4eaf699c 100644 --- a/ao-tools/ao-stmload/Makefile.am +++ b/ao-tools/ao-stmload/Makefile.am @@ -4,11 +4,14 @@ bin_PROGRAMS=ao-stmload  LIBSTLINKDIR=/local/src/stlink -AM_CFLAGS=$(LIBSTLINK_CFLAGS) $(LIBUSB_CFLAGS) -I../lib +AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBSTLINK_CFLAGS) $(LIBUSB_CFLAGS) +AO_STMLOAD_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a -ao_stmload_LDADD=$(LIBSTLINK_LIBS) $(LIBUSB_LIBS) -lelf +ao_stmload_DEPENDENCIES = $(AO_STMLOAD_LIBS) -ao_stmload_SOURCES=ao-stmload.c +ao_stmload_LDADD=$(AO_STMLOAD_LIBS) $(LIBSTLINK_LIBS) $(LIBUSB_LIBS) -lelf + +ao_stmload_SOURCES=ao-stmload.c ao-elf.c ao-stmload.h ao-selfload.c  man_MANS = ao-stmload.1 diff --git a/ao-tools/ao-stmload/ao-elf.c b/ao-tools/ao-stmload/ao-elf.c new file mode 100644 index 00000000..dad8fb80 --- /dev/null +++ b/ao-tools/ao-stmload/ao-elf.c @@ -0,0 +1,303 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao-elf.h" +#include <err.h> +#include <gelf.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include "ccdbg.h" +#include "ao-stmload.h" + +/* + * Look through the Elf file for the AltOS symbols + * that can be adjusted before the image is written + * to the device + */ +static int +find_symbols (Elf *e) +{ +	Elf_Scn 	*scn; +	Elf_Data	*symbol_data = NULL; +	GElf_Shdr	shdr; +	GElf_Sym       	sym; +	int		i, symbol_count, s; +	int		required = 0; +	char		*symbol_name; +	char		*section_name; +	size_t		shstrndx; + +	if (elf_getshdrstrndx(e, &shstrndx) < 0) +		return 0; + +	/* +	 * Find the symbols +	 */ + +	scn = NULL; +	while ((scn = elf_nextscn(e, scn)) != NULL) { + +		if (gelf_getshdr(scn, &shdr) != &shdr) +			return 0; + +		if (shdr.sh_type == SHT_SYMTAB) { +			symbol_data = elf_getdata(scn, NULL); +			symbol_count = shdr.sh_size / shdr.sh_entsize; +			break; +		} +	} + +	if (!symbol_data) +		return 0; + +	for (i = 0; i < symbol_count; i++) { +		gelf_getsym(symbol_data, i, &sym); + +		symbol_name = elf_strptr(e, shdr.sh_link, sym.st_name); + +		for (s = 0; s < ao_num_symbols; s++) +			if (!strcmp (ao_symbols[s].name, symbol_name)) { +				int	t; +				ao_symbols[s].addr = sym.st_value; +				if (ao_symbols[s].required) +					++required; +			} +	} + +	return required >= ao_num_required_symbols; +} + +uint32_t round4(uint32_t a) { +	return (a + 3) & ~3; +} + +struct hex_image * +new_load (uint32_t addr, uint32_t len) +{ +	struct hex_image *new; + +	len = round4(len); +	new = calloc (1, sizeof (struct hex_image) + len); +	if (!new) +		abort(); + +	new->address = addr; +	new->length = len; +	return new; +} + +void +load_paste(struct hex_image *into, struct hex_image *from) +{ +	if (from->address < into->address || into->address + into->length < from->address + from->length) +		abort(); + +	memcpy(into->data + from->address - into->address, from->data, from->length); +} + +/* + * Make a new load structure large enough to hold the old one and + * the new data + */ +struct hex_image * +expand_load(struct hex_image *from, uint32_t address, uint32_t length) +{ +	struct hex_image	*new; + +	if (from) { +		uint32_t	from_last = from->address + from->length; +		uint32_t	last = address + length; + +		if (address > from->address) +			address = from->address; +		if (last < from_last) +			last = from_last; + +		length = last - address; + +		if (address == from->address && length == from->length) +			return from; +	} +	new = new_load(address, length); +	if (from) { +		load_paste(new, from); +		free (from); +	} +	return new; +} + +/* + * Create a new load structure with data from the existing one + * and the new data + */ +struct hex_image * +load_write(struct hex_image *from, uint32_t address, uint32_t length, void *data) +{ +	struct hex_image	*new; + +	new = expand_load(from, address, length); +	memcpy(new->data + address - new->address, data, length); +	return new; +} + +/* + * Construct a large in-memory block for all + * of the loaded sections of the program + */ +static struct hex_image * +get_load(Elf *e) +{ +	Elf_Scn 	*scn; +	size_t		shstrndx; +	GElf_Shdr	shdr; +	Elf_Data	*data; +	char		*got_name; +	size_t		nphdr; +	size_t		p; +	GElf_Phdr	phdr; +	GElf_Addr	p_paddr; +	GElf_Off	p_offset; +	GElf_Addr	sh_paddr; +	struct hex_image	*load = NULL; +	char		*section_name; +	size_t		nshdr; +	size_t		s; +	 +	if (elf_getshdrstrndx(e, &shstrndx) < 0) +		return 0; + +	if (elf_getphdrnum(e, &nphdr) < 0) +		return 0; + +	if (elf_getshdrnum(e, &nshdr) < 0) +		return 0; + +	/* +	 * As far as I can tell, all of the phdr sections should +	 * be flashed to memory +	 */ +	for (p = 0; p < nphdr; p++) { + +		/* Find this phdr */ +		gelf_getphdr(e, p, &phdr); + +		if (phdr.p_type != PT_LOAD) +			continue; + +		p_offset = phdr.p_offset; +		/* Get the associated file section */ + +#if 0 +		printf ("offset %08x vaddr %08x paddr %08x filesz %08x memsz %08x\n", +			(uint32_t) phdr.p_offset, +			(uint32_t) phdr.p_vaddr, +			(uint32_t) phdr.p_paddr, +			(uint32_t) phdr.p_filesz, +			(uint32_t) phdr.p_memsz); +#endif +		 +		for (s = 0; s < nshdr; s++) { +			scn = elf_getscn(e, s); + +			if (!scn) { +				printf ("getscn failed\n"); +				abort(); +			} +			if (gelf_getshdr(scn, &shdr) != &shdr) { +				printf ("gelf_getshdr failed\n"); +				abort(); +			} + +			section_name = elf_strptr(e, shstrndx, shdr.sh_name); + +			if (phdr.p_offset <= shdr.sh_offset && shdr.sh_offset < phdr.p_offset + phdr.p_filesz) { +					 +				if (shdr.sh_size == 0) +					continue; + +				sh_paddr = phdr.p_paddr + shdr.sh_offset - phdr.p_offset; + +				printf ("\tsize %08x rom %08x exec %08x %s\n", +					(uint32_t) shdr.sh_size, +					(uint32_t) sh_paddr, +					(uint32_t) shdr.sh_addr, +					section_name); + +				data = elf_getdata(scn, NULL); + +				/* Write the section data into the memory block */ +				load = load_write(load, sh_paddr, shdr.sh_size, data->d_buf); +			} +		} +	} +	return load; +} + +/* + * Open the specified ELF file and + * check for the symbols we need + */ + +struct hex_image * +ao_load_elf(char *name) +{ +	int		fd; +	Elf		*e; +	Elf_Scn 	*scn; +	Elf_Data	*symbol_data = NULL; +	GElf_Shdr	shdr; +	GElf_Sym       	sym; +	size_t		n, shstrndx, sz; +	int		i, symbol_count, s; +	int		required = 0; +	struct hex_image	*image; + +	if (elf_version(EV_CURRENT) == EV_NONE) +		return NULL; + +	fd = open(name, O_RDONLY, 0); + +	if (fd < 0) +		return NULL; + +	e = elf_begin(fd, ELF_C_READ, NULL); + +	if (!e) +		return NULL; + +	if (elf_kind(e) != ELF_K_ELF) +		return NULL; + +	if (elf_getshdrstrndx(e, &shstrndx) != 0) +		return NULL; + +	if (!find_symbols(e)) { +		fprintf (stderr, "Cannot find required symbols\n"); +		return NULL; +	} + +	image = get_load(e); +	if (!image) { +		fprintf (stderr, "Cannot create memory image from file\n"); +		return NULL; +	} + +	return image; +} diff --git a/ao-tools/ao-stmload/ao-elf.h b/ao-tools/ao-stmload/ao-elf.h new file mode 100644 index 00000000..4303d5ca --- /dev/null +++ b/ao-tools/ao-stmload/ao-elf.h @@ -0,0 +1,24 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_ELF_H_ +#define _AO_ELF_H_ + +struct hex_image * +ao_load_elf(char *name); + +#endif diff --git a/ao-tools/ao-stmload/ao-selfload.c b/ao-tools/ao-stmload/ao-selfload.c new file mode 100644 index 00000000..b3105b21 --- /dev/null +++ b/ao-tools/ao-stmload/ao-selfload.c @@ -0,0 +1,118 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <sysexits.h> +#include <unistd.h> +#include <string.h> +#include "cc.h" +#include "cc-usb.h" +#include "ccdbg.h" +#include "ao-stmload.h" + +void +ao_self_block_read(struct cc_usb *cc, uint32_t address, uint8_t block[256]) +{ +	int			byte; +	cc_usb_sync(cc); +	cc_usb_printf(cc, "R %x\n", address); +//	printf ("read %08x\n", address); +	for (byte = 0; byte < 0x100; byte++) { +		block[byte] = cc_usb_getchar(cc); +//		printf (" %02x", block[byte]); +//		if ((byte & 0xf) == 0xf) +//			printf ("\n"); +	} +} + +void +ao_self_block_write(struct cc_usb *cc, uint32_t address, uint8_t block[256]) +{ +	int			byte; +	cc_usb_sync(cc); +	cc_usb_printf(cc, "W %x\n", address); +//	printf ("write %08x\n", address); +	for (byte = 0; byte < 0x100; byte++) { +		cc_usb_printf(cc, "%c", block[byte]); +//		printf (" %02x", block[byte]); +//		if ((byte & 0xf) == 0xf) +//			printf ("\n"); +	} +} + +struct hex_image * +ao_self_read(struct cc_usb *cc, uint32_t address, uint32_t length) +{ +	struct hex_image	*image; +	int			pages; +	int			page; +	uint32_t		base = address & ~0xff; +	uint32_t		bound = (address + length + 0xff) & ~0xff; + +	image = calloc(sizeof (struct hex_image) + (bound - base), 1); +	image->address = base; +	image->length = bound - base; +	pages = image->length / 0x100; +	for (page = 0; page < pages; page++) +		ao_self_block_read(cc, image->address + page * 0x100, image->data + page * 0x100); +	return image; +} + +int +ao_self_write(struct cc_usb *cc, struct hex_image *image) +{ +	uint8_t		block[256]; +	uint8_t		check[256]; +	uint32_t	base, bound, length, address; +	uint32_t	pages; +	uint32_t	page; + +	base = image->address & ~0xff; +	bound = (image->address + image->length + 0xff) & ~0xff; + +	address = base; +	length = bound - base; + +	pages = length / 0x100; +	printf ("Write %08x %d pages: ", address, length/0x100); fflush(stdout); +	for (page = 0; page < pages; page++) { +		uint32_t	start, stop; +		address = base + page * 0x100; + +		if (address < image->address || address + 0x100 > image->address + image->length) { +			ao_self_block_read(cc, address, block); +		} +		start = address; +		stop = address + 0x100; +		if (start < image->address) +			start = image->address; +		if (stop > image->address + image->length) +			stop = image->address + image->length; +		memcpy(block + start - address, image->data + start - image->address, stop - start); +		ao_self_block_write(cc, address, block); +		ao_self_block_read(cc, address, check); +		if (memcmp(block, check, 0x100) != 0) { +			fprintf(stderr, "Block at 0x%08x doesn't match\n", address); +			return 0; +		} +		putchar('.'); fflush(stdout); +	} +	printf("done\n"); +	return 1; +} diff --git a/ao-tools/ao-stmload/ao-stmload.c b/ao-tools/ao-stmload/ao-stmload.c index 89b818da..b9bf4392 100644 --- a/ao-tools/ao-stmload/ao-stmload.c +++ b/ao-tools/ao-stmload/ao-stmload.c @@ -26,365 +26,107 @@  #include <getopt.h>  #include <string.h>  #include "stlink-common.h" +#include "ao-elf.h" +#include "ccdbg.h" +#include "cc-usb.h" +#include "cc.h" +#include "ao-stmload.h"  #define AO_USB_DESC_STRING		3 -struct sym { -	unsigned	addr; -	char		*name; -	int		required; -} ao_symbols[] = { +struct sym ao_symbols[] = { -	{ 0,	"ao_romconfig_version",	1 }, +	{ 0, 0x08002100,	"ao_romconfig_version",	1 },  #define AO_ROMCONFIG_VERSION	(ao_symbols[0].addr) -	{ 0,	"ao_romconfig_check",	1 }, +	{ 0, 0x08002102,	"ao_romconfig_check",	1 },  #define AO_ROMCONFIG_CHECK	(ao_symbols[1].addr) -	{ 0,	"ao_serial_number", 1 }, +	{ 0, 0x08002104,	"ao_serial_number", 1 },  #define AO_SERIAL_NUMBER	(ao_symbols[2].addr) -	{ 0,	"ao_usb_descriptors", 0 }, -#define AO_USB_DESCRIPTORS	(ao_symbols[3].addr) +	{ 0, 0x08002108,	"ao_radio_cal", 0 }, +#define AO_RADIO_CAL		(ao_symbols[3].addr) -	{ 0,	"ao_radio_cal", 0 }, -#define AO_RADIO_CAL		(ao_symbols[4].addr) +	{ 0, 0x0800210c,	"ao_usb_descriptors", 0 }, +#define AO_USB_DESCRIPTORS	(ao_symbols[4].addr)  };  #define NUM_SYMBOLS		5  #define NUM_REQUIRED_SYMBOLS	3 -/* - * Look through the Elf file for the AltOS symbols - * that can be adjusted before the image is written - * to the device - */ -static int -find_symbols (Elf *e) -{ -	Elf_Scn 	*scn; -	Elf_Data	*symbol_data = NULL; -	GElf_Shdr	shdr; -	GElf_Sym       	sym; -	int		i, symbol_count, s; -	int		required = 0; -	char		*symbol_name; -	char		*section_name; -	size_t		shstrndx; - -	if (elf_getshdrstrndx(e, &shstrndx) < 0) -		return 0; - -	/* -	 * Find the symbols -	 */ - -	scn = NULL; -	while ((scn = elf_nextscn(e, scn)) != NULL) { - -		if (gelf_getshdr(scn, &shdr) != &shdr) -			return 0; - -#if 0 -		section_name = elf_strptr(e, shstrndx, shdr.sh_name); - -		printf ("name %s\n", section_name); - -		if (shdr.sh_type == SHT_PROGBITS) -		{ -			printf ("\ttype %lx\n", shdr.sh_type); -			printf ("\tflags %lx\n", shdr.sh_flags); -			printf ("\taddr %lx\n", shdr.sh_addr); -			printf ("\toffset %lx\n", shdr.sh_offset); -			printf ("\tsize %lx\n", shdr.sh_size); -			printf ("\tlink %lx\n", shdr.sh_link); -			printf ("\tinfo %lx\n", shdr.sh_info); -			printf ("\taddralign %lx\n", shdr.sh_addralign); -			printf ("\tentsize %lx\n", shdr.sh_entsize); -		} -#endif - -		if (shdr.sh_type == SHT_SYMTAB) { -			symbol_data = elf_getdata(scn, NULL); -			symbol_count = shdr.sh_size / shdr.sh_entsize; -			break; -		} -	} - -	if (!symbol_data) -		return 0; - -	for (i = 0; i < symbol_count; i++) { -		gelf_getsym(symbol_data, i, &sym); - -		symbol_name = elf_strptr(e, shdr.sh_link, sym.st_name); - -		for (s = 0; s < NUM_SYMBOLS; s++) -			if (!strcmp (ao_symbols[s].name, symbol_name)) { -				int	t; -				ao_symbols[s].addr = sym.st_value; -				if (ao_symbols[s].required) -					++required; -			} -	} - -	return required >= NUM_REQUIRED_SYMBOLS; -} - -struct load { -	uint32_t	addr; -	uint32_t	len; -	uint8_t		buf[0]; -}; - -uint32_t round4(uint32_t a) { -	return (a + 3) & ~3; -} - -struct load * -new_load (uint32_t addr, uint32_t len) -{ -	struct load *new; - -	len = round4(len); -	new = calloc (1, sizeof (struct load) + len); -	if (!new) -		abort(); - -	new->addr = addr; -	new->len = len; -	return new; -} - -void -load_paste(struct load *into, struct load *from) -{ -	if (from->addr < into->addr || into->addr + into->len < from->addr + from->len) -		abort(); - -	memcpy(into->buf + from->addr - into->addr, from->buf, from->len); -} - -/* - * Make a new load structure large enough to hold the old one and - * the new data - */ -struct load * -expand_load(struct load *from, uint32_t addr, uint32_t len) -{ -	struct load	*new; - -	if (from) { -		uint32_t	from_last = from->addr + from->len; -		uint32_t	last = addr + len; - -		if (addr > from->addr) -			addr = from->addr; -		if (last < from_last) -			last = from_last; - -		len = last - addr; - -		if (addr == from->addr && len == from->len) -			return from; -	} -	new = new_load(addr, len); -	if (from) { -		load_paste(new, from); -		free (from); -	} -	return new; -} - -/* - * Create a new load structure with data from the existing one - * and the new data - */ -struct load * -load_write(struct load *from, uint32_t addr, uint32_t len, void *data) -{ -	struct load	*new; - -	new = expand_load(from, addr, len); -	memcpy(new->buf + addr - new->addr, data, len); -	return new; -} - -/* - * Construct a large in-memory block for all - * of the loaded sections of the program - */ -static struct load * -get_load(Elf *e) -{ -	Elf_Scn 	*scn; -	size_t		shstrndx; -	GElf_Shdr	shdr; -	Elf_Data	*data; -	uint8_t		*buf; -	char		*got_name; -	size_t		nphdr; -	size_t		p; -	GElf_Phdr	phdr; -	GElf_Addr	p_paddr; -	GElf_Off	p_offset; -	GElf_Addr	sh_paddr; -	struct load	*load = NULL; -	char		*section_name; -	size_t		nshdr; -	size_t		s; -	 -	if (elf_getshdrstrndx(e, &shstrndx) < 0) -		return 0; - -	if (elf_getphdrnum(e, &nphdr) < 0) -		return 0; - -	if (elf_getshdrnum(e, &nshdr) < 0) -		return 0; - -	/* -	 * As far as I can tell, all of the phdr sections should -	 * be flashed to memory -	 */ -	for (p = 0; p < nphdr; p++) { - -		/* Find this phdr */ -		gelf_getphdr(e, p, &phdr); - -		if (phdr.p_type != PT_LOAD) -			continue; - -		p_offset = phdr.p_offset; -		/* Get the associated file section */ - -#if 0 -		printf ("offset %08x vaddr %08x paddr %08x filesz %08x memsz %08x\n", -			(uint32_t) phdr.p_offset, -			(uint32_t) phdr.p_vaddr, -			(uint32_t) phdr.p_paddr, -			(uint32_t) phdr.p_filesz, -			(uint32_t) phdr.p_memsz); -#endif -		 -		for (s = 0; s < nshdr; s++) { -			scn = elf_getscn(e, s); - -			if (!scn) { -				printf ("getscn failed\n"); -				abort(); -			} -			if (gelf_getshdr(scn, &shdr) != &shdr) { -				printf ("gelf_getshdr failed\n"); -				abort(); -			} - -			section_name = elf_strptr(e, shstrndx, shdr.sh_name); - -			if (phdr.p_offset <= shdr.sh_offset && shdr.sh_offset < phdr.p_offset + phdr.p_filesz) { -					 -				if (shdr.sh_size == 0) -					continue; - -				sh_paddr = phdr.p_paddr + shdr.sh_offset - phdr.p_offset; - -				printf ("\tsize %08x rom %08x exec %08x %s\n", -					(uint32_t) shdr.sh_size, -					(uint32_t) sh_paddr, -					(uint32_t) shdr.sh_addr, -					section_name); - -				data = elf_getdata(scn, NULL); - -				/* Write the section data into the memory block */ -				load = load_write(load, sh_paddr, shdr.sh_size, data->d_buf); -			} -		} -	} -	return load; -} +int ao_num_symbols = NUM_SYMBOLS; +int ao_num_required_symbols = NUM_REQUIRED_SYMBOLS;  /*   * Edit the to-be-written memory block   */  static int -rewrite(struct load *load, unsigned addr, uint8_t *data, int len) +rewrite(struct hex_image *load, unsigned address, uint8_t *data, int length)  {  	int 		i; -	if (addr < load->addr || load->addr + load->len < addr + len) +	if (address < load->address || load->address + load->length < address + length)  		return 0; -	printf("rewrite %04x:", addr); -	for (i = 0; i < len; i++) -		printf (" %02x", load->buf[addr - load->addr + i]); +	printf("rewrite %04x:", address); +	for (i = 0; i < length; i++) +		printf (" %02x", load->data[address - load->address + i]);  	printf(" ->"); -	for (i = 0; i < len; i++) +	for (i = 0; i < length; i++)  		printf (" %02x", data[i]);  	printf("\n"); -	memcpy(load->buf + addr - load->addr, data, len); +	memcpy(load->data + address - load->address, data, length);  }  /* - * Open the specified ELF file and - * check for the symbols we need + * Read a 16-bit value from the USB target   */ -Elf * -ao_open_elf(char *name) +static uint16_t +get_uint16_cc(struct cc_usb *cc, uint32_t addr)  { -	int		fd; -	Elf		*e; -	Elf_Scn 	*scn; -	Elf_Data	*symbol_data = NULL; -	GElf_Shdr	shdr; -	GElf_Sym       	sym; -	size_t		n, shstrndx, sz; -	int		i, symbol_count, s; -	int		required = 0; - -	if (elf_version(EV_CURRENT) == EV_NONE) -		return NULL; +	struct hex_image	*hex = ao_self_read(cc, addr, 2); +	uint16_t		v; +	uint8_t			*data; -	fd = open(name, O_RDONLY, 0); - -	if (fd < 0) -		return NULL; - -	e = elf_begin(fd, ELF_C_READ, NULL); - -	if (!e) -		return NULL; - -	if (elf_kind(e) != ELF_K_ELF) -		return NULL; - -	if (elf_getshdrstrndx(e, &shstrndx) != 0) -		return NULL; +	if (!hex) +		return 0; +	data = hex->data + addr - hex->address; +	v = data[0] | (data[1] << 8); +	free(hex); +	return v; +} -	if (!find_symbols(e)) { -		fprintf (stderr, "Cannot find required symbols\n"); -		return NULL; -	} +static uint32_t +get_uint32_cc(struct cc_usb *cc, uint32_t addr) +{ +	struct hex_image	*hex = ao_self_read(cc, addr, 4); +	uint32_t		v; +	uint8_t			*data; -	return e; +	if (!hex) +		return 0; +	data = hex->data + addr - hex->address; +	v = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); +	free(hex); +	return v;  }  /* - * Read a 32-bit value from the target device with arbitrary + * Read a 16-bit value from the target device with arbitrary   * alignment   */ -static uint32_t -get_uint32(stlink_t *sl, uint32_t addr) +static uint16_t +get_uint16_sl(stlink_t *sl, uint32_t addr)  {  	const 		uint8_t *data = sl->q_buf;  	uint32_t	actual_addr;  	int		off; -	uint32_t	result; +	uint16_t	result;  	sl->q_len = 0; -	printf ("read 0x%x\n", addr);  	actual_addr = addr & ~3; @@ -394,25 +136,37 @@ get_uint32(stlink_t *sl, uint32_t addr)  		abort();  	off = addr & 3; -	result = data[off] | (data[off + 1] << 8) | (data[off+2] << 16) | (data[off+3] << 24); -	printf ("read 0x%08x = 0x%08x\n", addr, result); +	result = data[off] | (data[off + 1] << 8); +	return result; +} + +static uint16_t +get_uint16(stlink_t *sl, struct cc_usb *cc, uint32_t addr) +{ +	uint16_t	result; +	if (cc) +		result = get_uint16_cc(cc, addr); +	else +		result = get_uint16_sl(sl, addr); +	printf ("read 0x%08x = 0x%04x\n", addr, result);  	return result;  }  /* - * Read a 16-bit value from the target device with arbitrary + * Read a 32-bit value from the target device with arbitrary   * alignment   */ -static uint16_t -get_uint16(stlink_t *sl, uint32_t addr) +static uint32_t +get_uint32_sl(stlink_t *sl, uint32_t addr)  {  	const 		uint8_t *data = sl->q_buf;  	uint32_t	actual_addr;  	int		off; -	uint16_t	result; +	uint32_t	result;  	sl->q_len = 0; +	printf ("read 0x%x\n", addr);  	actual_addr = addr & ~3; @@ -422,8 +176,24 @@ get_uint16(stlink_t *sl, uint32_t addr)  		abort();  	off = addr & 3; -	result = data[off] | (data[off + 1] << 8); -	printf ("read 0x%08x = 0x%04x\n", addr, result); +	result = data[off] | (data[off + 1] << 8) | (data[off+2] << 16) | (data[off+3] << 24); +	return result; +} + +/* + * Read a 32-bit value from the target device with arbitrary + * alignment + */ +static uint32_t +get_uint32(stlink_t *sl, struct cc_usb *cc, uint32_t addr) +{ +	uint32_t	result; + +	if (cc) +		result = get_uint32_cc(cc, addr); +	else +		result = get_uint32_sl(sl, addr); +	printf ("read 0x%08x = 0x%08x\n", addr, result);  	return result;  } @@ -436,10 +206,10 @@ get_uint16(stlink_t *sl, uint32_t addr)   * places this at 0x100 from the start of the rom section   */  static int -check_flashed(stlink_t *sl) +check_flashed(stlink_t *sl, struct cc_usb *cc)  { -	uint16_t	romconfig_version = get_uint16(sl, AO_ROMCONFIG_VERSION); -	uint16_t	romconfig_check = get_uint16(sl, AO_ROMCONFIG_CHECK); +	uint16_t	romconfig_version = get_uint16(sl, cc, AO_ROMCONFIG_VERSION); +	uint16_t	romconfig_check = get_uint16(sl, cc, AO_ROMCONFIG_CHECK);  	if (romconfig_version != (uint16_t) ~romconfig_check) {  		fprintf (stderr, "Device has not been flashed before\n"); @@ -449,6 +219,8 @@ check_flashed(stlink_t *sl)  }  static const struct option options[] = { +	{ .name = "stlink", .has_arg = 0, .val = 'S' }, +	{ .name = "tty", .has_arg = 1, .val = 'T' },  	{ .name = "device", .has_arg = 1, .val = 'D' },  	{ .name = "cal", .has_arg = 1, .val = 'c' },  	{ .name = "serial", .has_arg = 1, .val = 's' }, @@ -457,13 +229,17 @@ static const struct option options[] = {  static void usage(char *program)  { -	fprintf(stderr, "usage: %s [--cal=<radio-cal>] [--serial=<serial>] file.elf\n", program); +	fprintf(stderr, "usage: %s [--stlink] [--device=<device>] [-tty=<tty>] [--cal=<radio-cal>] [--serial=<serial>] file.{elf,ihx}\n", program);  	exit(1);  }  void -done(stlink_t *sl, int code) +done(stlink_t *sl, struct cc_usb *cc, int code)  { +	if (cc) { +/*		cc_usb_printf(cc, "a\n"); */ +		cc_usb_close(cc); +	}  	if (sl) {  		stlink_reset(sl);  		stlink_run(sl); @@ -473,6 +249,17 @@ done(stlink_t *sl, int code)  	exit (code);  } +static int +ends_with(char *whole, char *suffix) +{ +	int whole_len = strlen(whole); +	int suffix_len = strlen(suffix); + +	if (suffix_len > whole_len) +		return 0; +	return strcmp(whole + whole_len - suffix_len, suffix) == 0; +} +  int  main (int argc, char **argv)  { @@ -491,13 +278,20 @@ main (int argc, char **argv)  	char			cal_int[4];  	char			*cal_end;  	int			c; -	stlink_t		*sl; +	stlink_t		*sl = NULL;  	int			was_flashed = 0; -	struct load		*load; +	struct hex_image	*load;  	int			tries; +	struct cc_usb		*cc = NULL; +	int			use_stlink = 0; +	char			*tty = NULL; +	int			success; -	while ((c = getopt_long(argc, argv, "D:c:s:", options, NULL)) != -1) { +	while ((c = getopt_long(argc, argv, "T:D:c:s:S", options, NULL)) != -1) {  		switch (c) { +		case 'T': +			tty = optarg; +			break;  		case 'D':  			device = optarg;  			break; @@ -511,6 +305,9 @@ main (int argc, char **argv)  			if (serial_end == optarg || *serial_end != '\0')  				usage(argv[0]);  			break; +		case 'S': +			use_stlink = 1; +			break;  		default:  			usage(argv[0]);  			break; @@ -521,91 +318,145 @@ main (int argc, char **argv)  	if (filename == NULL)  		usage(argv[0]); -	/* -	 * Open the source file and load the symbols and -	 * flash data -	 */ -	 -	e = ao_open_elf(filename); -	if (!e) { -		fprintf(stderr, "Cannot open file \"%s\"\n", filename); -		exit(1); -	} - -	if (!find_symbols(e)) { -		fprintf(stderr, "Cannot find symbols in \"%s\"\n", filename); -		exit(1); -	} +	if (ends_with (filename, ".elf")) { +		load = ao_load_elf(filename); +	} else if (ends_with (filename, ".ihx")) { +		int	i; +		load = ccdbg_hex_load(filename); +		for (i = 0; i < ao_num_symbols; i++) +			ao_symbols[i].addr = ao_symbols[i].default_addr; +	} else +		usage(argv[0]); -	if (!(load = get_load(e))) { -		fprintf(stderr, "Cannot find program data in \"%s\"\n", filename); -		exit(1); -	} -		 -	/* Connect to the programming dongle -	 */ +	if (use_stlink) { +		/* Connect to the programming dongle +		 */ -	for (tries = 0; tries < 3; tries++) { -		if (device) { -			sl = stlink_v1_open(50); -		} else { -			sl = stlink_open_usb(50); +		for (tries = 0; tries < 3; tries++) { +			if (device) { +				sl = stlink_v1_open(50); +			} else { +				sl = stlink_open_usb(50); +			} +			if (!sl) { +				fprintf (stderr, "No STLink devices present\n"); +				done (sl, NULL, 1); +			} + +			if (sl->chip_id != 0) +				break; +			stlink_reset(sl); +			stlink_close(sl); +			sl = NULL;  		}  		if (!sl) { -			fprintf (stderr, "No STLink devices present\n"); -			done (sl, 1); +			fprintf (stderr, "Debugger connection failed\n"); +			exit(1);  		} -		if (sl->chip_id != 0) -			break; -		stlink_reset(sl); -		stlink_close(sl); -	} -	if (sl->chip_id == 0) { -		fprintf (stderr, "Debugger connection failed\n"); -		done(sl, 1); -	} +		/* Verify that the loaded image fits entirely within device flash +		 */ +		if (load->address < sl->flash_base || +		    sl->flash_base + sl->flash_size < load->address + load->length) { +			fprintf (stderr, "\%s\": Invalid memory range 0x%08x - 0x%08x\n", filename, +				 load->address, load->address + load->length); +			done(sl, NULL, 1); +		} -	/* Verify that the loaded image fits entirely within device flash -	 */ -	if (load->addr < sl->flash_base || -	    sl->flash_base + sl->flash_size < load->addr + load->len) { -		fprintf (stderr, "\%s\": Invalid memory range 0x%08x - 0x%08x\n", filename, -			 load->addr, load->addr + load->len); -		done(sl, 1); +		/* Enter debugging mode +		 */ +		if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE) +			stlink_exit_dfu_mode(sl); + +		if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE) +			stlink_enter_swd_mode(sl); +	} else { +		int	is_loader; +		int	tries; + +		for (tries = 0; tries < 3; tries++) { +			char	*this_tty = tty; +			if (!this_tty) +				this_tty = cc_usbdevs_find_by_arg(device, "AltosFlash"); +			if (!this_tty) +				this_tty = cc_usbdevs_find_by_arg(device, "MegaMetrum"); +			if (!this_tty) +				this_tty = getenv("ALTOS_TTY"); +			if (!this_tty) +				this_tty="/dev/ttyACM0"; + +			cc = cc_usb_open(this_tty); + +			if (!cc) +				exit(1); +			cc_usb_printf(cc, "v\n"); +			is_loader = 0; +			for (;;) { +				char	line[256]; +				cc_usb_getline(cc, line, sizeof(line)); +				if (!strncmp(line, "altos-loader", 12)) +					is_loader = 1; +				if (!strncmp(line, "software-version", 16)) +					break; +			} +			if (is_loader) +				break; +			printf ("rebooting to loader\n"); +			cc_usb_printf(cc, "L\n"); +			cc_usb_close(cc); +			sleep(1); +			cc = NULL; +		} +		if (!is_loader) { +			fprintf(stderr, "Cannot switch to boot loader\n"); +			exit(1); +		} +		{ +			uint8_t	check[256]; +			int	i = 0; + +			ao_self_block_read(cc, 0x08002000, check); +			for (;;) { +				uint8_t block[256]; +				putchar ('.'); +				if (++i == 40) { +					putchar('\n'); +					i = 0; +				} +				fflush(stdout); +				ao_self_block_write(cc, 0x08002000, block); +				ao_self_block_read(cc, 0x08002000, block); +				if (memcmp(block, check, 256/me ta) != 0) { +					fprintf (stderr, "read differed\n"); +					exit(1); +				} +			} +		}  	} -	/* Enter debugging mode -	 */ -	if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE) -		stlink_exit_dfu_mode(sl); - -	if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE) -		stlink_enter_swd_mode(sl); -  	/* Go fetch existing config values  	 * if available  	 */ -	was_flashed = check_flashed(sl); +	was_flashed = check_flashed(sl, cc);  	if (!serial) {  		if (!was_flashed) {  			fprintf (stderr, "Must provide serial number\n"); -			done(sl, 1); +			done(sl, cc, 1);  		} -		serial = get_uint16(sl, AO_SERIAL_NUMBER); +		serial = get_uint16(sl, cc, AO_SERIAL_NUMBER);  		if (!serial || serial == 0xffff) {  			fprintf (stderr, "Invalid existing serial %d\n", serial); -			done(sl, 1); +			done(sl, cc, 1);  		}  	}  	if (!cal && AO_RADIO_CAL && was_flashed) { -		cal = get_uint32(sl, AO_RADIO_CAL); +		cal = get_uint32(sl, cc, AO_RADIO_CAL);  		if (!cal || cal == 0xffffffff) {  			fprintf (stderr, "Invalid existing rf cal %d\n", cal); -			done(sl, 1); +			done(sl, cc, 1);  		}  	} @@ -618,32 +469,31 @@ main (int argc, char **argv)  	if (!rewrite(load, AO_SERIAL_NUMBER, serial_int, sizeof (serial_int))) {  		fprintf(stderr, "Cannot rewrite serial integer at %08x\n",  			AO_SERIAL_NUMBER); -		done(sl, 1); +		done(sl, cc, 1);  	}  	if (AO_USB_DESCRIPTORS) { -		unsigned	usb_descriptors; -		usb_descriptors = AO_USB_DESCRIPTORS - load->addr; +		uint32_t	usb_descriptors = AO_USB_DESCRIPTORS - load->address;  		string_num = 0; -		while (load->buf[usb_descriptors] != 0 && usb_descriptors < load->len) { -			if (load->buf[usb_descriptors+1] == AO_USB_DESC_STRING) { +		while (load->data[usb_descriptors] != 0 && usb_descriptors < load->length) { +			if (load->data[usb_descriptors+1] == AO_USB_DESC_STRING) {  				++string_num;  				if (string_num == 4)  					break;  			} -			usb_descriptors += load->buf[usb_descriptors]; +			usb_descriptors += load->data[usb_descriptors];  		} -		if (usb_descriptors >= load->len || load->buf[usb_descriptors] == 0 ) { +		if (usb_descriptors >= load->length || load->data[usb_descriptors] == 0 ) {  			fprintf(stderr, "Cannot rewrite serial string at %08x\n", AO_USB_DESCRIPTORS); -			done(sl, 1); +			done(sl, cc, 1);  		} -		serial_ucs2_len = load->buf[usb_descriptors] - 2; +		serial_ucs2_len = load->data[usb_descriptors] - 2;  		serial_ucs2 = malloc(serial_ucs2_len);  		if (!serial_ucs2) {  			fprintf(stderr, "Malloc(%d) failed\n", serial_ucs2_len); -			done(sl, 1); +			done(sl, cc, 1);  		}  		s = serial;  		for (i = serial_ucs2_len / 2; i; i--) { @@ -651,9 +501,9 @@ main (int argc, char **argv)  			serial_ucs2[i * 2 - 2] = (s % 10) + '0';  			s /= 10;  		} -		if (!rewrite(load, usb_descriptors + 2 + load->addr, serial_ucs2, serial_ucs2_len)) { +		if (!rewrite(load, usb_descriptors + 2 + load->address, serial_ucs2, serial_ucs2_len)) {  			fprintf (stderr, "Cannot rewrite USB descriptor at %08x\n", AO_USB_DESCRIPTORS); -			done(sl, 1); +			done(sl, cc, 1);  		}  	} @@ -671,10 +521,15 @@ main (int argc, char **argv)  	/* And flash the resulting image to the device  	 */ -	if (stlink_write_flash(sl, load->addr, load->buf, load->len) < 0) { +	if (cc) +		success = ao_self_write(cc, load); +	else +		success = (stlink_write_flash(sl, load->address, load->data, load->length) >= 0); +		 +	if (!success) {  		fprintf (stderr, "\"%s\": Write failed\n", filename); -		done(sl, 1); +		done(sl, cc, 1);  	} -	done(sl, 0); +	done(sl, cc, 0);  } diff --git a/ao-tools/ao-stmload/ao-stmload.h b/ao-tools/ao-stmload/ao-stmload.h new file mode 100644 index 00000000..2618b7f3 --- /dev/null +++ b/ao-tools/ao-stmload/ao-stmload.h @@ -0,0 +1,45 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_STMLOAD_H_ +#define _AO_STMLOAD_H_ + +struct sym { +	unsigned	addr; +	unsigned	default_addr; +	char		*name; +	int		required; +}; + +extern struct sym ao_symbols[]; + +extern int ao_num_symbols; +extern int ao_num_required_symbols; + +void +ao_self_block_read(struct cc_usb *cc, uint32_t address, uint8_t block[256]); + +void +ao_self_block_write(struct cc_usb *cc, uint32_t address, uint8_t block[256]); + +struct hex_image * +ao_self_read(struct cc_usb *cc, uint32_t address, uint32_t length); + +int +ao_self_write(struct cc_usb *cc, struct hex_image *image); + +#endif /* _AO_STMLOAD_H_ */ | 
