diff --git a/examples/lua/main.c b/examples/lua/main.c deleted file mode 100644 index 22458153e0..0000000000 --- a/examples/lua/main.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2018 FU Berlin - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License v2.1. See the file LICENSE in the top level - * directory for more details. - */ - -/** - * @ingroup examples - * @{ - * - * @file - * @brief Basic lua example application - * - * @author Daniel Petry - * - * @} - */ - -#include -#include -#include "lauxlib.h" -#include "lualib.h" - -#include "main.lua.h" - -int lua_run_script(const char *buffer, size_t buffer_len) -{ - - lua_State *L = luaL_newstate(); - - if (L == NULL) { - puts("cannot create state: not enough memory"); - return ENOMEM; - } - - luaL_openlibs(L); - luaL_loadbuffer(L, buffer, buffer_len, "lua input script"); - - if (lua_pcall(L, 0, 0, 0) != LUA_OK){ - puts("Lua script running failed"); - return EINTR; - } - - lua_close(L); - return 0; -} - -int main(void) -{ - puts("Lua RIOT build"); - lua_run_script(main_lua, main_lua_len); - return 0; -} diff --git a/examples/lua/Makefile b/examples/lua_basic/Makefile similarity index 93% rename from examples/lua/Makefile rename to examples/lua_basic/Makefile index 57c5c89fd3..91a55145f5 100644 --- a/examples/lua/Makefile +++ b/examples/lua_basic/Makefile @@ -1,4 +1,4 @@ -APPLICATION = lua +APPLICATION = lua_basic # If no BOARD is found in the environment, use this default: BOARD ?= native @@ -29,12 +29,10 @@ DEVELHELP ?= 1 # Change this to 0 show compiler invocation lines by default: QUIET ?= 1 -USEMODULE += ps - ifneq ($(BOARD),native) # This stack size is large enough to run Lua print() functions of # various lengths. Other functions untested. - CFLAGS += -DTHREAD_STACKSIZE_MAIN=4096 + CFLAGS += -DTHREAD_STACKSIZE_MAIN='(THREAD_STACKSIZE_DEFAULT+2048)' endif USEPKG += lua @@ -61,6 +59,6 @@ $(LUA_PATH)/: $(LUA_H): | $(LUA_PATH)/ $(LUA_H): $(LUA_PATH)/%.lua.h: %.lua - xxd -i $< | sed 's/^unsigned/const/g' > $@ + xxd -i $< | sed 's/^unsigned/const unsigned/g' > $@ $(RIOTBUILD_CONFIG_HEADER_C): $(LUA_H) diff --git a/examples/lua/README.md b/examples/lua_basic/README.md similarity index 100% rename from examples/lua/README.md rename to examples/lua_basic/README.md diff --git a/examples/lua_basic/main.c b/examples/lua_basic/main.c new file mode 100644 index 0000000000..0763ab4dae --- /dev/null +++ b/examples/lua_basic/main.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2018 FU Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup examples + * @{ + * + * @file + * @brief Basic lua example application + * + * @author Daniel Petry + * + * @} + */ + +#include +#include + +#include "lauxlib.h" +#include "lualib.h" +#include "lua_run.h" + +#include "main.lua.h" + +#define LUA_MEM_SIZE (11000) +static char lua_mem[LUA_MEM_SIZE] __attribute__ ((aligned(__BIGGEST_ALIGNMENT__))); + +int lua_run_script(const uint8_t *buffer, size_t buffer_len) +{ + lua_State *L = lua_riot_newstate(lua_mem, sizeof(lua_mem), NULL); + + if (L == NULL) { + puts("cannot create state: not enough memory"); + return ENOMEM; + } + + lua_riot_openlibs(L, LUAR_LOAD_BASE); + luaL_loadbuffer(L, (const char *)buffer, buffer_len, "lua input script"); + + if (lua_pcall(L, 0, 0, 0) != LUA_OK) { + puts("Lua script running failed"); + return EINTR; + } + + lua_close(L); + return 0; +} + +int main(void) +{ + puts("Lua RIOT build"); + lua_run_script(main_lua, main_lua_len); + puts("Lua interpreter exited"); + + return 0; +} diff --git a/examples/lua/main.lua b/examples/lua_basic/main.lua similarity index 100% rename from examples/lua/main.lua rename to examples/lua_basic/main.lua diff --git a/pkg/lua/Makefile b/pkg/lua/Makefile index d2f1a775de..69170baa95 100644 --- a/pkg/lua/Makefile +++ b/pkg/lua/Makefile @@ -1,11 +1,12 @@ PKG_NAME=lua PKG_URL=https://github.com/lua/lua.git +# tag: v5-3-4 PKG_VERSION=e354c6355e7f48e087678ec49e340ca0696725b1 PKG_LICENSE=MIT .PHONY: all -all: +all: Makefile.lua @cp Makefile.lua $(PKG_BUILDDIR) "$(MAKE)" -C $(PKG_BUILDDIR) -f Makefile.lua diff --git a/pkg/lua/Makefile.dep b/pkg/lua/Makefile.dep new file mode 100644 index 0000000000..2079d072aa --- /dev/null +++ b/pkg/lua/Makefile.dep @@ -0,0 +1,3 @@ +USEPKG += tlsf +USEMODULE += lua-contrib +USEMODULE += printf_float diff --git a/pkg/lua/Makefile.include b/pkg/lua/Makefile.include index 9fb515a3b4..ab9d3759b2 100644 --- a/pkg/lua/Makefile.include +++ b/pkg/lua/Makefile.include @@ -1 +1,3 @@ INCLUDES += -I$(PKGDIRBASE)/lua +INCLUDES += -I$(RIOTPKG)/lua/include +DIRS += $(RIOTPKG)/lua/contrib diff --git a/pkg/lua/Makefile.lua b/pkg/lua/Makefile.lua index f0bd4d8a38..b22984b2a1 100644 --- a/pkg/lua/Makefile.lua +++ b/pkg/lua/Makefile.lua @@ -1,9 +1,9 @@ -SRC := $(filter-out lua.c luac.c,$(wildcard *.c)) +SRC := $(filter-out loadlib.c lua.c luac.c,$(wildcard *.c)) -# This builds for native using POSIX system calls and some extra libraries, and -# removes a compiler warning that warns against using tmpnam(). -ifeq ($(BOARD),native) - CFLAGS += -DLUA_USE_LINUX -endif +CFLAGS += -fstack-usage -fconserve-stack \ + -DLUA_MAXCAPTURES=16 \ + -DL_MAXLENNUM=50 +# Enable these options to debug stack usage +# -Wstack-usage=128 -Wno-error=stack-usage=128 include $(RIOTBASE)/Makefile.base diff --git a/pkg/lua/contrib/Makefile b/pkg/lua/contrib/Makefile new file mode 100644 index 0000000000..50d6799441 --- /dev/null +++ b/pkg/lua/contrib/Makefile @@ -0,0 +1,3 @@ +MODULE = lua-contrib + +include $(RIOTBASE)/Makefile.base diff --git a/pkg/lua/contrib/binsearch.c b/pkg/lua/contrib/binsearch.c new file mode 100644 index 0000000000..2aa7f96264 --- /dev/null +++ b/pkg/lua/contrib/binsearch.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @file + * + * @brief Generic binary search for tables containing strings. + * @author Juan Carrano + * + */ + +#include + +#include "binsearch.h" + +int binsearch_str(const void *start, size_t offset, size_t stride, size_t nmemb, + const char *str, size_t n) +{ + const uint8_t *cstart = (((const uint8_t *)start) + offset); + size_t lo = 0, hi = nmemb; + + while (lo < hi) { + size_t mid = (lo + hi) / 2; + const char *target = *((const char *const *)(cstart + mid * stride)); + int cmp = strncmp(str, target, n); + + if (cmp == 0) { + return mid; + } + else if (cmp < 0) { + hi = mid; + } + else { /* (cmp > 0) */ + lo = mid + 1; + } + } + return (-ENOENT); +} + +const void *binsearch_str_p(const void *start, size_t offset, size_t stride, + size_t nmemb, const char *str, size_t n) +{ + int ix = binsearch_str(start, offset, stride, nmemb, str, n); + + return (ix == (-ENOENT)) ? NULL : (const uint8_t *)start + ix * stride; +} diff --git a/pkg/lua/contrib/binsearch.h b/pkg/lua/contrib/binsearch.h new file mode 100644 index 0000000000..9be7ca3db4 --- /dev/null +++ b/pkg/lua/contrib/binsearch.h @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2018 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @internal + * @{ + * @file + * + * @brief Generic binary search for tables containing strings. + * @author Juan Carrano + * + * It is often the case that one has an array of structs, where one of the + * members of the struct is a string pointer containing a key that must be + * searched. If the array is sorted by this key and of known length, a binary + * search can be performed. + * + * To make the code generic we must reinterpret the structure array + * as an array of pointers to string with a stride (separation in bytes between + * elements) and offset (position of the first element relative to the start of + * the array) given by the struct definition. + * + * For example, given the following struct and array definitions and assuming + * a 32 bit platform with strict aligment: + * struct s1 { + * int a; // Takes up 4 bytes + * char *name; // Takes up 4 bytes + * char m; // Takes up 1 byte + * }; + * struct s1 my_table[] = {......}; + * + * Then each element of my_table will be aligned to 12 bytes. The address of the + * "name" field of the first elements will be 4 bytes more than the address of + * "my_table". With this two numbers we can compute the address of the i-th + * "name" field as: + * [address of my_table] + offset + i*stride + * Where stride=12 bytes and offset = 4 bytes. + */ + +#ifndef BINSEARCH_H +#define BINSEARCH_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Produce a compiler error if x is not an lvalue. + */ +#define _ENSURE_LVALUE(x) ((void)sizeof(&(x))) + +/** + * UNSAFE MACRO: Difference in bytes between the addresses of two consecutive + * array elements. + */ +#define _ARRAY_STRIDE(arr) ((size_t)((uint8_t *)((arr) + 1) - (uint8_t *)(arr))) + +/** + * UNSAFE MACRO: Offset in bytes from the start of the array to member "member" + * of the first element. + */ +#define _ARRAY_MEMBER_OFFS(arr, member) \ + ((size_t)((uint8_t *)(&((arr)->member)) - (uint8_t *)(arr))) + +/** + * Find the index of the array element that contains "str" in + * member "member". + * + * A compile-time error will be raised if arr is not an lvalue. This ensures the + * macro is safe. + * + * @return Index of the array element containing the string. + * @return (-ENOENT) if it is not found. + */ +#define BINSEARCH_STR(arr, nmemb, member, str, n) \ + (_ENSURE_LVALUE(arr), \ + (binsearch_str((arr), _ARRAY_MEMBER_OFFS(arr, member), _ARRAY_STRIDE(arr), \ + (nmemb), (str), (n))) \ + ) + +/** + * Find a pointer of the array element that contains "str" in + * member "member". + * + * @return Address of the element containing the string (as a void pointer). + * @return Null if it is not found. + */ +#define BINSEARCH_STR_P(arr, nmemb, member, str, n) \ + (_ENSURE_LVALUE(arr), \ + (binsearch_str_p((arr), _ARRAY_MEMBER_OFFS(arr, member), _ARRAY_STRIDE(arr), \ + (nmemb), (str), (n))) \ + ) + +/** + * Search for an array element containing a string. + * + * This does NOT check for NULL pointers, though start can be NULL of the size + * (nmemb) is zero. + * + * @param start Pointer to start of array. The array must be ordered + * according to the search string. + * @param offset Offset of member containing string within structure. This + * can be determined using offsetof. + * @param stride Difference in bytes between the addresses of two consecutive + * array elements. + * @param nmemb Number of elements in the array. + * @param str String that will be compared against. + * @param n Compare up to n characters (see strncmp()) + * + * @return Index of the array element containing the string. + * @return (-ENOENT) if it is not found. + */ +int binsearch_str(const void *start, size_t offset, size_t stride, size_t nmemb, + const char *str, size_t n); + +/** + * Like binsearch_str but returns the pointer to the element. + * + * @return Address of the element containing the string. + * @return Null if it is not found. + */ +const void *binsearch_str_p(const void *start, size_t offset, size_t stride, + size_t nmemb, const char *str, size_t n); + + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif /* BINSEARCH_H */ diff --git a/pkg/lua/contrib/lua_loadlib.c b/pkg/lua/contrib/lua_loadlib.c new file mode 100644 index 0000000000..cedc2d1938 --- /dev/null +++ b/pkg/lua/contrib/lua_loadlib.c @@ -0,0 +1,263 @@ +/* + * Copyright (C) 1994-2017 Lua.org, PUC-Rio. + * Copyright (C) 2018 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ +/** + * @ingroup pkg_lua + * @{ + * @file + * + * @brief Replacement for the lua "package" module. + * @author Juan Carrano + * @author Roberto Ierusalimschy + * + * This file replaces the loadlib.c that comes with lua. It removes support + * for files (both lua files and c shared objects) and dynamic loading since + * none of these are present in RIOT. + * + * Instead, modules are searched in statically defined tables. In the case + * of C modules, the table contains pointers to C functions that act as module + * loaders. For pure Lua modules, the source code must be given as a string + * embedded in the application binary. + * + */ + +#define loadlib_c +#define LUA_LIB + +#include "lprefix.h" + +#include "lua.h" +#include "lauxlib.h" +#include "lualib.h" + +#include "binsearch.h" + +#include "lua_builtin.h" +#include "lua_loadlib.h" + +/* ======================== 'searchers' functions =========================== */ + +static int _ll_searcher_builtin_lua(lua_State *L, const char *name) +{ + const struct lua_riot_builtin_lua *lmodule = + BINSEARCH_STR_P(lua_riot_builtin_lua_table, + lua_riot_builtin_lua_table_len, + name, name, LUAR_MAX_MODULE_NAME); + + if (lmodule != NULL) { + int load_result = luaL_loadbuffer(L, (const char *)lmodule->code, + lmodule->code_size, + lmodule->name); + if (load_result == LUA_OK) { + lua_pushstring(L, name); /* will be 2nd argument to module */ + } + + return load_result; + } + else { + return LUAR_MODULE_NOTFOUND; + } +} + +/** + * Search in the list of pure lua modules. + * + * If the module is found, the source code is compiled and the compiled chunk + * is placed on the lua stack, followed by the module name (as a string). + */ +static int searcher_builtin_lua(lua_State *L) +{ + const char *name = luaL_checkstring(L, 1); + int load_result = _ll_searcher_builtin_lua(L, name); + + switch (load_result) { + case LUA_OK: + return 2; /* there are two elements in the stack */ + case LUAR_MODULE_NOTFOUND: + return luaL_error(L, "Module '%s' not found in Lua-builtins", + lua_tostring(L, 1)); + default: + return luaL_error(L, "error loading module '%s' from Lua-builtins: \n%s", + lua_tostring(L, 1), lua_tostring(L, 2)); + } +} + +static int _ll_searcher_builtin_c(lua_State *L, const char *name) +{ + const struct lua_riot_builtin_c *cmodule = + BINSEARCH_STR_P(lua_riot_builtin_c_table, + lua_riot_builtin_c_table_len, + name, name, LUAR_MAX_MODULE_NAME); + + if (cmodule != NULL) { + lua_pushcfunction(L, cmodule->luaopen); + lua_pushstring(L, name); /* will be 2nd argument to module */ + return LUA_OK; + } + else { + return LUAR_MODULE_NOTFOUND; + } +} + +/** + * Search in the list of C lua modules. + * + * If the module is found, the loader function is loaded with lua_pushcfunction + * and is returned. + */ +static int searcher_builtin_c(lua_State *L) +{ + const char *name = luaL_checkstring(L, 1); + int load_result = _ll_searcher_builtin_c(L, name); + + if (load_result == LUA_OK) { + return 2; + } + else { + return luaL_error(L, "Module '%s' not found in C-builtins", + lua_tostring(L, 1)); + } +} + +int lua_riot_getloader(lua_State *L, const char *name) +{ + int load_result; + + load_result = _ll_searcher_builtin_lua(L, name); + + if (load_result == LUAR_MODULE_NOTFOUND) { + load_result = _ll_searcher_builtin_c(L, name); + } + + return load_result; +} + +/* ======================== 'require' function ============================= */ + +static int searcher_preload(lua_State *L) +{ + const char *name = luaL_checkstring(L, 1); + + lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); + if (lua_getfield(L, -1, name) == LUA_TNIL) { /* not found? */ + lua_pushfstring(L, "\n\tno field package.preload['%s']", name); + } + return 1; +} + +static void findloader(lua_State *L, const char *name) +{ + int i; + luaL_Buffer msg; /* to build error message */ + + luaL_buffinit(L, &msg); + /* push 'package.searchers' to index 3 in the stack */ + if (lua_getfield(L, lua_upvalueindex(1), "searchers") != LUA_TTABLE) { + luaL_error(L, "'package.searchers' must be a table"); + } + /* iterate over available searchers to find a loader */ + for (i = 1;; i++) { + if (lua_rawgeti(L, 3, i) == LUA_TNIL) { /* no more searchers? */ + lua_pop(L, 1); /* remove nil */ + luaL_pushresult(&msg); /* create error message */ + luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1)); + } + lua_pushstring(L, name); + lua_call(L, 1, 2); /* call it */ + if (lua_isfunction(L, -2)) { /* did it find a loader? */ + return; /* module loader found */ + } + else if (lua_isstring(L, -2)) { /* searcher returned error message? */ + lua_pop(L, 1); /* remove extra return */ + luaL_addvalue(&msg); /* concatenate error message */ + } + else { + lua_pop(L, 2); /* remove both returns */ + } + } +} + +static int ll_require(lua_State *L) +{ + const char *name = luaL_checkstring(L, 1); + + lua_settop(L, 1); /* LOADED table will be at index 2 */ + lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + lua_getfield(L, 2, name); /* LOADED[name] */ + if (lua_toboolean(L, -1)) { /* is it there? */ + return 1; /* package is already loaded */ + } + /* else must load package */ + lua_pop(L, 1); /* remove 'getfield' result */ + findloader(L, name); + lua_pushstring(L, name); /* pass name as argument to module loader */ + lua_insert(L, -2); /* name is 1st argument (before search data) */ + lua_call(L, 2, 1); /* run loader to load module */ + if (!lua_isnil(L, -1)) { /* non-nil return? */ + lua_setfield(L, 2, name); /* LOADED[name] = returned value */ + } + if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */ + lua_pushboolean(L, 1); /* use true as result */ + lua_pushvalue(L, -1); /* extra copy to be returned */ + lua_setfield(L, 2, name); /* LOADED[name] = true */ + } + return 1; +} + +/* ====================== 'package' module loader =========================== */ + +static const luaL_Reg pk_funcs[] = { + /* placeholders */ + { "preload", NULL }, + { "searchers", NULL }, + { "loaded", NULL }, + { NULL, NULL } +}; + + +static const luaL_Reg ll_funcs[] = { + { "require", ll_require }, + { NULL, NULL } +}; + +LUAMOD_API int luaopen_package(lua_State *L) +{ + static const lua_CFunction searchers[] = + { searcher_preload, searcher_builtin_lua, searcher_builtin_c, NULL }; + int i; + + luaL_newlib(L, pk_funcs); /* create 'package' table */ + + /* create 'searchers' table */ + lua_createtable(L, sizeof(searchers) / sizeof(searchers[0]) - 1, 0); + /* fill it with predefined searchers */ + for (i = 0; searchers[i] != NULL; i++) { + lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */ + lua_pushcclosure(L, searchers[i], 1); + lua_rawseti(L, -2, i + 1); + } + + lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */ + + /* set field 'loaded' */ + luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + lua_setfield(L, -2, "loaded"); + + /* set field 'preload' */ + luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); + lua_setfield(L, -2, "preload"); + + + lua_pushglobaltable(L); + lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */ + luaL_setfuncs(L, ll_funcs, 1); /* open lib into global table */ + lua_pop(L, 1); /* pop global table */ + return 1; /* return 'package' table */ +} + +/** @} */ diff --git a/pkg/lua/contrib/lua_run.c b/pkg/lua/contrib/lua_run.c new file mode 100644 index 0000000000..fcb57f1689 --- /dev/null +++ b/pkg/lua/contrib/lua_run.c @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2018 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ +/** + * @ingroup pkg_lua + * @{ + * @file + * + * @brief Convenience functions for running Lua code. + * @author Juan Carrano + * + */ + +#define LUA_LIB + +#include "lprefix.h" + +#include +#include + +#include "kernel_defines.h" +#include "tlsf.h" + +#include "lua.h" +#include "lualib.h" +#include "lauxlib.h" + +#include "lua_run.h" +#include "lua_loadlib.h" + +const char *lua_riot_str_errors[] = { + "No errors", + "Error setting up the interpreter", + "Error while loading a builtin library", + "Cannot find the specified module", + "Compilation / syntax error", + "Unprotected error (uncaught exception)", + "Out of memory", + "Internal interpreter error", + "Unknown error" +}; + +/* The lua docs state the behavior in these cases: + * + * 1. ptr=?, size=0 -> free(ptr) + therefore ptr=NULL, size=0 -> NOP + * 2. ptr=? , size!=0 -> realloc(ptr, size) + * + * The TLSF code for realloc says: + * / * Zero-size requests are treated as free. * / + * if (ptr && size == 0) + * { + * tlsf_free(tlsf, ptr); + * } + * / * Requests with NULL pointers are treated as malloc. * / + * else if (!ptr) + * { + * p = tlsf_malloc(tlsf, size); + * } + * + * Therefore it is safe to use tlsf_realloc here. + */ +static void *lua_tlsf_alloc(void *ud, void *ptr, size_t osize, size_t nsize) +{ + tlsf_t tlsf = ud; + + (void)osize; + + return tlsf_realloc(tlsf, ptr, nsize); +} + +LUALIB_API lua_State *lua_riot_newstate(void *memory, size_t mem_size, + lua_CFunction panicf) +{ + lua_State *L; + + #ifdef LUA_DEBUG + Memcontrol *mc = memory; + #endif + + /* If we are using the lua debug module, let's reserve a space for the + * memcontrol block directly. We don't use the allocator because we lose + * the pointer, so we won't be able to free it and we will get a false + * positive if we try to check for memory leaks. + */ + #ifdef LUA_DEBUG + memory = (Memcontrol *)memory + 1; + mem_size -= (uint8_t *)memory - (uint8_t *)mc; + #endif + + tlsf_t tlsf = tlsf_create_with_pool(memory, mem_size); + + #ifdef LUA_DEBUG + luaB_init_memcontrol(mc, lua_tlsf_alloc, tlsf); + L = luaB_newstate(mc); + #else + L = lua_newstate(lua_tlsf_alloc, tlsf); + #endif + + if (L != NULL) { + lua_atpanic(L, panicf); + } + + return L; +} + +static const luaL_Reg loadedlibs[LUAR_LOAD_O_ALL] = { + { "_G", luaopen_base }, + { LUA_LOADLIBNAME, luaopen_package }, + { LUA_COLIBNAME, luaopen_coroutine }, + { LUA_TABLIBNAME, luaopen_table }, + { LUA_IOLIBNAME, luaopen_io }, + { LUA_OSLIBNAME, luaopen_os }, + { LUA_STRLIBNAME, luaopen_string }, + { LUA_MATHLIBNAME, luaopen_math }, + { LUA_UTF8LIBNAME, luaopen_utf8 }, + { LUA_DBLIBNAME, luaopen_debug }, +}; + +LUALIB_API int lua_riot_openlibs(lua_State *L, uint16_t modmask) +{ + int lib_index; + + #ifdef LUA_DEBUG + luaL_requiref(L, LUA_TESTLIBNAME, luaB_opentests, 1); + lua_pop(L, 1); + #endif + + for (lib_index = 0; lib_index < LUAR_LOAD_O_ALL; + lib_index++, modmask >>= 1) { + const luaL_Reg *lib = loadedlibs + lib_index; + + if (!(modmask & 1)) { + continue; + } + /* TODO: how can the loading fail? */ + luaL_requiref(L, lib->name, lib->func, 1); + lua_pop(L, 1); /* remove lib from stack (it is already global) */ + } + + return lib_index; +} + +/** + * Jump back to a save point (defined with setjmp). + * + * @note This function never returns! + */ +NORETURN static int _jump_back(lua_State *L) +{ + jmp_buf *jump_buffer = *(jmp_buf **)lua_getextraspace(L); + + /* FIXME: I dont think it's OK to print a message */ + lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n", + lua_tostring(L, -1)); + + /* TODO: try to return some info about the error object. */ + + longjmp(*jump_buffer, 1); +} + +static int lua_riot_do_module_or_buf(const uint8_t *buf, size_t buflen, + const char *modname, void *memory, size_t mem_size, + uint16_t modmask, int *retval) +{ + jmp_buf jump_buffer; + lua_State *volatile L = NULL; + volatile int tmp_retval = 0; /* we need to make it volatile because of the + setjmp/longjmp */ + volatile int status = LUAR_EXIT; + int compilation_result; + + if (setjmp(jump_buffer)) { /* We'll teleport back here if something goes wrong*/ + status = LUAR_INTERNAL_ERR; + goto lua_riot_do_error; + } + + L = lua_riot_newstate(memory, mem_size, _jump_back); + if (L == NULL) { + status = LUAR_STARTUP_ERR; + goto lua_riot_do_error; + } + + /* lua_getextraspace() gives us a pointer to an are large enough to hold a + * pointer. + * + * We store a pointer to the jump buffer in that area. + * + * lua_getextraspace() is therefore a pointer to a pointer to jump_buffer. + */ + *(jmp_buf **)lua_getextraspace(L) = &jump_buffer; + + tmp_retval = lua_riot_openlibs(L, modmask); + if (tmp_retval != LUAR_LOAD_O_ALL) { + status = LUAR_LOAD_ERR; + goto lua_riot_do_error; + } + + if (buf == NULL) { + compilation_result = lua_riot_getloader(L, modname); + } + else { + compilation_result = luaL_loadbufferx(L, (const char *)buf, + buflen, modname, "t"); + } + + switch (compilation_result) { + case LUAR_MODULE_NOTFOUND: + status = LUAR_NOMODULE; + goto lua_riot_do_error; + case LUA_ERRSYNTAX: + status = LUAR_COMPILE_ERR; + goto lua_riot_do_error; + case LUA_ERRMEM: /* fallthrough */ + case LUA_ERRGCMM: /* fallthrough */ + default: + status = LUAR_MEMORY_ERR; + goto lua_riot_do_error; + case LUA_OK: + break; + } + + if (buf != NULL) { + lua_pushstring(L, modname); + } + + switch (lua_pcall(L, 1, 1, 0)) { + case LUA_ERRRUN: /* fallthrough */ + case LUA_ERRGCMM: /* fallthrough */ + default: + status = LUAR_RUNTIME_ERR; + puts(lua_tostring(L, -1)); + goto lua_riot_do_error; + case LUA_ERRMEM: + status = LUAR_MEMORY_ERR; + goto lua_riot_do_error; + case LUA_OK: + break; + } + + tmp_retval = lua_tonumber(L, 1); + +lua_riot_do_error: + + if (L != NULL) { + lua_riot_close(L); + } + + if (retval != NULL) { + *retval = tmp_retval; + } + + return status; +} + + +LUALIB_API int lua_riot_do_module(const char *modname, void *memory, size_t mem_size, + uint16_t modmask, int *retval) +{ + return lua_riot_do_module_or_buf(NULL, 0, modname, memory, mem_size, modmask, + retval); +} + +LUALIB_API int lua_riot_do_buffer(const uint8_t *buf, size_t buflen, void *memory, + size_t mem_size, uint16_t modmask, int *retval) +{ + return lua_riot_do_module_or_buf(buf, buflen, "=BUFFER", memory, mem_size, + modmask, retval); +} + +#define MAX_ERR_STRING ((sizeof(lua_riot_str_errors) / sizeof(*lua_riot_str_errors)) - 1) +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) + +LUALIB_API const char *lua_riot_strerror(int errn) +{ + return lua_riot_str_errors[MIN((unsigned int)errn, MAX_ERR_STRING)]; +} + +/** @} */ diff --git a/pkg/lua/doc.txt b/pkg/lua/doc.txt index 944d45c632..50d6293ed4 100644 --- a/pkg/lua/doc.txt +++ b/pkg/lua/doc.txt @@ -1,6 +1,152 @@ /** * @defgroup pkg_lua Lua ported to RIOT * @ingroup pkg - * @brief Provides Lua support for RIOT + * @brief Provides a Lua interpreter for RIOT * @see https://github.com/lua/lua + * @see sys_lua + * + * # Lua programming language support + * + * ## Introduction + * + * This package embeds a [Lua 5.3](https://www.lua.org/) interpreter into RIOT. + * With a few exceptions, all the APIs mentioned in the + * [official documentation](https://www.lua.org/manual/5.3/) are available in + * this package too. + * + * ## Running Lua code. + * + * lua_run.h contains functions that make it easy to setup the interpreter and + * catch errors in a safe way. The functions from Lua's auxlib can still be used + * but then you must supply your own allocator and panic routines, load the + * builtin modules, etc. + * + * To run a chunk of code stored in an array use: + * ``` + * lua_riot_do_buffer(const char *buf, size_t buflen, void *memory, + * size_t mem_size, uint16_t modmask, int *retval); + * ``` + * The interpreter will not use the global heap for allocations, instead the + * user must supply a memory buffer. + * + * To save some memory, some builtin modules can be left out. `modmask` specifies + * which builtins to load. Note that if a builtin is not loaded by C code, then + * it cannot be loaded by Lua code later. + * + * `lua_riot_do_buffer` takes care of setting up the Lua state, registering a panic + * handler that does not crash the application, configuring an allocator, loading + * libraries, etc. + * + * To run a module as a script use `lua_riot_do_module`. This is roughly equivalent + * to executing: + * ``` + * require('modulename') + * ``` + * + * ## Memory requirements + * + * While generally efficient, the Lua interpreter was not really designed for + * constrained devices. + * + * A basic interpreter session typically requires about 12kB RAM. The stack + * but it depends on the functions used (string handling tends to use more stack). + * It also depends on the platform. + * + * There is currently no easy way to determine the stack needs other than trial + * and error. Future versions of the package will include instrumentation to + * this end. + * + * ## Adding your own modules. + * + * `lua_loadlib.c` contains two loaders, one for modules written in Lua and + * another one for C extensions. + * + * An index to the modules is stored in a table (there are two, one for each + * kind of module). The tables are indexed by the module name and must be sorted + * in ascending order by this key. + * + * The definitions for the table types are in `lua_builtin.h`. The loader module + * containes empty tables, defined as weak symbols so they can be ovewritten + * by the application. The variables that must be defined are: + * + * ``` + * /** Table containing all built in pure lua modules */ + * const struct lua_riot_builtin_lua *const lua_riot_builtin_lua_table; + * /** Number of elements of lua_riot_builtin_lua_table */ + * const size_t lua_riot_builtin_lua_table_len; + * + * /** Table containing all built in c lua modules */ + * const struct lua_riot_builtin_c *const lua_riot_builtin_c_table; + * /** Number of elements of lua_riot_builtin_c_table */ + * const size_t lua_riot_builtin_c_table_len; + * ``` + * + * Currently, these must be defined manually in the application code. In the + * future a script will generate this tables, populating them with both RIOT + * modules and the user modules. + * + * + * ## Customizations + * + * The upstream Lua code is used without with the following modifications. + * + * Modifications that affect the API: + * + * - lua.c (the main interface to the interpreter) is replaced by our own + * stripped-down version. The REPL is no longer included. + * - loadlib.c (the "package" module) is replaced by our own (simplified) + * loader. All the code dealing with files and dynamic loading has been + * removed. + * - os.tmpname() is removed as it caused compiler warnings and it is not + * really possible to use it right. Use io.tmpfile() instead. + * - The test module has been modified to allow it run in the RIOT environment. + * This is not a public API, though. + * + * Other modifications: + * + * - There is a patch changing the Makefile. This updated makefile is not used + * in the package, but is provided to aid development in a PC. + * - Some patches to reduce stack and memory usage. + * + * ### Patches + * + * A version of Lua with the patches applied is available at + * https://github.com/riot-appstore/lua. It can be downloaded and compiled in + * desktop computer, and the official test suite (https://www.lua.org/tests/) + * can then be run. + * + * Alternatively, the patches in this package can be directly applied to the + * official distribution. + * + * The updated makefile creates two standalone executables. Tests should be run + * with the debug executable. + * + * ## TODO + * + * The following features are missing and will be eventually added: + * + * - Load source code incrementally. It can be done now, but then the rest of the + * interpreter setup must be loaded manually. + * - Bindings to access RIOT functionality. + * - Support in the build system for easily including application-specific + * modules. + * - Instrumentation to measure stack consumption (and maybe prevent overflow). + * - Support for "frozen tables" (i.e. tables that live in ROM). + * - Provide a better way of supplying data to a script and getting back results. + * - Specify a function to call inside a module (????) + * - Expand this readme into a proper manual. + * + */ + +/* These are docs for the future (when we have the script to compile module tables) */ +/* + * # Running Lua and C code + * + * see \ref sys_lua for information on how to access RIOT modules from within + * Lua. + * + * While it is possible to include your application specific modules and run + * arbitrary Lua code only just using this interpreter, the \ref sys_lua module + * provides an automated way of handling Lua modules. + * */ diff --git a/pkg/lua/include/lua_builtin.h b/pkg/lua/include/lua_builtin.h new file mode 100644 index 0000000000..fcfec30bdf --- /dev/null +++ b/pkg/lua/include/lua_builtin.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2018 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ +/** + * @ingroup pkg_lua + * @{ + * @file + * + * @brief Definitions for including built-in modules. + * @author Juan Carrano + * + * The modules must be placed in the tables lua_riot_builtin_lua_table (for lua + * source code) and lua_riot_builtin_c_table (for C extensions) and the lengths + * of these tables must be in lua_riot_builtin_lua_table_len and + * lua_riot_builtin_c_table_len. + * + * These symbols are defined as weak, so there if they are not defined elsewhere + * they will default to zero (or NULL), that is, empty tables. + */ + +#ifndef LUA_BUILTIN_H +#define LUA_BUILTIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Avoid compilation errors where there are no external modules defined */ +/** + * Attribute to make symbols weak. + * + * @todo This should be made part of RIOT. + */ +#define WEAK __attribute__((weak)) + +/** + * Only the first `LUAR_MAX_MODULE_NAME` characters of a module name + * will be considered when performing a lookup. + */ +#define LUAR_MAX_MODULE_NAME 64 + +/** + * Entry describing a pure lua module whose source is built into the + * application binary. + */ +struct lua_riot_builtin_lua { + const char *name; /*!< Name of the module */ + const uint8_t *code; /*!< Lua source code buffer*/ + size_t code_size; /*!< Size of the source code buffer. */ +}; + +/** + * Entry describing a c lua module built into the + * application binary. + */ +struct lua_riot_builtin_c { + const char *name; /*!< Name of the module */ + int (*luaopen)(lua_State *); /*!< Loader function. It must place the module + * table at the top of the lua stack. + * @todo Add better docs. + */ +}; + +/** Table containing all built in pure lua modules */ +extern WEAK const struct lua_riot_builtin_lua *const lua_riot_builtin_lua_table; +/** Number of elements of lua_riot_builtin_lua_table */ +extern WEAK const size_t lua_riot_builtin_lua_table_len; + +/** Table containing all built in c lua modules */ +extern WEAK const struct lua_riot_builtin_c *const lua_riot_builtin_c_table; +/** Number of elements of lua_riot_builtin_c_table */ +extern WEAK const size_t lua_riot_builtin_c_table_len; + +#ifdef __cplusplus +extern "C" } +#endif + +#endif /* LUA_BUILTIN_H */ + +/** @} */ diff --git a/pkg/lua/include/lua_loadlib.h b/pkg/lua/include/lua_loadlib.h new file mode 100644 index 0000000000..f2ce87e14e --- /dev/null +++ b/pkg/lua/include/lua_loadlib.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2018 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ +/** + * @ingroup pkg_lua + * @{ + * @file + * + * @brief Lightweight C interface to the package loader. + * @author Juan Carrano + * + */ + +#ifndef LUA_LOADLIB_H +#define LUA_LOADLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Error code for when a modules is not found. + * + * The numeric value is chosen so that there is no collision with Lua's + * own error codes. + */ +#define LUAR_MODULE_NOTFOUND 50 + +/** + * Load a module as a chunk. + * + * This function is a lightweight "require". It does not require the "package" + * module to be loaded and does not register the module. + * Only the builtin tables are searched. + * + * Upon sucessful execution, the compiled chunk will be at the top of the lua + * stack. + * + * @param L Initialized Lua interpreter state. + * @param name Name of the module. + * + * @return Same as lua_load. If the module is a C-module, then this will + * always succeed and return LUA_OK. + */ +int lua_riot_getloader(lua_State *L, const char *name); + +#ifdef __cplusplus +extern "C" +} +#endif + +#endif /* LUA_LOADLIB_H */ + +/** @} */ diff --git a/pkg/lua/include/lua_run.h b/pkg/lua/include/lua_run.h new file mode 100644 index 0000000000..dcdbde42f9 --- /dev/null +++ b/pkg/lua/include/lua_run.h @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2018 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ +/** + * @ingroup pkg_lua + * @file + * @{ + * + * @brief Convenience functions for running Lua code. + * @author Juan Carrano + * + * This functions make it easy to create and use new Lua context: + * It provides: + * + * - Easy to use routines for executing modules as scrips. + * - Control over which modules get loaded. + * - Support for using a local heap allocator. + * - Out of memory handling via setjmp/longjmp. + * + * This library is not strictly required, as all of the functionality could be + * implemented in terms of the public lua api, but it covers most of the use + * cases, and thus avoids code repetition in applications. + * + */ + +#ifndef LUA_RUN_H +#define LUA_RUN_H + +#include + +#include "lua.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Convert a library index into a bit mask. + */ +#define LUAR_LOAD_FLAG(n) (((uint16_t)1) << (n)) + +/** + * Order in which the builtin libraries are loaded. + */ +enum LUAR_LOAD_ORDER { + LUAR_LOAD_O_BASE, + LUAR_LOAD_O_PACKAGE, + LUAR_LOAD_O_CORO, + LUAR_LOAD_O_TABLE, + LUAR_LOAD_O_IO, + LUAR_LOAD_O_OS, + LUAR_LOAD_O_STRING, + LUAR_LOAD_O_MATH, + LUAR_LOAD_O_UTF8, + LUAR_LOAD_O_DEBUG, + LUAR_LOAD_O_ALL, +}; + +/** Load the base globals (_G) */ +#define LUAR_LOAD_BASE LUAR_LOAD_FLAG(LUAR_LOAD_O_BASE) +/** Load ´package´ */ +#define LUAR_LOAD_PACKAGE LUAR_LOAD_FLAG(LUAR_LOAD_O_PACKAGE) +/** Load ´coroutine´ */ +#define LUAR_LOAD_CORO LUAR_LOAD_FLAG(LUAR_LOAD_O_CORO) +/** Load ´table´ */ +#define LUAR_LOAD_TABLE LUAR_LOAD_FLAG(LUAR_LOAD_O_TABLE) +/** Load ´io´ */ +#define LUAR_LOAD_IO LUAR_LOAD_FLAG(LUAR_LOAD_O_IO) +/** Load ´os´ */ +#define LUAR_LOAD_OS LUAR_LOAD_FLAG(LUAR_LOAD_O_OS) +/** Load ´string´ */ +#define LUAR_LOAD_STRING LUAR_LOAD_FLAG(LUAR_LOAD_O_STRING) +/** Load ´math´ */ +#define LUAR_LOAD_MATH LUAR_LOAD_FLAG(LUAR_LOAD_O_MATH) +/** Load ´utf8´ */ +#define LUAR_LOAD_UTF8 LUAR_LOAD_FLAG(LUAR_LOAD_O_UTF8) +/** Load ´debug´ */ +#define LUAR_LOAD_DEBUG LUAR_LOAD_FLAG(LUAR_LOAD_O_DEBUG) + +/* TODO: maybe we can implement a "restricted base" package containing a subset + * of base that is safe. */ + +#define LUAR_LOAD_ALL (0xFFFF) /** Load all standard modules */ +#define LUAR_LOAD_NONE (0x0000) /** Do not load any modules */ + +/** Errors that can be raised when running lua code. */ +enum LUAR_ERRORS { + LUAR_EXIT, /** The program exited without error. */ + LUAR_STARTUP_ERR, /** Error setting up the interpreter. */ + LUAR_LOAD_ERR, /** Error while loading libraries. */ + LUAR_NOMODULE, /** The specified module could not be found. */ + LUAR_COMPILE_ERR, /** The Lua code failed to compile. */ + LUAR_RUNTIME_ERR, /** Error in code execution. */ + LUAR_MEMORY_ERR, /** Lua could not allocate enough memory */ + LUAR_INTERNAL_ERR /** Error inside the Lua VM. + * Right now, if this happens, you may leak memory from + * the heap. If your program is the only one using the + * dynamic allocation, just clean the heap. + */ +}; + +/** + * Human-readable description of the errors + */ +extern const char *lua_riot_str_errors[]; + +/** + * Return a string describing an error from LUAR_ERRORS. + * + * @param errn Error number as returned by lua_riot_do_buffer() or + * lua_riot_do_buffer() + * + * @return A string describing the error, or "Unknown error". + */ +LUALIB_API const char *lua_riot_strerror(int errn); + +/** + * Initialize a lua state and set the panic handler. + * + * @todo Use a per-state allocator + * + * @param memory Pointer to memory region that will be used as heap for + * the allocator. Currently this functionality is not + * supported and this must be set to NULL. + * @param mem_size Size of the memory region that will be used as heap. + * Currently this functionality is not supported and this + * must be set to 0. + * @param panicf Function to be passed to lua_atpanic. If set to NULL, + * a generic function that does nothing will be used. + * + * @return the new state, or NULL if there is a memory allocation error. + */ +LUALIB_API lua_State *lua_riot_newstate(void *memory, size_t mem_size, + lua_CFunction panicf); + +/** + * Terminate the lua state. + * + * You must call this function if you want the finalizers (the __gc metamethods) + * to be called. + */ +#ifndef LUA_DEBUG + #define lua_riot_close lua_close +#else + #define lua_riot_close luaB_close +#endif /* LUA_DEBUG */ + +/** + * Open builtin libraries. + * + * This is like luaL_openlibs but it allows selecting which libraries will + * be loaded. + * + * Libraries are loaded in the order specified by the LUAR_LOAD_ORDER enum. If + * there is an error the load sequence is aborted and the index of the library + * that failed is reported. + * + * If debuging is enabled (compile with the LUA_DEBUG macro), then the test + * library will be unconditionally loaded. + * + * @param L Lua state + * @param modmask Binary mask that indicates which modules should be + * loaded. The mask is made from a combination of the + * LUAR_LOAD_* macros. + * + * @return The index of the library that failed to load, or LUAR_LOAD_O_ALL + * if all libraries were loaded. + */ +LUALIB_API int lua_riot_openlibs(lua_State *L, uint16_t modmask); + +/** + * Initialize the interpreter and run a built-in module in protected mode. + * + * In addition to running code in protected mode, this also sets a panic + * function that long-jumps back to this function, in case there is an internal + * interpreter error (LUAR_INTERNAL_ERR). + * Right now the only things that the application can are either to abort(), + * or to manually reset the heap (only if there's no other thread using it). + * + * @param modname name of the module. + * @param memory @see lua_riot_newstate() + * @param mem_size @see lua_riot_newstate() + * @param modmask @see lua_riot_newstate() + * @param[out] retval Value returned by the lua code, if it is a number, + * or zero if no value is returned or the value is not + * a number. If retval is null, the value is not stored. + * + * @return An error code ( @see LUAR_ERRORS). LUAR_EXIT indicates no error. + */ +LUALIB_API int lua_riot_do_module(const char *modname, void *memory, size_t mem_size, + uint16_t modmask, int *retval); + +/** + * Initialize the interpreter and run a user supplied buffer in protected mode. + * + * Only text data (i.e. lua source code) can be loaded by this function. The + * lua interpreter is not robust against corrupt binary code. + * + * @see lua_riot_do_module() for more information on internal errors. + * + * @param buf Text data (lua source code). + * @param buflen Size of the text data in bytes. If buf is + * a zero-terminated string, the zero must not be counted. + * @param memory @see lua_riot_newstate() + * @param mem_size @see lua_riot_newstate() + * @param modmask @see lua_riot_newstate() + * @param[out] retval @see lua_riot_do_module() + * @return @see lua_riot_do_module(). + */ +LUALIB_API int lua_riot_do_buffer(const uint8_t *buf, size_t buflen, void *memory, + size_t mem_size, uint16_t modmask, int *retval); + +#ifdef __cplusplus +extern "C" } +#endif + +/** @} */ + +#endif /* LUA_RUN_H */ diff --git a/pkg/lua/patches/0001-Remove-dependency-on-nonexistent-RIOT-syscalls.patch b/pkg/lua/patches/0001-Remove-dependency-on-nonexistent-RIOT-syscalls.patch deleted file mode 100644 index b4017f5382..0000000000 Binary files a/pkg/lua/patches/0001-Remove-dependency-on-nonexistent-RIOT-syscalls.patch and /dev/null differ diff --git a/pkg/lua/patches/0001-Remove-luaL_newstate.patch b/pkg/lua/patches/0001-Remove-luaL_newstate.patch new file mode 100644 index 0000000000..f7059b62a9 Binary files /dev/null and b/pkg/lua/patches/0001-Remove-luaL_newstate.patch differ diff --git a/pkg/lua/patches/0002-Allow-LUAL_BUFFERSIZE-to-be-defined-in-the-command-l.patch b/pkg/lua/patches/0002-Allow-LUAL_BUFFERSIZE-to-be-defined-in-the-command-l.patch new file mode 100644 index 0000000000..bb674624d4 Binary files /dev/null and b/pkg/lua/patches/0002-Allow-LUAL_BUFFERSIZE-to-be-defined-in-the-command-l.patch differ diff --git a/pkg/lua/patches/0003-Make-size-of-LoadF-buffer-configurable.patch b/pkg/lua/patches/0003-Make-size-of-LoadF-buffer-configurable.patch new file mode 100644 index 0000000000..0237936119 Binary files /dev/null and b/pkg/lua/patches/0003-Make-size-of-LoadF-buffer-configurable.patch differ diff --git a/pkg/lua/patches/0004-Remove-os.tmpname.patch b/pkg/lua/patches/0004-Remove-os.tmpname.patch new file mode 100644 index 0000000000..c94f3490e4 Binary files /dev/null and b/pkg/lua/patches/0004-Remove-os.tmpname.patch differ diff --git a/pkg/lua/patches/0005-Do-not-allocate-buffers-on-the-stack.patch b/pkg/lua/patches/0005-Do-not-allocate-buffers-on-the-stack.patch new file mode 100644 index 0000000000..fa9a70d173 Binary files /dev/null and b/pkg/lua/patches/0005-Do-not-allocate-buffers-on-the-stack.patch differ diff --git a/pkg/lua/patches/0006-Cleanup-test-module.patch b/pkg/lua/patches/0006-Cleanup-test-module.patch new file mode 100644 index 0000000000..0d22dd9fcf Binary files /dev/null and b/pkg/lua/patches/0006-Cleanup-test-module.patch differ diff --git a/pkg/lua/patches/0007-Add-a-proper-makefile.patch b/pkg/lua/patches/0007-Add-a-proper-makefile.patch new file mode 100644 index 0000000000..f6eb73d247 Binary files /dev/null and b/pkg/lua/patches/0007-Add-a-proper-makefile.patch differ diff --git a/pkg/lua/patches/0008-Default-to-32-bit-build-and-small-buffer-size.patch b/pkg/lua/patches/0008-Default-to-32-bit-build-and-small-buffer-size.patch new file mode 100644 index 0000000000..f9b79b0737 Binary files /dev/null and b/pkg/lua/patches/0008-Default-to-32-bit-build-and-small-buffer-size.patch differ