2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 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 #include <grub/kernel.h>
21 #include <grub/machine/boot.h>
22 #include <grub/machine/init.h>
23 #include <grub/machine/memory.h>
24 #include <grub/machine/console.h>
25 #include <grub/machine/kernel.h>
26 #include <grub/types.h>
29 #include <grub/misc.h>
30 #include <grub/loader.h>
32 #include <grub/cache.h>
33 #include <grub/time.h>
34 #include <grub/cpu/tsc.h>
42 #define MAX_REGIONS 32
44 static struct mem_region mem_regions
[MAX_REGIONS
];
45 static int num_regions
;
47 grub_addr_t grub_os_area_addr
;
48 grub_size_t grub_os_area_size
;
51 make_install_device (void)
53 /* XXX: This should be enough. */
54 char dev
[100], *ptr
= dev
;
56 if (grub_prefix
[0] != '(')
58 /* No hardcoded root partition - make it from the boot drive and the
59 partition number encoded at the install time. */
60 if (grub_boot_drive
== GRUB_BOOT_MACHINE_PXE_DL
)
62 grub_strcpy (dev
, "(pxe");
63 ptr
+= sizeof ("(pxe") - 1;
67 grub_snprintf (dev
, sizeof (dev
),
68 "(%cd%u", (grub_boot_drive
& 0x80) ? 'h' : 'f',
69 grub_boot_drive
& 0x7f);
70 ptr
+= grub_strlen (ptr
);
72 if (grub_install_dos_part
>= 0)
73 grub_snprintf (ptr
, sizeof (dev
) - (ptr
- dev
),
74 ",%u", grub_install_dos_part
+ 1);
75 ptr
+= grub_strlen (ptr
);
77 if (grub_install_bsd_part
>= 0)
78 grub_snprintf (ptr
, sizeof (dev
) - (ptr
- dev
), ",%c",
79 grub_install_bsd_part
+ 'a');
80 ptr
+= grub_strlen (ptr
);
83 grub_snprintf (ptr
, sizeof (dev
) - (ptr
- dev
), ")%s", grub_prefix
);
84 grub_strcpy (grub_prefix
, dev
);
90 /* Add a memory region. */
92 add_mem_region (grub_addr_t addr
, grub_size_t size
)
94 if (num_regions
== MAX_REGIONS
)
98 mem_regions
[num_regions
].addr
= addr
;
99 mem_regions
[num_regions
].size
= size
;
103 /* Compact memory regions. */
105 compact_mem_regions (void)
110 for (i
= 0; i
< num_regions
- 1; i
++)
111 for (j
= i
+ 1; j
< num_regions
; j
++)
112 if (mem_regions
[i
].addr
> mem_regions
[j
].addr
)
114 struct mem_region tmp
= mem_regions
[i
];
115 mem_regions
[i
] = mem_regions
[j
];
116 mem_regions
[j
] = tmp
;
119 /* Merge overlaps. */
120 for (i
= 0; i
< num_regions
- 1; i
++)
121 if (mem_regions
[i
].addr
+ mem_regions
[i
].size
>= mem_regions
[i
+ 1].addr
)
125 if (mem_regions
[i
].addr
+ mem_regions
[i
].size
126 < mem_regions
[j
].addr
+ mem_regions
[j
].size
)
127 mem_regions
[i
].size
= (mem_regions
[j
].addr
+ mem_regions
[j
].size
128 - mem_regions
[i
].addr
);
130 grub_memmove (mem_regions
+ j
, mem_regions
+ j
+ 1,
131 (num_regions
- j
- 1) * sizeof (struct mem_region
));
138 grub_machine_init (void)
143 /* Initialize the console as early as possible. */
144 grub_console_init ();
146 grub_lower_mem
= grub_get_memsize (0) << 10;
149 if (grub_lower_mem
< GRUB_MEMORY_MACHINE_RESERVED_END
)
150 grub_fatal ("too small memory");
153 /* Turn on Gate A20 to access >1MB. */
157 /* FIXME: This prevents loader/i386/linux.c from using low memory. When our
158 heap implements support for requesting a chunk in low memory, this should
159 no longer be a problem. */
161 /* Add the lower memory into free memory. */
162 if (grub_lower_mem
>= GRUB_MEMORY_MACHINE_RESERVED_END
)
163 add_mem_region (GRUB_MEMORY_MACHINE_RESERVED_END
,
164 grub_lower_mem
- GRUB_MEMORY_MACHINE_RESERVED_END
);
167 auto int NESTED_FUNC_ATTR
hook (grub_uint64_t
, grub_uint64_t
, grub_uint32_t
);
168 int NESTED_FUNC_ATTR
hook (grub_uint64_t addr
, grub_uint64_t size
, grub_uint32_t type
)
170 /* Avoid the lower memory. */
173 if (size
<= 0x100000 - addr
)
176 size
-= 0x100000 - addr
;
181 if (addr
<= 0xFFFFFFFF && type
== GRUB_MACHINE_MEMORY_AVAILABLE
)
185 len
= (grub_size_t
) ((addr
+ size
> 0xFFFFFFFF)
188 add_mem_region (addr
, len
);
194 grub_machine_mmap_iterate (hook
);
196 compact_mem_regions ();
198 /* Add the memory regions to free memory, except for the region starting
199 from 1MB. This region is partially used for loading OS images.
200 For now, 1/4 of this is added to free memory. */
201 for (i
= 0; i
< num_regions
; i
++)
202 if (mem_regions
[i
].addr
== 0x100000)
204 grub_size_t quarter
= mem_regions
[i
].size
>> 2;
206 grub_os_area_addr
= mem_regions
[i
].addr
;
207 grub_os_area_size
= mem_regions
[i
].size
- quarter
;
208 grub_mm_init_region ((void *) (grub_os_area_addr
+ grub_os_area_size
),
212 grub_mm_init_region ((void *) mem_regions
[i
].addr
, mem_regions
[i
].size
);
214 if (! grub_os_area_addr
)
215 grub_fatal ("no upper memory");
221 grub_machine_set_prefix (void)
223 /* Initialize the prefix. */
224 grub_env_set ("prefix", make_install_device ());
228 grub_machine_fini (void)
230 grub_console_fini ();
234 /* Return the end of the core image. */
236 grub_arch_modules_addr (void)
238 return GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR
239 + (grub_kernel_image_size
- GRUB_KERNEL_MACHINE_RAW_SIZE
);