====== 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 [[https://github.com/CheckPointSW/Scout|Scout]] which can possibly run on the camera. All the investigations below were done under 200D (SL2) at version 1.0.1. [[https://en.wikipedia.org/wiki/ESP32|ESP32]] ==== 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)