2 Copyright © 1995-2009, The AROS Development Team. All rights reserved.
5 /******************************************************************************
14 DEVICE/A, UNIT/N/K/A, PARTITIONNUMBER=PN/K/N, GRUB/K/A, FORCELBA/S
22 Installs the GRUB 2 bootloader to the boot block of the specified
27 DEVICE -- Device name (e.g. ata.device)
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.
41 Install-grub2-i386-pc DEVICE ata.device UNIT 0 GRUB DH0:boot/grub
47 Partition, SYS:System/Format
51 ******************************************************************************/
54 #include <aros/debug.h>
57 #include <proto/exec.h>
58 #include <proto/dos.h>
59 #include <proto/partition.h>
60 #include <proto/utility.h>
61 #include <aros/macros.h>
62 #include <devices/hardblocks.h>
63 #include <devices/newstyle.h>
64 #include <exec/errors.h>
65 #include <exec/memory.h>
66 #include <libraries/partition.h>
70 /* Defines for grub2 data */
71 /* boot.img pointers */
72 #define GRUB_BOOT_MACHINE_BPB_START 0x03
73 #define GRUB_BOOT_MACHINE_BPB_END 0x5a
74 #define GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC 0x01b8 /* Following grub2 grub-setup sources */
75 #define GRUB_BOOT_MACHINE_PART_START 0x01be
76 #define GRUB_BOOT_MACHINE_PART_END 0x01fe
77 #define GRUB_BOOT_MACHINE_KERNEL_SECTOR 0x5c
78 #define GRUB_BOOT_MACHINE_BOOT_DRIVE 0x64
79 #define GRUB_BOOT_MACHINE_DRIVE_CHECK 0x66
81 /* core.img pointers */
82 #define GRUB_KERNEL_MACHINE_INSTALL_DOS_PART 0x14
83 #define GRUB_KERNEL_MACHINE_INSTALL_BSD_PART 0x18
86 #define BIOS_HDISK_FLAG 0x80
88 #define MBR_MAX_PARTITIONS 4
89 #define MBRT_EXTENDED 0x05
90 #define MBRT_EXTENDED2 0x0f
91 #define BLCKLIST_ELEMENTS 14
110 #define VF_IS_TRACKDISK (1<<0)
111 #define VF_IS_RDB (1<<1)
121 const TEXT version
[] = "$VER: Install-grub2-i386-pc 41.3 (3.9.2009)";
123 CONST_STRPTR CORE_IMG_FILE_NAME
= "core.img";
126 (STRPTR
) ("DEVICE/A," "UNIT/N/K/A," "PARTITIONNUMBER=PN/K/N," "GRUB/K/A,"
129 IPTR myargs
[7] = { 0, 0, 0, 0, 0, 0 };
131 struct FileSysStartupMsg
*getDiskFSSM(CONST_STRPTR path
)
134 struct DeviceNode
*dn
;
138 D(bug("[install] getDiskFSSM('%s')\n", path
));
140 for (i
= 0; (path
[i
]) && (path
[i
] != ':'); i
++)
145 dl
= LockDosList(LDF_READ
);
148 dn
= (struct DeviceNode
*) FindDosEntry(dl
, dname
, LDF_DEVICES
);
149 UnLockDosList(LDF_READ
);
154 if (IsFileSystem(dname
))
156 return (struct FileSysStartupMsg
*) BADDR(dn
->dn_Startup
);
159 Printf("device '%s' doesn't contain a file system\n",
163 PrintFault(ERROR_OBJECT_NOT_FOUND
, dname
);
167 Printf("'%s' doesn't contain a device name\n", path
);
171 void fillGeometry(struct Volume
*volume
, struct DosEnvec
*de
)
175 D(bug("[install] fillGeometry(%x)\n", volume
));
177 spc
= de
->de_Surfaces
* de
->de_BlocksPerTrack
;
178 volume
->SizeBlock
= de
->de_SizeBlock
;
179 volume
->startblock
= de
->de_LowCyl
* spc
;
181 ((de
->de_HighCyl
- de
->de_LowCyl
+ 1) * spc
) - 1 + de
->de_Reserved
;
184 void nsdCheck(struct Volume
*volume
)
186 struct NSDeviceQueryResult nsdq
;
189 D(bug("[install] nsdCheck(%x)\n", volume
));
191 if (((volume
->startblock
+ volume
->countblock
) * /* last block */
192 ((volume
->SizeBlock
<< 2) / 512) /* 1 portion (block) equals 512 (bytes) */
195 nsdq
.SizeAvailable
= 0;
196 nsdq
.DevQueryFormat
= 0;
197 volume
->iotd
->iotd_Req
.io_Command
= NSCMD_DEVICEQUERY
;
198 volume
->iotd
->iotd_Req
.io_Data
= &nsdq
;
199 volume
->iotd
->iotd_Req
.io_Length
= sizeof(struct NSDeviceQueryResult
);
200 if (DoIO((struct IORequest
*) &volume
->iotd
->iotd_Req
) == IOERR_NOCMD
)
202 Printf("Device doesn't understand NSD-Query\n");
206 if ((volume
->iotd
->iotd_Req
.io_Actual
>
207 sizeof(struct NSDeviceQueryResult
))
208 || (volume
->iotd
->iotd_Req
.io_Actual
== 0)
209 || (volume
->iotd
->iotd_Req
.io_Actual
!= nsdq
.SizeAvailable
))
211 Printf("WARNING wrong io_Actual using NSD\n");
215 if (nsdq
.DeviceType
!= NSDEVTYPE_TRACKDISK
)
216 Printf("WARNING no trackdisk type\n");
217 for (cmdcheck
= nsdq
.SupportedCommands
; *cmdcheck
; cmdcheck
++)
219 if (*cmdcheck
== NSCMD_TD_READ64
)
220 volume
->readcmd
= NSCMD_TD_READ64
;
221 if (*cmdcheck
== NSCMD_TD_WRITE64
);
222 volume
->writecmd
= NSCMD_TD_WRITE64
;
224 if ((volume
->readcmd
!= NSCMD_TD_READ64
) ||
225 (volume
->writecmd
!= NSCMD_TD_WRITE64
))
226 Printf("WARNING no READ64/WRITE64\n");
232 struct Volume
*initVolume(CONST_STRPTR device
, ULONG unit
, ULONG flags
,
235 struct Volume
*volume
;
238 D(bug("[install] initVolume(%s:%d)\n", device
, unit
));
240 volume
= AllocVec(sizeof(struct Volume
), MEMF_PUBLIC
| MEMF_CLEAR
);
243 volume
->mp
= CreateMsgPort();
247 (struct IOExtTD
*) CreateIORequest(volume
->mp
,
248 sizeof(struct IOExtTD
));
251 volume
->blockbuffer
=
252 AllocVec(de
->de_SizeBlock
<< 2, MEMF_PUBLIC
| MEMF_CLEAR
);
253 if (volume
->blockbuffer
)
257 unit
, (struct IORequest
*) volume
->iotd
, flags
) == 0)
259 if (strcmp((const char *) device
, TD_NAME
) == 0)
260 volume
->flags
|= VF_IS_TRACKDISK
;
262 volume
->flags
|= VF_IS_RDB
; /* just assume we have RDB */
263 volume
->readcmd
= CMD_READ
;
264 volume
->writecmd
= CMD_WRITE
;
265 volume
->device
= device
;
266 volume
->unitnum
= unit
;
268 fillGeometry(volume
, de
);
273 error
= ERROR_NO_FREE_STORE
;
274 FreeVec(volume
->blockbuffer
);
277 error
= ERROR_NO_FREE_STORE
;
278 DeleteIORequest((struct IORequest
*) volume
->iotd
);
281 error
= ERROR_NO_FREE_STORE
;
282 DeleteMsgPort(volume
->mp
);
285 error
= ERROR_NO_FREE_STORE
;
289 error
= ERROR_NO_FREE_STORE
;
291 PrintFault(error
, NULL
);
295 void uninitVolume(struct Volume
*volume
)
297 D(bug("[install] uninitVolume(%x)\n", volume
));
299 CloseDevice((struct IORequest
*) volume
->iotd
);
300 FreeVec(volume
->blockbuffer
);
301 DeleteIORequest((struct IORequest
*) volume
->iotd
);
302 DeleteMsgPort(volume
->mp
);
306 static ULONG
_readwriteBlock(struct Volume
*volume
,
307 ULONG block
, APTR buffer
, ULONG length
,
313 volume
->iotd
->iotd_Req
.io_Command
= command
;
314 volume
->iotd
->iotd_Req
.io_Length
= length
;
315 volume
->iotd
->iotd_Req
.io_Data
= buffer
;
316 offset
= (UQUAD
) (volume
->startblock
+ block
) * (volume
->SizeBlock
<< 2);
317 volume
->iotd
->iotd_Req
.io_Offset
= offset
& 0xFFFFFFFF;
318 volume
->iotd
->iotd_Req
.io_Actual
= offset
>> 32;
319 retval
= DoIO((struct IORequest
*) &volume
->iotd
->iotd_Req
);
320 if (volume
->flags
& VF_IS_TRACKDISK
)
322 volume
->iotd
->iotd_Req
.io_Command
= TD_MOTOR
;
323 volume
->iotd
->iotd_Req
.io_Length
= 0;
324 DoIO((struct IORequest
*) &volume
->iotd
->iotd_Req
);
329 ULONG
readBlock(struct Volume
* volume
, ULONG block
, APTR buffer
, ULONG size
)
331 D(bug("[install] readBlock(vol:%x, block:%d, %d bytes)\n",
332 volume
, block
, size
));
334 return _readwriteBlock(volume
, block
, buffer
, size
, volume
->readcmd
);
337 ULONG
writeBlock(struct Volume
* volume
, ULONG block
, APTR buffer
, ULONG size
)
339 D(bug("[install] writeBlock(vol:%x, block:%d, %d bytes)\n",
340 volume
, block
, size
));
342 return _readwriteBlock(volume
, block
, buffer
, size
, volume
->writecmd
);
345 static BOOL
isKnownFs(ULONG dos_id
)
350 case ID_INTER_DOS_DISK
:
351 case ID_INTER_FFS_DISK
:
352 case ID_FASTDIR_DOS_DISK
:
353 case ID_FASTDIR_FFS_DISK
:
362 BOOL
isvalidFileSystem(struct Volume
* volume
, CONST_STRPTR device
,
366 struct PartitionBase
*PartitionBase
;
367 struct PartitionHandle
*ph
;
370 D(bug("[install] isvalidFileSystem(%x, %s, %d)\n", volume
, device
, unit
));
372 if (readBlock(volume
, 0, volume
->blockbuffer
, 512))
374 Printf("Read Error\n");
378 dos_id
= AROS_BE2LONG(volume
->blockbuffer
[0]);
380 if (!isKnownFs(dos_id
))
382 /* first block has no DOS\x so we don't have RDB for sure */
383 volume
->flags
&= ~VF_IS_RDB
;
384 if (readBlock(volume
, 1, volume
->blockbuffer
, 512))
386 Printf("Read Error\n");
390 dos_id
= AROS_BE2LONG(volume
->blockbuffer
[0]);
392 if (!isKnownFs(dos_id
))
395 volume
->dos_id
= dos_id
;
398 volume
->dos_id
= dos_id
;
400 volume
->partnum
= -1;
403 (struct PartitionBase
*) OpenLibrary((CONST_STRPTR
)
404 "partition.library", 1);
407 ph
= OpenRootPartition(device
, unit
);
410 if (OpenPartitionTable(ph
) == 0)
412 struct TagItem tags
[3];
415 tags
[1].ti_Tag
= TAG_DONE
;
416 tags
[0].ti_Tag
= PTT_TYPE
;
417 tags
[0].ti_Data
= (STACKIPTR
) & type
;
418 GetPartitionTableAttrs(ph
, tags
);
419 if (type
== PHPTT_MBR
)
421 struct PartitionHandle
*pn
;
423 struct PartitionHandle
*extph
= NULL
;
424 struct PartitionType ptype
= { };
426 tags
[0].ti_Tag
= PT_DOSENVEC
;
427 tags
[0].ti_Data
= (STACKIPTR
) & de
;
428 tags
[1].ti_Tag
= PT_TYPE
;
429 tags
[1].ti_Data
= (STACKIPTR
) & ptype
;
430 tags
[2].ti_Tag
= TAG_DONE
;
431 pn
= (struct PartitionHandle
*) ph
->table
->list
.lh_Head
;
432 while (pn
->ln
.ln_Succ
)
436 GetPartitionAttrs(pn
, tags
);
437 if (ptype
.id
[0] == MBRT_EXTENDED
438 || ptype
.id
[0] == MBRT_EXTENDED2
)
442 scp
= de
.de_Surfaces
* de
.de_BlocksPerTrack
;
443 if ((volume
->startblock
>= (de
.de_LowCyl
* scp
))
444 && (volume
->startblock
<=
445 (((de
.de_HighCyl
+ 1) * scp
) - 1)))
448 pn
= (struct PartitionHandle
*) pn
->ln
.ln_Succ
;
452 tags
[0].ti_Tag
= PT_POSITION
;
453 tags
[0].ti_Data
= (STACKIPTR
) & type
;
454 tags
[1].ti_Tag
= TAG_DONE
;
455 GetPartitionAttrs(pn
, tags
);
456 volume
->partnum
= (UBYTE
) type
;
459 ("[install] Primary partition found: partnum=%d\n",
462 else if (extph
!= NULL
)
464 if (OpenPartitionTable(extph
) == 0)
466 tags
[0].ti_Tag
= PTT_TYPE
;
467 tags
[0].ti_Data
= (STACKIPTR
) & type
;
468 tags
[1].ti_Tag
= TAG_DONE
;
469 GetPartitionTableAttrs(extph
, tags
);
470 if (type
== PHPTT_EBR
)
472 tags
[0].ti_Tag
= PT_DOSENVEC
;
473 tags
[0].ti_Data
= (STACKIPTR
) & de
;
474 tags
[1].ti_Tag
= TAG_DONE
;
475 pn
= (struct PartitionHandle
*) extph
->table
->
477 while (pn
->ln
.ln_Succ
)
481 offset
= extph
->de
.de_LowCyl
482 * extph
->de
.de_Surfaces
483 * extph
->de
.de_BlocksPerTrack
;
484 GetPartitionAttrs(pn
, tags
);
486 de
.de_Surfaces
* de
.de_BlocksPerTrack
;
487 if ((volume
->startblock
>=
488 offset
+ (de
.de_LowCyl
* scp
))
489 && (volume
->startblock
<=
491 (((de
.de_HighCyl
+ 1) * scp
) -
494 pn
= (struct PartitionHandle
*) pn
->ln
.
499 tags
[0].ti_Tag
= PT_POSITION
;
500 tags
[0].ti_Data
= (STACKIPTR
) & type
;
501 GetPartitionAttrs(pn
, tags
);
503 MBR_MAX_PARTITIONS
+ (UBYTE
) type
;
506 ("[install] Logical partition found: partnum=%d\n",
507 (int) volume
->partnum
));
510 ClosePartitionTable(extph
);
516 if (type
== PHPTT_RDB
)
518 /* just use whole hard disk */
523 ("only MBR and RDB partition tables are supported\n");
525 ClosePartitionTable(ph
);
529 /* just use whole hard disk */
532 CloseRootPartition(ph
);
535 Printf("Error OpenRootPartition(%s,%lu)\n", device
, (long)unit
);
536 CloseLibrary((struct Library
*) PartitionBase
);
539 Printf("Couldn't open partition.library\n");
543 struct Volume
*getGrubStageVolume(CONST_STRPTR device
, ULONG unit
,
544 ULONG flags
, struct DosEnvec
*de
)
546 struct Volume
*volume
;
548 volume
= initVolume(device
, unit
, flags
, de
);
550 D(bug("[install] getGrubStageVolume(): volume=%x\n", volume
));
554 if (isvalidFileSystem(volume
, device
, unit
))
558 Printf("stage2 is on an unsupported file system\n");
559 PrintFault(ERROR_OBJECT_WRONG_TYPE
, NULL
);
561 uninitVolume(volume
);
566 BOOL
isvalidPartition(CONST_STRPTR device
, ULONG unit
, LONG
* pnum
,
567 struct DosEnvec
* de
)
569 struct PartitionBase
*PartitionBase
;
570 struct PartitionHandle
*ph
;
575 ("[install] isvalidPartition(%s:%d, part:%d)\n", device
, unit
, pnum
));
578 (struct PartitionBase
*) OpenLibrary((CONST_STRPTR
)
579 "partition.library", 1);
582 ph
= OpenRootPartition(device
, unit
);
585 struct TagItem tags
[2];
587 tags
[1].ti_Tag
= TAG_DONE
;
588 /* is there a partition table? */
589 if (OpenPartitionTable(ph
) == 0)
593 /* install into partition bootblock */
594 tags
[0].ti_Tag
= PTT_TYPE
;
595 tags
[0].ti_Data
= (STACKIPTR
) & type
;
596 GetPartitionTableAttrs(ph
, tags
);
597 if (type
== PHPTT_MBR
)
599 struct PartitionHandle
*pn
;
601 /* search for partition */
602 tags
[0].ti_Tag
= PT_POSITION
;
603 tags
[0].ti_Data
= (STACKIPTR
) & type
;
604 pn
= (struct PartitionHandle
*) ph
->table
->list
.
606 while (pn
->ln
.ln_Succ
)
608 GetPartitionAttrs(pn
, tags
);
611 pn
= (struct PartitionHandle
*) pn
->ln
.ln_Succ
;
615 struct PartitionType ptype
;
617 /* is it an AROS partition? */
618 tags
[0].ti_Tag
= PT_TYPE
;
619 tags
[0].ti_Data
= (STACKIPTR
) & ptype
;
620 GetPartitionAttrs(pn
, tags
);
621 if (ptype
.id
[0] == 0x30)
623 tags
[0].ti_Tag
= PT_DOSENVEC
;
624 tags
[0].ti_Data
= (STACKIPTR
) de
;
625 GetPartitionAttrs(pn
, tags
);
630 ("partition is not of type AROS (0x30)\n");
635 ("partition %ld not found on device %s unit %lu\n",
636 (long)*pnum
, device
, (long)unit
);
641 ("you can only install in partitions which are MBR partitioned\n");
645 /* install into MBR */
646 tags
[0].ti_Tag
= PTT_TYPE
;
647 tags
[0].ti_Data
= (STACKIPTR
) & type
;
648 GetPartitionTableAttrs(ph
, tags
);
649 if ((type
== PHPTT_MBR
) || (type
== PHPTT_RDB
))
651 tags
[0].ti_Tag
= PT_DOSENVEC
;
652 tags
[0].ti_Data
= (STACKIPTR
) de
;
653 GetPartitionAttrs(ph
, tags
);
658 ("partition table type must be either MBR or RDB\n");
660 ClosePartitionTable(ph
);
664 /* FIXME: GetPartitionAttr() should always work for root partition */
665 CopyMem(&ph
->de
, de
, sizeof(struct DosEnvec
));
668 CloseRootPartition(ph
);
671 Printf("Error OpenRootPartition(%s,%lu)\n", device
, (long)unit
);
672 CloseLibrary((struct Library
*) PartitionBase
);
675 Printf("Couldn't open partition.library\n");
679 struct Volume
*getBBVolume(CONST_STRPTR device
, ULONG unit
, LONG
* partnum
)
681 struct Volume
*volume
;
684 D(bug("[install] getBBVolume(%s:%d, %d)\n", device
, unit
, partnum
));
686 if (isvalidPartition(device
, unit
, partnum
, &de
))
688 volume
= initVolume(device
, unit
, 0, &de
);
689 volume
->partnum
= partnum
? *partnum
: -1;
690 readBlock(volume
, 0, volume
->blockbuffer
, 512);
691 if (AROS_BE2LONG(volume
->blockbuffer
[0]) != IDNAME_RIGIDDISK
)
693 /* Clear the boot sector region! */
694 memset(volume
->blockbuffer
, 0x00, 446);
698 Printf("no space for bootblock (RDB is on block 0)\n");
703 /* Convert a unit number into a drive number as understood by GRUB */
704 UWORD
getDriveNumber(CONST_STRPTR device
, ULONG unit
)
706 struct PartitionHandle
*ph
;
710 for (i
= 0; i
< unit
; i
++)
712 ph
= OpenRootPartition(device
, i
);
716 CloseRootPartition(ph
);
723 BOOL
writeBootIMG(STRPTR bootimgpath
, struct Volume
* bootimgvol
, struct Volume
* coreimgvol
,
724 ULONG block
/* first block of core.img file */, ULONG unit
)
730 D(bug("[install] writeBootIMG(%x)\n", bootimgvol
));
732 fh
= Open(bootimgpath
, MODE_OLDFILE
);
735 if (Read(fh
, bootimgvol
->blockbuffer
, 512) == 512)
737 /* install into MBR ? */
738 if ((bootimgvol
->startblock
== 0)
739 && (!(bootimgvol
->flags
& VF_IS_TRACKDISK
)))
741 APTR boot_img
= bootimgvol
->blockbuffer
;
744 (UBYTE
*) (boot_img
+ GRUB_BOOT_MACHINE_BOOT_DRIVE
);
745 UWORD
*boot_drive_check
=
746 (UWORD
*) (boot_img
+ GRUB_BOOT_MACHINE_DRIVE_CHECK
);
748 if (unit
== bootimgvol
->unitnum
)
751 *boot_drive
= getDriveNumber(coreimgvol
->device
, unit
)
753 *boot_drive_check
= 0x9090;
755 D(bug("[install] writeBootIMG: Install to HARDDISK\n"));
758 error
= readBlock(bootimgvol
, 0, coreimgvol
->blockbuffer
, 512);
760 D(bug("[install] writeBootIMG: MBR Buffer @ %x\n", bootimgvol
->blockbuffer
));
761 D(bug("[install] writeBootIMG: Copying MBR BPB to %x\n",
762 (char *) bootimgvol
->blockbuffer
+ GRUB_BOOT_MACHINE_BPB_START
));
763 /* copy BPB (BIOS Parameter Block) */
765 ((APTR
) ((char *) coreimgvol
->blockbuffer
+ GRUB_BOOT_MACHINE_BPB_START
),
766 (APTR
) ((char *) bootimgvol
->blockbuffer
+ GRUB_BOOT_MACHINE_BPB_START
),
767 (GRUB_BOOT_MACHINE_BPB_END
- GRUB_BOOT_MACHINE_BPB_START
));
769 /* copy partition table - [Overwrites Floppy boot code] */
770 D(bug("[install] writeBootIMG: Copying MBR Partitions to %x\n",
771 (char *) bootimgvol
->blockbuffer
+ GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC
));
772 CopyMem((APTR
) ((char *) coreimgvol
->blockbuffer
+ GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC
),
773 (APTR
) ((char *) bootimgvol
->blockbuffer
+ GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC
),
774 (GRUB_BOOT_MACHINE_PART_END
- GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC
));
776 /* Store the core.img pointer .. */
777 ULONG
* coreimg_sector_start
= (ULONG
*) (boot_img
778 + GRUB_BOOT_MACHINE_KERNEL_SECTOR
);
779 coreimg_sector_start
[0] = block
;
780 D(bug("[install] writeBootIMG: core.img pointer = %ld\n", block
));
784 D(bug("[install] writeBootIMG: Install to FLOPPY\n"));
789 error
= writeBlock(bootimgvol
, 0, bootimgvol
->blockbuffer
, 512);
792 Printf("WriteError %lu\n", (long)error
);
797 Printf("WriteError %lu\n", (long)error
);
800 Printf("%s: Read Error\n", bootimgpath
);
804 PrintFault(IoErr(), bootimgpath
);
809 /* Collects the list of blocks that a file occupies on FFS filesystem */
810 ULONG
collectBlockListFFS(struct Volume
*volume
, ULONG block
, struct BlockNode
*blocklist
)
812 ULONG retval
, first_block
;
813 WORD blk_count
,count
;
816 D(bug("[install] collectBlockListFFS(%x, %ld, %x)\n", volume
, block
, blocklist
));
819 /* Clear the core.img sector pointers region! */
820 memset((UBYTE
*)&blocklist
[-BLCKLIST_ELEMENTS
],0x00, BLCKLIST_ELEMENTS
*sizeof(struct BlockNode
));
823 The number of first block of core.img will be stored in boot.img
824 so skip the first filekey in the first loop
827 retval
= _readwriteBlock(volume
, block
, volume
->blockbuffer
, volume
->SizeBlock
<<2,
832 D(bug("[install] collectBlockListFFS: ERROR reading block (error: %ld\n", retval
));
833 Printf("ReadError %lu\n", (long)retval
);
837 i
= volume
->SizeBlock
- 52;
838 first_block
= AROS_BE2LONG(volume
->blockbuffer
[volume
->SizeBlock
-51]);
841 D(bug("[install] collectBlockListFFS: First block @ %ld, i:%d\n", first_block
, i
));
846 retval
= _readwriteBlock(volume
, block
, volume
->blockbuffer
, volume
->SizeBlock
<<2,
850 D(bug("[install] collectBlockListFFS: ERROR reading block (error: %ld)\n", retval
));
851 Printf("ReadError %lu\n", (long)retval
);
855 D(bug("[install] collectBlockListFFS: read block %ld, i = %d\n", block
, i
));
856 while ((i
>=6) && (volume
->blockbuffer
[i
]))
858 D(bug("[install] collectBlockListFFS: i = %d\n", i
));
860 if current sector follows right after last sector
861 then we don't need a new element
863 if ((blocklist
[blk_count
].sector_lo
) &&
864 ((blocklist
[blk_count
].sector_lo
+blocklist
[blk_count
].count
)==
865 AROS_BE2LONG(volume
->blockbuffer
[i
])))
867 blocklist
[blk_count
].count
+= 1;
868 D(bug("[install] collectBlockListFFS: sector %d follows previous - increasing count of block %d to %d\n",
869 i
, blk_count
, blocklist
[blk_count
].count
));
873 blk_count
--; /* decrement first */
874 D(bug("[install] collectBlockListFFS: store new block (%d)\n", blk_count
));
876 if ((blk_count
-1) <= -BLCKLIST_ELEMENTS
)
878 D(bug("[install] collectBlockListFFS: ERROR: out of block space at sector %d, block %d\n",
880 Printf("There is no more space to save blocklist in core.img\n");
883 D(bug("[install] collectBlockListFFS: storing sector pointer for %d in block %d\n",
885 blocklist
[blk_count
].sector_lo
= AROS_BE2LONG(volume
->blockbuffer
[i
]);
886 blocklist
[blk_count
].sector_hi
= 0;
887 blocklist
[blk_count
].count
= 1;
891 i
= volume
->SizeBlock
- 51;
892 block
= AROS_BE2LONG(volume
->blockbuffer
[volume
->SizeBlock
- 2]);
893 D(bug("[install] collectBlockListFFS: next block %d, i = %d\n", block
, i
));
898 blocks in blocklist are relative to the first
899 sector of the HD (not partition)
902 D(bug("[install] collectBlockListFFS: successfully updated pointers for %d blocks\n", blk_count
));
905 for (count
=-1;count
>=blk_count
;count
--)
907 blocklist
[count
].sector_lo
+= volume
->startblock
;
908 blocklist
[count
].seg_adr
= 0x820 + (i
*32);
909 i
+= blocklist
[count
].count
;
910 D(bug("[install] collectBlockListFFS: correcting block %d for partition start\n", count
));
911 D(bug("[install] collectBlockListFFS: sector : %ld seg_adr : %x\n",
912 blocklist
[count
].sector_lo
, blocklist
[count
].seg_adr
));
915 first_block
+= volume
->startblock
;
916 D(bug("[install] collectBlockListFFS: corrected first block for partition start: %ld\n", first_block
));
921 /* Collects the list of blocks that a file occupies on SFS filesystem */
922 ULONG
collectBlockListSFS(struct Volume
*volume
, ULONG objectnode
, struct BlockNode
*blocklist
)
924 ULONG retval
, first_block
= 0;
925 WORD blk_count
= 0, count
= 0;
926 ULONG block_objectnoderoot
= 0, block_sfsobjectcontainer
= 0, block_extentbnoderoot
= 0;
927 ULONG nextblock
= 0, searchedblock
= 0;
929 UBYTE
* tmpBytePtr
= NULL
;
931 D(bug("[install] collectBlockListSFS(startblock: %ld, objectnode: %ld)\n", volume
->startblock
, objectnode
));
932 D(bug("[install] collectBlockListSFS(%ld, %d, %d)\n", volume
->countblock
, volume
->SizeBlock
, volume
->partnum
));
934 /* Clear the core.img sector pointers region! */
935 memset((UBYTE
*)&blocklist
[-BLCKLIST_ELEMENTS
],0x00, BLCKLIST_ELEMENTS
*sizeof(struct BlockNode
));
937 /* Description of actions:
938 * 1. Load SFS root block
939 * 2. From root block find the block containing root of objectnodes
940 * 3. Traverse the tree of objectnodes until block of objectdescriptor is found
941 * 4. Search the objectdescriptor for entry matching given objectnode from entry read the
942 * first block of file
943 * 5. Having first file block, find the extentbnode for that block and read number
944 * of blocks. Put first block and number of blocks into BlockList.
945 * 6. If the file has more blocks than this exntentbnode hold, find first file
946 * block in next extentbnode. Go to step 5.
947 * Use the SFS source codes for reference. They operate on structures not pointers
948 * and are much easier to understand.
951 /* Read root block */
952 retval
= _readwriteBlock(volume
, 0, volume
->blockbuffer
, volume
->SizeBlock
<<2,
957 D(bug("[install] collectBlockListSFS: ERROR reading root block (error: %ld)\n", retval
));
958 Printf("ReadError %lu\n", (long)retval
);
962 /* Get block pointers from root block */
963 block_objectnoderoot
= AROS_BE2LONG(volume
->blockbuffer
[28]); /* objectnoderoot - 29th ULONG */
964 block_extentbnoderoot
= AROS_BE2LONG(volume
->blockbuffer
[27]); /* extentbnoderoot - 28th ULONG */
966 D(bug("[install] collectBlockListSFS: objectnoderoot: %ld, extentbnoderoot %ld\n",
967 block_objectnoderoot
, block_extentbnoderoot
));
971 /* Find the SFSObjectContainer block for given objectnode */
972 /* Reference: SFS, nodes.c, function findnode */
973 nextblock
= block_objectnoderoot
;
974 D(bug("[install] collectBlockListSFS: searching in nextblock %d for sfsobjectcontainer for objectnode %ld\n",
975 nextblock
, objectnode
));
978 _readwriteBlock(volume
, nextblock
, volume
->blockbuffer
, volume
->SizeBlock
<<2,
981 /* If nodes == 1, we are at the correct nodecontainer, else go to next nodecontainer */
982 if (AROS_BE2LONG(volume
->blockbuffer
[4]) == 1)
984 /* read entry from position: be_node + sizeof(fsObjectNode) * (objectnode - be_nodenumber) */
985 tmpBytePtr
= (UBYTE
*)volume
->blockbuffer
;
986 ULONG index
= 20 + 10 * (objectnode
- AROS_BE2LONG(volume
->blockbuffer
[3]));
987 block_sfsobjectcontainer
= AROS_BE2LONG(((ULONG
*)(tmpBytePtr
+ index
))[0]);
988 D(bug("[install] collectBlockListSFS: leaf found in nextblock %ld, sfsobjectcontainer block is %ld \n",
989 nextblock
, block_sfsobjectcontainer
));
994 UWORD containerentry
=
995 (objectnode
- AROS_BE2LONG(volume
->blockbuffer
[3]))/AROS_BE2LONG(volume
->blockbuffer
[4]);
996 nextblock
= AROS_BE2LONG(volume
->blockbuffer
[containerentry
+ 5]) >> 4; /* 9-5 (2^9 = 512) */;
997 D(bug("[install] collectBlockListSFS: check next block %ld\n", nextblock
));
1001 if (block_sfsobjectcontainer
== 0)
1003 D(bug("[install] collectBlockListSFS: SFSObjectContainer not found\n"));
1004 Printf("SFSObjectContainer not found\n");
1010 /* Find the SFSObject in SFSObjectContainer for given objectnode */
1012 while((block_sfsobjectcontainer
!= 0) && (first_block
== 0))
1014 /* Read next SFS container block */
1015 retval
= _readwriteBlock(volume
, block_sfsobjectcontainer
, volume
->blockbuffer
, volume
->SizeBlock
<<2,
1020 D(bug("[install] collectBlockListSFS: ERROR reading block (error: %ld)\n", retval
));
1021 Printf("ReadError %lu\n", (long)retval
);
1025 /* Iterate over SFS objects and match the objectnode */
1027 * The first offset comes from :
1028 * sizeof(sfsblockheader) = uint32 + uint32 + uint32 (field of sfsobjectcontainer)
1029 * parent, next, previous = uint32 + uint32 + uint32 (fields of sfsobjectcontainers)
1031 tmpBytePtr
= ((UBYTE
*)volume
->blockbuffer
) + 12 + 12; /* tmpBytePtr points to first object in container */
1033 while (AROS_BE2LONG(((ULONG
*)(tmpBytePtr
+ 4))[0]) > 0) /* check on the objectnode field */
1036 /* Compare objectnode */
1037 if (AROS_BE2LONG(((ULONG
*)(tmpBytePtr
+ 4))[0]) == objectnode
)
1040 first_block
= AROS_BE2LONG(((ULONG
*)(tmpBytePtr
+ 12))[0]); /* data */
1041 D(bug("[install] collectBlockListSFS: first block is %ld\n", first_block
));
1045 /* Move to next object */
1046 /* Find end of name and end of comment */
1047 tmpBytePtr
+= 25; /* Point to name */
1049 for (i
= 2; i
> 0; tmpBytePtr
++, count
++)
1050 if (*tmpBytePtr
== '\0')
1053 /* Correction for aligment */
1054 if ((count
& 0x01) == 0 )
1058 /* Move to next sfs object container block */
1059 block_sfsobjectcontainer
= AROS_BE2LONG(volume
->blockbuffer
[4]); /* next field */
1063 if (first_block
== 0)
1065 D(bug("[install] collectBlockListSFS: First block not found\n"));
1066 Printf("First block not found\n");
1072 /* First file block found. Find all blocks of file */
1073 searchedblock
= first_block
;
1078 nextblock
= block_extentbnoderoot
;
1079 UBYTE
* BNodePtr
= NULL
;
1083 /* Find the extentbnode for this block */
1085 D(bug("[install] collectBlockListSFS: searching in nextblock %d for extentbnode for block %ld\n",
1086 nextblock
, searchedblock
));
1088 UBYTE
* BTreeContainerPtr
= NULL
;
1091 _readwriteBlock(volume
, nextblock
, volume
->blockbuffer
, volume
->SizeBlock
<<2,
1094 BTreeContainerPtr
= (UBYTE
*)(volume
->blockbuffer
+ 3); /* Starts right after the header */
1096 D(bug("[install] collectBlockListSFS: tree container nodecount: %d\n",
1097 AROS_BE2WORD(((UWORD
*)BTreeContainerPtr
)[0])));
1099 for (i
= AROS_BE2WORD(((UWORD
*)BTreeContainerPtr
)[0]) - 1; i
>=0; i
--) /* Start from last element */
1101 /* Read the BNode */
1102 tmpBytePtr
= BTreeContainerPtr
+ 4 + i
* BTreeContainerPtr
[3];
1104 if (AROS_BE2LONG(((ULONG
*)(tmpBytePtr
))[0]) <= searchedblock
) /* Check on the key field */
1106 BNodePtr
= tmpBytePtr
;
1111 /* Fail if BNodePtr still NULL */
1112 if (BNodePtr
== NULL
)
1114 D(bug("[install] collectBlockListSFS: Failed to travers extentbnode tree.\n"));
1115 Printf("Failed to travers extentbnode tree.\n");
1119 /* If we are at the leaf, stop */
1120 if (BTreeContainerPtr
[2])
1123 /* Else search further */
1124 nextblock
= AROS_BE2LONG(((ULONG
*)(BNodePtr
))[1]); /* data / next field */
1127 /* Found. Add BlockList entry */
1128 D(bug("[install] collectBlockListSFS: extentbnode for block %ld found. Block count: %d\n",
1129 searchedblock
, AROS_BE2WORD(((UWORD
*)(BNodePtr
+ 12))[0])));
1131 /* Add blocklist entry */
1134 /* Check if we still have spece left to add data to BlockList */
1135 if ((blk_count
-1) <= -BLCKLIST_ELEMENTS
)
1137 D(bug("[install] collectBlockListSFS: ERROR: out of block space\n"));
1138 Printf("There is no more space to save blocklist in core.img\n");
1142 blocklist
[blk_count
].sector_lo
= searchedblock
;
1143 blocklist
[blk_count
].sector_hi
= 0;
1144 blocklist
[blk_count
].count
= AROS_BE2WORD(((UWORD
*)(BNodePtr
+ 12))[0]);
1146 /* Handling of special situations */
1147 if (searchedblock
== first_block
)
1149 /* Writting first pack of blocks. Pointer needs to point to second file block */
1150 blocklist
[blk_count
].sector_lo
++;
1151 blocklist
[blk_count
].count
--;
1152 if (blocklist
[blk_count
].count
== 0)
1154 /* This means that the first pack of blocks contained only one block - first block */
1155 /* Since the first blocklist needs to start at second file block, 'reset' the blk_count */
1156 /* so that next iteration will overwrite the current results */
1161 /* Are there more blocks to read? */
1162 if (AROS_BE2LONG(((ULONG
*)(BNodePtr
))[1]) == 0)
1164 D(bug("[install] collectBlockListSFS: All core.img blocks found!\n"));
1168 searchedblock
= AROS_BE2LONG(((ULONG
*)(BNodePtr
))[1]); /* data / next field */
1172 /* Correct blocks for volume start */
1174 /* Blocks in blocklist are relative to the first sector of the HD (not partition) */
1176 for (count
=-1;count
>=blk_count
;count
--)
1178 blocklist
[count
].sector_lo
+= volume
->startblock
;
1179 blocklist
[count
].seg_adr
= 0x820 + (i
*32);
1180 i
+= blocklist
[count
].count
;
1181 D(bug("[install] collectBlockListFFS: correcting block %d for partition start\n", count
));
1182 D(bug("[install] collectBlockListFFS: sector : %ld seg_adr : %x\n",
1183 blocklist
[count
].sector_lo
, blocklist
[count
].seg_adr
));
1186 first_block
+= volume
->startblock
;
1191 /* Flushes the cache on the volume containing the specified path. */
1192 VOID
flushFS(CONST_STRPTR path
)
1197 for (i
= 0; path
[i
] != ':'; i
++)
1198 devname
[i
] = path
[i
];
1202 /* Try to flush 10 times. 5 seconds total */
1204 /* Failsafe in case first Inhibit fails in some way (was needed
1205 * for SFS because non flushed data was failing Inhibit) */
1207 for (i
= 0; i
< 10; i
++)
1209 if (Inhibit(devname
, DOSTRUE
))
1211 Inhibit(devname
, DOSFALSE
);
1219 BOOL
writeCoreIMG(BPTR fh
, UBYTE
*buffer
, struct Volume
*volume
)
1221 BOOL retval
= FALSE
;
1223 D(bug("[install] writeCoreIMG(%x)\n", volume
));
1225 if (Seek(fh
, 0, OFFSET_BEGINNING
) != -1)
1227 D(bug("[install] writeCoreIMG - write first block\n"));
1229 /* write back first block */
1230 if (Write(fh
, buffer
, 512) == 512)
1234 /* read second core.img block */
1235 if (Read(fh
, buffer
, 512) == 512)
1237 /* set partition number where core.img is on */
1239 LONG bsd_part
= 0; /*?? to fix = RDB part number of DH? */
1240 LONG
*install_dos_part
=
1241 (LONG
*) (buffer
+ GRUB_KERNEL_MACHINE_INSTALL_DOS_PART
);
1242 LONG
*install_bsd_part
=
1243 (LONG
*) (buffer
+ GRUB_KERNEL_MACHINE_INSTALL_BSD_PART
);
1245 dos_part
= volume
->partnum
;
1247 D(bug("[install] set dos part = %d\n", dos_part
));
1248 D(bug("[install] set bsd part = %d\n", bsd_part
));
1250 *install_dos_part
= dos_part
;
1251 *install_bsd_part
= bsd_part
;
1253 /* write second core.img block back */
1254 if (Seek(fh
, -512, OFFSET_CURRENT
) != -1)
1256 if (Write(fh
, buffer
, 512) == 512)
1261 Printf("Write Error\n");
1264 Printf("Seek Error\n");
1267 Printf("Read Error\n");
1270 Printf("Write Error\n");
1274 Printf("Seek Error\n");
1275 PrintFault(IoErr(), NULL
);
1280 ULONG
updateCoreIMG(CONST_STRPTR grubpath
, /* path of grub dir */
1281 struct Volume
*volume
, /* volume core.img is on */
1282 ULONG
*buffer
/* a buffer of at least 512 bytes */)
1285 struct FileInfoBlock fib
;
1287 TEXT coreimgpath
[256];
1289 D(bug("[install] updateCoreIMG(%x)\n", volume
));
1291 AddPart(coreimgpath
, grubpath
, 256);
1292 AddPart(coreimgpath
, CORE_IMG_FILE_NAME
, 256);
1293 fh
= Open(coreimgpath
, MODE_OLDFILE
);
1296 if (ExamineFH(fh
, &fib
))
1298 if (Read(fh
, buffer
, 512) == 512)
1301 Get and store all blocks of core.img in first block of core.img.
1302 First block of core.img will be returned.
1303 List of BlockNode starts at 512 - sizeof(BlockNode). List grows downwards.
1304 buffer is ULONG, buffer[128] is one pointer after first element(upwards).
1305 collectBlockList assumes it receives one pointer after first element(upwards).
1308 if (volume
->dos_id
== ID_SFS_BE_DISK
)
1310 D(bug("[install] core.img on SFS file system\n"));
1311 block
= collectBlockListSFS
1312 (volume
, fib
.fib_DiskKey
, (struct BlockNode
*)&buffer
[128]);
1315 if ((volume
->dos_id
== ID_FFS_DISK
) || (volume
->dos_id
== ID_INTER_DOS_DISK
) ||
1316 (volume
->dos_id
== ID_INTER_FFS_DISK
) || (volume
->dos_id
== ID_FASTDIR_DOS_DISK
) ||
1317 (volume
->dos_id
== ID_FASTDIR_FFS_DISK
))
1319 D(bug("[install] core.img on FFS file system\n"));
1320 block
= collectBlockListFFS
1321 (volume
, fib
.fib_DiskKey
, (struct BlockNode
*)&buffer
[128]);
1326 D(bug("[install] core.img on unsupported file system\n"));
1327 Printf("Unsupported file system\n");
1330 D(bug("[install] core.img first block: %ld\n", block
));
1334 if (!writeCoreIMG(fh
, (UBYTE
*)buffer
, volume
))
1339 Printf("%s: Read Error\n", coreimgpath
);
1342 PrintFault(IoErr(), coreimgpath
);
1348 PrintFault(IoErr(), coreimgpath
);
1352 /* Installs boot.img to MBR and updates core.img */
1353 BOOL
installGrubFiles(struct Volume
*coreimgvol
, /* core.img volume */
1354 CONST_STRPTR grubpath
, /* path to grub files */
1355 ULONG unit
, /* unit core.img is on */
1356 struct Volume
*bootimgvol
) /* boot device for boot.img */
1358 BOOL retval
= FALSE
;
1359 TEXT bootimgpath
[256];
1362 D(bug("[install] installStageFiles(%x)\n", bootimgvol
));
1364 /* Flush GRUB volume's cache */
1367 block
= updateCoreIMG(grubpath
, coreimgvol
, bootimgvol
->blockbuffer
);
1371 AddPart(bootimgpath
, grubpath
, 256);
1372 AddPart(bootimgpath
, (CONST_STRPTR
) "boot.img", 256);
1373 if (writeBootIMG(bootimgpath
, bootimgvol
, coreimgvol
, block
, unit
))
1377 bug("failed %d\n", IoErr());
1382 int main(int argc
, char **argv
)
1384 struct RDArgs
*rdargs
;
1385 struct Volume
*grubvol
;
1386 struct Volume
*bbvol
;
1387 struct FileSysStartupMsg
*fssm
;
1388 int ret
= RETURN_OK
;
1390 D(bug("[install] main()\n"));
1392 rdargs
= ReadArgs(template, myargs
, NULL
);
1395 CONST_STRPTR bootDevice
= (CONST_STRPTR
) myargs
[0];
1396 LONG unit
= *(LONG
*) myargs
[1];
1397 LONG
*partnum
= (LONG
*) myargs
[2];
1398 CONST_STRPTR grubpath
= (CONST_STRPTR
) myargs
[3];
1400 D(bug("[install] FORCELBA = %d\n", myargs
[4]));
1402 Printf("FORCELBA ignored\n");
1406 Printf("PARTITIONNUMBER not supported yet\n");
1408 return RETURN_ERROR
;
1411 fssm
= getDiskFSSM(grubpath
);
1414 CONST_STRPTR grubDevice
= AROS_BSTR_ADDR(fssm
->fssm_Device
);
1416 if (!strcmp((const char *) grubDevice
, (const char *) bootDevice
))
1418 struct DosEnvec
*dosEnvec
;
1419 dosEnvec
= (struct DosEnvec
*) BADDR(fssm
->fssm_Environ
);
1421 grubvol
= getGrubStageVolume(grubDevice
, fssm
->fssm_Unit
,
1422 fssm
->fssm_Flags
, dosEnvec
);
1426 bbvol
= getBBVolume(bootDevice
, unit
, partnum
);
1429 if (!installGrubFiles(grubvol
, grubpath
,
1430 fssm
->fssm_Unit
, bbvol
))
1433 uninitVolume(bbvol
);
1437 D(bug("getBBVolume failed miserably\n"));
1441 uninitVolume(grubvol
);
1446 Printf("%s is not on device %s unit %ld\n",
1447 grubpath
, bootDevice
, (long)unit
);
1453 Printf("kernel path must begin with a device name\n");
1461 PrintFault(IoErr(), (STRPTR
) argv
[0]);