2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2009 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
19 /* This is an emulation of EFI runtime services.
20 This allows a more uniform boot on i386 machines.
21 As it emulates only runtime service it isn't able
22 to chainload EFI bootloader on non-EFI system. */
25 #include <grub/file.h>
27 #include <grub/normal.h>
30 #include <grub/misc.h>
31 #include <grub/efiemu/efiemu.h>
32 #include <grub/machine/efiemu.h>
33 #include <grub/command.h>
34 #include <grub/cpu/cpuid.h>
36 /* System table. Two version depending on mode */
37 grub_efi_system_table32_t
*grub_efiemu_system_table32
= 0;
38 grub_efi_system_table64_t
*grub_efiemu_system_table64
= 0;
39 /* Modules may need to execute some actions after memory allocation happens */
40 static struct grub_efiemu_prepare_hook
*efiemu_prepare_hooks
= 0;
41 /* Linked list of configuration tables */
42 static struct grub_efiemu_configuration_table
*efiemu_config_tables
= 0;
44 /* Free all allocated space */
46 grub_efiemu_unload (void)
48 struct grub_efiemu_configuration_table
*cur
, *d
;
49 struct grub_efiemu_prepare_hook
*curhook
, *d2
;
50 grub_efiemu_loadcore_unload ();
52 grub_efiemu_mm_unload ();
54 for (cur
= efiemu_config_tables
; cur
;)
58 cur
->unload (cur
->data
);
62 efiemu_config_tables
= 0;
64 for (curhook
= efiemu_prepare_hooks
; curhook
;)
68 curhook
->unload (curhook
->data
);
72 efiemu_prepare_hooks
= 0;
77 /* Remove previously registered table from the list */
79 grub_efiemu_unregister_configuration_table (grub_efi_guid_t guid
)
81 struct grub_efiemu_configuration_table
*cur
, *prev
;
83 /* Special treating if head is to remove */
84 while (efiemu_config_tables
85 && !grub_memcmp (&(efiemu_config_tables
->guid
), &guid
, sizeof (guid
)))
87 if (efiemu_config_tables
->unload
)
88 efiemu_config_tables
->unload (efiemu_config_tables
->data
);
89 cur
= efiemu_config_tables
->next
;
90 grub_free (efiemu_config_tables
);
91 efiemu_config_tables
= cur
;
93 if (!efiemu_config_tables
)
96 /* Remove from chain */
97 for (prev
= efiemu_config_tables
, cur
= prev
->next
; cur
;)
98 if (grub_memcmp (&(cur
->guid
), &guid
, sizeof (guid
)) == 0)
101 cur
->unload (cur
->data
);
102 prev
->next
= cur
->next
;
111 return GRUB_ERR_NONE
;
115 grub_efiemu_register_prepare_hook (grub_err_t (*hook
) (void *data
),
116 void (*unload
) (void *data
),
119 struct grub_efiemu_prepare_hook
*nhook
;
121 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "you must supply the hook");
122 nhook
= (struct grub_efiemu_prepare_hook
*) grub_malloc (sizeof (*nhook
));
124 return grub_error (GRUB_ERR_OUT_OF_MEMORY
, "couldn't prepare hook");
126 nhook
->unload
= unload
;
128 nhook
->next
= efiemu_prepare_hooks
;
129 efiemu_prepare_hooks
= nhook
;
130 return GRUB_ERR_NONE
;
133 /* Register a configuration table either supplying the address directly
137 grub_efiemu_register_configuration_table (grub_efi_guid_t guid
,
138 void * (*get_table
) (void *data
),
139 void (*unload
) (void *data
),
142 struct grub_efiemu_configuration_table
*tbl
;
145 if (! get_table
&& ! data
)
146 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
147 "you must set at least get_table or data");
148 if ((err
= grub_efiemu_unregister_configuration_table (guid
)))
151 tbl
= (struct grub_efiemu_configuration_table
*) grub_malloc (sizeof (*tbl
));
153 return grub_error (GRUB_ERR_OUT_OF_MEMORY
, "couldn't register table");
156 tbl
->get_table
= get_table
;
157 tbl
->unload
= unload
;
159 tbl
->next
= efiemu_config_tables
;
160 efiemu_config_tables
= tbl
;
162 return GRUB_ERR_NONE
;
166 grub_cmd_efiemu_unload (grub_command_t cmd
__attribute__ ((unused
)),
167 int argc
__attribute__ ((unused
)),
168 char *args
[] __attribute__ ((unused
)))
170 return grub_efiemu_unload ();
174 grub_cmd_efiemu_prepare (grub_command_t cmd
__attribute__ ((unused
)),
175 int argc
__attribute__ ((unused
)),
176 char *args
[] __attribute__ ((unused
)))
178 return grub_efiemu_prepare ();
185 grub_efiemu_exit_boot_services (grub_efi_uintn_t map_key
186 __attribute__ ((unused
)))
188 /* Nothing to do here yet */
193 grub_efiemu_finish_boot_services (void)
195 /* Nothing to do here yet */
199 /* Load the runtime from the file FILENAME. */
201 grub_efiemu_load_file (const char *filename
)
206 file
= grub_file_open (filename
);
210 err
= grub_efiemu_mm_init ();
213 grub_file_close (file
);
214 grub_efiemu_unload ();
215 return grub_error (grub_errno
, "Couldn't init memory management");
218 grub_dprintf ("efiemu", "mm initialized\n");
220 err
= grub_efiemu_loadcore_init (file
);
223 grub_file_close (file
);
224 grub_efiemu_unload ();
228 grub_file_close (file
);
230 /* For configuration tables entry in system table. */
231 grub_efiemu_request_symbols (1);
233 return GRUB_ERR_NONE
;
237 grub_efiemu_autocore (void)
244 if (grub_efiemu_sizeof_uintn_t () != 0)
245 return GRUB_ERR_NONE
;
247 prefix
= grub_env_get ("prefix");
250 return grub_error (GRUB_ERR_FILE_NOT_FOUND
,
251 "couldn't find efiemu core because prefix "
254 longmode
= grub_i386_cpuid_has_longmode ();
256 filename
= grub_malloc (grub_strlen (prefix
) + sizeof ("efiemuXX.o") + 1);
258 return grub_error (GRUB_ERR_OUT_OF_MEMORY
,
259 "couldn't allocate temporary space");
263 grub_sprintf (filename
, "%s/efiemu64.o", prefix
);
264 err
= grub_efiemu_load_file (filename
);
267 if (! longmode
|| err
)
269 grub_sprintf (filename
, "%s/efiemu32.o", prefix
);
270 err
= grub_efiemu_load_file (filename
);
273 grub_free (filename
);
278 err
= grub_machine_efiemu_init_tables ();
283 return GRUB_ERR_NONE
;
287 grub_efiemu_prepare (void)
291 grub_dprintf ("efiemu", "Preparing %d-bit efiemu\n",
292 8 * grub_efiemu_sizeof_uintn_t ());
294 err
= grub_efiemu_autocore ();
296 /* Create NVRAM if not yet done. */
297 grub_efiemu_pnvram ();
299 if (grub_efiemu_sizeof_uintn_t () == 4)
300 return grub_efiemu_prepare32 (efiemu_prepare_hooks
, efiemu_config_tables
);
302 return grub_efiemu_prepare64 (efiemu_prepare_hooks
, efiemu_config_tables
);
307 grub_cmd_efiemu_load (grub_command_t cmd
__attribute__ ((unused
)),
308 int argc
, char *args
[])
312 grub_efiemu_unload ();
315 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "filename required");
317 err
= grub_efiemu_load_file (args
[0]);
321 err
= grub_machine_efiemu_init_tables ();
325 return GRUB_ERR_NONE
;
328 static grub_command_t cmd_loadcore
, cmd_prepare
, cmd_unload
;
331 grub_efiemu_pnvram_cmd_register (void);
333 GRUB_MOD_INIT(efiemu
)
335 cmd_loadcore
= grub_register_command ("efiemu_loadcore",
336 grub_cmd_efiemu_load
,
337 "efiemu_loadcore FILE",
338 "Load and initialize EFI emulator");
339 cmd_prepare
= grub_register_command ("efiemu_prepare",
340 grub_cmd_efiemu_prepare
,
342 "Finalize loading of EFI emulator");
343 cmd_unload
= grub_register_command ("efiemu_unload", grub_cmd_efiemu_unload
,
345 "Unload EFI emulator");
346 grub_efiemu_pnvram_cmd_register ();
349 GRUB_MOD_FINI(efiemu
)
351 grub_unregister_command (cmd_loadcore
);
352 grub_unregister_command (cmd_prepare
);
353 grub_unregister_command (cmd_unload
);
354 grub_efiemu_pnvram_cmd_unregister ();