DemoN API Interface Information

Xecuter

Staff member
Top TX Brass
Dec 6, 2002
11,459
128
Asia
team-xecuter.com

TIP



Please note that this document is not yet final but should give most developers enough to start "tinkering"




DemoN API Interface Information


Introduction

Xecuter currently provides two libraries in order for developers to interface with DemoN. The high-level API is covered in demon.dll, whereas the low-level API is accessible through dcp.dll.

The high-level API is a very abstract interface to DemoN. It offers complex operations such as reading/programming NAND-flash memories, as well executing XSVF files. These operations usually consist of a multitude of low-level API calls.

Developers who want to integrate DemoN support into their application, will most likely want to interface with the high-level API. Researchers/hackers may find the high-level API not suitable for a certain purpose and may need to go down to the bare metal and directly call low-level API functions.

The following two chapters will give detailed information about the high- and low-level API functions.


I. High-level API (demon.dll)

The high-level API currently offers the following 15 functions. In order to demonstrate their use, the full source code to dtool is provided as a reference.

Before any other high-level API function may be called, the user needs to create and initialize a demon_t structure by calling demon_create. The function will return a pointer to a demon_t structure on the heap. If the call to demon_create succeeds, the demon_t structure must finally be freed by calling demon_destroy.
Code:
demon_error_t demon_create(demon_t** self, demon_printf_fn_t printf, demon_delay_fn_t delay);
Calling demon_destroy will free the demon_t structure from the heap.
Code:
void demon_destroy(demon_t* self);
In order to send commands to DemoN, a USB communication channel must be established. This is accomplished by calling demon_open. If a connection to DemoN cannot be established instantly, demon_open will retry up to 10 times with a delay of 1 second in between.
Code:
demon_error_t demon_open(demon_t* self);
demon_close will close the USB communication channel previously established through a call to demon_open.
Code:
void demon_close(demon_t* self);
Calling demon_run_bootloader will switch DemoN into bootloader mode. When in bootloader mode, calling any other high-level API function besides demon_update_firmware or demon_run_firmware is an error and will result in undefined behavior. It is not necessary to check, if DemoN is in firmware mode before issuing a call to demon_run_bootloader.
Code:
demon_error_t demon_run_bootloader(demon_t* self);
Calling demon_run_firmware will switch DemoN back into firmware mode, if a valid firmware is present.
Code:
demon_error_t demon_run_firmware(demon_t* self);
demon_read_flash will dump the contents of the currently active NAND-flash into the given file. While dumping, the error correction code (ECC) is checked for each plane of each page and block.
Code:
demon_error_t demon_read_flash(demon_t* self, const char* filename);
Programming an image into the currently selected DemoN NAND-flash is triggered by calling demon_program_flash. Please note that the high-level API does not yet perform remapping of bad blocks! This feature will be added in a future release. Image files do not have to be full NAND-flash dumps. Missing blocks in the image will simply be skipped during programming.
Code:
demon_error_t demon_program_flash(demon_t* self, const char* filename);
demon_erase_flash will completely erase the currently active NAND-flash memory. Since demon_program_flash will erase each block prior to programming, it is thus not necessary to call demon_erase_flash before. This function offers a simple way to quickly dispose of any NAND-flash contents.
Code:
demon_error_t demon_erase_flash(demon_t* self);
demon_exec_xsvf will run the XSVF interpreter inside DemoN with data from the given file. This function is usually used to program/update Xecuter CoolRunner devices. Since the XSVF interpreter is generic, it can also be used to program arbitrary devices through the JTAG interface.
Code:
demon_error_t demon_exec_xsvf(demon_t* self, const char* filename);
The Xbox 360 can be powered on remotely by calling demon_power_on.
Code:
demon_error_t demon_power_on(demon_t* self);
demon_power_off will power off the Xbox 360.
Code:
demon_error_t demon_power_off(demon_t* self);
The currently active NAND-flash can be toggled by pressing either the button on the DemoN connector board, the SYNC button or by issuing a call to demon_select_flash.
Code:
demon_error_t demon_select_flash(demon_t* self, demon_flash_t flash);
demon_update_firmware will update the DemoN firmware with the image contained in the given file. Firmware updates are distributed in a special firmware archive format, which is cryptographically signed by Xecuter.
Code:
demon_error_t demon_update_firmware(demon_t* self, const char* filename);
The helper function demon_get_error formats an error code returned by any of the high-level API function into a human readable message.
Code:
const char* demon_get_error_msg(demon_error_t err);
II. Low-level API (dcp.dll)

