]>
Commit | Line | Data |
---|---|---|
4d8d554a CW |
1 | /* cmain.c - Startup code for the PowerPC. */ |
2 | /* | |
3 | * GRUB -- GRand Unified Bootloader | |
4 | * Copyright (C) 2003,2004,2005,2006,2007,2008 Free Software Foundation, Inc. | |
5 | * | |
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. | |
10 | * | |
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. | |
15 | * | |
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/>. | |
18 | */ | |
19 | ||
20 | #include <grub/kernel.h> | |
21 | #include <grub/misc.h> | |
22 | #include <grub/types.h> | |
23 | #include <grub/ieee1275/ieee1275.h> | |
24 | ||
25 | int (*grub_ieee1275_entry_fn) (void *) GRUB_IEEE1275_ENTRY_FN_ATTRIBUTE; | |
26 | ||
27 | grub_ieee1275_phandle_t grub_ieee1275_chosen; | |
28 | grub_ieee1275_ihandle_t grub_ieee1275_mmu; | |
29 | ||
30 | static grub_uint32_t grub_ieee1275_flags; | |
31 | \f | |
32 | ||
33 | ||
34 | int | |
35 | grub_ieee1275_test_flag (enum grub_ieee1275_flag flag) | |
36 | { | |
37 | return (grub_ieee1275_flags & (1 << flag)); | |
38 | } | |
39 | ||
40 | void | |
41 | grub_ieee1275_set_flag (enum grub_ieee1275_flag flag) | |
42 | { | |
43 | grub_ieee1275_flags |= (1 << flag); | |
44 | } | |
45 | ||
46 | static void | |
47 | grub_ieee1275_find_options (void) | |
48 | { | |
49 | grub_ieee1275_phandle_t root; | |
50 | grub_ieee1275_phandle_t options; | |
51 | grub_ieee1275_phandle_t openprom; | |
52 | grub_ieee1275_phandle_t bootrom; | |
53 | int rc; | |
54 | grub_uint32_t realmode = 0; | |
55 | char tmp[256]; | |
56 | int is_smartfirmware = 0; | |
57 | int is_olpc = 0; | |
58 | int is_qemu = 0; | |
59 | grub_ssize_t actual; | |
60 | ||
61 | #ifdef __sparc__ | |
62 | grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_PARTITION_0); | |
63 | #endif | |
64 | ||
65 | grub_ieee1275_finddevice ("/", &root); | |
66 | grub_ieee1275_finddevice ("/options", &options); | |
67 | grub_ieee1275_finddevice ("/openprom", &openprom); | |
68 | ||
69 | rc = grub_ieee1275_get_integer_property (options, "real-mode?", &realmode, | |
70 | sizeof realmode, 0); | |
71 | if (((rc >= 0) && realmode) || (grub_ieee1275_mmu == 0)) | |
72 | grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_REAL_MODE); | |
73 | ||
74 | rc = grub_ieee1275_get_property (openprom, "CodeGen-copyright", | |
75 | tmp, sizeof (tmp), 0); | |
76 | if (rc >= 0 && !grub_strncmp (tmp, "SmartFirmware(tm)", | |
77 | sizeof ("SmartFirmware(tm)") - 1)) | |
78 | is_smartfirmware = 1; | |
79 | ||
80 | rc = grub_ieee1275_get_property (root, "architecture", | |
81 | tmp, sizeof (tmp), 0); | |
82 | if (rc >= 0 && !grub_strcmp (tmp, "OLPC")) | |
83 | is_olpc = 1; | |
84 | ||
85 | rc = grub_ieee1275_get_property (root, "model", | |
86 | tmp, sizeof (tmp), 0); | |
87 | if (rc >= 0 && (!grub_strcmp (tmp, "Emulated PC") | |
88 | || !grub_strcmp (tmp, "IBM pSeries (emulated by qemu)"))) { | |
89 | is_qemu = 1; | |
90 | } | |
91 | ||
92 | if (rc >= 0 && grub_strncmp (tmp, "IBM", 3) == 0) | |
93 | grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_TREE_SCANNING_FOR_DISKS); | |
94 | ||
95 | /* Old Macs have no key repeat, newer ones have fully working one. | |
96 | The ones inbetween when repeated key generates an escaoe sequence | |
97 | only the escape is repeated. With this workaround however a fast | |
98 | e.g. down arrow-ESC is perceived as down arrow-down arrow which is | |
99 | also annoying but is less so than the original bug of exiting from | |
100 | the current window on arrow repeat. To avoid unaffected users suffering | |
101 | from this workaround match only exact models known to have this bug. | |
102 | */ | |
103 | if (rc >= 0 && grub_strcmp (tmp, "PowerBook3,3") == 0) | |
104 | grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_BROKEN_REPEAT); | |
105 | ||
106 | rc = grub_ieee1275_get_property (root, "compatible", | |
107 | tmp, sizeof (tmp), &actual); | |
108 | if (rc >= 0) | |
109 | { | |
110 | char *ptr; | |
e1c95655 ES |
111 | |
112 | if (grub_strncmp (tmp, "sun4v", 5) == 0) | |
113 | grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_RAW_DEVNAMES); | |
4d8d554a CW |
114 | for (ptr = tmp; ptr - tmp < actual; ptr += grub_strlen (ptr) + 1) |
115 | { | |
116 | if (grub_memcmp (ptr, "MacRISC", sizeof ("MacRISC") - 1) == 0 | |
117 | && (ptr[sizeof ("MacRISC") - 1] == 0 | |
118 | || grub_isdigit (ptr[sizeof ("MacRISC") - 1]))) | |
119 | { | |
120 | grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_BROKEN_ADDRESS_CELLS); | |
121 | grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_OFNET_SUFFIX); | |
122 | grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_VIRT_TO_REAL_BROKEN); | |
123 | grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_CURSORONOFF_ANSI_BROKEN); | |
124 | break; | |
125 | } | |
126 | } | |
127 | } | |
128 | ||
129 | if (is_smartfirmware) | |
130 | { | |
131 | /* Broken in all versions */ | |
132 | grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_BROKEN_OUTPUT); | |
133 | ||
134 | /* There are two incompatible ways of checking the version number. Try | |
135 | both. */ | |
136 | rc = grub_ieee1275_get_property (openprom, "SmartFirmware-version", | |
137 | tmp, sizeof (tmp), 0); | |
138 | if (rc < 0) | |
139 | rc = grub_ieee1275_get_property (openprom, "firmware-version", | |
140 | tmp, sizeof (tmp), 0); | |
141 | if (rc >= 0) | |
142 | { | |
143 | /* It is tempting to implement a version parser to set the flags for | |
144 | e.g. 1.3 and below. However, there's a special situation here. | |
145 | 3rd party updates which fix the partition bugs are common, and for | |
146 | some reason their fixes aren't being merged into trunk. So for | |
147 | example we know that 1.2 and 1.3 are broken, but there's 1.2.99 | |
148 | and 1.3.99 which are known good (and applying this workaround | |
149 | would cause breakage). */ | |
150 | if (!grub_strcmp (tmp, "1.0") | |
151 | || !grub_strcmp (tmp, "1.1") | |
152 | || !grub_strcmp (tmp, "1.2") | |
153 | || !grub_strcmp (tmp, "1.3")) | |
154 | { | |
155 | grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_PARTITION_0); | |
156 | grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_0_BASED_PARTITIONS); | |
157 | } | |
158 | } | |
159 | } | |
160 | ||
161 | if (is_olpc) | |
162 | { | |
163 | /* OLPC / XO laptops have three kinds of storage devices: | |
164 | ||
165 | - NAND flash. These are accessible via OFW callbacks, but: | |
166 | - Follow strange semantics, imposed by hardware constraints. | |
167 | - Its ABI is undocumented, and not stable. | |
168 | They lack "device_type" property, which conveniently makes GRUB | |
169 | skip them. | |
170 | ||
171 | - USB drives. Not accessible, because OFW shuts down the controller | |
172 | in order to prevent collisions with applications accessing it | |
173 | directly. Even worse, attempts to access it will NOT return | |
174 | control to the caller, so we have to avoid probing them. | |
175 | ||
176 | - SD cards. These work fine. | |
177 | ||
178 | To avoid breakage, we only need to skip USB probing. However, | |
179 | since detecting SD cards is more reliable, we do that instead. | |
180 | */ | |
181 | ||
182 | grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_OFDISK_SDCARD_ONLY); | |
183 | grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_HAS_CURSORONOFF); | |
184 | } | |
185 | ||
186 | if (is_qemu) | |
187 | { | |
188 | /* OpenFirmware hangs on qemu if one requests any memory below 1.5 MiB. */ | |
189 | grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_PRE1_5M_CLAIM); | |
190 | ||
191 | grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_HAS_CURSORONOFF); | |
192 | } | |
193 | ||
194 | if (! grub_ieee1275_finddevice ("/rom/boot-rom", &bootrom) | |
195 | || ! grub_ieee1275_finddevice ("/boot-rom", &bootrom)) | |
196 | { | |
197 | rc = grub_ieee1275_get_property (bootrom, "model", tmp, sizeof (tmp), 0); | |
198 | if (rc >= 0 && !grub_strncmp (tmp, "PPC Open Hack'Ware", | |
199 | sizeof ("PPC Open Hack'Ware") - 1)) | |
200 | { | |
201 | grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_BROKEN_OUTPUT); | |
202 | grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_CANNOT_SET_COLORS); | |
203 | grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_CANNOT_INTERPRET); | |
204 | grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_FORCE_CLAIM); | |
205 | grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_ANSI); | |
206 | } | |
207 | } | |
208 | } | |
209 | ||
210 | void | |
211 | grub_ieee1275_init (void) | |
212 | { | |
213 | grub_ieee1275_finddevice ("/chosen", &grub_ieee1275_chosen); | |
214 | ||
215 | if (grub_ieee1275_get_integer_property (grub_ieee1275_chosen, "mmu", &grub_ieee1275_mmu, | |
216 | sizeof grub_ieee1275_mmu, 0) < 0) | |
217 | grub_ieee1275_mmu = 0; | |
218 | ||
219 | grub_ieee1275_find_options (); | |
220 | } |