2 * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
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 (at your option) any later version.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA
23 * EFI file system access
39 /** bootmgfw.efi path within WIM */
40 static const wchar_t bootmgfw_path
[] = L
"\\Windows\\Boot\\EFI\\bootmgfw.efi";
42 /** Other paths within WIM */
43 static const wchar_t *efi_wim_paths
[] = {
44 L
"\\Windows\\Boot\\DVD\\EFI\\boot.sdi",
45 L
"\\Windows\\Boot\\DVD\\EFI\\BCD",
46 L
"\\Windows\\Boot\\Fonts\\segmono_boot.ttf",
47 L
"\\Windows\\Boot\\Fonts\\segoen_slboot.ttf",
48 L
"\\Windows\\Boot\\Fonts\\segoe_slboot.ttf",
49 L
"\\Windows\\Boot\\Fonts\\wgl4_boot.ttf",
50 L
"\\sms\\boot\\boot.sdi",
54 /** bootmgfw.efi file */
55 struct vdisk_file
*bootmgfw
;
58 * Get architecture-specific boot filename
60 * @ret bootarch Architecture-specific boot filename
62 static const CHAR16
* efi_bootarch ( void ) {
63 static const CHAR16 bootarch_full
[] = EFI_REMOVABLE_MEDIA_FILE_NAME
;
65 const CHAR16
*bootarch
= bootarch_full
;
67 for ( tmp
= bootarch_full
; *tmp
; tmp
++ ) {
69 bootarch
= ( tmp
+ 1 );
77 * @v vfile Virtual file
82 static void efi_read_file ( struct vdisk_file
*vfile
, void *data
,
83 size_t offset
, size_t len
) {
85 EFI_FILE_PROTOCOL
*file
= vfile
->opaque
;
89 /* Set file position */
90 if ( ( efirc
= file
->SetPosition ( file
, offset
) ) != 0 ) {
91 die ( "Could not set file position: %#lx\n",
92 ( ( unsigned long ) efirc
) );
96 if ( ( efirc
= file
->Read ( file
, &size
, data
) ) != 0 ) {
97 die ( "Could not read from file: %#lx\n",
98 ( ( unsigned long ) efirc
) );
104 pfventoy_file_read((const char *)vfile
->opaque
, (int)offset
, (int)len
, data
);
110 * @v vfile Virtual file
111 * @v data Data buffer
115 static void efi_patch_bcd ( struct vdisk_file
*vfile __unused
, void *data
,
116 size_t offset
, size_t len
) {
117 static const wchar_t search
[] = L
".exe";
118 static const wchar_t replace
[] = L
".efi";
121 /* Do nothing if BCD patching is disabled */
122 if ( cmdline_rawbcd
)
125 /* Patch any occurrences of ".exe" to ".efi". In the common
126 * simple cases, this allows the same BCD file to be used for
127 * both BIOS and UEFI systems.
129 for ( i
= 0 ; ( i
+ sizeof ( search
) ) < len
; i
++ ) {
130 if ( wcscasecmp ( ( data
+ i
), search
) == 0 ) {
131 memcpy ( ( data
+ i
), replace
, sizeof ( replace
) );
132 DBG ( "...patched BCD at %#zx: \"%ls\" to \"%ls\"\n",
133 ( offset
+ i
), search
, replace
);
139 * Extract files from EFI file system
141 * @v handle Device handle
143 void efi_extract ( EFI_HANDLE handle
) {
144 struct vdisk_file
*wim
= NULL
;
145 struct vdisk_file
*vfile
;
153 /* Read root directory */
154 for (i
= 0; i
< cmdline_vf_num
; i
++) {
155 pos
= strchr(cmdline_vf_path
[i
], ':');
158 k
= (int)strlen(cmdline_vf_path
[i
]);
160 memset(wname
, 0, sizeof(wname
));
161 for (j
= 0; j
< k
; j
++)
163 wname
[j
] = cmdline_vf_path
[i
][j
];
166 len
= pfventoy_file_size(pos
+ 1);
167 vfile
= vdisk_add_file (cmdline_vf_path
[i
], pos
+ 1, len
, efi_read_file
);
169 /* Check for special-case files */
170 if ( ( wcscasecmp ( wname
, efi_bootarch() ) == 0 ) ||
171 ( wcscasecmp ( wname
, L
"bootmgfw.efi" ) == 0 ) ) {
172 DBG ( "...found bootmgfw.efi file %ls\n", wname
);
174 } else if ( wcscasecmp ( wname
, L
"BCD" ) == 0 ) {
175 DBG ( "...found BCD\n" );
176 vdisk_patch_file ( vfile
, efi_patch_bcd
);
177 } else if ( wcscasecmp ( ( wname
+ ( wcslen ( wname
) - 4 ) ),
179 DBG ( "...found WIM file %ls\n", wname
);
184 /* Process WIM image */
186 vdisk_patch_file ( wim
, patch_wim
);
187 if ( ( ! bootmgfw
) &&
188 ( bootmgfw
= wim_add_file ( wim
, cmdline_index
,
190 efi_bootarch() ) ) ) {
191 DBG ( "...extracted %ls\n", bootmgfw_path
);
193 wim_add_files ( wim
, cmdline_index
, efi_wim_paths
);
196 /* Check that we have a boot file */
198 die ( "FATAL: no %ls or bootmgfw.efi found\n",