Skip to content

Commit 7f42b27

Browse files
committed
[patch] Patch the WIM image to include additional files
Add the ability to dynamically patch the WIM file to cause additional files to appear within the filesystem as seen by Windows. We do this by creating a new boot image metadata resource in which the directory \Windows\System32 includes additional directory entries for each file visible to wimboot (excluding any BCD, .sdi, or .wim files). This allows the boot process to be modified using e.g. a winpeshl.ini file dynamically generated by a web server. For example: #!ipxe kernel /wimboot initrd /media/Boot/BCD BCD initrd /media/Boot/boot.sdi boot.sdi initrd /media/sources/boot.wim boot.wim boot.wim initrd /cgi-bin/winpeshl.ini?mac=${mac} winpeshl.ini boot Signed-off-by: Michael Brown <mbrown@fensystems.co.uk>
1 parent 9285750 commit 7f42b27

File tree

9 files changed

+862
-57
lines changed

9 files changed

+862
-57
lines changed

src/cmdline.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
/** Use raw (unpatched) BCD files */
3636
int cmdline_rawbcd;
3737

38+
/** Use raw (unpatched) WIM files */
39+
int cmdline_rawwim;
40+
3841
/** Allow graphical output from bootmgr/bootmgfw */
3942
int cmdline_gui;
4043