In contrast to the high-level API, the low-level API is much more fine-grained and therefore allows more precise control over DemoN. Currently, the low-level API consists of 35 functions. Some functions may only be called in firmware mode [F], others only in bootloader mode and a few in any mode [A]. The mode in which a function may be called is specified in the function's signature. Calling a function in the wrong mode will result in undefined behavior.

Before any other low-level function may be called, the user needs to create and initialize a dcp_t structure by calling dcp_create. The function will return a pointer to a dcp_t structure on the heap. If the call to dcp_create succeeds, the dcp_t structure must finally be freed by calling dcp_destroy. A failed call to dcp_create may indicate, that the DemoN driver is not installed.
Code:
dcp_error_t dcp_create(dcp_t** self); [A]
Calling dcp_destroy will free the dcp_t structure from the heap.
Code:
void dcp_destroy(dcp_t* self); [A]
In order to send commands to DemoN, a USB communication channel must be established. This is accomplished by calling dcp_open.
Code:
dcp_error_t dcp_open(dcp_t* self); [A]
dcp_close will close the USB communication channel previously established through a call to dcp_open.
Code:
void dcp_close(dcp_t* self); [A]
The mode in which DemoN is currently executing (bootloader/firmware) can be queried by calling dcp_get_mode. This information is required for all subsequent low-level API calls. Calling a low-level API function from the wrong mode is undefined and will usually result DemoN halting further execution.
Code:
dcp_error_t dcp_get_mode(dcp_t* self, dcp_mode_t* mode); [A]
Calling dcp_get_proto_ver will return the firmware or bootloader protocol version number. The major version number is returned in the higher 8 bits, the minor version number in the lower 8 bits. Since the bootloader cannot be updated in the field, the bootloader protocol version number will never change. However, firmware protocol version numbers may change by updating the DemoN firmware.
Code:
dcp_error_t dcp_get_proto_ver(dcp_t* self, uint16_t* ver); [A]
The current protocol version numbers (major.minor) are as follows:
bootloader - 1.00
firmware - 1.00


If new commands are added to the DemoN USB communication protocol, the minor version number is incremented and a new low-level API function will be added to execute this command. As long as changes to the DemoN USB communication protocol are backwards compatible, only the minor version number will be incremented. An application is supposed to check compatibility with the currently installed DemoN firmware by querying the protocol version number and checking it against the minimal required version number.

At some point in the future, it may be necessary to change the DemoN USB communication protocol in a way it is no longer backwards compatible. In order to reflect this, the major protocol version number will be incremented.

Calling dcp_get_device_id returns the DemoN device ID.
Code:
dcp_error_t dcp_get_device_id(dcp_t* self, uint16_t* ver); [F]
These device IDs currently exist:
0x0000 - DemoN Phat 16MB
0x0001 - DemoN Slim 16MB

Calling dcp_get_firmware_ver returns the firmware version number. The major version number is returned in the higher 8 bits, the minor version number in the lower 8 bits.
Code:
dcp_error_t dcp_get_firmware_ver(dcp_t* self, uint16_t* ver); [F]
dcp_run_bootloader will switch DemoN into bootloader mode. Switching into bootloader mode is usually done in order to perform a firmware update.
Code:
dcp_error_t dcp_run_bootloader(dcp_t* self); [F]
dcp_get_ext_flash returns the currently active NAND-flash.
Code:
dcp_error_t dcp_get_ext_flash(dcp_t* self, dcp_ext_flash_t* flash); [F]
Calling dcp_set_ext_flash will set the NAND-flash specified by parameter flash as the new active NAND-flash.
Code:
dcp_error_t dcp_set_ext_flash(dcp_t* self, dcp_ext_flash_t flash); [F]
Prior to accessing the NAND-flash, DemoN needs to gain control over the NAND-flash control and data busses. This is triggered by calling dcp_acquire_ext_flash.
Code:
dcp_error_t dcp_acquire_ext_flash(dcp_t* self); [F]
Calling dcp_release_ext_flash will relase control over the NAND-flash control and data busses. As long as the busses are not released, the Xbox 360 may itself not access the NAND-flash.
Code:
dcp_error_t dcp_release_ext_flash(dcp_t* self); [F]
dcp_get_ext_flash_id will return the ID of the currently active NAND-flash.
Code:
dcp_error_t dcp_get_ext_flash_id(dcp_t* self, uint16_t* id); [F]
In order to perform bad block remapping, an application needs to know in advance the list of bad blocks in the currently active NAND-flash. Calling dcp_get_bad_blocks will return a dcp_bad_block_info_t structure holding all required information. The "num" field specifies the number of bad blocks. If this number exceeds 64, then this mostly indicates an installation error. The "blocks" field holds the list of "num" bad blocks.

