84PCE:OS:Applications
Contents
Application File Type
Applications for the CE calculator have the extension 8ek.
Relocations exist to place the app correctly in the archive, 6 bytes per block (2+22 bits):
0b00 indicates a reference to the code segment executing from Flash, and 0b10 indicates a reference to the data/bss segment in RAM. 0b01 and 0b11 are a reserved format;
Applications can be of arbitrary size, no longer multiples of 16kB.
Applications in the Archive
Applications are stored beginning at the address 03B0000h and grow downwards. 3 bytes are used as offsets to the start of the app, since the search is backwards. The following status bytes represent what might be found when parsing for applications:
081h = valid Flash application (part of the app header)
000h = deleted Flash application (part of the app header)
Some search code may look like this (Will locate the start of all the app headers):
_FindValidLocation: ld hl,03B0000h ; applications start here find: dec hl dec hl dec hl push hl ld de,(hl) ld hl,0FFFFFFh ; check for end or a,a sbc hl,de pop hl ret z ; found end of applications or a,a sbc hl,de ; hl points to the start of the app header here if found jr find
The actual App header contains certain fields which correspond to the type of data they represent. TI dropped the ball and even though these are variable length fields, the OS code can only handle headers that are padded to 256 bytes in length.
810(F)h = Master field, 4 bytes in length, which contains the offset to the signature field. (Big Endian)
811(2)h = Signing key ID. On the CE, this is 2 bytes in length with the value 0130Fh, indicating it was signed with the '130F' key.
812(D)h = Version information. Begins with the length of the version string, followed by the string itself. This is a minimum compatible version.
813(2)h = Unknown, but contains the 2 byte data 05900h.
814(N)h = Name of App. In this case, 'N' represents the length of the name in bytes. This field is then followed by the name of the app.
817(F)h = End app header information, 4 bytes in length, which contains the offset to the signature field. (Big Endian)
81A(1)h = Unknown, but contains the 1 byte data 007h
Other fields:
003h & 2(6)h & 009h & 0(4)h = Time stamp field. 4 bytes long; represents the number of seconds since January 1st 1997, 00:00:00 in some timezone, and some step of the build process.
00Dh & 0NNh = This (NN) represents how much padding until the next field, as app headers must be padded to 256 bytes.
002h & 03(E)h = Signature field. The is followed by the two bytes containing the value 0100h, the length of the 2048 bit signature
At the end of the signature is 3 bytes representing the size of the application. (These bytes are not included however)
App size calculation is as follows: [Length of master header + offset to signature field in (810)] + [4 bytes of signature field + 256 bytes of signature] + [3 bytes application size]
This is pretty much the same as adding 269 to the value in the big endian master field.
This is an example of such a header:
; Master Field -- This app is 102247 + 269 (102516) bytes in size .db 081h, 00Fh, 000h, 001h, 08fh, 067h ; Signing Key Field .db 081h, 012h, 013h, 00Fh ; Version information -- 00Bh represnets the length until the next field .db 081h, 02Dh, 00Bh, "5.0.0.0089", 000h ; Unknown field .db 081h, 032h, 059h, 000h ; Name Field -- Name is 7 bytes long, so that is where the 047h comes from .db 081h, 047h, "CabriJr" ; Unknown field .db 081h, 0A1h, 007h ; Time stamp -- Who knows what time is was? .db 003h, 026h, 009h, 004h .db 021h, 0BBh, 06Eh, 0DCh ; Amount of pading (This is so, so silly) .db 000h, 00Dh, 0C7h ; Padding of 0C7h (199) bytes .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .db 0,0,0,0,0,0,0 ; Final field .db 081h, 07Fh, 000h, 001h, 08Eh, 06dh ; End of 256 byte header
Additional App Structure
However, apps are also made up of a certain sequence of bytes following the header. Offsets are calculated from the posistion after the header, in addition to the offsets derived from offsets.
Offset after 256 byte header:
000h = The ASCII string "eZ8", potentially signifying an eZ80 application
003h = Null terminated Application name (zero padded to be 9 bytes in length with terminator byte)
00Ch = Flag
[Bit 0 - Disable TI splash screen] [Bit 1 - App can use OpenLib]
00Eh = Flag
[Bit 0 - Use offset 01Eh for languages] [Bit 1 - Integrated app] [Bit 2 - Unknown] [Bits 3-5 control something]
012h = Main section
015h = Initialized data section (Can be at most 4kB in size)
018h = Initialized data section Length
01Bh = Execution entry point (usually same as 012h)
01Eh = Unknown 3 byte offset used in Language apps (See 00Eh)
021h = Offset to ExecLib jump table
024h = Offset to the string used to display a message in the memory screen (Usually a copyright, i.e. "(c) 2005-2015 Texas Instruments")
027h = Reserved word
02Ah = Start of relocation table
ExecLib
In order to use ExecLib properly from BASIC programs, you must:
1. Set the proper bit at offset 00Ch.
2. Initialize offset 021h to the start of the library jump table
3. Ensure that the jump table offsets are stored in the relocation table
The format for the jump table is shown below: (Note that you store AppLibraryTable offset to 021h).
.db "LIB" .dl NUMBER_OF_FUNCTIONS_IN_JUMP_TABLE AppLibraryTable: .dl Function_1 .dl Function_2 ...
Relocations
Because apps are stored at a fixed memory address, they require a relocation table to relocate them during sending and defragmentation.
The relocation map consists of a six-byte entry for each location which needs to be updated.
Offset | Length | Contents |
---|---|---|
000h | 003h | Hole offset |
003h | 003h | base (2 bits) and relative value to place in hole (22 bits) |
Relocation Map Format
The hole offset specifies where in the application code or initial data table an absolute address needs to be updated. The value to store in the hole is calculated from the base and relative value. The base is 00 for code-segment relative and 10 for data-segment relative. Base values 01 and 11 are reserved.
Example
Here is a full demo program demonstrating finding each application, displaying the name, size, version, and copyright information
#include "ti84pce.inc" .db tExtTok,tAsm84CECmp .org usermem ;-------------------------------------------------------------------- ; Finds all the apps and displays info _FINDAPPS: ld ix,0 add ix,sp ld hl,ExecuteApp ld de,cursorImage ld bc,ExecuteApp_End-ExecuteApp_Start ldir call _ZeroOP3 ld a,appObj ld (OP3),a _: call _HomeUp call _ClrScrn call _OP3ToOP1 call _FindAppUp ; find the app ret c call _OP1ToOP3 ; store name ld hl,OP1+1 push hl call _PutS ; put name of app pop hl ; don't need this push/pop (here for readability) call _FindAppStart ; find the start of the app push hl call GetAppSize call _DispHL ; display the size of the app call _NewLine pop hl push hl push hl call _os_GetAppVersionString pop bc call _PutS call _NewLine pop hl call FindAppInfoString ; Get the information call _PutS _: call _GetCSC or a,a jr z,-_ cp a,sk2nd jr nz,--_ ld hl,OP3+1 jp cursorImage ;-------------------------------------------------------------------- ExecuteApp: ; HL -> name of app (0 terminated) .org cursorImage ExecuteApp_Start: ld de,progToEdit ld bc,8 ldir ld a,cxExtApps jp _NewContext ;---------------------------------------------------------------------------- FindAppInfoString: ; Finds the information string about an App ; i.e. (c) 2005-2014 Texas Instruments ; Arguments: ; HL : contains start of app address ld bc,$100 ; bypass some header info add hl,bc push hl pop de ld bc,$24 add hl,bc ld hl,(hl) ; load location of info string add hl,de or a,a sbc hl,de ; check if HL is 0 ret z add hl,de ; add extra bytes ret ;---------------------------------------------------------------------------- FindStartOfAppCode: ; Finds the start of the actual executable from the start of an App ; Arguments: ; HL : contains the start of the app address ld bc,$100 ; bypass some header info add hl,bc push hl pop de ld bc,$1B ; offset add hl,bc ld hl,(hl) add hl,de ret ;---------------------------------------------------------------------------- DeletePgrmFromUserMem: ld de,(asm_prgm_size) ; load total program prgmSize or a,a sbc hl,hl ld (asm_prgm_size),hl ; delete whatever current program was there ld hl,userMem jp _DelMem ; HL->place to delete, DE=amount to delete ;---------------------------------------------------------------------------- GetAppSize: ; Gets the size of an app based from the start of the app push hl call _NextFieldFromType ; move to start of signature call _NextFieldFromType ; move to end of signature pop de or a sbc hl,de inc hl inc hl inc hl ; bypass app size bytes ret ; haha, we're probably looking at another app here ExecuteApp_End:
Credits and Contribution
Matt "MateoConLechuga" Waltz