Browse Source

Add code for constructing single-file cpio archives on the fly

tags/v0.9.3
Michael Brown 17 years ago
parent
commit
726e366e8f
3 changed files with 166 additions and 30 deletions
  1. 75
    30
      src/arch/i386/image/bzimage.c
  2. 40
    0
      src/core/cpio.c
  3. 51
    0
      src/include/gpxe/cpio.h

+ 75
- 30
src/arch/i386/image/bzimage.c View File

@@ -35,6 +35,7 @@
35 35
 #include <gpxe/segment.h>
36 36
 #include <gpxe/init.h>
37 37
 #include <gpxe/initrd.h>
38
+#include <gpxe/cpio.h>
38 39
 
39 40
 struct image_type bzimage_image_type __image_type ( PROBE_NORMAL );
40 41
 
@@ -166,6 +167,63 @@ static int bzimage_set_cmdline ( struct image *image,
166 167
 	return 0;
167 168
 }
168 169
 
170
+/**
171
+ * Load initrd
172
+ *
173
+ * @v image		bzImage image
174
+ * @v initrd		initrd image
175
+ * @v address		Address at which to load, or UNULL
176
+ * @ret len		Length of loaded image, rounded up to 4 bytes
177
+ */
178
+static size_t bzimage_load_initrd ( struct image *image,
179
+				    struct image *initrd,
180
+				    userptr_t address ) {
181
+	char *filename = initrd->cmdline;
182
+	struct cpio_header cpio;
183
+        size_t offset = 0;
184
+
185
+	/* Ignore images which aren't initrds */
186
+	if ( initrd->type != &initrd_image_type )
187
+		return 0;
188
+
189
+	/* Create cpio header before non-prebuilt images */
190
+	if ( filename[0] ) {
191
+		size_t name_len = ( strlen ( filename ) + 1 );
192
+
193
+		DBGC ( image, "bzImage %p inserting initrd %p as %s\n",
194
+		       image, initrd, filename );
195
+		memset ( &cpio, '0', sizeof ( cpio ) );
196
+		memcpy ( cpio.c_magic, CPIO_MAGIC, sizeof ( cpio.c_magic ) );
197
+		cpio_set_field ( cpio.c_mode, 0100644 );
198
+		cpio_set_field ( cpio.c_nlink, 1 );
199
+		cpio_set_field ( cpio.c_filesize, initrd->len );
200
+		cpio_set_field ( cpio.c_namesize, name_len );
201
+		if ( address ) {
202
+			copy_to_user ( address, offset, &cpio,
203
+				       sizeof ( cpio ) );
204
+		}
205
+		offset += sizeof ( cpio );
206
+		if ( address ) {
207
+			copy_to_user ( address, offset, filename,
208
+				       name_len );
209
+		}
210
+		offset += name_len;
211
+		offset = ( ( offset + 0x03 ) & ~0x03 );
212
+	}
213
+
214
+	/* Copy in initrd image body */
215
+	if ( address ) {
216
+		DBGC ( image, "bzImage %p has initrd %p at [%lx,%lx)\n",
217
+		       image, initrd, address, ( address + offset ) );
218
+		memcpy_user ( address, offset, initrd->data, 0,
219
+			      initrd->len );
220
+	}
221
+	offset += initrd->len;
222
+
223
+	offset = ( ( offset + 0x03 ) & ~0x03 );
224
+	return offset;
225
+}
226
+
169 227
 /**
170 228
  * Load initrds, if any
171 229
  *
@@ -173,21 +231,16 @@ static int bzimage_set_cmdline ( struct image *image,
173 231
  * @v exec_ctx		Execution context
174 232
  * @ret rc		Return status code
175 233
  */