Code:
dcp_error_t dcp_get_bad_blocks(dcp_t* self, dcp_bad_block_info_t* info); [F]
Calling dcp_erase_ext_flash block will erase the given NAND-flash block.
Code:
dcp_error_t dcp_erase_ext_flash_block(dcp_t* self, uint16_t block); [F]
Calling dcp_erase_all_ext_flash_blocks will erase all NAND-flash blocks.
Code:
dcp_error_t dcp_erase_all_ext_flash_blocks(dcp_t* self); [F]
dcp_read_ext_flash_block returns "size" bytes of block "block" in the buffer pointed to by "buf". Please note that "size" must be equal to the block size (including spare area) of the currently active NAND-flash. Specifying a wrong "size" parameter may halt further USB communication.
Code:
dcp_error_t dcp_read_ext_flash_block(dcp_t* self, uint16_t block, uint32_t size, void* buf); [F]
By calling dcp_program_ext_flash_block, the block "block" will be programmed with "size" bytes of data pointed to by "buf". dcp_program_ext_flash_block will itself not erase the block before programming. This needs to be done by either calling dcp_erase_ext_flash_block or dcp_erase_all_ext_flash_blocks.
Code:
dcp_error_t dcp_program_ext_flash_block(dcp_t* self, uint16_t block, uint32_t size, const void* buf); [F]
dcp_assert_sb_reset must be called along with dcp_acquire_ext_flash in order for DemoN to gain control over NAND-flash control and data busses.
Code:
dcp_error_t dcp_assert_sb_reset(dcp_t* self); [F]
Control over NAND-flash control and data busses must be released after all NAND-flash operations are carried out. This is done by calling dcp_deassert_sb_reset along with dcp_release_ext_flash.
Code:
dcp_error_t dcp_deassert_sb_reset(dcp_t* self); [F]
dcp_read_serial reads data from DemoN's serial interface buffer. The buffer pointed to by "buf" must be 1536 bytes large, as this is the maximum number of bytes stored in DemoN's buffer. The "num" parameter indicated how many bytes were actually returned.
Code:
dcp_error_t dcp_read_serial(dcp_t* self, uint16_t* num, void* buf); [F]
Feeding data into DemoN's XSVF interpreter is a three step process. The transfer is first initiated by calling dcp_exec_xsvf_begin. The "size" parameter specifies the size of the XSVF file, which is to be transferred.

Subsequent calls to dcp_exec_xsvf_next transfer up to 64 byte sized chunks of the XSVF file. If the XSVF file is transferred completely, calling dcp_exec_xsvf_end will stop the interpreter.
Code:
dcp_error_t dcp_exec_xsvf_begin(dcp_t* self, uint32_t size); [F]
dcp_error_t dcp_exec_xsvf_next(dcp_t* self, uint8_t size, const void* buf); [F]
dcp_error_t dcp_exec_xsvf_end(dcp_t* self); [F]
Calling dcp_power_on will power on the Xbox 360 by sending a sequence of pulses over the so-called kiosk pin of the southbridge connector.
Code:
dcp_error_t dcp_power_on(dcp_t* self); [F]
Calling dcp_power_off will power off the Xbox 360.

