- GRUB 2 can now be installed on other disks besides the first one.
[cake.git] / workbench / c / Install-grub2-i386-pc.c
blobaee3ba295f6df2f406cc8edf60ee02b3c8ebee0c
1 /*
2 Copyright © 1995-2009, The AROS Development Team. All rights reserved.
3 $Id$
4 */
5 /******************************************************************************
8 NAME
10 Install-grub2-i386-pc
12 SYNOPSIS
14 DEVICE/A, UNIT/N/K/A, PARTITIONNUMBER=PN/K/N, GRUB/K/A, FORCELBA/S
16 LOCATION
20 FUNCTION
22 Installs the GRUB 2 bootloader to the boot block of the specified
23 disk or partition.
25 INPUTS
27 DEVICE -- Device name (e.g. ata.device)
28 UNIT -- Unit number
29 PN -- Specifies a partition number. If specified, GRUB is installed
30 to this partition's boot block. Otherwise, GRUB is installed to
31 the disk's boot block.
32 GRUB -- Path to GRUB directory.
33 FORCELBA -- Force use of LBA mode.
35 RESULT
37 NOTES
39 EXAMPLE
41 Install-grub2-i386-pc device ata.device unit 0 grub dh0:boot/grub
43 BUGS
45 SEE ALSO
47 Partition, Sys:System/Format
49 INTERNALS
51 ******************************************************************************/
53 #define DEBUG 0
54 #include <aros/debug.h>
56 #include <stdio.h>
57 #include <string.h>
58 #include <proto/exec.h>
59 #include <proto/dos.h>
60 #include <proto/partition.h>
61 #include <proto/utility.h>
62 #include <aros/macros.h>
63 #include <devices/hardblocks.h>
64 #include <devices/newstyle.h>
65 #include <exec/errors.h>
66 #include <exec/memory.h>
67 #include <libraries/partition.h>
71 /* Defines for grub2 data */
72 /* boot.img pointers */
73 #define GRUB_BOOT_MACHINE_BPB_START 0x03
74 #define GRUB_BOOT_MACHINE_BPB_END 0x3e
75 #define GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC 0x01b8 /* Following grub2 grub-setup sources */
76 #define GRUB_BOOT_MACHINE_PART_START 0x01be
77 #define GRUB_BOOT_MACHINE_PART_END 0x01fe
78 #define GRUB_BOOT_MACHINE_KERNEL_SECTOR 0x44
79 #define GRUB_BOOT_MACHINE_BOOT_DRIVE 0x4c
80 #define GRUB_BOOT_MACHINE_ROOT_DRIVE 0x4d
81 #define GRUB_BOOT_MACHINE_DRIVE_CHECK 0x4f
83 /* core.img pointers */
84 #define GRUB_KERNEL_MACHINE_INSTALL_DOS_PART 0x14
85 #define GRUB_KERNEL_MACHINE_INSTALL_BSD_PART 0x18
87 /* BIOS drive flag */
88 #define BIOS_HDISK_FLAG 0x80
90 #define MBR_MAX_PARTITIONS 4
91 #define MBRT_EXTENDED 0x05
92 #define MBRT_EXTENDED2 0x0f
93 #define BLCKLIST_ELEMENTS 14
95 struct Volume
97 struct MsgPort *mp;
98 struct IOExtTD *iotd;
99 ULONG readcmd;
100 ULONG writecmd;
101 ULONG startblock;
102 ULONG countblock;
103 ULONG unitnum;
104 UWORD SizeBlock;
105 UBYTE flags;
106 BYTE partnum;
107 ULONG *blockbuffer;
108 ULONG dos_id;
111 #define VF_IS_TRACKDISK (1<<0)
112 #define VF_IS_RDB (1<<1)
114 struct BlockNode
116 ULONG sector_lo;
117 ULONG sector_hi;
118 UWORD count;
119 UWORD seg_adr;
122 CONST_STRPTR CORE_IMG_FILE_NAME = "core.img";
124 STRPTR template =
125 (STRPTR) ("DEVICE/A," "UNIT/N/K/A," "PARTITIONNUMBER=PN/K/N," "GRUB/K/A,"
126 "FORCELBA/S");
128 IPTR myargs[7] = { 0, 0, 0, 0, 0, 0 };
130 struct FileSysStartupMsg *getDiskFSSM(CONST_STRPTR path)
132 struct DosList *dl;
133 struct DeviceNode *dn;
134 TEXT dname[32];
135 UBYTE i;
137 D(bug("[install] getDiskFSSM('%s')\n", path));
139 for (i = 0; (path[i]) && (path[i] != ':'); i++)
140 dname[i] = path[i];
141 if (path[i] == ':')
143 dname[i] = 0;
144 dl = LockDosList(LDF_READ);
145 if (dl)
147 dn = (struct DeviceNode *) FindDosEntry(dl, dname, LDF_DEVICES);
148 UnLockDosList(LDF_READ);
149 if (dn)
151 if (IsFileSystem(dname))
153 return (struct FileSysStartupMsg *) BADDR(dn->dn_Startup);
155 else
156 printf("device '%s' doesn't contain a file system\n",
157 dname);
159 else
160 PrintFault(ERROR_OBJECT_NOT_FOUND, dname);
163 else
164 printf("'%s' doesn't contain a device name\n", path);
165 return 0;
168 void fillGeometry(struct Volume *volume, struct DosEnvec *de)
170 ULONG spc;
172 D(bug("[install] fillGeometry(%x)\n", volume));
174 spc = de->de_Surfaces * de->de_BlocksPerTrack;
175 volume->SizeBlock = de->de_SizeBlock;
176 volume->startblock = de->de_LowCyl * spc;
177 volume->countblock =
178 ((de->de_HighCyl - de->de_LowCyl + 1) * spc) - 1 + de->de_Reserved;
181 void nsdCheck(struct Volume *volume)
183 struct NSDeviceQueryResult nsdq;
184 UWORD *cmdcheck;
186 D(bug("[install] nsdCheck(%x)\n", volume));
188 if (((volume->startblock + volume->countblock) * /* last block */
189 ((volume->SizeBlock << 2) / 512) /* 1 portion (block) equals 512 (bytes) */
190 ) > 8388608)
192 nsdq.SizeAvailable = 0;
193 nsdq.DevQueryFormat = 0;
194 volume->iotd->iotd_Req.io_Command = NSCMD_DEVICEQUERY;
195 volume->iotd->iotd_Req.io_Data = &nsdq;
196 volume->iotd->iotd_Req.io_Length = sizeof(struct NSDeviceQueryResult);
197 if (DoIO((struct IORequest *) &volume->iotd->iotd_Req) == IOERR_NOCMD)
199 printf("Device doesn't understand NSD-Query\n");
201 else
203 if ((volume->iotd->iotd_Req.io_Actual >
204 sizeof(struct NSDeviceQueryResult))
205 || (volume->iotd->iotd_Req.io_Actual == 0)
206 || (volume->iotd->iotd_Req.io_Actual != nsdq.SizeAvailable))
208 printf("WARNING wrong io_Actual using NSD\n");
210 else
212 if (nsdq.DeviceType != NSDEVTYPE_TRACKDISK)
213 printf("WARNING no trackdisk type\n");
214 for (cmdcheck = nsdq.SupportedCommands; *cmdcheck; cmdcheck++)
216 if (*cmdcheck == NSCMD_TD_READ64)
217 volume->readcmd = NSCMD_TD_READ64;
218 if (*cmdcheck == NSCMD_TD_WRITE64);
219 volume->writecmd = NSCMD_TD_WRITE64;
221 if ((volume->readcmd != NSCMD_TD_READ64) ||
222 (volume->writecmd != NSCMD_TD_WRITE64))
223 printf("WARNING no READ64/WRITE64\n");
229 struct Volume *initVolume(CONST_STRPTR device, ULONG unit, ULONG flags,
230 struct DosEnvec *de)
232 struct Volume *volume;
233 LONG error = 0;
235 D(bug("[install] initVolume(%s:%d)\n", device, unit));
237 volume = AllocVec(sizeof(struct Volume), MEMF_PUBLIC | MEMF_CLEAR);
238 if (volume)
240 volume->mp = CreateMsgPort();
241 if (volume->mp)
243 volume->iotd =
244 (struct IOExtTD *) CreateIORequest(volume->mp,
245 sizeof(struct IOExtTD));
246 if (volume->iotd)
248 volume->blockbuffer =
249 AllocVec(de->de_SizeBlock << 2, MEMF_PUBLIC | MEMF_CLEAR);
250 if (volume->blockbuffer)
252 if (OpenDevice
253 (device,
254 unit, (struct IORequest *) volume->iotd, flags) == 0)
256 if (strcmp((const char *) device, TD_NAME) == 0)
257 volume->flags |= VF_IS_TRACKDISK;
258 else
259 volume->flags |= VF_IS_RDB; /* just assume we have RDB */
260 volume->readcmd = CMD_READ;
261 volume->writecmd = CMD_WRITE;
262 volume->unitnum = unit;
263 volume->dos_id = 0;
264 fillGeometry(volume, de);
265 nsdCheck(volume);
266 return volume;
268 else
269 error = ERROR_NO_FREE_STORE;
270 FreeVec(volume->blockbuffer);
272 else
273 error = ERROR_NO_FREE_STORE;
274 DeleteIORequest((struct IORequest *) volume->iotd);
276 else
277 error = ERROR_NO_FREE_STORE;
278 DeleteMsgPort(volume->mp);
280 else
281 error = ERROR_NO_FREE_STORE;
282 FreeVec(volume);
284 else
285 error = ERROR_NO_FREE_STORE;
287 PrintFault(error, NULL);
288 return NULL;
291 void uninitVolume(struct Volume *volume)
293 D(bug("[install] uninitVolume(%x)\n", volume));
295 CloseDevice((struct IORequest *) volume->iotd);
296 FreeVec(volume->blockbuffer);
297 DeleteIORequest((struct IORequest *) volume->iotd);
298 DeleteMsgPort(volume->mp);
299 FreeVec(volume);
302 static ULONG _readwriteBlock(struct Volume *volume,
303 ULONG block, APTR buffer, ULONG length,
304 ULONG command)
306 UQUAD offset;
307 ULONG retval = 0;
309 volume->iotd->iotd_Req.io_Command = command;
310 volume->iotd->iotd_Req.io_Length = length;
311 volume->iotd->iotd_Req.io_Data = buffer;
312 offset = (UQUAD) (volume->startblock + block) * (volume->SizeBlock << 2);
313 volume->iotd->iotd_Req.io_Offset = offset & 0xFFFFFFFF;
314 volume->iotd->iotd_Req.io_Actual = offset >> 32;
315 retval = DoIO((struct IORequest *) &volume->iotd->iotd_Req);
316 if (volume->flags & VF_IS_TRACKDISK)
318 volume->iotd->iotd_Req.io_Command = TD_MOTOR;
319 volume->iotd->iotd_Req.io_Length = 0;
320 DoIO((struct IORequest *) &volume->iotd->iotd_Req);
322 return retval;
325 ULONG readBlock(struct Volume * volume, ULONG block, APTR buffer, ULONG size)
327 D(bug("[install] readBlock(vol:%x, block:%d, %d bytes)\n",
328 volume, block, size));
330 return _readwriteBlock(volume, block, buffer, size, volume->readcmd);
333 ULONG writeBlock(struct Volume * volume, ULONG block, APTR buffer, ULONG size)
335 D(bug("[install] writeBlock(vol:%x, block:%d, %d bytes)\n",
336 volume, block, size));
338 return _readwriteBlock(volume, block, buffer, size, volume->writecmd);
341 static BOOL isKnownFs(ULONG dos_id)
343 switch (dos_id)
345 case ID_FFS_DISK:
346 case ID_INTER_DOS_DISK:
347 case ID_INTER_FFS_DISK:
348 case ID_FASTDIR_DOS_DISK:
349 case ID_FASTDIR_FFS_DISK:
350 case ID_SFS_BE_DISK:
351 case ID_SFS_LE_DISK:
352 return TRUE;
355 return FALSE;
358 BOOL isvalidFileSystem(struct Volume * volume, CONST_STRPTR device,
359 ULONG unit)
361 BOOL retval = FALSE;
362 struct PartitionBase *PartitionBase;
363 struct PartitionHandle *ph;
364 ULONG dos_id;
366 D(bug("[install] isvalidFileSystem(%x, %s, %d)\n", volume, device, unit));
368 if (readBlock(volume, 0, volume->blockbuffer, 512))
370 printf("Read Error\n");
371 return FALSE;
374 dos_id = AROS_BE2LONG(volume->blockbuffer[0]);
376 if (!isKnownFs(dos_id))
378 /* first block has no DOS\x so we don't have RDB for sure */
379 volume->flags &= ~VF_IS_RDB;
380 if (readBlock(volume, 1, volume->blockbuffer, 512))
382 printf("Read Error\n");
383 return FALSE;
386 dos_id = AROS_BE2LONG(volume->blockbuffer[0]);
388 if (!isKnownFs(dos_id))
389 return FALSE;
390 else
391 volume->dos_id = dos_id;
393 else
394 volume->dos_id = dos_id;
396 volume->partnum = -1;
398 PartitionBase =
399 (struct PartitionBase *) OpenLibrary((CONST_STRPTR)
400 "partition.library", 1);
401 if (PartitionBase)
403 ph = OpenRootPartition(device, unit);
404 if (ph)
406 if (OpenPartitionTable(ph) == 0)
408 struct TagItem tags[3];
409 IPTR type;
411 tags[1].ti_Tag = TAG_DONE;
412 tags[0].ti_Tag = PTT_TYPE;
413 tags[0].ti_Data = (STACKIPTR) & type;
414 GetPartitionTableAttrs(ph, tags);
415 if (type == PHPTT_MBR)
417 struct PartitionHandle *pn;
418 struct DosEnvec de;
419 struct PartitionHandle *extph = NULL;
420 struct PartitionType ptype = { };
422 tags[0].ti_Tag = PT_DOSENVEC;
423 tags[0].ti_Data = (STACKIPTR) & de;
424 tags[1].ti_Tag = PT_TYPE;
425 tags[1].ti_Data = (STACKIPTR) & ptype;
426 tags[2].ti_Tag = TAG_DONE;
427 pn = (struct PartitionHandle *) ph->table->list.lh_Head;
428 while (pn->ln.ln_Succ)
430 ULONG scp;
432 GetPartitionAttrs(pn, tags);
433 if (ptype.id[0] == MBRT_EXTENDED
434 || ptype.id[0] == MBRT_EXTENDED2)
435 extph = pn;
436 else
438 scp = de.de_Surfaces * de.de_BlocksPerTrack;
439 if ((volume->startblock >= (de.de_LowCyl * scp))
440 && (volume->startblock <=
441 (((de.de_HighCyl + 1) * scp) - 1)))
442 break;
444 pn = (struct PartitionHandle *) pn->ln.ln_Succ;
446 if (pn->ln.ln_Succ)
448 tags[0].ti_Tag = PT_POSITION;
449 tags[0].ti_Data = (STACKIPTR) & type;
450 tags[1].ti_Tag = TAG_DONE;
451 GetPartitionAttrs(pn, tags);
452 volume->partnum = (UBYTE) type;
453 retval = TRUE;
454 D(bug
455 ("[install] Primary partition found: partnum=%d\n",
456 volume->partnum));
458 else if (extph != NULL)
460 if (OpenPartitionTable(extph) == 0)
462 tags[0].ti_Tag = PTT_TYPE;
463 tags[0].ti_Data = (STACKIPTR) & type;
464 tags[1].ti_Tag = TAG_DONE;
465 GetPartitionTableAttrs(extph, tags);
466 if (type == PHPTT_EBR)
468 tags[0].ti_Tag = PT_DOSENVEC;
469 tags[0].ti_Data = (STACKIPTR) & de;
470 tags[1].ti_Tag = TAG_DONE;
471 pn = (struct PartitionHandle *) extph->table->
472 list.lh_Head;
473 while (pn->ln.ln_Succ)
475 ULONG offset, scp;
477 offset = extph->de.de_LowCyl
478 * extph->de.de_Surfaces
479 * extph->de.de_BlocksPerTrack;
480 GetPartitionAttrs(pn, tags);
481 scp =
482 de.de_Surfaces * de.de_BlocksPerTrack;
483 if ((volume->startblock >=
484 offset + (de.de_LowCyl * scp))
485 && (volume->startblock <=
486 offset +
487 (((de.de_HighCyl + 1) * scp) -
488 1)))
489 break;
490 pn = (struct PartitionHandle *) pn->ln.
491 ln_Succ;
493 if (pn->ln.ln_Succ)
495 tags[0].ti_Tag = PT_POSITION;
496 tags[0].ti_Data = (STACKIPTR) & type;
497 GetPartitionAttrs(pn, tags);
498 volume->partnum =
499 MBR_MAX_PARTITIONS + (UBYTE) type;
500 retval = TRUE;
501 D(bug
502 ("[install] Logical partition found: partnum=%d\n",
503 (int) volume->partnum));
506 ClosePartitionTable(extph);
510 else
512 if (type == PHPTT_RDB)
514 /* just use whole hard disk */
515 retval = TRUE;
517 else
518 printf
519 ("only MBR and RDB partition tables are supported\n");
521 ClosePartitionTable(ph);
523 else
525 /* just use whole hard disk */
526 retval = TRUE;
528 CloseRootPartition(ph);
530 else
531 printf("Error OpenRootPartition(%s,%d)\n", device, unit);
532 CloseLibrary((struct Library *) PartitionBase);
534 else
535 printf("Couldn't open partition.library\n");
536 return retval;
539 struct Volume *getGrubStageVolume(CONST_STRPTR device, ULONG unit,
540 ULONG flags, struct DosEnvec *de)
542 struct Volume *volume;
544 volume = initVolume(device, unit, flags, de);
546 D(bug("[install] getGrubStageVolume(): volume=%x\n", volume));
548 if (volume)
550 if (isvalidFileSystem(volume, device, unit))
551 return volume;
552 else
554 printf("stage2 is on an unsupported file system\n");
555 PrintFault(ERROR_OBJECT_WRONG_TYPE, NULL);
557 uninitVolume(volume);
559 return 0;
562 BOOL isvalidPartition(CONST_STRPTR device, ULONG unit, LONG * pnum,
563 struct DosEnvec * de)
565 struct PartitionBase *PartitionBase;
566 struct PartitionHandle *ph;
567 ULONG type;
568 BOOL retval = FALSE;
570 D(bug
571 ("[install] isvalidPartition(%s:%d, part:%d)\n", device, unit, pnum));
573 PartitionBase =
574 (struct PartitionBase *) OpenLibrary((CONST_STRPTR)
575 "partition.library", 1);
576 if (PartitionBase)
578 ph = OpenRootPartition(device, unit);
579 if (ph)
581 struct TagItem tags[2];
583 tags[1].ti_Tag = TAG_DONE;
584 /* is there a partition table? */
585 if (OpenPartitionTable(ph) == 0)
587 if (pnum)
589 /* install into partition bootblock */
590 tags[0].ti_Tag = PTT_TYPE;
591 tags[0].ti_Data = (STACKIPTR) & type;
592 GetPartitionTableAttrs(ph, tags);
593 if (type == PHPTT_MBR)
595 struct PartitionHandle *pn;
597 /* search for partition */
598 tags[0].ti_Tag = PT_POSITION;
599 tags[0].ti_Data = (STACKIPTR) & type;
600 pn = (struct PartitionHandle *) ph->table->list.
601 lh_Head;
602 while (pn->ln.ln_Succ)
604 GetPartitionAttrs(pn, tags);
605 if (type == *pnum)
606 break;
607 pn = (struct PartitionHandle *) pn->ln.ln_Succ;
609 if (pn->ln.ln_Succ)
611 struct PartitionType ptype;
613 /* is it an AROS partition? */
614 tags[0].ti_Tag = PT_TYPE;
615 tags[0].ti_Data = (STACKIPTR) & ptype;
616 GetPartitionAttrs(pn, tags);
617 if (ptype.id[0] == 0x30)
619 tags[0].ti_Tag = PT_DOSENVEC;
620 tags[0].ti_Data = (STACKIPTR) de;
621 GetPartitionAttrs(pn, tags);
622 retval = TRUE;
624 else
625 printf
626 ("partition is not of type AROS (0x30)\n");
628 else
630 printf
631 ("partition %d not found on device %s unit %d\n",
632 *pnum, device, unit);
635 else
636 printf
637 ("you can only install in partitions which are MBR partitioned\n");
639 else
641 /* install into MBR */
642 tags[0].ti_Tag = PTT_TYPE;
643 tags[0].ti_Data = (STACKIPTR) & type;
644 GetPartitionTableAttrs(ph, tags);
645 if ((type == PHPTT_MBR) || (type == PHPTT_RDB))
647 tags[0].ti_Tag = PT_DOSENVEC;
648 tags[0].ti_Data = (STACKIPTR) de;
649 GetPartitionAttrs(ph, tags);
650 retval = TRUE;
652 else
653 printf
654 ("partition table type must be either MBR or RDB\n");
656 ClosePartitionTable(ph);
658 else
660 #warning "FIXME: GetPartitionAttr() should always work for root partition"
661 CopyMem(&ph->de, de, sizeof(struct DosEnvec));
662 retval = TRUE;
664 CloseRootPartition(ph);
666 else
667 printf("Error OpenRootPartition(%s,%d)\n", device, unit);
668 CloseLibrary((struct Library *) PartitionBase);
670 else
671 printf("Couldn't open partition.library\n");
672 return retval;
675 struct Volume *getBBVolume(CONST_STRPTR device, ULONG unit, LONG * partnum)
677 struct Volume *volume;
678 struct DosEnvec de;
680 D(bug("[install] getBBVolume(%s:%d, %d)\n", device, unit, partnum));
682 if (isvalidPartition(device, unit, partnum, &de))
684 volume = initVolume(device, unit, 0, &de);
685 volume->partnum = partnum ? *partnum : -1;
686 readBlock(volume, 0, volume->blockbuffer, 512);
687 if (AROS_BE2LONG(volume->blockbuffer[0]) != IDNAME_RIGIDDISK)
689 /* Clear the boot sector region! */
690 memset(volume->blockbuffer, 0x00, 446);
691 return volume;
693 else
694 printf("no space for bootblock (RDB is on block 0)\n");
696 return NULL;
699 BOOL writeBootIMG(STRPTR bootimgpath, struct Volume * bootimgvol, struct Volume * coreimgvol,
700 ULONG block /* first block of core.img file */, ULONG unit)
702 BOOL retval = FALSE;
703 LONG error = 0;
704 BPTR fh;
706 D(bug("[install] writeBootIMG(%x)\n", bootimgvol));
708 fh = Open(bootimgpath, MODE_OLDFILE);
709 if (fh)
711 if (Read(fh, bootimgvol->blockbuffer, 512) == 512)
713 /* install into MBR ? */
714 if ((bootimgvol->startblock == 0)
715 && (!(bootimgvol->flags & VF_IS_TRACKDISK)))
717 APTR boot_img = bootimgvol->blockbuffer;
719 UBYTE *boot_drive =
720 (UBYTE *) (boot_img + GRUB_BOOT_MACHINE_BOOT_DRIVE);
721 UBYTE *root_drive =
722 (UBYTE *) (boot_img + GRUB_BOOT_MACHINE_ROOT_DRIVE);
723 UWORD *boot_drive_check =
724 (UWORD *) (boot_img + GRUB_BOOT_MACHINE_DRIVE_CHECK);
726 if (unit == bootimgvol->unitnum)
727 *boot_drive = 0xFF;
728 else
729 *boot_drive = unit | BIOS_HDISK_FLAG;
730 *root_drive = 0xFF;
731 *boot_drive_check = 0x9090;
733 D(bug("[install] writeBootIMG: Install to HARDDISK\n"));
735 /* read old MBR */
736 error = readBlock(bootimgvol, 0, coreimgvol->blockbuffer, 512);
738 D(bug("[install] writeBootIMG: MBR Buffer @ %x\n", bootimgvol->blockbuffer));
739 D(bug("[install] writeBootIMG: Copying MBR BPB to %x\n",
740 (char *) bootimgvol->blockbuffer + GRUB_BOOT_MACHINE_BPB_START));
741 /* copy BPB (BIOS Parameter Block) */
742 CopyMem
743 ((APTR) ((char *) coreimgvol->blockbuffer + GRUB_BOOT_MACHINE_BPB_START),
744 (APTR) ((char *) bootimgvol->blockbuffer + GRUB_BOOT_MACHINE_BPB_START),
745 (GRUB_BOOT_MACHINE_BPB_END - GRUB_BOOT_MACHINE_BPB_START));
747 /* copy partition table - [Overwrites Floppy boot code] */
748 D(bug("[install] writeBootIMG: Copying MBR Partitions to %x\n",
749 (char *) bootimgvol->blockbuffer + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC));
750 CopyMem((APTR) ((char *) coreimgvol->blockbuffer + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC),
751 (APTR) ((char *) bootimgvol->blockbuffer + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC),
752 (GRUB_BOOT_MACHINE_PART_END - GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC));
754 /* Store the core.img pointer .. */
755 ULONG * coreimg_sector_start = (ULONG *) (boot_img
756 + GRUB_BOOT_MACHINE_KERNEL_SECTOR);
757 coreimg_sector_start[0] = block;
758 D(bug("[install] writeBootIMG: core.img pointer = %ld\n", block));
760 else
762 D(bug("[install] writeBootIMG: Install to FLOPPY\n"));
765 if (error == 0)
767 error = writeBlock(bootimgvol, 0, bootimgvol->blockbuffer, 512);
769 if (error)
770 printf("WriteError %d\n", error);
771 else
772 retval = TRUE;
774 else
775 printf("WriteError %d\n", error);
777 else
778 printf("%s: Read Error\n", bootimgpath);
779 Close(fh);
781 else
782 PrintFault(IoErr(), bootimgpath);
784 return retval;
787 /* Collects the list of blocks that a file occupies on FFS filesystem*/
788 ULONG collectBlockListFFS(struct Volume *volume, ULONG block, struct BlockNode *blocklist)
790 ULONG retval, first_block;
791 WORD blk_count,count;
792 UWORD i;
794 D(bug("[install] collectBlockListFFS(%x, %ld, %x)\n", volume, block, blocklist));
797 /* Clear the core.img sector pointers region! */
798 memset((UBYTE*)&blocklist[-BLCKLIST_ELEMENTS],0x00, BLCKLIST_ELEMENTS*sizeof(struct BlockNode));
801 The number of first block of core.img will be stored in boot.img
802 so skip the first filekey in the first loop
805 retval = _readwriteBlock(volume, block, volume->blockbuffer, volume->SizeBlock<<2,
806 volume->readcmd);
808 if (retval)
810 D(bug("[install] collectBlockListFFS: ERROR reading block (error: %ld\n", retval));
811 printf("ReadError %d\n", retval);
812 return 0;
815 i = volume->SizeBlock - 52;
816 first_block = AROS_BE2LONG(volume->blockbuffer[volume->SizeBlock-51]);
817 blk_count=0;
819 D(bug("[install] collectBlockListFFS: First block @ %ld, i:%d\n", first_block, i));
824 retval = _readwriteBlock(volume, block, volume->blockbuffer, volume->SizeBlock<<2,
825 volume->readcmd);
826 if (retval)
828 D(bug("[install] collectBlockListFFS: ERROR reading block (error: %ld)\n", retval));
829 printf("ReadError %d\n", retval);
830 return 0;
833 D(bug("[install] collectBlockListFFS: read block %ld, i = %d\n", block, i));
834 while ((i>=6) && (volume->blockbuffer[i]))
836 D(bug("[install] collectBlockListFFS: i = %d\n", i));
838 if current sector follows right after last sector
839 then we don't need a new element
841 if ((blocklist[blk_count].sector_lo) &&
842 ((blocklist[blk_count].sector_lo+blocklist[blk_count].count)==
843 AROS_BE2LONG(volume->blockbuffer[i])))
845 blocklist[blk_count].count += 1;
846 D(bug("[install] collectBlockListFFS: sector %d follows previous - increasing count of block %d to %d\n",
847 i, blk_count, blocklist[blk_count].count));
849 else
851 blk_count--; /* decrement first */
852 D(bug("[install] collectBlockListFFS: store new block (%d)\n", blk_count));
854 if ((blk_count-1) <= -BLCKLIST_ELEMENTS)
856 D(bug("[install] collectBlockListFFS: ERROR: out of block space at sector %d, block %d\n",
857 i, blk_count));
858 printf("There is no more space to save blocklist in core.img\n");
859 return 0;
861 D(bug("[install] collectBlockListFFS: storing sector pointer for %d in block %d\n",
862 i, blk_count));
863 blocklist[blk_count].sector_lo = AROS_BE2LONG(volume->blockbuffer[i]);
864 blocklist[blk_count].sector_hi = 0;
865 blocklist[blk_count].count = 1;
867 i--;
869 i = volume->SizeBlock - 51;
870 block = AROS_BE2LONG(volume->blockbuffer[volume->SizeBlock - 2]);
871 D(bug("[install] collectBlockListFFS: next block %d, i = %d\n", block, i));
872 } while (block);
876 blocks in blocklist are relative to the first
877 sector of the HD (not partition)
880 D(bug("[install] collectBlockListFFS: successfully updated pointers for %d blocks\n", blk_count));
882 i = 0;
883 for (count=-1;count>=blk_count;count--)
885 blocklist[count].sector_lo += volume->startblock;
886 blocklist[count].seg_adr = 0x820 + (i*32);
887 i += blocklist[count].count;
888 D(bug("[install] collectBlockListFFS: correcting block %d for partition start\n", count));
889 D(bug("[install] collectBlockListFFS: sector : %ld seg_adr : %x\n",
890 blocklist[count].sector_lo, blocklist[count].seg_adr));
893 first_block += volume->startblock;
894 D(bug("[install] collectBlockListFFS: corrected first block for partition start: %ld\n", first_block));
896 return first_block;
899 /* Collects the list of blocks that a file occupies on SFS filesystem*/
900 ULONG collectBlockListSFS(struct Volume *volume, ULONG objectnode, struct BlockNode *blocklist)
902 ULONG retval, first_block = 0;
903 WORD blk_count = 0, count = 0;
904 ULONG block_objectnoderoot = 0, block_sfsobjectcontainer = 0, block_extentbnoderoot = 0;
905 ULONG nextblock = 0, searchedblock = 0;
906 WORD i = 0;
907 UBYTE * tmpBytePtr = NULL;
909 D(bug("[install] collectBlockListSFS(startblock: %ld, objectnode: %ld)\n", volume->startblock, objectnode));
910 D(bug("[install] collectBlockListSFS(%ld, %d, %d)\n", volume->countblock, volume->SizeBlock, volume->partnum));
912 /* Clear the core.img sector pointers region! */
913 memset((UBYTE*)&blocklist[-BLCKLIST_ELEMENTS],0x00, BLCKLIST_ELEMENTS*sizeof(struct BlockNode));
915 /* Description of actions:
916 * 1. Load SFS root block
917 * 2. From root block find the block containing root of objectnodes
918 * 3. Traverse the tree of objectnodes until block of objectdescriptor is found
919 * 4. Search the objectdescriptor for entry matching given objectnode from entry read the
920 * first block of file
921 * 5. Having first file block, find the extentbnode for that block and read number
922 * of blocks. Put first block and number of blocks into BlockList.
923 * 6. If the file has more blocks than this exntentbnode hold, find first file
924 * block in next extentbnode. Go to step 5.
925 * Use the SFS source codes for reference. They operate on structures not pointers
926 * and are much easier to understand.
929 /* Read root block */
930 retval = _readwriteBlock(volume, 0, volume->blockbuffer, volume->SizeBlock<<2,
931 volume->readcmd);
933 if (retval)
935 D(bug("[install] collectBlockListSFS: ERROR reading root block (error: %ld)\n", retval));
936 printf("ReadError %d\n", retval);
937 return 0;
940 /* Get block pointers from root block */
941 block_objectnoderoot = AROS_BE2LONG(volume->blockbuffer[28]); /* objectnoderoot - 29th ULONG */
942 block_extentbnoderoot = AROS_BE2LONG(volume->blockbuffer[27]); /* extentbnoderoot - 28th ULONG */
944 D(bug("[install] collectBlockListSFS: objectnoderoot: %ld, extentbnoderoot %ld\n",
945 block_objectnoderoot, block_extentbnoderoot));
949 /* Find the SFSObjectContainer block for given objectnode */
950 /* Reference: SFS, nodes.c, function findnode */
951 nextblock = block_objectnoderoot;
952 D(bug("[install] collectBlockListSFS: searching in nextblock %d for sfsobjectcontainer for objectnode %ld\n",
953 nextblock, objectnode));
954 while(1)
956 _readwriteBlock(volume, nextblock, volume->blockbuffer, volume->SizeBlock<<2,
957 volume->readcmd);
959 /* If nodes == 1, we are at the correct nodecontainer, else go to next nodecontainer */
960 if (AROS_BE2LONG(volume->blockbuffer[4]) == 1)
962 /* read entry from position: be_node + sizeof(fsObjectNode) * (objectnode - be_nodenumber) */
963 tmpBytePtr = (UBYTE*)volume->blockbuffer;
964 ULONG index = 20 + 10 * (objectnode - AROS_BE2LONG(volume->blockbuffer[3]));
965 block_sfsobjectcontainer = AROS_BE2LONG(((ULONG*)(tmpBytePtr + index))[0]);
966 D(bug("[install] collectBlockListSFS: leaf found in nextblock %ld, sfsobjectcontainer block is %ld \n",
967 nextblock, block_sfsobjectcontainer));
968 break;
970 else
972 UWORD containerentry =
973 (objectnode - AROS_BE2LONG(volume->blockbuffer[3]))/AROS_BE2LONG(volume->blockbuffer[4]);
974 nextblock = AROS_BE2LONG(volume->blockbuffer[containerentry + 5]) >> 4; /* 9-5 (2^9 = 512) */;
975 D(bug("[install] collectBlockListSFS: check next block %ld\n", nextblock));
979 if (block_sfsobjectcontainer == 0)
981 D(bug("[install] collectBlockListSFS: SFSObjectContainer not found\n"));
982 printf("SFSObjectContainer not found\n");
983 return 0;
988 /* Find the SFSObject in SFSObjectContainer for given objectnode */
989 first_block = 0;
990 while((block_sfsobjectcontainer != 0) && (first_block == 0))
992 /* Read next SFS container block */
993 retval = _readwriteBlock(volume, block_sfsobjectcontainer, volume->blockbuffer, volume->SizeBlock<<2,
994 volume->readcmd);
996 if (retval)
998 D(bug("[install] collectBlockListSFS: ERROR reading block (error: %ld)\n", retval));
999 printf("ReadError %d\n", retval);
1000 return 0;
1003 /* Iterate over SFS objects and match the objectnode */
1005 * The first offset comes from :
1006 * sizeof(sfsblockheader) = uint32 + uint32 + uint32 (field of sfsobjectcontainer)
1007 * parent, next, previous = uint32 + uint32 + uint32 (fields of sfsobjectcontainers)
1009 tmpBytePtr = ((UBYTE*)volume->blockbuffer) + 12 + 12; /* tmpBytePtr points to first object in container */
1011 while (AROS_BE2LONG(((ULONG*)(tmpBytePtr + 4))[0]) > 0) /* check on the objectnode field */
1014 /* Compare objectnode */
1015 if (AROS_BE2LONG(((ULONG*)(tmpBytePtr + 4))[0]) == objectnode)
1017 /* Found! */
1018 first_block = AROS_BE2LONG(((ULONG*)(tmpBytePtr + 12))[0]); /* data */
1019 D(bug("[install] collectBlockListSFS: first block is %ld\n", first_block));
1020 break;
1023 /* Move to next object */
1024 /* Find end of name and end of comment */
1025 tmpBytePtr += 25; /* Point to name */
1026 count = 0;
1027 for (i = 2; i > 0; tmpBytePtr++, count++)
1028 if (*tmpBytePtr == '\0')
1029 i--;
1031 /* Correction for aligment */
1032 if ((count & 0x01) == 0 )
1033 tmpBytePtr++;
1036 /* Move to next sfs object container block */
1037 block_sfsobjectcontainer = AROS_BE2LONG(volume->blockbuffer[4]); /* next field */
1041 if (first_block == 0)
1043 D(bug("[install] collectBlockListSFS: First block not found\n"));
1044 printf("First block not found\n");
1045 return 0;
1050 /* First file block found. Find all blocks of file */
1051 searchedblock = first_block;
1052 blk_count = 0;
1054 while(1)
1056 nextblock = block_extentbnoderoot;
1057 UBYTE * BNodePtr = NULL;
1059 while(1)
1061 /* Find the extentbnode for this block */
1063 D(bug("[install] collectBlockListSFS: searching in nextblock %d for extentbnode for block %ld\n",
1064 nextblock, searchedblock));
1066 UBYTE * BTreeContainerPtr = NULL;
1067 BNodePtr = NULL;
1069 _readwriteBlock(volume, nextblock, volume->blockbuffer, volume->SizeBlock<<2,
1070 volume->readcmd);
1072 BTreeContainerPtr = (UBYTE*)(volume->blockbuffer + 3); /* Starts right after the header */
1074 D(bug("[install] collectBlockListSFS: tree container nodecount: %d\n",
1075 AROS_BE2WORD(((UWORD*)BTreeContainerPtr)[0])));
1077 for (i = AROS_BE2WORD(((UWORD*)BTreeContainerPtr)[0]) - 1; i >=0; i--) /* Start from last element */
1079 /* Read the BNode */
1080 tmpBytePtr = BTreeContainerPtr + 4 + i * BTreeContainerPtr[3];
1082 if (AROS_BE2LONG(((ULONG*)(tmpBytePtr))[0]) <= searchedblock) /* Check on the key field */
1084 BNodePtr = tmpBytePtr;
1085 break;
1089 /* Fail if BNodePtr still NULL */
1090 if (BNodePtr == NULL)
1092 D(bug("[install] collectBlockListSFS: Failed to travers extentbnode tree.\n"));
1093 printf("Failed to travers extentbnode tree.\n");
1094 return 0;
1097 /* If we are at the leaf, stop */
1098 if (BTreeContainerPtr[2])
1099 break;
1101 /* Else search further */
1102 nextblock = AROS_BE2LONG(((ULONG*)(BNodePtr))[1]); /* data / next field */
1105 /* Found. Add BlockList entry */
1106 D(bug("[install] collectBlockListSFS: extentbnode for block %ld found. Block count: %d\n",
1107 searchedblock, AROS_BE2WORD(((UWORD*)(BNodePtr + 12))[0])));
1109 /* Add blocklist entry */
1110 blk_count--;
1112 /* Check if we still have spece left to add data to BlockList */
1113 if ((blk_count-1) <= -BLCKLIST_ELEMENTS)
1115 D(bug("[install] collectBlockListSFS: ERROR: out of block space\n"));
1116 printf("There is no more space to save blocklist in core.img\n");
1117 return 0;
1120 blocklist[blk_count].sector_lo = searchedblock;
1121 blocklist[blk_count].sector_hi = 0;
1122 blocklist[blk_count].count = AROS_BE2WORD(((UWORD*)(BNodePtr + 12))[0]);
1124 /* Handling of special situations */
1125 if (searchedblock == first_block)
1127 /* Writting first pack of blocks. Pointer needs to point to second file block */
1128 blocklist[blk_count].sector_lo++;
1129 blocklist[blk_count].count--;
1130 if (blocklist[blk_count].count == 0)
1132 /* This means that the first pack of blocks contained only one block - first block */
1133 /* Since the first blocklist needs to start at second file block, 'reset' the blk_count */
1134 /* so that next iteration will overwrite the current results */
1135 blk_count++;
1139 /* Are there more blocks to read? */
1140 if (AROS_BE2LONG(((ULONG*)(BNodePtr))[1]) == 0)
1142 D(bug("[install] collectBlockListSFS: All core.img blocks found!\n"));
1143 break;
1145 else
1146 searchedblock = AROS_BE2LONG(((ULONG*)(BNodePtr))[1]); /* data / next field */
1150 /* Correct blocks for volume start */
1152 /* Blocks in blocklist are relative to the first sector of the HD (not partition) */
1153 i = 0;
1154 for (count=-1;count>=blk_count;count--)
1156 blocklist[count].sector_lo += volume->startblock;
1157 blocklist[count].seg_adr = 0x820 + (i*32);
1158 i += blocklist[count].count;
1159 D(bug("[install] collectBlockListFFS: correcting block %d for partition start\n", count));
1160 D(bug("[install] collectBlockListFFS: sector : %ld seg_adr : %x\n",
1161 blocklist[count].sector_lo, blocklist[count].seg_adr));
1164 first_block += volume->startblock;
1166 return first_block;
1169 /* Flushes the cache on the volume containing the specified path. */
1170 VOID flushFS(CONST_STRPTR path)
1172 TEXT devname[256];
1173 UWORD i;
1175 for (i = 0; path[i] != ':'; i++)
1176 devname[i] = path[i];
1177 devname[i++] = ':';
1178 devname[i] = '\0';
1180 /* Try to flush 10 times. 5 seconds total */
1182 /* Failsfase in case first Inhibit fails in some way (was needed
1183 * for SFS because non flushed data was failing Inhibit) */
1185 for (i = 0; i < 10; i++)
1187 if (Inhibit(devname, DOSTRUE))
1189 Inhibit(devname, DOSFALSE);
1190 break;
1192 else
1193 Delay(25);
1197 BOOL writeCoreIMG(BPTR fh, UBYTE *buffer, struct Volume *volume)
1199 BOOL retval = FALSE;
1201 D(bug("[install] writeCoreIMG(%x)\n", volume));
1203 if (Seek(fh, 0, OFFSET_BEGINNING) != -1)
1205 D(bug("[install] writeCoreIMG - write first block\n"));
1207 /* write back first block */
1208 if (Write(fh, buffer, 512) == 512)
1212 /* read second core.img block */
1213 if (Read(fh, buffer, 512) == 512)
1215 /* set partition number where core.img is on */
1216 LONG dos_part = 0;
1217 LONG bsd_part = 0; /*?? to fix = RDB part number of DH? */
1218 LONG *install_dos_part =
1219 (LONG *) (buffer + GRUB_KERNEL_MACHINE_INSTALL_DOS_PART);
1220 LONG *install_bsd_part =
1221 (LONG *) (buffer + GRUB_KERNEL_MACHINE_INSTALL_BSD_PART);
1223 dos_part = volume->partnum;
1225 D(bug("[install] set dos part = %d\n", dos_part));
1226 D(bug("[install] set bsd part = %d\n", bsd_part));
1228 *install_dos_part = dos_part;
1229 *install_bsd_part = bsd_part;
1231 /* write second core.img block back */
1232 if (Seek(fh, -512, OFFSET_CURRENT) != -1)
1234 if (Write(fh, buffer, 512) == 512)
1236 retval = TRUE;
1238 else
1239 printf("Write Error\n");
1241 else
1242 printf("Seek Error\n");
1244 else
1245 printf("Read Error\n");
1247 else
1248 printf("Write Error\n");
1250 else
1252 printf("Seek Error\n");
1253 PrintFault(IoErr(), NULL);
1255 return retval;
1258 ULONG updateCoreIMG(CONST_STRPTR grubpath, /* path of grub dir */
1259 struct Volume *volume, /* volume core.img is on */
1260 ULONG *buffer /* a buffer of at least 512 bytes */)
1262 ULONG block = 0;
1263 struct FileInfoBlock fib;
1264 BPTR fh;
1265 TEXT coreimgpath[256];
1267 D(bug("[install] updateCoreIMG(%x)\n", volume));
1269 AddPart(coreimgpath, grubpath, 256);
1270 AddPart(coreimgpath, CORE_IMG_FILE_NAME, 256);
1271 fh = Open(coreimgpath, MODE_OLDFILE);
1272 if (fh)
1274 if (Examine(fh, &fib))
1276 if (Read(fh, buffer, 512) == 512)
1279 Get and store all blocks of core.img in first block of core.img.
1280 First block of core.img will be returned.
1281 List of BlockNode starts at 512 - sizeof(BlockNode). List grows downwards.
1282 buffer is ULONG, buffer[128] is one pointer after first element(upwards).
1283 collectBlockList assumes it receives one pointer after first element(upwards).
1286 if (volume->dos_id == ID_SFS_BE_DISK)
1288 D(bug("[install] core.img on SFS file system\n"));
1289 block = collectBlockListSFS
1290 (volume, fib.fib_DiskKey, (struct BlockNode *)&buffer[128]);
1292 else
1293 if ((volume->dos_id == ID_FFS_DISK) || (volume->dos_id == ID_INTER_DOS_DISK) ||
1294 (volume->dos_id == ID_INTER_FFS_DISK) || (volume->dos_id == ID_FASTDIR_DOS_DISK) ||
1295 (volume->dos_id == ID_FASTDIR_FFS_DISK))
1297 D(bug("[install] core.img on FFS file system\n"));
1298 block = collectBlockListFFS
1299 (volume, fib.fib_DiskKey, (struct BlockNode *)&buffer[128]);
1301 else
1303 block = 0;
1304 D(bug("[install] core.img on unsupported file system\n"));
1305 printf("Unsupported file system\n");
1308 D(bug("[install] core.img first block: %ld\n", block));
1310 if (block)
1312 if (!writeCoreIMG(fh, (UBYTE *)buffer, volume))
1313 block = 0;
1316 else
1317 printf("%s: Read Error\n", coreimgpath);
1319 else
1320 PrintFault(IoErr(), coreimgpath);
1322 Close(fh);
1325 else
1326 PrintFault(IoErr(), coreimgpath);
1327 return block;
1330 /* Installs boot.img to MBR and updates core.img */
1331 BOOL installGrubFiles(struct Volume *coreimgvol, /* core.img volume */
1332 CONST_STRPTR grubpath, /* path to grub files */
1333 ULONG unit, /* unit core.img is on */
1334 struct Volume *bootimgvol) /* boot device for boot.img */
1336 BOOL retval = FALSE;
1337 TEXT bootimgpath[256];
1338 ULONG block;
1340 D(bug("[install] installStageFiles(%x)\n", bootimgvol));
1342 /* Flush GRUB volume's cache */
1343 flushFS(grubpath);
1345 block = updateCoreIMG(grubpath, coreimgvol, bootimgvol->blockbuffer);
1347 if (block)
1349 AddPart(bootimgpath, grubpath, 256);
1350 AddPart(bootimgpath, (CONST_STRPTR) "boot.img", 256);
1351 if (writeBootIMG(bootimgpath, bootimgvol, coreimgvol, block, unit))
1352 retval = TRUE;
1354 else
1355 bug("failed %d\n", IoErr());
1357 return retval;
1360 int main(int argc, char **argv)
1362 struct RDArgs *rdargs;
1363 struct Volume *grubvol;
1364 struct Volume *bbvol;
1365 struct FileSysStartupMsg *fssm;
1366 int ret = RETURN_OK;
1368 D(bug("[install] main()\n"));
1370 rdargs = ReadArgs(template, myargs, NULL);
1371 if (rdargs)
1373 CONST_STRPTR bootDevice = (CONST_STRPTR) myargs[0];
1374 LONG unit = *(LONG *) myargs[1];
1375 LONG *partnum = (LONG *) myargs[2];
1376 CONST_STRPTR grubpath = (CONST_STRPTR) myargs[3];
1378 D(bug("[install] FORCELBA = %d\n", myargs[4]));
1379 if (myargs[4])
1380 printf("FORCELBA ignored\n");
1382 if (partnum)
1384 printf("PARTITIONNUMBER not supported yet\n");
1385 FreeArgs(rdargs);
1386 return RETURN_ERROR;
1389 fssm = getDiskFSSM(grubpath);
1390 if (fssm != NULL)
1392 CONST_STRPTR grubDevice = AROS_BSTR_ADDR(fssm->fssm_Device);
1394 if (!strcmp((const char *) grubDevice, (const char *) bootDevice))
1396 struct DosEnvec *dosEnvec;
1397 dosEnvec = (struct DosEnvec *) BADDR(fssm->fssm_Environ);
1399 grubvol = getGrubStageVolume(grubDevice, fssm->fssm_Unit,
1400 fssm->fssm_Flags, dosEnvec);
1401 if (grubvol)
1404 bbvol = getBBVolume(bootDevice, unit, partnum);
1405 if (bbvol)
1407 if (!installGrubFiles(grubvol, grubpath,
1408 fssm->fssm_Unit, bbvol))
1409 ret = RETURN_ERROR;
1411 uninitVolume(bbvol);
1413 else
1415 D(bug("getBBVolume failed miserably\n"));
1416 ret = RETURN_ERROR;
1419 uninitVolume(grubvol);
1422 else
1424 printf("%s is not on device %s unit %d\n",
1425 grubpath, bootDevice, unit);
1426 ret = RETURN_ERROR;
1429 else if (fssm)
1431 printf("kernel path must begin with a device name\n");
1432 FreeArgs(rdargs);
1433 ret = RETURN_ERROR;
1436 FreeArgs(rdargs);
1438 else
1439 PrintFault(IoErr(), (STRPTR) argv[0]);
1441 return ret;