Paulo Alcantara
2015-Jul-22 23:27 UTC
[syslinux] [PULL 0/8] MultiFS suppport for BIOS and EFI
So last week I was wondering if XFS was still working -- even with its last on-disk structure changes -- and it _suprisingly_ worked as expected. Right, now I can finally get rid of GRUB and use Syslinux to boot my Linux on EFI from a rootfs with xfs. Shit, I have two partitions (the first one being the required ESP) so there is no way to access the other partitions since because Syslinux does not support multiple disk and/or partitions -- yet. I completly refused to accept that and then looked at the current status of MultiFS support; its original implementation only worked on BIOS. Therefore I started working on EFI support and -- luckily enough -- I also had Raphael to help me with development and testing. (I'm really glad to hack Syslinux again. What a great project...) The MultiFS syntax is basically "(hdX,Y)/path/to/file", where X is disk number and Y is partition number. Please test it and report to us if any issue found. Signed-off-by: Paulo Alcantara <pcacjr at zytor.com> --- The following changes since commit 8702009fc7a6689432d17d4ea05d9c878452c57a: efi: rename pxe_handle to image_device_handle (2015-07-19 08:09:10 -0400) are available in the git repository at: git://git.zytor.com/users/pcacjr/syslinux.git multifs-for-upstream for you to fetch changes up to b8ca887baec49b6375e12a2ef5847dd4f2017232: efi/multifs: fix misuse of static private information (2015-07-22 19:20:43 -0300) ---------------------------------------------------------------- Paulo Alcantara (5): ldlinux/kernel: contemplate multifs path syntax efi: add MultiFS support sys/common: handle multifs paths in findpath() multifs: add support for both UEFI and BIOS firmware efi/multifs: fix misuse of static private information Raphael S. Carvalho (3): Move partiter from com32/chain to com32/lib/syslinux core: MultiFS infrastructure added. Wire up MultiFS support. com32/chain/Makefile | 2 +- com32/chain/chain.c | 4 +- com32/chain/mangle.c | 4 +- com32/chain/mangle.h | 2 +- com32/chain/options.c | 4 +- com32/elflink/ldlinux/kernel.c | 9 ++ com32/elflink/ldlinux/ldlinux.c | 9 ++ com32/include/syslinux/multifs_utils.h | 32 ++++ com32/{chain => include/syslinux}/partiter.h | 0 com32/{chain => include/syslinux}/utility.h | 3 +- com32/lib/sys/module/common.c | 7 +- com32/lib/syslinux/multifs_utils.c | 91 +++++++++++ com32/{chain => lib/syslinux}/partiter.c | 6 +- com32/{chain => lib/syslinux}/utility.c | 2 +- core/bios.c | 11 ++ core/fs/cache.c | 2 +- core/fs/diskio.c | 28 +++- core/fs/diskio_bios.c | 40 ++--- core/fs/fs.c | 21 ++- core/fs/readdir.c | 8 +- core/include/multifs.h | 50 ++++++ core/multifs.c | 221 +++++++++++++++++++++++++++ core/multifs_bios.c | 75 +++++++++ efi/diskio.c | 32 ++-- efi/main.c | 26 +++- efi/multifs.c | 166 ++++++++++++++++++++ efi/multifs_utils.h | 52 +++++++ mk/lib.mk | 3 +- 28 files changed, 845 insertions(+), 65 deletions(-) create mode 100644 com32/include/syslinux/multifs_utils.h rename com32/{chain => include/syslinux}/partiter.h (100%) rename com32/{chain => include/syslinux}/utility.h (97%) create mode 100644 com32/lib/syslinux/multifs_utils.c rename com32/{chain => lib/syslinux}/partiter.c (99%) rename com32/{chain => lib/syslinux}/utility.c (99%) create mode 100644 core/include/multifs.h create mode 100644 core/multifs.c create mode 100644 core/multifs_bios.c create mode 100644 efi/multifs.c create mode 100644 efi/multifs_utils.h -- 2.1.0
Paulo Alcantara
2015-Jul-22 23:27 UTC
[syslinux] [PULL 1/8] Move partiter from com32/chain to com32/lib/syslinux
From: "Raphael S. Carvalho" <raphael.scarv at gmail.com> MultiFS depends on the availability of partiter to find a partition. Cc: Gene Cumm <gene.cumm at gmail.com> Signed-off-by: Raphael S. Carvalho <raphael.scarv at gmail.com> Signed-off-by: Paulo Alcantara <pcacjr at zytor.com> --- com32/chain/Makefile | 2 +- com32/chain/chain.c | 4 +- com32/chain/mangle.c | 4 +- com32/chain/mangle.h | 2 +- com32/chain/options.c | 4 +- com32/chain/partiter.c | 726 -------------------------------------- com32/chain/partiter.h | 119 ------- com32/chain/utility.c | 256 -------------- com32/chain/utility.h | 75 ---- com32/include/syslinux/partiter.h | 119 +++++++ com32/include/syslinux/utility.h | 76 ++++ com32/lib/syslinux/partiter.c | 726 ++++++++++++++++++++++++++++++++++++++ com32/lib/syslinux/utility.c | 256 ++++++++++++++ mk/lib.mk | 2 +- 14 files changed, 1186 insertions(+), 1185 deletions(-) delete mode 100644 com32/chain/partiter.c delete mode 100644 com32/chain/partiter.h delete mode 100644 com32/chain/utility.c delete mode 100644 com32/chain/utility.h create mode 100644 com32/include/syslinux/partiter.h create mode 100644 com32/include/syslinux/utility.h create mode 100644 com32/lib/syslinux/partiter.c create mode 100644 com32/lib/syslinux/utility.c diff --git a/com32/chain/Makefile b/com32/chain/Makefile index d7b5aa8..a7d1f66 100644 --- a/com32/chain/Makefile +++ b/com32/chain/Makefile @@ -16,7 +16,7 @@ VPATH = $(SRC) include $(MAKEDIR)/elf.mk -OBJS = chain.o partiter.o utility.o options.o mangle.o +OBJS = chain.o options.o mangle.o CFLAGS += -fno-strict-aliasing all: chain.c32 diff --git a/com32/chain/chain.c b/com32/chain/chain.c index 4e9e32d..f9fe07e 100644 --- a/com32/chain/chain.c +++ b/com32/chain/chain.c @@ -35,9 +35,9 @@ #include <syslinux/disk.h> #include <syslinux/video.h> #include "chain.h" -#include "utility.h" +#include <syslinux/utility.h> #include "options.h" -#include "partiter.h" +#include <syslinux/partiter.h> #include "mangle.h" static int fixed_cnt = 128; /* see comments in main() */ diff --git a/com32/chain/mangle.c b/com32/chain/mangle.c index 275d0aa..64d9c19 100644 --- a/com32/chain/mangle.c +++ b/com32/chain/mangle.c @@ -37,8 +37,8 @@ #include <syslinux/config.h> #include "chain.h" #include "options.h" -#include "utility.h" -#include "partiter.h" +#include <syslinux/utility.h> +#include <syslinux/partiter.h> #include "mangle.h" static const char cmldr_signature[8] = "cmdcons"; diff --git a/com32/chain/mangle.h b/com32/chain/mangle.h index 42f6c5b..98b2f2c 100644 --- a/com32/chain/mangle.h +++ b/com32/chain/mangle.h @@ -32,7 +32,7 @@ #define COM32_CHAIN_MANGLE_H #include "chain.h" -#include "partiter.h" +#include <syslinux/partiter.h> /* file's manglers */ int manglef_isolinux(struct data_area *data); diff --git a/com32/chain/options.c b/com32/chain/options.c index 2b51939..b3c986e 100644 --- a/com32/chain/options.c +++ b/com32/chain/options.c @@ -33,8 +33,8 @@ #include <stdlib.h> #include <string.h> #include "chain.h" -#include "partiter.h" -#include "utility.h" +#include <syslinux/partiter.h> +#include <syslinux/utility.h> #include "options.h" struct options opt; diff --git a/com32/chain/partiter.c b/com32/chain/partiter.c deleted file mode 100644 index 4937f0c..0000000 --- a/com32/chain/partiter.c +++ /dev/null @@ -1,726 +0,0 @@ -/* ----------------------------------------------------------------------- * - * - * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved - * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin - * Copyright 2010 Shao Miller - * Copyright 2010-2015 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 "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)) - -/* virtual forwards */ - -static void pi_dtor_(struct part_iter *); -static int pi_next_(struct part_iter *); -static int pi_dos_next(struct part_iter *); -static int pi_gpt_next(struct part_iter *); - -/* vtab and types */ - -static struct itertype types[] = { - [0] = { - .dtor = &pi_dtor_, - .next = &pi_dos_next, -}, [1] = { - .dtor = &pi_dtor_, - .next = &pi_gpt_next, -}, [2] = { - .dtor = &pi_dtor_, - .next = &pi_next_, -}}; - -const struct itertype * const typedos = types; -const struct itertype * const typegpt = types+1; -const struct itertype * const typeraw = types+2; - -/* pi_dtor_() - common/raw iterator cleanup */ -static void pi_dtor_(struct part_iter *iter) -{ - /* syslinux's free is null resilient */ - free(iter->data); -} - -/* pi_ctor() - common/raw iterator initialization */ -static int pi_ctor(struct part_iter *iter, - const struct disk_info *di, int flags -) -{ - memcpy(&iter->di, di, sizeof *di); - iter->flags = flags; - iter->index0 = -1; - iter->length = di->lbacnt; - - iter->type = typeraw; - return 0; -} - -/* pi_dos_ctor() - MBR/EBR iterator specific initialization */ -static int pi_dos_ctor(struct part_iter *iter, - const struct disk_info *di, int flags, - const struct disk_dos_mbr *mbr -) -{ - if (pi_ctor(iter, di, flags)) - return -1; - - if (!(iter->data = malloc(sizeof *mbr))) { - critm(); - goto bail; - } - - memcpy(iter->data, mbr, sizeof *mbr); - - iter->dos.bebr_index0 = -1; - iter->dos.disk_sig = mbr->disk_sig; - - iter->type = typedos; - return 0; -bail: - pi_dtor_(iter); - return -1; -} - -/* pi_gpt_ctor() - GPT iterator specific initialization */ -static int pi_gpt_ctor(struct part_iter *iter, - const struct disk_info *di, int flags, - const struct disk_gpt_header *gpth, const struct disk_gpt_part_entry *gptl -) -{ - uint64_t siz; - - if (pi_ctor(iter, di, flags)) - return -1; - - siz = (uint64_t)gpth->part_count * gpth->part_size; - - if (!(iter->data = malloc((size_t)siz))) { - critm(); - goto bail; - } - - memcpy(iter->data, gptl, (size_t)siz); - - iter->gpt.pe_count = (int)gpth->part_count; - iter->gpt.pe_size = (int)gpth->part_size; - iter->gpt.ufirst = gpth->lba_first_usable; - iter->gpt.ulast = gpth->lba_last_usable; - - memcpy(&iter->gpt.disk_guid, &gpth->disk_guid, sizeof gpth->disk_guid); - memcpy(&iter->gpt.part_guid, &gpth->disk_guid, sizeof gpth->disk_guid); - - iter->type = typegpt; - return 0; -bail: - pi_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("The 1st EBR entry must be data or empty."); - return -1; - } - - if (!(iter->flags & PIF_STRICT)) - return 0; - - 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->dos.nebr_siz) { - - error("Logical partition (in EBR) with invalid offset and/or length."); - 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("The 2nd EBR entry must be extended or empty."); - return -1; - } - - if (!(iter->flags & PIF_STRICT)) - return 0; - - 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->dos.bebr_siz) { - - error("Extended partition (EBR) with invalid offset and/or length."); - 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 (!(iter->flags & PIF_STRICT)) - return 0; - - if (!dp->start_lba || - !dp->length || - !sane(dp->start_lba, dp->length) || - ((iter->flags & PIF_STRICTER) && (dp->start_lba + dp->length > iter->di.lbacnt))) { - error("Primary partition (in MBR) with invalid offset and/or length."); - 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->gpt.pe_size); - - if (guid_is0(&gp->type)) - return 0; - - if (!(iter->flags & PIF_STRICT)) - return 0; - - if (gp->lba_first < iter->gpt.ufirst || - gp->lba_last > iter->gpt.ulast) { - error("LBA sectors of GPT partition are beyond the range allowed in GPT header."); - return -1; - } - - return 0; -} - -static int 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; - return -1; - } - - if (ost_is_ext(dp->ostype)) { - if (iter->dos.bebr_index0 >= 0) { - error("More than 1 extended partition."); - iter->status = PI_INSANE; - return -1; - } - /* record base EBR index */ - iter->dos.bebr_index0 = iter->index0; - } - if (!ost_is_nondata(dp->ostype) || (iter->flags & PIF_STEPALL)) { - *lba = dp->start_lba; - *_dp = dp; - break; - } - } - - return 0; -} - -static int prep_base_ebr(struct part_iter *iter) -{ - struct disk_dos_part_entry *dp; - - if (iter->dos.bebr_index0 < 0) /* if we don't have base extended partition at all */ - return -1; - else if (!iter->dos.bebr_lba) { /* if not initialized yet */ - dp = ((struct disk_dos_mbr *)iter->data)->table + iter->dos.bebr_index0; - - iter->dos.bebr_lba = dp->start_lba; - iter->dos.bebr_siz = dp->length; - - iter->dos.nebr_lba = dp->start_lba; - iter->dos.nebr_siz = dp->length; - - iter->index0--; - } - return 0; -} - -static int 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) < 0) { - iter->status = PI_DONE; - return -1; - } - - while (++iter->index0 < 1024 && iter->dos.nebr_lba) { - free(iter->data); - if (!(iter->data - disk_read_sectors(&iter->di, iter->dos.nebr_lba, 1))) { - error("Couldn't load EBR."); - iter->status = PI_ERRLOAD; - return -1; - } - - /* check sanity of loaded data */ - if (notsane_logical(iter) || notsane_extended(iter)) { - iter->status = PI_INSANE; - return -1; - } - - dp = ((struct disk_dos_mbr *)iter->data)->table; - - iter->dos.cebr_lba = iter->dos.nebr_lba; - iter->dos.cebr_siz = iter->dos.nebr_siz; - - /* setup next frame values */ - if (dp[1].ostype) { - iter->dos.nebr_lba = iter->dos.bebr_lba + dp[1].start_lba; - iter->dos.nebr_siz = dp[1].length; - } else { - iter->dos.nebr_lba = 0; - iter->dos.nebr_siz = 0; - } - - if (!dp[0].ostype) - iter->dos.logskipcnt++; - - if (dp[0].ostype || (iter->flags & PIF_STEPALL)) { - *lba = dp[0].start_lba ? iter->dos.cebr_lba + dp[0].start_lba : 0; - *_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 PIF_STEPALL flag is set, we will never - * reach this place. - */ - } - iter->status = PI_DONE; - return -1; -} - -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->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->gpt.part_label[i] = (char)orig_lab[i]; - } - iter->gpt.part_label[PI_GPTLABSIZE/2] = 0; -} - -static inline int valid_crc(uint32_t crc, const uint8_t *buf, unsigned int siz) -{ - return crc == crc32(crc32(0, NULL, 0), buf, siz); -} - -static int valid_crc_gpth(struct disk_gpt_header *gh, int flags) -{ - uint32_t crc, crcc; - - if (!(flags & PIF_GPTHCRC)) - return 1; - - crc = gh->chksum; - gh->chksum = 0; - crcc = crc32(crc32(0, NULL, 0), (const uint8_t *)gh, gh->hdr_size); - gh->chksum = crc; - return crc == crcc; -} - -static int valid_crc_gptl(const struct disk_gpt_header *gh, const struct disk_gpt_part_entry *gl, int flags) -{ - uint32_t crcc; - - if (!(flags & PIF_GPTLCRC)) - return 1; - - crcc = crc32(crc32(0, NULL, 0), (const uint8_t *)gl, gh->part_size * gh->part_count); - return gh->table_chksum == crcc; -} - -static int pi_next_(struct part_iter *iter) -{ - iter->status = PI_DONE; - return iter->status; -} - -static int pi_dos_next(struct part_iter *iter) -{ - uint32_t abs_lba = 0; - struct disk_dos_part_entry *dos_part = NULL; - - if (iter->status) - return iter->status; - - /* look for primary partitions */ - if (iter->index0 < 4 && - dos_next_mbr(iter, &abs_lba, &dos_part) < 0) - return iter->status; - - /* look for logical partitions */ - if (iter->index0 >= 4 && - dos_next_ebr(iter, &abs_lba, &dos_part) < 0) - return iter->status; - - /* - * note special index handling: - * in case PIF_STEPALL is set - this makes the index consistent with - * non-PIF_STEPALL iterators - */ - - if (!dos_part->ostype) - iter->index = -1; - else - iter->index = iter->index0 + 1 - iter->dos.logskipcnt; - iter->abs_lba = abs_lba; - iter->length = dos_part->length; - iter->record = (char *)dos_part; - -#ifdef DEBUG - disk_dos_part_dump(dos_part); -#endif - - return iter->status; -} - -static int pi_gpt_next(struct part_iter *iter) -{ - const struct disk_gpt_part_entry *gpt_part = NULL; - - if (iter->status) - return iter->status; - - while (++iter->index0 < iter->gpt.pe_count) { - gpt_part = (const struct disk_gpt_part_entry *) - (iter->data + iter->index0 * iter->gpt.pe_size); - - if (notsane_gpt(iter)) { - iter->status = PI_INSANE; - return iter->status; - } - - if (!guid_is0(&gpt_part->type) || (iter->flags & PIF_STEPALL)) - break; - } - /* no more partitions ? */ - if (iter->index0 == iter->gpt.pe_count) { - iter->status = PI_DONE; - return iter->status; - } - /* gpt_part is guaranteed to be valid here */ - iter->index = iter->index0 + 1; - iter->abs_lba = gpt_part->lba_first; - iter->length = gpt_part->lba_last - gpt_part->lba_first + 1; - iter->record = (char *)gpt_part; - memcpy(&iter->gpt.part_guid, &gpt_part->uid, sizeof(struct guid)); - gpt_conv_label(iter); - -#ifdef DEBUG - disk_gpt_part_dump(gpt_part); -#endif - - return iter->status; -} - -static struct part_iter *pi_alloc(void) -{ - struct part_iter *iter; - if (!(iter = malloc(sizeof *iter))) - critm(); - else - memset(iter, 0, sizeof *iter); - return iter; -} - -/* pi_del() - delete iterator */ -void pi_del(struct part_iter **_iter) -{ - if(!_iter || !*_iter) - return; - pi_dtor(*_iter); - free(*_iter); - *_iter = NULL; -} - -static int notsane_gpt_hdr(const struct disk_info *di, const struct disk_gpt_header *gpth, int flags) -{ - 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 */ - uint64_t gpt_sec; /* secondary gpt header */ - - if (!(flags & PIF_STRICT)) - return 0; - - if (gpth->lba_alt < gpth->lba_cur) - gpt_sec = gpth->lba_cur; - else - gpt_sec = gpth->lba_alt; - 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). - */ - if (gpt_loff < 2 || !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 && gpt_loff <= gpth->lba_last_usable) || - gpt_loff + gpt_lcnt > gpt_sec || - ((flags & PIF_STRICTER) && (gpt_sec >= di->lbacnt)) || - gpth->part_size < sizeof(struct disk_gpt_part_entry)) - return -1; - - return 0; -} - -static void try_gpt_we(const char *str, int sec) -{ - if (sec) - error(str); - else - warn(str); -} - -static struct disk_gpt_header *try_gpt_hdr(const struct disk_info *di, int sec, int flags) -{ - const char *desc = sec ? "backup" : "primary"; - uint64_t gpt_cur = sec ? di->lbacnt - 1 : 1; - struct disk_gpt_header *gpth; - char errbuf[96]; - - gpth = disk_read_sectors(di, gpt_cur, 1); - if (!gpth) { - sprintf(errbuf, "Unable to read %s GPT header.", desc); - goto out; - } - if(!valid_crc_gpth(gpth, flags)) { - sprintf(errbuf, "Invalid checksum of %s GPT header.", desc); - goto out; - } - if(notsane_gpt_hdr(di, gpth, flags)) { - sprintf(errbuf, "Checksum of %s GPT header is valid, but values fail sanity checks.", desc); - goto out; - } - return gpth; -out: - try_gpt_we(errbuf, sec); - free(gpth); - return NULL; -} - -static struct disk_gpt_part_entry *try_gpt_list(const struct disk_info *di, const struct disk_gpt_header *gpth, int alt, int flags) -{ - int pri = gpth->lba_cur < gpth->lba_alt; - const char *desc = alt ? "alternative" : "main"; - struct disk_gpt_part_entry *gptl; - char errbuf[64]; - uint32_t gpt_lcnt; /* size of GPT partition in sectors */ - uint64_t gpt_loff; /* offset to GPT partition list in sectors */ - - gpt_lcnt = (gpth->part_size * gpth->part_count + di->bps - 1) / di->bps; - if (!alt) { - /* prefer header value for partition table if not asking for alternative */ - gpt_loff = gpth->lba_table; - } else { - /* try to read alternative, we have to calculate its position */ - if (!pri) - gpt_loff = gpth->lba_alt + 1; - else - gpt_loff = gpth->lba_alt - gpt_lcnt; - } - - gptl = disk_read_sectors(di, gpt_loff, gpt_lcnt); - if (!gptl) { - sprintf(errbuf, "Unable to read %s GPT partition list.", desc); - goto out; - } - if (!valid_crc_gptl(gpth, gptl, flags)) { - sprintf(errbuf, "Invalid checksum of %s GPT partition list.", desc); - goto out; - } - return gptl; -out: - try_gpt_we(errbuf, alt); - free(gptl); - return NULL; -} - -/* pi_begin() - validate and and get proper iterator for a disk described by di */ -struct part_iter *pi_begin(const struct disk_info *di, int flags) -{ - int isgpt = 0, ret = -1; - struct part_iter *iter; - struct disk_dos_mbr *mbr = NULL; - struct disk_gpt_header *gpth = NULL; - struct disk_gpt_part_entry *gptl = NULL; - - /* Preallocate iterator */ - if (!(iter = pi_alloc())) - goto out; - - /* Read MBR */ - if (!(mbr = disk_read_sectors(di, 0, 1))) { - error("Unable to read the first disk sector."); - goto out; - } - - /* Check for MBR magic */ - if (mbr->sig != disk_mbr_sig_magic) { - warn("No MBR magic, treating disk as raw."); - /* looks like RAW */ - ret = pi_ctor(iter, di, flags); - goto out; - } - - /* Check for GPT protective MBR */ - for (size_t i = 0; i < 4; i++) - isgpt |= (mbr->table[i].ostype == 0xEE); - isgpt = isgpt && !(flags & PIF_PREFMBR); - - /* Try to read GPT header */ - if (isgpt) { - gpth = try_gpt_hdr(di, 0, flags); - if (!gpth) - /* - * this read might fail if bios reports different disk size (different vm/pc) - * not much we can do here to avoid it - */ - gpth = try_gpt_hdr(di, 1, flags); - if (!gpth) - goto out; - } - - if (gpth && gpth->rev.uint32 == 0x00010000 && - !memcmp(gpth->sig, disk_gpt_sig_magic, sizeof gpth->sig)) { - /* looks like GPT v1.0 */ -#ifdef DEBUG - dprintf("Looks like a GPT v1.0 disk.\n"); - disk_gpt_header_dump(gpth); -#endif - gptl = try_gpt_list(di, gpth, 0, flags); - if (!gptl) - gptl = try_gpt_list(di, gpth, 1, flags); - if (!gptl) - goto out; - - /* looks like GPT */ - ret = pi_gpt_ctor(iter, di, flags, gpth, gptl); - } else { - /* looks like MBR */ - ret = pi_dos_ctor(iter, di, flags, mbr); - } -out: - if (ret < 0) { - free(iter); - iter = NULL; - } - 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 deleted file mode 100644 index a48f8d6..0000000 --- a/com32/chain/partiter.h +++ /dev/null @@ -1,119 +0,0 @@ -/* ----------------------------------------------------------------------- * - * - * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved - * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin - * Copyright 2010 Shao Miller - * Copyright 2010-2015 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.h - * - * Provides disk / partition iteration. - */ - -#ifndef COM32_CHAIN_PARTITER_H -#define COM32_CHAIN_PARTITER_H - -#include <stdint.h> -#include <syslinux/disk.h> - -/* status */ - -enum {PI_ERRLOAD = -31, PI_INSANE, PI_OK = 0, PI_DONE}; - -/* flags */ - -enum {PIF_STEPALL = 1, PIF_PREFMBR = 2, PIF_STRICT = 4, PIF_STRICTER = 8, PIF_GPTHCRC = 16, PIF_GPTLCRC = 32}; - -struct itertype; -struct part_iter; - -struct itertype { - void (*dtor)(struct part_iter *); - int (*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 abs_lba; - uint64_t length; - int index0; /* including holes, from -1 (disk, then parts from 0) */ - int index; /* excluding holes, from 0 (disk, then parts from 1), -1 means hole, if PIF_STEPALL is set */ - int flags; /* flags, see #defines above */ - int status; /* current status, see enums above */ - struct disk_info di; - union { - struct { - uint32_t disk_sig; /* 32bit disk signature as stored in MBR */ - - uint32_t bebr_lba; /* absolute lba of base extended partition */ - uint32_t bebr_siz; /* size of base extended partition */ - - uint32_t cebr_lba; /* absolute lba of curr ext. partition */ - uint32_t cebr_siz; /* size of curr ext. partition */ - uint32_t nebr_lba; /* absolute lba of next ext. partition */ - uint32_t nebr_siz; /* size of next ext. partition */ - - int bebr_index0; /* index of (0-3) of base ext. part., -1 if not present in MBR */ - int logskipcnt; /* how many logical holes were skipped */ - } dos; - struct { - 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; - }; -}; - -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 flags); -void pi_del(struct part_iter **); - -/* inline virtuals */ -static inline int pi_next(struct part_iter *iter) -{ - return iter->type->next(iter); -} - -static inline void pi_dtor(struct part_iter *iter) -{ - iter->type->dtor(iter); -} - -#endif - -/* vim: set ts=8 sts=4 sw=4 noet: */ diff --git a/com32/chain/utility.c b/com32/chain/utility.c deleted file mode 100644 index 180749e..0000000 --- a/com32/chain/utility.c +++ /dev/null @@ -1,256 +0,0 @@ -/* ----------------------------------------------------------------------- * - * - * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved - * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin - * Copyright 2010 Shao Miller - * Copyright 2010-2015 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. - * - * ----------------------------------------------------------------------- */ - -#include <com32.h> -#include <fcntl.h> -#include <stdint.h> -#include <stdio.h> -#include <errno.h> -#include <unistd.h> -#include <string.h> -#include <fs.h> -#include <syslinux/disk.h> -#include <syslinux/pmapi.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", - [8] = "exFAT", -}; - -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)); -} - -int guid_is0(const struct guid *guid) -{ - return - !(guid->data1 || - guid->data2 || - guid->data3 || - guid->data4); -} - -/* - * mode explanation: - * - * cnul - "strict" mode, never returning higher value than obtained from cbios - * cadd - if the disk is larger than reported geometry /and/ if the geometry has - * less cylinders than 1024 - it means that the total size is somewhere - * between cs and cs+1; in this particular case, we bump the cs to be able - * to return matching chs triplet - * cmax - assume we can use any cylinder value - * - * by default cadd seems most reasonable, giving consistent results with e.g. - * sfdisk's behavior - */ -void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, int 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) { - if (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 = (lba % ss) + 1; - 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) -{ - struct com32_filedata fd; - uint32_t lba = 0; - int size = 65536; - char *buf; - - buf = lmalloc(size); - if (!buf) - return 0; - - /* Put the filename in the bounce buffer */ - strlcpy(buf, filename, size); - - if (open_file(buf, O_RDONLY, &fd) <= 0) { - goto fail; /* Filename not found */ - } - - /* Since the first member is the LBA, we simply cast */ - lba = *((uint32_t *) MK_PTR(0, fd.handle)); - - /* Call comapi_close() to free the structure */ - close_file(fd.handle); - -fail: - lfree(buf); - return lba; -} - -/* drive offset detection */ -int drvoff_detect(int type) -{ - if (bpbV40 <= type && type <= bpbVNT) { - return 0x24; - } else if (type == bpbV70) { - return 0x40; - } else if (type == bpbEXF) { - return 0x6F; - } - - 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; - - /* exFAT mess first (media descriptor is 0 here) */ - if (!memcmp(sec + 0x03, "EXFAT ", 8)) { - rev = bpbEXF; - goto out; - } - - /* 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 deleted file mode 100644 index f8e9c61..0000000 --- a/com32/chain/utility.h +++ /dev/null @@ -1,75 +0,0 @@ -/* ----------------------------------------------------------------------- * - * - * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved - * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin - * Copyright 2010 Shao Miller - * Copyright 2010-2015 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. - * - * ----------------------------------------------------------------------- */ - -#ifndef COM32_CHAIN_UTILITY_H -#define COM32_CHAIN_UTILITY_H - -#include <stdint.h> -#include <stdio.h> -#include <syslinux/disk.h> -#include <syslinux/movebits.h> - -/* most (all ?) bpb "types" known to humankind as of 2012 */ -enum {bpbUNK, bpbV20, bpbV30, bpbV32, bpbV34, bpbV40, bpbVNT, bpbV70, bpbEXF}; - -/* see utility.c for details */ -enum {L2C_CNUL, L2C_CADD, L2C_CMAX}; - -/* first usable and first unusable offsets */ -#define dosmin ((addr_t)0x500u) -#define dosmax ((addr_t)(*(uint16_t *) 0x413 << 10)) - -void wait_key(void); -void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, int mode); -uint32_t get_file_lba(const char *filename); -int drvoff_detect(int type); -int bpb_detect(const uint8_t *bpb, const char *tag); -int guid_is0(const struct guid *guid); - -static inline int warn(const char *x) -{ - return fprintf(stderr, "WARN: %s\n", x); -} - -static inline int error(const char *x) -{ - return fprintf(stderr, "ERR: %s\n", x); -} - -static inline int crit(const char *x) -{ - return fprintf(stderr, "CRIT: %s @%s:%d\n", x, __FILE__, __LINE__); -} - -#define critm() crit("Malloc failure.") - -#endif - -/* vim: set ts=8 sts=4 sw=4 noet: */ diff --git a/com32/include/syslinux/partiter.h b/com32/include/syslinux/partiter.h new file mode 100644 index 0000000..a48f8d6 --- /dev/null +++ b/com32/include/syslinux/partiter.h @@ -0,0 +1,119 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin + * Copyright 2010 Shao Miller + * Copyright 2010-2015 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.h + * + * Provides disk / partition iteration. + */ + +#ifndef COM32_CHAIN_PARTITER_H +#define COM32_CHAIN_PARTITER_H + +#include <stdint.h> +#include <syslinux/disk.h> + +/* status */ + +enum {PI_ERRLOAD = -31, PI_INSANE, PI_OK = 0, PI_DONE}; + +/* flags */ + +enum {PIF_STEPALL = 1, PIF_PREFMBR = 2, PIF_STRICT = 4, PIF_STRICTER = 8, PIF_GPTHCRC = 16, PIF_GPTLCRC = 32}; + +struct itertype; +struct part_iter; + +struct itertype { + void (*dtor)(struct part_iter *); + int (*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 abs_lba; + uint64_t length; + int index0; /* including holes, from -1 (disk, then parts from 0) */ + int index; /* excluding holes, from 0 (disk, then parts from 1), -1 means hole, if PIF_STEPALL is set */ + int flags; /* flags, see #defines above */ + int status; /* current status, see enums above */ + struct disk_info di; + union { + struct { + uint32_t disk_sig; /* 32bit disk signature as stored in MBR */ + + uint32_t bebr_lba; /* absolute lba of base extended partition */ + uint32_t bebr_siz; /* size of base extended partition */ + + uint32_t cebr_lba; /* absolute lba of curr ext. partition */ + uint32_t cebr_siz; /* size of curr ext. partition */ + uint32_t nebr_lba; /* absolute lba of next ext. partition */ + uint32_t nebr_siz; /* size of next ext. partition */ + + int bebr_index0; /* index of (0-3) of base ext. part., -1 if not present in MBR */ + int logskipcnt; /* how many logical holes were skipped */ + } dos; + struct { + 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; + }; +}; + +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 flags); +void pi_del(struct part_iter **); + +/* inline virtuals */ +static inline int pi_next(struct part_iter *iter) +{ + return iter->type->next(iter); +} + +static inline void pi_dtor(struct part_iter *iter) +{ + iter->type->dtor(iter); +} + +#endif + +/* vim: set ts=8 sts=4 sw=4 noet: */ diff --git a/com32/include/syslinux/utility.h b/com32/include/syslinux/utility.h new file mode 100644 index 0000000..e2667a0 --- /dev/null +++ b/com32/include/syslinux/utility.h @@ -0,0 +1,76 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin + * Copyright 2010 Shao Miller + * Copyright 2010-2015 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. + * + * ----------------------------------------------------------------------- */ + +#ifndef COM32_CHAIN_UTILITY_H +#define COM32_CHAIN_UTILITY_H + +#include <stdint.h> +#include <stdio.h> +#include <syslinux/disk.h> +#include <syslinux/movebits.h> +#include <klibc/compiler.h> + +/* most (all ?) bpb "types" known to humankind as of 2012 */ +enum {bpbUNK, bpbV20, bpbV30, bpbV32, bpbV34, bpbV40, bpbVNT, bpbV70, bpbEXF}; + +/* see utility.c for details */ +enum {L2C_CNUL, L2C_CADD, L2C_CMAX}; + +/* first usable and first unusable offsets */ +#define dosmin ((addr_t)0x500u) +#define dosmax ((addr_t)(*(uint16_t *) 0x413 << 10)) + +void wait_key(void); +void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, int mode); +uint32_t get_file_lba(const char *filename); +int drvoff_detect(int type); +int bpb_detect(const uint8_t *bpb, const char *tag); +int guid_is0(const struct guid *guid); + +static inline int warn(const char *x) +{ + return fprintf(stderr, "WARN: %s\n", x); +} + +static __unusedfunc int error(const char *x) +{ + return fprintf(stderr, "ERR: %s\n", x); +} + +static inline int crit(const char *x) +{ + return fprintf(stderr, "CRIT: %s @%s:%d\n", x, __FILE__, __LINE__); +} + +#define critm() crit("Malloc failure.") + +#endif + +/* vim: set ts=8 sts=4 sw=4 noet: */ diff --git a/com32/lib/syslinux/partiter.c b/com32/lib/syslinux/partiter.c new file mode 100644 index 0000000..3ae2583 --- /dev/null +++ b/com32/lib/syslinux/partiter.c @@ -0,0 +1,726 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin + * Copyright 2010 Shao Miller + * Copyright 2010-2015 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 <syslinux/partiter.h> +#include <syslinux/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)) + +/* virtual forwards */ + +static void pi_dtor_(struct part_iter *); +static int pi_next_(struct part_iter *); +static int pi_dos_next(struct part_iter *); +static int pi_gpt_next(struct part_iter *); + +/* vtab and types */ + +static struct itertype types[] = { + [0] = { + .dtor = &pi_dtor_, + .next = &pi_dos_next, +}, [1] = { + .dtor = &pi_dtor_, + .next = &pi_gpt_next, +}, [2] = { + .dtor = &pi_dtor_, + .next = &pi_next_, +}}; + +const struct itertype * const typedos = types; +const struct itertype * const typegpt = types+1; +const struct itertype * const typeraw = types+2; + +/* pi_dtor_() - common/raw iterator cleanup */ +static void pi_dtor_(struct part_iter *iter) +{ + /* syslinux's free is null resilient */ + free(iter->data); +} + +/* pi_ctor() - common/raw iterator initialization */ +static int pi_ctor(struct part_iter *iter, + const struct disk_info *di, int flags +) +{ + memcpy(&iter->di, di, sizeof *di); + iter->flags = flags; + iter->index0 = -1; + iter->length = di->lbacnt; + + iter->type = typeraw; + return 0; +} + +/* pi_dos_ctor() - MBR/EBR iterator specific initialization */ +static int pi_dos_ctor(struct part_iter *iter, + const struct disk_info *di, int flags, + const struct disk_dos_mbr *mbr +) +{ + if (pi_ctor(iter, di, flags)) + return -1; + + if (!(iter->data = malloc(sizeof *mbr))) { + critm(); + goto bail; + } + + memcpy(iter->data, mbr, sizeof *mbr); + + iter->dos.bebr_index0 = -1; + iter->dos.disk_sig = mbr->disk_sig; + + iter->type = typedos; + return 0; +bail: + pi_dtor_(iter); + return -1; +} + +/* pi_gpt_ctor() - GPT iterator specific initialization */ +static int pi_gpt_ctor(struct part_iter *iter, + const struct disk_info *di, int flags, + const struct disk_gpt_header *gpth, const struct disk_gpt_part_entry *gptl +) +{ + uint64_t siz; + + if (pi_ctor(iter, di, flags)) + return -1; + + siz = (uint64_t)gpth->part_count * gpth->part_size; + + if (!(iter->data = malloc((size_t)siz))) { + critm(); + goto bail; + } + + memcpy(iter->data, gptl, (size_t)siz); + + iter->gpt.pe_count = (int)gpth->part_count; + iter->gpt.pe_size = (int)gpth->part_size; + iter->gpt.ufirst = gpth->lba_first_usable; + iter->gpt.ulast = gpth->lba_last_usable; + + memcpy(&iter->gpt.disk_guid, &gpth->disk_guid, sizeof gpth->disk_guid); + memcpy(&iter->gpt.part_guid, &gpth->disk_guid, sizeof gpth->disk_guid); + + iter->type = typegpt; + return 0; +bail: + pi_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("The 1st EBR entry must be data or empty."); + return -1; + } + + if (!(iter->flags & PIF_STRICT)) + return 0; + + 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->dos.nebr_siz) { + + error("Logical partition (in EBR) with invalid offset and/or length."); + 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("The 2nd EBR entry must be extended or empty."); + return -1; + } + + if (!(iter->flags & PIF_STRICT)) + return 0; + + 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->dos.bebr_siz) { + + error("Extended partition (EBR) with invalid offset and/or length."); + 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 (!(iter->flags & PIF_STRICT)) + return 0; + + if (!dp->start_lba || + !dp->length || + !sane(dp->start_lba, dp->length) || + ((iter->flags & PIF_STRICTER) && (dp->start_lba + dp->length > iter->di.lbacnt))) { + error("Primary partition (in MBR) with invalid offset and/or length."); + 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->gpt.pe_size); + + if (guid_is0(&gp->type)) + return 0; + + if (!(iter->flags & PIF_STRICT)) + return 0; + + if (gp->lba_first < iter->gpt.ufirst || + gp->lba_last > iter->gpt.ulast) { + error("LBA sectors of GPT partition are beyond the range allowed in GPT header."); + return -1; + } + + return 0; +} + +static int 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; + return -1; + } + + if (ost_is_ext(dp->ostype)) { + if (iter->dos.bebr_index0 >= 0) { + error("More than 1 extended partition."); + iter->status = PI_INSANE; + return -1; + } + /* record base EBR index */ + iter->dos.bebr_index0 = iter->index0; + } + if (!ost_is_nondata(dp->ostype) || (iter->flags & PIF_STEPALL)) { + *lba = dp->start_lba; + *_dp = dp; + break; + } + } + + return 0; +} + +static int prep_base_ebr(struct part_iter *iter) +{ + struct disk_dos_part_entry *dp; + + if (iter->dos.bebr_index0 < 0) /* if we don't have base extended partition at all */ + return -1; + else if (!iter->dos.bebr_lba) { /* if not initialized yet */ + dp = ((struct disk_dos_mbr *)iter->data)->table + iter->dos.bebr_index0; + + iter->dos.bebr_lba = dp->start_lba; + iter->dos.bebr_siz = dp->length; + + iter->dos.nebr_lba = dp->start_lba; + iter->dos.nebr_siz = dp->length; + + iter->index0--; + } + return 0; +} + +static int 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) < 0) { + iter->status = PI_DONE; + return -1; + } + + while (++iter->index0 < 1024 && iter->dos.nebr_lba) { + free(iter->data); + if (!(iter->data + disk_read_sectors(&iter->di, iter->dos.nebr_lba, 1))) { + error("Couldn't load EBR."); + iter->status = PI_ERRLOAD; + return -1; + } + + /* check sanity of loaded data */ + if (notsane_logical(iter) || notsane_extended(iter)) { + iter->status = PI_INSANE; + return -1; + } + + dp = ((struct disk_dos_mbr *)iter->data)->table; + + iter->dos.cebr_lba = iter->dos.nebr_lba; + iter->dos.cebr_siz = iter->dos.nebr_siz; + + /* setup next frame values */ + if (dp[1].ostype) { + iter->dos.nebr_lba = iter->dos.bebr_lba + dp[1].start_lba; + iter->dos.nebr_siz = dp[1].length; + } else { + iter->dos.nebr_lba = 0; + iter->dos.nebr_siz = 0; + } + + if (!dp[0].ostype) + iter->dos.logskipcnt++; + + if (dp[0].ostype || (iter->flags & PIF_STEPALL)) { + *lba = dp[0].start_lba ? iter->dos.cebr_lba + dp[0].start_lba : 0; + *_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 PIF_STEPALL flag is set, we will never + * reach this place. + */ + } + iter->status = PI_DONE; + return -1; +} + +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->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->gpt.part_label[i] = (char)orig_lab[i]; + } + iter->gpt.part_label[PI_GPTLABSIZE/2] = 0; +} + +static int valid_crc(uint32_t crc, const uint8_t *buf, unsigned int siz) +{ + return crc == crc32(crc32(0, NULL, 0), buf, siz); +} + +static int valid_crc_gpth(struct disk_gpt_header *gh, int flags) +{ + uint32_t crc, crcc; + + if (!(flags & PIF_GPTHCRC)) + return 1; + + crc = gh->chksum; + gh->chksum = 0; + crcc = crc32(crc32(0, NULL, 0), (const uint8_t *)gh, gh->hdr_size); + gh->chksum = crc; + return crc == crcc; +} + +static int valid_crc_gptl(const struct disk_gpt_header *gh, const struct disk_gpt_part_entry *gl, int flags) +{ + uint32_t crcc; + + if (!(flags & PIF_GPTLCRC)) + return 1; + + crcc = crc32(crc32(0, NULL, 0), (const uint8_t *)gl, gh->part_size * gh->part_count); + return gh->table_chksum == crcc; +} + +static int pi_next_(struct part_iter *iter) +{ + iter->status = PI_DONE; + return iter->status; +} + +static int pi_dos_next(struct part_iter *iter) +{ + uint32_t abs_lba = 0; + struct disk_dos_part_entry *dos_part = NULL; + + if (iter->status) + return iter->status; + + /* look for primary partitions */ + if (iter->index0 < 4 && + dos_next_mbr(iter, &abs_lba, &dos_part) < 0) + return iter->status; + + /* look for logical partitions */ + if (iter->index0 >= 4 && + dos_next_ebr(iter, &abs_lba, &dos_part) < 0) + return iter->status; + + /* + * note special index handling: + * in case PIF_STEPALL is set - this makes the index consistent with + * non-PIF_STEPALL iterators + */ + + if (!dos_part->ostype) + iter->index = -1; + else + iter->index = iter->index0 + 1 - iter->dos.logskipcnt; + iter->abs_lba = abs_lba; + iter->length = dos_part->length; + iter->record = (char *)dos_part; + +#ifdef DEBUG + disk_dos_part_dump(dos_part); +#endif + + return iter->status; +} + +static int pi_gpt_next(struct part_iter *iter) +{ + const struct disk_gpt_part_entry *gpt_part = NULL; + + if (iter->status) + return iter->status; + + while (++iter->index0 < iter->gpt.pe_count) { + gpt_part = (const struct disk_gpt_part_entry *) + (iter->data + iter->index0 * iter->gpt.pe_size); + + if (notsane_gpt(iter)) { + iter->status = PI_INSANE; + return iter->status; + } + + if (!guid_is0(&gpt_part->type) || (iter->flags & PIF_STEPALL)) + break; + } + /* no more partitions ? */ + if (iter->index0 == iter->gpt.pe_count) { + iter->status = PI_DONE; + return iter->status; + } + /* gpt_part is guaranteed to be valid here */ + iter->index = iter->index0 + 1; + iter->abs_lba = gpt_part->lba_first; + iter->length = gpt_part->lba_last - gpt_part->lba_first + 1; + iter->record = (char *)gpt_part; + memcpy(&iter->gpt.part_guid, &gpt_part->uid, sizeof(struct guid)); + gpt_conv_label(iter); + +#ifdef DEBUG + disk_gpt_part_dump(gpt_part); +#endif + + return iter->status; +} + +static struct part_iter *pi_alloc(void) +{ + struct part_iter *iter; + if (!(iter = malloc(sizeof *iter))) + critm(); + else + memset(iter, 0, sizeof *iter); + return iter; +} + +/* pi_del() - delete iterator */ +void pi_del(struct part_iter **_iter) +{ + if(!_iter || !*_iter) + return; + pi_dtor(*_iter); + free(*_iter); + *_iter = NULL; +} + +static int notsane_gpt_hdr(const struct disk_info *di, const struct disk_gpt_header *gpth, int flags) +{ + 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 */ + uint64_t gpt_sec; /* secondary gpt header */ + + if (!(flags & PIF_STRICT)) + return 0; + + if (gpth->lba_alt < gpth->lba_cur) + gpt_sec = gpth->lba_cur; + else + gpt_sec = gpth->lba_alt; + 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). + */ + if (gpt_loff < 2 || !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 && gpt_loff <= gpth->lba_last_usable) || + gpt_loff + gpt_lcnt > gpt_sec || + ((flags & PIF_STRICTER) && (gpt_sec >= di->lbacnt)) || + gpth->part_size < sizeof(struct disk_gpt_part_entry)) + return -1; + + return 0; +} + +static void try_gpt_we(const char *str, int sec) +{ + if (sec) + error(str); + else + warn(str); +} + +static struct disk_gpt_header *try_gpt_hdr(const struct disk_info *di, int sec, int flags) +{ + const char *desc = sec ? "backup" : "primary"; + uint64_t gpt_cur = sec ? di->lbacnt - 1 : 1; + struct disk_gpt_header *gpth; + char errbuf[96]; + + gpth = disk_read_sectors(di, gpt_cur, 1); + if (!gpth) { + sprintf(errbuf, "Unable to read %s GPT header.", desc); + goto out; + } + if(!valid_crc_gpth(gpth, flags)) { + sprintf(errbuf, "Invalid checksum of %s GPT header.", desc); + goto out; + } + if(notsane_gpt_hdr(di, gpth, flags)) { + sprintf(errbuf, "Checksum of %s GPT header is valid, but values fail sanity checks.", desc); + goto out; + } + return gpth; +out: + try_gpt_we(errbuf, sec); + free(gpth); + return NULL; +} + +static struct disk_gpt_part_entry *try_gpt_list(const struct disk_info *di, const struct disk_gpt_header *gpth, int alt, int flags) +{ + int pri = gpth->lba_cur < gpth->lba_alt; + const char *desc = alt ? "alternative" : "main"; + struct disk_gpt_part_entry *gptl; + char errbuf[64]; + uint32_t gpt_lcnt; /* size of GPT partition in sectors */ + uint64_t gpt_loff; /* offset to GPT partition list in sectors */ + + gpt_lcnt = (gpth->part_size * gpth->part_count + di->bps - 1) / di->bps; + if (!alt) { + /* prefer header value for partition table if not asking for alternative */ + gpt_loff = gpth->lba_table; + } else { + /* try to read alternative, we have to calculate its position */ + if (!pri) + gpt_loff = gpth->lba_alt + 1; + else + gpt_loff = gpth->lba_alt - gpt_lcnt; + } + + gptl = disk_read_sectors(di, gpt_loff, gpt_lcnt); + if (!gptl) { + sprintf(errbuf, "Unable to read %s GPT partition list.", desc); + goto out; + } + if (!valid_crc_gptl(gpth, gptl, flags)) { + sprintf(errbuf, "Invalid checksum of %s GPT partition list.", desc); + goto out; + } + return gptl; +out: + try_gpt_we(errbuf, alt); + free(gptl); + return NULL; +} + +/* pi_begin() - validate and and get proper iterator for a disk described by di */ +struct part_iter *pi_begin(const struct disk_info *di, int flags) +{ + int isgpt = 0, ret = -1; + struct part_iter *iter; + struct disk_dos_mbr *mbr = NULL; + struct disk_gpt_header *gpth = NULL; + struct disk_gpt_part_entry *gptl = NULL; + + /* Preallocate iterator */ + if (!(iter = pi_alloc())) + goto out; + + /* Read MBR */ + if (!(mbr = disk_read_sectors(di, 0, 1))) { + error("Unable to read the first disk sector."); + goto out; + } + + /* Check for MBR magic */ + if (mbr->sig != disk_mbr_sig_magic) { + warn("No MBR magic, treating disk as raw."); + /* looks like RAW */ + ret = pi_ctor(iter, di, flags); + goto out; + } + + /* Check for GPT protective MBR */ + for (size_t i = 0; i < 4; i++) + isgpt |= (mbr->table[i].ostype == 0xEE); + isgpt = isgpt && !(flags & PIF_PREFMBR); + + /* Try to read GPT header */ + if (isgpt) { + gpth = try_gpt_hdr(di, 0, flags); + if (!gpth) + /* + * this read might fail if bios reports different disk size (different vm/pc) + * not much we can do here to avoid it + */ + gpth = try_gpt_hdr(di, 1, flags); + if (!gpth) + goto out; + } + + if (gpth && gpth->rev.uint32 == 0x00010000 && + !memcmp(gpth->sig, disk_gpt_sig_magic, sizeof gpth->sig)) { + /* looks like GPT v1.0 */ +#ifdef DEBUG + dprintf("Looks like a GPT v1.0 disk.\n"); + disk_gpt_header_dump(gpth); +#endif + gptl = try_gpt_list(di, gpth, 0, flags); + if (!gptl) + gptl = try_gpt_list(di, gpth, 1, flags); + if (!gptl) + goto out; + + /* looks like GPT */ + ret = pi_gpt_ctor(iter, di, flags, gpth, gptl); + } else { + /* looks like MBR */ + ret = pi_dos_ctor(iter, di, flags, mbr); + } +out: + if (ret < 0) { + free(iter); + iter = NULL; + } + free(mbr); + free(gpth); + free(gptl); + + return iter; +} + +/* vim: set ts=8 sts=4 sw=4 noet: */ diff --git a/com32/lib/syslinux/utility.c b/com32/lib/syslinux/utility.c new file mode 100644 index 0000000..ecf5a37 --- /dev/null +++ b/com32/lib/syslinux/utility.c @@ -0,0 +1,256 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin + * Copyright 2010 Shao Miller + * Copyright 2010-2015 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. + * + * ----------------------------------------------------------------------- */ + +#include <com32.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <string.h> +#include <fs.h> +#include <syslinux/disk.h> +#include <syslinux/pmapi.h> +#include <syslinux/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", + [8] = "exFAT", +}; + +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)); +} + +int guid_is0(const struct guid *guid) +{ + return + !(guid->data1 || + guid->data2 || + guid->data3 || + guid->data4); +} + +/* + * mode explanation: + * + * cnul - "strict" mode, never returning higher value than obtained from cbios + * cadd - if the disk is larger than reported geometry /and/ if the geometry has + * less cylinders than 1024 - it means that the total size is somewhere + * between cs and cs+1; in this particular case, we bump the cs to be able + * to return matching chs triplet + * cmax - assume we can use any cylinder value + * + * by default cadd seems most reasonable, giving consistent results with e.g. + * sfdisk's behavior + */ +void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, int 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) { + if (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 = (lba % ss) + 1; + 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) +{ + struct com32_filedata fd; + uint32_t lba = 0; + int size = 65536; + char *buf; + + buf = lmalloc(size); + if (!buf) + return 0; + + /* Put the filename in the bounce buffer */ + strlcpy(buf, filename, size); + + if (open_file(buf, O_RDONLY, &fd) <= 0) { + goto fail; /* Filename not found */ + } + + /* Since the first member is the LBA, we simply cast */ + lba = *((uint32_t *) MK_PTR(0, fd.handle)); + + /* Call comapi_close() to free the structure */ + close_file(fd.handle); + +fail: + lfree(buf); + return lba; +} + +/* drive offset detection */ +int drvoff_detect(int type) +{ + if (bpbV40 <= type && type <= bpbVNT) { + return 0x24; + } else if (type == bpbV70) { + return 0x40; + } else if (type == bpbEXF) { + return 0x6F; + } + + 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; + + /* exFAT mess first (media descriptor is 0 here) */ + if (!memcmp(sec + 0x03, "EXFAT ", 8)) { + rev = bpbEXF; + goto out; + } + + /* 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/mk/lib.mk b/mk/lib.mk index ceb95bd..c56d3e3 100644 --- a/mk/lib.mk +++ b/mk/lib.mk @@ -106,7 +106,7 @@ LIBOTHER_OBJS = \ pci/writeb.o pci/writew.o pci/writel.o \ \ sys/x86_init_fpu.o math/pow.o math/strtod.o \ - syslinux/disk.o \ + syslinux/disk.o syslinux/utility.o syslinux/partiter.o \ \ syslinux/setup_data.o -- 2.1.0
Paulo Alcantara
2015-Jul-22 23:27 UTC
[syslinux] [PULL 2/8] core: MultiFS infrastructure added.
From: "Raphael S. Carvalho" <raphael.scarv at gmail.com> MULTIFS SYNTAX: (hd[disk number],[partition number])/path/to/file The meaning of this_fs was changed to improve the flexibility of the support. Now, this_fs means the file system being currently used. root_fs was created to save the context of the main file system (where ldlinux.sys lives in). get_fs_info is a function pointer that will be later hooked to a function from ldlinux.c32. get_fs_info is expected to return a fs_info structure given the MultiFS path. Cc: Gene Cumm <gene.cumm at gmail.com> Signed-off-by: Raphael S. Carvalho <raphael.scarv at gmail.com> Signed-off-by: Paulo Alcantara <pcacjr at zytor.com> --- core/fs/cache.c | 2 +- core/fs/diskio.c | 28 ++++++++++++++----- core/fs/diskio_bios.c | 40 ++++++++++++++------------ core/fs/fs.c | 22 +++++++++++---- core/fs/readdir.c | 9 +++++- core/include/multifs.h | 61 ++++++++++++++++++++++++++++++++++++++++ core/multifs.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 206 insertions(+), 32 deletions(-) create mode 100644 core/include/multifs.h create mode 100644 core/multifs.c diff --git a/core/fs/cache.c b/core/fs/cache.c index 8da75bc..31a5db3 100644 --- a/core/fs/cache.c +++ b/core/fs/cache.c @@ -15,7 +15,7 @@ * the block size, which is 512 byte for FAT fs of the current * implementation since the block(cluster) size in FAT is a bit big. */ -void cache_init(struct device *dev, int block_size_shift) +__export void cache_init(struct device *dev, int block_size_shift) { struct cache *prev, *cur; char *data = dev->cache_data; diff --git a/core/fs/diskio.c b/core/fs/diskio.c index e9a4c1d..94cc351 100644 --- a/core/fs/diskio.c +++ b/core/fs/diskio.c @@ -21,14 +21,28 @@ void getoneblk(struct disk *disk, char *buf, block_t block, int block_size) /* * Initialize the device structure. */ -struct device * device_init(void *args) +__export struct device *device_init(void *args) { - static struct device dev; + struct device *dev; - dev.disk = firmware->disk_init(args); - dev.cache_size = 128*1024; - dev.cache_data = malloc(dev.cache_size); - dev.cache_init = 0; /* Explicitly set cache as uninitialized */ + dev = malloc(sizeof(struct device)); + if (!dev) + return NULL; - return &dev; + dev->disk = firmware->disk_init(args); + if (!dev->disk) + goto out; + + dev->cache_size = 128*1024; + dev->cache_data = malloc(dev->cache_size); + if (!dev->cache_data) + goto out_disk; + dev->cache_init = 0; + + return dev; +out_disk: + free(dev->disk); +out: + free(dev); + return NULL; } diff --git a/core/fs/diskio_bios.c b/core/fs/diskio_bios.c index 7feb7fc..621896f 100644 --- a/core/fs/diskio_bios.c +++ b/core/fs/diskio_bios.c @@ -287,7 +287,7 @@ static int edd_rdwr_sectors(struct disk *disk, void *buf, struct disk *bios_disk_init(void *private) { - static struct disk disk; + struct disk *disk; struct bios_disk_private *priv = (struct bios_disk_private *)private; com32sys_t *regs = priv->regs; static __lowmem struct edd_disk_params edd_params; @@ -302,6 +302,10 @@ struct disk *bios_disk_init(void *private) int sector_size; unsigned int hard_max_transfer; + disk = malloc(sizeof(struct disk)); + if (!disk) + return NULL; + memset(&ireg, 0, sizeof ireg); ireg.edx.b[0] = devno; @@ -319,18 +323,18 @@ struct disk *bios_disk_init(void *private) hard_max_transfer = 63; /* CBIOS parameters */ - disk.h = bsHeads; - disk.s = bsSecPerTrack; + disk->h = bsHeads; + disk->s = bsSecPerTrack; if ((int8_t)devno < 0) { /* Get hard disk geometry from BIOS */ - + ireg.eax.b[1] = 0x08; __intcall(0x13, &ireg, &oreg); - + if (!(oreg.eflags.l & EFLAGS_CF)) { - disk.h = oreg.edx.b[1] + 1; - disk.s = oreg.ecx.b[0] & 63; + disk->h = oreg.edx.b[1] + 1; + disk->s = oreg.ecx.b[0] & 63; } } @@ -374,24 +378,24 @@ struct disk *bios_disk_init(void *private) } - disk.disk_number = devno; - disk.sector_size = sector_size; - disk.sector_shift = ilog2(sector_size); - disk.part_start = part_start; - disk.secpercyl = disk.h * disk.s; - disk.rdwr_sectors = ebios ? edd_rdwr_sectors : chs_rdwr_sectors; + disk->disk_number = devno; + disk->sector_size = sector_size; + disk->sector_shift = ilog2(sector_size); + disk->part_start = part_start; + disk->secpercyl = disk->h * disk->s; + disk->rdwr_sectors = ebios ? edd_rdwr_sectors : chs_rdwr_sectors; if (!MaxTransfer || MaxTransfer > hard_max_transfer) MaxTransfer = hard_max_transfer; - disk.maxtransfer = MaxTransfer; + disk->maxtransfer = MaxTransfer; dprintf("disk %02x cdrom %d type %d sector %u/%u offset %llu limit %u\n", - devno, cdrom, ebios, sector_size, disk.sector_shift, - part_start, disk.maxtransfer); + devno, cdrom, ebios, sector_size, disk->sector_shift, + part_start, disk->maxtransfer); - disk.private = private; - return &disk; + disk->private = private; + return disk; } void pm_fs_init(com32sys_t *regs) diff --git a/core/fs/fs.c b/core/fs/fs.c index 4161848..a5d8db4 100644 --- a/core/fs/fs.c +++ b/core/fs/fs.c @@ -10,9 +10,14 @@ #include "dev.h" #include "fs.h" #include "cache.h" +#include "multifs.h" -/* The currently mounted filesystem */ -__export struct fs_info *this_fs = NULL; /* Root filesystem */ +/* root_fs means the file system where ldlinux.sys lives in. */ +__export struct fs_info *root_fs = NULL; +/* this_fs means the file system being currently used. */ +__export struct fs_info *this_fs = NULL; +/* export p_ops to be used outside the core */ +__export const struct fs_ops **p_ops = NULL; /* Actual file structures (we don't have malloc yet...) */ __export struct file files[MAX_OPEN]; @@ -345,6 +350,9 @@ __export int open_file(const char *name, int flags, struct com32_filedata *filed dprintf("open_file %s\n", name); + if (switch_fs(&name)) + return -1; + mangle_name(mangled_name, name); rv = searchdir(mangled_name, flags); @@ -362,6 +370,9 @@ __export int open_file(const char *name, int flags, struct com32_filedata *filed filedata->blocklg2 = SECTOR_SHIFT(file->fs); filedata->handle = rv; + restore_fs(); + restore_chdir_start(); + return rv; } @@ -403,6 +414,7 @@ void fs_init(const struct fs_ops **ops, void *priv) /* Default name for the root directory */ fs.cwd_name[0] = '/'; + p_ops = ops; while ((blk_shift < 0) && *ops) { /* set up the fs stucture */ @@ -428,7 +440,7 @@ void fs_init(const struct fs_ops **ops, void *priv) while (1) ; } - this_fs = &fs; + root_fs = this_fs = &fs; /* initialize the cache only if it wasn't already initialized * by the fs driver */ @@ -443,8 +455,8 @@ void fs_init(const struct fs_ops **ops, void *priv) } if (fs.fs_ops->chdir_start) { - if (fs.fs_ops->chdir_start() < 0) - printf("Failed to chdir to start directory\n"); + if (fs.fs_ops->chdir_start() < 0) + printf("Failed to chdir to start directory\n"); } SectorShift = fs.sector_shift; diff --git a/core/fs/readdir.c b/core/fs/readdir.c index 546a704..2a1efde 100644 --- a/core/fs/readdir.c +++ b/core/fs/readdir.c @@ -4,6 +4,7 @@ #include <sys/dirent.h> #include "fs.h" #include "core.h" +#include "multifs.h" /* * Open a directory @@ -13,6 +14,9 @@ __export DIR *opendir(const char *path) int rv; struct file *file; + if (switch_fs(&path)) + return NULL; + rv = searchdir(path, O_RDONLY|O_DIRECTORY); if (rv < 0) return NULL; @@ -24,6 +28,9 @@ __export DIR *opendir(const char *path) return NULL; } + restore_fs(); + restore_chdir_start(); + return (DIR *)file; } @@ -35,7 +42,7 @@ __export struct dirent *readdir(DIR *dir) static struct dirent buf; struct file *dd_dir = (struct file *)dir; int rv = -1; - + if (dd_dir) { if (dd_dir->fs->fs_ops->readdir) { rv = dd_dir->fs->fs_ops->readdir(dd_dir, &buf); diff --git a/core/include/multifs.h b/core/include/multifs.h new file mode 100644 index 0000000..861ca97 --- /dev/null +++ b/core/include/multifs.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com> + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef MULTIFS_H +#define MULTIFS_H + +/* + * MULTIFS SYNTAX: + * (hd[disk number],[partition number])/path/to/file + * + * E.G.: (hd0,1)/dir/file means /dir/file at partition 1 of the disk 0. + * Disk and Partition numbering starts from 0 and 1 respectivelly. + */ +#include "fs.h" + +/* + * root_fs means the file system where ldlinux.sys lives in. + * this_fs means the file system being currently used. + */ +extern struct fs_info *this_fs, *root_fs; + +/* + * Set this_fs back to root_fs, + * otherwise unexpected behavior may occurs. + */ +static inline void restore_fs(void) +{ + this_fs = root_fs; +} + +/* + * Basically restores the cwd of the underlying fs. + */ +static inline void restore_chdir_start(void) +{ + if (this_fs->fs_ops->chdir_start) { + if (this_fs->fs_ops->chdir_start() < 0) + printf("Failed to chdir to start directory\n"); + } +} + +typedef struct fs_info *(*get_fs_info_t)(const char **); +extern int switch_fs(const char **); + +#endif /* MULTIFS_H */ diff --git a/core/multifs.c b/core/multifs.c new file mode 100644 index 0000000..8951ef7 --- /dev/null +++ b/core/multifs.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com> + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <klibc/compiler.h> +#include <stdio.h> +#include <assert.h> +#include "multifs.h" + +static get_fs_info_t get_fs_info = NULL; + +/* + * Enable MultiFS support + * This function is called from ldlinux.c32 to enable MultiFS support. + * + * @addr: address of the get_fs_info function from ldlinux.c32. + */ +__export void enable_multifs(get_fs_info_t addr) +{ + if (addr) { + get_fs_info = addr; + dprintf("MultiFS: set get_fs_info to %p\n", get_fs_info); + } +} + +/* + * The request is considered MultiFS if the path starts + * with an open parentheses. + * + * @ret: Upon success, set this_fs to the fs where the underlying file + * resides and returns 0. Upon failure, returns -1; + */ +int switch_fs(const char **path) +{ + struct fs_info *fs; + + assert(path && *path); + if ((*path)[0] != '(') { + /* If so, don't need to restore chdir */ + if (this_fs == root_fs) + return 0; + + fs = root_fs; + goto ret; + } + + if (__unlikely(!get_fs_info)) { + printf("MultiFS support is not enabled!\n"); + return -1; + } + + fs = get_fs_info(path); + if (!fs) { + dprintf("MultiFS: It wasn't possible to get the proper fs!\n"); + return -1; + } +ret: + this_fs = fs; + restore_chdir_start(); + return 0; +} -- 2.1.0
From: "Raphael S. Carvalho" <raphael.scarv at gmail.com> This patch finishes the MultiFS support. init_multifs gets called in the main (startup) function of ldlinux.c32, so MultiFS will be initialized automatically. init_multifs calls enable_multifs (lives in the core) to hook get_fs_info. Subsequent accesses will callback the get_fs_info living in ldlinux.c32. Cc: Gene Cumm <gene.cumm at gmail.com> Signed-off-by: Raphael S. Carvalho <raphael.scarv at gmail.com> Signed-off-by: Paulo Alcantara <pcacjr at zytor.com> --- com32/elflink/ldlinux/ldlinux.c | 2 + com32/include/syslinux/multifs_utils.h | 51 ++++++ com32/lib/syslinux/multifs_utils.c | 323 +++++++++++++++++++++++++++++++++ mk/lib.mk | 1 + 4 files changed, 377 insertions(+) create mode 100644 com32/include/syslinux/multifs_utils.h create mode 100644 com32/lib/syslinux/multifs_utils.c diff --git a/com32/elflink/ldlinux/ldlinux.c b/com32/elflink/ldlinux/ldlinux.c index 9b01dd3..97b4be2 100644 --- a/com32/elflink/ldlinux/ldlinux.c +++ b/com32/elflink/ldlinux/ldlinux.c @@ -303,6 +303,8 @@ __export int main(int argc __unused, char **argv) const char *cmdline; size_t count = 0; + init_multifs(); /* Init MultiFS support */ + ldlinux_console_init(); parse_configs(&argv[1]); diff --git a/com32/include/syslinux/multifs_utils.h b/com32/include/syslinux/multifs_utils.h new file mode 100644 index 0000000..90ef6d6 --- /dev/null +++ b/com32/include/syslinux/multifs_utils.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2012 Andre Ericson <de.ericson at gmail.com> + * Copyright (C) 2012 Paulo Cavalcanti <pcacjr at zytor.com> + * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com> + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef MULTIDISK_UTILS_H +#define MULTIDISK_UTILS_H + +#include <syslinux/partiter.h> +#include "fs.h" + +struct part_node { + int partition; + struct fs_info *fs; + struct part_node *next; +}; + +struct queue_head { + struct part_node *first; + struct part_node *last; +}; + +/* + * Needs to keep ROOT_FS_OPS after fs_init() + * to be used by multidisk + */ +extern const struct fs_ops **p_ops; + +/* + * Used to initialize MultiFS support + */ +extern void enable_multifs(void *); +extern void init_multifs(void); + +#endif /* MULTIDISK_UTILS_H */ diff --git a/com32/lib/syslinux/multifs_utils.c b/com32/lib/syslinux/multifs_utils.c new file mode 100644 index 0000000..d243ef2 --- /dev/null +++ b/com32/lib/syslinux/multifs_utils.c @@ -0,0 +1,323 @@ +/* + * Copyright (C) 2012 Andre Ericson <de.ericson at gmail.com> + * Copyright (C) 2012 Paulo Cavalcanti <pcacjr at zytor.com> + * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com> + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include <syslinux/multifs_utils.h> +#include "core.h" +#include "disk.h" +#include "cache.h" +#include "minmax.h" + +/* 0x80 - 0xFF + * BIOS limitation */ +#define DISK_ID_OFFSET 0x80 +#define DISKS_MAX 128 + +/* MaxTransfer for MultiFS access */ +#define MAX_TRANSFER 127 + +static struct queue_head *parts_info[DISKS_MAX]; + +/* + * Store info about the FS into a specific queue to be used later. + * + * @ret: 0 on success, -1 on failure. + */ +static int add_fs(struct fs_info *fs, uint8_t disk, uint8_t partition) +{ + struct queue_head *head = parts_info[disk]; + struct part_node *node; + + node = malloc(sizeof(struct part_node)); + if (!node) + return -1; + node->fs = fs; + node->next = NULL; + node->partition = partition; + + if (!head) { + head = malloc(sizeof(struct queue_head)); + if (!head) { + free(node); + return -1; + } + head->first = head->last = node; + parts_info[disk] = head; + return 0; + } + head->last->next = node; + head->last = node; + return 0; +} + +/* + * Check if the FS was previously allocated. + * + * @ret: return the fs on success, NULL on failure. + */ +static struct fs_info *get_fs(uint8_t disk, uint8_t partition) +{ + struct part_node *i; + + for (i = parts_info[disk]->first; i; i = i->next) { + if (i->partition == partition) + return i->fs; + } + return NULL; +} + +/* + * Attempt to find a partition based on drive and partition numbers. + * + * @ret: 0 on success, -1 on failure. + */ +static int find_partition(struct part_iter **_iter, struct disk_info *diskinfo, + int partition) +{ + struct part_iter *iter = NULL; + + if (!(iter = pi_begin(diskinfo, 0))) + return -1; + + do { + if (iter->index == partition) + break; + } while (!pi_next(iter)); + + if (iter->status) { + dprintf("MultiFS: Request disk/partition combination not found.\n"); + goto bail; + } + dprintf("MultiFS: found 0x%llx at idex: %i and partition %i\n", + iter->abs_lba, iter->index, partition); + + *_iter = iter; + return 0; +bail: + pi_del(&iter); + return -1; +} + +/* + * Get a number till the delimiter is found. + * + * @ret: addr to delimiter+1 on success, NULL on failure. + */ +static const char *get_num(const char *p, char delimiter, uint8_t *data) +{ + uint32_t n = 0; + + while (*p) { + if (*p < '0' || *p > '9') + break; + + n = (n * 10) + (*p - '0'); + p++; + + if (*p == delimiter) { + p++; /* Skip delimiter */ + *data = min(n, UINT8_MAX); /* Avoid overflow */ + return p; + } + } + return NULL; +} + +/* + * Parse MultiFS path. Syntax: + * (hd[disk number],[partition number])/path/to/file + * + * @ret: Returns syntax validity. + */ +static int parse_multifs_path(const char **path, uint8_t *hdd, + uint8_t *partition) +{ + const char *p = *path; + static const char *cwd = "."; + + *hdd = *partition = 0; + p++; /* Skip open parentheses */ + + /* Get hd number (Range: 0 - (DISKS_MAX - 1)) */ + if (*p != 'h' || *(p + 1) != 'd') + return -1; + + p += 2; /* Skip 'h' and 'd' */ + p = get_num(p, ',', hdd); + if (!p) + return -1; + if (*hdd >= DISKS_MAX) { + printf("MultiFS: hdd is out of range: 0-%d\n", DISKS_MAX - 1); + return -1; + } + + /* Get partition number (Range: 0 - 0xFF) */ + p = get_num(p, ')', partition); + if (!p) + return -1; + + if (*p == '\0') { + /* Assume it's a cwd request */ + p = cwd; + } + + *path = p; + dprintf("MultiFS: hdd: %u partition: %u path: %s\n", + *hdd, *partition, *path); + return 0; +} + +/* + * Set up private struct based on paramaters. + * This structure will be used later to set up a device + * to (disk x,partition y). + * + * @devno: Device number (range: 0 - (DISKS_MAX - 1)). + * @part_start: Start LBA. + * @bsHeads: Number of heads. + * @bsSecPerTrack: Sectors per track. + */ +static void *get_private(uint8_t devno, uint64_t part_start, + uint16_t bsHeads, uint16_t bsSecPerTrack) +{ + static com32sys_t regs; + static struct bios_disk_private priv; + + priv.regs = ®s; + + regs.edx.b[0] = devno; + regs.edx.b[1] = 0; // TODO: cdrom ... always 0??? + regs.ecx.l = part_start & 0xFFFFFFFF; + regs.ebx.l = part_start >> 32; + regs.esi.w[0] = bsHeads; + regs.edi.w[0] = bsSecPerTrack; + regs.ebp.l = MAX_TRANSFER; // TODO: should it be pre-defined??? + + return (void *) &priv; +} + +/* + * 1) Set up a new device based on the disk and the partition. + * 2) Find which file system is installed in this device. + * 3) Set up fs_info based on the fs, add to queue, and return it. + * 4) Subsequent accesses to the same disk and partition will get + * fs_info from the queue. + * + * It handles the important stuff to get the MultiFS support working. + */ +static struct fs_info *get_fs_info(const char **path) +{ + const struct fs_ops **ops; + struct fs_info *fsp; + struct disk_info diskinfo; + struct part_iter *iter = NULL; + struct device *dev = NULL; + void *private; + int blk_shift = -1; + uint8_t disk_devno, hdd, partition; + + if (parse_multifs_path(path, &hdd, &partition)) { + printf("MultiFS: Syntax invalid: %s\n", *path); + return NULL; + } + + fsp = get_fs(hdd, partition - 1); + if (fsp) + return fsp; + + fsp = malloc(sizeof(struct fs_info)); + if (!fsp) + return NULL; + + disk_devno = DISK_ID_OFFSET + hdd; + if (disk_get_params(disk_devno, &diskinfo)) + goto bail; + + if (find_partition(&iter, &diskinfo, partition)) { + printf("MultiFS: Failed to get disk/partition: %s\n", *path); + goto bail; + } + private = get_private(disk_devno, iter->abs_lba, diskinfo.head, + diskinfo.spt); + + /* Default name for the root directory */ + fsp->cwd_name[0] = '/'; + fsp->cwd_name[1] = '\0'; + + ops = p_ops; + while ((blk_shift < 0) && *ops) { + /* set up the fs stucture */ + fsp->fs_ops = *ops; + + /* + * This boldly assumes that we don't mix FS_NODEV filesystems + * with FS_DEV filesystems... + */ + if (fsp->fs_ops->fs_flags & FS_NODEV) { + fsp->fs_dev = NULL; + } else { + if (!dev) { + dev = device_init(private); + if (!dev) + goto bail; + } + fsp->fs_dev = dev; + } + /* invoke the fs-specific init code */ + blk_shift = fsp->fs_ops->fs_init(fsp); + ops++; + } + if (blk_shift < 0) { + printf("MultiFS: No valid file system found!\n"); + goto free_dev; + } + + /* add fs_info into hdd queue */ + if (add_fs(fsp, hdd, partition - 1)) + goto free_dev; + + /* initialize the cache */ + if (fsp->fs_dev && fsp->fs_dev->cache_data) + cache_init(fsp->fs_dev, blk_shift); + + /* start out in the root directory */ + if (fsp->fs_ops->iget_root) { + fsp->root = fsp->fs_ops->iget_root(fsp); + fsp->cwd = get_inode(fsp->root); + } + + return fsp; +free_dev: + free(dev->disk); + free(dev->cache_data); + free(dev); +bail: + free(fsp); + return NULL; +} + +/* + * Initialize MultiFS support + */ +void init_multifs(void) +{ + enable_multifs(&get_fs_info); + dprintf("MultiFS support was enabled successfully!\n"); +} diff --git a/mk/lib.mk b/mk/lib.mk index c56d3e3..d059ad5 100644 --- a/mk/lib.mk +++ b/mk/lib.mk @@ -107,6 +107,7 @@ LIBOTHER_OBJS = \ \ sys/x86_init_fpu.o math/pow.o math/strtod.o \ syslinux/disk.o syslinux/utility.o syslinux/partiter.o \ + syslinux/multifs_utils.o \ \ syslinux/setup_data.o -- 2.1.0
Paulo Alcantara
2015-Jul-22 23:27 UTC
[syslinux] [PULL 4/8] ldlinux/kernel: contemplate multifs path syntax
The initramfs path in the configuration file might come with multifs path syntax (e.g. (hdX,Y)/initramfs...), so we must include it so multifs will know how fs ops to switch to. Cc: Gene Cumm <gene.cumm at gmail.com> Signed-off-by: Paulo Alcantara <pcacjr at zytor.com> --- com32/elflink/ldlinux/kernel.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/com32/elflink/ldlinux/kernel.c b/com32/elflink/ldlinux/kernel.c index f3ba37f..f9738a7 100644 --- a/com32/elflink/ldlinux/kernel.c +++ b/com32/elflink/ldlinux/kernel.c @@ -88,6 +88,15 @@ int new_linux_kernel(char *okernel, char *ocmdline) temp++; /* Skip = or , */ p = temp; + if (*p == '(') { + /* handle MultiFS path syntax: e.g. (hdX,Y)... */ + do { + p++; + n++; + } while (*p && *p != ')'); + p++; + n++; + } while (*p != ' ' && *p != ',' && *p) { p++; n++; -- 2.1.0
The system firmware will expose device handles of all MBR/GPT partitions which support BlockIo and/or DiskIo protocols, so find them and pass through MultiFS driver. Even in EFI environment ldlinux will be loaded up, so to avoid initialise multifs twice call init_multifs() earlier. Cc: Gene Cumm <gene.cumm at gmail.com> Signed-off-by: Paulo Alcantara <pcacjr at zytor.com> --- com32/elflink/ldlinux/execute.c | 3 + com32/elflink/ldlinux/ldlinux.c | 2 - core/fs/fs.c | 1 - core/fs/readdir.c | 1 - core/multifs.c | 1 - efi/diskio.c | 32 +++-- efi/main.c | 22 ++- efi/multifs_utils.c | 296 ++++++++++++++++++++++++++++++++++++++++ efi/multifs_utils.h | 52 +++++++ 9 files changed, 387 insertions(+), 23 deletions(-) create mode 100644 efi/multifs_utils.c create mode 100644 efi/multifs_utils.h diff --git a/com32/elflink/ldlinux/execute.c b/com32/elflink/ldlinux/execute.c index 653c880..da89305 100644 --- a/com32/elflink/ldlinux/execute.c +++ b/com32/elflink/ldlinux/execute.c @@ -30,6 +30,7 @@ #include <syslinux/movebits.h> #include <syslinux/config.h> #include <syslinux/boot.h> +#include <syslinux/multifs_utils.h> const struct image_types image_boot_types[] = { { "localboot", IMAGE_TYPE_LOCALBOOT }, @@ -147,6 +148,8 @@ __export void execute(const char *cmdline, uint32_t type, bool sysappend) if (!config) goto out; + init_multifs(); + realpath(config, kernel, FILENAME_MAX); /* If we got anything on the command line, do a chdir */ diff --git a/com32/elflink/ldlinux/ldlinux.c b/com32/elflink/ldlinux/ldlinux.c index 97b4be2..9b01dd3 100644 --- a/com32/elflink/ldlinux/ldlinux.c +++ b/com32/elflink/ldlinux/ldlinux.c @@ -303,8 +303,6 @@ __export int main(int argc __unused, char **argv) const char *cmdline; size_t count = 0; - init_multifs(); /* Init MultiFS support */ - ldlinux_console_init(); parse_configs(&argv[1]); diff --git a/core/fs/fs.c b/core/fs/fs.c index a5d8db4..1bea6b5 100644 --- a/core/fs/fs.c +++ b/core/fs/fs.c @@ -371,7 +371,6 @@ __export int open_file(const char *name, int flags, struct com32_filedata *filed filedata->handle = rv; restore_fs(); - restore_chdir_start(); return rv; } diff --git a/core/fs/readdir.c b/core/fs/readdir.c index 2a1efde..07fae5d 100644 --- a/core/fs/readdir.c +++ b/core/fs/readdir.c @@ -29,7 +29,6 @@ __export DIR *opendir(const char *path) } restore_fs(); - restore_chdir_start(); return (DIR *)file; } diff --git a/core/multifs.c b/core/multifs.c index 8951ef7..aafce57 100644 --- a/core/multifs.c +++ b/core/multifs.c @@ -71,6 +71,5 @@ int switch_fs(const char **path) } ret: this_fs = fs; - restore_chdir_start(); return 0; } diff --git a/efi/diskio.c b/efi/diskio.c index d6a160e..64014fe 100644 --- a/efi/diskio.c +++ b/efi/diskio.c @@ -43,7 +43,7 @@ static int efi_rdwr_sectors(struct disk *disk, void *buf, struct disk *efi_disk_init(void *private) { - static struct disk disk; + struct disk *disk; struct efi_disk_private *priv = (struct efi_disk_private *)private; EFI_HANDLE handle = priv->dev_handle; EFI_BLOCK_IO *bio; @@ -60,33 +60,37 @@ struct disk *efi_disk_init(void *private) if (status != EFI_SUCCESS) return NULL; + disk = malloc(sizeof(*disk)); + if (!disk) + return NULL; + /* * XXX Do we need to map this to a BIOS disk number? */ - disk.disk_number = bio->Media->MediaId; + disk->disk_number = bio->Media->MediaId; - disk.sector_size = bio->Media->BlockSize; - disk.rdwr_sectors = efi_rdwr_sectors; - disk.sector_shift = ilog2(disk.sector_size); + disk->sector_size = bio->Media->BlockSize; + disk->rdwr_sectors = efi_rdwr_sectors; + disk->sector_shift = ilog2(disk->sector_size); - dprintf("sector_size=%d, disk_number=%d\n", disk.sector_size, - disk.disk_number); + dprintf("sector_size=%d, disk_number=%d\n", disk->sector_size, + disk->disk_number); priv->bio = bio; priv->dio = dio; - disk.private = private; + disk->private = private; #if 0 - disk.part_start = part_start; - disk.secpercyl = disk.h * disk.s; + disk->part_start = part_start; + disk->secpercyl = disk->h * disk->s; - disk.maxtransfer = MaxTransfer; + disk->maxtransfer = MaxTransfer; dprintf("disk %02x cdrom %d type %d sector %u/%u offset %llu limit %u\n", - media_id, cdrom, ebios, sector_size, disk.sector_shift, - part_start, disk.maxtransfer); + media_id, cdrom, ebios, sector_size, disk->sector_shift, + part_start, disk->maxtransfer); #endif - return &disk; + return disk; } diff --git a/efi/main.c b/efi/main.c index 9c3c2f2..a165b05 100644 --- a/efi/main.c +++ b/efi/main.c @@ -15,6 +15,7 @@ #include "efi.h" #include "fio.h" #include "version.h" +#include "multifs_utils.h" __export uint16_t PXERetry; __export char copyright_str[] = "Copyright (C) 2011-" YEAR_STR "\n"; @@ -1199,6 +1200,11 @@ static inline void syslinux_register_efi(void) extern void init(void); extern const struct fs_ops vfat_fs_ops; +extern const struct fs_ops ext2_fs_ops; +extern const struct fs_ops ntfs_fs_ops; +extern const struct fs_ops xfs_fs_ops; +extern const struct fs_ops btrfs_fs_ops; +extern const struct fs_ops ufs_fs_ops; extern const struct fs_ops pxe_fs_ops; char free_high_memory[4096]; @@ -1206,6 +1212,11 @@ char free_high_memory[4096]; extern char __bss_start[]; extern char __bss_end[]; +static const struct fs_ops *fs_ops[] = { + &vfat_fs_ops, &ext2_fs_ops, &ntfs_fs_ops, &xfs_fs_ops, &btrfs_fs_ops, + &ufs_fs_ops, &pxe_fs_ops, NULL, +}; + static void efi_setcwd(CHAR16 *dp) { CHAR16 *c16; @@ -1242,7 +1253,6 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *table) EFI_PXE_BASE_CODE *pxe; EFI_LOADED_IMAGE *info; EFI_STATUS status = EFI_SUCCESS; - const struct fs_ops *ops[] = { NULL, NULL }; unsigned long len = (unsigned long)__bss_end - (unsigned long)__bss_start; static struct efi_disk_private priv; SIMPLE_INPUT_INTERFACE *in; @@ -1279,10 +1289,14 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *table) } efi_derivative(SYSLINUX_FS_SYSLINUX); - ops[0] = &vfat_fs_ops; + status = init_multifs(); + if (EFI_ERROR(status)) { + Print(L"Failed to initialise multifs support: %r\n", + status); + goto out; + } } else { efi_derivative(SYSLINUX_FS_PXELINUX); - ops[0] = &pxe_fs_ops; image_device_handle = info->DeviceHandle; } @@ -1303,7 +1317,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *table) */ efi_setcwd(DevicePathToStr(info->FilePath)); - fs_init(ops, (void *)&priv); + fs_init(fs_ops, (void *)&priv); /* * There may be pending user input that wasn't processed by diff --git a/efi/multifs_utils.c b/efi/multifs_utils.c new file mode 100644 index 0000000..a4e3ff9 --- /dev/null +++ b/efi/multifs_utils.c @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2015 Paulo Alcantara <pcacjr at zytor.com> + * Copyright (C) 2012 Andre Ericson <de.ericson at gmail.com> + * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com> + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include <fs.h> +#include <ilog2.h> +#include <disk.h> + +#include "cache.h" +#include "minmax.h" +#include "multifs_utils.h" +#include "efi.h" + +#define DISKS_MAX 0xff + +static EFI_HANDLE *_logical_parts = NULL; +static unsigned int _logical_parts_no = 0; +static struct queue_head *parts_info[DISKS_MAX]; + +/* Find all BlockIo device handles which is a logical partition */ +static EFI_STATUS find_all_logical_parts(void) +{ + EFI_STATUS status; + unsigned long len = 0; + EFI_HANDLE *handles = NULL; + unsigned long i; + EFI_BLOCK_IO *bio; + + if (_logical_parts) { + status = EFI_SUCCESS; + goto out; + } + + status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, + &BlockIoProtocol, NULL, &len, NULL); + if (EFI_ERROR(status) && status != EFI_BUFFER_TOO_SMALL) + goto out; + + handles = malloc(len); + if (!handles) { + status = EFI_OUT_OF_RESOURCES; + goto out; + } + + _logical_parts = malloc(len); + if (!_logical_parts) { + status = EFI_OUT_OF_RESOURCES; + goto out_free; + } + + status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, + &BlockIoProtocol, NULL, &len, + (void **)handles); + if (EFI_ERROR(status)) + goto out_free; + + for (i = 0; i < len / sizeof(EFI_HANDLE); i++) { + status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i], + &BlockIoProtocol, (void **)&bio); + if (EFI_ERROR(status)) + goto out_free; + if (bio->Media->LogicalPartition) { + _logical_parts[_logical_parts_no++] = handles[i]; + } + } + + free(handles); + return status; + +out_free: + if (handles) + free(handles); + if (_logical_parts) + free(_logical_parts); +out: + return status; +} + +static inline EFI_HANDLE get_logical_part(unsigned int partno) +{ + if (!_logical_parts || partno > _logical_parts_no) + return NULL; + return _logical_parts[partno - 1]; +} + +static int add_fs(struct fs_info *fs, uint8_t disk, uint8_t partition) +{ + struct queue_head *head = parts_info[disk]; + struct part_node *node; + + node = malloc(sizeof(struct part_node)); + if (!node) + return -1; + node->fs = fs; + node->next = NULL; + node->partition = partition; + + if (!head) { + head = malloc(sizeof(struct queue_head)); + if (!head) { + free(node); + return -1; + } + head->first = head->last = node; + parts_info[disk] = head; + return 0; + } + head->last->next = node; + head->last = node; + return 0; +} + +static struct fs_info *get_fs(uint8_t disk, uint8_t partition) +{ + struct part_node *i; + + for (i = parts_info[disk]->first; i; i = i->next) { + if (i->partition == partition) + return i->fs; + } + return NULL; +} + +static EFI_HANDLE find_partition(unsigned int diskno, unsigned int partno) +{ + return get_logical_part(partno); +} + +static const char *get_num(const char *p, char delimiter, unsigned int *data) +{ + uint32_t n = 0; + + while (*p) { + if (*p < '0' || *p > '9') + break; + n = (n * 10) + (*p - '0'); + p++; + if (*p == delimiter) { + p++; /* skip delimiter */ + *data = min(n, UINT8_MAX); /* avoid overflow */ + return p; + } + } + return NULL; +} + +static int parse_multifs_path(const char **path, unsigned int *hdd, + unsigned int *partition) +{ + const char *p = *path; + static const char *cwd = "."; + + *hdd = *partition = 0; + p++; /* Skip open parentheses */ + + /* Get hd number (Range: 0 - (DISKS_MAX - 1)) */ + if (*p != 'h' || *(p + 1) != 'd') + return -1; + + p += 2; /* Skip 'h' and 'd' */ + p = get_num(p, ',', hdd); + if (!p) + return -1; + if (*hdd >= DISKS_MAX) { + printf("MultiFS: hdd is out of range: 0-%d\n", DISKS_MAX - 1); + return -1; + } + + /* Get partition number (Range: 0 - 0xFF) */ + p = get_num(p, ')', partition); + if (!p) + return -1; + + if (*p == '\0') { + /* Assume it's a cwd request */ + p = cwd; + } + + *path = p; + dprintf("MultiFS: hdd: %u partition: %u path: %s\n", + *hdd, *partition, *path); + return 0; +} + +static inline void *get_private(EFI_HANDLE lpart) +{ + static struct efi_disk_private priv; + priv.dev_handle = lpart; + return (void *)&priv; +} + +static struct fs_info *get_fs_info(const char **path) +{ + const struct fs_ops **ops; + struct fs_info *fsp; + EFI_HANDLE dh; + struct device *dev = NULL; + void *private; + int blk_shift = -1; + unsigned int hdd, partition; + + if (parse_multifs_path(path, &hdd, &partition)) { + return NULL; + } + + fsp = get_fs(hdd, partition - 1); + if (fsp) + return fsp; + + fsp = malloc(sizeof(struct fs_info)); + if (!fsp) + return NULL; + + dh = find_partition(hdd, partition); + if (!dh) + goto bail; + dprintf("\nMultiFS: found partition %d\n", partition); + private = get_private(dh); + + /* set default name for the root directory */ + fsp->cwd_name[0] = '/'; + fsp->cwd_name[1] = '\0'; + + ops = p_ops; + while ((blk_shift < 0) && *ops) { + /* set up the fs stucture */ + fsp->fs_ops = *ops; + + /* + * This boldly assumes that we don't mix FS_NODEV filesystems + * with FS_DEV filesystems... + */ + if (fsp->fs_ops->fs_flags & FS_NODEV) { + fsp->fs_dev = NULL; + } else { + if (!dev) { + dev = device_init(private); + if (!dev) + goto bail; + } + fsp->fs_dev = dev; + } + /* invoke the fs-specific init code */ + blk_shift = fsp->fs_ops->fs_init(fsp); + ops++; + } + if (blk_shift < 0) { + dprintf("MultiFS: No valid file system found!\n"); + goto free_dev; + } + + if (add_fs(fsp, hdd, partition - 1)) + goto free_dev; + if (fsp->fs_dev && fsp->fs_dev->cache_data && !fsp->fs_dev->cache_init) + cache_init(fsp->fs_dev, blk_shift); + if (fsp->fs_ops->iget_root) { + fsp->root = fsp->fs_ops->iget_root(fsp); + fsp->cwd = get_inode(fsp->root); + } + return fsp; + +free_dev: + free(dev->disk); + free(dev->cache_data); + free(dev); +bail: + free(fsp); + return NULL; +} + +EFI_STATUS init_multifs(void) +{ + EFI_STATUS status; + + status = find_all_logical_parts(); + enable_multifs(get_fs_info); + dprintf("MultiFS: initialised\n"); + + return status; +} diff --git a/efi/multifs_utils.h b/efi/multifs_utils.h new file mode 100644 index 0000000..7ae5b43 --- /dev/null +++ b/efi/multifs_utils.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2012-2015 Paulo Alcantara <pcacjr at zytor.com> + * Copyright (C) 2012 Andre Ericson <de.ericson at gmail.com> + * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com> + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef MULTIDISK_UTILS_H +#define MULTIDISK_UTILS_H + +#include <fs.h> + +#include "efi.h" + +struct part_node { + int partition; + struct fs_info *fs; + struct part_node *next; +}; + +struct queue_head { + struct part_node *first; + struct part_node *last; +}; + +/* + * Needs to keep ROOT_FS_OPS after fs_init() + * to be used by multidisk + */ +extern const struct fs_ops **p_ops; + +/* + * Used to initialize MultiFS support + */ +extern void enable_multifs(void *); +extern EFI_STATUS init_multifs(void); + +#endif /* MULTIDISK_UTILS_H */ -- 2.1.0
Paulo Alcantara
2015-Jul-22 23:27 UTC
[syslinux] [PULL 6/8] sys/common: handle multifs paths in findpath()
By looking for PATH entries and trying to find multifs-like paths does not make any sense. Only try to open it once. Cc: Gene Cumm <gene.cumm at gmail.com> Signed-off-by: Paulo Alcantara <pcacjr at zytor.com> --- com32/lib/sys/module/common.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/com32/lib/sys/module/common.c b/com32/lib/sys/module/common.c index 05a27e8..73155ad 100644 --- a/com32/lib/sys/module/common.c +++ b/com32/lib/sys/module/common.c @@ -59,12 +59,17 @@ void print_elf_symbols(struct elf_module *module) { FILE *findpath(char *name) { + int is_multifs_path = 0; + char *p; struct path_entry *entry; char path[FILENAME_MAX]; FILE *f; + /* NOTE: multifs already handle both relative and absolute paths */ + if ((p = strchr(name, ')')) && strchr(p, ')')) + is_multifs_path = 1; /* assume multifs-like path */ f = fopen(name, "rb"); /* for full path */ - if (f) + if (f || is_multifs_path) return f; list_for_each_entry(entry, &PATH, list) { -- 2.1.0
Paulo Alcantara
2015-Jul-22 23:27 UTC
[syslinux] [PULL 7/8] multifs: add support for both UEFI and BIOS firmware
The previous MultiFS implementation only supported BIOS, so this patch basically keeps common code in a single place and separate firmware-specific functions that'll be exposed later. A generic interface has been added to be able to switch among different FSes regardless which firmware is being used. Although, each implementation has to implement init() and get_is_info() functions, pass through multifs_ops structure and they'll get called in starting of ldlinux. Cc: Gene Cumm <gene.cumm at gmail.com> Signed-off-by: Paulo Alcantara <pcacjr at zytor.com> --- com32/elflink/ldlinux/execute.c | 3 - com32/elflink/ldlinux/ldlinux.c | 9 + com32/include/syslinux/multifs_utils.h | 25 +-- com32/lib/syslinux/multifs_utils.c | 318 +++++---------------------------- core/bios.c | 11 ++ core/fs/fs.c | 4 +- core/fs/readdir.c | 4 +- core/include/multifs.h | 43 ++--- core/multifs.c | 214 ++++++++++++++++++---- core/multifs_bios.c | 75 ++++++++ efi/main.c | 18 +- efi/multifs.c | 162 +++++++++++++++++ efi/multifs_utils.c | 296 ------------------------------ 13 files changed, 514 insertions(+), 668 deletions(-) create mode 100644 core/multifs_bios.c create mode 100644 efi/multifs.c delete mode 100644 efi/multifs_utils.c diff --git a/com32/elflink/ldlinux/execute.c b/com32/elflink/ldlinux/execute.c index da89305..653c880 100644 --- a/com32/elflink/ldlinux/execute.c +++ b/com32/elflink/ldlinux/execute.c @@ -30,7 +30,6 @@ #include <syslinux/movebits.h> #include <syslinux/config.h> #include <syslinux/boot.h> -#include <syslinux/multifs_utils.h> const struct image_types image_boot_types[] = { { "localboot", IMAGE_TYPE_LOCALBOOT }, @@ -148,8 +147,6 @@ __export void execute(const char *cmdline, uint32_t type, bool sysappend) if (!config) goto out; - init_multifs(); - realpath(config, kernel, FILENAME_MAX); /* If we got anything on the command line, do a chdir */ diff --git a/com32/elflink/ldlinux/ldlinux.c b/com32/elflink/ldlinux/ldlinux.c index 9b01dd3..78da0e8 100644 --- a/com32/elflink/ldlinux/ldlinux.c +++ b/com32/elflink/ldlinux/ldlinux.c @@ -5,6 +5,7 @@ #include <string.h> #include <core.h> #include <fs.h> +#include <multifs.h> #include "cli.h" #include "console.h" #include "com32.h" @@ -13,6 +14,7 @@ #include "syslinux/adv.h" #include "syslinux/boot.h" #include "syslinux/config.h" +#include "syslinux/multifs_utils.h" #include <sys/module.h> @@ -292,6 +294,11 @@ static void __destructor close_console(void) close(i); } +void do_init_multifs(void) +{ + multifs_ops->init(bios_find_partition); +} + void ldlinux_console_init(void) { openconsole(&dev_stdcon_r, &dev_ansiserial_w); @@ -303,6 +310,8 @@ __export int main(int argc __unused, char **argv) const char *cmdline; size_t count = 0; + do_init_multifs(); + ldlinux_console_init(); parse_configs(&argv[1]); diff --git a/com32/include/syslinux/multifs_utils.h b/com32/include/syslinux/multifs_utils.h index 90ef6d6..4bf29a6 100644 --- a/com32/include/syslinux/multifs_utils.h +++ b/com32/include/syslinux/multifs_utils.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2012 Andre Ericson <de.ericson at gmail.com> - * Copyright (C) 2012 Paulo Cavalcanti <pcacjr at zytor.com> + * Copyright (C) 2012-2015 Paulo Alcantara <pcacjr at zytor.com> * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com> * * This program is free software; you can redistribute it and/or modify @@ -25,27 +25,8 @@ #include <syslinux/partiter.h> #include "fs.h" -struct part_node { - int partition; - struct fs_info *fs; - struct part_node *next; -}; +typedef void *(*bios_find_partition_t)(uint8_t, uint8_t); -struct queue_head { - struct part_node *first; - struct part_node *last; -}; - -/* - * Needs to keep ROOT_FS_OPS after fs_init() - * to be used by multidisk - */ -extern const struct fs_ops **p_ops; - -/* - * Used to initialize MultiFS support - */ -extern void enable_multifs(void *); -extern void init_multifs(void); +void *bios_find_partition(uint8_t diskno, uint8_t partno); #endif /* MULTIDISK_UTILS_H */ diff --git a/com32/lib/syslinux/multifs_utils.c b/com32/lib/syslinux/multifs_utils.c index d243ef2..1f15030 100644 --- a/com32/lib/syslinux/multifs_utils.c +++ b/com32/lib/syslinux/multifs_utils.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2012 Andre Ericson <de.ericson at gmail.com> - * Copyright (C) 2012 Paulo Cavalcanti <pcacjr at zytor.com> + * Copyright (C) 2012-2015 Paulo Alcantara <pcacjr at zytor.com> * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com> * * This program is free software; you can redistribute it and/or modify @@ -18,306 +18,74 @@ * Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#include <syslinux/multifs_utils.h> #include "core.h" +#include "fs.h" #include "disk.h" #include "cache.h" -#include "minmax.h" + +#include <syslinux/multifs_utils.h> /* 0x80 - 0xFF * BIOS limitation */ #define DISK_ID_OFFSET 0x80 -#define DISKS_MAX 128 /* MaxTransfer for MultiFS access */ #define MAX_TRANSFER 127 -static struct queue_head *parts_info[DISKS_MAX]; - -/* - * Store info about the FS into a specific queue to be used later. - * - * @ret: 0 on success, -1 on failure. - */ -static int add_fs(struct fs_info *fs, uint8_t disk, uint8_t partition) -{ - struct queue_head *head = parts_info[disk]; - struct part_node *node; - - node = malloc(sizeof(struct part_node)); - if (!node) - return -1; - node->fs = fs; - node->next = NULL; - node->partition = partition; - - if (!head) { - head = malloc(sizeof(struct queue_head)); - if (!head) { - free(node); - return -1; - } - head->first = head->last = node; - parts_info[disk] = head; - return 0; - } - head->last->next = node; - head->last = node; - return 0; -} - -/* - * Check if the FS was previously allocated. - * - * @ret: return the fs on success, NULL on failure. - */ -static struct fs_info *get_fs(uint8_t disk, uint8_t partition) +static void *get_private(uint8_t devno, uint64_t part_start, + uint16_t bsHeads, uint16_t bsSecPerTrack) { - struct part_node *i; + com32sys_t *regs; + struct bios_disk_private *priv; - for (i = parts_info[disk]->first; i; i = i->next) { - if (i->partition == partition) - return i->fs; + regs = malloc(sizeof(*regs)); + if (!regs) + return NULL; + memset(regs, 0, sizeof(*regs)); + + regs->edx.b[0] = devno; + regs->edx.b[1] = 0; /* XXX: cdrom ->->-> always 0? */ + regs->ecx.l = part_start & 0xFFFFFFFF; + regs->ebx.l = part_start >> 32; + regs->esi.w[0] = bsHeads; + regs->edi.w[0] = bsSecPerTrack; + regs->ebp.l = MAX_TRANSFER; /* XXX: should it be pre-defined? */ + + priv = malloc(sizeof(*priv)); + if (!priv) { + free(regs); + priv = NULL; + } else { + priv->regs = regs; } - return NULL; + return priv; } -/* - * Attempt to find a partition based on drive and partition numbers. - * - * @ret: 0 on success, -1 on failure. - */ -static int find_partition(struct part_iter **_iter, struct disk_info *diskinfo, - int partition) +void *bios_find_partition(uint8_t diskno, uint8_t partno) { + uint8_t disk_devno; struct part_iter *iter = NULL; + struct disk_info diskinfo; + + dprintf("%s: diskno %d partition %d\n", __func__, diskno, partno); - if (!(iter = pi_begin(diskinfo, 0))) - return -1; + disk_devno = DISK_ID_OFFSET + diskno; + if (disk_get_params(disk_devno, &diskinfo)) + return NULL; + if (!(iter = pi_begin(&diskinfo, 0))) + return NULL; do { - if (iter->index == partition) + if (iter->index == partno) break; } while (!pi_next(iter)); if (iter->status) { dprintf("MultiFS: Request disk/partition combination not found.\n"); - goto bail; - } - dprintf("MultiFS: found 0x%llx at idex: %i and partition %i\n", - iter->abs_lba, iter->index, partition); - - *_iter = iter; - return 0; -bail: - pi_del(&iter); - return -1; -} - -/* - * Get a number till the delimiter is found. - * - * @ret: addr to delimiter+1 on success, NULL on failure. - */ -static const char *get_num(const char *p, char delimiter, uint8_t *data) -{ - uint32_t n = 0; - - while (*p) { - if (*p < '0' || *p > '9') - break; - - n = (n * 10) + (*p - '0'); - p++; - - if (*p == delimiter) { - p++; /* Skip delimiter */ - *data = min(n, UINT8_MAX); /* Avoid overflow */ - return p; - } - } - return NULL; -} - -/* - * Parse MultiFS path. Syntax: - * (hd[disk number],[partition number])/path/to/file - * - * @ret: Returns syntax validity. - */ -static int parse_multifs_path(const char **path, uint8_t *hdd, - uint8_t *partition) -{ - const char *p = *path; - static const char *cwd = "."; - - *hdd = *partition = 0; - p++; /* Skip open parentheses */ - - /* Get hd number (Range: 0 - (DISKS_MAX - 1)) */ - if (*p != 'h' || *(p + 1) != 'd') - return -1; - - p += 2; /* Skip 'h' and 'd' */ - p = get_num(p, ',', hdd); - if (!p) - return -1; - if (*hdd >= DISKS_MAX) { - printf("MultiFS: hdd is out of range: 0-%d\n", DISKS_MAX - 1); - return -1; - } - - /* Get partition number (Range: 0 - 0xFF) */ - p = get_num(p, ')', partition); - if (!p) - return -1; - - if (*p == '\0') { - /* Assume it's a cwd request */ - p = cwd; - } - - *path = p; - dprintf("MultiFS: hdd: %u partition: %u path: %s\n", - *hdd, *partition, *path); - return 0; -} - -/* - * Set up private struct based on paramaters. - * This structure will be used later to set up a device - * to (disk x,partition y). - * - * @devno: Device number (range: 0 - (DISKS_MAX - 1)). - * @part_start: Start LBA. - * @bsHeads: Number of heads. - * @bsSecPerTrack: Sectors per track. - */ -static void *get_private(uint8_t devno, uint64_t part_start, - uint16_t bsHeads, uint16_t bsSecPerTrack) -{ - static com32sys_t regs; - static struct bios_disk_private priv; - - priv.regs = ®s; - - regs.edx.b[0] = devno; - regs.edx.b[1] = 0; // TODO: cdrom ... always 0??? - regs.ecx.l = part_start & 0xFFFFFFFF; - regs.ebx.l = part_start >> 32; - regs.esi.w[0] = bsHeads; - regs.edi.w[0] = bsSecPerTrack; - regs.ebp.l = MAX_TRANSFER; // TODO: should it be pre-defined??? - - return (void *) &priv; -} - -/* - * 1) Set up a new device based on the disk and the partition. - * 2) Find which file system is installed in this device. - * 3) Set up fs_info based on the fs, add to queue, and return it. - * 4) Subsequent accesses to the same disk and partition will get - * fs_info from the queue. - * - * It handles the important stuff to get the MultiFS support working. - */ -static struct fs_info *get_fs_info(const char **path) -{ - const struct fs_ops **ops; - struct fs_info *fsp; - struct disk_info diskinfo; - struct part_iter *iter = NULL; - struct device *dev = NULL; - void *private; - int blk_shift = -1; - uint8_t disk_devno, hdd, partition; - - if (parse_multifs_path(path, &hdd, &partition)) { - printf("MultiFS: Syntax invalid: %s\n", *path); - return NULL; - } - - fsp = get_fs(hdd, partition - 1); - if (fsp) - return fsp; - - fsp = malloc(sizeof(struct fs_info)); - if (!fsp) + pi_del(&iter); return NULL; - - disk_devno = DISK_ID_OFFSET + hdd; - if (disk_get_params(disk_devno, &diskinfo)) - goto bail; - - if (find_partition(&iter, &diskinfo, partition)) { - printf("MultiFS: Failed to get disk/partition: %s\n", *path); - goto bail; - } - private = get_private(disk_devno, iter->abs_lba, diskinfo.head, - diskinfo.spt); - - /* Default name for the root directory */ - fsp->cwd_name[0] = '/'; - fsp->cwd_name[1] = '\0'; - - ops = p_ops; - while ((blk_shift < 0) && *ops) { - /* set up the fs stucture */ - fsp->fs_ops = *ops; - - /* - * This boldly assumes that we don't mix FS_NODEV filesystems - * with FS_DEV filesystems... - */ - if (fsp->fs_ops->fs_flags & FS_NODEV) { - fsp->fs_dev = NULL; - } else { - if (!dev) { - dev = device_init(private); - if (!dev) - goto bail; - } - fsp->fs_dev = dev; - } - /* invoke the fs-specific init code */ - blk_shift = fsp->fs_ops->fs_init(fsp); - ops++; } - if (blk_shift < 0) { - printf("MultiFS: No valid file system found!\n"); - goto free_dev; - } - - /* add fs_info into hdd queue */ - if (add_fs(fsp, hdd, partition - 1)) - goto free_dev; - - /* initialize the cache */ - if (fsp->fs_dev && fsp->fs_dev->cache_data) - cache_init(fsp->fs_dev, blk_shift); - - /* start out in the root directory */ - if (fsp->fs_ops->iget_root) { - fsp->root = fsp->fs_ops->iget_root(fsp); - fsp->cwd = get_inode(fsp->root); - } - - return fsp; -free_dev: - free(dev->disk); - free(dev->cache_data); - free(dev); -bail: - free(fsp); - return NULL; -} - -/* - * Initialize MultiFS support - */ -void init_multifs(void) -{ - enable_multifs(&get_fs_info); - dprintf("MultiFS support was enabled successfully!\n"); + dprintf("MultiFS: found 0x%llx at index: %i and partition %i\n", + iter->abs_lba, iter->index, partno); + return get_private(disk_devno, iter->abs_lba, diskinfo.head, diskinfo.spt); } diff --git a/core/bios.c b/core/bios.c index 7fb37fe..0ce31df 100644 --- a/core/bios.c +++ b/core/bios.c @@ -1,6 +1,7 @@ #include <sys/ansi.h> #include <sys/io.h> #include <fs.h> +#include <multifs.h> #include <bios.h> #include <com32.h> #include <graphics.h> @@ -15,6 +16,7 @@ #include "core.h" __export struct firmware *firmware = NULL; +__export const struct multifs_ops *multifs_ops = NULL; extern struct ansi_ops bios_ansi_ops; @@ -713,7 +715,16 @@ struct firmware bios_fw = { .mem = &bios_mem_ops, }; +struct fs_info *bios_multifs_get_fs_info(const char **path); +extern void bios_multifs_init(void); + +const struct multifs_ops bios_multifs_ops = { + .get_fs_info = bios_multifs_get_fs_info, + .init = bios_multifs_init, +}; + void syslinux_register_bios(void) { firmware = &bios_fw; + multifs_ops = &bios_multifs_ops; } diff --git a/core/fs/fs.c b/core/fs/fs.c index 1bea6b5..4feb798 100644 --- a/core/fs/fs.c +++ b/core/fs/fs.c @@ -350,7 +350,7 @@ __export int open_file(const char *name, int flags, struct com32_filedata *filed dprintf("open_file %s\n", name); - if (switch_fs(&name)) + if (multifs_switch_fs(&name)) return -1; mangle_name(mangled_name, name); @@ -370,7 +370,7 @@ __export int open_file(const char *name, int flags, struct com32_filedata *filed filedata->blocklg2 = SECTOR_SHIFT(file->fs); filedata->handle = rv; - restore_fs(); + multifs_restore_fs(); return rv; } diff --git a/core/fs/readdir.c b/core/fs/readdir.c index 07fae5d..8acdd55 100644 --- a/core/fs/readdir.c +++ b/core/fs/readdir.c @@ -14,7 +14,7 @@ __export DIR *opendir(const char *path) int rv; struct file *file; - if (switch_fs(&path)) + if (multifs_switch_fs(&path)) return NULL; rv = searchdir(path, O_RDONLY|O_DIRECTORY); @@ -28,7 +28,7 @@ __export DIR *opendir(const char *path) return NULL; } - restore_fs(); + multifs_restore_fs(); return (DIR *)file; } diff --git a/core/include/multifs.h b/core/include/multifs.h index 861ca97..0d6bff1 100644 --- a/core/include/multifs.h +++ b/core/include/multifs.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com> + * Copyright (C) 2015 Paulo Alcantara <pcacjr at zytor.com> * * 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 @@ -20,6 +21,8 @@ #ifndef MULTIFS_H #define MULTIFS_H +#include "fs.h" + /* * MULTIFS SYNTAX: * (hd[disk number],[partition number])/path/to/file @@ -27,35 +30,21 @@ * E.G.: (hd0,1)/dir/file means /dir/file at partition 1 of the disk 0. * Disk and Partition numbering starts from 0 and 1 respectivelly. */ -#include "fs.h" - -/* - * root_fs means the file system where ldlinux.sys lives in. - * this_fs means the file system being currently used. - */ -extern struct fs_info *this_fs, *root_fs; -/* - * Set this_fs back to root_fs, - * otherwise unexpected behavior may occurs. - */ -static inline void restore_fs(void) -{ - this_fs = root_fs; -} +struct multifs_ops { + struct fs_info *(*get_fs_info)(const char **); + void (*init)(void *); +}; -/* - * Basically restores the cwd of the underlying fs. - */ -static inline void restore_chdir_start(void) -{ - if (this_fs->fs_ops->chdir_start) { - if (this_fs->fs_ops->chdir_start() < 0) - printf("Failed to chdir to start directory\n"); - } -} +extern struct fs_info *root_fs; +extern const struct fs_ops **p_ops; +extern const struct multifs_ops *multifs_ops; -typedef struct fs_info *(*get_fs_info_t)(const char **); -extern int switch_fs(const char **); +struct fs_info *multifs_get_fs(uint8_t diskno, uint8_t partno); +int multifs_parse_path(const char **path, uint8_t *diskno, uint8_t *partno); +int multifs_setup_fs_info(struct fs_info *fsp, uint8_t diskno, uint8_t partno, + void *priv); +void multifs_restore_fs(void); +int multifs_switch_fs(const char **path); #endif /* MULTIFS_H */ diff --git a/core/multifs.c b/core/multifs.c index aafce57..d979db6 100644 --- a/core/multifs.c +++ b/core/multifs.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com> + * Copyright (C) 2015 Paulo Alcantara <pcacjr at zytor.com> * * 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 @@ -17,58 +18,203 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include <klibc/compiler.h> #include <stdio.h> #include <assert.h> +#include <fs.h> +#include <ilog2.h> +#include <disk.h> +#include <cache.h> +#include <minmax.h> + #include "multifs.h" -static get_fs_info_t get_fs_info = NULL; +#define DISKS_MAX 0x7f -/* - * Enable MultiFS support - * This function is called from ldlinux.c32 to enable MultiFS support. - * - * @addr: address of the get_fs_info function from ldlinux.c32. - */ -__export void enable_multifs(get_fs_info_t addr) +struct part_node { + int partition; + struct fs_info *fs; + struct part_node *next; +}; + +struct queue_head { + struct part_node *first; + struct part_node *last; +}; + +static struct queue_head *parts_info[DISKS_MAX]; + +static int add_fs(struct fs_info *fs, uint8_t diskno, uint8_t partno) { - if (addr) { - get_fs_info = addr; - dprintf("MultiFS: set get_fs_info to %p\n", get_fs_info); + struct queue_head *head = parts_info[diskno]; + struct part_node *node; + + node = malloc(sizeof(struct part_node)); + if (!node) + return -1; + node->fs = fs; + node->next = NULL; + node->partition = partno; + + if (!head) { + head = malloc(sizeof(struct queue_head)); + if (!head) { + free(node); + return -1; + } + head->first = head->last = node; + parts_info[diskno] = head; + return 0; } + head->last->next = node; + head->last = node; + return 0; } -/* - * The request is considered MultiFS if the path starts - * with an open parentheses. - * - * @ret: Upon success, set this_fs to the fs where the underlying file - * resides and returns 0. Upon failure, returns -1; - */ -int switch_fs(const char **path) +struct fs_info *multifs_get_fs(uint8_t diskno, uint8_t partno) +{ + struct part_node *i; + + for (i = parts_info[diskno]->first; i; i = i->next) { + if (i->partition == partno) + return i->fs; + } + return NULL; +} + +static const char *get_num(const char *p, char delimiter, uint8_t *data) +{ + uint32_t n = 0; + + while (*p) { + if (*p < '0' || *p > '9') + break; + n = (n * 10) + (*p - '0'); + p++; + if (*p == delimiter) { + p++; /* skip delimiter */ + *data = min(n, UINT8_MAX); /* avoid overflow */ + return p; + } + } + return NULL; +} + +int multifs_parse_path(const char **path, uint8_t *diskno, uint8_t *partno) +{ + const char *p = *path; + static const char *cwd = "."; + + *diskno = *partno = 0; + p++; /* Skip open parentheses */ + + /* Get hd number (Range: 0 - (DISKS_MAX - 1)) */ + if (*p != 'h' || *(p + 1) != 'd') + return -1; + + p += 2; /* Skip 'h' and 'd' */ + p = get_num(p, ',', diskno); + if (!p) + return -1; + if (*diskno >= DISKS_MAX) { + printf("MultiFS: disk number is out of range: 0-%d\n", DISKS_MAX - 1); + return -1; + } + + /* Get partition number (Range: 0 - 0xFF) */ + p = get_num(p, ')', partno); + if (!p) + return -1; + + if (*p == '\0') { + /* Assume it's a cwd request */ + p = cwd; + } + + *path = p; + dprintf("MultiFS: disk: %u partition: %u path: %s\n", *diskno, *partno, + *path); + return 0; +} + +int multifs_setup_fs_info(struct fs_info *fsp, uint8_t diskno, uint8_t partno, + void *priv) +{ + const struct fs_ops **ops; + int blk_shift = -1; + struct device *dev = NULL; + + /* set default name for the root directory */ + fsp->cwd_name[0] = '/'; + fsp->cwd_name[1] = '\0'; + + ops = p_ops; + while ((blk_shift < 0) && *ops) { + /* set up the fs stucture */ + fsp->fs_ops = *ops; + + /* + * This boldly assumes that we don't mix FS_NODEV filesystems + * with FS_DEV filesystems... + */ + if (fsp->fs_ops->fs_flags & FS_NODEV) { + fsp->fs_dev = NULL; + } else { + if (!dev) { + dev = device_init(priv); + if (!dev) + return -1; + } + fsp->fs_dev = dev; + } + /* invoke the fs-specific init code */ + blk_shift = fsp->fs_ops->fs_init(fsp); + ops++; + } + if (blk_shift < 0) { + dprintf("%s: no valid file system found!\n", __func__); + goto out_free; + } + + if (add_fs(fsp, diskno, partno - 1)) + goto out_free; + if (fsp->fs_dev && fsp->fs_dev->cache_data) + cache_init(fsp->fs_dev, blk_shift); + if (fsp->fs_ops->iget_root) { + fsp->root = fsp->fs_ops->iget_root(fsp); + fsp->cwd = get_inode(fsp->root); + } + return 0; + +out_free: + free(dev->disk); + free(dev->cache_data); + free(dev); + return -1; +} + +void multifs_restore_fs(void) +{ + this_fs = root_fs; +} + +int multifs_switch_fs(const char **path) { struct fs_info *fs; assert(path && *path); if ((*path)[0] != '(') { - /* If so, don't need to restore chdir */ - if (this_fs == root_fs) - return 0; + /* If so, don't need to restore chdir */ + if (this_fs == root_fs) + return 0; - fs = root_fs; - goto ret; + fs = root_fs; + goto ret; } - if (__unlikely(!get_fs_info)) { - printf("MultiFS support is not enabled!\n"); - return -1; - } + fs = multifs_ops->get_fs_info(path); + if (!fs) + return -1; - fs = get_fs_info(path); - if (!fs) { - dprintf("MultiFS: It wasn't possible to get the proper fs!\n"); - return -1; - } ret: this_fs = fs; return 0; diff --git a/core/multifs_bios.c b/core/multifs_bios.c new file mode 100644 index 0000000..923773f --- /dev/null +++ b/core/multifs_bios.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012 Andre Ericson <de.ericson at gmail.com> + * Copyright (C) 2012-2015 Paulo Alcantara <pcacjr at zytor.com> + * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com> + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "core.h" +#include "fs.h" +#include "disk.h" +#include "cache.h" +#include "multifs.h" + +#include <syslinux/multifs_utils.h> + +/* MaxTransfer for MultiFS access */ +#define MAX_TRANSFER 127 + +static bios_find_partition_t find_partition = NULL; + +__export struct fs_info *bios_multifs_get_fs_info(const char **path) +{ + struct fs_info *fsp; + void *private; + uint8_t hdd, partition; + struct multifs_utils_part_info *pinfo; + int ret; + + if (multifs_parse_path(path, &hdd, &partition)) { + printf("MultiFS: Syntax invalid: %s\n", *path); + return NULL; + } + + fsp = multifs_get_fs(hdd, partition - 1); + if (fsp) + return fsp; + + fsp = malloc(sizeof(struct fs_info)); + if (!fsp) + return NULL; + + private = find_partition(hdd, partition); + if (!private) { + printf("MultiFS: Failed to get disk/partition: %s\n", *path); + goto bail; + } + ret = multifs_setup_fs_info(fsp, hdd, partition, private); + if (ret) { + goto bail; + } + return fsp; + +bail: + free(fsp); + return NULL; +} + +__export void bios_multifs_init(void *addr) +{ + find_partition = addr; + dprintf("%s: initialised MultiFS support\n", __func__); +} diff --git a/efi/main.c b/efi/main.c index a165b05..b2c8b0c 100644 --- a/efi/main.c +++ b/efi/main.c @@ -5,6 +5,7 @@ #include <codepage.h> #include <core.h> #include <fs.h> +#include <multifs.h> #include <com32.h> #include <syslinux/memscan.h> #include <syslinux/firmware.h> @@ -15,7 +16,6 @@ #include "efi.h" #include "fio.h" #include "version.h" -#include "multifs_utils.h" __export uint16_t PXERetry; __export char copyright_str[] = "Copyright (C) 2011-" YEAR_STR "\n"; @@ -132,6 +132,7 @@ void __cdecl core_farcall(uint32_t c, const com32sys_t *a, com32sys_t *b) __export struct firmware *firmware = NULL; __export void *__syslinux_adv_ptr; __export size_t __syslinux_adv_size; +__export const struct multifs_ops *multifs_ops = NULL; char core_xfer_buf[65536]; struct iso_boot_info { uint32_t pvd; /* LBA of primary volume descriptor */ @@ -1193,9 +1194,18 @@ struct firmware efi_fw = { .mem = &efi_mem_ops, }; +extern struct fs_info *efi_multifs_get_fs_info(const char **path); +extern void efi_multifs_init(void); + +const struct multifs_ops efi_multifs_ops = { + .get_fs_info = efi_multifs_get_fs_info, + .init = efi_multifs_init, +}; + static inline void syslinux_register_efi(void) { firmware = &efi_fw; + multifs_ops = &efi_multifs_ops; } extern void init(void); @@ -1289,12 +1299,6 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *table) } efi_derivative(SYSLINUX_FS_SYSLINUX); - status = init_multifs(); - if (EFI_ERROR(status)) { - Print(L"Failed to initialise multifs support: %r\n", - status); - goto out; - } } else { efi_derivative(SYSLINUX_FS_PXELINUX); image_device_handle = info->DeviceHandle; diff --git a/efi/multifs.c b/efi/multifs.c new file mode 100644 index 0000000..418d0c2 --- /dev/null +++ b/efi/multifs.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2015 Paulo Alcantara <pcacjr at zytor.com> + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include <fs.h> +#include <multifs.h> + +#include "efi.h" + +static EFI_HANDLE *logical_parts = NULL; +static unsigned int logical_parts_no = 0; + +/* Find all device handles which support EFI_BLOCK_IO_PROTOCOL and are logical + * partitions */ +static EFI_STATUS find_all_logical_parts(void) +{ + EFI_STATUS status; + unsigned long len = 0; + EFI_HANDLE *handles = NULL; + unsigned long i; + EFI_BLOCK_IO *bio; + + if (logical_parts) { + status = EFI_SUCCESS; + goto out; + } + + status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, + &BlockIoProtocol, NULL, &len, NULL); + if (EFI_ERROR(status) && status != EFI_BUFFER_TOO_SMALL) + goto out; + + handles = malloc(len); + if (!handles) { + status = EFI_OUT_OF_RESOURCES; + goto out; + } + + logical_parts = malloc(len); + if (!logical_parts) { + status = EFI_OUT_OF_RESOURCES; + goto out_free; + } + + status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, + &BlockIoProtocol, NULL, &len, + (void **)handles); + if (EFI_ERROR(status)) + goto out_free; + + for (i = 0; i < len / sizeof(EFI_HANDLE); i++) { + status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i], + &BlockIoProtocol, (void **)&bio); + if (EFI_ERROR(status)) + goto out_free; + if (bio->Media->LogicalPartition) { + logical_parts[logical_parts_no++] = handles[i]; + } + } + + free(handles); + return status; + +out_free: + if (handles) + free(handles); + if (logical_parts) + free(logical_parts); +out: + return status; +} + +static inline EFI_HANDLE get_logical_part(unsigned int partno) +{ + if (!logical_parts || partno > logical_parts_no) + return NULL; + return logical_parts[partno - 1]; +} + +static inline EFI_HANDLE find_device_handle(unsigned int diskno, + unsigned int partno) +{ + return get_logical_part(partno); +} + +static inline void *get_dev_info_priv(EFI_HANDLE lpart) +{ + static struct efi_disk_private priv; + priv.dev_handle = lpart; + return (void *)&priv; +} + +__export struct fs_info *efi_multifs_get_fs_info(const char **path) +{ + uint8_t diskno; + uint8_t partno; + struct fs_info *fsp; + EFI_HANDLE handle; + void *priv; + int ret; + + if (multifs_parse_path(path, &diskno, &partno)) + return NULL; + + fsp = multifs_get_fs(diskno, partno - 1); + if (fsp) + return fsp; + + fsp = malloc(sizeof(*fsp)); + if (!fsp) + return NULL; + + handle = find_device_handle(diskno, partno); + if (!handle) + goto free_fsp; + dprintf("%s: found partition %d\n", __func__, partno); + + priv = get_dev_info_priv(handle); + if (!priv) + goto free_fsp; + + ret = multifs_setup_fs_info(fsp, diskno, partno, priv); + if (ret) { + dprintf("%s: failed to set up fs info\n", __func__); + goto free_dev_info; + } + return fsp; + +free_dev_info: + free(priv); +free_fsp: + free(fsp); + return NULL; +} + +__export void efi_multifs_init(void *addr __attribute__((unused))) +{ + EFI_STATUS status; + + status = find_all_logical_parts(); + if (EFI_ERROR(status)) { + printf("%s: failed to locate device handles of logical partitions\n", + __func__); + printf("%s: EFI status code: 0x%08X\n", __func__, status); + return; + } + dprintf("%s: initialised MultiFS support\n", __func__); +} diff --git a/efi/multifs_utils.c b/efi/multifs_utils.c deleted file mode 100644 index a4e3ff9..0000000 --- a/efi/multifs_utils.c +++ /dev/null @@ -1,296 +0,0 @@ -/* - * Copyright (c) 2015 Paulo Alcantara <pcacjr at zytor.com> - * Copyright (C) 2012 Andre Ericson <de.ericson at gmail.com> - * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com> - * - * 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; either version 2 of the License, or - * (at your option) any later version. - * - * 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; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ -#include <fs.h> -#include <ilog2.h> -#include <disk.h> - -#include "cache.h" -#include "minmax.h" -#include "multifs_utils.h" -#include "efi.h" - -#define DISKS_MAX 0xff - -static EFI_HANDLE *_logical_parts = NULL; -static unsigned int _logical_parts_no = 0; -static struct queue_head *parts_info[DISKS_MAX]; - -/* Find all BlockIo device handles which is a logical partition */ -static EFI_STATUS find_all_logical_parts(void) -{ - EFI_STATUS status; - unsigned long len = 0; - EFI_HANDLE *handles = NULL; - unsigned long i; - EFI_BLOCK_IO *bio; - - if (_logical_parts) { - status = EFI_SUCCESS; - goto out; - } - - status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, - &BlockIoProtocol, NULL, &len, NULL); - if (EFI_ERROR(status) && status != EFI_BUFFER_TOO_SMALL) - goto out; - - handles = malloc(len); - if (!handles) { - status = EFI_OUT_OF_RESOURCES; - goto out; - } - - _logical_parts = malloc(len); - if (!_logical_parts) { - status = EFI_OUT_OF_RESOURCES; - goto out_free; - } - - status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, - &BlockIoProtocol, NULL, &len, - (void **)handles); - if (EFI_ERROR(status)) - goto out_free; - - for (i = 0; i < len / sizeof(EFI_HANDLE); i++) { - status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i], - &BlockIoProtocol, (void **)&bio); - if (EFI_ERROR(status)) - goto out_free; - if (bio->Media->LogicalPartition) { - _logical_parts[_logical_parts_no++] = handles[i]; - } - } - - free(handles); - return status; - -out_free: - if (handles) - free(handles); - if (_logical_parts) - free(_logical_parts); -out: - return status; -} - -static inline EFI_HANDLE get_logical_part(unsigned int partno) -{ - if (!_logical_parts || partno > _logical_parts_no) - return NULL; - return _logical_parts[partno - 1]; -} - -static int add_fs(struct fs_info *fs, uint8_t disk, uint8_t partition) -{ - struct queue_head *head = parts_info[disk]; - struct part_node *node; - - node = malloc(sizeof(struct part_node)); - if (!node) - return -1; - node->fs = fs; - node->next = NULL; - node->partition = partition; - - if (!head) { - head = malloc(sizeof(struct queue_head)); - if (!head) { - free(node); - return -1; - } - head->first = head->last = node; - parts_info[disk] = head; - return 0; - } - head->last->next = node; - head->last = node; - return 0; -} - -static struct fs_info *get_fs(uint8_t disk, uint8_t partition) -{ - struct part_node *i; - - for (i = parts_info[disk]->first; i; i = i->next) { - if (i->partition == partition) - return i->fs; - } - return NULL; -} - -static EFI_HANDLE find_partition(unsigned int diskno, unsigned int partno) -{ - return get_logical_part(partno); -} - -static const char *get_num(const char *p, char delimiter, unsigned int *data) -{ - uint32_t n = 0; - - while (*p) { - if (*p < '0' || *p > '9') - break; - n = (n * 10) + (*p - '0'); - p++; - if (*p == delimiter) { - p++; /* skip delimiter */ - *data = min(n, UINT8_MAX); /* avoid overflow */ - return p; - } - } - return NULL; -} - -static int parse_multifs_path(const char **path, unsigned int *hdd, - unsigned int *partition) -{ - const char *p = *path; - static const char *cwd = "."; - - *hdd = *partition = 0; - p++; /* Skip open parentheses */ - - /* Get hd number (Range: 0 - (DISKS_MAX - 1)) */ - if (*p != 'h' || *(p + 1) != 'd') - return -1; - - p += 2; /* Skip 'h' and 'd' */ - p = get_num(p, ',', hdd); - if (!p) - return -1; - if (*hdd >= DISKS_MAX) { - printf("MultiFS: hdd is out of range: 0-%d\n", DISKS_MAX - 1); - return -1; - } - - /* Get partition number (Range: 0 - 0xFF) */ - p = get_num(p, ')', partition); - if (!p) - return -1; - - if (*p == '\0') { - /* Assume it's a cwd request */ - p = cwd; - } - - *path = p; - dprintf("MultiFS: hdd: %u partition: %u path: %s\n", - *hdd, *partition, *path); - return 0; -} - -static inline void *get_private(EFI_HANDLE lpart) -{ - static struct efi_disk_private priv; - priv.dev_handle = lpart; - return (void *)&priv; -} - -static struct fs_info *get_fs_info(const char **path) -{ - const struct fs_ops **ops; - struct fs_info *fsp; - EFI_HANDLE dh; - struct device *dev = NULL; - void *private; - int blk_shift = -1; - unsigned int hdd, partition; - - if (parse_multifs_path(path, &hdd, &partition)) { - return NULL; - } - - fsp = get_fs(hdd, partition - 1); - if (fsp) - return fsp; - - fsp = malloc(sizeof(struct fs_info)); - if (!fsp) - return NULL; - - dh = find_partition(hdd, partition); - if (!dh) - goto bail; - dprintf("\nMultiFS: found partition %d\n", partition); - private = get_private(dh); - - /* set default name for the root directory */ - fsp->cwd_name[0] = '/'; - fsp->cwd_name[1] = '\0'; - - ops = p_ops; - while ((blk_shift < 0) && *ops) { - /* set up the fs stucture */ - fsp->fs_ops = *ops; - - /* - * This boldly assumes that we don't mix FS_NODEV filesystems - * with FS_DEV filesystems... - */ - if (fsp->fs_ops->fs_flags & FS_NODEV) { - fsp->fs_dev = NULL; - } else { - if (!dev) { - dev = device_init(private); - if (!dev) - goto bail; - } - fsp->fs_dev = dev; - } - /* invoke the fs-specific init code */ - blk_shift = fsp->fs_ops->fs_init(fsp); - ops++; - } - if (blk_shift < 0) { - dprintf("MultiFS: No valid file system found!\n"); - goto free_dev; - } - - if (add_fs(fsp, hdd, partition - 1)) - goto free_dev; - if (fsp->fs_dev && fsp->fs_dev->cache_data && !fsp->fs_dev->cache_init) - cache_init(fsp->fs_dev, blk_shift); - if (fsp->fs_ops->iget_root) { - fsp->root = fsp->fs_ops->iget_root(fsp); - fsp->cwd = get_inode(fsp->root); - } - return fsp; - -free_dev: - free(dev->disk); - free(dev->cache_data); - free(dev); -bail: - free(fsp); - return NULL; -} - -EFI_STATUS init_multifs(void) -{ - EFI_STATUS status; - - status = find_all_logical_parts(); - enable_multifs(get_fs_info); - dprintf("MultiFS: initialised\n"); - - return status; -} -- 2.1.0
Paulo Alcantara
2015-Jul-22 23:27 UTC
[syslinux] [PULL 8/8] efi/multifs: fix misuse of static private information
The get_dev_info_priv() function cannot return a reference of a static variable since there might be multiple device handles and each one per logical partition. A typical example of this failure is when a configuration file contains multifs-path-syntax like, so multifs will initialised to the first partition found (including its device handle) and the other ones will be using the same partition to do I/O. Cc: Gene Cumm <gene.cumm at gmail.com> Signed-off-by: Paulo Alcantara <pcacjr at zytor.com> --- efi/multifs.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/efi/multifs.c b/efi/multifs.c index 418d0c2..63bf73e 100644 --- a/efi/multifs.c +++ b/efi/multifs.c @@ -97,11 +97,15 @@ static inline EFI_HANDLE find_device_handle(unsigned int diskno, return get_logical_part(partno); } -static inline void *get_dev_info_priv(EFI_HANDLE lpart) +static inline void *get_dev_info_priv(EFI_HANDLE handle) { - static struct efi_disk_private priv; - priv.dev_handle = lpart; - return (void *)&priv; + struct efi_disk_private *priv; + + priv = malloc(sizeof(*priv)); + if (!priv) + return NULL; + priv->dev_handle = handle; + return priv; } __export struct fs_info *efi_multifs_get_fs_info(const char **path) @@ -136,11 +140,11 @@ __export struct fs_info *efi_multifs_get_fs_info(const char **path) ret = multifs_setup_fs_info(fsp, diskno, partno, priv); if (ret) { dprintf("%s: failed to set up fs info\n", __func__); - goto free_dev_info; + goto free_priv; } return fsp; -free_dev_info: +free_priv: free(priv); free_fsp: free(fsp); -- 2.1.0
> The MultiFS syntax is basically "(hdX,Y)/path/to/file", where X is disk > number and Y is partition number. >Thank you. As a reminder, please note: _ There was a syntax discussion about "multifs", so additional syntax forms should be allowed too (please read the whole email thread): http://www.syslinux.org/archives/2014-June/022173.html Examples: __ Space or comma should be valid alternatives (as chain.c32); __ Not only numbering, but also labels, uuid's and other forms of identification should be allowed / supported too (as chain.c32). _ And _please_ I beg you all to use the simple term "multifs", without unnecessary "fanciness": http://www.syslinux.org/archives/2014-July/022493.html TIA, Ady.
Raphael S Carvalho
2015-Jul-23 21:09 UTC
[syslinux] [PULL 0/8] MultiFS suppport for BIOS and EFI
On Wed, Jul 22, 2015 at 11:15 PM, Ady via Syslinux <syslinux at zytor.com> wrote:> > > The MultiFS syntax is basically "(hdX,Y)/path/to/file", where X is disk > > number and Y is partition number. > > > > Thank you. > > As a reminder, please note: > > _ There was a syntax discussion about "multifs", so additional syntax > forms should be allowed too (please read the whole email thread): > http://www.syslinux.org/archives/2014-June/022173.html > Examples: > __ Space or comma should be valid alternatives (as chain.c32); > __ Not only numbering, but also labels, uuid's and other forms of > identification should be allowed / supported too (as chain.c32). >My sincere opinion is to apply this patchset as-is, and incrementally improve multifs. Lack of alternatives (additional features) *should not* be a reason to block this patchset. Again, I really think that this patchset should be applied unless a technical reason, e.g. some deficiency introduced by one of the patches, says otherwise. HPA, what do you think?> > _ And _please_ I beg you all to use the simple term "multifs", without > unnecessary "fanciness": > http://www.syslinux.org/archives/2014-July/022493.html > > TIA, > Ady. > > _______________________________________________ > Syslinux mailing list > Submissions to Syslinux at zytor.com > Unsubscribe or set options at: > http://www.zytor.com/mailman/listinfo/syslinux >-- Raphael S. Carvalho
Michal Soltys
2015-Aug-08 10:49 UTC
[syslinux] [PULL 1/8] Move partiter from com32/chain to com32/lib/syslinux
On 2015-07-23 01:27, Paulo Alcantara via Syslinux wrote:> From: "Raphael S. Carvalho" <raphael.scarv at gmail.com> > > MultiFS depends on the availability of partiter to find a partition. > > Cc: Gene Cumm <gene.cumm at gmail.com> > Signed-off-by: Raphael S. Carvalho <raphael.scarv at gmail.com> > Signed-off-by: Paulo Alcantara <pcacjr at zytor.com> > --- > com32/chain/Makefile | 2 +- > com32/chain/chain.c | 4 +- > com32/chain/mangle.c | 4 +- > com32/chain/mangle.h | 2 +- > com32/chain/options.c | 4 +- > com32/chain/partiter.c | 726 -------------------------------------- > com32/chain/partiter.h | 119 ------- > com32/chain/utility.c | 256 -------------- > com32/chain/utility.h | 75 ---- > com32/include/syslinux/partiter.h | 119 +++++++ > com32/include/syslinux/utility.h | 76 ++++ > com32/lib/syslinux/partiter.c | 726 ++++++++++++++++++++++++++++++++++++++ > com32/lib/syslinux/utility.c | 256 ++++++++++++++For the record, moving utility.h (which is just a bunch of functions referenced in different chain files) is probably too much. And those functions are not that useful outside chain. Essentially, just: - move warn(), critm(), error() to partiter.h - redefine guid_is0() in partiter.c - remove references to utility.h Would be IMHO cleaner approach.
... Syslinux MultiFS test: - QEMU/KVM SeaBIOS: PASSED - Bare-metal BIOS: FAILED [1] - OVMF: FAILED [2] - Bare-metal UEFI: not tested [1] stalled: Loading (hd3,2)/vmlinuz-4.3.2-200.fc22.x86_64... [2] "failed: No such file or directory" http://git.zytor.com/users/pcacjr/syslinux.git/tree/core/include/multifs.h?h=multifs-for-upstream#n27 * MULTIFS SYNTAX: * (hd[disk number],[partition number])/path/to/file * * E.G.: (hd0,1)/dir/file means /dir/file at partition 1 of the disk 0. * Disk and Partition numbering starts from 0 and 1 respectivelly. */ ... # fdisk -l /dev/vdb | grep -w 83 /dev/vdb2 2099200 4194303 2095104 1023M 83 Linux # mount | grep vdb2 /dev/vdb2 on /data type ext4 ... # ls -1 /data initramfs-4.4.0-0.rc5.git0.1.fc24.x86_64.img lost+found vmlinuz-4.4.0-0.rc5.git0.1.fc24.x86_64 BOOT: find_all_partitions: failed to set EFI disk info efi_multifs_init: failed to find disk partitions: Invalid Parameter No DEFAULT or UI configuration directive found! boot: 2 Loading (hd1,2)/vmlinuz-4.4.0-0.rc5.git0.1.fc24.x86_64... failed: No such file o r directory boot: SW: qemu-2.5.0-1.fc24.x86_64 seabios-1.9.0-1.fc24.noarch edk2.git-ovmf-x64-0-20151218.b1388.g8873b17.noarch http://goo.gl/Gm4ffO /syslinux efi64 syslinux-6.04-0.22.20151210git721a0af.fc24.x86_64.rpm syslinux-efi64-6.04-0.22.20151210git721a0af.fc24.x86_64.rpm syslinux-extlinux-6.04-0.22.20151210git721a0af.fc24.x86_64.rpm syslinux-extlinux-nonlinux-6.04-0.22.20151210git721a0af.fc24.noarch.rpm syslinux-nonlinux-6.04-0.22.20151210git721a0af.fc24.noarch.rpm
On 20.12.2015 09:55, poma wrote:> ... > > Syslinux MultiFS test: > > - QEMU/KVM SeaBIOS: PASSED > - Bare-metal BIOS: FAILED [1] > - OVMF: FAILED [2] > - Bare-metal UEFI: not tested > > > [1] stalled: > Loading (hd3,2)/vmlinuz-4.3.2-200.fc22.x86_64... > > > [2] "failed: No such file or directory" > > http://git.zytor.com/users/pcacjr/syslinux.git/tree/core/include/multifs.h?h=multifs-for-upstream#n27 > * MULTIFS SYNTAX: > * (hd[disk number],[partition number])/path/to/file > * > * E.G.: (hd0,1)/dir/file means /dir/file at partition 1 of the disk 0. > * Disk and Partition numbering starts from 0 and 1 respectivelly. > */ > ... > > > # fdisk -l /dev/vdb | grep -w 83 > /dev/vdb2 2099200 4194303 2095104 1023M 83 Linux > # mount | grep vdb2 > /dev/vdb2 on /data type ext4 ... > # ls -1 /data > initramfs-4.4.0-0.rc5.git0.1.fc24.x86_64.img > lost+found > vmlinuz-4.4.0-0.rc5.git0.1.fc24.x86_64 > > > BOOT: > find_all_partitions: failed to set EFI disk info > efi_multifs_init: failed to find disk partitions: Invalid Parameter > No DEFAULT or UI configuration directive found! > boot: 2 > Loading (hd1,2)/vmlinuz-4.4.0-0.rc5.git0.1.fc24.x86_64... failed: No such file o > r directory > boot: > > > SW: > qemu-2.5.0-1.fc24.x86_64 > seabios-1.9.0-1.fc24.noarch > edk2.git-ovmf-x64-0-20151218.b1388.g8873b17.noarch > > http://goo.gl/Gm4ffO > /syslinux efi64 > syslinux-6.04-0.22.20151210git721a0af.fc24.x86_64.rpm > syslinux-efi64-6.04-0.22.20151210git721a0af.fc24.x86_64.rpm > syslinux-extlinux-6.04-0.22.20151210git721a0af.fc24.x86_64.rpm > syslinux-extlinux-nonlinux-6.04-0.22.20151210git721a0af.fc24.noarch.rpm > syslinux-nonlinux-6.04-0.22.20151210git721a0af.fc24.noarch.rpm > >http://git.zytor.com/users/pcacjr/syslinux.git/log/?h=multifs-for-upstream without the last two patches: 0009-s-MultiFS-multifs.patch 0010-efi-multifs-correctly-enumerate-partitions-per-disk.patch OVMF MultiFS BOOT failed-stalled, the same as on Bare-metal BIOS No DEFAULT or UI configuration directive found! boot: 2 Loading (hd1,2)/vmlinuz-4.4.0-0.rc5.git0.1.fc24.x86_64... http://goo.gl/Gm4ffO /syslinux efi64/ttyS0-debug.txt