r9263@lvps87-230-33-50: verhaegs | 2008-10-04 23:31:42 +0200
[AROS.git] / workbench / c / Install-grub2-i386-pc.c
blob4e5b073bfcc38965b22b43bcc91402df3f2cb5d1
1 /*
2 Copyright © 1995-2008, 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
18 SYS:C
20 FUNCTION
22 Installs the GRUB bootloader to the bootblock of the specified disk.
24 INPUTS
26 DEVICE -- Device name (eg. ata.device)
27 UNIT -- Unit number
28 PN -- Partition number (advice: the first AROS FFS partition)
29 GRUB -- Path to GRUB directory.
30 FORCELBA -- Force use of LBA mode.
32 RESULT
34 NOTES
36 EXAMPLE
38 install-pc device ata.device unit 0 PN 1 grub dh0:boot/grub
40 BUGS
42 SEE ALSO
44 Partition, Sys:System/Format
46 INTERNALS
48 ******************************************************************************/
50 #define DEBUG 0
51 #include <aros/debug.h>
53 #include <stdio.h>
54 #include <string.h>
55 #include <proto/exec.h>
56 #include <proto/dos.h>
57 #include <proto/partition.h>
58 #include <proto/utility.h>
59 #include <aros/macros.h>
60 #include <devices/hardblocks.h>
61 #include <devices/newstyle.h>
62 #include <exec/errors.h>
63 #include <exec/memory.h>
64 #include <libraries/partition.h>
68 /* Defines for grub2 data */
69 /* boot.img pointers */
70 #define GRUB_BOOT_MACHINE_BPB_START 0x03
71 #define GRUB_BOOT_MACHINE_BPB_END 0x3e
72 #define GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC 0x01b8 /* Following grub2 grub-setup sources */
73 #define GRUB_BOOT_MACHINE_PART_START 0x01be
74 #define GRUB_BOOT_MACHINE_PART_END 0x01fe
75 #define GRUB_BOOT_MACHINE_KERNEL_SECTOR 0x44
76 #define GRUB_BOOT_MACHINE_BOOT_DRIVE 0x4c
77 #define GRUB_BOOT_MACHINE_ROOT_DRIVE 0x4d
78 #define GRUB_BOOT_MACHINE_DRIVE_CHECK 0x4f
80 /* core.img pointers */
81 #define GRUB_KERNEL_MACHINE_INSTALL_DOS_PART 0x14
82 #define GRUB_KERNEL_MACHINE_INSTALL_BSD_PART 0x18
84 /* BIOS drive flag */
85 #define BIOS_HDISK_FLAG 0x80
87 #define MBR_MAX_PARTITIONS 4
88 #define MBRT_EXTENDED 0x05
89 #define MBRT_EXTENDED2 0x0f
90 #define BLCKLIST_ELEMENTS 14
92 struct Volume
94 struct MsgPort *mp;
95 struct IOExtTD *iotd;
96 ULONG readcmd;
97 ULONG writecmd;
98 ULONG startblock;
99 ULONG countblock;
100 ULONG unitnum;
101 UWORD SizeBlock;
102 UBYTE flags;
103 BYTE partnum;
104 ULONG *blockbuffer;
105 ULONG dos_id;
108 #define VF_IS_TRACKDISK (1<<0)
109 #define VF_IS_RDB (1<<1)
111 struct BlockNode
113 ULONG sector_lo;
114 ULONG sector_hi;
115 UWORD count;
116 UWORD seg_adr;
119 CONST_STRPTR CORE_IMG_FILE_NAME = "core.img";
121 STRPTR template =
122 (STRPTR) ("DEVICE/A," "UNIT/N/K/A," "PARTITIONNUMBER=PN/K/N," "GRUB/K/A,"
123 "FORCELBA/S");
125 IPTR myargs[7] = { 0, 0, 0, 0, 0, 0 };
127 struct FileSysStartupMsg *getDiskFSSM(CONST_STRPTR path)
129 struct DosList *dl;
130 struct DeviceNode *dn;
131 TEXT dname[32];
132 UBYTE i;
134 D(bug("[install] getDiskFSSM('%s')\n", path));
136 for (i = 0; (path[i]) && (path[i] != ':'); i++)
137 dname[i] = path[i];
138 if (path[i] == ':')
140 dname[i] = 0;
141 dl = LockDosList(LDF_READ);
142 if (dl)
144 dn = (struct DeviceNode *) FindDosEntry(dl, dname, LDF_DEVICES);
145 UnLockDosList(LDF_READ);
146 if (dn)
148 if (IsFileSystem(dname))
150 return (struct FileSysStartupMsg *) BADDR(dn->dn_Startup);
152 else
153 printf("device '%s' doesn't contain a file system\n",
154 dname);
156 else
157 PrintFault(ERROR_OBJECT_NOT_FOUND, dname);
160 else
161 printf("'%s' doesn't contain a device name\n", path);
162 return 0;
165 void fillGeometry(struct Volume *volume, struct DosEnvec *de)
167 ULONG spc;
169 D(bug("[install] fillGeometry(%x)\n", volume));
171 spc = de->de_Surfaces * de->de_BlocksPerTrack;
172 volume->SizeBlock = de->de_SizeBlock;
173 volume->startblock = de->de_LowCyl * spc;
174 volume->countblock =
175 ((de->de_HighCyl - de->de_LowCyl + 1) * spc) - 1 + de->de_Reserved;
178 void nsdCheck(struct Volume *volume)
180 struct NSDeviceQueryResult nsdq;
181 UWORD *cmdcheck;
183 D(bug("[install] nsdCheck(%x)\n", volume));
185 if (((volume->startblock + volume->countblock) * /* last block */
186 ((volume->SizeBlock << 2) / 512) /* 1 portion (block) equals 512 (bytes) */
187 ) > 8388608)
189 nsdq.SizeAvailable = 0;
190 nsdq.DevQueryFormat = 0;
191 volume->iotd->iotd_Req.io_Command = NSCMD_DEVICEQUERY;
192 volume->iotd->iotd_Req.io_Data = &nsdq;
193 volume->iotd->iotd_Req.io_Length = sizeof(struct NSDeviceQueryResult);
194 if (DoIO((struct IORequest *) &volume->iotd->iotd_Req) == IOERR_NOCMD)
196 printf("Device doesn't understand NSD-Query\n");
198 else
200 if ((volume->iotd->iotd_Req.io_Actual >
201 sizeof(struct NSDeviceQueryResult))
202 || (volume->iotd->iotd_Req.io_Actual == 0)
203 || (volume->iotd->iotd_Req.io_Actual != nsdq.SizeAvailable))
205 printf("WARNING wrong io_Actual using NSD\n");
207 else
209 if (nsdq.DeviceType != NSDEVTYPE_TRACKDISK)
210 printf("WARNING no trackdisk type\n");
211 for (cmdcheck = nsdq.SupportedCommands; *cmdcheck; cmdcheck++)
213 if (*cmdcheck == NSCMD_TD_READ64)
214 volume->readcmd = NSCMD_TD_READ64;
215 if (*cmdcheck == NSCMD_TD_WRITE64);
216 volume->writecmd = NSCMD_TD_WRITE64;
218 if ((volume->readcmd != NSCMD_TD_READ64) ||
219 (volume->writecmd != NSCMD_TD_WRITE64))
220 printf("WARNING no READ64/WRITE64\n");
226 struct Volume *initVolume(CONST_STRPTR device, ULONG unit, ULONG flags,
227 struct DosEnvec *de)
229 struct Volume *volume;
230 LONG error = 0;
232 D(bug("[install] initVolume(%s:%d)\n", device, unit));
234 volume = AllocVec(sizeof(struct Volume), MEMF_PUBLIC | MEMF_CLEAR);
235 if (volume)
237 volume->mp = CreateMsgPort();
238 if (volume->mp)
240 volume->iotd =
241 (struct IOExtTD *) CreateIORequest(volume->mp,
242 sizeof(struct IOExtTD));
243 if (volume->iotd)
245 volume->blockbuffer =
246 AllocVec(de->de_SizeBlock << 2, MEMF_PUBLIC | MEMF_CLEAR);
247 if (volume->blockbuffer)
249 if (OpenDevice
250 (device,
251 unit, (struct IORequest *) volume->iotd, flags) == 0)
253 if (strcmp((const char *) device, TD_NAME) == 0)
254 volume->flags |= VF_IS_TRACKDISK;
255 else
256 volume->flags |= VF_IS_RDB; /* just assume we have RDB */
257 volume->readcmd = CMD_READ;
258 volume->writecmd = CMD_WRITE;
259 volume->unitnum = unit;
260 volume->dos_id = 0;
261 fillGeometry(volume, de);
262 nsdCheck(volume);
263 return volume;
265 else
266 error = ERROR_NO_FREE_STORE;
267 FreeVec(volume->blockbuffer);
269 else
270 error = ERROR_NO_FREE_STORE;
271 DeleteIORequest((struct IORequest *) volume->iotd);
273 else
274 error = ERROR_NO_FREE_STORE;
275 DeleteMsgPort(volume->mp);
277 else
278 error = ERROR_NO_FREE_STORE;
279 FreeVec(volume);
281 else
282 error = ERROR_NO_FREE_STORE;
284 PrintFault(error, NULL);
285 return NULL;
288 void uninitVolume(struct Volume *volume)
290 D(bug("[install] uninitVolume(%x)\n", volume));
292 CloseDevice((struct IORequest *) volume->iotd);
293 FreeVec(volume->blockbuffer);
294 DeleteIORequest((struct IORequest *) volume->iotd);
295 DeleteMsgPort(volume->mp);
296 FreeVec(volume);
299 static ULONG _readwriteBlock(struct Volume *volume,
300 ULONG block, APTR buffer, ULONG length,
301 ULONG command)
303 UQUAD offset;
304 ULONG retval = 0;
306 volume->iotd->iotd_Req.io_Command = command;
307 volume->iotd->iotd_Req.io_Length = length;
308 volume->iotd->iotd_Req.io_Data = buffer;
309 offset = (UQUAD) (volume->startblock + block) * (volume->SizeBlock << 2);
310 volume->iotd->iotd_Req.io_Offset = offset & 0xFFFFFFFF;
311 volume->iotd->iotd_Req.io_Actual = offset >> 32;
312 retval = DoIO((struct IORequest *) &volume->iotd->iotd_Req);
313 if (volume->flags & VF_IS_TRACKDISK)
315 volume->iotd->iotd_Req.io_Command = TD_MOTOR;
316 volume->iotd->iotd_Req.io_Length = 0;
317 DoIO((struct IORequest *) &volume->iotd->iotd_Req);
319 return retval;
322 ULONG readBlock(struct Volume * volume, ULONG block, APTR buffer, ULONG size)
324 D(bug("[install] readBlock(vol:%x, block:%d, %d bytes)\n",
325 volume, block, size));
327 return _readwriteBlock(volume, block, buffer, size, volume->readcmd);
330 ULONG writeBlock(struct Volume * volume, ULONG block, APTR buffer, ULONG size)
332 D(bug("[install] writeBlock(vol:%x, block:%d, %d bytes)\n",
333 volume, block, size));
335 return _readwriteBlock(volume, block, buffer, size, volume->writecmd);
338 static BOOL isKnownFs(ULONG dos_id)
340 switch (dos_id)
342 case ID_FFS_DISK:
343 case ID_INTER_DOS_DISK:
344 case ID_INTER_FFS_DISK:
345 case ID_FASTDIR_DOS_DISK:
346 case ID_FASTDIR_FFS_DISK:
347 case ID_SFS_BE_DISK:
348 case ID_SFS_LE_DISK:
349 return TRUE;
352 return FALSE;
355 BOOL isvalidFileSystem(struct Volume * volume, CONST_STRPTR device,
356 ULONG unit)
358 BOOL retval = FALSE;
359 struct PartitionBase *PartitionBase;
360 struct PartitionHandle *ph;
361 ULONG dos_id;
363 D(bug("[install] isvalidFileSystem(%x, %s, %d)\n", volume, device, unit));
365 if (readBlock(volume, 0, volume->blockbuffer, 512))
367 printf("Read Error\n");
368 return FALSE;
371 dos_id = AROS_BE2LONG(volume->blockbuffer[0]);
373 if (!isKnownFs(dos_id))
375 /* first block has no DOS\x so we don't have RDB for sure */
376 volume->flags &= ~VF_IS_RDB;
377 if (readBlock(volume, 1, volume->blockbuffer, 512))
379 printf("Read Error\n");
380 return FALSE;
383 dos_id = AROS_BE2LONG(volume->blockbuffer[0]);
385 if (!isKnownFs(dos_id))
386 return FALSE;
387 else
388 volume->dos_id = dos_id;
390 else
391 volume->dos_id = dos_id;
393 volume->partnum = -1;
395 PartitionBase =
396 (struct PartitionBase *) OpenLibrary((CONST_STRPTR)
397 "partition.library", 1);
398 if (PartitionBase)
400 ph = OpenRootPartition(device, unit);
401 if (ph)
403 if (OpenPartitionTable(ph) == 0)
405 struct TagItem tags[3];
406 IPTR type;
408 tags[1].ti_Tag = TAG_DONE;
409 tags[0].ti_Tag = PTT_TYPE;
410 tags[0].ti_Data = (STACKIPTR) & type;
411 GetPartitionTableAttrs(ph, tags);
412 if (type == PHPTT_MBR)
414 struct PartitionHandle *pn;
415 struct DosEnvec de;
416 struct PartitionHandle *extph = NULL;
417 struct PartitionType ptype = { };
419 tags[0].ti_Tag = PT_DOSENVEC;
420 tags[0].ti_Data = (STACKIPTR) & de;
421 tags[1].ti_Tag = PT_TYPE;
422 tags[1].ti_Data = (STACKIPTR) & ptype;
423 tags[2].ti_Tag = TAG_DONE;
424 pn = (struct PartitionHandle *) ph->table->list.lh_Head;
425 while (pn->ln.ln_Succ)
427 ULONG scp;
429 GetPartitionAttrs(pn, tags);
430 if (ptype.id[0] == MBRT_EXTENDED
431 || ptype.id[0] == MBRT_EXTENDED2)
432 extph = pn;
433 else
435 scp = de.de_Surfaces * de.de_BlocksPerTrack;
436 if ((volume->startblock >= (de.de_LowCyl * scp))
437 && (volume->startblock <=
438 (((de.de_HighCyl + 1) * scp) - 1)))
439 break;
441 pn = (struct PartitionHandle *) pn->ln.ln_Succ;
443 if (pn->ln.ln_Succ)
445 tags[0].ti_Tag = PT_POSITION;
446 tags[0].ti_Data = (STACKIPTR) & type;
447 tags[1].ti_Tag = TAG_DONE;
448 GetPartitionAttrs(pn, tags);
449 volume->partnum = (UBYTE) type;
450 retval = TRUE;
451 D(bug
452 ("[install] Primary partition found: partnum=%d\n",
453 volume->partnum));
455 else if (extph != NULL)
457 if (OpenPartitionTable(extph) == 0)
459 tags[0].ti_Tag = PTT_TYPE;
460 tags[0].ti_Data = (STACKIPTR) & type;
461 tags[1].ti_Tag = TAG_DONE;
462 GetPartitionTableAttrs(extph, tags);
463 if (type == PHPTT_EBR)
465 tags[0].ti_Tag = PT_DOSENVEC;
466 tags[0].ti_Data = (STACKIPTR) & de;
467 tags[1].ti_Tag = TAG_DONE;
468 pn = (struct PartitionHandle *) extph->table->
469 list.lh_Head;
470 while (pn->ln.ln_Succ)
472 ULONG offset, scp;
474 offset = extph->de.de_LowCyl
475 * extph->de.de_Surfaces
476 * extph->de.de_BlocksPerTrack;
477 GetPartitionAttrs(pn, tags);
478 scp =
479 de.de_Surfaces * de.de_BlocksPerTrack;
480 if ((volume->startblock >=
481 offset + (de.de_LowCyl * scp))
482 && (volume->startblock <=
483 offset +
484 (((de.de_HighCyl + 1) * scp) -
485 1)))
486 break;
487 pn = (struct PartitionHandle *) pn->ln.
488 ln_Succ;
490 if (pn->ln.ln_Succ)
492 tags[0].ti_Tag = PT_POSITION;
493 tags[0].ti_Data = (STACKIPTR) & type;
494 GetPartitionAttrs(pn, tags);
495 volume->partnum =
496 MBR_MAX_PARTITIONS + (UBYTE) type;
497 retval = TRUE;
498 D(bug
499 ("[install] Logical partition found: partnum=%d\n",
500 (int) volume->partnum));
503 ClosePartitionTable(extph);
507 else
509 if (type == PHPTT_RDB)
511 /* just use whole hard disk */
512 retval = TRUE;
514 else
515 printf
516 ("only MBR and RDB partition tables are supported\n");
518 ClosePartitionTable(ph);
520 else
522 /* just use whole hard disk */
523 retval = TRUE;
525 CloseRootPartition(ph);
527 else
528 printf("Error OpenRootPartition(%s,%d)\n", device, unit);
529 CloseLibrary((struct Library *) PartitionBase);
531 else
532 printf("Couldn't open partition.library\n");
533 return retval;
536 struct Volume *getGrubStageVolume(CONST_STRPTR device, ULONG unit,
537 ULONG flags, struct DosEnvec *de)
539 struct Volume *volume;
541 volume = initVolume(device, unit, flags, de);
543 D(bug("[install] getGrubStageVolume(): volume=%x\n", volume));
545 if (volume)
547 if (isvalidFileSystem(volume, device, unit))
548 return volume;
549 else
551 printf("stage2 is on an unsupported file system\n");
552 PrintFault(ERROR_OBJECT_WRONG_TYPE, NULL);
554 uninitVolume(volume);
556 return 0;
559 BOOL isvalidPartition(CONST_STRPTR device, ULONG unit, LONG * pnum,
560 struct DosEnvec * de)
562 struct PartitionBase *PartitionBase;
563 struct PartitionHandle *ph;
564 ULONG type;
565 BOOL retval = FALSE;
567 D(bug
568 ("[install] isvalidPartition(%s:%d, part:%d)\n", device, unit, pnum));
570 PartitionBase =
571 (struct PartitionBase *) OpenLibrary((CONST_STRPTR)
572 "partition.library", 1);
573 if (PartitionBase)
575 ph = OpenRootPartition(device, unit);
576 if (ph)
578 struct TagItem tags[2];
580 tags[1].ti_Tag = TAG_DONE;
581 /* is there a partition table? */
582 if (OpenPartitionTable(ph) == 0)
584 if (pnum)
586 /* install into partition bootblock */
587 tags[0].ti_Tag = PTT_TYPE;
588 tags[0].ti_Data = (STACKIPTR) & type;
589 GetPartitionTableAttrs(ph, tags);
590 if (type == PHPTT_MBR)
592 struct PartitionHandle *pn;
594 /* search for partition */
595 tags[0].ti_Tag = PT_POSITION;
596 tags[0].ti_Data = (STACKIPTR) & type;
597 pn = (struct PartitionHandle *) ph->table->list.
598 lh_Head;
599 while (pn->ln.ln_Succ)
601 GetPartitionAttrs(pn, tags);
602 if (type == *pnum)
603 break;
604 pn = (struct PartitionHandle *) pn->ln.ln_Succ;
606 if (pn->ln.ln_Succ)
608 struct PartitionType ptype;
610 /* is it an AROS partition? */
611 tags[0].ti_Tag = PT_TYPE;
612 tags[0].ti_Data = (STACKIPTR) & ptype;
613 GetPartitionAttrs(pn, tags);
614 if (ptype.id[0] == 0x30)
616 tags[0].ti_Tag = PT_DOSENVEC;
617 tags[0].ti_Data = (STACKIPTR) de;
618 GetPartitionAttrs(pn, tags);
619 retval = TRUE;
621 else
622 printf
623 ("partition is not of type AROS (0x30)\n");
625 else
627 printf
628 ("partition %d not found on device %s unit %d\n",
629 *pnum, device, unit);
632 else
633 printf
634 ("you can only install in partitions which are MBR partitioned\n");
636 else
638 /* install into MBR */
639 tags[0].ti_Tag = PTT_TYPE;
640 tags[0].ti_Data = (STACKIPTR) & type;
641 GetPartitionTableAttrs(ph, tags);
642 if ((type == PHPTT_MBR) || (type == PHPTT_RDB))
644 tags[0].ti_Tag = PT_DOSENVEC;
645 tags[0].ti_Data = (STACKIPTR) de;
646 GetPartitionAttrs(ph, tags);
647 retval = TRUE;
649 else
650 printf
651 ("partition table type must be either MBR or RDB\n");
653 ClosePartitionTable(ph);
655 else
657 #warning "FIXME: GetPartitionAttr() should always work for root partition"
658 CopyMem(&ph->de, de, sizeof(struct DosEnvec));
659 retval = TRUE;
661 CloseRootPartition(ph);
663 else
664 printf("Error OpenRootPartition(%s,%d)\n", device, unit);
665 CloseLibrary((struct Library *) PartitionBase);
667 else
668 printf("Couldn't open partition.library\n");
669 return retval;
672 struct Volume *getBBVolume(CONST_STRPTR device, ULONG unit, LONG * partnum)
674 struct Volume *volume;
675 struct DosEnvec de;
677 D(bug("[install] getBBVolume(%s:%d, %d)\n", device, unit, partnum));
679 if (isvalidPartition(device, unit, partnum, &de))
681 volume = initVolume(device, unit, 0, &de);
682 volume->partnum = partnum ? *partnum : -1;
683 readBlock(volume, 0, volume->blockbuffer, 512);
684 if (AROS_BE2LONG(volume->blockbuffer[0]) != IDNAME_RIGIDDISK)
686 /* Clear the boot sector region! */
687 memset(volume->blockbuffer, 0x00, 446);
688 return volume;
690 else
691 printf("no space for bootblock (RDB is on block 0)\n");
693 return NULL;
696 BOOL writeBootIMG(STRPTR bootimgpath, struct Volume * bootimgvol, struct Volume * coreimgvol,
697 ULONG block /* first block of core.img file */, ULONG unit)
699 BOOL retval = FALSE;
700 LONG error = 0;
701 BPTR fh;
703 D(bug("[install] writeBootIMG(%x)\n", bootimgvol));
705 fh = Open(bootimgpath, MODE_OLDFILE);
706 if (fh)
708 if (Read(fh, bootimgvol->blockbuffer, 512) == 512)
710 /* install into MBR ? */
711 if ((bootimgvol->startblock == 0)
712 && (!(bootimgvol->flags & VF_IS_TRACKDISK)))
714 APTR boot_img = bootimgvol->blockbuffer;
716 UBYTE *boot_drive =
717 (UBYTE *) (boot_img + GRUB_BOOT_MACHINE_BOOT_DRIVE);
718 UBYTE *root_drive =
719 (UBYTE *) (boot_img + GRUB_BOOT_MACHINE_ROOT_DRIVE);
720 UWORD *boot_drive_check =
721 (UWORD *) (boot_img + GRUB_BOOT_MACHINE_DRIVE_CHECK);
723 *boot_drive = 0xFF;
724 *root_drive = 0xFF;
725 *boot_drive_check = 0x9090;
727 D(bug("[install] writeBootIMG: Install to HARDDISK\n"));
729 /* read old MBR */
730 error = readBlock(bootimgvol, 0, coreimgvol->blockbuffer, 512);
732 D(bug("[install] writeBootIMG: MBR Buffer @ %x\n", bootimgvol->blockbuffer));
733 D(bug("[install] writeBootIMG: Copying MBR BPB to %x\n",
734 (char *) bootimgvol->blockbuffer + GRUB_BOOT_MACHINE_BPB_START));
735 /* copy BPB (BIOS Parameter Block) */
736 CopyMem
737 ((APTR) ((char *) coreimgvol->blockbuffer + GRUB_BOOT_MACHINE_BPB_START),
738 (APTR) ((char *) bootimgvol->blockbuffer + GRUB_BOOT_MACHINE_BPB_START),
739 (GRUB_BOOT_MACHINE_BPB_END - GRUB_BOOT_MACHINE_BPB_START));
741 /* copy partition table - [Overwrites Floppy boot code] */
742 D(bug("[install] writeBootIMG: Copying MBR Partitions to %x\n",
743 (char *) bootimgvol->blockbuffer + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC));
744 CopyMem((APTR) ((char *) coreimgvol->blockbuffer + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC),
745 (APTR) ((char *) bootimgvol->blockbuffer + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC),
746 (GRUB_BOOT_MACHINE_PART_END - GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC));
748 /* Store the core.img pointer .. */
749 ULONG * coreimg_sector_start = (ULONG *) (boot_img
750 + GRUB_BOOT_MACHINE_KERNEL_SECTOR);
751 coreimg_sector_start[0] = block;
752 D(bug("[install] writeBootIMG: core.img pointer = %ld\n", block));
754 else
756 D(bug("[install] writeBootIMG: Install to FLOPPY\n"));
759 if (error == 0)
761 error = writeBlock(bootimgvol, 0, bootimgvol->blockbuffer, 512);
763 if (error)
764 printf("WriteError %d\n", error);
765 else
766 retval = TRUE;
768 else
769 printf("WriteError %d\n", error);
771 else
772 printf("%s: Read Error\n", bootimgpath);
773 Close(fh);
775 else
776 PrintFault(IoErr(), bootimgpath);
778 return retval;
781 /* Collects the list of blocks that a file occupies on FFS filesystem*/
782 ULONG collectBlockListFFS(struct Volume *volume, ULONG block, struct BlockNode *blocklist)
784 ULONG retval, first_block;
785 WORD blk_count,count;
786 UWORD i;
788 D(bug("[install] collectBlockListFFS(%x, %ld, %x)\n", volume, block, blocklist));
791 /* Clear the core.img sector pointers region! */
792 memset((UBYTE*)&blocklist[-BLCKLIST_ELEMENTS],0x00, BLCKLIST_ELEMENTS*sizeof(struct BlockNode));
795 The number of first block of core.img will be stored in boot.img
796 so skip the first filekey in the first loop
799 retval = _readwriteBlock(volume, block, volume->blockbuffer, volume->SizeBlock<<2,
800 volume->readcmd);
802 if (retval)
804 D(bug("[install] collectBlockListFFS: ERROR reading block (error: %ld\n", retval));
805 printf("ReadError %d\n", retval);
806 return 0;
809 i = volume->SizeBlock - 52;
810 first_block = AROS_BE2LONG(volume->blockbuffer[volume->SizeBlock-51]);
811 blk_count=0;
813 D(bug("[install] collectBlockListFFS: First block @ %ld, i:%d\n", first_block, i));
818 retval = _readwriteBlock(volume, block, volume->blockbuffer, volume->SizeBlock<<2,
819 volume->readcmd);
820 if (retval)
822 D(bug("[install] collectBlockListFFS: ERROR reading block (error: %ld)\n", retval));
823 printf("ReadError %d\n", retval);
824 return 0;
827 D(bug("[install] collectBlockListFFS: read block %ld, i = %d\n", block, i));
828 while ((i>=6) && (volume->blockbuffer[i]))
830 D(bug("[install] collectBlockListFFS: i = %d\n", i));
832 if current sector follows right after last sector
833 then we don't need a new element
835 if ((blocklist[blk_count].sector_lo) &&
836 ((blocklist[blk_count].sector_lo+blocklist[blk_count].count)==
837 AROS_BE2LONG(volume->blockbuffer[i])))
839 blocklist[blk_count].count += 1;
840 D(bug("[install] collectBlockListFFS: sector %d follows previous - increasing count of block %d to %d\n",
841 i, blk_count, blocklist[blk_count].count));
843 else
845 blk_count--; /* decrement first */
846 D(bug("[install] collectBlockListFFS: store new block (%d)\n", blk_count));
848 if ((blk_count-1) <= -BLCKLIST_ELEMENTS)
850 D(bug("[install] collectBlockListFFS: ERROR: out of block space at sector %d, block %d\n",
851 i, blk_count));
852 printf("There is no more space to save blocklist in core.img\n");
853 return 0;
855 D(bug("[install] collectBlockListFFS: storing sector pointer for %d in block %d\n",
856 i, blk_count));
857 blocklist[blk_count].sector_lo = AROS_BE2LONG(volume->blockbuffer[i]);
858 blocklist[blk_count].sector_hi = 0;
859 blocklist[blk_count].count = 1;
861 i--;
863 i = volume->SizeBlock - 51;
864 block = AROS_BE2LONG(volume->blockbuffer[volume->SizeBlock - 2]);
865 D(bug("[install] collectBlockListFFS: next block %d, i = %d\n", block, i));
866 } while (block);
870 blocks in blocklist are relative to the first
871 sector of the HD (not partition)
874 D(bug("[install] collectBlockListFFS: successfully updated pointers for %d blocks\n", blk_count));
876 i = 0;
877 for (count=-1;count>=blk_count;count--)
879 blocklist[count].sector_lo += volume->startblock;
880 blocklist[count].seg_adr = 0x820 + (i*32);
881 i += blocklist[count].count;
882 D(bug("[install] collectBlockListFFS: correcting block %d for partition start\n", count));
883 D(bug("[install] collectBlockListFFS: sector : %ld seg_adr : %x\n",
884 blocklist[count].sector_lo, blocklist[count].seg_adr));
887 first_block += volume->startblock;
888 D(bug("[install] collectBlockListFFS: corrected first block for partition start: %ld\n", first_block));
890 return first_block;
893 /* Collects the list of blocks that a file occupies on SFS filesystem*/
894 ULONG collectBlockListSFS(struct Volume *volume, ULONG objectnode, struct BlockNode *blocklist)
896 ULONG retval, first_block = 0;
897 WORD blk_count = 0, count = 0;
898 ULONG block_objectnoderoot = 0, block_sfsobjectcontainer = 0, block_extentbnoderoot = 0;
899 ULONG nextblock = 0, searchedblock = 0;
900 WORD i = 0;
901 UBYTE * tmpBytePtr = NULL;
903 D(bug("[install] collectBlockListSFS(startblock: %ld, objectnode: %ld)\n", volume->startblock, objectnode));
904 D(bug("[install] collectBlockListSFS(%ld, %d, %d)\n", volume->countblock, volume->SizeBlock, volume->partnum));
906 /* Clear the core.img sector pointers region! */
907 memset((UBYTE*)&blocklist[-BLCKLIST_ELEMENTS],0x00, BLCKLIST_ELEMENTS*sizeof(struct BlockNode));
909 /* Description of actions:
910 * 1. Load SFS root block
911 * 2. From root block find the block containing root of objectnodes
912 * 3. Traverse the tree of objectnodes until block of objectdescriptor is found
913 * 4. Search the objectdescriptor for entry matching given objectnode from entry read the
914 * first block of file
915 * 5. Having first file block, find the extentbnode for that block and read number
916 * of blocks. Put first block and number of blocks into BlockList.
917 * 6. If the file has more blocks than this exntentbnode hold, find first file
918 * block in next extentbnode. Go to step 5.
919 * Use the SFS source codes for reference. They operate on structures not pointers
920 * and are much easier to understand.
923 /* Read root block */
924 retval = _readwriteBlock(volume, 0, volume->blockbuffer, volume->SizeBlock<<2,
925 volume->readcmd);
927 if (retval)
929 D(bug("[install] collectBlockListSFS: ERROR reading root block (error: %ld)\n", retval));
930 printf("ReadError %d\n", retval);
931 return 0;
934 /* Get block pointers from root block */
935 block_objectnoderoot = AROS_BE2LONG(volume->blockbuffer[28]); /* objectnoderoot - 29th ULONG */
936 block_extentbnoderoot = AROS_BE2LONG(volume->blockbuffer[27]); /* extentbnoderoot - 28th ULONG */
938 D(bug("[install] collectBlockListSFS: objectnoderoot: %ld, extentbnoderoot %ld\n",
939 block_objectnoderoot, block_extentbnoderoot));
943 /* Find the SFSObjectContainer block for given objectnode */
944 /* Reference: SFS, nodes.c, function findnode */
945 nextblock = block_objectnoderoot;
946 D(bug("[install] collectBlockListSFS: searching in nextblock %d for sfsobjectcontainer for objectnode %ld\n",
947 nextblock, objectnode));
948 while(1)
950 _readwriteBlock(volume, nextblock, volume->blockbuffer, volume->SizeBlock<<2,
951 volume->readcmd);
953 /* If nodes == 1, we are at the correct nodecontainer, else go to next nodecontainer */
954 if (AROS_BE2LONG(volume->blockbuffer[4]) == 1)
956 /* read entry from position: be_node + sizeof(fsObjectNode) * (objectnode - be_nodenumber) */
957 tmpBytePtr = (UBYTE*)volume->blockbuffer;
958 ULONG index = 20 + 10 * (objectnode - AROS_BE2LONG(volume->blockbuffer[3]));
959 block_sfsobjectcontainer = AROS_BE2LONG(((ULONG*)(tmpBytePtr + index))[0]);
960 D(bug("[install] collectBlockListSFS: leaf found in nextblock %ld, sfsobjectcontainer block is %ld \n",
961 nextblock, block_sfsobjectcontainer));
962 break;
964 else
966 UWORD containerentry =
967 (objectnode - AROS_BE2LONG(volume->blockbuffer[3]))/AROS_BE2LONG(volume->blockbuffer[4]);
968 nextblock = AROS_BE2LONG(volume->blockbuffer[containerentry + 5]) >> 4; /* 9-5 (2^9 = 512) */;
969 D(bug("[install] collectBlockListSFS: check next block %ld\n", nextblock));
973 if (block_sfsobjectcontainer == 0)
975 D(bug("[install] collectBlockListSFS: SFSObjectContainer not found\n"));
976 printf("SFSObjectContainer not found\n");
977 return 0;
982 /* Find the SFSObject in SFSObjectContainer for given objectnode */
983 first_block = 0;
984 while((block_sfsobjectcontainer != 0) && (first_block == 0))
986 /* Read next SFS container block */
987 retval = _readwriteBlock(volume, block_sfsobjectcontainer, volume->blockbuffer, volume->SizeBlock<<2,
988 volume->readcmd);
990 if (retval)
992 D(bug("[install] collectBlockListSFS: ERROR reading block (error: %ld)\n", retval));
993 printf("ReadError %d\n", retval);
994 return 0;
997 /* Iterate over SFS objects and match the objectnode */
999 * The first offset comes from :
1000 * sizeof(sfsblockheader) = uint32 + uint32 + uint32 (field of sfsobjectcontainer)
1001 * parent, next, previous = uint32 + uint32 + uint32 (fields of sfsobjectcontainers)
1003 tmpBytePtr = ((UBYTE*)volume->blockbuffer) + 12 + 12; /* tmpBytePtr points to first object in container */
1005 while (AROS_BE2LONG(((ULONG*)(tmpBytePtr + 4))[0]) > 0) /* check on the objectnode field */
1008 /* Compare objectnode */
1009 if (AROS_BE2LONG(((ULONG*)(tmpBytePtr + 4))[0]) == objectnode)
1011 /* Found! */
1012 first_block = AROS_BE2LONG(((ULONG*)(tmpBytePtr + 12))[0]); /* data */
1013 D(bug("[install] collectBlockListSFS: first block is %ld\n", first_block));
1014 break;
1017 /* Move to next object */
1018 /* Find end of name and end of comment */
1019 tmpBytePtr += 25; /* Point to name */
1020 count = 0;
1021 for (i = 2; i > 0; tmpBytePtr++, count++)
1022 if (*tmpBytePtr == '\0')
1023 i--;
1025 /* Correction for aligment */
1026 if ((count & 0x01) == 0 )
1027 tmpBytePtr++;
1030 /* Move to next sfs object container block */
1031 block_sfsobjectcontainer = AROS_BE2LONG(volume->blockbuffer[4]); /* next field */
1035 if (first_block == 0)
1037 D(bug("[install] collectBlockListSFS: First block not found\n"));
1038 printf("First block not found\n");
1039 return 0;
1044 /* First file block found. Find all blocks of file */
1045 searchedblock = first_block;
1046 blk_count = 0;
1048 while(1)
1050 nextblock = block_extentbnoderoot;
1051 UBYTE * BNodePtr = NULL;
1053 while(1)
1055 /* Find the extentbnode for this block */
1057 D(bug("[install] collectBlockListSFS: searching in nextblock %d for extentbnode for block %ld\n",
1058 nextblock, searchedblock));
1060 UBYTE * BTreeContainerPtr = NULL;
1061 BNodePtr = NULL;
1063 _readwriteBlock(volume, nextblock, volume->blockbuffer, volume->SizeBlock<<2,
1064 volume->readcmd);
1066 BTreeContainerPtr = (UBYTE*)(volume->blockbuffer + 3); /* Starts right after the header */
1068 D(bug("[install] collectBlockListSFS: tree container nodecount: %d\n",
1069 AROS_BE2WORD(((UWORD*)BTreeContainerPtr)[0])));
1071 for (i = AROS_BE2WORD(((UWORD*)BTreeContainerPtr)[0]) - 1; i >=0; i--) /* Start from last element */
1073 /* Read the BNode */
1074 tmpBytePtr = BTreeContainerPtr + 4 + i * BTreeContainerPtr[3];
1076 if (AROS_BE2LONG(((ULONG*)(tmpBytePtr))[0]) <= searchedblock) /* Check on the key field */
1078 BNodePtr = tmpBytePtr;
1079 break;
1083 /* Fail if BNodePtr still NULL */
1084 if (BNodePtr == NULL)
1086 D(bug("[install] collectBlockListSFS: Failed to travers extentbnode tree.\n"));
1087 printf("Failed to travers extentbnode tree.\n");
1088 return 0;
1091 /* If we are at the leaf, stop */
1092 if (BTreeContainerPtr[2])
1093 break;
1095 /* Else search further */
1096 nextblock = AROS_BE2LONG(((ULONG*)(BNodePtr))[1]); /* data / next field */
1099 /* Found. Add BlockList entry */
1100 D(bug("[install] collectBlockListSFS: extentbnode for block %ld found. Block count: %d\n",
1101 searchedblock, AROS_BE2WORD(((UWORD*)(BNodePtr + 12))[0])));
1103 /* Add blocklist entry */
1104 blk_count--;
1106 /* Check if we still have spece left to add data to BlockList */
1107 if ((blk_count-1) <= -BLCKLIST_ELEMENTS)
1109 D(bug("[install] collectBlockListSFS: ERROR: out of block space\n"));
1110 printf("There is no more space to save blocklist in core.img\n");
1111 return 0;
1114 blocklist[blk_count].sector_lo = searchedblock;
1115 blocklist[blk_count].sector_hi = 0;
1116 blocklist[blk_count].count = AROS_BE2WORD(((UWORD*)(BNodePtr + 12))[0]);
1118 /* Handling of special situations */
1119 if (searchedblock == first_block)
1121 /* Writting first pack of blocks. Pointer needs to point to second file block */
1122 blocklist[blk_count].sector_lo++;
1123 blocklist[blk_count].count--;
1124 if (blocklist[blk_count].count == 0)
1126 /* This means that the first pack of blocks contained only one block - first block */
1127 /* Since the first blocklist needs to start at second file block, 'reset' the blk_count */
1128 /* so that next iteration will overwrite the current results */
1129 blk_count++;
1133 /* Are there more blocks to read? */
1134 if (AROS_BE2LONG(((ULONG*)(BNodePtr))[1]) == 0)
1136 D(bug("[install] collectBlockListSFS: All core.img blocks found!\n"));
1137 break;
1139 else
1140 searchedblock = AROS_BE2LONG(((ULONG*)(BNodePtr))[1]); /* data / next field */
1144 /* Correct blocks for volume start */
1146 /* Blocks in blocklist are relative to the first sector of the HD (not partition) */
1147 i = 0;
1148 for (count=-1;count>=blk_count;count--)
1150 blocklist[count].sector_lo += volume->startblock;
1151 blocklist[count].seg_adr = 0x820 + (i*32);
1152 i += blocklist[count].count;
1153 D(bug("[install] collectBlockListFFS: correcting block %d for partition start\n", count));
1154 D(bug("[install] collectBlockListFFS: sector : %ld seg_adr : %x\n",
1155 blocklist[count].sector_lo, blocklist[count].seg_adr));
1158 first_block += volume->startblock;
1160 return first_block;
1163 /* Flushes the cache on the volume containing the specified path. */
1164 VOID flushFS(CONST_STRPTR path)
1166 TEXT devname[256];
1167 UWORD i;
1169 for (i = 0; path[i] != ':'; i++)
1170 devname[i] = path[i];
1171 devname[i++] = ':';
1172 devname[i] = '\0';
1174 /* Try to flush 10 times. 5 seconds total */
1176 /* Failsfase in case first Inhibit fails in some way (was needed
1177 * for SFS because non flushed data was failing Inhibit) */
1179 for (i = 0; i < 10; i++)
1181 if (Inhibit(devname, DOSTRUE))
1183 Inhibit(devname, DOSFALSE);
1184 break;
1186 else
1187 Delay(25);
1191 BOOL writeCoreIMG(BPTR fh, UBYTE *buffer, struct Volume *volume)
1193 BOOL retval = FALSE;
1195 D(bug("[install] writeCoreIMG(%x)\n", volume));
1197 if (Seek(fh, 0, OFFSET_BEGINNING) != -1)
1199 D(bug("[install] writeCoreIMG - write first block\n"));
1201 /* write back first block */
1202 if (Write(fh, buffer, 512) == 512)
1206 /* read second core.img block */
1207 if (Read(fh, buffer, 512) == 512)
1209 /* set partition number where core.img is on */
1210 LONG dos_part = 0;
1211 LONG bsd_part = 0; /*?? to fix = RDB part number of DH? */
1212 LONG *install_dos_part =
1213 (LONG *) (buffer + GRUB_KERNEL_MACHINE_INSTALL_DOS_PART);
1214 LONG *install_bsd_part =
1215 (LONG *) (buffer + GRUB_KERNEL_MACHINE_INSTALL_BSD_PART);
1217 dos_part = volume->partnum;
1219 D(bug("[install] set dos part = %d\n", dos_part));
1220 D(bug("[install] set bsd part = %d\n", bsd_part));
1222 *install_dos_part = dos_part;
1223 *install_bsd_part = bsd_part;
1225 /* write second core.img block back */
1226 if (Seek(fh, -512, OFFSET_CURRENT) != -1)
1228 if (Write(fh, buffer, 512) == 512)
1230 retval = TRUE;
1232 else
1233 printf("Write Error\n");
1235 else
1236 printf("Seek Error\n");
1238 else
1239 printf("Read Error\n");
1241 else
1242 printf("Write Error\n");
1244 else
1246 printf("Seek Error\n");
1247 PrintFault(IoErr(), NULL);
1249 return retval;
1252 ULONG updateCoreIMG(CONST_STRPTR grubpath, /* path of grub dir */
1253 struct Volume *volume, /* volume core.img is on */
1254 ULONG *buffer /* a buffer of at least 512 bytes */)
1256 ULONG block = 0;
1257 struct FileInfoBlock fib;
1258 BPTR fh;
1259 TEXT coreimgpath[256];
1261 D(bug("[install] updateCoreIMG(%x)\n", volume));
1263 AddPart(coreimgpath, grubpath, 256);
1264 AddPart(coreimgpath, CORE_IMG_FILE_NAME, 256);
1265 fh = Open(coreimgpath, MODE_OLDFILE);
1266 if (fh)
1268 if (Examine(fh, &fib))
1270 if (Read(fh, buffer, 512) == 512)
1273 Get and store all blocks of core.img in first block of core.img.
1274 First block of core.img will be returned.
1275 List of BlockNode starts at 512 - sizeof(BlockNode). List grows downwards.
1276 buffer is ULONG, buffer[128] is one pointer after first element(upwards).
1277 collectBlockList assumes it receives one pointer after first element(upwards).
1280 if (volume->dos_id == ID_SFS_BE_DISK)
1282 D(bug("[install] core.img on SFS file system\n"));
1283 block = collectBlockListSFS
1284 (volume, fib.fib_DiskKey, (struct BlockNode *)&buffer[128]);
1286 else
1287 if ((volume->dos_id == ID_FFS_DISK) || (volume->dos_id == ID_INTER_DOS_DISK) ||
1288 (volume->dos_id == ID_INTER_FFS_DISK) || (volume->dos_id == ID_FASTDIR_DOS_DISK) ||
1289 (volume->dos_id == ID_FASTDIR_FFS_DISK))
1291 D(bug("[install] core.img on FFS file system\n"));
1292 block = collectBlockListFFS
1293 (volume, fib.fib_DiskKey, (struct BlockNode *)&buffer[128]);
1295 else
1297 block = 0;
1298 D(bug("[install] core.img on unsupported file system\n"));
1299 printf("Unsupported file system\n");
1302 D(bug("[install] core.img first block: %ld\n", block));
1304 if (block)
1306 if (!writeCoreIMG(fh, (UBYTE *)buffer, volume))
1307 block = 0;
1310 else
1311 printf("%s: Read Error\n", coreimgpath);
1313 else
1314 PrintFault(IoErr(), coreimgpath);
1316 Close(fh);
1319 else
1320 PrintFault(IoErr(), coreimgpath);
1321 return block;
1324 /* Installs boot.img to MBR and updates core.img */
1325 BOOL installGrubFiles(struct Volume *coreimgvol, /* core.img volume */
1326 CONST_STRPTR grubpath, /* path to grub files */
1327 ULONG unit, /* unit core.img is on */
1328 struct Volume *bootimgvol) /* boot device for boot.img */
1330 BOOL retval = FALSE;
1331 TEXT bootimgpath[256];
1332 ULONG block;
1334 D(bug("[install] installStageFiles(%x)\n", bootimgvol));
1336 /* Flush GRUB volume's cache */
1337 flushFS(grubpath);
1339 block = updateCoreIMG(grubpath, coreimgvol, bootimgvol->blockbuffer);
1341 if (block)
1343 AddPart(bootimgpath, grubpath, 256);
1344 AddPart(bootimgpath, (CONST_STRPTR) "boot.img", 256);
1345 if (writeBootIMG(bootimgpath, bootimgvol, coreimgvol, block, unit))
1346 retval = TRUE;
1348 else
1349 bug("failed %d\n", IoErr());
1351 return retval;
1354 int main(int argc, char **argv)
1356 struct RDArgs *rdargs;
1357 struct Volume *grubvol;
1358 struct Volume *bbvol;
1359 struct FileSysStartupMsg *fssm;
1360 int ret = RETURN_OK;
1362 D(bug("[install] main()\n"));
1364 rdargs = ReadArgs(template, myargs, NULL);
1365 if (rdargs)
1367 CONST_STRPTR bootDevice = (CONST_STRPTR) myargs[0];
1368 LONG unit = *(LONG *) myargs[1];
1369 LONG *partnum = (LONG *) myargs[2];
1370 CONST_STRPTR grubpath = (CONST_STRPTR) myargs[3];
1372 D(bug("[install] FORCELBA = %d\n", myargs[4]));
1373 if (myargs[4])
1374 printf("FORCELBA ignored\n");
1376 if (partnum)
1378 printf("PARTITIONNUMBER not supported yet\n");
1379 FreeArgs(rdargs);
1380 return RETURN_ERROR;
1383 fssm = getDiskFSSM(grubpath);
1384 if (fssm != NULL)
1386 CONST_STRPTR grubDevice = AROS_BSTR_ADDR(fssm->fssm_Device);
1388 if (!strcmp((const char *) grubDevice, (const char *) bootDevice))
1390 struct DosEnvec *dosEnvec;
1391 dosEnvec = (struct DosEnvec *) BADDR(fssm->fssm_Environ);
1393 grubvol = getGrubStageVolume(grubDevice, fssm->fssm_Unit,
1394 fssm->fssm_Flags, dosEnvec);
1395 if (grubvol)
1398 bbvol = getBBVolume(bootDevice, unit, partnum);
1399 if (bbvol)
1401 if (!installGrubFiles(grubvol, grubpath,
1402 fssm->fssm_Unit, bbvol))
1403 ret = RETURN_ERROR;
1405 uninitVolume(bbvol);
1407 else
1409 D(bug("getBBVolume failed miserably\n"));
1410 ret = RETURN_ERROR;
1413 uninitVolume(grubvol);
1416 else
1418 printf("%s is not on device %s unit %d\n",
1419 grubpath, bootDevice, unit);
1420 ret = RETURN_ERROR;
1423 else if (fssm)
1425 printf("kernel path must begin with a device name\n");
1426 FreeArgs(rdargs);
1427 ret = RETURN_ERROR;
1430 FreeArgs(rdargs);
1432 else
1433 PrintFault(IoErr(), (STRPTR) argv[0]);
1435 return ret;