diff options
Diffstat (limited to 'com32')
166 files changed, 12447 insertions, 3171 deletions
diff --git a/com32/MCONFIG b/com32/MCONFIG deleted file mode 100644 index a74ed326..00000000 --- a/com32/MCONFIG +++ /dev/null @@ -1,98 +0,0 @@ -## -*- makefile -*- ------------------------------------------------------- -## -## Copyright 2008-2009 H. Peter Anvin - All Rights Reserved -## Copyright 2009 Intel Corporation; author: H. Peter Anvin -## -## 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., 51 Franklin St, Fifth Floor, -## Boston MA 02110-1301, USA; either version 2 of the License, or -## (at your option) any later version; incorporated herein by reference. -## -## ----------------------------------------------------------------------- - -## -## COM32 common configurables -## - -include $(topdir)/MCONFIG - -GCCOPT := $(call gcc_ok,-std=gnu99,) -GCCOPT += $(call gcc_ok,-m32,) -GCCOPT += $(call gcc_ok,-fno-stack-protector,) -GCCOPT += $(call gcc_ok,-fwrapv,) -GCCOPT += $(call gcc_ok,-freg-struct-return,) -GCCOPT += -mregparm=3 -DREGPARM=3 -march=i386 -Os -GCCOPT += $(call gcc_ok,-fPIE,-fPIC) -GCCOPT += $(call gcc_ok,-fno-exceptions,) -GCCOPT += $(call gcc_ok,-fno-asynchronous-unwind-tables,) -GCCOPT += $(call gcc_ok,-fno-strict-aliasing,) -GCCOPT += $(call gcc_ok,-falign-functions=0,-malign-functions=0) -GCCOPT += $(call gcc_ok,-falign-jumps=0,-malign-jumps=0) -GCCOPT += $(call gcc_ok,-falign-labels=0,-malign-labels=0) -GCCOPT += $(call gcc_ok,-falign-loops=0,-malign-loops=0) -GCCOPT += $(call gcc_ok,-mpreferred-stack-boundary=2,) -GCCOPT += $(call gcc_ok,-incoming-stack-boundary=2,) - -com32 := $(topdir)/com32 -RELOCS := $(com32)/tools/relocs - -ifneq ($(NOGPL),1) -GPLLIB = $(com32)/gpllib/libcom32gpl.a -GPLINCLUDE = -I$(com32)/gplinclude -else -GPLLIB = -GPLINCLUDE = -endif - -CFLAGS = $(GCCOPT) $(GCCWARN) -march=i386 \ - -fomit-frame-pointer -D__COM32__ \ - -nostdinc -iwithprefix include \ - -I$(com32)/libutil/include -I$(com32)/include $(GPLINCLUDE) -SFLAGS = $(GCCOPT) $(GCCWARN) -march=i386 \ - -fomit-frame-pointer -D__COM32__ \ - -nostdinc -iwithprefix include \ - -I$(com32)/libutil/include -I$(com32)/include $(GPLINCLUDE) - -COM32LD = $(com32)/lib/com32.ld -LDFLAGS = -m elf_i386 --emit-relocs -T $(COM32LD) -LIBGCC := $(shell $(CC) $(GCCOPT) --print-libgcc) - -LNXCFLAGS = -I$(com32)/libutil/include $(GCCWARN) -O -g \ - -D_GNU_SOURCE -D_FORTIFY_SOURCE=0 -Wno-error -LNXSFLAGS = -g -LNXLDFLAGS = -g - -C_LIBS = $(com32)/libutil/libutil_com.a $(GPLLIB) \ - $(com32)/lib/libcom32.a $(LIBGCC) -C_LNXLIBS = $(com32)/libutil/libutil_lnx.a - -.SUFFIXES: .lss .c .lo .o .elf .c32 .lnx - -.PRECIOUS: %.o -%.o: %.S - $(CC) $(MAKEDEPS) $(SFLAGS) -c -o $@ $< - -.PRECIOUS: %.o -%.o: %.c - $(CC) $(MAKEDEPS) $(CFLAGS) -c -o $@ $< - -.PRECIOUS: %.elf -%.elf: %.o $(LIBS) $(C_LIBS) $(COM32LD) - $(LD) $(LDFLAGS) -o $@ $(filter-out $(COM32LD),$^) - -.PRECIOUS: %.lo -%.lo: %.S - $(CC) $(MAKEDEPS) $(LNXSFLAGS) -c -o $@ $< - -.PRECIOUS: %.lo -%.lo: %.c - $(CC) $(MAKEDEPS) $(LNXCFLAGS) -c -o $@ $< - -.PRECIOUS: %.lnx -%.lnx: %.lo $(LNXLIBS) $(C_LNXLIBS) - $(CC) $(LNXCFLAGS) -o $@ $^ - -%.c32: %.elf - $(OBJCOPY) -O binary $< $@ - $(RELOCS) $< >> $@ || ( rm -f $@ ; false ) diff --git a/com32/Makefile b/com32/Makefile index b090c403..b59fd3f9 100644 --- a/com32/Makefile +++ b/com32/Makefile @@ -1,5 +1,5 @@ -SUBDIRS = tools lib gpllib libutil modules mboot menu samples rosh cmenu \ - hdt gfxboot sysdump lua/src +SUBDIRS = libupload tools lib gpllib libutil modules mboot menu samples rosh cmenu \ + hdt gfxboot sysdump lua/src chain all tidy dist clean spotless install: set -e; for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done diff --git a/com32/chain/Makefile b/com32/chain/Makefile new file mode 100644 index 00000000..9d398a85 --- /dev/null +++ b/com32/chain/Makefile @@ -0,0 +1,42 @@ +## ----------------------------------------------------------------------- +## +## Copyright 2001-2010 H. Peter Anvin - All Rights Reserved +## Copyright 2010 Michal Soltys +## +## 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. +## +## ----------------------------------------------------------------------- + + +topdir = ../.. +MAKEDIR = $(topdir)/mk +include $(MAKEDIR)/com32.mk + +OBJS = chain.o partiter.o utility.o options.o mangle.o + +all: chain.c32 + +chain.elf: $(OBJS) $(LIBS) $(C_LIBS) + $(LD) $(LDFLAGS) -o $@ $^ + +%.o: %.c + $(CC) $(MAKEDEPS) $(CFLAGS) $(CHAINEXTOPT) -c -o $@ $< + +tidy dist: + rm -f *.o *.lo *.a *.lst *.elf .*.d *.tmp + +clean: tidy + rm -f *.lnx + +spotless: clean + rm -f *.lss *.c32 *.com + rm -f *~ \#* + +install: + + +-include .*.d diff --git a/com32/chain/chain.c b/com32/chain/chain.c new file mode 100644 index 00000000..30153c4d --- /dev/null +++ b/com32/chain/chain.c @@ -0,0 +1,658 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin + * Copyright 2010 Shao Miller + * Copyright 2010 Michal Soltys + * + * 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. + * + * ----------------------------------------------------------------------- */ + +/* + * Please see doc/chain.txt for the detailed documentation. + */ + +#include <com32.h> +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <console.h> +#include <consoles.h> +#include <minmax.h> +#include <stdbool.h> +#include <dprintf.h> +#include <errno.h> +#include <unistd.h> +#include <syslinux/loadfile.h> +#include <syslinux/bootrm.h> +#include <syslinux/config.h> +#include <syslinux/disk.h> +#include <syslinux/video.h> +#include "common.h" +#include "chain.h" +#include "utility.h" +#include "options.h" +#include "partiter.h" +#include "mangle.h" + +static int fixed_cnt = 128; /* see comments in main() */ + +static int overlap(const struct data_area *a, const struct data_area *b) +{ + return + a->base + a->size > b->base && + b->base + b->size > a->base; +} + +static int is_phys(uint8_t sdifs) +{ + return + sdifs == SYSLINUX_FS_SYSLINUX || + sdifs == SYSLINUX_FS_EXTLINUX || + sdifs == SYSLINUX_FS_ISOLINUX; +} + +/* + * Search for a specific drive, based on the MBR signature. + * Return drive and iterator at 0th position. + */ +static int find_by_sig(uint32_t mbr_sig, + struct part_iter **_boot_part) +{ + struct part_iter *boot_part = NULL; + struct disk_info diskinfo; + int drive; + + for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) { + if (disk_get_params(drive, &diskinfo)) + continue; /* Drive doesn't exist */ + if (!(boot_part = pi_begin(&diskinfo, 0))) + continue; + /* Check for a MBR disk */ + if (boot_part->type != typedos) { + pi_del(&boot_part); + continue; + } + if (boot_part->sub.dos.disk_sig == mbr_sig) { + goto ok; + } + } + drive = -1; +ok: + *_boot_part = boot_part; + return drive; +} + +/* + * Search for a specific drive/partition, based on the GPT GUID. + * Return drive and iterator at proper position. + */ +static int find_by_guid(const struct guid *gpt_guid, + struct part_iter **_boot_part) +{ + struct part_iter *boot_part = NULL; + struct disk_info diskinfo; + int drive; + + for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) { + if (disk_get_params(drive, &diskinfo)) + continue; /* Drive doesn't exist */ + if (!(boot_part = pi_begin(&diskinfo, 0))) + continue; + /* Check for a GPT disk */ + if (boot_part->type != typegpt) { + pi_del(&boot_part); + continue; + } + /* Check for a matching GPT disk guid */ + if (!memcmp(&boot_part->sub.gpt.disk_guid, gpt_guid, sizeof(*gpt_guid))) { + goto ok; + } + /* disk guid doesn't match, maybe partition guid will */ + while (!pi_next(&boot_part)) { + if (!memcmp(&boot_part->sub.gpt.part_guid, gpt_guid, sizeof(*gpt_guid))) + goto ok; + } + } + drive = -1; +ok: + *_boot_part = boot_part; + return drive; +} + +/* + * Search for a specific drive/partition, based on the GPT label. + * Return drive and iterator at proper position. + */ +static int find_by_label(const char *label, struct part_iter **_boot_part) +{ + struct part_iter *boot_part = NULL; + struct disk_info diskinfo; + int drive; + + for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) { + if (disk_get_params(drive, &diskinfo)) + continue; /* Drive doesn't exist */ + if (!(boot_part = pi_begin(&diskinfo, 0))) + continue; + /* Check for a GPT disk */ + if (!(boot_part->type == typegpt)) { + pi_del(&boot_part); + continue; + } + /* Check for a matching partition */ + while (!pi_next(&boot_part)) { + if (!strcmp(label, boot_part->sub.gpt.part_label)) + goto ok; + } + } + drive = -1; +ok: + *_boot_part = boot_part; + return drive; +} + +static void do_boot(struct data_area *data, int ndata) +{ + uint16_t *const bios_fbm = (uint16_t *) 0x413; + addr_t dosmem = (addr_t)(*bios_fbm << 10); /* Technically a low bound */ + struct syslinux_memmap *mmap; + struct syslinux_movelist *mlist = NULL; + addr_t endimage; + uint8_t driveno = opt.regs.edx.b[0]; + uint8_t swapdrive = driveno & 0x80; + int i; + + mmap = syslinux_memory_map(); + + if (!mmap) { + error("Cannot read system memory map\n"); + return; + } + + endimage = 0; + for (i = 0; i < ndata; i++) { + if (data[i].base + data[i].size > endimage) + endimage = data[i].base + data[i].size; + } + if (endimage > dosmem) + goto too_big; + + for (i = 0; i < ndata; i++) { + if (syslinux_add_movelist(&mlist, data[i].base, + (addr_t) data[i].data, data[i].size)) + goto enomem; + } + + if (opt.swap && driveno != swapdrive) { + static const uint8_t swapstub_master[] = { + /* The actual swap code */ + 0x53, /* 00: push bx */ + 0x0f, 0xb6, 0xda, /* 01: movzx bx,dl */ + 0x2e, 0x8a, 0x57, 0x60, /* 04: mov dl,[cs:bx+0x60] */ + 0x5b, /* 08: pop bx */ + 0xea, 0, 0, 0, 0, /* 09: jmp far 0:0 */ + 0x90, 0x90, /* 0E: nop; nop */ + /* Code to install this in the right location */ + /* Entry with DS = CS; ES = SI = 0; CX = 256 */ + 0x26, 0x66, 0x8b, 0x7c, 0x4c, /* 10: mov edi,[es:si+4*0x13] */ + 0x66, 0x89, 0x3e, 0x0a, 0x00, /* 15: mov [0x0A],edi */ + 0x26, 0x8b, 0x3e, 0x13, 0x04, /* 1A: mov di,[es:0x413] */ + 0x4f, /* 1F: dec di */ + 0x26, 0x89, 0x3e, 0x13, 0x04, /* 20: mov [es:0x413],di */ + 0x66, 0xc1, 0xe7, 0x16, /* 25: shl edi,16+6 */ + 0x26, 0x66, 0x89, 0x7c, 0x4c, /* 29: mov [es:si+4*0x13],edi */ + 0x66, 0xc1, 0xef, 0x10, /* 2E: shr edi,16 */ + 0x8e, 0xc7, /* 32: mov es,di */ + 0x31, 0xff, /* 34: xor di,di */ + 0xf3, 0x66, 0xa5, /* 36: rep movsd */ + 0xbe, 0, 0, /* 39: mov si,0 */ + 0xbf, 0, 0, /* 3C: mov di,0 */ + 0x8e, 0xde, /* 3F: mov ds,si */ + 0x8e, 0xc7, /* 41: mov es,di */ + 0x66, 0xb9, 0, 0, 0, 0, /* 43: mov ecx,0 */ + 0x66, 0xbe, 0, 0, 0, 0, /* 49: mov esi,0 */ + 0x66, 0xbf, 0, 0, 0, 0, /* 4F: mov edi,0 */ + 0xea, 0, 0, 0, 0, /* 55: jmp 0:0 */ + /* pad out to segment boundary */ + 0x90, 0x90, /* 5A: ... */ + 0x90, 0x90, 0x90, 0x90, /* 5C: ... */ + }; + static uint8_t swapstub[1024]; + uint8_t *p; + + /* Note: we can't rely on either INT 13h nor the dosmem + vector to be correct at this stage, so we have to use an + installer stub to put things in the right place. + Round the installer location to a 1K boundary so the only + possible overlap is the identity mapping. */ + endimage = (endimage + 1023u) & ~1023u; + + /* Create swap stub */ + memcpy(swapstub, swapstub_master, sizeof swapstub_master); + *(uint16_t *) & swapstub[0x3a] = opt.regs.ds; + *(uint16_t *) & swapstub[0x3d] = opt.regs.es; + *(uint32_t *) & swapstub[0x45] = opt.regs.ecx.l; + *(uint32_t *) & swapstub[0x4b] = opt.regs.esi.l; + *(uint32_t *) & swapstub[0x51] = opt.regs.edi.l; + *(uint16_t *) & swapstub[0x56] = opt.regs.ip; + *(uint16_t *) & swapstub[0x58] = opt.regs.cs; + p = &swapstub[sizeof swapstub_master]; + + /* Mapping table; start out with identity mapping everything */ + for (i = 0; i < 256; i++) + p[i] = (uint8_t)i; + + /* And the actual swap */ + p[driveno] = swapdrive; + p[swapdrive] = driveno; + + /* Adjust registers */ + opt.regs.ds = opt.regs.cs = (uint16_t)(endimage >> 4); + opt.regs.esi.l = opt.regs.es = 0; + opt.regs.ecx.l = sizeof swapstub >> 2; + opt.regs.ip = 0x10; /* Installer offset */ + opt.regs.ebx.b[0] = opt.regs.edx.b[0] = swapdrive; + + if (syslinux_add_movelist(&mlist, endimage, (addr_t) swapstub, + sizeof swapstub)) + goto enomem; + + endimage += sizeof swapstub; + } + + /* Tell the shuffler not to muck with this area... */ + syslinux_add_memmap(&mmap, endimage, 0xa0000 - endimage, SMT_RESERVED); + + /* Force text mode */ + syslinux_force_text_mode(); + + fputs("Booting...\n", stdout); + syslinux_shuffle_boot_rm(mlist, mmap, opt.keeppxe, &opt.regs); + error("Chainboot failed!\n"); + return; + +too_big: + error("Loader file too large\n"); + return; + +enomem: + error("Out of memory\n"); + return; +} + +int find_dp(struct part_iter **_iter) +{ + struct part_iter *iter = NULL; + struct disk_info diskinfo; + struct guid gpt_guid; + uint64_t fs_lba; + int drive, hd, partition; + const union syslinux_derivative_info *sdi; + + sdi = syslinux_derivative_info(); + + if (!strncmp(opt.drivename, "mbr", 3)) { + if (find_by_sig(strtoul(opt.drivename + 4, NULL, 0), &iter) < 0) { + error("Unable to find requested MBR signature.\n"); + goto bail; + } + } else if (!strncmp(opt.drivename, "guid", 4)) { + if (str_to_guid(opt.drivename + 5, &gpt_guid)) + goto bail; + if (find_by_guid(&gpt_guid, &iter) < 0) { + error("Unable to find requested GPT disk or partition by guid.\n"); + goto bail; + } + } else if (!strncmp(opt.drivename, "label", 5)) { + if (!opt.drivename[6]) { + error("No label specified.\n"); + goto bail; + } + if (find_by_label(opt.drivename + 6, &iter) < 0) { + error("Unable to find requested GPT partition by label.\n"); + goto bail; + } + } else if ((opt.drivename[0] == 'h' || opt.drivename[0] == 'f') && + opt.drivename[1] == 'd') { + hd = opt.drivename[0] == 'h' ? 0x80 : 0; + opt.drivename += 2; + drive = hd | strtol(opt.drivename, NULL, 0); + + if (disk_get_params(drive, &diskinfo)) + goto bail; + /* this will start iteration over FDD, possibly raw */ + if (!(iter = pi_begin(&diskinfo, 0))) + goto bail; + + } else if (!strcmp(opt.drivename, "boot") || !strcmp(opt.drivename, "fs")) { + if (!is_phys(sdi->c.filesystem)) { + error("When syslinux is not booted from physical disk (or its emulation),\n" + "'boot' and 'fs' are meaningless.\n"); + goto bail; + } + /* offsets match, but in case it changes in the future */ + if (sdi->c.filesystem == SYSLINUX_FS_ISOLINUX) { + drive = sdi->iso.drive_number; + fs_lba = *sdi->iso.partoffset; + } else { + drive = sdi->disk.drive_number; + fs_lba = *sdi->disk.partoffset; + } + if (disk_get_params(drive, &diskinfo)) + goto bail; + /* this will start iteration over disk emulation, possibly raw */ + if (!(iter = pi_begin(&diskinfo, 0))) + goto bail; + + /* 'fs' => we should lookup the syslinux partition number and use it */ + if (!strcmp(opt.drivename, "fs")) { + while (!pi_next(&iter)) { + if (iter->start_lba == fs_lba) + break; + } + /* broken part structure or other problems */ + if (iter->status) { + error("Can't find myself on the drive I booted from.\n"); + goto bail; + } + } + } else { + error("Unparsable drive specification.\n"); + goto bail; + } + /* main options done - only thing left is explicit partition specification, + * if we're still at the disk stage with the iterator AND user supplied + * partition number (including disk pseudo-partition). + */ + if (!iter->index && opt.partition) { + partition = strtol(opt.partition, NULL, 0); + /* search for matching part#, including disk */ + do { + if (iter->index == partition) + break; + } while (!pi_next(&iter)); + if (iter->status) { + error("Requested disk / partition combination not found.\n"); + goto bail; + } + } + + if (!(iter->di.disk & 0x80) && iter->index) { + error("WARNING: Partitions on floppy devices may not work.\n"); + } + + *_iter = iter; + + return 0; + +bail: + pi_del(&iter); + return -1; +} + +static int setup_handover(const struct part_iter *iter, + struct data_area *data) +{ + struct disk_dos_part_entry *ha; + uint32_t synth_size; + uint32_t *plen; + + if (!iter->index) { /* implies typeraw or non-iterated */ + uint32_t len; + /* RAW handover protocol */ + synth_size = sizeof(struct disk_dos_part_entry); + ha = malloc(synth_size); + if (!ha) { + error("Could not build RAW hand-over record!\n"); + goto bail; + } + len = ~0u; + if (iter->length < len) + len = (uint32_t)iter->length; + lba2chs(&ha->start, &iter->di, 0, l2c_cadd); + lba2chs(&ha->end, &iter->di, len - 1, l2c_cadd); + ha->active_flag = 0x80; + ha->ostype = 0xDA; /* "Non-FS Data", anything is good here though ... */ + ha->start_lba = 0; + ha->length = len; + } else if (iter->type == typegpt) { + /* GPT handover protocol */ + synth_size = sizeof(struct disk_dos_part_entry) + + sizeof(uint32_t) + (uint32_t)iter->sub.gpt.pe_size; + ha = malloc(synth_size); + if (!ha) { + error("Could not build GPT hand-over record!\n"); + goto bail; + } + lba2chs(&ha->start, &iter->di, iter->start_lba, l2c_cadd); + lba2chs(&ha->end, &iter->di, iter->start_lba + iter->length - 1, l2c_cadd); + ha->active_flag = 0x80; + ha->ostype = 0xED; + /* All bits set by default */ + ha->start_lba = ~0u; + ha->length = ~0u; + /* If these fit the precision, pass them on */ + if (iter->start_lba < ha->start_lba) + ha->start_lba = (uint32_t)iter->start_lba; + if (iter->length < ha->length) + ha->length = (uint32_t)iter->length; + /* Next comes the GPT partition record length */ + plen = (uint32_t *) (ha + 1); + plen[0] = (uint32_t)iter->sub.gpt.pe_size; + /* Next comes the GPT partition record copy */ + memcpy(plen + 1, iter->record, plen[0]); +#ifdef DEBUG + dprintf("GPT handover:\n"); + disk_dos_part_dump(ha); + disk_gpt_part_dump((struct disk_gpt_part_entry *)(plen + 1)); +#endif + } else if (iter->type == typedos) { + /* MBR handover protocol */ + synth_size = sizeof(struct disk_dos_part_entry); + ha = malloc(synth_size); + if (!ha) { + error("Could not build MBR hand-over record!\n"); + goto bail; + } + memcpy(ha, iter->record, synth_size); + /* make sure these match bios imaginations and are ebr agnostic */ + lba2chs(&ha->start, &iter->di, iter->start_lba, l2c_cadd); + lba2chs(&ha->end, &iter->di, iter->start_lba + iter->length - 1, l2c_cadd); + ha->start_lba = (uint32_t)iter->start_lba; + ha->length = (uint32_t)iter->length; + +#ifdef DEBUG + dprintf("MBR handover:\n"); + disk_dos_part_dump(ha); +#endif + } else { + /* shouldn't ever happen */ + goto bail; + } + + data->base = 0x7be; + data->size = synth_size; + data->data = (void *)ha; + + return 0; +bail: + return -1; +} + +int main(int argc, char *argv[]) +{ + struct part_iter *iter = NULL; + void *sbck = NULL; + struct data_area fdat, hdat, sdat, data[3]; + int ndata = 0; + + console_ansi_raw(); + + memset(&fdat, 0, sizeof(fdat)); + memset(&hdat, 0, sizeof(hdat)); + memset(&sdat, 0, sizeof(sdat)); + + opt_set_defs(); + if (opt_parse_args(argc, argv)) + goto bail; + +#if 0 + /* Get max fixed disk number */ + fixed_cnt = *(uint8_t *)(0x475); + + /* + * hmm, looks like we can't do that - + * some bioses/vms just set it to 1 + * and go on living happily + * any better options than hardcoded 0x80 - 0xFF ? + */ +#endif + + /* Get disk/part iterator matching user supplied options */ + if (find_dp(&iter)) + goto bail; + + /* Perform initial partition entry mangling */ + if (manglepe_fixchs(iter)) + goto bail; + if (manglepe_hide(iter)) + goto bail; + + /* Load the boot file */ + if (opt.file) { + fdat.base = (opt.fseg << 4) + opt.foff; + + if (loadfile(opt.file, &fdat.data, &fdat.size)) { + error("Couldn't read the boot file.\n"); + goto bail; + } + if (fdat.base + fdat.size - 1 > ADDRMAX) { + error("The boot file is too big to load at this address.\n"); + goto bail; + } + } + + /* Load the sector */ + if (opt.sect) { + sdat.base = (opt.sseg << 4) + opt.soff; + sdat.size = iter->di.bps; + + if (sdat.base + sdat.size - 1 > ADDRMAX) { + error("The sector cannot be loaded at such high address.\n"); + goto bail; + } + if (!(sdat.data = disk_read_sectors(&iter->di, iter->start_lba, 1))) { + error("Couldn't read the sector.\n"); + goto bail; + } + if (opt.save) { + if (!(sbck = malloc(sdat.size))) { + error("Couldn't allocate cmp-buf for option 'save'.\n"); + goto bail; + } + memcpy(sbck, sdat.data, sdat.size); + } + if (opt.file && opt.maps && overlap(&fdat, &sdat)) { + error("WARNING: The sector won't be mmapped, as it would conflict with the boot file.\n"); + opt.maps = false; + } + } + + /* Prep the handover */ + if (opt.hand) { + if (setup_handover(iter, &hdat)) + goto bail; + /* Verify possible conflicts */ + if ( ( opt.file && overlap(&fdat, &hdat)) || + ( opt.maps && overlap(&sdat, &hdat)) ) { + error("WARNING: Handover area won't be prepared,\n" + "as it would conflict with the boot file and/or the sector.\n"); + opt.hand = false; + } + } + + /* Adjust registers */ + + mangler_init(iter); + mangler_handover(iter, &hdat); + mangler_grldr(iter); + + /* Patching functions */ + + if (manglef_isolinux(&fdat)) + goto bail; + + if (manglef_grub(iter, &fdat)) + goto bail; +#if 0 + if (manglef_drmk(&fdat)) + goto bail; +#endif + if (manglef_bpb(iter, &fdat)) + goto bail; + + if (mangles_bpb(iter, &sdat)) + goto bail; + + if (mangles_save(iter, &sdat, sbck)) + goto bail; + + if (manglesf_bss(&sdat, &fdat)) + goto bail; + + /* This *must* be after BPB saving or copying */ + if (mangles_cmldr(&sdat)) + goto bail; + + /* + * Prepare boot-time mmap data. We should to it here, as manglers could + * potentially alter some of the data. + */ + + if (opt.file) + memcpy(data + ndata++, &fdat, sizeof(fdat)); + if (opt.maps) + memcpy(data + ndata++, &sdat, sizeof(sdat)); + if (opt.hand) + memcpy(data + ndata++, &hdat, sizeof(hdat)); + +#ifdef DEBUG + printf("iter->di dsk, bps: %X, %u\niter->di lbacnt, C*H*S: %"PRIu64", %u\n" + "iter->di C, H, S: %u, %u, %u\n", + iter->di.disk, iter->di.bps, + iter->di.lbacnt, iter->di.cyl * iter->di.head * iter->di.spt, + iter->di.cyl, iter->di.head, iter->di.spt); + printf("iter idx: %d\n", iter->index); + printf("iter lba: %"PRIu64"\n", iter->start_lba); + if (opt.hand) + printf("hand lba: %u\n", + ((struct disk_dos_part_entry *)hdat.data)->start_lba); +#endif + + if (opt.warn) { + puts("Press any key to continue booting..."); + wait_key(); + } + + if (ndata && !opt.brkchain) /* boot only if we actually chainload */ + do_boot(data, ndata); + else + error("Service-only run completed, exiting.\n"); +bail: + pi_del(&iter); + /* Free allocated areas */ + free(fdat.data); + free(sdat.data); + free(hdat.data); + free(sbck); + return 255; +} + +/* vim: set ts=8 sts=4 sw=4 noet: */ diff --git a/com32/chain/chain.h b/com32/chain/chain.h new file mode 100644 index 00000000..fc481bc6 --- /dev/null +++ b/com32/chain/chain.h @@ -0,0 +1,14 @@ +#ifndef _COM32_CHAIN_CHAIN_H +#define _COM32_CHAIN_CHAIN_H + +#include <syslinux/movebits.h> + +struct data_area { + void *data; + addr_t base; + addr_t size; +}; + +#endif + +/* vim: set ts=8 sts=4 sw=4 noet: */ diff --git a/com32/chain/common.h b/com32/chain/common.h new file mode 100644 index 00000000..b170a732 --- /dev/null +++ b/com32/chain/common.h @@ -0,0 +1,9 @@ +#ifndef _COM32_CHAIN_COMMON_H +#define _COM32_CHAIN_COMMON_H + +#define ADDRMAX 0x9EFFFu +#define ADDRMIN 0x500u + +#endif + +/* vim: set ts=8 sts=4 sw=4 noet: */ diff --git a/com32/chain/mangle.c b/com32/chain/mangle.c new file mode 100644 index 00000000..8358106e --- /dev/null +++ b/com32/chain/mangle.c @@ -0,0 +1,618 @@ +#include <com32.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <dprintf.h> +#include <syslinux/config.h> +#include "common.h" +#include "chain.h" +#include "options.h" +#include "utility.h" +#include "partiter.h" +#include "mangle.h" + +static const char cmldr_signature[8] = "cmdcons"; + +/* Create boot info table: needed when you want to chainload + * another version of ISOLINUX (or another bootlaoder that needs + * the -boot-info-table switch of mkisofs) + * (will only work when run from ISOLINUX) + */ +int manglef_isolinux(struct data_area *data) +{ + const union syslinux_derivative_info *sdi; + unsigned char *isolinux_bin; + uint32_t *checksum, *chkhead, *chktail; + uint32_t file_lba = 0; + + if (!(opt.file && opt.isolinux)) + return 0; + + sdi = syslinux_derivative_info(); + + if (sdi->c.filesystem != SYSLINUX_FS_ISOLINUX) { + error ("The isolinux= option is only valid when run from ISOLINUX.\n"); + goto bail; + } + + /* Boot info table info (integers in little endian format) + + Offset Name Size Meaning + 8 bi_pvd 4 bytes LBA of primary volume descriptor + 12 bi_file 4 bytes LBA of boot file + 16 bi_length 4 bytes Boot file length in bytes + 20 bi_csum 4 bytes 32-bit checksum + 24 bi_reserved 40 bytes Reserved + + The 32-bit checksum is the sum of all the 32-bit words in the + boot file starting at byte offset 64. All linear block + addresses (LBAs) are given in CD sectors (normally 2048 bytes). + + LBA of primary volume descriptor should already be set to 16. + */ + + isolinux_bin = (unsigned char *)data->data; + + /* Get LBA address of bootfile */ + file_lba = get_file_lba(opt.file); + + if (file_lba == 0) { + error("Failed to find LBA offset of the boot file\n"); + goto bail; + } + /* Set it */ + *((uint32_t *) & isolinux_bin[12]) = file_lba; + + /* Set boot file length */ + *((uint32_t *) & isolinux_bin[16]) = data->size; + + /* Calculate checksum */ + checksum = (uint32_t *) & isolinux_bin[20]; + chkhead = (uint32_t *) & isolinux_bin[64]; + chktail = (uint32_t *) & isolinux_bin[data->size & ~3u]; + *checksum = 0; + while (chkhead < chktail) + *checksum += *chkhead++; + + /* + * Deal with possible fractional dword at the end; + * this *should* never happen... + */ + if (data->size & 3) { + uint32_t xword = 0; + memcpy(&xword, chkhead, data->size & 3); + *checksum += xword; + } + return 0; +bail: + return -1; +} + +/* + * Legacy grub's stage2 chainloading + */ +int manglef_grub(const struct part_iter *iter, struct data_area *data) +{ + /* Layout of stage2 file (from byte 0x0 to 0x270) */ + struct grub_stage2_patch_area { + /* 0x0 to 0x205 */ + char unknown[0x206]; + /* 0x206: compatibility version number major */ + uint8_t compat_version_major; + /* 0x207: compatibility version number minor */ + uint8_t compat_version_minor; + + /* 0x208: install_partition variable */ + struct { + /* 0x208: sub-partition in sub-partition part2 */ + uint8_t part3; + /* 0x209: sub-partition in top-level partition */ + uint8_t part2; + /* 0x20a: top-level partiton number */ + uint8_t part1; + /* 0x20b: BIOS drive number (must be 0) */ + uint8_t drive; + } __attribute__ ((packed)) install_partition; + + /* 0x20c: deprecated (historical reason only) */ + uint32_t saved_entryno; + /* 0x210: stage2_ID: will always be STAGE2_ID_STAGE2 = 0 in stage2 */ + uint8_t stage2_id; + /* 0x211: force LBA */ + uint8_t force_lba; + /* 0x212: version string (will probably be 0.97) */ + char version_string[5]; + /* 0x217: config filename */ + char config_file[89]; + /* 0x270: start of code (after jump from 0x200) */ + char codestart[1]; + } __attribute__ ((packed)) *stage2; + + if (!(opt.file && opt.grub)) + return 0; + + if (data->size < sizeof(struct grub_stage2_patch_area)) { + error("The file specified by grub=<loader> is too small to be stage2 of GRUB Legacy.\n"); + goto bail; + } + stage2 = data->data; + + /* + * Check the compatibility version number to see if we loaded a real + * stage2 file or a stage2 file that we support. + */ + if (stage2->compat_version_major != 3 + || stage2->compat_version_minor != 2) { + error("The file specified by grub=<loader> is not a supported stage2 GRUB Legacy binary.\n"); + goto bail; + } + + /* + * GRUB Legacy wants the partition number in the install_partition + * variable, located at offset 0x208 of stage2. + * When GRUB Legacy is loaded, it is located at memory address 0x8208. + * + * It looks very similar to the "boot information format" of the + * Multiboot specification: + * http://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Boot-information-format + * + * 0x208 = part3: sub-partition in sub-partition part2 + * 0x209 = part2: sub-partition in top-level partition + * 0x20a = part1: top-level partition number + * 0x20b = drive: BIOS drive number (must be 0) + * + * GRUB Legacy doesn't store the BIOS drive number at 0x20b, but at + * another location. + * + * Partition numbers always start from zero. + * Unused partition bytes must be set to 0xFF. + * + * We only care about top-level partition, so we only need to change + * "part1" to the appropriate value: + * -1: whole drive (default) (-1 = 0xFF) + * 0-3: primary partitions + * 4-*: logical partitions + */ + stage2->install_partition.part1 = (uint8_t)(iter->index - 1); + + /* + * Grub Legacy reserves 89 bytes (from 0x8217 to 0x826f) for the + * config filename. The filename passed via grubcfg= will overwrite + * the default config filename "/boot/grub/menu.lst". + */ + if (opt.grubcfg) { + if (strlen(opt.grubcfg) > sizeof(stage2->config_file) - 1) { + error ("The config filename length can't exceed 88 characters.\n"); + goto bail; + } + + strcpy((char *)stage2->config_file, opt.grubcfg); + } + + return 0; +bail: + return -1; +} +#if 0 +/* + * Dell's DRMK chainloading. + */ +int manglef_drmk(struct data_area *data) +{ + /* + * DRMK entry is different than MS-DOS/PC-DOS + * A new size, aligned to 16 bytes to ease use of ds:[bp+28]. + * We only really need 4 new, usable bytes at the end. + */ + + if (!(opt.file && opt.drmk)) + return 0; + + uint32_t tsize = (data->size + 19) & 0xfffffff0; + const union syslinux_derivative_info *sdi; + uint64_t fs_lba; + + sdi = syslinux_derivative_info(); + /* We should lookup the Syslinux partition offset and use it */ + fs_lba = *sdi->disk.partoffset; + + /* + * fs_lba should be verified against the disk as some DRMK + * variants will check and fail if it does not match + */ + dprintf(" fs_lba offset is %d\n", fs_lba); + /* DRMK only uses a DWORD */ + if (fs_lba > 0xffffffff) { + error("LBA very large; Only using lower 32 bits; DRMK will probably fail\n"); + } + opt.regs.ss = opt.regs.fs = opt.regs.gs = 0; /* Used before initialized */ + if (!realloc(data->data, tsize)) { + error("Failed to realloc for DRMK.\n"); + goto bail; + } + data->size = tsize; + /* ds:bp is assumed by DRMK to be the boot sector */ + /* offset 28 is the FAT HiddenSectors value */ + opt.regs.ds = (uint16_t)((tsize >> 4) + (opt.fseg - 2)); + /* "Patch" into tail of the new space */ + *(uint32_t *)((char*)data->data + tsize - 4) = (uint32_t)fs_lba; + + return 0; +bail: + return -1; +} +#endif +/* Adjust BPB common function */ +static int mangle_bpb(const struct part_iter *iter, struct data_area *data, const char *tag) +{ + unsigned int off; + int type = bpb_detect(data->data, tag); + + /* BPB: hidden sectors 32bit*/ + if (type >= bpbV34) { + if (iter->start_lba < ~0u) + *(uint32_t *) ((char *)data->data + 0x1c) = (uint32_t)iter->start_lba; + else + /* won't really help much, but ... */ + *(uint32_t *) ((char *)data->data + 0x1c) = ~0u; + } + /* BPB: hidden sectors 16bit*/ + if (bpbV30 <= type && type <= bpbV32) { + if (iter->start_lba < 0xFFFF) + *(uint16_t *) ((char *)data->data + 0x1c) = (uint16_t)iter->start_lba; + else + /* won't really help much, but ... */ + *(uint16_t *) ((char *)data->data + 0x1c) = (uint16_t)~0u; + } + /* BPB: legacy geometry */ + if (type >= bpbV30) { + if (iter->di.cbios) + *(uint32_t *)((char *)data->data + 0x18) = (uint32_t)((iter->di.head << 16) | iter->di.spt); + else { + if (iter->di.disk & 0x80) + *(uint32_t *)((char *)data->data + 0x18) = 0x00FF003F; + else + *(uint32_t *)((char *)data->data + 0x18) = 0x00020012; + } + } + /* BPB: drive */ + if (drvoff_detect(type, &off)) { + *(uint8_t *)((char *)data->data + off) = (uint8_t) + (opt.swap ? iter->di.disk & 0x80 : iter->di.disk); + } + + return 0; +} + +/* + * Adjust BPB of a BPB-compatible file + */ +int manglef_bpb(const struct part_iter *iter, struct data_area *data) +{ + if (!(opt.file && opt.filebpb)) + return 0; + + return mangle_bpb(iter, data, "file"); +} + +/* + * Adjust BPB of a sector + */ +int mangles_bpb(const struct part_iter *iter, struct data_area *data) +{ + if (!(opt.sect && opt.setbpb)) + return 0; + + return mangle_bpb(iter, data, "sect"); +} + +/* + * This function performs full BPB patching, analogously to syslinux's + * native BSS. + */ +int manglesf_bss(struct data_area *sec, struct data_area *fil) +{ + int type1, type2; + unsigned int cnt = 0; + + if (!(opt.sect && opt.file && opt.bss)) + return 0; + + type1 = bpb_detect(fil->data, "bss/file"); + type2 = bpb_detect(sec->data, "bss/sect"); + + if (!type1 || !type2) { + error("Couldn't determine the BPB type for option 'bss'.\n"); + goto bail; + } + if (type1 != type2) { + error("Option 'bss' can't be used,\n" + "when a sector and a file have incompatible BPBs.\n"); + goto bail; + } + + /* Copy common 2.0 data */ + memcpy((char *)fil->data + 0x0B, (char *)sec->data + 0x0B, 0x0D); + + /* Copy 3.0+ data */ + if (type1 <= bpbV30) { + cnt = 0x06; + } else if (type1 <= bpbV32) { + cnt = 0x08; + } else if (type1 <= bpbV34) { + cnt = 0x0C; + } else if (type1 <= bpbV40) { + cnt = 0x2E; + } else if (type1 <= bpbVNT) { + cnt = 0x3C; + } else if (type1 <= bpbV70) { + cnt = 0x42; + } + memcpy((char *)fil->data + 0x18, (char *)sec->data + 0x18, cnt); + + return 0; +bail: + return -1; +} + +/* + * Save sector. + */ +int mangles_save(const struct part_iter *iter, const struct data_area *data, void *org) +{ + if (!(opt.sect && opt.save)) + return 0; + + if (memcmp(org, data->data, data->size)) { + if (disk_write_sectors(&iter->di, iter->start_lba, data->data, 1)) { + error("Cannot write the updated sector.\n"); + goto bail; + } + /* function can be called again */ + memcpy(org, data->data, data->size); + } + + return 0; +bail: + return -1; +} + +/* + * To boot the Recovery Console of Windows NT/2K/XP we need to write + * the string "cmdcons\0" to memory location 0000:7C03. + * Memory location 0000:7C00 contains the bootsector of the partition. + */ +int mangles_cmldr(struct data_area *data) +{ + if (!(opt.sect && opt.cmldr)) + return 0; + + memcpy((char *)data->data + 3, cmldr_signature, sizeof(cmldr_signature)); + return 0; +} + +/* Set common registers */ +int mangler_init(const struct part_iter *iter) +{ + /* Set initial registry values */ + if (opt.file) { + opt.regs.cs = opt.regs.ds = opt.regs.ss = (uint16_t)opt.fseg; + opt.regs.ip = (uint16_t)opt.fip; + } else { + opt.regs.cs = opt.regs.ds = opt.regs.ss = (uint16_t)opt.sseg; + opt.regs.ip = (uint16_t)opt.sip; + } + + if (opt.regs.ip == 0x7C00 && !opt.regs.cs) + opt.regs.esp.l = 0x7C00; + + /* DOS kernels want the drive number in BL instead of DL. Indulge them. */ + opt.regs.ebx.b[0] = opt.regs.edx.b[0] = (uint8_t)iter->di.disk; + + return 0; +} + +/* ds:si & ds:bp */ +int mangler_handover(const struct part_iter *iter, const struct data_area *data) +{ + if (opt.file && opt.maps && !opt.hptr) { + opt.regs.esi.l = opt.regs.ebp.l = opt.soff; + opt.regs.ds = (uint16_t)opt.sseg; + opt.regs.eax.l = 0; + } else if (opt.hand) { + /* base is really 0x7be */ + opt.regs.esi.l = opt.regs.ebp.l = data->base; + opt.regs.ds = 0; + if (iter->index && iter->type == typegpt) /* must be iterated and GPT */ + opt.regs.eax.l = 0x54504721; /* '!GPT' */ + else + opt.regs.eax.l = 0; + } + + return 0; +} + +/* + * GRLDR of GRUB4DOS wants the partition number in DH: + * -1: whole drive (default) + * 0-3: primary partitions + * 4-*: logical partitions + */ +int mangler_grldr(const struct part_iter *iter) +{ + if (opt.grldr) + opt.regs.edx.b[1] = (uint8_t)(iter->index - 1); + + return 0; +} + +/* + * try to copy values from temporary iterator, if positions match + */ +static void push_embr(struct part_iter *diter, struct part_iter *siter) +{ + if (diter->sub.dos.cebr_lba == siter->sub.dos.cebr_lba && + diter->di.disk == siter->di.disk) { + memcpy(diter->data, siter->data, sizeof(struct disk_dos_mbr)); + } +} + +static int mpe_sethide(struct part_iter *iter, struct part_iter *miter) +{ + struct disk_dos_part_entry *dp; + static const uint16_t mask = + (1 << 0x01) | (1 << 0x04) | (1 << 0x06) | + (1 << 0x07) | (1 << 0x0b) | (1 << 0x0c) | (1 << 0x0e); + uint8_t t; + + dp = (struct disk_dos_part_entry *)iter->record; + t = dp->ostype; + + if ((t <= 0x1f) && ((mask >> (t & ~0x10u)) & 1)) { + /* It's a hideable partition type */ + if (miter->index == iter->index || opt.hide & 4) + t &= (uint8_t)(~0x10u); /* unhide */ + else + t |= 0x10u; /* hide */ + } + if (dp->ostype != t) { + dp->ostype = t; + return -1; + } + return 0; +} + +/* + * miter - iterator we match against + * hide bits meaning: + * ..| - enable (1) / disable (0) + * .|. - all (1) / pri (0) + * |.. - unhide (1) / hide (0) + */ +int manglepe_hide(struct part_iter *miter) +{ + int wb = 0, werr = 0; + struct part_iter *iter = NULL; + struct disk_dos_part_entry *dp; + int ridx; + + if (!opt.hide) + return 0; + + if (miter->type != typedos) { + error("Options '*hide*' is meaningful only for legacy partition scheme.\n"); + return -1; + } + + if (miter->index < 1) + error("WARNING: It's impossible to unhide a disk.\n"); + + if (miter->index > 4 && !(opt.hide & 2)) + error("WARNING: your partition is beyond mbr, so it can't be unhidden without '*hideall'.\n"); + + if (!(iter = pi_begin(&miter->di, 1))) /* turn stepall on */ + return -1; + + while (!pi_next(&iter) && !werr) { + ridx = iter->rawindex; + if (!(opt.hide & 2) && ridx > 4) + break; /* skip when we're constrained to pri only */ + + dp = (struct disk_dos_part_entry *)iter->record; + if (dp->ostype) + wb |= mpe_sethide(iter, miter); + + if (ridx >= 4 && wb && !werr) { + push_embr(miter, iter); + werr |= disk_write_sectors(&iter->di, iter->sub.dos.cebr_lba, iter->data, 1); + wb = 0; + } + } + + if (iter->status > PI_DONE) + goto bail; + + /* last write */ + if (wb && !werr) { + push_embr(miter, iter); + werr |= disk_write_sectors(&iter->di, iter->sub.dos.cebr_lba, iter->data, 1); + } + if (werr) + error("WARNING: failed to write E/MBR during '*hide*'\n"); + +bail: + pi_del(&iter); + return 0; +} + +static int mpe_setchs(const struct disk_info *di, + struct disk_dos_part_entry *dp, + uint32_t lba1) +{ + uint32_t ochs1, ochs2; + + ochs1 = *(uint32_t *)dp->start; + ochs2 = *(uint32_t *)dp->end; + + lba2chs(&dp->start, di, lba1, l2c_cadd); + lba2chs(&dp->end, di, lba1 + dp->length - 1, l2c_cadd); + + return + *(uint32_t *)dp->start != ochs1 || + *(uint32_t *)dp->end != ochs2; +} + +/* + * miter - iterator we match against + */ +int manglepe_fixchs(struct part_iter *miter) +{ + int wb = 0, werr = 0; + struct part_iter *iter = NULL; + struct disk_dos_part_entry *dp; + int ridx; + + if (!opt.fixchs) + return 0; + + if (miter->type != typedos) { + error("Options 'fixchs' is meaningful only for legacy partition scheme.\n"); + return -1; + } + + if (!(iter = pi_begin(&miter->di, 1))) /* turn stepall on */ + return -1; + + while (!pi_next(&iter) && !werr) { + ridx = iter->rawindex; + dp = (struct disk_dos_part_entry *)iter->record; + + wb |= mpe_setchs(&iter->di, dp, (uint32_t)iter->start_lba); + if (ridx > 4) + wb |= mpe_setchs(&iter->di, dp + 1, iter->sub.dos.nebr_lba); + + if (ridx >= 4 && wb && !werr) { + push_embr(miter, iter); + werr |= disk_write_sectors(&iter->di, iter->sub.dos.cebr_lba, iter->data, 1); + wb = 0; + } + } + + if (iter->status > PI_DONE) + goto bail; + + /* last write */ + if (wb && !werr) { + push_embr(miter, iter); + werr |= disk_write_sectors(&iter->di, iter->sub.dos.cebr_lba, iter->data, 1); + } + if (werr) + error("WARNING: failed to write E/MBR during 'fixchs'\n"); + +bail: + pi_del(&iter); + return 0; +} + +/* vim: set ts=8 sts=4 sw=4 noet: */ diff --git a/com32/chain/mangle.h b/com32/chain/mangle.h new file mode 100644 index 00000000..bcefea3b --- /dev/null +++ b/com32/chain/mangle.h @@ -0,0 +1,32 @@ +#ifndef _COM32_CHAIN_MANGLE_H +#define _COM32_CHAIN_MANGLE_H + +#include "chain.h" +#include "partiter.h" + +/* file's manglers */ +int manglef_isolinux(struct data_area *data); +int manglef_grub(const struct part_iter *iter, struct data_area *data); +int manglef_bpb(const struct part_iter *iter, struct data_area *data); +/* int manglef_drmk(struct data_area *data);*/ + +/* sector's manglers */ +int mangles_bpb(const struct part_iter *iter, struct data_area *data); +int mangles_save(const struct part_iter *iter, const struct data_area *data, void *org); +int mangles_cmldr(struct data_area *data); + +/* sector + file's manglers */ +int manglesf_bss(struct data_area *sec, struct data_area *fil); + +/* registers' manglers */ +int mangler_init(const struct part_iter *iter); +int mangler_handover(const struct part_iter *iter, const struct data_area *data); +int mangler_grldr(const struct part_iter *iter); + +/* partition layout's manglers */ +int manglepe_fixchs(struct part_iter *miter); +int manglepe_hide(struct part_iter *miter); + +#endif + +/* vim: set ts=8 sts=4 sw=4 noet: */ diff --git a/com32/chain/options.c b/com32/chain/options.c new file mode 100644 index 00000000..658a45ca --- /dev/null +++ b/com32/chain/options.c @@ -0,0 +1,376 @@ +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include "common.h" +#include "chain.h" +#include "utility.h" +#include "options.h" + +struct options opt; + +static int soi_s2n(char *ptr, unsigned int *seg, + unsigned int *off, + unsigned int *ip, + unsigned int def) +{ + unsigned int segval = 0, offval, ipval, val; + char *p; + + offval = def; + ipval = def; + + segval = strtoul(ptr, &p, 0); + if (p[0] == ':' && p[1] && p[1] != ':') + offval = strtoul(p+1, &p, 0); + if (p[0] == ':' && p[1] && p[1] != ':') + ipval = strtoul(p+1, NULL, 0); + + val = (segval << 4) + offval; + + if (val < ADDRMIN || val > ADDRMAX) { + error("Invalid seg:off:* address specified..\n"); + goto bail; + } + + val = (segval << 4) + ipval; + + if (ipval > 0xFFFE || val < ADDRMIN || val > ADDRMAX) { + error("Invalid seg:*:ip address specified.\n"); + goto bail; + } + + if (seg) + *seg = segval; + if (off) + *off = offval; + if (ip) + *ip = ipval; + + return 0; +bail: + return -1; +} + +static void usage(void) +{ + unsigned int i; + static const char key[] = "Press any key...\n"; + static const char *const usage[] = { +"\ +Usage:\n\ + chain.c32 [options]\n\ + chain.c32 {fd|hd}<disk#>{,| }[<part#>] [options]\n\ + chain.c32 mbr{:|=}<id>{,| }[<part#>] [options]\n\ + chain.c32 guid{:|=}<guid>{,| }[<part#>] [options]\n\ + chain.c32 label{:|=}<label> [<part#>] [options]\n\ + chain.c32 boot{,| }[<part#>] [options]\n\ + chain.c32 fs [options]\n\ +", "\ +\nOptions ('no' prefix specifies default value):\n\ + sect[=<s[:o[:i]]>] Load sector at <s:o>, jump to <s:i>\n\ + - defaults to 0:0x7C00:0x7C00\n\ + - ommited o/i values default to 0\n\ + maps Map loaded sector into real memory\n\ + nosetbpb Fix BPB fields in loaded sector\n\ + nofilebpb Apply 'setbpb' to loaded file\n\ + nosave Write adjusted sector back to disk\n\ + hand Prepare handover area\n\ + nohptr Force ds:si and ds:bp to point to handover area\n\ + noswap Swap drive numbers, if bootdisk is not fd0/hd0\n\ + nohide Disable all hide variations (also the default)\n\ + hide Hide primary partitions, unhide selected partition\n\ + hideall Hide *all* partitions, unhide selected partition\n\ + unhide Unhide primary partitions\n\ + unhideall Unhide *all* partitions\n\ + nofixchs Walk *all* partitions and fix E/MBRs' chs values\n\ + nokeeppxe Keep the PXE and UNDI stacks in memory (PXELINUX)\n\ + nowarn Wait for a keypress to continue chainloading\n\ + - useful to see emited warnings\n\ + nobreak Actually perform the chainloading\n\ +", "\ +\nOptions continued ...\n\ + file=<file> Load and execute <file>\n\ + seg=<s[:o[:i]]> Load file at <s:o>, jump to <s:i>\n\ + - defaults to 0:0x7C00:0x7C00\n\ + - ommited o/i values default to 0\n\ + isolinux=<loader> Load another version of ISOLINUX\n\ + ntldr=<loader> Load Windows NTLDR, SETUPLDR.BIN or BOOTMGR\n\ + reactos=<loader> Load ReactOS's loader\n\ + cmldr=<loader> Load Recovery Console of Windows NT/2K/XP/2003\n\ + freedos=<loader> Load FreeDOS KERNEL.SYS\n\ + msdos=<loader> Load MS-DOS 2.xx - 6.xx IO.SYS\n\ + msdos7=<loader> Load MS-DOS 7+ IO.SYS\n\ + pcdos=<loader> Load PC-DOS IBMBIO.COM\n\ + drmk=<loader> Load DRMK DELLBIO.BIN\n\ + grub=<loader> Load GRUB Legacy stage2\n\ + grubcfg=<filename> Set alternative config filename for GRUB Legacy\n\ + grldr=<loader> Load GRUB4DOS grldr\n\ + bss=<filename> Emulate syslinux's BSS\n\ + bs=<filename> Emulate syslinux's BS\n\ +\nPlease see doc/chain.txt for the detailed documentation.\n\ +" + }; + for (i = 0; i < sizeof(usage)/sizeof(usage[0]); i++) { + if (i) { + error(key); + wait_key(); + } + error(usage[i]); + } +} + +void opt_set_defs(void) +{ + memset(&opt, 0, sizeof(opt)); + opt.sect = true; /* by def. load sector */ + opt.maps = true; /* by def. map sector */ + opt.hand = true; /* by def. prepare handover */ + opt.brkchain = false; /* by def. do chainload */ + opt.foff = opt.soff = opt.fip = opt.sip = 0x7C00; + opt.drivename = "boot"; +#ifdef DEBUG + opt.warn = true; +#endif +} + +int opt_parse_args(int argc, char *argv[]) +{ + int i; + unsigned int v; + char *p; + + for (i = 1; i < argc; i++) { + if (!strncmp(argv[i], "file=", 5)) { + opt.file = argv[i] + 5; + } else if (!strcmp(argv[i], "nofile")) { + opt.file = NULL; + } else if (!strncmp(argv[i], "seg=", 4)) { + if (soi_s2n(argv[i] + 4, &opt.fseg, &opt.foff, &opt.fip, 0)) + goto bail; + } else if (!strncmp(argv[i], "bss=", 4)) { + opt.file = argv[i] + 4; + opt.bss = true; + opt.maps = false; + opt.setbpb = true; + /* opt.save = true; */ + } else if (!strncmp(argv[i], "bs=", 3)) { + opt.file = argv[i] + 3; + opt.sect = false; + opt.filebpb = true; + } else if (!strncmp(argv[i], "isolinux=", 9)) { + opt.file = argv[i] + 9; + opt.isolinux = true; + opt.hand = false; + opt.sect = false; + } else if (!strncmp(argv[i], "ntldr=", 6)) { + opt.fseg = 0x2000; /* NTLDR wants this address */ + opt.foff = 0; + opt.fip = 0; + opt.file = argv[i] + 6; + opt.setbpb = true; + /* opt.save = true; */ + opt.hand = false; + } else if (!strncmp(argv[i], "reactos=", 8)) { + /* + * settings based on commit + * ad4cf1470977f648ee1dd45e97939589ccb0393c + * note, conflicts with: + * http://reactos.freedoors.org/Reactos%200.3.13/ReactOS-0.3.13-REL-src/boot/freeldr/notes.txt + */ + opt.fseg = 0; + opt.foff = 0x8000; + opt.fip = 0x8100; + opt.file = argv[i] + 8; + opt.setbpb = true; + /* opt.save = true; */ + opt.hand = false; + } else if (!strncmp(argv[i], "cmldr=", 6)) { + opt.fseg = 0x2000; /* CMLDR wants this address */ + opt.foff = 0; + opt.fip = 0; + opt.file = argv[i] + 6; + opt.cmldr = true; + opt.setbpb = true; + /* opt.save = true; */ + opt.hand = false; + } else if (!strncmp(argv[i], "freedos=", 8)) { + opt.fseg = 0x60; /* FREEDOS wants this address */ + opt.foff = 0; + opt.fip = 0; + opt.sseg = 0x1FE0; + opt.file = argv[i] + 8; + opt.setbpb = true; + /* opt.save = true; */ + opt.hand = false; + } else if ( (v = 6, !strncmp(argv[i], "msdos=", v) || + !strncmp(argv[i], "pcdos=", v)) || + (v = 7, !strncmp(argv[i], "msdos7=", v)) ) { + opt.fseg = 0x70; /* MS-DOS 2.00 .. 6.xx wants this address */ + opt.foff = 0; + opt.fip = v == 7 ? 0x200 : 0; /* MS-DOS 7.0+ wants this ip */ + opt.sseg = 0x8000; + opt.file = argv[i] + v; + opt.setbpb = true; + /* opt.save = true; */ + opt.hand = false; + } else if (!strncmp(argv[i], "drmk=", 5)) { + opt.fseg = 0x70; /* DRMK wants this address */ + opt.foff = 0; + opt.fip = 0; + opt.sseg = 0x2000; + opt.soff = 0; + opt.sip = 0; + opt.file = argv[i] + 5; + /* opt.drmk = true; */ + opt.setbpb = true; + /* opt.save = true; */ + opt.hand = false; + } else if (!strncmp(argv[i], "grub=", 5)) { + opt.fseg = 0x800; /* stage2 wants this address */ + opt.foff = 0; + opt.fip = 0x200; + opt.file = argv[i] + 5; + opt.grub = true; + opt.hand = false; + opt.sect = false; + } else if (!strncmp(argv[i], "grubcfg=", 8)) { + opt.grubcfg = argv[i] + 8; + } else if (!strncmp(argv[i], "grldr=", 6)) { + opt.file = argv[i] + 6; + opt.grldr = true; + opt.hand = false; + opt.sect = false; + } else if (!strcmp(argv[i], "keeppxe")) { + opt.keeppxe = 3; + } else if (!strcmp(argv[i], "nokeeppxe")) { + opt.keeppxe = 0; + } else if (!strcmp(argv[i], "maps")) { + opt.maps = true; + } else if (!strcmp(argv[i], "nomaps")) { + opt.maps = false; + } else if (!strcmp(argv[i], "hand")) { + opt.hand = true; + } else if (!strcmp(argv[i], "nohand")) { + opt.hand = false; + } else if (!strcmp(argv[i], "hptr")) { + opt.hptr = true; + } else if (!strcmp(argv[i], "nohptr")) { + opt.hptr = false; + } else if (!strcmp(argv[i], "swap")) { + opt.swap = true; + } else if (!strcmp(argv[i], "noswap")) { + opt.swap = false; + } else if (!strcmp(argv[i], "nohide")) { + opt.hide = 0; + } else if (!strcmp(argv[i], "hide")) { + opt.hide = 1; /* 001b */ + } else if (!strcmp(argv[i], "hideall")) { + opt.hide = 2; /* 010b */ + } else if (!strcmp(argv[i], "unhide")) { + opt.hide = 5; /* 101b */ + } else if (!strcmp(argv[i], "unhideall")) { + opt.hide = 6; /* 110b */ + } else if (!strcmp(argv[i], "setbpb")) { + opt.setbpb = true; + } else if (!strcmp(argv[i], "nosetbpb")) { + opt.setbpb = false; + } else if (!strcmp(argv[i], "filebpb")) { + opt.filebpb = true; + } else if (!strcmp(argv[i], "nofilebpb")) { + opt.filebpb = false; + } else if (!strncmp(argv[i], "sect=", 5) || + !strcmp(argv[i], "sect")) { + if (argv[i][4]) { + if (soi_s2n(argv[i] + 5, &opt.sseg, &opt.soff, &opt.sip, 0)) + goto bail; + } + opt.sect = true; + } else if (!strcmp(argv[i], "nosect")) { + opt.sect = false; + opt.maps = false; + } else if (!strcmp(argv[i], "save")) { + opt.save = true; + } else if (!strcmp(argv[i], "nosave")) { + opt.save = false; + } else if (!strcmp(argv[i], "fixchs")) { + opt.fixchs = true; + } else if (!strcmp(argv[i], "nofixchs")) { + opt.fixchs = false; + } else if (!strcmp(argv[i], "warn")) { + opt.warn = true; + } else if (!strcmp(argv[i], "nowarn")) { + opt.warn = false; + } else if (!strcmp(argv[i], "nobreak")) { + opt.brkchain = false; + } else if (!strcmp(argv[i], "break")) { + opt.brkchain = true; + opt.file = NULL; + opt.maps = false; + opt.hand = false; + } else if (((argv[i][0] == 'h' || argv[i][0] == 'f') + && argv[i][1] == 'd') + || !strncmp(argv[i], "mbr:", 4) + || !strncmp(argv[i], "mbr=", 4) + || !strncmp(argv[i], "guid:", 5) + || !strncmp(argv[i], "guid=", 5) + || !strncmp(argv[i], "label:", 6) + || !strncmp(argv[i], "label=", 6) + || !strcmp(argv[i], "boot") + || !strncmp(argv[i], "boot,", 5) + || !strcmp(argv[i], "fs")) { + opt.drivename = argv[i]; + if (strncmp(argv[i], "label", 5)) + p = strchr(opt.drivename, ','); + else + p = NULL; + if (p) { + *p = '\0'; + opt.partition = p + 1; + } else if (argv[i + 1] && argv[i + 1][0] >= '0' + && argv[i + 1][0] <= '9') { + opt.partition = argv[++i]; + } + } else { + usage(); + goto bail; + } + } + + if (opt.grubcfg && !opt.grub) { + error("grubcfg=<filename> must be used together with grub=<loader>.\n"); + goto bail; + } + +#if 0 + if ((!opt.maps || !opt.sect) && !opt.file) { + error("You have to load something.\n"); + goto bail; + } +#endif + + if (opt.filebpb && !opt.file) { + error("Option 'filebpb' requires a file.\n"); + goto bail; + } + + if (opt.save && !opt.sect) { + error("Option 'save' requires a sector.\n"); + goto bail; + } + + if (opt.setbpb && !opt.sect) { + error("Option 'setbpb' requires a sector.\n"); + goto bail; + } + + if (opt.maps && !opt.sect) { + error("Option 'maps' requires a sector.\n"); + goto bail; + } + + return 0; +bail: + return -1; +} + +/* vim: set ts=8 sts=4 sw=4 noet: */ diff --git a/com32/chain/options.h b/com32/chain/options.h new file mode 100644 index 00000000..4493ef1f --- /dev/null +++ b/com32/chain/options.h @@ -0,0 +1,47 @@ +#ifndef _COM32_CHAIN_OPTIONS_H +#define _COM32_CHAIN_OPTIONS_H + +#include <stdint.h> +#include <syslinux/bootrm.h> + +struct options { + unsigned int fseg; + unsigned int foff; + unsigned int fip; + unsigned int sseg; + unsigned int soff; + unsigned int sip; + const char *drivename; + const char *partition; + const char *file; + const char *grubcfg; + bool isolinux; + bool cmldr; + bool drmk; + bool grub; + bool grldr; + bool maps; + bool hand; + bool hptr; + bool swap; + int hide; + bool sect; + bool save; + bool bss; + bool setbpb; + bool filebpb; + bool fixchs; + bool warn; + bool brkchain; + uint16_t keeppxe; + struct syslinux_rm_regs regs; +}; + +extern struct options opt; + +void opt_set_defs(void); +int opt_parse_args(int argc, char *argv[]); + +#endif + +/* vim: set ts=8 sts=4 sw=4 noet: */ diff --git a/com32/chain/partiter.c b/com32/chain/partiter.c new file mode 100644 index 00000000..1acd1958 --- /dev/null +++ b/com32/chain/partiter.c @@ -0,0 +1,805 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2003-2010 H. Peter Anvin - All Rights Reserved + * Copyright 2010 Shao Miller + * Copyright 2010 Michal Soltys + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * partiter.c + * + * Provides disk / partition iteration. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <zlib.h> +#include <syslinux/disk.h> +#include "common.h" +#include "partiter.h" +#include "utility.h" + +#define ost_is_ext(type) ((type) == 0x05 || (type) == 0x0F || (type) == 0x85) +#define ost_is_nondata(type) (ost_is_ext(type) || (type) == 0x00) +#define sane(s,l) ((s)+(l) > (s)) + +/* forwards */ + +static int iter_ctor(struct part_iter *, va_list *); +static int iter_dos_ctor(struct part_iter *, va_list *); +static int iter_gpt_ctor(struct part_iter *, va_list *); +static void iter_dtor(struct part_iter *); +static struct part_iter *pi_dos_next(struct part_iter *); +static struct part_iter *pi_gpt_next(struct part_iter *); +static struct part_iter *pi_raw_next(struct part_iter *); + +static struct itertype types[] = { + [0] = { + .ctor = &iter_dos_ctor, + .dtor = &iter_dtor, + .next = &pi_dos_next, +}, [1] = { + .ctor = &iter_gpt_ctor, + .dtor = &iter_dtor, + .next = &pi_gpt_next, +}, [2] = { + .ctor = &iter_ctor, + .dtor = &iter_dtor, + .next = &pi_raw_next, +}}; + +const struct itertype * const typedos = types; +const struct itertype * const typegpt = types+1; +const struct itertype * const typeraw = types+2; + +#ifdef DEBUG +static int inv_type(const void *type) +{ + int i, cnt = sizeof(types)/sizeof(types[0]); + for (i = 0; i < cnt; i++) { + if (type == types + i) + return 0; + } + return -1; +} +#endif + +/** + * iter_ctor() - common iterator initialization + * @iter: iterator pointer + * @args(0): disk_info structure used for disk functions + * @args(1): stepall modifier + * + * Second and further arguments are passed as a pointer to va_list + **/ +static int iter_ctor(struct part_iter *iter, va_list *args) +{ + const struct disk_info *di = va_arg(*args, const struct disk_info *); + int stepall = va_arg(*args, int); + +#ifdef DEBUG + if (!di) + return -1; +#endif + + memcpy(&iter->di, di, sizeof(struct disk_info)); + iter->stepall = stepall; + iter->index0 = -1; + iter->length = di->lbacnt; + + return 0; +} + +/** + * iter_dtor() - common iterator cleanup + * @iter: iterator pointer + * + **/ +static void iter_dtor(struct part_iter *iter) +{ + free(iter->data); +} + +/** + * iter_dos_ctor() - MBR/EBR iterator specific initialization + * @iter: iterator pointer + * @args(0): disk_info structure used for disk functions + * @args(1): pointer to buffer with loaded valid MBR + * + * Second and further arguments are passed as a pointer to va_list. + * This function only makes rudimentary checks. If user uses + * pi_new(), he/she is responsible for doing proper sanity checks. + **/ +static int iter_dos_ctor(struct part_iter *iter, va_list *args) +{ + const struct disk_dos_mbr *mbr; + + /* uses args(0) */ + if (iter_ctor(iter, args)) + return -1; + + mbr = va_arg(*args, const struct disk_dos_mbr *); + +#ifdef DEBUG + if (!mbr) + goto bail; +#endif + + if (!(iter->data = malloc(sizeof(struct disk_dos_mbr)))) + goto bail; + + memcpy(iter->data, mbr, sizeof(struct disk_dos_mbr)); + + iter->sub.dos.bebr_index0 = -1; + iter->sub.dos.disk_sig = mbr->disk_sig; + + return 0; +bail: + iter->type->dtor(iter); + return -1; +} + +/** + * iter_gpt_ctor() - GPT iterator specific initialization + * @iter: iterator pointer + * @args(0): ptr to disk_info structure + * @args(1): ptr to buffer with GPT header + * @args(2): ptr to buffer with GPT partition list + * + * Second and further arguments are passed as a pointer to va_list. + * This function only makes rudimentary checks. If user uses + * pi_new(), he/she is responsible for doing proper sanity checks. + **/ +static int iter_gpt_ctor(struct part_iter *iter, va_list *args) +{ + uint64_t siz; + const struct disk_gpt_header *gpth; + const struct disk_gpt_part_entry *gptl; + + /* uses args(0) */ + if (iter_ctor(iter, args)) + return -1; + + gpth = va_arg(*args, const struct disk_gpt_header *); + gptl = va_arg(*args, const struct disk_gpt_part_entry *); + +#ifdef DEBUG + if (!gpth || !gptl) + goto bail; +#endif + + siz = (uint64_t)gpth->part_count * gpth->part_size; + +#ifdef DEBUG + if (!siz || (siz + iter->di.bps - 1) / iter->di.bps > 255u || + gpth->part_size < sizeof(struct disk_gpt_part_entry)) { + goto bail; + } +#endif + + if (!(iter->data = malloc((size_t)siz))) + goto bail; + + memcpy(iter->data, gptl, (size_t)siz); + + iter->sub.gpt.pe_count = (int)gpth->part_count; + iter->sub.gpt.pe_size = (int)gpth->part_size; + iter->sub.gpt.ufirst = gpth->lba_first_usable; + iter->sub.gpt.ulast = gpth->lba_last_usable; + + memcpy(&iter->sub.gpt.disk_guid, &gpth->disk_guid, sizeof(struct guid)); + + return 0; +bail: + iter->type->dtor(iter); + return -1; +} + +/* Logical partition must be sane, meaning: + * - must be data or empty + * - must have non-0 start and length + * - values must not wrap around 32bit + * - must be inside current EBR frame + */ + +static int notsane_logical(const struct part_iter *iter) +{ + const struct disk_dos_part_entry *dp; + uint32_t end_log; + + dp = ((struct disk_dos_mbr *)iter->data)->table; + + if (!dp[0].ostype) + return 0; + + if (ost_is_ext(dp[0].ostype)) { + error("1st EBR entry must be data or empty.\n"); + return -1; + } + + end_log = dp[0].start_lba + dp[0].length; + + if (!dp[0].start_lba || + !dp[0].length || + !sane(dp[0].start_lba, dp[0].length) || + end_log > iter->sub.dos.ebr_size) { + + error("Insane logical partition.\n"); + return -1; + } + + return 0; +} + +/* Extended partition must be sane, meaning: + * - must be extended or empty + * - must have non-0 start and length + * - values must not wrap around 32bit + * - must be inside base EBR frame + */ + +static int notsane_extended(const struct part_iter *iter) +{ + const struct disk_dos_part_entry *dp; + uint32_t end_ebr; + + dp = ((struct disk_dos_mbr *)iter->data)->table; + + if (!dp[1].ostype) + return 0; + + if (!ost_is_nondata(dp[1].ostype)) { + error("2nd EBR entry must be extended or empty.\n"); + return -1; + } + + end_ebr = dp[1].start_lba + dp[1].length; + + if (!dp[1].start_lba || + !dp[1].length || + !sane(dp[1].start_lba, dp[1].length) || + end_ebr > iter->sub.dos.bebr_size) { + + error("Insane extended partition.\n"); + return -1; + } + + return 0; +} + +/* Primary partition must be sane, meaning: + * - must have non-0 start and length + * - values must not wrap around 32bit + */ + +static int notsane_primary(const struct part_iter *iter) +{ + const struct disk_dos_part_entry *dp; + dp = ((struct disk_dos_mbr *)iter->data)->table + iter->index0; + + if (!dp->ostype) + return 0; + + if (!dp->start_lba || + !dp->length || + !sane(dp->start_lba, dp->length) || + dp->start_lba + dp->length > iter->di.lbacnt) { + error("Insane primary (MBR) partition.\n"); + return -1; + } + + return 0; +} + +static int notsane_gpt(const struct part_iter *iter) +{ + const struct disk_gpt_part_entry *gp; + gp = (const struct disk_gpt_part_entry *) + (iter->data + iter->index0 * iter->sub.gpt.pe_size); + + if (guid_is0(&gp->type)) + return 0; + + if (gp->lba_first < iter->sub.gpt.ufirst || + gp->lba_last > iter->sub.gpt.ulast) { + error("Insane GPT partition.\n"); + return -1; + } + + return 0; +} + +static int pi_dos_next_mbr(struct part_iter *iter, uint32_t *lba, + struct disk_dos_part_entry **_dp) +{ + struct disk_dos_part_entry *dp; + + while (++iter->index0 < 4) { + dp = ((struct disk_dos_mbr *)iter->data)->table + iter->index0; + + if (notsane_primary(iter)) { + iter->status = PI_INSANE; + goto bail; + } + + if (ost_is_ext(dp->ostype)) { + if (iter->sub.dos.bebr_index0 >= 0) { + error("You have more than 1 extended partition.\n"); + iter->status = PI_INSANE; + goto bail; + } + /* record base EBR index */ + iter->sub.dos.bebr_index0 = iter->index0; + } + if (!ost_is_nondata(dp->ostype) || iter->stepall) { + *lba = dp->start_lba; + *_dp = dp; + break; + } + } + + return 0; +bail: + return -1; +} + +static int prep_base_ebr(struct part_iter *iter) +{ + struct disk_dos_part_entry *dp; + + if (iter->sub.dos.bebr_index0 < 0) /* if we don't have base extended partition at all */ + return -1; + else if (!iter->sub.dos.bebr_start) { /* if not initialized yet */ + dp = ((struct disk_dos_mbr *)iter->data)->table + iter->sub.dos.bebr_index0; + + iter->sub.dos.bebr_start = dp->start_lba; + iter->sub.dos.bebr_size = dp->length; + + iter->sub.dos.ebr_start = 0; + iter->sub.dos.ebr_size = iter->sub.dos.bebr_size; + + iter->sub.dos.cebr_lba = 0; + iter->sub.dos.nebr_lba = iter->sub.dos.bebr_start; + + iter->index0--; + } + return 0; +} + +static int pi_dos_next_ebr(struct part_iter *iter, uint32_t *lba, + struct disk_dos_part_entry **_dp) +{ + struct disk_dos_part_entry *dp; + + if (prep_base_ebr(iter)) { + iter->status = PI_DONE; + return -1; + } + + while (++iter->index0 < 1024 && iter->sub.dos.nebr_lba) { + free(iter->data); + if (!(iter->data = + disk_read_sectors(&iter->di, iter->sub.dos.nebr_lba, 1))) { + error("Couldn't load EBR.\n"); + iter->status = PI_ERRLOAD; + return -1; + } + + if (notsane_logical(iter) || notsane_extended(iter)) { + iter->status = PI_INSANE; + return -1; + } + + dp = ((struct disk_dos_mbr *)iter->data)->table; + + iter->sub.dos.cebr_lba = iter->sub.dos.nebr_lba; + + /* setup next frame values */ + if (dp[1].ostype) { + iter->sub.dos.ebr_start = dp[1].start_lba; + iter->sub.dos.ebr_size = dp[1].length; + iter->sub.dos.nebr_lba = iter->sub.dos.bebr_start + dp[1].start_lba; + } else { + iter->sub.dos.ebr_start = 0; + iter->sub.dos.ebr_size = 0; + iter->sub.dos.nebr_lba = 0; + } + + if (!dp[0].ostype) + iter->sub.dos.skipcnt++; + + if (dp[0].ostype || iter->stepall) { + *lba = iter->sub.dos.cebr_lba + dp[0].start_lba; + *_dp = dp; + return 0; + } + /* + * This way it's possible to continue, if some crazy soft left a "hole" + * - EBR with a valid extended partition without a logical one. In + * such case, linux will not reserve a number for such hole - so we + * don't increase index0. If stepall flag is set, we will never reach + * this place. + */ + } + iter->status = PI_DONE; + return -1; +} + +static struct part_iter *pi_dos_next(struct part_iter *iter) +{ + uint32_t start_lba = 0; + struct disk_dos_part_entry *dos_part = NULL; + + if (iter->status) + goto bail; + + /* look for primary partitions */ + if (iter->index0 < 4 && + pi_dos_next_mbr(iter, &start_lba, &dos_part)) + goto bail; + + /* look for logical partitions */ + if (iter->index0 >= 4 && + pi_dos_next_ebr(iter, &start_lba, &dos_part)) + goto bail; + + /* + * note special index handling, if we have stepall set - + * this is made to keep index consistent with non-stepall + * iterators + */ + + if (iter->index0 >= 4 && !dos_part->ostype) + iter->index = -1; + else + iter->index = iter->index0 - iter->sub.dos.skipcnt + 1; + iter->rawindex = iter->index0 + 1; + iter->start_lba = start_lba; + iter->length = dos_part->length; + iter->record = (char *)dos_part; + +#ifdef DEBUG + disk_dos_part_dump(dos_part); +#endif + + return iter; +bail: + return NULL; +} + +static void gpt_conv_label(struct part_iter *iter) +{ + const struct disk_gpt_part_entry *gp; + const int16_t *orig_lab; + + gp = (const struct disk_gpt_part_entry *) + (iter->data + iter->index0 * iter->sub.gpt.pe_size); + orig_lab = (const int16_t *)gp->name; + + /* caveat: this is very crude conversion */ + for (int i = 0; i < PI_GPTLABSIZE/2; i++) { + iter->sub.gpt.part_label[i] = (char)orig_lab[i]; + } + iter->sub.gpt.part_label[PI_GPTLABSIZE/2] = 0; +} + +static struct part_iter *pi_gpt_next(struct part_iter *iter) +{ + const struct disk_gpt_part_entry *gpt_part = NULL; + + if (iter->status) + goto bail; + + while (++iter->index0 < iter->sub.gpt.pe_count) { + gpt_part = (const struct disk_gpt_part_entry *) + (iter->data + iter->index0 * iter->sub.gpt.pe_size); + + if (notsane_gpt(iter)) { + iter->status = PI_INSANE; + goto bail; + } + + if (!guid_is0(&gpt_part->type) || iter->stepall) + break; + } + /* no more partitions ? */ + if (iter->index0 == iter->sub.gpt.pe_count) { + iter->status = PI_DONE; + goto bail; + } + /* gpt_part is guaranteed to be valid here */ + iter->index = iter->index0 + 1; + iter->rawindex = iter->index0 + 1; + iter->start_lba = gpt_part->lba_first; + iter->length = gpt_part->lba_last - gpt_part->lba_first + 1; + iter->record = (char *)gpt_part; + memcpy(&iter->sub.gpt.part_guid, &gpt_part->uid, sizeof(struct guid)); + gpt_conv_label(iter); + +#ifdef DEBUG + disk_gpt_part_dump(gpt_part); +#endif + + return iter; +bail: + return NULL; +} + +static struct part_iter *pi_raw_next(struct part_iter *iter) +{ + iter->status = PI_DONE; + return NULL; +} + +static int check_crc(uint32_t crc_match, const uint8_t *buf, unsigned int siz) +{ + uint32_t crc; + + crc = crc32(0, NULL, 0); + crc = crc32(crc, buf, siz); + + return crc_match != crc; +} + +static int gpt_check_hdr_crc(const struct disk_info * const diskinfo, struct disk_gpt_header **_gh) +{ + struct disk_gpt_header *gh = *_gh; + uint64_t lba_alt; + uint32_t hold_crc32; + + hold_crc32 = gh->chksum; + gh->chksum = 0; + if (check_crc(hold_crc32, (const uint8_t *)gh, gh->hdr_size)) { + error("WARNING: Primary GPT header checksum invalid.\n"); + /* retry with backup */ + lba_alt = gh->lba_alt; + free(gh); + if (!(gh = *_gh = disk_read_sectors(diskinfo, lba_alt, 1))) { + error("Couldn't read backup GPT header.\n"); + return -1; + } + hold_crc32 = gh->chksum; + gh->chksum = 0; + if (check_crc(hold_crc32, (const uint8_t *)gh, gh->hdr_size)) { + error("Secondary GPT header checksum invalid.\n"); + return -1; + } + } + /* restore old checksum */ + gh->chksum = hold_crc32; + + return 0; +} + +/* + * ---------------------------------------------------------------------------- + * Following functions are for users to call. + * ---------------------------------------------------------------------------- + */ + + +int pi_next(struct part_iter **_iter) +{ + struct part_iter *iter; + + if(!_iter || !*_iter) + return 0; + iter = *_iter; +#ifdef DEBUG + if (inv_type(iter->type)) { + error("This is not a valid iterator.\n"); + return 0; + } +#endif + if ((iter = iter->type->next(iter))) { + *_iter = iter; + } + return (*_iter)->status; +} + +/** + * pi_new() - get new iterator + * @itertype: iterator type + * @...: variable arguments passed to ctors + * + * Variable arguments depend on the type. Please see functions: + * iter_gpt_ctor() and iter_dos_ctor() for details. + **/ +struct part_iter *pi_new(const struct itertype *type, ...) +{ + int badctor = 0; + struct part_iter *iter = NULL; + va_list ap; + + va_start(ap, type); + +#ifdef DEBUG + if (inv_type(type)) { + error("Unknown iterator requested.\n"); + goto bail; + } +#endif + + if (!(iter = malloc(sizeof(struct part_iter)))) { + error("Couldn't allocate memory for the iterator.\n"); + goto bail; + } + + memset(iter, 0, sizeof(struct part_iter)); + iter->type = type; + + if (type->ctor(iter, &ap)) { + badctor = -1; + error("Cannot initialize the iterator.\n"); + goto bail; + } + +bail: + va_end(ap); + if (badctor) { + free(iter); + iter = NULL; + } + return iter; +} + +/** + * pi_del() - delete iterator + * @iter: iterator double pointer + * + **/ + +void pi_del(struct part_iter **_iter) +{ + struct part_iter *iter; + + if(!_iter || !*_iter) + return; + iter = *_iter; + +#ifdef DEBUG + if (inv_type(iter->type)) { + error("This is not a valid iterator.\n"); + return; + } +#endif + + iter->type->dtor(iter); + free(iter); + *_iter = NULL; +} + +/** + * pi_begin() - check disk, validate, and get proper iterator + * @di: diskinfo struct pointer + * + * This function checks the disk for GPT or legacy partition table and allocates + * an appropriate iterator. + **/ +struct part_iter *pi_begin(const struct disk_info *di, int stepall) +{ + int setraw = 0; + struct part_iter *iter = NULL; + struct disk_dos_mbr *mbr = NULL; + struct disk_gpt_header *gpth = NULL; + struct disk_gpt_part_entry *gptl = NULL; + + /* Read MBR */ + if (!(mbr = disk_read_sectors(di, 0, 1))) { + error("Couldn't read first disk sector.\n"); + goto bail; + } + + setraw = -1; + + /* Check for MBR magic*/ + if (mbr->sig != disk_mbr_sig_magic) { + error("No MBR magic.\n"); + goto bail; + } + + /* Check for GPT protective MBR */ + if (mbr->table[0].ostype == 0xEE) { + if (!(gpth = disk_read_sectors(di, 1, 1))) { + error("Couldn't read potential GPT header.\n"); + goto bail; + } + } + + if (gpth && gpth->rev.uint32 == 0x00010000 && + !memcmp(gpth->sig, disk_gpt_sig_magic, sizeof(disk_gpt_sig_magic))) { + /* looks like GPT v1.0 */ + uint64_t gpt_loff; /* offset to GPT partition list in sectors */ + uint64_t gpt_lsiz; /* size of GPT partition list in bytes */ + uint64_t gpt_lcnt; /* size of GPT partition in sectors */ +#ifdef DEBUG + puts("Looks like a GPT v1.0 disk."); + disk_gpt_header_dump(gpth); +#endif + /* Verify checksum, fallback to backup, then bail if invalid */ + if (gpt_check_hdr_crc(di, &gpth)) + goto bail; + + gpt_loff = gpth->lba_table; + gpt_lsiz = (uint64_t)gpth->part_size * gpth->part_count; + gpt_lcnt = (gpt_lsiz + di->bps - 1) / di->bps; + + /* + * disk_read_sectors allows reading of max 255 sectors, so we use + * it as a sanity check base. EFI doesn't specify max (AFAIK). + * Apart from that, some extensive sanity checks. + */ + if (!gpt_loff || !gpt_lsiz || gpt_lcnt > 255u || + gpth->lba_first_usable > gpth->lba_last_usable || + !sane(gpt_loff, gpt_lcnt) || + gpt_loff + gpt_lcnt > gpth->lba_first_usable || + !sane(gpth->lba_last_usable, gpt_lcnt) || + gpth->lba_last_usable + gpt_lcnt >= gpth->lba_alt || + gpth->lba_alt >= di->lbacnt || + gpth->part_size < sizeof(struct disk_gpt_part_entry)) { + error("Invalid GPT header's values.\n"); + goto bail; + } + if (!(gptl = disk_read_sectors(di, gpt_loff, (uint8_t)gpt_lcnt))) { + error("Couldn't read GPT partition list.\n"); + goto bail; + } + /* Check array checksum(s). */ + if (check_crc(gpth->table_chksum, (const uint8_t *)gptl, (unsigned int)gpt_lsiz)) { + error("WARNING: GPT partition list checksum invalid, trying backup.\n"); + free(gptl); + /* secondary array directly precedes secondary header */ + if (!(gptl = disk_read_sectors(di, gpth->lba_alt - gpt_lcnt, (uint8_t)gpt_lcnt))) { + error("Couldn't read backup GPT partition list.\n"); + goto bail; + } + if (check_crc(gpth->table_chksum, (const uint8_t *)gptl, (unsigned int)gpt_lsiz)) { + error("Backup GPT partition list checksum invalid.\n"); + goto bail; + } + } + /* allocate iterator and exit */ + iter = pi_new(typegpt, di, stepall, gpth, gptl); + } else { + /* looks like MBR */ + iter = pi_new(typedos, di, stepall, mbr); + } + + setraw = 0; +bail: + if (setraw) { + error("WARNING: treating disk as raw.\n"); + iter = pi_new(typeraw, di, stepall); + } + free(mbr); + free(gpth); + free(gptl); + + return iter; +} + +/* vim: set ts=8 sts=4 sw=4 noet: */ diff --git a/com32/chain/partiter.h b/com32/chain/partiter.h new file mode 100644 index 00000000..7deeb534 --- /dev/null +++ b/com32/chain/partiter.h @@ -0,0 +1,107 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2003-2010 H. Peter Anvin - All Rights Reserved + * Copyright 2010 Michal Soltys + * Copyright 2010 Shao Miller + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * partiter.h + * + * Provides disk / partition iteration. + */ + +#ifndef _COM32_CHAIN_PARTITER_H +#define _COM32_CHAIN_PARTITER_H + +#include <stdint.h> +#include <syslinux/disk.h> + +#define PI_ERRLOAD 3 +#define PI_INSANE 2 +#define PI_DONE 1 +#define PI_OK 0 + +struct itertype; +struct part_iter; + +struct itertype { + int (*ctor)(struct part_iter *, va_list *); + void (*dtor)(struct part_iter *); + struct part_iter *(*next) (struct part_iter *); +}; + +#define PI_GPTLABSIZE ((int)sizeof(((struct disk_gpt_part_entry *)0)->name)) + +struct part_iter { + const struct itertype *type; + char *data; + char *record; + uint64_t start_lba; + uint64_t length; + int index; + int rawindex; + struct disk_info di; + int stepall; + int status; + /* internal */ + int index0; + union _sub { + struct _dos { + uint32_t disk_sig; + uint32_t nebr_lba; + uint32_t cebr_lba; + /* internal */ + uint32_t ebr_start; + uint32_t ebr_size; + uint32_t bebr_start; + uint32_t bebr_size; + int bebr_index0; + int skipcnt; + } dos; + struct _gpt { + struct guid disk_guid; + struct guid part_guid; + char part_label[PI_GPTLABSIZE/2+1]; + int pe_count; + int pe_size; + uint64_t ufirst; + uint64_t ulast; + } gpt; + } sub; +}; + +extern const struct itertype * const typedos; +extern const struct itertype * const typegpt; +extern const struct itertype * const typeraw; + +struct part_iter *pi_begin(const struct disk_info *, int stepall); +struct part_iter *pi_new(const struct itertype *, ...); +void pi_del(struct part_iter **); +int pi_next(struct part_iter **); + +#endif + +/* vim: set ts=8 sts=4 sw=4 noet: */ diff --git a/com32/chain/utility.c b/com32/chain/utility.c new file mode 100644 index 00000000..fb59551b --- /dev/null +++ b/com32/chain/utility.c @@ -0,0 +1,214 @@ +#include <com32.h> +#include <stdint.h> +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <string.h> +#include <syslinux/disk.h> +#include "utility.h" + +static const char *bpbtypes[] = { + [0] = "unknown", + [1] = "2.0", + [2] = "3.0", + [3] = "3.2", + [4] = "3.4", + [5] = "4.0", + [6] = "8.0 (NT+)", + [7] = "7.0", +}; + +void error(const char *msg) +{ + fputs(msg, stderr); +} + +int guid_is0(const struct guid *guid) +{ + return !*(const uint64_t *)guid && !*((const uint64_t *)guid + 1); +} + +void wait_key(void) +{ + int cnt; + char junk; + + /* drain */ + do { + errno = 0; + cnt = read(0, &junk, 1); + } while (cnt > 0 || (cnt < 0 && errno == EAGAIN)); + + /* wait */ + do { + errno = 0; + cnt = read(0, &junk, 1); + } while (!cnt || (cnt < 0 && errno == EAGAIN)); +} + +void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, uint32_t mode) +{ + uint32_t c, h, s, t; + uint32_t cs, hs, ss; + + /* + * Not much reason here, but if we have no valid CHS geometry, we assume + * "typical" ones to have something to return. + */ + if (di->cbios) { + cs = di->cyl; + hs = di->head; + ss = di->spt; + if (mode == l2c_cadd && cs < 1024 && di->lbacnt > cs*hs*ss) + cs++; + else if (mode == l2c_cmax) + cs = 1024; + } else { + if (di->disk & 0x80) { + cs = 1024; + hs = 255; + ss = 63; + } else { + cs = 80; + hs = 2; + ss = 18; + } + } + + if (lba >= cs*hs*ss) { + s = ss; + h = hs - 1; + c = cs - 1; + } else { + s = ((uint32_t)lba % ss) + 1; + t = (uint32_t)lba / ss; + h = t % hs; + c = t / hs; + } + + (*dst)[0] = h; + (*dst)[1] = s | ((c & 0x300) >> 2); + (*dst)[2] = c; +} + +uint32_t get_file_lba(const char *filename) +{ + com32sys_t inregs; + uint32_t lba; + + /* Start with clean registers */ + memset(&inregs, 0, sizeof(com32sys_t)); + + /* Put the filename in the bounce buffer */ + strlcpy(__com32.cs_bounce, filename, __com32.cs_bounce_size); + + /* Call comapi_open() which returns a structure pointer in SI + * to a structure whose first member happens to be the LBA. + */ + inregs.eax.w[0] = 0x0006; + inregs.esi.w[0] = OFFS(__com32.cs_bounce); + inregs.es = SEG(__com32.cs_bounce); + __com32.cs_intcall(0x22, &inregs, &inregs); + + if ((inregs.eflags.l & EFLAGS_CF) || inregs.esi.w[0] == 0) { + return 0; /* Filename not found */ + } + + /* Since the first member is the LBA, we simply cast */ + lba = *((uint32_t *) MK_PTR(inregs.ds, inregs.esi.w[0])); + + /* Clean the registers for the next call */ + memset(&inregs, 0, sizeof(com32sys_t)); + + /* Put the filename in the bounce buffer */ + strlcpy(__com32.cs_bounce, filename, __com32.cs_bounce_size); + + /* Call comapi_close() to free the structure */ + inregs.eax.w[0] = 0x0008; + inregs.esi.w[0] = OFFS(__com32.cs_bounce); + inregs.es = SEG(__com32.cs_bounce); + __com32.cs_intcall(0x22, &inregs, &inregs); + + return lba; +} + +/* drive offset detection */ +int drvoff_detect(int type, unsigned int *off) +{ + if (bpbV40 <= type && type <= bpbVNT) { + *off = 0x24; + } else if (type == bpbV70) { + *off = 0x40; + } else + return 0; + + return -1; +} + +/* + * heuristics could certainly be improved + */ +int bpb_detect(const uint8_t *sec, const char *tag) +{ + int a, b, c, jmp = -1, rev = 0; + + /* media descriptor check */ + if ((sec[0x15] & 0xF0) != 0xF0) + goto out; + + if (sec[0] == 0xEB) /* jump short */ + jmp = 2 + *(int8_t *)(sec + 1); + else if (sec[0] == 0xE9) /* jump near */ + jmp = 3 + *(int16_t *)(sec + 1); + + if (jmp < 0) /* no boot code at all ? */ + goto nocode; + + /* sanity */ + if (jmp < 0x18 || jmp > 0x1F0) + goto out; + + /* detect by jump */ + if (jmp >= 0x18 && jmp < 0x1E) + rev = bpbV20; + else if (jmp >= 0x1E && jmp < 0x20) + rev = bpbV30; + else if (jmp >= 0x20 && jmp < 0x24) + rev = bpbV32; + else if (jmp >= 0x24 && jmp < 0x46) + rev = bpbV34; + + /* TODO: some better V2 - V3.4 checks ? */ + + if (rev) + goto out; + /* + * BPB info: + * 2.0 == 0x0B - 0x17 + * 3.0 == 2.0 + 0x18 - 0x1D + * 3.2 == 3.0 + 0x1E - 0x1F + * 3.4 ==!2.0 + 0x18 - 0x23 + * 4.0 == 3.4 + 0x24 - 0x45 + * NT ==~3.4 + 0x24 - 0x53 + * 7.0 == 3.4 + 0x24 - 0x59 + */ + +nocode: + a = memcmp(sec + 0x03, "NTFS", 4); + b = memcmp(sec + 0x36, "FAT", 3); + c = memcmp(sec + 0x52, "FAT", 3); /* ext. DOS 7+ bs */ + + if ((sec[0x26] & 0xFE) == 0x28 && !b) { + rev = bpbV40; + } else if (sec[0x26] == 0x80 && !a) { + rev = bpbVNT; + } else if ((sec[0x42] & 0xFE) == 0x28 && !c) { + rev = bpbV70; + } + +out: + printf("BPB detection (%s): %s\n", tag, bpbtypes[rev]); + return rev; +} + +/* vim: set ts=8 sts=4 sw=4 noet: */ diff --git a/com32/chain/utility.h b/com32/chain/utility.h new file mode 100644 index 00000000..8a08be71 --- /dev/null +++ b/com32/chain/utility.h @@ -0,0 +1,30 @@ +#ifndef _COM32_CHAIN_UTILITY_H +#define _COM32_CHAIN_UTILITY_H + +#include <stdint.h> +#include <syslinux/disk.h> + +#define bpbUNK 0 +#define bpbV20 1 +#define bpbV30 2 +#define bpbV32 3 +#define bpbV34 4 +#define bpbV40 5 +#define bpbVNT 6 +#define bpbV70 7 + +#define l2c_cnul 0 +#define l2c_cadd 1 +#define l2c_cmax 2 + +void error(const char *msg); +int guid_is0(const struct guid *guid); +void wait_key(void); +void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, uint32_t mode); +uint32_t get_file_lba(const char *filename); +int drvoff_detect(int type, unsigned int *off); +int bpb_detect(const uint8_t *bpb, const char *tag); + +#endif + +/* vim: set ts=8 sts=4 sw=4 noet: */ diff --git a/com32/cmenu/Makefile b/com32/cmenu/Makefile index 794af741..446bbcdd 100644 --- a/com32/cmenu/Makefile +++ b/com32/cmenu/Makefile @@ -17,11 +17,12 @@ NOGPL := 1 -# This must be defined before MCONFIG is included +# This must be defined before com32.mk is included LIBS = libmenu/libmenu.a topdir = ../.. -include ../MCONFIG +MAKEDIR = $(topdir)/mk +include $(MAKEDIR)/com32.mk CFLAGS += -I./libmenu diff --git a/com32/gdbstub/Makefile b/com32/gdbstub/Makefile index 5513876b..38d003cc 100644 --- a/com32/gdbstub/Makefile +++ b/com32/gdbstub/Makefile @@ -15,7 +15,8 @@ ## topdir = ../.. -include ../MCONFIG +MAKEDIR = $(topdir)/mk +include $(MAKEDIR)/com32.mk CFLAGS += -fPIE diff --git a/com32/gfxboot/Makefile b/com32/gfxboot/Makefile index 73133e1b..183115f4 100644 --- a/com32/gfxboot/Makefile +++ b/com32/gfxboot/Makefile @@ -12,7 +12,8 @@ ## ----------------------------------------------------------------------- topdir = ../.. -include ../MCONFIG +MAKEDIR = $(topdir)/mk +include $(MAKEDIR)/com32.mk MODULES = gfxboot.c32 diff --git a/com32/gfxboot/gfxboot.c b/com32/gfxboot/gfxboot.c index 37499202..aa05caf8 100644 --- a/com32/gfxboot/gfxboot.c +++ b/com32/gfxboot/gfxboot.c @@ -102,6 +102,8 @@ typedef struct __attribute__ ((packed)) { // 0: GFX_CB_MENU_INIT accepts 32 bit addresses // 1: knows about xmem_start, xmem_end uint16_t reserved_1; // 62: + uint32_t gfxboot_cwd; // 64: if set, points to current gfxboot working directory relative + // to syslinux working directory } gfx_config_t; @@ -181,6 +183,7 @@ int main(int argc, char **argv) { int menu_index; const union syslinux_derivative_info *sdi; + char working_dir[256]; openconsole(&dev_stdcon_r, &dev_stdcon_w); @@ -224,6 +227,10 @@ int main(int argc, char **argv) return 0; } + if(getcwd(working_dir, sizeof working_dir)) { + gfx_config.gfxboot_cwd = (uint32_t) working_dir; + } + if(gfx_init(argv[1])) { printf("Error setting up gfxboot\n"); if(argc > 2) show_message(argv[2]); @@ -806,6 +813,12 @@ void boot(int index) int i, label_len; unsigned ipapp; const struct syslinux_ipappend_strings *ipappend; + char *gfxboot_cwd = (char *) gfx_config.gfxboot_cwd; + + if(gfxboot_cwd) { + chdir(gfxboot_cwd); + gfx_config.gfxboot_cwd = 0; + } for(menu_ptr = menu; menu_ptr; menu_ptr = menu_ptr->next, index--) { if(!index) break; @@ -922,11 +935,15 @@ void boot_entry(menu_t *menu_ptr, char *arg) *skip_nonspaces(s) = 0; initrd_arg = s; } + else if(initrd_arg) { + free(s0); + initrd_arg = s0 = strdup(initrd_arg); + } if(initrd_arg) { initrd = initramfs_init(); - while((t = strsep(&s, ","))) { + while((t = strsep(&initrd_arg, ","))) { initrd_buf = load_one(t, &initrd_size); if(!initrd_buf) { @@ -945,7 +962,7 @@ void boot_entry(menu_t *menu_ptr, char *arg) gfx_done(); - syslinux_boot_linux(kernel, kernel_size, initrd, arg); + syslinux_boot_linux(kernel, kernel_size, initrd, NULL, arg); } diff --git a/com32/gplinclude/acpi/acpi.h b/com32/gplinclude/acpi/acpi.h index 94589f35..bf3ffdb7 100644 --- a/com32/gplinclude/acpi/acpi.h +++ b/com32/gplinclude/acpi/acpi.h @@ -95,4 +95,5 @@ void parse_madt(s_acpi * acpi); int search_rsdp(s_acpi *acpi); void get_acpi_description_header(uint8_t *q, s_acpi_description_header * adh); bool parse_header(uint64_t *address, s_acpi *acpi); +char *flags_to_string(char *buffer, uint16_t flags); #endif diff --git a/com32/gplinclude/cpuid.h b/com32/gplinclude/cpuid.h index 53a08085..6a33e9cb 100644 --- a/com32/gplinclude/cpuid.h +++ b/com32/gplinclude/cpuid.h @@ -18,9 +18,11 @@ #include <stdbool.h> #include <stdint.h> +#include <stdio.h> #include <cpufeature.h> #include <sys/bitops.h> #include <sys/cpu.h> +#include <sys/io.h> #include <klibc/compiler.h> #define PAGE_SIZE 4096 @@ -28,99 +30,112 @@ #define CPU_MODEL_SIZE 48 #define CPU_VENDOR_SIZE 48 +#define CPU_FLAGS(m_) \ +m_(bool, fpu, /* Onboard FPU */) \ +m_(bool, vme, /* Virtual Mode Extensions */) \ +m_(bool, de, /* Debugging Extensions */) \ +m_(bool, pse, /* Page Size Extensions */) \ +m_(bool, tsc, /* Time Stamp Counter */) \ +m_(bool, msr, /* Model-Specific Registers, RDMSR, WRMSR */) \ +m_(bool, pae, /* Physical Address Extensions */) \ +m_(bool, mce, /* Machine Check Architecture */) \ +m_(bool, cx8, /* CMPXCHG8 instruction */) \ +m_(bool, apic, /* Onboard APIC */) \ +m_(bool, sep, /* SYSENTER/SYSEXIT */) \ +m_(bool, mtrr, /* Memory Type Range Registers */) \ +m_(bool, pge, /* Page Global Enable */) \ +m_(bool, mca, /* Machine Check Architecture */) \ +m_(bool, cmov, /* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */) \ +m_(bool, pat, /* Page Attribute Table */) \ +m_(bool, pse_36, /* 36-bit PSEs */) \ +m_(bool, psn, /* Processor serial number */) \ +m_(bool, clflsh, /* Supports the CLFLUSH instruction */) \ +m_(bool, dts, /* Debug Trace Store */) \ +m_(bool, acpi, /* ACPI via MSR */) \ +m_(bool, pbe, /* Pending Break Enable */) \ +m_(bool, mmx, /* Multimedia Extensions */) \ +m_(bool, fxsr, /* FXSAVE and FXRSTOR instructions (fast save and restore of FPU context), and CR4.OSFXSR available */) \ +m_(bool, sse, /* Streaming SIMD Extensions */) \ +m_(bool, sse2, /* Streaming SIMD Extensions 2 */) \ +m_(bool, ss, /* CPU self snoop */) \ +m_(bool, htt, /* Hyper-Threading */) \ +m_(bool, acc, /* Automatic clock control */) \ +m_(bool, syscall, /* SYSCALL/SYSRET */) \ +m_(bool, mp, /* MP Capable. */) \ +m_(bool, nx, /* Execute Disable */) \ +m_(bool, mmxext, /* AMD MMX extensions */) \ +m_(bool, fxsr_opt, /* FXSAVE/FXRSTOR optimizations */) \ +m_(bool, gbpages, /* "pdpe1gb" GB pages */) \ +m_(bool, rdtscp, /* RDTSCP */) \ +m_(bool, lm, /* Long Mode (x86-64) */) \ +m_(bool, nowext, /* AMD 3DNow! extensions */) \ +m_(bool, now, /* 3DNow! */) \ +m_(bool, smp, /* A smp configuration has been found */) \ +m_(bool, pni, /* Streaming SIMD Extensions-3 */) \ +m_(bool, pclmulqd, /* PCLMULQDQ instruction */) \ +m_(bool, dtes64, /* 64-bit Debug Store */) \ +m_(bool, vmx, /* Hardware virtualization */) \ +m_(bool, smx, /* Safer Mode */) \ +m_(bool, est, /* Enhanced SpeedStep */) \ +m_(bool, tm2, /* Thermal Monitor 2 */) \ +m_(bool, sse3, /* Supplemental SSE-3 */) \ +m_(bool, cid, /* Context ID */) \ +m_(bool, fma, /* Fused multiply-add */) \ +m_(bool, cx16, /* CMPXCHG16B */) \ +m_(bool, xtpr, /* Send Task Priority Messages */) \ +m_(bool, pdcm, /* Performance Capabilities */) \ +m_(bool, dca, /* Direct Cache Access */) \ +m_(bool, xmm4_1, /* "sse4_1" SSE-4.1 */) \ +m_(bool, xmm4_2, /* "sse4_2" SSE-4.2 */) \ +m_(bool, x2apic, /* x2APIC */) \ +m_(bool, movbe, /* MOVBE instruction */) \ +m_(bool, popcnt, /* POPCNT instruction */) \ +m_(bool, aes, /* AES Instruction */) \ +m_(bool, xsave, /* XSAVE/XRSTOR/XSETBV/XGETBV */) \ +m_(bool, osxsave, /* XSAVE enabled in the OS */) \ +m_(bool, avx, /* Advanced Vector Extensions */) \ +m_(bool, hypervisor, /* Running on a hypervisor */) \ +m_(bool, ace2, /* Advanced Cryptography Engine v2 */) \ +m_(bool, ace2_en, /* ACE v2 enabled */) \ +m_(bool, phe, /* PadLock Hash Engine */) \ +m_(bool, phe_en, /* PadLock Hash Engine Enabled */) \ +m_(bool, pmm, /* PadLock Montgomery Multiplier */) \ +m_(bool, pmm_en, /* PadLock Montgomery Multiplier enabled */) \ +m_(bool, svm, /* Secure virtual machine */) \ +m_(bool, extapic, /* Extended APIC space */) \ +m_(bool, cr8_legacy, /* CR8 in 32-bit mode */) \ +m_(bool, abm, /* Advanced bit manipulation */) \ +m_(bool, sse4a, /* SSE4-A */) \ +m_(bool, misalignsse, /* Misaligned SSE mode */) \ +m_(bool, nowprefetch, /* 3DNow prefetch instructions */) \ +m_(bool, osvw, /* OS Visible Workaround */) \ +m_(bool, ibs, /* Instruction Based Sampling */) \ +m_(bool, sse5, /* SSE5 */) \ +m_(bool, skinit, /* SKINIT/STGI instructions */) \ +m_(bool, wdt, /* Watchdog Timer */) \ +m_(bool, ida, /* Intel Dynamic Acceleration */) \ +m_(bool, arat, /* Always Running APIC Timer */) \ +m_(bool, tpr_shadow, /* Intel TPR Shadow */) \ +m_(bool, vnmi, /* Intel Virtual NMI */) \ +m_(bool, flexpriority, /* Intel FlexPriority */) \ +m_(bool, ept, /* Intel Extended Page Table */) \ +m_(bool, vpid, /* Intel Virtual Processor ID */) + +#define STRUCT_MEMBERS(type_, name_, comment_) type_ name_; + +#define STRUCT_MEMBER_NAMES(type_, name_, comment_) #name_ , + +#define STRUCTURE_MEMBER_OFFSETS(type_, name_, comment_) \ + offsetof(s_cpu_flags, name_), + typedef struct { - bool fpu; /* Onboard FPU */ - bool vme; /* Virtual Mode Extensions */ - bool de; /* Debugging Extensions */ - bool pse; /* Page Size Extensions */ - bool tsc; /* Time Stamp Counter */ - bool msr; /* Model-Specific Registers, RDMSR, WRMSR */ - bool pae; /* Physical Address Extensions */ - bool mce; /* Machine Check Architecture */ - bool cx8; /* CMPXCHG8 instruction */ - bool apic; /* Onboard APIC */ - bool sep; /* SYSENTER/SYSEXIT */ - bool mtrr; /* Memory Type Range Registers */ - bool pge; /* Page Global Enable */ - bool mca; /* Machine Check Architecture */ - bool cmov; /* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */ - bool pat; /* Page Attribute Table */ - bool pse_36; /* 36-bit PSEs */ - bool psn; /* Processor serial number */ - bool clflsh; /* Supports the CLFLUSH instruction */ - bool dts; /* Debug Trace Store */ - bool acpi; /* ACPI via MSR */ - bool pbe; /* Pending Break Enable */ - bool mmx; /* Multimedia Extensions */ - bool fxsr; /* FXSAVE and FXRSTOR instructions (fast save and restore */ - /* of FPU context), and CR4.OSFXSR available */ - bool sse; /* Streaming SIMD Extensions */ - bool sse2; /* Streaming SIMD Extensions 2 */ - bool ss; /* CPU self snoop */ - bool htt; /* Hyper-Threading */ - bool acc; /* Automatic clock control */ - bool syscall; /* SYSCALL/SYSRET */ - bool mp; /* MP Capable. */ - bool nx; /* Execute Disable */ - bool mmxext; /* AMD MMX extensions */ - bool fxsr_opt; /* FXSAVE/FXRSTOR optimizations */ - bool gbpages; /* "pdpe1gb" GB pages */ - bool rdtscp; /* RDTSCP */ - bool lm; /* Long Mode (x86-64) */ - bool nowext; /* AMD 3DNow! extensions */ - bool now; /* 3DNow! */ - bool smp; /* A smp configuration has been found */ - bool pni; /* Streaming SIMD Extensions-3 */ - bool pclmulqd; /* PCLMULQDQ instruction */ - bool dtes64; /* 64-bit Debug Store */ - bool vmx; /* Hardware virtualization */ - bool smx; /* Safer Mode */ - bool est; /* Enhanced SpeedStep */ - bool tm2; /* Thermal Monitor 2 */ - bool sse3; /* Supplemental SSE-3 */ - bool cid; /* Context ID */ - bool fma; /* Fused multiply-add */ - bool cx16; /* CMPXCHG16B */ - bool xtpr; /* Send Task Priority Messages */ - bool pdcm; /* Performance Capabilities */ - bool dca; /* Direct Cache Access */ - bool xmm4_1; /* "sse4_1" SSE-4.1 */ - bool xmm4_2; /* "sse4_2" SSE-4.2 */ - bool x2apic; /* x2APIC */ - bool movbe; /* MOVBE instruction */ - bool popcnt; /* POPCNT instruction */ - bool aes; /* AES Instruction */ - bool xsave; /* XSAVE/XRSTOR/XSETBV/XGETBV */ - bool osxsave; /* XSAVE enabled in the OS */ - bool avx; /* Advanced Vector Extensions */ - bool hypervisor; /* Running on a hypervisor */ - bool ace2; /* Advanced Cryptography Engine v2 */ - bool ace2_en; /* ACE v2 enabled */ - bool phe; /* PadLock Hash Engine */ - bool phe_en; /* PadLock Hash Engine Enabled */ - bool pmm; /* PadLock Montgomery Multiplier */ - bool pmm_en; /* PadLock Montgomery Multiplier enabled */ - bool svm; /* Secure virtual machine */ - bool extapic; /* Extended APIC space */ - bool cr8_legacy; /* CR8 in 32-bit mode */ - bool abm; /* Advanced bit manipulation */ - bool sse4a; /* SSE4-A */ - bool misalignsse; /* Misaligned SSE mode */ - bool nowprefetch; /* 3DNow prefetch instructions */ - bool osvw; /* OS Visible Workaround */ - bool ibs; /* Instruction Based Sampling */ - bool sse5; /* SSE5 */ - bool skinit; /* SKINIT/STGI instructions */ - bool wdt; /* Watchdog Timer */ - bool ida; /* Intel Dynamic Acceleration */ - bool arat; /* Always Running APIC Timer */ - bool tpr_shadow; /* Intel TPR Shadow */ - bool vnmi; /* Intel Virtual NMI */ - bool flexpriority; /* Intel FlexPriority */ - bool ept; /* Intel Extended Page Table */ - bool vpid; /* Intel Virtual Processor ID */ + CPU_FLAGS(STRUCT_MEMBERS) } s_cpu_flags; +extern size_t cpu_flags_offset[]; +extern const char *cpu_flags_names[]; +extern size_t cpu_flags_count; + typedef struct { char vendor[CPU_VENDOR_SIZE]; uint8_t vendor_id; @@ -135,6 +150,7 @@ typedef struct { s_cpu_flags flags; } s_cpu; +extern bool get_cpu_flag_value_from_name(s_cpu *cpu, const char * flag); /**********************************************************************************/ /**********************************************************************************/ /* From this point this is some internal stuff mainly taken from the linux kernel */ @@ -171,11 +187,37 @@ typedef struct { #define X86_VENDOR_RISE 6 #define X86_VENDOR_TRANSMETA 7 #define X86_VENDOR_NSC 8 -#define X86_VENDOR_NUM 9 -#define X86_VENDOR_UNKNOWN 0xff +#define X86_VENDOR_UNKNOWN 9 +#define X86_VENDOR_NUM 10 #define cpu_has(c, bit) test_bit(bit, (c)->x86_capability) +// Taken from asm/processor-flags.h +// NSC/Cyrix CPU configuration register indexes +#define CX86_CCR2 0xc2 +#define CX86_CCR3 0xc3 +#define CX86_DIR0 0xfe +#define CX86_DIR1 0xff + +static const char Cx86_model[][9] = { + "Cx486", "Cx486", "5x86 ", "6x86", "MediaGX ", "6x86MX ", + "M II ", "Unknown" +}; + +static const char Cx486_name[][5] = { + "SLC", "DLC", "SLC2", "DLC2", "SRx", "DRx", + "SRx2", "DRx2" +}; + +static const char Cx486S_name[][4] = { + "S", "S2", "Se", "S2e" +}; + +static const char Cx486D_name[][4] = { + "DX", "DX2", "?", "?", "?", "DX4" +}; + + /* * CPU type and hardware bug flags. Kept separately for each CPU. * Members of this structure are referenced in head.S, so think twice @@ -260,6 +302,16 @@ struct intel_mp_floating { uint8_t mpf_feature5; /* Unused (0) */ }; +static inline uint8_t getCx86(uint8_t reg) { + outb(reg, 0x22); + return inb(0x23); +} + +static inline void setCx86(uint8_t reg, uint8_t data) { + outb(reg, 0x22); + outb(data, 0x23); +} + extern void get_cpu_vendor(struct cpuinfo_x86 *c); extern void detect_cpu(s_cpu * cpu); #endif 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/gplinclude/zzjson/zzjson.h b/com32/gplinclude/zzjson/zzjson.h new file mode 100644 index 00000000..d4b32e12 --- /dev/null +++ b/com32/gplinclude/zzjson/zzjson.h @@ -0,0 +1,116 @@ +/* ZZJSON - Copyright (C) 2008 by Ivo van Poorten + * License: GNU Lesser General Public License version 2.1 + */ +#ifndef ZZJSON_H +#define ZZJSON_H + +#include <stdlib.h> + +/* Version: */ + +#define ZZJSON_VERSION_MAJOR 1 +#define ZZJSON_VERSION_MINOR 1 +#define ZZJSON_VERSION_MICRO 0 +#define ZZJSON_VERSION_INT ( 1<<16 | 1<<8 | 0 ) +#define ZZJSON_IDENT "zzjson 1.1.0" + +/* Defines: */ + +#define ZZJSON_ALLOW_EXTRA_COMMA 1 +#define ZZJSON_ALLOW_ILLEGAL_ESCAPE 2 +#define ZZJSON_ALLOW_CONTROL_CHARS 4 +#define ZZJSON_ALLOW_GARBAGE_AT_END 8 +#define ZZJSON_ALLOW_COMMENTS 16 + +#define ZZJSON_VERY_LOOSE (-1) +#define ZZJSON_VERY_STRICT 0 + +/* Types: */ + +/* needed by: pa = parser, pr = printer, f = free, q = query, c = create */ +typedef struct ZZJSON_CONFIG { + int strictness; // pa + void *ihandle; // pa + int (*getchar)(void *ihandle); // pa + int (*ungetchar)(int c, void *ihandle); // pa + void *(*malloc)(size_t size); // pa c + void *(*calloc)(size_t nmemb, size_t size); // pa c + void (*free)(void *ptr); // pa f c + void *(*realloc)(void *ptr, size_t size); // pa + void *ehandle; // pa pr c + void (*error)(void *ehandle, const char *format, ...); // pa pr c + void *ohandle; // pr + int (*print)(void *ohandle, const char *format, ...); // pr + int (*putchar)(int c, void *handle); // pr +} ZZJSON_CONFIG; + +typedef enum ZZJSON_TYPE { + ZZJSON_NONE = 0, + ZZJSON_OBJECT, + ZZJSON_ARRAY, + ZZJSON_STRING, + ZZJSON_NUMBER_NEGINT, + ZZJSON_NUMBER_POSINT, + ZZJSON_NUMBER_DOUBLE, + ZZJSON_NULL, + ZZJSON_TRUE, + ZZJSON_FALSE +} ZZJSON_TYPE; + +typedef struct ZZJSON { + ZZJSON_TYPE type; + union { + struct { + char *label; + struct ZZJSON *val; + } object; + struct { + struct ZZJSON *val; + } array; + struct { + char *string; + } string; + struct { + union { + unsigned long long ival; + double dval; + } val; + } number; + } value; + struct ZZJSON *next; +} ZZJSON; + +/* Functions: */ + +ZZJSON *zzjson_parse(ZZJSON_CONFIG *config); +void zzjson_free(ZZJSON_CONFIG *config, ZZJSON *zzjson); +int zzjson_print(ZZJSON_CONFIG *config, ZZJSON *zzjson); + +ZZJSON *zzjson_object_find_label(ZZJSON *zzjson, char *label); +ZZJSON *zzjson_object_find_labels(ZZJSON *zzjson, ...); // end with , NULL +unsigned int zzjson_object_count(ZZJSON *zzjson); +unsigned int zzjson_array_count(ZZJSON *zzjson); + +ZZJSON *zzjson_create_true(ZZJSON_CONFIG *config); +ZZJSON *zzjson_create_false(ZZJSON_CONFIG *config); +ZZJSON *zzjson_create_null(ZZJSON_CONFIG *config); +ZZJSON *zzjson_create_number_d(ZZJSON_CONFIG *config, double d); +ZZJSON *zzjson_create_number_i(ZZJSON_CONFIG *config, long long i); +ZZJSON *zzjson_create_string(ZZJSON_CONFIG *config, char *s); + +/* list of ZZJSON *'s and end with , NULL */ +ZZJSON *zzjson_create_array(ZZJSON_CONFIG *config, ...); + +/* list of char*,ZZJSON* pairs, end with , NULL */ +ZZJSON *zzjson_create_object(ZZJSON_CONFIG *config, ...); + +ZZJSON *zzjson_array_prepend(ZZJSON_CONFIG *config, ZZJSON *array, + ZZJSON *val); +ZZJSON *zzjson_array_append (ZZJSON_CONFIG *config, ZZJSON *array, + ZZJSON *val); + +ZZJSON *zzjson_object_prepend(ZZJSON_CONFIG *config, ZZJSON *object, + char *label, ZZJSON *val); +ZZJSON *zzjson_object_append (ZZJSON_CONFIG *config, ZZJSON *object, + char *label, ZZJSON *val); +#endif diff --git a/com32/gpllib/Makefile b/com32/gpllib/Makefile index a1740610..4b7b8468 100644 --- a/com32/gpllib/Makefile +++ b/com32/gpllib/Makefile @@ -4,11 +4,12 @@ # Include configuration rules topdir = ../.. -include ../lib/MCONFIG +MAKEDIR = $(topdir)/mk +include $(MAKEDIR)/lib.mk -REQFLAGS += -I../gplinclude +REQFLAGS += -I../gplinclude -I../gplinclude/zzjson -GPLDIRS := . disk dmi vpd acpi +GPLDIRS := . disk dmi vpd acpi zzjson LIBOBJS := $(foreach dir,$(GPLDIRS),$(patsubst %.c,%.o,$(wildcard $(dir)/*.c))) BINDIR = /usr/bin diff --git a/com32/gpllib/acpi/acpi.c b/com32/gpllib/acpi/acpi.c index 8e5ee29c..d2bf29e5 100644 --- a/com32/gpllib/acpi/acpi.c +++ b/com32/gpllib/acpi/acpi.c @@ -32,6 +32,25 @@ #include <memory.h> #include "acpi/acpi.h" +/* M1PS flags have to be interpreted as strings */ +char *flags_to_string(char *buffer, uint16_t flags) +{ + memset(buffer, 0, sizeof(buffer)); + strcpy(buffer, "default"); + if ((flags & POLARITY_ACTIVE_HIGH) == POLARITY_ACTIVE_HIGH) + strcpy(buffer, "high"); + else if ((flags & POLARITY_ACTIVE_LOW) == POLARITY_ACTIVE_LOW) + strcpy(buffer, "low"); + if ((flags & TRIGGER_EDGE) == TRIGGER_EDGE) + strncat(buffer, " edge", 5); + else if ((flags & TRIGGER_LEVEL) == TRIGGER_LEVEL) + strncat(buffer, " level", 6); + else + strncat(buffer, " default", 8); + + return buffer; +} + void dbg_printf(const char *fmt, ...) { va_list args; diff --git a/com32/gpllib/cpuid.c b/com32/gpllib/cpuid.c index 2d5b5ce9..2abd0bda 100644 --- a/com32/gpllib/cpuid.c +++ b/com32/gpllib/cpuid.c @@ -20,8 +20,31 @@ #include <string.h> #include "cpuid.h" +const char *cpu_flags_names[] = { + CPU_FLAGS(STRUCT_MEMBER_NAMES) +}; + +size_t cpu_flags_offset[] = { + CPU_FLAGS(STRUCTURE_MEMBER_OFFSETS) +}; + +size_t cpu_flags_count = sizeof cpu_flags_names / sizeof *cpu_flags_names; + struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = { }; +bool get_cpu_flag_value_from_name(s_cpu *cpu, const char * flag_name) { + size_t i; + bool cpu_flag_present=false, *flag_value = &cpu_flag_present; + + for (i = 0; i < cpu_flags_count; i++) { + if (strcmp(cpu_flags_names[i],flag_name) == 0) { + flag_value = (bool *)((char *)&cpu->flags + cpu_flags_offset[i]); + } + } + return *flag_value; +} + + /* * CPUID functions returning a single datum */ @@ -73,6 +96,48 @@ static struct cpu_dev transmeta_cpu_dev = { .c_ident = {"GenuineTMx86", "TransmetaCPU"} }; +static struct cpu_dev nsc_cpu_dev = { + .c_vendor = "National Semiconductor", + .c_ident = {"Geode by NSC"} +}; + +static struct cpu_dev unknown_cpu_dev = { + .c_vendor = "Unknown Vendor", + .c_ident = {"Unknown CPU"} +}; + +/* + * Read NSC/Cyrix DEVID registers (DIR) to get more detailed info. about the CPU + */ +void do_cyrix_devid(unsigned char *dir0, unsigned char *dir1) +{ + unsigned char ccr2, ccr3; + + /* we test for DEVID by checking whether CCR3 is writable */ + ccr3 = getCx86(CX86_CCR3); + setCx86(CX86_CCR3, ccr3 ^ 0x80); + getCx86(0xc0); /* dummy to change bus */ + + if (getCx86(CX86_CCR3) == ccr3) { /* no DEVID regs. */ + ccr2 = getCx86(CX86_CCR2); + setCx86(CX86_CCR2, ccr2 ^ 0x04); + getCx86(0xc0); /* dummy */ + + if (getCx86(CX86_CCR2) == ccr2) /* old Cx486SLC/DLC */ + *dir0 = 0xfd; + else { /* Cx486S A step */ + setCx86(CX86_CCR2, ccr2); + *dir0 = 0xfe; + } + } else { + setCx86(CX86_CCR3, ccr3); /* restore CCR3 */ + + /* read DIR0 and DIR1 CPU registers */ + *dir0 = getCx86(CX86_DIR0); + *dir1 = getCx86(CX86_DIR1); + } +} + void init_cpu_devs(void) { cpu_devs[X86_VENDOR_INTEL] = &intel_cpu_dev; @@ -83,6 +148,8 @@ void init_cpu_devs(void) cpu_devs[X86_VENDOR_CENTAUR] = ¢aur_cpu_dev; cpu_devs[X86_VENDOR_RISE] = &rise_cpu_dev; cpu_devs[X86_VENDOR_TRANSMETA] = &transmeta_cpu_dev; + cpu_devs[X86_VENDOR_NSC] = &nsc_cpu_dev; + cpu_devs[X86_VENDOR_UNKNOWN] = &unknown_cpu_dev; } void get_cpu_vendor(struct cpuinfo_x86 *c) @@ -90,7 +157,7 @@ void get_cpu_vendor(struct cpuinfo_x86 *c) char *v = c->x86_vendor_id; int i; init_cpu_devs(); - for (i = 0; i < X86_VENDOR_NUM; i++) { + for (i = 0; i < X86_VENDOR_NUM-1; i++) { if (cpu_devs[i]) { if (!strcmp(v, cpu_devs[i]->c_ident[0]) || (cpu_devs[i]->c_ident[1] && @@ -177,6 +244,96 @@ void detect_cache(uint32_t xlvl, struct cpuinfo_x86 *c) c->x86_l2_cache_size = l2size; } +void detect_cyrix(struct cpuinfo_x86 *c) { + unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0; + char *buf = c->x86_model_id; + char Cx86_cb[] = "?.5x Core/Bus Clock"; + const char cyrix_model_mult1[] = "12??43"; + const char cyrix_model_mult2[] = "12233445"; + const char *p = NULL; + + do_cyrix_devid(&dir0, &dir1); + dir0_msn = dir0 >> 4; /* identifies CPU "family" */ + dir0_lsn = dir0 & 0xf; /* model or clock multiplier */ + c->x86_model = (dir1 >> 4) + 1; + c->x86_mask = dir1 & 0xf; + switch (dir0_msn) { + unsigned char tmp; + + case 0: /* Cx486SLC/DLC/SRx/DRx */ + p = Cx486_name[dir0_lsn & 7]; + break; + + case 1: /* Cx486S/DX/DX2/DX4 */ + p = (dir0_lsn & 8) ? Cx486D_name[dir0_lsn & 5] : Cx486S_name[dir0_lsn & 3]; + break; + + case 2: /* 5x86 */ + Cx86_cb[2] = cyrix_model_mult1[dir0_lsn & 5]; + p = Cx86_cb+2; + break; + + case 3: /* 6x86/6x86L */ + Cx86_cb[1] = ' '; + Cx86_cb[2] = cyrix_model_mult1[dir0_lsn & 5]; + if (dir1 > 0x21) { /* 686L */ + Cx86_cb[0] = 'L'; + p = Cx86_cb; + (c->x86_model)++; + } else /* 686 */ + p = Cx86_cb+1; + + c->coma_bug = 1; + break; + case 4: + c->x86_l1_data_cache_size = 16; /* Yep 16K integrated cache thats it */ + if (c->cpuid_level != 2) { /* Media GX */ + Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4'; + p = Cx86_cb+2; + } + break; + + case 5: /* 6x86MX/M II */ + if (dir1 > 7) { + dir0_msn++; /* M II */ + } else { + c->coma_bug = 1; /* 6x86MX, it has the bug. */ + } + + tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0; + Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7]; + p = Cx86_cb+tmp; + if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20)) + (c->x86_model)++; + break; + + case 0xf: /* Cyrix 486 without DEVID registers */ + switch (dir0_lsn) { + case 0xd: /* either a 486SLC or DLC w/o DEVID */ + dir0_msn = 0; + p = Cx486_name[(c->hard_math) ? 1 : 0]; + break; + + case 0xe: /* a 486S A step */ + dir0_msn = 0; + p = Cx486S_name[0]; + break; + } + break; + + default: + dir0_msn = 7; + break; + } + + /* If the processor is unknown, we keep the model name we got + * from the generic call */ + if (dir0_msn < 7) { + strcpy(buf, Cx86_model[dir0_msn & 7]); + if (p) strcat(buf, p); + } +} + void generic_identify(struct cpuinfo_x86 *c) { uint32_t tfms, xlvl; @@ -222,6 +379,13 @@ void generic_identify(struct cpuinfo_x86 *c) get_model_name(c); /* Default name */ } + /* Specific detection code */ + switch (c->x86_vendor) { + case X86_VENDOR_CYRIX: + case X86_VENDOR_NSC: detect_cyrix(c); break; + default: break; + } + /* Detecting the number of cores */ switch (c->x86_vendor) { case X86_VENDOR_AMD: @@ -435,17 +599,12 @@ void set_generic_info(struct cpuinfo_x86 *c, s_cpu * cpu) void detect_cpu(s_cpu * cpu) { struct cpuinfo_x86 c; + memset(&c,0,sizeof(c)); c.x86_clflush_size = 32; - c.x86_l1_data_cache_size = 0; - c.x86_l1_instruction_cache_size = 0; - c.x86_l2_cache_size = 0; c.x86_vendor = X86_VENDOR_UNKNOWN; c.cpuid_level = -1; /* CPUID not detected */ - c.x86_model = c.x86_mask = 0; /* So far unknown... */ c.x86_num_cores = 1; - memset(&c.x86_capability, 0, sizeof(c.x86_capability)); - memset(&c.x86_vendor_id, 0, sizeof(c.x86_vendor_id)); - memset(&c.x86_model_id, 0, sizeof(c.x86_model_id)); + memset(&cpu->flags, 0, sizeof(s_cpu_flags)); if (!have_cpuid_p()) return; diff --git a/com32/gpllib/disk/labels.c b/com32/gpllib/disk/labels.c index ad3d33b3..f27ff655 100644 --- a/com32/gpllib/disk/labels.c +++ b/com32/gpllib/disk/labels.c @@ -36,29 +36,29 @@ void get_label(int label, char **buffer_label) strlcpy(buffer, "DOS 3.31+ 16-bit FAT (over 32M)", buffer_size); break; case 0x07: - strlcpy(buffer, "OS/2 IFS (e.g., HPFS)", buffer_size); - break; + strlcpy(buffer, "NTFS/exFAT/HPFS", buffer_size); //case 0x07: strlcpy(buffer, "Advanced Unix", buffer_size); break; //case 0x07: strlcpy(buffer, "Windows NT NTFS", buffer_size); break; //case 0x07: strlcpy(buffer, "QNX2.x (pre-1988)", buffer_size); break; - case 0x08: - strlcpy(buffer, "OS/2 (v1.0-1.3 only)", buffer_size); break; + case 0x08: + strlcpy(buffer, "AIX", buffer_size); //case 0x08: strlcpy(buffer, "AIX boot partition", buffer_size); break; //case 0x08: strlcpy(buffer, "SplitDrive", buffer_size); break; //case 0x08: strlcpy(buffer, "DELL partition spanning multiple drives", buffer_size); break; //case 0x08: strlcpy(buffer, "Commodore DOS", buffer_size); break; //case 0x08: strlcpy(buffer, "QNX 1.x and 2.x ("qny")", buffer_size); break; - case 0x09: - strlcpy(buffer, "AIX data partition", buffer_size); break; + case 0x09: + strlcpy(buffer, "AIX bootable partition", buffer_size); //case 0x09: strlcpy(buffer, "Coherent filesystem", buffer_size); break; //case 0x09: strlcpy(buffer, "QNX 1.x and 2.x ("qnz")", buffer_size); break; + break; case 0x0a: strlcpy(buffer, "OS/2 Boot Manager", buffer_size); - break; //case 0x0a: strlcpy(buffer, "Coherent swap partition", buffer_size); break; //case 0x0a: strlcpy(buffer, "OPUS", buffer_size); break; + break; case 0x0b: strlcpy(buffer, "WIN95 OSR2 32-bit FAT", buffer_size); break; @@ -72,13 +72,13 @@ void get_label(int label, char **buffer_label) strlcpy(buffer, "WIN95: Extended partition, LBA-mapped", buffer_size); break; case 0x10: - strlcpy(buffer, "OPUS (?)", buffer_size); + strlcpy(buffer, "OPUS", buffer_size); break; case 0x11: strlcpy(buffer, "Hidden DOS 12-bit FAT", buffer_size); break; case 0x12: - strlcpy(buffer, "Compaq config partition", buffer_size); + strlcpy(buffer, "Compaq diagnostic partition", buffer_size); break; case 0x14: strlcpy(buffer, "Hidden DOS 16-bit FAT <32M", buffer_size); @@ -87,7 +87,7 @@ void get_label(int label, char **buffer_label) strlcpy(buffer, "Hidden DOS 16-bit FAT >=32M", buffer_size); break; case 0x17: - strlcpy(buffer, "Hidden IFS (e.g., HPFS)", buffer_size); + strlcpy(buffer, "Hidden HPFS/exFAT/NTFS", buffer_size); break; case 0x18: strlcpy(buffer, "AST SmartSleep Partition", buffer_size); @@ -111,8 +111,8 @@ void get_label(int label, char **buffer_label) break; case 0x21: strlcpy(buffer, "Reserved", buffer_size); - break; //case 0x21: strlcpy(buffer, "Unused", buffer_size); break; + break; case 0x22: strlcpy(buffer, "Unused", buffer_size); break; @@ -125,6 +125,18 @@ void get_label(int label, char **buffer_label) case 0x26: strlcpy(buffer, "Reserved", buffer_size); break; + case 0x27: + strlcpy(buffer, "PQService (Acer laptop hidden rescue partition)", buffer_size); + //Windows RE hidden partition + //MirOS BSD partition + //RouterBOOT kernel partition + break; + case 0x2a: + strlcpy(buffer, "AtheOS File System (AFS)", buffer_size); + break; + case 0x2b: + strlcpy(buffer, "SyllableSecure (SylStor)", buffer_size); + break; case 0x31: strlcpy(buffer, "Reserved", buffer_size); break; @@ -148,8 +160,8 @@ void get_label(int label, char **buffer_label) break; case 0x39: strlcpy(buffer, "Plan 9 partition", buffer_size); - break; //case 0x39: strlcpy(buffer, "THEOS ver 4 spanned partition", buffer_size); break; + break; case 0x3a: strlcpy(buffer, "THEOS ver 4 4gb partition", buffer_size); break; @@ -166,15 +178,15 @@ void get_label(int label, char **buffer_label) strlcpy(buffer, "Venix 80286", buffer_size); break; case 0x41: - strlcpy(buffer, "Linux/MINIX (sharing disk with DRDOS)", buffer_size); - break; + strlcpy(buffer, "PPC PReP Boot", buffer_size); break; //case 0x41: strlcpy(buffer, "Personal RISC Boot", buffer_size); break; - //case 0x41: strlcpy(buffer, "PPC PReP (Power PC Reference Platform) Boot", buffer_size); break; - case 0x42: - strlcpy(buffer, "Linux swap (sharing disk with DRDOS)", buffer_size); + // strlcpy(buffer, "Linux/MINIX (sharing disk with DRDOS)", buffer_size); break; - //case 0x42: strlcpy(buffer, "SFS (Secure Filesystem)", buffer_size); break; + case 0x42: + strlcpy(buffer, "SFS (Secure Filesystem)", buffer_size); break; + // strlcpy(buffer, "Linux swap (sharing disk with DRDOS)", buffer_size); //case 0x42: strlcpy(buffer, "Windows 2000 marker", buffer_size); break; + break; case 0x43: strlcpy(buffer, "Linux native (sharing disk with DRDOS)", buffer_size); break; @@ -183,9 +195,9 @@ void get_label(int label, char **buffer_label) break; case 0x45: strlcpy(buffer, "Boot-US boot manager", buffer_size); - break; //case 0x45: strlcpy(buffer, "Priam", buffer_size); break; //case 0x45: strlcpy(buffer, "EUMEL/Elan", buffer_size); break; + break; case 0x46: strlcpy(buffer, "EUMEL/Elan", buffer_size); break; @@ -197,8 +209,8 @@ void get_label(int label, char **buffer_label) break; case 0x4a: strlcpy(buffer, "AdaOS Aquila (Default)", buffer_size); - break; //case 0x4a: strlcpy(buffer, "ALFS/THIN lightweight filesystem for DOS", buffer_size); break; + break; case 0x4c: strlcpy(buffer, "Oberon partition", buffer_size); break; @@ -210,22 +222,22 @@ void get_label(int label, char **buffer_label) break; case 0x4f: strlcpy(buffer, "QNX4.x 3rd part", buffer_size); - break; //case 0x4f: strlcpy(buffer, "Oberon partition", buffer_size); break; + break; case 0x50: strlcpy(buffer, "OnTrack Disk Manager (older versions) RO", buffer_size); - break; //case 0x50: strlcpy(buffer, "Lynx RTOS", buffer_size); break; //case 0x50: strlcpy(buffer, "Native Oberon (alt)", buffer_size); break; + break; case 0x51: strlcpy(buffer, "OnTrack Disk Manager RW (DM6 Aux1)", buffer_size); - break; //case 0x51: strlcpy(buffer, "Novell", buffer_size); break; + break; case 0x52: strlcpy(buffer, "CP/M", buffer_size); - break; //case 0x52: strlcpy(buffer, "Microport SysV/AT", buffer_size); break; + break; case 0x53: strlcpy(buffer, "Disk Manager 6.0 Aux3", buffer_size); break; @@ -237,12 +249,12 @@ void get_label(int label, char **buffer_label) break; case 0x56: strlcpy(buffer, "Golden Bow VFeature Partitioned Volume.", buffer_size); - break; //case 0x56: strlcpy(buffer, "DM converted to EZ-BIOS", buffer_size); break; + break; case 0x57: strlcpy(buffer, "DrivePro", buffer_size); - break; //case 0x57: strlcpy(buffer, "VNDI Partition", buffer_size); break; + break; case 0x5c: strlcpy(buffer, "Priam EDisk", buffer_size); break; @@ -255,9 +267,9 @@ void get_label(int label, char **buffer_label) buffer_size); break; case 0x64: - strlcpy(buffer, "PC-ARMOUR protected partition", buffer_size); + strlcpy(buffer, "Novell Netware 286, 2.xx", buffer_size); break; + //strlcpy(buffer, "PC-ARMOUR protected partition", buffer_size); break; - //case 0x64: strlcpy(buffer, "Novell Netware 286, 2.xx", buffer_size); break; case 0x65: strlcpy(buffer, "Novell Netware 386, 3.xx or 4.xx", buffer_size); break; @@ -280,13 +292,15 @@ void get_label(int label, char **buffer_label) case 0x71: strlcpy(buffer, "Reserved", buffer_size); break; + case 0x72: + strlcpy(buffer, "V7/x86", buffer_size); + break; case 0x73: strlcpy(buffer, "Reserved", buffer_size); break; case 0x74: - strlcpy(buffer, "Reserved", buffer_size); - break; - //case 0x74: strlcpy(buffer, "Scramdisk partition", buffer_size); break; + //strlcpy(buffer, "Reserved", buffer_size); + strlcpy(buffer, "Scramdisk partition", buffer_size); break; case 0x75: strlcpy(buffer, "IBM PC/IX", buffer_size); break; @@ -301,37 +315,40 @@ void get_label(int label, char **buffer_label) strlcpy(buffer, "XOSL FS", buffer_size); break; case 0x7E: - strlcpy(buffer, " ", buffer_size); + strlcpy(buffer, "Unused", buffer_size); break; case 0x80: strlcpy(buffer, "MINIX until 1.4a", buffer_size); break; case 0x81: strlcpy(buffer, "MINIX since 1.4b, early Linux", buffer_size); - break; //case 0x81: strlcpy(buffer, "Mitac disk manager", buffer_size); break; - //case 0x82: strlcpy(buffer, "Prime", buffer_size); break; - //case 0x82: strlcpy(buffer, "Solaris x86", buffer_size); break; + break; case 0x82: strlcpy(buffer, "Linux swap", buffer_size); + //case 0x82: strlcpy(buffer, "Prime", buffer_size); break; + //case 0x82: strlcpy(buffer, "Solaris x86", buffer_size); break; break; case 0x83: strlcpy(buffer, "Linux native (usually ext2fs)", buffer_size); break; case 0x84: strlcpy(buffer, "OS/2 hidden C: drive", buffer_size); - break; //case 0x84: strlcpy(buffer, "Hibernation partition", buffer_size); break; + break; case 0x85: strlcpy(buffer, "Linux extended partition", buffer_size); break; - //case 0x86: strlcpy(buffer, "Old Linux RAID partition superblock", buffer_size); break; case 0x86: strlcpy(buffer, "NTFS volume set", buffer_size); + //case 0x86: strlcpy(buffer, "Old Linux RAID partition superblock", buffer_size); break; break; case 0x87: strlcpy(buffer, "NTFS volume set", buffer_size); break; + case 0x88: + strlcpy(buffer, "Linux Plaintext", buffer_size); + break; case 0x8a: strlcpy(buffer, "Linux Kernel Partition (used by AiR-BOOT)", buffer_size); @@ -349,7 +366,7 @@ void get_label(int label, char **buffer_label) buffer_size); break; case 0x8e: - strlcpy(buffer, "Linux Logical Volume Manager partition", buffer_size); + strlcpy(buffer, "Linux LVM partition", buffer_size); break; case 0x90: strlcpy(buffer, "Free FDISK hidden Primary DOS FAT16 partitition", @@ -365,14 +382,17 @@ void get_label(int label, char **buffer_label) break; case 0x93: strlcpy(buffer, "Hidden Linux native partition", buffer_size); - break; //case 0x93: strlcpy(buffer, "Amoeba", buffer_size); break; + break; case 0x94: strlcpy(buffer, "Amoeba bad block table", buffer_size); break; case 0x95: strlcpy(buffer, "MIT EXOPC native partitions", buffer_size); break; + case 0x96: + strlcpy(buffer, "CHRP ISO-9660 filesystem", buffer_size); + break; case 0x97: strlcpy(buffer, "Free FDISK hidden Primary DOS FAT32 partitition", buffer_size); @@ -392,6 +412,9 @@ void get_label(int label, char **buffer_label) strlcpy(buffer, "Free FDISK hidden DOS extended partitition (LBA)", buffer_size); break; + case 0x9e: + strlcpy(buffer, "ForthOS partition", buffer_size); + break; case 0x9f: strlcpy(buffer, "BSD/OS", buffer_size); break; @@ -400,13 +423,13 @@ void get_label(int label, char **buffer_label) break; case 0xa1: strlcpy(buffer, "Laptop hibernation partition", buffer_size); - break; //case 0xa1: strlcpy(buffer, "HP Volume Expansion (SpeedStor variant)", buffer_size); break; + break; case 0xa3: - strlcpy(buffer, "Reserved", buffer_size); + strlcpy(buffer, "HP Volume Expansion (SpeedStor variant)", buffer_size); break; case 0xa4: - strlcpy(buffer, "Reserved", buffer_size); + strlcpy(buffer, "HP Volume Expansion (SpeedStor variant)", buffer_size); break; case 0xa5: strlcpy(buffer, "BSD/386, 386BSD, NetBSD, FreeBSD", buffer_size); @@ -415,7 +438,7 @@ void get_label(int label, char **buffer_label) strlcpy(buffer, "OpenBSD", buffer_size); break; case 0xa7: - strlcpy(buffer, "NEXTSTEP", buffer_size); + strlcpy(buffer, "NeXTSTEP", buffer_size); break; case 0xa8: strlcpy(buffer, "Mac OS-X", buffer_size); @@ -429,8 +452,8 @@ void get_label(int label, char **buffer_label) break; case 0xab: strlcpy(buffer, "Mac OS-X Boot partition", buffer_size); - break; //case 0xab: strlcpy(buffer, "GO! partition", buffer_size); break; + break; case 0xae: strlcpy(buffer, "ShagOS filesystem", buffer_size); break; @@ -441,16 +464,19 @@ void get_label(int label, char **buffer_label) strlcpy(buffer, "BootStar Dummy", buffer_size); break; case 0xb1: - strlcpy(buffer, "Reserved", buffer_size); + strlcpy(buffer, "HP Volume Expansion (SpeedStor variant)", buffer_size); + break; + case 0xb2: + strlcpy(buffer, "QNX Neutrino Power-Safe filesystem", buffer_size); break; case 0xb3: - strlcpy(buffer, "Reserved", buffer_size); + strlcpy(buffer, "HP Volume Expansion (SpeedStor variant)", buffer_size); break; case 0xb4: - strlcpy(buffer, "Reserved", buffer_size); + strlcpy(buffer, "HP Volume Expansion (SpeedStor variant)", buffer_size); break; case 0xb6: - strlcpy(buffer, "Reserved", buffer_size); + strlcpy(buffer, "HP Volume Expansion (SpeedStor variant)", buffer_size); break; case 0xb7: strlcpy(buffer, "BSDI BSD/386 filesystem", buffer_size); @@ -461,21 +487,27 @@ void get_label(int label, char **buffer_label) case 0xbb: strlcpy(buffer, "Boot Wizard hidden", buffer_size); break; + case 0xbc: + strlcpy(buffer, "Acronis backup partition", buffer_size); + break; case 0xbe: strlcpy(buffer, "Solaris 8 boot partition", buffer_size); break; + case 0xbf: + strlcpy(buffer, "Solaris partition", buffer_size); + break; case 0xc0: strlcpy(buffer, "CTOS", buffer_size); - break; //case 0xc0: strlcpy(buffer, "REAL/32 secure small partition", buffer_size); break; //case 0xc0: strlcpy(buffer, "NTFT Partition", buffer_size); break; + break; case 0xc1: strlcpy(buffer, "DRDOS/secured (FAT-12)", buffer_size); break; case 0xc2: - strlcpy(buffer, "Reserved for DR-DOS 7+", buffer_size); + strlcpy(buffer, "Hidden Linux", buffer_size); break; + //strlcpy(buffer, "Reserved for DR-DOS 7+", buffer_size); break; - //case 0xc2: strlcpy(buffer, "Hidden Linux", buffer_size); break; case 0xc3: strlcpy(buffer, "Hidden Linux swap", buffer_size); break; @@ -487,21 +519,21 @@ void get_label(int label, char **buffer_label) break; case 0xc6: strlcpy(buffer, "DRDOS/secured (FAT-16, >= 32M)", buffer_size); - break; //case 0xc6: strlcpy(buffer, "Windows NT corrupted FAT16 volume/stripe set", buffer_size); break; + break; case 0xc7: strlcpy(buffer, "Windows NT corrupted NTFS volume/stripe set", buffer_size); - break; //case 0xc7: strlcpy(buffer, "Syrinx boot", buffer_size); break; + break; case 0xc8: - strlcpy(buffer, "(See also ID c2.)", buffer_size); + strlcpy(buffer, "Reserved for DR-DOS 8.0+", buffer_size); break; case 0xc9: - strlcpy(buffer, "(See also ID c2.)", buffer_size); + strlcpy(buffer, "Reserved for DR-DOS 8.0+", buffer_size); break; case 0xca: - strlcpy(buffer, "(See also ID c2.)", buffer_size); + strlcpy(buffer, "Reserved for DR-DOS 8.0+", buffer_size); break; case 0xcb: strlcpy(buffer, "reserved for DRDOS/secured (FAT32)", buffer_size); @@ -515,6 +547,9 @@ void get_label(int label, char **buffer_label) case 0xce: strlcpy(buffer, "reserved for DRDOS/secured (FAT16, LBA)", buffer_size); break; + case 0xcf: + strlcpy(buffer, "DR-DOS 7.04+ secured EXT DOS (LBA)", buffer_size); + break; case 0xd0: strlcpy(buffer, "REAL/32 secure big partition", buffer_size); break; @@ -541,9 +576,9 @@ void get_label(int label, char **buffer_label) strlcpy(buffer, "Digital Research CP/M, Concurrent CP/M, Concurrent DOS", buffer_size); - break; //case 0xdb: strlcpy(buffer, "CTOS (Convergent Technologies OS -Unisys)", buffer_size); break; //case 0xdb: strlcpy(buffer, "KDG Telemetry SCPU boot", buffer_size); break; + break; case 0xdd: strlcpy(buffer, "Hidden CTOS Memdump?", buffer_size); break; @@ -575,24 +610,30 @@ void get_label(int label, char **buffer_label) strlcpy(buffer, "Tandy DOS with logical sectored FAT (According to Powerquest.)", buffer_size); - break; //case 0xe5: strlcpy(buffer, "Reserved", buffer_size); break; + break; case 0xe6: - strlcpy(buffer, "Reserved", buffer_size); + strlcpy(buffer, "Storage Dimensions SpeedStor", buffer_size); + break; + case 0xe8: + strlcpy(buffer, "LUKS", buffer_size); break; case 0xeb: - strlcpy(buffer, "BFS (aka BeFS)", buffer_size); + strlcpy(buffer, "BeOS", buffer_size); + break; + case 0xec: + strlcpy(buffer, "SkyOS SkyFS", buffer_size); break; case 0xed: strlcpy(buffer, "Reserved for Matthias Paul's Sprytix", buffer_size); break; case 0xee: strlcpy(buffer, - "Indication that this legacy MBR is followed by an EFI header", + "GPT", buffer_size); break; case 0xef: - strlcpy(buffer, "Partition that contains an EFI file system", + strlcpy(buffer, "EFI file system", buffer_size); break; case 0xf0: @@ -613,8 +654,8 @@ void get_label(int label, char **buffer_label) break; case 0xf4: strlcpy(buffer, "SpeedStor large partition", buffer_size); - break; //case 0xf4: strlcpy(buffer, "Prologue single-volume partition", buffer_size); break; + break; case 0xf5: strlcpy(buffer, "Prologue multi-volume partition", buffer_size); break; @@ -623,6 +664,12 @@ void get_label(int label, char **buffer_label) "Reserved (Powerquest writes: Storage Dimensions SpeedStor. )", buffer_size); break; + case 0xf7: + strlcpy(buffer, "DDRdrive Solid State File System", buffer_size); + break; + case 0xf9: + strlcpy(buffer, "pCache", buffer_size); + break; case 0xfa: strlcpy(buffer, "Bochs", buffer_size); break; @@ -638,12 +685,12 @@ void get_label(int label, char **buffer_label) buffer_size); break; case 0xfe: - strlcpy(buffer, "SpeedStor > 1024 cyl.", buffer_size); - break; - //case 0xfe: strlcpy(buffer, "LANstep", buffer_size); break; + strlcpy(buffer, "LANstep", buffer_size); break; + //strlcpy(buffer, "SpeedStor > 1024 cyl.", buffer_size); //case 0xfe: strlcpy(buffer, "IBM PS/2 IML (Initial Microcode Load) partition, located at the end of the disk.", buffer_size); break; //case 0xfe: strlcpy(buffer, "Windows NT Disk Administrator hidden partition", buffer_size); break; //case 0xfe: strlcpy(buffer, "Linux Logical Volume Manager partition (old)", buffer_size); break; + break; case 0xff: strlcpy(buffer, "Xenix Bad Block Table ", buffer_size); break; diff --git a/com32/gpllib/zzjson/zzjson_create.c b/com32/gpllib/zzjson/zzjson_create.c new file mode 100644 index 00000000..7e6bd5bd --- /dev/null +++ b/com32/gpllib/zzjson/zzjson_create.c @@ -0,0 +1,240 @@ +/* JSON Create ZZJSON structures + * ZZJSON - Copyright (C) 2008 by Ivo van Poorten + * License: GNU Lesser General Public License version 2.1 + */ + +#include "zzjson.h" +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +#ifdef CONFIG_NO_ERROR_MESSAGES +#define ERROR(x...) +#else +#define ERROR(x...) config->error(config->ehandle, ##x) +#endif +#define MEMERROR() ERROR("out of memory") + +static ZZJSON *zzjson_create_templ(ZZJSON_CONFIG *config, ZZJSON_TYPE type) { + ZZJSON *zzjson = config->calloc(1, sizeof(ZZJSON)); + if (!zzjson) MEMERROR(); + else zzjson->type = type; + return zzjson; +} + +ZZJSON *zzjson_create_true(ZZJSON_CONFIG *config) { + return zzjson_create_templ(config, ZZJSON_TRUE); +} + +ZZJSON *zzjson_create_false(ZZJSON_CONFIG *config) { + return zzjson_create_templ(config, ZZJSON_FALSE); +} + +ZZJSON *zzjson_create_null(ZZJSON_CONFIG *config) { + return zzjson_create_templ(config, ZZJSON_NULL); +} + +ZZJSON *zzjson_create_number_d(ZZJSON_CONFIG *config, double d) { + ZZJSON *zzjson = zzjson_create_templ(config, ZZJSON_NUMBER_DOUBLE); + if (zzjson) + zzjson->value.number.val.dval = d; + return zzjson; +} + +ZZJSON *zzjson_create_number_i(ZZJSON_CONFIG *config, long long i) { + ZZJSON *zzjson = zzjson_create_templ(config, ZZJSON_NUMBER_NEGINT); + if (zzjson) { + zzjson->type = i<0LL ? ZZJSON_NUMBER_NEGINT : ZZJSON_NUMBER_POSINT; + zzjson->value.number.val.ival = llabs(i); + } + return zzjson; +} + +/* sdup mimics strdup, but avoids having another function pointer in config */ +static char *sdup(ZZJSON_CONFIG *config, char *s) { + size_t slen = strlen(s)+1; + char *scopy = config->malloc(slen); + + if (!scopy) MEMERROR(); + else memcpy(scopy, s, slen); + return scopy; +} + +ZZJSON *zzjson_create_string(ZZJSON_CONFIG *config, char *s) { + ZZJSON *zzjson = NULL; + char *scopy; + + if (!(scopy = sdup(config,s))) return zzjson; + + if ((zzjson = zzjson_create_templ(config, ZZJSON_STRING))) + zzjson->value.string.string = scopy; + else + config->free(scopy); + + return zzjson; +} + +ZZJSON *zzjson_create_array(ZZJSON_CONFIG *config, ...) { + ZZJSON *zzjson, *retval, *val; + va_list ap; + + if (!(zzjson = zzjson_create_templ(config, ZZJSON_ARRAY))) return zzjson; + retval = zzjson; + + va_start(ap, config); + val = va_arg(ap, ZZJSON *); + while (val) { + zzjson->value.array.val = val; + val = va_arg(ap, ZZJSON *); + + if (val) { + ZZJSON *next = zzjson_create_templ(config, ZZJSON_ARRAY); + if (!next) { + while (retval) { + next = retval->next; + config->free(retval); + retval = next; + } + break; + } + zzjson->next = next; + zzjson = next; + } + } + va_end(ap); + return retval; +} + +ZZJSON *zzjson_create_object(ZZJSON_CONFIG *config, ...) { + ZZJSON *zzjson, *retval, *val; + char *label, *labelcopy; + va_list ap; + + if (!(zzjson = zzjson_create_templ(config, ZZJSON_OBJECT))) return zzjson; + retval = zzjson; + + va_start(ap, config); + label = va_arg(ap, char *); + while (label) { + val = va_arg(ap, ZZJSON *); + labelcopy = sdup(config, label); + + if (!labelcopy) { + zzjson_free(config, retval); + retval = NULL; + break; + } + + zzjson->value.object.label = labelcopy; + zzjson->value.object.val = val; + + label = va_arg(ap, char *); + + if (label) { + ZZJSON *next = zzjson_create_templ(config, ZZJSON_OBJECT); + if (!next) { + while (retval) { + next = retval->next; + config->free(retval->value.object.label); + config->free(retval); + retval = next; + } + break; + } + zzjson->next = next; + zzjson = next; + } + } + va_end(ap); + return retval; +} + +ZZJSON *zzjson_array_prepend(ZZJSON_CONFIG *config, ZZJSON *array, + ZZJSON *val) { + ZZJSON *zzjson; + + if (!array->value.array.val) { /* empty array */ + array->value.array.val = val; + return array; + } + + zzjson = zzjson_create_templ(config, ZZJSON_ARRAY); + if (zzjson) { + zzjson->value.array.val = val; + zzjson->next = array; + } + return zzjson; +} + +ZZJSON *zzjson_array_append(ZZJSON_CONFIG *config, ZZJSON *array, + ZZJSON *val) { + ZZJSON *retval = array, *zzjson; + + if (!array->value.array.val) { /* empty array */ + array->value.array.val = val; + return array; + } + + zzjson = zzjson_create_templ(config, ZZJSON_ARRAY); + if (!zzjson) return NULL; + + while (array->next) array = array->next; + + zzjson->value.array.val = val; + array->next = zzjson; + + return retval; +} + +ZZJSON *zzjson_object_prepend(ZZJSON_CONFIG *config, ZZJSON *object, + char *label, ZZJSON *val) { + ZZJSON *zzjson = NULL; + char *labelcopy = sdup(config, label); + + if (!labelcopy) return zzjson; + + if (!object->value.object.label) { /* empty object */ + object->value.object.label = labelcopy; + object->value.object.val = val; + return object; + } + + zzjson = zzjson_create_templ(config, ZZJSON_OBJECT); + if (zzjson) { + zzjson->value.object.label = labelcopy; + zzjson->value.object.val = val; + zzjson->next = object; + } else { + config->free(labelcopy); + } + return zzjson; +} + +ZZJSON *zzjson_object_append(ZZJSON_CONFIG *config, ZZJSON *object, + char *label, ZZJSON *val) { + ZZJSON *retval = object, *zzjson = NULL; + char *labelcopy = sdup(config, label); + + if (!labelcopy) return zzjson; + + if (!object->value.object.label) { /* empty object */ + object->value.object.label = labelcopy; + object->value.object.val = val; + return object; + } + + zzjson = zzjson_create_templ(config, ZZJSON_OBJECT); + if (!zzjson) { + config->free(labelcopy); + return NULL; + } + + while (object->next) object = object->next; + + zzjson->value.object.label = labelcopy; + zzjson->value.object.val = val; + object->next = zzjson; + + return retval; +} + diff --git a/com32/gpllib/zzjson/zzjson_free.c b/com32/gpllib/zzjson/zzjson_free.c new file mode 100644 index 00000000..01dfd242 --- /dev/null +++ b/com32/gpllib/zzjson/zzjson_free.c @@ -0,0 +1,29 @@ +/* JSON free + * ZZJSON - Copyright (C) 2008 by Ivo van Poorten + * License: GNU Lesser General Public License version 2.1 + */ + +#include "zzjson.h" + +void zzjson_free(ZZJSON_CONFIG *config, ZZJSON *zzjson) { + while (zzjson) { + ZZJSON *next; + switch(zzjson->type) { + case ZZJSON_OBJECT: + config->free(zzjson->value.object.label); + zzjson_free(config, zzjson->value.object.val); + break; + case ZZJSON_ARRAY: + zzjson_free(config, zzjson->value.array.val); + break; + case ZZJSON_STRING: + config->free(zzjson->value.string.string); + break; + default: + break; + } + next = zzjson->next; + config->free(zzjson); + zzjson = next; + } +} diff --git a/com32/gpllib/zzjson/zzjson_parse.c b/com32/gpllib/zzjson/zzjson_parse.c new file mode 100644 index 00000000..ecb6f61e --- /dev/null +++ b/com32/gpllib/zzjson/zzjson_parse.c @@ -0,0 +1,490 @@ +/* JSON Parser + * ZZJSON - Copyright (C) 2008-2009 by Ivo van Poorten + * License: GNU Lesser General Public License version 2.1 + */ + +#include "zzjson.h" +#include <ctype.h> +#include <string.h> +#include <math.h> +#include <stdio.h> + +#define GETC() config->getchar(config->ihandle) +#define UNGETC(c) config->ungetchar(c, config->ihandle) +#define SKIPWS() skipws(config) +#ifdef CONFIG_NO_ERROR_MESSAGES +#define ERROR(x...) +#else +#define ERROR(x...) config->error(config->ehandle, ##x) +#endif +#define MEMERROR() ERROR("out of memory") + +#define ALLOW_EXTRA_COMMA (config->strictness & ZZJSON_ALLOW_EXTRA_COMMA) +#define ALLOW_ILLEGAL_ESCAPE (config->strictness & ZZJSON_ALLOW_ILLEGAL_ESCAPE) +#define ALLOW_CONTROL_CHARS (config->strictness & ZZJSON_ALLOW_CONTROL_CHARS) +#define ALLOW_GARBAGE_AT_END (config->strictness & ZZJSON_ALLOW_GARBAGE_AT_END) +#define ALLOW_COMMENTS (config->strictness & ZZJSON_ALLOW_COMMENTS) + +static ZZJSON *parse_array(ZZJSON_CONFIG *config); +static ZZJSON *parse_object(ZZJSON_CONFIG *config); + +static void skipws(ZZJSON_CONFIG *config) { + int d, c = GETC(); +morews: + while (isspace(c)) c = GETC(); + if (!ALLOW_COMMENTS) goto endws; + if (c != '/') goto endws; + d = GETC(); + if (d != '*') goto endws; /* pushing back c will generate a parse error */ + c = GETC(); +morecomments: + while (c != '*') { + if (c == EOF) goto endws; + c = GETC(); + } + c = GETC(); + if (c != '/') goto morecomments; + c = GETC(); + if (isspace(c) || c == '/') goto morews; +endws: + UNGETC(c); +} + +static char *parse_string(ZZJSON_CONFIG *config) { + unsigned int len = 16, pos = 0; + int c; + char *str = NULL; + + SKIPWS(); + c = GETC(); + if (c != '"') { + ERROR("string: expected \" at the start"); + return NULL; + } + + str = config->malloc(len); + if (!str) { + MEMERROR(); + return NULL; + } + c = GETC(); + while (c > 0 && c != '"') { + if (!ALLOW_CONTROL_CHARS && c >= 0 && c <= 31) { + ERROR("string: control characters not allowed"); + goto errout; + } + if (c == '\\') { + c = GETC(); + switch (c) { + case 'b': c = '\b'; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'u': { + UNGETC(c); /* ignore \uHHHH, copy verbatim */ + c = '\\'; + break; + } + case '\\': case '/': case '"': + break; + default: + if (!ALLOW_ILLEGAL_ESCAPE) { + ERROR("string: illegal escape character"); + goto errout; + } + } + } + str[pos++] = c; + if (pos == len-1) { + void *tmp = str; + len *= 2; + str = config->realloc(str, len); + if (!str) { + MEMERROR(); + str = tmp; + goto errout; + } + } + c = GETC(); + } + if (c != '"') { + ERROR("string: expected \" at the end"); + goto errout; + } + str[pos] = 0; + return str; + +errout: + config->free(str); + return NULL; +} + +static ZZJSON *parse_string2(ZZJSON_CONFIG *config) { + ZZJSON *zzjson = NULL; + char *str; + + str = parse_string(config); + if (str) { + zzjson = config->calloc(1, sizeof(ZZJSON)); + if (!zzjson) { + MEMERROR(); + config->free(str); + return NULL; + } + zzjson->type = ZZJSON_STRING; + zzjson->value.string.string = str; + } + return zzjson; +} + +static ZZJSON *parse_number(ZZJSON_CONFIG *config) { + ZZJSON *zzjson; + unsigned long long ival = 0, expo = 0; + double dval = 0.0, frac = 0.0, fracshft = 10.0; + int c, dbl = 0, sign = 1, signexpo = 1; + + SKIPWS(); + c = GETC(); + if (c == '-') { + sign = -1; + c = GETC(); + } + if (c == '0') { + c = GETC(); + goto skip; + } + + if (!isdigit(c)) { + ERROR("number: digit expected"); + return NULL; + } + + while (isdigit(c)) { + ival *= 10; + ival += c - '0'; + c = GETC(); + } + +skip: + if (c != '.') goto skipfrac; + + dbl = 1; + + c = GETC(); + if (!isdigit(c)) { + ERROR("number: digit expected"); + return NULL; + } + + while (isdigit(c)) { + frac += (double)(c - '0') / fracshft; + fracshft *= 10.0; + c = GETC(); + } + +skipfrac: + if (c != 'e' && c != 'E') goto skipexpo; + + dbl = 1; + + c = GETC(); + if (c == '+') + c = GETC(); + else if (c == '-') { + signexpo = -1; + c = GETC(); + } + + if (!isdigit(c)) { + ERROR("number: digit expected"); + return NULL; + } + + while (isdigit(c)) { + expo *= 10; + expo += c - '0'; + c = GETC(); + } + +skipexpo: + UNGETC(c); + + if (dbl) { + dval = sign * (long long) ival; + dval += sign * frac; + dval *= pow(10.0, (double) signexpo * expo); + } + + zzjson = config->calloc(1, sizeof(ZZJSON)); + if (!zzjson) { + MEMERROR(); + return NULL; + } + if (dbl) { + zzjson->type = ZZJSON_NUMBER_DOUBLE; + zzjson->value.number.val.dval = dval; + } else { + zzjson->type = sign < 0 ? ZZJSON_NUMBER_NEGINT : ZZJSON_NUMBER_POSINT; + zzjson->value.number.val.ival = ival; + } + + return zzjson; +} + +static ZZJSON *parse_literal(ZZJSON_CONFIG *config, char *s, ZZJSON_TYPE t) { + char b[strlen(s)+1]; + unsigned int i; + + for (i=0; i<strlen(s); i++) b[i] = GETC(); + b[i] = 0; + + if (!strcmp(b,s)) { + ZZJSON *zzjson; + zzjson = config->calloc(1, sizeof(ZZJSON)); + if (!zzjson) { + MEMERROR(); + return NULL; + } + zzjson->type = t; + return zzjson; + } + ERROR("literal: expected %s", s); + return NULL; +} + +static ZZJSON *parse_true(ZZJSON_CONFIG *config) { + return parse_literal(config, (char *)"true", ZZJSON_TRUE); +} + +static ZZJSON *parse_false(ZZJSON_CONFIG *config) { + return parse_literal(config, (char *)"false", ZZJSON_FALSE); +} + +static ZZJSON *parse_null(ZZJSON_CONFIG *config) { + return parse_literal(config, (char *)"null", ZZJSON_NULL); +} + +static ZZJSON *parse_value(ZZJSON_CONFIG *config) { + ZZJSON *retval = NULL; + int c; + + SKIPWS(); + c = GETC(); + UNGETC(c); + switch (c) { + case '"': retval = parse_string2(config); break; + case '0': case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': case '-': + retval = parse_number(config); break; + case '{': retval = parse_object(config); break; + case '[': retval = parse_array(config); break; + case 't': retval = parse_true(config); break; + case 'f': retval = parse_false(config); break; + case 'n': retval = parse_null(config); break; + } + + if (!retval) { + ERROR("value: invalid value"); + return retval; + } + + return retval; +} + +static ZZJSON *parse_array(ZZJSON_CONFIG *config) { + ZZJSON *retval = NULL, **next = &retval; + int c; + + SKIPWS(); + c = GETC(); + if (c != '[') { + ERROR("array: expected '['"); + return NULL; + } + + SKIPWS(); + c = GETC(); + while (c > 0 && c != ']') { + ZZJSON *zzjson = NULL, *val = NULL; + + UNGETC(c); + + SKIPWS(); + val = parse_value(config); + if (!val) { + ERROR("array: value expected"); + goto errout; + } + + SKIPWS(); + c = GETC(); + if (c != ',' && c != ']') { + ERROR("array: expected ',' or ']'"); +errout_with_val: + zzjson_free(config, val); + goto errout; + } + if (c == ',') { + SKIPWS(); + c = GETC(); + if (c == ']' && !ALLOW_EXTRA_COMMA) { + ERROR("array: expected value after ','"); + goto errout_with_val; + } + } + UNGETC(c); + + zzjson = config->calloc(1, sizeof(ZZJSON)); + if (!zzjson) { + MEMERROR(); + zzjson_free(config, val); + goto errout_with_val; + } + zzjson->type = ZZJSON_ARRAY; + zzjson->value.array.val = val; + *next = zzjson; + next = &zzjson->next; + + c = GETC(); + } + + if (c != ']') { + ERROR("array: expected ']'"); + goto errout; + } + + if (!retval) { /* empty array, [ ] */ + retval = config->calloc(1, sizeof(ZZJSON)); + if (!retval) { + MEMERROR(); + return NULL; + } + retval->type = ZZJSON_ARRAY; + } + + return retval; + +errout: + zzjson_free(config, retval); + return NULL; +} + +static ZZJSON *parse_object(ZZJSON_CONFIG *config) { + ZZJSON *retval = NULL; + int c; + ZZJSON **next = &retval; + + SKIPWS(); + c = GETC(); + if (c != '{') { + ERROR("object: expected '{'"); + return NULL; + } + + SKIPWS(); + c = GETC(); + while (c > 0 && c != '}') { + ZZJSON *zzjson = NULL, *val = NULL; + char *str; + + UNGETC(c); + + str = parse_string(config); + if (!str) { + ERROR("object: expected string"); +errout_with_str: + config->free(str); + goto errout; + } + + SKIPWS(); + c = GETC(); + if (c != ':') { + ERROR("object: expected ':'"); + goto errout_with_str; + } + + SKIPWS(); + val = parse_value(config); + if (!val) { + ERROR("object: value expected"); + goto errout_with_str; + } + + SKIPWS(); + c = GETC(); + if (c != ',' && c != '}') { + ERROR("object: expected ',' or '}'"); +errout_with_str_and_val: + zzjson_free(config, val); + goto errout_with_str; + } + if (c == ',') { + SKIPWS(); + c = GETC(); + if (c == '}' && !ALLOW_EXTRA_COMMA) { + ERROR("object: expected pair after ','"); + goto errout_with_str_and_val; + } + } + UNGETC(c); + + zzjson = config->calloc(1, sizeof(ZZJSON)); + if (!zzjson) { + MEMERROR(); + goto errout_with_str_and_val; + } + zzjson->type = ZZJSON_OBJECT; + zzjson->value.object.label = str; + zzjson->value.object.val = val; + *next = zzjson; + next = &zzjson->next; + + c = GETC(); + } + + if (c != '}') { + ERROR("object: expected '}'"); + goto errout; + } + + if (!retval) { /* empty object, { } */ + retval = config->calloc(1, sizeof(ZZJSON)); + if (!retval) { + MEMERROR(); + return NULL; + } + retval->type = ZZJSON_OBJECT; + } + + return retval; + +errout: + zzjson_free(config, retval); + return NULL; +} + +ZZJSON *zzjson_parse(ZZJSON_CONFIG *config) { + ZZJSON *retval; + int c; + + SKIPWS(); + c = GETC(); + UNGETC(c); + if (c == '[') retval = parse_array(config); + else if (c == '{') retval = parse_object(config); + else { ERROR("expected '[' or '{'"); return NULL; } + + if (!retval) return NULL; + + SKIPWS(); + c = GETC(); + if (c >= 0 && !ALLOW_GARBAGE_AT_END) { + ERROR("parse: garbage at end of file"); + zzjson_free(config, retval); + return NULL; + } + + return retval; +} diff --git a/com32/gpllib/zzjson/zzjson_print.c b/com32/gpllib/zzjson/zzjson_print.c new file mode 100644 index 00000000..a59b3b09 --- /dev/null +++ b/com32/gpllib/zzjson/zzjson_print.c @@ -0,0 +1,110 @@ +/* JSON Printer + * ZZJSON - Copyright (C) 2008 by Ivo van Poorten + * License: GNU Lesser General Public License version 2.1 + */ + +#include "zzjson.h" + +#define PRINT(fmt...) if (config->print(config->ohandle, ##fmt) < 0) return -1; +//#define PUTC(c) if (config->putchar(c, config->ohandle) < 0) return -1; +#define PUTC(c) PRINT("%c",c) +#define INC 4 + +static int print_string(ZZJSON_CONFIG *config, char *s) { + int c, bs; + if (!s) return 0; + while ((c = *s++)) { + bs = 1; + switch (c) { +// case '/': // useless escape of forward slash + case '\\': + if (*s == 'u') bs = 0; // copy \uHHHH verbatim + break; + case '"': break; + case '\b': c = 'b'; break; + case '\f': c = 'f'; break; + case '\n': c = 'n'; break; + case '\r': c = 'r'; break; + case '\t': c = 't'; break; + default: bs = 0; break; + } + if (bs) PUTC('\\'); + PUTC(c); + } + return 0; +} + +static int zzjson_print2(ZZJSON_CONFIG *config, ZZJSON *zzjson, + unsigned int indent, unsigned int objval) { + char c = 0, d = 0; + if (!zzjson) return -1; + + switch(zzjson->type) { + case ZZJSON_OBJECT: c = '{'; d = '}'; break; + case ZZJSON_ARRAY: c = '['; d = ']'; break; + default: break; + } + + if (c) PRINT("%s%*s%c", indent ? "\n" : "", indent, "", c); + + while (zzjson) { + switch(zzjson->type) { + case ZZJSON_OBJECT: + if (zzjson->value.object.val) { + PRINT("\n%*s\"", indent+INC, ""); + if (print_string(config, zzjson->value.object.label) < 0) + return -1; + PRINT("\" :"); + if (zzjson_print2(config, zzjson->value.object.val, + indent+INC, 1) < 0) return -1; + } + break; + case ZZJSON_ARRAY: + if (zzjson->value.array.val) + if (zzjson_print2(config, zzjson->value.array.val, + indent+INC, 0) < 0) return -1; + break; + case ZZJSON_STRING: + PRINT(objval ? " \"" : "\n%*s\"", indent, ""); + if (print_string(config, zzjson->value.string.string)<0) return -1; + PUTC('"'); + break; + case ZZJSON_FALSE: + PRINT(objval ? " false" : "\n%*sfalse", indent, ""); + break; + case ZZJSON_NULL: + PRINT(objval ? " null" : "\n%*snull", indent, ""); + break; + case ZZJSON_TRUE: + PRINT(objval ? " true" : "\n%*strue", indent, ""); + break; + case ZZJSON_NUMBER_NEGINT: + case ZZJSON_NUMBER_POSINT: + case ZZJSON_NUMBER_DOUBLE: + PRINT(objval ? " " : "\n%*s", indent, ""); + if (zzjson->type == ZZJSON_NUMBER_DOUBLE) { + PRINT("%16.16e", zzjson->value.number.val.dval); + } else { + if (zzjson->type == ZZJSON_NUMBER_NEGINT) PUTC('-'); + PRINT("%llu", zzjson->value.number.val.ival); + } + default: + break; + } + zzjson = zzjson->next; + if (zzjson) PUTC(','); + } + + if (d) PRINT("\n%*s%c", indent, "", d); + + return 0; +} + +int zzjson_print(ZZJSON_CONFIG *config, ZZJSON *zzjson) { + int retval = zzjson_print2(config, zzjson, 0, 0); +// if (retval >= 0) retval = config->putchar('\n', config->ohandle); +#ifndef CONFIG_NO_ERROR_MESSAGES + if (retval < 0) config->error(config->ehandle, "print: unable to print"); +#endif + return retval; +} diff --git a/com32/gpllib/zzjson/zzjson_query.c b/com32/gpllib/zzjson/zzjson_query.c new file mode 100644 index 00000000..35ba7b79 --- /dev/null +++ b/com32/gpllib/zzjson/zzjson_query.c @@ -0,0 +1,63 @@ +/* JSON query + * ZZJSON - Copyright (C) 2008 by Ivo van Poorten + * License: GNU Lesser General Public License version 2.1 + */ + +#include "zzjson.h" +#include <string.h> +#include <stdarg.h> + +ZZJSON *zzjson_object_find_label(ZZJSON *zzjson, char *label) { + if (zzjson->type != ZZJSON_OBJECT) return NULL; + + while (zzjson) { + char *string = zzjson->value.object.label; + + if (zzjson->type != ZZJSON_OBJECT) return NULL; + if (!string) return NULL; + + if (!strcmp(string, label)) + return zzjson->value.object.val; + zzjson = zzjson->next; + } + return NULL; +} + +ZZJSON *zzjson_object_find_labels(ZZJSON *zzjson, ...) { + va_list ap; + char *lbl; + + va_start(ap, zzjson); + lbl = va_arg(ap, char *); + while (lbl) { + zzjson = zzjson_object_find_label(zzjson, lbl); + if (!zzjson) break; + lbl = va_arg(ap, char *); + } + va_end(ap); + + return zzjson; +} + +unsigned int zzjson_object_count(ZZJSON *zzjson) { + unsigned int count = 1; + + if (zzjson->type != ZZJSON_OBJECT) return 0; + if (!zzjson->value.object.label) return 0; /* empty { } */ + + while ((zzjson = zzjson->next)) count++; + + return count; +} + +unsigned int zzjson_array_count(ZZJSON *zzjson) { + unsigned int count = 1; + + if (zzjson->type != ZZJSON_ARRAY) return 0; + if (!zzjson->value.array.val) return 0; /* empty [ ] */ + + while ((zzjson = zzjson->next)) count++; + + return count; +} + diff --git a/com32/hdt/.gitignore b/com32/hdt/.gitignore index 98927943..82d5b472 100644 --- a/com32/hdt/.gitignore +++ b/com32/hdt/.gitignore @@ -5,3 +5,4 @@ floppy/syslinux.cfg *.iso iso/ *gz +hdt*checksums diff --git a/com32/hdt/Makefile b/com32/hdt/Makefile index 40ea3ac4..add640a7 100644 --- a/com32/hdt/Makefile +++ b/com32/hdt/Makefile @@ -16,11 +16,11 @@ ## topdir = ../.. -include ../MCONFIG +MAKEDIR = $(topdir)/mk +include $(MAKEDIR)/com32.mk -LIBS = ../cmenu/libmenu/libmenu.a ../libutil/libutil_com.a \ - ../lib/libcom32.a $(LIBGCC) -CFLAGS += -I$(com32)/cmenu/libmenu +LIBS = ../cmenu/libmenu/libmenu.a ../libupload/libcom32upload.a +CFLAGS += -I$(com32)/cmenu/libmenu -I$(com32) MODULES = hdt.c32 TESTFILES = @@ -28,7 +28,8 @@ TESTFILES = OBJS = $(patsubst %.c,%.o,$(wildcard *.c)) VERSION = $(shell $(SED) -n 's/\#define VERSION \"\(.*\)\"/\1/p' hdt.h) CODENAME = $(shell $(SED) -n 's/\#define CODENAME \"\(.*\)\"/\1/p' hdt.h) -VERSION_C32 = $(shell echo $(VERSION) | $(SED) -e 's/-/_/g' | $(SED) -e 's/\./_/g') +NODASH_VERSION = $(shell echo $(VERSION) | $(SED) -e 's/-/_/g' | $(SED) -e 's/\./_/g') +SUM_FILE = hdt-$(VERSION).checksums MEMTEST_URL = http://memtest.org/download/4.20/memtest86+-4.20.bin MEMTEST = memtest.bin @@ -44,6 +45,7 @@ FLOPPY_DIR ?= floppy PCI_IDS_FILE ?= $(PWD)/$(FLOPPY_DIR)/pci.ids GZ_PCI_IDS_FILE ?= $(PCI_IDS_FILE).gz MENU_COM32 ?= $(com32)/menu/menu.c32 +CHAIN_COM32 ?= $(com32)/chain/chain.c32 ART_DIR ?= art/ QEMU ?= qemu-kvm @@ -55,11 +57,11 @@ hdt.elf : $(OBJS) $(LIBS) $(C_LIBS) memtest: -[ ! -f $(FLOPPY_DIR)/$(MEMTEST) ] && $(WGET) $(MEMTEST_URL) -O $(FLOPPY_DIR)/$(MEMTEST) -hdt.img: hdt.c32 $(FLOPPY_DIR)/hdt.cfg $(FLOPPY_DIR)/mtools.conf $(topdir)/mtools/syslinux $(MENU_COM32) memtest +hdt.img: hdt.c32 $(FLOPPY_DIR)/hdt.cfg $(FLOPPY_DIR)/mtools.conf $(topdir)/mtools/syslinux $(MENU_COM32) memtest $(CHAIN_COM32) rm -f hdt*.img $(SED) -e 's/%VERSION%/$(VERSION)/g' $(FLOPPY_DIR)/hdt.cfg |\ $(SED) -e 's/%CODENAME%/$(CODENAME)/g' > $(FLOPPY_DIR)/syslinux.cfg - MTOOLSRC=$(PWD)/$(FLOPPY_DIR)/mtools.conf $(MFORMAT) -v HDT_$(VERSION) -f 1440 -C a: + MTOOLSRC=$(PWD)/$(FLOPPY_DIR)/mtools.conf $(MFORMAT) -v HDT_$(NODASH_VERSION) -f 1440 -C a: $(topdir)/mtools/syslinux hdt.img -[ ! -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) @@ -67,10 +69,13 @@ hdt.img: hdt.c32 $(FLOPPY_DIR)/hdt.cfg $(FLOPPY_DIR)/mtools.conf $(topdir)/mtool -[ -f $(MODULES_PCIMAP_FILE) ] && cat $(MODULES_PCIMAP_FILE) | $(GZIPPROG) - -f | MTOOLSRC=$(PWD)/$(FLOPPY_DIR)/mtools.conf $(MCOPY) - a:modules.pcimap MTOOLSRC=$(PWD)/$(FLOPPY_DIR)/mtools.conf $(MCOPY) hdt.c32 a: MTOOLSRC=$(PWD)/$(FLOPPY_DIR)/mtools.conf $(MCOPY) $(MENU_COM32) a: + MTOOLSRC=$(PWD)/$(FLOPPY_DIR)/mtools.conf $(MCOPY) $(CHAIN_COM32) a: @ [ -f $(GZ_PCI_IDS_FILE) ] && MTOOLSRC=$(PWD)/$(FLOPPY_DIR)/mtools.conf $(MCOPY) $(GZ_PCI_IDS_FILE) a:pci.ids || printf "\nThe $(GZ_PCI_IDS_FILE) file is missing and can be downloaded from http://pciids.sourceforge.net and gzipped in\nthe ./com32/hdt/$(FLOPPY_DIR) directory of the extracted Syslinux source.\n\n" 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 @@ -89,7 +94,10 @@ hdt.iso: hdt.c32 $(topdir)/core/isolinux.bin $(FLOPPY_DIR)/hdt.cfg memtest cp hdt.c32 $(ISO_DIR)/$(ISOLINUX_DIR) cp $(FLOPPY_DIR)/$(MEMTEST) $(ISO_DIR)/$(ISOLINUX_DIR) 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)\ @@ -106,8 +114,18 @@ hdt.iso: hdt.c32 $(topdir)/core/isolinux.bin $(FLOPPY_DIR)/hdt.cfg memtest mv hdt.iso hdt-$(VERSION).iso ln -sf hdt-$(VERSION).iso hdt.iso -release: spotless hdt.c32 hdt.img hdt.img.gz hdt.iso - mv hdt.c32 hdt_$(VERSION_C32).c32 +hdt-hybrid.iso: hdt.iso ../../utils/isohybrid + cp hdt-$(VERSION).iso hdt-hybrid-$(VERSION).iso + ../../utils/isohybrid --partok hdt-hybrid-$(VERSION).iso + ln -sf hdt-hybrid-$(VERSION).iso hdt-hybrid.iso + +release: spotless hdt.c32 hdt.img hdt.img.gz hdt.iso hdt-hybrid.iso + mv hdt.c32 hdt_$(NODASH_VERSION).c32 + md5sum hdt_$(NODASH_VERSION).c32 >$(SUM_FILE) + md5sum hdt-$(VERSION).iso >>$(SUM_FILE) + md5sum hdt-hybrid-$(VERSION).iso >>$(SUM_FILE) + md5sum hdt-$(VERSION).img >>$(SUM_FILE) + md5sum hdt-$(VERSION).img.gz >>$(SUM_FILE) test: hdt.img $(QEMU) -fda hdt.img @@ -123,6 +141,7 @@ spotless: clean rm -rf $(ISO_DIR) rm -rf $(FLOPPY_DIR)/$(MEMTEST) rm -rf $(FLOPPY_DIR)/pci.ids* + rm -rf hdt-*checksums rm -f *~ \#* install: 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 f72a2134..524c4e06 100644 --- a/com32/hdt/floppy/hdt.cfg +++ b/com32/hdt/floppy/hdt.cfg @@ -77,6 +77,34 @@ ENDTEXT COM32 hdt.c32 APPEND modules_pcimap=modules.pcimap modules_alias=modules.alias pciids=pci.ids verbose nomenu +LABEL dump +MENU LABEL Dump hardware config to TFTP server +TEXT HELP + Starts HDT using the Command Line Interface (CLI) and run 'dump' + VESA mode is enabled +ENDTEXT +COM32 hdt.c32 +APPEND modules_pcimap=modules.pcimap modules_alias=modules.alias pciids=pci.ids quiet vesa nomenu auto='dump' + +LABEL postexec +MENU LABEL Dump memory info, sleep 5 and start memtest entry +TEXT HELP + Starts HDT using the Command Line Interface (CLI), show an item, say a message reboot and start memtest + 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`;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 LABEL memtest diff --git a/com32/hdt/hdt-cli-acpi.c b/com32/hdt/hdt-cli-acpi.c index 1b608c26..55b0c3c7 100644 --- a/com32/hdt/hdt-cli-acpi.c +++ b/com32/hdt/hdt-cli-acpi.c @@ -37,7 +37,7 @@ /* Print ACPI's table header in a defined formating */ static void show_header(void *address, s_acpi_description_header * h) { - more_printf("%-4s v%03x %-6s %-7s 0x%08x %-4s 0x%08x @ 0x%p\n", + more_printf("%-4s v%03x %-6s %-8s 0x%08x %-7s 0x%08x @ 0x%p\n", h->signature, h->revision, h->oem_id, h->oem_table_id, h->oem_revision, h->creator_id, h->creator_revision, address) } @@ -158,25 +158,6 @@ static void show_local_apic(s_madt * madt) } } -/* M1PS flags have to be interpreted as strings */ -static char *flags_to_string(char *buffer, uint16_t flags) -{ - memset(buffer, 0, sizeof(buffer)); - strcpy(buffer, "default"); - if ((flags & POLARITY_ACTIVE_HIGH) == POLARITY_ACTIVE_HIGH) - strcpy(buffer, "high"); - else if ((flags & POLARITY_ACTIVE_LOW) == POLARITY_ACTIVE_LOW) - strcpy(buffer, "low"); - if ((flags & TRIGGER_EDGE) == TRIGGER_EDGE) - strncat(buffer, " edge", 5); - else if ((flags & TRIGGER_LEVEL) == TRIGGER_LEVEL) - strncat(buffer, " level", 6); - else - strncat(buffer, " default", 8); - - return buffer; -} - /* Display the local apic NMI configuration */ static void show_local_apic_nmi(s_madt * madt) { @@ -225,7 +206,7 @@ static void show_io_apic(s_madt * madt) break; } - more_printf("IO_APIC[%d] : apic_id[0x%02x] adress[0x%08x] %s\n", + more_printf("IO_APIC[%d] : apic_id[0x%02x] address[0x%08x] %s\n", i, sio->io_apic_id, sio->io_apic_address, buffer); } } @@ -286,10 +267,12 @@ struct cli_callback_descr list_acpi_show_modules[] = { { .name = "apic", .exec = show_acpi_apic, + .nomodule = false, }, { .name = NULL, .exec = NULL, + .nomodule = false, }, }; diff --git a/com32/hdt/hdt-cli-disk.c b/com32/hdt/hdt-cli-disk.c index 24fce676..10c95d7d 100644 --- a/com32/hdt/hdt-cli-disk.c +++ b/com32/hdt/hdt-cli-disk.c @@ -225,14 +225,17 @@ struct cli_callback_descr list_disk_show_modules[] = { { .name = "disks", .exec = main_show_disks, + .nomodule = false, }, { .name = "disk", .exec = main_show_disk, + .nomodule = false, }, { .name = NULL, .exec = NULL, + .nomodule = false, }, }; diff --git a/com32/hdt/hdt-cli-dmi.c b/com32/hdt/hdt-cli-dmi.c index 45cbb240..02bea0f7 100644 --- a/com32/hdt/hdt-cli-dmi.c +++ b/com32/hdt/hdt-cli-dmi.c @@ -617,62 +617,77 @@ struct cli_callback_descr list_dmi_show_modules[] = { { .name = CLI_DMI_BASE_BOARD, .exec = show_dmi_base_board, + .nomodule = false, }, { .name = CLI_DMI_BIOS, .exec = show_dmi_bios, + .nomodule = false, }, { .name = CLI_DMI_BATTERY, .exec = show_dmi_battery, + .nomodule = false, }, { .name = CLI_DMI_CHASSIS, .exec = show_dmi_chassis, + .nomodule = false, }, { .name = CLI_DMI_MEMORY, .exec = show_dmi_memory_modules, + .nomodule = false, }, { .name = CLI_DMI_MEMORY_BANK, .exec = show_dmi_memory_bank, + .nomodule = false, }, { .name = "module", .exec = show_dmi_memory_module, + .nomodule = false, }, { .name = CLI_DMI_PROCESSOR, .exec = show_dmi_cpu, + .nomodule = false, }, { .name = CLI_DMI_SYSTEM, .exec = show_dmi_system, + .nomodule = false, }, { .name = CLI_DMI_OEM, .exec = show_dmi_oem_strings, + .nomodule = false, }, { .name = CLI_DMI_SECURITY, .exec = show_dmi_hardware_security, + .nomodule = false, }, { .name = CLI_DMI_IPMI, .exec = show_dmi_ipmi, + .nomodule = false, }, { .name = CLI_DMI_CACHE, .exec = show_dmi_cache, + .nomodule = false, }, { .name = CLI_DMI_LIST, .exec = show_dmi_modules, + .nomodule = false, }, { .name = NULL, .exec = NULL, + .nomodule = false, }, }; diff --git a/com32/hdt/hdt-cli-hdt.c b/com32/hdt/hdt-cli-hdt.c index 65068232..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); @@ -250,97 +250,209 @@ static void do_reboot(int argc __unused, char **argv __unused, syslinux_reboot(1); } +/** + * do_dump - dump info + **/ +static void do_dump(int argc __unused, char **argv __unused, + struct s_hardware *hardware) +{ + dump(hardware); +} + +/** + * 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 , + struct s_hardware *hardware) +{ + (void) hardware; + if (argc == 0) return; + + char text_to_say[255]={0}; + int arg=0; +#if DEBUG + for (int i=0; i<argc;i++) dprintf("SAY: arg[%d]={%s}\n",i,argv[i]); +#endif + char *argument = strchr(argv[arg],'`'); + if ( argument != NULL) { + argument++; + strcat(text_to_say, argument); + + while ((strchr(argument, '`') == NULL) && (arg+1<argc)) { + arg++; + argument = (char *)argv[arg]; + strcat(text_to_say, " "); + strcat(text_to_say, argument); + } + + /* Removing last ` if any */ + char *last_quote = strrchr(text_to_say,'`'); + if ( last_quote != NULL ) { + *last_quote='\0'; + dprintf("SAY CMD = [%s]\n",text_to_say); + } + + more_printf("%s\n",text_to_say); + } +} + /* Default hdt mode */ struct cli_callback_descr list_hdt_default_modules[] = { { .name = CLI_CLEAR, .exec = cli_clear_screen, + .nomodule = false, }, { .name = CLI_EXIT, .exec = do_exit, + .nomodule = false, }, { .name = CLI_HELP, .exec = show_cli_help, + .nomodule = false, }, { .name = CLI_MENU, .exec = goto_menu, + .nomodule = false, }, { .name = CLI_REBOOT, .exec = do_reboot, + .nomodule = false, }, { .name = CLI_HISTORY, .exec = print_history, + .nomodule = false, + }, + { + .name = CLI_DUMP, + .exec = do_dump, + .nomodule = false, + }, + { + .name = CLI_SAY, + .exec = do_say, + .nomodule = true, + }, + { + .name = CLI_DISPLAY, + .exec = do_display, + .nomodule = true, + }, + { + .name = CLI_SLEEP, + .exec = do_sleep, + .nomodule = true, }, { .name = NULL, - .exec = NULL}, + .exec = NULL, + .nomodule = false}, }; struct cli_callback_descr list_hdt_show_modules[] = { { .name = CLI_SUMMARY, .exec = main_show_summary, + .nomodule = false, }, { .name = CLI_PCI, .exec = main_show_pci, + .nomodule = false, }, { .name = CLI_DMI, .exec = main_show_dmi, + .nomodule = false, }, { .name = CLI_CPU, .exec = main_show_cpu, + .nomodule = false, }, { .name = CLI_DISK, .exec = disks_summary, + .nomodule = false, }, { .name = CLI_PXE, .exec = main_show_pxe, + .nomodule = false, }, { .name = CLI_SYSLINUX, .exec = main_show_syslinux, + .nomodule = false, }, { .name = CLI_KERNEL, .exec = main_show_kernel, + .nomodule = false, }, { .name = CLI_VESA, .exec = main_show_vesa, + .nomodule = false, }, { .name = CLI_HDT, .exec = main_show_hdt, + .nomodule = false, }, { .name = CLI_VPD, .exec = main_show_vpd, + .nomodule = false, }, { .name = CLI_MEMORY, .exec = show_dmi_memory_modules, + .nomodule = false, }, { .name = CLI_ACPI, .exec = main_show_acpi, + .nomodule = false, }, { .name = "modes", .exec = main_show_modes, + .nomodule = false, }, { .name = NULL, .exec = NULL, + .nomodule = false, }, }; @@ -348,10 +460,12 @@ struct cli_callback_descr list_hdt_set_modules[] = { { .name = CLI_MODE, .exec = cli_set_mode, + .nomodule = false, }, { .name = NULL, .exec = NULL, + .nomodule = false, }, }; diff --git a/com32/hdt/hdt-cli-memory.c b/com32/hdt/hdt-cli-memory.c index 51d087e8..c05b7cd6 100644 --- a/com32/hdt/hdt-cli-memory.c +++ b/com32/hdt/hdt-cli-memory.c @@ -101,22 +101,27 @@ struct cli_callback_descr list_memory_show_modules[] = { { .name = "e820", .exec = show_memory_e820, + .nomodule=false, }, { .name = "e801", .exec = show_memory_e801, + .nomodule=false, }, { .name = "88", .exec = show_memory_88, + .nomodule=false, }, { .name = CLI_DMI_MEMORY_BANK, .exec = show_dmi_memory_bank, + .nomodule=false, }, { .name = NULL, .exec = NULL, + .nomodule=false, }, }; diff --git a/com32/hdt/hdt-cli-pci.c b/com32/hdt/hdt-cli-pci.c index 07c079d5..75fc0011 100644 --- a/com32/hdt/hdt-cli-pci.c +++ b/com32/hdt/hdt-cli-pci.c @@ -266,14 +266,17 @@ struct cli_callback_descr list_pci_show_modules[] = { { .name = CLI_IRQ, .exec = show_pci_irq, + .nomodule=false, }, { .name = CLI_PCI_DEVICE, .exec = show_pci_device, + .nomodule=false, }, { .name = NULL, .exec = NULL, + .nomodule=false, }, }; diff --git a/com32/hdt/hdt-cli-vesa.c b/com32/hdt/hdt-cli-vesa.c index 702f8bd6..ca44987a 100644 --- a/com32/hdt/hdt-cli-vesa.c +++ b/com32/hdt/hdt-cli-vesa.c @@ -98,10 +98,12 @@ struct cli_callback_descr list_vesa_show_modules[] = { { .name = CLI_MODES, .exec = show_vesa_modes, + .nomodule=false, }, { .name = NULL, .exec = NULL, + .nomodule=false, }, }; @@ -109,15 +111,18 @@ struct cli_callback_descr list_vesa_commands[] = { { .name = CLI_ENABLE, .exec = enable_vesa, + .nomodule=false, }, { .name = CLI_DISABLE, .exec = disable_vesa, + .nomodule=false, }, { .name = NULL, .exec = NULL, + .nomodule=false, }, }; diff --git a/com32/hdt/hdt-cli.c b/com32/hdt/hdt-cli.c index 8b5335eb..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); } } @@ -365,14 +365,14 @@ static void parse_command_line(char *line, char **command, char **module, *command = malloc((token_len + 1) * sizeof(char)); strlcpy(*command, pch, token_len); (*command)[token_len] = '\0'; - dprintf("CLI DEBUG: command = %s\n", *command); + dprintf("CLI DEBUG parse: command = %s\n", *command); args_pos += args_len; } else if (token_found == 1) { /* Module */ *module = malloc((token_len + 1) * sizeof(char)); strlcpy(*module, pch, token_len); (*module)[token_len] = '\0'; - dprintf("CLI DEBUG: module = %s\n", *module); + dprintf("CLI DEBUG parse: module = %s\n", *module); args_pos += args_len; } else (*argc)++; @@ -380,7 +380,7 @@ static void parse_command_line(char *line, char **command, char **module, token_found++; pch = pch_next; } - dprintf("CLI DEBUG: argc = %d\n", *argc); + dprintf("CLI DEBUG parse: argc = %d\n", *argc); /* Skip arguments handling if none is supplied */ if (!*argc) @@ -390,9 +390,9 @@ static void parse_command_line(char *line, char **command, char **module, *argv = malloc(*argc * sizeof(char *)); pch = strtok(line + args_pos, CLI_SPACE); while (pch != NULL) { - dprintf("CLI DEBUG: argv[%d] = %s\n", argc_iter, pch); - argv[argc_iter] = malloc(sizeof(pch) * sizeof(char)); - strlcpy(argv[argc_iter], pch, sizeof(pch)); + dprintf("CLI DEBUG parse: argv[%d] = %s\n", argc_iter, pch); + argv[argc_iter] = malloc(strlen(pch) * sizeof(char)); + strlcpy(argv[argc_iter], pch, strlen(pch)); argc_iter++; pch = strtok(NULL, CLI_SPACE); /* @@ -585,6 +585,7 @@ static void autocomplete(char *line) parse_command_line(line, &command, &module, &argc, argv); + dprintf("CLI DEBUG autocomplete: before checking args\n"); /* If the user specified arguments, there is nothing we can complete */ if (argc != 0) goto out; @@ -625,22 +626,43 @@ static void exec_command(char *line, struct s_hardware *hardware) /* This will allocate memory for command and module */ parse_command_line(line, &command, &module, &argc, argv); + dprintf("CLI DEBUG exec: Checking for aliases\n"); /* * Expand shortcuts, if needed * This will allocate memory for argc/argv */ expand_aliases(line, &command, &module, &argc, argv); + + find_cli_callback_descr(command, current_mode->default_modules, + ¤t_module); - if (module == NULL) { - dprintf("CLI DEBUG: single command detected\n"); + if ((module == NULL) || (current_module->nomodule == true)) { + dprintf("CLI DEBUG exec : single command detected\n"); /* * A single word was specified: look at the list of default * commands in the current mode to see if there is a match. * If not, it may be a generic function (exit, help, ...). These * are stored in the list of default commands of the hdt mode. */ - find_cli_callback_descr(command, current_mode->default_modules, - ¤t_module); + + /* First of all it the command doesn't need module, let's rework the arguments */ + if ((current_module->nomodule == true) && ( module != NULL)) { + dprintf("CLI_DEBUG exec: Reworking arguments with argc=%d\n",argc); + char **new_argv=NULL; + new_argv=malloc((argc + 2)*sizeof(char)); + for (int argc_iter=0; argc_iter<argc; argc_iter++) { + dprintf("CLI_DEBUG exec rework : copy %d to %d (%s)\n",argc_iter,argc_iter+1,argv[argc_iter]); + new_argv[argc_iter+1] = malloc(strlen(argv[argc_iter])); + strlcpy(new_argv[argc_iter+1], argv[argc_iter], strlen(argv[argc_iter])); + free(argv[argc_iter]); + } + new_argv[0] = malloc(strlen(module)*sizeof(char)); + strlcpy(new_argv[0], module, strlen(module)); + argc++; + free(argv); + argv=new_argv; + } + if (current_module != NULL) current_module->exec(argc, argv, hardware); else if (!strncmp(command, CLI_SHOW, sizeof(CLI_SHOW) - 1) && @@ -657,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 { /* @@ -673,7 +695,7 @@ static void exec_command(char *line, struct s_hardware *hardware) * hdt> set mode dmi */ if (!strncmp(command, CLI_SHOW, sizeof(CLI_SHOW) - 1)) { - dprintf("CLI DEBUG: %s command detected\n", CLI_SHOW); + dprintf("CLI DEBUG exec: %s command detected\n", CLI_SHOW); /* Look first for a 'show' callback in the current mode */ find_cli_callback_descr(module, current_mode->show_modules, ¤t_module); @@ -681,6 +703,7 @@ static void exec_command(char *line, struct s_hardware *hardware) if (current_module != NULL) current_module->exec(argc, argv, hardware); else { + dprintf("CLI DEBUG exec: Looking for callback\n"); /* Look now for a 'show' callback in the hdt mode */ find_cli_callback_descr(module, hdt_mode.show_modules, ¤t_module); @@ -691,7 +714,7 @@ static void exec_command(char *line, struct s_hardware *hardware) printf("unknown module: '%s'\n", module); } } else if (!strncmp(command, CLI_SET, sizeof(CLI_SET) - 1)) { - dprintf("CLI DEBUG: %s command detected\n", CLI_SET); + dprintf("CLI DEBUG exec : %s command detected\n", CLI_SET); /* Look now for a 'set' callback in the hdt mode */ find_cli_callback_descr(module, current_mode->set_modules, ¤t_module); @@ -738,8 +761,7 @@ void start_auto_mode(struct s_hardware *hardware) int nb_commands = 0; char *commands[MAX_NB_AUTO_COMMANDS]; - if (!quiet) - more_printf("\nEntering Auto mode\n"); + more_printf("\nEntering Auto mode\n"); /* Protecting the auto_label from the strtok modifications */ char *temp = strdup(hardware->auto_label); @@ -811,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; } @@ -820,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 13291092..82a4fc99 100644 --- a/com32/hdt/hdt-cli.h +++ b/com32/hdt/hdt-cli.h @@ -65,6 +65,10 @@ #define CLI_ACPI "acpi" #define CLI_ENABLE "enable" #define CLI_DISABLE "disable" +#define CLI_DUMP "dump" +#define CLI_SAY "say" +#define CLI_DISPLAY "display" +#define CLI_SLEEP "sleep" typedef enum { INVALID_MODE, @@ -119,6 +123,7 @@ struct cli_module_descr { struct cli_callback_descr { const char *name; void (*exec) (int argc, char **argv, struct s_hardware * hardware); + bool nomodule; }; /* Manage aliases */ diff --git a/com32/hdt/hdt-common.c b/com32/hdt/hdt-common.c index f1557b86..dcad28cd 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)) { @@ -106,6 +111,36 @@ void detect_parameters(const int argc, const char *argv[], max_console_lines = MAX_CLI_LINES; } else if (!strncmp(argv[i], "nomenu", 6)) { menumode = false; + } else if (!strncmp(argv[i], "dump_filename=", 14)) { + strlcpy(hardware->dump_filename, argv[i] + 14, + sizeof(hardware->dump_filename)); + } else if (!strncmp(argv[i], "dump_path=", 10)) { + strlcpy(hardware->dump_path, argv[i] + 10, + sizeof(hardware->dump_path)); + } else if (!strncmp(argv[i], "tftp_ip=", 8)) { + strlcpy(hardware->tftp_ip, argv[i] + 8, + sizeof(hardware->tftp_ip)); + } else if (!strncmp(argv[i], "postexec=", 9)) { + /* The postexec= parameter is separated in several argv[] + * as it can contains spaces. + * We use the AUTO_DELIMITER char to define the limits + * of this parameter. + * i.e postexec='linux memtest.bin' + */ + + char *argument = (char*)argv[i]+10; + /* Extracting the first parameter */ + strcpy(hardware->postexec, argument); + + /* While we can't find the other AUTO_DELIMITER, let's process the argv[] */ + while ((strchr(argument, AUTO_DELIMITER) == NULL) && (i+1<argc)) { + i++; + argument = (char *)argv[i]; + strcat(hardware->postexec, " "); + strcat(hardware->postexec, argument); + } + + hardware->postexec[strlen(hardware->postexec) - 1] = 0; } else if (!strncmp(argv[i], "auto=", 5)) { /* The auto= parameter is separated in several argv[] * as it can contains spaces. @@ -115,25 +150,19 @@ void detect_parameters(const int argc, const char *argv[], */ automode=true; + char *argument = (char*)argv[i]+6; /* Extracting the first parameter */ - strcpy(hardware->auto_label, argv[i] + 6); - strcat(hardware->auto_label, " "); - char *pos; - i++; + strcpy(hardware->auto_label, argument); /* While we can't find the other AUTO_DELIMITER, let's process the argv[] */ - while (((pos = strstr(argv[i], AUTO_DELIMITER)) == NULL) - && (i < argc)) { - strcat(hardware->auto_label, argv[i]); - strcat(hardware->auto_label, " "); + while ((strchr(argument, AUTO_DELIMITER) == NULL) && (i+1<argc)) { i++; - } + argument = (char *)argv[i]; + strcat(hardware->auto_label, " "); + strcat(hardware->auto_label, argument); + } - /* If we didn't reach the end of the line, let's grab the last item */ - if (i < argc) { - strcat(hardware->auto_label, argv[i]); - hardware->auto_label[strlen(hardware->auto_label) - 1] = 0; - } + hardware->auto_label[strlen(hardware->auto_label) - 1] = 0; } } } @@ -203,7 +232,13 @@ void init_hardware(struct s_hardware *hardware) sizeof hardware->modules_alias_path); memset(hardware->memtest_label, 0, sizeof hardware->memtest_label); memset(hardware->auto_label, 0, sizeof hardware->auto_label); + memset(hardware->dump_path, 0, sizeof hardware->dump_path); + memset(hardware->dump_filename, 0, sizeof hardware->dump_filename); memset(hardware->vesa_background, 0, sizeof hardware->vesa_background); + memset(hardware->tftp_ip, 0, sizeof hardware->tftp_ip); + memset(hardware->postexec, 0, sizeof hardware->postexec); + strcat(hardware->dump_path, "hdt"); + strcat(hardware->dump_filename, "%{m}+%{p}+%{v}"); strcat(hardware->pciids_path, "pci.ids"); strcat(hardware->modules_pcimap_path, "modules.pcimap"); strcat(hardware->modules_alias_path, "modules.alias"); @@ -652,7 +687,7 @@ char *del_multi_spaces(char *p) * As we search for a double spacing * we have to be sure then string is * long enough to be processed */ - while (*p && *p + 1) { + while (*p && *(p + 1)) { /* If we have two consecutive spaces */ if ((*p == ' ') && (*(p + 1) == ' ')) { @@ -709,8 +744,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 df7d2c98..c2299b48 100644 --- a/com32/hdt/hdt-common.h +++ b/com32/hdt/hdt-common.h @@ -48,16 +48,18 @@ #include "cpuid.h" #include "dmi/dmi.h" #include "hdt-ata.h" -#include "../lib/sys/vesa/vesa.h" +#include <lib/sys/vesa/vesa.h> #include <vpd/vpd.h> #include <libansi.h> #include <acpi/acpi.h> +#include <libupload/upload_backend.h> /* Declare a variable or data structure as unused. */ #define __unused __attribute__ (( unused )) /* This two values are used for switching for the menu to the CLI mode */ #define HDT_SWITCH_TO_CLI "hdt_switch_to_cli" +#define HDT_DUMP "hdt_dump" #define HDT_RETURN_TO_CLI 100 #define MAX_VESA_MODES 255 @@ -71,7 +73,7 @@ /* The char that separate two commands */ #define AUTO_SEPARATOR ";" /* The char that surround the list of commands */ -#define AUTO_DELIMITER "'" +#define AUTO_DELIMITER '\'' /* Graphic to load in background when using the vesa mode */ #define CLI_DEFAULT_BACKGROUND "backgnd.png" @@ -80,9 +82,14 @@ #define MAX_CLI_LINES 20 #define MAX_VESA_CLI_LINES 24 +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; @@ -110,16 +117,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 */ @@ -209,9 +218,13 @@ struct s_hardware { char modules_pcimap_path[255]; char modules_alias_path[255]; char pciids_path[255]; + char dump_path[255]; /* Dump path on the tftp server */ + char dump_filename[255]; /* Dump filename on the tftp server */ + char tftp_ip[255]; /* IP address of tftp server (dump mode) */ char memtest_label[255]; char auto_label[AUTO_COMMAND_SIZE]; char vesa_background[255]; + char postexec[255]; }; void reset_more_printf(void); @@ -236,4 +249,5 @@ int detect_vesa(struct s_hardware *hardware); void detect_memory(struct s_hardware *hardware); void init_console(struct s_hardware *hardware); void detect_hardware(struct s_hardware *hardware); +void dump(struct s_hardware *hardware); #endif diff --git a/com32/hdt/hdt-dump-acpi.c b/com32/hdt/hdt-dump-acpi.c new file mode 100644 index 00000000..4cbaf66f --- /dev/null +++ b/com32/hdt/hdt-dump-acpi.c @@ -0,0 +1,600 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2011 Erwan Velu - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- + */ + +#include "hdt-common.h" +#include "hdt-dump.h" + +void show_header(char *name, void *address, s_acpi_description_header *h, ZZJSON_CONFIG *config, ZZJSON **item) +{ + char signature[10]={0}; + char revision[10]={0}; + char s_address[16]={0}; + char oem_id[16]={0}; + char oem_table_id[16]={0}; + char oem_revision[16]={0}; + char creator_revision[16]={0}; + char creator_id[16]={0}; + snprintf(signature,sizeof(signature),"%s",h->signature); + snprintf(revision,sizeof(revision),"0x%03x",h->revision); + snprintf(oem_id,sizeof(oem_id),"%s",h->oem_id); + snprintf(oem_table_id,sizeof(oem_table_id),"%s",h->oem_table_id); + snprintf(creator_id,sizeof(creator_id),"%s",h->creator_id); + snprintf(oem_revision,sizeof(oem_revision),"0x%08x",h->oem_revision); + snprintf(creator_revision,sizeof(creator_revision),"0x%08x",h->creator_revision); + snprintf(s_address,sizeof(s_address),"%p",address); + + char address_name[32]={0}; + char signature_name[32]={0}; + char revision_name[32]={0}; + char oem_id_name[32]={0}; + char oem_table_id_name[32]={0}; + char oem_revision_name[32]={0}; + char creator_revision_name[32]={0}; + char creator_id_name[32]={0}; + snprintf(signature_name,sizeof(signature_name),"acpi.%s.signature",name); + snprintf(revision_name,sizeof(revision_name),"acpi.%s.revision",name); + snprintf(address_name,sizeof(address_name),"acpi.%s.address",name); + snprintf(oem_id_name,sizeof(oem_id_name),"acpi.%s.oem_id",name); + snprintf(oem_table_id_name,sizeof(oem_table_id_name),"acpi.%s.oem_table_id",name); + snprintf(oem_revision_name,sizeof(oem_revision_name),"acpi.%s.oem_revision",name); + snprintf(creator_revision_name,sizeof(creator_revision_name),"acpi.%s.creator_revision",name); + snprintf(creator_id_name,sizeof(creator_id_name),"acpi.%s.creator_id",name); + + APPEND_ARRAY + add_as(signature_name,signature) + add_as(revision_name,revision) + add_as(oem_id_name,oem_id) + add_as(oem_table_id_name,oem_table_id) + add_as(oem_revision_name,oem_revision) + add_as(creator_id_name,creator_id) + add_as(creator_revision_name,creator_revision) + add_as(address_name,s_address) + END_OF_APPEND; + + FLUSH_OBJECT; + +} + +void dump_rsdt(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item) +{ + char valid[8]={0}; + snprintf(valid,sizeof(valid),"%s","false"); + if (acpi->rsdt.valid) { + snprintf(valid,sizeof(valid),"%s","true"); + } + CREATE_ARRAY + add_as("acpi.item","rsdt") + add_as("acpi.rsdt.is_valid",valid) + END_OF_ARRAY; + + if (acpi->rsdt.valid==false) { + FLUSH_OBJECT; + return; + } + + show_header("rsdt",acpi->rsdt.address, &acpi->rsdt.header, config, item); +} + +void dump_xsdt(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item) +{ + char valid[8]={0}; + snprintf(valid,sizeof(valid),"%s","false"); + if (acpi->xsdt.valid) { + snprintf(valid,sizeof(valid),"%s","true"); + } + CREATE_ARRAY + add_as("acpi.item","xsdt") + add_as("acpi.xsdt.is_valid",valid) + END_OF_ARRAY; + + if (acpi->xsdt.valid==false) { + FLUSH_OBJECT; + return; + } + + show_header("xsdt",acpi->xsdt.address, &acpi->xsdt.header, config, item); +} + +void dump_fadt(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item) +{ + char valid[8]={0}; + snprintf(valid,sizeof(valid),"%s","false"); + if (acpi->rsdt.valid) { + snprintf(valid,sizeof(valid),"%s","true"); + } + CREATE_ARRAY + add_as("acpi.item","fadt") + add_as("acpi.fadt.is_valid",valid) + END_OF_ARRAY; + + if (acpi->fadt.valid==false) { + FLUSH_OBJECT; + return; + } + + show_header("fadt",acpi->fadt.address, &acpi->fadt.header, config, item); +} + +void dump_dsdt(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item) +{ + char valid[8]={0}; + snprintf(valid,sizeof(valid),"%s","false"); + if (acpi->dsdt.valid) { + snprintf(valid,sizeof(valid),"%s","true"); + } + CREATE_ARRAY + add_as("acpi.item","dsdt") + add_as("acpi.dsdt.is_valid",valid) + END_OF_ARRAY; + + if (acpi->dsdt.valid==false) { + FLUSH_OBJECT; + return; + } + + show_header("dsdt",acpi->dsdt.address, &acpi->dsdt.header, config, item); +} + +void dump_sbst(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item) +{ + char valid[8]={0}; + snprintf(valid,sizeof(valid),"%s","false"); + if (acpi->sbst.valid) { + snprintf(valid,sizeof(valid),"%s","true"); + } + CREATE_ARRAY + add_as("acpi.item","sbst") + add_as("acpi.sbst.is_valid",valid) + END_OF_ARRAY; + + if (acpi->sbst.valid==false) { + FLUSH_OBJECT; + return; + } + + show_header("sbst",acpi->sbst.address, &acpi->sbst.header, config, item); +} + +void dump_ecdt(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item) +{ + char valid[8]={0}; + snprintf(valid,sizeof(valid),"%s","false"); + if (acpi->ecdt.valid) { + snprintf(valid,sizeof(valid),"%s","true"); + } + CREATE_ARRAY + add_as("acpi.item","ecdt") + add_as("acpi.ecdt.is_valid",valid) + END_OF_ARRAY; + + if (acpi->ecdt.valid==false) { + FLUSH_OBJECT; + return; + } + + show_header("ecdt",acpi->ecdt.address, &acpi->ecdt.header, config, item); +} + +void dump_hpet(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item) +{ + char valid[8]={0}; + snprintf(valid,sizeof(valid),"%s","false"); + if (acpi->hpet.valid) { + snprintf(valid,sizeof(valid),"%s","true"); + } + CREATE_ARRAY + add_as("acpi.item","hpet") + add_as("acpi.hpet.is_valid",valid) + END_OF_ARRAY; + + if (acpi->hpet.valid==false) { + FLUSH_OBJECT; + return; + } + + show_header("hpet",acpi->hpet.address, &acpi->hpet.header, config, item); +} + +void dump_tcpa(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item) +{ + char valid[8]={0}; + snprintf(valid,sizeof(valid),"%s","false"); + if (acpi->tcpa.valid) { + snprintf(valid,sizeof(valid),"%s","true"); + } + CREATE_ARRAY + add_as("acpi.item","tcpa") + add_as("acpi.tcpa.is_valid",valid) + END_OF_ARRAY; + + if (acpi->tcpa.valid==false) { + FLUSH_OBJECT; + return; + } + + show_header("tcpa",acpi->tcpa.address, &acpi->tcpa.header, config, item); +} + +void dump_mcfg(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item) +{ + char valid[8]={0}; + snprintf(valid,sizeof(valid),"%s","false"); + if (acpi->mcfg.valid) { + snprintf(valid,sizeof(valid),"%s","true"); + } + CREATE_ARRAY + add_as("acpi.item","mcfg") + add_as("acpi.mcfg.is_valid",valid) + END_OF_ARRAY; + + if (acpi->mcfg.valid==false) { + FLUSH_OBJECT; + return; + } + + show_header("mcfg",acpi->mcfg.address, &acpi->mcfg.header, config, item); +} + +void dump_slic(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item) +{ + char valid[8]={0}; + snprintf(valid,sizeof(valid),"%s","false"); + if (acpi->slic.valid) { + snprintf(valid,sizeof(valid),"%s","true"); + } + CREATE_ARRAY + add_as("acpi.item","slic") + add_as("acpi.slic.is_valid",valid) + END_OF_ARRAY; + + if (acpi->slic.valid==false) { + FLUSH_OBJECT; + return; + } + + show_header("slic",acpi->slic.address, &acpi->slic.header, config, item); +} + + +void dump_boot(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item) +{ + char valid[8]={0}; + snprintf(valid,sizeof(valid),"%s","false"); + if (acpi->boot.valid) { + snprintf(valid,sizeof(valid),"%s","true"); + } + CREATE_ARRAY + add_as("acpi.item","boot") + add_as("acpi.boot.is_valid",valid) + END_OF_ARRAY; + + if (acpi->boot.valid==false) { + FLUSH_OBJECT; + return; + } + + show_header("boot",acpi->boot.address, &acpi->boot.header, config, item); +} + +void dump_madt(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item) +{ + char valid[8]={0}; + snprintf(valid,sizeof(valid),"%s","false"); + if (acpi->madt.valid) { + snprintf(valid,sizeof(valid),"%s","true"); + } + CREATE_ARRAY + add_as("acpi.item","madt") + add_as("acpi.madt.is_valid",valid) + END_OF_ARRAY; + + if (acpi->madt.valid==false) { + FLUSH_OBJECT; + return; + } + + show_header("madt",acpi->madt.address, &acpi->madt.header, config, item); +} + +void dump_ssdt(s_ssdt *ssdt, ZZJSON_CONFIG * config, ZZJSON ** item) +{ + char valid[8]={0}; + snprintf(valid,sizeof(valid),"%s","false"); + if (ssdt->valid) { + snprintf(valid,sizeof(valid),"%s","true"); + } + CREATE_ARRAY + add_as("acpi.item","ssdt") + add_as("acpi.ssdt.is_valid",valid) + END_OF_ARRAY; + + if (ssdt->valid==false) { + FLUSH_OBJECT; + return; + } + + show_header("ssdt",ssdt->address, &ssdt->header, config, item); +} + +void dump_rsdp(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item) +{ + char valid[8]={0}; + snprintf(valid,sizeof(valid),"%s","false"); + if (acpi->rsdp.valid) { + snprintf(valid,sizeof(valid),"%s","true"); + } + CREATE_ARRAY + add_as("acpi.item","rsdp") + add_as("acpi.rsdp.is_valid",valid) + END_OF_ARRAY; + + if (acpi->rsdp.valid==false) { + FLUSH_OBJECT; + return; + } + + s_rsdp *r = &acpi->rsdp; + char revision[10]={0}; + char address[16]={0}; + char oem_id[16]={0}; + snprintf(revision,sizeof(revision),"0x%03x",r->revision); + snprintf(address,sizeof(address),"%p",r->address); + snprintf(oem_id,sizeof(oem_id),"%s",r->oem_id); + APPEND_ARRAY + add_as("acpi.rsdp.revision",revision) + add_as("acpi.rsdp.oem_id",oem_id) + add_as("acpi.rsdp.address",address) + END_OF_APPEND; + + FLUSH_OBJECT; + +} + +void dump_facs(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item) +{ + char valid[8]={0}; + snprintf(valid,sizeof(valid),"%s","false"); + if (acpi->facs.valid) { + snprintf(valid,sizeof(valid),"%s","true"); + } + CREATE_ARRAY + add_as("acpi.item","facs") + add_as("acpi.facs.is_valid",valid) + END_OF_ARRAY; + + if (acpi->facs.valid==false) { + FLUSH_OBJECT; + return; + } + + s_facs *fa = &acpi->facs; + char address[16]={0}; + snprintf(address,sizeof(address),"%p",fa->address); + APPEND_ARRAY + add_as("acpi.facs.address",address) + END_OF_APPEND; + + FLUSH_OBJECT; + +} + +void dump_interrupt_source_override(s_madt * madt, ZZJSON_CONFIG * config, ZZJSON ** item) +{ + CREATE_ARRAY + add_as("acpi.item","interrupt_source_override") + add_ai("acpi.interrupt_source_override.count", madt->interrupt_source_override_count) + END_OF_ARRAY; + + if (madt->interrupt_source_override_count == 0) { + FLUSH_OBJECT; + return; + } + + /* Let's process each interrupt source override */ + for (int i = 0; i < madt->interrupt_source_override_count; i++) { + s_interrupt_source_override *siso = &madt->interrupt_source_override[i]; + char buffer[20] = {0}; + char bus_type[10]= {0}; + + /* Spec report bus type 0 as ISA */ + if (siso->bus == 0) + strcpy(bus_type, "ISA"); + else + strcpy(bus_type, "unknown"); + + APPEND_ARRAY + add_as("acpi.interrupt_source_override.bus_type",bus_type) + add_ai("acpi.interrupt_source_override.bus",siso->bus) + add_ai("acpi.interrupt_source_override.bus_irq",siso->source) + add_ai("acpi.interrupt_source_override.global_irq",siso->global_system_interrupt) + add_as("acpi.interrupt_source_override.flags",flags_to_string(buffer,siso->flags)) + END_OF_APPEND; + } + FLUSH_OBJECT; +} + +void dump_io_apic(s_madt * madt, ZZJSON_CONFIG * config, ZZJSON ** item) +{ + CREATE_ARRAY + add_as("acpi.item","io_apic") + add_ai("acpi.io_apic.count", madt->io_apic_count) + END_OF_ARRAY; + + if (madt->io_apic_count == 0) { + FLUSH_OBJECT; + return; + } + + /* For all IO APICS */ + for (int i = 0; i < madt->io_apic_count; i++) { + s_io_apic *sio = &madt->io_apic[i]; + char buffer[15]={0}; + memset(buffer, 0, sizeof(buffer)); + /* GSI base reports the GSI configuration + * Let's interpret it as string */ + switch (sio->global_system_interrupt_base) { + case 0: + strcpy(buffer, "0-23"); + break; + case 24: + strcpy(buffer,"24-39"); + break; + case 40: + strcpy(buffer, "40-55"); + break; + default: + strcpy(buffer,"Unknown"); + break; + } + + char apic_id[16] = { 0 }; + char address[16] = { 0 }; + snprintf(apic_id,sizeof(apic_id),"0x%02x",sio->io_apic_id); + snprintf(address,sizeof(address),"0x%08x",sio->io_apic_address); + APPEND_ARRAY + add_ai("acpi.io_apic.number",i) + add_as("acpi.io_apic.apic_id",apic_id) + add_as("acpi.io_apic.adress",address) + add_as("acpi.io_apic.gsi",buffer) + END_OF_APPEND; + } + FLUSH_OBJECT; +} + +void dump_local_apic_nmi(s_madt * madt, ZZJSON_CONFIG * config, ZZJSON ** item) +{ + CREATE_ARRAY + add_as("acpi.item","local_apic_nmi") + add_ai("acpi.local_apic_nmi.count", madt->local_apic_nmi_count) + END_OF_ARRAY; + + if (madt->local_apic_nmi_count == 0) { + FLUSH_OBJECT; + return; + } + + for (int i = 0; i < madt->local_apic_nmi_count; i++) { + s_local_apic_nmi *slan = &madt->local_apic_nmi[i]; + char buffer[20]={0}; + char acpi_id[16] = { 0 }; + char local_apic_lint[16] = { 0 }; + snprintf(acpi_id, sizeof(acpi_id), "0x%02x", slan->acpi_processor_id); + snprintf(local_apic_lint, sizeof(local_apic_lint), "0x%02x", slan->local_apic_lint); + APPEND_ARRAY + add_as("acpi.processor_id", acpi_id) + add_as("acpi.local_apic_nmi.flags", flags_to_string(buffer,slan->flags)) + add_as("acpi.local_apic_nmi.lint",local_apic_lint) + END_OF_APPEND; + } + + FLUSH_OBJECT; +} + +void dump_local_apic(s_madt * madt, ZZJSON_CONFIG * config, ZZJSON ** item) +{ + char buffer[16] = { 0 }; + snprintf(buffer, sizeof(buffer), "0x%08x", madt->local_apic_address); + + CREATE_ARRAY + add_as("acpi.item","local_apic") + add_as("acpi.local_apic.address", buffer) + add_ai("acpi.processor_local_apic.count", madt->processor_local_apic_count) + END_OF_ARRAY; + + if (madt->processor_local_apic_count ==0) { + FLUSH_OBJECT; + return; + } + + /* For all detected logical CPU */ + for (int i = 0; i < madt->processor_local_apic_count; i++) { + s_processor_local_apic *sla = &madt->processor_local_apic[i]; + char lapic_status[16] = { 0 }; + char acpi_id[16] = { 0 }; + char apic_id[16] = { 0 }; + + snprintf(lapic_status,sizeof(lapic_status),"%s","disabled"); + /* Let's check if the flags reports the cpu as enabled */ + if ((sla->flags & PROCESSOR_LOCAL_APIC_ENABLE) == + PROCESSOR_LOCAL_APIC_ENABLE) + snprintf(lapic_status,sizeof(lapic_status),"%s","enabled"); + snprintf(acpi_id, sizeof(acpi_id), "0x%02x", sla->acpi_id); + snprintf(apic_id, sizeof(apic_id), "0x%02x", sla->apic_id); + APPEND_ARRAY + add_ai("acpi.cpu.apic_id", sla->apic_id) + add_as("acpi.cpu.apic_id (hex)", apic_id) + add_as("acpi.cpu.acpi_id (hex)", acpi_id) + add_as("acpi.lapic.enabled", lapic_status) + END_OF_APPEND; + } + FLUSH_OBJECT; +} + +void dump_acpi(struct s_hardware *hardware, ZZJSON_CONFIG * config, + ZZJSON ** item) +{ + CREATE_NEW_OBJECT; + add_hb(is_acpi_valid); + if (hardware->is_acpi_valid == false) + goto exit; + + s_madt *madt = &hardware->acpi.madt; + add_b("acpi.apic.detected", madt->valid); + if (madt->valid == false) { + goto exit; + } + + FLUSH_OBJECT; + + dump_local_apic(madt, config, item); + dump_local_apic_nmi(madt, config, item); + dump_io_apic(madt, config, item); + dump_interrupt_source_override(madt, config, item); + + dump_rsdp(&hardware->acpi,config,item); + dump_rsdt(&hardware->acpi,config,item); + dump_xsdt(&hardware->acpi,config,item); + dump_fadt(&hardware->acpi,config,item); + dump_dsdt(&hardware->acpi,config,item); + dump_sbst(&hardware->acpi,config,item); + dump_ecdt(&hardware->acpi,config,item); + dump_hpet(&hardware->acpi,config,item); + dump_tcpa(&hardware->acpi,config,item); + dump_mcfg(&hardware->acpi,config,item); + dump_slic(&hardware->acpi,config,item); + dump_boot(&hardware->acpi,config,item); + dump_madt(&hardware->acpi,config,item); + for (int i = 0; i < hardware->acpi.ssdt_count; i++) { + if ((hardware->acpi.ssdt[i] != NULL) && (hardware->acpi.ssdt[i]->valid)) + dump_ssdt(hardware->acpi.ssdt[i], config, item); + } + dump_facs(&hardware->acpi,config,item); + +exit: + to_cpio("acpi"); +} diff --git a/com32/hdt/hdt-dump-cpu.c b/com32/hdt/hdt-dump-cpu.c new file mode 100644 index 00000000..33d561c8 --- /dev/null +++ b/com32/hdt/hdt-dump-cpu.c @@ -0,0 +1,53 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2011 Erwan Velu - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- + */ + +#include "hdt-common.h" +#include "hdt-dump.h" + +void dump_cpu(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) { + + CREATE_NEW_OBJECT; + add_hs(cpu.vendor); + add_hs(cpu.model); + add_hi(cpu.vendor_id); + add_hi(cpu.family); + add_hi(cpu.model_id); + add_hi(cpu.stepping); + add_hi(cpu.num_cores); + add_hi(cpu.l1_data_cache_size); + add_hi(cpu.l1_instruction_cache_size); + add_hi(cpu.l2_cache_size); + size_t i; + for (i = 0; i < cpu_flags_count; i++) { + char temp[128]={0}; + snprintf(temp,sizeof(temp),"cpu.flags.%s",cpu_flags_names[i]); + add_b(temp,get_cpu_flag_value_from_name(&hardware->cpu,cpu_flags_names[i])); + } + FLUSH_OBJECT; + to_cpio("cpu"); +} diff --git a/com32/hdt/hdt-dump-disks.c b/com32/hdt/hdt-dump-disks.c new file mode 100644 index 00000000..ff744b30 --- /dev/null +++ b/com32/hdt/hdt-dump-disks.c @@ -0,0 +1,145 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2011 Erwan Velu - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- + */ + +#include "hdt-common.h" +#include "hdt-dump.h" +#include "hdt-util.h" + +ZZJSON_CONFIG *config; +ZZJSON **item; + +static void show_partition_information(struct driveinfo *drive_info, + struct part_entry *ptab, + int partition_offset, + int nb_partitions_seen) { + char size[11] = {0}; + char bootloader_name[9] = {0}; + char ostype[64]={0}; + char *parttype; + unsigned int start, end; + char bootable[6] = {0}; + + int i = nb_partitions_seen; + start = partition_offset; + end = start + ptab->length - 1; + + if (ptab->length > 0) + sectors_to_size(ptab->length, size); + + get_label(ptab->ostype, &parttype); + get_bootloader_string(drive_info, ptab, bootloader_name, 9); + if (ptab->active_flag == 0x80) + snprintf(bootable,sizeof(bootable),"%s","true"); + else + snprintf(bootable,sizeof(bootable),"%s","false"); + + snprintf(ostype,sizeof(ostype),"%02X",ptab->ostype); + + APPEND_ARRAY + add_ai("partition->number",i) + add_ai("partition->sector_start",start) + add_ai("partition->sector_end",end) + add_as("partition->size",size) + add_as("partition->type",parttype) + add_as("partition->os_type",ostype) + add_as("partition->boot_flag",bootable) + END_OF_APPEND; + free(parttype); +} + + + +void show_disk(struct s_hardware *hardware, ZZJSON_CONFIG *conf, ZZJSON **it, int drive) { + config=conf; + item=it; + int i = drive - 0x80; + struct driveinfo *d = &hardware->disk_info[i]; + char mbr_name[50]={0}; + char disk_size[11]={0}; + + get_mbr_string(hardware->mbr_ids[i], &mbr_name,sizeof(mbr_name)); + if ((int)d->edd_params.sectors > 0) + sectors_to_size((int)d->edd_params.sectors, disk_size); + + char disk[5]={0}; + char edd_version[5]={0}; + snprintf(disk,sizeof(disk),"0x%X",d->disk); + snprintf(edd_version,sizeof(edd_version),"%X",d->edd_version); + zzjson_print(config, *item); + zzjson_free(config, *item); + + CREATE_ARRAY + add_as("disk->number",disk) + add_ai("disk->cylinders",d->legacy_max_cylinder +1) + add_ai("disk->heads",d->legacy_max_head +1) + add_ai("disk->sectors_per_track",d->legacy_sectors_per_track) + add_as("disk->edd_version",edd_version) + add_as("disk->size",disk_size) + add_ai("disk->bytes_per_sector",(int)d->edd_params.bytes_per_sector) + add_ai("disk->sectors_per_track",(int)d->edd_params.sectors_per_track) + add_as("disk->host_bus",remove_spaces((char *)d->edd_params.host_bus_type)) + add_as("disk->interface_type",remove_spaces((char *)d->edd_params.interface_type)) + add_as("disk->mbr_name",mbr_name) + add_ai("disk->mbr_id",hardware->mbr_ids[i]) + END_OF_ARRAY; + + if (parse_partition_table(d, &show_partition_information)) { + if (errno_disk) { + APPEND_ARRAY + add_as("disk->error", "IO Error") + END_OF_APPEND; + } else { + APPEND_ARRAY + add_as("disk->error", "Unrecognized Partition Layout") + END_OF_APPEND; + } + } +} + +void dump_disks(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) { + bool found=false; + + if (hardware->disks_count > 0) + for (int drive = 0x80; drive < 0xff; drive++) { + if (hardware->disk_info[drive - 0x80].cbios) { + if (found==false) { + CREATE_NEW_OBJECT; + add_b("disks->is_valid",true); + found=true; + } + show_disk(hardware, config, item, drive); + } + } + + if (found==false) { + CREATE_NEW_OBJECT; + add_b("disks->is_valid",false); + } + FLUSH_OBJECT; + to_cpio("disks"); +} diff --git a/com32/hdt/hdt-dump-dmi.c b/com32/hdt/hdt-dump-dmi.c new file mode 100644 index 00000000..6e5c1ce8 --- /dev/null +++ b/com32/hdt/hdt-dump-dmi.c @@ -0,0 +1,447 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2011 Erwan Velu - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- + */ + +#include "hdt-common.h" +#include "hdt-dump.h" + +void dump_hardware_security(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) { + if (!hardware->dmi.hardware_security.filled) { + CREATE_NEW_OBJECT; + add_s("dmi.warning","No hardware security structure found"); + FLUSH_OBJECT; + return; + } + + CREATE_NEW_OBJECT; + add_s("dmi.item","hardware_security"); + add_hs(dmi.hardware_security.power_on_passwd_status); + add_hs(dmi.hardware_security.keyboard_passwd_status); + add_hs(dmi.hardware_security.administrator_passwd_status); + add_hs(dmi.hardware_security.front_panel_reset_status); + FLUSH_OBJECT; +} + +void dump_oem_strings(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) { + if (strlen(hardware->dmi.oem_strings) == 0) { + CREATE_NEW_OBJECT; + add_s("dmi.warning","No OEM structure found"); + FLUSH_OBJECT; + return; + } + CREATE_NEW_OBJECT; + add_s("dmi.item","OEM"); + add_hs(dmi.oem_strings); + FLUSH_OBJECT; +} + +void dump_memory_size(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) { + CREATE_NEW_OBJECT; + add_s("dmi.item","memory size"); + add_i("dmi.memory_size (KB)",hardware->detected_memory_size); + add_i("dmi.memory_size (MB)",(hardware->detected_memory_size + (1 << 9)) >> 10); + FLUSH_OBJECT; +} + +void dump_memory_modules(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) { + + if (hardware->dmi.memory_module_count == 0) { + CREATE_NEW_OBJECT; + add_s("dmi.warning","No memory module structure found"); + FLUSH_OBJECT; + return; + } + + for (int module=0; module<hardware->dmi.memory_module_count;module++) { + if (hardware->dmi.memory_module[module].filled == false) { + char msg[64]={0}; + snprintf(msg,sizeof(msg),"Module %d doesn't contain any information", module); + + CREATE_NEW_OBJECT; + add_s("dmi.warning",msg); + FLUSH_OBJECT; + continue; + } + + CREATE_NEW_OBJECT; + add_i("Memory module", module); + add_s("dmi.memory_module.socket_designation", hardware->dmi.memory_module[module].socket_designation); + add_s("dmi.memory_module.bank_connections", hardware->dmi.memory_module[module].bank_connections); + add_s("dmi.memory_module.speed", hardware->dmi.memory_module[module].speed); + add_s("dmi.memory_module.type", hardware->dmi.memory_module[module].type); + add_s("dmi.memory_module.installed_size", hardware->dmi.memory_module[module].installed_size); + add_s("dmi.memory_module.enabled_size", hardware->dmi.memory_module[module].enabled_size); + add_s("dmi.memory_module.error_status", hardware->dmi.memory_module[module].error_status); + FLUSH_OBJECT; + } +} + +void dump_cache(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) { + + if (hardware->dmi.cache_count == 0) { + CREATE_NEW_OBJECT; + add_s("dmi.warning","No cache structure found"); + FLUSH_OBJECT; + return; + } + + for (int cache=0; cache<hardware->dmi.cache_count;cache++) { + CREATE_NEW_OBJECT; + add_i("Cache", cache); + add_s("dmi.cache.socket_designation", hardware->dmi.cache[cache].socket_designation); + add_s("dmi.cache.configuration", hardware->dmi.cache[cache].configuration); + add_s("dmi.cache.mode", hardware->dmi.cache[cache].mode); + add_s("dmi.cache.location", hardware->dmi.cache[cache].location); + add_i("dmi.cache.installed_size (KB)", hardware->dmi.cache[cache].installed_size); + add_i("dmi.cache.max_size (KB)", hardware->dmi.cache[cache].max_size); + add_s("dmi.cache.supported_sram_types", hardware->dmi.cache[cache].supported_sram_types); + add_s("dmi.cache.installed_sram_types", hardware->dmi.cache[cache].installed_sram_types); + add_i("dmi.cache.speed (ns)", hardware->dmi.cache[cache].speed); + add_s("dmi.cache.error_correction_type", hardware->dmi.cache[cache].error_correction_type); + add_s("dmi.cache.system_type", hardware->dmi.cache[cache].system_type); + add_s("dmi.cache.associativity", hardware->dmi.cache[cache].associativity); + FLUSH_OBJECT; + } +} +void dump_memory_banks(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) { + + if (hardware->dmi.memory_count == 0) { + CREATE_NEW_OBJECT; + add_s("dmi.warning","No memory bank structure found"); + FLUSH_OBJECT; + return; + } + + for (int bank=0; bank<hardware->dmi.memory_count;bank++) { + + if (hardware->dmi.memory[bank].filled == false) { + char msg[64]={0}; + snprintf(msg,sizeof(msg),"Bank %d doesn't contain any information", bank); + + CREATE_NEW_OBJECT; + add_s("dmi.warning",msg); + FLUSH_OBJECT; + continue; + } + + CREATE_NEW_OBJECT; + add_i("Memory Bank", bank); + add_s("dmi.memory.form_factor", hardware->dmi.memory[bank].form_factor); + add_s("dmi.memory.type", hardware->dmi.memory[bank].type); + add_s("dmi.memory.type_detail", hardware->dmi.memory[bank].type_detail); + add_s("dmi.memory.speed", hardware->dmi.memory[bank].speed); + add_s("dmi.memory.size", hardware->dmi.memory[bank].size); + add_s("dmi.memory.device_set", hardware->dmi.memory[bank].device_set); + add_s("dmi.memory.device_locator", hardware->dmi.memory[bank].device_locator); + add_s("dmi.memory.bank_locator", hardware->dmi.memory[bank].bank_locator); + add_s("dmi.memory.total_width", hardware->dmi.memory[bank].total_width); + add_s("dmi.memory.data_width", hardware->dmi.memory[bank].data_width); + add_s("dmi.memory.error", hardware->dmi.memory[bank].error); + add_s("dmi.memory.vendor", hardware->dmi.memory[bank].manufacturer); + add_s("dmi.memory.serial", hardware->dmi.memory[bank].serial); + add_s("dmi.memory.asset_tag", hardware->dmi.memory[bank].asset_tag); + add_s("dmi.memory.part_number", hardware->dmi.memory[bank].part_number); + FLUSH_OBJECT; + } +} + +void dump_processor(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) { + if (hardware->dmi.processor.filled == false) { + CREATE_NEW_OBJECT; + add_s("dmi.warning","no processor structure found"); + FLUSH_OBJECT; + return; + } + + char voltage[16]={0}; + snprintf(voltage,sizeof(voltage),"%d.%02d", + hardware->dmi.processor.voltage_mv / 1000, + hardware->dmi.processor.voltage_mv - ((hardware->dmi.processor.voltage_mv / 1000) * 1000)); + + CREATE_NEW_OBJECT; + add_s("dmi.item","processor"); + add_hs(dmi.processor.socket_designation); + add_hs(dmi.processor.type); + add_hs(dmi.processor.family); + add_hs(dmi.processor.manufacturer); + add_hs(dmi.processor.version); + add_hi(dmi.processor.external_clock); + add_hi(dmi.processor.max_speed); + add_hi(dmi.processor.current_speed); + add_hi(dmi.processor.signature.type); + add_hi(dmi.processor.signature.family); + add_hi(dmi.processor.signature.model); + add_hi(dmi.processor.signature.stepping); + add_hi(dmi.processor.signature.minor_stepping); + add_s("dmi.processor.voltage",voltage); + add_hs(dmi.processor.status); + add_hs(dmi.processor.upgrade); + add_hs(dmi.processor.cache1); + add_hs(dmi.processor.cache2); + add_hs(dmi.processor.cache3); + add_hs(dmi.processor.serial); + add_hs(dmi.processor.part_number); + add_hi(dmi.processor.core_count); + add_hi(dmi.processor.core_enabled); + add_hi(dmi.processor.thread_count); + add_hs(dmi.processor.id); + for (int i = 0; i < PROCESSOR_FLAGS_ELEMENTS; i++) { + if (((bool *) (&hardware->dmi.processor.cpu_flags))[i] == true) { + add_s("dmi.processor.flag",(char *)cpu_flags_strings[i]); + } + } + FLUSH_OBJECT; +} + +void dump_battery(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) { + if (hardware->dmi.battery.filled == false) { + CREATE_NEW_OBJECT; + add_s("dmi.warning","no battery structure found"); + FLUSH_OBJECT; + return; + } + + CREATE_NEW_OBJECT; + add_s("dmi.item","battery"); + add_hs(dmi.battery.manufacturer); + add_hs(dmi.battery.manufacture_date); + add_hs(dmi.battery.serial); + add_hs(dmi.battery.name); + add_hs(dmi.battery.chemistry); + add_hs(dmi.battery.design_capacity); + add_hs(dmi.battery.design_voltage); + add_hs(dmi.battery.sbds); + add_hs(dmi.battery.sbds_manufacture_date); + add_hs(dmi.battery.sbds_chemistry); + add_hs(dmi.battery.maximum_error); + add_hs(dmi.battery.oem_info); + FLUSH_OBJECT; +} + +void dump_ipmi(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) { + if (hardware->dmi.ipmi.filled == false) { + CREATE_NEW_OBJECT; + add_s("dmi.warning","no IPMI structure found"); + FLUSH_OBJECT; + return; + } + + char spec_ver[16]={0}; + char i2c[16]={0}; + char base[16]={0}; + snprintf(spec_ver,sizeof(spec_ver),"%u.%u", + hardware->dmi.ipmi.major_specification_version, + hardware->dmi.ipmi.minor_specification_version); + + snprintf(i2c,sizeof(i2c),"0x%02x", hardware->dmi.ipmi.I2C_slave_address); + snprintf(base,sizeof(base),"%08X%08X", + (uint32_t)(hardware->dmi.ipmi.base_address >> 32), + (uint32_t)((hardware->dmi.ipmi.base_address & 0xFFFF) & ~1)); + + CREATE_NEW_OBJECT; + add_s("dmi.item","ipmi"); + add_hs(dmi.ipmi.interface_type); + add_s("dmi.ipmi.spec_version",spec_ver); + add_hi(dmi.ipmi.I2C_slave_address); + add_hi(dmi.ipmi.nv_address); + add_s("dmi.ipmi.base_address",base); + add_hi(dmi.ipmi.irq); + FLUSH_OBJECT; +} + +void dump_chassis(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) { + if (hardware->dmi.chassis.filled == false) { + CREATE_NEW_OBJECT; + add_s("dmi.warning","no chassis structure found"); + FLUSH_OBJECT; + return; + } + + CREATE_NEW_OBJECT; + add_s("dmi.item","bios"); + add_hs(dmi.chassis.manufacturer); + add_hs(dmi.chassis.type); + add_hs(dmi.chassis.lock); + add_hs(dmi.chassis.version); + add_hs(dmi.chassis.serial); + add_s("dmi.chassis.asset_tag",del_multi_spaces(hardware->dmi.chassis.asset_tag)); + add_hs(dmi.chassis.boot_up_state); + add_hs(dmi.chassis.power_supply_state); + add_hs(dmi.chassis.thermal_state); + add_hs(dmi.chassis.security_status); + add_hs(dmi.chassis.oem_information); + add_hi(dmi.chassis.height); + add_hi(dmi.chassis.nb_power_cords); + FLUSH_OBJECT; +} + +void dump_bios(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) { + if (hardware->dmi.bios.filled == false) { + CREATE_NEW_OBJECT; + add_s("dmi.warning","no bios structure found"); + FLUSH_OBJECT; + return; + } + char address[16]={0}; + char runtime[16]={0}; + char rom[16]={0}; + snprintf(address,sizeof(address),"0x%04X0",hardware->dmi.bios.address); + snprintf(runtime,sizeof(runtime),"%u %s",hardware->dmi.bios.runtime_size, hardware->dmi.bios.runtime_size_unit); + snprintf(rom,sizeof(rom),"%u %s",hardware->dmi.bios.rom_size, hardware->dmi.bios.rom_size_unit); + + CREATE_NEW_OBJECT; + add_s("dmi.item","bios"); + add_hs(dmi.bios.vendor); + add_hs(dmi.bios.version); + add_hs(dmi.bios.release_date); + add_hs(dmi.bios.bios_revision); + add_hs(dmi.bios.firmware_revision); + add_s("dmi.bios.address",address); + add_s("dmi.bios.runtime_size",runtime); + add_s("dmi.bios.rom_size",rom); + for (int i = 0; i < BIOS_CHAR_NB_ELEMENTS; i++) { + if (((bool *) (&hardware->dmi.bios.characteristics))[i] == true) { + add_s("dmi.bios.characteristics",(char *)bios_charac_strings[i]); + } + } + + for (int i = 0; i < BIOS_CHAR_X1_NB_ELEMENTS; i++) { + if (((bool *) (&hardware->dmi.bios.characteristics_x1))[i] == true) { + add_s("dmi.bios.characteristics",(char *)bios_charac_x1_strings[i]); + } + } + + for (int i = 0; i < BIOS_CHAR_X2_NB_ELEMENTS; i++) { + if (((bool *) (&hardware->dmi.bios.characteristics_x2))[i] == true) { + add_s("dmi.bios.characteristics",(char *)bios_charac_x2_strings[i]); + } + } + FLUSH_OBJECT; +} + +void dump_system(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) { + + if (hardware->dmi.system.filled == false) { + CREATE_NEW_OBJECT; + add_s("dmi.warning","no system structure found"); + FLUSH_OBJECT; + return; + } + char system_reset_status[10]={0}; + char watchdog_timer[15]={0}; + snprintf(system_reset_status,sizeof(system_reset_status),"%s", (hardware->dmi.system.system_reset.status ? "Enabled" :"Disabled")); + snprintf(watchdog_timer,sizeof(watchdog_timer),"%s", (hardware->dmi.system.system_reset.watchdog ? "Present" :"Not Present")); + + CREATE_NEW_OBJECT; + add_s("dmi.item","system"); + add_hs(dmi.system.manufacturer); + add_hs(dmi.system.product_name); + add_hs(dmi.system.version); + add_hs(dmi.system.serial); + add_hs(dmi.system.uuid); + add_hs(dmi.system.wakeup_type); + add_hs(dmi.system.sku_number); + add_hs(dmi.system.family); + add_hs(dmi.system.configuration_options); + add_s("dmi.system.system_reset.status",system_reset_status); + add_s("dmi.system.system_reset.watchdog",watchdog_timer); + add_hs(dmi.system.system_reset.boot_option); + add_hs(dmi.system.system_reset.boot_option_on_limit); + add_hs(dmi.system.system_reset.reset_count); + add_hs(dmi.system.system_reset.reset_limit); + add_hs(dmi.system.system_reset.timer_interval); + add_hs(dmi.system.system_reset.timeout); + add_hs(dmi.system.system_boot_status); + FLUSH_OBJECT; +} + +void dump_base_board(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) { + + if (hardware->dmi.base_board.filled == false) { + CREATE_NEW_OBJECT; + add_s("dmi.warning","no base_board structure found"); + FLUSH_OBJECT; + return; + } + + CREATE_NEW_OBJECT; + add_s("dmi.item","base_board"); + add_hs(dmi.base_board.manufacturer); + add_hs(dmi.base_board.product_name); + add_hs(dmi.base_board.version); + add_hs(dmi.base_board.serial); + add_hs(dmi.base_board.asset_tag); + add_hs(dmi.base_board.location); + add_hs(dmi.base_board.type); + for (int i = 0; i < BASE_BOARD_NB_ELEMENTS; i++) { + if (((bool *) (&hardware->dmi.base_board.features))[i] == true) { + add_s("dmi.base_board.features",(char *)base_board_features_strings[i]); + } + } + + for (unsigned int i = 0; i < sizeof hardware->dmi.base_board.devices_information / + sizeof *hardware->dmi.base_board.devices_information; i++) { + if (strlen(hardware->dmi.base_board.devices_information[i].type)) { + add_s("dmi.base_board.devices_information.type", hardware->dmi.base_board.devices_information[i].type); + add_i("dmi.base_board.devices_information.status", hardware->dmi.base_board.devices_information[i].status); + add_s("dmi.base_board.devices_information.description", hardware->dmi.base_board.devices_information[i].description); + } + } + FLUSH_OBJECT; +} + +void dump_dmi(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) { + + CREATE_NEW_OBJECT; + add_hb(is_dmi_valid); + + if (hardware->is_dmi_valid == false) { + FLUSH_OBJECT; + goto exit; + } else { + char buffer[8]={0}; + snprintf(buffer,sizeof(buffer),"%d.%d",hardware->dmi.dmitable.major_version, hardware->dmi.dmitable.minor_version); + add_s("dmi.version",buffer); + FLUSH_OBJECT; + } + + dump_base_board(hardware,config,item); + dump_system(hardware,config,item); + dump_bios(hardware,config,item); + dump_chassis(hardware,config,item); + dump_ipmi(hardware,config,item); + dump_battery(hardware,config,item); + dump_processor(hardware,config,item); + dump_cache(hardware,config,item); + dump_memory_banks(hardware,config,item); + dump_memory_modules(hardware,config,item); + dump_memory_size(hardware,config,item); + dump_oem_strings(hardware,config,item); + dump_hardware_security(hardware,config,item); +exit: + to_cpio("dmi"); +} diff --git a/com32/hdt/hdt-dump-hdt.c b/com32/hdt/hdt-dump-hdt.c new file mode 100644 index 00000000..d081ebdb --- /dev/null +++ b/com32/hdt/hdt-dump-hdt.c @@ -0,0 +1,50 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2011 Erwan Velu - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- + */ + +#include "hdt-common.h" +#include "hdt-dump.h" +#include <syslinux/config.h> + +void dump_hdt(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) { + + (void) hardware; + CREATE_NEW_OBJECT; + add_s("hdt.product_name",PRODUCT_NAME); + add_s("hdt.version",VERSION); + add_s("hdt.code_name",CODENAME); + add_s("hdt.author", AUTHOR); + add_s("hdt.core_developer", CORE_DEVELOPER); + char *contributors[NB_CONTRIBUTORS] = CONTRIBUTORS; + for (int c = 0; c < NB_CONTRIBUTORS; c++) { + add_s("hdt.contributor", contributors[c]); + } + add_s("hdt.website",WEBSITE_URL); + add_s("hdt.irc_channel",IRC_CHANNEL); + FLUSH_OBJECT + to_cpio("hdt"); +} diff --git a/com32/hdt/hdt-dump-kernel.c b/com32/hdt/hdt-dump-kernel.c new file mode 100644 index 00000000..e0df8320 --- /dev/null +++ b/com32/hdt/hdt-dump-kernel.c @@ -0,0 +1,69 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2011 Erwan Velu - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- + */ + +#include "hdt-common.h" +#include "hdt-dump.h" + +void dump_kernel(struct s_hardware *hardware, ZZJSON_CONFIG * config, + ZZJSON ** item) +{ + struct pci_device *pci_device = NULL; + CREATE_ARRAY + add_as("Linux Kernel modules", "") + END_OF_ARRAY; + + if (hardware->pci_ids_return_code == -ENOPCIIDS) { + APPEND_ARRAY + add_as("Error", "No pci.ids file") + END_OF_APPEND FLUSH_OBJECT; + return; + } + + if ((hardware->modules_pcimap_return_code == -ENOMODULESPCIMAP) + &&(hardware->modules_pcimap_return_code == -ENOMODULESALIAS)) { + APPEND_ARRAY + add_as("Error", "No modules.pcimap or modules.alias file") + END_OF_APPEND FLUSH_OBJECT; + return; + + } + + /* For every detected pci device, compute its submenu */ + for_each_pci_func(pci_device, hardware->pci_domain) { + if (pci_device == NULL) + continue; + for (int kmod = 0; + kmod < pci_device->dev_info->linux_kernel_module_count; kmod++) { + APPEND_ARRAY + add_as(pci_device->dev_info->category_name, pci_device->dev_info->linux_kernel_module[kmod]) + END_OF_APPEND; + } + } + FLUSH_OBJECT; + to_cpio("kernel"); +} diff --git a/com32/hdt/hdt-dump-memory.c b/com32/hdt/hdt-dump-memory.c new file mode 100644 index 00000000..5095d3c2 --- /dev/null +++ b/com32/hdt/hdt-dump-memory.c @@ -0,0 +1,133 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2011 Erwan Velu - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- + */ + +#include <memory.h> +#include "hdt-common.h" +#include "hdt-dump.h" + +void dump_88(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) { + + (void) hardware; + int mem_size = 0; + CREATE_NEW_OBJECT; + if (detect_memory_88(&mem_size)) { + add_s("memory.error","8800h memory configuration is invalid"); + FLUSH_OBJECT + return; + } + + add_s("dmi.item","memory via 88"); + add_i("memory.size (KiB)", mem_size); + add_i("memory.size (MiB)", mem_size >> 10); + FLUSH_OBJECT; +} + +void dump_e801(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) { + + (void) hardware; + int mem_low, mem_high = 0; + CREATE_NEW_OBJECT; + if (detect_memory_e801(&mem_low,&mem_high)) { + add_s("memory.error","e801 memory configuration is invalid"); + FLUSH_OBJECT; + return; + } + + add_s("dmi.item","memory via e801"); + add_i("memory.total.size (KiB)", mem_low + (mem_high << 6)); + add_i("memory.total.size (MiB)", (mem_low >> 10) + (mem_high >> 4)); + add_i("memory.low.size (KiB)", mem_low ); + add_i("memory.low.size (MiB)", mem_low >> 10); + add_i("memory.high.size (KiB)", mem_high << 6); + add_i("memory.high.size (MiB)", mem_high >> 4); + FLUSH_OBJECT; + +} +void dump_e820(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) { + + (void) hardware; + struct e820entry map[E820MAX]; + struct e820entry nm[E820MAX]; + unsigned long memsize = 0; + int count = 0; + char type[14] = {0}; + + detect_memory_e820(map, E820MAX, &count); + memsize = memsize_e820(map, count); + + CREATE_NEW_OBJECT; + add_s("dmi.item","memory via e820"); + add_i("memory.total.size (KiB)", memsize); + add_i("memory.total.size (MiB)", (memsize + (1 << 9)) >> 10); + FLUSH_OBJECT; + + for (int i = 0; i < count; i++) { + get_type(map[i].type, type, sizeof(type)); + char begin[24]={0}; + char size[24]={0}; + char end[24]={0}; + snprintf(begin,sizeof(begin),"0x%016llx",map[i].addr); + snprintf(size,sizeof(size),"0x%016llx",map[i].size); + snprintf(end,sizeof(end),"0x%016llx",map[i].addr+map[i].size); + CREATE_NEW_OBJECT; + add_s("memory.segment.start",begin); + add_s("memory.segment.size ",size); + add_s("memory.segment.end ",end); + add_s("memory.segment.type ",remove_spaces(type)); + FLUSH_OBJECT; + } + + int nr = sanitize_e820_map(map, nm, count); + for (int i = 0; i < nr; i++) { + get_type(nm[i].type, type, sizeof(type)); + char begin[24]={0}; + char size[24]={0}; + char end[24]={0}; + snprintf(begin,sizeof(begin),"0x%016llx",nm[i].addr); + snprintf(size,sizeof(size),"0x%016llx",nm[i].size); + snprintf(end,sizeof(end),"0x%016llx",nm[i].addr+nm[i].size); + CREATE_NEW_OBJECT; + add_s("sanitized_memory.segment.start",begin); + add_s("sanitized_memory.segment.size ",size); + add_s("sanitized_memory.segment.end ",end); + add_s("sanitized_memory.segment.type ",remove_spaces(type)); + FLUSH_OBJECT; + } +} + +void dump_memory(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) { + + CREATE_NEW_OBJECT; + add_s("Memory configuration","true"); + FLUSH_OBJECT; + + dump_88(hardware,config,item); + dump_e801(hardware,config,item); + dump_e820(hardware,config,item); + to_cpio("memory"); +} diff --git a/com32/hdt/hdt-dump-pci.c b/com32/hdt/hdt-dump-pci.c new file mode 100644 index 00000000..b1f18fdf --- /dev/null +++ b/com32/hdt/hdt-dump-pci.c @@ -0,0 +1,136 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2011 Erwan Velu - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- + */ + +#include "hdt-common.h" +#include "hdt-dump.h" + +void dump_pci(struct s_hardware *hardware, ZZJSON_CONFIG * config, + ZZJSON ** item) +{ + int i = 1; + struct pci_device *pci_device=NULL; + char kernel_modules[LINUX_KERNEL_MODULE_SIZE * + MAX_KERNEL_MODULES_PER_PCI_DEVICE]; + bool nopciids = false; + bool nomodulespcimap = false; + bool nomodulesalias = false; + bool nomodulesfile = false; + int bus = 0, slot = 0, func = 0; + + if (hardware->pci_ids_return_code == -ENOPCIIDS) { + nopciids = true; + } + if (hardware->modules_pcimap_return_code == -ENOMODULESPCIMAP) { + nomodulespcimap = true; + } + if (hardware->modules_pcimap_return_code == -ENOMODULESALIAS) { + nomodulesalias = true; + } + + nomodulesfile = nomodulespcimap && nomodulesalias; + + CREATE_NEW_OBJECT; + + add_i("pci_device.count", hardware->nb_pci_devices); + + FLUSH_OBJECT; + /* For every detected pci device, compute its submenu */ + for_each_pci_func(pci_device, hardware->pci_domain) { + if (pci_device == NULL) + continue; + char v[10] = { 0 }; + char sv[10] = { 0 }; + char p[10] = { 0 }; + char sp[10] = { 0 }; + char c[10] = { 0 }; + char r[10] = { 0 }; + + CREATE_NEW_OBJECT; + bus = __pci_bus; + slot = __pci_slot; + func = __pci_func; + + memset(kernel_modules, 0, sizeof kernel_modules); + for (int kmod = 0; + kmod < pci_device->dev_info->linux_kernel_module_count; kmod++) { + if (kmod > 0) { + strncat(kernel_modules, " | ", 3); + } + strncat(kernel_modules, + pci_device->dev_info->linux_kernel_module[kmod], + LINUX_KERNEL_MODULE_SIZE - 1); + } + if (pci_device->dev_info->linux_kernel_module_count == 0) + strlcpy(kernel_modules, "unknown", 7); + + add_i("pci_device.number", i); + if (nopciids == false) { + add_s("pci_device.vendor_name", pci_device->dev_info->vendor_name); + add_s("pci_device.product_name", + pci_device->dev_info->product_name); + } + if (nomodulesfile == false) { + add_s("pci_device.class_name", pci_device->dev_info->class_name); + add_s("pci_device.kernel_module", kernel_modules); + } + + snprintf(v, sizeof(v), "%04x", pci_device->vendor); + snprintf(p, sizeof(p), "%04x", pci_device->product); + snprintf(sv, sizeof(sv), "%04x", pci_device->sub_vendor); + snprintf(sp, sizeof(sp), "%04x", pci_device->sub_product); + snprintf(c, sizeof(c), "%02x.%02x.%02x", + pci_device->class[2], + pci_device->class[1], pci_device->class[0]); + snprintf(r, sizeof(r), "%02x", pci_device->revision); + add_s("pci_device.vendor_id", v); + add_s("pci_device.product_id", p); + add_s("pci_device.sub_vendor_id", sv); + add_s("pci_device.sub_product_id", sp); + add_s("pci_device.class_id", c); + add_s("pci_device.revision", r); + if ((pci_device->dev_info->irq > 0) + && (pci_device->dev_info->irq < 255)) + add_i("pci_device.irq", pci_device->dev_info->irq); + + add_i("pci_device.latency", pci_device->dev_info->latency); + add_i("pci_device.bus", bus); + add_i("pci_device.slot", slot); + add_i("pci_device.func", func); + + if (hardware->is_pxe_valid == true) { + if ((hardware->pxe.pci_device != NULL) + && (hardware->pxe.pci_device == pci_device)) { + add_hs(pxe.mac_addr); + add_s("pxe", "Current boot device"); + } + } + i++; + FLUSH_OBJECT; + } + to_cpio("pci"); +} diff --git a/com32/hdt/hdt-dump-pxe.c b/com32/hdt/hdt-dump-pxe.c new file mode 100644 index 00000000..4e25c943 --- /dev/null +++ b/com32/hdt/hdt-dump-pxe.c @@ -0,0 +1,80 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2011 Erwan Velu - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- + */ + +#include "hdt-common.h" +#include "hdt-dump.h" +#include <sys/gpxe.h> +#include <netinet/in.h> + +void dump_pxe(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) { + struct in_addr in; + + CREATE_NEW_OBJECT; + add_hb(is_pxe_valid); + if (hardware->is_pxe_valid) { + char buffer[32] = {0}; + snprintf(buffer,sizeof(buffer),"0x%x",hardware->pxe.vendor_id); + add_s("pxe.vendor_id",buffer); + snprintf(buffer,sizeof(buffer),"0x%x",hardware->pxe.product_id); + add_s("pxe.product_id",buffer); + snprintf(buffer,sizeof(buffer),"0x%x",hardware->pxe.subvendor_id); + add_s("pxe.subvendor_id",buffer); + snprintf(buffer,sizeof(buffer),"0x%x",hardware->pxe.subproduct_id); + add_s("pxe.subproduct_id",buffer); + + if (hardware->pci_ids_return_code == -ENOPCIIDS || (hardware->pxe.pci_device == NULL)) { + add_s("Manufacturer_name","no_pci_ids_file or no device found"); + add_s("Product_name","no_pci_ids_file or no device found"); + } else { + add_s("Manufacturer_name", hardware->pxe.pci_device->dev_info->vendor_name); + add_s("Product_name", hardware->pxe.pci_device->dev_info->product_name); + } + + add_hi(pxe.rev); + add_hi(pxe.pci_bus); + add_hi(pxe.pci_dev); + add_hi(pxe.pci_func); + add_hi(pxe.base_class); + add_hi(pxe.sub_class); + add_hi(pxe.prog_intf); + add_hi(pxe.nictype); + add_hs(pxe.mac_addr); + + in.s_addr = hardware->pxe.dhcpdata.cip; + add_s("pxe.client_ip", inet_ntoa(in)); + in.s_addr = hardware->pxe.dhcpdata.sip; + add_s("pxe.next_server_ip",inet_ntoa(in)); + in.s_addr = hardware->pxe.dhcpdata.gip; + add_s("pxe.relay_agent_ip",inet_ntoa(in)); + memcpy(&in, hardware->pxe.ip_addr, sizeof in); + add_s("pxe.ipaddr",inet_ntoa(in)); + add_b("gpxe_detected",is_gpxe()); + } + FLUSH_OBJECT; + to_cpio("pxe"); +} diff --git a/com32/hdt/hdt-dump-syslinux.c b/com32/hdt/hdt-dump-syslinux.c new file mode 100644 index 00000000..7cef925f --- /dev/null +++ b/com32/hdt/hdt-dump-syslinux.c @@ -0,0 +1,43 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2011 Erwan Velu - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- + */ + +#include "hdt-common.h" +#include "hdt-dump.h" +#include <syslinux/config.h> + +void dump_syslinux(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) { + + CREATE_NEW_OBJECT; + add_hs(syslinux_fs); + add_hs(sv->version_string); + add_hi(sv->version); + add_hi(sv->max_api); + add_hs(sv->copyright_string); + FLUSH_OBJECT + to_cpio("syslinux"); +} diff --git a/com32/hdt/hdt-dump-vesa.c b/com32/hdt/hdt-dump-vesa.c new file mode 100644 index 00000000..97d56c95 --- /dev/null +++ b/com32/hdt/hdt-dump-vesa.c @@ -0,0 +1,67 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2011 Erwan Velu - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- + */ + +#include "hdt-common.h" +#include "hdt-dump.h" +#include <syslinux/config.h> + +void dump_vesa(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) { + + CREATE_NEW_OBJECT; + add_hb(is_vesa_valid); + if (hardware->is_vesa_valid) { + char buffer[64]={0}; + snprintf(buffer,sizeof(buffer),"%d.%d", hardware->vesa.major_version, hardware->vesa.minor_version); + add_s("vesa.version",buffer); + add_hs(vesa.vendor); + add_hs(vesa.product); + add_hs(vesa.product_revision); + add_hi(vesa.software_rev); + memset(buffer,0,sizeof(buffer)); + snprintf(buffer,sizeof(buffer),"%d KB",hardware->vesa.total_memory*64); + add_s("vesa.memory",buffer); + add_i("vesa.modes",hardware->vesa.vmi_count); + FLUSH_OBJECT; + for (int i = 0; i < hardware->vesa.vmi_count; i++) { + struct vesa_mode_info *mi = &hardware->vesa.vmi[i].mi; + if ((mi->h_res == 0) || (mi->v_res == 0)) + continue; + CREATE_NEW_OBJECT; + memset(buffer,0,sizeof(buffer)); + snprintf(buffer,sizeof(buffer),"0x%04x",hardware->vesa.vmi[i].mode + 0x200); + add_s("vesa.kernel_mode",buffer); + add_i("vesa.hres",mi->h_res); + add_i("vesa.vres",mi->v_res); + add_i("vesa.bpp",mi->bpp); + FLUSH_OBJECT; + } + } else { + FLUSH_OBJECT; + } + to_cpio("vesa"); +} diff --git a/com32/hdt/hdt-dump-vpd.c b/com32/hdt/hdt-dump-vpd.c new file mode 100644 index 00000000..36451c8a --- /dev/null +++ b/com32/hdt/hdt-dump-vpd.c @@ -0,0 +1,47 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2011 Erwan Velu - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- + */ + +#include "hdt-common.h" +#include "hdt-dump.h" + +void dump_vpd(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) { + + CREATE_NEW_OBJECT; + add_hb(is_vpd_valid); + if (hardware->is_vpd_valid) { + add_hs(vpd.bios_build_id); + add_hs(vpd.bios_release_date); + add_hs(vpd.bios_version); + add_hs(vpd.default_flash_filename); + add_hs(vpd.box_serial_number); + add_hs(vpd.motherboard_serial_number); + add_hs(vpd.machine_type_model); + } + FLUSH_OBJECT; + to_cpio("vpd"); +} diff --git a/com32/hdt/hdt-dump.c b/com32/hdt/hdt-dump.c new file mode 100644 index 00000000..b1748c8e --- /dev/null +++ b/com32/hdt/hdt-dump.c @@ -0,0 +1,229 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2011 Erwan Velu - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <getkey.h> +#include <syslinux/config.h> +#include "hdt-common.h" +#include "hdt-dump.h" + +struct print_buf p_buf; + +struct dump_option { + char *flag; + char *item; +}; + +char *get_value_from_option(struct s_hardware *hardware, char *option) +{ + struct dump_option dump_options[10]; + dump_options[0].flag = "%{m}"; + dump_options[0].item = hardware->pxe.mac_addr; + + dump_options[1].flag = "%{v}"; + dump_options[1].item = hardware->dmi.system.manufacturer; + + dump_options[2].flag = "%{p}"; + dump_options[2].item = hardware->dmi.system.product_name; + + dump_options[3].flag = "%{ba}"; + dump_options[3].item = hardware->dmi.base_board.asset_tag; + + dump_options[4].flag = "%{bs}"; + dump_options[4].item = hardware->dmi.base_board.serial; + + dump_options[5].flag = "%{ca}"; + dump_options[5].item = hardware->dmi.chassis.asset_tag; + + dump_options[6].flag = "%{cs}"; + dump_options[6].item = hardware->dmi.chassis.serial; + + dump_options[7].flag = "%{sk}"; + dump_options[7].item = hardware->dmi.system.sku_number; + + dump_options[8].flag = "%{ss}"; + dump_options[8].item = hardware->dmi.system.serial; + + dump_options[9].flag = NULL; + dump_options[9].item = NULL; + + for (int i = 0; i < 9; i++) { + if (strcmp(option, dump_options[i].flag) == 0) { + return remove_spaces(dump_options[i].item); + } + } + + return NULL; +} + +char *compute_filename(struct s_hardware *hardware) +{ + + char *filename = malloc(512); + snprintf(filename, 512, "%s/%s", hardware->dump_path, + hardware->dump_filename); + + /* Until we found some dump parameters */ + char *buffer; + while ((buffer = strstr(filename, "%{"))) { + // Find the end of the parameter + char *buffer_end = strstr(buffer, "}"); + + // Extracting the parameter between %{ and } + char option[8] = { 0 }; + strncpy(option, buffer, buffer_end - buffer + 1); + + /* Replace this option by its value in the filename + * Filename is longer than the previous filename we had + * so let's restart from the beginning */ + filename = + strreplace(filename, option, + get_value_from_option(hardware, option)); + } + + /* We replace the ":" in the filename by some "-" + * This will avoid Microsoft FS turning crazy */ + chrreplace(filename, ':', '-'); + + /* Avoid space to make filename easier to manipulate */ + chrreplace(filename, ' ', '_'); + + return filename; +} + +int dumpprintf(FILE * p, const char *format, ...) +{ + va_list ap; + int rv; + + (void)p; + va_start(ap, format); + rv = vbufprintf(&p_buf, format, ap); + va_end(ap); + return rv; +} + +void to_cpio(char *filename) +{ + cpio_writefile(upload, filename, p_buf.buf, p_buf.len); + if ((p_buf.buf) && (p_buf.len > 0)) { + memset(p_buf.buf, 0, p_buf.len); + free(p_buf.buf); + p_buf.buf = NULL; + p_buf.size = 0; + p_buf.len = 0; + } +} + +void flush(ZZJSON_CONFIG * config, ZZJSON ** item) +{ + zzjson_print(config, *item); + zzjson_free(config, *item); + *item = NULL; +} + +/** + * dump - dump info + **/ +void dump(struct s_hardware *hardware) +{ + if (hardware->is_pxe_valid == false) { + more_printf("PXE stack was not detected, Dump feature is not available\n"); + return; + } + + const union syslinux_derivative_info *sdi = syslinux_derivative_info(); + int err = 0; + ZZJSON *json = NULL; + ZZJSON_CONFIG config = { ZZJSON_VERY_STRICT, NULL, + (int (*)(void *))fgetc, + NULL, + malloc, calloc, free, realloc, + stderr, NULL, stdout, + (int (*)(void *, const char *,...))dumpprintf, + (int (*)(int, void *))fputc + }; + + memset(&p_buf, 0, sizeof(p_buf)); + + /* By now, we only support TFTP reporting */ + upload = &upload_tftp; + upload->name = "tftp"; + + /* The following defines the behavior of the reporting */ + char *arg[64]; + char *filename = compute_filename(hardware); + + /* The filename */ + arg[0] = filename; + /* The server to upload the file */ + if (strlen(hardware->tftp_ip) != 0) { + arg[1] = hardware->tftp_ip; + arg[2] = NULL; + } else { + arg[1] = NULL; + snprintf(hardware->tftp_ip, sizeof(hardware->tftp_ip), + "%u.%u.%u.%u", + ((uint8_t *) & sdi->pxe.ipinfo->serverip)[0], + ((uint8_t *) & sdi->pxe.ipinfo->serverip)[1], + ((uint8_t *) & sdi->pxe.ipinfo->serverip)[2], + ((uint8_t *) & sdi->pxe.ipinfo->serverip)[3]); + + } + + /* We initiate the cpio to send */ + cpio_init(upload, (const char **)arg); + + dump_cpu(hardware, &config, &json); + dump_pxe(hardware, &config, &json); + dump_syslinux(hardware, &config, &json); + dump_vpd(hardware, &config, &json); + dump_vesa(hardware, &config, &json); + dump_disks(hardware, &config, &json); + dump_dmi(hardware, &config, &json); + dump_memory(hardware, &config, &json); + dump_pci(hardware, &config, &json); + dump_acpi(hardware, &config, &json); + dump_kernel(hardware, &config, &json); + dump_hdt(hardware, &config, &json); + + /* We close & flush the file to send */ + cpio_close(upload); + + if ((err = flush_data(upload)) != TFTP_OK) { + /* As we manage a tftp connection, let's display the associated error message */ + more_printf("Dump failed !\n"); + more_printf("TFTP ERROR on : %s:/%s \n", hardware->tftp_ip, filename); + more_printf("TFTP ERROR msg : %s \n", tftp_string_error_message[-err]); + } else { + more_printf("Dump file sent at %s:/%s\n", hardware->tftp_ip, filename); + } +} diff --git a/com32/hdt/hdt-dump.h b/com32/hdt/hdt-dump.h new file mode 100644 index 00000000..f9669dac --- /dev/null +++ b/com32/hdt/hdt-dump.h @@ -0,0 +1,85 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 20011 Erwan Velu - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <bufprintf.h> +#include <zzjson/zzjson.h> +#include "hdt-common.h" + +// Macros to manipulate Arrays +#define APPEND_ARRAY ZZJSON *temp_array; temp_array = zzjson_array_append(config, *item, zzjson_create_object(config, +#define APPEND_OBJECT_ARRAY(value) ZZJSON *temp_ar; temp_ar = zzjson_array_append(config, *item, value); *item=temp_ar; +#define CREATE_ARRAY *item = zzjson_create_array(config, zzjson_create_object(config, +#define add_ai(name,value) name,zzjson_create_number_i(config,value), +#define add_ahi(value) add_ai(#value,hardware->value) +#define add_as(name,value) name,zzjson_create_string(config,value), +#define add_ahs(value) add_as(#value,hardware->value) +#define END_OF_ARRAY NULL),NULL) +#define END_OF_APPEND NULL)); *item=temp_array; + +// Macros to manipulate objects +#define CREATE_NEW_OBJECT *item = zzjson_create_object(config, NULL); +#define FLUSH_OBJECT flush(config, item); + +// Macros to manipulate integers as objects +#define add_i(name,value) *item = zzjson_object_append(config, *item, name, zzjson_create_number_i(config, value)) +#define add_hi(value) add_i(#value,hardware->value) + +// Macros to manipulate strings as objects +#define add_s(name,value) *item = zzjson_object_append(config, *item, name, zzjson_create_string(config, value)) +#define add_hs(value) add_s(#value,(char *)hardware->value) + +// Macros to manipulate bool as objects +#define add_bool_true(name) *item = zzjson_object_append(config, *item, (char *)name, zzjson_create_true(config)) +#define add_bool_false(name) *item = zzjson_object_append(config, *item, (char*)name, zzjson_create_false(config)) +#define add_b(name,value) if (value==true) {add_bool_true(name);} else {add_bool_false(name);} +#define add_hb(value) add_b(#value,hardware->value) + +extern struct print_buf p_buf; + +void print_and_flush(ZZJSON_CONFIG *config, ZZJSON **item); +int dumpprintf(FILE *p, const char *format, ...); +void flush (ZZJSON_CONFIG *config, ZZJSON ** item); +void to_cpio(char *filename); + +void dump_cpu(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item); +void dump_pxe(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item); +void dump_syslinux(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item); +void dump_vpd(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item); +void dump_vesa(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item); +void dump_disks(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item); +void dump_dmi(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item); +void dump_memory(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item); +void dump_pci(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item); +void dump_acpi(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item); +void dump_kernel(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item); +void dump_hdt(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item); +void dump(struct s_hardware *hardware); diff --git a/com32/hdt/hdt-menu-acpi.c b/com32/hdt/hdt-menu-acpi.c index 16bcf73a..8e0ba18f 100644 --- a/com32/hdt/hdt-menu-acpi.c +++ b/com32/hdt/hdt-menu-acpi.c @@ -32,7 +32,7 @@ void compute_table(struct s_my_menu *menu, void *address, s_acpi_description_hea char buffer[SUBMENULEN + 1] = { 0 }; char statbuffer[STATLEN + 1] = { 0 }; - snprintf(buffer, sizeof buffer, "%-4s v%03x %-6s %-7s %-7s %08x", + snprintf(buffer, sizeof buffer, "%-4s v%03x %-6s %-8s %-7s %08x", h->signature, h->revision, h->oem_id, h->oem_table_id, h->creator_id, h->creator_revision); snprintf(statbuffer, sizeof statbuffer, "%-4s v%03x %-6s %-7s 0x%08x %-4s 0x%08x @ 0x%p", h->signature, h->revision, h->oem_id, h->oem_table_id, @@ -52,7 +52,7 @@ static void compute_acpi_tables(struct s_my_menu *menu, char buffer[SUBMENULEN + 1] = { 0 }; - snprintf(buffer, sizeof buffer, "%-4s %-4s %-6s %-7s %-7s %-8s", + snprintf(buffer, sizeof buffer, "%-4s %-4s %-6s %-8s %-7s %-8s", "ACPI", "rev", "oem", "table_id", "creator", "creator_rev"); add_item(buffer, "Description", OPT_INACTIVE, NULL, 0); menu->items_count++; diff --git a/com32/hdt/hdt-menu-disk.c b/com32/hdt/hdt-menu-disk.c index b0b4a5ac..0716b435 100644 --- a/com32/hdt/hdt-menu-disk.c +++ b/com32/hdt/hdt-menu-disk.c @@ -120,9 +120,9 @@ static void compute_partition_information(struct driveinfo *drive_info, add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); } - snprintf(buffer, sizeof buffer, "Bootable : %s", + snprintf(buffer, sizeof buffer, "Boot Flag : %s", (ptab->active_flag == 0x80) ? "Yes" : "No"); - snprintf(statbuffer, sizeof statbuffer, "Bootable: %s", + snprintf(statbuffer, sizeof statbuffer, "Boot Flag: %s", (ptab->active_flag == 0x80) ? "Yes" : "No"); add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); @@ -243,12 +243,12 @@ void compute_disks(struct s_hdt_menu *menu, struct s_hardware *hardware) if (hardware->disks_count == 0) return; - for (int i = 0; i < hardware->disks_count; i++) { - if (!hardware->disk_info[i].cbios) + for (int drive = 0x80; drive < 0xff; drive++) { + if (!hardware->disk_info[drive - 0x80].cbios) continue; /* Invalid geometry */ compute_disk_module ((struct s_my_menu *)&(menu->disk_sub_menu), nb_sub_disk_menu, - hardware, i); + hardware, drive - 0x80); nb_sub_disk_menu++; } diff --git a/com32/hdt/hdt-menu-pxe.c b/com32/hdt/hdt-menu-pxe.c index 426bfe07..12d8b116 100644 --- a/com32/hdt/hdt-menu-pxe.c +++ b/com32/hdt/hdt-menu-pxe.c @@ -34,7 +34,7 @@ void compute_PXE(struct s_my_menu *menu, struct s_hardware *hardware) { char buffer[SUBMENULEN + 1]; char infobar[STATLEN + 1]; - char gpxe[4]; + char gpxe[4]={0}; if (hardware->is_pxe_valid == false) return; @@ -113,8 +113,8 @@ void compute_PXE(struct s_my_menu *menu, struct s_hardware *hardware) add_item(buffer, infobar, OPT_INACTIVE, NULL, 0); menu->items_count++; - if (is_gpxe()) strcat(gpxe,"Yes"); - else strcat (gpxe,"No"); + if (is_gpxe()) snprintf(gpxe,sizeof(gpxe),"%s","Yes"); + else snprintf (gpxe, sizeof(gpxe), "%s", "No"); snprintf(buffer, sizeof buffer, "gPXE Detected: %s", gpxe); snprintf(infobar, sizeof infobar, "gPXE Detected: %s", gpxe); diff --git a/com32/hdt/hdt-menu-summary.c b/com32/hdt/hdt-menu-summary.c index ad87c299..cef7e69e 100644 --- a/com32/hdt/hdt-menu-summary.c +++ b/com32/hdt/hdt-menu-summary.c @@ -52,8 +52,7 @@ void compute_summarymenu(struct s_my_menu *menu, struct s_hardware *hardware) add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0); menu->items_count++; - char features[SUBMENULEN + 1]; - memset(features, 0, sizeof(features)); + char features[255]={0}; if (hardware->dmi.processor.thread_count != 0) sprintf(buffer, ", %d thread", hardware->dmi.processor.thread_count); else diff --git a/com32/hdt/hdt-menu.c b/com32/hdt/hdt-menu.c index 0fdee039..50b3eaa8 100644 --- a/com32/hdt/hdt-menu.c +++ b/com32/hdt/hdt-menu.c @@ -62,6 +62,12 @@ int start_menu_mode(struct s_hardware *hardware, char *version_string) (curr->data, HDT_SWITCH_TO_CLI, sizeof(HDT_SWITCH_TO_CLI))) { return HDT_RETURN_TO_CLI; } + /* Tweak, we want to start the dump mode */ + if (!strncmp + (curr->data, HDT_DUMP, sizeof(HDT_DUMP))) { + dump(hardware); + return 0; + } if (!strncmp (curr->data, HDT_REBOOT, sizeof(HDT_REBOOT))) { syslinux_reboot(1); @@ -289,6 +295,12 @@ void compute_main_menu(struct s_hdt_menu *hdt_menu, struct s_hardware *hardware) add_item("S<w>itch to CLI", "Switch to Command Line", OPT_RUN, HDT_SWITCH_TO_CLI, 0); + + if (hardware->is_pxe_valid == true) { + add_item("<D>ump to tftp", "Dump to tftp", OPT_RUN, + HDT_DUMP, 0); + } + add_item("<A>bout", "About Menu", OPT_SUBMENU, NULL, hdt_menu->about_menu.menu); add_item("<R>eboot", "Reboot", OPT_RUN, HDT_REBOOT, 0); diff --git a/com32/hdt/hdt.c b/com32/hdt/hdt.c index a1e3923c..653995d0 100644 --- a/com32/hdt/hdt.c +++ b/com32/hdt/hdt.c @@ -72,16 +72,23 @@ 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; if (!menumode || automode) start_cli_mode(&hardware); else { - int return_code = start_menu_mode(&hardware, version_string); + return_code = start_menu_mode(&hardware, version_string); if (return_code == HDT_RETURN_TO_CLI) start_cli_mode(&hardware); - else - return return_code; } - return 0; + + /* Do we got request to do something at exit time ? */ + if (strlen(hardware.postexec)>0) { + more_printf("Executing postexec instructions : %s\n",hardware.postexec); + runsyslinuxcmd(hardware.postexec); + } + + return return_code; } diff --git a/com32/hdt/hdt.h b/com32/hdt/hdt.h index dd489480..e385417a 100644 --- a/com32/hdt/hdt.h +++ b/com32/hdt/hdt.h @@ -33,8 +33,8 @@ #define AUTHOR "Erwan Velu" #define CORE_DEVELOPER "Pierre-Alexandre Meyer" #define CONTACT "hdt@zytor.com" -#define VERSION "0.4.1" -#define CODENAME "chouffe" +#define VERSION "0.5.2" +#define CODENAME "Manon" #define NB_CONTRIBUTORS 3 #define CONTRIBUTORS {"Sebastien Gonzalve (Patches)", "Gert Hulselmans (Tests)", "Alexander Andino (Design)"} #define WEBSITE_URL "http://hdt-project.org" diff --git a/com32/include/bitsize/stddef.h b/com32/include/bitsize/stddef.h index caa5e726..213e8ab7 100644 --- a/com32/include/bitsize/stddef.h +++ b/com32/include/bitsize/stddef.h @@ -6,13 +6,9 @@ #define _BITSIZE_STDDEF_H #define _SIZE_T -#if defined(__s390__) || defined(__hppa__) || defined(__cris__) -typedef unsigned long size_t; -#else typedef unsigned int size_t; -#endif #define _PTRDIFF_T -typedef signed int ptrdiff_t; +typedef signed long ptrdiff_t; #endif /* _BITSIZE_STDDEF_H */ diff --git a/com32/include/bitsize/stdint.h b/com32/include/bitsize/stdint.h index 8cbfc5dd..8e444b6d 100644 --- a/com32/include/bitsize/stdint.h +++ b/com32/include/bitsize/stdint.h @@ -5,24 +5,24 @@ #ifndef _BITSIZE_STDINT_H #define _BITSIZE_STDINT_H -typedef signed char int8_t; -typedef short int int16_t; -typedef int int32_t; -typedef long long int int64_t; +typedef signed char int8_t; +typedef short int int16_t; +typedef int int32_t; +typedef long long int int64_t; -typedef unsigned char uint8_t; -typedef unsigned short int uint16_t; -typedef unsigned int uint32_t; -typedef unsigned long long int uint64_t; +typedef unsigned char uint8_t; +typedef unsigned short int uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long int uint64_t; -typedef int int_fast16_t; -typedef int int_fast32_t; +typedef int int_fast16_t; +typedef int int_fast32_t; -typedef unsigned int uint_fast16_t; -typedef unsigned int uint_fast32_t; +typedef unsigned int uint_fast16_t; +typedef unsigned int uint_fast32_t; -typedef int intptr_t; -typedef unsigned int uintptr_t; +typedef int intptr_t; +typedef unsigned int uintptr_t; #define __INT64_C(c) c ## LL #define __UINT64_C(c) c ## ULL @@ -31,4 +31,4 @@ typedef unsigned int uintptr_t; #define __PRIFAST_RANK "" #define __PRIPTR_RANK "" -#endif /* _BITSIZE_STDINT_H */ +#endif /* _BITSIZE_STDINT_H */ diff --git a/com32/include/bitsize/stdintconst.h b/com32/include/bitsize/stdintconst.h index 8157dd06..7db63bdf 100644 --- a/com32/include/bitsize/stdintconst.h +++ b/com32/include/bitsize/stdintconst.h @@ -15,4 +15,4 @@ #define UINTPTR_C(c) UINT32_C(c) #define PTRDIFF_C(c) INT32_C(c) -#endif /* _BITSIZE_STDINTCONST_H */ +#endif /* _BITSIZE_STDINTCONST_H */ diff --git a/com32/include/bitsize/stdintlimits.h b/com32/include/bitsize/stdintlimits.h index b44fe011..d85094d9 100644 --- a/com32/include/bitsize/stdintlimits.h +++ b/com32/include/bitsize/stdintlimits.h @@ -19,4 +19,4 @@ #define PTRDIFF_MIN INT32_MIN #define PTRDIFF_MAX INT32_MAX -#endif /* _BITSIZE_STDINTLIMITS_H */ +#endif /* _BITSIZE_STDINTLIMITS_H */ diff --git a/com32/include/bufprintf.h b/com32/include/bufprintf.h new file mode 100644 index 00000000..5cbeaa4b --- /dev/null +++ b/com32/include/bufprintf.h @@ -0,0 +1,10 @@ +#define BUFPAD 4096 + +struct print_buf { + char *buf; + size_t len; + size_t size; +}; + +int vbufprintf(struct print_buf *buf, const char *format, va_list ap); +int bufprintf(struct print_buf *buf, const char *format, ...); diff --git a/com32/include/cpufeature.h b/com32/include/cpufeature.h index df9dd3d3..83263c2c 100644 --- a/com32/include/cpufeature.h +++ b/com32/include/cpufeature.h @@ -7,7 +7,7 @@ #ifndef __ASM_I386_CPUFEATURE_H #define __ASM_I386_CPUFEATURE_H -#define NCAPINTS 7 /* N 32-bit words worth of info */ +#define NCAPINTS 9 /* N 32-bit words worth of info */ /* Intel-defined CPU features, CPUID level 0x00000001 (edx), word 0 */ #define X86_FEATURE_FPU (0*32+ 0) /* Onboard FPU */ diff --git a/com32/include/ctype.h b/com32/include/ctype.h index 83bbda1c..6e0645ee 100644 --- a/com32/include/ctype.h +++ b/com32/include/ctype.h @@ -117,5 +117,6 @@ __ctype_inline int tolower(int __c) } __extern char *skipspace(const char *p); +__extern void chrreplace(char *source, char old, char new); #endif /* _CTYPE_H */ diff --git a/com32/include/dhcp.h b/com32/include/dhcp.h new file mode 100644 index 00000000..afef9242 --- /dev/null +++ b/com32/include/dhcp.h @@ -0,0 +1,40 @@ +#ifndef DHCP_H +#define DHCP_H + +#include <inttypes.h> + +struct dhcp_option { + void *data; + int len; +}; + +struct dhcp_packet { + uint8_t op; /* 0 */ + uint8_t htype; /* 1 */ + uint8_t hlen; /* 2 */ + uint8_t hops; /* 3 */ + uint32_t xid; /* 4 */ + uint16_t secs; /* 8 */ + uint16_t flags; /* 10 */ + uint32_t ciaddr; /* 12 */ + uint32_t yiaddr; /* 16 */ + uint32_t siaddr; /* 20 */ + uint32_t giaddr; /* 24 */ + uint8_t chaddr[16]; /* 28 */ + uint8_t sname[64]; /* 44 */ + uint8_t file[128]; /* 108 */ + uint32_t magic; /* 236 */ + uint8_t options[4]; /* 240 */ +}; + +#define DHCP_VENDOR_MAGIC 0x63825363 + +int dhcp_pack_packet(void *packet, size_t *len, + const struct dhcp_option opt[256]); + +int dhcp_unpack_packet(const void *packet, size_t len, + struct dhcp_option opt[256]); + +#endif /* DHCP_H */ + + diff --git a/com32/include/dprintf.h b/com32/include/dprintf.h index 30a21ada..b8a3b84c 100644 --- a/com32/include/dprintf.h +++ b/com32/include/dprintf.h @@ -7,16 +7,30 @@ #ifdef DEBUG -#include <stdio.h> +# include <stdio.h> +# ifdef DEBUG_STDIO +# define dprintf printf +# define vdprintf vprintf +# else void dprintf(const char *, ...); void vdprintf(const char *, va_list); +# endif #else -#define dprintf(fmt, ...) ((void)(0)) -#define vdprintf(fmt, ap) ((void)(0)) +# define dprintf(fmt, ...) ((void)(0)) +# define vdprintf(fmt, ap) ((void)(0)) #endif /* DEBUG */ +# if DEBUG >= 2 +/* Really verbose debugging... */ +# define dprintf2 dprintf +# define vdprintf2 vdprintf +# else +# define dprintf2(fmt, ...) ((void)(0)) +# define vdprintf2(fmt, ap) ((void)(0)) +# endif + #endif /* _DPRINTF_H */ diff --git a/com32/include/netinet/in.h b/com32/include/netinet/in.h index ccf04750..d2af351f 100644 --- a/com32/include/netinet/in.h +++ b/com32/include/netinet/in.h @@ -5,6 +5,7 @@ #include <stdint.h> #include <klibc/compiler.h> +#include <klibc/extern.h> #define __htons_macro(v) ((uint16_t) \ (((uint16_t)(v) << 8) | \ @@ -53,4 +54,6 @@ struct in_addr { in_addr_t s_addr; }; +__extern char *inet_ntoa(struct in_addr); + #endif /* _NETINET_IN_H */ diff --git a/com32/include/stdint.h b/com32/include/stdint.h index a8391bf9..f64f0278 100644 --- a/com32/include/stdint.h +++ b/com32/include/stdint.h @@ -5,138 +5,112 @@ #ifndef _STDINT_H #define _STDINT_H -/* Exact types */ +#include <bitsize/stdint.h> -typedef signed char int8_t; -typedef signed short int16_t; -typedef signed int int32_t; -typedef signed long long int64_t; +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; -typedef unsigned long long uint64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; -/* Small types */ +typedef int8_t int_fast8_t; +typedef int64_t int_fast64_t; -typedef signed char int_least8_t; -typedef signed short int_least16_t; -typedef signed int int_least32_t; -typedef signed long long int_least64_t; +typedef uint8_t uint_fast8_t; +typedef uint64_t uint_fast64_t; -typedef unsigned char uint_least8_t; -typedef unsigned short uint_least16_t; -typedef unsigned int uint_least32_t; -typedef unsigned long long uint_least64_t; +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; -/* Fast types */ - -typedef signed char int_fast8_t; -typedef signed short int_fast16_t; -typedef signed int int_fast32_t; -typedef signed long long int_fast64_t; - -typedef unsigned char uint_fast8_t; -typedef unsigned short uint_fast16_t; -typedef unsigned int uint_fast32_t; -typedef unsigned long long uint_fast64_t; - -/* Pointer types */ - -typedef int32_t intptr_t; -typedef uint32_t uintptr_t; +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) -/* Maximal types */ +#define INT8_MIN (-128) +#define INT16_MIN (-32768) +#define INT32_MIN (-2147483647-1) +#define INT64_MIN (__INT64_C(-9223372036854775807)-1) -typedef int64_t intmax_t; -typedef uint64_t uintmax_t; +#define INT8_MAX (127) +#define INT16_MAX (32767) +#define INT32_MAX (2147483647) +#define INT64_MAX (__INT64_C(9223372036854775807)) -/* - * To be strictly correct... - */ -#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) +#define UINT8_MAX (255U) +#define UINT16_MAX (65535U) +#define UINT32_MAX (4294967295U) +#define UINT64_MAX (__UINT64_C(18446744073709551615)) -# define INT8_MIN (-128) -# define INT16_MIN (-32767-1) -# define INT32_MIN (-2147483647-1) -# define INT64_MIN (-9223372036854775807LL-1) +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST64_MIN INT64_MIN -# define INT8_MAX (127) -# define INT16_MAX (32767) -# define INT32_MAX (2147483647) -# define INT64_MAX (9223372036854775807LL) +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MAX INT64_MAX -# define UINT8_MAX (255U) -# define UINT16_MAX (65535U) -# define UINT32_MAX (4294967295U) -# define UINT64_MAX (18446744073709551615ULL) +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX -# define INT_LEAST8_MIN (-128) -# define INT_LEAST16_MIN (-32767-1) -# define INT_LEAST32_MIN (-2147483647-1) -# define INT_LEAST64_MIN (-9223372036854775807LL-1) +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST64_MIN INT64_MIN -# define INT_LEAST8_MAX (127) -# define INT_LEAST16_MAX (32767) -# define INT_LEAST32_MAX (2147483647) -# define INT_LEAST64_MAX (9223372036854775807LL) +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST64_MAX INT64_MAX -# define UINT_LEAST8_MAX (255U) -# define UINT_LEAST16_MAX (65535U) -# define UINT_LEAST32_MAX (4294967295U) -# define UINT_LEAST64_MAX (18446744073709551615ULL) +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST64_MAX UINT64_MAX -# define INT_FAST8_MIN (-128) -# define INT_FAST16_MIN (-32767-1) -# define INT_FAST32_MIN (-2147483647-1) -# define INT_FAST64_MIN (-9223372036854775807LL-1) +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX -# define INT_FAST8_MAX (127) -# define INT_FAST16_MAX (32767) -# define INT_FAST32_MAX (2147483647) -# define INT_FAST64_MAX (9223372036854775807LL) +#include <bitsize/stdintlimits.h> -# define UINT_FAST8_MAX (255U) -# define UINT_FAST16_MAX (65535U) -# define UINT_FAST32_MAX (4294967295U) -# define UINT_FAST64_MAX (18446744073709551615ULL) +#endif -# define INTPTR_MIN (-2147483647-1) -# define INTPTR_MAX (2147483647) -# define UINTPTR_MAX (4294967295U) +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) -# define INTMAX_MIN (-9223372036854775807LL-1) -# define INTMAX_MAX (9223372036854775807LL) -# define UINTMAX_MAX (18446744073709551615ULL) +#define INT8_C(c) c +#define INT16_C(c) c +#define INT32_C(c) c +#define INT64_C(c) __INT64_C(c) -/* ptrdiff_t limit */ -# define PTRDIFF_MIN (-2147483647-1) -# define PTRDIFF_MAX (2147483647) +#define UINT8_C(c) c ## U +#define UINT16_C(c) c ## U +#define UINT32_C(c) c ## U +#define UINT64_C(c) __UINT64_C(c) -/* sig_atomic_t limit */ -# define SIG_ATOMIC_MIN (-2147483647-1) -# define SIG_ATOMIC_MAX (2147483647) +#define INT_LEAST8_C(c) INT8_C(c) +#define INT_LEAST16_C(c) INT16_C(c) +#define INT_LEAST32_C(c) INT32_C(c) +#define INT_LEAST64_C(c) INT64_C(c) -/* size_t limit */ -# define SIZE_MAX (4294967295U) +#define UINT_LEAST8_C(c) UINT8_C(c) +#define UINT_LEAST16_C(c) UINT16_C(c) +#define UINT_LEAST32_C(c) UINT32_C(c) +#define UINT_LEAST64_C(c) UINT64_C(c) -#endif /* STDC_LIMIT_MACROS */ +#define INT_FAST8_C(c) INT8_C(c) +#define INT_FAST64_C(c) INT64_C(c) -#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) +#define UINT_FAST8_C(c) UINT8_C(c) +#define UINT_FAST64_C(c) UINT64_C(c) -# define INT8_C(n) n -# define INT16_C(n) n -# define INT32_C(n) n -# define INT64_C(n) n ## LL +#define INTMAX_C(c) INT64_C(c) +#define UINTMAX_C(c) UINT64_C(c) -# define UINT8_C(n) n ## U -# define UINT16_C(n) n ## U -# define UINT32_C(n) n ## U -# define UINT64_C(n) n ## ULL +#include <bitsize/stdintconst.h> -# define INTMAX_C(n) n ## LL -# define UINTMAX_C(n) n ## ULL +#endif -#endif /* STDC_CONSTANT_MACROS */ +/* Keep the kernel from trying to define these types... */ +#define __BIT_TYPES_DEFINED__ -#endif /* _STDINT_H */ +#endif /* _STDINT_H */ diff --git a/com32/include/string.h b/com32/include/string.h index af9792b6..d847440d 100644 --- a/com32/include/string.h +++ b/com32/include/string.h @@ -42,5 +42,6 @@ __extern char *strsep(char **, const char *); __extern size_t strspn(const char *, const char *); __extern char *strstr(const char *, const char *); __extern char *strtok(char *, const char *); +__extern char *strreplace(const char *, const char *, const char *); #endif /* _STRING_H */ diff --git a/com32/include/syslinux/disk.h b/com32/include/syslinux/disk.h new file mode 100644 index 00000000..f96ca686 --- /dev/null +++ b/com32/include/syslinux/disk.h @@ -0,0 +1,180 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin + * Copyright (C) 2010 Shao Miller + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/** + * @file syslinux/disk.h + * + * Deal with disks and partitions + */ + +#ifndef _SYSLINUX_DISK_H +#define _SYSLINUX_DISK_H + +#include <com32.h> +#include <stdint.h> + +#define SECTOR 512u /* bytes/sector */ + +struct disk_info { + int disk; + int ebios; /* EBIOS supported on this disk */ + int cbios; /* CHS geometry is valid */ + uint32_t bps; /* bytes per sector */ + uint64_t lbacnt; /* total amount of sectors */ + uint32_t cyl; + uint32_t head; + uint32_t spt; +}; + +struct disk_ebios_dapa { + uint16_t len; + uint16_t count; + uint16_t off; + uint16_t seg; + uint64_t lba; +} __attribute__ ((packed)); + +struct disk_ebios_eparam { + uint16_t len; + uint16_t info; + uint32_t cyl; + uint32_t head; + uint32_t spt; + uint64_t lbacnt; + uint16_t bps; /* bytes per sector */ + uint32_t edd; + uint16_t dpi_sig; + uint8_t dpi_len; + char reserved1[3]; + char hostbus[4]; + char if_type[8]; + char if_path[8]; + char dev_path[8]; + char reserved2; + uint8_t checksum; +} __attribute__ ((packed)); + +/** + * CHS (cylinder, head, sector) value extraction macros. + * Taken from WinVBlock. None expand to an lvalue. +*/ +#define chs_head(chs) chs[0] +#define chs_sector(chs) (chs[1] & 0x3F) +#define chs_cyl_high(chs) (((uint16_t)(chs[1] & 0xC0)) << 2) +#define chs_cyl_low(chs) ((uint16_t)chs[2]) +#define chs_cylinder(chs) (chs_cyl_high(chs) | chs_cyl_low(chs)) +typedef uint8_t disk_chs[3]; + +/* A DOS partition table entry */ +struct disk_dos_part_entry { + uint8_t active_flag; /* 0x80 if "active" */ + disk_chs start; + uint8_t ostype; + disk_chs end; + uint32_t start_lba; + uint32_t length; +} __attribute__ ((packed)); + +/* A DOS MBR */ +struct disk_dos_mbr { + char code[440]; + uint32_t disk_sig; + char pad[2]; + struct disk_dos_part_entry table[4]; + uint16_t sig; +} __attribute__ ((packed)); +#define disk_mbr_sig_magic 0xAA55 + +/** + * A GPT disk/partition GUID + * + * Be careful with endianness, you must adjust it yourself + * iff you are directly using the fourth data chunk. + * There might be a better header for this... + */ +struct guid { + uint32_t data1; + uint16_t data2; + uint16_t data3; + uint64_t data4; +} __attribute__ ((packed)); + +/* A GPT partition */ +struct disk_gpt_part_entry { + struct guid type; + struct guid uid; + uint64_t lba_first; + uint64_t lba_last; + uint64_t attribs; + char name[72]; +} __attribute__ ((packed)); + +/* A GPT header */ +struct disk_gpt_header { + char sig[8]; + union { + struct { + uint16_t minor; + uint16_t major; + } fields __attribute__ ((packed)); + uint32_t uint32; + char raw[4]; + } rev __attribute__ ((packed)); + uint32_t hdr_size; + uint32_t chksum; + char reserved1[4]; + uint64_t lba_cur; + uint64_t lba_alt; + uint64_t lba_first_usable; + uint64_t lba_last_usable; + struct guid disk_guid; + uint64_t lba_table; + uint32_t part_count; + uint32_t part_size; + uint32_t table_chksum; + char reserved2[1]; +} __attribute__ ((packed)); +static const char disk_gpt_sig_magic[] = "EFI PART"; + +extern int disk_int13_retry(const com32sys_t * inreg, com32sys_t * outreg); +extern int disk_get_params(int disk, struct disk_info *const diskinfo); +extern void *disk_read_sectors(const struct disk_info *const diskinfo, + uint64_t lba, uint8_t count); +extern int disk_write_sectors(const struct disk_info *const diskinfo, + uint64_t lba, const void *data, uint8_t count); +extern int disk_write_verify_sectors(const struct disk_info *const diskinfo, + uint64_t lba, const void *buf, uint8_t count); +extern void disk_dos_part_dump(const struct disk_dos_part_entry *const part); +extern void guid_to_str(char *buf, const struct guid *const id); +extern int str_to_guid(const char *buf, struct guid *const id); +extern void disk_gpt_part_dump(const struct disk_gpt_part_entry *const + gpt_part); +extern void disk_gpt_header_dump(const struct disk_gpt_header *const gpt); + +#endif /* _SYSLINUX_DISK_H */ diff --git a/com32/include/syslinux/linux.h b/com32/include/syslinux/linux.h index 754d1b64..f5f95fb0 100644 --- a/com32/include/syslinux/linux.h +++ b/com32/include/syslinux/linux.h @@ -1,6 +1,7 @@ /* ----------------------------------------------------------------------- * * * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved + * Copyright 2012 Intel Corporation; author: H. Peter Anvin * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -51,8 +52,26 @@ struct initramfs { }; #define INITRAMFS_MAX_ALIGN 4096 +struct setup_data_header { + uint64_t next; + uint32_t type; + uint32_t len; +} __packed; + +struct setup_data { + struct setup_data *prev, *next; + const void *data; + struct setup_data_header hdr; +}; + +#define SETUP_NONE 0 +#define SETUP_E820_EXT 1 +#define SETUP_DTB 2 + int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, - struct initramfs *initramfs, char *cmdline); + struct initramfs *initramfs, + struct setup_data *setup_data, + char *cmdline); /* Initramfs manipulation functions */ @@ -70,4 +89,12 @@ int initramfs_load_file(struct initramfs *ihead, const char *src_filename, int initramfs_add_trailer(struct initramfs *ihead); int initramfs_load_archive(struct initramfs *ihead, const char *filename); +/* Setup data manipulation functions */ + +struct setup_data *setup_data_init(void); +int setup_data_add(struct setup_data *head, uint32_t type, + const void *data, size_t data_len); +int setup_data_load(struct setup_data *head, uint32_t type, + const char *filename); + #endif /* _SYSLINUX_LINUX_H */ diff --git a/com32/include/syslinux/movebits.h b/com32/include/syslinux/movebits.h index 54ee7ff9..8bcdf3ed 100644 --- a/com32/include/syslinux/movebits.h +++ b/com32/include/syslinux/movebits.h @@ -83,7 +83,12 @@ int syslinux_memmap_find(struct syslinux_memmap *list, addr_t * start, addr_t * len, addr_t align); /* Debugging functions */ -void syslinux_dump_movelist(FILE * file, struct syslinux_movelist *ml); -void syslinux_dump_memmap(FILE * file, struct syslinux_memmap *memmap); +#ifdef DEBUG +void syslinux_dump_movelist(struct syslinux_movelist *ml); +void syslinux_dump_memmap(struct syslinux_memmap *memmap); +#else +#define syslinux_dump_movelist(x) ((void)0) +#define syslinux_dump_memmap(x) ((void)0) +#endif #endif /* _SYSLINUX_MOVEBITS_H */ diff --git a/com32/lib/MCONFIG b/com32/lib/MCONFIG deleted file mode 100644 index 44278bd1..00000000 --- a/com32/lib/MCONFIG +++ /dev/null @@ -1,80 +0,0 @@ -# -*- makefile -*- - -include $(topdir)/MCONFIG - -GCCOPT := $(call gcc_ok,-std=gnu99,) -GCCOPT += $(call gcc_ok,-m32,) -GCCOPT += $(call gcc_ok,-fno-stack-protector,) -GCCOPT += $(call gcc_ok,-fwrapv,) -GCCOPT += $(call gcc_ok,-freg-struct-return,) -GCCOPT += $(call gcc_ok,-fPIE,-fPIC) -GCCOPT += $(call gcc_ok,-fno-exceptions,) -GCCOPT += $(call gcc_ok,-fno-asynchronous-unwind-tables,) -GCCOPT += $(call gcc_ok,-fno-strict-aliasing,) -GCCOPT += $(call gcc_ok,-falign-functions=0,-malign-functions=0) -GCCOPT += $(call gcc_ok,-falign-jumps=0,-malign-jumps=0) -GCCOPT += $(call gcc_ok,-falign-labels=0,-malign-labels=0) -GCCOPT += $(call gcc_ok,-falign-loops=0,-malign-loops=0) -GCCOPT += $(call gcc_ok,-mpreferred-stack-boundary=2,) - -INCLUDE = -I. -STRIP = strip --strip-all -R .comment -R .note - -# zlib and libpng configuration flags -LIBFLAGS = -DDYNAMIC_CRC_TABLE -DPNG_NO_CONSOLE_IO \ - -DPNG_NO_WRITE_SUPPORTED \ - -DPNG_NO_MNG_FEATURES \ - -DPNG_NO_READ_tIME -DPNG_NO_WRITE_tIME - -# We need some features in libpng which apparently aren't available in the -# fixed-point versions. It's OK, because we have to have a non-graphical -# fallback anyway, just use that on old machines... -# LIBFLAGS += -DPNG_NO_FLOATING_POINT_SUPPORTED - -REQFLAGS = $(GCCOPT) -g -mregparm=3 -DREGPARM=3 -D__COM32__ \ - -nostdinc -iwithprefix include -I. -I./sys -I../include -OPTFLAGS = -Os -march=i386 -falign-functions=0 -falign-jumps=0 \ - -falign-labels=0 -ffast-math -fomit-frame-pointer -WARNFLAGS = $(GCCWARN) -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Winline - -CFLAGS = $(OPTFLAGS) $(REQFLAGS) $(WARNFLAGS) $(LIBFLAGS) -LDFLAGS = -m elf32_i386 - -.SUFFIXES: .c .o .a .so .lo .i .S .s .ls .ss .lss - -% : %.c # Cancel default rule - -% : %.S - -.c.o: - $(CC) $(MAKEDEPS) $(CFLAGS) -c -o $@ $< - -.c.i: - $(CC) $(MAKEDEPS) $(CFLAGS) -E -o $@ $< - -.c.s: - $(CC) $(MAKEDEPS) $(CFLAGS) -S -o $@ $< - -.S.o: - $(CC) $(MAKEDEPS) $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $< - -.S.s: - $(CC) $(MAKEDEPS) $(CFLAGS) -D__ASSEMBLY__ -E -o $@ $< - -.S.lo: - $(CC) $(MAKEDEPS) $(CFLAGS) $(SOFLAGS) -D__ASSEMBLY__ -c -o $@ $< - -.S.ls: - $(CC) $(MAKEDEPS) $(CFLAGS) $(SOFLAGS) -D__ASSEMBLY__ -E -o $@ $< - -.s.o: - $(CC) $(MAKEDEPS) $(CFLAGS) -x assembler -c -o $@ $< - -.ls.lo: - $(CC) $(MAKEDEPS) $(CFLAGS) $(SOFLAGS) -x assembler -c -o $@ $< - -.c.lo: - $(CC) $(MAKEDEPS) $(CFLAGS) $(SOFLAGS) -c -o $@ $< - -.c.ls: - $(CC) $(MAKEDEPS) $(CFLAGS) $(SOFLAGS) -S -o $@ $< diff --git a/com32/lib/Makefile b/com32/lib/Makefile index 48a166dd..5ab1fac4 100644 --- a/com32/lib/Makefile +++ b/com32/lib/Makefile @@ -4,8 +4,9 @@ # Include configuration rules NOGPL := 1 -topdir = ../.. -include MCONFIG +topdir = ../../ +MAKEDIR = $(topdir)/mk +include $(MAKEDIR)/lib.mk LIBOBJS = \ abort.o atexit.o atoi.o atol.o atoll.o calloc.o creat.o \ @@ -28,6 +29,10 @@ LIBOBJS = \ asprintf.o vasprintf.o strlcpy.o strlcat.o \ vsscanf.o zalloc.o \ skipspace.o \ + chrreplace.o \ + bufprintf.o \ + inet.o dhcppack.o dhcpunpack.o \ + strreplace.o \ \ lmalloc.o lstrdup.o \ \ @@ -122,7 +127,11 @@ LIBOBJS = \ syslinux/setadv.o \ \ syslinux/video/fontquery.o syslinux/video/forcetext.o \ - syslinux/video/reportmode.o + syslinux/video/reportmode.o \ + \ + syslinux/disk.o \ + \ + syslinux/setup_data.o # These are the objects which are also imported into the core LIBCOREOBJS = \ diff --git a/com32/lib/bufprintf.c b/com32/lib/bufprintf.c new file mode 100644 index 00000000..939bcec3 --- /dev/null +++ b/com32/lib/bufprintf.c @@ -0,0 +1,41 @@ +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <bufprintf.h> + +int vbufprintf(struct print_buf *buf, const char *format, va_list ap) +{ + va_list ap2; + int rv; + + va_copy(ap2, ap); + rv = vsnprintf(NULL, 0, format, ap); + + /* >= to make sure we have space for terminating null */ + if (rv + buf->len >= buf->size) { + size_t newsize = rv + buf->len + BUFPAD; + char *newbuf; + + newbuf = realloc(buf->buf, newsize); + if (!newbuf) + return -1; + + buf->buf = newbuf; + buf->size = newsize; + } + + rv = vsnprintf(buf->buf + buf->len, buf->size - buf->len, format, ap2); + buf->len += rv; + return rv; +} + +int bufprintf(struct print_buf *buf, const char *format, ...) +{ + va_list ap; + int rv; + + va_start(ap, format); + rv = vbufprintf(buf, format, ap); + va_end(ap); + return rv; +} diff --git a/com32/lib/chrreplace.c b/com32/lib/chrreplace.c new file mode 100644 index 00000000..65786f94 --- /dev/null +++ b/com32/lib/chrreplace.c @@ -0,0 +1,11 @@ +#include <ctype.h> + +/* Replace char 'old' by char 'new' in source */ +void chrreplace(char *source, char old, char new) +{ + while (*source) { + source++; + if (source[0] == old) source[0]=new; + } +} + diff --git a/com32/lib/com32.ld b/com32/lib/com32.ld index 37ee46cf..008e4ceb 100644 --- a/com32/lib/com32.ld +++ b/com32/lib/com32.ld @@ -36,36 +36,23 @@ SECTIONS .rodata1 : { *(.rodata1) } __rodata_end = .; - /* Ensure the __preinit_array_start label is properly aligned. We - could instead move the label definition inside the section, but - the linker would then create the section even if it turns out to - be empty, which isn't pretty. */ + /* + * The difference betwee .ctors/.dtors and .init_array/.fini_array + * is the ordering, but we don't use prioritization for libcom32, so + * just lump them all together and hope that's okay. + */ . = ALIGN(4); - .preinit_array : { - PROVIDE (__preinit_array_start = .); - *(.preinit_array) - PROVIDE (__preinit_array_end = .); - } - .init_array : { - PROVIDE (__init_array_start = .); - *(.init_array) - PROVIDE (__init_array_end = .); - } - .fini_array : { - PROVIDE (__fini_array_start = .); - *(.fini_array) - PROVIDE (__fini_array_end = .); - } .ctors : { PROVIDE (__ctors_start = .); - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) + KEEP (*(SORT(.preinit_array*))) + KEEP (*(SORT(.init_array*))) + KEEP (*(SORT(.ctors*))) PROVIDE (__ctors_end = .); } .dtors : { PROVIDE (__dtors_start = .); - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) + KEEP (*(SORT(.fini_array*))) + KEEP (*(SORT(.dtors*))) PROVIDE (__dtors_end = .); } diff --git a/com32/lib/dhcppack.c b/com32/lib/dhcppack.c new file mode 100644 index 00000000..a08583c4 --- /dev/null +++ b/com32/lib/dhcppack.c @@ -0,0 +1,166 @@ +#include <stdlib.h> +#include <errno.h> +#include <string.h> +// #include <arpa/inet.h> +#include <netinet/in.h> + +// #include "dhcp.h" +#include <dhcp.h> + +/* + * Pack DHCP options into an option field, without overload support. + * On return, len contains the number of active bytes, and the full + * field is zero-padded. + * + * Options which are successfully placed have their length zeroed out. + */ +static int dhcp_pack_field_zero(void *field, size_t *len, + struct dhcp_option opt[256]) +{ + int i; + size_t xlen, plen; + const uint8_t *p; + uint8_t *q = field; + size_t spc = *len; + int err = 0; + + if (!*len) + return ENOSPC; + + for (i = 1; i < 255; i++) { + if (opt[i].len < 0) + continue; + + /* We need to handle the 0 case as well as > 255 */ + if (opt[i].len <= 255) + xlen = opt[i].len + 2; + else + xlen = opt[i].len + 2*((opt[i].len+254)/255); + + p = opt[i].data; + + if (xlen >= spc) { + /* This option doesn't fit... */ + err++; + continue; + } + + xlen = opt[i].len; + do { + *q++ = i; + *q++ = plen = xlen > 255 ? 255 : xlen; + if (plen) + memcpy(q, p, plen); + q += plen; + p += plen; + spc -= plen+2; + xlen -= plen; + } while (xlen); + + opt[i].len = -1; + } + + *q++ = 255; /* End marker */ + memset(q, 0, spc); /* Zero-pad the rest of the field */ + + *len = xlen = q - (uint8_t *)field; + return err; +} + +/* + * Pack DHCP options into an option field, without overload support. + * On return, len contains the number of active bytes, and the full + * field is zero-padded. + * + * Use this to encode encapsulated option fields. + */ +int dhcp_pack_field(void *field, size_t *len, + struct dhcp_option opt[256]) +{ + struct dhcp_option ox[256]; + + memcpy(ox, opt, sizeof ox); + return dhcp_pack_field_zero(field, len, ox); +} + +/* + * Pack DHCP options into a packet. + * Apply overloading if (and only if) the "file" or "sname" option + * doesn't fit in the respective dedicated fields. + */ +int dhcp_pack_packet(void *packet, size_t *len, + const struct dhcp_option opt[256]) +{ + struct dhcp_packet *pkt = packet; + size_t spc = *len; + uint8_t overload; + struct dhcp_option ox[256]; + uint8_t *q; + int err; + + if (spc < sizeof(struct dhcp_packet)) + return ENOSPC; /* Buffer impossibly small */ + + pkt->magic = htonl(DHCP_VENDOR_MAGIC); + + memcpy(ox, opt, sizeof ox); + + /* Figure out if we should do overloading or not */ + overload = 0; + + if (opt[67].len > 128) + overload |= 1; + else + ox[67].len = -1; + + if (opt[66].len > 64) + overload |= 2; + else + ox[66].len = -1; + + /* Kill any passed-in overload option */ + ox[52].len = -1; + + q = pkt->options; + spc -= 240; + + /* Force option 53 (DHCP packet type) first */ + if (ox[53].len == 1) { + *q++ = 53; + *q++ = 1; + *q++ = *(uint8_t *)ox[53].data; + spc -= 3; + ox[53].len = -1; + } + + /* Follow with the overload option, if applicable */ + if (overload) { + *q++ = 52; + *q++ = 1; + *q++ = overload; + spc -= 3; + } + + err = dhcp_pack_field_zero(q, &spc, ox); + *len = spc + (q-(uint8_t *)packet); + + if (overload & 1) { + spc = 128; + err = dhcp_pack_field_zero(pkt->file, &spc, ox); + } else { + memset(pkt->file, 0, 128); + if (opt[67].len > 0) + memcpy(pkt->file, opt[67].data, opt[67].len); + } + + if (overload & 2) { + spc = 64; + err = dhcp_pack_field_zero(pkt->sname, &spc, ox); + } else { + memset(pkt->sname, 0, 64); + if (opt[66].len > 0) + memcpy(pkt->sname, opt[66].data, opt[66].len); + } + + return err; +} diff --git a/com32/lib/dhcpunpack.c b/com32/lib/dhcpunpack.c new file mode 100644 index 00000000..248173a8 --- /dev/null +++ b/com32/lib/dhcpunpack.c @@ -0,0 +1,116 @@ +#define _GNU_SOURCE /* For strnlen() */ +#include <stdlib.h> +#include <errno.h> +#include <string.h> +// #include <arpa/inet.h> +#include <netinet/in.h> + +// #include "dhcp.h" +#include <dhcp.h> + +/* + * Unpack DHCP options from a field. Assumes opt is pre-initalized + * (to all zero in the common case.) + */ +int dhcp_unpack_field(const void *field, size_t len, + struct dhcp_option opt[256]) +{ + const uint8_t *p = field; + int err = 0; + + while (len > 1) { + uint8_t op; + size_t xlen; + + op = *p++; len--; + if (op == 0) + continue; + else if (op == 255) + break; + + xlen = *p++; len--; + if (xlen > len) + break; + if (opt[op].len < 0) + opt[op].len = 0; + if (xlen) { + opt[op].data = realloc(opt[op].data, + opt[op].len + xlen + 1); + if (!opt[op].data) { + err = ENOMEM; + continue; + } + memcpy((char *)opt[op].data + opt[op].len, p, xlen); + opt[op].len += xlen; + /* Null-terminate as a courtesy to users */ + *((char *)opt[op].data + opt[op].len) = 0; + p += xlen; + len -= xlen; + } + } + + return err; +} + +/* + * Unpack a DHCP packet, with overload support. Do not use this + * to unpack an encapsulated option set. + */ +int dhcp_unpack_packet(const void *packet, size_t len, + struct dhcp_option opt[256]) +{ + const struct dhcp_packet *pkt = packet; + int err; + uint8_t overload; + int i; + + if (len < 240 || pkt->magic != htonl(DHCP_VENDOR_MAGIC)) + return EINVAL; /* Bogus packet */ + + for (i = 0; i < 256; i++) { + opt[i].len = -1; /* Option not present */ + opt[i].data = NULL; + } + + err = dhcp_unpack_field(pkt->options, len-240, opt); + + overload = 0; + if (opt[52].len == 1) { + overload = *(uint8_t *)opt[52].data; + free(opt[52].data); + opt[52].len = -1; + opt[52].data = NULL; + } + + if (overload & 1) { + err |= dhcp_unpack_field(pkt->file, 128, opt); + } else { + opt[67].len = strnlen((const char *)pkt->file, 128); + if (opt[67].len) { + opt[67].data = malloc(opt[67].len + 1); + if (opt[67].data) { + memcpy(opt[67].data, pkt->file, opt[67].len); + *((char *)opt[67].data + opt[67].len) = 0; + } else { + err |= ENOMEM; + } + } + } + + if (overload & 2) { + err |= dhcp_unpack_field(pkt->sname, 64, opt); + } else { + opt[66].len = strnlen((const char *)pkt->sname, 64); + if (opt[66].len) { + opt[66].data = malloc(opt[66].len + 1); + if (opt[66].data) { + memcpy(opt[66].data, pkt->file, opt[66].len); + *((char *)opt[66].data + opt[66].len) = 0; + } else { + err |= ENOMEM; + } + } + } + + return err; +} diff --git a/com32/lib/dprintf.c b/com32/lib/dprintf.c index 900c0a47..aad11746 100644 --- a/com32/lib/dprintf.c +++ b/com32/lib/dprintf.c @@ -9,6 +9,7 @@ #define DEBUG 1 #include <dprintf.h> +#ifndef dprintf void dprintf(const char *format, ...) { va_list ap; @@ -17,3 +18,4 @@ void dprintf(const char *format, ...) vdprintf(format, ap); va_end(ap); } +#endif diff --git a/com32/lib/inet.c b/com32/lib/inet.c new file mode 100644 index 00000000..133645ed --- /dev/null +++ b/com32/lib/inet.c @@ -0,0 +1,39 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2011 Erwan Velu - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- + */ + +#include <stdio.h> +#include <netinet/in.h> + +char *inet_ntoa(struct in_addr addr) +{ + static char buf[16]; + const uint8_t *bytes = (const uint8_t *)&addr.s_addr; + + sprintf(buf, "%u.%u.%u.%u", bytes[0], bytes[1], bytes[2], bytes[3]); + return buf; +} diff --git a/com32/lib/pci/scan.c b/com32/lib/pci/scan.c index c8334b11..fe00fc25 100644 --- a/com32/lib/pci/scan.c +++ b/com32/lib/pci/scan.c @@ -41,12 +41,7 @@ #include <stdbool.h> #include <ctype.h> #include <syslinux/zio.h> - -#ifdef DEBUG -# define dprintf printf -#else -# define dprintf(...) ((void)0) -#endif +#include <dprintf.h> #define MAX_LINE 512 @@ -66,15 +61,6 @@ static int hex_to_int(char *hexa) return strtoul(hexa, NULL, 16); } -/* Replace char 'old' by char 'new' in source */ -void chr_replace(char *source, char old, char new) -{ - while (*source) { - source++; - if (source[0] == old) source[0]=new; - } -} - /* Try to match any pci device to the appropriate kernel module */ /* it uses the modules.pcimap from the boot device */ int get_module_name_from_pcimap(struct pci_domain *domain, @@ -135,7 +121,7 @@ int get_module_name_from_pcimap(struct pci_domain *domain, * in the module name whereas modules.alias is only using '_'. * To avoid kernel modules duplication, let's rename all '-' in '_' * to match what modules.alias provides */ - case 0:chr_replace(result,'-','_');strcpy(module_name,result); break; + case 0:chrreplace(result,'-','_');strcpy(module_name,result); break; case 1:strcpy(vendor_id,result); break; case 2:strcpy(product_id,result); break; case 3:strcpy(sub_vendor_id,result); break; @@ -593,14 +579,14 @@ void free_pci_domain(struct pci_domain *domain) free(func->dev_info); free(func); } - free(slot); } + free(slot); } - free(bus); } + free(bus); } - free(domain); } + free(domain); } } diff --git a/com32/lib/strreplace.c b/com32/lib/strreplace.c new file mode 100644 index 00000000..d59efe0e --- /dev/null +++ b/com32/lib/strreplace.c @@ -0,0 +1,58 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2011 Erwan Velu - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- + */ + +#include <string.h> +#include <stdlib.h> + +char *strreplace(const char *string, const char *string_to_replace, + const char *string_to_insert) +{ + char *token = NULL; + char *out = NULL; + + size_t slen, srlen, silen; + + token = strstr(string, string_to_replace); + if (!token) + return strdup(string); + + slen = strlen(string); + srlen = strlen(string_to_replace); + silen = strlen(string_to_insert); + + out = malloc(slen - srlen + silen + 1); + if (!out) + return NULL; + + memcpy(out, string, token - string); + memcpy(out + (token - string), string_to_insert, silen); + memcpy(out + (token - string) + silen, token + srlen, + slen - srlen - (token - string) + 1); + + return out; +} diff --git a/com32/lib/syslinux/disk.c b/com32/lib/syslinux/disk.c new file mode 100644 index 00000000..d6409af6 --- /dev/null +++ b/com32/lib/syslinux/disk.c @@ -0,0 +1,534 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin + * Copyright (C) 2010 Shao Miller + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/** + * @file disk.c + * + * Deal with disks and partitions + */ + +#include <dprintf.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslinux/disk.h> + +/** + * Call int 13h, but with retry on failure. Especially floppies need this. + * + * @v inreg CPU register settings upon INT call + * @v outreg CPU register settings returned by INT call + * @ret (int) 0 upon success, -1 upon failure + */ +int disk_int13_retry(const com32sys_t * inreg, com32sys_t * outreg) +{ + int retry = 6; /* Number of retries */ + com32sys_t tmpregs; + + if (!outreg) + outreg = &tmpregs; + + while (retry--) { + __intcall(0x13, inreg, outreg); + if (!(outreg->eflags.l & EFLAGS_CF)) + return 0; /* CF=0, OK */ + } + + return -1; /* Error */ +} + +/** + * Query disk parameters and EBIOS availability for a particular disk. + * + * @v disk The INT 0x13 disk drive number to process + * @v diskinfo The structure to save the queried params to + * @ret (int) 0 upon success, -1 upon failure + */ +int disk_get_params(int disk, struct disk_info *const diskinfo) +{ + static com32sys_t inreg, outreg; + struct disk_ebios_eparam *eparam = __com32.cs_bounce; + + memset(diskinfo, 0, sizeof *diskinfo); + diskinfo->disk = disk; + diskinfo->bps = SECTOR; + + /* Get EBIOS support */ + memset(&inreg, 0, sizeof inreg); + inreg.eax.b[1] = 0x41; + inreg.ebx.w[0] = 0x55aa; + inreg.edx.b[0] = disk; + inreg.eflags.b[0] = 0x3; /* CF set */ + + __intcall(0x13, &inreg, &outreg); + + if (!(outreg.eflags.l & EFLAGS_CF) && + outreg.ebx.w[0] == 0xaa55 && (outreg.ecx.b[0] & 1)) { + diskinfo->ebios = 1; + } + + /* Get extended disk parameters if ebios == 1 */ + if (diskinfo->ebios) { + memset(&inreg, 0, sizeof inreg); + inreg.eax.b[1] = 0x48; + inreg.edx.b[0] = disk; + inreg.esi.w[0] = OFFS(eparam); + inreg.ds = SEG(eparam); + + memset(eparam, 0, sizeof *eparam); + eparam->len = sizeof *eparam; + + __intcall(0x13, &inreg, &outreg); + + if (!(outreg.eflags.l & EFLAGS_CF)) { + diskinfo->lbacnt = eparam->lbacnt; + if (eparam->bps) + diskinfo->bps = eparam->bps; + /* + * don't think about using geometry data returned by + * 48h, as it can differ from 08h a lot ... + */ + } + } + /* + * Get disk parameters the old way - really only useful for hard + * disks, but if we have a partitioned floppy it's actually our best + * chance... + */ + memset(&inreg, 0, sizeof inreg); + inreg.eax.b[1] = 0x08; + inreg.edx.b[0] = disk; + + __intcall(0x13, &inreg, &outreg); + + if (outreg.eflags.l & EFLAGS_CF) + return diskinfo->ebios ? 0 : -1; + + diskinfo->spt = 0x3f & outreg.ecx.b[0]; + diskinfo->head = 1 + outreg.edx.b[1]; + diskinfo->cyl = 1 + (outreg.ecx.b[1] | ((outreg.ecx.b[0] & 0xc0u) << 2)); + + if (diskinfo->spt) + diskinfo->cbios = 1; /* Valid geometry */ + else { + diskinfo->head = 1; + diskinfo->spt = 1; + diskinfo->cyl = 1; + } + + if (!diskinfo->lbacnt) + diskinfo->lbacnt = diskinfo->cyl * diskinfo->head * diskinfo->spt; + + return 0; +} + +/** + * Get disk block(s) and return a malloc'd buffer. + * + * @v diskinfo The disk drive to read from + * @v lba The logical block address to begin reading at + * @v count The number of sectors to read + * @ret data An allocated buffer with the read data + * + * Uses the disk number and information from diskinfo. Read count sectors + * from drive, starting at lba. Return a new buffer, or NULL upon failure. + */ +void *disk_read_sectors(const struct disk_info *const diskinfo, uint64_t lba, + uint8_t count) +{ + com32sys_t inreg; + struct disk_ebios_dapa *dapa = __com32.cs_bounce; + void *buf = (char *)__com32.cs_bounce + diskinfo->bps; + void *data; + uint32_t maxcnt; + + maxcnt = (__com32.cs_bounce_size - diskinfo->bps) / diskinfo->bps; + if (!count || count > maxcnt || lba + count > diskinfo->lbacnt) + return NULL; + + memset(&inreg, 0, sizeof inreg); + + if (diskinfo->ebios) { + dapa->len = sizeof(*dapa); + dapa->count = count; + dapa->off = OFFS(buf); + dapa->seg = SEG(buf); + dapa->lba = lba; + + inreg.esi.w[0] = OFFS(dapa); + inreg.ds = SEG(dapa); + inreg.edx.b[0] = diskinfo->disk; + inreg.eax.b[1] = 0x42; /* Extended read */ + } else { + unsigned int c, h, s, t; + /* + * if we passed lba + count check and we get here, that means that + * lbacnt was calculated from chs geometry (or faked from 1/1/1), thus + * 32bits are perfectly enough and lbacnt corresponds to cylinder + * boundary + */ + s = lba % diskinfo->spt; + t = lba / diskinfo->spt; + h = t % diskinfo->head; + c = t / diskinfo->head; + + inreg.eax.b[0] = count; + inreg.eax.b[1] = 0x02; /* Read */ + inreg.ecx.b[1] = c; + inreg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1); + inreg.edx.b[1] = h; + inreg.edx.b[0] = diskinfo->disk; + inreg.ebx.w[0] = OFFS(buf); + inreg.es = SEG(buf); + } + + if (disk_int13_retry(&inreg, NULL)) + return NULL; + + data = malloc(count * diskinfo->bps); + if (data) + memcpy(data, buf, count * diskinfo->bps); + return data; +} + +/** + * Write disk block(s). + * + * @v diskinfo The disk drive to write to + * @v lba The logical block address to begin writing at + * @v data The data to write + * @v count The number of sectors to write + * @ret (int) 0 upon success, -1 upon failure + * + * Uses the disk number and information from diskinfo. + * Write sector(s) to a disk drive, starting at lba. + */ +int disk_write_sectors(const struct disk_info *const diskinfo, uint64_t lba, + const void *data, uint8_t count) +{ + com32sys_t inreg; + struct disk_ebios_dapa *dapa = __com32.cs_bounce; + void *buf = (char *)__com32.cs_bounce + diskinfo->bps; + uint32_t maxcnt; + + maxcnt = (__com32.cs_bounce_size - diskinfo->bps) / diskinfo->bps; + if (!count || count > maxcnt || lba + count > diskinfo->lbacnt) + return -1; + + memcpy(buf, data, count * diskinfo->bps); + memset(&inreg, 0, sizeof inreg); + + if (diskinfo->ebios) { + dapa->len = sizeof(*dapa); + dapa->count = count; + dapa->off = OFFS(buf); + dapa->seg = SEG(buf); + dapa->lba = lba; + + inreg.esi.w[0] = OFFS(dapa); + inreg.ds = SEG(dapa); + inreg.edx.b[0] = diskinfo->disk; + inreg.eax.b[1] = 0x43; /* Extended write */ + } else { + unsigned int c, h, s, t; + /* + * if we passed lba + count check and we get here, that means that + * lbacnt was calculated from chs geometry (or faked from 1/1/1), thus + * 32bits are perfectly enough and lbacnt corresponds to cylinder + * boundary + */ + s = lba % diskinfo->spt; + t = lba / diskinfo->spt; + h = t % diskinfo->head; + c = t / diskinfo->head; + + inreg.eax.b[0] = count; + inreg.eax.b[1] = 0x03; /* Write */ + inreg.ecx.b[1] = c; + inreg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1); + inreg.edx.b[1] = h; + inreg.edx.b[0] = diskinfo->disk; + inreg.ebx.w[0] = OFFS(buf); + inreg.es = SEG(buf); + } + + if (disk_int13_retry(&inreg, NULL)) + return -1; + + return 0; /* ok */ +} + +/** + * Write disk blocks and verify they were written. + * + * @v diskinfo The disk drive to write to + * @v lba The logical block address to begin writing at + * @v buf The data to write + * @v count The number of sectors to write + * @ret rv 0 upon success, -1 upon failure + * + * Uses the disk number and information from diskinfo. + * Writes sectors to a disk drive starting at lba, then reads them back + * to verify they were written correctly. + */ +int disk_write_verify_sectors(const struct disk_info *const diskinfo, + uint64_t lba, const void *buf, uint8_t count) +{ + char *rb; + int rv; + + rv = disk_write_sectors(diskinfo, lba, buf, count); + if (rv) + return rv; /* Write failure */ + rb = disk_read_sectors(diskinfo, lba, count); + if (!rb) + return -1; /* Readback failure */ + rv = memcmp(buf, rb, count * diskinfo->bps); + free(rb); + return rv ? -1 : 0; +} + +/** + * Dump info about a DOS partition entry + * + * @v part The 16-byte partition entry to examine + */ +void disk_dos_part_dump(const struct disk_dos_part_entry *const part) +{ + (void)part; + dprintf("Partition status _____ : 0x%.2x\n" + "Partition CHS start\n" + " Cylinder ___________ : 0x%.4x (%u)\n" + " Head _______________ : 0x%.2x (%u)\n" + " Sector _____________ : 0x%.2x (%u)\n" + "Partition type _______ : 0x%.2x\n" + "Partition CHS end\n" + " Cylinder ___________ : 0x%.4x (%u)\n" + " Head _______________ : 0x%.2x (%u)\n" + " Sector _____________ : 0x%.2x (%u)\n" + "Partition LBA start __ : 0x%.8x (%u)\n" + "Partition LBA count __ : 0x%.8x (%u)\n" + "-------------------------------\n", + part->active_flag, + chs_cylinder(part->start), + chs_cylinder(part->start), + chs_head(part->start), + chs_head(part->start), + chs_sector(part->start), + chs_sector(part->start), + part->ostype, + chs_cylinder(part->end), + chs_cylinder(part->end), + chs_head(part->end), + chs_head(part->end), + chs_sector(part->end), + chs_sector(part->end), + part->start_lba, part->start_lba, part->length, part->length); +} + +/* Trivial error message output */ +static inline void error(const char *msg) +{ + fputs(msg, stderr); +} + +/** + * This walk-map effectively reverses the little-endian + * portions of a GPT disk/partition GUID for a string representation. + * There might be a better header for this... + */ +static const char guid_le_walk_map[] = { + 3, -1, -1, -1, 0, + 5, -1, 0, + 3, -1, 0, + 2, 1, 0, + 1, 1, 1, 1, 1, 1 +}; + +/** + * Fill a buffer with a textual GUID representation. + * + * @v buf Points to a minimum array of 37 chars + * @v id The GUID to represent as text + * + * The buffer must be >= char[37] and will be populated + * with an ASCII NUL C string terminator. + * Example: 11111111-2222-3333-4444-444444444444 + * Endian: LLLLLLLL-LLLL-LLLL-BBBB-BBBBBBBBBBBB + */ +void guid_to_str(char *buf, const struct guid *const id) +{ + unsigned int i = 0; + const char *walker = (const char *)id; + + while (i < sizeof(guid_le_walk_map)) { + walker += guid_le_walk_map[i]; + if (!guid_le_walk_map[i]) + *buf = '-'; + else { + *buf = ((*walker & 0xF0) >> 4) + '0'; + if (*buf > '9') + *buf += 'A' - '9' - 1; + buf++; + *buf = (*walker & 0x0F) + '0'; + if (*buf > '9') + *buf += 'A' - '9' - 1; + } + buf++; + i++; + } + *buf = 0; +} + +/** + * Create a GUID structure from a textual GUID representation. + * + * @v buf Points to a GUID string to parse + * @v id Points to a GUID to be populated + * @ret (int) Returns 0 upon success, -1 upon failure + * + * The input buffer must be >= 32 hexadecimal chars and be + * terminated with an ASCII NUL. Returns non-zero on failure. + * Example: 11111111-2222-3333-4444-444444444444 + * Endian: LLLLLLLL-LLLL-LLLL-BBBB-BBBBBBBBBBBB + */ +int str_to_guid(const char *buf, struct guid *const id) +{ + char guid_seq[sizeof(struct guid) * 2]; + unsigned int i = 0; + char *walker = (char *)id; + + while (*buf && i < sizeof(guid_seq)) { + switch (*buf) { + /* Skip these three characters */ + case '{': + case '}': + case '-': + break; + default: + /* Copy something useful to the temp. sequence */ + if ((*buf >= '0') && (*buf <= '9')) + guid_seq[i] = *buf - '0'; + else if ((*buf >= 'A') && (*buf <= 'F')) + guid_seq[i] = *buf - 'A' + 10; + else if ((*buf >= 'a') && (*buf <= 'f')) + guid_seq[i] = *buf - 'a' + 10; + else { + /* Or not */ + error("Illegal character in GUID!\n"); + return -1; + } + i++; + } + buf++; + } + /* Check for insufficient valid characters */ + if (i < sizeof(guid_seq)) { + error("Too few GUID characters!\n"); + return -1; + } + buf = guid_seq; + i = 0; + while (i < sizeof(guid_le_walk_map)) { + if (!guid_le_walk_map[i]) + i++; + walker += guid_le_walk_map[i]; + *walker = *buf << 4; + buf++; + *walker |= *buf; + buf++; + i++; + } + return 0; +} + +/** + * Display GPT partition details. + * + * @v gpt_part The GPT partition entry to display + */ +void disk_gpt_part_dump(const struct disk_gpt_part_entry *const gpt_part) +{ + unsigned int i; + char guid_text[37]; + + dprintf("----------------------------------\n" + "GPT part. LBA first __ : 0x%.16llx\n" + "GPT part. LBA last ___ : 0x%.16llx\n" + "GPT part. attribs ____ : 0x%.16llx\n" + "GPT part. name _______ : '", + gpt_part->lba_first, gpt_part->lba_last, gpt_part->attribs); + for (i = 0; i < sizeof(gpt_part->name); i++) { + if (gpt_part->name[i]) + dprintf("%c", gpt_part->name[i]); + } + dprintf("'"); + guid_to_str(guid_text, &gpt_part->type); + dprintf("GPT part. type GUID __ : {%s}\n", guid_text); + guid_to_str(guid_text, &gpt_part->uid); + dprintf("GPT part. unique ID __ : {%s}\n", guid_text); +} + +/** + * Display GPT header details. + * + * @v gpt The GPT header to display + */ +void disk_gpt_header_dump(const struct disk_gpt_header *const gpt) +{ + char guid_text[37]; + + printf("GPT sig ______________ : '%8.8s'\n" + "GPT major revision ___ : 0x%.4x\n" + "GPT minor revision ___ : 0x%.4x\n" + "GPT header size ______ : 0x%.8x\n" + "GPT header checksum __ : 0x%.8x\n" + "GPT reserved _________ : '%4.4s'\n" + "GPT LBA current ______ : 0x%.16llx\n" + "GPT LBA alternative __ : 0x%.16llx\n" + "GPT LBA first usable _ : 0x%.16llx\n" + "GPT LBA last usable __ : 0x%.16llx\n" + "GPT LBA part. table __ : 0x%.16llx\n" + "GPT partition count __ : 0x%.8x\n" + "GPT partition size ___ : 0x%.8x\n" + "GPT part. table chksum : 0x%.8x\n", + gpt->sig, + gpt->rev.fields.major, + gpt->rev.fields.minor, + gpt->hdr_size, + gpt->chksum, + gpt->reserved1, + gpt->lba_cur, + gpt->lba_alt, + gpt->lba_first_usable, + gpt->lba_last_usable, + gpt->lba_table, gpt->part_count, gpt->part_size, gpt->table_chksum); + guid_to_str(guid_text, &gpt->disk_guid); + printf("GPT disk GUID ________ : {%s}\n", guid_text); +} diff --git a/com32/lib/syslinux/dump_mmap.c b/com32/lib/syslinux/dump_mmap.c index 3f1e340b..85638cd9 100644 --- a/com32/lib/syslinux/dump_mmap.c +++ b/com32/lib/syslinux/dump_mmap.c @@ -28,20 +28,22 @@ /* * dump_mmap.c * - * Writes a syslinux_memmap out to a specified file. This is - * intended for debugging. + * Writes a syslinux_memmap out to a dprintf. */ #include <stdio.h> +#include <dprintf.h> #include <syslinux/movebits.h> -void syslinux_dump_memmap(FILE * file, struct syslinux_memmap *memmap) +#ifdef DEBUG +void syslinux_dump_memmap(struct syslinux_memmap *memmap) { - fprintf(file, "%10s %10s %10s\n" + dprintf("%10s %10s %10s\n" "--------------------------------\n", "Start", "Length", "Type"); while (memmap->next) { - fprintf(file, "0x%08x 0x%08x %10d\n", memmap->start, + dprintf("0x%08x 0x%08x %10d\n", memmap->start, memmap->next->start - memmap->start, memmap->type); memmap = memmap->next; } } +#endif diff --git a/com32/lib/syslinux/dump_movelist.c b/com32/lib/syslinux/dump_movelist.c index 282d0068..4042ce96 100644 --- a/com32/lib/syslinux/dump_movelist.c +++ b/com32/lib/syslinux/dump_movelist.c @@ -33,14 +33,17 @@ */ #include <stdio.h> +#include <dprintf.h> #include <syslinux/movebits.h> -void syslinux_dump_movelist(FILE * file, struct syslinux_movelist *ml) +#ifdef DEBUG +void syslinux_dump_movelist(struct syslinux_movelist *ml) { - fprintf(file, "%10s %10s %10s\n" + dprintf("%10s %10s %10s\n" "--------------------------------\n", "Dest", "Src", "Length"); while (ml) { - fprintf(file, "0x%08x 0x%08x 0x%08x\n", ml->dst, ml->src, ml->len); + dprintf("0x%08x 0x%08x 0x%08x\n", ml->dst, ml->src, ml->len); ml = ml->next; } } +#endif diff --git a/com32/lib/syslinux/load_linux.c b/com32/lib/syslinux/load_linux.c index c1ce875c..856141f8 100644 --- a/com32/lib/syslinux/load_linux.c +++ b/com32/lib/syslinux/load_linux.c @@ -38,21 +38,13 @@ #include <inttypes.h> #include <string.h> #include <minmax.h> +#include <errno.h> #include <suffix_number.h> #include <syslinux/align.h> #include <syslinux/linux.h> #include <syslinux/bootrm.h> #include <syslinux/movebits.h> - -#ifndef DEBUG -# define DEBUG 0 -#endif -#if DEBUG -# include <stdio.h> -# define dprintf printf -#else -# define dprintf(f, ...) ((void)0) -#endif +#include <dprintf.h> struct linux_header { uint8_t boot_sector_1[0x0020]; @@ -189,13 +181,16 @@ static int map_initramfs(struct syslinux_movelist **fraglist, } int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, - struct initramfs *initramfs, char *cmdline) + struct initramfs *initramfs, + struct setup_data *setup_data, + char *cmdline) { struct linux_header hdr, *whdr; size_t real_mode_size, prot_mode_size; addr_t real_mode_base, prot_mode_base; addr_t irf_size; size_t cmdline_size, cmdline_offset; + struct setup_data *sdp; struct syslinux_rm_regs regs; struct syslinux_movelist *fraglist = NULL; struct syslinux_memmap *mmap = NULL; @@ -318,10 +313,8 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, if (!mmap || !amap) goto bail; -#if DEBUG dprintf("Initial memory map:\n"); - syslinux_dump_memmap(stdout, mmap); -#endif + syslinux_dump_memmap(mmap); /* If the user has specified a memory limit, mark that as unavailable. Question: should we mark this off-limit in the mmap as well (meaning @@ -460,6 +453,49 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, } } + if (setup_data) { + uint64_t *prev_ptr = &whdr->setup_data; + + for (sdp = setup_data->next; sdp != setup_data; sdp = sdp->next) { + struct syslinux_memmap *ml; + const addr_t align_mask = 15; /* Header is 16 bytes */ + addr_t best_addr = 0; + size_t size = sdp->hdr.len + sizeof(sdp->hdr); + + if (!sdp->data || !sdp->hdr.len) + continue; + + if (hdr.version < 0x0209) { + /* Setup data not supported */ + errno = ENXIO; /* Kind of arbitrary... */ + goto bail; + } + + for (ml = amap; ml->type != SMT_END; ml = ml->next) { + addr_t adj_start = (ml->start + align_mask) & ~align_mask; + addr_t adj_end = ml->next->start & ~align_mask; + + if (ml->type == SMT_FREE && adj_end - adj_start >= size) + best_addr = (adj_end - size) & ~align_mask; + } + + if (!best_addr) + goto bail; + + *prev_ptr = best_addr; + prev_ptr = &sdp->hdr.next; + + if (syslinux_add_memmap(&amap, best_addr, size, SMT_ALLOC)) + goto bail; + if (syslinux_add_movelist(&fraglist, best_addr, + (addr_t)&sdp->hdr, sizeof sdp->hdr)) + goto bail; + if (syslinux_add_movelist(&fraglist, best_addr + sizeof sdp->hdr, + (addr_t)sdp->data, sdp->hdr.len)) + goto bail; + } + } + /* Set up the registers on entry */ memset(®s, 0, sizeof regs); regs.es = regs.ds = regs.ss = regs.fs = regs.gs = real_mode_base >> 4; @@ -468,16 +504,14 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, /* Linux is OK with sp = 0 = 64K, but perhaps other things aren't... */ regs.esp.w[0] = min(cmdline_offset, (size_t) 0xfff0); -#if DEBUG dprintf("Final memory map:\n"); - syslinux_dump_memmap(stdout, mmap); + syslinux_dump_memmap(mmap); dprintf("Final available map:\n"); - syslinux_dump_memmap(stdout, amap); + syslinux_dump_memmap(amap); dprintf("Initial movelist:\n"); - syslinux_dump_movelist(stdout, fraglist); -#endif + syslinux_dump_movelist(fraglist); syslinux_shuffle_boot_rm(fraglist, mmap, 0, ®s); diff --git a/com32/lib/syslinux/movebits.c b/com32/lib/syslinux/movebits.c index bd5ce0e8..7a05f3c1 100644 --- a/com32/lib/syslinux/movebits.c +++ b/com32/lib/syslinux/movebits.c @@ -48,21 +48,7 @@ #include <stdbool.h> #include <syslinux/movebits.h> - -#ifndef DEBUG -# ifdef TEST -# define DEBUG 1 -# else -# define DEBUG 0 -# endif -#endif - -#if DEBUG -# include <stdio.h> -# define dprintf printf -#else -# define dprintf(...) ((void)0) -#endif +#include <dprintf.h> static jmp_buf new_movelist_bail; @@ -242,10 +228,8 @@ static void shuffle_dealias(struct syslinux_movelist **fraglist, addr_t ps, pe, xs, xe, delta; bool advance; -#if DEBUG dprintf("Before alias resolution:\n"); - syslinux_dump_movelist(stdout, *fraglist); -#endif + syslinux_dump_movelist(*fraglist); *postcopy = NULL; @@ -316,12 +300,10 @@ restart: ; } -#if DEBUG dprintf("After alias resolution:\n"); - syslinux_dump_movelist(stdout, *fraglist); + syslinux_dump_movelist(*fraglist); dprintf("Post-shuffle copies:\n"); - syslinux_dump_movelist(stdout, *postcopy); -#endif + syslinux_dump_movelist(*postcopy); } /* @@ -449,12 +431,10 @@ nomem: /* As long as there are unprocessed fragments in the chain... */ while ((fp = &frags, f = *fp)) { -#if DEBUG dprintf("Current free list:\n"); - syslinux_dump_memmap(stdout, mmap); + syslinux_dump_memmap(mmap); dprintf("Current frag list:\n"); - syslinux_dump_movelist(stdout, frags); -#endif + syslinux_dump_movelist(frags); /* Scan for fragments which can be discarded without action. */ if (f->src == f->dst) { @@ -692,16 +672,16 @@ int main(int argc, char *argv[]) *fep = NULL; - printf("Input move list:\n"); - syslinux_dump_movelist(stdout, frags); - printf("Input free list:\n"); - syslinux_dump_memmap(stdout, memmap); + dprintf("Input move list:\n"); + syslinux_dump_movelist(frags); + dprintf("Input free list:\n"); + syslinux_dump_memmap(memmap); if (syslinux_compute_movelist(&moves, frags, memmap)) { printf("Failed to compute a move sequence\n"); return 1; } else { - printf("Final move list:\n"); + dprintf("Final move list:\n"); syslinux_dump_movelist(stdout, moves); return 0; } diff --git a/com32/lib/syslinux/setup_data.c b/com32/lib/syslinux/setup_data.c new file mode 100644 index 00000000..a36c5b61 --- /dev/null +++ b/com32/lib/syslinux/setup_data.c @@ -0,0 +1,47 @@ +#include <stdlib.h> +#include <syslinux/linux.h> +#include <syslinux/loadfile.h> + +struct setup_data *setup_data_init(void) +{ + struct setup_data *setup_data; + + setup_data = zalloc(sizeof(*setup_data)); + if (!setup_data) + return NULL; + + setup_data->prev = setup_data->next = setup_data; + return setup_data; +} + +int setup_data_add(struct setup_data *head, uint32_t type, + const void *data, size_t data_len) +{ + struct setup_data *setup_data; + + setup_data = zalloc(sizeof(*setup_data)); + if (!setup_data) + return -1; + + setup_data->data = data; + setup_data->hdr.len = data_len; + setup_data->hdr.type = type; + setup_data->prev = head->prev; + setup_data->next = head; + head->prev->next = setup_data; + head->prev = setup_data; + + return 0; +} + +int setup_data_load(struct setup_data *head, uint32_t type, + const char *filename) +{ + void *data; + size_t len; + + if (loadfile(filename, &data, &len)) + return -1; + + return setup_data_add(head, type, data, len); +} diff --git a/com32/lib/syslinux/shuffle.c b/com32/lib/syslinux/shuffle.c index 54a7e651..e9ee6aad 100644 --- a/com32/lib/syslinux/shuffle.c +++ b/com32/lib/syslinux/shuffle.c @@ -39,26 +39,10 @@ #include <inttypes.h> #include <com32.h> #include <minmax.h> +#include <dprintf.h> #include <syslinux/movebits.h> #include <klibc/compiler.h> -#ifndef DEBUG -# define DEBUG 0 -#endif - -#define dprintf(f, ...) ((void)0) -#define dprintf2(f, ...) ((void)0) - -#if DEBUG -# include <stdio.h> -# undef dprintf -# define dprintf printf -# if DEBUG > 1 -# undef dprintf2 -# define dprintf2 printf -# endif -#endif - struct shuffle_descriptor { uint32_t dst, src, len; }; diff --git a/com32/lib/syslinux/zonelist.c b/com32/lib/syslinux/zonelist.c index b548211f..7034c4be 100644 --- a/com32/lib/syslinux/zonelist.c +++ b/com32/lib/syslinux/zonelist.c @@ -39,21 +39,7 @@ #include <stdlib.h> #include <syslinux/align.h> #include <syslinux/movebits.h> - -#ifndef DEBUG -# ifdef TEST -# define DEBUG 1 -# else -# define DEBUG 0 -# endif -#endif - -#if DEBUG -# include <stdio.h> -# define dprintf printf -#else -# define dprintf(...) ((void)0) -#endif +#include <dprintf.h> /* * Create an empty syslinux_memmap list. @@ -96,10 +82,8 @@ int syslinux_add_memmap(struct syslinux_memmap **list, struct syslinux_memmap *range; enum syslinux_memmap_types oldtype; -#if DEBUG dprintf("Input memmap:\n"); - syslinux_dump_memmap(stdout, *list); -#endif + syslinux_dump_memmap(*list); /* Remove this to make len == 0 mean all of memory */ if (len == 0) @@ -164,10 +148,8 @@ int syslinux_add_memmap(struct syslinux_memmap **list, } } -#if DEBUG dprintf("After adding (%#x,%#x,%d):\n", start, len, type); - syslinux_dump_memmap(stdout, *list); -#endif + syslinux_dump_memmap(*list); return 0; } diff --git a/com32/lib/vdprintf.c b/com32/lib/vdprintf.c index d74f2782..c1f90a63 100644 --- a/com32/lib/vdprintf.c +++ b/com32/lib/vdprintf.c @@ -14,6 +14,8 @@ #define DEBUG 1 #include <dprintf.h> +#ifndef vdprintf + #define BUFFER_SIZE 4096 enum serial_port_regs { @@ -114,3 +116,5 @@ void vdprintf(const char *format, va_list ap) while (rv--) debug_putc(*p++); } + +#endif /* vdprintf */ diff --git a/com32/libupload/.gitignore b/com32/libupload/.gitignore new file mode 100644 index 00000000..e0292b19 --- /dev/null +++ b/com32/libupload/.gitignore @@ -0,0 +1,2 @@ +*.o +*.a diff --git a/com32/libupload/Makefile b/com32/libupload/Makefile new file mode 100644 index 00000000..83053350 --- /dev/null +++ b/com32/libupload/Makefile @@ -0,0 +1,39 @@ +# Include configuration rules +topdir = ../.. +MAKEDIR = $(topdir)/mk +include $(MAKEDIR)/com32.mk + +REQFLAGS += -I./ + +SUBDIRS := . +LIBOBJS := $(foreach dir,$(SUBDIRS),$(patsubst %.c,%.o,$(wildcard $(dir)/*.c))) + +BINDIR = /usr/bin +LIBDIR = /usr/lib +DATADIR = /usr/share +AUXDIR = $(DATADIR)/syslinux +INCDIR = /usr/include +COM32DIR = $(AUXDIR)/com32 + +all: libcom32upload.a + +libcom32upload.a : $(LIBOBJS) + rm -f $@ + $(AR) cq $@ $^ + $(RANLIB) $@ + +tidy dist clean: + find . \( -name \*.o -o -name \*.a -o -name .\*.d -o -name \*.tmp \) -print0 | \ + xargs -0r rm -f + +spotless: clean + rm -f *.a + rm -f *~ \#* */*~ */\#* + +install: all + mkdir -m 755 -p $(INSTALLROOT)$(COM32DIR) + install -m 644 libcom32upload.a $(INSTALLROOT)$(COM32DIR) + mkdir -p $(INSTALLROOT)$(COM32DIR)/include/ + cp -r *.h $(INSTALLROOT)$(COM32DIR)/include/ + +-include .*.d */.*.d */*/.*.d diff --git a/com32/sysdump/cpio.c b/com32/libupload/cpio.c index 81d0d4be..25b464d4 100644 --- a/com32/sysdump/cpio.c +++ b/com32/libupload/cpio.c @@ -9,10 +9,10 @@ #include <inttypes.h> #include <stdbool.h> #include <zlib.h> -#include "backend.h" +#include "upload_backend.h" #include "ctime.h" -int cpio_pad(struct backend *be) +int cpio_pad(struct upload_backend *be) { static char pad[4]; /* Up to 4 zero bytes */ if (be->dbytes & 3) @@ -21,7 +21,7 @@ int cpio_pad(struct backend *be) return 0; } -int cpio_hdr(struct backend *be, uint32_t mode, size_t datalen, +int cpio_hdr(struct upload_backend *be, uint32_t mode, size_t datalen, const char *filename) { static uint32_t inode = 2; @@ -31,7 +31,7 @@ int cpio_hdr(struct backend *be, uint32_t mode, size_t datalen, cpio_pad(be); - sprintf(hdr, "%06o%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x", + sprintf(hdr, "%06o%08x%08x%08x%08x%08x%08x%08zx%08x%08x%08x%08x%08x%08x", 070701, /* c_magic */ inode++, /* c_ino */ mode, /* c_mode */ @@ -52,12 +52,12 @@ int cpio_hdr(struct backend *be, uint32_t mode, size_t datalen, return rv; } -int cpio_mkdir(struct backend *be, const char *filename) +int cpio_mkdir(struct upload_backend *be, const char *filename) { return cpio_hdr(be, MODE_DIR, 0, filename); } -int cpio_writefile(struct backend *be, const char *filename, +int cpio_writefile(struct upload_backend *be, const char *filename, const void *data, size_t len) { int rv; @@ -69,7 +69,7 @@ int cpio_writefile(struct backend *be, const char *filename, return rv; } -int cpio_close(struct backend *be) +int cpio_close(struct upload_backend *be) { return cpio_hdr(be, 0, 0, "TRAILER!!!"); } diff --git a/com32/sysdump/ctime.c b/com32/libupload/ctime.c index 56c8efb6..56c8efb6 100644 --- a/com32/sysdump/ctime.c +++ b/com32/libupload/ctime.c diff --git a/com32/sysdump/ctime.h b/com32/libupload/ctime.h index e6461253..e6461253 100644 --- a/com32/sysdump/ctime.h +++ b/com32/libupload/ctime.h diff --git a/com32/sysdump/serial.c b/com32/libupload/serial.c index a3987531..a3987531 100644 --- a/com32/sysdump/serial.c +++ b/com32/libupload/serial.c diff --git a/com32/sysdump/serial.h b/com32/libupload/serial.h index 356f2cef..356f2cef 100644 --- a/com32/sysdump/serial.h +++ b/com32/libupload/serial.h diff --git a/com32/sysdump/srecsend.h b/com32/libupload/srecsend.h index 667be20d..667be20d 100644 --- a/com32/sysdump/srecsend.h +++ b/com32/libupload/srecsend.h diff --git a/com32/libupload/tftp.h b/com32/libupload/tftp.h new file mode 100644 index 00000000..323dc16a --- /dev/null +++ b/com32/libupload/tftp.h @@ -0,0 +1,22 @@ +#include <stdint.h> + +#ifndef UPLOAD_TFTP +#define UPLOAD_TFTP +/* TFTP Error codes */ +enum tftp_error_codes { +TFTP_ERR_UNKNOWN_ERROR = 0, // We have to use the message from the server +TFTP_ERR_FILE_NOT_FOUND = 1, /**< File not found */ +TFTP_ERR_ACCESS_DENIED = 2, /**< Access violation */ +TFTP_ERR_DISK_FULL = 3, /**< Disk full or allocation exceeded */ +TFTP_ERR_ILLEGAL_OP = 4, /**< Illegal TFTP operation */ +TFTP_ERR_UNKNOWN_TID = 5, /**< Unknown transfer ID */ +TFTP_ERR_FILE_EXISTS = 6, /**< File already exists */ +TFTP_ERR_UNKNOWN_USER = 7, /**< No such user */ +TFTP_ERR_BAD_OPTS = 8, /**< Option negotiation failed */ +TFTP_ERR_UNABLE_TO_RESOLVE = 9, // Not in RFC, internal usage +TFTP_ERR_UNABLE_TO_CONNECT = 10, // Not in RFC, internal usage +TFTP_OK = 11, /* Not in RFC */ +}; + +extern const char *tftp_string_error_message[]; +#endif diff --git a/com32/libupload/upload_backend.h b/com32/libupload/upload_backend.h new file mode 100644 index 00000000..7ea03e46 --- /dev/null +++ b/com32/libupload/upload_backend.h @@ -0,0 +1,56 @@ +#ifndef BACKEND_H +#define BACKEND_H + +#include <stddef.h> +#include <inttypes.h> +#include <stdbool.h> +#include <zlib.h> +#include "serial.h" +#include "tftp.h" + +/* Backend flags */ +#define BE_NEEDLEN 0x01 + +struct upload_backend { + const char *name; + const char *helpmsg; + int minargs; + + size_t dbytes; + size_t zbytes; + const char **argv; + + uint32_t now; + + int (*write)(struct upload_backend *); + + z_stream zstream; + char *outbuf; + size_t alloc; +}; + +/* zout.c */ +int init_data(struct upload_backend *be, const char *argv[]); +int write_data(struct upload_backend *be, const void *buf, size_t len); +int flush_data(struct upload_backend *be); + +/* cpio.c */ +#define cpio_init init_data +int cpio_hdr(struct upload_backend *be, uint32_t mode, size_t datalen, + const char *filename); +int cpio_mkdir(struct upload_backend *be, const char *filename); +int cpio_writefile(struct upload_backend *be, const char *filename, + const void *data, size_t len); +int cpio_close(struct upload_backend *be); +#define MODE_FILE 0100644 +#define MODE_DIR 0040755 + +/* backends.c */ +struct upload_backend *get_upload_backend(const char *name); + +/* backends */ +extern struct upload_backend upload_tftp; +extern struct upload_backend upload_ymodem; +extern struct upload_backend upload_srec; + +#endif /* BACKEND_H */ diff --git a/com32/sysdump/be_srec.c b/com32/libupload/upload_srec.c index fc69c886..c1907131 100644 --- a/com32/sysdump/be_srec.c +++ b/com32/libupload/upload_srec.c @@ -6,7 +6,7 @@ #include <stdio.h> #include <inttypes.h> #include <minmax.h> -#include "backend.h" +#include "upload_backend.h" /* Write a single S-record */ static int write_srecord(unsigned int len, unsigned int alen, @@ -43,7 +43,7 @@ static int write_srecord(unsigned int len, unsigned int alen, return 0; } -static int be_srec_write(struct backend *be) +static int upload_srec_write(struct upload_backend *be) { char name[33]; const char *buf; @@ -77,9 +77,9 @@ static int be_srec_write(struct backend *be) return 0; } -struct backend be_srec = { +struct upload_backend upload_srec = { .name = "srec", .helpmsg = "[filename]", .minargs = 0, - .write = be_srec_write, + .write = upload_srec_write, }; diff --git a/com32/sysdump/be_tftp.c b/com32/libupload/upload_tftp.c index 36a91eb8..5e73c1c5 100644 --- a/com32/sysdump/be_tftp.c +++ b/com32/libupload/upload_tftp.c @@ -8,8 +8,7 @@ #include <syslinux/config.h> #include <netinet/in.h> #include <sys/times.h> - -#include "backend.h" +#include "upload_backend.h" enum tftp_opcode { TFTP_RRQ = 1, @@ -19,6 +18,12 @@ enum tftp_opcode { TFTP_ERROR = 5, }; +struct tftp_error { + uint16_t opcode; + uint16_t errcode; + char errmsg[0]; +} __attribute__ (( packed )); + struct tftp_state { uint32_t my_ip; uint32_t srv_ip; @@ -28,6 +33,21 @@ struct tftp_state { uint16_t seq; }; +const char *tftp_string_error_message[]={ +"", +"File not found", +"Access Denied", +"Disk Full", +"Illegal Operation", +"Unknown Transfert ID", +"File already exists", +"Unknown User", +"Negociation failed", +"Unable to resolve hostname", // not in RFC +"Unable to connect", // not in RFC +"No Error", +}; + #define RCV_BUF 2048 static int send_ack_packet(struct tftp_state *tftp, @@ -51,7 +71,7 @@ static int send_ack_packet(struct tftp_state *tftp, ireg.eax.w[0] = 0x0009; for (timeout = timeouts ; *timeout ; timeout++) { - memset(uw, 0, sizeof uw); + memset(uw, 0, sizeof *uw); memcpy(uw+1, pkt, len); uw->ip = tftp->srv_ip; uw->gw = tftp->srv_gw; @@ -69,7 +89,7 @@ static int send_ack_packet(struct tftp_state *tftp, start = times(NULL); do { - memset(ur, 0, sizeof ur); + memset(ur, 0, sizeof *ur); ur->src_ip = tftp->srv_ip; ur->dest_ip = tftp->my_ip; ur->s_port = tftp->srv_port; @@ -91,9 +111,14 @@ static int send_ack_packet(struct tftp_state *tftp, if (ntohs(xb[0]) == TFTP_ACK && ntohs(xb[1]) == tftp->seq) { tftp->srv_port = ur->s_port; - err = 0; /* All good! */ + err = TFTP_OK; /* All good! */ goto done; - } else if (ntohs(xb[1]) == TFTP_ERROR) { + } else if (ntohs(xb[0]) == TFTP_ERROR) { + struct tftp_error *te = (struct tftp_error *)(ur+1); + if (te->errcode == TFTP_ERR_UNKNOWN_ERROR) { + tftp_string_error_message[TFTP_ERR_UNKNOWN_ERROR]=strdup(te->errmsg); + } + err=-ntohs(te->errcode); // Return the associated error code goto done; } } @@ -107,12 +132,13 @@ done: return err; } -static int be_tftp_write(struct backend *be) +static int upload_tftp_write(struct upload_backend *be) { static uint16_t local_port = 0x4000; struct tftp_state tftp; char buffer[512+4+6]; int nlen; + int err=TFTP_OK; const union syslinux_derivative_info *sdi = syslinux_derivative_info(); const char *data = be->outbuf; @@ -129,30 +155,30 @@ static int be_tftp_write(struct backend *be) if (be->argv[1]) { tftp.srv_ip = pxe_dns(be->argv[1]); if (!tftp.srv_ip) { - printf("\nUnable to resolve hostname: %s\n", be->argv[1]); - return -1; +// printf("\nUnable to resolve hostname: %s\n", be->argv[1]); + return -TFTP_ERR_UNABLE_TO_RESOLVE; } } else { tftp.srv_ip = sdi->pxe.ipinfo->serverip; if (!tftp.srv_ip) { - printf("\nNo server IP address\n"); - return -1; +// printf("\nNo server IP address\n"); + return -TFTP_ERR_UNABLE_TO_CONNECT; } } - printf("server %u.%u.%u.%u... ", +/* printf("server %u.%u.%u.%u... ", ((uint8_t *)&tftp.srv_ip)[0], ((uint8_t *)&tftp.srv_ip)[1], ((uint8_t *)&tftp.srv_ip)[2], - ((uint8_t *)&tftp.srv_ip)[3]); + ((uint8_t *)&tftp.srv_ip)[3]);*/ buffer[0] = 0; buffer[1] = TFTP_WRQ; nlen = strlcpy(buffer+2, be->argv[0], 512); memcpy(buffer+3+nlen, "octet", 6); - if (send_ack_packet(&tftp, buffer, 2+nlen+1+6)) - return -1; + if ((err=send_ack_packet(&tftp, buffer, 2+nlen+1+6))!=TFTP_OK) + return err; do { chunk = len >= 512 ? 512 : len; @@ -163,16 +189,16 @@ static int be_tftp_write(struct backend *be) data += chunk; len -= chunk; - if (send_ack_packet(&tftp, buffer, chunk+4)) - return -1; + if ((err=send_ack_packet(&tftp, buffer, chunk+4))!=TFTP_OK) + return err; } while (chunk == 512); - return 0; + return TFTP_OK; } -struct backend be_tftp = { +struct upload_backend upload_tftp = { .name = "tftp", .helpmsg = "filename [tftp_server]", .minargs = 1, - .write = be_tftp_write, + .write = upload_tftp_write, }; diff --git a/com32/sysdump/be_ymodem.c b/com32/libupload/upload_ymodem.c index 316b3d4e..c42327d8 100644 --- a/com32/sysdump/be_ymodem.c +++ b/com32/libupload/upload_ymodem.c @@ -5,7 +5,7 @@ #include <string.h> #include <stdio.h> #include <inttypes.h> -#include "backend.h" +#include "upload_backend.h" #include "serial.h" enum { @@ -98,7 +98,7 @@ static void send_ack(struct ymodem_state *ym, const uint8_t *blk, size_t bytes) } while (ack_buf == NAK); } -static int be_ymodem_write(struct backend *be) +static int upload_ymodem_write(struct upload_backend *be) { static const uint8_t eot_buf = EOT; uint8_t ack_buf; @@ -167,9 +167,9 @@ static int be_ymodem_write(struct backend *be) return 0; } -struct backend be_ymodem = { +struct upload_backend upload_ymodem = { .name = "ymodem", .helpmsg = "filename [port [speed]]", .minargs = 1, - .write = be_ymodem_write, + .write = upload_ymodem_write, }; diff --git a/com32/sysdump/ymodem.txt b/com32/libupload/ymodem.txt index 2264ff78..2264ff78 100644 --- a/com32/sysdump/ymodem.txt +++ b/com32/libupload/ymodem.txt diff --git a/com32/sysdump/zout.c b/com32/libupload/zout.c index ece934cc..47c0d308 100644 --- a/com32/sysdump/zout.c +++ b/com32/libupload/zout.c @@ -8,12 +8,12 @@ #include <inttypes.h> #include <stdbool.h> #include <zlib.h> -#include "backend.h" +#include "upload_backend.h" #include "ctime.h" #define ALLOC_CHUNK 65536 -int init_data(struct backend *be, const char *argv[]) +int init_data(struct upload_backend *be, const char *argv[]) { be->now = posix_time(); be->argv = argv; @@ -33,7 +33,7 @@ int init_data(struct backend *be, const char *argv[]) return 0; } -static int do_deflate(struct backend *be, int flush) +static int do_deflate(struct upload_backend *be, int flush) { int rv; char *buf; @@ -55,7 +55,7 @@ static int do_deflate(struct backend *be, int flush) } -int write_data(struct backend *be, const void *buf, size_t len) +int write_data(struct upload_backend *be, const void *buf, size_t len) { int rv = Z_OK; @@ -75,9 +75,10 @@ int write_data(struct backend *be, const void *buf, size_t len) } /* Output the data and shut down the stream */ -int flush_data(struct backend *be) +int flush_data(struct upload_backend *be) { int rv = Z_OK; + int err=-1; while (rv != Z_STREAM_END) { rv = do_deflate(be, Z_FINISH); @@ -85,15 +86,15 @@ int flush_data(struct backend *be) return -1; } - printf("Uploading data, %u bytes... ", be->zbytes); +// printf("Uploading data, %u bytes... ", be->zbytes); - if (be->write(be)) - return -1; + if ((err=be->write(be)) != 0) + return err; free(be->outbuf); be->outbuf = NULL; be->dbytes = be->zbytes = be->alloc = 0; - printf("done.\n"); +// printf("done.\n"); return 0; } diff --git a/com32/libutil/Makefile b/com32/libutil/Makefile index 7a6b5272..83e23a0a 100644 --- a/com32/libutil/Makefile +++ b/com32/libutil/Makefile @@ -30,7 +30,8 @@ ## topdir = ../.. -include ../MCONFIG +MAKEDIR = $(topdir)/mk +include $(MAKEDIR)/com32.mk LIBOBJS = ansiline.o ansiraw.o get_key.o keyname.o \ sha1hash.o unbase64.o \ diff --git a/com32/lua/src/Makefile b/com32/lua/src/Makefile index 4081bfe1..f03f7a7f 100644 --- a/com32/lua/src/Makefile +++ b/com32/lua/src/Makefile @@ -16,9 +16,9 @@ ## topdir = ../../.. -include ../../MCONFIG +MAKEDIR = $(topdir)/mk +include $(MAKEDIR)/com32.mk -LIBS = ../../lib/libcom32.a $(LIBGCC) LNXLIBS = # Temporarily allow warnings not being treated as errors @@ -44,6 +44,7 @@ LIBLUA_OBJS += dmi.o LIBLUA_OBJS += cpu.o LIBLUA_OBJS += pci.o LIBLUA_OBJS += vesa.o +LIBLUA_OBJS += dhcp.o CFLAGS += -DLUA_ANSI @@ -54,7 +55,7 @@ $(LIBLUA) : $(LIBLUA_OBJS) $(AR) cq $@ $^ $(RANLIB) $@ -lua.elf : $(OBJS) $(LIBLUA) $(LIBS) $(C_LIBS) +lua.elf : $(OBJS) $(LIBLUA) $(C_LIBS) $(LD) $(LDFLAGS) -o $@ $^ tidy dist: 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/dhcp.c b/com32/lua/src/dhcp.c new file mode 100644 index 00000000..af948131 --- /dev/null +++ b/com32/lua/src/dhcp.c @@ -0,0 +1,358 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2007 H. Peter Anvin - All Rights Reserved + * Copyright 2011 Timothy J Gleason <timmgleason_at_gmail.com> - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * dhcp.c + * + * Adds DHCPINFO functionality to the lua.c32 binary + * + * gettable() returns a table of the BOOTP message fields returned by + * the DHCP server for use in a Lua pxeboot script + * See http://tools.ietf.org/html/rfc1542 + * + * lua key value RFC key + * ----------------------------------------------------------------------- + * opcode op message opcode + * hardware.type htype Hardware address type + * hardware.length hlen Hardware address length + * hops hops Used by relay agents + * transaction.id xid transaction id + * elapsed.seconds secs Secs elapsed since client boot + * flags flags DHCP Flags field + * client.ip.addr ciaddr client IP addr + * your.ip.addr yiaddr 'Your' IP addr. (from server) + * server.ip.addr siaddr Boot server IP addr + * gateway.ip.addr giaddr Relay agent IP addr + * client.mac chaddr Client hardware addr + * server.hostname sname Optl. boot server hostname + * boot.file file boot file name (ascii path) + * magic.cookie cookie Magic cookie + * + * getoptions() returns a table of the DHCP Options field of the BOOTP + * message returned by the DHCP server for use in a Lua pxeboot script. + * Many of the options are reurned formatted in as strings in a standard, + * recognizable format, such as IP addresses. + * + * 1, 2, and 4 byte numerical options are returned as integers. + * + * Other Options with non-standard formats are returned as strings of the + * raw binary number that was returned by the DHCP server and must be decoded + * in a Lua script + * + * The Options table returns the Option code as the key except where there + * are multiple values returned. In those cases, an extra key increment number + * is added to allow individual access to each Option value. + * + * lua key value value Name + * ----------------------------------------------------------------------- + * 1 Subnet Mask + * 6.1 DNS Server [element 1] + * 6.2 DNS Server [element 2] + * 6.3 DNS Server [element 3] + * 209 PXE Configuration File + * 21.1 Policy Filter [element 1] + * 21.2 Policy Filter [element 2] + * + * Options that can have a list of values, but contain only one (like Option 6) + * will not return with .sub key values. + * + * Usage: + t = dhcp.gettable() + + for k,v in pairs(t) do + print(k.." : "..v) + end + */ + +#include <stdio.h> +#include "dhcp.h" +#include "lua.h" +#include "lauxlib.h" +#include "lualib.h" +#include <syslinux/pxe.h> + +#define STR_BUF_SIZE 129 /* Sized to accomdate File field in BOOTP message */ + +void +ip_address_list(lua_State *L, uint8_t* value, uint8_t len, uint8_t option ) +{ + static char op_name[64]; + static char op_value[255]; + int loop; + + loop = len/4; + + if ( loop == 1) { + sprintf(op_name, "%u", option); + lua_pushstring(L, op_name); + sprintf(op_value, "%u.%u.%u.%u", value[0], value[1], value[2], value[3]); + lua_pushstring(L, op_value); + lua_settable(L,-3); + } else { + for (int done = 0; done < loop; done++){ + sprintf(op_name, "%u.%d", option, done+1); + lua_pushstring(L, op_name); + sprintf(op_value, "%u.%u.%u.%u", value[0+(done*4)], value[1+(done*4)], value[2+(done*4)], value[3+(done*4)]); + lua_pushstring(L, op_value); + lua_settable(L,-3); + } + } + +} + +static int dhcp_getoptions(lua_State *L) +{ + void* dhcpdata = 0; + dhcp_t* dhcp = 0; + size_t dhcplen = 0; + + /* Append the DHCP info */ + if (pxe_get_cached_info(PXENV_PACKET_TYPE_DHCP_ACK, + &dhcpdata, &dhcplen)) + { + return 0; + } + + dhcp = (dhcp_t*)dhcpdata; + + lua_newtable(L); + + int done = 0; + uint8_t* ptr = (uint8_t*)&dhcp->options; + uint8_t len; + uint8_t option; + uint8_t* value; + static char op_name[64]; + + do { + option = *ptr++; + len = *ptr++; + value = ptr; + ptr += len; + switch (option) { +// IP Address formatted lists, including singles + case 1: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 16: + case 21: /* Policy Filters - address/mask */ + case 28: + case 32: + case 33: /* Static routes - destination/router */ + case 41: + case 42: + case 44: + case 45: + case 47: + case 48: + case 49: + case 50: + case 51: + case 54: + case 65: + case 68: + case 69: + case 70: + case 71: + case 72: + case 73: + case 74: + case 75: + case 76: + ip_address_list(L, value, len, option); + break; +// 4byte options - numerical + case 2: + case 24: + case 35: + case 38: + case 58: + case 59: + case 211: + sprintf(op_name, "%u", option); + lua_pushstring(L, op_name); + lua_pushinteger(L, ntohl(*(long*)value)); + lua_settable(L,-3); + break; +// 2byte options -numerical + case 13: + case 22: + case 26: + case 57: + sprintf(op_name, "%u", option); + lua_pushstring(L, op_name); + lua_pushinteger(L, ntohs(*(short*)value)); + lua_settable(L,-3); + break; +// 1byte options - numerical + case 19: + case 20: + case 23: + case 27: + case 29: + case 30: + case 31: + case 34: + case 36: + case 37: + case 39: + case 46: + case 52: + case 53: + sprintf(op_name, "%u", option); + lua_pushstring(L, op_name); + lua_pushinteger(L, *value); + lua_settable(L,-3); + break; + case 255: + done = 1; + break; + default: + sprintf(op_name, "%u", option); + lua_pushstring(L, op_name); + lua_pushlstring(L, (const char*)value, len); + lua_settable(L,-3); + break; + } + + } while (!done); + + return 1; +} + +static int dhcp_gettable(lua_State *L) +{ + void* dhcpdata = 0; + dhcp_t* dhcp = 0; + size_t dhcplen = 0; + static char dhcp_arg[STR_BUF_SIZE]; + + /* Append the DHCP info */ + if (pxe_get_cached_info(PXENV_PACKET_TYPE_DHCP_ACK, + &dhcpdata, &dhcplen)) + { + return 0; + } + + dhcp = (dhcp_t*)dhcpdata; + + + lua_newtable(L); + + lua_pushstring(L, "opcode"); + lua_pushinteger(L, dhcp->op); + lua_settable(L,-3); + + lua_pushstring(L, "hardware.type"); + lua_pushinteger(L, dhcp->htype); + lua_settable(L,-3); + + lua_pushstring(L, "hardware.length"); + lua_pushinteger(L, dhcp->hlen); + lua_settable(L,-3); + + lua_pushstring(L, "hops"); + lua_pushinteger(L, dhcp->hops); + lua_settable(L,-3); + + lua_pushstring(L, "transaction.id"); + lua_pushinteger(L, ntohl(dhcp->xid)); + lua_settable(L,-3); + + lua_pushstring(L, "elapsed.seconds"); + lua_pushinteger(L, ntohs(dhcp->secs)); + lua_settable(L,-3); + + lua_pushstring(L, "flags"); + lua_pushinteger(L, ntohs(dhcp->flags)); + lua_settable(L,-3); + + sprintf(dhcp_arg, "%u.%u.%u.%u", dhcp->ciaddr[0], dhcp->ciaddr[1], dhcp->ciaddr[2], dhcp->ciaddr[3]); + lua_pushstring(L, "client.ip.addr"); + lua_pushstring(L, dhcp_arg); + lua_settable(L,-3); + + sprintf(dhcp_arg, "%u.%u.%u.%u", dhcp->yiaddr[0], dhcp->yiaddr[1], dhcp->yiaddr[2], dhcp->yiaddr[3]); + lua_pushstring(L, "your.ip.addr"); + lua_pushstring(L, dhcp_arg); + lua_settable(L,-3); + + sprintf(dhcp_arg, "%u.%u.%u.%u", dhcp->siaddr[0], dhcp->siaddr[1], dhcp->siaddr[2], dhcp->siaddr[3]); + lua_pushstring(L, "server.ip.addr"); + lua_pushstring(L, dhcp_arg); + lua_settable(L,-3); + + sprintf(dhcp_arg, "%u.%u.%u.%u", dhcp->giaddr[0], dhcp->giaddr[1], dhcp->giaddr[2], dhcp->giaddr[3]); + lua_pushstring(L, "gateway.ip.addr"); + lua_pushstring(L, dhcp_arg); + lua_settable(L,-3); + + sprintf(dhcp_arg, "%02X:%02X:%02X:%02X:%02X:%02X", + dhcp->chaddr[0], dhcp->chaddr[1], dhcp->chaddr[2], + dhcp->chaddr[3], dhcp->chaddr[4], dhcp->chaddr[5]); + lua_pushstring(L, "client.mac"); + lua_pushstring(L, dhcp_arg); + lua_settable(L,-3); + + snprintf(dhcp_arg, STR_BUF_SIZE, "%s", dhcp->sname); + dhcp_arg[STR_BUF_SIZE-1] = 0; /* Guarantee for lua_pushstring that dhcp_arg is 0 terminated /*/ + lua_pushstring(L, "server.hostname"); + lua_pushstring(L, dhcp_arg); + lua_settable(L,-3); + + snprintf(dhcp_arg, STR_BUF_SIZE, "%s", dhcp->file); + dhcp_arg[STR_BUF_SIZE-1] = 0; /* Guarantee for lua_pushstring that dhcp_arg is 0 terminated /*/ + lua_pushstring(L, "boot.file"); + lua_pushstring(L, dhcp_arg); + lua_settable(L,-3); + + sprintf(dhcp_arg, "%u.%u.%u.%u", dhcp->cookie[0], dhcp->cookie[1], dhcp->cookie[2], dhcp->cookie[3]); + lua_pushstring(L, "magic.cookie"); + lua_pushstring(L, dhcp_arg); + lua_settable(L,-3); + + return 1; +} + +static const luaL_reg dhcplib[] = { + {"gettable", dhcp_gettable}, + {"getoptions", dhcp_getoptions}, + {NULL, NULL} +}; + +LUALIB_API int luaopen_dhcp (lua_State *L) { + luaL_openlib(L, LUA_DHCPLIBNAME, dhcplib, 0); + return 1; +} diff --git a/com32/lua/src/dhcp.h b/com32/lua/src/dhcp.h new file mode 100644 index 00000000..a398cfc1 --- /dev/null +++ b/com32/lua/src/dhcp.h @@ -0,0 +1,49 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2007 H. Peter Anvin - All Rights Reserved + * Copyright 2011 Timothy J Gleason <timmgleason_at_gmail.com> - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +#include <stdint.h> + +typedef struct dhcp { + uint8_t op; /* message opcode */ + uint8_t htype; /* Hardware address type */ + uint8_t hlen; /* Hardware address length */ + uint8_t hops; /* Used by relay agents */ + uint32_t xid; /* transaction id */ + uint16_t secs; /* Secs elapsed since client boot */ + uint16_t flags; /* DHCP Flags field */ + uint8_t ciaddr[4]; /* client IP addr */ + uint8_t yiaddr[4]; /* 'Your' IP addr. (from server) */ + uint8_t siaddr[4]; /* Boot server IP addr */ + uint8_t giaddr[4]; /* Relay agent IP addr */ + uint8_t chaddr[16]; /* Client hardware addr */ + uint8_t sname[64]; /* Optl. boot server hostname */ + uint8_t file[128]; /* boot file name (ascii path) */ + uint8_t cookie[4]; /* Magic cookie */ + uint8_t options[1020]; /* Options */ +} dhcp_t; + 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/linit.c b/com32/lua/src/linit.c index 6c7f63e4..6e978736 100644 --- a/com32/lua/src/linit.c +++ b/com32/lua/src/linit.c @@ -33,6 +33,7 @@ static const luaL_Reg lualibs[] = { {LUA_PCILIBNAME, luaopen_pci}, {LUA_SYSLINUXLIBNAME, luaopen_syslinux}, {LUA_VESALIBNAME, luaopen_vesa}, + {LUA_DHCPLIBNAME, luaopen_dhcp}, #endif {NULL, NULL} }; 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/lualib.h b/com32/lua/src/lualib.h index 0ae6ba75..40d1bf29 100644 --- a/com32/lua/src/lualib.h +++ b/com32/lua/src/lualib.h @@ -54,6 +54,9 @@ LUALIB_API int (luaopen_vesa) (lua_State *L); #define LUA_CPULIBNAME "cpu" LUALIB_API int (luaopen_cpu) (lua_State *L); + +#define LUA_DHCPLIBNAME "dhcp" +LUALIB_API int (luaopen_dhcp) (lua_State *L); #endif /* open all previous libraries */ diff --git a/com32/lua/src/syslinux.c b/com32/lua/src/syslinux.c index 9b207db7..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); @@ -278,7 +279,7 @@ static int sl_boot_linux(lua_State * L) msleep(10000); */ - ret = syslinux_boot_linux(kernel_data, kernel_len, initramfs, newcmdline); + ret = syslinux_boot_linux(kernel_data, kernel_len, initramfs, NULL, newcmdline); printf("syslinux_boot_linux returned %d\n", ret); @@ -405,7 +406,36 @@ static int sl_boot_it(lua_State * L) (void)mem_limit; return syslinux_boot_linux(kernel->data, kernel->size, - initramfs, (char *)cmdline); + 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) @@ -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/Makefile b/com32/mboot/Makefile index 7e6c2e96..b7ee1154 100644 --- a/com32/mboot/Makefile +++ b/com32/mboot/Makefile @@ -16,9 +16,9 @@ ## topdir = ../.. -include ../MCONFIG +MAKEDIR = $(topdir)/mk +include $(MAKEDIR)/com32.mk -LIBS = ../libutil/libutil_com.a ../lib/libcom32.a $(LIBGCC) LNXLIBS = ../libutil/libutil_lnx.a MODULES = mboot.c32 @@ -28,7 +28,7 @@ OBJS = mboot.o map.o mem.o initvesa.o apm.o solaris.o syslinux.o all: $(MODULES) $(TESTFILES) -mboot.elf : $(OBJS) $(LIBS) $(C_LIBS) +mboot.elf : $(OBJS) $(C_LIBS) $(LD) $(LDFLAGS) -o $@ $^ tidy dist: diff --git a/com32/mboot/map.c b/com32/mboot/map.c index 0a71d4c9..99add306 100644 --- a/com32/mboot/map.c +++ b/com32/mboot/map.c @@ -91,10 +91,9 @@ int init_map(void) error("Failed to allocate initial memory map!\n"); return -1; } -#if DEBUG + dprintf("Initial memory map:\n"); - syslinux_dump_memmap(stdout, mmap); -#endif + syslinux_dump_memmap(mmap); return 0; } 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/Makefile b/com32/menu/Makefile index 2a032728..b67b997d 100644 --- a/com32/menu/Makefile +++ b/com32/menu/Makefile @@ -15,9 +15,9 @@ ## topdir = ../.. -include ../MCONFIG +MAKEDIR = $(topdir)/mk +include $(MAKEDIR)/com32.mk -LIBS = ../libutil/libutil_com.a ../lib/libcom32.a $(LIBGCC) LNXLIBS = ../libutil/libutil_lnx.a MODULES = menu.c32 vesamenu.c32 @@ -28,10 +28,10 @@ COMMONOBJS = menumain.o readconfig.o passwd.o drain.o printmsg.o colors.o \ all: $(MODULES) $(TESTFILES) -menu.elf : menu.o $(COMMONOBJS) $(LIBS) $(C_LIBS) +menu.elf : menu.o $(COMMONOBJS) $(C_LIBS) $(LD) $(LDFLAGS) -o $@ $^ -vesamenu.elf : vesamenu.o $(COMMONOBJS) $(LIBS) $(C_LIBS) +vesamenu.elf : vesamenu.o $(COMMONOBJS) $(C_LIBS) $(LD) $(LDFLAGS) -o $@ $^ tidy dist: diff --git a/com32/menu/menumain.c b/com32/menu/menumain.c index 5b3f6bd1..8573901c 100644 --- a/com32/menu/menumain.c +++ b/com32/menu/menumain.c @@ -806,7 +806,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 0ac2564a..431017f6 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 2d479132..f110e584 100644 --- a/com32/modules/Makefile +++ b/com32/modules/Makefile @@ -16,13 +16,15 @@ ## topdir = ../.. -include ../MCONFIG +MAKEDIR = $(topdir)/mk +include $(MAKEDIR)/com32.mk -MODULES = chain.c32 config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 \ +MODULES = config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 \ disk.c32 pcitest.c32 elf.c32 linux.c32 reboot.c32 pmload.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 whichsys.c32 + ifcpu.c32 cpuid.c32 cat.c32 pwd.c32 ifplop.c32 zzjson.c32 \ + whichsys.c32 prdhcp.c32 pxechn.c32 kontron_wdt.c32 ifmemdsk.c32 TESTFILES = diff --git a/com32/modules/chain.c b/com32/modules/chain.c deleted file mode 100644 index 48f53ffd..00000000 --- a/com32/modules/chain.c +++ /dev/null @@ -1,1870 +0,0 @@ -/* ----------------------------------------------------------------------- * - * - * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved - * Copyright 2009-2011 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. - * - * ----------------------------------------------------------------------- */ - -/* - * chain.c - * - * Chainload a hard disk (currently rather braindead.) - * - * Usage: chain [options] - * chain hd<disk#> [<partition>] [options] - * chain fd<disk#> [options] - * chain mbr:<id> [<partition>] [options] - * chain guid:<guid> [<partition>] [options] - * chain label:<label> [<partition>] [options] - * chain boot [<partition>] [options] - * - * For example, "chain msdos=io.sys" will load DOS from the current Syslinux - * filesystem. "chain hd0 1" will boot the first partition on the first hard - * disk. - * - * When none of the "hdX", "fdX", "mbr:", "guid:", "label:", "boot" or "fs" - * options are specified, the default behaviour is equivalent to "boot". - * "boot" means to use the current Syslinux drive, and you can also specify - * a partition. - * - * The mbr: syntax means search all the hard disks until one with a - * specific MBR serial number (bytes 440-443) is found. - * - * Partitions 1-4 are primary, 5+ logical, 0 = boot MBR (default.) - * - * "fs" will use the current Syslinux filesystem as the boot drive/partition. - * When booting from PXELINUX, you will most likely wish to specify a disk. - * - * Options: - * - * file=<loader> - * loads the file <loader> **from the Syslinux filesystem** - * instead of loading the boot sector. - * - * seg=<segment> - * loads at and jumps to <seg>:0000 instead of 0000:7C00. - * - * isolinux=<loader> - * chainload another version/build of the ISOLINUX bootloader and patch - * the loader with appropriate parameters in memory. - * This avoids the need for the -eltorito-alt-boot parameter of mkisofs, - * when you want more than one ISOLINUX per CD/DVD. - * - * ntldr=<loader> - * equivalent to seg=0x2000 file=<loader> sethidden, - * used with WinNT's loaders - * - * cmldr=<loader> - * used with Recovery Console of Windows NT/2K/XP. - * same as ntldr=<loader> & "cmdcons\0" written to - * the system name field in the bootsector - * - * freedos=<loader> - * equivalent to seg=0x60 file=<loader> sethidden, - * used with FreeDOS' kernel.sys. - * - * msdos=<loader> - * pcdos=<loader> - * equivalent to seg=0x70 file=<loader> sethidden, - * used with DOS' io.sys. - * - * drmk=<loader> - * Similar to msdos=<loader> but prepares the special options - * for the Dell Real Mode Kernel. - * - * grub=<loader> - * same as seg=0x800 file=<loader> & jumping to seg 0x820, - * used with GRUB Legacy stage2 files. - * - * grubcfg=<filename> - * set an alternative config filename in stage2 of Grub Legacy, - * only applicable in combination with "grub=<loader>". - * - * grldr=<loader> - * pass the partition number to GRUB4DOS, - * used with GRUB4DOS' grldr. - * - * swap - * if the disk is not fd0/hd0, install a BIOS stub which swaps - * the drive numbers. - * - * hide - * change type of primary partitions with IDs 01, 04, 06, 07, - * 0b, 0c, or 0e to 1x, except for the selected partition, which - * is converted the other way. - * - * sethidden - * update the "hidden sectors" (partition offset) field in a - * FAT/NTFS boot sector. - * - * keeppxe - * keep the PXE and UNDI stacks in memory (PXELINUX only). - */ - -#include <com32.h> -#include <stdlib.h> -#include <stdio.h> -#include <ctype.h> -#include <string.h> -#include <console.h> -#include <minmax.h> -#include <stdbool.h> -#include <dprintf.h> -#include <syslinux/loadfile.h> -#include <syslinux/bootrm.h> -#include <syslinux/config.h> -#include <syslinux/video.h> - -#define SECTOR 512 /* bytes/sector */ - -static struct options { - const char *loadfile; - uint16_t keeppxe; - uint16_t seg; - bool isolinux; - bool cmldr; - bool grub; - bool grldr; - const char *grubcfg; - bool swap; - bool hide; - bool sethidden; - bool drmk; -} opt; - -struct data_area { - void *data; - addr_t base; - addr_t size; -}; - -static inline void error(const char *msg) -{ - fputs(msg, stderr); -} - -/* - * Call int 13h, but with retry on failure. Especially floppies need this. - */ -static int int13_retry(const com32sys_t * inreg, com32sys_t * outreg) -{ - int retry = 6; /* Number of retries */ - com32sys_t tmpregs; - - if (!outreg) - outreg = &tmpregs; - - while (retry--) { - __intcall(0x13, inreg, outreg); - if (!(outreg->eflags.l & EFLAGS_CF)) - return 0; /* CF=0, OK */ - } - - return -1; /* Error */ -} - -/* - * Query disk parameters and EBIOS availability for a particular disk. - */ -struct diskinfo { - int disk; - int ebios; /* EBIOS supported on this disk */ - int cbios; /* CHS geometry is valid */ - int head; - int sect; -} disk_info; - -static int get_disk_params(int disk) -{ - static com32sys_t getparm, parm, getebios, ebios; - - disk_info.disk = disk; - disk_info.ebios = disk_info.cbios = 0; - - /* Get EBIOS support */ - getebios.eax.w[0] = 0x4100; - getebios.ebx.w[0] = 0x55aa; - getebios.edx.b[0] = disk; - getebios.eflags.b[0] = 0x3; /* CF set */ - - __intcall(0x13, &getebios, &ebios); - - if (!(ebios.eflags.l & EFLAGS_CF) && - ebios.ebx.w[0] == 0xaa55 && (ebios.ecx.b[0] & 1)) { - disk_info.ebios = 1; - } - - /* Get disk parameters -- really only useful for - hard disks, but if we have a partitioned floppy - it's actually our best chance... */ - getparm.eax.b[1] = 0x08; - getparm.edx.b[0] = disk; - - __intcall(0x13, &getparm, &parm); - - if (parm.eflags.l & EFLAGS_CF) - return disk_info.ebios ? 0 : -1; - - disk_info.head = parm.edx.b[1] + 1; - disk_info.sect = parm.ecx.b[0] & 0x3f; - if (disk_info.sect == 0) { - disk_info.sect = 1; - } else { - disk_info.cbios = 1; /* Valid geometry */ - } - - return 0; -} - -/* - * Get a disk block and return a malloc'd buffer. - * Uses the disk number and information from disk_info. - */ -struct ebios_dapa { - uint16_t len; - uint16_t count; - uint16_t off; - uint16_t seg; - uint64_t lba; -}; - -/* Read count sectors from drive, starting at lba. Return a new buffer */ -static void *read_sectors(uint64_t lba, uint8_t count) -{ - com32sys_t inreg; - struct ebios_dapa *dapa = __com32.cs_bounce; - void *buf = (char *)__com32.cs_bounce + SECTOR; - void *data; - - if (!count) - /* Silly */ - return NULL; - - memset(&inreg, 0, sizeof inreg); - - if (disk_info.ebios) { - dapa->len = sizeof(*dapa); - dapa->count = count; - dapa->off = OFFS(buf); - dapa->seg = SEG(buf); - dapa->lba = lba; - - inreg.esi.w[0] = OFFS(dapa); - inreg.ds = SEG(dapa); - inreg.edx.b[0] = disk_info.disk; - inreg.eax.b[1] = 0x42; /* Extended read */ - } else { - unsigned int c, h, s, t; - - if (!disk_info.cbios) { - /* We failed to get the geometry */ - - if (lba) - return NULL; /* Can only read MBR */ - - s = h = c = 0; - } else { - s = lba % disk_info.sect; - t = lba / disk_info.sect; /* Track = head*cyl */ - h = t % disk_info.head; - c = t / disk_info.head; - } - - if (s >= 63 || h >= 256 || c >= 1024) - return NULL; - - inreg.eax.b[0] = count; - inreg.eax.b[1] = 0x02; /* Read */ - inreg.ecx.b[1] = c; - inreg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1); - inreg.edx.b[1] = h; - inreg.edx.b[0] = disk_info.disk; - inreg.ebx.w[0] = OFFS(buf); - inreg.es = SEG(buf); - } - - if (int13_retry(&inreg, NULL)) - return NULL; - - data = malloc(count * SECTOR); - if (data) - memcpy(data, buf, count * SECTOR); - return data; -} - -static int write_sector(unsigned int lba, const void *data) -{ - com32sys_t inreg; - struct ebios_dapa *dapa = __com32.cs_bounce; - void *buf = (char *)__com32.cs_bounce + SECTOR; - - memcpy(buf, data, SECTOR); - memset(&inreg, 0, sizeof inreg); - - if (disk_info.ebios) { - dapa->len = sizeof(*dapa); - dapa->count = 1; /* 1 sector */ - dapa->off = OFFS(buf); - dapa->seg = SEG(buf); - dapa->lba = lba; - - inreg.esi.w[0] = OFFS(dapa); - inreg.ds = SEG(dapa); - inreg.edx.b[0] = disk_info.disk; - inreg.eax.w[0] = 0x4300; /* Extended write */ - } else { - unsigned int c, h, s, t; - - if (!disk_info.cbios) { - /* We failed to get the geometry */ - - if (lba) - return -1; /* Can only write MBR */ - - s = h = c = 0; - } else { - s = lba % disk_info.sect; - t = lba / disk_info.sect; /* Track = head*cyl */ - h = t % disk_info.head; - c = t / disk_info.head; - } - - if (s >= 63 || h >= 256 || c >= 1024) - return -1; - - inreg.eax.w[0] = 0x0301; /* Write one sector */ - inreg.ecx.b[1] = c; - inreg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1); - inreg.edx.b[1] = h; - inreg.edx.b[0] = disk_info.disk; - inreg.ebx.w[0] = OFFS(buf); - inreg.es = SEG(buf); - } - - if (int13_retry(&inreg, NULL)) - return -1; - - return 0; /* ok */ -} - -static int write_verify_sector(unsigned int lba, const void *buf) -{ - char *rb; - int rv; - - rv = write_sector(lba, buf); - if (rv) - return rv; /* Write failure */ - rb = read_sectors(lba, 1); - if (!rb) - return -1; /* Readback failure */ - rv = memcmp(buf, rb, SECTOR); - free(rb); - return rv ? -1 : 0; -} - -/* - * CHS (cylinder, head, sector) value extraction macros. - * Taken from WinVBlock. Does not expand to an lvalue -*/ -#define chs_head(chs) chs[0] -#define chs_sector(chs) (chs[1] & 0x3F) -#define chs_cyl_high(chs) (((uint16_t)(chs[1] & 0xC0)) << 2) -#define chs_cyl_low(chs) ((uint16_t)chs[2]) -#define chs_cylinder(chs) (chs_cyl_high(chs) | chs_cyl_low(chs)) -typedef uint8_t chs[3]; - -/* A DOS partition table entry */ -struct part_entry { - uint8_t active_flag; /* 0x80 if "active" */ - chs start; - uint8_t ostype; - chs end; - uint32_t start_lba; - uint32_t length; -} __attribute__ ((packed)); - -static void mbr_part_dump(const struct part_entry *part) -{ - (void)part; - dprintf("Partition status _____ : 0x%.2x\n" - "Partition CHS start\n" - " Cylinder ___________ : 0x%.4x (%u)\n" - " Head _______________ : 0x%.2x (%u)\n" - " Sector _____________ : 0x%.2x (%u)\n" - "Partition type _______ : 0x%.2x\n" - "Partition CHS end\n" - " Cylinder ___________ : 0x%.4x (%u)\n" - " Head _______________ : 0x%.2x (%u)\n" - " Sector _____________ : 0x%.2x (%u)\n" - "Partition LBA start __ : 0x%.8x (%u)\n" - "Partition LBA count __ : 0x%.8x (%u)\n" - "-------------------------------\n", - part->active_flag, - chs_cylinder(part->start), - chs_cylinder(part->start), - chs_head(part->start), - chs_head(part->start), - chs_sector(part->start), - chs_sector(part->start), - part->ostype, - chs_cylinder(part->end), - chs_cylinder(part->end), - chs_head(part->end), - chs_head(part->end), - chs_sector(part->end), - chs_sector(part->end), - part->start_lba, - part->start_lba, - part->length, - part->length); -} - -/* A DOS MBR */ -struct mbr { - char code[440]; - uint32_t disk_sig; - char pad[2]; - struct part_entry table[4]; - uint16_t sig; -} __attribute__ ((packed)); -static const uint16_t mbr_sig_magic = 0xAA55; - -/* Search for a specific drive, based on the MBR signature; bytes 440-443 */ -static int find_disk(uint32_t mbr_sig) -{ - int drive; - bool is_me; - struct mbr *mbr; - - for (drive = 0x80; drive <= 0xff; drive++) { - if (get_disk_params(drive)) - continue; /* Drive doesn't exist */ - if (!(mbr = read_sectors(0, 1))) - continue; /* Cannot read sector */ - is_me = (mbr->disk_sig == mbr_sig); - free(mbr); - if (is_me) - return drive; - } - return -1; -} - -/* Forward declaration */ -struct disk_part_iter; - -/* Partition-/scheme-specific routine returning the next partition */ -typedef struct disk_part_iter *(*disk_part_iter_func) (struct disk_part_iter * - part); - -/* Contains details for a partition under examination */ -struct disk_part_iter { - /* The block holding the table we are part of */ - char *block; - /* The LBA for the beginning of data */ - uint64_t lba_data; - /* The partition number, as determined by our heuristic */ - int index; - /* The DOS partition record to pass, if applicable */ - const struct part_entry *record; - /* Function returning the next available partition */ - disk_part_iter_func next; - /* Partition-/scheme-specific details */ - union { - /* MBR specifics */ - int mbr_index; - /* EBR specifics */ - struct { - /* The first extended partition's start LBA */ - uint64_t lba_extended; - /* Any applicable parent, or NULL */ - struct disk_part_iter *parent; - /* The parent extended partition index */ - int parent_index; - } ebr; - /* GPT specifics */ - struct { - /* Real (not effective) index in the partition table */ - int index; - /* Current partition GUID */ - const struct guid *part_guid; - /* Current partition label */ - const char *part_label; - /* Count of entries in GPT */ - int parts; - /* Partition record size */ - uint32_t size; - } gpt; - } private; -}; - -static struct disk_part_iter *next_ebr_part(struct disk_part_iter *part) -{ - const struct part_entry *ebr_table; - const struct part_entry *parent_table = - ((const struct mbr *)part->private.ebr.parent->block)->table; - static const struct part_entry phony = {.start_lba = 0 }; - uint64_t ebr_lba; - - /* Don't look for a "next EBR" the first time around */ - if (part->private.ebr.parent_index >= 0) - /* Look at the linked list */ - ebr_table = ((const struct mbr *)part->block)->table + 1; - /* Do we need to look for an extended partition? */ - if (part->private.ebr.parent_index < 0 || !ebr_table->start_lba) { - /* Start looking for an extended partition in the MBR */ - while (++part->private.ebr.parent_index < 4) { - uint8_t type = parent_table[part->private.ebr.parent_index].ostype; - - if ((type == 0x05) || (type == 0x0F) || (type == 0x85)) - break; - } - if (part->private.ebr.parent_index == 4) - /* No extended partitions found */ - goto out_finished; - part->private.ebr.lba_extended = - parent_table[part->private.ebr.parent_index].start_lba; - ebr_table = &phony; - } - /* Load next EBR */ - ebr_lba = ebr_table->start_lba + part->private.ebr.lba_extended; - free(part->block); - part->block = read_sectors(ebr_lba, 1); - if (!part->block) { - error("Could not load EBR!\n"); - goto err_ebr; - } - ebr_table = ((const struct mbr *)part->block)->table; - dprintf("next_ebr_part:\n"); - mbr_part_dump(ebr_table); - - /* - * Sanity check entry: must not extend outside the - * extended partition. This is necessary since some OSes - * put crap in some entries. - */ - { - const struct mbr *mbr = - (const struct mbr *)part->private.ebr.parent->block; - const struct part_entry *extended = - mbr->table + part->private.ebr.parent_index; - - if (ebr_table[0].start_lba >= extended->start_lba + extended->length) { - dprintf("Insane logical partition!\n"); - goto err_insane; - } - } - /* Success */ - part->lba_data = ebr_table[0].start_lba + ebr_lba; - dprintf("Partition %d logical lba %u\n", part->index, part->lba_data); - part->index++; - part->record = ebr_table; - return part; - -err_insane: - - free(part->block); - part->block = NULL; -err_ebr: - -out_finished: - free(part->private.ebr.parent->block); - free(part->private.ebr.parent); - free(part->block); - free(part); - return NULL; -} - -static struct disk_part_iter *next_mbr_part(struct disk_part_iter *part) -{ - struct disk_part_iter *ebr_part; - /* Look at the partition table */ - struct part_entry *table = ((struct mbr *)part->block)->table; - - /* Look for data partitions */ - while (++part->private.mbr_index < 4) { - uint8_t type = table[part->private.mbr_index].ostype; - - if (type == 0x00 || type == 0x05 || type == 0x0F || type == 0x85) - /* Skip empty or extended partitions */ - continue; - if (!table[part->private.mbr_index].length) - /* Empty */ - continue; - break; - } - /* If we're currently the last partition, it's time for EBR processing */ - if (part->private.mbr_index == 4) { - /* Allocate another iterator for extended partitions */ - ebr_part = malloc(sizeof(*ebr_part)); - if (!ebr_part) { - error("Could not allocate extended partition iterator!\n"); - goto err_alloc; - } - /* Setup EBR iterator parameters */ - ebr_part->block = NULL; - ebr_part->index = 4; - ebr_part->record = NULL; - ebr_part->next = next_ebr_part; - ebr_part->private.ebr.parent = part; - /* Trigger an initial EBR load */ - ebr_part->private.ebr.parent_index = -1; - /* The EBR iterator is responsible for freeing us */ - return next_ebr_part(ebr_part); - } - dprintf("next_mbr_part:\n"); - mbr_part_dump(table + part->private.mbr_index); - - /* Update parameters to reflect this new partition. Re-use iterator */ - part->lba_data = table[part->private.mbr_index].start_lba; - dprintf("Partition %d primary lba %u\n", part->private.mbr_index, part->lba_data); - part->index = part->private.mbr_index + 1; - part->record = table + part->private.mbr_index; - return part; - - free(ebr_part); -err_alloc: - - free(part->block); - free(part); - return NULL; -} - -/* - * GUID - * Be careful with endianness, you must adjust it yourself - * iff you are directly using the fourth data chunk - */ -struct guid { - uint32_t data1; - uint16_t data2; - uint16_t data3; - uint64_t data4; -} __attribute__ ((packed)); - - /* - * This walk-map effectively reverses the little-endian - * portions of the GUID in the output text - */ -static const char guid_le_walk_map[] = { - 3, -1, -1, -1, 0, - 5, -1, 0, - 3, -1, 0, - 2, 1, 0, - 1, 1, 1, 1, 1, 1 -}; - -#if DEBUG -/* - * Fill a buffer with a textual GUID representation. - * The buffer must be >= char[37] and will be populated - * with an ASCII NUL C string terminator. - * Example: 11111111-2222-3333-4444-444444444444 - * Endian: LLLLLLLL-LLLL-LLLL-BBBB-BBBBBBBBBBBB - */ -static void guid_to_str(char *buf, const struct guid *id) -{ - unsigned int i = 0; - const char *walker = (const char *)id; - - while (i < sizeof(guid_le_walk_map)) { - walker += guid_le_walk_map[i]; - if (!guid_le_walk_map[i]) - *buf = '-'; - else { - *buf = ((*walker & 0xF0) >> 4) + '0'; - if (*buf > '9') - *buf += 'A' - '9' - 1; - buf++; - *buf = (*walker & 0x0F) + '0'; - if (*buf > '9') - *buf += 'A' - '9' - 1; - } - buf++; - i++; - } - *buf = 0; -} -#endif - -/* - * Create a GUID structure from a textual GUID representation. - * The input buffer must be >= 32 hexadecimal chars and be - * terminated with an ASCII NUL. Returns non-zero on failure. - * Example: 11111111-2222-3333-4444-444444444444 - * Endian: LLLLLLLL-LLLL-LLLL-BBBB-BBBBBBBBBBBB - */ -static int str_to_guid(const char *buf, struct guid *id) -{ - char guid_seq[sizeof(struct guid) * 2]; - unsigned int i = 0; - char *walker = (char *)id; - - while (*buf && i < sizeof(guid_seq)) { - switch (*buf) { - /* Skip these three characters */ - case '{': - case '}': - case '-': - break; - default: - /* Copy something useful to the temp. sequence */ - if ((*buf >= '0') && (*buf <= '9')) - guid_seq[i] = *buf - '0'; - else if ((*buf >= 'A') && (*buf <= 'F')) - guid_seq[i] = *buf - 'A' + 10; - else if ((*buf >= 'a') && (*buf <= 'f')) - guid_seq[i] = *buf - 'a' + 10; - else { - /* Or not */ - error("Illegal character in GUID!\n"); - return -1; - } - i++; - } - buf++; - } - /* Check for insufficient valid characters */ - if (i < sizeof(guid_seq)) { - error("Too few GUID characters!\n"); - return -1; - } - buf = guid_seq; - i = 0; - while (i < sizeof(guid_le_walk_map)) { - if (!guid_le_walk_map[i]) - i++; - walker += guid_le_walk_map[i]; - *walker = *buf << 4; - buf++; - *walker |= *buf; - buf++; - i++; - } - return 0; -} - -/* A GPT partition */ -struct gpt_part { - struct guid type; - struct guid uid; - uint64_t lba_first; - uint64_t lba_last; - uint64_t attribs; - char name[72]; -} __attribute__ ((packed)); - -static void gpt_part_dump(const struct gpt_part *gpt_part) -{ -#ifdef DEBUG - unsigned int i; - char guid_text[37]; - - dprintf("----------------------------------\n" - "GPT part. LBA first __ : 0x%.16llx\n" - "GPT part. LBA last ___ : 0x%.16llx\n" - "GPT part. attribs ____ : 0x%.16llx\n" - "GPT part. name _______ : '", - gpt_part->lba_first, gpt_part->lba_last, gpt_part->attribs); - for (i = 0; i < sizeof(gpt_part->name); i++) { - if (gpt_part->name[i]) - dprintf("%c", gpt_part->name[i]); - } - dprintf("'"); - guid_to_str(guid_text, &gpt_part->type); - dprintf("GPT part. type GUID __ : {%s}\n", guid_text); - guid_to_str(guid_text, &gpt_part->uid); - dprintf("GPT part. unique ID __ : {%s}\n", guid_text); -#endif - (void)gpt_part; -} - -/* A GPT header */ -struct gpt { - char sig[8]; - union { - struct { - uint16_t minor; - uint16_t major; - } fields __attribute__ ((packed)); - uint32_t uint32; - char raw[4]; - } rev __attribute__ ((packed)); - uint32_t hdr_size; - uint32_t chksum; - char reserved1[4]; - uint64_t lba_cur; - uint64_t lba_alt; - uint64_t lba_first_usable; - uint64_t lba_last_usable; - struct guid disk_guid; - uint64_t lba_table; - uint32_t part_count; - uint32_t part_size; - uint32_t table_chksum; - char reserved2[1]; -} __attribute__ ((packed)); -static const char gpt_sig_magic[] = "EFI PART"; - -#if DEBUG -static void gpt_dump(const struct gpt *gpt) -{ - char guid_text[37]; - - printf("GPT sig ______________ : '%8.8s'\n" - "GPT major revision ___ : 0x%.4x\n" - "GPT minor revision ___ : 0x%.4x\n" - "GPT header size ______ : 0x%.8x\n" - "GPT header checksum __ : 0x%.8x\n" - "GPT reserved _________ : '%4.4s'\n" - "GPT LBA current ______ : 0x%.16llx\n" - "GPT LBA alternative __ : 0x%.16llx\n" - "GPT LBA first usable _ : 0x%.16llx\n" - "GPT LBA last usable __ : 0x%.16llx\n" - "GPT LBA part. table __ : 0x%.16llx\n" - "GPT partition count __ : 0x%.8x\n" - "GPT partition size ___ : 0x%.8x\n" - "GPT part. table chksum : 0x%.8x\n", - gpt->sig, - gpt->rev.fields.major, - gpt->rev.fields.minor, - gpt->hdr_size, - gpt->chksum, - gpt->reserved1, - gpt->lba_cur, - gpt->lba_alt, - gpt->lba_first_usable, - gpt->lba_last_usable, - gpt->lba_table, gpt->part_count, gpt->part_size, gpt->table_chksum); - guid_to_str(guid_text, &gpt->disk_guid); - printf("GPT disk GUID ________ : {%s}\n", guid_text); -} -#endif - -static struct disk_part_iter *next_gpt_part(struct disk_part_iter *part) -{ - const struct gpt_part *gpt_part = NULL; - - while (++part->private.gpt.index < part->private.gpt.parts) { - gpt_part = - (const struct gpt_part *)(part->block + - (part->private.gpt.index * - part->private.gpt.size)); - if (!gpt_part->lba_first) - continue; - break; - } - /* Were we the last partition? */ - if (part->private.gpt.index == part->private.gpt.parts) { - goto err_last; - } - part->lba_data = gpt_part->lba_first; - part->private.gpt.part_guid = &gpt_part->uid; - part->private.gpt.part_label = gpt_part->name; - /* Update our index */ - part->index = part->private.gpt.index + 1; - gpt_part_dump(gpt_part); - - /* In a GPT scheme, we re-use the iterator */ - return part; - -err_last: - free(part->block); - free(part); - - return NULL; -} - -static struct disk_part_iter *get_first_partition(struct disk_part_iter *part) -{ - const struct gpt *gpt_candidate; - - /* - * Ignore any passed partition iterator. The caller should - * have passed NULL. Allocate a new partition iterator - */ - part = malloc(sizeof(*part)); - if (!part) { - error("Count not allocate partition iterator!\n"); - goto err_alloc_iter; - } - /* Read MBR */ - part->block = read_sectors(0, 2); - if (!part->block) { - error("Could not read two sectors!\n"); - goto err_read_mbr; - } - /* Check for an MBR */ - if (((struct mbr *)part->block)->sig != mbr_sig_magic) { - error("No MBR magic!\n"); - goto err_mbr; - } - /* Establish a pseudo-partition for the MBR (index 0) */ - part->index = 0; - part->record = NULL; - part->private.mbr_index = -1; - part->next = next_mbr_part; - /* Check for a GPT disk */ - gpt_candidate = (const struct gpt *)(part->block + SECTOR); - if (!memcmp(gpt_candidate->sig, gpt_sig_magic, sizeof(gpt_sig_magic))) { - /* LBA for partition table */ - uint64_t lba_table; - - /* It looks like one */ - /* TODO: Check checksum. Possibly try alternative GPT */ -#if DEBUG - puts("Looks like a GPT disk."); - gpt_dump(gpt_candidate); -#endif - /* TODO: Check table checksum (maybe) */ - /* Note relevant GPT details */ - part->next = next_gpt_part; - part->private.gpt.index = -1; - part->private.gpt.parts = gpt_candidate->part_count; - part->private.gpt.size = gpt_candidate->part_size; - lba_table = gpt_candidate->lba_table; - gpt_candidate = NULL; - /* Load the partition table */ - free(part->block); - part->block = - read_sectors(lba_table, - ((part->private.gpt.size * part->private.gpt.parts) + - SECTOR - 1) / SECTOR); - if (!part->block) { - error("Could not read GPT partition list!\n"); - goto err_gpt_table; - } - } - /* Return the pseudo-partition's next partition, which is real */ - return part->next(part); - -err_gpt_table: - -err_mbr: - - free(part->block); - part->block = NULL; -err_read_mbr: - - free(part); -err_alloc_iter: - - return NULL; -} - -/* - * Search for a specific drive/partition, based on the GPT GUID. - * We return the disk drive number if found, as well as populating the - * boot_part pointer with the matching partition, if applicable. - * If no matching partition is found or the GUID is a disk GUID, - * boot_part will be populated with NULL. If not matching disk is - * found, we return -1. - */ -static int find_by_guid(const struct guid *gpt_guid, - struct disk_part_iter **boot_part) -{ - int drive; - bool is_me; - struct gpt *header; - - for (drive = 0x80; drive <= 0xff; drive++) { - if (get_disk_params(drive)) - continue; /* Drive doesn't exist */ - if (!(header = read_sectors(1, 1))) - continue; /* Cannot read sector */ - if (memcmp(&header->sig, gpt_sig_magic, sizeof(gpt_sig_magic))) { - /* Not a GPT disk */ - free(header); - continue; - } -#if DEBUG - gpt_dump(header); -#endif - is_me = !memcmp(&header->disk_guid, gpt_guid, sizeof(*gpt_guid)); - free(header); - if (!is_me) { - /* Check for a matching partition */ - boot_part[0] = get_first_partition(NULL); - while (boot_part[0]) { - is_me = - !memcmp(boot_part[0]->private.gpt.part_guid, gpt_guid, - sizeof(*gpt_guid)); - if (is_me) - break; - boot_part[0] = boot_part[0]->next(boot_part[0]); - } - } else - boot_part[0] = NULL; - if (is_me) - return drive; - } - return -1; -} - -/* - * Search for a specific partition, based on the GPT label. - * We return the disk drive number if found, as well as populating the - * boot_part pointer with the matching partition, if applicable. - * If no matching partition is found, boot_part will be populated with - * NULL and we return -1. - */ -static int find_by_label(const char *label, struct disk_part_iter **boot_part) -{ - int drive; - bool is_me; - - for (drive = 0x80; drive <= 0xff; drive++) { - if (get_disk_params(drive)) - continue; /* Drive doesn't exist */ - /* Check for a GPT disk */ - boot_part[0] = get_first_partition(NULL); - if (!(boot_part[0]->next == next_gpt_part)) { - /* Not a GPT disk */ - while (boot_part[0]) { - /* Run through until the end */ - boot_part[0] = boot_part[0]->next(boot_part[0]); - } - continue; - } - /* Check for a matching partition */ - while (boot_part[0]) { - char gpt_label[sizeof(((struct gpt_part *) NULL)->name)]; - const char *gpt_label_scanner = - boot_part[0]->private.gpt.part_label; - int j = 0; - - /* Re-write the GPT partition label as ASCII */ - while (gpt_label_scanner < - boot_part[0]->private.gpt.part_label + sizeof(gpt_label)) { - if ((gpt_label[j] = *gpt_label_scanner)) - j++; - gpt_label_scanner++; - } - if ((is_me = !strcmp(label, gpt_label))) - break; - boot_part[0] = boot_part[0]->next(boot_part[0]); - } - if (is_me) - return drive; - } - - return -1; -} - -static void do_boot(struct data_area *data, int ndata, - struct syslinux_rm_regs *regs) -{ - uint16_t *const bios_fbm = (uint16_t *) 0x413; - addr_t dosmem = *bios_fbm << 10; /* Technically a low bound */ - struct syslinux_memmap *mmap; - struct syslinux_movelist *mlist = NULL; - addr_t endimage; - uint8_t driveno = regs->edx.b[0]; - uint8_t swapdrive = driveno & 0x80; - int i; - - mmap = syslinux_memory_map(); - - if (!mmap) { - error("Cannot read system memory map\n"); - return; - } - - endimage = 0; - for (i = 0; i < ndata; i++) { - if (data[i].base + data[i].size > endimage) - endimage = data[i].base + data[i].size; - } - if (endimage > dosmem) - goto too_big; - - for (i = 0; i < ndata; i++) { - if (syslinux_add_movelist(&mlist, data[i].base, - (addr_t) data[i].data, data[i].size)) - goto enomem; - } - - if (opt.swap && driveno != swapdrive) { - static const uint8_t swapstub_master[] = { - /* The actual swap code */ - 0x53, /* 00: push bx */ - 0x0f, 0xb6, 0xda, /* 01: movzx bx,dl */ - 0x2e, 0x8a, 0x57, 0x60, /* 04: mov dl,[cs:bx+0x60] */ - 0x5b, /* 08: pop bx */ - 0xea, 0, 0, 0, 0, /* 09: jmp far 0:0 */ - 0x90, 0x90, /* 0E: nop; nop */ - /* Code to install this in the right location */ - /* Entry with DS = CS; ES = SI = 0; CX = 256 */ - 0x26, 0x66, 0x8b, 0x7c, 0x4c, /* 10: mov edi,[es:si+4*0x13] */ - 0x66, 0x89, 0x3e, 0x0a, 0x00, /* 15: mov [0x0A],edi */ - 0x26, 0x8b, 0x3e, 0x13, 0x04, /* 1A: mov di,[es:0x413] */ - 0x4f, /* 1F: dec di */ - 0x26, 0x89, 0x3e, 0x13, 0x04, /* 20: mov [es:0x413],di */ - 0x66, 0xc1, 0xe7, 0x16, /* 25: shl edi,16+6 */ - 0x26, 0x66, 0x89, 0x7c, 0x4c, /* 29: mov [es:si+4*0x13],edi */ - 0x66, 0xc1, 0xef, 0x10, /* 2E: shr edi,16 */ - 0x8e, 0xc7, /* 32: mov es,di */ - 0x31, 0xff, /* 34: xor di,di */ - 0xf3, 0x66, 0xa5, /* 36: rep movsd */ - 0xbe, 0, 0, /* 39: mov si,0 */ - 0xbf, 0, 0, /* 3C: mov di,0 */ - 0x8e, 0xde, /* 3F: mov ds,si */ - 0x8e, 0xc7, /* 41: mov es,di */ - 0x66, 0xb9, 0, 0, 0, 0, /* 43: mov ecx,0 */ - 0x66, 0xbe, 0, 0, 0, 0, /* 49: mov esi,0 */ - 0x66, 0xbf, 0, 0, 0, 0, /* 4F: mov edi,0 */ - 0xea, 0, 0, 0, 0, /* 55: jmp 0:0 */ - /* pad out to segment boundary */ - 0x90, 0x90, /* 5A: ... */ - 0x90, 0x90, 0x90, 0x90, /* 5C: ... */ - }; - static uint8_t swapstub[1024]; - uint8_t *p; - - /* Note: we can't rely on either INT 13h nor the dosmem - vector to be correct at this stage, so we have to use an - installer stub to put things in the right place. - Round the installer location to a 1K boundary so the only - possible overlap is the identity mapping. */ - endimage = (endimage + 1023) & ~1023; - - /* Create swap stub */ - memcpy(swapstub, swapstub_master, sizeof swapstub_master); - *(uint16_t *) & swapstub[0x3a] = regs->ds; - *(uint16_t *) & swapstub[0x3d] = regs->es; - *(uint32_t *) & swapstub[0x45] = regs->ecx.l; - *(uint32_t *) & swapstub[0x4b] = regs->esi.l; - *(uint32_t *) & swapstub[0x51] = regs->edi.l; - *(uint16_t *) & swapstub[0x56] = regs->ip; - *(uint16_t *) & swapstub[0x58] = regs->cs; - p = &swapstub[sizeof swapstub_master]; - - /* Mapping table; start out with identity mapping everything */ - for (i = 0; i < 256; i++) - p[i] = i; - - /* And the actual swap */ - p[driveno] = swapdrive; - p[swapdrive] = driveno; - - /* Adjust registers */ - regs->ds = regs->cs = endimage >> 4; - regs->es = regs->esi.l = 0; - regs->ecx.l = sizeof swapstub >> 2; - regs->ip = 0x10; /* Installer offset */ - regs->ebx.b[0] = regs->edx.b[0] = swapdrive; - - if (syslinux_add_movelist(&mlist, endimage, (addr_t) swapstub, - sizeof swapstub)) - goto enomem; - - endimage += sizeof swapstub; - } - - /* Tell the shuffler not to muck with this area... */ - syslinux_add_memmap(&mmap, endimage, 0xa0000 - endimage, SMT_RESERVED); - - /* Force text mode */ - syslinux_force_text_mode(); - - fputs("Booting...\n", stdout); - syslinux_shuffle_boot_rm(mlist, mmap, opt.keeppxe, regs); - error("Chainboot failed!\n"); - return; - -too_big: - error("Loader file too large\n"); - return; - -enomem: - error("Out of memory\n"); - return; -} - -static int hide_unhide(struct mbr *mbr, int part) -{ - int i; - struct part_entry *pt; - const uint16_t mask = - (1 << 0x01) | (1 << 0x04) | (1 << 0x06) | (1 << 0x07) | (1 << 0x0b) | (1 - << - 0x0c) - | (1 << 0x0e); - uint8_t t; - bool write_back = false; - - for (i = 1; i <= 4; i++) { - pt = mbr->table + i - 1; - t = pt->ostype; - if ((t <= 0x1f) && ((mask >> (t & ~0x10)) & 1)) { - /* It's a hideable partition type */ - if (i == part) - t &= ~0x10; /* unhide */ - else - t |= 0x10; /* hide */ - } - if (t != pt->ostype) { - write_back = true; - pt->ostype = t; - } - } - - if (write_back) - return write_verify_sector(0, mbr); - - return 0; /* ok */ -} - -static uint32_t get_file_lba(const char *filename) -{ - com32sys_t inregs; - uint32_t lba; - - /* Start with clean registers */ - memset(&inregs, 0, sizeof(com32sys_t)); - - /* Put the filename in the bounce buffer */ - strlcpy(__com32.cs_bounce, filename, __com32.cs_bounce_size); - - /* Call comapi_open() which returns a structure pointer in SI - * to a structure whose first member happens to be the LBA. - */ - inregs.eax.w[0] = 0x0006; - inregs.esi.w[0] = OFFS(__com32.cs_bounce); - inregs.es = SEG(__com32.cs_bounce); - __com32.cs_intcall(0x22, &inregs, &inregs); - - if ((inregs.eflags.l & EFLAGS_CF) || inregs.esi.w[0] == 0) { - return 0; /* Filename not found */ - } - - /* Since the first member is the LBA, we simply cast */ - lba = *((uint32_t *) MK_PTR(inregs.ds, inregs.esi.w[0])); - - /* Clean the registers for the next call */ - memset(&inregs, 0, sizeof(com32sys_t)); - - /* Put the filename in the bounce buffer */ - strlcpy(__com32.cs_bounce, filename, __com32.cs_bounce_size); - - /* Call comapi_close() to free the structure */ - inregs.eax.w[0] = 0x0008; - inregs.esi.w[0] = OFFS(__com32.cs_bounce); - inregs.es = SEG(__com32.cs_bounce); - __com32.cs_intcall(0x22, &inregs, &inregs); - - return lba; -} - -static void usage(void) -{ - static const char usage[] = "\ -Usage: chain.c32 [options]\n\ - chain.c32 hd<disk#> [<partition>] [options]\n\ - chain.c32 fd<disk#> [options]\n\ - chain.c32 mbr:<id> [<partition>] [options]\n\ - chain.c32 guid:<guid> [<partition>] [options]\n\ - chain.c32 label:<label> [<partition>] [options]\n\ - chain.c32 boot [<partition>] [options]\n\ - chain.c32 fs [options]\n\ -Options: file=<loader> Load and execute file, instead of boot sector\n\ - isolinux=<loader> Load another version of ISOLINUX\n\ - ntldr=<loader> Load Windows NTLDR, SETUPLDR.BIN or BOOTMGR\n\ - cmldr=<loader> Load Recovery Console of Windows NT/2K/XP/2003\n\ - freedos=<loader> Load FreeDOS KERNEL.SYS\n\ - msdos=<loader> Load MS-DOS IO.SYS\n\ - pcdos=<loader> Load PC-DOS IBMBIO.COM\n\ - drmk=<loader> Load DRMK DELLBIO.BIN\n\ - grub=<loader> Load GRUB Legacy stage2\n\ - grubcfg=<filename> Set alternative config filename for GRUB Legacy\n\ - grldr=<loader> Load GRUB4DOS grldr\n\ - seg=<segment> Jump to <seg>:0000, instead of 0000:7C00\n\ - swap Swap drive numbers, if bootdisk is not fd0/hd0\n\ - hide Hide primary partitions, except selected partition\n\ - sethidden Set the FAT/NTFS hidden sectors field\n\ - keeppxe Keep the PXE and UNDI stacks in memory (PXELINUX)\n\ -See syslinux/com32/modules/chain.c for more information\n"; - error(usage); -} - -int main(int argc, char *argv[]) -{ - struct mbr *mbr = NULL; - char *p; - struct disk_part_iter *cur_part = NULL; - struct syslinux_rm_regs regs; - char *drivename, *partition; - int hd, drive, whichpart = 0; /* MBR by default */ - int i; - uint64_t fs_lba = 0; /* Syslinux partition */ - uint32_t file_lba = 0; - struct guid gpt_guid; - unsigned char *isolinux_bin; - uint32_t *checksum, *chkhead, *chktail; - struct data_area data[3]; - int ndata = 0; - addr_t load_base; - static const char cmldr_signature[8] = "cmdcons"; - - openconsole(&dev_null_r, &dev_stdcon_w); - - drivename = "boot"; - partition = NULL; - - /* Prepare the register set */ - memset(®s, 0, sizeof regs); - - for (i = 1; i < argc; i++) { - if (!strncmp(argv[i], "file=", 5)) { - opt.loadfile = argv[i] + 5; - } else if (!strncmp(argv[i], "seg=", 4)) { - uint32_t segval = strtoul(argv[i] + 4, NULL, 0); - if (segval < 0x50 || segval > 0x9f000) { - error("Invalid segment\n"); - goto bail; - } - opt.seg = segval; - } else if (!strncmp(argv[i], "isolinux=", 9)) { - opt.loadfile = argv[i] + 9; - opt.isolinux = true; - } else if (!strncmp(argv[i], "ntldr=", 6)) { - opt.seg = 0x2000; /* NTLDR wants this address */ - opt.loadfile = argv[i] + 6; - opt.sethidden = true; - } else if (!strncmp(argv[i], "cmldr=", 6)) { - opt.seg = 0x2000; /* CMLDR wants this address */ - opt.loadfile = argv[i] + 6; - opt.cmldr = true; - opt.sethidden = true; - } else if (!strncmp(argv[i], "freedos=", 8)) { - opt.seg = 0x60; /* FREEDOS wants this address */ - opt.loadfile = argv[i] + 8; - opt.sethidden = true; - } else if (!strncmp(argv[i], "msdos=", 6) || - !strncmp(argv[i], "pcdos=", 6)) { - opt.seg = 0x70; /* MS-DOS 2.0+ wants this address */ - opt.loadfile = argv[i] + 6; - opt.sethidden = true; - } else if (!strncmp(argv[i], "drmk=", 5)) { - opt.seg = 0x70; /* DRMK wants this address */ - opt.loadfile = argv[i] + 5; - opt.sethidden = true; - opt.drmk = true; - } else if (!strncmp(argv[i], "grub=", 5)) { - opt.seg = 0x800; /* stage2 wants this address */ - opt.loadfile = argv[i] + 5; - opt.grub = true; - } else if (!strncmp(argv[i], "grubcfg=", 8)) { - opt.grubcfg = argv[i] + 8; - } else if (!strncmp(argv[i], "grldr=", 6)) { - opt.loadfile = argv[i] + 6; - opt.grldr = true; - } else if (!strcmp(argv[i], "swap")) { - opt.swap = true; - } else if (!strcmp(argv[i], "noswap")) { - opt.swap = false; - } else if (!strcmp(argv[i], "hide")) { - opt.hide = true; - } else if (!strcmp(argv[i], "nohide")) { - opt.hide = false; - } else if (!strcmp(argv[i], "keeppxe")) { - opt.keeppxe = 3; - } else if (!strcmp(argv[i], "sethidden")) { - opt.sethidden = true; - } else if (!strcmp(argv[i], "nosethidden")) { - opt.sethidden = false; - } else if (((argv[i][0] == 'h' || argv[i][0] == 'f') - && argv[i][1] == 'd') - || !strncmp(argv[i], "mbr:", 4) - || !strncmp(argv[i], "mbr=", 4) - || !strncmp(argv[i], "guid:", 5) - || !strncmp(argv[i], "guid=", 5) - || !strncmp(argv[i], "uuid:", 5) - || !strncmp(argv[i], "uuid=", 5) - || !strncmp(argv[i], "label:", 6) - || !strncmp(argv[i], "label=", 6) - || !strcmp(argv[i], "boot") - || !strncmp(argv[i], "boot,", 5) - || !strcmp(argv[i], "fs")) { - drivename = argv[i]; - p = strchr(drivename, ','); - if (p) { - *p = '\0'; - partition = p + 1; - } else if (argv[i + 1] && argv[i + 1][0] >= '0' - && argv[i + 1][0] <= '9') { - partition = argv[++i]; - } - } else { - usage(); - goto bail; - } - } - - if (opt.grubcfg && !opt.grub) { - error("grubcfg=<filename> must be used together with grub=<loader>.\n"); - goto bail; - } - - if (opt.seg) { - regs.es = regs.cs = regs.ss = regs.ds = regs.fs = regs.gs = opt.seg; - } else { - regs.ip = regs.esp.l = 0x7c00; - } - - hd = 0; - if (!strncmp(drivename, "mbr", 3)) { - drive = find_disk(strtoul(drivename + 4, NULL, 0)); - if (drive == -1) { - error("Unable to find requested MBR signature\n"); - goto bail; - } - } else if (!strncmp(drivename, "guid", 4) || - !strncmp(drivename, "uuid", 4)) { - if (str_to_guid(drivename + 5, &gpt_guid)) - goto bail; - drive = find_by_guid(&gpt_guid, &cur_part); - if (drive == -1) { - error("Unable to find requested GPT disk/partition\n"); - goto bail; - } - } else if (!strncmp(drivename, "label", 5)) { - if (!drivename[6]) { - error("No label specified.\n"); - goto bail; - } - drive = find_by_label(drivename + 6, &cur_part); - if (drive == -1) { - error("Unable to find requested partition by label\n"); - goto bail; - } - } else if ((drivename[0] == 'h' || drivename[0] == 'f') && - drivename[1] == 'd') { - hd = drivename[0] == 'h'; - drivename += 2; - drive = (hd ? 0x80 : 0) | strtoul(drivename, NULL, 0); - } else if (!strcmp(drivename, "boot") || !strcmp(drivename, "fs")) { - const union syslinux_derivative_info *sdi; - - sdi = syslinux_derivative_info(); - if (sdi->c.filesystem == SYSLINUX_FS_PXELINUX) - drive = 0x80; /* Boot drive not available */ - else - drive = sdi->disk.drive_number; - if (!strcmp(drivename, "fs") - && (sdi->c.filesystem == SYSLINUX_FS_SYSLINUX - || sdi->c.filesystem == SYSLINUX_FS_EXTLINUX - || sdi->c.filesystem == SYSLINUX_FS_ISOLINUX)) - /* We should lookup the Syslinux partition number and use it */ - fs_lba = *sdi->disk.partoffset; - } else { - error("Unparsable drive specification\n"); - goto bail; - } - - /* DOS kernels want the drive number in BL instead of DL. Indulge them. */ - regs.ebx.b[0] = regs.edx.b[0] = drive; - - /* Get the disk geometry and disk access setup */ - if (get_disk_params(drive)) { - error("Cannot get disk parameters\n"); - goto bail; - } - - /* Get MBR */ - if (!(mbr = read_sectors(0, 1))) { - error("Cannot read Master Boot Record or sector 0\n"); - goto bail; - } - - if (partition) - whichpart = strtoul(partition, NULL, 0); - /* "guid:" or "label:" might have specified a partition */ - if (cur_part) - whichpart = cur_part->index; - - /* Boot the MBR by default */ - if (!cur_part && (whichpart || fs_lba)) { - /* Boot a partition, possibly the Syslinux partition itself */ - cur_part = get_first_partition(NULL); - while (cur_part) { - if ((cur_part->index == whichpart) - || (cur_part->lba_data == fs_lba)) - /* Found the partition to boot */ - break; - cur_part = cur_part->next(cur_part); - } - if (!cur_part) { - error("Requested partition not found!\n"); - goto bail; - } - whichpart = cur_part->index; - } - - if (!(drive & 0x80) && whichpart) { - error("Warning: Partitions of floppy devices may not work\n"); - } - - /* - * GRLDR of GRUB4DOS wants the partition number in DH: - * -1: whole drive (default) - * 0-3: primary partitions - * 4-*: logical partitions - */ - if (opt.grldr) - regs.edx.b[1] = whichpart - 1; - - if (opt.hide) { - if (whichpart < 1 || whichpart > 4) - error("WARNING: hide specified without a non-primary partition\n"); - if (hide_unhide(mbr, whichpart)) - error("WARNING: failed to write MBR for 'hide'\n"); - } - - /* Do the actual chainloading */ - load_base = opt.seg ? (opt.seg << 4) : 0x7c00; - - if (opt.loadfile) { - fputs("Loading the boot file...\n", stdout); - if (loadfile(opt.loadfile, &data[ndata].data, &data[ndata].size)) { - error("Failed to load the boot file\n"); - goto bail; - } - data[ndata].base = load_base; - load_base = 0x7c00; /* If we also load a boot sector */ - - /* Create boot info table: needed when you want to chainload - another version of ISOLINUX (or another bootlaoder that needs - the -boot-info-table switch of mkisofs) - (will only work when run from ISOLINUX) */ - if (opt.isolinux) { - const union syslinux_derivative_info *sdi; - sdi = syslinux_derivative_info(); - - if (sdi->c.filesystem == SYSLINUX_FS_ISOLINUX) { - /* Boot info table info (integers in little endian format) - - Offset Name Size Meaning - 8 bi_pvd 4 bytes LBA of primary volume descriptor - 12 bi_file 4 bytes LBA of boot file - 16 bi_length 4 bytes Boot file length in bytes - 20 bi_csum 4 bytes 32-bit checksum - 24 bi_reserved 40 bytes Reserved - - The 32-bit checksum is the sum of all the 32-bit words in the - boot file starting at byte offset 64. All linear block - addresses (LBAs) are given in CD sectors (normally 2048 bytes). - - LBA of primary volume descriptor should already be set to 16. - */ - - isolinux_bin = (unsigned char *)data[ndata].data; - - /* Get LBA address of bootfile */ - file_lba = get_file_lba(opt.loadfile); - - if (file_lba == 0) { - error("Failed to find LBA offset of the boot file\n"); - goto bail; - } - /* Set it */ - *((uint32_t *) & isolinux_bin[12]) = file_lba; - - /* Set boot file length */ - *((uint32_t *) & isolinux_bin[16]) = data[ndata].size; - - /* Calculate checksum */ - checksum = (uint32_t *) & isolinux_bin[20]; - chkhead = (uint32_t *) & isolinux_bin[64]; - chktail = (uint32_t *) & isolinux_bin[data[ndata].size & ~3]; - *checksum = 0; - while (chkhead < chktail) - *checksum += *chkhead++; - - /* - * Deal with possible fractional dword at the end; - * this *should* never happen... - */ - if (data[ndata].size & 3) { - uint32_t xword = 0; - memcpy(&xword, chkhead, data[ndata].size & 3); - *checksum += xword; - } - } else { - error - ("The isolinux= option is only valid when run from ISOLINUX\n"); - goto bail; - } - } - - if (opt.grub) { - /* Layout of stage2 file (from byte 0x0 to 0x270) */ - struct grub_stage2_patch_area { - /* 0x0 to 0x205 */ - char unknown[0x206]; - /* 0x206: compatibility version number major */ - uint8_t compat_version_major; - /* 0x207: compatibility version number minor */ - uint8_t compat_version_minor; - - /* 0x208: install_partition variable */ - struct { - /* 0x208: sub-partition in sub-partition part2 */ - uint8_t part3; - /* 0x209: sub-partition in top-level partition */ - uint8_t part2; - /* 0x20a: top-level partiton number */ - uint8_t part1; - /* 0x20b: BIOS drive number (must be 0) */ - uint8_t drive; - } __attribute__ ((packed)) install_partition; - - /* 0x20c: deprecated (historical reason only) */ - uint32_t saved_entryno; - /* 0x210: stage2_ID: will always be STAGE2_ID_STAGE2 = 0 in stage2 */ - uint8_t stage2_id; - /* 0x211: force LBA */ - uint8_t force_lba; - /* 0x212: version string (will probably be 0.97) */ - char version_string[5]; - /* 0x217: config filename */ - char config_file[89]; - /* 0x270: start of code (after jump from 0x200) */ - char codestart[1]; - } __attribute__ ((packed)) *stage2; - - if (data[ndata].size < sizeof(struct grub_stage2_patch_area)) { - error - ("The file specified by grub=<loader> is to small to be stage2 of GRUB Legacy.\n"); - goto bail; - } - - stage2 = data[ndata].data; - - /* - * Check the compatibility version number to see if we loaded a real - * stage2 file or a stage2 file that we support. - */ - if (stage2->compat_version_major != 3 - || stage2->compat_version_minor != 2) { - error - ("The file specified by grub=<loader> is not a supported stage2 GRUB Legacy binary\n"); - goto bail; - } - - /* jump 0x200 bytes into the loadfile */ - regs.ip = 0x200; - - /* - * GRUB Legacy wants the partition number in the install_partition - * variable, located at offset 0x208 of stage2. - * When GRUB Legacy is loaded, it is located at memory address 0x8208. - * - * It looks very similar to the "boot information format" of the - * Multiboot specification: - * http://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Boot-information-format - * - * 0x208 = part3: sub-partition in sub-partition part2 - * 0x209 = part2: sub-partition in top-level partition - * 0x20a = part1: top-level partition number - * 0x20b = drive: BIOS drive number (must be 0) - * - * GRUB Legacy doesn't store the BIOS drive number at 0x20b, but at - * another location. - * - * Partition numbers always start from zero. - * Unused partition bytes must be set to 0xFF. - * - * We only care about top-level partition, so we only need to change - * "part1" to the appropriate value: - * -1: whole drive (default) (-1 = 0xFF) - * 0-3: primary partitions - * 4-*: logical partitions - */ - stage2->install_partition.part1 = whichpart - 1; - - /* - * Grub Legacy reserves 89 bytes (from 0x8217 to 0x826f) for the - * config filename. The filename passed via grubcfg= will overwrite - * the default config filename "/boot/grub/menu.lst". - */ - if (opt.grubcfg) { - if (strlen(opt.grubcfg) > sizeof(stage2->config_file) - 1) { - error - ("The config filename length can't exceed 88 characters.\n"); - goto bail; - } - - strcpy((char *)stage2->config_file, opt.grubcfg); - } - } - - if (opt.drmk) { - /* DRMK entry is different than MS-DOS/PC-DOS */ - /* - * A new size, aligned to 16 bytes to ease use of ds:[bp+28]. - * We only really need 4 new, usable bytes at the end. - */ - int tsize = (data[ndata].size + 19) & 0xfffffff0; - const union syslinux_derivative_info *sdi; - - sdi = syslinux_derivative_info(); - /* We should lookup the Syslinux partition offset and use it */ - fs_lba = *sdi->disk.partoffset; - /* - * fs_lba should be verified against the disk as some DRMK - * variants will check and fail if it does not match - */ - dprintf(" fs_lba offset is %d\n", fs_lba); - /* DRMK only uses a DWORD */ - if (fs_lba > 0xffffffff) { - error("LBA very large; Only using lower 32 bits; DRMK will probably fail\n"); - } - regs.ss = regs.fs = regs.gs = 0; /* Used before initialized */ - if (!realloc(data[ndata].data, tsize)) { - error("Failed to realloc for DRMK\n"); - goto bail; /* We'll never make it */ - } - data[ndata].size = tsize; - /* ds:bp is assumed by DRMK to be the boot sector */ - /* offset 28 is the FAT HiddenSectors value */ - regs.ds = (tsize >> 4) + (opt.seg - 2); - /* "Patch" into tail of the new space */ - *(int *)(data[ndata].data + tsize - 4) = (int)(fs_lba & 0xffffffff); - } - - ndata++; - } - - if (!opt.loadfile || data[0].base >= 0x7c00 + SECTOR) { - /* Actually read the boot sector */ - if (!cur_part) { - data[ndata].data = mbr; - } else if (!(data[ndata].data = read_sectors(cur_part->lba_data, 1))) { - error("Cannot read boot sector\n"); - goto bail; - } - data[ndata].size = SECTOR; - data[ndata].base = load_base; - - if (!opt.loadfile) { - const struct mbr *br = - (const struct mbr *)((char *)data[ndata].data + - data[ndata].size - sizeof(struct mbr)); - if (br->sig != mbr_sig_magic) { - error - ("Boot sector signature not found (unbootable disk/partition?)\n"); - goto bail; - } - } - /* - * To boot the Recovery Console of Windows NT/2K/XP we need to write - * the string "cmdcons\0" to memory location 0000:7C03. - * Memory location 0000:7C00 contains the bootsector of the partition. - */ - if (cur_part && opt.cmldr) { - memcpy((char *)data[ndata].data + 3, cmldr_signature, - sizeof cmldr_signature); - } - - /* - * Modify the hidden sectors (partition offset) copy in memory; - * this modifies the field used by FAT and NTFS filesystems, and - * possibly other boot loaders which use the same format. - */ - if (cur_part && opt.sethidden) { - *(uint32_t *) ((char *)data[ndata].data + 28) = cur_part->lba_data; - } - - ndata++; - } - - if (cur_part) { - if (cur_part->next == next_gpt_part) { - /* Do GPT hand-over, if applicable (as per syslinux/doc/gpt.txt) */ - struct part_entry *record; - /* Look at the GPT partition */ - const struct gpt_part *gp = (const struct gpt_part *) - (cur_part->block + - (cur_part->private.gpt.size * cur_part->private.gpt.index)); - /* Note the partition length */ - uint64_t lba_count = gp->lba_last - gp->lba_first + 1; - /* The length of the hand-over */ - int synth_size = - sizeof(struct part_entry) + sizeof(uint32_t) + - cur_part->private.gpt.size; - /* Will point to the partition record length in the hand-over */ - uint32_t *plen; - - /* Allocate the hand-over record */ - record = malloc(synth_size); - if (!record) { - error("Could not build GPT hand-over record!\n"); - goto bail; - } - /* Synthesize the record */ - memset(record, 0, synth_size); - record->active_flag = 0x80; - record->ostype = 0xED; - /* All bits set by default */ - record->start_lba = ~(uint32_t) 0; - record->length = ~(uint32_t) 0; - /* If these fit the precision, pass them on */ - if (cur_part->lba_data < record->start_lba) - record->start_lba = cur_part->lba_data; - if (lba_count < record->length) - record->length = lba_count; - /* Next comes the GPT partition record length */ - plen = (uint32_t *) (record + 1); - plen[0] = cur_part->private.gpt.size; - /* Next comes the GPT partition record copy */ - memcpy(plen + 1, gp, plen[0]); - cur_part->record = record; - - regs.eax.l = 0x54504721; /* '!GPT' */ - data[ndata].base = 0x7be; - data[ndata].size = synth_size; - data[ndata].data = (void *)record; - ndata++; - regs.esi.w[0] = 0x7be; - - dprintf("GPT handover:\n"); - mbr_part_dump(record); - gpt_part_dump((struct gpt_part *)(plen + 1)); - } else if (cur_part->record) { - /* MBR handover protocol */ - static struct part_entry handover_record; - - handover_record = *cur_part->record; - handover_record.start_lba = cur_part->lba_data; - - data[ndata].base = 0x7be; - data[ndata].size = sizeof handover_record; - data[ndata].data = &handover_record; - ndata++; - regs.esi.w[0] = 0x7be; - - dprintf("MBR handover:\n"); - mbr_part_dump(&handover_record); - } - } - - do_boot(data, ndata, ®s); - -bail: - if (cur_part) { - free(cur_part->block); - free((void *)cur_part->record); - } - free(cur_part); - free(mbr); - return 255; -} diff --git a/com32/modules/elf.c b/com32/modules/elf.c index 182afa60..0ac45174 100644 --- a/com32/modules/elf.c +++ b/com32/modules/elf.c @@ -120,10 +120,8 @@ int boot_elf(void *ptr, size_t len, char **argv) if (!mmap || !amap) goto bail; -#if DEBUG dprintf("Initial memory map:\n"); - syslinux_dump_memmap(stdout, mmap); -#endif + syslinux_dump_memmap(mmap); ph = (Elf32_Phdr *) (cptr + eh->e_phoff); @@ -185,10 +183,8 @@ int boot_elf(void *ptr, size_t len, char **argv) if (!stack_frame) goto bail; -#if DEBUG dprintf("Right before syslinux_memmap_largest()...\n"); - syslinux_dump_memmap(stdout, amap); -#endif + syslinux_dump_memmap(amap); if (syslinux_memmap_largest(amap, SMT_FREE, &lstart, &llen)) goto bail; /* NO free memory?! */ @@ -239,16 +235,14 @@ int boot_elf(void *ptr, size_t len, char **argv) regs.eip = eh->e_entry; regs.esp = stack_pointer; -#if DEBUG dprintf("Final memory map:\n"); - syslinux_dump_memmap(stdout, mmap); + syslinux_dump_memmap(mmap); dprintf("Final available map:\n"); - syslinux_dump_memmap(stdout, amap); + syslinux_dump_memmap(amap); dprintf("Movelist:\n"); - syslinux_dump_movelist(stdout, ml); -#endif + syslinux_dump_movelist(ml); /* This should not return... */ fputs("Booting...\n", stdout); diff --git a/com32/modules/ethersel.c b/com32/modules/ethersel.c index 5c3cf02a..28dc62ca 100644 --- a/com32/modules/ethersel.c +++ b/com32/modules/ethersel.c @@ -38,12 +38,7 @@ #include <com32.h> #include <syslinux/boot.h> #include <syslinux/config.h> - -#ifdef DEBUG -# define dprintf printf -#else -# define dprintf(...) ((void)0) -#endif +#include <dprintf.h> #define MAX_LINE 512 diff --git a/com32/modules/ifcpu.c b/com32/modules/ifcpu.c index a28acc4e..0aa63327 100644 --- a/com32/modules/ifcpu.c +++ b/com32/modules/ifcpu.c @@ -49,11 +49,12 @@ static void usage(void) " dry-run : just do the detection, don't boot \n" "\n" "cpu_features could be:\n" - " 64 : Processor is x86_64 compatible (lm cpu flag)\n" - " hvm : Processor features hardware virtualization (hvm or svm cpu flag)\n" - " multicore : Processor must be multi-core \n" - " smp : System must be multi-processor \n" - " pae : Processor features Physical Address Extension (PAE)\n" + " 64 : Processor is x86_64 compatible (lm cpu flag)\n" + " hvm : Processor features hardware virtualization (hvm or svm cpu flag)\n" + " multicore : Processor must be multi-core \n" + " smp : System must be multi-processor \n" + " pae : Processor features Physical Address Extension (PAE)\n" + " hypervisor : Processor is running under an hypervisor\n" "\n" "if you want to match many cpu features, just separate them with a single space.\n"); } @@ -114,30 +115,34 @@ int main(int argc, char *argv[]) args[n++] = &argv[i + 1]; } else if (!strcmp(argv[i], "64")) { if (debug) - printf(" 64bit : %s on this system\n", + printf(" 64bit : %s on this system\n", show_bool(cpu.flags.lm)); hardware_matches = cpu.flags.lm && hardware_matches; } else if (!strcmp(argv[i], "pae")) { if (debug) - printf(" pae : %s on this system\n", + printf(" pae : %s on this system\n", show_bool(cpu.flags.pae)); hardware_matches = cpu.flags.pae && hardware_matches; } else if (!strcmp(argv[i], "hvm")) { if (debug) - printf(" hvm : %s on this system\n", + printf(" hvm : %s on this system\n", show_bool((cpu.flags.vmx || cpu.flags.svm))); hardware_matches = (cpu.flags.vmx || cpu.flags.svm) && hardware_matches; } else if (!strcmp(argv[i], "multicore")) { if (debug) - printf(" multicore : %d cores on this system\n", cpu.num_cores); + printf(" multicore : %d cores on this system\n", cpu.num_cores); if (cpu.num_cores > 1) multicore = true; hardware_matches = multicore && hardware_matches; } else if (!strcmp(argv[i], "smp")) { if (debug) - printf(" smp : %s on this system\n", show_bool(cpu.flags.smp)); + printf(" smp : %s on this system\n", show_bool(cpu.flags.smp)); hardware_matches = cpu.flags.smp && hardware_matches; + } else if (!strcmp(argv[i], "hypervisor")) { + if (debug) + printf(" hypervisor : %s on this system\n", show_bool(cpu.flags.hypervisor)); + hardware_matches = cpu.flags.hypervisor && hardware_matches; } else if (!strcmp(argv[i], "dry-run")) { dryrun = true; } else if (!strcmp(argv[i], "debug")) { diff --git a/com32/modules/ifmemdsk.c b/com32/modules/ifmemdsk.c new file mode 100644 index 00000000..cfed87f9 --- /dev/null +++ b/com32/modules/ifmemdsk.c @@ -0,0 +1,392 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2011 Shao Miller - 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., 51 Franklin St, Fifth Floor, + * Boston MA 02110-1301, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/**** + * @file ifmemdsk.c + * + * This COM32 module detects if there are MEMDISKs established. + */ + +static const char usage_text[] = "\ +Usage:\n\ + ifmemdsk.c32 [<option> [...]] --info [<option> [...]]\n\ + ifmemdsk.c32 [<option> [...]] [<detected_cmd>] -- [<not_detected_cmd>]\n\ +\n\ +Options:\n\ + --info . . . . . Displays info about MEMDISK(s)\n\ + --safe-hooks . . Will scan INT 13h \"safe hook\" chain\n\ + --mbfts . . . . . Will scan memory for MEMDISK mBFTs\n\ + --no-sequential Suppresses probing all drive numbers\n\ +\n\ +If a MEMDISK is found, or if a particular MEMDISK is sought by the options\n\ +and is found, then the 'detected_cmd' action will be taken, else the\n\ +'not_detected_cmd' action will be taken.\n\ +\n"; + +#include <stdio.h> +#include <string.h> +#include <alloca.h> +#include <com32.h> +#include <console.h> +#include <syslinux/boot.h> + +/* Pull in MEMDISK common structures */ +#include "../../memdisk/mstructs.h" + +/*** Macros */ +#define M_GET_DRIVE_PARAMS (0x08) +#define M_SEGOFFTOPTR(seg, off) (((seg) << 4) + (off)) +#define M_INT13H M_SEGOFFTOPTR(0x0000, 0x0013 * 4) +#define M_FREEBASEMEM M_SEGOFFTOPTR(0x0040, 0x0013) +#define M_TOP M_SEGOFFTOPTR(0x9FFF, 0x0000) + +/*** Object types */ +typedef struct mdi s_mdi; +typedef real_addr_t u_segoff; +typedef struct safe_hook s_safe_hook; +typedef struct mBFT s_mbft; + +/*** Function types */ +typedef int f_find(void); + +/*** Function declarations */ +static const s_mdi * installation_check(int); +static f_find scan_drives; +static f_find walk_safe_hooks; +static const s_safe_hook * is_safe_hook(const void *); +static const s_mdi * is_memdisk_hook(const s_safe_hook *); +static f_find scan_mbfts; +static const s_mbft * is_mbft(const void *); +static f_find do_nothing; +static void memdisk_info(const s_mdi *); +static void boot_args(char **); +static const char * bootloadername(uint8_t); + +/*** Structure/union definitions */ + +/*** Objects */ +static int show_info = 0; + +/*** Function definitions */ + +int main(int argc, char ** argv) { + static f_find * do_scan_drives = scan_drives; + static f_find * do_walk_safe_hooks = do_nothing; + static f_find * do_scan_mbfts = do_nothing; + char ** detected_cmd; + char ** not_detected_cmd; + char ** cmd; + char ** cur_arg; + int show_usage; + int found; + + (void) argc; + + openconsole(&dev_null_r, &dev_stdcon_w); + + detected_cmd = NULL; + not_detected_cmd = NULL; + show_usage = 1; + for (cur_arg = argv + 1; *cur_arg; ++cur_arg) { + /* Check for command divider */ + if (!strcmp(*cur_arg, "--")) { + show_usage = 0; + *cur_arg = NULL; + not_detected_cmd = cur_arg + 1; + break; + } + + /* Check for '--info' */ + if (!strcmp(*cur_arg, "--info")) { + show_usage = 0; + show_info = 1; + continue; + } + + /* Other options */ + if (!strcmp(*cur_arg, "--no-sequential")) { + do_scan_drives = do_nothing; + continue; + } + + if (!strcmp(*cur_arg, "--safe-hooks")) { + do_walk_safe_hooks = walk_safe_hooks; + continue; + } + + if (!strcmp(*cur_arg, "--mbfts")) { + do_scan_mbfts = scan_mbfts; + continue; + } + + /* Check for invalid option */ + if (!memcmp(*cur_arg, "--", sizeof "--" - 1)) { + puts("Invalid option!"); + show_usage = 1; + break; + } + + /* Set 'detected_cmd' if it's null */ + if (!detected_cmd) + detected_cmd = cur_arg; + + continue; + } + + if (show_usage) { + fprintf(stderr, usage_text); + return 1; + } + + found = 0; + found += do_walk_safe_hooks(); + found += do_scan_mbfts(); + found += do_scan_drives(); + + cmd = found ? detected_cmd : not_detected_cmd; + if (cmd && *cmd) + boot_args(cmd); + + return 0; + } + +static const s_mdi * installation_check(int drive) { + com32sys_t params, results; + int found; + + /* Set parameters for INT 0x13 call */ + memset(¶ms, 0, sizeof params); + params.eax.w[0] = M_GET_DRIVE_PARAMS << 8; + params.edx.w[0] = drive; + /* 'ME' 'MD' 'IS' 'K?' */ + params.eax.w[1] = 0x454D; + params.ecx.w[1] = 0x444D; + params.edx.w[1] = 0x5349; + params.ebx.w[1] = 0x3F4B; + + /* Perform the call */ + __intcall(0x13, ¶ms, &results); + + /* Check result */ + found = ( + /* '!M' 'EM' 'DI' 'SK' */ + results.eax.w[1] == 0x4D21 && + results.ecx.w[1] == 0x4D45 && + results.edx.w[1] == 0x4944 && + results.ebx.w[1] == 0x4B53 + ); + + if (found) + return MK_PTR(results.es, results.edi.w[0]); + + return NULL; + } + +static int scan_drives(void) { + int found, drive; + const s_mdi * mdi; + + for (found = drive = 0; drive <= 0xFF; ++drive) { + mdi = installation_check(drive); + if (!mdi) + continue; + + memdisk_info(mdi); + ++found; + continue; + } + + return found; + } + +static int walk_safe_hooks(void) { + static const u_segoff * const int13 = (void *) M_INT13H; + const void * addr; + int found; + const s_safe_hook * hook; + const s_mdi * mdi; + + /* INT 0x13 vector */ + addr = MK_PTR(int13->seg_off.segment, int13->seg_off.offset); + found = 0; + while (addr) { + hook = is_safe_hook(addr); + if (!hook) + break; + + mdi = is_memdisk_hook(hook); + if (mdi) { + memdisk_info(mdi); + ++found; + } + + addr = MK_PTR( + hook->old_hook.seg_off.segment, + hook->old_hook.seg_off.offset + ); + continue; + } + return found; + } + +static const s_safe_hook * is_safe_hook(const void * addr) { + static const char magic[] = "$INT13SF"; + const s_safe_hook * const test = addr; + + if (memcmp(test->signature, magic, sizeof magic - 1)) + return NULL; + + return test; + } + +static const s_mdi * is_memdisk_hook(const s_safe_hook * hook) { + static const char magic[] = "MEMDISK"; + const s_mbft * mbft; + + if (memcmp(hook->vendor, magic, sizeof magic - 1)) + return NULL; + + /* An mBFT is always aligned */ + mbft = MK_PTR(hook->mbft >> 4, 0); + return &mbft->mdi; + } + +static int scan_mbfts(void) { + static const uint16_t * const free_base_mem = (void *) M_FREEBASEMEM; + static const void * const top = (void *) M_TOP; + const void * addr; + const s_mbft * mbft; + int found; + + found = 0; + for (addr = MK_PTR(*free_base_mem << 4, 0); addr < top; addr += 1 << 4) { + if (!(mbft = is_mbft(addr))) + continue; + + memdisk_info(&mbft->mdi); + ++found; + continue; + } + + return found; + } + +static const s_mbft * is_mbft(const void * addr) { + static const char magic[] = "mBFT"; + const s_mbft * const test = addr; + const uint8_t * ptr, * end; + uint8_t chksum; + + if (memcmp(test->acpi.signature, magic, sizeof magic - 1)) + return NULL; + + if (test->acpi.length != sizeof *test) + return NULL; + + end = (void *) (test + 1); + chksum = 0; + for (ptr = addr; ptr < end; ++ptr) + chksum += *ptr; + if (chksum) + return NULL; + + /* Looks like it's an mBFT! */ + return test; + } + +static int do_nothing(void) { + return 0; + } + +static void memdisk_info(const s_mdi * mdi) { + const char * cmdline; + + if (!show_info) + return; + + cmdline = MK_PTR( + mdi->cmdline.seg_off.segment, + mdi->cmdline.seg_off.offset + ); + printf( + "Found MEMDISK version %u.%02u:\n" + " diskbuf == 0x%08X, disksize == %u sectors\n" + " bootloaderid == 0x%02X (%s),\n" + " cmdline: %s\n", + mdi->version_major, + mdi->version_minor, + mdi->diskbuf, + mdi->disksize, + mdi->bootloaderid, + bootloadername(mdi->bootloaderid), + cmdline + ); + return; + } + +/* This function copyright H. Peter Anvin */ +static void boot_args(char **args) +{ + int len = 0, a = 0; + char **pp; + const char *p; + char c, *q, *str; + + for (pp = args; *pp; pp++) + len += strlen(*pp) + 1; + + q = str = alloca(len); + for (pp = args; *pp; pp++) { + p = *pp; + while ((c = *p++)) + *q++ = c; + *q++ = ' '; + a = 1; + } + q -= a; + *q = '\0'; + + if (!str[0]) + syslinux_run_default(); + else + syslinux_run_command(str); +} + +/* This function copyright H. Peter Anvin */ +static const char *bootloadername(uint8_t id) +{ + static const struct { + uint8_t id, mask; + const char *name; + } *lp, list[] = { + {0x00, 0xf0, "LILO"}, + {0x10, 0xf0, "LOADLIN"}, + {0x31, 0xff, "SYSLINUX"}, + {0x32, 0xff, "PXELINUX"}, + {0x33, 0xff, "ISOLINUX"}, + {0x34, 0xff, "EXTLINUX"}, + {0x30, 0xf0, "Syslinux family"}, + {0x40, 0xf0, "Etherboot"}, + {0x50, 0xf0, "ELILO"}, + {0x70, 0xf0, "GrUB"}, + {0x80, 0xf0, "U-Boot"}, + {0xA0, 0xf0, "Gujin"}, + {0xB0, 0xf0, "Qemu"}, + {0x00, 0x00, "unknown"} + }; + + for (lp = list;; lp++) { + if (((id ^ lp->id) & lp->mask) == 0) + return lp->name; + } +} + 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/linux.c b/com32/modules/linux.c index b902ebc5..76443f91 100644 --- a/com32/modules/linux.c +++ b/com32/modules/linux.c @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------- * * * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved - * Copyright 2009 Intel Corporation; author: H. Peter Anvin + * Copyright 2009-2012 Intel Corporation; author: H. Peter Anvin * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -38,6 +38,7 @@ * Usage: linux.c32 [-dhcpinfo] kernel arguments... */ +#include <errno.h> #include <stdbool.h> #include <stdlib.h> #include <stdio.h> @@ -108,10 +109,31 @@ static char *make_cmdline(char **argv) return cmdline; } +static int setup_data_file(struct setup_data *setup_data, + uint32_t type, const char *filename, + bool opt_quiet) +{ + if (!opt_quiet) + printf("Loading %s... ", filename); + + if (setup_data_load(setup_data, type, filename)) { + if (opt_quiet) + printf("Loading %s ", filename); + printf("failed\n"); + return -1; + } + + if (!opt_quiet) + printf("ok\n"); + + return 0; +} + int main(int argc, char *argv[]) { const char *kernel_name; struct initramfs *initramfs; + struct setup_data *setup_data; char *cmdline; char *boot_image; void *kernel_data; @@ -120,7 +142,7 @@ int main(int argc, char *argv[]) bool opt_quiet = false; void *dhcpdata; size_t dhcplen; - char **argp, *arg, *p; + char **argp, **argl, *arg, *p; openconsole(&dev_null_r, &dev_stdcon_w); @@ -144,9 +166,12 @@ int main(int argc, char *argv[]) kernel_name = arg; + errno = 0; boot_image = malloc(strlen(kernel_name) + 12); - if (!boot_image) + if (!boot_image) { + fprintf(stderr, "Error allocating BOOT_IMAGE string: "); goto bail; + } strcpy(boot_image, "BOOT_IMAGE="); strcpy(boot_image + 11, kernel_name); /* argp now points to the kernel name, and the command line follows. @@ -159,23 +184,30 @@ int main(int argc, char *argv[]) if (!opt_quiet) printf("Loading %s... ", kernel_name); + errno = 0; if (loadfile(kernel_name, &kernel_data, &kernel_len)) { if (opt_quiet) printf("Loading %s ", kernel_name); - printf("failed!\n"); + printf("failed: "); goto bail; } if (!opt_quiet) printf("ok\n"); + errno = 0; cmdline = make_cmdline(argp); - if (!cmdline) + if (!cmdline) { + fprintf(stderr, "make_cmdline() failed: "); goto bail; + } /* Initialize the initramfs chain */ + errno = 0; initramfs = initramfs_init(); - if (!initramfs) + if (!initramfs) { + fprintf(stderr, "initramfs_init() failed: "); goto bail; + } if ((arg = find_argument(argp, "initrd="))) { do { @@ -185,10 +217,11 @@ int main(int argc, char *argv[]) if (!opt_quiet) printf("Loading %s... ", arg); + errno = 0; if (initramfs_load_archive(initramfs, arg)) { if (opt_quiet) printf("Loading %s ", kernel_name); - printf("failed!\n"); + printf("failed: "); goto bail; } if (!opt_quiet) @@ -202,15 +235,57 @@ int main(int argc, char *argv[]) /* Append the DHCP info */ if (opt_dhcpinfo && !pxe_get_cached_info(PXENV_PACKET_TYPE_DHCP_ACK, &dhcpdata, &dhcplen)) { + errno = 0; if (initramfs_add_file(initramfs, dhcpdata, dhcplen, dhcplen, - "/dhcpinfo.dat", 0, 0755)) + "/dhcpinfo.dat", 0, 0755)) { + fprintf(stderr, "Unable to add DHCP info: "); goto bail; + } + } + + /* Handle dtb and eventually other setup data */ + setup_data = setup_data_init(); + if (!setup_data) + goto bail; + + for (argl = argv; (arg = *argl); argl++) { + if (!memcmp(arg, "dtb=", 4)) { + if (setup_data_file(setup_data, SETUP_DTB, arg+4, opt_quiet)) + goto bail; + } else if (!memcmp(arg, "blob.", 5)) { + uint32_t type; + char *ep; + + type = strtoul(arg + 5, &ep, 10); + if (ep[0] != '=' || !ep[1]) + continue; + + if (!type) + continue; + + if (setup_data_file(setup_data, type, ep+1, opt_quiet)) + goto bail; + } } /* This should not return... */ - syslinux_boot_linux(kernel_data, kernel_len, initramfs, cmdline); + errno = 0; + syslinux_boot_linux(kernel_data, kernel_len, initramfs, + setup_data, cmdline); + fprintf(stderr, "syslinux_boot_linux() failed: "); bail: - fprintf(stderr, "Kernel load failure (insufficient memory?)\n"); + switch(errno) { + case ENOENT: + fprintf(stderr, "File not found\n"); + break; + case ENOMEM: + fprintf(stderr, "Out of memory\n"); + break; + default: + fprintf(stderr, "Error %d\n", errno); + break; + } + fprintf(stderr, "%s: Boot aborted!\n", progname); return 1; } diff --git a/com32/modules/pcitest.c b/com32/modules/pcitest.c index 672023ad..9921ee6d 100644 --- a/com32/modules/pcitest.c +++ b/com32/modules/pcitest.c @@ -39,12 +39,7 @@ #include <com32.h> #include <sys/pci.h> #include <stdbool.h> - -#ifdef DEBUG -# define dprintf printf -#else -# define dprintf(...) ((void)0) -#endif +#include <dprintf.h> char display_line = 0; #define moreprintf(...) \ diff --git a/com32/modules/pmload.c b/com32/modules/pmload.c index 3064a94f..4c01db08 100644 --- a/com32/modules/pmload.c +++ b/com32/modules/pmload.c @@ -81,10 +81,8 @@ int boot_raw(void *ptr, size_t len, addr_t where, char **argv) if (!mmap || !amap) goto bail; -#if DEBUG dprintf("Initial memory map:\n"); - syslinux_dump_memmap(stdout, mmap); -#endif + syslinux_dump_memmap(mmap); dprintf("Segment at 0x%08x len 0x%08x\n", where, len); @@ -119,10 +117,8 @@ int boot_raw(void *ptr, size_t len, addr_t where, char **argv) if (!stack_frame) goto bail; -#if DEBUG dprintf("Right before syslinux_memmap_largest()...\n"); - syslinux_dump_memmap(stdout, amap); -#endif + syslinux_dump_memmap(amap); if (syslinux_memmap_largest(amap, SMT_FREE, &lstart, &llen)) goto bail; /* NO free memory?! */ @@ -173,16 +169,14 @@ int boot_raw(void *ptr, size_t len, addr_t where, char **argv) regs.eip = where; regs.esp = stack_pointer; -#if DEBUG dprintf("Final memory map:\n"); - syslinux_dump_memmap(stdout, mmap); + syslinux_dump_memmap(mmap); dprintf("Final available map:\n"); - syslinux_dump_memmap(stdout, amap); + syslinux_dump_memmap(amap); dprintf("Movelist:\n"); - syslinux_dump_movelist(stdout, ml); -#endif + syslinux_dump_movelist(ml); /* This should not return... */ fputs("Booting...\n", stdout); 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 new file mode 100644 index 00000000..26376900 --- /dev/null +++ b/com32/modules/pxechn.c @@ -0,0 +1,1161 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2010-2012 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. + * + * ----------------------------------------------------------------------- */ + +/* + * pxechn.c + * + * PXE Chain Loader; Chain load to another PXE network boot program + * that may be on another host. + */ + +#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> +#include <dhcp.h> +#include <limits.h> + + +#ifdef DEBUG +# define PXECHN_DEBUG 1 +#else +# define PXECHN_DEBUG 0 +#endif + +typedef union { + uint64_t q; + uint32_t l[2]; + uint16_t w[4]; + uint8_t b[8]; +} reg64_t; + +#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 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 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 dprintf0 +#define dprintf_pc_pa dprintf +#define dprintf_pc_so_s dprintf0 + +#define t_PXENV_RESTART_TFTP t_PXENV_TFTP_READ_FILE + +#define STACK_SPLIT 11 + +/* same as pxelinux.asm REBOOT_TIME */ +#define REBOOT_TIME 300 + +#define NUM_DHCP_OPTS 256 +#define DHCP_OPT_LEN_MAX 256 +#define PXE_VENDOR_RAW_PRN_MAX 0x7F +#define PXECHN_HOST_LEN 256 /* 63 bytes per label; 255 max total */ + +#define PXECHN_NUM_PKT_TYPE 3 +#define PXECHN_NUM_PKT_AVAIL 2*PXECHN_NUM_PKT_TYPE +#define PXECHN_PKT_TYPE_START PXENV_PACKET_TYPE_DHCP_DISCOVER + +#define PXECHN_FORCE_PKT1 0x80000000 +#define PXECHN_FORCE_PKT2 0x40000000 +#define PXECHN_FORCE_ALL (PXECHN_FORCE_PKT1 | PXECHN_FORCE_PKT2) +#define PXECHN_FORCE_ALL_1 0 +#define STRASINT_str ('s' + (('t' + ('r' << 8)) << 8)) + +#define min(a,b) (((a) < (b)) ? (a) : (b)) + +const char app_name_str[] = "pxechn.c32"; + +struct pxelinux_opt { + char *fn; /* Filename as passed to us */ + in_addr_t fip; /* fn's IP component */ + char *fp; /* fn's path component */ + in_addr_t gip; /* giaddr; Gateway/DHCP relay */ + 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]; + struct dhcp_option opts[PXECHN_NUM_PKT_TYPE][NUM_DHCP_OPTS]; + char p_unpacked[PXECHN_NUM_PKT_TYPE]; +}; + + +/* from chain.c */ +struct data_area { + void *data; + addr_t base; + addr_t size; +}; + +/* From chain.c */ +static inline void error(const char *msg) +{ + fputs(msg, stderr); +} + +/* From chain.c */ +static void do_boot(struct data_area *data, int ndata, + struct syslinux_rm_regs *regs) +{ + uint16_t *const bios_fbm = (uint16_t *) 0x413; + addr_t dosmem = *bios_fbm << 10; /* Technically a low bound */ + struct syslinux_memmap *mmap; + struct syslinux_movelist *mlist = NULL; + addr_t endimage; + int i; + + mmap = syslinux_memory_map(); + + if (!mmap) { + error("Cannot read system memory map\n"); + return; + } + + endimage = 0; + for (i = 0; i < ndata; i++) { + if (data[i].base + data[i].size > endimage) + endimage = data[i].base + data[i].size; + } + if (endimage > dosmem) + goto too_big; + + for (i = 0; i < ndata; i++) { + if (syslinux_add_movelist(&mlist, data[i].base, + (addr_t) data[i].data, data[i].size)) + goto enomem; + } + + + /* Tell the shuffler not to muck with this area... */ + syslinux_add_memmap(&mmap, endimage, 0xa0000 - endimage, SMT_RESERVED); + + /* Force text mode */ + syslinux_force_text_mode(); + + fputs("Booting...\n", stdout); + syslinux_shuffle_boot_rm(mlist, mmap, 3, regs); + error("Chainboot failed!\n"); + return; + +too_big: + error("Loader file too large\n"); + return; + +enomem: + error("Out of memory\n"); + return; +} + +void usage(void) +{ + printf("USAGE:\n" + " %s [OPTIONS]... _new-nbp_\n" + " %s -r _new-nbp_ (calls PXE stack PXENV_RESTART_TFTP)\n" + "OPTIONS:\n" + " [-c config] [-g gateway] [-p prefix] [-t reboot] [-u] [-w] [-W]" + " [-o opt.ty=val]\n\n", + app_name_str, app_name_str); +} + +void pxe_error(int ierr, const char *evt, const char *msg) +{ + if (msg) + printf("%s", msg); + else if (evt) + printf("Error while %s: ", evt); + printf("%d:%s\n", ierr, strerror(ierr)); +} + +int pressanykey(clock_t tm) { + int inc; + + printf("Press any key to continue. "); + inc = get_key(stdin, tm); + puts(""); + return inc; +} + +int dhcp_find_opt(pxe_bootp_t *p, size_t len, uint8_t opt) +{ + int rv = -1; + int i, vlen, oplen; + uint8_t *d; + uint32_t magic; + + if (!p) { + dprintf(" packet pointer is null\n"); + return rv; + } + vlen = len - ((void *)&(p->vendor) - (void *)p); + d = p->vendor.d; + magic = ntohl(*((uint32_t *)d)); + if (magic != VM_RFC1048) /* Invalid DHCP packet */ + vlen = 0; + for (i = 4; i < vlen; i++) { + if (d[i] == opt) { + dprintf("\n @%03X-%2d\n", i, d[i]); + rv = i; + break; + } + if (d[i] == ((NUM_DHCP_OPTS) - 1)) /* End of list */ + break; + if (d[i]) { /* Skip padding */ + oplen = d[++i]; + i += oplen; + } + } + return rv; +} + +void print_pxe_vendor_raw(pxe_bootp_t *p, size_t len) +{ + int i, vlen; + + if (!p) { + printf(" packet pointer is null\n"); + return; + } + vlen = len - ((void *)&(p->vendor) - (void *)p); + if (vlen > PXE_VENDOR_RAW_PRN_MAX) + vlen = PXE_VENDOR_RAW_PRN_MAX; + dprintf(" rawLen = %d", vlen); + for (i = 0; i < vlen; i++) { + if ((i & 0xf) == 0) + printf("\n %04X:", i); + printf(" %02X", p->vendor.d[i]); + } + printf("\n"); +} + +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; + 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] == ((NUM_DHCP_OPTS) - 1)) /* 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 || len <= 0) { + 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); + dprint_pxe_vendor_blk(p, len); +} + +void pxe_set_regs(struct syslinux_rm_regs *regs) +{ + com32sys_t tregs; + + regs->ip = 0x7C00; + /* Plan A uses SS:[SP + 4] */ + /* sdi->pxe.stack is a usable pointer, not something that can be nicely + and reliably split to SS:SP without causing issues */ + tregs.eax.l = 0x000A; + __intcall(0x22, &tregs, &tregs); + regs->ss = tregs.fs; + regs->esp.l = tregs.esi.w[0] + sizeof(tregs); + /* Plan B uses [ES:BX] */ + regs->es = tregs.es; + regs->ebx = tregs.ebx; + dprintf("\nsp:%04x ss:%04x es:%04x bx:%04x\n", regs->esp.w[0], + regs->ss, regs->es, regs->ebx.w[0]); + /* Zero out everything else just to be sure */ + regs->cs = regs->ds = regs->fs = regs->gs = 0; + regs->eax.l = regs->ecx.l = regs->edx.l = 0; +} + +int hostlen_limit(int len) +{ + return min(len, ((PXECHN_HOST_LEN) - 1)); +} + +//FIXME: To a library +/* Parse a filename into an IPv4 address and filename pointer + * returns Based on the interpretation of fn + * 0 regular file name + * 1 in format IP::FN + * 2 TFTP URL + * 3 HTTP URL + * 4 FTP URL + * 3 + 2^30 HTTPS URL + * -1 if fn is another URL type + */ +int pxechn_parse_fn(char fn[], in_addr_t *fip, char *host, char *fp[]) +{ + in_addr_t tip = 0; + char *csep, *ssep, *hsep; /* Colon, Slash separator positions */ + int hlen, plen; /* Hostname, protocol length */ + int rv = 0; + + csep = strchr(fn, ':'); + if (csep) { + if (csep[1] == ':') { /* assume IP::FN */ + *fp = &csep[2]; + rv = 1; + if (fn[0] != ':') { + hlen = hostlen_limit(csep - fn); + memcpy(host, fn, hlen); + host[hlen] = 0; + } + } else if ((csep[1] == '/') && (csep[2] == '/')) { + /* URL: proto://host:port/path/file */ + /* proto://[user[:passwd]@]host[:port]/path/file */ + ssep = strchr(csep + 3, '/'); + if (ssep) { + hlen = hostlen_limit(ssep - (csep + 3)); + *fp = ssep + 1; + } else { + hlen = hostlen_limit(strlen(csep + 3)); + } + memcpy(host, (csep + 3), hlen); + host[hlen] = 0; + plen = csep - fn; + if (strncmp(fn, "tftp", plen) == 0) + rv = 2; + else if (strncmp(fn, "http", plen) == 0) + rv = 3; + else if (strncmp(fn, "ftp", plen) == 0) + rv = 4; + else if (strncmp(fn, "https", plen) == 0) + rv = 3 + ( 1 << 30 ); + else + rv = -1; + } else { + csep = NULL; + } + } + if (!csep) { + *fp = fn; + } + if (host[0]) { + hsep = strchr(host, '@'); + if (!hsep) + hsep = host; + tip = pxe_dns(hsep); + } + if (tip != 0) + *fip = tip; + dprintf0(" host '%s'\n fp '%s'\n fip %08x\n", host, *fp, ntohl(*fip)); + return rv; +} + +void pxechn_opt_free(struct dhcp_option *opt) +{ + free(opt->data); + opt->len = -1; +} + +void pxechn_fill_pkt(struct pxelinux_opt *pxe, int ptype) +{ + int rv = -1; + int p1, p2; + if ((ptype < 0) || (ptype > PXECHN_NUM_PKT_TYPE)) + rv = -2; + p1 = ptype - PXECHN_PKT_TYPE_START; + p2 = p1 + PXECHN_NUM_PKT_TYPE; + if ((rv >= -1) && (!pxe_get_cached_info(ptype, + (void **)&(pxe->p[p1].data), (size_t *)&(pxe->p[p1].len)))) { + pxe->p[p2].data = malloc(2048); + if (pxe->p[p2].data) { + memcpy(pxe->p[p2].data, pxe->p[p1].data, pxe->p[p1].len); + pxe->p[p2].len = pxe->p[p1].len; + rv = 0; + dprint_pxe_bootp_t((pxe_bootp_t *)(pxe->p[p1].data), pxe->p[p1].len); + dpressanykey(INT_MAX); + } else { + printf("%s: ERROR: Unable to malloc() for second packet\n", app_name_str); + } + } else { + printf("%s: ERROR: Unable to retrieve first packet\n", app_name_str); + } + if (rv <= -1) { + pxechn_opt_free(&pxe->p[p1]); + } +} + +void pxechn_init(struct pxelinux_opt *pxe) +{ + /* Init for paranoia */ + pxe->fn = NULL; + pxe->fp = NULL; + pxe->force = 0; + 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++){ + for (int i = 0; i < NUM_DHCP_OPTS; i++) { + pxe->opts[j][i].data = NULL; + pxe->opts[j][i].len = -1; + } + pxe->p_unpacked[j] = 0; + pxe->p[j].data = NULL; + pxe->p[j+PXECHN_NUM_PKT_TYPE].data = NULL; + pxe->p[j].len = 0; + pxe->p[j+PXECHN_NUM_PKT_TYPE].len = 0; + } + pxechn_fill_pkt(pxe, PXENV_PACKET_TYPE_CACHED_REPLY); +} + +int pxechn_to_hex(char i) +{ + if (i >= '0' && i <= '9') + return (i - '0'); + if (i >= 'A' && i <= 'F') + return (i - 'A' + 10); + if (i >= 'a' && i <= 'f') + return (i - 'a' + 10); + if (i == 0) + return -1; + return -2; +} + +int pxechn_parse_2bhex(char ins[]) +{ + int ret = -2; + int n0 = -3, n1 = -3; + /* NULL pointer */ + if (!ins) { + ret = -1; + /* pxechn_to_hex can handle the NULL character by returning -1 and + breaking the execution of the statement chain */ + } else if (((n0 = pxechn_to_hex(ins[0])) >= 0) + && ((n1 = pxechn_to_hex(ins[1])) >= 0)) { + ret = (n0 * 16) + n1; + } else if (n0 == -1) { /* Leading NULL char */ + ret = -1; + } + return ret; +} + +int pxechn_optnum_ok(int optnum) +{ + if ((optnum > 0) && (optnum < ((NUM_DHCP_OPTS) - 1))) + return 1; + return 0; +} + +int pxechn_optnum_ok_notres(int optnum) +{ + if ((optnum <= 0) && (optnum >= ((NUM_DHCP_OPTS) - 1))) + return 0; + switch(optnum){ + case 66: case 67: + return 0; + break; + default: return 1; + } +} + +int pxechn_optlen_ok(int optlen) +{ + if ((optlen >= 0) && (optlen < ((DHCP_OPT_LEN_MAX) - 1))) + return 1; + return 0; +} + +int pxechn_setopt(struct dhcp_option *opt, void *data, int len) +{ + void *p; + if (!opt || !data) + return -1; + if (len < 0) { + return -3; + } + p = realloc(opt->data, len); + if (!p && len) { /* Allow for len=0 */ + pxechn_opt_free(opt); + return -2; + } + opt->data = p; + memcpy(opt->data, data, len); + opt->len = len; + return len; +} + +int pxechn_setopt_str(struct dhcp_option *opt, void *data) +{ + return pxechn_setopt(opt, data, strnlen(data, DHCP_OPT_LEN_MAX)); +} + +int pxechn_parse_int(char *data, char istr[], int tlen) +{ + int terr = errno; + + if ((tlen == 1) || (tlen == 2) || (tlen == 4)) { + errno = 0; + uint32_t optval = strtoul(istr, NULL, 0); + if (errno) + return -3; + errno = terr; + switch(tlen){ + case 1: + if (optval & 0xFFFFFF00) + return -4; + break; + case 2: + if (optval & 0xFFFF0000) + return -4; + optval = htons(optval); + break; + case 4: + optval = htonl(optval); + break; + } + memcpy(data, &optval, tlen); + } else if (tlen == 8) { + errno = 0; + uint64_t optval = strtoull(istr, NULL, 0); + if (errno) + return -3; + errno = terr; + optval = htonq(optval); + memcpy(data, &optval, tlen); + } else { + return -2; + } + return tlen; +} + +int pxechn_parse_hex_sep(char *data, char istr[], char sep) +{ + int len = 0; + int ipos = 0, ichar; + + if (!data || !istr) + return -1; + while ((istr[ipos]) && (len < DHCP_OPT_LEN_MAX)) { + dprintf(" %02X%02X", *((int *)(istr + ipos)) & 0xFF, *((int *)(istr + ipos +1)) & 0xFF); + ichar = pxechn_parse_2bhex(istr + ipos); + if (ichar >=0) { + data[len++] = ichar; + } else { + return -EINVAL; + } + if (!istr[ipos+2]){ + ipos += 2; + } else if (istr[ipos+2] != sep) { + return -(EINVAL + 1); + } else { + ipos += 3; + } + } + return len; +} + +int pxechn_parse_opttype(char istr[], int optnum) +{ + char *pos; + int tlen, type, tmask; + + if (!istr) + return -1; + pos = strchr(istr, '='); + if (!pos) + return -2; + if (istr[0] != '.') { + if (!pxechn_optnum_ok(optnum)) + return -3; + return -3; /* do lookup here */ + } else { + tlen = pos - istr - 1; + if ((tlen < 1) || (tlen > 4)) + return -4; + tmask = 0xFFFFFFFF >> (8 * (4 - tlen)); + type = (*(int*)(istr + 1)) & tmask; + } + return type; +} + +int pxechn_parse_setopt(struct dhcp_option opts[], struct dhcp_option *iopt, + char istr[]) +{ + int rv = 0, optnum, opttype; + char *cpos = NULL, *pos; + + if (!opts || !iopt || !(iopt->data)) + return -1; + if (!istr || !istr[0]) + return -2; + // -EINVAL; + optnum = strtoul(istr, &cpos, 0); + if (!pxechn_optnum_ok(optnum)) + return -3; + pos = strchr(cpos, '='); + if (!pos) + return -4; + opttype = pxechn_parse_opttype(cpos, optnum); + pos++; + switch(opttype) { + case 'b': + iopt->len = pxechn_parse_int(iopt->data, pos, 1); + break; + case 'l': + iopt->len = pxechn_parse_int(iopt->data, pos, 4); + break; + case 'q': + iopt->len = pxechn_parse_int(iopt->data, pos, 8); + break; + case 's': + case STRASINT_str: + iopt->len = strlen(pos); + if (iopt->len > DHCP_OPT_LEN_MAX) + iopt->len = DHCP_OPT_LEN_MAX; + memcpy(iopt->data, pos, iopt->len); + dprintf_pc_so_s("s.len=%d\trv=%d\n", iopt->len, rv); + break; + case 'w': + iopt->len = pxechn_parse_int(iopt->data, pos, 2); + break; + case 'x': + iopt->len = pxechn_parse_hex_sep(iopt->data, pos, ':'); + break; + default: + return -6; + break; + } + if (pxechn_optlen_ok(iopt->len)) { + rv = pxechn_setopt(&(opts[optnum]), (void *)(iopt->data), iopt->len); + } + if((opttype == 's') || (opttype == STRASINT_str)) + dprintf_pc_so_s("rv=%d\n", rv); + return rv; +} + +int pxechn_parse_force(const char istr[]) +{ + uint32_t rv = 0; + char *pos; + int terr = errno; + + errno = 0; + rv = strtoul(istr, &pos, 0); + if ((istr == pos ) || ((rv == ULONG_MAX) && (errno))) + rv = 0; + errno = terr; + return rv; +} + +int pxechn_uuid_set(struct pxelinux_opt *pxe) +{ + int ret = 0; + + if (!pxe->p_unpacked[0]) + ret = dhcp_unpack_packet((pxe_bootp_t *)(pxe->p[0].data), + pxe->p[0].len, pxe->opts[0]); + if (ret) { + error("Could not unpack packet\n"); + return -ret; /* dhcp_unpack_packet always returns positive errors */ + } + + if (pxe->opts[0][97].len >= 0 ) + pxechn_setopt(&(pxe->opts[2][97]), pxe->opts[0][97].data, pxe->opts[0][97].len); + return 1; + return 0; +} + +int pxechn_parse_args(int argc, char *argv[], struct pxelinux_opt *pxe, + struct dhcp_option opts[]) +{ + int arg, optnum, rv = 0; + char *p = NULL; + const char optstr[] = "c:f:g:o:p:St:uwW"; + struct dhcp_option iopt; + + if (pxe->p[5].data) + pxe->fip = ( (pxe_bootp_t *)(pxe->p[5].data) )->sip; + else + pxe->fip = 0; + /* Fill */ + pxe->fn = argv[0]; + pxechn_parse_fn(pxe->fn, &(pxe->fip), pxe->host, &(pxe->fp)); + pxechn_setopt_str(&(opts[67]), pxe->fp); + pxechn_setopt_str(&(opts[66]), pxe->host); + iopt.data = malloc(DHCP_OPT_LEN_MAX); + iopt.len = 0; + while ((rv >= 0) && (arg = getopt(argc, argv, optstr)) >= 0) { + dprintf_pc_pa(" Got arg '%c'/'%c' addr %08X val %s\n", arg == '?' ? optopt : arg, arg, (unsigned int)optarg, optarg ? optarg : ""); + switch(arg) { + case 'c': /* config */ + pxechn_setopt_str(&(opts[209]), optarg); + break; + case 'f': /* force */ + pxe->force = pxechn_parse_force(optarg); + break; + case 'g': /* gateway/DHCP relay */ + pxe->gip = pxe_dns(optarg); + break; + case 'n': /* native */ + break; + case 'o': /* option */ + rv = pxechn_parse_setopt(opts, &iopt, optarg); + break; + 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) { + optnum = htonl(optnum); + pxechn_setopt(&(opts[211]), (void *)(&optnum), 4); + } else { + rv = -3; + } + break; + case 'u': /* UUID: copy option 97 from packet 1 if present */ + pxechn_uuid_set(pxe); + break; + case 'w': /* wait */ + pxe->wait = 1; + break; + case 'W': /* WDS */ + pxe->wds = 1; + break; + case '?': + rv = -'?'; + default: + break; + } + if (rv >= 0) /* Clear it since getopt() doesn't guarentee it */ + optarg = NULL; + } + if (iopt.data) + pxechn_opt_free(&iopt); +/* FIXME: consider reordering the application of parsed command line options + such that the new nbp may be at the end */ + if (rv >= 0) { + rv = 0; + } else if (arg != '?') { + printf("Invalid argument for -%c: %s\n", arg, optarg); + } + dprintf("pxechn_parse_args rv=%d\n", rv); + return rv; +} + +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 */ + bootp0 = (pxe_bootp_t *)(pxe->p[2].data); + bootp1 = (pxe_bootp_t *)(pxe->p[5].data); + + ret = dhcp_unpack_packet(bootp0, pxe->p[2].len, opts); + if (ret) { + error("Could not unpack packet\n"); + return -ret; + } + pxe->p_unpacked[2] = 1; + pxe->gip = bootp1->gip; + + ret = pxechn_parse_args(argc, argv, pxe, opts); + if (ret) + return ret; + 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); + if (ret) { + error("Could not pack packet\n"); + return -ret; /* dhcp_pack_packet always returns positive errors */ + } + return ret; +} + +/* dhcp_pkt2pxe: Copy packet to PXE's BC data for a ptype packet + * Input: + * p Packet data to copy + * len length of data to copy + * ptype Packet type to overwrite + */ +int dhcp_pkt2pxe(pxe_bootp_t *p, size_t len, int ptype) +{ + com32sys_t reg; + t_PXENV_GET_CACHED_INFO *ci; + void *cp; + int rv = -1; + + if (!(ci = lzalloc(sizeof(t_PXENV_GET_CACHED_INFO)))){ + dprintf("Unable to lzalloc() for PXE call structure\n"); + rv = 1; + goto ret; + } + ci->Status = PXENV_STATUS_FAILURE; + ci->PacketType = ptype; + memset(®, 0, sizeof(reg)); + reg.eax.w[0] = 0x0009; + reg.ebx.w[0] = PXENV_GET_CACHED_INFO; + reg.edi.w[0] = OFFS(ci); + reg.es = SEG(ci); + __intcall(0x22, ®, ®); + + if (ci->Status != PXENV_STATUS_SUCCESS) { + dprintf("PXE Get Cached Info failed: %d\n", ci->Status); + rv = 2; + goto ret; + } + + cp = MK_PTR(ci->Buffer.seg, ci->Buffer.offs); + if (!(memcpy(cp, p, len))) { + dprintf("Failed to copy packet\n"); + rv = 3; + goto ret; + } +ret: + lfree(ci); + return rv; +} + +int pxechn_mergeopt(struct pxelinux_opt *pxe, int d, int s) +{ + int ret = 0, i; + + if ((d >= PXECHN_NUM_PKT_TYPE) || (s >= PXECHN_NUM_PKT_TYPE) + || (d < 0) || (s < 0)) { + return -2; + } + if (!pxe->p_unpacked[s]) + ret = dhcp_unpack_packet(pxe->p[s].data, pxe->p[s].len, pxe->opts[s]); + if (ret) { + error("Could not unpack packet for merge\n"); + printf("Error %d (%d)\n", ret, EINVAL); + if (ret == EINVAL) { + if (pxe->p[s].len < 240) + printf("Packet %d is too short: %d (240)\n", s, pxe->p[s].len); + else if (((const struct dhcp_packet *)(pxe->p[s].data))->magic != htonl(DHCP_VENDOR_MAGIC)) + printf("Packet %d has no magic\n", s); + else + error("Unknown EINVAL error\n"); + } else { + error("Unknown error\n"); + } + return -ret; + } + for (i = 0; i < NUM_DHCP_OPTS; i++) { + if (pxe->opts[d][i].len <= -1) { + if (pxe->opts[s][i].len >= 0) + pxechn_setopt(&(pxe->opts[d][i]), pxe->opts[s][i].data, pxe->opts[s][i].len); + } + } + return 0; +} + +/* pxechn: Chainload to new PXE file ourselves + * Input: + * argc Count of arguments passed + * argv Values of arguments passed + * Returns 0 on success (which should never happen) + * 1 on loadfile() error + * 2 if DHCP Option 52 (Option Overload) used file field + * -1 on usage error + */ +int pxechn(int argc, char *argv[]) +{ + struct pxelinux_opt pxe; + pxe_bootp_t* p[(2 * PXECHN_NUM_PKT_TYPE)]; + int rv = 0; + int i; + struct data_area file; + struct syslinux_rm_regs regs; + + pxechn_init(&pxe); + for (i = 0; i < (2 * PXECHN_NUM_PKT_TYPE); i++) { + p[i] = (pxe_bootp_t *)(pxe.p[i].data); + } + + /* Parse arguments and patch packet 1 */ + rv = pxechn_args(argc, argv, &pxe); + dpressanykey(INT_MAX); + if (rv) + goto ret; + pxe_set_regs(®s); + /* Load the file late; it's the most time-expensive operation */ + printf("%s: Attempting to load '%s': ", app_name_str, pxe.fn); + if (loadfile(pxe.fn, &file.data, &file.size)) { + pxe_error(errno, NULL, NULL); + rv = -2; + goto ret; + } + puts("loaded."); + /* we'll be shuffling to the standard location of 7C00h */ + file.base = 0x7C00; + if ((pxe.wds) || + ((pxe.force) && ((pxe.force & (~PXECHN_FORCE_ALL)) == 0))) { + printf("Forcing behavior %08X\n", pxe.force); + // P2 is the same as P3 if no PXE server present. + if ((pxe.wds) || + (pxe.force & PXECHN_FORCE_PKT2)) { + pxechn_fill_pkt(&pxe, PXENV_PACKET_TYPE_DHCP_ACK); + rv = pxechn_mergeopt(&pxe, 2, 1); + if (rv) { + dprintf("Merge Option returned %d\n", rv); + } + rv = dhcp_pack_packet(p[5], (size_t *)&(pxe.p[5].len), pxe.opts[2]); + rv = dhcp_pkt2pxe(p[5], pxe.p[5].len, PXENV_PACKET_TYPE_DHCP_ACK); + } + if (pxe.force & PXECHN_FORCE_PKT1) { + puts("Unimplemented force option utilized"); + } + } + rv = dhcp_pkt2pxe(p[5], pxe.p[5].len, PXENV_PACKET_TYPE_CACHED_REPLY); + dprint_pxe_bootp_t(p[5], pxe.p[5].len); + if ((pxe.wds) || + ((pxe.force) && ((pxe.force & (~PXECHN_FORCE_ALL)) == 0))) { + // printf("Forcing behavior %08X\n", pxe.force); + // P2 is the same as P3 if no PXE server present. + if ((pxe.wds) || + (pxe.force & PXECHN_FORCE_PKT2)) { + rv = dhcp_pkt2pxe(p[5], pxe.p[5].len, PXENV_PACKET_TYPE_DHCP_ACK); + } + } else if (pxe.force) { + printf("FORCE: bad argument %08X\n", pxe.force); + } + printf("\n...Ready to boot:\n"); + if (pxe.wait) { + pressanykey(INT_MAX); + } else { + dpressanykey(INT_MAX); + } + if (true) { + puts(" Attempting to boot..."); + do_boot(&file, 1, ®s); + } + /* If failed, copy backup back in and abort */ + dhcp_pkt2pxe(p[2], pxe.p[2].len, PXENV_PACKET_TYPE_CACHED_REPLY); + if (pxe.force && ((pxe.force & (~PXECHN_FORCE_ALL)) == 0)) { + if (pxe.force & PXECHN_FORCE_PKT2) { + rv = dhcp_pkt2pxe(p[1], pxe.p[1].len, PXENV_PACKET_TYPE_DHCP_ACK); + } + } +ret: + return rv; +} + +/* pxe_restart: Restart the PXE environment with a new PXE file + * Input: + * ifn Name of file to chainload to in a format PXELINUX understands + * This must strictly be TFTP or relative file + */ +int pxe_restart(char *ifn) +{ + int rv = 0; + struct pxelinux_opt pxe; + com32sys_t reg; + t_PXENV_RESTART_TFTP *pxep; /* PXENV callback Parameter */ + + pxe.fn = ifn; + pxechn_fill_pkt(&pxe, PXENV_PACKET_TYPE_CACHED_REPLY); + if (pxe.p[5].data) + pxe.fip = ( (pxe_bootp_t *)(pxe.p[5].data) )->sip; + else + pxe.fip = 0; + rv = pxechn_parse_fn(pxe.fn, &(pxe.fip), pxe.host, &(pxe.fp)); + if ((rv > 2) || (rv < 0)) { + printf("%s: ERROR: Unparsable filename argument: '%s'\n\n", app_name_str, pxe.fn); + goto ret; + } + printf(" Attempting to boot '%s'...\n\n", pxe.fn); + memset(®, 0, sizeof reg); + if (sizeof(t_PXENV_TFTP_READ_FILE) <= __com32.cs_bounce_size) { + pxep = __com32.cs_bounce; + memset(pxep, 0, sizeof(t_PXENV_RESTART_TFTP)); + } else if (!(pxep = lzalloc(sizeof(t_PXENV_RESTART_TFTP)))){ + dprintf("Unable to lzalloc() for PXE call structure\n"); + goto ret; + } + pxep->Status = PXENV_STATUS_SUCCESS; /* PXENV_STATUS_FAILURE */ + strcpy((char *)pxep->FileName, ifn); + pxep->BufferSize = 0x8000; + pxep->Buffer = (void *)0x7c00; + pxep->ServerIPAddress = pxe.fip; + dprintf("FN='%s' %08X %08X %08X %08X\n\n", (char *)pxep->FileName, + pxep->ServerIPAddress, (unsigned int)pxep, + pxep->BufferSize, (unsigned int)pxep->Buffer); + dprintf("PXENV_RESTART_TFTP status %d\n", pxep->Status); + reg.eax.w[0] = 0x0009; + reg.ebx.w[0] = PXENV_RESTART_TFTP; + reg.edi.w[0] = OFFS(pxep); + reg.es = SEG(pxep); + + __intcall(0x22, ®, ®); + + printf("PXENV_RESTART_TFTP returned %d\n", pxep->Status); + if (pxep != __com32.cs_bounce) + lfree(pxep); + +ret: + return rv; +} + +/* pxechn_gpxe: Use gPXE to chainload a new NBP + * Input: + * argc Count of arguments passed + * argv Values of arguments passed + * Returns 0 on success (which should never happen) + * 1 on loadfile() error + * -1 on usage error + */ +//FIXME:Implement +int pxechn_gpxe(int argc, char *argv[]) +{ + int rv = 0; + struct pxelinux_opt pxe; + + if (argc) { + printf("%s\n", argv[0]); + pxechn_args(argc, argv, &pxe); + } + return rv; +} + +int main(int argc, char *argv[]) +{ + int rv= -1; + int err; + const struct syslinux_version *sv; + + /* Initialization */ + err = errno; + console_ansi_raw(); /* sets errno = 9 (EBADF) */ + /* printf("%d %d\n", err, errno); */ + errno = err; + sv = syslinux_version(); + if (sv->filesystem != SYSLINUX_FS_PXELINUX) { + printf("%s: May only run in PXELINUX\n", app_name_str); + argc = 1; /* prevents further processing to boot */ + } + if (argc == 2) { + if ((strcasecmp(argv[1], "-h") == 0) || ((strcmp(argv[1], "-?") == 0)) + || (strcasecmp(argv[1], "--help") == 0)) { + argc = 1; + } else { + rv = pxechn(argc - 1, &argv[1]); + } + } else if (argc >= 3) { + if ((strcmp(argv[1], "-r") == 0)) { + if (argc == 3) + rv = pxe_restart(argv[2]); + } else { + rv = pxechn(argc - 1, &argv[1]); + } + } + if (rv <= -1 ) { + usage(); + rv = 1; + } + return rv; +} diff --git a/com32/modules/zzjson.c b/com32/modules/zzjson.c new file mode 100644 index 00000000..e2516fa1 --- /dev/null +++ b/com32/modules/zzjson.c @@ -0,0 +1,101 @@ +/* + * Display directory contents + */ +#include <stdlib.h> +#include <stdio.h> +#include <console.h> +#include <string.h> +#include <com32.h> +#include <zzjson/zzjson.h> +#include <stdarg.h> + +static void myerror(void *ehandle, const char *format, ...) { + va_list ap; + fprintf(ehandle, "error: "); + va_start(ap, format); + vfprintf(ehandle, format, ap); + va_end(ap); + fputc('\n', ehandle); +} + + +int main(int argc, char *argv[]) +{ + openconsole(&dev_rawcon_r, &dev_stdcon_w); + (void) argc; + (void) argv; + ZZJSON *tmp; + ZZJSON_CONFIG config = { ZZJSON_VERY_STRICT, NULL, + (int(*)(void*)) fgetc, + NULL, + malloc, calloc, free, realloc, + stderr, myerror, stdout, + (int(*)(void*,const char*,...)) fprintf, + (int(*)(int,void*)) fputc }; + + do { + ZZJSON *tmp2; + + tmp = zzjson_create_array(&config, + zzjson_create_number_d(&config, 3.14), + zzjson_create_number_i(&config, 1234LL), + zzjson_create_number_i(&config, -4321LL), + zzjson_create_true(&config), + zzjson_create_false(&config), + zzjson_create_null(&config), + zzjson_create_string(&config, "hello, world"), + zzjson_create_object(&config, + "picard", zzjson_create_string(&config, "jean-luc"), + "riker", zzjson_create_string(&config, "william t."), + NULL), + zzjson_create_object(&config, NULL), + zzjson_create_array(&config, NULL), + NULL ); + + if (!tmp) { + fprintf(stderr, "error during creation of json tree\n"); + break; + } + + tmp2 = zzjson_array_prepend(&config, tmp, + zzjson_create_string(&config, "prepended string")); + + if (!tmp2) { + fprintf(stderr, "error during prepend\n"); + break; + } + tmp = tmp2; + + tmp2 = zzjson_array_append(&config, tmp, + zzjson_create_string(&config, "appended string (slow)")); + + if (!tmp2) { + fprintf(stderr, "error during append\n"); + break; + } + tmp = tmp2; + + zzjson_print(&config, tmp); + } while(0); + if (tmp) zzjson_free(&config, tmp); + + { + tmp = zzjson_create_array(&config, NULL); /* empty array */ + tmp = zzjson_array_prepend(&config, tmp, zzjson_create_true(&config)); + zzjson_print(&config, tmp); + zzjson_free(&config, tmp); + } + + { + tmp = zzjson_create_object(&config, NULL); /* empty object */ + tmp = zzjson_object_prepend(&config, tmp, "hello", + zzjson_create_string(&config, "world")); + tmp = zzjson_object_append(&config, tmp, "goodbye", + zzjson_create_string(&config, "cruel world")); + zzjson_print(&config, tmp); + zzjson_free(&config, tmp); + } + + return 0; +} + diff --git a/com32/rosh/MCONFIG b/com32/rosh/MCONFIG deleted file mode 100644 index 25c41396..00000000 --- a/com32/rosh/MCONFIG +++ /dev/null @@ -1,27 +0,0 @@ -## -*- makefile -*- ------------------------------------------------------- -## -## Copyright 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., 51 Franklin St, Fifth Floor, -## Boston MA 02110-1301, USA; either version 2 of the License, or -## (at your option) any later version; incorporated herein by reference. -## -## ----------------------------------------------------------------------- - -## -## COM32 GRC configurables -## - -## Include the COM32 common configurables -include ../MCONFIG - -# CFLAGS = $(GCCOPT) $(GCCWARN) -march=i386 \ -# -fomit-frame-pointer -D__COM32__ \ -# -nostdinc -iwithprefix include \ -# -I$(com32)/libutil/include -I$(com32)/include -# -g3 -dD - -# LNXCFLAGS = -I$(com32)/libutil/include $(GCCWARN) -O -g3 -D_GNU_SOURCE -dD -# -U__GNUC__ diff --git a/com32/rosh/Makefile b/com32/rosh/Makefile index f4b7d866..766f68d5 100644 --- a/com32/rosh/Makefile +++ b/com32/rosh/Makefile @@ -17,7 +17,8 @@ ## topdir = ../.. -include MCONFIG +MAKEDIR = $(topdir)/mk +include $(MAKEDIR)/rosh.mk # from com32/sysdump/Makefile # The DATE is set on the make command line when building binaries for diff --git a/com32/samples/Makefile b/com32/samples/Makefile index bee2b992..76986d59 100644 --- a/com32/samples/Makefile +++ b/com32/samples/Makefile @@ -15,7 +15,8 @@ ## topdir = ../.. -include ../MCONFIG +MAKEDIR = $(topdir)/mk +include $(MAKEDIR)/com32.mk all: hello.c32 resolv.c32 serialinfo.c32 \ localboot.c32 \ diff --git a/com32/sysdump/Makefile b/com32/sysdump/Makefile index bffee3a2..98e7f15a 100644 --- a/com32/sysdump/Makefile +++ b/com32/sysdump/Makefile @@ -16,12 +16,15 @@ ## topdir = ../.. -include ../MCONFIG +MAKEDIR = $(topdir)/mk +include $(MAKEDIR)/com32.mk -include $(topdir)/version.mk -LIBS = ../libutil/libutil_com.a ../lib/libcom32.a $(LIBGCC) +LIBS = ../libupload/libcom32upload.a LNXLIBS = ../libutil/libutil_lnx.a +CFLAGS += -I$(com32) -I$(topdir) + MODULES = sysdump.c32 TESTFILES = diff --git a/com32/sysdump/acpi.c b/com32/sysdump/acpi.c index 8671fc8a..50222335 100644 --- a/com32/sysdump/acpi.c +++ b/com32/sysdump/acpi.c @@ -18,7 +18,6 @@ #include <string.h> #include <stdlib.h> #include "sysdump.h" -#include "backend.h" #include "rbtree.h" struct acpi_rsdp { @@ -151,7 +150,7 @@ static const struct acpi_rsdp *find_rsdp(void) return scan_for_rsdp(0xe0000, 0x100000); } -static void dump_table(struct backend *be, +static void dump_table(struct upload_backend *be, const char name[], const void *ptr, uint32_t len) { char namebuf[64]; @@ -171,7 +170,7 @@ static void dump_table(struct backend *be, write_data(be, ptr, len); } -static void dump_rsdt(struct backend *be, const struct acpi_rsdp *rsdp) +static void dump_rsdt(struct upload_backend *be, const struct acpi_rsdp *rsdp) { const struct acpi_rsdt *rsdt; uint32_t i, n; @@ -196,7 +195,7 @@ static void dump_rsdt(struct backend *be, const struct acpi_rsdp *rsdp) } } -static void dump_xsdt(struct backend *be, const struct acpi_rsdp *rsdp) +static void dump_xsdt(struct upload_backend *be, const struct acpi_rsdp *rsdp) { const struct acpi_xsdt *xsdt; uint32_t rsdp_len = rsdp->rev > 0 ? rsdp->len : 20; @@ -231,7 +230,7 @@ static void dump_xsdt(struct backend *be, const struct acpi_rsdp *rsdp) } } -void dump_acpi(struct backend *be) +void dump_acpi(struct upload_backend *be) { const struct acpi_rsdp *rsdp; uint32_t rsdp_len; diff --git a/com32/sysdump/backend.h b/com32/sysdump/backend.h deleted file mode 100644 index f2b3bc25..00000000 --- a/com32/sysdump/backend.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef BACKEND_H -#define BACKEND_H - -#include <stddef.h> -#include <inttypes.h> -#include <stdbool.h> -#include <zlib.h> -#include "serial.h" - -/* Backend flags */ -#define BE_NEEDLEN 0x01 - -struct backend { - const char *name; - const char *helpmsg; - int minargs; - - size_t dbytes; - size_t zbytes; - const char **argv; - - uint32_t now; - - int (*write)(struct backend *); - - z_stream zstream; - char *outbuf; - size_t alloc; -}; - -/* zout.c */ -int init_data(struct backend *be, const char *argv[]); -int write_data(struct backend *be, const void *buf, size_t len); -int flush_data(struct backend *be); - -/* cpio.c */ -#define cpio_init init_data -int cpio_hdr(struct backend *be, uint32_t mode, size_t datalen, - const char *filename); -int cpio_mkdir(struct backend *be, const char *filename); -int cpio_writefile(struct backend *be, const char *filename, - const void *data, size_t len); -int cpio_close(struct backend *be); -#define MODE_FILE 0100644 -#define MODE_DIR 0040755 - -/* backends.c */ -struct backend *get_backend(const char *name); - -/* backends */ -extern struct backend be_tftp; -extern struct backend be_ymodem; -extern struct backend be_srec; - -#endif /* BACKEND_H */ diff --git a/com32/sysdump/cpuid.c b/com32/sysdump/cpuid.c index 372a70db..e7fc5767 100644 --- a/com32/sysdump/cpuid.c +++ b/com32/sysdump/cpuid.c @@ -8,7 +8,6 @@ #include <com32.h> #include <sys/cpu.h> #include "sysdump.h" -#include "backend.h" struct cpuid_data { uint32_t eax, ebx, ecx, edx; @@ -29,7 +28,7 @@ static void get_cpuid(uint32_t eax, uint32_t ecx, struct cpuid_data *data) #define CPUID_CHUNK 128 -void dump_cpuid(struct backend *be) +void dump_cpuid(struct upload_backend *be) { struct cpuid_info *buf = NULL; int nentry, nalloc; diff --git a/com32/sysdump/data.h b/com32/sysdump/data.h deleted file mode 100644 index deacf721..00000000 --- a/com32/sysdump/data.h +++ /dev/null @@ -1,2 +0,0 @@ -#ifndef DATA_H -#define DATA_H diff --git a/com32/sysdump/dmi.c b/com32/sysdump/dmi.c index be4cce46..ce25efa4 100644 --- a/com32/sysdump/dmi.c +++ b/com32/sysdump/dmi.c @@ -6,7 +6,6 @@ #include <string.h> #include <stdlib.h> #include "sysdump.h" -#include "backend.h" struct dmi_header { char signature[5]; @@ -60,7 +59,7 @@ static bool is_smbios(size_t dptr) is_old_dmi(dptr+16); } -static void dump_smbios(struct backend *be, size_t dptr) +static void dump_smbios(struct upload_backend *be, size_t dptr) { const struct smbios_header *smb = (void *)dptr; struct smbios_header smx = *smb; @@ -82,7 +81,7 @@ static void dump_smbios(struct backend *be, size_t dptr) write_data(be, (const void *)smb->dmi.tbladdr, smb->dmi.tbllen); } -static void dump_old_dmi(struct backend *be, size_t dptr) +static void dump_old_dmi(struct upload_backend *be, size_t dptr) { const struct dmi_header *dmi = (void *)dptr; struct fake { @@ -108,7 +107,7 @@ static void dump_old_dmi(struct backend *be, size_t dptr) write_data(be, (const void *)dmi->tbladdr, dmi->tbllen); } -void dump_dmi(struct backend *be) +void dump_dmi(struct upload_backend *be) { size_t dptr; diff --git a/com32/sysdump/main.c b/com32/sysdump/main.c index d0d40a7b..f672585d 100644 --- a/com32/sysdump/main.c +++ b/com32/sysdump/main.c @@ -19,8 +19,7 @@ #include <dprintf.h> #include <console.h> #include <sys/cpu.h> -#include "../../version.h" -#include "backend.h" +#include <version.h> #include "sysdump.h" const char program[] = "sysdump"; @@ -32,7 +31,7 @@ __noreturn die(const char *msg) exit(1); } -static void dump_all(struct backend *be, const char *argv[]) +static void dump_all(struct upload_backend *be, const char *argv[]) { cpio_init(be, argv); @@ -50,20 +49,20 @@ static void dump_all(struct backend *be, const char *argv[]) flush_data(be); } -static struct backend *backends[] = +static struct upload_backend *upload_backends[] = { - &be_tftp, - &be_ymodem, - &be_srec, + &upload_tftp, + &upload_ymodem, + &upload_srec, NULL }; __noreturn usage(void) { - struct backend **bep, *be; + struct upload_backend **bep, *be; printf("Usage:\n"); - for (bep = backends ; (be = *bep) ; bep++) + for (bep = upload_backends ; (be = *bep) ; bep++) printf(" %s %s %s\n", program, be->name, be->helpmsg); exit(1); @@ -71,7 +70,7 @@ __noreturn usage(void) int main(int argc, char *argv[]) { - struct backend **bep, *be; + struct upload_backend **bep, *be; openconsole(&dev_null_r, &dev_stdcon_w); fputs(version, stdout); @@ -79,7 +78,7 @@ int main(int argc, char *argv[]) if (argc < 2) usage(); - for (bep = backends ; (be = *bep) ; bep++) { + for (bep = upload_backends ; (be = *bep) ; bep++) { if (!strcmp(be->name, argv[1])) break; } diff --git a/com32/sysdump/memmap.c b/com32/sysdump/memmap.c index 251107d5..929873fe 100644 --- a/com32/sysdump/memmap.c +++ b/com32/sysdump/memmap.c @@ -7,7 +7,6 @@ #include <stdlib.h> #include <com32.h> #include "sysdump.h" -#include "backend.h" #define E820_CHUNK 128 struct e820_info { @@ -16,7 +15,7 @@ struct e820_info { uint8_t data[24]; }; -static void dump_e820(struct backend *be) +static void dump_e820(struct upload_backend *be) { com32sys_t ireg, oreg; struct e820_info *curr; @@ -63,7 +62,7 @@ static void dump_e820(struct backend *be) lfree(curr); } -void dump_memory_map(struct backend *be) +void dump_memory_map(struct upload_backend *be) { com32sys_t ireg, oreg; diff --git a/com32/sysdump/memory.c b/com32/sysdump/memory.c index 6552e7f3..377f9a99 100644 --- a/com32/sysdump/memory.c +++ b/com32/sysdump/memory.c @@ -7,7 +7,6 @@ #include <stdlib.h> #include <sys/cpu.h> #include "sysdump.h" -#include "backend.h" static char *lowmem; static size_t lowmem_len; @@ -29,7 +28,7 @@ void snapshot_lowmem(void) } } -static void dump_memory_range(struct backend *be, const void *where, +static void dump_memory_range(struct upload_backend *be, const void *where, const void *addr, size_t len) { char filename[32]; @@ -38,7 +37,7 @@ static void dump_memory_range(struct backend *be, const void *where, cpio_writefile(be, filename, where, len); } -void dump_memory(struct backend *be) +void dump_memory(struct upload_backend *be) { printf("Dumping memory... "); diff --git a/com32/sysdump/pci.c b/com32/sysdump/pci.c index 1d687279..9c23a841 100644 --- a/com32/sysdump/pci.c +++ b/com32/sysdump/pci.c @@ -7,9 +7,8 @@ #include <stdlib.h> #include <sys/pci.h> #include "sysdump.h" -#include "backend.h" -static void dump_pci_device(struct backend *be, pciaddr_t a, uint8_t hdrtype) +static void dump_pci_device(struct upload_backend *be, pciaddr_t a, uint8_t hdrtype) { unsigned int bus = pci_bus(a); unsigned int dev = pci_dev(a); @@ -31,7 +30,7 @@ static void dump_pci_device(struct backend *be, pciaddr_t a, uint8_t hdrtype) cpio_writefile(be, filename, data, sizeof data); } -void dump_pci(struct backend *be) +void dump_pci(struct upload_backend *be) { int cfgtype; unsigned int nbus, ndev, nfunc, maxfunc; diff --git a/com32/sysdump/sysdump.h b/com32/sysdump/sysdump.h index a5b963f8..72e4875e 100644 --- a/com32/sysdump/sysdump.h +++ b/com32/sysdump/sysdump.h @@ -1,15 +1,15 @@ #ifndef SYSDUMP_H #define SYSDUMP_H -struct backend; +#include <libupload/upload_backend.h> -void dump_memory_map(struct backend *); +void dump_memory_map(struct upload_backend *); void snapshot_lowmem(void); -void dump_memory(struct backend *); -void dump_dmi(struct backend *); -void dump_acpi(struct backend *); -void dump_cpuid(struct backend *); -void dump_pci(struct backend *); -void dump_vesa_tables(struct backend *); +void dump_memory(struct upload_backend *); +void dump_dmi(struct upload_backend *); +void dump_acpi(struct upload_backend *); +void dump_cpuid(struct upload_backend *); +void dump_pci(struct upload_backend *); +void dump_vesa_tables(struct upload_backend *); #endif /* SYSDUMP_H */ diff --git a/com32/sysdump/vesa.c b/com32/sysdump/vesa.c index 017f9e4f..42adc3da 100644 --- a/com32/sysdump/vesa.c +++ b/com32/sysdump/vesa.c @@ -1,10 +1,9 @@ #include <string.h> #include <stdio.h> -#include "../lib/sys/vesa/vesa.h" -#include "backend.h" +#include <lib/sys/vesa/vesa.h> #include "sysdump.h" -void dump_vesa_tables(struct backend *be) +void dump_vesa_tables(struct upload_backend *be) { com32sys_t rm; struct vesa_info *vip; diff --git a/com32/tools/Makefile b/com32/tools/Makefile index e34296b4..0161baf1 100644 --- a/com32/tools/Makefile +++ b/com32/tools/Makefile @@ -10,11 +10,13 @@ ## ## ----------------------------------------------------------------------- -topdir = ../.. -include $(topdir)/MCONFIG.build +MAKEDIR = ../../mk +include $(MAKEDIR)/build.mk BINS = relocs +INCLUDES += -I./include + all : $(BINS) relocs : relocs.o diff --git a/com32/tools/include/tools/le_byteshift.h b/com32/tools/include/tools/le_byteshift.h new file mode 100644 index 00000000..c99d45a6 --- /dev/null +++ b/com32/tools/include/tools/le_byteshift.h @@ -0,0 +1,70 @@ +#ifndef _TOOLS_LE_BYTESHIFT_H +#define _TOOLS_LE_BYTESHIFT_H + +#include <linux/types.h> + +static inline __u16 __get_unaligned_le16(const __u8 *p) +{ + return p[0] | p[1] << 8; +} + +static inline __u32 __get_unaligned_le32(const __u8 *p) +{ + return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24; +} + +static inline __u64 __get_unaligned_le64(const __u8 *p) +{ + return (__u64)__get_unaligned_le32(p + 4) << 32 | + __get_unaligned_le32(p); +} + +static inline void __put_unaligned_le16(__u16 val, __u8 *p) +{ + *p++ = val; + *p++ = val >> 8; +} + +static inline void __put_unaligned_le32(__u32 val, __u8 *p) +{ + __put_unaligned_le16(val >> 16, p + 2); + __put_unaligned_le16(val, p); +} + +static inline void __put_unaligned_le64(__u64 val, __u8 *p) +{ + __put_unaligned_le32(val >> 32, p + 4); + __put_unaligned_le32(val, p); +} + +static inline __u16 get_unaligned_le16(const void *p) +{ + return __get_unaligned_le16((const __u8 *)p); +} + +static inline __u32 get_unaligned_le32(const void *p) +{ + return __get_unaligned_le32((const __u8 *)p); +} + +static inline __u64 get_unaligned_le64(const void *p) +{ + return __get_unaligned_le64((const __u8 *)p); +} + +static inline void put_unaligned_le16(__u16 val, void *p) +{ + __put_unaligned_le16(val, p); +} + +static inline void put_unaligned_le32(__u32 val, void *p) +{ + __put_unaligned_le32(val, p); +} + +static inline void put_unaligned_le64(__u64 val, void *p) +{ + __put_unaligned_le64(val, p); +} + +#endif /* _TOOLS_LE_BYTESHIFT_H */ diff --git a/com32/tools/relocs.c b/com32/tools/relocs.c index 24742060..86fc7c50 100644 --- a/com32/tools/relocs.c +++ b/com32/tools/relocs.c @@ -13,12 +13,16 @@ #define USE_BSD #include <endian.h> #include <regex.h> -#include <sys/types.h> +#include <tools/le_byteshift.h> + +static void die(char *fmt, ...); #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) static Elf32_Ehdr ehdr; static unsigned long reloc_count, reloc_idx; static unsigned long *relocs; +static unsigned long reloc16_count, reloc16_idx; +static unsigned long *relocs16; struct section { Elf32_Shdr shdr; @@ -29,60 +33,87 @@ struct section { }; static struct section *secs; -static void die(char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - exit(1); -} +enum symtype { + S_ABS, + S_REL, + S_SEG, + S_LIN, + S_NSYMTYPES +}; +static const char * const sym_regex_kernel[S_NSYMTYPES] = { /* * Following symbols have been audited. Don't warn user about * absolute relocations present w.r.t these symbols. */ + [S_ABS] = + "^(__.*_len|__.*_dwords)$", -/* True absolute relocations */ +/* + * These symbols are known to be relative, even if the linker marks them + * as absolute (typically defined outside any section in the linker script.) + */ + [S_REL] = + "^(__.*_start|__.*_end|_end|_[se](text|data))$", +}; -static const char safe_abs_regex[] = -"^(__.*_len|__.*_dwords)$"; -static regex_t safe_abs_regex_c; -static int is_safe_abs_reloc(const char *sym_name) -{ - return !regexec(&safe_abs_regex_c, sym_name, 0, NULL, 0); -} +static const char * const sym_regex_realmode[S_NSYMTYPES] = { +/* + * These are 16-bit segment symbols when compiling 16-bit code. + */ + [S_SEG] = + "^real_mode_seg$", -/* These are relative even though the linker marks them absolute */ +/* + * These are offsets belonging to segments, as opposed to linear addresses, + * when compiling 16-bit code. + */ + [S_LIN] = + "^pa_", +}; -static const char safe_rel_regex[] = -"^(__.*_start|__.*_end|_end|_[se](text|data))$"; -static regex_t safe_rel_regex_c; +static const char * const *sym_regex; -static int is_safe_rel_reloc(const char *sym_name) +static regex_t sym_regex_c[S_NSYMTYPES]; +static int is_reloc(enum symtype type, const char *sym_name) { - return !regexec(&safe_rel_regex_c, sym_name, 0, NULL, 0); + return sym_regex[type] && + !regexec(&sym_regex_c[type], sym_name, 0, NULL, 0); } -static void regex_init(void) +static void regex_init(int use_real_mode) { - char errbuf[128]; - int err; + char errbuf[128]; + int err; + int i; - err = regcomp(&safe_abs_regex_c, safe_abs_regex, - REG_EXTENDED|REG_NOSUB); - if (err) { - regerror(err, &safe_abs_regex_c, errbuf, sizeof errbuf); - die("%s", errbuf); - } + if (use_real_mode) + sym_regex = sym_regex_realmode; + else + sym_regex = sym_regex_kernel; - err = regcomp(&safe_rel_regex_c, safe_rel_regex, - REG_EXTENDED|REG_NOSUB); - if (err) { - regerror(err, &safe_rel_regex_c, errbuf, sizeof errbuf); - die("%s", errbuf); - } + for (i = 0; i < S_NSYMTYPES; i++) { + if (!sym_regex[i]) + continue; + + err = regcomp(&sym_regex_c[i], sym_regex[i], + REG_EXTENDED|REG_NOSUB); + + if (err) { + regerror(err, &sym_regex_c[i], errbuf, sizeof errbuf); + die("%s", errbuf); + } + } +} + +static void die(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + exit(1); } static const char *sym_type(unsigned type) @@ -153,13 +184,16 @@ static const char *rel_type(unsigned type) REL_TYPE(R_386_RELATIVE), REL_TYPE(R_386_GOTOFF), REL_TYPE(R_386_GOTPC), + REL_TYPE(R_386_8), + REL_TYPE(R_386_PC8), + REL_TYPE(R_386_16), + REL_TYPE(R_386_PC16), #undef REL_TYPE }; - const char *name = NULL; - if (type < ARRAY_SIZE(type_name)) + const char *name = "unknown type rel type name"; + if (type < ARRAY_SIZE(type_name) && type_name[type]) { name = type_name[type]; - if (!name) - name = "unknown"; + } return name; } @@ -189,7 +223,7 @@ static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym) name = sym_strtab + sym->st_name; } else { - name = sec_name(secs[sym->st_shndx].shdr.sh_name); + name = sec_name(sym->st_shndx); } return name; } @@ -428,7 +462,7 @@ static void print_absolute_symbols(void) printf("\n"); } -static int print_absolute_relocs(FILE *f) +static void print_absolute_relocs(void) { int i, printed = 0; @@ -472,17 +506,18 @@ static int print_absolute_relocs(FILE *f) * Before warning check if this absolute symbol * relocation is harmless. */ - if (is_safe_abs_reloc(name) || - is_safe_rel_reloc(name)) + if (is_reloc(S_ABS, name) || is_reloc(S_REL, name)) continue; if (!printed) { - fprintf(f, "Unknown absolute relocations present\n"); - fprintf(f, "Offset Info Type Sym.Value Sym.Name\n"); + printf("WARNING: Absolute relocations" + " present\n"); + printf("Offset Info Type Sym.Value " + "Sym.Name\n"); printed = 1; } - fprintf(f, "%08x %08x %10s %08x %s\n", + printf("%08x %08x %10s %08x %s\n", rel->r_offset, rel->r_info, rel_type(ELF32_R_TYPE(rel->r_info)), @@ -492,12 +527,11 @@ static int print_absolute_relocs(FILE *f) } if (printed) - fputc('\n', f); - - return printed; + printf("\n"); } -static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym)) +static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym), + int use_real_mode) { int i; /* Walk through the relocations */ @@ -522,31 +556,71 @@ static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym)) Elf32_Rel *rel; Elf32_Sym *sym; unsigned r_type; + const char *symname; + int shn_abs; + rel = &sec->reltab[j]; sym = &sh_symtab[ELF32_R_SYM(rel->r_info)]; r_type = ELF32_R_TYPE(rel->r_info); - /* Don't visit relocations to absolute symbols */ - if (sym->st_shndx == SHN_ABS && - !is_safe_rel_reloc(sym_name(sym_strtab, sym))) - continue; + + shn_abs = sym->st_shndx == SHN_ABS; switch (r_type) { case R_386_NONE: case R_386_PC32: + case R_386_PC16: + case R_386_PC8: case R_386_GOTPC: case R_386_GOTOFF: case R_386_GOT32: case R_386_PLT32: - /* Relative relocations don't need to - be adjusted */ + /* + * NONE can be ignored and and PC relative + * relocations don't need to be adjusted. + */ break; + + case R_386_16: + symname = sym_name(sym_strtab, sym); + if (!use_real_mode) + goto bad; + if (shn_abs) { + if (is_reloc(S_ABS, symname)) + break; + else if (!is_reloc(S_SEG, symname)) + goto bad; + } else { + if (is_reloc(S_LIN, symname)) + goto bad; + else + break; + } + visit(rel, sym); + break; + case R_386_32: - /* Visit relocations that need adjustment */ + symname = sym_name(sym_strtab, sym); + if (shn_abs) { + if (is_reloc(S_ABS, symname)) + break; + else if (!is_reloc(S_REL, symname)) + goto bad; + } else { + if (use_real_mode && + !is_reloc(S_LIN, symname)) + break; + } visit(rel, sym); break; default: die("Unsupported relocation type: %s (%d)\n", rel_type(r_type), r_type); + break; + bad: + symname = sym_name(sym_strtab, sym); + die("Invalid %s %s relocation: %s\n", + shn_abs ? "absolute" : "relative", + rel_type(r_type), symname); } } } @@ -554,8 +628,12 @@ static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym)) static void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym) { - (void)rel; (void)sym; - reloc_count += 1; + (void)sym; + + if (ELF32_R_TYPE(rel->r_info) == R_386_16) + reloc16_count++; + else + reloc_count++; } static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym) @@ -563,7 +641,10 @@ static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym) (void)sym; /* Remember the address that needs to be adjusted. */ - relocs[reloc_idx++] = rel->r_offset; + if (ELF32_R_TYPE(rel->r_info) == R_386_16) + relocs16[reloc16_idx++] = rel->r_offset; + else + relocs[reloc_idx++] = rel->r_offset; } static int cmp_relocs(const void *va, const void *vb) @@ -573,23 +654,41 @@ static int cmp_relocs(const void *va, const void *vb) return (*a == *b)? 0 : (*a > *b)? 1 : -1; } -static void emit_relocs(int as_text) +static int write32(unsigned int v, FILE *f) +{ + unsigned char buf[4]; + + put_unaligned_le32(v, buf); + return fwrite(buf, 1, 4, f) == 4 ? 0 : -1; +} + +static void emit_relocs(int as_text, int use_real_mode) { int i; /* Count how many relocations I have and allocate space for them. */ reloc_count = 0; - walk_relocs(count_reloc); + walk_relocs(count_reloc, use_real_mode); relocs = malloc(reloc_count * sizeof(relocs[0])); if (!relocs) { die("malloc of %d entries for relocs failed\n", reloc_count); } + + relocs16 = malloc(reloc16_count * sizeof(relocs[0])); + if (!relocs16) { + die("malloc of %d entries for relocs16 failed\n", + reloc16_count); + } /* Collect up the relocations */ reloc_idx = 0; - walk_relocs(collect_reloc); + walk_relocs(collect_reloc, use_real_mode); + + if (reloc16_count && !use_real_mode) + die("Segment relocations found but --realmode not specified\n"); /* Order the relocations for more efficient processing */ qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs); + qsort(relocs16, reloc16_count, sizeof(relocs16[0]), cmp_relocs); /* Print the relocations */ if (as_text) { @@ -598,61 +697,83 @@ static void emit_relocs(int as_text) */ printf(".section \".data.reloc\",\"a\"\n"); printf(".balign 4\n"); - for (i = 0; i < reloc_count; i++) { - printf("\t .long 0x%08lx\n", relocs[i]); + if (use_real_mode) { + printf("\t.long %lu\n", reloc16_count); + for (i = 0; i < reloc16_count; i++) + printf("\t.long 0x%08lx\n", relocs16[i]); + printf("\t.long %lu\n", reloc_count); + for (i = 0; i < reloc_count; i++) { + printf("\t.long 0x%08lx\n", relocs[i]); + } + } else { + for (i = 0; i < reloc_count; i++) { + printf("\t.long 0x%08lx\n", relocs[i]); + } + /* Print a stop */ + printf("\t.long 0x%08lx\n", (unsigned long)0); } + printf("\n"); } else { - unsigned char buf[4]; - /* Now print each relocation */ - for (i = 0; i < reloc_count; i++) { - buf[0] = (relocs[i] >> 0) & 0xff; - buf[1] = (relocs[i] >> 8) & 0xff; - buf[2] = (relocs[i] >> 16) & 0xff; - buf[3] = (relocs[i] >> 24) & 0xff; - fwrite(buf, 4, 1, stdout); + if (use_real_mode) { + write32(reloc16_count, stdout); + for (i = 0; i < reloc16_count; i++) + write32(relocs16[i], stdout); + write32(reloc_count, stdout); + + /* Now print each relocation */ + for (i = 0; i < reloc_count; i++) + write32(relocs[i], stdout); + } else { + /* Now print each relocation */ + for (i = 0; i < reloc_count; i++) { + write32(relocs[i], stdout); + } + + /* Print a stop */ + write32(0, stdout); } - /* Print a stop */ - memset(buf, 0, sizeof buf); - fwrite(buf, 4, 1, stdout); } } static void usage(void) { - die("relocs [--abs-syms |--abs-relocs | --text] vmlinux\n"); + die("relocs [--abs-syms|--abs-relocs|--text|--realmode] vmlinux\n"); } int main(int argc, char **argv) { int show_absolute_syms, show_absolute_relocs; - int as_text; + int as_text, use_real_mode; const char *fname; FILE *fp; int i; - int err = 0; show_absolute_syms = 0; show_absolute_relocs = 0; as_text = 0; + use_real_mode = 0; fname = NULL; for (i = 1; i < argc; i++) { char *arg = argv[i]; if (*arg == '-') { - if (strcmp(argv[1], "--abs-syms") == 0) { + if (strcmp(arg, "--abs-syms") == 0) { show_absolute_syms = 1; continue; } - - if (strcmp(argv[1], "--abs-relocs") == 0) { + if (strcmp(arg, "--abs-relocs") == 0) { show_absolute_relocs = 1; continue; } - else if (strcmp(argv[1], "--text") == 0) { + if (strcmp(arg, "--text") == 0) { as_text = 1; continue; } + if (strcmp(arg, "--realmode") == 0) { + use_real_mode = 1; + continue; + } } else if (!fname) { fname = arg; @@ -663,10 +784,7 @@ int main(int argc, char **argv) if (!fname) { usage(); } - - - regex_init(); - + regex_init(use_real_mode); fp = fopen(fname, "r"); if (!fp) { die("Cannot open %s: %s\n", @@ -682,10 +800,9 @@ int main(int argc, char **argv) return 0; } if (show_absolute_relocs) { - print_absolute_relocs(stdout); + print_absolute_relocs(); return 0; } - err = print_absolute_relocs(stderr); - emit_relocs(as_text); - return err; + emit_relocs(as_text, use_real_mode); + return 0; } |