source: grub-pc/trunk/fuentes/.pc/install_powerpc_machtypes.patch/grub-core/osdep/windows/platform.c @ 22

Last change on this file since 22 was 22, checked in by mabarracus, 4 years ago

updated version and apply net.ifnames=0 into debian/rules

File size: 12.2 KB
Line 
1/*
2 *  GRUB  --  GRand Unified Bootloader
3 *  Copyright (C) 2013  Free Software Foundation, Inc.
4 *
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.
9 *
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.
14 *
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/>.
17 */
18
19#include <config-util.h>
20
21#include <windows.h>
22#include <grub/util/install.h>
23#include <grub/util/misc.h>
24#include <grub/efi/api.h>
25#include <grub/charset.h>
26#include <grub/gpt_partition.h>
27
28#define GRUB_EFI_GLOBAL_VARIABLE_GUID_WINDOWS_STR L"{8be4df61-93ca-11d2-aa0d-00e098032b8c}"
29
30static enum { PLAT_UNK, PLAT_BIOS, PLAT_EFI } platform;
31static DWORD (WINAPI * func_GetFirmwareEnvironmentVariableW) (LPCWSTR lpName,
32                                                              LPCWSTR lpGuid,
33                                                              PVOID pBuffer,
34                                                              DWORD nSize);
35static BOOL (WINAPI * func_SetFirmwareEnvironmentVariableW) (LPCWSTR lpName,
36                                                             LPCWSTR lpGuid,
37                                                             PVOID pBuffer,
38                                                             DWORD nSize);
39static void (WINAPI * func_GetNativeSystemInfo) (LPSYSTEM_INFO lpSystemInfo);
40
41static int
42get_efi_privilegies (void)
43{
44  int ret = 1;
45  HANDLE hSelf;
46  TOKEN_PRIVILEGES tkp;
47
48  if (!OpenProcessToken (GetCurrentProcess(),
49                         TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hSelf))
50    return 0;
51
52  LookupPrivilegeValue (NULL, SE_SYSTEM_ENVIRONMENT_NAME,
53                        &tkp.Privileges[0].Luid);
54  tkp.PrivilegeCount = 1;
55  tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
56  if (!AdjustTokenPrivileges (hSelf, FALSE, &tkp, 0, NULL, 0))
57    ret = 0;
58  if (GetLastError () != ERROR_SUCCESS)
59    ret = 0;
60  CloseHandle (hSelf);
61  return 1;
62}
63
64static void
65get_platform (void)
66{
67  HMODULE kernel32;
68  char buffer[256];
69
70  if (platform != PLAT_UNK)
71    return;
72
73  kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
74  if (!kernel32)
75    {
76      platform = PLAT_BIOS;
77      return;
78    }
79
80  func_GetFirmwareEnvironmentVariableW = (void *)
81    GetProcAddress (kernel32, "GetFirmwareEnvironmentVariableW");
82  func_SetFirmwareEnvironmentVariableW = (void *)
83    GetProcAddress (kernel32, "SetFirmwareEnvironmentVariableW");
84  func_GetNativeSystemInfo = (void *)
85    GetProcAddress (kernel32, "GetNativeSystemInfo");
86  if (!func_GetNativeSystemInfo)
87    func_GetNativeSystemInfo = GetSystemInfo;
88  if (!func_GetFirmwareEnvironmentVariableW
89      || !func_SetFirmwareEnvironmentVariableW)
90    {
91      platform = PLAT_BIOS;
92      return;
93    }
94
95  if (!get_efi_privilegies ())
96    {
97      grub_util_warn (_("Insufficient privileges to access firmware, assuming BIOS"));
98      platform = PLAT_BIOS;
99    }
100
101  if (!func_GetFirmwareEnvironmentVariableW (L"BootOrder", GRUB_EFI_GLOBAL_VARIABLE_GUID_WINDOWS_STR,
102                                             buffer, sizeof (buffer))
103      && GetLastError () != ERROR_INVALID_FUNCTION)
104    {
105      platform = PLAT_BIOS;
106      return;
107    }   
108  platform = PLAT_EFI;
109  return;
110}
111
112const char *
113grub_install_get_default_x86_platform (void)
114{ 
115  SYSTEM_INFO si;
116
117  get_platform ();
118  if (platform != PLAT_EFI)
119    return "i386-pc";
120
121  /* EFI */
122  /* Assume 64-bit in case of failure.  */
123  si.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64;
124  func_GetNativeSystemInfo (&si);
125  if (si.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL)
126    return "x86_64-efi";
127  else
128    return "i386-efi";
129}
130
131static void *
132get_efi_variable (const wchar_t *varname, ssize_t *len)
133{
134  void *ret = NULL;
135  size_t alloc_size = 256, read_size;
136  get_platform ();
137  while (1)
138    {
139      DWORD err;
140      ret = xmalloc (alloc_size);
141      read_size = func_GetFirmwareEnvironmentVariableW (varname, GRUB_EFI_GLOBAL_VARIABLE_GUID_WINDOWS_STR,
142                                                        ret, alloc_size);
143      err = GetLastError ();
144      if (read_size)
145        {
146          *len = read_size;
147          return ret;
148        }
149      if (err == ERROR_INSUFFICIENT_BUFFER
150          && alloc_size * 2 != 0)
151        {
152          alloc_size *= 2;
153          free (ret);
154          continue;
155        }
156      if (err == ERROR_ENVVAR_NOT_FOUND)
157        {
158          *len = -1;
159          return NULL;
160        }
161      *len = -2;
162      return NULL;
163    }
164}
165
166static void
167set_efi_variable (const wchar_t *varname, void *in, grub_size_t len)
168{
169  get_platform ();
170  func_SetFirmwareEnvironmentVariableW (varname, GRUB_EFI_GLOBAL_VARIABLE_GUID_WINDOWS_STR,
171                                        in, len);
172}
173
174static char
175bin2hex (int v)
176{
177  if (v < 10)
178    return '0' + v;
179  return 'A' + v - 10;
180}
181
182static void *
183get_efi_variable_bootn (grub_uint16_t n, ssize_t *len)
184{
185  wchar_t varname[20] = L"Boot0000";
186  varname[7] = bin2hex (n & 0xf);
187  varname[6] = bin2hex ((n >> 4) & 0xf);
188  varname[5] = bin2hex ((n >> 8) & 0xf);
189  varname[4] = bin2hex ((n >> 12) & 0xf);
190  return get_efi_variable (varname, len);
191}
192
193static void
194set_efi_variable_bootn (grub_uint16_t n, void *in, grub_size_t len)
195{
196  wchar_t varname[20] = L"Boot0000";
197  varname[7] = bin2hex (n & 0xf);
198  varname[6] = bin2hex ((n >> 4) & 0xf);
199  varname[5] = bin2hex ((n >> 8) & 0xf);
200  varname[4] = bin2hex ((n >> 12) & 0xf);
201  set_efi_variable (varname, in, len);
202}
203
204void
205grub_install_register_efi (grub_device_t efidir_grub_dev,
206                           const char *efifile_path,
207                           const char *efi_distributor)
208{
209  grub_uint16_t *boot_order, *new_boot_order;
210  grub_uint16_t *distributor16;
211  grub_uint8_t *entry;
212  grub_size_t distrib8_len, distrib16_len, path16_len, path8_len;
213  ssize_t boot_order_len, new_boot_order_len;
214  grub_uint16_t order_num = 0;
215  int have_order_num = 0;
216  grub_size_t max_path_length;
217  grub_uint8_t *path;
218  void *pathptr;
219  struct grub_efi_hard_drive_device_path *hddp;
220  struct grub_efi_file_path_device_path *filep;
221  struct grub_efi_device_path *endp;
222
223  get_platform ();
224  if (platform != PLAT_EFI)
225    grub_util_error ("%s", _("no EFI routines are available when running in BIOS mode"));
226
227  distrib8_len = grub_strlen (efi_distributor);
228  distributor16 = xmalloc ((distrib8_len + 1) * GRUB_MAX_UTF16_PER_UTF8
229                           * sizeof (grub_uint16_t));
230  distrib16_len = grub_utf8_to_utf16 (distributor16, distrib8_len * GRUB_MAX_UTF16_PER_UTF8,
231                                      (const grub_uint8_t *) efi_distributor,
232                                      distrib8_len, 0);
233  distributor16[distrib16_len] = 0;
234
235  /* Windows doesn't allow to list variables so first look for bootorder to
236     find if there is an entry from the same distributor. If not try sequentially
237     until we find same distributor or empty spot.  */
238  boot_order = get_efi_variable (L"BootOrder", &boot_order_len);
239  if (boot_order_len < -1)
240    grub_util_error ("%s", _("unexpected EFI error"));
241  if (boot_order_len > 0)
242    {
243      size_t i;
244      for (i = 0; i < boot_order_len / 2; i++)
245        {
246          void *current = NULL;
247          ssize_t current_len;
248          current = get_efi_variable_bootn (i, &current_len);
249          if (current_len < 0)
250            continue; /* FIXME Should we abort on error? */
251          if (current_len < (distrib16_len + 1) * sizeof (grub_uint16_t)
252              + 6)
253            {
254              grub_free (current);
255              continue;
256            }
257          if (grub_memcmp ((grub_uint16_t *) current + 3,
258                           distributor16,
259                           (distrib16_len + 1) * sizeof (grub_uint16_t)) != 0)
260            {
261              grub_free (current);
262              continue;
263            }
264          order_num = i;
265          have_order_num = 1;
266          grub_util_info ("Found matching distributor at Boot%04x",
267                          order_num);
268          grub_free (current);
269          break;
270        }
271    }
272  if (!have_order_num)
273    {
274      size_t i;
275      for (i = 0; i < 0x10000; i++)
276        {
277          void *current = NULL;
278          ssize_t current_len;
279          current = get_efi_variable_bootn (i, &current_len);
280          if (current_len < -1)
281            continue; /* FIXME Should we abort on error? */
282          if (current_len == -1)
283            {
284              if (!have_order_num)
285                {
286                  order_num = i;
287                  have_order_num = 1;
288                  grub_util_info ("Creating new entry at Boot%04x",
289                                  order_num);
290                }
291              continue;
292            }
293          if (current_len < (distrib16_len + 1) * sizeof (grub_uint16_t)
294              + 6)
295            {
296              grub_free (current);
297              continue;
298            }
299          if (grub_memcmp ((grub_uint16_t *) current + 3,
300                           distributor16,
301                           (distrib16_len + 1) * sizeof (grub_uint16_t)) != 0)
302            {
303              grub_free (current);
304              continue;
305            }
306          order_num = i;
307          have_order_num = 1;
308          grub_util_info ("Found matching distributor at Boot%04x",
309                          order_num);
310          grub_free (current);
311          break;
312        }
313    }
314  if (!have_order_num)
315    grub_util_error ("%s", _("Couldn't find a free BootNNNN slot"));
316  path8_len = grub_strlen (efifile_path);
317  max_path_length = sizeof (*hddp) + sizeof (*filep) + (path8_len * GRUB_MAX_UTF16_PER_UTF8 + 1) * sizeof (grub_uint16_t) + sizeof (*endp);
318  entry = xmalloc (6 + (distrib16_len + 1) * sizeof (grub_uint16_t) + max_path_length);
319  /* attributes: active.  */
320  entry[0] = 1;
321  entry[1] = 0;
322  entry[2] = 0;
323  entry[3] = 0;
324  grub_memcpy (entry + 6,
325               distributor16,
326               (distrib16_len + 1) * sizeof (grub_uint16_t));
327
328  path = entry + 6 + (distrib16_len + 1) * sizeof (grub_uint16_t);
329  pathptr = path;
330
331  hddp = pathptr;
332  grub_memset (hddp, 0, sizeof (*hddp));
333  hddp->header.type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE;
334  hddp->header.subtype = GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE;
335  hddp->header.length = sizeof (*hddp);
336  hddp->partition_number = efidir_grub_dev->disk->partition ? efidir_grub_dev->disk->partition->number + 1 : 1;
337  if (efidir_grub_dev->disk->partition
338      && grub_strcmp (efidir_grub_dev->disk->partition->partmap->name, "msdos") == 0)
339    {
340      grub_partition_t p;
341
342      p = efidir_grub_dev->disk->partition;
343      efidir_grub_dev->disk->partition = p->parent;
344      if (grub_disk_read (efidir_grub_dev->disk, 0, 440,
345                          4, hddp->partition_signature))
346        grub_util_error ("%s", grub_errmsg);
347      efidir_grub_dev->disk->partition = p;
348
349      hddp->partmap_type = 1;
350      hddp->signature_type = 1;
351    }
352  else if (efidir_grub_dev->disk->partition
353           && grub_strcmp (efidir_grub_dev->disk->partition->partmap->name, "gpt") == 0)
354    {
355      struct grub_gpt_partentry gptdata;
356      grub_partition_t p;
357
358      p = efidir_grub_dev->disk->partition;
359      efidir_grub_dev->disk->partition = p->parent;
360      if (grub_disk_read (efidir_grub_dev->disk,
361                          p->offset, p->index,
362                          sizeof (gptdata), &gptdata))
363        grub_util_error ("%s", grub_errmsg);
364      efidir_grub_dev->disk->partition = p;
365      grub_memcpy (hddp->partition_signature,
366                   gptdata.guid, 16);
367
368      hddp->partmap_type = 2;
369      hddp->signature_type = 2;
370    }
371
372  hddp->partition_start = grub_partition_get_start (efidir_grub_dev->disk->partition)
373    << (efidir_grub_dev->disk->log_sector_size - GRUB_DISK_SECTOR_BITS);
374  hddp->partition_size = grub_disk_get_size (efidir_grub_dev->disk)
375    << (efidir_grub_dev->disk->log_sector_size - GRUB_DISK_SECTOR_BITS);
376
377  pathptr = hddp + 1;
378  filep = pathptr;
379  filep->header.type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE;
380  filep->header.subtype = GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE;
381
382  path16_len = grub_utf8_to_utf16 (filep->path_name,
383                                   path8_len * GRUB_MAX_UTF16_PER_UTF8,
384                                   (const grub_uint8_t *) efifile_path,
385                                   path8_len, 0);
386  filep->path_name[path16_len] = 0;
387  filep->header.length = sizeof (*filep) + (path16_len + 1) * sizeof (grub_uint16_t);
388  pathptr = &filep->path_name[path16_len + 1];
389  endp = pathptr;
390  endp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
391  endp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
392  endp->length = sizeof (*endp);
393  pathptr = endp + 1;
394
395  entry[4] = (grub_uint8_t *) pathptr - path;
396  entry[5] = ((grub_uint8_t *) pathptr - path) >> 8;
397
398  new_boot_order = xmalloc ((boot_order_len > 0 ? boot_order_len : 0) + 2);
399  new_boot_order[0] = order_num;
400  new_boot_order_len = 1;
401  {
402    ssize_t i;
403    for (i = 0; i < boot_order_len / 2; i++)
404      if (boot_order[i] != order_num)
405        new_boot_order[new_boot_order_len++] = boot_order[i];
406  }
407
408  set_efi_variable_bootn (order_num, entry, (grub_uint8_t *) pathptr - entry);
409  set_efi_variable (L"BootOrder", new_boot_order, new_boot_order_len * sizeof (grub_uint16_t));
410}
411
412void
413grub_install_register_ieee1275 (int is_prep, const char *install_device,
414                                int partno, const char *relpath)
415{
416  grub_util_error ("%s", _("no IEEE1275 routines are available for your platform"));
417}
418
419void
420grub_install_sgi_setup (const char *install_device,
421                        const char *imgfile, const char *destname)
422{
423  grub_util_error ("%s", _("no SGI routines are available for your platform"));
424}
Note: See TracBrowser for help on using the repository browser.