]> git.proxmox.com Git - grub2.git/blob - loader/machoXX.c
Merge my local branch
[grub2.git] / loader / machoXX.c
1
2 #include <grub/file.h>
3 #include <grub/mm.h>
4 #include <grub/misc.h>
5
6 #define min(a,b) (((a) < (b)) ? (a) : (b))
7
8 int
9 SUFFIX (grub_macho_contains_macho) (grub_macho_t macho)
10 {
11 return macho->offsetXX != -1;
12 }
13
14 void
15 SUFFIX (grub_macho_parse) (grub_macho_t macho)
16 {
17 grub_macho_header_t head;
18
19 /* Is there any candidate at all? */
20 if (macho->offsetXX == -1)
21 return;
22
23 /* Read header and check magic*/
24 if (grub_file_seek (macho->file, macho->offsetXX) == (grub_off_t) -1
25 || grub_file_read (macho->file, &head, sizeof (head))
26 != sizeof(head))
27 {
28 grub_error (GRUB_ERR_READ_ERROR, "cannot read Mach-O header");
29 macho->offsetXX = -1;
30 return;
31 }
32 if (head.magic != GRUB_MACHO_MAGIC)
33 {
34 grub_error (GRUB_ERR_BAD_OS, "invalid Mach-O " XX "-bit header");
35 macho->offsetXX = -1;
36 return;
37 }
38
39 /* Read commands. */
40 macho->ncmdsXX = head.ncmds;
41 macho->cmdsizeXX = head.sizeofcmds;
42 macho->cmdsXX = grub_malloc(macho->cmdsizeXX);
43 if (! macho->cmdsXX)
44 {
45 grub_error (GRUB_ERR_OUT_OF_MEMORY, "not enough memory to read commands");
46 return;
47 }
48 if (grub_file_read (macho->file, macho->cmdsXX,
49 (grub_size_t) macho->cmdsizeXX)
50 != (grub_ssize_t) macho->cmdsizeXX)
51 {
52 grub_error (GRUB_ERR_READ_ERROR, "cannot read Mach-O header");
53 macho->offsetXX = -1;
54 }
55 }
56
57 typedef int NESTED_FUNC_ATTR (*grub_macho_iter_hook_t)
58 (grub_macho_t , struct grub_macho_cmd *,
59 void *);
60
61 static grub_err_t
62 grub_macho_cmds_iterate (grub_macho_t macho,
63 grub_macho_iter_hook_t hook,
64 void *hook_arg)
65 {
66 grub_uint8_t *hdrs = macho->cmdsXX;
67 int i;
68 if (! macho->cmdsXX)
69 return grub_error (GRUB_ERR_BAD_OS, "couldn't find " XX "-bit Mach-O");
70 for (i = 0; i < macho->ncmdsXX; i++)
71 {
72 struct grub_macho_cmd *hdr = (struct grub_macho_cmd *) hdrs;
73 if (hook (macho, hdr, hook_arg))
74 break;
75 hdrs += hdr->cmdsize;
76 }
77
78 return grub_errno;
79 }
80
81 grub_size_t
82 SUFFIX (grub_macho_filesize) (grub_macho_t macho)
83 {
84 if (SUFFIX (grub_macho_contains_macho) (macho))
85 return macho->endXX - macho->offsetXX;
86 return 0;
87 }
88
89 grub_err_t
90 SUFFIX (grub_macho_readfile) (grub_macho_t macho, void *dest)
91 {
92 grub_ssize_t read;
93 if (! SUFFIX (grub_macho_contains_macho) (macho))
94 return grub_error (GRUB_ERR_BAD_OS,
95 "couldn't read architecture-specific part");
96
97 if (grub_file_seek (macho->file, macho->offsetXX) == (grub_off_t) -1)
98 {
99 grub_error_push ();
100 return grub_error (GRUB_ERR_BAD_OS,
101 "invalid offset in program header");
102 }
103
104 read = grub_file_read (macho->file, dest,
105 macho->endXX - macho->offsetXX);
106 if (read != (grub_ssize_t) (macho->endXX - macho->offsetXX))
107 {
108 grub_error_push ();
109 return grub_error (GRUB_ERR_BAD_OS,
110 "couldn't read architecture-specific part");
111 }
112 return GRUB_ERR_NONE;
113 }
114
115 /* Calculate the amount of memory spanned by the segments. */
116 grub_err_t
117 SUFFIX (grub_macho_size) (grub_macho_t macho, grub_macho_addr_t *segments_start,
118 grub_macho_addr_t *segments_end, int flags)
119 {
120 int nr_phdrs = 0;
121
122 /* Run through the program headers to calculate the total memory size we
123 should claim. */
124 auto int NESTED_FUNC_ATTR calcsize (grub_macho_t _macho,
125 struct grub_macho_cmd *phdr, void *_arg);
126 int NESTED_FUNC_ATTR calcsize (grub_macho_t _macho __attribute__ ((unused)),
127 struct grub_macho_cmd *hdr0,
128 void *_arg __attribute__ ((unused)))
129 {
130 grub_macho_segment_t *hdr = (grub_macho_segment_t *) hdr0;
131 if (hdr->cmd != GRUB_MACHO_CMD_SEGMENT)
132 return 0;
133
134 if (! hdr->vmsize)
135 return 0;
136
137 if (! hdr->filesize && (flags & GRUB_MACHO_NOBSS))
138 return 0;
139
140 nr_phdrs++;
141 if (hdr->vmaddr < *segments_start)
142 *segments_start = hdr->vmaddr;
143 if (hdr->vmaddr + hdr->vmsize > *segments_end)
144 *segments_end = hdr->vmaddr + hdr->vmsize;
145 return 0;
146 }
147
148 *segments_start = (grub_macho_addr_t) -1;
149 *segments_end = 0;
150
151 grub_macho_cmds_iterate (macho, calcsize, 0);
152
153 if (nr_phdrs == 0)
154 return grub_error (GRUB_ERR_BAD_OS, "no program headers present");
155
156 if (*segments_end < *segments_start)
157 /* Very bad addresses. */
158 return grub_error (GRUB_ERR_BAD_OS, "bad program header load addresses");
159
160 return GRUB_ERR_NONE;
161 }
162
163 /* Load every loadable segment into memory specified by `_load_hook'. */
164 grub_err_t
165 SUFFIX (grub_macho_load) (grub_macho_t macho, char *offset, int flags)
166 {
167 grub_err_t err = 0;
168 auto int NESTED_FUNC_ATTR do_load(grub_macho_t _macho,
169 struct grub_macho_cmd *hdr0,
170 void *_arg __attribute__ ((unused)));
171 int NESTED_FUNC_ATTR do_load(grub_macho_t _macho,
172 struct grub_macho_cmd *hdr0,
173 void *_arg __attribute__ ((unused)))
174 {
175 grub_macho_segment_t *hdr = (grub_macho_segment_t *) hdr0;
176
177 if (hdr->cmd != GRUB_MACHO_CMD_SEGMENT)
178 return 0;
179
180 if (! hdr->filesize && (flags & GRUB_MACHO_NOBSS))
181 return 0;
182 if (! hdr->vmsize)
183 return 0;
184
185 if (grub_file_seek (_macho->file, hdr->fileoff
186 + _macho->offsetXX) == (grub_off_t) -1)
187 {
188 grub_error_push ();
189 grub_error (GRUB_ERR_BAD_OS,
190 "invalid offset in program header");
191 return 1;
192 }
193
194 if (hdr->filesize)
195 {
196 grub_ssize_t read;
197 read = grub_file_read (_macho->file, offset + hdr->vmaddr,
198 min (hdr->filesize, hdr->vmsize));
199 if (read != (grub_ssize_t) min (hdr->filesize, hdr->vmsize))
200 {
201 /* XXX How can we free memory from `load_hook'? */
202 grub_error_push ();
203 err=grub_error (GRUB_ERR_BAD_OS,
204 "couldn't read segment from file: "
205 "wanted 0x%lx bytes; read 0x%lx bytes",
206 hdr->filesize, read);
207 return 1;
208 }
209 }
210
211 if (hdr->filesize < hdr->vmsize)
212 grub_memset (offset + hdr->vmaddr + hdr->filesize,
213 0, hdr->vmsize - hdr->filesize);
214 return 0;
215 }
216
217 grub_macho_cmds_iterate (macho, do_load, 0);
218
219 return err;
220 }
221
222 grub_macho_addr_t
223 SUFFIX (grub_macho_get_entry_point) (grub_macho_t macho)
224 {
225 grub_macho_addr_t entry_point = 0;
226 auto int NESTED_FUNC_ATTR hook(grub_macho_t _macho,
227 struct grub_macho_cmd *hdr,
228 void *_arg __attribute__ ((unused)));
229 int NESTED_FUNC_ATTR hook(grub_macho_t _macho __attribute__ ((unused)),
230 struct grub_macho_cmd *hdr,
231 void *_arg __attribute__ ((unused)))
232 {
233 if (hdr->cmd == GRUB_MACHO_CMD_THREAD)
234 entry_point = ((grub_macho_thread_t *) hdr)->entry_point;
235 return 0;
236 }
237 grub_macho_cmds_iterate (macho, hook, 0);
238 return entry_point;
239 }