Table of Contents
LIME CORE
Lime core is the networking processor which was found to be present in DIGIC 7 and above. The main motive behind this was to ease debugging by using a network-based debugger Scout which can possibly run on the camera.
All the investigations below were done under 200D (SL2) at version 1.0.1.
LIME Shell
The networking processor was found to have a DryOS implementation with an interactive shell which can be accessed from the ICU through UART.
Now before accessing it, the Lime core needs to be powered on. This can simply be done from the Canon GUI where the WIFI can be enabled (WPS led blinking).
Interestingly enough a new category is added to the ICU dry shell help command(?
) named NetDomain
when the networking processor is on.
[NetDomain] netlog
running netlog
in the dry shell printed the following:
NETLOG( 18): 7.55sec(0x02f3) [PComNetCommonIF.c:443] leave_drv NETLOG( 34): 7.55sec(0x02f3) [PComNetCommonIF.c:466] enter_drv NETLOG( 50): 7.55sec(0x02f3) [PComNetCommonIF.c:473] leave_drv NETLOG( 66): 7.55sec(0x02f3) [PComNetCommonIF.c:466] enter_drv NETLOG( 82): 7.55sec(0x02f3) [PComNetCommonIF.c:473] leave_drv NETLOG( 98): 7.55sec(0x02f3) [PComNetCommonIF.c:466] enter_drv ...
This log most likely showed the interactions from the ICU to the Lime core on the lower level as it was filled with leave_drv
and enter_drv
messages and nothing more.
Now from the dry shell(ICU), executing uart_change
when LIME was active changed the shell from Dry[MusaPUX]>
to Dry[LIME]>
.
The help command ?
printed the following:
Dry[MusaPUX]> uart_change Dry[LIME]> ? [Kern] extask meminfo mkcfg dminfo exobjinfo stdlibcfg sysvers xd xm prio resume suspend release sem mutex event mq [User] exit timer mkobjsize kill delete cmp date [Test] time count mktest iotest chkspi [Network] netvers eci arp dhcpc ifconfig mbufs netstat route ping tcputil dnsutil [WELL] nell-attach nell-detach nell-wakeup nlog up down stat scan join leave wset wget wep w12get w12set elog uap wfd [TMN] tm rt wpse wpscmd wcf wcfcmd [Utility] uart_change [NetDomain] wprd wtst actlog
Memory Map
Address | Description | Processor | Size |
---|---|---|---|
rom:0xa0000000 | Entry point | LIME | 0x16a6f0 |
rom:0xe0c8fc78 | ROM0.BIN mapping for network processor | N/A | 0x16a6f0 |
ram:0x01800730 | Ram segment start | LIME | 0x431063 |
Musa(ICU) & LIME communication
PComNetSocket
is the 'api' which transfers commands from the ICU to Lime and vice versa.
Every registered function which can be called from the ICU to Lime has the prefix of Invoke
in Lime.
Lime
Approximately 53 functions can be 'invoked' the from ICU from the PComNetSocket
API for the CommonSyncWrite
table.
There are multiple tables but CommonSyncWrite
is the most useful one since it exposes some of the higher level sockets.
Every function which can be called is on a table at 0x01a9f9a5(CommonSyncWrite) and the first one being InvokeSocket
.
(Was found using a string search of Invoke
)
CommonSyncWrite | |||
---|---|---|---|
Address | Contents | Index | Name |
ram:01a9f9a5 | 30 07 02 a0 | 1 | InvokeSocket |
ram:01a9f9a9 | 84 07 02 a0 | 2 | InvokeBindConnectCommon (socket_bind) |
ram:01a9f9ad | e0 07 02 a0 | 3 | InvokeBindConnectCommon (socket_connect) |
ram:01a9f9b1 | 3c 08 02 a0 | 4 | InvokeListen |
ram:01a9f9b5 | 88 08 02 a0 | 5 | InvokeAccept |
ram:01a9f9b9 | 28 09 02 a0 | 6 | InvokeRecvmsg |
ram:01a9f9bd | 28 09 02 a0 | 7 | InvokeRecvmsg |
ram:01a9f9c1 | 80 0a 02 a0 | 8 | InvokeSend |
ram:01a9f9c5 | c8 0a 02 a0 | 9 | InvokeSendto |
Musa (ICU)
function FUN_E07146B8 takes in three parameters which apparently lookup the table on the Lime core, processes the function on the Lime core and returns the result back to the ICU.
FUN_E07146B8(int index,int *parameterArray,int parameterArraySize)
Canon already has many 'filler' functions for Lime functions which should be called instead and they can be found by looking up the xrefs of 0xe07146b8 with the parameters passed in.
For example socket_bind
which is InvokeBindConnectCommon
with an index of 2
is passed to 0xe07146b8 like this:
FUN_E07146B8(0x2,&local_28,0x14);
In this case, local_28 would hold the return values as this function is also blocking.
Here are the common networking stubs found:
Networking stubs for 200D 1.0.1 | |||
---|---|---|---|
Address | Name | Signatures | Info |
0xe0110cc4 | socket_convertfd | int socket_convertfd(int sockfd) | (found from xrefs of FUN_E07146B8) |
0xe071d880 | socket_create | int socket_create(int domain, int type, int protocol); | translation from ICU to lime is needed with socket_convertfd |
0xe071d8b8 | socket_bind | int socket_bind(int sockfd, void *addr, int addrlen) | found from index, CommonSyncWrite |
0xe071d8f2 | socket_connect | int socket_connect(int sockfd, void *addr, int addrlen) | found from index, CommonSyncWrite |
0xe071d92c | socket_listen | int socket_listen(int sockfd, int backlogl) | found from index, CommonSyncWrite |
0xe071d960 | socket_accept | int socket_accept(int sockfd, void *addr, int addrlen) | found from rpc_accept |
0xe071d99a | socket_recv | int socket_recv(int sockfd, void *buf, int len, int flags) | found from 'rpc_recv' |
0xe071da20 | socket_send | socket_send(int sockfd, void *buf, int len, int flags) | found from index, CommonSyncWrite |
0xe071da80 | socket_setsockopt | socket_setsockopt(int socket, int level, int option_name, const void *option_value, int option_len) | found from 'rpc_setsockopt' |
0xe071db7a | socket_shutdown | socket_shutdown(int sockfd, int flag) | found from index, CommonSyncWrite |
0xe0714a20 | socket_close | socket_close(int sockfd) | found from index, CommonSyncWrite. needs converted fd |
0xe010608e | socket_select_caller | socket_select_caller(int convertedsock, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) | found from 'rpc_select' |
socket_select_caller
is not the actual socket_select function since this function needs the descriptors to be converted by the socket_convertfd
function and the fd_set
used must also be converted by socket_convertfd
.
So socket_select
could look like this:
int socket_select(int sockfd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { int converted = socket_convertfd(sockfd); return socket_select_caller(converted, readfds, writefds, exceptfds, timeout); }
and the fd_set could look like this:
typedef struct my_fd_set { uint32_t fds_bits[64]; } my_fd_set; int my_FD_ISSET(unsigned long n, struct my_fd_set *p) { int convert = socket_convertfd(n); uint32_t mask = 1 << (convert % 32); return p->fds_bits[convert / 32] & mask; } void my_FD_SET(unsigned long n, struct my_fd_set *p) { int convert = socket_convertfd(n); uint32_t mask = 1 << (convert % 32); p->fds_bits[convert / 32] |= mask; } void my_FD_CLR(unsigned long n, struct my_fd_set *p) { int convert = socket_convertfd(n); uint32_t mask = 1 << (convert % 32); p->fds_bits[convert / 32] &= ~mask; }
Misc
Socket | ||
---|---|---|
Option | Value | Info |
AF_INET | 0x1 | Internet IP Protocol |
SOCK_STREAM | 0x1 | TCP Protocol |
Socket Options | ||
---|---|---|
Option | Value | Info |
SOL_SOCKET | 0xffff | options at the socket level |
SO_REUSEADDR | 0x2 | allow reuse of local addresses |
socket_bind
and socket_connect
takes in three parameters. The array which is passed in should look like this:
char sockaddr[8]; // 1 = IPv4, 2 = IPv6, 3 = Ethernet sockaddr[0] = 0x00; sockaddr[1] = 0x01; // port 25565 sockaddr[2] = 0x63; // low byte sockaddr[3] = 0xdd; // high byte // ip address: 192.168.10.22 sockaddr[4] = 192; sockaddr[5] = 168; sockaddr[6] = 10; sockaddr[7] = 22;
socket_bind(sock,sockaddr, 0x8) socket_connect(sock,sockaddr, 0x8)