summaryrefslogtreecommitdiff
path: root/efi/multifs.c
diff options
context:
space:
mode:
Diffstat (limited to 'efi/multifs.c')
-rw-r--r--efi/multifs.c162
1 files changed, 162 insertions, 0 deletions
diff --git a/efi/multifs.c b/efi/multifs.c
new file mode 100644
index 00000000..418d0c2c
--- /dev/null
+++ b/efi/multifs.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2015 Paulo Alcantara <pcacjr@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__);
+}