revert between 56095 -> 55830 in arch
[AROS.git] / arch / all-pc / boot / grub2-tools / Install-grub2.c
blob75c6e1feb73b4829a645d7dcd3b6e6571309eb60
1 /*
2 Copyright © 1995-2015, The AROS Development Team. All rights reserved.
3 $Id$
4 */
5 /******************************************************************************
8 NAME
10 Install-grub2
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 EFI machines don't need this utility because EFI doesn't need a bootblock.
40 It is capable of loading files directly from the filesystem.
42 EXAMPLE
44 Install-grub2 DEVICE ata.device UNIT 0 GRUB DH0:boot/grub
46 BUGS
48 SEE ALSO
50 Partition, SYS:System/Format
52 INTERNALS
54 ******************************************************************************/
56 #define DEBUG 1
57 #include <aros/debug.h>
59 #include <string.h>
60 #include <proto/debug.h>
61 #include <proto/exec.h>
62 #include <proto/dos.h>
63 #include <proto/partition.h>
64 #include <proto/utility.h>
65 #include <aros/macros.h>
66 #include <devices/hardblocks.h>
67 #include <devices/newstyle.h>
68 #include <exec/errors.h>
69 #include <exec/memory.h>
70 #include <libraries/partition.h>
72 /* These define some offsets */
73 #define ASM_FILE /* Omit grub_uint64_t reference */
74 #define GRUB_MACHINE I386_PC
76 #include <grub/i386/pc/boot.h>
77 #include <grub/offsets.h>
79 /* BIOS drive flag */
80 #define BIOS_HDISK_FLAG 0x80
82 #define MBR_MAX_PARTITIONS 4
83 #define MBRT_EXTENDED 0x05
84 #define MBRT_EXTENDED2 0x0f
85 #define BLCKLIST_ELEMENTS 14
87 struct Volume
89 struct PartitionHandle *root; /* Device root handle */
90 struct PartitionHandle *part; /* The actual partition */
91 ULONG startblock; /* Offset, for stage volume */
92 ULONG countblock;
93 CONST_STRPTR device; /* Informative, for error messages */
94 ULONG unitnum;
95 UWORD SizeBlock; /* In bytes */
96 UBYTE flags;
97 LONG partnum; /* -1 for device root */
98 ULONG *blockbuffer;
99 ULONG dos_id;
102 #define VF_IS_TRACKDISK (1<<0)
103 #define VF_IS_RDB (1<<1)
105 struct BlockNode
107 ULONG sector_lo;
108 ULONG sector_hi;
109 UWORD count;
110 UWORD seg_adr;
113 const TEXT version[] = "$VER: Install-grub2 41.3 " ADATE;
115 static CONST_STRPTR CORE_IMG_FILE_NAME = "core.img";
116 static CONST_STRPTR template ="DEVICE/A,UNIT/N/K/A,PARTITIONNUMBER=PN/K/N,GRUB/K/A,FORCELBA/S,TEST/S";
118 struct PartitionBase *PartitionBase;
119 IPTR myargs[7] = { 0, 0, 0, 0, 0, 0, 0 };
121 #define ARG_TESTING 5
123 struct FileSysStartupMsg *getDiskFSSM(CONST_STRPTR path)
125 struct DosList *dl;
126 struct DeviceNode *dn;
127 TEXT dname[32];
128 UBYTE i;
130 D(bug("[install] getDiskFSSM('%s')\n", path));
132 for (i = 0; (path[i]) && (path[i] != ':'); i++)
133 dname[i] = path[i];
134 if (path[i] == ':')
136 dname[i] = 0;
137 dl = LockDosList(LDF_READ);
138 if (dl)
140 dn = (struct DeviceNode *) FindDosEntry(dl, dname, LDF_DEVICES);
141 UnLockDosList(LDF_READ);
142 if (dn)
144 dname[i] = ':';
145 dname[i + 1] = '\0';
146 if (IsFileSystem(dname))
148 return (struct FileSysStartupMsg *) BADDR(dn->dn_Startup);
150 else
151 Printf("device '%s' doesn't contain a file system\n",
152 dname);
154 else
155 PrintFault(ERROR_OBJECT_NOT_FOUND, dname);
158 else
159 Printf("'%s' doesn't contain a device name\n", path);
160 return 0;
163 static BOOL AllocBuffer(struct Volume *volume)
165 volume->blockbuffer = AllocMem(volume->SizeBlock, MEMF_PUBLIC | MEMF_CLEAR);
166 if (!volume->blockbuffer)
168 Printf("Failed to allocate data buffer!\n");
169 return FALSE;
171 return TRUE;
174 BOOL fillGeometry(struct Volume *volume, struct DosEnvec *de)
176 ULONG spc;
178 D(bug("[install] fillGeometry(%x)\n", volume));
180 spc = de->de_Surfaces * de->de_BlocksPerTrack;
181 volume->SizeBlock = de->de_SizeBlock << 2;
182 volume->startblock = de->de_LowCyl * spc;
183 volume->countblock =
184 ((de->de_HighCyl - de->de_LowCyl + 1) * spc) - 1 + de->de_Reserved;
185 volume->part = volume->root;
186 return AllocBuffer(volume);
189 void DumpVolume(struct Volume *volume, const char *header)
191 if (!myargs[ARG_TESTING])
192 return;
194 Printf("%s: %s unit %lu partition %ld\n", header, volume->device, volume->unitnum, volume->partnum);
197 struct Volume *initVolume(CONST_STRPTR device, ULONG unit)
199 struct Volume *volume;
201 D(bug("[install] initVolume(%s:%d)\n", device, unit));
203 volume = AllocMem(sizeof(struct Volume), MEMF_PUBLIC | MEMF_CLEAR);
204 if (volume)
206 volume->root = OpenRootPartition(device, unit);
207 if (volume->root)
209 if (strcmp((const char *) device, TD_NAME) == 0)
210 volume->flags |= VF_IS_TRACKDISK;
211 else
212 volume->flags |= VF_IS_RDB; /* just assume we have RDB */
214 volume->device = device;
215 volume->unitnum = unit;
216 volume->startblock = 0;
217 volume->partnum = -1;
218 volume->dos_id = 0;
220 return volume;
222 else
223 Printf("Failed to open device %s unit %ld!\n", device, unit);
225 FreeMem(volume, sizeof(struct Volume));
227 else
228 PrintFault(ERROR_NO_FREE_STORE, NULL);
230 return NULL;
233 void uninitVolume(struct Volume *volume)
235 D(bug("[install] uninitVolume(%x)\n", volume));
237 if (volume->blockbuffer)
238 FreeMem(volume->blockbuffer, volume->SizeBlock);
239 if (volume->root)
241 ClosePartitionTable(volume->root);
242 CloseRootPartition(volume->root);
244 FreeMem(volume, sizeof (struct Volume));
247 ULONG readBlock(struct Volume * volume, ULONG block, APTR buffer, ULONG size)
249 D(bug("[install] readBlock(vol:%x, block:%d, %d bytes)\n",
250 volume, block, size));
252 return ReadPartitionData(volume->startblock + block, volume->part, buffer, size);
255 ULONG writeBlock(struct Volume * volume, ULONG block, APTR buffer, ULONG size)
257 D(bug("[install] writeBlock(vol:%x, block:%d, %d bytes)\n",
258 volume, block, size));
260 if (myargs[ARG_TESTING])
261 return 0;
263 return WritePartitionData(volume->startblock + block, volume->part, buffer, size);
266 static BOOL isKnownFs(ULONG dos_id)
268 switch (dos_id)
270 case ID_FFS_DISK:
271 case ID_INTER_DOS_DISK:
272 case ID_INTER_FFS_DISK:
273 case ID_FASTDIR_DOS_DISK:
274 case ID_FASTDIR_FFS_DISK:
275 case ID_SFS_BE_DISK:
276 case ID_SFS_LE_DISK:
277 return TRUE;
280 return FALSE;
283 static BOOL GetPartitionNum(struct Volume *volume, struct PartitionHandle *parent,
284 struct PartitionHandle **extph)
286 struct PartitionHandle *pn;
287 UQUAD offset, start, end;
289 GetPartitionAttrsTags(parent, PT_STARTBLOCK, &offset, TAG_DONE);
291 for (pn = (struct PartitionHandle *) parent->table->list.lh_Head;
292 pn->ln.ln_Succ;
293 pn = (struct PartitionHandle *) pn->ln.ln_Succ)
295 if (extph)
297 struct PartitionType ptype = { };
299 GetPartitionAttrsTags(pn, PT_TYPE, &ptype, TAG_DONE);
300 if (ptype.id[0] == MBRT_EXTENDED || ptype.id[0] == MBRT_EXTENDED2)
302 *extph = pn;
303 continue;
307 GetPartitionAttrsTags(pn, PT_STARTBLOCK, &start, PT_ENDBLOCK, &end, TAG_DONE);
308 start += offset;
309 end += offset;
311 D(KPrintF("[install] checking partition start %llu end %llu\n", start, end));
312 if ((volume->startblock >= start) && (volume->startblock <= end))
314 GetPartitionAttrsTags(pn, PT_POSITION, &volume->partnum, TAG_DONE);
315 return TRUE;
318 return FALSE;
321 BOOL isvalidFileSystem(struct Volume *volume)
323 BOOL retval = FALSE;
324 ULONG dos_id;
326 D(bug("[install] isvalidFileSystem(%s, %d)\n", volume->device, volume->unitnum));
328 if (readBlock(volume, 0, volume->blockbuffer, volume->SizeBlock))
330 Printf("Read Error\n");
331 return FALSE;
334 dos_id = AROS_BE2LONG(volume->blockbuffer[0]);
336 if (!isKnownFs(dos_id))
338 /* first block has no DOS\x so we don't have RDB for sure */
339 volume->flags &= ~VF_IS_RDB;
340 if (readBlock(volume, 1, volume->blockbuffer, volume->SizeBlock))
342 Printf("Read Error\n");
343 return FALSE;
346 dos_id = AROS_BE2LONG(volume->blockbuffer[0]);
348 if (!isKnownFs(dos_id))
349 return FALSE;
351 D(bug("[install] Detected known DOSType 0x%08X\n", dos_id));
352 volume->dos_id = dos_id;
354 D(bug("[install] Looking for partition startblock %lu\n", volume->startblock));
355 if (OpenPartitionTable(volume->root) == 0)
357 struct TagItem tags[2];
358 ULONG type;
360 tags[1].ti_Tag = TAG_DONE;
361 tags[0].ti_Tag = PTT_TYPE;
362 tags[0].ti_Data = (STACKIPTR) & type;
363 GetPartitionTableAttrs(volume->root, tags);
365 if (type == PHPTT_MBR)
367 struct PartitionHandle *extph = NULL;
369 D(bug("[install] Found MBR table\n"));
370 if (GetPartitionNum(volume, volume->root, &extph))
372 retval = TRUE;
373 D(bug("[install] Primary partition found: partnum=%d\n", volume->partnum));
375 else if (extph != NULL)
377 if (OpenPartitionTable(extph) == 0)
379 GetPartitionTableAttrs(extph, tags);
380 if (type == PHPTT_EBR)
382 D(bug("[install] Found EBR table\n"));
383 if (GetPartitionNum(volume, extph, NULL))
385 volume->partnum += MBR_MAX_PARTITIONS;
386 retval = TRUE;
387 D(bug("[install] Logical partition found: partnum=%d\n", volume->partnum));
390 ClosePartitionTable(extph);
394 else if (type == PHPTT_RDB)
396 /* just use whole hard disk */
397 retval = TRUE;
399 else
400 Printf("only MBR and RDB partition tables are supported\n");
402 ClosePartitionTable(volume->root);
404 else
406 /* just use whole hard disk */
407 retval = TRUE;
409 return retval;
412 struct Volume *getGrubStageVolume(CONST_STRPTR device, ULONG unit,
413 ULONG flags, struct DosEnvec *de)
415 struct Volume *volume;
417 volume = initVolume(device, unit);
419 D(bug("[install] getGrubStageVolume(): volume=%x\n", volume));
421 if (volume)
423 if (fillGeometry(volume, de))
425 if (isvalidFileSystem(volume))
426 return volume;
427 else
429 Printf("stage2 is on an unsupported file system\n");
430 PrintFault(ERROR_OBJECT_WRONG_TYPE, NULL);
433 uninitVolume(volume);
435 return 0;
438 BOOL isvalidPartition(struct Volume *volume, LONG *pnum)
440 ULONG type;
441 struct TagItem tags[2];
442 BOOL retval = FALSE;
444 D(bug("[install] isvalidPartition(%d)\n", pnum));
446 tags[1].ti_Tag = TAG_DONE;
448 if (pnum)
450 /* install into partition bootblock */
451 /* is there a partition table? */
452 if (OpenPartitionTable(volume->root) == 0)
454 tags[0].ti_Tag = PTT_TYPE;
455 tags[0].ti_Data = (STACKIPTR) & type;
456 GetPartitionTableAttrs(volume->root, tags);
457 if (type == PHPTT_MBR)
459 struct PartitionHandle *pn;
461 /* search for partition */
462 tags[0].ti_Tag = PT_POSITION;
463 tags[0].ti_Data = (STACKIPTR) & type;
464 pn = (struct PartitionHandle *) volume->root->table->list.lh_Head;
465 while (pn->ln.ln_Succ)
467 GetPartitionAttrs(pn, tags);
468 if (type == *pnum)
469 break;
470 pn = (struct PartitionHandle *) pn->ln.ln_Succ;
472 if (pn->ln.ln_Succ)
474 struct PartitionType ptype;
476 /* is it an AROS partition? */
477 tags[0].ti_Tag = PT_TYPE;
478 tags[0].ti_Data = (STACKIPTR) & ptype;
479 GetPartitionAttrs(pn, tags);
480 if (ptype.id[0] == 0x30)
482 volume->part = pn;
483 retval = TRUE;
485 else
486 Printf("partition is not of type AROS (0x30)\n");
488 else
489 Printf("partition %ld not found on device %s unit %lu\n", *pnum, volume->device, volume->unitnum);
491 else
492 Printf("you can only install in partitions which are MBR partitioned\n");
494 else
495 Printf("Failed to open partition table on device %s unit %lu\n", *pnum, volume->device, volume->unitnum);
497 else
499 /* install into MBR */
500 volume->part = volume->root;
501 retval = TRUE;
504 if (retval)
506 volume->SizeBlock = volume->part->de.de_SizeBlock << 2;
507 retval = AllocBuffer(volume);
510 return retval;
513 struct Volume *getBBVolume(CONST_STRPTR device, ULONG unit, LONG * partnum)
515 struct Volume *volume;
517 D(bug("[install] getBBVolume(%s:%d, %d)\n", device, unit, partnum));
519 volume = initVolume(device, unit);
520 if (!volume)
521 return NULL;
523 if (isvalidPartition(volume, partnum))
525 volume->partnum = partnum ? *partnum : -1;
526 readBlock(volume, 0, volume->blockbuffer, volume->SizeBlock);
527 if (AROS_BE2LONG(volume->blockbuffer[0]) != IDNAME_RIGIDDISK)
529 /* Clear the boot sector region! */
530 memset(volume->blockbuffer, 0x00, 446);
531 return volume;
533 else
534 Printf("no space for bootblock (RDB is on block 0)\n");
536 uninitVolume(volume);
537 return NULL;
540 /* Convert a unit number into a drive number as understood by GRUB */
541 UWORD getDriveNumber(CONST_STRPTR device, ULONG unit)
543 struct PartitionHandle *ph;
544 ULONG i;
545 UWORD hd_count = 0;
547 for (i = 0; i < unit; i++)
549 ph = OpenRootPartition(device, i);
550 if (ph != NULL)
552 hd_count++;
553 CloseRootPartition(ph);
557 return hd_count;
560 BOOL writeBootIMG(STRPTR bootimgpath, struct Volume * bootimgvol, struct Volume * coreimgvol,
561 ULONG block /* first block of core.img file */, ULONG unit)
563 BOOL retval = FALSE;
564 LONG error = 0;
565 BPTR fh;
567 D(bug("[install] writeBootIMG(%x)\n", bootimgvol));
569 fh = Open(bootimgpath, MODE_OLDFILE);
570 if (fh)
572 if (Read(fh, bootimgvol->blockbuffer, 512) == 512)
574 /* install into MBR ? */
575 if ((bootimgvol->startblock == 0)
576 && (!(bootimgvol->flags & VF_IS_TRACKDISK)))
578 APTR boot_img = bootimgvol->blockbuffer;
580 UBYTE *boot_drive =
581 (UBYTE *) (boot_img + GRUB_BOOT_MACHINE_BOOT_DRIVE);
582 UWORD *boot_drive_check =
583 (UWORD *) (boot_img + GRUB_BOOT_MACHINE_DRIVE_CHECK);
585 if (unit == bootimgvol->unitnum)
586 *boot_drive = 0xFF;
587 else
588 *boot_drive = getDriveNumber(coreimgvol->device, unit)
589 | BIOS_HDISK_FLAG;
590 *boot_drive_check = 0x9090;
592 D(bug("[install] writeBootIMG: Install to HARDDISK\n"));
594 /* read old MBR */
595 error = readBlock(bootimgvol, 0, coreimgvol->blockbuffer, 512);
597 D(bug("[install] writeBootIMG: MBR Buffer @ %x\n", bootimgvol->blockbuffer));
598 D(bug("[install] writeBootIMG: Copying MBR BPB to %x\n",
599 (char *) bootimgvol->blockbuffer + GRUB_BOOT_MACHINE_BPB_START));
600 /* copy BPB (BIOS Parameter Block) */
601 CopyMem
602 ((APTR) ((char *) coreimgvol->blockbuffer + GRUB_BOOT_MACHINE_BPB_START),
603 (APTR) ((char *) bootimgvol->blockbuffer + GRUB_BOOT_MACHINE_BPB_START),
604 (GRUB_BOOT_MACHINE_BPB_END - GRUB_BOOT_MACHINE_BPB_START));
606 /* copy partition table - [Overwrites Floppy boot code] */
607 D(bug("[install] writeBootIMG: Copying MBR Partitions to %x\n",
608 (char *) bootimgvol->blockbuffer + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC));
609 CopyMem((APTR) ((char *) coreimgvol->blockbuffer + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC),
610 (APTR) ((char *) bootimgvol->blockbuffer + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC),
611 (GRUB_BOOT_MACHINE_PART_END - GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC));
613 /* Store the core.img pointer .. */
614 ULONG * coreimg_sector_start = (ULONG *) (boot_img
615 + GRUB_BOOT_MACHINE_KERNEL_SECTOR);
616 coreimg_sector_start[0] = block;
617 D(bug("[install] writeBootIMG: core.img pointer = %ld\n", block));
619 else
621 D(bug("[install] writeBootIMG: Install to FLOPPY\n"));
624 if (error == 0)
626 error = writeBlock(bootimgvol, 0, bootimgvol->blockbuffer, 512);
628 if (error)
629 Printf("WriteError %lu\n", (long)error);
630 else
631 retval = TRUE;
633 else
634 Printf("WriteError %lu\n", (long)error);
636 else
637 Printf("%s: Read Error\n", bootimgpath);
638 Close(fh);
640 else
641 PrintFault(IoErr(), bootimgpath);
643 return retval;
646 /* Collects the list of blocks that a file occupies on FFS filesystem */
647 ULONG collectBlockListFFS(struct Volume *volume, ULONG block, struct BlockNode *blocklist)
649 ULONG retval, first_block;
650 WORD blk_count,count;
651 UWORD i;
653 D(bug("[install] collectBlockListFFS(%x, %ld, %x)\n", volume, block, blocklist));
656 /* Clear the core.img sector pointers region! */
657 memset((UBYTE*)&blocklist[-BLCKLIST_ELEMENTS],0x00, BLCKLIST_ELEMENTS*sizeof(struct BlockNode));
660 The number of first block of core.img will be stored in boot.img
661 so skip the first filekey in the first loop
664 retval = readBlock(volume, block, volume->blockbuffer, volume->SizeBlock);
666 if (retval)
668 D(bug("[install] collectBlockListFFS: ERROR reading block (error: %ld\n", retval));
669 Printf("ReadError %lu\n", (long)retval);
670 return 0;
673 i = volume->SizeBlock - 52;
674 first_block = AROS_BE2LONG(volume->blockbuffer[volume->SizeBlock-51]);
675 blk_count=0;
677 D(bug("[install] collectBlockListFFS: First block @ %ld, i:%d\n", first_block, i));
682 retval = readBlock(volume, block, volume->blockbuffer, volume->SizeBlock);
683 if (retval)
685 D(bug("[install] collectBlockListFFS: ERROR reading block (error: %ld)\n", retval));
686 Printf("ReadError %lu\n", (long)retval);
687 return 0;
690 D(bug("[install] collectBlockListFFS: read block %ld, i = %d\n", block, i));
691 while ((i>=6) && (volume->blockbuffer[i]))
693 D(bug("[install] collectBlockListFFS: i = %d\n", i));
695 if current sector follows right after last sector
696 then we don't need a new element
698 if ((blocklist[blk_count].sector_lo) &&
699 ((blocklist[blk_count].sector_lo+blocklist[blk_count].count)==
700 AROS_BE2LONG(volume->blockbuffer[i])))
702 blocklist[blk_count].count += 1;
703 D(bug("[install] collectBlockListFFS: sector %d follows previous - increasing count of block %d to %d\n",
704 i, blk_count, blocklist[blk_count].count));
706 else
708 blk_count--; /* decrement first */
709 D(bug("[install] collectBlockListFFS: store new block (%d)\n", blk_count));
711 if ((blk_count-1) <= -BLCKLIST_ELEMENTS)
713 D(bug("[install] collectBlockListFFS: ERROR: out of block space at sector %d, block %d\n",
714 i, blk_count));
715 Printf("There is no more space to save blocklist in core.img\n");
716 return 0;
718 D(bug("[install] collectBlockListFFS: storing sector pointer for %d in block %d\n",
719 i, blk_count));
720 blocklist[blk_count].sector_lo = AROS_BE2LONG(volume->blockbuffer[i]);
721 blocklist[blk_count].sector_hi = 0;
722 blocklist[blk_count].count = 1;
724 i--;
726 i = volume->SizeBlock - 51;
727 block = AROS_BE2LONG(volume->blockbuffer[volume->SizeBlock - 2]);
728 D(bug("[install] collectBlockListFFS: next block %d, i = %d\n", block, i));
729 } while (block);
733 blocks in blocklist are relative to the first
734 sector of the HD (not partition)
737 D(bug("[install] collectBlockListFFS: successfully updated pointers for %d blocks\n", blk_count));
739 i = 0;
740 for (count=-1;count>=blk_count;count--)
742 blocklist[count].sector_lo += volume->startblock;
743 blocklist[count].seg_adr = 0x820 + (i*32);
744 i += blocklist[count].count;
745 D(bug("[install] collectBlockListFFS: correcting block %d for partition start\n", count));
746 D(bug("[install] collectBlockListFFS: sector : %ld seg_adr : %x\n",
747 blocklist[count].sector_lo, blocklist[count].seg_adr));
750 first_block += volume->startblock;
751 D(bug("[install] collectBlockListFFS: corrected first block for partition start: %ld\n", first_block));
753 return first_block;
756 /* Collects the list of blocks that a file occupies on SFS filesystem */
757 ULONG collectBlockListSFS(struct Volume *volume, ULONG objectnode, struct BlockNode *blocklist)
759 ULONG retval, first_block = 0;
760 WORD blk_count = 0, count = 0;
761 ULONG block_objectnoderoot = 0, block_sfsobjectcontainer = 0, block_extentbnoderoot = 0;
762 ULONG nextblock = 0, searchedblock = 0;
763 WORD i = 0;
764 UBYTE * tmpBytePtr = NULL;
766 D(bug("[install] collectBlockListSFS(startblock: %ld, objectnode: %ld)\n", volume->startblock, objectnode));
767 D(bug("[install] collectBlockListSFS(%ld, %d, %d)\n", volume->countblock, volume->SizeBlock, volume->partnum));
769 /* Clear the core.img sector pointers region! */
770 memset((UBYTE*)&blocklist[-BLCKLIST_ELEMENTS],0x00, BLCKLIST_ELEMENTS*sizeof(struct BlockNode));
772 /* Description of actions:
773 * 1. Load SFS root block
774 * 2. From root block find the block containing root of objectnodes
775 * 3. Traverse the tree of objectnodes until block of objectdescriptor is found
776 * 4. Search the objectdescriptor for entry matching given objectnode from entry read the
777 * first block of file
778 * 5. Having first file block, find the extentbnode for that block and read number
779 * of blocks. Put first block and number of blocks into BlockList.
780 * 6. If the file has more blocks than this exntentbnode hold, find first file
781 * block in next extentbnode. Go to step 5.
782 * Use the SFS source codes for reference. They operate on structures not pointers
783 * and are much easier to understand.
786 /* Read root block */
787 retval = readBlock(volume, 0, volume->blockbuffer, volume->SizeBlock);
789 if (retval)
791 D(bug("[install] collectBlockListSFS: ERROR reading root block (error: %ld)\n", retval));
792 Printf("ReadError %lu\n", (long)retval);
793 return 0;
796 /* Get block pointers from root block */
797 block_objectnoderoot = AROS_BE2LONG(volume->blockbuffer[28]); /* objectnoderoot - 29th ULONG */
798 block_extentbnoderoot = AROS_BE2LONG(volume->blockbuffer[27]); /* extentbnoderoot - 28th ULONG */
800 D(bug("[install] collectBlockListSFS: objectnoderoot: %ld, extentbnoderoot %ld\n",
801 block_objectnoderoot, block_extentbnoderoot));
805 /* Find the SFSObjectContainer block for given objectnode */
806 /* Reference: SFS, nodes.c, function findnode */
807 nextblock = block_objectnoderoot;
808 D(bug("[install] collectBlockListSFS: searching in nextblock %d for sfsobjectcontainer for objectnode %ld\n",
809 nextblock, objectnode));
810 while(1)
812 readBlock(volume, nextblock, volume->blockbuffer, volume->SizeBlock);
814 /* If nodes == 1, we are at the correct nodecontainer, else go to next nodecontainer */
815 if (AROS_BE2LONG(volume->blockbuffer[4]) == 1)
817 /* read entry from position: be_node + sizeof(fsObjectNode) * (objectnode - be_nodenumber) */
818 tmpBytePtr = (UBYTE*)volume->blockbuffer;
819 ULONG index = 20 + 10 * (objectnode - AROS_BE2LONG(volume->blockbuffer[3]));
820 block_sfsobjectcontainer = AROS_BE2LONG(((ULONG*)(tmpBytePtr + index))[0]);
821 D(bug("[install] collectBlockListSFS: leaf found in nextblock %ld, sfsobjectcontainer block is %ld \n",
822 nextblock, block_sfsobjectcontainer));
823 break;
825 else
827 UWORD containerentry =
828 (objectnode - AROS_BE2LONG(volume->blockbuffer[3]))/AROS_BE2LONG(volume->blockbuffer[4]);
829 nextblock = AROS_BE2LONG(volume->blockbuffer[containerentry + 5]) >> 4; /* 9-5 (2^9 = 512) */;
830 D(bug("[install] collectBlockListSFS: check next block %ld\n", nextblock));
834 if (block_sfsobjectcontainer == 0)
836 D(bug("[install] collectBlockListSFS: SFSObjectContainer not found\n"));
837 Printf("SFSObjectContainer not found\n");
838 return 0;
843 /* Find the SFSObject in SFSObjectContainer for given objectnode */
844 first_block = 0;
845 while((block_sfsobjectcontainer != 0) && (first_block == 0))
847 /* Read next SFS container block */
848 retval = readBlock(volume, block_sfsobjectcontainer, volume->blockbuffer, volume->SizeBlock);
850 if (retval)
852 D(bug("[install] collectBlockListSFS: ERROR reading block (error: %ld)\n", retval));
853 Printf("ReadError %lu\n", (long)retval);
854 return 0;
857 /* Iterate over SFS objects and match the objectnode */
859 * The first offset comes from :
860 * sizeof(sfsblockheader) = uint32 + uint32 + uint32 (field of sfsobjectcontainer)
861 * parent, next, previous = uint32 + uint32 + uint32 (fields of sfsobjectcontainers)
863 tmpBytePtr = ((UBYTE*)volume->blockbuffer) + 12 + 12; /* tmpBytePtr points to first object in container */
865 while (AROS_BE2LONG(((ULONG*)(tmpBytePtr + 4))[0]) > 0) /* check on the objectnode field */
868 /* Compare objectnode */
869 if (AROS_BE2LONG(((ULONG*)(tmpBytePtr + 4))[0]) == objectnode)
871 /* Found! */
872 first_block = AROS_BE2LONG(((ULONG*)(tmpBytePtr + 12))[0]); /* data */
873 D(bug("[install] collectBlockListSFS: first block is %ld\n", first_block));
874 break;
877 /* Move to next object */
878 /* Find end of name and end of comment */
879 tmpBytePtr += 25; /* Point to name */
880 count = 0;
881 for (i = 2; i > 0; tmpBytePtr++, count++)
882 if (*tmpBytePtr == '\0')
883 i--;
885 /* Correction for aligment */
886 if ((count & 0x01) == 0 )
887 tmpBytePtr++;
890 /* Move to next sfs object container block */
891 block_sfsobjectcontainer = AROS_BE2LONG(volume->blockbuffer[4]); /* next field */
895 if (first_block == 0)
897 D(bug("[install] collectBlockListSFS: First block not found\n"));
898 Printf("First block not found\n");
899 return 0;
904 /* First file block found. Find all blocks of file */
905 searchedblock = first_block;
906 blk_count = 0;
908 while(1)
910 nextblock = block_extentbnoderoot;
911 UBYTE * BNodePtr = NULL;
913 while(1)
915 /* Find the extentbnode for this block */
917 D(bug("[install] collectBlockListSFS: searching in nextblock %d for extentbnode for block %ld\n",
918 nextblock, searchedblock));
920 UBYTE * BTreeContainerPtr = NULL;
921 BNodePtr = NULL;
923 readBlock(volume, nextblock, volume->blockbuffer, volume->SizeBlock);
925 BTreeContainerPtr = (UBYTE*)(volume->blockbuffer + 3); /* Starts right after the header */
927 D(bug("[install] collectBlockListSFS: tree container nodecount: %d\n",
928 AROS_BE2WORD(((UWORD*)BTreeContainerPtr)[0])));
930 for (i = AROS_BE2WORD(((UWORD*)BTreeContainerPtr)[0]) - 1; i >=0; i--) /* Start from last element */
932 /* Read the BNode */
933 tmpBytePtr = BTreeContainerPtr + 4 + i * BTreeContainerPtr[3];
935 if (AROS_BE2LONG(((ULONG*)(tmpBytePtr))[0]) <= searchedblock) /* Check on the key field */
937 BNodePtr = tmpBytePtr;
938 break;
942 /* Fail if BNodePtr still NULL */
943 if (BNodePtr == NULL)
945 D(bug("[install] collectBlockListSFS: Failed to travers extentbnode tree.\n"));
946 Printf("Failed to travers extentbnode tree.\n");
947 return 0;
950 /* If we are at the leaf, stop */
951 if (BTreeContainerPtr[2])
952 break;
954 /* Else search further */
955 nextblock = AROS_BE2LONG(((ULONG*)(BNodePtr))[1]); /* data / next field */
958 /* Found. Add BlockList entry */
959 D(bug("[install] collectBlockListSFS: extentbnode for block %ld found. Block count: %d\n",
960 searchedblock, AROS_BE2WORD(((UWORD*)(BNodePtr + 12))[0])));
962 /* Add blocklist entry */
963 blk_count--;
965 /* Check if we still have spece left to add data to BlockList */
966 if ((blk_count-1) <= -BLCKLIST_ELEMENTS)
968 D(bug("[install] collectBlockListSFS: ERROR: out of block space\n"));
969 Printf("There is no more space to save blocklist in core.img\n");
970 return 0;
973 blocklist[blk_count].sector_lo = searchedblock;
974 blocklist[blk_count].sector_hi = 0;
975 blocklist[blk_count].count = AROS_BE2WORD(((UWORD*)(BNodePtr + 12))[0]);
977 /* Handling of special situations */
978 if (searchedblock == first_block)
980 /* Writting first pack of blocks. Pointer needs to point to second file block */
981 blocklist[blk_count].sector_lo++;
982 blocklist[blk_count].count--;
983 if (blocklist[blk_count].count == 0)
985 /* This means that the first pack of blocks contained only one block - first block */
986 /* Since the first blocklist needs to start at second file block, 'reset' the blk_count */
987 /* so that next iteration will overwrite the current results */
988 blk_count++;
992 /* Are there more blocks to read? */
993 if (AROS_BE2LONG(((ULONG*)(BNodePtr))[1]) == 0)
995 D(bug("[install] collectBlockListSFS: All core.img blocks found!\n"));
996 break;
998 else
999 searchedblock = AROS_BE2LONG(((ULONG*)(BNodePtr))[1]); /* data / next field */
1003 /* Correct blocks for volume start */
1005 /* Blocks in blocklist are relative to the first sector of the HD (not partition) */
1006 i = 0;
1007 for (count=-1;count>=blk_count;count--)
1009 blocklist[count].sector_lo += volume->startblock;
1010 blocklist[count].seg_adr = 0x820 + (i*32);
1011 i += blocklist[count].count;
1012 D(bug("[install] collectBlockListFFS: correcting block %d for partition start\n", count));
1013 D(bug("[install] collectBlockListFFS: sector : %ld seg_adr : %x\n",
1014 blocklist[count].sector_lo, blocklist[count].seg_adr));
1017 first_block += volume->startblock;
1019 return first_block;
1022 /* Flushes the cache on the volume containing the specified path. */
1023 VOID flushFS(CONST_STRPTR path)
1025 TEXT devname[256];
1026 UWORD i;
1028 for (i = 0; path[i] != ':'; i++)
1029 devname[i] = path[i];
1030 devname[i++] = ':';
1031 devname[i] = '\0';
1033 /* Try to flush 10 times. 5 seconds total */
1035 /* Failsafe in case first Inhibit fails in some way (was needed
1036 * for SFS because non flushed data was failing Inhibit) */
1038 for (i = 0; i < 10; i++)
1040 if (Inhibit(devname, DOSTRUE))
1042 Inhibit(devname, DOSFALSE);
1043 break;
1045 else
1046 Delay(25);
1050 BOOL writeCoreIMG(BPTR fh, UBYTE *buffer, struct Volume *volume)
1052 BOOL retval = FALSE;
1054 if (myargs[ARG_TESTING])
1055 return TRUE;
1057 D(bug("[install] writeCoreIMG(%x)\n", volume));
1059 if (Seek(fh, 0, OFFSET_BEGINNING) != -1)
1061 D(bug("[install] writeCoreIMG - write first block\n"));
1063 /* write back first block */
1064 if (Write(fh, buffer, 512) == 512)
1068 /* read second core.img block */
1069 if (Read(fh, buffer, 512) == 512)
1071 /* set partition number where core.img is on */
1072 LONG dos_part = 0;
1073 LONG bsd_part = 0; /*?? to fix = RDB part number of DH? */
1074 LONG *install_dos_part =
1075 (LONG *) (buffer + GRUB_KERNEL_MACHINE_INSTALL_DOS_PART);
1076 LONG *install_bsd_part =
1077 (LONG *) (buffer + GRUB_KERNEL_MACHINE_INSTALL_BSD_PART);
1079 dos_part = volume->partnum;
1081 D(bug("[install] set dos part = %d\n", dos_part));
1082 D(bug("[install] set bsd part = %d\n", bsd_part));
1084 *install_dos_part = dos_part;
1085 *install_bsd_part = bsd_part;
1087 /* write second core.img block back */
1088 if (Seek(fh, -512, OFFSET_CURRENT) != -1)
1090 if (Write(fh, buffer, 512) == 512)
1092 retval = TRUE;
1094 else
1095 Printf("Write Error\n");
1097 else
1098 Printf("Seek Error\n");
1100 else
1101 Printf("Read Error\n");
1103 else
1104 Printf("Write Error\n");
1106 else
1108 Printf("Seek Error\n");
1109 PrintFault(IoErr(), NULL);
1111 return retval;
1114 ULONG updateCoreIMG(CONST_STRPTR grubpath, /* path of grub dir */
1115 struct Volume *volume, /* volume core.img is on */
1116 ULONG *buffer /* a buffer of at least 512 bytes */)
1118 ULONG block = 0;
1119 struct FileInfoBlock fib;
1120 BPTR fh;
1121 TEXT coreimgpath[256];
1123 D(bug("[install] updateCoreIMG(%x)\n", volume));
1125 AddPart(coreimgpath, grubpath, 256);
1126 AddPart(coreimgpath, CORE_IMG_FILE_NAME, 256);
1127 fh = Open(coreimgpath, MODE_OLDFILE);
1128 if (fh)
1130 if (ExamineFH(fh, &fib))
1132 if (Read(fh, buffer, 512) == 512)
1135 Get and store all blocks of core.img in first block of core.img.
1136 First block of core.img will be returned.
1137 List of BlockNode starts at 512 - sizeof(BlockNode). List grows downwards.
1138 buffer is ULONG, buffer[128] is one pointer after first element(upwards).
1139 collectBlockList assumes it receives one pointer after first element(upwards).
1142 if (volume->dos_id == ID_SFS_BE_DISK)
1144 D(bug("[install] core.img on SFS file system\n"));
1145 block = collectBlockListSFS
1146 (volume, fib.fib_DiskKey, (struct BlockNode *)&buffer[128]);
1148 else
1149 if ((volume->dos_id == ID_FFS_DISK) || (volume->dos_id == ID_INTER_DOS_DISK) ||
1150 (volume->dos_id == ID_INTER_FFS_DISK) || (volume->dos_id == ID_FASTDIR_DOS_DISK) ||
1151 (volume->dos_id == ID_FASTDIR_FFS_DISK))
1153 D(bug("[install] core.img on FFS file system\n"));
1154 block = collectBlockListFFS
1155 (volume, fib.fib_DiskKey, (struct BlockNode *)&buffer[128]);
1157 else
1159 block = 0;
1160 D(bug("[install] core.img on unsupported file system\n"));
1161 Printf("Unsupported file system\n");
1164 D(bug("[install] core.img first block: %ld\n", block));
1166 if (block)
1168 if (!writeCoreIMG(fh, (UBYTE *)buffer, volume))
1169 block = 0;
1172 else
1173 Printf("%s: Read Error\n", coreimgpath);
1175 else
1176 PrintFault(IoErr(), coreimgpath);
1178 Close(fh);
1181 else
1182 PrintFault(IoErr(), coreimgpath);
1183 return block;
1186 /* Installs boot.img to MBR and updates core.img */
1187 BOOL installGrubFiles(struct Volume *coreimgvol, /* core.img volume */
1188 CONST_STRPTR grubpath, /* path to grub files */
1189 ULONG unit, /* unit core.img is on */
1190 struct Volume *bootimgvol) /* boot device for boot.img */
1192 BOOL retval = FALSE;
1193 TEXT bootimgpath[256];
1194 ULONG block;
1196 D(bug("[install] installStageFiles(%x)\n", bootimgvol));
1198 /* Flush GRUB volume's cache */
1199 flushFS(grubpath);
1201 block = updateCoreIMG(grubpath, coreimgvol, bootimgvol->blockbuffer);
1203 if (block)
1205 AddPart(bootimgpath, grubpath, 256);
1206 AddPart(bootimgpath, (CONST_STRPTR) "boot.img", 256);
1207 if (writeBootIMG(bootimgpath, bootimgvol, coreimgvol, block, unit))
1208 retval = TRUE;
1210 else
1211 bug("failed %d\n", IoErr());
1213 return retval;
1216 int main(int argc, char **argv)
1218 struct RDArgs *rdargs;
1219 struct Volume *grubvol;
1220 struct Volume *bbvol;
1221 struct FileSysStartupMsg *fssm;
1222 int ret = RETURN_OK;
1224 PartitionBase = (struct PartitionBase *)OpenLibrary("partition.library", 3);
1225 if (!PartitionBase)
1227 Printf("Failed to open partition.library v3!\n");
1228 return 20;
1231 D(bug("[install] main()\n"));
1233 rdargs = ReadArgs(template, myargs, NULL);
1234 if (rdargs)
1236 CONST_STRPTR bootDevice = (CONST_STRPTR) myargs[0];
1237 LONG unit = *(LONG *) myargs[1];
1238 LONG *partnum = (LONG *) myargs[2];
1239 CONST_STRPTR grubpath = (CONST_STRPTR) myargs[3];
1241 D(bug("[install] FORCELBA = %d\n", myargs[4]));
1242 if (myargs[4])
1243 Printf("FORCELBA ignored\n");
1244 if (myargs[ARG_TESTING])
1245 Printf("Test mode. No data will be changed!\n");
1247 if (partnum)
1249 Printf("PARTITIONNUMBER not supported yet\n");
1250 FreeArgs(rdargs);
1251 return RETURN_ERROR;
1254 fssm = getDiskFSSM(grubpath);
1255 if (fssm != NULL)
1257 CONST_STRPTR grubDevice = AROS_BSTR_ADDR(fssm->fssm_Device);
1259 if (!strcmp((const char *) grubDevice, (const char *) bootDevice))
1261 struct DosEnvec *dosEnvec;
1262 dosEnvec = (struct DosEnvec *) BADDR(fssm->fssm_Environ);
1264 grubvol = getGrubStageVolume(grubDevice, fssm->fssm_Unit,
1265 fssm->fssm_Flags, dosEnvec);
1266 if (grubvol)
1268 DumpVolume(grubvol, "GRUB volume");
1270 bbvol = getBBVolume(bootDevice, unit, partnum);
1271 if (bbvol)
1273 DumpVolume(bbvol, "Bootblock volume");
1275 if (!installGrubFiles(grubvol, grubpath,
1276 fssm->fssm_Unit, bbvol))
1277 ret = RETURN_ERROR;
1279 uninitVolume(bbvol);
1281 else
1283 D(bug("getBBVolume failed miserably\n"));
1284 ret = RETURN_ERROR;
1287 uninitVolume(grubvol);
1290 else
1292 Printf("%s is not on device %s unit %ld\n",
1293 grubpath, bootDevice, (long)unit);
1294 ret = RETURN_ERROR;
1297 else if (fssm)
1299 Printf("kernel path must begin with a device name\n");
1300 FreeArgs(rdargs);
1301 ret = RETURN_ERROR;
1304 FreeArgs(rdargs);
1306 else
1307 PrintFault(IoErr(), (STRPTR) argv[0]);
1309 CloseLibrary(&PartitionBase->lib);
1310 return ret;