FreeCalypso > hg > freecalypso-tools
changeset 0:e7502631a0f9
initial import from freecalypso-sw rev 1033:5ab737ac3ad7
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,15 @@ +SUBDIR= ffstools lcdemu loadtools miscutil rvinterf + +all: ${SUBDIR} + +${SUBDIR}: FRC + cd $@; ${MAKE} ${MFLAGS} + +clean: FRC + rm -f a.out core errs + for i in ${SUBDIR}; do (cd $$i; ${MAKE} ${MFLAGS} clean); done + +install: FRC + for i in ${SUBDIR}; do (cd $$i; ${MAKE} ${MFLAGS} install); done + +FRC:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,49 @@ +You are looking at the top level of the FreeCalypso host tools package. All +tools in this package have been written to run on a Unix-based or Unix-like +host system, such as a GNU/Linux PC or laptop, with the expectation that the +user will compile them from the source using her regular system C compiler. + +Most of these tools interface to and operate on Calypso-based GSM devices, +while a few perform some ancillary functions. Please see +doc/Host-tools-overview for the listing of what tools are available and what +they do. These tools are built in the following source directories: + +ffstools tiffs, mokoffs and pirffs are built here. + +loadtools fc-loadtool, fc-iram, fc-xram and fc-compalram form the part of + FC host tools called loadtools, which used to be its own + package. In common with the rest of FC host tools, loadtools + run on a PC or whatever host system, but they also require two + target-side components called loadagent (for all targets) and + compalstage (for Compal phones only). If you are working with + a packaged release of FC host tools, as opposed to a random + snapshot of the source tree, precompiled binaries for loadagent + and compalstage will be included under + loadtools/target-binaries. + +lcdemu fc-lcdemu is built here. + +miscutil fc-rgbconv, fc-serterm and imei-luhn are built here. + +rvinterf Everything dealing with the RVTMUX interface to running GSM + firmwares and everything based on the rvinterf framework is + built under rvinterf. + + The tfc139 utility, which logically belongs with loadtools, is + built in the rvinterf subtree because it is built from mostly + the same source components as rvtdump and rvinterf. + +The 5 directories listed above contain all of FC host tools; they are all you +need in order to get a fully working installation of these tools if you are +using the provided precompiled binaries for loadagent and compalstage. However, +if you would like to recompile these components from source, you will need the +following additional stuff: + +target-utils The source for loadagent and compalstage lives here, along with + a few extra target utilities that are of interest only to + developers. + +toolchain Scripts and patches for building the gcc+binutils toolchain + targeting ARM7, the CPU core of the Calypso GSM/GPRS baseband + processor. You'll need to build and install this toolchain + first before you can build target-utils.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/Compal-unlock Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,389 @@ +Using FreeCalypso tools to unlock Motorola C1xx phones +====================================================== + +The ultimate goal of the FreeCalypso project is to produce our own complete GSM +dumbphone firmware which We the People fully own, control and compile from +source ourselves, running at first on some selected pre-existing hardware +targets, and then ultimately on our own Free Dumb Phone hardware. While that +goal is still far past the visible horizon, what can we do in the meantime to +make our current forced use of existing proprietary dumbphone firmwares a +little more tolerable? This article presents one such hack: using FreeCalypso +loadtools to dump the flash content of Compal phones for analysis, including +TIFFS, and to replace one existing proprietary fw version with another, e.g., +to remove carrier branding and the associated SIM restriction. + +Serial access + +Mot C1xx (Compal) phones have a 2.5 mm headset jack that dual-functions as a +debug/programming serial port. In hardware terms, there is an electrically +controlled switch (MUX) inside that switches the external jack between the +analog headset signals and the digital serial ones; this switch is controlled +by a GPIO signal from the Calypso. The hardware power-up state of this switch +is serial; Mot/Compal's standard fw switches it to headset upon boot, but the +serial setting persists long enough to use it to break into the bootloader. + +Bootloader + +The Calypso DBB (digital baseband) chip used in these phones has an on-chip +boot ROM, but it also has a hardware pin that enables or disables this boot +ROM, and unfortunately these phones have it disabled. If the boot ROM were +enabled in hardware, it would provide an unstoppable and unbrickable way to +take control of the device through the externally-accessible serial port like +we have on Openmoko and Pirelli phones, but unfortunately the hardware we have +available is not wired that way. + +However, Mot/Compal's standard firmware on these phones includes a bootloader, +a part that executes before any of the rest of the fw image is allowed to +execute or is made use of in any way, and this Compal-specific bootloader has a +provision for interrupting the boot process and diverting it to an externally- +supplied piece of code loaded over the serial line. Older fw versions have +this feature enabled unconditionally, but some of the newer versions have a +malfeature whereby the serial boot interrupt and code download possibility may +be disabled. Some C1xx phones out in the wild, particularly all North American +C139s with TracFone branding and some of the Cingular-branded ones as well, +have such maliciously-locked firmware in them. + +Fortunately though, these maliciously-locked firmwares (or at least all versions +we've encountered so far) have been found to have another hole through which we +can break in, as described in the TFC139-breakin article. We can exploit this +hole in the firmware to gain code execution access to the Calypso, and then use +the latter to reprogram the flash, replacing the ultra-malicious firmware with +some other version that, although still proprietary, is a little less evil. + +Making first contact +==================== + +If you have a C1xx phone which you are seeking to free, your first step should +be to try breaking in with fc-loadtool, using the Compal bootloader method. +With the phone powered off, but containing a charged battery (SIM present or +absent, doesn't matter), proceed as follows: + +1. Connect the serial or USB-serial cable between your PC or other host and the + target phone's headset jack. + +2. On the host end, run fc-loadtool like this: + +C11x/123: fc-loadtool -h compal /dev/ttyXXX +C139/140: fc-loadtool -h compal -c 1003 /dev/ttyXXX +C155/156: fc-loadtool -h c155 /dev/ttyXXX + +3. Press the power button on the phone. A momentary press is sufficient and + recommended: the hardware powers up and causes the boot code to run exactly + the same whether the power button is pressed momentarily or held down. + + Normal phone power-up requires the button to be held down because the + standard firmware does a check fairly late in the boot process to see if the + power button is still held down, and commands the hardware (the ABB) to + power off if it is not - it is a standard feature to prevent phones from + turning themselves on inadvertently from accidental momentary presses of + that button. But if the goal is to cause the boot code to run, but not to + boot the regular fw all the way, a momentary press is ideal. + +If your phone has a bootloader without the malicious lock in it, the above +procedure should result in fc-loadtool gaining full access to the target and +landing you at a loadtool> prompt. You can dump the flash content and analyse +it, etc. If you would like to change to a different fw version (to remove the +SIM lock / carrier branding or for any other reason), see the corresponding +later section of this article. + +Alternative method +================== + +If the above procedure fails to gain access to the Calypso because the boot +code in the phone never offers a serial download opportunity, the alternate +break-in method should be tried, going through the full running firmware +instead of just the bootloader part thereof. Proceed as follows: + +1. Remove the SIM (if there was one to begin with) and put the charged battery + back in. Charge the battery if necessary, using the standard charging + function of the existing fw. + +2. Power the phone up for normal boot: hold the power button down like a + regular user would, without fc-loadtool or other serial break-in tools. + The fw will boot up, notice the lack of a SIM, and the display will read + "SIM card absent" or something to that effect, depending on the fw version. + +3. Key in this magic sequence: **16379#. A hidden "Trace Switch" menu should + appear, with the choices being "Trace On" and "Earphone". Select "Trace On". + The electrically controlled hardware switch mentioned earlier in this article + should now be set back to the UART, bringing the latter out to the headset + jack. Because Mot/Compal's firmware is based on TI's reference architecture, + the interface presented by the running fw on this serial port is TI's RVTMUX, + albeit at 57600 baud instead of TI's default of 115200. + +4. Connect the headset jack serial cable if it wasn't already connected, and + run this FreeCalypso utility: + + tfc139 /dev/ttyXXX + +(The name tfc139 is historical; the current version is expected to work with + all Mot C1xx firmwares.) + +Compal's TI-based firmware implements some of TI's Test Mode commands, and one +of these commands is a raw memory write. It also implements some of TI's GPF +"system primitive" commands, including the MEMCHECK command that causes the +firmware to report some info on all running GPF tasks, including the location +of each task's stack. Our tfc139 utility will try to break into the phone +(gain code execution access) by querying the target fw for the location of the +L1A task's stack, and then using Test Mode memory write commands to write a +piece of shellcode into an unused RAM location and to make this code execute by +overwriting a function return address on the stack of the L1A task that +processes these Test Mode commands. + +If the stack smashing hack succeeds, the shellcode injected by tfc139 will send +a message out the serial port indicating this success, and then re-enable the +Calypso boot ROM and jump to it. Once the boot ROM code gains control, it will +wait forever for a serial code download following its standard protocol. If +tfc139 gets the success indication from the target, it will announce this +success and direct you to run: + +fc-loadtool -h compal -c none /dev/ttyXXX + +Do as it says. The -c none option tells fc-loadtool to skip compalstage and +proceed directly to feeding loadagent to the Calypso boot ROM. You should now +be in full control of the phone via fc-loadtool. + +There is one additional quirk worth mentioning. It appears that Mot/Compal's +main fw keeps resetting the RTC alarm registers in the Calypso DBB as it runs, +always keeping the alarm time in the near future relative to the current time. +When one breaks into this firmware with tfc139 and takes over the control of +the device with fc-loadtool, this alarm time will almost certainly be reached, +and the RTC alarm will go off. This alarm has no effect on loadtool operation +(i.e., it cannot reset the CPU or otherwise wrestle control away from loadtool, +so it doesn't add any bricking risk), but it has one quite surprising effect +upon exit, i.e., when you are done with your loadtool session and give it the +exit command. + +Loadtool's configured default exit action for this target is to send a power-off +command to the Iota ABB, leaving the device cleanly powered off. However, if +the RTC alarm has gone off previously during the session, the ABB will instantly +power the phone back on, and put it through a new boot cycle. The firmware +handles this special form of boot rather oddly: it proceeds to the same end +state it would have reached via a normal power button hold-down boot (powered +on with the "Insert SIM" message on the LCD), but it reaches this state almost +instantly, without going through the power-on LCD logo and buzz phase. Odd, +but harmless. This explanation has been included to save other hackers the +hours of bewildered head-scratching I spent chasing this quirk down. + +Dumping and reloading flash +=========================== + +Once you break in with fc-loadtool (either through the bootloader or through +tfc139), the first step you should do is make a dump (backup) of the flash: + +loadtool> flash dump2bin flashdump.bin + +Before you do any flash write (erase or program) operations, please realise +that these phones are brickable. Because the Calypso boot ROM is disabled at +the board level (Calypso DBB's nIBOOT configuration input is tied high directly +underneath the BGA package!), when the phone powers up, the ARM7 core starts +executing instructions directly out of the flash, from address 0. Therefore, +flash sector 0 must contain good working boot code (one that allows serial code +download access for recovery) at all times. If you erase this sector or fill +it with some garbage (anything other than good working boot code) and then power +the phone off or otherwise lose control of it, the phone will be unrecoverably +bricked! + +On most C1xx models there seems to be no way to access the Calypso's JTAG +signals, hence no possibility of using JTAG to unbrick a bricked phone. And +because the flash chip is a micro-BGA, it is quite unlikely that one could +successfully desolder it, program it in a standalone flash chip programmer, +and then put it back on the board. Thus if you brick your C1xx phone, then +most likely it is truly toast. You've been warned! + +That being said, if your phone came with a maliciously locked bootloader, such +that you had to use tfc139 to break in, then replacing that bootloader with a +non-malware version is pretty much a necessity, and taking the chance of +bricking the phone becomes a necessary risk. Even if the bootloader version in +your C1xx is free of the locking malfeature, if you need to reflash the main fw +to a different version, one still needs to erase and reprogram the dangerous +sector: on C11x/123 and C139/140 the main fw image starts at 0x2000, but the +erase block boundary doesn't come until 0x10000. + +The good news, however, is that fc-loadtool has special support for rewriting +the boot sector on Compal phones with minimal risk of bricking. The command is: + +flash erase-program-boot binfile [length] + +The first argument is the name of the file (in straight binary format) +containing the new boot code; the second argument (always interpreted as hex) +is the number of bytes to program, always starting at 0. If only one argument +is given, the length of the file is used instead, which must not exceed the +length of flash sector 0: 64 KiB on C11x/123 and C139/140, or 8 KiB on C155/156. + +This special command minimizes the bricking vulnerability window by loading the +entirety of the new boot code to be programmed into a scratchpad RAM buffer on +the target first (no problem because it's 64 KiB max), then commanding loadagent +(the code that actually runs on the Calypso when you use fc-loadtool) to perform +the "atomic" operation of erasing flash sector 0, then immediately reprogramming +it with the bits that are already in scratchpad RAM on the phone. + +With this approach the phone will only be bricked if the battery dies or is +physically yanked out of the phone in the time window between the beginning of +the erase operation and the last critical bit of the new boot code being +programmed - on the order of a second or two, or if the flash operations fail +for some reason. However, the phone will *not* be bricked with this approach +if the serial connection between fc-loadtool or the target gets broken during +the window in question, or if the host machine running fc-loadtool crashes: no +flash operations start until loadtool gives the go-ahead command to loadagent, +and once loadagent receives the latter command, it will proceed till completion +without caring if loadtool is still there or not. + +Of course the conventional flash erase and flash program-bin commands will be +happy to operate on flash sector 0 just like any other sector, but doing so is +NOT recommended, as the window of vulnerability for bricking would then be +considerably greater. + +Unlocked firmware for C139 +========================== + +If your phone is a North American (1900+850 MHz) C139, and you are reading this +article because it came with Cingular or TracFone branding, whereas you would +like to use it with SIMs and networks of your own choosing instead, you've come +to the right place. We have an unlocked and non-carrier-branded (Mot branding +only) version of the fw that runs on these phones, and you can use FreeCalypso +loadtools to flash this version into your C139 whether it came with Cingular or +TF branding originally. Download this file: + +ftp.freecalypso.org:/pub/GSM/Compal/c139-unlocked-fw.zip + +Unzip it, and you'll get c139-unlocked-fw.bin - that is the image you'll need +to flash into your phone. Get in with fc-loadtool (using tfc139 if necessary +for bootloader-locked phones) and make a backup of the original flash content. +Then reflash the firmware as follows: + +flash erase-program-boot c139-unlocked-fw.bin 2000 +flash erase 10000 360000 +flash program-bin 2000 c139-unlocked-fw.bin 2000 + +The 3 commands given above will reflash the phone as follows: + +* The first 0x2000 bytes of the firmware image in c139-unlocked-fw.bin comprise + the boot code. This fw version features the "good" boot code *without* the + access locking malfeature. The erase-program-boot command will erase flash + sector 0 (the entire 64 KiB sector, as the physics of the flash chip dictates) + and then immediately reprogram its first 8 KiB with the "good" boot code from + the unlocked fw image file. The remaining 56 KiB of this sector will be blank + after this step. + +* The following "regular" flash erase command is to erase the following 54 + sectors (also of 64 KiB each) in preparation for programming the main fw + image in there. + +* The last command programs the bulk of the fw image into blank flash that has + been erased by the first two commands. + +I also recommend erasing the old FFS that was maintained by the old fw version, +so that the new fw will automatically format a "virgin" FFS the first time it +boots: + +flash erase 370000 50000 + +After this procedure the phone should retain its original IMEI and factory RF +calibration values, as these are stored in the 8 KiB sector at 0x3FC000 which +is not touched per the above procedure - not in the FFS. + +The same procedure should be followed for flashing all firmwares for C11x/123 +and C139/140 phones. In the case of C11x/123, adjust the length for the "main" +erase and program operations appropriately for the flash configuration in your +phone. + +Flashing newer firmware versions +================================ + +The flashing procedure given above, where the first 0x2000 bytes of the new fw +image (the bootloader part) are written with the flash erase-program-boot +command and the regular flash program-bin command writes everything from 0x2000 +onward, is only correct for older firmware versions whose bootloader portion is +completely free from the access locking malfeature: not only unlocked, but with +no provision for locking at all. In these older fw versions the boot code is +fully contained in the first 0x2000 bytes and nothing from 0x2000 onward affects +the ability to perform a new serial boot, hence the bricking vulnerability +window ends at 0x2000. However, this flashing procedure should NOT be used for +newer fw versions that have the provision for locking the bootloader - it's the +provision that matters in this case, even if the lock hasn't been activated - +if you flash one of these newer fw versions as above, you will risk bricking +your phone! + +If you need to flash one of the newer fw versions that includes the bootloader +lock provision, you need to take some additional precautionary steps: + +1. Examine the fw image you wish to flash with a hex dump viewer. Look starting + at offset 0x2000. You should see 3 identifying ASCII strings: one right at + 0x2000, another at 0x2020 and one more at 0x2040. Then look at 4 bytes at + offset 0x2060. If they contain 0xFFFFFFFF (blank flash) like the surrounding + unused bytes, then you have an older fw version without the bootloader lock + provision - you can safely flash it as in the previous section. If it's a + newer fw version with the bootloader lock provision, the word at 0x2060 will + contain either 0x00000000 or 0xDDDDDDDD, corresponding to the activated + (access disabled) and non-activated (access enabled) states of the lock, + respectively. + +2. If the fw image you wish to flash has 0x00000000 at 0x2060, you must patch + it to 0xDDDDDDDD with a hex editor before flashing. Just because our tfc139 + utility can recover phones with maliciously locked bootloaders does NOT mean + that you should *ever* deliberately flash such a bootloader-locked fw image + into your phone! Recovery of locked phones via tfc139 depends on the + complete fw image being present and working, not just the bootloader part, + hence if you were to flash an image that has a lockable bootloader with the + lock activated, the bricking vulnerability window will extend until the + *entire* fw image has been programmed - far too dangerous. + +3. When flashing the image with fc-loadtool, use a slightly different command + sequence compared to the previous section: + + flash erase-program-boot new-fw-image.bin 10000 + flash erase 10000 360000 + flash program-bin 10000 new-fw-image.bin 10000 360000 + +The difference is that the boundary between the part handled with flash +erase-program-boot and the part handled with flash program-bin has been moved +from 0x2000 to 0x10000. Because the word at 0x2060 is part of the bricking +vulnerability window with these newer fw versions, one should rewrite the +entire boot sector of the flash (including the beginning of the main fw image) +with flash erase-program-boot for safety. + +Unlocking while keeping the same fw version +=========================================== + +Suppose you have a phone with a locked bootloader such that you had to break in +with tfc139, you would like to unlock it so you can use RAM-based (non-flash) +tools such as c139explore or OsmocomBB with it, but you have no particular need +to change the main fw from the original version to a different one. If you +need to perform such a cisversion unlock, you can do it as follows: + +1. Break in with tfc139; +2. Use fc-loadtool's flash dump2bin command to save the first 64 KiB sector + of the flash to a file; +3. Using a hex editor, patch the word at 0x2060 from 0x00000000 to 0xDDDDDDDD; +4. Use fc-loadtool's flash erase-program-boot command to flash the patched + (unlocked) boot sector back into the phone. + +C155/156 differences +==================== + +C155/156 phones are nicer than the others in that they use a flash chip with a +"bottom boot" configuration. C11x/123 and C139/140 use "top boot" flash chips, +which is why the boot code and the first 56 KiB of the main fw image live in +the same erase block on those phones. The boot code and the control hand-off +interface between it and the main fw have also been revamped in C155/156 fw, +and the new structure is: + +8 KiB sector at 0: contains the boot code +7 more 8 KiB sectors starting at 0x2000: blank and unused +64 KiB sector at 0x10000: also blank and unused +64 KiB sector at 0x20000: beginning of main fw image + +With this new flash layout, it is now possible to erase and program the main fw +region starting at 0x20000 without ever erasing the boot code sector or doing +any writes to it, so there is no bricking vulnerability window at all. (The +phone can still be bricked though if one types the wrong command and erases the +boot sector inadvertently, so be careful.) + +So far the only phones in this family that I laid my hacking hands on have been +North American C156 units, all from the same seller and batch (hence identical), +so I don't know if there exist any maliciously-locked boot code versions in +this family - the boot code in my C156 is free of any malfeatures. But if "bad" +versions of C155/156 boot code do exist, and if you can break into the phone +somehow, you can use the flash erase-program-boot command to rewrite the boot +code with minimal risk of bricking just like on the other Compal families.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/Compiling Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,140 @@ +There are 3 parts to the complete FreeCalypso software suite which are built +independently of each other: + +* The tools that run on a GNU/Linux PC or other host system are the most + straightforward: there is a top level Makefile (named Makefile.hosttools if + you looking at a development source snapshot, will be renamed to just + Makefile in packaged releases of the host tools) that coordinates building + and installing all of them. + +* The gsm-fw tree, which will eventually become our main GSM firmware, needs to + be built with a GNU cross-compiler toolchain for ARM7. This firmware can be + built for several different target devices and with different feature + configurations, hence there is no singular build for it - it's more like the + Linux kernel in terms of its build configuration management. + +* We also have a few utilities which need to be compiled to run on Calypso + targets, but which are not part of gsm-fw; they are gathered in the + target-utils tree. They are built with the same GNU toolchain for ARM7 as + gsm-fw, but don't have any fancy configuration system. + +Building and installing FreeCalypso host tools +============================================== + +If you are working with a packaged FC host tools release, just run 'make', then +'make install' as root. If you are working with a development source snapshot, +do 'make -f Makefile.hosttools' instead. + +The "standard" install directories are /usr/local/bin for binaries and +/usr/local/share/freecalypso for helper files. If you need to change these +paths to something else, you'll need to edit a bunch of individual component +Makefiles, and possibly also some source files like loadtools/defpath.c - +sorry, FreeCalypso is not GNU and does not use autotools. + +All FreeCalypso host tools are written in plain C, and with the exception of a +few utilities in the "special-purpose hacks" category, they have absolutely no +library dependencies beyond libc. In other words, they are very friendly to +those who like bare bones minimalist systems. The only exceptions are +fc-getpirimei and fc-pirhackinit which use libcrypto from OpenSSL for DES +functions, and fc-lcdemu which needs libX11 to compile and an X11 display to +run. But as you can read in Host-tools-overview, these utilities are not +particularly important, so if your system lacks those libraries, just edit the +Makefiles to not build these utilities - it is very unlikely that you will miss +them. + +To those who are going to build distro packages from these fc-host-tools: it +is recommended that you leave fc-getpirimei, fc-pirhackinit and fc-lcdemu out +of the basic package - please don't create extra dependencies just to support a +few odd hacks which are unlikely to ever be used by anyone other than the +developer who needed them at one time and no longer even uses them herself as +their original one-time purpose has already been served. + +Building and installing the ARM7 toolchain +========================================== + +The current "official" GNU ARM toolchain for FreeCalypso consists of +binutils-2.21.1, gcc-4.5.4 and newlib-2.0.0 with a specific set of patches and +build configuration options. Build it as follows: + +1. Download these 3 source tarballs for the standard GNU+newlib components: + + binutils-2.21.1a.tar.bz2 + gcc-core-4.5.4.tar.bz2 + newlib-2.0.0.tar.gz + +2. Run the build+install.sh script in the toolchain directory. Read the + comments in the script first for the usage instructions. + +The toolchain thus built will need to be in your PATH before you can compile +gsm-fw or target-utils. + +Please note: the toolchain that is prescribed for FreeCalypso as above is +*believed* to be equivalent to the one used by OsmocomBB, but there are no +guarantees. Use any other toolchain at your own risk. + +Compiling target-utils +====================== + +Running 'make' in the target-utils tree with the ARM7 toolchain present in your +PATH will result in compalstage and loadagent being built; these are the two +components needed in order to use FreeCalypso loadtools. Run 'make install' to +install these target binaries in /usr/local/share/freecalypso, which is where +loadtools will look for them. + +Run 'make all' in target-utils to build some other components that aren't +really needed. + +Compiling FreeCalypso GSM firmware +================================== + +The firmware in our gsm-fw tree can be built in many different configurations, +hence there is no singular build for it. The configuration choices consist of: + +* Which target device the firmware should be built for: the target device + selection is made at compile time; do not attempt to take a firmware image + built for one target device and flash or fc-xram it into another! + +* What functionality is to be included. As the FreeCalypso firmware subproject + moves forward, we gradually add chunks of functionality, slowly approaching + what each target device is ultimately capable of. However, each time we add + a new piece of functionality, the ability to build a firmware image that works + like before, without the newly added functionality, still remains. Each + feature to be included needs to be explicitly selected. + +* Miscellaneous configuration: which Calypso UART should be used for what, + should the firmware use a real FFS (flash file system) in flash or a fake one + in RAM, etc. + +The GSM firmware build configuration is set by way of an editable text file +named build.conf; the configuration and build procedure is as follows: + +1. Look at the available repertoire of standard configurations under + gsm-fw/configs and choose which one you would like to use, either as-is or + as a basis for your own; + +2. Copy the configuration you selected to build.conf in the gsm-fw directory; + +3. Optionally edit it to taste - the configuration language is Bourne shell; + +4. Run 'make' in the gsm-fw directory. + +Depending on the configuration, either a flashable or a RAM-loadable image will +be built by default. A flashable image will appear in finlink/flashImage.bin; +these images are meant to be programmed with fc-loadtool's flash program-bin +command; the starting flash address at which the image needs to be programmed +depends on the target device - see target-specific notes. A RAM-loadable image +will appear in finlink/ramImage.srec; these images are meant to be loaded and +run with the fc-xram utility. + +It is possible to build either a flashable or a RAM-loadable image, or both, +without changing build.conf: run 'make flashImage' or 'make ramImage' as +desired. (The compilation of each module from source into a .o and all +intermediate linking steps are agnostic to whether a flashImage or a ramImage +is being built, only the very final link step differs.) Any otherwise working +configuration can be built into a flashImage, even if it makes no logical sense +to do so, but the ability to build a ramImage for a given configuration depends +on the code image size (which in turn depends on the selected feature set) and +the amount of RAM available on the target in question: most Calypso GSM devices +have small RAM, enough to satisfy a GSM firmware's data space requirements, but +not enough to hold the entire firmware code in RAM as well. Please see target- +specific notes for more details.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/High-speed-serial Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,111 @@ +The highest baud rate supported by "standard" PC serial ports is 115200 bps, +but Calypso UARTs can go quite a bit faster. Being clocked with 13 MHz (a +standard frequency in the GSM world), these UARTs can produce non-standard +(outside of the GSM world) baud rates of 203125, 406250 and 812500 bps. When +working with Motorola C1xx and Openmoko GTA01/02 phones which present a debug +and programming serial interface on a 2.5 mm headset jack, one can make use of +these high serial baud rates by using a USB to headset jack programming cable +based on one of the better USB-serial chips that can support these GSM special +baud rates well above 115200. The two USB-serial chips that are known to work +in this manner are CP2102 and FTDI, although each of the two requires its own +special quirks described below. Other USB to serial cables use chips which +don't support the high baud rates in question, and therefore are limited to +115200 baud max like a "standard" PC serial port. + +FreeCalypso tools can use these high serial baud rates in the following ways: + +* When you use fc-loadtool to dump and program GSM device flash memory + (flashing firmware images), the transfers get annoyingly slow at 115200 baud + if you have to do it a lot. Switching to 406250 or even better 812500 baud + makes them go considerably faster. + +* Some of our target devices have large enough RAM to execute a GSM firmware + image entirely from RAM without flashing - very handy for development and + experimentation. The tool used to run these RAM-based images is fc-xram, + and it also supports the option of using high serial baud rates for the image + transfer for the same reason: repeatedly transferring 1.5 MiB images over + 115200 baud gets tiresome. + +* If you are building your own GSM firmware (either FC GSM fw or one of our + TCS211-based hacks), you can make it run its RVTMUX interface at 406250 or + 812500 baud. We used this trick when we tried to make TCS211 with D-Sample- + targeting UI (176x220 pix LCD, 16 bits per pixel) send its virtual LCD raster + blits out the serial port. Our rvtdump and rvinterf utilities support this + mode of operation by providing options to select different baud rates. + +Using CP2102 adapters +===================== + +CP2102 chips have a built-in EEPROM that contains (among other things) a +32-entry table in which the supported serial baud rates are programmed. In +order to support the special GSM baud rates, these rates need to be added to +that table, displacing some other entries. The convention established by the +Pirelli DP-L10 phone (has a CP2102 built in and programmed at the factory for +GSM baud rates) is that 203120 baud takes the place of 230400, 406250 takes the +place of 460800, and 812500 takes the place of 921600. + +Because you need a special cable anyway to make the necessary physical +connection to the debug/programming serial port presented on a 2.5 mm headset +jack, you will probably be buying the requisite cable from a specialized +professional vendor. In that case it is that vendor's responsibility to sell +you the cable with the CP2102 chip already programmed with GSM baud rates: +because the physical construction of the cable (2.5 mm headset jack on the +serial end) makes it specific to GSM devices, and all known GSM devices use a +13 MHz clock or some integer multiple thereof, it is pointless for a +physically-GSM-specific cable to be set up for 230400/460800/921600 baud when +all known GSM devices will need 203125/406250/812500 baud instead. + +If you making a CP2102-based serial cable yourself (either for your own personal +use or professionally/commercially), please follow these instructions for baud +rate programming: + +http://bb.osmocom.org/trac/wiki/Hardware/CP210xTutorial + +If you follow the procedure given on that page, your CP2102 will be programmed +the same way as the one in the Pirelli DP-L10 (Foxconn's original factory +programming). + +The serial port handling code in FreeCalypso host tools is written to request +B230400 from termios when 203125 baud is desired, likewise B460800 for 406250 +baud and B921600 for 812500 baud. Therefore, if you have a CP2102-based cable +with properly programmed EEPROM, everything will Just Work. + +Using FTDI adapters +=================== + +Unlike CP2102, FTDI adapters don't require any non-volatile EEPROM programming +for GSM baud rates, but they have a different pain point - arguably a worse one +- that is entirely a software issue. The API which the Linux kernel provides +to userspace applications for opening and configuring serial ports provides no +clean, sensible way for an application to request a particular baud rate that +is not in the predefined-once-and-for-all list, and to make it unambiguous to +the in-kernel driver exactly what it wants. + +The method provided by the ftdi_sio driver in the standard Linux kernel is +gross, and I (Space Falcon) refuse to use it. The serial port handling code in +FreeCalypso host tools is written for the clean CP2102 way, and is *not* muddied +with the muck that would be necessary to get the high GSM baud rates with an +unpatched ftdi_sio driver. Therefore, if you would like to use one of the high +GSM baud rates with FreeCalypso with an FTDI adapter, you will need to dirty +your Linux host system with a hacky kernel patch. The patch provided in +linux-2.6.37.6-ftdi_sio.c.patch (made against Linux 2.6.37.6, which is what I +use - came with Slackware 13.37 - adapt as necessary for your kernel version) +makes the ftdi_sio driver behave like a GSM-programmed CP2102: termios B230400 +turns into 203125 baud, B460800 turns into 406250 and B921600 turns into 812500. + +This patch won't break other software (*cough* osmocom-bb *cough*) that does +use the "standard" ftdi_sio way of requesting high GSM baud rates, i.e., both +ways of selecting these baud rates should still work, but if you have other +(non-GSM) serial devices on the same system which need 230400, 460800 or 921600 +baud, those will break. + +Using adapters built into phones +================================ + +The Calypso chip has no native USB capabilities, thus if a Calypso phone +presents a USB charging+data port to the user, it must have a USB to serial +converter built in. The only phone we currently know of that does this is +Pirelli DP-L10, and its built-in USB-serial adapter chip is CP2102. It has +already been programmed with the correct GSM baud rates on Foxconn's original +production line, thus one can always use 812500 baud with FreeCalypso tools on +this phone and it will Just Work.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/Host-tools-overview Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,125 @@ +FreeCalypso host tools suite features the following tools that are potentially +useful to end users: + +fc-loadtool This is the tool used to read and write the non-volatile flash + memory of supported GSM devices. It can be used to reflash + these devices with new firmware (whether pre-existing or new + firmwares developed within our project), and to save and restore + flash backups. This tool operates on the target device (phone + or modem) while its regular firmware is shut down. + +fc-fsio This tool connects to GSM devices running one of the supported + firmware versions while the fw is running (unlike fc-loadtool + which operates on a device while its regular fw is shut down) + and allows you to manipulate (read and write) the device's + flash file system. It is thus a higher-level tool than + fc-loadtool. It is intended primarily for working with our own + firmwares, but it also works with Pirelli's original fw. + +fc-shell FreeCalypso firmwares have a feature of our own invention (not + present in any pre-existing ones) to accept AT commands over + the RVTMUX interface. It is useful when no second UART is + available for a dedicated standard AT command interface. + fc-shell is the tool that allows you to send AT commands to the + firmware in this manner; it also allows a few other kinds of + asynchronous commands to be sent. + +tfc139 This tool breaks into Mot C1xx phones via shellcode injection, + a method that works despite any bootloader locks, allowing you + to reflash locked phones with new firmware with fc-loadtool. + The name of the utility is historical: previously it was + specific to TFC139 phones (C139s sold with TracFone branding), + but the current version is expected to work with all Mot C1xx + firmware versions. + +imei-luhn A simple utility for computing or verifying the Luhn check + digit of an IMEI number. + +The following host tools are primarily for developers, but may be useful to +end users as well: + +rvtdump This tool produces a human-readable dump of all output emitted + by a TI-based GSM fw on the RVTMUX binary packet interface. It + can also log this dump to a file. + +rvinterf This tool is a superset of rvtdump: it not only dumps and/or + logs all output from the GSM fw, but also provides a mechanism + for sending command packets to it. Rvinterf is the engine + behind fc-fsio, fc-shell and fc-tmsh. + +tiffs, These tools perform "in vitro" analysis of flash file system +mokoffs, (FFS) images read out of GSM devices with TI-based firmwares. +pirffs You can list and extract the FFS content captured as a raw + flash image, and even perform a few "forensic" operations along + the lines of reading deleted files and seeing the history of + FFS modifications. tiffs is the main program, whereas mokoffs + and pirffs are convenience wrappers for the common FFS + configurations from Openmoko and Pirelli. + +fc-getpirimei This utility retrieves the factory-programmed IMEI of a Pirelli + DP-L10 phone by quering its running firmware over the RVTMUX + interface. + +fc-serterm This tool is a trivial serial terminal program. Its special + feature is that any output coming the serial port that isn't + printable ASCII is displayed as by cat -v. It is useful for + talking to serially-interfaced devices that mix ASCII with + binary in their serial talk. + +The following tools are really just for developers: + +ctracedec GSM firmwares built in TI's Windows environment (official ones + as well as our own hacks based on the TCS211 semi-src) have a + "compressed trace" misfeature whereby many of the ASCII strings + in debug trace messages get replaced with numeric indices at + build time, and these numeric indices are all that gets emitted + on the RVTMUX serial channel. This numeric trace output can be + turned back into ASCII strings if you have the str2ind.tab file + corresponding to the fw version that emitted the output in + question; this ctracedec utility performs that decoding. + +fc-iram, Reprogramming the non-volatile flash memory is not the only way +fc-xram, to run your own code on a Calypso GSM device. If your code is +fc-compalram small enough to fit entirely into the available RAM on the + device, and you would like to just run it without flashing it + permanently, these tools do the job of loading code images into + different kinds of RAM through different download protocols. + +fc-tmsh TI had a tool called TMSH that stood for "test mode shell". We + don't know exactly how it worked, hence we make no claim of our + own test mode shell being anything like TI's original, but we + do have a test mode shell of our own. It sends command packets + to the ETM (Enhanced Test Mode) component in the GSM firmware + and displays its responses in a purely asynchronous manner, + i.e., our tool has no knowledge of any correspondence between + the commands it sends and the responses they elicit. (In + contrast, fc-fsio described above also talks to ETM, but it + does so synchronously.) + +fc-olddump This tool captures a memory dump from a GSM device whose + firmware implements the old non-enhanced Test Mode memory read + command. It works with Mot C1xx original firmwares. + +fc-rgbconv A simple aid for phone UI development that converts RGB color + values between human-intuitive 8:8:8 format and the 5:6:5 format + used by the color LCDs in the phones targeted by FreeCalypso. + +The following tools are really just special-purpose hacks: + +fc-dspapidump This utility uses ETM in synchronous mode to read and dump the + contents of the DSP API RAM in a target Calypso GSM device + while the firmware is running. + +fc-lcdemu We have TI's TCS211 firmware semi-src that includes TI's + demo/prototype phone UI targeting the 176x220 pixel LCD on TI's + D-Sample development kit, but no suitable hardware on which we + could run this fw with this UI and see it in action. We built + a hacked-up version of the fw that emits all raster blits + intended for the big LCD on the RVTMUX serial interface, and + this fc-lcdemu utility is a plug-in for rvinterf that actually + displays these LCD blits in an X11 window. + +fc-pirhackinit This fc-pirhackinit utility is highly specific to the + TCS211-on-Pirelli exercise. DO NOT run it against Pirelli's + stock firmware, nor is it needed when using our full-source + FreeCalypso firmware.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/RVTMUX Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,236 @@ +TI's Calypso GSM/GPRS baseband processor chip has not one but two UART serial +ports, called "MODEM" and "IrDA" in the hardware documentation. In hardware +terms, both support basic data-leads-only UART operation at a fixed baud rate, +but their extended capabilities differ: the IrDA UART adds IrDA capability (no +surprise), whereas the MODEM UART adds hardware flow control and autobaud. If +one is not implementing an actual IrDA interface, then the so-called "IrDA" +UART becomes a strict subset of the MODEM one in terms of hw capabilities - +just an extra UART, but a somewhat less capable one. + +In a classic modem design such as that present in the GTA0x smartphones made by +FIC/Openmoko, the Calypso presents a standard AT command interface on its MODEM +UART port. (In the case of GTA0x phones this serial channel is wired to the +phone's application processor; in a standalone modem it would be wired to a +USB-serial chip or even to a classic RS-232 DB25 port.) However, what is less +known is that the standard firmware for such modems simultaneously presents an +entirely different interface on the IrDA UART - an interface intended for +development, debugging and factory production testing (which includes RF +calibration and IMEI etc programming), rather than for "normal" end users. + +Normally this debug/development serial interface (called RVTMUX as will be +explained momentarily) is hidden from "ordinary" users - for example, on FIC +GTA0x phones it is wired to the analog headset jack through a hardware switch +which needs to be enabled through a GPIO signal from the AP. On Mot C139 and +its siblings the situation is similar: one needs to key in the secret magic +sequence **16379#, and then the firmware presents a hidden menu for switching +the analog headset jack between its "normal" function and the UART carrying +RVTMUX. + +But there also exist some oddball devices on which the RVTMUX interface is +presented "in your face". The Pirelli DP-L10 phone has a USB charging port +which is also wired (through a CP2102 USB-serial chip) to the IrDA UART on the +Calypso - that's right, IrDA, not MODEM - a design decision with which this +hacker strongly disagrees. (It'll definitely be wired to the MODEM UART +instead on our own semi-clone of this phone, but I digress.) Apparently Foxconn +(the designers of this phone) had no desire to provide a standard AT command +interface, and instead the only "official" way to use the "data" function of +their USB port (rather than the charging function) is for their "PC sync" +feature, i.e., their proprietary Weendoze software. And guess what, their +proprietary "PC sync" feature works over TI's RVTMUX interface, as that is +what's presented on Calypso's IrDA UART behind the CP2102! + +OK, so what is this RVTMUX? RV stands for RiViera, an application framework +which TI added to their GSM firmware suite in the early 2000s, T stands for +trace, and MUX stands for multiplexor. It's a binary packet interface, although +many of these packets contain ASCII debug messages inside. The framing format +is the same in both directions: each packet begins and ends with an STX (0x02) +byte, all payload bytes except 0x02 and 0x10 are sent literally, and there is a +DLE (0x10) byte prepended before any 0x02 or 0x10 in the payload. It's the same +general principle as asynchronous HDLC (RFC 1662): packets can contain any +binary data, and the framing provides packet boundaries - although TI's version +is a little less robust than async-HDLC when it comes to recovering after lost +synchronization. + +The firmware suite component responsible for actually sending and receiving +these packets over the assigned UART port (usually IrDA, but can be MODEM too, +as on Compal phones for example) is called RVT (RiViera Trace), and it +implements a MUX function. There are several logical channels multiplexed over +one physical serial port, and the first byte of every packet indicates which +logical channel it belongs to. Any component within the GSM firmware suite can +send packets to RVT for transmission on this serial interface, and can also +register to receive packets beginning with a particular type ID byte. + +Debug trace output +================== + +All GSM device firmwares that are based on TI's Calypso chipset reference fw +continuously emit quite voluminous debug trace output on their RVTMUX serial +port, whether it is hidden or exposed on a given device. Like all RVTMUX +traffic, this debug trace output takes the form of binary packets as explained +above, but the content of these packets is mostly ASCII with some binary header +bytes prepended. FreeCalypso host utility rvtdump captures all serial output +from a GSM device's RVTMUX port, parses the packet structure and displays this +output in line-oriented pure ASCII with all binary parts decoded. + +Test Mode commands +================== + +The other major use of the RVTMUX interface is sending so-called Test Mode +commands from an external host to a running GSM device. Depending on the +firmware version, a GSM device can be commanded to do any of the following +things through this mechanism: + +* Exercise RF test modes, e.g., transmit continuously at a set frequency and + power level; +* Read and write arbitrary memory locations in the Calypso ARM7 address space; +* Read and write ABB chip registers; +* Reboot or power off; +* Access and manipulate the device's flash file system (FFS). + +In the segment of history of interest to us TI has produced two different +target firmware components that can receive, interpret and act upon Test Mode +command packets: + +* The original Test Mode component of Layer 1, called L1TM or TML1: this + component handles all RF test modes (needed for RF calibration on device + production lines), and originally it also implemented memory and ABB register + read and write commands, and provided access to TMFFS1 (see below). In the + original implementation this component registered itself as the handler for + the "TM" RVTMUX channel (RVT packet type 0x14), so it would receive all TM + packets sent to the device. + +* Enhanced Test Mode (ETM) is a later invention. It registers itself (instead + of the old TM in L1) with RVT as the handler for the "TM" RVTMUX channel, and + then provides a registration service of its own, such that various components + in the fw suite can register to receive external command packets passing + first through RVT, then through ETM, and can send responses passing through + ETM, then through RVT back to the external host. If a given fw version + contains both ETM and L1TM, then L1TM registers itself with ETM; an external + host would send exactly the same binary command packets to exercise RF test + modes, but inside the firmware they now pass through ETM on their way to L1TM. + +The ETM_CORE module contained within ETM itself provides some low-level debug +commands: by sending the right binary command packets to the GSM device via the +RVTMUX serial channel, an external host can examine or modify any memory +location and any hardware register, cause the device to reset, etc. Prior to +ETM some of these functions (but not all) could be exercised through older TM3 +commands, but in FreeCalypso we became familiar with the ETM versions of these +commands long before the older ones because we got the ETM component in full +source form, whereas our copy of TCS211 (TI's reference fw) has L1TM in a +binary library. + +Our TCS211/leo2moko reference fw has both ETM and L1TM, thus it accepts both +ETM and TM3 command packets. ETM commands (including TMFFS2, see below) work +on Pirelli's fw, but Mot/Compal's original fw for the C139 has only the +original non-enhanced Test Mode, not ETM. + +FFS access via TM/ETM +===================== + +One of the essential facilities provided in one form or another in all known +incarnations of the Test Mode mechanism is the ability to access and manipulate +the GSM device's flash file system (FFS). See TIFFS-Overview for a description +of this file system. TI's TMFFS1 and TMFFS2 protocols provide a command and +response packet interface to the FFS API functions inside the fw, and enable an +external host connected to the GSM device via the RVTMUX channel to perform +arbitrary read and write operations on the device file system. + +In the segment of history of interest to us TI has produced two different +and entirely incompatible versions of the TMFFS protocol: TMFFS1 and TMFFS2. +Or rather, what is now called TMFFS1 was originally just TMFFS, and then came +TMFFS2. TMFFS2 works only through ETM, whereas TMFFS1 predates ETM: in the +original implementation the tm_ffs() function in the FFS code was called from +L1TM code. + +Our copy of TCS211 reference fw includes the source for both TMFFS1 and TMFFS2; +it is theoretically possible to build a firmware image that includes both TMFFS +versions (they won't conflict because they respond to different command +packets), but it is pretty clear that TI never intended to have both enabled +at the same time. Our copy of TCS211 came with TMFFS1 enabled and we didn't +change it when we made the moko12 (leo2moko-r1) fw release for the Openmoko +community (the previous proprietary mokoN firmwares also implement TMFFS1), +but we have subsequently switched to TMFFS2 for our current TCS211-based work. + +Pirelli's fw implements TMFFS2: we don't have any source for this fw, but our +FreeCalypso host utilities written to talk the TMFFS2 protocol based on our +available TCS211 source work beautifully when run against Pirelli's fw. + +Use in FreeCalypso +================== + +The FreeCalypso project has adopted the same general firmware architecture as +that exhibited by TI's standard firmwares from the Moko/Pirelli time frame. We +use TI's RiViera framework lifted directly out of the TCS211 reference fw, and +that includes the RVT module and the RVTMUX interface it presents. Our GSM fw +emits the same 3 kinds of debug traces (RV, L1 and GPF) as the pre-existing +firmwares with which we are seeking functional parity, and for Test Mode +functionality we have the option of including ETM, TMFFS1 and/or TMFFS2 in our +firmware builds. (Both TMFFS versions require ETM in our implementation, and +it is possible to build a firmware image with both included.) + +We have adopted ETM and TMFFS2 as the standard combination for FreeCalypso, +i.e., ETM_CORE for memory and ABB register reads and writes and TMFFS2 for +external FFS access. We needed to develop our own host tools for operating on +GSM device FFS via one of the two TMFFS protocols, and after studying the fw +source implementing both, I (Space Falcon) came to the conclusion that TMFFS2 +is both more capable and more reliable; my guess is that TMFFS1 was likely kept +around only because some of TI's crappy Weendoze host software depended on it. +(See gsm-fw/services/ffs/tmffs.c if you would like to judge for yourself.) + +We have the following host tools for communicating with TI-based GSM firmwares +(both our own and some of the existing proprietary ones): + +rvtdump This tool produces a human-readable dump of all output emitted + by a TI-based GSM fw in the form of RVTMUX binary packets. It + can also log this dump to a file. + +rvinterf This tool is a superset of rvtdump: it not only dumps and/or + logs all output from the GSM fw, but also provides a mechanism + for sending command packets to it. + +Rvinterf is the engine behind the following host tools that send Test Mode +commands to a target: + +fc-tmsh This is our basic tool for sending Test Mode commands to a + running GSM fw. It is strictly asynchronous in that commands + entered by the operator get sent to the target, and any response + packets received from the target are displayed as they come in. + The tool has no knowledge of any correspondence between commands + being sent and whatever responses they should elicit, i.e., it + is perfectly suited for experimental discovery of firmware + behaviour in response to Test Mode commands. + + This tool was written before we realized that there was/is an + older, more basic Test Mode predating ETM, hence in many place + we say "ETM" when we really should have said "TM". Oh well... + +fc-fsio This tool speaks the TMFFS2 protocol and allows a user or + developer to perform a wide range of operations on the file + system of a GSM device. It operates synchronously, i.e., it + sends ETM/TMFFS2 commands and expects responses in strict + lock-step; a single user command may translate into a large + number of ETM/TMFFS2 command packet exchanges. + +AT commands over RVTMUX +======================= + +There is one more use to which we put the RVTMUX debug serial interface that is +an original FreeCalypso invention: communicating with the AT command interpreter +(ATI). TI's original architecture assumes that if a product is to offer a +standard AT command interface (the product is either a GSM/GPRS modem for which +this AT command interface is the sole mode of usage or a feature phone that +offers a data port as one of its features), then it will be presented on a +dedicated UART separate from RVTMUX. + +However, many of our target devices have only one UART practically accessible, +and even when we use Openmoko's modem as our development platform, the RVTMUX +interface is more convenient because it connects externally, whereas the MODEM +UART is connected to the application processor of the smartphone. Therefore, +we developed a way to pass AT commands over RVTMUX. We created a new RVTMUX +channel for this interface and assigned it RVT packet type 0x1A. Packets sent +from an external host to the GSM device carry AT commands and SMS string input, +whereas packets flowing the other way carry ATI's responses to commands and +asynchronous notifications such as incoming calls. + +The host utility for talking AT commands to a FreeCalypso GSM device via RVTMUX +is fc-shell; it works via rvinterf just like fc-fsio and fc-tmsh.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/TFC139-breakin Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,120 @@ +Maliciously locked bootloader +============================= + +When Compal (Motorola's ODM who designed and built their C1xx phones for them) +designed the firmware architecture and flash memory layout for their phones, +they made a bad design decision by putting the boundary between their bootloader +and the main fw image at 0x2000, even though the flash erase block boundary +doesn't come until 0x10000 - thus every time the main fw needs to be reflashed +to a different version, the dangerous boot sector has to be reflashed too. + +But then they made things even worse in the newer versions of their fw by +introducing a bootloader lock malfeature whereby the ability to interrupt boot +and load code serially may be artificially disabled. This malfeature is +implemented as follows: + +* In the original firmware layout (before the addition of the malfeature in + question) the boot code occupies the flash range from 0 through 0x1FFF, then + there are some ID strings at 0x2000, 0x2020 and 0x2040, and then the part of + the firmware that used to be at 0x10000 in TI's reference fw starts at 0x20A0, + with the entry point at 0x20F8 (corresponding to TI's 0x10058). + + With the addition of the bootloader lock malfeature the 32-bit word at 0x2060 + (previously unused and filled with 0xFFFFFFFF) became a control word telling + the bootloader whether diversion of the boot path to serial code download + should be allowed or not. + +* When firmware images with this malfeature present are first built, the word + at 0x2060 contains 0xDDDDDDDD. (Does D stand for debug or development, or + was the developer who implemented this malfeature fascinated by large bra + cups? We may never know.) This word MUST read as 0xDDDDDDDD in order for + the boot code to allow serial download: if it reads as any other value (e.g., + if it contains 0xFFFFFFFF because only the 8192 byte boot code has been + programmed into flash sector 0, with blank flash from 0x2000 onward), no + serial download opportunity will ever be offered and the phone is effectively + bricked! + +* For as long as the word at 0x2060 still contained 0xDDDDDDDD, Compal's + developers could continue gaining access through the bootloader and reflashing + their firmware. But when phones were to be shipped to customers with the + malicious bootloader lock activated, they probably sent some Test Mode command + (see RVTMUX write-up) to their running fw that caused it to write 0x00000000 + into the flash word at 0x2060. (Remember that any bit in a NOR flash memory + can be programmed from 1 to 0 at any time in any combination, but changing + bits from 0 back to 1 is only possible with full sector erasure.) + +* Once the word at 0x2060 has been programmed (in the flash memory sense) from + 0xDDDDDDDD down to 0x00000000, the phone is irreversibly locked and has lost + its ability to ever run a different firmware version, like a kamikaze pilot's + plane that has discarded its landing gear and can only crash now. + +Recovery procedure +================== + +While it probably was Compal's, Motorola's and various carriers' intent that the +bootloader lock on their phones be truly irreversible, the unlocking community +has now developed a method for recovering these phones (restoring their ability +to run any firmware of the user's choice) which (we hope) will work with all of +the existing locked-down firmware versions. It works as follows: + +* Even though the bootloader is locked down, if one boots the full fw regularly, + one can still access the RVTMUX interface which the TI-based fw implements + for debug trace and factory programming functions. One needs to key in the + magic sequence **16379# into the running fw, and a hidden menu will appear, + giving the operator the option to enable trace. Selecting this option will + cause the fw to switch the headset jack to the UART carrying RVTMUX. + +* Mot/Compal's firmware is based on a quite old version of TI's chipset + reference fw (relative to late TCS211 from the Openmoko/Pirelli era), and it + does not feature the Enhanced Test Mode (ETM) component with which we are + most familiar. However, it does implement the older set of non-enhanced + Test Mode commands, and these TM commands just happen to include raw memory + read and write operations at an arbitrary address. (For a while we were + under a mistaken belief that these commands were Compal's inventions, until + we discovered TI's original TM predating ETM.) + +* The ability to write arbitrary bytes into arbitrary RAM locations while the + phone firmware is running means that we can inject a piece of shellcode into + an unused RAM location and then cause this shellcode to gain execution by + overwriting a function return address on the stack. + +* Once you can execute your own code on the Calypso, everything becomes possible + once again. At that point one can trivially reverse the bootloader lock by + erasing flash sector 0 and rewriting it with 0xDDDDDDDD in the 0x2060 word, + or even better, rewriting this boot sector with an older version of the boot + code that lacks the locking malfeature altogether. + +Procedure variations: old mot931c.exe vs. new tfc139 +==================================================== + +We first became aware of the possibility of recovering locked-down phones as +described above in the spring of 2014 when FreeCalypso developer Space Falcon +became aware of the existence of Windows utility mot931c.exe (binary w/o source) +that performs a variant of this unlocking procedure specific to one particular +locked-down firmware version: C139 phones with TracFone branding, fw version +8.8.17. At first we had replicated the operation of this Windows tool verbatim +in our own Unix/Linux-based tfc139 libre tool; this variant of the shellcode- +based unlocking procedure worked well on TFC139 units, but could not crack other +locked-down fw versions, e.g., Cingular-branded C139 phones with fw version +1.9.24. + +Subsequent investigation revealed that whoever wrote that mot931c.exe Windows +tool had not studied the operation of Motorola/Compal's TI-based firmware deeply +enough, and implemented their shellcode injection quite suboptimally: the stack +smashing process is hitting the wrong stack (not the stack of the L1A task in +whose context the Test Mode commands sent over the UART are executing), and it +is only through dumb luck that this version of the break-in procedure worked +at all. The limitation of working only with one specific fw version results +from this poor method of shellcode injection (mindless choice of the wrong stack +for smashing), and instead of adapting it in a version-specific manner to other +particular locked-down fw versions at hand, I (Space Falcon) reimplemented our +tfc139 utility to smash the right stack (that of the L1A task), and thereby +made it generic to all Mot C1xx firmware versions. + +Our Compal firmware break-in utility is still called tfc139, but it is no longer +specific to TFC139 phones; instead it should work with all Mot C1xx firmwares. +The shellcode injected by tfc139 re-enables the Calypso chip's own boot ROM and +jumps to it; this boot ROM will endlessly wait for a serial download because +the word at 0x2000 contains neither 0 nor 1 (it is part of an identifying ASCII +string in Mot/Compal's fw), and the operator can then run fc-loadtool to +perform arbitrary flash operations.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/TIFFS-Overview Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,395 @@ +All TI GSM firmwares known to this author (FreeCalypso developer Space Falcon) +implement some kind of flash file system, or FFS. Several different FFS code +implementations, and correspondingly several different on-flash data formats, +have been used throughout the history of TI's involvement in the wireless +terminal business. The FFS incarnation of primary interest to the FreeCalypso +project is the one invented by Mads Meisner-Jensen at TI in the early 2000s +(at least according to the comments in the sources available to us), and it is +relevant to us in the following ways: + +* When targeting the GSM modem in Openmoko's GTA01/02 smartphones, we need to + work with the original FFS from the factory (call it MokoFFS), the same FFS + as used by the mokoN firmwares: this FFS contains the IMEI and the RF + calibration values from the factory, which we most certainly don't want to go + without. + +* The Leonardo firmware semi-src which we are using as the reference for + building our own full source, multi-target GSM fw contains a turnkey-working + implementation of this very FFS, using the on-flash format in question and + providing run-time APIs expected by the rest of the GSM fw suite. Following + the principle of ``if it ain't broke, don't fix it'', we can use this FFS not + only on the gtamodem target, but also on other targets, including those where + we would be starting from a blank state and thus have the freedom to use + whatever FFS we like. + +* The original proprietary fw on the Pirelli DP-L10 phone also happens to use + an FFS in the same format. Pirelli's FFS does *not* contain the IMEI or any + of the RF calibration values though, and trying to reuse it directly for our + own FC GSM fw seems to be more trouble than benefit - so we'll probably have + our fw start with a blank TIFFS instead - but there is still insight to be + gained from in-vitro examination of captured Pirelli FFS images. + +Naming +====== + +I have previously referred to the FFS format in question as Mokopir-FFS or +MPFFS, from "Moko" and "Pirelli". I was originally hesitant to call it TIFFS, +as lacking the source code, I had no way of knowing whether the FFS format and +implementation were of TI's own invention, or something that TI licensed as a +black box from one of their many proprietary software partners. (I was unable +to identify it as any well-known, industry-standard FFS format, but absence of +evidence is not evidence of absence.) But now that we have TI's original source +code which implements this FFS (first the MV100-0.1.rar source, then the full +Leonardo one), complete with comments and a HISTORY file, we know that our FFS +was invented and implemented by someone named Mads Meisner-Jensen at TI - I'm +guessing in the SSA group in Nice, France. + +I am now making a naming transition from MPFFS to TIFFS: there is really no +link between this FFS format and the Openmoko+Pirelli duo, other than the +happenstance of me having first encountered this FFS on these two GSM device +brands, and the name TIFFS is more neutrally-descriptive. + +What it is +========== + +In a rare departure from TI's norm (most of TI's GSM firmware and associated +development tools suffer from heavy Windows poisoning), what I call TIFFS is +very Unixy. It is a file system with a hierarchical directory tree structure +and with Unixy forward-slash-separated, case-sensitive pathnames; the semantics +of "what is a file" and "what is a directory" are exactly the same as in UNIX; +and TIFFS even supports symlinks, although that support is a little under- +developed, and apparently no FFS symlinks were ever used in any production GSM +device. Thus the FFS implemented in TI-based GSM devices (modems and +"dumbphones") is really no different from, for example, JFFS2 in embedded Linux +systems. + +(The only traditional UNIX file system features which are missing in TIFFS are + the creation/modification/access timestamps and the ownership/permission + fields.) + +The FFS in a GSM device typically stores two kinds of content: + +* Factory data: IMEI, RF calibration values, device make/model/revision + ID strings etc. These files are expected to be programmed on the factory + production line and not changed afterward. + +* Dynamic data written into the FFS in normal device operation: when you use a + "dumbphone" running TI-based firmware, every time you store something "on the + phone" or in "non-volatile memory", that item is actually stored in the FFS. + (Where else, if you think of it?) That includes contacts and received SMS + stored "on the phone" instead of the SIM, any selections you make in the + settings/preferences menus which persist across reboots (power cycles), call + history etc. + +It needs to be noted that the "dynamic data" aspect of FFS usage applies not +only to complete phones, but also to modems like the one used in the GTA01/02. +One would naively think that non-volatile storage of data in flash outside of +factory programming would be needed only in a device with its own UI, and that +a modem subservient to external AT commands would be completely stateless +across reboot/power cycles; but that is not the case in actuality. TI's GSM +firmwares, including the Openmoko ones (the "standard" mokoN), are designed to +always "mount" their FFS with read/write access; TI's FFS implementation in the +firmware has no concept of a "read-only mount". + +I am still investigating just what kinds of data are routinely written into the +non-volatile FFS by the firmware in normal operation on devices like the GTA0x +modem, but there most definitely are some. + +There is no hard separation between "static" and "dynamic" data in the file +system structure; TIFFS is thus akin to an embedded Linux system with just a +single root file system containing both "static" files like userland binaries +and "dynamic" ones like configuration files under /etc which the user is +expected to edit with vi after logging into the box, or log and similar files +created by the system itself under /var, for example. + +Where it lives +============== + +The type of flash memory used in Calypso GSM modems and "dumbphones" is called +NOR flash. This NOR flash memory is physically divided (by the design of the +flash chip itself) into units called "sectors" or more descriptively, erase +blocks. The typical NOR flash sector size (in Calypso GSM devices) ranges from +64 KiB in the GTA02 modem's NOR flash (4 MiB total) to 256 KiB in the +S71PL129NC0 flash+RAM chip used in the Pirelli DP-L10 (16 MiB of flash total). +The key physical property is that any bit may be changed from a '1' to a '0' at +any time, in any combination, but resetting of '0' bits back to ones can be +done only on the granularity of these largish sectors, in an operation called +"sector erase". + +The location of TIFFS within the flash memory of a given GSM device is defined +by the firmware design of that device, but is always some integral number of +contiguous flash sectors. Some examples: + +* On the GTA01/02 GSM modem, FFS occupies 7 sectors of 64 KiB each, starting at + flash offset 0x380000. + +* On the Pirelli DP-L10, the FFS used by the original proprietary fw occupies + 18 sectors of 256 KiB each (for 4.5 MiB in total), starting at the beginning + of the 2nd flash chip select (0x02000000 in the ARM7 address space). + +* On Motorola/Compal C139/140 phones, the FFS used by the original proprietary + fw occupies 5 sectors of 64 KiB each (320 KiB in total), starting at 0x370000. + C11x/123 use smaller FFS configurations, whereas C155/156 seem to have + switched to some other FFS format, different from our familiar TIFFS. + +* The smallest real FFS configuration called for by the table in dev.c in TI's + original Leonardo fw source is 3 sectors of 64 KiB each; the same table also + sports a 4 KiB x 4 configuration for RAM-based testing (emulation of FFS in + RAM without real flash). + +* The largest FFS configuration that has been envisioned by the original + designers seems to be somewhere around 128 sectors. + +Each flash sector used for TIFFS begins with this 6-byte signature: + +46 66 73 23 10 02 + +The first 4 bytes are 'Ffs#' in ASCII, and the following two bytes are the +format version number of 0x0210 in little-endian byte order. The following two +bytes give a count of how many times that sector has been erased and rewritten +(FF FF in "fresh" or "virgin" FFS images), and the following byte indicates +that block's role and status in the FFS life cycle. + +How it works +============ + +Just like JFFS2 and other high-quality flash file systems, TIFFS is designed to +recover gracefully from any possible power failure or crash: one can yank the +battery from the GSM device (or induce a firmware crash) at the most mis- +opportune moment in the middle of an FFS write operation, and the FFS is +expected to recover on the next boot cycle. I won't be able to document here +all gory details of exactly how this goal is achieved, partly because I haven't +studied the code to the requisite level of depth myself yet, but all of the +responsible code lives under gsm-fw/services/ffs in this freecalypso-sw source +tree; feel free to study it. + +In its "normal" or "clean" state (i.e., when not in the middle of a write +operation or recovery from an ungracefully interrupted one), a TIFFS instance +consists of the following 3 types of blocks: + +* One block containing inode records, indicated by AB in its type/flags/status + byte in the block header; +* N-2 blocks (where N is the total number of flash sectors allocated for the + FFS) containing (or waiting to be filled with) data chunks - indicated by BD + in the type/flags/status byte; +* One "free" block, indicated by BF - destined to become a new AB or a new BD + at some point. + +Each object written into the FFS (file, directory or symlink) consists of a +16-byte inode record written into the AB block and a data chunk written into +one of the BD blocks. The data chunk includes the name of the object, hence +one is required even for directories. Data chunks are contiguous, uncompressed, +and subject to an upper size limit of 2048 or 8192 bytes, depending on the FFS +configuration. Files larger than this limit are stored in a "segmented" form, +giving rise to a 4th inode or object type (after file, directory and symlink): +segment. Each segment of a segmented file consists of not only a data chunk, +but also an inode record for the segment, which gives the location of the data +chunk and ties the segment object into the overall FFS structure, making it +accessible. + +Because aside from complete sector erasure, flash memory bits can only +transition from '1' to '0' but not the other way around, overwriting an existing +file with some new content (an operation which any reasonable file system must +implement in some way) cannot be done in place. Instead like most flash file +systems, TIFFS implements this common operation by writing the new version of +the file to a new location (previously blank flash) and then invalidating the +old version - and doing all that while keeping in mind the possibility of an +ungraceful crash or powerdown at any moment, and the requirement of recovering +gracefully from any such event. + +Of course as an FFS receives more write activity, even if one keeps overwriting +some existing files with new content of the same size, without adding to the +visible total content size (think du(1) command), eventually all remaining blank +flash space will fill up. At that point (or at some earlier point, depending +on the FFS design and/or configuration) the FFS has to invoke a compaction or +reclamation or garbage collection procedure: any "mixed" blocks containing both +valid and stale data are transitioned into a "stale-only" state by having the +active data moved to a new block, and then the "all stale" blocks are subjected +to sector erasure, becoming new blank sectors. The logic responsible for these +operations once again needs to be resilient to the possibility of a crash or +powerdown occurring at the most mis-opportune moment, and it also needs to +implement flash wear leveling: there is a physical limit to how many times a +given flash sector can be erased and rewritten before it goes bad. + +All of the above are common and well-known principles, successfully implemented +in well-known flash file systems such as JFFS2 in Linux. TIFFS is absolutely +no different in this regard; for the implementation details, read the source +code. + +How this FFS comes into being +============================= + +(This section is only relevant to you if you plan on physically producing your + own GSM phones or modems on your own factory production line, like this author + fancies doing in the not-too-distant future, or if you simply enjoy knowing + how it is done.) + +To my knowledge, TI never used or produced a tool akin to mkfs.jffs2 in the +embedded Linux world, which would produce a TIFFS image complete with some +initial directory and file content "in vitro". Instead it appears that the FFS +instances found in shipped products such as Openmoko phones have been created +"in vivo" by TI's firmware running on the device itself during the "production +test" phase. + +The process seems to go like this: + +* When the printed circuit board is physically populated with components such + as the Calypso chip and the flash chip, the latter can be blank - if the + board design has the nIBOOT pin pulled low, enabling the Calypso boot ROM + (Openmoko and Pirelli both good on this one, but shame on Compal!), there is + no need to preprogram the flash chip with anything prior to populating it on + the board, and the device remains fully unbrickable at all times afterward. + +* When the assembled board is powered up for the first time, with completely + blank flash, the Calypso boot ROM will sit there and patiently wait for a + code download on either of its two UARTs. + +* Using TI's FLUID (Flash Loader Utility Independent of Device) or FreeCalypso's + fc-loadtool free replacement, the factory production station loads the main + firmware image into the flash. Note, it is just the firmware image at this + step, and the FFS sectors remain blank. + +* The board is commanded to reboot (or power-cycled), and the firmware image + boots for the first time. + +* TI's FFS implementation code in their standard firmware reacts to all blank + flash in the FFS sectors as follows: it performs what they call the preformat + operation, writing the TIFFS signature and a BF state byte into every FFS + sector, but the main "format" operation, which sets up the AB/BD block roles, + creates the root inode and makes the FFS ready to accept the creation of its + first directories and files, is not done automatically. + +In order to perform the FFS format operation and then fill the new FFS with +whatever directories and files are deemed needed to be present in "fresh" +shipping products, the factory production station connects to the just-booted +firmware running on the target via the RVT/ETM protocol (see the RVTMUX +write-up), and sends "test mode" commands to this running firmware. These +"FFS test mode" (or TMFFS) commands include the format operation, an mkdir +operation to create directories, and a "file write" operation akin to doing +'cat > /dir/whatever/file', creating files in FFS and storing any desired data +in them. + +The IMEI is assigned and written into FFS in this process, but it is not the +only data item that will be unique for each individual device made. Much more +important are the RF calibration values: I have yet to learn exactly what is +being (or needs to be) measured, how these measurements are performed (under +what conditions; what external test equipment is needed), and how these measured +and recorded RF calibration values affect GSM device operation, but this TI +presentation gives some clues: + +ftp://ftp.ifctf.org/pub/GSM/Calypso/rf_calibration.pdf + +All of these calibration values are stored in a bunch of files under the +/gsm/rf subtree, and these files seem to be "owned" by the L1 code. The latter +has RAM data structures which correspond to these files; upon normal boot the +initialization code looks in FFS, and if it finds any of the RF calibration +files, it reads each present file into the corresponding RAM data structure, +overwriting the compiled-in defaults. It appears (slightly uncertain because I +have not yet reintegrated the code in question into our own gsm-fw) that the RF +calibration files in FFS come into being as follows: + +* The RF calibration code in L1 (i.e., part of the main GSM fw) performs the + measurements and stores results in its RAM data structures as commanded by + the production test station through the "test mode" interface; + +* A final test mode command directs the above L1 code to write its RAM data + structures into FFS. + +Once I actually learn this RF calibration process properly in connection with +building my own Calypso-based GSM "dumbphone", I'll be able to say exactly what +it would take to recreate these RF calibration values if they are lost. But +until then the only advice I can give is to make a backup copy of your modem +FFS with fc-loadtool, and to save it securely. + +Compal and Pirelli differences +============================== + +The above description refers to TI's vanilla reference version, and it seems +like Openmoko (FIC) was the only phone/modem manufacturer who followed it +without major deviations. In contrast, both Compal (Mot C1xx) and Foxconn +(Pirelli DP-L10) moved the vital per-unit factory data (IMEI and RF calibration) +out of the FFS into their own ad hoc flash data structures (which are very +difficult to reverse-engineer and make use of, unfortunately), leaving their FFS +only for less critical data. + +In Compal's case (at least on the C139 model with which I have extensive +personal experience) the FFS stores only users' personal information and nothing +more. One can turn the phone off, use fc-loadtool to erase the FFS sectors, and +boot the regular fw back up; the fw will automatically do a new FFS format (it +even displays a message on the LCD as it does so) and carry on happily as a +"fresh" or "blank", perfectly functional and usable phone. + +In Pirelli's case, booting their official fw with blank FFS sectors will also +result in the FFS being automatically formatted, but their fw expects some +static "asset" files to be present in this FFS: UI graphics and language +strings, ringtones, firmware images for the WiFi and VoIP processors and some +static configuration files, about 3 MiB in total. Thus although the firmware +will auto-format the blank FFS sectors, it won't function normally with all of +these "asset" files missing. Foxconn's original factory production line station +must have uploaded these files to each phone via the TMFFS2 protocol, and our +FreeCalypso suite now features a tool that can replicate this feat: fc-fsio. + +FreeCalypso support for TIFFS +============================= + +Aside from implementing and using it in our own gsm-fw, FreeCalypso offers +the following support for TIFFS: + +1. We have a utility for "in vitro" examination of FFS images read out of GSM + devices with fc-loadtool. This tiffs utility (along with mokoffs and pirffs + wrappers) lives in the ffstools top-level directory of the freecalypso-sw + source tree. This TIFFS "in vitro analyzer" utility supplants the earlier + mpffs-* tools, and adds some additional examination functionality. It is + strictly a "read only" tool, however - it is not designed for "in vitro" + editing of TIFFS images. + +2. A number of FC tools may be strung together into a kit for editing the FFS + content of a GSM device, e.g., for changing the IMEI. The following pieces + will be involved: + +* What is destined to eventually become our totally free GSM fw (the gsm-fw + source subtree at the top of freecalypso-sw) does not contain any of the + actual GSM protocol stack (or even L1) functionality yet, but it already + contains both the FFS code and those components (ETM and TMFFS[12]) which + are needed for interfacing an external "test mode shell" to this FFS + implementation through the RVTMUX interface. And when our gsm-fw does gain + the actual GSM functionality, the ability to build a minimal FFS+ETM-only + configuration will still be retained. + +* The minimal FFS+ETM subset of gsm-fw can be built into a ramImage (runs + entirely from RAM via fc-xram, no flashing), and run on a physical device + such as the GTA0x GSM modem via the fc-xram host utility; + +* After loading the ramImage, fc-xram will immediately exec our rvinterf host + utility (see rvinterf/README); + +* Once the GSM device is running what is effectively an FFS editing agent out + of RAM, accessed via rvinterf over the serial channel, the user can run + fc-tmsh or fc-fsio, and this "test mode shell" provides commands for writing + things to FFS exactly like one would do in the factory production line + environment for which TI taylored their tools. + +The "in vivo" method of editing the FFS content of a GSM device described above +will probably sound very convoluted, and you may find yourself asking for a way +to do it "in vitro" instead: read the FFS out of flash with fc-loadtool, edit +that image "in vitro" with some utility on your PC, and then use fc-loadtool +again to program it back into your device. But consider that an "in vitro" FFS +modification would involve erasing and rewriting all sectors of your FFS, +whereas an "in vivo" modification of some small file like the IMEI would be +just a short flash write operation without any erasures at all, i.e., kinder +on the flash. + +In any case, the "in vivo" method is already available now because all of the +components involved therein are also needed for other development uses in the +FreeCalypso project, whereas developing a fully-functional "in vitro" +alternative (one that can create an FFS image "de novo" from a tree of files +and directories a la mkfs.jffs2, or add new files to an existing TIFFS image +etc) would be a good amount of extra work which we otherwise don't need - hence +the latter is not very likely to be written any time soon. + +However, if the "in vitro" modification you seek is something trivial like +changing the byte content of a file such as /pcm/IMEI or /gsm/com/rfcap without +changing its length, you can use the existing "in vitro, read-only" tiffs host +utility to find the exact byte location of the file data within the TIFFS image, +and then use your favourite hex editor to whack whatever new byte content you +like at that offset.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/TIFFS-old-description Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,461 @@ +The description of TIFFS that follows was originally written in the summer of +SE52 (A.D. 2013), before the major TI source discoveries which happened later +that year. The text following the dividing line below has not been edited in +content since it was written; for a newer write-up based on the current source- +enabled understanding and reflecting the current FreeCalypso plans with respect +to this FFS, see TIFFS-Overview. + +------------------------------------------------------------------------------- + +This is a description, based on reverse engineering, of the flash file system +(FFS) implemented in Pirelli's original firmware for the DP-L10 GSM/WiFi dual +mode mobile phone, and in the Closedmoko GTA0x modem firmware. Not knowing the +"proper" name for this FFS, and needing _some_ identifier to refer to it, I +have named it Mokopir-FFS, from "Moko" and "Pirelli" - sometimes abbreviated +further to MPFFS. + +(I have previously called the FFS in question MysteryFFS; but now that I've + successfully reverse-engineered it, it isn't as much of a mystery any more :-) + +At a high functional level, Mokopir-FFS presents the following features: + +* Has a directory tree structure like UNIX file systems; + +* The file system API that must be implemented inside the proprietary firmware + appears to use UNIX-style pathnames; doing strings on firmware images reveals + pathname strings like these: + + /var/dbg/dar + /gsm/l3/rr_white_list + /gsm/l3/rr_medium_rxlev_thr + /gsm/l3/rr_upper_rxlev_thr + /gsm/l3/shield + + Parsing the corresponding FFS image with tools included in the present + package has confirmed that the directory structure implied by these pathnames + does indeed exist in the FFS. + +* Absolutely no DOS-ish semantics seen anywhere: no 8.3 filenames and no + colon-separated device names (seen in the TSM30 file system source, for + example) are visible in the Closedmoko/Pirelli FFS. + +* File contents are stored uncompressed, but not necessarily contiguous: one + could probably store a file in FFS which is bigger than the flash sector + size, it which case it can never be contiguous in a writable FFS (see below), + and the firmware implementation seems to limit chunk sizes to a fairly small + number: on the Pirelli phones all largish files are divided into chunks of + 8 KiB each, and on my GTA02 the largest observed chunk size is only 2 KiB. + + The smaller files, like the IMEI and the firmware ID strings in my GTA02 FFS, + are contiguous. + +* The FFS structure is such that the length of "user" payload data stored in + each chunk (and consequently, in each file) can be known exactly in bytes, + with the files/chunks able to contain arbitrary binary data. (This property + may seem obvious or trivial, as all familiar UNIX and DOS file systems have + it, but contrast with RT-11 for example.) + +* The flash file system is a writable one: the running firmware can create, + delete and overwrite files (and possibly directories too) in the live FFS; + thus the FFS design is such that allows these operations to be performed + within the physical constraints of NOR flash write operations. + +I have reverse-engineered this Mokopir-FFS on a read-only level. What it means +is that I, or anyone else who can read this document and the accompanying +source for the listing/extraction utilities, can take a Mokopir-FFS image read +out of a device and see/extract its full content: the complete directory tree +and the exact binary byte content of all files contained therein. + +However, the knowledge possessed by the present hacker (and conveyed in this +document and the accompanying source code) is NOT sufficient for constructing a +valid Mokopir-FFS image "in vitro" given a tree of directories and files, or +for making modifications to the file or directory content of an existing image +and producing a content-modified image that is also valid; valid as in suitable +for the original proprietary firmware to make its normal read and write +operations without noticing anything amiss. + +Constructing "de novo" Mokopir-FFS images or modifying existing images in such +a way that they remain 100% valid for all read and write operations of the +original proprietary firmware would, at the very minimum, require an +understanding of the meaning of *all* fields of the on-media FFS format. Some +of these fields are still left as "non-understood" for now though: a read-only +implementation can get away with simply ignoring them, but a writer/generator +would have to put *something* in those fields. + +As you read the "read-only" description of the Mokopir-FFS on-media format in +the remainder of this document, it should become fairly obvious which pieces +are missing before our understanding of this FFS can be elevated to a +"writable" level. + +However, when it comes to writing new code to run on the two Calypso phones in +question (Closedmoko and Pirelli), it seems, at least to the present hacker, +that a read-only understanding of Mokopir-FFS should be sufficient: + +* In the case of Closedmoko GTA0x modems, the FFS is seen to contain the IMEI + and the RF calibration data. The format of the former is obvious; the latter + not so much - but in any case, the information of interest is clearly of a + read-only nature. It's difficult to tell (or rather, I haven't bothered to + experiment enough) whether the Closedmoko firmware does any writes to FFS or + if the FFS is treated as read-only outside of the production line environment, + but in any case, it seems to me that for any 3rd party replacement firmware, + the best strategy would be to treat the FFS as a read-only source of IMEI and + RF calibration data, and nothing more. + +* In the case of Pirelli phones, the FFS is used to store user data: sent and + received SMS (and MMS/email/whatever), call history, UI settings, pictures + taken with the camera, and whatever else. It also stores a ton of files + which I can only presume were meant to be immutable except at the time of + firmware updates: graphics for the UI, ringtones, i18n UI strings, and even + "helper" firmware images for the WiFi and VoIP processors. However, no IMEI + or RF calibration data are anywhere to be found in the FFS - instead this + information appears to be stored in the "factory block" at the end of the + flash (in its own sector) outside of the FFS. + + Being able to parse FFS images extracted out of Pirelli phones "in vitro" + allows us to steal some of these helper files (UI artwork, ringtones, + WiFi/VoIP helpers), and some of these might even come useful to firmware + replacement projects, but it seems to me that a replacement firmware would + be better off using its own FFS design for storing user data, and as to + retrieving the original IMEI and RF calibration data, the original FFS isn't + of any use for that anyway. + +======================= +Moko/Pirelli FFS format +======================= + +OK, now that I'm done with the introduction, we can get to the actual +Mokopir-FFS format. + +* On the GTA0x modem (or at least on my GTA02; my sample size is 1) the FFS + occupies 7 flash sectors of 64 KiB each at offsets 0x380000 through 0x3E0000, + inclusive. + +(The 4 MiB NOR flash chip used by Closedmoko has an independent R/W bank + division between the first 3 MiB and the last 1 MiB. The first 3 MiB are used + to hold the field-flashable closed firmware images distributed as *.m0 files; + the independent last megabyte holds the FFS, and thus the FW could be + implemented to do FFS writes while running from flash in the main bank. + Less than half of that last megabyte appears to be used for the FFS though; + the rest appears to be unused - blank flash observed.) + +* On the Pirelli the FFS occupies 18 sectors of 256 KiB each at offsets 0 + through 0x440000 (inclusive) of the 2nd flash chip select, the one wired to + nCS3 on the Calypso. + +Each flash sector allocated to FFS begins with the following signature: + +00000000: 46 66 73 23 10 02 xx yy zz FF FF FF FF FF FF FF Ffs#............ + +The bytes shown as xx and yy above serve a non-understood purpose; as a guess, +they may hold some info for the flash wear leveling algorithm: in a "virgin" +FFS image like that found in my GTA02 (which never had a SIM card in it and +never made or received a call) or read out of a "virgin" Pirelli phone that +hasn't seen any active use yet, both of these bytes are FFs, but when I look at +FFS images read out of the Pirelli which I currently use as my everyday-use +cellphone, I see other values in sectors which must have been erased and +rewritten. A read-only implementation can ignore these bytes, as mine does. + +The byte shown as zz is more important though, even to a read-only +implementation. The 3 values I've encountered in this byte so far are AB, BD +and BF. Per my current understanding, in a "healthy" FFS exactly one sector +will have AB in its header, exactly one will have BF, and the rest will have +BD. The meanings are (or appear to be): + +AB: the sector holds a vital data structure which I have called the active + index block; +BD: the sector holds regular data; +BF: the sector is blank except for the header, can be turned into a new AB or + BD. + +(Note that a flash program operation, which can turn 1s into 0s but not the + other way around, can turn BF into either AB or BD - but neither AB nor BD can + be turned into any other valid value.) + +In a "virgin" FFS image (as explained above) the first FFS sector is AB, the +last one is BF, and the ones in between are BDs. + +An FFS read operation (a search for a given pathname, or a listing of all +present directories and files) needs to start with locating the active index +block - the FFS sector with AB in the header. Following this header, which is +treated as being 16 bytes long (almost everything in Mokopir-FFS is aligned on +16-byte boundaries), the active index block contains a linear array of 16-byte +records, each record describing an FFS object: directory, file or file +continuation chunk. + +Here is my current understanding of the 16-byte index block record structure: + +2 bytes: Length of the described chunk in bytes +1 byte: Purpose/meaning not understood, ignored by my current code +1 byte: Object type +2 bytes: Descendant pointer +2 bytes: Sibling pointer +4 bytes: Data pointer +4 bytes: Purpose/meaning not understood, ignored by my current code + +(On the Calypso phones of interest, all multibyte fields are in the native + little-endian byte order of the ARM7TDMI processor.) + +The active index block gets filled with these records as objects are created; +the first record goes right after the 'Ffs#'...AB header (padded to 16 bytes); +the last record (at any given moment) is followed by blank flash for the +remainder of the sector. Records thus appear in the order in which they are +created, which bears no direct relation to the directory tree structure. + +The objects, each described by a record in the index block, are organized into +a tree structure by the descendant and sibling pointers, plus the object type +indicator byte. Let's start with the latter; the following objtype byte values +have been observed: + +00: deleted object - a read-only implementation should ignore everything except + the descendant and sibling pointers. (A write-capable implementation would + need more care - it would need a way of reclaiming dirty flash space taken + up by deleted/overwritten files.) + +E1: a special file - see the description of the /.journal file further down +F1: a regular file (head chunk thereof) +F2: a directory +F4: file continuation chunk (explained below) + +Each record in the index block has an associated chunk in one of the data +sectors; the index record contains fields giving the address and length of this +chunk. The length of a chunk is always a nonzero multiple of 16 bytes, and is +stored (as a number in bytes) in the first 16-bit field of the 16-byte index +entry. The address of each chunk is given by the data pointer field of the +index record, and it is reckoned in 16-byte units (thereby 16-byte alignment is +required) from the beginning of the FFS sector group in the flash address space. + +For objects of type F1 and F2 (regular files and directories) the just-described +chunk begins with the name of the file or subdirectory as a NUL-terminated ASCII +string. This name is just for the current level of the directory tree, just +like in UNIX directories, thus one will have chunk names like gsm, l3, eplmn +etc, rather than /gsm/l3/eplmn. One practical effect is that one can't readily +see pathnames or any of the directory structure by looking at an FFS image as a +raw hex dump; the structure is only revealed when one uses a parsing program +like those which accompany this document. + +In the case of directories, the "chunk" part of the object contains only the +name of the directory itself, padded with FFs to a 16-byte boundary. For +example, an FFS directory named /gsm would be represented by an object +consisting of two flash writes: a 16-byte entry in the active index block, with +the object type byte set to F2, and a corresponding 16-byte chunk in one of the +data sectors, with the 16 bytes containing "gsm", a terminating NUL byte, and +12 FF bytes to pad up to 16. In the case of files, this name may be followed +by the first chunk of file data content, as explained further down. + +In order to parse the FFS directory tree (whether the objective is to dump the +whole thing recursively or to find a specific file given a pathname), one needs +to first (well, after finding the active AB block) find the root directory node. +The root directory object is similar to other directory objects: it has a type +of F2, and an associated chunk of 16 bytes in one of the data sectors. The +latter contains the name of the root node: on the Pirelli it is "/", whereas on +my GTA02 it is "/ffs-root". + +The astute reader should notice that it really makes no sense to store a name +for the root node, and indeed, this name plays no part in the traversal of the +directory tree given an absolute pathname. But instead this name, or rather +its first character, appears to be used for the purpose of locating the root +node itself. At first I had assumed that the index record for the root node is +always the first record in the active index block right after the signature +header - that is how it is in "virgin" FFS images, and also in some quite non- +virgin ones I have pulled from my daily-use Pirelli. Naturally my first version +of the Mokopir-FFS (then called MysteryFFS) extraction utility expected the root +node to always be at index #1. But then I got some additional Pirelli phones, +and discovered that in certain cases, index record #1 is a deleted object (the +original root node which has been deleted), and the new active root node is +somewhere in the middle of the index! + +Thus it appears that in order to find the active root node, one needs to scan +the active index block linearly from the beginning (disregarding the tree +structure pointers in this initial pass), looking for a non-deleted object of +type F2 (a directory) whose corresponding name chunk sports a name beginning +with the '/' character. (Anyone who's been raised in UNIX will immediately +know that the path separator character '/' is the only character other than NUL +that's absolutely forbidden in the individual filenames - so this special +"root node name" is the only case of a '/' character appearing in what would +otherwise be a regular filename.) + +[What causes the root node to be somewhere other than at index #1? I assume it + has to do with the dirty space reclamation / data movement algorithm. In a + "virgin" FFS image the very first sector is the active index block, and the + following sector is the first to hold chunks, beginning with the name chunk of + the root node. Now what happens if all data in that sector aside from the + root node name and some other mostly-static directory names becomes dirty, + i.e., belonging to deleted or overwritten files? How would that flash space + get reclaimed? I assume that the FFS firmware algorithm moves all still-active + chunks to a new flash sector, invalidating the old copies - turning the latter + into deleted objects. The root node will be among them. Then at some point + the active index block is going to fill up too, and will need to be rewritten + into a new sector - at which point the previously-deleted index entries are + omitted and the root node becomes #1 again...] + +Tree structure + +Once the root node has been found, the descendant and sibling pointers are used +to traverse the tree structure. For each directory object, including the root +node, the descendant pointer points to the first child object of this directory: +the first file or subdirectory contained therein. (Descendant and sibling +pointers take the form of index numbers in the active index block. A "nil" +pointer is indicated by all 1s (FFFF) - the usual all-0s NULL pointer convention +couldn't be used because it's flash, where the blank state is all 1s.) If the +descendant pointer of a directory object is nil, that means an empty directory. +The sibling pointer of each file or directory points to its next sibling, i.e., +the next member of the same parent directory. The sibling pointer of the root +node is nil. + +Data content of files + +Objects of type F1 are the head chunks of files. Each file has a head chunk, +and may or may not have continuation chunks. More precisely, the head chunk +may contain only the name (or viewed alternatively, 0 bytes of data), or it may +contain a nonzero number of payload bytes; orthogonally to this variability, +there may or may not be continuation chunk(s) present. + +Continuation chunks + +The descendant pointer of each file head object (the object of type F1, the one +reached by traversing the directory tree) indicates whether or not there are +any continuation chunks present. If this descendant pointer is nil, there are +no continuation chunks; otherwise it points to the first continuation chunk +object. File continuation objects have type F4, don't have any siblings (the +sibling pointer is nil - but see below regarding relocated chunks), and the +descendant pointer of each continuation object points to the next continuation +object, if there is one - nil otherwise. + +Payload data delineation + +Each chunk, whether head or continuation, always has a length that is a nonzero +multiple of 16 bytes. The length of the chunk here means the amount of flash +space it occupies in its data sector - which is NOT equal to the payload data +length. + +The head chunk of each file begins with the filename, terminated by a NUL byte. +If there are any payload data bytes present in this head chunk (I'll explain +momentarily how you would tell), the byte immediately after the NUL that +terminates the filename is the first byte of the payload. In the case of a +continuation chunk, there is no filename and the first byte of the chunk is the +first byte of that chunk's portion of the user data payload. + +Each data-containing chunk (head or continuation) has the following termination +after the last byte of that chunk's payload data: one byte of 00, followed by +however many bytes are needed ([0,15] range) of FFs to pad to a 16-byte +boundary. A file head chunk that has no payload data has the same format as a +directory name chunk: filename followed by its terminating NUL followed by +[0,15] bytes of FFs to pad to the next 16-byte boundary. + +When working with a head chunk, find the beginning of possible payload data (1 +byte after the filename terminating NUL) and find the end per the standard +termination logic: scanning from the end of the chunk, skip FFs until 00 is +found (encountering anything else is an error). If the head chunk has no data, +the effective data length (end_pointer - start_pointer) will be 0 or -1. (The +latter possibility is the most likely, as there will normally be a "shared" 00 +byte, serving as both the filename terminator and the 00 before the padding +FF bytes.) + +Relocated chunks + +Let's go back to the scenario in which a particular data sector is full (no more +usable free space left) and contains a mixture of active and dirty (deleted or +invalidated) data. How does the dirty flash space get reclaimed, so that the +amount of available space (blank flash ready to hold new data) becomes equal to +the total FFS size minus the total size of active files and overhead? It can +only be done by relocating the still-active objects from the full sector to a +new one, invalidating the old copies, and once the old sector consists of +nothing but invalidated data, subjecting it to flash erasure. + +So how do the active FFS objects get relocated from a "condemned" sector to a +new one? If the object is a directory, a new index entry is created, pointing +to the newly relocated name chunk, but it is then made to fit into the old tree +structure without disrupting the latter: the new index entry is added at the +tail of the sibling-chain of the parent directory's descendants, the old index +entry for the same directory is invalidated (as if the directory were rmdir'ed), +and the descendant pointer of the newly written index entry is set to a copy of +the descendant pointer from the old index entry for the same directory. The +same approach is used when the head chunk of a file needs to be relocated; in +both cases a read-only FFS implementation doesn't need to do anything special to +support reading file and directory objects that have been relocated in this +manner. + +However, if the relocated object is a file continuation chunk, then the manner +in which such objects get relocated does affect file reading code. What if a +chunk in the middle of a chain linked by "descend" pointers needs to be moved? +What happens in this case is that the old copy of the chunk gets invalidated +(the object type byte turned to 00) like in the other object relocating cases, +and the sibling pointer of that old index entry (which was originally FFFF as +continuation objects have no siblings) is set to point to the new index entry +for the same chunk. The "descend" pointer in the new index entry is a copy of +that pointer from the old index entry. + +The manner of chunk relocation just described has been observed in the FFS +images read out of my most recent batch of Pirelli phones - the same ones in +which the root directory object is not at index #1. Thinking about it as I +write this, I've realized that the way in which continuation objects get +relocated is exactly the same as for other object types - thus the compaction +code in the firmware doesn't need to examine what object type it is moving. +However, the case of continuation chunk relocation deserves special attention +because it affects a read-only implementation like ours - the utilities whose +source accompanies this document used to fail on these FFS images until I +implemented the following additional handling: + +When following the chunk chain of a file, normally the only object type that's +expected is F4 - any other object type is an error. However, as a result of +chunk relocation, one can also encounter deleted objects, i.e., type == 00. +If such a deleted object is encountered, follow its sibling pointer, which must +be non-nil. + +Journal file + +Every Mokopir-FFS image I've seen so far contains a special file named +/.journal; this file is special in the following ways: + +* The object type byte is E1 instead of F1; +* Unlike regular files, this special file is internally-writable. + +What I mean by the above is that regular files are mostly immutable: once a +file has been created with some data content in the head chunk, it can only be +either appended to (one or more continuation chunks added), or overwritten by +creating a new file with the same name at the same level in the tree hierarchy +and invalidating the old one. But the special /.journal file is different: I +have never observed it to consist of more than the head chunk, and this head +chunk is pre-allocated with some largish and apparently fixed length (4 KiB on +my GTA02, 16 KiB on the Pirelli). This pre-allocated chunk contains what look +like 16-byte records at the beginning (on the first 4-byte boundary after the +NUL terminating the ".journal" name), followed by blank flash for the remainder +of the pre-allocated chunk - so it surely looks like new flash writes happen +within this chunk. + +I do not currently know the purpose of this /.journal file or the meaning of the +records it seems to contain. This understanding would surely be needed if one +wanted to create FFS images from scratch or to implement FFS write operations, +but I reason that a read-only implementation can get away with simply ignoring +this file. I reason that this file can't be necessary in order to parse an FFS +image for reading because one needs to parse the tree structure first in order +to locate this journal file itself. + +------------------------------------------------------------------------------- + +That's all I can think of right now. If anything is unclear, see the +accompanying source code for the listing/extraction utilities: with the general +explanation given by this document, it should be clear what my code does and +why. And if a given piece of knowledge is found neither in this document nor +in my source code, then I don't know it myself either, and my read-only +Mokopir-FFS implementation makes do without it. + +All knowledge contained herein has been recovered by reverse engineering. +Believe it or not, I have figured it out by staring at the hex dump of FFS +sectors, reasoning about how one could possibly implement an FFS given the +requirement of dynamic writability and the physical constraints of flash memory, +and writing listing/extraction test code iteratively until I got something that +appears to correctly parse all FFS images available to me - the result is the +code in this package. + +I never got as far as attempting to locate the FFS implementation routines +within the proprietary firmware binary code images, and I haven't found an +implementation of this particular FFS in any of the leaked sources yet either. +The TSM30 code doesn't seem to be of any use as its FFS appears to be totally +different. As to the more recently found LoCosto code leak, I found that one a +few days *after* I got the Moko/Pirelli "MysteryFFS" reverse-engineered on my +own, and when I did look at the FFS in the LoCosto code later, I saw what seems +to be a different FFS as well. + +Michael Spacefalcon +SE 52 Mes 16
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/linux-2.6.37.6-ftdi_sio.c.patch Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,29 @@ +--- ftdi_sio.c.orig 2011-03-27 11:01:41.000000000 -0800 ++++ ftdi_sio.c 2015-10-30 13:18:40.879000032 -0800 +@@ -949,7 +949,7 @@ + static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; + __u32 divisor; + /* divisor shifted 3 bits to the left */ +- int divisor3 = base / 2 / baud; ++ int divisor3 = (base / 2 + baud / 2) / baud; + divisor = divisor3 >> 3; + divisor |= (__u32)divfrac[divisor3 & 0x7] << 14; + /* Deal with special cases for highest baud rates. */ +@@ -1087,6 +1087,17 @@ + baud = tty_get_baud_rate(tty); + dbg("%s - tty_get_baud_rate reports speed %d", __func__, baud); + ++ /* ++ * FreeCalypso hack: translate non-std high ++ * baud rates for GSM like CP2102 does. ++ */ ++ if (baud == 230400) ++ baud = 203125; ++ else if (baud == 460800) ++ baud = 406250; ++ else if (baud == 921600) ++ baud = 812500; ++ + /* 2. Observe async-compatible custom_divisor hack, update baudrate + if needed */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ffstools/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,15 @@ +SUBDIR= tiffs-rd tiffs-wrappers + +all: ${SUBDIR} + +${SUBDIR}: FRC + cd $@; ${MAKE} ${MFLAGS} + +clean: FRC + rm -f a.out core errs + for i in ${SUBDIR}; do (cd $$i; ${MAKE} ${MFLAGS} clean); done + +install: FRC + for i in ${SUBDIR}; do (cd $$i; ${MAKE} ${MFLAGS} install); done + +FRC:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ffstools/README Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,31 @@ +You are looking at the source for the TIFFS In Vitro Analyzer utility. You may +have downloaded it either as a separate package or as part of the larger +freecalypso-sw suite. + +See TIFFS-Overview (in ../doc if you are working with the full freecalypso-sw +source tree) for a general description of what TIFFS is and why it matters. + +The utility contained in the present package runs on a general purpose GNU/Linux +(or other Unix) host and enables "in vitro" examination of Flash File System +images read out of TI-based GSM devices. Using this utility, you can list the +directory and file content of an FFS image, cat any individual file in the FFS, +or extract the complete FFS content into your regular Unix file system. Some +"forensic" operations are also supported: by listing the inode array, one can +deduce the order in which the present FFS content got created, and see what +files have been overwritten or deleted in the span of still-visible history. +One can then cat the old byte content of those overwritten or deleted files, +if those data chunks are still in the FFS image (i.e., if the flash sector in +question has not been reclaimed yet). + +Compilation and installation are straightforward: run 'make' to compile the +source; you should get 3 executable binaries named tiffs, mokoffs and pirffs; +then run 'make install' as root to install them in /usr/local/bin. The binary +named tiffs is the main program; mokoffs and pirffs are wrappers that simplify +the most common current use cases. + +To install somewhere other than /usr/local/bin, edit the INSTBIN= setting in +the subdirectory Makefiles. You will also need to edit +tiffs-wrappers/installpath.c accordingly, as the mokoffs and pirffs wrappers +are designed to exec tiffs by its absolute installed pathname. + +See Usage for the usage instructions.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ffstools/Usage Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,148 @@ +The generic tiffs utility needs to be invoked as follows: + +tiffs [global-options] <imgfile> <org> <cmd> [command-args] + +The first 3 non-optional arguments are the filename of the TIFFS image under +examination, the FFS organization being examined, and the operation to be +performed. The present utility is designed in the classic Unix manner in that +each invokation performs a single operation and exits, such that invokations of +tiffs (or one of the wrappers described below) may be plumbed into pipes and +the like. + +The 2nd argument to tiffs after the FFS image filename describes how the TIFFS +instance under study is organized in terms of flash sectors. The syntax of +this argument is KxN, where K is the flash sector size in KiB and N is the +number of sectors occupied by the FFS. For MokoFFS images the correct +organization argument is 64x7 (7 sectors of 64 KiB each); for Pirelli's FFS +images it is 256x18 (18 sectors of 256 KiB each). + +The following global options may be given before the image filename argument: + +-a num + + Use the specified flash block (sector) as the inode array block. + +-o offset + + The FFS image begins at the specified offset within the file, rather + than at the beginning. This option is useful when working with complete + device flash dumps of which FFS is only a part, starting somewhere + other than at 0. + +-r ino + + Use the specified inode as the root. Per Falcon's convention, TIFFS + inode numbers are always given in hex, hence this argument is + interpreted as hex without needing a 0x prefix. + +The invokation syntax for mokoffs and pirffs wrappers is the same as for tiffs, +except that the FFS organization argument (64x7 or 256x18) is omitted; the +wrapper fills that argument in before passing the command to the main tiffs +program. The only other difference is that instead of the generic -o global +option, mokoffs takes a -f global option (no argument) which indicates that one +is working with a complete flash dump image, rather than just the FFS portion; +mokoffs -f gets translated into tiffs -o0x380000. (pirffs has no such option +at all because Pirelli's FFS starts at offset 0 within its respective flash +chip select.) + +The next argument after the FFS organization for tiffs (or after the image +filename for mokoffs/pirffs) is the command (or operation) to be performed. +The following tiffs commands are currently available: + +General information commands +============================ + +These commands display general or summary information about the FFS image: + +tiffs <...> blkhdr + +This command displays the basic information contained in the header of each +flash erase block comprising the FFS image. + +tiffs <...> fsinfo + +This command displays some general information about the file system. + +Standard listing/extraction commands +==================================== + +These commands list or extract the normally-visible content of the FFS, i.e., +the content which is visible when the FFS is "mounted" normally, and which the +FFS promises to preserve - as opposed to deleted or overwritten content. + +tiffs <...> ls [-v[v]] [pathname...] + +Tiffs ls without additional arguments yields a listing of the complete FFS +directory tree, akin to tar tv. Example output fragment: + +fr 4096 /.journal +d /gsm +d /gsm/rf +d /gsm/rf/tx +f 512 /gsm/rf/tx/ramps.900 +f 128 /gsm/rf/tx/levels.900 +f 128 /gsm/rf/tx/calchan.900 + +The first character is 'f' for files or 'd' for directories. An 'r' following +immediately afterward means that the object has the read-only attribute set. +For files the listing includes the content size in bytes, and the last part is +the pathname of the object within the FFS. + +With a single -v option added after ls, the output will include verbose +information as to the segmentation structure of each file. With two -v options +or with -vv, this additional output will also include the byte offset of each +data chunk, relative to the beginning of the FFS image. + +Tiffs ls with a pathname argument yields information about the specified FFS +object; -v and -vv options act as already described, but are arguably more +useful when listing single files. + +tiffs <...> cat [-v|-h] pathname + +Just like the standard Unix cat(1) command, but cat'ing files from the FFS image +under study. The non-standard -h option means hex dump - it is handy because +almost all files in TI's GSM device FFS are binary, rather than ASCII. + +tiffs <...> xtr dest-dir + +This command extracts the complete content of the FFS into your ordinary Unix +file system. The sole argument is the local directory into which the root of +the GSM device FFS should be extracted. + +Forensic analysis commands +========================== + +Unlike the "standard" listing/extraction commands which present TIFFS as a +"normal" Unix file system, using the "forensic" commands effectively requires +that the operator understands how TIFFS works, in particular, what an inode is +in TIFFS. + +tiffs <...> lsino [-v[v]] + +This command lists the FFS inode array from first to last; this listing order +will normally correspond to the forward chronological order of object creation. +-v and -vv options add verbosity. + +'.' in the object type column means segment, '~' means a deleted object. The +lsino command only lists the inode array, and does not try to recover the +original type of deleted/overwritten objects from the journal or other clues. +The program attempts to recover the pathname of each inode, but because such +reverse mapping from inodes to pathnames is not an operation which TIFFS was +properly designed to support, and the pathname recovery algorithm in this TIFFS +IVA tool is made as generic as possible (doesn't look at the object types), the +lsino listing will occasionally include some bogus pathnames. Once again, it +is expected that the operator knows what s/he is doing when using these forensic +commands. + +tiffs <...> lsino [-v[v]] [-f] ino... + +This command works just like ls with an explicit pathname argument, but takes +one or more inode numbers instead. The -f option matters only if the requested +inode is in the deleted/overwritten state; it tells the lsino command to assume +that the object is/was the head inode of a file; -vf and -vvf combinations are +particularly useful. + +tiffs <...> catino [-v|-h] ino + +Just like regular cat, but takes an inode number instead of a pathname. Can be +used to cat the old content of deleted or overwritten files.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ffstools/tiffs-rd/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,20 @@ +CC= gcc +CFLAGS= -O2 +PROG= tiffs +OBJS= basics.o cat.o globals.o inode.o ls.o main.o object.o tree.o xtr.o +HDRS= globals.h pathname.h struct.h types.h +INSTBIN=/usr/local/bin + +all: ${PROG} + +${PROG}: ${OBJS} + ${CC} -o $@ ${OBJS} + +${OBJS}: ${HDRS} + +install: ${PROG} + mkdir -p ${INSTBIN} + install -c ${PROG} ${INSTBIN} + +clean: + rm -f ${PROG} *.o *.out *errs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ffstools/tiffs-rd/basics.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,155 @@ +/* + * This C module implements the "basics" of TIFFS image analysis. + */ + +#include <sys/types.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <strings.h> +#include "types.h" +#include "struct.h" +#include "globals.h" + +u8 tiffs_header[6] = {'F', 'f', 's', '#', 0x10, 0x02}; + +read_ffs_image() +{ + int fd; + struct stat st; + + fd = open(imgfile, O_RDONLY); + if (fd < 0) { + perror(imgfile); + exit(1); + } + fstat(fd, &st); + if (!S_ISREG(st.st_mode)) { + fprintf(stderr, "error: %s is not a regular file\n", imgfile); + exit(1); + } + if (st.st_size < imgfile_offset) { + fprintf(stderr, + "error: offset given with -o exceeds the size of the file\n"); + exit(1); + } + if (st.st_size - imgfile_offset < total_ffs_size) { + fprintf(stderr, + "error: %s is shorter than FFS size of 0x%lx bytes\n", + imgfile, (u_long)total_ffs_size); + exit(1); + } + image = mmap(NULL, total_ffs_size, PROT_READ, MAP_PRIVATE, fd, + imgfile_offset); + if (image == MAP_FAILED) { + perror("mmap"); + exit(1); + } + close(fd); +} + +cmd_blkhdr() +{ + int blk; + u8 *blkhdr; + + read_ffs_image(); + for (blk = 0; blk < total_blocks; blk++) { + printf("Block %3d: ", blk); + blkhdr = image + blk * eraseblk_size; + if (bcmp(blkhdr, tiffs_header, sizeof tiffs_header)) { + printf("No TIFFS header\n"); + continue; + } + printf("age %02X%02X, type/status %02X\n", + blkhdr[7], blkhdr[6], blkhdr[8]); + } + exit(0); +} + +find_inode_block() +{ + int i, abcnt; + u8 *ptr; + + if (index_blk_num >= 0) { + if (index_blk_num >= total_blocks) { + fprintf(stderr, + "invalid block # given with the -a option\n"); + exit(1); + } + ptr = image + index_blk_num * eraseblk_size; + if (bcmp(ptr, tiffs_header, sizeof tiffs_header)) { + fprintf(stderr, + "error: block specified with -a has no TIFFS header\n"); + exit(1); + } + if (ptr[8] != 0xAB) { + fprintf(stderr, + "error: block specified with -a is not an AB block\n"); + exit(1); + } + inode_block = ptr; + return(0); + } + abcnt = 0; + for (ptr = image, i = 0; i < total_blocks; i++, ptr += eraseblk_size) { + if (bcmp(ptr, tiffs_header, sizeof tiffs_header)) { + fprintf(stderr, + "warning: no TIFFS signature in erase block #%d (offset %x)\n", + i, ptr - image); + continue; + } + switch (ptr[8]) { + case 0xAB: + if (verbose) + fprintf(stderr, + "Found AB index in erase block #%d (offset %x)\n", + i, ptr - image); + index_blk_num = i; + inode_block = ptr; + abcnt++; + continue; + case 0xBD: + case 0xBF: + continue; + } + fprintf(stderr, + "warning: unexpected block type/status %02X at offset %x\n", + ptr[8], ptr - image); + } + if (!inode_block) { + fprintf(stderr, + "error: could not find an active inode block in %s\n", + imgfile); + exit(1); + } + if (abcnt > 1) { + fprintf(stderr, + "error: found more than one AB block; use -a\n"); + exit(1); + } + return(0); +} + +cmd_fsinfo() +{ + read_ffs_image(); + find_inode_block(); + printf("Active inode block (AB) is block #%d\n", index_blk_num); + alloc_inode_table(); + find_root_inode(); + printf("Root inode is #%x\n", root_inode); + if (validate_obj_name(root_inode, 1)) { + printf("Root inode (format) name: %s\n", + inode_info[root_inode]->dataptr); + exit(0); + } else { + printf("No valid name found in the root inode!\n"); + exit(1); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ffstools/tiffs-rd/cat.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,233 @@ +/* + * This C module implements the cat and catino commands. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> +#include "types.h" +#include "struct.h" +#include "globals.h" +#include "pathname.h" + +int cat_mode; + +static u8 hex_buf[16]; +static int hex_fill; +static u32 hex_offset; + +cat_hex_flush() +{ + int i, c; + + printf("%08X: ", hex_offset); + for (i = 0; i < 16; i++) { + if (i < hex_fill) + printf("%02X ", hex_buf[i]); + else + fputs(" ", stdout); + if (i == 7 || i == 15) + putchar(' '); + } + for (i = 0; i < hex_fill; i++) { + c = hex_buf[i]; + if (c < ' ' || c > '~') + c = '.'; + putchar(c); + } + putchar('\n'); +} + +cat_hex_byte(inb) +{ + hex_buf[hex_fill++] = inb; + if (hex_fill >= 16) { + cat_hex_flush(); + hex_offset += hex_fill; + hex_fill = 0; + } +} + +void +cat_chunk(ch) + struct chunkinfo *ch; +{ + u8 *p; + int c; + + if (!ch->len) + return; + switch (cat_mode) { + case 0: + write(1, ch->start, ch->len); + return; + case 1: + for (p = ch->start; p < ch->end; p++) { + c = *p; + if (c >= ' ' && c <= '~' || c == '\n') + putchar(c); + else { + if (c & 0x80) { + putchar('M'); + putchar('-'); + c &= 0x7F; + } + putchar('^'); + if (c == 0x7F) + putchar('?'); + else + putchar(c + '@'); + } + } + return; + case 2: + for (p = ch->start; p < ch->end; p++) + cat_hex_byte(*p); + return; + } +} + +void +cat_finish() +{ + switch (cat_mode) { + case 1: + putchar('\n'); + return; + case 2: + if (hex_fill) + cat_hex_flush(); + return; + } +} + +static void +segment_cat_callback(inf, opaque) + struct inode_info *inf; + u_long opaque; +{ + struct chunkinfo chi; + + size_extra_chunk(inf, &chi); + cat_chunk(&chi); +} + +cmd_cat(argc, argv) + char **argv; +{ + extern int optind; + int c, headino; + struct inode_info *inf; + struct chunkinfo chi; + + optind = 0; + while ((c = getopt(argc, argv, "hv")) != EOF) + switch (c) { + case 'h': + cat_mode = 2; + continue; + case 'v': + cat_mode = 1; + continue; + default: +usage: fprintf(stderr, "usage: cat [-v|-h] pathname\n"); + exit(1); + } + if (argc != optind + 1) + goto usage; + + read_ffs_image(); + find_inode_block(); + alloc_inode_table(); + find_root_inode(); + + headino = find_pathname(argv[optind]); + inf = inode_info[headino]; + switch (inf->type) { + case 0xE1: + case 0xF1: + break; + case 0xF2: + fprintf(stderr, "error: the requested object is a directory\n"); + exit(1); + case 0xF3: + fprintf(stderr, +"error: the requested object is a symlink; use readlink instead of cat\n"); + exit(1); + default: + fprintf(stderr, "error: unexpected object type %02X\n", + inf->type); + exit(1); + } + size_head_chunk(inf, &chi); + cat_chunk(&chi); + iterate_seg_file(headino, segment_cat_callback, 0L, 0, 0); + cat_finish(); + exit(0); +} + +cmd_catino(argc, argv) + char **argv; +{ + extern int optind; + int c, headino; + struct inode_info *inf; + struct chunkinfo chi; + + optind = 0; + while ((c = getopt(argc, argv, "hv")) != EOF) + switch (c) { + case 'h': + cat_mode = 2; + continue; + case 'v': + cat_mode = 1; + continue; + default: +usage: fprintf(stderr, "usage: catino [-v|-h] ino\n"); + exit(1); + } + if (argc != optind + 1) + goto usage; + headino = strtoul(argv[optind], 0, 16); + + read_ffs_image(); + find_inode_block(); + alloc_inode_table(); + if (!validate_inode(headino)) { + fprintf(stderr, "catino: specified inode number is invalid\n"); + exit(1); + } + inf = inode_info[headino]; + switch (inf->type) { + case 0x00: + case 0xE1: + case 0xF1: + case 0xF3: + break; + case 0xF2: + fprintf(stderr, "error: the requested object is a directory\n"); + exit(1); + default: + fprintf(stderr, "error: unexpected object type %02X\n", + inf->type); + exit(1); + } + if (!inf->len) { + fprintf(stderr, "error: requested inode has been reclaimed\n"); + exit(1); + } + if (!validate_obj_name(headino, 0)) { + fprintf(stderr, +"error: no valid name at the beginning of the requested seghead chunk\n"); + exit(1); + } + size_head_chunk(inf, &chi); + cat_chunk(&chi); + iterate_seg_file(headino, segment_cat_callback, 0L, !inf->type, 0); + cat_finish(); + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ffstools/tiffs-rd/globals.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,20 @@ +/* + * Definitions of global variables for the tiffs IVA program. + */ + +#include <sys/types.h> +#include "types.h" +#include "struct.h" + +char *imgfile; +off_t imgfile_offset; +u32 eraseblk_size; +int total_blocks; +u32 total_ffs_size; +int index_blk_num = -1, root_inode; +int inode_limit; +int verbose, verbose2; +int old_16bit_location; + +u8 *image, *inode_block; +struct inode_info **inode_info;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ffstools/tiffs-rd/globals.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,16 @@ +/* + * extern declarations of global variables + */ + +extern char *imgfile; +extern off_t imgfile_offset; +extern u32 eraseblk_size; +extern int total_blocks; +extern u32 total_ffs_size; +extern int index_blk_num, root_inode; +extern int inode_limit; +extern int verbose, verbose2; +extern int old_16bit_location; + +extern u8 *image, *inode_block; +extern struct inode_info **inode_info;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ffstools/tiffs-rd/inode.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,164 @@ +/* + * This C module implements the reading and decoding of inode information. + */ + +#include <sys/types.h> +#include <endian.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "types.h" +#include "struct.h" +#include "globals.h" + +u8 blank_flash_line[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + +alloc_inode_table() +{ + inode_info = malloc(sizeof(struct inode_info *) * inode_limit); + if (!inode_info) { + perror("malloc of inode table"); + exit(1); + } + bzero(inode_info, sizeof(struct inode_info *) * inode_limit); +} + +static int +convert_ptr(in, infp) + int in; + int *infp; +{ + if (in == 0xFFFF) { + *infp = 0; + return(0); + } + if (in < 1 || in >= inode_limit) + return(-1); + *infp = in; + return(1); +} + +validate_inode(ino) +{ + struct inode_flash *fl; + struct inode_info *inf; + + if (ino < 1 || ino >= inode_limit) + return(0); + if (inode_info[ino]) + return(1); + fl = (struct inode_flash *)inode_block + ino; + if (!bcmp(fl, blank_flash_line, sizeof blank_flash_line)) + return(0); + inf = malloc(sizeof(struct inode_info)); + if (!inf) { + perror("malloc of struct inode_info"); + exit(1); + } + bzero(inf, sizeof(struct inode_info)); + inf->ino = ino; + inf->len = le16toh(fl->len); + if (inf->len & 0xF) { + fprintf(stderr, + "warning: inode #%x: invalid length, skipping\n", ino); + free(inf); + return(0); + } + inf->type = fl->type; + switch (inf->type) { + case 0x00: + break; + case 0xE1: + case 0xF1: + case 0xF2: + case 0xF3: + case 0xF4: + if (!inf->len) { + fprintf(stderr, + "warning: inode #%x: non-deleted object has zero length, skipping\n", + ino); + free(inf); + return(0); + } + break; + default: + fprintf(stderr, + "warning: inode #%x: unexpected object type %02X, skipping\n", + ino, inf->type); + free(inf); + return(0); + } + if (convert_ptr(le16toh(fl->descend), &inf->descend) < 0) { + fprintf(stderr, + "warning: inode #%x: invalid descend pointer, skipping\n", + ino); + free(inf); + return(0); + } + if (convert_ptr(le16toh(fl->sibling), &inf->sibling) < 0) { + fprintf(stderr, + "warning: inode #%x: invalid sibling pointer, skipping\n", + ino); + free(inf); + return(0); + } + if (inf->len) { + inf->rawloc = le32toh(fl->dataptr); + if (old_16bit_location) + inf->rawloc >>= 16; + if (inf->rawloc > 0x0FFFFFFF) { +invdptr: fprintf(stderr, + "warning: inode #%x: invalid data pointer, skipping\n", + ino); + free(inf); + return(0); + } + inf->offset = inf->rawloc << 4; + if (inf->offset >= total_ffs_size) + goto invdptr; + if (inf->offset + inf->len > total_ffs_size) { + fprintf(stderr, +"warning: inode #%x: data pointer + length > FFS total size, skipping\n", + ino); + free(inf); + return(0); + } + inf->dataptr = image + inf->offset; + } + inode_info[ino] = inf; + return(1); +} + +find_root_inode() +{ + int ino; + + if (root_inode) { + if (!validate_inode(root_inode)) { + fprintf(stderr, + "error: root inode specified with -r is invalid\n"); + exit(1); + } + return(1); + } + for (ino = 1; ino < inode_limit; ino++) { + if (!validate_inode(ino)) + continue; + if (inode_info[ino]->type != 0xF2) + continue; + if (*inode_info[ino]->dataptr != '/') + continue; + root_inode = ino; + if (verbose) + fprintf(stderr, "Found root inode at #%x\n", ino); + if (inode_info[ino]->sibling) + fprintf(stderr, + "warning: root inode #%x has a non-null sibling pointer\n", + ino); + return(0); + } + fprintf(stderr, "error: no root inode found; try -r\n"); + exit(1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ffstools/tiffs-rd/ls.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,338 @@ +/* + * This C module implements the ls and lsino commands. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "types.h" +#include "struct.h" +#include "globals.h" +#include "pathname.h" + +static void +segment_size_callback(inf, opaque) + struct inode_info *inf; + u_long opaque; +{ + size_t *accump = (size_t *) opaque; + struct chunkinfo chi; + + size_extra_chunk(inf, &chi); + *accump += chi.len; +} + +size_t +get_file_size(seghead_ino, deleted) +{ + struct chunkinfo chi; + size_t accum; + + size_head_chunk(inode_info[seghead_ino], &chi); + accum = chi.len; + iterate_seg_file(seghead_ino, segment_size_callback, (u_long) &accum, + deleted, 0); + return(accum); +} + +static void +segment_ls_callback(inf, opaque) + struct inode_info *inf; + u_long opaque; +{ + struct chunkinfo chi; + + size_extra_chunk(inf, &chi); + if (verbose2 > 1) + printf("seg #%04x @%08x length=%lu\n", inf->ino, inf->offset, + (u_long) chi.len); + else + printf("seg #%04x length=%lu\n", inf->ino, (u_long) chi.len); +} + +ls_seg_file(seghead_ino, deleted) +{ + struct inode_info *inf = inode_info[seghead_ino]; + struct chunkinfo chi; + + size_head_chunk(inf, &chi); + printf("%lu bytes in seghead", (u_long) chi.len); + if (verbose2 > 1) + printf(", starting at offset %lx", + (u_long)(inf->byte_after_name - image)); + putchar('\n'); + iterate_seg_file(seghead_ino, segment_ls_callback, 0L, deleted, + verbose2 > 1); +} + +void +ls_tree_callback(pathname, ino, depth) + char *pathname; +{ + struct inode_info *inf = inode_info[ino]; + u_long size; + char readonly; + + if (inf->type & 0x10) + readonly = ' '; + else + readonly = 'r'; + switch (inf->type) { + case 0xE1: + case 0xF1: + size = get_file_size(ino, 0); + printf("f%c %7lu %s\n", readonly, size, pathname); + if (verbose2) + ls_seg_file(ino, 0); + return; + case 0xE2: + case 0xF2: + printf("d%c %s\n", readonly, pathname); + return; + case 0xE3: + case 0xF3: + printf("l%c %s\n", readonly, pathname); + return; + default: + fprintf(stderr, + "BUG: bad inode byte %02X reached ls_tree_callback()\n", + inf->type); + exit(1); + } +} + +ls_by_pathname(pathname) + char *pathname; +{ + int ino; + struct inode_info *inf; + char *type; + + printf("%s\n", pathname); + ino = find_pathname(pathname); + printf("inode #%x\n", ino); + inf = inode_info[ino]; + switch (inf->type) { + case 0xE1: + type = "read-only file"; + break; + case 0xF1: + type = "file"; + break; + case 0xF2: + type = "directory"; + break; + case 0xF3: + type = "symlink"; + break; + default: + type = "???"; + } + printf("object type %02X (%s)\n", inf->type, type); + if (!validate_obj_name(ino, ino == root_inode)) { + printf("No valid object name in the chunk!\n"); + exit(1); + } + printf("object name: %s\n", inf->dataptr); + if (inf->type == 0xF1 || inf->type == 0xE1) { + printf("total size: %lu bytes\n", + (u_long) get_file_size(ino, 0)); + if (verbose2) + ls_seg_file(ino, 0); + } + putchar('\n'); +} + +cmd_ls(argc, argv) + char **argv; +{ + extern int optind; + int c; + + read_ffs_image(); + find_inode_block(); + alloc_inode_table(); + find_root_inode(); + + optind = 0; + while ((c = getopt(argc, argv, "v")) != EOF) + switch (c) { + case 'v': + verbose2++; + continue; + default: + fprintf(stderr, "usage: ls [-v[v]] [pathname...]\n"); + exit(1); + } + if (optind >= argc) { + traverse_visible_tree(ls_tree_callback); + exit(0); + } + for (; optind < argc; optind++) + ls_by_pathname(argv[optind]); + exit(0); +} + +lsino_all() +{ + int ino, last_ino = 0; + struct inode_info *inf; + char pathname[PATHNAME_BUF_SIZE], typech; + int pathstat; + char descend_str[8], sibling_str[8]; + + for (ino = 1; ino < inode_limit; ino++) { + if (!validate_inode(ino)) + continue; + if (ino != last_ino + 1) + printf("GAP in inode numbers\n"); + inf = inode_info[ino]; + pathstat = pathname_of_inode(ino, pathname); + if (pathstat < 0) + strcpy(pathname, "-nopath-"); + switch (inf->type) { + case 0x00: + typech = '~'; + break; + case 0xE1: + case 0xF1: + typech = 'f'; + break; + case 0xF2: + typech = 'd'; + break; + case 0xF3: + typech = 'l'; + break; + case 0xF4: + typech = '.'; + break; + default: + typech = '?'; + } + printf("#%04x %c %s\n", ino, typech, pathname); + if (inf->type && !(inf->type & 0x10)) + printf("\tread-only object\n"); + if (ino == root_inode) + printf("\tactive root\n"); + else if (inf->nparents < 1) + printf("\torphan\n"); + else if (inf->nparents > 1) + printf("\tparent: #%x (%d)\n", inf->parent, + inf->nparents); + else if (pathstat < 0 || verbose2) + printf("\tparent: #%x\n", inf->parent); + if (verbose2 > 1) { + if (inf->descend) + sprintf(descend_str, "#%x", inf->descend); + else + strcpy(descend_str, "null"); + if (inf->sibling) + sprintf(sibling_str, "#%x", inf->sibling); + else + strcpy(sibling_str, "null"); + printf("\tchild: %s, sibling: %s\n", + descend_str, sibling_str); + } + if (!inf->len) + printf("\treclaimed\n"); + last_ino = ino; + } + exit(0); +} + +void +lsino_one(ino, assume_file) +{ + struct inode_info *inf; + char pathname[PATHNAME_BUF_SIZE], *type; + + if (!validate_inode(ino)) { + fprintf(stderr, "lsino: specified inode number is invalid\n"); + exit(1); + } + printf("inode #%x\n", ino); + inf = inode_info[ino]; + if (pathname_of_inode(ino, pathname) >= 0) + printf("Pathname: %s\n", pathname); + else + printf("No pathname found\n"); + inf = inode_info[ino]; + switch (inf->type) { + case 0x00: + type = "deleted"; + break; + case 0xE1: + type = "read-only file"; + break; + case 0xF1: + type = "file"; + break; + case 0xF2: + type = "directory"; + break; + case 0xF3: + type = "symlink"; + break; + case 0xF4: + type = "segment"; + break; + default: + type = "???"; + } + printf("object type %02X (%s)\n", inf->type, type); + if (!inf->len) { + printf("This inode has been reclaimed\n\n"); + return; + } + if (validate_obj_name(ino, 1)) + printf("object name: %s\n", inf->dataptr); + else { + printf("No valid object name in the chunk\n\n"); + return; + } + if (inf->type == 0xF1 || inf->type == 0xE1 || + !inf->type && assume_file) { + printf("total size: %lu bytes\n", + (u_long) get_file_size(ino, !inf->type)); + if (verbose2) + ls_seg_file(ino, !inf->type); + } + putchar('\n'); +} + +cmd_lsino(argc, argv) + char **argv; +{ + extern int optind; + int c, assume_file = 0, ino; + + read_ffs_image(); + find_inode_block(); + alloc_inode_table(); + find_root_inode(); + treewalk_all(); + + optind = 0; + while ((c = getopt(argc, argv, "fv")) != EOF) + switch (c) { + case 'f': + assume_file++; + continue; + case 'v': + verbose2++; + continue; + default: + fprintf(stderr, "usage: lsino [-v[v]] [ino...]\n"); + exit(1); + } + if (optind >= argc) + return lsino_all(); + for (; optind < argc; optind++) { + ino = strtoul(argv[optind], 0, 16); + lsino_one(ino, assume_file); + } + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ffstools/tiffs-rd/main.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,128 @@ +/* + * This C module contains the main() function for the tiffs utility, + * dispatching control to different operation commands. + */ + +#include <sys/types.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "types.h" +#include "globals.h" + +parse_org_arg(arg) + char *arg; +{ + char *cp; + + cp = index(arg, 'x'); + if (!cp || !isdigit(cp[1]) || !isdigit(arg[0])) { + fprintf(stderr, + "error: TIFFS organization argument \"%s\" is invalid\n", arg); + exit(1); + } + *cp++ = '\0'; + if (!strcmp(arg, "8")) + eraseblk_size = 0x2000; + else if (!strcmp(arg, "16")) + eraseblk_size = 0x4000; + else if (!strcmp(arg, "32")) + eraseblk_size = 0x8000; + else if (!strcmp(arg, "64")) + eraseblk_size = 0x10000; + else if (!strcmp(arg, "128")) + eraseblk_size = 0x20000; + else if (!strcmp(arg, "256")) + eraseblk_size = 0x40000; + else { + fprintf(stderr, + "error: \"%s\" is not a recognized flash sector size\n", + arg); + exit(1); + } + total_blocks = atoi(cp); + if (total_blocks < 1 || total_blocks > 128) { + fprintf(stderr, + "error: \"%s\" is not a reasonable number of FFS sectors\n", + cp); + exit(1); + } + total_ffs_size = eraseblk_size * total_blocks; + inode_limit = eraseblk_size >> 4; +} + +extern int cmd_blkhdr(); +extern int cmd_cat(); +extern int cmd_catino(); +extern int cmd_fsinfo(); +extern int cmd_ls(); +extern int cmd_lsino(); +extern int cmd_xtr(); + +static struct cmdtab { + char *cmd; + int (*func)(); +} cmdtab[] = { + {"blkhdr", cmd_blkhdr}, + {"cat", cmd_cat}, + {"catino", cmd_catino}, + {"fsck", NULL}, + {"fsinfo", cmd_fsinfo}, + {"ls", cmd_ls}, + {"lsino", cmd_lsino}, + {"xtr", cmd_xtr}, + {NULL, NULL} +}; + +main(argc, argv) + char **argv; +{ + extern int optind; + extern char *optarg; + int c; + char *cmd; + struct cmdtab *tp; + + while ((c = getopt(argc, argv, "+a:o:Or:v")) != EOF) + switch (c) { + case 'a': + index_blk_num = atoi(optarg); + continue; + case 'o': + imgfile_offset = strtoul(optarg, 0, 0); + continue; + case 'O': + old_16bit_location = 1; + continue; + case 'r': + root_inode = strtoul(optarg, 0, 16); + continue; + case 'v': + verbose++; + continue; + default: +usage: fprintf(stderr, + "usage: %s [global-options] <imgfile> <org> <op> ...\n", + argv[0]); + exit(1); + } + if (argc - optind < 3) + goto usage; + imgfile = argv[optind]; + parse_org_arg(argv[optind+1]); + cmd = argv[optind+2]; + + for (tp = cmdtab; tp->cmd; tp++) + if (!strcmp(tp->cmd, cmd)) + break; + if (!tp->func) { + fprintf(stderr, + "%s: operation \"%s\" is unknown or unimplemented\n", + argv[0], cmd); + exit(1); + } + optind += 2; + return tp->func(argc - optind, argv + optind); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ffstools/tiffs-rd/object.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,153 @@ +/* + * This C module implements object-level analysis. + */ + +#include <sys/types.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "types.h" +#include "struct.h" +#include "globals.h" +#include "pathname.h" + +validate_obj_name(ino, root_special) +{ + struct inode_info *inf = inode_info[ino]; + u8 *p, *endp; + int c; + + if (!inf->len) + return(0); + p = inf->dataptr; + endp = p + inf->len; + for (; ; p++) { + if (p >= endp) + return(0); + c = *p; + if (!c) + break; + if (c < ' ' || c > '~') + return(0); + if (root_special || isalnum(c)) + continue; + switch (c) { + case '.': + case ',': + case '_': + case '-': + case '+': + case '%': + case '$': + case '#': + continue; + default: + return(0); + } + } + if (!root_special) { + c = p - inf->dataptr; + if (c < 1 || c > MAX_FN_COMPONENT) + return(0); + if (!strcmp(inf->dataptr, ".") || !strcmp(inf->dataptr, "..")) + return(0); + } + inf->byte_after_name = p + 1; + return(1); +} + +u8 * +find_end_of_chunk(inf) + struct inode_info *inf; +{ + u8 *p; + int i; + + p = inf->dataptr + inf->len; + for (i = 1; i <= 16; i++) { + if (!p[-i]) + return(p - i); + if (p[-i] != 0xFF) + break; + } + fprintf(stderr, + "error: chunk @%x (inode #%x): no valid termination found\n", + inf->offset, inf->ino); + return(p); /* bogon, allows the rest to continue */ +} + +size_head_chunk(inf, chi) + struct inode_info *inf; + struct chunkinfo *chi; +{ + chi->start = inf->byte_after_name; + chi->end = find_end_of_chunk(inf); + if (chi->start >= chi->end) { + chi->len = 0; + return(0); + } else { + chi->len = chi->end - chi->start; + return(1); + } +} + +size_extra_chunk(inf, chi) + struct inode_info *inf; + struct chunkinfo *chi; +{ + chi->start = inf->dataptr; + chi->end = find_end_of_chunk(inf); + chi->len = chi->end - chi->start; +} + +void +iterate_seg_file(seghead, callback, callback_data, deleted, verbose) + void (*callback)(); + u_long callback_data; +{ + int ino; + struct inode_info *inf; + + for (ino = inode_info[seghead]->descend; ino; ino = inf->descend) { +loop: if (!validate_inode(ino)) { + fprintf(stderr, + "error: following seg file hit invalid inode #%x\n", + ino); + return; + } + inf = inode_info[ino]; + switch (inf->type) { + case 0xF4: + callback(inf, callback_data); + continue; + case 0x00: + if (deleted) { + if (inf->len) + callback(inf, callback_data); + else + fprintf(stderr, + "error: presumed deleted segment inode #%x has been reclaimed\n", + ino); + continue; + } + if (!inf->sibling) { + fprintf(stderr, + "error: segment object at inode #%x: marked deleted, but no sibling\n", + ino); + return; + } + if (verbose) + printf("seg inode #%x deleted, moved to #%x\n", + ino, inf->sibling); + ino = inf->sibling; + goto loop; + default: + fprintf(stderr, + "error: inode #%x: unexpected type %02X when expecting segment (F4)\n", + ino, inf->type); + return; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ffstools/tiffs-rd/pathname.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,3 @@ +#define MAX_FN_COMPONENT 20 +#define MAX_DIR_NEST 6 +#define PATHNAME_BUF_SIZE ((MAX_FN_COMPONENT+1) * (MAX_DIR_NEST+1) + 1)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ffstools/tiffs-rd/struct.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,47 @@ +/* actual TIFFS on-media structure */ +struct inode_flash { + u16 len; + u8 reserved1; + u8 type; + u16 descend; + u16 sibling; + u32 dataptr; + u16 sequence; + u16 updates; +}; + +struct journal_entry { + u8 status; + u8 objtype; + u16 this_ino; + u16 link_ptr; + u16 replacee; + u32 location; + u16 size; + u16 repli; /* ??? */ +}; + +/* our own distilled info struct */ +struct inode_info { + int ino; + /* info from the inode record */ + int type; + int descend; + int sibling; + u16 len; + u32 rawloc; + u32 offset; + u8 *dataptr; + /* filled by treewalk */ + int nparents; + int parent; + /* filled by misc */ + u8 *byte_after_name; +}; + +/* chunk location and size info */ +struct chunkinfo { + u8 *start; + u8 *end; + size_t len; +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ffstools/tiffs-rd/tree.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,237 @@ +/* + * This C module implements operations on the tree level. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "types.h" +#include "struct.h" +#include "globals.h" +#include "pathname.h" + +static void +visible_walk_dir(pathbuf_start, pathbuf_ptr, dirino, depth, callback) + char *pathbuf_start, *pathbuf_ptr; + void (*callback)(); +{ + int ndepth = depth + 1; + int child; + struct inode_info *inf; + + if (depth > MAX_DIR_NEST) { + fprintf(stderr, + "error: max dir nesting exceeded at inode #%x\n", + dirino); + return; + } + for (child = inode_info[dirino]->descend; child; child = inf->sibling) { + if (!validate_inode(child)) { + fprintf(stderr, + "error: walk of visible tree hit invalid inode #%x\n", + child); + return; + } + inf = inode_info[child]; + switch (inf->type) { + case 0x00: + /* walking the *visible* tree: skip deleted objects */ + continue; + case 0xF4: + fprintf(stderr, + "warning: directory #%x has child #%x of type segment (F4), skipping\n", + dirino, child); + continue; + } + if (!validate_obj_name(child, 0)) { + fprintf(stderr, + "visible tree walk error: no valid name for inode #%x\n", + child); + continue; + } + sprintf(pathbuf_ptr, "/%s", inf->dataptr); + callback(pathbuf_start, child, ndepth); + if (inf->type == 0xF2) + visible_walk_dir(pathbuf_start, + index(pathbuf_ptr, '\0'), child, + ndepth, callback); + } +} + +traverse_visible_tree(callback) + void (*callback)(); +{ + char pathbuf[PATHNAME_BUF_SIZE]; + + visible_walk_dir(pathbuf, pathbuf, root_inode, 0, callback); +} + +/* + * The following function iterates through the descendants of a directory + * object looking for a specific directory-member filename. + * + * Arguments: + * - inode # of the parent directory + * - inode # of the first descendant (descendant pointer from the dir object) + * - filename to search for + * + * Returns: inode # of the sought descendant object if found, 0 otherwise. + */ +find_dir_member(dirino, first_descend, srchname) + char *srchname; +{ + int ino; + struct inode_info *inf; + + for (ino = first_descend; ino; ino = inf->sibling) { + if (!validate_inode(ino)) { + fprintf(stderr, + "error: pathname search hit invalid inode #%x\n", + ino); + exit(1); + } + inf = inode_info[ino]; + switch (inf->type) { + case 0x00: + /* walking the *visible* tree: skip deleted objects */ + continue; + case 0xF4: + fprintf(stderr, + "warning: directory #%x has child #%x of type segment (F4), skipping\n", + dirino, ino); + continue; + } + if (!validate_obj_name(ino, 0)) { + fprintf(stderr, + "visible tree walk error: no valid name for inode #%x\n", + ino); + continue; + } + if (!strcmp(inf->dataptr, srchname)) + return(ino); + } + return(0); +} + +/* + * The following function searches for a pathname from the root down. + * Returns the inode # if found, otherwise exits with an error message + * indicating which step failed. + * + * Warning: the pathname in the argument buffer will be destroyed: + * 0s put in place of the slashes. + */ +find_pathname(pathname) + char *pathname; +{ + char *cur, *next; + int ino; + struct inode_info *inf; + + cur = pathname; + if (*cur == '/') + cur++; + else { + fprintf(stderr, + "bad pathname \"%s\": TIFFS pathnames must be absolute\n", + pathname); + exit(1); + } + for (ino = root_inode; cur; cur = next) { + if (!*cur) + break; + next = index(cur, '/'); + if (next == cur) { + fprintf(stderr, + "malformed pathname: multiple adjacent slashes\n"); + exit(1); + } + if (next) + *next++ = '\0'; + inf = inode_info[ino]; + if (inf->type != 0xF2) { + fprintf(stderr, + "pathname search error: encountered a non-directory\n"); + exit(1); + } + ino = find_dir_member(ino, inf->descend, cur); + if (!ino) { + fprintf(stderr, + "pathname search error: component name not found\n"); + exit(1); + } + } + return(ino); +} + +/* + * treewalk_all() walks the entire inode tree from the root down, without + * regard to object types, including deleted objects and even reclaimed ones. + * The output is the filling of the parent and nparents fields in the inode + * info array. + */ + +static void +treewalk_all_node(parent) +{ + int child; + struct inode_info *inf; + + for (child = inode_info[parent]->descend; child; child = inf->sibling) { + if (!validate_inode(child)) { + fprintf(stderr, + "error: walk of complete tree hit invalid inode #%x\n", + child); + return; + } + inf = inode_info[child]; + inf->parent = parent; + inf->nparents++; + if (inf->nparents >= inode_limit) { + fprintf(stderr, + "error: detected loop in inode tree at #%x, child of #%x\n", + child, parent); + return; + } + if (inf->nparents == 1) + treewalk_all_node(child); + } +} + +treewalk_all() +{ + treewalk_all_node(root_inode); +} + +pathname_of_inode(ino, pnbuf) + char *pnbuf; +{ + int level; + char *revpath[MAX_DIR_NEST+1]; + struct inode_info *inf; + char *op; + + for (level = 0; ino != root_inode; ino = inf->parent) { + if (!validate_obj_name(ino, 0)) + return(-1); + inf = inode_info[ino]; + if (!inf->parent) + return(-1); + if (level > MAX_DIR_NEST) + return(-1); + revpath[level++] = (char *) inf->dataptr; + } + op = pnbuf; + if (!level) + *op++ = '/'; + while (level) { + level--; + *op++ = '/'; + strcpy(op, revpath[level]); + op = index(op, '\0'); + } + *op = '\0'; + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ffstools/tiffs-rd/types.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,12 @@ +/* + * I like using u8/u16/u32, but they don't seem to be defined anywhere. + * So I solve the whole portability problem by defining them myself. + */ + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; + +typedef signed char s8; +typedef signed short s16; +typedef signed int s32;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ffstools/tiffs-rd/xtr.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,105 @@ +/* + * This C module implements the xtr command. + */ + +#include <sys/types.h> +#include <sys/file.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> +#include "types.h" +#include "struct.h" +#include "globals.h" +#include "pathname.h" + +static void +dump_head_chunk(fd, headino) +{ + struct inode_info *inf = inode_info[headino]; + struct chunkinfo chi; + + if (size_head_chunk(inf, &chi)) + write(fd, chi.start, chi.len); +} + +static void +dump_extra_chunk(inf, opaque) + struct inode_info *inf; + u_long opaque; +{ + int fd = (int)opaque; + struct chunkinfo chi; + + size_extra_chunk(inf, &chi); + write(fd, chi.start, chi.len); +} + +extract_file(relpath, headino) + char *relpath; +{ + int fd; + + fd = open(relpath, O_WRONLY|O_CREAT|O_TRUNC, 0666); + if (fd < 0) { + perror(relpath); + exit(1); + } + dump_head_chunk(fd, headino); + iterate_seg_file(headino, dump_extra_chunk, (u_long)fd, 0, 0); + close(fd); +} + +void +xtr_tree_callback(pathname, ino, depth) + char *pathname; +{ + struct inode_info *inf = inode_info[ino]; + + switch (inf->type) { + case 0xE1: + case 0xF1: + /* skip /.journal; those who need it can cat it */ + if (strcmp(pathname, "/.journal")) + extract_file(pathname + 1, ino); + return; + case 0xE2: + case 0xF2: + if (mkdir(pathname + 1, 0777) < 0) { + perror(pathname + 1); + exit(1); + } + return; + case 0xE3: + case 0xF3: + fprintf(stderr, + "symlink at %s ignored: symlink extraction not implemented yet\n", + pathname); + return; + default: + fprintf(stderr, + "BUG: bad inode byte %02X reached xtr_tree_callback()\n", + inf->type); + exit(1); + } +} + +cmd_xtr(argc, argv) + char **argv; +{ + if (argc != 2) { + fprintf(stderr, "usage: xtr dest-dir\n"); + exit(1); + } + read_ffs_image(); + find_inode_block(); + alloc_inode_table(); + find_root_inode(); + if (chdir(argv[1]) < 0) { + perror(argv[1]); + exit(1); + } + traverse_visible_tree(xtr_tree_callback); + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ffstools/tiffs-wrappers/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,22 @@ +CC= gcc +CFLAGS= -O2 +PROGS= mokoffs pirffs +INSTBIN=/usr/local/bin + +MOKOFFS_OBJS= installpath.o mokoffs.o +PIRFFS_OBJS= installpath.o pirffs.o + +all: ${PROGS} + +mokoffs: ${MOKOFFS_OBJS} + ${CC} ${CFLAGS} -o $@ ${MOKOFFS_OBJS} + +pirffs: ${PIRFFS_OBJS} + ${CC} ${CFLAGS} -o $@ ${PIRFFS_OBJS} + +install: ${PROGS} + mkdir -p ${INSTBIN} + install -c ${PROGS} ${INSTBIN} + +clean: + rm -f *.o *.out *errs ${PROGS}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ffstools/tiffs-wrappers/installpath.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,7 @@ +/* + * Our mokoffs and pirffs wrappers exec the main tiffs binary; in order + * to do it efficiently without execvp etc, we hard-code the pathname + * where that binary is installed. + */ + +char tiffs_prog_pathname[] = "/usr/local/bin/tiffs";
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ffstools/tiffs-wrappers/mokoffs.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,86 @@ +/* + * mokoffs is a wrapper around tiffs: we pass the user's command along, + * together with any options, but insert the 64x7 FFS organization argument + * automatically. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> + +extern char tiffs_prog_pathname[]; + +char *imgfile; +char *aopt, *ropt; +int fflag; +char **passon_argv; +int passon_argc; +int output_argc; +char **output_argv; + +main(argc, argv) + char **argv; +{ + extern int optind; + extern char *optarg; + int c; + char **sp, **dp; + + while ((c = getopt(argc, argv, "+a:fr:")) != EOF) + switch (c) { + case 'a': + aopt = optarg; + continue; + case 'f': + fflag++; + continue; + case 'r': + ropt = optarg; + continue; + default: +usage: fprintf(stderr, + "usage: %s [global-options] <imgfile> <op> ...\n", + argv[0]); + exit(1); + } + if (argc - optind < 2) + goto usage; + imgfile = argv[optind++]; + passon_argv = argv + optind; + passon_argc = argc - optind; + + output_argc = passon_argc + 3; + if (fflag) + output_argc++; + if (aopt) + output_argc += 2; + if (ropt) + output_argc += 2; + output_argv = malloc(sizeof(char *) * (output_argc + 1)); + if (!output_argv) { + perror("malloc for tiffs argument list"); + exit(1); + } + dp = output_argv; + *dp++ = "tiffs"; + if (fflag) + *dp++ = "-o0x380000"; + if (aopt) { + *dp++ = "-a"; + *dp++ = aopt; + } + if (ropt) { + *dp++ = "-r"; + *dp++ = ropt; + } + *dp++ = imgfile; + *dp++ = "64x7"; + for (sp = passon_argv; *sp; sp++) + *dp++ = *sp; + *dp = 0; + execvp(tiffs_prog_pathname, output_argv); + perror(tiffs_prog_pathname); + exit(1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ffstools/tiffs-wrappers/pirffs.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,78 @@ +/* + * pirffs is a wrapper around tiffs: we pass the user's command along, + * together with any options, but insert the 256x18 FFS organization argument + * automatically. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> + +extern char tiffs_prog_pathname[]; + +char *imgfile; +char *aopt, *ropt; +char **passon_argv; +int passon_argc; +int output_argc; +char **output_argv; + +main(argc, argv) + char **argv; +{ + extern int optind; + extern char *optarg; + int c; + char **sp, **dp; + + while ((c = getopt(argc, argv, "+a:r:")) != EOF) + switch (c) { + case 'a': + aopt = optarg; + continue; + case 'r': + ropt = optarg; + continue; + default: +usage: fprintf(stderr, + "usage: %s [global-options] <imgfile> <op> ...\n", + argv[0]); + exit(1); + } + if (argc - optind < 2) + goto usage; + imgfile = argv[optind++]; + passon_argv = argv + optind; + passon_argc = argc - optind; + + output_argc = passon_argc + 3; + if (aopt) + output_argc += 2; + if (ropt) + output_argc += 2; + output_argv = malloc(sizeof(char *) * (output_argc + 1)); + if (!output_argv) { + perror("malloc for tiffs argument list"); + exit(1); + } + dp = output_argv; + *dp++ = "tiffs"; + if (aopt) { + *dp++ = "-a"; + *dp++ = aopt; + } + if (ropt) { + *dp++ = "-r"; + *dp++ = ropt; + } + *dp++ = imgfile; + *dp++ = "256x18"; + for (sp = passon_argv; *sp; sp++) + *dp++ = *sp; + *dp = 0; + execvp(tiffs_prog_pathname, output_argv); + perror(tiffs_prog_pathname); + exit(1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lcdemu/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,17 @@ +CC= gcc +CFLAGS= -O2 +PROG= fc-lcdemu +OBJS= globals.o main.o process.o window.o ximage.o xrm.o +INSTBIN=/usr/local/bin + +all: ${PROG} + +${PROG}: ${OBJS} + ${CC} ${CFLAGS} -o $@ ${OBJS} -lX11 + +install: ${PROG} + mkdir -p ${INSTBIN} + install -c ${PROG} ${INSTBIN} + +clean: + rm -f *.o *.out *errs ${PROG}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lcdemu/globals.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,20 @@ +/* + * LCDemu based on HECterm by the same author + * Definitions of global variables + */ + +#include <X11/Xlib.h> +#include <X11/Xresource.h> +#include <X11/Xutil.h> + +char *progbasename, *proginstancename; +char *mydisplayname; +Display *mydisplay; +Window mainwindow; +GC mainwingc; +int display_depth; + +XrmDatabase xrmdb_defaults, xrmdb_displayres, xrmdb_cmdline; +XrmQuark xrmquark_topclass, xrmquark_topinstance; + +XImage *(*convert_function)();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lcdemu/globals.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,16 @@ +/* + * LCDemu based on HECterm by the same author + * External declaratiions for global variables + */ + +extern char *progbasename, *proginstancename; +extern char *mydisplayname; +extern Display *mydisplay; +extern Window mainwindow; +extern GC mainwingc; +extern int display_depth; + +extern XrmDatabase xrmdb_defaults, xrmdb_displayres, xrmdb_cmdline; +extern XrmQuark xrmquark_topclass, xrmquark_topinstance; + +extern XImage *(*convert_function)();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lcdemu/main.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,166 @@ +/* + * LCDemu main module + */ + +#include <sys/types.h> +#include <sys/errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <X11/Xlib.h> +#include <X11/Xresource.h> +#include <X11/Xutil.h> +#include "globals.h" + +main(argc, argv) + char **argv; +{ + XrmInitialize(); + process_cmdline(argc, argv); + open_display(); + init_image_conversion(); + load_resources(); + create_our_window(); + set_initial_window_title(); + set_initial_icon_name(); + create_mainwin_gc(); + XMapWindow(mydisplay, mainwindow); + XFlush(mydisplay); + + mainloop(); + /* NOTREACHED */ +} + +process_cmdline(argc, argv) + char **argv; +{ + register char **ap, *opt; + char *rhost, *ruser; + int len; + + if (argc < 1) { + fprintf(stderr, "fc-lcdemu: invalid invokation\n"); + exit(1); + } + opt = rindex(argv[0], '/'); + if (opt) + progbasename = opt + 1; + else + progbasename = argv[0]; + proginstancename = progbasename; + for (ap = argv+1; *ap; ) { + if (**ap == '-') + opt = *ap++; + else + break; + if (!strcmp(opt, "-display")) { + if (!*ap) { +argreq: fprintf(stderr, "%s: %s requires an argument\n", + progbasename, opt); + exit(1); + } + mydisplayname = *ap++; + continue; + } + if (!strcmp(opt, "-name")) { + if (!*ap) + goto argreq; + proginstancename = *ap++; + continue; + } + if (!strcmp(opt, "-geometry") || !strcmp(opt, "-geom")) { + if (!*ap) + goto argreq; + XrmPutStringResource(&xrmdb_cmdline, "LCDemu.geometry", + *ap++); + continue; + } + if (!strcmp(opt, "-iconic")) { + XrmPutStringResource(&xrmdb_cmdline, "LCDemu.iconic", + "on"); + continue; + } + if (!strcmp(opt, "-title")) { + if (!*ap) + goto argreq; + XrmPutStringResource(&xrmdb_cmdline, "LCDemu.title", + *ap++); + continue; + } + if (!strcmp(opt, "-borderwidth") || !strcmp(opt, "-bw")) { + if (!*ap) + goto argreq; + XrmPutStringResource(&xrmdb_cmdline, "*borderWidth", + *ap++); + continue; + } + if (!strcmp(opt, "-bordercolor") || !strcmp(opt, "-bd")) { + if (!*ap) + goto argreq; + XrmPutStringResource(&xrmdb_cmdline, "*borderColor", + *ap++); + continue; + } + if (!strcmp(opt, "-xrm")) { + if (!*ap) + goto argreq; + XrmPutLineResource(&xrmdb_cmdline, *ap++); + continue; + } + fprintf(stderr, "%s: %s: unrecognized option\n", progbasename, + opt); + exit(1); + } +} + +open_display() +{ + if (!mydisplayname) + mydisplayname = getenv("DISPLAY"); + if (!mydisplayname) { + fprintf(stderr, "%s: no X display available\n", progbasename); + exit(1); + } + mydisplay = XOpenDisplay(mydisplayname); + if (!mydisplay) { + fprintf(stderr, "%s: unable to open display %s\n", progbasename, + mydisplayname); + exit(1); + } +} + +mainloop() +{ + register int i, cc; + XEvent event; + fd_set readfds; + int maxfd; + char buf[1024]; + + maxfd = ConnectionNumber(mydisplay) + 1; + for (;;) { + cc = XPending(mydisplay); + for (i = 0; i < cc; i++) + XNextEvent(mydisplay, &event); + XFlush(mydisplay); + FD_ZERO(&readfds); + FD_SET(0, &readfds); + FD_SET(ConnectionNumber(mydisplay), &readfds); + i = select(maxfd, &readfds, NULL, NULL, NULL); + if (i < 0) { + if (errno == EINTR) + continue; + perror("select"); + exit(1); + } + if (FD_ISSET(0, &readfds)) { + cc = read(0, buf, sizeof buf); + if (cc > 0) + input_on_stdin(buf, cc); + else + exit(0); + XFlush(mydisplay); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lcdemu/process.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,108 @@ +/* + * Processing of LCD output (input to us) + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> +#include <strings.h> +#include <X11/Xlib.h> +#include <X11/Xresource.h> +#include <X11/Xutil.h> +#include "globals.h" + +#define MAX_WIDTH 176 + +static unsigned +hexdecode(str) + char *str; +{ + unsigned accum = 0; + int i, c, n; + + for (i = 0; i < 4; i++) { + c = str[i]; + if (isdigit(c)) + n = c - '0'; + else if (isupper(c)) + n = c - 'A' + 10; + else + n = c - 'a' + 10; + accum <<= 4; + accum |= n; + } + return(accum); +} + +process_input_line(line) + char *line; +{ + int blitrow, blitcol, npix; + uint16_t pix16[MAX_WIDTH]; + char *cp; + XImage *xi; + + for (cp = line; isspace(*cp); cp++) + ; + if (!isdigit(*cp)) { +inv: fprintf(stderr, "fc-lcdemu: invalid input line\n"); + exit(1); + } + blitrow = atoi(cp); + while (isdigit(*cp)) + cp++; + if (!isspace(*cp)) + goto inv; + while (isspace(*cp)) + cp++; + if (!isdigit(*cp)) + goto inv; + blitcol = atoi(cp); + while (isdigit(*cp)) + cp++; + if (!isspace(*cp)) + goto inv; + while (isspace(*cp)) + cp++; + if (!isxdigit(*cp)) + goto inv; + for (npix = 0; *cp; ) { + if (!isxdigit(cp[0]) || !isxdigit(cp[1]) || + !isxdigit(cp[2]) || !isxdigit(cp[3])) + goto inv; + if (npix >= MAX_WIDTH) { + fprintf(stderr, + "fc-lcdemu error: input line exceeds MAX_WIDTH of %d pixels\n", + MAX_WIDTH); + exit(1); + } + pix16[npix++] = hexdecode(cp); + cp += 4; + } + xi = convert_function(pix16, npix); + XPutImage(mydisplay, mainwindow, mainwingc, xi, 0, 0, blitcol, blitrow, + npix, 1); + XDestroyImage(xi); +} + +input_on_stdin(inbuf, incount) + char *inbuf; +{ + char *input_end = inbuf + incount; + static char linebuf[1024]; + static int linesz; + char *cp; + + for (cp = inbuf; cp < input_end; cp++) { + if (*cp == '\n') { + linebuf[linesz] = '\0'; + process_input_line(linebuf); + linesz = 0; + continue; + } + if (linesz < sizeof(linebuf) - 1) + linebuf[linesz++] = *cp; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lcdemu/window.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,157 @@ +/* + * LCDemu based on HECterm by the same author + * X11 window creation functions + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <X11/Xlib.h> +#include <X11/Xresource.h> +#include <X11/Xutil.h> +#include "globals.h" + +extern char *xrm_lookup(); + +create_our_window() +{ + XrmQuark instquarks[3], classquarks[3]; + register char *cp; + register int i, geomask; + int pixwidth, pixheight, xpos, ypos; + XSetWindowAttributes xswa; + u_long xswamask; + XColor bdcolor; + XClassHint xclasshint; + XWMHints wmhints; + XSizeHints wm_normal_hints; + + /* Determine our geometry */ + instquarks[0] = xrmquark_topinstance; + classquarks[0] = xrmquark_topclass; + classquarks[1] = instquarks[1] = XrmStringToQuark("geometry"); + instquarks[2] = classquarks[2] = NULLQUARK; + cp = xrm_lookup(instquarks, classquarks); + if (cp) { + geomask = XParseGeometry(cp, &xpos, &ypos, &pixwidth, + &pixheight); + free(cp); + } else + geomask = 0; + if (!(geomask & WidthValue)) + pixwidth = 176; + if (!(geomask & HeightValue)) + pixheight = 220; + if (!(geomask & XValue)) + xpos = 0; + else if (geomask & XNegative) + xpos += DisplayWidth(mydisplay, DefaultScreen(mydisplay)) - + pixwidth; + if (!(geomask & YValue)) + ypos = 0; + else if (geomask & YNegative) + ypos += DisplayHeight(mydisplay, DefaultScreen(mydisplay)) - + pixheight; + /* fill out XSetWindowAttributes */ + xswa.event_mask = 0; /* not interested in any events */ + xswamask = CWEventMask; + /* border color */ + classquarks[1] = instquarks[1] = XrmStringToQuark("borderColor"); + cp = xrm_lookup(instquarks, classquarks); + if (cp) { + i = XParseColor(mydisplay, DefaultColormap(mydisplay, + DefaultScreen(mydisplay)), cp, &bdcolor); + free(cp); + if (i) { + i = XAllocColor(mydisplay, DefaultColormap(mydisplay, + DefaultScreen(mydisplay)), &bdcolor); + if (i) { + xswa.border_pixel = bdcolor.pixel; + xswamask |= CWBorderPixel; + } + } + } + /* border width */ + classquarks[1] = instquarks[1] = XrmStringToQuark("borderWidth"); + cp = xrm_lookup(instquarks, classquarks); + if (cp) { + i = atoi(cp); + free(cp); + } else + i = 2; + /* go for it! */ + mainwindow = XCreateWindow(mydisplay, DefaultRootWindow(mydisplay), + xpos, ypos, pixwidth, pixheight, i, CopyFromParent, + InputOutput, CopyFromParent, xswamask, &xswa); + /* set window manager properties */ + xclasshint.res_name = proginstancename; + xclasshint.res_class = "LEDemu"; + XSetClassHint(mydisplay, mainwindow, &xclasshint); + wmhints.flags = InputHint | StateHint; + wmhints.input = False; + classquarks[1] = instquarks[1] = XrmStringToQuark("iconic"); + cp = xrm_lookup(instquarks, classquarks); + if (cp) { + i = parse_boolean_resource(cp); + free(cp); + } else + i = 0; + wmhints.initial_state = i ? IconicState : NormalState; + XSetWMHints(mydisplay, mainwindow, &wmhints); + if (geomask & (WidthValue|HeightValue)) + wm_normal_hints.flags = USSize; + else + wm_normal_hints.flags = PSize; + if (geomask & (XValue|YValue)) + wm_normal_hints.flags |= USPosition; + XSetWMNormalHints(mydisplay, mainwindow, &wm_normal_hints); +} + +set_initial_window_title() +{ + XrmQuark instquarks[3], classquarks[3]; + register char *cp; + char buf[256]; + + instquarks[0] = xrmquark_topinstance; + classquarks[0] = xrmquark_topclass; + instquarks[1] = XrmStringToQuark("title"); + classquarks[1] = XrmStringToQuark("Title"); + instquarks[2] = classquarks[2] = NULLQUARK; + cp = xrm_lookup(instquarks, classquarks); + if (cp) { + XStoreName(mydisplay, mainwindow, cp); + free(cp); + return; + } + XStoreName(mydisplay, mainwindow, "Emulated LCD"); +} + +set_initial_icon_name() +{ + XrmQuark instquarks[3], classquarks[3]; + register char *cp; + + instquarks[0] = xrmquark_topinstance; + classquarks[0] = xrmquark_topclass; + instquarks[1] = XrmStringToQuark("iconName"); + classquarks[1] = XrmStringToQuark("IconName"); + instquarks[2] = classquarks[2] = NULLQUARK; + cp = xrm_lookup(instquarks, classquarks); + if (cp) { + XSetIconName(mydisplay, mainwindow, cp); + free(cp); + return; + } + XSetIconName(mydisplay, mainwindow, proginstancename); +} + +create_mainwin_gc() +{ + XGCValues xgcval; + + xgcval.graphics_exposures = False; + mainwingc = XCreateGC(mydisplay, mainwindow, GCGraphicsExposures, + &xgcval); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lcdemu/ximage.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,59 @@ +/* + * LCDemu based on HECterm by the same author + * XImage conversion muck + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <X11/Xlib.h> +#include <X11/Xresource.h> +#include <X11/Xutil.h> +#include "globals.h" + +XImage * +convert_image_depth24(input, npix) + uint16_t *input; + int npix; +{ + uint32_t *imgbuf; + int i, in, r, g, b; + XImage *img; + + imgbuf = malloc(npix * 4); + if (!imgbuf) { + perror("malloc"); + exit(1); + } + for (i = 0; i < npix; i++) { + in = input[i]; + r = (in & 0xF800) << 8; + g = (in & 0x07E0) << 5; + b = (in & 0x001F) << 3; + imgbuf[i] = r | g | b; + } + img = XCreateImage(mydisplay, CopyFromParent, display_depth, ZPixmap, + 0, (char *) imgbuf, npix, 1, 32, 0); + if (!img) { + perror("XCreateImage"); + exit(1); + } + return(img); +} + +init_image_conversion() +{ + display_depth = DefaultDepth(mydisplay, DefaultScreen(mydisplay)); + switch (display_depth) { + case 24: + convert_function = convert_image_depth24; + break; + default: + fprintf(stderr, +"error: fc-lcdemu has not been adapted for X11 depth != 24, yours is %d\n", + display_depth); + exit(1); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lcdemu/xrm.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,97 @@ +/* + * LCDemu based on HECterm by the same author + * Xrm functions + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <X11/Xlib.h> +#include <X11/Xresource.h> +#include <X11/Xutil.h> +#include "globals.h" + +static char appdefaults_pathname[] = + "/usr/local/share/freecalypso/lcdemu-defaults"; + +load_resources() +{ + xrmquark_topclass = XrmStringToQuark("LCDemu"); + xrmquark_topinstance = XrmStringToQuark(proginstancename); + xrmdb_defaults = XrmGetFileDatabase(appdefaults_pathname); + xrmdb_displayres = + XrmGetStringDatabase(XResourceManagerString(mydisplay)); +} + +/* + * The following function looks up a resource in all of our databases + * and returns a pointer (char *) to the value in a malloced buffer that + * can be freed when it is no longer needed. My reading of X11R4 + * documentation indicates that resource values returned from Xrm functions + * are not necessarily NUL-terminated (no claim is made that they are + * and XrmValue structure has a size field), which is why I copy to + * my own buffer and NUL-terminate it there. + * + * Returns NULL pointer if not found in any of the databases. + */ +char * +xrm_lookup(instquarks, classquarks) + XrmQuark *instquarks, *classquarks; +{ + XrmRepresentation reptype; + XrmValue value; + register char *buf; + + if (XrmQGetResource(xrmdb_cmdline, instquarks, classquarks, &reptype, + &value)) + goto found; + if (XrmQGetResource(xrmdb_displayres, instquarks, classquarks, &reptype, + &value)) + goto found; + if (XrmQGetResource(xrmdb_defaults, instquarks, classquarks, &reptype, + &value)) + goto found; + return(NULL); +found: buf = malloc(value.size + 1); + if (!buf) { + perror("malloc"); + exit(1); + } + bcopy(value.addr, buf, value.size); + buf[value.size] = '\0'; + return(buf); +} + +parse_boolean_resource(str) + register char *str; +{ + if (!strcasecmp(str, "on") || !strcasecmp(str, "true") || + !strcasecmp(str, "yes")) + return(1); + if (!strcasecmp(str, "off") || !strcasecmp(str, "false") || + !strcasecmp(str, "no")) + return(0); + return(atoi(str)); +} + +get_boolean_resource(resource, def) + char *resource; + int def; +{ + XrmQuark instquarks[3], classquarks[3]; + register char *cp; + register int i; + + instquarks[0] = xrmquark_topinstance; + classquarks[0] = xrmquark_topclass; + classquarks[1] = instquarks[1] = XrmStringToQuark(resource); + instquarks[2] = classquarks[2] = NULLQUARK; + cp = xrm_lookup(instquarks, classquarks); + if (cp) { + i = parse_boolean_resource(cp); + free(cp); + } else + i = def; + return(i); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/CHANGES Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,31 @@ +Changes from loadtools-r2 to fc-host-tools-r3: + +* Implemented support for Mot C1xx (Compal) targets in addition to the + previously supported Openmoko and Pirelli. Compal phones have different + flash, require a different procedure for gaining code download access, and + have additional bricking concerns. + +* Updated loadagent includes Intel flash support and ABB commands needed for + Compal phones. + +* The range of IRAM addresses used by loadagent changed to allow gsm-fw + ramImage builds (chain-loaded with fc-xram) to load their IRAM code section + directly into place. + +* Loadtool's flash program-bin command now automatically performs a CRC-32 + verification after programming. + +* Miscellaneous minor polish. + +Changes from loadtools-r1 to loadtools-r2: + +* A flash ID check has been implemented in fc-loadtool, invoked automatically + before doing any erase or program operations, or explicitly at any time with + the flash info command. This check ensures that the type of flash chip in + the target GSM device is the same as what loadtool thinks it is, based on the + hardware parameters file. + +* fc-xram command line syntax changed slightly in order to support immediate + passing of the serial line to rvinterf/rvtdump. + +* Miscellaneous minor polish.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,43 @@ +CC= gcc +CFLAGS= -O2 +PROGS= fc-iram fc-loadtool fc-xram fc-compalram +INSTBIN=/usr/local/bin + +EXTRA_OBJ= compalload.o + +COMPALRAM_OBJS= compalload.o compalram.o defpath.o sercomm.o ttypassthru.o + +IRAM_OBJS= defpath.o hexdecode.o hwparam.o hwparamstubs.o romload.o \ + sercomm.o sertool.o srecreader.o ttypassthru.o ${EXTRA_OBJ} + +LOADTOOL_OBJS= crc32tab.o defpath.o flashops.o flcmplboot.o flmain.o flmisc.o \ + flprogbin.o flprogsrec.o flutil.o hexdecode.o hwparam.o \ + labaud.o ltdispatch.o ltdump.o ltexit.o lthelp.o ltmain.o \ + ltmisc.o ltpassthru.o ltscript.o romload.o sercomm.o \ + srecreader.o tpinterf.o tpinterf2.o tpinterf3.o ${EXTRA_OBJ} + +XRAM_OBJS= chainload.o clmain.o defpath.o hexdecode.o hwparam.o \ + hwparamstubs.o initscript.o labaud.o romload.o sercomm.o \ + srecreader.o tpinterf.o ttypassthru.o ${EXTRA_OBJ} + +all: ${PROGS} + +fc-compalram: ${COMPALRAM_OBJS} + ${CC} ${CFLAGS} -o $@ ${COMPALRAM_OBJS} + +fc-iram: ${IRAM_OBJS} + ${CC} ${CFLAGS} -o $@ ${IRAM_OBJS} + +fc-loadtool: ${LOADTOOL_OBJS} + ${CC} ${CFLAGS} -o $@ ${LOADTOOL_OBJS} + +fc-xram: ${XRAM_OBJS} + ${CC} ${CFLAGS} -o $@ ${XRAM_OBJS} + +install: + mkdir -p ${INSTBIN} + install -c ${PROGS} ${INSTBIN} + ./install-helpers.sh + +clean: + rm -f *.o *.out *errs ${PROGS}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/README Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,265 @@ +The set of host tools built in this directory consists of: + +fc-loadtool The tool for operating on Calypso GSM devices at a low + level. After "breaking" into the target GSM device in + its boot process and getting FreeCalypso loadagent + running on the target (out of Calypso internal RAM, aka + IRAM), loadtool presents an interactive command prompt + with commands for peeking and poking registers and most + importantly, reading and writing any part of the + device's non-volatile flash memory. + +fc-iram & fc-xram These utilities are intended for FreeCalypso developers + only. They load an S-record code image into IRAM or + XRAM, respectively, induce a transfer of control to the + loaded code, and then drop into a serial line pass-thru + mode for the operator to interact with the thus loaded + target code. + +The currently supported target devices are the Compal family of basic +dumbphones, the Openmoko GTA0x GSM modem and the Pirelli DP-L10 feature phone. + +All tools in the FreeCalypso loadtools suite work by feeding pieces of code to +the target device as it boots, preventing the booting of its regular firmware +and diverting control to these externally-loaded code pieces. These pieces of +ARM7 target code need to be installed on the host system running loadtools, +normally in /usr/local/share/freecalypso: + +loadagent This is the "agent" code that runs on the target device when + fc-loadtool is operating on it: loadtool carries out its + operations by sending commands to loadagent. There is only one + version of loadagent for all currently supported Calypso + targets: loadagent does not access any resources outside of the + Calypso chip itself unless commanded to do so, and loadtool + supports different target devices with different hardware + configurations by sending different commands to loadagent as + appropriate. + +compalstage For Compal phones only: a little piece of code that is fed to + the original fw's bootloader via the serial download protocol + provided by the latter; it re-enables the Calypso chip boot ROM + and jumps to it, allowing our loadagent to be loaded in the + same way as on freedom-enabled devices. + +If you are working with a development snapshot of the freecalypso-sw source +tree, you will need to compile and install a GNU cross-compiler toolchain +targeting ARM7 (see ../toolchain) and then use that toolchain to compile +loadagent and compalstage (see ../target-utils) before you can successfully use +loadtools to operate on a target device. End-user oriented releases of +FreeCalypso host tools will include prebuilt loadagent and compalstage binaries +in the target-binaries subdirectory. + +Installing +========== + +Just run 'make' and 'make install' as usual. If the target-binaries directory +is present, your installation will be complete and ready to use. If you are +building these pieces yourself from source, do a 'make' and 'make install' in +../target-utils, after you have the ARM7 gcc toolchain installed and working. + +Basic usage +=========== + +The steps for bringing up fc-loadtool to operate on a target Calypso device are +as follows: + +1. If you are using a USB serial adapter, or operating on a Pirelli phone that + has one built in, connect the USB side first so that the necessary + /dev/ttyUSB* device node appears. + +2. Run fc-loadtool like this: + + fc-loadtool $TARGETOPT /dev/ttyXXX + + Change /dev/ttyXXX to the actual serial port you are using, and change + $TARGETOPT to: + + Device Needed options + ----------------------------------- + Mot C11x/123 -h compal + Mot C139/140 -h compal -c 1003 + Mot C155/156 -h c155 + Openmoko GTA02 -h gta02 + Pirelli DP-L10 -h pirelli + +3. Cause the target device to execute its boot path. Openmoko GTA0x and + Pirelli DP-L10 targets have the Calypso boot ROM enabled, and will interrupt + and divert their normal boot path when they "hear" the beacons which + fc-loadtool will be sending down the serial line. Compal phones have this + boot ROM disabled at the board level, but their standard firmware includes a + flash-resident bootloader that offers a different way of interrupting the + boot path and loading code over the serial line; fc-loadtool will be set up + to speak the latter protocol when run with the corresponding options from + the table above. + +You will see messages showing fc-loadtool's progress with feeding first +compalstage (if needed), then loadagent (always needed) to the target device, +followed by some target-specific initialization done via loadagent commands. +If all of the above succeeds, you will land at a loadtool> prompt. Type +'help', and it will guide you from there. Alternatively, you can familiarize +yourself with loadtool commands and operations without actually running it by +reading the loadtool.help text file. + +Command line options +==================== + +The fc-loadtool command lines shown above will usually be sufficient. However, +here is the complete command line description for all 3 tools: + +fc-iram [options] ttyport iramimage.srec +fc-xram [options] ttyport xramimage.srec [2ndprog] +fc-loadtool [options] ttyport + +The available options are common for all 3 utilities, with a few noted +exceptions: + +-a /path/to/loadagent + + This option applies only to fc-loadtool and fc-xram. It specifies the + pathname at which the required loadagent.srec image should be sought, + overriding the compiled-in default. + +-b baud + + This option is common for all 3 utilities. It selects the baud rate + to be used when pushing the IRAM image to the Calypso boot ROM. In the + case of fc-iram, the selected baud rate will be in effect when the + loaded IRAM image is jumped to and fc-iram drops into the serial tty + pass-thru mode; in the case of fc-loadtool, it will be the initial baud + rate for communicating with loadagent, which can be switched later with + the baud command. The default is 115200 baud. + +-B baud + + This option is specific to fc-xram. It selects the baud rate to be + used when pushing the XRAM image to loadagent. If no -B option is + specified, fc-xram will communicate with loadagent at the same baud + rate that was used to load loadagent itself via the Calypso boot ROM + download protocol, i.e., the rate selected with -b, defaulting to + 115200 baud if no -b option was given either. Neither -b nor -B + affects the baud rate that will be in effect when the loaded XRAM image + is jumped to and fc-xram drops into the serial tty pass-thru mode: that + baud rate independently defaults to 115200 baud and can only be changed + with the -r option. + +-c <compalstage flavor> + + This option is common for all 3 utilities. It directs the tools to + perform the Compal loading stage before proceeding with the Calypso + boot ROM serial protocol, and selects the "flavor" of compalstage to + use. As you can see in the source, compalstage is built in 3 different + versions, for different C1xx models which exhibit different quirks. + + This option overrides the compal-stage setting given in the hardware + parameter file selected with -h or -H; the -c or -C option must be given + after -h or -H in order to take effect. -c none disables the Compal + stage and causes the tools to proceed directly to the Calypso boot ROM + phase, even on targets for which the hardware parameter file specifies + compal-stage. + +-C /path/to/compalstage-binary + + This option is just like -c, except that the given argument is used + directly as the compalstage binary file pathname (absolute or relative) + without checking or alteration. + +-h hwtype + + This option is common for all 3 utilities. It selects the specific + target device configuration to be used. More precisely, it constructs + a pathname of the form /usr/local/share/freecalypso/%s.config, where %s + is the argument given to this option, and uses that file as the hardware + parameter file. + + The hardware configurations known to the present release of FreeCalypso + loadtools are listed in the "Basic usage" section above. + +-H /path/to/hwparam-file + + This option is just like -h, except that the given argument is used + directly as the hardware parameter file pathname (absolute or relative) + without alteration. + +-i num + + This option is common for all 3 utilities. It specifies the interval + in milliseconds at which the tool will send "please interrupt the boot + process" beacons out the serial port, hoping to catch the Calypso + internal boot ROM. The default is 13 ms. + +-n + + This option does anything only when loadtools have been compiled to run + on GTA0x AP (see the corresponding section below). If you've compiled + loadtools with the -DGTA0x_AP_BUILD option, it has an effect of making + each tool automatically toggle the modem power control upon startup, + removing the need for manual sequencing of the Calypso boot process. + This -n option suppresses that action, making the AP build behave like + the standard build in this regard. + +-r baud (fc-loadtool) + + This option is specific to fc-loadtool. It causes the tool to skip its + normal steps of feeding loadagent and possibly compalstage to the target + via special serial protocols, and instead assume that the target is + already running loadagent, communicating at the specified baud rate. + In other words, reattach to an already running loadagent. Use this + option if your fc-loadtool session has been terminated ungracefully and + you would like to reattach and resume, rather than forcibly reset the + target by yanking and reinserting the battery and restart from the + beginning. + +-r baud (fc-xram) + + This option is specific to fc-xram. It selects the serial line baud + rate which should be set just before the loaded XRAM image is jumped + to; the default is 115200 baud. + +fc-xram 2nd program invokation +============================== + +The fc-xram utility can take two possible actions after it has loaded the +specified S-record image into XRAM: + +* The default action, in the absence of additional command line arguments, is + to drop into a serial tty pass-thru mode, just like fc-iram. + +* The alternative action is to invoke a 2nd program and pass the serial + communication channel to it. This 2nd program invokation facility is intended + primarily for passing the serial communication channel to rvinterf or rvtdump + from the FreeCalypso software suite, not for launching any arbitrary 3rd-party + programs from fc-xram. + +The intended usage scenario is that one builds a version of the FreeCalypso GSM +firmware (or some subset thereof, such as an "in vivo" FFS editing agent) in the +ramImage configuration, fc-xram is used to load that ramImage into the target +device, and then the serial communication channel (RVTMUX) is immediately taken +over by rvinterf or rvtdump. + +Openmoko GTA0x +============== + +All of the above instructions assume that you are running these loadtools on a +general-purpose host system such as a GNU/Linux PC or laptop, and will +potentially use them to operate on multiple Calypso targets of different kinds. +If instead you are building loadtools to run on the application processor of a +smartphone such as Openmoko GTA0x, then it makes no sense for that special build +of loadtools to support any target other than the specific modem in that +smartphone. Loadtools can be built with compalstage support excluded and with +GTA0x-specific modem power control included instead. This build will still +include a bunch of functions of no relevance to GTA0x, but oh well.. + +To build loadtools for the GTA0x AP, you'll need to make the following +modifications to the Makefile: + +* Change the CC= line to point to the appropriate cross-compiler (which you'll + need to provide yourself); + +* Change the CFLAGS= line: add the right options to target the ARM920T core in + the GTA0x AP (e.g., -march=armv4t -mtune=arm920t), and add -DGTA0x_AP_BUILD + to enable some code that makes sense only when running on the GTA0x AP. + +* Change EXTRA_OBJ= from listing compalload.o to listing compaldummy.o and + gtapower.o instead. + +See gta-ap-build.sed for an example.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/README.old Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,271 @@ +You are looking at the source for the FreeCalypso loadtools package. You may +have downloaded it either as a separate package or as part of the larger +freecalypso-sw suite. + +The tools in this package are written to run on some Unix/Linux machine +(normally a PC/Linux desktop or laptop) that acts as a host for operating on +Calypso target devices. All of these tools communicate with the Calypso target +through a serial port; each tool begins its operation by sending special byte +sequences to this serial port which are designed to interrupt the Calypso +device boot process in the ROM bootloader. + +Three utilities are currently built as part of FreeCalypso loadtools: + +fc-iram & fc-xram These utilities are intended for FreeCalypso developers + only. They load an S-record code image into IRAM or + XRAM, respectively, induce a transfer of control to the + loaded code, and then drop into a serial line pass-thru + mode for the operator to interact with the thus loaded + target code. + +fc-loadtool This utility is intended for both developers and end + users. After establishing communication with the + target, fc-loadtool drops into interactive operation. + Once at the loadtool> prompt, you can peek and poke + registers, and most importantly, dump (read) and load + (program) the flash memory of the target device. + +Loadagent +========= + +Both fc-loadtool and fc-xram work by first feeding a FreeCalypso-developed +program called loadagent to the Calypso ROM bootloader; all further operations +(loading code into XRAM or flash) are done via this loadagent. An S-record +image of the loadagent program is required for fc-loadtool and fc-xram to work. +That program is in turn built with the ARM7 toolchain. + +If you are working with the full freecalypso-sw suite, you presumably already +have the proper ARM7 toolchain built and installed. To build loadagent, simply +run 'make' in the ../target-utils tree. + +If you have downloaded a separately-packaged version of FreeCalypso loadtools, +the package should have a prebuilt loadagent.srec image included, sparing +non-developer users the nontrivial hurdle of having to build and install a +special cross-compilation toolchain. The same loadagent binary is designed to +work on all supported Calypso targets. + +Building and installing loadtools +================================= + +Normally the machine on which you build and install fc-loadtools would be your +PC/Linux desktop or laptop, the system you would use to program or otherwise +interact with Calypso phones by way of appropriate USB-to-phone cables. Just +like loadagent, the host utilities you are going to build and install aren't +specific to a particular target device; instead you will select the target +device at run time via a command line option. Hence you can build and install +the host utilities (usual 'make' and 'make install') without limiting your +setup to just one target phone type. + +However, if your intended target device is an Openmoko GTA02 (or GTA01) +smartphone, there is one additional complication: one cannot directly access +the Calypso part of these phones from the outside without going through the +phone's application processor first. If you would like to use fc-loadtool to +read or write the GSM flash memory of your GTA0x (load a different firmware +image, dump the flash file system for backup or examination, restore a previous +backup etc), there are two ways to do it: + +1. The recommended way for FreeCalypso developers is to get a special serial + cable (low voltage, as in 3.3V or lower - *NOT* RS-232 levels - please don't + fry your precious phone!) that would plug into the 2.5mm jack on the left + side of the phone that is normally intended for a wired headset. This way + you can use your regular build of fc-loadtool (and fc-iram & fc-xram) on + your PC/Linux (or other) development host, no need to build anything for + GTA0x AP, and all communication happens directly between your development + host and the Calypso part of your target phone - not going through the AP + at all. You still need working software on the GTA0x AP to do battery + management, to power the Calypso block on and off, and to enable the headset + jack "download" path, but it is much less burdensome than having to do the + actual FreeCalypso work from the AP. + +Having the headset jack do double duty as a programming port is actually a +standard practice in the world of basic (non-smart) cellular phones, and +furthermore, the pinout used by FIC on the GTA0x phones just happens to be +exactly the same as that used by Compal/Motorola - hence the same headset jack +serial cables that are used by OsmocomBB with the latter phones (the famous +"T191 unlock cable") will also work for connecting from an external host +directly to the Calypso part of GTA0x phones. + +2. If you are an end user who simply wishes to reflash a different GSM firmware + image, it can be done from inside the phone (from the AP) without having to + acquire special hardware (as in the cable described above). However, the + trade-off is that in return for saving on the special hardware, you have to + do more work on the software. You will have to use a cross-compiler + targeting the ARM/Linux AP environment (*not* the ARM7 cross-compiler used + for the GSM firmware itself!) to build fc-loadtools to run on the GTA0x AP. + +Building loadtools for GTA0x AP +=============================== + +If you've decided to build loadtools for the GTA0x AP, you'll need to make the +following modifications to the Makefile: + +* Change the CC= line to point to the appropriate cross-compiler (which you'll + need to provide yourself); + +* Change the CFLAGS= line: add the right options to target the ARM920T core in + the GTA0x AP (e.g., -march=armv4t -mtune=arm920t), and add -DGTA0x_AP_BUILD + to enable some code that makes sense only when running on the GTA0x AP. + +* Change EXTRA_OBJ= to EXTRA_OBJ=gtapower.o, i.e., add gtapower.c (compiling + into gtapower.o) to the build. + +See gta-ap-build.sed for an example. + +Running fc-loadtool +=================== + +Once you've got loadtools built and installed, you can run fc-loadtool +as follows: + +To operate on a Pirelli DP-L10 that appears as /dev/ttyUSB0: + +fc-loadtool -h pirelli /dev/ttyUSB0 + +The usb2serial chip inside the phone is bus-powered and will be visible as +/dev/ttyUSBx whether the phone battery is present or not. There are two ways +to break into the bootloader: + +1. Run the fc-loadtool command given above with the USB cable connected, but no + battery present. Once loadtool says "Sending beacons to <port>", insert the + battery. + +2. Connect the USB cable to a powered-on phone running its original factory + firmware. (If the phone was off, it will power up and boot in the "charging + only" mode - it is not possible for a Calypso/Iota phone to be completely + off when both the battery and the charging voltage are present.) Run + fc-loadtool as above - it will start sending its beacons, which will be + ignored by the running fw. Then execute the "power off" operation from the + UI (unlock the keypad, then press and hold the red button). The presence of + USB VBUS (used as the charging power source on this phone) will turn the + power-off into a reboot, and you'll break into the bootloader. + +To operate on the Calypso block of a GTA02, accessing it from an external +PC/Linux host via a USB-to-headset-jack serial cable that appears as +/dev/ttyUSB0: + +fc-loadtool -h gta02 /dev/ttyUSB0 + +Run the above command first, then power on the GSM modem from the AP - or power +it off, then on if it was on already. The "download" path needs to be enabled +(controlled from the AP) and fc-loadtool needs to be running on the external +host when the modem is powered on. + +To operate on the Calypso block of a GTA02, running fc-loadtool from inside the +phone, i.e., from the AP of the same GTA02: + +fc-loadtool -h gta02 /dev/ttySAC0 + +In this last scenario the specially built version of fc-loadtool running on the +AP takes care of manipulating the modem power to induce entry into the +bootloader, thus no extra manual steps are needed. + +See loadtool.help for a detailed description of the functionality and commands +that are available once loadtool is running and communicating with loadagent on +the target device. + +Command line options +==================== + +The fc-loadtool command lines shown above will usually be sufficient. However, +here is the complete command line description for all 3 tools: + +fc-iram [options] ttyport iramimage.srec +fc-xram [options] ttyport xramimage.srec [2ndprog] +fc-loadtool [options] ttyport + +The available options are common for all 3 utilities, with a few noted +exceptions: + +-a /path/to/loadagent + + This option applies only to fc-loadtool and fc-xram. It specifies the + pathname at which the required loadagent.srec image should be sought, + overriding the compiled-in default. + +-b baud + + This option is common for all 3 utilities. It selects the baud rate + to be used when pushing the IRAM image to the Calypso boot ROM. In the + case of fc-iram, the selected baud rate will be in effect when the + loaded IRAM image is jumped to and fc-iram drops into the serial tty + pass-thru mode; in the case of fc-loadtool, it will be the initial baud + rate for communicating with loadagent, which can be switched later with + the baud command. The default is 115200 baud. + +-B baud + + This option is specific to fc-xram. It selects the baud rate to be + used when pushing the XRAM image to loadagent. If no -B option is + specified, fc-xram will communicate with loadagent at the same baud + rate that was used to load loadagent itself via the Calypso boot ROM + download protocol, i.e., the rate selected with -b, defaulting to + 115200 baud if no -b option was given either. Neither -b nor -B + affects the baud rate that will be in effect when the loaded XRAM image + is jumped to and fc-xram drops into the serial tty pass-thru mode: that + baud rate independently defaults to 115200 baud and can only be changed + with the -r option. + +-h hwtype + + This option is common for all 3 utilities. It selects the specific + target device configuration to be used. More precisely, it constructs + a pathname of the form /usr/local/share/freecalypso/%s.config, where %s + is the argument given to this option, and uses that file as the hardware + parameters file. + + The hardware configurations known to the present release of FreeCalypso + loadtools are gta02 and pirelli. + +-H /path/to/hwparam-file + + This option is just like -h, except that the given argument is used + directly as the hardware parameter file pathname (absolute or relative) + without alteration. + +-i num + + This option is common for all 3 utilities. It specifies the interval + in milliseconds at which the tool will send "please interrupt the boot + process" beacons out the serial port, hoping to catch the Calypso + internal boot ROM. The default is 13 ms. + +-n + + This option does anything only when loadtools have been compiled to run + on GTA0x AP. If you've compiled loadtools with the -DGTA0x_AP_BUILD + option, it has an effect of making each tool automatically toggle the + modem power control upon startup, removing the need for manual + sequencing of the Calypso boot process. This -n option suppresses that + action, making the AP build behave like the standard build in this + regard. + +-r baud + + This option is specific to fc-xram. It selects the serial line baud + rate which should be set just before the loaded XRAM image is jumped + to; the default is 115200 baud. + +fc-xram 2nd program invokation +============================== + +The fc-xram utility can take two possible actions after it has loaded the +specified S-record image into XRAM: + +* The default action, in the absence of additional command line arguments, is + to drop into a serial tty pass-thru mode, just like fc-iram. + +* The alternative action is to invoke a 2nd program and pass the serial + communication channel to it. This 2nd program invokation facility is intended + primarily for passing the serial communication channel to rvinterf or rvtdump + from the FreeCalypso software suite, not for launching any arbitrary 3rd-party + programs from fc-xram. + +The intended usage scenario is that one builds a version of the FreeCalypso GSM +firmware (or some subset thereof, such as an "in vivo" FFS editing agent) in the +ramImage configuration, fc-xram is used to load that ramImage into the target +device, and then the serial communication channel (RVTMUX) is immediately taken +over by rvinterf or rvtdump. + +More detailed usage instructions will be written when the rvinterf tools reach +a point of being usable by more than just the original developer; until then, +read the source code.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/baudrate.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,7 @@ +/* this header file defines the data structure for baud rate machinations */ + +struct baudrate { + char *name; + speed_t termios_code; + int bootrom_code; +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/chainload.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,114 @@ +/* + * This module implements the chain-loading of XRAM images via loadagent. + */ + +#include <sys/types.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "srecreader.h" + +struct srecreader xramimage; + +extern struct baudrate *current_baud_rate; +extern struct baudrate *xram_run_baudrate; + +static void +make_ml_arg(rec, buf) + u_char *rec; + char *buf; +{ + register int i, len; + register char *s; + + len = rec[0] + 1; + s = buf; + for (i = 0; i < len; i++) { + sprintf(s, "%02X", rec[i]); + s += 2; + } + *s = '\0'; +} + +perform_chain_load() +{ + int resp; + unsigned long rec_count; + char *argv[3], srecarg[516]; + + if (open_srec_file(&xramimage) < 0) + exit(1); + argv[0] = "ML"; + argv[1] = srecarg; + argv[2] = 0; + for (rec_count = 0; ; ) { + if (read_s_record(&xramimage) < 0) + exit(1); + switch (xramimage.record_type) { + case '0': + if (xramimage.lineno == 1) + continue; + fprintf(stderr, + "%s: S0 record found in line %d (expected in line 1 only)\n", + xramimage.filename, xramimage.lineno); + exit(1); + case '3': + case '7': + if (s3s7_get_addr_data(&xramimage) < 0) + exit(1); + break; + default: + fprintf(stderr, + "%s line %d: S%c record type not supported\n", + xramimage.filename, xramimage.lineno, + xramimage.record_type); + exit(1); + } + if (xramimage.record_type == '7') + break; + /* must be S3 */ + if (xramimage.datalen < 1) { + fprintf(stderr, + "%s line %d: S3 record has zero data length\n", + xramimage.filename, xramimage.lineno); + exit(1); + } + if (!rec_count) + printf("Each \'.\' is 100 S-records\n"); + make_ml_arg(xramimage.record, srecarg); + tpinterf_make_cmd(argv); + if (tpinterf_send_cmd()) + exit(1); + if (tpinterf_pass_output(1)) + exit(1); + rec_count++; + if (rec_count % 100 == 0) { + putchar('.'); + fflush(stdout); + } + } + /* got S7 */ + fclose(xramimage.openfile); + if (!rec_count) { + fprintf(stderr, + "%s line %d: S7 without any preceding S3 data records\n", + xramimage.filename, xramimage.lineno); + exit(1); + } + if (xram_run_baudrate != current_baud_rate) { + resp = loadagent_switch_baud(xram_run_baudrate); + if (resp) + exit(1); + } + printf("Sending jump command\n"); + sprintf(srecarg, "%lX", (u_long) xramimage.addr); + argv[0] = "jump"; + tpinterf_make_cmd(argv); + if (tpinterf_send_cmd()) + exit(1); + printf("Sent \"%s %s\": XRAM image should now be running!\n", + argv[0], argv[1]); + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/clmain.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,143 @@ +/* + * This module contains the main() function for the XRAM chain-loading + * utility fc-xram. + */ + +#include <sys/types.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <termios.h> +#include <unistd.h> +#include "baudrate.h" +#include "srecreader.h" + +extern char *target_ttydev; +extern struct srecreader iramimage; +extern char default_loadagent_image[]; +extern struct srecreader xramimage; +extern char hw_init_script[]; +extern struct baudrate baud_rate_table[]; +extern struct baudrate *current_baud_rate; +extern int gta_modem_poweron; + +extern struct baudrate *find_baudrate_by_name(); + +struct baudrate *xram_load_baudrate; +struct baudrate *xram_run_baudrate = baud_rate_table; /* 1st entry default */ + +char **passon_argv; +int passon_argc; + +main(argc, argv) + char **argv; +{ + extern char *optarg; + extern int optind; + int c; + struct baudrate *br; + + while ((c = getopt(argc, argv, "+a:b:B:c:C:h:H:i:nr:")) != EOF) + switch (c) { + case 'a': + iramimage.filename = optarg; + continue; + case 'b': + set_romload_baudrate(optarg); + continue; + case 'B': + br = find_baudrate_by_name(optarg); + if (!br) + exit(1); /* error msg already printed */ + xram_load_baudrate = br; + continue; + case 'c': + set_compalstage_short(optarg); + continue; + case 'C': + set_compalstage_fullpath(optarg); + continue; + case 'h': + read_hwparam_file_shortname(optarg); + continue; + case 'H': + read_hwparam_file_fullpath(optarg); + continue; + case 'i': + set_beacon_interval(optarg); + continue; + case 'n': + gta_modem_poweron = 0; + continue; + case 'r': + br = find_baudrate_by_name(optarg); + if (!br) + exit(1); /* error msg already printed */ + xram_run_baudrate = br; + continue; + case '?': + default: +usage: fprintf(stderr, + "usage: fc-xram [options] ttyport xramimage.srec [2ndprog]\n"); + exit(1); + } + if (argc - optind < 2) + goto usage; + target_ttydev = argv[optind]; + xramimage.filename = argv[optind+1]; + if (!iramimage.filename) + iramimage.filename = default_loadagent_image; + if (argc - optind >= 3) { + passon_argv = argv + optind + 2; + passon_argc = argc - optind - 2; + } + + open_target_serial(); + perform_compal_stage(1); + perform_romload(); + /* loadagent should be running now */ + if (tpinterf_pass_output(1) < 0) + exit(1); + if (hw_init_script[0]) { + printf("Executing init script %s\n", hw_init_script); + c = exec_init_script(hw_init_script); + if (c) + exit(1); + } + if (xram_load_baudrate && xram_load_baudrate != current_baud_rate) { + c = loadagent_switch_baud(xram_load_baudrate); + if (c) + exit(1); + } + printf("Sending XRAM image to loadagent\n"); + perform_chain_load(); + if (passon_argv) + exec_2nd_prog(); + tty_passthru(); + exit(0); +} + +exec_2nd_prog() +{ + char **execp_argv; + char **sp, **dp; + extern int target_fd; + char desc_arg[16]; + + sprintf(desc_arg, "-d%d", target_fd); + execp_argv = (char **) malloc(sizeof(char *) * (passon_argc + 2)); + if (!execp_argv) { + perror("malloc argv for execvp"); + exit(1); + } + sp = passon_argv; + dp = execp_argv; + *dp++ = *sp++; + *dp++ = desc_arg; + while (*sp) + *dp++ = *sp++; + *dp = NULL; + execvp(execp_argv[0], execp_argv); + fprintf(stderr, "Unable to execvp %s\n", passon_argv[0]); + exit(1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/compaldummy.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,20 @@ +/* + * If you need to build a version of loadtools without compalstage support, + * e.g., because you are building for GTA01/02 AP, substitute this dummy + * module in the place of compalload.c to get a passing build. + */ + +void +set_compalstage_short() +{ +} + +void +set_compalstage_fullpath() +{ +} + +perform_compal_stage() +{ + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/compalload.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,222 @@ +/* + * This module implements Compal's serial code loading protocol to load + * what we call compalstage, a piece of code that re-enables the Calypso + * boot ROM and allows us to use the same loadagent which we use on + * freedom-enabled target devices. + */ + +#include <sys/param.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <termios.h> +#include <unistd.h> + +extern char default_helpers_dir[]; +extern char *target_ttydev; +extern int target_fd; +extern struct termios target_termios; + +static char compalstage_pathname[MAXPATHLEN]; +static u_char *compalstage_imgbuf; +static size_t compalstage_len, compalstage_totlen; +static int rx_state; +static u_char rx_msg[3]; + +void +set_compalstage_short(arg) + char *arg; +{ + if (strcmp(arg, "none")) + sprintf(compalstage_pathname, "%s/compalstage-%s.bin", + default_helpers_dir, arg); + else + compalstage_pathname[0] = 0; +} + +void +set_compalstage_fullpath(arg) + char *arg; +{ + strcpy(compalstage_pathname, arg); +} + +static void +compute_checksum() +{ + size_t i, l; + u_char ck; + + ck = 0x02; + l = compalstage_len + 3; + for (i = 1; i < l; i++) + ck ^= compalstage_imgbuf[i]; + compalstage_imgbuf[l] = ck; +} + +static +handle_rx_msg() +{ + static u_char download_cmd[7] = {0x1B, 0xF6, 0x02, 0x00, + 0x52, 0x01, 0x53}; + + if (rx_msg[0] == 0x41 && rx_msg[1] == 0x01 && rx_msg[2] == 0x40) { + printf("Received PROMPT1, sending download command\n"); + write(target_fd, download_cmd, 7); + return(0); + } else if (rx_msg[0] == 0x41 && rx_msg[1] == 0x02 && rx_msg[2] == 0x43){ + printf("Received PROMPT2, sending download image\n"); + write(target_fd, compalstage_imgbuf, compalstage_totlen); + return(0); + } else if (rx_msg[0] == 0x41 && rx_msg[1] == 0x03 && rx_msg[2] == 0x42){ + printf("Received ACK; downloaded image should now be running!\n"); + return(1); + } else if (rx_msg[0] == 0x45 && rx_msg[1] == 0x53 && rx_msg[2] == 0x16){ + printf("Bootloader indicates bad checksum :-(\n"); + return(0); + } else if (rx_msg[0] == 0x41 && rx_msg[1] == 0x03 && rx_msg[2] == 0x57){ + printf("Bootloader indicates bad magic :-(\n"); + return(0); + } else { + printf("Unknown msg from bootloader: 1B F6 02 00 %02X %02X %02X\n", + rx_msg[0], rx_msg[1], rx_msg[2]); + return(0); + } +} + +static +handle_rx_byte(rxb) +{ + switch (rx_state) { + case 0: + if (rxb == 0x1B) + rx_state = 1; + return(0); + case 1: + if (rxb == 0xF6) + rx_state = 2; + else if (rxb == 0x1B) + rx_state = 1; + else + rx_state = 0; + return(0); + case 2: + if (rxb == 0x02) + rx_state = 3; + else if (rxb == 0x1B) + rx_state = 1; + else + rx_state = 0; + return(0); + case 3: + if (rxb == 0x00) + rx_state = 4; + else if (rxb == 0x1B) + rx_state = 1; + else + rx_state = 0; + return(0); + case 4: + rx_msg[0] = rxb; + rx_state = 5; + return(0); + case 5: + rx_msg[1] = rxb; + rx_state = 6; + return(0); + case 6: + rx_msg[2] = rxb; + rx_state = 0; + return handle_rx_msg(); + } +} + +static void +read_loop() +{ + u_char rdbuf[16]; + int cc, i; + + for (;;) { + cc = read(target_fd, rdbuf, sizeof rdbuf); + if (cc <= 0) { + fprintf(stderr, "EOF/error on target tty\n"); + exit(1); + } + for (i = 0; i < cc; i++) + if (handle_rx_byte(rdbuf[i])) + return; + } +} + +perform_compal_stage(for_boot_rom) +{ + int fd; + struct stat st; + static int zero = 0; + + if (!compalstage_pathname[0]) + return(0); + fd = open(compalstage_pathname, O_RDONLY); + if (fd < 0) { + perror(compalstage_pathname); + exit(1); + } + fstat(fd, &st); + if (!S_ISREG(st.st_mode)) { + fprintf(stderr, "error: %s is not a regular file\n", + compalstage_pathname); + exit(1); + } + if (st.st_size > 65535) { + fprintf(stderr, + "error: %s exceed Compal download limit of 65535 bytes\n", + compalstage_pathname); + exit(1); + } + compalstage_len = st.st_size; + compalstage_totlen = compalstage_len + 4; + compalstage_imgbuf = malloc(compalstage_totlen); + if (!compalstage_imgbuf) { + perror("malloc"); + exit(1); + } + compalstage_imgbuf[0] = 0x02; + compalstage_imgbuf[1] = compalstage_len >> 8; + compalstage_imgbuf[2] = compalstage_len; + if (read(fd, compalstage_imgbuf+3, compalstage_len) != compalstage_len){ + fprintf(stderr, "%s: read error or short read\n", + compalstage_pathname); + exit(1); + } + close(fd); + compute_checksum(); + + printf("Using Compal stage image %s\n", compalstage_pathname); + cfsetispeed(&target_termios, B115200); + cfsetospeed(&target_termios, B115200); + if (tcsetattr(target_fd, TCSAFLUSH, &target_termios) < 0) { + perror("tcsetattr to switch baud rate"); + exit(1); + } + ioctl(target_fd, FIONBIO, &zero); + printf("Waiting for PROMPT1 from target (%s) at 115200 baud\n", + target_ttydev); + read_loop(); + free(compalstage_imgbuf); + + if (for_boot_rom) { + cfsetispeed(&target_termios, B19200); + cfsetospeed(&target_termios, B19200); + if (tcsetattr(target_fd, TCSAFLUSH, &target_termios) < 0) { + perror("tcsetattr to switch baud rate"); + exit(1); + } + } + + return(1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/compalram.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,26 @@ +/* + * This module contains the main() function for fc-compalram, a trivial + * utility that feeds a binary download image to Compal's bootloader + * and then switches into serial tty pass-through. + */ + +#include <stdio.h> +#include <stdlib.h> + +extern char *target_ttydev; + +main(argc, argv) + char **argv; +{ + if (argc != 3) { + fprintf(stderr, "usage: fc-compalram ttyport image.bin\n"); + exit(1); + } + target_ttydev = argv[1]; + set_compalstage_fullpath(argv[2]); + + open_target_serial(); + perform_compal_stage(0); + tty_passthru(); + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/crc32tab.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,70 @@ +/* This CRC-32 table has been computed for the LSB-first direction */ + +#include <stdint.h> + +uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, + 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, + 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, + 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, + 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, + 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, + 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, + 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, + 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, + 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, + 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, + 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, + 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, + 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, + 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, + 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, + 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, + 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, + 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/defpath.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,9 @@ +/* + * By default the loadagent.srec target utility and some hardware parameter + * files are sought in an installation directory, to make the more common + * command line operations more manageable. + */ + +char default_helpers_dir[] = "/usr/local/share/freecalypso"; +char default_loadagent_image[] = "/usr/local/share/freecalypso/loadagent.srec"; +char loadtool_help_file[] = "/usr/local/share/freecalypso/loadtool.help";
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/flash.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,73 @@ +/* this header file contains definitions for fc-loadtool flash support */ + +/* + * The following structures represent an "abstract" + * description of flash devices. + * + * A "region" is a consecutive group of erase units of the same size. + */ + +struct flash_region_desc { + uint32_t sector_size; + unsigned nsectors; +}; + +#define CFI_MAX_REGIONS 4 + +/* + * The info in struct flash_geom can be either + * gathered from CFI or hard-coded. + */ +struct flash_geom { + uint32_t total_size; + unsigned nregions; + struct flash_region_desc regions[CFI_MAX_REGIONS]; + unsigned total_sectors; +}; + +struct flash_idcheck { + uint16_t offset; + uint16_t expect_val; +}; + +struct flash_bank_desc { + uint32_t align_size; + struct flash_geom *geom; + struct flash_idcheck *idcheck_table; + unsigned idcheck_num; +}; + +struct flash_device_desc { + char *name; + struct flash_bank_desc *bank_desc; + unsigned nbanks; + struct flash_cmdset *cmdset; +}; + +/* the following structures describe flash banks as accessible to us */ + +struct sector_info { + uint32_t start; + uint32_t size; +}; + +struct flash_cmdset { + char *cmdset_name; + int (*reset_cmd)(); + int (*status_cmd)(); + int (*unlock_sector)(); + int (*erase_sector)(); + int (*prep_for_program)(); + char *loadagent_setbase_cmd; + char *loadagent_program_cmd; + int needs_unlock; +}; + +struct flash_bank_info { + uint32_t base_addr; + struct flash_bank_desc *bank_desc; + struct flash_geom *geom; + struct flash_cmdset *ops; + struct sector_info *sectors; + int idcheck_done; +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/flashops.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,218 @@ +/* + * This module implements those flash operations which are dependent + * on the AMD vs. Intel command set style. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <time.h> +#include "flash.h" + +/* common stub functions */ + +static +noop() +{ + return(0); +} + +static +invalid() +{ + fprintf(stderr, + "This operation is not applicable to the selected flash type\n"); + return(-1); +} + +/* AMD flash functions */ + +amd_reset_cmd(bi) + struct flash_bank_info *bi; +{ + if (do_w16(bi->base_addr + 0xAAA, 0xF0)) { + fprintf(stderr, + "unexpected response to w16 when resetting flash to read mode!\n"); + return(-1); + } + return(0); +} + +amd_sector_erase(bi, sp) + struct flash_bank_info *bi; + struct sector_info *sp; +{ + int stat; + uint16_t flstat; + time_t start_time, curtime; + + stat = do_w16(bi->base_addr + sp->start + 0xAAA, 0xAA); + if (stat) { +bad_w16: fprintf(stderr, + "unexpected response to w16 in erase cmd sequence - aborting\n"); + return(-1); + } + stat = do_w16(bi->base_addr + sp->start + 0x554, 0x55); + if (stat) + goto bad_w16; + stat = do_w16(bi->base_addr + sp->start + 0xAAA, 0x80); + if (stat) + goto bad_w16; + stat = do_w16(bi->base_addr + sp->start + 0xAAA, 0xAA); + if (stat) + goto bad_w16; + stat = do_w16(bi->base_addr + sp->start + 0x554, 0x55); + if (stat) + goto bad_w16; + stat = do_w16(bi->base_addr + sp->start + 0xAAA, 0x30); + if (stat) + goto bad_w16; + start_time = time(0); + for (;;) { + stat = do_r16(bi->base_addr + sp->start, &flstat); + if (stat) + return(stat); /* error msg already printed */ + if (flstat == 0xFFFF) + return(0); + curtime = time(0); + if (curtime >= start_time + 20) { + fprintf(stderr, "erase timeout, aborting\n"); + return(-1); + } + } +} + +struct flash_cmdset flash_cmdset_amd = { + .cmdset_name = "AMD", + .reset_cmd = amd_reset_cmd, + .status_cmd = invalid, + .unlock_sector = invalid, + .erase_sector = amd_sector_erase, + .prep_for_program = noop, + .loadagent_setbase_cmd = "AMFB", + .loadagent_program_cmd = "AMFW", + .needs_unlock = 0, +}; + +/* Intel flash functions */ + +intel_reset_cmd(bi) + struct flash_bank_info *bi; +{ + if (do_w16(bi->base_addr, 0xFF)) { + fprintf(stderr, + "unexpected response to w16 when resetting flash to read mode!\n"); + return(-1); + } + return(0); +} + +intel_status_cmd(bi) + struct flash_bank_info *bi; +{ + int stat; + uint16_t sr; + + /* issue Read SR command */ + stat = do_w16(bi->base_addr, 0x70); + if (stat) { + fprintf(stderr, + "unexpected response to w16 for Read SR command\n"); + return(-1); + } + stat = do_r16(bi->base_addr, &sr); + if (stat) + return(stat); /* error msg already printed */ + sr &= 0xFF; + printf("Status Register: %02X\n", sr); + return(0); +} + +intel_sector_unlock(bi, sp) + struct flash_bank_info *bi; + struct sector_info *sp; +{ + int stat; + + stat = do_w16(bi->base_addr + sp->start, 0x60); + if (stat) { +bad_w16: fprintf(stderr, + "unexpected response to w16 in block unlock cmd sequence - aborting\n"); + return(-1); + } + stat = do_w16(bi->base_addr + sp->start, 0xD0); + if (stat) + goto bad_w16; + return(0); +} + +intel_sector_erase(bi, sp) + struct flash_bank_info *bi; + struct sector_info *sp; +{ + int stat; + uint16_t flstat; + time_t start_time, curtime; + + stat = intel_sector_unlock(bi, sp); + if (stat) + return(stat); /* error msg already printed */ + /* clear SR */ + stat = do_w16(bi->base_addr + sp->start, 0x50); + if (stat) { +bad_w16: fprintf(stderr, + "unexpected response to w16 in erase cmd sequence - aborting\n"); + return(-1); + } + /* send the actual block erase command */ + stat = do_w16(bi->base_addr + sp->start, 0x20); + if (stat) + goto bad_w16; + stat = do_w16(bi->base_addr + sp->start, 0xD0); + if (stat) + goto bad_w16; + /* wait for completion */ + start_time = time(0); + for (;;) { + stat = do_r16(bi->base_addr + sp->start, &flstat); + if (stat) + return(stat); /* error msg already printed */ + if (flstat & 0x80) + break; + curtime = time(0); + if (curtime >= start_time + 20) { + fprintf(stderr, "erase timeout, aborting\n"); + return(-1); + } + } + if (flstat & 0x20) { + fprintf(stderr, "block erase failed!\n"); + return(-1); + } else + return(0); +} + +intel_clear_sr(bi) + struct flash_bank_info *bi; +{ + printf("Clearing Intel flash SR\n"); + if (do_w16(bi->base_addr, 0x50)) { + fprintf(stderr, + "unexpected response to w16 for Clear SR command\n"); + return(-1); + } + return(0); +} + +struct flash_cmdset flash_cmdset_intel = { + .cmdset_name = "Intel", + .reset_cmd = intel_reset_cmd, + .status_cmd = intel_status_cmd, + .unlock_sector = intel_sector_unlock, + .erase_sector = intel_sector_erase, + .prep_for_program = intel_clear_sr, + .loadagent_setbase_cmd = "INFB", + .loadagent_program_cmd = "INFW", + .needs_unlock = 1, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/flcmplboot.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,256 @@ +/* + * This module contains the implementation of the flash erase-program-boot + * hack for brickable Compal phones. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <ctype.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "flash.h" + +extern struct flash_bank_info flash_bank_info[2]; +extern struct flash_cmdset flash_cmdset_intel; + +extern uint32_t crc32_table[]; + +static int hack_enabled; +static uint32_t boot_sector_size; +static uint32_t ram_buffer_addr; + +/* called from hwparam.c config file parser */ +void +set_boot_reflash_hack(arg, filename_for_errs, lineno_for_errs) + char *arg; + char *filename_for_errs; + int lineno_for_errs; +{ + char *cp, *np, *ep; + + if (hack_enabled) { + fprintf(stderr, + "%s line %d: duplicate boot-reflash-hack setting\n", + filename_for_errs, lineno_for_errs); + exit(1); + } + for (cp = arg; isspace(*cp); cp++) + ; + if (!*cp || *cp == '#') { +too_few_arg: fprintf(stderr, + "%s line %d: boot-reflash-hack setting: too few arguments\n", + filename_for_errs, lineno_for_errs); + exit(1); + } + for (np = cp; *cp && !isspace(*cp); cp++) + ; + if (!*cp) + goto too_few_arg; + *cp++ = '\0'; + ram_buffer_addr = strtoul(np, &ep, 16); + if (*ep) { +invhex: fprintf(stderr, + "%s line %d: syntax error (hex arguments expected)\n", + filename_for_errs, lineno_for_errs); + exit(1); + } + while (isspace(*cp)) + cp++; + if (!*cp || *cp == '#') + goto too_few_arg; + for (np = cp; *cp && !isspace(*cp); cp++) + ; + if (*cp) + *cp++ = '\0'; + boot_sector_size = strtoul(np, &ep, 16); + if (*ep) + goto invhex; + while (isspace(*cp)) + cp++; + if (*cp && *cp != '#') { + fprintf(stderr, + "%s line %d: boot-reflash-hack setting: too many arguments\n", + filename_for_errs, lineno_for_errs); + exit(1); + } + hack_enabled = 1; +} + +static void +make_s3_record(buf, dest_addr, datalen) + u_char *buf; + uint32_t dest_addr; +{ + int totlen, i; + u_char accum; + + buf[0] = totlen = datalen + 5; + buf[1] = dest_addr >> 24; + buf[2] = dest_addr >> 16; + buf[3] = dest_addr >> 8; + buf[4] = dest_addr; + accum = 0; + for (i = 0; i < totlen; i++) + accum += buf[i]; + buf[i] = ~accum; +} + +static void +make_ml_arg(rec, buf) + u_char *rec; + char *buf; +{ + register int i, len; + register char *s; + + len = rec[0] + 1; + s = buf; + for (i = 0; i < len; i++) { + sprintf(s, "%02X", rec[i]); + s += 2; + } + *s = '\0'; +} + +flashcmd_erase_program_boot(argc, argv) + char **argv; +{ + FILE *binf; + struct stat filestat; + size_t len; + char *strtoul_endp; + char *targv[5], longarg[513]; + char shortarg1[9], shortarg2[9], shortarg3[9]; + u_char databuf[256]; + int reclen, cc, i; + uint32_t ramaddr, remlen, crcaccum; + u_long crc_from_target; + + if (!hack_enabled) { + fprintf(stderr, + "Operation not applicable to this target device\n"); + return(-1); + } + if (argc < 3 || argc > 4) { +inv: fprintf(stderr, "usage: %s %s binfile [length]\n", + argv[0], argv[1]); + return(-1); + } + if (flash_get_cfi(0) < 0) + return(-1); + if (flash_bank_info[0].geom->regions[0].sector_size + != boot_sector_size) { + fprintf(stderr, + "error: detected flash boot sector size differs from config\n"); + return(-1); + } + if (flash_bank_info[0].ops != &flash_cmdset_intel) { + fprintf(stderr, + "error: operation implemented for Intel flash only\n"); + return(-1); + } + + binf = fopen(argv[2], "r"); + if (!binf) { + perror(argv[2]); + return(-1); + } + fstat(fileno(binf), &filestat); + if (!S_ISREG(filestat.st_mode)) { + fprintf(stderr, "%s is not a regular file\n", argv[2]); + fclose(binf); + return(-1); + } + if (argc > 3) { + len = strtoul(argv[3], &strtoul_endp, 16); + if (*strtoul_endp) { + fclose(binf); + goto inv; + } + if (len > filestat.st_size) { + fprintf(stderr, + "error: specified length exceeds file length\n"); + fclose(binf); + return(-1); + } + } else + len = filestat.st_size; + if (len > boot_sector_size) { + fprintf(stderr, "error: length exceeds boot sector size\n"); + fclose(binf); + return(-1); + } + if (len & 1) { + fprintf(stderr, "error: length must be even\n"); + fclose(binf); + return(-1); + } + + printf("Loading new boot code into target RAM at %lx\n", + (u_long) ram_buffer_addr); + targv[0] = "ML"; + targv[1] = longarg; + targv[2] = 0; + ramaddr = ram_buffer_addr; + crcaccum = 0xFFFFFFFF; + for (remlen = len; remlen; remlen -= reclen) { + if (remlen >= 250) + reclen = 250; + else + reclen = remlen; + cc = fread(databuf + 5, 1, reclen, binf); + if (cc != reclen) { + fclose(binf); + fprintf(stderr, "error reading from %s\n", argv[2]); + return(-1); + } + for (i = 0; i < reclen; i++) /* update running CRC */ + crcaccum = crc32_table[crcaccum & 0xFF ^ databuf[i+5]] + ^ (crcaccum >> 8); + make_s3_record(databuf, ramaddr, reclen); + make_ml_arg(databuf, longarg); + tpinterf_make_cmd(targv); + if (tpinterf_send_cmd() < 0) { + fclose(binf); + return(-1); + } + cc = tpinterf_pass_output(1); + if (cc) { + fclose(binf); + return(cc); + } + ramaddr += reclen; + putchar('.'); + fflush(stdout); + } + putchar('\n'); + fclose(binf); + + printf("Verifying CRC-32 in target RAM\n"); + if (crc32_on_target((u_long) ram_buffer_addr, (u_long) len, + &crc_from_target) < 0) + return(-1); + if (crc_from_target == crcaccum) + printf("match (%08lX)\n", crc_from_target); + else { + fprintf(stderr, "error: CRC mismatch!\n"); + return(-1); + } + + printf("Commanding flash erase+program operation on the target\n"); + sprintf(shortarg1, "%lx", (u_long) ram_buffer_addr); + sprintf(shortarg2, "%lx", (u_long) flash_bank_info[0].base_addr); + sprintf(shortarg3, "%lx", (u_long) len); + targv[0] = "intel-rewrite-sector"; + targv[1] = shortarg1; + targv[2] = shortarg2; + targv[3] = shortarg3; + targv[4] = 0; + tpinterf_make_cmd(targv); + if (tpinterf_send_cmd() < 0) + return(-1); + return tpinterf_pass_output(20); /* 20 s timeout */ +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/flmain.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,260 @@ +/* + * This module is the main entry point for fc-loadtool flash functions + */ + +#include <sys/types.h> +#include <ctype.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "flash.h" + +/* K5A32xx device description */ + +static struct flash_geom k5a32xx_topboot_geom = { + .total_size = 0x400000, + .nregions = 2, + .regions = {0x10000, 63, 0x2000, 8}, + .total_sectors = 71, +}; + +static struct flash_idcheck k5a32xx_topboot_idcheck[2] = { + {0x00, 0x00EC}, + {0x02, 0x22A0} +}; + +static struct flash_bank_desc k5a32xx_topboot_bankdesc = { + 0x400000, &k5a32xx_topboot_geom, k5a32xx_topboot_idcheck, 2 +}; + +/* S{29,71}PL129N device description */ + +static struct flash_geom pl129n_ce1_geom = { + .total_size = 0x800000, + .nregions = 2, + .regions = {0x10000, 4, 0x40000, 31}, + .total_sectors = 35, +}; + +static struct flash_geom pl129n_ce2_geom = { + .total_size = 0x800000, + .nregions = 2, + .regions = {0x40000, 31, 0x10000, 4}, + .total_sectors = 35, +}; + +static struct flash_idcheck pl129n_idcheck[4] = { + {0x00, 0x0001}, + {0x02, 0x227E}, + {0x1C, 0x2221}, + {0x1E, 0x2200} +}; + +static struct flash_bank_desc pl129n_banks[2] = { + {0x800000, &pl129n_ce1_geom, pl129n_idcheck, 4}, + {0x800000, &pl129n_ce2_geom, pl129n_idcheck, 4} +}; + +/* bank configurations for CFI */ + +static struct flash_bank_desc cfi_4M_bankdesc = { + 0x400000, 0, 0, 0 +}; + +static struct flash_bank_desc cfi_8M_bankdesc = { + 0x800000, 0, 0, 0 +}; + +/* list of supported flash devices */ + +extern struct flash_cmdset flash_cmdset_amd; + +struct flash_device_desc flash_device_list[] = { + {"cfi-4M", &cfi_4M_bankdesc, 1, 0}, + {"cfi-8M", &cfi_8M_bankdesc, 1, 0}, + {"k5a32xx_t", &k5a32xx_topboot_bankdesc, 1, &flash_cmdset_amd}, + {"pl129n", pl129n_banks, 2, &flash_cmdset_amd}, + {0, 0, 0, 0} /* array terminator */ +}; + +/* the following variables describe our selected flash device */ + +struct flash_device_desc *selected_flash_device; +struct flash_bank_info flash_bank_info[2]; + +/* called from hwparam.c config file parser */ +void +set_flash_device(arg, filename_for_errs, lineno_for_errs) + char *arg; + char *filename_for_errs; + int lineno_for_errs; +{ + char *cp, *np, *ep; + struct flash_device_desc *tp; + int bank; + struct flash_bank_info *bi; + + if (selected_flash_device) { + fprintf(stderr, "%s line %d: duplicate flash setting\n", + filename_for_errs, lineno_for_errs); + exit(1); + } + for (cp = arg; isspace(*cp); cp++) + ; + if (!*cp || *cp == '#') { +too_few_arg: fprintf(stderr, + "%s line %d: flash setting: too few arguments\n", + filename_for_errs, lineno_for_errs); + exit(1); + } + for (np = cp; *cp && !isspace(*cp); cp++) + ; + if (*cp) + *cp++ = '\0'; + for (tp = flash_device_list; tp->name; tp++) + if (!strcmp(tp->name, np)) + break; + if (!tp->name) { + fprintf(stderr, + "%s line %d: unknown flash device \"%s\"\n", + filename_for_errs, lineno_for_errs, np); + exit(1); + } + selected_flash_device = tp; + + /* now initialize flash_bank_info */ + for (bank = 0; bank < selected_flash_device->nbanks; bank++) { + while (isspace(*cp)) + cp++; + if (!*cp || *cp == '#') + goto too_few_arg; + for (np = cp; *cp && !isspace(*cp); cp++) + ; + if (*cp) + *cp++ = '\0'; + bi = flash_bank_info + bank; + bi->base_addr = strtoul(np, &ep, 16); + if (*ep) { + fprintf(stderr, +"%s line %d: syntax error (base addr expected after flash device type)\n", + filename_for_errs, lineno_for_errs); + exit(1); + } + /* the rest comes from the flash device type */ + bi->bank_desc = selected_flash_device->bank_desc + bank; + if (bi->base_addr & (bi->bank_desc->align_size - 1)) { + fprintf(stderr, +"%s line %d: flash bank %d base addr is not aligned to the bank size (0x%lx)\n", + filename_for_errs, lineno_for_errs, bank, + (u_long) bi->bank_desc->align_size); + exit(1); + } + bi->geom = bi->bank_desc->geom; + bi->ops = selected_flash_device->cmdset; + } + while (isspace(*cp)) + cp++; + if (*cp && *cp != '#') { + fprintf(stderr, + "%s line %d: flash setting: too many arguments\n", + filename_for_errs, lineno_for_errs); + exit(1); + } +} + +flashcmd_help() +{ + return loadtool_help("flash"); +} + +flashcmd_info(argc, argv, bank) + char **argv; +{ + struct flash_bank_info *bi; + + if (argc > 2) { + fprintf(stderr, "error: too many arguments\n"); + return(-1); + } + bi = flash_bank_info + bank; + printf("Flash device type: %s\n", selected_flash_device->name); + printf("Bank %d base address: %08lX\n", bank, (u_long) bi->base_addr); + if (flash_get_cfi(bank) < 0) + return(-1); + printf("Bank %d total size: %lx\n", bank, + (u_long) bi->geom->total_size); + printf("Sectors in bank %d: %u (%u regions)\n", bank, + bi->geom->total_sectors, bi->geom->nregions); + printf("Command set style: %s\n", bi->ops->cmdset_name); + flash_id_check(bank, 1); + if (selected_flash_device->nbanks == 2 && !bank) + printf("\nFlash device has 2 banks; flash2 command available\n"); + return(0); +} + +extern int flashcmd_blankchk(); +extern int flashcmd_dump2file(); +extern int flashcmd_erase(); +extern int flashcmd_erase_program_boot(); +extern int flashcmd_progbin(); +extern int flashcmd_program_m0(); +extern int flashcmd_program_srec(); +extern int flashcmd_quickprog(); +extern int flashcmd_reset(); +extern int flashcmd_sectors(); +extern int flashcmd_status(); +extern int flashcmd_unlock(); + +static struct cmdtab { + char *cmd; + int (*func)(); +} cmdtab[] = { + {"blankchk", flashcmd_blankchk}, + {"dump2bin", flashcmd_dump2file}, + {"dump2srec", flashcmd_dump2file}, + {"erase", flashcmd_erase}, + {"erase-program-boot", flashcmd_erase_program_boot}, + {"help", flashcmd_help}, + {"info", flashcmd_info}, + {"program-bin", flashcmd_progbin}, + {"program-m0", flashcmd_program_m0}, + {"program-srec", flashcmd_program_srec}, + {"quickprog", flashcmd_quickprog}, + {"reset", flashcmd_reset}, + {"sectors", flashcmd_sectors}, + {"status", flashcmd_status}, + {"unlock", flashcmd_unlock}, + {0, 0} +}; + +cmd_flash(argc, argv) + char **argv; +{ + int bank; + struct cmdtab *tp; + + if (!selected_flash_device) { + fprintf(stderr, "No flash configuration defined\n"); + return(-1); + } + if (argv[0][5] == '2') { + if (selected_flash_device->nbanks < 2) { + fprintf(stderr, "Flash device %s has only one bank\n", + selected_flash_device->name); + return(-1); + } + bank = 1; + } else + bank = 0; + for (tp = cmdtab; tp->cmd; tp++) + if (!strcmp(tp->cmd, argv[1])) + break; + if (!tp->func) { + fprintf(stderr, "%s %s: unknown/unimplemented subcommand\n", + argv[0], argv[1]); + return(-1); + } + return tp->func(argc, argv, bank); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/flmisc.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,311 @@ +/* + * Miscellaneous flash commands (fc-loadtool) are implemented here + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "flash.h" + +extern struct flash_bank_info flash_bank_info[2]; + +flashcmd_blankchk(argc, argv, bank) + char **argv; +{ + struct flash_bank_info *bi; + u_long offset, len; + char *strtoul_endp; + char *targv[4], targ_start[10], targ_len[10]; + + if (argc != 4) { +inv: fprintf(stderr, "usage: %s %s hex-start-offset hex-length\n", + argv[0], argv[1]); + return(-1); + } + offset = strtoul(argv[2], &strtoul_endp, 16); + if (*strtoul_endp) + goto inv; + if (flash_get_cfi(bank) < 0) + return(-1); + bi = flash_bank_info + bank; + if (offset >= bi->geom->total_size) { + fprintf(stderr, + "error: specified offset exceeds flash bank size (0x%lx)\n", + (u_long) bi->geom->total_size); + return(-1); + } + len = strtoul(argv[3], &strtoul_endp, 16); + if (*strtoul_endp) + goto inv; + if (len > bi->geom->total_size - offset) { + fprintf(stderr, + "error: specified offset+length exceed flash bank size (0x%lx)\n", + (u_long) bi->geom->total_size); + return(-1); + } + /* reset flash to read mode */ + if (bi->ops->reset_cmd(bi) < 0) + return(-1); + sprintf(targ_start, "%lx", (u_long) bi->base_addr + offset); + sprintf(targ_len, "%lx", len); + targv[0] = "blankchk"; + targv[1] = targ_start; + targv[2] = targ_len; + targv[3] = 0; + tpinterf_make_cmd(targv); + if (tpinterf_send_cmd() < 0) + return(-1); + return tpinterf_pass_output(10); /* 10 s timeout */ +} + +flashcmd_dump2file(argc, argv, bank) + char **argv; +{ + struct flash_bank_info *bi; + u_long offset, dumplen, maxlen; + char *strtoul_endp; + int format; + + if (argc < 3 || argc > 5) { +inv: fprintf(stderr, "usage: %s %s outfile [offset [length]]\n", + argv[0], argv[1]); + return(-1); + } + if (flash_get_cfi(bank) < 0) + return(-1); + bi = flash_bank_info + bank; + if (argc >= 4) { + offset = strtoul(argv[3], &strtoul_endp, 16); + if (*strtoul_endp) + goto inv; + if (offset >= bi->geom->total_size) { + fprintf(stderr, + "error: specified offset exceeds flash bank size (0x%lx)\n", + (u_long) bi->geom->total_size); + return(-1); + } + } else + offset = 0; + maxlen = bi->geom->total_size - offset; + if (argc >= 5) { + dumplen = strtoul(argv[4], &strtoul_endp, 16); + if (*strtoul_endp) + goto inv; + if (dumplen > maxlen) { + fprintf(stderr, + "error: specified offset+length exceed flash bank size (0x%lx)\n", + (u_long) bi->geom->total_size); + return(-1); + } + } else + dumplen = maxlen; + switch (argv[1][5]) { + case 'b': + format = 0; + break; + case 's': + format = 1; + break; + default: + fprintf(stderr, + "internal bug: bad format in flashcmd_dump2file()\n"); + return(-1); + } + /* reset flash to read mode */ + if (bi->ops->reset_cmd(bi) < 0) + return(-1); + return loadtool_memdump(bi->base_addr + offset, dumplen, argv[2], + format); +} + +flashcmd_erase(argc, argv, bank) + char **argv; +{ + struct flash_bank_info *bi; + u_long offset, len; + char *strtoul_endp; + struct sector_info *startsec, *endsec, *sp; + int stat; + + if (argc != 4) { +inv: fprintf(stderr, "usage: %s %s hex-start-offset hex-length\n", + argv[0], argv[1]); + return(-1); + } + offset = strtoul(argv[2], &strtoul_endp, 16); + if (*strtoul_endp) + goto inv; + if (flash_get_cfi(bank) < 0) + return(-1); + bi = flash_bank_info + bank; + if (offset >= bi->geom->total_size) { + fprintf(stderr, + "error: specified offset exceeds flash bank size (0x%lx)\n", + (u_long) bi->geom->total_size); + return(-1); + } + len = strtoul(argv[3], &strtoul_endp, 16); + if (*strtoul_endp) + goto inv; + if (len > bi->geom->total_size - offset) { + fprintf(stderr, + "error: specified offset+length exceed flash bank size (0x%lx)\n", + (u_long) bi->geom->total_size); + return(-1); + } + if (!len) { + printf("Zero length specified - nothing to do!\n"); + return(0); + } + /* now enforce sector alignment for both offset and length */ + if (get_flash_sector_table(bank) < 0) + return(-1); + if (get_flash_sector_range(bi, offset, len, &startsec, &endsec) < 0) + return(-1); + stat = flash_id_check(bank, 0); + if (stat) + return(stat); + printf("Erasing %d sector(s)\n", endsec - startsec); + for (sp = startsec; sp < endsec; sp++) { + stat = bi->ops->erase_sector(bi, sp); + if (stat) + return(stat); + putchar('.'); + fflush(stdout); + } + putchar('\n'); + return(0); +} + +flashcmd_quickprog(argc, argv, bank) + char **argv; +{ + struct flash_bank_info *bi; + char *targv[4], targ_base[10]; + int stat; + + if (argc != 4) { + fprintf(stderr, "usage: %s %s hex-offset hex-data-string\n", + argv[0], argv[1]); + return(-1); + } + if (flash_get_cfi(bank) < 0) + return(-1); + bi = flash_bank_info + bank; + sprintf(targ_base, "%lx", (u_long) bi->base_addr); + targv[0] = bi->ops->loadagent_setbase_cmd; + targv[1] = targ_base; + targv[2] = 0; + tpinterf_make_cmd(targv); + if (tpinterf_send_cmd() < 0) + return(-1); + stat = tpinterf_pass_output(1); + if (stat) + return(stat); + targv[0] = bi->ops->loadagent_program_cmd; + targv[1] = argv[2]; + targv[2] = argv[3]; + targv[3] = 0; + if (tpinterf_make_cmd(targv) < 0) { + fprintf(stderr, + "error: unable to form AMFW/INFW target command\n"); + return(-1); + } + if (tpinterf_send_cmd() < 0) + return(-1); + return tpinterf_pass_output(1); +} + +flashcmd_reset(argc, argv, bank) + char **argv; +{ + struct flash_bank_info *bi; + + if (argc > 2) { + fprintf(stderr, "error: too many arguments\n"); + return(-1); + } + if (flash_get_cfi(bank) < 0) + return(-1); + bi = flash_bank_info + bank; + return bi->ops->reset_cmd(bi); +} + +flashcmd_status(argc, argv, bank) + char **argv; +{ + struct flash_bank_info *bi; + + if (argc > 2) { + fprintf(stderr, "error: too many arguments\n"); + return(-1); + } + if (flash_get_cfi(bank) < 0) + return(-1); + bi = flash_bank_info + bank; + return bi->ops->status_cmd(bi); +} + +flashcmd_unlock(argc, argv, bank) + char **argv; +{ + struct flash_bank_info *bi; + u_long offset, len; + char *strtoul_endp; + struct sector_info *startsec, *endsec, *sp; + int stat; + + if (flash_get_cfi(bank) < 0) + return(-1); + bi = flash_bank_info + bank; + if (!bi->ops->needs_unlock) { + fprintf(stderr, + "This operation is not applicable to the selected flash type\n"); + return(-1); + } + if (argc != 4) { +inv: fprintf(stderr, "usage: %s %s hex-start-offset hex-length\n", + argv[0], argv[1]); + return(-1); + } + offset = strtoul(argv[2], &strtoul_endp, 16); + if (*strtoul_endp) + goto inv; + if (offset >= bi->geom->total_size) { + fprintf(stderr, + "error: specified offset exceeds flash bank size (0x%lx)\n", + (u_long) bi->geom->total_size); + return(-1); + } + len = strtoul(argv[3], &strtoul_endp, 16); + if (*strtoul_endp) + goto inv; + if (len > bi->geom->total_size - offset) { + fprintf(stderr, + "error: specified offset+length exceed flash bank size (0x%lx)\n", + (u_long) bi->geom->total_size); + return(-1); + } + if (!len) { + printf("Zero length specified - nothing to do!\n"); + return(0); + } + /* now enforce sector alignment for both offset and length */ + if (get_flash_sector_table(bank) < 0) + return(-1); + if (get_flash_sector_range(bi, offset, len, &startsec, &endsec) < 0) + return(-1); + printf("Unlocking %d sector(s)\n", endsec - startsec); + for (sp = startsec; sp < endsec; sp++) { + stat = bi->ops->unlock_sector(bi, sp); + if (stat) + return(stat); + putchar('.'); + fflush(stdout); + } + putchar('\n'); + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/flprogbin.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,200 @@ +/* + * This module implements the flash program-bin command: + * programming flash using a binary file as the data source. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <time.h> +#include "flash.h" + +extern struct flash_bank_info flash_bank_info[2]; +extern uint32_t crc32_table[]; + +flashcmd_progbin(argc, argv, bank) + char **argv; +{ + struct flash_bank_info *bi; + u_long flashoff, fileoff, len, origlen, bytesdone; + u_long crc_base_addr, crc_from_target; + uint32_t crcaccum; + char *strtoul_endp; + FILE *binf; + struct stat filestat; + char *targv[4], shortarg[10], longarg[513]; + u_char databuf[256]; + int reclen, cc, i; + time_t curtime, last_time; + + if (argc < 4 || argc > 6) { +inv: fprintf(stderr, + "usage: %s %s flash-offset binfile [file-offset [length]]\n", + argv[0], argv[1]); + return(-1); + } + flashoff = strtoul(argv[2], &strtoul_endp, 16); + if (*strtoul_endp) + goto inv; + if (flash_get_cfi(bank) < 0) + return(-1); + bi = flash_bank_info + bank; + if (flashoff >= bi->geom->total_size) { + fprintf(stderr, + "error: specified flash offset exceeds bank size (0x%lx)\n", + (u_long) bi->geom->total_size); + return(-1); + } + if (flashoff & 1) { + fprintf(stderr, "error: flash offset must be even\n"); + return(-1); + } + binf = fopen(argv[3], "r"); + if (!binf) { + perror(argv[3]); + return(-1); + } + fstat(fileno(binf), &filestat); + if (!S_ISREG(filestat.st_mode)) { + fprintf(stderr, "%s is not a regular file\n", argv[3]); + fclose(binf); + return(-1); + } + if (argc > 4) { + fileoff = strtoul(argv[4], &strtoul_endp, 16); + if (*strtoul_endp) { + fclose(binf); + goto inv; + } + if (fileoff > filestat.st_size) { + fprintf(stderr, + "error: specified file offset exceeds file length\n"); + fclose(binf); + return(-1); + } + } else + fileoff = 0; + if (argc > 5) { + len = strtoul(argv[5], &strtoul_endp, 16); + if (*strtoul_endp) { + fclose(binf); + goto inv; + } + if (len > filestat.st_size - fileoff) { + fprintf(stderr, + "error: specified file offset+length exceed file length\n"); + fclose(binf); + return(-1); + } + } else + len = filestat.st_size - fileoff; + if (!len) { + printf("Length is zero - nothing to do!\n"); + fclose(binf); + return(0); + } + if (len > bi->geom->total_size - flashoff) { + fprintf(stderr, + "error: specified flash offset+length exceed bank size (0x%lx)\n", + (u_long) bi->geom->total_size); + fclose(binf); + return(-1); + } + if (len & 1) { + fprintf(stderr, "error: program length must be even\n"); + fclose(binf); + return(-1); + } + + /* finally done with the arg parsing etc, can get to work now */ + if (flash_id_check(bank, 0) < 0) { + fclose(binf); + return(-1); + } + crc_base_addr = bi->base_addr + flashoff; + sprintf(shortarg, "%lx", (u_long) bi->base_addr); + targv[0] = bi->ops->loadagent_setbase_cmd; + targv[1] = shortarg; + targv[2] = 0; + printf("Setting flash base address: %s %s\n", targv[0], targv[1]); + tpinterf_make_cmd(targv); + if (tpinterf_send_cmd() < 0) { + fclose(binf); + return(-1); + } + cc = tpinterf_pass_output(1); + if (cc) { + fclose(binf); + return(cc); + } + if (bi->ops->prep_for_program(bi) < 0) { + fclose(binf); + return(-1); + } + fseek(binf, fileoff, SEEK_SET); + targv[0] = bi->ops->loadagent_program_cmd; + targv[1] = shortarg; + targv[2] = longarg; + targv[3] = 0; + printf("Programming flash: %lu (0x%lx) bytes\n", len, len); + origlen = len; + bytesdone = 0; + last_time = 0; + crcaccum = 0xFFFFFFFF; + while (len) { + if (len >= 256) + reclen = 256; + else + reclen = len; + cc = fread(databuf, 1, reclen, binf); + if (cc != reclen) { + fclose(binf); + fprintf(stderr, "error reading from %s\n", argv[3]); + return(-1); + } + for (i = 0; i < reclen; i++) /* update running CRC */ + crcaccum = crc32_table[crcaccum & 0xFF ^ databuf[i]] + ^ (crcaccum >> 8); + sprintf(shortarg, "%lx", flashoff); + build_flashw_hex_string(databuf, longarg, reclen >> 1, 0); + tpinterf_make_cmd(targv); + if (tpinterf_send_cmd() < 0) { + fclose(binf); + return(-1); + } + i = tpinterf_pass_output(8); /* 8 s timeout */ + if (i) { + fclose(binf); + return(i); + } + flashoff += reclen; + len -= reclen; + bytesdone += reclen; + cc = bytesdone * 100 / origlen; + time(&curtime); + if (curtime != last_time || cc == 100) { + printf("\r0x%lx bytes programmed (%i%%)", + bytesdone, cc); + fflush(stdout); + } + last_time = curtime; + } + putchar('\n'); + fclose(binf); + + /* reset flash to read mode */ + if (bi->ops->reset_cmd(bi) < 0) + return(-1); + printf("Verifying CRC-32 of programmed flash area\n"); + if (crc32_on_target(crc_base_addr, origlen, &crc_from_target) < 0) + return(-1); + if (crc_from_target == crcaccum) { + printf("match (%08lX)\n", crc_from_target); + return(0); + } else { + fprintf(stderr, "error: CRC mismatch!\n"); + return(-1); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/flprogsrec.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,158 @@ +/* + * This module implements the flash program-srec and flash program-m0 commands: + * programming flash using S-record files as the data source. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include "flash.h" +#include "srecreader.h" + +extern struct flash_bank_info flash_bank_info[2]; + +flashcmd_progsrec_gen(bank, imgfile, is_m0) + char *imgfile; +{ + struct flash_bank_info *bi; + struct srecreader srr; + char *targv[4], shortarg[10], longarg[513]; + int resp; + unsigned long rec_count; + + if (flash_get_cfi(bank) < 0) + return(-1); + bi = flash_bank_info + bank; + srr.filename = imgfile; + resp = open_srec_file(&srr); + if (resp < 0) + return(resp); + resp = flash_id_check(bank, 0); + if (resp) { + fclose(srr.openfile); + return(resp); + } + sprintf(shortarg, "%lx", (u_long) bi->base_addr); + targv[0] = bi->ops->loadagent_setbase_cmd; + targv[1] = shortarg; + targv[2] = 0; + printf("Setting flash base address: %s %s\n", targv[0], targv[1]); + tpinterf_make_cmd(targv); + if (tpinterf_send_cmd() < 0) { + fclose(srr.openfile); + return(-1); + } + resp = tpinterf_pass_output(1); + if (resp) { + fclose(srr.openfile); + return(resp); + } + if (bi->ops->prep_for_program(bi) < 0) { + fclose(srr.openfile); + return(-1); + } + targv[0] = bi->ops->loadagent_program_cmd; + targv[1] = shortarg; + targv[2] = longarg; + targv[3] = 0; + for (rec_count = 0; ; ) { + if (read_s_record(&srr) < 0) { + /* error msg already printed */ + fclose(srr.openfile); + return(-1); + } + if (srr.record_type == '0') { + if (srr.lineno == 1) + continue; + fprintf(stderr, + "Warning: S0 record found in line %d of %s (expected in line 1 only)\n", + srr.lineno, srr.filename); + continue; + } else if (srr.record_type == '7') + break; + else if (srr.record_type != '3') { + fprintf(stderr, + "Warning: unsupported S%c record type in line %d of %s\n", + srr.record_type, srr.lineno, srr.filename); + continue; + } + /* must be S3 */ + if (s3s7_get_addr_data(&srr) < 0) { + /* error msg already printed */ + fclose(srr.openfile); + return(-1); + } + if (srr.datalen < 1) { + fprintf(stderr, + "%s line %d: S3 record of zero data length ignored\n", + srr.filename, srr.lineno); + continue; + } + if (srr.addr & 1 || srr.datalen & 1) { + fprintf(stderr, + "%s line %d: violates word alignment requirement\n", + srr.filename, srr.lineno); + fclose(srr.openfile); + return(-1); + } + srr.addr &= bi->geom->total_size - 1; + if (srr.addr + srr.datalen > bi->geom->total_size) { + fprintf(stderr, + "%s line %d: goes past the end of the flash bank\n", + srr.filename, srr.lineno); + fclose(srr.openfile); + return(-1); + } + if (!rec_count) + printf("Programming flash, each \'.\' is 100 S-records\n"); + sprintf(shortarg, "%lx", (u_long) srr.addr); + build_flashw_hex_string(srr.record + 5, longarg, + srr.datalen >> 1, is_m0); + tpinterf_make_cmd(targv); + if (tpinterf_send_cmd() < 0) { + fclose(srr.openfile); + return(-1); + } + resp = tpinterf_pass_output(8); /* 8 s timeout */ + if (resp) { + fclose(srr.openfile); + return(resp); + } + rec_count++; + if (rec_count % 100 == 0) { + putchar('.'); + fflush(stdout); + } + } + /* got S7 */ + fclose(srr.openfile); + if (!rec_count) { + fprintf(stderr, + "%s line %d: S7 without any preceding S3 data records\n", + srr.filename, srr.lineno); + return(-1); + } + printf("\nProgramming complete\n"); + return(0); +} + +flashcmd_program_srec(argc, argv, bank) + char **argv; +{ + if (argc != 3) { + fprintf(stderr, "usage: %s %s image.srec\n", argv[0], argv[1]); + return(-1); + } + return flashcmd_progsrec_gen(bank, argv[2], 0); +} + +flashcmd_program_m0(argc, argv, bank) + char **argv; +{ + if (argc != 3) { + fprintf(stderr, "usage: %s %s image.m0\n", argv[0], argv[1]); + return(-1); + } + return flashcmd_progsrec_gen(bank, argv[2], 1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/flutil.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,350 @@ +/* + * Miscellaneous utility functions for flash support + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include "flash.h" + +extern struct flash_bank_info flash_bank_info[2]; +extern struct flash_cmdset flash_cmdset_amd; +extern struct flash_cmdset flash_cmdset_intel; + +static int +cfi_read_byte(bi, off, ret16p) + struct flash_bank_info *bi; + int off; + uint16_t *ret16p; +{ + return do_r16(bi->base_addr + (off << 1), ret16p); +} + +static int +cfi_read_twobyte(bi, off, retptr) + struct flash_bank_info *bi; + int off; + uint16_t *retptr; +{ + uint16_t lo, hi; + + if (cfi_read_byte(bi, off, &lo) < 0) + return(-1); + lo &= 0xFF; + if (cfi_read_byte(bi, off + 1, &hi) < 0) + return(-1); + hi &= 0xFF; + *retptr = (hi << 8) | lo; + return(0); +} + +flash_get_cfi(bank) +{ + struct flash_bank_info *bi; + struct flash_geom *geom; + struct flash_region_desc *reg; + int nr; + uint16_t rdval, cmdset_id; + uint32_t size_check; + + bi = flash_bank_info + bank; + if (bi->geom) + return(0); + printf("Performing CFI query\n"); + if (do_w16(bi->base_addr + 0xAA, 0x98)) { + fprintf(stderr, "unexpected response to w16 - aborting\n"); + return(-1); + } + /* if do_r16() returns -1, error msg has already been printed */ + if (cfi_read_byte(bi, 0x10, &rdval) < 0) + return(-1); + if (rdval != 'Q') { +noqry: fprintf(stderr, "error: no QRY response from flash\n"); + amd_reset_cmd(bi); + return(-1); + } + if (cfi_read_byte(bi, 0x11, &rdval) < 0) + return(-1); + if (rdval != 'R') + goto noqry; + if (cfi_read_byte(bi, 0x12, &rdval) < 0) + return(-1); + if (rdval != 'Y') + goto noqry; + if (cfi_read_twobyte(bi, 0x13, &cmdset_id) < 0) + return(-1); + if (!bi->ops) { + switch (cmdset_id) { + case 2: + bi->ops = &flash_cmdset_amd; + break; + case 3: + bi->ops = &flash_cmdset_intel; + break; + default: + fprintf(stderr, "error: command set %04X unsupported\n", + cmdset_id); + amd_reset_cmd(bi); + return(-1); + } + } + geom = malloc(sizeof(struct flash_geom)); + if (!geom) { + fprintf(stderr, + "unable to malloc buffer for flash bank %d CFI geometry structure\n", + bank); + bi->ops->reset_cmd(bi); + return(-1); + } + /* total device size */ + if (cfi_read_byte(bi, 0x27, &rdval) < 0) { +free_and_immed_out: + free(geom); + return(-1); + } + if (rdval < 20 || rdval > 24) { + fprintf(stderr, + "error: CFI reports unreasonable device size\n"); +free_and_clean_out: + free(geom); + bi->ops->reset_cmd(bi); + return(-1); + } + geom->total_size = 1 << rdval; + if (geom->total_size > bi->bank_desc->align_size) { + fprintf(stderr, + "error: CFI device size 0x%lx exceeds configured maximum 0x%lx\n", + (u_long) geom->total_size, bi->bank_desc->align_size); + goto free_and_clean_out; + } + if (cfi_read_byte(bi, 0x2C, &rdval) < 0) + goto free_and_immed_out; + if (rdval < 1 || rdval > CFI_MAX_REGIONS) { + fprintf(stderr, + "error: CFI reports unreasonable # of erase regions\n"); + goto free_and_clean_out; + } + geom->nregions = rdval; + geom->total_sectors = 0; + size_check = 0; + for (nr = 0; nr < geom->nregions; nr++) { + reg = geom->regions + nr; + if (cfi_read_twobyte(bi, 0x2D + nr*4, &rdval) < 0) + goto free_and_immed_out; + if (rdval > 255) { + fprintf(stderr, + "error: CFI reports unreasonable # of sectors in region %d\n", + nr); + goto free_and_clean_out; + } + reg->nsectors = rdval + 1; + geom->total_sectors += reg->nsectors; + if (cfi_read_twobyte(bi, 0x2F + nr*4, &rdval) < 0) + goto free_and_immed_out; + if (rdval < 0x20 || rdval > 0x400) { + fprintf(stderr, + "error: CFI reports unreasonable sector size in region %d\n", + nr); + goto free_and_clean_out; + } + reg->sector_size = rdval << 8; + size_check += reg->sector_size * reg->nsectors; + } + if (bi->ops->reset_cmd(bi) < 0) { + /* error msg already printed */ + free(geom); + return(-1); + } + if (size_check != geom->total_size) { + fprintf(stderr, +"CFI error: added size of erase regions (%lx) != reported devive size (%lx)\n", + (u_long) size_check, (u_long) geom->total_size); + free(geom); + return(-1); + } + /* all checks passed */ + bi->geom = geom; + printf( +"CFI query successful: total size %lx, %u sectors, command set style %04X\n", + (u_long) geom->total_size, geom->total_sectors, cmdset_id); + return(1); +} + +get_flash_sector_table(bank) +{ + struct flash_bank_info *bi; + struct flash_geom *geom; + struct flash_region_desc *reg; + struct sector_info *sp; + uint32_t offset; + int nr, i; + + bi = flash_bank_info + bank; + if (bi->sectors) + return(0); + i = flash_get_cfi(bank); + if (i < 0) + return(i); + geom = bi->geom; + sp = (struct sector_info *) malloc(sizeof(struct sector_info) + * (geom->total_sectors + 1)); + if (!sp) { + fprintf(stderr, + "unable to malloc buffer for flash bank %d sector table\n", + bank); + return(-1); + } + bi->sectors = sp; + /* now fill it */ + offset = 0; + for (nr = 0; nr < geom->nregions; nr++) { + reg = geom->regions + nr; + for (i = 0; i < reg->nsectors; i++) { + sp->start = offset; + sp->size = reg->sector_size; + sp++; + offset += reg->sector_size; + } + } + /* sanity checks */ + if (sp - bi->sectors != geom->total_sectors) { + fprintf(stderr, + "BUG in get_flash_sector_table(): wrong # of sectors at the end\n"); + abort(); + } + if (offset != geom->total_size) { + fprintf(stderr, + "BUG in get_flash_sector_table(): wrong offset at the end\n"); + abort(); + } + /* finish */ + sp->start = 0; + sp->size = 0; + return(0); +} + +flashcmd_sectors(argc, argv, bank) + char **argv; +{ + struct flash_bank_info *bi; + struct sector_info *sp; + + if (argc > 2) { + fprintf(stderr, "error: too many arguments\n"); + return(-1); + } + if (get_flash_sector_table(bank) < 0) + return(-1); + bi = flash_bank_info + bank; + printf("%u sectors in flash bank %d:\n", bi->geom->total_sectors, bank); + printf("Offset Size\n"); + for (sp = bi->sectors; sp->size; sp++) + printf("%08lX %lx\n", (u_long) sp->start, (u_long) sp->size); + return(0); +} + +get_flash_sector_range(bi, useroff, userlen, startp, endp) + struct flash_bank_info *bi; + u_long useroff, userlen; + struct sector_info **startp, **endp; +{ + struct sector_info *sp; + uint32_t remlen; + + for (sp = bi->sectors; sp->size; sp++) + if (sp->start == useroff) + break; + if (!sp->size) { + fprintf(stderr, + "error: specified offset not aligned to a flash sector boundary\n"); + return(-1); + } + *startp = sp; + for (remlen = userlen; remlen; ) { + if (remlen < sp->size) { + fprintf(stderr, + "error: specified length not aligned to a flash sector boundary\n"); + return(-1); + } + remlen -= sp->size; + sp++; + } + *endp = sp; + return(0); +} + +build_flashw_hex_string(bin, strbuf, nwords, m0src) + u_char *bin; + char *strbuf; + int nwords, m0src; +{ + int i; + u_char *dp; + char *s; + + for (dp = bin, s = strbuf, i = 0; i < nwords; dp += 2, s += 4, i++) { + if (m0src) + sprintf(s, "%02X%02X", dp[0], dp[1]); + else + sprintf(s, "%02X%02X", dp[1], dp[0]); + } + *s = '\0'; +} + +flash_id_check(bank, repeat) +{ + struct flash_bank_info *bi; + struct flash_bank_desc *bd; + struct flash_idcheck *id; + int stat, fail; + uint16_t rdval; + unsigned cnt; + + bi = flash_bank_info + bank; + if (bi->idcheck_done && !repeat) + return(0); + bd = bi->bank_desc; + if (!bd->idcheck_table || !bd->idcheck_num) + return(0); + printf("Performing flash ID check\n"); + stat = do_w16(bi->base_addr + 0xAAA, 0xAA); + if (stat) { +bad_w16: fprintf(stderr, + "unexpected response to w16 in read ID cmd sequence - aborting\n"); + return(-1); + } + stat = do_w16(bi->base_addr + 0x554, 0x55); + if (stat) + goto bad_w16; + stat = do_w16(bi->base_addr + 0xAAA, 0x90); + if (stat) + goto bad_w16; + id = bd->idcheck_table; + fail = 0; + for (cnt = 0; cnt < bd->idcheck_num; cnt++) { + stat = do_r16(bi->base_addr + id->offset, &rdval); + if (stat) + return(stat); /* error msg already printed */ + printf("offset %02X: %04X -- ", (int)id->offset, (int)rdval); + if (rdval == id->expect_val) + printf("PASS\n"); + else { + printf("FAIL: expected %04X\n", (int)id->expect_val); + fail = 1; + break; + } + id++; + } + /* reset flash to read mode */ + stat = do_w16(bi->base_addr + 0xAAA, 0xF0); + if (stat) { + fprintf(stderr, + "unexpected response to w16 when resetting flash to read mode!\n"); + return(-1); + } + if (fail) + return(-1); + bi->idcheck_done = 1; + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/gta-ap-build.sed Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,3 @@ +s,^CC=.*$,CC= /opt/arm-2012.03/bin/arm-none-linux-gnueabi-gcc, +s,^CFLAGS=.*$,CFLAGS= -O2 -march=armv4t -mtune=arm920t -DGTA0x_AP_BUILD, +s,^EXTRA_OBJ=.*$,EXTRA_OBJ= compaldummy.o gtapower.o,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/gtapower.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,54 @@ +/* + * This module is included only when loadtools are being built to run on the + * GTA0x application processor (AP). It provides automated modem power + * control, i.e., coordinates modem power control with loadtools operations + * for convenience. + */ + +#include <sys/types.h> +#include <sys/file.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +/* + * Check this pathname: it is correct for the kernel version I'm using + * on my test GTA02, but it differs for some other kernel versions. + */ +static char modem_powerctl_pathname[] = + "/sys/bus/platform/devices/gta02-pm-gsm.0/power_on"; + +void +set_gta_modem_power_ctrl(boolval) +{ + char strbuf[16]; + int len, fd; + + len = sprintf(strbuf, "%d\n", boolval); + fd = open(modem_powerctl_pathname, O_WRONLY); + if (fd < 0) { + perror(modem_powerctl_pathname); + exit(1); + } + write(fd, strbuf, len); + close(fd); +} + +void +fork_gta_modem_poweron() +{ + int i; + + i = fork(); + if (i < 0) { + perror("fork"); + exit(1); + } + if (i) + return; + printf("Toggling %s\n", modem_powerctl_pathname); + set_gta_modem_power_ctrl(0); + usleep(350000); + set_gta_modem_power_ctrl(1); + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/hexdecode.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,30 @@ +/* + * This module contains the decode_hex_byte() function, + * which is used by the SREC file reader and will likely be used + * by other code as well, such as the dump-to-file function + * of loadtool. + */ + +#include <ctype.h> + +decode_hex_byte(s) + char *s; +{ + register int u, l; + + if (!isxdigit(s[0]) || !isxdigit(s[1])) + return(-1); + if (isdigit(s[0])) + u = s[0] - '0'; + else if (isupper(s[0])) + u = s[0] - 'A' + 10; + else + u = s[0] - 'a' + 10; + if (isdigit(s[1])) + l = s[1] - '0'; + else if (isupper(s[1])) + l = s[1] - 'A' + 10; + else + l = s[1] - 'a' + 10; + return((u << 4) | l); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/hwparam.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,190 @@ +/* + * This module contains the code that reads the hardware parameter files + * specified with -h or -H, and sets variables for later use by other code. + */ + +#include <sys/param.h> +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> + +extern char default_helpers_dir[]; + +extern void set_boot_reflash_hack(); +extern void set_default_exit_mode(); +extern void set_flash_device(); + +char hw_init_script[128]; + +static void +handle_compal_stage(arg, filename_for_errs, lineno_for_errs) + char *arg; + char *filename_for_errs; + int lineno_for_errs; +{ + char *cp; + + while (isspace(*arg)) + arg++; + if (!*arg) { + fprintf(stderr, + "%s line %d: compal-stage setting requires an argument\n", + filename_for_errs, lineno_for_errs); + exit(1); + } + for (cp = arg; *cp && !isspace(*cp); cp++) + ; + *cp = '\0'; + set_compalstage_short(arg); +} + +static void +handle_init_script(arg, filename_for_errs, lineno_for_errs) + char *arg; + char *filename_for_errs; + int lineno_for_errs; +{ + char *cp; + + while (isspace(*arg)) + arg++; + if (!*arg) { + fprintf(stderr, + "%s line %d: init-script setting requires an argument\n", + filename_for_errs, lineno_for_errs); + exit(1); + } + for (cp = arg; *cp && !isspace(*cp); cp++) + ; + *cp = '\0'; + if (cp - arg > sizeof(hw_init_script) - 1) { + fprintf(stderr, + "%s line %d: init-script argument is too long (buffer overflow)\n", + filename_for_errs, lineno_for_errs); + exit(1); + } + strcpy(hw_init_script, arg); +} + +static void +handle_pll_config(arg, filename_for_errs, lineno_for_errs) + char *arg; + char *filename_for_errs; + int lineno_for_errs; +{ + int mult, div; + + while (isspace(*arg)) + arg++; + if (!isdigit(*arg)) { +inv: fprintf(stderr, "%s line %d: pll-config argument must be M/N\n", + filename_for_errs, lineno_for_errs); + exit(1); + } + mult = atoi(arg); + arg++; + if (isdigit(*arg)) + arg++; + if (*arg++ != '/') + goto inv; + if (!isdigit(*arg)) + goto inv; + div = atoi(arg); + arg++; + if (*arg && !isspace(*arg)) + goto inv; + if (mult < 0 || mult > 31 || div < 1 || div > 4) { + fprintf(stderr, + "%s line %d: pll-config argument is out of range\n", + filename_for_errs, lineno_for_errs); + exit(1); + } + set_romload_pll_conf((mult << 2) | (div - 1)); +} + +static void +handle_rhea_cntl(arg, filename_for_errs, lineno_for_errs) + char *arg; + char *filename_for_errs; + int lineno_for_errs; +{ + int byte; + + while (isspace(*arg)) + arg++; + if (arg[0] == '0' && (arg[1] == 'x' || arg[1] == 'X')) + arg += 2; + byte = decode_hex_byte(arg); + if (byte < 0 || arg[2] && !isspace(arg[2])) { + fprintf(stderr, + "%s line %d: rhea-cntl argument must be a hex byte value\n", + filename_for_errs, lineno_for_errs); + exit(1); + } + set_romload_rhea_cntl(byte); +} + +static struct cmdtab { + char *name; + void (*func)(); +} cmdtab[] = { + {"boot-reflash-hack", set_boot_reflash_hack}, + {"compal-stage", handle_compal_stage}, + {"exit-mode", set_default_exit_mode}, + {"flash", set_flash_device}, + {"init-script", handle_init_script}, + {"pll-config", handle_pll_config}, + {"rhea-cntl", handle_rhea_cntl}, + {0, 0} +}; + +void +read_hwparam_file_fullpath(filename) + char *filename; +{ + FILE *f; + char linebuf[512]; + int lineno; + char *cp, *np; + struct cmdtab *tp; + + f = fopen(filename, "r"); + if (!f) { + perror(filename); + exit(1); + } + for (lineno = 1; fgets(linebuf, sizeof linebuf, f); lineno++) { + for (cp = linebuf; isspace(*cp); cp++) + ; + if (!*cp || *cp == '#') + continue; + for (np = cp; *cp && !isspace(*cp); cp++) + ; + if (*cp) + *cp++ = '\0'; + for (tp = cmdtab; tp->name; tp++) + if (!strcmp(tp->name, np)) + break; + if (tp->func) + tp->func(cp, filename, lineno); + else { + fprintf(stderr, + "%s line %d: setting \"%s\" not understood\n", + filename, lineno, np); + exit(1); + } + } + fclose(f); +} + +void +read_hwparam_file_shortname(confname) + char *confname; +{ + char pathname[MAXPATHLEN]; + + sprintf(pathname, "%s/%s.config", default_helpers_dir, confname); + read_hwparam_file_fullpath(pathname); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/hwparamstubs.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,21 @@ +/* + * The exit-mode and flash settings in the hardware parameter files + * specified with -h or -H are meaningful only for fc-loadtool, but + * the same hwparam.c code is included in fc-iram and fc-xram as well. + * This module provides the stubs, allowing fc-iram and fc-xram to link. + */ + +void +set_default_exit_mode() +{ +} + +void +set_flash_device() +{ +} + +void +set_boot_reflash_hack() +{ +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/initscript.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,124 @@ +/* + * This module has been copied from ltscript.c, ltdispatch.c and ltpassthru.c: + * here we implement the init-script functionality for fc-xram. + */ + +#include <sys/param.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> + +extern char default_helpers_dir[]; + +extern int cmd_baud(); + +static +loadagent_cmd(argc, argv) + char **argv; +{ + if (tpinterf_make_cmd(argv) < 0) { + fprintf(stderr, "error: unable to form target command\n"); + return(-1); + } + if (tpinterf_send_cmd() < 0) + return(-1); + return tpinterf_pass_output(1); +} + +static struct cmdtab { + char *cmd; + int minargs; + int maxargs; + int (*func)(); +} cmdtab[] = { + {"baud", 1, 1, cmd_baud}, + {"w8", 2, 2, loadagent_cmd}, + {"w16", 2, 2, loadagent_cmd}, + {"w32", 2, 2, loadagent_cmd}, + {0, 0, 0, 0} +}; + +static +dispatch_cmd(cmd) + char *cmd; +{ + char *argv[10]; + char *cp, **ap; + struct cmdtab *tp; + + for (cp = cmd; isspace(*cp); cp++) + ; + if (!*cp || *cp == '#') + return(0); + printf("init-script command: %s\n", cp); + argv[0] = cp; + while (*cp && !isspace(*cp)) + cp++; + if (*cp) + *cp++ = '\0'; + for (tp = cmdtab; tp->cmd; tp++) + if (!strcmp(tp->cmd, argv[0])) + break; + if (!tp->func) { + fprintf(stderr, "error: no such command\n"); + return(-1); + } + for (ap = argv + 1; ; ) { + while (isspace(*cp)) + cp++; + if (!*cp || *cp == '#') + break; + if (ap - argv - 1 >= tp->maxargs) { + fprintf(stderr, "error: too many arguments\n"); + return(-1); + } + *ap++ = cp; + while (*cp && !isspace(*cp)) + cp++; + if (*cp) + *cp++ = '\0'; + } + if (ap - argv - 1 < tp->minargs) { + fprintf(stderr, "error: too few arguments\n"); + return(-1); + } + *ap = 0; + return tp->func(ap - argv, argv); +} + +exec_init_script(script_name) + char *script_name; +{ + char pathbuf[MAXPATHLEN], *openfname; + FILE *f; + char linebuf[512], *cp; + int lineno, retval = 0; + + if (index(script_name, '/')) + openfname = script_name; + else { + sprintf(pathbuf, "%s/%s", default_helpers_dir, script_name); + openfname = pathbuf; + } + f = fopen(openfname, "r"); + if (!f) { + perror(openfname); + return(-1); + } + for (lineno = 1; fgets(linebuf, sizeof linebuf, f); lineno++) { + cp = index(linebuf, '\n'); + if (!cp) { + fprintf(stderr, "%s line %d: missing newline\n", + openfname, lineno); + fclose(f); + return(-1); + } + *cp = '\0'; + retval = dispatch_cmd(linebuf); + if (retval) + break; + } + fclose(f); + return(retval); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/install-helpers.sh Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,25 @@ +#!/bin/sh +# A functional installation of FreeCalypso loadtools consists of not only +# the fc-* host binaries, but also the loadagent and compalstage target +# binaries and some script and help files. This shell script is +# responsible for installing the latter. + +instdir=/usr/local/share/freecalypso +set -ex +mkdir -p $instdir + +# The target-binaries directory may or may not be present. Loadagent and +# compalstage are built in the target-utils tree with the ARM7 toolchain, +# hence having prebuilt binaries would be an important convenience for +# end user releases. But if one is working with just a source tree, with +# nothing prebuilt, there will be no target-binaries directory here; +# one needs to have the ARM7 toolchain installed, then build target-utils, +# then do a 'make install' there. + +if [ -d target-binaries ] +then + install -c target-binaries/* $instdir +fi + +# scripts and loadtool.help should always be present +install -c scripts/* loadtool.help $instdir
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/labaud.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,48 @@ +/* + * This module handles the switching of serial baud rates + * in coordination with loadagent. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <termios.h> +#include <unistd.h> +#include "baudrate.h" + +extern int target_fd; +extern struct baudrate *current_baud_rate; +extern struct baudrate *find_baudrate_by_name(); + +loadagent_switch_baud(newbr) + struct baudrate *newbr; +{ + char *argv[3]; + static char U = 'U'; + + printf("Switching loadagent communication to %s baud\n", newbr->name); + argv[0] = "baud"; + argv[1] = newbr->name; + argv[2] = 0; + tpinterf_make_cmd(argv); + if (tpinterf_send_cmd() < 0) + return(-1); + switch_baud_rate(newbr); + usleep(150000); + write(target_fd, &U, 1); + return tpinterf_pass_output(1); +} + +cmd_baud(argc, argv) + char **argv; +{ + struct baudrate *br; + + if (argc < 2) { + printf("Current baud rate is %s\n", current_baud_rate->name); + return(0); + } + br = find_baudrate_by_name(argv[1]); + if (!br) + return(-1); /* error msg already printed */ + return loadagent_switch_baud(br); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/loadtool.help Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,348 @@ +This is the help file for fc-loadtool. See lthelp.c for the code +that parses and displays it. The parsing code is the only +documentation for the format of this help file - if you are going to +edit this help text, read the parsing code first. + +=== main +This utility allows you to perform the following operations +on your Calypso GSM device: + +* Peek and poke registers +* Dump any part of memory +* Read and program flash + +See the following help topics for more information: + +help peekpoke Register peek and poke commands +help flash Flash operation commands +help all List of all implemented commands +help exit Controlling the cleanup on exit + +=== all +abbr Read an ABB register +abbw Write an ABB register +baud Switch the serial comm with loadagent to a different baud rate +crc32 Get CRC-32 of a memory area on the target +dieid Read the Calypso die ID +dump Dump a target memory region in hex and ASCII +dump2bin Dump a target memory region to a file in binary format +dump2srec Dump a target memory region to a file in S-record format +exec Execute a command script +exit Exit from loadtool and clean up the target device state +flash Flash operations +flash2 Operations on the 2nd flash bank (Pirelli phone only) +quit Alias for exit +r8 Read an 8-bit register or memory location +r16 Read a 16-bit register or memory location +r32 Read a 32-bit register or memory location +w8 Write an 8-bit register or memory location +w16 Write a 16-bit register or memory location +w32 Write a 32-bit register or memory location + +To get help on any command, type help and the command keyword. + +=== abbr +=== abbw +abbr pg reg Read ABB register <reg> on page <pg> +abbw pg reg val Write <val> into register <reg> on page <pg> + +The <pg> and <reg> arguments default to decimal unless prefixed with 0x; +the <val> argument to abbw is always hexadecimal. + +=== baud +baud Display the current baud rate +baud <rate> Switch the baud rate to <rate> (number in bps) + +The supported baud rates are: + +Standard: 19200, 38400, 57600, 115200 +Calypso special: 203125, 406250, 812500 + +The baud command coordinates the necessary simultaneous switching of the +baud rate on both the host and the target (loadagent). Loadagent always +supports all of the listed rates and will switch happily, but in the case +of the higher non-standard baud rates fc-loadtool has no way of knowing +ahead of time whether or not the requested baud rate is supported by your +usb2serial adapter or whatever other serial port hardware and driver +you are using. If the baud rate switch fails, the communication link with +the target will be broken and fc-loadtool will exit ungracefully. + +=== crc32 +crc32 hex-start hex-len + +The first argument is the starting target memory address in hex; the second +argument is the length of the area to CRC, also in hex. The command will be +sent to loadagent; CRC-32 of the requested range will be computed on the target +and displayed in hex. + +=== dieid +dieid Display the Calypso die ID +dieid <filename> Display the Calypso die ID, and also save it in the + named file + +The Calypso die ID resides in 4 16-bit registers at target addresses +0xFFFEF010 through 0xFFFEF016. It is displayed on the terminal and optionally +saved to a file in this simple form: + +FFFEF010: xxxx +FFFEF012: xxxx +FFFEF014: xxxx +FFFEF016: xxxx + +=== dump +dump hex-start hex-len + +The first argument is the starting target memory address in hex; the second +argument is the length of the area to dump, also in hex. The dump will be +displayed on the terminal in hex and ASCII. + +=== dump2bin +=== dump2srec +dump2bin hex-start hex-len outfile +dump2srec hex-start hex-len outfile + +The first argument is the starting target memory address in hex; the second +argument is the length of the area to dump, also in hex; the third argument +is the name of the output file to be created/written. The dump will be saved +in binary or S-records as per the chosen command, always in the native byte +order of the Calypso ARM7 target (little-endian). + +=== exec +exec <script-file> + +Read and execute commands from the named file. If the given file name contains +no slashes, the script file is sought in the default directory (normally +/usr/local/share/freecalypso unless changed in the code); otherwise the given +name is used directly as the pathname. + +=== exit +=== quit +exit Clean up the target in the default manner and exit +exit bare Exit loadtool without doing anything to the target +exit iota-off Exit loadtool and command an ABB power-off on the target +exit jump0 Exit loadtool and command the target to reboot via jump to 0 + +The default method of cleaning up the target device state upon exit is set +in the hardware parameters file selected with the -h or -H command line +option; it is the exit-mode setting. On the Pirelli phone the default exit +mode is jump0: it causes the phone to reboot and enter the "charging boot" +mode, as the USB cable is connected and VBUS is present. On Compal phones the +default exit mode is iota-off. + +If your device is a GTA02 and you are running fc-loadtool from inside the phone +(from the AP), the exit command will power off the modem from the AP. If you +are talking to GTA02 Calypso from an external host via the headset jack, there +is nothing that fc-loadtool can currently do to power the modem off (exit is +the same as exit bare in this case) - power it off yourself from the AP. + +If you do an exit bare without powering the target device off in some other +way, the device will still be running loadagent, which is probably not what you +want. However, it is the proper exit mode if you have powered off or reset the +target device by brute force (yanking the battery). + +=== flash +=== flash2 +The primary end use of fc-loadtool is for reading and writing the NOR flash +memories of the supported GSM devices. Compal phones and the GTA0x GSM modem +have only one flash bank (as in chip select), and are manipulated with the +flash command. The Pirelli phone has two flash banks (as in chip selects) of +8 MiB each; they are manipulated with the flash and flash2 commands. + +The following flash operations are available on all target devices: + +flash blankchk Blank-check a region of flash +flash dump2bin Dump flash content to a file in binary format +flash dump2srec Dump flash content to a file in S-record format +flash erase Erase a region of flash +flash info Display flash configuration info +flash program-bin Program flash with a binary file +flash program-m0 Program flash with an image in TI's *.m0 format +flash program-srec Program flash with an image in standard S-record format +flash quickprog Program a few flash words from the command line +flash reset Reset flash chip to read array mode +flash sectors Display the list of flash sector addresses and sizes + +Substitute flash2 instead of flash when operating on the 2nd flash chip select +of Pirelli-style flash memory configurations. Prepend help before a command to +get usage information, e.g., help flash program-bin. See help compal for some +additional info specific to Compal targets. + +=== compal +=== compalflash +=== flash:compal +Compal phones have Intel or Intel-style flash chips; other Calypso targets for +which loadtool was originally designed have AMD-style flash chips. The author +of the present software has a personal bias toward AMD-style flash, hence the +support for Intel-style flash is not as clean. Compal phones also have the +Calypso boot ROM disabled, and depend on flash-resident boot code instead. +This property makes them brickable. + +The following additional loadtool commands apply only to Compal targets with +Intel-style flash: + +flash erase-program-boot Erase and reprogram the boot sector +flash status Read Intel flash Status Register +flash unlock Unlock flash sectors + +=== flash:blankchk +flash[2] blankchk hex-start-offset hex-length + +Blank-checks an area of flash starting at the specified hex offset (from the +base address of the flash bank) and extending for the specified hex length. +Reports whether the checked region is blank or not. Flash must be blank (FF in +all bytes) before it can be programmed. + +=== flash:dump2bin +flash[2] dump2bin outfile [offset [length]] + +Read device flash content and save it to a file. If only a filename is +specified, the full flash bank is dumped; one can optionally specify a starting +offset and an explicit length, both in hex. + +This command is merely a user-friendly front-end to the plain dump2bin command; +see help dump2bin. + +=== flash:dump2srec +flash[2] dump2srec outfile [offset [length]] + +Read device flash content and save it to a file. If only a filename is +specified, the full flash bank is dumped; one can optionally specify a starting +offset and an explicit length, both in hex. + +This command is merely a user-friendly front-end to the plain dump2srec command; +see help dump2srec. + +=== flash:erase +flash[2] erase hex-start-offset hex-length + +Erases an area of flash starting at the specified hex offset (from the base +address of the flash bank) and extending for the specified hex length. + +Flash memory can only be erased (turning 0 bits back to 1s) in units of +sectors, as set in stone by the design of the flash chip in use. Loadtool +knows the sector layout of the flash chip in your device from CFI or from the +hardware parameters file (you can display it with the flash[2] sectors +command), and enforces that both arguments to the flash[2] erase command lie +on sector boundaries. + +=== flash:erase-program-boot +flash erase-program-boot binfile [length] + +This operation is applicable to Compal targets only. This command erases and +reprograms flash sector 0 (the boot sector) with minimized vulnerability to +bricking by loading the new boot code into a scratchpad RAM area on the target, +then commanding loadagent (running on the target) to erase and reprogram the +dangerous flash sector without requiring further interaction with loadtool. +(In contrast, loadtool's "regular" flash erase and program operations are +driven primarily by loadtool, with loadagent providing only low-level +functions.) + +The new bits to be programmed are taken from the specified binary file. Byte 0 +of the file goes into byte 0 of the flash and so on, for the specified length. +If no length argument is given, it defaults to the length of the file, which +must not exceed the length of flash sector 0: 64 KiB on the "basic" Compal +phones or 8 KiB on C155/156. + +=== flash:info +This command displays summary information about the flash memory configuration +of the Calypso target device loadtool thinks it's talking to. + +=== flash:program-bin +flash[2] program-bin flash-offset binfile [file-offset [length]] + +This command programs flash, using a binary file as the data source. One must +always specify the starting flash offset (from the base address of the flash +bank), but the starting file offset and length are optional, defaulting to the +whole file. + +The binary file must be in the native byte order of the Calypso ARM7 processor, +which is little-endian. Images produced by flash[2] dump2bin are suitable. + +=== flash:program-m0 +flash[2] program-m0 image.m0 + +*.m0 is the format that has been used by companies like TI and Closedmoko for +their proprietary firmware images. It is emitted by TI's hex470 tool, and in +the proprietary environment it is fed as an input to FLUID. (The latter is +TI's Flash Loader Utility Independent of Device, and fc-loadtool can be seen as +an independent reimplementation thereof - although it doesn't have the same +level of device-independence.) The *.m0 format is actually a variant of +Motorola's SREC, but with a different byte order: each 16-bit word is +byte-reversed relative to the native byte order of the ARM7 processor. +(This strange byte order actually makes some sense if one views the image as a +long array of 16-bit hex values; 16 bits is the width of the flash memory on +Calypso GSM devices and thus the natural unit size for flash programming.) + +Because each S-record contains an address, no addresses or offsets need to be +specified in the flash[2] program-m0 command, only the image file. + +=== flash:program-srec +flash[2] program-srec image.srec + +This command programs the flash with an image in the standard S-record format, +in the native little-endian byte order of the Calypso ARM7 processor. It is +the opposite byte order from that used by TI's *.m0 files - +see help flash program-m0. Images produced by flash[2] dump2srec are suitable +for flash[2] program-srec. + +Because each S-record contains an address, no addresses or offsets need to be +specified in the flash[2] program-srec command, only the image file. + +=== flash:quickprog +flash[2] quickprog hex-offset hex-data-string + +This command is intended only for developers; it provides raw access to +loadagent's basic flash write primitive. Read the source code for more +information. + +=== flash:reset +Intel-style flash memory chips (found in Compal phones) have two "stable" or +"quiescent" states: reading array data and reading the status register (SR). +After an erase or program operation the flash chip is "parked" in the Read SR +state; the flash reset command switches it back to reading array data. + +This command works for AMD-style flash as well (found in Openmoko and Pirelli +phones), but it is normally not needed, as AMD-style flash chips automatically +return to the read-array-data state after every erase or program operation. + +=== flash:sectors +This command displays the list of sector offsets and sizes for the flash chip +in the Calypso target device loadtool thinks it's talking to. + +=== flash:status +This command is only applicable to Intel-style flash as found in Compal phones. +It reads the flash chip's Status Register, which can be used to diagnose errors +incurred by previous erase or program operations. + +=== flash:unlock +flash unlock hex-start-offset hex-length + +This command is only applicable to Intel-style flash as found in Compal phones. +These flash chips power up with each sector (erase block) in the "locked" state; +each sector needs to be unlocked before it can be erased or programmed. + +This command is normally not needed, as the flash erase command unlocks each +sector before erasing it. However, if you are going to perform program +operations in some sectors without erasing them, you will need to unlock them +explicitly first. + +This command operates only on sector boundaries just like flash erase. + +=== r8 +=== r16 +=== r32 +=== w8 +=== w16 +=== w32 +=== peekpoke +The register peek and poke commands are: + +r8 addr Read an 8-bit register or memory location +r16 addr Read a 16-bit register or memory location +r32 addr Read a 32-bit register or memory location +w8 addr data Write an 8-bit register or memory location +w16 addr data Write a 16-bit register or memory location +w32 addr data Write a 32-bit register or memory location + +All addresses and data values are in hex. +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/ltdispatch.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,97 @@ +/* + * This module implements the command dispatch for fc-loadtool + */ + +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> + +extern int cmd_baud(); +extern int cmd_crc32(); +extern int cmd_dieid(); +extern int cmd_dump2bin(); +extern int cmd_dump2srec(); +extern int cmd_exec(); +extern int cmd_exit(); +extern int cmd_flash(); +extern int cmd_help(); +extern int loadtool_cmd_passthru(); + +static struct cmdtab { + char *cmd; + int minargs; + int maxargs; + int (*func)(); +} cmdtab[] = { + {"abbr", 2, 2, loadtool_cmd_passthru}, + {"abbw", 3, 3, loadtool_cmd_passthru}, + {"baud", 0, 1, cmd_baud}, + {"crc32", 2, 2, cmd_crc32}, + {"dieid", 0, 1, cmd_dieid}, + {"dump", 2, 2, loadtool_cmd_passthru}, + {"dump2bin", 3, 3, cmd_dump2bin}, + {"dump2srec", 3, 3, cmd_dump2srec}, + {"exec", 1, 1, cmd_exec}, + {"exit", 0, 1, cmd_exit}, + {"flash", 1, 5, cmd_flash}, + {"flash2", 1, 5, cmd_flash}, + {"help", 0, 2, cmd_help}, + {"quit", 0, 1, cmd_exit}, + {"r8", 1, 1, loadtool_cmd_passthru}, + {"r16", 1, 1, loadtool_cmd_passthru}, + {"r32", 1, 1, loadtool_cmd_passthru}, + {"w8", 2, 2, loadtool_cmd_passthru}, + {"w16", 2, 2, loadtool_cmd_passthru}, + {"w32", 2, 2, loadtool_cmd_passthru}, + {0, 0, 0, 0} +}; + +loadtool_dispatch_cmd(cmd, is_script) + char *cmd; +{ + char *argv[10]; + char *cp, **ap; + struct cmdtab *tp; + + for (cp = cmd; isspace(*cp); cp++) + ; + if (!*cp || *cp == '#') + return(0); + if (is_script) + printf("Script command: %s\n", cp); + argv[0] = cp; + while (*cp && !isspace(*cp)) + cp++; + if (*cp) + *cp++ = '\0'; + for (tp = cmdtab; tp->cmd; tp++) + if (!strcmp(tp->cmd, argv[0])) + break; + if (!tp->func) { + fprintf(stderr, "error: no such command\n"); + return(-1); + } + for (ap = argv + 1; ; ) { + while (isspace(*cp)) + cp++; + if (!*cp || *cp == '#') + break; + if (ap - argv - 1 >= tp->maxargs) { + fprintf(stderr, "error: too many arguments\n"); + return(-1); + } + *ap++ = cp; + while (*cp && !isspace(*cp)) + cp++; + if (*cp) + *cp++ = '\0'; + } + if (ap - argv - 1 < tp->minargs) { + fprintf(stderr, "error: too few arguments\n"); + return(-1); + } + *ap = 0; + return tp->func(ap - argv, argv); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/ltdump.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,257 @@ +/* + * This module implements the dump2bin and dump2srec functionality + * of fc-loadtool. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <time.h> + +extern uint32_t crc32_table[]; +extern char target_response_line[]; + +crc32_on_target(area_base, area_len, retptr) + u_long area_base, area_len, *retptr; +{ + char arg1[10], arg2[10], *argv[4]; + int stat; + char *strtoul_endp; + + sprintf(arg1, "%lx", area_base); + sprintf(arg2, "%lx", area_len); + argv[0] = "crc32"; + argv[1] = arg1; + argv[2] = arg2; + argv[3] = 0; + tpinterf_make_cmd(argv); + if (tpinterf_send_cmd() < 0) + return(-1); + stat = tpinterf_capture_output_oneline(10); /* 10 s timeout */ + if (stat != 1) { +errout: fprintf(stderr, "error: malformed response to crc32 command\n"); + return(-1); + } + if (strlen(target_response_line) != 8) + goto errout; + *retptr = strtoul(target_response_line, &strtoul_endp, 16); + if (strtoul_endp != target_response_line + 8) + goto errout; + return(0); +} + +cmd_crc32(argc, argv) + char **argv; +{ + u_long area_base, area_len; + char *strtoul_endp; + u_long crc_result; + int stat; + + area_base = strtoul(argv[1], &strtoul_endp, 16); + if (*strtoul_endp) { +inv: fprintf(stderr, "usage: crc32 hex-start hex-len\n"); + return(-1); + } + area_len = strtoul(argv[2], &strtoul_endp, 16); + if (*strtoul_endp) + goto inv; + stat = crc32_on_target(area_base, area_len, &crc_result); + if (stat == 0) + printf("%08lX\n", crc_result); + return(stat); +} + +/* the actual dump facility */ + +static FILE *dump_outfile; +static int dump_save_srec; +static uint32_t dump_nextaddr, dump_crcaccum; +static uint32_t dump_total_len, dump_progress_len; +static u_char dump_binrec[0x86]; +static time_t dump_last_time; + +static char dumpsrec_s0_line[] = "S007000044554D50C2\n"; +static char dumpsrec_s7_line[] = "S70500000000FA\n"; + +static +dump_receiver(line) + char *line; +{ + int i, b; + u_char sr_cksum; + uint32_t addr_from_srec; + time_t curtime; + + if (strncmp(line, "S385", 4)) { + fprintf(stderr, + "error: target response is not the expected S385...\n"); + return(-1); + } + for (i = 0; i < 0x86; i++) { + b = decode_hex_byte(line + i*2 + 2); + if (b < 0) { + fprintf(stderr, + "data from target: S-record hex decode error\n"); + return(-1); + } + dump_binrec[i] = b; + } + sr_cksum = 0; + for (i = 0; i < 0x86; i++) + sr_cksum += dump_binrec[i]; + if (sr_cksum != 0xFF) { + fprintf(stderr, "data from target: bad S-record checksum\n"); + return(-1); + } + /* basic S-record format OK; now verify the address */ + addr_from_srec = ((uint32_t) dump_binrec[1] << 24) | + ((uint32_t) dump_binrec[2] << 16) | + ((uint32_t) dump_binrec[3] << 8) | + (uint32_t) dump_binrec[4]; + if (addr_from_srec != dump_nextaddr) { + fprintf(stderr, + "error: S3 record from target has the wrong address\n"); + return(-1); + } + /* all checks passed - save it */ + if (dump_save_srec) { + if (!dump_progress_len) + fputs(dumpsrec_s0_line, dump_outfile); + fprintf(dump_outfile, "%s\n", line); + } else + fwrite(dump_binrec + 5, 1, 0x80, dump_outfile); + /* update running CRC */ + for (i = 0; i < 0x80; i++) + dump_crcaccum = crc32_table[dump_crcaccum & 0xFF ^ + dump_binrec[i+5]] ^ + (dump_crcaccum >> 8); + /* progress indication */ + dump_progress_len += 0x80; + i = dump_progress_len * 100 / dump_total_len; + time(&curtime); + if (curtime != dump_last_time || i == 100) { + printf("\rRx %lu out of %lu bytes (%i%%)", + (u_long) dump_progress_len, (u_long) dump_total_len, i); + fflush(stdout); + } + dump_nextaddr += 0x80; + dump_last_time = curtime; + return(1); +} + +loadtool_memdump(start_addr, area_len, filename, fmt_srec) + u_long start_addr, area_len; + char *filename; +{ + u_long target_crc_init, target_crc_fin; + char *target_argv[4], target_arg1[10], target_arg2[10]; + int stat; + + if (start_addr & 0x7F || area_len & 0x7F) { + fprintf(stderr, + "error: implementation limit: 128-byte alignment required\n"); + return(-1); + } + printf("Requesting initial CRC-32 of the area from target...\n"); + stat = crc32_on_target(start_addr, area_len, &target_crc_init); + if (stat) + return(stat); + printf("got %08lX\n", target_crc_init); + dump_outfile = fopen(filename, "w"); + if (!dump_outfile) { + perror(filename); + return(-1); + } + dump_save_srec = fmt_srec; + dump_nextaddr = start_addr; + dump_crcaccum = 0xFFFFFFFF; + dump_total_len = area_len; + dump_progress_len = 0; + + printf("Requesting memory dump...\n"); + sprintf(target_arg1, "%lx", start_addr); + sprintf(target_arg2, "%lx", area_len); + target_argv[0] = "DUMP"; + target_argv[1] = target_arg1; + target_argv[2] = target_arg2; + target_argv[3] = 0; + tpinterf_make_cmd(target_argv); + stat = tpinterf_send_cmd(); + if (stat < 0) { + fclose(dump_outfile); + return(stat); + } + stat = tpinterf_capture_output(2, dump_receiver); + if (stat < 0) { + fclose(dump_outfile); + return(stat); + } + putchar('\n'); /* after last progress line */ + + /* sanity checks */ + if (dump_nextaddr != start_addr + area_len) { + fclose(dump_outfile); + fprintf(stderr, + "error: received dump length does not match expected\n"); + return(-1); + } + if (dump_crcaccum != (uint32_t) target_crc_init) { + fclose(dump_outfile); + fprintf(stderr, "error: CRC mismatch (computed %lX)\n", + (u_long) dump_crcaccum); + return(-1); + } + if (fmt_srec) + fputs(dumpsrec_s7_line, dump_outfile); + fclose(dump_outfile); + printf("Requesting another CRC-32 of the area from target...\n"); + stat = crc32_on_target(start_addr, area_len, &target_crc_fin); + if (stat) + return(stat); + if (target_crc_fin == target_crc_init) { + printf("match, dump successful\n"); + return(0); + } else { + fprintf(stderr, "mismatch: got %lX this time\n", + target_crc_fin); + return(-1); + } +} + +cmd_dump2bin(argc, argv) + char **argv; +{ + u_long area_base, area_len; + char *strtoul_endp; + + area_base = strtoul(argv[1], &strtoul_endp, 16); + if (*strtoul_endp) { +inv: fprintf(stderr, "usage: dump2bin hex-start hex-len outfile\n"); + return(-1); + } + area_len = strtoul(argv[2], &strtoul_endp, 16); + if (*strtoul_endp) + goto inv; + return loadtool_memdump(area_base, area_len, argv[3], 0); +} + +cmd_dump2srec(argc, argv) + char **argv; +{ + u_long area_base, area_len; + char *strtoul_endp; + + area_base = strtoul(argv[1], &strtoul_endp, 16); + if (*strtoul_endp) { +inv: fprintf(stderr, "usage: dump2srec hex-start hex-len outfile\n"); + return(-1); + } + area_len = strtoul(argv[2], &strtoul_endp, 16); + if (*strtoul_endp) + goto inv; + return loadtool_memdump(area_base, area_len, argv[3], 1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/ltexit.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,109 @@ +/* + * This module implements the loadtool exit command, along with its + * options for jump-reboot and Iota power-off. + */ + +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> + +static void +exit_bare() +{ + exit(0); +} + +static void +exit_gta02_cutpwr() +{ +#ifdef GTA0x_AP_BUILD + set_gta_modem_power_ctrl(0); +#endif + exit(0); +} + +static void +exit_iotaoff() +{ + static char *poweroff_argv[2] = {"poweroff", 0}; + + tpinterf_make_cmd(poweroff_argv); + tpinterf_send_cmd(); + exit(0); +} + +static void +exit_jump0() +{ + static char *jump0_argv[3] = {"jump", "0", 0}; + + tpinterf_make_cmd(jump0_argv); + tpinterf_send_cmd(); + exit(0); +} + +void (*default_exit)() = exit_bare; + +static struct kwtab { + char *kw; + void (*func)(); +} exit_modes[] = { + {"bare", exit_bare}, + {"gta02-cutpwr", exit_gta02_cutpwr}, + {"iota-off", exit_iotaoff}, + {"jump0", exit_jump0}, + {0, 0} +}; + +cmd_exit(argc, argv) + char **argv; +{ + struct kwtab *tp; + + if (argc < 2) + default_exit(); + for (tp = exit_modes; tp->kw; tp++) + if (!strcmp(tp->kw, argv[1])) + break; + if (!tp->func) { + fprintf(stderr, + "error: \"%s\" is not an understood exit mode\n", + argv[1]); + return(-1); + } + tp->func(); +} + +/* called from hwparam.c config file parser */ +void +set_default_exit_mode(arg, filename_for_errs, lineno_for_errs) + char *arg; + char *filename_for_errs; + int lineno_for_errs; +{ + char *cp; + struct kwtab *tp; + + while (isspace(*arg)) + arg++; + if (!*arg) { + fprintf(stderr, + "%s line %d: exit-mode setting requires an argument\n", + filename_for_errs, lineno_for_errs); + exit(1); + } + for (cp = arg; *cp && !isspace(*cp); cp++) + ; + *cp = '\0'; + for (tp = exit_modes; tp->kw; tp++) + if (!strcmp(tp->kw, arg)) + break; + if (!tp->func) { + fprintf(stderr, + "%s line %d: \"%s\" is not an understood exit mode\n", + filename_for_errs, lineno_for_errs, arg); + exit(1); + } + default_exit = tp->func; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/lthelp.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,80 @@ +/* + * This module implements the loadtool help facility. + */ + +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> + +extern char loadtool_help_file[]; + +loadtool_help(topic) + char *topic; +{ + FILE *f; + char linebuf[256]; + char *cp, *np; + int flag; + + f = fopen(loadtool_help_file, "r"); + if (!f) { + perror(loadtool_help_file); + return(-1); + } + for (;;) { + if (!fgets(linebuf, sizeof linebuf, f)) { + fprintf(stderr, "Help topic \"%s\" not found\n", topic); + fclose(f); + return(-1); + } + if (linebuf[0] != '=' || linebuf[1] != '=' || linebuf[2] != '=') + continue; + for (cp = linebuf + 3; isspace(*cp); cp++) + ; + for (np = cp; *cp && !isspace(*cp); cp++) + ; + if (*cp) + *cp++ = '\0'; + if (!strcmp(np, topic)) + break; + } + for (flag = 0; fgets(linebuf, sizeof linebuf, f); ) { + if (linebuf[0] == '=' && linebuf[1] == '=' && + linebuf[2] == '=') { + if (flag) + break; + else + continue; + } + fputs(linebuf, stdout); + flag = 1; + } + fclose(f); + return(0); +} + +cmd_help(argc, argv) + char **argv; +{ + char flashtopic[32]; + + switch (argc) { + case 1: + return loadtool_help("main"); + case 2: + return loadtool_help(argv[1]); + case 3: + if ((!strcmp(argv[1], "flash") || !strcmp(argv[1], "flash2")) + && strlen(argv[2]) <= 20) { + sprintf(flashtopic, "flash:%s", argv[2]); + return loadtool_help(flashtopic); + } + fprintf(stderr, "No such help topic\n"); + return(-1); + default: + fprintf(stderr, "internal error in cmd_help(): bad argc\n"); + abort(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/ltmain.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,98 @@ +/* + * This module contains the main() function for fc-loadtool + */ + +#include <sys/types.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include "srecreader.h" + +extern char *target_ttydev; +extern struct srecreader iramimage; +extern char default_loadagent_image[]; +extern char hw_init_script[]; +extern void (*default_exit)(); +extern int gta_modem_poweron; + +extern struct baudrate *find_baudrate_by_name(); + +static struct baudrate *reattach; + +main(argc, argv) + char **argv; +{ + extern char *optarg; + extern int optind; + int c; + char command[512]; + + while ((c = getopt(argc, argv, "a:b:c:C:h:H:i:nr:")) != EOF) + switch (c) { + case 'a': + iramimage.filename = optarg; + continue; + case 'b': + set_romload_baudrate(optarg); + continue; + case 'c': + set_compalstage_short(optarg); + continue; + case 'C': + set_compalstage_fullpath(optarg); + continue; + case 'h': + read_hwparam_file_shortname(optarg); + continue; + case 'H': + read_hwparam_file_fullpath(optarg); + continue; + case 'i': + set_beacon_interval(optarg); + continue; + case 'n': + gta_modem_poweron = 0; + continue; + case 'r': + reattach = find_baudrate_by_name(optarg); + if (!reattach) + exit(1); /* error msg already printed */ + continue; + case '?': + default: +usage: fprintf(stderr, + "usage: fc-loadtool [options] ttyport\n"); + exit(1); + } + if (argc - optind != 1) + goto usage; + target_ttydev = argv[optind]; + if (!iramimage.filename) + iramimage.filename = default_loadagent_image; + + open_target_serial(); + if (reattach) + switch_baud_rate(reattach); + else { + perform_compal_stage(1); + perform_romload(); + putchar('\n'); + if (tpinterf_pass_output(1) < 0) + exit(1); + putchar('\n'); + if (hw_init_script[0]) { + printf("Executing init script %s\n", hw_init_script); + loadtool_exec_script(hw_init_script); + } + } + for (;;) { + if (isatty(0)) { + fputs("loadtool> ", stdout); + fflush(stdout); + } + if (!fgets(command, sizeof command, stdin)) + default_exit(); + loadtool_dispatch_cmd(command, 0); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/ltmisc.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,37 @@ +/* + * This module is a place to implement little miscellaneous fc-loadtool + * commands which don't belong anywhere else. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdint.h> + +cmd_dieid(argc, argv) + char **argv; +{ + static uint32_t addrs[4] = {0xFFFEF010, 0xFFFEF012, 0xFFFEF014, + 0xFFFEF016}; + uint16_t data[4]; + int i, stat; + FILE *of; + + for (i = 0; i < 4; i++) { + stat = do_r16(addrs[i], data + i); + if (stat) + return(stat); + printf("%08lX: %04X\n", (u_long)addrs[i], (int)data[i]); + } + if (argc < 2) + return(0); + of = fopen(argv[1], "w"); + if (!of) { + perror(argv[1]); + return(-1); + } + for (i = 0; i < 4; i++) + fprintf(of, "%08lX: %04X\n", (u_long)addrs[i], (int)data[i]); + fclose(of); + printf("Saved to %s\n", argv[1]); + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/ltpassthru.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,19 @@ +/* + * This module contains the loadtool_cmd_passthru() function, + * which implements the simplest commands that pass directly + * through to loadagent. + */ + +#include <stdio.h> + +loadtool_cmd_passthru(argc, argv) + char **argv; +{ + if (tpinterf_make_cmd(argv) < 0) { + fprintf(stderr, "error: unable to form target command\n"); + return(-1); + } + if (tpinterf_send_cmd() < 0) + return(-1); + return tpinterf_pass_output(1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/ltscript.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,54 @@ +/* + * This module contains the code that implements the loadtool scripting + * functionality: init-script setting and the exec command. + */ + +#include <sys/param.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> + +extern char default_helpers_dir[]; + +loadtool_exec_script(script_name) + char *script_name; +{ + char pathbuf[MAXPATHLEN], *openfname; + FILE *f; + char linebuf[512], *cp; + int lineno, retval = 0; + + if (index(script_name, '/')) + openfname = script_name; + else { + sprintf(pathbuf, "%s/%s", default_helpers_dir, script_name); + openfname = pathbuf; + } + f = fopen(openfname, "r"); + if (!f) { + perror(openfname); + return(-1); + } + for (lineno = 1; fgets(linebuf, sizeof linebuf, f); lineno++) { + cp = index(linebuf, '\n'); + if (!cp) { + fprintf(stderr, "%s line %d: missing newline\n", + openfname, lineno); + fclose(f); + return(-1); + } + *cp = '\0'; + retval = loadtool_dispatch_cmd(linebuf, 1); + if (retval) + break; + } + fclose(f); + return(retval); +} + +cmd_exec(argc, argv) + char **argv; +{ + return loadtool_exec_script(argv[1]); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/romload.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,319 @@ +/* + * This module implements the communication protocol for pushing our + * IRAM-loadable code to the Calypso ROM bootloader. + */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <sys/errno.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <strings.h> +#include <termios.h> +#include <unistd.h> +#include "baudrate.h" +#include "srecreader.h" + +extern int errno; + +extern char *target_ttydev; +extern int target_fd; +extern struct baudrate baud_rate_table[]; +extern struct baudrate *find_baudrate_by_name(); + +struct srecreader iramimage; +struct baudrate *romload_baud_rate = baud_rate_table; /* 1st entry default */ + +/* global var always defined, but does anything only for GTA0x_AP_BUILD */ +int gta_modem_poweron = 1; + +static int beacon_interval = 13; /* in milliseconds */ + +static u_char beacon_cmd[2] = {'<', 'i'}; + +static u_char param_cmd[11] = {'<', 'p', + 0x00, /* baud rate select code (115200) */ + 0x00, /* DPLL setup: leave it off like on power-up, */ + /* OsmocomBB does the same thing */ + 0x00, 0x04, /* chip select timing (WS) settings */ + /* our setting matches both OsmocomBB */ + /* and what the ROM runs with */ + /* before receiving this command */ + 0x22, /* FFFF:F900 register config, low byte */ + /* OsmocomBB sends 0x00 here, but I've chosen */ + /* 0x22 to match the setting of this register */ + /* used by the boot ROM before this command. */ + 0x00, 0x01, 0xD4, 0xC0 /* UART timeout */ + /* I've chosen the same value as what the */ + /* boot ROM runs with before getting this cmd */ +}; + +static u_char write_cmd[10] = {'<', 'w', 0x01, 0x01, 0x00}; +static u_char cksum_cmd[3] = {'<', 'c'}; +static u_char branch_cmd[6] = {'<', 'b'}; + +#define INTERMEDIATE_TIMEOUT 500 /* ms to wait for responses */ +#define SERIAL_FLUSH_DELAY 200 /* also in ms */ + +/* + * The following function should be called by command line option + * parsers upon encountering the -i option. + */ +set_beacon_interval(arg) + char *arg; +{ + int i; + + i = atoi(arg); + if (i < 2 || i > 500) { + fprintf(stderr, "invalid -i argument specified\n"); + exit(1); + } + beacon_interval = i; +} + +/* + * The following function should be called by command line option + * parsers upon encountering the -b option. + */ +set_romload_baudrate(arg) + char *arg; +{ + struct baudrate *br; + + br = find_baudrate_by_name(arg); + if (!br) + exit(1); /* error msg already printed */ + if (br->bootrom_code < 0) { + fprintf(stderr, + "baud rate of %s is not supported by the Calypso boot ROM\n", + br->name); + exit(1); + } + romload_baud_rate = br; +} + +/* + * The following functions alter some of the parameters sent to the + * boot ROM in the <p command. + */ +set_romload_pll_conf(byte) +{ + param_cmd[3] = byte; +} + +set_romload_rhea_cntl(byte) +{ + param_cmd[6] = byte; +} + +static int +expect_response(timeout) +{ + char buf[2]; + fd_set fds; + struct timeval tv; + int pass, cc; + + for (pass = 0; pass < 2; ) { + FD_ZERO(&fds); + FD_SET(target_fd, &fds); + tv.tv_sec = 0; + tv.tv_usec = timeout * 1000; + cc = select(target_fd+1, &fds, NULL, NULL, &tv); + if (cc < 0) { + if (errno == EINTR) + continue; + perror("select"); + exit(1); + } + if (cc < 1) + return(-1); + cc = read(target_fd, buf + pass, 2 - pass); + if (cc <= 0) { + perror("read after successful select"); + exit(1); + } + if (pass == 0 && buf[0] != '>') + continue; + pass += cc; + } + return(buf[1]); +} + +static +send_beacons() +{ + printf("Sending beacons to %s\n", target_ttydev); +#ifdef GTA0x_AP_BUILD + if (gta_modem_poweron) + fork_gta_modem_poweron(); +#endif + do + write(target_fd, beacon_cmd, sizeof beacon_cmd); + while (expect_response(beacon_interval) != 'i'); + return 0; +} + +static uint32_t +compute_block_cksum() +{ + uint32_t sum; + int i, llen; + + sum = iramimage.datalen + 5; + llen = iramimage.datalen + 4; + for (i = 0; i < llen; i++) + sum += iramimage.record[i+1]; + return sum; +} + +perform_romload() +{ + int resp; + uint16_t image_cksum; + unsigned long rec_count; + static int zero = 0; + + if (open_srec_file(&iramimage) < 0) + exit(1); + ioctl(target_fd, FIONBIO, &zero); + send_beacons(); + printf("Got beacon response, attempting download\n"); + + usleep(SERIAL_FLUSH_DELAY * 1000); + tcflush(target_fd, TCIFLUSH); + param_cmd[2] = romload_baud_rate->bootrom_code; + write(target_fd, param_cmd, sizeof param_cmd); + resp = expect_response(INTERMEDIATE_TIMEOUT); + if (resp != 'p') { + if (resp < 0) + fprintf(stderr, "No response to <p command\n"); + else if (isprint(resp)) + fprintf(stderr, + "Got >%c in response to <p command; expected >p\n", + resp); + else + fprintf(stderr, + "Got > %02X in response to <p command; expected >p\n", + resp); + exit(1); + } + printf("<p command successful, switching to %s baud\n", + romload_baud_rate->name); + switch_baud_rate(romload_baud_rate); + usleep(SERIAL_FLUSH_DELAY * 1000); + tcflush(target_fd, TCIFLUSH); + + image_cksum = 0; + for (rec_count = 0; ; ) { + if (read_s_record(&iramimage) < 0) + exit(1); + switch (iramimage.record_type) { + case '0': + if (iramimage.lineno == 1) + continue; + fprintf(stderr, + "%s: S0 record found in line %d (expected in line 1 only)\n", + iramimage.filename, iramimage.lineno); + exit(1); + case '3': + case '7': + if (s3s7_get_addr_data(&iramimage) < 0) + exit(1); + break; + default: + fprintf(stderr, + "%s line %d: S%c record type not supported\n", + iramimage.filename, iramimage.lineno, + iramimage.record_type); + exit(1); + } + if (iramimage.record_type == '7') + break; + /* must be S3 */ + if (iramimage.datalen < 1) { + fprintf(stderr, + "%s line %d: S3 record has zero data length\n", + iramimage.filename, iramimage.lineno); + exit(1); + } + /* form <w command */ + if (!rec_count) + printf("Sending image payload\n"); + write_cmd[5] = iramimage.datalen; + bcopy(iramimage.record + 1, write_cmd + 6, 4); + write(target_fd, write_cmd, sizeof write_cmd); + write(target_fd, iramimage.record + 5, iramimage.datalen); + /* update our checksum accumulator */ + image_cksum += ~compute_block_cksum() & 0xFF; + /* collect response */ + resp = expect_response(INTERMEDIATE_TIMEOUT); + if (resp != 'w') { + fprintf(stderr, "Block #%lu: ", rec_count); + if (resp < 0) + fprintf(stderr, "No response to <w command\n"); + else if (isprint(resp)) + fprintf(stderr, + "Got >%c in response to <w command; expected >w\n", + resp); + else + fprintf(stderr, + "Got > %02X in response to <w command; expected >w\n", + resp); + exit(1); + } + putchar('.'); + fflush(stdout); + rec_count++; + } + /* got S7 */ + fclose(iramimage.openfile); + if (!rec_count) { + fprintf(stderr, + "%s line %d: S7 without any preceding S3 data records\n", + iramimage.filename, iramimage.lineno); + exit(1); + } + + /* send <c */ + printf("Sending checksum\n"); + cksum_cmd[2] = ~image_cksum & 0xFF; + write(target_fd, cksum_cmd, sizeof cksum_cmd); + resp = expect_response(INTERMEDIATE_TIMEOUT); + if (resp != 'c') { + if (resp < 0) + fprintf(stderr, "No response to <c command\n"); + else if (isprint(resp)) + fprintf(stderr, + "Got >%c in response to <c command; expected >c\n", + resp); + else + fprintf(stderr, + "Got > %02X in response to <c command; expected >c\n", + resp); + exit(1); + } + printf("<c command successful, sending <b\n"); + + bcopy(iramimage.record + 1, branch_cmd + 2, 4); + write(target_fd, branch_cmd, sizeof branch_cmd); + resp = expect_response(INTERMEDIATE_TIMEOUT); + if (resp != 'b') { + if (resp < 0) + fprintf(stderr, "No response to <b command\n"); + else if (isprint(resp)) + fprintf(stderr, + "Got >%c in response to <b command; expected >b\n", + resp); + else + fprintf(stderr, + "Got > %02X in response to <b command; expected >b\n", + resp); + exit(1); + } + printf("<b command successful: downloaded image should now be running!\n"); + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/scripts/c155.config Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,23 @@ +# This configuration is for Motorola C155/156 phones. Use the "generic" +# compal configuration for C11x/123 and C139/140. + +compal-stage thumb + +# Parameters for the Calypso boot ROM; +# will result in the ARM core being clocked at 52 MHz as we want. + +pll-config 4/1 +rhea-cntl 0x00 + +# The remaining settings are carried out via loadagent commands +init-script c155.init + +# Flash: use CFI autodetection, 8 MiB max +# Unlike C139, C155 and C156 phones do have working flash mapping at 0x03000000 +flash cfi-8M 0x03000000 + +# bottom boot flash, sector 0 is only 8 KiB +boot-reflash-hack 0x820000 0x2000 + +# Perform a Iota poweroff when we are done +exit-mode iota-off
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/scripts/c155.init Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,15 @@ +# Set WS=3 for both nCS0 and nCS1, same as the more basic Compal phones + +w16 fffffb00 00A3 +w16 fffffb02 00A3 + +# We need to switch the CS4/ADD22 pin from its default function of CS4 +# to the needed ADD22, to access the 8 MiB of flash. Compal's C155/156 +# in-flash boot code does this setting, but let's do it ourselves too. + +w16 fffef006 0008 + +# We don't mess with the FFFF:FB10 register on C155/156, i.e., we +# leave the "enable boot ROM" setting established by compalstage. +# Unlike C139, C155 and C156 phones do have working flash mapping +# at 0x03000000, so we use that.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/scripts/compal.config Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,36 @@ +# This configuration is intended to be applicable to all of C11x, C123, +# C139 and C140. The "plain" version of compalstage selected below +# should work for all C11x/123; it will also work on C139/140 phones +# that had the simpler boot code flashed into them, as will be used for +# FreeCalypso. When running loadtools with this config on C139/140 +# phones that still have the "official" fw in them, one will need to +# specify -h compal -c 1003 to use the inefficient ~15 KiB version of +# compalstage. + +compal-stage plain + +# Whether we are breaking in through compalstage (as above) or through +# tfc139, the re-enabled Calypso boot ROM is used to load our loadagent +# into IRAM. The boot ROM will autodetect the Calypso input clock as +# 26 MHz (physical reality) when entered through compalstage, or as +# 13 MHz when entered through tfc139 - the latter results from the +# original fw setting bit 7 in the FFFF:FD02 register (VTCXO_DIV2), +# which the boot ROM does not clear. +# +# However, the following configuration will result in the ARM core +# being clocked at 52 MHz in both cases. + +pll-config 4/1 +rhea-cntl 0x00 + +# The remaining settings are carried out via loadagent commands +init-script compal.init + +# Flash: use CFI autodetection, 4 MiB max +# mapped at 0, see compal.init for the explanation +flash cfi-4M 0 + +boot-reflash-hack 0x820000 0x10000 + +# Perform a Iota poweroff when we are done +exit-mode iota-off
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/scripts/compal.init Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,16 @@ +# Set WS=3 for both nCS0 and nCS1. This configuration is used by OsmocomBB +# for all 3 Compal models (E86/88/99), and is also seen in the IDA disassembly +# listing of c115-1.0.46.E firmware contributed by Christophe Devine. + +w16 fffffb00 00A3 +w16 fffffb02 00A3 + +# We need to set the FFFF:FB10 register to map the flash (not the boot ROM) +# to address 0. We need this mapping in order to be able to dump and program +# the entire flash, as for some reason the alternate nCS0 mapping at 0x03000000 +# does not work on Compal phones. (That alternate mapping works fine on +# Openmoko and Pirelli phones, though. Perhaps the different Calypso chip +# version is the culprit, or perhaps this alternate mapping works only if the +# physical nIBOOT pin is low.) + +w16 fffffb10 0300
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/scripts/cs2-4ws-8mb.init Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,11 @@ +# This loadtool init script provides memory interface register setup +# for targets which fit the following criteria: +# +# 3 chip selects are used: nCS0, nCS1 and nCS2 +# 4 wait states are to be used (register setting 00A4) +# 8 MiB memory banks are in use, such that ADD22 needs to be enabled + +w16 fffffb00 00A4 +w16 fffffb02 00A4 +w16 fffffb04 00A4 +w16 fffef006 0008
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/scripts/dsample.config Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,22 @@ +# The following parameters go into the <p command sent to the boot ROM +# The values to be used have been gleaned from the 20020917 fw image + +# CLKTCXO input is 13 MHz on the D-Sample, and with Calypso C05 +# the max allowed PLL'ed clock is 78 MHz for the DSP and 39 MHz for the ARM. +# TI's firmware sets the PLL up to multiply by 6 (giving 78 MHz) with +# divide by 2 for the ARM, but the boot ROM doesn't do the latter when +# the input clock is 13 MHz. Hence we'll program the PLL to multiply +# by 3, putting everything at 39 MHz. + +pll-config 3/1 +rhea-cntl 0x00 # set by 20020917 fw, hence presumed correct + +# The remaining settings are carried out via loadagent commands +init-script cs2-4ws-8mb.init + +# 8 MiB flash, accessible at 0x03000000 without Compal-like problems, +# let's use CFI. +flash cfi-8M 0x03000000 + +# Perform a Iota poweroff when we are done +exit-mode iota-off
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/scripts/fcfam.config Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,22 @@ +# This loadtool target configuration is intended to be applicable to all +# original hardware designs created within the FreeCalypso project, +# starting with FCDEV3B. Specifically, it should fit all targets that +# satisfy the following criteria: +# +# The DBB chip is Calypso C035 +# The RF block is Rita (26 MHz VCXO) +# Spansion S71PL129NC0 used for flash and XRAM, copied from Pirelli DP-L10 +# The 2nd flash chip select is wired to nCS2 + +# The following parameters go into the <p command sent to the boot ROM +pll-config 4/1 # 26 MHz in, PLL&DSP @ 104 MHz, ARM @ 52 MHz +rhea-cntl 0x00 # good for all Calypso platforms + +# The remaining settings are carried out via loadagent commands +init-script cs2-4ws-8mb.init + +# Flash type and chip select base addresses +flash pl129n 0x03000000 0x01800000 + +# Perform a Iota poweroff when we are done +exit-mode iota-off
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/scripts/gta02.config Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,18 @@ +# If one is running fc-loadtool from inside the GTA02 (i.e., from the AP, +# as opposed to an external host connected via the headset jack), the +# following setting will cause the fc-loadtool utility to power the modem off +# fully upon exit. + +exit-mode gta02-cutpwr + +# The following parameters go into the <p command sent to the boot ROM +# same values as in pirelli.config, apparently correct for this modem too + +pll-config 4/1 # 26 MHz in, PLL&DSP @ 104 MHz, ARM @ 52 MHz +rhea-cntl 0x00 # fastest setting, used by OsmocomBB, presumably correct + +# Configure memory timings with loadagent commands +init-script k5a3281.init + +# Flash type and chip select base address (full access mapping) +flash k5a32xx_t 0x03000000
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/scripts/k5a3281.init Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,12 @@ +# The RAM+flash MCP in the GTA02 GSM modem block is SEC K5A3281CTM. +# The closest datasheet that could be found is for K5A3280; +# all current understanding of this IC is based on the latter datasheet. + +# OsmocomBB sets WS=3 for both nCS0 and nCS1. At first I was concerned that +# the setting was wrong for nCS0, but I have now located the responsible +# code in the moko11 binary (see the moko11 notes file in the +# freecalypso-reveng Hg tree) and confirmed that the official firmware +# runs with the same settings. So let's do likewise. + +w16 fffffb00 00A3 +w16 fffffb02 00A3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/scripts/pirelli.config Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,18 @@ +# The following parameters go into the <p command sent to the boot ROM + +pll-config 4/1 # 26 MHz in, PLL&DSP @ 104 MHz, ARM @ 52 MHz +rhea-cntl 0x00 # fastest setting, used by OsmocomBB, presumably correct + +# The remaining settings are carried out via loadagent commands +init-script pirelli.init + +# Flash type and chip select base addresses +flash pl129n 0x03000000 0x02000000 + +# On this phone the current best exit strategy is jump0. +# A Iota power-off, even if we implement one, won't be any different: +# having the serial connection implies a USB connection, that in turn +# implies having VBUS, and thus a Iota power-off will immediately +# result in another power-on for charger-insert. + +exit-mode jump0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/scripts/pirelli.init Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,27 @@ +# This phone has 3 memory chip selects: +# +# nCS0: flash chip select 1 +# nCS1: RAM chip select +# nCS3: flash chip select 2 +# +# All 3 chip select lines go to the same physical IC, a RAM/flash MCP. +# We set WS=4 for all 3 here, copying what OsmocomBB does. The access +# time listed in the datasheet is 70 ns for both RAM and flash, and per +# my math setting WS=3 *might* work, but it could be marginal, so let's +# play it safe for now. + +w16 fffffb00 00A4 +w16 fffffb02 00A4 +w16 fffffb06 00A4 + +# We also need to switch the CS4/ADD22 pin from its default function +# of CS4 to the needed ADD22. + +w16 fffef006 0008 + +# With this phone all Calypso serial access always goes through the +# CP2102 usb2serial IC inside the phone itself, which is programmed +# to support the high non-standard baud rates. So we can safely +# switch to 812500 baud unconditionally. + +baud 812500
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/sercomm.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,87 @@ +/* + * This module handles the establishment of serial communication + * with the target, i.e., the host-side termios stuff. + */ + +#include <sys/types.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <termios.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> +#include "baudrate.h" + +char *target_ttydev; +int target_fd; +struct termios target_termios; + +struct baudrate baud_rate_table[] = { + /* the first listed rate will be our default */ + {"115200", B115200, 0}, + {"57600", B57600, 1}, + {"38400", B38400, 2}, + {"19200", B19200, 4}, + /* non-standard high baud rates "remapped" by CP2102 usb2serial IC */ + {"812500", B921600, -1}, + {"406250", B460800, -1}, + {"203125", B230400, -1}, + /* table search terminator */ + {NULL, B0, -1}, +}; +struct baudrate *current_baud_rate; + +open_target_serial() +{ + target_fd = open(target_ttydev, O_RDWR|O_NONBLOCK); + if (target_fd < 0) { + perror(target_ttydev); + exit(1); + } + target_termios.c_iflag = IGNBRK; + target_termios.c_oflag = 0; + target_termios.c_cflag = CLOCAL|HUPCL|CREAD|CS8; + target_termios.c_lflag = 0; + target_termios.c_cc[VMIN] = 1; + target_termios.c_cc[VTIME] = 0; + /* start at B19200, as that's what we'll need to use initially */ + cfsetispeed(&target_termios, B19200); + cfsetospeed(&target_termios, B19200); + if (tcsetattr(target_fd, TCSAFLUSH, &target_termios) < 0) { + perror("initial tcsetattr on target"); + exit(1); + } + return 0; +} + +struct baudrate * +find_baudrate_by_name(srch_name) + char *srch_name; +{ + struct baudrate *br; + + for (br = baud_rate_table; br->name; br++) + if (!strcmp(br->name, srch_name)) + break; + if (br->name) + return(br); + else { + fprintf(stderr, "error: baud rate \"%s\" not known\n", + srch_name); + return(NULL); + } +} + +switch_baud_rate(br) + struct baudrate *br; +{ + cfsetispeed(&target_termios, br->termios_code); + cfsetospeed(&target_termios, br->termios_code); + if (tcsetattr(target_fd, TCSAFLUSH, &target_termios) < 0) { + perror("tcsetattr to switch baud rate"); + exit(1); + } + current_baud_rate = br; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/sertool.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,65 @@ +/* + * This module contains the main() function for fc-iram, previously + * called fc-sertool: the simplest of the FreeCalypso loading tools, + * which sends the user-specified IRAM SREC image to the boot ROM + * and then switches into serial tty pass-through. + */ + +#include <sys/types.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include "srecreader.h" + +extern char *target_ttydev; +extern struct srecreader iramimage; +extern int gta_modem_poweron; + +main(argc, argv) + char **argv; +{ + extern char *optarg; + extern int optind; + int c; + + while ((c = getopt(argc, argv, "b:c:C:h:H:i:n")) != EOF) + switch (c) { + case 'b': + set_romload_baudrate(optarg); + continue; + case 'c': + set_compalstage_short(optarg); + continue; + case 'C': + set_compalstage_fullpath(optarg); + continue; + case 'h': + read_hwparam_file_shortname(optarg); + continue; + case 'H': + read_hwparam_file_fullpath(optarg); + continue; + case 'i': + set_beacon_interval(optarg); + continue; + case 'n': + gta_modem_poweron = 0; + continue; + case '?': + default: +usage: fprintf(stderr, + "usage: fc-iram [options] ttyport iramimage.srec\n"); + exit(1); + } + if (argc - optind != 2) + goto usage; + target_ttydev = argv[optind]; + iramimage.filename = argv[optind+1]; + + open_target_serial(); + perform_compal_stage(1); + perform_romload(); + tty_passthru(); + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/srecreader.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,106 @@ +/* + * This module contains the functions for reading S-record files. + */ + +#include <sys/types.h> +#include <stdint.h> +#include <stdio.h> +#include <ctype.h> +#include <strings.h> +#include "srecreader.h" + +open_srec_file(sr) + struct srecreader *sr; +{ + sr->openfile = fopen(sr->filename, "r"); + if (!sr->openfile) { + perror(sr->filename); + return(-1); + } + sr->lineno = 0; + return(0); +} + +static +srec2bin(sr, asciiline) + struct srecreader *sr; + char *asciiline; +{ + register int i, l, b; + + l = decode_hex_byte(asciiline + 2); + if (l < 1) { + fprintf(stderr, "%s line %d: S-record length octet is bad\n", + sr->filename, sr->lineno); + return(-1); + } + sr->record[0] = l; + for (i = 1; i <= l; i++) { + b = decode_hex_byte(asciiline + i*2 + 2); + if (b < 0) { + fprintf(stderr, + "%s line %d: S-record hex decode error\n", + sr->filename, sr->lineno); + return(-1); + } + sr->record[i] = b; + } + return(0); +} + +static +srec_cksum(sr) + struct srecreader *sr; +{ + u_char accum; + register int i, len; + + len = sr->record[0] + 1; + accum = 0; + for (i = 0; i < len; i++) + accum += sr->record[i]; + if (accum != 0xFF) { + fprintf(stderr, "%s line %d: bad S-record checksum\n", + sr->filename, sr->lineno); + return(-1); + } + return(0); +} + +read_s_record(sr) + struct srecreader *sr; +{ + char asciiline[1024]; + + if (!fgets(asciiline, sizeof asciiline, sr->openfile)) { + fprintf(stderr, "%s: premature EOF after %d S-records\n", + sr->filename, sr->lineno); + return(-1); + } + sr->lineno++; + if (asciiline[0] != 'S' || !isdigit(asciiline[1])) { + fprintf(stderr, "%s line %d: S-record expected\n", + sr->filename, sr->lineno); + return(-1); + } + sr->record_type = asciiline[1]; + if (srec2bin(sr, asciiline) < 0) + return(-1); + return srec_cksum(sr); +} + +s3s7_get_addr_data(sr) + struct srecreader *sr; +{ + if (sr->record[0] < 5) { + fprintf(stderr, "%s line %d: S%c record is too short\n", + sr->filename, sr->lineno, sr->record_type); + return(-1); + } + sr->datalen = sr->record[0] - 5; + sr->addr = ((uint32_t)sr->record[1] << 24) | + ((uint32_t)sr->record[2] << 16) | + ((uint32_t)sr->record[3] << 8) | + (uint32_t)sr->record[4]; + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/srecreader.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,11 @@ +/* this header file defines the data structures for the SREC reader module */ + +struct srecreader { + char *filename; + FILE *openfile; + int lineno; + u_char record[256]; /* binary */ + char record_type; /* ASCII char */ + u_char datalen; + uint32_t addr; +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/tpinterf.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,178 @@ +/* + * Target program interface - this module provides some primitives + * for communicating programmatically with loadagent and possibly + * other target-utils. This module will be linked by both + * fc-loadtool and fc-chainload. + */ + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/errno.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> + +extern int errno; + +extern int target_fd; + +/* definition matches ../target-utils/libcommon/cmdentry.c */ +#define MAXCMD 527 + +/* + * static buffer between tpinterf_make_cmd and tpinterf_send_cmd + * + * We store the command with an ending \r\n so we can use it for + * matching the received echo as well, hence the sizing of the + * buffer. + */ +static char cmdbuf[MAXCMD+2]; +static int cmdlen; + +static int +arg_chars_valid(arg) + char *arg; +{ + char *cp; + + for (cp = arg; *cp; cp++) + if (*cp < ' ' || *cp > '~') + return(0); + return(1); +} + +/* + * This function takes a command for the target in argv form and + * converts it to a space-separated continuous string which can be + * passed as tty "keyboard" input to the target, enforcing length + * and character validity limits in the process. The output is + * stored in an internal static buffer for subsequent + * tpinterf_send_cmd(). + * + * Return value: 0 if everything OK, or -1 if some constraint is + * violated. + */ +tpinterf_make_cmd(argv) + char **argv; +{ + int arglen; + char **ap, *dp; + + dp = cmdbuf; + cmdlen = 0; + for (ap = argv; *ap; ap++) { + arglen = strlen(*ap); + if (ap != argv) + arglen++; /* separating space */ + if (arglen > MAXCMD - cmdlen) + return(-1); + if (!arg_chars_valid(*ap)) + return(-1); + if (ap != argv) + *dp++ = ' '; + strcpy(dp, *ap); + dp += strlen(*ap); + cmdlen += arglen; + } + *dp++ = '\r'; + *dp = '\n'; + return(0); +} + +/* + * This function sends the previously-constructed command to the target, + * and collects the expected echo. + * + * Return value: 0 if successful, -1 on errors (timeout or wrong response) + */ +tpinterf_send_cmd() +{ + char echobuf[MAXCMD+2]; + fd_set fds; + struct timeval tv; + int rcvd, cc; + + write(target_fd, cmdbuf, cmdlen + 1); + for (rcvd = 0; rcvd < cmdlen + 2; ) { + FD_ZERO(&fds); + FD_SET(target_fd, &fds); + tv.tv_sec = 1; + tv.tv_usec = 0; + cc = select(target_fd+1, &fds, NULL, NULL, &tv); + if (cc < 0) { + if (errno == EINTR) + continue; + perror("select"); + return(-1); + } + if (cc < 1) { + fprintf(stderr, + "error: timeout waiting for command echo\n"); + return(-1); + } + cc = read(target_fd, echobuf + rcvd, cmdlen + 2 - rcvd); + if (cc <= 0) { + perror("read after successful select"); + return(-1); + } + rcvd += cc; + } + if (bcmp(echobuf, cmdbuf, cmdlen + 2)) { + fprintf(stderr, "error: command echo mismatch\n"); + return(-1); + } else + return(0); +} + +/* + * This functions reads the serial output from the target until a + * '=' prompt is received. All intermediate output is passed to + * stdout. + * + * Return value: 0 if '=' prompt received immediately, + * positive if some scribble came before the prompt, -1 on errors + * (timeout, read errors, etc). + */ +tpinterf_pass_output(timeout) +{ + char buf[512], *cp; + fd_set fds; + struct timeval tv; + int cc, newline = 1, totout = 0; + + for (;;) { + FD_ZERO(&fds); + FD_SET(target_fd, &fds); + tv.tv_sec = timeout; + tv.tv_usec = 0; + cc = select(target_fd+1, &fds, NULL, NULL, &tv); + if (cc < 0) { + if (errno == EINTR) + continue; + perror("select"); + return(-1); + } + if (cc < 1) { + fprintf(stderr, + "error: timeout waiting for \'=\' prompt from target\n"); + return(-1); + } + cc = read(target_fd, buf, sizeof buf); + if (cc <= 0) { + perror("read after successful select"); + return(-1); + } + for (cp = buf; cc; cp++) { + cc--; + if (*cp == '=' && newline && !cc) + return(totout); + putchar(*cp); + totout++; + if (*cp == '\n') + newline = 1; + else + newline = 0; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/tpinterf2.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,113 @@ +/* + * This module provides a more advanced target interface function + * than tpinterf.c - programmatic capture of target responses, + * for dumps etc. It will be linked by fc-loadtool, but not fc-chainload. + */ + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/errno.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> + +extern int errno; + +extern int target_fd; + +/* + * This functions reads the serial output from the target until a + * '=' prompt is received. All intermediate output is parsed into + * lines and passed to a callback function. + * + * The callback function is called with a pointer to each received + * line, stored in a buffer ending in NUL, with CRLF stripped. + * The callback function is expected to return an int. If the + * callback return value is negative, this function returns immediately + * with that negative value. If the callback return value is positive + * or zero, it is added to an accumulator. + * + * Termination: this function returns when it has received a '=' at + * the beginning of a line (return value is the callback return + * accumulator, or 0 if no lines came), if the callback returns a + * negative value (that value is returned), or if an error is detected + * within this function (return value -1, and an error message + * printed on stderr). + */ +tpinterf_capture_output(timeout, callback) + int timeout; /* seconds */ + int (*callback)(); +{ + char buf[512], *cp; + char line[1024], *dp = line; + fd_set fds; + struct timeval tv; + int cc, linelen = 0; + int totout = 0, cbret; + + for (;;) { + FD_ZERO(&fds); + FD_SET(target_fd, &fds); + tv.tv_sec = timeout; + tv.tv_usec = 0; + cc = select(target_fd+1, &fds, NULL, NULL, &tv); + if (cc < 0) { + if (errno == EINTR) + continue; + perror("select"); + return(-1); + } + if (cc < 1) { + fprintf(stderr, + "error: timeout waiting for \'=\' prompt from target\n"); + return(-1); + } + cc = read(target_fd, buf, sizeof buf); + if (cc <= 0) { + perror("read after successful select"); + return(-1); + } + for (cp = buf; cc; cp++) { + cc--; + if (*cp == '=' && !linelen && !cc) + return(totout); + if (*cp == '\r') + continue; + if (*cp == '\n') { + *dp = '\0'; + cbret = callback(line); + if (cbret < 0) + return(cbret); + totout += cbret; + dp = line; + linelen = 0; + continue; + } + *dp++ = *cp; + linelen++; + if (linelen >= sizeof line) { + fprintf(stderr, + "error: target response line length exceeds buffer\n"); + return(-1); + } + } + } +} + +/* single line response capture mechanism */ +/* same line buffer size as in tpinterf_capture_output() */ +char target_response_line[1024]; + +static +oneline_catcher(linein) + char *linein; +{ + strcpy(target_response_line, linein); + return(1); +} + +tpinterf_capture_output_oneline(timeout) +{ + return tpinterf_capture_output(timeout, oneline_catcher); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/tpinterf3.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,60 @@ +/* + * The do_r16() and do_w16() functions implemented in this module + * provide programmatic access to the r16 and w16 commands on the target. + * They will be used to implement some flash operations. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> + +extern char target_response_line[]; + +do_r16(addr, retptr) + uint32_t addr; + uint16_t *retptr; +{ + char addr_arg[10], *argv[3]; + int stat; + char *strtoul_endp; + + sprintf(addr_arg, "%lx", (u_long) addr); + argv[0] = "r16"; + argv[1] = addr_arg; + argv[2] = 0; + tpinterf_make_cmd(argv); + if (tpinterf_send_cmd() < 0) + return(-1); + stat = tpinterf_capture_output_oneline(1); + if (stat != 1) { +errout: fprintf(stderr, "error: malformed response to r16 command\n"); + return(-1); + } + if (strlen(target_response_line) != 4) + goto errout; + *retptr = strtoul(target_response_line, &strtoul_endp, 16); + if (strtoul_endp != target_response_line + 4) + goto errout; + return(0); +} + +do_w16(addr, data) + uint32_t addr; + uint16_t data; +{ + char addr_arg[10], data_arg[10], *argv[4]; + + sprintf(addr_arg, "%lx", (u_long) addr); + sprintf(data_arg, "%lx", (u_long) data); + argv[0] = "w16"; + argv[1] = addr_arg; + argv[2] = data_arg; + argv[3] = 0; + tpinterf_make_cmd(argv); + if (tpinterf_send_cmd() < 0) + return(-1); + return tpinterf_pass_output(1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/ttypassthru.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,109 @@ +/* + * This module implements the pass-thru operation mode, in which + * the Unix host tty is cross-connected directly to the target + * running some code we have just loaded. + */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/errno.h> +#include <termios.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <strings.h> + +extern int errno; + +extern int target_fd; + +static struct termios saved_termios, my_termios; + +static void +safe_output(buf, cc) + u_char *buf; +{ + int i, c; + + for (i = 0; i < cc; i++) { + c = buf[i]; + if (c == '\r' || c == '\n' || c == '\t' || c == '\b') { + putchar(c); + continue; + } + if (c & 0x80) { + putchar('M'); + putchar('-'); + c &= 0x7F; + } + if (c < 0x20) { + putchar('^'); + putchar(c + '@'); + } else if (c == 0x7F) { + putchar('^'); + putchar('?'); + } else + putchar(c); + } + fflush(stdout); +} + +static void +loop() +{ + char buf[BUFSIZ]; + fd_set fds, fds1; + register int i, cc, max; + + FD_ZERO(&fds); + FD_SET(0, &fds); + FD_SET(target_fd, &fds); + max = target_fd + 1; + for (;;) { + bcopy(&fds, &fds1, sizeof(fd_set)); + i = select(max, &fds1, NULL, NULL, NULL); + if (i < 0) { + if (errno == EINTR) + continue; + tcsetattr(0, TCSAFLUSH, &saved_termios); + perror("select"); + exit(1); + } + if (FD_ISSET(0, &fds1)) { + cc = read(0, buf, sizeof buf); + if (cc <= 0) + return; + if (cc == 1 && buf[0] == 0x1C) + return; + write(target_fd, buf, cc); + } + if (FD_ISSET(target_fd, &fds1)) { + cc = read(target_fd, buf, sizeof buf); + if (cc <= 0) { + tcsetattr(0, TCSAFLUSH, &saved_termios); + fprintf(stderr, "EOF/error on target tty\n"); + exit(1); + } + safe_output(buf, cc); + } + } +} + +tty_passthru() +{ + static int zero = 0; + + ioctl(target_fd, FIONBIO, &zero); + + tcgetattr(0, &saved_termios); + bcopy(&saved_termios, &my_termios, sizeof(struct termios)); + cfmakeraw(&my_termios); + my_termios.c_cc[VMIN] = 1; + my_termios.c_cc[VTIME] = 0; + tcsetattr(0, TCSAFLUSH, &my_termios); + + printf("Entering tty pass-thru; type ^\\ to exit\r\n\n"); + loop(); + tcsetattr(0, TCSAFLUSH, &saved_termios); + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/miscutil/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,27 @@ +CC= gcc +CFLAGS= -O2 +PROGS= fc-rgbconv fc-serterm imei-luhn +INSTBIN=/usr/local/bin + +all: ${PROGS} + +SERTERM_OBJS= fc-serterm.o openport.o ttypassthru.o + +fc-rgbconv: fc-rgbconv.c + ${CC} ${CFLAGS} -o $@ $@.c + +fc-serterm: ${SERTERM_OBJS} + ${CC} ${CFLAGS} -o $@ ${SERTERM_OBJS} + +ttypassthru.o: ../loadtools/ttypassthru.c + ${CC} ${CFLAGS} -c -o $@ $< + +imei-luhn: imei-luhn.c + ${CC} ${CFLAGS} -o $@ $@.c + +install: + mkdir -p ${INSTBIN} + install -c ${PROGS} ${INSTBIN} + +clean: + rm -f ${PROGS} *.o *errs *.out
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/miscutil/fc-rgbconv.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,77 @@ +/* + * This utility is an aid for phone UI development. The color LCDs in the + * phones targeted by FreeCalypso implement 16-bit color in RGB 5:6:5 format, + * but these 16-bit color words are not particularly intuitive in raw hex form. + * In contrast, a 24-bit RGB 8:8:8 color given in RRGGBB hex form is quite + * intuitive, at least to those who understand RGB. + * + * This utility performs the conversion. It takes a single command line + * argument that must be either 4 or 6 hex digits. If the argument is 4 hex + * digits, it is interpreted as RGB 5:6:5 and converted into RGB 8:8:8. + * If the argument is 6 hex digits, it is interpreted as RGB 8:8:8 and + * converted into RGB 5:6:5. The output of the conversion is emitted on + * stdout as 4 or 6 hex digits. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> + +is_arg_all_hex(str) + char *str; +{ + char *cp; + int c; + + for (cp = str; c = *cp++; ) + if (!isxdigit(c)) + return(0); + return(1); +} + +convert_565_to_888(in) + unsigned in; +{ + unsigned r, g, b; + + r = in >> 11; + g = (in >> 5) & 0x3F; + b = in & 0x1F; + printf("%02X%02X%02X\n", r << 3, g << 2, b << 3); +} + +convert_888_to_565(in) + unsigned in; +{ + unsigned r, g, b; + + r = (in >> 16) >> 3; + g = ((in >> 8) & 0xFF) >> 2; + b = (in & 0xFF) >> 3; + printf("%04X\n", (r << 11) | (g << 5) | b); +} + +main(argc, argv) + char **argv; +{ + unsigned in; + + if (argc != 2) { +usage: fprintf(stderr, + "please specify one 4-digit or 6-digit hex RGB value\n"); + exit(1); + } + if (!is_arg_all_hex(argv[1])) + goto usage; + in = strtoul(argv[1], 0, 16); + switch (strlen(argv[1])) { + case 4: + convert_565_to_888(in); + exit(0); + case 6: + convert_888_to_565(in); + exit(0); + } + goto usage; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/miscutil/fc-serterm.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,24 @@ +/* + * This hack-utility opens a serial port at the user-specified baud rate + * and drops into a terminal pass-thru mode, except that any binary bytes + * received on this port are turned into cat -v form. The intent is for + * sniffing on and/or talking to targets that emit some ASCII mixed in + * with binary. + */ + +#include <stdio.h> +#include <stdlib.h> + +int target_fd; + +main(argc, argv) + char **argv; +{ + if (argc != 3) { + fprintf(stderr, "usage: %s ttyname baudrate\n", argv[0]); + exit(1); + } + open_target_serial(argv[1], argv[2]); + tty_passthru(); + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/miscutil/imei-luhn.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,76 @@ +/* + * This program computes the Luhn check digit for an IMEI number given + * the first 14 digits, or verifies the correctness of this check digit + * given a 15-digit number as input. + * + * The number given on the command line may optionally include punctuation, + * which is skipped and ignored. + */ + +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> + +char digits[15]; + +compute_cd() +{ + int i, dig, sum; + + sum = 0; + for (i = 0; i < 14; i++) { + dig = digits[i]; + if (i & 1) { + dig *= 2; + if (dig > 9) + dig -= 9; + } + sum += dig; + } + dig = sum % 10; + if (dig) + dig = 10 - dig; + return dig; +} + +main(argc, argv) + char **argv; +{ + char *cp; + int i; + + if (argc != 2) { +usage: fprintf(stderr, "usage: %s number\n", argv[0]); + exit(2); + } + cp = argv[1]; + if (!isdigit(*cp)) + goto usage; + for (i = 0; *cp; ) { + if (ispunct(*cp)) + cp++; + if (!isdigit(*cp)) + goto usage; + if (i >= 15) { +wrong_len: fprintf(stderr, + "error: argument must have 14 or 15 digits\n"); + exit(2); + } + digits[i++] = *cp++ - '0'; + } + switch (i) { + case 14: + printf("%d\n", compute_cd()); + exit(0); + case 15: + if (digits[14] == compute_cd()) { + printf("IMEI OK\n"); + exit(0); + } else { + printf("Check digit mismatch!\n"); + exit(1); + } + default: + goto wrong_len; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/miscutil/openport.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,65 @@ +/* + * Serial port opening code for fc-serterm + */ + +#include <sys/types.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <termios.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> + +extern int target_fd; + +static struct baudrate { + char *name; + speed_t termios_code; +} baud_rate_table[] = { + {"19200", B19200}, + {"38400", B38400}, + {"57600", B57600}, + {"115200", B115200}, + /* non-standard high baud rates "remapped" by CP2102 usb2serial IC */ + {"203125", B230400}, + {"406250", B460800}, + {"812500", B921600}, + /* table search terminator */ + {NULL, B0} +}; + +open_target_serial(ttydev, baudname) + char *ttydev, *baudname; +{ + struct termios target_termios; + struct baudrate *br; + + for (br = baud_rate_table; br->name; br++) + if (!strcmp(br->name, baudname)) + break; + if (!br->name) { + fprintf(stderr, "baud rate \"%s\" unknown/unsupported\n", + baudname); + exit(1); + } + target_fd = open(ttydev, O_RDWR|O_NONBLOCK); + if (target_fd < 0) { + perror(ttydev); + exit(1); + } + target_termios.c_iflag = IGNBRK; + target_termios.c_oflag = 0; + target_termios.c_cflag = CLOCAL|HUPCL|CREAD|CS8; + target_termios.c_lflag = 0; + target_termios.c_cc[VMIN] = 1; + target_termios.c_cc[VTIME] = 0; + cfsetispeed(&target_termios, br->termios_code); + cfsetospeed(&target_termios, br->termios_code); + if (tcsetattr(target_fd, TCSAFLUSH, &target_termios) < 0) { + perror("initial tcsetattr on target"); + exit(1); + } + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,21 @@ +PROGDIR=asyncshell ctracedec etmsync lowlevel tmsh +LIBDIR= libasync libg23 +SUBDIR= ${PROGDIR} ${LIBDIR} + +all: ${SUBDIR} + +asyncshell: libasync libg23 +lowlevel: libg23 +tmsh: libasync + +${SUBDIR}: FRC + cd $@; ${MAKE} ${MFLAGS} + +clean: FRC + rm -f a.out core errs + for i in ${SUBDIR}; do (cd $$i; ${MAKE} ${MFLAGS} clean); done + +install: FRC + for i in ${PROGDIR}; do (cd $$i; ${MAKE} ${MFLAGS} install); done + +FRC:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/asyncshell/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,19 @@ +CC= gcc +CFLAGS= -O2 -I../include +PROG= fc-shell +OBJS= at.o gsm0610.o init.o main.o oneshot.o parse.o pktsort.o poweroff.o \ + rxctl.o sendarb.o sendsp.o tchcmd.o tchplay.o tchrec.o usercmd.o +LIBS= ../libasync/libasync.a ../libg23/libg23.a +INSTBIN=/usr/local/bin + +all: ${PROG} + +${PROG}: ${OBJS} ${LIBS} + ${CC} ${CFLAGS} -o $@ ${OBJS} ${LIBS} + +install: ${PROG} + mkdir -p ${INSTBIN} + install -c ${PROG} ${INSTBIN} + +clean: + rm -f *.o *.out *errs ${PROG}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/asyncshell/at.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,45 @@ +/* + * Functions for the AT-over-RVTMUX interface + */ + +#include <sys/types.h> +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "pktmux.h" +#include "limits.h" + +send_string_to_ati(str) + char *str; +{ + unsigned len; + u_char sendpkt[MAX_PKT_TO_TARGET+1]; + + len = strlen(str); + if (len + 1 > MAX_PKT_TO_TARGET) { + printf("error: max pkt to target limit exceeded\n"); + return(1); + } + /* fill out the packet */ + sendpkt[0] = RVT_AT_HEADER; + strcpy(sendpkt + 1, str); + /* send it! */ + send_pkt_to_target(sendpkt, len + 1); + return(0); +} + +void +cmd_sendat(arg) + char *arg; +{ + while (isspace(*arg)) + arg++; + if (!*arg) { + printf("error: missing string argument\n"); + return; + } + ati_rx_control(1); + send_string_to_ati(arg); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/asyncshell/gsm0610.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,336 @@ +/* + * TI's DSP has API words from which GSM 06.10 codec bits that have been + * demodulated from the downlink may be read, FreeCalypso firmware has + * an experimental feature by way of which these bits may be forwarded + * to the external host, and fc-shell provides a mechanism to record + * this downlink speech stream in a file. We would like to record these + * files in the libgsm format which the FLOSS world has adopted as the + * standard, so that they can be played with the SoX play command, + * for example. But the bit order is different between what TI's DSP + * gives us and libgsm, hence we need to reshuffle the bits here. + * + * Adapted from OsmocomBB. + */ + +#include <sys/types.h> +#include <string.h> +#include <strings.h> + +/* GSM FR - subjective importance bit ordering */ + /* This array encodes GSM 05.03 Table 2. + * It's also GSM 06.10 Table A.2.1a + * + * It converts between serial parameter output by the encoder and the + * order needed before channel encoding. + */ +const u_short gsm0610_bitorder[260] = { + 0, /* LARc0:5 */ + 47, /* Xmaxc0:5 */ + 103, /* Xmaxc1:5 */ + 159, /* Xmaxc2:5 */ + 215, /* Xmaxc3:5 */ + 1, /* LARc0:4 */ + 6, /* LARc1:5 */ + 12, /* LARc2:4 */ + 2, /* LARc0:3 */ + 7, /* LARc1:4 */ + 13, /* LARc2:3 */ + 17, /* LARc3:4 */ + 36, /* Nc0:6 */ + 92, /* Nc1:6 */ + 148, /* Nc2:6 */ + 204, /* Nc3:6 */ + 48, /* Xmaxc0:4 */ + 104, /* Xmaxc1:4 */ + 160, /* Xmaxc2:4 */ + 216, /* Xmaxc3:4 */ + 8, /* LARc1:3 */ + 22, /* LARc4:3 */ + 26, /* LARc5:3 */ + 37, /* Nc0:5 */ + 93, /* Nc1:5 */ + 149, /* Nc2:5 */ + 205, /* Nc3:5 */ + 38, /* Nc0:4 */ + 94, /* Nc1:4 */ + 150, /* Nc2:4 */ + 206, /* Nc3:4 */ + 39, /* Nc0:3 */ + 95, /* Nc1:3 */ + 151, /* Nc2:3 */ + 207, /* Nc3:3 */ + 40, /* Nc0:2 */ + 96, /* Nc1:2 */ + 152, /* Nc2:2 */ + 208, /* Nc3:2 */ + 49, /* Xmaxc0:3 */ + 105, /* Xmaxc1:3 */ + 161, /* Xmaxc2:3 */ + 217, /* Xmaxc3:3 */ + 3, /* LARc0:2 */ + 18, /* LARc3:3 */ + 30, /* LARc6:2 */ + 41, /* Nc0:1 */ + 97, /* Nc1:1 */ + 153, /* Nc2:1 */ + 209, /* Nc3:1 */ + 23, /* LARc4:2 */ + 27, /* LARc5:2 */ + 43, /* bc0:1 */ + 99, /* bc1:1 */ + 155, /* bc2:1 */ + 211, /* bc3:1 */ + 42, /* Nc0:0 */ + 98, /* Nc1:0 */ + 154, /* Nc2:0 */ + 210, /* Nc3:0 */ + 45, /* Mc0:1 */ + 101, /* Mc1:1 */ + 157, /* Mc2:1 */ + 213, /* Mc3:1 */ + 4, /* LARc0:1 */ + 9, /* LARc1:2 */ + 14, /* LARc2:2 */ + 33, /* LARc7:2 */ + 19, /* LARc3:2 */ + 24, /* LARc4:1 */ + 31, /* LARc6:1 */ + 44, /* bc0:0 */ + 100, /* bc1:0 */ + 156, /* bc2:0 */ + 212, /* bc3:0 */ + 50, /* Xmaxc0:2 */ + 106, /* Xmaxc1:2 */ + 162, /* Xmaxc2:2 */ + 218, /* Xmaxc3:2 */ + 53, /* xmc0_0:2 */ + 56, /* xmc0_1:2 */ + 59, /* xmc0_2:2 */ + 62, /* xmc0_3:2 */ + 65, /* xmc0_4:2 */ + 68, /* xmc0_5:2 */ + 71, /* xmc0_6:2 */ + 74, /* xmc0_7:2 */ + 77, /* xmc0_8:2 */ + 80, /* xmc0_9:2 */ + 83, /* xmc0_10:2 */ + 86, /* xmc0_11:2 */ + 89, /* xmc0_12:2 */ + 109, /* xmc1_0:2 */ + 112, /* xmc1_1:2 */ + 115, /* xmc1_2:2 */ + 118, /* xmc1_3:2 */ + 121, /* xmc1_4:2 */ + 124, /* xmc1_5:2 */ + 127, /* xmc1_6:2 */ + 130, /* xmc1_7:2 */ + 133, /* xmc1_8:2 */ + 136, /* xmc1_9:2 */ + 139, /* xmc1_10:2 */ + 142, /* xmc1_11:2 */ + 145, /* xmc1_12:2 */ + 165, /* xmc2_0:2 */ + 168, /* xmc2_1:2 */ + 171, /* xmc2_2:2 */ + 174, /* xmc2_3:2 */ + 177, /* xmc2_4:2 */ + 180, /* xmc2_5:2 */ + 183, /* xmc2_6:2 */ + 186, /* xmc2_7:2 */ + 189, /* xmc2_8:2 */ + 192, /* xmc2_9:2 */ + 195, /* xmc2_10:2 */ + 198, /* xmc2_11:2 */ + 201, /* xmc2_12:2 */ + 221, /* xmc3_0:2 */ + 224, /* xmc3_1:2 */ + 227, /* xmc3_2:2 */ + 230, /* xmc3_3:2 */ + 233, /* xmc3_4:2 */ + 236, /* xmc3_5:2 */ + 239, /* xmc3_6:2 */ + 242, /* xmc3_7:2 */ + 245, /* xmc3_8:2 */ + 248, /* xmc3_9:2 */ + 251, /* xmc3_10:2 */ + 254, /* xmc3_11:2 */ + 257, /* xmc3_12:2 */ + 46, /* Mc0:0 */ + 102, /* Mc1:0 */ + 158, /* Mc2:0 */ + 214, /* Mc3:0 */ + 51, /* Xmaxc0:1 */ + 107, /* Xmaxc1:1 */ + 163, /* Xmaxc2:1 */ + 219, /* Xmaxc3:1 */ + 54, /* xmc0_0:1 */ + 57, /* xmc0_1:1 */ + 60, /* xmc0_2:1 */ + 63, /* xmc0_3:1 */ + 66, /* xmc0_4:1 */ + 69, /* xmc0_5:1 */ + 72, /* xmc0_6:1 */ + 75, /* xmc0_7:1 */ + 78, /* xmc0_8:1 */ + 81, /* xmc0_9:1 */ + 84, /* xmc0_10:1 */ + 87, /* xmc0_11:1 */ + 90, /* xmc0_12:1 */ + 110, /* xmc1_0:1 */ + 113, /* xmc1_1:1 */ + 116, /* xmc1_2:1 */ + 119, /* xmc1_3:1 */ + 122, /* xmc1_4:1 */ + 125, /* xmc1_5:1 */ + 128, /* xmc1_6:1 */ + 131, /* xmc1_7:1 */ + 134, /* xmc1_8:1 */ + 137, /* xmc1_9:1 */ + 140, /* xmc1_10:1 */ + 143, /* xmc1_11:1 */ + 146, /* xmc1_12:1 */ + 166, /* xmc2_0:1 */ + 169, /* xmc2_1:1 */ + 172, /* xmc2_2:1 */ + 175, /* xmc2_3:1 */ + 178, /* xmc2_4:1 */ + 181, /* xmc2_5:1 */ + 184, /* xmc2_6:1 */ + 187, /* xmc2_7:1 */ + 190, /* xmc2_8:1 */ + 193, /* xmc2_9:1 */ + 196, /* xmc2_10:1 */ + 199, /* xmc2_11:1 */ + 202, /* xmc2_12:1 */ + 222, /* xmc3_0:1 */ + 225, /* xmc3_1:1 */ + 228, /* xmc3_2:1 */ + 231, /* xmc3_3:1 */ + 234, /* xmc3_4:1 */ + 237, /* xmc3_5:1 */ + 240, /* xmc3_6:1 */ + 243, /* xmc3_7:1 */ + 246, /* xmc3_8:1 */ + 249, /* xmc3_9:1 */ + 252, /* xmc3_10:1 */ + 255, /* xmc3_11:1 */ + 258, /* xmc3_12:1 */ + 5, /* LARc0:0 */ + 10, /* LARc1:1 */ + 15, /* LARc2:1 */ + 28, /* LARc5:1 */ + 32, /* LARc6:0 */ + 34, /* LARc7:1 */ + 35, /* LARc7:0 */ + 16, /* LARc2:0 */ + 20, /* LARc3:1 */ + 21, /* LARc3:0 */ + 25, /* LARc4:0 */ + 52, /* Xmaxc0:0 */ + 108, /* Xmaxc1:0 */ + 164, /* Xmaxc2:0 */ + 220, /* Xmaxc3:0 */ + 55, /* xmc0_0:0 */ + 58, /* xmc0_1:0 */ + 61, /* xmc0_2:0 */ + 64, /* xmc0_3:0 */ + 67, /* xmc0_4:0 */ + 70, /* xmc0_5:0 */ + 73, /* xmc0_6:0 */ + 76, /* xmc0_7:0 */ + 79, /* xmc0_8:0 */ + 82, /* xmc0_9:0 */ + 85, /* xmc0_10:0 */ + 88, /* xmc0_11:0 */ + 91, /* xmc0_12:0 */ + 111, /* xmc1_0:0 */ + 114, /* xmc1_1:0 */ + 117, /* xmc1_2:0 */ + 120, /* xmc1_3:0 */ + 123, /* xmc1_4:0 */ + 126, /* xmc1_5:0 */ + 129, /* xmc1_6:0 */ + 132, /* xmc1_7:0 */ + 135, /* xmc1_8:0 */ + 138, /* xmc1_9:0 */ + 141, /* xmc1_10:0 */ + 144, /* xmc1_11:0 */ + 147, /* xmc1_12:0 */ + 167, /* xmc2_0:0 */ + 170, /* xmc2_1:0 */ + 173, /* xmc2_2:0 */ + 176, /* xmc2_3:0 */ + 179, /* xmc2_4:0 */ + 182, /* xmc2_5:0 */ + 185, /* xmc2_6:0 */ + 188, /* xmc2_7:0 */ + 191, /* xmc2_8:0 */ + 194, /* xmc2_9:0 */ + 197, /* xmc2_10:0 */ + 200, /* xmc2_11:0 */ + 203, /* xmc2_12:0 */ + 223, /* xmc3_0:0 */ + 226, /* xmc3_1:0 */ + 229, /* xmc3_2:0 */ + 232, /* xmc3_3:0 */ + 235, /* xmc3_4:0 */ + 238, /* xmc3_5:0 */ + 241, /* xmc3_6:0 */ + 244, /* xmc3_7:0 */ + 247, /* xmc3_8:0 */ + 250, /* xmc3_9:0 */ + 253, /* xmc3_10:0 */ + 256, /* xmc3_11:0 */ + 259, /* xmc3_12:0 */ + 11, /* LARc1:0 */ + 29, /* LARc5:0 */ +}; + +static int +msb_get_bit(buf, bn) + u_char *buf; +{ + int pos_byte = bn >> 3; + int pos_bit = 7 - (bn & 7); + + return (buf[pos_byte] >> pos_bit) & 1; +} + +static void +msb_set_bit(buf, bn, bit) + u_char *buf; +{ + int pos_byte = bn >> 3; + int pos_bit = 7 - (bn & 7); + + buf[pos_byte] |= (bit << pos_bit); +} + +void +gsm0610_tidsp_to_libgsm(inbytes, outbytes) + u_char *inbytes, *outbytes; +{ + int i, di, si; + + bzero(outbytes, 33); + outbytes[0] = 0xD0; + for (i = 0; i < 260; i++) { + di = gsm0610_bitorder[i]; + si = (i > 181) ? i + 4 : i; + msb_set_bit(outbytes, 4 + di, msb_get_bit(inbytes, si)); + } +} + +void +gsm0610_libgsm_to_tidsp(inbytes, outbytes) + u_char *inbytes, *outbytes; +{ + int i, di, si; + + bzero(outbytes, 33); + for (i = 0; i < 260; i++) { + si = gsm0610_bitorder[i]; + di = (i > 181) ? i + 4 : i; + msb_set_bit(outbytes, di, msb_get_bit(inbytes, 4 + si)); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/asyncshell/init.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,21 @@ +/* + * This module contains the initialization code for fc-shell. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "pktmux.h" +#include "localsock.h" + +init() +{ + static u_char want_rvt_lost[9] = {CLI2RVI_WANT_RVTRACE, + 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00}; + + localsock_prep_for_length_rx(); + send_init_command(want_rvt_lost, 9); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/asyncshell/main.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,96 @@ +/* + * This module contains the main() function for fc-shell. + */ + +#include <sys/types.h> +#include <sys/errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +char *socket_pathname = "/tmp/rvinterf_socket"; +char *rvinterf_ttyport; +int ttyhacks, dflag; + +int sock; + +extern char *rvinterf_Bopt, *rvinterf_lopt, *rvinterf_wopt; + +main(argc, argv) + char **argv; +{ + extern int optind; + extern char *optarg; + int c, sopt = 0; + fd_set fds; + + while ((c = getopt(argc, argv, "B:dl:p:s:w:")) != EOF) + switch (c) { + case 'B': + rvinterf_Bopt = optarg; + continue; + case 'd': + dflag++; + continue; + case 'l': + rvinterf_lopt = optarg; + continue; + case 'p': + rvinterf_ttyport = optarg; + continue; + case 's': + socket_pathname = optarg; + sopt++; + continue; + case 'w': + rvinterf_wopt = optarg; + continue; + case '?': + default: +usage: fprintf(stderr, + "usage: %s [options] [command]\n", argv[0]); + exit(1); + } + if (rvinterf_ttyport) { + if (sopt) { + fprintf(stderr, + "%s error: -p and -s options are mutually exclusive\n", + argv[0]); + exit(1); + } + launch_rvinterf(rvinterf_ttyport); + } else { + if (rvinterf_Bopt || rvinterf_lopt || rvinterf_wopt) { + fprintf(stderr, +"%s error: -B, -l and -w options are meaningful only when launching rvinterf\n", + argv[0]); + exit(1); + } + connect_local_socket(); + } + + if (argv[optind]) + return oneshot_command(argc - optind, argv + optind); + + ttyhacks = isatty(0) && !dflag; + init(); + tty_init(); + for (;;) { + FD_ZERO(&fds); + FD_SET(0, &fds); + FD_SET(sock, &fds); + c = select(sock+1, &fds, 0, 0, 0); + if (c < 0) { + if (errno == EINTR) + continue; + tty_cleanup(); + perror("select"); + exit(1); + } + if (FD_ISSET(0, &fds)) + handle_tty_input(); + if (FD_ISSET(sock, &fds)) + handle_rvinterf_input(); + fflush(stdout); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/asyncshell/oneshot.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,54 @@ +/* + * This module implements the one-shot command mode of fc-shell. + */ + +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "limits.h" + +extern int cmd_poweroff(); +extern int cmd_send_oneshot(); +extern int cmd_sp_oneshot(); +extern int cmd_tchdl_oneshot(); +extern int cmd_tgtreset(); + +static struct cmdtab { + char *cmd; + int minargs; + int maxargs; + int (*func)(); +} cmdtab[] = { + {"poweroff", 0, 0, cmd_poweroff}, + {"send", 1, MAX_PKT_TO_TARGET, cmd_send_oneshot}, + {"sp", 2, 2, cmd_sp_oneshot}, + {"tch-dl", 1, 1, cmd_tchdl_oneshot}, + {"tgtreset", 0, 0, cmd_tgtreset}, + {0, 0, 0, 0} +}; + +oneshot_command(argc, argv) + char **argv; +{ + struct cmdtab *tp; + + for (tp = cmdtab; tp->cmd; tp++) + if (!strcmp(tp->cmd, argv[0])) + break; + if (!tp->func) { + fprintf(stderr, + "error: \"%s\" is not a valid one-shot command\n", + argv[0]); + exit(1); + } + if (argc - 1 > tp->maxargs) { + fprintf(stderr, "%s: too many arguments\n", tp->cmd); + exit(1); + } + if (argc - 1 < tp->minargs) { + fprintf(stderr, "%s: too few arguments\n", tp->cmd); + exit(1); + } + return tp->func(argc, argv); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/asyncshell/parse.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,53 @@ +/* + * This module implements the parser helper function that allows + * the same code to be reused between interactive and one-shot + * versions of the same command. + */ + +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> + +parse_interactive_command_into_argv(argstr, argv, min_arg, max_arg, argcp) + char *argstr, **argv; + int min_arg, max_arg, *argcp; +{ + char *cp, **ap; + + cp = argstr; + for (ap = argv; ; ) { + while (isspace(*cp)) + cp++; + if (!*cp || *cp == '#') + break; + if (ap - argv >= max_arg) { + printf("error: too many arguments\n"); + return(-1); + } + if (*cp == '"') { + *ap++ = ++cp; + while (*cp && *cp != '"') + cp++; + if (*cp != '"') { + printf("error: unterminated quoted string\n"); + return(-1); + } + *cp++ = '\0'; + } else { + *ap++ = cp; + while (*cp && !isspace(*cp)) + cp++; + if (*cp) + *cp++ = '\0'; + } + } + if (ap - argv < min_arg) { + printf("error: too few arguments\n"); + return(-1); + } + *ap = 0; + *argcp = ap - argv; + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/asyncshell/pktsort.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,83 @@ +/* + * Here we sort out incoming packets from the target relayed via rvinterf. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "pktmux.h" +#include "limits.h" +#include "localsock.h" +#include "localtypes.h" + +extern u_char rvi_msg[]; +extern int rvi_msg_len; + +static void +process_rvt() +{ + u32 useid; + + if (rvi_msg_len < 7) { + tty_cleanup(); + fprintf(stderr, "Error: rvinterf sent us an invalid RVT msg\n"); + exit(1); + } + useid = rvi_msg[2] << 24 | rvi_msg[3] << 16 | rvi_msg[4] << 8 + | rvi_msg[5]; + switch (useid) { + case 0: + handle_useid_0(); + return; + default: + tty_cleanup(); + fprintf(stderr, "unexpected fwd of USEID %08X from rvinterf\n", + useid); + exit(1); + } +} + +static void +gpf_packet_rx() +{ + char fmtbuf[MAX_PKT_FROM_TARGET*8]; /* size it generously */ + + format_g23_packet(rvi_msg + 1, rvi_msg_len - 1, fmtbuf); + async_msg_output(fmtbuf); +} + +static void +response_from_ati() +{ + char buf[MAX_PKT_FROM_TARGET*4+2]; + + strcpy(buf, "ATI: "); + safe_print_trace(rvi_msg + 2, rvi_msg_len - 2, buf + 5); + async_msg_output(buf); +} + +void +process_pkt_from_target() +{ + switch (rvi_msg[1]) { + case RVT_RV_HEADER: + process_rvt(); + return; + case RVT_L23_HEADER: + gpf_packet_rx(); + return; + case RVT_AT_HEADER: + response_from_ati(); + return; + case RVT_TCH_HEADER: + tch_packet_rx(); + return; + default: + tty_cleanup(); + fprintf(stderr, "unexpected fwd of MUX %02X from rvinterf\n", + rvi_msg[1]); + exit(1); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/asyncshell/poweroff.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,44 @@ +/* + * fc-shell poweroff and tgtreset commands + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include "pktmux.h" +#include "etm.h" + +send_etm_cmd(buf, len) + u_char *buf; +{ + int i, c; + + buf[0] = RVT_TM_HEADER; + c = 0; + for (i = 1; i <= len; i++) + c ^= buf[i]; + buf[i] = c; + send_pkt_to_target(buf, len + 2); + return 0; +} + +cmd_poweroff() +{ + u_char cmdpkt[7]; + + cmdpkt[1] = ETM_CORE; + cmdpkt[2] = TMCORE_OPC_CODEC_WR; + cmdpkt[3] = 30; /* VRPCDEV */ + cmdpkt[4] = 0x01; /* low 8 bits */ + cmdpkt[5] = 0; /* high 2 bits */ + return send_etm_cmd(cmdpkt, 5); +} + +cmd_tgtreset() +{ + u_char cmdpkt[4]; + + cmdpkt[1] = ETM_CORE; + cmdpkt[2] = TMCORE_OPC_RESET; + return send_etm_cmd(cmdpkt, 2); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/asyncshell/rxctl.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,103 @@ +/* + * This module contains the code for enabling and disabling the receiving + * of various packet types via rvinterf. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "pktmux.h" +#include "localsock.h" + +void +send_rxctl_cmd(channel, enable) +{ + u_char cmdbuf[2]; + + cmdbuf[0] = enable ? CLI2RVI_WANT_MUXPROTO : CLI2RVI_DROP_MUXPROTO; + cmdbuf[1] = channel; + send_init_command(cmdbuf, 2); +} + +void +ati_rx_control(newstate) +{ + static int state = 0; + + if (state == newstate) + return; + send_rxctl_cmd(RVT_AT_HEADER, newstate); + state = newstate; +} + +void +gpf_rx_control(newstate) +{ + static int state = 0; + + if (state == newstate) + return; + send_rxctl_cmd(RVT_L23_HEADER, newstate); + state = newstate; +} + +void +tch_rx_control(newstate) +{ + static int state = 0; + + if (state == newstate) + return; + send_rxctl_cmd(RVT_TCH_HEADER, newstate); + state = newstate; +} + +void +rxctl_user_cmd(args, enable) + char *args; +{ + char *cp, *np; + int gotsome = 0; + + for (cp = args; ; ) { + while (isspace(*cp)) + cp++; + if (!*cp) { + if (!gotsome) + printf("error: argument required\n"); + return; + } + for (np = cp; *cp && !isspace(*cp); cp++) + ; + if (*cp) + *cp++ = '\0'; + if (!strcmp(np, "ati")) + ati_rx_control(enable); + else if (!strcmp(np, "gpf")) + gpf_rx_control(enable); + else if (!strcmp(np, "tch")) + tch_rx_control(enable); + else { + printf("error: unknown channel \"%s\"\n", np); + return; + } + gotsome++; + } +} + +void +cmd_enable(args) + char *args; +{ + rxctl_user_cmd(args, 1); +} + +void +cmd_disable(args) + char *args; +{ + rxctl_user_cmd(args, 0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/asyncshell/sendarb.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,51 @@ +/* + * Command for sending arbitrary packets to the target + */ + +#include <sys/types.h> +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "limits.h" + +cmd_send_common(argc, argv) + char **argv; +{ + u_char sendpkt[MAX_PKT_TO_TARGET]; + unsigned pktlen = argc, i; + char *endp; + + for (i = 0; i < pktlen; i++) { + sendpkt[i] = strtoul(argv[i], &endp, 16); + if (*endp) { + printf( + "error: all arguments to send command must be hex bytes\n"); + return(1); + } + } + /* send it! */ + send_pkt_to_target(sendpkt, pktlen); + return(0); +} + +void +cmd_send_interactive(argstr) + char *argstr; +{ + char *argv[MAX_PKT_TO_TARGET+1]; + int argc, rc; + + rc = parse_interactive_command_into_argv(argstr, argv, 1, + MAX_PKT_TO_TARGET, &argc); + if (rc < 0) + return; + cmd_send_common(argc, argv); +} + +cmd_send_oneshot(argc, argv) + char **argv; +{ + return cmd_send_common(argc - 1, argv + 1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/asyncshell/sendsp.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,82 @@ +/* + * Functions for sending GPF system primitives to the target + */ + +#include <sys/types.h> +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "pktmux.h" +#include "limits.h" + +send_gpf_sysprim(stackdest, primstr) + char *stackdest, *primstr; +{ + unsigned intlen; + u_char sendpkt[MAX_PKT_TO_TARGET+1]; + unsigned pktlen; + + if (strlen(stackdest) > 4) { + printf( + "error: stack destination arg may not exceed 4 characters\n"); + return(1); + } + intlen = 12 + strlen(primstr); + pktlen = intlen + 4; + if (pktlen > MAX_PKT_TO_TARGET) { + printf("error: max pkt to target limit exceeded\n"); + return(1); + } + /* fill out the packet */ + sendpkt[0] = RVT_L23_HEADER; + sendpkt[1] = 0xB7; /* system prim */ + sendpkt[2] = intlen; + sendpkt[3] = intlen >> 8; + /* send zeros for the timestamp */ + sendpkt[4] = 0; + sendpkt[5] = 0; + sendpkt[6] = 0; + sendpkt[7] = 0; + /* as far as TI's sw is concerned, we are PCO */ + sendpkt[8] = 'P'; + sendpkt[9] = 'C'; + sendpkt[10] = 'O'; + sendpkt[11] = ' '; + sprintf(sendpkt + 12, "%-4s%s", stackdest, primstr); + /* send it! */ + send_pkt_to_target(sendpkt, pktlen); + return(0); +} + +void +cmd_sp_interactive(args) + char *args; +{ + char *cp, *np; + + for (cp = args; isspace(*cp); cp++) + ; + if (!*cp) { +err: printf("error: two arguments required\n"); + return; + } + for (np = cp; *cp && !isspace(*cp); cp++) + ; + if (!*cp) + goto err; + *cp++ = '\0'; + while (isspace(*cp)) + cp++; + if (!*cp) + goto err; + gpf_rx_control(1); + send_gpf_sysprim(np, cp); +} + +cmd_sp_oneshot(argc, argv) + char **argv; +{ + return send_gpf_sysprim(argv[1], argv[2]); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/asyncshell/tchcmd.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,185 @@ +/* + * Commands for manipulating the experimental TCH rerouting feature + * of FreeCalypso GSM firmware + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "pktmux.h" +#include "limits.h" +#include "tch_feature.h" + +extern u_char rvi_msg[]; +extern int rvi_msg_len; + +static int tch_rawdump_mode; + +send_tch_config_req(config) +{ + u_char sendpkt[3]; + + sendpkt[0] = RVT_TCH_HEADER; + sendpkt[1] = TCH_CONFIG_REQ; + sendpkt[2] = config; + /* send it! */ + send_pkt_to_target(sendpkt, 3); + return(0); +} + +cmd_tchdl_common(argc, argv) + char **argv; +{ + int config; + + if (!strcmp(argv[0], "enable") || !strcmp(argv[0], "on") || + !strcmp(argv[0], "1")) + config = 1; + else if (!strcmp(argv[0], "disable") || !strcmp(argv[0], "off") || + !strcmp(argv[0], "0")) + config = 0; + else { + printf("error: boolean argument required\n"); + return(1); + } + return send_tch_config_req(config); +} + +void +cmd_tchdl_interactive(argstr) + char *argstr; +{ + char *argv[2]; + int argc, rc; + + rc = parse_interactive_command_into_argv(argstr, argv, 1, 1, &argc); + if (rc < 0) + return; + tch_rx_control(1); + cmd_tchdl_common(argc, argv); +} + +cmd_tchdl_oneshot(argc, argv) + char **argv; +{ + return cmd_tchdl_common(argc - 1, argv + 1); +} + +static void +tch_rawdump() +{ + char buf[MAX_PKT_FROM_TARGET*3+5], *dp; + u_char *cp, *endp; + + cp = rvi_msg + 2; + endp = rvi_msg + rvi_msg_len; + strcpy(buf, "TCH:"); + dp = buf + 4; + while (cp < endp) { + sprintf(dp, " %02X", *cp++); + dp += 3; + } + *dp = '\0'; + async_msg_output(buf); +} + +void +tch_packet_rx() +{ + char buf[128]; + + if (tch_rawdump_mode) { + tch_rawdump(); + return; + } + if (rvi_msg_len < 3) { +inv: async_msg_output("Error: invalid TCH packet received"); + return; + } + switch (rvi_msg[2]) { + case TCH_CONFIG_CONF: + if (rvi_msg_len != 4) + goto inv; + if (rvi_msg[3] & 0xFE) + goto inv; + sprintf(buf, "TCH_CONFIG_CONF: DL forwarding is %s", + rvi_msg[3] ? "enabled" : "disabled"); + async_msg_output(buf); + return; + case TCH_ULBITS_CONF: + if (rvi_msg_len != 3) + goto inv; + tch_ulbits_conf(); + return; + case TCH_DLBITS_IND: + if (rvi_msg_len != 43) + goto inv; + tch_dlbits_handler(); + return; + default: + goto inv; + } +} + +static void +cmd_tch_dumpraw(argc, argv) + char **argv; +{ + if (argc < 2) { + printf("error: too few arguments\n"); + return; + } + if (!strcmp(argv[1], "enable") || !strcmp(argv[1], "on") || + !strcmp(argv[1], "1")) + tch_rawdump_mode = 1; + else if (!strcmp(argv[1], "disable") || !strcmp(argv[1], "off") || + !strcmp(argv[1], "0")) + tch_rawdump_mode = 0; + else + printf("error: boolean argument required\n"); +} + +static void +cmd_tch_status(argc, argv) + char **argv; +{ + if (argc > 1) { + printf("error: too many arguments\n"); + return; + } + show_tch_record_status(); + show_tch_play_status(); + printf("TCH raw dump mode is %s\n", + tch_rawdump_mode ? "enabled" : "disabled"); +} + +void +cmd_tch_dispatch(argstr) + char *argstr; +{ + char *argv[3]; + int argc, rc; + + rc = parse_interactive_command_into_argv(argstr, argv, 1, 2, &argc); + if (rc < 0) + return; + if (!strcmp(argv[0], "dump-raw")) { + cmd_tch_dumpraw(argc, argv); + return; + } + if (!strcmp(argv[0], "play")) { + cmd_tch_play(argc, argv); + return; + } + if (!strcmp(argv[0], "record")) { + cmd_tch_record(argc, argv); + return; + } + if (!strcmp(argv[0], "status")) { + cmd_tch_status(argc, argv); + return; + } + printf("error: invalid tch subcommand\n"); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/asyncshell/tchplay.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,118 @@ +/* + * TCH uplink play-from-file functionality + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "pktmux.h" +#include "tch_feature.h" + +extern u_char rvi_msg[]; +extern int rvi_msg_len; + +extern void async_msg_output(); + +static FILE *gsm_data_file; +static int queued_frames; + +#define QUEUE_LIMIT 3 + +static void +sync_msgout(msg) + char *msg; +{ + printf("%s\n", msg); +} + +static void +fill_uplink(msgout) + void (*msgout)(); +{ + u_char readbytes[33], sendpkt[35]; + int cc; + + sendpkt[0] = RVT_TCH_HEADER; + sendpkt[1] = TCH_ULBITS_REQ; + while (queued_frames < QUEUE_LIMIT) { + cc = fread(readbytes, 1, 33, gsm_data_file); + if (cc < 33) { + if (cc) + msgout("TCH UL: extra bytes at the end of the file"); + msgout("TCH UL: file play finished"); + gsm_data_file = 0; + return; + } + if ((readbytes[0] & 0xF0) != 0xD0) { + msgout("TCH UL: bad file input, play aborted"); + gsm_data_file = 0; + return; + } + gsm0610_libgsm_to_tidsp(readbytes, sendpkt + 2); + send_pkt_to_target(sendpkt, 35); + queued_frames++; + } +} + +void +tch_ulbits_conf() +{ + if (queued_frames > 0) + queued_frames--; + if (gsm_data_file) + fill_uplink(async_msg_output); +} + +static void +cmd_tch_play_start(filename) + char *filename; +{ + if (gsm_data_file) { + printf("error: tch play session already in progress\n"); + return; + } + gsm_data_file = fopen(filename, "r"); + if (!gsm_data_file) { + perror(filename); + return; + } + printf("Starting TCH UL play from file\n"); + tch_rx_control(1); + fill_uplink(sync_msgout); +} + +static void +cmd_tch_play_stop() +{ + if (!gsm_data_file) { + printf("error: no tch play session in progress\n"); + return; + } + fclose(gsm_data_file); + gsm_data_file = 0; + printf("TCH UL play from file terminated\n"); +} + +void +cmd_tch_play(argc, argv) + char **argv; +{ + if (argc < 2) { + printf("error: too few arguments\n"); + return; + } + if (strcmp(argv[1], "stop")) + cmd_tch_play_start(argv[1]); + else + cmd_tch_play_stop(); +} + +void +show_tch_play_status() +{ + printf("TCH UL play from file: %s\n", + gsm_data_file ? "RUNNING" : "not running"); + printf("Outstanding UL frames: %d\n", queued_frames); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/asyncshell/tchrec.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,83 @@ +/* + * TCH downlink recording functionality + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "pktmux.h" +#include "tch_feature.h" + +extern u_char rvi_msg[]; +extern int rvi_msg_len; + +static FILE *gsm_data_file; +static u_long frame_count; + +void +tch_dlbits_handler() +{ + u_char writebytes[33]; + + if (!gsm_data_file) + return; + gsm0610_tidsp_to_libgsm(rvi_msg + 9, writebytes); + fwrite(writebytes, 1, 33, gsm_data_file); + frame_count++; +} + +static void +cmd_tch_record_start(filename) + char *filename; +{ + if (gsm_data_file) { + printf("error: tch record session already in progress\n"); + return; + } + gsm_data_file = fopen(filename, "w"); + if (!gsm_data_file) { + perror(filename); + return; + } + printf("Starting TCH DL recording\n"); + tch_rx_control(1); + send_tch_config_req(1); + frame_count = 0; +} + +static void +cmd_tch_record_stop() +{ + if (!gsm_data_file) { + printf("error: no tch record session in progress\n"); + return; + } + fclose(gsm_data_file); + gsm_data_file = 0; + printf("TCH DL recording stopped, captured %lu speech frames\n", + frame_count); + send_tch_config_req(0); +} + +void +cmd_tch_record(argc, argv) + char **argv; +{ + if (argc < 2) { + printf("error: too few arguments\n"); + return; + } + if (strcmp(argv[1], "stop")) + cmd_tch_record_start(argv[1]); + else + cmd_tch_record_stop(); +} + +void +show_tch_record_status() +{ + printf("TCH DL recording: %s\n", + gsm_data_file ? "RUNNING" : "not running"); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/asyncshell/usercmd.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,74 @@ +/* + * This module implements interactive fc-shell command dispatch. + */ + +#include <sys/types.h> +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> + +extern char usercmd[]; + +extern void cmd_disable(); +extern void cmd_enable(); +extern void cmd_poweroff(); +extern void cmd_sendat(); +extern void cmd_send_interactive(); +extern void cmd_sp_interactive(); +extern void cmd_tch_dispatch(); +extern void cmd_tchdl_interactive(); +extern void cmd_tgtreset(); + +void +cmd_exit() +{ + tty_cleanup(); + exit(0); +} + +static struct cmdtab { + char *cmd; + void (*func)(); +} cmdtab[] = { + {"disable", cmd_disable}, + {"enable", cmd_enable}, + {"exit", cmd_exit}, + {"poweroff", cmd_poweroff}, + {"quit", cmd_exit}, + {"send", cmd_send_interactive}, + {"sp", cmd_sp_interactive}, + {"str", cmd_sendat}, + {"tch", cmd_tch_dispatch}, + {"tch-dl", cmd_tchdl_interactive}, + {"tgtreset", cmd_tgtreset}, + {0, 0} +}; + +void +dispatch_user_cmd() +{ + char *cp, *np; + struct cmdtab *tp; + + for (cp = usercmd; isspace(*cp); cp++) + ; + if (!*cp || *cp == '#') + return; + if (!strncmp(cp, "AT", 2) || !strncmp(cp, "at", 2)) { + cmd_sendat(cp); + return; + } + for (np = cp; *cp && !isspace(*cp); cp++) + ; + if (*cp) + *cp++ = '\0'; + for (tp = cmdtab; tp->cmd; tp++) + if (!strcmp(tp->cmd, np)) + break; + if (tp->func) + tp->func(cp); + else + printf("error: no such command\n"); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/ctracedec/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,17 @@ +CC= gcc +CFLAGS= -O2 +PROG= ctracedec +OBJS= decode.o doprnt.o main.o processlog.o readtab.o +INSTBIN=/usr/local/bin + +all: ${PROG} + +${PROG}: ${OBJS} + ${CC} ${CFLAGS} -o $@ ${OBJS} + +install: ${PROG} + mkdir -p ${INSTBIN} + install -c ${PROG} ${INSTBIN} + +clean: + rm -f *.o *.out *errs ${PROG}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/ctracedec/decode.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,150 @@ +/* + * This module implements the actual decoding of compressed traces. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> + +extern char *str2ind_tab_filename; +extern int str2ind_array_size; +extern char **str2ind_orig_strings; +extern char **str2ind_param_strings; + +#define MAX_PRINTF_PARAMS 16 + +static int cindex, cindex_nchars; +static u_char param_bytes_array[256]; +static int param_bytes_count; +static char *format_string, *param_type_string; +static int num_printf_params; +static u_long printf_params[MAX_PRINTF_PARAMS]; +static char output_buf[2048]; + +decode_hex_digit(c) +{ + if (isdigit(c)) + return(c - '0'); + else if (isupper(c)) + return(c - 'A' + 10); + else + return(c - 'a' + 10); +} + +static int +decode_idx_and_params(line) + char *line; +{ + char *cp; + u_char *dp; + + for (cp = line; isdigit(*cp); cp++) + ; + if (*cp && *cp != ' ') + return(-1); + cindex = atoi(line); + cindex_nchars = cp - line; + for (dp = param_bytes_array; *cp; ) { + if (*cp++ != ' ') + return(-1); + if (!isxdigit(cp[0]) || !isxdigit(cp[1])) + return(-1); + *dp++ = decode_hex_digit(cp[0]) << 4 | decode_hex_digit(cp[1]); + cp += 2; + } + param_bytes_count = dp - param_bytes_array; + return(0); +} + +static void +decode_parameters(filename_for_errs, lineno_for_errs) + char *filename_for_errs; +{ + int pi, type; + u_char *bp, *endp; + + bp = param_bytes_array; + endp = bp + param_bytes_count; + for (pi = 0; pi < num_printf_params; pi++) { + type = param_type_string[pi]; + switch (type) { + case 'c': + if (bp >= endp) { +wrong_param_byte_count: fprintf(stderr, + "%s line %d: wrong number of parameter bytes for %s entry #%d\n", + filename_for_errs, lineno_for_errs, + str2ind_tab_filename, cindex); + exit(1); + } + printf_params[pi] = *bp++; + continue; + case 'i': + case 'p': + case '*': + if (bp > endp - 4) + goto wrong_param_byte_count; + printf_params[pi] = (u_long) bp[0] | + (u_long) bp[1] << 8 | + (u_long) bp[2] << 16 | + (u_long) bp[3] << 24; + bp += 4; + continue; + case 's': + printf_params[pi] = (u_long) bp; + for (;;) { + if (bp >= endp) { + fprintf(stderr, + "%s line %d: unterminated string parameter in compressed trace\n", + filename_for_errs, + lineno_for_errs); + exit(1); + } + if (!*bp++) + break; + } + continue; + default: + fprintf(stderr, + "%s entry #%d: parameter type \'%c\' not supported\n", + str2ind_tab_filename, cindex, type); + exit(1); + } + } + if (bp != endp) + goto wrong_param_byte_count; +} + +process_ctrace_line(line, cindex_offset, filename_for_errs, lineno_for_errs) + char *line, *filename_for_errs; +{ + if (decode_idx_and_params(line + cindex_offset) < 0) { + fprintf(stderr, + "%s line %d: unable to decode compressed trace line\n", + filename_for_errs, lineno_for_errs); + exit(1); + } + if (cindex >= str2ind_array_size) { + fprintf(stderr, + "%s line %d: index %d exceeds the range of %s\n", + filename_for_errs, lineno_for_errs, cindex, + str2ind_tab_filename); + exit(1); + } + format_string = str2ind_orig_strings[cindex]; + param_type_string = str2ind_param_strings[cindex]; + num_printf_params = strlen(param_type_string); + if (num_printf_params > MAX_PRINTF_PARAMS) { + fprintf(stderr, + "error: entry #%d in %s has too many parameters\n", + cindex, str2ind_tab_filename); + exit(1); + } + decode_parameters(filename_for_errs, lineno_for_errs); + ind2str_doprnt(format_string, printf_params, output_buf); + printf("%.*s \"%s\"\n", cindex_offset + cindex_nchars, line, + output_buf); + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/ctracedec/doprnt.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,322 @@ +/* + * We need our own implementation of an sprintf-like function in order + * to expand compressed traces with format strings from str2ind.tab + * and parameters decoded from the serial byte stream. This module is + * a hacked-up version of the guts of the printf family of functions + * from 4.3BSD-Tahoe. + */ + +#include <sys/types.h> +#include <ctype.h> +#include <string.h> +#include <strings.h> + +static void +safe_out_char(c, pp) + int c; + char **pp; +{ + char *dp; + + c &= 0xFF; + dp = *pp; + if (c & 0x80) { + *dp++ = 'M'; + *dp++ = '-'; + c &= 0x7F; + } + if (c < 0x20) { + *dp++ = '^'; + *dp++ = c + '@'; + } else if (c == 0x7F) { + *dp++ = '^'; + *dp++ = '?'; + } else + *dp++ = c; + *pp = dp; +} + +#define PUTC(ch) safe_out_char((ch), &outp) + +#define ARG() \ + _ulong = *argp++; + +#define BUF 12 + +#define todigit(c) ((c) - '0') +#define tochar(n) ((n) + '0') + +#define LONGINT 0x01 /* long integer */ +#define LONGDBL 0x02 /* long double; unimplemented */ +#define SHORTINT 0x04 /* short integer */ +#define ALT 0x08 /* alternate form */ +#define LADJUST 0x10 /* left adjustment */ +#define ZEROPAD 0x20 /* zero (as opposed to blank) pad */ +#define HEXPREFIX 0x40 /* add 0x or 0X prefix */ + +ind2str_doprnt(fmt0, argp, outp) + u_char *fmt0, *outp; + u_long *argp; +{ + register u_char *fmt; /* format string */ + register int ch; /* character from fmt */ + register int cnt; /* return value accumulator */ + register int n; /* random handy integer */ + register char *t; /* buffer pointer */ + u_long _ulong; /* integer arguments %[diouxX] */ + int base; /* base for [diouxX] conversion */ + int dprec; /* decimal precision in [diouxX] */ + int fieldsz; /* field size expanded by sign, etc */ + int flags; /* flags as above */ + int prec; /* precision from format (%.3d), or -1 */ + int realsz; /* field size expanded by decimal precision */ + int size; /* size of converted field or string */ + int width; /* width from format (%8d), or 0 */ + char sign; /* sign prefix (' ', '+', '-', or \0) */ + char softsign; /* temporary negative sign for floats */ + char *digs; /* digits for [diouxX] conversion */ + char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ + + fmt = fmt0; + digs = "0123456789abcdef"; + for (cnt = 0;; ++fmt) { + for (; (ch = *fmt) && ch != '%'; ++cnt, ++fmt) + PUTC(ch); + if (!ch) { + *outp = '\0'; + return (cnt); + } + + flags = 0; dprec = 0; width = 0; + prec = -1; + sign = '\0'; + +rflag: switch (*++fmt) { + case ' ': + /* + * ``If the space and + flags both appear, the space + * flag will be ignored.'' + * -- ANSI X3J11 + */ + if (!sign) + sign = ' '; + goto rflag; + case '#': + flags |= ALT; + goto rflag; + case '*': + /* + * ``A negative field width argument is taken as a + * - flag followed by a positive field width.'' + * -- ANSI X3J11 + * They don't exclude field widths read from args. + */ + if ((width = *argp++) >= 0) + goto rflag; + width = -width; + /* FALLTHROUGH */ + case '-': + flags |= LADJUST; + goto rflag; + case '+': + sign = '+'; + goto rflag; + case '.': + if (*++fmt == '*') + n = *argp++; + else { + n = 0; + while (isascii(*fmt) && isdigit(*fmt)) + n = 10 * n + todigit(*fmt++); + --fmt; + } + prec = n < 0 ? -1 : n; + goto rflag; + case '0': + /* + * ``Note that 0 is taken as a flag, not as the + * beginning of a field width.'' + * -- ANSI X3J11 + */ + flags |= ZEROPAD; + goto rflag; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + n = 0; + do { + n = 10 * n + todigit(*fmt); + } while (isascii(*++fmt) && isdigit(*fmt)); + width = n; + --fmt; + goto rflag; + case 'L': + flags |= LONGDBL; + goto rflag; + case 'h': + flags |= SHORTINT; + goto rflag; + case 'l': + flags |= LONGINT; + goto rflag; + case 'c': + *(t = buf) = *argp++; + size = 1; + sign = '\0'; + goto pforw; + case 'D': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'd': + case 'i': + ARG(); + if ((long)_ulong < 0) { + _ulong = -_ulong; + sign = '-'; + } + base = 10; + goto number; + case 'O': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'o': + ARG(); + base = 8; + goto nosign; + case 'p': + /* + * ``The argument shall be a pointer to void. The + * value of the pointer is converted to a sequence + * of printable characters, in an implementation- + * defined manner.'' + * -- ANSI X3J11 + */ + /* NOSTRICT */ + _ulong = *argp++; + base = 16; + goto nosign; + case 's': + if (!(t = (char *)*argp++)) + t = "(null)"; + if (prec >= 0) { + /* + * can't use strlen; can only look for the + * NUL in the first `prec' characters, and + * strlen() will go further. + */ + char *p; + + for (p = t, size = 0; size < prec; p++, size++) + if (*p == '\0') + break; + } else + size = strlen(t); + sign = '\0'; + goto pforw; + case 'U': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'u': + ARG(); + base = 10; + goto nosign; + case 'X': + digs = "0123456789ABCDEF"; + /* FALLTHROUGH */ + case 'x': + ARG(); + base = 16; + /* leading 0x/X only if non-zero */ + if (flags & ALT && _ulong != 0) + flags |= HEXPREFIX; + + /* unsigned conversions */ +nosign: sign = '\0'; + /* + * ``... diouXx conversions ... if a precision is + * specified, the 0 flag will be ignored.'' + * -- ANSI X3J11 + */ +number: if ((dprec = prec) >= 0) + flags &= ~ZEROPAD; + + /* + * ``The result of converting a zero value with an + * explicit precision of zero is no characters.'' + * -- ANSI X3J11 + */ + t = buf + BUF; + if (_ulong != 0 || prec != 0) { + do { + *--t = digs[_ulong % base]; + _ulong /= base; + } while (_ulong); + digs = "0123456789abcdef"; + if (flags & ALT && base == 8 && *t != '0') + *--t = '0'; /* octal leading 0 */ + } + size = buf + BUF - t; + +pforw: + /* + * All reasonable formats wind up here. At this point, + * `t' points to a string which (if not flags&LADJUST) + * should be padded out to `width' places. If + * flags&ZEROPAD, it should first be prefixed by any + * sign or other prefix; otherwise, it should be blank + * padded before the prefix is emitted. After any + * left-hand padding and prefixing, emit zeroes + * required by a decimal [diouxX] precision, then print + * the string proper, then emit zeroes required by any + * leftover floating precision; finally, if LADJUST, + * pad with blanks. + */ + + /* + * compute actual size, so we know how much to pad + * fieldsz excludes decimal prec; realsz includes it + */ + fieldsz = size; + if (sign) + fieldsz++; + if (flags & HEXPREFIX) + fieldsz += 2; + realsz = dprec > fieldsz ? dprec : fieldsz; + + /* right-adjusting blank padding */ + if ((flags & (LADJUST|ZEROPAD)) == 0 && width) + for (n = realsz; n < width; n++) + PUTC(' '); + /* prefix */ + if (sign) + PUTC(sign); + if (flags & HEXPREFIX) { + PUTC('0'); + PUTC((char)*fmt); + } + /* right-adjusting zero padding */ + if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) + for (n = realsz; n < width; n++) + PUTC('0'); + /* leading zeroes from decimal precision */ + for (n = fieldsz; n < dprec; n++) + PUTC('0'); + + for (n = size; --n >= 0; ) + PUTC(*t++); + /* left-adjusting padding (always blank) */ + if (flags & LADJUST) + for (n = realsz; n < width; n++) + PUTC(' '); + /* finally, adjust cnt */ + cnt += width > realsz ? width : realsz; + break; + case '\0': /* "%?" prints ?, unless ? is NULL */ + *outp = '\0'; + return (cnt); + default: + PUTC((char)*fmt); + cnt++; + } + } + /* NOTREACHED */ +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/ctracedec/main.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,26 @@ +/* + * This module contains the main() function for ctracedec + */ + +#include <stdio.h> +#include <stdlib.h> + +char *str2ind_tab_filename; + +main(argc, argv) + char **argv; +{ + int i; + + if (argc < 3) { + fprintf(stderr, + "usage: %s str2ind.tab logfile [more log files]\n", + argv[0]); + exit(1); + } + str2ind_tab_filename = argv[1]; + read_str2ind_tab(); + for (i = 2; i < argc; i++) + process_log_file(argv[i]); + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/ctracedec/processlog.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,81 @@ +/* + * This module contains the code that processes rvtdump/rvinterf log files + * at the high level and identifies which lines are compressed traces. + */ + +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> + +is_logline_ctrace(line) + char *line; +{ + char *cp = line; + + if (*cp++ != '[') + return(0); + if (!isdigit(*cp++)) + return(0); + if (!isdigit(*cp++)) + return(0); + if (*cp++ != ':') + return(0); + if (!isdigit(*cp++)) + return(0); + if (!isdigit(*cp++)) + return(0); + if (*cp++ != ':') + return(0); + if (!isdigit(*cp++)) + return(0); + if (!isdigit(*cp++)) + return(0); + if (strncmp(cp, "] GPF trace ", 12)) + return(0); + cp += 12; + while (isalpha(*cp)) { + while (*cp && !isspace(*cp)) + cp++; + if (isspace(*cp)) + cp++; + else + return(0); + } + if (isdigit(*cp)) + return(cp - line); + else + return(0); +} + +process_log_file(filename) + char *filename; +{ + FILE *f; + char linebuf[512], *cp; + int lineno, i; + + f = fopen(filename, "r"); + if (!f) { + perror(filename); + exit(1); + } + for (lineno = 1; fgets(linebuf, sizeof linebuf, f); lineno++) { + cp = index(linebuf, '\n'); + if (!cp) { + fprintf(stderr, + "error: %s line %d is too long or unterminated\n", + filename, lineno); + exit(1); + } + *cp = '\0'; + i = is_logline_ctrace(linebuf); + if (i) + process_ctrace_line(linebuf, i, filename, lineno); + else + puts(linebuf); + } + fclose(f); + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/ctracedec/readtab.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,145 @@ +/* + * This module handles the reading and parsing of str2ind.tab + */ + +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> + +extern char *str2ind_tab_filename; + +int str2ind_array_size; +char **str2ind_orig_strings; +char **str2ind_param_strings; + +static FILE *readF; +static char linebuf[256]; +static int lineno; + +static void +read_line() +{ + char *cp; + + if (!fgets(linebuf, sizeof linebuf, readF)) { + fprintf(stderr, "error: premature EOF reading from %s\n", + str2ind_tab_filename); + exit(1); + } + lineno++; + cp = index(linebuf, '\n'); + if (!cp) { + fprintf(stderr, + "error: %s line %d is too long or unterminated\n", + str2ind_tab_filename, lineno); + exit(1); + } + *cp = '\0'; + if (cp > linebuf && cp[-1] == '\r') + cp[-1] = '\0'; +} + +static void +line_pure_num() +{ + char *cp; + + for (cp = linebuf; isspace(*cp); cp++) + ; + if (!isdigit(*cp)) { +inv: fprintf(stderr, "%s line %d: pure number expected\n", + str2ind_tab_filename, lineno); + exit(1); + } + while (isdigit(*cp)) + cp++; + if (*cp) + goto inv; +} + +static char * +copystr(str) + char *str; +{ + static char null = '\0'; + char *buf; + + if (str[0]) { + buf = malloc(strlen(str) + 1); + if (!buf) { + perror("malloc"); + exit(1); + } + strcpy(buf, str); + return(buf); + } else + return(&null); +} + +static void +process_record_line(idx) +{ + char *cp, *cp2; + int i; + + for (cp = linebuf; isspace(*cp); cp++) + ; + if (!isdigit(*cp)) { +syntaxerr: fprintf(stderr, "%s line %d: unexpected syntax\n", + str2ind_tab_filename, lineno); + exit(1); + } + while (isdigit(*cp)) + cp++; + if (*cp++ != ',') + goto syntaxerr; + i = atoi(linebuf); + if (i != idx) { + fprintf(stderr, "%s line %d lists wrong index (expected %d)\n", + str2ind_tab_filename, lineno, idx); + exit(1); + } + cp2 = index(cp, ','); + if (!cp2) + goto syntaxerr; + *cp2++ = '\0'; + str2ind_param_strings[idx] = copystr(cp); + str2ind_orig_strings[idx] = copystr(cp2); +} + +read_str2ind_tab() +{ + int idx; + + readF = fopen(str2ind_tab_filename, "r"); + if (!readF) { + perror(str2ind_tab_filename); + exit(1); + } + /* skip the timestamp line: the user is responsible for matching */ + read_line(); + line_pure_num(); + /* read the line with the array size */ + read_line(); + line_pure_num(); + str2ind_array_size = atoi(linebuf); + if (str2ind_array_size < 1) { + fprintf(stderr, "error: %s gives index array size < 1\n", + str2ind_tab_filename); + exit(1); + } + str2ind_orig_strings = malloc(sizeof(char *) * str2ind_array_size); + str2ind_param_strings = malloc(sizeof(char *) * str2ind_array_size); + if (!str2ind_orig_strings || !str2ind_param_strings) { + perror("malloc"); + exit(1); + } + for (idx = 0; idx < str2ind_array_size; idx++) { + read_line(); + process_record_line(idx); + } + fclose(readF); + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/doc/README.old Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,70 @@ +You are looking at the suite of FreeCalypso tools for talking to the RVTMUX +interface provided by TI-based GSM firmwares. If you haven't already, please +read ../doc/RVTMUX first. + +The fundamental difference between these tools and loadtools is that loadtools +operate on a GSM device while its regular firmware is shut down, whereas the +present rvinterf tools talk to active running GSM firmwares. + +The following tools are currently implemented: + +rvtdump Opens the serial port, decodes TI's binary packet protocol, and + simply dumps every received/decoded packet on stdout in a human- + readable form. No provision for sending anything to the target. + Intended use: observing the debug trace output which all TI + firmwares emit as standard "background noise". This utility + allows one to observe/log/study the "noise" that appears on + Pirelli's USB-serial port (running Pirelli's original fw), + as well as that emitted on the IrDA (headset jack) port on the + GTA02 by mokoN/leo2moko firmwares. + +rvinterf Provides a bidirectional interface to RVTMUX on the host side. + It dumps and/or logs the "background noise" emitted by the + target just like rvtdump, but also creates a local UNIX domain + socket on the host machine to which other programs can connect, + replicating the MUXing function on the host side. + +fc-tmsh Interactive asynchronous test mode shell. This program connects + to a target GSM device through rvinterf and allows a developer- + operator to send various ETM commands to the target. ETM + responses are decoded (sometimes only lightly) and displayed. + fc-tmsh is fully asynchronous in that it continuously listens + (via select(2)) both for user input and for packets from the + target at the same time, translating any user-entered commands + into packets to the target and conversely, scribbling on the + terminal when a packet arrives from the target. It has no + knowledge of any correspondence between commands and responses + they normally elicit. + +g23sh Like fc-tmsh (same asynchronous design), but for GPF/G23 rather + than ETM. This tool and FreeCalypso project's understanding of + GPF/G23 in general are currently in the earliest stages, so it + is premature to try to describe it any further at this point. + +fc-sendsp Precursor to g23sh; even less worthy of further documentation. + +fc-fsio This program uses RVTMUX, ETM and TMFFS2 to access the live file + system of a running GSM firmware. Of the existing proprietary + firmwares, the only one that implements the TMFFS2 protocol + required for fc-fsio is Pirelli's, to the best of our knowledge. + This program connects to the target through rvinterf, but it + differs from fc-tmsh in that it operates in a synchronous + manner: the flow of operation is driven by user commands (just + like in fc-loadtool), and every time the program sends an ETM + command packet to the target, it expects a lock-step response. + +tfc139 See ../doc/Compal-unlock + +The fc-fsio, fc-tmsh and g23sh tools connect to the target not directly, but +via rvinterf. Two usage scenarios are supported: + +1. The user explicitly runs rvinterf (either directly or secondary to fc-xram, + when testing an experimental FreeCalypso firmware ramImage), leaves it + running (either backgrounded or in its own terminal window), and then runs + one of the "client" programs: fc-fsio, fc-tmsh or g23sh. The two programs + connect via local UNIX domain sockets on the host machine. + +2. All of the "client" programs under discussion can also launch rvinterf + themselves. An instance of rvinterf lauched in this manner becomes a child + process of the "client" program, terminating together with it, and the two + processes communicate via an unnamed and unbound socket pair.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/doc/README.older Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,89 @@ +I (Spacefalcon the Outlaw, FreeCalypso developer) am still learning what kinds +of traffic may be passed across TI's RVTMUX binary-packet serial interface. We +already know that much of this traffic is debug trace output, i.e., +unidirectional and essentially unconditional output from the GSM device. All +of the "standard" firmwares we have (mokoN, our leo2moko which functions almost +identically, and Pirelli's fw) produce massive volumes of such trace output in +normal operation. We already know that this "unsolicited" trace output comes +in at least 3 different flavors: + +* RiViera traces emitted by rvf_send_trace() +* L1 traces +* G23 traces + +The RVTMUX interface can be used for more than just trace output, though: any +component in TI's fw suite can send and/or register to receive binary packets. +As I slowly work my way through various components which comprise TI's Leonardo +fw whose semi-source we use as our reference version, learning what they do and +reintegrating them in our own gsm-fw, I will undoubtedly uncover additional uses +to which the RVTMUX interface is put. + +Aside from the trivial provision in the RVT module itself whereby an external +host can send a command to the target to set a filter masking some of the RV +trace output, so far the only entity I've come across which accepts packets from +an external host is ETM (Enhanced Test Mode). ETM implements a registration +system of its own, whereby other modules can register with ETM to receive +certain external command messages passing first through RVT, then through ETM. + +Because I do not yet have a clear mental picture of *every* function for which +the RVTMUX interface will ever be used, it is correspondingly impractical to +decide on a once-and-for-all design of what the host-side software for talking +to this interface should be like. Therefore, it is currently premature to +expect any stability in the present rvinterf subdirectory of freecalypso-sw; I +may implement something one day, then toss it away the next day (without +providing much in the way of backward compatibility) when I come up with some +other idea. + +The current roadmap for what the rvinterf suite of host tools is envisioned to +look like eventually is as follows: + +rvtdump Opens the serial port, decodes TI's binary packet protocol, and + simply dumps every received/decoded packet on stdout in a human- + readable form. No provision for sending anything to the target. + Intended use: observing the debug trace output which all TI + firmwares emit as standard "background noise". This utility has + already been written, and it allows one to observe/log/study the + "noise" that appears on Pirelli's USB-serial port (running + Pirelli's original fw), as well as that emitted on the IrDA + (headset jack) port on the GTA02 by mokoN/leo2moko firmwares. + +rvinterf My plan is to make a copy of rvtdump, called rvinterf, and have + it act very much like rvtdump: receive TI's packets from the + serial port, decode them and print the decoded form on stdout. + However, rvinterf will also create a listening UNIX domain + socket to which other programs in the present suite will + connect. These other programs connecting through rvinterf will + be able to send packets to the target, as well as register to + receive certain kinds of target->host message packets. + +fc-tmsh FreeCalypso Test Mode Shell is my vision for the utility which + will provide a practically usable interface to ETM. ETM's + general mode of operation seems to be (weasel phrase inserted + because many other fw components may connect through ETM, and I + have yet to study all of them) command-response: an external + host sends a command to ETM, that command gets dispatched to the + proper registered handler, the command function is executed, a + response packet is composed, and finally that response is sent + back to the host. But because all code on the target side is + under active development and debugging, we should not expect + perfect lock-step behaviour on the interface; instead, our + fc-tmsh should be fundamentally asynchronous: when the user + enters a command, the appropriate command packet is sent to the + target, but we are prepared for target->host messages at any + time, without enforcing strict correspondence to issued + commands: let the developer-operator sort that out instead. + +The usage scenario I envision is that one will need to run rvinterf first +(either directly or through fc-xram) in one terminal window, leave it running, +then run fc-tmsh in another terminal window, and have it connect to rvinterf +via the local UNIX domain socket interface. Why such complexity, why not have +one program do everything? I suspect that in many debug/experimentation +sessions it will be necessary to use fc-tmsh on "noisy" targets, i.e., in +scenarios where the target is continuously spewing its "normal" voluminous debug +trace output, such that the "interesting" output as in responses to commands +gets drowned in the noise. In such a scenario it would be helpful to have one +terminal window in which one sees the transcript of the fc-tmsh session, +consisting of issued commands and received ETM responses without the general +noise, and another window in which one sees all RVTMUX interface activity in +real time - the latter would allow one to observe commands having side effects +outside of ETM, such as crashing the whole fw. :-)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/doc/rvinterf.usage Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,59 @@ +Rvinterf (the specific program by this name) is an extended version of rvtdump +(see rvtdump.usage) that decodes and dumps and/or logs any and all output +generated by the firmware running on the target just like rvtdump, but also +creates a local UNIX domain socket on the host machine to which "client" +programs can connect. "Client" programs connecting to rvinterf via this local +socket interface can: + +1. Receive copies of selected RVTMUX packets coming from the target; + +2. Send arbitrary RVTMUX packets toward the target. + +Rvinterf is invoked just like rvtdump: + +rvinterf [options] /dev/ttyXXX + +The following options have the same meaning as in rvtdump, see rvtdump.usage +for the details: -b, -B, -d and -l. The only difference is that -b without -l +is potentially useful and thus allowed. + +Additional rvinterf options which don't exist in rvtdump are: + +-n + + Suppress the output on stdout like -b, but don't fork into background. + This option is passed by "client" programs when they invoke rvinterf + behind the scenes instead of connecting to an already-running rvinterf + instance. + +-s pathname_for_socket + + By default the local UNIX domain socket created by rvinterf is bound to + /tmp/rvinterf_socket; this option allows any other pathname to be + specified. + +-S <file descriptor number> + + This option is not meant for direct use by human users. It is passed + by "client" programs when they invoke rvinterf behind the scenes with + an unnamed and unbound socket pair instead of conecting to an already- + running rvinterf instance. + +-w number_in_seconds + + It has been discovered experimentally that if an RVTMUX packet is sent + to a target when the latter is in the "deep sleep" state, the target + wakes up, but the packet that was sent is not received correctly. TI's + reference fw seems to wait for 10 s after last serial activity before + falling into deep sleep (provided that all other conditions for that + sleep mode are satisfied), hence the following workaround has been + implemented in rvinterf: if a packet is to be sent to the target and + more than a set time has elapsed since the last transmitted packet, the + packet is preceded by a "wake-up shot" of 64 0 bytes (outside of a + packet, ignored by the fw) and a 100 ms pause. This hack is not pretty, + but it appears to do its job of making RVTMUX communication with target + firmwares reliable. + + The -w option changes the elapsed time threshold at which the "wake-up + shot" is sent; the default is 7 s. Specify -w 0 to disable this hack + altogether.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/doc/rvtdump.usage Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,40 @@ +Rvtdump is a utility that listens on a serial port, receives traces or any other +packets emitted by the running firmware of a GSM device in TI's RVTMUX format, +decodes them into readable ASCII and emits them to stdout and/or to a log file. +It is to be invoked as follows: + +rvtdump [options] /dev/ttyXXX + +where the sole non-option argument is the serial port it should open and listen +on. + +The available options are: + +-b + + Normally the rvtdump process remains in the foreground and emits its + output on stdout. The -b option suppresses the normal output and causes + rvtdump to put itself in the background: fork at startup, then have the + parent exit while the child remains running. -b is not useful and not + allowed without -l. + +-B baud + + Selects which RVTMUX serial channel baud rate our tool should listen + for. Defaults to 115200 baud, which appears to be TI's default and is + correct for mokoN, leo2moko and Pirelli's fw. Use -B 57600 for Compal's + RVTMUX, the one accessible via **16379#. + +-d <file descriptor number> + + This option is not meant for direct use by human users. It is inserted + automatically when rvtdump is launched from fc-xram as the secondary + program that immediately takes over the serial channel. + +-l logfile + + Log all received and decoded packets into the specified file in addition + to (without -b) or instead of (with -b) dumping them on stdout. Each + line in the log file is also time-stamped; the timestamps are in GMT + (gmtime(3)) instead of local time - Spacefalcon the Outlaw dislikes + local times.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/doc/tfc139.usage Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,38 @@ +The tfc139 hack-utility (see ../../doc/Compal-unlock) is based on the +rvinterf/rvtdump skeleton, and it needs to be invoked as follows: + +tfc139 [options] /dev/ttyXXX + +In the well-tested use case of breaking into TFC139 phones with fw version +8.8.17, no options are normally needed, but the following options are supported: + +-a address + + This option changes the RAM address into which the "shellcode" is to be + written; the argument is always interpreted as hex. The default is + 0x800000, as used by the mot931c.exe closed source tool on whose + reverse-engineering our hack-utility is based. + +-B baud + + This option changes the serial baud rate just like in rvinterf and + rvtdump, but the default is 57600 as needed for breaking into TFC139 + firmware. + +-l logfile + + Log activity in a file, just like rvinterf and rvtdump. + +-s address + + Just like mot931c.exe has been observed to do, we start our stack + smashing attempts at a certain address, and keep incrementing by 4 + until we either succeed or crash the fw in some other way that does not + help us. This option changes the starting address for these stack + smashing attempts; the argument is always interpreted as hex. The + default is 0x837C54, as observed from the reverse engineering of + mot931c. + +-w number_in_seconds + + See rvinterf.usage; the option is the same for tfc139 as for rvinterf.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,44 @@ +CC= gcc +CFLAGS= -O2 -I../include +PROGS= fc-dspapidump fc-fsio fc-getpirimei fc-olddump fc-pirhackinit +INSTBIN=/usr/local/bin + +DSPDUMP_OBJS= connect.o dspapidump.o interf.o launchrvif.o memops.o \ + simplemain.o + +FSIO_OBJS= connect.o dispatch.o fdcmd.o fileio.o fsbasics.o fscmdtab.o \ + fserr.o fsiomain.o fsmisc.o fspath.o fsread.o fsupload.o \ + fswrite.o interf.o launchrvif.o memcmd.o memops.o rfcap.o \ + stddirs.o symlink.o + +OLDDUMP_OBJS= connect.o interf.o launchrvif.o memops.o olddump.o simplemain.o + +PIRIMEI_OBJS= connect.o interf.o launchrvif.o memops.o pirimei.o \ + pirimeimain.o simplemain.o + +PIRHACK_OBJS= connect.o fileio.o fserr.o interf.o launchrvif.o memops.o \ + pirhackinit.o pirimei.o rfcap.o simplemain.o stddirs.o + +all: ${PROGS} + +fc-dspapidump: ${DSPDUMP_OBJS} + ${CC} ${CFLAGS} -o $@ ${DSPDUMP_OBJS} + +fc-fsio: ${FSIO_OBJS} + ${CC} ${CFLAGS} -o $@ ${FSIO_OBJS} + +fc-olddump: ${OLDDUMP_OBJS} + ${CC} ${CFLAGS} -o $@ ${OLDDUMP_OBJS} + +fc-getpirimei: ${PIRIMEI_OBJS} + ${CC} ${CFLAGS} -o $@ ${PIRIMEI_OBJS} -lcrypto + +fc-pirhackinit: ${PIRHACK_OBJS} + ${CC} ${CFLAGS} -o $@ ${PIRHACK_OBJS} -lcrypto + +install: ${PROGS} + mkdir -p ${INSTBIN} + install -c ${PROGS} ${INSTBIN} + +clean: + rm -f *.o *.out *errs ${PROGS}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/cmdtab.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,8 @@ +struct cmdtab { + char *cmd; + int minargs; + int maxargs; + int (*func)(); +}; + +#define MAX_CMD_ARGS 16
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/connect.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,56 @@ +/* + * Connecting to an already running rvinterf process + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <unistd.h> +#include "pktmux.h" +#include "localsock.h" +#include "exitcodes.h" + +char *socket_pathname = "/tmp/rvinterf_socket"; +int sock; + +connect_local_socket() +{ + /* local socket binding voodoo copied from osmocon */ + struct sockaddr_un local; + unsigned int namelen; + int rc; + + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) { + perror("socket(AF_UNIX, SOCK_STREAM, 0)"); + exit(ERROR_UNIX); + } + + local.sun_family = AF_UNIX; + strncpy(local.sun_path, socket_pathname, sizeof(local.sun_path)); + local.sun_path[sizeof(local.sun_path) - 1] = '\0'; + + /* we use the same magic that X11 uses in Xtranssock.c for + * calculating the proper length of the sockaddr */ +#if defined(BSD44SOCKETS) || defined(__UNIXWARE__) + local.sun_len = strlen(local.sun_path); +#endif +#if defined(BSD44SOCKETS) || defined(SUN_LEN) + namelen = SUN_LEN(&local); +#else + namelen = strlen(local.sun_path) + + offsetof(struct sockaddr_un, sun_path) + 1; +#endif + + rc = connect(sock, (struct sockaddr *) &local, namelen); + if (rc != 0) { + perror(socket_pathname); + exit(ERROR_RVINTERF); + } + + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/dispatch.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,131 @@ +/* + * This module implements the command dispatch for fc-fsio + * and possibly other similar utilities in the future. + */ + +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "cmdtab.h" +#include "exitcodes.h" + +extern struct cmdtab cmdtab[]; + +parse_and_dispatch_cmd(cmd, is_script) + char *cmd; +{ + char *argv[MAX_CMD_ARGS+2]; + char *cp, **ap; + struct cmdtab *tp; + + for (cp = cmd; isspace(*cp); cp++) + ; + if (!*cp || *cp == '#') + return(0); + if (is_script) + printf("Script command: %s\n", cp); + argv[0] = cp; + while (*cp && !isspace(*cp)) + cp++; + if (*cp) + *cp++ = '\0'; + for (tp = cmdtab; tp->cmd; tp++) + if (!strcmp(tp->cmd, argv[0])) + break; + if (!tp->func) { + fprintf(stderr, "error: no such command\n"); + return(ERROR_USAGE); + } + for (ap = argv + 1; ; ) { + while (isspace(*cp)) + cp++; + if (!*cp || *cp == '#') + break; + if (ap - argv - 1 >= tp->maxargs) { + fprintf(stderr, "error: too many arguments\n"); + return(ERROR_USAGE); + } + if (*cp == '"') { + *ap++ = ++cp; + while (*cp && *cp != '"') + cp++; + if (*cp != '"') { + fprintf(stderr, + "error: unterminated quoted string\n"); + return(ERROR_USAGE); + } + *cp++ = '\0'; + } else { + *ap++ = cp; + while (*cp && !isspace(*cp)) + cp++; + if (*cp) + *cp++ = '\0'; + } + } + if (ap - argv - 1 < tp->minargs) { + fprintf(stderr, "error: too few arguments\n"); + return(ERROR_USAGE); + } + *ap = 0; + return tp->func(ap - argv, argv); +} + +dispatch_ready_argv(argc, argv) + char **argv; +{ + struct cmdtab *tp; + + for (tp = cmdtab; tp->cmd; tp++) + if (!strcmp(tp->cmd, argv[0])) + break; + if (!tp->func) { + fprintf(stderr, "error: no such command\n"); + return(ERROR_USAGE); + } + if (argc - 1 > tp->maxargs) { + fprintf(stderr, "error: too many arguments\n"); + return(ERROR_USAGE); + } + if (argc - 1 < tp->minargs) { + fprintf(stderr, "error: too few arguments\n"); + return(ERROR_USAGE); + } + return tp->func(argc, argv); +} + +cmd_exec(argc, argv) + char **argv; +{ + FILE *f; + char linebuf[512], *cp; + int lineno, retval = 0; + + f = fopen(argv[1], "r"); + if (!f) { + perror(argv[1]); + return(ERROR_USAGE); + } + for (lineno = 1; fgets(linebuf, sizeof linebuf, f); lineno++) { + cp = index(linebuf, '\n'); + if (!cp) { + fprintf(stderr, "%s line %d: missing newline\n", + argv[1], lineno); + fclose(f); + return(ERROR_USAGE); + } + *cp = '\0'; + retval = parse_and_dispatch_cmd(linebuf, 1); + if (retval) + break; + } + fclose(f); + return(retval); +} + +cmd_exit() +{ + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/dspapidump.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,39 @@ +/* + * This utility uses ETM in synchronous mode to read and dump the contents + * of the DSP API RAM in a target Calypso GSM device while the firmware is + * running. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <stdint.h> +#include <endian.h> +#include "exitcodes.h" + +#define APIF_ADDR 0xFFD00000 +#define API_SIZE_IN_WORDS 0x2000 + +single_op_main() +{ + uint16_t buf[64], *linebase; + unsigned off; + int rc, i, j; + + for (off = 0; off < API_SIZE_IN_WORDS; ) { + rc = do_memory_read_16(APIF_ADDR + off * 2, buf, 0x40); + if (rc) + return(rc); + for (i = 0; i < 8; i++) { + printf("%04X:", off); + linebase = buf + i * 8; + for (j = 0; j < 8; j++) + printf(" %04X", le16toh(linebase[j])); + putchar('\n'); + off += 8; + } + } + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/exitcodes.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,5 @@ +#define ERROR_USAGE 1 +#define ERROR_TARGET 2 +#define ERROR_RVINTERF 3 +#define ERROR_UNIX 4 +#define ERROR_BUG 5
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/fdcmd.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,87 @@ +/* + * File descriptor debug commands + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "etm.h" +#include "ffs.h" +#include "tmffs2.h" +#include "limits.h" +#include "localtypes.h" +#include "localstruct.h" +#include "cmdtab.h" +#include "exitcodes.h" + +cmd_fd_open(argc, argv) + char **argv; +{ + int rc, fd; + + rc = fd_open(argv[1], strtoul(argv[2], 0, 16), &fd); + if (rc) + return(rc); + printf("%d\n", fd); + return(0); +} + +cmd_fd_read(argc, argv) + char **argv; +{ + u_char databuf[MAX_READ_DATA]; + int rc, sz, off, l; + + rc = fd_read(strtoul(argv[1], 0, 0), databuf, strtoul(argv[2], 0, 0), + &sz); + if (rc) + return(rc); + printf("%d bytes read\n", sz); + for (off = 0; off < sz; off += 16) { + l = sz - off; + if (l > 16) + l = 16; + hexdump_line(off, databuf + off, l); + } + return(0); +} + +cmd_fd_close(argc, argv) + char **argv; +{ + return fd_close(strtoul(argv[1], 0, 0)); +} + +struct cmdtab fd_cmds[] = { + {"close", 1, 1, cmd_fd_close}, + {"open", 2, 2, cmd_fd_open}, + {"read", 2, 2, cmd_fd_read}, + {0, 0, 0, 0} +}; + +cmd_fd(argc, argv) + char **argv; +{ + struct cmdtab *tp; + int extargs; + + for (tp = fd_cmds; tp->cmd; tp++) + if (!strcmp(tp->cmd, argv[1])) + break; + if (!tp->func) { + fprintf(stderr, "error: no such fd command\n"); + return(ERROR_USAGE); + } + extargs = argc - 2; + if (extargs > tp->maxargs) { + fprintf(stderr, "error: too many arguments\n"); + return(ERROR_USAGE); + } + if (extargs < tp->minargs) { + fprintf(stderr, "error: too few arguments\n"); + return(ERROR_USAGE); + } + return tp->func(argc - 1, argv + 1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/fileio.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,401 @@ +/* + * FFS2 file descriptor I/O operations + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "etm.h" +#include "ffs.h" +#include "ffserr.h" +#include "tmffs2.h" +#include "limits.h" +#include "localtypes.h" +#include "localstruct.h" +#include "exitcodes.h" + +extern u_char rvi_msg[]; +extern int rvi_msg_len; + +fd_open(pathname, flags, fdrtn) + char *pathname; + int flags, *fdrtn; +{ + u_char cmdpkt[MAX_PKT_TO_TARGET], *dp; + int rc, slen; + + slen = strlen(pathname); + if (slen >= TMFFS_STRING_SIZE) { + printf("error: pathname arg exceeds string length limit\n"); + return(ERROR_USAGE); + } + dp = cmdpkt + 1; + *dp++ = ETM_FFS2; + *dp++ = TMFFS_OPEN; + *dp++ = slen + 1; + strcpy(dp, pathname); + dp += slen + 1; + *dp++ = flags; + rc = etm_pkt_exch(cmdpkt, dp - cmdpkt - 1); + if (rc) + return(rc); + if (rvi_msg[3]) { + report_ffs_err("open fd", rvi_msg[3]); + return(ERROR_TARGET); + } + if (rvi_msg_len != 6) { + printf("error: open fd response has wrong length\n"); + return(ERROR_TARGET); + } + *fdrtn = rvi_msg[4]; + return(0); +} + +fd_read(fd, databuf, rdsize, rdret) + u_char *databuf; + int fd, rdsize, *rdret; +{ + u_char cmdpkt[6]; + int rc, sz; + + if (rdsize > MAX_READ_DATA) { + printf("error: # of bytes to read may not exceed %d\n", + MAX_READ_DATA); + return(ERROR_USAGE); + } + cmdpkt[1] = ETM_FFS2; + cmdpkt[2] = TMFFS_READ; + cmdpkt[3] = fd; + cmdpkt[4] = rdsize; + rc = etm_pkt_exch(cmdpkt, 4); + if (rc) + return(rc); + if (rvi_msg[3]) { + report_ffs_err("read fd", rvi_msg[3]); + return(ERROR_TARGET); + } + if (rvi_msg_len < 6) { + *rdret = 0; + return(0); + } + sz = rvi_msg[4]; + if (rvi_msg_len != sz + 6 || sz > rdsize) { + printf("error: read fd response has wrong length\n"); + return(ERROR_TARGET); + } + bcopy(rvi_msg + 5, databuf, sz); + *rdret = sz; + return(0); +} + +fd_write(fd, data, wrsize) + u_char *data; +{ + u_char cmdpkt[MAX_PKT_TO_TARGET], *dp; + int rc; + + if (wrsize > MAX_PKT_TO_TARGET - 6) { + printf("error: fd write data fails to fit in the packet\n"); + return(ERROR_USAGE); + } + dp = cmdpkt + 1; + *dp++ = ETM_FFS2; + *dp++ = TMFFS_WRITE; + *dp++ = fd; + *dp++ = wrsize; + bcopy(data, dp, wrsize); + dp += wrsize; + rc = etm_pkt_exch(cmdpkt, dp - cmdpkt - 1); + if (rc) + return(rc); + if (rvi_msg[3]) { + report_ffs_err("fd write", rvi_msg[3]); + return(ERROR_TARGET); + } + if (rvi_msg_len != 6) { + printf("error: TMFFS_WRITE response has wrong length\n"); + return(ERROR_TARGET); + } + if (rvi_msg[4] != wrsize) { + printf("fd write error: # of bytes written != requested\n"); + return(ERROR_TARGET); + } + return(0); +} + +fd_close(fd) +{ + u_char cmdpkt[5]; + int rc; + + cmdpkt[1] = ETM_FFS2; + cmdpkt[2] = TMFFS_CLOSE; + cmdpkt[3] = fd; + rc = etm_pkt_exch(cmdpkt, 3); + if (rc) + return(rc); + if (rvi_msg[3]) { + report_ffs_err("close fd", rvi_msg[3]); + return(ERROR_TARGET); + } + if (rvi_msg_len != 5) { + printf("error: close fd response has wrong length\n"); + return(ERROR_TARGET); + } + return(0); +} + +do_file_read(pathname, databuf, rdsize, rdret) + char *pathname; + u_char *databuf; + int rdsize, *rdret; +{ + u_char cmdpkt[MAX_PKT_TO_TARGET], *dp; + int rc, slen, sz; + + slen = strlen(pathname); + if (slen >= TMFFS_STRING_SIZE) { + printf("error: pathname arg exceeds string length limit\n"); + return(ERROR_USAGE); + } + if (rdsize > MAX_READ_DATA) { + printf("error: # of bytes to read may not exceed %d\n", + MAX_READ_DATA); + return(ERROR_USAGE); + } + dp = cmdpkt + 1; + *dp++ = ETM_FFS2; + *dp++ = TMFFS_FILE_READ; + *dp++ = slen + 1; + strcpy(dp, pathname); + dp += slen + 1; + *dp++ = rdsize; + rc = etm_pkt_exch(cmdpkt, dp - cmdpkt - 1); + if (rc) + return(rc); + if (rvi_msg[3]) { + report_ffs_err("read file", rvi_msg[3]); + return(ERROR_TARGET); + } + if (rvi_msg_len < 6) { + *rdret = 0; + return(0); + } + sz = rvi_msg[4]; + if (rvi_msg_len != sz + 6 || sz > rdsize) { + printf("error: read file response has wrong length\n"); + return(ERROR_TARGET); + } + bcopy(rvi_msg + 5, databuf, sz); + *rdret = sz; + return(0); +} + +max_short_file_write(pathname) + char *pathname; +{ + return MAX_PKT_TO_TARGET - 3 - (strlen(pathname) + 2) - 3; +} + +do_short_fwrite(pathname, data, datalen) + char *pathname; + u_char *data; +{ + u_char cmdpkt[MAX_PKT_TO_TARGET], *dp; + int rc, slen; + + slen = strlen(pathname); + if (slen >= TMFFS_STRING_SIZE) { + printf("error: pathname arg exceeds string length limit\n"); + return(ERROR_USAGE); + } + if (datalen > max_short_file_write(pathname)) { + printf("error: short write data fails to fit in the packet\n"); + return(ERROR_USAGE); + } + dp = cmdpkt + 1; + *dp++ = ETM_FFS2; + *dp++ = TMFFS_FILE_WRITE; + *dp++ = slen + 1; + strcpy(dp, pathname); + dp += slen + 1; + *dp++ = datalen; + bcopy(data, dp, datalen); + dp += datalen; + *dp++ = FFS_O_CREATE | FFS_O_TRUNC; + rc = etm_pkt_exch(cmdpkt, dp - cmdpkt - 1); + if (rc) + return(rc); + if (rvi_msg_len != 5) { + printf("error: TMFFS_FILE_WRITE response has wrong length\n"); + return(ERROR_TARGET); + } + if (rvi_msg[3]) { + report_ffs_err("short file write", rvi_msg[3]); + return(ERROR_TARGET); + } + return(0); +} + +do_opendir(pathname, statertn, countrtn) + char *pathname; + u_char *statertn; + int *countrtn; +{ + u_char cmdpkt[MAX_PKT_TO_TARGET], *dp; + int rc, slen; + + slen = strlen(pathname); + if (slen >= TMFFS_STRING_SIZE) { + printf("error: pathname arg exceeds string length limit\n"); + return(ERROR_USAGE); + } + dp = cmdpkt + 1; + *dp++ = ETM_FFS2; + *dp++ = TMFFS_OPENDIR; + *dp++ = slen + 1; + strcpy(dp, pathname); + dp += slen + 1; + rc = etm_pkt_exch(cmdpkt, dp - cmdpkt - 1); + if (rc) + return(rc); + if (rvi_msg[3]) { + report_ffs_err("opendir", rvi_msg[3]); + return(ERROR_TARGET); + } + if (rvi_msg_len != 11 || rvi_msg[5] != 4) { + printf("error: opendir response has wrong length\n"); + return(ERROR_TARGET); + } + *countrtn = rvi_msg[4]; + bcopy(rvi_msg + 6, statertn, 4); + return(0); +} + +do_readdir(state, namebuf, namebuflen) + u_char *state; + char *namebuf; +{ + u_char cmdpkt[10]; + int rc, slen; + + cmdpkt[1] = ETM_FFS2; + cmdpkt[2] = TMFFS_READDIR; + cmdpkt[3] = 4; + bcopy(state, cmdpkt+4, 4); + cmdpkt[8] = TMFFS_STRING_SIZE; + rc = etm_pkt_exch(cmdpkt, 8); + if (rc) + return(rc); + if (rvi_msg[3]) { + report_ffs_err("readdir", rvi_msg[3]); + return(ERROR_TARGET); + } + if (rvi_msg_len < 14) { +malformed: printf("error: readdir response is malformed\n"); + return(ERROR_TARGET); + } + if (rvi_msg[5] != 4) + goto malformed; + slen = rvi_msg[10]; + if (slen < 2 || rvi_msg_len != slen + 12) + goto malformed; + if (slen > namebuflen) { + printf("error: readdir response exceeds provided buffer\n"); + return(ERROR_TARGET); + } + if (rvi_msg[11 + slen - 1]) /* must be terminating NUL */ + goto malformed; + bcopy(rvi_msg + 6, state, 4); + strcpy(namebuf, rvi_msg + 11); + return(0); +} + +do_xlstat(pathname, result) + char *pathname; + struct stat_info *result; +{ + u_char cmdpkt[MAX_PKT_TO_TARGET], *dp; + int rc, slen; + + slen = strlen(pathname); + if (slen >= TMFFS_STRING_SIZE) { + printf("error: pathname arg exceeds string length limit\n"); + return(ERROR_USAGE); + } + dp = cmdpkt + 1; + *dp++ = ETM_FFS2; + *dp++ = TMFFS_XLSTAT; + *dp++ = slen + 1; + strcpy(dp, pathname); + dp += slen + 1; + rc = etm_pkt_exch(cmdpkt, dp - cmdpkt - 1); + if (rc) + return(rc); + if (rvi_msg[3]) { + report_ffs_err("xlstat", rvi_msg[3]); + return(ERROR_TARGET); + } + if (rvi_msg_len != 30 || rvi_msg[4] != 24) { + printf("error: xlstat response has wrong length\n"); + return(ERROR_TARGET); + } + result->type = rvi_msg[5]; + result->flags = rvi_msg[6]; + result->inode = rvi_msg[7] | rvi_msg[8] << 8; + result->size = rvi_msg[9] | rvi_msg[10] << 8 | rvi_msg[11] << 16 | + rvi_msg[12] << 24; + result->space = rvi_msg[13] | rvi_msg[14] << 8 | rvi_msg[15] << 16 | + rvi_msg[16] << 24; + result->location = rvi_msg[17] | rvi_msg[18] << 8 | rvi_msg[19] << 16 | + rvi_msg[20] << 24; + result->block = rvi_msg[22]; + result->sequence = rvi_msg[23] | rvi_msg[24] << 8; + result->updates = rvi_msg[25] | rvi_msg[26] << 8; + return(0); +} + +do_mkdir_existok(pathname) + char *pathname; +{ + u_char cmdpkt[MAX_PKT_TO_TARGET], *dp; + int rc, slen; + struct stat_info stat; + + slen = strlen(pathname); + if (slen >= TMFFS_STRING_SIZE) { + printf("error: pathname arg exceeds string length limit\n"); + return(ERROR_USAGE); + } + dp = cmdpkt + 1; + *dp++ = ETM_FFS2; + *dp++ = TMFFS_MKDIR; + *dp++ = slen + 1; + strcpy(dp, pathname); + dp += slen + 1; + rc = etm_pkt_exch(cmdpkt, dp - cmdpkt - 1); + if (rc) + return(rc); + if (rvi_msg_len != 5) { + printf("error: mkdir response has wrong length\n"); + return(ERROR_TARGET); + } + if (!rvi_msg[3]) /* success */ + return(0); + if (rvi_msg[3] != TMFFS_ERR_EXISTS) { + report_ffs_err("mkdir", rvi_msg[3]); + return(ERROR_TARGET); + } + /* object already exists: OK if it's a directory, error otherwise */ + rc = do_xlstat(pathname, &stat); + if (rc) + return(rc); + if (stat.type == OT_DIR) + return(0); + else { + printf("error: %s exists and is not a directory\n", pathname); + return(ERROR_TARGET); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/fsbasics.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,96 @@ +/* + * Basic FFS2 operations + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "etm.h" +#include "ffs.h" +#include "tmffs2.h" +#include "limits.h" +#include "ffslimits.h" +#include "localtypes.h" +#include "localstruct.h" +#include "exitcodes.h" + +extern u_char rvi_msg[]; +extern int rvi_msg_len; + +cmd_ffs2ver() +{ + u_char cmdpkt[4]; + int rc; + + cmdpkt[1] = ETM_FFS2; + cmdpkt[2] = TMFFS_VERSION; + rc = etm_pkt_exch(cmdpkt, 2); + if (rc) + return(rc); + if (rvi_msg[3]) { + printf("FFS2 error %d\n", rvi_msg[3]); + return(ERROR_TARGET); + } + if (rvi_msg_len != 7) { + printf("error: FFS2 version response has wrong length\n"); + return(ERROR_TARGET); + } + printf("FFS2 version: %02X.%02X\n", rvi_msg[5], rvi_msg[4]); + return(0); +} + +cmd_ls(argc, argv) + char **argv; +{ + u_char state[4]; + char namebuf[256]; + int nument, i, rc; + + rc = do_opendir(argv[1], state, &nument); + if (rc) + return(rc); + if (!nument) { + printf("<empty dir>\n"); + return(0); + } + for (i = 0; i < nument; i++) { + rc = do_readdir(state, namebuf, sizeof namebuf); + if (rc) + return(rc); + printf("%s\n", namebuf); + } + return(0); +} + +cmd_stat(argc, argv) + char **argv; +{ + struct stat_info stat; + int rc; + char *type; + + rc = do_xlstat(argv[1], &stat); + if (rc) + return(rc); + switch (stat.type) { + case OT_FILE: + type = "file"; + break; + case OT_DIR: + type = "directory"; + break; + case OT_LINK: + type = "symlink"; + break; + default: + type = "???"; + } + printf("Type: %s%s\n", type, + stat.flags & OF_READONLY ? ", read-only" : ""); + printf("inode %x\n", stat.inode); + printf("size %u, space %u\n", stat.size, stat.space); + printf("location=%x, block %d\n", stat.location, stat.block); + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/fscmdtab.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,66 @@ +/* + * fc-fsio command dispatch table + */ + +#include "cmdtab.h" + +extern int cmd_cpout(); +extern int cmd_cpout_file(); +extern int cmd_delete(); +extern int cmd_dieid(); +extern int cmd_exec(); +extern int cmd_exit(); +extern int cmd_fd(); +extern int cmd_ffs2ver(); +extern int cmd_format(); +extern int cmd_fwrite(); +extern int cmd_hd(); +extern int cmd_ll(); +extern int cmd_ls(); +extern int cmd_memdump(); +extern int cmd_mkdir(); +extern int cmd_omemdump(); +extern int cmd_preformat(); +extern int cmd_readlink(); +extern int cmd_set_imeisv(); +extern int cmd_set_pcm_string(); +extern int cmd_set_rfcap(); +extern int cmd_stat(); +extern int cmd_symlink(); +extern int cmd_uploadfs(); +extern int cmd_upload_file(); +extern int cmd_upload_subtree(); + +extern int create_std_dirs(); + +struct cmdtab cmdtab[] = { + {"cpout", 2, 2, cmd_cpout}, + {"cpout-file", 2, 2, cmd_cpout_file}, + {"create-std-dirs", 0, 0, create_std_dirs}, + {"delete", 1, 1, cmd_delete}, + {"dieid", 0, 0, cmd_dieid}, + {"exec", 1, 1, cmd_exec}, + {"exit", 0, 0, cmd_exit}, + {"fd", 2, 3, cmd_fd}, + {"ffs2ver", 0, 0, cmd_ffs2ver}, + {"format", 1, 1, cmd_format}, + {"fwrite", 3, 3, cmd_fwrite}, + {"hd", 1, 1, cmd_hd}, + {"ll", 1, 1, cmd_ll}, + {"ls", 1, 1, cmd_ls}, + {"memdump", 2, 2, cmd_memdump}, + {"mkdir", 1, 1, cmd_mkdir}, + {"mk-std-dirs", 0, 0, create_std_dirs}, + {"omemdump", 2, 2, cmd_omemdump}, + {"preformat", 0, 0, cmd_preformat}, + {"readlink", 1, 1, cmd_readlink}, + {"set-imeisv", 2, 2, cmd_set_imeisv}, + {"set-pcm-string", 2, 2, cmd_set_pcm_string}, + {"set-rfcap", 1, 1, cmd_set_rfcap}, + {"stat", 1, 1, cmd_stat}, + {"symlink", 2, 2, cmd_symlink}, + {"upload-file", 2, 2, cmd_upload_file}, + {"upload-fs", 1, 1, cmd_uploadfs}, + {"upload-subtree", 2, 2, cmd_upload_subtree}, + {0, 0, 0, 0} +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/fserr.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,69 @@ +/* + * FFS error decoding + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "etm.h" +#include "ffs.h" +#include "ffserr.h" + +static struct errtab { + int errcode; + char *desc; +} errtab[] = { + {TMFFS_ERR_NODEVICE, "EFFS_NODEVICE: flash device unknown"}, + {TMFFS_ERR_CORRUPTED, "EFFS_CORRUPTED: filesystem corrupted"}, + {TMFFS_ERR_NOPREFORMAT, "EFFS_NOPREFORMAT: ffs not preformatted"}, + {TMFFS_ERR_NOFORMAT, "EFFS_NOFORMAT: ffs not formatted"}, + {TMFFS_ERR_BADFORMAT, + "EFFS_BADFORMAT: incompatible ffs version, reformat needed"}, + {TMFFS_ERR_MAGIC, "EFFS_MAGIC: bad magic"}, + {TMFFS_ERR_AGAIN, "EFFS_AGAIN: not ready, try again later"}, + {TMFFS_ERR_NOSYS, "EFFS_NOSYS: function not implemented"}, + {TMFFS_ERR_DRIVER, "EFFS_DRIVER: ffs device driver error"}, + {TMFFS_ERR_NOSPACE, "EFFS_NOSPACE: out of data space"}, + {TMFFS_ERR_FSFULL, "EFFS_FSFULL: file system full, no free inodes"}, + {TMFFS_ERR_BADNAME, "EFFS_BADNAME: bad filename"}, + {TMFFS_ERR_NOTFOUND, "EFFS_NOTFOUND: object not found"}, + {TMFFS_ERR_EXISTS, "EFFS_EXISTS: object exists"}, + {TMFFS_ERR_ACCESS, "EFFS_ACCESS: access permission violation"}, + {TMFFS_ERR_NAMETOOLONG, "EFFS_NAMETOOLONG"}, + {TMFFS_ERR_INVALID, "EFFS_INVALID"}, + {TMFFS_ERR_DIRNOTEMPTY, "EFFS_DIRNOTEMPTY"}, + {TMFFS_ERR_NOTADIR, "EFFS_NOTADIR"}, + {TMFFS_ERR_SPARE, "EFFS_SPARE"}, + {TMFFS_ERR_FILETOOBIG, "EFFS_FILETOOBIG"}, + {TMFFS_ERR_NOTAFILE, "EFFS_NOTAFILE"}, + {TMFFS_ERR_PATHTOODEEP, "EFFS_PATHTOODEEP"}, + {TMFFS_ERR_NUMFD, "EFFS_NUMFD: max number of open files reached"}, + {TMFFS_ERR_BADFD, "EFFS_BADFD: bad file descriptor"}, + {TMFFS_ERR_BADOP, "EFFS_BADOP: bad operation"}, + {TMFFS_ERR_LOCKED, "EFFS_LOCKED: the file is locked"}, + {TMFFS_ERR_TOOBIG, "EFFS_TOOBIG: tmffs buffer overflow"}, + {TMFFS_ERR_MEMORY, "EFFS_MEMORY: out of memory"}, + {TMFFS_ERR_MSGSEND, "EFFS_MSGSEND: message send failed"}, + {TMFFS_ERR_SIBLINGLOOP, "EFFS_SIBLINGLOOP: directory sibling loop"}, + {TMFFS_ERR_NOBLOCKS, "EFFS_NOBLOCKS: debug error?"}, + {TMFFS_ERR_DBR, "EFFS_DBR: debug error?"}, + {TMFFS_ERR_RECLAIMLOOP, "EFFS_RECLAIMLOOP: debug error?"}, + {0, 0} +}; + +report_ffs_err(oper, errcode) + char *oper; +{ + struct errtab *tp; + char *errdesc; + + for (tp = errtab; tp->errcode; tp++) + if (tp->errcode == errcode) + break; + errdesc = tp->desc; + if (!errdesc) + errdesc = "unknown"; + printf("%s: FFS error %d (%s)\n", oper, errcode, errdesc); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/fsiomain.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,76 @@ +/* + * This module contains the main() function for fc-fsio. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include "exitcodes.h" + +extern char *socket_pathname; +extern char *rvinterf_ttyport, *rvinterf_Bopt, *rvinterf_lopt, *rvinterf_wopt; + +main(argc, argv) + char **argv; +{ + extern int optind; + extern char *optarg; + int c, sopt = 0; + char command[512]; + + while ((c = getopt(argc, argv, "B:l:p:s:w:")) != EOF) + switch (c) { + case 'B': + rvinterf_Bopt = optarg; + continue; + case 'l': + rvinterf_lopt = optarg; + continue; + case 'p': + rvinterf_ttyport = optarg; + continue; + case 's': + socket_pathname = optarg; + sopt++; + continue; + case 'w': + rvinterf_wopt = optarg; + continue; + case '?': + default: +usage: fprintf(stderr, + "usage: %s [options] [command]\n", argv[0]); + exit(ERROR_USAGE); + } + if (rvinterf_ttyport) { + if (sopt) { + fprintf(stderr, + "%s error: -p and -s options are mutually exclusive\n", + argv[0]); + exit(ERROR_USAGE); + } + launch_rvinterf(); + } else { + if (rvinterf_Bopt || rvinterf_lopt || rvinterf_wopt) { + fprintf(stderr, +"%s error: -B, -l and -w options are meaningful only when launching rvinterf\n", + argv[0]); + exit(ERROR_USAGE); + } + connect_local_socket(); + } + + setlinebuf(stdout); + if (argv[optind]) + return dispatch_ready_argv(argc - optind, argv + optind); + for (;;) { + if (isatty(0)) { + rx_control(0); + fputs("fsio> ", stdout); + fflush(stdout); + } + if (!fgets(command, sizeof command, stdin)) + exit(0); + parse_and_dispatch_cmd(command, 0); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/fsmisc.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,149 @@ +/* + * Miscellaneous (dangerous!) FFS2 operations + */ + +#include <sys/types.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "etm.h" +#include "ffs.h" +#include "tmffs2.h" +#include "limits.h" +#include "ffslimits.h" +#include "localtypes.h" +#include "localstruct.h" +#include "exitcodes.h" + +extern u_char rvi_msg[]; +extern int rvi_msg_len; + +cmd_format(argc, argv) + char **argv; +{ + u_char cmdpkt[MAX_PKT_TO_TARGET], *dp; + int rc, slen; + + slen = strlen(argv[1]); + if (slen >= TMFFS_STRING_SIZE) { + printf("error: argument exceeds string length limit\n"); + return; + } + dp = cmdpkt + 1; + *dp++ = ETM_FFS2; + *dp++ = TMFFS_FORMAT; + *dp++ = slen + 1; + strcpy(dp, argv[1]); + dp += slen + 1; + /* magic is 0x2BAD, 16-bit little-endian */ + *dp++ = 0xAD; + *dp++ = 0x2B; + rc = etm_pkt_exch(cmdpkt, dp - cmdpkt - 1); + if (rc) + return(rc); + if (rvi_msg_len != 5) { + printf("error: TMFFS_FORMAT response has wrong length\n"); + return(ERROR_TARGET); + } + if (rvi_msg[3]) { + report_ffs_err("format", rvi_msg[3]); + return(ERROR_TARGET); + } + return(0); +} + +cmd_preformat() +{ + u_char cmdpkt[6]; + int rc; + + cmdpkt[1] = ETM_FFS2; + cmdpkt[2] = TMFFS_PREFORMAT; + /* magic is 0xDEAD, 16-bit little-endian */ + cmdpkt[3] = 0xAD; + cmdpkt[4] = 0xDE; + rc = etm_pkt_exch(cmdpkt, 4); + if (rc) + return(rc); + if (rvi_msg_len != 5) { + printf("error: TMFFS_PREFORMAT response has wrong length\n"); + return(ERROR_TARGET); + } + if (rvi_msg[3]) { + report_ffs_err("preformat", rvi_msg[3]); + return(ERROR_TARGET); + } + return(0); +} + +cmd_set_imeisv(argc, argv) + char **argv; +{ + char *filename, *cp, digits[16]; + u_char bytes[8]; + int pcm_order, i; + + if (!strcmp(argv[1], "pcm")) { + filename = "/pcm/IMEI"; + pcm_order = 1; + } else if (!strcmp(argv[1], "fc")) { + filename = "/etc/IMEISV"; + pcm_order = 0; + } else { + fprintf(stderr, + "error: IMEISV storage type argument must be \"pcm\" or \"fc\"\n"); + return(ERROR_USAGE); + } + cp = argv[2]; + if (!isdigit(*cp)) { +inv: fprintf(stderr, + "error: 2nd argument must have 16 decimal digits\n"); + return(ERROR_USAGE); + } + for (i = 0; i < 16; i++) { + if (ispunct(*cp)) + cp++; + if (!isdigit(*cp)) + goto inv; + digits[i] = *cp++ - '0'; + } + if (*cp) + goto inv; + for (i = 0; i < 8; i++) + bytes[i] = pcm_order ? digits[i*2+1] << 4 | digits[i*2] + : digits[i*2] << 4 | digits[i*2+1]; + printf("Writing \"%02X %02X %02X %02X %02X %02X %02X %02X\" into %s\n", + bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], + bytes[6], bytes[7], filename); + return do_short_fwrite(filename, bytes, 8); +} + +cmd_set_pcm_string(argc, argv) + char **argv; +{ + char filename[16]; + + if (strcmp(argv[1], "CGMI") && strcmp(argv[1], "CGMM") && + strcmp(argv[1], "CGMR") && strcmp(argv[1], "CGSN")) { + fprintf(stderr, + "error: \"%s\" is not a recognized PCM string file name\n", + argv[1]); + return(ERROR_USAGE); + } + sprintf(filename, "/pcm/%s", argv[1]); + if (strlen(argv[2]) > 20) { + fprintf(stderr, + "error: %s string may not exceed 20 characters\n", + filename); + return(ERROR_USAGE); + } + return do_short_fwrite(filename, argv[2], strlen(argv[2])); +} + +cmd_set_rfcap(argc, argv) + char **argv; +{ + return set_rfcap(argv[1]); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/fspath.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,70 @@ +/* + * FFS pathname manipulation functions + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "ffs.h" +#include "limits.h" +#include "ffslimits.h" +#include "exitcodes.h" + +validate_ffs_pathname(cand) + char *cand; +{ + char *cp; + int depth, c; + + cp = cand; + if (*cp++ != '/') { + fprintf(stderr, "error: FFS pathnames must be absolute\n"); + return(-1); + } + for (depth = 0; *cp; depth++) { + if (*cp == '/') { + fprintf(stderr, + "error: FFS pathname must not contain duplicate slashes\n"); + return(-1); + } + for (c = 0; *cp && *cp != '/'; cp++) + c++; + if (c > MAX_FN_COMPONENT) { + fprintf(stderr, + "error: FFS pathname component is too long\n"); + return(-1); + } + if (!*cp) + continue; + cp++; + if (!*cp) { + fprintf(stderr, + "error: FFS pathname must not end with a trailing slash\n"); + return(-1); + } + } + if (depth > MAX_NAME_DEPTH) { + fprintf(stderr, "error: FFS pathname exceeds depth limit\n"); + return(-1); + } + return(depth); +} + +char * +pathname_for_ffs_child(parent, childbuf) + char *parent, *childbuf; +{ + int depth; + char *cp; + + depth = validate_ffs_pathname(parent); + if (depth < 0 || depth >= MAX_NAME_DEPTH) + return(0); + strcpy(childbuf, parent); + cp = index(childbuf, '\0'); + if (depth) + *cp++ = '/'; + return(cp); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/fsread.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,291 @@ +/* + * Commands for reading the content of a GSM device's file system + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> +#include "etm.h" +#include "ffs.h" +#include "tmffs2.h" +#include "limits.h" +#include "ffslimits.h" +#include "localtypes.h" +#include "localstruct.h" +#include "exitcodes.h" + +extern char *pathname_for_ffs_child(); + +void +ll_print_line(pathname, stat) + char *pathname; + struct stat_info *stat; +{ + char readonly; + char rlbuf[256]; + + if (stat->flags & OF_READONLY) + readonly = 'r'; + else + readonly = ' '; + switch (stat->type) { + case OT_FILE: + printf("f%c %7u %s\n", readonly, stat->size, pathname); + return; + case OT_DIR: + printf("d%c %s\n", readonly, pathname); + return; + case OT_LINK: + if (do_readlink_sancheck(pathname, rlbuf)) + strcpy(rlbuf, "<invalid>"); + printf("l%c %s -> %s\n", readonly, pathname, rlbuf); + return; + default: + printf("?%c %s\n", readonly, pathname); + } +} + +cmd_ll(argc, argv) + char **argv; +{ + struct stat_info stat; + u_char rdstate[4]; + char rdbuf[MAX_FN_COMPONENT+1], childpath[MAX_FULL_PATHNAME+1], *childp; + int nument, i, rc; + + if (validate_ffs_pathname(argv[1]) < 0) + return(ERROR_USAGE); /* err msg already printed */ + rc = do_xlstat(argv[1], &stat); + if (rc) + return(rc); + if (stat.type != OT_DIR) { + ll_print_line(argv[1], &stat); + return(0); + } + rc = do_opendir(argv[1], rdstate, &nument); + if (rc) + return(rc); + if (!nument) { + printf("<empty dir>\n"); + return(0); + } + childp = pathname_for_ffs_child(argv[1], childpath); + if (!childp) { + printf("error: non-empty dir at the limit of pathname depth\n"); + return(ERROR_TARGET); + } + for (i = 0; i < nument; i++) { + rc = do_readdir(rdstate, rdbuf, MAX_FN_COMPONENT+1); + if (rc) + return(rc); + if (index(rdbuf, '/')) { + printf("error: readdir result contains a slash\n"); + return(ERROR_TARGET); + } + strcpy(childp, rdbuf); + rc = do_xlstat(childpath, &stat); + if (rc) { + printf("xlstat failed on %s\n", childpath); + return(rc); + } + ll_print_line(childpath, &stat); + } + return(0); +} + +void +hexdump_line(offset, buf, len) + u_char *buf; +{ + int i, c; + + printf("%02X: ", offset); + for (i = 0; i < 16; i++) { + if (i < len) + printf("%02X ", buf[i]); + else + fputs(" ", stdout); + if (i == 7 || i == 15) + putchar(' '); + } + for (i = 0; i < len; i++) { + c = buf[i]; + if (c < ' ' || c > '~') + c = '.'; + putchar(c); + } + putchar('\n'); +} + +cmd_hd(argc, argv) + char **argv; +{ + u_char databuf[MAX_READ_DATA]; + int rc, sz, off, l; + + rc = do_file_read(argv[1], databuf, MAX_READ_DATA, &sz); + if (rc) + return(rc); + printf("%d bytes read\n", sz); + for (off = 0; off < sz; off += 16) { + l = sz - off; + if (l > 16) + l = 16; + hexdump_line(off, databuf + off, l); + } + return(0); +} + +cpout_object(ffspath, hostpath) + char *ffspath, *hostpath; +{ + struct stat_info stat; + int rc; + + rc = do_xlstat(ffspath, &stat); + if (rc) + return(rc); + switch (stat.type) { + case OT_FILE: + return cpout_file(ffspath, hostpath); + case OT_DIR: + return cpout_dir(ffspath, hostpath); + case OT_LINK: + printf("skipping FFS symlink %s\n", ffspath); + return(0); + default: + printf("error: stat returned bad objtype for %s\n", ffspath); + return(ERROR_TARGET); + } +} + +cpout_file(ffspath, hostpath) + char *ffspath, *hostpath; +{ + int tfd; + FILE *of; + u_char buf[MAX_READ_DATA]; + int rc, sz; + + printf("copying %s\n", ffspath); + rc = fd_open(ffspath, FFS_O_RDONLY, &tfd); + if (rc) + return(rc); + of = fopen(hostpath, "w"); + if (!of) { + perror(hostpath); + fd_close(tfd); + return(ERROR_UNIX); + } + for (;;) { + rc = fd_read(tfd, buf, MAX_READ_DATA, &sz); + if (rc) { + fd_close(tfd); + fclose(of); + return(rc); + } + if (!sz) + break; + fwrite(buf, 1, sz, of); + } + fclose(of); + return fd_close(tfd); +} + +host_mkdir(pathname) + char *pathname; +{ + int rc; + struct stat st; + + rc = stat(pathname, &st); + if (rc < 0) { + rc = mkdir(pathname, 0777); + if (rc < 0) { + perror(pathname); + return(ERROR_UNIX); + } + return(0); + } else { + if (S_ISDIR(st.st_mode)) + return(0); + else { + fprintf(stderr, + "error: %s already exists and is not a directory\n", + pathname); + return(ERROR_UNIX); + } + } +} + +cpout_dir(ffspath_dir, hostpath_dir) + char *ffspath_dir, *hostpath_dir; +{ + u_char rdstate[4]; + char rdbuf[MAX_FN_COMPONENT+1], ffspath_child[MAX_FULL_PATHNAME+1]; + char *childp; + char hostpath_child[MAXPATHLEN]; + int nument, i, rc, childerr; + + printf("dir %s\n", ffspath_dir); + rc = host_mkdir(hostpath_dir); + if (rc) + return(rc); + rc = do_opendir(ffspath_dir, rdstate, &nument); + if (rc) + return(rc); + if (!nument) + return(0); + childp = pathname_for_ffs_child(ffspath_dir, ffspath_child); + if (!childp) { + printf("error: non-empty dir at the limit of pathname depth\n"); + return(ERROR_TARGET); + } + childerr = 0; + for (i = 0; i < nument; i++) { + rc = do_readdir(rdstate, rdbuf, MAX_FN_COMPONENT+1); + if (rc) + return(rc); + if (index(rdbuf, '/')) { + printf("error: readdir result contains a slash\n"); + return(ERROR_TARGET); + } + strcpy(childp, rdbuf); + if (rdbuf[0] == '.') { + printf("skipping %s\n", ffspath_child); + continue; + } + if (strlen(hostpath_dir) + strlen(rdbuf) + 2 > + sizeof hostpath_child) { + fprintf(stderr, + "error: host side pathname buffer overflow\n"); + return(ERROR_UNIX); + } + sprintf(hostpath_child, "%s/%s", hostpath_dir, rdbuf); + rc = cpout_object(ffspath_child, hostpath_child); + if (rc && rc != ERROR_TARGET) + return(rc); + if (rc) + childerr = rc; + } + return(childerr); +} + +cmd_cpout(argc, argv) + char **argv; +{ + if (validate_ffs_pathname(argv[1]) < 0) + return(ERROR_USAGE); /* err msg already printed */ + return cpout_object(argv[1], argv[2]); +} + +cmd_cpout_file(argc, argv) + char **argv; +{ + return cpout_file(argv[1], argv[2]); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/fsupload.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,146 @@ +/* + * upload-fs implementation + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <dirent.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "etm.h" +#include "ffs.h" +#include "ffserr.h" +#include "tmffs2.h" +#include "limits.h" +#include "ffslimits.h" +#include "localtypes.h" +#include "localstruct.h" +#include "exitcodes.h" + +uploadfs_level(srcpath, depth, prefix) + char *srcpath, *prefix; +{ + char ffs_childpath[MAX_FULL_PATHNAME+1], *ffs_childp; + DIR *rdd; + struct dirent *dirent; + char hostpath_child[MAXPATHLEN]; + struct stat hst; + int rc; + + strcpy(ffs_childpath, prefix); + ffs_childp = index(ffs_childpath, '\0'); + *ffs_childp++ = '/'; + rdd = opendir(srcpath); + if (!rdd) { + perror(srcpath); + return(ERROR_UNIX); + } + while (dirent = readdir(rdd)) { + if (dirent->d_name[0] == '.') + continue; + if (strlen(dirent->d_name) > MAX_FN_COMPONENT) { + fprintf(stderr, + "error: \"%s\" in %s exceeds the FFS component name limit\n", + dirent->d_name, srcpath); + closedir(rdd); + return(ERROR_USAGE); + } + if (strlen(srcpath) + strlen(dirent->d_name) + 2 > + sizeof hostpath_child) { + fprintf(stderr, + "error: host side pathname buffer overflow\n"); + closedir(rdd); + return(ERROR_UNIX); + } + sprintf(hostpath_child, "%s/%s", srcpath, dirent->d_name); + if (lstat(hostpath_child, &hst) < 0) { + perror(hostpath_child); + closedir(rdd); + return(ERROR_UNIX); + } + strcpy(ffs_childp, dirent->d_name); + switch (hst.st_mode & S_IFMT) { + case S_IFREG: + printf("uploading %s\n", ffs_childpath); + rc = fwrite_from_file(ffs_childpath, hostpath_child); + if (rc) { + closedir(rdd); + return(rc); + } + break; + case S_IFDIR: + if (depth >= MAX_NAME_DEPTH-1) { + fprintf(stderr, + "error: directory nesting too deep at %s\n", + hostpath_child); + closedir(rdd); + return(ERROR_USAGE); + } + printf("mkdir %s\n", ffs_childpath); + rc = do_mkdir_existok(ffs_childpath); + if (rc) { + closedir(rdd); + return(rc); + } + rc = uploadfs_level(hostpath_child, depth + 1, + ffs_childpath); + if (rc) { + closedir(rdd); + return(rc); + } + break; + default: + fprintf(stderr, + "error: %s is neither a regular file nor a directory\n", + hostpath_child); + closedir(rdd); + return(ERROR_USAGE); + } + } + closedir(rdd); + return(0); +} + +cmd_uploadfs(argc, argv) + char **argv; +{ + return uploadfs_level(argv[1], 0, ""); +} + +cmd_upload_file(argc, argv) + char **argv; +{ + if (strlen(argv[2]) >= TMFFS_STRING_SIZE) { + fprintf(stderr, + "error: pathname arg exceeds string length limit\n"); + return(ERROR_USAGE); + } + return fwrite_from_file(argv[2], argv[1]); +} + +cmd_upload_subtree(argc, argv) + char **argv; +{ + int rc, depth; + + depth = validate_ffs_pathname(argv[2]); + if (depth < 0) + return(ERROR_USAGE); /* error msg already printed */ + if (depth == 0) { + fprintf(stderr, "please use upload-fs command instead\n"); + return(ERROR_USAGE); + } + if (depth >= MAX_NAME_DEPTH) { + fprintf(stderr, "cannot upload into max-depth directory\n"); + return(ERROR_USAGE); + } + printf("mkdir %s\n", argv[2]); + rc = do_mkdir_existok(argv[2]); + if (rc) + return(rc); + return uploadfs_level(argv[1], depth, argv[2]); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/fswrite.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,163 @@ +/* + * FFS write operation commands + */ + +#include <sys/types.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "etm.h" +#include "ffs.h" +#include "ffserr.h" +#include "tmffs2.h" +#include "limits.h" +#include "localtypes.h" +#include "localstruct.h" +#include "exitcodes.h" + +extern u_char rvi_msg[]; +extern int rvi_msg_len; + +cmd_mkdir(argc, argv) + char **argv; +{ + return do_mkdir_existok(argv[1]); +} + +cmd_delete(argc, argv) + char **argv; +{ + u_char cmdpkt[MAX_PKT_TO_TARGET], *dp; + int rc, slen; + + slen = strlen(argv[1]); + if (slen >= TMFFS_STRING_SIZE) { + printf("error: pathname arg exceeds string length limit\n"); + return(ERROR_USAGE); + } + dp = cmdpkt + 1; + *dp++ = ETM_FFS2; + *dp++ = TMFFS_REMOVE; + *dp++ = slen + 1; + strcpy(dp, argv[1]); + dp += slen + 1; + rc = etm_pkt_exch(cmdpkt, dp - cmdpkt - 1); + if (rc) + return(rc); + if (rvi_msg_len != 5) { + printf("error: TMFFS_REMOVE response has wrong length\n"); + return(ERROR_TARGET); + } + if (rvi_msg[3]) { + report_ffs_err("ffs_remove", rvi_msg[3]); + return(ERROR_TARGET); + } + return(0); +} + +hexdigit(c) +{ + if (isdigit(c)) + return(c - '0'); + else if (isupper(c)) + return(c - 'A' + 10); + else + return(c - 'a' + 10); +} + +fwrite_hex_string(pathname, strarg) + char *pathname, *strarg; +{ + u_char buf[256]; + int maxlen, len; + char *cp; + + maxlen = max_short_file_write(pathname); + for (cp = strarg, len = 0; ; cp += 2) { + while (isspace(*cp)) + cp++; + if (!*cp) + break; + if (!isxdigit(cp[0]) || !isxdigit(cp[1])) { + fprintf(stderr, "error: invalid hex string argument\n"); + return(ERROR_USAGE); + } + if (len >= maxlen) { + fprintf(stderr, + "error: hex string exceeds write packet limit\n"); + return(ERROR_USAGE); + } + buf[len++] = hexdigit(cp[0]) << 4 | hexdigit(cp[1]); + } + return do_short_fwrite(pathname, buf, len); +} + +fwrite_from_file(pathname, srcfile) + char *pathname, *srcfile; +{ + u_char buf[240]; + FILE *srcf; + int rc, cc, first, tfd; + + srcf = fopen(srcfile, "r"); + if (!srcf) { + perror(srcfile); + return(ERROR_UNIX); + } + for (first = 1; cc = fread(buf, 1, sizeof buf, srcf); first = 0) { + if (first) { + if (cc < sizeof buf && + cc <= max_short_file_write(pathname)) { + fclose(srcf); + return do_short_fwrite(pathname, buf, cc); + } + rc = fd_open(pathname, + FFS_O_WRONLY | FFS_O_CREATE | FFS_O_TRUNC, + &tfd); + if (rc) { + fclose(srcf); + return(rc); + } + } + rc = fd_write(tfd, buf, cc); + if (rc) { + fclose(srcf); + fd_close(tfd); + return(rc); + } + } + fclose(srcf); + if (first) { + /* 0 length file: do an open-for-write to create it */ + rc = fd_open(pathname, + FFS_O_WRONLY | FFS_O_CREATE | FFS_O_TRUNC, + &tfd); + if (rc) + return(rc); + } + return fd_close(tfd); +} + +cmd_fwrite(argc, argv) + char **argv; +{ + if (strlen(argv[1]) >= TMFFS_STRING_SIZE) { + fprintf(stderr, + "error: pathname arg exceeds string length limit\n"); + return(ERROR_USAGE); + } + if (!strcmp(argv[2], "ascii")) + return do_short_fwrite(argv[1], argv[3], strlen(argv[3])); + else if (!strcmp(argv[2], "hex")) + return fwrite_hex_string(argv[1], argv[3]); + else if (!strcmp(argv[2], "file")) + return fwrite_from_file(argv[1], argv[3]); + else { + fprintf(stderr, +"error: middle argument to fwrite cmd must be \"ascii\", \"hex\" or \"file\"\n" + ); + return(ERROR_USAGE); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/interf.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,156 @@ +/* + * In this module we implement our synchronous interface to the target + * via rvinterf. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include "limits.h" +#include "localsock.h" +#include "pktmux.h" +#include "exitcodes.h" + +extern int sock; + +int rx_enable_state; +u_char rvi_msg[LOCALSOCK_MAX_MSG]; +int rvi_msg_len; + +static void +collect_bytes_from_rvi(buf, nbytes) + u_char *buf; +{ + int cc; + + while (nbytes) { + cc = read(sock, buf, nbytes); + if (cc <= 0) { + perror("read from rvinterf socket"); + exit(ERROR_RVINTERF); + } + buf += cc; + nbytes -= cc; + } +} + +collect_rvi_msg() +{ + u_char lenbuf[2]; + + collect_bytes_from_rvi(lenbuf, 2); + rvi_msg_len = lenbuf[0] << 8 | lenbuf[1]; + if (rvi_msg_len < 1 || rvi_msg_len > LOCALSOCK_MAX_MSG) { + fprintf(stderr, "Invalid length from rvinterf: %02X%02X\n", + lenbuf[0], lenbuf[1]); + exit(ERROR_RVINTERF); + } + collect_bytes_from_rvi(rvi_msg, rvi_msg_len); + return(0); +} + +send_rvimisc_command(cmdpkt, cmdlen) + u_char *cmdpkt; +{ + u_char lenbuf[2]; + + lenbuf[0] = 0; + lenbuf[1] = cmdlen; + write(sock, lenbuf, 2); + write(sock, cmdpkt, cmdlen); +} + +rx_control(enable) +{ + u_char cmdpkt[2]; + int cmdlen; + + /* are we already in the desired state? */ + if (rx_enable_state == enable) + return(0); + /* no, do the work */ + if (enable) { + cmdpkt[0] = CLI2RVI_WANT_MUXPROTO; + cmdpkt[1] = RVT_TM_HEADER; + cmdlen = 2; + } else { + cmdpkt[0] = CLI2RVI_RESET_PACKET_RX; + cmdlen = 1; + } + send_rvimisc_command(cmdpkt, cmdlen); + collect_rvi_msg(); + if (rvi_msg[0] != RVI2CLI_LOCAL_CMD_RESP || rvi_msg_len < 2) { + fprintf(stderr, + "error: unexpected response to rvinterf local command\n"); + exit(ERROR_RVINTERF); + } + if (rvi_msg[1] != '+') { + fprintf(stderr, "Error from rvinterf: %.*s\n", rvi_msg_len - 1, + rvi_msg + 1); + exit(ERROR_RVINTERF); + } + rx_enable_state = enable; + return(0); +} + +send_pkt_to_target(pkt, pktlen) + u_char *pkt; +{ + u_char hdrbuf[3]; + int len1; + + len1 = pktlen + 1; + hdrbuf[0] = len1 >> 8; + hdrbuf[1] = len1 & 0xFF; + hdrbuf[2] = CLI2RVI_PKT_TO_TARGET; + write(sock, hdrbuf, 3); + write(sock, pkt, pktlen); +} + +target_pkt_exch(outpkt, outpktlen) + u_char *outpkt; +{ + rx_control(1); + send_pkt_to_target(outpkt, outpktlen); + collect_rvi_msg(); + if (rvi_msg[0] != RVI2CLI_PKT_FROM_TARGET) { + fprintf(stderr, + "error: unexpected response type from rvinterf\n"); + exit(ERROR_RVINTERF); + } + return(0); +} + +etm_pkt_exch(outbuf, outlen) + u_char *outbuf; +{ + int i, c; + + outbuf[0] = RVT_TM_HEADER; + c = 0; + for (i = 1; i <= outlen; i++) + c ^= outbuf[i]; + outbuf[i] = c; + target_pkt_exch(outbuf, outlen + 2); + if (rvi_msg[1] != RVT_TM_HEADER) { + printf("error: packet from target is not ETM!\n"); + return(ERROR_TARGET); + } + if (rvi_msg_len < 5) { + printf("error: ETM response packet is too short\n"); + return(ERROR_TARGET); + } + c = 0; + for (i = 2; i < rvi_msg_len; i++) + c ^= rvi_msg[i]; + if (c) { + printf("ETM response checksum error!\n"); + return(ERROR_TARGET); + } + if (rvi_msg[2] != outbuf[1]) { + printf("error: target response is from wrong ETM component\n"); + return(ERROR_TARGET); + } + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/launchrvif.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,63 @@ +/* + * This module implements the optional "behind the scenes" invokation + * of rvinterf from fc-fsio etc. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include "exitcodes.h" + +static char rvinterf_pathname[] = "/usr/local/bin/rvinterf"; + +extern int sock; + +char *rvinterf_ttyport, *rvinterf_Bopt, *rvinterf_lopt, *rvinterf_wopt; + +launch_rvinterf() +{ + int sp[2], rc; + char *rvif_argv[11], Sarg[16], **ap; + + rc = socketpair(AF_UNIX, SOCK_STREAM, 0, sp); + if (rc < 0) { + perror("socketpair"); + exit(ERROR_UNIX); + } + sock = sp[0]; + sprintf(Sarg, "-S%d", sp[1]); + ap = rvif_argv; + *ap++ = "rvinterf"; + *ap++ = Sarg; + *ap++ = "-n"; + if (rvinterf_Bopt) { + *ap++ = "-B"; + *ap++ = rvinterf_Bopt; + } + if (rvinterf_lopt) { + *ap++ = "-l"; + *ap++ = rvinterf_lopt; + } + if (rvinterf_wopt) { + *ap++ = "-w"; + *ap++ = rvinterf_wopt; + } + *ap++ = rvinterf_ttyport; + *ap = 0; + rc = vfork(); + if (rc < 0) { + perror("vfork for launching rvinterf"); + exit(ERROR_UNIX); + } + if (!rc) { + /* we are in the child - do the exec */ + close(sp[0]); + execv(rvinterf_pathname, rvif_argv); + perror(rvinterf_pathname); + _exit(1); + } + close(sp[1]); + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/localstruct.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,17 @@ +/* + * The struct defined below captures the results of a stat (actually xlstat) + * operation on the target; it is a host (aka local) struct, with host byte + * ordering, alignment and data types. + */ + +struct stat_info { + u8 type; + u8 flags; + int inode; + u32 size; // size of data space occupied by object + u32 space; // size of physical data space occupied by object + u32 location; + u8 block; + u16 sequence; + u16 updates; +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/memcmd.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,94 @@ +/* + * User commands for reading memory regions and Calypso die ID via ETM + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "etm.h" +#include "tm3.h" +#include "limits.h" +#include "localtypes.h" +#include "exitcodes.h" + +static void +memdump_line(addr, buf, len) + u32 addr; + u_char *buf; +{ + int i, c; + + printf("%08X: ", addr); + for (i = 0; i < 16; i++) { + if (i < len) + printf("%02X ", buf[i]); + else + fputs(" ", stdout); + if (i == 7 || i == 15) + putchar(' '); + } + for (i = 0; i < len; i++) { + c = buf[i]; + if (c < ' ' || c > '~') + c = '.'; + putchar(c); + } + putchar('\n'); +} + +cmd_memdump(argc, argv) + char **argv; +{ + u_char databuf[MAX_MEMREAD_BYTES]; + u32 memaddr; + int rc, sz, off, l; + + memaddr = strtoul(argv[1], 0, 16); + sz = strtoul(argv[2], 0, 16); + rc = do_memory_read(memaddr, databuf, sz); + if (rc) + return(rc); + for (off = 0; off < sz; off += 16) { + l = sz - off; + if (l > 16) + l = 16; + memdump_line(memaddr + off, databuf + off, l); + } + return(0); +} + +cmd_omemdump(argc, argv) + char **argv; +{ + u_char databuf[TM3_MEMREAD_MAX]; + u32 memaddr; + int rc, sz, off, l; + + memaddr = strtoul(argv[1], 0, 16); + sz = strtoul(argv[2], 0, 16); + rc = do_memory_read_tm3(memaddr, databuf, sz); + if (rc) + return(rc); + for (off = 0; off < sz; off += 16) { + l = sz - off; + if (l > 16) + l = 16; + memdump_line(memaddr + off, databuf + off, l); + } + return(0); +} + +cmd_dieid() +{ + u_char buf[8]; + int rc; + + rc = do_dieid_read(buf); + if (rc) + return(rc); + printf("%02X %02X %02X %02X %02X %02X %02X %02X\n", buf[0], buf[1], + buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/memops.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,166 @@ +/* + * Functions for reading memory regions and Calypso die ID via ETM + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "etm.h" +#include "tm3.h" +#include "limits.h" +#include "localtypes.h" +#include "exitcodes.h" + +extern u_char rvi_msg[]; +extern int rvi_msg_len; + +do_memory_read(memaddr, databuf, nbytes) + u32 memaddr; + u_char *databuf; +{ + u_char cmdpkt[10]; + int rc; + + if (nbytes > MAX_MEMREAD_BYTES) { + printf("error: # of bytes to read may not exceed %d\n", + MAX_MEMREAD_BYTES); + return(ERROR_USAGE); + } + cmdpkt[1] = ETM_CORE; + cmdpkt[2] = TMCORE_OPC_MEM; + cmdpkt[3] = 0x01; + cmdpkt[4] = nbytes; + cmdpkt[5] = memaddr; + cmdpkt[6] = memaddr >> 8; + cmdpkt[7] = memaddr >> 16; + cmdpkt[8] = memaddr >> 24; + rc = etm_pkt_exch(cmdpkt, 8); + if (rc) + return(rc); + if (rvi_msg[3]) { + printf("ETM error response to mem read request: 0x%02X\n", + rvi_msg[3]); + return(ERROR_TARGET); + } + if (rvi_msg_len != nbytes + 7) { + printf("error: mem read response has wrong length\n"); + return(ERROR_TARGET); + } + if (rvi_msg[4] != TMCORE_OPC_MEM || rvi_msg[5] != 0x01) { + printf("error: mem read response has wrong opcode\n"); + return(ERROR_TARGET); + } + bcopy(rvi_msg + 6, databuf, nbytes); + return(0); +} + +do_memory_read_16(memaddr, databuf, nwords) + u32 memaddr; + u_char *databuf; +{ + u_char cmdpkt[10]; + int rc; + + if (nwords > MAX_MEMREAD_16BIT) { + printf("error: # of 16-bit words to read may not exceed %d\n", + MAX_MEMREAD_16BIT); + return(ERROR_USAGE); + } + cmdpkt[1] = ETM_CORE; + cmdpkt[2] = TMCORE_OPC_MEM; + cmdpkt[3] = 0x02; + cmdpkt[4] = nwords; + cmdpkt[5] = memaddr; + cmdpkt[6] = memaddr >> 8; + cmdpkt[7] = memaddr >> 16; + cmdpkt[8] = memaddr >> 24; + rc = etm_pkt_exch(cmdpkt, 8); + if (rc) + return(rc); + if (rvi_msg[3]) { + printf("ETM error response to mem read 16 request: 0x%02X\n", + rvi_msg[3]); + return(ERROR_TARGET); + } + if (rvi_msg_len != nwords * 2 + 7) { + printf("error: mem read 16 response has wrong length\n"); + return(ERROR_TARGET); + } + if (rvi_msg[4] != TMCORE_OPC_MEM || rvi_msg[5] != 0x02) { + printf("error: mem read 16 response has wrong opcode\n"); + return(ERROR_TARGET); + } + bcopy(rvi_msg + 6, databuf, nwords * 2); + return(0); +} + +do_memory_read_tm3(memaddr, databuf, nbytes) + u32 memaddr; + u_char *databuf; +{ + u_char cmdpkt[11]; + int rc; + + if (nbytes > TM3_MEMREAD_MAX) { + printf("error: # of bytes to read may not exceed %d\n", + TM3_MEMREAD_MAX); + return(ERROR_USAGE); + } + cmdpkt[1] = MEM_READ; + cmdpkt[2] = memaddr; + cmdpkt[3] = memaddr >> 8; + cmdpkt[4] = memaddr >> 16; + cmdpkt[5] = memaddr >> 24; + cmdpkt[6] = nbytes; + cmdpkt[7] = 0; + cmdpkt[8] = 0; + cmdpkt[9] = 0; + rc = etm_pkt_exch(cmdpkt, 9); + if (rc) + return(rc); + if (rvi_msg[3]) { + printf("TM3 error response to mem read request: 0x%02X\n", + rvi_msg[3]); + return(ERROR_TARGET); + } + if (rvi_msg_len != nbytes + 9) { + printf("error: mem read response has wrong length\n"); + return(ERROR_TARGET); + } + if (rvi_msg[4] != nbytes || rvi_msg[5] || rvi_msg[6] || rvi_msg[7]) { + printf("error: mem read response has wrong length echo\n"); + return(ERROR_TARGET); + } + bcopy(rvi_msg + 8, databuf, nbytes); + return(0); +} + +do_dieid_read(databuf) + u_char *databuf; +{ + u_char cmdpkt[4]; + int rc; + + cmdpkt[1] = ETM_CORE; + cmdpkt[2] = TMCORE_OPC_DIEID; + rc = etm_pkt_exch(cmdpkt, 2); + if (rc) + return(rc); + if (rvi_msg[3]) { + printf("ETM error response to die ID read request: 0x%02X\n", + rvi_msg[3]); + return(ERROR_TARGET); + } + if (rvi_msg_len != 14) { + printf("error: die ID read response has wrong length\n"); + return(ERROR_TARGET); + } + if (rvi_msg[4] != TMCORE_OPC_DIEID) { + printf("error: die ID read response has wrong opcode\n"); + return(ERROR_TARGET); + } + bcopy(rvi_msg + 5, databuf, 8); + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/olddump.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,55 @@ +/* + * This utility uses the old TM3 memory read command (in a synchronous manner + * using our etmsync infrastructure) to read the memory of a GSM device running + * a compatible fw version; it was written as an aid for reverse-engineering + * bootloader-locked Mot C139 fw versions. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "tm3.h" +#include "localtypes.h" +#include "exitcodes.h" + +#define CHUNK_SIZE TM3_MEMREAD_MAX + +single_op_main(argc, argv) + char **argv; +{ + u32 addr, len, chunk; + char buf[CHUNK_SIZE]; + FILE *outf; + int rc; + + if (argc != 3) { + fprintf(stderr, + "usage: fc-olddump [options] start-addr dump-length binfile\n"); + exit(ERROR_USAGE); + } + addr = strtoul(argv[0], 0, 16); + len = strtoul(argv[1], 0, 16); + outf = fopen(argv[2], "w"); + if (!outf) { + perror(argv[2]); + exit(ERROR_UNIX); + } + while (len) { + chunk = len; + if (chunk > CHUNK_SIZE) + chunk = CHUNK_SIZE; + rc = do_memory_read_tm3(addr, buf, chunk); + if (rc) + exit(rc); + fwrite(buf, 1, chunk, outf); + putchar('.'); + fflush(stdout); + addr += chunk; + len -= chunk; + } + putchar('\n'); + fclose(outf); + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/pirhackinit.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,160 @@ +/* + * This fc-pirhackinit utility is highly specific to the TCS211-on-Pirelli + * exercise. DO NOT run it against Pirelli's stock firmware, nor is it needed + * when using our full-source FreeCalypso firmware. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "etm.h" +#include "ffs.h" +#include "tmffs2.h" +#include "localtypes.h" +#include "exitcodes.h" + +extern u_char pirelli_imeisv[8]; + +write_pcm_imei() +{ + static char destfile[] = "/pcm/IMEI"; + u_char swapped[8]; + int i, d1, d2; + + printf("Writing %s\n", destfile); + for (i = 0; i < 8; i++) { + d1 = pirelli_imeisv[i] >> 4; + d2 = pirelli_imeisv[i] & 0xF; + swapped[i] = (d2 << 4) | d1; + } + return do_short_fwrite(destfile, swapped, 8); +} + +read_mem_region(memaddr, databuf, total_bytes) + u32 memaddr; + u_char *databuf; +{ + int chunk, remain, rc; + + for (remain = total_bytes; remain; remain -= chunk) { + chunk = remain; + if (chunk > MAX_MEMREAD_BYTES) + chunk = MAX_MEMREAD_BYTES; + rc = do_memory_read(memaddr, databuf, chunk); + if (rc) + return(rc); + memaddr += chunk; + databuf += chunk; + } + return(0); +} + +write_buf_to_file(pathname, data, datalen) + char *pathname; + u_char *data; +{ + int tfd, rc, chunk, remain; + + if (datalen <= max_short_file_write(pathname)) + return do_short_fwrite(pathname, data, datalen); + /* do it the long way */ + rc = fd_open(pathname, FFS_O_WRONLY | FFS_O_CREATE | FFS_O_TRUNC, &tfd); + if (rc) + return(rc); + for (remain = datalen; remain; remain -= chunk) { + chunk = remain; + if (chunk > 240) + chunk = 240; + rc = fd_write(tfd, data, chunk); + if (rc) { + fd_close(tfd); + return(rc); + } + data += chunk; + } + return fd_close(tfd); +} + +copy_calib_record(memaddr, pathname, size) + u32 memaddr; + char *pathname; + int size; +{ + u_char *buf; + int rc; + + buf = malloc(size); + if (!buf) { + perror("malloc"); + exit(ERROR_UNIX); + } + rc = read_mem_region(memaddr, buf, size); + if (rc) { + free(buf); + return(rc); + } + rc = write_buf_to_file(pathname, buf, size); + free(buf); + return(rc); +} + +static struct calmap { + u32 offset; + int size; + char *ti_equiv; +} pirelli_cal_map[] = { + {0x06E5, 36, "/sys/adccal"}, + {0x072B, 512, "/gsm/rf/tx/ramps.900"}, + {0x092C, 128, "/gsm/rf/tx/levels.900"}, + {0x09AD, 128, "/gsm/rf/tx/calchan.900"}, + {0x0A2E, 512, "/gsm/rf/tx/ramps.1800"}, + {0x0C2F, 128, "/gsm/rf/tx/levels.1800"}, + {0x0CB0, 128, "/gsm/rf/tx/calchan.1800"}, + {0x0D31, 512, "/gsm/rf/tx/ramps.1900"}, + {0x0F32, 128, "/gsm/rf/tx/levels.1900"}, + {0x0FB3, 128, "/gsm/rf/tx/calchan.1900"}, + {0x10AF, 40, "/gsm/rf/rx/calchan.900"}, + {0x10D8, 8, "/gsm/rf/rx/agcparams.900"}, + {0x10E1, 40, "/gsm/rf/rx/calchan.1800"}, + {0x110A, 8, "/gsm/rf/rx/agcparams.1800"}, + {0x1113, 40, "/gsm/rf/rx/calchan.1900"}, + {0x113C, 8, "/gsm/rf/rx/agcparams.1900"}, + {0, 0, 0} +}; + +copy_calib_data() +{ + struct calmap *tp; + int rc; + + printf("Copying calibration records to FFS\n"); + for (tp = pirelli_cal_map; tp->size; tp++) { + rc = copy_calib_record(0x027F0000 + tp->offset, tp->ti_equiv, + tp->size); + if (rc) + return(rc); + } + return(0); +} + +single_op_main() +{ + int rc; + + rc = get_pirelli_imei(); + if (rc) + return(rc); + printf("Creating TCS211 file system directories\n"); + rc = create_std_dirs(); + if (rc) + return(rc); + rc = write_pcm_imei(); + if (rc) + return(rc); + rc = copy_calib_data(); + if (rc) + return(rc); + return set_rfcap("tri900"); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/pirimei.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,44 @@ +/* + * Reading and decryption of Pirelli's factory IMEI record + */ + +#include <sys/types.h> +#include <openssl/des.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "exitcodes.h" + +u_char pirelli_imeisv[8]; + +get_pirelli_imei() +{ + DES_cblock ciphertext[2], dieid_key, decrypted[2]; + DES_key_schedule keysched; + int rc; + static char failmsg[] = + "decryption failed: no valid IMEI record or incompatible firmware\n"; + + printf("Requesting Calypso die ID\n"); + rc = do_dieid_read(dieid_key); + if (rc) + return(rc); + printf("Reading IMEI record in Pirelli's factory data block\n"); + rc = do_memory_read(0x027F0504, ciphertext, 16); + if (rc) + return(rc); + DES_set_key_unchecked(&dieid_key, &keysched); + DES_ecb_encrypt(&ciphertext[0], &decrypted[0], &keysched, DES_DECRYPT); + DES_ecb_encrypt(&ciphertext[1], &decrypted[1], &keysched, DES_DECRYPT); + if (bcmp(decrypted[1], dieid_key, 8)) { + printf(failmsg); + return(ERROR_TARGET); + } + bcopy(decrypted[0], pirelli_imeisv, 8); + printf("Factory IMEISV is %02X%02X%02X%02X-%02X%02X%02X-%02X\n", + pirelli_imeisv[0], pirelli_imeisv[1], pirelli_imeisv[2], + pirelli_imeisv[3], pirelli_imeisv[4], pirelli_imeisv[5], + pirelli_imeisv[6], pirelli_imeisv[7]); + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/pirimeimain.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,6 @@ +/* just a rather silly wrapper */ + +single_op_main() +{ + return get_pirelli_imei(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/rfcap.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,51 @@ +/* + * Setting of /gsm/com/rfcap + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "exitcodes.h" + +static struct band_table { + char *keyword; + u_char bytes[4]; +} band_table[] = { + {"dual-eu", {0x00, 0x0B, 0x41, 0x00}}, + {"dual-us", {0x00, 0x14, 0x00, 0x14}}, + {"tri900", {0x00, 0x0F, 0x41, 0x10}}, + {"tri850", {0x00, 0x16, 0x01, 0x14}}, + {"quad", {0x00, 0x1F, 0x41, 0x14}}, + {0, {0x00, 0x00, 0x00, 0x00}} +}; + +static u_char rfcap_tail[12] = {0x00, 0x00, 0x00, 0x00, + 0x50, 0x00, 0x00, 0xA5, + 0x05, 0x00, 0xC0, 0x00}; + +set_rfcap(band_config_kw) + char *band_config_kw; +{ + static char filename[] = "/gsm/com/rfcap"; + u_char bytes[16]; + struct band_table *tp; + + for (tp = band_table; tp->keyword; tp++) + if (!strcmp(tp->keyword, band_config_kw)) + break; + if (!tp->keyword) { + printf("error: band configuration \"%s\" not known\n", + band_config_kw); + return(ERROR_USAGE); + } + bcopy(tp->bytes, bytes, 4); + bcopy(rfcap_tail, bytes + 4, 12); + + printf("Writing \"%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\" into %s\n", + bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], + bytes[6], bytes[7], bytes[8], bytes[9], bytes[10], bytes[11], + bytes[12], bytes[13], bytes[14], bytes[15], filename); + return do_short_fwrite(filename, bytes, 16); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/simplemain.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,63 @@ +/* + * This module contains the main() function for simple etmsync programs + * that execute a single operation without a command dispatcher. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include "exitcodes.h" + +extern char *socket_pathname; +extern char *rvinterf_ttyport, *rvinterf_Bopt, *rvinterf_lopt, *rvinterf_wopt; + +main(argc, argv) + char **argv; +{ + extern int optind; + extern char *optarg; + int c, sopt = 0; + + while ((c = getopt(argc, argv, "B:l:p:s:w:")) != EOF) + switch (c) { + case 'B': + rvinterf_Bopt = optarg; + continue; + case 'l': + rvinterf_lopt = optarg; + continue; + case 'p': + rvinterf_ttyport = optarg; + continue; + case 's': + socket_pathname = optarg; + sopt++; + continue; + case 'w': + rvinterf_wopt = optarg; + continue; + case '?': + default: + /* error msg already printed */ + exit(ERROR_USAGE); + } + if (rvinterf_ttyport) { + if (sopt) { + fprintf(stderr, + "%s error: -p and -s options are mutually exclusive\n", + argv[0]); + exit(ERROR_USAGE); + } + launch_rvinterf(); + } else { + if (rvinterf_Bopt || rvinterf_lopt || rvinterf_wopt) { + fprintf(stderr, +"%s error: -B, -l and -w options are meaningful only when launching rvinterf\n", + argv[0]); + exit(ERROR_USAGE); + } + connect_local_socket(); + } + + return single_op_main(argc - optind, argv + optind); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/stddirs.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,39 @@ +/* + * An automated way to create the standard set of FFS directories + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "exitcodes.h" + +static char *std_dir_list[] = { + "/gsm", + "/gsm/com", + "/gsm/rf", + "/gsm/rf/rx", + "/gsm/rf/tx", + "/pcm", + "/sys", + "/mmi", + "/var", + "/var/dbg", + "/aud", + "/etc", + 0 +}; + +create_std_dirs() +{ + char **dirp; + int rc; + + for (dirp = std_dir_list; *dirp; dirp++) { + rc = do_mkdir_existok(*dirp); + if (rc) + return(rc); + } + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/etmsync/symlink.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,141 @@ +/* + * Commands for experimenting with FFS symlinks + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "etm.h" +#include "ffs.h" +#include "tmffs2.h" +#include "limits.h" +#include "ffslimits.h" +#include "localtypes.h" +#include "localstruct.h" +#include "exitcodes.h" + +extern u_char rvi_msg[]; +extern int rvi_msg_len; + +do_symlink(target, realobj) + char *target, *realobj; +{ + u_char cmdpkt[MAX_PKT_TO_TARGET], *dp; + int rc, targlen, reallen; + + reallen = strlen(realobj); + if (reallen >= TMFFS_STRING_SIZE) { + printf("error: pathname arg exceeds string length limit\n"); + return(ERROR_USAGE); + } + targlen = strlen(target); + if (3 + (reallen+2) + (targlen+2) + 1 > MAX_PKT_TO_TARGET) { + printf("error: symlink request fails to fit into packet\n"); + return(ERROR_USAGE); + } + dp = cmdpkt + 1; + *dp++ = ETM_FFS2; + *dp++ = TMFFS_SYMLINK; + *dp++ = reallen + 1; + strcpy(dp, realobj); + dp += reallen + 1; + *dp++ = targlen + 1; + strcpy(dp, target); + dp += targlen + 1; + rc = etm_pkt_exch(cmdpkt, dp - cmdpkt - 1); + if (rc) + return(rc); + if (rvi_msg_len != 5) { + printf("error: TMFFS_SYMLINK response has wrong length\n"); + return(ERROR_TARGET); + } + if (rvi_msg[3]) { + report_ffs_err("symlink", rvi_msg[3]); + return(ERROR_TARGET); + } + return(0); +} + +cmd_symlink(argc, argv) + char **argv; +{ + return do_symlink(argv[1], argv[2]); +} + +do_readlink(pathname, databuf, rdret) + char *pathname; + u_char *databuf; + int *rdret; +{ + u_char cmdpkt[MAX_PKT_TO_TARGET], *dp; + int rc, slen, sz; + + slen = strlen(pathname); + if (slen >= TMFFS_STRING_SIZE) { + printf("error: pathname arg exceeds string length limit\n"); + return(ERROR_USAGE); + } + dp = cmdpkt + 1; + *dp++ = ETM_FFS2; + *dp++ = TMFFS_READLINK; + *dp++ = slen + 1; + strcpy(dp, pathname); + dp += slen + 1; + *dp++ = 0; /* dummy 2nd buffer */ + rc = etm_pkt_exch(cmdpkt, dp - cmdpkt - 1); + if (rc) + return(rc); + if (rvi_msg[3]) { + report_ffs_err("readlink", rvi_msg[3]); + return(ERROR_TARGET); + } + if (rvi_msg_len < 6) { + *rdret = 0; + return(0); + } + sz = rvi_msg[4]; + if (rvi_msg_len != sz + 6) { + printf("error: readlink response has wrong length\n"); + return(ERROR_TARGET); + } + bcopy(rvi_msg + 5, databuf, sz); + *rdret = sz; + return(0); +} + +cmd_readlink(argc, argv) + char **argv; +{ + u_char databuf[256]; + int rc, sz, off, l; + + rc = do_readlink(argv[1], databuf, &sz); + if (rc) + return(rc); + printf("%d bytes read\n", sz); + for (off = 0; off < sz; off += 16) { + l = sz - off; + if (l > 16) + l = 16; + hexdump_line(off, databuf + off, l); + } + return(0); +} + +do_readlink_sancheck(pathname, databuf) + char *pathname; + u_char *databuf; +{ + int rc, sz; + + rc = do_readlink(pathname, databuf, &sz); + if (rc) + return(rc); + if (sz < 2 || databuf[sz-1]) { + printf("error: readlink on %s returned garbage\n", pathname); + return(ERROR_TARGET); + } + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/include/etm.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,53 @@ +/* + * This header file contains various definitions for talking to ETM. + */ + +#define ETM_USE_ID 0x001E0004 + +/* ETM Module IDs */ +enum { + ETM_TM3 = 0x00, // Use of old TM3 protocol + ETM_CORE = 0x01, + ETM_TMT = 0x02, // Pseudo module + ETM_SH = 0x03, // Pseudo module + ETM_TM3_MISC = 0x04, // Pseudo module - Target side + ETM_RF = 0x05, + ETM_IMEI = 0x06, + ETM_FFS2 = 0x07, + ETM_AUDIO = 0x08, + ETM_TPU = 0x09, // Not official part ETM + ETM_PWR = 0x0A, + ETM_BT = 0x0B, + ETM_L23 = 0x0C, + ETM_RESERVED10 = 0x0D, + ETM_RESERVED11 = 0x0E, + ETM_RESERVED12 = 0x0F, + + ETM_CUST = 0xC0, // Customize id + ETM_CUST1 = 0xC1, // Customize id + ETM_CUST2 = 0xC2, // Customize id + ETM_CUST3 = 0xC3, // Customize id + ETM_CUST4 = 0xC4, // Customize id + ETM_CUST5 = 0xC5, // Customize id + ETM_CUST6 = 0xC6, // Customize id + ETM_CUST7 = 0xC7, // Customize id + ETM_CUST8 = 0xC8, // Customize id + + ETM_TEST = 0xAA, // used for test of dll's + ETM_TASK = 0xEE, // ETM TASK in Target + + ETM_FFS1 = 0x70 +}; + +/* ETM_CORE opcodes */ +#define TMCORE_OPC_MEM 0x61 +#define TMCORE_OPC_ECHO 0x62 +#define TMCORE_OPC_RESET 0x63 +#define TMCORE_OPC_DEBUG 0x64 +#define TMCORE_OPC_VERSION 0x65 +#define TMCORE_OPC_CODEC_RD 0x66 +#define TMCORE_OPC_CODEC_WR 0x67 +#define TMCORE_OPC_DIEID 0x68 + +#define MAX_MEMREAD_BYTES 238 +#define MAX_MEMREAD_16BIT 119
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/include/ffs.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,114 @@ +/* + * A few generic FFS API definitions which apply to both TMFFS1 and TMFFS2 + */ + +enum FFS_OBJECT_TYPE { + OT_FILE = 1, + OT_DIR = 2, + OT_LINK = 3, + OT_SEGMENT = 4 +}; + +enum FFS_OBJECT_FLAGS { + OF_READONLY = 1<<4 // object cannot be modified +}; + +enum FFS_OPEN { + FFS_O_EMPTY = 0x00, // Okay? + FFS_O_CREATE = 0x01, + FFS_O_APPEND = 0x02, + FFS_O_EXCL = 0x04, + FFS_O_TRUNC = 0x08, + FFS_O_RDONLY = 0x10, + FFS_O_WRONLY = 0x20, + FFS_O_RDWR = FFS_O_RDONLY | FFS_O_WRONLY +}; + +enum FFS_SEEK { + FFS_SEEK_SET = 0, + FFS_SEEK_CUR = 1, + FFS_SEEK_END = 2 +}; + +enum FFS_QUERY { // data size, description + Q_BYTES_FREE = 1, // 4, number of free bytes in FFS + Q_BYTES_USED = 2, // 4, number of used bytes in FFS + Q_BYTES_LOST = 3, // 4, number of lost bytes in FFS + Q_BYTES_MAX = 4, // 4, number of max available bytes in FFS + Q_BYTES_FREE_RAW = 5, // 4, number of free raw bytes in FFS (used internal) + + Q_FD_BUF_SIZE = 10, // 4, size of buffer used by stream functions + + Q_TM_BUFADDR = 11, // 4, testmode buffer addr + Q_TM_BUFSIZE = 12, // 4, testmode ffs buffer size + Q_DEV_BASE = 13, // 4, FFS device base address + Q_CHUNK_SIZE_MAX = 14, // 4, max size of chunks made by non stream fkt. + + // FFS versions + Q_FFS_API_VERSION = 16, // 2, FFS API Version + Q_FFS_DRV_VERSION = 17, // 2, FFS Driver Version + Q_FFS_REVISION = 18, // 2, FFS Revision (from PRCS) + Q_FFS_FORMAT_READ = 19, // 2, FFS version as read from ffs + Q_FFS_LASTERROR = 20, // 2, FFS last error (from init) + Q_FFS_FORMAT_WRITE = 21, // 2, FFS version as written to ffs on format + Q_FFS_TM_VERSION = 22, // 2, FFS Testmode version + + // File system queries + Q_FILENAME_MAX = 24, // 2, max filename length + Q_PATH_DEPTH_MAX = 25, // 2, max path/directory nesting depth + Q_FD_MAX = 26, // 2, max numbers of simultaneous open files + + Q_OBJECTS_FREE = 32, // 2, number of objects that can be created + Q_INODES_USED = 33, // 2, number of inodes used + Q_INODES_LOST = 34, // 2, number of inodes lost + Q_OBJECTS_USED = 33, // 2, DEPRECATED: old name for Q_INODES_USED + Q_OBJECTS_LOST = 34, // 2, DEPRECATED: old name for Q_INODES_LOST + Q_OBJECTS_MAX = 35, // 2, max number of valid objects allowed + Q_INODES_MAX = 36, // 2, physical total max number of inodes + Q_INODES_HIGH = 37, // 2, watermark for when inodes will be reclaimed + Q_LOST_HIGH = 38, // 2, watermark for when data block will be reclaimed + + // Device queries + Q_DEV_MANUFACTURER = 48, // 2, flash manufacturer ID + Q_DEV_DEVICE = 49, // 2, flash device ID + Q_DEV_BLOCKS = 50, // 2, number of FFS blocks in device + Q_DEV_ATOMSIZE = 51, // 2, atomsize used by FFS for this device + Q_DEV_DRIVER = 52, // 2, flash device driver + + // All queries below here are for debug purpose only, are unsupported + // and can change at any time without notice! + + // Miscellaneous/Internal + Q_BLOCKS_FREE_MIN = 64, // 2, Number of spare blocks (0 or 1) + + Q_BLOCKS_FREE = 70, // 2, number of free blocks + + // Debug queries + Q_FS_FLAGS = 80, + Q_FS_INODES = 81, + Q_FS_ROOT = 82, + + Q_OBJECTS_TOTAL = 90, // 2, Accumulated number of valid objects + Q_TOTAL_OBJECTS = 90, // 2, DEPRECATED: old name for Q_OBJECTS_TOTAL + + Q_STATS_FIRST = 100, + Q_STATS_DRECLAIMS = 100, + Q_STATS_IRECLAIMS = 101, + Q_STATS_BRECLAIMS = 102, + Q_STATS_DATA_RECLAIMED = 103, + Q_STATS_INODES_RECLAIMED = 104, + Q_STATS_DATA_ALLOCATED = 105, + + Q_REQUEST_ID_LAST = 110, + + Q_DEBUG_FIRST = 120, + Q_DEBUG_0 = 120, + Q_DEBUG_1 = 121, + Q_DEBUG_2 = 122, + Q_DEBUG_3 = 123, + Q_DEBUG_LAST = 127, + + // individual lines of the bstat array can be returned by the following + // id plus the bstat index of the line wanted. + Q_BSTAT = -128 +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/include/ffserr.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,48 @@ +/* + * FFS error codes as returned in TMFFS2 response byte packets: + * these are positive, whereas the ones in the gsm-fw code + * are negative. + */ + +enum TMFFS_ERRORS { + TMFFS_ERR_NODEVICE = 1, /* flash device unknown */ + TMFFS_ERR_CORRUPTED = 2, /* filesystem corrupted!? */ + TMFFS_ERR_NOPREFORMAT = 3, /* ffs not preformatted */ + TMFFS_ERR_NOFORMAT = 4, /* ffs not formatted */ + TMFFS_ERR_BADFORMAT = 5, /* incompatible ffs version, re-format needed */ + TMFFS_ERR_MAGIC = 6, /* bad magic */ + TMFFS_ERR_AGAIN = 7, /* not ready, try again later */ + TMFFS_ERR_NOSYS = 8, /* function not implemented */ + TMFFS_ERR_DRIVER = 9, /* ffs device driver error */ + + TMFFS_ERR_NOSPACE = 10, /* out of data space */ + TMFFS_ERR_FSFULL = 11, /* file system full, no free inodes */ + TMFFS_ERR_BADNAME = 12, /* bad filename */ + TMFFS_ERR_NOTFOUND = 13, /* object not found */ + TMFFS_ERR_EXISTS = 14, /* object exists */ + TMFFS_ERR_ACCESS = 15, /* access permission violation */ + TMFFS_ERR_NAMETOOLONG = 16, /* filename too long */ + TMFFS_ERR_INVALID = 17, /* invalid argument */ + TMFFS_ERR_DIRNOTEMPTY = 18, /* directory not empty */ + TMFFS_ERR_NOTADIR = 19, /* object is not a directory */ + TMFFS_ERR_SPARE = 20, /* SPARE */ + TMFFS_ERR_FILETOOBIG = 21, /* file too big */ + TMFFS_ERR_NOTAFILE = 22, /* object is not a file */ + TMFFS_ERR_PATHTOODEEP = 23, /* path too deep */ + + TMFFS_ERR_NUMFD = 24, /* Max number of open files reached */ + TMFFS_ERR_BADFD = 25, /* Bad file descriptor */ + TMFFS_ERR_BADOP = 26, /* Bad operation */ + TMFFS_ERR_LOCKED = 27, /* The file is locked */ + + TMFFS_ERR_TOOBIG = 30, /* too big (tmffs buffer overflow) */ + TMFFS_ERR_MEMORY = 31, /* out of memory */ + TMFFS_ERR_MSGSEND = 32, /* message send failed */ + + /* debug errors - ??? */ + + TMFFS_ERR_SIBLINGLOOP = 40, /* directory sibling loop */ + TMFFS_ERR_NOBLOCKS = 41, /* No more blocks!? */ + TMFFS_ERR_DBR = 42, /* Data reclaim did not finish!? */ + TMFFS_ERR_RECLAIMLOOP = 43 /* Data reclaim loop */ +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/include/ffslimits.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,22 @@ +/* + * Limits on FFS filenames and pathnames + * + * The deepest pathname allowed is one of the form /1/2/3/4/5/6, where the + * last component may be a file, a directory or a symlink; if this last + * component is a directory, it has to be empty, because any child of + * that directory would violate the depth limit. + * + * The proper FFS pathname form begins with a slash (all pathnames must + * be absolute, no Unix processes in the fw means no current directories), + * has exactly one slash in each separating place (no double slashes), + * and no trailing slash except in the special case of the root directory, + * whose full pathname is "/". + * + * Each component name is [1,20] characters long; combining this limit + * with the maximum depth of 6 puts the maximum length of a properly-formed + * full pathname at 126 characters. + */ + +#define MAX_FN_COMPONENT 20 +#define MAX_NAME_DEPTH 6 +#define MAX_FULL_PATHNAME ((MAX_FN_COMPONENT+1) * MAX_NAME_DEPTH)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/include/limits.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,32 @@ +/* + * For sizing our buffers etc in the rvinterf suite, including the local + * UNIX domain socket protocol between rvinterf and fc-tmsh etc, we need + * to have some limits on the message sizes in both host->target and + * target->host directions. + * + * For the host->target direction, the choice of message size limit is + * easy: the packet Rx code in RVT on the target side also has a limit + * (quite naturally, as it needs to use a static buffer to reassemble + * incoming packets as they arrive at the UART in unpredictable interrupt- + * sized chunks), so we set our limit to match that in RVT. + */ + +#define MAX_PKT_TO_TARGET 255 + +/* + * In the other direction (target->host), there is no fixed limit + * definition easily visible in the target fw code: any fw component + * can call rvt_send_trace_cpy() or rvt_mem_alloc() followed by + * rvt_send_trace_no_cpy(), or some higher-level API that reduces to + * these functions, with a message of any size, subject only to memory + * limits, which obviously aren't as strict as a #define'd maximum + * message size. Hence in this direction we use our own arbitrary + * choice of size limit. + */ + +#define MAX_PKT_FROM_TARGET 512 + +/* + * Both limit definitions above counts all bytes between the opening and + * closing STX flags, but not DLEs inserted for binary transparency. + */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/include/localsock.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,80 @@ +/* + * This header defines and describes (through comments) the local UNIX domain + * socket interface implemented between rvinterf and its clients like fc-tmsh. + * + * The UNIX domain sockets used for this ad hoc interface are of the + * SOCK_STREAM kind, but the true nature of the communication is message-based. + * We use the same trick that is used for DNS over TCP: every message in each + * direction is preceded by a 2-byte length. This length is sent MSB first + * just like in DNS over TCP. The limit on the size of these messages + * (for sizing buffers etc) is: + */ + +#define LOCALSOCK_MAX_MSG 1024 + +/* + * Each message in the client->rvinterf direction (can be seen as command) + * begins (after the length) with an opcode byte as follows: + */ + +#define CLI2RVI_WANT_RVTRACE 0x00 +#define CLI2RVI_WANT_MUXPROTO 0x01 +#define CLI2RVI_PKT_TO_TARGET 0x02 +#define CLI2RVI_RAWBYTES_TO_TARGET 0x03 +#define CLI2RVI_RESET_PACKET_RX 0x04 +#define CLI2RVI_DROP_MUXPROTO 0x05 + +/* + * The first two commands (CLI2RVI_WANT_RVTRACE and CLI2RVI_WANT_MUXPROTO) + * are the means by which client programs inform rvinterf that they are + * interested in receiving copies of certain packets coming from the target. + * + * The CLI2RVI_WANT_RVTRACE opcode needs to be followed by a USEID mask value + * and a USEID match value, both in the network byte order, i.e., MSB first, + * for a total message length of 9 bytes. For every RV trace message received + * from the target, rvinterf will iterate through all active clients to see who + * is interested: if the received USEID ANDed with the mask equals the match + * value, the message will be forwarded to that client. + * + * The CLI2RVI_WANT_MUXPROTO opcode needs to be followed by one byte + * identifying the RVTMUX protocol of interest, i.e., the first byte of the + * packets exchanged between the host and the target, e.g., 0x12 for L1 traces + * as defined in pktmux.h, for a total message length of 2 bytes. + * + * The CLI2RVI_RESET_PACKET_RX opcode resets the "interests" previously set + * with CLI2RVI_WANT_RVTRACE and/or CLI2RVI_WANT_MUXPROTO. It is a "blanket" + * reset; the command message consists of just the opcode. The + * CLI2RVI_DROP_MUXPROTO command is more specific and undoes the effect of a + * previous CLI2RVI_WANT_MUXPROTO; it needs to be followed by one byte + * identifying the RVTMUX protocol in question, just like CLI2RVI_WANT_MUXPROTO. + * + * The last two commands (CLI2RVI_PKT_TO_TARGET and CLI2RVI_RAWBYTES_TO_TARGET) + * cause data payload to be sent to the target serial port. Payload following + * CLI2RVI_PKT_TO_TARGET (must not exceed MAX_PKT_TO_TARGET) is sent with the + * proper packet encapsulation per TI; bytes following + * CLI2RVI_RAWBYTES_TO_TARGET are sent raw. + */ + +/* + * Each message in the rvinterf->client direction begins (after the length) + * with a message type byte as follows: + */ + +#define RVI2CLI_PKT_FROM_TARGET 0x00 +#define RVI2CLI_LOCAL_CMD_RESP 0x01 + +/* + * Messages beginning with RVI2CLI_PKT_FROM_TARGET are packets received + * from the target GSM device; the byte following this type code is the + * first byte of the packet from the target, e.g., 0x11 for RV traces or + * 0x12 for L1 traces. Rvinterf will only start sending these messages + * to a client after that client has expressed interest in receiving + * target->host packets of a particular type. + * + * Messages beginning with RVI2CLI_LOCAL_CMD_RESP are generated locally + * by rvinterf itself as responses to commands, currently as responses to + * CLI2RVI_WANT_{RVTRACE,MUXPROTO}. The byte following the + * RVT2CLI_LOCAL_CMD_RESP type code is ASCII '+' or ASCII '-', indicating + * success or error, respectively. Any remaining bytes form a message + * for the user. + */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/include/localtypes.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,7 @@ +/* + * Our own definition of u8/u16/u32 + */ + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/include/pktmux.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,20 @@ +/* + * Definitions for the RVT MUX over-the-wire protocol + */ + +#define STX 0x02 +#define DLE 0x10 + +#define RVT_RV_HEADER 0x11 +#define RVT_L1_HEADER 0x12 +#define RVT_L23_HEADER 0x13 +#define RVT_TM_HEADER 0x14 +#define RVT_RNET_HEADER 0x15 +#define RVT_PROF_HEADER 0x16 +#define RVT_GTTBACK_HEADER 0x17 +#define RVT_OTHER_HEADER 0x18 +/* FreeCalypso additions */ +#define RVT_AT_HEADER 0x1A +#define RVT_EXTUI_HEADER 0x1B +#define RVT_TCH_HEADER 0x1C +#define RVT_KEEPALIVE_HEADER 0x1D
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/include/tch_feature.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,12 @@ +/* + * This header file contains definitions for the + * custom voice TCH rerouting feature that + * has been implemented as an experiment in the + * FreeCalypso GSM firmware. + */ + +#define TCH_CONFIG_REQ 0x11 +#define TCH_CONFIG_CONF 0x12 +#define TCH_ULBITS_REQ 0x13 +#define TCH_ULBITS_CONF 0x14 +#define TCH_DLBITS_IND 0x15
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/include/tm3.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,47 @@ +/* + * This header file contains various definitions for talking to the old + * non-enhanced Test Mode firmware component. + */ + +/* CID opcodes */ +enum +{ + TM_INIT = 0x20, + TM_MODE_SET = 0x21, + VERSION_GET = 0x22, + RF_ENABLE = 0x23, + STATS_READ = 0x24, + STATS_CONFIG_WRITE = 0x25, + STATS_CONFIG_READ = 0x26, + RF_PARAM_WRITE = 0x30, + RF_PARAM_READ = 0x31, + RF_TABLE_WRITE = 0x32, + RF_TABLE_READ = 0x33, + RX_PARAM_WRITE = 0x34, + RX_PARAM_READ = 0x35, + TX_PARAM_WRITE = 0x36, + TX_PARAM_READ = 0x37, + TX_TEMPLATE_WRITE = 0x38, + TX_TEMPLATE_READ = 0x39, + MEM_WRITE = 0x40, + MEM_READ = 0x41, + CODEC_WRITE = 0x42, + CODEC_READ = 0x43, + MISC_PARAM_WRITE = 0x44, + MISC_PARAM_READ = 0x45, + MISC_TABLE_WRITE = 0x46, + MISC_TABLE_READ = 0x47, + MISC_ENABLE = 0x48, + SPECIAL_PARAM_WRITE = 0x50, + SPECIAL_PARAM_READ = 0x51, + SPECIAL_TABLE_WRITE = 0x52, + SPECIAL_TABLE_READ = 0x53, + SPECIAL_ENABLE = 0x54, + + TPU_TABLE_WRITE = 0x55, + TPU_TABLE_READ = 0x56, + + TM_FFS = 0x70 +}; + +#define TM3_MEMREAD_MAX 0x7C
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/include/tmffs1.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,58 @@ +/****************************************************************************** + * FFS1 Protocol Indentifiers + ******************************************************************************/ + +enum FFS1_PROTOCOL_IDENTIFIERS { + FPI_END = 0, /* end */ + FPI_BEGIN, /* begin */ + FPI_TMFFS_VERSION, /* tmffs_version */ + + FPI_PREFORMAT, /* preformat */ + FPI_FORMAT, /* format */ + + FPI_FCREATE, /* fcreate */ + FPI_FUPDATE, /* fupdate */ + FPI_FWRITE, /* fwrite */ + FPI_FREAD, /* fread */ + FPI_REMOVE, /* remove */ + + FPI_MKDIR, /* mkdir */ + FPI_OPENDIR, /* opendir */ + FPI_READDIR, /* readdir */ + + FPI_STAT, /* stat */ + FPI_LINKSTAT, /* linkstat */ + + FPI_SYMLINK, /* symlink */ + FPI_READLINK, /* readlink */ + + FPI_QUERY, /* query */ + FPI_FCONTROL, /* fcontrol */ + + FPI_INIT, /* init */ + FPI_EXIT, /* exit */ + + FPI_PCM_GETFILEINFO, /* getfileinfo */ + FPI_PCM_READFILE, /* readfile */ + FPI_PCM_WRITEFILE, /* writefile */ + FPI_PCM_READRECORD, /* readrecord */ + FPI_PCM_WRITERECORD, /* writerecord */ + + FPI_BUFREAD, /* buf_read */ + FPI_BUFWRITE, /* buf_write */ + FPI_BUFSET, /* buf_set */ + + FPI_UINT8, /* UINT8 */ + FPI_UINT16, /* UINT16 */ + FPI_UINT32, /* UINT32 */ + FPI_INT8, /* INT8 */ + FPI_INT16, /* INT16 */ + FPI_INT32, /* INT32 */ + FPI_BUFFER, /* BUFFER */ + FPI_DATA, /* DATA */ + FPI_STRBUF, /* STRBUF */ + FPI_STRING, /* STRING */ + + FPI_TFFS /* TFFS */ + +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/include/tmffs2.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,49 @@ +/****************************************************************************** + * FFS2 Protocol Indentifiers + ******************************************************************************/ + +enum FFS2_PROTOCOL_IDENTIFIERS { + TMFFS_FORMAT = 'f', + TMFFS_PREFORMAT = 'p', + + TMFFS_MKDIR = 'm', + TMFFS_OPENDIR = 'o', + TMFFS_READDIR = 'D', + TMFFS_REMOVE = 'd', + TMFFS_RENAME = 'n', + TMFFS_XLSTAT = 'x', + + TMFFS_SYMLINK = 'y', + TMFFS_READLINK = 'Y', + + TMFFS_OPEN = 'O', + TMFFS_CLOSE = 'C', + TMFFS_READ = 'R', + TMFFS_WRITE = 'W', + TMFFS_SEEK = 'S', + + TMFFS_FTRUNCATE = 'T', + TMFFS_TRUNCATE = 't', + + TMFFS_FILE_READ = 'r', + TMFFS_FILE_WRITE = 'w', + + TMFFS_FSTAT = 'F', + TMFFS_LSTAT = 'l', + TMFFS_STAT = 's', + + TMFFS_FCONTROL = 'c', + TMFFS_QUERY = 'q', + + TMFFS_INIT = 'i', + TMFFS_EXIT = 'e', + + // Special + TMFFS_DIRXLSTAT = 'X', + + TMFFS_VERSION = 'v', + TMFFS_TFFS = 'z' +}; + +#define TMFFS_STRING_SIZE 127 /* includes the terminating NUL */ +#define MAX_READ_DATA 254
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/libasync/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,13 @@ +CC= gcc +CFLAGS= -O2 -I../include +OBJS= init.o interf.o launchrvif.o rvtrace.o ttymagic.o +LIB= libasync.a + +all: ${LIB} + +${LIB}: ${OBJS} + ar rcu $@ ${OBJS} + ranlib $@ + +clean: + rm -f *.[oa] errs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/libasync/README Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,3 @@ +This host side library contains common modules for tools like fc-tmsh and +g23sh which operate asynchronously. This code has been factored out of +fc-tmsh.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/libasync/init.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,66 @@ +/* + * This module contains the common initialization code for fc-tmsh and g23sh. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <unistd.h> +#include "pktmux.h" +#include "localsock.h" + +extern char *socket_pathname; +extern int sock; + +connect_local_socket() +{ + /* local socket binding voodoo copied from osmocon */ + struct sockaddr_un local; + unsigned int namelen; + int rc; + + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) { + perror("socket(AF_UNIX, SOCK_STREAM, 0)"); + exit(1); + } + + local.sun_family = AF_UNIX; + strncpy(local.sun_path, socket_pathname, sizeof(local.sun_path)); + local.sun_path[sizeof(local.sun_path) - 1] = '\0'; + + /* we use the same magic that X11 uses in Xtranssock.c for + * calculating the proper length of the sockaddr */ +#if defined(BSD44SOCKETS) || defined(__UNIXWARE__) + local.sun_len = strlen(local.sun_path); +#endif +#if defined(BSD44SOCKETS) || defined(SUN_LEN) + namelen = SUN_LEN(&local); +#else + namelen = strlen(local.sun_path) + + offsetof(struct sockaddr_un, sun_path) + 1; +#endif + + rc = connect(sock, (struct sockaddr *) &local, namelen); + if (rc != 0) { + perror(socket_pathname); + exit(1); + } + + return(0); +} + +send_init_command(cmdpkt, cmdlen) + u_char *cmdpkt; +{ + u_char lenbuf[2]; + + lenbuf[0] = 0; + lenbuf[1] = cmdlen; + write(sock, lenbuf, 2); + write(sock, cmdpkt, cmdlen); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/libasync/interf.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,106 @@ +/* + * This module implements the link to rvinterf. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include "localsock.h" + +extern int sock; + +u_char rvi_msg[LOCALSOCK_MAX_MSG]; +int rvi_msg_len; + +static int rx_state, rx_left; +static u_char *rx_ptr; + +void +localsock_prep_for_length_rx() +{ + rx_state = 0; + rx_ptr = rvi_msg; + rx_left = 2; +} + +static void +prep_for_message_rx() +{ + rx_state = 1; + rx_ptr = rvi_msg; + rx_left = rvi_msg_len; +} + +void +process_msg_from_rvinterf() +{ + switch (rvi_msg[0]) { + case RVI2CLI_PKT_FROM_TARGET: + process_pkt_from_target(); + return; + case RVI2CLI_LOCAL_CMD_RESP: + if (rvi_msg_len < 2) + goto bad; + if (rvi_msg[1] == '+') + return; + tty_cleanup(); + fprintf(stderr, "Error from rvinterf: %.*s\n", rvi_msg_len - 1, + rvi_msg + 1); + exit(1); + default: + bad: + tty_cleanup(); + fprintf(stderr, + "Error: unexpected message type %02X from rvinterf\n", + rvi_msg[0]); + exit(1); + } +} + +void +handle_rvinterf_input() +{ + int cc; + + cc = read(sock, rx_ptr, rx_left); + if (cc <= 0) { + tty_cleanup(); + perror("read from rvinterf socket"); + exit(1); + } + rx_ptr += cc; + rx_left -= cc; + if (rx_left) + return; + /* got the thing, process it */ + if (rx_state) { + process_msg_from_rvinterf(); + localsock_prep_for_length_rx(); + } else { + rvi_msg_len = rvi_msg[0] << 8 | rvi_msg[1]; + if (rvi_msg_len < 1 || rvi_msg_len > LOCALSOCK_MAX_MSG) { + tty_cleanup(); + fprintf(stderr, + "Invalid length from rvinterf: %02X%02X\n", + rvi_msg[0], rvi_msg[1]); + exit(1); + } + prep_for_message_rx(); + } +} + +void +send_pkt_to_target(pkt, pktlen) + u_char *pkt; +{ + u_char hdrbuf[3]; + int len1; + + len1 = pktlen + 1; + hdrbuf[0] = len1 >> 8; + hdrbuf[1] = len1 & 0xFF; + hdrbuf[2] = CLI2RVI_PKT_TO_TARGET; + write(sock, hdrbuf, 3); + write(sock, pkt, pktlen); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/libasync/launchrvif.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,63 @@ +/* + * This module implements the optional "behind the scenes" invokation + * of rvinterf from fc-tmsh. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +static char rvinterf_pathname[] = "/usr/local/bin/rvinterf"; + +extern int sock; + +char *rvinterf_Bopt, *rvinterf_lopt, *rvinterf_wopt; + +launch_rvinterf(ttyport) + char *ttyport; +{ + int sp[2], rc; + char *rvif_argv[11], Sarg[16], **ap; + + rc = socketpair(AF_UNIX, SOCK_STREAM, 0, sp); + if (rc < 0) { + perror("socketpair"); + exit(1); + } + sock = sp[0]; + sprintf(Sarg, "-S%d", sp[1]); + ap = rvif_argv; + *ap++ = "rvinterf"; + *ap++ = Sarg; + *ap++ = "-n"; + if (rvinterf_Bopt) { + *ap++ = "-B"; + *ap++ = rvinterf_Bopt; + } + if (rvinterf_lopt) { + *ap++ = "-l"; + *ap++ = rvinterf_lopt; + } + if (rvinterf_wopt) { + *ap++ = "-w"; + *ap++ = rvinterf_wopt; + } + *ap++ = ttyport; + *ap = 0; + rc = vfork(); + if (rc < 0) { + perror("vfork for launching rvinterf"); + exit(1); + } + if (!rc) { + /* we are in the child - do the exec */ + close(sp[0]); + execv(rvinterf_pathname, rvif_argv); + perror(rvinterf_pathname); + _exit(1); + } + close(sp[1]); + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/libasync/rvtrace.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,54 @@ +/* + * Here we detect and handle "Lost Message" packets. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "pktmux.h" +#include "limits.h" +#include "localsock.h" + +extern u_char rvi_msg[]; +extern int rvi_msg_len; + +void +safe_print_trace(src, srclen, dest) + u_char *src; + char *dest; +{ + int i, c; + char *dp; + + dp = dest; + for (i = 0; i < srclen; i++) { + c = src[i]; + if (c & 0x80) { + *dp++ = 'M'; + *dp++ = '-'; + c &= 0x7F; + } + if (c < 0x20) { + *dp++ = '^'; + *dp++ = c + '@'; + } else if (c == 0x7F) { + *dp++ = '^'; + *dp++ = '?'; + } else + *dp++ = c; + } + *dp = '\0'; +} + +void +handle_useid_0() +{ + char buf[MAX_PKT_FROM_TARGET*4]; + + if (strncmp(rvi_msg + 7, "RVT: Lost Message", 17)) + return; + safe_print_trace(rvi_msg + 7, rvi_msg_len - 7, buf); + async_msg_output(buf); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/libasync/ttymagic.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,112 @@ +/* + * This module contains the tty "magic" code for fc-tmsh. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <unistd.h> +#include <termios.h> + +extern int ttyhacks; + +struct termios orig_termios, our_termios; + +#define MAX_USER_CMD 78 +char usercmd[MAX_USER_CMD+1]; +int usercmd_len; + +void +tty_init() +{ + if (!ttyhacks) + return; + tcgetattr(0, &orig_termios); + bcopy(&orig_termios, &our_termios, sizeof(struct termios)); + our_termios.c_oflag &= ~(OCRNL | ONOCR | ONLRET); + our_termios.c_lflag &= ~(ICANON | ECHO); + our_termios.c_cc[VMIN] = 1; + our_termios.c_cc[VTIME] = 0; + tcsetattr(0, TCSAFLUSH, &our_termios); + putchar('>'); + fflush(stdout); +} + +void +tty_cleanup() +{ + if (!ttyhacks) + return; + tcsetattr(0, TCSAFLUSH, &orig_termios); +} + +void +handle_tty_input() +{ + char buf[256]; + int i, c, cc; + + cc = read(0, buf, sizeof buf); + if (cc <= 0) { + tty_cleanup(); + exit(0); + } + for (i = 0; i < cc; i++) { + c = buf[i]; + if (c >= ' ' && c <= '~') { + if (usercmd_len >= MAX_USER_CMD) + continue; + usercmd[usercmd_len++] = c; + if (ttyhacks) + putchar(c); /* echo */ + continue; + } + switch (c) { + case '\b': + case 0x7F: + if (!usercmd_len) + continue; + usercmd_len--; + if (ttyhacks) { + putchar('\b'); + putchar(' '); + putchar('\b'); + } + continue; + case '\n': + case '\r': + usercmd[usercmd_len] = '\0'; + if (ttyhacks) + putchar('\n'); /* echo */ + dispatch_user_cmd(); + usercmd_len = 0; + if (ttyhacks) + putchar('>'); /* new prompt */ + } + } +} + +void +async_msg_output(msg) + char *msg; +{ + int msglen, i; + + msglen = strlen(msg); + if (ttyhacks) + putchar('\r'); + fputs(msg, stdout); + if (ttyhacks) + for (i = msglen; i < usercmd_len + 1; i++) + putchar(' '); + putchar('\n'); + if (!ttyhacks) + return; + /* reprint the input line */ + putchar('>'); + if (!usercmd_len) + return; + fwrite(usercmd, 1, usercmd_len, stdout); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/libg23/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,13 @@ +CC= gcc +CFLAGS= -O2 +OBJS= fmtdispatch.o fmtfunc.o +LIB= libg23.a + +all: ${LIB} + +${LIB}: ${OBJS} + ar rcu $@ ${OBJS} + ranlib $@ + +clean: + rm -f *.[oa] errs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/libg23/README Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,11 @@ +The library built in this directory is a host side library, not for the target. +This library implements some functions for handling packet exchanges with GPF, +and it will be linked by some of the programs in the rvinterf suite. + +It needs to be noted that the RVTMUX channel belonging to GPF was named +RVT_L23_HEADER by TI, and as a result, I thought that these packets related +specifically to the higher layers of the protocol stack. But now we know that +hierarchically speaking, GPF sits *below* L1, not above, and GPF packets should +not be automatically associated with G23. This realization was made fairly +late, thus "g23" appears in a bunch of function names, and in the name of this +library.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/libg23/fmtdispatch.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,144 @@ +/* + * This libg23 module exports the format_g23_packet() function, which + * validates the packet, then dispatches it to format_g23_trace(), + * format_g23_sysprim() or format_g23_psprim() as appropriate, or + * prints it in raw hex if malformed. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> + +static int +basic_checks(rxpkt, rxpkt_len) + u_char *rxpkt; +{ + int i, c; + + if (rxpkt_len < 17) + return(0); + /* check version bits in the header byte */ + if ((rxpkt[1] & 0xC0) != 0x80) + return(0); + /* check the length */ + c = rxpkt[2] | rxpkt[3] << 8; + if (c + 4 != rxpkt_len) + return(0); + /* ensure that the "from" and "to" are printable ASCII */ + for (i = 8; i < 16; i++) { + c = rxpkt[i]; + if (c < ' ' || c > '~') + return(0); + } + /* basic checks pass */ + return(1); +} + +static int +psprim_extra_checks(rxpkt, rxpkt_len) + u_char *rxpkt; +{ + int i, c; + + if (rxpkt_len < 24) + return(0); + /* "original rcvr" field needs to be printable ASCII */ + for (i = 16; i < 20; i++) { + c = rxpkt[i]; + if (c < ' ' || c > '~') + return(0); + } + /* checks pass */ + return(1); +} + +static void +print_unknown_bin(rxpkt, rxpkt_len, outbuf) + u_char *rxpkt; + char *outbuf; +{ + int i; + char *dp; + + dp = outbuf; + strcpy(dp, "GPF UNK:"); + dp += 8; + for (i = 1; i < rxpkt_len; i++) { + sprintf(dp, " %02X", rxpkt[i]); + dp += 3; + } + *dp = '\0'; +} + +static void +print_old_ascii(rxpkt, rxpkt_len, outbuf) + u_char *rxpkt; + char *outbuf; +{ + char *dp; + int txtlen = rxpkt_len - 1; + + dp = outbuf; + strcpy(dp, "GPF ASC: "); + dp += 9; + bcopy(rxpkt + 1, dp, txtlen); + dp += txtlen; + *dp = '\0'; +} + +static int +is_old_ascii(rxpkt, rxpkt_len) + u_char *rxpkt; +{ + int i, c; + + for (i = 1; i < rxpkt_len; i++) { + c = rxpkt[i]; + if (c < ' ' || c > '~') + return(0); + } + return(1); +} + +static void +print_malformed(rxpkt, rxpkt_len, outbuf) + u_char *rxpkt; + char *outbuf; +{ + if (is_old_ascii(rxpkt, rxpkt_len)) + print_old_ascii(rxpkt, rxpkt_len, outbuf); + else + print_unknown_bin(rxpkt, rxpkt_len, outbuf); +} + +void +format_g23_packet(rxpkt, rxpkt_len, outbuf) + u_char *rxpkt; + char *outbuf; +{ + if (!basic_checks(rxpkt, rxpkt_len)) { + print_malformed(rxpkt, rxpkt_len, outbuf); + return; + } + /* dispatch by type */ + switch (rxpkt[1] & 0x30) { + case 0x10: + /* PS primitive */ + if (psprim_extra_checks(rxpkt, rxpkt_len)) + format_g23_psprim(rxpkt, rxpkt_len, outbuf); + else + print_malformed(rxpkt, rxpkt_len, outbuf); + return; + case 0x20: + /* trace */ + format_g23_trace(rxpkt, rxpkt_len, outbuf); + return; + case 0x30: + /* system primitive */ + format_g23_sysprim(rxpkt, rxpkt_len, outbuf); + return; + default: + print_malformed(rxpkt, rxpkt_len, outbuf); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/libg23/fmtfunc.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,167 @@ +/* + * This libg23 module exports functions for formatting 3 different kinds + * of GPF packets into human-readable form: traces, system primitives + * and protocol stack primitives. + * + * GPF packets passed to these functions for decoding MUST have already + * been verified to be well-formed for their respective type. + */ + +#include <sys/types.h> +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> + +static int +entity_name_well_formed(p) + char *p; +{ + int i, len; + + if (!isupper(p[0])) + return(0); + for (i = 0; i < 4; i++) + if (!isalnum(p[i])) + break; + len = i; + for (; i < 4; i++) + if (p[i] != ' ') + return(0); + return(len); +} + +static void +print_entity_name(raw, outp) + char *raw, **outp; +{ + int len; + + len = entity_name_well_formed(raw); + if (len) { + sprintf(*outp, "%.*s", len, raw); + *outp += len; + } else { + sprintf(*outp, "\"%.4s\"", raw); + *outp += 6; + } +} + +static void +print_common_hdr(rxpkt, outp, typestr) + u_char *rxpkt; + char **outp, *typestr; +{ + sprintf(*outp, "GPF %s id=%02X ts=%02X%02X%02X%02X ", typestr, + rxpkt[1], rxpkt[7], rxpkt[6], rxpkt[5], rxpkt[4]); + *outp = index(*outp, '\0'); + print_entity_name(rxpkt + 8, outp); + *(*outp)++ = '-'; + *(*outp)++ = '>'; + print_entity_name(rxpkt + 12, outp); + *(*outp)++ = ' '; +} + +static void +format_text(rxpkt, rxpkt_len, start_off, outp) + u_char *rxpkt; + char *outp; +{ + int i, c; + + *outp++ = '\"'; + for (i = start_off; i < rxpkt_len; i++) { + c = rxpkt[i]; + if (c & 0x80) { + *outp++ = 'M'; + *outp++ = '-'; + c &= 0x7F; + } + if (c < 0x20) { + *outp++ = '^'; + *outp++ = c + '@'; + } else if (c == 0x7F) { + *outp++ = '^'; + *outp++ = '?'; + } else + *outp++ = c; + } + *outp++ = '\"'; + *outp = '\0'; +} + +static void +format_compressed_trace(rxpkt, rxpkt_len, start_off, outp) + u_char *rxpkt; + char *outp; +{ + int i; + + i = start_off + 1; + sprintf(outp, "%d", rxpkt[i+1] << 8 | rxpkt[i]); + outp = index(outp, '\0'); + i += 4; + for (; i < rxpkt_len; i++) { + sprintf(outp, " %02X", rxpkt[i]); + outp += 3; + } + *outp = '\0'; +} + +void +format_g23_trace(rxpkt, rxpkt_len, outbuf) + u_char *rxpkt; + char *outbuf; +{ + char *outp = outbuf; + int i; + + print_common_hdr(rxpkt, &outp, "trace"); + i = 16; + if (rxpkt[i] < 0x20) { + sprintf(outp, "tc=%02X ", rxpkt[i]); + outp += 6; + i++; + } + if (rxpkt_len - i >= 5 && rxpkt[i] == '%' && + !rxpkt[i+3] && !rxpkt[i+4]) + format_compressed_trace(rxpkt, rxpkt_len, i, outp); + else + format_text(rxpkt, rxpkt_len, i, outp); +} + +void +format_g23_sysprim(rxpkt, rxpkt_len, outbuf) + u_char *rxpkt; + char *outbuf; +{ + char *outp = outbuf; + int i; + + print_common_hdr(rxpkt, &outp, "sysprim"); + format_text(rxpkt, rxpkt_len, 16, outp); +} + +void +format_g23_psprim(rxpkt, rxpkt_len, outbuf) + u_char *rxpkt; + char *outbuf; +{ + char *outp = outbuf; + int i; + + print_common_hdr(rxpkt, &outp, "PSprim"); + /* original destination */ + *outp++ = '('; + print_entity_name(rxpkt + 16, &outp); + *outp++ = ')'; + /* opcode */ + sprintf(outp, " %02X%02X%02X%02X", + rxpkt[23], rxpkt[22], rxpkt[21], rxpkt[20]); + outp += 9; + for (i = 24; i < rxpkt_len; i++) { + sprintf(outp, " %02X", rxpkt[i]); + outp += 3; + } + *outp = '\0'; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/lowlevel/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,31 @@ +CC= gcc +CFLAGS= -O2 +PROGS= rvtdump rvinterf tfc139 +INSTBIN=/usr/local/bin +LIBG23= ../libg23/libg23.a + +RVTDUMP_OBJS= format.o format_fc.o openport.o output.o packetrx.o rvtdump.o + +RVINTERF_OBJS= clientcmd.o format.o format_fc.o localsock.o logsent.o \ + openport.o output.o packetrx.o packettx.o pktfwd.o rviflcd.o \ + rvifmain.o + +TFC139_OBJS= format.o openport.o output.o packetrx.o packettx.o tfc139.o + +all: ${PROGS} + +rvtdump: ${RVTDUMP_OBJS} ${LIBG23} + ${CC} ${CFLAGS} -o $@ ${RVTDUMP_OBJS} ${LIBG23} + +rvinterf: ${RVINTERF_OBJS} ${LIBG23} + ${CC} ${CFLAGS} -o $@ ${RVINTERF_OBJS} ${LIBG23} + +tfc139: ${TFC139_OBJS} ${LIBG23} + ${CC} ${CFLAGS} -o $@ ${TFC139_OBJS} ${LIBG23} + +install: ${PROGS} + mkdir -p ${INSTBIN} + install -c ${PROGS} ${INSTBIN} + +clean: + rm -f *.o *.out *errs ${PROGS}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/lowlevel/client.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,22 @@ +/* + * The structure defined in this header file is malloced in rvinterf + * for every client program connection. + */ + +#define MAX_RVT_INTEREST 4 + +typedef unsigned u32; + +struct client { + struct client *next; + int fd; + int rx_state; + u_char rx_buf[LOCALSOCK_MAX_MSG]; + int rx_msglen; + u_char *rx_ptr; + int rx_left; + int int_rvt_count; + u32 int_rvt_mask[MAX_RVT_INTEREST]; + u32 int_rvt_match[MAX_RVT_INTEREST]; + char int_proto[12]; +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/lowlevel/clientcmd.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,89 @@ +/* + * This rvinterf module implements the handling of client commands. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <unistd.h> +#include "../include/pktmux.h" +#include "../include/limits.h" +#include "../include/localsock.h" +#include "client.h" + +void +process_msg_from_client(cli) + struct client *cli; +{ + int c; + + switch (cli->rx_buf[0]) { + case CLI2RVI_WANT_RVTRACE: + if (cli->rx_msglen != 9) { + send_local_msg_to_client(cli, "-Bad command length"); + return; + } + c = cli->int_rvt_count; + if (c >= MAX_RVT_INTEREST) { + send_local_msg_to_client(cli, + "-Error: too many RVT interests"); + return; + } + cli->int_rvt_mask[c] = cli->rx_buf[1] << 24 | + cli->rx_buf[2] << 16 | + cli->rx_buf[3] << 8 | cli->rx_buf[4]; + cli->int_rvt_match[c] = cli->rx_buf[5] << 24 | + cli->rx_buf[6] << 16 | + cli->rx_buf[7] << 8 | cli->rx_buf[8]; + cli->int_rvt_count++; + send_local_msg_to_client(cli, "+OK"); + return; + case CLI2RVI_WANT_MUXPROTO: + if (cli->rx_msglen != 2) { + send_local_msg_to_client(cli, "-Bad command length"); + return; + } + if (cli->rx_buf[1] < 0x12 || cli->rx_buf[1] > 0x1D) { + send_local_msg_to_client(cli, + "-Unsupported protocol MUX value"); + return; + } + cli->int_proto[cli->rx_buf[1] - 0x12] = 1; + send_local_msg_to_client(cli, "+OK"); + return; + case CLI2RVI_DROP_MUXPROTO: + if (cli->rx_msglen != 2) { + send_local_msg_to_client(cli, "-Bad command length"); + return; + } + if (cli->rx_buf[1] < 0x12 || cli->rx_buf[1] > 0x1D) { + send_local_msg_to_client(cli, + "-Unsupported protocol MUX value"); + return; + } + cli->int_proto[cli->rx_buf[1] - 0x12] = 0; + send_local_msg_to_client(cli, "+OK"); + return; + case CLI2RVI_RESET_PACKET_RX: + cli->int_rvt_count = 0; + bzero(cli->int_proto, sizeof(cli->int_proto)); + send_local_msg_to_client(cli, "+OK"); + return; + case CLI2RVI_PKT_TO_TARGET: + c = cli->rx_msglen - 1; + if (c < 1 || c > MAX_PKT_TO_TARGET) { + send_local_msg_to_client(cli, + "-Invalid Tx packet length"); + return; + } + send_pkt_to_target(cli->rx_buf + 1, c); + log_sent_packet(cli->rx_buf + 1, c); + return; + case CLI2RVI_RAWBYTES_TO_TARGET: + /* To be implemented */ + default: + send_local_msg_to_client(cli, "-Unimplemented command"); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/lowlevel/format.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,138 @@ +/* + * This module implements the decoding of Rx packets + * into human-readable form. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include "../include/pktmux.h" +#include "../include/limits.h" + +extern u_char rxpkt[]; +extern size_t rxpkt_len; + +static char fmtbuf[MAX_PKT_FROM_TARGET*8]; /* size it generously */ + +void +print_rv_trace() +{ + int i, c; + char *dp; + + dp = fmtbuf; + strcpy(dp, "RV "); + dp += 3; + /* the SWE static ID is sent MSB first */ + for (i = 1; i <= 4; i++) { + sprintf(dp, "%02X", rxpkt[i]); + dp += 2; + } + /* severity level */ + sprintf(dp, " %d ", rxpkt[5]); + dp = index(dp, '\0'); + for (i = 6; i < rxpkt_len; i++) { + c = rxpkt[i]; + if (c & 0x80) { + *dp++ = 'M'; + *dp++ = '-'; + c &= 0x7F; + } + if (c < 0x20) { + *dp++ = '^'; + *dp++ = c + '@'; + } else if (c == 0x7F) { + *dp++ = '^'; + *dp++ = '?'; + } else + *dp++ = c; + } + *dp = '\0'; + output_line(fmtbuf); +} + +void +print_l1_trace() +{ + int i, c; + char *dp; + + dp = fmtbuf; + strcpy(dp, "L1: "); + dp += 4; + for (i = 1; i < rxpkt_len; i++) { + if ((i+1 < rxpkt_len) && + (rxpkt[i] == '\r' && rxpkt[i+1] == '\n' || + rxpkt[i] == '\n' && rxpkt[i+1] == '\r')) { + *dp = '\0'; + output_line(fmtbuf); + if (i+2 == rxpkt_len) + return; + dp = fmtbuf; + *dp++ = '+'; + *dp++ = ' '; + i++; + continue; + } + c = rxpkt[i]; + if (c & 0x80) { + *dp++ = 'M'; + *dp++ = '-'; + c &= 0x7F; + } + if (c < 0x20) { + *dp++ = '^'; + *dp++ = c + '@'; + } else if (c == 0x7F) { + *dp++ = '^'; + *dp++ = '?'; + } else + *dp++ = c; + } + /* will get here only if no newline sequence at the end */ + *dp = '\0'; + output_line(fmtbuf); +} + +void +print_g23_trace() +{ + /* messy logic factored out into libg23 */ + format_g23_packet(rxpkt, (int)rxpkt_len, fmtbuf); + output_line(fmtbuf); +} + +void +print_tm_output_raw() +{ + int i; + char *dp; + + dp = fmtbuf; + strcpy(dp, "TM:"); + dp += 3; + for (i = 1; i < rxpkt_len; i++) { + sprintf(dp, " %02X", rxpkt[i]); + dp += 3; + } + *dp = '\0'; + output_line(fmtbuf); +} + +void +print_unknown_packet() +{ + int i; + char *dp; + + dp = fmtbuf; + strcpy(dp, "UNK:"); + dp += 4; + for (i = 0; i < rxpkt_len; i++) { + sprintf(dp, " %02X", rxpkt[i]); + dp += 3; + } + *dp = '\0'; + output_line(fmtbuf); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/lowlevel/format_fc.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,99 @@ +/* + * This module has been split off from format.c; it implements the decoding + * of those Rx packet types which have been invented in FreeCalypso. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include "../include/pktmux.h" +#include "../include/limits.h" + +extern u_char rxpkt[]; +extern size_t rxpkt_len; + +static char fmtbuf[MAX_PKT_FROM_TARGET*8]; /* size it generously */ + +void +print_ati_output() +{ + int i, c; + char *dp; + + dp = fmtbuf; + strcpy(dp, "ATI: "); + dp += 5; + for (i = 1; i < rxpkt_len; i++) { + c = rxpkt[i]; + if (c & 0x80) { + *dp++ = 'M'; + *dp++ = '-'; + c &= 0x7F; + } + if (c < 0x20) { + *dp++ = '^'; + *dp++ = c + '@'; + } else if (c == 0x7F) { + *dp++ = '^'; + *dp++ = '?'; + } else + *dp++ = c; + } + *dp = '\0'; + output_line(fmtbuf); +} + +void +print_fc_lld_msg() +{ + int i, c; + char *dp; + + dp = fmtbuf; + strcpy(dp, "LLD: "); + dp += 5; + for (i = 1; i < rxpkt_len; i++) { + c = rxpkt[i]; + if (c & 0x80) { + *dp++ = 'M'; + *dp++ = '-'; + c &= 0x7F; + } + if (c < 0x20) { + *dp++ = '^'; + *dp++ = c + '@'; + } else if (c == 0x7F) { + *dp++ = '^'; + *dp++ = '?'; + } else + *dp++ = c; + } + *dp = '\0'; + output_line(fmtbuf); +} + +void +print_tch_output_raw() +{ + int i; + char *dp; + + dp = fmtbuf; + strcpy(dp, "TCH:"); + dp += 4; + for (i = 1; i < rxpkt_len; i++) { + sprintf(dp, " %02X", rxpkt[i]); + dp += 3; + } + *dp = '\0'; + output_line(fmtbuf); +} + +void +report_extui_packet() +{ + sprintf(fmtbuf, "LCD OUT: row %u col %u-%u", rxpkt[1], rxpkt[2], + rxpkt[2] + (rxpkt_len - 3) / 2 - 1); + output_line(fmtbuf); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/lowlevel/localsock.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,180 @@ +/* + * This rvinterf module handles the local UNIX domain socket interface + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <unistd.h> +#include "../include/localsock.h" +#include "client.h" + +int listener; + +extern struct client *client_head; +extern int max_fd; +extern char *socket_pathname; +extern int socketpair_fd; + +create_listener_socket() +{ + /* local socket binding voodoo copied from osmocon */ + struct sockaddr_un local; + unsigned int namelen; + int rc; + + listener = socket(AF_UNIX, SOCK_STREAM, 0); + if (listener < 0) { + perror("socket(AF_UNIX, SOCK_STREAM, 0)"); + exit(1); + } + + local.sun_family = AF_UNIX; + strncpy(local.sun_path, socket_pathname, sizeof(local.sun_path)); + local.sun_path[sizeof(local.sun_path) - 1] = '\0'; + unlink(local.sun_path); + + /* we use the same magic that X11 uses in Xtranssock.c for + * calculating the proper length of the sockaddr */ +#if defined(BSD44SOCKETS) || defined(__UNIXWARE__) + local.sun_len = strlen(local.sun_path); +#endif +#if defined(BSD44SOCKETS) || defined(SUN_LEN) + namelen = SUN_LEN(&local); +#else + namelen = strlen(local.sun_path) + + offsetof(struct sockaddr_un, sun_path) + 1; +#endif + + rc = bind(listener, (struct sockaddr *) &local, namelen); + if (rc != 0) { + perror("bind on local socket"); + exit(1); + } + rc = listen(listener, 3); + if (rc != 0) { + perror("listen"); + exit(1); + } + + if (listener > max_fd) + max_fd = listener; + return(0); +} + +static void +prep_for_length_rx(cli) + struct client *cli; +{ + cli->rx_state = 0; + cli->rx_ptr = cli->rx_buf; + cli->rx_left = 2; +} + +static void +prep_for_message_rx(cli) + struct client *cli; +{ + cli->rx_state = 1; + cli->rx_ptr = cli->rx_buf; + cli->rx_left = cli->rx_msglen; +} + +handle_listener_select() +{ + struct sockaddr_un un_addr; + socklen_t len; + int rc; + struct client *newcli; + + len = sizeof(un_addr); + rc = accept(listener, (struct sockaddr *) &un_addr, &len); + if (rc < 0) { + perror("rvinterf: accept"); + exit(1); + } + if (rc > max_fd) + max_fd = rc; + newcli = malloc(sizeof(struct client)); + if (!newcli) { + perror("rvinterf: malloc for new client"); + exit(1); + } + bzero(newcli, sizeof(struct client)); + newcli->fd = rc; + newcli->next = client_head; + client_head = newcli; + prep_for_length_rx(newcli); + output_line("*** Client program connected"); + return(0); +} + +create_socketpair_client() +{ + struct client *cli; + + if (socketpair_fd > max_fd) + max_fd = socketpair_fd; + cli = malloc(sizeof(struct client)); + if (!cli) { + perror("rvinterf: malloc for socketpair client"); + exit(1); + } + bzero(cli, sizeof(struct client)); + cli->fd = socketpair_fd; + client_head = cli; + prep_for_length_rx(cli); + return(0); +} + +send_local_msg_to_client(cli, msg) + struct client *cli; + char *msg; +{ + int len, len1; + u_char hdr[3]; + + len = strlen(msg); + len1 = len + 1; + hdr[0] = len1 >> 8; + hdr[1] = len1 & 0xFF; + hdr[2] = RVI2CLI_LOCAL_CMD_RESP; + write(cli->fd, hdr, 3); + write(cli->fd, msg, len); +} + +void +handle_client_select(cli) + struct client *cli; +{ + int cc; + + cc = read(cli->fd, cli->rx_ptr, cli->rx_left); + if (cc <= 0) { + /* normal client exit condition */ + output_line("*** Client program disconnected"); +close_socket: cli->rx_state = 2; + return; + } + cli->rx_ptr += cc; + cli->rx_left -= cc; + if (cli->rx_left) + return; + /* got the thing, process it */ + if (cli->rx_state) { + prep_for_length_rx(cli); + process_msg_from_client(cli); + } else { + cli->rx_msglen = cli->rx_buf[0] << 8 | cli->rx_buf[1]; + if (cli->rx_msglen < 1 || cli->rx_msglen > LOCALSOCK_MAX_MSG) { + send_local_msg_to_client(cli, + "-Invalid length, closing socket"); + goto close_socket; + } + prep_for_message_rx(cli); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/lowlevel/logsent.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,85 @@ +/* + * This module implements the logging of sent packets + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include "../include/pktmux.h" +#include "../include/limits.h" + +static void +log_sent_ati(pkt, pktlen) + u_char *pkt; +{ + char buf[MAX_PKT_TO_TARGET*4+10]; + int i, c; + char *dp; + + strcpy(buf, "Sent to ATI: "); + dp = buf + 13; + for (i = 1; i < pktlen; i++) { + c = pkt[i]; + if (c & 0x80) { + *dp++ = 'M'; + *dp++ = '-'; + c &= 0x7F; + } + if (c < 0x20) { + *dp++ = '^'; + *dp++ = c + '@'; + } else if (c == 0x7F) { + *dp++ = '^'; + *dp++ = '?'; + } else + *dp++ = c; + } + *dp = '\0'; + output_line(buf); +} + +static void +log_sent_gpf(pkt, pktlen) + u_char *pkt; +{ + char buf[MAX_PKT_TO_TARGET*4+30]; + + strcpy(buf, "Sent "); + format_g23_packet(pkt, pktlen, buf + 5); + output_line(buf); +} + +static void +log_sent_other(pkt, pktlen) + u_char *pkt; +{ + char buf[MAX_PKT_TO_TARGET*3+5]; + int i; + char *dp; + + dp = buf; + strcpy(dp, "Sent"); + dp += 4; + for (i = 0; i < pktlen; i++) { + sprintf(dp, " %02X", pkt[i]); + dp += 3; + } + *dp = '\0'; + output_line(buf); +} + +log_sent_packet(pkt, pktlen) + u_char *pkt; +{ + switch (pkt[0]) { + case RVT_L23_HEADER: + log_sent_gpf(pkt, pktlen); + return; + case RVT_AT_HEADER: + log_sent_ati(pkt, pktlen); + return; + default: + log_sent_other(pkt, pktlen); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/lowlevel/openport.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,82 @@ +/* + * This module takes care of opening the serial port and setting the + * proper "raw" termios modes, including the baud rate. + */ + +#include <sys/types.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <termios.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> + +int target_fd; +char *baudrate_name = "115200"; + +static struct baudrate { + char *name; + speed_t termios_code; +} baud_rate_table[] = { + {"19200", B19200}, + {"38400", B38400}, + {"57600", B57600}, + {"115200", B115200}, + /* non-standard high baud rates "remapped" by CP2102 usb2serial IC */ + {"203125", B230400}, + {"406250", B460800}, + {"812500", B921600}, + /* table search terminator */ + {NULL, B0} +}; + +static speed_t +get_baud_rate() +{ + struct baudrate *br; + + for (br = baud_rate_table; br->name; br++) + if (!strcmp(br->name, baudrate_name)) + break; + if (!br->name) { + fprintf(stderr, "baud rate \"%s\" unknown/unsupported\n", + baudrate_name); + exit(1); + } + return br->termios_code; +} + +open_target_serial(ttydev) + char *ttydev; +{ + struct termios target_termios; + speed_t br_code; + + br_code = get_baud_rate(); + target_fd = open(ttydev, O_RDWR|O_NONBLOCK); + if (target_fd < 0) { + perror(ttydev); + exit(1); + } + target_termios.c_iflag = IGNBRK; + target_termios.c_oflag = 0; + target_termios.c_cflag = CLOCAL|HUPCL|CREAD|CS8; + target_termios.c_lflag = 0; + target_termios.c_cc[VMIN] = 1; + target_termios.c_cc[VTIME] = 0; + cfsetispeed(&target_termios, br_code); + cfsetospeed(&target_termios, br_code); + if (tcsetattr(target_fd, TCSAFLUSH, &target_termios) < 0) { + perror("initial tcsetattr on target"); + exit(1); + } + return 0; +} + +set_serial_nonblock(state) + int state; +{ + ioctl(target_fd, FIONBIO, &state); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/lowlevel/output.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,38 @@ +/* + * This module implements the output/logging function + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <unistd.h> +#include <time.h> + +extern int no_output; +extern FILE *logF; +extern time_t logtime; + +static struct tm last_tm; + +void +output_line(item) + char *item; +{ + struct tm *curtm; + + if (!no_output) + printf("%s\n", item); + if (!logF) + return; + curtm = gmtime(&logtime); + if (curtm->tm_year != last_tm.tm_year || + curtm->tm_mon != last_tm.tm_mon || + curtm->tm_mday != last_tm.tm_mday) + fprintf(logF, "%d-%02d-%02d (gmtime):\n", curtm->tm_year + 1900, + curtm->tm_mon+1, curtm->tm_mday); + fprintf(logF, "[%02d:%02d:%02d] %s\n", curtm->tm_hour, curtm->tm_min, + curtm->tm_sec, item); + bcopy(curtm, &last_tm, sizeof(struct tm)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/lowlevel/packetrx.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,87 @@ +/* + * This module handles the lowest level of serial packet Rx + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include "../include/pktmux.h" +#include "../include/limits.h" + +extern int target_fd; + +u_char rxpkt[MAX_PKT_FROM_TARGET]; +size_t rxpkt_len; + +static int in_pkt, dle_state, toobig; + +static void +process_inbyte(inb) +{ + char errbuf[128]; + + if (!in_pkt) { + if (inb != STX || dle_state) { + rxpkt_len++; + dle_state = (inb == DLE); + return; + } + if (rxpkt_len) { + sprintf(errbuf, + "Warning: Rx %u byte%s outside of a packet", + (unsigned)rxpkt_len, rxpkt_len != 1 ? "s" : ""); + output_line(errbuf); + rxpkt_len = 0; + } + in_pkt = 1; + toobig = 0; + return; + } + if (dle_state) { + dle_state = 0; + if (inb != STX && inb != DLE) { + sprintf(errbuf, + "Rx framing error: %02X after DLE", inb); + output_line(errbuf); + in_pkt = 0; + rxpkt_len = 0; + return; + } + goto data; + } + if (inb == DLE) { + dle_state = 1; + return; + } else if (inb == STX) { + if (!rxpkt_len) + return; + in_pkt = 0; + handle_rx_packet(); + rxpkt_len = 0; + return; + } +data: if (rxpkt_len >= MAX_PKT_FROM_TARGET) { + if (!toobig) { + output_line("Error: Rx packet too big!"); + toobig = 1; + } + return; + } + rxpkt[rxpkt_len++] = inb; +} + +void +process_serial_rx() +{ + u_char rdbuf[512]; + int cc, i; + + cc = read(target_fd, rdbuf, sizeof rdbuf); + if (cc <= 0) { + perror("Error/EOF reading from target"); + exit(1); + } + for (i = 0; i < cc; i++) + process_inbyte(rdbuf[i]); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/lowlevel/packettx.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,49 @@ +/* + * This module handles the lowest level of serial packet Tx + */ + +#include <sys/types.h> +#include <sys/time.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <unistd.h> +#include "../include/pktmux.h" +#include "../include/limits.h" + +extern int target_fd; +extern int wakeup_after_sec; + +static u_char wakeup_shot[64]; +static struct timeval last_tx; + +send_pkt_to_target(pkt, pktlen) + u_char *pkt; +{ + u_char buf[MAX_PKT_TO_TARGET*2+2]; + u_char *cp, *dp, *endp; + int c; + struct timeval curtime, timediff; + + gettimeofday(&curtime, 0); + if (wakeup_after_sec) { + timersub(&curtime, &last_tx, &timediff); + if (timediff.tv_sec >= wakeup_after_sec) { + write(target_fd, wakeup_shot, sizeof wakeup_shot); + usleep(100000); + } + } + endp = pkt + pktlen; + dp = buf; + *dp++ = STX; + for (cp = pkt; cp < endp; cp++) { + c = *cp; + if (c == STX || c == DLE) + *dp++ = DLE; + *dp++ = c; + } + *dp++ = STX; + write(target_fd, buf, dp - buf); + bcopy(&curtime, &last_tx, sizeof(struct timeval)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/lowlevel/pktfwd.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,62 @@ +/* + * This rvinterf module handles the forwarding of target->host packets + * to clients connected via the local socket interface. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <unistd.h> +#include "../include/pktmux.h" +#include "../include/localsock.h" +#include "client.h" + +extern u_char rxpkt[]; +extern size_t rxpkt_len; + +extern struct client *client_head; + +forward_pkt_to_client(cli) + struct client *cli; +{ + int len1; + u_char hdr[3]; + + len1 = rxpkt_len + 1; + hdr[0] = len1 >> 8; + hdr[1] = len1 & 0xFF; + hdr[2] = RVI2CLI_PKT_FROM_TARGET; + write(cli->fd, hdr, 3); + write(cli->fd, rxpkt, rxpkt_len); +} + +forward_rv_trace() +{ + u32 useid; + struct client *cli; + int i, match; + + useid = rxpkt[1] << 24 | rxpkt[2] << 16 | rxpkt[3] << 8 | rxpkt[4]; + for (cli = client_head; cli; cli = cli->next) { + match = 0; + for (i = 0; i < cli->int_rvt_count; i++) + if ((useid & cli->int_rvt_mask[i]) == + cli->int_rvt_match[i]) { + match = 1; + break; + } + if (match) + forward_pkt_to_client(cli); + } +} + +forward_nonrvt_pkt() +{ + struct client *cli; + + for (cli = client_head; cli; cli = cli->next) + if (cli->int_proto[rxpkt[0] - 0x12]) + forward_pkt_to_client(cli); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/lowlevel/rviflcd.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,40 @@ +/* + * This rvinterf module implements the piping of LCD output to fc-lcdemu + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <unistd.h> + +extern u_char rxpkt[]; +extern size_t rxpkt_len; + +char *extlcd_program; +FILE *extlcd_pout; +u_char extlcd_invert; + +void +open_extlcd_pipe() +{ + extlcd_pout = popen(extlcd_program, "w"); + if (!extlcd_pout) { + perror(extlcd_program); + exit(1); + } +} + +void +output_to_extlcd() +{ + int i; + + fprintf(extlcd_pout, "%u %u ", rxpkt[1], rxpkt[2]); + for (i = 3; i < rxpkt_len; i += 2) + fprintf(extlcd_pout, "%02X%02X", rxpkt[i+1] ^ extlcd_invert, + rxpkt[i] ^ extlcd_invert); + fputc('\n', extlcd_pout); + fflush(extlcd_pout); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/lowlevel/rvifmain.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,213 @@ +/* + * This module contains the main() function for rvinterf + */ + +#include <sys/types.h> +#include <sys/errno.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <time.h> +#include "../include/pktmux.h" +#include "../include/localsock.h" +#include "client.h" + +extern int target_fd, listener; +extern char *baudrate_name; +extern char *extlcd_program; +extern u_char extlcd_invert; + +extern u_char rxpkt[]; +extern size_t rxpkt_len; + +struct client *client_head; +int socketpair_fd; + +char *logfname; +FILE *logF; +time_t logtime; +int background, no_output; +int max_fd; + +char *socket_pathname = "/tmp/rvinterf_socket"; + +int wakeup_after_sec = 7; + +main(argc, argv) + char **argv; +{ + extern char *optarg; + extern int optind; + int c; + fd_set fds; + struct client *cli, **clip; + + while ((c = getopt(argc, argv, "bB:d:l:ns:S:vw:X:")) != EOF) + switch (c) { + case 'b': + background++; + /* FALL THRU */ + case 'n': + no_output++; + continue; + case 'B': + baudrate_name = optarg; + continue; + case 'd': + target_fd = atoi(optarg); + continue; + case 'l': + logfname = optarg; + continue; + case 's': + socket_pathname = optarg; + continue; + case 'S': + socketpair_fd = atoi(optarg); + continue; + case 'v': + extlcd_invert = 0xFF; + continue; + case 'w': + wakeup_after_sec = strtoul(optarg, 0, 0); + continue; + case 'X': + extlcd_program = optarg; + continue; + case '?': + default: +usage: fprintf(stderr, + "usage: %s [options] ttyport\n", argv[0]); + exit(1); + } + if (target_fd <= 0) { + if (argc - optind != 1) + goto usage; + open_target_serial(argv[optind]); + } + max_fd = target_fd; + if (extlcd_program) + open_extlcd_pipe(); + + set_serial_nonblock(0); + setlinebuf(stdout); + if (logfname) { + logF = fopen(logfname, "w"); + if (!logF) { + perror(logfname); + exit(1); + } + setlinebuf(logF); + fprintf(logF, "*** Log of rvinterf session ***\n"); + } + if (socketpair_fd) + create_socketpair_client(); + else + create_listener_socket(); + if (background) { + c = fork(); + if (c < 0) { + perror("fork"); + exit(1); + } + if (c) { + printf("rvinterf forked into background (pid %d)\n", c); + exit(0); + } + } + signal(SIGPIPE, SIG_IGN); + for (;;) { + FD_ZERO(&fds); + FD_SET(target_fd, &fds); + if (listener) + FD_SET(listener, &fds); + for (clip = &client_head; cli = *clip; ) { + if (cli->rx_state == 2) { + close(cli->fd); + *clip = cli->next; + free(cli); + continue; + } + FD_SET(cli->fd, &fds); + clip = &cli->next; + } + if (socketpair_fd && !client_head) + exit(0); + c = select(max_fd+1, &fds, 0, 0, 0); + time(&logtime); + if (c < 0) { + if (errno == EINTR) + continue; + perror("select"); + exit(1); + } + if (FD_ISSET(target_fd, &fds)) + process_serial_rx(); + if (listener && FD_ISSET(listener, &fds)) + handle_listener_select(); + for (cli = client_head; cli; cli = cli->next) + if (FD_ISSET(cli->fd, &fds)) + handle_client_select(cli); + } +} + +handle_rx_packet() +{ + switch (rxpkt[0]) { + case RVT_RV_HEADER: + if (rxpkt_len < 6) + goto unknown; + if (!no_output || logF) + print_rv_trace(); + if (client_head) + forward_rv_trace(); + return; + case RVT_L1_HEADER: + if (!no_output || logF) + print_l1_trace(); + if (client_head) + forward_nonrvt_pkt(); + return; + case RVT_L23_HEADER: + if (!no_output || logF) + print_g23_trace(); + if (client_head) + forward_nonrvt_pkt(); + return; + case RVT_TM_HEADER: + if (!no_output || logF) + print_tm_output_raw(); + if (client_head) + forward_nonrvt_pkt(); + return; + case RVT_AT_HEADER: + if (!no_output || logF) + print_ati_output(); + if (client_head) + forward_nonrvt_pkt(); + return; + case RVT_EXTUI_HEADER: + if (rxpkt_len < 5 || !(rxpkt_len & 1)) + goto unknown; + if (extlcd_program) + output_to_extlcd(); + else + report_extui_packet(); + return; + case RVT_TCH_HEADER: + if (!no_output || logF) + print_tch_output_raw(); + if (client_head) + forward_nonrvt_pkt(); + return; + case '*': + print_fc_lld_msg(); + return; + default: + unknown: + print_unknown_packet(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/lowlevel/rvtdump.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,138 @@ +/* + * This program reads bytes from a serial port, parses them assuming + * TI's RVT MUX format, and prints every decoded packet. + */ + +#include <sys/types.h> +#include <sys/errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <time.h> +#include "../include/pktmux.h" + +extern int target_fd; +extern char *baudrate_name; + +extern u_char rxpkt[]; +extern size_t rxpkt_len; + +char *logfname; +FILE *logF; +time_t logtime; +int background; +int no_output; /* for output.c */ + +main(argc, argv) + char **argv; +{ + extern char *optarg; + extern int optind; + int c; + fd_set fds; + + while ((c = getopt(argc, argv, "bB:d:l:")) != EOF) + switch (c) { + case 'b': + background++; + no_output++; /* for output.c */ + continue; + case 'B': + baudrate_name = optarg; + continue; + case 'd': + target_fd = atoi(optarg); + continue; + case 'l': + logfname = optarg; + continue; + case '?': + default: +usage: fprintf(stderr, + "usage: %s [options] ttyport\n", argv[0]); + exit(1); + } + if (background && !logfname) { + fprintf(stderr, "%s: -b is meaningless without -l\n", argv[0]); + exit(1); + } + if (target_fd <= 0) { + if (argc - optind != 1) + goto usage; + open_target_serial(argv[optind]); + } + + set_serial_nonblock(0); + setlinebuf(stdout); + if (logfname) { + logF = fopen(logfname, "w"); + if (!logF) { + perror(logfname); + exit(1); + } + setlinebuf(logF); + fprintf(logF, "*** Log of decoded RVT output ***\n"); + } + if (background) { + c = fork(); + if (c < 0) { + perror("fork"); + exit(1); + } + if (c) { + printf("rvtdump forked into background (pid %d)\n", c); + exit(0); + } + } + for (;;) { + FD_ZERO(&fds); + FD_SET(target_fd, &fds); + c = select(target_fd+1, &fds, 0, 0, 0); + time(&logtime); + if (c < 0) { + if (errno == EINTR) + continue; + perror("select"); + exit(1); + } + if (FD_ISSET(target_fd, &fds)) + process_serial_rx(); + } +} + +handle_rx_packet() +{ + switch (rxpkt[0]) { + case RVT_RV_HEADER: + if (rxpkt_len < 6) + goto unknown; + print_rv_trace(); + return; + case RVT_L1_HEADER: + print_l1_trace(); + return; + case RVT_L23_HEADER: + print_g23_trace(); + return; + case RVT_TM_HEADER: + print_tm_output_raw(); + return; + case RVT_AT_HEADER: + print_ati_output(); + return; + case RVT_EXTUI_HEADER: + if (rxpkt_len < 5 || !(rxpkt_len & 1)) + goto unknown; + report_extui_packet(); + return; + case RVT_TCH_HEADER: + print_tch_output_raw(); + return; + case '*': + print_fc_lld_msg(); + return; + default: + unknown: + print_unknown_packet(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/lowlevel/tfc139.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,311 @@ +/* + * This program facilitates the recovery of those Compal/Motorola phones + * whose bootloaders have been maliciously locked down. It connects + * to a running Mot C1xx firmware through the RVTMUX interface provided + * by the latter and uses the Test Mode memory write command (which + * these firmwares implement just like TI's reference fw) to inject + * some shellcode and to transfer control to it by overwriting a + * function return address on the stack. The injected shellcode then + * enables the Calypso boot ROM and jumps to it, allowing fc-loadtool + * to take over from there. + */ + +#include <sys/types.h> +#include <sys/errno.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <unistd.h> +#include <time.h> +#include "../include/pktmux.h" +#include "../include/limits.h" + +extern int target_fd; +extern char *baudrate_name; + +extern u_char rxpkt[]; +extern size_t rxpkt_len; + +char *logfname; +FILE *logF; +time_t logtime; +int no_output; /* for output.c */ + +int wakeup_after_sec = 1; + +/* see ../../target-utils/tf-breakin/payload.S for the source */ +static u_char shellcode[114] = { + 0x78, 0x47, 0xC0, 0x46, 0xD3, 0xF0, 0x21, 0xE3, + 0x50, 0x10, 0x9F, 0xE5, 0xF5, 0x00, 0xA0, 0xE3, + 0xB2, 0x00, 0xC1, 0xE1, 0xA0, 0x00, 0xA0, 0xE3, + 0xB2, 0x00, 0xC1, 0xE1, 0x40, 0x60, 0x9F, 0xE5, + 0x05, 0x00, 0xD6, 0xE5, 0x20, 0x00, 0x10, 0xE3, + 0xFC, 0xFF, 0xFF, 0x0A, 0x38, 0x10, 0x8F, 0xE2, + 0x06, 0x20, 0xA0, 0xE3, 0x01, 0x00, 0xD1, 0xE4, + 0x00, 0x00, 0xC6, 0xE5, 0x01, 0x20, 0x52, 0xE2, + 0xFB, 0xFF, 0xFF, 0x1A, 0x05, 0x00, 0xD6, 0xE5, + 0x40, 0x00, 0x10, 0xE3, 0xFC, 0xFF, 0xFF, 0x0A, + 0x10, 0x10, 0x9F, 0xE5, 0x01, 0x2C, 0xA0, 0xE3, + 0xB0, 0x20, 0xC1, 0xE1, 0x00, 0xF0, 0xA0, 0xE3, + 0x02, 0xF8, 0xFF, 0xFF, 0x00, 0x58, 0xFF, 0xFF, + 0x10, 0xFB, 0xFF, 0xFF, 0x02, 0x02, 0x02, 0x4F, + 0x4B, 0x02 +}; + +static unsigned shellcode_load_addr; +static unsigned stack_smash_addr; +static int thumb_entry = 1; + +static u_char stack_smash_payload[4]; +static int breakin_in_progress; + +static char *target_tty_port; + +static void +send_compal_memwrite(addr, payload, payload_len) + unsigned addr; + u_char *payload; +{ + u_char pkt[MAX_PKT_TO_TARGET]; + int i, csum, csum_offset; + + pkt[0] = RVT_TM_HEADER; + pkt[1] = 0x40; /* old TM3 MEM_WRITE command */ + pkt[2] = addr; + pkt[3] = addr >> 8; + pkt[4] = addr >> 16; + pkt[5] = addr >> 24; + bcopy(payload, pkt + 6, payload_len); + csum_offset = payload_len + 6; + csum = 0; + for (i = 1; i < csum_offset; i++) + csum ^= pkt[i]; + pkt[i] = csum; + send_pkt_to_target(pkt, i + 1); +} + +static void +initiate_breakin() +{ + char msgbuf[80]; + unsigned jump_addr; + + sprintf(msgbuf, + "Using shellcode load addr 0x%x, stack smash starting addr 0x%x", + shellcode_load_addr, stack_smash_addr); + output_line(msgbuf); + jump_addr = shellcode_load_addr; + if (thumb_entry) + jump_addr += 1; + else + jump_addr += 4; + stack_smash_payload[0] = jump_addr; + stack_smash_payload[1] = jump_addr >> 8; + stack_smash_payload[2] = jump_addr >> 16; + stack_smash_payload[3] = jump_addr >> 24; + output_line("Sending shellcode RAM write"); + send_compal_memwrite(shellcode_load_addr, shellcode, sizeof shellcode); + breakin_in_progress = 1; +} + +static void +send_memcheck_query() +{ + u_char sendpkt[25]; + + output_line("Sending GPF MEMCHECK query"); + /* fill out the packet */ + sendpkt[0] = RVT_L23_HEADER; + sendpkt[1] = 0xB7; /* system prim */ + sendpkt[2] = 20; + sendpkt[3] = 0; + /* send zeros for the timestamp */ + sendpkt[4] = 0; + sendpkt[5] = 0; + sendpkt[6] = 0; + sendpkt[7] = 0; + /* fixed string with all fields */ + strcpy(sendpkt + 8, "PCO L1 MEMCHECK"); + /* send it! */ + send_pkt_to_target(sendpkt, 24); +} + +main(argc, argv) + char **argv; +{ + extern char *optarg; + extern int optind; + int c; + fd_set fds; + + baudrate_name = "57600"; /* what C139 firmware uses */ + while ((c = getopt(argc, argv, "a:AB:l:ms:w:")) != EOF) + switch (c) { + case 'a': + shellcode_load_addr = strtoul(optarg, 0, 16); + continue; + case 'B': + baudrate_name = optarg; + continue; + case 'l': + logfname = optarg; + continue; + case 'm': + /* mimic mot931c.exe */ + shellcode_load_addr = 0x800000; + stack_smash_addr = 0x837C54; + /* FALL THRU */ + case 'A': + thumb_entry = 0; + continue; + case 's': + stack_smash_addr = strtoul(optarg, 0, 16); + continue; + case 'w': + wakeup_after_sec = strtoul(optarg, 0, 0); + continue; + case '?': + default: +usage: fprintf(stderr, + "usage: %s [options] ttyport\n", argv[0]); + exit(1); + } + if (argc - optind != 1) + goto usage; + if (stack_smash_addr && !shellcode_load_addr) { + fprintf(stderr, "usage error: -a option required with -s\n"); + exit(1); + } + open_target_serial(argv[optind]); + target_tty_port = argv[optind]; + + set_serial_nonblock(0); + setlinebuf(stdout); + if (logfname) { + logF = fopen(logfname, "w"); + if (!logF) { + perror(logfname); + exit(1); + } + setlinebuf(logF); + fprintf(logF, "*** Log of TFC139 break-in session ***\n"); + } + time(&logtime); + if (stack_smash_addr) + initiate_breakin(); + else + send_memcheck_query(); + for (;;) { + FD_ZERO(&fds); + FD_SET(target_fd, &fds); + c = select(target_fd+1, &fds, 0, 0, 0); + time(&logtime); + if (c < 0) { + if (errno == EINTR) + continue; + perror("select"); + exit(1); + } + if (FD_ISSET(target_fd, &fds)) + process_serial_rx(); + } +} + +static void +handle_tm_response() +{ + char msgbuf[80]; + + if (!breakin_in_progress) { + output_line("TM response unexpected at this time"); + return; + } + if (rxpkt_len != 4 || rxpkt[1] != 0x40 || rxpkt[2] || rxpkt[3] != 0x40){ + output_line("TM response differs from expected"); + return; + } + sprintf(msgbuf, "Sending stack smash write at 0x%x", stack_smash_addr); + output_line(msgbuf); + send_compal_memwrite(stack_smash_addr, stack_smash_payload, 4); + stack_smash_addr += 4; +} + +static void +analyze_gpf_packet() +{ + unsigned stackbase, untouched; + static char format[] = + "Name:L1 Stat:%*s Count:%*s Prio:%*s Stack:%x Size:%*s Untouched:%u"; + char msgbuf[80]; + + if (rxpkt_len < 17 || rxpkt_len > 128) + return; + /* it needs to be a trace packet */ + if ((rxpkt[1] & 0xF0) != 0xA0) + return; + /* check the length */ + if (rxpkt[2] + 4 != rxpkt_len) + return; + if (rxpkt[3]) + return; + /* skip timestamp, check src and dest */ + if (strncmp(rxpkt + 8, "SYSTPCO ", 8)) + return; + /* terminating NUL for sscanf */ + rxpkt[rxpkt_len] = '\0'; + if (sscanf(rxpkt + 16, format, &stackbase, &untouched) != 2) + return; + /* success! */ + sprintf(msgbuf, + "Parsed L1 stack location: base=0x%x, untouched=%u (0x%x)", + stackbase, untouched, untouched); + output_line(msgbuf); + if (stackbase & 3) { + output_line("Error: stack base address is not word-aligned"); + exit(1); + } + untouched &= ~3; + if (!shellcode_load_addr) { + if (untouched < sizeof shellcode) { + output_line("Error: not enough room for shellcode"); + exit(1); + } + shellcode_load_addr = stackbase; + } + stack_smash_addr = stackbase + untouched; + initiate_breakin(); +} + +handle_rx_packet() +{ + if (rxpkt_len == 2 && rxpkt[0] == 'O' && rxpkt[1] == 'K') { + output_line( + "Success: target should now be in boot ROM download wait"); + printf("You can now run fc-loadtool -h compal -c none %s\n", + target_tty_port); + exit(0); + } + switch (rxpkt[0]) { + case RVT_RV_HEADER: + if (rxpkt_len < 6) + goto unknown; + print_rv_trace(); + return; + case RVT_L1_HEADER: + print_l1_trace(); + return; + case RVT_L23_HEADER: + print_g23_trace(); + if (!breakin_in_progress) + analyze_gpf_packet(); + return; + case RVT_TM_HEADER: + print_tm_output_raw(); + handle_tm_response(); + return; + default: + unknown: + print_unknown_packet(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/old/before-rvinterf/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,23 @@ +CC= gcc +CFLAGS= -O2 +PROGS= rvtdump +XPROGS= etmsend +INSTBIN=/usr/local/bin + +RVTDUMP_OBJS= log.o openport.o packetrx.o packettx.o rvtdump.o rvtdump_tx.o \ + trdump.o + +all: ${PROGS} ${XPROGS} + +rvtdump: ${RVTDUMP_OBJS} + ${CC} ${CFLAGS} -o $@ ${RVTDUMP_OBJS} + +etmsend: etmsend.c + ${CC} ${CFLAGS} -o $@ $@.c + +install: ${PROGS} + mkdir -p ${INSTBIN} + install -c ${PROGS} ${INSTBIN} + +clean: + rm -f *.o *.out *errs ${PROGS} ${XPROGS}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/old/before-rvinterf/etmsend.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,79 @@ +/* + * This program is a hack that sends a hand-crafted ETM packet + * to the UNIX-local dgram socket established by rvtdump with -s option. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <unistd.h> +#include "pktmux.h" +#include "txpkt.h" + +char sockpath[] = "/tmp/rvt_send_socket"; + +u_char packet[MAX_PKT_TO_TARGET]; +int payload_len; + +main(argc, argv) + char **argv; +{ + int i, c, s; + struct sockaddr_un local; + unsigned int namelen; + + if (argc < 2) { + fprintf(stderr, "usage: %s hexbytes...\n", argv[0]); + exit(1); + } + payload_len = argc - 1; + if (payload_len > MAX_PKT_TO_TARGET-2) { + fprintf(stderr, + "%s: too many bytes (packet length limit exceeded)\n", + argv[0]); + exit(1); + } + + packet[0] = RVT_TM_HEADER; + for (i = 1; i <= payload_len; i++) + packet[i] = strtoul(argv[i], 0, 16); + c = 0; + for (i = 1; i <= payload_len; i++) + c ^= packet[i]; + packet[payload_len+1] = c; + + s = socket(AF_UNIX, SOCK_DGRAM, 0); + if (s < 0) { + perror("socket(AF_UNIX, SOCK_DGRAM, 0)"); + exit(1); + } + + local.sun_family = AF_UNIX; + strncpy(local.sun_path, sockpath, sizeof(local.sun_path)); + local.sun_path[sizeof(local.sun_path) - 1] = '\0'; + + /* we use the same magic that X11 uses in Xtranssock.c for + * calculating the proper length of the sockaddr */ +#if defined(BSD44SOCKETS) || defined(__UNIXWARE__) + local.sun_len = strlen(local.sun_path); +#endif +#if defined(BSD44SOCKETS) || defined(SUN_LEN) + namelen = SUN_LEN(&local); +#else + namelen = strlen(local.sun_path) + + offsetof(struct sockaddr_un, sun_path); +#endif + + i = sendto(s, packet, payload_len+2, 0, + (struct sockaddr *) &local, namelen); + if (i < 0) { + perror("sendto"); + exit(1); + } + + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/old/before-rvinterf/log.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,50 @@ +/* + * This module implements the logging function + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <unistd.h> +#include <time.h> + +extern char pr_item[]; + +extern FILE *logF; +extern time_t logtime; + +static struct tm last_tm; + +log_item() +{ + struct tm *curtm; + + curtm = gmtime(&logtime); + if (curtm->tm_year != last_tm.tm_year || + curtm->tm_mon != last_tm.tm_mon || + curtm->tm_mday != last_tm.tm_mday) + fprintf(logF, "%d-%02d-%02d (gmtime):\n", curtm->tm_year + 1900, + curtm->tm_mon+1, curtm->tm_mday); + fprintf(logF, "[%02d:%02d:%02d] %s\n", curtm->tm_hour, curtm->tm_min, + curtm->tm_sec, pr_item); + bcopy(curtm, &last_tm, sizeof(struct tm)); +} + +log_sent_packet(pkt, pktlen) + u_char *pkt; +{ + int i; + char *dp; + + dp = pr_item; + strcpy(dp, "Sent"); + dp += 4; + for (i = 0; i < pktlen; i++) { + sprintf(dp, " %02X", pkt[i]); + dp += 3; + } + *dp = '\0'; + print_item(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/old/before-rvinterf/openport.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,82 @@ +/* + * This module takes care of opening the serial port and setting the + * proper "raw" termios modes, including the baud rate. + */ + +#include <sys/types.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <termios.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> + +int target_fd; +char *baudrate_name = "115200"; + +static struct baudrate { + char *name; + speed_t termios_code; +} baud_rate_table[] = { + {"19200", B19200}, + {"38400", B38400}, + {"57600", B57600}, + {"115200", B115200}, + /* non-standard high baud rates "remapped" by CP2102 usb2serial IC */ + {"203125", B230400}, + {"406250", B460800}, + {"812500", B921600}, + /* table search terminator */ + {NULL, B0} +}; + +static speed_t +get_baud_rate() +{ + struct baudrate *br; + + for (br = baud_rate_table; br->name; br++) + if (!strcmp(br->name, baudrate_name)) + break; + if (!br->name) { + fprintf(stderr, "baud rate \"%s\" unknown/unsupported\n", + baudrate_name); + exit(1); + } + return br->termios_code; +} + +open_target_serial(ttydev) + char *ttydev; +{ + struct termios target_termios; + speed_t br_code; + + br_code = get_baud_rate(); + target_fd = open(ttydev, O_RDWR|O_NONBLOCK); + if (target_fd < 0) { + perror(ttydev); + exit(1); + } + target_termios.c_iflag = IGNBRK; + target_termios.c_oflag = 0; + target_termios.c_cflag = CLOCAL|HUPCL|CREAD|CS8; + target_termios.c_lflag = 0; + target_termios.c_cc[VMIN] = 1; + target_termios.c_cc[VTIME] = 0; + cfsetispeed(&target_termios, br_code); + cfsetospeed(&target_termios, br_code); + if (tcsetattr(target_fd, TCSAFLUSH, &target_termios) < 0) { + perror("initial tcsetattr on target"); + exit(1); + } + return 0; +} + +set_serial_nonblock(state) + int state; +{ + ioctl(target_fd, FIONBIO, &state); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/old/before-rvinterf/packetrx.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,88 @@ +/* + * This module handles the lowest level of serial packet Rx + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include "pktmux.h" + +extern int target_fd; + +#define MAXPKT 512 +u_char rxpkt[MAXPKT]; +size_t rxpkt_len; + +extern char pr_item[]; + +static int in_pkt, dle_state, toobig; + +static void +process_inbyte(inb) +{ + if (!in_pkt) { + if (inb != STX || dle_state) { + rxpkt_len++; + dle_state = (inb == DLE); + return; + } + if (rxpkt_len) { + sprintf(pr_item, + "Warning: Rx %u byte%s outside of a packet", + (unsigned)rxpkt_len, rxpkt_len != 1 ? "s" : ""); + print_item(); + rxpkt_len = 0; + } + in_pkt = 1; + toobig = 0; + return; + } + if (dle_state) { + dle_state = 0; + if (inb != STX && inb != DLE) { + sprintf(pr_item, + "Rx framing error: %02X after DLE\n", inb); + print_item(); + in_pkt = 0; + rxpkt_len = 0; + return; + } + goto data; + } + if (inb == DLE) { + dle_state = 1; + return; + } else if (inb == STX) { + if (!rxpkt_len) + return; + in_pkt = 0; + handle_rx_packet(); + rxpkt_len = 0; + return; + } +data: if (rxpkt_len >= MAXPKT) { + if (!toobig) { + sprintf(pr_item, "Error: Rx packet too big!\n"); + print_item(); + toobig = 1; + } + return; + } + rxpkt[rxpkt_len++] = inb; +} + +void +process_serial_rx() +{ + u_char rdbuf[512]; + int cc, i; + + cc = read(target_fd, rdbuf, sizeof rdbuf); + if (cc <= 0) { + perror("Error/EOF reading from target"); + exit(1); + } + for (i = 0; i < cc; i++) + process_inbyte(rdbuf[i]); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/old/before-rvinterf/packettx.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,32 @@ +/* + * This module handles the lowest level of serial packet Tx + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include "pktmux.h" +#include "txpkt.h" + +extern int target_fd; + +send_pkt_to_target(pkt, pktlen) + u_char *pkt; +{ + u_char buf[MAX_PKT_TO_TARGET*2+2]; + u_char *cp, *dp, *endp; + int c; + + endp = pkt + pktlen; + dp = buf; + *dp++ = STX; + for (cp = pkt; cp < endp; cp++) { + c = *cp; + if (c == STX || c == DLE) + *dp++ = DLE; + *dp++ = c; + } + *dp++ = STX; + write(target_fd, buf, dp - buf); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/old/before-rvinterf/pktmux.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,16 @@ +/* + * Definitions for the RVT MUX over-the-wire protocol + */ + +#define STX 0x02 +#define DLE 0x10 + +#define RVT_RV_HEADER 0x11 +#define RVT_L1_HEADER 0x12 +#define RVT_L23_HEADER 0x13 +#define RVT_TM_HEADER 0x14 +#define RVT_RNET_HEADER 0x15 +#define RVT_PROF_HEADER 0x16 +#define RVT_GTTBACK_HEADER 0x17 +#define RVT_OTHER_HEADER 0x18 +#define RVT_INVALID_HEADER 0xFF
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/old/before-rvinterf/rvtdump.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,123 @@ +/* + * This program reads bytes from a serial port, parses them assuming + * TI's RVT MUX format, and prints every decoded packet. + */ + +#include <sys/types.h> +#include <sys/errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <time.h> + +extern int target_fd; +extern char *baudrate_name; + +extern char pr_item[]; +extern int sendsock_fd; + +char *logfname; +FILE *logF; +time_t logtime; +int background, sendsock_enable; + +main(argc, argv) + char **argv; +{ + extern char *optarg; + extern int optind; + int c, maxfd; + fd_set fds; + + while ((c = getopt(argc, argv, "bB:d:l:s")) != EOF) + switch (c) { + case 'b': + background++; + continue; + case 'B': + baudrate_name = optarg; + continue; + case 'd': + target_fd = atoi(optarg); + continue; + case 'l': + logfname = optarg; + continue; + case 's': + sendsock_enable++; + continue; + case '?': + default: +usage: fprintf(stderr, + "usage: %s [options] ttyport\n", argv[0]); + exit(1); + } + if (background && !logfname) { + fprintf(stderr, "%s: -b is meaningless without -l\n", argv[0]); + exit(1); + } + if (target_fd <= 0) { + if (argc - optind != 1) + goto usage; + open_target_serial(argv[optind]); + } + + set_serial_nonblock(0); + setlinebuf(stdout); + if (logfname) { + logF = fopen(logfname, "w"); + if (!logF) { + perror(logfname); + exit(1); + } + fprintf(logF, "*** Log of decoded RVT output ***\n"); + setlinebuf(logF); + } + if (sendsock_enable) + create_send_socket(); + if (background) { + c = fork(); + if (c < 0) { + perror("fork"); + exit(1); + } + if (c) { + printf("rvtdump forked into background (pid %d)\n", c); + exit(0); + } + } + maxfd = target_fd; + if (sendsock_fd > maxfd) + maxfd = sendsock_fd; + for (;;) { + FD_ZERO(&fds); + FD_SET(target_fd, &fds); + if (sendsock_enable) + FD_SET(sendsock_fd, &fds); + c = select(maxfd+1, &fds, 0, 0, 0); + time(&logtime); + if (c < 0) { + if (errno == EINTR) + continue; + perror("select"); + exit(1); + } + if (FD_ISSET(target_fd, &fds)) + process_serial_rx(); + if (FD_ISSET(sendsock_fd, &fds)) + handle_sendsock(); + } +} + +handle_rx_packet() +{ + print_rx_packet(); +} + +print_item() +{ + if (!background) + printf("%s\n", pr_item); + if (logF) + log_item(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/old/before-rvinterf/rvtdump_tx.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,70 @@ +/* + * This module contains the implementation of the Tx extension to rvtdump + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <unistd.h> +#include "txpkt.h" + +static char sockpath[] = "/tmp/rvt_send_socket"; + +int sendsock_fd; +u_char sendsock_pkt[MAX_PKT_TO_TARGET]; +int sendsock_pktlen; + +create_send_socket() +{ + /* local socket binding voodoo copied from osmocon */ + struct sockaddr_un local; + unsigned int namelen; + int rc; + + sendsock_fd = socket(AF_UNIX, SOCK_DGRAM, 0); + if (sendsock_fd < 0) { + perror("socket(AF_UNIX, SOCK_DGRAM, 0)"); + exit(1); + } + + local.sun_family = AF_UNIX; + strncpy(local.sun_path, sockpath, sizeof(local.sun_path)); + local.sun_path[sizeof(local.sun_path) - 1] = '\0'; + unlink(local.sun_path); + + /* we use the same magic that X11 uses in Xtranssock.c for + * calculating the proper length of the sockaddr */ +#if defined(BSD44SOCKETS) || defined(__UNIXWARE__) + local.sun_len = strlen(local.sun_path); +#endif +#if defined(BSD44SOCKETS) || defined(SUN_LEN) + namelen = SUN_LEN(&local); +#else + namelen = strlen(local.sun_path) + + offsetof(struct sockaddr_un, sun_path); +#endif + + rc = bind(sendsock_fd, (struct sockaddr *) &local, namelen); + if (rc != 0) { + perror("bind on local dgram socket"); + exit(1); + } + + return(0); +} + +handle_sendsock() +{ + sendsock_pktlen = recv(sendsock_fd, sendsock_pkt, MAX_PKT_TO_TARGET, 0); + if (sendsock_pktlen <= 0) { + fprintf(stderr, "return value from recv on socket: %d\n", + sendsock_pktlen); + exit(1); + } + send_pkt_to_target(sendsock_pkt, sendsock_pktlen); + log_sent_packet(sendsock_pkt, sendsock_pktlen); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/old/before-rvinterf/trdump.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,169 @@ +/* + * This module implements the basic dump of any incoming packets + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include "pktmux.h" + +extern u_char rxpkt[]; +extern size_t rxpkt_len; + +char pr_item[4096]; + +void +print_rv_trace() +{ + int i, c; + char *dp; + + dp = pr_item; + strcpy(dp, "RV "); + dp += 3; + /* the SWE static ID is sent MSB first */ + for (i = 1; i <= 4; i++) { + sprintf(dp, "%02X", rxpkt[i]); + dp += 2; + } + /* severity level */ + sprintf(dp, " %d ", rxpkt[5]); + dp = index(dp, '\0'); + for (i = 6; i < rxpkt_len; i++) { + c = rxpkt[i]; + if (c & 0x80) { + *dp++ = 'M'; + *dp++ = '-'; + c &= 0x7F; + } + if (c < 0x20) { + *dp++ = '^'; + *dp++ = c + '@'; + } else if (c == 0x7F) { + *dp++ = '^'; + *dp++ = '?'; + } else + *dp++ = c; + } + *dp = '\0'; + print_item(); +} + +void +print_l1_trace() +{ + int i, c; + char *dp; + + dp = pr_item; + strcpy(dp, "L1: "); + dp += 4; + for (i = 1; i < rxpkt_len; i++) { + if ((i+1 < rxpkt_len) && + (rxpkt[i] == '\r' && rxpkt[i+1] == '\n' || + rxpkt[i] == '\n' && rxpkt[i+1] == '\r')) { + *dp = '\0'; + print_item(); + if (i+2 == rxpkt_len) + return; + dp = pr_item; + *dp++ = '+'; + *dp++ = ' '; + i++; + continue; + } + c = rxpkt[i]; + if (c & 0x80) { + *dp++ = 'M'; + *dp++ = '-'; + c &= 0x7F; + } + if (c < 0x20) { + *dp++ = '^'; + *dp++ = c + '@'; + } else if (c == 0x7F) { + *dp++ = '^'; + *dp++ = '?'; + } else + *dp++ = c; + } + /* will get here only if no newline sequence at the end */ + *dp = '\0'; + print_item(); +} + +void +print_g23_trace() +{ + int i; + char *dp; + + dp = pr_item; + strcpy(dp, "G23:"); + dp += 4; + for (i = 1; i < rxpkt_len; i++) { + sprintf(dp, " %02X", rxpkt[i]); + dp += 3; + } + *dp = '\0'; + print_item(); +} + +void +print_etm_output_raw() +{ + int i; + char *dp; + + dp = pr_item; + strcpy(dp, "ETM:"); + dp += 4; + for (i = 1; i < rxpkt_len; i++) { + sprintf(dp, " %02X", rxpkt[i]); + dp += 3; + } + *dp = '\0'; + print_item(); +} + +void +print_unknown_packet() +{ + int i; + char *dp; + + dp = pr_item; + strcpy(dp, "UNK:"); + dp += 4; + for (i = 0; i < rxpkt_len; i++) { + sprintf(dp, " %02X", rxpkt[i]); + dp += 3; + } + *dp = '\0'; + print_item(); +} + +void +print_rx_packet() +{ + switch (rxpkt[0]) { + case RVT_RV_HEADER: + if (rxpkt_len < 6) + goto unknown; + print_rv_trace(); + return; + case RVT_L1_HEADER: + print_l1_trace(); + return; + case RVT_L23_HEADER: + print_g23_trace(); + return; + case RVT_TM_HEADER: + print_etm_output_raw(); + return; + default: + unknown: + print_unknown_packet(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/old/before-rvinterf/txpkt.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,15 @@ +/* + * For sizing our buffers etc in rvinterf, we need a limit on the size of + * message packets we can send to the target. As it happens, the packet + * Rx code in RVT on the target side also has a limit (quite naturally, + * as it needs to use a static buffer to reassemble incoming packets as + * they arrive at the UART in unpredictable interrupt-sized chunks), so + * we set our limit to match that in RVT. + */ + +#define MAX_PKT_TO_TARGET 255 + +/* + * The above limit definition counts all bytes between the opening and + * closing STX flags, but not DLEs inserted for binary transparency. + */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/old/format_g23.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,241 @@ +/* + * This module implements the decoding of G23 trace packets into + * human-readable form - or more precisely, traces, system primitives + * and other packets that can be emitted through GPF on targets. + * The decoding is based on my (Space Falcon's) understanding + * of the packet format, which is in turn based on the GPF sources + * available to us, now integrated under gsm-fw/gpf. + */ + +#include <sys/types.h> +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include "../include/pktmux.h" +#include "../include/limits.h" + +extern u_char rxpkt[]; +extern size_t rxpkt_len; +extern char fmtbuf[]; + +static char *fmtbuf_ptr; + +static int +basic_checks() +{ + int i, c; + + if (rxpkt_len < 17) + return(0); + /* check version bits in the header byte */ + if ((rxpkt[1] & 0xC0) != 0x80) + return(0); + /* check the length */ + c = rxpkt[2] | rxpkt[3] << 8; + if (c + 4 != rxpkt_len) + return(0); + /* ensure that the "from" and "to" are printable ASCII */ + for (i = 8; i < 16; i++) { + c = rxpkt[i]; + if (c < ' ' || c > '~') + return(0); + } + /* basic checks pass */ + return(1); +} + +static int +psprim_extra_checks() +{ + int i, c; + + if (rxpkt_len < 24) + return(0); + /* "original rcvr" field needs to be printable ASCII */ + for (i = 16; i < 20; i++) { + c = rxpkt[i]; + if (c < ' ' || c > '~') + return(0); + } + /* checks pass */ + return(1); +} + +static void +print_malformed() +{ + int i; + char *dp; + + dp = fmtbuf; + strcpy(dp, "G23 UNK:"); + dp += 8; + for (i = 1; i < rxpkt_len; i++) { + sprintf(dp, " %02X", rxpkt[i]); + dp += 3; + } + *dp = '\0'; + output_line(fmtbuf); +} + +static int +entity_name_well_formed(p) + char *p; +{ + int i, len; + + if (!isupper(p[0])) + return(0); + for (i = 0; i < 4; i++) + if (!isalnum(p[i])) + break; + len = i; + for (; i < 4; i++) + if (p[i] != ' ') + return(0); + return(len); +} + +static void +print_entity_name(raw) + char *raw; +{ + int len; + + len = entity_name_well_formed(raw); + if (len) + sprintf(fmtbuf_ptr, "%.*s", len, raw); + else + sprintf(fmtbuf_ptr, "\"%.4s\"", raw); + fmtbuf_ptr = index(fmtbuf_ptr, '\0'); +} + +static void +print_common_hdr(typestr) + char *typestr; +{ + sprintf(fmtbuf, "G23 %s id=%02X ts=%02X%02X%02X%02X ", typestr, + rxpkt[1], rxpkt[7], rxpkt[6], rxpkt[5], rxpkt[4]); + fmtbuf_ptr = index(fmtbuf, '\0'); + print_entity_name(rxpkt + 8); + *fmtbuf_ptr++ = '-'; + *fmtbuf_ptr++ = '>'; + print_entity_name(rxpkt + 12); + *fmtbuf_ptr++ = ' '; +} + +static void +format_text(start_off) +{ + int i, c; + + *fmtbuf_ptr++ = '\"'; + for (i = start_off; i < rxpkt_len; i++) { + c = rxpkt[i]; + if (c & 0x80) { + *fmtbuf_ptr++ = 'M'; + *fmtbuf_ptr++ = '-'; + c &= 0x7F; + } + if (c < 0x20) { + *fmtbuf_ptr++ = '^'; + *fmtbuf_ptr++ = c + '@'; + } else if (c == 0x7F) { + *fmtbuf_ptr++ = '^'; + *fmtbuf_ptr++ = '?'; + } else + *fmtbuf_ptr++ = c; + } + *fmtbuf_ptr++ = '\"'; + *fmtbuf_ptr = '\0'; + output_line(fmtbuf); +} + +static void +format_compressed_trace(start_off) +{ + int i; + + i = start_off + 1; + sprintf(fmtbuf_ptr, "%d", rxpkt[i+1] << 8 | rxpkt[i]); + fmtbuf_ptr = index(fmtbuf_ptr, '\0'); + i += 4; + for (; i < rxpkt_len; i++) { + sprintf(fmtbuf_ptr, " %02X", rxpkt[i]); + fmtbuf_ptr += 3; + } + *fmtbuf_ptr = '\0'; + output_line(fmtbuf); +} + +static void +format_trace() +{ + int i; + + i = 16; + if (rxpkt[i] < 0x20) { + sprintf(fmtbuf_ptr, "tc=%02X ", rxpkt[i]); + fmtbuf_ptr += 6; + i++; + } + if (rxpkt_len - i >= 5 && rxpkt[i] == '%' && + !rxpkt[i+3] && !rxpkt[i+4]) + format_compressed_trace(i); + else + format_text(i); +} + +static void +format_psprim() +{ + int i; + + /* original destination */ + *fmtbuf_ptr++ = '('; + print_entity_name(rxpkt + 16); + *fmtbuf_ptr++ = ')'; + /* opcode */ + sprintf(fmtbuf_ptr, " %02X%02X%02X%02X", + rxpkt[23], rxpkt[22], rxpkt[21], rxpkt[20]); + fmtbuf_ptr += 9; + for (i = 24; i < rxpkt_len; i++) { + sprintf(fmtbuf_ptr, " %02X", rxpkt[i]); + fmtbuf_ptr += 3; + } + *fmtbuf_ptr = '\0'; + output_line(fmtbuf); +} + +void +print_g23_trace() +{ + if (!basic_checks()) { + print_malformed(); + return; + } + /* dispatch by type */ + switch (rxpkt[1] & 0x30) { + case 0x10: + /* PS primitive */ + if (psprim_extra_checks()) { + print_common_hdr("PSprim"); + format_psprim(); + } else + print_malformed(); + return; + case 0x20: + /* trace */ + print_common_hdr("trace"); + format_trace(); + return; + case 0x30: + /* system primitive */ + print_common_hdr("sysprim"); + format_text(16); + return; + default: + print_malformed(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/old/g23sh/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,18 @@ +CC= gcc +CFLAGS= -O2 -I../include +PROG= g23sh +OBJS= init.o main.o pktsort.o sendsp.o usercmd.o +LIBS= ../libasync/libasync.a ../libg23/libg23.a +INSTBIN=/usr/local/bin + +all: ${PROG} + +${PROG}: ${OBJS} ${LIBS} + ${CC} ${CFLAGS} -o $@ ${OBJS} ${LIBS} + +install: ${PROG} + mkdir -p ${INSTBIN} + install -c ${PROG} ${INSTBIN} + +clean: + rm -f *.o *.out *errs ${PROG}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/old/g23sh/init.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,27 @@ +/* + * This module contains the initialization code for g23sh. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "pktmux.h" +#include "localsock.h" + +extern int sock; + +init() +{ + static u_char want_rvt_lost[9] = {CLI2RVI_WANT_RVTRACE, + 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00}; + static u_char want_l23_mux[2] = {CLI2RVI_WANT_MUXPROTO, RVT_L23_HEADER}; + + if (!sock) + connect_local_socket(); + localsock_prep_for_length_rx(); + send_init_command(want_rvt_lost, 9); + send_init_command(want_l23_mux, 2); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/old/g23sh/main.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,86 @@ +/* + * This module contains the main() function for g23sh. + */ + +#include <sys/types.h> +#include <sys/errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +char *socket_pathname = "/tmp/rvinterf_socket"; +int ttyhacks, dflag; + +int sock; + +extern char *rvinterf_Bopt, *rvinterf_lopt, *rvinterf_wopt; + +main(argc, argv) + char **argv; +{ + extern int optind; + extern char *optarg; + int c; + fd_set fds; + + while ((c = getopt(argc, argv, "B:dl:s:w:")) != EOF) + switch (c) { + case 'B': + rvinterf_Bopt = optarg; + continue; + case 'd': + dflag++; + continue; + case 'l': + rvinterf_lopt = optarg; + continue; + case 's': + socket_pathname = optarg; + continue; + case 'w': + rvinterf_wopt = optarg; + continue; + case '?': + default: +usage: fprintf(stderr, + "usage: %s [options] [ttyport]\n", argv[0]); + exit(1); + } + switch (argc - optind) { + case 0: + if (rvinterf_Bopt || rvinterf_lopt || rvinterf_wopt) { + fprintf(stderr, + "%s: -B, -l and -w options are meaningful only when launching rvinterf\n", + argv[0]); + exit(1); + } + break; + case 1: + launch_rvinterf(argv[optind]); + break; + default: + goto usage; + } + + ttyhacks = isatty(0) && !dflag; + init(); + tty_init(); + for (;;) { + FD_ZERO(&fds); + FD_SET(0, &fds); + FD_SET(sock, &fds); + c = select(sock+1, &fds, 0, 0, 0); + if (c < 0) { + if (errno == EINTR) + continue; + tty_cleanup(); + perror("select"); + exit(1); + } + if (FD_ISSET(0, &fds)) + handle_tty_input(); + if (FD_ISSET(sock, &fds)) + handle_rvinterf_input(); + fflush(stdout); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/old/g23sh/pktsort.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,67 @@ +/* + * Here we sort out incoming packets from the target relayed via rvinterf. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "pktmux.h" +#include "limits.h" +#include "localsock.h" +#include "localtypes.h" + +extern u_char rvi_msg[]; +extern int rvi_msg_len; + +static void +process_rvt() +{ + u32 useid; + + if (rvi_msg_len < 7) { + tty_cleanup(); + fprintf(stderr, "Error: rvinterf sent us an invalid RVT msg\n"); + exit(1); + } + useid = rvi_msg[2] << 24 | rvi_msg[3] << 16 | rvi_msg[4] << 8 + | rvi_msg[5]; + switch (useid) { + case 0: + handle_useid_0(); + return; + default: + tty_cleanup(); + fprintf(stderr, "unexpected fwd of USEID %08X from rvinterf\n", + useid); + exit(1); + } +} + +void +g23_packet_rx() +{ + char fmtbuf[MAX_PKT_FROM_TARGET*8]; /* size it generously */ + + format_g23_packet(rvi_msg + 1, rvi_msg_len - 1, fmtbuf); + async_msg_output(fmtbuf); +} + +void +process_pkt_from_target() +{ + switch (rvi_msg[1]) { + case RVT_RV_HEADER: + process_rvt(); + return; + case RVT_L23_HEADER: + g23_packet_rx(); + return; + default: + tty_cleanup(); + fprintf(stderr, "unexpected fwd of MUX %02X from rvinterf\n", + rvi_msg[1]); + exit(1); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/old/g23sh/sendsp.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,53 @@ +/* + * g23sh system primitive sending command + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "pktmux.h" +#include "limits.h" + +void +cmd_sendsp(argc, argv) + char **argv; +{ + char *stackdest, *primarg; + unsigned intlen; + u_char sendpkt[MAX_PKT_TO_TARGET+1]; + unsigned pktlen; + + stackdest = argv[1]; + primarg = argv[2]; + if (strlen(stackdest) > 4) { + printf( + "error: stack destination arg may not exceed 4 characters\n"); + return; + } + intlen = 12 + strlen(primarg); + pktlen = intlen + 4; + if (pktlen > MAX_PKT_TO_TARGET) { + printf("error: max pkt to target limit exceeded\n"); + return; + } + /* fill out the packet */ + sendpkt[0] = RVT_L23_HEADER; + sendpkt[1] = 0xB7; /* system prim */ + sendpkt[2] = intlen; + sendpkt[3] = intlen >> 8; + /* send zeros for the timestamp */ + sendpkt[4] = 0; + sendpkt[5] = 0; + sendpkt[6] = 0; + sendpkt[7] = 0; + /* as far as TI's sw is concerned, we are PCO */ + sendpkt[8] = 'P'; + sendpkt[9] = 'C'; + sendpkt[10] = 'O'; + sendpkt[11] = ' '; + sprintf(sendpkt + 12, "%-4s%s", stackdest, primarg); + /* send it! */ + send_pkt_to_target(sendpkt, pktlen); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/old/g23sh/usercmd.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,90 @@ +/* + * This module implements g23sh user command dispatch. + */ + +#include <sys/types.h> +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> + +extern char usercmd[]; + +extern void cmd_sendsp(); + +void +cmd_exit() +{ + tty_cleanup(); + exit(0); +} + +static struct cmdtab { + char *cmd; + int minargs; + int maxargs; + void (*func)(); +} cmdtab[] = { + {"exit", 0, 0, cmd_exit}, + {"quit", 0, 0, cmd_exit}, + {"sp", 2, 2, cmd_sendsp}, + {0, 0, 0, 0} +}; + +void +dispatch_user_cmd() +{ + char *argv[10]; + char *cp, **ap; + struct cmdtab *tp; + + for (cp = usercmd; isspace(*cp); cp++) + ; + if (!*cp || *cp == '#') + return; + argv[0] = cp; + while (*cp && !isspace(*cp)) + cp++; + if (*cp) + *cp++ = '\0'; + for (tp = cmdtab; tp->cmd; tp++) + if (!strcmp(tp->cmd, argv[0])) + break; + if (!tp->func) { + printf("error: no such command\n"); + return; + } + for (ap = argv + 1; ; ) { + while (isspace(*cp)) + cp++; + if (!*cp || *cp == '#') + break; + if (ap - argv - 1 >= tp->maxargs) { + printf("error: too many arguments\n"); + return; + } + if (*cp == '"') { + *ap++ = ++cp; + while (*cp && *cp != '"') + cp++; + if (*cp != '"') { + printf("error: unterminated quoted string\n"); + return; + } + *cp++ = '\0'; + } else { + *ap++ = cp; + while (*cp && !isspace(*cp)) + cp++; + if (*cp) + *cp++ = '\0'; + } + } + if (ap - argv - 1 < tp->minargs) { + printf("error: too few arguments\n"); + return; + } + *ap = 0; + tp->func(ap - argv, argv); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/old/sendsp/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,18 @@ +CC= gcc +CFLAGS= -O2 -I../include +PROGS= fc-sendsp +INSTBIN=/usr/local/bin + +SENDSP_OBJS= rvifsend.o sendsp.o + +all: ${PROGS} + +fc-sendsp: ${SENDSP_OBJS} + ${CC} ${CFLAGS} -o $@ ${SENDSP_OBJS} + +install: ${PROGS} + mkdir -p ${INSTBIN} + install -c ${PROGS} ${INSTBIN} + +clean: + rm -f *.o *.out *errs ${PROGS}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/old/sendsp/rvifsend.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,66 @@ +/* + * This module is currently linked by fc-sendsp, and may be used by + * other similar hack-utilities in the future. Here we connect to + * rvinterf, send one packet to the target, and call it done. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <unistd.h> +#include "localsock.h" + +extern char *socket_pathname; + +send_pkt_to_target(pkt, pktlen) + u_char *pkt; + unsigned pktlen; +{ + /* local socket binding voodoo copied from osmocon */ + struct sockaddr_un local; + unsigned int namelen; + int sock, rc; + u_char hdrbuf[3]; + int len1; + + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) { + perror("socket(AF_UNIX, SOCK_STREAM, 0)"); + exit(1); + } + + local.sun_family = AF_UNIX; + strncpy(local.sun_path, socket_pathname, sizeof(local.sun_path)); + local.sun_path[sizeof(local.sun_path) - 1] = '\0'; + + /* we use the same magic that X11 uses in Xtranssock.c for + * calculating the proper length of the sockaddr */ +#if defined(BSD44SOCKETS) || defined(__UNIXWARE__) + local.sun_len = strlen(local.sun_path); +#endif +#if defined(BSD44SOCKETS) || defined(SUN_LEN) + namelen = SUN_LEN(&local); +#else + namelen = strlen(local.sun_path) + + offsetof(struct sockaddr_un, sun_path) + 1; +#endif + + rc = connect(sock, (struct sockaddr *) &local, namelen); + if (rc != 0) { + perror(socket_pathname); + exit(1); + } + + len1 = pktlen + 1; + hdrbuf[0] = len1 >> 8; + hdrbuf[1] = len1 & 0xFF; + hdrbuf[2] = CLI2RVI_PKT_TO_TARGET; + write(sock, hdrbuf, 3); + write(sock, pkt, pktlen); + close(sock); + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/old/sendsp/sendsp.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,71 @@ +/* + * This hack-utility sends a GPF System Primitive given on the command line + * to a target GSM device via rvinterf. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "pktmux.h" +#include "limits.h" + +char *socket_pathname = "/tmp/rvinterf_socket"; + +main(argc, argv) + char **argv; +{ + char *stackdest, *primarg; + unsigned intlen; + u_char sendpkt[MAX_PKT_TO_TARGET]; + unsigned pktlen; + + if (argc < 3) { +usage: fprintf(stderr, "usage: %s [-s socket] stackdest primarg\n", + argv[0]); + exit(1); + } + if (strcmp(argv[1], "-s")) { + if (argc != 3) + goto usage; + stackdest = argv[1]; + primarg = argv[2]; + } else { + if (argc != 5) + goto usage; + socket_pathname = argv[2]; + stackdest = argv[3]; + primarg = argv[4]; + } + if (strlen(stackdest) > 4) { + fprintf(stderr, + "error: stack destination arg may not exceed 4 characters\n"); + exit(1); + } + intlen = 12 + strlen(primarg) + 1; + pktlen = intlen + 4; + if (pktlen > MAX_PKT_TO_TARGET) { + fprintf(stderr, "error: max pkt to target limit exceeded\n"); + exit(1); + } + /* fill out the packet */ + sendpkt[0] = RVT_L23_HEADER; + sendpkt[1] = 0xB7; /* system prim */ + sendpkt[2] = intlen; + sendpkt[3] = intlen >> 8; + /* send zeros for the timestamp */ + sendpkt[4] = 0; + sendpkt[5] = 0; + sendpkt[6] = 0; + sendpkt[7] = 0; + /* as far as TI's sw is concerned, we are PCO */ + sendpkt[8] = 'P'; + sendpkt[9] = 'C'; + sendpkt[10] = 'O'; + sendpkt[11] = ' '; + sprintf(sendpkt + 12, "%-4s%s", stackdest, primarg); + /* send it! */ + send_pkt_to_target(sendpkt, pktlen); + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/tmsh/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,20 @@ +CC= gcc +CFLAGS= -O2 -I../include +PROGS= fc-tmsh +INSTBIN=/usr/local/bin +LIBS= ../libasync/libasync.a + +TMSH_OBJS= abb.o etmbasic.o ffs2.o ffs2resp.o ffs2wr.o init.o main.o \ + misc.o omr.o pktsort.o tmcore.o usercmd.o + +all: ${PROGS} + +fc-tmsh: ${TMSH_OBJS} ${LIBS} + ${CC} ${CFLAGS} -o $@ ${TMSH_OBJS} ${LIBS} + +install: ${PROGS} + mkdir -p ${INSTBIN} + install -c ${PROGS} ${INSTBIN} + +clean: + rm -f *.o *.out *errs ${PROGS}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/tmsh/abb.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,98 @@ +/* + * In this module we are going to implement commands dealing with the ABB. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "pktmux.h" +#include "limits.h" +#include "localtypes.h" +#include "etm.h" + +extern u_char rvi_msg[]; +extern int rvi_msg_len; + +void +cmd_abbr(argc, argv) + char **argv; +{ + u32 page, reg; + u_char cmdpkt[5]; + + page = strtoul(argv[1], 0, 0); + reg = strtoul(argv[2], 0, 0); + if (page > 1 || reg > 31) { + printf("error: argument(s) out of range\n"); + return; + } + cmdpkt[1] = ETM_CORE; + cmdpkt[2] = TMCORE_OPC_CODEC_RD; + cmdpkt[3] = page << 5 | reg; + send_etm_cmd(cmdpkt, 3); +} + +void +abbr_response() +{ + unsigned pg, reg, val; + char buf[80]; + + if (rvi_msg[3]) { + print_etm_pkt_raw("abbr error"); + return; + } + if (rvi_msg_len != 9) { + print_etm_pkt_raw("abbr malformed resp"); + return; + } + pg = rvi_msg[5] >> 5; + reg = rvi_msg[5] & 0x1F; + val = rvi_msg[6] | rvi_msg[7] << 8; + sprintf(buf, "abbr %u %u: %03X", pg, reg, val); + async_msg_output(buf); +} + +void +cmd_abbw(argc, argv) + char **argv; +{ + u32 page, reg, val; + u_char cmdpkt[7]; + + page = strtoul(argv[1], 0, 0); + reg = strtoul(argv[2], 0, 0); + val = strtoul(argv[3], 0, 16); + if (page > 1 || reg > 31 || val > 0x3FF) { + printf("error: argument(s) out of range\n"); + return; + } + cmdpkt[1] = ETM_CORE; + cmdpkt[2] = TMCORE_OPC_CODEC_WR; + cmdpkt[3] = page << 5 | reg; + cmdpkt[4] = val; + cmdpkt[5] = val >> 8; + send_etm_cmd(cmdpkt, 5); +} + +void +abbw_response() +{ + unsigned pg, reg; + char buf[80]; + + if (rvi_msg[3]) { + print_etm_pkt_raw("abbw error"); + return; + } + if (rvi_msg_len != 7) { + print_etm_pkt_raw("abbw malformed resp"); + return; + } + pg = rvi_msg[5] >> 5; + reg = rvi_msg[5] & 0x1F; + sprintf(buf, "abbw %u %u OK", pg, reg); + async_msg_output(buf); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/tmsh/etmbasic.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,107 @@ +/* + * Basic ETM interaction + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "pktmux.h" +#include "limits.h" +#include "etm.h" +#include "tm3.h" + +extern u_char rvi_msg[]; +extern int rvi_msg_len; + +void +print_etm_pkt_raw(err) + char *err; +{ + char buf[MAX_PKT_FROM_TARGET*3+80], *dp; + int i; + + sprintf(buf, "%s:", err); + dp = index(buf, '\0'); + for (i = 2; i < rvi_msg_len; i++) { + sprintf(dp, " %02X", rvi_msg[i]); + dp += 3; + } + async_msg_output(buf); +} + +void +etm_packet_rx() +{ + int i, c; + + if (rvi_msg_len < 4) { +runt: print_etm_pkt_raw("TM runt"); + return; + } + c = 0; + for (i = 2; i < rvi_msg_len; i++) + c ^= rvi_msg[i]; + if (c) { + print_etm_pkt_raw("BAD CKSUM"); + return; + } + switch (rvi_msg[2]) { + case ETM_CORE: + if (rvi_msg_len < 6) + goto runt; + tmcore_msg_rx(); + return; + case ETM_FFS1: + print_etm_pkt_raw("FFS1"); + return; + case ETM_FFS2: + if (rvi_msg_len < 5) + goto runt; + handle_ffs2_response(); + return; + /* TM3 */ + case MEM_READ: + if (rvi_msg_len < 5) + goto runt; + handle_omr_response(); + return; + default: + print_etm_pkt_raw("TM unknown"); + } +} + +void +cmd_etmpkt(argc, argv) + char **argv; +{ + u_char pkt[MAX_PKT_TO_TARGET]; + int di, c, b; + char **ap; + + pkt[0] = RVT_TM_HEADER; + di = 1; + c = 0; + for (ap = argv + 1; *ap; ap++) { + b = strtoul(*ap, 0, 16); + pkt[di++] = b; + c ^= b; + } + pkt[di++] = c; + send_pkt_to_target(pkt, di); +} + +void +send_etm_cmd(buf, len) + u_char *buf; +{ + int i, c; + + buf[0] = RVT_TM_HEADER; + c = 0; + for (i = 1; i <= len; i++) + c ^= buf[i]; + buf[i] = c; + send_pkt_to_target(buf, len + 2); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/tmsh/ffs2.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,349 @@ +/* + * In this module we are going to implement TMFFS2 functionality. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "limits.h" +#include "localtypes.h" +#include "etm.h" +#include "ffs.h" +#include "tmffs2.h" + +void +cmd_ffs2_close(argc, argv) + char **argv; +{ + u_char cmdpkt[5]; + + cmdpkt[1] = ETM_FFS2; + cmdpkt[2] = TMFFS_CLOSE; + cmdpkt[3] = strtoul(argv[1], 0, 0); + send_etm_cmd(cmdpkt, 3); +} + +void +cmd_ffs2_delete(argc, argv) + char **argv; +{ + u_char cmdpkt[MAX_PKT_TO_TARGET], *dp; + int slen; + + slen = strlen(argv[1]); + if (slen >= TMFFS_STRING_SIZE) { + printf("error: pathname arg exceeds string length limit\n"); + return; + } + dp = cmdpkt + 1; + *dp++ = ETM_FFS2; + *dp++ = TMFFS_REMOVE; + *dp++ = slen + 1; + strcpy(dp, argv[1]); + dp += slen + 1; + send_etm_cmd(cmdpkt, dp - cmdpkt - 1); +} + +void +cmd_ffs2_format(argc, argv) + char **argv; +{ + u_char cmdpkt[MAX_PKT_TO_TARGET], *dp; + int slen; + + slen = strlen(argv[1]); + if (slen >= TMFFS_STRING_SIZE) { + printf("error: argument exceeds string length limit\n"); + return; + } + dp = cmdpkt + 1; + *dp++ = ETM_FFS2; + *dp++ = TMFFS_FORMAT; + *dp++ = slen + 1; + strcpy(dp, argv[1]); + dp += slen + 1; + /* magic is 0x2BAD, 16-bit little-endian */ + *dp++ = 0xAD; + *dp++ = 0x2B; + send_etm_cmd(cmdpkt, dp - cmdpkt - 1); +} + +void +cmd_ffs2_mkdir(argc, argv) + char **argv; +{ + u_char cmdpkt[MAX_PKT_TO_TARGET], *dp; + int slen; + + slen = strlen(argv[1]); + if (slen >= TMFFS_STRING_SIZE) { + printf("error: pathname arg exceeds string length limit\n"); + return; + } + dp = cmdpkt + 1; + *dp++ = ETM_FFS2; + *dp++ = TMFFS_MKDIR; + *dp++ = slen + 1; + strcpy(dp, argv[1]); + dp += slen + 1; + send_etm_cmd(cmdpkt, dp - cmdpkt - 1); +} + +void +cmd_ffs2_open(argc, argv) + char **argv; +{ + u_char cmdpkt[MAX_PKT_TO_TARGET], *dp; + int slen; + + slen = strlen(argv[1]); + if (slen >= TMFFS_STRING_SIZE) { + printf("error: pathname arg exceeds string length limit\n"); + return; + } + dp = cmdpkt + 1; + *dp++ = ETM_FFS2; + *dp++ = TMFFS_OPEN; + *dp++ = slen + 1; + strcpy(dp, argv[1]); + dp += slen + 1; + *dp++ = strtoul(argv[2], 0, 16); + send_etm_cmd(cmdpkt, dp - cmdpkt - 1); +} + +void +cmd_ffs2_opendir(argc, argv) + char **argv; +{ + u_char cmdpkt[MAX_PKT_TO_TARGET], *dp; + int slen; + + slen = strlen(argv[1]); + if (slen >= TMFFS_STRING_SIZE) { + printf("error: pathname arg exceeds string length limit\n"); + return; + } + dp = cmdpkt + 1; + *dp++ = ETM_FFS2; + *dp++ = TMFFS_OPENDIR; + *dp++ = slen + 1; + strcpy(dp, argv[1]); + dp += slen + 1; + send_etm_cmd(cmdpkt, dp - cmdpkt - 1); +} + +void +cmd_ffs2_preformat() +{ + u_char cmdpkt[6]; + + cmdpkt[1] = ETM_FFS2; + cmdpkt[2] = TMFFS_PREFORMAT; + /* magic is 0xDEAD, 16-bit little-endian */ + cmdpkt[3] = 0xAD; + cmdpkt[4] = 0xDE; + send_etm_cmd(cmdpkt, 4); +} + +void +cmd_ffs2_query(argc, argv) + char **argv; +{ + u_char cmdpkt[5]; + + cmdpkt[1] = ETM_FFS2; + cmdpkt[2] = TMFFS_QUERY; + cmdpkt[3] = strtoul(argv[1], 0, 0); + send_etm_cmd(cmdpkt, 3); +} + +void +cmd_ffs2_readfd(argc, argv) + char **argv; +{ + u_char cmdpkt[6]; + + cmdpkt[1] = ETM_FFS2; + cmdpkt[2] = TMFFS_READ; + cmdpkt[3] = strtoul(argv[1], 0, 0); + cmdpkt[4] = strtoul(argv[2], 0, 0); + send_etm_cmd(cmdpkt, 4); +} + +void +cmd_ffs2_readfile(argc, argv) + char **argv; +{ + u_char cmdpkt[MAX_PKT_TO_TARGET], *dp; + int slen; + + slen = strlen(argv[1]); + if (slen >= TMFFS_STRING_SIZE) { + printf("error: pathname arg exceeds string length limit\n"); + return; + } + dp = cmdpkt + 1; + *dp++ = ETM_FFS2; + *dp++ = TMFFS_FILE_READ; + *dp++ = slen + 1; + strcpy(dp, argv[1]); + dp += slen + 1; + *dp++ = strtoul(argv[2], 0, 0); + send_etm_cmd(cmdpkt, dp - cmdpkt - 1); +} + +void +cmd_ffs2_stat(argc, argv) + char **argv; +{ + u_char cmdpkt[MAX_PKT_TO_TARGET], *dp; + int slen; + + slen = strlen(argv[1]); + if (slen >= TMFFS_STRING_SIZE) { + printf("error: pathname arg exceeds string length limit\n"); + return; + } + dp = cmdpkt + 1; + *dp++ = ETM_FFS2; + *dp++ = TMFFS_STAT; + *dp++ = slen + 1; + strcpy(dp, argv[1]); + dp += slen + 1; + send_etm_cmd(cmdpkt, dp - cmdpkt - 1); +} + +void +cmd_ffs2_version() +{ + u_char cmdpkt[4]; + + cmdpkt[1] = ETM_FFS2; + cmdpkt[2] = TMFFS_VERSION; + send_etm_cmd(cmdpkt, 2); +} + +void +cmd_ffs2_wrfile(argc, argv) + char **argv; +{ + u_char cmdpkt[MAX_PKT_TO_TARGET], *dp; + int slen, slen2; + + slen = strlen(argv[1]); + if (slen >= TMFFS_STRING_SIZE) { + printf("error: pathname arg exceeds string length limit\n"); + return; + } + slen2 = strlen(argv[2]); + if (slen2 > 64) { + printf("error: write test data argument is too long\n"); + return; + } + dp = cmdpkt + 1; + *dp++ = ETM_FFS2; + *dp++ = TMFFS_FILE_WRITE; + *dp++ = slen + 1; + strcpy(dp, argv[1]); + dp += slen + 1; + *dp++ = slen2; /* no NUL-termination on test data */ + strcpy(dp, argv[2]); + dp += slen2; + *dp++ = FFS_O_CREATE | FFS_O_TRUNC; + send_etm_cmd(cmdpkt, dp - cmdpkt - 1); +} + +void +cmd_ffs2_writefd(argc, argv) + char **argv; +{ + u_char cmdpkt[MAX_PKT_TO_TARGET], *dp; + int slen2; + + slen2 = strlen(argv[2]); + if (slen2 > 64) { + printf("error: write test data argument is too long\n"); + return; + } + dp = cmdpkt + 1; + *dp++ = ETM_FFS2; + *dp++ = TMFFS_WRITE; + *dp++ = strtoul(argv[1], 0, 0); + *dp++ = slen2; /* no NUL-termination on test data */ + strcpy(dp, argv[2]); + dp += slen2; + send_etm_cmd(cmdpkt, dp - cmdpkt - 1); +} + +void +cmd_ffs2_xlstat(argc, argv) + char **argv; +{ + u_char cmdpkt[MAX_PKT_TO_TARGET], *dp; + int slen; + + slen = strlen(argv[1]); + if (slen >= TMFFS_STRING_SIZE) { + printf("error: pathname arg exceeds string length limit\n"); + return; + } + dp = cmdpkt + 1; + *dp++ = ETM_FFS2; + *dp++ = TMFFS_XLSTAT; + *dp++ = slen + 1; + strcpy(dp, argv[1]); + dp += slen + 1; + send_etm_cmd(cmdpkt, dp - cmdpkt - 1); +} + +static struct cmdtab { + char *cmd; + int minargs; + int maxargs; + void (*func)(); +} ffs2_cmds[] = { + {"close", 1, 1, cmd_ffs2_close}, + {"delete", 1, 1, cmd_ffs2_delete}, + {"format", 1, 1, cmd_ffs2_format}, + {"mkdir", 1, 1, cmd_ffs2_mkdir}, + {"open", 2, 2, cmd_ffs2_open}, + {"opendir", 1, 1, cmd_ffs2_opendir}, + {"preformat", 0, 0, cmd_ffs2_preformat}, + {"query", 1, 1, cmd_ffs2_query}, + {"readfd", 2, 2, cmd_ffs2_readfd}, + {"readfile", 2, 2, cmd_ffs2_readfile}, + {"stat", 1, 1, cmd_ffs2_stat}, + {"version", 0, 0, cmd_ffs2_version}, + {"wrfile", 2, 2, cmd_ffs2_wrfile}, + {"writefd", 2, 2, cmd_ffs2_writefd}, + {"xlstat", 1, 1, cmd_ffs2_xlstat}, + {0, 0, 0, 0} +}; + +void +cmd_ffs2(argc, argv) + char **argv; +{ + struct cmdtab *tp; + int extargs; + + for (tp = ffs2_cmds; tp->cmd; tp++) + if (!strcmp(tp->cmd, argv[1])) + break; + if (!tp->func) { + printf("error: no such ffs2 command\n"); + return; + } + extargs = argc - 2; + if (extargs > tp->maxargs) { + printf("error: too many arguments\n"); + return; + } + if (extargs < tp->minargs) { + printf("error: too few arguments\n"); + return; + } + tp->func(argc - 1, argv + 1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/tmsh/ffs2resp.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,20 @@ +/* + * Handling of TMFFS2 responses from ETM + */ + +#include <sys/types.h> +#include <stdio.h> + +extern u_char rvi_msg[]; +extern int rvi_msg_len; + +void +handle_ffs2_response() +{ + if (rvi_msg[3]) + print_etm_pkt_raw("FFS2 error"); + else if (rvi_msg_len == 5) + async_msg_output("FFS2 command successful"); + else + print_etm_pkt_raw("FFS2 response"); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/tmsh/ffs2wr.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,111 @@ +/* + * In this module we are going to implement some high-level FFS write + * operations, using the TMFFS2 protocol. + */ + +#include <sys/types.h> +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "limits.h" +#include "localtypes.h" +#include "etm.h" +#include "ffs.h" +#include "tmffs2.h" + +void +send_file_write(filename, data, size) + char *filename; + u_char *data; +{ + u_char cmdpkt[MAX_PKT_TO_TARGET], *dp; + + dp = cmdpkt + 1; + *dp++ = ETM_FFS2; + *dp++ = TMFFS_FILE_WRITE; + *dp++ = strlen(filename) + 1; + strcpy(dp, filename); + dp += strlen(filename) + 1; + *dp++ = size; /* data size in bytes */ + bcopy(data, dp, size); + dp += size; + *dp++ = FFS_O_CREATE | FFS_O_TRUNC; + send_etm_cmd(cmdpkt, dp - cmdpkt - 1); +} + +void +cmd_set_imeisv(argc, argv) + char **argv; +{ + char *filename, *cp, digits[16]; + u_char bytes[8]; + int pcm_order, i; + + if (!strcmp(argv[1], "pcm")) { + filename = "/pcm/IMEI"; + pcm_order = 1; + } else if (!strcmp(argv[1], "fc")) { + filename = "/etc/IMEISV"; + pcm_order = 0; + } else { + printf( + "error: IMEISV storage type argument must be \"pcm\" or \"fc\"\n"); + return; + } + cp = argv[2]; + if (!isdigit(*cp)) { +inv: printf("error: 2nd argument must have 16 decimal digits\n"); + return; + } + for (i = 0; i < 16; i++) { + if (ispunct(*cp)) + cp++; + if (!isdigit(*cp)) + goto inv; + digits[i] = *cp++ - '0'; + } + if (*cp) + goto inv; + for (i = 0; i < 8; i++) + bytes[i] = pcm_order ? digits[i*2+1] << 4 | digits[i*2] + : digits[i*2] << 4 | digits[i*2+1]; + printf("Writing \"%02X %02X %02X %02X %02X %02X %02X %02X\" into %s\n", + bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], + bytes[6], bytes[7], filename); + send_file_write(filename, bytes, 8); +} + +void +cmd_set_pcm_string(argc, argv) + char **argv; +{ + char filename[16]; + + if (strcmp(argv[1], "CGMI") && strcmp(argv[1], "CGMM") && + strcmp(argv[1], "CGMR") && strcmp(argv[1], "CGSN")) { + printf("error: \"%s\" is not a recognized PCM string file name\n", + argv[1]); + return; + } + sprintf(filename, "/pcm/%s", argv[1]); + if (strlen(argv[2]) > 20) { + printf("error: %s string may not exceed 20 characters\n", + filename); + return; + } + send_file_write(filename, argv[2], strlen(argv[2])); +} + +void +cmd_set_rfcap(argc, argv) + char **argv; +{ + u_char bytes[16]; + int i; + + for (i = 0; i < 16; i++) + bytes[i] = strtoul(argv[i+1], 0, 16); + send_file_write("/gsm/com/rfcap", bytes, 16); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/tmsh/init.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,31 @@ +/* + * This module contains the initialization code for fc-tmsh. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "pktmux.h" +#include "localsock.h" + +extern int sock; + +init() +{ + static u_char want_rvt_lost[9] = {CLI2RVI_WANT_RVTRACE, + 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00}; + static u_char want_rvt_etm[9] = {CLI2RVI_WANT_RVTRACE, + 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x1E, 0x00, 0x04}; + static u_char want_etm_mux[2] = {CLI2RVI_WANT_MUXPROTO, RVT_TM_HEADER}; + + if (!sock) + connect_local_socket(); + localsock_prep_for_length_rx(); + send_init_command(want_rvt_lost, 9); + send_init_command(want_rvt_etm, 9); + send_init_command(want_etm_mux, 2); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/tmsh/main.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,86 @@ +/* + * This module contains the main() function for fc-tmsh. + */ + +#include <sys/types.h> +#include <sys/errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +char *socket_pathname = "/tmp/rvinterf_socket"; +int ttyhacks, dflag; + +int sock; + +extern char *rvinterf_Bopt, *rvinterf_lopt, *rvinterf_wopt; + +main(argc, argv) + char **argv; +{ + extern int optind; + extern char *optarg; + int c; + fd_set fds; + + while ((c = getopt(argc, argv, "B:dl:s:w:")) != EOF) + switch (c) { + case 'B': + rvinterf_Bopt = optarg; + continue; + case 'd': + dflag++; + continue; + case 'l': + rvinterf_lopt = optarg; + continue; + case 's': + socket_pathname = optarg; + continue; + case 'w': + rvinterf_wopt = optarg; + continue; + case '?': + default: +usage: fprintf(stderr, + "usage: %s [options] [ttyport]\n", argv[0]); + exit(1); + } + switch (argc - optind) { + case 0: + if (rvinterf_Bopt || rvinterf_lopt || rvinterf_wopt) { + fprintf(stderr, + "%s: -B, -l and -w options are meaningful only when launching rvinterf\n", + argv[0]); + exit(1); + } + break; + case 1: + launch_rvinterf(argv[optind]); + break; + default: + goto usage; + } + + ttyhacks = isatty(0) && !dflag; + init(); + tty_init(); + for (;;) { + FD_ZERO(&fds); + FD_SET(0, &fds); + FD_SET(sock, &fds); + c = select(sock+1, &fds, 0, 0, 0); + if (c < 0) { + if (errno == EINTR) + continue; + tty_cleanup(); + perror("select"); + exit(1); + } + if (FD_ISSET(0, &fds)) + handle_tty_input(); + if (FD_ISSET(sock, &fds)) + handle_rvinterf_input(); + fflush(stdout); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/tmsh/misc.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,24 @@ +/* + * Commands which don't belong anywhere else + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "pktmux.h" +#include "etm.h" +#include "tmffs1.h" + +void +cmd_check_ffs1(argc, argv) + char **argv; +{ + u_char cmdpkt[5]; + + cmdpkt[1] = ETM_FFS1; + cmdpkt[2] = FPI_TMFFS_VERSION; + cmdpkt[3] = FPI_END; + send_etm_cmd(cmdpkt, 3); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/tmsh/omr.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,94 @@ +/* + * Old-style memory read command + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "pktmux.h" +#include "limits.h" +#include "localtypes.h" +#include "tm3.h" + +extern u_char rvi_msg[]; +extern int rvi_msg_len; + +static void +memdump_line(off, inbuf, len) + u_char *inbuf; +{ + char outbuf[80], *dp; + int i, c; + + sprintf(outbuf, "omr %02X: ", off); + dp = index(outbuf, '\0'); + for (i = 0; i < 16; i++) { + if (i < len) + sprintf(dp, "%02X ", inbuf[i]); + else + strcpy(dp, " "); + dp += 3; + if (i == 7 || i == 15) + *dp++ = ' '; + } + for (i = 0; i < len; i++) { + c = inbuf[i]; + if (c < ' ' || c > '~') + c = '.'; + *dp++ = c; + } + *dp = '\0'; + async_msg_output(outbuf); +} + +void +handle_omr_response() +{ + int off, len; + + if (rvi_msg[3]) { + print_etm_pkt_raw("TM3 memread error"); + return; + } + if (rvi_msg_len < 10) { +bad: print_etm_pkt_raw("omr bad resp"); + return; + } + if (rvi_msg[5] || rvi_msg[6] || rvi_msg[7]) + goto bad; + if (rvi_msg_len != rvi_msg[4] + 9) + goto bad; + for (off = 0; off < rvi_msg[4]; off += len) { + len = rvi_msg[4] - off; + if (len > 16) + len = 16; + memdump_line(off, rvi_msg + 8 + off, len); + } +} + +void +cmd_omr(argc, argv) + char **argv; +{ + u32 addr, size; + u_char cmdpkt[11]; + + addr = strtoul(argv[1], 0, 16); + size = strtoul(argv[2], 0, 16); + if (size < 1 || size > TM3_MEMREAD_MAX) { + printf("error: count argument outside valid range\n"); + return; + } + cmdpkt[1] = MEM_READ; + cmdpkt[2] = addr; + cmdpkt[3] = addr >> 8; + cmdpkt[4] = addr >> 16; + cmdpkt[5] = addr >> 24; + cmdpkt[6] = size; + cmdpkt[7] = 0; + cmdpkt[8] = 0; + cmdpkt[9] = 0; + send_etm_cmd(cmdpkt, 9); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/tmsh/pktsort.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,72 @@ +/* + * Here we sort out incoming packets from the target relayed via rvinterf. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "pktmux.h" +#include "limits.h" +#include "localsock.h" +#include "localtypes.h" +#include "etm.h" + +extern u_char rvi_msg[]; +extern int rvi_msg_len; + +static void +print_etm_trace() +{ + char buf[MAX_PKT_FROM_TARGET*4]; + + strcpy(buf, "ETM Tr: "); + safe_print_trace(rvi_msg + 7, rvi_msg_len - 7, buf + 8); + async_msg_output(buf); +} + +static void +process_rvt() +{ + u32 useid; + + if (rvi_msg_len < 7) { + tty_cleanup(); + fprintf(stderr, "Error: rvinterf sent us an invalid RVT msg\n"); + exit(1); + } + useid = rvi_msg[2] << 24 | rvi_msg[3] << 16 | rvi_msg[4] << 8 + | rvi_msg[5]; + switch (useid) { + case 0: + handle_useid_0(); + return; + case ETM_USE_ID: + print_etm_trace(); + return; + default: + tty_cleanup(); + fprintf(stderr, "unexpected fwd of USEID %08X from rvinterf\n", + useid); + exit(1); + } +} + +void +process_pkt_from_target() +{ + switch (rvi_msg[1]) { + case RVT_RV_HEADER: + process_rvt(); + return; + case RVT_TM_HEADER: + etm_packet_rx(); + return; + default: + tty_cleanup(); + fprintf(stderr, "unexpected fwd of MUX %02X from rvinterf\n", + rvi_msg[1]); + exit(1); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/tmsh/tmcore.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,448 @@ +/* + * In this module we are going to implement commands which send requests + * to ETM_CORE and the handling of responses from that target module. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "pktmux.h" +#include "limits.h" +#include "localtypes.h" +#include "etm.h" + +extern u_char rvi_msg[]; +extern int rvi_msg_len; + +static void +rw8_response() +{ + char buf[MAX_PKT_FROM_TARGET*3+80], *dp; + int num, i; + + if (rvi_msg[3]) { + print_etm_pkt_raw("rw8 error"); + return; + } + num = rvi_msg_len - 7; + if (!num) { + async_msg_output("w8 OK"); + return; + } + strcpy(buf, "r8:"); + dp = buf + 3; + for (i = 0; i < num; i++) { + sprintf(dp, " %02X", rvi_msg[i+6]); + dp += 3; + } + async_msg_output(buf); +} + +static void +rw16_response() +{ + char buf[MAX_PKT_FROM_TARGET*3+80], *dp; + int num, i, d, off; + + if (rvi_msg[3]) { + print_etm_pkt_raw("rw16 error"); + return; + } + num = rvi_msg_len - 7; + if (!num) { + async_msg_output("w16 OK"); + return; + } + if (num & 1) { + print_etm_pkt_raw("rw16 malformed resp"); + return; + } + num >>= 1; + strcpy(buf, "r16:"); + dp = buf + 4; + off = 6; + for (i = 0; i < num; i++) { + d = rvi_msg[off] | rvi_msg[off+1] << 8; + off += 2; + sprintf(dp, " %04X", d); + dp += 5; + } + async_msg_output(buf); +} + +static void +rw32_response() +{ + char buf[MAX_PKT_FROM_TARGET*3+80], *dp; + int num, i, d, off; + + if (rvi_msg[3]) { + print_etm_pkt_raw("rw32 error"); + return; + } + num = rvi_msg_len - 7; + if (!num) { + async_msg_output("w32 OK"); + return; + } + if (num & 3) { + print_etm_pkt_raw("rw32 malformed resp"); + return; + } + num >>= 2; + strcpy(buf, "r32:"); + dp = buf + 4; + off = 6; + for (i = 0; i < num; i++) { + d = rvi_msg[off] | rvi_msg[off+1] << 8 | rvi_msg[off+2] << 16 + | rvi_msg[off+3] << 24; + off += 4; + sprintf(dp, " %08X", d); + dp += 9; + } + async_msg_output(buf); +} + +static void +dieid_response() +{ + char buf[MAX_PKT_FROM_TARGET*3+80], *dp; + int num, i; + + if (rvi_msg[3]) { + print_etm_pkt_raw("dieid error"); + return; + } + num = rvi_msg_len - 6; + strcpy(buf, "dieid resp:"); + dp = buf + 11; + for (i = 0; i < num; i++) { + sprintf(dp, " %02X", rvi_msg[i+5]); + dp += 3; + } + async_msg_output(buf); +} + +static void +echo_response() +{ + if (rvi_msg[3]) + print_etm_pkt_raw("echo error"); + else + print_etm_pkt_raw("echo resp"); +} + +static void +version_response() +{ + char buf[80]; + + if (rvi_msg[3]) { + print_etm_pkt_raw("version error"); + return; + } + if (rvi_msg_len != 10) { + print_etm_pkt_raw("version malformed resp"); + return; + } + sprintf(buf, "version resp: %02X%02X%02X%02X", rvi_msg[8], rvi_msg[7], + rvi_msg[6], rvi_msg[5]); + async_msg_output(buf); +} + +void +tmcore_msg_rx() +{ + switch (rvi_msg[4]) { + case TMCORE_OPC_MEM: + if (rvi_msg_len < 7) + goto unknown; + switch (rvi_msg[5]) { + case 0x00: + case 0x04: + rw32_response(); + return; + case 0x01: + rw8_response(); + return; + case 0x02: + rw16_response(); + return; + default: + goto unknown; + } + case TMCORE_OPC_ECHO: + echo_response(); + return; + case TMCORE_OPC_VERSION: + version_response(); + return; + case TMCORE_OPC_CODEC_RD: + abbr_response(); + return; + case TMCORE_OPC_CODEC_WR: + abbw_response(); + return; + case TMCORE_OPC_DIEID: + dieid_response(); + return; + default: + unknown: + print_etm_pkt_raw("ETM_CORE resp"); + } +} + +void +cmd_r8(argc, argv) + char **argv; +{ + u32 addr; + int count; + u_char cmdpkt[10]; + + addr = strtoul(argv[1], 0, 16); + if (argv[2]) + count = strtoul(argv[2], 0, 0); + else + count = 1; + if (count < 1 || count > 253) { + printf("error: count argument outside valid range\n"); + return; + } + cmdpkt[1] = ETM_CORE; + cmdpkt[2] = TMCORE_OPC_MEM; + cmdpkt[3] = 0x01; + cmdpkt[4] = count; + cmdpkt[5] = addr; + cmdpkt[6] = addr >> 8; + cmdpkt[7] = addr >> 16; + cmdpkt[8] = addr >> 24; + send_etm_cmd(cmdpkt, 8); +} + +void +cmd_r16(argc, argv) + char **argv; +{ + u32 addr; + int count; + u_char cmdpkt[10]; + + addr = strtoul(argv[1], 0, 16); + if (argv[2]) + count = strtoul(argv[2], 0, 0); + else + count = 1; + if (addr & 1) { + printf("error: address not aligned\n"); + return; + } + if (count < 1 || count > 126) { + printf("error: count argument outside valid range\n"); + return; + } + cmdpkt[1] = ETM_CORE; + cmdpkt[2] = TMCORE_OPC_MEM; + cmdpkt[3] = 0x02; + cmdpkt[4] = count; + cmdpkt[5] = addr; + cmdpkt[6] = addr >> 8; + cmdpkt[7] = addr >> 16; + cmdpkt[8] = addr >> 24; + send_etm_cmd(cmdpkt, 8); +} + +void +cmd_r32(argc, argv) + char **argv; +{ + u32 addr; + int count; + u_char cmdpkt[10]; + + addr = strtoul(argv[1], 0, 16); + if (argv[2]) + count = strtoul(argv[2], 0, 0); + else + count = 1; + if (addr & 3) { + printf("error: address not aligned\n"); + return; + } + if (count < 1 || count > 63) { + printf("error: count argument outside valid range\n"); + return; + } + cmdpkt[1] = ETM_CORE; + cmdpkt[2] = TMCORE_OPC_MEM; + cmdpkt[3] = 0x04; + cmdpkt[4] = count; + cmdpkt[5] = addr; + cmdpkt[6] = addr >> 8; + cmdpkt[7] = addr >> 16; + cmdpkt[8] = addr >> 24; + send_etm_cmd(cmdpkt, 8); +} + +void +cmd_w8(argc, argv) + char **argv; +{ + u32 addr, v; + u_char cmdpkt[MAX_PKT_TO_TARGET]; + int di; + char **ap; + + addr = strtoul(argv[1], 0, 16); + cmdpkt[1] = ETM_CORE; + cmdpkt[2] = TMCORE_OPC_MEM; + cmdpkt[3] = 0x11; + cmdpkt[4] = argc - 2; + cmdpkt[5] = addr; + cmdpkt[6] = addr >> 8; + cmdpkt[7] = addr >> 16; + cmdpkt[8] = addr >> 24; + di = 9; + for (ap = argv + 2; *ap; ap++) { + v = strtoul(*ap, 0, 16); + cmdpkt[di++] = v; + } + send_etm_cmd(cmdpkt, di - 1); +} + +void +cmd_w16(argc, argv) + char **argv; +{ + u32 addr, v; + u_char cmdpkt[MAX_PKT_TO_TARGET]; + int di; + char **ap; + + addr = strtoul(argv[1], 0, 16); + if (addr & 1) { + printf("error: address not aligned\n"); + return; + } + cmdpkt[1] = ETM_CORE; + cmdpkt[2] = TMCORE_OPC_MEM; + cmdpkt[3] = 0x12; + cmdpkt[4] = argc - 2; + cmdpkt[5] = addr; + cmdpkt[6] = addr >> 8; + cmdpkt[7] = addr >> 16; + cmdpkt[8] = addr >> 24; + di = 9; + for (ap = argv + 2; *ap; ap++) { + v = strtoul(*ap, 0, 16); + cmdpkt[di++] = v; + cmdpkt[di++] = v >> 8; + } + send_etm_cmd(cmdpkt, di - 1); +} + +void +cmd_w32(argc, argv) + char **argv; +{ + u32 addr, v; + u_char cmdpkt[MAX_PKT_TO_TARGET]; + int di; + char **ap; + + addr = strtoul(argv[1], 0, 16); + if (addr & 3) { + printf("error: address not aligned\n"); + return; + } + cmdpkt[1] = ETM_CORE; + cmdpkt[2] = TMCORE_OPC_MEM; + cmdpkt[3] = 0x14; + cmdpkt[4] = argc - 2; + cmdpkt[5] = addr; + cmdpkt[6] = addr >> 8; + cmdpkt[7] = addr >> 16; + cmdpkt[8] = addr >> 24; + di = 9; + for (ap = argv + 2; *ap; ap++) { + v = strtoul(*ap, 0, 16); + cmdpkt[di++] = v; + cmdpkt[di++] = v >> 8; + cmdpkt[di++] = v >> 16; + cmdpkt[di++] = v >> 24; + } + send_etm_cmd(cmdpkt, di - 1); +} + +void +cmd_dieid(argc, argv) + char **argv; +{ + u_char cmdpkt[4]; + + cmdpkt[1] = ETM_CORE; + cmdpkt[2] = TMCORE_OPC_DIEID; + send_etm_cmd(cmdpkt, 2); +} + +void +cmd_ping(argc, argv) + char **argv; +{ + int delay, size; + u_char cmdpkt[8]; + + if (argc > 1) { + delay = strtoul(argv[1], 0, 0); + if (delay > 65535) { + printf("error: ping delay argument too big\n"); + return; + } + } else + delay = 0; + if (argc > 2) { + size = strtoul(argv[2], 0, 0); + if (size > 240) { + printf("error: ping size argument too big\n"); + return; + } + } else + size = 1; + cmdpkt[1] = ETM_CORE; + cmdpkt[2] = TMCORE_OPC_ECHO; + cmdpkt[3] = delay; + cmdpkt[4] = delay >> 8; + cmdpkt[5] = size; + cmdpkt[6] = size >> 8; + send_etm_cmd(cmdpkt, 6); +} + +void +cmd_tgtreset(argc, argv) + char **argv; +{ + u_char cmdpkt[4]; + + cmdpkt[1] = ETM_CORE; + cmdpkt[2] = TMCORE_OPC_RESET; + send_etm_cmd(cmdpkt, 2); +} + +void +cmd_version(argc, argv) + char **argv; +{ + u32 arg; + u_char cmdpkt[8]; + + arg = strtoul(argv[1], 0, 16); + cmdpkt[1] = ETM_CORE; + cmdpkt[2] = TMCORE_OPC_VERSION; + cmdpkt[3] = arg; + cmdpkt[4] = arg >> 8; + cmdpkt[5] = arg >> 16; + cmdpkt[6] = arg >> 24; + send_etm_cmd(cmdpkt, 6); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/tmsh/usercmd.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,126 @@ +/* + * This module implements fc-tmsh user command dispatch. + */ + +#include <sys/types.h> +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> + +extern char usercmd[]; + +extern void cmd_abbr(); +extern void cmd_abbw(); +extern void cmd_check_ffs1(); +extern void cmd_dieid(); +extern void cmd_etmpkt(); +extern void cmd_ffs2(); +extern void cmd_omr(); +extern void cmd_ping(); +extern void cmd_r8(); +extern void cmd_r16(); +extern void cmd_r32(); +extern void cmd_set_imeisv(); +extern void cmd_set_pcm_string(); +extern void cmd_set_rfcap(); +extern void cmd_tgtreset(); +extern void cmd_version(); +extern void cmd_w8(); +extern void cmd_w16(); +extern void cmd_w32(); + +void +cmd_exit() +{ + tty_cleanup(); + exit(0); +} + +static struct cmdtab { + char *cmd; + int minargs; + int maxargs; + void (*func)(); +} cmdtab[] = { + {"abbr", 2, 2, cmd_abbr}, + {"abbw", 3, 3, cmd_abbw}, + {"check-ffs1", 0, 0, cmd_check_ffs1}, + {"dieid", 0, 0, cmd_dieid}, + {"etmpkt", 1, 253, cmd_etmpkt}, + {"exit", 0, 0, cmd_exit}, + {"ffs2", 1, 3, cmd_ffs2}, + {"omr", 2, 2, cmd_omr}, + {"ping", 0, 2, cmd_ping}, + {"quit", 0, 0, cmd_exit}, + {"r8", 1, 2, cmd_r8}, + {"r16", 1, 2, cmd_r16}, + {"r32", 1, 2, cmd_r32}, + {"set-imeisv", 2, 2, cmd_set_imeisv}, + {"set-pcm-string", 2, 2, cmd_set_pcm_string}, + {"set-rfcap", 16, 16, cmd_set_rfcap}, + {"tgtreset", 0, 0, cmd_tgtreset}, + {"version", 1, 1, cmd_version}, + {"w8", 2, 246, cmd_w8}, + {"w16", 2, 123, cmd_w16}, + {"w32", 2, 62, cmd_w32}, + {0, 0, 0, 0} +}; + +void +dispatch_user_cmd() +{ + char *argv[257]; + char *cp, **ap; + struct cmdtab *tp; + + for (cp = usercmd; isspace(*cp); cp++) + ; + if (!*cp || *cp == '#') + return; + argv[0] = cp; + while (*cp && !isspace(*cp)) + cp++; + if (*cp) + *cp++ = '\0'; + for (tp = cmdtab; tp->cmd; tp++) + if (!strcmp(tp->cmd, argv[0])) + break; + if (!tp->func) { + printf("error: no such command\n"); + return; + } + for (ap = argv + 1; ; ) { + while (isspace(*cp)) + cp++; + if (!*cp || *cp == '#') + break; + if (ap - argv - 1 >= tp->maxargs) { + printf("error: too many arguments\n"); + return; + } + if (*cp == '"') { + *ap++ = ++cp; + while (*cp && *cp != '"') + cp++; + if (*cp != '"') { + printf("error: unterminated quoted string\n"); + return; + } + *cp++ = '\0'; + } else { + *ap++ = cp; + while (*cp && !isspace(*cp)) + cp++; + if (*cp) + *cp++ = '\0'; + } + } + if (ap - argv - 1 < tp->minargs) { + printf("error: too few arguments\n"); + return; + } + *ap = 0; + tp->func(ap - argv, argv); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,30 @@ +FOR_LOADTOOLS= compalstage loadagent +ALLPROGS= ${FOR_LOADTOOLS} c139explore c139-lldbg helloapp pirexplore \ + tf-breakin +LIBS= libbase libcommon libload libprintf libtiffs +SUBDIR= ${ALLPROGS} ${LIBS} + +default: ${FOR_LOADTOOLS} +all: ${ALLPROGS} + +c139explore: libbase libcommon libprintf +c139-lldbg: libbase libcommon libprintf +helloapp: libbase libcommon libprintf +loadagent: libbase libcommon libload libprintf +pirexplore: libbase libcommon libprintf libtiffs + +${SUBDIR}: FRC + cd $@; ${MAKE} ${MFLAGS} + +install: FRC + for i in ${FOR_LOADTOOLS}; do (cd $$i; ${MAKE} ${MFLAGS} install); done + +clean: FRC + rm -f a.out core errs + for i in ${SUBDIR}; do \ + if [ -d $$i ]; then \ + (cd $$i; ${MAKE} ${MFLAGS} clean) \ + fi \ + done + +FRC:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/README Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,34 @@ +The following target utilities or code components are currently buildable in +this target-utils tree: + +compalstage For Compal phones only: a little piece of code that is fed to + the original fw's bootloader via the serial download protocol + provided by the latter; it re-enables the Calypso chip boot ROM + and jumps to it, allowing our loadagent to be loaded in the + same way as on freedom-enabled devices. + +helloapp Template/skeleton for building programs like loadagent and + pirexplore. + +loadagent Loadagent is built to be loaded and run out of the Calypso + internal (on-chip) RAM, and does not depend on any hardware + outside of the Calypso chip itself - thus it should run + unchanged on all Calypso targets. It expects to be loaded by + the Calypso ROM bootloader in the UART download mode, and it + reads a RAM variable left behind by the ROM code that indicates + which UART has been used to perform that download - it then + uses that same UART to communicate with the host, presenting an + interactive command prompt. You can run loadagent "raw" by + loading loadagent.srec with fc-iram, but normally it is used + "behind the scenes" by fc-loadtool and fc-xram. + +pirexplore For Pirelli DP-L10 target only: this program is built in the + same manner as loadagent (also runs out of IRAM, expects to be + loaded with fc-iram, and presents an interactive command prompt + on the autodetected UART), but it automatically performs some + hardware (board level) initialization specific to the Pirelli, + and offers additional commands for exploring the hardware + features of this device. + +tf-breakin Here we build the payload for the tfc139 hack-utility; see + ../rvinterf/lowlevel/tfc139.c for the ugly details.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/c139-lldbg/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,27 @@ +CC= arm-elf-gcc +CFLAGS= -Os -fno-builtin +CPPFLAGS=-I../include +LD= arm-elf-ld +OBJCOPY=arm-elf-objcopy + +PROG= lldbg +OBJS= entry.o cmdtab.o entryinfo.o main.o mygetchar.o uartbase.o +LIBS= ../libcommon/libcommon.a ../libprintf/libprintf.a ../libbase/libbase.a +LDS= lldbg.lds + +TC_LIBS=`${CC} -print-file-name=libc.a` \ + `${CC} -print-file-name=libgcc.a` + +all: ${PROG}.bin + +${PROG}.elf: ${OBJS} ${LIBS} ${LDS} + ${LD} -N -T ${LDS} -o $@ ${OBJS} ${LIBS} \ + --start-group ${TC_LIBS} --end-group + +${PROG}.bin: ${PROG}.elf + ${OBJCOPY} -O binary $< $@ + +clean: + rm -f *.o *errs *core *.elf *.bin *.srec crt0.S + +FRC:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/c139-lldbg/cmdtab.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,23 @@ +#include "cmdtab.h" + +extern void cmd_entryinfo(); +extern void cmd_r8(); +extern void cmd_r16(); +extern void cmd_r32(); +extern void cmd_w8(); +extern void cmd_w16(); +extern void cmd_w32(); + +extern void cmd_memdump_human(); + +const struct cmdtab cmdtab[] = { + {"dump", cmd_memdump_human}, + {"entry", cmd_entryinfo}, + {"r8", cmd_r8}, + {"r16", cmd_r16}, + {"r32", cmd_r32}, + {"w8", cmd_w8}, + {"w16", cmd_w16}, + {"w32", cmd_w32}, + {0, 0} +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/c139-lldbg/entry.S Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,20 @@ + .text + .globl _entry +_entry: + .code 16 + bx pc + nop + + .code 32 + stmfd sp!, {r0-r12,lr} + mrs r0, CPSR + mov r1, sp + /* supervisor mode, disable all interrupts */ + msr CPSR_c, #0xd3 + ldr sp, =stack_bottom + /* save entry SP and CPSR */ + ldr r2, =lldbg_entry_cpsr + str r0, [r2] + ldr r2, =lldbg_entry_sp + str r1, [r2] + b main
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/c139-lldbg/entryinfo.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,11 @@ +#include "types.h" + +u32 lldbg_entry_cpsr; +u32 lldbg_entry_sp; + +void +cmd_entryinfo() +{ + printf("CPSR on entry: %08X\n", lldbg_entry_cpsr); + printf("SP on entry after register save: %08X\n", lldbg_entry_sp); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/c139-lldbg/lldbg.lds Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,42 @@ +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_entry) +SECTIONS +{ + /* code */ + . = 0x3B0000; + .text : { + /* regular code */ + *(.text*) + /* gcc voodoo */ + *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx) + . = ALIGN(4); + } + + /* read-only data */ + . = ALIGN(4); + .rodata : { + *(.rodata*) + } + + /* initialized data */ + . = ALIGN(4); + .data : { + *(.data) + } + PROVIDE(edata = .); + + /* uninitialized data */ + .bss 0x83C000 (NOLOAD) : { + . = ALIGN(4); + __bss_start = .; + *(.bss) + } + . = ALIGN(4); + __bss_end = .; + /* end of image */ + _end = .; + PROVIDE(end = .); +} + +stack_bottom = 0x83FFFC;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/c139-lldbg/main.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,9 @@ +main() +{ + printf("\2\2\2*Standalone Low Level Debugger entered\2"); + for (;;) { + putchar('>'); + if (command_entry()) + command_dispatch(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/c139-lldbg/mygetchar.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,21 @@ +/* + * The interactive command entry (editing) function in libcommon + * will call mygetchar() for its character input. It is supposed + * to be a blocking wait for input, but in some programs other + * processing can be done while waiting - for example, check for + * keypad presses as well. This is the basic version which waits + * for serial input and nothing else. + */ + +extern int serial_in_poll(); + +int +mygetchar() +{ + register int c; + + do + c = serial_in_poll(); + while (c < 0); + return c; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/c139-lldbg/uartbase.S Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,5 @@ + .section .rodata + .balign 4 + .globl uart_base +uart_base: + .word 0xFFFF5800
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/c139explore/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,30 @@ +CC= arm-elf-gcc +CFLAGS= -Os -fno-builtin +CPPFLAGS=-I../include +LD= arm-elf-ld +OBJCOPY=arm-elf-objcopy + +PROG= c139explore +OBJS= crt0.o backlight.o cmdtab.o lcd.o main.o mygetchar.o uartbase.o uwire.o +LIBS= ../libcommon/libcommon.a ../libprintf/libprintf.a ../libbase/libbase.a +LDS= ../env/compalram.lds + +TC_LIBS=`${CC} -print-file-name=libc.a` \ + `${CC} -print-file-name=libgcc.a` + +all: ${PROG}.bin + +crt0.S: ../env/crt0.S + ln -s $< . + +${PROG}.elf: ${OBJS} ${LIBS} ${LDS} + ${LD} -N -T ${LDS} -o $@ ${OBJS} ${LIBS} \ + --start-group ${TC_LIBS} --end-group + +${PROG}.bin: ${PROG}.elf + ${OBJCOPY} -O binary $< $@ + +clean: + rm -f *.o *errs *core *.elf *.bin *.srec crt0.S + +FRC:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/c139explore/backlight.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,42 @@ +#include <sys/types.h> +#include <string.h> +#include "types.h" +#include "abbdefs.h" + +#define GPIO_OUT_REG (*(volatile u16 *) 0xfffe4802) +#define BACKLIGHT_GPIO_MASK 0x0002 + +#define AUXLED_KPBL_OFF 0x000 +#define AUXLED_KPBL_ON 0x002 + +void +cmd_dbl(argbulk) + char *argbulk; +{ + char *argv[2]; + + if (parse_args(argbulk, 1, 1, argv, 0) < 0) + return; + if (!strcmp(argv[0], "on")) + GPIO_OUT_REG |= BACKLIGHT_GPIO_MASK; + else if (!strcmp(argv[0], "off")) + GPIO_OUT_REG &= ~BACKLIGHT_GPIO_MASK; + else + printf("ERROR: \"on\" or \"off\" argument expected\n"); +} + +void +cmd_kpbl(argbulk) + char *argbulk; +{ + char *argv[2]; + + if (parse_args(argbulk, 1, 1, argv, 0) < 0) + return; + if (!strcmp(argv[0], "on")) + abb_reg_write(AUXLED, AUXLED_KPBL_ON); + else if (!strcmp(argv[0], "off")) + abb_reg_write(AUXLED, AUXLED_KPBL_OFF); + else + printf("ERROR: \"on\" or \"off\" argument expected\n"); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/c139explore/cmdtab.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,47 @@ +#include "cmdtab.h" + +extern void cmd_abbr(); +extern void cmd_abbw(); +extern void cmd_dbl(); +extern void cmd_hbars(); +extern void cmd_jump(); +extern void cmd_kpbl(); +extern void cmd_lcdcmd(); +extern void cmd_lcdfill(); +extern void cmd_lcdinit(); +extern void cmd_lcdpix(); +extern void cmd_r8(); +extern void cmd_r16(); +extern void cmd_r32(); +extern void cmd_vbars(); +extern void cmd_w8(); +extern void cmd_w16(); +extern void cmd_w32(); + +extern void abb_init(); +extern void abb_power_off(); +extern void cmd_memdump_human(); + +const struct cmdtab cmdtab[] = { + {"abbinit", abb_init}, + {"abbr", cmd_abbr}, + {"abbw", cmd_abbw}, + {"dbl", cmd_dbl}, + {"dump", cmd_memdump_human}, + {"hbars", cmd_hbars}, + {"jump", cmd_jump}, + {"kpbl", cmd_kpbl}, + {"lcdcmd", cmd_lcdcmd}, + {"lcdfill", cmd_lcdfill}, + {"lcdinit", cmd_lcdinit}, + {"lcdpix", cmd_lcdpix}, + {"poweroff", abb_power_off}, + {"r8", cmd_r8}, + {"r16", cmd_r16}, + {"r32", cmd_r32}, + {"vbars", cmd_vbars}, + {"w8", cmd_w8}, + {"w16", cmd_w16}, + {"w32", cmd_w32}, + {0, 0} +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/c139explore/lcd.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,174 @@ +#include <sys/types.h> +#include "types.h" + +static void +send_cmd_data(cmdbyte, databyte) +{ + send_via_uwire(cmdbyte); + send_via_uwire(databyte | 0x100); +} + +void +cmd_lcdcmd(argbulk) + char *argbulk; +{ + char *argv[3]; + u_long cmd, data; + + if (parse_args(argbulk, 2, 2, argv, 0) < 0) + return; + if (parse_hexarg(argv[0], 2, &cmd) < 0) { + printf("ERROR: arg1 must be a valid 8-bit hex value\n"); + return; + } + if (parse_hexarg(argv[1], 2, &data) < 0) { + printf("ERROR: arg2 must be a valid 8-bit hex value\n"); + return; + } + send_cmd_data(cmd, data); +} + +static void +send_pixel_value(pix) +{ + send_via_uwire((pix >> 8) | 0x100); + send_via_uwire((pix & 0xFF) | 0x100); +} + +void +cmd_lcdpix(argbulk) + char *argbulk; +{ + char *argv[2]; + u_long pixval; + + if (parse_args(argbulk, 1, 1, argv, 0) < 0) + return; + if (parse_hexarg(argv[0], 4, &pixval) < 0) { + printf("ERROR: arg1 must be a valid 16-bit hex value\n"); + return; + } + send_pixel_value(pixval); +} + +void +cmd_lcdinit() +{ + /* from OsmocomBB */ + send_cmd_data(0x3F, 0x01); + send_cmd_data(0x20, 0x03); + send_cmd_data(0x31, 0x03); +} + +static void +set_lcd_addr_region(xstart, xend, ystart, yend) +{ + send_cmd_data(0x10, xstart); + send_cmd_data(0x11, ystart); + send_cmd_data(0x12, xend); + send_cmd_data(0x13, yend); + send_cmd_data(0x14, xstart); + send_cmd_data(0x15, ystart); +} + +void +cmd_lcdfill(argbulk) + char *argbulk; +{ + int argc; + char *argv[6]; + u_long pixval; + int xstart, xend, ystart, yend; + int npix; + + if (parse_args(argbulk, 1, 5, argv, &argc) < 0) + return; + if (parse_hexarg(argv[0], 4, &pixval) < 0) { + printf("ERROR: arg1 must be a valid 16-bit hex value\n"); + return; + } + switch (argc) { + case 1: + xstart = ystart = 0; + xend = 95; + yend = 63; + break; + case 5: + xstart = atoi(argv[1]); + if (xstart < 0 || xstart > 95) { +range_err: printf("ERROR: coordinate arg out of range\n"); + return; + } + xend = atoi(argv[2]); + if (xend < 0 || xend > 95) + goto range_err; + ystart = atoi(argv[3]); + if (ystart < 0 || ystart > 63) + goto range_err; + yend = atoi(argv[4]); + if (yend < 0 || yend > 63) + goto range_err; + if (xend < xstart || yend < ystart) { + printf("ERROR: negative range\n"); + return; + } + break; + default: + printf("ERROR: wrong number of arguments\n"); + return; + } + set_lcd_addr_region(xstart, xend, ystart, yend); + npix = (xend + 1 - xstart) * (yend + 1 - ystart); + while (npix--) + send_pixel_value(pixval); +} + +void +cmd_hbars() +{ + int i, j, k, p; + + /* + * The result of this command should be 8 horizontal bars + * in the natural RGB order. + */ + set_lcd_addr_region(16, 79, 0, 63); + for (i = 0; i < 8; i++) { + for (j = 0; j < 8; j++) { + p = 0; + if (i & 4) + p |= 0xF800; + if (i & 2) + p |= 0x07E0; + if (i & 1) + p |= 0x001F; + for (k = 0; k < 64; k++) + send_pixel_value(p); + } + } +} + +void +cmd_vbars() +{ + int i, j, k, p; + + /* + * The result of this command should be 8 vertical bars + * in the natural RGB order. + */ + set_lcd_addr_region(16, 79, 0, 63); + for (i = 0; i < 64; i++) { + for (j = 0; j < 8; j++) { + p = 0; + if (j & 4) + p |= 0xF800; + if (j & 2) + p |= 0x07E0; + if (j & 1) + p |= 0x001F; + for (k = 0; k < 8; k++) + send_pixel_value(p); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/c139explore/main.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,20 @@ +#include "types.h" + +main() +{ + /* delay kludge workaround for defect in fc-compalram */ + osmo_delay_ms(30); + printf("C139 hardware exploration utility running\n"); + /* GPIO init */ + *(volatile u16 *)0xfffe4802 = 0x0002; + *(volatile u16 *)0xfffe4804 = 0xFFF5; + /* take peripherals out of reset */ + *(volatile u16 *)0xfffffd04 = 0xFFF3; + abb_init(); + uwire_init(); + for (;;) { + putchar('='); + if (command_entry()) + command_dispatch(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/c139explore/mygetchar.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,21 @@ +/* + * The interactive command entry (editing) function in libcommon + * will call mygetchar() for its character input. It is supposed + * to be a blocking wait for input, but in some programs other + * processing can be done while waiting - for example, check for + * keypad presses as well. This is the basic version which waits + * for serial input and nothing else. + */ + +extern int serial_in_poll(); + +int +mygetchar() +{ + register int c; + + do + c = serial_in_poll(); + while (c < 0); + return c; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/c139explore/uartbase.S Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,5 @@ + .section .rodata + .balign 4 + .globl uart_base +uart_base: + .word 0xFFFF5800
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/c139explore/uwire.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,103 @@ +/* Driver for uWire Master Controller inside TI Calypso */ +/* lifted from OsmocomBB and ported to FreeCalypso target-utils environment */ + +/* (C) 2010 by Sylvain Munaut <tnt@246tNt.com> + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include "types.h" + +struct uwire_regs { + u16 reg_data; + u16 reg_csr; + u16 reg_sr1; + u16 reg_sr2; + u16 reg_sr3; +}; + +#define UWIRE_REGS (*(volatile struct uwire_regs *) 0xFFFE4000) + +#define UWIRE_CSR_BITS_RD(n) (((n) & 0x1f) << 0) +#define UWIRE_CSR_BITS_WR(n) (((n) & 0x1f) << 5) +#define UWIRE_CSR_IDX(n) (((n) & 3) << 10) +#define UWIRE_CSR_CS_CMD (1 << 12) +#define UWIRE_CSR_START (1 << 13) +#define UWIRE_CSR_CSRB (1 << 14) +#define UWIRE_CSR_RDRB (1 << 15) + +#define UWIRE_CSn_EDGE_RD (1 << 0) /* 1=falling 0=rising */ +#define UWIRE_CSn_EDGE_WR (1 << 1) /* 1=falling 0=rising */ +#define UWIRE_CSn_CS_LVL (1 << 2) +#define UWIRE_CSn_FRQ_DIV2 (0 << 3) +#define UWIRE_CSn_FRQ_DIV4 (1 << 3) +#define UWIRE_CSn_FRQ_DIV8 (2 << 3) +#define UWIRE_CSn_CKH + +#define UWIRE_CSn_SHIFT(n) (((n) & 1) ? 6 : 0) +#define UWIRE_CSn_REG(n) (((n) & 2) ? REG_SR2 : REG_SR1) + +#define UWIRE_SR3_CLK_EN (1 << 0) +#define UWIRE_SR3_CLK_DIV2 (0 << 1) +#define UWIRE_SR3_CLK_DIV4 (1 << 1) +#define UWIRE_SR3_CLK_DIV7 (2 << 1) +#define UWIRE_SR3_CLK_DIV10 (3 << 1) + +static inline void _uwire_wait(int mask, int val) +{ + while ((UWIRE_REGS.reg_csr & mask) != val); +} + +/* + * Let's try changing the chip select logic from OsmocomBB way + * to the way seen in TI's R2D source. + */ + +void uwire_init(void) +{ + UWIRE_REGS.reg_sr3 = UWIRE_SR3_CLK_EN | UWIRE_SR3_CLK_DIV2; + UWIRE_REGS.reg_sr1 = UWIRE_CSn_FRQ_DIV2; +#if 0 + UWIRE_REGS.reg_sr1 = UWIRE_CSn_CS_LVL | UWIRE_CSn_FRQ_DIV2; + UWIRE_REGS.reg_csr = UWIRE_CSR_IDX(0) | UWIRE_CSR_CS_CMD; + _uwire_wait(UWIRE_CSR_CSRB, 0); +#endif +} + +send_via_uwire(word) + unsigned word; +{ +#if 0 + /* select the chip */ + UWIRE_REGS.reg_csr = UWIRE_CSR_IDX(0) | UWIRE_CSR_CS_CMD; + _uwire_wait(UWIRE_CSR_CSRB, 0); +#endif + + UWIRE_REGS.reg_data = word << 7; + UWIRE_REGS.reg_csr = UWIRE_CSR_BITS_WR(9) | UWIRE_CSR_START + | UWIRE_CSR_CS_CMD; + _uwire_wait(UWIRE_CSR_CSRB, 0); + + /* unselect the chip */ + UWIRE_REGS.reg_csr = UWIRE_CSR_IDX(0) | 0; +#if 0 + _uwire_wait(UWIRE_CSR_CSRB, 0); +#endif + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/compalstage/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,30 @@ +CC= arm-elf-gcc +OBJCOPY=arm-elf-objcopy + +TARGETS=compalstage-plain.bin compalstage-thumb.bin compalstage-1003.bin +INSTDIR=/usr/local/share/freecalypso + +all: ${TARGETS} + +.SUFFIXES: .o .bin + +.o.bin: + ${OBJCOPY} -O binary $< $@ + +compalstage-1003.o: compalstage.S + ${CC} -DPAD_TO_1003 -c -o $@ $< + +compalstage-plain.o: compalstage.S + ${CC} -c -o $@ $< + +compalstage-thumb.o: compalstage.S + ${CC} -DTHUMB_ENTRY -c -o $@ $< + +install: + mkdir -p ${INSTDIR} + install -c ${TARGETS} ${INSTDIR} + +clean: + rm -f *.o *errs *core *.bin + +FRC:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/compalstage/README Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,33 @@ +FreeCalypso loadtools have been designed from the beginning to work through +the Calypso chip's own boot ROM. This approach works great for Openmoko and +Pirelli targets, but Compal phones unfortunately have this Calypso boot ROM +disabled at the board level. To run our own code in these phones instead of +booting the regular firmware, we need to go through Compal's own boot code. +The latter allows loading code into IRAM and jumping to it, but not in the +same way as how we do it through the Calypso boot ROM. + +One could argue that the "proper" way to support these Compal phones would be +to build a different version of our loadagent that is designed to be loaded +through Compal's boot code instead of the Calypso boot ROM, and then redesign +our fc-loadtool and fc-xram utilities to work with different loadagents loaded +in different ways on different target devices. But I don't feel like doing +that - too invasive to the once-clean design of loadtools. + +Hence I am adopting a different solution that works in the same way as +OsmocomBB's "chain loading": the IRAM image that is fed to Compal's boot code +is not our real loadagent, but a tiny piece of code that enables the Calypso +boot ROM and jumps to it. All loadtools host programs will include this +optional "Compal stage" at the beginning, enabled for targets that need it, +but will then always fall into the Calypso boot ROM IRAM download path. + +The approach I'm adopting is doubly inefficient for Mot C139/140 phones whose +bootloader effectively requires that the downloaded image be ~15 KiB long +even when we only need to download 32 bytes. But hey, our ultimate goal is to +produce our own Calypso phones, rather than hack those made by diabolical +manufacturers who do not Respect Your Freedom; running our own gsm-fw on the +Mot C139 is only a transitional step, so making fc-loadtool/fc-xram entry +slower by a second or two is probably an acceptable price for keeping the +code clean for the boot-ROM-enabled free world. + +In this directory we build the several different versions of compalstage +needed for different C1xx models.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/compalstage/compalstage.S Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,27 @@ + .text + .org 0 + +#if THUMB_ENTRY + .code 16 + bx pc + nop +#endif + .code 32 + +/* delay loop like OsmocomBB does */ + mov r1, #0xa0000 +1: subs r1, r1, #1 + bne 1b +/* enable the Calypso boot ROM */ + ldr r1, reg_addr + mov r2, #0x0100 + strh r2, [r1] +/* jump to it! */ + mov pc, #0 +reg_addr: + .word 0xFFFFFB10 + +#if PAD_TO_1003 + .org 0x3be0 + .ascii "1003" +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/env/compalram.lds Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,47 @@ +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_entry) +SECTIONS +{ + /* code */ + . = 0x800100; + .text : { + /* regular code */ + *(.text*) + /* gcc voodoo */ + *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx) + . = ALIGN(4); + } + + /* read-only data */ + . = ALIGN(4); + .rodata : { + *(.rodata*) + } + + /* initialized data */ + . = ALIGN(4); + .data : { + *(.data) + } + PROVIDE(edata = .); + + /* magic signature for C139/140 bootloader */ + .magic 0x803ce0 : { + LONG(0x33303031) + } + + /* uninitialized data */ + .bss (NOLOAD) : { + . = ALIGN(4); + __bss_start = .; + *(.bss) + } + . = ALIGN(4); + __bss_end = .; + /* end of image */ + _end = .; + PROVIDE(end = .); +} + +stack_bottom = 0x83FFFC;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/env/crt0.S Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,19 @@ +#include "halt.h" + + .text + .code 32 + .global _entry +_entry: + ldr sp, =stack_bottom +@ zero bss + ldr r0, =__bss_start + ldr r2, =__bss_end + sub r1, r2, r0 + bl bzero +@ C code entry + bl main + mov r0, #HALTCODE_MAINEXITED + .global _exit +_exit: nop +1: nop + b 1b
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/env/iram.lds Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,50 @@ +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_entry) +SECTIONS +{ + /* code */ + . = Base_addr; + .text : { + /* regular code */ + *(.text*) + /* gcc voodoo */ + *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx) + . = ALIGN(4); + } + + /* read-only data */ + . = ALIGN(4); + .rodata : { + *(.rodata*) + } + + /* initialized data */ + . = ALIGN(4); + .data : { + *(.data) + } + PROVIDE(edata = .); + + /* uninitialized data */ + .bss (NOLOAD) : { + . = ALIGN(4); + __bss_start = .; + *(.bss) + } + . = ALIGN(4); + __bss_end = .; + /* end of image */ + _end = .; + PROVIDE(end = .); +} + +/* + * stack_bottom will be set via the --defsym option to ld. + * Some programs have minimal IRAM requirements, so it would make more + * sense to set stack_bottom to 0x83FFFC, don't use the upper half of + * IRAM for anything, and make that program portable to Calypso Lite + * devices. But for some other programs we might have some use for + * the larger IRAM of our full Calypso devices, in which case we would + * want to set stack_bottom to 0x87FFFC instead. + */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/helloapp/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,31 @@ +CC= arm-elf-gcc +CFLAGS= -Os -fno-builtin +CPPFLAGS=-I../include +LD= arm-elf-ld +OBJCOPY=arm-elf-objcopy + +PROG= helloapp +OBJS= crt0.o cmdtab.o main.o mygetchar.o +LIBS= ../libcommon/libcommon.a ../libprintf/libprintf.a ../libbase/libbase.a +LDS= ../env/iram.lds + +TC_LIBS=`${CC} -print-file-name=libc.a` \ + `${CC} -print-file-name=libgcc.a` + +all: ${PROG}.srec + +crt0.S: ../env/crt0.S + ln -s $< . + +${PROG}.elf: ${OBJS} ${LIBS} ${LDS} + ${LD} -N --defsym Base_addr=0x800750 --defsym stack_bottom=0x83FFFC \ + -T ${LDS} -o $@ ${OBJS} ${LIBS} \ + --start-group ${TC_LIBS} --end-group + +${PROG}.srec: ${PROG}.elf + ${OBJCOPY} -O srec --srec-forceS3 --srec-len=30 $< $@ + +clean: + rm -f *.o *errs *core *.elf *.bin *.srec crt0.S + +FRC:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/helloapp/cmdtab.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,18 @@ +#include "cmdtab.h" + +extern void cmd_r8(); +extern void cmd_r16(); +extern void cmd_r32(); +extern void cmd_w8(); +extern void cmd_w16(); +extern void cmd_w32(); + +const struct cmdtab cmdtab[] = { + {"r8", cmd_r8}, + {"r16", cmd_r16}, + {"r32", cmd_r32}, + {"w8", cmd_w8}, + {"w16", cmd_w16}, + {"w32", cmd_w32}, + {0, 0} +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/helloapp/main.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,11 @@ +main() +{ + uart_select_init(); + printf("Hello-world demo app running\n"); + print_boot_rom_info(); + for (;;) { + putchar('='); + if (command_entry()) + command_dispatch(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/helloapp/mygetchar.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,21 @@ +/* + * The interactive command entry (editing) function in libcommon + * will call mygetchar() for its character input. It is supposed + * to be a blocking wait for input, but in some programs other + * processing can be done while waiting - for example, check for + * keypad presses as well. This is the basic version which waits + * for serial input and nothing else. + */ + +extern int serial_in_poll(); + +int +mygetchar() +{ + register int c; + + do + c = serial_in_poll(); + while (c < 0); + return c; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/include/abbdefs.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,155 @@ +/* lifted from OsmocomBB */ + +#ifndef _TWL3025_H +#define _TWL3025_H + +#define PAGE(n) (n << 7) +enum twl3025_reg { + VRPCCFG = PAGE(1) | 30, + VRPCDEV = PAGE(0) | 30, + VRPCMSK = PAGE(1) | 31, + VRPCMSKABB = PAGE(1) | 29, + VRPCSTS = PAGE(0) | 31, + /* Monitoring ADC Registers */ + MADCTRL = PAGE(0) | 13, + MADCSTAT = PAGE(0) | 24, + VBATREG = PAGE(0) | 15, + VCHGREG = PAGE(0) | 16, + ICHGREG = PAGE(0) | 17, + VBKPREG = PAGE(0) | 18, + ADIN1REG = PAGE(0) | 19, + ADIN2REG = PAGE(0) | 20, + ADIN3REG = PAGE(0) | 21, + ADIN4REG = PAGE(0) | 22, + /* Clock Generator Registers */ + TOGBR1 = PAGE(0) | 4, + TOGBR2 = PAGE(0) | 5, + PWDNRG = PAGE(1) | 9, + TAPCTRL = PAGE(1) | 19, + TAPREG = PAGE(1) | 20, + /* Automatic Frequency Control (AFC) Registers */ + AUXAFC1 = PAGE(0) | 7, + AUXAFC2 = PAGE(0) | 8, + AFCCTLADD = PAGE(1) | 21, + AFCOUT = PAGE(1) | 22, + /* Automatic Power Control (APC) Registers */ + APCDEL1 = PAGE(0) | 2, + APCDEL2 = PAGE(1) | 26, + AUXAPC = PAGE(0) | 9, + APCRAM = PAGE(0) | 10, + APCOFF = PAGE(0) | 11, + APCOUT = PAGE(1) | 12, + /* Auxiliary DAC Control Register */ + AUXDAC = PAGE(0) | 12, + /* SimCard Control Register */ + VRPCSIM = PAGE(1) | 23, + /* LED Driver Register */ + AUXLED = PAGE(1) | 24, + /* Battery Charger Interface (BCI) Registers */ + CHGREG = PAGE(0) | 25, + BCICTL1 = PAGE(0) | 28, + BCICTL2 = PAGE(0) | 29, + BCICONF = PAGE(1) | 13, + /* Interrupt and Bus Control (IBIC) Registers */ + ITMASK = PAGE(0) | 28, + ITSTATREG = PAGE(0) | 27, /* both pages! */ + PAGEREG = PAGE(0) | 1, /* both pages! */ + /* Baseband Codec (BBC) Registers */ + BULIOFF = PAGE(1) | 2, + BULQOFF = PAGE(1) | 3, + BULIDAC = PAGE(1) | 5, + BULQDAC = PAGE(1) | 4, + BULGCAL = PAGE(1) | 14, + BULDATA1 = PAGE(0) | 3, /* 16 words */ + BBCTRL = PAGE(1) | 6, + /* Voiceband Codec (VBC) Registers */ + VBCTRL1 = PAGE(1) | 8, + VBCTRL2 = PAGE(1) | 11, + VBPOP = PAGE(1) | 10, + VBUCTRL = PAGE(1) | 7, + VBDCTRL = PAGE(0) | 6, +}; +#define BULDATA2 BULDATA1 + +/* available ADC inputs on IOTA */ +enum twl3025_dac_inputs {/* === Signal ============================= */ + MADC_VBAT=0, /* battery voltage / 4 */ + MADC_VCHG=1, /* charger voltage / 5 */ + MADC_ICHG=2, /* I-sense amp or CHGREG DAC output */ + MADC_VBKP=3, /* backup battery voltage / 4 */ + MADC_ADIN1=4, /* VADCID, sense battery type, not used */ + MADC_ADIN2=5, /* Temperature sensor in Battery */ + MADC_ADIN3=6, /* Mode_detect: sense 2.5mm jack insertion */ + MADC_ADIN4=7, /* RITA: TEMP_SEN */ + MADC_NUM_CHANNELS=8 +}; + +enum madcstat_reg_bits { /* monitoring ADC status register */ + ADCBUSY = 0x01 /* if set, a conversion is currently going on */ +}; + +/* BCICTL1 register bits */ +enum bcictl1_reg_bits { + MESBAT = 1<<0, /* connect resistive divider for bat voltage */ + DACNBUF = 1<<1, /* bypass DAC buffer */ + THSENS0 = 1<<3, /* thermal sensor bias current (ADIN2), bit 0 */ + THSENS1 = 1<<4, /* "" bit 1 */ + THSENS2 = 1<<5, /* "" bit 2 */ + THEN = 1<<6, /* enable thermal sensor bias current (ADIN1) */ + TYPEN = 1<<7 /* enable bias current for battery type reading */ +}; + +/* BCICTL1 register bits */ +enum bcictl2_reg_bits { + CHEN = 1<<0, /* enable charger */ + CHIV = 1<<1, /* 1=constant current, 0=constant voltage */ + CHBPASSPA=1<<2, /* full charging of the battery during pulse radio */ + CLIB = 1<<3, /* calibrate I-to-V amp (short input pins) */ + CHDISPA = 1<<4, /* disabel charging during pulse radio (???) */ + LEDC = 1<<5, /* enable LED during charge */ + CGAIN4 = 1<<6, /* if set, I-to-V amp gain is reduced from 10 to 4 */ + PREOFF = 1<<7 /* disable battery precharge */ +}; + +enum vrpcsts_reg_bits { + ONBSTS = 1<<0, /* button push switched on the mobile */ + ONRSTS = 1<<1, /* RPWON terminal switched on the mobile */ + ITWSTS = 1<<2, /* ITWAKEUP terminal switched on the mobile */ + CHGSTS = 1<<3, /* plugging in charger has switched on the mobile */ + ONREFLT= 1<<4, /* state of PWON terminal after debouncing */ + ONMRFLT= 1<<5, /* state of RPWON terminal after debouncing */ + CHGPRES= 1<<6 /* charger is connected */ +}; + +enum togbr2_bits { + TOGBR2_KEEPR = (1 << 0), /* Clear KEEPON bit */ + TOGBR2_KEEPS = (1 << 1), /* Set KEEPON bit */ + TOGBR2_ACTR = (1 << 2), /* Dectivate MCLK */ + TOGBR2_ACTS = (1 << 3), /* Activate MCLK */ + TOGBR2_IBUFPTR1 = (1 << 4), /* Initialize pointer of burst buffer 1 */ + TOGBR2_IBUFPTR2 = (1 << 5), /* Initialize pointer of burst buffer 2 */ + TOGBR2_IAPCPTR = (1 << 6), /* Initialize pointer of APC RAM */ +}; + +/* How a RAMP value is encoded */ +#define ABB_RAMP_VAL(up, down) ( ((down & 0x1F) << 5) | (up & 0x1F) ) + +enum twl3025_unit { + TWL3025_UNIT_AFC, + TWL3025_UNIT_MAD, + TWL3025_UNIT_ADA, + TWL3025_UNIT_VDL, + TWL3025_UNIT_VUL, +}; + +enum twl3025_tsp_bits { + BULON = 0x80, + BULCAL = 0x40, + BULENA = 0x20, + BDLON = 0x10, + BDLCAL = 0x08, + BDLENA = 0x04, + STARTADC = 0x02, +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/include/cmdtab.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,6 @@ +/* this structure is used for interactive command dispatch */ + +struct cmdtab { + char *cmd; + void (*func)(); +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/include/halt.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,11 @@ +/* + * In some error cases in our loadagent code we have no better course + * of action available than to halt in a tight loop. We define _exit() + * to do the latter. We have defined some codes for the argument value + * that goes into R0; if you manage to hook up JTAG and get it to work, + * you might be able to see what went wrong. + */ + +#define HALTCODE_MAINEXITED 0x40 +#define HALTCODE_INVALIDUART 0x41 +#define HALTCODE_BOOTROMVER 0x42
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/include/ns16550.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,101 @@ +#ifndef __NS16550_H +#define __NS16550_H + +/* NS16550 registers */ +#define NS16550_RBR 0 +#define NS16550_THR 0 +#define NS16550_IER 1 +#define NS16550_IIR 2 +#define NS16550_FCR 2 +#define NS16550_LCR 3 +#define NS16550_MCR 4 +#define NS16550_LSR 5 +#define NS16550_MSR 6 +#define NS16550_SCR 7 +#define NS16550_DLL 0 +#define NS16550_DLM 1 + +#ifndef __ASSEMBLER__ +#include "types.h" + +struct ns16550_regs { + u8 datareg; + u8 ier; + u8 iir_fcr; + u8 lcr; + u8 mcr; + u8 lsr; + u8 msr; + u8 scr; +}; +#endif + +/* IER bits */ +#define NS16550_IER_EDSSI 0x08 +#define NS16550_IER_ELSI 0x04 +#define NS16550_IER_ETBEI 0x02 +#define NS16550_IER_ERBFI 0x01 + +/* IIR bits */ +#define NS16550_IIR_FIFOEN 0xC0 +#define NS16550_IIR_INTID 0x0E +#define NS16550_IIR_INT_RLS 0x06 +#define NS16550_IIR_INT_RDA 0x04 +#define NS16550_IIR_INT_CTO 0x0C +#define NS16550_IIR_INT_THRE 0x02 +#define NS16550_IIR_INT_MODEM 0x00 +#define NS16550_IIR_INTPEND 0x01 + +/* FCR bits */ + +#define NS16550_FCR_RXTR 0xC0 +#define NS16550_FCR_RXTR_1 0x00 +#define NS16550_FCR_RXTR_4 0x40 +#define NS16550_FCR_RXTR_8 0x80 +#define NS16550_FCR_RXTR_14 0xC0 +#define NS16550_FCR_DMAMODE 0x08 +#define NS16550_FCR_TXRST 0x04 +#define NS16550_FCR_RXRST 0x02 +#define NS16550_FCR_FIFOEN 0x01 + +/* LCR bits */ +#define NS16550_LCR_DLAB 0x80 +#define NS16550_LCR_BREAK 0x40 +#define NS16550_LCR_STICK 0x20 +#define NS16550_LCR_EPS 0x10 +#define NS16550_LCR_PEN 0x08 +#define NS16550_LCR_STB 0x04 +#define NS16550_LCR_WLS 0x03 +#define NS16550_LCR_WLS_5 0x00 +#define NS16550_LCR_WLS_6 0x01 +#define NS16550_LCR_WLS_7 0x02 +#define NS16550_LCR_WLS_8 0x03 + +/* MCR bits */ +#define NS16550_MCR_LOOP 0x10 +#define NS16550_MCR_OUT2 0x08 +#define NS16550_MCR_OUT1 0x04 +#define NS16550_MCR_RTS 0x02 +#define NS16550_MCR_DTR 0x01 + +/* LSR bits */ +#define NS16550_LSR_ERR 0x80 +#define NS16550_LSR_TEMP 0x40 +#define NS16550_LSR_THRE 0x20 +#define NS16550_LSR_BI 0x10 +#define NS16550_LSR_FE 0x08 +#define NS16550_LSR_PE 0x04 +#define NS16550_LSR_OE 0x02 +#define NS16550_LSR_DR 0x01 + +/* MSR bits */ +#define NS16550_MSR_DCD 0x80 +#define NS16550_MSR_RI 0x40 +#define NS16550_MSR_DSR 0x20 +#define NS16550_MSR_CTS 0x10 +#define NS16550_MSR_DDCD 0x08 +#define NS16550_MSR_TERI 0x04 +#define NS16550_MSR_DDSR 0x02 +#define NS16550_MSR_DCTS 0x01 + +#endif /* __NS16550_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/include/romvars.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,36 @@ +/* + * Our loadagent will always be loaded into Calypso targets by the on-chip + * boot ROM operating in the UART download mode. The lowest IRAM address + * at which we can load our code is 0x800750; somewhat lower at 0x800518 + * the boot ROM downloader has a few variables which may have been intended + * to be private to the boot ROM, but which are useful to us. For example, + * by looking at these variables, we can see which of the two UARTs was + * used to feed our code to the boot ROM, and use the same UART for + * subsequent communication - without building multiple versions of our + * loadagent or resorting to other ugliness. + * + * This header file defines the layout of the IRAM structure in question, + * based on the disassembly of the boot ROM. + */ + +#ifndef __ROMVARS_H +#define __ROMVARS_H + +#include "types.h" + +struct boot_rom_vars { + u8 baud_rate_code; + u8 pad1[3]; + u32 uart_timeout; + u8 uart_id; + u8 pll_config; + u16 cs_ws_config; + u8 clktcxo_13mhz; + u8 rhea_cntl; + u16 chksum_cmd; + u16 chksum_accum; + u16 pad2; + u32 branch_addr; +}; + +#endif /* include guard */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/include/rtc.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,34 @@ +/* Calypso RTC registers */ + +#ifndef __CALYPSO_RTC_H +#define __CALYPSO_RTC_H + +#include "types.h" + +#define RTC_REGS_BASE 0xFFFE1800 + +struct rtctime { + u8 seconds; + u8 minutes; + u8 hours; + u8 day_of_month; + u8 month; + u8 year; + u8 day_of_week; + u8 pad; +}; + +struct rtcregs { + struct rtctime rtc_cur; + struct rtctime rtc_alarm; + u8 rtc_ctrl_reg; + u8 rtc_status_reg; + u8 rtc_int_reg; + u8 rtc_comp_lsb_reg; + u8 rtc_comp_msb_reg; + u8 rtc_res_prog_reg; +}; + +#define RTC_REGS (*(volatile struct rtcregs *) RTC_REGS_BASE) + +#endif /* include guard */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/include/types.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,18 @@ +/* + * I personally like the u8/u16/u32 types, but I don't see them + * being defined in any of the headers provided by newlib. + * So we'll define them ourselves. + */ + +#ifndef __OUR_OWN_TYPES_H +#define __OUR_OWN_TYPES_H + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; + +typedef signed char s8; +typedef signed short s16; +typedef signed int s32; + +#endif /* include guard */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libbase/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,16 @@ +CC= arm-elf-gcc +CFLAGS= -Os -fno-builtin +CPPFLAGS=-I../include +AR= arm-elf-ar +RANLIB= arm-elf-ranlib + +OBJS= abbdrv.o osmodelay.o serio.o spidrv.o + +all: libbase.a + +libbase.a: ${OBJS} + ${AR} cru $@ ${OBJS} + ${RANLIB} $@ + +clean: + rm -f *.[oa] *errs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libbase/abbdrv.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,102 @@ +/* Driver for Analog Baseband Circuit (TWL3025) */ +/* lifted from OsmocomBB and ported to FreeCalypso target-utils environment */ + +/* (C) 2010 by Harald Welte <laforge@gnumonks.org> + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include "types.h" +#include "abbdefs.h" + +/* TWL3025 */ +#define REG_PAGE(n) ((n) >> 7) +#define REG_ADDR(n) ((n) & 0x1f) + +#define TWL3025_DEV_IDX 0 /* On the SPI bus */ +#define TWL3025_TSP_DEV_IDX 0 /* On the TSP bus */ + +int abb_state_initdone, abb_state_page; + +void +abb_reg_write(reg, data) +{ + u16 tx; + + if (reg != PAGEREG && REG_PAGE(reg) != abb_state_page) + abb_select_page(REG_PAGE(reg)); + + tx = ((data & 0x3ff) << 6) | (REG_ADDR(reg) << 1); + + spi_xfer(TWL3025_DEV_IDX, 16, &tx, 0); +} + +u16 +abb_reg_read(reg) +{ + u16 tx, rx; + + if (REG_PAGE(reg) != abb_state_page) + abb_select_page(REG_PAGE(reg)); + + tx = (REG_ADDR(reg) << 1) | 1; + + /* A read cycle contains two SPI transfers */ + spi_xfer(TWL3025_DEV_IDX, 16, &tx, &rx); + osmo_delay_ms(1); + spi_xfer(TWL3025_DEV_IDX, 16, &tx, &rx); + + rx >>= 6; + + return rx; +} + +/* Switch the register page of the TWL3025 */ +abb_select_page(page) +{ + if (page == 0) + abb_reg_write(PAGEREG, 1 << 0); + else + abb_reg_write(PAGEREG, 1 << 1); + abb_state_page = page; + return(0); +} + +abb_init() +{ + if (abb_state_initdone) + return(0); + spi_init(); + abb_select_page(0); + /* CLK13M enable */ + abb_reg_write(TOGBR2, TOGBR2_ACTS); + osmo_delay_ms(1); + /* for whatever reason we need to do this twice */ + abb_reg_write(TOGBR2, TOGBR2_ACTS); + osmo_delay_ms(1); + abb_state_initdone = 1; + return(1); +} + +void +abb_power_off() +{ + abb_init(); + serial_flush(); + abb_reg_write(VRPCDEV, 0x01); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libbase/osmodelay.S Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,30 @@ +/* + * This assembly module provides a replica of OsmocomBB's bogo-millisecond + * delay_ms() function. It is literally a copy of what OsmocomBB's delay_ms() + * compiles to with their gcc version and their optimization settings, as seen + * by doing arm-elf-objdump on their lib/delay.o. + * + * This hack is intended for those cases where we have to copy OsmocomBB's + * black magic voodoo operations with no ability to understand what is actually + * needed, such as SPCA552E initialization on the Pirelli DP-L10. + */ + + .text + .code 32 + .globl osmo_delay_ms +osmo_delay_ms: + mov r3, #0 + sub sp, sp, #4 + str r3, [sp] + ldr r3, =1300 + mul r3, r0, r3 + b 2f +1: ldr r2, [sp] + ldr r2, [sp] + add r2, r2, #1 + str r2, [sp] +2: ldr r2, [sp] + cmp r2, r3 + bcc 1b + add sp, sp, #4 + bx lr
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libbase/serio.S Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,36 @@ +#include "ns16550.h" + +@ this module implements the elementary serial I/O operations + + .comm uart_base,4,4 + + .text + .code 32 + .global serial_out +serial_out: + ldr r1, =uart_base + ldr r2, [r1] +1: ldrb r3, [r2, #NS16550_LSR] + tst r3, #NS16550_LSR_THRE + beq 1b + strb r0, [r2, #NS16550_THR] + bx lr + + .global serial_in_poll +serial_in_poll: + ldr r1, =uart_base + ldr r2, [r1] + ldrb r3, [r2, #NS16550_LSR] + tst r3, #NS16550_LSR_DR + ldrneb r0, [r2, #NS16550_RBR] + mvneq r0, #0 + bx lr + + .global serial_flush +serial_flush: + ldr r1, =uart_base + ldr r2, [r1] +1: ldrb r3, [r2, #NS16550_LSR] + tst r3, #NS16550_LSR_TEMP + beq 1b + bx lr
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libbase/spidrv.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,139 @@ +/* Driver for SPI Master Controller inside TI Calypso */ +/* lifted from OsmocomBB and ported to FreeCalypso target-utils environment */ + +/* (C) 2010 by Harald Welte <laforge@gnumonks.org> + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include "types.h" + +#define ASIC_CONF_REG (*(volatile u16 *) 0xFFFEF008) + +struct spi_regs { + u16 reg_set1; + u16 reg_set2; + u16 reg_ctrl; + u16 reg_status; + u16 reg_tx_lsb; + u16 reg_tx_msb; + u16 reg_rx_lsb; + u16 reg_rx_msb; +}; + +#define SPI_REGS (*(volatile struct spi_regs *) 0xFFFE3000) + +#define BASE_ADDR_SPI 0xfffe3000 +#define SPI_REG(n) (BASE_ADDR_SPI+(n)) + +#define SPI_SET1_EN_CLK (1 << 0) +#define SPI_SET1_WR_IRQ_DIS (1 << 4) +#define SPI_SET1_RDWR_IRQ_DIS (1 << 5) + +#define SPI_CTRL_RDWR (1 << 0) +#define SPI_CTRL_WR (1 << 1) +#define SPI_CTRL_NB_SHIFT 2 +#define SPI_CTRL_AD_SHIFT 7 + +#define SPI_STATUS_RE (1 << 0) /* Read End */ +#define SPI_STATUS_WE (1 << 1) /* Write End */ + +spi_init() +{ + static int initdone; + + if (initdone) + return(0); + ASIC_CONF_REG |= 0x6000; + SPI_REGS.reg_set1 = SPI_SET1_EN_CLK | SPI_SET1_WR_IRQ_DIS | + SPI_SET1_RDWR_IRQ_DIS; + SPI_REGS.reg_set2 = 0x0001; + initdone = 1; + return(1); +} + +spi_xfer(dev_idx, bitlen, dout, din) + void *dout, *din; +{ + int bytes_per_xfer; + u16 reg_status, reg_ctrl = 0; + u32 tmp; + + if (bitlen <= 0) + return 0; + + if (bitlen > 32) + return -1; + + if (dev_idx > 4) + return -1; + + bytes_per_xfer = bitlen / 8; + if (bitlen % 8) + bytes_per_xfer ++; + + reg_ctrl |= (bitlen - 1) << SPI_CTRL_NB_SHIFT; + reg_ctrl |= (dev_idx & 0x7) << SPI_CTRL_AD_SHIFT; + + if (bitlen <= 8) { + tmp = *(u8 *)dout; + tmp <<= 24 + (8-bitlen); /* align to MSB */ + } else if (bitlen <= 16) { + tmp = *(u16 *)dout; + tmp <<= 16 + (16-bitlen); /* align to MSB */ + } else { + tmp = *(u32 *)dout; + tmp <<= (32-bitlen); /* align to MSB */ + } + + /* fill transmit registers */ + SPI_REGS.reg_tx_msb = tmp >> 16; + SPI_REGS.reg_tx_lsb = tmp; + + /* initiate transfer */ + if (din) + reg_ctrl |= SPI_CTRL_RDWR; + else + reg_ctrl |= SPI_CTRL_WR; + SPI_REGS.reg_ctrl = reg_ctrl; + + /* wait until the transfer is complete */ + while (1) { + reg_status = SPI_REGS.reg_status; + if (din && (reg_status & SPI_STATUS_RE)) + break; + else if (reg_status & SPI_STATUS_WE) + break; + } + /* FIXME: calibrate how much delay we really need (seven 13MHz cycles) */ + osmo_delay_ms(1); + + if (din) { + tmp = SPI_REGS.reg_rx_msb << 16; + tmp |= SPI_REGS.reg_rx_lsb; + + if (bitlen <= 8) + *(u8 *)din = tmp & 0xff; + else if (bitlen <= 16) + *(u16 *)din = tmp & 0xffff; + else + *(u32 *)din = tmp; + } + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libcommon/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,18 @@ +CC= arm-elf-gcc +CFLAGS= -Os -fno-builtin +CPPFLAGS=-I../include +AR= arm-elf-ar +RANLIB= arm-elf-ranlib + +OBJS= abbcmd.o cmdentry.o dispatch.o hexarg.o parseargs.o uartsel.o \ + cmd_baud_switch.o cmd_dieid.o cmd_jump.o cmd_r8.o cmd_r16.o cmd_r32.o \ + cmd_w8.o cmd_w16.o cmd_w32.o cmd_memdump_human.o cmd_memdump_machine.o + +all: libcommon.a + +libcommon.a: ${OBJS} + ${AR} cru $@ ${OBJS} + ${RANLIB} $@ + +clean: + rm -f *.[oa] *errs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libcommon/abbcmd.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,51 @@ +/* + * abbr pg reg -- read ABB register + * abbw pg reg val -- write ABB register + */ + +#include <sys/types.h> +#include "types.h" +#include "abbdefs.h" + +extern u16 abb_reg_read(); +extern void abb_reg_write(); + +void +cmd_abbr(argbulk) + char *argbulk; +{ + char *argv[3]; + u32 pg, reg, val; + + if (parse_args(argbulk, 2, 2, argv, 0) < 0) + return; + pg = strtoul(argv[0], 0, 0); + reg = strtoul(argv[1], 0, 0); + if (pg > 1 || reg > 31) { + printf("ERROR: argument(s) out of range\n"); + return; + } + abb_init(); + val = abb_reg_read(PAGE(pg) | reg); + printf("%03X\n", val); +} + +void +cmd_abbw(argbulk) + char *argbulk; +{ + char *argv[4]; + u32 pg, reg, val; + + if (parse_args(argbulk, 3, 3, argv, 0) < 0) + return; + pg = strtoul(argv[0], 0, 0); + reg = strtoul(argv[1], 0, 0); + val = strtoul(argv[2], 0, 16); + if (pg > 1 || reg > 31 || val > 0x3FF) { + printf("ERROR: argument(s) out of range\n"); + return; + } + abb_init(); + abb_reg_write(PAGE(pg) | reg, val); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libcommon/cmd_baud_switch.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,112 @@ +/* + * Baud rate switching command + */ + +#include <stdlib.h> +#include "types.h" +#include "ns16550.h" + +extern struct ns16550_regs *uart_base; +extern int serial_in_poll(); + +static const struct tab { + int baud; + int divisor; +} rate_table[] = { + /* + * First support the rates and divisors implemented by the + * Calypso boot ROM. Dividing 13 MHz by 7 gives an approximation + * of 115200 (x16); the divisors used by the boot ROM code for + * the slower baud rates are all 7x the usual PC value. + */ + {115200, 7}, + {57600, 7 * 2}, + {38400, 7 * 3}, + {28800, 7 * 4}, + {19200, 7 * 6}, + /* + * Going faster than ~115200 baud means using a divisor + * less than 7, resulting in a non-standard baud rate. + * The /1, /2 and /4 seem like reasonable choices. + */ + {812500, 1}, + {406250, 2}, + {203125, 4}, + /* that's all we really need to support */ + {0, 0} +}; + +/* + * The following helper function actually switches the UART + * baud rate divisor. Call serial_flush() first. It returns the + * old divisor value. + * + * Note the u8 type for both the new and old divisor values. + * All supported divisors are well below 255, so we don't bother + * with the upper byte. + */ +static u8 +actually_switch_baud(newdiv) + u8 newdiv; +{ + volatile struct ns16550_regs *regs; + u8 save_lcr, save_old_baud; + + regs = uart_base; + save_lcr = regs->lcr; + regs->lcr = save_lcr | NS16550_LCR_DLAB; + save_old_baud = regs->datareg; + regs->datareg = newdiv; + regs->lcr = save_lcr; + return(save_old_baud); +} + +void +cmd_baud_switch(argbulk) + char *argbulk; +{ + char *argv[2]; + int baudarg; + struct tab *tp; + u8 save_old_baud; + int c; + + if (parse_args(argbulk, 1, 1, argv, 0) < 0) + return; + baudarg = atoi(argv[0]); + for (tp = rate_table; tp->baud; tp++) + if (tp->baud == baudarg) + break; + if (!tp->baud) { + printf("ERROR: invalid/unimplemented baud rate argument\n"); + return; + } + + /* do it */ + serial_flush(); + save_old_baud = actually_switch_baud(tp->divisor); + + /* + * After getting the echo of this command at the old baud rate + * (see the serial flush call just before switching the divisor), + * the line will go silent from the user's perspective. + * The user should wait just a little bit, then send us a 0x55 ('U') + * at the new baud rate - we should be in the below loop waiting + * for this character by then. Receiving that character + * correctly (0x55 was chosen for the bit pattern - unlikely to + * be received if the sender is sending at a wrong baud rate) + * will cause us to conclude this command and return a new '=' + * prompt at the new baud rate. + * + * If we get something else, we assume that someone messed up, + * switch back to the old baud rate, scribble an error message + * and return. + */ + do + c = serial_in_poll(); + while (c < 0); + if (c != 0x55) { + actually_switch_baud(save_old_baud); + printf("ERROR: no \'U\' received, switched back to old baud rate\n"); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libcommon/cmd_dieid.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,10 @@ +#include "types.h" + +void +cmd_dieid() +{ + u32 addr; + + for (addr = 0xFFFEF010; addr <= 0xFFFEF016; addr += 2) + printf("%08X: %04X\n", addr, *(volatile u16 *)addr); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libcommon/cmd_jump.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,24 @@ +/* + * jump hexaddr -- transfer control with BX + */ + +#include <sys/types.h> +#include "types.h" + +void +cmd_jump(argbulk) + char *argbulk; +{ + char *argv[2]; + u_long addr; + + if (parse_args(argbulk, 1, 1, argv, 0) < 0) + return; + if (parse_hexarg(argv[0], 8, &addr) < 0) { + printf("ERROR: argument must be a valid 32-bit hex address\n"); + return; + } + serial_flush(); + asm volatile ("bx %0" : : "r" (addr)); + __builtin_unreachable(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libcommon/cmd_memdump_human.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,50 @@ +/* + * This is a human-oriented memory dump command. The dump is given in + * both hex and ASCII, with readable spacing. + */ + +#include <sys/types.h> +#include "types.h" + +void +cmd_memdump_human(argbulk) + char *argbulk; +{ + char *argv[3]; + u_long start, length; + u_long offset; + u_char intbuf[16]; + int i, c; + + if (parse_args(argbulk, 2, 2, argv, 0) < 0) + return; + if (parse_hexarg(argv[0], 8, &start) < 0) { + printf("ERROR: arg1 must be a valid 32-bit hex address\n"); + return; + } + if (parse_hexarg(argv[1], 8, &length) < 0) { + printf("ERROR: arg2 must be a valid 32-bit hex value (length)\n"); + return; + } + if (start & 0xF || length & 0xF) { + printf("ERROR: implementation limit: 16-byte alignment required\n"); + return; + } + for (offset = 0; offset < length; offset += 0x10) { + bcopy(start + offset, intbuf, 0x10); + printf("%08X: ", start + offset); + for (i = 0; i < 16; i++) { + printf("%02X ", intbuf[i]); + if ((i & 3) == 3) + putchar(' '); + } + for (i = 0; i < 16; i++) { + c = intbuf[i]; + if (c >= ' ' && c <= '~') + putchar(c); + else + putchar('.'); + } + putchar('\n'); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libcommon/cmd_memdump_machine.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,50 @@ +/* + * This is a machine-oriented memory dump command. The output is in the + * form of S3 records. + */ + +#include <sys/types.h> +#include "types.h" + +void +cmd_memdump_machine(argbulk) + char *argbulk; +{ + char *argv[3]; + u_long start, length; + u_long addr; + u_char srbuf[0x86], cksum; + int i; + + if (parse_args(argbulk, 2, 2, argv, 0) < 0) + return; + if (parse_hexarg(argv[0], 8, &start) < 0) { + printf("ERROR: arg1 must be a valid 32-bit hex address\n"); + return; + } + if (parse_hexarg(argv[1], 8, &length) < 0) { + printf("ERROR: arg2 must be a valid 32-bit hex value (length)\n"); + return; + } + if (start & 0x7F || length & 0x7F) { + printf("ERROR: implementation limit: 128-byte alignment required\n"); + return; + } + srbuf[0] = 0x85; + for (addr = start; addr < start + length; addr += 0x80) { + srbuf[1] = addr >> 24; + srbuf[2] = addr >> 16; + srbuf[3] = addr >> 8; + srbuf[4] = addr; + bcopy(addr, srbuf + 5, 0x80); + cksum = 0; + for (i = 0; i < 0x85; i++) + cksum += srbuf[i]; + srbuf[i] = ~cksum; + putchar('S'); + putchar('3'); + for (i = 0; i < 0x86; i++) + printf("%02X", srbuf[i]); + putchar('\n'); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libcommon/cmd_r16.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,26 @@ +/* + * r16 hexaddr -- read a 16-bit register or memory location + */ + +#include <sys/types.h> +#include "types.h" + +void +cmd_r16(argbulk) + char *argbulk; +{ + char *argv[2]; + u_long addr; + + if (parse_args(argbulk, 1, 1, argv, 0) < 0) + return; + if (parse_hexarg(argv[0], 8, &addr) < 0) { + printf("ERROR: argument must be a valid 32-bit hex address\n"); + return; + } + if (addr & 1) { + printf("ERROR: unaligned address\n"); + return; + } + printf("%04X\n", *(volatile u16 *)addr); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libcommon/cmd_r32.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,26 @@ +/* + * r32 hexaddr -- read a 32-bit register or memory location + */ + +#include <sys/types.h> +#include "types.h" + +void +cmd_r32(argbulk) + char *argbulk; +{ + char *argv[2]; + u_long addr; + + if (parse_args(argbulk, 1, 1, argv, 0) < 0) + return; + if (parse_hexarg(argv[0], 8, &addr) < 0) { + printf("ERROR: argument must be a valid 32-bit hex address\n"); + return; + } + if (addr & 3) { + printf("ERROR: unaligned address\n"); + return; + } + printf("%08X\n", *(volatile u32 *)addr); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libcommon/cmd_r8.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,22 @@ +/* + * r8 hexaddr -- read an 8-bit register or memory location + */ + +#include <sys/types.h> +#include "types.h" + +void +cmd_r8(argbulk) + char *argbulk; +{ + char *argv[2]; + u_long addr; + + if (parse_args(argbulk, 1, 1, argv, 0) < 0) + return; + if (parse_hexarg(argv[0], 8, &addr) < 0) { + printf("ERROR: argument must be a valid 32-bit hex address\n"); + return; + } + printf("%02X\n", *(volatile u8 *)addr); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libcommon/cmd_w16.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,30 @@ +/* + * w16 hexaddr xxxx -- write a 16-bit register or memory location + */ + +#include <sys/types.h> +#include "types.h" + +void +cmd_w16(argbulk) + char *argbulk; +{ + char *argv[3]; + u_long addr, data; + + if (parse_args(argbulk, 2, 2, argv, 0) < 0) + return; + if (parse_hexarg(argv[0], 8, &addr) < 0) { + printf("ERROR: arg1 must be a valid 32-bit hex address\n"); + return; + } + if (addr & 1) { + printf("ERROR: unaligned address\n"); + return; + } + if (parse_hexarg(argv[1], 4, &data) < 0) { + printf("ERROR: arg2 must be a valid 16-bit hex value\n"); + return; + } + *(volatile u16 *)addr = data; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libcommon/cmd_w32.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,30 @@ +/* + * w32 hexaddr xxxxxxxx -- write a 32-bit register or memory location + */ + +#include <sys/types.h> +#include "types.h" + +void +cmd_w32(argbulk) + char *argbulk; +{ + char *argv[3]; + u_long addr, data; + + if (parse_args(argbulk, 2, 2, argv, 0) < 0) + return; + if (parse_hexarg(argv[0], 8, &addr) < 0) { + printf("ERROR: arg1 must be a valid 32-bit hex address\n"); + return; + } + if (addr & 3) { + printf("ERROR: unaligned address\n"); + return; + } + if (parse_hexarg(argv[1], 8, &data) < 0) { + printf("ERROR: arg2 must be a valid 32-bit hex value\n"); + return; + } + *(volatile u32 *)addr = data; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libcommon/cmd_w8.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,26 @@ +/* + * w8 hexaddr xx -- write an 8-bit register or memory location + */ + +#include <sys/types.h> +#include "types.h" + +void +cmd_w8(argbulk) + char *argbulk; +{ + char *argv[3]; + u_long addr, data; + + if (parse_args(argbulk, 2, 2, argv, 0) < 0) + return; + if (parse_hexarg(argv[0], 8, &addr) < 0) { + printf("ERROR: arg1 must be a valid 32-bit hex address\n"); + return; + } + if (parse_hexarg(argv[1], 2, &data) < 0) { + printf("ERROR: arg2 must be a valid 8-bit hex value\n"); + return; + } + *(volatile u8 *)addr = data; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libcommon/cmdentry.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,72 @@ +/* + * This module implements ASCII command entry via the serial port, + * with normal echo and minimal editing (rubout and kill). + * + * The command string buffer is bss-allocated here as well. It is + * sized to allow a maximum-size S-record to be sent as a command, + * as that is how we expect flash loading and XRAM chain-loading + * to be done. + */ + +#define MAXCMD 527 + +char command[MAXCMD+1]; + +/* + * The command_entry() function takes no arguments, and begins by waiting + * for serial input - hence the prompt should be printed before calling it. + * + * This function returns when one of the following characters is received: + * CR - accepts the command + * ^C or ^U - cancels the command + * + * The return value is non-zero if a non-empty command was accepted with CR, + * or 0 if the user hit CR with no input or if the command was canceled + * with ^C or ^U. In any case a CRLF is sent out the serial port + * to close the input echo line before this function returns. + */ +command_entry() +{ + int inlen, ch; + + for (inlen = 0; ; ) { + ch = mygetchar(); + if (ch >= ' ' && ch <= '~') { + if (inlen < MAXCMD) { + command[inlen++] = ch; + putchar(ch); + } else + /* putchar(7) */; + continue; + } + switch (ch) { + case '\r': + case '\n': + command[inlen] = '\0'; + putchar('\n'); + return(inlen); + case '\b': /* BS */ + case 0x7F: /* DEL */ + if (inlen) { + putchar('\b'); + putchar(' '); + putchar('\b'); + inlen--; + } else + /* putchar(7) */; + continue; + case 0x03: /* ^C */ + putchar('^'); + putchar('C'); + putchar('\n'); + return(0); + case 0x15: /* ^U */ + putchar('^'); + putchar('U'); + putchar('\n'); + return(0); + default: + /* putchar(7) */; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libcommon/dispatch.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,32 @@ +/* + * This module implements the dispatch of interactively entered + * commands to their respective implementation functions via cmdtab. + */ + +#include "cmdtab.h" + +extern char command[]; +extern struct cmdtab cmdtab[]; + +void +command_dispatch() +{ + char *cp, *np; + struct cmdtab *tp; + + for (cp = command; *cp == ' '; cp++) + ; + if (!*cp) + return; + for (np = cp; *cp && *cp != ' '; cp++) + ; + if (*cp) + *cp++ = '\0'; + for (tp = cmdtab; tp->cmd; tp++) + if (!strcmp(tp->cmd, np)) + break; + if (tp->func) + tp->func(cp); + else + printf("ERROR: unknown or unimplemented command\n"); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libcommon/hexarg.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,29 @@ +/* + * Many commands take hex arguments. This module contains the parse_hexarg() + * function, which is a wrapper around strtoul that performs some additional + * checks. + */ + +#include <sys/types.h> +#include <ctype.h> +#include <stdlib.h> + +parse_hexarg(arg, maxdigits, valp) + char *arg; + int maxdigits; + u_long *valp; +{ + char *cp = arg, *bp; + int len; + + if (cp[0] == '0' && (cp[1] == 'x' || cp[1] == 'X')) + cp += 2; + for (bp = cp; *cp; cp++) + if (!isxdigit(*cp)) + return(-1); + len = cp - bp; + if (len < 1 || len > maxdigits) + return(-1); + *valp = strtoul(arg, 0, 16); + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libcommon/parseargs.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,39 @@ +/* + * This module contains the parse_args() function, which parses the "rest" + * part of an entered command into an argc/argv-style argument array. + */ + +parse_args(unparsed, minargs, maxargs, argv, argcp) + char *unparsed; + int minargs, maxargs; + char **argv; + int *argcp; +{ + int argc; + char *cp; + + argc = 0; + for (cp = unparsed; ; ) { + while (*cp == ' ') + cp++; + if (!*cp) + break; + if (argc >= maxargs) { + printf("ERROR: too many arguments\n"); + return(-1); + } + argv[argc++] = cp; + while (*cp && *cp != ' ') + cp++; + if (*cp) + *cp++ = '\0'; + } + if (argc < minargs) { + printf("ERROR: too few arguments\n"); + return(-1); + } + argv[argc] = 0; + if (argcp) + *argcp = argc; + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libcommon/uartsel.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,54 @@ +/* + * uart_select_init() figures out which UART was used to load us + * through the boot ROM, and sets things up for us to use the same + * UART for our communication. + */ + +#include "types.h" +#include "romvars.h" +#include "ns16550.h" +#include "halt.h" + +extern struct ns16550_regs *uart_base; + +static u16 rom_version; +static struct boot_rom_vars *rom_vars; +static char *uart_name; + +uart_select_init() +{ + rom_version = *(u16 *)0x1FFE; + + switch (rom_version) { + case 0x0200: + rom_vars = (struct boot_rom_vars *) 0x800504; + break; + case 0x0300: + rom_vars = (struct boot_rom_vars *) 0x800518; + break; + default: + _exit(HALTCODE_BOOTROMVER); + } + + switch (rom_vars->uart_id) { + case 0: + uart_base = (struct ns16550_regs *) 0xFFFF5800; + uart_name = "MODEM"; + break; + case 1: + uart_base = (struct ns16550_regs *) 0xFFFF5000; + uart_name = "IrDA"; + break; + default: + _exit(HALTCODE_INVALIDUART); + } +} + +print_boot_rom_info() +{ + printf("Loaded via boot ROM v%04X, UART %d (%s) at baud rate #%d\n", + rom_version, rom_vars->uart_id, uart_name, + rom_vars->baud_rate_code); + printf("CLKTCXO input autodetected to be %d MHz\n", + rom_vars->clktcxo_13mhz ? 13 : 26); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libload/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,17 @@ +CC= arm-elf-gcc +CFLAGS= -Os -fno-builtin +CPPFLAGS=-I../include +AR= arm-elf-ar +RANLIB= arm-elf-ranlib + +OBJS= cmd_blankchk.o cmd_crc32.o cmd_memload.o \ + amdflash.o hexstrings.o intelflash.o + +all: libload.a + +libload.a: ${OBJS} + ${AR} cru $@ ${OBJS} + ${RANLIB} $@ + +clean: + rm -f *.[oa] *errs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libload/amdflash.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,90 @@ +/* + * This module implements the AMFB and AMFW commands for programming + * AMD-style flash memories. Syntax: + * + * AMFB <baseaddr> -- sets the base address for subsequent AMFW commands + * AMFW <offset> <hexstring> -- the actual flash write operation + * + * The flash memory is assumed to be 16 bits wide. The hex string + * argument to the AMFW command is just data, with no header, address, + * length, checksum or other additions. The number of hex digits in the + * string must be a multiple of 4, and the byte order is the same as + * that of TI's *.m0 files: we interpret the string as consisting of + * 16-bit words rather than bytes. + * + * The address to which each flash write is directed is the sum of the + * base given to AMFB and the offset given to AMFW. The fixed offsets + * of 0xAAA and 0x554 (0x555 and 0x2AA in words) prescribed for the flash + * programming command sequence are also made from the base set with AMFB. + */ + +#include <sys/types.h> +#include "types.h" + +static u32 base_addr; + +void +cmd_AMFB(argbulk) + char *argbulk; +{ + char *argv[2]; + u_long addr; + + if (parse_args(argbulk, 1, 1, argv, 0) < 0) + return; + if (parse_hexarg(argv[0], 8, &addr) < 0) { + printf("ERROR: argument must be a valid 32-bit hex address\n"); + return; + } + if (addr & 1) { + printf("ERROR: odd address\n"); + return; + } + base_addr = addr; +} + +void +cmd_AMFW(argbulk) + char *argbulk; +{ + char *argv[3], *s; + u_long offset; + volatile u16 *flashptr; + u32 datum; /* needs to be u32 for decode_hex_digits() */ + int i; + + if (parse_args(argbulk, 2, 2, argv, 0) < 0) + return; + if (parse_hexarg(argv[0], 8, &offset) < 0) { + printf("ERROR: offset argument must a valid 32-bit hex value\n"); + return; + } + if (offset & 1) { + printf("ERROR: odd offset argument\n"); + return; + } + flashptr = (volatile u16 *)(base_addr + offset); + for (s = argv[1]; *s; flashptr++, s += 4) { + if (decode_hex_digits(s, 4, &datum) < 0) { + printf("ERROR: bad AMFW hex string argument\n"); + return; + } + if (*flashptr != 0xFFFF) { + printf("ERROR: flash not blank at %08X\n", + (u_long) flashptr); + return; + } + *(volatile u16 *)(base_addr + 0xAAA) = 0xAA; + *(volatile u16 *)(base_addr + 0x554) = 0x55; + *(volatile u16 *)(base_addr + 0xAAA) = 0xA0; + *flashptr = datum; + for (i = 10000; i; i--) + if (*flashptr == datum) + break; + if (!i) { + printf("ERROR: flash write timeout at %08X\n", + (u_long) flashptr); + return; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libload/cmd_blankchk.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,35 @@ +/* + * Flash blank check command + */ + +#include <sys/types.h> +#include "types.h" + +void +cmd_blankchk(argbulk) + char *argbulk; +{ + char *argv[3]; + u_long start, length; + u_long addr; + int c; + + if (parse_args(argbulk, 2, 2, argv, 0) < 0) + return; + if (parse_hexarg(argv[0], 8, &start) < 0) { + printf("ERROR: arg1 must be a valid 32-bit hex address\n"); + return; + } + if (parse_hexarg(argv[1], 8, &length) < 0) { + printf("ERROR: arg2 must be a valid 32-bit hex value (length)\n"); + return; + } + for (addr = start; addr < start + length; addr++) { + c = *(volatile u8 *)addr; + if (c != 0xFF) { + printf("Not blank: %02X at %08X\n", c, addr); + return; + } + } + printf("OK\n"); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libload/cmd_crc32.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,100 @@ +/* + * The crc32 command is an integrity checking aid for flash dumps + * via loadtool. + */ + +#include <sys/types.h> +#include "types.h" + +/* This CRC-32 table has been computed for the LSB-first direction */ + +static u32 crc32tab[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, + 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, + 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, + 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, + 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, + 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, + 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, + 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, + 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, + 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, + 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, + 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, + 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, + 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, + 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, + 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, + 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, + 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, + 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; + +void +cmd_crc32(argbulk) + char *argbulk; +{ + char *argv[3]; + u_long start, length; + u_long addr, crc; + + if (parse_args(argbulk, 2, 2, argv, 0) < 0) + return; + if (parse_hexarg(argv[0], 8, &start) < 0) { + printf("ERROR: arg1 must be a valid 32-bit hex address\n"); + return; + } + if (parse_hexarg(argv[1], 8, &length) < 0) { + printf("ERROR: arg2 must be a valid 32-bit hex value (length)\n"); + return; + } + crc = 0xFFFFFFFF; + for (addr = start; addr < start + length; addr++) + crc = crc32tab[crc & 0xFF ^ *(volatile u8 *)addr] ^ (crc >> 8); + printf("%08X\n", crc); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libload/cmd_memload.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,52 @@ +/* + * This module implements the ML (memory load) command, which will be + * used by fc-chainload. + * + * The sole argument to the ML command is the body of an S3 record + * with the initial "S3" characters stripped, i.e., starting with the + * "count" byte, followed by the address, data and checksum bytes + * exactly as in the original S3 record. + */ + +#include "types.h" + +void +cmd_memload(argbulk) + char *argbulk; +{ + char *argv[2], *s; + u8 srecbin[256], cksum; + int len, i, c; + u32 addr; + + if (parse_args(argbulk, 1, 1, argv, 0) < 0) + return; + s = argv[0]; + if (decode_hex_digits(s, 2, &len) < 0) { +inv: printf("ERROR: ML argument is invalid\n"); + return; + } + s += 2; + if (len < 6) + goto inv; + srecbin[0] = len; + for (i = 1; i <= len; i++) { + if (decode_hex_digits(s, 2, &c) < 0) + goto inv; + s += 2; + srecbin[i] = c; + } + cksum = 0; + for (i = 0; i <= len; i++) + cksum += srecbin[i]; + if (cksum != 0xFF) { + printf("ERROR: bad ML S-record checksum\n"); + return; + } + len -= 5; + addr = ((u32)srecbin[1] << 24) | + ((u32)srecbin[2] << 16) | + ((u32)srecbin[3] << 8) | + (u32)srecbin[4]; + bcopy(srecbin + 5, addr, len); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libload/hexstrings.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,33 @@ +/* + * The decode_hex_digits() function contained in this module + * will be used by the XRAM and flash loading commands + * which take SREC-like long hex string arguments. + */ + +#include <ctype.h> +#include "types.h" + +decode_hex_digits(str, ndigits, valp) + char *str; + int ndigits; + u32 *valp; +{ + u32 accum; + int i, c; + + accum = 0; + for (i = 0; i < ndigits; i++) { + c = *str++; + if (!isxdigit(c)) + return(-1); + accum <<= 4; + if (isdigit(c)) + accum += c - '0'; + else if (islower(c)) + accum += c - 'a' + 10; + else + accum += c - 'A' + 10; + } + *valp = accum; + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libload/intelflash.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,139 @@ +/* + * This module implements the INFB and INFW commands for programming + * Intel-style flash memories. The syntax and operation are exactly + * the same as the AMD flash counterparts AMFB and AMFW. + * + * The intel-rewrite-sector command (erase+program with a minimum of + * vulnerability for brickable-boot Compal phones) is implemented + * here as well. + */ + +#include <sys/types.h> +#include "types.h" + +static u32 base_addr; + +void +cmd_INFB(argbulk) + char *argbulk; +{ + char *argv[2]; + u_long addr; + + if (parse_args(argbulk, 1, 1, argv, 0) < 0) + return; + if (parse_hexarg(argv[0], 8, &addr) < 0) { + printf("ERROR: argument must be a valid 32-bit hex address\n"); + return; + } + if (addr & 1) { + printf("ERROR: odd address\n"); + return; + } + base_addr = addr; +} + +void +cmd_INFW(argbulk) + char *argbulk; +{ + char *argv[3], *s; + u_long offset; + volatile u16 *flashptr; + u32 datum; /* needs to be u32 for decode_hex_digits() */ + u16 stat; + int i; + + if (parse_args(argbulk, 2, 2, argv, 0) < 0) + return; + if (parse_hexarg(argv[0], 8, &offset) < 0) { + printf("ERROR: offset argument must a valid 32-bit hex value\n"); + return; + } + if (offset & 1) { + printf("ERROR: odd offset argument\n"); + return; + } + flashptr = (volatile u16 *)(base_addr + offset); + for (s = argv[1]; *s; flashptr++, s += 4) { + if (decode_hex_digits(s, 4, &datum) < 0) { + printf("ERROR: bad INFW hex string argument\n"); + return; + } + *flashptr = 0x40; + *flashptr = datum; + for (i = 10000; i; i--) { + stat = *flashptr; + if (stat & 0x80) + break; + } + if (!i) { + printf("ERROR: flash write timeout at %08X\n", + (u_long) flashptr); + return; + } + if (stat & 0x10) { + printf("ERROR: program operation failed at %08X\n", + (u_long) flashptr); + return; + } + } +} + +void +cmd_intel_rewrite_sector(argbulk) + char *argbulk; +{ + char *argv[4]; + u_long srcaddr, dstaddr, len; + const u16 *srcptr; + volatile u16 *flashptr; + u16 stat; + + if (parse_args(argbulk, 3, 3, argv, 0) < 0) + return; + if (parse_hexarg(argv[0], 8, &srcaddr) < 0) { +invarg: printf("ERROR: invalid argument(s)\n"); + return; + } + if (parse_hexarg(argv[1], 8, &dstaddr) < 0) + goto invarg; + if (parse_hexarg(argv[2], 8, &len) < 0) + goto invarg; + if (srcaddr & 1 || dstaddr & 1 || len & 1) { + printf("ERROR: all 3 arguments must be even\n"); + return; + } + srcptr = (const u16 *) srcaddr; + flashptr = (volatile u16 *) dstaddr; + /* unlock the flash sector first */ + *flashptr = 0x60; + *flashptr = 0xD0; + /* clear SR */ + *flashptr = 0x50; + /* erase */ + *flashptr = 0x20; + *flashptr = 0xD0; + /* wait for erase completion */ + for (;;) { + stat = *flashptr; + if (stat & 0x80) + break; + } + if (stat & 0x30) { + printf("ERROR: erase operation failed!\n"); + return; + } + /* now program the new content */ + for (; len; len -= 2) { + *flashptr = 0x40; + *flashptr = *srcptr++; + for (;;) { + stat = *flashptr; + if (stat & 0x80) + break; + } + flashptr++; + } + printf("Operation complete, final SR: %02X\n", stat & 0xFF); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libprintf/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,16 @@ +CC= arm-elf-gcc +CFLAGS= -Os -fno-builtin +AR= arm-elf-ar +RANLIB= arm-elf-ranlib + +OBJS= doprnt.o printf.o putchar.o puts.o sprintf.o sprintf_putchar.o \ + vprintf.o vsprintf.o + +all: libprintf.a + +libprintf.a: ${OBJS} + ${AR} cru $@ ${OBJS} + ${RANLIB} $@ + +clean: + rm -f *.[oa] *errs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libprintf/README Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,15 @@ +The present libprintf is a very light printf implementation that is well-suited +for simple bare-metal programs like loadagent; in the present case it overrides +the much heavier printf implementation in newlib. Programs like the present +loadagent only need printf in order to scribble on the serial console port, +and the most sensible implementation is to have the "character output" function +from the guts of printf point directly to the physical UART output routine, or +a trivial wrapper that turns \n into \r\n. In contrast, newlib's version would +pull in the complete FILE table infrastructure and malloc etc - maybe OK for +more complex embedded programs that use those facilities for other things under +a bona fide RTOS, but it would be disgusting to pull that stuff in for a +minimal program like ours. + +The present printf implementation has been used earlier by the same author +(Michael Spacefalcon) in the StarMON family of PowerPC bootloaders, and in my +MC68x302-based SDSL CPE devices (Hack-o-Rocket and OSDCU).
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libprintf/doprnt.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,297 @@ +/* the guts of printf - this implementation came from 4.3BSD-Tahoe */ + +#include <sys/types.h> +#include <ctype.h> +#include <stdarg.h> + +#define PUTC(ch) ((*outfunc)((ch), outfunc_param)) + +#define ARG() \ + _ulong = flags&LONGINT ? va_arg(argp, long) : va_arg(argp, int); + +#define BUF 12 + +#define todigit(c) ((c) - '0') +#define tochar(n) ((n) + '0') + +#define LONGINT 0x01 /* long integer */ +#define LONGDBL 0x02 /* long double; unimplemented */ +#define SHORTINT 0x04 /* short integer */ +#define ALT 0x08 /* alternate form */ +#define LADJUST 0x10 /* left adjustment */ +#define ZEROPAD 0x20 /* zero (as opposed to blank) pad */ +#define HEXPREFIX 0x40 /* add 0x or 0X prefix */ + +_doprnt(fmt0, argp, outfunc, outfunc_param) + u_char *fmt0; + va_list argp; + void (*outfunc)(); + void *outfunc_param; +{ + register u_char *fmt; /* format string */ + register int ch; /* character from fmt */ + register int cnt; /* return value accumulator */ + register int n; /* random handy integer */ + register char *t; /* buffer pointer */ + u_long _ulong; /* integer arguments %[diouxX] */ + int base; /* base for [diouxX] conversion */ + int dprec; /* decimal precision in [diouxX] */ + int fieldsz; /* field size expanded by sign, etc */ + int flags; /* flags as above */ + int prec; /* precision from format (%.3d), or -1 */ + int realsz; /* field size expanded by decimal precision */ + int size; /* size of converted field or string */ + int width; /* width from format (%8d), or 0 */ + char sign; /* sign prefix (' ', '+', '-', or \0) */ + char softsign; /* temporary negative sign for floats */ + char *digs; /* digits for [diouxX] conversion */ + char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ + + fmt = fmt0; + digs = "0123456789abcdef"; + for (cnt = 0;; ++fmt) { + for (; (ch = *fmt) && ch != '%'; ++cnt, ++fmt) + PUTC(ch); + if (!ch) + return (cnt); + + flags = 0; dprec = 0; width = 0; + prec = -1; + sign = '\0'; + +rflag: switch (*++fmt) { + case ' ': + /* + * ``If the space and + flags both appear, the space + * flag will be ignored.'' + * -- ANSI X3J11 + */ + if (!sign) + sign = ' '; + goto rflag; + case '#': + flags |= ALT; + goto rflag; + case '*': + /* + * ``A negative field width argument is taken as a + * - flag followed by a positive field width.'' + * -- ANSI X3J11 + * They don't exclude field widths read from args. + */ + if ((width = va_arg(argp, int)) >= 0) + goto rflag; + width = -width; + /* FALLTHROUGH */ + case '-': + flags |= LADJUST; + goto rflag; + case '+': + sign = '+'; + goto rflag; + case '.': + if (*++fmt == '*') + n = va_arg(argp, int); + else { + n = 0; + while (isascii(*fmt) && isdigit(*fmt)) + n = 10 * n + todigit(*fmt++); + --fmt; + } + prec = n < 0 ? -1 : n; + goto rflag; + case '0': + /* + * ``Note that 0 is taken as a flag, not as the + * beginning of a field width.'' + * -- ANSI X3J11 + */ + flags |= ZEROPAD; + goto rflag; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + n = 0; + do { + n = 10 * n + todigit(*fmt); + } while (isascii(*++fmt) && isdigit(*fmt)); + width = n; + --fmt; + goto rflag; + case 'L': + flags |= LONGDBL; + goto rflag; + case 'h': + flags |= SHORTINT; + goto rflag; + case 'l': + flags |= LONGINT; + goto rflag; + case 'c': + *(t = buf) = va_arg(argp, int); + size = 1; + sign = '\0'; + goto pforw; + case 'D': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'd': + case 'i': + ARG(); + if ((long)_ulong < 0) { + _ulong = -_ulong; + sign = '-'; + } + base = 10; + goto number; + case 'n': + if (flags & LONGINT) + *va_arg(argp, long *) = cnt; + else if (flags & SHORTINT) + *va_arg(argp, short *) = cnt; + else + *va_arg(argp, int *) = cnt; + break; + case 'O': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'o': + ARG(); + base = 8; + goto nosign; + case 'p': + /* + * ``The argument shall be a pointer to void. The + * value of the pointer is converted to a sequence + * of printable characters, in an implementation- + * defined manner.'' + * -- ANSI X3J11 + */ + /* NOSTRICT */ + _ulong = (u_long)va_arg(argp, void *); + base = 16; + goto nosign; + case 's': + if (!(t = va_arg(argp, char *))) + t = "(null)"; + if (prec >= 0) { + /* + * can't use strlen; can only look for the + * NUL in the first `prec' characters, and + * strlen() will go further. + */ + char *p; + + for (p = t, size = 0; size < prec; p++, size++) + if (*p == '\0') + break; + } else + size = strlen(t); + sign = '\0'; + goto pforw; + case 'U': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'u': + ARG(); + base = 10; + goto nosign; + case 'X': + digs = "0123456789ABCDEF"; + /* FALLTHROUGH */ + case 'x': + ARG(); + base = 16; + /* leading 0x/X only if non-zero */ + if (flags & ALT && _ulong != 0) + flags |= HEXPREFIX; + + /* unsigned conversions */ +nosign: sign = '\0'; + /* + * ``... diouXx conversions ... if a precision is + * specified, the 0 flag will be ignored.'' + * -- ANSI X3J11 + */ +number: if ((dprec = prec) >= 0) + flags &= ~ZEROPAD; + + /* + * ``The result of converting a zero value with an + * explicit precision of zero is no characters.'' + * -- ANSI X3J11 + */ + t = buf + BUF; + if (_ulong != 0 || prec != 0) { + do { + *--t = digs[_ulong % base]; + _ulong /= base; + } while (_ulong); + digs = "0123456789abcdef"; + if (flags & ALT && base == 8 && *t != '0') + *--t = '0'; /* octal leading 0 */ + } + size = buf + BUF - t; + +pforw: + /* + * All reasonable formats wind up here. At this point, + * `t' points to a string which (if not flags&LADJUST) + * should be padded out to `width' places. If + * flags&ZEROPAD, it should first be prefixed by any + * sign or other prefix; otherwise, it should be blank + * padded before the prefix is emitted. After any + * left-hand padding and prefixing, emit zeroes + * required by a decimal [diouxX] precision, then print + * the string proper, then emit zeroes required by any + * leftover floating precision; finally, if LADJUST, + * pad with blanks. + */ + + /* + * compute actual size, so we know how much to pad + * fieldsz excludes decimal prec; realsz includes it + */ + fieldsz = size; + if (sign) + fieldsz++; + if (flags & HEXPREFIX) + fieldsz += 2; + realsz = dprec > fieldsz ? dprec : fieldsz; + + /* right-adjusting blank padding */ + if ((flags & (LADJUST|ZEROPAD)) == 0 && width) + for (n = realsz; n < width; n++) + PUTC(' '); + /* prefix */ + if (sign) + PUTC(sign); + if (flags & HEXPREFIX) { + PUTC('0'); + PUTC((char)*fmt); + } + /* right-adjusting zero padding */ + if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) + for (n = realsz; n < width; n++) + PUTC('0'); + /* leading zeroes from decimal precision */ + for (n = fieldsz; n < dprec; n++) + PUTC('0'); + + for (n = size; --n >= 0; ) + PUTC(*t++); + /* left-adjusting padding (always blank) */ + if (flags & LADJUST) + for (n = realsz; n < width; n++) + PUTC(' '); + /* finally, adjust cnt */ + cnt += width > realsz ? width : realsz; + break; + case '\0': /* "%?" prints ?, unless ? is NULL */ + return (cnt); + default: + PUTC((char)*fmt); + cnt++; + } + } + /* NOTREACHED */ +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libprintf/printf.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,15 @@ +#include <stdarg.h> + +extern void putchar(); + +int +printf(char *fmt, ...) +{ + va_list ap; + int len; + + va_start(ap, fmt); + len = _doprnt(fmt, ap, &putchar); + va_end(ap); + return(len); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libprintf/putchar.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,9 @@ +extern void serial_out(); + +void +putchar(ch) +{ + if (ch == '\n') + serial_out('\r'); + serial_out(ch); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libprintf/puts.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,10 @@ +void +puts(s) + char *s; +{ + int c; + + while (c = *s++) + putchar(c); + putchar('\n'); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libprintf/sprintf.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,18 @@ +#include <stdarg.h> + +extern void _sprintf_putchar(); + +int +sprintf(char *strdest, char *fmt, ...) +{ + va_list ap; + char *strptr; + int len; + + strptr = strdest; + va_start(ap, fmt); + len = _doprnt(fmt, ap, &_sprintf_putchar, &strptr); + va_end(ap); + *strptr = '\0'; + return(len); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libprintf/sprintf_putchar.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,7 @@ +void +_sprintf_putchar(ch, pp) + int ch; + char **pp; +{ + *(*pp)++ = ch; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libprintf/vprintf.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,11 @@ +#include <stdarg.h> + +extern void putchar(); + +int +vprintf(fmt, ap) + char *fmt; + va_list ap; +{ + return(_doprnt(fmt, ap, &putchar)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libprintf/vsprintf.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,17 @@ +#include <stdarg.h> + +extern void _sprintf_putchar(); + +int +vsprintf(str, fmt, ap) + va_list ap; + char *str, *fmt; +{ + char *strptr; + int len; + + strptr = str; + len = _doprnt(fmt, ap, &_sprintf_putchar, &strptr); + *strptr = '\0'; + return(len); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libtiffs/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,16 @@ +CC= arm-elf-gcc +CFLAGS= -Os -fno-builtin +CPPFLAGS=-I../include +AR= arm-elf-ar +RANLIB= arm-elf-ranlib + +OBJS= basicfind.o cmd_find.o findfile.o globals.o init.o rdinmem.o + +all: libtiffs.a + +libtiffs.a: ${OBJS} + ${AR} cru $@ ${OBJS} + ${RANLIB} $@ + +clean: + rm -f *.[oa] *errs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libtiffs/basicfind.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,65 @@ +#include <sys/types.h> +#include "types.h" +#include "struct.h" +#include "globals.h" +#include "macros.h" + +extern char *index(); + +static +find_named_child(start, seekname) + char *seekname; +{ + int ino; + struct inode *irec; + + for (ino = start; ino != 0xFFFF; ino = irec->sibling) { + irec = mpffs_active_index + ino; + if (!irec->type) + continue; + if (!strcmp(inode_to_dataptr(irec), seekname)) + return(ino); + } + return(0); +} + +mpffs_pathname_to_inode(pathname) + char *pathname; +{ + int ino, stat; + struct inode *irec; + char *cur, *next; + + stat = mpffs_init(); + if (stat < 0) + return(stat); + cur = pathname; + if (*cur == '/') + cur++; + for (ino = mpffs_root_ino; cur; cur = next) { + if (!*cur) + break; + next = index(cur, '/'); + if (next == cur) { + printf("malformed pathname: multiple adjacent slashes\n"); + return(-1); + } + if (next) + *next++ = '\0'; + irec = mpffs_active_index + ino; + if (irec->type != OBJTYPE_DIR) { + printf("Error: non-terminal non-directory\n"); + if (next) + next[-1] = '/'; + return(-1); + } + ino = find_named_child(irec->descend, cur); + if (next) + next[-1] = '/'; + if (!ino) { + printf("Error: pathname component not found\n"); + return(-1); + } + } + return(ino); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libtiffs/cmd_find.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,25 @@ +#include <sys/types.h> +#include "types.h" + +void +cmd_find(argbulk) + char *argbulk; +{ + char *argv[2]; + int stat, cont; + u8 *start; + size_t size; + + if (parse_args(argbulk, 1, 1, argv, 0) < 0) + return; + stat = mpffs_find_file(argv[0], &start, &size, &cont); + if (stat < 0) + return; + printf("chunk @%08X size %x\n", (u32)start, (u32)size); + while (cont) { + stat = mpffs_get_segment(cont, &start, &size, &cont); + if (stat < 0) + return; + printf("chunk @%08X size %x\n", (u32)start, (u32)size); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libtiffs/findfile.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,106 @@ +#include <sys/types.h> +#include "types.h" +#include "struct.h" +#include "globals.h" +#include "macros.h" + +static u8 * +find_endofchunk(ino) +{ + struct inode *irec = mpffs_active_index + ino; + u8 *p; + int i; + + p = inode_to_dataptr(irec) + irec->len; + for (i = 0; i < 16; i++) { + p--; + if (!*p) + return(p); + if (*p != 0xFF) + break; + } + printf("Error: inode #%x has no valid termination\n", ino); + return(p); /* XXX */ +} + +mpffs_find_file(pathname, startret, sizeret, continue_ret) + char *pathname; + u8 **startret; + size_t *sizeret; + int *continue_ret; +{ + int ino, cont; + struct inode *irec; + u8 *start, *end; + int size; + + ino = mpffs_pathname_to_inode(pathname); + if (ino <= 0) + return(-1); + irec = mpffs_active_index + ino; + if (irec->type != OBJTYPE_FILE) { + printf("Error: %s is not a regular file\n", pathname); + return(-1); + } + start = inode_to_dataptr(irec); + start += strlen(start) + 1; + end = find_endofchunk(ino); + size = end - start; + if (size < 0) + size = 0; + cont = irec->descend; + if (cont == 0xFFFF) + cont = 0; + if (startret) + *startret = start; + if (sizeret) + *sizeret = size; + if (continue_ret) + *continue_ret = cont; + return(0); +} + +mpffs_get_segment(ino, startret, sizeret, continue_ret) + int ino; + u8 **startret; + size_t *sizeret; + int *continue_ret; +{ + int cont; + struct inode *irec; + u8 *start, *end; + int size; + + for (;;) { + irec = mpffs_active_index + ino; + if (irec->type) + break; + if (irec->sibling == 0xFFFF) { + printf("Error: segment inode #%d: deleted and no sibling\n", + ino); + return(-1); + } + ino = irec->sibling; + } + if (irec->type != OBJTYPE_SEGMENT) { + printf("Error: inode #%x is not a segment\n", ino); + return(-1); + } + start = inode_to_dataptr(irec); + end = find_endofchunk(ino); + size = end - start; + if (size <= 0) { + printf("Error: segment inode #%x: bad length\n", ino); + return(-1); + } + cont = irec->descend; + if (cont == 0xFFFF) + cont = 0; + if (startret) + *startret = start; + if (sizeret) + *sizeret = size; + if (continue_ret) + *continue_ret = cont; + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libtiffs/globals.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,8 @@ +/* global variables for the MPFFS reader code */ + +#include "types.h" +#include "struct.h" + +struct inode *mpffs_active_index; +int mpffs_root_ino; +int mpffs_init_done;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libtiffs/globals.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,9 @@ +/* global variables for the MPFFS reader code - extern declarations */ + +extern struct inode *mpffs_active_index; +extern int mpffs_root_ino; +extern int mpffs_init_done; + +extern const u32 mpffs_base_addr; +extern const u32 mpffs_sector_size; +extern const int mpffs_nsectors;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libtiffs/init.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,74 @@ +#include "types.h" +#include "struct.h" +#include "globals.h" +#include "macros.h" + +static const u8 ffs_sector_signature[6] = {'F', 'f', 's', '#', 0x10, 0x02}; +static const u8 blank_flash_line[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF}; + +static +find_indexblk() +{ + u32 sector_addr; + u8 *sector_ptr; + int i; + + printf("Looking for MPFFS active index block\n"); + sector_addr = mpffs_base_addr; + for (i = 0; i < mpffs_nsectors; i++) { + sector_ptr = (u8 *) sector_addr; + if (!bcmp(sector_ptr, ffs_sector_signature, 6) && + sector_ptr[8] == 0xAB) { + printf("Found at %08X\n", sector_addr); + mpffs_active_index = (struct inode *) sector_ptr; + return(0); + } + sector_addr += mpffs_sector_size; + } + printf("Error: Not found in any of the %d candidate sectors\n", + mpffs_nsectors); + return(-1); +} + +static +find_rootino() +{ + int ino; + struct inode *irec; + + printf("Looking for the root inode\n"); + for (ino = 1; ; ino++) { + if (ino >= mpffs_sector_size >> 4) { + printf("Error: Hit end of sector, no root inode found\n"); + return(-1); + } + irec = mpffs_active_index + ino; + if (!bcmp((u8 *) irec, blank_flash_line, 16)) { + printf("Error: Hit blank flash, no root inode found\n"); + return(-1); + } + if (irec->type == OBJTYPE_DIR && *inode_to_dataptr(irec) == '/') + break; + } + printf("Found at inode #%x\n", ino); + mpffs_root_ino = ino; + return(0); +} + +mpffs_init() +{ + int stat; + + if (mpffs_init_done) + return(0); + stat = find_indexblk(); + if (stat < 0) + return(stat); + stat = find_rootino(); + if (stat < 0) + return(stat); + mpffs_init_done = 1; + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libtiffs/macros.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,1 @@ +#define inode_to_dataptr(i) ((u8 *)mpffs_base_addr + ((i)->dataptr << 4))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libtiffs/rdinmem.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,42 @@ +#include <sys/types.h> +#include "types.h" +#include "struct.h" +#include "globals.h" +#include "macros.h" + +mpffs_read_into_ram(pathname, buf, maxlen, lenrtn) + char *pathname; + u8 *buf; + size_t maxlen, *lenrtn; +{ + int stat, cont; + u8 *chunk_start; + size_t chunk_size, real_len, roomleft; + + stat = mpffs_find_file(pathname, &chunk_start, &chunk_size, &cont); + if (stat < 0) + return(stat); + if (chunk_size > maxlen) { +toobig: printf("Error: %s is bigger than the read buffer\n", pathname); + return(-1); + } + real_len = chunk_size; + bcopy(chunk_start, buf, chunk_size); + buf += chunk_size; + roomleft = maxlen - chunk_size; + while (cont) { + stat = mpffs_get_segment(cont, &chunk_start, &chunk_size, + &cont); + if (stat < 0) + return(stat); + if (chunk_size > roomleft) + goto toobig; + real_len += chunk_size; + bcopy(chunk_start, buf, chunk_size); + buf += chunk_size; + roomleft -= chunk_size; + } + if (lenrtn) + *lenrtn = real_len; + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/libtiffs/struct.h Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,25 @@ +struct inode { + u16 len; + u8 reserved1; + u8 type; + u16 descend; + u16 sibling; + u32 dataptr; + u16 sequence; + u16 updates; +}; + +#define OBJTYPE_FILE 0xF1 +#define OBJTYPE_DIR 0xF2 +#define OBJTYPE_SEGMENT 0xF4 + +struct journal { + u8 status; + u8 objtype; + u16 this_ino; + u16 link_ptr; + u16 replacee; + u32 location; + u16 size; + u16 repli; /* ??? */ +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/loadagent/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,38 @@ +CC= arm-elf-gcc +CFLAGS= -Os -fno-builtin +CPPFLAGS=-I../include +LD= arm-elf-ld +OBJCOPY=arm-elf-objcopy + +INSTDIR=/usr/local/share/freecalypso + +PROG= loadagent +OBJS= crt0.o cmdtab.o main.o mygetchar.o +LIBS= ../libload/libload.a ../libcommon/libcommon.a ../libprintf/libprintf.a \ + ../libbase/libbase.a +LDS= ../env/iram.lds + +TC_LIBS=`${CC} -print-file-name=libc.a` \ + `${CC} -print-file-name=libgcc.a` + +all: ${PROG}.srec + +crt0.S: ../env/crt0.S + ln -s $< . + +${PROG}.elf: ${OBJS} ${LIBS} ${LDS} + ${LD} -N --defsym Base_addr=0x838000 --defsym stack_bottom=0x83FFFC \ + -T ${LDS} -o $@ ${OBJS} ${LIBS} \ + --start-group ${TC_LIBS} --end-group + +${PROG}.srec: ${PROG}.elf + ${OBJCOPY} -O srec --srec-forceS3 --srec-len=30 $< $@ + +install: + mkdir -p ${INSTDIR} + install -c ${PROG}.srec ${INSTDIR} + +clean: + rm -f *.o *errs *core *.elf *.bin *.srec crt0.S + +FRC:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/loadagent/cmdtab.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,52 @@ +#include "cmdtab.h" + +extern void cmd_AMFB(); +extern void cmd_AMFW(); +extern void cmd_INFB(); +extern void cmd_INFW(); +extern void cmd_abbr(); +extern void cmd_abbw(); +extern void cmd_blankchk(); +extern void cmd_crc32(); +extern void cmd_jump(); +extern void cmd_r8(); +extern void cmd_r16(); +extern void cmd_r32(); +extern void cmd_w8(); +extern void cmd_w16(); +extern void cmd_w32(); + +extern void cmd_baud_switch(); +extern void cmd_intel_rewrite_sector(); +extern void cmd_memdump_human(); +extern void cmd_memdump_machine(); +extern void cmd_memload(); + +extern void abb_init(); +extern void abb_power_off(); + +const struct cmdtab cmdtab[] = { + {"AMFB", cmd_AMFB}, + {"AMFW", cmd_AMFW}, + {"DUMP", cmd_memdump_machine}, + {"INFB", cmd_INFB}, + {"INFW", cmd_INFW}, + {"ML", cmd_memload}, + {"abbinit", abb_init}, + {"abbr", cmd_abbr}, + {"abbw", cmd_abbw}, + {"baud", cmd_baud_switch}, + {"blankchk", cmd_blankchk}, + {"crc32", cmd_crc32}, + {"dump", cmd_memdump_human}, + {"intel-rewrite-sector", cmd_intel_rewrite_sector}, + {"jump", cmd_jump}, + {"poweroff", abb_power_off}, + {"r8", cmd_r8}, + {"r16", cmd_r16}, + {"r32", cmd_r32}, + {"w8", cmd_w8}, + {"w16", cmd_w16}, + {"w32", cmd_w32}, + {0, 0} +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/loadagent/main.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,15 @@ +/* + * FreeCalypso loadagent main() function lives here + */ + +main() +{ + uart_select_init(); + printf("FreeCalypso loadagent running\n"); + print_boot_rom_info(); + for (;;) { + putchar('='); + if (command_entry()) + command_dispatch(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/loadagent/mygetchar.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,21 @@ +/* + * The interactive command entry (editing) function in libcommon + * will call mygetchar() for its character input. It is supposed + * to be a blocking wait for input, but in some programs other + * processing can be done while waiting - for example, check for + * keypad presses as well. This is the basic version which waits + * for serial input and nothing else. + */ + +extern int serial_in_poll(); + +int +mygetchar() +{ + register int c; + + do + c = serial_in_poll(); + while (c < 0); + return c; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/pirexplore/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,32 @@ +CC= arm-elf-gcc +CFLAGS= -Os -fno-builtin +CPPFLAGS=-I../include +LD= arm-elf-ld +OBJCOPY=arm-elf-objcopy + +PROG= pirexplore +OBJS= crt0.o cmdtab.o ffsparam.o flashid.o lcd.o main.o mygetchar.o rtc.o +LIBS= ../libtiffs/libtiffs.a ../libcommon/libcommon.a \ + ../libprintf/libprintf.a ../libbase/libbase.a +LDS= ../env/iram.lds + +TC_LIBS=`${CC} -print-file-name=libc.a` \ + `${CC} -print-file-name=libgcc.a` + +all: ${PROG}.srec + +crt0.S: ../env/crt0.S + ln -s $< . + +${PROG}.elf: ${OBJS} ${LIBS} ${LDS} + ${LD} -N --defsym Base_addr=0x800750 --defsym stack_bottom=0x87FFFC \ + -T ${LDS} -o $@ ${OBJS} ${LIBS} \ + --start-group ${TC_LIBS} --end-group + +${PROG}.srec: ${PROG}.elf + ${OBJCOPY} -O srec --srec-forceS3 --srec-len=30 $< $@ + +clean: + rm -f *.o *errs *core *.elf *.bin *.srec crt0.S + +FRC:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/pirexplore/cmdtab.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,57 @@ +#include "cmdtab.h" + +extern void cmd_abbr(); +extern void cmd_abbw(); +extern void cmd_baud_switch(); +extern void cmd_blit(); +extern void cmd_dieid(); +extern void cmd_find(); +extern void cmd_flashid(); +extern void cmd_jump(); +extern void cmd_lcdfill(); +extern void cmd_lcdinit(); +extern void cmd_lcdtest(); +extern void cmd_r8(); +extern void cmd_r16(); +extern void cmd_r32(); +extern void cmd_rtc(); +extern void cmd_rtccomp(); +extern void cmd_spca(); +extern void cmd_spcainit(); +extern void cmd_w8(); +extern void cmd_w16(); +extern void cmd_w32(); + +extern void abb_init(); +extern void abb_power_off(); +extern void cmd_memdump_human(); +extern void mpffs_init(); + +const struct cmdtab cmdtab[] = { + {"abbinit", abb_init}, + {"abbr", cmd_abbr}, + {"abbw", cmd_abbw}, + {"baud", cmd_baud_switch}, + {"blit", cmd_blit}, + {"dieid", cmd_dieid}, + {"dump", cmd_memdump_human}, + {"ffsinit", mpffs_init}, + {"find", cmd_find}, + {"flashid", cmd_flashid}, + {"jump", cmd_jump}, + {"lcdfill", cmd_lcdfill}, + {"lcdinit", cmd_lcdinit}, + {"lcdtest", cmd_lcdtest}, + {"poweroff", abb_power_off}, + {"r8", cmd_r8}, + {"r16", cmd_r16}, + {"r32", cmd_r32}, + {"rtc", cmd_rtc}, + {"rtccomp", cmd_rtccomp}, + {"spca", cmd_spca}, + {"spcainit", cmd_spcainit}, + {"w8", cmd_w8}, + {"w16", cmd_w16}, + {"w32", cmd_w32}, + {0, 0} +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/pirexplore/ffsparam.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,11 @@ +/* + * This module is linked into pirexplore for the purpose of telling the + * somewhat generic libmpffs exactly where the FFS is located on this + * device and how it is structured. + */ + +#include "types.h" + +const u32 mpffs_base_addr = 0x02000000; +const u32 mpffs_sector_size = 0x40000; +const int mpffs_nsectors = 18;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/pirexplore/flashid.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,29 @@ +#include "types.h" + +void +cmd_flashid(argbulk) + char *argbulk; +{ + char *argv[2]; + u32 base_addr; + + if (parse_args(argbulk, 1, 1, argv, 0) < 0) + return; + if (argv[0][0] == '1' && !argv[0][1]) + base_addr = 0x03000000; + else if (argv[0][0] == '2' && !argv[0][1]) + base_addr = 0x02000000; + else { + printf("ERROR: argument must be 1 or 2\n"); + return; + } + printf("Base addr: %08X\n", base_addr); + *(volatile u16 *)(base_addr + 0xAAA) = 0xAA; + *(volatile u16 *)(base_addr + 0x554) = 0x55; + *(volatile u16 *)(base_addr + 0xAAA) = 0x90; + printf("offset 00: %04X\n", *(volatile u16 *)(base_addr + 0x00)); + printf("offset 02: %04X\n", *(volatile u16 *)(base_addr + 0x02)); + printf("offset 1C: %04X\n", *(volatile u16 *)(base_addr + 0x1C)); + printf("offset 1E: %04X\n", *(volatile u16 *)(base_addr + 0x1E)); + *(volatile u16 *)(base_addr + 0xAAA) = 0xF0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/pirexplore/lcd.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,276 @@ +/* + * Almost all of this Pirelli LCD black magic has been lifted from OsmocomBB. + */ + +#include <sys/types.h> +#include "types.h" + +#define GPIO_OUT_REG (*(volatile u16 *)0xFFFE4802) +#define nCS4_ADDR0 (*(volatile u16 *)0x02800000) +#define nCS4_ADDR2 (*(volatile u16 *)0x02800002) + +fb_spca_write(addr, data) +{ + GPIO_OUT_REG &= 0xFF7F; + nCS4_ADDR0 = addr; + nCS4_ADDR2 = data; +} + +void +cmd_spca(argbulk) + char *argbulk; +{ + char *argv[3]; + u_long addr, data; + + if (parse_args(argbulk, 2, 2, argv, 0) < 0) + return; + if (parse_hexarg(argv[0], 4, &addr) < 0) { + printf("ERROR: arg1 must be a valid 16-bit hex value\n"); + return; + } + if (parse_hexarg(argv[1], 4, &data) < 0) { + printf("ERROR: arg2 must be a valid 16-bit hex value\n"); + return; + } + fb_spca_write(addr, data); +} + +void +cmd_spcainit() +{ + /* + * Apparently we have to give it a reset pulse, then immediately + * do the black magic register write sequence. + */ + GPIO_OUT_REG = 0x0000; + GPIO_OUT_REG = 0x0012; + /* non-understandable voodoo copied from OsmocomBB */ + fb_spca_write(0x7e, 0x00); /* internal register access */ + osmo_delay_ms(10); + fb_spca_write(0x7a, 0x00); /* keep CPU in reset state */ + osmo_delay_ms(10); + fb_spca_write(0x7f, 0x00); /* select main page */ + osmo_delay_ms(5); + fb_spca_write(0x72, 0x07); /* don't reshape timing, 16 bit mode */ + fb_spca_write(0x14, 0x03); + fb_spca_write(0x7f, 0x00); /* select main page */ + osmo_delay_ms(5); + fb_spca_write(0x06, 0xff); + fb_spca_write(0x7f, 0x09); + fb_spca_write(0x19, 0x08); /* backlight: 0x08 is on, 0x0c is off */ + fb_spca_write(0x23, 0x18); +} + +enum s6b33b1x_cmdflag { CMD, DATA, END }; + +struct s6b33b1x_cmdlist { + enum s6b33b1x_cmdflag is_cmd:8; /* 1: is a command, 0: is data, 2: end marker! */ + u_char data; /* 8 bit to send to LC display */ +}; + +static const struct s6b33b1x_cmdlist +s6b33b1x_initdata[] = { + { CMD, 0x26 }, /* CMD DCDC and AMP ON/OFF set */ + { DATA, 0x00 }, /* DATA: everything off */ + { CMD, 0x02 }, /* CMD Oscillation Mode Set */ + { DATA, 0x00 }, /* DATA: oscillator off */ + { CMD, 0x2c }, /* CMD Standby Mode off */ + { CMD, 0x50 }, /* CMD Display off */ + { CMD, 0x02 }, /* CMD Oscillation Mode Set */ + { DATA, 0x01 }, /* DATA: oscillator on */ + { CMD, 0x26 }, /* CMD DCDC and AMP ON/OFF set */ + { DATA, 0x01 }, /* DATA: Booster 1 on */ + { CMD, 0x26 }, /* CMD DCDC and AMP ON/OFF set */ + { DATA, 0x09 }, /* DATA: Booster 1 on, OP-AMP on */ + { CMD, 0x26 }, /* CMD DCDC and AMP ON/OFF set */ + { DATA, 0x0b }, /* DATA: Booster 1 + 2 on, OP-AMP on */ + { CMD, 0x26 }, /* CMD DCDC and AMP ON/OFF set */ + { DATA, 0x0f }, /* DATA: Booster 1 + 2 + 3 on, OP-AMP on */ + { CMD, 0x20 }, /* CMD DC-DC Select */ + { DATA, 0x01 }, /* DATA: step up x1.5 */ + { CMD, 0x24 }, /* CMD DCDC Clock Division Set */ + { DATA, 0x0a }, /* DATA: fPCK = fOSC/6 */ + { CMD, 0x2a }, /* CMD Contrast Control */ + { DATA, 0x2d }, /* DATA: default contrast */ + { CMD, 0x30 }, /* CMD Adressing mode set */ + { DATA, 0x0b }, /* DATA: 65536 color mode */ + { CMD, 0x10 }, /* CMD Driver output mode set */ + { DATA, 0x03 }, /* DATA: Display duty: 1/132 */ + { CMD, 0x34 }, /* CMD N-line inversion set */ + { DATA, 0x88 }, /* DATA: inversion on, one frame, every 8 blocks */ + { CMD, 0x40 }, /* CMD Entry mode set */ + { DATA, 0x00 }, /* DATA: Y address counter mode */ + { CMD, 0x28 }, /* CMD Temperature Compensation set */ + { DATA, 0x01 }, /* DATA: slope -0.05%/degC */ + { CMD, 0x32 }, /* CMD ROW vector mode set */ + { DATA, 0x01 }, /* DATA: every 2 subgroup */ + { CMD, 0x51 }, /* CMD Display on */ + { END, 0x00 }, /* MARKER: end of list */ +}; + +static void +fb_s6b33b1x_send_cmdlist(p) + struct s6b33b1x_cmdlist *p; +{ + while(p->is_cmd != END) { + nCS4_ADDR0 = p->data; + p++; + } +} + +void +cmd_lcdinit() +{ + GPIO_OUT_REG |= 0x0080; + fb_s6b33b1x_send_cmdlist(s6b33b1x_initdata); +} + +set_lcd_addr_region(xstart, xend, ystart, yend) +{ + GPIO_OUT_REG |= 0x0080; + nCS4_ADDR0 = 0x42; + nCS4_ADDR0 = ystart + 4; + nCS4_ADDR0 = yend + 4; + nCS4_ADDR0 = 0x43; + nCS4_ADDR0 = xstart; + nCS4_ADDR0 = xend; +} + +void +cmd_lcdfill(argbulk) + char *argbulk; +{ + int argc; + char *argv[6]; + u_long pixval; + int xstart, xend, ystart, yend; + int npix; + + if (parse_args(argbulk, 1, 5, argv, &argc) < 0) + return; + if (parse_hexarg(argv[0], 4, &pixval) < 0) { + printf("ERROR: arg1 must be a valid 16-bit hex value\n"); + return; + } + switch (argc) { + case 1: + xstart = ystart = 0; + xend = yend = 127; + break; + case 5: + xstart = atoi(argv[1]); + if (xstart < 0 || xstart > 127) { +range_err: printf("ERROR: coordinate arg out of range\n"); + return; + } + xend = atoi(argv[2]); + if (xend < 0 || xend > 127) + goto range_err; + ystart = atoi(argv[3]); + if (ystart < 0 || ystart > 127) + goto range_err; + yend = atoi(argv[4]); + if (yend < 0 || yend > 127) + goto range_err; + if (xend < xstart || yend < ystart) { + printf("ERROR: negative range\n"); + return; + } + break; + default: + printf("ERROR: wrong number of arguments\n"); + return; + } + set_lcd_addr_region(xstart, xend, ystart, yend); + npix = (xend + 1 - xstart) * (yend + 1 - ystart); + while (npix--) + nCS4_ADDR2 = pixval; +} + +void +cmd_lcdtest() +{ + int i, j, k, p; + + /* + * The result of this command should be 8 vertical bars + * in the natural RGB order. + */ + set_lcd_addr_region(10, 89, 10, 89); + for (i = 0; i < 80; i++) { + for (j = 0; j < 8; j++) { + p = 0; + if (j & 4) + p |= 0xF800; + if (j & 2) + p |= 0x07E0; + if (j & 1) + p |= 0x001F; + for (k = 0; k < 10; k++) + nCS4_ADDR2 = p; + } + } +} + +void +cmd_blit(argbulk) + char *argbulk; +{ + int argc; + char *argv[6]; + u16 imgbuf[16384]; + size_t img_file_size; + int xstart, ystart, width, height; + int npix, i; + + if (parse_args(argbulk, 1, 5, argv, &argc) < 0) + return; + if (mpffs_read_into_ram(argv[0], imgbuf, 32768, &img_file_size) < 0) + return; + switch (argc) { + case 1: + xstart = ystart = 0; + width = height = 128; + break; + case 3: + xstart = ystart = 0; + goto widthheight; + case 5: + xstart = atoi(argv[3]); + if (xstart < 0 || xstart > 127) { +range_err: printf("ERROR: coordinate arg out of range\n"); + return; + } + ystart = atoi(argv[4]); + if (ystart < 0 || ystart > 127) + goto range_err; + /* FALL THRU */ + widthheight: + width = atoi(argv[1]); + if (width < 1 || width > 128) + goto range_err; + height = atoi(argv[2]); + if (height < 1 || height > 128) + goto range_err; + if (xstart + width > 128) + goto range_err; + if (ystart + height > 128) + goto range_err; + break; + default: + printf("ERROR: wrong number of arguments\n"); + return; + } + npix = width * height; + if (img_file_size != npix * 2) { + printf("ERROR: image file size (%u bytes) does not match WxH\n", + img_file_size); + return; + } + set_lcd_addr_region(xstart, xstart + width - 1, + ystart, ystart + height - 1); + /* the artwork images in Pirelli's FFS appear to be inverted */ + for (i = 0; i < npix; i++) + nCS4_ADDR2 = ~imgbuf[i]; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/pirexplore/main.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,34 @@ +#include "types.h" + +main() +{ + uart_select_init(); + printf("Pirelli hardware exploration utility running\n"); + print_boot_rom_info(); + /* + * Make the same register settings as in the init script used by + * fc-loadtool and fc-xram: ../../loadtools/scripts/pirelli.init + */ + *(volatile u16 *)0xfffffb00 = 0x00A4; + *(volatile u16 *)0xfffffb02 = 0x00A4; + *(volatile u16 *)0xfffffb06 = 0x00A4; + *(volatile u16 *)0xfffef006 = 0x0008; + /* + * Other register settings replicating what OsmocomBB does + * in board/pirelli_dpl10/init.c + */ + *(volatile u16 *)0xfffef008 = 0x7090; + *(volatile u16 *)0xfffef00a = 0x021F; + *(volatile u16 *)0xfffe4804 = 0xFF6D; + *(volatile u16 *)0xfffe4802 = 0x0000; + /* nCS4 setup for SPCA552E */ + *(volatile u16 *)0xfffffb0a = 0x00A7; + /* initialize PWL registers like OsmocomBB does */ + *(volatile u8 *)0xfffe8000 = 0x32; + *(volatile u8 *)0xfffe8001 = 0x01; + for (;;) { + putchar('='); + if (command_entry()) + command_dispatch(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/pirexplore/mygetchar.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,21 @@ +/* + * The interactive command entry (editing) function in libcommon + * will call mygetchar() for its character input. It is supposed + * to be a blocking wait for input, but in some programs other + * processing can be done while waiting - for example, check for + * keypad presses as well. This is the basic version which waits + * for serial input and nothing else. + */ + +extern int serial_in_poll(); + +int +mygetchar() +{ + register int c; + + do + c = serial_in_poll(); + while (c < 0); + return c; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/pirexplore/rtc.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,59 @@ +#include "types.h" +#include "rtc.h" + +static void +read_time(tm) + struct rtctime *tm; +{ + tm->year = RTC_REGS.rtc_cur.year; + tm->month = RTC_REGS.rtc_cur.month; + tm->day_of_month = RTC_REGS.rtc_cur.day_of_month; + tm->day_of_week = RTC_REGS.rtc_cur.day_of_week; + tm->hours = RTC_REGS.rtc_cur.hours; + tm->minutes = RTC_REGS.rtc_cur.minutes; + tm->seconds = RTC_REGS.rtc_cur.seconds; +} + +void +cmd_rtc() +{ + u8 ctrl; + struct rtctime time1, time2; + int c; + + ctrl = RTC_REGS.rtc_ctrl_reg; + printf("RTC_CTRL_REG = %02X ", ctrl); + switch (ctrl) { + case 0x00: + printf("(frozen)\n"); + break; + case 0x01: + printf("(running)\n"); + break; + default: + printf("(unexpected)\n"); + return; + } + printf("Reading RTC time"); + for (;;) { + c = serial_in_poll(); + if (c >= 0) { + printf("<INTERRUPT>\n"); + return; + } + read_time(&time1); + read_time(&time2); + if (!bcmp(&time1.minutes, &time2.minutes, 6)) + break; + } + printf("\nDATE %02X-%02X-%02X DOW %02X TIME %02X:%02X:%02X\n", + time2.year, time2.month, time2.day_of_month, time2.day_of_week, + time2.hours, time2.minutes, time2.seconds); +} + +void +cmd_rtccomp() +{ + printf("%04X\n", (RTC_REGS.rtc_comp_msb_reg << 8) | + RTC_REGS.rtc_comp_lsb_reg); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/tf-breakin/Makefile Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,20 @@ +CC= arm-elf-gcc +OBJCOPY=arm-elf-objcopy + +all: payload.o payload.bin embed.c + +.SUFFIXES: .o .bin + +.o.bin: + ${OBJCOPY} -O binary $< $@ + +mkembed: mkembed.c + gcc -O2 -o $@ $@.c + +embed.c: payload.bin mkembed + ./mkembed payload.bin $@ + +clean: + rm -f *.o *errs *core *.bin mkembed embed.c + +FRC:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/tf-breakin/mkembed.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,77 @@ +#include <sys/types.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#define PAYLOAD_SIZE 116 +u_char payload_buf[PAYLOAD_SIZE]; + +read_binary(filename) + char *filename; +{ + int fd; + struct stat st; + + fd = open(filename, O_RDONLY); + if (fd < 0) { + perror(filename); + exit(1); + } + fstat(fd, &st); + if (!S_ISREG(st.st_mode)) { + fprintf(stderr, "error: %s is not a regular file\n", filename); + exit(1); + } + if (st.st_size != PAYLOAD_SIZE) { + fprintf(stderr, "error: %s size mismatch\n", filename); + exit(1); + } + if (read(fd, payload_buf, PAYLOAD_SIZE) != PAYLOAD_SIZE) { + perror("read error"); + exit(1); + } + close(fd); +} + +write_output(filename) + char *filename; +{ + FILE *of; + int i, j, idx; + + of = fopen(filename, "w"); + if (!of) { + perror(filename); + exit(1); + } + fprintf(of, "u_char shellcode[%d] = {\n", PAYLOAD_SIZE); + idx = 0; + for (i = 0; i < 15; i++) { + for (j = 0; j < 8; j++) { + if (j) + putc(' ', of); + else + putc('\t', of); + fprintf(of, "0x%02X,", payload_buf[idx++]); + if (idx >= PAYLOAD_SIZE) + break; + } + putc('\n', of); + } + fputs("};\n", of); + fclose(of); +} + +main(argc, argv) + char **argv; +{ + if (argc != 3) { + fprintf(stderr, "usage: %s payload.bin output.c\n", argv[0]); + exit(1); + } + read_binary(argv[1]); + write_output(argv[2]); + exit(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/target-utils/tf-breakin/payload.S Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,43 @@ + .text + .org 0 + +@ allow entry in Thumb state + .code 16 + bx pc + nop + + .code 32 + +@ set CPSR like mot931c payload does + msr CPSR_c, #0xd3 +@ disable the watchdog + ldr r1, =0xfffff802 + mov r0, #0xf5 + strh r0, [r1, #2] + mov r0, #0xa0 + strh r0, [r1, #2] +@ MODEM UART + ldr r6, =0xffff5800 +@ wait for any previous output to flush out +1: ldrb r0, [r6, #5] + tst r0, #0x20 + beq 1b +@ send our indication + adr r1, outstr + mov r2, #6 +1: ldrb r0, [r1], #1 + strb r0, [r6] + subs r2, r2, #1 + bne 1b +@ wait for this output to go out to the TxD pin +1: ldrb r0, [r6, #5] + tst r0, #0x40 + beq 1b +@ enable the Calypso boot ROM + ldr r1, =0xFFFFFB10 + mov r2, #0x0100 + strh r2, [r1] +@ jump to it! + mov pc, #0 + .ltorg +outstr: .byte 2,2,2,'O','K',2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolchain/binutils-patches/elf32-arm.patch Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,62 @@ +# The present patch to the ARM ELF linking code in binutils (made against +# binutils-2.21.1a) is a hack that affects the generation of Thumb->ARM +# call veneers. The binutils linker can make these veneers in two forms: +# +# "Short" "Long" +# (16-bit) bx pc (16-bit) bx pc +# (16-bit) nop (16-bit) nop +# (32-bit) b dest (32-bit) ldr pc, [pc, #-4] +# (32-bit) .long target +# +# For code that's going to run on the Calypso ARM7 processor, the +# "short" form is the one we want: because of the way the address space +# is laid out, the range of an ARM branch instruction will always be +# sufficient for us, whereas the long version is more costly in terms +# of the number of cycles required, especially when executing from +# external memory. +# +# Unfortunately, the code which decides between these two forms +# (located in the arm_type_of_stub() function in bfd/elf32-arm.c) +# is broken. The original code (which you can see below in the +# "before" part of the patch hunk) exhibits two problems: +# +# 1. The distance that matters here is not from the original +# call point to the destination, but from the stub to +# the destination - and in this function we don't know +# where the stub will end up. +# +# 2. Because it's an ARM branch, the limits should be +# ARM_MAX_[BF]WD_BRANCH_OFFSET, not the THM_ ones. +# +# The 2nd problem would be trivial to fix, but the 1st one +# much less so: this function doesn't know where the stub +# will end up, and considering that for the present purpose +# of the FreeCalypso project always emitting the "short" +# version would be perfect, there is no justification for +# expending the time and effort to restructure the linker +# to do the proper relaxation for the case at hand. +# +# Therefore, the patch we apply is a hack: we simply force the +# use of the "short" form unconditionally. + +*** elf32-arm.c Wed May 11 07:29:12 2011 +--- elf32-arm-patched.c Mon Aug 19 03:24:38 2013 +*************** +*** 3203,3211 **** + : arm_stub_long_branch_v4t_thumb_arm); + + /* Handle v4t short branches. */ +! if ((stub_type == arm_stub_long_branch_v4t_thumb_arm) +! && (branch_offset <= THM_MAX_FWD_BRANCH_OFFSET) +! && (branch_offset >= THM_MAX_BWD_BRANCH_OFFSET)) + stub_type = arm_stub_short_branch_v4t_thumb_arm; + } + } +--- 3203,3209 ---- + : arm_stub_long_branch_v4t_thumb_arm); + + /* Handle v4t short branches. */ +! if (stub_type == arm_stub_long_branch_v4t_thumb_arm) + stub_type = arm_stub_short_branch_v4t_thumb_arm; + } + }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolchain/build+install.sh Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,90 @@ +#!/bin/sh +# +# This script builds and installs binutils, gcc and newlib in the order +# necessary for the whole thing to work. The present version is based +# on OsmocomBB's gnu-arm-build.2.sh script, which is in turn based on +# yet another source. The present version has been concocted by +# Spacefalcon the Outlaw for use in the FreeCalypso project. +# +# This script needs to be invoked with two arguments: +# +# $1: the path to the directory containing the upstream binutils, gcc +# and newlib source tarballs; +# +# $2: the path to the directory where the built toolchain should be +# installed. +# +# Note that there isn't a single install step at the end, instead this +# script will build and install one component, then proceed to build the +# next component which depends on the previous one, etc. For this reason +# you should create a dedicated install directory that is writable by your +# regular (non-root) uid, then run this script to populate that directory +# with the toolchain. + +if [ $# != 2 ] +then + echo "usage: $0 path-to-tarballs path-to-install" + exit 1 +fi + +set -ex + +target_args="--target=arm-elf" + +# binutils come first +tar xjf $1/binutils-2.21.1a.tar.bz2 +# apply patches +patch binutils-2.21.1/bfd/elf32-arm.c < binutils-patches/elf32-arm.patch +mkdir -p binutils-build +cd binutils-build +../binutils-2.21.1/configure --prefix=$2 ${target_args} --disable-nls +make all +make install +cd .. + +# unpack gcc and newlib sources at the same time: the gcc build +# will be pointed to newlib headers +gcc_version=4.5.4 +newlib_version=2.0.0 +tar xjf $1/gcc-core-${gcc_version}.tar.bz2 +tar xzf $1/newlib-${newlib_version}.tar.gz + +# patch gcc as needed +cp t-arm-elf gcc-${gcc_version}/gcc/config/arm + +# gcc depends on binutils - add our install destination dir to the PATH +# we prepend it to avoid surprises if some other arm-elf- toolchain +# happens to be present already +PATH=$2/bin:$PATH +export PATH + +mkdir -p gcc-build +cd gcc-build +../gcc-${gcc_version}/configure --prefix=$2 ${target_args} \ + --enable-interwork --enable-multilib \ + --with-cpu=arm7tdmi --with-float=soft \ + --enable-languages=c --with-newlib \ + --with-headers=`pwd`/newlib-${newlib_version}/newlib/libc/include \ + --with-system-zlib --disable-shared \ + --disable-nls +make all-gcc +make install-gcc +cd .. + +# now we can build newlib +mkdir newlib-build +cd newlib-build +../newlib-${newlib_version}/configure --prefix=$2 ${target_args} \ + --enable-interwork --enable-multilib \ + --enable-target-optspace --enable-newlib-reent-small \ + --disable-newlib-supplied-syscalls \ + --disable-nls +make all +make install +cd .. + +# and finally, libgcc +cd gcc-build +make all +make install +cd ..
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolchain/clean.sh Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,8 @@ +#!/bin/sh +set -ex +rm -rf binutils-2.21.1 +rm -rf binutils-build +rm -rf gcc-4.5.4 +rm -rf gcc-build +rm -rf newlib-2.0.0 +rm -rf newlib-build
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolchain/t-arm-elf Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,130 @@ +# This is a modified version of the gcc/config/arm/t-arm-elf file +# from gcc-4.5.4. It has been modified by Spacefalcon the Outlaw +# for the FreeCalypso project; the changes are in the multilib +# configuration: +# +# a) The fpu multilib has been commented out +# b) The -mthumb-interwork multilib has been uncommented + +# Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, +# 2008 Free Software Foundation, Inc. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GCC is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# For most CPUs we have an assembly soft-float implementations. +# However this is not true for ARMv6M. Here we want to use the soft-fp C +# implementation. The soft-fp code is only build for ARMv6M. This pulls +# in the asm implementation for other CPUs. +LIB1ASMFUNCS += _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _bb_init_func \ + _call_via_rX _interwork_call_via_rX \ + _lshrdi3 _ashrdi3 _ashldi3 \ + _arm_negdf2 _arm_addsubdf3 _arm_muldivdf3 _arm_cmpdf2 _arm_unorddf2 \ + _arm_fixdfsi _arm_fixunsdfsi \ + _arm_truncdfsf2 _arm_negsf2 _arm_addsubsf3 _arm_muldivsf3 \ + _arm_cmpsf2 _arm_unordsf2 _arm_fixsfsi _arm_fixunssfsi \ + _arm_floatdidf _arm_floatdisf _arm_floatundidf _arm_floatundisf \ + _clzsi2 _clzdi2 + +MULTILIB_OPTIONS = marm/mthumb +MULTILIB_DIRNAMES = arm thumb +MULTILIB_EXCEPTIONS = +MULTILIB_MATCHES = + +#MULTILIB_OPTIONS += march=armv7 +#MULTILIB_DIRNAMES += thumb2 +#MULTILIB_EXCEPTIONS += march=armv7* marm/*march=armv7* +#MULTILIB_MATCHES += march?armv7=march?armv7-a +#MULTILIB_MATCHES += march?armv7=march?armv7-r +#MULTILIB_MATCHES += march?armv7=march?armv7-m +#MULTILIB_MATCHES += march?armv7=mcpu?cortex-a8 +#MULTILIB_MATCHES += march?armv7=mcpu?cortex-r4 +#MULTILIB_MATCHES += march?armv7=mcpu?cortex-m3 + +# Not quite true. We can support hard-vfp calling in Thumb2, but how do we +# express that here? Also, we really need architecture v5e or later +# (mcrr etc). +# MULTILIB_OPTIONS += mfloat-abi=hard +# MULTILIB_DIRNAMES += fpu +# MULTILIB_EXCEPTIONS += *mthumb/*mfloat-abi=hard* + +# MULTILIB_OPTIONS += mcpu=ep9312 +# MULTILIB_DIRNAMES += ep9312 +# MULTILIB_EXCEPTIONS += *mthumb/*mcpu=ep9312* +# +# MULTILIB_OPTIONS += mlittle-endian/mbig-endian +# MULTILIB_DIRNAMES += le be +# MULTILIB_MATCHES += mbig-endian=mbe mlittle-endian=mle +# +# MULTILIB_OPTIONS += mhard-float/msoft-float +# MULTILIB_DIRNAMES += fpu soft +# MULTILIB_EXCEPTIONS += *mthumb/*mhard-float* +# +MULTILIB_OPTIONS += mno-thumb-interwork/mthumb-interwork +MULTILIB_DIRNAMES += normal interwork +# +# MULTILIB_OPTIONS += fno-leading-underscore/fleading-underscore +# MULTILIB_DIRNAMES += elf under +# +# MULTILIB_OPTIONS += mcpu=arm7 +# MULTILIB_DIRNAMES += nofmult +# MULTILIB_EXCEPTIONS += *mthumb*/*mcpu=arm7* +# # Note: the multilib_exceptions matches both -mthumb and +# # -mthumb-interwork +# # +# # We have to match all the arm cpu variants which do not have the +# # multiply instruction and treat them as if the user had specified +# # -mcpu=arm7. Note that in the following the ? is interpreted as +# # an = for the purposes of matching command line options. +# # FIXME: There ought to be a better way to do this. +# MULTILIB_MATCHES += mcpu?arm7=mcpu?arm7d +# MULTILIB_MATCHES += mcpu?arm7=mcpu?arm7di +# MULTILIB_MATCHES += mcpu?arm7=mcpu?arm70 +# MULTILIB_MATCHES += mcpu?arm7=mcpu?arm700 +# MULTILIB_MATCHES += mcpu?arm7=mcpu?arm700i +# MULTILIB_MATCHES += mcpu?arm7=mcpu?arm710 +# MULTILIB_MATCHES += mcpu?arm7=mcpu?arm710c +# MULTILIB_MATCHES += mcpu?arm7=mcpu?arm7100 +# MULTILIB_MATCHES += mcpu?arm7=mcpu?arm7500 +# MULTILIB_MATCHES += mcpu?arm7=mcpu?arm7500fe +# MULTILIB_MATCHES += mcpu?arm7=mcpu?arm6 +# MULTILIB_MATCHES += mcpu?arm7=mcpu?arm60 +# MULTILIB_MATCHES += mcpu?arm7=mcpu?arm600 +# MULTILIB_MATCHES += mcpu?arm7=mcpu?arm610 +# MULTILIB_MATCHES += mcpu?arm7=mcpu?arm620 + +EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crti.o crtn.o + +# If EXTRA_MULTILIB_PARTS is not defined above then define EXTRA_PARTS here +# EXTRA_PARTS = crtbegin.o crtend.o crti.o crtn.o + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib + +# Currently there is a bug somewhere in GCC's alias analysis +# or scheduling code that is breaking _fpmul_parts in fp-bit.c. +# Disabling function inlining is a workaround for this problem. +TARGET_LIBGCC2_CFLAGS = -fno-inline + +# Assemble startup files. +$(T)crti.o: $(srcdir)/config/arm/crti.asm $(GCC_PASSES) + $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \ + -c -o $(T)crti.o -x assembler-with-cpp $(srcdir)/config/arm/crti.asm + +$(T)crtn.o: $(srcdir)/config/arm/crtn.asm $(GCC_PASSES) + $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \ + -c -o $(T)crtn.o -x assembler-with-cpp $(srcdir)/config/arm/crtn.asm +