176
-static int bzimage_load_initrd ( struct image *image,
177
-				 struct bzimage_exec_context *exec_ctx ) {
234
+static int bzimage_load_initrds ( struct image *image,
235
+				  struct bzimage_exec_context *exec_ctx ) {
178 236
 	struct image *initrd;
179
-	size_t initrd_len;
180 237
 	size_t total_len = 0;
181
-	size_t offset = 0;
182
-	physaddr_t start;
238
+	physaddr_t address;
183 239
 	int rc;
184 240
 
185 241
 	/* Add up length of all initrd images */
186 242
 	for_each_image ( initrd ) {
187
-		if ( initrd->type != &initrd_image_type )
188
-			continue;
189
-		initrd_len = ( ( initrd->len + 0x0f ) & ~0x0f );
190
-		total_len += initrd_len;
243
+		total_len += bzimage_load_initrd ( image, initrd, UNULL );
191 244
 	}
192 245
 
193 246
 	/* Give up if no initrd images found */
@@ -198,47 +251,39 @@ static int bzimage_load_initrd ( struct image *image,
198 251
 	 * starting from the downloaded kernel image itself and
199 252
 	 * working downwards until we hit an available region.
200 253
 	 */
201
-	for ( start = ( user_to_phys ( image->data, 0 ) & ~0xfffff ) ; ;
202
-	      start -= 0x100000 ) {
254
+	for ( address = ( user_to_phys ( image->data, 0 ) & ~0xfffff ) ; ;
255
+	      address -= 0x100000 ) {
203 256
 		/* Check that we're not going to overwrite the
204 257
 		 * kernel itself.  This check isn't totally
205 258
 		 * accurate, but errs on the side of caution.
206 259
 		 */
207
-		if ( start <= ( BZI_LOAD_HIGH_ADDR + image->len ) ) {
260
+		if ( address <= ( BZI_LOAD_HIGH_ADDR + image->len ) ) {
208 261
 			DBGC ( image, "bzImage %p could not find a location "
209 262
 			       "for initrd\n", image );
210 263
 			return -ENOBUFS;
211 264
 		}
212 265
 		/* Check that we are within the kernel's range */
213
-		if ( ( start + total_len ) > exec_ctx->mem_limit )
266
+		if ( ( address + total_len ) > exec_ctx->mem_limit )
214 267
 			continue;
215 268
 		/* Prepare and verify segment */
216
-		if ( ( rc = prep_segment ( phys_to_user ( start ), 0,
269
+		if ( ( rc = prep_segment ( phys_to_user ( address ), 0,
217 270
 					   total_len ) ) != 0 )
218 271
 			continue;
219 272
 		/* Use this address */
220 273
 		break;
221 274
 	}
222 275
 
276
+	/* Record initrd location */
277
+	exec_ctx->ramdisk_image = address;
278
+	exec_ctx->ramdisk_size = total_len;
279
+
223 280
 	/* Construct initrd */
224 281
 	DBGC ( image, "bzImage %p constructing initrd at [%lx,%lx)\n",
225
-	       image, start, ( start + total_len ) );
282
+	       image, address, ( address + total_len ) );
226 283
 	for_each_image ( initrd ) {
227
-		if ( initrd->type != &initrd_image_type )
228
-			continue;
229
-		initrd_len = ( ( initrd->len + 0x0f ) & ~0x0f );
230
-		DBGC ( image, "bzImage %p has initrd %p at [%lx,%lx)\n",
231
-		       image, initrd, ( start + offset ),
232
-		       ( start + offset + initrd->len ) );
233
-		memcpy_user ( phys_to_user ( start ), offset,
234
-			      initrd->data, 0, initrd->len );
235
-		offset += initrd_len;
284
+		address += bzimage_load_initrd ( image, initrd,
285
+						 phys_to_user ( address ) );
236 286
 	}
237
-	assert ( offset == total_len );
238
-
239
-	/* Record initrd location */
240
-	exec_ctx->ramdisk_image = start;
241
-	exec_ctx->ramdisk_size = total_len;
242 287
 
243 288
 	return 0;
244 289
 }
@@ -281,7 +326,7 @@ static int bzimage_exec ( struct image *image ) {
281 326
 		return rc;
282 327
 
283 328
 	/* Load any initrds */
284
-	if ( ( rc = bzimage_load_initrd ( image, &exec_ctx ) ) != 0 )
329
+	if ( ( rc = bzimage_load_initrds ( image, &exec_ctx ) ) != 0 )
285 330
 		return rc;
286 331
 
287 332
 	/* Update and store kernel header */

+ 40
- 0
src/core/cpio.c View File

@@ -0,0 +1,40 @@
1
+/*
2
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+/** @file
20
+ *
21
+ * CPIO archives
22
+ *
23
+ */
24
+
25
+#include <stdio.h>
26
+#include <string.h>
27
+#include <gpxe/cpio.h>
28
+
29
+/**
30
+ * Set field within a CPIO header
31
+ *
32
+ * @v field		Field within CPIO header
33
+ * @v value		Value to set
34
+ */
35
+void cpio_set_field ( char *field, unsigned long value ) {
36
+	char buf[9];
37
+
38
+	snprintf ( buf, sizeof ( buf ), "%08lx", value );
39
+	memcpy ( field, buf, 8 );
40
+}

+ 51
- 0
src/include/gpxe/cpio.h View File

@@ -0,0 +1,51 @@
1
+#ifndef _GPXE_CPIO_H
2
+#define _GPXE_CPIO_H
3
+
4
+/** @file
5
+ *
6
+ * CPIO archives
7
+ *
8
+ */
9
+
10
+/** A CPIO archive header
11
+ *
12
+ * All field are hexadecimal ASCII numbers padded with '0' on the
13
+ * left to the full width of the field.
14
+ */
15
+struct cpio_header {
16
+	/** The string "070701" or "070702" */
17
+	char c_magic[6];
18
+	/** File inode number */
19
+	char c_ino[8];
20
+	/** File mode and permissions */
21
+	char c_mode[8];
22
+	/** File uid */
23
+	char c_uid[8];
24
+	/** File gid */
25
+	char c_gid[8];
26
+	/** Number of links */
27
+	char c_nlink[8];
28
+	/** Modification time */
29
+	char c_mtime[8];
30
+	/** Size of data field */
31
+	char c_filesize[8];
32
+	/** Major part of file device number */
33
+	char c_maj[8];
34
+	/** Minor part of file device number */
35
+	char c_min[8];
36
+	/** Major part of device node reference */
37
+	char c_rmaj[8];
38
+	/** Minor part of device node reference */
39
+	char c_rmin[8];
40
+	/** Length of filename, including final NUL */
41
+	char c_namesize[8];
42
+	/** Checksum of data field if c_magic is 070702, othersize zero */
43
+	char c_chksum[8];
44
+} __attribute__ (( packed ));
45
+
46
+/** CPIO magic */
47
+#define CPIO_MAGIC "070701"
48
+
49
+extern void cpio_set_field ( char *field, unsigned long value );
50
+
51
+#endif /* _GPXE_CPIO_H */

Loading…
Cancel
Save