@@ -88,6 +91,8 @@ void process_cmdline ( char *cmdline ) {
8891
/* Process this argument */
8992
if ( strcmp ( key, "rawbcd" ) == 0 ) {
9093
cmdline_rawbcd = 1;
94+
} else if ( strcmp ( key, "rawwim" ) == 0 ) {
95+
cmdline_rawwim = 1;
9196
} else if ( strcmp ( key, "gui" ) == 0 ) {
9297
cmdline_gui = 1;
9398
} else if ( strcmp ( key, "pause" ) == 0 ) {

src/cmdline.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
*/
2929

3030
extern int cmdline_rawbcd;
31+
extern int cmdline_rawwim;
3132
extern int cmdline_gui;
3233
extern int cmdline_pause;
3334
extern int cmdline_pause_quiet;

src/script.lds

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,23 +67,21 @@ SECTIONS {
6767

6868
/* bootmgr.exe hardcodes the address 0x30000 for use as a
6969
* buffer accessible by real-mode code. We can't fit our
70-
* code, data, and stack below this region, so explicitly
71-
* place the stack higher in memory.
70+
* .text, .data, and .bss below this region, so explicitly
71+
* place the .bss higher in memory.
7272
*/
7373
_forbidden_start = 0x30000;
7474
_forbidden_end = 0x40000;
7575

7676
/* Uninitialised data section */
7777
.bss ( NOLOAD ) : {
7878
_bss = .;
79-
*(.bss)
80-
*(.bss.*)
81-
*(COMMON)
82-
8379
ASSERT ( ABSOLUTE ( . ) <= ABSOLUTE ( _forbidden_start ),
8480
"Binary is too large" );
8581
. = ABSOLUTE ( _forbidden_end );
86-
82+
*(.bss)
83+
*(.bss.*)
84+
*(COMMON)
8785
*(.stack)
8886
*(.stack.*)
8987
. = ALIGN ( alignment );

src/vdisk.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
#include "vdisk.h"
3333

3434
/** Virtual files */
35-
static struct vdisk_file vdisk_files[VDISK_MAX_FILES];
35+
struct vdisk_file vdisk_files[VDISK_MAX_FILES];
3636

3737
/**
3838
* Read from virtual Master Boot Record

src/vdisk.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,8 @@ struct vdisk_file {
600600
size_t len );
601601
};
602602

603+
extern struct vdisk_file vdisk_files[VDISK_MAX_FILES];
604+
603605
extern void vdisk_read ( uint64_t lba, unsigned int count, void *data );
604606
extern struct vdisk_file *
605607
vdisk_add_file ( const char *name, void *opaque, size_t len,

src/wim.c

Lines changed: 112 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -285,10 +285,45 @@ int wim_read ( struct vdisk_file *file, struct wim_header *header,
285285
return 0;
286286
}
287287

288+
/**
289+
* Get number of images
290+
*
291+
* @v file Virtual file
292+
* @v header WIM header
293+
* @v count Count of images to fill in
294+
* @ret rc Return status code
295+
*/
296+
int wim_count ( struct vdisk_file *file, struct wim_header *header,
297+
unsigned int *count ) {
298+
struct wim_lookup_entry entry;
299+
size_t offset;
300+
int rc;
301+
302+
/* Count metadata entries */
303+
for ( offset = 0 ; ( offset + sizeof ( entry ) ) <= header->lookup.len ;
304+
offset += sizeof ( entry ) ) {
305+
306+
/* Read entry */
307+
if ( ( rc = wim_read ( file, header, &header->lookup, &entry,
308+
offset, sizeof ( entry ) ) ) != 0 )
309+
return rc;
310+
311+
/* Check for metadata entries */
312+
if ( entry.resource.zlen__flags & WIM_RESHDR_METADATA ) {
313+
(*count)++;
314+
DBG2 ( "...found image %d metadata at +%#zx\n",
315+
*count, offset );
316+
}
317+
}
318+
319+
return 0;
320+
}
321+
288322
/**
289323
* Get WIM image metadata
290324
*
291325
* @v file Virtual file
326+
* @v header WIM header
292327
* @v index Image index, or 0 to use boot image
293328
* @v meta Metadata to fill in
294329
* @ret rc Return status code
@@ -318,8 +353,8 @@ int wim_metadata ( struct vdisk_file *file, struct wim_header *header,
318353
/* Look for our target entry */
319354
if ( entry.resource.zlen__flags & WIM_RESHDR_METADATA ) {
320355
found++;
321-
DBG ( "...found image %d metadata at +%#zx\n",
322-
found, offset );
356+
DBG2 ( "...found image %d metadata at +%#zx\n",
357+
found, offset );
323358
if ( found == index ) {
324359
memcpy ( meta, &entry.resource,
325360
sizeof ( *meta ) );
@@ -339,23 +374,23 @@ int wim_metadata ( struct vdisk_file *file, struct wim_header *header,
339374
* @v file Virtual file
340375
* @v header WIM header
341376
* @v meta Metadata
342-
* @v offset Directory offset
343377
* @v name Name
378+
* @v offset Directory offset (will be updated)
344379
* @v direntry Directory entry to fill in
345380
* @ret rc Return status code
346381
*/
347382
static int wim_direntry ( struct vdisk_file *file, struct wim_header *header,
348-
struct wim_resource_header *meta, size_t offset,
349-
const wchar_t *name,
383+
struct wim_resource_header *meta,
384+
const wchar_t *name, size_t *offset,
350385
struct wim_directory_entry *direntry ) {
351386
wchar_t name_buf[ wcslen ( name ) + 1 /* NUL */ ];
352387
int rc;
353388

354389
/* Search directory */
355-
for ( ; ; offset += direntry->len ) {
390+
for ( ; ; *offset += direntry->len ) {
356391

357392
/* Read length field */
358-
if ( ( rc = wim_read ( file, header, meta, direntry, offset,
393+
if ( ( rc = wim_read ( file, header, meta, direntry, *offset,
359394
sizeof ( direntry->len ) ) ) != 0 )
360395
return rc;
361396

@@ -366,7 +401,7 @@ static int wim_direntry ( struct vdisk_file *file, struct wim_header *header,
366401
}
367402

368403
/* Read fixed-length portion of directory entry */
369-
if ( ( rc = wim_read ( file, header, meta, direntry, offset,
404+
if ( ( rc = wim_read ( file, header, meta, direntry, *offset,
370405
sizeof ( *direntry ) ) ) != 0 )
371406
return rc;
372407

@@ -376,7 +411,7 @@ static int wim_direntry ( struct vdisk_file *file, struct wim_header *header,
376411

377412
/* Read name */
378413
if ( ( rc = wim_read ( file, header, meta, &name_buf,
379-
( offset + sizeof ( *direntry ) ),
414+
( *offset + sizeof ( *direntry ) ),
380415
sizeof ( name_buf ) ) ) != 0 )
381416
return rc;
382417

@@ -390,23 +425,21 @@ static int wim_direntry ( struct vdisk_file *file, struct wim_header *header,
390425
}
391426

392427
/**
393-
* Get file resource
428+
* Get directory entry for a path
394429
*
395430
* @v file Virtual file
396431
* @v header WIM header
397432
* @v meta Metadata
398-
* @v path Path to file
399-
* @v resource File resource to fill in
433+
* @v path Path to file/directory
434+
* @v offset Directory entry offset to fill in
435+
* @v direntry Directory entry to fill in
400436
* @ret rc Return status code
401437
*/
402-
int wim_file ( struct vdisk_file *file, struct wim_header *header,
438+
int wim_path ( struct vdisk_file *file, struct wim_header *header,
403439
struct wim_resource_header *meta, const wchar_t *path,
404-
struct wim_resource_header *resource ) {
440+
size_t *offset, struct wim_directory_entry *direntry ) {
405441
wchar_t path_copy[ wcslen ( path ) + 1 /* WNUL */ ];
406442
struct wim_security_header security;
407-
struct wim_directory_entry direntry;
408-
struct wim_lookup_entry entry;
409-
size_t offset;
410443
wchar_t *name;
411444
wchar_t *next;
412445
int rc;
@@ -417,22 +450,48 @@ int wim_file ( struct vdisk_file *file, struct wim_header *header,
417450
return rc;
418451

419452
/* Get root directory offset */
420-
offset = ( ( security.len + sizeof ( uint64_t ) - 1 ) &
421-
~( sizeof ( uint64_t ) - 1 ) );
453+
direntry->subdir = ( ( security.len + sizeof ( uint64_t ) - 1 ) &
454+
~( sizeof ( uint64_t ) - 1 ) );
422455

423456
/* Find directory entry */
424457
name = memcpy ( path_copy, path, sizeof ( path_copy ) );
425458
do {
426459
next = wcschr ( name, L'\\' );
427460
if ( next )
428461
*next = L'\0';
429-
if ( ( rc = wim_direntry ( file, header, meta, offset, name,
430-
&direntry ) ) != 0 )
462+
*offset = direntry->subdir;
463+
if ( ( rc = wim_direntry ( file, header, meta, name, offset,
464+
direntry ) ) != 0 )
431465
return rc;
432-
offset = direntry.subdir;
433466
name = ( next + 1 );
434467
} while ( next );
435468

469+
return 0;
470+
}
471+
472+
/**
473+
* Get file resource
474+
*
475+
* @v file Virtual file
476+
* @v header WIM header
477+
* @v meta Metadata
478+
* @v path Path to file
479+
* @v resource File resource to fill in
480+
* @ret rc Return status code
481+
*/
482+
int wim_file ( struct vdisk_file *file, struct wim_header *header,
483+
struct wim_resource_header *meta, const wchar_t *path,
484+
struct wim_resource_header *resource ) {
485+
struct wim_directory_entry direntry;
486+
struct wim_lookup_entry entry;
487+
size_t offset;
488+
int rc;
489+
490+
/* Find directory entry */
491+
if ( ( rc = wim_path ( file, header, meta, path, &offset,
492+
&direntry ) ) != 0 )
493+
return rc;
494+
436495
/* File matching file entry */
437496
for ( offset = 0 ; ( offset + sizeof ( entry ) ) <= header->lookup.len ;
438497
offset += sizeof ( entry ) ) {
@@ -455,3 +514,34 @@ int wim_file ( struct vdisk_file *file, struct wim_header *header,
455514
DBG ( "Cannot find file %ls\n", path );
456515
return -1;
457516
}
517+
518+
/**
519+
* Get length of a directory
520+
*
521+
* @v file Virtual file
522+
* @v header WIM header
523+
* @v meta Metadata
524+
* @v offset Directory offset
525+
* @v len Directory length to fill in (excluding terminator)
526+
* @ret rc Return status code
527+
*/
528+
int wim_dir_len ( struct vdisk_file *file, struct wim_header *header,
529+
struct wim_resource_header *meta, size_t offset,
530+
size_t *len ) {
531+
struct wim_directory_entry direntry;
532+
int rc;
533+
534+
/* Search directory */
535+
for ( *len = 0 ; ; *len += direntry.len ) {
536+
537+
/* Read length field */
538+
if ( ( rc = wim_read ( file, header, meta, &direntry,
539+
( offset + *len ),
540+
sizeof ( direntry.len ) ) ) != 0 )
541+
return rc;
542+
543+
/* Check for end of this directory */
544+
if ( ! direntry.len )
545+
return 0;
546+
}
547+
}

src/wim.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,14 +166,31 @@ struct wim_directory_entry {
166166
uint16_t name_len;
167167
} __attribute__ (( packed ));
168168

169+
/** Normal file */
170+
#define WIM_ATTR_NORMAL 0x00000080UL
171+
172+
/** No security information exists for this file */
173+
#define WIM_NO_SECURITY 0xffffffffUL
174+
175+
/** Windows complains if the time fields are left at zero */
176+
#define WIM_MAGIC_TIME 0x1a7b83d2ad93000ULL
177+
169178
extern int wim_header ( struct vdisk_file *file, struct wim_header *header );
179+
extern int wim_count ( struct vdisk_file *file, struct wim_header *header,
180+
unsigned int *count );
170181
extern int wim_metadata ( struct vdisk_file *file, struct wim_header *header,
171182
unsigned int index, struct wim_resource_header *meta);
172183
extern int wim_read ( struct vdisk_file *file, struct wim_header *header,
173184
struct wim_resource_header *resource, void *data,
174185
size_t offset, size_t len );
186+
extern int wim_path ( struct vdisk_file *file, struct wim_header *header,
187+
struct wim_resource_header *meta, const wchar_t *path,
188+
size_t *offset, struct wim_directory_entry *direntry );
175189
extern int wim_file ( struct vdisk_file *file, struct wim_header *header,
176190
struct wim_resource_header *meta, const wchar_t *path,
177191
struct wim_resource_header *resource );
192+
extern int wim_dir_len ( struct vdisk_file *file, struct wim_header *header,
193+
struct wim_resource_header *meta, size_t offset,
194+
size_t *len );
178195

179196
#endif /* _WIM_H */

src/wimboot.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@
6262
#include <stdint.h>
6363
#include <bootapp.h>
6464

65+
/** Construct wide-character version of a string constant */
66+
#define L( x ) _L ( x )
67+
#define _L( x ) L ## x
68+
6569
/** Page size */
6670
#define PAGE_SIZE 4096
6771

0 commit comments

Comments
 (0)