FreeCalypso > hg > freecalypso-docs
diff TCS211-fw-arch @ 0:fcd1cf531017
TCS211-fw-arch masterpiece written
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Mon, 08 Oct 2018 19:52:50 +0000 |
parents | |
children | 5de1f72ce941 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TCS211-fw-arch Mon Oct 08 19:52:50 2018 +0000 @@ -0,0 +1,1867 @@ +This document describes the architecture of TI's TCS211 firmware and that of +our FreeCalypso Magnetite and Selenite firmwares which are based on it. + +What is TCS211, and why we use it as our reference +================================================== + +TI were in the business of making GSM baseband chipsets for about a decade +from the late 1990s up until 2009, and over that time span both their silicon +and their firmware architecture had evolved in many different ways. All of our +work in the FreeCalypso family of projects is based on one fairly arbitrary +snapshot, a rather arbitrarily picked single point in that long evolutionary +line: we use the Calypso chipset as opposed to both the ones before and the +ones after, and we use TI's TCS211 firmware from 2007 as our golden reference, +as opposed to other equally valid ways of architecturing the fw that came +before and after our arbitrarily picked snapshot. + +Q: Why do we use the Calypso chipset as opposed to LoCosto or E-Costo or +whatever was TI's very last offering before they got out of that business? + +A: Because that's what Openmoko used: their Neo FreeRunner aka GTA02 smartphones +were our primary hardware target for many years before we gathered the money +and the courage to build our own board-level hardware starting from just chips +bought on the Chinese surplus market. + +Q: Why do we use TI's TCS211 firmware from 2007 and its architecture as our +golden reference, as opposed to any of the other infinitely many equally valid +ways of architecturing a working firmware implementation for the same Calypso +chipset? + +A: Because it works flawlessly, and is extremely stable as a commercial product. +The firmware which Openmoko got from TI had only a tiny difference from TI's +internal TCS211 mainline (TSPACT signal definitions in tpudrv12.h which are +different between the quadband RFFE on TI's internal reference hw and the +triband one in FIC's commercial implementation), and with only a few additional +changes related to our use of a newer flash chip that wasn't supported back in +TI's and Openmoko's days, this golden reference fw can run equally well on our +own FCDEV3B. + +Relation between TCS211 and FreeCalypso +======================================= + +The only "pure" TCS211 firmware we got is the one that has been salvaged from +the ruins of Openmoko. To the best of our knowledge, it is the world's only +surviving copy of any version of TCS211 - it is entirely possible that even TI +may not have it any more in any of their archives, given the length of time that +has passed and the total lack of interest in this "ancient junk". In its pure +form, this world's sole surviving copy of TI's TCS211 fw is laden with blobs +(many components exist only as binary object libraries with no corresponding +source), and it features a build system that is very thoroughly Windows-based. +And to top it off, that configuration and build system has many critical +components which also exist only as compiled binaries (Windows executables or +Java bytecode) with no corresponding source. + +We started by replacing the original configuration and build system of TCS211 +with our own one that is Unix-based rather than Windows-based, and implemented +in Bourne shell with a few C helpers instead of XML, Java and Perl. The result +was named FreeCalypso Magnetite. At first we changed only the configuration +and build system, but kept all of the original TCS211 code, including all of +the binary-only components. Then we deblobbed it gradually, replacing binary- +only components with source, one component at a time. Where did we get the +source for the pieces that came as binary objects with no corresponding source? +The answer is different for different components: + +* For GSM Layer 1 (a very critical and highly chipset-dependent component), we + did a painstaking reconstruction which you can see in the tcs211-l1-reconst + repository. That world's last surviving copy of TCS211 which we got only had + *.c files censored out, while all of the original *.h files were preserved - + and thanks to the preserved configuration and build system, we also got all + of the original compilation lines including compiler options, -D definitions + and -I include paths. For most of the missing *.c files we got a "wrong" + version from the TCS3/LoCosto source. The reconstruction proceeded by taking + these "wrong version" *.c files, putting them one module (one *.c file) at a + time into the TCS211 build environment, and massaging each individual *.c + file until it compiled into a perfect match to the original binary object. + Thus we have reconstructed a full C source for the L1 component which for all + practical purposes can be treated as if it were the lost original source. + +* For some small pieces like the tpudrv12 RF driver and the OSL and OSX + components of GPF it was more of a translation from disassembly to C: the C + code we use is of our own writing, but it faithfully matches the logic + implemented by the original blobs as recovered through disassembly. + +* The G23M protocol stack is a very large and complex component, and our copy + of TCS211 (the world's only surviving copy to the best of our knowledge) has + it in binary-only form. Trying to source-reconstruct it precisely like we + did with L1 would have been infeasible, hence we took a different approach: + we put together a TCS2/TCS3 hybrid in which we made a wholesale replacement + of all G23M components: we adopted the new version of G23M wholesale without + trying to recreate the old version. + +* Both TCS211 and TI's newer TCS3.2 fw for the LoCosto chipset are based on + Nucleus PLUS RTOS (different versions), and both firmwares have their Nucleus + only as binary object libraries, no source. However, we got another version + of Nucleus from about the same time frame (slightly newer than the one TI used + in TCS211, but slightly older than the one in TCS3.2) from a non-TI source + (it was posted on a Russian web forum by Comrade XVilka), and in FreeCalypso + Selenite we use this new Nucleus as a replacement for TCS211 original version + in the same manner as how we had earlier made a wholesale replacement of the + G23M protocol stack. + +With two major components (Nucleus and the G23M PS) replaced with non-TCS211 +versions, our Magnetite hybrid and Selenite firmwares are no longer TCS211, but +they still faithfully follow the _architecture_ of TCS211: in each case when we +replaced the code, we made the new code version fit perfectly into the original +architecture without any disruptive changes. Thus anyone who desires to +understand our current FreeCalypso firmwares (Magnetite and Selenite) needs to +first understand the original TCS211 architecture, as it is essentially +unchanged. + +Why not use the LoCosto chipset and its TCS3.2 firmware? +======================================================== + +We went the Calypso route and not the LoCosto route because of the circumstances +that surrounded the beginning of our family of projects. We did not get all of +the tools needed for working with LoCosto chips and TI's TCS3.2 fw (CSST and +SBuild) until the spring of 2015, and by that time we had invested too much into +the Calypso to throw it all away and restart anew in the uncharted waters of +LoCosto. Another factor is that the software for talking to LoCosto's ROM +bootloader (CSST) exists only as Windows binaries sans source, and it would +require some effort to reverse-engineer the protocol and implement a free and +Unix-based alternative - whereas for the Calypso this work was already done by +OsmocomBB folks before we entered the scene. Finally, in the case of the +Calypso we have read out the actual content of the ROMs (both the ARM boot ROM +and the DSP ROM) and the ARM boot ROM code has been disassembled and thoroughly +understood - whereas in the case of LoCosto it is not certain if we can even +read out the ROM content, as it is said to be protected against reading. + +If someone else desires to play with LoCosto, either by hacking a Peek device +or by building an I-Sample board from the available PADS PCB file, go for it! +But the FreeCalypso core team is sticking with the Calypso chipset for now, and +our actively maintained Magnetite and Selenite firmwares follow the architecture +of TCS211, not that of TCS3.2. + +Relation between the ARM and DSP cores in the Calypso +===================================================== + +The Calypso digital baseband processor chip has two processor cores in it: an +ARM7TDMI core that runs the main firmware and a C54x DSP core that performs the +more burdensome signal processing tasks. The DSP is subservient to the ARM: +only the ARM comes out of reset and starts executing code upon power-up, while +the DSP is held in reset (does not run) until and unless the ARM firmware starts +it running. + +The ARM core executes code from outside of the Calypso chip itself: in normal +operation (outside of development) there is a flash memory chip connected to +Calypso's external memory bus, and the Calypso's ARM core executes firmware +stored in this flash. There is an optional (enabled or disabled by a hardware +pin) ARM boot ROM inside the Calypso chip; when this boot ROM is enabled by +nIBOOT pin strapping on the board (like it is on Openmoko and FreeCalypso +hardware), the ARM core executes code from this boot ROM first upon power-up or +reset before jumping to external flash. The tiny piece of code that is hard- +cast in this mask ROM acts as an unbricking aid: it gives a certain time window +during which the boot process can be interrupted and diverted if certain magic +characters are sent into either of Calypso's two UARTs by an external +development host, and if nothing is received on either UART during that time +window (as would be the case in normal usage of a Calypso phone or modem), the +boot ROM transfers control to the firmware image in the external flash. The +end result is that the ARM core always runs code from outside of the Calypso +chip itself, either the firmware image in the flash or whatever code is fed by +an external development host to the boot ROM serially over a UART. + +There is also an internal RAM inside the Calypso from which the ARM can execute +code (512 KiB on the full Calypso version or 256 KiB on Calypso Lite silicon +used in some historical low-end phones); the primary purpose of this internal +RAM is to allow chosen sections of code to execute faster without the +performance penalty of the external memory bus, but it is volatile RAM, not ROM +or flash, hence it doesn't have any code in it until and unless loaded by the +firmware copying code from flash or via the serial boot protocol. + +In contrast, the DSP is very different. The DSP core can never execute any +code from outside the chip, and has no access to the Calypso chip's external +memory bus at all. Instead the only two memories accessible to the DSP are a +mask ROM and a fast internal RAM. The DSP's dedicated mask ROM is 128 Kwords; +the DSP's RAM is 28 Kwords, out of which 8 Kwords constitute the so-called API +RAM which is accessible to both ARM and DSP cores. (The C54x DSP addresses +memory by words instead of bytes, hence the memory sizes are given in Kwords +instead of KiB.) + +The main bulk of the DSP's operating program is already hard-cast in the silicon +in the 128 Kword mask ROM. The DSP ROM code is structured in such a way that +any part of it can be overridden by downloadable patch codes which get loaded +somewhere in the DSP's 28 Kword RAM, but because the RAM is significantly +smaller than the ROM, downloadable DSP code cannot replace the entirety of the +ROM code - instead the code needs to be patched very selectively only where +necessary to fix a bug that was discovered after the silicon was made or to +extend the DSP functionality with a new feature. + +The DSP ROM code in the Calypso silicon we are using has been successfully read +out, but it is only the executable binary code and data - we never found a copy +of the source for this DSP ROM code. And even if we had this source, we would +not be able to casually modify and recompile it without spending millions of +dollars to fab a new chip revision with a modified mask ROM. Having this source +would allow us to develop our own DSP patch codes and to understand and maintain +the existing ones, hence we need to make an effort to convince TI to release +the source for the DSP ROM if they have it in their archives, but if no +surviving copy of this source exists anywhere in the world, the fallback plan +would be to reverse-engineer the DSP ROM code by disassembly. The latter plan +has not been pursued yet because of the very high labor cost it would involve. + +It is possible to run the Calypso DSP without any patches, i.e., have it run +only the code that is already in the mask ROM. Our competitor OsmocomBB +operates in this manner, and we have also built and run modified versions of +our TCS211-based FreeCalypso firmware with DSP patch loading disabled as an +experiment. However, all ARM-side firmwares that have been officially released +by TI for production use including our TCS211-20070608 golden reference do apply +downloadable patches to the DSP, and are designed to run with this patched DSP; +running them with DSP patching disabled results in unstable operation. + +DSP patch codes that are included in ARM-side Calypso firmwares take the form +of const char arrays initialized with hex bytes; these C source files with hex +char arrays inside were apparently produced from C54x COFF files with a tool +called coff2c, but we never got any of those COFF files or whatever source (C +or assembly) they were built from. At the present time in the FreeCalypso +family of projects we use the DSP patch codes (hex char arrays) which we got +with our copy of TCS211 from 20070608, and we treat the entire DSP block (the +combination of mask ROM plus patches) as a functional black box. + +Having to treat the DSP as a black box is certainly a major shortcoming of our +FreeCalypso solution. However, I (Mother Mychaela) would much rather have a +phone or modem in which only the DSP is a black box while I get to maintain all +of the upper layers with full freedom, as opposed to the status quo alternative +of a very high-level black box with FOTA backdoors. Unlike the ubiquitous +high-level black boxes from the likes of Qualcomm, the DSP in the Calypso cannot +be backdoored: it has no access to the ARM address space, thus no access to the +flash (cannot surreptitiously modify the firmware) and no access to any of the +higher-level radio protocol state maintained by the ARM, all it can do is +modulate and demodulate bursts and run voice codecs _as commanded by the ARM_. +Furthermore, the DSP has no access to the Calypso chip's TPU (Time Processing +Unit, the block that controls board-level RF hardware) and thus has no direct +control over any of the RF hardware: it cannot initiate radio transmission or +even reception on its own, instead the ARM firmware has to configure the RF +hardware via the TPU for each and every Rx or Tx time window. + +Finally, if anyone is truly paranoid about the possibility of backdoors in the +DSP, the DSP ROM code has been read out - you are welcome to hire a professional +reverser of your choice to disassemble and audit it as thoroughly as you like. +This code is unchangeable by virtue of being hard-cast in a mask ROM in the +silicon. + +The rest of this document covers the firmware that runs on the ARM core; it +controls the DSP via its API RAM, a form of shared memory interface. + +High-level structure of TCS211 firmware +======================================= + +The code base that makes up TI's TCS211 firmware consists of 3 main divisions: +chipset software, Condat G23M (GSM and GPRS L23 protocol stacks, ACI and +optional handset UI layers) and GPF. Let us look at them in turn: + +chipsetsw division +------------------ + +In the original TCS211 delivery there was a top-level directory named chipsetsw +(chipset software), containing code that is specific to TI's chipsets in +particular and was never intended to run on any other hardware. This code +division has been retained intact in our FreeCalypso Magnetite and Selenite +firmwares, taken in its entirety from our TCS211 golden reference, although we +have shortened the name: this code division now resides under src/cs in +Magnetite and Selenite. Aside from a few bits of system glue, this chipsetsw +breaks down into two further subdivisions: the L1+drivers core and the SSA +division. + +L1+drivers core +--------------- + +This division resides under chipsetsw/layer1 and chipsetsw/drivers/drv_core, or +under src/cs/layer1 and src/cs/drivers/drv_core in our version. The most +important piece here is L1 (GSM Layer 1): this code drives the DSP and the RF +hardware, and thereby makes the Calypso function as a GSM MS (mobile station) +and not merely as a general purpose microprocessor platform. This code can be +considered to be the most important part of the entire firmware. + +At one time TI had a so-called standalone L1 configuration, selected by the +OP_L1_STANDALONE C preprocessor symbol. We don't have the bits that are needed +to build this configuration (they were probably never released outside of TI at +all), but it appears that this fw build configuration consisted of just Nucleus, +L1, the drivers under drv_core, the OSL and OSX parts of GPF without the rest, +and some stubs for the few higher-level functions that are intertied with L1. + +The drivers under chipsetsw/drivers are divided into drv_core and drv_app: the +former are the most essential or fundamental ones, used by L1 and/or needed for +the OP_L1_STANDALONE config; the latter belong to the higher-level SSA division +described below. + +SSA division +------------ + +TI had a group called System Software and Applications (SSA), and they supplied +those parts of the firmware that are neither L1+drv_core nor Condat G23M. The +more interesting pieces here include the flash file system (FFS), the debug +trace facility (RVT), the Enhanced Test Mode (ETM) facility that allows +external development and production tools to poke at the firmware, RiViera Audio +Service (playing various beeps and ringtones through the DSP, a front-end to L1 +audio functions), LCD and keypad drivers for Calypso-based handsets, and various +supportive functions implemented via the Iota ABB: switch-on and switch-off +logic, battery monitoring and charging, backlight LED control. + +All firmware components in the SSA division are built on top of a framework +called RiViera - more will be said about it later. Everything under +chipsetsw/drivers/drv_app, chipsetsw/riviera and chipsetsw/services (or under +src/cs/drivers/drv_app, src/cs/riviera and src/cs/services in our version) +belongs to the SSA realm. + +Condat G23M division +-------------------- + +At the beginning of TI's involvement in the GSM baseband chipset business, they +only developed and maintained their own L1 code, which eventually grew into the +larger chipsetsw division described above, while the rest of the protocol stack +(which is hardware-independent) was licensed from another company called Condat. +Later Condat as a company was fully acquired by TI, and the once-customer of +this code became its owner. The name of TI/Condat's implementation of GSM +layers 2&3 for the MS side is G23M, and it forms its own major division of the +overall fw architecture. + +The overall Condat code realm can be further subdivided into GSM and GPRS L23 +protocol stacks, the Application Control Interface (ACI) which includes the AT +command interpreter (ATI), and additional phone UI layers which are only +included in handset but not modem firmwares. + +We don't know exactly how TI maintained this software internally: given that it +is mostly hardware-independent aside from integration details and some minor +features which may be present on one hw platform but not on another, it would +have made the most sense for TI to maintain a single internal mainline common +to both Calypso and LoCosto, and then integrate the code from this mainline into +chipset-specific customer releases. We have no way of knowing if TI indeed +followed this approach or not, but when we took the version of G23M from the +TCS3.2 source for the LoCosto chipset and grafted it onto the chipsetsw +foundation from TCS211 for the Calypso to produce our TCS2/TCS3 hybrid, the +integration went surprisingly smoothly. The full-source version of G23M which +we took from TCS3/LoCosto is newer than the binary-only version featured in the +world's last surviving copy of TCS211 from Openmoko. + +GPF island of stability +----------------------- + +Underlying the G23M protocol stack is a special layer called GPF, which was +originally Condat's Generic Protocol stack Framework. Apparently Condat were +in the business of developing and maintaining a whole bunch of protocol stacks: +GSM MS side, GSM network side, TETRA and who knows what else. GPF was their +common underpinning for all of their protocol stack projects, which ran on top +of many different OS environments: Nucleus, pSOS, VxWorks, Unix/Linux, Win32 +and who knows what else. + +In the case of TI/FreeCalypso GSM fw, both the protocol stack and the underlying +OS environment are fixed: GSM and Nucleus, respectively. But GPF is still a +critically important layer in the firmware architecture: in addition to serving +as the glue between the G23M stack and Nucleus, it provides some important +support infrastructure for the protocol stack. + +However, what makes GPF very special is the way in which it relates to the rest +of the firmware architecture. GPF remained common and unchanged across TI's +many different projects, and it is so independent from the rest of the firmware +and its build configuration that TI were able to make company-wide GPF library +builds and then plop them into multiple fw projects which used them as +configuration-independent prebuilt libraries. All TI firmware (semi-)sources +we've got use GPF in prebuilt library form and are not set up to recompile any +part of it from source. + +Our FC Magnetite firmware uses the original binary libs from TCS211-Openmoko +for its GPF component, but for FC Selenite the project requirement is to be +completely blob-free, hence we had to reconstruct the source for GPF. The +original source for most parts of GPF was found between TCS3.2 from Peek/FGW +and TCS211 from OM (the former had the source for the core "frame" modules and +the latter had the source for misc and tst), but we never got the source for the +OSL and OSX components, hence we had to reconstruct them from disassembly. OSL +is the glue layer between GPF and Nucleus, OSX is the glue layer between GPF +and L1. + +Firmware boot process +===================== + +As already mentioned earlier, the Calypso chip itself includes an ARM boot ROM +in the silicon that serves as an unbricking aid: it provides a certain time +window during which the boot process can be interrupted and diverted if certain +magic characters are sent into either of Calypso's two UARTs by an external +host, and if nothing is received on either UART during that time window, the +boot ROM transfers control to the firmware image in the external flash. As we +understand it, Calypso was TI's first DBB (digital baseband processor) chip to +include this boot ROM, and their previous DBB chips did not have such: they +would always execute code directly from external flash immediately out of reset. + +TI's TCS211 and earlier firmwares are structured in such a way that they boot +and run exactly the same way whether the Calypso boot ROM is present and +enabled, present but disabled, or not present at all. They put magic constant +0x00000001 in the 32-bit word at flash address 0x2000, which tells the Calypso +boot ROM (if it is present and enabled) to boot the flash fw image in legacy +mode: after providing the unbricking time window, the boot ROM moves itself out +of the way (sets two bits in the FFFF:FB10 register which tell the chip to unmap +the boot ROM and to map external memory at address 0) and induces a watchdog +reset, causing the chip to re-execute the reset vector, this time directly out +of external flash - thus the firmware boots as if the boot ROM weren't there, +but the ROM's unbricking function is retained. + +In order to make it easier to load new firmware images during development on +pre-Calypso platforms which didn't have a boot ROM, TI had developed a flash- +resident bootloader stage and included it in their fw architecture. This +bootloader stage is placed at the beginning of the flash at the reset vector, +and the rest of the firmware begins at an erase unit boundary. The bootloader +stage executes first, and before it jumps to the main firmware entry point +(_INT_Initialize) for normal boot, it offers an opportunity for the boot process +to be interrupted and diverted if an external host sends certain magic command +packets into either of the two UARTs during the allotted time window. If the +external host does interrupt and divert the boot process in this manner, it can +feed a code image to the bootloader to be written somewhere in target RAM, and +then command the bootloader to jump to it. It is exactly the same functionality +(though with different serial protocol specifics) as implemented in the Calypso +boot ROM. The ROM version is obviously superior because it is unbrickable, but +the flash-resident, built-with-firmware version is what TI used before they +came up with the idea of the boot ROM for the Calypso. + +When the boot-ROM-equipped Calypso came along, TI kept the flash-resident +bootloader in the firmware: it does no harm aside from adding a little bit of +delay to the boot process, it does not conflict with the ROM bootloader as the +two speak different serial protocols and respond to different interrupt-boot +sequences, and it allowed TI to keep the same firmware architecture for +platforms with and without a boot ROM. However, in our FreeCalypso firmwares +starting with Magnetite we have removed this extra bootloader stage for the +following reasons: + +* It is not useful to us on any of our hardware targets: on those devices that + have the Calypso boot ROM enabled, we use that boot ROM and get full + unbrickability, whereas on Mot C1xx phones we have to work with Mot/Compal's + own different bootloader and serial protocol at least initially, hence it + makes the most sense to stick with the same after the conversion to + FreeCalypso as well. + +* As delivered by TI with their full production TCS211 fw releases, their + firmware-resident bootloader works as intended only on hw platforms with + 13 MHz VCXOs like the original D-Sample (Clara RF), and is broken on platforms + like Rita RF (the only RF chip for which we have driver code!) with 26 MHz + VCXOs: there is no conditionally-compiled code anywhere in the bootloader + code path to set the VCLKOUT_DIV2 bit in the CNTL_CLK register on 26 MHz + platforms, thus the UARTs are fed with 26 MHz instead of the standard 13 MHz + clock expected in normal operation, and the intended baud rate of 115200 bps + turns into 230400. Because 230400 bps is a baud rate which Calypso UARTs + *cannot* produce in normal GSM operation (when the peripheral clock network + runs at the expected 13 MHz), tools that are designed to talk to Calypso GSM + devices are typically not designed to support this baud rate. In particular + for CP2102 USB-serial adapters, the precedent established by the factory + CP2102 EEPROM programming in the Pirelli DP-L10 phone is that the baud rate + entry for 230400 bps is replaced with 203125 bps, which is a valid baud rate + for Calypso UARTs running at 13 MHz. + +* We have no source for TI's firmware-resident bootloader, only linkable binary + objects that came with our world's last surviving copy of TCS211, which are + incompatible with our goal of blob-free firmware. + +Because this extra bootloader stage is ultimately unnecessary in our +environment, the deblobbing goal was easier accomplished by removing it +altogether instead of expending effort on a blob-free replacement. Because I +wasn't comfortable with modifying TMS470 assembly code and linker script magic, +the removal of the bootloader was accomplished by stubbing out its C body with +an empty function. In the gcc-built FC Selenite version it is removed +completely, without any leftover stubs. + +Finally, it needs to be noted for the sake of completeness that Compal's +bootloader used on Mot C1xx phones is a modified version based on TI's original +bootloader. However, this factoid matters only for historians and genealogists; +for all practical purposes it is an unrelated animal, as Mot/Compal's serial +protocol for interrupting and diverting the boot process is their own and bears +no resemblance to TI's version. And yes, Mot/Compal's version does set the +VCLKOUT_DIV2 bit in the CNTL_CLK register to adjust for the 26 MHz clock input +as its first order of business; it was probably the very first issue they had +to fix. + +When we build FC Magnetite or FC Selenite TMS470 firmware for Mot C1xx targets, +we use dd to strip off the first 64 KiB of the image produced by TI's linker +(the part where TI's bootloader resides, be it intact or stubbed out) and flash +the remaining image (the main body of the fw) starting at flash address 0x10000. +In the gcc-built Selenite version we natively link images that are designed to +be flashed at 0x10000 without any dirty hacks. Common to all FC firmwares for +C1xx targets, the bootloader image we put at 0 (in the brickable flash sector) +is a modified version based on one of Mot/Compal's originals: we have binary- +patched it to redirect the exception vectors from Mot/Compal's 0x20A0 to 0x10000 +and to move the main fw entry point from Mot/Compal's 0x20F8 to TI's 0x10058. + +None of this muckery applies to our own FreeCalypso hardware or to our +predecessor Openmoko's hw: on these good hw targets the complete fw image as +built is flashed at 0, and there is no possibility of bricking because we use +the boot ROM to gain access irrespective of what's in the flash. + +Main firmware entry point +------------------------- + +With the bootloader distraction out of the way, the main fw entry point is at +the _INT_Initialize symbol in the int.s assembly module, located in +src/cs/system/main/int.s in Magnetite and Selenite. The functional equivalent +for the gcc environment in Selenite is in src/cs/system/main/gcc/bootentry.S. +This assembly code performs some basic hardware initialization, sets up +sensible memory timings for the boot path phase before DPLL setup, copies the +IRAM code (the code that is intended to execute out of the fast internal RAM) +from flash to where it needs to be, zeros both IRAM and XRAM .bss regions, does +TI's cinit/auto_init business for initialized data in the TMS470 environment +(Selenite gcc version copies .data from flash to RAM instead), sets up the +system, IRQ, FIQ and exception stacks, does some assembly initialization for +Nucleus and finally jumps to Nucleus' C entry point INC_Initialize(). + +Further initialization takes place in the Init_Target() and Init_Drivers() +functions called from Application_Initialize(), which is the last function +called by INC_Initialize() before starting the Nucleus task scheduler. + +Nucleus environment +=================== + +Like all classic TI firmwares, ours is based on the Nucleus PLUS RTOS. Just +like TI's original code on which we are based, we use only a small subset of +the functionality provided by Nucleus - but because the latter is a library, +the pieces we don't use simply don't get pulled into the link. The main +function we get out of Nucleus is the scheduling of threads, or tasks as +Nucleus calls them. + +Aside from pre-stack-setup assembly init code and ARM exception handlers, every +piece of code in the firmware executes in one of the following contexts: + +* Application_Initialize(): this function and everything called from it execute + just before Nucleus' thread scheduler starts; at this point interrupts are + disabled at the ARM7 core level (in the CPSR) and must not be enabled; the + stack is Nucleus' "system stack" which is also used by the scheduler and LISRs + as explained below. + +* Regular threads or tasks: once Application_Initialize() finishes, all code + with the exception of interrupt handlers (LISRs and HISRs as explained below) + runs in the context of some Nucleus task. Whenever you are trying to debug + or simply understand some piece of code in the firmware, the first question + you should ask is "which task does this code execute in?". Most functional + components run in their own tasks, i.e., a given piece of code is only + intended to run within the Nucleus task that belongs to the component in + question. On the other hand, some components are implemented as APIs, + functions to be called from other components: these don't have their own task + associated with them, and instead they run in the context of whatever task + they were called from. Some only get called from one task: for example, the + "uartfax" driver API calls only get called from the protocol stack's UART + entity, which is its own task. Other component API functions like FFS and + trace can get called from just about any task in the system. Many components + have both their own task and some API functions to be called from other tasks, + and the API functions oftentimes post messages to the task to be worked on by + the latter; the just-mentioned FFS and trace functions work in this manner. + + In our TCS211-mimicking Magnetite and Selenite firmwares every Nucleus task is + created either through RiViera or through GPF, and not in any other way - see + the description of RiViera and GPF below. + +* LISRs (Low level Interrupt Service Routines): these are the interrupt handlers + that run immediately when an ARM IRQ or FIQ comes in. The code at the IRQ and + FIQ vector entry points calls Nucleus' magic stack switching function + (switches the CPU from IRQ/FIQ into SVC mode, saves the interrupted thread's + registers on that thread's stack, and switches to the "system" stack) and + then calls TI's IRQ dispatcher implemented in C. The latter figures out + which Calypso interrupt needs to be handled and calls the handler configured + in the compiled-in table. Nucleus' LISR registration framework is not used + by the GSM fw, but these interrupt handlers should be viewed as LISRs + nonetheless. + + There is one additional difference between canonical Nucleus and TI's version + (we've replicated the latter): canonical Nucleus was designed to support + nested LISRs, i.e., IRQs re-enabled in the magic stack switching function, + but in TI's version which we follow this IRQ re-enabling is removed: each LISR + runs with interrupts disabled and cannot be interrupted. (The corner case of + an FIQ interruping an IRQ remains to be looked at more closely as bugs may be + hiding there, but Calypso doesn't really use FIQ interrupts.) There is really + no need for LISR nesting in our GSM fw, as each LISR is very short: most LISRs + do nothing more than trigger the corresponding HISR. + +* HISRs (High level Interrupt Service Routines): these hold an intermediate + place between LISRs and tasks, similar to softirqs in the Linux kernel. A + HISR can be activated by a LISR calling NU_Activate_HISR(), and when the LISR + returns, the HISR will run before the interrupted task (or some higher + priority task, see below) can resume. HISRs run with CPU interrupts enabled, + thus more interrupts can occur, with their LISRs executing and possibly + triggering other HISRs. All triggered HISRs must complete and thereby go + "quiescent" before task scheduling resumes, i.e., all HISRs as a group have a + higher scheduling priority than tasks. + +Nucleus implements priority scheduling for tasks. Tasks have their priority set +when they are created (through RiViera or GPF, see below), and a higher priority +task will run until it gets blocked waiting for something, at which time lower +priority tasks will run. If a lower priority task sends a message to a higher +priority task, unblocking the latter which was waiting for incoming messages, +the lower priority task will effectively suspend itself immediately while the +higher priority task runs to process the message it was sent. + +HISRs oftentimes post messages to their associated tasks as well; if one of +these messages unblocks a higher priority task, that unblocked task will run +upon the completion of the HISR instead of the original lower priority task +that was interrupted by the LISR that triggered the HISR. Nucleus' scheduler +is fun! + +RiViera and GPF +=============== + +RiViera and GPF are two parallel/independent/competing wrappers around or +layers above Nucleus. GPF comes from Condat and is used by the G23M protocol +stack and indirectly by L1 (the peculiar way in which L1 ties in with the rest +of the firmware will be covered later), whereas RiViera is used by the fw +components from TI's SSA group: flash file system, debug trace, RiViera Audio +Service and so forth. + +At some point in their post-Calypso TCS3.x program TI decided to eliminate +RiViera as an independent framework and to reimplement RiViera APIs (used by +peripheral but necessary code such as FFS, ETM, various drivers etc) over GPF. +This arrangement is used in the TCS3.2 LoCosto firmware from which we have +lifted our source replacements for much of the code that came as binary objects +in our reference TCS211 version. However, our current Magnetite and Selenite +firmwares follow the architecture of TCS211, not that of TCS3.2, and because +the entire SSA division of the fw including the RiViera core came in full source +form in our copy of TCS211, it was only natural to keep this code and its +architecture. + +Start-up process continued +========================== + +As mentioned earlier, Nucleus calls the application's software init function +called Application_Initialize() after it initializes itself but before starting +the task scheduler. This function in TCS211 is just the following: + +Application_Initialize() +{ + Init_Target(); + Init_Drivers(); + Cust_Init_Layer1(); + Init_Serial_Flows(); + StartFrame(); + Init_Unmask_IT(); +} + +Cust_Init_Layer1() is in L1, StartFrame() is in GPF, and the remaining 4 init +functions live in the init.c module under src/cs/system/main. + +The Init_Target() function finishes the hardware initialization that was +started by the assembly code at the firmware boot entry point (int.s): among +other things, it sets up the final memory timings that will be used by the +running fw and configures the Calypso DPLL which provides multiplied internal +clocks to both ARM and DSP cores. On Calypso C035 silicon which is used on our +own FreeCalypso boards and on most of our pre-existing hw targets the DPLL and +the DSP run at 104 MHz and the ARM gets half of that, running at 52 MHz. +Init_Target() also calls AI_InitIOConfig(), the function that initializes +Calypso GPIO directions and initial outputs; both of these functions typically +need to be tweaked when adding support for a new Calypso board target. + +The Init_Drivers() function is primarily responsible for initializing RiViera +and FFS, although it also does a bit of init related to ABB and SIM drivers. + +I mentioned earlier that every Nucleus task in our firmware gets created and +started either through RiViera or through GPF. All GPF tasks are created and +placed into the runable state in the Application_Initialize() context: the work +is done by GPF init code in gpf/frame/frame.c, and the top level GPF init +function called from Application_Initialize() is StartFrame(). Thus when +Application_Initialize() finishes and the Nucleus thread scheduler starts +running for the first time, all GPF tasks are there to be scheduled. + +There is a compiled-in table of all protocol stack entities and the tasks in +which they need to run; in TCS211 these GPF config bits live under +g23m/condat/frame/config for the GSM+GPRS configuration and under +g23m/condat/com/src/config for the GSM-only config without GPRS. Canonically +each protocol stack entity runs in its own task, but sometimes two or more are +combined to run in the same task: for example, in the minimal GSM "voice only" +configuration (no CSD, fax or GPRS) CC, SMS and SS entities share the same task +named CM. Unlike RiViera, GPF does not support dynamic starting and stopping +of tasks. + +As each GPF task starts running (immediately upon entry into Nucleus' scheduling +loop as Application_Initialize() finishes), pf_TaskEntry() function in +gpf/frame/frame.c is the first code it runs. This function creates the queue +for messages to be sent to all entities running within the task in question, +calls each entity's pei_init() function (repeatedly until it succeeds: it will +fail until the other entities to which this entity needs to send messages have +created their message queues), and then falls into the main body of the task: +for all "regular" entities/tasks except L1, this main body consists of waiting +for messages (or signals or timeouts) to arrive on the queue and dispatching +each received message to the appropriate handler in the right entity. + +RiViera tasks get started in a different way. The responsible code lives in +src/cs/system/main/create_RVtasks.c, and the create_tasks() function found in +that module is called by Init_Drivers() in the Application_Initialize() context. +But this function does not directly create and start every configured RiViera +task like StartFrame() does for GPF. Instead it creates a special helper task +which will do this work once scheduled. Thus at the completion of +Application_Initialize() and the beginning of scheduling the set of runable +Nucleus tasks consists of all GPF ones plus the special RV starter task. Once +the RV starter task gets scheduled, it will call rvm_start_swe() to launch +every configured RiViera SWE (SoftWare Entity), which in turns entails creating +the tasks in which these SWEs are to run. + +Dynamic memory allocation +========================= + +All dynamic memory allocation (i.e., all RAM usage beyond statically allocated +variables and buffers) is once again done either through RiViera or through GPF, +and in no other way. Ultimately all areas of the physical RAM that will ever +be used by the fw in any way are allocated when the fw is compiled and linked: +the areas from which RiViera and GPF serve their dynamic memory allocations are +statically allocated as char arrays in the respective C modules and placed in +the appropriate IRAM or XRAM .bss section by the linker script; RiViera and GPF +then provide API functions that allocate memory dynamically from these +statically allocated large pools. + +RiViera and GPF have entirely separate memory pools from which they serve their +respective clients, hence there is no possibility of one affecting the other. +Riviera's memory allocation scheme is very much like the classic malloc&free: +there is one large unstructured pool from which all allocations are made, one +can allocate a chunk of any size, free chunks are merged when physically +adjacent, and fragmentation is an issue: a memory allocation request may fail +even when there is enough memory available in total if it is too fragmented. + +GPF's dynamic memory allocation facility is considerably more robust: while it +does maintain one or two (depending on configuration) memory pools of the +traditional "dynamic" kind (like malloc&free, susceptible to fragmentation), +most GPF memory allocation works on "partition" memory instead. Here GPF +maintains 3 separate groups of pools: PRIM, TEST and DMEM; each allocation +request must specify the appropriate pool group and cannot affect the others. +Within each pool there is a fixed number of partitions of a fixed size: for +example, in TI's TCS211 GSM+GPRS configuration the PRIM pool group consists of +190 partitions of 60 bytes, 110 partitions of 128 bytes, 50 partitions of 632 +bytes and 7 partitions of 1600 bytes. An allocation request from a given pool +group (e.g., PRIM) can request any arbitrary size in bytes, but it gets rounded +up to the nearest partition size and allocated out of the respective pool. If +no free partition is available, the requesting task is suspended until another +task frees one. Because these partitions are used primarily for intertask +communication, if none are free, it can only mean (assuming that the firmware +functions correctly) that all partitions have been allocated and sent to some +queue for some task to work on, hence eventually they will get freed. + +This scheme implemented in GPF is extremely robust in the opinion of this +author, and the other purely "dynamic" scheme is used (in the case of GPF) only +for init-time allocations which are never freed, such as task stacks - hence +the GPF-based part of the firmware is not suspectible at all to the problem of +memory fragmentation. But Riviera does suffer from this problem, and the +concern is more than just theoretical: one major user of Riviera-based dynamic +memory allocation is the trace facility (described in its own section below), +and my observation of the trace output from Pirelli's proprietary fw (which +appears to use the same architecture with separate Riviera and GPF) suggests +that after the fw has been running for a while, Riviera memory gets fragmented +to a point where many traces are being dropped. Replacing Riviera's poor +dynamic memory allocation scheme with a GPF-like partition-based one is a to-do +item for our project. + +Message-based intertask communication +===================================== + +Even though all entities of the G23M protocol stack are linked together into +one monolithic fw image and there is nothing to stop them from calling each +other's functions and accessing each other's variables, they don't work that +way. Instead all communication between entities is done through messages, just +as if they ran in separate address spaces or even on separate processors. +Buffers for this message exchange are allocated from a GPF partition pool: an +entity that needs to send a message to another entity allocates a buffer of the +needed size, fills it with the message to be sent, and posts it on the recipient +entity's message queue, all through GPF services. The other entity simply +processes the stream of messages that arrives on its message queue, freeing each +message (returning the buffer to the partition pool it came from) as it is +processed. + +Riviera-based tasks use a similar mechanism: unlike G23M protocol stack +entities, most Riviera-based functional modules provide APIs that are called as +functions from other tasks, but these API functions typically allocate a memory +buffer (through Riviera), fill it with the call parameters, and post it to the +associated task's message queue (also in the Riviera land) to be worked on. +Once the worker task gets the job done, it will either call a callback function +or post a response message back to the requestor - the latter option is only +possible if the requesting entity is also Riviera-based. + +A closer look at GPF +==================== + +There are certain sublayers within GPF which need to be pointed out. The 3 +major subdivisions within GPF are: + +* The meaty core of GPF: this part is the code under src/gpf/frame in our + Selenite GPF reconstruction, originating from gpf/FRAME in the TCS3.2 source + from Peek/FGW. It appears that this part was originally intended to be both + project-independent (same for GSM, TETRA etc) and OS-independent (same for + Nucleus, pSOS, VxWorks etc). This is the part of GPF that matters for the + G23M stack: all APIs called by PS entities are implemented here, and so are + all other PS-facing functions such as startup. (PS = protocol stack) + +* OS adaptation layer (OSL): this is the part of GPF that adapts it to a given + underlying OS, in our case Nucleus. + +* Test interface: see the code under gpf/tst in TCS211 from Openmoko or in + FC Selenite. This part handles the trace output from all entities that run + under GPF and the mechanism for sending external debug commands to the GPF+PS + subsystem. + +GPF was a difficult step in our GSM firmware deblobbing process because no +complete source for it could be found anywhere: apparently GPF was so stable +and so independent of firmware particulars (Calypso or LoCosto, GSM only or +GSM+GPRS, modem or complete phone with UI etc) that it appears to have been +used and distributed as prebuilt binary libraries even inside TI. All TI fw +(semi-)sources we've got use GPF in prebuilt library form and are not set up to +recompile any part of it from source. (They had to include all GPF header +files though, as most of them are included by G23M C modules, and it would be +too much hassle to figure out which ones are or aren't needed, hence all were +included.) + +Fortunately though, we were able to find the sources for most parts of GPF: + +* The LoCosto source in TCS3.2_N5.24_M18_V1.11_M23BTH_PSL1_src.zip features the + source for the "core" part of GPF under gpf/FRAME - these sources aren't + actually used by that fw's build system (it only uses the prebuilt binary + libs for GPF), but they are there. + +* Our TCS211 semi-src doesn't have any sources for the core part of GPF, but + instead it features the source for the test interface and some "misc" parts: + under gpf/MISC and gpf/tst in that source tree - these sources are not present + in the LoCosto version from Peek. + +The GPF frame, misc and tst sources we have found have been verified to match +the binary objects that came with TCS211 from OM: they can be compiled into a +bit-for-bit match. However, one critical piece was still missing: the OS +adaptation layer. It appears that the GPF core (vsi_??? modules) and OSL +(os_??? modules) were maintained and built together, ending up together in +frame_<blah>.lib files in the binary form used to build firmwares, but the +source for the "frame" part in the Peek find contained only vsi_*.c and others, +but not any of os_*.c. + +Our FC Magnetite firmware uses the original binary libs from TCS211-Openmoko +for its GPF component, but for FC Selenite the project requirement is to be +completely blob-free, hence we had to reconstruct the source for the OSL part +of GPF from disassembly. This work was originally done in 2014 in the context +of our first attempt at gcc-built blob-free GSM fw (FC Citrine, now deemed to +be a dead end and fully retired); this reconstruction was then dug up and +adapted for Selenite in 2018. As of this writing, this reconstruction is still +not 100% complete (one complex error handling function is stubbed out) and not +yet trusted to be fully correct, thus our fully deblobbed Selenite firmware is +currently considered experimental; our current production fw is still Magnetite +with blobs for GPF. + +A closer look at L1 +=================== + +The L1 code is remarkable in how little intertie it has with the rest of the +firmware it is linked into. It is almost entirely self-contained, expecting +only 4 functions to be provided by the underlying OS environment: + +os_alloc_sig -- allocate message buffer +os_free_sig -- free message buffer +os_send_sig -- send message to upper layers +os_receive_sig -- receive message from upper layers + +It helps to remember that at the beginning of TI's involvement in the GSM +baseband chipset business, L1 was the only thing they "owned", while Condat, +the maintainers of the higher level protocol stack, was a separate company. +TI's "turnkey" solution must have consisted of their own L1 code plus G23M code +(including GPF etc) licensed from Condat, but I'm guessing that TI probably +wanted to retain the ability to sell their chips with their L1 without being +entangled by Condat: let the customer use their own GSM L23 stack, or perhaps +work out their own independent licensing arrangements with Condat. I'm +guessing that L1 was maintained as its own highly independent and at least +conceptually portable entity for these reasons. + +The way in which L1 is intertied into the rest of the fw is the same in all TI +production firmwares we have seen, including both our TCS211 reference and the +TCS3.2 LoCosto version. There is a module called OSX, which is an extremely +thin adaptation layer that implements the APIs expected by L1 in terms of GPF. +Furthermore, this OSX layer provides header file isolation: the only "outside" +(non-L1) header included by L1 is cust_os.h, and it defines the necessary +interface to OSX *without* including any other headers (no GPF headers in +particular), using only the C language's native types. Apart from this +cust_os.h header, the entire OSX layer is implemented in one C module (osx.c, +which we had to reconstruct from osx.obj as the source was missing - but it's +very simple) which does include some GPF headers and implements the OSX API in +terms of GPF services. Thus in both TI's production firmwares and our own ones, +L1 does sit on top of GPF, but very indirectly. + +More specifically, the "production" version of OSX implements its API in terms +of *high-level* GPF functions, i.e., VSI. However, they also had an interesting +OP_L1_STANDALONE configuration which omitted not only all of G23M, but also the +core of GPF and possibly the Riviera environment as well. We don't have a way +to recreate this configuration exactly as it existed inside TI because we don't +have the source bits specific to this configuration, but we do have a little +bit of insight into how it worked. + +It appears that TI's OP_L1_STANDALONE build used a special "gutted" version of +GPF in which the "meaty core" (VSI etc) was removed. The OS layer (os_??? +modules implementing os_*() functions) that interfaces to Nucleus was kept, and +so was OSX used by L1 - but this time the OSX API functions were implemented in +terms of os_*() ones (low-level wrappers around Nucleus) instead of the higher- +level VSI APIs provided by the "meaty core" of GPF. It is purely a guess on my +part, but perhaps this hack was also done in the days before TI's acquisition +of Condat, and by omitting the "meaty core" of GPF, TI could claim that their +OP_L1_STANDALONE configuration did not contain any of Condat's "intellectual +property". + +Run-time structure of L1 +======================== + +L1 consists of two major parts: L1S and L1A. L1S is the synchronous part where +the most time-critical functions are performed; it runs as a Nucleus HISR. The +hardware in the Calypso generates an interrupt on every TDMA frame (4.615 ms, +or more precisely 60/13 ms), and the LISR handler for this interrupt triggers +the L1S HISR. L1S communicates with L1A through a shared memory data structure, +and also sometimes allocates message buffers and posts them to L1A's incoming +message queue (both via OSX API functions, i.e., via GPF in disguise). + +L1A runs as a regular task under Nucleus, and includes a blocking call (to GPF +via OSX) to wait for incoming messages on its queue. It is one big loop that +waits for incoming messages, then processes each received message and commands +L1S to do most of the work. The entry point to L1A in the L1 code proper is +l1a_task(), although the responsibility for running it as a task falls on some +"glue" code outside of L1 proper. TI's production firmwares with G23M included +have an L1 protocol stack entity within G23M whose only job (aside from some +initialization) is to run l1a_task() in the Nucleus task created by GPF for +that protocol stack entity; we do the same in our firmwares. + +Communication between L1 and G23M +================================= + +It is remarkable that L1 and G23M don't have any header files in common: L1 +uses its own (almost fully self-contained), whereas the G23M+GPF realm is its +own world with its own header files. One has to ask then: how do they +communicate? OK, we know they communicate through primitives (messages in +buffers allocated from GPF's PRIM partition memory pool) passed via message +queues, but what about the data structures in these messages? Where are those +defined if there are no header files in common between L1 and G23M? + +The answer is that there are separate definitions of the L1<->G23M interface on +each side, and TI must have kept them in sync manually. Not exactly a +recommended programming or software maintenance practice for sure, but TI took +care of it, and the existing proprietary products based on TI's firmware are +rock solid, so it is not really our place to complain. + +TI's firmwares from the era we are working with (both our TCS211 golden +reference and the TCS3.2/LoCosto source from which we took the newer full-source +version of G23M for our TCS2/TCS3 hybrid) also include a component called ALR. +It resides in the G23M code realm: G23M coding style, uses Condat header files, +runs as its own protocol stack entity under GPF. This component appears to +serve as a glue layer between the rest of the G23M stack (which is supposed to +be truly hardware-independent) and TI's L1. + +Speaking of ALR, it is worth mentioning that there is a little naming +inconsistency here. ALR is known to the connect-by-name logic in GPF as "PL" +(physical layer, apparently), while the ACI entity (Application Control +Interface, the top level entity) is known to the same logic as "MMI". No big +deal really, but hopefully knowing this quirk will save someone some confusion. + +A closer look at our FreeCalypso TCS2/TCS3 hybrid +================================================= + +Because we don't have an official TI firmware release for the Calypso in full +source form and because I am not willing to throw away all of our Calypso work +and restart anew with LoCosto with its own host of unknowns, the only currently +available way for us to have blob-free production-quality GSM mobile station fw +is the TCS2/TCS3 hybrid implemented in FC Magnetite and Selenite. This hybrid +is made by taking the G23M version from TCS3/LoCosto and grafting it onto the +chipsetsw foundation from TCS211, including the original TCS211/Calypso version +of L1 which we have meticulously source-reconstructed. The version of GPF used +for this hybrid is also the TCS211 version in Magnetite or our source +reconstruction thereof in Selenite. + +The Condat G23M pieces have been hybridized as follows: + +* cdginc generated header files are a special hybrid version described below; + +* The include files under condat/com/inc and condat/com/include are the TCS3 + version, except for pwr.h and rtc.h for which we use the TCS2 version; + +* comlib is the TCS2 version, except for cl_rlcmac.c which is from TCS3; + +* config modules (condat/com/src/config and condat/frame/config) are the TCS2 + version, with some fixes for the needs of the TCS3 version of G23M PS and our + own FreeCalypso fixes; + +* Condat drivers (condat/com/src/driver) are the TCS2 version; + +* All G23M PS components are the TCS3 version by necessity, as this is the part + for which the source is missing in our TCS211 version, with the exception of + ALR - the original source for the TCS211 version of ALR has miraculously + survived, the ALR source in TCS211 from OM can be compiled into a perfect + match for the binary lib version; + +* We use the TCS2 version of ALR (the interface to our TCS211 L1) and not the + TCS3 version (a change from Citrine), but it is compiled with the same hybrid + cdginc headers as the rest of hybrid G23M, not the old TCS211 ones; + +* ACI is the TCS3 version - we have the source for both versions, but trying to + use the old TCS2 version of ACI on top of the new TCS3 version of the PS + would cause untold breakage; + +* The UI layers (MFW and BMI) for handset fw builds are handled like ACI: we + have the source for both versions, but we use the TCS3 version which works + with the TCS3 versions of ACI and cdginc; + +* The CST (Customer Specific Task) component is the TCS2 version - while it + logically belongs in the Condat realm, the code lives in the chipsetsw realm + under chipsetsw/services/cst (yes, it's under services with SSA stuff even + though it doesn't use RiViera) and thus our copy of TCS211 from OM has this + source preserved. + +With this hybrid arrangement the main splice point lies above ALR, and there +are many little splice points throughout the code where some upper-level code +from TCS3 needs to talk to lower-level code from TCS2. There are no inversions, +i.e., no places where TCS2 code sits on top of code from TCS3, although there +are a few instances where TCS2 C code uses some TCS3 header files. + +TCS3 feature flags +------------------ + +Our TCS3.2/LoCosto code from Peek/FGW from 20090327 supports several new GSM +features (apparently related to GSM release 99) which are not supported by our +TCS211-20070608 golden reference from OM. All of these new features can be +enabled or disabled with conditional compilation flags. Our TCS2/TCS3 hybrid +currently has all of these new features disabled: it was too difficult for me +to figure out if these new features require some support from the hardware or +the DSP which is present on LoCosto but not Calypso, and even if our hw and DSP +have all of the necessary capabilities, at least some of the new features +require adding some code to L1, which is incompatible with my approach of +reconstructing TCS211 L1 pristinely. + +In any case, the GSM functionality we get by using the new version of G23M with +new feature flags disabled on top of pristine TCS211 L1 cannot be any worse +than what we would have had if we had the full corresponding source for our +TCS211-20070608 golden reference, and it is probably a little better because we +are using a newer version of G23M code. + +cdginc headers +-------------- + +Much of the code in the Condat G23M realm makes heavy use of a set of machine- +generated C header files called cdginc. These header files contain various +definitions related both to the GSM air protocols being implemented and to G23M +protocol stack internals (interfaces and message structures between components), +and they are generated from a set of message definition files (*.mdf) and +primitive definition files (*.pdf) by a tool called ccdgen. The *.{mdf,pdf} +inputs to ccdgen are human-readable ASCII, and of course the generated C header +files are human-readable too, but we have no source for the ccdgen tool itself, +only a Windows binary which we can run under Wine. + +The ccdgen binary problem is yet another instance of so far incomplete +liberation of the GSM firmware. It is currently a very low-priority problem: +we do not casually edit any of the *.{mdf,pdf} inputs to ccdgen, and we don't +run ccdgen on every fw build - instead we have run ccdgen once and checked its +output files (generated C headers) into our Magnetite and Selenite trees as if +they were sources. If we are not able to convince TI to dig up and release the +source for ccdgen, there is a viable albeit costly alternative: hire a Windows +reverser to RE the ccdgen.exe binary (262144 bytes) and produce a C +reimplementation that replicates all of its logic. It is a Win32 console app, +no GUI, and it is a pure data processing application without any hardware access +or OS functions or any other muckery: it is probably pure ANSI C code that reads +and parses a bunch of ASCII input files, performs some business logic on the +data, and writes another bunch of ASCII text files as outputs. It is currently +a very low-priority task though; reversing the Calypso DSP ROM code should +probably be a higher priority. + +The set of cdginc headers for our TCS2/TCS3 hybrid has been generated as +follows: + +* All of the *.mdf files are the TCS3 version; + +* All of the *.pdf files except mphc.pdf and mphp.pdf are also the TCS3 version; + +* mphc.pdf and mphp.pdf are the TCS211 version - this is the interface to + TCS211 L1; + +* All new feature flags (see discussion above) are set to disabled. + +Condat Coder and Decoder (CCD) +------------------------------ + +CCD is a firmware component in the Condat G23M realm which I haven't really +studied yet. It consists of two parts: + +* A fixed portion which TI used to distribute in binary form and which various + firmware projects used as a prebuilt library like GPF - technically TI + considered it to be a part of GPF, although we prefer to treat it as its own + more independent entity; + +* The ccddata portion which needs to be compiled with cdginc headers for each + given project. + +We got the source for both parts of CCD only in the TCS3.2/LoCosto version, but +not in the TCS211 version, hence the decision was easy: we use the TCS3 version +of CCD (both parts) with the TCS3 version of cdginc with the TCS3 version of +the G23M PS. + +TCS3.2 GPF discrepancy +---------------------- + +A careful examination of the prebuilt GPF libraries under gpf/LIB in the TCS3.2 +LoCosto source tree has revealed that a few of the binary objects exhibit some +differences from the TCS211 version which we've been treating as our golden +reference: + +* The os_mis module (OSL miscellany) in the IRAM library implements a new + function called os_CheckQueueEvent() and defines a new global data object + named my_os_mis_Protect; + +* The os_tim module (OSL timer code) in the flash (XIP) library has some code + differences; + +* The vsi_tim module (VSI timer code) in the flash (XIP) library has some code + differences; + +* The vsi_tim module (VSI timer code) in the IRAM library has some code + differences and makes use of the new os_CheckQueueEvent() function. + +In the case of os_??? modules we have no corresponding source for either +version, but the vsi_tim difference is more bizarre: we got our vsi_tim.c source +(and the rest of vsi_*.c) from the TCS3.2/LoCosto source, but this source +matches the TCS211 binary version and not the newer and different binary version +used by the TCS3.2 build system! (Remember that none of TI's firmware build +systems that we have seen are set up to recompile any part of GPF from source, +they used it only as prebuilt libraries.) + +Because we have the corresponding source for the "old" version of GPF frame core +but not for the "new" version, we are continuing to treat the "old" TCS211 +version as our golden reference: we use the source pieces which we got, and we +use the "old" os_???.obj blobs as our basis for reconstruction via disassembly. + +Because the changes in the TCS3.2 binary version of GPF involve only the +implementation of a part of VSI but not its API (there are no changes to any +part of the GPF API presented to the G23M PS that I can see anywhere), I have +every good reason to believe that there is no problem with using the new TCS3.2 +version of G23M with the old version of GPF from TCS211: it should work no worse +than pure TCS211. + +It should also be noted that if we ever succeed in getting some more complete +GPF source out of TI (including the source for the OS adaptation layer which is +difficult to reconstruct), thanks to the great stability and independence of +GPF, we will be happy with *any* version, does not need to match either TCS211 +or TCS3.2. + +GPRS implementation differences +------------------------------- + +There is a visible difference between the way GPRS is implemented in the old +TCS211-20070608 blob version of G23M and the way it is implemented in the newer +TCS3.2/LoCosto version we are using for our hybrid. The new implementation adds +a new protocol stack entity named UPM (User Plane Manager), and the pre-existing +SM and SNDCP entities have been significantly changed to work with this UPM. +Because we are using the GPRS config modules (condat/frame/config) from TCS211, +we had to add a -DFF_UPM compilation flag to include UPM in the GPF +configuration for the GSM+GPRS protocol stack. + +A closer look at ACI +==================== + +The Application Control Interface (ACI) is the crown that sits on top of the +G23M protocol stack. It includes the AT command interpreter (ATI) component, +and this AT command interface is brought to the outside world via the UART +protocol stack entity. The UART entity implements the GSM 07.10 MUX, can +operate the physical UART in either multiplexed or non-multiplexed mode (the +latter is the default on boot for a plain ASCII AT command interface) as +commanded by ACI, and establishes 1 to 4 logical channels carrying AT commands +to ACI. When a CSD or fax call or a GPRS PPP session is in progress, the data +path is switched to run between the UART entity and the appropriate GSM or GPRS +protocol stack destination. In the case of modem products that are designed to +be controlled by an external host via AT commands, this combination of ACI and +UART entities provides the ultimate end function of the device. + +The set of implemented AT commands is defined in ati_cmd.c: this is the C file +where new AT commands get added; there is also an enum of command IDs in +aci_cmh.h which needs to be extended. For every AT command listed in the table +in ati_cmd.c there is a handler function: for example, for the AT+CFUN command +there is a setatPlusCFUN() function that handles setting and a queatPlusCFUN() +function that handles querying. For some simple AT commands like AT+CGxx +queries the function listed in ati_cmd.c does the entirety of the work, but for +most of the interesting GSM commands (including the AT+CFUN example just used) +the set and query functions implemented in the ATI layer only handle the parsing +of ASCII arguments and generation of ASCII output (if any), whereas the actual +command implementation happens in the CMH layer below. + +Below ATI but still within ACI lies the sublayer of command handlers (CMH). +For each AT command that does something to the GSM mobile station there is a +functional equivalent, a C function that performs the same operation as the +spec-defined AT command, but is designed to be used natively from C code, +without AT command string parsing or output formatting. For the AT+CFUN example +used above, the setatPlusCFUN() ATI function parses the arguments from ASCII +and then calls sAT_PlusCFUN() to perform the actual operation, whereas the +queatPlusCFUN() ATI function calls qAT_PlusCFUN() to retrieve the current state +and then prints it out in ASCII. This functional interface is used by TI's +demo/prototype phone UI implementation described in the Handset-UI-fw companion +document. + +Finally, at the bottom of ACI lies the sublayer of Protocol Stack Adapters +(PSA): these are pieces of code that execute within the ACI task and exchange +primitives with various G23M protocol stack entities below. + +We have the source for both TCS2 and TCS3 versions of ACI. The TCS2 version is +from Openmoko, containing OM's modifications, and we had to go through these +changes and additions by OM, reject the bogus ones and reimplement the sensible +ones in the new TCS3 version of ACI for our TCS2/TCS3 hybrid going forward. + +Flash file system +================= + +Every GSM device that is based on TI's firmware architecture contains not only +the firmware image proper, but also a flash file system that is separate from +the fw image and is maintained in a different part of the flash chip. The FFS +implementation code is a mandatory part of the firmware; in TCS211 it resides +in chipsetsw/drivers/drv_app/ffs and logically belongs to the SSA realm. This +code initializes early in the fw boot process in the Application_Initialize() +context before the start of Nucleus task scheduling; the responsible function +is ffs_main_init() called from Init_Drivers(). + +Flash driver support and FFS location +------------------------------------- + +Determining the location of the flash area allocated for FFS and the flash +driver to be used to write to it is a combination of autodetection and hard- +coding. The approach implemented in the original TCS211 code is as follows: +there is a piece of autodetection code that reads the flash chip ID, and the +autodetected ID is then looked up in a hard-coded table that gives the driver +and geometry details and the location of the FFS sectors for each supported +flash chip type. However, this approach has its limitations: + +* The sequence of write operations which TI's autodetection code issues in + order to put the flash chip into its Read ID mode worked for older flash + chips that were used by TI and Openmoko, but does not work for the newer + Spansion S71PL129NC0HFW4B flash chip which we (FreeCalypso) have copied from + the Pirelli DP-L10 phone. + +* While the physical flash chip used on a given phone or modem board is a + physical property that can be autodetected, the choice of which flash sectors + should be used for FFS is a matter of policy. Before we built our own + FreeCalypso hardware, we had to run our fw on some pre-existing "alien" hw + targets, and we still support such usage to a limited extent. When we run + our FreeCalypso fw on an alien hw target as an aftermarket deal, our + aftermarket FFS location needs to be chosen quite carefully. + +* Some flash chips have two chip select banks, and with such chips it is + generally desirable to put the FFS in the second bank. However, it is a + matter of board wiring whether that second flash chip select is connected to + Calypso chip select nCS2, nCS3 or nCS4 - thus FFS addresses in the second bank + have to be hard-coded with conditional compilation per board type and cannot + be autodetected. + +To support our new repertoire of possible hardware targets, the logic has been +changed as follows in our Magnetite and Selenite firmwares: + +* When the target is our own FC hardware family (CONFIG_TARGET_FCFAM) or the + Pirelli DP-L10 phone (CONFIG_TARGET_PIRELLI), flash chip type autodetection + is disabled and a strictly fixed hard-coded FFS configuration is used; + +* When the target is one of Mot C1xx subfamilies, the autodetection logic is + kept (several different flash chip types are found in these phones), but a + different table is used, giving our aftermarket FFS configurations for these + Mot C1xx flash chip types; + +* When the target is gtamodem (Openmoko GTA01/02 modem) or dsample (TI's + D-Sample board), we use the original autodetection logic and device table + which we got from TI/Openmoko. + +We have also changed the AMD multibank flash driver to issue write commands in +a way that is compatible with our new S71PL129NC0HFW4B chip. + +FFS life cycle +-------------- + +In products that have been built according to TI's original way, including +Openmoko GTA01/02 and our own FreeCalypso devices, the FFS is formatted and +initialized with some essential content at the time of device manufacture, and +this factory-created and factory-initialized FFS then persists for the lifetime +of the device. In our factory environment at FreeCalypso hardware manufacturing +we initialize the flash on our freshly assembled boards like this: + +flash erase 0 0x800000 +flash program-bin 0 fwimage.bin +flash2 erase 0 0x800000 + +This factory procedure (which should ONLY be executed at the factory and never +by any end users or even sw/fw developers and tinkerers) ensures that the flash +is completely blank everywhere except the fw image loaded at the time of +production, and when this fw image boots for the first time, it will see blank +flash in the FFS sectors. When TI's FFS code in ffs_main_init() sees this +condition, it performs what TI called a preformat: it writes a basic FFS block +header into each FFS sector, but does not automatically perform a full format - +instead the latter needs to be commanded explicitly by the production station +via one of TMFFS command packet protocols as described later in this article. +In FreeCalypso we have adopted TMFFS2 as our choice of Test Mode FFS access +protocol, our host side implementation of this protocol is fc-fsio, and we +format and initialize the FFS on our devices with an fc-fsio command script as +part of our factory procedure. + +FFS content and usage +--------------------- + +TI's firmware architecture uses the FFS for many purposes: + +* The IMEI is stored in the FFS - GSMA can proclaim all they want that it + "MUST" be stored in some kind of super-secure one-time programmable fuses, + but in TI's architecture and in FreeCalypso it is just a regular file in the + FFS. + +* A number of RF calibration tables are stored in FFS and read by the RF code + in L1. If you have a Rohde&Schwarz CMU200 instrument which is itself in good + repair and calibration standing and a metrology-grade RF cabling setup whose + insertion loss at the relevant GSM frequencies is precisely known, creating + or recreating these RF calibration values is as simple as executing one shell + script that takes a few minutes to run - this is how we do it at FreeCalypso + hw manufacturing - but if you are an ordinary user or sw/fw developer or + tinkerer without a professional calibration station setup, you need to use + the RF calibration values that have been written into the FFS by the device + manufacturer. These RF calibration tables live under /gsm/rf. + +* /gsm/com/rfcap tells the RR component in the G23M protocol stack (not L1!) + which frequency bands are supported on a given device - on our devices it is + a factory-programmed file distinguishing between tri900 and tri850 units and + telling the firmware which bands it should scan for possible GSM cells. + +* Manufacturer, model and revision ID strings may be written into /pcm/CGMI, + /pcm/CGMM and /pcm/CGMR, respectively, to be returned by the corresponding + AT+CGxx query commands. + +* The G23M protocol stack writes a number of dynamically updated files under + the /gsm hierarchy and under /pcm. + +* TI's demo/prototype UI code (see Handset-UI-fw companion document) writes its + persistent state in files under /mmi. + +* Audio mode configuration files are kept under /aud - see the Audio-mode-config + article in freecalypso-tools. + +* If a given product uses the Melody E1 mechanism, melody files to be played + through the RiViera Audio Service are kept in FFS - see the Melody_E1 article + in freecalypso-tools. + +Building firmware for different targets +======================================= + +TI's TCS3.2 firmware for their LoCosto chipset which was rejected by the Mother +for reasons described near the beginning of this article makes a complete break +from the past and has no possibility of supporting any pre-LoCosto chips such +as our beloved Calypso, but TI's previous evolutionary developments weren't so +drastic: the evolution to Calypso from previous chips such as Hercules and +Ulysse was smoother, and our reference TCS211 fw is littered with C preprocessor +conditionals supporting TI's earlier development boards prior to D-Sample and +DBB chips prior to Calypso. + +TI's configuration management architecture supported only TI's own development +boards and not any of the end product boards: unfortunately they did not follow +a development model like the Linux kernel where everyone is encouraged to +contribute their custom board support bits upstream and the mainline kernel +strives to support every hw target that was ever supported with a single source +tree, instead it was the divergent model where every end device manufacturer +would take TI's reference firmware source and hack it for their specific needs +with no concern for upstreamability or support for targets or applications +other than their own. TI's firmware build configuration model defined the +following C preprocessor symbols relating to support for different hw targets, +all numeric, i.e., each symbol is always defined to a number: + +BOARD identifies which board is to be targeted, with numbers assigned for +different development boards made by various TI groups, but generally not for +customer boards. The only Calypso-based BOARD number is 41, originally +assigned for the D-Sample but then also reused for the Leonardo; all other +BOARD numbers are for some other chipsets that aren't Calypso. The previous +board before D-Sample was C-Sample, which is BOARD 9, but I am not sure exactly +what chipset it had - perhaps it was Ulysse/Nausica/Clara. There is still +plenty of support for BOARD 9 and even earlier boards in the firmware source we +got. + +CHIPSET identifies the main DBB chip. The interesting numbers are 7 for the +very original Calypso C05 rev A, 8 for Calypso C05 rev B (found on the D-Sample +board which the Mother scored in 2015), 10 for Calypso C035 (the Calypso silicon +version we work with in FreeCalypso), 11 for Calypso Lite (same as the regular +Calypso except for smaller IRAM), 12 for Calypso+ (a short-lived intermediate +step between Calypso and LoCosto) and 15 for LoCosto. + +ANLG_FAM (previously ANALOG) identifies the ABB chip. The numbers are 1 for +Nausica, 2 for Iota (what we use) and 3 for Syren (typically used with Calypso+ +like on the E-Sample board). + +RF_FAM (previously just RF) identifies the RF hardware hooked up to the baseband +chipset. The interesting numbers are 10 for Clara (D-Sample) and 12 for Rita, +the latter being the only RF chip for which we have driver support. + +Naturally any code that cares about DBB register differences would use the +CHIPSET definition, ABB support code would use ANLG_FAM, RF support code would +use RF_FAM, and finally code that needs to know about board-level peripherals +like LCDs and keypads would use the BOARD symbol. This model worked fine up to +D-Sample: for example, the code for C-Sample vs. D-Sample LCDs and keypads is +cleanly conditionalized on BOARD 9 vs. BOARD 41. However, the waters got badly +muddied when TI introduced their Leonardo board and instead of giving it its +own BOARD number, reused BOARD number 41 from D-Sample. + +D-Sample was TI's primary internal development platform for the Calypso, +featuring Iota for the ABB and Clara for the RF part. It was a great solid +platform in every way except the RF part: the old Clara RF is inconvenient +(needs more external parts) and TI were marketing their newer Rita RF to real +end device manufacturers, but the D-Sample still worked great for development: +if you aren't working specifically on the RF part, it doesn't matter as long as +you have a working driver for it, which we lack. Then TI made another Calypso +development board called Leonardo, featuring the same Calypso+Iota baseband +plus the newer Rita RF. But this Leonardo never fully replaced the D-Sample +for any of the high-level development in the SSA and UI groups. + +Openmoko's modem is a direct derivative of the Leonardo, the only change being +the RFFE (for some reason FIC didn't like TI's quadband RFFE as implemented on +Leonardo and E-Sample boards and used their own slightly hobbled triband RFFE +instead), and the firmware build given to OM was TI's Leonardo fw with just a +few tweaks in tpudrv12.h to account for the RFFE control signal differences. +However, because Leonardo never got its own BOARD number and the BOARD symbol +is still set to 41, all of the SSA/UI code (LCD, keypad, battery charging etc) +is still built as if for D-Sample - but none of that code is used on a pure AT +command modem without UI functions or UI hardware, hence OM probably never +noticed anything odd. + +And it wasn't just Openmoko - it appears that TI used their Leonardo boards +mostly or perhaps even solely in the ACI configuration without UI layers +(MMI=0 build configuration), while all or most UI development was done on +D-Sample kits. Their TCS211 reference fw product officially supported both +D-Sample and Leonardo targets in both ACI and BMI+MFW configurations, but if +one were to build a high-end UI-enabled config for the Leonardo like pdt_2272, +it would target a 176x220 pixel color LCD, the LCD output driver would be the +one for the D-Sample (expecting memory-mapped LCD registers on nCS3), and the +keypad driver would expect D-Sample keypad wiring. Looking at the available +Leonardo schematics I see a serial (uWire) LCD interface instead and a more +basic keypad with different wiring, so I don't see how those Leonardo+UI +firmware builds could possibly work. Perhaps some other group at TI did some +UI work on Leonardo boards, but never made it into the internal mainline +from which TCS211 releases were cut - who knows... + +Finally, aside from the basic failure to distinguish properly between D-Sample +and Leonardo boards, this whole BOARD number system provides absolutely no +mechanism to distinguish between TI's development boards and end product boards +derived from them, or between end product boards of vendor A vs. vendor B, or +between end product model A and model B from the same vendor - it's always +BOARD 41 as far as TI's code is concerned. When TI had to modify their code +for OM to support FIC's different TSPACT signal wiring, they just edited the +definitions in tpudrv12.h without any conditionals, so one couldn't build +binaries for the original Leonardo vs. OM's hardware from the same source tree +in different configs. + +The build system of TCS211 produces a set of generated C header files named +*.cfg (instead of the more natural *.h); these generated config headers define +all of the C preprocessor symbols listed above and many more. They are included +sometimes as #include "board.cfg" and othertimes as #include "config/board.cfg" +(ditto for other *.cfg), thus the list of -I directories passed by the build +system on compiler invocation lines needs to include both the config directory +and its parent. In our Magnetite and Selenite build systems we likewise +generate these *.cfg headers; some of the symbols defined therein are variable +and originate from Bourne shell variables in our own configuration system, but +many others are fixed. See scripts/cfg-template in our Magnetite and Selenite +trees for the magic. + +The BOARD symbol is always fixed at 41 in all FreeCalypso firmwares, +corresponding to TI's D-Sample and Leonardo, and we use our own different +mechanism to distinguish among our supported targets. The solution adopted in +Magnetite and Selenite is as follows: we are supplementing TI's *.cfg files +with our own fc-target.cfg (included as #include "fc-target.cfg" or as +#include "config/fc-target.cfg" matching whatever existing TI code we are +gently extending), and this fc-target.cfg header is populated by the build +system by copying the appropriate targets/*.h header file. These targets/*.h +header snippets define C preprocessor symbols of our own invention like +CONFIG_TARGET_xxx, and whenever we need to know our target in C code, we +#include "fc-target.cfg" and use #ifdef logic based on these preprocessor +symbols of our own addition. + +RVTMUX debug and development interface +====================================== + +The Calypso chip has two UARTs, and TI's TCS211 firmware and its predecessors +are designed with the assumption that both of these UARTs are available. Per +TI's fw architecture, Calypso's MODEM UART presents the standard AT command +interface with GSM 07.10 MUX, CSD, fax and GPRS capabilities as described +earlier when we looked at ACI and ATI, whereas the other UART (called the IrDA +UART in hardware docs but not used for that purpose) presents a vitally +important debug, development and production interface called RVTMUX. This +RVTMUX interface can also be moved to the MODEM UART, in which case the standard +AT command interface is lost. + +RVTMUX is a binary packet interface, and it got its name because it is a MUX of +multiple logical channels managed by the RiViera Trace (RVT) firmware component. +RVTMUX is often thought of as being primarily a debug trace interface, as that +is the primary use to which it is put: in normal operation the firmware emits +quite voluminous debug trace output on the IrDA UART, encapsulated in 3 +different RVTMUX channels as explained below. However, it is also possible to +send a number of different debug and development commands to the firmware via +this interface, and this functionality is used as a critical component in +Calypso GSM device factory production line processes: this RVTMUX interface is +the only way by which the FFS can be initialized, RF calibration and tests can +be performed and the IMEI can be set at the factory. + +Communication with a running firmware over this RVTMUX interface in a +development or production setting (whether passively reading debug traces or +actively sending development or test commands to the running fw) requires +specialized host tools. TI originally had a suite of Windows-based tools for +this purpose, but we are not using them in FreeCalypso: we only got Windows +binaries without any sources, and even in the case of those binaries we only +got an incomplete set with some important tools missing. Instead we are using +our own Unix-based tools called FreeCalypso host tools; these tools have been +developed from scratch by Mother Mychaela after studying the firmware components +with which they need to communicate. + +Debug trace output +================== + +The firmware component that "owns" the physical UART channel assigned to RVTMUX +is RVT, contained in chipsetsw/riviera/rvt in TCS211 or in src/cs/riviera/rvt +in our Magnetite and Selenite firmwares. It is a Riviera-based component, +and it has a Nucleus task that is created and started through Riviera. All +calls to the actual driver for the UART are made from RVT. In the case of +output from the Calypso GSM device to an external host, all such output is +performed in the context of RVT's Nucleus task; this task drains RVT's message +queue and emits the content of allocated buffers posted to it, freeing them +afterward. (The dynamic memory allocation system in this case is Riviera's, +which is susceptible to fragmentation - see discussion earlier in this article.) +Therefore, every trace or other output packet emitted from a GSM device running +our fw (or any of the proprietary firmwares based on the same architecture) +appears as a result of a message in a dynamically allocated buffer having been +posted to RVT's queue. + +RVT exports several API functions that are intended to be called from other +tasks, it is by way of these functions that most output is submitted to RVT. +One can call rvt_send_trace_cpy() with a fully prepared output message, and +that function will allocate a buffer from Riviera's dynamic memory allocator +properly accounted to RVT, fill it and post it to the RVT task's queue. +Alternatively, one can call rvt_mem_alloc() to allocate the buffer, fill it in +and then pass it to rvt_send_trace_no_cpy(). + +At higher levels, there are a total of 3 kinds of debug traces that can be +emitted: + +* Riviera traces: these are generated by various components implemented in + Riviera land, although in reality any component can generate a trace of this + form by calling rvf_send_trace() - this function can be called from any task. + +* L1 traces: L1 has its own trace facility implemented in + src/cs/layer1/cfile/l1_trace.c; it generates its traces as ASCII messages and + sends them out via rvt_send_trace_cpy(). + +* GPF traces: code that runs in GPF/G23M land and uses those header files and + coding conventions etc can emit traces through GPF. GPF's trace functions + (implemented in gpf/frame/vsi_trc.c) allocate a memory partition from + GPF's TEST pool, format the trace into it, and send the trace primitive to + GPF's special test interface task. That task receives trace and other GPF + test interface primitives on its queue, performs some manipulations on them, + and ultimately generates RVT trace output, i.e., a new dynamic memory buffer + is allocated in the Riviera land, the trace is copied there, and the Riviera + buffer goes to the RVT task for the actual output. + +Trace masking +============= + +The RV trace facility invoked via rvf_send_trace() has a crude masking ability, +but by default all traces are enabled. In TI's standard firmwares most of the +trace output comes from L1: L1's trace output is very voluminous, and most of +it is fully enabled by default. + +On the other hand, GPF and therefore G23M traces are mostly disabled by default. +One can turn the trace verbosity level from any GPF-based entity up or down by +sending a "system primitive" command to the running fw, and another such command +can be used to save these masks in FFS, so that they will be restored on the +next boot cycle and be effective at the earliest possible time. Enabling *all* +GPF trace output for all entities is generally not useful though, as it is so +verbose that a developer trying to make sense of it will likely drown in it - +and it will also overwhelm the debug trace facility itself, causing most of +these far too voluminous traces to be lost. Therefore, a developer seeking to +debug an issue in the G23M protocol stack needs to enable traces very +judiciously. + +GPF compressed trace hack +========================= + +TI's Windows-based GSM firmware build systems include a hack called str2ind. +Seeking to reduce the fw image size by eliminating trace ASCII strings from it, +and seeking to reduce the load on the RVTMUX serial interface by eliminating +the transmission time of these strings, they passed their sources through an +ad hoc preprocessor that replaces these ASCII strings with numeric indices. +The compilation process with this str2ind hack becomes very messy: each source +file is first passed through the C preprocessor, then the intermediate form is +passed through str2ind, and finally the de-string-ified form is compiled, with +the compiler being told not to run the C preprocessor again. + +TI's str2ind tool maintains a table of correspondence between the original trace +ASCII strings and the indices they've been turned into, and a copy of this table +becomes essential for making sense of GPF trace output: the firmware now emits +only numeric indices which are useless without this str2ind.tab mapping table. + +Our FC Magnetite build system retains the option of using str2ind, but it is +disabled by default: str2ind significantly increases firmware compilation times, +the resulting fw image sizes without str2ind are fine (the slight increase does +not push us over any limits), and we haven't had any issues with ASCII strings +overloading the trace interface. However, there is an additional complication +stemming from the choice of two possible G23M PS versions, one of which is a +set of blob libraries: + +* If Magnetite is compiled in a pure TCS211 configuration using the original + blob version of G23M PS, these blobs already have str2ind indices baked into + them instead of trace ASCII strings, hence the frozen str2ind.tab file from + Openmoko that maps these indices back to strings needs to be used. + +* If Magnetite is compiled in a TCS2/TCS3 hybrid config without G23M blobs, + then unless you enable it explicitly with USE_STR2IND=1, no str2ind will be + used at all. + +Our blob-free FC Selenite firmware does not support str2ind at all - we shall +stick with full ASCII string traces until and unless we run into an actual (as +opposed to hypothetical) problem with either fw image size or serial interface +load. + +RVTMUX command input +==================== + +RVTMUX is not just debug trace output: it is also possible for an external host +to send commands to the running fw via RVTMUX. + +Inside the fw RVTMUX input is handled by the RVT entity by way of a Nucleus +HISR. This HISR gets triggered when Rx bytes arrive at the designated UART, +and it calls the UART driver to collect the input. RVT code running in this +HISR parses the message structure and figures out which fw component the +incoming message is addressed to. Any fw component can register to receive +RVTMUX packets, and provides a callback function with this registration; this +callback function is called in the context of the HISR. + +In the original TCS211 fw there are only two components that register to receive +external host commands via RVTMUX: ETM and GPF, hence these are the only command +packet types that can be sent to this original fw. In FreeCalypso we have kept +these, and we've also added some new RVTMUX channels of our own invention. + +Test Mode (TM) and Enhanced Test Mode (ETM) +=========================================== + +A 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 like TCS211 does, 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 the sole surviving copy of TCS211 that serves as our golden +reference came with L1TM in binary object form like the rest of L1, and we got +to source-reconstructing it only much later. + +ETM is implemented as a Riviera SWE and has its own Nucleus task; the callback +function that gets called from the RVT HISR posts received messages onto ETM's +own queue drained by its task. The ETM task gets scheduled, picks up the +command posted to its queue, executes it, and sends a response message back to +the external host through RVT. + +Because all ETM commands funnel through ETM's queue and task, and that task +won't start looking at a new command until it finished handling the previous +one, all ETM commands and responses are in strict lock-step: it is not possible +to send two commands and have their responses come in out of order, and it makes +no sense to send another ETM command prior to receiving the response to the +previous one. (But there can still be debug traces or other traffic intermixed +on RVTMUX in between an ETM command and the corresponding response!) + +L1TM commands get posted to the message queue of the L1A task and then executed +in that task's context. + +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 (at least in TI's original architecture, +as opposed to Motorola's bastardized version) is the ability to access and +manipulate the GSM device's flash file system (FFS) that was described earlier +in this article. 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 Magnetite and +Selenite firmwares. + +Our choice of TMFFS2 over TMFFS1 was driven by the need to develop our own host +tools to replace TI's original ones which we never got. 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 (Mother +Mychaela) 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 the implementation +code in chipsetsw/drivers/drv_app/ffs/board/tmffs.c in TCS211 if you would like +to judge for yourself.) Our host tool that speaks the TMFFS2 protocol is +fc-fsio. + +GPF external command input +========================== + +The other component that can receive external commands is GPF. GPF's test +interface can receive so-called "system primitives", which are ASCII string +commands parsed and acted upon by GPF, and also binary protocol stack +primitives. Remember how all entities in the G23M stack communicate by sending +messages to each other? Well, GPF's test interface allows such messages to be +injected externally as well, directed to any entity in the running fw. System +primitive commands can also be used to cause entities to send their outgoing +primitives to the test interface, either instead of or in addition to the +originally intended recipient. + +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, in the case of our FreeCalypso family of projects about 2 years had +passed between our first functional GSM fw attempts in 2015 and us successfully +building our own development board in 2017; during this time we had to work on +various crippled pre-existing Calypso devices, and many of them had only one +UART practically accessible. In response to this situation 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, described below. + +Now that we have built a proper FreeCalypso development board with two UARTs, +the use of this AT-over-RVTMUX hack is deprecated for general usage: this hack +does not support any data services (CSD or GPRS), and even for SMS it is +crippled because maximum-length messages cannot be sent in the more capable PDU +mode. However, it still comes in handy during certain casual testing sessions, +and it is required if one needs to run our FreeCalypso firmware on Mot C1xx or +Pirelli DP-L10 hardware. + +FC host tools for talking to firmwares via RVTMUX +================================================= + +The fundamental tool for talking to running firmwares via RVTMUX is a program +called rvinterf. It runs on a Unix/Linux host machine, opens a serial port +that is expected to be connected to the RVTMUX UART on the target, and then +speaks TI's binary packet protocol on that serial port. It then performs two +functions: + +* If rvinterf is run in the foreground in a terminal window (or more precisely, + if its default terminal output is not disabled), every packet received from + the target is decoded and printed on stdout in human-readable ASCII. For + some packets like TM/ETM responses this "human-readable" form is just a hex + dump, but the trace messages which the firmware emits on its own are printed + in truly human-readable form. This output can also be saved to a log file. + +* Rvinterf creates a local UNIX domain socket on the machine it is running on, + and other host tools can then connect to this socket to exchange packets with + the firmware. Client programs connected to rvinterf via this local socket + interface can register to receive copies of packets sent by the target on + specific RVTMUX channels, and they can also send arbitrary packets to the + target. + +Our main "client" programs for actively interacting with running firmwares via +rvinterf are: + +fc-tmsh This utility speaks the TM/ETM protocol. It supports almost + all ETM and L1TM commands that are supported by our reference + TCS211 fw with the important exception of TMFFS; support means + that fc-tmsh can issue these commands and decode the firmware's + responses to them. fc-tmsh operates asynchronously in that the + issuance of commands to the target and the display of firmware + responses are completely decoupled; this asynchronous model is + a good match for L1/RF test mode commands and simple ETM + operations, but is a poor fit for FFS manipulation. fc-tmsh's + companion fc-fsio implements FFS access via TMFFS2, and we + don't have a host side implementation for TI's older TMFFS1 + protocol. + +fc-fsio This utility speaks the TMFFS2 protocol over the TM/ETM RVTMUX + channel (same channel as used by fc-tmsh, so don't try to run + both at the same time) and implements fairly high-level FFS read + and write operations. fc-fsio is used to format and initialize + the FFS on newly made devices in our hardware manufacturing + environment, it can upload files or entire subtrees into target + device FFS, it has higher-level commands for writing some files + like the IMEI, rfcap and AT+CGxx ID strings, and it can list and + read out FFS content. Unlike fc-tmsh, fc-fsio is synchronous: + it is built on command-response (send a command and expect a + response) primitives, and a single user command can turn into a + large number of command-response exchanges on the RVTMUX + interface. fc-fsio also implements a few non-FFS commands + because they naturally fit into this ETM synchronous model. + +fc-shell This tool is asynchronous like fc-tmsh, but instead of talking + and listening on the TM/ETM RVTMUX channel, it talks and listens + on GPF's channel and on the new AT-over-RVTMUX channel which we + added in FreeCalypso. fc-shell can be used to issue system + primitive commands to GPF (and to see firmware responses to + them), and to talk AT commands via RVTMUX. + +Finally, if you only need to passively observe the firmware's debug trace output +and don't need to make any active pokes at the target, our rvtdump utility is a +stripped-down version of rvinterf (or historically its predecessor) that only +decodes and prints/logs the output from the target without sending anything to +it. + +Further reading +=============== + +Believe it or not, some of the documentation that was written by the original +vendors of the software in question and which we've been able to locate turns +out to be fairly relevant and helpful, such that I recommend reading it. + +Documentation for Nucleus PLUS RTOS: + + ftp://ftp.freecalypso.org/pub/embedded/Nucleus/nucleus_manuals.tar.bz2 + + Quite informative, and fits our version of Nucleus just fine. + +Riviera environment: + + ftp://ftp.freecalypso.org/pub/GSM/Calypso/riviera_preso.pdf + + It's in slide presentation form, not a detailed technical document, but + it covers a lot of points, and all that Riviera stuff described in the + preso *is* present in our fw for real, hence it should be considered + relevant. + +GPF documentation: + + https://www.freecalypso.org/LoCosto-docs/SW%20doc/frame_users_guide.pdf + https://www.freecalypso.org/LoCosto-docs/SW%20doc/vsipei_api.pdf + + Very good reading, helped me understand GPF when I first reached this + part of firmware reintegration. + +TCS3.x/LoCosto fw architecture: + + https://www.freecalypso.org/LoCosto-docs/SW%20doc/TCS2_1_to_3_2_Migration_v0_8.pdf + ftp://ftp.freecalypso.org/pub/GSM/LoCosto/LoCosto_Software_Architecture_Specification_Document.pdf + + These TI docs focus mostly on how they changed the fw architecture from + their TCS2.x program (Calypso) to their newer TCS3.x (LoCosto), but one + can still get a little insight into the "old" TCS211 architecture they + were moving away from, which is the architecture we've adopted for + FreeCalypso.