9
0
Fork 0

partitons: add framework

so we can support multiple format

use filetpye to detect the parser to use

Cc: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
Jean-Christophe PLAGNIOL-VILLARD 2013-02-16 14:47:07 +01:00 committed by Sascha Hauer
parent a7d9ec0498
commit 263bb23ed2
7 changed files with 194 additions and 100 deletions

View File

@ -478,19 +478,7 @@ config PARTITION
bool
prompt "Enable Partitions"
config PARTITION_DISK
depends on PARTITION
bool "DISK partition support"
help
Add support for handling common partition tables on all kind of disk
like devices (harddisks, CF cards, SD cards and so on)
config PARTITION_DISK_DOS
depends on PARTITION_DISK
default y
bool "DOS partition support"
help
Add support to handle partitions in DOS style.
source common/partitions/Kconfig
config DEFAULT_ENVIRONMENT
bool

View File

@ -7,7 +7,7 @@ obj-$(CONFIG_ENV_HANDLING) += environment.o
obj-$(CONFIG_AUTO_COMPLETE) += complete.o
obj-$(CONFIG_POLLER) += poller.o
obj-$(CONFIG_BLOCK) += block.o
obj-$(CONFIG_PARTITION_DISK) += partitions.o
obj-$(CONFIG_PARTITION_DISK) += partitions.o partitions/
obj-$(CONFIG_CMD_LOADS) += s_record.o
obj-$(CONFIG_OFTREE) += oftree.o

View File

