User Tools

Site Tools


digic:processors:lime

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.

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:01a9f9a530 07 02 a01InvokeSocket
ram:01a9f9a984 07 02 a02InvokeBindConnectCommon (socket_bind)
ram:01a9f9ade0 07 02 a03InvokeBindConnectCommon (socket_connect)
ram:01a9f9b13c 08 02 a04InvokeListen
ram:01a9f9b588 08 02 a05InvokeAccept
ram:01a9f9b928 09 02 a06InvokeRecvmsg
ram:01a9f9bd28 09 02 a07InvokeRecvmsg
ram:01a9f9c180 0a 02 a08InvokeSend
ram:01a9f9c5c8 0a 02 a09InvokeSendto

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
0xe0110cc4socket_convertfdint socket_convertfd(int sockfd) (found from xrefs of FUN_E07146B8)
0xe071d880socket_createint socket_create(int domain, int type, int protocol); translation from ICU to lime is needed with socket_convertfd
0xe071d8b8socket_bindint socket_bind(int sockfd, void *addr, int addrlen) found from index, CommonSyncWrite
0xe071d8f2socket_connectint socket_connect(int sockfd, void *addr, int addrlen) found from index, CommonSyncWrite
0xe071d92csocket_listenint socket_listen(int sockfd, int backlogl) found from index, CommonSyncWrite
0xe071d960socket_acceptint socket_accept(int sockfd, void *addr, int addrlen) found from rpc_accept
0xe071d99asocket_recvint socket_recv(int sockfd, void *buf, int len, int flags) found from 'rpc_recv'
0xe071da20socket_sendsocket_send(int sockfd, void *buf, int len, int flags) found from index, CommonSyncWrite
0xe071da80socket_setsockoptsocket_setsockopt(int socket, int level, int option_name, const void *option_value, int option_len) found from 'rpc_setsockopt'
0xe071db7asocket_shutdownsocket_shutdown(int sockfd, int flag) found from index, CommonSyncWrite
0xe0714a20socket_closesocket_close(int sockfd) found from index, CommonSyncWrite. needs converted fd
0xe010608esocket_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
OptionValueInfo
AF_INET 0x1Internet IP Protocol
SOCK_STREAM0x1TCP Protocol
Socket Options
OptionValueInfo
SOL_SOCKET0xffffoptions at the socket level
SO_REUSEADDR 0x2allow 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)
digic/processors/lime.txt · Last modified: 2021/03/16 12:01 by coon