diff options
58 files changed, 1861 insertions, 629 deletions
@@ -111,7 +111,6 @@ include $(MAKEDIR)/syslinux.mk # directories. # -# List of module objects that should be installed for all derivatives ifndef EFI_BUILD MODULES = memdisk/memdisk memdump/memdump.com modules/*.com \ com32/menu/*.c32 com32/modules/*.c32 com32/mboot/*.c32 \ @@ -129,6 +128,9 @@ MODULES = com32/menu/*.c32 com32/modules/*.c32 com32/mboot/*.c32 \ com32/elflink/ldlinux/*.c32 endif +# List of module objects that should be installed for all derivatives +INSTALLABLE_MODULES = $(filter-out com32/gpllib%,$(MODULES)) + # syslinux.exe is BTARGET so as to not require everyone to have the # mingw suite installed BTARGET = version.gen version.h version.mk @@ -173,7 +175,7 @@ INSTALL_SBIN = extlinux/extlinux INSTALL_AUX = core/pxelinux.0 gpxe/gpxelinux.0 gpxe/gpxelinuxk.0 \ core/isolinux.bin core/isolinux-debug.bin \ dos/syslinux.com \ - mbr/*.bin $(MODULES) + mbr/*.bin $(INSTALLABLE_MODULES) INSTALL_AUX_OPT = win32/syslinux.exe win64/syslinux64.exe INSTALL_DIAG = diag/mbr/handoff.bin \ diag/geodsp/geodsp1s.img.xz diag/geodsp/geodspms.img.xz @@ -182,11 +184,11 @@ INSTALL_DIAG = diag/mbr/handoff.bin \ INSTALLSUBDIRS = com32 utils dosutil # Things to install in /boot/extlinux -EXTBOOTINSTALL = $(MODULES) +EXTBOOTINSTALL = $(INSTALLABLE_MODULES) # Things to install in /tftpboot NETINSTALLABLE = core/pxelinux.0 gpxe/gpxelinux.0 \ - $(MODULES) + $(INSTALLABLE_MODULES) endif # ifdef EFI_BUILD @@ -2,9 +2,51 @@ Starting with 1.47, changes marked with SYSLINUX, PXELINUX, ISOLINUX or EXTLINUX apply to that specific program only; other changes apply to all derivatives. +Changes in 5.00: + * com32: Switched from the COM32 object format to ELF as it is + a much more powerful format that allows undefined symbols to + be resolved at runtime and dynamic loading of module + dependencies, which means modules now become shared object + files instead of statically linked binaries - reducing both + disk space and runtime memory consumption. + * core: Split non-core functionality into ldlinux.c32, which + is an ELF module loaded by the core that contains everything + the core doesn't require to boot the system, e.g. config + parser, command-line interface, etc. + * Replaced __intcall() calls with direct function calls now + that we can resolve undefined symbols at runtime, thanks to + the ELF object support. Now that we no longer need to go + through the 16-bit interrupt mechanism we can make full use + of the 32-bit execution environment. This change required + reimplementing lots of the 16-bit assembly code from core/ + in C. + * com32: __com32.cs_bounce is gone now we always run in a + 32-bit environment once we execute ldlinux.c32. + * ldlinux: A new "PATH" directive was added to the ldlinux.c32 + config parser that specifies a colon-separated list of + directories to search when attempting to load modules. + Changes in 4.06: * Support for NTFS, by Paulo Alcantara. * EXTLINUX: more robust device detection, allow user to override. + * kontron_wdt.c32: Add a new module to enable the hardware + watchdog of some Kontron boards. It allows enabling the watchdog + and then booting a given image. + * HDT updated, and now can display images regarding some detection + steps. Add postexec command to run a particular entry after + HDT's execution, add silent option and various fixes. + * ifcpu.c32: Detect hypervisor presence. + * lua.c32: Add dhcp support and support for native Syslinux + functions syslinux_config(), syslinux_ipappend_strings() and + syslinux_reboot(). + * isohybrid: Workaround for various EFI systems. + * pxechn.c32, a PXE NBP chainloader. More versatile alternative + to pxechain.com and resolves the PXELINUX -> WDS issue with + Microsoft Windows Server 2008R2 (Gene Cumm). + * btrfs: Fix booting off of a subvolume. + * com32: Add device tree support. + * SYSLINUX: Fix relative paths for VFAT. The CONFIG and APPEND + directives now support entirely relative paths. Changes in 4.05: * HDT updated, and now supports uploading data to a TFTP @@ -20,6 +20,13 @@ SYSLINUX now builds in a Linux environment, using nasm. You need nasm version 2.03 or later (2.07 or later recommended) to build SYSLINUX from source. See http://www.nasm.us/ for information about nasm. +"utils/isohybrid" needs the UUID library and following header file, + + /usr/include/uuid/uuid.h + +You can get them from the "uuid-dev" package on Debian based systems +or from the "libuuid-devel" package on RPM based distributions. + There is now a mailing list for SYSLINUX. See the end of syslinux.txt for details. diff --git a/com32/elflink/ldlinux/ldlinux.c b/com32/elflink/ldlinux/ldlinux.c index f82b1662..d9635956 100644 --- a/com32/elflink/ldlinux/ldlinux.c +++ b/com32/elflink/ldlinux/ldlinux.c @@ -271,7 +271,7 @@ int main(int argc __unused, char **argv __unused) size_t count = 0; char *config_argv[2] = { NULL, NULL }; - openconsole(&dev_rawcon_r, &dev_ansiserial_w); + openconsole(&dev_stdcon_r, &dev_ansiserial_w); if (ConfigName[0]) config_argv[0] = ConfigName; diff --git a/com32/gplinclude/dmi/dmi_bios.h b/com32/gplinclude/dmi/dmi_bios.h index 5d47e899..4af7e0bd 100644 --- a/com32/gplinclude/dmi/dmi_bios.h +++ b/com32/gplinclude/dmi/dmi_bios.h @@ -22,7 +22,7 @@ #define BIOS_BIOS_REVISION_SIZE 16 #define BIOS_FIRMWARE_REVISION_SIZE 16 -#define BIOS_CHAR_NB_ELEMENTS 28 +#define BIOS_CHAR_NB_ELEMENTS 29 #define BIOS_CHAR_X1_NB_ELEMENTS 8 #define BIOS_CHAR_X2_NB_ELEMENTS 3 @@ -46,6 +46,7 @@ typedef struct { bool boot_from_cd; bool selectable_boot; bool bios_rom_socketed; + bool boot_from_pcmcia; bool edd; bool japanese_floppy_nec_9800_1_2MB; bool japanese_floppy_toshiba_1_2MB; diff --git a/com32/hdt/Makefile b/com32/hdt/Makefile index 386c7472..362b4874 100644 --- a/com32/hdt/Makefile +++ b/com32/hdt/Makefile @@ -19,10 +19,7 @@ VPATH = $(SRC) include $(MAKEDIR)/elf.mk LIBS = $(objdir)/com32/libupload/libcom32upload.a -C_LIBS += $(objdir)/com32/cmenu/libmenu/libmenu.c32 \ - $(objdir)/com32/libutil/libutil_com.c32 \ - $(objdir)/com32/lib/libcom32.c32 \ - $(objdir)/com32/gpllib/libcom32gpl.c32 +C_LIBS += $(objdir)/com32/cmenu/libmenu/libmenu.c32 CFLAGS += -I$(com32)/cmenu/libmenu -I$(com32) MODULES = hdt.c32 @@ -77,6 +74,8 @@ hdt.img: hdt.c32 $(FLOPPY_DIR)/hdt.cfg $(FLOPPY_DIR)/mtools.conf $(topdir)/mtool MTOOLSRC=$(PWD)/$(FLOPPY_DIR)/mtools.conf $(MCOPY) $(FLOPPY_DIR)/syslinux.cfg a: MTOOLSRC=$(PWD)/$(FLOPPY_DIR)/mtools.conf $(MCOPY) $(FLOPPY_DIR)/$(MEMTEST) a: MTOOLSRC=$(PWD)/$(FLOPPY_DIR)/mtools.conf $(MCOPY) $(ART_DIR)/backgnd.png a: + MTOOLSRC=$(PWD)/$(FLOPPY_DIR)/mtools.conf $(MCOPY) $(ART_DIR)/display.png a: + MTOOLSRC=$(PWD)/$(FLOPPY_DIR)/mtools.conf $(MCOPY) $(ART_DIR)/red.png a: mv hdt.img hdt-$(VERSION).img ln -sf hdt-$(VERSION).img hdt.img @@ -97,6 +96,8 @@ hdt.iso: hdt.c32 $(topdir)/core/isolinux.bin $(FLOPPY_DIR)/hdt.cfg memtest cp $(MENU_COM32) $(ISO_DIR)/$(ISOLINUX_DIR) cp $(CHAIN_COM32) $(ISO_DIR)/$(ISOLINUX_DIR) cp -av $(ART_DIR)/backgnd.png $(ISO_DIR)/$(ISOLINUX_DIR) + cp -av $(ART_DIR)/display.png $(ISO_DIR)/$(ISOLINUX_DIR) + cp -av $(ART_DIR)/red.png $(ISO_DIR)/$(ISOLINUX_DIR) -[ ! -f $(GZ_PCI_IDS_FILE) ] && cp /usr/share/hwdata/pci.ids $(PCI_IDS_FILE) && $(GZIPPROG) $(PCI_IDS_FILE) -[ ! -f $(GZ_PCI_IDS_FILE) ] && cp /usr/share/pci.ids $(PCI_IDS_FILE) && $(GZIPPROG) $(PCI_IDS_FILE) -[ -f $(MODULES_ALIAS_FILE) ] && cp $(MODULES_ALIAS_FILE) $(ISO_DIR)/$(ISOLINUX_DIR)\ diff --git a/com32/hdt/art/display.png b/com32/hdt/art/display.png Binary files differnew file mode 100644 index 00000000..31fabef6 --- /dev/null +++ b/com32/hdt/art/display.png diff --git a/com32/hdt/art/red.png b/com32/hdt/art/red.png Binary files differnew file mode 100644 index 00000000..c5616ac2 --- /dev/null +++ b/com32/hdt/art/red.png diff --git a/com32/hdt/floppy/hdt.cfg b/com32/hdt/floppy/hdt.cfg index e5f3b0a0..524c4e06 100644 --- a/com32/hdt/floppy/hdt.cfg +++ b/com32/hdt/floppy/hdt.cfg @@ -93,7 +93,17 @@ TEXT HELP VESA mode is enabled ENDTEXT COM32 hdt.c32 -APPEND modules_pcimap=modules.pcimap modules_alias=modules.alias pciids=pci.ids quiet vesa nomenu auto='show memory;say `########`;say `Starting memtest in 5 sec`%5;exit' postexec='memtest' +APPEND modules_pcimap=modules.pcimap modules_alias=modules.alias pciids=pci.ids quiet vesa nomenu auto='show memory;say `########`;say `Starting memtest in 5 sec`;sleep 5;exit' postexec='memtest' + +LABEL display +MENU LABEL Display feature (VESA mode) +TEXT HELP + Starts HDT using the Command Line Interface (CLI) + VESA mode is enabled + A Picture is shown by using the display command +ENDTEXT +COM32 hdt.c32 +APPEND modules_pcimap=modules.pcimap modules_alias=modules.alias pciids=pci.ids silent nomenu vesa auto='display display.png; sleep 5000; display red.png' MENU SEPARATOR diff --git a/com32/hdt/hdt-cli-hdt.c b/com32/hdt/hdt-cli-hdt.c index f7f7e949..3c571d60 100644 --- a/com32/hdt/hdt-cli-hdt.c +++ b/com32/hdt/hdt-cli-hdt.c @@ -54,12 +54,12 @@ static void main_show_modes(int argc __unused, char **argv __unused, int i = 0; reset_more_printf(); - printf("Available modes:\n"); + more_printf("Available modes:\n"); while (list_modes[i]) { printf("%s ", list_modes[i]->name); i++; } - printf("\n"); + more_printf("\n"); } /** @@ -119,7 +119,7 @@ static void show_cli_help(int argc __unused, char **argv __unused, find_cli_mode_descr(hdt_cli.mode, ¤t_mode); - printf("Available commands are:\n"); + more_printf("Available commands are:\n"); /* List first default modules of the mode */ if (current_mode->default_modules && current_mode->default_modules->modules) { @@ -154,7 +154,7 @@ static void show_cli_help(int argc __unused, char **argv __unused, /* List secondly the show modules of the mode */ if (current_mode->show_modules && current_mode->show_modules->modules) { - printf("\nshow commands:\n"); + more_printf("\nshow commands:\n"); j = 0; while (current_mode->show_modules->modules[j].name) { printf("%s ", current_mode->show_modules->modules[j].name); @@ -165,7 +165,7 @@ static void show_cli_help(int argc __unused, char **argv __unused, /* List thirdly the set modules of the mode */ if (current_mode->set_modules && current_mode->set_modules->modules) { - printf("\nset commands:\n"); + more_printf("\nset commands:\n"); j = 0; while (current_mode->set_modules->modules[j].name) { printf("%s ", current_mode->set_modules->modules[j].name); @@ -260,6 +260,30 @@ static void do_dump(int argc __unused, char **argv __unused, } /** + * do_sleep - sleep a number of milliseconds + **/ +static void do_sleep(int argc , char **argv , + struct s_hardware *hardware) +{ + (void) hardware; + if (argc != 1) return; + more_printf("Sleep %d milliseconds\n",atoi(argv[0])); + msleep(atoi(argv[0])); +} + +/** + * do_display - display an image to user + **/ +static void do_display(int argc , char **argv , + struct s_hardware *hardware) +{ + (void) hardware; + if ((argc != 1) || (vesamode == false)) return; + more_printf("Display %s file\n",argv[0]); + vesacon_load_background(argv[0]); +} + +/** * do_say - say message to user **/ static void do_say(int argc , char **argv , @@ -270,7 +294,6 @@ static void do_say(int argc , char **argv , char text_to_say[255]={0}; int arg=0; - int sleep_time=0; #if DEBUG for (int i=0; i<argc;i++) dprintf("SAY: arg[%d]={%s}\n",i,argv[i]); #endif @@ -293,24 +316,7 @@ static void do_say(int argc , char **argv , dprintf("SAY CMD = [%s]\n",text_to_say); } - /* The % char can be in the same argument, let's consider it again */ - arg--; - - /* Searching for a % argument to determine the time to show the message */ - char *time_to_display = NULL; - /* Search for a requested time to display */ - while ( ((time_to_display=strchr(argument, '%')) == NULL) && (arg+1<argc)) { - arg++; - argument = (char *)argv[arg]; - } - - if (time_to_display != NULL) { - sleep_time=atoi(time_to_display+1); - dprintf("SAY CMD :Time to display = %d\n",sleep_time); - } - - printf("%s\n",text_to_say); - sleep(sleep_time); + more_printf("%s\n",text_to_say); } } @@ -357,6 +363,16 @@ struct cli_callback_descr list_hdt_default_modules[] = { .nomodule = true, }, { + .name = CLI_DISPLAY, + .exec = do_display, + .nomodule = true, + }, + { + .name = CLI_SLEEP, + .exec = do_sleep, + .nomodule = true, + }, + { .name = NULL, .exec = NULL, .nomodule = false}, diff --git a/com32/hdt/hdt-cli.c b/com32/hdt/hdt-cli.c index 11984e5a..7542da83 100644 --- a/com32/hdt/hdt-cli.c +++ b/com32/hdt/hdt-cli.c @@ -132,7 +132,7 @@ void set_mode(cli_mode_t mode, struct s_hardware *hardware) break; case PXE_MODE: if (hardware->sv->filesystem != SYSLINUX_FS_PXELINUX) { - printf("You are not currently using PXELINUX\n"); + more_printf("You are not currently using PXELINUX\n"); break; } hdt_cli.mode = mode; @@ -160,7 +160,7 @@ void set_mode(cli_mode_t mode, struct s_hardware *hardware) break; case DMI_MODE: if (!hardware->is_dmi_valid) { - printf("No valid DMI table found, exiting.\n"); + more_printf("No valid DMI table found, exiting.\n"); break; } hdt_cli.mode = mode; @@ -172,7 +172,7 @@ void set_mode(cli_mode_t mode, struct s_hardware *hardware) break; case VPD_MODE: if (!hardware->is_vpd_valid) { - printf("No valid VPD table found, exiting.\n"); + more_printf("No valid VPD table found, exiting.\n"); break; } hdt_cli.mode = mode; @@ -188,9 +188,9 @@ void set_mode(cli_mode_t mode, struct s_hardware *hardware) break; default: /* Invalid mode */ - printf("Unknown mode, please choose among:\n"); + more_printf("Unknown mode, please choose among:\n"); while (list_modes[i]) { - printf("\t%s\n", list_modes[i]->name); + more_printf("\t%s\n", list_modes[i]->name); i++; } } @@ -199,7 +199,7 @@ void set_mode(cli_mode_t mode, struct s_hardware *hardware) /* There is not cli_mode_descr struct for the exit mode */ if (current_mode == NULL && hdt_cli.mode != EXIT_MODE) { /* Shouldn't get here... */ - printf("!!! BUG: Mode '%d' unknown.\n", hdt_cli.mode); + more_printf("!!! BUG: Mode '%d' unknown.\n", hdt_cli.mode); } } @@ -679,7 +679,7 @@ static void exec_command(char *line, struct s_hardware *hardware) if (current_module != NULL) current_module->exec(argc, argv, hardware); else - printf("unknown command: '%s'\n", command); + more_printf("unknown command: '%s'\n", command); } } else { /* @@ -833,7 +833,7 @@ void start_cli_mode(struct s_hardware *hardware) find_cli_mode_descr(hdt_cli.mode, ¤t_mode); if (current_mode == NULL) { /* Shouldn't get here... */ - printf("!!! BUG: Mode '%d' unknown.\n", hdt_cli.mode); + more_printf("!!! BUG: Mode '%d' unknown.\n", hdt_cli.mode); return; } @@ -842,7 +842,7 @@ void start_cli_mode(struct s_hardware *hardware) start_auto_mode(hardware); } - printf("Entering CLI mode\n"); + more_printf("Entering CLI mode\n"); reset_prompt(); diff --git a/com32/hdt/hdt-cli.h b/com32/hdt/hdt-cli.h index 30fe5187..82a4fc99 100644 --- a/com32/hdt/hdt-cli.h +++ b/com32/hdt/hdt-cli.h @@ -67,6 +67,8 @@ #define CLI_DISABLE "disable" #define CLI_DUMP "dump" #define CLI_SAY "say" +#define CLI_DISPLAY "display" +#define CLI_SLEEP "sleep" typedef enum { INVALID_MODE, diff --git a/com32/hdt/hdt-common.c b/com32/hdt/hdt-common.c index f729a107..289d74e3 100644 --- a/com32/hdt/hdt-common.c +++ b/com32/hdt/hdt-common.c @@ -63,6 +63,9 @@ void detect_parameters(const int argc, const char *argv[], /* Quiet mode - make the output more quiet */ quiet = true; + /* Silent mode - make not output at all */ + silent = false; + /* Vesa mode isn't set until we explictly call it */ vesamode = false; @@ -75,6 +78,8 @@ void detect_parameters(const int argc, const char *argv[], for (int i = 1; i < argc; i++) { if (!strncmp(argv[i], "quiet", 5)) { quiet = true; + } else if (!strncmp(argv[i], "silent", 6)) { + silent = true; } else if (!strncmp(argv[i], "verbose", 7)) { quiet = false; } else if (!strncmp(argv[i], "modules_pcimap=", 15)) { @@ -749,8 +754,8 @@ void detect_hardware(struct s_hardware *hardware) if (!quiet) more_printf("DMI: Detecting Table\n"); if (detect_dmi(hardware) == -ENODMITABLE) { - printf("DMI: ERROR ! Table not found ! \n"); - printf("DMI: Many hardware components will not be detected ! \n"); + more_printf("DMI: ERROR ! Table not found ! \n"); + more_printf("DMI: Many hardware components will not be detected ! \n"); } else { if (!quiet) more_printf("DMI: Table found ! (version %u.%u)\n", diff --git a/com32/hdt/hdt-common.h b/com32/hdt/hdt-common.h index 4a288b44..53aa43e7 100644 --- a/com32/hdt/hdt-common.h +++ b/com32/hdt/hdt-common.h @@ -84,6 +84,9 @@ struct upload_backend *upload; /* Defines if the cli is quiet*/ bool quiet; +/* Defines if the cli is totally silent*/ +bool silent; + /* Defines if we must use the vesa mode */ bool vesamode; @@ -111,16 +114,18 @@ extern bool disable_more_printf; * one \n (and only one) */ #define more_printf(...) do {\ - if (__likely(!disable_more_printf)) {\ - if (display_line_nb == max_console_lines) {\ - display_line_nb=0;\ - printf("\n--More--");\ - get_key(stdin, 0);\ - printf("\033[2K\033[1G\033[1F");\ + if (__likely(!silent)) {\ + if (__likely(!disable_more_printf)) {\ + if (display_line_nb == max_console_lines) {\ + display_line_nb=0;\ + printf("\n--More--");\ + get_key(stdin, 0);\ + printf("\033[2K\033[1G\033[1F");\ + }\ + display_line_nb++;\ }\ - display_line_nb++;\ + printf(__VA_ARGS__);\ }\ - printf(__VA_ARGS__);\ } while (0); /* Display CPU registers for debugging purposes */ diff --git a/com32/hdt/hdt-dump.c b/com32/hdt/hdt-dump.c index b963e19b..b1748c8e 100644 --- a/com32/hdt/hdt-dump.c +++ b/com32/hdt/hdt-dump.c @@ -156,7 +156,7 @@ void flush(ZZJSON_CONFIG * config, ZZJSON ** item) void dump(struct s_hardware *hardware) { if (hardware->is_pxe_valid == false) { - printf("PXE stack was not detected, Dump feature is not available\n"); + more_printf("PXE stack was not detected, Dump feature is not available\n"); return; } diff --git a/com32/hdt/hdt.c b/com32/hdt/hdt.c index 851b0462..653995d0 100644 --- a/com32/hdt/hdt.c +++ b/com32/hdt/hdt.c @@ -72,7 +72,7 @@ int main(const int argc, const char *argv[]) clear_screen(); printf("\033[1;1H"); - printf("%s\n", version_string); + more_printf("%s\n", version_string); int return_code = 0; @@ -86,7 +86,7 @@ int main(const int argc, const char *argv[]) /* Do we got request to do something at exit time ? */ if (strlen(hardware.postexec)>0) { - printf("Executing postexec instructions : %s\n",hardware.postexec); + more_printf("Executing postexec instructions : %s\n",hardware.postexec); runsyslinuxcmd(hardware.postexec); } diff --git a/com32/hdt/hdt.h b/com32/hdt/hdt.h index 041d726d..e385417a 100644 --- a/com32/hdt/hdt.h +++ b/com32/hdt/hdt.h @@ -33,7 +33,7 @@ #define AUTHOR "Erwan Velu" #define CORE_DEVELOPER "Pierre-Alexandre Meyer" #define CONTACT "hdt@zytor.com" -#define VERSION "0.5.2-pre2" +#define VERSION "0.5.2" #define CODENAME "Manon" #define NB_CONTRIBUTORS 3 #define CONTRIBUTORS {"Sebastien Gonzalve (Patches)", "Gert Hulselmans (Tests)", "Alexander Andino (Design)"} diff --git a/com32/lua/src/cpu.c b/com32/lua/src/cpu.c index 8a246e3d..6ef4e5a3 100644 --- a/com32/lua/src/cpu.c +++ b/com32/lua/src/cpu.c @@ -9,13 +9,13 @@ #include"lualib.h" #include"cpuid.h" -static void add_string_item(lua_State *L, const char *item, const char *value_str) { +void add_string_item(lua_State *L, const char *item, const char *value_str) { lua_pushstring(L,item); lua_pushstring(L,value_str); lua_settable(L,-3); } -static void add_int_item(lua_State *L, const char *item, int value_int) { +void add_int_item(lua_State *L, const char *item, int value_int) { lua_pushstring(L,item); lua_pushnumber(L,value_int); lua_settable(L,-3); diff --git a/com32/lua/src/dmi.c b/com32/lua/src/dmi.c index c8329d33..984fb60c 100644 --- a/com32/lua/src/dmi.c +++ b/com32/lua/src/dmi.c @@ -9,275 +9,487 @@ #include "lualib.h" #include "dmi/dmi.h" -static int dmi_gettable(lua_State *L) +extern void add_string_item(lua_State*, const char*, const char*); +extern void add_int_item(lua_State*, const char*, int); +typedef int (*table_fn)(lua_State*, s_dmi*); + +/* Add a Lua_String entry to the table on stack + xxx_P is the poiter version (i.e., pBase is a pointer) + xxx_S is the staic version (i.e., Base is the struct) +*/ +#define LUA_ADD_STR_P(pLua_state, pBase, Field) \ + add_string_item(pLua_state, #Field, pBase->Field); +#define LUA_ADD_STR_S(pLua_state, Base, Field) \ + add_string_item(pLua_state, #Field, Base.Field); + +/* Add a Lua_Number entry to the table on stack + xxx_P is the poiter version (i.e., pBase is a pointer) + xxx_S is the staic version (i.e., Base is the struct) +*/ +#define LUA_ADD_NUM_P(pLua_state, pBase, Field) \ + add_int_item(pLua_state, #Field, pBase->Field); +#define LUA_ADD_NUM_S(pLua_state, Base, Field) \ + add_int_item(pLua_state, #Field, Base.Field); + +/* Add a sub-DMI table to the table on stack + All (*table_fn)() have to be named as get_<tabel_name>_table() for this + macro to work. For example, for the bios subtable, the table_fn is + get_bios_table() and the subtable name is "bios". + All (*table_fn)() have to return 1 if a subtable is created on the stack + or 0 if the subtable is not created (no corresponding dim subtable found). +*/ +#define LUA_ADD_TABLE(pLua_state, pDmi, tb_name) \ + add_dmi_sub_table(pLua_state, pDmi, #tb_name, get_ ## tb_name ## _table); + + +static void add_dmi_sub_table(lua_State *L, s_dmi *dmi_ptr, char *table_name, + table_fn get_table_fn) { - s_dmi dmi; - - lua_newtable(L); - - if ( ! dmi_iterate(&dmi) ) { - printf("No DMI Structure found\n"); - return -1; + if (get_table_fn(L, dmi_ptr)) { /* only adding it when it is there */ + lua_pushstring(L, table_name); + lua_insert(L, -2); + lua_settable(L,-3); } +} - parse_dmitable(&dmi); - - /* bios */ - lua_pushstring(L, "bios.vendor"); - lua_pushstring(L, dmi.bios.vendor); - lua_settable(L,-3); - - lua_pushstring(L, "bios.version"); - lua_pushstring(L, dmi.bios.version); - lua_settable(L,-3); - - lua_pushstring(L, "bios.release_date"); - lua_pushstring(L, dmi.bios.release_date); - lua_settable(L,-3); - lua_pushstring(L, "bios.bios_revision"); - lua_pushstring(L, dmi.bios.bios_revision); - lua_settable(L,-3); +void get_bool_table(lua_State *L, const char *str_table[], int n_elem, + bool *bool_table) +{ + int i; + for (i = 0; i < n_elem; i++) { + if (!str_table[i] || !*str_table[i]) /* aviod NULL/empty string */ + continue; + + lua_pushstring(L, str_table[i]); + lua_pushboolean(L, bool_table[i]); + lua_settable(L,-3); + } +} - lua_pushstring(L, "bios.firmware_revision"); - lua_pushstring(L, dmi.bios.firmware_revision); - lua_settable(L,-3); - lua_pushstring(L, "bios.address"); - lua_pushnumber(L, dmi.bios.address); - lua_settable(L,-3); +/* +** {====================================================== +** DMI subtables +** ======================================================= +*/ +static int get_bios_table(lua_State *L, s_dmi *dmi_ptr) +{ + s_bios *bios = &dmi_ptr->bios; - lua_pushstring(L, "bios.runtime_size"); - lua_pushnumber(L, dmi.bios.runtime_size); + if (!bios->filled) + return 0; + /* bios */ + lua_newtable(L); + LUA_ADD_STR_P(L, bios, vendor) + LUA_ADD_STR_P(L, bios, version) + LUA_ADD_STR_P(L, bios, release_date) + LUA_ADD_STR_P(L, bios, bios_revision) + LUA_ADD_STR_P(L, bios, firmware_revision) + LUA_ADD_NUM_P(L, bios, address) + LUA_ADD_NUM_P(L, bios, runtime_size) + LUA_ADD_STR_P(L, bios, runtime_size_unit) + LUA_ADD_NUM_P(L, bios, rom_size) + LUA_ADD_STR_P(L, bios, rom_size_unit) + + /* bios characteristics */ + lua_pushstring(L, "chars"); + lua_newtable(L); + get_bool_table(L, bios_charac_strings, + sizeof(s_characteristics)/sizeof(bool), + (bool *)(&bios->characteristics)); + get_bool_table(L, bios_charac_x1_strings, + sizeof(s_characteristics_x1)/sizeof(bool), + (bool *)(&bios->characteristics_x1)); + get_bool_table(L, bios_charac_x2_strings, + sizeof(s_characteristics_x2)/sizeof(bool), + (bool *)(&bios->characteristics_x2)); lua_settable(L,-3); - lua_pushstring(L, "bios.runtime_size_unit"); - lua_pushstring(L, dmi.bios.runtime_size_unit); - lua_settable(L,-3); + return 1; +} - lua_pushstring(L, "bios.rom_size"); - lua_pushnumber(L, dmi.bios.rom_size); - lua_settable(L,-3); - lua_pushstring(L, "bios.rom_size_unit"); - lua_pushstring(L, dmi.bios.rom_size_unit); - lua_settable(L,-3); +static int get_system_table(lua_State *L, s_dmi *dmi_ptr) +{ + s_system *system = &dmi_ptr->system; + if (!system->filled) + return 0; /* system */ - lua_pushstring(L, "system.manufacturer"); - lua_pushstring(L, dmi.system.manufacturer); - lua_settable(L,-3); - - lua_pushstring(L, "system.product_name"); - lua_pushstring(L, dmi.system.product_name); - lua_settable(L,-3); - - lua_pushstring(L, "system.version"); - lua_pushstring(L, dmi.system.version); - lua_settable(L,-3); - - lua_pushstring(L, "system.serial"); - lua_pushstring(L, dmi.system.serial); - lua_settable(L,-3); - - lua_pushstring(L, "system.uuid"); - lua_pushstring(L, dmi.system.uuid); - lua_settable(L,-3); + lua_newtable(L); + LUA_ADD_STR_P(L, system, manufacturer) + LUA_ADD_STR_P(L, system, product_name) + LUA_ADD_STR_P(L, system, version) + LUA_ADD_STR_P(L, system, serial) + LUA_ADD_STR_P(L, system, uuid) + LUA_ADD_STR_P(L, system, wakeup_type) + LUA_ADD_STR_P(L, system, sku_number) + LUA_ADD_STR_P(L, system, family) + LUA_ADD_STR_P(L, system, system_boot_status) + LUA_ADD_STR_P(L, system, configuration_options) + + /* system reset */ + if (system->system_reset.filled) { + lua_pushstring(L, "reset"); + lua_newtable(L); + LUA_ADD_NUM_S(L, system->system_reset, status) + LUA_ADD_NUM_S(L, system->system_reset, watchdog) + LUA_ADD_STR_S(L, system->system_reset, boot_option) + LUA_ADD_STR_S(L, system->system_reset, boot_option_on_limit) + LUA_ADD_STR_S(L, system->system_reset, reset_count) + LUA_ADD_STR_S(L, system->system_reset, reset_limit) + LUA_ADD_STR_S(L, system->system_reset, timer_interval) + LUA_ADD_STR_S(L, system->system_reset, timeout) + lua_settable(L,-3); + } - lua_pushstring(L, "system.wakeup_type"); - lua_pushstring(L, dmi.system.wakeup_type); - lua_settable(L,-3); + return 1; +} - lua_pushstring(L, "system.sku_number"); - lua_pushstring(L, dmi.system.sku_number); - lua_settable(L,-3); - lua_pushstring(L, "system.family"); - lua_pushstring(L, dmi.system.family); - lua_settable(L,-3); +static int get_base_board_table(lua_State *L, s_dmi *dmi_ptr) +{ + s_base_board *base_board = &dmi_ptr->base_board; + int n_dev = sizeof(base_board->devices_information) / + sizeof(base_board->devices_information[0]); + int i, j, has_dev; + if (!base_board->filled) + return 0; /* base_board */ - lua_pushstring(L, "base_board.manufacturer"); - lua_pushstring(L, dmi.base_board.manufacturer); - lua_settable(L,-3); - - lua_pushstring(L, "base_board.product_name"); - lua_pushstring(L, dmi.base_board.product_name); - lua_settable(L,-3); + lua_newtable(L); + LUA_ADD_STR_P(L, base_board, manufacturer) + LUA_ADD_STR_P(L, base_board, product_name) + LUA_ADD_STR_P(L, base_board, version) + LUA_ADD_STR_P(L, base_board, serial) + LUA_ADD_STR_P(L, base_board, asset_tag) + LUA_ADD_STR_P(L, base_board, location) + LUA_ADD_STR_P(L, base_board, type) + + /* base board features */ + lua_pushstring(L, "features"); + lua_newtable(L); + get_bool_table(L, base_board_features_strings, + sizeof(s_base_board_features)/sizeof(bool), + (bool *)(&base_board->features)); + lua_settable(L,-3); + + /* on-board devices */ + for (has_dev = 0, i = 0; i < n_dev; i++) + if (*base_board->devices_information[i].type) + has_dev++; + + if (has_dev) { + lua_pushstring(L, "devices"); + lua_newtable(L); + for (i = 0, j = 1; i < n_dev; i++) { + if (!*base_board->devices_information[i].type) /* empty device */ + continue; + + lua_pushinteger(L, j++); + lua_newtable(L); + LUA_ADD_STR_S(L, base_board->devices_information[i], type) + LUA_ADD_STR_S(L, base_board->devices_information[i], description) + LUA_ADD_NUM_S(L, base_board->devices_information[i], status) + lua_settable(L,-3); + } + lua_settable(L,-3); + } - lua_pushstring(L, "base_board.version"); - lua_pushstring(L, dmi.base_board.version); - lua_settable(L,-3); + return 1; +} - lua_pushstring(L, "base_board.serial"); - lua_pushstring(L, dmi.base_board.serial); - lua_settable(L,-3); - lua_pushstring(L, "base_board.asset_tag"); - lua_pushstring(L, dmi.base_board.asset_tag); - lua_settable(L,-3); +static int get_chassis_table(lua_State *L, s_dmi *dmi_ptr) +{ + s_chassis *chassis = &dmi_ptr->chassis; - lua_pushstring(L, "base_board.location"); - lua_pushstring(L, dmi.base_board.location); - lua_settable(L,-3); + if (!chassis->filled) + return 0; + /* chassis */ + lua_newtable(L); + LUA_ADD_STR_P(L, chassis, manufacturer) + LUA_ADD_STR_P(L, chassis, type) + LUA_ADD_STR_P(L, chassis, lock) + LUA_ADD_STR_P(L, chassis, version) + LUA_ADD_STR_P(L, chassis, serial) + LUA_ADD_STR_P(L, chassis, asset_tag) + LUA_ADD_STR_P(L, chassis, boot_up_state) + LUA_ADD_STR_P(L, chassis, power_supply_state) + LUA_ADD_STR_P(L, chassis, thermal_state) + LUA_ADD_STR_P(L, chassis, security_status) + LUA_ADD_STR_P(L, chassis, oem_information) + LUA_ADD_NUM_P(L, chassis, height) + LUA_ADD_NUM_P(L, chassis, nb_power_cords) - lua_pushstring(L, "base_board.type"); - lua_pushstring(L, dmi.base_board.type); - lua_settable(L,-3); + return 1; +} - /* chassis */ - lua_pushstring(L, "chassis.manufacturer"); - lua_pushstring(L, dmi.chassis.manufacturer); - lua_settable(L,-3); - lua_pushstring(L, "chassis.type"); - lua_pushstring(L, dmi.chassis.type); - lua_settable(L,-3); +static int get_processor_table(lua_State *L, s_dmi *dmi_ptr) +{ + s_processor *processor = &dmi_ptr->processor; + s_signature *signature = &processor->signature; - lua_pushstring(L, "chassis.lock"); - lua_pushstring(L, dmi.chassis.lock); + if (!processor->filled) + return 0; + /* processor */ + lua_newtable(L); + LUA_ADD_STR_P(L, processor, socket_designation) + LUA_ADD_STR_P(L, processor, type) + LUA_ADD_STR_P(L, processor, family) + LUA_ADD_STR_P(L, processor, manufacturer) + LUA_ADD_STR_P(L, processor, version) + LUA_ADD_NUM_P(L, processor, external_clock) + LUA_ADD_NUM_P(L, processor, max_speed) + LUA_ADD_NUM_P(L, processor, current_speed) + LUA_ADD_NUM_P(L, processor, voltage_mv) + LUA_ADD_STR_P(L, processor, status) + LUA_ADD_STR_P(L, processor, upgrade) + LUA_ADD_STR_P(L, processor, cache1) + LUA_ADD_STR_P(L, processor, cache2) + LUA_ADD_STR_P(L, processor, cache3) + LUA_ADD_STR_P(L, processor, serial) + LUA_ADD_STR_P(L, processor, part_number) + LUA_ADD_STR_P(L, processor, id) + LUA_ADD_NUM_P(L, processor, core_count) + LUA_ADD_NUM_P(L, processor, core_enabled) + LUA_ADD_NUM_P(L, processor, thread_count) + + /* processor signature */ + lua_pushstring(L, "signature"); + lua_newtable(L); + LUA_ADD_NUM_P(L, signature, type) + LUA_ADD_NUM_P(L, signature, family) + LUA_ADD_NUM_P(L, signature, model) + LUA_ADD_NUM_P(L, signature, stepping) + LUA_ADD_NUM_P(L, signature, minor_stepping) lua_settable(L,-3); - lua_pushstring(L, "chassis.version"); - lua_pushstring(L, dmi.chassis.version); + /* processor flags */ + lua_pushstring(L, "flags"); + lua_newtable(L); + get_bool_table(L, cpu_flags_strings, + sizeof(s_dmi_cpu_flags)/sizeof(bool), + (bool *)(&processor->cpu_flags)); lua_settable(L,-3); - lua_pushstring(L, "chassis.serial"); - lua_pushstring(L, dmi.chassis.serial); - lua_settable(L,-3); + return 1; +} - lua_pushstring(L, "chassis.asset_tag"); - lua_pushstring(L, dmi.chassis.asset_tag); - lua_settable(L,-3); - lua_pushstring(L, "chassis.boot_up_state"); - lua_pushstring(L, dmi.chassis.boot_up_state); - lua_settable(L,-3); +static int get_battery_table(lua_State *L, s_dmi *dmi_ptr) +{ + s_battery *battery = &dmi_ptr->battery; - lua_pushstring(L, "chassis.power_supply_state"); - lua_pushstring(L, dmi.chassis.power_supply_state); - lua_settable(L,-3); + if (!battery->filled) + return 0; + /* battery */ + lua_newtable(L); + LUA_ADD_STR_P(L, battery, location) + LUA_ADD_STR_P(L, battery, manufacturer) + LUA_ADD_STR_P(L, battery, manufacture_date) + LUA_ADD_STR_P(L, battery, serial) + LUA_ADD_STR_P(L, battery, name) + LUA_ADD_STR_P(L, battery, chemistry) + LUA_ADD_STR_P(L, battery, design_capacity) + LUA_ADD_STR_P(L, battery, design_voltage) + LUA_ADD_STR_P(L, battery, sbds) + LUA_ADD_STR_P(L, battery, sbds_serial) + LUA_ADD_STR_P(L, battery, maximum_error) + LUA_ADD_STR_P(L, battery, sbds_manufacture_date) + LUA_ADD_STR_P(L, battery, sbds_chemistry) + LUA_ADD_STR_P(L, battery, oem_info) - lua_pushstring(L, "chassis.thermal_state"); - lua_pushstring(L, dmi.chassis.thermal_state); - lua_settable(L,-3); + return 1; +} - lua_pushstring(L, "chassis.security_status"); - lua_pushstring(L, dmi.chassis.security_status); - lua_settable(L,-3); - lua_pushstring(L, "chassis.oem_information"); - lua_pushstring(L, dmi.chassis.oem_information); - lua_settable(L,-3); +static int get_memory_table(lua_State *L, s_dmi *dmi_ptr) +{ + s_memory *memory = dmi_ptr->memory; + int i, j, n_mem = dmi_ptr->memory_count; - lua_pushstring(L, "chassis.height"); - lua_pushnumber(L, dmi.chassis.height); - lua_settable(L,-3); + if (n_mem <= 0) /* no memory info */ + return 0; - lua_pushstring(L, "chassis.nb_power_cords"); - lua_pushnumber(L, dmi.chassis.nb_power_cords); - lua_settable(L,-3); + /* memory */ + lua_newtable(L); + for (j = 1, i = 0; i < n_mem; i++) { + if (!memory[i].filled) + continue; + + lua_pushinteger(L, j++); + lua_newtable(L); + LUA_ADD_STR_S(L, memory[i], manufacturer) + LUA_ADD_STR_S(L, memory[i], error) + LUA_ADD_STR_S(L, memory[i], total_width) + LUA_ADD_STR_S(L, memory[i], data_width) + LUA_ADD_STR_S(L, memory[i], size) + LUA_ADD_STR_S(L, memory[i], form_factor) + LUA_ADD_STR_S(L, memory[i], device_set) + LUA_ADD_STR_S(L, memory[i], device_locator) + LUA_ADD_STR_S(L, memory[i], bank_locator) + LUA_ADD_STR_S(L, memory[i], type) + LUA_ADD_STR_S(L, memory[i], type_detail) + LUA_ADD_STR_S(L, memory[i], speed) + LUA_ADD_STR_S(L, memory[i], serial) + LUA_ADD_STR_S(L, memory[i], asset_tag) + LUA_ADD_STR_S(L, memory[i], part_number) + lua_settable(L,-3); + } + return 1; +} - /* processor */ - lua_pushstring(L, "processor.socket_designation"); - lua_pushstring(L, dmi.processor.socket_designation); - lua_settable(L,-3); - lua_pushstring(L, "processor.type"); - lua_pushstring(L, dmi.processor.type); - lua_settable(L,-3); +static int get_memory_module_table(lua_State *L, s_dmi *dmi_ptr) +{ + s_memory_module *memory_module = dmi_ptr->memory_module; + int i, j, n_mem = dmi_ptr->memory_module_count; - lua_pushstring(L, "processor.family"); - lua_pushstring(L, dmi.processor.family); - lua_settable(L,-3); + if (n_mem <= 0) /* no memory module info */ + return 0; - lua_pushstring(L, "processor.manufacturer"); - lua_pushstring(L, dmi.processor.manufacturer); - lua_settable(L,-3); + /* memory module */ + lua_newtable(L); + for (j = 1, i = 0; i < n_mem; i++) { + if (!memory_module[i].filled) + continue; + + lua_pushinteger(L, j++); + lua_newtable(L); + LUA_ADD_STR_S(L, memory_module[i], socket_designation) + LUA_ADD_STR_S(L, memory_module[i], bank_connections) + LUA_ADD_STR_S(L, memory_module[i], speed) + LUA_ADD_STR_S(L, memory_module[i], type) + LUA_ADD_STR_S(L, memory_module[i], installed_size) + LUA_ADD_STR_S(L, memory_module[i], enabled_size) + LUA_ADD_STR_S(L, memory_module[i], error_status) + lua_settable(L,-3); + } + return 1; +} - lua_pushstring(L, "processor.version"); - lua_pushstring(L, dmi.processor.version); - lua_settable(L,-3); - lua_pushstring(L, "processor.external_clock"); - lua_pushnumber(L, dmi.processor.external_clock); - lua_settable(L,-3); +static int get_cache_table(lua_State *L, s_dmi *dmi_ptr) +{ + s_cache *cache = dmi_ptr->cache; + int i, n_cache = dmi_ptr->cache_count; - lua_pushstring(L, "processor.max_speed"); - lua_pushnumber(L, dmi.processor.max_speed); - lua_settable(L,-3); + if (n_cache <= 0) /* no cache info */ + return 0; - lua_pushstring(L, "processor.current_speed"); - lua_pushnumber(L, dmi.processor.current_speed); - lua_settable(L,-3); + /* memory */ + lua_newtable(L); + for (i = 0; i < n_cache; i++) { + lua_pushinteger(L, i + 1); + lua_newtable(L); + LUA_ADD_STR_S(L, cache[i], socket_designation) + LUA_ADD_STR_S(L, cache[i], configuration) + LUA_ADD_STR_S(L, cache[i], mode) + LUA_ADD_STR_S(L, cache[i], location) + LUA_ADD_NUM_S(L, cache[i], installed_size) + LUA_ADD_NUM_S(L, cache[i], max_size) + LUA_ADD_STR_S(L, cache[i], supported_sram_types) + LUA_ADD_STR_S(L, cache[i], installed_sram_types) + LUA_ADD_NUM_S(L, cache[i], speed) + LUA_ADD_STR_S(L, cache[i], error_correction_type) + LUA_ADD_STR_S(L, cache[i], system_type) + LUA_ADD_STR_S(L, cache[i], associativity) + lua_settable(L,-3); + } + return 1; +} - lua_pushstring(L, "processor.signature.type"); - lua_pushnumber(L, dmi.processor.signature.type); - lua_settable(L,-3); - lua_pushstring(L, "processor.signature.family"); - lua_pushnumber(L, dmi.processor.signature.family); - lua_settable(L,-3); +static int get_hardware_security_table(lua_State *L, s_dmi *dmi_ptr) +{ + if (!dmi_ptr->hardware_security.filled) + return 0; + /* hardware_security */ + lua_newtable(L); + LUA_ADD_STR_S(L, dmi_ptr->hardware_security, power_on_passwd_status) + LUA_ADD_STR_S(L, dmi_ptr->hardware_security, keyboard_passwd_status) + LUA_ADD_STR_S(L, dmi_ptr->hardware_security, administrator_passwd_status) + LUA_ADD_STR_S(L, dmi_ptr->hardware_security, front_panel_reset_status) - lua_pushstring(L, "processor.signature.model"); - lua_pushnumber(L, dmi.processor.signature.model); - lua_settable(L,-3); + return 1; +} - lua_pushstring(L, "processor.signature.stepping"); - lua_pushnumber(L, dmi.processor.signature.stepping); - lua_settable(L,-3); - lua_pushstring(L, "processor.signature.minor_stepping"); - lua_pushnumber(L, dmi.processor.signature.minor_stepping); - lua_settable(L,-3); +static int get_dmi_info_table(lua_State *L, s_dmi *dmi_ptr) +{ + dmi_table *dmitable = &dmi_ptr->dmitable; - lua_pushstring(L, "processor.voltage_mv"); - lua_pushnumber(L, dmi.processor.voltage_mv); - lua_settable(L,-3); + /* dmi info */ + lua_newtable(L); + LUA_ADD_NUM_P(L, dmitable, num) + LUA_ADD_NUM_P(L, dmitable, len) + LUA_ADD_NUM_P(L, dmitable, ver) + LUA_ADD_NUM_P(L, dmitable, base) + LUA_ADD_NUM_P(L, dmitable, major_version) + LUA_ADD_NUM_P(L, dmitable, minor_version) - lua_pushstring(L, "processor.status"); - lua_pushstring(L, dmi.processor.status); - lua_settable(L,-3); + return 1; +} - lua_pushstring(L, "processor.upgrade"); - lua_pushstring(L, dmi.processor.upgrade); - lua_settable(L,-3); - lua_pushstring(L, "processor.cache1"); - lua_pushstring(L, dmi.processor.cache1); - lua_settable(L,-3); +static int get_ipmi_table(lua_State *L, s_dmi *dmi_ptr) +{ + s_ipmi *ipmi = &dmi_ptr->ipmi; - lua_pushstring(L, "processor.cache2"); - lua_pushstring(L, dmi.processor.cache2); - lua_settable(L,-3); + if (!ipmi->filled) + return 0; + /* ipmi */ + lua_newtable(L); + LUA_ADD_STR_P(L, ipmi, interface_type) + LUA_ADD_NUM_P(L, ipmi, major_specification_version) + LUA_ADD_NUM_P(L, ipmi, minor_specification_version) + LUA_ADD_NUM_P(L, ipmi, I2C_slave_address) + LUA_ADD_NUM_P(L, ipmi, nv_address) + LUA_ADD_NUM_P(L, ipmi, base_address) + LUA_ADD_NUM_P(L, ipmi, irq) - lua_pushstring(L, "processor.cache3"); - lua_pushstring(L, dmi.processor.cache3); - lua_settable(L,-3); + return 1; +} +/* +** {====================================================== +** End of DMI subtables +** ======================================================= +*/ - lua_pushstring(L, "processor.serial"); - lua_pushstring(L, dmi.processor.serial); - lua_settable(L,-3); - lua_pushstring(L, "processor.part_number"); - lua_pushstring(L, dmi.processor.part_number); - lua_settable(L,-3); +static int dmi_gettable(lua_State *L) +{ + s_dmi dmi; - lua_pushstring(L, "processor.id"); - lua_pushstring(L, dmi.processor.id); - lua_settable(L,-3); + lua_newtable(L); - lua_pushstring(L, "processor.core_count"); - lua_pushnumber(L, dmi.processor.core_count); - lua_settable(L,-3); + if ( ! dmi_iterate(&dmi) ) { + printf("No DMI Structure found\n"); + return -1; + } - lua_pushstring(L, "processor.core_enabled"); - lua_pushnumber(L, dmi.processor.core_enabled); - lua_settable(L,-3); + parse_dmitable(&dmi); - lua_pushstring(L, "processor.thread_count"); - lua_pushnumber(L, dmi.processor.thread_count); - lua_settable(L,-3); + LUA_ADD_NUM_S(L, dmi, memory_module_count) + LUA_ADD_NUM_S(L, dmi, memory_count) + LUA_ADD_NUM_S(L, dmi, cache_count) + LUA_ADD_STR_S(L, dmi, oem_strings) + + LUA_ADD_TABLE(L, &dmi, bios) + LUA_ADD_TABLE(L, &dmi, system) + LUA_ADD_TABLE(L, &dmi, base_board) + LUA_ADD_TABLE(L, &dmi, chassis) + LUA_ADD_TABLE(L, &dmi, processor) + LUA_ADD_TABLE(L, &dmi, battery) + LUA_ADD_TABLE(L, &dmi, memory) + LUA_ADD_TABLE(L, &dmi, memory_module) + LUA_ADD_TABLE(L, &dmi, cache) + LUA_ADD_TABLE(L, &dmi, ipmi) + LUA_ADD_TABLE(L, &dmi, hardware_security) + LUA_ADD_TABLE(L, &dmi, dmi_info) /* set global variable: lua_setglobal(L, "dmitable"); */ diff --git a/com32/lua/src/liolib.c b/com32/lua/src/liolib.c index 3f27395d..cf9dca22 100644 --- a/com32/lua/src/liolib.c +++ b/com32/lua/src/liolib.c @@ -18,12 +18,18 @@ #include "lauxlib.h" #include "lualib.h" - +#ifdef SYSLINUX + #define NO_TMP_FILE 1 + #define NO_READ_NUMBER 1 + #define NO_TEST_EOF 1 + #define NO_CLEAR_ERR 1 + #define NO_F_SEEK 1 + #define NO_F_SETVBUF 1 +#endif #define IO_INPUT 1 #define IO_OUTPUT 2 - static const char *const fnames[] = {"input", "output"}; @@ -180,7 +186,7 @@ static int io_popen (lua_State *L) { } -#ifndef SYSLINUX +#ifndef NO_TMP_FILE static int io_tmpfile (lua_State *L) { FILE **pf = newfile(L); *pf = tmpfile(); @@ -271,7 +277,7 @@ static int io_lines (lua_State *L) { ** ======================================================= */ -#ifndef SYSLINUX +#ifndef NO_READ_NUMBER /* No fscanf() and thus no read_number() */ static int read_number (lua_State *L, FILE *f) { lua_Number d; if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) { @@ -283,8 +289,9 @@ static int read_number (lua_State *L, FILE *f) { return 0; /* read fails */ } } +#endif - +#ifndef NO_TEST_EOF /* no buffering -> no ungetc() -> no EOF test */ static int test_eof (lua_State *L, FILE *f) { int c = getc(f); ungetc(c, f); @@ -315,7 +322,6 @@ static int read_line (lua_State *L, FILE *f) { } } -#ifndef SYSLINUX /* Not used */ static int read_chars (lua_State *L, FILE *f, size_t n) { size_t rlen; /* how much to read */ size_t nr; /* number of chars actually read */ @@ -337,7 +343,9 @@ static int g_read (lua_State *L, FILE *f, int first) { int nargs = lua_gettop(L) - 1; int success; int n; +#ifndef NO_CLEAR_ERR clearerr(f); +#endif if (nargs == 0) { /* no arguments? */ success = read_line(L, f); n = first+1; /* to return 1 result */ @@ -348,14 +356,22 @@ static int g_read (lua_State *L, FILE *f, int first) { for (n = first; nargs-- && success; n++) { if (lua_type(L, n) == LUA_TNUMBER) { size_t l = (size_t)lua_tointeger(L, n); +#ifndef NO_TEST_EOF success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); +#else /* we don't have test_eof defined */ + success = (l == 0) ? 1 : read_chars(L, f, l); +#endif } else { const char *p = lua_tostring(L, n); luaL_argcheck(L, p && p[0] == '*', n, "invalid option"); switch (p[1]) { case 'n': /* number */ +#ifndef NO_READ_NUMBER success = read_number(L, f); +#else + return luaL_argerror(L, n, "\"*number\" not supported"); +#endif break; case 'l': /* line */ success = read_line(L, f); @@ -388,7 +404,6 @@ static int io_read (lua_State *L) { static int f_read (lua_State *L) { return g_read(L, tofile(L), 2); } -#endif static int io_readline (lua_State *L) { @@ -441,7 +456,7 @@ static int f_write (lua_State *L) { return g_write(L, tofile(L), 2); } -#ifndef SYSLINUX +#ifndef NO_F_SEEK static int f_seek (lua_State *L) { static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; static const char *const modenames[] = {"set", "cur", "end", NULL}; @@ -456,8 +471,9 @@ static int f_seek (lua_State *L) { return 1; } } +#endif - +#ifndef NO_F_SETVBUF static int f_setvbuf (lua_State *L) { static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; static const char *const modenames[] = {"no", "full", "line", NULL}; @@ -488,8 +504,8 @@ static const luaL_Reg iolib[] = { {"open", io_open}, {"output", io_output}, {"popen", io_popen}, -#ifndef SYSLINUX {"read", io_read}, +#ifndef NO_TMP_FILE {"tmpfile", io_tmpfile}, #endif {"type", io_type}, @@ -502,9 +518,11 @@ static const luaL_Reg flib[] = { {"close", io_close}, {"flush", f_flush}, {"lines", f_lines}, -#ifndef SYSLINUX {"read", f_read}, +#ifndef NO_F_SEEK {"seek", f_seek}, +#endif +#ifndef NO_F_SETVBUF {"setvbuf", f_setvbuf}, #endif {"write", f_write}, diff --git a/com32/lua/src/syslinux.c b/com32/lua/src/syslinux.c index af5db834..afcdcaad 100644 --- a/com32/lua/src/syslinux.c +++ b/com32/lua/src/syslinux.c @@ -39,6 +39,7 @@ #include "syslinux/loadfile.h" #include "syslinux/linux.h" #include "syslinux/config.h" +#include "syslinux/reboot.h" int __parse_argv(char ***argv, const char *str); @@ -408,6 +409,35 @@ static int sl_boot_it(lua_State * L) initramfs, NULL, (char *)cmdline); } +static int sl_config_file(lua_State * L) +{ + const char *config_file = syslinux_config_file(); + lua_pushstring(L, config_file); + return 1; +} + +static int sl_reboot(lua_State * L) +{ + int warm_boot = luaL_optint(L, 1, 0); + /* explicitly convert it to 1 or 0 */ + warm_boot = warm_boot? 1 : 0; + syslinux_reboot(warm_boot); + return 0; +} + +static int sl_ipappend_strs(lua_State * L) +{ + int i; + const struct syslinux_ipappend_strings *ip_strs = syslinux_ipappend_strings(); + lua_newtable(L); + for (i = 0; i < ip_strs->count; i++) { + lua_pushinteger(L, i + 1); + lua_pushstring(L, ip_strs->ptr[i]); + lua_settable(L,-3); + } + return 1; +} + static int sl_derivative(lua_State * L) { const struct syslinux_version *sv; @@ -459,6 +489,9 @@ static const luaL_reg syslinuxlib[] = { {"initramfs_load_archive", sl_initramfs_load_archive}, {"initramfs_add_file", sl_initramfs_add_file}, {"boot_it", sl_boot_it}, + {"config_file", sl_config_file}, + {"ipappend_strs", sl_ipappend_strs}, + {"reboot", sl_reboot}, {"derivative", sl_derivative}, {"version", sl_version}, {NULL, NULL} diff --git a/com32/mboot/mboot.c b/com32/mboot/mboot.c index 35450e03..10e6701c 100644 --- a/com32/mboot/mboot.c +++ b/com32/mboot/mboot.c @@ -198,7 +198,7 @@ int main(int argc, char *argv[]) } if (init_map()) - return 1; /* Failed to allocate intitial map */ + return 1; /* Failed to allocate initial map */ /* * Map the primary image. This should be done before mapping anything diff --git a/com32/menu/menumain.c b/com32/menu/menumain.c index c9762b27..487f8299 100644 --- a/com32/menu/menumain.c +++ b/com32/menu/menumain.c @@ -808,7 +808,7 @@ static const char *run_menu(void) while (entry < cm->nentries && is_disabled(cm->menu_entries[entry])) entry++; } - if (entry >= cm->nentries) { + if (entry >= cm->nentries - 1) { entry = cm->nentries - 1; while (entry > 0 && is_disabled(cm->menu_entries[entry])) entry--; diff --git a/com32/menu/readconfig.c b/com32/menu/readconfig.c index 69f524c4..cffe8e3d 100644 --- a/com32/menu/readconfig.c +++ b/com32/menu/readconfig.c @@ -392,7 +392,9 @@ static void record(struct menu *m, struct labeldata *ld, const char *append) break; } - if (ld->menudefault && me->action == MA_CMD) + if (ld->menudefault && (me->action == MA_CMD || + me->action == MA_GOTO || + me->action == MA_GOTO_UNRES)) m->defentry = m->nentries - 1; } diff --git a/com32/modules/Makefile b/com32/modules/Makefile index 392c720f..d87127dc 100644 --- a/com32/modules/Makefile +++ b/com32/modules/Makefile @@ -15,10 +15,6 @@ ## COM32 standard modules ## -LIBS = $(objdir)/com32/gpllib/libcom32gpl.c32 \ - $(objdir)/com32/lib/libcom32.c32 \ - $(objdir)/com32/libutil/libutil_com.c32 - VPATH = $(SRC) include $(MAKEDIR)/elf.mk @@ -27,7 +23,7 @@ MODULES = config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 \ meminfo.c32 sdi.c32 sanboot.c32 ifcpu64.c32 vesainfo.c32 \ kbdmap.c32 cmd.c32 vpdtest.c32 host.c32 ls.c32 gpxecmd.c32 \ ifcpu.c32 cpuid.c32 cat.c32 pwd.c32 ifplop.c32 zzjson.c32 \ - whichsys.c32 hello.c32 pxechn.c32 + whichsys.c32 prdhcp.c32 pxechn.c32 kontron_wdt.c32 ifmemdsk.c32 TESTFILES = @@ -37,7 +33,7 @@ all: $(MODULES) $(TESTFILES) dmitest.o: dmitest.c $(CC) $(CFLAGS) $(GPLINCLUDE) -c -o $@ $< -dmitest.c32 : dmi_utils.o dmitest.o $(GPLLIB) $(LIBS) $(C_LIBS) +dmitest.c32 : dmi_utils.o dmitest.o $(C_LIBS) $(LD) $(LDFLAGS) -o $@ $^ tidy dist: diff --git a/com32/modules/hello.c b/com32/modules/hello.c deleted file mode 100644 index d3d4d299..00000000 --- a/com32/modules/hello.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - * hello.c - A simple ELF module that sorts a couple of numbers - * - * Created on: Aug 11, 2008 - * Author: Stefan Bucur <stefanb@zytor.com> - */ - -#include <stdio.h> -#include <stdlib.h> - -#include "sort.h" - -#define NUM_COUNT 10 -#define MAX_NUM 100 - -int main(int argc __unused, char **argv __unused) -{ - int *nums = NULL; - - nums = malloc(NUM_COUNT * sizeof(int)); - printf("Hello, world, from 0x%08X! malloc return %p\n", (unsigned int)&main, nums); - - free(nums); - - return 0; -} diff --git a/com32/modules/kontron_wdt.c b/com32/modules/kontron_wdt.c new file mode 100644 index 00000000..4e1d2535 --- /dev/null +++ b/com32/modules/kontron_wdt.c @@ -0,0 +1,414 @@ +/* + * kempld_wdt.c - Kontron PLD watchdog driver + * + * Copyright (c) 2010 Kontron Embedded Modules GmbH + * Author: Michael Brunner <michael.brunner@kontron.com> + * Author: Erwan Velu <erwan.velu@zodiacaerospace.com> + * + * Note: From the PLD watchdog point of view timeout and pretimeout are + * defined differently than in the kernel. + * First the pretimeout stage runs out before the timeout stage gets + * active. This has to be kept in mind. + * + * Kernel/API: P-----| pretimeout + * |-----------------------T timeout + * Watchdog: |-----------------P pretimeout_stage + * |-----T timeout_stage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <string.h> +#include <sys/io.h> +#include <unistd.h> +#include <syslinux/boot.h> +#include <stdio.h> +#include <stdlib.h> +#include <console.h> +#include "kontron_wdt.h" + +struct kempld_device_data pld; +struct kempld_watchdog_data wdt; +uint8_t status; +char default_label[255]; + +/* Default Timeout is 60sec */ +#define TIMEOUT 60 +#define PRETIMEOUT 0 + +#define do_div(n,base) ({ \ + int __res; \ + __res = ((unsigned long) n) % (unsigned) base; \ + n = ((unsigned long) n) / (unsigned) base; \ + __res; }) + + +/* Basic Wrappers to get code as less changed as possible */ +void iowrite8(uint8_t val, uint16_t addr) { outb(val,addr); } +void iowrite16(uint16_t val, uint16_t addr) { outw(val,addr); } +void iowrite32(uint32_t val, uint16_t addr) { outl(val,addr);} +uint8_t ioread8(uint16_t addr) { return inb(addr);} +uint16_t ioread16(uint16_t addr) { return inw(addr);} +uint32_t ioread32(uint32_t addr) { return inl(addr);} + + +/** + * kempld_set_index - change the current register index of the PLD + * @pld: kempld_device_data structure describing the PLD + * @index: register index on the chip + * + * This function changes the register index of the PLD. + */ +void kempld_set_index(struct kempld_device_data *pld, uint8_t index) +{ + if (pld->last_index != index) { + iowrite8(index, pld->io_index); + pld->last_index = index; + } +} + + +uint8_t kempld_read8(struct kempld_device_data *pld, uint8_t index) { + kempld_set_index(pld, index); + return ioread8(pld->io_data); +} + + +void kempld_write8(struct kempld_device_data *pld, uint8_t index, uint8_t data) { + kempld_set_index(pld, index); + iowrite8(data, pld->io_data); +} + + +uint16_t kempld_read16(struct kempld_device_data *pld, uint8_t index) +{ + return kempld_read8(pld, index) | kempld_read8(pld, index+1) << 8; +} + + +void kempld_write16(struct kempld_device_data *pld, uint8_t index, uint16_t data) +{ + kempld_write8(pld, index, (uint8_t)data); + kempld_write8(pld, index+1, (uint8_t)(data>>8)); +} + +uint32_t kempld_read32(struct kempld_device_data *pld, uint8_t index) +{ + return kempld_read16(pld, index) | kempld_read16(pld, index+2) << 16; +} + +void kempld_write32(struct kempld_device_data *pld, uint8_t index, uint32_t data) +{ + kempld_write16(pld, index, (uint16_t)data); + kempld_write16(pld, index+2, (uint16_t)(data>>16)); +} + +static void kempld_release_mutex(struct kempld_device_data *pld) +{ + iowrite8(pld->last_index | KEMPLD_MUTEX_KEY, pld->io_index); +} + +void init_structure(void) { + /* set default values for the case we start the watchdog or change + * the configuration */ + memset(&wdt,0,sizeof(wdt)); + memset(&pld,0,sizeof(pld)); + memset(&default_label,0,sizeof(default_label)); + wdt.timeout = TIMEOUT; + wdt.pretimeout = PRETIMEOUT; + wdt.pld = &pld; + + pld.io_base=KEMPLD_IOPORT; + pld.io_index=KEMPLD_IOPORT; + pld.io_data=KEMPLD_IODATA; + pld.pld_clock=33333333; +} + +static int kempld_probe(void) { + /* Check for empty IO space */ + int ret=0; + uint8_t index_reg = ioread8(pld.io_index); + if ((index_reg == 0xff) && (ioread8(pld.io_data) == 0xff)) { + ret = 1; + goto err_empty_io; + } + printf("Kempld structure found at 0x%X (data @ 0x%X)\n",pld.io_base,pld.io_data); + return 0; + +err_empty_io: + printf("No IO Found !\n"); + return ret; +} + +static int kempld_wdt_probe_stages(struct kempld_watchdog_data *wdt) +{ + struct kempld_device_data *pld = wdt->pld; + int i, ret; + uint32_t timeout; + uint32_t timeout_mask; + struct kempld_watchdog_stage *stage; + + wdt->stages = 0; + wdt->timeout_stage = NULL; + wdt->pretimeout_stage = NULL; + + for (i = 0; i < KEMPLD_WDT_MAX_STAGES; i++) { + + timeout = kempld_read32(pld, KEMPLD_WDT_STAGE_TIMEOUT(i)); + kempld_write32(pld, KEMPLD_WDT_STAGE_TIMEOUT(i), 0x00000000); + timeout_mask = kempld_read32(pld, KEMPLD_WDT_STAGE_TIMEOUT(i)); + kempld_write32(pld, KEMPLD_WDT_STAGE_TIMEOUT(i), timeout); + + if (timeout_mask != 0xffffffff) { + stage = malloc(sizeof(struct kempld_watchdog_stage)); + if (stage == NULL) { + ret = -1; + goto err_alloc_stages; + } + stage->num = i; + stage->timeout_mask = ~timeout_mask; + wdt->stage[i] = stage; + wdt->stages++; + + /* assign available stages to timeout and pretimeout */ + if (wdt->stages == 1) + wdt->timeout_stage = stage; + else if (wdt->stages == 2) { + wdt->pretimeout_stage = wdt->timeout_stage; + wdt->timeout_stage = stage; + } + } else { + wdt->stage[i] = NULL; + } + } + + return 0; +err_alloc_stages: + kempld_release_mutex(pld); + printf("Cannot allocate stages\n"); + return ret; +} + +static int kempld_wdt_keepalive(struct kempld_watchdog_data *wdt) +{ + struct kempld_device_data *pld = wdt->pld; + + kempld_write8(pld, KEMPLD_WDT_KICK, 'K'); + + return 0; +} + +static int kempld_wdt_setstageaction(struct kempld_watchdog_data *wdt, + struct kempld_watchdog_stage *stage, + int action) +{ + struct kempld_device_data *pld = wdt->pld; + uint8_t stage_cfg; + + if (stage == NULL) + return -1; + + stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->num)); + stage_cfg &= ~KEMPLD_WDT_STAGE_CFG_ACTION_MASK; + stage_cfg |= (action & KEMPLD_WDT_STAGE_CFG_ACTION_MASK); + if (action == KEMPLD_WDT_ACTION_RESET) + stage_cfg |= KEMPLD_WDT_STAGE_CFG_ASSERT; + else + stage_cfg &= ~KEMPLD_WDT_STAGE_CFG_ASSERT; + + kempld_write8(pld, KEMPLD_WDT_STAGE_CFG(stage->num), stage_cfg); + stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->num)); + + return 0; +} + +static int kempld_wdt_setstagetimeout(struct kempld_watchdog_data *wdt, + struct kempld_watchdog_stage *stage, + int timeout) +{ + struct kempld_device_data *pld = wdt->pld; + uint8_t stage_cfg; + uint8_t prescaler; + uint64_t stage_timeout64; + uint32_t stage_timeout; + + if (stage == NULL) + return -1; + + prescaler = KEMPLD_WDT_PRESCALER_21BIT; + + stage_timeout64 = ((uint64_t)timeout*pld->pld_clock); + do_div(stage_timeout64, KEMPLD_PRESCALER(prescaler)); + stage_timeout = stage_timeout64 & stage->timeout_mask; + + if (stage_timeout64 != (uint64_t)stage_timeout) + return -1; + + stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->num)); + stage_cfg &= ~KEMPLD_WDT_STAGE_CFG_PRESCALER_MASK; + stage_cfg |= KEMPLD_WDT_STAGE_CFG_SET_PRESCALER(prescaler); + kempld_write8(pld, KEMPLD_WDT_STAGE_CFG(stage->num), stage_cfg); + kempld_write32(pld, KEMPLD_WDT_STAGE_TIMEOUT(stage->num), + stage_timeout); + + return 0; +} + + +static int kempld_wdt_settimeout(struct kempld_watchdog_data *wdt) +{ + int stage_timeout; + int stage_pretimeout; + int ret; + if ((wdt->timeout <= 0) || + (wdt->pretimeout < 0) || + (wdt->pretimeout > wdt->timeout)) { + ret = -1; + goto err_check_values; + } + + if ((wdt->pretimeout == 0) || (wdt->pretimeout_stage == NULL)) { + if (wdt->pretimeout != 0) + printf("No pretimeout stage available, only enabling reset!\n"); + stage_pretimeout = 0; + stage_timeout = wdt->timeout; + } else { + stage_pretimeout = wdt->timeout - wdt->pretimeout; + stage_timeout = wdt->pretimeout; + } + + if (stage_pretimeout != 0) { + ret = kempld_wdt_setstageaction(wdt, wdt->pretimeout_stage, + KEMPLD_WDT_ACTION_NMI); + } else if ((stage_pretimeout == 0) + && (wdt->pretimeout_stage != NULL)) { + ret = kempld_wdt_setstageaction(wdt, wdt->pretimeout_stage, + KEMPLD_WDT_ACTION_NONE); + } else + ret = 0; + if (ret) + goto err_setstage; + + if (stage_pretimeout != 0) { + ret = kempld_wdt_setstagetimeout(wdt, wdt->pretimeout_stage, + stage_pretimeout); + if (ret) + goto err_setstage; + } + + ret = kempld_wdt_setstageaction(wdt, wdt->timeout_stage, + KEMPLD_WDT_ACTION_RESET); + if (ret) + goto err_setstage; + + ret = kempld_wdt_setstagetimeout(wdt, wdt->timeout_stage, + stage_timeout); + if (ret) + goto err_setstage; + + return 0; +err_setstage: +err_check_values: + return ret; +} + +static int kempld_wdt_start(struct kempld_watchdog_data *wdt) +{ + struct kempld_device_data *pld = wdt->pld; + uint8_t status; + + status = kempld_read8(pld, KEMPLD_WDT_CFG); + status |= KEMPLD_WDT_CFG_ENABLE; + kempld_write8(pld, KEMPLD_WDT_CFG, status); + status = kempld_read8(pld, KEMPLD_WDT_CFG); + + /* check if the watchdog was enabled */ + if (!(status & KEMPLD_WDT_CFG_ENABLE)) + return -1; + + return 0; +} + +/* A regular configuration file looks like + + LABEL WDT + COM32 wdt.c32 + APPEND timeout=120 default_label=local +*/ +void detect_parameters(const int argc, const char *argv[]) { + for (int i = 1; i < argc; i++) { + /* Override the timeout if specified on the cmdline */ + if (!strncmp(argv[i], "timeout=", 8)) { + wdt.timeout=atoi(argv[i]+8); + } else + /* Define which boot entry shall be used */ + if (!strncmp(argv[i], "default_label=", 14)) { + strlcpy(default_label, argv[i] + 14, sizeof(default_label)); + } + } +} + +int main(int argc, const char *argv[]) { + int ret=0; + openconsole(&dev_rawcon_r, &dev_stdcon_w); + init_structure(); + detect_parameters(argc,argv); + kempld_probe(); + + /* probe how many usable stages we have */ + if (kempld_wdt_probe_stages(&wdt)) { + printf("Cannot Probe Stages\n"); + return -1; + } + + /* Useless but who knows */ + wdt.ident.firmware_version = KEMPLD_WDT_REV_GET(kempld_read8(&pld, KEMPLD_WDT_REV)); + + status = kempld_read8(&pld, KEMPLD_WDT_CFG); + /* kick the watchdog if it is already enabled, otherwise start it */ + if (status & KEMPLD_WDT_CFG_ENABLE) { + /* Maybye the BIOS did setup a first timer + * in this case, let's enforce the timeout + * to be sure we do have the proper value */ + kempld_wdt_settimeout(&wdt); + kempld_wdt_keepalive(&wdt); + } else { + ret = kempld_wdt_settimeout(&wdt); + if (ret) { + printf("Unable to setup timeout !\n"); + goto booting; + } + + ret = kempld_wdt_start(&wdt); + if (ret) { + printf("Unable to start watchdog !\n"); + goto booting; + } + + } + + printf("Watchog armed ! Rebooting in %d seconds if no feed occurs !\n",wdt.timeout); + +booting: + /* Release Mutex to let Linux's Driver taking control */ + kempld_release_mutex(&pld); + + /* Let's boot the default entry if specified */ + if (strlen(default_label)>0) { + printf("Executing default label = '%s'\n",default_label); + syslinux_run_command(default_label); + } else { + return ret; + } +} diff --git a/com32/modules/kontron_wdt.h b/com32/modules/kontron_wdt.h new file mode 100644 index 00000000..e916de30 --- /dev/null +++ b/com32/modules/kontron_wdt.h @@ -0,0 +1,117 @@ +/* + * kempld_wdt.h - Kontron PLD watchdog driver definitions + * + * Copyright (c) 2010 Kontron Embedded Modules GmbH + * Author: Michael Brunner <michael.brunner@kontron.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _KEMPLD_WDT_H_ +#define _KEMPLD_WDT_H_ +#include <stdint.h> + +#define KEMPLD_IOPORT 0x0a80 +#define KEMPLD_IODATA (KEMPLD_IOPORT+1) + +#define KEMPLD_MUTEX_KEY 0x80 + +/* watchdog register definitions */ +#define KEMPLD_WDT_KICK 0x16 +#define KEMPLD_WDT_REV 0x16 +#define KEMPLD_WDT_REV_GET(x) (x & 0xf) +#define KEMPLD_WDT_CFG 0x17 +#define KEMPLD_WDT_CFG_STAGE_TIMEOUT_OCCURED(x) (1<<x) +#define KEMPLD_WDT_CFG_ENABLE_LOCK 0x8 +#define KEMPLD_WDT_CFG_ENABLE 0x10 +#define KEMPLD_WDT_CFG_AUTO_RELOAD 0x40 +#define KEMPLD_WDT_CFG_GLOBAL_LOCK 0x80 +#define KEMPLD_WDT_STAGE_CFG(x) (0x18+x) +#define KEMPLD_WDT_STAGE_CFG_ACTION_MASK 0x7 +#define KEMPLD_WDT_STAGE_CFG_GET_ACTION(x) (x & 0x7) +#define KEMPLD_WDT_STAGE_CFG_ASSERT 0x8 +#define KEMPLD_WDT_STAGE_CFG_PRESCALER_MASK 0x30 +#define KEMPLD_WDT_STAGE_CFG_GET_PRESCALER(x) ((x & 0x30)>>4) +#define KEMPLD_WDT_STAGE_CFG_SET_PRESCALER(x) ((x & 0x30)<<4) +#define KEMPLD_WDT_STAGE_TIMEOUT(x) (0x1b+x*4) +#define KEMPLD_WDT_MAX_STAGES 3 + +#define KEMPLD_WDT_ACTION_NONE 0x0 +#define KEMPLD_WDT_ACTION_RESET 0x1 +#define KEMPLD_WDT_ACTION_NMI 0x2 +#define KEMPLD_WDT_ACTION_SMI 0x3 +#define KEMPLD_WDT_ACTION_SCI 0x4 +#define KEMPLD_WDT_ACTION_DELAY 0x5 + +#define KEMPLD_WDT_PRESCALER_21BIT 0x0 +#define KEMPLD_WDT_PRESCALER_17BIT 0x1 +#define KEMPLD_WDT_PRESCALER_12BIT 0x2 + +const int kempld_prescaler_bits[] = { 21, 17, 12 }; + +struct kempld_watchdog_stage { + int num; + uint32_t timeout_mask; +}; + +/** + * struct kempld_device_data - Internal representation of the PLD device + * @io_base: Pointer to the IO memory + * @io_index: Pointer to the IO index register + * @io_data: Pointer to the IO data register + * @pld_clock: PLD clock frequency + * @lock: PLD spin-lock + * @lock_flags: PLD spin-lock flags + * @have_mutex: Bool value that indicates if mutex is aquired + * @last_index: Last written index value + * @rscr: Kernel resource structure + * @dev: Pointer to kernel device structure + * @info: KEMPLD info structure + */ +struct kempld_device_data { + uint16_t io_base; + uint16_t io_index; + uint16_t io_data; + uint32_t pld_clock; +/* spinlock_t lock; + unsigned long lock_flags; */ + int have_mutex; + uint8_t last_index; +/* struct resource rscr; + struct device *dev; + struct kempld_info info;*/ +}; + +struct watchdog_info { + uint32_t options; /* Options the card/driver supports */ + uint32_t firmware_version; /* Firmware version of the card */ + uint8_t identity[32]; /* Identity of the board */ +}; + +struct kempld_watchdog_data { + unsigned int revision; + int timeout; + int pretimeout; + unsigned long is_open; + unsigned long expect_close; + int stages; + struct kempld_watchdog_stage *timeout_stage; + struct kempld_watchdog_stage *pretimeout_stage; + struct kempld_device_data *pld; + struct kempld_watchdog_stage *stage[KEMPLD_WDT_MAX_STAGES]; + struct watchdog_info ident; +}; + +#endif /* _KEMPLD_WDT_H_ */ +#define KEMPLD_PRESCALER(x) (0xffffffff>>(32-kempld_prescaler_bits[x])) diff --git a/com32/modules/prdhcp.c b/com32/modules/prdhcp.c new file mode 100644 index 00000000..e1785a03 --- /dev/null +++ b/com32/modules/prdhcp.c @@ -0,0 +1,164 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2010-2011 Gene Cumm - All Rights Reserved + * + * Portions from chain.c: + * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin + * Significant portions copyright (C) 2010 Shao Miller + * [partition iteration, GPT, "fs"] + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * prdhcp.c + * + * Print the contents of the 3 DHCP packets + */ + +#include <stdio.h> +#include <stdlib.h> +#include <consoles.h> +#include <console.h> +#include <errno.h> +#include <string.h> +#include <syslinux/config.h> +#include <syslinux/loadfile.h> +#include <syslinux/bootrm.h> +#include <syslinux/video.h> +#include <com32.h> +#include <stdint.h> +#include <syslinux/pxe.h> +#include <sys/gpxe.h> +#include <unistd.h> +#include <getkey.h> + +#define DEBUG 0 + +#define dprintf0(f, ...) ((void)0) + +#ifdef DEBUG +# define dpressanykey pressanykey +# define dprintf printf +# define dprint_pxe_bootp_t print_pxe_bootp_t +# define dprint_pxe_vendor_blk print_pxe_vendor_blk +# define dprint_pxe_vendor_raw print_pxe_vendor_raw +#else +# define dpressanykey(void) ((void)0) +# define dprintf(f, ...) ((void)0) +# define dprint_pxe_bootp_t(p, l) ((void)0) +# define dprint_pxe_vendor_blk(p, l) ((void)0) +# define dprint_pxe_vendor_raw(p, l) ((void)0) +#endif + +#define dprintf_opt_cp dprintf0 +#define dprintf_opt_inj dprintf + + +const char app_name_str[] = "prdhcp.c32"; + + +int pressanykey(void) { + int inc; + + printf("Press any key to continue. "); + inc = KEY_NONE; + while (inc == KEY_NONE) + inc = get_key(stdin, 6000); + puts(""); + return inc; +} + +void print_pxe_vendor_blk(pxe_bootp_t *p, size_t len) +{ + int i, vlen, oplen, j; + uint8_t *d; + uint32_t magic; + if (!p) { + printf(" packet pointer is null\n"); + return; + } + vlen = len - ((void *)&(p->vendor) - (void *)p); + printf(" Vendor Data: Len=%d", vlen); + d = p->vendor.d; + /* Print only 256 characters of the vendor/option data */ + /* + print_pxe_vendor_raw(p, (len - vlen) + 256); + vlen = 0; + */ + magic = ntohl(*((uint32_t *)d)); + printf(" Magic: %08X", ntohl(*((uint32_t *)d))); + if (magic != VM_RFC1048) /* Invalid DHCP packet */ + vlen = 0; + for (i = 4; i < vlen; i++) { + if (d[i]) /* Skip the padding */ + printf("\n @%03X-%3d", i, d[i]); + if (d[i] == 255) /* End of list */ + break; + if (d[i]) { + oplen = d[++i]; + printf(" l=%3d:", oplen); + for (j = (++i + oplen); i < vlen && i < j; i++) { + printf(" %02X", d[i]); + } + i--; + } + } + printf("\n"); +} + +void print_pxe_bootp_t(pxe_bootp_t *p, size_t len) +{ + if (!p) { + printf(" packet pointer is null\n"); + return; + } + printf(" op:%02X hw:%02X hl:%02X gh:%02X id:%08X se:%04X f:%04X" + " cip:%08X\n", p->opcode, p->Hardware, p->Hardlen, p->Gatehops, + ntohl(p->ident), ntohs(p->seconds), ntohs(p->Flags), ntohl(p->cip)); + printf(" yip:%08X sip:%08X gip:%08X", + ntohl(p->yip), ntohl(p->sip), ntohl(p->gip)); + printf(" caddr-%02X:%02X:%02X:%02X:%02X:%02X\n", p->CAddr[0], + p->CAddr[1], p->CAddr[2], p->CAddr[3], p->CAddr[4], p->CAddr[5]); + printf(" sName: '%s'\n", p->Sname); + printf(" bootfile: '%s'\n", p->bootfile); + print_pxe_vendor_blk(p, len); +} + +void print_dhcp_pkt_all(void) +{ + pxe_bootp_t *p; + size_t len; + int i; + int ptype[3] = {PXENV_PACKET_TYPE_DHCP_DISCOVER, PXENV_PACKET_TYPE_DHCP_ACK, PXENV_PACKET_TYPE_CACHED_REPLY}; + + for (i = 0; i < 3; i++) { + if (!pxe_get_cached_info(ptype[i], + (void **)&(p), &(len))) { + dprintf("Got packet #%d/%d\n", (i + 1), ptype[i]); + print_pxe_bootp_t(p, len); + pressanykey(); + } + } +} + +int main(void) +{ + int rv= -1; + const struct syslinux_version *sv; + + console_ansi_raw(); + sv = syslinux_version(); + if (sv->filesystem != SYSLINUX_FS_PXELINUX) { + printf("%s: May only run in PXELINUX\n", app_name_str); + return -2; + } + print_dhcp_pkt_all(); + return rv; +} diff --git a/com32/modules/pxechn.c b/com32/modules/pxechn.c index 39ac72ea..7f2002db 100644 --- a/com32/modules/pxechn.c +++ b/com32/modules/pxechn.c @@ -43,7 +43,11 @@ #include <limits.h> -#define PXECHN_DEBUG 1 +#ifdef DEBUG +# define PXECHN_DEBUG 1 +#else +# define PXECHN_DEBUG 0 +#endif typedef union { uint64_t q; @@ -54,15 +58,21 @@ typedef union { #define dprintf0(f, ...) ((void)0) +#ifndef dprintf +# if (PXECHN_DEBUG > 0) +# define dprintf printf +# else +# define dprintf(f, ...) ((void)0) +# endif +#endif + #if (PXECHN_DEBUG > 0) # define dpressanykey pressanykey -# define dprintf printf # define dprint_pxe_bootp_t print_pxe_bootp_t # define dprint_pxe_vendor_blk print_pxe_vendor_blk # define dprint_pxe_vendor_raw print_pxe_vendor_raw #else # define dpressanykey(tm) ((void)0) -# define dprintf(f, ...) ((void)0) # define dprint_pxe_bootp_t(p, l) ((void)0) # define dprint_pxe_vendor_blk(p, l) ((void)0) # define dprint_pxe_vendor_raw(p, l) ((void)0) @@ -107,6 +117,7 @@ struct pxelinux_opt { uint32_t force; uint32_t wait; /* Additional decision to wait before boot */ int32_t wds; /* WDS option/level */ + in_addr_t sip; /* siaddr: Next Server IP Address */ struct dhcp_option p[PXECHN_NUM_PKT_AVAIL]; /* original _DHCP_DISCOVER, _DHCP_ACK, _CACHED_REPLY then modified packets */ char host[PXECHN_HOST_LEN]; @@ -453,6 +464,7 @@ void pxechn_init(struct pxelinux_opt *pxe) pxe->wait = 0; pxe->gip = 0; pxe->wds = 0; + pxe->sip = 0; pxe->host[0] = 0; pxe->host[((NUM_DHCP_OPTS) - 1)] = 0; for (int j = 0; j < PXECHN_NUM_PKT_TYPE; j++){ @@ -731,7 +743,7 @@ int pxechn_parse_args(int argc, char *argv[], struct pxelinux_opt *pxe, { int arg, optnum, rv = 0; char *p = NULL; - const char optstr[] = "c:f:g:o:p:t:uwW"; + const char optstr[] = "c:f:g:o:p:St:uwW"; struct dhcp_option iopt; if (pxe->p[5].data) @@ -765,6 +777,9 @@ int pxechn_parse_args(int argc, char *argv[], struct pxelinux_opt *pxe, case 'p': /* prefix */ pxechn_setopt_str(&(opts[210]), optarg); break; + case 'S': /* sip from sName */ + pxe->sip = 1; + break; case 't': /* timeout */ optnum = strtoul(optarg, &p, 0); if (p != optarg) { @@ -809,6 +824,7 @@ int pxechn_args(int argc, char *argv[], struct pxelinux_opt *pxe) pxe_bootp_t *bootp0, *bootp1; int ret = 0; struct dhcp_option *opts; + char *str; opts = pxe->opts[2]; /* Start filling packet #1 */ @@ -826,7 +842,30 @@ int pxechn_args(int argc, char *argv[], struct pxelinux_opt *pxe) ret = pxechn_parse_args(argc, argv, pxe, opts); if (ret) return ret; - bootp1->sip = pxe->fip; + if (pxe->sip > 0xFFFFFF) { /* a real IPv4 address */ + bootp1->sip = pxe->sip; + } else if ((pxe->sip == 1) + && (opts[66].len > 0)){ + /* unterminated? */ + if (strnlen(opts[66].data, opts[66].len) == (size_t)opts[66].len) { + str = malloc(opts[66].len + 1); + if (str) { + memcpy(str, opts[66].data, opts[66].len); + str[opts[66].len] = 0; + } + } else { + str = opts[66].data; + } + if (str) { + bootp1->sip = pxe_dns(str); + if (str != opts[66].data) + free(str); + } else { + bootp1->sip = pxe->fip; + } + } else { + bootp1->sip = pxe->fip; + } bootp1->gip = pxe->gip; ret = dhcp_pack_packet(bootp1, (size_t *)&(pxe->p[5].len), opts); diff --git a/com32/samples/hello.c b/com32/samples/hello.c index eef85283..d3d4d299 100644 --- a/com32/samples/hello.c +++ b/com32/samples/hello.c @@ -1,41 +1,26 @@ -/* ----------------------------------------------------------------------- * - * - * Copyright 2004-2008 H. Peter Anvin - All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, Inc., 53 Temple Place Ste 330, - * Boston MA 02111-1307, USA; either version 2 of the License, or - * (at your option) any later version; incorporated herein by reference. - * - * ----------------------------------------------------------------------- */ - /* - * hello.c + * hello.c - A simple ELF module that sorts a couple of numbers * - * Hello, World! using libcom32 + * Created on: Aug 11, 2008 + * Author: Stefan Bucur <stefanb@zytor.com> */ -#include <string.h> #include <stdio.h> -#include <console.h> +#include <stdlib.h> -int main(int argc, char *argv[]) -{ - int i; +#include "sort.h" + +#define NUM_COUNT 10 +#define MAX_NUM 100 -#if 0 - /* this hangs! */ - openconsole(&dev_stdcon_r, &dev_stdcon_w); -#else - /* this works */ - openconsole(&dev_rawcon_r, &dev_ansiserial_w); -#endif +int main(int argc __unused, char **argv __unused) +{ + int *nums = NULL; - printf("Hello, World!\n"); + nums = malloc(NUM_COUNT * sizeof(int)); + printf("Hello, world, from 0x%08X! malloc return %p\n", (unsigned int)&main, nums); - for (i = 1; i < argc; i++) - printf("%s%c", argv[i], (i == argc - 1) ? '\n' : ' '); + free(nums); return 0; } diff --git a/core/comboot.inc b/core/comboot.inc index 62c79ec8..fcd6c756 100644 --- a/core/comboot.inc +++ b/core/comboot.inc @@ -517,10 +517,8 @@ comapi_cleanup: ret ; -; INT 22h AX=000Dh Clean up then replace bootstrap +; INT 22h AX=000Dh Obsolete ; -comapi_chainboot: - ret ; ; INT 22h AX=000Eh Get configuration file name diff --git a/core/elflink/load_env32.c b/core/elflink/load_env32.c index 9810ac93..f3dd1e77 100644 --- a/core/elflink/load_env32.c +++ b/core/elflink/load_env32.c @@ -146,6 +146,8 @@ void load_env32(com32sys_t * regs __unused) if (!search_dirs(&fp->i.fd, search_directories, filenames, realname)) start_ldlinux(argv); + + writestr("\nFailed to load ldlinux.c32"); } int create_args_and_load(char *cmdline) diff --git a/core/fs/ext2/ext2.c b/core/fs/ext2/ext2.c index ea211005..957c60b7 100644 --- a/core/fs/ext2/ext2.c +++ b/core/fs/ext2/ext2.c @@ -164,6 +164,9 @@ static struct inode *ext2_iget_by_inr(struct fs_info *fs, uint32_t inr) struct inode *inode; e_inode = ext2_get_inode(fs, inr); + if (!e_inode) + return NULL; + if (!(inode = alloc_inode(fs, inr, sizeof(struct ext2_pvt_inode)))) return NULL; fill_inode(inode, e_inode); diff --git a/diag/mbr/README b/diag/mbr/README index 96b67c6c..786816c6 100644 --- a/diag/mbr/README +++ b/diag/mbr/README @@ -11,7 +11,7 @@ Writing out an MBR is straight forward (it is assumed below that /dev/hda is the dd conv=notrunc bs=440 count=1 if=mbr.bin of=/dev/hda -Writing a VBR to match Syslinux requires more work as it must have a jump and be offset into the partition (and as a result the code must be compaible with this offset): +Writing a VBR to match Syslinux requires more work as it must have a jump and be offset into the partition (and as a result the code must be compatible with this offset): echo -en "\0353\0130\0220" |dd conv=notrunc bs=1 count=3 of=/dev/hda1 dd conv=notrunc bs=2 count=210 seek=45 if=mbr.bin of=/dev/hda1 diff --git a/doc/comboot.txt b/doc/comboot.txt index 04d5deb8..6e9d7ab5 100644 --- a/doc/comboot.txt +++ b/doc/comboot.txt @@ -560,29 +560,7 @@ AX=000Ch [2.00] Perform final cleanup meanings in future versions of Syslinux. -AX=000Dh [2.08] Cleanup and replace bootstrap code - Input: AX 000Dh - DX derivative-specific flags (see previous function) - EDI bootstrap code (linear address, can be in high memory) - ECX bootstrap code length in bytes (must fit in low mem) - EBX(!) initial value of EDX after bootstrap - ESI initial value of ESI after bootstrap - DS initial value of DS after bootstrap - Output: Does not return - - This routine performs final cleanup, then takes a piece of - code, copies it over the primary bootstrap at address 7C00h, - and jumps to it. This can be used to chainload boot sectors, - MBRs, bootstraps, etc. - - Normal boot sectors expect DL to contain the drive number, - and, for hard drives (DL >= 80h) DS:SI to contain a pointer to - the 16-byte partition table entry. The memory between - 600h-7FFh is available to put the partition table entry in. - - For PXELINUX, if the PXE stack is not unloaded, all registers - (except DS, ESI and EDX) and the stack will be set up as they - were set up by the PXE ROM. +AX=000Dh [2.08] Obsoleted in 3.80 AX=000Eh [2.11] Get configuration file name @@ -627,57 +605,7 @@ AX=0010h [3.00] Resolve hostname [PXELINUX] AX=0011h [3.05] Obsoleted in 3.80 -AX=0012h [3.50] Cleanup, shuffle and boot - Input: AX 0012h - DX derivative-specific flags (see function 000Ch) - ES:DI shuffle descriptor list (must be in low memory) - CX number of shuffle descriptors - EBX(!) initial value of EDX after bootstrap - ESI initial value of ESI after bootstrap - DS initial value of DS after bootstrap - EBP CS:IP of routine to jump to - Output: Does not return - (if CX is too large the routine returns with CF=1) - - This routine performs final cleanup, then performs a sequence - of copies, and jumps to a specified real mode entry point. - This is a more general version of function 000Dh, which can - also be used to load other types of programs. - - The copies must not touch memory below address 7C00h. - - ES:DI points to a list of CX descriptors each of the form: - - Offset Size Meaning - 0 dword destination address - 4 dword source address - 8 dword length in bytes - - The copies are overlap-safe, like memmove(). - - Starting in version 3.50, if the source address is -1 - (FFFFFFFFh) then the block specified by the destination - address and the length is set to all zero. - - Starting in version 3.50, if the destination address is -1 - (FFFFFFFFh) then the data block is loaded as a new set of - descriptors, and processing is continued (and unprocessed - descriptors are lost, this is thus typically only used as the - last descriptor in a block.) The block must still fit in the - internal descriptor buffer (see function 0011h), but can, of - course, itself chain another block. - - - Normal boot sectors expect DL to contain the drive number, - and, for hard drives (DL >= 80h) DS:SI to contain a pointer to - the 16-byte partition table entry. The memory between - 600h-7FFh is available to put the partition table entry in. - - For PXELINUX, if the PXE stack is not unloaded, all registers - (except DS, ESI and EDX) and the stack will be set up as they - were set up by the PXE ROM. - - This interface was probably broken before version 3.50. +AX=0012h [3.50] Obsoleted in 3.80 AX=0013h [3.08] Idle loop call diff --git a/doc/menu.txt b/doc/menu.txt index 620527e6..8a999cd4 100644 --- a/doc/menu.txt +++ b/doc/menu.txt @@ -18,7 +18,7 @@ See menu/README for more information. +++ THE SIMPLE MENU SYSTEM +++ The simple menu system is a single module located at -com32/modules/vesamenu.c32 (graphical) or com32/modules/menu.c32 (text +com32/menu/vesamenu.c32 (graphical) or com32/menu/menu.c32 (text mode only). It uses the same configuration file as the regular Syslinux command line, and displays all the LABEL statements. diff --git a/doc/pxechn.txt b/doc/pxechn.txt index a09bbe2b..7853d9ab 100644 --- a/doc/pxechn.txt +++ b/doc/pxechn.txt @@ -1,88 +1,131 @@ -= pxechn.c32 = += pxechn.c32(1) = :doctype: manpage :author: Gene Cumm :email: gene.cumm@gmail.com -:revdate: 2012-05-27 +:revdate: 2012-09-16 == NAME == -pxechn.c32 - Chainboot to new NBP +pxechn.c32 - Chainboot to new Network Boot Program (NBP) == SYNOPSIS == +[verse] *pxechn.c32* [-h | --help | -?] *pxechn.c32* -r 'FILE' *pxechn.c32* 'FILE' ['OPTIONS'] == DESCRIPTION == -Chainboot to a new NBP (Network Boot Program) 'FILE' with options to adjust PXE packet #3 (PXENV_PACKET_TYPE_CACHED_REPLY) to alter end behavior. 'FILE' may be a filename, an IP::FN ( 192.168.1.1::path/to/file.0 ), or URL. 'FILE' is parsed to adjust the DHCP 'sname' field/option 66 and 'file' field/option 67. +Chainboot to a new Network Boot Program (NBP) 'FILE' with options to +adjust PXE packet #3 (PXENV_PACKET_TYPE_CACHED_REPLY) to alter end +behavior. 'FILE' may be a filename, an IP::FN ( +192.168.1.1::path/to/file.0 ), or URL. 'FILE' is parsed to adjust the +DHCP 'sname' field/option 66 and 'file' field/option 67. // but these may be override-able in the future. == OPTIONS == *-c* 'CONFIG':: - PXELINUX config file (DHCP Option 209). + 'config' file for PXELINUX (DHCP Option 209). // *-f* 'MOD':: -// Force behavior specified by 'MOD' +// 'Force' behavior specified by modifier 'MOD' // // *-g* 'HOST':: -// Set DHCP gateway/relay. Parsed by pxe_dns(). +// Set 'gateway'/relay DHCP field to 'HOST'. Parsed by pxe_dns(). // *-h*, *--help*, *-?*:: - Print usage information; invalid options will also cause this. + Print 'help'/usage information; invalid options will also cause + this. // *-n*:: -// Use native methods, ignoring underlying gPXE/iPXE. +// Use 'native' methods, ignoring underlying gPXE/iPXE. // // *-N*:: -// Use non-native methods to utilize gPXE/iPXE (if available). +// Use 'non-native' methods to utilize gPXE/iPXE (if available). // *-o* 'OPT.TYPE=VALUE':: - Specify a generic option. 'OPT' is in 'DECIMAL INPUT' format (below). 'TYPE' specifies the output type and input syntax. 'b'yte, 'w'ord(2B), 'l'ong(4B), 'q'uad(8B), character 's'tring and colon-separated he'x' string (case insensitive; bytes must have 2 digits and each byte must be separated). byte, word, long and quad input values must meet criteria for 'DECIMAL INPUT' + Set 'option'. 'OPT' is in 'DECIMAL INPUT' format (below). 'TYPE' + specifies the output type and input syntax (listed here in quotes + and at present, 1 character). ''b'yte', ''w'ord'(2B), ''l'ong'(4B), + ''q'uad'(8B), character ''s'tring' and colon-separated 'he'x'' + string (case insensitive; bytes must have 2 digits and each byte + must be separated). byte, word, long and quad input values must + meet criteria for 'DECIMAL INPUT' *-p* 'PATH':: - PXELINUX path (DHCP Option 210). + 'path' option for PXELINUX (DHCP Option 210). *-r*:: - Call the PXE stack with PXENV_RESTART_TFTP. _Must_ be the only option and before 'FILE'. + 'restart'. Call the PXE stack with PXENV_RESTART_TFTP. _Must_ be + the only option and before 'FILE'. + +*-S*:: + Set 'sip' based on sname field/option 66 (by direct IP if a + period-delimited address or otherwise DNS). *-t* 'SECONDS':: - PXELINUX timeout (DHCP Option 211). + 'timeout' option for PXELINUX (DHCP Option 211). // *-u*:: -// Copy UUID (Option 97) if found in packet #1 +// Copy 'UUID' (Option 97) if found in packet #1 *-w*:: - wait after loading before booting for user input. + 'wait'. After loading, wait for user input before booting. *-W*:: - Enable WDS (Windows Deployment Services) - specific options. + Enable 'WDS' (Windows Deployment Services) - specific options. + 'FILE' (or its overrides for DHCP fields siaddr and file) must point + at the WDS server. + *NOTE:* As of 2012-05-31, there is a known issue with gPXE/iPXE, at + least with undionly.kkpxe. +// PXELINUX asks gPXE/iPXE to unload, reverting to an underlying stack == DECIMAL INPUT == -All parameters that are defaulted to decimal format are processed by *strtoul*(3) with a base of 0 which allows alternate formats and finds a suitable non-space separating character. +All parameters that are defaulted to decimal format are processed by +*strtoul*(3) with a base of 0 which allows alternate formats and finds a +suitable non-space separating character. == EXAMPLES == -pxechn.c32 http://myhost.dom.loc/path/nbp.0 -c myconfig - Load nbp.0 and set PXELINUX config (option 209). - -pxechn.c32 gpxelinux.0 -p http://172.16.23.1/tftp/ -w -c myconfig -o 15.s=domain.loc -o 6.x=0A:01:01:02:ac:17:4D:Ec - - Load gpxelinux.0 from the current directory, set prefix, wait to execute, set first config, set the domain name and 2 domain name servers (case mixed to show insensitivity; 10.1.1.2 and 172.23.77.236). - -pxechn.c32 gpxelinux.0 -p http://172.16.23.1/tftp/ -w -X A012345678 -x 197:00d0de00 -pxechn.c32 gpxelinux.0 -p http://172.16.23.1/tftp/ -w -X A012:3456:78 -x 197:00-d0-de-00 - Both of these are equivalent. Load gpxelinux.0 (relative to the current directory and not altering sname/option 66), set the PXELINUX path prefix, wait after loading, set option 160 to 0x12 0x34 0x56 0x78, and option 197 to 0x00 0xD0 0xDE 0x00. +`pxechn.c32 http://myhost.dom.loc/path/nbp.0 -c myconfig`:: + Load nbp.0 and set PXELINUX config (option 209). + +`pxechn.c32 gpxelinux.0 -p http://10.1.1.4/tftp/ -w -c myconfig -o 15.s=domain.loc -o 6.x=0A:01:01:02:ac:17:4D:Ec -`:: + Load gpxelinux.0 from the current directory, set prefix, wait to + execute, set first config, set the domain name and 2 domain name + servers (case mixed to show insensitivity; 10.1.1.2 and + 172.23.77.236). + +`pxechn.c32 gpxelinux.0 -p http://10.1.1.4/tftp/ -w -o 0xA0.x=12:34:56:78 -x 197.x=00:d0:de:00`:: + Load gpxelinux.0 (relative to the current directory and not + altering sname/option 66), set the PXELINUX path prefix, wait after + loading, set option 160 to 0x12 0x34 0x56 0x78, and option 197 to + 0x00 0xD0 0xDE 0x00. + +`pxechn.c32 10.1.1.8:boot\x86\wdsnbp.com -W`:: + Load wdsnbp.com from 10.1.1.8 and copy DHCP Option 66 to DHCP + field sname if there's room. + +`pxechn.c32 10.1.1.4:boot\x86\wdsnbp.com -W -o 66.x=0a:01:01:08 -S`:: + Load wdsnbp.com from 10.1.1.4, point packets to 10.1.1.8 for use + with WDS, copy DHCP Option 66 to DHCP field sname if there's room + and decode this to an IPv4 address. == NOTES == -Please note that some NBPs may ignore packet #3 by either not examining it at all or by issuing its own DHCP DISCOVER/REQUEST, negating all DHCP field/option modifications by pxechn.c32. +Please note that some NBPs may ignore packet #3 by either not examining +it at all or by issuing its own DHCP DISCOVER/REQUEST, negating all DHCP +field/option modifications by pxechn.c32, including Microsoft Windows +Server 2008R2 WDS's wdsnbp.com. See also option '-W'. -URL specifications in 'FILE' that include user/password before the host will currently cause the siaddr field to not be set properly. +URL specifications in 'FILE' that include user/password before the host +will currently cause the siaddr field to not be set properly. -The non-space constraint is due to how Syslinux variants parse the command line as of 2012-01-12. +The non-space constraint is due to how Syslinux variants parse the +command line as of 2012-09-16. == AUTHOR == @@ -91,4 +134,5 @@ The non-space constraint is due to how Syslinux variants parse the command line == COPYRIGHT == Copyright \(C) 2012 {author}. Free use of this software is granted under -the terms of the GNU General Public License (GPL). +the terms of the GNU General Public License (GPL), version 2 (GPLv2) +(or, at your option, any later version). diff --git a/doc/syslinux.txt b/doc/syslinux.txt index 07d5df9a..e9923a63 100644 --- a/doc/syslinux.txt +++ b/doc/syslinux.txt @@ -100,7 +100,7 @@ directory on the disk. There are two versions of the Linux installer; one in the "mtools" directory which requires no special privilege (other than write permission to the device where you are installing) but requires the -mtools program suite to be available, and one in the "unix" directory +mtools program suite to be available, and one in the "linux" directory which requires root privilege. @@ -450,6 +450,13 @@ F12 filename compatibility with earlier versions, F10 can also be entered as <Ctrl-F>0. +PATH path + Specify a colon-separated (':') list of directories to search + when attempting to load modules. This directive is useful for + specifying the directories containing the lib*.c32 library + files as other modules may be dependent on these files, but + may not reside in the same directory. + Blank lines are ignored. Note that the configuration file is not completely decoded. Syntax diff --git a/dos/dosexe.ld b/dos/dosexe.ld index 76bfc758..bd6ad8ba 100644 --- a/dos/dosexe.ld +++ b/dos/dosexe.ld @@ -26,7 +26,7 @@ SECTIONS __header_size = .; __payload_lma = .; - . = 0x100000000 - syslinux_ldlinux_size; + . = 0x100000000 - syslinux_size; .payload : AT (__payload_lma) { __payload_start = .; *(.payload) @@ -35,13 +35,13 @@ SECTIONS __payload_len = ABSOLUTE(__payload_end) - ABSOLUTE(__payload_start); __payload_dwords = __payload_len >> 2; - __text_lma = __payload_lma + syslinux_ldlinux_size; + __text_lma = __payload_lma + syslinux_size; __payload_sseg = (__payload_lma - __text_lma) >> 4; _exe_text_seg = (__text_lma - __header_size) >> 4; /* * __assert1 = ASSERT((__payload_len == syslinux_ldlinux_size), - * "syslinux_ldlinux_size must equal the size of .payload"); + * "syslinux_size must equal the size of .payload"); */ . = 0; .text : AT (__text_lma) { diff --git a/dos/ldlinux.S b/dos/ldlinux.S index 17a65830..9145bd7b 100644 --- a/dos/ldlinux.S +++ b/dos/ldlinux.S @@ -1,5 +1,5 @@ /* - * Wrap ldlinux.sys; this needs special handling for DOS. + * Wrap ldlinux.sys and ldlinux.c32; this needs special handling for DOS. */ .section ".payload","aw" @@ -10,6 +10,14 @@ syslinux_ldlinux: .space ((syslinux_ldlinux - .) & 511) syslinux_ldlinux_size = . - syslinux_ldlinux .size syslinux_ldlinux, .-syslinux_ldlinux + .globl syslinux_ldlinuxc32, syslinux_ldlinuxc32_size +syslinux_ldlinuxc32: + .incbin "../com32/elflink/ldlinux/ldlinux.c32" + .space ((syslinux_ldlinuxc32 - .) & 511) +syslinux_ldlinuxc32_size = . - syslinux_ldlinuxc32 + .size syslinux_ldlinuxc32, .-syslinux_ldlinuxc32 + .globl syslinux_size +syslinux_size = . - syslinux_ldlinux .section ".rodata","a" .balign 4 @@ -17,3 +25,7 @@ syslinux_ldlinux_size = . - syslinux_ldlinux syslinux_ldlinux_len: .long syslinux_ldlinux_size .size syslinux_ldlinux_len, .-syslinux_ldlinux_len + .globl syslinux_ldlinuxc32_len +syslinux_ldlinuxc32_len: + .long syslinux_ldlinuxc32_size + .size syslinux_ldlinuxc32_len, .-syslinux_ldlinuxc32_len diff --git a/dos/syslinux.c b/dos/syslinux.c index fa4bf387..eb8bace6 100644 --- a/dos/syslinux.c +++ b/dos/syslinux.c @@ -121,15 +121,15 @@ int rename(const char *oldname, const char *newname) return 0; } -ssize_t write_ldlinux(int fd) +ssize_t write_file_seg(int fd, unsigned char *buf, const unsigned int len) { - uint16_t ldlinux_seg = ((size_t)syslinux_ldlinux >> 4) + ds(); + uint16_t seg = ((size_t)buf >> 4) + ds(); uint32_t offset = 0; uint16_t rv; uint8_t err; - while (offset < syslinux_ldlinux_len) { - uint32_t chunk = syslinux_ldlinux_len - offset; + while (offset < len) { + uint32_t chunk = len - offset; if (chunk > 32768) chunk = 32768; asm volatile ("pushw %%ds ; " @@ -137,7 +137,7 @@ ssize_t write_ldlinux(int fd) "int $0x21 ; " "popw %%ds ; " "setc %0":"=bcdm" (err), "=a"(rv) :"a"(0x4000), "b"(fd), "c"(chunk), "d" (offset & 15), - "SD" ((uint16_t)(ldlinux_seg + (offset >> 4)))); + "SD" ((uint16_t)(seg + (offset >> 4)))); if (err || rv == 0) die("file write error"); offset += rv; @@ -583,11 +583,53 @@ static void adjust_mbr(int device, int writembr, int set_active) write_mbr(device, sectbuf); } +static void move_file(int dev_fd, char *pathname, char *filename) +{ + char new_name[160]; + char *cp = new_name + 3; + const char *sd; + int slash = 1; + + new_name[0] = dev_fd | 0x40; + new_name[1] = ':'; + new_name[2] = '\\'; + + for (sd = opt.directory; *sd; sd++) { + char c = *sd; + + if (c == '/' || c == '\\') { + if (slash) + continue; + c = '\\'; + slash = 1; + } else { + slash = 0; + } + + *cp++ = c; + } + + /* Skip if subdirectory == root */ + if (cp > new_name + 3) { + if (!slash) + *cp++ = '\\'; + + memcpy(cp, filename, 12); + + set_attributes(pathname, 0); + if (rename(pathname, new_name)) + set_attributes(pathname, 0x07); + else + set_attributes(new_name, 0x07); + } +} + int main(int argc, char *argv[]) { static unsigned char sectbuf[SECTOR_SIZE]; int dev_fd, fd; static char ldlinux_name[] = "@:\\ldlinux.sys"; + static char ldlinuxc32_name[] = "@:\\ldlinux.c32"; struct libfat_filesystem *fs; libfat_sector_t s, *secp; libfat_sector_t *sectors; @@ -647,14 +689,21 @@ int main(int argc, char *argv[]) } ldlinux_name[0] = dev_fd | 0x40; + ldlinuxc32_name[0] = dev_fd | 0x40; set_attributes(ldlinux_name, 0); fd = creat(ldlinux_name, 0); /* SYSTEM HIDDEN READONLY */ - write_ldlinux(fd); + write_file_seg(fd, syslinux_ldlinux, syslinux_ldlinux_len); write_file(fd, syslinux_adv, 2 * ADV_SIZE); close(fd); set_attributes(ldlinux_name, 0x07); /* SYSTEM HIDDEN READONLY */ + set_attributes(ldlinuxc32_name, 0); + fd = creat(ldlinuxc32_name, 0); /* SYSTEM HIDDEN READONLY */ + write_file_seg(fd, syslinux_ldlinuxc32, syslinux_ldlinuxc32_len); + close(fd); + set_attributes(ldlinuxc32_name, 0x07); /* SYSTEM HIDDEN READONLY */ + /* * Now, use libfat to create a block map. This probably * should be changed to use ioctl(...,FIBMAP,...) since @@ -681,43 +730,8 @@ int main(int argc, char *argv[]) * If requested, move ldlinux.sys */ if (opt.directory) { - char new_ldlinux_name[160]; - char *cp = new_ldlinux_name + 3; - const char *sd; - int slash = 1; - - new_ldlinux_name[0] = dev_fd | 0x40; - new_ldlinux_name[1] = ':'; - new_ldlinux_name[2] = '\\'; - - for (sd = opt.directory; *sd; sd++) { - char c = *sd; - - if (c == '/' || c == '\\') { - if (slash) - continue; - c = '\\'; - slash = 1; - } else { - slash = 0; - } - - *cp++ = c; - } - - /* Skip if subdirectory == root */ - if (cp > new_ldlinux_name + 3) { - if (!slash) - *cp++ = '\\'; - - memcpy(cp, "ldlinux.sys", 12); - - set_attributes(ldlinux_name, 0); - if (rename(ldlinux_name, new_ldlinux_name)) - set_attributes(ldlinux_name, 0x07); - else - set_attributes(new_ldlinux_name, 0x07); - } + move_file(dev_fd, ldlinux_name, "ldlinux.sys"); + move_file(dev_fd, ldlinuxc32_name, "ldlinux.c32"); } /* diff --git a/extlinux/Makefile b/extlinux/Makefile index b1a76a0a..91486880 100644 --- a/extlinux/Makefile +++ b/extlinux/Makefile @@ -30,6 +30,7 @@ SRCS = main.c \ ../libinstaller/setadv.c \ ../libinstaller/advio.c \ ../libinstaller/bootsect_bin.c \ + ../libinstaller/ldlinuxc32_bin.c \ ../libinstaller/ldlinux_bin.c OBJS = $(patsubst %.c,%.o,$(notdir $(SRCS))) diff --git a/extlinux/main.c b/extlinux/main.c index b72bee2b..27527335 100644 --- a/extlinux/main.c +++ b/extlinux/main.c @@ -76,7 +76,7 @@ static char subvol[BTRFS_SUBVOL_MAX]; /* * Get the size of a block device */ -uint64_t get_size(int devfd) +static uint64_t get_size(int devfd) { uint64_t bytes; uint32_t sects; @@ -210,7 +210,7 @@ ok: * * Returns the number of modified bytes in the boot file. */ -int patch_file_and_bootblock(int fd, const char *dir, int devfd) +static int patch_file_and_bootblock(int fd, const char *dir, int devfd) { struct stat dirst, xdst; struct hd_geometry geo; @@ -398,16 +398,18 @@ int install_bootblock(int fd, const char *device) int ext2_fat_install_file(const char *path, int devfd, struct stat *rst) { - char *file, *oldfile; + char *file, *oldfile, *c32file; int fd = -1, dirfd = -1; int modbytes; - int r1, r2; + int r1, r2, r3; r1 = asprintf(&file, "%s%sldlinux.sys", path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/"); r2 = asprintf(&oldfile, "%s%sextlinux.sys", path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/"); - if (r1 < 0 || !file || r2 < 0 || !oldfile) { + r3 = asprintf(&c32file, "%s%sldlinux.c32", + path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/"); + if (r1 < 0 || !file || r2 < 0 || !oldfile || r3 < 0 || !c32file) { perror(program); return 1; } @@ -474,8 +476,22 @@ int ext2_fat_install_file(const char *path, int devfd, struct stat *rst) unlink(oldfile); } + fd = open(c32file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC, + S_IRUSR | S_IRGRP | S_IROTH); + if (fd < 0) { + perror(c32file); + goto bail; + } + + r3 = xpwrite(fd, syslinux_ldlinuxc32, syslinux_ldlinuxc32_len, 0); + if (r3 != syslinux_ldlinuxc32_len) { + fprintf(stderr, "%s: write failure on %s\n", program, c32file); + goto bail; + } + free(file); free(oldfile); + free(c32file); return 0; bail: @@ -486,6 +502,7 @@ bail: free(file); free(oldfile); + free(c32file); return 1; } @@ -494,6 +511,9 @@ bail: since the cow feature of btrfs will move the ldlinux.sys every where */ int btrfs_install_file(const char *path, int devfd, struct stat *rst) { + char *file; + int fd, rv; + patch_file_and_bootblock(-1, path, devfd); if (xpwrite(devfd, boot_image, boot_image_len, BTRFS_EXTLINUX_OFFSET) != boot_image_len) { @@ -511,7 +531,37 @@ int btrfs_install_file(const char *path, int devfd, struct stat *rst) perror(path); return 1; } - return 0; + + /* + * Note that we *can* install ldinux.c32 as a regular file because + * it doesn't need to be within the first 64K. The Syslinux core + * has enough smarts to search the btrfs dirs and find this file. + */ + rv = asprintf(&file, "%s%sldlinux.c32", + path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/"); + if (rv < 0 || !file) { + perror(program); + return 1; + } + + fd = open(file, O_WRONLY | O_TRUNC | O_CREAT | O_SYNC, + S_IRUSR | S_IRGRP | S_IROTH); + if (fd < 0) { + perror(file); + free(file); + return 1; + } + + rv = xpwrite(fd, syslinux_ldlinuxc32, syslinux_ldlinuxc32_len, 0); + if (rv != (int)syslinux_ldlinuxc32_len) { + fprintf(stderr, "%s: write failure on %s\n", program, file); + rv = 1; + } else + rv = 0; + + close(fd); + free(file); + return rv; } /* @@ -746,7 +796,7 @@ static char * get_default_subvol(char * rootdir, char * subvol) return subvol; } -int install_file(const char *path, int devfd, struct stat *rst) +static int install_file(const char *path, int devfd, struct stat *rst) { if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS) return ext2_fat_install_file(path, devfd, rst); @@ -915,6 +965,8 @@ static const char *find_device_mountinfo(const char *path, dev_t dev) struct stat st; m = find_mount(path, NULL); + if (!m) + return NULL; if (m->devpath[0] == '/' && m->dev == dev && !stat(m->devpath, &st) && S_ISBLK(st.st_mode) && st.st_rdev == dev) @@ -1174,7 +1226,7 @@ static int ext_write_adv(const char *path, const char *cfg, int devfd) return write_adv(path, cfg); } -int install_loader(const char *path, int update_only) +static int install_loader(const char *path, int update_only) { struct stat st, fst; int devfd, rv; diff --git a/libinstaller/Makefile b/libinstaller/Makefile index 30c3d3d6..644ea664 100644 --- a/libinstaller/Makefile +++ b/libinstaller/Makefile @@ -1,6 +1,6 @@ # _bin.c files required by both BTARGET and ITARGET installers BINFILES = bootsect_bin.c ldlinux_bin.c \ - mbr_bin.c gptmbr_bin.c + mbr_bin.c gptmbr_bin.c ldlinuxc32_bin.c PERL = perl @@ -22,6 +22,9 @@ gptmbr_bin.c: $(OBJ)/../mbr/gptmbr.bin bin2c.pl installer: $(BINFILES) +ldlinuxc32_bin.c: ../com32/elflink/ldlinux/ldlinux.c32 bin2c.pl + $(PERL) bin2c.pl syslinux_ldlinuxc32 < $< > $@ + tidy: rm -f $(BINFILES) diff --git a/libinstaller/syslinux.h b/libinstaller/syslinux.h index 8b86f881..f60a066e 100644 --- a/libinstaller/syslinux.h +++ b/libinstaller/syslinux.h @@ -26,6 +26,9 @@ extern unsigned char syslinux_ldlinux[]; extern const unsigned int syslinux_ldlinux_len; extern const int syslinux_ldlinux_mtime; +extern unsigned char syslinux_ldlinuxc32[]; +extern const unsigned int syslinux_ldlinuxc32_len; + #define boot_sector syslinux_bootsect #define boot_sector_len syslinux_bootsect_len #define boot_image syslinux_ldlinux diff --git a/libinstaller/syslxint.h b/libinstaller/syslxint.h index 2e317d0e..e5428b79 100644 --- a/libinstaller/syslxint.h +++ b/libinstaller/syslxint.h @@ -23,6 +23,17 @@ # define X86_MEM 0 #endif +#ifdef __GNUC__ +# ifdef __MINGW32__ + /* gcc 4.7 miscompiles packed structures in MS-bitfield mode */ +# define PACKED __attribute__((packed,gcc_struct)) +# else +# define PACKED __attribute__((packed)) +# endif +#else +# error "Need to define PACKED for this compiler" +#endif + /* * Access functions for littleendian numbers, possibly misaligned. */ @@ -190,7 +201,7 @@ struct ext_patch_area { struct syslinux_extent { uint64_t lba; uint16_t len; -} __attribute__((packed)); +} PACKED; /* FAT bootsector format, also used by other disk-based derivatives */ struct fat_boot_sector { @@ -218,7 +229,7 @@ struct fat_boot_sector { char VolumeLabel[11]; char FileSysType[8]; uint8_t Code[442]; - } __attribute__ ((packed)) bs16; + } PACKED bs16; struct { uint32_t FATSz32; uint16_t ExtFlags; @@ -234,13 +245,13 @@ struct fat_boot_sector { char VolumeLabel[11]; char FileSysType[8]; uint8_t Code[414]; - } __attribute__ ((packed)) bs32; - } __attribute__ ((packed)); + } PACKED bs32; + } PACKED; uint32_t bsMagic; uint16_t bsForwardPtr; uint16_t bsSignature; -} __attribute__ ((packed)); +} PACKED; /* NTFS bootsector format */ struct ntfs_boot_sector { @@ -273,7 +284,7 @@ struct ntfs_boot_sector { uint32_t bsMagic; uint16_t bsForwardPtr; uint16_t bsSignature; -} __attribute__((packed)); +} PACKED; #define FAT_bsHead bsJump #define FAT_bsHeadLen offsetof(struct fat_boot_sector, bsBytesPerSec) diff --git a/libinstaller/syslxmod.c b/libinstaller/syslxmod.c index 5ec156ac..98e2710a 100644 --- a/libinstaller/syslxmod.c +++ b/libinstaller/syslxmod.c @@ -96,8 +96,6 @@ static inline void *ptr(void *img, uint16_t *offset_p) * Returns the number of modified bytes in ldlinux.sys if successful, * otherwise -1. */ -#define NADV 2 - int syslinux_patch(const sector_t *sectp, int nsectors, int stupid, int raid_mode, const char *subdir, const char *subvol) diff --git a/linux/Makefile b/linux/Makefile index d63306af..f88a6cb3 100644 --- a/linux/Makefile +++ b/linux/Makefile @@ -29,6 +29,7 @@ SRCS = syslinux.c \ ../libinstaller/fs.c \ ../libinstaller/syslxmod.c \ ../libinstaller/bootsect_bin.c \ + ../libinstaller/ldlinuxc32_bin.c \ ../libinstaller/ldlinux_bin.c OBJS = $(patsubst %.c,%.o,$(notdir $(SRCS))) diff --git a/linux/syslinux.c b/linux/syslinux.c index 4b13b7fe..f4749ead 100755 --- a/linux/syslinux.c +++ b/linux/syslinux.c @@ -238,6 +238,24 @@ int modify_existing_adv(const char *path) return 0; } +int do_open_file(char *name) +{ + int fd; + + if ((fd = open(name, O_RDONLY)) >= 0) { + uint32_t zero_attr = 0; + ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &zero_attr); + close(fd); + } + + unlink(name); + fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0444); + if (fd < 0) + perror(opt.device); + + return fd; +} + int main(int argc, char *argv[]) { static unsigned char sectbuf[SECTOR_SIZE]; @@ -253,7 +271,7 @@ int main(int argc, char *argv[]) const char *errmsg; int mnt_cookie; int patch_sectors; - int i; + int i, rv; mypid = getpid(); umask(077); @@ -408,16 +426,8 @@ int main(int argc, char *argv[]) if (modify_adv() < 0) exit(1); - if ((fd = open(ldlinux_name, O_RDONLY)) >= 0) { - uint32_t zero_attr = 0; - ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &zero_attr); - close(fd); - } - - unlink(ldlinux_name); - fd = open(ldlinux_name, O_WRONLY | O_CREAT | O_TRUNC, 0444); + fd = do_open_file(ldlinux_name); if (fd < 0) { - perror(opt.device); err = 1; goto umount; } @@ -451,6 +461,31 @@ int main(int argc, char *argv[]) close(fd); sync(); + sprintf(ldlinux_name, "%sldlinux.c32", ldlinux_path); + fd = do_open_file(ldlinux_name); + if (fd < 0) { + err = 1; + goto umount; + } + + rv = xpwrite(fd, syslinux_ldlinuxc32, syslinux_ldlinuxc32_len, 0); + if (rv != (int)syslinux_ldlinuxc32_len) { + fprintf(stderr, "%s: write failure on %s\n", program, ldlinux_name); + exit(1); + } + + fsync(fd); + /* + * Set the attributes + */ + { + uint32_t attr = 0x07; /* Hidden+System+Readonly */ + ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &attr); + } + + close(fd); + sync(); + umount: do_umount(mntpath, mnt_cookie); sync(); diff --git a/memdisk/mstructs.h b/memdisk/mstructs.h index fecbff40..0b0dc07d 100644 --- a/memdisk/mstructs.h +++ b/memdisk/mstructs.h @@ -121,9 +121,9 @@ typedef union { uint8_t specify1; /* "First specify byte" */ uint8_t specify2; /* "Second specify byte" */ uint8_t delay; /* Delay until motor turn off */ - uint8_t sectors; /* Sectors/track */ - uint8_t bps; /* Bytes/sector (02h = 512) */ + + uint8_t sectors; /* Sectors/track */ uint8_t isgap; /* Length of intersector gap */ uint8_t dlen; /* Data length (0FFh) */ uint8_t fgap; /* Formatting gap */ @@ -95,5 +95,5 @@ C_LNXLIBS = $(objdir)/com32/libutil/libutil_lnx.a \ %.lnx: %.lo $(LNXLIBS) $(C_LNXLIBS) $(CC) $(LNXCFLAGS) -o $@ $^ -%.c32: %.o $(LIBS) +%.c32: %.o $(C_LIBS) $(LD) $(LDFLAGS) -o $@ $^ diff --git a/mtools/Makefile b/mtools/Makefile index 3544388e..3f9c42b3 100755 --- a/mtools/Makefile +++ b/mtools/Makefile @@ -12,6 +12,7 @@ SRCS = syslinux.c \ ../libinstaller/setadv.c \ ../libinstaller/bootsect_bin.c \ ../libinstaller/ldlinux_bin.c \ + ../libinstaller/ldlinuxc32_bin.c \ $(wildcard $(SRC)/../libfat/*.c) OBJS = $(patsubst %.c,%.o,$(notdir $(SRCS))) diff --git a/mtools/syslinux.c b/mtools/syslinux.c index c65021bb..f43b5a5e 100755 --- a/mtools/syslinux.c +++ b/mtools/syslinux.c @@ -125,6 +125,64 @@ int libfat_xpread(intptr_t pp, void *buf, size_t secsize, return xpread(pp, buf, secsize, offset); } +static int move_file(char *filename) +{ + char target_file[4096], command[5120]; + char *cp = target_file, *ep = target_file + sizeof target_file - 16; + const char *sd; + int slash = 1; + int status; + + cp += sprintf(cp, "'s:/"); + for (sd = opt.directory; *sd; sd++) { + if (*sd == '/' || *sd == '\\') { + if (slash) + continue; /* Remove duplicated slashes */ + slash = 1; + } else if (*sd == '\'' || *sd == '!') { + slash = 0; + if (cp < ep) + *cp++ = '\''; + if (cp < ep) + *cp++ = '\\'; + if (cp < ep) + *cp++ = *sd; + if (cp < ep) + *cp++ = '\''; + continue; + } else { + slash = 0; + } + + if (cp < ep) + *cp++ = *sd; + } + if (!slash) + *cp++ = '/'; + sprintf(cp, "%s'", filename); + + /* This command may fail legitimately */ + sprintf(command, "mattrib -h -r -s %s 2>/dev/null", target_file); + status = system(command); + (void)status; /* Keep _FORTIFY_SOURCE happy */ + + sprintf(command, "mmove -D o -D O s:/%s %s", filename, target_file); + status = system(command); + + if (!WIFEXITED(status) || WEXITSTATUS(status)) { + fprintf(stderr, + "%s: warning: unable to move %s\n", program, filename); + + sprintf(command, "mattrib +r +h +s s:/%s", filename); + status = system(command); + } else { + sprintf(command, "mattrib +r +h +s %s", target_file); + status = system(command); + } + + return status; +} + int main(int argc, char *argv[]) { static unsigned char sectbuf[SECTOR_SIZE]; @@ -284,63 +342,38 @@ int main(int argc, char *argv[]) /* Move ldlinux.sys to the desired location */ if (opt.directory) { - char target_file[4096], command[5120]; - char *cp = target_file, *ep = target_file + sizeof target_file - 16; - const char *sd; - int slash = 1; - - cp += sprintf(cp, "'s:/"); - for (sd = opt.directory; *sd; sd++) { - if (*sd == '/' || *sd == '\\') { - if (slash) - continue; /* Remove duplicated slashes */ - slash = 1; - } else if (*sd == '\'' || *sd == '!') { - slash = 0; - if (cp < ep) - *cp++ = '\''; - if (cp < ep) - *cp++ = '\\'; - if (cp < ep) - *cp++ = *sd; - if (cp < ep) - *cp++ = '\''; - continue; - } else { - slash = 0; - } - - if (cp < ep) - *cp++ = *sd; - } - if (!slash) - *cp++ = '/'; - strcpy(cp, "ldlinux.sys'"); + status = move_file("ldlinux.sys"); + } else { + status = system("mattrib +r +h +s s:/ldlinux.sys"); + } - /* This command may fail legitimately */ - sprintf(command, "mattrib -h -r -s %s 2>/dev/null", target_file); - status = system(command); - (void)status; /* Keep _FORTIFY_SOURCE happy */ + if (!WIFEXITED(status) || WEXITSTATUS(status)) { + fprintf(stderr, + "%s: warning: failed to set system bit on ldlinux.sys\n", + program); + } - sprintf(command, "mmove -D o -D O s:/ldlinux.sys %s", target_file); - status = system(command); + /* This command may fail legitimately */ + status = system("mattrib -h -r -s s:/ldlinux.c32 2>/dev/null"); + (void)status; /* Keep _FORTIFY_SOURCE happy */ - if (!WIFEXITED(status) || WEXITSTATUS(status)) { - fprintf(stderr, - "%s: warning: unable to move ldlinux.sys\n", program); + mtp = popen("mcopy -D o -D O -o - s:/ldlinux.c32", "w"); + if (!mtp || fwrite(syslinux_ldlinuxc32, 1, syslinux_ldlinuxc32_len, mtp) + != syslinux_ldlinuxc32_len || + (status = pclose(mtp), !WIFEXITED(status) || WEXITSTATUS(status))) { + die("failed to create ldlinux.c32"); + } - status = system("mattrib +r +h +s s:/ldlinux.sys"); - } else { - sprintf(command, "mattrib +r +h +s %s", target_file); - status = system(command); - } + /* Move ldlinux.c32 to the desired location */ + if (opt.directory) { + status = move_file("ldlinux.c32"); } else { - status = system("mattrib +r +h +s s:/ldlinux.sys"); + status = system("mattrib +r +h +s s:/ldlinux.c32"); } if (!WIFEXITED(status) || WEXITSTATUS(status)) { fprintf(stderr, - "%s: warning: failed to set system bit on ldlinux.sys\n", + "%s: warning: failed to set system bit on ldlinux.c32\n", program); } diff --git a/utils/isohybrid.c b/utils/isohybrid.c index ac04bfd4..97d43b86 100644 --- a/utils/isohybrid.c +++ b/utils/isohybrid.c @@ -434,10 +434,10 @@ lendian_64(const uint64_t s) if (*(uint8_t *)&r) return s; - r = (s & 0x00000000000000FF) << 56 | (s & 0xFF00000000000000) >> 56 - | (s & 0x000000000000FF00) << 40 | (s & 0x00FF000000000000) >> 40 - | (s & 0x0000000000FF0000) << 24 | (s & 0x0000FF0000000000) >> 24 - | (s & 0x00000000FF000000) << 8 | (s & 0x000000FF00000000) >> 8; + r = (s & 0x00000000000000FFull) << 56 | (s & 0xFF00000000000000ull) >> 56 + | (s & 0x000000000000FF00ull) << 40 | (s & 0x00FF000000000000ull) >> 40 + | (s & 0x0000000000FF0000ull) << 24 | (s & 0x0000FF0000000000ull) >> 24 + | (s & 0x00000000FF000000ull) << 8 | (s & 0x000000FF00000000ull) >> 8; return r; } @@ -759,7 +759,7 @@ initialise_gpt(uint8_t *gpt, uint32_t current, uint32_t alternate, int primary) reverse_uuid(disk_uuid); } - header->signature = lendian_64(0x5452415020494645); + header->signature = lendian_64(0x5452415020494645ull); header->revision = lendian_int(0x010000); header->headerSize = lendian_int(0x5c); header->currentLBA = lendian_64(current); diff --git a/win/syslinux.c b/win/syslinux.c index 669450eb..f8e27801 100644 --- a/win/syslinux.c +++ b/win/syslinux.c @@ -236,6 +236,53 @@ int libfat_readfile(intptr_t pp, void *buf, size_t secsize, return secsize; } +static void move_file(char *pathname, char *filename) +{ + char new_name[strlen(opt.directory) + 16]; + char *cp = new_name + 3; + const char *sd; + int slash = 1; + + new_name[0] = opt.device[0]; + new_name[1] = ':'; + new_name[2] = '\\'; + + for (sd = opt.directory; *sd; sd++) { + char c = *sd; + + if (c == '/' || c == '\\') { + if (slash) + continue; + c = '\\'; + slash = 1; + } else { + slash = 0; + } + + *cp++ = c; + } + + /* Skip if subdirectory == root */ + if (cp > new_name + 3) { + if (!slash) + *cp++ = '\\'; + + memcpy(cp, filename, 12); + + /* Delete any previous file */ + SetFileAttributes(pathname, FILE_ATTRIBUTE_NORMAL); + DeleteFile(pathname); + if (!MoveFile(pathname, new_name)) + SetFileAttributes(pathname, FILE_ATTRIBUTE_READONLY | + FILE_ATTRIBUTE_SYSTEM | + FILE_ATTRIBUTE_HIDDEN); + else + SetFileAttributes(new_name, FILE_ATTRIBUTE_READONLY | + FILE_ATTRIBUTE_SYSTEM | + FILE_ATTRIBUTE_HIDDEN); + } +} + int main(int argc, char *argv[]) { HANDLE f_handle, d_handle; @@ -249,6 +296,7 @@ int main(int argc, char *argv[]) static char drive_name[] = "\\\\.\\?:"; static char drive_root[] = "?:\\"; static char ldlinux_name[] = "?:\\ldlinux.sys"; + static char ldlinuxc32_name[] = "?:\\ldlinux.c32"; const char *errmsg; struct libfat_filesystem *fs; libfat_sector_t s, *secp; @@ -290,6 +338,7 @@ int main(int argc, char *argv[]) /* Determines the drive type */ drive_name[4] = opt.device[0]; ldlinux_name[0] = opt.device[0]; + ldlinuxc32_name[0] = opt.device[0]; drive_root[0] = opt.device[0]; drive_type = GetDriveType(drive_root); @@ -340,10 +389,12 @@ int main(int argc, char *argv[]) /* Change to normal attributes to enable deletion */ /* Just ignore error if the file do not exists */ SetFileAttributes(ldlinux_name, FILE_ATTRIBUTE_NORMAL); + SetFileAttributes(ldlinuxc32_name, FILE_ATTRIBUTE_NORMAL); /* Delete the file */ /* Just ignore error if the file do not exists */ DeleteFile(ldlinux_name); + DeleteFile(ldlinuxc32_name); /* Initialize the ADV -- this should be smarter */ syslinux_reset_adv(syslinux_adv); @@ -463,52 +514,40 @@ map_done: CloseHandle(f_handle); /* Move the file to the desired location */ - if (opt.directory) { - char new_ldlinux_name[strlen(opt.directory) + 16]; - char *cp = new_ldlinux_name + 3; - const char *sd; - int slash = 1; - - new_ldlinux_name[0] = opt.device[0]; - new_ldlinux_name[1] = ':'; - new_ldlinux_name[2] = '\\'; - - for (sd = opt.directory; *sd; sd++) { - char c = *sd; - - if (c == '/' || c == '\\') { - if (slash) - continue; - c = '\\'; - slash = 1; - } else { - slash = 0; - } + if (opt.directory) + move_file(ldlinux_name, "ldlinux.sys"); - *cp++ = c; - } + f_handle = CreateFile(ldlinuxc32_name, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, CREATE_ALWAYS, + FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | + FILE_ATTRIBUTE_HIDDEN, NULL); - /* Skip if subdirectory == root */ - if (cp > new_ldlinux_name + 3) { - if (!slash) - *cp++ = '\\'; - - memcpy(cp, "ldlinux.sys", 12); - - /* Delete any previous file */ - SetFileAttributes(new_ldlinux_name, FILE_ATTRIBUTE_NORMAL); - DeleteFile(new_ldlinux_name); - if (!MoveFile(ldlinux_name, new_ldlinux_name)) - SetFileAttributes(ldlinux_name, FILE_ATTRIBUTE_READONLY | - FILE_ATTRIBUTE_SYSTEM | - FILE_ATTRIBUTE_HIDDEN); - else - SetFileAttributes(new_ldlinux_name, FILE_ATTRIBUTE_READONLY | - FILE_ATTRIBUTE_SYSTEM | - FILE_ATTRIBUTE_HIDDEN); - } + if (f_handle == INVALID_HANDLE_VALUE) { + error("Unable to create ldlinux.c32"); + exit(1); + } + + /* Write ldlinux.c32 file */ + if (!WriteFile(f_handle, syslinux_ldlinuxc32, syslinux_ldlinuxc32_len, + &bytes_written, NULL) || + bytes_written != syslinux_ldlinuxc32_len) { + error("Could not write ldlinux.c32"); + exit(1); + } + + /* Now flush the media */ + if (!FlushFileBuffers(f_handle)) { + error("FlushFileBuffers failed"); + exit(1); } + CloseHandle(f_handle); + + /* Move the file to the desired location */ + if (opt.directory) + move_file(ldlinuxc32_name, "ldlinux.c32"); + /* Make the syslinux boot sector */ syslinux_make_bootsect(sectbuf, fs_type); diff --git a/win32/Makefile b/win32/Makefile index 943a966a..a417a4b8 100644 --- a/win32/Makefile +++ b/win32/Makefile @@ -57,6 +57,7 @@ LIBSRC = ../libinstaller/fs.c \ ../libinstaller/getopt/getopt_long.c \ ../libinstaller/bootsect_bin.c \ ../libinstaller/ldlinux_bin.c \ + ../libinstaller/ldlinuxc32_bin.c \ ../libinstaller/mbr_bin.c \ $(wildcard $(SRC)/../libfat/*.c) LIBOBJS = $(patsubst %.c,%.obj,$(notdir $(LIBSRC))) diff --git a/win64/Makefile b/win64/Makefile index f28570ae..176f8482 100644 --- a/win64/Makefile +++ b/win64/Makefile @@ -47,6 +47,7 @@ LIBSRC = ../libinstaller/fs.c \ ../libinstaller/getopt/getopt_long.c \ ../libinstaller/bootsect_bin.c \ ../libinstaller/ldlinux_bin.c \ + ../libinstaller/ldlinuxc32_bin.c \ ../libinstaller/mbr_bin.c \ $(wildcard $(SRC)/../libfat/*.c) LIBOBJS = $(patsubst %.c,%.obj,$(notdir $(LIBSRC))) |