@ -27,92 +27,12 @@
#include <block.h>
#include <asm/unaligned.h>
#include <disks.h>
#include <dma.h>
#include <filetype.h>
#include <dma.h>
struct partition {
uint64_t first_sec;
uint64_t size;
};
#include "partitions/parser.h"
struct partition_desc {
int used_entries;
struct partition parts[8];
};
/**
* Guess the size of the disk, based on the partition table entries
* @param dev device to create partitions for
* @param table partition table
* @return sector count
*/
static int disk_guess_size(struct device_d *dev, struct partition_entry *table)
{
uint64_t size = 0;
int i;
for (i = 0; i < 4; i++) {
if (table[i].partition_start != 0) {
size += get_unaligned_le32(&table[i].partition_start) - size;
size += get_unaligned_le32(&table[i].partition_size);
}
}
return (int)size;
}
/**
* Check if a DOS like partition describes this block device
* @param blk Block device to register to
* @param pd Where to store the partition information
*
* It seems at least on ARM this routine canot use temp. stack space for the
* sector. So, keep the malloc/free.
*/
static void __maybe_unused try_dos_partition(struct block_device *blk,
struct partition_desc *pd)
{
uint8_t *buffer;
struct partition_entry *table;
struct partition pentry;
int i, rc;
buffer = dma_alloc(SECTOR_SIZE);
/* read in the MBR to get the partition table */
rc = blk->ops->read(blk, buffer, 0, 1);
if (rc != 0) {
dev_err(blk->dev, "Cannot read MBR/partition table\n");
goto on_error;
}
if (is_fat_or_mbr(buffer, NULL) != filetype_mbr) {
dev_info(blk->dev, "No partition table found\n");
goto on_error;
}
table = (struct partition_entry *)&buffer[446];
/* valid for x86 BIOS based disks only */
if (IS_ENABLED(CONFIG_DISK_BIOS) && blk->num_blocks == 0)
blk->num_blocks = disk_guess_size(blk->dev, table);
for (i = 0; i < 4; i++) {
pentry.first_sec = get_unaligned_le32(&table[i].partition_start);
pentry.size = get_unaligned_le32(&table[i].partition_size);
if (pentry.first_sec != 0) {
pd->parts[pd->used_entries].first_sec = pentry.first_sec;
pd->parts[pd->used_entries].size = pentry.size;
pd->used_entries++;
} else {
dev_dbg(blk->dev, "Skipping empty partition %d\n", i);
}
}
on_error:
dma_free(buffer);
}
static LIST_HEAD(partition_parser_list);
/**
* Register one partition on the given block device
@ -135,6 +55,33 @@ static int register_one_partition(struct block_device *blk,
0, partition_name);
}
static struct partition_parser *partition_parser_get_by_filetype(uint8_t *buf)
{
enum filetype type;
struct partition_parser *parser;
/* first new partition table as EFI GPT */
type = file_detect_type(buf, SECTOR_SIZE * 2);
list_for_each_entry(parser, &partition_parser_list, list) {
if (parser->type == type)
return parser;
}
/* if not parser found search for old one
* so if EFI GPT not enable take it as MBR
* useful for compatibility
*/
type = file_detect_type(buf, SECTOR_SIZE);
list_for_each_entry(parser, &partition_parser_list, list) {
if (parser->type == type)
return parser;
}
return NULL;
}
/**
* Try to collect partition information on the given block device
* @param blk Block device to examine
@ -147,10 +94,23 @@ int parse_partition_table(struct block_device *blk)
struct partition_desc pdesc = { .used_entries = 0, };
int i;
int rc = 0;
struct partition_parser *parser;
uint8_t *buf;
buf = dma_alloc(SECTOR_SIZE * 2);
rc = blk->ops->read(blk, buf, 0, 2);
if (rc != 0) {
dev_err(blk->dev, "Cannot read MBR/partition table\n");
goto on_error;
}
parser = partition_parser_get_by_filetype(buf);
if (!parser)
goto on_error;
parser->parse(buf, blk, &pdesc);
#ifdef CONFIG_PARTITION_DISK_DOS
try_dos_partition(blk, &pdesc);
#endif
if (!pdesc.used_entries)
return 0;
@ -165,5 +125,14 @@ int parse_partition_table(struct block_device *blk)
rc = 0;
}
on_error:
dma_free(buf);
return rc;
}
int partition_parser_register(struct partition_parser *p)
{
list_add_tail(&p->list, &partition_parser_list);
return 0;
}

13
common/partitions/Kconfig Normal file
View File

@ -0,0 +1,13 @@
config PARTITION_DISK
depends on PARTITION
bool "DISK partition support"
help
Add support for handling common partition tables on all kind of disk
like devices (harddisks, CF cards, SD cards and so on)
config PARTITION_DISK_DOS
depends on PARTITION_DISK
default y
bool "DOS partition support"
help
Add support to handle partitions in DOS style.

View File

@ -0,0 +1 @@
obj-$(CONFIG_PARTITION_DISK_DOS) += dos.o

88
common/partitions/dos.c Normal file
View File

@ -0,0 +1,88 @@
/*
* Copyright (C) 2009...2011 Juergen Beisert, Pengutronix
*
* 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.
*/
#include <common.h>
#include <disks.h>
#include <init.h>
#include <asm/unaligned.h>
#include "parser.h"
/**
* Guess the size of the disk, based on the partition table entries
* @param dev device to create partitions for
* @param table partition table
* @return sector count
*/
static int disk_guess_size(struct device_d *dev, struct partition_entry *table)
{
uint64_t size = 0;
int i;
for (i = 0; i < 4; i++) {
if (table[i].partition_start != 0) {
size += get_unaligned_le32(&table[i].partition_start) - size;
size += get_unaligned_le32(&table[i].partition_size);
}
}
return (int)size;
}
/**
* Check if a DOS like partition describes this block device
* @param blk Block device to register to
* @param pd Where to store the partition information
*
* It seems at least on ARM this routine canot use temp. stack space for the
* sector. So, keep the malloc/free.
*/
static void dos_partition(void *buf, struct block_device *blk,
struct partition_desc *pd)
{
struct partition_entry *table;
struct partition pentry;
uint8_t *buffer = buf;
int i;
table = (struct partition_entry *)&buffer[446];
/* valid for x86 BIOS based disks only */
if (IS_ENABLED(CONFIG_DISK_BIOS) && blk->num_blocks == 0)
blk->num_blocks = disk_guess_size(blk->dev, table);
for (i = 0; i < 4; i++) {
pentry.first_sec = get_unaligned_le32(&table[i].partition_start);
pentry.size = get_unaligned_le32(&table[i].partition_size);
if (pentry.first_sec != 0) {
pd->parts[pd->used_entries].first_sec = pentry.first_sec;
pd->parts[pd->used_entries].size = pentry.size;
pd->used_entries++;
} else {
dev_dbg(blk->dev, "Skipping empty partition %d\n", i);
}
}
}
struct partition_parser dos = {
.parse = dos_partition,
.type = filetype_mbr,
};
static int dos_partition_init(void)
{
return partition_parser_register(&dos);
}
postconsole_initcall(dos_partition_init);

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2013 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
*
* Under GPLv2 only
*/
#ifndef __PARTITIONS_PARSER_H__
#define __PARTITIONS_PARSER_H__
#include <block.h>
#include <filetype.h>
#include <linux/list.h>
#define MAX_PARTITION 8
struct partition {
uint64_t first_sec;
uint64_t size;
};
struct partition_desc {
int used_entries;
struct partition parts[MAX_PARTITION];
};
struct partition_parser {
void (*parse)(void *buf, struct block_device *blk, struct partition_desc *pd);
enum filetype type;
struct list_head list;
};
int partition_parser_register(struct partition_parser *p);
#endif /* __PARTITIONS_PARSER_H__ */