This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit aaf1a5e113c8443afca7fa14a0cf75f010069125 Author: Jiuzhu Dong <[email protected]> AuthorDate: Wed Sep 29 22:45:24 2021 +0800 fs/partition: support parse mbr partition Signed-off-by: Jiuzhu Dong <[email protected]> --- fs/partition/Kconfig | 4 + fs/partition/Make.defs | 4 + fs/partition/fs_mbr.c | 214 ++++++++++++++++++++++++++++++++++++++++++++ fs/partition/fs_partition.c | 5 ++ fs/partition/partition.h | 6 ++ 5 files changed, 233 insertions(+) diff --git a/fs/partition/Kconfig b/fs/partition/Kconfig index 584b602..a2f0b70 100644 --- a/fs/partition/Kconfig +++ b/fs/partition/Kconfig @@ -11,6 +11,10 @@ config PTABLE_PARTITION bool "PTABLE support" default n +config MBR_PARTITION + bool "MBR support" + default n + endmenu endif diff --git a/fs/partition/Make.defs b/fs/partition/Make.defs index 0d8cf9e..78d72b6 100644 --- a/fs/partition/Make.defs +++ b/fs/partition/Make.defs @@ -28,6 +28,10 @@ ifeq ($(CONFIG_PTABLE_PARTITION),y) CSRCS += fs_ptable.c endif +ifeq ($(CONFIG_MBR_PARTITION),y) +CSRCS += fs_mbr.c +endif + # Include partition build support DEPPATH += --dep-path partition diff --git a/fs/partition/fs_mbr.c b/fs/partition/fs_mbr.c new file mode 100644 index 0000000..84a5f66 --- /dev/null +++ b/fs/partition/fs_mbr.c @@ -0,0 +1,214 @@ +/**************************************************************************** + * fs/partition/fs_mbr.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <debug.h> +#include <endian.h> +#include <string.h> + +#include <nuttx/kmalloc.h> + +#include "partition.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define MBR_SIZE 512 +#define MBR_LBA_TO_BLOCK(lba, blk) ((le32toh(lba) * 512 + (blk) - 1) / (blk)) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* These three have identical behaviour; use the second one if DOS FDISK gets + * confused about extended/logical partitions starting past cylinder 1023. + */ + +enum mbr_type_e +{ + DOS_EXTENDED_PARTITION = 5, + LINUX_EXTENDED_PARTITION = 0x85, + WIN98_EXTENDED_PARTITION = 0x0f, +}; + +/* Description of one partition table entry (D*S type) */ + +begin_packed_struct struct mbr_entry_s +{ + uint8_t boot_indicator; /* Maybe marked as an active partition */ + uint8_t chs_begin[3]; /* Start of the partition in cylinders, heads and sectors */ + uint8_t type; /* Filesystem type */ + uint8_t chs_end[3]; /* End of the partition in cylinders, heads and sectors */ + uint32_t partition_start; /* Start of the partition in LBA notation */ + uint32_t partition_size; /* Start of the partition in LBA notation */ +} end_packed_struct; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static inline int is_extended(uint8_t type) +{ + return (type == DOS_EXTENDED_PARTITION || + type == WIN98_EXTENDED_PARTITION || + type == LINUX_EXTENDED_PARTITION); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: parse_mbr_partition + * + * Description: + * parse the mbr(Master_boot_record) partition. + * + * Input Parameters: + * state - The partition table state + * handler - The function to be called for each found partition + * arg - A caller provided value to return with the handler + * + * Returned Value: + * Zero on success; A negated errno value is returned on a failure + * + ****************************************************************************/ + +int parse_mbr_partition(FAR struct partition_state_s *state, + partition_handler_t handler, + FAR void *arg) +{ + struct partition_s pentry; + FAR struct mbr_entry_s *table; + FAR struct mbr_entry_s *extended = NULL; + FAR uint8_t *buffer; + int num; + int ret; + int i; + + num = (MBR_SIZE + state->blocksize - 1) / state->blocksize; + buffer = kmm_malloc(num * state->blocksize); + if (!buffer) + { + return -ENOMEM; + } + + ret = read_partition_block(state, buffer, 0, num); + if (ret < 0) + { + kmm_free(buffer); + return ret; + } + + if (buffer[0x1fe] != 0x55 || buffer[0x1ff] != 0xaa) + { + kmm_free(buffer); + return -EINVAL; + } + + memset(&pentry, 0, sizeof(pentry)); + table = (FAR struct mbr_entry_s *)&buffer[0x1be]; + for (i = 0; i < 4; i++) + { + pentry.firstblock = MBR_LBA_TO_BLOCK(table[i].partition_start, + state->blocksize); + pentry.nblocks = MBR_LBA_TO_BLOCK(table[i].partition_size, + state->blocksize); + + if (pentry.nblocks != 0) + { + if (!is_extended(table[i].type)) + { + handler(&pentry, arg); + pentry.index++; + } + else if(!extended) + { + extended = &table[i]; + } + } + else + { + finfo("Skipping empty partition %d\n", i); + } + } + + if (extended) + { + uint32_t ebr_block; + ebr_block = MBR_LBA_TO_BLOCK(extended->partition_start, + state->blocksize); + while (1) + { + ret = read_partition_block(state, buffer, ebr_block, num); + if (ret < 0) + { + goto out; + } + + if (buffer[0x1fe] != 0x55 || buffer[0x1ff] != 0xaa) + { + ferr("block %x doesn't contain an EBR signature\n", + ebr_block); + ret = -EINVAL; + goto out; + } + + for (i = 0x1de; i < 0x1fe; ++i) + { + if (buffer[i]) + { + ferr("EBR's third or fourth partition non-empty\n"); + ret = -EINVAL; + goto out; + } + } + + /* the first entry defines the extended partition */ + + pentry.firstblock = ebr_block + MBR_LBA_TO_BLOCK( + table[0].partition_start, state->blocksize); + pentry.nblocks = MBR_LBA_TO_BLOCK(table[0].partition_size, + state->blocksize); + handler(&pentry, arg); + pentry.index++; + + /* the second entry defines the start of the next ebr if != 0 */ + + if (table[1].partition_start) + { + ebr_block = pentry.firstblock + MBR_LBA_TO_BLOCK( + table[1].partition_start, state->blocksize); + } + else + { + break; + } + } + } + +out: + kmm_free(buffer); + return ret; +} diff --git a/fs/partition/fs_partition.c b/fs/partition/fs_partition.c index 4a9287d..95b5799 100644 --- a/fs/partition/fs_partition.c +++ b/fs/partition/fs_partition.c @@ -52,6 +52,11 @@ static const partition_parser_t g_parser[] = #ifdef CONFIG_PTABLE_PARTITION parse_ptable_partition, #endif + +#ifdef CONFIG_MBR_PARTITION + parse_mbr_partition, +#endif + NULL }; diff --git a/fs/partition/partition.h b/fs/partition/partition.h index 8c05c14..2358202 100644 --- a/fs/partition/partition.h +++ b/fs/partition/partition.h @@ -58,6 +58,12 @@ int parse_ptable_partition(FAR struct partition_state_s *state, FAR void *arg); #endif +#ifdef CONFIG_MBR_PARTITION +int parse_mbr_partition(FAR struct partition_state_s *state, + partition_handler_t handler, + FAR void *arg); +#endif + #endif /* CONFIG_DISABLE_MOUNTPOINT */ #endif /* __FS_PARTITION_PARTITION_H */
