1 /* Code for managing symbols and pointers in efiemu */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2009 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
22 #include <grub/misc.h>
23 #include <grub/efiemu/efiemu.h>
24 #include <grub/efiemu/runtime.h>
26 static int ptv_written
= 0;
27 static int ptv_alloc
= 0;
28 static int ptv_handle
= 0;
29 static int ptv_requested
= 0;
30 static struct grub_efiemu_sym
*efiemu_syms
= 0;
32 struct grub_efiemu_sym
34 struct grub_efiemu_sym
*next
;
41 grub_efiemu_free_syms (void)
43 struct grub_efiemu_sym
*cur
, *d
;
44 for (cur
= efiemu_syms
; cur
;)
47 grub_free (cur
->name
);
55 grub_efiemu_mm_return_request (ptv_handle
);
59 /* Announce that the module will need NUM allocators */
60 /* Because of deferred memory allocation all the relocators have to be
61 announced during phase 1*/
63 grub_efiemu_request_symbols (int num
)
66 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
67 "symbols have already been allocated");
69 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
70 "can't request negative symbols");
75 /* Resolve the symbol name NAME and set HANDLE and OFF accordingly */
77 grub_efiemu_resolve_symbol (const char *name
, int *handle
, grub_off_t
*off
)
79 struct grub_efiemu_sym
*cur
;
80 for (cur
= efiemu_syms
; cur
; cur
= cur
->next
)
81 if (!grub_strcmp (name
, cur
->name
))
83 *handle
= cur
->handle
;
87 grub_dprintf ("efiemu", "%s not found\n", name
);
88 return grub_error (GRUB_ERR_BAD_OS
, "symbol %s isn't found", name
);
91 /* Register symbol named NAME in memory handle HANDLE at offset OFF */
93 grub_efiemu_register_symbol (const char *name
, int handle
, grub_off_t off
)
95 struct grub_efiemu_sym
*cur
;
96 cur
= (struct grub_efiemu_sym
*) grub_malloc (sizeof (*cur
));
97 grub_dprintf ("efiemu", "registering symbol '%s'\n", name
);
99 return grub_error (GRUB_ERR_OUT_OF_MEMORY
, "couldn't register symbol");
100 cur
->name
= grub_strdup (name
);
101 cur
->next
= efiemu_syms
;
102 cur
->handle
= handle
;
109 /* Go from phase 1 to phase 2. Must be called before similar function in mm.c */
111 grub_efiemu_alloc_syms (void)
113 ptv_alloc
= ptv_requested
;
114 ptv_handle
= grub_efiemu_request_memalign
115 (1, (ptv_requested
+ 1) * sizeof (struct grub_efiemu_ptv_rel
),
116 GRUB_EFI_RUNTIME_SERVICES_DATA
);
117 grub_efiemu_register_symbol ("efiemu_ptv_relloc", ptv_handle
, 0);
121 /* Write value (pointer to memory PLUS_HANDLE)
122 - (pointer to memory MINUS_HANDLE) + VALUE to ADDR assuming that the
123 size SIZE bytes. If PTV_NEEDED is 1 then announce it to runtime that this
124 value needs to be recomputed before going to virtual mode
127 grub_efiemu_write_value (void *addr
, grub_uint32_t value
, int plus_handle
,
128 int minus_handle
, int ptv_needed
, int size
)
130 /* Announce relocator to runtime */
133 struct grub_efiemu_ptv_rel
*ptv_rels
134 = grub_efiemu_mm_obtain_request (ptv_handle
);
136 if (ptv_needed
&& ptv_written
>= ptv_alloc
)
137 return grub_error (GRUB_ERR_OUT_OF_MEMORY
,
138 "your module didn't declare efiemu "
139 " relocators correctly");
142 ptv_rels
[ptv_written
].minustype
143 = grub_efiemu_mm_get_type (minus_handle
);
145 ptv_rels
[ptv_written
].minustype
= 0;
148 ptv_rels
[ptv_written
].plustype
149 = grub_efiemu_mm_get_type (plus_handle
);
151 ptv_rels
[ptv_written
].plustype
= 0;
153 ptv_rels
[ptv_written
].addr
= PTR_TO_UINT64 (addr
);
154 ptv_rels
[ptv_written
].size
= size
;
157 /* memset next value to zero to mark the end */
158 grub_memset (&ptv_rels
[ptv_written
], 0, sizeof (ptv_rels
[ptv_written
]));
161 /* Compute the value */
163 value
-= PTR_TO_UINT32 (grub_efiemu_mm_obtain_request (minus_handle
));
166 value
+= PTR_TO_UINT32 (grub_efiemu_mm_obtain_request (plus_handle
));
168 /* Write the value */
172 *((grub_uint64_t
*) addr
) = value
;
175 *((grub_uint32_t
*) addr
) = value
;
178 *((grub_uint16_t
*) addr
) = value
;
181 *((grub_uint8_t
*) addr
) = value
;
184 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "wrong symbol size");
187 return GRUB_ERR_NONE
;