grub2: bring back build of aros-side grub2 tools
[AROS.git] / workbench / c / install-i386-pc.c
blob01eeadb7743f099b892eda58161921e0da6d4351
1 /*
2 Copyright © 1995-2009, The AROS Development Team. All rights reserved.
3 $Id$
4 */
5 /******************************************************************************
8 NAME
10 Install-i386-pc
12 SYNOPSIS
14 DEVICE/A, UNIT/N/K/A, PARTITIONNUMBER=PN/K/N, GRUB/K/A, FORCELBA/S
16 LOCATION
20 FUNCTION
22 Installs the GRUB bootloader to the bootblock of the specified disk.
24 INPUTS
26 DEVICE -- Device name (e.g. 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-i386-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 #include <string.h>
51 #include <proto/dos.h>
52 #include <proto/exec.h>
53 #include <proto/partition.h>
54 #include <aros/macros.h>
55 #include <devices/hardblocks.h>
56 #include <devices/newstyle.h>
57 #include <dos/dos.h>
58 #include <exec/errors.h>
59 #include <exec/memory.h>
60 #include <libraries/partition.h>
62 #define DEBUG 0
63 #include <aros/debug.h>
65 /* Defines for grub data */
66 /* Stage 1 pointers */
67 #define MBR_BPBEND 0x3e
68 #define GRUB_BOOT_DRIVE 0x40
69 #define GRUB_FORCE_LBA 0x41
70 #define GRUB_STAGE2_SECTOR 0x44
71 #define MBR_PARTSTART 0x1be
72 #define MBR_PARTEND 0x1fe
73 /* Stage 2 pointers */
75 /* BIOS drive flag */
76 #define BIOS_HDISK_FLAG 0x80
78 #define MBR_MAX_PARTITIONS 4
79 #define MBRT_EXTENDED 0x05
80 #define MBRT_EXTENDED2 0x0f
82 struct Volume {
83 struct MsgPort *mp;
84 struct IOExtTD *iotd;
85 ULONG readcmd;
86 ULONG writecmd;
87 ULONG startblock;
88 ULONG countblock;
89 CONST_STRPTR device;
90 ULONG unitnum;
91 UWORD SizeBlock;
92 UBYTE flags;
93 BYTE partnum;
94 ULONG *blockbuffer;
97 #define VF_IS_TRACKDISK (1<<0)
98 #define VF_IS_RDB (1<<1)
100 struct BlockNode {
101 ULONG sector;
102 UWORD count;
103 UWORD seg_adr;
106 const TEXT version[] = "$VER: Install-i386-pc 41.2 (4.6.2009)";
108 char *template =
109 "DEVICE/A,"
110 "UNIT/N/K/A,"
111 "PARTITIONNUMBER=PN/K/N," /* Partition whose boot block we should install stage1 in */
112 "GRUB/K/A,"
113 "FORCELBA/S";
114 IPTR myargs[7] = {0,0,0,0,0,0};
116 struct FileSysStartupMsg *getDiskFSSM(STRPTR path) {
117 struct DosList *dl;
118 struct DeviceNode *dn;
119 char dname[32];
120 UBYTE i;
122 D(bug("[install-i386] getDiskFSSM('%s')\n", path));
124 for (i=0;(path[i]) && (path[i]!=':');i++)
125 dname[i] = path[i];
126 if (path[i] == ':')
128 dname[i] = 0;
129 dl = LockDosList(LDF_READ);
130 if (dl)
132 dn = (struct DeviceNode *)FindDosEntry(dl, dname, LDF_DEVICES);
133 UnLockDosList(LDF_READ);
134 if (dn)
136 dname[i] = ':';
137 dname[i + 1] = '\0';
138 if (IsFileSystem(dname))
140 return (struct FileSysStartupMsg *)BADDR(dn->dn_Startup);
142 else
143 Printf("device '%s' doesn't contain a file system\n", dname);
145 else
146 PrintFault(ERROR_OBJECT_NOT_FOUND, dname);
149 else
150 Printf("'%s' doesn't contain a device name\n",path);
151 return 0;
154 void fillGeometry(struct Volume *volume, struct DosEnvec *de) {
155 ULONG spc;
157 D(bug("[install-i386] fillGeometry(%x)\n", volume));
159 spc = de->de_Surfaces*de->de_BlocksPerTrack;
160 volume->SizeBlock = de->de_SizeBlock;
161 volume->startblock = de->de_LowCyl*spc;
162 volume->countblock =((de->de_HighCyl-de->de_LowCyl+1)*spc)-1+de->de_Reserved;
165 void nsdCheck(struct Volume *volume) {
166 struct NSDeviceQueryResult nsdq;
167 UWORD *cmdcheck;
169 D(bug("[install-i386] nsdCheck(%x)\n", volume));
171 if (
173 (volume->startblock+volume->countblock)* /* last block */
174 ((volume->SizeBlock<<2)/512) /* 1 portion (block) equals 512 (bytes) */
175 )>8388608)
177 nsdq.SizeAvailable=0;
178 nsdq.DevQueryFormat=0;
179 volume->iotd->iotd_Req.io_Command=NSCMD_DEVICEQUERY;
180 volume->iotd->iotd_Req.io_Data=&nsdq;
181 volume->iotd->iotd_Req.io_Length=sizeof(struct NSDeviceQueryResult);
182 if (DoIO((struct IORequest *)&volume->iotd->iotd_Req)==IOERR_NOCMD)
184 Printf("Device doesn't understand NSD-Query\n");
186 else
188 if (
189 (volume->iotd->iotd_Req.io_Actual>sizeof(struct NSDeviceQueryResult)) ||
190 (volume->iotd->iotd_Req.io_Actual==0) ||
191 (volume->iotd->iotd_Req.io_Actual!=nsdq.SizeAvailable)
194 Printf("WARNING wrong io_Actual using NSD\n");
196 else
198 if (nsdq.DeviceType != NSDEVTYPE_TRACKDISK)
199 Printf("WARNING no trackdisk type\n");
200 for (cmdcheck=nsdq.SupportedCommands;*cmdcheck;cmdcheck++)
202 if (*cmdcheck == NSCMD_TD_READ64)
203 volume->readcmd = NSCMD_TD_READ64;
204 if (*cmdcheck == NSCMD_TD_WRITE64)
205 volume->writecmd = NSCMD_TD_WRITE64;
207 if (
208 (volume->readcmd!=NSCMD_TD_READ64) ||
209 (volume->writecmd!=NSCMD_TD_WRITE64)
211 Printf("WARNING no READ64/WRITE64\n");
218 struct Volume *initVolume(STRPTR device, ULONG unit, ULONG flags, struct DosEnvec *de) {
219 struct Volume *volume;
220 LONG error=0;
222 D(bug("[install-i386] initVolume(%s:%d)\n", device, unit));
224 volume = AllocVec(sizeof(struct Volume), MEMF_PUBLIC | MEMF_CLEAR);
225 if (volume)
227 volume->mp = CreateMsgPort();
228 if (volume->mp)
230 volume->iotd = (struct IOExtTD *)CreateIORequest(volume->mp, sizeof(struct IOExtTD));
231 if (volume->iotd)
233 volume->blockbuffer = AllocVec(de->de_SizeBlock<<2, MEMF_PUBLIC | MEMF_CLEAR);
234 if (volume->blockbuffer)
236 if (
237 OpenDevice
239 device,
240 unit,
241 (struct IORequest *)volume->iotd,
242 flags
243 ) == 0
246 if (strcmp(device, "trackdisk.device")==0)
247 volume->flags |= VF_IS_TRACKDISK;
248 else
249 volume->flags |= VF_IS_RDB; /* just assume we have RDB */
250 volume->readcmd = CMD_READ;
251 volume->writecmd = CMD_WRITE;
252 volume->device = device;
253 volume->unitnum = unit;
254 fillGeometry(volume, de);
255 nsdCheck(volume);
256 return volume;
258 else
259 error = ERROR_NO_FREE_STORE;
260 FreeVec(volume->blockbuffer);
262 else
263 error = ERROR_NO_FREE_STORE;
264 DeleteIORequest((struct IORequest *)volume->iotd);
266 else
267 error = ERROR_NO_FREE_STORE;
268 DeleteMsgPort(volume->mp);
270 else
271 error = ERROR_NO_FREE_STORE;
272 FreeVec(volume);
274 else
275 error = ERROR_NO_FREE_STORE;
276 PrintFault(error, NULL);
277 return 0;
280 void uninitVolume(struct Volume *volume)
283 D(bug("[install-i386] uninitVolume(%x)\n", volume));
285 CloseDevice((struct IORequest *)volume->iotd);
286 FreeVec(volume->blockbuffer);
287 DeleteIORequest((struct IORequest *)volume->iotd);
288 DeleteMsgPort(volume->mp);
289 FreeVec(volume);
292 ULONG readwriteBlock
294 struct Volume *volume,
295 ULONG block, APTR buffer, ULONG length,
296 ULONG command
299 UQUAD offset;
300 ULONG retval=0;
302 D(bug("[install-i386] readwriteBlock(vol:%x, block:%d, %d bytes)\n", volume, block, length));
304 volume->iotd->iotd_Req.io_Command = command;
305 volume->iotd->iotd_Req.io_Length = length;
306 volume->iotd->iotd_Req.io_Data = buffer;
307 offset = (UQUAD)(volume->startblock+block)*(volume->SizeBlock<<2);
308 volume->iotd->iotd_Req.io_Offset = offset & 0xFFFFFFFF;
309 volume->iotd->iotd_Req.io_Actual = offset>>32;
310 retval = DoIO((struct IORequest *)&volume->iotd->iotd_Req);
311 if (volume->flags & VF_IS_TRACKDISK)
313 volume->iotd->iotd_Req.io_Command = TD_MOTOR;
314 volume->iotd->iotd_Req.io_Length = 0;
315 DoIO((struct IORequest *)&volume->iotd->iotd_Req);
317 return retval;
320 BOOL isvalidFileSystem(struct Volume *volume, STRPTR device, ULONG unit) {
321 BOOL retval = FALSE;
322 struct PartitionBase *PartitionBase;
323 struct PartitionHandle *ph;
325 D(bug("[install-i386] isvalidFileSystem(%x, %s, %d)\n", volume, device, unit));
327 if (readwriteBlock(volume, 0, volume->blockbuffer, 512, volume->readcmd))
329 Printf("Read Error\n");
330 return FALSE;
332 if (
333 ((AROS_BE2LONG(volume->blockbuffer[0]) & 0xFFFFFF00)!=0x444F5300) ||
334 ((AROS_BE2LONG(volume->blockbuffer[0]) & 0xFF) == 0)
337 /* first block has no DOS\x so we don't have RDB for sure */
338 volume->flags &= ~VF_IS_RDB;
339 if (readwriteBlock(volume, 1, volume->blockbuffer, 512, volume->readcmd))
341 Printf("Read Error\n");
342 return FALSE;
344 if (
345 ((AROS_BE2LONG(volume->blockbuffer[0]) & 0xFFFFFF00)!=0x444F5300) ||
346 ((AROS_BE2LONG(volume->blockbuffer[0]) & 0xFF) == 0)
348 return FALSE;
350 volume->partnum = -1;
351 PartitionBase = (struct PartitionBase *)OpenLibrary("partition.library", 1);
352 if (PartitionBase)
354 ph = OpenRootPartition(device, unit);
355 if (ph)
357 if (OpenPartitionTable(ph) == 0)
359 struct TagItem tags[3];
360 IPTR type;
362 tags[1].ti_Tag = TAG_DONE;
363 tags[0].ti_Tag = PTT_TYPE;
364 tags[0].ti_Data = (STACKIPTR)&type;
365 GetPartitionTableAttrs(ph, tags);
366 if (type == PHPTT_MBR)
368 struct PartitionHandle *pn;
369 struct DosEnvec de;
370 struct PartitionHandle *extph = NULL;
371 struct PartitionType ptype = {{0}};
373 tags[0].ti_Tag = PT_DOSENVEC;
374 tags[0].ti_Data = (STACKIPTR)&de;
375 tags[1].ti_Tag = PT_TYPE;
376 tags[1].ti_Data = (STACKIPTR)&ptype;
377 tags[2].ti_Tag = TAG_DONE;
378 pn = (struct PartitionHandle *)ph->table->list.lh_Head;
379 while (pn->ln.ln_Succ)
381 ULONG scp;
383 GetPartitionAttrs(pn, tags);
384 if (ptype.id[0] == MBRT_EXTENDED || ptype.id[0] == MBRT_EXTENDED2)
385 extph = pn;
386 else
388 scp = de.de_Surfaces*de.de_BlocksPerTrack;
389 if (
390 (volume->startblock>=(de.de_LowCyl*scp)) &&
391 (volume->startblock<=(((de.de_HighCyl+1)*scp)-1))
393 break;
395 pn = (struct PartitionHandle *)pn->ln.ln_Succ;
397 if (pn->ln.ln_Succ)
399 tags[0].ti_Tag = PT_POSITION;
400 tags[0].ti_Data = (STACKIPTR)&type;
401 tags[1].ti_Tag = TAG_DONE;
402 GetPartitionAttrs(pn, tags);
403 volume->partnum = (UBYTE)type;
404 retval = TRUE;
405 D(bug("[install-i386] Primary partition found: partnum=%ld\n", volume->partnum));
407 else if (extph != NULL)
409 if (OpenPartitionTable(extph) == 0)
411 tags[0].ti_Tag = PTT_TYPE;
412 tags[0].ti_Data = (STACKIPTR)&type;
413 tags[1].ti_Tag = TAG_DONE;
414 GetPartitionTableAttrs(extph, tags);
415 if (type == PHPTT_EBR)
417 tags[0].ti_Tag = PT_DOSENVEC;
418 tags[0].ti_Data = (STACKIPTR)&de;
419 tags[1].ti_Tag = TAG_DONE;
420 pn = (struct PartitionHandle *)extph->table->list.lh_Head;
421 while (pn->ln.ln_Succ)
423 ULONG offset, scp;
425 offset = extph->de.de_LowCyl
426 * extph->de.de_Surfaces
427 * extph->de.de_BlocksPerTrack;
428 GetPartitionAttrs(pn, tags);
429 scp = de.de_Surfaces*de.de_BlocksPerTrack;
430 if (
431 (volume->startblock>=offset+(de.de_LowCyl*scp)) &&
432 (volume->startblock<=offset+(((de.de_HighCyl+1)*scp)-1))
434 break;
435 pn = (struct PartitionHandle *)pn->ln.ln_Succ;
437 if (pn->ln.ln_Succ)
439 tags[0].ti_Tag = PT_POSITION;
440 tags[0].ti_Data = (STACKIPTR)&type;
441 GetPartitionAttrs(pn, tags);
442 volume->partnum = MBR_MAX_PARTITIONS + (UBYTE)type;
443 retval = TRUE;
444 D(bug("[install-i386] Logical partition found: partnum=%ld\n", volume->partnum));
447 ClosePartitionTable(extph);
451 else
453 if (type == PHPTT_RDB)
455 /* just use whole hard disk */
456 retval = TRUE;
458 else
459 Printf("only MBR and RDB partition tables are supported\n");
461 ClosePartitionTable(ph);
463 else
465 /* just use whole hard disk */
466 retval = TRUE;
468 CloseRootPartition(ph);
470 else
471 Printf("Error OpenRootPartition(%s,%lu)\n", device, (long)unit);
472 CloseLibrary((struct Library *)PartitionBase);
474 else
475 Printf("Couldn't open partition.library\n");
476 return retval;
479 struct Volume *getGrubStageVolume
481 STRPTR device,
482 ULONG unit,
483 ULONG flags,
484 struct DosEnvec *de
487 struct Volume *volume;
489 volume = initVolume(device, unit, flags, de);
491 D(bug("[install-i386] getGrubStageVolume(): volume=%x\n", volume));
493 if (volume)
495 if (isvalidFileSystem(volume, device, unit))
496 return volume;
497 else
499 Printf("stage2 is on an unsupported file system\n");
500 PrintFault(ERROR_OBJECT_WRONG_TYPE, NULL);
502 uninitVolume(volume);
504 return 0;
507 BOOL isvalidPartition
509 STRPTR device,
510 ULONG unit,
511 LONG *pnum,
512 struct DosEnvec *de
515 struct PartitionBase *PartitionBase;
516 struct PartitionHandle *ph;
517 ULONG type;
518 BOOL retval=FALSE;
520 D(bug("[install-i386] isvalidPartition(%s:%d, part:%d)\n", device, unit, pnum));
522 PartitionBase = (struct PartitionBase *)OpenLibrary("partition.library", 1);
523 if (PartitionBase)
525 ph = OpenRootPartition(device, unit);
526 if (ph)
528 struct TagItem tags[2];
530 tags[1].ti_Tag = TAG_DONE;
531 /* is there a partition table? */
532 if (OpenPartitionTable(ph) == 0)
534 if (pnum)
536 /* install into partition bootblock */
537 tags[0].ti_Tag = PTT_TYPE;
538 tags[0].ti_Data = (STACKIPTR)&type;
539 GetPartitionTableAttrs(ph, tags);
540 if (type == PHPTT_MBR)
542 struct PartitionHandle *pn;
544 /* search for partition */
545 tags[0].ti_Tag = PT_POSITION;
546 tags[0].ti_Data = (STACKIPTR)&type;
547 pn = (struct PartitionHandle *)ph->table->list.lh_Head;
548 while (pn->ln.ln_Succ)
550 GetPartitionAttrs(pn, tags);
551 if (type == *pnum)
552 break;
553 pn = (struct PartitionHandle *)pn->ln.ln_Succ;
555 if (pn->ln.ln_Succ)
557 struct PartitionType ptype;
559 /* is it an AROS partition? */
560 tags[0].ti_Tag = PT_TYPE;
561 tags[0].ti_Data = (STACKIPTR)&ptype;
562 GetPartitionAttrs(pn, tags);
563 if (ptype.id[0] == 0x30)
565 tags[0].ti_Tag = PT_DOSENVEC;
566 tags[0].ti_Data = (STACKIPTR)de;
567 GetPartitionAttrs(pn, tags);
568 retval = TRUE;
570 else
571 Printf("partition is not of type AROS (0x30)\n");
573 else
575 Printf
577 "partition %ld not found on device %s unit %lu\n",
578 (long)*pnum, device, (long)unit
582 else
583 Printf("you can only install in partitions which are MBR partitioned\n");
585 else
587 /* install into MBR */
588 tags[0].ti_Tag = PTT_TYPE;
589 tags[0].ti_Data = (STACKIPTR)&type;
590 GetPartitionTableAttrs(ph, tags);
591 if ((type == PHPTT_MBR) || (type == PHPTT_RDB))
593 tags[0].ti_Tag = PT_DOSENVEC;
594 tags[0].ti_Data = (STACKIPTR)de;
595 GetPartitionAttrs(ph, tags);
596 retval = TRUE;
598 else
599 Printf("partition table type must be either MBR or RDB\n");
601 ClosePartitionTable(ph);
603 else
605 /* FIXME: GetPartitionAttr() should always work for root partition */
606 CopyMem(&ph->de, de, sizeof(struct DosEnvec));
607 retval = TRUE;
609 CloseRootPartition(ph);
611 else
612 Printf("Error OpenRootPartition(%s,%lu)\n", device, (long)unit);
613 CloseLibrary((struct Library *)PartitionBase);
615 else
616 Printf("Couldn't open partition.library\n");
617 return retval;
620 struct Volume *getBBVolume(STRPTR device, ULONG unit, LONG *partnum) {
621 struct Volume *volume;
622 struct DosEnvec de;
624 D(bug("[install-i386] getBBVolume(%s:%d, %d)\n", device, unit, partnum));
626 if (isvalidPartition(device, unit, partnum, &de))
628 volume = initVolume(device, unit, 0, &de);
629 volume->partnum = partnum ? *partnum : -1;
630 readwriteBlock(volume, 0, volume->blockbuffer, 512, volume->readcmd);
631 if (AROS_BE2LONG(volume->blockbuffer[0]) != IDNAME_RIGIDDISK)
633 memset(volume->blockbuffer,0x00, 446); /* Clear the boot sector region! */
634 return volume;
636 else
637 Printf("no space for bootblock (RDB is on block 0)\n");
639 return NULL;
642 ULONG collectBlockList
644 struct Volume *volume,
645 ULONG block,
646 struct BlockNode *blocklist
649 ULONG retval, first_block;
650 WORD blk_count,count;
651 UWORD i;
653 D(bug("[install-i386] collectBlockList(%x, %d, %x)\n", volume, block, blocklist));
655 /* TODO: logical/physical blocks */
657 initialze stage2-blocklist
658 (it is NULL-terminated)
660 // for (blk_count=-1;blocklist[blk_count].sector!=0;blk_count--)
661 // blocklist[blk_count].sector = 0;
663 memset((char *)&blocklist[-20],0x00, 20*sizeof(struct BlockNode)); /* Clear the stage2 sector pointers region! */
664 D(bug("[install-i386] collectBlockList: Cleared sector list (20 entries) [start: %x, end %x]\n", &blocklist[-20], &blocklist[-1]));
667 the first block of stage2 will be stored in stage1
668 so skip the first filekey in the first loop
670 /* FIXME: Block read twice */
671 retval=readwriteBlock
673 volume, block, volume->blockbuffer, volume->SizeBlock<<2,
674 volume->readcmd
676 if (retval)
678 D(bug("[install-i386] collectBlockList: ERROR reading block (error: %ld\n", retval));
679 Printf("ReadError %lu\n", (long)retval);
680 return 0;
683 i = volume->SizeBlock - 52;
684 first_block = AROS_BE2LONG(volume->blockbuffer[volume->SizeBlock-51]);
685 blk_count=0;
687 D(bug("[install-i386] collectBlockList: First block @ %x, i:%d\n", first_block, i));
692 retval=readwriteBlock
694 volume, block, volume->blockbuffer, volume->SizeBlock<<2,
695 volume->readcmd
697 if (retval)
699 D(bug("[install-i386] collectBlockList: ERROR reading block (error: %ld)\n", retval));
700 Printf("ReadError %lu\n", (long)retval);
701 return 0;
703 D(bug("[install-i386] collectBlockList: read block %lx, i = %d\n", block, i));
704 while ((i>=6) && (volume->blockbuffer[i]))
706 D(bug("[install-i386] collectBlockList: i = %d\n", i));
708 if current sector follows right after last sector
709 then we don't need a new element
711 if (
712 (blocklist[blk_count].sector) &&
713 ((blocklist[blk_count].sector+blocklist[blk_count].count)==
714 AROS_BE2LONG(volume->blockbuffer[i]))
717 blocklist[blk_count].count += 1;
718 D(bug("[install-i386] collectBlockList: sector %d follows previous - increasing count of block %d to %d\n", i, blk_count, blocklist[blk_count].count));
720 else
722 blk_count--; /* decrement first */
723 D(bug("[install-i386] collectBlockList: store new block (%d)\n", blk_count));
724 if (blocklist[blk_count-1].sector != 0)
726 D(bug("[install-i386] collectBlockList: ERROR: out of block space at sector %d, block %d\n", i, blk_count));
727 Printf("There is no more space to save blocklist in stage2\n");
728 return 0;
730 D(bug("[install-i386] collectBlockList: storing sector pointer for %d in block %d\n", i, blk_count));
731 blocklist[blk_count].sector = AROS_BE2LONG(volume->blockbuffer[i]);
732 blocklist[blk_count].count = 1;
734 i--;
736 i = volume->SizeBlock - 51;
737 block = AROS_BE2LONG(volume->blockbuffer[volume->SizeBlock - 2]);
738 D(bug("[install-i386] collectBlockList: next block %d, i = %d\n", block, i));
739 } while (block);
741 blocks in blocklist are relative to the first
742 sector of the HD (not partition)
744 D(bug("[install-i386] collectBlockList: successfully updated pointers for %d blocks\n", blk_count));
746 i = 0;
747 for (count=-1;count>=blk_count;count--)
749 blocklist[count].sector += volume->startblock;
750 blocklist[count].seg_adr = 0x820 + (i*32);
751 i += blocklist[count].count;
752 D(bug("[install-i386] collectBlockList: correcting block %d for partition start\n", count));
753 D(bug("[install-i386] collectBlockList: sector : %x seg_adr : %x\n", blocklist[count].sector, blocklist[count].seg_adr));
755 return first_block;
758 void copyRootPath(char *dst, char *rpdos, BOOL isRDB) {
760 D(bug("[install-i386] copyRootPath()\n"));
762 if (isRDB)
764 /* we have an RDB so use devicename */
765 *dst++ = '/';
766 while ((*rpdos) && (*rpdos!=':'))
767 *dst++ = *rpdos++;
769 else
771 while ((*rpdos) && (*rpdos!=':'))
772 rpdos++;
774 rpdos++; /* skip colon */
775 *dst++ = '/';
776 /* append path */
777 while (*rpdos)
778 *dst++ = *rpdos++;
779 if (dst[-1] == '/')
780 dst[-1] = 0;
781 else
782 *dst = 0;
785 /* Convert a unit number into a drive number as understood by GRUB */
786 UWORD getDriveNumber(CONST_STRPTR device, ULONG unit)
788 struct PartitionHandle *ph;
789 ULONG i;
790 UWORD hd_count = 0;
792 for (i = 0; i < unit; i++)
794 ph = OpenRootPartition(device, i);
795 if (ph != NULL)
797 hd_count++;
798 CloseRootPartition(ph);
802 return hd_count;
805 UBYTE *memstr(UBYTE *mem, UBYTE *str, LONG len) {
806 UBYTE *next;
807 UBYTE *search;
808 LONG left;
810 while (len)
812 len--;
813 if (*mem++ == *str)
815 next = mem;
816 search = str+1;
817 left = len;
818 while ((*search) && (left) && (*next++ == *search++))
819 left--;
820 if (*search == 0)
821 return mem-1;
824 return 0;
827 BOOL writeStage2
829 BPTR fh,
830 UBYTE *buffer,
831 STRPTR grubpath,
832 struct Volume *volume
835 BOOL retval = FALSE;
836 char *menuname;
838 D(bug("[install-i386] writeStage2(%x)\n", volume));
840 if (Seek(fh, 0, OFFSET_BEGINNING) != -1)
842 /* write back first block */
843 if (Write(fh, buffer, 512)==512)
845 /* read second stage2 block */
846 if (Read(fh, buffer, 512) == 512)
848 /* set partition number where stage2 is on */
849 buffer[8] = 0xFF;
850 buffer[9] = 0xFF;
851 buffer[10] = volume->partnum;
852 buffer[11] = 0;
853 /* get ptr to version string */
854 menuname = buffer+18;
855 while (*menuname++); /* skip version string */
856 copyRootPath(menuname, grubpath, volume->flags & VF_IS_RDB);
857 strcat(menuname, "/menu.lst");
858 /* write second stage2 block back */
859 if (Seek(fh, -512, OFFSET_CURRENT) != -1)
861 if (Write(fh, buffer, 512) == 512)
863 retval = TRUE;
865 else
866 Printf("%s: Write Error\n", menuname);
868 else
869 Printf("%s: Seek Error\n", menuname);
871 else
872 Printf("Read Error\n");
874 else
875 Printf("Write Error\n");
877 else
878 PrintFault(IoErr(), NULL);
879 return retval;
882 ULONG changeStage2
884 STRPTR grubpath, /* path of grub dir */
885 struct Volume *volume, /* volume stage2 is on */
886 ULONG *buffer /* a buffer of at least 512 bytes */
889 ULONG block = 0;
890 struct FileInfoBlock fib;
891 BPTR fh;
892 char stage2path[256];
894 D(bug("[install-i386] changeStage2(%x)\n", volume));
896 AddPart(stage2path, grubpath, 256);
897 AddPart(stage2path, "stage2", 256);
898 fh = Open(stage2path, MODE_OLDFILE);
899 if (fh)
901 if (ExamineFH(fh, &fib))
903 if (Read(fh, buffer, 512) == 512)
906 get and store all blocks of stage2 in first block of stage2
907 first block of stage2 will be returned
909 block = collectBlockList
910 (volume, fib.fib_DiskKey, (struct BlockNode *)&buffer[128]);
912 if (block)
914 if (!writeStage2(fh, (UBYTE *)buffer, grubpath, volume))
915 block = 0;
918 else
919 Printf("%s: Read Error\n", stage2path);
921 else
922 PrintFault(IoErr(), stage2path);
923 Close(fh);
925 else
926 PrintFault(IoErr(), stage2path);
927 return block;
930 BOOL writeStage1
932 STRPTR stage1path,
933 struct Volume *volume,
934 struct Volume *s2vol,
935 ULONG block, /* first block of stage2 file */
936 ULONG unit
939 BOOL retval = FALSE;
940 LONG error = 0;
941 BPTR fh;
943 D(bug("[install-i386] writeStage1(%x)\n", volume));
945 fh = Open(stage1path, MODE_OLDFILE);
946 if (fh)
948 if (Read(fh, volume->blockbuffer, 512) == 512)
950 /* install into MBR ? */
951 if ((volume->startblock == 0) && (!(volume->flags & VF_IS_TRACKDISK)))
953 D(bug("[install-i386] writeStage1: Install to HARDDISK\n"));
954 // read old MBR
955 error = readwriteBlock
956 (volume, 0, s2vol->blockbuffer, 512, volume->readcmd);
958 D(bug("[install-i386] writeStage1: MBR Buffer @ %x\n", volume->blockbuffer));
959 D(bug("[install-i386] writeStage1: Copying MBR BPB to %x\n", (char *)volume->blockbuffer + 0x04));
960 // copy BPB (BIOS Parameter Block)
961 CopyMem
963 (APTR)((char *)s2vol->blockbuffer + 0x04),
964 (APTR)((char *)volume->blockbuffer + 0x04),
965 (MBR_BPBEND - 4)
967 // copy partition table - [Overwrites Floppy boot code]
968 D(bug("[install-i386] writeStage1: Copying MBR Partitions to %x\n", (char *)volume->blockbuffer + MBR_PARTSTART));
969 CopyMem
971 (APTR)((char *)s2vol->blockbuffer + MBR_PARTSTART),
972 (APTR)((char *)volume->blockbuffer + MBR_PARTSTART),
973 (MBR_PARTEND - MBR_PARTSTART)
975 // store the drive num stage2 is stored on
976 ((char *)volume->blockbuffer)[GRUB_BOOT_DRIVE] =
977 getDriveNumber(volume->device, unit) | BIOS_HDISK_FLAG;
978 // Store the stage 2 pointer ..
979 ULONG * stage2_sector_start = (ULONG *)((char *)volume->blockbuffer + GRUB_STAGE2_SECTOR);
980 D(bug("[install-i386] writeStage1: writing stage2 pointer @ %x\n", stage2_sector_start));
981 stage2_sector_start[0] = block;
982 D(bug("[install-i386] writeStage1: stage2 pointer = %x\n", stage2_sector_start[0]));
983 stage2_sector_start[0] += s2vol->startblock;
984 D(bug("[install-i386] writeStage1: + offset [%d] = %x\n", s2vol->startblock, stage2_sector_start[0]));
986 if (myargs[4]!=0)
988 D(bug("[install-i386] writeStage1: Forcing LBA\n"));
989 ((char *)volume->blockbuffer)[GRUB_FORCE_LBA] = 1;
991 else
993 D(bug("[install-i386] writeStage1: NOT Forcing LBA\n"));
994 ((char *)volume->blockbuffer)[GRUB_FORCE_LBA] = 0;
997 else
999 D(bug("[install-i386] writeStage1: Install to FLOPPY\n"));
1002 if (error == 0)
1004 error = readwriteBlock
1005 (volume, 0, volume->blockbuffer, 512, volume->writecmd);
1006 if (error)
1007 Printf("WriteError %lu\n", (long)error);
1008 else
1009 retval = TRUE;
1011 else
1012 Printf("WriteError %lu\n", (long)error);
1014 else
1015 Printf("%s: Read Error\n", stage1path);
1016 Close(fh);
1018 else
1019 PrintFault(IoErr(), stage1path);
1020 return retval;
1023 /* Flushes the cache on the volume containing the specified path. */
1024 VOID flushFS(CONST TEXT *path)
1026 char devname[256];
1027 UWORD i;
1029 for (i = 0; path[i] != ':'; i++)
1030 devname[i] = path[i];
1031 devname[i++] = ':';
1032 devname[i] = '\0';
1033 if (Inhibit(devname, DOSTRUE))
1034 Inhibit(devname, DOSFALSE);
1037 BOOL installStageFiles
1039 struct Volume *s2vol, /* stage2 volume */
1040 STRPTR stagepath, /* path to stage* files */
1041 ULONG unit, /* unit stage2 is on */
1042 struct Volume *s1vol /* device on which stage1 will be stored */
1045 BOOL retval = FALSE;
1046 char stagename[256];
1047 ULONG block;
1049 D(bug("[install-i386] installStageFiles(%x)\n", s1vol));
1051 /* Flush GRUB volume's cache */
1052 flushFS(stagepath);
1054 block = changeStage2(stagepath, s2vol, s1vol->blockbuffer);
1055 if (block)
1057 AddPart(stagename, stagepath, 256);
1058 AddPart(stagename, "stage1", 256);
1059 if (writeStage1(stagename, s1vol, s2vol, block, unit))
1060 retval = TRUE;
1062 return retval;
1065 int main(int argc, char **argv) {
1067 struct RDArgs *rdargs;
1068 struct Volume *grubvol;
1069 struct Volume *bbvol;
1070 struct FileSysStartupMsg *fssm;
1072 D(bug("[install-i386] main()\n"));
1074 rdargs = ReadArgs(template, myargs, NULL);
1075 if (rdargs)
1077 D(bug("[install-i386] FORCELBA = %d\n",myargs[4]));
1079 fssm = getDiskFSSM((STRPTR)myargs[3]);
1080 if (fssm != NULL)
1082 if (
1083 (strcmp(AROS_BSTR_ADDR(fssm->fssm_Device),(char*)myargs[0])==0)
1086 grubvol = getGrubStageVolume
1088 AROS_BSTR_ADDR(fssm->fssm_Device),
1089 fssm->fssm_Unit,
1090 fssm->fssm_Flags,
1091 (struct DosEnvec *)BADDR(fssm->fssm_Environ)
1093 if (grubvol)
1095 bbvol=getBBVolume
1097 (STRPTR)myargs[0],
1098 *((LONG *)myargs[1]),
1099 (LONG *)myargs[2]
1101 if (bbvol)
1103 ULONG retval=0;
1105 getBBVolume() read block 0
1106 if the partition directly contains a filesystem
1107 (currently only DOS\x is supported) we have
1108 to move block 0 to block 1 to make space for stage1
1110 if (
1111 (grubvol->startblock == bbvol->startblock) &&
1112 ((AROS_BE2LONG(bbvol->blockbuffer[0]) & 0xFFFFFF00)==0x444F5300)
1115 grubvol->flags &= ~VF_IS_RDB;
1116 retval = readwriteBlock
1117 (bbvol, 0, bbvol->blockbuffer, 512, bbvol->readcmd);
1119 if (retval == 0)
1121 installStageFiles
1123 grubvol,
1124 (STRPTR)myargs[3], /* grub path (stage1/2) */
1125 fssm->fssm_Unit,
1126 bbvol
1129 else
1130 Printf("Read Error: %lu\n", (long)retval);
1131 uninitVolume(bbvol);
1133 uninitVolume(grubvol);
1136 else
1138 Printf
1140 "%s is not on device %s unit %lu\n",
1141 (STRPTR)myargs[3], (STRPTR)myargs[0], (long)*((ULONG *)myargs[1])
1145 else
1146 if (fssm)
1147 Printf("kernel path must begin with a device name\n");
1148 FreeArgs(rdargs);
1150 else
1151 PrintFault(IoErr(), argv[0]);
1152 return 0;