From: Keith Packard Date: Sat, 13 Jan 2018 06:27:41 +0000 (-0800) Subject: altoslib/altosuilib: Validate rom image is for target device X-Git-Tag: 1.8.5~1^2~2^2~2 X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=commitdiff_plain;h=b95db5819885da89504d5e11decfda98cfac37aa altoslib/altosuilib: Validate rom image is for target device This should avoid mis-programming devices with incorrect firmware. Signed-off-by: Keith Packard --- diff --git a/altoslib/AltosFlash.java b/altoslib/AltosFlash.java index c8db1f77..9bf0da25 100644 --- a/altoslib/AltosFlash.java +++ b/altoslib/AltosFlash.java @@ -254,7 +254,7 @@ public class AltosFlash extends AltosProgrammer { clock_init(); int remain = image.data.length; - int flash_addr = image.address; + int flash_addr = (int) image.address; int image_start = 0; action("start", 0); @@ -295,7 +295,7 @@ public class AltosFlash extends AltosProgrammer { if (!aborted) { action("done", 100); if (debug != null) { - debug.set_pc(image.address); + debug.set_pc((int) image.address); debug.resume(); } } @@ -331,12 +331,16 @@ public class AltosFlash extends AltosProgrammer { rom_config = romconfig; } - public AltosRomconfig romconfig() throws InterruptedException { + public AltosRomconfig target_romconfig() throws InterruptedException { if (!check_rom_config()) return null; return rom_config; } + public AltosRomconfig image_romconfig() { + return new AltosRomconfig(image); + } + public AltosFlash(File file, AltosLink link, AltosFlashListener listener) throws IOException, FileNotFoundException, InterruptedException { this.file = file; diff --git a/altoslib/AltosHexfile.java b/altoslib/AltosHexfile.java index 7ab121ad..6aa98383 100644 --- a/altoslib/AltosHexfile.java +++ b/altoslib/AltosHexfile.java @@ -46,7 +46,7 @@ class HexFileInputStream extends PushbackInputStream { } class HexRecord implements Comparable { - public int address; + public long address; public int type; public byte checksum; public byte[] data; @@ -110,7 +110,14 @@ class HexRecord implements Comparable { public int compareTo(Object other) { HexRecord o = (HexRecord) other; - return address - o.address; + + long diff = address - o.address; + + if (diff > 0) + return 1; + if (diff < 0) + return -1; + return 0; } public String toString() { @@ -119,8 +126,8 @@ class HexRecord implements Comparable { public HexRecord(HexFileInputStream input) throws IOException, EOFException { read_state state = read_state.marker; - int nhexbytes = 0; - int hex = 0; + long nhexbytes = 0; + long hex = 0; int ndata = 0; byte got_checksum; @@ -154,7 +161,7 @@ class HexRecord implements Comparable { switch (state) { case length: - data = new byte[hex]; + data = new byte[(int) hex]; state = read_state.address; nhexbytes = 4; break; @@ -164,7 +171,7 @@ class HexRecord implements Comparable { nhexbytes = 2; break; case type: - type = hex; + type = (int) hex; if (data.length > 0) state = read_state.data; else @@ -211,12 +218,21 @@ class HexRecord implements Comparable { } public class AltosHexfile { - public int address; + public long address; + public long max_address; public byte[] data; LinkedList symlist = new LinkedList(); - public byte get_byte(int a) { - return data[a - address]; + public byte get_byte(long a) { + return data[(int) (a - address)]; + } + + public int get_u8(long a) { + return ((int) get_byte(a)) & 0xff; + } + + public int get_u16(long a) { + return get_u8(a) | (get_u8(a+1) << 8); } /* CC1111-based products have the romconfig stuff located @@ -237,6 +253,15 @@ public class AltosHexfile { new AltosHexsym("ao_usb_descriptors", ao_usb_descriptors_addr) }; + static final int AO_USB_DESC_DEVICE = 1; + static final int AO_USB_DESC_STRING = 3; + + static final int AO_ROMCONFIG_VERSION_INDEX = 0; + static final int AO_ROMCONFIG_CHECK_INDEX = 1; + static final int AO_SERIAL_NUMBER_INDEX = 2; + static final int AO_RADIO_CAL_INDEX = 3; + static final int AO_USB_DESCRIPTORS_INDEX = 4; + private void add_cc_symbols() { for (int i = 0; i < cc_symbols.length; i++) symlist.add(cc_symbols[i]); @@ -262,6 +287,92 @@ public class AltosHexfile { return null; } + private long find_usb_descriptors() { + AltosHexsym usb_descriptors = lookup_symbol("ao_usb_descriptors"); + long a; + + if (usb_descriptors == null) + return -1; + + /* Walk the descriptors looking for the device */ + a = usb_descriptors.address; + while (get_u8(a+1) != AO_USB_DESC_DEVICE) { + int delta = get_u8(a); + a += delta; + if (delta == 0 || a >= max_address) + return -1; + } + return a; + } + + public AltosUsbId find_usb_id() { + long a = find_usb_descriptors(); + + if (a == -1) + return null; + + /* Walk the descriptors looking for the device */ + while (get_u8(a+1) != AO_USB_DESC_DEVICE) { + int delta = get_u8(a); + a += delta; + if (delta == 0 || a >= max_address) + return null; + } + + return new AltosUsbId(get_u16(a + 8), + get_u16(a + 10)); + } + + public String find_usb_product() { + long a = find_usb_descriptors(); + int num_strings; + int product_string; + + if (a == -1) + return null; + + product_string = get_u8(a+15); + + /* Walk the descriptors looking for the device */ + num_strings = 0; + for (;;) { + if (get_u8(a+1) == AO_USB_DESC_STRING) { + ++num_strings; + if (num_strings == product_string + 1) + break; + } + + int delta = get_u8(a); + a += delta; + if (delta == 0 || a >= max_address) + return null; + } + + int product_len = get_u8(a); + + System.out.printf("Product is at %x length %d\n", a, product_len); + + for (int i = 0; i < product_len; i++) + System.out.printf(" %2d: %02x\n", i, get_u8(a+i)); + + if (product_len <= 0) + return null; + + String product = ""; + + for (int i = 0; i < product_len - 2; i += 2) { + int c = get_u16(a + 2 + i); + + System.out.printf("character %x\n", c); + + product += Character.toString((char) c); + } + + System.out.printf("product %s\n", product); + + return product; + } + private String make_string(byte[] data, int start, int length) { String s = ""; for (int i = 0; i < length; i++) @@ -269,9 +380,10 @@ public class AltosHexfile { return s; } - public AltosHexfile(byte[] bytes, int offset) { + public AltosHexfile(byte[] bytes, long offset) { data = bytes; address = offset; + max_address = address + bytes.length; } public AltosHexfile(FileInputStream file) throws IOException { @@ -335,7 +447,8 @@ public class AltosHexfile { throw new IOException("hex file too large"); data = new byte[(int) (bound - base)]; - address = (int) base; + address = base; + max_address = bound; Arrays.fill(data, (byte) 0xff); /* Paint the records into the new array */ @@ -366,4 +479,4 @@ public class AltosHexfile { } } } -} \ No newline at end of file +} diff --git a/altoslib/AltosProgrammer.java b/altoslib/AltosProgrammer.java index 0a828a32..e4f57578 100644 --- a/altoslib/AltosProgrammer.java +++ b/altoslib/AltosProgrammer.java @@ -28,7 +28,9 @@ public abstract class AltosProgrammer { abstract public void abort(); - abstract public AltosRomconfig romconfig() throws InterruptedException; + abstract public AltosRomconfig target_romconfig() throws InterruptedException; + + abstract public AltosRomconfig image_romconfig(); abstract public void set_romconfig(AltosRomconfig config); -} \ No newline at end of file +} diff --git a/altoslib/AltosRomconfig.java b/altoslib/AltosRomconfig.java index 46ee2b6e..1fbb4115 100644 --- a/altoslib/AltosRomconfig.java +++ b/altoslib/AltosRomconfig.java @@ -26,20 +26,31 @@ public class AltosRomconfig { public int check; public int serial_number; public int radio_calibration; + public AltosUsbId usb_id; + public String usb_product; - static private int find_offset(AltosHexfile hexfile, String name, int len) throws AltosNoSymbol { + static private long find_address(AltosHexfile hexfile, String name, int len) throws AltosNoSymbol { AltosHexsym symbol = hexfile.lookup_symbol(name); - if (symbol == null) - throw new AltosNoSymbol(name); - int offset = (int) symbol.address - hexfile.address; - if (offset < 0 || hexfile.data.length < offset + len) + if (symbol == null) { + System.out.printf("no symbol %s\n", name); throw new AltosNoSymbol(name); - return offset; + } + if (hexfile.address <= symbol.address && symbol.address + len < hexfile.max_address) { + System.out.printf("%s: %x\n", name, symbol.address); + return symbol.address; + } + System.out.printf("invalid symbol addr %x range is %x - %x\n", + symbol.address, hexfile.address, hexfile.max_address); + throw new AltosNoSymbol(name); + } + + static private int find_offset(AltosHexfile hexfile, String name, int len) throws AltosNoSymbol { + return (int) (find_address(hexfile, name, len) - hexfile.address); } static int get_int(AltosHexfile hexfile, String name, int len) throws AltosNoSymbol { byte[] bytes = hexfile.data; - int start = find_offset(hexfile, name, len); + int start = (int) find_offset(hexfile, name, len); int v = 0; int o = 0; @@ -112,13 +123,17 @@ public class AltosRomconfig { public AltosRomconfig(AltosHexfile hexfile) { try { + System.out.printf("Attempting symbols\n"); version = get_int(hexfile, ao_romconfig_version, 2); + System.out.printf("version %d\n", version); check = get_int(hexfile, ao_romconfig_check, 2); + System.out.printf("check %d\n", check); if (check == (~version & 0xffff)) { switch (version) { case 2: case 1: serial_number = get_int(hexfile, ao_serial_number, 2); + System.out.printf("serial %d\n", serial_number); try { radio_calibration = get_int(hexfile, ao_radio_cal, 4); } catch (AltosNoSymbol missing) { @@ -128,6 +143,19 @@ public class AltosRomconfig { break; } } + System.out.printf("attempting usbid\n"); + usb_id = hexfile.find_usb_id(); + if (usb_id == null) + System.out.printf("No usb id\n"); + else + System.out.printf("usb id: %04x:%04x\n", + usb_id.vid, usb_id.pid); + usb_product = hexfile.find_usb_product(); + if (usb_product == null) + System.out.printf("No usb product\n"); + else + System.out.printf("usb product: %s\n", usb_product); + } catch (AltosNoSymbol missing) { valid = false; } @@ -137,9 +165,16 @@ public class AltosRomconfig { ao_romconfig_version, ao_romconfig_check, ao_serial_number, - ao_radio_cal + ao_radio_cal, + ao_usb_descriptors, }; + private static int fetch_len(String name) { + if (name.equals(ao_usb_descriptors)) + return 256; + return 2; + } + private final static String[] required_names = { ao_romconfig_version, ao_romconfig_check, @@ -153,13 +188,16 @@ public class AltosRomconfig { return false; } - public static int fetch_base(AltosHexfile hexfile) throws AltosNoSymbol { - int base = 0x7fffffff; + public static long fetch_base(AltosHexfile hexfile) throws AltosNoSymbol { + long base = 0xffffffffL; for (String name : fetch_names) { try { - int addr = find_offset(hexfile, name, 2) + hexfile.address; + int len = fetch_len(name); + long addr = find_address(hexfile, name, len); + if (addr < base) base = addr; + System.out.printf("symbol %s at %x base %x\n", name, addr, base); } catch (AltosNoSymbol ns) { if (name_required(name)) throw (ns); @@ -168,19 +206,22 @@ public class AltosRomconfig { return base; } - public static int fetch_bounds(AltosHexfile hexfile) throws AltosNoSymbol { - int bounds = 0; + public static long fetch_bounds(AltosHexfile hexfile) throws AltosNoSymbol { + long bounds = 0; for (String name : fetch_names) { try { - int addr = find_offset(hexfile, name, 2) + hexfile.address; + int len = fetch_len(name); + long addr = find_address(hexfile, name, len) + len; if (addr > bounds) bounds = addr; + System.out.printf("symbol %s at %x bounds %x\n", name, addr, bounds); } catch (AltosNoSymbol ns) { if (name_required(name)) throw (ns); } } - return bounds + 2; + + return bounds; } public void write (AltosHexfile hexfile) throws IOException { diff --git a/altoslib/AltosSelfFlash.java b/altoslib/AltosSelfFlash.java index 53782172..c7ea147f 100644 --- a/altoslib/AltosSelfFlash.java +++ b/altoslib/AltosSelfFlash.java @@ -45,18 +45,33 @@ public class AltosSelfFlash extends AltosProgrammer { int b; byte[] data = new byte[len]; + System.out.printf("read_memory %x %d\n", addr, len); for (int offset = 0; offset < len; offset += 0x100) { link.printf("R %x\n", addr + offset); byte[] reply = link.get_binary_reply(5000, 0x100); if (reply == null) throw new IOException("Read device memory timeout"); - for (b = 0; b < len; b++) + for (b = 0; b < 0x100 && b + offset < len; b++) data[b+offset] = reply[b]; } return data; } + AltosHexfile read_hexfile(long addr, int len) throws InterruptedException { + try { + byte[] mem = read_memory(addr, len); + + AltosHexfile hexfile = new AltosHexfile(mem, addr); + + if (image != null) + hexfile.add_symbols(image); + return hexfile; + } catch (IOException ie) { + return null; + } + } + void write_memory(long addr, byte[] data, int start, int len) { int b; link.printf("W %x\n", addr); @@ -143,18 +158,14 @@ public class AltosSelfFlash extends AltosProgrammer { private AltosHexfile get_rom() throws InterruptedException { try { - int base = AltosRomconfig.fetch_base(image); - int bounds = AltosRomconfig.fetch_bounds(image); - byte[] data = read_memory(base, bounds - base); - AltosHexfile hexfile = new AltosHexfile(data, base); - hexfile.add_symbols(image); - return hexfile; - } catch (AltosNoSymbol none) { - return null; - } catch (IOException ie) { + long base = AltosRomconfig.fetch_base(image); + long bounds = AltosRomconfig.fetch_bounds(image); + + System.out.printf("rom base %x bounds %x\n", base, bounds); + return read_hexfile(base, (int) (bounds - base)); + } catch (AltosNoSymbol ns) { return null; } - } public boolean check_rom_config() throws InterruptedException { @@ -173,12 +184,16 @@ public class AltosSelfFlash extends AltosProgrammer { rom_config = romconfig; } - public AltosRomconfig romconfig() throws InterruptedException { + public AltosRomconfig target_romconfig() throws InterruptedException { if (!check_rom_config()) return null; return rom_config; } + public AltosRomconfig image_romconfig() { + return new AltosRomconfig(image); + } + public AltosSelfFlash(File file, AltosLink link, AltosFlashListener listener) throws IOException, FileNotFoundException, InterruptedException { this.file = file; @@ -187,4 +202,4 @@ public class AltosSelfFlash extends AltosProgrammer { input = new FileInputStream(file); image = new AltosHexfile(input); } -} \ No newline at end of file +} diff --git a/altoslib/AltosUsbId.java b/altoslib/AltosUsbId.java new file mode 100644 index 00000000..e3794304 --- /dev/null +++ b/altoslib/AltosUsbId.java @@ -0,0 +1,26 @@ +/* + * Copyright © 2018 Keith Packard + * + * 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, either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +package org.altusmetrum.altoslib_12; + +public class AltosUsbId { + public int vid; + public int pid; + + + public AltosUsbId(int vid, int pid) { + this.vid = vid; + this.pid = pid; + } +} diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index 2a1cb8e4..7c5d767d 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -99,6 +99,7 @@ altoslib_JAVA = \ AltosRomconfig.java \ AltosSavedState.java \ AltosSelfFlash.java \ + AltosUsbId.java \ AltosSensorMM.java \ AltosSensorEMini.java \ AltosSensorTM.java \ diff --git a/altosuilib/AltosFlashUI.java b/altosuilib/AltosFlashUI.java index ca089ca8..c717e47c 100644 --- a/altosuilib/AltosFlashUI.java +++ b/altosuilib/AltosFlashUI.java @@ -276,8 +276,37 @@ public class AltosFlashUI return true; } - boolean update_rom_config_info(AltosRomconfig existing_config) { + boolean rom_config_matches (AltosRomconfig a, AltosRomconfig b) { + if (a.usb_id != null && b.usb_id != null && + (a.usb_id.vid != b.usb_id.vid || + a.usb_id.pid != b.usb_id.pid)) + return false; + + if (a.usb_product != null && b.usb_product != null && + !a.usb_product.equals(b.usb_product)) + return false; + + return true; + } + + boolean update_rom_config_info(AltosRomconfig existing_config, AltosRomconfig image_config) { AltosRomconfig new_config; + + if (!rom_config_matches(existing_config, image_config)) { + int ret = JOptionPane.showConfirmDialog(this, + String.format("Device is %04x:%04x %s\nImage is %04x:%04x %s\nFlash anyways?", + existing_config.usb_id.vid, + existing_config.usb_id.pid, + existing_config.usb_product, + image_config.usb_id.vid, + image_config.usb_id.pid, + image_config.usb_product), + "Image doesn't match Device", + JOptionPane.YES_NO_OPTION); + if (ret != JOptionPane.YES_OPTION) + return false; + } + new_config = AltosRomconfigUI.show(frame, existing_config); if (new_config == null) return false; @@ -335,13 +364,15 @@ public class AltosFlashUI else programmer = new AltosSelfFlash(ui.file, link, this); - final AltosRomconfig current_config = programmer.romconfig(); + final AltosRomconfig current_config = programmer.target_romconfig(); + + final AltosRomconfig image_config = programmer.image_romconfig(); final Semaphore await_rom_config = new Semaphore(0); SwingUtilities.invokeLater(new Runnable() { public void run() { ui.programmer = programmer; - ui.update_rom_config_info(current_config); + ui.update_rom_config_info(current_config, image_config); await_rom_config.release(); } });