summaryrefslogtreecommitdiffstats
path: root/uClinux-2.4.20-uc1/drivers/mtd/bootldr.c
blob: 43fcd6bea8b89bedddd10a62403af3fdbe605ce6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
/*
 * Read flash partition table from Compaq Bootloader
 *
 * Copyright 2001 Compaq Computer Corporation.
 *
 * $Id: bootldr.c,v 1.6 2001/10/02 15:05:11 dwmw2 Exp $
 *
 * Use consistent with the GNU GPL is permitted,
 * provided that this copyright notice is
 * preserved in its entirety in all copies and derived works.
 *
 * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
 * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
 * FITNESS FOR ANY PARTICULAR PURPOSE.
 *
 */

/*
 * Maintainer: Jamey Hicks (jamey.hicks@compaq.com)
 */

#include <linux/kernel.h>
#include <linux/slab.h>

#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <asm/setup.h>
#include <linux/bootmem.h>

#define FLASH_PARTITION_NAMELEN 32
enum LFR_FLAGS {
   LFR_SIZE_PREFIX = 1,		/* prefix data with 4-byte size */
   LFR_PATCH_BOOTLDR = 2,	/* patch bootloader's 0th instruction */
   LFR_KERNEL = 4,		/* add BOOTIMG_MAGIC, imgsize and VKERNEL_BASE to head of programmed region (see bootldr.c) */
   LFR_EXPAND = 8               /* expand partition size to fit rest of flash */
};

// the tags are parsed too early to malloc or alloc_bootmem so we'll fix it
// for now
#define MAX_NUM_PARTITIONS 8
typedef struct FlashRegion {
   char name[FLASH_PARTITION_NAMELEN];
   unsigned long base;
   unsigned long size;
   enum LFR_FLAGS flags;
} FlashRegion;

typedef struct BootldrFlashPartitionTable {
  int magic; /* should be filled with 0x646c7470 (btlp) BOOTLDR_PARTITION_MAGIC */
  int npartitions;
  struct FlashRegion partition[8];
} BootldrFlashPartitionTable;

#define BOOTLDR_MAGIC      0x646c7462        /* btld: marks a valid bootldr image */
#define BOOTLDR_PARTITION_MAGIC  0x646c7470  /* btlp: marks a valid bootldr partition table in params sector */

#define BOOTLDR_MAGIC_OFFSET 0x20 /* offset 0x20 into the bootldr */
#define BOOTCAP_OFFSET 0X30 /* offset 0x30 into the bootldr */

#define BOOTCAP_WAKEUP	(1<<0)
#define BOOTCAP_PARTITIONS (1<<1) /* partition table stored in params sector */
#define BOOTCAP_PARAMS_AFTER_BOOTLDR (1<<2) /* params sector right after bootldr sector(s), else in last sector */

static struct BootldrFlashPartitionTable Table;
static struct BootldrFlashPartitionTable *partition_table = NULL;


int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts)
{
	struct mtd_partition *parts;
	int ret, retlen, i;
	int npartitions = 0;
	long partition_table_offset;
	long bootmagic = 0;
	long bootcap = 0;
	int namelen = 0;

	char *names; 

#if 0
	/* verify bootldr magic */
	ret = master->read(master, BOOTLDR_MAGIC_OFFSET, sizeof(long), &retlen, (void *)&bootmagic);
	if (ret) 
		goto out;
        if (bootmagic != BOOTLDR_MAGIC)
                goto out;
	/* see if bootldr supports partition tables and where to find the partition table */
	ret = master->read(master, BOOTCAP_OFFSET, sizeof(long), &retlen, (void *)&bootcap);
	if (ret) 
		goto out;

	if (!(bootcap & BOOTCAP_PARTITIONS))
		goto out;
	if (bootcap & BOOTCAP_PARAMS_AFTER_BOOTLDR)
		partition_table_offset = master->erasesize;
	else
		partition_table_offset = master->size - master->erasesize;

	printk(__FUNCTION__ ": partition_table_offset=%#lx\n", partition_table_offset);
	printk(__FUNCTION__ ": ptable_addr=%#lx\n", ptable_addr);


	/* Read the partition table */
	partition_table = (struct BootldrFlashPartitionTable *)kmalloc(PAGE_SIZE, GFP_KERNEL);
	if (!partition_table)
		return -ENOMEM;

	ret = master->read(master, partition_table_offset,
			   PAGE_SIZE, &retlen, (void *)partition_table);
	if (ret)
	    goto out;

#endif
	if (!partition_table)
	    return -ENOMEM;

	
	printk(__FUNCTION__ ": magic=%#x\n", partition_table->magic);
	printk(__FUNCTION__ ": numPartitions=%#x\n", partition_table->npartitions);


	/* check for partition table magic number */
	if (partition_table->magic != BOOTLDR_PARTITION_MAGIC) 
		goto out;
	npartitions = (partition_table->npartitions > MAX_NUM_PARTITIONS)?
	    MAX_NUM_PARTITIONS:partition_table->npartitions;	

	printk(__FUNCTION__ ": npartitions=%#x\n", npartitions);

	for (i = 0; i < npartitions; i++) {
		namelen += strlen(partition_table->partition[i].name) + 1;
	}

	parts = kmalloc(sizeof(*parts)*npartitions + namelen, GFP_KERNEL);
	if (!parts) {
		ret = -ENOMEM;
		goto out;
	}
	names = (char *)&parts[npartitions];
	memset(parts, 0, sizeof(*parts)*npartitions + namelen);



	// from here we use the partition table
	for (i = 0; i < npartitions; i++) {
                struct FlashRegion *partition = &partition_table->partition[i];
		const char *name = partition->name;
		parts[i].name = names;
		names += strlen(name) + 1;
		strcpy(parts[i].name, name);

                if (partition->flags & LFR_EXPAND)
                        parts[i].size = MTDPART_SIZ_FULL;
                else
                        parts[i].size = partition->size;
		parts[i].offset = partition->base;
		parts[i].mask_flags = 0;
		
		printk("        partition %s o=%x s=%x\n", 
		       parts[i].name, parts[i].offset, parts[i].size);

	}

	ret = npartitions;
	*pparts = parts;

 out:
#if 0
	if (partition_table)
		kfree(partition_table);
#endif
	
	return ret;
}


static int __init parse_tag_ptable(const struct tag *tag)
{
    char buf[128];
    int i;
    int j;
    
    partition_table = &Table;

#ifdef CONFIG_DEBUG_LL    
    sprintf(buf,"ptable: magic = = 0x%lx  npartitions= %d \n",
	    tag->u.ptable.magic,tag->u.ptable.npartitions);
    printascii(buf);
    
    for (i=0; i<tag->u.ptable.npartitions; i++){
	sprintf(buf,"ptable: partition name = %s base= 0x%lx  size= 0x%lx flags= 0x%lx\n",
	    (char *) (&tag->u.ptable.partition[i].name[0]),
		tag->u.ptable.partition[i].base,
		tag->u.ptable.partition[i].size,
		tag->u.ptable.partition[i].flags);
	printascii(buf);
    }
#endif

    memcpy((void *)partition_table,(void *) (&(tag->u.ptable)),sizeof(partition_table) +
	sizeof(struct FlashRegion)*tag->u.ptable.npartitions);

    
    return 0;
}

__tagtable(ATAG_PTABLE, parse_tag_ptable);

EXPORT_SYMBOL(parse_bootldr_partitions);


MODULE_LICENSE("GPL");
MODULE_AUTHOR("Compaq Computer Corporation");
MODULE_DESCRIPTION("Parsing code for Compaq bootldr partitions");