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