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/>.
20
#include <grub/machine/memory.h>
21
#include <grub/memory.h>
22
#include <grub/misc.h>
23
#include <grub/term.h>
24
#include <grub/loader.h>
26
#define min(a,b) (((a) < (b)) ? (a) : (b))
28
static void *hooktarget = 0;
30
extern grub_uint8_t grub_machine_mmaphook_start;
31
extern grub_uint8_t grub_machine_mmaphook_end;
32
extern grub_uint8_t grub_machine_mmaphook_int12;
33
extern grub_uint8_t grub_machine_mmaphook_int15;
35
static grub_uint16_t grub_machine_mmaphook_int12offset = 0;
36
static grub_uint16_t grub_machine_mmaphook_int12segment = 0;
37
extern grub_uint16_t grub_machine_mmaphook_int15offset;
38
extern grub_uint16_t grub_machine_mmaphook_int15segment;
40
extern grub_uint16_t grub_machine_mmaphook_mmap_num;
41
extern grub_uint16_t grub_machine_mmaphook_kblow;
42
extern grub_uint16_t grub_machine_mmaphook_kbin16mb;
43
extern grub_uint16_t grub_machine_mmaphook_64kbin4gb;
45
struct grub_e820_mmap_entry
50
} __attribute__((packed));
54
preboot (int noreturn __attribute__ ((unused)))
56
struct grub_e820_mmap_entry *hookmmap, *hookmmapcur;
57
auto int NESTED_FUNC_ATTR fill_hook (grub_uint64_t, grub_uint64_t,
59
int NESTED_FUNC_ATTR fill_hook (grub_uint64_t addr, grub_uint64_t size,
62
grub_dprintf ("mmap", "mmap chunk %llx-%llx:%x\n", addr, addr + size, type);
63
hookmmapcur->addr = addr;
64
hookmmapcur->len = size;
65
hookmmapcur->type = type;
71
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
72
"no space is allocated for memory hook");
74
grub_dprintf ("mmap", "installing preboot handlers\n");
76
hookmmapcur = hookmmap = (struct grub_e820_mmap_entry *)
77
((grub_uint8_t *) hooktarget + (&grub_machine_mmaphook_end
78
- &grub_machine_mmaphook_start));
80
grub_mmap_iterate (fill_hook);
81
grub_machine_mmaphook_mmap_num = hookmmapcur - hookmmap;
83
grub_machine_mmaphook_kblow = grub_mmap_get_lower () >> 10;
84
grub_machine_mmaphook_kbin16mb
85
= min (grub_mmap_get_upper (),0x3f00000ULL) >> 10;
86
grub_machine_mmaphook_64kbin4gb
87
= min (grub_mmap_get_post64 (), 0xfc000000ULL) >> 16;
90
*((grub_uint16_t *) 0x413) = grub_mmap_get_lower () >> 10;
92
/* Save old interrupt handlers. */
93
grub_machine_mmaphook_int12offset = *((grub_uint16_t *) 0x48);
94
grub_machine_mmaphook_int12segment = *((grub_uint16_t *) 0x4a);
95
grub_machine_mmaphook_int15offset = *((grub_uint16_t *) 0x54);
96
grub_machine_mmaphook_int15segment = *((grub_uint16_t *) 0x56);
98
grub_dprintf ("mmap", "hooktarget = %p\n", hooktarget);
100
/* Install the interrupt handlers. */
101
grub_memcpy (hooktarget, &grub_machine_mmaphook_start,
102
&grub_machine_mmaphook_end - &grub_machine_mmaphook_start);
104
*((grub_uint16_t *) 0x4a) = PTR_TO_UINT32 (hooktarget) >> 4;
105
*((grub_uint16_t *) 0x56) = PTR_TO_UINT32 (hooktarget) >> 4;
106
*((grub_uint16_t *) 0x48) = &grub_machine_mmaphook_int12
107
- &grub_machine_mmaphook_start;
108
*((grub_uint16_t *) 0x54) = &grub_machine_mmaphook_int15
109
- &grub_machine_mmaphook_start;
111
return GRUB_ERR_NONE;
117
/* Restore old interrupt handlers. */
118
*((grub_uint16_t *) 0x48) = grub_machine_mmaphook_int12offset;
119
*((grub_uint16_t *) 0x4a) = grub_machine_mmaphook_int12segment;
120
*((grub_uint16_t *) 0x54) = grub_machine_mmaphook_int15offset;
121
*((grub_uint16_t *) 0x56) = grub_machine_mmaphook_int15segment;
123
return GRUB_ERR_NONE;
129
static int reentry = 0;
130
static int mmapregion = 0;
131
static int slots_available = 0;
134
auto int NESTED_FUNC_ATTR count_hook (grub_uint64_t, grub_uint64_t,
136
int NESTED_FUNC_ATTR count_hook (grub_uint64_t addr __attribute__ ((unused)),
137
grub_uint64_t size __attribute__ ((unused)),
138
grub_uint32_t type __attribute__ ((unused)))
145
return GRUB_ERR_NONE;
147
grub_dprintf ("mmap", "registering\n");
149
grub_mmap_iterate (count_hook);
151
/* Mapping hook itself may introduce up to 2 additional regions. */
154
if (regcount <= slots_available)
155
return GRUB_ERR_NONE;
159
grub_mmap_free_and_unregister (mmapregion);
164
hooksize = &grub_machine_mmaphook_end - &grub_machine_mmaphook_start
165
+ regcount * sizeof (struct grub_e820_mmap_entry);
166
/* Allocate an integer number of KiB. */
167
hooksize = ((hooksize - 1) | 0x3ff) + 1;
168
slots_available = (hooksize - (&grub_machine_mmaphook_end
169
- &grub_machine_mmaphook_start))
170
/ sizeof (struct grub_e820_mmap_entry);
174
= grub_mmap_malign_and_register (16, hooksize, &mmapregion,
175
GRUB_MACHINE_MEMORY_RESERVED,
176
GRUB_MMAP_MALLOC_LOW);
182
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "no space for mmap hook");
184
return GRUB_ERR_NONE;
188
grub_machine_mmap_register (grub_uint64_t start __attribute__ ((unused)),
189
grub_uint64_t size __attribute__ ((unused)),
190
int type __attribute__ ((unused)),
191
int handle __attribute__ ((unused)))
194
static void *preb_handle = 0;
196
err = malloc_hook ();
202
grub_dprintf ("mmap", "adding preboot\n");
204
= grub_loader_register_preboot_hook (preboot, preboot_rest,
205
GRUB_LOADER_PREBOOT_HOOK_PRIO_MEMORY);
209
return GRUB_ERR_NONE;
213
grub_machine_mmap_unregister (int handle __attribute__ ((unused)))
215
return GRUB_ERR_NONE;