84PCE:OS:Applications

From WikiTI
Revision as of 23:37, 1 October 2017 by MateoConLechuga (Talk | contribs)

Jump to: navigation, search

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 set - don't draw the TI splash screen] [Bit 1 set - app can use OpenLib]

00Eh = Flag, [Bit 0 set - use the offset in 01Eh] [Bit 3 controls 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 (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 not stored at a fixed memory address, they require a relocation table to relocate them during sending and defragmentation.

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)
; 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	_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