1/*
2 * Read flash partition table from Compaq Bootloader
3 *
4 * Copyright 2001 Compaq Computer Corporation.
5 *
6 * $Id: bootldr.c,v 1.1.1.1 2008/10/15 03:26:35 james26_jang Exp $
7 *
8 * Use consistent with the GNU GPL is permitted,
9 * provided that this copyright notice is
10 * preserved in its entirety in all copies and derived works.
11 *
12 * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
13 * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
14 * FITNESS FOR ANY PARTICULAR PURPOSE.
15 *
16 */
17
18/*
19 * Maintainer: Jamey Hicks (jamey.hicks@compaq.com)
20 */
21
22#include <linux/kernel.h>
23#include <linux/slab.h>
24
25#include <linux/mtd/mtd.h>
26#include <linux/mtd/partitions.h>
27#include <asm/setup.h>
28#include <linux/bootmem.h>
29
30#define FLASH_PARTITION_NAMELEN 32
31enum LFR_FLAGS {
32   LFR_SIZE_PREFIX = 1,		/* prefix data with 4-byte size */
33   LFR_PATCH_BOOTLDR = 2,	/* patch bootloader's 0th instruction */
34   LFR_KERNEL = 4,		/* add BOOTIMG_MAGIC, imgsize and VKERNEL_BASE to head of programmed region (see bootldr.c) */
35   LFR_EXPAND = 8               /* expand partition size to fit rest of flash */
36};
37
38// the tags are parsed too early to malloc or alloc_bootmem so we'll fix it
39// for now
40#define MAX_NUM_PARTITIONS 8
41typedef struct FlashRegion {
42   char name[FLASH_PARTITION_NAMELEN];
43   unsigned long base;
44   unsigned long size;
45   enum LFR_FLAGS flags;
46} FlashRegion;
47
48typedef struct BootldrFlashPartitionTable {
49  int magic; /* should be filled with 0x646c7470 (btlp) BOOTLDR_PARTITION_MAGIC */
50  int npartitions;
51  struct FlashRegion partition[8];
52} BootldrFlashPartitionTable;
53
54#define BOOTLDR_MAGIC      0x646c7462        /* btld: marks a valid bootldr image */
55#define BOOTLDR_PARTITION_MAGIC  0x646c7470  /* btlp: marks a valid bootldr partition table in params sector */
56
57#define BOOTLDR_MAGIC_OFFSET 0x20 /* offset 0x20 into the bootldr */
58#define BOOTCAP_OFFSET 0X30 /* offset 0x30 into the bootldr */
59
60#define BOOTCAP_WAKEUP	(1<<0)
61#define BOOTCAP_PARTITIONS (1<<1) /* partition table stored in params sector */
62#define BOOTCAP_PARAMS_AFTER_BOOTLDR (1<<2) /* params sector right after bootldr sector(s), else in last sector */
63
64static struct BootldrFlashPartitionTable Table;
65static struct BootldrFlashPartitionTable *partition_table = NULL;
66
67
68int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts)
69{
70	struct mtd_partition *parts;
71	int ret, retlen, i;
72	int npartitions = 0;
73	long partition_table_offset;
74	long bootmagic = 0;
75	long bootcap = 0;
76	int namelen = 0;
77
78	char *names;
79
80	if (!partition_table)
81	    return -ENOMEM;
82
83
84	printk(__FUNCTION__ ": magic=%#x\n", partition_table->magic);
85	printk(__FUNCTION__ ": numPartitions=%#x\n", partition_table->npartitions);
86
87
88	/* check for partition table magic number */
89	if (partition_table->magic != BOOTLDR_PARTITION_MAGIC)
90		goto out;
91	npartitions = (partition_table->npartitions > MAX_NUM_PARTITIONS)?
92	    MAX_NUM_PARTITIONS:partition_table->npartitions;
93
94	printk(__FUNCTION__ ": npartitions=%#x\n", npartitions);
95
96	for (i = 0; i < npartitions; i++) {
97		namelen += strlen(partition_table->partition[i].name) + 1;
98	}
99
100	parts = kmalloc(sizeof(*parts)*npartitions + namelen, GFP_KERNEL);
101	if (!parts) {
102		ret = -ENOMEM;
103		goto out;
104	}
105	names = (char *)&parts[npartitions];
106	memset(parts, 0, sizeof(*parts)*npartitions + namelen);
107
108
109
110	// from here we use the partition table
111	for (i = 0; i < npartitions; i++) {
112                struct FlashRegion *partition = &partition_table->partition[i];
113		const char *name = partition->name;
114		parts[i].name = names;
115		names += strlen(name) + 1;
116		strcpy(parts[i].name, name);
117
118                if (partition->flags & LFR_EXPAND)
119                        parts[i].size = MTDPART_SIZ_FULL;
120                else
121                        parts[i].size = partition->size;
122		parts[i].offset = partition->base;
123		parts[i].mask_flags = 0;
124
125		printk("        partition %s o=%x s=%x\n",
126		       parts[i].name, parts[i].offset, parts[i].size);
127
128	}
129
130	ret = npartitions;
131	*pparts = parts;
132
133 out:
134
135	return ret;
136}
137
138
139static int __init parse_tag_ptable(const struct tag *tag)
140{
141    char buf[128];
142    int i;
143    int j;
144
145    partition_table = &Table;
146
147#ifdef CONFIG_DEBUG_LL
148    sprintf(buf,"ptable: magic = = 0x%lx  npartitions= %d \n",
149	    tag->u.ptable.magic,tag->u.ptable.npartitions);
150    printascii(buf);
151
152    for (i=0; i<tag->u.ptable.npartitions; i++){
153	sprintf(buf,"ptable: partition name = %s base= 0x%lx  size= 0x%lx flags= 0x%lx\n",
154	    (char *) (&tag->u.ptable.partition[i].name[0]),
155		tag->u.ptable.partition[i].base,
156		tag->u.ptable.partition[i].size,
157		tag->u.ptable.partition[i].flags);
158	printascii(buf);
159    }
160#endif
161
162    memcpy((void *)partition_table,(void *) (&(tag->u.ptable)),sizeof(partition_table) +
163	sizeof(struct FlashRegion)*tag->u.ptable.npartitions);
164
165
166    return 0;
167}
168
169__tagtable(ATAG_PTABLE, parse_tag_ptable);
170
171EXPORT_SYMBOL(parse_bootldr_partitions);
172
173
174MODULE_LICENSE("GPL");
175MODULE_AUTHOR("Compaq Computer Corporation");
176MODULE_DESCRIPTION("Parsing code for Compaq bootldr partitions");
177