aboutsummaryrefslogtreecommitdiff
path: root/sysutils/grub2-efi/files/patch-grub-core_loader_i386_bsd.c
blob: a69efa6d22b239c348d46454e77ab37ac31976fb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
--- grub-core/loader/i386/bsd.c.orig	2015-01-30 16:34:55 UTC
+++ grub-core/loader/i386/bsd.c
@@ -42,12 +42,14 @@
 GRUB_MOD_LICENSE ("GPLv3+");
 
 #include <grub/video.h>
+#include <grub/acpi.h>
 #ifdef GRUB_MACHINE_PCBIOS
 #include <grub/machine/biosnum.h>
 #endif
 #ifdef GRUB_MACHINE_EFI
 #include <grub/efi/efi.h>
 #define NETBSD_DEFAULT_VIDEO_MODE "800x600"
+#define FREEBSD_DEFAULT_VIDEO_MODE "auto"
 #else
 #define NETBSD_DEFAULT_VIDEO_MODE "text"
 #include <grub/i386/pc/vbe.h>
@@ -585,6 +587,72 @@ freebsd_get_zfs (void)
   grub_free (uuid);
 }
 
+#ifdef GRUB_MACHINE_EFI
+
+static grub_err_t
+grub_freebsd_setup_video (void)
+{
+  struct grub_video_mode_info mode_info;
+  void *framebuffer;
+  const char *modevar;
+  struct grub_freebsd_btinfo_framebuf efifb;
+  grub_err_t err;
+  grub_video_driver_id_t driv_id;
+
+  modevar = grub_env_get ("gfxpayload");
+
+  /* Now all graphical modes are acceptable.
+     May change in future if we have modes without framebuffer.  */
+  if (modevar && *modevar != 0)
+    {
+      char *tmp;
+      tmp = grub_xasprintf ("%s;" FREEBSD_DEFAULT_VIDEO_MODE, modevar);
+      if (! tmp)
+	return grub_errno;
+      err = grub_video_set_mode (tmp, 0, 0);
+      grub_free (tmp);
+    }
+  else
+    err = grub_video_set_mode (FREEBSD_DEFAULT_VIDEO_MODE, 0, 0);
+
+  if (err)
+    return err;
+
+  driv_id = grub_video_get_driver_id ();
+  if (driv_id == GRUB_VIDEO_DRIVER_NONE)
+    return GRUB_ERR_NONE;
+
+  err = grub_video_get_info_and_fini (&mode_info, &framebuffer);
+
+  if (err)
+    return err;
+
+  efifb.fb_width = mode_info.width;
+  efifb.fb_height = mode_info.height;
+  efifb.fb_stride = mode_info.pitch / mode_info.bytes_per_pixel;
+
+  efifb.fb_addr = (grub_addr_t) framebuffer;
+  efifb.fb_size = ALIGN_UP (mode_info.pitch * efifb.fb_height, 65536);
+
+  if ( mode_info.blue_field_pos == 16 ) {
+    efifb.fb_mask_red = 0x000000ff;
+    efifb.fb_mask_green = 0x0000ff00;
+    efifb.fb_mask_blue = 0x00ff0000;
+  }
+
+  if ( mode_info.blue_field_pos == 0 ) {
+    efifb.fb_mask_red = 0x00ff0000;
+    efifb.fb_mask_green = 0x0000ff00;
+    efifb.fb_mask_blue = 0x000000ff;
+  }
+
+  efifb.fb_mask_reserved = 0xff000000;
+
+  err = grub_bsd_add_meta ( FREEBSD_MODINFO_METADATA | FREEBSD_BTINFO_FRAMEBUF, &efifb, sizeof (efifb));
+  return err;
+}
+#endif
+
 static grub_err_t
 grub_freebsd_boot (void)
 {
@@ -603,6 +671,55 @@ grub_freebsd_boot (void)
 
   bi.boot_device = freebsd_biosdev;
 
+#ifdef GRUB_MACHINE_EFI
+  /* When booting in EFI mode, we need to export some additional kernel ACPI hints */
+  struct grub_acpi_rsdp_v10 *v1;
+  struct grub_acpi_rsdp_v20 *v2;
+  v1 = grub_acpi_get_rsdpv1 ();
+  v2 = grub_acpi_get_rsdpv2 ();
+  if (v2 && v2->length > 40)
+    v2 = 0;
+
+  int revision;
+  char acpiBuf[24];
+
+  if (v1)
+  {
+     revision = v1->revision;
+     if ( revision == 0 )
+        revision = 1;
+     grub_snprintf (acpiBuf, sizeof (acpiBuf), "%d", revision);
+     grub_env_set("kFreeBSD.hint.acpi.0.revision", acpiBuf);
+
+     grub_snprintf (acpiBuf, sizeof (acpiBuf), "%s", v1->oemid);
+     grub_env_set("kFreeBSD.hint.acpi.0.oem", acpiBuf);
+
+     grub_snprintf (acpiBuf, sizeof (acpiBuf), "0x%016x", v1->rsdt_addr);
+     grub_env_set("kFreeBSD.hint.acpi.0.rsdt", acpiBuf);
+
+     grub_snprintf (acpiBuf, sizeof (acpiBuf), "0x%016llx", (unsigned long long)v1);
+     grub_env_set("kFreeBSD.hint.acpi.0.rsdp", acpiBuf);
+  }
+
+  if (v2)
+  {
+     revision = v2->rsdpv1.revision;
+     if ( revision == 0 )
+        revision = 1;
+
+     grub_snprintf (acpiBuf, sizeof (acpiBuf), "%d", revision);
+     grub_env_set("kFreeBSD.hint.acpi.0.revision", acpiBuf);
+
+     grub_snprintf (acpiBuf, sizeof (acpiBuf), "0x%016llx", (unsigned long long)v2->xsdt_addr);
+     grub_env_set("kFreeBSD.hint.acpi.0.xsdt", acpiBuf);
+
+     grub_snprintf (acpiBuf, sizeof (acpiBuf), "%d", v2->length);
+     grub_env_set("kFreeBSD.hint.acpi.0.xsdt_length", acpiBuf);
+  }
+
+
+#endif
+
   p_size = 0;
   FOR_SORTED_ENV (var)
     if ((grub_memcmp (var->name, "kFreeBSD.", sizeof("kFreeBSD.") - 1) == 0) && (var->name[sizeof("kFreeBSD.") - 1]))
@@ -688,6 +805,10 @@ grub_freebsd_boot (void)
 		*(grub_uint32_t *) p_tag = bootflags;
 	      break;
 
+	    case FREEBSD_MODINFO_METADATA | FREEBSD_BTINFO_FRAMEBUF:
+	      grub_memcpy (p_tag, tag->data, tag->len);
+	      break;
+
 	    case FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_ENVP:
 	      if (is_64bit)
 		*(grub_uint64_t *) p_tag = bi.environment;
@@ -717,7 +838,10 @@ grub_freebsd_boot (void)
 
   bi.kern_end = kern_end;
 
+#ifndef GRUB_MACHINE_EFI
+  /* Don't set text mode on EFI boot */
   grub_video_set_mode ("text", 0, 0);
+#endif
 
   if (is_64bit)
     {
@@ -1561,6 +1685,16 @@ grub_cmd_freebsd (grub_extcmd_context_t 
 				   FREEBSD_MODINFOMD_KERNEND, &data, len);
 	  if (err)
 	    return err;
+
+#ifdef GRUB_MACHINE_EFI
+	  err = grub_freebsd_setup_video ();
+	  if (err)
+	  {
+	    grub_print_error ();
+	    grub_puts_ (N_("Booting in EFI blind mode"));
+	    grub_errno = GRUB_ERR_NONE;
+	  }
+#endif
 	}
       grub_bsd_get_device (&freebsd_biosdev, &unit, &slice, &part);
       freebsd_zfsguid = 0;