From 2b9124f3c09731dbacaf0682f899101b6813a28c Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Thu, 16 Aug 2018 17:03:23 -0400 Subject: [PATCH] lib: Add bossac 1.9 code to lib directory Signed-off-by: Kevin O'Connor --- lib/README | 4 + lib/bossac/LICENSE | 24 + lib/bossac/Makefile | 347 ++++++++++++++ lib/bossac/src/Applet.cpp | 64 +++ lib/bossac/src/Applet.h | 65 +++ lib/bossac/src/CmdOpts.cpp | 159 +++++++ lib/bossac/src/CmdOpts.h | 88 ++++ lib/bossac/src/D2xNvmFlash.cpp | 347 ++++++++++++++ lib/bossac/src/D2xNvmFlash.h | 76 +++ lib/bossac/src/D5xNvmFlash.cpp | 352 ++++++++++++++ lib/bossac/src/D5xNvmFlash.h | 79 ++++ lib/bossac/src/Device.cpp | 692 ++++++++++++++++++++++++++++ lib/bossac/src/Device.h | 104 +++++ lib/bossac/src/EefcFlash.cpp | 363 +++++++++++++++ lib/bossac/src/EefcFlash.h | 88 ++++ lib/bossac/src/EfcFlash.cpp | 295 ++++++++++++ lib/bossac/src/EfcFlash.h | 83 ++++ lib/bossac/src/FileError.h | 94 ++++ lib/bossac/src/Flash.cpp | 106 +++++ lib/bossac/src/Flash.h | 180 ++++++++ lib/bossac/src/Flasher.cpp | 373 +++++++++++++++ lib/bossac/src/Flasher.h | 110 +++++ lib/bossac/src/LinuxPortFactory.cpp | 109 +++++ lib/bossac/src/LinuxPortFactory.h | 60 +++ lib/bossac/src/PortFactory.h | 68 +++ lib/bossac/src/PosixSerialPort.cpp | 332 +++++++++++++ lib/bossac/src/PosixSerialPort.h | 66 +++ lib/bossac/src/Samba.cpp | 672 +++++++++++++++++++++++++++ lib/bossac/src/Samba.h | 115 +++++ lib/bossac/src/SerialPort.h | 82 ++++ lib/bossac/src/WordCopyApplet.cpp | 62 +++ lib/bossac/src/WordCopyApplet.h | 49 ++ lib/bossac/src/WordCopyArm.asm | 47 ++ lib/bossac/src/WordCopyArm.cpp | 25 + lib/bossac/src/WordCopyArm.h | 18 + lib/bossac/src/bossac.cpp | 489 ++++++++++++++++++++ 36 files changed, 6287 insertions(+) create mode 100644 lib/bossac/LICENSE create mode 100644 lib/bossac/Makefile create mode 100644 lib/bossac/src/Applet.cpp create mode 100644 lib/bossac/src/Applet.h create mode 100644 lib/bossac/src/CmdOpts.cpp create mode 100644 lib/bossac/src/CmdOpts.h create mode 100644 lib/bossac/src/D2xNvmFlash.cpp create mode 100644 lib/bossac/src/D2xNvmFlash.h create mode 100644 lib/bossac/src/D5xNvmFlash.cpp create mode 100644 lib/bossac/src/D5xNvmFlash.h create mode 100644 lib/bossac/src/Device.cpp create mode 100644 lib/bossac/src/Device.h create mode 100644 lib/bossac/src/EefcFlash.cpp create mode 100644 lib/bossac/src/EefcFlash.h create mode 100644 lib/bossac/src/EfcFlash.cpp create mode 100644 lib/bossac/src/EfcFlash.h create mode 100644 lib/bossac/src/FileError.h create mode 100644 lib/bossac/src/Flash.cpp create mode 100644 lib/bossac/src/Flash.h create mode 100644 lib/bossac/src/Flasher.cpp create mode 100644 lib/bossac/src/Flasher.h create mode 100644 lib/bossac/src/LinuxPortFactory.cpp create mode 100644 lib/bossac/src/LinuxPortFactory.h create mode 100644 lib/bossac/src/PortFactory.h create mode 100644 lib/bossac/src/PosixSerialPort.cpp create mode 100644 lib/bossac/src/PosixSerialPort.h create mode 100644 lib/bossac/src/Samba.cpp create mode 100644 lib/bossac/src/Samba.h create mode 100644 lib/bossac/src/SerialPort.h create mode 100644 lib/bossac/src/WordCopyApplet.cpp create mode 100644 lib/bossac/src/WordCopyApplet.h create mode 100644 lib/bossac/src/WordCopyArm.asm create mode 100644 lib/bossac/src/WordCopyArm.cpp create mode 100644 lib/bossac/src/WordCopyArm.h create mode 100644 lib/bossac/src/bossac.cpp diff --git a/lib/README b/lib/README index c785c7de..00f888e2 100644 --- a/lib/README +++ b/lib/README @@ -50,6 +50,10 @@ The hub-ctrl directory contains code from: https://github.com/codazoda/hub-ctrl.c/ revision 42095e522859059e8a5f4ec05c1e3def01a870a9. +The bossac directory contains code from: + https://github.com/shumatech/BOSSA +version 1.9 (b176eeef918fc810045c832348590595120187b4). + The pru_rpmsg directory contains code from: https://github.com/dinuxbg/pru-gcc-examples revision 425a42d82006cf0aa24be27b483d2f6a41607489. The code is taken diff --git a/lib/bossac/LICENSE b/lib/bossac/LICENSE new file mode 100644 index 00000000..da4f48cd --- /dev/null +++ b/lib/bossac/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2011-2016, ShumaTech +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/lib/bossac/Makefile b/lib/bossac/Makefile new file mode 100644 index 00000000..35fe857a --- /dev/null +++ b/lib/bossac/Makefile @@ -0,0 +1,347 @@ +.DEFAULT_GOAL := all + +# +# Version +# +VERSION=1.9 +WXVERSION=3.0 + +# +# Source files +# +COMMON_SRCS=Samba.cpp Flash.cpp D5xNvmFlash.cpp D2xNvmFlash.cpp EfcFlash.cpp EefcFlash.cpp Applet.cpp WordCopyApplet.cpp Flasher.cpp Device.cpp +APPLET_SRCS=WordCopyArm.asm +BOSSA_SRCS=BossaForm.cpp BossaWindow.cpp BossaAbout.cpp BossaApp.cpp BossaBitmaps.cpp BossaInfo.cpp BossaThread.cpp BossaProgress.cpp +BOSSA_BMPS=BossaLogo.bmp BossaIcon.bmp ShumaTechLogo.bmp +BOSSAC_SRCS=bossac.cpp CmdOpts.cpp +BOSSASH_SRCS=bossash.cpp Shell.cpp Command.cpp + +# +# Build directories +# +BINDIR=bin +OBJDIR=obj +SRCDIR=src +RESDIR=res +INSTALLDIR=install + +# +# Determine OS +# +OS:=$(shell uname -s | cut -c -7) + +# +# Windows rules +# +ifeq ($(OS),MINGW32) +# Use wxWindows development branch to work around font scaling issues on Windows +WXVERSION=3.1 +EXE=.exe +COMMON_SRCS+=WinSerialPort.cpp WinPortFactory.cpp +COMMON_LDFLAGS=-Wl,--enable-auto-import -static -static-libstdc++ -static-libgcc +COMMON_LIBS=-ltermcap -Wl,--as-needed -lsetupapi +BOSSA_RC=BossaRes.rc +WIXDIR="C:\Program Files (x86)\WiX Toolset v3.10\bin" +CODE_SIGN=$(INSTALLDIR)\\code_sign.p12 +TIMESTAMP=http://timestamp.comodoca.com/authenticode +SIGNTOOL="C:\Program Files (x86)\Windows Kits\10\bin\x64\signtool.exe" +INF2CAT="C:\Program Files (x86)\Windows Kits\10\bin\x86\Inf2Cat.exe" + +define bossa_msi +$(OBJDIR)\\bossa-$(1)-$(VERSION).wixobj: $(INSTALLDIR)\\bossa.wxs + $(WIXDIR)\\candle.exe -dVersion=$(VERSION) -arch $(1) -out $$@ -ext $(WIXDIR)\\WixUIExtension.dll -ext $(WIXDIR)\\WixDifxAppExtension.dll $$< + +$(BINDIR)\\bossa-$(1)-$(VERSION).msi: $(OBJDIR)\\bossa-$(1)-$(VERSION).wixobj + $(WIXDIR)\\light.exe -cultures:null -out $$@ -pdbout $(OBJDIR)\\bossa.wixpdb -sice:ICE57 -ext $(WIXDIR)\\WixUIExtension.dll -ext $(WIXDIR)\\WixDifxAppExtension.dll $(WIXDIR)\\difxapp_$(1).wixlib $$< + $$(Q)read -p "Password:" -rs PASSWORD; \ + cmd /C '$(SIGNTOOL) sign /v /fd sha256 /f $(CODE_SIGN) -t $(TIMESTAMP) /p '$$$$PASSWORD' $$@' +endef + +$(eval $(call bossa_msi,x86)) +$(eval $(call bossa_msi,x64)) + +$(INSTALLDIR)\\bossa.cat: $(INSTALLDIR)\\bossa.inf + export TMP=$$(mktemp -d); \ + cp $< $$TMP; \ + cmd /C '$(INF2CAT) /v /driver:'$$(cygpath -w $$TMP)' /os:XP_X86,Vista_X86,Vista_X64,7_X86,7_X64,8_X86,8_X64,6_3_X86,6_3_X64,10_x86,10_x64'; \ + mv $$TMP/bossa.cat $@; \ + rm -rf $$TMP; \ + read -p "Password:" -rs PASSWORD; \ + cmd /C '$(SIGNTOOL) sign /v /fd sha256 /f $(CODE_SIGN) -t $(TIMESTAMP) /p '$$PASSWORD' $@' + +bossa.cat: $(INSTALLDIR)\\bossa.cat + +install32: $(BINDIR)\\bossa-x86-$(VERSION).msi +install64: $(BINDIR)\\bossa-x64-$(VERSION).msi +.PHONY: install +install: strip install32 install64 + +endif + +# +# Linux rules +# +ifeq ($(OS),Linux) +COMMON_SRCS+=PosixSerialPort.cpp LinuxPortFactory.cpp +COMMON_LIBS=-Wl,--as-needed +COMMON_CXXFLAGS=-std=c++11 +WX_LIBS+=-lX11 + +MACHINE:=$(shell uname -m) + +install: strip + tar cvzf $(BINDIR)/bossa-$(MACHINE)-$(VERSION).tgz -C $(BINDIR) bossa$(EXE) bossac$(EXE) bossash$(EXE) +endif + +# +# OS X rules +# +ifeq ($(OS),Darwin) +COMMON_SRCS+=PosixSerialPort.cpp OSXPortFactory.cpp +COMMON_CXXFLAGS=-arch x86_64 -mmacosx-version-min=10.9 +COMMON_LDFLAGS=-arch x86_64 -mmacosx-version-min=10.9 +APP=BOSSA.app +DMG=bossa-$(VERSION).dmg +VOLUME=BOSSA +BACKGROUND=$(INSTALLDIR)/background.png +.PHONY: install +app: + mkdir -p $(BINDIR)/$(APP)/Contents/MacOS + mkdir -p $(BINDIR)/$(APP)/Contents/Resources + cp -f $(INSTALLDIR)/Info.plist $(BINDIR)/$(APP)/Contents + echo -n "APPL????" > $(BINDIR)/$(APP)/Contents/PkgInfo + ln -f $(BINDIR)/bossa $(BINDIR)/$(APP)/Contents/MacOS/bossa + cp -f $(RESDIR)/BossaIcon.icns $(BINDIR)/$(APP)/Contents/Resources +install: strip app + hdiutil create -ov -megabytes 5 -fs HFS+ -volname $(VOLUME) $(BINDIR)/$(DMG) + hdiutil attach -noautoopen $(BINDIR)/$(DMG) + cp -R $(BINDIR)/$(APP) /Volumes/$(VOLUME)/ + cp $(BINDIR)/bossac$(EXE) /Volumes/$(VOLUME)/ + cp $(BINDIR)/bossash$(EXE) /Volumes/$(VOLUME)/ + ln -s /Applications /Volumes/$(VOLUME)/Applications + ln -s /usr/local/bin /Volumes/$(VOLUME)/bin + mkdir /Volumes/$(VOLUME)/.background + cp $(BACKGROUND) /Volumes/$(VOLUME)/.background + osascript < $(INSTALLDIR)/dmgwin.osa + hdiutil detach /Volumes/$(VOLUME)/ + hdiutil convert -format UDBZ -o $(BINDIR)/tmp$(DMG) $(BINDIR)/$(DMG) + mv -f $(BINDIR)/tmp$(DMG) $(BINDIR)/$(DMG) +endif + +# +# OpenBSD rules +# (This is likely to work without changes, but not tested, on other BSDs) +# +ifeq ($(OS),OpenBSD) + +COMMON_SRCS+=PosixSerialPort.cpp BSDPortFactory.cpp + +# This is only needed for bossash, but we can't add it to BOSSASH_LIBS here +# because that one is redefined later. +COMMON_LIBS+=-ltermcap + +# As of 5.7, OpenBSD packages WxWidgets 2.8 +# bossa builds, runs, and appears to play nicely with this version, +# but fails to do anything useful on systems that don't have hardware +# serial ports because of USB detection problems. +# (The SAM's USB programming port doesn't get recognized as a ucom +# device, and a USB serial adaptor attached to the UART gets detected +# by bossa as a USB interface and doesn't fall back to the serial +# programming protocol.) +WXVERSION=2.8 + +endif + +ifeq (${OS},FreeBSD) + +# This is only needed for bossash, but we can't add it to BOSSASH_LIBS here +# because that one is redefined later. +COMMON_SRCS+=PosixSerialPort.cpp BSDPortFactory.cpp + +endif + +# +# Object files +# +COMMON_OBJS=$(foreach src,$(COMMON_SRCS),$(OBJDIR)/$(src:%.cpp=%.o)) +APPLET_OBJS=$(foreach src,$(APPLET_SRCS),$(OBJDIR)/$(src:%.asm=%.o)) +BOSSA_OBJS=$(APPLET_OBJS) $(COMMON_OBJS) $(foreach src,$(BOSSA_SRCS),$(OBJDIR)/$(src:%.cpp=%.o)) +ifdef BOSSA_RC +BOSSA_OBJS+=$(OBJDIR)/$(BOSSA_RC:%.rc=%.o) +endif +BOSSAC_OBJS=$(APPLET_OBJS) $(COMMON_OBJS) $(foreach src,$(BOSSAC_SRCS),$(OBJDIR)/$(src:%.cpp=%.o)) +BOSSASH_OBJS=$(APPLET_OBJS) $(COMMON_OBJS) $(foreach src,$(BOSSASH_SRCS),$(OBJDIR)/$(src:%.cpp=%.o)) + +# +# Dependencies +# +DEPENDS=$(COMMON_SRCS:%.cpp=$(OBJDIR)/%.d) +DEPENDS+=$(APPLET_SRCS:%.asm=$(OBJDIR)/%.d) +DEPENDS+=$(BOSSA_SRCS:%.cpp=$(OBJDIR)/%.d) +DEPENDS+=$(BOSSAC_SRCS:%.cpp=$(OBJDIR)/%.d) +DEPENDS+=$(BOSSASH_SRCS:%.cpp=$(OBJDIR)/%.d) + +# +# Tools +# +Q?=@ +CXX?=g++ +ARM=arm-none-eabi- +ARMAS=$(ARM)as +ARMOBJCOPY=$(ARM)objcopy + +# +# CXX Flags +# +# COMMON_CXXFLAGS+=-Wall -Werror -MT $@ -MD -MP -MF $(@:%.o=%.d) -DVERSION=\"$(VERSION)\" -g -O2 +COMMON_CXXFLAGS+=-Wall -MT $@ -MD -MP -MF $(@:%.o=%.d) -DVERSION=\"$(VERSION)\" -g -O2 $(CXXFLAGS) +WX_CXXFLAGS:=$(shell wx-config --cxxflags --version=$(WXVERSION)) -DWX_PRECOMP -Wno-ctor-dtor-privacy -O2 -fno-strict-aliasing +BOSSA_CXXFLAGS=$(COMMON_CXXFLAGS) $(WX_CXXFLAGS) +BOSSAC_CXXFLAGS=$(COMMON_CXXFLAGS) +BOSSASH_CXXFLAGS=$(COMMON_CXXFLAGS) + +# +# LD Flags +# +COMMON_LDFLAGS+=-g $(LDFLAGS) +BOSSA_LDFLAGS=$(COMMON_LDFLAGS) +BOSSAC_LDFLAGS=$(COMMON_LDFLAGS) +BOSSASH_LDFLAGS=$(COMMON_LDFLAGS) + +# +# Libs +# +COMMON_LIBS+= +WX_LIBS:=$(shell wx-config --libs --version=$(WXVERSION)) $(WX_LIBS) +BOSSA_LIBS=$(COMMON_LIBS) $(WX_LIBS) +BOSSAC_LIBS=$(COMMON_LIBS) +BOSSASH_LIBS=-lreadline $(COMMON_LIBS) + +# +# Main targets +# +all: $(BINDIR)/bossa$(EXE) $(BINDIR)/bossac$(EXE) $(BINDIR)/bossash$(EXE) + +# +# Common rules +# +define common_obj +$(OBJDIR)/$(1:%.cpp=%.o): $(SRCDIR)/$(1) + @echo CPP COMMON $$< + $$(Q)$$(CXX) $$(COMMON_CXXFLAGS) -c -o $$@ $$< +endef +$(foreach src,$(COMMON_SRCS),$(eval $(call common_obj,$(src)))) + +# +# Applet rules +# +define applet_obj +$(SRCDIR)/$(1:%.asm=%.cpp): $(SRCDIR)/$(1) + @echo APPLET $(1:%.asm=%) + $$(Q)$$(ARMAS) -o $$(@:$(SRCDIR)/%.cpp=$(OBJDIR)/%.obj) $$< + $$(Q)$$(ARMOBJCOPY) -O binary $$(@:$(SRCDIR)/%.cpp=$(OBJDIR)/%.obj) $$(@:$(SRCDIR)/%.cpp=$(OBJDIR)/%.bin) + $$(Q)./appletgen $(1:%.asm=%) $(SRCDIR) $(OBJDIR) +$(OBJDIR)/$(1:%.asm=%.o): $(SRCDIR)/$(1:%.asm=%.cpp) + @echo CPP APPLET $$< + $$(Q)$$(CXX) $$(COMMON_CXXFLAGS) -c -o $$(@) $$(<:%.asm=%.cpp) +endef +$(foreach src,$(APPLET_SRCS),$(eval $(call applet_obj,$(src)))) + +# +# BOSSA rules +# +define bossa_obj +$(OBJDIR)/$(1:%.cpp=%.o): $(SRCDIR)/$(1) + @echo CPP BOSSA $$< + $$(Q)$$(CXX) $$(BOSSA_CXXFLAGS) -c -o $$@ $$< +endef +$(foreach src,$(BOSSA_SRCS),$(eval $(call bossa_obj,$(src)))) + +# +# Resource rules +# +ifeq ($(OS),MINGW32) +$(OBJDIR)/$(BOSSA_RC:%.rc=%.o): $(RESDIR)/$(BOSSA_RC) + @echo RC $< + $(Q)`wx-config --rescomp --version=$(WXVERSION)` -o $@ $< +endif + +# +# BOSSAC rules +# +define bossac_obj +$(OBJDIR)/$(1:%.cpp=%.o): $(SRCDIR)/$(1) + @echo CPP BOSSAC $$< + $$(Q)$$(CXX) $$(BOSSAC_CXXFLAGS) -c -o $$@ $$< +endef +$(foreach src,$(BOSSAC_SRCS),$(eval $(call bossac_obj,$(src)))) + +# +# BOSSASH rules +# +define bossash_obj +$(OBJDIR)/$(1:%.cpp=%.o): $(SRCDIR)/$(1) + @echo CPP BOSSASH $$< + $$(Q)$$(CXX) $$(BOSSASH_CXXFLAGS) -c -o $$@ $$< +endef +$(foreach src,$(BOSSASH_SRCS),$(eval $(call bossash_obj,$(src)))) + +# +# BMP rules +# +define bossa_bmp +$(SRCDIR)/$(1:%.bmp=%.cpp): $(RESDIR)/$(1) + @echo BIN2C $$< + $(Q)bin2c $$< $$@ +endef +$(foreach bmp,$(BOSSA_BMPS),$(eval $(call bossa_bmp,$(bmp)))) + +# +# Directory rules +# +$(OBJDIR): + @mkdir $@ + +$(BINDIR): + @mkdir $@ + +# +# Target rules +# +$(BOSSA_OBJS): | $(OBJDIR) +$(BINDIR)/bossa$(EXE): $(foreach bmp,$(BOSSA_BMPS),$(SRCDIR)/$(bmp:%.bmp=%.cpp)) $(BOSSA_OBJS) | $(BINDIR) + @echo LD $@ + $(Q)$(CXX) $(BOSSA_LDFLAGS) -o $@ $(BOSSA_OBJS) $(BOSSA_LIBS) + +$(BOSSAC_OBJS): | $(OBJDIR) +$(BINDIR)/bossac$(EXE): $(BOSSAC_OBJS) | $(BINDIR) + @echo LD $@ + $(Q)$(CXX) $(BOSSAC_LDFLAGS) -o $@ $(BOSSAC_OBJS) $(BOSSAC_LIBS) + +$(BOSSASH_OBJS): | $(OBJDIR) +$(BINDIR)/bossash$(EXE): $(BOSSASH_OBJS) | $(BINDIR) + @echo LD $@ + $(Q)$(CXX) $(BOSSASH_LDFLAGS) -o $@ $(BOSSASH_OBJS) $(BOSSASH_LIBS) + +strip-bossa: $(BINDIR)/bossa$(EXE) + @echo STRIP $^ + $(Q)strip $^ + +strip-bossac: $(BINDIR)/bossac$(EXE) + @echo STRIP $^ + $(Q)strip $^ + +strip-bossash: $(BINDIR)/bossash$(EXE) + @echo STRIP $^ + $(Q)strip $^ + +strip: strip-bossa strip-bossac strip-bossash + +clean: + @echo CLEAN + $(Q)rm -rf $(BINDIR) $(OBJDIR) + +# +# Include dependencies +# +-include $(DEPENDS) diff --git a/lib/bossac/src/Applet.cpp b/lib/bossac/src/Applet.cpp new file mode 100644 index 00000000..7bba24bb --- /dev/null +++ b/lib/bossac/src/Applet.cpp @@ -0,0 +1,64 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// +#include "Applet.h" + +Applet::Applet(Samba& samba, + uint32_t addr, + uint8_t* code, + uint32_t size, + uint32_t start, + uint32_t stack, + uint32_t reset) : + _samba(samba), _addr(addr), _size(size), _start(start), _stack(stack), _reset(reset) +{ + _samba.write(addr, code, size); +} + +void +Applet::setStack(uint32_t stack) +{ + _samba.writeWord(_stack, stack); +} + +void +Applet::run() +{ + // Add one to the start address for Thumb mode + _samba.go(_start + 1); +} + +void +Applet::runv() +{ + // Add one to the start address for Thumb mode + _samba.writeWord(_reset, _start + 1); + + // The stack is the first reset vector + _samba.go(_stack); +} diff --git a/lib/bossac/src/Applet.h b/lib/bossac/src/Applet.h new file mode 100644 index 00000000..4acb504a --- /dev/null +++ b/lib/bossac/src/Applet.h @@ -0,0 +1,65 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// +#ifndef _APPLET_H +#define _APPLET_H + +#include + +#include "Samba.h" + +class Applet +{ +public: + Applet(Samba& samba, + uint32_t addr, + uint8_t* code, + uint32_t size, + uint32_t start, + uint32_t stack, + uint32_t reset); + virtual ~Applet() {} + + virtual uint32_t size() { return _size; } + virtual uint32_t addr() { return _addr; } + + virtual void setStack(uint32_t stack); + + virtual void run(); // To be used for Thumb-1 based devices (ARM7TDMI, ARM9) + virtual void runv(); // To be used for Thumb-2 based devices (Cortex-Mx) + +protected: + Samba& _samba; + uint32_t _addr; // Address in device SRAM where will be placed the applet + uint32_t _size; // Applet size + uint32_t _start; // + uint32_t _stack; // Applet stack address in device SRAM + uint32_t _reset; +}; + +#endif // _APPLET_H diff --git a/lib/bossac/src/CmdOpts.cpp b/lib/bossac/src/CmdOpts.cpp new file mode 100644 index 00000000..675f7e1d --- /dev/null +++ b/lib/bossac/src/CmdOpts.cpp @@ -0,0 +1,159 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include + +#include "CmdOpts.h" + +CmdOpts::CmdOpts(int argc, char* argv[], int numOpts, Option* opts) : + _argc(argc), _argv(argv), _numOpts(numOpts), _opts(opts) +{ +} + +CmdOpts::~CmdOpts() +{ +} + +void +CmdOpts::usage(FILE* out) +{ + int optIdx; + char name[40]; + const char* start; + const char* end; + + for (optIdx = 0; optIdx < _numOpts; optIdx++) + { + if (_opts[optIdx].arg.has == ArgOptional) + snprintf(name, sizeof(name), " -%c, --%s[=%s]", + _opts[optIdx].letter, + _opts[optIdx].name, + _opts[optIdx].arg.name); + else if (_opts[optIdx].arg.has == ArgRequired) + snprintf(name, sizeof(name), " -%c, --%s=%s", + _opts[optIdx].letter, + _opts[optIdx].name, + _opts[optIdx].arg.name); + else + snprintf(name, sizeof(name), " -%c, --%s", + _opts[optIdx].letter, + _opts[optIdx].name); + + fprintf(out, "%-23s ", name); + + start = _opts[optIdx].help; + while ((end = strchr(start, '\n'))) + { + fwrite(start, end - start + 1, 1, out); + fprintf(out, "%24s", ""); + start = end + 1; + } + fprintf(out, "%s\n", start); + } +} + +int +CmdOpts::parse() +{ + struct option long_opts[_numOpts + 1]; + char optstring[_numOpts * 3 + 1]; + char* optPtr = optstring; + int optIdx; + int rc; + + for (optIdx = 0; optIdx < _numOpts; optIdx++) + { + *_opts[optIdx].present = false; + + *optPtr++ = _opts[optIdx].letter; + long_opts[optIdx].name = _opts[optIdx].name; + switch (_opts[optIdx].arg.has) + { + default: + case ArgNone: + long_opts[optIdx].has_arg = no_argument; + break; + case ArgOptional: + long_opts[optIdx].has_arg = optional_argument; + *optPtr++ = ':'; + *optPtr++ = ':'; + break; + case ArgRequired: + long_opts[optIdx].has_arg = required_argument; + *optPtr++ = ':'; + break; + } + long_opts[optIdx].flag = NULL; + long_opts[optIdx].val = 0; + } + + memset(&long_opts[_numOpts], 0, sizeof(long_opts[_numOpts])); + *optPtr = '\0'; + optIdx = 0; + while ((rc = getopt_long(_argc, _argv, optstring, long_opts, &optIdx)) != -1) + { + if (rc == '?') + return -1; + + if (rc != 0) + optIdx = find(rc); + + assert(optIdx >= 0 && optIdx < _numOpts); + *_opts[optIdx].present = true; + if (_opts[optIdx].arg.has != ArgNone && optarg) + { + switch (_opts[optIdx].arg.type) + { + case ArgInt: + *_opts[optIdx].arg.value.intPtr = strtol(optarg, NULL, 0); + break; + default: + case ArgString: + *_opts[optIdx].arg.value.strPtr = optarg; + break; + } + } + } + + return optind; +} + +int +CmdOpts::find(char letter) +{ + int optIdx; + + for (optIdx = 0; optIdx < _numOpts; optIdx++) + if (_opts[optIdx].letter == letter) + break; + + return optIdx; +} diff --git a/lib/bossac/src/CmdOpts.h b/lib/bossac/src/CmdOpts.h new file mode 100644 index 00000000..f752a5df --- /dev/null +++ b/lib/bossac/src/CmdOpts.h @@ -0,0 +1,88 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// +#ifndef _OPTION_H +#define _OPTION_H + +#include +#include + +typedef enum +{ + ArgNone, + ArgOptional, + ArgRequired +} ArgHas; + +typedef enum +{ + ArgInt, + ArgString +} ArgType; + +typedef struct +{ + ArgHas has; + ArgType type; + const char* name; + union + { + void* voidPtr; + int* intPtr; + std::string* strPtr; + } value; +} OptArg; + +typedef struct +{ + char letter; + const char* name; + bool* present; + OptArg arg; + const char* help; +} Option; + +class CmdOpts +{ +public: + CmdOpts(int argc, char* argv[], int numOpts, Option* opts); + virtual ~CmdOpts(); + + void usage(FILE* out); + int parse(); + +private: + int _argc; + char** _argv; + int _numOpts; + Option* _opts; + + int find(char letter); +}; + +#endif // _OPTION_H diff --git a/lib/bossac/src/D2xNvmFlash.cpp b/lib/bossac/src/D2xNvmFlash.cpp new file mode 100644 index 00000000..0974936c --- /dev/null +++ b/lib/bossac/src/D2xNvmFlash.cpp @@ -0,0 +1,347 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2018, ShumaTech +// +// 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 3 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. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +/////////////////////////////////////////////////////////////////////////////// + +#include "D2xNvmFlash.h" + +// CMDEX field should be 0xA5 to allow execution of any command. +#define CMDEX_KEY 0xa500 + +// NVM ready bit mask +#define NVM_INT_STATUS_READY_MASK 0x1 + +// NVM status mask +#define NVM_CTRL_STATUS_MASK 0xFFEB + +#define NVM_REG_BASE 0x41004000 + +#define NVM_REG_CTRLA 0x00 +#define NVM_REG_CTRLB 0x04 +#define NVM_REG_INTFLAG 0x14 +#define NVM_REG_STATUS 0x18 +#define NVM_REG_ADDR 0x1c +#define NVM_REG_LOCK 0x20 + +#define NVM_CMD_ER 0x02 +#define NVM_CMD_WP 0x04 +#define NVM_CMD_EAR 0x05 +#define NVM_CMD_WAP 0x06 +#define NVM_CMD_LR 0x40 +#define NVM_CMD_UR 0x41 +#define NVM_CMD_SSB 0x45 +#define NVM_CMD_PBC 0x44 + +#define ERASE_ROW_PAGES 4 // pages + +// NVM User Row +#define NVM_UR_ADDR 0x804000 +#define NVM_UR_SIZE (_size * ERASE_ROW_PAGES) +#define NVM_UR_BOD33_ENABLE_OFFSET 0x1 +#define NVM_UR_BOD33_ENABLE_MASK 0x6 +#define NVM_UR_BOD33_RESET_OFFSET 0x1 +#define NVM_UR_BOD33_RESET_MASK 0x7 +#define NVM_UR_NVM_LOCK_OFFSET 0x6 + +D2xNvmFlash::D2xNvmFlash( + Samba& samba, + const std::string& name, + uint32_t pages, + uint32_t size, + uint32_t user, + uint32_t stack) + : + Flash(samba, name, 0, pages, size, 1, 16, user, stack), _eraseAuto(true) +{ +} + +D2xNvmFlash::~D2xNvmFlash() +{ +} + +void +D2xNvmFlash::erase(uint32_t offset, uint32_t size) +{ + uint32_t eraseSize = _size * ERASE_ROW_PAGES; + + // Offset must be a multiple of the erase size + if (offset % eraseSize) + throw FlashEraseError(); + + // Offset and size must be in range + if (offset + size > totalSize()) + throw FlashEraseError(); + + uint32_t eraseEnd = (offset + size + eraseSize - 1) / eraseSize; + + // Erase each erase size set of pages + for (uint32_t eraseNum = offset / eraseSize; eraseNum < eraseEnd; eraseNum++) + { + waitReady(); + + // Clear error bits + uint16_t statusReg = readReg(NVM_REG_STATUS); + writeReg(NVM_REG_STATUS, statusReg | NVM_CTRL_STATUS_MASK); + + // Issue erase command + uint32_t wordAddr = (eraseNum * eraseSize) / 2; + writeReg(NVM_REG_ADDR, wordAddr); + command(NVM_CMD_ER); + } +} + +void +D2xNvmFlash::eraseAll(uint32_t offset) +{ + // Use the extended Samba command if available + if (_samba.canChipErase()) + { + _samba.chipErase(offset); + } + else + { + erase(offset, totalSize() - offset); + } +} + +void +D2xNvmFlash::eraseAuto(bool enable) +{ + _eraseAuto = enable; +} + +std::vector +D2xNvmFlash::getLockRegions() +{ + uint8_t lockBits = 0; + uint32_t addr = NVM_UR_ADDR + NVM_UR_NVM_LOCK_OFFSET; + std::vector regions(_lockRegions); + + for (uint32_t region = 0; region < _lockRegions; region++) + { + if (region % 8 == 0) + lockBits = _samba.readByte(addr++); + regions[region] = (lockBits & (1 << (region % 8))) == 0; + } + + return regions; +} + +bool +D2xNvmFlash::getSecurity() +{ + return (readReg(NVM_REG_STATUS) & 0x100) != 0; +} + +bool +D2xNvmFlash::getBod() +{ + uint8_t byte = _samba.readByte(NVM_UR_ADDR + NVM_UR_BOD33_ENABLE_OFFSET); + + return (byte & NVM_UR_BOD33_ENABLE_MASK) != 0; +} + +bool +D2xNvmFlash::getBor() +{ + uint8_t byte = _samba.readByte(NVM_UR_ADDR + NVM_UR_BOD33_RESET_OFFSET); + + return (byte & NVM_UR_BOD33_RESET_MASK) != 0; +} + +bool +D2xNvmFlash::getBootFlash() +{ + return true; +} + +void +D2xNvmFlash::readUserRow(std::unique_ptr& userRow) +{ + if (!userRow) + { + userRow.reset(new uint8_t[NVM_UR_SIZE]); + _samba.read(NVM_UR_ADDR, userRow.get(), NVM_UR_SIZE); + } +} + +void +D2xNvmFlash::writeOptions() +{ + std::unique_ptr userRow; + + if (canBor() && _bor.isDirty() && _bor.get() != getBor()) + { + readUserRow(userRow); + if (_bor.get()) + userRow[NVM_UR_BOD33_RESET_OFFSET] |= NVM_UR_BOD33_RESET_MASK; + else + userRow[NVM_UR_BOD33_RESET_OFFSET] &= ~NVM_UR_BOD33_RESET_MASK; + } + if (canBod() && _bod.isDirty() && _bod.get() != getBod()) + { + readUserRow(userRow); + if (_bod.get()) + userRow[NVM_UR_BOD33_ENABLE_OFFSET] |= NVM_UR_BOD33_ENABLE_MASK; + else + userRow[NVM_UR_BOD33_ENABLE_OFFSET] &= ~NVM_UR_BOD33_ENABLE_MASK; + } + if (_regions.isDirty()) + { + // Check if any lock bits are different from the current set + std::vector current = getLockRegions(); + if (!equal(_regions.get().begin(), _regions.get().end(), current.begin())) + { + readUserRow(userRow); + + uint8_t* lockBits = &userRow[NVM_UR_NVM_LOCK_OFFSET]; + for (uint32_t region = 0; region < _regions.get().size(); region++) + { + if (_regions.get()[region]) + lockBits[region / 8] &= ~(1 << (region % 8)); + else + lockBits[region / 8] |= (1 << (region % 8)); + } + } + } + + // Erase and write the user row if modified + if (userRow) + { + // Disable cache and configure manual page write + writeReg(NVM_REG_CTRLB, readReg(NVM_REG_CTRLB) | (0x1 << 18) | (0x1 << 7)); + + // Erase user row + writeReg(NVM_REG_ADDR, NVM_UR_ADDR / 2); + command(NVM_CMD_EAR); + + // Write user row in page chunks + for (uint32_t offset = 0; offset < NVM_UR_SIZE; offset += _size) + { + // Load the buffer with the page + loadBuffer(&userRow[offset], _size); + + // Clear page buffer + command(NVM_CMD_PBC); + + // Copy page to page buffer + _wordCopy.setDstAddr(NVM_UR_ADDR + offset); + _wordCopy.setSrcAddr(_onBufferA ? _pageBufferA : _pageBufferB); + _onBufferA = !_onBufferA; + waitReady(); + _wordCopy.runv(); + + // Write the page + writeReg(NVM_REG_ADDR, (NVM_UR_ADDR + offset) / 2); + command(NVM_CMD_WAP); + } + } + + // Always do security last + if (_security.isDirty() && _security.get() == true && _security.get() != getSecurity()) + { + command(NVM_CMD_SSB); + } +} + +void +D2xNvmFlash::writePage(uint32_t page) +{ + if (page >= _pages) + { + throw FlashPageError(); + } + + // Disable cache and configure manual page write + writeReg(NVM_REG_CTRLB, readReg(NVM_REG_CTRLB) | (0x1 << 18) | (0x1 << 7)); + + // Auto-erase if writing at the start of the erase page + if (_eraseAuto && page % ERASE_ROW_PAGES == 0) + erase(page * _size, ERASE_ROW_PAGES * _size); + + // Clear page buffer + command(NVM_CMD_PBC); + + // Compute the start address. + uint32_t addr = _addr + (page * _size); + + _wordCopy.setDstAddr(addr); + _wordCopy.setSrcAddr(_onBufferA ? _pageBufferA : _pageBufferB); + _onBufferA = !_onBufferA; + waitReady(); + _wordCopy.runv(); + + writeReg(NVM_REG_ADDR, addr / 2); + command(NVM_CMD_WP); +} + +void +D2xNvmFlash::waitReady() +{ + while ((readReg(NVM_REG_INTFLAG) & 0x1) == 0); +} + +void +D2xNvmFlash::readPage(uint32_t page, uint8_t* buf) +{ + if (page >= _pages) + { + throw FlashPageError(); + } + + _samba.read(_addr + (page * _size), buf, _size); +} + +uint32_t +D2xNvmFlash::readReg(uint8_t reg) +{ + return _samba.readWord(NVM_REG_BASE + reg); +} + +void +D2xNvmFlash::writeReg(uint8_t reg, uint32_t value) +{ + _samba.writeWord(NVM_REG_BASE + reg, value); +} + +void +D2xNvmFlash::command(uint8_t cmd) +{ + waitReady(); + + writeReg(NVM_REG_CTRLA, CMDEX_KEY | cmd); + + waitReady(); + + if (readReg(NVM_REG_INTFLAG) & 0x2) + { + // Clear the error bit + writeReg(NVM_REG_INTFLAG, 0x2); + throw FlashCmdError(); + } +} + +void +D2xNvmFlash::writeBuffer(uint32_t dst_addr, uint32_t size) +{ + // Auto-erase if enabled + if (_eraseAuto) + erase(dst_addr, size); + + // Call the base class method + Flash::writeBuffer(dst_addr, size); +} diff --git a/lib/bossac/src/D2xNvmFlash.h b/lib/bossac/src/D2xNvmFlash.h new file mode 100644 index 00000000..d7c36948 --- /dev/null +++ b/lib/bossac/src/D2xNvmFlash.h @@ -0,0 +1,76 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2018, ShumaTech +// +// 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 3 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. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _D2XNVMFLASH_H +#define _D2XNVMFLASH_H + +#include +#include + +#include "Flash.h" + +class D2xNvmFlash : public Flash +{ +public: + D2xNvmFlash( + Samba& samba, + const std::string& name, + uint32_t pages, + uint32_t size, + uint32_t user, + uint32_t stack); + + virtual ~D2xNvmFlash(); + + void eraseAll(uint32_t offset); + void eraseAuto(bool enable); + + std::vector getLockRegions(); + + bool getSecurity(); + + bool getBod(); + bool canBod() { return true; } + + bool getBor(); + bool canBor() { return true; } + + bool getBootFlash(); + bool canBootFlash() { return false; } + + void writeOptions(); + + void writePage(uint32_t page); + void readPage(uint32_t page, uint8_t* data); + + void writeBuffer(uint32_t dst_addr, uint32_t size); + +protected: + bool _eraseAuto; + + uint32_t readReg(uint8_t reg); + void writeReg(uint8_t reg, uint32_t value); + + void waitReady(); + void command(uint8_t cmd); + void erase(uint32_t offset, uint32_t size); + void readUserRow(std::unique_ptr& userRow); +}; + +#endif // _D2XNVMFLASH_H diff --git a/lib/bossac/src/D5xNvmFlash.cpp b/lib/bossac/src/D5xNvmFlash.cpp new file mode 100644 index 00000000..81e5583f --- /dev/null +++ b/lib/bossac/src/D5xNvmFlash.cpp @@ -0,0 +1,352 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2018, ShumaTech +// +// 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 3 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. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +/////////////////////////////////////////////////////////////////////////////// + +#include "D5xNvmFlash.h" + + +#define CMDEX_KEY 0xa500 + +#define NVM_REG_BASE 0x41004000 + +#define NVM_REG_CTRLA 0x00 +#define NVM_REG_CTRLB 0x04 +#define NVM_REG_INTFLAG 0x10 +#define NVM_REG_STATUS 0x12 +#define NVM_REG_ADDR 0x14 +#define NVM_REG_RUNLOCK 0x18 + +#define NVM_CMD_EP 0x00 +#define NVM_CMD_EB 0x01 +#define NVM_CMD_WP 0x03 +#define NVM_CMD_WQW 0x04 +#define NVM_CMD_LR 0x11 +#define NVM_CMD_UR 0x12 +#define NVM_CMD_SSB 0x16 +#define NVM_CMD_PBC 0x15 + +#define ERASE_BLOCK_PAGES 16 // pages + +// NVM User Page +#define NVM_UP_ADDR 0x804000 +#define NVM_UP_SIZE (_size) +#define NVM_UP_BOD33_DISABLE_OFFSET 0x0 +#define NVM_UP_BOD33_DISABLE_MASK 0x1 +#define NVM_UP_BOD33_RESET_OFFSET 0x1 +#define NVM_UP_BOD33_RESET_MASK 0x2 +#define NVM_UP_NVM_LOCK_OFFSET 0x8 + +D5xNvmFlash::D5xNvmFlash( + Samba& samba, + const std::string& name, + uint32_t pages, + uint32_t size, + uint32_t user, + uint32_t stack) + : + Flash(samba, name, 0, pages, size, 1, 32, user, stack), _eraseAuto(true) +{ +} + +D5xNvmFlash::~D5xNvmFlash() +{ +} + +void +D5xNvmFlash::erase(uint32_t offset, uint32_t size) +{ + uint32_t eraseSize = _size * ERASE_BLOCK_PAGES; + + // Offset must be a multiple of the erase size + if (offset % eraseSize) + throw FlashEraseError(); + + // Offset and size must be in range + if (offset + size > totalSize()) + throw FlashEraseError(); + + uint32_t eraseEnd = (offset + size + eraseSize - 1) / eraseSize; + + // Erase each erase size set of pages + for (uint32_t eraseNum = offset / eraseSize; eraseNum < eraseEnd; eraseNum++) + { + // Issue erase command + writeRegU32(NVM_REG_ADDR, eraseNum * eraseSize); + command(NVM_CMD_EB); + } +} + +void +D5xNvmFlash::eraseAll(uint32_t offset) +{ + // Use the extended Samba command if available + if (_samba.canChipErase()) + { + _samba.chipErase(offset); + } + else + { + erase(offset, totalSize() - offset); + } +} + +void +D5xNvmFlash::waitReady() +{ + while ((readRegU16(NVM_REG_STATUS) & 0x1) == 0); +} + +void +D5xNvmFlash::eraseAuto(bool enable) +{ + _eraseAuto = enable; +} + +std::vector +D5xNvmFlash::getLockRegions() +{ + uint8_t lockBits = 0; + uint32_t addr = NVM_UP_ADDR + NVM_UP_NVM_LOCK_OFFSET; + std::vector regions(_lockRegions); + + for (uint32_t region = 0; region < _lockRegions; region++) + { + if (region % 8 == 0) + lockBits = _samba.readByte(addr++); + regions[region] = (lockBits & (1 << (region % 8))) == 0; + } + + return regions; +} + +bool +D5xNvmFlash::getSecurity() +{ + // There doesn't seem to be a way to read this + return false; +} + +bool +D5xNvmFlash::getBod() +{ + uint8_t byte = _samba.readByte(NVM_UP_ADDR + NVM_UP_BOD33_DISABLE_OFFSET); + + return (byte & NVM_UP_BOD33_DISABLE_MASK) == 0; +} + +bool +D5xNvmFlash::getBor() +{ + uint8_t byte = _samba.readByte(NVM_UP_ADDR + NVM_UP_BOD33_RESET_OFFSET); + + return (byte & NVM_UP_BOD33_RESET_MASK) != 0; +} + +bool +D5xNvmFlash::getBootFlash() +{ + return true; +} + +void +D5xNvmFlash::readUserPage(std::unique_ptr& userPage) +{ + if (!userPage) + { + userPage.reset(new uint8_t[NVM_UP_SIZE]); + _samba.read(NVM_UP_ADDR, userPage.get(), NVM_UP_SIZE); + } +} + +void +D5xNvmFlash::writeOptions() +{ + std::unique_ptr userPage; + + if (canBor() && _bor.isDirty() && _bor.get() != getBor()) + { + readUserPage(userPage); + if (_bor.get()) + userPage[NVM_UP_BOD33_RESET_OFFSET] |= NVM_UP_BOD33_RESET_MASK; + else + userPage[NVM_UP_BOD33_RESET_OFFSET] &= ~NVM_UP_BOD33_RESET_MASK; + } + if (canBod() && _bod.isDirty() && _bod.get() != getBod()) + { + readUserPage(userPage); + if (_bod.get()) + userPage[NVM_UP_BOD33_DISABLE_OFFSET] &= ~NVM_UP_BOD33_DISABLE_MASK; + else + userPage[NVM_UP_BOD33_DISABLE_OFFSET] |= NVM_UP_BOD33_DISABLE_MASK; + } + if (_regions.isDirty()) + { + // Check if any lock bits are different from the current set + std::vector current = getLockRegions(); + if (!equal(_regions.get().begin(), _regions.get().end(), current.begin())) + { + readUserPage(userPage); + + uint8_t* lockBits = &userPage[NVM_UP_NVM_LOCK_OFFSET]; + for (uint32_t region = 0; region < _regions.get().size(); region++) + { + if (_regions.get()[region]) + lockBits[region / 8] &= ~(1 << (region % 8)); + else + lockBits[region / 8] |= (1 << (region % 8)); + } + } + } + + // Erase and write the user page if modified + if (userPage) + { + // Configure manual page write and disable caches + writeRegU16(NVM_REG_CTRLA, (readRegU16(NVM_REG_CTRLA) | (0x3 << 14)) & 0xffcf); + + // Erase user page + writeRegU32(NVM_REG_ADDR, NVM_UP_ADDR); + command(NVM_CMD_EP); + + // Write user page in quad-word chunks + for (uint32_t offset = 0; offset < NVM_UP_SIZE; offset += 16) + { + // Load the buffer with the quad word + loadBuffer(&userPage[offset], 16); + + // Clear page buffer + command(NVM_CMD_PBC); + + // Copy quad word to page buffer + _wordCopy.setDstAddr(NVM_UP_ADDR + offset); + _wordCopy.setSrcAddr(_onBufferA ? _pageBufferA : _pageBufferB); + _wordCopy.setWords(4); + _onBufferA = !_onBufferA; + waitReady(); + _wordCopy.runv(); + + // Write the quad word + writeRegU32(NVM_REG_ADDR, NVM_UP_ADDR + offset); + command(NVM_CMD_WQW); + } + } + + // Always do security last + if (_security.isDirty() && _security.get() == true && _security.get() != getSecurity()) + { + command(NVM_CMD_SSB); + } +} + +void +D5xNvmFlash::writePage(uint32_t page) +{ + if (page >= _pages) + { + throw FlashPageError(); + } + + // Configure manual page write and disable caches + writeRegU16(NVM_REG_CTRLA, (readRegU16(NVM_REG_CTRLA) | (0x3 << 14)) & 0xffcf); + + // Auto-erase if writing at the start of the erase page + if (_eraseAuto && page % ERASE_BLOCK_PAGES == 0) + { + erase(page * _size, ERASE_BLOCK_PAGES * _size); + } + + // Clear page bur + command(NVM_CMD_PBC); + + uint32_t addr = _addr + (page * _size ); + + _wordCopy.setDstAddr(addr); + _wordCopy.setSrcAddr(_onBufferA ? _pageBufferA : _pageBufferB); + _wordCopy.setWords(_size / sizeof(uint32_t)); + _onBufferA = !_onBufferA; + waitReady(); + _wordCopy.runv(); + + writeRegU32(NVM_REG_ADDR, addr); + command(NVM_CMD_WP); +} + +void +D5xNvmFlash::readPage(uint32_t page, uint8_t* buf) +{ + if (page >= _pages) + { + throw FlashPageError(); + } + + _samba.read(_addr + (page * _size), buf, _size); +} + +uint16_t +D5xNvmFlash::readRegU16(uint8_t reg) +{ + return (uint16_t) _samba.readByte(NVM_REG_BASE + reg) | + (_samba.readByte(NVM_REG_BASE + reg + 1) << 8); +} + +void +D5xNvmFlash::writeRegU16(uint8_t reg, uint16_t value) +{ + _samba.writeByte(NVM_REG_BASE + reg, value & 0xff); + _samba.writeByte(NVM_REG_BASE + reg + 1, value >> 8); +} + +uint32_t +D5xNvmFlash::readRegU32(uint8_t reg) +{ + return _samba.readWord(NVM_REG_BASE + reg); +} + +void +D5xNvmFlash::writeRegU32(uint8_t reg, uint32_t value) +{ + _samba.writeWord(NVM_REG_BASE + reg, value); +} + +void +D5xNvmFlash::command(uint8_t cmd) +{ + waitReady(); + + writeRegU32(NVM_REG_CTRLB, CMDEX_KEY | cmd); + + waitReady(); + + if (readRegU16(NVM_REG_INTFLAG) & 0xce) + { + // Clear the error bits + writeRegU16(NVM_REG_INTFLAG, 0xce); + throw FlashCmdError(); + } +} + +void +D5xNvmFlash::writeBuffer(uint32_t dst_addr, uint32_t size) +{ + // Auto-erase if writing at the start of the erase page + if (_eraseAuto && ((dst_addr / _size) % ERASE_BLOCK_PAGES == 0)) + erase(dst_addr, size); + + // Call the base class method + Flash::writeBuffer(dst_addr, size); +} diff --git a/lib/bossac/src/D5xNvmFlash.h b/lib/bossac/src/D5xNvmFlash.h new file mode 100644 index 00000000..d266f588 --- /dev/null +++ b/lib/bossac/src/D5xNvmFlash.h @@ -0,0 +1,79 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2018, ShumaTech +// +// 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 3 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. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _D5XNVMFLASH_H +#define _D5XNVMFLASH_H + +#include +#include + +#include "Flash.h" + +class D5xNvmFlash : public Flash +{ +public: + D5xNvmFlash( + Samba& samba, + const std::string& name, + uint32_t pages, + uint32_t size, + uint32_t user, + uint32_t stack); + + virtual ~D5xNvmFlash(); + + void eraseAll(uint32_t offset); + void eraseAuto(bool enable); + + std::vector getLockRegions(); + + bool getSecurity(); + + bool getBod(); + bool canBod() { return true; } + + bool getBor(); + bool canBor() { return true; } + + bool getBootFlash(); + bool canBootFlash() { return false; } + + void writeOptions(); + + void writePage(uint32_t page); + void readPage(uint32_t page, uint8_t* data); + + void writeBuffer(uint32_t dst_addr, uint32_t size); + +protected: + bool _eraseAuto; + + uint16_t readRegU16(uint8_t reg); + void writeRegU16(uint8_t reg, uint16_t value); + uint32_t readRegU32(uint8_t reg); + void writeRegU32(uint8_t reg, uint32_t value); + + void waitReady(); + void command(uint8_t cmd); + void erase(uint32_t offset, uint32_t size); + void checkError(); + void readUserPage(std::unique_ptr& userPage); +}; + +#endif // _D5XNVMFLASH_H diff --git a/lib/bossac/src/Device.cpp b/lib/bossac/src/Device.cpp new file mode 100644 index 00000000..457570ec --- /dev/null +++ b/lib/bossac/src/Device.cpp @@ -0,0 +1,692 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// +#include "Device.h" +#include "EfcFlash.h" +#include "EefcFlash.h" +#include "D2xNvmFlash.h" +#include "D5xNvmFlash.h" + +void +Device::readChipId(uint32_t& chipId, uint32_t& extChipId) +{ + if ((chipId = _samba.readWord(0x400e0740)) != 0) + { + extChipId = _samba.readWord(0x400e0744); + } + else if ((chipId = _samba.readWord(0x400e0940)) != 0) + { + extChipId = _samba.readWord(0x400e0944); + } +} + +void +Device::create() +{ + Flash* flashPtr; + uint32_t chipId = 0; + uint32_t cpuId = 0; + uint32_t extChipId = 0; + uint32_t deviceId = 0; + + // Device identification must be performed carefully to avoid reading from + // addresses that devices do not support which will lock up the CPU + + // All devices support addresss 0 as the ARM reset vector so if the vector is + // a ARM7TDMI branch, then assume we have an Atmel SAM7/9 CHIPID register + if ((_samba.readWord(0x0) & 0xff000000) == 0xea000000) + { + chipId = _samba.readWord(0xfffff240); + } + else + { + // Next try the ARM CPUID register since all Cortex-M devices support it + cpuId = _samba.readWord(0xe000ed00) & 0x0000fff0; + + // Cortex-M0+ + if (cpuId == 0xC600) + { + // These should support the ARM device ID register + deviceId = _samba.readWord(0x41002018); + } + // Cortex-M4 + else if (cpuId == 0xC240) + { + // SAM4 processors have a reset vector to the SAM-BA ROM + if ((_samba.readWord(0x4) & 0xfff00000) == 0x800000) + { + readChipId(chipId, extChipId); + } + // Else we should have a device that supports the ARM device ID register + else + { + deviceId = _samba.readWord(0x41002018); + } + } + // For all other Cortex versions try the Atmel chip ID registers + else + { + readChipId(chipId, extChipId); + } + } + + // Instantiate the proper flash for the device + switch (chipId & 0x7fffffe0) + { + // + // SAM7SE + // + case 0x272a0a40: + _family = FAMILY_SAM7SE; + flashPtr = new EfcFlash(_samba, "AT91SAM7SE512", 0x100000, 2048, 256, 2, 32, 0x202000, 0x208000, true); + break; + case 0x272a0940: + _family = FAMILY_SAM7SE; + flashPtr = new EfcFlash(_samba, "AT91SAM7SE256", 0x100000, 1024, 256, 1, 16, 0x202000, 0x208000, true); + break; + case 0x272a0340: + _family = FAMILY_SAM7SE; + flashPtr = new EfcFlash(_samba, "AT91SAM7SE32", 0x100000, 256, 128, 1, 8, 0x201400, 0x201C00, true); + break; + // + // SAM7S + // + case 0x270b0a40: + _family = FAMILY_SAM7S; + flashPtr = new EfcFlash(_samba, "AT91SAM7S512", 0x100000, 2048, 256, 2, 32, 0x202000, 0x210000, false); + break; + case 0x270d0940: // A + case 0x270b0940: // B/C + _family = FAMILY_SAM7S; + flashPtr = new EfcFlash(_samba, "AT91SAM7S256", 0x100000, 1024, 256, 1, 16, 0x202000, 0x210000, false); + break; + case 0x270c0740: // A + case 0x270a0740: // B/C + _family = FAMILY_SAM7S; + flashPtr = new EfcFlash(_samba, "AT91SAM7S128", 0x100000, 512, 256, 1, 8, 0x202000, 0x208000, false); + break; + case 0x27090540: + _family = FAMILY_SAM7S; + flashPtr = new EfcFlash(_samba, "AT91SAM7S64", 0x100000, 512, 128, 1, 16, 0x202000, 0x204000, false); + break; + case 0x27080340: + _family = FAMILY_SAM7S; + flashPtr = new EfcFlash(_samba, "AT91SAM7S32", 0x100000, 256, 128, 1, 8, 0x201400, 0x202000, false); + break; + case 0x27050240: + _family = FAMILY_SAM7S; + flashPtr = new EfcFlash(_samba, "AT91SAM7S16", 0x100000, 256, 64, 1, 8, 0x200000, 0x200e00, false); + break; + // + // SAM7XC + // + case 0x271c0a40: + _family = FAMILY_SAM7XC; + flashPtr = new EfcFlash(_samba, "AT91SAMXC512", 0x100000, 2048, 256, 2, 32, 0x202000, 0x220000, true); + break; + case 0x271b0940: + _family = FAMILY_SAM7XC; + flashPtr = new EfcFlash(_samba, "AT91SAMXC256", 0x100000, 1024, 256, 1, 16, 0x202000, 0x210000, true); + break; + case 0x271a0740: + _family = FAMILY_SAM7XC; + flashPtr = new EfcFlash(_samba, "AT91SAMXC128", 0x100000, 512, 256, 1, 8, 0x202000, 0x208000, true); + break; + // + // SAM7X + // + case 0x275c0a40: + _family = FAMILY_SAM7X; + flashPtr = new EfcFlash(_samba, "AT91SAMX512", 0x100000, 2048, 256, 2, 32, 0x202000, 0x220000, true); + break; + case 0x275b0940: + _family = FAMILY_SAM7X; + flashPtr = new EfcFlash(_samba, "AT91SAMX256", 0x100000, 1024, 256, 1, 16, 0x202000, 0x210000, true); + break; + case 0x275a0740: + _family = FAMILY_SAM7X; + flashPtr = new EfcFlash(_samba, "AT91SAMX128", 0x100000, 512, 256, 1, 8, 0x202000, 0x208000, true); + break; + // + // SAM4S + // + case 0x29870ee0: // A + case 0x29970ee0: // B + case 0x29A70ee0: // C + _family = FAMILY_SAM4S; + flashPtr = new EefcFlash(_samba, "ATSAM4SD32", 0x400000, 4096, 512, 2, 256, 0x20001000, 0x20010000, 0x400e0a00, false); + break; + case 0x29870c30: // A + case 0x29970c30: // B + case 0x29a70c30: // C + _family = FAMILY_SAM4S; + flashPtr = new EefcFlash(_samba, "ATSAM4SD16", 0x400000, 2048, 512, 2, 256, 0x20001000, 0x20010000, 0x400e0a00, false); + break; + case 0x28870ce0: // A + case 0x28970ce0: // B + case 0x28A70ce0: // C + _family = FAMILY_SAM4S; + flashPtr = new EefcFlash(_samba, "ATSAM4SA16", 0x400000, 2048, 512, 1, 256, 0x20001000, 0x20010000, 0x400e0a00, false); + break; + case 0x288c0ce0 : // A + case 0x289c0ce0 : // B + case 0x28ac0ce0 : // C + _family = FAMILY_SAM4S; + flashPtr = new EefcFlash(_samba, "ATSAM4S16", 0x400000, 2048, 512, 1, 128, 0x20001000, 0x20020000, 0x400e0a00, false); + break; + case 0x288c0ae0 : // A + case 0x289c0ae0 : // B + case 0x28ac0ae0 : // C + _family = FAMILY_SAM4S; + flashPtr = new EefcFlash(_samba, "ATSAM4S8", 0x400000, 1024, 512, 1, 64, 0x20001000, 0x20020000, 0x400e0a00, false); + break; + case 0x288b09e0 : // A + case 0x289b09e0 : // B + case 0x28ab09e0 : // C + _family = FAMILY_SAM4S; + flashPtr = new EefcFlash(_samba, "ATSAM4S4", 0x400000, 512, 512, 1, 16, 0x20001000, 0x20010000, 0x400e0a00, false); + break; + case 0x288b07e0 : // A + case 0x289b07e0 : // B + case 0x28ab07e0 : // C + _family = FAMILY_SAM4S; + flashPtr = new EefcFlash(_samba, "ATSAM4S2", 0x400000, 256, 512, 1, 16, 0x20001000, 0x20010000, 0x400e0a00, false); + break; + // + // SAM3N + // + case 0x29340960 : // A + case 0x29440960 : // B + case 0x29540960 : // C + _family = FAMILY_SAM3N; + flashPtr = new EefcFlash(_samba, "ATSAM3N4", 0x400000, 1024, 256, 1, 16, 0x20001000, 0x20006000, 0x400e0a00, false); + break; + case 0x29390760 : // A + case 0x29490760 : // B + case 0x29590760 : // C + _family = FAMILY_SAM3N; + flashPtr = new EefcFlash(_samba, "ATSAM3N2", 0x400000, 512, 256, 1, 8, 0x20001000, 0x20004000, 0x400e0a00, false); + break; + case 0x29380560 : // A + case 0x29480560 : // B + case 0x29580560 : // C + _family = FAMILY_SAM3N; + flashPtr = new EefcFlash(_samba, "ATSAM3N1", 0x400000, 256, 256, 1, 4, 0x20000800, 0x20002000, 0x400e0a00, false); + break; + case 0x29380360 : // A + case 0x29480360 : // B + case 0x29580360 : // C + _family = FAMILY_SAM3N; + flashPtr = new EefcFlash(_samba, "ATSAM3N0", 0x400000, 128, 256, 1, 1, 0x20000800, 0x20002000, 0x400e0a00, false); + break; + // + // SAM3S + // + case 0x299b0a60 : // B + case 0x29ab0a60 : // C + _family = FAMILY_SAM3S; + flashPtr = new EefcFlash(_samba, "ATSAM3SD8", 0x400000, 2048, 256, 1, 16, 0x20001000, 0x20010000, 0x400e0a00, false); + break; + case 0x289b0a60 : // B + case 0x28ab0a60 : // C + _family = FAMILY_SAM3S; + flashPtr = new EefcFlash(_samba, "ATSAM3S8", 0x400000, 2048, 256, 1, 16, 0x20001000, 0x20010000, 0x400e0a00, false); + break; + case 0x28800960 : // A + case 0x28900960 : // B + case 0x28a00960 : // C + _family = FAMILY_SAM3S; + flashPtr = new EefcFlash(_samba, "ATSAM3S4", 0x400000, 1024, 256, 1, 16, 0x20001000, 0x2000c000, 0x400e0a00, false); + break; + case 0x288a0760 : // A + case 0x289a0760 : // B + case 0x28aa0760 : // C + _family = FAMILY_SAM3S; + flashPtr = new EefcFlash(_samba, "ATSAM3S2", 0x400000, 512, 256, 1, 8, 0x20000800, 0x20008000, 0x400e0a00, false); + break; + case 0x288a0560 : // A + case 0x289a0560 : // B + case 0x28aa0560 : // C + _family = FAMILY_SAM3S; + flashPtr = new EefcFlash(_samba, "ATSAM3S1", 0x400000, 256, 256, 1, 4, 0x20000800, 0x20004000, 0x400e0a00, false); + break; + // + // SAM3U + // + case 0x28000960 : // C + case 0x28100960 : // E + _family = FAMILY_SAM3U; + flashPtr = new EefcFlash(_samba, "ATSAM3U4", 0xE0000, 1024, 256, 2, 32, 0x20001000, 0x20008000, 0x400e0800, false); + break; + case 0x280a0760 : // C + case 0x281a0760 : // E + _family = FAMILY_SAM3U; + flashPtr = new EefcFlash(_samba, "ATSAM3U2", 0x80000, 512, 256, 1, 16, 0x20001000, 0x20004000, 0x400e0800, false); + break; + case 0x28090560 : // C + case 0x28190560 : // E + _family = FAMILY_SAM3U; + flashPtr = new EefcFlash(_samba, "ATSAM3U1", 0x80000, 256, 256, 1, 8, 0x20001000, 0x20002000, 0x400e0800, false); + break; + // + // SAM3X + // + case 0x286e0a60 : // 8H + case 0x285e0a60 : // 8E + case 0x284e0a60 : // 8C + _family = FAMILY_SAM3X; + flashPtr = new EefcFlash(_samba, "ATSAM3X8", 0x80000, 2048, 256, 2, 32, 0x20001000, 0x20010000, 0x400e0a00, false); + break; + case 0x285b0960 : // 4E + case 0x284b0960 : // 4C + _family = FAMILY_SAM3X; + flashPtr = new EefcFlash(_samba, "ATSAM3X4", 0x80000, 1024, 256, 2, 16, 0x20001000, 0x20008000, 0x400e0a00, false); + break; + // + // SAM3A + // + case 0x283e0A60 : // 8C + _family = FAMILY_SAM3A; + flashPtr = new EefcFlash(_samba, "ATSAM3A8", 0x80000, 2048, 256, 2, 32, 0x20001000, 0x20010000, 0x400e0a00, false); + break; + case 0x283b0960 : // 4C + _family = FAMILY_SAM3A; + flashPtr = new EefcFlash(_samba, "ATSAM3A4", 0x80000, 1024, 256, 2, 16, 0x20001000, 0x20008000, 0x400e0a00, false); + break; + // + // SAM7L + // + case 0x27330740 : + _family = FAMILY_SAM7L; + flashPtr = new EefcFlash(_samba, "ATSAM7L128", 0x100000, 512, 256, 1, 16, 0x2ffb40, 0x300700, 0xffffff60, false); + break; + case 0x27330540 : + _family = FAMILY_SAM7L; + flashPtr = new EefcFlash(_samba, "ATSAM7L64", 0x100000, 256, 256, 1, 8, 0x2ffb40, 0x300700, 0xffffff60, false); + break; + // + // SAM9XE + // + case 0x329aa3a0 : + _family = FAMILY_SAM9XE; + flashPtr = new EefcFlash(_samba, "ATSAM9XE512", 0x200000, 1024, 512, 1, 32, 0x300000, 0x307000, 0xfffffa00, true); + break; + case 0x329a93a0 : + _family = FAMILY_SAM9XE; + flashPtr = new EefcFlash(_samba, "ATSAM9XE256", 0x200000, 512, 512, 1, 16, 0x300000, 0x307000, 0xfffffa00, true); + break; + case 0x329973a0 : + _family = FAMILY_SAM9XE; + flashPtr = new EefcFlash(_samba, "ATSAM9XE128", 0x200000, 256, 512, 1, 8, 0x300000, 0x303000, 0xfffffa00, true); + break; + // + // SAM4E + // + case 0x23cc0ce0: + switch (extChipId) + { + case 0x00120200: // E + case 0x00120201: // C + _family = FAMILY_SAM4E; + flashPtr = new EefcFlash(_samba, "ATSAM4E16", 0x400000, 2048, 512, 1, 128, 0x20001000, 0x20020000, 0x400e0a00, false); + break; + case 0x00120208: // E + case 0x00120209: // C + _family = FAMILY_SAM4E; + flashPtr = new EefcFlash(_samba, "ATSAM4E8", 0x400000, 1024, 512, 1, 64, 0x20001000, 0x20020000, 0x400e0a00, false); + break; + } + break; + // + // SAME70 + // + case 0x210d0a00: + _family = FAMILY_SAME70; + flashPtr = new EefcFlash(_samba, "ATSAME70x19", 0x400000, 1024, 512, 1, 32, 0x20401000, 0x20404000, 0x400e0c00, false); + break; + case 0x21020c00: + _family = FAMILY_SAME70; + flashPtr = new EefcFlash(_samba, "ATSAME70x20", 0x400000, 2048, 512, 1, 64, 0x20401000, 0x20404000, 0x400e0c00, false); + break; + case 0x21020e00: + _family = FAMILY_SAME70; + flashPtr = new EefcFlash(_samba, "ATSAME70x21", 0x400000, 4096, 512, 1, 128, 0x20401000, 0x20404000, 0x400e0c00, false); + break; + // + // SAMS70 + // + case 0x211d0a00: + _family = FAMILY_SAMS70; + flashPtr = new EefcFlash(_samba, "ATSAMS70x19", 0x400000, 1024, 512, 1, 32, 0x20401000, 0x20404000, 0x400e0c00, false); + break; + case 0x21120c00: + _family = FAMILY_SAMS70; + flashPtr = new EefcFlash(_samba, "ATSAMS70x20", 0x400000, 2048, 512, 1, 64, 0x20401000, 0x20404000, 0x400e0c00, false); + break; + case 0x21120e00: + _family = FAMILY_SAMS70; + flashPtr = new EefcFlash(_samba, "ATSAMS70x21", 0x400000, 4096, 512, 1, 128, 0x20401000, 0x20404000, 0x400e0c00, false); + break; + // + // SAMV70 + // + case 0x213d0a00: + _family = FAMILY_SAMV70; + flashPtr = new EefcFlash(_samba, "ATSAMV70x19", 0x400000, 1024, 512, 1, 32, 0x20401000, 0x20404000, 0x400e0c00, false); + break; + case 0x21320c00: + _family = FAMILY_SAMV70; + flashPtr = new EefcFlash(_samba, "ATSAMV70x20", 0x400000, 2048, 512, 1, 64, 0x20401000, 0x20404000, 0x400e0c00, false); + break; + // + // SAMV71 + // + case 0x212d0a00: + _family = FAMILY_SAMV71; + flashPtr = new EefcFlash(_samba, "ATSAMV71x19", 0x400000, 1024, 512, 1, 32, 0x20401000, 0x20404000, 0x400e0c00, false); + break; + case 0x21220c00: + _family = FAMILY_SAMV71; + flashPtr = new EefcFlash(_samba, "ATSAMV71x20", 0x400000, 2048, 512, 1, 64, 0x20401000, 0x20404000, 0x400e0c00, false); + break; + case 0x21220e00: + _family = FAMILY_SAMV71; + flashPtr = new EefcFlash(_samba, "ATSAMV71x21", 0x400000, 4096, 512, 1, 128, 0x20401000, 0x20404000, 0x400e0c00, false); + break; + // + // No CHIPID devices + // + case 0: + switch (deviceId & 0xffff00ff) + { + // + // SAMD21 + // + case 0x10010003: // J15A + case 0x10010008: // G15A + case 0x1001000d: // E15A + case 0x10010021: // J15B + case 0x10010024: // G15B + case 0x10010027: // E15B + case 0x10010056: // E15B WLCSP + case 0x10010063: // E15C WLCSP + _family = FAMILY_SAMD21; + flashPtr = new D2xNvmFlash(_samba, "ATSAMD21x15", 512, 64, 0x20000800, 0x20001000) ; + break; + + case 0x10010002: // J16A + case 0x10010007: // G16A + case 0x1001000c: // E16A + case 0x10010020: // J16B + case 0x10010023: // G16B + case 0x10010026: // E16B + case 0x10010055: // E16B WLCSP + case 0x10010062: // E16C WLCSP + _family = FAMILY_SAMD21; + flashPtr = new D2xNvmFlash(_samba, "ATSAMD21x16", 1024, 64, 0x20001000, 0x20002000) ; + break; + + case 0x10010001: // J17A + case 0x10010006: // G17A + case 0x1001000b: // E17A + case 0x10010010: // G17A WLCSP + _family = FAMILY_SAMD21; + flashPtr = new D2xNvmFlash(_samba, "ATSAMD21x17", 2048, 64, 0x20002000, 0x20004000) ; + break; + + case 0x10010000: // J18A + case 0x10010005: // G18A + case 0x1001000a: // E18A + case 0x1001000f: // G18A WLCSP + _family = FAMILY_SAMD21; + flashPtr = new D2xNvmFlash(_samba, "ATSAMD21x18", 4096, 64, 0x20004000, 0x20008000) ; + break; + + // + // SAMR21 + // + case 0x1001001e: // E16A + case 0x1001001b: // G16A + _family = FAMILY_SAMR21; + flashPtr = new D2xNvmFlash(_samba, "ATSAMR21x16", 1024, 64, 0x20001000, 0x20002000) ; + break; + + case 0x1001001d: // E17A + case 0x1001001a: // G17A + _family = FAMILY_SAMR21; + flashPtr = new D2xNvmFlash(_samba, "ATSAMR21x17", 2048, 64, 0x20002000, 0x20004000) ; + break; + + case 0x1001001c: // E18A + case 0x10010019: // G18A + _family = FAMILY_SAMR21; + flashPtr = new D2xNvmFlash(_samba, "ATSAMR21x18", 4096, 64, 0x20004000, 0x20008000) ; + break; + + case 0x10010018: // E19A + _family = FAMILY_SAMR21; + flashPtr = new D2xNvmFlash(_samba, "ATSAMR21x19", 4096, 64, 0x20004000, 0x20008000) ; + break; + + // + // SAML21 + // + case 0x1081000d: // E15A + case 0x1081001c: // E15B + _family = FAMILY_SAMD21; + flashPtr = new D2xNvmFlash(_samba, "ATSAML21x15", 512, 64, 0x20000800, 0x20001000) ; + break; + + case 0x10810002: // J16A + case 0x10810007: // G16A + case 0x1081000c: // E16A + case 0x10810011: // J16B + case 0x10810016: // G16B + case 0x1081001b: // E16B + _family = FAMILY_SAML21; + flashPtr = new D2xNvmFlash(_samba, "ATSAML21x16", 1024, 64, 0x20001000, 0x20002000) ; + break; + + case 0x10810001: // J17A + case 0x10810006: // G17A + case 0x1081000b: // E17A + case 0x10810010: // J17B + case 0x10810015: // G17B + case 0x1081001a: // E17B + _family = FAMILY_SAML21; + flashPtr = new D2xNvmFlash(_samba, "ATSAML21x17", 2048, 64, 0x20002000, 0x20004000) ; + break; + + case 0x10810000: // J18A + case 0x10810005: // G18A + case 0x1081000a: // E18A + case 0x1081000f: // J18B + case 0x10810014: // G18B + case 0x10810019: // E18B + _family = FAMILY_SAML21; + flashPtr = new D2xNvmFlash(_samba, "ATSAML21x18", 4096, 64, 0x20004000, 0x20008000) ; + break; + + // + // SAMD51 + // + case 0x60060006: // J18A + case 0x60060008: // G18A + _family = FAMILY_SAMD51; + flashPtr = new D5xNvmFlash(_samba, "ATSAMD51x18", 512, 512, 0x20004000, 0x20008000) ; + break; + + case 0x60060001: // P19A + case 0x60060003: // N19A + case 0x60060005: // J19A + case 0x60060007: // G19A + _family = FAMILY_SAMD51; + flashPtr = new D5xNvmFlash(_samba, "ATSAMD51x19", 1024, 512, 0x20004000, 0x20008000) ; + break; + + case 0x60060000: // P20A + case 0x60060002: // N20A + case 0x60060004: // J20A + _family = FAMILY_SAMD51; + flashPtr = new D5xNvmFlash(_samba, "ATSAMD51x20", 2048, 512, 0x20004000, 0x20008000) ; + break; + + // + // SAME51 + // + case 0x61810003: // J18A + _family = FAMILY_SAME51; + flashPtr = new D5xNvmFlash(_samba, "ATSAME51x18", 512, 512, 0x20004000, 0x20008000) ; + break; + + case 0x61810002: // J19A + case 0x61810001: // N19A + _family = FAMILY_SAME51; + flashPtr = new D5xNvmFlash(_samba, "ATSAME51x19", 1024, 512, 0x20004000, 0x20008000) ; + break; + + case 0x61810004: // J20A + case 0x61810000: // N20A + _family = FAMILY_SAME51; + flashPtr = new D5xNvmFlash(_samba, "ATSAME51x20", 2048, 512, 0x20004000, 0x20008000) ; + break; + + // + // SAME53 + // + case 0x61830006: // J18A + _family = FAMILY_SAME53; + flashPtr = new D5xNvmFlash(_samba, "ATSAME53x18", 512, 512, 0x20004000, 0x20008000) ; + break; + + case 0x61830005: // J19A + case 0x61830003: // N19A + _family = FAMILY_SAME53; + flashPtr = new D5xNvmFlash(_samba, "ATSAME53x19", 1024, 512, 0x20004000, 0x20008000) ; + break; + + case 0x61830004: // J20A + case 0x61830002: // N20A + _family = FAMILY_SAME53; + flashPtr = new D5xNvmFlash(_samba, "ATSAME53x20", 2048, 512, 0x20004000, 0x20008000) ; + break; + + // + // SAME54 + // + case 0x61840001: // P19A + case 0x61840003: // N19A + _family = FAMILY_SAME54; + flashPtr = new D5xNvmFlash(_samba, "ATSAME54x19", 1024, 512, 0x20004000, 0x20008000) ; + break; + + case 0x61840000: // P20A + case 0x61840002: // N20A + _family = FAMILY_SAME54; + flashPtr = new D5xNvmFlash(_samba, "ATSAME54x20", 2048, 512, 0x20004000, 0x20008000) ; + break; + + // + // Unknown + // + default: + throw DeviceUnsupportedError(); + break; + } + break; + + // + // Unsupported device + // + default: + throw DeviceUnsupportedError(); + break; + } + + _flash = std::unique_ptr(flashPtr); +} + +void +Device::reset() +{ + try + { + switch (_family) + { + case FAMILY_SAMD21: + case FAMILY_SAMR21: + case FAMILY_SAML21: + case FAMILY_SAMD51: + case FAMILY_SAME51: + case FAMILY_SAME53: + case FAMILY_SAME54: + case FAMILY_SAME70: + case FAMILY_SAMS70: + case FAMILY_SAMV70: + case FAMILY_SAMV71: + _samba.writeWord(0xE000ED0C, 0x05FA0004); + break; + + case FAMILY_SAM3X: + case FAMILY_SAM3S: + case FAMILY_SAM3A: + _samba.writeWord(0x400E1A00, 0xA500000D); + break; + + case FAMILY_SAM3U: + _samba.writeWord(0x400E1200, 0xA500000D); + break; + + case FAMILY_SAM3N: + case FAMILY_SAM4S: + _samba.writeWord(0x400E1400, 0xA500000D); + break; + + case FAMILY_SAM4E: + _samba.writeWord(0x400E1800, 0xA500000D); + break; + + case FAMILY_SAM7S: + case FAMILY_SAM7SE: + case FAMILY_SAM7X: + case FAMILY_SAM7XC: + case FAMILY_SAM7L: + case FAMILY_SAM9XE: + _samba.writeWord(0xFFFFFD00, 0xA500000D); + break; + + default: + break; + } + } + catch (std::exception& expected) + { // writeWord will most likely throw an exception when the CPU is reset + } +} + + diff --git a/lib/bossac/src/Device.h b/lib/bossac/src/Device.h new file mode 100644 index 00000000..5475c557 --- /dev/null +++ b/lib/bossac/src/Device.h @@ -0,0 +1,104 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// +#ifndef _DEVICE_H +#define _DEVICE_H + +#include + +#include "Samba.h" +#include "Flash.h" + +class DeviceUnsupportedError : public std::exception +{ +public: + DeviceUnsupportedError() : exception() {}; + const char* what() const throw() { return "Device unsupported"; } +}; + +class Device +{ +public: + enum Family { + FAMILY_NONE, + + FAMILY_SAM7S, + FAMILY_SAM7SE, + FAMILY_SAM7X, + FAMILY_SAM7XC, + FAMILY_SAM7L, + + FAMILY_SAM3N, + FAMILY_SAM3S, + FAMILY_SAM3U, + FAMILY_SAM3X, + FAMILY_SAM3A, + + FAMILY_SAM4S, + FAMILY_SAM4E, + + FAMILY_SAM9XE, + + FAMILY_SAMD21, + FAMILY_SAMR21, + FAMILY_SAML21, + + FAMILY_SAMD51, + FAMILY_SAME51, + FAMILY_SAME53, + FAMILY_SAME54, + + FAMILY_SAME70, + FAMILY_SAMS70, + FAMILY_SAMV70, + FAMILY_SAMV71, + }; + + Device(Samba& samba) : _samba(samba), _flash(nullptr), _family(FAMILY_NONE) {} + virtual ~Device() {} + + void create(); + + Family getFamily() { return _family; } + + typedef std::unique_ptr const FlashPtr; + + FlashPtr& getFlash() { return _flash; } + + void reset(); + +private: + Samba& _samba; + std::unique_ptr _flash; + Family _family; + + void readChipId(uint32_t& chipId, uint32_t& extChipId); +}; + +#endif // _DEVICE_H + diff --git a/lib/bossac/src/EefcFlash.cpp b/lib/bossac/src/EefcFlash.cpp new file mode 100644 index 00000000..988c3b7e --- /dev/null +++ b/lib/bossac/src/EefcFlash.cpp @@ -0,0 +1,363 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// +#include "EefcFlash.h" + +#include +#include +#include + +#define EEFC_KEY 0x5a + +#define EEFC0_FMR (_regs + 0x00) +#define EEFC0_FCR (_regs + 0x04) +#define EEFC0_FSR (_regs + 0x08) +#define EEFC0_FRR (_regs + 0x0C) + +#define EEFC1_FMR (_regs + 0x200) +#define EEFC1_FCR (_regs + 0x204) +#define EEFC1_FSR (_regs + 0x208) +#define EEFC1_FRR (_regs + 0x20C) + +#define EEFC_FCMD_GETD 0x0 +#define EEFC_FCMD_WP 0x1 +#define EEFC_FCMD_WPL 0x2 +#define EEFC_FCMD_EWP 0x3 +#define EEFC_FCMD_EWPL 0x4 +#define EEFC_FCMD_EA 0x5 +#define EEFC_FCMD_EPA 0x7 +#define EEFC_FCMD_SLB 0x8 +#define EEFC_FCMD_CLB 0x9 +#define EEFC_FCMD_GLB 0xa +#define EEFC_FCMD_SGPB 0xb +#define EEFC_FCMD_CGPB 0xc +#define EEFC_FCMD_GGPB 0xd + +const uint32_t +EefcFlash::PagesPerErase = 8; + +EefcFlash::EefcFlash(Samba& samba, + const std::string& name, + uint32_t addr, + uint32_t pages, + uint32_t size, + uint32_t planes, + uint32_t lockRegions, + uint32_t user, + uint32_t stack, + uint32_t regs, + bool canBrownout) + : Flash(samba, name, addr, pages, size, planes, lockRegions, user, stack), + _regs(regs), _canBrownout(canBrownout), _eraseAuto(true) +{ + assert(planes == 1 || planes == 2); + assert(pages <= 4096); + assert(lockRegions <= 256); + + // SAM3 Errata (FWS must be 6) + _samba.writeWord(EEFC0_FMR, 0x6 << 8); + if (planes == 2) + _samba.writeWord(EEFC1_FMR, 0x6 << 8); +} + +EefcFlash::~EefcFlash() +{ +} + +void +EefcFlash::eraseAll(uint32_t offset) +{ + // Do a full chip erase if the offset is 0 + if (offset == 0) + { + waitFSR(); + writeFCR0(EEFC_FCMD_EA, 0); + if (_planes == 2) + { + waitFSR(); + writeFCR1(EEFC_FCMD_EA, 0); + } + + // Erase all can take an exceptionally long time on some devices + // so wait on FSR for up to 30 seconds + waitFSR(30); + } + // Else we must do it by pages + else + { + // Offset must be on an erase page boundary + if (offset % (_size * PagesPerErase)) + throw FlashEraseError(); + + // Erase each PagesPerErase set of pages + for (uint32_t pageNum = offset / _size; pageNum < _pages; pageNum += PagesPerErase) + { + if (_planes == 1 || pageNum < _pages / 2) + { + waitFSR(); + writeFCR0(EEFC_FCMD_EPA, pageNum | 0x1); + } + else + { + waitFSR(); + writeFCR1(EEFC_FCMD_EPA, (pageNum % (_pages / 2)) | 0x1); + } + } + } +} + +void +EefcFlash::eraseAuto(bool enable) +{ + _eraseAuto = enable; +} + +std::vector +EefcFlash::getLockRegions() +{ + std::vector regions(_lockRegions); + uint32_t frr; + uint32_t bit; + + waitFSR(); + for (uint32_t region = 0; region < _lockRegions; region++) + { + if (_planes == 2 && region >= _lockRegions / 2) + { + bit = region - _lockRegions / 2; + writeFCR1(EEFC_FCMD_GLB, 0); + waitFSR(); + frr = readFRR1(); + while (bit >= 32) + { + frr = readFRR1(); + bit -= 32; + } + regions[region] = (frr & (1 << bit)) != 0; + } + else + { + bit = region; + writeFCR0(EEFC_FCMD_GLB, 0); + waitFSR(); + frr = readFRR0(); + while (bit >= 32) + { + frr = readFRR0(); + bit -= 32; + } + regions[region] = (frr & (1 << bit)) != 0; + } + } + + return regions; +} + +bool +EefcFlash::getSecurity() +{ + waitFSR(); + writeFCR0(EEFC_FCMD_GGPB, 0); + waitFSR(); + return (readFRR0() & (1 << 0)); +} + +bool +EefcFlash::getBod() +{ + if (!_canBrownout) + return false; + + waitFSR(); + writeFCR0(EEFC_FCMD_GGPB, 0); + waitFSR(); + return (readFRR0() & (1 << 1)); +} + +bool +EefcFlash::getBor() +{ + if (!_canBrownout) + return false; + + waitFSR(); + writeFCR0(EEFC_FCMD_GGPB, 0); + waitFSR(); + return (readFRR0() & (1 << 2)); +} + +bool +EefcFlash::getBootFlash() +{ + waitFSR(); + writeFCR0(EEFC_FCMD_GGPB, 0); + waitFSR(); + return (readFRR0() & (1 << (_canBrownout ? 3 : 1))); +} + +void +EefcFlash::writeOptions() +{ + if (canBootFlash() && _bootFlash.isDirty() && _bootFlash.get() != getBootFlash()) + { + waitFSR(); + writeFCR0(_bootFlash.get() ? EEFC_FCMD_SGPB : EEFC_FCMD_CGPB, (canBod() ? 3 : 1)); + } + if (canBor() && _bor.isDirty() && _bor.get() != getBor()) + { + waitFSR(); + writeFCR0(_bor.get() ? EEFC_FCMD_SGPB : EEFC_FCMD_CGPB, 2); + } + if (canBod() && _bod.isDirty() && _bod.get() != getBod()) + { + waitFSR(); + writeFCR0(_bod.get() ? EEFC_FCMD_SGPB : EEFC_FCMD_CGPB, 1); + } + if (_regions.isDirty()) + { + uint32_t page; + std::vector current; + + if (_regions.get().size() >= _lockRegions) + throw FlashRegionError(); + + current = getLockRegions(); + + for (uint32_t region = 0; region < _lockRegions; region++) + { + if (_regions.get()[region] != current[region]) + { + if (_planes == 2 && region >= _lockRegions / 2) + { + page = (region - _lockRegions / 2) * _pages / _lockRegions; + waitFSR(); + writeFCR1(_regions.get()[region] ? EEFC_FCMD_SLB : EEFC_FCMD_CLB, page); + } + else + { + page = region * _pages / _lockRegions; + waitFSR(); + writeFCR0(_regions.get()[region] ? EEFC_FCMD_SLB : EEFC_FCMD_CLB, page); + } + } + } + } + if (_security.isDirty() && _security.get() == true && _security.get() != getSecurity()) + { + waitFSR(); + writeFCR0(EEFC_FCMD_SGPB, 0); + } +} + +void +EefcFlash::writePage(uint32_t page) +{ + if (page >= _pages) + throw FlashPageError(); + + _wordCopy.setDstAddr(_addr + page * _size); + _wordCopy.setSrcAddr(_onBufferA ? _pageBufferA : _pageBufferB); + _onBufferA = !_onBufferA; + waitFSR(); + _wordCopy.runv(); + if (_planes == 2 && page >= _pages / 2) + writeFCR1(_eraseAuto ? EEFC_FCMD_EWP : EEFC_FCMD_WP, page - _pages / 2); + else + writeFCR0(_eraseAuto ? EEFC_FCMD_EWP : EEFC_FCMD_WP, page); +} + +void +EefcFlash::readPage(uint32_t page, uint8_t* data) +{ + if (page >= _pages) + throw FlashPageError(); + + // The SAM3 firmware has a bug where it returns all zeros for reads + // directly from the flash so instead, we copy the flash page to + // SRAM and read it from there. + _wordCopy.setDstAddr(_onBufferA ? _pageBufferA : _pageBufferB); + _wordCopy.setSrcAddr(_addr + page * _size); + waitFSR(); + _wordCopy.runv(); + _samba.read(_onBufferA ? _pageBufferA : _pageBufferB, data, _size); +} + +void +EefcFlash::waitFSR(int seconds) +{ + int tries = seconds * 1000; + uint32_t fsr0; + uint32_t fsr1 = 0x1; + + while (tries-- > 0) + { + fsr0 = _samba.readWord(EEFC0_FSR); + if (fsr0 & 0x2) + throw FlashCmdError(); + if (fsr0 & 0x4) + throw FlashLockError(); + + if (_planes == 2) + { + fsr1 = _samba.readWord(EEFC1_FSR); + if (fsr1 & 0x2) + throw FlashCmdError(); + if (fsr1 & 0x4) + throw FlashLockError(); + } + if (fsr0 & fsr1 & 0x1) + break; + usleep(1000); + } + if (tries == 0) + throw FlashTimeoutError(); +} + +void +EefcFlash::writeFCR0(uint8_t cmd, uint32_t arg) +{ + _samba.writeWord(EEFC0_FCR, (EEFC_KEY << 24) | (arg << 8) | cmd); +} + +void +EefcFlash::writeFCR1(uint8_t cmd, uint32_t arg) +{ + _samba.writeWord(EEFC1_FCR, (EEFC_KEY << 24) | (arg << 8) | cmd); +} + +uint32_t +EefcFlash::readFRR0() +{ + return _samba.readWord(EEFC0_FRR); +} + +uint32_t +EefcFlash::readFRR1() +{ + return _samba.readWord(EEFC1_FRR); +} diff --git a/lib/bossac/src/EefcFlash.h b/lib/bossac/src/EefcFlash.h new file mode 100644 index 00000000..40fabc1a --- /dev/null +++ b/lib/bossac/src/EefcFlash.h @@ -0,0 +1,88 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// +#ifndef _EEFCFLASH_H +#define _EEFCFLASH_H + +#include +#include + +#include "Flash.h" + +class EefcFlash : public Flash +{ +public: + EefcFlash(Samba& samba, + const std::string& name, + uint32_t addr, + uint32_t pages, + uint32_t size, + uint32_t planes, + uint32_t lockRegions, + uint32_t user, + uint32_t stack, + uint32_t regs, + bool canBrownout); + virtual ~EefcFlash(); + + void eraseAll(uint32_t offset); + void eraseAuto(bool enable); + + std::vector getLockRegions(); + + bool getSecurity(); + + bool getBod(); + bool canBod() { return _canBrownout; } + + bool getBor(); + bool canBor() { return _canBrownout; } + + bool getBootFlash(); + bool canBootFlash() { return true; } + + void writeOptions(); + + void writePage(uint32_t page); + void readPage(uint32_t page, uint8_t* data); + + static const uint32_t PagesPerErase; + +private: + uint32_t _regs; + bool _canBrownout; + bool _eraseAuto; + + void waitFSR(int seconds = 1); + void writeFCR0(uint8_t cmd, uint32_t arg); + void writeFCR1(uint8_t cmd, uint32_t arg); + uint32_t readFRR0(); + uint32_t readFRR1(); +}; + +#endif // _EEFCFLASH_H diff --git a/lib/bossac/src/EfcFlash.cpp b/lib/bossac/src/EfcFlash.cpp new file mode 100644 index 00000000..9b212385 --- /dev/null +++ b/lib/bossac/src/EfcFlash.cpp @@ -0,0 +1,295 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// +#include "EfcFlash.h" + +#include +#include +#include + +#define EFC_KEY 0x5a + +#define EFC0_FMR 0xffffff60 +#define EFC0_FCR 0xffffff64 +#define EFC0_FSR 0xffffff68 + +#define EFC1_FMR 0xffffff70 +#define EFC1_FCR 0xffffff74 +#define EFC1_FSR 0xffffff78 + +#define EFC_FCMD_WP 0x1 +#define EFC_FCMD_SLB 0x2 +#define EFC_FCMD_WPL 0x3 +#define EFC_FCMD_CLB 0x4 +#define EFC_FCMD_EA 0x8 +#define EFC_FCMD_SGPB 0xb +#define EFC_FCMD_CGPB 0xd +#define EFC_FCMD_SSB 0xf + +EfcFlash::EfcFlash(Samba& samba, + const std::string& name, + uint32_t addr, + uint32_t pages, + uint32_t size, + uint32_t planes, + uint32_t lockRegions, + uint32_t user, + uint32_t stack, + bool canBootFlash) + : Flash(samba, name, addr, pages, size, planes, lockRegions, user, stack), + _canBootFlash(canBootFlash) +{ + assert(planes == 1 || planes == 2); + assert(pages <= planes * 1024); + assert(lockRegions <= 32); + + eraseAuto(true); +} + +EfcFlash::~EfcFlash() +{ +} + +void +EfcFlash::eraseAll(uint32_t offset) +{ + if (offset != 0) + throw FlashEraseError(); + + waitFSR(); + writeFCR0(EFC_FCMD_EA, 0); + if (_planes == 2) + { + waitFSR(); + writeFCR0(EFC_FCMD_EA, _pages / 2); + } +} + +void +EfcFlash::eraseAuto(bool enable) +{ + uint32_t fmr; + + waitFSR(); + fmr = _samba.readWord(EFC0_FMR); + if (enable) + fmr &= ~(1 << 7); + else + fmr |= (1 << 7); + + _samba.writeWord(EFC0_FMR, fmr); + if (_planes == 2) + { + waitFSR(); + _samba.writeWord(EFC1_FMR, fmr); + } +} + +std::vector +EfcFlash::getLockRegions() +{ + std::vector regions(_lockRegions); + uint32_t fsr0; + uint32_t fsr1; + + fsr0 = readFSR0(); + if (_planes == 2) + fsr1 = readFSR1(); + else + fsr1 = 0; + + for (uint32_t region = 0; region < _lockRegions; region++) + { + if (_planes == 2 && region >= _lockRegions / 2) + regions[region] = (fsr1 & (1 << (16 + region - _lockRegions / 2))) != 0; + else + regions[region] = (fsr0 & (1 << (16 + region))) != 0; + } + + return regions; +} + +bool +EfcFlash::getSecurity() +{ + return (readFSR0() & (1 << 4)); +} + +bool +EfcFlash::getBod() +{ + return (readFSR0() & (1 << 8)); +} + +bool +EfcFlash::getBor() +{ + return (readFSR0() & (2 << 8)); +} + +bool +EfcFlash::getBootFlash() +{ + if (!_canBootFlash) + return false; + + return (readFSR0() & (1 << 10)); +} + +void +EfcFlash::writeOptions() +{ + if (canBootFlash() && _bootFlash.isDirty() && _bootFlash.get() != getBootFlash()) + { + waitFSR(); + writeFCR0(_bootFlash.get() ? EFC_FCMD_SGPB : EFC_FCMD_CGPB, 2); + } + if (canBor() && _bor.isDirty() && _bor.get() != getBor()) + { + waitFSR(); + writeFCR0(_bor.get() ? EFC_FCMD_SGPB : EFC_FCMD_CGPB, 1); + } + if (canBod() && _bod.isDirty() && _bod.get() != getBod()) + { + waitFSR(); + writeFCR0(_bod.get() ? EFC_FCMD_SGPB : EFC_FCMD_CGPB, 0); + } + if (_regions.isDirty()) + { + uint32_t page; + std::vector current; + + current = getLockRegions(); + + for (uint32_t region = 0; region < _regions.get().size(); region++) + { + if (_regions.get()[region] != current[region]) + { + if (_planes == 2 && region >= _lockRegions / 2) + { + page = (region - _lockRegions / 2) * _pages / _lockRegions; + waitFSR(); + writeFCR1(_regions.get()[region] ? EFC_FCMD_SLB : EFC_FCMD_CLB, page); + } + else + { + page = region * _pages / _lockRegions; + waitFSR(); + writeFCR0(_regions.get()[region] ? EFC_FCMD_SLB : EFC_FCMD_CLB, page); + } + } + } + } + if (_security.isDirty() && _security.get() == true && _security.get() != getSecurity()) + { + waitFSR(); + writeFCR0(EFC_FCMD_SSB, 0); + } +} + +void +EfcFlash::writePage(uint32_t page) +{ + if (page >= _pages) + throw FlashPageError(); + + _wordCopy.setDstAddr(_addr + page * _size); + _wordCopy.setSrcAddr(_onBufferA ? _pageBufferA : _pageBufferB); + _onBufferA = !_onBufferA; + waitFSR(); + _wordCopy.run(); + if (_planes == 2 && page >= _pages / 2) + writeFCR1(EFC_FCMD_WP, page - _pages / 2); + else + writeFCR0(EFC_FCMD_WP, page); +} + +void +EfcFlash::readPage(uint32_t page, uint8_t* data) +{ + if (page >= _pages) + throw FlashPageError(); + + waitFSR(); + _samba.read(_addr + page * _size, data, _size); +} + +void +EfcFlash::waitFSR(int seconds) +{ + int tries = seconds * 1000; + uint32_t fsr0; + uint32_t fsr1 = 0x1; + + while (tries-- > 0) + { + fsr0 = readFSR0(); + if (fsr0 & 0x2) + throw FlashCmdError(); + if (fsr0 & 0x4) + throw FlashLockError(); + + if (_planes == 2) + { + fsr1 = readFSR1(); + if (fsr1 & 0x2) + throw FlashCmdError(); + if (fsr1 & 0x4) + throw FlashLockError(); + } + if (fsr0 & fsr1 & 0x1) + break; + usleep(1000); + } + if (tries == 0) + throw FlashTimeoutError(); +} + +void +EfcFlash::writeFCR0(uint8_t cmd, uint32_t arg) +{ + _samba.writeWord(EFC0_FCR, (EFC_KEY << 24) | (arg << 8) | cmd); +} + +void +EfcFlash::writeFCR1(uint8_t cmd, uint32_t arg) +{ + _samba.writeWord(EFC1_FCR, (EFC_KEY << 24) | (arg << 8) | cmd); +} + +uint32_t +EfcFlash::readFSR0() +{ + return _samba.readWord(EFC0_FSR); +} + +uint32_t +EfcFlash::readFSR1() +{ + return _samba.readWord(EFC1_FSR); +} diff --git a/lib/bossac/src/EfcFlash.h b/lib/bossac/src/EfcFlash.h new file mode 100644 index 00000000..cf22f0b8 --- /dev/null +++ b/lib/bossac/src/EfcFlash.h @@ -0,0 +1,83 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// +#ifndef _EFCFLASH_H +#define _EFCFLASH_H + +#include +#include + +#include "Flash.h" + +class EfcFlash : public Flash +{ +public: + EfcFlash(Samba& samba, + const std::string& name, + uint32_t addr, + uint32_t pages, + uint32_t size, + uint32_t planes, + uint32_t lockRegions, + uint32_t user, + uint32_t stack, + bool canBootFlash); + virtual ~EfcFlash(); + + void eraseAll(uint32_t offset); + void eraseAuto(bool enable); + + std::vector getLockRegions(); + + bool getSecurity(); + + bool getBod(); + bool canBod() { return true; } + + bool getBor(); + bool canBor() { return true; } + + bool getBootFlash(); + bool canBootFlash() { return _canBootFlash; } + + void writeOptions(); + + void writePage(uint32_t page); + void readPage(uint32_t page, uint8_t* data); + +private: + bool _canBootFlash; + + void waitFSR(int seconds = 1); + void writeFCR0(uint8_t cmd, uint32_t arg); + void writeFCR1(uint8_t cmd, uint32_t arg); + uint32_t readFSR0(); + uint32_t readFSR1(); +}; + +#endif // _EFCFLASH_H diff --git a/lib/bossac/src/FileError.h b/lib/bossac/src/FileError.h new file mode 100644 index 00000000..ff2fb284 --- /dev/null +++ b/lib/bossac/src/FileError.h @@ -0,0 +1,94 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// +#ifndef _FILEERROR_H +#define _FILEERROR_H + +#include +#include +#include + +#include "Flash.h" +#include "Samba.h" + +class FileError : public std::exception +{ +public: + FileError() : std::exception() {} +}; + +class FileOpenError : public FileError +{ +public: + FileOpenError() : FileError(), _errnum(0) {}; + FileOpenError(int errnum) : FileError(), _errnum(errnum) {}; + const char* what() const throw() + { + if (_errnum == 0) + return "Unable to open file"; + else + return strerror(_errnum); + } +private: + int _errnum; +}; + +class FileIoError : public FileError +{ +public: + FileIoError() : FileError(), _errnum(0) {}; + FileIoError(int errnum) : FileError(), _errnum(errnum) {}; + const char* what() const throw() + { + if (_errnum == 0) + return "File I/O operation failed"; + else + return strerror(_errnum); + } +private: + int _errnum; +}; + +class FileShortError : public FileError +{ +public: + FileShortError() : FileError() {}; + const char* what() const throw() + { + return "Operation ended with a short write"; + } +}; + +class FileSizeError : public FileError +{ +public: + FileSizeError() {}; + const char* what() const throw() { return "File operation exceeds flash size"; } +}; + +#endif // _FILEERROR_H diff --git a/lib/bossac/src/Flash.cpp b/lib/bossac/src/Flash.cpp new file mode 100644 index 00000000..b00dfa0e --- /dev/null +++ b/lib/bossac/src/Flash.cpp @@ -0,0 +1,106 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// +#include "Flash.h" + +#include + +Flash::Flash(Samba& samba, + const std::string& name, + uint32_t addr, + uint32_t pages, + uint32_t size, + uint32_t planes, + uint32_t lockRegions, + uint32_t user, + uint32_t stack) + : _samba(samba), _name(name), _addr(addr), _pages(pages), _size(size), + _planes(planes), _lockRegions(lockRegions), _user(user), _wordCopy(samba, user) +{ + assert((size & (size - 1)) == 0); + assert((pages & (pages - 1)) == 0); + assert((lockRegions & (lockRegions - 1)) == 0); + + _wordCopy.setWords(size / sizeof(uint32_t)); + _wordCopy.setStack(stack); + + _onBufferA = true; + + // page buffers will have the size of a physical page and will be situated right after the applet + _pageBufferA = ((_user + _wordCopy.size() + 3) / 4) * 4; // we need to avoid non 32bits aligned access on Cortex-M0+ + _pageBufferB = _pageBufferA + size; +} + +void +Flash::setLockRegions(const std::vector& regions) +{ + if (regions.size() > _lockRegions) + throw FlashRegionError(); + + _regions.set(regions); +} + +void +Flash::setSecurity() +{ + _security.set(true); +} + +void +Flash::setBor(bool enable) +{ + if (canBor()) + _bor.set(enable); +} + +void +Flash::setBod(bool enable) +{ + if (canBod()) + _bod.set(enable); +} + +void +Flash::setBootFlash(bool enable) +{ + if (canBootFlash()) + _bootFlash.set(enable); +} + +void +Flash::loadBuffer(const uint8_t* data, uint16_t bufferSize) +{ + _samba.write(_onBufferA ? _pageBufferA : _pageBufferB, data, bufferSize); +} + +void +Flash::writeBuffer(uint32_t dst_addr, uint32_t size) +{ + _samba.writeBuffer(_onBufferA ? _pageBufferA : _pageBufferB, dst_addr + _addr, size); +} + diff --git a/lib/bossac/src/Flash.h b/lib/bossac/src/Flash.h new file mode 100644 index 00000000..5d3a37b3 --- /dev/null +++ b/lib/bossac/src/Flash.h @@ -0,0 +1,180 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// +#ifndef _FLASH_H +#define _FLASH_H + +#include +#include +#include +#include + +#include "Samba.h" +#include "WordCopyApplet.h" + +class FlashPageError : public std::exception +{ +public: + FlashPageError() : exception() {}; + const char* what() const throw() { return "Invalid flash page"; } +}; + +class FlashRegionError : public std::exception +{ +public: + FlashRegionError() : exception() {}; + const char* what() const throw() { return "Invalid lock region"; } +}; + +class FlashLockError : public std::exception +{ +public: + FlashLockError() : exception() {}; + const char* what() const throw() { return "Flash page is locked"; } +}; + +class FlashCmdError : public std::exception +{ +public: + FlashCmdError() : exception() {}; + const char* what() const throw() { return "Flash command failed"; } +}; + +class FlashTimeoutError : public std::exception +{ +public: + FlashTimeoutError() : exception() {}; + const char* what() const throw() { return "Flash command timeout"; } +}; + +class BootFlashError : public std::exception +{ +public: + BootFlashError() : exception() {}; + const char* what() const throw() { return "Unable to clear boot flash for this device"; } + +}; + +class FlashEraseError : public std::exception +{ +public: + FlashEraseError() : exception() {}; + const char* what() const throw() { return "Flash erase failed"; } + +}; + +template +class FlashOption +{ +public: + FlashOption() : _dirty(false) {} + virtual ~FlashOption() {} + void set(const T& value) { _value = value; _dirty = true; } + const T& get() { return _value; } + bool isDirty() { return _dirty; } + +private: + T _value; + bool _dirty; +}; + +class Flash +{ +public: + Flash(Samba& samba, + const std::string& name, + uint32_t addr, // Flash base address + uint32_t pages, // Number of pages + uint32_t size, // Page size in bytes + uint32_t planes, // Number of flash planes + uint32_t lockRegions, // Number of flash lock regions + uint32_t user, // Address in SRAM where the applet and buffers will be placed + uint32_t stack); // Address in SRAM where the applet stack will be placed + virtual ~Flash() {} + + const std::string& name() { return _name; } + + virtual uint32_t address() { return _addr; } + virtual uint32_t pageSize() { return _size; } + virtual uint32_t numPages() { return _pages; } + virtual uint32_t numPlanes() { return _planes; } + virtual uint32_t totalSize() { return _size * _pages; } + virtual uint32_t lockRegions() { return _lockRegions; } + + virtual void eraseAll(uint32_t offset) = 0; + virtual void eraseAuto(bool enable) = 0; + + virtual std::vector getLockRegions() = 0; + virtual void setLockRegions(const std::vector& regions); + + virtual bool getSecurity() = 0; + virtual void setSecurity(); + + virtual bool getBod() = 0; + virtual void setBod(bool enable); + virtual bool canBod() = 0; + + virtual bool getBor() = 0; + virtual void setBor(bool enable); + virtual bool canBor() = 0; + + virtual bool getBootFlash() = 0; + virtual void setBootFlash(bool enable); + virtual bool canBootFlash() = 0; + + virtual void writeOptions() = 0; + + virtual void writePage(uint32_t page) = 0; + virtual void readPage(uint32_t page, uint8_t* data) = 0; + + virtual void writeBuffer(uint32_t dst_addr, uint32_t size); + virtual void loadBuffer(const uint8_t* data, uint16_t size); + +protected: + Samba& _samba; + std::string _name; + uint32_t _addr; + uint32_t _pages; + uint32_t _size; + uint32_t _planes; + uint32_t _lockRegions; + uint32_t _user; + WordCopyApplet _wordCopy; + + FlashOption _bootFlash; + FlashOption< std::vector > _regions; + FlashOption _bod; + FlashOption _bor; + FlashOption _security; + + bool _onBufferA; + uint32_t _pageBufferA; + uint32_t _pageBufferB; +}; + +#endif // _FLASH_H diff --git a/lib/bossac/src/Flasher.cpp b/lib/bossac/src/Flasher.cpp new file mode 100644 index 00000000..7591cf9f --- /dev/null +++ b/lib/bossac/src/Flasher.cpp @@ -0,0 +1,373 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include + +#include "Flasher.h" + +using namespace std; + +void +FlasherInfo::print() +{ + bool first; + + printf("Device : %s\n", name.c_str()); + printf("Version : %s\n", version.c_str()); + printf("Address : 0x%x\n", address); + printf("Pages : %d\n", numPages); + printf("Page Size : %d bytes\n", pageSize); + printf("Total Size : %dKB\n", totalSize / 1024); + printf("Planes : %d\n", numPlanes); + printf("Lock Regions : %zd\n", lockRegions.size()); + printf("Locked : "); + first = true; + for (uint32_t region = 0; region < lockRegions.size(); region++) + { + if (lockRegions[region]) + { + printf("%s%d", first ? "" : ",", region); + first = false; + } + } + printf("%s\n", first ? "none" : ""); + printf("Security : %s\n", security ? "true" : "false"); + if (canBootFlash) + printf("Boot Flash : %s\n", bootFlash ? "true" : "false"); + if (canBod) + printf("BOD : %s\n", bod ? "true" : "false"); + if (canBor) + printf("BOR : %s\n", bor ? "true" : "false"); +} + +void +Flasher::erase(uint32_t foffset) +{ + _observer.onStatus("Erase flash\n"); + _flash->eraseAll(foffset); + _flash->eraseAuto(false); +} + +void +Flasher::write(const char* filename, uint32_t foffset) +{ + FILE* infile; + uint32_t pageSize = _flash->pageSize(); + uint32_t pageNum = 0; + uint32_t numPages; + long fsize; + size_t fbytes; + + if (foffset % pageSize != 0 || foffset >= _flash->totalSize()) + throw FlashOffsetError(); + + infile = fopen(filename, "rb"); + if (!infile) + throw FileOpenError(errno); + + try + { + if (fseek(infile, 0, SEEK_END) != 0 || (fsize = ftell(infile)) < 0) + throw FileIoError(errno); + + rewind(infile); + + numPages = (fsize + pageSize - 1) / pageSize; + if (numPages > _flash->numPages()) + throw FileSizeError(); + + _observer.onStatus("Write %ld bytes to flash (%u pages)\n", fsize, numPages); + + if (_samba.canWriteBuffer()) + { + uint32_t offset = 0; + uint32_t bufferSize = _samba.writeBufferSize(); + uint8_t buffer[bufferSize]; + + while ((fbytes = fread(buffer, 1, bufferSize, infile)) > 0) + { + _observer.onProgress(offset / pageSize, numPages); + + if (fbytes < bufferSize) + { + memset(buffer + fbytes, 0, bufferSize - fbytes); + fbytes = (fbytes + pageSize - 1) / pageSize * pageSize; + } + + _flash->loadBuffer(buffer, fbytes); + _flash->writeBuffer(foffset + offset, fbytes); + offset += fbytes; + } + + } + else + { + uint8_t buffer[pageSize]; + uint32_t pageOffset = foffset / pageSize; + + while ((fbytes = fread(buffer, 1, pageSize, infile)) > 0) + { + _observer.onProgress(pageNum, numPages); + + _flash->loadBuffer(buffer, fbytes); + _flash->writePage(pageOffset + pageNum); + + pageNum++; + if (pageNum == numPages || fbytes != pageSize) + break; + } + + } + } + catch(...) + { + fclose(infile); + throw; + } + + fclose(infile); + _observer.onProgress(numPages, numPages); +} + +bool +Flasher::verify(const char* filename, uint32_t& pageErrors, uint32_t& totalErrors, uint32_t foffset) +{ + FILE* infile; + uint32_t pageSize = _flash->pageSize(); + uint8_t bufferA[pageSize]; + uint8_t bufferB[pageSize]; + uint32_t pageNum = 0; + uint32_t numPages; + uint32_t pageOffset; + uint32_t byteErrors = 0; + uint16_t calcCrc = 0; + uint16_t flashCrc; + long fsize; + size_t fbytes; + + pageErrors = 0; + totalErrors = 0; + + if (foffset % pageSize != 0 || foffset >= _flash->totalSize()) + throw FlashOffsetError(); + + pageOffset = foffset / pageSize; + + infile = fopen(filename, "rb"); + if (!infile) + throw FileOpenError(errno); + + try + { + if (fseek(infile, 0, SEEK_END) != 0 || (fsize = ftell(infile)) < 0) + throw FileIoError(errno); + + rewind(infile); + + numPages = (fsize + pageSize - 1) / pageSize; + if (numPages > _flash->numPages()) + throw FileSizeError(); + + _observer.onStatus("Verify %ld bytes of flash\n", fsize); + + while ((fbytes = fread(bufferA, 1, pageSize, infile)) > 0) + { + byteErrors = 0; + + _observer.onProgress(pageNum, numPages); + + if (_samba.canChecksumBuffer()) + { + for (uint32_t i = 0; i < fbytes; i++) + calcCrc = _samba.checksumCalc(bufferA[i], calcCrc); + + flashCrc = _samba.checksumBuffer((pageOffset + pageNum) * pageSize, fbytes); + + if (flashCrc != calcCrc) + { + _flash->readPage(pageOffset + pageNum, bufferB); + + for (uint32_t i = 0; i < fbytes; i++) + { + if (bufferA[i] != bufferB[i]) + byteErrors++; + } + } + } + else + { + _flash->readPage(pageOffset + pageNum, bufferB); + + for (uint32_t i = 0; i < fbytes; i++) + { + if (bufferA[i] != bufferB[i]) + byteErrors++; + } + } + + if (byteErrors != 0) + { + pageErrors++; + totalErrors += byteErrors; + } + + pageNum++; + if (pageNum == numPages || fbytes != pageSize) + break; + } + } + catch(...) + { + fclose(infile); + throw; + } + + fclose(infile); + + _observer.onProgress(numPages, numPages); + + if (pageErrors != 0) + return false; + + return true; +} + +void +Flasher::read(const char* filename, uint32_t fsize, uint32_t foffset) +{ + FILE* outfile; + uint32_t pageSize = _flash->pageSize(); + uint8_t buffer[pageSize]; + uint32_t pageNum = 0; + uint32_t pageOffset; + uint32_t numPages; + size_t fbytes; + + if (foffset % pageSize != 0 || foffset >= _flash->totalSize()) + throw FlashOffsetError(); + + pageOffset = foffset / pageSize; + + if (fsize == 0) + fsize = pageSize * (_flash->numPages() - pageOffset); + + numPages = (fsize + pageSize - 1) / pageSize; + if (pageOffset + numPages > _flash->numPages()) + throw FileSizeError(); + + outfile = fopen(filename, "wb"); + if (!outfile) + throw FileOpenError(errno); + + _observer.onStatus("Read %d bytes from flash\n", fsize); + + try + { + for (pageNum = 0; pageNum < numPages; pageNum++) + { + _observer.onProgress(pageNum, numPages); + + _flash->readPage(pageOffset + pageNum, buffer); + + if (pageNum == numPages - 1 && fsize % pageSize > 0) + pageSize = fsize % pageSize; + fbytes = fwrite(buffer, 1, pageSize, outfile); + if (fbytes != pageSize) + throw FileShortError(); + } + } + catch(...) + { + fclose(outfile); + throw; + } + + _observer.onProgress(numPages, numPages); + + fclose(outfile); +} + +void +Flasher::lock(string& regionArg, bool enable) +{ + if (regionArg.empty()) + { + _observer.onStatus("%s all regions\n", enable ? "Lock" : "Unlock"); + std::vector regions(_flash->lockRegions(), enable); + _flash->setLockRegions(regions); + } + else + { + size_t pos = 0; + size_t delim; + uint32_t region; + string sub; + std::vector regions = _flash->getLockRegions(); + + do + { + delim = regionArg.find(',', pos); + sub = regionArg.substr(pos, delim - pos); + region = strtol(sub.c_str(), NULL, 0); + _observer.onStatus("%s region %d\n", enable ? "Lock" : "Unlock", region); + regions[region] = enable; + pos = delim + 1; + } while (delim != string::npos); + + _flash->setLockRegions(regions); + } +} + +void +Flasher::info(FlasherInfo& info) +{ + info.name = _flash->name(); + info.version = _samba.version(); + info.address = _flash->address(); + info.numPages = _flash->numPages(); + info.pageSize = _flash->pageSize(); + info.totalSize = _flash->numPages() * _flash->pageSize(); + info.numPlanes = _flash->numPlanes(); + info.security = _flash->getSecurity(); + info.bootFlash = _flash->getBootFlash(); + info.bod = _flash->getBod(); + info.bor = _flash->getBor(); + + info.canBootFlash = _flash->canBootFlash(); + info.canBod = _flash->canBod(); + info.canBor = _flash->canBor(); + info.canChipErase = _samba.canChipErase(); + info.canWriteBuffer = _samba.canWriteBuffer(); + info.canChecksumBuffer = _samba.canChecksumBuffer(); + info.lockRegions = _flash->getLockRegions(); +} diff --git a/lib/bossac/src/Flasher.h b/lib/bossac/src/Flasher.h new file mode 100644 index 00000000..c926fb36 --- /dev/null +++ b/lib/bossac/src/Flasher.h @@ -0,0 +1,110 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// +#ifndef _FLASHER_H +#define _FLASHER_H + +#include +#include +#include + +#include "Device.h" +#include "Flash.h" +#include "Samba.h" +#include "FileError.h" + +class FlashOffsetError : public std::exception +{ +public: + FlashOffsetError() : std::exception() {}; + virtual const char* what() const throw() { return "Flash offset is invalid"; } +}; + +class FlasherObserver +{ +public: + FlasherObserver() {} + virtual ~FlasherObserver() {} + + virtual void onStatus(const char *message, ...) = 0; + virtual void onProgress(int num, int div) = 0; +}; + +class FlasherInfo +{ +public: + FlasherInfo() {} + virtual ~FlasherInfo() {} + + void print(); + + std::string name; + uint32_t chipId; + uint32_t extChipId; + std::string version; + uint32_t address; + uint32_t numPages; + uint32_t pageSize; + uint32_t totalSize; + uint32_t numPlanes; + + bool security; + bool bootFlash; + bool bod; + bool bor; + + bool canBootFlash; + bool canBod; + bool canBor; + bool canChipErase; + bool canWriteBuffer; + bool canChecksumBuffer; + + std::vector lockRegions; +}; + +class Flasher +{ +public: + Flasher(Samba& samba, Device& device, FlasherObserver& observer) : _samba(samba), _flash(device.getFlash()), _observer(observer) {} + virtual ~Flasher() {} + + void erase(uint32_t foffset); + void write(const char* filename, uint32_t foffset = 0); + bool verify(const char* filename, uint32_t& pageErrors, uint32_t& totalErrors, uint32_t foffset = 0); + void read(const char* filename, uint32_t fsize, uint32_t foffset = 0); + void lock(std::string& regionArg, bool enable); + void info(FlasherInfo& info); + +private: + Samba& _samba; + Device::FlashPtr& _flash; + FlasherObserver& _observer; +}; + +#endif // _FLASHER_H diff --git a/lib/bossac/src/LinuxPortFactory.cpp b/lib/bossac/src/LinuxPortFactory.cpp new file mode 100644 index 00000000..80499bf9 --- /dev/null +++ b/lib/bossac/src/LinuxPortFactory.cpp @@ -0,0 +1,109 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// +#include "LinuxPortFactory.h" +#include "PosixSerialPort.h" + +#include +#include + +#include + +LinuxPortFactory::LinuxPortFactory() +{ + _dir = opendir("/dev"); +} + +LinuxPortFactory::~LinuxPortFactory() +{ + if (_dir) + closedir(_dir); +} + +SerialPort::Ptr +LinuxPortFactory::create(const std::string& name) +{ + bool isUsb = false; + + if (name.find("ttyUSB") != std::string::npos || + name.find("ttyACM") != std::string::npos) + isUsb = true; + + return create(name, isUsb); +} + +SerialPort::Ptr +LinuxPortFactory::create(const std::string& name, bool isUsb) +{ + return SerialPort::Ptr(new PosixSerialPort(name, isUsb)); +} + +std::string +LinuxPortFactory::begin() +{ + if (!_dir) + return end(); + + rewinddir(_dir); + + return next(); +} + +std::string +LinuxPortFactory::next() +{ + struct dirent* entry; + + if (!_dir) + return end(); + + while ((entry = readdir(_dir))) + { + if (strncmp("ttyUSB", entry->d_name, sizeof("ttyUSB") - 1) == 0) + return std::string(entry->d_name); + else if (strncmp("ttyACM", entry->d_name, sizeof("ttyACM") - 1) == 0) + return std::string(entry->d_name); + else if (strncmp("ttyS", entry->d_name, sizeof("ttyS") - 1) == 0) + return std::string(entry->d_name); + } + + return end(); +} + +std::string +LinuxPortFactory::end() +{ + return std::string(); +} + +std::string +LinuxPortFactory::def() +{ + return std::string("/dev/ttyACM0"); +} + diff --git a/lib/bossac/src/LinuxPortFactory.h b/lib/bossac/src/LinuxPortFactory.h new file mode 100644 index 00000000..50f60f95 --- /dev/null +++ b/lib/bossac/src/LinuxPortFactory.h @@ -0,0 +1,60 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// +#ifndef _LINUXPORTFACTORY_H +#define _LINUXPORTFACTORY_H + +class LinuxPortFactory; +#include "PortFactory.h" + +#include +#include + +#include + + +class LinuxPortFactory : public PortFactoryBase +{ +public: + LinuxPortFactory(); + virtual ~LinuxPortFactory(); + + virtual std::string begin(); + virtual std::string end(); + virtual std::string next(); + virtual std::string def(); + + virtual SerialPort::Ptr create(const std::string& name); + virtual SerialPort::Ptr create(const std::string& name, bool isUsb); + +private: + std::string _empty; + DIR* _dir; +}; + +#endif // _LINUXPORTFACTORY_H diff --git a/lib/bossac/src/PortFactory.h b/lib/bossac/src/PortFactory.h new file mode 100644 index 00000000..3b3b631e --- /dev/null +++ b/lib/bossac/src/PortFactory.h @@ -0,0 +1,68 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// +#ifndef _PORTFACTORY_H +#define _PORTFACTORY_H + +#include + +#include "SerialPort.h" + +class PortFactoryBase +{ +public: + PortFactoryBase() {} + virtual ~PortFactoryBase() {} + + virtual std::string begin() = 0; + virtual std::string end() = 0; + virtual std::string next() = 0; + virtual std::string def() = 0; + + virtual SerialPort::Ptr create(const std::string& name) = 0; + virtual SerialPort::Ptr create(const std::string& name, bool isUsb) = 0; +}; + +#if defined(__WIN32__) +#include "WinPortFactory.h" +typedef WinPortFactory PortFactory; +#elif defined(__linux__) +#include "LinuxPortFactory.h" +typedef LinuxPortFactory PortFactory; +#elif defined(__APPLE__) +#include "OSXPortFactory.h" +typedef OSXPortFactory PortFactory; +#elif defined(__OpenBSD__) || defined(__FreeBSD__) +// This is likely to work (but not tested) for the other BSDs as well +#include "BSDPortFactory.h" +typedef BSDPortFactory PortFactory; +#else +#error "Platform is not supported" +#endif + +#endif // _PORTFACTORY_H diff --git a/lib/bossac/src/PosixSerialPort.cpp b/lib/bossac/src/PosixSerialPort.cpp new file mode 100644 index 00000000..45eaca9c --- /dev/null +++ b/lib/bossac/src/PosixSerialPort.cpp @@ -0,0 +1,332 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// +#include "PosixSerialPort.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifndef B460800 +#define B460800 460800 +#endif +#ifndef B921600 +#define B921600 921600 +#endif + +PosixSerialPort::PosixSerialPort(const std::string& name, bool isUsb) : + SerialPort(name), _devfd(-1), _isUsb(isUsb), _timeout(0), + _autoFlush(false) +{ +} + +PosixSerialPort::~PosixSerialPort() +{ + if (_devfd >= 0) + ::close(_devfd); +} + +bool +PosixSerialPort::open(int baud, + int data, + SerialPort::Parity parity, + SerialPort::StopBit stop) +{ + struct termios options; + speed_t speed; + // Try opening port assuming _name is full path. If it fails + // try "/dev/" + _name + _devfd = ::open(_name.c_str(), O_RDWR | O_NOCTTY | O_NDELAY); + if (_devfd == -1) + { + std::string dev("/dev/"); + dev += _name; + _devfd = ::open(dev.c_str(), O_RDWR | O_NOCTTY | O_NDELAY); + if (_devfd == -1) + return false; + } + + if (tcgetattr(_devfd, &options) == -1) + { + close(); + return false; + } + + switch (baud) + { + case 1200: + speed = B1200; + break; + case 9600: + speed = B9600; + break; + case 19200: + speed = B19200; + break; + case 38400: + speed = B38400; + break; + case 57600: + speed = B57600; + break; + case 115200: + speed = B115200; + break; + case 230400: + speed = B230400; + break; + case 460800: + speed = B460800; + break; + case 921600: + speed = B921600; + break; + default: + close(); + return false; + } + + if (cfsetispeed(&options, speed) || cfsetospeed(&options, speed)) + { + close(); + return false; + } + + options.c_cflag |= (CLOCAL | CREAD); + + switch (data) + { + case 8: + options.c_cflag &= ~CSIZE; + options.c_cflag |= CS8; + break; + case 7: + options.c_cflag &= ~CSIZE; + options.c_cflag |= CS7; + break; + default: + close(); + return false; + } + + switch (parity) + { + case SerialPort::ParityNone: + options.c_cflag &= ~PARENB; + options.c_cflag &= ~PARODD; + options.c_iflag &= ~(INPCK | ISTRIP); + break; + case SerialPort::ParityOdd: + options.c_cflag |= PARENB; + options.c_cflag |= PARODD; + options.c_iflag |= (INPCK | ISTRIP); + break; + case SerialPort::ParityEven: + options.c_cflag |= PARENB; + options.c_cflag &= ~PARODD; + options.c_iflag |= (INPCK | ISTRIP); + break; + default: + close(); + return false; + } + + switch (stop) + { + case StopBitOne: + options.c_cflag &= ~CSTOPB; + break; + case StopBitTwo: + options.c_cflag |= CSTOPB; + break; + default: + close(); + return false; + } + + // No hardware flow control + options.c_cflag &= ~CRTSCTS; + + // No software flow control + options.c_iflag &= ~(IXON | IXOFF | IXANY); + + // Raw input + options.c_iflag &= ~(BRKINT | ICRNL); + options.c_lflag &= ~(ICANON | IEXTEN | ECHO | ECHOE | ISIG); + + // Raw output + options.c_oflag &= ~OPOST; + + // No wait time + options.c_cc[VMIN] = 0; + options.c_cc[VTIME] = 0; + + if (tcsetattr(_devfd, TCSANOW, &options)) + { + close(); + return false; + } + + return true; +} + +void +PosixSerialPort::close() +{ + if (_devfd >= 0) + ::close(_devfd); + _devfd = -1; +} + +int +PosixSerialPort::read(uint8_t* buffer, int len) +{ + fd_set fds; + struct timeval tv; + int numread = 0; + int retval; + + if (_devfd == -1) + return -1; + + while (numread < len) + { + FD_ZERO(&fds); + FD_SET(_devfd, &fds); + + tv.tv_sec = _timeout / 1000; + tv.tv_usec = (_timeout % 1000) * 1000; + + retval = select(_devfd + 1, &fds, NULL, NULL, &tv); + + if (retval < 0) + { + return -1; + } + else if (retval == 0) + { + return numread; + } + else if (FD_ISSET(_devfd, &fds)) + { + retval = ::read(_devfd, (uint8_t*) buffer + numread, len - numread); + if (retval < 0) + return -1; + numread += retval; + } + } + + return numread; +} + +int +PosixSerialPort::write(const uint8_t* buffer, int len) +{ + if (_devfd == -1) + return -1; + + int res = ::write(_devfd, buffer, len); + // Used on macos to avoid upload errors + if (_autoFlush) + flush(); + return res; +} + +int +PosixSerialPort::get() +{ + uint8_t byte; + + if (_devfd == -1) + return -1; + + if (read(&byte, 1) != 1) + return -1; + + return byte; +} + +int +PosixSerialPort::put(int c) +{ + uint8_t byte; + + byte = c; + return write(&byte, 1); +} + +void +PosixSerialPort::flush() +{ + // There isn't a reliable way to flush on a file descriptor + // so we just wait it out. One millisecond is the USB poll + // interval so that should cover it. + usleep(1000); +} + +bool +PosixSerialPort::timeout(int millisecs) +{ + _timeout = millisecs; + return true; +} + +void +PosixSerialPort::setDTR(bool dtr) +{ + if (_devfd == -1) + return; + + int iFlags = TIOCM_DTR; + + ioctl(_devfd, (dtr ? TIOCMBIS : TIOCMBIC), &iFlags); +} + +void +PosixSerialPort::setRTS(bool rts) +{ + if (_devfd == -1) + return; + + int iFlags = TIOCM_RTS; + + ioctl(_devfd, (rts ? TIOCMBIS : TIOCMBIC), &iFlags); +} + +void +PosixSerialPort::setAutoFlush(bool autoflush) +{ + _autoFlush = autoflush; +} diff --git a/lib/bossac/src/PosixSerialPort.h b/lib/bossac/src/PosixSerialPort.h new file mode 100644 index 00000000..a79fe889 --- /dev/null +++ b/lib/bossac/src/PosixSerialPort.h @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// +#ifndef _POSIXSERIALPORT_H +#define _POSIXSERIALPORT_H + +#include "SerialPort.h" + +class PosixSerialPort : public SerialPort +{ +public: + PosixSerialPort(const std::string& name, bool isUsb); + virtual ~PosixSerialPort(); + + bool open(int baud = 115200, + int data = 8, + SerialPort::Parity parity = SerialPort::ParityNone, + SerialPort::StopBit stop = SerialPort::StopBitOne); + void close(); + + bool isUsb() { return _isUsb; }; + + int read(uint8_t* data, int size); + int write(const uint8_t* data, int size); + int get(); + int put(int c); + + bool timeout(int millisecs); + void flush(); + void setDTR(bool dtr); + void setRTS(bool rts); + void setAutoFlush(bool autoflush); + +private: + int _devfd; + bool _isUsb; + int _timeout; + bool _autoFlush; +}; + +#endif // _POSIXSERIALPORT_H diff --git a/lib/bossac/src/Samba.cpp b/lib/bossac/src/Samba.cpp new file mode 100644 index 00000000..490e3936 --- /dev/null +++ b/lib/bossac/src/Samba.cpp @@ -0,0 +1,672 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// +#include "Samba.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +// XMODEM definitions +#define BLK_SIZE 128 +#define MAX_RETRIES 5 +#define SOH 0x01 +#define EOT 0x04 +#define ACK 0x06 +#define NAK 0x15 +#define CAN 0x18 +#define START 'C' + +#define TIMEOUT_QUICK 100 +#define TIMEOUT_NORMAL 1000 +#define TIMEOUT_LONG 5000 + +#define min(a, b) ((a) < (b) ? (a) : (b)) + +Samba::Samba() : + _canChipErase(false), + _canWriteBuffer(false), + _canChecksumBuffer(false), + _readBufferSize(0), + _debug(false), + _isUsb(false) +{ +} + +Samba::~Samba() +{ +} + +bool +Samba::init() +{ + uint8_t cmd[3]; + + _port->timeout(TIMEOUT_QUICK); + + // Flush garbage + uint8_t dummy[1024]; + _port->read(dummy, sizeof(dummy)); + + if (!_isUsb) + { + if (_debug) + printf("Send auto-baud\n"); + + // RS-232 auto-baud sequence + _port->put(0x80); + _port->get(); + _port->put(0x80); + _port->get(); + _port->put('#'); + _port->read(cmd, 3); + } + + // Set binary mode + if (_debug) + printf("Set binary mode\n"); + cmd[0] = 'N'; + cmd[1] = '#'; + _port->write(cmd, 2); + _port->read(cmd, 2); + + std::string ver; + try + { + ver = version(); + } + catch(SambaError& err) + { + return false; + } + + std::size_t extIndex = ver.find("[Arduino:"); + if (extIndex != string::npos) + { + extIndex += 9; + while (ver[extIndex] != ']') + { + switch (ver[extIndex]) + { + case 'X': _canChipErase = true; break; + case 'Y': _canWriteBuffer = true; break; + case 'Z': _canChecksumBuffer = true; break; + } + extIndex++; + } + + // All SAMD-based Arduino/AdaFruit boards have a bug in their bootloader + // that trying to read 64 bytes or more over USB corrupts the data. + // We must limit these boards to read chunks of 63 bytes. + if (_isUsb) + _readBufferSize = 63; + } + + _port->timeout(TIMEOUT_NORMAL); + + return true; +} + +bool +Samba::connect(SerialPort::Ptr port, int bps) +{ + _port = move(port); + + // Try to connect at a high speed if USB + _isUsb = _port->isUsb(); + if (_isUsb) + { + if (_port->open(921600) && init()) + { + if (_debug) + printf("Connected at 921600 baud\n"); + return true; + } + else + { + _port->close(); + } + } + _isUsb = false; + + // Try the serial port at slower speed + if (_port->open(bps) && init()) + { + if (_debug) + printf("Connected at %d baud\n", bps); + return true; + } + + disconnect(); + return false; +} + +void +Samba::disconnect() +{ + _port->close(); + _port.release(); +} + +void +Samba::writeByte(uint32_t addr, uint8_t value) +{ + uint8_t cmd[14]; + + if (_debug) + printf("%s(addr=%#x,value=%#x)\n", __FUNCTION__, addr, value); + + snprintf((char*) cmd, sizeof(cmd), "O%08X,%02X#", addr, value); + if (_port->write(cmd, sizeof(cmd) - 1) != sizeof(cmd) - 1) + throw SambaError(); + + // The SAM firmware has a bug that if the command and binary data + // are received in the same USB data packet, then the firmware + // gets confused. Even though the writes are separated in the code, + // USB drivers often do write combining which can put them together + // in the same USB data packet. To avoid this, we call the serial + // port object's flush method before writing the data. + if (_isUsb) + _port->flush(); +} + +uint8_t +Samba::readByte(uint32_t addr) +{ + uint8_t cmd[13]; + uint8_t value; + + snprintf((char*) cmd, sizeof(cmd), "o%08X,4#", addr); + if (_port->write(cmd, sizeof(cmd) - 1) != sizeof(cmd) - 1) + throw SambaError(); + if (_port->read(cmd, sizeof(uint8_t)) != sizeof(uint8_t)) + throw SambaError(); + + value = cmd[0]; + + if (_debug) + printf("%s(addr=%#x)=%#x\n", __FUNCTION__, addr, value); + + return value; +} + + +void +Samba::writeWord(uint32_t addr, uint32_t value) +{ + uint8_t cmd[20]; + + if (_debug) + printf("%s(addr=%#x,value=%#x)\n", __FUNCTION__, addr, value); + + snprintf((char*) cmd, sizeof(cmd), "W%08X,%08X#", addr, value); + if (_port->write(cmd, sizeof(cmd) - 1) != sizeof(cmd) - 1) + throw SambaError(); + + // The SAM firmware has a bug that if the command and binary data + // are received in the same USB data packet, then the firmware + // gets confused. Even though the writes are sperated in the code, + // USB drivers often do write combining which can put them together + // in the same USB data packet. To avoid this, we call the serial + // port object's flush method before writing the data. + if (_isUsb) + _port->flush(); +} + + +uint32_t +Samba::readWord(uint32_t addr) +{ + uint8_t cmd[13]; + uint32_t value; + + snprintf((char*) cmd, sizeof(cmd), "w%08X,4#", addr); + if (_port->write(cmd, sizeof(cmd) - 1) != sizeof(cmd) - 1) + throw SambaError(); + if (_port->read(cmd, sizeof(uint32_t)) != sizeof(uint32_t)) + throw SambaError(); + + value = (cmd[3] << 24 | cmd[2] << 16 | cmd[1] << 8 | cmd[0] << 0); + + if (_debug) + printf("%s(addr=%#x)=%#x\n", __FUNCTION__, addr, value); + + return value; +} + +static const uint16_t crc16Table[256] = { + 0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7, + 0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef, + 0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6, + 0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de, + 0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485, + 0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d, + 0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4, + 0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc, + 0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823, + 0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b, + 0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12, + 0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a, + 0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41, + 0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49, + 0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70, + 0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78, + 0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f, + 0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067, + 0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e, + 0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256, + 0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d, + 0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405, + 0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c, + 0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634, + 0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab, + 0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3, + 0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a, + 0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92, + 0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9, + 0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1, + 0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8, + 0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0 +}; + +uint16_t +Samba::crc16Calc(const uint8_t *data, int len) +{ + uint16_t crc16 = 0; + + while (len-- > 0) + crc16 = (crc16 << 8) ^ crc16Table[((crc16 >> 8) ^ *(uint8_t*) data++) & 0xff]; + return crc16; +} + +bool +Samba::crc16Check(const uint8_t *blk) +{ + uint16_t crc16; + + crc16 = blk[BLK_SIZE + 3] << 8 | blk[BLK_SIZE + 4]; + return (crc16Calc(&blk[3], BLK_SIZE) == crc16); +} + +void +Samba::crc16Add(uint8_t *blk) +{ + uint16_t crc16; + + crc16 = crc16Calc(&blk[3], BLK_SIZE); + blk[BLK_SIZE + 3] = (crc16 >> 8) & 0xff; + blk[BLK_SIZE + 4] = crc16 & 0xff; +} + +uint16_t +Samba::checksumCalc(uint8_t data, uint16_t crc16) { + return (crc16 << 8) ^ crc16Table[((crc16 >> 8) ^ data) & 0xff]; +} + +void +Samba::readXmodem(uint8_t* buffer, int size) +{ + uint8_t blk[BLK_SIZE + 5]; + uint32_t blkNum = 1; + int retries; + int bytes; + + while (size > 0) + { + for (retries = 0; retries < MAX_RETRIES; retries++) + { + if (blkNum == 1) + _port->put(START); + + bytes = _port->read(blk, sizeof(blk)); + if (bytes == sizeof(blk) && + blk[0] == SOH && + blk[1] == (blkNum & 0xff) && + crc16Check(blk)) + break; + + if (blkNum != 1) + _port->put(NAK); + } + if (retries == MAX_RETRIES) + throw SambaError(); + + _port->put(ACK); + + memmove(buffer, &blk[3], min(size, BLK_SIZE)); + buffer += BLK_SIZE; + size -= BLK_SIZE; + blkNum++; + } + + for (retries = 0; retries < MAX_RETRIES; retries++) + { + if (_port->get() == EOT) + { + _port->put(ACK); + break; + } + _port->put(NAK); + } + if (retries == MAX_RETRIES) + throw SambaError(); +} + +void +Samba::writeXmodem(const uint8_t* buffer, int size) +{ + uint8_t blk[BLK_SIZE + 5]; + uint32_t blkNum = 1; + int retries; + int bytes; + + for (retries = 0; retries < MAX_RETRIES; retries++) + { + if (_port->get() == START) + break; + } + if (retries == MAX_RETRIES) + throw SambaError(); + + while (size > 0) + { + blk[0] = SOH; + blk[1] = (blkNum & 0xff); + blk[2] = ~(blkNum & 0xff); + memmove(&blk[3], buffer, min(size, BLK_SIZE)); + if (size < BLK_SIZE) + memset(&blk[3] + size, 0, BLK_SIZE - size); + crc16Add(blk); + + for (retries = 0; retries < MAX_RETRIES; retries++) + { + bytes = _port->write(blk, sizeof(blk)); + if (bytes != sizeof(blk)) + throw SambaError(); + + if (_port->get() == ACK) + break; + } + + if (retries == MAX_RETRIES) + throw SambaError(); + + buffer += BLK_SIZE; + size -= BLK_SIZE; + blkNum++; + } + + for (retries = 0; retries < MAX_RETRIES; retries++) + { + _port->put(EOT); + if (_port->get() == ACK) + break; + } + if (retries == MAX_RETRIES) + throw SambaError(); +} + +void +Samba::readBinary(uint8_t* buffer, int size) +{ + if (_port->read(buffer, size) != size) + throw SambaError(); +} + +void +Samba::writeBinary(const uint8_t* buffer, int size) +{ + while (size) + { + int written = _port->write(buffer, size); + if (written <= 0) + throw SambaError(); + buffer += written; + size -= written; + } +} + +void +Samba::read(uint32_t addr, uint8_t* buffer, int size) +{ + uint8_t cmd[20]; + int chunk; + + if (_debug) + printf("%s(addr=%#x,size=%#x)\n", __FUNCTION__, addr, size); + + // The SAM firmware has a bug reading powers of 2 over 32 bytes + // via USB. If that is the case here, then read the first byte + // with a readByte and then read one less than the requested size. + if (_isUsb && _readBufferSize == 0 && size > 32 && !(size & (size - 1))) + { + *buffer = readByte(addr); + addr++; + buffer++; + size--; + } + + while (size > 0) + { + // Handle any limitations on the size of the read + if (_readBufferSize > 0 && size > _readBufferSize) + chunk = _readBufferSize; + else + chunk = size; + + snprintf((char*) cmd, sizeof(cmd), "R%08X,%08X#", addr, chunk); + if (_port->write(cmd, sizeof(cmd) - 1) != sizeof(cmd) - 1) + throw SambaError(); + + if (_isUsb) + readBinary(buffer, chunk); + else + readXmodem(buffer, chunk); + + size -= chunk; + addr += chunk; + buffer += chunk; + } +} + +void +Samba::write(uint32_t addr, const uint8_t* buffer, int size) +{ + uint8_t cmd[20]; + + if (_debug) + printf("%s(addr=%#x,size=%#x)\n", __FUNCTION__, addr, size); + + snprintf((char*) cmd, sizeof(cmd), "S%08X,%08X#", addr, size); + if (_port->write(cmd, sizeof(cmd) - 1) != sizeof(cmd) - 1) + throw SambaError(); + + // The SAM firmware has a bug that if the command and binary data + // are received in the same USB data packet, then the firmware + // gets confused. Even though the writes are separated in the code, + // USB drivers often do write combining which can put them together + // in the same USB data packet. To avoid this, we call the serial + // port object's flush method before writing the data. + if (_isUsb) + { + _port->flush(); + writeBinary(buffer, size); + } + else + { + writeXmodem(buffer, size); + } +} + +void +Samba::go(uint32_t addr) +{ + uint8_t cmd[11]; + + if (_debug) + printf("%s(addr=%#x)\n", __FUNCTION__, addr); + + snprintf((char*) cmd, sizeof(cmd), "G%08X#", addr); + if (_port->write(cmd, sizeof(cmd) - 1) != sizeof(cmd) - 1) + throw SambaError(); + + // The SAM firmware can get confused if another command is + // received in the same USB data packet as the go command + // so we flush after writing the command over USB. + if (_isUsb) + _port->flush(); +} + +std::string +Samba::version() +{ + uint8_t cmd[256]; + char* str; + int size; + int pos; + + cmd[0] = 'V'; + cmd[1] = '#'; + _port->write(cmd, 2); + + _port->timeout(TIMEOUT_QUICK); + size = _port->read(cmd, sizeof(cmd) - 1); + _port->timeout(TIMEOUT_NORMAL); + if (size <= 0) + throw SambaError(); + + str = (char*) cmd; + for (pos = 0; pos < size; pos++) + { + if (!isprint(str[pos])) + break; + } + str[pos] = '\0'; + + std::string ver(str); + + if (_debug) + printf("%s()=%s\n", __FUNCTION__, ver.c_str()); + + return ver; +} + +void +Samba::chipErase(uint32_t start_addr) +{ + if (!_canChipErase) + throw SambaError(); + + uint8_t cmd[64]; + + if (_debug) + printf("%s(addr=%#x)\n", __FUNCTION__, start_addr); + + int l = snprintf((char*) cmd, sizeof(cmd), "X%08X#", start_addr); + if (_port->write(cmd, l) != l) + throw SambaError(); + _port->timeout(TIMEOUT_LONG); + _port->read(cmd, 3); // Expects "X\n\r" + _port->timeout(TIMEOUT_NORMAL); + if (cmd[0] != 'X') + throw SambaError(); +} + +void +Samba::writeBuffer(uint32_t src_addr, uint32_t dst_addr, uint32_t size) +{ + if (!_canWriteBuffer) + throw SambaError(); + + if (size > checksumBufferSize()) + throw SambaError(); + + if (_debug) + printf("%s(scr_addr=%#x, dst_addr=%#x, size=%#x)\n", __FUNCTION__, src_addr, dst_addr, size); + + uint8_t cmd[64]; + int l = snprintf((char*) cmd, sizeof(cmd), "Y%08X,0#", src_addr); + if (_port->write(cmd, l) != l) + throw SambaError(); + _port->timeout(TIMEOUT_QUICK); + cmd[0] = 0; + _port->read(cmd, 3); // Expects "Y\n\r" + _port->timeout(TIMEOUT_NORMAL); + if (cmd[0] != 'Y') + throw SambaError(); + + l = snprintf((char*) cmd, sizeof(cmd), "Y%08X,%08X#", dst_addr, size); + if (_port->write(cmd, l) != l) + throw SambaError(); + _port->timeout(TIMEOUT_LONG); + cmd[0] = 0; + _port->read(cmd, 3); // Expects "Y\n\r" + _port->timeout(TIMEOUT_NORMAL); + if (cmd[0] != 'Y') + throw SambaError(); +} + +uint16_t +Samba::checksumBuffer(uint32_t start_addr, uint32_t size) +{ + if (!_canChecksumBuffer) + throw SambaError(); + + if (size > checksumBufferSize()) + throw SambaError(); + + if (_debug) + printf("%s(start_addr=%#x, size=%#x) = ", __FUNCTION__, start_addr, size); + + uint8_t cmd[64]; + int l = snprintf((char*) cmd, sizeof(cmd), "Z%08X,%08X#", start_addr, size); + if (_port->write(cmd, l) != l) + throw SambaError(); + _port->timeout(TIMEOUT_LONG); + cmd[0] = 0; + _port->read(cmd, 12); // Expects "Z00000000#\n\r" + _port->timeout(TIMEOUT_NORMAL); + if (cmd[0] != 'Z') + throw SambaError(); + + cmd[9] = 0; + errno = 0; + uint32_t res = strtol((char*) &cmd[1], NULL, 16); + if (errno != 0) + throw SambaError(); + if (_debug) + printf("%x\n", res); + return res; +} + diff --git a/lib/bossac/src/Samba.h b/lib/bossac/src/Samba.h new file mode 100644 index 00000000..84bea406 --- /dev/null +++ b/lib/bossac/src/Samba.h @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _SAMBA_H +#define _SAMBA_H + +#include +#include +#include +#include + +#include "SerialPort.h" + +class SambaError : public std::exception +{ +public: + SambaError() : exception() {}; + const char* what() const throw() { return "SAM-BA operation failed"; } +}; + + + +class Samba +{ +public: + Samba(); + virtual ~Samba(); + + bool connect(SerialPort::Ptr port, int bps = 115200); + void disconnect(); + + void writeByte(uint32_t addr, uint8_t value); + uint8_t readByte(uint32_t addr); + + void writeWord(uint32_t addr, uint32_t value); + uint32_t readWord(uint32_t addr); + + void write(uint32_t addr, const uint8_t* buffer, int size); + void read(uint32_t addr, uint8_t* buffer, int size); + + void go(uint32_t addr); + + std::string version(); + + void chipId(uint32_t& chipId, uint32_t& extChipId); + + void setDebug(bool debug) { _debug = debug; } + + const SerialPort& getSerialPort() { return *_port; } + + void reset(); + + // Extended SAM-BA functions + bool canChipErase() { return _canChipErase; } + void chipErase(uint32_t start_addr); + + bool canWriteBuffer() { return _canWriteBuffer; } + void writeBuffer(uint32_t src_addr, uint32_t dst_addr, uint32_t size); + uint32_t writeBufferSize() { return 4096; } + + bool canChecksumBuffer() { return _canChecksumBuffer; } + uint16_t checksumBuffer(uint32_t start_addr, uint32_t size); + uint32_t checksumBufferSize() { return 4096; } + uint16_t checksumCalc(uint8_t c, uint16_t crc); + +private: + bool _canChipErase; + bool _canWriteBuffer; + bool _canChecksumBuffer; + int _readBufferSize; + bool _debug; + bool _isUsb; + SerialPort::Ptr _port; + + bool init(); + + uint16_t crc16Calc(const uint8_t *data, int len); + bool crc16Check(const uint8_t *blk); + void crc16Add(uint8_t *blk); + void writeXmodem(const uint8_t* buffer, int size); + void readXmodem(uint8_t* buffer, int size); + + void writeBinary(const uint8_t* buffer, int size); + void readBinary(uint8_t* buffer, int size); + +}; + + +#endif // _SAMBA_H diff --git a/lib/bossac/src/SerialPort.h b/lib/bossac/src/SerialPort.h new file mode 100644 index 00000000..6ebbcc7b --- /dev/null +++ b/lib/bossac/src/SerialPort.h @@ -0,0 +1,82 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// +#ifndef _SERIALPORT_H +#define _SERIALPORT_H + +#include +#include +#include + +class SerialPort +{ +public: + SerialPort(const std::string& name) : _name(name) {} + virtual ~SerialPort() {} + + enum Parity + { + ParityNone, + ParityOdd, + ParityEven, + }; + + enum StopBit + { + StopBitOne, + StopBitOneFive, + StopBitTwo, + }; + + virtual bool open(int baud = 115200, + int data = 8, + Parity parity = ParityNone, + StopBit stop = StopBitOne) = 0; + virtual void close() = 0; + + virtual bool isUsb() = 0; + + virtual int read(uint8_t* data, int size) = 0; + virtual int write(const uint8_t* data, int size) = 0; + virtual int get() = 0; + virtual int put(int c) = 0; + + virtual bool timeout(int millisecs) = 0; + virtual void flush() = 0; + virtual void setDTR(bool dtr) = 0; + virtual void setRTS(bool rts) = 0; + + virtual std::string name() const { return _name; } + + typedef std::unique_ptr Ptr; + +protected: + std::string _name; +}; + +#endif // _SERIALPORT_H diff --git a/lib/bossac/src/WordCopyApplet.cpp b/lib/bossac/src/WordCopyApplet.cpp new file mode 100644 index 00000000..39741d96 --- /dev/null +++ b/lib/bossac/src/WordCopyApplet.cpp @@ -0,0 +1,62 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// +#include "WordCopyApplet.h" + +WordCopyApplet::WordCopyApplet(Samba& samba, uint32_t addr) + : Applet(samba, + addr, + applet.code, + sizeof(applet.code), + addr + applet.start, + addr + applet.stack, + addr + applet.reset) +{ +} + +WordCopyApplet::~WordCopyApplet() +{ +} + +void +WordCopyApplet::setDstAddr(uint32_t dstAddr) +{ + _samba.writeWord(_addr + applet.dst_addr, dstAddr); +} + +void +WordCopyApplet::setSrcAddr(uint32_t srcAddr) +{ + _samba.writeWord(_addr + applet.src_addr, srcAddr); +} + +void +WordCopyApplet::setWords(uint32_t words) +{ + _samba.writeWord(_addr + applet.words, words); +} diff --git a/lib/bossac/src/WordCopyApplet.h b/lib/bossac/src/WordCopyApplet.h new file mode 100644 index 00000000..7f6ac95c --- /dev/null +++ b/lib/bossac/src/WordCopyApplet.h @@ -0,0 +1,49 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// +#ifndef _WORDCOPYAPPLET_H +#define _WORDCOPYAPPLET_H + +#include "Applet.h" +#include "WordCopyArm.h" + +class WordCopyApplet : public Applet +{ +public: + WordCopyApplet(Samba& samba, uint32_t addr); + virtual ~WordCopyApplet(); + + void setDstAddr(uint32_t dstAddr); + void setSrcAddr(uint32_t srcAddr); + void setWords(uint32_t words); + +private: + static WordCopyArm applet; +}; + +#endif // _WORDCOPYAPPLET_H diff --git a/lib/bossac/src/WordCopyArm.asm b/lib/bossac/src/WordCopyArm.asm new file mode 100644 index 00000000..b9f291d0 --- /dev/null +++ b/lib/bossac/src/WordCopyArm.asm @@ -0,0 +1,47 @@ + .global start + .global stack + .global reset + .global dst_addr + .global src_addr + .global words + + .text + .thumb + .align 0 + +start: + ldr r0, dst_addr + ldr r1, src_addr + ldr r2, words + b check + +copy: + ldmia r1!, {r3} + stmia r0!, {r3} + sub r2, #1 + +check: + cmp r2, #0 + bne copy + + @ Fix for SAM-BA stack bug + ldr r0, reset + cmp r0, #0 + bne return + ldr r0, stack + mov sp, r0 + +return: + bx lr + + .align 0 +stack: + .word 0 +reset: + .word 0 +dst_addr: + .word 0 +src_addr: + .word 0 +words: + .word 0 diff --git a/lib/bossac/src/WordCopyArm.cpp b/lib/bossac/src/WordCopyArm.cpp new file mode 100644 index 00000000..09bb1175 --- /dev/null +++ b/lib/bossac/src/WordCopyArm.cpp @@ -0,0 +1,25 @@ +// WARNING!!! DO NOT EDIT - FILE GENERATED BY APPLETGEN +#include "WordCopyArm.h" +#include "WordCopyApplet.h" + +WordCopyArm WordCopyApplet::applet = { +// dst_addr +0x00000028, +// reset +0x00000024, +// src_addr +0x0000002c, +// stack +0x00000020, +// start +0x00000000, +// words +0x00000030, +// code +{ +0x09, 0x48, 0x0a, 0x49, 0x0a, 0x4a, 0x02, 0xe0, 0x08, 0xc9, 0x08, 0xc0, 0x01, 0x3a, 0x00, 0x2a, +0xfa, 0xd1, 0x04, 0x48, 0x00, 0x28, 0x01, 0xd1, 0x01, 0x48, 0x85, 0x46, 0x70, 0x47, 0xc0, 0x46, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +} +}; diff --git a/lib/bossac/src/WordCopyArm.h b/lib/bossac/src/WordCopyArm.h new file mode 100644 index 00000000..d3975e83 --- /dev/null +++ b/lib/bossac/src/WordCopyArm.h @@ -0,0 +1,18 @@ +// WARNING!!! DO NOT EDIT - FILE GENERATED BY APPLETGEN +#ifndef _WORDCOPYARM_H +#define _WORDCOPYARM_H + +#include + +typedef struct +{ + uint32_t dst_addr; + uint32_t reset; + uint32_t src_addr; + uint32_t stack; + uint32_t start; + uint32_t words; + uint8_t code[52]; +} WordCopyArm; + +#endif // _WORDCOPYARM_H diff --git a/lib/bossac/src/bossac.cpp b/lib/bossac/src/bossac.cpp new file mode 100644 index 00000000..450d0fa1 --- /dev/null +++ b/lib/bossac/src/bossac.cpp @@ -0,0 +1,489 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2011-2018, ShumaTech +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include + +#include "CmdOpts.h" +#include "Samba.h" +#include "PortFactory.h" +#include "Device.h" +#include "Flasher.h" + +using namespace std; + +class BossaConfig +{ +public: + BossaConfig(); + virtual ~BossaConfig() {} + + bool erase; + bool write; + bool read; + bool verify; + bool offset; + bool reset; + bool port; + bool boot; + bool bor; + bool bod; + bool lock; + bool unlock; + bool security; + bool info; + bool debug; + bool help; + bool usbPort; + bool arduinoErase; + + int readArg; + int offsetArg; + string portArg; + int bootArg; + int bodArg; + int borArg; + string lockArg; + string unlockArg; + bool usbPortArg; +}; + +BossaConfig::BossaConfig() +{ + erase = false; + write = false; + read = false; + verify = false; + port = false; + boot = false; + bod = false; + bor = false; + lock = false; + security = false; + info = false; + help = false; + usbPort = false; + arduinoErase = false; + + readArg = 0; + offsetArg = 0; + bootArg = 1; + bodArg = 1; + borArg = 1; + usbPortArg=1; + + reset = false; +} + +class BossaObserver : public FlasherObserver +{ +public: + BossaObserver() : _lastTicks(-1) {} + virtual ~BossaObserver() {} + + virtual void onStatus(const char *message, ...); + virtual void onProgress(int num, int div); +private: + int _lastTicks; +}; + +void +BossaObserver::onStatus(const char *message, ...) +{ + va_list ap; + + va_start(ap, message); + vprintf(message, ap); + va_end(ap); +} + +void +BossaObserver::onProgress(int num, int div) +{ + int ticks; + int bars = 30; + + ticks = num * bars / div; + + if (ticks == _lastTicks) + return; + + printf("\r["); + while (ticks-- > 0) + { + putchar('='); + bars--; + } + while (bars-- > 0) + { + putchar(' '); + } + printf("] %d%% (%d/%d pages)", num * 100 / div, num, div); + fflush(stdout); + + _lastTicks = 0; +} + +static BossaConfig config; +static Option opts[] = +{ + { + 'e', "erase", &config.erase, + { ArgNone }, + "erase the entire flash starting at the offset" + }, + { + 'w', "write", &config.write, + { ArgNone }, + "write FILE to the flash; accelerated when\n" + "combined with erase option" + }, + { + 'r', "read", &config.read, + { ArgOptional, ArgInt, "SIZE", { &config.readArg } }, + "read SIZE from flash and store in FILE;\n" + "read entire flash if SIZE not specified" + }, + { + 'v', "verify", &config.verify, + { ArgNone }, + "verify FILE matches flash contents" + }, + { + 'o', "offset", &config.offset, + { ArgRequired, ArgInt, "OFFSET", { &config.offsetArg } }, + "start erase/write/read/verify operation at flash OFFSET;\n" + "OFFSET must be aligned to a flash page boundary" + }, + { + 'p', "port", &config.port, + { ArgRequired, ArgString, "PORT", { &config.portArg } }, + "use serial PORT to communicate to device;\n" + "default behavior is to use first serial port" + }, + { + 'b', "boot", &config.boot, + { ArgOptional, ArgInt, "BOOL", { &config.bootArg } }, + "boot from ROM if BOOL is 0;\n" + "boot from FLASH if BOOL is 1 [default];\n" + "option is ignored on unsupported devices" + }, + { + 'c', "bod", &config.bod, + { ArgOptional, ArgInt, "BOOL", { &config.bodArg } }, + "no brownout detection if BOOL is 0;\n" + "brownout detection is on if BOOL is 1 [default]" + }, + { + 't', "bor", &config.bor, + { ArgOptional, ArgInt, "BOOL", { &config.borArg } }, + "no brownout reset if BOOL is 0;\n" + "brownout reset is on if BOOL is 1 [default]" + }, + { + 'l', "lock", &config.lock, + { ArgOptional, ArgString, "REGION", { &config.lockArg } }, + "lock the flash REGION as a comma-separated list;\n" + "lock all if not given [default]" + }, + { + 'u', "unlock", &config.unlock, + { ArgOptional, ArgString, "REGION", { &config.unlockArg } }, + "unlock the flash REGION as a comma-separated list;\n" + "unlock all if not given [default]" + }, + { + 's', "security", &config.security, + { ArgNone }, + "set the flash security flag" + }, + { + 'i', "info", &config.info, + { ArgNone }, + "display device information" + }, + { + 'd', "debug", &config.debug, + { ArgNone }, + "print debug messages" + }, + { + 'h', "help", &config.help, + { ArgNone }, + "display this help text" + }, + { + 'U', "usb-port", &config.usbPort, + { ArgOptional, ArgInt, "BOOL", { &config.usbPortArg } }, + "force serial port detection to USB if BOOL is 1 [default]\n" + "or to RS-232 if BOOL is 0" + }, + { + 'R', "reset", &config.reset, + { ArgNone }, + "reset CPU (if supported)" + }, + { + 'a', "arduino-erase", &config.arduinoErase, + { ArgNone }, + "erase and reset via Arduino 1200 baud hack" + } +}; + +int +help(const char* program) +{ + fprintf(stderr, "Try '%s -h' or '%s --help' for more information\n", program, program); + return 1; +} + +static struct timeval start_time; + +void +timer_start() +{ + gettimeofday(&start_time, NULL); +} + +float +timer_stop() +{ + struct timeval end; + gettimeofday(&end, NULL); + return (end.tv_sec - start_time.tv_sec) + (end.tv_usec - start_time.tv_usec) / 1000000.0; +} + +int +main(int argc, char* argv[]) +{ + int args; + char* pos; + CmdOpts cmd(argc, argv, sizeof(opts) / sizeof(opts[0]), opts); + + if ((pos = strrchr(argv[0], '/')) || (pos = strrchr(argv[0], '\\'))) + argv[0] = pos + 1; + + if (argc <= 1) + { + fprintf(stderr, "%s: you must specify at least one option\n", argv[0]); + return help(argv[0]); + } + + args = cmd.parse(); + if (args < 0) + return help(argv[0]); + + if (config.read && (config.write || config.verify)) + { + fprintf(stderr, "%s: read option is exclusive of write or verify\n", argv[0]); + return help(argv[0]); + } + + if (config.read || config.write || config.verify) + { + if (args == argc) + { + fprintf(stderr, "%s: missing file\n", argv[0]); + return help(argv[0]); + } + argc--; + } + if (args != argc) + { + fprintf(stderr, "%s: extra arguments found\n", argv[0]); + return help(argv[0]); + } + + if (config.help) + { + printf("Usage: %s [OPTION...] [FILE]\n", argv[0]); + printf("Basic Open Source SAM-BA Application (BOSSA) Version " VERSION "\n" + "Flash programmer for Atmel SAM devices.\n" + "Copyright (c) 2011-2018 ShumaTech (http://www.shumatech.com)\n" + "\n" + "Examples:\n" + " bossac -e -w -v -b image.bin # Erase flash, write flash with image.bin,\n" + " # verify the write, and set boot from flash\n" + " bossac -r0x10000 image.bin # Read 64KB from flash and store in image.bin\n" + ); + printf("\nOptions:\n"); + cmd.usage(stdout); + printf("\nReport bugs to \n"); + return 1; + } + + try + { + Samba samba; + PortFactory portFactory; + + if (config.debug) + samba.setDebug(true); + + if (!config.port) + config.portArg = portFactory.def(); + + if (config.arduinoErase) + { + SerialPort::Ptr port; + port = portFactory.create(config.portArg, config.usbPortArg != 0); + + if(!port->open(1200)) + { + fprintf(stderr, "Failed to open port at 1200bps\n"); + return 1; + } + + port->setRTS(true); + port->setDTR(false); + port->close(); + } + + if (config.portArg.empty()) + { + fprintf(stderr, "No serial ports available\n"); + return 1; + } + + bool res; + if (config.usbPort) + res = samba.connect(portFactory.create(config.portArg, config.usbPortArg != 0)); + else + res = samba.connect(portFactory.create(config.portArg)); + if (!res) + { + fprintf(stderr, "No device found on %s\n", config.portArg.c_str()); + return 1; + } + + Device device(samba); + device.create(); + + Device::FlashPtr& flash = device.getFlash(); + + BossaObserver observer; + Flasher flasher(samba, device, observer); + + if (config.info) + { + FlasherInfo info; + flasher.info(info); + info.print(); + } + + if (config.unlock) + flasher.lock(config.unlockArg, false); + + if (config.erase) + { + timer_start(); + flasher.erase(config.offsetArg); + printf("\nDone in %5.3f seconds\n", timer_stop()); + } + + if (config.write) + { + timer_start(); + flasher.write(argv[args], config.offsetArg); + printf("\nDone in %5.3f seconds\n", timer_stop()); + } + + if (config.verify) + { + uint32_t pageErrors; + uint32_t totalErrors; + + timer_start(); + if (!flasher.verify(argv[args], pageErrors, totalErrors, config.offsetArg)) + { + printf("\nVerify failed\nPage errors: %d\nByte errors: %d\n", + pageErrors, totalErrors); + return 2; + } + + printf("\nVerify successful\nDone in %5.3f seconds\n", timer_stop()); + } + + if (config.read) + { + timer_start(); + flasher.read(argv[args], config.readArg, config.offsetArg); + printf("\nDone in %5.3f seconds\n", timer_stop()); + } + + if (config.boot) + { + printf("Set boot flash %s\n", config.bootArg ? "true" : "false"); + flash->setBootFlash(config.bootArg); + } + + if (config.bod) + { + printf("Set brownout detect %s\n", config.bodArg ? "true" : "false"); + flash->setBod(config.bodArg); + } + + if (config.bor) + { + printf("Set brownout reset %s\n", config.borArg ? "true" : "false"); + flash->setBor(config.borArg); + } + + if (config.security) + { + printf("Set security\n"); + flash->setSecurity(); + } + + if (config.lock) + flasher.lock(config.lockArg, true); + + flash->writeOptions(); + + if (config.reset) + device.reset(); + } + catch (exception& e) + { + fprintf(stderr, "\n%s\n", e.what()); + return 1; + } + catch(...) + { + fprintf(stderr, "\nUnhandled exception\n"); + return 1; + } + + return 0; +} +