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. The following status bytes represent what might be found when parsing for applications:
0FFh = empty (this signifies the end of the available applications)
081h = valid Flash application (part of the app header)
000h = deleted Flash application (part of the app header)
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.
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 of main header information, followed by perhaps may be a 4 byte checksum
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 + 256 (102503) 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 3 bytes long, so that is where the 043h 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 Data
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 = Copy of the application name (zero padded to be 9 bytes in length)
00Ch = Flag, Bit 0 set -- don't draw the TI splash screen
00Eh = Flag, Bit 0,1
012h = Unknown offset -- 3 bytes
015h = Contains the offset to the initialized data section which should be copied to ram (Can be at most 4kB in size)
018h = Contains the length of the initialized data section
01Bh = Contains the offset to the location to begin execution
01Eh = Unknown
024h = Contains the offset to the string used to display a message in the memory screen (Usually a copyright, i.e. "(c) 2005-2015 Texas Instruments")
027h = Unknown offset -- 3 bytes
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 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) ; An alternative would be to copy to progtoedit and call _NewConext0 .org cursorImage ExecuteApp_Start: push hl call DeletePgrmFromUserMem ld hl,$100 call _EnoughMem pop hl jp c, _ErrMemory call _FindAppStart ; This locates the start of executable code for an app ld a,E_Validation jp c,_JError ; If we can't find it, that's a problem (throw a validation error) push hl ; push location of start of app call _ReloadAppEntryVecs call _AppSetup set appRunning,(iy+APIFlg) ; turn on apps set 6,(iy+$28) res 0,(iy+$2C) ; set some app flags set appAllowContext,(iy+APIFlg) ; turn on apps ld hl,$D1787C ; copy to ram data location ld bc,$FFF call _MemClear ; zero out the ram data section pop hl ; hl -> start of app push hl ; de -> start of code for app ld bc,$100 ; bypass header information add hl,bc ex de,hl ld hl,$18 ; find the start of the data to copy to ram add hl,de ld hl,(hl) call __icmpzero ; initialize the bss if it exists jr z,+_ push hl pop bc ld hl,$15 add hl,de ld hl,(hl) add hl,de ld de,$D1787C ; copy it in ldir _: pop hl ; hl -> start of app call FindStartOfAppCode ; After this, hl -> start of code for app jp (hl) ;---------------------------------------------------------------------------- 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 _AddNextAppFieldOffset ; move to start of signature call _AddNextAppFieldOffset ; 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