summaryrefslogtreecommitdiffstats
path: root/target/linux/lantiq/patches-3.0/201-owrt-mtd_uimage_split.patch
blob: 6c6a45ac041bebf1475e894defc2ef4a1904c666 (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
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -41,6 +41,10 @@ config MTD_ROOTFS_SPLIT
 	bool "Automatically split 'rootfs' partition for squashfs"
 	default y
 
+config MTD_UIMAGE_SPLIT
+	bool "Automatically split 'linux' partition into 'kernel' and 'rootfs'"
+	default y
+
 config MTD_REDBOOT_PARTS
 	tristate "RedBoot partition table parsing"
 	---help---
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -861,6 +861,82 @@ static int refresh_rootfs_split(struct m
 }
 #endif /* CONFIG_MTD_ROOTFS_SPLIT */
 
+
+#ifdef CONFIG_MTD_UIMAGE_SPLIT
+static unsigned long find_uimage_size(struct mtd_info *mtd,
+				      unsigned long offset)
+{
+#define UBOOT_MAGIC	0x56190527
+	unsigned long magic = 0;
+	unsigned long temp;
+	size_t len;
+	int ret;
+
+	ret = mtd->read(mtd, offset, 4, &len, (void *)&magic);
+	if (ret || len != sizeof(magic))
+		return 0;
+
+	if (le32_to_cpu(magic) != UBOOT_MAGIC)
+		return 0;
+
+	ret = mtd->read(mtd, offset + 12, 4, &len, (void *)&temp);
+	if (ret || len != sizeof(temp))
+		return 0;
+
+	return temp + 0x40;
+}
+
+static int detect_squashfs_partition(struct mtd_info *mtd, unsigned long offset)
+{
+	unsigned long temp;
+	size_t len;
+	int ret;
+
+	ret = mtd->read(mtd, offset, 4, &len, (void *)&temp);
+	if (ret || len != sizeof(temp))
+		return 0;
+
+	return le32_to_cpu(temp) == SQUASHFS_MAGIC;
+}
+
+static int split_uimage(struct mtd_info *mtd,
+			const struct mtd_partition *part)
+{
+	static struct mtd_partition split_partitions[] = {
+		{
+			.name = "kernel",
+			.offset = 0x0,
+			.size = 0x0,
+		}, {
+			.name = "rootfs",
+			.offset = 0x0,
+			.size = 0x0,
+		},
+	};
+
+	split_partitions[0].size = find_uimage_size(mtd, part->offset);
+	if (!split_partitions[0].size) {
+		printk(KERN_NOTICE "no uImage found in linux partition\n");
+		return -1;
+	}
+
+	if (!detect_squashfs_partition(mtd,
+				       part->offset
+				       + split_partitions[0].size)) {
+		split_partitions[0].size &= ~(mtd->erasesize - 1);
+		split_partitions[0].size += mtd->erasesize;
+	}
+
+	split_partitions[0].offset = part->offset;
+	split_partitions[1].offset = part->offset + split_partitions[0].size;
+	split_partitions[1].size = part->size - split_partitions[0].size;
+
+	add_mtd_partitions(mtd, split_partitions, 2);
+
+	return 0;
+}
+#endif
+
 /*
  * This function, given a master MTD object and a partition table, creates
  * and registers slave MTD objects which are bound to the master according to
@@ -894,6 +970,17 @@ int add_mtd_partitions(struct mtd_info *
 
 		add_mtd_device(&slave->mtd);
 
+#ifdef CONFIG_MTD_UIMAGE_SPLIT
+		if (!strcmp(parts[i].name, "linux")) {
+			ret = split_uimage(master, &parts[i]);
+
+			if (ret) {
+				printk(KERN_WARNING
+				       "Can't split linux partition\n");
+			}
+		}
+#endif
+
 		if (!strcmp(parts[i].name, "rootfs")) {
 #ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
 			if (ROOT_DEV == 0) {