From 346423c040fe4ac31dae7c1afcb1d853cc80635c Mon Sep 17 00:00:00 2001 From: Cástor Muñoz Date: Thu, 4 Feb 2016 23:05:17 +0100 Subject: mks5lboot v1.0 - dualboot installer for s5l8702 targets A tool to install/uninstall a bootloader into a s5l8702 based device: - iPod Classic 6G - iPod Nano 3G (TODO) See mks5lboot/README for detailed info. Change-Id: I451d2aaff34509ebd356e4660647e5222c5d3409 --- rbutil/mks5lboot/.gitignore | 2 + rbutil/mks5lboot/Makefile | 35 ++ rbutil/mks5lboot/README | 209 ++++++++ rbutil/mks5lboot/dualboot.c | 664 +++++++++++++++++++++++++ rbutil/mks5lboot/dualboot.h | 4 + rbutil/mks5lboot/dualboot/.gitignore | 3 + rbutil/mks5lboot/dualboot/Makefile | 97 ++++ rbutil/mks5lboot/dualboot/autoconf.h | 74 +++ rbutil/mks5lboot/dualboot/bin2c.c | 140 ++++++ rbutil/mks5lboot/dualboot/dualboot.c | 287 +++++++++++ rbutil/mks5lboot/dualboot/dualboot.lds | 59 +++ rbutil/mks5lboot/dualboot/init.S | 43 ++ rbutil/mks5lboot/ipoddfu.c | 875 +++++++++++++++++++++++++++++++++ rbutil/mks5lboot/main.c | 287 +++++++++++ rbutil/mks5lboot/mkdfu.c | 318 ++++++++++++ rbutil/mks5lboot/mks5lboot.h | 129 +++++ 16 files changed, 3226 insertions(+) create mode 100644 rbutil/mks5lboot/.gitignore create mode 100644 rbutil/mks5lboot/Makefile create mode 100644 rbutil/mks5lboot/README create mode 100644 rbutil/mks5lboot/dualboot.c create mode 100644 rbutil/mks5lboot/dualboot.h create mode 100644 rbutil/mks5lboot/dualboot/.gitignore create mode 100644 rbutil/mks5lboot/dualboot/Makefile create mode 100644 rbutil/mks5lboot/dualboot/autoconf.h create mode 100644 rbutil/mks5lboot/dualboot/bin2c.c create mode 100644 rbutil/mks5lboot/dualboot/dualboot.c create mode 100644 rbutil/mks5lboot/dualboot/dualboot.lds create mode 100644 rbutil/mks5lboot/dualboot/init.S create mode 100644 rbutil/mks5lboot/ipoddfu.c create mode 100644 rbutil/mks5lboot/main.c create mode 100644 rbutil/mks5lboot/mkdfu.c create mode 100644 rbutil/mks5lboot/mks5lboot.h (limited to 'rbutil/mks5lboot') diff --git a/rbutil/mks5lboot/.gitignore b/rbutil/mks5lboot/.gitignore new file mode 100644 index 0000000000..9078451a7a --- /dev/null +++ b/rbutil/mks5lboot/.gitignore @@ -0,0 +1,2 @@ +buildposix/ +mks5lboot diff --git a/rbutil/mks5lboot/Makefile b/rbutil/mks5lboot/Makefile new file mode 100644 index 0000000000..ba118eefd0 --- /dev/null +++ b/rbutil/mks5lboot/Makefile @@ -0,0 +1,35 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +CFLAGS += -Wall -Wextra + +OUTPUT = mks5lboot + +# inputs for lib +LIBSOURCES := dualboot.c mkdfu.c ipoddfu.c +# inputs for binary only +SOURCES := $(LIBSOURCES) main.c +# dependencies for binary +EXTRADEPS := + +ifeq ($(findstring MINGW,$(shell uname)),MINGW) +LDOPTS += -lsetupapi +# optional libusb support on Windows +ifdef DISABLE_LIBUSBAPI +CFLAGS += -DNO_LIBUSBAPI +else +LDOPTS += -Wl,-Bstatic -lusb-1.0 +endif +else +# Linux, OS X +LDOPTS += -lusb-1.0 +endif + +include ../libtools.make + +# explicit dependencies on dualboot.{c,h} and mks5lboot.h +$(OBJDIR)mks5lboot.o: dualboot.h dualboot.c mks5lboot.h +$(OBJDIR)main.o: dualboot.h dualboot.c main.c mks5lboot.h diff --git a/rbutil/mks5lboot/README b/rbutil/mks5lboot/README new file mode 100644 index 0000000000..c2df299867 --- /dev/null +++ b/rbutil/mks5lboot/README @@ -0,0 +1,209 @@ +mks5lboot +--------- + +A tool to install/uninstall a dual bootloader into a s5l8702 based +device: + + - iPod Classic 6G + - iPod Nano 3G (TODO) + + +Usage +----- + + mks5lboot --bl-inst [-p ] [--single] + --bl-uninst [-p ] + --dfuscan [--loop []] [-p ] + --dfusend [-p ] + --dfureset [--loop []] [-p ] + --mkdfu-inst [--single] + --mkdfu-uninst + --mkdfu-raw + +Commands: + --bl-inst Install file into an iPod device + (same as --mkdfu-inst and --dfusend). + --bl-uninst Remove a bootloader from an iPod device (same as + --mkdfu-uninst and --dfusend). + + --dfuscan scan for DFU USB devices and outputs the status. + --dfusend send DFU image to the device. + --dfureset reset DFU USB device bus. + + --mkdfu-inst Build a DFU image containing an installer for + , save it as . + --mkdfu-uninst Build a DFU image containing an uninstaler for + devices, save it as . + --mkdfu-raw Build a DFU image containing raw executable + code, save it as . + is the code you want to run, it is loaded at + address 0x2200030c and executed. + + is the rockbox bootloader that you want to + install (previously scrambled with tools/scramble utility). + + is the name of the platform (type of device) for + which the DFU uninstaller will be built. Currently supported + platform names are: + ipod6g: iPod Classic 6G + +Options: + -p, --pid Use a specific (Product Id) USB device, + if this option is ommited then it uses the + first USB DFU device found. + -l, --loop Run the command every seconds, default + period ( ommited) is 1 seconds. + -S, --single Be careful using this option. The bootloader + is installed for single boot, the original + Apple NOR boot is destroyed (if it exists), + and only Rockbox can be used. + + +Dual bootloader installation +---------------------------- + +Prerequisites: + + - An iPod Classic 6th with Apple firmware installed and running, current + supported FW versions for existing models: + + Classic 6th 80/160 Late 2007 (1G): 1.1.2 + Classic 6th 120 Late 2008 (2G): 2.0.1 + Classic 6th 160 Late 2009 (3G): 2.0.4 + Classic 6th 160 Late 2012 (4G): 2.0.5 + + - If your iPod is formated using Apple partitions you must convert this + ipod to FAT32 format (aka a "winpod"), see http://www.rockbox.org/ + wiki/IpodConversionToFAT32 + + - It is recommended to install the RB firmware before installing the dual + bootloader for the first time. Install Rockbox using RockboxUtility or + download the latest daily build and uncompress it into the root folder + of the iPod. + + Windows only: + + - If iTunes is installed: + . Configure iTunes: Summary -> Options -> check "Enable disk use". + + - If iTunes is not installed: + . You need a DFU USB driver for your device. To check if there is a + valid USB driver installed, put your device on DFU mode and choose + one of either: + a) Use Windows Device Manager to verify if you USB DFU device is + present. + b) Use mks5lboot tool running "mks5lboot --dfuscan", common output: + . When the DFU device is found and a valid driver is installed: + [INFO] DFU device state: 2 + . When the device is found but there is no driver installed: + [ERR] Could not open USB device: LIBUSB_ERROR_NOT_SUPPORTED + . Then the device is found but driver is not valid (probably a + libusb-win32 driver is installed): + [ERR] Could not set USB configuration: LIBUSB_ERROR_NOT_FOUND + . If there is no valid DFU driver installed, try one of these: + a) Use Zadig (http://zadig.akeo.ie/) to build and install a WinUSB + (libusb.info) or libusbK driver for your device. Note that + libusb-win32 (libusb0) drivers are not valid for mks5lboot. + b) Use Apple Mobile Device USB driver (included with iTunes). + +Command line install: + + - If you are using iTunes on Windows, close iTunes and kill (or pause) + iTunesHelper.exe before entering DFU mode. + + - Put you device on DFU mode by pressing and holding SELECT+MENU buttons + for about 12 seconds. + + You can notice when the device enters DFU mode running the next command + to scan the USB bus every second (press Ctrl-C to abort the scan): + mks5lboot --dfuscan --loop + + - To install or update a bootloader, build the DFU installer and send it + to the device: + mks5lboot --bl-inst /path/to/bootloader-ipod6g.ipod + + When the DFU imagen is loaded and executed, the device emits an 'alive' + tone (2000Hz/100ms). When the bootloader is successfully installed then + a dual tone beep sounds (1000Hz/100ms+2000Hz/150ms) and the device + reboots. If something went bad then 330Hz/500ms tone is emited and the + device reboots. When three 330Hz tones sounds, it means that the NOR + got corrupted and the device must be restored using iTunes (should not + happen). + + - To remove a previously installed bootloader, build the DFU uninstaler + and send it to the device: + mks5lboot --bl-uninst ipod6g + + If USB access is denied, try to run the mks5lboot tool using a privileged + user (i.e. Administrator or root). + + +Dual-Boot +--------- + +The purpose of this program is to provide dual-boot between the original +firmware and the new (rockbox) firmware. + +The button press check is done ~800 ms. after power-up or reboot, then: + + SELECT + MENU: resets the device after ~5 seconds, then if SELECT+MENU + remains pressed the device enters DFU mode after an + additional period of ~8 seconds. + SELECT + LEFT: enter OF diagnostics (after ~7 seconds). + SELECT + PLAY: enter OF diskmode (after ~7 seconds). + SELECT + RIGHT: enter bootloader USB mode. + MENU: enter OF + Hold Switch locked: enter OF (see below for details). + Any other combination: launch Rockbox. + +Switch current firmware: + + Tries to behave like ipod Video, see http://download.rockbox.org/manual/ + rockbox-ipodvideo/rockbox-buildch3.html#x5-290003.1.3 + + Apple is the current FW: + - Stop playback and wait a few seconds for hard disk spin-down. + - Press and hold SELECT+MENU, after ~5 seconds the player hard resets, + release the buttons when the screen goes black. + + Rockbox is the current FW: + - Shut down the device using "Long Play" key press. + - Once the device is powered off, there are three ways to enter OF: + 1) Press and hold MENU button for at least ~800 ms. + 2) Turn on the Hold switch immediately after turning the player on, + it must be done before "Loading Rockbox..." message appears (~3 + seconds from power-on). Be careful, if the hold switch is locked + when Rockbox starts then your RB settings will be cleared! + 3) You can also load the original firmware by shutting down the + device, then clicking the Hold switch on and connecting the iPod + to your computer. + + +Single-Boot +----------- + +Use --single option if the Apple firmware is not installed on your iPod +and/or you want to force the installation of the bootloader to use Rockbox +as unique firmware. The single-boot installer writes the bootloader on the +NOR with no previous check, the original Apple NOR boot is destroyed if it +exists. + +To build the DFU single-boot installer and send it to the device: + mks5lboot --bl-inst --single /path/to/bootloader-ipod6g.ipod + + +Compilation +----------- + +Needs libusb > 1.0 installed, tested on: + +Linux: gcc-4.9.2 + libusb-1.0.19 +Windows XP: mingw32-gcc-4.8.1 + libusbx-1.0.15 +OS X 10.11: clang-7.3.0 + libusb-1.0.20 + + +Hacking +------- + +See comments in mkdfu.c, ipoddfu.c, dualboot.c and bootloader/ipod6g.c for +more information. diff --git a/rbutil/mks5lboot/dualboot.c b/rbutil/mks5lboot/dualboot.c new file mode 100644 index 0000000000..4c1608fc41 --- /dev/null +++ b/rbutil/mks5lboot/dualboot.c @@ -0,0 +1,664 @@ +/* Generated by bin2c */ + +#include "dualboot.h" + +unsigned char dualboot_install_ipod6g[5396] = { + 0xd7, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x24, 0xd0, 0x9f, 0xe5, 0xdb, 0x00, 0xa0, 0xe3, + 0x00, 0xf0, 0x21, 0xe1, 0x18, 0xd0, 0x9f, 0xe5, 0xd3, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, + 0x10, 0xd0, 0x9f, 0xe5, 0x05, 0x08, 0xa0, 0xe3, 0x78, 0x00, 0x80, 0xe3, 0x10, 0x0f, 0x01, 0xee, + 0x1d, 0x00, 0x00, 0xeb, 0x0c, 0x03, 0x00, 0x22, 0x0c, 0x03, 0x00, 0x22, 0x7f, 0x40, 0x2d, 0xe9, + 0x5c, 0x10, 0x9f, 0xe5, 0x10, 0x20, 0xa0, 0xe3, 0x0d, 0x00, 0xa0, 0xe1, 0xea, 0x04, 0x00, 0xeb, + 0x00, 0x00, 0xa0, 0xe3, 0x02, 0x10, 0xa0, 0xe3, 0x0d, 0x20, 0xa0, 0xe1, 0x10, 0x30, 0xa0, 0xe3, + 0x8d, 0x04, 0x00, 0xeb, 0x3c, 0x60, 0x9f, 0xe5, 0x0d, 0x40, 0xa0, 0xe1, 0x00, 0x50, 0xa0, 0xe3, + 0x06, 0x10, 0xa0, 0xe1, 0x0d, 0x00, 0xa0, 0xe1, 0x10, 0x20, 0xa0, 0xe3, 0x77, 0x00, 0x00, 0xeb, + 0x10, 0x60, 0x86, 0xe2, 0x00, 0x00, 0x50, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0x01, 0x50, 0x85, 0xe2, + 0x04, 0x00, 0x55, 0xe3, 0xf5, 0xff, 0xff, 0x1a, 0x05, 0x00, 0xa0, 0xe1, 0x10, 0xd0, 0x8d, 0xe2, + 0x70, 0x80, 0xbd, 0xe8, 0x10, 0x00, 0x02, 0x22, 0x54, 0x17, 0x00, 0x22, 0x70, 0x40, 0x2d, 0xe9, + 0xae, 0x00, 0x00, 0xeb, 0x7c, 0x41, 0x9f, 0xe5, 0x7c, 0x01, 0x9f, 0xe5, 0xa3, 0x04, 0x00, 0xeb, + 0x00, 0x00, 0xa0, 0xe3, 0x04, 0x10, 0xa0, 0xe3, 0xc4, 0x00, 0x00, 0xeb, 0x0e, 0x30, 0xd4, 0xe5, + 0x0d, 0x00, 0xd4, 0xe5, 0x0c, 0x10, 0xd4, 0xe5, 0x0f, 0x20, 0xd4, 0xe5, 0x03, 0x38, 0xa0, 0xe1, + 0x00, 0x34, 0x83, 0xe1, 0x01, 0x30, 0x83, 0xe1, 0x02, 0x2c, 0x83, 0xe1, 0x40, 0x50, 0xd4, 0xe5, + 0x02, 0x00, 0xa0, 0xe3, 0x02, 0x1b, 0x84, 0xe2, 0x10, 0x30, 0x84, 0xe2, 0xee, 0x01, 0x00, 0xeb, + 0x40, 0x20, 0xa0, 0xe3, 0x02, 0x00, 0xa0, 0xe3, 0x04, 0x10, 0xa0, 0xe1, 0x02, 0x30, 0x84, 0xe0, + 0xe9, 0x01, 0x00, 0xeb, 0x00, 0x00, 0x55, 0xe3, 0x08, 0x00, 0x00, 0x0a, 0x04, 0x10, 0xa0, 0xe1, + 0x02, 0x09, 0xa0, 0xe3, 0x62, 0x03, 0x00, 0xeb, 0x10, 0x31, 0x9f, 0xe5, 0x10, 0x21, 0x9f, 0xe5, + 0x00, 0x00, 0x50, 0xe3, 0x02, 0x00, 0xa0, 0x11, 0x03, 0x00, 0xa0, 0x01, 0x33, 0x00, 0x00, 0xea, + 0x02, 0x09, 0xa0, 0xe3, 0xfc, 0x10, 0x9f, 0xe5, 0xfc, 0x20, 0x9f, 0xe5, 0x77, 0x03, 0x00, 0xeb, + 0x00, 0x00, 0x50, 0xe3, 0x2c, 0x00, 0x00, 0x1a, 0xb7, 0xff, 0xff, 0xeb, 0x04, 0x00, 0x50, 0xe3, + 0x0a, 0x00, 0x00, 0x1a, 0xdc, 0x00, 0x9f, 0xe5, 0xc5, 0x01, 0x00, 0xeb, 0xd4, 0x10, 0x9f, 0xe5, + 0xd4, 0x20, 0x9f, 0xe5, 0x02, 0x09, 0x80, 0xe2, 0x6c, 0x03, 0x00, 0xeb, 0x00, 0x00, 0x50, 0xe3, + 0x21, 0x00, 0x00, 0x1a, 0xac, 0xff, 0xff, 0xeb, 0x04, 0x00, 0x50, 0xe3, 0x1e, 0x00, 0x00, 0x0a, + 0xa0, 0x00, 0x9f, 0xe5, 0xba, 0x01, 0x00, 0xeb, 0x00, 0x40, 0xa0, 0xe1, 0x23, 0x03, 0x00, 0xeb, + 0x04, 0x00, 0x50, 0xe1, 0xa4, 0x00, 0x9f, 0x35, 0x18, 0x00, 0x00, 0x3a, 0x02, 0x09, 0x84, 0xe2, + 0x90, 0x10, 0x9f, 0xe5, 0x3e, 0x03, 0x00, 0xeb, 0x00, 0x00, 0x50, 0xe3, 0x05, 0x00, 0x00, 0x0a, + 0x02, 0x09, 0xa0, 0xe3, 0x6c, 0x10, 0x9f, 0xe5, 0x39, 0x03, 0x00, 0xeb, 0x00, 0x00, 0x50, 0xe3, + 0x6c, 0x00, 0x9f, 0x15, 0x0d, 0x00, 0x00, 0x1a, 0x6c, 0x20, 0x9f, 0xe5, 0x01, 0x00, 0xa0, 0xe3, + 0x60, 0x10, 0x9f, 0xe5, 0xc8, 0x01, 0x00, 0xeb, 0x02, 0x09, 0xa0, 0xe3, 0x54, 0x10, 0x9f, 0xe5, + 0x2f, 0x03, 0x00, 0xeb, 0x58, 0x30, 0x9f, 0xe5, 0x0c, 0x20, 0x83, 0xe2, 0x00, 0x00, 0x50, 0xe3, + 0x03, 0x00, 0xa0, 0x01, 0x02, 0x00, 0xa0, 0x11, 0x00, 0x00, 0x00, 0xea, 0x2c, 0x00, 0x9f, 0xe5, + 0x40, 0x20, 0x9f, 0xe5, 0x40, 0x30, 0x9f, 0xe5, 0xb4, 0x10, 0x92, 0xe5, 0x03, 0x00, 0x51, 0xe1, + 0xfc, 0xff, 0xff, 0x9a, 0x49, 0x04, 0x00, 0xeb, 0x01, 0x26, 0xa0, 0xe3, 0xf2, 0x35, 0xa0, 0xe3, + 0x00, 0x20, 0x83, 0xe5, 0xfe, 0xff, 0xff, 0xea, 0xd0, 0x17, 0x00, 0x22, 0x94, 0x17, 0x00, 0x22, + 0x4c, 0x17, 0x00, 0x22, 0x9c, 0x17, 0x00, 0x22, 0x00, 0x00, 0x02, 0x22, 0x00, 0x08, 0x02, 0x22, + 0x46, 0x17, 0x00, 0x22, 0x40, 0x17, 0x00, 0x22, 0x00, 0x00, 0x70, 0x3c, 0x7f, 0x84, 0x1e, 0x00, + 0x10, 0x40, 0x2d, 0xe9, 0x00, 0x30, 0xa0, 0xe3, 0x07, 0x00, 0x00, 0xea, 0x03, 0x40, 0xd0, 0xe7, + 0x03, 0xc0, 0xd1, 0xe7, 0x01, 0x20, 0x42, 0xe2, 0x0c, 0x00, 0x54, 0xe1, 0x01, 0x30, 0x83, 0xe2, + 0x01, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x6c, 0xe0, 0x10, 0x80, 0xbd, 0xe8, 0x00, 0x00, 0x52, 0xe3, + 0xf5, 0xff, 0xff, 0x1a, 0x02, 0x00, 0xa0, 0xe1, 0x10, 0x80, 0xbd, 0xe8, 0x1f, 0x30, 0x00, 0xe2, + 0x01, 0x20, 0xa0, 0xe3, 0xc0, 0x02, 0xa0, 0xe1, 0x00, 0x00, 0x51, 0xe3, 0x12, 0x33, 0xa0, 0xe1, + 0x02, 0x20, 0x00, 0xe0, 0x08, 0x00, 0x00, 0x0a, 0x3c, 0x10, 0x9f, 0xe5, 0x3c, 0x00, 0x9f, 0xe5, + 0x00, 0x00, 0x52, 0xe3, 0x00, 0x20, 0xa0, 0x11, 0x01, 0x20, 0xa0, 0x01, 0x00, 0x10, 0x92, 0xe5, + 0x03, 0x30, 0xc1, 0xe1, 0x00, 0x30, 0x82, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x18, 0x10, 0x9f, 0xe5, + 0x18, 0x00, 0x9f, 0xe5, 0x00, 0x00, 0x52, 0xe3, 0x01, 0x00, 0xa0, 0x01, 0x00, 0x20, 0x90, 0xe5, + 0x03, 0x30, 0x82, 0xe1, 0x00, 0x30, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x48, 0x00, 0x50, 0x3c, + 0x4c, 0x00, 0x50, 0x3c, 0x70, 0x40, 0x2d, 0xe9, 0x10, 0x50, 0x9d, 0xe5, 0x01, 0x30, 0x43, 0xe2, + 0x01, 0x50, 0x45, 0xe2, 0x03, 0x60, 0x02, 0xe2, 0x0f, 0x30, 0x03, 0xe2, 0x05, 0x52, 0xa0, 0xe1, + 0x03, 0xc0, 0xc0, 0xe3, 0xff, 0x50, 0x05, 0xe2, 0x06, 0x36, 0x83, 0xe1, 0x00, 0x40, 0x9c, 0xe5, + 0x05, 0x30, 0x83, 0xe1, 0x30, 0x50, 0x9f, 0xe5, 0x02, 0x20, 0x00, 0xe2, 0x82, 0x21, 0xa0, 0xe1, + 0x00, 0x00, 0x51, 0xe3, 0x02, 0x19, 0xa0, 0x03, 0x00, 0x10, 0xa0, 0x13, 0x35, 0x42, 0x04, 0xe0, + 0x01, 0x30, 0x83, 0xe1, 0x13, 0x22, 0x84, 0xe1, 0x00, 0x20, 0x8c, 0xe5, 0xb0, 0x20, 0xd0, 0xe1, + 0x03, 0x00, 0x52, 0xe1, 0xfc, 0xff, 0xff, 0x1a, 0x70, 0x80, 0xbd, 0xe8, 0x00, 0x00, 0xff, 0xff, + 0x5c, 0xc0, 0x9f, 0xe5, 0x13, 0x40, 0x2d, 0xe9, 0x44, 0xe0, 0x9c, 0xe5, 0x01, 0x40, 0xa0, 0xe3, + 0x01, 0xec, 0xce, 0xe3, 0x00, 0x20, 0xa0, 0xe3, 0x04, 0x30, 0xa0, 0xe1, 0x44, 0xe0, 0x8c, 0xe5, + 0x40, 0x00, 0x9f, 0xe5, 0x04, 0x10, 0xa0, 0xe1, 0x00, 0x40, 0x8d, 0xe5, 0xd8, 0xff, 0xff, 0xeb, + 0x04, 0x10, 0xa0, 0xe1, 0x25, 0x00, 0xa0, 0xe3, 0xbb, 0xff, 0xff, 0xeb, 0x28, 0x30, 0x9f, 0xe5, + 0x11, 0x2d, 0xa0, 0xe3, 0xa0, 0x20, 0x83, 0xe5, 0x0b, 0x20, 0xa0, 0xe3, 0xb0, 0x20, 0x83, 0xe5, + 0x00, 0x20, 0xe0, 0xe3, 0xa8, 0x20, 0x83, 0xe5, 0x04, 0x20, 0x82, 0xe2, 0xa4, 0x20, 0x83, 0xe5, + 0x1c, 0x80, 0xbd, 0xe8, 0x00, 0x00, 0x50, 0x3c, 0x12, 0x00, 0x50, 0x3c, 0x00, 0x00, 0x70, 0x3c, + 0x04, 0x30, 0x9f, 0xe5, 0x00, 0x11, 0x83, 0xe7, 0x1e, 0xff, 0x2f, 0xe1, 0xac, 0x17, 0x00, 0x22, + 0x80, 0x20, 0x9f, 0xe5, 0x00, 0x00, 0x51, 0xe3, 0x7c, 0x30, 0x9f, 0xe5, 0x02, 0x30, 0xa0, 0x11, + 0x01, 0x00, 0x50, 0xe3, 0x0a, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x50, 0xe3, 0x0f, 0x00, 0x00, 0x0a, + 0x00, 0x00, 0x50, 0xe3, 0x1e, 0xff, 0x2f, 0x11, 0x60, 0x10, 0x9f, 0xe5, 0x00, 0x20, 0x91, 0xe5, + 0x22, 0x28, 0xa0, 0xe1, 0x02, 0x28, 0xa0, 0xe1, 0x02, 0x30, 0x83, 0xe1, 0x00, 0x30, 0x81, 0xe5, + 0x1e, 0xff, 0x2f, 0xe1, 0x44, 0x10, 0x9f, 0xe5, 0xc0, 0x20, 0x91, 0xe5, 0x02, 0x28, 0xa0, 0xe1, + 0x22, 0x28, 0xa0, 0xe1, 0x03, 0x38, 0x82, 0xe1, 0xc0, 0x30, 0x81, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, + 0x28, 0x00, 0x9f, 0xe5, 0xc0, 0x21, 0x90, 0xe5, 0xff, 0x24, 0xc2, 0xe3, 0x03, 0x2c, 0x82, 0xe1, + 0xc0, 0x21, 0x80, 0xe5, 0xe0, 0x21, 0x90, 0xe5, 0xff, 0x20, 0xc2, 0xe3, 0x23, 0x34, 0x82, 0xe1, + 0xe0, 0x31, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x22, 0x22, 0x00, 0x00, 0xef, 0xee, 0x00, 0x00, + 0x00, 0x00, 0xf0, 0x3c, 0x01, 0x00, 0x50, 0xe3, 0x01, 0x10, 0x21, 0xe2, 0x06, 0x00, 0x00, 0x0a, + 0x02, 0x00, 0x50, 0xe3, 0x06, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x50, 0xe3, 0x24, 0x30, 0x9f, 0x05, + 0x0e, 0x10, 0x81, 0x03, 0x00, 0x12, 0x83, 0x05, 0x1e, 0xff, 0x2f, 0xe1, 0x18, 0x30, 0x9f, 0xe5, + 0x00, 0x00, 0x00, 0xea, 0x14, 0x30, 0x9f, 0xe5, 0x08, 0x20, 0x9f, 0xe5, 0x03, 0x30, 0x81, 0xe1, + 0x00, 0x32, 0x82, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0xf0, 0x3c, 0x0e, 0x04, 0x06, 0x00, + 0x0e, 0x06, 0x0e, 0x00, 0x02, 0x00, 0x50, 0xe3, 0x10, 0x40, 0x2d, 0xe9, 0xbc, 0x30, 0x9f, 0x05, + 0x03, 0x00, 0x00, 0x0a, 0xb8, 0x20, 0x9f, 0xe5, 0x01, 0x00, 0x50, 0xe3, 0xb4, 0x30, 0x9f, 0xe5, + 0x02, 0x30, 0xa0, 0x01, 0xb0, 0x40, 0x9f, 0xe5, 0xb0, 0xc0, 0x9f, 0xe5, 0x01, 0x20, 0xa0, 0xe3, + 0x00, 0x20, 0x83, 0xe5, 0x02, 0x00, 0x50, 0xe3, 0xa4, 0x30, 0x9f, 0x05, 0x02, 0x00, 0x00, 0x0a, + 0x01, 0x00, 0x50, 0xe3, 0x04, 0x30, 0xa0, 0x01, 0x0c, 0x30, 0xa0, 0x11, 0x00, 0x30, 0x93, 0xe5, + 0x1f, 0x3e, 0x03, 0xe2, 0x01, 0x0c, 0x53, 0xe3, 0xf5, 0xff, 0xff, 0x0a, 0x02, 0x00, 0x50, 0xe3, + 0x80, 0x30, 0x9f, 0x05, 0x03, 0x00, 0x00, 0x0a, 0x7c, 0x20, 0x9f, 0xe5, 0x01, 0x00, 0x50, 0xe3, + 0x78, 0x30, 0x9f, 0xe5, 0x02, 0x30, 0xa0, 0x01, 0x5c, 0xc0, 0x9f, 0xe5, 0x5c, 0x20, 0x9f, 0xe5, + 0x00, 0x10, 0x83, 0xe5, 0x02, 0x00, 0x50, 0xe3, 0x54, 0x30, 0x9f, 0x05, 0x02, 0x00, 0x00, 0x0a, + 0x01, 0x00, 0x50, 0xe3, 0x0c, 0x30, 0xa0, 0x01, 0x02, 0x30, 0xa0, 0x11, 0x00, 0x30, 0x93, 0xe5, + 0x3e, 0x0c, 0x13, 0xe3, 0xf6, 0xff, 0xff, 0x0a, 0x02, 0x00, 0x50, 0xe3, 0x40, 0x00, 0x9f, 0x05, + 0x04, 0x00, 0x00, 0x0a, 0x3c, 0x30, 0x9f, 0xe5, 0x3c, 0x20, 0x9f, 0xe5, 0x01, 0x00, 0x50, 0xe3, + 0x02, 0x00, 0xa0, 0x01, 0x03, 0x00, 0xa0, 0x11, 0x00, 0x00, 0x90, 0xe5, 0x10, 0x80, 0xbd, 0xe8, + 0x34, 0x00, 0x20, 0x3d, 0x34, 0x00, 0xe0, 0x3c, 0x34, 0x00, 0x30, 0x3c, 0x08, 0x00, 0xe0, 0x3c, + 0x08, 0x00, 0x30, 0x3c, 0x08, 0x00, 0x20, 0x3d, 0x10, 0x00, 0x20, 0x3d, 0x10, 0x00, 0xe0, 0x3c, + 0x10, 0x00, 0x30, 0x3c, 0x20, 0x00, 0x20, 0x3d, 0x20, 0x00, 0x30, 0x3c, 0x20, 0x00, 0xe0, 0x3c, + 0x02, 0x00, 0x50, 0xe3, 0xf0, 0x40, 0x2d, 0xe9, 0xd8, 0x30, 0x9f, 0x05, 0x03, 0x00, 0x00, 0x0a, + 0xd4, 0xc0, 0x9f, 0xe5, 0x01, 0x00, 0x50, 0xe3, 0xd0, 0x30, 0x9f, 0xe5, 0x0c, 0x30, 0xa0, 0x01, + 0x02, 0x00, 0x50, 0xe3, 0x00, 0x10, 0x83, 0xe5, 0xc4, 0x30, 0x9f, 0x05, 0x03, 0x00, 0x00, 0x0a, + 0xc0, 0xc0, 0x9f, 0xe5, 0x01, 0x00, 0x50, 0xe3, 0xbc, 0x30, 0x9f, 0xe5, 0x0c, 0x30, 0xa0, 0x01, + 0x00, 0x40, 0x93, 0xe5, 0x00, 0xc0, 0xa0, 0xe3, 0x01, 0x40, 0x84, 0xe3, 0x00, 0x40, 0x83, 0xe5, + 0xa8, 0x70, 0x9f, 0xe5, 0xa8, 0x60, 0x9f, 0xe5, 0xa8, 0x50, 0x9f, 0xe5, 0xa8, 0x40, 0x9f, 0xe5, + 0x12, 0x00, 0x00, 0xea, 0x02, 0x00, 0x50, 0xe3, 0xa0, 0x30, 0x9f, 0x05, 0x02, 0x00, 0x00, 0x0a, + 0x01, 0x00, 0x50, 0xe3, 0x07, 0x30, 0xa0, 0x01, 0x06, 0x30, 0xa0, 0x11, 0x00, 0x30, 0x93, 0xe5, + 0x3e, 0x0c, 0x13, 0xe3, 0xf6, 0xff, 0xff, 0x0a, 0x02, 0x00, 0x50, 0xe3, 0x80, 0x30, 0x9f, 0x05, + 0x02, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe3, 0x05, 0x30, 0xa0, 0x01, 0x04, 0x30, 0xa0, 0x11, + 0x00, 0x30, 0x93, 0xe5, 0x01, 0x10, 0x41, 0xe2, 0x0c, 0x30, 0xc2, 0xe7, 0x01, 0xc0, 0x8c, 0xe2, + 0x00, 0x00, 0x51, 0xe3, 0xea, 0xff, 0xff, 0x1a, 0x02, 0x00, 0x50, 0xe3, 0x30, 0x00, 0x9f, 0x05, + 0x04, 0x00, 0x00, 0x0a, 0x2c, 0x30, 0x9f, 0xe5, 0x2c, 0x20, 0x9f, 0xe5, 0x01, 0x00, 0x50, 0xe3, + 0x02, 0x00, 0xa0, 0x11, 0x03, 0x00, 0xa0, 0x01, 0x00, 0x30, 0x90, 0xe5, 0x01, 0x30, 0xc3, 0xe3, + 0x00, 0x30, 0x80, 0xe5, 0xf0, 0x80, 0xbd, 0xe8, 0x34, 0x00, 0x20, 0x3d, 0x34, 0x00, 0xe0, 0x3c, + 0x34, 0x00, 0x30, 0x3c, 0x04, 0x00, 0x20, 0x3d, 0x04, 0x00, 0xe0, 0x3c, 0x04, 0x00, 0x30, 0x3c, + 0x08, 0x00, 0xe0, 0x3c, 0x08, 0x00, 0x30, 0x3c, 0x20, 0x00, 0xe0, 0x3c, 0x20, 0x00, 0x30, 0x3c, + 0x08, 0x00, 0x20, 0x3d, 0x20, 0x00, 0x20, 0x3d, 0x02, 0x00, 0x50, 0xe3, 0x2e, 0x00, 0x80, 0x02, + 0x02, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe3, 0x2b, 0x00, 0xa0, 0x03, 0x22, 0x00, 0xa0, 0x13, + 0x00, 0x10, 0xa0, 0xe3, 0xe4, 0xfe, 0xff, 0xea, 0x02, 0x00, 0x50, 0xe3, 0x10, 0x40, 0x2d, 0xe9, + 0x00, 0x40, 0xa0, 0xe1, 0x30, 0x00, 0xa0, 0x03, 0x02, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x54, 0xe3, + 0x2b, 0x00, 0xa0, 0x03, 0x22, 0x00, 0xa0, 0x13, 0x01, 0x10, 0xa0, 0xe3, 0xda, 0xfe, 0xff, 0xeb, + 0x02, 0x00, 0x54, 0xe3, 0x04, 0x31, 0x9f, 0x05, 0x03, 0x00, 0x00, 0x0a, 0x00, 0x21, 0x9f, 0xe5, + 0x01, 0x00, 0x54, 0xe3, 0xfc, 0x30, 0x9f, 0xe5, 0x02, 0x30, 0xa0, 0x01, 0x02, 0x00, 0x54, 0xe3, + 0x0f, 0x20, 0xa0, 0xe3, 0x00, 0x20, 0x83, 0xe5, 0xec, 0x30, 0x9f, 0x05, 0x03, 0x00, 0x00, 0x0a, + 0xe8, 0x20, 0x9f, 0xe5, 0x01, 0x00, 0x54, 0xe3, 0xe4, 0x30, 0x9f, 0xe5, 0x02, 0x30, 0xa0, 0x01, + 0x00, 0x20, 0x93, 0xe5, 0x02, 0x00, 0x54, 0xe3, 0x0c, 0x20, 0x82, 0xe3, 0x00, 0x20, 0x83, 0xe5, + 0xd0, 0x30, 0x9f, 0x05, 0x03, 0x00, 0x00, 0x0a, 0xcc, 0x20, 0x9f, 0xe5, 0x01, 0x00, 0x54, 0xe3, + 0xc8, 0x30, 0x9f, 0xe5, 0x02, 0x30, 0xa0, 0x01, 0xc4, 0x20, 0x9f, 0xe5, 0x02, 0x00, 0x54, 0xe3, + 0x04, 0x21, 0x92, 0xe7, 0x00, 0x20, 0x83, 0xe5, 0xb8, 0x30, 0x9f, 0x05, 0x03, 0x00, 0x00, 0x0a, + 0xb4, 0x20, 0x9f, 0xe5, 0x01, 0x00, 0x54, 0xe3, 0xb0, 0x30, 0x9f, 0xe5, 0x02, 0x30, 0xa0, 0x01, + 0x02, 0x00, 0x54, 0xe3, 0x06, 0x20, 0xa0, 0xe3, 0x00, 0x20, 0x83, 0xe5, 0xa0, 0x30, 0x9f, 0x05, + 0x03, 0x00, 0x00, 0x0a, 0x9c, 0x20, 0x9f, 0xe5, 0x01, 0x00, 0x54, 0xe3, 0x98, 0x30, 0x9f, 0xe5, + 0x02, 0x30, 0xa0, 0x01, 0x94, 0x20, 0x9f, 0xe5, 0x02, 0x00, 0x54, 0xe3, 0x00, 0x20, 0x83, 0xe5, + 0x54, 0x30, 0x9f, 0x05, 0x03, 0x00, 0x00, 0x0a, 0x50, 0x20, 0x9f, 0xe5, 0x01, 0x00, 0x54, 0xe3, + 0x4c, 0x30, 0x9f, 0xe5, 0x02, 0x30, 0xa0, 0x01, 0x00, 0x20, 0x93, 0xe5, 0x02, 0x00, 0x54, 0xe3, + 0x0c, 0x20, 0x82, 0xe3, 0x00, 0x20, 0x83, 0xe5, 0x2c, 0x40, 0x9f, 0x05, 0x04, 0x00, 0x00, 0x0a, + 0x2c, 0x30, 0x9f, 0xe5, 0x24, 0x20, 0x9f, 0xe5, 0x01, 0x00, 0x54, 0xe3, 0x02, 0x40, 0xa0, 0x01, + 0x03, 0x40, 0xa0, 0x11, 0x01, 0x30, 0xa0, 0xe3, 0x00, 0x30, 0x84, 0xe5, 0x10, 0x80, 0xbd, 0xe8, + 0x08, 0x00, 0x20, 0x3d, 0x08, 0x00, 0xe0, 0x3c, 0x08, 0x00, 0x30, 0x3c, 0x00, 0x00, 0x20, 0x3d, + 0x00, 0x00, 0xe0, 0x3c, 0x00, 0x00, 0x30, 0x3c, 0x30, 0x00, 0x20, 0x3d, 0x30, 0x00, 0xe0, 0x3c, + 0x30, 0x00, 0x30, 0x3c, 0xac, 0x17, 0x00, 0x22, 0x0c, 0x00, 0x20, 0x3d, 0x0c, 0x00, 0xe0, 0x3c, + 0x0c, 0x00, 0x30, 0x3c, 0x04, 0x00, 0x20, 0x3d, 0x04, 0x00, 0xe0, 0x3c, 0x04, 0x00, 0x30, 0x3c, + 0x18, 0x06, 0x01, 0x00, 0x0c, 0x30, 0x80, 0xe2, 0x02, 0xc0, 0xd3, 0xe5, 0x01, 0x10, 0xd3, 0xe5, + 0x0c, 0x20, 0xd0, 0xe5, 0x03, 0x30, 0xd3, 0xe5, 0x0c, 0x08, 0xa0, 0xe1, 0x01, 0x04, 0x80, 0xe1, + 0x02, 0x00, 0x80, 0xe1, 0x03, 0x0c, 0x80, 0xe1, 0x5f, 0x0d, 0x80, 0xe2, 0x3f, 0x00, 0x80, 0xe2, + 0xff, 0x0e, 0xc0, 0xe3, 0x0f, 0x00, 0xc0, 0xe3, 0x1e, 0xff, 0x2f, 0xe1, 0x70, 0x40, 0x2d, 0xe9, + 0x18, 0xd0, 0x4d, 0xe2, 0x04, 0x40, 0x8d, 0xe2, 0x03, 0x50, 0xa0, 0xe1, 0x00, 0x60, 0xa0, 0xe1, + 0x01, 0x00, 0xa0, 0xe1, 0x02, 0x10, 0xa0, 0xe1, 0x04, 0x20, 0xa0, 0xe1, 0xf5, 0x01, 0x00, 0xeb, + 0x04, 0x10, 0xa0, 0xe1, 0x05, 0x00, 0xa0, 0xe1, 0x10, 0x20, 0xa0, 0xe3, 0xc2, 0x02, 0x00, 0xeb, + 0x06, 0x10, 0xa0, 0xe1, 0x05, 0x20, 0xa0, 0xe1, 0x01, 0x00, 0xa0, 0xe3, 0x10, 0x30, 0xa0, 0xe3, + 0x65, 0x02, 0x00, 0xeb, 0x18, 0xd0, 0x8d, 0xe2, 0x70, 0x80, 0xbd, 0xe8, 0x01, 0x00, 0x50, 0xe3, + 0xf0, 0x47, 0x2d, 0xe9, 0x0c, 0x50, 0xd1, 0xe5, 0x0c, 0x30, 0x81, 0xe2, 0x00, 0x40, 0xa0, 0xe1, + 0x01, 0x00, 0xa0, 0x03, 0x02, 0x00, 0xa0, 0x13, 0x03, 0x80, 0xd3, 0xe5, 0x02, 0x70, 0xd3, 0xe5, + 0x01, 0x60, 0xd3, 0xe5, 0x02, 0xa0, 0xa0, 0xe1, 0x07, 0x00, 0xc1, 0xe5, 0x40, 0x30, 0x81, 0xe2, + 0x02, 0x00, 0xa0, 0xe3, 0x40, 0x20, 0xa0, 0xe3, 0xdb, 0xff, 0xff, 0xeb, 0x07, 0x78, 0xa0, 0xe1, + 0x06, 0x64, 0x87, 0xe1, 0x05, 0x50, 0x86, 0xe1, 0x08, 0x3c, 0x85, 0xe1, 0x04, 0x00, 0xa0, 0xe1, + 0x0a, 0x20, 0xa0, 0xe1, 0x02, 0x10, 0xa0, 0xe3, 0xf0, 0x47, 0xbd, 0xe8, 0x4a, 0x02, 0x00, 0xea, + 0x10, 0x40, 0x2d, 0xe9, 0x00, 0x40, 0xa0, 0xe1, 0x04, 0x00, 0xa0, 0xe1, 0x01, 0x10, 0xa0, 0xe3, + 0xbf, 0xfe, 0xff, 0xeb, 0x05, 0x10, 0xa0, 0xe3, 0x04, 0x00, 0xa0, 0xe1, 0xd0, 0xfe, 0xff, 0xeb, + 0xff, 0x10, 0xa0, 0xe3, 0x04, 0x00, 0xa0, 0xe1, 0xcd, 0xfe, 0xff, 0xeb, 0x00, 0x10, 0xa0, 0xe3, + 0x01, 0x30, 0x10, 0xe2, 0x04, 0x00, 0xa0, 0xe1, 0x01, 0x00, 0x00, 0x0a, 0xb4, 0xfe, 0xff, 0xeb, + 0xf0, 0xff, 0xff, 0xea, 0x04, 0x00, 0xa0, 0xe1, 0x03, 0x10, 0xa0, 0xe1, 0x10, 0x40, 0xbd, 0xe8, + 0xaf, 0xfe, 0xff, 0xea, 0x70, 0x40, 0x2d, 0xe9, 0x00, 0x50, 0x51, 0xe2, 0x00, 0x40, 0xa0, 0xe1, + 0x07, 0x00, 0x00, 0x1a, 0x01, 0x10, 0x81, 0xe2, 0xa9, 0xfe, 0xff, 0xeb, 0x04, 0x10, 0xa0, 0xe3, + 0x04, 0x00, 0xa0, 0xe1, 0xba, 0xfe, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x05, 0x10, 0xa0, 0xe1, + 0xa3, 0xfe, 0xff, 0xeb, 0x01, 0x10, 0xa0, 0xe3, 0x04, 0x00, 0xa0, 0xe1, 0xa0, 0xfe, 0xff, 0xeb, + 0x50, 0x10, 0xa0, 0xe3, 0x04, 0x00, 0xa0, 0xe1, 0xb1, 0xfe, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, + 0x00, 0x10, 0xa0, 0xe3, 0x9a, 0xfe, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x01, 0x10, 0xa0, 0xe3, + 0x97, 0xfe, 0xff, 0xeb, 0x01, 0x10, 0xa0, 0xe3, 0x04, 0x00, 0xa0, 0xe1, 0xa8, 0xfe, 0xff, 0xeb, + 0x00, 0x00, 0x55, 0xe3, 0x1c, 0x10, 0xa0, 0x03, 0x00, 0x10, 0xa0, 0x13, 0x04, 0x00, 0xa0, 0xe1, + 0xa3, 0xfe, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x00, 0x10, 0xa0, 0xe3, 0x8c, 0xfe, 0xff, 0xeb, + 0x00, 0x00, 0x55, 0xe3, 0x70, 0x80, 0xbd, 0x08, 0x04, 0x00, 0xa0, 0xe1, 0x01, 0x10, 0xa0, 0xe3, + 0x87, 0xfe, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x06, 0x10, 0xa0, 0xe3, 0x98, 0xfe, 0xff, 0xeb, + 0x04, 0x00, 0xa0, 0xe1, 0x00, 0x10, 0xa0, 0xe3, 0x70, 0x40, 0xbd, 0xe8, 0x80, 0xfe, 0xff, 0xea, + 0x70, 0x40, 0x2d, 0xe9, 0x00, 0x40, 0xa0, 0xe1, 0x01, 0x50, 0xa0, 0xe1, 0x1d, 0xff, 0xff, 0xeb, + 0x04, 0x00, 0xa0, 0xe1, 0xb5, 0xff, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x01, 0x10, 0xa0, 0xe3, + 0xc7, 0xff, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 0x74, 0xfe, 0xff, 0xeb, + 0x04, 0x00, 0xa0, 0xe1, 0x20, 0x10, 0xa0, 0xe3, 0x85, 0xfe, 0xff, 0xeb, 0x25, 0x18, 0xa0, 0xe1, + 0xff, 0x10, 0x01, 0xe2, 0x04, 0x00, 0xa0, 0xe1, 0x81, 0xfe, 0xff, 0xeb, 0x25, 0x14, 0xa0, 0xe1, + 0xff, 0x10, 0x01, 0xe2, 0x04, 0x00, 0xa0, 0xe1, 0x7d, 0xfe, 0xff, 0xeb, 0xff, 0x10, 0x05, 0xe2, + 0x04, 0x00, 0xa0, 0xe1, 0x7a, 0xfe, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x00, 0x10, 0xa0, 0xe3, + 0x63, 0xfe, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x00, 0x10, 0xa0, 0xe3, 0xb0, 0xff, 0xff, 0xeb, + 0x04, 0x00, 0xa0, 0xe1, 0x70, 0x40, 0xbd, 0xe8, 0xf6, 0xfe, 0xff, 0xea, 0xf0, 0x45, 0x2d, 0xe9, + 0x00, 0x40, 0xa0, 0xe1, 0x24, 0xd0, 0x4d, 0xe2, 0x02, 0x50, 0xa0, 0xe1, 0x03, 0x70, 0xa0, 0xe1, + 0x01, 0x60, 0xa0, 0xe1, 0xf7, 0xfe, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x8f, 0xff, 0xff, 0xeb, + 0x04, 0x00, 0xa0, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 0x51, 0xfe, 0xff, 0xeb, 0x03, 0x10, 0xa0, 0xe3, + 0x04, 0x00, 0xa0, 0xe1, 0x62, 0xfe, 0xff, 0xeb, 0x26, 0x18, 0xa0, 0xe1, 0xff, 0x10, 0x01, 0xe2, + 0x04, 0x00, 0xa0, 0xe1, 0x5e, 0xfe, 0xff, 0xeb, 0x26, 0x14, 0xa0, 0xe1, 0xff, 0x10, 0x01, 0xe2, + 0x04, 0x00, 0xa0, 0xe1, 0x5a, 0xfe, 0xff, 0xeb, 0xff, 0x10, 0x06, 0xe2, 0x04, 0x00, 0xa0, 0xe1, + 0x57, 0xfe, 0xff, 0xeb, 0x00, 0x60, 0xa0, 0xe3, 0x0d, 0x80, 0xa0, 0xe1, 0x15, 0x00, 0x00, 0xea, + 0x20, 0x00, 0x57, 0xe3, 0x07, 0xa0, 0xa0, 0xb1, 0x20, 0xa0, 0xa0, 0xa3, 0x04, 0x00, 0xa0, 0xe1, + 0x0a, 0x10, 0xa0, 0xe1, 0x0d, 0x20, 0xa0, 0xe1, 0x8c, 0xfe, 0xff, 0xeb, 0x05, 0x00, 0xa0, 0xe1, + 0x0d, 0x10, 0xa0, 0xe1, 0x0a, 0x20, 0xa0, 0xe1, 0xac, 0xfd, 0xff, 0xeb, 0x00, 0x30, 0xa0, 0xe3, + 0x00, 0x00, 0x50, 0xe3, 0x01, 0x60, 0x86, 0x13, 0x03, 0x20, 0xd8, 0xe7, 0x02, 0x30, 0x83, 0xe2, + 0xff, 0x00, 0x52, 0xe3, 0x02, 0x60, 0x86, 0x13, 0x0a, 0x00, 0x53, 0xe1, 0xf9, 0xff, 0xff, 0xba, + 0x20, 0x50, 0x85, 0xe2, 0x20, 0x70, 0x47, 0xe2, 0x00, 0x00, 0x57, 0xe3, 0xe7, 0xff, 0xff, 0xca, + 0x00, 0x10, 0xa0, 0xe3, 0x04, 0x00, 0xa0, 0xe1, 0x25, 0xfe, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, + 0xbc, 0xfe, 0xff, 0xeb, 0x06, 0x00, 0xa0, 0xe1, 0x24, 0xd0, 0x8d, 0xe2, 0xf0, 0x85, 0xbd, 0xe8, + 0xf0, 0x4f, 0x2d, 0xe9, 0x00, 0x40, 0xa0, 0xe1, 0x14, 0xd0, 0x4d, 0xe2, 0x01, 0x50, 0xa0, 0xe1, + 0x02, 0x70, 0xa0, 0xe1, 0x03, 0x80, 0xa0, 0xe1, 0x53, 0x00, 0x00, 0xea, 0x05, 0x6a, 0xa0, 0xe1, + 0x26, 0x6a, 0xa0, 0xe1, 0x01, 0x6a, 0x66, 0xe2, 0x08, 0x00, 0x56, 0xe1, 0x08, 0x60, 0xa0, 0xa1, + 0x04, 0x00, 0xa0, 0xe1, 0x05, 0x10, 0xa0, 0xe1, 0x07, 0x20, 0xa0, 0xe1, 0x06, 0x30, 0xa0, 0xe1, + 0xb1, 0xff, 0xff, 0xeb, 0x01, 0x00, 0x10, 0xe3, 0x44, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x10, 0xe3, + 0x03, 0x00, 0x00, 0x0a, 0xff, 0x1e, 0xc5, 0xe3, 0x0f, 0x10, 0xc1, 0xe3, 0x04, 0x00, 0xa0, 0xe1, + 0x86, 0xff, 0xff, 0xeb, 0x00, 0x30, 0xa0, 0xe3, 0x03, 0x20, 0xd7, 0xe7, 0x07, 0x90, 0xa0, 0xe1, + 0xff, 0x00, 0x52, 0xe3, 0x01, 0x30, 0x83, 0xe2, 0x02, 0x00, 0x00, 0x1a, 0x06, 0x00, 0x53, 0xe1, + 0xf8, 0xff, 0xff, 0xba, 0x35, 0x00, 0x00, 0xea, 0x04, 0x00, 0xa0, 0xe1, 0x9d, 0xfe, 0xff, 0xeb, + 0x04, 0x00, 0xa0, 0xe1, 0x35, 0xff, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x01, 0x10, 0xa0, 0xe3, + 0x47, 0xff, 0xff, 0xeb, 0x25, 0x34, 0xa0, 0xe1, 0xff, 0x30, 0x03, 0xe2, 0x25, 0x28, 0xa0, 0xe1, + 0xff, 0x20, 0x02, 0xe2, 0x08, 0x30, 0x8d, 0xe5, 0x06, 0xa0, 0xa0, 0xe1, 0xff, 0x30, 0x05, 0xe2, + 0x01, 0xb0, 0xa0, 0xe3, 0x04, 0x20, 0x8d, 0xe5, 0x0c, 0x30, 0x8d, 0xe5, 0x04, 0x00, 0xa0, 0xe1, + 0x01, 0x10, 0xa0, 0xe3, 0xea, 0xfd, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0xad, 0x10, 0xa0, 0xe3, + 0xfb, 0xfd, 0xff, 0xeb, 0x00, 0x00, 0x5b, 0xe3, 0x00, 0xb0, 0xa0, 0xe3, 0x08, 0x00, 0x00, 0x0a, + 0x04, 0x10, 0x9d, 0xe5, 0x04, 0x00, 0xa0, 0xe1, 0xf5, 0xfd, 0xff, 0xeb, 0x08, 0x10, 0x9d, 0xe5, + 0x04, 0x00, 0xa0, 0xe1, 0xf2, 0xfd, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x0c, 0x10, 0x9d, 0xe5, + 0xef, 0xfd, 0xff, 0xeb, 0x00, 0x10, 0xd9, 0xe5, 0x04, 0x00, 0xa0, 0xe1, 0xec, 0xfd, 0xff, 0xeb, + 0x01, 0x10, 0xd9, 0xe5, 0x04, 0x00, 0xa0, 0xe1, 0xe9, 0xfd, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, + 0x00, 0x10, 0xa0, 0xe3, 0xd2, 0xfd, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x0b, 0xff, 0xff, 0xeb, + 0x02, 0xa0, 0x5a, 0xe2, 0x02, 0x90, 0x89, 0xe2, 0xdf, 0xff, 0xff, 0x1a, 0x04, 0x00, 0xa0, 0xe1, + 0x0a, 0x10, 0xa0, 0xe1, 0x1a, 0xff, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x61, 0xfe, 0xff, 0xeb, + 0x08, 0x80, 0x66, 0xe0, 0x06, 0x70, 0x87, 0xe0, 0x06, 0x50, 0x85, 0xe0, 0x00, 0x00, 0x58, 0xe3, + 0xa9, 0xff, 0xff, 0xca, 0x14, 0xd0, 0x8d, 0xe2, 0xf0, 0x8f, 0xbd, 0xe8, 0xf0, 0x41, 0x2d, 0xe9, + 0x00, 0x40, 0xa0, 0xe1, 0x03, 0x50, 0xa0, 0xe1, 0x02, 0x70, 0xa0, 0xe1, 0x01, 0x60, 0xa0, 0xe1, + 0x5c, 0xfe, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0xf4, 0xfe, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, + 0x01, 0x10, 0xa0, 0xe3, 0xb6, 0xfd, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x03, 0x10, 0xa0, 0xe3, + 0xc7, 0xfd, 0xff, 0xeb, 0x26, 0x18, 0xa0, 0xe1, 0xff, 0x10, 0x01, 0xe2, 0x04, 0x00, 0xa0, 0xe1, + 0xc3, 0xfd, 0xff, 0xeb, 0x26, 0x14, 0xa0, 0xe1, 0xff, 0x10, 0x01, 0xe2, 0x04, 0x00, 0xa0, 0xe1, + 0xbf, 0xfd, 0xff, 0xeb, 0xff, 0x10, 0x06, 0xe2, 0x04, 0x00, 0xa0, 0xe1, 0xbc, 0xfd, 0xff, 0xeb, + 0x04, 0x00, 0xa0, 0xe1, 0x07, 0x10, 0xa0, 0xe1, 0x05, 0x20, 0xa0, 0xe1, 0xf7, 0xfd, 0xff, 0xeb, + 0x04, 0x00, 0xa0, 0xe1, 0x00, 0x10, 0xa0, 0xe3, 0xa1, 0xfd, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, + 0xf0, 0x41, 0xbd, 0xe8, 0x37, 0xfe, 0xff, 0xea, 0x00, 0x10, 0xa0, 0xe3, 0x77, 0xfd, 0xff, 0xea, + 0x10, 0x40, 0x2d, 0xe9, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x40, 0xa0, 0xe1, 0x73, 0xfd, 0xff, 0xeb, + 0x04, 0x00, 0xa0, 0xe1, 0x00, 0x10, 0xa0, 0xe3, 0x10, 0x40, 0xbd, 0xe8, 0x94, 0xfd, 0xff, 0xea, + 0xf0, 0x40, 0x2d, 0xe9, 0x6c, 0x40, 0x9f, 0xe5, 0x2c, 0xd0, 0x4d, 0xe2, 0x00, 0x00, 0xa0, 0xe3, + 0xf2, 0xff, 0xff, 0xeb, 0x60, 0x70, 0x9f, 0xe5, 0x04, 0x50, 0xa0, 0xe1, 0x0d, 0x60, 0xa0, 0xe1, + 0x04, 0x10, 0xa0, 0xe1, 0x28, 0x20, 0xa0, 0xe3, 0x0d, 0x30, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe3, + 0xc5, 0xff, 0xff, 0xeb, 0x0d, 0x00, 0xa0, 0xe1, 0x40, 0x10, 0x9f, 0xe5, 0x04, 0x20, 0xa0, 0xe3, + 0xfa, 0xfc, 0xff, 0xeb, 0x28, 0x40, 0x84, 0xe2, 0x00, 0x00, 0x50, 0xe3, 0x04, 0x00, 0x00, 0x1a, + 0x0c, 0x30, 0x9d, 0xe5, 0x03, 0x00, 0x55, 0xe1, 0x03, 0x50, 0xa0, 0x21, 0x07, 0x00, 0x54, 0xe1, + 0xee, 0xff, 0xff, 0x1a, 0x00, 0x00, 0xa0, 0xe3, 0xda, 0xff, 0xff, 0xeb, 0x0a, 0x09, 0x45, 0xe2, + 0x2c, 0xd0, 0x8d, 0xe2, 0xf0, 0x80, 0xbd, 0xe8, 0x00, 0xfe, 0x0f, 0x00, 0xe0, 0xff, 0x0f, 0x00, + 0xb8, 0x17, 0x00, 0x22, 0x0c, 0x30, 0x81, 0xe2, 0x70, 0x40, 0x2d, 0xe9, 0x02, 0x50, 0xd3, 0xe5, + 0x01, 0x40, 0xa0, 0xe1, 0x01, 0x10, 0xd3, 0xe5, 0x0c, 0x20, 0xd4, 0xe5, 0x03, 0x30, 0xd3, 0xe5, + 0x05, 0x58, 0xa0, 0xe1, 0x01, 0x54, 0x85, 0xe1, 0x02, 0x50, 0x85, 0xe1, 0x03, 0x5c, 0x85, 0xe1, + 0x00, 0x60, 0xa0, 0xe1, 0x02, 0x5b, 0x85, 0xe2, 0x00, 0x00, 0xa0, 0xe3, 0xc7, 0xff, 0xff, 0xeb, + 0x06, 0x10, 0xa0, 0xe1, 0x04, 0x20, 0xa0, 0xe1, 0x05, 0x30, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe3, + 0x3e, 0xff, 0xff, 0xeb, 0x04, 0x20, 0xa0, 0xe1, 0x06, 0x10, 0xa0, 0xe1, 0x05, 0x30, 0xa0, 0xe1, + 0x00, 0x00, 0xa0, 0xe3, 0xfc, 0xfe, 0xff, 0xeb, 0x00, 0x40, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe3, + 0xb8, 0xff, 0xff, 0xeb, 0x01, 0x00, 0x24, 0xe2, 0x01, 0x00, 0x00, 0xe2, 0x70, 0x80, 0xbd, 0xe8, + 0xf0, 0x45, 0x2d, 0xe9, 0x01, 0x40, 0xa0, 0xe1, 0x14, 0xd0, 0x4d, 0xe2, 0x00, 0x80, 0xa0, 0xe1, + 0x00, 0x00, 0xa0, 0xe3, 0x02, 0x60, 0xa0, 0xe1, 0xb0, 0xff, 0xff, 0xeb, 0x08, 0x10, 0xa0, 0xe1, + 0x02, 0x2b, 0xa0, 0xe3, 0x04, 0x30, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe3, 0x86, 0xff, 0xff, 0xeb, + 0x00, 0x00, 0xa0, 0xe3, 0xa7, 0xff, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x40, 0x11, 0x9f, 0xe5, + 0x04, 0x20, 0xa0, 0xe3, 0xb9, 0xfc, 0xff, 0xeb, 0x00, 0x00, 0x50, 0xe3, 0x00, 0x00, 0xe0, 0x13, + 0x49, 0x00, 0x00, 0x1a, 0x04, 0x10, 0xa0, 0xe1, 0x40, 0x20, 0xa0, 0xe3, 0x0d, 0x30, 0xa0, 0xe1, + 0x02, 0x00, 0xa0, 0xe3, 0x48, 0xfe, 0xff, 0xeb, 0x0d, 0x00, 0xa0, 0xe1, 0x40, 0x10, 0x84, 0xe2, + 0x10, 0x20, 0xa0, 0xe3, 0xad, 0xfc, 0xff, 0xeb, 0x0d, 0x50, 0xa0, 0xe1, 0x00, 0x70, 0x50, 0xe2, + 0x01, 0x00, 0xe0, 0x13, 0x3c, 0x00, 0x00, 0x1a, 0x0c, 0x30, 0x84, 0xe2, 0x02, 0x50, 0xd3, 0xe5, + 0x01, 0x10, 0xd3, 0xe5, 0x0c, 0x20, 0xd4, 0xe5, 0x05, 0x58, 0xa0, 0xe1, 0x03, 0x30, 0xd3, 0xe5, + 0x01, 0x54, 0x85, 0xe1, 0x02, 0x50, 0x85, 0xe1, 0x03, 0x5c, 0x85, 0xe1, 0x7e, 0x0b, 0x55, 0xe3, + 0x2e, 0x00, 0x00, 0x8a, 0x08, 0x30, 0x84, 0xe2, 0x02, 0xc0, 0xd3, 0xe5, 0x01, 0xa0, 0xd3, 0xe5, + 0x08, 0x10, 0xd4, 0xe5, 0x03, 0x20, 0xd3, 0xe5, 0x0c, 0xc8, 0xa0, 0xe1, 0x0a, 0x34, 0x8c, 0xe1, + 0x01, 0x30, 0x83, 0xe1, 0x02, 0x3c, 0x83, 0xe1, 0x05, 0x00, 0x53, 0xe1, 0x23, 0x00, 0x00, 0x8a, + 0x07, 0x30, 0xd4, 0xe5, 0x01, 0x30, 0x43, 0xe2, 0x01, 0x00, 0x53, 0xe3, 0x03, 0x00, 0xe0, 0x83, + 0x21, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x56, 0xe3, 0x1e, 0x00, 0x00, 0x0a, 0x77, 0xff, 0xff, 0xeb, + 0x06, 0x30, 0xa0, 0xe1, 0x07, 0x00, 0xa0, 0xe1, 0x02, 0x1b, 0x88, 0xe2, 0x05, 0x20, 0xa0, 0xe1, + 0x4d, 0xff, 0xff, 0xeb, 0x07, 0x00, 0xa0, 0xe1, 0x6e, 0xff, 0xff, 0xeb, 0x07, 0x30, 0xd4, 0xe5, + 0x01, 0x00, 0x53, 0xe3, 0x03, 0x00, 0x00, 0x1a, 0x07, 0x00, 0xa0, 0xe1, 0x04, 0x10, 0xa0, 0xe1, + 0x06, 0x20, 0xa0, 0xe1, 0x28, 0xfe, 0xff, 0xeb, 0x06, 0x10, 0xa0, 0xe1, 0x05, 0x20, 0xa0, 0xe1, + 0x0d, 0x30, 0xa0, 0xe1, 0x02, 0x00, 0xa0, 0xe3, 0x0f, 0xfe, 0xff, 0xeb, 0x0d, 0x00, 0xa0, 0xe1, + 0x10, 0x10, 0x84, 0xe2, 0x10, 0x20, 0xa0, 0xe3, 0x74, 0xfc, 0xff, 0xeb, 0x0d, 0x70, 0xa0, 0xe1, + 0x00, 0x00, 0x50, 0xe3, 0x04, 0x00, 0xe0, 0x13, 0x02, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x00, 0xea, + 0x02, 0x00, 0xe0, 0xe3, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0xa0, 0xe3, 0x14, 0xd0, 0x8d, 0xe2, + 0xf0, 0x85, 0xbd, 0xe8, 0xbd, 0x17, 0x00, 0x22, 0xf0, 0x4f, 0x2d, 0xe9, 0x00, 0x50, 0xa0, 0xe1, + 0x54, 0xd0, 0x4d, 0xe2, 0x01, 0x40, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe3, 0x01, 0x10, 0xa0, 0xe3, + 0x02, 0x60, 0xa0, 0xe1, 0x70, 0xfc, 0xff, 0xeb, 0x0e, 0x23, 0xa0, 0xe3, 0x01, 0x10, 0xa0, 0xe3, + 0x02, 0xc0, 0xa0, 0xe1, 0x10, 0x30, 0x8d, 0xe2, 0x04, 0x10, 0x82, 0xe5, 0x00, 0x00, 0x9c, 0xe5, + 0x0e, 0x23, 0xa0, 0xe3, 0x01, 0x00, 0x10, 0xe2, 0xfb, 0xff, 0xff, 0x1a, 0x40, 0xc0, 0x64, 0xe2, + 0xa4, 0x72, 0xa0, 0xe1, 0x84, 0xe1, 0xa0, 0xe1, 0x7c, 0x81, 0x9f, 0xe5, 0xa4, 0xaa, 0xa0, 0xe1, + 0xa4, 0x96, 0xa0, 0xe1, 0xff, 0x70, 0x07, 0xe2, 0xff, 0xe0, 0x0e, 0xe2, 0x0c, 0xc0, 0x65, 0xe0, + 0xff, 0x90, 0x09, 0xe2, 0x04, 0x70, 0x8d, 0xe5, 0x00, 0xe0, 0x8d, 0xe5, 0x0c, 0xc0, 0x8d, 0xe5, + 0x02, 0x10, 0xa0, 0xe1, 0xff, 0xa0, 0x0a, 0xe2, 0x00, 0x70, 0xa0, 0xe1, 0xa4, 0x4e, 0xa0, 0xe1, + 0x10, 0xc0, 0x8d, 0xe2, 0x02, 0xe0, 0xa0, 0xe1, 0x04, 0x00, 0x82, 0xe5, 0x08, 0x90, 0x8d, 0xe5, + 0x00, 0x00, 0x82, 0xe5, 0x0c, 0x20, 0x9d, 0xe5, 0x02, 0x00, 0x85, 0xe0, 0x00, 0x00, 0x50, 0xe3, + 0x25, 0x00, 0x00, 0xda, 0x00, 0x20, 0xa0, 0xe3, 0x02, 0x70, 0x8c, 0xe7, 0x04, 0x20, 0x82, 0xe2, + 0x40, 0x00, 0x52, 0xe3, 0xfb, 0xff, 0xff, 0x1a, 0x40, 0x00, 0x50, 0xe3, 0x07, 0x20, 0xa0, 0xd1, + 0x40, 0x90, 0x60, 0xd2, 0x03, 0x00, 0x00, 0xda, 0x09, 0x00, 0x00, 0xea, 0x02, 0xb0, 0xd5, 0xe7, + 0x02, 0xb0, 0xcc, 0xe7, 0x01, 0x20, 0x82, 0xe2, 0x09, 0x00, 0x52, 0xe1, 0xfa, 0xff, 0xff, 0xba, + 0x07, 0x00, 0x50, 0xe3, 0x7f, 0x20, 0xe0, 0xe3, 0x09, 0x20, 0xc3, 0xe7, 0x00, 0x00, 0xa0, 0xd3, + 0x08, 0x00, 0x00, 0xda, 0x3b, 0x40, 0xc3, 0xe5, 0x3c, 0xa0, 0xc3, 0xe5, 0x08, 0x20, 0x9d, 0xe5, + 0x01, 0x00, 0xa0, 0xe3, 0x3d, 0x20, 0xc3, 0xe5, 0x04, 0x20, 0x9d, 0xe5, 0x3e, 0x20, 0xc3, 0xe5, + 0x00, 0x20, 0x9d, 0xe5, 0x3f, 0x20, 0xc3, 0xe5, 0xb0, 0x20, 0x9f, 0xe5, 0x02, 0x90, 0x8c, 0xe0, + 0x32, 0x93, 0x89, 0xe2, 0x40, 0x90, 0x49, 0xe2, 0x00, 0x90, 0x99, 0xe5, 0x04, 0x90, 0x82, 0xe4, + 0x08, 0x00, 0x52, 0xe1, 0xf8, 0xff, 0xff, 0x1a, 0x09, 0x00, 0x00, 0xea, 0x8c, 0x20, 0x9f, 0xe5, + 0x02, 0x00, 0x85, 0xe0, 0x32, 0x03, 0x80, 0xe2, 0x40, 0x00, 0x40, 0xe2, 0x00, 0x00, 0x90, 0xe5, + 0x04, 0x00, 0x82, 0xe4, 0x08, 0x00, 0x52, 0xe1, 0xf8, 0xff, 0xff, 0x1a, 0x40, 0x50, 0x85, 0xe2, + 0x00, 0x00, 0xa0, 0xe3, 0x00, 0x20, 0x91, 0xe5, 0x02, 0x20, 0x82, 0xe3, 0x00, 0x20, 0x81, 0xe5, + 0x00, 0x20, 0x91, 0xe5, 0x01, 0x00, 0x12, 0xe3, 0xfc, 0xff, 0xff, 0x1a, 0x00, 0x20, 0x9e, 0xe5, + 0x00, 0x00, 0x50, 0xe3, 0x08, 0x20, 0x82, 0xe3, 0x00, 0x20, 0x8e, 0xe5, 0xc0, 0xff, 0xff, 0x0a, + 0x3c, 0x30, 0x9f, 0xe5, 0x3c, 0x10, 0x9f, 0xe5, 0x03, 0x20, 0xa0, 0xe1, 0x06, 0x00, 0x92, 0xe6, + 0x04, 0x30, 0x83, 0xe2, 0x32, 0x23, 0x82, 0xe2, 0x20, 0x20, 0x42, 0xe2, 0x01, 0x00, 0x53, 0xe1, + 0x00, 0x00, 0x82, 0xe5, 0xf7, 0xff, 0xff, 0x1a, 0x00, 0x00, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe1, + 0x05, 0xfc, 0xff, 0xeb, 0x54, 0xd0, 0x8d, 0xe2, 0xf0, 0x8f, 0xbd, 0xe8, 0x80, 0x00, 0x00, 0x38, + 0x40, 0x00, 0x00, 0x38, 0x20, 0x00, 0x00, 0x38, 0x34, 0x00, 0x00, 0x38, 0xf0, 0x47, 0x2d, 0xe9, + 0x00, 0x40, 0xa0, 0xe1, 0x01, 0x50, 0xa0, 0xe1, 0x0a, 0x00, 0xa0, 0xe3, 0x01, 0x10, 0xa0, 0xe3, + 0xe3, 0x85, 0xa0, 0xe3, 0x03, 0x60, 0xa0, 0xe1, 0x02, 0x70, 0xa0, 0xe1, 0x01, 0xa0, 0xa0, 0xe3, + 0xf5, 0xfb, 0xff, 0xeb, 0x00, 0x30, 0xa0, 0xe3, 0x74, 0x30, 0x88, 0xe5, 0x78, 0x30, 0x88, 0xe5, + 0x7c, 0x30, 0x88, 0xe5, 0x80, 0x30, 0x88, 0xe5, 0x08, 0xa0, 0x88, 0xe5, 0x08, 0x30, 0x88, 0xe5, + 0x00, 0xa0, 0x88, 0xe5, 0x10, 0x30, 0x88, 0xe5, 0x6c, 0x50, 0x88, 0xe5, 0x6c, 0x20, 0x98, 0xe5, + 0x0a, 0x00, 0x54, 0xe1, 0x09, 0x40, 0xa0, 0x03, 0x08, 0x40, 0xa0, 0x13, 0x02, 0x20, 0xe0, 0xe1, + 0x88, 0x20, 0x88, 0xe5, 0x8c, 0x30, 0x88, 0xe5, 0x14, 0x40, 0x88, 0xe5, 0x18, 0x60, 0x88, 0xe5, + 0x20, 0x70, 0x88, 0xe5, 0x24, 0x60, 0x88, 0xe5, 0x28, 0x70, 0x88, 0xe5, 0x2c, 0x60, 0x88, 0xe5, + 0x30, 0x70, 0x88, 0xe5, 0x34, 0x60, 0x88, 0xe5, 0x3c, 0x00, 0x00, 0xeb, 0x08, 0x30, 0xa0, 0xe1, + 0x04, 0xa0, 0x88, 0xe5, 0x0c, 0x20, 0x93, 0xe5, 0x0f, 0x00, 0x12, 0xe3, 0xfc, 0xff, 0xff, 0x0a, + 0x0a, 0x00, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0xf0, 0x47, 0xbd, 0xe8, 0xd2, 0xfb, 0xff, 0xea, + 0x98, 0x30, 0x9f, 0xe5, 0xf0, 0x45, 0x2d, 0xe9, 0x94, 0xc0, 0x9f, 0xe5, 0xfa, 0x4f, 0xa0, 0xe3, + 0x03, 0x60, 0xa0, 0xe1, 0x8c, 0x50, 0x9f, 0xe5, 0x1c, 0x00, 0x00, 0xea, 0xb4, 0x10, 0x93, 0xe5, + 0xb2, 0x80, 0xd0, 0xe1, 0xa2, 0xa0, 0xa0, 0xe1, 0x94, 0x18, 0x27, 0xe0, 0x00, 0x20, 0xa0, 0xe3, + 0x09, 0x00, 0x00, 0xea, 0x01, 0x20, 0x22, 0xe2, 0x06, 0x1c, 0x82, 0xe3, 0x0e, 0x10, 0x81, 0xe3, + 0x00, 0x12, 0x8c, 0xe5, 0xb4, 0x10, 0x93, 0xe5, 0x01, 0x10, 0x8a, 0xe0, 0xb4, 0x80, 0x93, 0xe5, + 0x08, 0x80, 0x61, 0xe0, 0x00, 0x00, 0x58, 0xe3, 0xfb, 0xff, 0xff, 0xba, 0xb4, 0x10, 0x93, 0xe5, + 0x01, 0x10, 0x67, 0xe0, 0x00, 0x00, 0x51, 0xe3, 0xf1, 0xff, 0xff, 0xba, 0x00, 0x52, 0x8c, 0xe5, + 0xb4, 0x70, 0xd0, 0xe1, 0xb4, 0x10, 0x96, 0xe5, 0x94, 0x17, 0x22, 0xe0, 0xb4, 0x10, 0x93, 0xe5, + 0x01, 0x10, 0x62, 0xe0, 0x00, 0x00, 0x51, 0xe3, 0xfb, 0xff, 0xff, 0xba, 0x06, 0x00, 0x80, 0xe2, + 0xb0, 0x20, 0xd0, 0xe1, 0x00, 0x00, 0x52, 0xe3, 0xdf, 0xff, 0xff, 0x1a, 0xf0, 0x85, 0xbd, 0xe8, + 0x00, 0x00, 0x70, 0x3c, 0x00, 0x00, 0xf0, 0x3c, 0x0e, 0x06, 0x00, 0x00, 0x00, 0x30, 0xa0, 0xe3, + 0x02, 0x00, 0x00, 0xea, 0x03, 0xc0, 0xd1, 0xe7, 0x03, 0xc0, 0xc0, 0xe7, 0x01, 0x30, 0x83, 0xe2, + 0x00, 0x00, 0x52, 0xe3, 0x01, 0x20, 0x42, 0xe2, 0xf9, 0xff, 0xff, 0x1a, 0x1e, 0xff, 0x2f, 0xe1, + 0x7e, 0xff, 0x17, 0xee, 0xfd, 0xff, 0xff, 0x1a, 0x00, 0x10, 0xa0, 0xe3, 0x9a, 0x1f, 0x07, 0xee, + 0x1e, 0xff, 0x2f, 0xe1, 0xb8, 0x0b, 0xf4, 0x01, 0xf4, 0x01, 0xb8, 0x0b, 0xf4, 0x01, 0xf4, 0x01, + 0xb8, 0x0b, 0xf4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x76, 0xdc, 0x1d, 0x32, 0xb2, 0x46, + 0xa6, 0xc9, 0x7d, 0x5a, 0x61, 0xd3, 0x49, 0x4c, 0x1e, 0xf0, 0xd9, 0xde, 0xc2, 0x7e, 0xec, 0x02, + 0x7c, 0x15, 0x76, 0xbb, 0x5c, 0x4f, 0x2d, 0x95, 0x06, 0x85, 0xdf, 0x28, 0xe4, 0xd7, 0xf4, 0x82, + 0xc0, 0x73, 0xb0, 0x53, 0x26, 0xfc, 0xb0, 0xfe, 0x60, 0x80, 0x7d, 0x33, 0xa8, 0xde, 0xf8, 0x49, + 0xbb, 0xbe, 0x01, 0x45, 0xff, 0x62, 0x40, 0x19, 0xf4, 0x01, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe8, 0x03, 0x64, 0x00, 0x00, 0x00, 0xf4, 0x01, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x68, 0x73, 0x6c, 0x66, + 0x00, 0x38, 0x37, 0x30, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x37, 0x30, 0x32, 0x31, 0x2e, 0x30, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; +unsigned char dualboot_uninstall_ipod6g[5076] = { + 0xd7, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x24, 0xd0, 0x9f, 0xe5, 0xdb, 0x00, 0xa0, 0xe3, + 0x00, 0xf0, 0x21, 0xe1, 0x18, 0xd0, 0x9f, 0xe5, 0xd3, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, + 0x10, 0xd0, 0x9f, 0xe5, 0x05, 0x08, 0xa0, 0xe3, 0x78, 0x00, 0x80, 0xe3, 0x10, 0x0f, 0x01, 0xee, + 0x1d, 0x00, 0x00, 0xeb, 0x0c, 0x03, 0x00, 0x22, 0x0c, 0x03, 0x00, 0x22, 0x7f, 0x40, 0x2d, 0xe9, + 0x5c, 0x10, 0x9f, 0xe5, 0x10, 0x20, 0xa0, 0xe3, 0x0d, 0x00, 0xa0, 0xe1, 0xaf, 0x04, 0x00, 0xeb, + 0x00, 0x00, 0xa0, 0xe3, 0x02, 0x10, 0xa0, 0xe3, 0x0d, 0x20, 0xa0, 0xe1, 0x10, 0x30, 0xa0, 0xe3, + 0x52, 0x04, 0x00, 0xeb, 0x3c, 0x60, 0x9f, 0xe5, 0x0d, 0x40, 0xa0, 0xe1, 0x00, 0x50, 0xa0, 0xe3, + 0x06, 0x10, 0xa0, 0xe1, 0x0d, 0x00, 0xa0, 0xe1, 0x10, 0x20, 0xa0, 0xe3, 0x50, 0x00, 0x00, 0xeb, + 0x10, 0x60, 0x86, 0xe2, 0x00, 0x00, 0x50, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0x01, 0x50, 0x85, 0xe2, + 0x04, 0x00, 0x55, 0xe3, 0xf5, 0xff, 0xff, 0x1a, 0x05, 0x00, 0xa0, 0xe1, 0x10, 0xd0, 0x8d, 0xe2, + 0x70, 0x80, 0xbd, 0xe8, 0x10, 0x00, 0x02, 0x22, 0x68, 0x16, 0x00, 0x22, 0x70, 0x40, 0x2d, 0xe9, + 0x87, 0x00, 0x00, 0xeb, 0xe8, 0x00, 0x9f, 0xe5, 0x69, 0x04, 0x00, 0xeb, 0x00, 0x00, 0xa0, 0xe3, + 0x04, 0x10, 0xa0, 0xe3, 0x9e, 0x00, 0x00, 0xeb, 0x02, 0x09, 0xa0, 0xe3, 0xd4, 0x10, 0x9f, 0xe5, + 0x00, 0x20, 0xa0, 0xe3, 0x5a, 0x03, 0x00, 0xeb, 0x00, 0x00, 0x50, 0xe3, 0x25, 0x00, 0x00, 0x1a, + 0xd5, 0xff, 0xff, 0xeb, 0x04, 0x00, 0x50, 0xe3, 0x20, 0x00, 0x00, 0x1a, 0xb4, 0x00, 0x9f, 0xe5, + 0xbc, 0x01, 0x00, 0xeb, 0xac, 0x10, 0x9f, 0xe5, 0xac, 0x20, 0x9f, 0xe5, 0x00, 0x50, 0xa0, 0xe1, + 0x02, 0x09, 0x80, 0xe2, 0x4e, 0x03, 0x00, 0xeb, 0x00, 0x40, 0x50, 0xe2, 0x19, 0x00, 0x00, 0x1a, + 0xc9, 0xff, 0xff, 0xeb, 0x04, 0x00, 0x50, 0xe3, 0x16, 0x00, 0x00, 0x0a, 0x01, 0x00, 0xa0, 0xe3, + 0x80, 0x10, 0x9f, 0xe5, 0x80, 0x20, 0x9f, 0xe5, 0xd0, 0x01, 0x00, 0xeb, 0x02, 0x09, 0xa0, 0xe3, + 0x70, 0x10, 0x9f, 0xe5, 0x23, 0x03, 0x00, 0xeb, 0x00, 0x00, 0x50, 0xe3, 0x6c, 0x00, 0x9f, 0x05, + 0x0d, 0x00, 0x00, 0x0a, 0x04, 0x00, 0xa0, 0xe1, 0x16, 0x03, 0x00, 0xeb, 0x54, 0x00, 0x9f, 0xe5, + 0xa4, 0x01, 0x00, 0xeb, 0x25, 0x26, 0xa0, 0xe1, 0x02, 0x19, 0x80, 0xe2, 0x21, 0x16, 0xa0, 0xe1, + 0x04, 0x00, 0xa0, 0xe1, 0x41, 0x02, 0x00, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x0b, 0x03, 0x00, 0xeb, + 0x3c, 0x00, 0x9f, 0xe5, 0x00, 0x00, 0x00, 0xea, 0x38, 0x00, 0x9f, 0xe5, 0x38, 0x20, 0x9f, 0xe5, + 0x38, 0x30, 0x9f, 0xe5, 0xb4, 0x10, 0x92, 0xe5, 0x03, 0x00, 0x51, 0xe1, 0xfc, 0xff, 0xff, 0x9a, + 0x33, 0x04, 0x00, 0xeb, 0x01, 0x26, 0xa0, 0xe3, 0xf2, 0x35, 0xa0, 0xe3, 0x00, 0x20, 0x83, 0xe5, + 0xfe, 0xff, 0xff, 0xea, 0xa8, 0x16, 0x00, 0x22, 0x00, 0x00, 0x02, 0x22, 0x00, 0x08, 0x02, 0x22, + 0x54, 0x16, 0x00, 0x22, 0xb0, 0x16, 0x00, 0x22, 0x60, 0x16, 0x00, 0x22, 0x00, 0x00, 0x70, 0x3c, + 0x7f, 0x84, 0x1e, 0x00, 0x10, 0x40, 0x2d, 0xe9, 0x00, 0x30, 0xa0, 0xe3, 0x07, 0x00, 0x00, 0xea, + 0x03, 0x40, 0xd0, 0xe7, 0x03, 0xc0, 0xd1, 0xe7, 0x01, 0x20, 0x42, 0xe2, 0x0c, 0x00, 0x54, 0xe1, + 0x01, 0x30, 0x83, 0xe2, 0x01, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x6c, 0xe0, 0x10, 0x80, 0xbd, 0xe8, + 0x00, 0x00, 0x52, 0xe3, 0xf5, 0xff, 0xff, 0x1a, 0x02, 0x00, 0xa0, 0xe1, 0x10, 0x80, 0xbd, 0xe8, + 0x1f, 0x30, 0x00, 0xe2, 0x01, 0x20, 0xa0, 0xe3, 0xc0, 0x02, 0xa0, 0xe1, 0x00, 0x00, 0x51, 0xe3, + 0x12, 0x33, 0xa0, 0xe1, 0x02, 0x20, 0x00, 0xe0, 0x08, 0x00, 0x00, 0x0a, 0x3c, 0x10, 0x9f, 0xe5, + 0x3c, 0x00, 0x9f, 0xe5, 0x00, 0x00, 0x52, 0xe3, 0x00, 0x20, 0xa0, 0x11, 0x01, 0x20, 0xa0, 0x01, + 0x00, 0x10, 0x92, 0xe5, 0x03, 0x30, 0xc1, 0xe1, 0x00, 0x30, 0x82, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, + 0x18, 0x10, 0x9f, 0xe5, 0x18, 0x00, 0x9f, 0xe5, 0x00, 0x00, 0x52, 0xe3, 0x01, 0x00, 0xa0, 0x01, + 0x00, 0x20, 0x90, 0xe5, 0x03, 0x30, 0x82, 0xe1, 0x00, 0x30, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, + 0x48, 0x00, 0x50, 0x3c, 0x4c, 0x00, 0x50, 0x3c, 0x70, 0x40, 0x2d, 0xe9, 0x10, 0x50, 0x9d, 0xe5, + 0x01, 0x30, 0x43, 0xe2, 0x01, 0x50, 0x45, 0xe2, 0x03, 0x60, 0x02, 0xe2, 0x0f, 0x30, 0x03, 0xe2, + 0x05, 0x52, 0xa0, 0xe1, 0x03, 0xc0, 0xc0, 0xe3, 0xff, 0x50, 0x05, 0xe2, 0x06, 0x36, 0x83, 0xe1, + 0x00, 0x40, 0x9c, 0xe5, 0x05, 0x30, 0x83, 0xe1, 0x30, 0x50, 0x9f, 0xe5, 0x02, 0x20, 0x00, 0xe2, + 0x82, 0x21, 0xa0, 0xe1, 0x00, 0x00, 0x51, 0xe3, 0x02, 0x19, 0xa0, 0x03, 0x00, 0x10, 0xa0, 0x13, + 0x35, 0x42, 0x04, 0xe0, 0x01, 0x30, 0x83, 0xe1, 0x13, 0x22, 0x84, 0xe1, 0x00, 0x20, 0x8c, 0xe5, + 0xb0, 0x20, 0xd0, 0xe1, 0x03, 0x00, 0x52, 0xe1, 0xfc, 0xff, 0xff, 0x1a, 0x70, 0x80, 0xbd, 0xe8, + 0x00, 0x00, 0xff, 0xff, 0x5c, 0xc0, 0x9f, 0xe5, 0x13, 0x40, 0x2d, 0xe9, 0x44, 0xe0, 0x9c, 0xe5, + 0x01, 0x40, 0xa0, 0xe3, 0x01, 0xec, 0xce, 0xe3, 0x00, 0x20, 0xa0, 0xe3, 0x04, 0x30, 0xa0, 0xe1, + 0x44, 0xe0, 0x8c, 0xe5, 0x40, 0x00, 0x9f, 0xe5, 0x04, 0x10, 0xa0, 0xe1, 0x00, 0x40, 0x8d, 0xe5, + 0xd8, 0xff, 0xff, 0xeb, 0x04, 0x10, 0xa0, 0xe1, 0x25, 0x00, 0xa0, 0xe3, 0xbb, 0xff, 0xff, 0xeb, + 0x28, 0x30, 0x9f, 0xe5, 0x11, 0x2d, 0xa0, 0xe3, 0xa0, 0x20, 0x83, 0xe5, 0x0b, 0x20, 0xa0, 0xe3, + 0xb0, 0x20, 0x83, 0xe5, 0x00, 0x20, 0xe0, 0xe3, 0xa8, 0x20, 0x83, 0xe5, 0x04, 0x20, 0x82, 0xe2, + 0xa4, 0x20, 0x83, 0xe5, 0x1c, 0x80, 0xbd, 0xe8, 0x00, 0x00, 0x50, 0x3c, 0x12, 0x00, 0x50, 0x3c, + 0x00, 0x00, 0x70, 0x3c, 0x04, 0x30, 0x9f, 0xe5, 0x00, 0x11, 0x83, 0xe7, 0x1e, 0xff, 0x2f, 0xe1, + 0xc0, 0x16, 0x00, 0x22, 0x80, 0x20, 0x9f, 0xe5, 0x00, 0x00, 0x51, 0xe3, 0x7c, 0x30, 0x9f, 0xe5, + 0x02, 0x30, 0xa0, 0x11, 0x01, 0x00, 0x50, 0xe3, 0x0a, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x50, 0xe3, + 0x0f, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x50, 0xe3, 0x1e, 0xff, 0x2f, 0x11, 0x60, 0x10, 0x9f, 0xe5, + 0x00, 0x20, 0x91, 0xe5, 0x22, 0x28, 0xa0, 0xe1, 0x02, 0x28, 0xa0, 0xe1, 0x02, 0x30, 0x83, 0xe1, + 0x00, 0x30, 0x81, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x44, 0x10, 0x9f, 0xe5, 0xc0, 0x20, 0x91, 0xe5, + 0x02, 0x28, 0xa0, 0xe1, 0x22, 0x28, 0xa0, 0xe1, 0x03, 0x38, 0x82, 0xe1, 0xc0, 0x30, 0x81, 0xe5, + 0x1e, 0xff, 0x2f, 0xe1, 0x28, 0x00, 0x9f, 0xe5, 0xc0, 0x21, 0x90, 0xe5, 0xff, 0x24, 0xc2, 0xe3, + 0x03, 0x2c, 0x82, 0xe1, 0xc0, 0x21, 0x80, 0xe5, 0xe0, 0x21, 0x90, 0xe5, 0xff, 0x20, 0xc2, 0xe3, + 0x23, 0x34, 0x82, 0xe1, 0xe0, 0x31, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x22, 0x22, 0x00, 0x00, + 0xef, 0xee, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3c, 0x01, 0x00, 0x50, 0xe3, 0x01, 0x10, 0x21, 0xe2, + 0x06, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x50, 0xe3, 0x06, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x50, 0xe3, + 0x24, 0x30, 0x9f, 0x05, 0x0e, 0x10, 0x81, 0x03, 0x00, 0x12, 0x83, 0x05, 0x1e, 0xff, 0x2f, 0xe1, + 0x18, 0x30, 0x9f, 0xe5, 0x00, 0x00, 0x00, 0xea, 0x14, 0x30, 0x9f, 0xe5, 0x08, 0x20, 0x9f, 0xe5, + 0x03, 0x30, 0x81, 0xe1, 0x00, 0x32, 0x82, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0xf0, 0x3c, + 0x0e, 0x04, 0x06, 0x00, 0x0e, 0x06, 0x0e, 0x00, 0x02, 0x00, 0x50, 0xe3, 0x10, 0x40, 0x2d, 0xe9, + 0xbc, 0x30, 0x9f, 0x05, 0x03, 0x00, 0x00, 0x0a, 0xb8, 0x20, 0x9f, 0xe5, 0x01, 0x00, 0x50, 0xe3, + 0xb4, 0x30, 0x9f, 0xe5, 0x02, 0x30, 0xa0, 0x01, 0xb0, 0x40, 0x9f, 0xe5, 0xb0, 0xc0, 0x9f, 0xe5, + 0x01, 0x20, 0xa0, 0xe3, 0x00, 0x20, 0x83, 0xe5, 0x02, 0x00, 0x50, 0xe3, 0xa4, 0x30, 0x9f, 0x05, + 0x02, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe3, 0x04, 0x30, 0xa0, 0x01, 0x0c, 0x30, 0xa0, 0x11, + 0x00, 0x30, 0x93, 0xe5, 0x1f, 0x3e, 0x03, 0xe2, 0x01, 0x0c, 0x53, 0xe3, 0xf5, 0xff, 0xff, 0x0a, + 0x02, 0x00, 0x50, 0xe3, 0x80, 0x30, 0x9f, 0x05, 0x03, 0x00, 0x00, 0x0a, 0x7c, 0x20, 0x9f, 0xe5, + 0x01, 0x00, 0x50, 0xe3, 0x78, 0x30, 0x9f, 0xe5, 0x02, 0x30, 0xa0, 0x01, 0x5c, 0xc0, 0x9f, 0xe5, + 0x5c, 0x20, 0x9f, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x02, 0x00, 0x50, 0xe3, 0x54, 0x30, 0x9f, 0x05, + 0x02, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe3, 0x0c, 0x30, 0xa0, 0x01, 0x02, 0x30, 0xa0, 0x11, + 0x00, 0x30, 0x93, 0xe5, 0x3e, 0x0c, 0x13, 0xe3, 0xf6, 0xff, 0xff, 0x0a, 0x02, 0x00, 0x50, 0xe3, + 0x40, 0x00, 0x9f, 0x05, 0x04, 0x00, 0x00, 0x0a, 0x3c, 0x30, 0x9f, 0xe5, 0x3c, 0x20, 0x9f, 0xe5, + 0x01, 0x00, 0x50, 0xe3, 0x02, 0x00, 0xa0, 0x01, 0x03, 0x00, 0xa0, 0x11, 0x00, 0x00, 0x90, 0xe5, + 0x10, 0x80, 0xbd, 0xe8, 0x34, 0x00, 0x20, 0x3d, 0x34, 0x00, 0xe0, 0x3c, 0x34, 0x00, 0x30, 0x3c, + 0x08, 0x00, 0xe0, 0x3c, 0x08, 0x00, 0x30, 0x3c, 0x08, 0x00, 0x20, 0x3d, 0x10, 0x00, 0x20, 0x3d, + 0x10, 0x00, 0xe0, 0x3c, 0x10, 0x00, 0x30, 0x3c, 0x20, 0x00, 0x20, 0x3d, 0x20, 0x00, 0x30, 0x3c, + 0x20, 0x00, 0xe0, 0x3c, 0x02, 0x00, 0x50, 0xe3, 0xf0, 0x40, 0x2d, 0xe9, 0xd8, 0x30, 0x9f, 0x05, + 0x03, 0x00, 0x00, 0x0a, 0xd4, 0xc0, 0x9f, 0xe5, 0x01, 0x00, 0x50, 0xe3, 0xd0, 0x30, 0x9f, 0xe5, + 0x0c, 0x30, 0xa0, 0x01, 0x02, 0x00, 0x50, 0xe3, 0x00, 0x10, 0x83, 0xe5, 0xc4, 0x30, 0x9f, 0x05, + 0x03, 0x00, 0x00, 0x0a, 0xc0, 0xc0, 0x9f, 0xe5, 0x01, 0x00, 0x50, 0xe3, 0xbc, 0x30, 0x9f, 0xe5, + 0x0c, 0x30, 0xa0, 0x01, 0x00, 0x40, 0x93, 0xe5, 0x00, 0xc0, 0xa0, 0xe3, 0x01, 0x40, 0x84, 0xe3, + 0x00, 0x40, 0x83, 0xe5, 0xa8, 0x70, 0x9f, 0xe5, 0xa8, 0x60, 0x9f, 0xe5, 0xa8, 0x50, 0x9f, 0xe5, + 0xa8, 0x40, 0x9f, 0xe5, 0x12, 0x00, 0x00, 0xea, 0x02, 0x00, 0x50, 0xe3, 0xa0, 0x30, 0x9f, 0x05, + 0x02, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe3, 0x07, 0x30, 0xa0, 0x01, 0x06, 0x30, 0xa0, 0x11, + 0x00, 0x30, 0x93, 0xe5, 0x3e, 0x0c, 0x13, 0xe3, 0xf6, 0xff, 0xff, 0x0a, 0x02, 0x00, 0x50, 0xe3, + 0x80, 0x30, 0x9f, 0x05, 0x02, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe3, 0x05, 0x30, 0xa0, 0x01, + 0x04, 0x30, 0xa0, 0x11, 0x00, 0x30, 0x93, 0xe5, 0x01, 0x10, 0x41, 0xe2, 0x0c, 0x30, 0xc2, 0xe7, + 0x01, 0xc0, 0x8c, 0xe2, 0x00, 0x00, 0x51, 0xe3, 0xea, 0xff, 0xff, 0x1a, 0x02, 0x00, 0x50, 0xe3, + 0x30, 0x00, 0x9f, 0x05, 0x04, 0x00, 0x00, 0x0a, 0x2c, 0x30, 0x9f, 0xe5, 0x2c, 0x20, 0x9f, 0xe5, + 0x01, 0x00, 0x50, 0xe3, 0x02, 0x00, 0xa0, 0x11, 0x03, 0x00, 0xa0, 0x01, 0x00, 0x30, 0x90, 0xe5, + 0x01, 0x30, 0xc3, 0xe3, 0x00, 0x30, 0x80, 0xe5, 0xf0, 0x80, 0xbd, 0xe8, 0x34, 0x00, 0x20, 0x3d, + 0x34, 0x00, 0xe0, 0x3c, 0x34, 0x00, 0x30, 0x3c, 0x04, 0x00, 0x20, 0x3d, 0x04, 0x00, 0xe0, 0x3c, + 0x04, 0x00, 0x30, 0x3c, 0x08, 0x00, 0xe0, 0x3c, 0x08, 0x00, 0x30, 0x3c, 0x20, 0x00, 0xe0, 0x3c, + 0x20, 0x00, 0x30, 0x3c, 0x08, 0x00, 0x20, 0x3d, 0x20, 0x00, 0x20, 0x3d, 0x02, 0x00, 0x50, 0xe3, + 0x2e, 0x00, 0x80, 0x02, 0x02, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe3, 0x2b, 0x00, 0xa0, 0x03, + 0x22, 0x00, 0xa0, 0x13, 0x00, 0x10, 0xa0, 0xe3, 0xe4, 0xfe, 0xff, 0xea, 0x02, 0x00, 0x50, 0xe3, + 0x10, 0x40, 0x2d, 0xe9, 0x00, 0x40, 0xa0, 0xe1, 0x30, 0x00, 0xa0, 0x03, 0x02, 0x00, 0x00, 0x0a, + 0x01, 0x00, 0x54, 0xe3, 0x2b, 0x00, 0xa0, 0x03, 0x22, 0x00, 0xa0, 0x13, 0x01, 0x10, 0xa0, 0xe3, + 0xda, 0xfe, 0xff, 0xeb, 0x02, 0x00, 0x54, 0xe3, 0x04, 0x31, 0x9f, 0x05, 0x03, 0x00, 0x00, 0x0a, + 0x00, 0x21, 0x9f, 0xe5, 0x01, 0x00, 0x54, 0xe3, 0xfc, 0x30, 0x9f, 0xe5, 0x02, 0x30, 0xa0, 0x01, + 0x02, 0x00, 0x54, 0xe3, 0x0f, 0x20, 0xa0, 0xe3, 0x00, 0x20, 0x83, 0xe5, 0xec, 0x30, 0x9f, 0x05, + 0x03, 0x00, 0x00, 0x0a, 0xe8, 0x20, 0x9f, 0xe5, 0x01, 0x00, 0x54, 0xe3, 0xe4, 0x30, 0x9f, 0xe5, + 0x02, 0x30, 0xa0, 0x01, 0x00, 0x20, 0x93, 0xe5, 0x02, 0x00, 0x54, 0xe3, 0x0c, 0x20, 0x82, 0xe3, + 0x00, 0x20, 0x83, 0xe5, 0xd0, 0x30, 0x9f, 0x05, 0x03, 0x00, 0x00, 0x0a, 0xcc, 0x20, 0x9f, 0xe5, + 0x01, 0x00, 0x54, 0xe3, 0xc8, 0x30, 0x9f, 0xe5, 0x02, 0x30, 0xa0, 0x01, 0xc4, 0x20, 0x9f, 0xe5, + 0x02, 0x00, 0x54, 0xe3, 0x04, 0x21, 0x92, 0xe7, 0x00, 0x20, 0x83, 0xe5, 0xb8, 0x30, 0x9f, 0x05, + 0x03, 0x00, 0x00, 0x0a, 0xb4, 0x20, 0x9f, 0xe5, 0x01, 0x00, 0x54, 0xe3, 0xb0, 0x30, 0x9f, 0xe5, + 0x02, 0x30, 0xa0, 0x01, 0x02, 0x00, 0x54, 0xe3, 0x06, 0x20, 0xa0, 0xe3, 0x00, 0x20, 0x83, 0xe5, + 0xa0, 0x30, 0x9f, 0x05, 0x03, 0x00, 0x00, 0x0a, 0x9c, 0x20, 0x9f, 0xe5, 0x01, 0x00, 0x54, 0xe3, + 0x98, 0x30, 0x9f, 0xe5, 0x02, 0x30, 0xa0, 0x01, 0x94, 0x20, 0x9f, 0xe5, 0x02, 0x00, 0x54, 0xe3, + 0x00, 0x20, 0x83, 0xe5, 0x54, 0x30, 0x9f, 0x05, 0x03, 0x00, 0x00, 0x0a, 0x50, 0x20, 0x9f, 0xe5, + 0x01, 0x00, 0x54, 0xe3, 0x4c, 0x30, 0x9f, 0xe5, 0x02, 0x30, 0xa0, 0x01, 0x00, 0x20, 0x93, 0xe5, + 0x02, 0x00, 0x54, 0xe3, 0x0c, 0x20, 0x82, 0xe3, 0x00, 0x20, 0x83, 0xe5, 0x2c, 0x40, 0x9f, 0x05, + 0x04, 0x00, 0x00, 0x0a, 0x2c, 0x30, 0x9f, 0xe5, 0x24, 0x20, 0x9f, 0xe5, 0x01, 0x00, 0x54, 0xe3, + 0x02, 0x40, 0xa0, 0x01, 0x03, 0x40, 0xa0, 0x11, 0x01, 0x30, 0xa0, 0xe3, 0x00, 0x30, 0x84, 0xe5, + 0x10, 0x80, 0xbd, 0xe8, 0x08, 0x00, 0x20, 0x3d, 0x08, 0x00, 0xe0, 0x3c, 0x08, 0x00, 0x30, 0x3c, + 0x00, 0x00, 0x20, 0x3d, 0x00, 0x00, 0xe0, 0x3c, 0x00, 0x00, 0x30, 0x3c, 0x30, 0x00, 0x20, 0x3d, + 0x30, 0x00, 0xe0, 0x3c, 0x30, 0x00, 0x30, 0x3c, 0xc0, 0x16, 0x00, 0x22, 0x0c, 0x00, 0x20, 0x3d, + 0x0c, 0x00, 0xe0, 0x3c, 0x0c, 0x00, 0x30, 0x3c, 0x04, 0x00, 0x20, 0x3d, 0x04, 0x00, 0xe0, 0x3c, + 0x04, 0x00, 0x30, 0x3c, 0x18, 0x06, 0x01, 0x00, 0x0c, 0x30, 0x80, 0xe2, 0x02, 0xc0, 0xd3, 0xe5, + 0x01, 0x10, 0xd3, 0xe5, 0x0c, 0x20, 0xd0, 0xe5, 0x03, 0x30, 0xd3, 0xe5, 0x0c, 0x08, 0xa0, 0xe1, + 0x01, 0x04, 0x80, 0xe1, 0x02, 0x00, 0x80, 0xe1, 0x03, 0x0c, 0x80, 0xe1, 0x5f, 0x0d, 0x80, 0xe2, + 0x3f, 0x00, 0x80, 0xe2, 0xff, 0x0e, 0xc0, 0xe3, 0x0f, 0x00, 0xc0, 0xe3, 0x1e, 0xff, 0x2f, 0xe1, + 0x70, 0x40, 0x2d, 0xe9, 0x18, 0xd0, 0x4d, 0xe2, 0x04, 0x40, 0x8d, 0xe2, 0x03, 0x50, 0xa0, 0xe1, + 0x00, 0x60, 0xa0, 0xe1, 0x01, 0x00, 0xa0, 0xe1, 0x02, 0x10, 0xa0, 0xe1, 0x04, 0x20, 0xa0, 0xe1, + 0xe1, 0x01, 0x00, 0xeb, 0x04, 0x10, 0xa0, 0xe1, 0x05, 0x00, 0xa0, 0xe1, 0x10, 0x20, 0xa0, 0xe3, + 0xae, 0x02, 0x00, 0xeb, 0x06, 0x10, 0xa0, 0xe1, 0x05, 0x20, 0xa0, 0xe1, 0x01, 0x00, 0xa0, 0xe3, + 0x10, 0x30, 0xa0, 0xe3, 0x51, 0x02, 0x00, 0xeb, 0x18, 0xd0, 0x8d, 0xe2, 0x70, 0x80, 0xbd, 0xe8, + 0x01, 0x00, 0x50, 0xe3, 0xf0, 0x47, 0x2d, 0xe9, 0x0c, 0x50, 0xd1, 0xe5, 0x0c, 0x30, 0x81, 0xe2, + 0x00, 0x40, 0xa0, 0xe1, 0x01, 0x00, 0xa0, 0x03, 0x02, 0x00, 0xa0, 0x13, 0x03, 0x80, 0xd3, 0xe5, + 0x02, 0x70, 0xd3, 0xe5, 0x01, 0x60, 0xd3, 0xe5, 0x02, 0xa0, 0xa0, 0xe1, 0x07, 0x00, 0xc1, 0xe5, + 0x40, 0x30, 0x81, 0xe2, 0x02, 0x00, 0xa0, 0xe3, 0x40, 0x20, 0xa0, 0xe3, 0xdb, 0xff, 0xff, 0xeb, + 0x07, 0x78, 0xa0, 0xe1, 0x06, 0x64, 0x87, 0xe1, 0x05, 0x50, 0x86, 0xe1, 0x08, 0x3c, 0x85, 0xe1, + 0x04, 0x00, 0xa0, 0xe1, 0x0a, 0x20, 0xa0, 0xe1, 0x02, 0x10, 0xa0, 0xe3, 0xf0, 0x47, 0xbd, 0xe8, + 0x36, 0x02, 0x00, 0xea, 0x10, 0x40, 0x2d, 0xe9, 0x00, 0x40, 0xa0, 0xe1, 0x04, 0x00, 0xa0, 0xe1, + 0x01, 0x10, 0xa0, 0xe3, 0xbf, 0xfe, 0xff, 0xeb, 0x05, 0x10, 0xa0, 0xe3, 0x04, 0x00, 0xa0, 0xe1, + 0xd0, 0xfe, 0xff, 0xeb, 0xff, 0x10, 0xa0, 0xe3, 0x04, 0x00, 0xa0, 0xe1, 0xcd, 0xfe, 0xff, 0xeb, + 0x00, 0x10, 0xa0, 0xe3, 0x01, 0x30, 0x10, 0xe2, 0x04, 0x00, 0xa0, 0xe1, 0x01, 0x00, 0x00, 0x0a, + 0xb4, 0xfe, 0xff, 0xeb, 0xf0, 0xff, 0xff, 0xea, 0x04, 0x00, 0xa0, 0xe1, 0x03, 0x10, 0xa0, 0xe1, + 0x10, 0x40, 0xbd, 0xe8, 0xaf, 0xfe, 0xff, 0xea, 0x70, 0x40, 0x2d, 0xe9, 0x00, 0x50, 0x51, 0xe2, + 0x00, 0x40, 0xa0, 0xe1, 0x07, 0x00, 0x00, 0x1a, 0x01, 0x10, 0x81, 0xe2, 0xa9, 0xfe, 0xff, 0xeb, + 0x04, 0x10, 0xa0, 0xe3, 0x04, 0x00, 0xa0, 0xe1, 0xba, 0xfe, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, + 0x05, 0x10, 0xa0, 0xe1, 0xa3, 0xfe, 0xff, 0xeb, 0x01, 0x10, 0xa0, 0xe3, 0x04, 0x00, 0xa0, 0xe1, + 0xa0, 0xfe, 0xff, 0xeb, 0x50, 0x10, 0xa0, 0xe3, 0x04, 0x00, 0xa0, 0xe1, 0xb1, 0xfe, 0xff, 0xeb, + 0x04, 0x00, 0xa0, 0xe1, 0x00, 0x10, 0xa0, 0xe3, 0x9a, 0xfe, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, + 0x01, 0x10, 0xa0, 0xe3, 0x97, 0xfe, 0xff, 0xeb, 0x01, 0x10, 0xa0, 0xe3, 0x04, 0x00, 0xa0, 0xe1, + 0xa8, 0xfe, 0xff, 0xeb, 0x00, 0x00, 0x55, 0xe3, 0x1c, 0x10, 0xa0, 0x03, 0x00, 0x10, 0xa0, 0x13, + 0x04, 0x00, 0xa0, 0xe1, 0xa3, 0xfe, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x00, 0x10, 0xa0, 0xe3, + 0x8c, 0xfe, 0xff, 0xeb, 0x00, 0x00, 0x55, 0xe3, 0x70, 0x80, 0xbd, 0x08, 0x04, 0x00, 0xa0, 0xe1, + 0x01, 0x10, 0xa0, 0xe3, 0x87, 0xfe, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x06, 0x10, 0xa0, 0xe3, + 0x98, 0xfe, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x00, 0x10, 0xa0, 0xe3, 0x70, 0x40, 0xbd, 0xe8, + 0x80, 0xfe, 0xff, 0xea, 0x70, 0x40, 0x2d, 0xe9, 0x00, 0x40, 0xa0, 0xe1, 0x01, 0x50, 0xa0, 0xe1, + 0x1d, 0xff, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0xb5, 0xff, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, + 0x01, 0x10, 0xa0, 0xe3, 0xc7, 0xff, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x01, 0x10, 0xa0, 0xe3, + 0x74, 0xfe, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x20, 0x10, 0xa0, 0xe3, 0x85, 0xfe, 0xff, 0xeb, + 0x25, 0x18, 0xa0, 0xe1, 0xff, 0x10, 0x01, 0xe2, 0x04, 0x00, 0xa0, 0xe1, 0x81, 0xfe, 0xff, 0xeb, + 0x25, 0x14, 0xa0, 0xe1, 0xff, 0x10, 0x01, 0xe2, 0x04, 0x00, 0xa0, 0xe1, 0x7d, 0xfe, 0xff, 0xeb, + 0xff, 0x10, 0x05, 0xe2, 0x04, 0x00, 0xa0, 0xe1, 0x7a, 0xfe, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, + 0x00, 0x10, 0xa0, 0xe3, 0x63, 0xfe, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x00, 0x10, 0xa0, 0xe3, + 0xb0, 0xff, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x70, 0x40, 0xbd, 0xe8, 0xf6, 0xfe, 0xff, 0xea, + 0x70, 0x40, 0x2d, 0xe9, 0x00, 0x50, 0xa0, 0xe1, 0x01, 0x46, 0xa0, 0xe1, 0x02, 0x60, 0xa0, 0xe1, + 0x00, 0x00, 0x00, 0xea, 0xd6, 0xff, 0xff, 0xeb, 0x00, 0x00, 0x56, 0xe3, 0x04, 0x10, 0xa0, 0xe1, + 0x05, 0x00, 0xa0, 0xe1, 0x01, 0x4a, 0x84, 0xe2, 0x01, 0x60, 0x46, 0xe2, 0xf8, 0xff, 0xff, 0x1a, + 0x70, 0x80, 0xbd, 0xe8, 0xf0, 0x45, 0x2d, 0xe9, 0x00, 0x40, 0xa0, 0xe1, 0x24, 0xd0, 0x4d, 0xe2, + 0x02, 0x50, 0xa0, 0xe1, 0x03, 0x70, 0xa0, 0xe1, 0x01, 0x60, 0xa0, 0xe1, 0xea, 0xfe, 0xff, 0xeb, + 0x04, 0x00, 0xa0, 0xe1, 0x82, 0xff, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x01, 0x10, 0xa0, 0xe3, + 0x44, 0xfe, 0xff, 0xeb, 0x03, 0x10, 0xa0, 0xe3, 0x04, 0x00, 0xa0, 0xe1, 0x55, 0xfe, 0xff, 0xeb, + 0x26, 0x18, 0xa0, 0xe1, 0xff, 0x10, 0x01, 0xe2, 0x04, 0x00, 0xa0, 0xe1, 0x51, 0xfe, 0xff, 0xeb, + 0x26, 0x14, 0xa0, 0xe1, 0xff, 0x10, 0x01, 0xe2, 0x04, 0x00, 0xa0, 0xe1, 0x4d, 0xfe, 0xff, 0xeb, + 0xff, 0x10, 0x06, 0xe2, 0x04, 0x00, 0xa0, 0xe1, 0x4a, 0xfe, 0xff, 0xeb, 0x00, 0x60, 0xa0, 0xe3, + 0x0d, 0x80, 0xa0, 0xe1, 0x15, 0x00, 0x00, 0xea, 0x20, 0x00, 0x57, 0xe3, 0x07, 0xa0, 0xa0, 0xb1, + 0x20, 0xa0, 0xa0, 0xa3, 0x04, 0x00, 0xa0, 0xe1, 0x0a, 0x10, 0xa0, 0xe1, 0x0d, 0x20, 0xa0, 0xe1, + 0x7f, 0xfe, 0xff, 0xeb, 0x05, 0x00, 0xa0, 0xe1, 0x0d, 0x10, 0xa0, 0xe1, 0x0a, 0x20, 0xa0, 0xe1, + 0x9f, 0xfd, 0xff, 0xeb, 0x00, 0x30, 0xa0, 0xe3, 0x00, 0x00, 0x50, 0xe3, 0x01, 0x60, 0x86, 0x13, + 0x03, 0x20, 0xd8, 0xe7, 0x02, 0x30, 0x83, 0xe2, 0xff, 0x00, 0x52, 0xe3, 0x02, 0x60, 0x86, 0x13, + 0x0a, 0x00, 0x53, 0xe1, 0xf9, 0xff, 0xff, 0xba, 0x20, 0x50, 0x85, 0xe2, 0x20, 0x70, 0x47, 0xe2, + 0x00, 0x00, 0x57, 0xe3, 0xe7, 0xff, 0xff, 0xca, 0x00, 0x10, 0xa0, 0xe3, 0x04, 0x00, 0xa0, 0xe1, + 0x18, 0xfe, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0xaf, 0xfe, 0xff, 0xeb, 0x06, 0x00, 0xa0, 0xe1, + 0x24, 0xd0, 0x8d, 0xe2, 0xf0, 0x85, 0xbd, 0xe8, 0xf0, 0x4f, 0x2d, 0xe9, 0x00, 0x40, 0xa0, 0xe1, + 0x14, 0xd0, 0x4d, 0xe2, 0x01, 0x50, 0xa0, 0xe1, 0x02, 0x70, 0xa0, 0xe1, 0x03, 0x80, 0xa0, 0xe1, + 0x53, 0x00, 0x00, 0xea, 0x05, 0x6a, 0xa0, 0xe1, 0x26, 0x6a, 0xa0, 0xe1, 0x01, 0x6a, 0x66, 0xe2, + 0x08, 0x00, 0x56, 0xe1, 0x08, 0x60, 0xa0, 0xa1, 0x04, 0x00, 0xa0, 0xe1, 0x05, 0x10, 0xa0, 0xe1, + 0x07, 0x20, 0xa0, 0xe1, 0x06, 0x30, 0xa0, 0xe1, 0xb1, 0xff, 0xff, 0xeb, 0x01, 0x00, 0x10, 0xe3, + 0x44, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x10, 0xe3, 0x03, 0x00, 0x00, 0x0a, 0xff, 0x1e, 0xc5, 0xe3, + 0x0f, 0x10, 0xc1, 0xe3, 0x04, 0x00, 0xa0, 0xe1, 0x79, 0xff, 0xff, 0xeb, 0x00, 0x30, 0xa0, 0xe3, + 0x03, 0x20, 0xd7, 0xe7, 0x07, 0x90, 0xa0, 0xe1, 0xff, 0x00, 0x52, 0xe3, 0x01, 0x30, 0x83, 0xe2, + 0x02, 0x00, 0x00, 0x1a, 0x06, 0x00, 0x53, 0xe1, 0xf8, 0xff, 0xff, 0xba, 0x35, 0x00, 0x00, 0xea, + 0x04, 0x00, 0xa0, 0xe1, 0x90, 0xfe, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x28, 0xff, 0xff, 0xeb, + 0x04, 0x00, 0xa0, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 0x3a, 0xff, 0xff, 0xeb, 0x25, 0x34, 0xa0, 0xe1, + 0xff, 0x30, 0x03, 0xe2, 0x25, 0x28, 0xa0, 0xe1, 0xff, 0x20, 0x02, 0xe2, 0x08, 0x30, 0x8d, 0xe5, + 0x06, 0xa0, 0xa0, 0xe1, 0xff, 0x30, 0x05, 0xe2, 0x01, 0xb0, 0xa0, 0xe3, 0x04, 0x20, 0x8d, 0xe5, + 0x0c, 0x30, 0x8d, 0xe5, 0x04, 0x00, 0xa0, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 0xdd, 0xfd, 0xff, 0xeb, + 0x04, 0x00, 0xa0, 0xe1, 0xad, 0x10, 0xa0, 0xe3, 0xee, 0xfd, 0xff, 0xeb, 0x00, 0x00, 0x5b, 0xe3, + 0x00, 0xb0, 0xa0, 0xe3, 0x08, 0x00, 0x00, 0x0a, 0x04, 0x10, 0x9d, 0xe5, 0x04, 0x00, 0xa0, 0xe1, + 0xe8, 0xfd, 0xff, 0xeb, 0x08, 0x10, 0x9d, 0xe5, 0x04, 0x00, 0xa0, 0xe1, 0xe5, 0xfd, 0xff, 0xeb, + 0x04, 0x00, 0xa0, 0xe1, 0x0c, 0x10, 0x9d, 0xe5, 0xe2, 0xfd, 0xff, 0xeb, 0x00, 0x10, 0xd9, 0xe5, + 0x04, 0x00, 0xa0, 0xe1, 0xdf, 0xfd, 0xff, 0xeb, 0x01, 0x10, 0xd9, 0xe5, 0x04, 0x00, 0xa0, 0xe1, + 0xdc, 0xfd, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x00, 0x10, 0xa0, 0xe3, 0xc5, 0xfd, 0xff, 0xeb, + 0x04, 0x00, 0xa0, 0xe1, 0xfe, 0xfe, 0xff, 0xeb, 0x02, 0xa0, 0x5a, 0xe2, 0x02, 0x90, 0x89, 0xe2, + 0xdf, 0xff, 0xff, 0x1a, 0x04, 0x00, 0xa0, 0xe1, 0x0a, 0x10, 0xa0, 0xe1, 0x0d, 0xff, 0xff, 0xeb, + 0x04, 0x00, 0xa0, 0xe1, 0x54, 0xfe, 0xff, 0xeb, 0x08, 0x80, 0x66, 0xe0, 0x06, 0x70, 0x87, 0xe0, + 0x06, 0x50, 0x85, 0xe0, 0x00, 0x00, 0x58, 0xe3, 0xa9, 0xff, 0xff, 0xca, 0x14, 0xd0, 0x8d, 0xe2, + 0xf0, 0x8f, 0xbd, 0xe8, 0xf0, 0x41, 0x2d, 0xe9, 0x00, 0x40, 0xa0, 0xe1, 0x03, 0x50, 0xa0, 0xe1, + 0x02, 0x70, 0xa0, 0xe1, 0x01, 0x60, 0xa0, 0xe1, 0x4f, 0xfe, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, + 0xe7, 0xfe, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 0xa9, 0xfd, 0xff, 0xeb, + 0x04, 0x00, 0xa0, 0xe1, 0x03, 0x10, 0xa0, 0xe3, 0xba, 0xfd, 0xff, 0xeb, 0x26, 0x18, 0xa0, 0xe1, + 0xff, 0x10, 0x01, 0xe2, 0x04, 0x00, 0xa0, 0xe1, 0xb6, 0xfd, 0xff, 0xeb, 0x26, 0x14, 0xa0, 0xe1, + 0xff, 0x10, 0x01, 0xe2, 0x04, 0x00, 0xa0, 0xe1, 0xb2, 0xfd, 0xff, 0xeb, 0xff, 0x10, 0x06, 0xe2, + 0x04, 0x00, 0xa0, 0xe1, 0xaf, 0xfd, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x07, 0x10, 0xa0, 0xe1, + 0x05, 0x20, 0xa0, 0xe1, 0xea, 0xfd, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x00, 0x10, 0xa0, 0xe3, + 0x94, 0xfd, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0xf0, 0x41, 0xbd, 0xe8, 0x2a, 0xfe, 0xff, 0xea, + 0x00, 0x10, 0xa0, 0xe3, 0x6a, 0xfd, 0xff, 0xea, 0x10, 0x40, 0x2d, 0xe9, 0x01, 0x10, 0xa0, 0xe3, + 0x00, 0x40, 0xa0, 0xe1, 0x66, 0xfd, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, 0x00, 0x10, 0xa0, 0xe3, + 0x10, 0x40, 0xbd, 0xe8, 0x87, 0xfd, 0xff, 0xea, 0x0c, 0x30, 0x81, 0xe2, 0x70, 0x40, 0x2d, 0xe9, + 0x02, 0x50, 0xd3, 0xe5, 0x01, 0x40, 0xa0, 0xe1, 0x01, 0x10, 0xd3, 0xe5, 0x0c, 0x20, 0xd4, 0xe5, + 0x03, 0x30, 0xd3, 0xe5, 0x05, 0x58, 0xa0, 0xe1, 0x01, 0x54, 0x85, 0xe1, 0x02, 0x50, 0x85, 0xe1, + 0x03, 0x5c, 0x85, 0xe1, 0x00, 0x60, 0xa0, 0xe1, 0x02, 0x5b, 0x85, 0xe2, 0x00, 0x00, 0xa0, 0xe3, + 0xe8, 0xff, 0xff, 0xeb, 0x06, 0x10, 0xa0, 0xe1, 0x04, 0x20, 0xa0, 0xe1, 0x05, 0x30, 0xa0, 0xe1, + 0x00, 0x00, 0xa0, 0xe3, 0x5f, 0xff, 0xff, 0xeb, 0x04, 0x20, 0xa0, 0xe1, 0x06, 0x10, 0xa0, 0xe1, + 0x05, 0x30, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe3, 0x1d, 0xff, 0xff, 0xeb, 0x00, 0x40, 0xa0, 0xe1, + 0x00, 0x00, 0xa0, 0xe3, 0xd9, 0xff, 0xff, 0xeb, 0x01, 0x00, 0x24, 0xe2, 0x01, 0x00, 0x00, 0xe2, + 0x70, 0x80, 0xbd, 0xe8, 0xf0, 0x45, 0x2d, 0xe9, 0x01, 0x40, 0xa0, 0xe1, 0x14, 0xd0, 0x4d, 0xe2, + 0x00, 0x80, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe3, 0x02, 0x60, 0xa0, 0xe1, 0xd1, 0xff, 0xff, 0xeb, + 0x08, 0x10, 0xa0, 0xe1, 0x02, 0x2b, 0xa0, 0xe3, 0x04, 0x30, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe3, + 0xa7, 0xff, 0xff, 0xeb, 0x00, 0x00, 0xa0, 0xe3, 0xc8, 0xff, 0xff, 0xeb, 0x04, 0x00, 0xa0, 0xe1, + 0x40, 0x11, 0x9f, 0xe5, 0x04, 0x20, 0xa0, 0xe3, 0xcd, 0xfc, 0xff, 0xeb, 0x00, 0x00, 0x50, 0xe3, + 0x00, 0x00, 0xe0, 0x13, 0x49, 0x00, 0x00, 0x1a, 0x04, 0x10, 0xa0, 0xe1, 0x40, 0x20, 0xa0, 0xe3, + 0x0d, 0x30, 0xa0, 0xe1, 0x02, 0x00, 0xa0, 0xe3, 0x5c, 0xfe, 0xff, 0xeb, 0x0d, 0x00, 0xa0, 0xe1, + 0x40, 0x10, 0x84, 0xe2, 0x10, 0x20, 0xa0, 0xe3, 0xc1, 0xfc, 0xff, 0xeb, 0x0d, 0x50, 0xa0, 0xe1, + 0x00, 0x70, 0x50, 0xe2, 0x01, 0x00, 0xe0, 0x13, 0x3c, 0x00, 0x00, 0x1a, 0x0c, 0x30, 0x84, 0xe2, + 0x02, 0x50, 0xd3, 0xe5, 0x01, 0x10, 0xd3, 0xe5, 0x0c, 0x20, 0xd4, 0xe5, 0x05, 0x58, 0xa0, 0xe1, + 0x03, 0x30, 0xd3, 0xe5, 0x01, 0x54, 0x85, 0xe1, 0x02, 0x50, 0x85, 0xe1, 0x03, 0x5c, 0x85, 0xe1, + 0x7e, 0x0b, 0x55, 0xe3, 0x2e, 0x00, 0x00, 0x8a, 0x08, 0x30, 0x84, 0xe2, 0x02, 0xc0, 0xd3, 0xe5, + 0x01, 0xa0, 0xd3, 0xe5, 0x08, 0x10, 0xd4, 0xe5, 0x03, 0x20, 0xd3, 0xe5, 0x0c, 0xc8, 0xa0, 0xe1, + 0x0a, 0x34, 0x8c, 0xe1, 0x01, 0x30, 0x83, 0xe1, 0x02, 0x3c, 0x83, 0xe1, 0x05, 0x00, 0x53, 0xe1, + 0x23, 0x00, 0x00, 0x8a, 0x07, 0x30, 0xd4, 0xe5, 0x01, 0x30, 0x43, 0xe2, 0x01, 0x00, 0x53, 0xe3, + 0x03, 0x00, 0xe0, 0x83, 0x21, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x56, 0xe3, 0x1e, 0x00, 0x00, 0x0a, + 0x98, 0xff, 0xff, 0xeb, 0x06, 0x30, 0xa0, 0xe1, 0x07, 0x00, 0xa0, 0xe1, 0x02, 0x1b, 0x88, 0xe2, + 0x05, 0x20, 0xa0, 0xe1, 0x6e, 0xff, 0xff, 0xeb, 0x07, 0x00, 0xa0, 0xe1, 0x8f, 0xff, 0xff, 0xeb, + 0x07, 0x30, 0xd4, 0xe5, 0x01, 0x00, 0x53, 0xe3, 0x03, 0x00, 0x00, 0x1a, 0x07, 0x00, 0xa0, 0xe1, + 0x04, 0x10, 0xa0, 0xe1, 0x06, 0x20, 0xa0, 0xe1, 0x3c, 0xfe, 0xff, 0xeb, 0x06, 0x10, 0xa0, 0xe1, + 0x05, 0x20, 0xa0, 0xe1, 0x0d, 0x30, 0xa0, 0xe1, 0x02, 0x00, 0xa0, 0xe3, 0x23, 0xfe, 0xff, 0xeb, + 0x0d, 0x00, 0xa0, 0xe1, 0x10, 0x10, 0x84, 0xe2, 0x10, 0x20, 0xa0, 0xe3, 0x88, 0xfc, 0xff, 0xeb, + 0x0d, 0x70, 0xa0, 0xe1, 0x00, 0x00, 0x50, 0xe3, 0x04, 0x00, 0xe0, 0x13, 0x02, 0x00, 0x00, 0x0a, + 0x02, 0x00, 0x00, 0xea, 0x02, 0x00, 0xe0, 0xe3, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0xa0, 0xe3, + 0x14, 0xd0, 0x8d, 0xe2, 0xf0, 0x85, 0xbd, 0xe8, 0xd1, 0x16, 0x00, 0x22, 0xf0, 0x4f, 0x2d, 0xe9, + 0x00, 0x50, 0xa0, 0xe1, 0x54, 0xd0, 0x4d, 0xe2, 0x01, 0x40, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe3, + 0x01, 0x10, 0xa0, 0xe3, 0x02, 0x60, 0xa0, 0xe1, 0x84, 0xfc, 0xff, 0xeb, 0x0e, 0x23, 0xa0, 0xe3, + 0x01, 0x10, 0xa0, 0xe3, 0x02, 0xc0, 0xa0, 0xe1, 0x10, 0x30, 0x8d, 0xe2, 0x04, 0x10, 0x82, 0xe5, + 0x00, 0x00, 0x9c, 0xe5, 0x0e, 0x23, 0xa0, 0xe3, 0x01, 0x00, 0x10, 0xe2, 0xfb, 0xff, 0xff, 0x1a, + 0x40, 0xc0, 0x64, 0xe2, 0xa4, 0x72, 0xa0, 0xe1, 0x84, 0xe1, 0xa0, 0xe1, 0x7c, 0x81, 0x9f, 0xe5, + 0xa4, 0xaa, 0xa0, 0xe1, 0xa4, 0x96, 0xa0, 0xe1, 0xff, 0x70, 0x07, 0xe2, 0xff, 0xe0, 0x0e, 0xe2, + 0x0c, 0xc0, 0x65, 0xe0, 0xff, 0x90, 0x09, 0xe2, 0x04, 0x70, 0x8d, 0xe5, 0x00, 0xe0, 0x8d, 0xe5, + 0x0c, 0xc0, 0x8d, 0xe5, 0x02, 0x10, 0xa0, 0xe1, 0xff, 0xa0, 0x0a, 0xe2, 0x00, 0x70, 0xa0, 0xe1, + 0xa4, 0x4e, 0xa0, 0xe1, 0x10, 0xc0, 0x8d, 0xe2, 0x02, 0xe0, 0xa0, 0xe1, 0x04, 0x00, 0x82, 0xe5, + 0x08, 0x90, 0x8d, 0xe5, 0x00, 0x00, 0x82, 0xe5, 0x0c, 0x20, 0x9d, 0xe5, 0x02, 0x00, 0x85, 0xe0, + 0x00, 0x00, 0x50, 0xe3, 0x25, 0x00, 0x00, 0xda, 0x00, 0x20, 0xa0, 0xe3, 0x02, 0x70, 0x8c, 0xe7, + 0x04, 0x20, 0x82, 0xe2, 0x40, 0x00, 0x52, 0xe3, 0xfb, 0xff, 0xff, 0x1a, 0x40, 0x00, 0x50, 0xe3, + 0x07, 0x20, 0xa0, 0xd1, 0x40, 0x90, 0x60, 0xd2, 0x03, 0x00, 0x00, 0xda, 0x09, 0x00, 0x00, 0xea, + 0x02, 0xb0, 0xd5, 0xe7, 0x02, 0xb0, 0xcc, 0xe7, 0x01, 0x20, 0x82, 0xe2, 0x09, 0x00, 0x52, 0xe1, + 0xfa, 0xff, 0xff, 0xba, 0x07, 0x00, 0x50, 0xe3, 0x7f, 0x20, 0xe0, 0xe3, 0x09, 0x20, 0xc3, 0xe7, + 0x00, 0x00, 0xa0, 0xd3, 0x08, 0x00, 0x00, 0xda, 0x3b, 0x40, 0xc3, 0xe5, 0x3c, 0xa0, 0xc3, 0xe5, + 0x08, 0x20, 0x9d, 0xe5, 0x01, 0x00, 0xa0, 0xe3, 0x3d, 0x20, 0xc3, 0xe5, 0x04, 0x20, 0x9d, 0xe5, + 0x3e, 0x20, 0xc3, 0xe5, 0x00, 0x20, 0x9d, 0xe5, 0x3f, 0x20, 0xc3, 0xe5, 0xb0, 0x20, 0x9f, 0xe5, + 0x02, 0x90, 0x8c, 0xe0, 0x32, 0x93, 0x89, 0xe2, 0x40, 0x90, 0x49, 0xe2, 0x00, 0x90, 0x99, 0xe5, + 0x04, 0x90, 0x82, 0xe4, 0x08, 0x00, 0x52, 0xe1, 0xf8, 0xff, 0xff, 0x1a, 0x09, 0x00, 0x00, 0xea, + 0x8c, 0x20, 0x9f, 0xe5, 0x02, 0x00, 0x85, 0xe0, 0x32, 0x03, 0x80, 0xe2, 0x40, 0x00, 0x40, 0xe2, + 0x00, 0x00, 0x90, 0xe5, 0x04, 0x00, 0x82, 0xe4, 0x08, 0x00, 0x52, 0xe1, 0xf8, 0xff, 0xff, 0x1a, + 0x40, 0x50, 0x85, 0xe2, 0x00, 0x00, 0xa0, 0xe3, 0x00, 0x20, 0x91, 0xe5, 0x02, 0x20, 0x82, 0xe3, + 0x00, 0x20, 0x81, 0xe5, 0x00, 0x20, 0x91, 0xe5, 0x01, 0x00, 0x12, 0xe3, 0xfc, 0xff, 0xff, 0x1a, + 0x00, 0x20, 0x9e, 0xe5, 0x00, 0x00, 0x50, 0xe3, 0x08, 0x20, 0x82, 0xe3, 0x00, 0x20, 0x8e, 0xe5, + 0xc0, 0xff, 0xff, 0x0a, 0x3c, 0x30, 0x9f, 0xe5, 0x3c, 0x10, 0x9f, 0xe5, 0x03, 0x20, 0xa0, 0xe1, + 0x06, 0x00, 0x92, 0xe6, 0x04, 0x30, 0x83, 0xe2, 0x32, 0x23, 0x82, 0xe2, 0x20, 0x20, 0x42, 0xe2, + 0x01, 0x00, 0x53, 0xe1, 0x00, 0x00, 0x82, 0xe5, 0xf7, 0xff, 0xff, 0x1a, 0x00, 0x00, 0xa0, 0xe3, + 0x00, 0x10, 0xa0, 0xe1, 0x19, 0xfc, 0xff, 0xeb, 0x54, 0xd0, 0x8d, 0xe2, 0xf0, 0x8f, 0xbd, 0xe8, + 0x80, 0x00, 0x00, 0x38, 0x40, 0x00, 0x00, 0x38, 0x20, 0x00, 0x00, 0x38, 0x34, 0x00, 0x00, 0x38, + 0xf0, 0x47, 0x2d, 0xe9, 0x00, 0x40, 0xa0, 0xe1, 0x01, 0x50, 0xa0, 0xe1, 0x0a, 0x00, 0xa0, 0xe3, + 0x01, 0x10, 0xa0, 0xe3, 0xe3, 0x85, 0xa0, 0xe3, 0x03, 0x60, 0xa0, 0xe1, 0x02, 0x70, 0xa0, 0xe1, + 0x01, 0xa0, 0xa0, 0xe3, 0x09, 0xfc, 0xff, 0xeb, 0x00, 0x30, 0xa0, 0xe3, 0x74, 0x30, 0x88, 0xe5, + 0x78, 0x30, 0x88, 0xe5, 0x7c, 0x30, 0x88, 0xe5, 0x80, 0x30, 0x88, 0xe5, 0x08, 0xa0, 0x88, 0xe5, + 0x08, 0x30, 0x88, 0xe5, 0x00, 0xa0, 0x88, 0xe5, 0x10, 0x30, 0x88, 0xe5, 0x6c, 0x50, 0x88, 0xe5, + 0x6c, 0x20, 0x98, 0xe5, 0x0a, 0x00, 0x54, 0xe1, 0x09, 0x40, 0xa0, 0x03, 0x08, 0x40, 0xa0, 0x13, + 0x02, 0x20, 0xe0, 0xe1, 0x88, 0x20, 0x88, 0xe5, 0x8c, 0x30, 0x88, 0xe5, 0x14, 0x40, 0x88, 0xe5, + 0x18, 0x60, 0x88, 0xe5, 0x20, 0x70, 0x88, 0xe5, 0x24, 0x60, 0x88, 0xe5, 0x28, 0x70, 0x88, 0xe5, + 0x2c, 0x60, 0x88, 0xe5, 0x30, 0x70, 0x88, 0xe5, 0x34, 0x60, 0x88, 0xe5, 0x3c, 0x00, 0x00, 0xeb, + 0x08, 0x30, 0xa0, 0xe1, 0x04, 0xa0, 0x88, 0xe5, 0x0c, 0x20, 0x93, 0xe5, 0x0f, 0x00, 0x12, 0xe3, + 0xfc, 0xff, 0xff, 0x0a, 0x0a, 0x00, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0xf0, 0x47, 0xbd, 0xe8, + 0xe6, 0xfb, 0xff, 0xea, 0x98, 0x30, 0x9f, 0xe5, 0xf0, 0x45, 0x2d, 0xe9, 0x94, 0xc0, 0x9f, 0xe5, + 0xfa, 0x4f, 0xa0, 0xe3, 0x03, 0x60, 0xa0, 0xe1, 0x8c, 0x50, 0x9f, 0xe5, 0x1c, 0x00, 0x00, 0xea, + 0xb4, 0x10, 0x93, 0xe5, 0xb2, 0x80, 0xd0, 0xe1, 0xa2, 0xa0, 0xa0, 0xe1, 0x94, 0x18, 0x27, 0xe0, + 0x00, 0x20, 0xa0, 0xe3, 0x09, 0x00, 0x00, 0xea, 0x01, 0x20, 0x22, 0xe2, 0x06, 0x1c, 0x82, 0xe3, + 0x0e, 0x10, 0x81, 0xe3, 0x00, 0x12, 0x8c, 0xe5, 0xb4, 0x10, 0x93, 0xe5, 0x01, 0x10, 0x8a, 0xe0, + 0xb4, 0x80, 0x93, 0xe5, 0x08, 0x80, 0x61, 0xe0, 0x00, 0x00, 0x58, 0xe3, 0xfb, 0xff, 0xff, 0xba, + 0xb4, 0x10, 0x93, 0xe5, 0x01, 0x10, 0x67, 0xe0, 0x00, 0x00, 0x51, 0xe3, 0xf1, 0xff, 0xff, 0xba, + 0x00, 0x52, 0x8c, 0xe5, 0xb4, 0x70, 0xd0, 0xe1, 0xb4, 0x10, 0x96, 0xe5, 0x94, 0x17, 0x22, 0xe0, + 0xb4, 0x10, 0x93, 0xe5, 0x01, 0x10, 0x62, 0xe0, 0x00, 0x00, 0x51, 0xe3, 0xfb, 0xff, 0xff, 0xba, + 0x06, 0x00, 0x80, 0xe2, 0xb0, 0x20, 0xd0, 0xe1, 0x00, 0x00, 0x52, 0xe3, 0xdf, 0xff, 0xff, 0x1a, + 0xf0, 0x85, 0xbd, 0xe8, 0x00, 0x00, 0x70, 0x3c, 0x00, 0x00, 0xf0, 0x3c, 0x0e, 0x06, 0x00, 0x00, + 0x00, 0x30, 0xa0, 0xe3, 0x02, 0x00, 0x00, 0xea, 0x03, 0xc0, 0xd1, 0xe7, 0x03, 0xc0, 0xc0, 0xe7, + 0x01, 0x30, 0x83, 0xe2, 0x00, 0x00, 0x52, 0xe3, 0x01, 0x20, 0x42, 0xe2, 0xf9, 0xff, 0xff, 0x1a, + 0x1e, 0xff, 0x2f, 0xe1, 0x7e, 0xff, 0x17, 0xee, 0xfd, 0xff, 0xff, 0x1a, 0x00, 0x10, 0xa0, 0xe3, + 0x9a, 0x1f, 0x07, 0xee, 0x1e, 0xff, 0x2f, 0xe1, 0xb8, 0x0b, 0xf4, 0x01, 0xf4, 0x01, 0xb8, 0x0b, + 0xf4, 0x01, 0xf4, 0x01, 0xb8, 0x0b, 0xf4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x76, 0xdc, + 0x1d, 0x32, 0xb2, 0x46, 0xa6, 0xc9, 0x7d, 0x5a, 0x61, 0xd3, 0x49, 0x4c, 0x1e, 0xf0, 0xd9, 0xde, + 0xc2, 0x7e, 0xec, 0x02, 0x7c, 0x15, 0x76, 0xbb, 0x5c, 0x4f, 0x2d, 0x95, 0x06, 0x85, 0xdf, 0x28, + 0xe4, 0xd7, 0xf4, 0x82, 0xc0, 0x73, 0xb0, 0x53, 0x26, 0xfc, 0xb0, 0xfe, 0x60, 0x80, 0x7d, 0x33, + 0xa8, 0xde, 0xf8, 0x49, 0xbb, 0xbe, 0x01, 0x45, 0xff, 0x62, 0x40, 0x19, 0xf4, 0x01, 0x64, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe8, 0x03, 0x64, 0x00, 0x00, 0x00, 0xf4, 0x01, 0x96, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x68, 0x73, 0x6c, 0x66, 0x00, 0x38, 0x37, 0x30, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; diff --git a/rbutil/mks5lboot/dualboot.h b/rbutil/mks5lboot/dualboot.h new file mode 100644 index 0000000000..c8952a4c07 --- /dev/null +++ b/rbutil/mks5lboot/dualboot.h @@ -0,0 +1,4 @@ +/* Generated by bin2c */ + +extern unsigned char dualboot_install_ipod6g[5396]; +extern unsigned char dualboot_uninstall_ipod6g[5076]; diff --git a/rbutil/mks5lboot/dualboot/.gitignore b/rbutil/mks5lboot/dualboot/.gitignore new file mode 100644 index 0000000000..34c53b3c82 --- /dev/null +++ b/rbutil/mks5lboot/dualboot/.gitignore @@ -0,0 +1,3 @@ +build/ +*.arm-bin +bin2c diff --git a/rbutil/mks5lboot/dualboot/Makefile b/rbutil/mks5lboot/dualboot/Makefile new file mode 100644 index 0000000000..51ce816ca0 --- /dev/null +++ b/rbutil/mks5lboot/dualboot/Makefile @@ -0,0 +1,97 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id$ +# +ifndef V +SILENT = @ +endif + +CC = gcc +LD = ld +OC = objcopy +CROSS ?= arm-elf-eabi- + +ROOTDIR = ../../.. +FIRMDIR = $(ROOTDIR)/firmware +FWARM = $(FIRMDIR)/target/arm +FW8702 = $(FWARM)/s5l8702 +BUILDDIR = build/ +LINKFILE = dualboot.lds + +# Edit the following variables when adding a new target. +# mks5lboot.c also needs to be edited to refer to these +# To add a new target x you need to: +# 1) add x to the list in TARGETS +# 2) create a variable named OPT_x of the form: +# OPT_x=target specific defines +TARGETS = ipod6g +OPT_ipod6g = -DIPOD_6G -DMEMORYSIZE=64 + +LOADERS = install uninstall +OPT_install = +OPT_uninstall = -DDUALBOOT_UNINSTALL + +# target/loader specific options +$(foreach l, $(LOADERS),$(foreach t, $(TARGETS),\ + $(eval OPT_$(l)_$(t) = $(OPT_$(l)) $(OPT_$(t))))) + +DEFINES = -DBOOTLOADER + +SOURCES = init.S dualboot.c +SOURCES += $(ROOTDIR)/lib/arm_support/support-arm.S +SOURCES += $(wildcard $(FIRMDIR)/asm/mem*.c $(FIRMDIR)/libc/mem*.c) +SOURCES += $(addprefix $(FWARM)/, mmu-arm.S) +SOURCES += $(addprefix $(FW8702)/, clocking-s5l8702.c spi-s5l8702.c nor-s5l8702.c crypto-s5l8702.c) +# target/loader specific sources +SRCTARGET = piezo-.c +$(foreach l, $(LOADERS), $(foreach t, $(TARGETS),\ + $(eval SRC_$(l)_$(t) = $(addprefix $(FW8702)/$(t)/, $(subst -.,-$(subst ipod,,$(t)).,$(SRCTARGET)))))) + +INCLUDES += -I. -I.. -I$(FIRMDIR) -I$(FWARM) -I$(FW8702) +INCLUDES += $(addprefix -I$(FIRMDIR)/, export include libc/include kernel/include) +# target/loader specific includes +$(foreach l,$(LOADERS),$(foreach t,$(TARGETS),$(eval INC_$(l)_$(t) = -I$(FW8702)/$(t)))) + +CFLAGS = $(INCLUDES) -mcpu=arm926ej-s -std=gnu99 -nostdlib -ffreestanding -Os -W -Wall\ + -Wundef -Wstrict-prototypes -ffunction-sections -fdata-sections -Wl,--gc-sections $(DEFINES) + +# Build filenames prefix +PFX = dualboot_ + +BOOTBINS = $(foreach l, $(LOADERS),$(foreach t, $(TARGETS),$(PFX)$(l)_$(t).arm-bin)) + +OUTPUTDUALBOOT = ../dualboot.h ../dualboot.c +OUTPUTDEBUG = $(BOOTBINS:%.arm-bin=$(BUILDDIR)%.arm-elf) $(BOOTBINS:%.arm-bin=$(BUILDDIR)%.lds) + + +all: $(BUILDDIR) $(OUTPUTDUALBOOT) + +$(BUILDDIR)$(PFX)%.lds: $(LINKFILE) + @echo Creating $@ + $(SILENT)$(CROSS)$(CC) $(INC_$*) $(CFLAGS) $(OPT_$*) -E -x c - < $< | sed '/#/d' > $@ + +$(BUILDDIR)$(PFX)%.arm-elf: $(BUILDDIR)$(PFX)%.lds $(SOURCES) + @echo CC -T $(notdir $^ $(SRC_$*)) + $(SILENT)$(CROSS)$(CC) $(INC_$*) $(CFLAGS) $(OPT_$*) -o $@ -T$^ $(SRC_$*) + +$(PFX)%.arm-bin: $(BUILDDIR)$(PFX)%.arm-elf + @echo OC $< + $(SILENT)$(CROSS)$(OC) -O binary $< $@ + +bin2c: bin2c.c + $(CC) -o $@ $< + +$(OUTPUTDUALBOOT): bin2c $(BOOTBINS) + ./bin2c ../dualboot $(BOOTBINS) + +$(BUILDDIR): + mkdir -p $@ + +clean: + rm -rf bin2c $(BOOTBINS) $(BUILDDIR) + +.PRECIOUS: $(OUTPUTDEBUG) diff --git a/rbutil/mks5lboot/dualboot/autoconf.h b/rbutil/mks5lboot/dualboot/autoconf.h new file mode 100644 index 0000000000..cd5b3f9aeb --- /dev/null +++ b/rbutil/mks5lboot/dualboot/autoconf.h @@ -0,0 +1,74 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id:$ + * + * Copyright (C) 2012 by Andrew Ryabinin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __BUILD_AUTOCONF_H +#define __BUILD_AUTOCONF_H + +/* lower case names match the what's exported in the Makefile + * upper case name looks nicer in the code */ + +#define arch_none 0 +#define ARCH_NONE 0 + +#define arch_sh 1 +#define ARCH_SH 1 + +#define arch_m68k 2 +#define ARCH_M68K 2 + +#define arch_arm 3 +#define ARCH_ARM 3 + +#define arch_mips 4 +#define ARCH_MIPS 4 + +#define arch_x86 5 +#define ARCH_X86 5 + +#define arch_amd64 6 +#define ARCH_AMD64 6 + +/* Define target machine architecture */ +#define ARCH arch_arm +/* Optionally define architecture version */ +#define ARCH_VERSION 5 + +/* Define endianess for the target or simulator platform */ +#define ROCKBOX_LITTLE_ENDIAN 1 + +/* Define this if you build rockbox to support the logf logging and display */ +#undef ROCKBOX_HAS_LOGF + +/* Define this if you want logf to output to the serial port */ +#undef LOGF_SERIAL + +/* Define this to record a chart with timings for the stages of boot */ +#undef DO_BOOTCHART + +/* the threading backend we use */ +#define ASSEMBLER_THREADS + +/* root of Rockbox */ +#define ROCKBOX_DIR "/.rockbox" +#define ROCKBOX_SHARE_PATH "" +#define ROCKBOX_BINARY_PATH "" +#define ROCKBOX_LIBRARY_PATH "" + +#endif /* __BUILD_AUTOCONF_H */ diff --git a/rbutil/mks5lboot/dualboot/bin2c.c b/rbutil/mks5lboot/dualboot/bin2c.c new file mode 100644 index 0000000000..4d74a19696 --- /dev/null +++ b/rbutil/mks5lboot/dualboot/bin2c.c @@ -0,0 +1,140 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2007 Dave Chapman + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +static off_t filesize(int fd) +{ + struct stat buf; + + fstat(fd,&buf); + return buf.st_size; +} + +static void write_cfile(const unsigned char* buf, off_t len, FILE* fp, const char *name) +{ + int i; + + fprintf(fp,"unsigned char %s[%ld] = {",name,len); + + for (i=0;i orig_len) + memset(buf+orig_len, 0, len-orig_len); + + /* remove file extension */ + ext = strchr (array, '.'); + if (ext != NULL) + *ext = '\0'; + write_cfile (buf, len, cfile, array); + fprintf(hfile,"extern unsigned char %s[%ld];\n",array,len); + + close(fd); + } + + fclose(cfile); + fclose(hfile); + + return 0; +} diff --git a/rbutil/mks5lboot/dualboot/dualboot.c b/rbutil/mks5lboot/dualboot/dualboot.c new file mode 100644 index 0000000000..b8167ec124 --- /dev/null +++ b/rbutil/mks5lboot/dualboot/dualboot.c @@ -0,0 +1,287 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2015 by Cástor Muñoz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include +#include + +#include "config.h" +#include "system.h" +#include "button.h" + +#include "s5l8702.h" +#include "clocking-s5l8702.h" +#include "spi-s5l8702.h" +#include "nor-target.h" +#include "piezo.h" + +/* How it works: + * + * - dualboot-installer: installs or updates a RB bootloader, the bootloader + * to install/update is already included into dualboot-installer.dfu file, + * once it is executed by the iPod device: + * + * 1) locates an original NORBOOT (ONB): first it looks at offset=32KB, if + * a NORBOOT is found but it is not an ONB then it is supposed it is a + * RB bootloader (that should be updated), then the ONB is loaded from + * offset=32KB+old_BLSIZE). + * 2) write ONB at 32KB+new_BLSIZE, if it fails then: + * 2a) try to restore ONB to its 'pristine' place (offset=32KB), if it + * also fails then the NOR got corrupted (ONB probably destroyed) + * and iTunes should be used to restore the iPod. + * 3) write new (included) RB bootloader at offset=32KB, it it fails then + * goto 2a) + * + * - dualboot-uninstaller: uninstall RB bootloader from NOR, leaving it at + * it's previous (pristine) state. + * + * See bootloader/ipod6g.c for notes on how the RB bootloader works. + * + * + * Pristine NOR Rockboxed NOR + * 1MB ______________ + * | | + * | flsh DIR | + * 1MB-0x200 |______________| + * | | + * | File 1 | + * |..............| + * | | + * . . + * . . + * . . + * | | + * |..............| + * | | . . + * | File N | . . + * |______________| |______________| + * | | | | + * | | | | + * | | | Unused | + * | | | | + * | Unused | 160KB+BLSZ |______________| + * | | | | + * | | | Original | + * | | | NOR boot | + * 160KB |______________| | (decrypted) | + * | | | | + * | | 32KB+BLSZ |______________| + * | Original | | | + * | NOR boot | | Decrypted | + * | (encrypted) | | Rockbox | + * | | | Bootloader | + * 32KB |______________| 32KB |______________| + * | | | | + * | | . . + * | | . . + * |______________| + * | | + * | SysCfg | + * 0 |______________| + * + */ + +#define OF_LOADADDR IRAM1_ORIG + +/* tone sequences: period (uS), duration (ms), silence (ms) */ +static uint16_t alive[] = { 500,100,0, 0 }; +static uint16_t happy[] = { 1000,100,0, 500,150,0, 0 }; +static uint16_t fatal[] = { 3000,500,500, 3000,500,500, 3000,500,0, 0 }; +#define sad2 (&fatal[3]) +#define sad (&fatal[6]) + +/* iPod Classic: decrypted hashes for known OFs */ +static unsigned char of_sha[][SIGN_SZ] = { + "\x66\x66\x76\xDC\x1D\x32\xB2\x46\xA6\xC9\x7D\x5A\x61\xD3\x49\x4C", /* v1.1.2 */ + "\x1E\xF0\xD9\xDE\xC2\x7E\xEC\x02\x7C\x15\x76\xBB\x5C\x4F\x2D\x95", /* v2.0.1 */ + "\x06\x85\xDF\x28\xE4\xD7\xF4\x82\xC0\x73\xB0\x53\x26\xFC\xB0\xFE", /* v2.0.4 */ + "\x60\x80\x7D\x33\xA8\xDE\xF8\x49\xBB\xBE\x01\x45\xFF\x62\x40\x19" /* v2.0.5 */ +}; +#define N_OF (int)(sizeof(of_sha)/SIGN_SZ) + +/* we can assume that unknown FW is a RB bootloader */ +#define FW_RB N_OF + +static int identify_fw(struct Im3Info *hinfo) +{ + unsigned char hash[SIGN_SZ]; + int of; + + /* decrypt hash to identify OF */ + memcpy(hash, hinfo->u.enc12.data_sign, SIGN_SZ); + hwkeyaes(HWKEYAES_DECRYPT, HWKEYAES_UKEY, hash, SIGN_SZ); + + for (of = 0; of < N_OF; of++) + if (memcmp(hash, of_sha[of], SIGN_SZ) == 0) + break; + + return of; +} + +#ifdef DUALBOOT_UNINSTALL +/* Uninstall RB bootloader */ +void main(void) +{ + struct Im3Info *hinfo; + void *fw_addr; + uint16_t *status; + unsigned bl_nor_sz; + + usec_timer_init(); + piezo_seq(alive); + spi_clkdiv(SPI_PORT, 4); /* SPI clock = 27/5 MHz. */ + + hinfo = (struct Im3Info*)OF_LOADADDR; + fw_addr = (void*)hinfo + IM3HDR_SZ; + + if (im3_read(NORBOOT_OFF, hinfo, NULL) != 0) { + status = sad; + goto bye; /* no FW found */ + } + + if (identify_fw(hinfo) != FW_RB) { + status = happy; + goto bye; /* RB bootloader not installed, nothing to do */ + } + + /* if found FW is a RB bootloader, OF should start just behind it */ + bl_nor_sz = im3_nor_sz(hinfo); + if ((im3_read(NORBOOT_OFF + bl_nor_sz, hinfo, fw_addr) != 0) + || (identify_fw(hinfo) == FW_RB)) { + status = sad; + goto bye; /* OF not found */ + } + + /* decrypted OF correctly loaded, encrypt it before restoration */ + im3_crypt(HWKEYAES_ENCRYPT, hinfo, fw_addr); + + /* restore OF to it's original place */ + if (!im3_write(NORBOOT_OFF, hinfo)) { + status = fatal; + goto bye; /* corrupted NOR, use iTunes to restore */ + } + + /* erase freed NOR blocks */ + bootflash_init(SPI_PORT); + bootflash_erase_blocks(SPI_PORT, + (NORBOOT_OFF + im3_nor_sz(hinfo)) >> 12, bl_nor_sz >> 12); + bootflash_close(SPI_PORT); + + status = happy; + +bye: + /* minimum time between the initial and the final beeps */ + while (USEC_TIMER < 2000000); + piezo_seq(status); + WDTCON = 0x100000; /* WDT reset */ + while (1); +} + +#else +/* Install RB bootloader */ +struct Im3Info bl_hinfo __attribute__((section(".im3info.data"))) = +{ + .ident = IM3_IDENT, + .version = IM3_VERSION, + .enc_type = 2, +}; + +static uint32_t get_uint32le(unsigned char *p) +{ + return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); +} + +void main(void) +{ + uint16_t *status = happy; + int single_boot; + struct Im3Info *hinfo; + void *fw_addr; + unsigned bl_nor_sz; + + usec_timer_init(); + piezo_seq(alive); + spi_clkdiv(SPI_PORT, 4); /* SPI clock = 27/5 MHz. */ + + /* check for single boot installation, is is configured when + mks5lboot.exe builds the .dfu image */ + single_boot = bl_hinfo.info_sign[0]; + + /* sign RB bootloader (data and header), but don't encrypt it, + use current decrypted image for faster load */ + im3_sign(HWKEYAES_UKEY, (void*)&bl_hinfo + IM3HDR_SZ, + get_uint32le(bl_hinfo.data_sz), bl_hinfo.u.enc12.data_sign); + im3_sign(HWKEYAES_UKEY, &bl_hinfo, IM3INFOSIGN_SZ, bl_hinfo.info_sign); + + if (single_boot) { + if (!im3_write(NORBOOT_OFF, &bl_hinfo)) + status = sad; + goto bye; + } + + hinfo = (struct Im3Info*)OF_LOADADDR; + fw_addr = (void*)hinfo + IM3HDR_SZ; + + if (im3_read(NORBOOT_OFF, hinfo, fw_addr) != 0) { + status = sad; + goto bye; /* no FW found */ + } + + if (identify_fw(hinfo) == FW_RB) { + /* FW found, but not OF, assume it is a RB bootloader, + already decrypted OF should be located just behind */ + int nor_offset = NORBOOT_OFF + im3_nor_sz(hinfo); + if ((im3_read(nor_offset, hinfo, fw_addr) != 0) + || (identify_fw(hinfo) == FW_RB)) { + status = sad; + goto bye; /* OF not found, use iTunes to restore */ + } + } + + bl_nor_sz = im3_nor_sz(&bl_hinfo); + /* safety check - verify we are not going to overwrite useful data */ + if (flsh_get_unused() < bl_nor_sz) { + status = sad2; + goto bye; /* no space if flash, use iTunes to restore */ + } + + /* write decrypted OF and RB bootloader, if any of these fails we + will try to retore OF to its original place */ + if (!im3_write(NORBOOT_OFF + bl_nor_sz, hinfo) + || !im3_write(NORBOOT_OFF, &bl_hinfo)) { + im3_crypt(HWKEYAES_ENCRYPT, hinfo, fw_addr); + if (!im3_write(NORBOOT_OFF, hinfo)) { + /* corrupted NOR, use iTunes to restore */ + status = fatal; + } + else { + /* RB bootloader not succesfully intalled, but device + was restored and should be working as before */ + status = sad; + } + } + +bye: + /* minimum time between the initial and the final beeps */ + while (USEC_TIMER < 2000000); + piezo_seq(status); + WDTCON = 0x100000; /* WDT reset */ + while (1); +} +#endif /* DUALBOOT_UNINSTALL */ diff --git a/rbutil/mks5lboot/dualboot/dualboot.lds b/rbutil/mks5lboot/dualboot/dualboot.lds new file mode 100644 index 0000000000..cb92e2a286 --- /dev/null +++ b/rbutil/mks5lboot/dualboot/dualboot.lds @@ -0,0 +1,59 @@ +#define ASM +#include "config.h" +#include "cpu.h" +#include "mks5lboot.h" + +ENTRY(_start) +OUTPUT_FORMAT(elf32-littlearm) +OUTPUT_ARCH(arm) + +#define BIN_ORIG DFU_LOADADDR + BIN_OFFSET +#define BIN_SIZE MAX_PAYLOAD + +MEMORY +{ + IRAM : ORIGIN = BIN_ORIG, LENGTH = BIN_SIZE +} + +SECTIONS +{ + .text : { + *(.init.text*) + *(.text*) + *(.icode*) + . = ALIGN(4); + } > IRAM + + /* include initialized BSS (if any) into DFU image */ + .bss : { + *(.bss*) + *(.ibss*) + *(COMMON) + . = ALIGN(4); + } > IRAM + +#if 1 + /* reuse pwnage as stack, 0x30c bytes available */ + _exception_stack = BIN_ORIG; + _supervisor_stack = _exception_stack; +#else + /* include stack into DFU image */ + .stack : { + . += 0x400; + _supervisor_stack = .; + . += 0x200; + _exception_stack = .; + } > IRAM +#endif + + .data : { + *(.data*) + *(.rodata*) + *(.idata*) + *(.irodata*) + /* place bootloader IM3 header at the end, mkdfu + will concatenate the bootloader binary here */ + . = ALIGN(16); + *(.im3info.data*) + } > IRAM +} diff --git a/rbutil/mks5lboot/dualboot/init.S b/rbutil/mks5lboot/dualboot/init.S new file mode 100644 index 0000000000..bd049515f4 --- /dev/null +++ b/rbutil/mks5lboot/dualboot/init.S @@ -0,0 +1,43 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: + * + * Copyright © 2009 Michael Sparmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + + .section .init.text, "ax", %progbits + .global _start + +_start: + mov r0, #0xD7 + msr CPSR_c, r0 @ Abort mode, IRQs/FIQs disabled + ldr sp, =_exception_stack + + mov r0, #0xDB + msr CPSR_c, r0 @ Undefined Instruction mode, IRQs/FIQs disabled + ldr sp, =_exception_stack + + mov r0, #0xD3 + msr CPSR_c, r0 @ Supervisor mode, IRQs/FIQs disabled + ldr sp, =_supervisor_stack + + MOV R0, #0x00050000 + ORR R0, #0x00000078 + MCR p15, 0, R0, c1, c0, 0 @ Get rid of some CPU "features" likely to cause trouble + + bl main + .ltorg diff --git a/rbutil/mks5lboot/ipoddfu.c b/rbutil/mks5lboot/ipoddfu.c new file mode 100644 index 0000000000..6d303d6603 --- /dev/null +++ b/rbutil/mks5lboot/ipoddfu.c @@ -0,0 +1,875 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2015 by Cástor Muñoz + * + * based on: + * ipoddfu_c by user890104 + * xpwn/pwnmetheus2 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef NO_LIBUSBAPI +#define USE_LIBUSBAPI +#endif + +#include +#include +#include +#include +#include +#ifdef WIN32 +#include +#include +#include +#endif + +#ifdef USE_LIBUSBAPI +#include +#endif + +#include "mks5lboot.h" + + +static void sleep_ms(unsigned int ms) +{ + struct timespec req; + req.tv_sec = ms / 1000; + req.tv_nsec = (ms % 1000) * 1000000; + nanosleep(&req, NULL); +} + +/* + * CRC32 functions + * Based on public domain implementation by Finn Yannick Jacobs. + */ + +/* Written and copyright 1999 by Finn Yannick Jacobs + * No rights were reserved to this, so feel free to + * manipulate or do with it, what you want or desire :) + */ + +#define CRC32_DEFAULT_SEED 0xffffffff + +/* crc32table[] built by crc32_init() */ +static unsigned long crc32table[256]; + +/* Calculate crc32. Little endian. + * Standard seed is 0xffffffff or 0. + * Some implementations xor result with 0xffffffff after calculation. + */ +static uint32_t crc32(void *data, unsigned int len, uint32_t seed) +{ + uint8_t *d = data; + + while (len--) + { + seed = ((seed >> 8) & 0x00FFFFFF) ^ crc32table [(seed ^ *d++) & 0xFF]; + } + + return seed; +} + +/* Calculate crc32table */ +static void crc32_init() +{ + uint32_t poly = 0xEDB88320L; + uint32_t crc; + int i, j; + + for (i = 0; i < 256; ++i) + { + crc = i; + + for (j = 8; j > 0; --j) + { + crc = (crc >> 1) ^ ((crc & 1) ? poly : 0); + } + + crc32table[i] = crc; + } +} + + +/* + * DFU + */ + +/* must be pow2 <= wTransferSize (2048) */ +#define DFU_PKT_SZ 2048 + +#define APPLE_VID 0x05AC + +static int KNOWN_PIDS[] = +{ + /* DFU */ + 0x1220, /* Nano 2G */ + 0x1223, /* Nano 3G and Classic 1G/2G/3G/4G */ + 0x1224, /* Shuffle 3G */ + 0x1225, /* Nano 4G */ + 0x1231, /* Nano 5G */ + 0x1232, /* Nano 6G */ + 0x1233, /* Shuffle 4G */ + 0x1234, /* Nano 7G */ + /* WTF */ + 0x1240, /* Nano 2G */ + 0x1241, /* Classic 1G */ + 0x1242, /* Nano 3G */ + 0x1243, /* Nano 4G */ + 0x1245, /* Classic 2G */ + 0x1246, /* Nano 5G */ + 0x1247, /* Classic 3G */ + 0x1248, /* Nano 6G */ + 0x1249, /* Nano 7G */ + 0x124a, /* Nano 7G */ + 0x1250, /* Classic 4G */ + 0 +}; + +struct usbControlSetup { + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} __attribute__ ((packed)); +#define USB_CS_SZ (sizeof(struct usbControlSetup)) + +struct usbStatusData { + uint8_t bStatus; + uint8_t bwPollTimeout0; + uint8_t bwPollTimeout1; + uint8_t bwPollTimeout2; + uint8_t bState; + uint8_t iString; +} __attribute__ ((packed)); + +/* DFU 1.1 specs */ +typedef enum DFUState { + appIDLE = 0, + appDETACH = 1, + dfuIDLE = 2, + dfuDNLOAD_SYNC = 3, + dfuDNBUSY = 4, + dfuDNLOAD_IDLE = 5, + dfuMANIFEST_SYNC = 6, + dfuMANIFEST = 7, + dfuMANIFEST_WAIT_RESET = 8, + dfuUPLOAD_IDLE = 9, + dfuERROR = 10 +} DFUState; + +typedef enum DFUStatus { + errNONE = 0, + errTARGET = 1, + errFILE = 2, + errWRITE = 3, + errERASE = 4, + errCHECK_ERASED = 5, + errPROG = 6, + errVERIFY = 7, + errADDRESS = 8, + errNOTDONE = 9, + errFIRMWARE = 10, + errVENDOR = 11, + errUSBR = 12, + errPOR = 13, + errUNKNOWN = 14, + errSTALLEDPKT = 15 +} DFUStatus; + +typedef enum DFURequest { + DFU_DETACH = 0, + DFU_DNLOAD = 1, + DFU_UPLOAD = 2, + DFU_GETSTATUS = 3, + DFU_CLRSTATUS = 4, + DFU_GETSTATE = 5, + DFU_ABORT = 6 +} DFURequest; + +struct dfuDev { + struct dfuAPI *api; + int found_pid; + int detached; + char descr[256]; + int res; /* API result: 1->ok, 0->failure */ + char err[256]; + /* API private */ +#ifdef WIN32 + HANDLE fh; + HANDLE ph; + DWORD ec; /* winapi error code */ +#endif +#ifdef USE_LIBUSBAPI + libusb_context* ctx; + libusb_device_handle* devh; + int rc; /* libusb return code */ +#endif +}; + +struct dfuAPI { + char *name; + int (*open_fn)(struct dfuDev*, int*); + int (*dfureq_fn)(struct dfuDev*, struct usbControlSetup*, void*); + int (*reset_fn)(struct dfuDev*); + void (*close_fn)(struct dfuDev*); +}; + + +/* + * low-level (API specific) functions + */ +static int dfu_check_id(int vid, int pid, int *pid_list) +{ + int *p; + if (vid != APPLE_VID) + return 0; + for (p = pid_list; *p; p++) + if (*p == pid) + return 1; + return 0; +} + +/* adds extra DFU request error info */ +static void dfu_add_reqerrstr(struct dfuDev *dfuh, struct usbControlSetup *cs) +{ + snprintf(dfuh->err + strlen(dfuh->err), + sizeof(dfuh->err) - strlen(dfuh->err), " (cs=%02x/%d/%d/%d/%d)", + cs->bmRequestType, cs->bRequest, cs->wValue, cs->wIndex, cs->wLength); +} + +#ifdef WIN32 +static int dfu_winapi_chkrc(struct dfuDev *dfuh, char *str, bool success) +{ + dfuh->res = (int)success; + if (!success) { + dfuh->ec = GetLastError(); + snprintf(dfuh->err, sizeof(dfuh->err), "%s error %ld", str, dfuh->ec); + } + return dfuh->res; +} + +static int dfu_winapi_request(struct dfuDev *dfuh, + struct usbControlSetup* cs, void* data) +{ + unsigned char buf[USB_CS_SZ + DFU_PKT_SZ]; + DWORD rdwr; + bool rc; + + memcpy(buf, cs, USB_CS_SZ); + + if (cs->bmRequestType & 0x80) + { + rc = ReadFile(dfuh->ph, buf, USB_CS_SZ + cs->wLength, &rdwr, NULL); + memcpy(data, buf+USB_CS_SZ, cs->wLength); + dfu_winapi_chkrc(dfuh, "DFU request failed: ReadFile()", rc); + } + else + { + memcpy(buf+USB_CS_SZ, data, cs->wLength); + rc = WriteFile(dfuh->ph, buf, USB_CS_SZ + cs->wLength, &rdwr, NULL); + dfu_winapi_chkrc(dfuh, "DFU request failed: WriteFile()", rc); + } + + if (!dfuh->res) + dfu_add_reqerrstr(dfuh, cs); + return dfuh->res; +} + +static int dfu_winapi_reset(struct dfuDev *dfuh) +{ + DWORD bytesReturned; + bool rc = DeviceIoControl(dfuh->fh, 0x22000c, + NULL, 0, NULL, 0, &bytesReturned, NULL); + return dfu_winapi_chkrc(dfuh, + "Could not reset USB device: DeviceIoControl()", rc); +} + +static void dfu_winapi_close(struct dfuDev *dfuh) +{ + if (dfuh->fh != INVALID_HANDLE_VALUE) { + CloseHandle(dfuh->fh); + dfuh->fh = INVALID_HANDLE_VALUE; + } + if (dfuh->ph != INVALID_HANDLE_VALUE) { + CloseHandle(dfuh->ph); + dfuh->ph = INVALID_HANDLE_VALUE; + } +} + +static const GUID GUID_AAPLDFU = + { 0xB8085869L, 0xFEB9, 0x404B, {0x8C, 0xB1, 0x1E, 0x5C, 0x14, 0xFA, 0x8C, 0x54}}; + +static int dfu_winapi_open(struct dfuDev *dfuh, int *pid_list) +{ + const GUID *guid = &GUID_AAPLDFU; + HDEVINFO devinfo = NULL; + SP_DEVICE_INTERFACE_DETAIL_DATA_A* details = NULL; + SP_DEVICE_INTERFACE_DATA iface; + char *path = NULL; + DWORD i, size; + bool rc; + + dfuh->fh = + dfuh->ph = INVALID_HANDLE_VALUE; + dfuh->found_pid = 0; + dfuh->res = 1; /* ok */ + dfuh->ec = 0; + + /* Get DFU path */ + devinfo = SetupDiGetClassDevsA(guid, NULL, NULL, + DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + if (!dfu_winapi_chkrc(dfuh, "SetupDiGetClassDevsA()", + (devinfo != INVALID_HANDLE_VALUE))) + goto error; + + iface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + + for (i = 0; SetupDiEnumDeviceInterfaces(devinfo, NULL, guid, i, &iface); i++) + { + int vid, pid; + + SetupDiGetDeviceInterfaceDetailA(devinfo, &iface, NULL, 0, &size, NULL); + + if (details) free(details); + details = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*) malloc(size); + details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); + rc = SetupDiGetDeviceInterfaceDetailA(devinfo, &iface, details, size, NULL, NULL); + if (!dfu_winapi_chkrc(dfuh, "SetupDiGetDeviceInterfaceDetailA()", rc)) + goto error; + + CharUpperA(details->DevicePath); + if (sscanf(details->DevicePath, "%*4cUSB#VID_%04x&PID_%04x%*s", &vid, &pid) != 2) + continue; + if (!dfu_check_id(vid, pid, pid_list)) + continue; + + if (path) free(path); + path = malloc(size - sizeof(DWORD) + 16); + memcpy(path, details->DevicePath, size - sizeof(DWORD)); + + dfuh->fh = CreateFileA(path, GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + if (!dfu_winapi_chkrc(dfuh, "CreateFileA(fh)", (dfuh->fh != INVALID_HANDLE_VALUE))) + goto error; + + strcat(path, "\\PIPE0"); + dfuh->ph = CreateFileA(path, GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + if (!dfu_winapi_chkrc(dfuh, "CreateFileA(ph)", (dfuh->ph != INVALID_HANDLE_VALUE))) + goto error; + + /* ok */ + snprintf(dfuh->descr, sizeof(dfuh->descr), "%s", details->DevicePath); + dfuh->found_pid = pid; + goto bye; + } + + if (!dfu_winapi_chkrc(dfuh, "SetupDiEnumDeviceInterfaces()", + (GetLastError() == ERROR_NO_MORE_ITEMS))) + goto error; + + /* no devices found */ + +bye: + if (path) free(path); + if (details) free(details); + if (devinfo) SetupDiDestroyDeviceInfoList(devinfo); + return dfuh->res; + +error: + dfu_winapi_close(dfuh); + goto bye; +} +#endif /* WIN32 */ + +#ifdef USE_LIBUSBAPI +static int dfu_libusb_chkrc(struct dfuDev *dfuh, char *str) +{ + dfuh->res = (dfuh->rc < LIBUSB_SUCCESS) ? 0 : 1; + if (dfuh->res == 0) + snprintf(dfuh->err, sizeof(dfuh->err), + "%s: %s", str, libusb_error_name(dfuh->rc)); + return dfuh->res; +} + +static int dfu_libusb_request(struct dfuDev *dfuh, + struct usbControlSetup *cs, void *data) +{ + dfuh->rc = libusb_control_transfer(dfuh->devh, cs->bmRequestType, + cs->bRequest, cs->wValue, cs->wIndex, data, cs->wLength, 500); + if (!dfu_libusb_chkrc(dfuh, "DFU request failed")) + dfu_add_reqerrstr(dfuh, cs); + return dfuh->res; +} + +static int dfu_libusb_reset(struct dfuDev *dfuh) +{ + dfuh->rc = libusb_reset_device(dfuh->devh); + return dfu_libusb_chkrc(dfuh, "Could not reset USB device"); +} + +static void dfu_libusb_close(struct dfuDev *dfuh) +{ + if (dfuh->devh) { + libusb_release_interface(dfuh->devh, 0); + if (dfuh->detached) + libusb_attach_kernel_driver(dfuh->devh, 0); + libusb_close(dfuh->devh); + dfuh->devh = NULL; + } + if (dfuh->ctx) { + libusb_exit(dfuh->ctx); + dfuh->ctx = NULL; + } +} + +static int dfu_libusb_open(struct dfuDev *dfuh, int *pid_list) +{ + struct libusb_device_descriptor desc; + libusb_device **devs = NULL, *dev; + int n_devs, i; + + dfuh->devh = NULL; + dfuh->found_pid = 0; + dfuh->detached = 0; + dfuh->res = 1; /* ok */ + + dfuh->rc = libusb_init(&(dfuh->ctx)); + if (!dfu_libusb_chkrc(dfuh, "Could not init USB library")) { + dfuh->ctx = NULL; /* invalidate ctx (if any) */ + goto error; + } + + n_devs = + dfuh->rc = libusb_get_device_list(dfuh->ctx, &devs); + if (!dfu_libusb_chkrc(dfuh, "Could not get USB device list")) + goto error; + + for (i = 0; i < n_devs; ++i) + { + dev = devs[i]; + + /* Note: since libusb-1.0.16 (LIBUSB_API_VERSION >= 0x01000102) + this function always succeeds. */ + if (libusb_get_device_descriptor(dev, &desc) != LIBUSB_SUCCESS) + continue; /* Unable to get device descriptor */ + + if (!dfu_check_id(desc.idVendor, desc.idProduct, pid_list)) + continue; + + dfuh->rc = libusb_open(dev, &(dfuh->devh)); + if (!dfu_libusb_chkrc(dfuh, "Could not open USB device")) + goto error; + + dfuh->rc = libusb_set_configuration(dfuh->devh, 1); + if (!dfu_libusb_chkrc(dfuh, "Could not set USB configuration")) + goto error; + + dfuh->rc = libusb_kernel_driver_active(dfuh->devh, 0); + if (dfuh->rc != LIBUSB_ERROR_NOT_SUPPORTED) { + if (!dfu_libusb_chkrc(dfuh, "Could not get USB driver status")) + goto error; + if (dfuh->rc == 1) { + dfuh->rc = libusb_detach_kernel_driver(dfuh->devh, 0); + if (!dfu_libusb_chkrc(dfuh, "Could not detach USB driver")) + goto error; + dfuh->detached = 1; + } + } + + dfuh->rc = libusb_claim_interface(dfuh->devh, 0); + if (!dfu_libusb_chkrc(dfuh, "Could not claim USB interface")) + goto error; + + /* ok */ + snprintf(dfuh->descr, sizeof(dfuh->descr), + "[%04x:%04x] at bus %d, device %d, USB ver. %04x", + desc.idVendor, desc.idProduct, libusb_get_bus_number(dev), + libusb_get_device_address(dev), desc.bcdUSB); + dfuh->found_pid = desc.idProduct; + break; + } + +bye: + if (devs) + libusb_free_device_list(devs, 1); + if (!dfuh->found_pid) + dfu_libusb_close(dfuh); + return dfuh->res; + +error: + goto bye; +} +#endif /* USE_LIBUSBAPI */ + +/* list of suported APIs: + * Windows: winapi and libusb (optional) + * Linux and OSX: libusb + */ +static struct dfuAPI api_list[] = +{ +#ifdef WIN32 + { "winapi", + dfu_winapi_open, + dfu_winapi_request, + dfu_winapi_reset, + dfu_winapi_close }, +#endif +#ifdef USE_LIBUSBAPI + { "libusb", + dfu_libusb_open, + dfu_libusb_request, + dfu_libusb_reset, + dfu_libusb_close }, +#endif +#ifdef __APPLE__ + /* TODO: implement API for OS X < 10.6 ??? */ +#endif +}; +#define DFU_N_APIS (sizeof(api_list)/sizeof(struct dfuAPI)) + +/* + * mid-layer (common) functions + */ +static void dfu_set_errstr(struct dfuDev *dfuh, char *str) +{ + strncpy(dfuh->err, str, sizeof(dfuh->err)); +} + +static int DEBUG_DFUREQ = 0; + +static int dfu_request(struct dfuDev *dfuh, + struct usbControlSetup *cs, void *data) +{ + if (!DEBUG_DFUREQ) + return dfuh->api->dfureq_fn(dfuh, cs, data); + + /* DEBUG */ + + /* previous state */ + unsigned char ste = 0; + struct usbControlSetup css = { 0xA1, DFU_GETSTATE, 0, 0, sizeof(ste) }; + if (!dfuh->api->dfureq_fn(dfuh, &css, &ste)) { + snprintf(dfuh->err + strlen(dfuh->err), sizeof(dfuh->err) - + strlen(dfuh->err), " [DEBUG_DFUREQ ERROR: state=%d]", ste); + return 0; + } + + int ret = dfuh->api->dfureq_fn(dfuh, cs, data); + fprintf(stderr, "[DEBUG]: REQ: ste=%d, cs=%2x/%d/%d/%d/%d -> %s", + ste, cs->bmRequestType, cs->bRequest, cs->wValue, + cs->wIndex, cs->wLength, ret ? "ok" : "ERROR"); + if (cs->bRequest == DFU_GETSTATE) + fprintf(stderr, " (state=%d)", *((unsigned char*)(data))); + if (cs->bRequest == DFU_GETSTATUS) { + struct usbStatusData *sd = (struct usbStatusData*)data; + fprintf(stderr, " (status=%d, polltmo=%d, state=%d)", sd->bStatus, + (sd->bwPollTimeout2 << 16) | (sd->bwPollTimeout1 << 8) | + (sd->bwPollTimeout0), sd->bState); + } + fputc('\n', stderr); + fflush(stderr); + return ret; +} + +static int dfureq_getstatus(struct dfuDev *dfuh, int *status, + int *poll_tmo /*ms*/, int *state) +{ + struct usbStatusData sd = { 0, 0, 0, 0, 0, 0 }; + struct usbControlSetup cs = { 0xA1, DFU_GETSTATUS, 0, 0, sizeof(sd) }; + int ret = dfu_request(dfuh, &cs, &sd); + if (status) *status = sd.bStatus; + if (state) *state = sd.bState; + if (poll_tmo) *poll_tmo = (sd.bwPollTimeout2 << 16) | + (sd.bwPollTimeout1 << 8) | (sd.bwPollTimeout0); + return ret; +} + +static int dfureq_getstate(struct dfuDev *dfuh, int *state) +{ + if (!state) + return 1; /* nothing to do */ + unsigned char sts = 0; + struct usbControlSetup cs = { 0xA1, DFU_GETSTATE, 0, 0, sizeof(sts) }; + int ret = dfu_request(dfuh, &cs, &sts); + *state = sts; + return ret; +} + +static int dfureq_dnload(struct dfuDev* dfuh, uint16_t blknum, + uint16_t len, unsigned char *data) +{ + struct usbControlSetup cs = { 0x21, DFU_DNLOAD, blknum, 0, len }; + return dfu_request(dfuh, &cs, data); +} + +/* not used */ +#if 0 +static int dfureq_upload(struct dfuDev* dfuh, + uint16_t blknum, uint16_t len, unsigned char *data) +{ + struct usbControlSetup cs = { 0xA1, DFU_UPLOAD, blknum, 0, len }; + return dfu_request(dfuh, &cs, data); +} + +static int dfureq_clrstatus(struct dfuDev* dfuh) +{ + struct usbControlSetup cs = { 0x21, DFU_CLRSTATUS, 0, 0, 0 }; + return dfu_request(dfuh, &cs, NULL); +} + +static int dfureq_abort(struct dfuDev* dfuh) +{ + struct usbControlSetup cs = { 0x21, DFU_ABORT, 0, 0, 0 }; + return dfu_request(dfuh, &cs, NULL); +} + +/* not implemented on DFU8702 */ +static int dfureq_detach(struct dfuDev* dfuh, int tmo) +{ + struct usbControlSetup cs = { 0x21, DFU_DETACH, tmo, 0, 0 }; + return dfu_request(dfuh, &cs, NULL); +} +#endif + +static int dfu_send_packet(struct dfuDev* dfuh, uint16_t blknum, + uint16_t len, unsigned char *data, int *status, + int *poll_tmo, int *state, int *pre_state) +{ + if (!dfureq_dnload(dfuh, blknum, len, data)) + return 0; + + /* device is in dfuDLSYNC state, waiting for a GETSTATUS request + to enter the next state, if she respond with dfuDLBUSY then + we must wait to resend the GETSTATUS request */ + + if (!dfureq_getstatus(dfuh, status, poll_tmo, state)) + return 0; + + if (*state == dfuDNBUSY) { + if (*poll_tmo) + sleep_ms(*poll_tmo); + if (!dfureq_getstate(dfuh, pre_state)) + return 0; + if (!dfureq_getstatus(dfuh, status, poll_tmo, state)) + return 0; + } + + return 1; +} + +static int dfu_download_file(struct dfuDev* dfuh, + unsigned char *data, unsigned long size) +{ + unsigned int blknum, len, remaining; + int status, poll_tmo, state; + + if (!dfureq_getstate(dfuh, &state)) + goto error; + + if (state != dfuIDLE) { + dfu_set_errstr(dfuh, "Could not start DFU download: not idle"); + goto error; + } + + blknum = 0; + remaining = size; + while (remaining) + { + len = (remaining < DFU_PKT_SZ) ? remaining : DFU_PKT_SZ; + + if (!dfu_send_packet(dfuh, blknum, len, data + + blknum*DFU_PKT_SZ, &status, &poll_tmo, &state, NULL)) + goto error; + + if (state != dfuDNLOAD_IDLE) { + dfu_set_errstr(dfuh, "DFU download aborted: unexpected state"); + goto error; + } + + remaining -= len; + blknum++; + } + + /* send ZLP */ + int pre_state = 0; + if (!dfu_send_packet(dfuh, blknum, 0, NULL, + &status, &poll_tmo, &state, &pre_state)) { + if (pre_state == dfuMANIFEST_SYNC) + goto ok; /* pwnaged .dfu file */ + goto error; + } + + if (state != dfuMANIFEST) { + if (status == errFIRMWARE) + dfu_set_errstr(dfuh, "DFU download failed: corrupt firmware"); + else + dfu_set_errstr(dfuh, "DFU download failed: unexpected state"); + goto error; + } + + /* wait for manifest stage */ + if (poll_tmo) + sleep_ms(poll_tmo); + + if (!dfureq_getstatus(dfuh, &status, NULL, &state)) + goto ok; /* 1223 .dfu file */ + + + /* TODO: next code never tested */ + + if (state != dfuMANIFEST_WAIT_RESET) { + if (status == errVERIFY) + dfu_set_errstr(dfuh, "DFU manifest failed: wrong FW verification"); + else + dfu_set_errstr(dfuh, "DFU manifest failed: unexpected state"); + goto error; + } + + if (!dfuh->api->reset_fn(dfuh)) + goto error; + +ok: + return 1; +error: + return 0; +} + +static int dfu_open(struct dfuDev *dfuh, int pid) +{ + int pid_l[2] = {0}; + struct dfuAPI *api; + unsigned i; + + pid_l[0] = pid; + + for (i = 0; i < DFU_N_APIS; i++) + { + api = &api_list[i]; + if (!(api->open_fn(dfuh, pid ? pid_l : KNOWN_PIDS))) + return 0; /* error */ + if (dfuh->found_pid) { + dfuh->api = api; + printf("[INFO] %s: found %s\n", api->name, dfuh->descr); + fflush(stdout); + return 1; /* ok */ + } + printf("[INFO] %s: no DFU devices found\n", api->name); + fflush(stdout); + } + + dfu_set_errstr(dfuh, "DFU device not found"); + return 0; +} + +static void dfu_destroy(struct dfuDev *dfuh) +{ + if (dfuh) { + if (dfuh->api) + dfuh->api->close_fn(dfuh); + free(dfuh); + } +} + +static struct dfuDev *dfu_create() +{ + return calloc(sizeof(struct dfuDev), 1); +} + +/* + * exported functions + */ +int ipoddfu_send(int pid, unsigned char *data, int size, + char* errstr, int errstrsize) +{ + struct dfuDev *dfuh; + unsigned char *buf; + unsigned int checksum; + int ret = 1; /* ok */ + + dfuh = dfu_create(); + + buf = malloc(size+4); + if (!buf) { + dfu_set_errstr(dfuh, "Could not allocate memory for DFU buffer"); + goto error; + } + + if (memcmp(data, IM3_IDENT, 4)) { + dfu_set_errstr(dfuh, "Bad DFU image data"); + goto error; + } + + /* FIXME: big endian */ + crc32_init(); + checksum = crc32(data, size, CRC32_DEFAULT_SEED); + memcpy(buf, data, size); + memcpy(buf+size, &checksum, 4); + + if (!dfu_open(dfuh, pid)) + goto error; + + if (!dfu_download_file(dfuh, buf, size+4)) + goto error; + +bye: + if (buf) free(buf); + dfu_destroy(dfuh); + return ret; + +error: + ret = 0; + if (errstr) + snprintf(errstr, errstrsize, "[ERR] %s", dfuh->err); + goto bye; +} + +/* search for the DFU device and gets its DFUState */ +int ipoddfu_scan(int pid, int *state, int reset, + char* errstr, int errstrsize) +{ + struct dfuDev *dfuh; + int ret = 1; /* ok */ + + dfuh = dfu_create(); + + if (!dfu_open(dfuh, pid)) + goto error; + + if (reset) + if (!dfuh->api->reset_fn(dfuh)) + goto error; + + if (!dfureq_getstate(dfuh, state)) + goto error; + +bye: + dfu_destroy(dfuh); + return ret; + +error: + ret = 0; + if (errstr) + snprintf(errstr, errstrsize, "[ERR] %s", dfuh->err); + goto bye; +} + +void ipoddfu_debug(int debug) +{ + DEBUG_DFUREQ = debug; +} diff --git a/rbutil/mks5lboot/main.c b/rbutil/mks5lboot/main.c new file mode 100644 index 0000000000..98c85b9bb7 --- /dev/null +++ b/rbutil/mks5lboot/main.c @@ -0,0 +1,287 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id:$ + * + * Copyright (C) 2015 by Cástor Muñoz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mks5lboot.h" + +/* Win32 compatibility */ +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#define DEFAULT_LOOP_PERIOD 1 /* seconds */ + +#define ERROR(format, ...) \ + do { \ + snprintf(errstr, errstrsize, "[ERR] "format, __VA_ARGS__); \ + goto error; \ + } while(0) + +static int write_file(char *outfile, unsigned char* buf, + int bufsize, char* errstr, int errstrsize) +{ + int fd = open(outfile, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0666); + if (fd < 0) + ERROR("Could not open %s for writing", outfile); + + if (write(fd, buf, bufsize) != bufsize) + ERROR("Could not write file %s", outfile); + + return 1; + +error: + return 0; +} + +static unsigned char *read_file(char *infile, int *bufsize, + char* errstr, int errstrsize) +{ + unsigned char *buf; + int fd; + struct stat s; + + fd = open(infile, O_RDONLY|O_BINARY); + if (fd < 0) + ERROR("Could not open %s for reading", infile); + + if (fstat(fd, &s) < 0) + ERROR("Checking size of input file %s", infile); + + *bufsize = s.st_size; + + buf = malloc(*bufsize); + if (buf == NULL) + ERROR("Could not allocate memory for %s", infile); + + if (read(fd, buf, *bufsize) != *bufsize) + ERROR("Could not read file %s", infile); + + return buf; + +error: + return NULL; +} + +static void sleep_ms(unsigned int ms) +{ + struct timespec req; + req.tv_sec = ms / 1000; + req.tv_nsec = (ms % 1000) * 1000000; + nanosleep(&req, NULL); +} + +static void usage(void) +{ + fprintf(stderr, + "Usage:\n" + " mks5lboot --bl-inst [-p ] [--single]\n" + " --bl-uninst [-p ]\n" + " --dfuscan [--loop []] [-p ]\n" + " --dfusend [-p ]\n" + " --dfureset [--loop []] [-p ]\n" + " --mkdfu-inst [--single]\n" + " --mkdfu-uninst \n" + " --mkdfu-raw \n" + "\n" + "Commands:\n" + " --bl-inst Install file into an iPod device\n" + " (same as --mkdfu-inst and --dfusend).\n" + " --bl-uninst Remove a bootloader from an iPod device (same as\n" + " --mkdfu-uninst and --dfusend).\n" + "\n" + " --dfuscan scan for DFU USB devices and outputs the status.\n" + " --dfusend send DFU image to the device.\n" + " --dfureset reset DFU USB device bus.\n" + "\n" + " --mkdfu-inst Build a DFU image containing an installer for\n" + " , save it as .\n" + " --mkdfu-uninst Build a DFU image containing an uninstaler for\n" + " devices, save it as .\n" + " --mkdfu-raw Build a DFU image containing raw executable\n" + " code, save it ass . \n" + " is the code you want to run, it is loaded at\n" + " address 0x%08x and executed.\n" + "\n" + " is the rockbox bootloader that you want to\n" + " install (previously scrambled with tools/scramble utility).\n" + "\n" + " is the name of the platform (type of device) for\n" + " which the DFU uninstaller will be built. Currently supported\n" + " platform names are:\n" + " ipod6g: iPod Classic 6G\n" + "\n" + "Options:\n" + " -p, --pid Use a specific (Product Id) USB device,\n" + " if this option is ommited then it uses the\n" + " first USB DFU device found.\n" + " -l, --loop Run the command every seconds, default\n" + " period ( ommited) is %d seconds.\n" + " -S, --single Be careful using this option. The bootloader\n" + " is installed for single boot, the original\n" + " Apple NOR boot is destroyed (if it exists),\n" + " and only Rockbox can be used.\n" + , DFU_LOADADDR + BIN_OFFSET + , DEFAULT_LOOP_PERIOD); + + exit(1); +} + +int main(int argc, char* argv[]) +{ + char *dfuoutfile = NULL; + char *dfuinfile = NULL; + char *dfu_arg = NULL; + int dfu_type = DFU_NONE; + int n_cmds = 0; + int scan = 0; + int pid = 0; + int reset = 0; + int loop = 0; + int single = 0; + char errstr[200]; + unsigned char *dfubuf; + int dfusize; + + fprintf(stderr, + "mks5lboot Version " VERSION "\n" + "This is free software; see the source for copying conditions. There is NO\n" + "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" + "\n"); + fflush(stderr); + + while (--argc) + { + argv++; + if (!memcmp(*argv, "--bl", 4)) { + if (!strcmp(*argv+4, "-inst")) dfu_type = DFU_INST; + else if (!strcmp(*argv+4, "-uninst")) dfu_type = DFU_UNINST; + else usage(); + if (!--argc) usage(); + dfu_arg = *++argv; + n_cmds++; + } + else if (!memcmp(*argv, "--mkdfu", 7)) { + if (!strcmp(*argv+7, "-inst")) dfu_type = DFU_INST; + else if (!strcmp(*argv+7, "-uninst")) dfu_type = DFU_UNINST; + else if (!strcmp(*argv+7, "-raw")) dfu_type = DFU_RAW; + else usage(); + if (!--argc) usage(); + dfu_arg = *++argv; + if (!--argc) usage(); + dfuoutfile = *++argv; + n_cmds++; + } + else if (!strcmp(*argv, "--dfusend")) { + if (!--argc) usage(); + dfuinfile = *++argv; + n_cmds++; + } + else if (!strcmp(*argv, "--dfuscan")) { + scan = 1; + n_cmds++; + } + else if (!strcmp(*argv, "--dfureset")) { + scan = 1; + reset = 1; + n_cmds++; + } + else if (!strcmp(*argv, "--pid") || !strcmp(*argv, "-p")) { + if (!--argc) usage(); + if (sscanf(*++argv, "%x", &pid) != 1) usage(); + } + else if (!strcmp(*argv, "--loop") || !strcmp (*argv, "-l")) { + if (!(argc-1) || *(argv+1)[0] == '-') { + loop = DEFAULT_LOOP_PERIOD; + } + else { + if ((sscanf(*++argv, "%d", &loop) != 1) || !loop) usage(); + argc--; + } + } + else if (!strcmp(*argv, "--single") || !strcmp(*argv, "-S")) { + single = 1; + } + else if (!strcmp(*argv, "--debug")) { + ipoddfu_debug(1); + } + else + usage(); + } + + if (n_cmds != 1) + usage(); + + if ((dfu_type == DFU_INST) && single) + dfu_type = DFU_INST_SINGLE; + + if (scan) { + int cnt = 0; + while (1) { + int state, res; + if (loop) printf("[%d] ", cnt); + else printf("[INFO] "); + printf("DFU %s:\n", reset ? "reset":"scan"); + res = ipoddfu_scan(pid, &state, reset, errstr, sizeof(errstr)); + if (res == 0) + printf("%s\n", errstr); + else + printf("[INFO] DFU device state: %d\n", state); + if (!loop) + exit(!res); + fflush(stdout); + sleep_ms(loop*1000); + cnt += loop; + } + } + + if (dfuinfile) + dfubuf = read_file(dfuinfile, &dfusize, errstr, sizeof(errstr)); + else + dfubuf = mkdfu(dfu_type, dfu_arg, &dfusize, errstr, sizeof(errstr)); + + if (!dfubuf) + goto error; + + if (dfuoutfile) { + if (write_file(dfuoutfile, dfubuf, dfusize, errstr, sizeof(errstr))) { + printf("[INFO] Created file %s (%d bytes)\n", dfuoutfile, dfusize); + exit(0); + } + } + else { + if (ipoddfu_send(pid, dfubuf, dfusize, errstr, sizeof(errstr))) { + printf("[INFO] DFU image sent successfully (%d bytes)\n", dfusize); + exit(0); + } + } + +error: + printf("%s\n", errstr); + exit(1); +} diff --git a/rbutil/mks5lboot/mkdfu.c b/rbutil/mks5lboot/mkdfu.c new file mode 100644 index 0000000000..6ac0daf1ac --- /dev/null +++ b/rbutil/mks5lboot/mkdfu.c @@ -0,0 +1,318 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2015 by Cástor Muñoz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "mks5lboot.h" + +/* Header for ARM code binaries */ +#include "dualboot.h" + +/* Win32 compatibility */ +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +/* + * This code is based on emCORE, adds a couple of improvements thanks to + * some extra features in Apple's ROM: + * - Generic Im3Info header valid for all payloads. It is done by moving + * the certificate to a fixed position (before data), and using a 'magic' + * value (0x300) for signature offset. + * - Some integer overflows in ROM make it possible to use the free space + * available in Im3Hdr, resulting a maximum payload size of: + * 128 KiB - 0x50 bytes (IM3INFO_SZ) - 700 bytes (CERT_SIZE). + */ + +const struct ipod_models ipod_identity[] = +{ + [MODEL_IPOD6G] = { + "Classic 6G", "ipod6g", "ip6g", 71, + dualboot_install_ipod6g, sizeof(dualboot_install_ipod6g), + dualboot_uninstall_ipod6g, sizeof(dualboot_uninstall_ipod6g) }, +}; + +struct Im3Info s5l8702hdr = +{ + .ident = IM3_IDENT, + .version = IM3_VERSION, + .enc_type = 3, + .u.enc34 = { + .sign_off = "\x00\x03\x00\x00", + .cert_off = "\x50\xF8\xFF\xFF", /* -0x800 + CERT_OFFSET */ + .cert_sz = "\xBA\x02\x00\x00", /* CERT_SIZE */ + }, + .info_sign = "\xC2\x54\x51\x31\xDC\xC0\x84\xA4" + "\x7F\xD1\x45\x08\xE8\xFF\xE8\x1D", +}; + +unsigned char s5l8702pwnage[/*CERT_SIZE*/] = +{ + "\x30\x82\x00\x7A\x30\x66\x02\x00\x30\x0D\x06\x09\x2A\x86\x48\x86" + "\xF7\x0D\x01\x01\x05\x05\x00\x30\x0B\x31\x09\x30\x07\x06\x03\x55" + "\x04\x03\x13\x00\x30\x1E\x17\x0D\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x17\x0D\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x30\x0B\x31\x09\x30\x07\x06\x03\x55\x04\x03\x13" + "\x00\x30\x19\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01" + "\x05\x00\x03\x08\x00\x30\x05\x02\x01\x00\x02\x00\x30\x0D\x06\x09" + "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x01\x00\x30\x82" + "\x00\x7A\x30\x66\x02\x00\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D" + "\x01\x01\x05\x05\x00\x30\x0B\x31\x09\x30\x07\x06\x03\x55\x04\x03" + "\x13\x00\x30\x1E\x17\x0D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x17\x0D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x30\x0B\x31\x09\x30\x07\x06\x03\x55\x04\x03\x13\x00\x30" + "\x19\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00" + "\x03\x08\x00\x30\x05\x02\x01\x00\x02\x00\x30\x0D\x06\x09\x2A\x86" + "\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x01\x00\x30\x82\x01\xBA" + "\x30\x50\x02\x00\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01" + "\x05\x05\x00\x30\x00\x30\x1E\x17\x0D\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x17\x0D\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x30\x00\x30\x19\x30\x0D\x06\x09\x2A\x86\x48" + "\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x08\x00\x30\x05\x02\x01\x00" + "\x02\x00\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05" + "\x00\x03\x82\x01\x55" +}; + +static uint32_t get_uint32le(unsigned char* p) +{ + return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); +} + +static uint32_t get_uint32be(unsigned char* p) +{ + return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; +} + +static void put_uint32le(unsigned char* p, uint32_t x) +{ + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; +} + +#define ERROR(format, ...) \ + do { \ + snprintf(errstr, errstrsize, "[ERR] "format, __VA_ARGS__); \ + goto error; \ + } while(0) + +static unsigned char *load_file(char *filename, int *bufsize, + const struct ipod_models** model, + char* errstr, int errstrsize) +{ + int fd, i; + struct stat s; + unsigned char header[8]; + unsigned char *buf = NULL; + bool is_rbbl = (model); + + fd = open(filename, O_RDONLY|O_BINARY); + if (fd < 0) + ERROR("Could not open %s for reading", filename); + + if (fstat(fd, &s) < 0) + ERROR("Checking filesize of input file %s", filename); + *bufsize = s.st_size; + + if (is_rbbl) { + /* Read Rockbox header */ + if (read(fd, header, sizeof(header)) != sizeof(header)) + ERROR("Could not read file %s", filename); + *bufsize -= sizeof(header); + + for (i = 0; i < NUM_MODELS; i++) + if (memcmp(ipod_identity[i].rb_model_name, header + 4, 4) == 0) + break; + + if (i == NUM_MODELS) + ERROR("Model name \"%4.4s\" unknown. " + "Is this really a rockbox bootloader?", header + 4); + + *model = &ipod_identity[i]; + } + + buf = malloc(*bufsize); + if (buf == NULL) + ERROR("Could not allocate memory for %s", filename); + + if (read(fd, buf, *bufsize) != *bufsize) + ERROR("Could not read file %s", filename); + + if (is_rbbl) { + /* Check checksum */ + uint32_t sum = (*model)->rb_model_num; + for (i = 0; i < *bufsize; i++) { + /* add 8 unsigned bits but keep a 32 bit sum */ + sum += buf[i]; + } + if (sum != get_uint32be(header)) + ERROR("Checksum mismatch in %s", filename); + } + + close(fd); + return buf; + +error: + if (fd >= 0) + close(fd); + if (buf) + free(buf); + return NULL; +} + +unsigned char *mkdfu(int dfu_type, char *dfu_arg, int* dfu_size, + char* errstr, int errstrsize) +{ + const struct ipod_models *model = NULL; + unsigned char *dfu_buf = NULL; + unsigned char *f_buf; + int f_size; + uint32_t padded_bl_size; + uint32_t cert_off, cert_sz; + off_t cur_off; + char *dfu_desc; + int i; + + switch (dfu_type) + { + case DFU_INST: + case DFU_INST_SINGLE: + f_buf = load_file(dfu_arg, &f_size, &model, errstr, errstrsize); + if (f_buf == NULL) + goto error; + /* IM3 data size should be padded to 16 */ + padded_bl_size = ((f_size + 0xf) & ~0xf); + *dfu_size = BIN_OFFSET + (model->dualboot_install_size + + (IM3HDR_SZ - (int)IM3INFO_SZ) + (int)padded_bl_size); + dfu_desc = (dfu_type == DFU_INST_SINGLE) ? "BL installer (single)" + : "BL installer"; + break; + + case DFU_UNINST: + for (i = 0; i < NUM_MODELS; i++) { + if (!strcmp(ipod_identity[i].platform_name, dfu_arg)) { + model = &ipod_identity[i]; + break; + } + } + if (!model) + ERROR("Platform name \"%s\" unknown", dfu_arg); + + *dfu_size = BIN_OFFSET + model->dualboot_uninstall_size; + dfu_desc = "BL uninstaller"; + break; + + case DFU_RAW: + default: + f_buf = load_file(dfu_arg, &f_size, NULL, errstr, errstrsize); + if (f_buf == NULL) + goto error; + /* IM3 data size should be padded to 16 */ + *dfu_size = BIN_OFFSET + ((f_size + 0xf) & ~0xf); + dfu_desc = "raw binary"; + break; + } + + printf("[INFO] Building DFU:\n"); + printf("[INFO] type: %s\n", dfu_desc); + if ((dfu_type == DFU_INST) || (dfu_type == DFU_INST_SINGLE)) + printf("[INFO] BL size: %d\n", f_size); + if (dfu_type == DFU_RAW) + printf("[INFO] BIN size: %d\n", f_size); + printf("[INFO] DFU size: %d\n", *dfu_size); + if (model) { + printf("[INFO] model name: %s\n", model->model_name); + printf("[INFO] platform: %s\n", model->platform_name); + printf("[INFO] RB name: %s\n", model->rb_model_name); + printf("[INFO] RB num: %d\n", model->rb_model_num); + } + + if (*dfu_size > DFU_MAXSIZE) + ERROR("DFU image (%d bytes) too big", *dfu_size); + + dfu_buf = calloc(*dfu_size, 1); + if (!dfu_buf) + ERROR("Could not allocate %d bytes for DFU image", *dfu_size); + + cert_off = get_uint32le(s5l8702hdr.u.enc34.cert_off); + cert_sz = get_uint32le(s5l8702hdr.u.enc34.cert_sz); + + memcpy(dfu_buf, &s5l8702hdr, sizeof(s5l8702hdr)); + + cur_off = IM3HDR_SZ + cert_off; + + memcpy(dfu_buf + cur_off, s5l8702pwnage, sizeof(s5l8702pwnage)); + + /* set entry point */ + cur_off += cert_sz - 4; + put_uint32le(dfu_buf + cur_off, DFU_LOADADDR + BIN_OFFSET); + + cur_off = BIN_OFFSET; + + switch (dfu_type) + { + case DFU_INST: + case DFU_INST_SINGLE: + /* copy the dualboot installer binary */ + memcpy(dfu_buf + cur_off, model->dualboot_install, + model->dualboot_install_size); + /* point to the start of the included IM3 header info */ + cur_off += model->dualboot_install_size - IM3INFO_SZ; + /* set bootloader data size */ + struct Im3Info *bl_info = (struct Im3Info*)(dfu_buf + cur_off); + put_uint32le(bl_info->data_sz, padded_bl_size); + /* use info_sign to pass params to the dualboot installer */ + if (dfu_type == DFU_INST_SINGLE) + bl_info->info_sign[0] = 0x1; + /* add bootloader binary */ + cur_off += IM3HDR_SZ; + memcpy(dfu_buf + cur_off, f_buf, f_size); + break; + + case DFU_UNINST: + /* copy the dualboot uninstaller binary */ + memcpy(dfu_buf + cur_off, model->dualboot_uninstall, + model->dualboot_uninstall_size); + break; + + case DFU_RAW: + default: + /* add raw binary */ + memcpy(dfu_buf + cur_off, f_buf, f_size); + break; + } + + return dfu_buf; + +error: + if (dfu_buf) + free(dfu_buf); + return NULL; +} diff --git a/rbutil/mks5lboot/mks5lboot.h b/rbutil/mks5lboot/mks5lboot.h new file mode 100644 index 0000000000..084bec61f9 --- /dev/null +++ b/rbutil/mks5lboot/mks5lboot.h @@ -0,0 +1,129 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id:$ + * + * Copyright (C) 2015 by Cástor Muñoz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __MK6GBOOT_H__ +#define __MK6GBOOT_H__ + +/* useful for dualboot.lds */ +#define DFU_LOADADDR 0x22000000 +#define DFU_MAXSIZE 0x20000 /* maximum .dfu file size */ + +#define CERT_OFFSET 0x50 /* IM3INFO_SZ */ +#define CERT_SIZE 698 +#define BIN_OFFSET (CERT_OFFSET + ((CERT_SIZE + 0x3) & ~ 0x3)) +#define MAX_PAYLOAD (DFU_MAXSIZE - BIN_OFFSET) + +#ifndef ASM +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define IM3_IDENT "8702" +#define IM3_VERSION "1.0" +#define IM3HDR_SZ 0x800 +#define IM3INFO_SZ (sizeof(struct Im3Info)) +#define IM3INFOSIGN_SZ (offsetof(struct Im3Info, info_sign)) + +#define SIGN_SZ 16 + +struct Im3Info +{ + uint8_t ident[4]; + uint8_t version[3]; + uint8_t enc_type; + uint8_t entry[4]; /* LE */ + uint8_t data_sz[4]; /* LE */ + union { + struct { + uint8_t data_sign[SIGN_SZ]; + uint8_t _reserved[32]; + } enc12; + struct { + uint8_t sign_off[4]; /* LE */ + uint8_t cert_off[4]; /* LE */ + uint8_t cert_sz[4]; /* LE */ + uint8_t _reserved[36]; + } enc34; + } u; + uint8_t info_sign[SIGN_SZ]; +} __attribute__ ((packed)); + +struct Im3Hdr +{ + struct Im3Info info; + uint8_t _zero[IM3HDR_SZ - sizeof(struct Im3Info)]; +} __attribute__ ((packed)); + + +/* Supported models */ +enum { + MODEL_UNKNOWN = -1, + MODEL_IPOD6G = 0, + /* new models go here */ + + NUM_MODELS +}; + +struct ipod_models { + /* Descriptive name of this model */ + const char* model_name; + /* for bootloader uninstallers */ + const char* platform_name; + /* Model name used in the Rockbox header in ".ipod" files - these match the + -add parameter to the "scramble" tool */ + const char* rb_model_name; + /* Model number used to initialise the checksum in the Rockbox header in + ".ipod" files - these are the same as MODEL_NUMBER in config-target.h */ + const int rb_model_num; + /* Dualboot functions for this model */ + const unsigned char* dualboot_install; + int dualboot_install_size; + const unsigned char* dualboot_uninstall; + int dualboot_uninstall_size; +}; +extern const struct ipod_models ipod_identity[]; + + +enum { + DFU_NONE = -1, + DFU_INST, /* RB installer */ + DFU_INST_SINGLE, /* RB installer (single) */ + DFU_UNINST, /* RB uninstaller */ + DFU_RAW /* raw binary */ +}; + +unsigned char *mkdfu(int dfu_type, char *dfu_arg, int* dfu_size, + char* errstr, int errstrsize); + +int ipoddfu_send(int pid, unsigned char *buf, int size, + char* errstr, int errstrsize); +int ipoddfu_scan(int pid, int *state, int reset, + char* errstr, int errstrsize); +void ipoddfu_debug(int debug); + +#ifdef __cplusplus +}; +#endif +#endif /* ASM */ + +#endif /* __MK6GBOOT_H__ */ -- cgit