lnodemcu.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. #define lnodemcu_c
  2. #define LUA_CORE
  3. #include "lua.h"
  4. #include <string.h>
  5. #include <stdlib.h>
  6. #include "lobject.h"
  7. #include "lstate.h"
  8. #include "lapi.h"
  9. #include "lauxlib.h"
  10. #include "lfunc.h"
  11. #include "lgc.h"
  12. #include "lstring.h"
  13. #include "ltable.h"
  14. #include "ltm.h"
  15. #include "lnodemcu.h"
  16. #include "lundump.h"
  17. #include "lzio.h"
  18. #ifdef LUA_USE_ESP
  19. #include "platform.h"
  20. #include "user_interface.h"
  21. #include "vfs.h"
  22. #endif
  23. /*
  24. ** This is a mixed bag of NodeMCU additions broken into the following sections:
  25. ** * POSIX vs VFS file API abstraction
  26. ** * Emulate Platform_XXX() API
  27. ** * ESP and HOST lua_debugbreak() test stubs
  28. ** * NodeMCU lua.h API extensions
  29. ** * NodeMCU LFS Table emulator
  30. ** * NodeMCU bootstrap to set up and to reimage LFS resources
  31. **
  32. ** Just search down for //== or ==// to flip through the sections.
  33. */
  34. #define byte_addr(p) cast(char *,p)
  35. #define byteptr(p) cast(lu_byte *, p)
  36. #define byteoffset(p,q) (byteptr(p) - byteptr(q))
  37. #define wordptr(p) cast(lu_int32 *, p)
  38. #define wordoffset(p,q) (wordptr(p) - wordptr(q))
  39. //== Wrap POSIX and VFS file API =============================================//
  40. #ifdef LUA_USE_ESP
  41. int luaopen_file(lua_State *L);
  42. # define l_file(f) int f
  43. # define l_open(f) vfs_open(f, "r")
  44. # define l_close(f) vfs_close(f)
  45. # define l_feof(f) vfs_eof(f)
  46. # define l_read(f,b) vfs_read(f, b, sizeof (b))
  47. # define l_rewind(f) vfs_lseek(f, 0, VFS_SEEK_SET)
  48. #else
  49. # define l_file(f) FILE *f
  50. # define l_open(n) fopen(n,"rb")
  51. # define l_close(f) fclose(f)
  52. # define l_feof(f) feof(f)
  53. # define l_read(f,b) fread(b, 1, sizeof (b), f)
  54. # define l_rewind(f) rewind(f)
  55. #endif
  56. //== Emulate Platform_XXX() API ==============================================//
  57. #ifdef LUA_USE_ESP
  58. extern void dbg_printf(const char *fmt, ...); // DEBUG
  59. #undef printf
  60. #define printf(...) dbg_printf(__VA_ARGS__) // DEBUG
  61. #define FLASH_PAGE_SIZE INTERNAL_FLASH_SECTOR_SIZE
  62. /* Erasing the LFS invalidates ESP instruction cache, so doing a block 64Kb */
  63. /* read is the simplest way to flush the icache, restoring cache coherency */
  64. #define flush_icache(F) \
  65. UNUSED(memcmp(F->addr, F->addr+(0x8000/sizeof(*F->addr)), 0x8000));
  66. #define unlockFlashWrite()
  67. #define lockFlashWrite()
  68. #else // LUA_USE_HOST
  69. #include<stdio.h> // DEBUG
  70. /*
  71. ** The ESP implementation use a platform_XXX() API to provide a level of
  72. ** H/W abstraction. The following functions and macros emulate a subset
  73. ** of this API for the host environment. LFSregion is the true address in
  74. ** the luac process address space of the mapped LFS region. All actual
  75. ** erasing and writing is done relative to this address.
  76. **
  77. ** In normal LFS emulation the LFSaddr is also set to this LFSregion address
  78. ** so that any subsequent execution using LFS refers to the correct memory
  79. ** address.
  80. **
  81. ** The second LFS mode is used to create absolute LFS images for directly
  82. ** downloading to the ESP or including in a firmware image, and in this case
  83. ** LFSaddr refers to the actual ESP mapped address of the ESP LFS region.
  84. ** This is a 32-bit address typically in the address range 0x40210000-0x402FFFFF
  85. ** (and with the high 32bits set to 0 in the case of 64-bit execution). Such
  86. ** images are solely intended for ESP execution and any attempt to execute
  87. ** them in a host execution environment will result in an address exception.
  88. */
  89. #define PLATFORM_RCR_FLASHLFS 4
  90. #define LFS_SIZE 0x40000
  91. #define FLASH_PAGE_SIZE 0x1000
  92. #define FLASH_BASE 0x90000 /* Some 'Random' but typical value */
  93. #define IROM0_SEG 0x40210000ul
  94. void *LFSregion = NULL;
  95. static void *LFSaddr = NULL;
  96. static size_t LFSbase = FLASH_BASE;
  97. extern char *LFSimageName;
  98. #ifdef __unix__
  99. /* On POSIX systems we can toggle the "Flash" write attribute */
  100. #include <sys/mman.h>
  101. #define aligned_malloc(a,n) posix_memalign(&a, FLASH_PAGE_SIZE, (n))
  102. #define unlockFlashWrite() mprotect(LFSaddr, LFS_SIZE, PROT_READ| PROT_WRITE)
  103. #define lockFlashWrite() mprotect(LFSaddr, LFS_SIZE, PROT_READ)
  104. #else
  105. #define aligned_malloc(a,n) ((a = malloc(n)) == NULL)
  106. #define unlockFlashWrite()
  107. #define lockFlashWrite()
  108. #endif
  109. #define platform_rcr_write(id,rec,l) (128)
  110. #define platform_flash_phys2mapped(n) \
  111. (byteptr(LFSaddr) + (n) - LFSbase)
  112. #define platform_flash_mapped2phys(n) \
  113. (byteoffset(n, LFSaddr) + LFSbase)
  114. #define platform_flash_get_sector_of_address(n) ((n)>>12)
  115. #define platform_rcr_delete(id) LFSimageName = NULL
  116. #define platform_rcr_read(id,s) \
  117. (*s = LFSimageName, (LFSimageName) ? strlen(LFSimageName) : ~0);
  118. void luaN_setabsolute(lu_int32 addr) {
  119. LFSaddr = cast(void *, cast(size_t, addr));
  120. LFSbase = addr - IROM0_SEG;
  121. }
  122. static lu_int32 platform_flash_get_partition (lu_int32 part_id, lu_int32 *addr) {
  123. lua_assert(part_id == NODEMCU_LFS0_PARTITION);
  124. if (!LFSregion) {
  125. if(aligned_malloc(LFSregion, LFS_SIZE))
  126. return 0;
  127. memset(LFSregion, ~0, LFS_SIZE);
  128. lockFlashWrite();
  129. }
  130. if(LFSaddr == NULL)
  131. LFSaddr = LFSregion;
  132. *addr = LFSbase;
  133. return LFS_SIZE;
  134. }
  135. static void platform_flash_erase_sector(lu_int32 i) {
  136. lua_assert (i >= LFSbase/FLASH_PAGE_SIZE &&
  137. i < (LFSbase+LFS_SIZE)/FLASH_PAGE_SIZE);
  138. unlockFlashWrite();
  139. memset(byteptr(LFSregion) + (i*FLASH_PAGE_SIZE - LFSbase), ~(0), FLASH_PAGE_SIZE);
  140. lockFlashWrite();
  141. }
  142. static void platform_s_flash_write(const void *from, lu_int32 to, lu_int32 len) {
  143. lua_assert(to >= LFSbase && to + len < LFSbase + LFS_SIZE); /* DEBUG */
  144. unlockFlashWrite();
  145. memcpy(byteptr(LFSregion) + (to-LFSbase), from, len);
  146. lockFlashWrite();
  147. }
  148. #define flush_icache(F) /* not needed */
  149. #endif
  150. //== ESP and HOST lua_debugbreak() test stubs ================================//
  151. #ifdef DEVELOPMENT_USE_GDB
  152. /*
  153. * lua_debugbreak is a stub used by lua_assert() if DEVELOPMENT_USE_GDB is
  154. * defined. On the ESP, instead of crashing out with an assert error, this hook
  155. * starts the GDB remote stub if not already running and then issues a break.
  156. * The rationale here is that when testing the developer might be using screen /
  157. * PuTTY to work interactively with the Lua Interpreter via UART0. However if
  158. * an assert triggers, then there is the option to exit the interactive session
  159. * and start the Xtensa remote GDB which will then sync up with the remote GDB
  160. * client to allow forensics of the error. On the host it is an stub which can
  161. * be set as a breakpoint in the gdb debugger.
  162. */
  163. extern void gdbstub_init(void);
  164. extern void gdbstub_redirect_output(int);
  165. LUALIB_API void lua_debugbreak(void) {
  166. #ifdef LUA_USE_HOST
  167. /* allows debug backtrace analysis of assert fails */
  168. lua_writestring(" lua_debugbreak ", sizeof(" lua_debugbreak ")-1);
  169. #else
  170. static int repeat_entry = 0;
  171. if (repeat_entry == 0) {
  172. dbg_printf("Start up the gdb stub if not already started\n");
  173. gdbstub_init();
  174. gdbstub_redirect_output(1);
  175. repeat_entry = 1;
  176. }
  177. asm("break 0,0" ::);
  178. #endif
  179. }
  180. #endif
  181. //== NodeMCU lua.h API extensions ============================================//
  182. LUA_API int lua_freeheap (void) {
  183. #ifdef LUA_USE_HOST
  184. return MAX_INT;
  185. #else
  186. return (int) platform_freeheap();
  187. #endif
  188. }
  189. LUA_API int lua_getstrings(lua_State *L, int opt) {
  190. stringtable *tb = NULL;
  191. Table *t;
  192. int i, j, n = 0;
  193. if (n == 0)
  194. tb = &G(L)->strt;
  195. #ifdef LUA_USE_ESP
  196. else if (n == 1 && G(L)->ROstrt.hash)
  197. tb = &G(L)->ROstrt;
  198. #endif
  199. if (tb == NULL)
  200. return 0;
  201. lua_lock(L);
  202. t = luaH_new(L);
  203. sethvalue(L, L->top, t);
  204. api_incr_top(L);
  205. luaH_resize(L, t, tb->nuse, 0);
  206. luaC_checkGC(L);
  207. lua_unlock(L);
  208. for (i = 0, j = 1; i < tb->size; i++) {
  209. TString *o;
  210. for(o = tb->hash[i]; o; o = o->u.hnext) {
  211. TValue s;
  212. setsvalue(L, &s, o);
  213. luaH_setint(L, hvalue(L->top-1), j++, &s); /* table[n] = true */
  214. }
  215. }
  216. return 1;
  217. }
  218. LUA_API void lua_createrotable (lua_State *L, ROTable *t,
  219. const ROTable_entry *e, ROTable *mt) {
  220. int i, j;
  221. lu_byte flags = ~0;
  222. const char *plast = (char *)"_";
  223. for (i = 0; e[i].key; i++) {
  224. if (e[i].key[0] == '_' && strcmp(e[i].key,plast)) {
  225. plast = e[i].key;
  226. lua_pushstring(L,e[i].key);
  227. for (j=0; j<TM_EQ; j++){
  228. if(tsvalue(L->top-1)==G(L)->tmname[i]) {
  229. flags |= cast_byte(1u<<i);
  230. break;
  231. }
  232. }
  233. lua_pop(L,1);
  234. }
  235. }
  236. t->next = (GCObject *)1;
  237. t->tt = LUA_TTBLROF;
  238. t->marked = LROT_MARKED;
  239. t->flags = flags;
  240. t->lsizenode = i;
  241. t->metatable = cast(Table *, mt);
  242. t->entry = cast(ROTable_entry *, e);
  243. }
  244. //== NodeMCU LFS Table emulator ==============================================//
  245. static int lfs_func (lua_State* L);
  246. LROT_BEGIN(LFS_meta, NULL, LROT_MASK_INDEX)
  247. LROT_FUNCENTRY( __index, lfs_func)
  248. LROT_END(LFS_meta, NULL, LROT_MASK_INDEX)
  249. LROT_BEGIN(LFS, LROT_TABLEREF(LFS_meta), 0)
  250. LROT_END(LFS, LROT_TABLEREF(LFS_meta), 0)
  251. static int lfs_func (lua_State* L) { /*T[1] = LFS, T[2] = fieldname */
  252. const char *name = lua_tostring(L, 2);
  253. LFSHeader *fh = G(L)->l_LFS;
  254. Proto *f;
  255. LClosure *cl;
  256. lua_settop(L,2);
  257. if (!fh) { /* return nil if LFS not loaded */
  258. lua_pushnil(L);
  259. return 1;
  260. }
  261. if (!strcmp(name, "_config")) {
  262. size_t ba = cast(size_t, fh);
  263. lua_createtable(L, 0, 3);
  264. lua_pushinteger(L, cast(lua_Integer, ba));
  265. lua_setfield(L, -2, "lfs_mapped");
  266. lua_pushinteger(L, cast(lua_Integer, platform_flash_mapped2phys(ba)));
  267. lua_setfield(L, -2, "lfs_base");
  268. lua_pushinteger(L, G(L)->LFSsize);
  269. lua_setfield(L, -2, "lfs_size");
  270. return 1;
  271. } else if (!strcmp(name, "_list")) {
  272. int i = 1;
  273. setobjs2s(L, L->top-2, &G(L)->LFStable); /* overwrite T[1] with LSFtable */
  274. lua_newtable(L); /* new list table at T[3] */
  275. lua_pushnil(L); /* first key (nil) at T4] */
  276. while (lua_next(L, 1) != 0) { /* loop over LSFtable k,v at T[4:5] */
  277. lua_pop(L, 1); /* dump value */
  278. lua_pushvalue(L, -1); /* dup key */
  279. lua_rawseti(L, 3, i++); /* table[i]=key */
  280. }
  281. return 1;
  282. } else if (!strcmp(name, "_time")) {
  283. lua_pushinteger(L, fh->timestamp);
  284. return 1;
  285. }
  286. setobjs2s(L, L->top-2, &G(L)->LFStable); /* overwrite T[1] with LSFtable */
  287. if (lua_rawget(L,1) != LUA_TNIL) { /* get LFStable[name] */
  288. lua_pushglobaltable(L);
  289. f = cast(Proto *, lua_topointer(L,-2));
  290. lua_lock(L);
  291. cl = luaF_newLclosure(L, f->sizeupvalues);
  292. setclLvalue(L, L->top-2, cl); /* overwrite f addr slot with closure */
  293. cl->p = f; /* bind f to it */
  294. if (cl->nupvalues >= 1) { /* does it have at least one upvalue? */
  295. luaF_initupvals(L, cl ); /* initialise upvals */
  296. setobj(L, cl->upvals[0]->v, L->top-1); /* set UV[1] to _ENV */
  297. }
  298. lua_unlock(L);
  299. lua_pop(L,1); /* pop _ENV leaving closure at ToS */
  300. }
  301. return 1;
  302. }
  303. //== NodeMCU bootstrap to set up and to reimage LFS resources ================//
  304. /*
  305. ** This processing uses 2 init hooks during the Lua startup. The first is
  306. ** called early in the Lua state setup to initialize the LFS if present. The
  307. ** second is only used to rebuild the LFS region; this requires the Lua
  308. ** environment to be in place, so this second hook is immediately before
  309. ** processing LUA_INIT.
  310. **
  311. ** An application library initiates an LFS rebuild by writing a FLASHLFS
  312. ** message to the Reboot Config Record area (RCR), and then restarting the
  313. ** processor. This RCR record is read during startup by the 2nd hook. The
  314. ** content is the name of the Lua LFS image file to be loaded. If present then
  315. ** the LFS reload process is initiated instead of LUA_INIT. This uses lundump
  316. ** functions to load the components directly into the LFS region.
  317. **
  318. ** FlashState used to share context with the low level lua_load write routines
  319. ** is passed as a ZIO data field. Note this is only within the phase
  320. ** processing and not across phases.
  321. */
  322. typedef struct LFSflashState {
  323. lua_State *L;
  324. LFSHeader hdr;
  325. l_file(f);
  326. const char *LFSfileName;
  327. lu_int32 *addr;
  328. lu_int32 oNdx; /* in size_t units */
  329. lu_int32 oChunkNdx; /* in size_t units */
  330. lu_int32 *oBuff; /* FLASH_PAGE_SIZE bytes */
  331. lu_byte *inBuff; /* FLASH_PAGE_SIZE bytes */
  332. lu_int32 inNdx; /* in bytes */
  333. lu_int32 addrPhys;
  334. lu_int32 size;
  335. lu_int32 allocmask;
  336. stringtable ROstrt;
  337. GCObject *pLTShead;
  338. } LFSflashState;
  339. #define WORDSIZE sizeof(lu_int32)
  340. #define OSIZE (FLASH_PAGE_SIZE/WORDSIZE)
  341. #define ISIZE (FLASH_PAGE_SIZE)
  342. #ifdef LUA_USE_ESP
  343. #define ALIGN(F,n) (n + WORDSIZE - 1) / WORDSIZE;
  344. #else
  345. #define ALIGN(F,n) ((n + F->allocmask) & ~(F->allocmask)) / WORDSIZE;
  346. #endif
  347. /* This conforms to the ZIO lua_Reader spec, hence the L parameter */
  348. static const char *readF (lua_State *L, void *ud, size_t *size) {
  349. UNUSED(L);
  350. LFSflashState *F = cast(LFSflashState *, ud);
  351. if (F->inNdx > 0) {
  352. *size = F->inNdx;
  353. F->inNdx = 0;
  354. } else {
  355. if (l_feof(F->f)) return NULL;
  356. *size = l_read(F->f, F->inBuff) ; /* read block */
  357. }
  358. return cast(const char *,F->inBuff);
  359. }
  360. static void eraseLFS(LFSflashState *F) {
  361. lu_int32 i;
  362. printf("\nErasing LFS from flash addr 0x%06x", F->addrPhys);
  363. unlockFlashWrite();
  364. for (i = 0; i < F->size; i += FLASH_PAGE_SIZE) {
  365. size_t *f = cast(size_t *, F->addr + i/sizeof(*f));
  366. lu_int32 s = platform_flash_get_sector_of_address(F->addrPhys + i);
  367. /* it is far faster not erasing if you don't need to */
  368. #ifdef LUA_USE_ESP
  369. if (*f == ~0 && !memcmp(f, f + 1, FLASH_PAGE_SIZE - sizeof(*f)))
  370. continue;
  371. #endif
  372. platform_flash_erase_sector(s);
  373. printf(".");
  374. }
  375. printf(" to 0x%06x\n", F->addrPhys + F->size-1);
  376. flush_icache(F);
  377. lockFlashWrite();
  378. }
  379. LUAI_FUNC void luaN_setFlash(void *F, unsigned int o) {
  380. luaN_flushFlash(F); /* flush the pending write buffer */
  381. lua_assert((o & (WORDSIZE-1))==0);
  382. cast(LFSflashState *,F)->oChunkNdx = o/WORDSIZE;
  383. }
  384. LUAI_FUNC void luaN_flushFlash(void *vF) {
  385. LFSflashState *F = cast(LFSflashState *, vF);
  386. lu_int32 start = F->addrPhys + F->oChunkNdx*WORDSIZE;
  387. lu_int32 size = F->oNdx * WORDSIZE;
  388. lua_assert(start + size < F->addrPhys + F->size); /* is write in bounds? */
  389. //printf("Flush Buf: %6x (%u)\n", F->oNdx, size); //DEBUG
  390. platform_s_flash_write(F->oBuff, start, size);
  391. F->oChunkNdx += F->oNdx;
  392. F->oNdx = 0;
  393. }
  394. LUAI_FUNC void *luaN_writeFlash(void *vF, const void *rec, size_t n) {
  395. LFSflashState *F = cast(LFSflashState *, vF);
  396. lu_byte *p = byteptr(F->addr + F->oChunkNdx + F->oNdx);
  397. //int i; printf("writing %4u bytes:", (lu_int32) n); for (i=0;i<n;i++){printf(" %02x", byteptr(rec)[i]);} printf("\n");
  398. if (n==0)
  399. return p;
  400. while (1) {
  401. int nw = ALIGN(F, n);
  402. if (F->oNdx + nw > OSIZE) {
  403. /* record overflows the buffer so fill buffer, flush and repeat */
  404. int rem = OSIZE - F->oNdx;
  405. if (rem)
  406. memcpy(F->oBuff+F->oNdx, rec, rem * WORDSIZE);
  407. rec = cast(void *, cast(lu_int32 *, rec) + rem);
  408. n -= rem * WORDSIZE;
  409. F->oNdx = OSIZE;
  410. luaN_flushFlash(F);
  411. } else {
  412. /* append remaining record to buffer */
  413. F->oBuff[F->oNdx+nw-1] = 0; /* ensure any trailing odd byte are 0 */
  414. memcpy(F->oBuff+F->oNdx, rec, n);
  415. F->oNdx += nw;
  416. break;
  417. }
  418. }
  419. //int i; for (i=0;i<(rem * WORDSIZE); i++) {printf("%c%02x",i?' ':'.',*((lu_byte*)rec+i));}
  420. //for (i=0;i<n; i++) printf("%c%02x",i?' ':'.',*((lu_byte*)rec+i));
  421. //printf("\n");
  422. return p;
  423. }
  424. /*
  425. ** Hook used in Lua Startup to carry out the optional LFS startup processes.
  426. */
  427. LUAI_FUNC int luaN_init (lua_State *L) {
  428. static LFSflashState *F = NULL;
  429. int n;
  430. static LFSHeader *fh;
  431. /*
  432. * The first entry is called from lstate.c:f_luaopen() before modules
  433. * are initialised. This is detected because F is NULL on first entry.
  434. */
  435. if (F == NULL) {
  436. size_t Fsize = sizeof(LFSflashState) + OSIZE*WORDSIZE + ISIZE;
  437. /* outlining the buffers just makes debugging easier. Sorry */
  438. F = calloc(Fsize, 1);
  439. F->oBuff = wordptr(F + 1);
  440. F->inBuff = byteptr(F->oBuff + OSIZE);
  441. n = platform_rcr_read(PLATFORM_RCR_FLASHLFS, cast(void**, &F->LFSfileName));
  442. F->size = platform_flash_get_partition (NODEMCU_LFS0_PARTITION, &F->addrPhys);
  443. if (F->size) {
  444. F->addr = cast(lu_int32 *, platform_flash_phys2mapped(F->addrPhys));
  445. fh = cast(LFSHeader *, F->addr);
  446. if (n < 0) {
  447. global_State *g = G(L);
  448. g->LFSsize = F->size;
  449. /* Set up LFS hooks on normal Entry */
  450. if (fh->flash_sig == FLASH_SIG) {
  451. g->l_LFS = fh;
  452. g->seed = fh->seed;
  453. g->ROstrt.hash = cast(TString **, F->addr + fh->oROhash);
  454. g->ROstrt.nuse = fh->nROuse ;
  455. g->ROstrt.size = fh->nROsize;
  456. sethvalue(L, &g->LFStable, cast(Table *, F->addr + fh->protoROTable));
  457. lua_writestringerror("LFS image %s\n", "loaded");
  458. } else if ((fh->flash_sig != 0 && fh->flash_sig != ~0)) {
  459. lua_writestringerror("LFS image %s\n", "corrupted.");
  460. eraseLFS(F);
  461. }
  462. }
  463. }
  464. return 0;
  465. } else { /* hook 2 called from protected pmain, so can throw errors. */
  466. int status = 0;
  467. if (F->LFSfileName) { /* hook == 2 LFS image load */
  468. ZIO z;
  469. /*
  470. * To avoid reboot loops, the load is only attempted once, so we
  471. * always deleted the RCR record if we enter this path. Also note
  472. * that this load process can throw errors and if so these are
  473. * caught by the parent function in lua.c
  474. */
  475. #ifdef DEVELOPMENT_USE_GDB
  476. /* For GDB builds, prefixing the filename with ! forces a break in the hook */
  477. if (F->LFSfileName[0] == '!') {
  478. lua_debugbreak();
  479. F->LFSfileName++;
  480. }
  481. #endif
  482. platform_rcr_delete(PLATFORM_RCR_FLASHLFS);
  483. #ifdef LUA_USE_ESP
  484. luaopen_file(L);
  485. #endif
  486. if (!(F->f = l_open(F->LFSfileName))) {
  487. free(F);
  488. return luaL_error(L, "cannot open %s", F->LFSfileName);
  489. }
  490. eraseLFS(F);
  491. luaZ_init(L, &z, readF, F);
  492. lua_lock(L);
  493. #ifdef LUA_USE_HOST
  494. F->allocmask = (LFSaddr == LFSregion) ? sizeof(size_t) - 1 :
  495. sizeof(lu_int32) - 1;
  496. status = luaU_undumpLFS(L, &z, LFSaddr != LFSregion);
  497. #else
  498. status = luaU_undumpLFS(L, &z, 0);
  499. #endif
  500. lua_unlock(L);
  501. l_close(F->f);
  502. free(F);
  503. F = NULL;
  504. if (status == LUA_OK)
  505. lua_pushstring(L, "!LFSrestart!"); /* Signal a restart */
  506. lua_error(L); /* throw error / restart request */
  507. } else { /* hook == 2, Normal startup */
  508. free(F);
  509. F = NULL;
  510. }
  511. return status;
  512. }
  513. }
  514. // =============================================================================
  515. #define getfield(L,t,f) \
  516. lua_getglobal(L, #t); luaL_getmetafield( L, 1, #f ); lua_remove(L, -2);
  517. LUAI_FUNC int lua_lfsreload (lua_State *L) {
  518. int n = 0;
  519. #ifdef LUA_USE_ESP
  520. size_t l;
  521. int off = 0;
  522. const char *img = lua_tolstring(L, 1, &l);
  523. #ifdef DEVELOPMENT_USE_GDB
  524. if (*img == '!') /* For GDB builds, any leading ! is ignored for checking */
  525. off = 1; /* existence. This forces a debug break in the init hook */
  526. #endif
  527. lua_settop(L, 1);
  528. lua_getglobal(L, "file");
  529. if (lua_isnil(L, 2)) {
  530. lua_pushstring(L, "No file system mounted");
  531. return 1;
  532. }
  533. lua_getfield(L, 2, "exists");
  534. lua_pushstring(L, img + off);
  535. lua_call(L, 1, 1);
  536. if (G(L)->LFSsize == 0 || lua_toboolean(L, -1) == 0) {
  537. lua_pushstring(L, "No LFS partition allocated");
  538. return 1;
  539. }
  540. n = platform_rcr_write(PLATFORM_RCR_FLASHLFS, img, l+1);/* incl trailing \0 */
  541. if (n>0)
  542. system_restart();
  543. #endif
  544. lua_pushboolean(L, n>0);
  545. return 1;
  546. }
  547. LUAI_FUNC int lua_lfsindex (lua_State *L) {
  548. lua_settop(L,1);
  549. if (lua_isstring(L, 1)){
  550. lua_getglobal(L, "LFS");
  551. lua_getfield(L, 2, lua_tostring(L,1));
  552. } else {
  553. lua_pushnil(L);
  554. }
  555. return 1;
  556. }