Task's tc_TrapCode is now called when a processor exception occurs.
[cake.git] / workbench / c / install-i386-pc.c
blob71fa29c050db330ccde7b2ea465634fa62e2843b
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
18 SYS:C
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 <stdio.h>
51 #include <string.h>
52 #include <proto/dos.h>
53 #include <proto/exec.h>
54 #include <proto/partition.h>
55 #include <aros/macros.h>
56 #include <devices/hardblocks.h>
57 #include <devices/newstyle.h>
58 #include <dos/dos.h>
59 #include <exec/errors.h>
60 #include <exec/memory.h>
61 #include <libraries/partition.h>
63 #define DEBUG 0
64 #include <aros/debug.h>
66 /* Defines for grub data */
67 /* Stage 1 pointers */
68 #define MBR_BPBEND 0x3e
69 #define GRUB_BOOT_DRIVE 0x40
70 #define GRUB_FORCE_LBA 0x41
71 #define GRUB_STAGE2_SECTOR 0x44
72 #define MBR_PARTSTART 0x1be
73 #define MBR_PARTEND 0x1fe
74 /* Stage 2 pointers */
76 /* BIOS drive flag */
77 #define BIOS_HDISK_FLAG 0x80
79 #define MBR_MAX_PARTITIONS 4
80 #define MBRT_EXTENDED 0x05
81 #define MBRT_EXTENDED2 0x0f
83 struct Volume {
84 struct MsgPort *mp;
85 struct IOExtTD *iotd;
86 ULONG readcmd;
87 ULONG writecmd;
88 ULONG startblock;
89 ULONG countblock;
90 CONST_STRPTR device;
91 ULONG unitnum;
92 UWORD SizeBlock;
93 UBYTE flags;
94 BYTE partnum;
95 ULONG *blockbuffer;
98 #define VF_IS_TRACKDISK (1<<0)
99 #define VF_IS_RDB (1<<1)
101 struct BlockNode {
102 ULONG sector;
103 UWORD count;
104 UWORD seg_adr;
107 const TEXT version[] = "$VER: Install-i386-pc 41.2 (4.6.2009)";
109 char *template =
110 "DEVICE/A,"
111 "UNIT/N/K/A,"
112 "PARTITIONNUMBER=PN/K/N," /* Partition whose boot block we should install stage1 in */
113 "GRUB/K/A,"
114 "FORCELBA/S";
115 IPTR myargs[7] = {0,0,0,0,0,0};
117 struct FileSysStartupMsg *getDiskFSSM(STRPTR path) {
118 struct DosList *dl;
119 struct DeviceNode *dn;
120 char dname[32];
121 UBYTE i;
123 D(bug("[install-i386] getDiskFSSM('%s')\n", path));
125 for (i=0;(path[i]) && (path[i]!=':');i++)
126 dname[i] = path[i];
127 if (path[i] == ':')
129 dname[i] = 0;
130 dl = LockDosList(LDF_READ);
131 if (dl)
133 dn = (struct DeviceNode *)FindDosEntry(dl, dname, LDF_DEVICES);
134 UnLockDosList(LDF_READ);
135 if (dn)
137 if (IsFileSystem(dname))
139 return (struct FileSysStartupMsg *)BADDR(dn->dn_Startup);
141 else
142 printf("device '%s' doesn't contain a file system\n", dname);
144 else
145 PrintFault(ERROR_OBJECT_NOT_FOUND, dname);
148 else
149 printf("'%s' doesn't contain a device name\n",path);
150 return 0;
153 void fillGeometry(struct Volume *volume, struct DosEnvec *de) {
154 ULONG spc;
156 D(bug("[install-i386] fillGeometry(%x)\n", volume));
158 spc = de->de_Surfaces*de->de_BlocksPerTrack;
159 volume->SizeBlock = de->de_SizeBlock;
160 volume->startblock = de->de_LowCyl*spc;
161 volume->countblock =((de->de_HighCyl-de->de_LowCyl+1)*spc)-1+de->de_Reserved;
164 void nsdCheck(struct Volume *volume) {
165 struct NSDeviceQueryResult nsdq;
166 UWORD *cmdcheck;
168 D(bug("[install-i386] nsdCheck(%x)\n", volume));
170 if (
172 (volume->startblock+volume->countblock)* /* last block */
173 ((volume->SizeBlock<<2)/512) /* 1 portion (block) equals 512 (bytes) */
174 )>8388608)
176 nsdq.SizeAvailable=0;
177 nsdq.DevQueryFormat=0;
178 volume->iotd->iotd_Req.io_Command=NSCMD_DEVICEQUERY;
179 volume->iotd->iotd_Req.io_Data=&nsdq;
180 volume->iotd->iotd_Req.io_Length=sizeof(struct NSDeviceQueryResult);
181 if (DoIO((struct IORequest *)&volume->iotd->iotd_Req)==IOERR_NOCMD)
183 printf("Device doesn't understand NSD-Query\n");
185 else
187 if (
188 (volume->iotd->iotd_Req.io_Actual>sizeof(struct NSDeviceQueryResult)) ||
189 (volume->iotd->iotd_Req.io_Actual==0) ||
190 (volume->iotd->iotd_Req.io_Actual!=nsdq.SizeAvailable)
193 printf("WARNING wrong io_Actual using NSD\n");
195 else
197 if (nsdq.DeviceType != NSDEVTYPE_TRACKDISK)
198 printf("WARNING no trackdisk type\n");
199 for (cmdcheck=nsdq.SupportedCommands;*cmdcheck;cmdcheck++)
201 if (*cmdcheck == NSCMD_TD_READ64)
202 volume->readcmd = NSCMD_TD_READ64;
203 if (*cmdcheck == NSCMD_TD_WRITE64);
204 volume->writecmd = NSCMD_TD_WRITE64;
206 if (
207 (volume->readcmd!=NSCMD_TD_READ64) ||
208 (volume->writecmd!=NSCMD_TD_WRITE64)
210 printf("WARNING no READ64/WRITE64\n");
217 struct Volume *initVolume(STRPTR device, ULONG unit, ULONG flags, struct DosEnvec *de) {
218 struct Volume *volume;
219 LONG error=0;
221 D(bug("[install-i386] initVolume(%s:%d)\n", device, unit));
223 volume = AllocVec(sizeof(struct Volume), MEMF_PUBLIC | MEMF_CLEAR);
224 if (volume)
226 volume->mp = CreateMsgPort();
227 if (volume->mp)
229 volume->iotd = (struct IOExtTD *)CreateIORequest(volume->mp, sizeof(struct IOExtTD));
230 if (volume->iotd)
232 volume->blockbuffer = AllocVec(de->de_SizeBlock<<2, MEMF_PUBLIC | MEMF_CLEAR);
233 if (volume->blockbuffer)
235 if (
236 OpenDevice
238 device,
239 unit,
240 (struct IORequest *)volume->iotd,
241 flags
242 ) == 0
245 if (strcmp(device, "trackdisk.device")==0)
246 volume->flags |= VF_IS_TRACKDISK;
247 else
248 volume->flags |= VF_IS_RDB; /* just assume we have RDB */
249 volume->readcmd = CMD_READ;
250 volume->writecmd = CMD_WRITE;
251 volume->device = device;
252 volume->unitnum = unit;
253 fillGeometry(volume, de);
254 nsdCheck(volume);
255 return volume;
257 else
258 error = ERROR_NO_FREE_STORE;
259 FreeVec(volume->blockbuffer);
261 else
262 error = ERROR_NO_FREE_STORE;
263 DeleteIORequest((struct IORequest *)volume->iotd);
265 else
266 error = ERROR_NO_FREE_STORE;
267 DeleteMsgPort(volume->mp);
269 else
270 error = ERROR_NO_FREE_STORE;
271 FreeVec(volume);
273 else
274 error = ERROR_NO_FREE_STORE;
275 PrintFault(error, NULL);
276 return 0;
279 void uninitVolume(struct Volume *volume)
282 D(bug("[install-i386] uninitVolume(%x)\n", volume));
284 CloseDevice((struct IORequest *)volume->iotd);
285 FreeVec(volume->blockbuffer);
286 DeleteIORequest((struct IORequest *)volume->iotd);
287 DeleteMsgPort(volume->mp);
288 FreeVec(volume);
291 ULONG readwriteBlock
293 struct Volume *volume,
294 ULONG block, APTR buffer, ULONG length,
295 ULONG command
298 UQUAD offset;
299 ULONG retval=0;
301 D(bug("[install-i386] readwriteBlock(vol:%x, block:%d, %d bytes)\n", volume, block, length));
303 volume->iotd->iotd_Req.io_Command = command;
304 volume->iotd->iotd_Req.io_Length = length;
305 volume->iotd->iotd_Req.io_Data = buffer;
306 offset = (UQUAD)(volume->startblock+block)*(volume->SizeBlock<<2);
307 volume->iotd->iotd_Req.io_Offset = offset & 0xFFFFFFFF;
308 volume->iotd->iotd_Req.io_Actual = offset>>32;
309 retval = DoIO((struct IORequest *)&volume->iotd->iotd_Req);
310 if (volume->flags & VF_IS_TRACKDISK)
312 volume->iotd->iotd_Req.io_Command = TD_MOTOR;
313 volume->iotd->iotd_Req.io_Length = 0;
314 DoIO((struct IORequest *)&volume->iotd->iotd_Req);
316 return retval;
319 BOOL isvalidFileSystem(struct Volume *volume, STRPTR device, ULONG unit) {
320 BOOL retval = FALSE;
321 struct PartitionBase *PartitionBase;
322 struct PartitionHandle *ph;
324 D(bug("[install-i386] isvalidFileSystem(%x, %s, %d)\n", volume, device, unit));
326 if (readwriteBlock(volume, 0, volume->blockbuffer, 512, volume->readcmd))
328 printf("Read Error\n");
329 return FALSE;
331 if (
332 ((AROS_BE2LONG(volume->blockbuffer[0]) & 0xFFFFFF00)!=0x444F5300) ||
333 ((AROS_BE2LONG(volume->blockbuffer[0]) & 0xFF) == 0)
336 /* first block has no DOS\x so we don't have RDB for sure */
337 volume->flags &= ~VF_IS_RDB;
338 if (readwriteBlock(volume, 1, volume->blockbuffer, 512, volume->readcmd))
340 printf("Read Error\n");
341 return FALSE;
343 if (
344 ((AROS_BE2LONG(volume->blockbuffer[0]) & 0xFFFFFF00)!=0x444F5300) ||
345 ((AROS_BE2LONG(volume->blockbuffer[0]) & 0xFF) == 0)
347 return FALSE;
349 volume->partnum = -1;
350 PartitionBase = (struct PartitionBase *)OpenLibrary("partition.library", 1);
351 if (PartitionBase)
353 ph = OpenRootPartition(device, unit);
354 if (ph)
356 if (OpenPartitionTable(ph) == 0)
358 struct TagItem tags[3];
359 IPTR type;
361 tags[1].ti_Tag = TAG_DONE;
362 tags[0].ti_Tag = PTT_TYPE;
363 tags[0].ti_Data = (STACKIPTR)&type;
364 GetPartitionTableAttrs(ph, tags);
365 if (type == PHPTT_MBR)
367 struct PartitionHandle *pn;
368 struct DosEnvec de;
369 struct PartitionHandle *extph = NULL;
370 struct PartitionType ptype = {{0}};
372 tags[0].ti_Tag = PT_DOSENVEC;
373 tags[0].ti_Data = (STACKIPTR)&de;
374 tags[1].ti_Tag = PT_TYPE;
375 tags[1].ti_Data = (STACKIPTR)&ptype;
376 tags[2].ti_Tag = TAG_DONE;
377 pn = (struct PartitionHandle *)ph->table->list.lh_Head;
378 while (pn->ln.ln_Succ)
380 ULONG scp;
382 GetPartitionAttrs(pn, tags);
383 if (ptype.id[0] == MBRT_EXTENDED || ptype.id[0] == MBRT_EXTENDED2)
384 extph = pn;
385 else
387 scp = de.de_Surfaces*de.de_BlocksPerTrack;
388 if (
389 (volume->startblock>=(de.de_LowCyl*scp)) &&
390 (volume->startblock<=(((de.de_HighCyl+1)*scp)-1))
392 break;
394 pn = (struct PartitionHandle *)pn->ln.ln_Succ;
396 if (pn->ln.ln_Succ)
398 tags[0].ti_Tag = PT_POSITION;
399 tags[0].ti_Data = (STACKIPTR)&type;
400 tags[1].ti_Tag = TAG_DONE;
401 GetPartitionAttrs(pn, tags);
402 volume->partnum = (UBYTE)type;
403 retval = TRUE;
404 D(bug("[install-i386] Primary partition found: partnum=%ld\n", volume->partnum));
406 else if (extph != NULL)
408 if (OpenPartitionTable(extph) == 0)
410 tags[0].ti_Tag = PTT_TYPE;
411 tags[0].ti_Data = (STACKIPTR)&type;
412 tags[1].ti_Tag = TAG_DONE;
413 GetPartitionTableAttrs(extph, tags);
414 if (type == PHPTT_EBR)
416 tags[0].ti_Tag = PT_DOSENVEC;
417 tags[0].ti_Data = (STACKIPTR)&de;
418 tags[1].ti_Tag = TAG_DONE;
419 pn = (struct PartitionHandle *)extph->table->list.lh_Head;
420 while (pn->ln.ln_Succ)
422 ULONG offset, scp;
424 offset = extph->de.de_LowCyl
425 * extph->de.de_Surfaces
426 * extph->de.de_BlocksPerTrack;
427 GetPartitionAttrs(pn, tags);
428 scp = de.de_Surfaces*de.de_BlocksPerTrack;
429 if (
430 (volume->startblock>=offset+(de.de_LowCyl*scp)) &&
431 (volume->startblock<=offset+(((de.de_HighCyl+1)*scp)-1))
433 break;
434 pn = (struct PartitionHandle *)pn->ln.ln_Succ;
436 if (pn->ln.ln_Succ)
438 tags[0].ti_Tag = PT_POSITION;
439 tags[0].ti_Data = (STACKIPTR)&type;
440 GetPartitionAttrs(pn, tags);
441 volume->partnum = MBR_MAX_PARTITIONS + (UBYTE)type;
442 retval = TRUE;
443 D(bug("[install-i386] Logical partition found: partnum=%ld\n", volume->partnum));
446 ClosePartitionTable(extph);
450 else
452 if (type == PHPTT_RDB)
454 /* just use whole hard disk */
455 retval = TRUE;
457 else
458 printf("only MBR and RDB partition tables are supported\n");
460 ClosePartitionTable(ph);
462 else
464 /* just use whole hard disk */
465 retval = TRUE;
467 CloseRootPartition(ph);
469 else
470 printf("Error OpenRootPartition(%s,%ld)\n", device, unit);
471 CloseLibrary((struct Library *)PartitionBase);
473 else
474 printf("Couldn't open partition.library\n");
475 return retval;
478 struct Volume *getGrubStageVolume
480 STRPTR device,
481 ULONG unit,
482 ULONG flags,
483 struct DosEnvec *de
486 struct Volume *volume;
488 volume = initVolume(device, unit, flags, de);
490 D(bug("[install-i386] getGrubStageVolume(): volume=%x\n", volume));
492 if (volume)
494 if (isvalidFileSystem(volume, device, unit))
495 return volume;
496 else
498 printf("stage2 is on an unsupported file system\n");
499 PrintFault(ERROR_OBJECT_WRONG_TYPE, NULL);
501 uninitVolume(volume);
503 return 0;
506 BOOL isvalidPartition
508 STRPTR device,
509 ULONG unit,
510 LONG *pnum,
511 struct DosEnvec *de
514 struct PartitionBase *PartitionBase;
515 struct PartitionHandle *ph;
516 ULONG type;
517 BOOL retval=FALSE;
519 D(bug("[install-i386] isvalidPartition(%s:%d, part:%d)\n", device, unit, pnum));
521 PartitionBase = (struct PartitionBase *)OpenLibrary("partition.library", 1);
522 if (PartitionBase)
524 ph = OpenRootPartition(device, unit);
525 if (ph)
527 struct TagItem tags[2];
529 tags[1].ti_Tag = TAG_DONE;
530 /* is there a partition table? */
531 if (OpenPartitionTable(ph) == 0)
533 if (pnum)
535 /* install into partition bootblock */
536 tags[0].ti_Tag = PTT_TYPE;
537 tags[0].ti_Data = (STACKIPTR)&type;
538 GetPartitionTableAttrs(ph, tags);
539 if (type == PHPTT_MBR)
541 struct PartitionHandle *pn;
543 /* search for partition */
544 tags[0].ti_Tag = PT_POSITION;
545 tags[0].ti_Data = (STACKIPTR)&type;
546 pn = (struct PartitionHandle *)ph->table->list.lh_Head;
547 while (pn->ln.ln_Succ)
549 GetPartitionAttrs(pn, tags);
550 if (type == *pnum)
551 break;
552 pn = (struct PartitionHandle *)pn->ln.ln_Succ;
554 if (pn->ln.ln_Succ)
556 struct PartitionType ptype;
558 /* is it an AROS partition? */
559 tags[0].ti_Tag = PT_TYPE;
560 tags[0].ti_Data = (STACKIPTR)&ptype;
561 GetPartitionAttrs(pn, tags);
562 if (ptype.id[0] == 0x30)
564 tags[0].ti_Tag = PT_DOSENVEC;
565 tags[0].ti_Data = (STACKIPTR)de;
566 GetPartitionAttrs(pn, tags);
567 retval = TRUE;
569 else
570 printf("partition is not of type AROS (0x30)\n");
572 else
574 printf
576 "partition %ld not found on device %s unit %ld\n",
577 *pnum, device, unit
581 else
582 printf("you can only install in partitions which are MBR partitioned\n");
584 else
586 /* install into MBR */
587 tags[0].ti_Tag = PTT_TYPE;
588 tags[0].ti_Data = (STACKIPTR)&type;
589 GetPartitionTableAttrs(ph, tags);
590 if ((type == PHPTT_MBR) || (type == PHPTT_RDB))
592 tags[0].ti_Tag = PT_DOSENVEC;
593 tags[0].ti_Data = (STACKIPTR)de;
594 GetPartitionAttrs(ph, tags);
595 retval = TRUE;
597 else
598 printf("partition table type must be either MBR or RDB\n");
600 ClosePartitionTable(ph);
602 else
604 #warning "FIXME: GetPartitionAttr() should always work for root partition"
605 CopyMem(&ph->de, de, sizeof(struct DosEnvec));
606 retval = TRUE;
608 CloseRootPartition(ph);
610 else
611 printf("Error OpenRootPartition(%s,%ld)\n", device, unit);
612 CloseLibrary((struct Library *)PartitionBase);
614 else
615 printf("Couldn't open partition.library\n");
616 return retval;
619 struct Volume *getBBVolume(STRPTR device, ULONG unit, LONG *partnum) {
620 struct Volume *volume;
621 struct DosEnvec de;
623 D(bug("[install-i386] getBBVolume(%s:%d, %d)\n", device, unit, partnum));
625 if (isvalidPartition(device, unit, partnum, &de))
627 volume = initVolume(device, unit, 0, &de);
628 volume->partnum = partnum ? *partnum : -1;
629 readwriteBlock(volume, 0, volume->blockbuffer, 512, volume->readcmd);
630 if (AROS_BE2LONG(volume->blockbuffer[0]) != IDNAME_RIGIDDISK)
632 memset(volume->blockbuffer,0x00, 446); /* Clear the boot sector region! */
633 return volume;
635 else
636 printf("no space for bootblock (RDB is on block 0)\n");
638 return NULL;
641 ULONG collectBlockList
643 struct Volume *volume,
644 ULONG block,
645 struct BlockNode *blocklist
648 ULONG retval, first_block;
649 WORD blk_count,count;
650 UWORD i;
652 D(bug("[install-i386] collectBlockList(%x, %d, %x)\n", volume, block, blocklist));
654 #warning "TODO: logical/physical blocks"
656 initialze stage2-blocklist
657 (it is NULL-terminated)
659 // for (blk_count=-1;blocklist[blk_count].sector!=0;blk_count--)
660 // blocklist[blk_count].sector = 0;
662 memset((char *)&blocklist[-20],0x00, 20*sizeof(struct BlockNode)); /* Clear the stage2 sector pointers region! */
663 D(bug("[install-i386] collectBlockList: Cleared sector list (20 entries) [start: %x, end %x]\n", &blocklist[-20], &blocklist[-1]));
666 the first block of stage2 will be stored in stage1
667 so skip the first filekey in the first loop
669 #warning "Block read twice"
670 retval=readwriteBlock
672 volume, block, volume->blockbuffer, volume->SizeBlock<<2,
673 volume->readcmd
675 if (retval)
677 D(bug("[install-i386] collectBlockList: ERROR reading block (error: %ld\n", retval));
678 printf("ReadError %ld\n", retval);
679 return 0;
682 i = volume->SizeBlock - 52;
683 first_block = AROS_BE2LONG(volume->blockbuffer[volume->SizeBlock-51]);
684 blk_count=0;
686 D(bug("[install-i386] collectBlockList: First block @ %x, i:%d\n", first_block, i));
691 retval=readwriteBlock
693 volume, block, volume->blockbuffer, volume->SizeBlock<<2,
694 volume->readcmd
696 if (retval)
698 D(bug("[install-i386] collectBlockList: ERROR reading block (error: %ld)\n", retval));
699 printf("ReadError %ld\n", retval);
700 return 0;
702 D(bug("[install-i386] collectBlockList: read block %lx, i = %d\n", block, i));
703 while ((i>=6) && (volume->blockbuffer[i]))
705 D(bug("[install-i386] collectBlockList: i = %d\n", i));
707 if current sector follows right after last sector
708 then we don't need a new element
710 if (
711 (blocklist[blk_count].sector) &&
712 ((blocklist[blk_count].sector+blocklist[blk_count].count)==
713 AROS_BE2LONG(volume->blockbuffer[i]))
716 blocklist[blk_count].count += 1;
717 D(bug("[install-i386] collectBlockList: sector %d follows previous - increasing count of block %d to %d\n", i, blk_count, blocklist[blk_count].count));
719 else
721 blk_count--; /* decrement first */
722 D(bug("[install-i386] collectBlockList: store new block (%d)\n", blk_count));
723 if (blocklist[blk_count-1].sector != 0)
725 D(bug("[install-i386] collectBlockList: ERROR: out of block space at sector %d, block %d\n", i, blk_count));
726 printf("There is no more space to save blocklist in stage2\n");
727 return 0;
729 D(bug("[install-i386] collectBlockList: storing sector pointer for %d in block %d\n", i, blk_count));
730 blocklist[blk_count].sector = AROS_BE2LONG(volume->blockbuffer[i]);
731 blocklist[blk_count].count = 1;
733 i--;
735 i = volume->SizeBlock - 51;
736 block = AROS_BE2LONG(volume->blockbuffer[volume->SizeBlock - 2]);
737 D(bug("[install-i386] collectBlockList: next block %d, i = %d\n", block, i));
738 } while (block);
740 blocks in blocklist are relative to the first
741 sector of the HD (not partition)
743 D(bug("[install-i386] collectBlockList: successfully updated pointers for %d blocks\n", blk_count));
745 i = 0;
746 for (count=-1;count>=blk_count;count--)
748 blocklist[count].sector += volume->startblock;
749 blocklist[count].seg_adr = 0x820 + (i*32);
750 i += blocklist[count].count;
751 D(bug("[install-i386] collectBlockList: correcting block %d for partition start\n", count));
752 D(bug("[install-i386] collectBlockList: sector : %x seg_adr : %x\n", blocklist[count].sector, blocklist[count].seg_adr));
754 return first_block;
757 void copyRootPath(char *dst, char *rpdos, BOOL isRDB) {
759 D(bug("[install-i386] copyRootPath()\n"));
761 if (isRDB)
763 /* we have an RDB so use devicename */
764 *dst++ = '/';
765 while ((*rpdos) && (*rpdos!=':'))
766 *dst++ = *rpdos++;
768 else
770 while ((*rpdos) && (*rpdos!=':'))
771 rpdos++;
773 rpdos++; /* skip colon */
774 *dst++ = '/';
775 /* append path */
776 while (*rpdos)
777 *dst++ = *rpdos++;
778 if (dst[-1] == '/')
779 dst[-1] = 0;
780 else
781 *dst = 0;
784 /* Convert a unit number into a drive number as understood by GRUB */
785 UWORD getDriveNumber(CONST_STRPTR device, ULONG unit)
787 struct PartitionHandle *ph;
788 ULONG i;
789 UWORD hd_count = 0;
791 for (i = 0; i < unit; i++)
793 ph = OpenRootPartition(device, i);
794 if (ph != NULL)
796 hd_count++;
797 CloseRootPartition(ph);
801 return hd_count;
804 UBYTE *memstr(UBYTE *mem, UBYTE *str, LONG len) {
805 UBYTE *next;
806 UBYTE *search;
807 LONG left;
809 while (len)
811 len--;
812 if (*mem++ == *str)
814 next = mem;
815 search = str+1;
816 left = len;
817 while ((*search) && (left) && (*next++ == *search++))
818 left--;
819 if (*search == 0)
820 return mem-1;
823 return 0;
826 BOOL writeStage2
828 BPTR fh,
829 UBYTE *buffer,
830 STRPTR grubpath,
831 struct Volume *volume
834 BOOL retval = FALSE;
835 char *menuname;
837 D(bug("[install-i386] writeStage2(%x)\n", volume));
839 if (Seek(fh, 0, OFFSET_BEGINNING) != -1)
841 /* write back first block */
842 if (Write(fh, buffer, 512)==512)
844 /* read second stage2 block */
845 if (Read(fh, buffer, 512) == 512)
847 /* set partition number where stage2 is on */
848 buffer[8] = 0xFF;
849 buffer[9] = 0xFF;
850 buffer[10] = volume->partnum;
851 buffer[11] = 0;
852 /* get ptr to version string */
853 menuname = buffer+18;
854 while (*menuname++); /* skip version string */
855 copyRootPath(menuname, grubpath, volume->flags & VF_IS_RDB);
856 strcat(menuname, "/menu.lst");
857 /* write second stage2 block back */
858 if (Seek(fh, -512, OFFSET_CURRENT) != -1)
860 if (Write(fh, buffer, 512) == 512)
862 retval = TRUE;
864 else
865 printf("%s: Write Error\n", menuname);
867 else
868 printf("%s: Seek Error\n", menuname);
870 else
871 printf("Read Error\n");
873 else
874 printf("Write Error\n");
876 else
877 PrintFault(IoErr(), NULL);
878 return retval;
881 ULONG changeStage2
883 STRPTR grubpath, /* path of grub dir */
884 struct Volume *volume, /* volume stage2 is on */
885 ULONG *buffer /* a buffer of at least 512 bytes */
888 ULONG block = 0;
889 struct FileInfoBlock fib;
890 BPTR fh;
891 char stage2path[256];
893 D(bug("[install-i386] changeStage2(%x)\n", volume));
895 AddPart(stage2path, grubpath, 256);
896 AddPart(stage2path, "stage2", 256);
897 fh = Open(stage2path, MODE_OLDFILE);
898 if (fh)
900 if (Examine(fh, &fib))
902 if (Read(fh, buffer, 512) == 512)
905 get and store all blocks of stage2 in first block of stage2
906 first block of stage2 will be returned
908 block = collectBlockList
909 (volume, fib.fib_DiskKey, (struct BlockNode *)&buffer[128]);
911 if (block)
913 if (!writeStage2(fh, (UBYTE *)buffer, grubpath, volume))
914 block = 0;
917 else
918 printf("%s: Read Error\n", stage2path);
920 else
921 PrintFault(IoErr(), stage2path);
922 Close(fh);
924 else
925 PrintFault(IoErr(), stage2path);
926 return block;
929 BOOL writeStage1
931 STRPTR stage1path,
932 struct Volume *volume,
933 struct Volume *s2vol,
934 ULONG block, /* first block of stage2 file */
935 ULONG unit
938 BOOL retval = FALSE;
939 LONG error = 0;
940 BPTR fh;
942 D(bug("[install-i386] writeStage1(%x)\n", volume));
944 fh = Open(stage1path, MODE_OLDFILE);
945 if (fh)
947 if (Read(fh, volume->blockbuffer, 512) == 512)
949 /* install into MBR ? */
950 if ((volume->startblock == 0) && (!(volume->flags & VF_IS_TRACKDISK)))
952 D(bug("[install-i386] writeStage1: Install to HARDDISK\n"));
953 // read old MBR
954 error = readwriteBlock
955 (volume, 0, s2vol->blockbuffer, 512, volume->readcmd);
957 D(bug("[install-i386] writeStage1: MBR Buffer @ %x\n", volume->blockbuffer));
958 D(bug("[install-i386] writeStage1: Copying MBR BPB to %x\n", (char *)volume->blockbuffer + 0x04));
959 // copy BPB (BIOS Parameter Block)
960 CopyMem
962 (APTR)((char *)s2vol->blockbuffer + 0x04),
963 (APTR)((char *)volume->blockbuffer + 0x04),
964 (MBR_BPBEND - 4)
966 // copy partition table - [Overwrites Floppy boot code]
967 D(bug("[install-i386] writeStage1: Copying MBR Partitions to %x\n", (char *)volume->blockbuffer + MBR_PARTSTART));
968 CopyMem
970 (APTR)((char *)s2vol->blockbuffer + MBR_PARTSTART),
971 (APTR)((char *)volume->blockbuffer + MBR_PARTSTART),
972 (MBR_PARTEND - MBR_PARTSTART)
974 // store the drive num stage2 is stored on
975 ((char *)volume->blockbuffer)[GRUB_BOOT_DRIVE] =
976 getDriveNumber(volume->device, unit) | BIOS_HDISK_FLAG;
977 // Store the stage 2 pointer ..
978 ULONG * stage2_sector_start = (ULONG *)((char *)volume->blockbuffer + GRUB_STAGE2_SECTOR);
979 D(bug("[install-i386] writeStage1: writing stage2 pointer @ %x\n", stage2_sector_start));
980 stage2_sector_start[0] = block;
981 D(bug("[install-i386] writeStage1: stage2 pointer = %x\n", stage2_sector_start[0]));
982 stage2_sector_start[0] += s2vol->startblock;
983 D(bug("[install-i386] writeStage1: + offset [%d] = %x\n", s2vol->startblock, stage2_sector_start[0]));
985 if (myargs[4]!=0)
987 D(bug("[install-i386] writeStage1: Forcing LBA\n"));
988 ((char *)volume->blockbuffer)[GRUB_FORCE_LBA] = 1;
990 else
992 D(bug("[install-i386] writeStage1: NOT Forcing LBA\n"));
993 ((char *)volume->blockbuffer)[GRUB_FORCE_LBA] = 0;
996 else
998 D(bug("[install-i386] writeStage1: Install to FLOPPY\n"));
1001 if (error == 0)
1003 error = readwriteBlock
1004 (volume, 0, volume->blockbuffer, 512, volume->writecmd);
1005 if (error)
1006 printf("WriteError %ld\n", error);
1007 else
1008 retval = TRUE;
1010 else
1011 printf("WriteError %ld\n", error);
1013 else
1014 printf("%s: Read Error\n", stage1path);
1015 Close(fh);
1017 else
1018 PrintFault(IoErr(), stage1path);
1019 return retval;
1022 /* Flushes the cache on the volume containing the specified path. */
1023 VOID flushFS(CONST TEXT *path)
1025 char devname[256];
1026 UWORD i;
1028 for (i = 0; path[i] != ':'; i++)
1029 devname[i] = path[i];
1030 devname[i++] = ':';
1031 devname[i] = '\0';
1032 if (Inhibit(devname, DOSTRUE))
1033 Inhibit(devname, DOSFALSE);
1036 BOOL installStageFiles
1038 struct Volume *s2vol, /* stage2 volume */
1039 STRPTR stagepath, /* path to stage* files */
1040 ULONG unit, /* unit stage2 is on */
1041 struct Volume *s1vol /* device on which stage1 will be stored */
1044 BOOL retval = FALSE;
1045 char stagename[256];
1046 ULONG block;
1048 D(bug("[install-i386] installStageFiles(%x)\n", s1vol));
1050 /* Flush GRUB volume's cache */
1051 flushFS(stagepath);
1053 block = changeStage2(stagepath, s2vol, s1vol->blockbuffer);
1054 if (block)
1056 AddPart(stagename, stagepath, 256);
1057 AddPart(stagename, "stage1", 256);
1058 if (writeStage1(stagename, s1vol, s2vol, block, unit))
1059 retval = TRUE;
1061 return retval;
1064 int main(int argc, char **argv) {
1066 struct RDArgs *rdargs;
1067 struct Volume *grubvol;
1068 struct Volume *bbvol;
1069 struct FileSysStartupMsg *fssm;
1071 D(bug("[install-i386] main()\n"));
1073 rdargs = ReadArgs(template, myargs, NULL);
1074 if (rdargs)
1076 D(bug("[install-i386] FORCELBA = %d\n",myargs[4]));
1078 fssm = getDiskFSSM((STRPTR)myargs[3]);
1079 if (fssm != NULL)
1081 if (
1082 (strcmp(AROS_BSTR_ADDR(fssm->fssm_Device),(char*)myargs[0])==0)
1085 grubvol = getGrubStageVolume
1087 AROS_BSTR_ADDR(fssm->fssm_Device),
1088 fssm->fssm_Unit,
1089 fssm->fssm_Flags,
1090 (struct DosEnvec *)BADDR(fssm->fssm_Environ)
1092 if (grubvol)
1094 bbvol=getBBVolume
1096 (STRPTR)myargs[0],
1097 *((LONG *)myargs[1]),
1098 (LONG *)myargs[2]
1100 if (bbvol)
1102 ULONG retval=0;
1104 getBBVolume() read block 0
1105 if the partition directly contains a filesystem
1106 (currently only DOS\x is supported) we have
1107 to move block 0 to block 1 to make space for stage1
1109 if (
1110 (grubvol->startblock == bbvol->startblock) &&
1111 ((AROS_BE2LONG(bbvol->blockbuffer[0]) & 0xFFFFFF00)==0x444F5300)
1114 grubvol->flags &= ~VF_IS_RDB;
1115 retval = readwriteBlock
1116 (bbvol, 0, bbvol->blockbuffer, 512, bbvol->readcmd);
1118 if (retval == 0)
1120 installStageFiles
1122 grubvol,
1123 (STRPTR)myargs[3], /* grub path (stage1/2) */
1124 fssm->fssm_Unit,
1125 bbvol
1128 else
1129 printf("Read Error: %ld\n", retval);
1130 uninitVolume(bbvol);
1132 uninitVolume(grubvol);
1135 else
1137 printf
1139 "%s is not on device %s unit %ld\n",
1140 (STRPTR)myargs[3], (STRPTR)myargs[0], *((LONG *)myargs[1])
1144 else
1145 if (fssm)
1146 printf("kernel path must begin with a device name\n");
1147 FreeArgs(rdargs);
1149 else
1150 PrintFault(IoErr(), argv[0]);
1151 return 0;