Code:
dcp_error_t dcp_power_off(dcp_t* self); [F]
Calling dcp_get_bootloader_ver returns the bootloader version number. The major version number is returned in the higher 8 bits, the minor version number in the lower 8 bits.
Code:
dcp_error_t dcp_get_bootloader_ver(dcp_t* self, uint16_t* ver); [B]
dcp_run_firmware will switch DemoN into firmware mode, if a valid firmware is present.
Code:
dcp_error_t dcp_run_firmware(dcp_t* self); [B]
An application may check for the presence of a valid firmware by calling dcp_check_firmware_status. If no firmware is present, this indicates that a prior firmware update sequence has not completed successfully.
Code:
dcp_error_t dcp_check_firmware_status(dcp_t* self, dcp_fwstat_t* stat); [B]
Before a DemoN MCU flash page may be erased or programmed, dcp_update_firmware_begin must be called to enter the firmware update sequence. Failing to do so will halt all further execution.
Code:
dcp_error_t dcp_update_firmware_begin(dcp_t* self); [B]
Once all firmware pages have been updated successfully, dcp_update_firmware_end must be called to leave the firmware update sequence.
Code:
dcp_error_t dcp_update_firmware_end(dcp_t* self); [B]
dcp_read_int_flash_page will read an encrypted page of DemoN's MCU flash. Pages always have a size of 256 bytes.
Code:
dcp_error_t dcp_read_int_flash_page(dcp_t* self, uint8_t page, void* buf); [B]
dcp_erase_int_flash_page will erase the given page of DemoN's MCU flash.
Code:
dcp_error_t dcp_erase_int_flash_page(dcp_t* self, uint8_t page); [B]
Calling dcp_program_int_flash_page will program "page" with 256 bytes of data pointed to by "buf". The data for the firmware update must be encrypted with a key. Since this key is only known to Xecuter, firmware updates cannot be issued by anyone else for obvious security reasons. Data for the firmware update is usually read from a firmware archive.
Code:
dcp_error_t dcp_program_int_flash_page(dcp_t* self, uint8_t page, const void* buf);
 

Ubergeek

Xecuter Groupie
Feb 24, 2003
6,272
0
California, USA
you guys remember when people were calling this merely a "dual nand" device?

point and laugh at them
We did say it was much much more :)

This is only the beginning - wait until add-ons like Bluetooth and Wifi and LCD start being made to work with all those lovely gpios and this great API interface.

think of the possibilities..... iPhone, iPad, Android........
 

joona2134

VIP Member
Jan 31, 2011
269
0
Walsall, UK
Ok sold, I ordered one after reading ubers comment lol
 

IceKiller

VIP Member
Nov 5, 2011
24
0
nice work ;)

hope to see a few other programs integrating it!
 

NeoGodSpeed

VIP Member
Mar 14, 2007
150
0
Arizona
We did say it was much much more :)

This is only the beginning - wait until add-ons like Bluetooth and Wifi and LCD start being made to work with all those lovely gpios and this great API interface.

think of the possibilities..... iPhone, iPad, Android........
cant wait for the Bluetooth and LCD
 

fieso

Full Member
Feb 1, 2011
27
0
Thx for sharing API and source.

Hope critic is welcome, Imo following should be changed in dtool.
*) using goto in high level language is bad conding style
*) make commands case-insensitive ("read", ..., "xbox360", "demon")
 
Last edited:

nitram

VIP Member
Jan 10, 2012
36
0
UK
Can't wait to get my demon, wonder if you could make a POST/UART reader out of it. I remember someone saying there were spare io's we could use.
 

Xecuter

Staff member
Top TX Brass
Dec 6, 2002
11,459
128
Asia
team-xecuter.com
Thx for sharing API and source.

Hope critic is welcome, Imo following should be changed in dtool.
*) using goto in high level language is bad conding style
*) make commands case-insensitive ("read", ..., "xbox360", "demon")
Critic is always welcome heh :)

However you're wrong in this case (imo)

gotos are indeed considered bad coding style (in general), but when it comes to programming, no rule is set into stone. The use of goto is widespread in the linux kernel for exactly one purpose - error handling, and that's what we used it for.

Millions of lines of great operating system code rely on this :)

I appreciate your input though !
 

fieso

Full Member
Feb 1, 2011
27
0
gotos are indeed considered bad coding style (in general), but when it comes to programming, no rule is set into stone. The use of goto is widespread in the linux kernel for exactly one purpose - error handling, and that's what we used it for.

Millions of lines of great operating system code rely on this
I know, its proper named and structured to keep code readable. But in this case cleanup-code isnt that much to make it necessary.

Anyway, thx for your reply.

PS: Any change we get something similar for x360usb?
 

360backupman

BANNED
Mar 16, 2011
286
0
I know, its proper named and structured to keep code readable. But in this case cleanup-code isnt that much to make it necessary.

Anyway, thx for your reply.

PS: Any change we get something similar for x360usb?
Say you did, what would be the purpose?
 

PersonCC

Senior Member
Apr 14, 2012
123
0
Thank you so much for having an API guide...

I love it when people open up development for everyone... just might have to buy one just to develop with ;)


(Sorry for posting on an older thread, didn't notice till after I posted)