6 #include <syslinux/config.h>
13 static const char cmldr_signature[8] = "cmdcons";
15 /* Create boot info table: needed when you want to chainload
16 * another version of ISOLINUX (or another bootlaoder that needs
17 * the -boot-info-table switch of mkisofs)
18 * (will only work when run from ISOLINUX)
20 int manglef_isolinux(struct data_area *data)
22 const union syslinux_derivative_info *sdi;
23 unsigned char *isolinux_bin;
24 uint32_t *checksum, *chkhead, *chktail;
25 uint32_t file_lba = 0;
30 sdi = syslinux_derivative_info();
32 if (sdi->c.filesystem != SYSLINUX_FS_ISOLINUX) {
33 error ("The isolinux= option is only valid when run from ISOLINUX.\n");
37 /* Boot info table info (integers in little endian format)
39 Offset Name Size Meaning
40 8 bi_pvd 4 bytes LBA of primary volume descriptor
41 12 bi_file 4 bytes LBA of boot file
42 16 bi_length 4 bytes Boot file length in bytes
43 20 bi_csum 4 bytes 32-bit checksum
44 24 bi_reserved 40 bytes Reserved
46 The 32-bit checksum is the sum of all the 32-bit words in the
47 boot file starting at byte offset 64. All linear block
48 addresses (LBAs) are given in CD sectors (normally 2048 bytes).
50 LBA of primary volume descriptor should already be set to 16.
53 isolinux_bin = (unsigned char *)data->data;
55 /* Get LBA address of bootfile */
56 file_lba = get_file_lba(opt.file);
59 error("Failed to find LBA offset of the boot file\n");
63 *((uint32_t *) & isolinux_bin[12]) = file_lba;
65 /* Set boot file length */
66 *((uint32_t *) & isolinux_bin[16]) = data->size;
68 /* Calculate checksum */
69 checksum = (uint32_t *) & isolinux_bin[20];
70 chkhead = (uint32_t *) & isolinux_bin[64];
71 chktail = (uint32_t *) & isolinux_bin[data->size & ~3u];
73 while (chkhead < chktail)
74 *checksum += *chkhead++;
77 * Deal with possible fractional dword at the end;
78 * this *should* never happen...
82 memcpy(&xword, chkhead, data->size & 3);
91 * GRLDR of GRUB4DOS wants the partition number in DH:
92 * -1: whole drive (default)
93 * 0-3: primary partitions
94 * 4-*: logical partitions
96 int manglef_grldr(const struct part_iter *iter)
101 opt.regs.edx.b[1] = (uint8_t)(iter->index - 1);
106 * Legacy grub's stage2 chainloading
108 int manglef_grub(const struct part_iter *iter, struct data_area *data)
110 /* Layout of stage2 file (from byte 0x0 to 0x270) */
111 struct grub_stage2_patch_area {
114 /* 0x206: compatibility version number major */
115 uint8_t compat_version_major;
116 /* 0x207: compatibility version number minor */
117 uint8_t compat_version_minor;
119 /* 0x208: install_partition variable */
121 /* 0x208: sub-partition in sub-partition part2 */
123 /* 0x209: sub-partition in top-level partition */
125 /* 0x20a: top-level partiton number */
127 /* 0x20b: BIOS drive number (must be 0) */
129 } __attribute__ ((packed)) install_partition;
131 /* 0x20c: deprecated (historical reason only) */
132 uint32_t saved_entryno;
133 /* 0x210: stage2_ID: will always be STAGE2_ID_STAGE2 = 0 in stage2 */
135 /* 0x211: force LBA */
137 /* 0x212: version string (will probably be 0.97) */
138 char version_string[5];
139 /* 0x217: config filename */
140 char config_file[89];
141 /* 0x270: start of code (after jump from 0x200) */
143 } __attribute__ ((packed)) *stage2;
148 if (data->size < sizeof(struct grub_stage2_patch_area)) {
149 error("The file specified by grub=<loader> is too small to be stage2 of GRUB Legacy.\n");
155 * Check the compatibility version number to see if we loaded a real
156 * stage2 file or a stage2 file that we support.
158 if (stage2->compat_version_major != 3
159 || stage2->compat_version_minor != 2) {
160 error("The file specified by grub=<loader> is not a supported stage2 GRUB Legacy binary.\n");
165 * GRUB Legacy wants the partition number in the install_partition
166 * variable, located at offset 0x208 of stage2.
167 * When GRUB Legacy is loaded, it is located at memory address 0x8208.
169 * It looks very similar to the "boot information format" of the
170 * Multiboot specification:
171 * http://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Boot-information-format
173 * 0x208 = part3: sub-partition in sub-partition part2
174 * 0x209 = part2: sub-partition in top-level partition
175 * 0x20a = part1: top-level partition number
176 * 0x20b = drive: BIOS drive number (must be 0)
178 * GRUB Legacy doesn't store the BIOS drive number at 0x20b, but at
181 * Partition numbers always start from zero.
182 * Unused partition bytes must be set to 0xFF.
184 * We only care about top-level partition, so we only need to change
185 * "part1" to the appropriate value:
186 * -1: whole drive (default) (-1 = 0xFF)
187 * 0-3: primary partitions
188 * 4-*: logical partitions
190 stage2->install_partition.part1 = (uint8_t)(iter->index - 1);
193 * Grub Legacy reserves 89 bytes (from 0x8217 to 0x826f) for the
194 * config filename. The filename passed via grubcfg= will overwrite
195 * the default config filename "/boot/grub/menu.lst".
198 if (strlen(opt.grubcfg) > sizeof(stage2->config_file) - 1) {
199 error ("The config filename length can't exceed 88 characters.\n");
203 strcpy((char *)stage2->config_file, opt.grubcfg);
212 * Adjust BPB of a BPB-compatible file
214 int mangles_bpb(const struct part_iter *iter, struct data_area *data)
216 /* BPB: hidden sectors */
218 if (iter->start_lba < ~0u)
219 *(uint32_t *) ((char *)data->data + 0x1c) = (uint32_t)iter->start_lba;
221 /* won't really help much, but ... */
222 *(uint32_t *) ((char *)data->data + 0x1c) = ~0u;
224 /* BPB: legacy geometry */
227 *(uint32_t *)((char *)data->data + 0x18) = (uint32_t)((iter->di.head << 16) | iter->di.sect);
229 if (iter->di.disk & 0x80)
230 *(uint32_t *)((char *)data->data + 0x18) = 0x00FF003F;
232 *(uint32_t *)((char *)data->data + 0x18) = 0x00020012;
237 *(uint8_t *)((char *)data->data + opt.drvoff) = (uint8_t)
238 (opt.swap ? iter->di.disk & 0x80 : iter->di.disk);
243 int manglef_bpb(const struct part_iter *iter, struct data_area *data)
248 return mangles_bpb(iter, data);
251 int mangles_save(const struct part_iter *iter, const struct data_area *data, void *org)
256 if (memcmp(org, data->data, data->size)) {
257 if (disk_write_sector(&iter->di, iter->start_lba, data->data)) {
258 error("Cannot write the updated sector.\n");
261 /* function is ready do be called again */
262 memcpy(org, data->data, data->size);
272 * To boot the Recovery Console of Windows NT/2K/XP we need to write
273 * the string "cmdcons\0" to memory location 0000:7C03.
274 * Memory location 0000:7C00 contains the bootsector of the partition.
276 int mangles_cmldr(struct data_area *data)
281 memcpy((char *)data->data + 3, cmldr_signature, sizeof(cmldr_signature));
287 * Dell's DRMK chainloading.
289 int manglef_drmk(struct data_area *data)
292 * DRMK entry is different than MS-DOS/PC-DOS
293 * A new size, aligned to 16 bytes to ease use of ds:[bp+28].
294 * We only really need 4 new, usable bytes at the end.
300 uint32_t tsize = (data->size + 19) & 0xfffffff0;
301 opt.regs.ss = opt.regs.fs = opt.regs.gs = 0; /* Used before initialized */
302 if (!realloc(data->data, tsize)) {
303 error("Failed to realloc for DRMK.\n");
307 /* ds:[bp+28] must be 0x0000003f */
308 opt.regs.ds = (uint16_t)((tsize >> 4) + (opt.fseg - 2));
309 /* "Patch" into tail of the new space */
310 *(uint32_t *)((char*)data->data + tsize - 4) = 0x0000003f;
318 /* vim: set ts=8 sts=4 sw=4 noet: */