2 Copyright © 1995-2009, The AROS Development Team. All rights reserved.
14 #include <exec/alerts.h>
15 #include <aros/asmcall.h>
16 #include <aros/bootloader.h>
17 #include <exec/lists.h>
18 #include <exec/memory.h>
19 #include <exec/resident.h>
20 #include <exec/types.h>
21 #include <libraries/configvars.h>
22 #include <libraries/expansionbase.h>
23 #include <libraries/partition.h>
24 #include <utility/tagitem.h>
25 #include <devices/bootblock.h>
26 #include <devices/timer.h>
28 #include <proto/exec.h>
29 #include <proto/expansion.h>
30 #include <proto/partition.h>
31 #include <proto/bootloader.h>
33 #include <aros/debug.h>
34 #include <aros/macros.h>
36 #define uppercase(x) ((x >= 'a' && x <= 'z') ? (x & 0xdf) : x)
43 static const UBYTE boot_end
;
44 int AROS_SLIB_ENTRY(init
,boot
)();
46 const struct Resident boot_resident
=
49 (struct Resident
*)&boot_resident
,
56 "AROS Boot Strap 41.0\r\n",
60 static const struct _dt
{
64 { 0xffffffff, AROS_MAKE_ID('B','E','F','S' ), "befs.handler" },
65 { 0xffffff00, AROS_MAKE_ID('B','S','D','\0'), "bsd.handler" },
66 { 0xffffff00, AROS_MAKE_ID('C','P','M','\0'), "cpm.handler" },
67 { 0xffffff00, AROS_MAKE_ID('D','O','S','\0'), "afs.handler" },
68 { 0xffffff00, AROS_MAKE_ID('E','X','T','\0'), "ext.handler" },
69 { 0xffffff00, AROS_MAKE_ID('F','A','T','\0'), "fat.handler" },
70 { 0xffffff00, AROS_MAKE_ID('L','V','M','\0'), "lvm.handler" },
71 { 0xffffff00, AROS_MAKE_ID('M','N','X','\0'), "minix.handler" },
72 { 0xffffffff, AROS_MAKE_ID('N','T','F','S' ), "ntfs.handler" },
73 { 0xffffffff, AROS_MAKE_ID('R','A','I','D' ), "raid.handler" },
74 { 0xffffff00, AROS_MAKE_ID('S','F','S','\0'), "sfs.handler" },
75 { 0xffffff00, AROS_MAKE_ID('S','K','Y','\0'), "skyfs.handler" },
76 { 0xffffffff, AROS_MAKE_ID('V','F','A','T' ), "fat.handler" },
80 static const struct _pt
{
83 { 0x01, AROS_MAKE_ID('F','A','T',' ') }, /* DOS 12-bit FAT */
84 { 0x04, AROS_MAKE_ID('F','A','T',' ') }, /* DOS 16-bit FAT (up to 32M) */
85 { 0x06, AROS_MAKE_ID('F','A','T',' ') }, /* DOS 16-bit FAT (over 32M) */
86 { 0x07, AROS_MAKE_ID('N','T','F','S') }, /* Windows NT NTFS */
87 { 0x0b, AROS_MAKE_ID('V','F','A','T') }, /* W95 FAT32 */
88 { 0x0c, AROS_MAKE_ID('V','F','A','T') }, /* W95 LBA FAT32 */
89 { 0x0e, AROS_MAKE_ID('F','A','T',' ') }, /* W95 16-bit LBA FAT */
90 { 0x2c, AROS_MAKE_ID('D','O','S','\0') }, /* AOS OFS */
91 { 0x2d, AROS_MAKE_ID('D','O','S','\1') }, /* AOS FFS */
92 { 0x2e, AROS_MAKE_ID('D','O','S','\3') }, /* AOS FFS-I */
93 { 0x2f, AROS_MAKE_ID('S','F','S','\0') }, /* AOS SFS */
94 { 0x80, AROS_MAKE_ID('M','N','X','\0') }, /* MINIX until 1.4a */
95 { 0x81, AROS_MAKE_ID('M','N','X','\1') }, /* MINIX since 1.4b */
96 { 0x83, AROS_MAKE_ID('E','X','T','\2') }, /* linux native partition */
97 { 0x8e, AROS_MAKE_ID('L','V','M','\0') }, /* linux LVM partition */
98 { 0x9f, AROS_MAKE_ID('B','S','D','\0') }, /* BSD/OS */
99 { 0xa5, AROS_MAKE_ID('B','S','D','\1') }, /* NetBSD, FreeBSD */
100 { 0xa6, AROS_MAKE_ID('B','S','D','\2') }, /* OpenBSD */
101 { 0xdb, AROS_MAKE_ID('C','P','M','\2') }, /* CPM/M */
102 { 0xeb, AROS_MAKE_ID('B','E','F','S') }, /* BeOS FS */
103 { 0xec, AROS_MAKE_ID('S','K','Y','\0') }, /* SkyOS FS */
104 { 0xfd, AROS_MAKE_ID('R','A','I','D') }, /* linux RAID with autodetect */
108 static STRPTR
MatchHandler(IPTR DosType
)
113 for (i
= 0; i
< (sizeof(DosTypes
) / sizeof(struct _dt
)); i
++)
115 if ((DosType
& DosTypes
[i
].mask
) == DosTypes
[i
].type
)
124 static IPTR
MatchPartType(UBYTE PartType
)
129 for (i
= 0; i
< (sizeof(PartTypes
) / sizeof(struct _pt
)); i
++)
131 if ((IPTR
)PartType
== PartTypes
[i
].part
)
133 type
= PartTypes
[i
].type
;
140 static ULONG
GetOffset(struct PartitionBase
*PartitionBase
,
141 struct PartitionHandle
*ph
)
147 tags
[0] = PT_DOSENVEC
;
153 GetPartitionAttrs(ph
, (struct TagItem
*)tags
);
154 offset
+= de
.de_LowCyl
* de
.de_Surfaces
* de
.de_BlocksPerTrack
;
160 static VOID AddPartitionVolume
162 struct ExpansionBase
*ExpansionBase
,
163 struct PartitionBase
*PartitionBase
,
164 struct FileSysStartupMsg
*fssm
,
165 struct PartitionHandle
*table
,
166 struct PartitionHandle
*pn
,
167 struct ExecBase
* SysBase
171 ULONG i
, blockspercyl
;
172 const struct PartitionAttribute
*attrs
;
175 struct DeviceNode
*devnode
;
176 struct PartitionType ptyp
;
178 TEXT
*devname
, *handler
;
181 D(bug("[Boot] AddPartitionVolume\n"));
182 pp
= AllocVec(sizeof(struct DosEnvec
) + sizeof(IPTR
) * 4,
183 MEMF_PUBLIC
| MEMF_CLEAR
);
186 attrs
= QueryPartitionAttrs(table
);
187 while ((attrs
->attribute
!= PTA_DONE
) && (attrs
->attribute
!= PTA_NAME
))
188 attrs
++; /* look for name attr */
189 if (attrs
->attribute
!= PTA_DONE
)
191 D(bug("[Boot] RDB partition\n"));
192 /* partition has a name => RDB partition */
194 tags
[1] = (IPTR
)name
;
195 tags
[2] = PT_DOSENVEC
;
196 tags
[3] = (IPTR
)&pp
[4];
197 tags
[4] = PT_BOOTABLE
;
198 tags
[5] = (IPTR
)&bootable
;
200 GetPartitionAttrs(pn
, (struct TagItem
*)tags
);
201 D(bug("[Boot] Partition name: %s bootable: %d\n", name
, bootable
));
202 /* BHFormat complains if this bit is not set, and it's really wrong to have it unset. So we explicitly set it here.
203 Pavel Fedin <sonic_amiga@rambler.ru> */
204 pp
[4 + DE_BUFMEMTYPE
] |= MEMF_PUBLIC
;
208 D(bug("[Boot] MBR partition\n"));
209 /* partition doesn't have a name => MBR partition */
210 tags
[0] = PT_POSITION
;
211 tags
[1] = (IPTR
)&ppos
;
213 tags
[3] = (IPTR
)&ptyp
;
214 tags
[4] = PT_DOSENVEC
;
215 tags
[5] = (IPTR
)&pp
[4];
217 GetPartitionAttrs(pn
, (struct TagItem
*)tags
);
221 devname
= AROS_BSTR_ADDR(fssm
->fssm_Device
);
222 for (i
= 0; i
< 26; i
++)
224 if (*devname
== '.' || *devname
== '\0')
226 name
[i
] = (UBYTE
)uppercase(*devname
);
229 if ((fssm
->fssm_Unit
/ 10))
230 name
[i
++] = '0' + (UBYTE
)(fssm
->fssm_Unit
/ 10);
231 name
[i
++] = '0' + (UBYTE
)(fssm
->fssm_Unit
% 10);
233 if (table
->table
->type
== PHPTT_EBR
)
236 name
[i
++] = '0' + (UBYTE
)(ppos
/ 10);
237 name
[i
++] = '0' + (UBYTE
)(ppos
% 10);
239 D(bug("[Boot] Partition name: %s type: %lu bootable: %d\n", name
, ptyp
.id
[0], bootable
));
240 /* set DOSTYPE based on the partition type */
241 pp
[4 + DE_DOSTYPE
] = MatchPartType(ptyp
.id
[0]);
242 /* set some common DOSENV fields */
243 pp
[4 + DE_TABLESIZE
] = DE_BOOTBLOCKS
;
244 pp
[4 + DE_NUMBUFFERS
] = 20;
245 pp
[4 + DE_BUFMEMTYPE
] = MEMF_PUBLIC
;
246 pp
[4 + DE_MAXTRANSFER
] = 0x00200000;
247 pp
[4 + DE_MASK
] = 0x7ffffffe;
248 /* set some fs specific fields */
253 case 0x2e: /* FFS I */
255 pp
[4 + DE_SECSPERBLOCK
] = 1;
256 pp
[4 + DE_RESERVEDBLKS
] = 2;
257 pp
[4 + DE_BOOTBLOCKS
] = 2;
263 pp
[1] = (IPTR
)AROS_BSTR_ADDR(fssm
->fssm_Device
);
264 pp
[2] = fssm
->fssm_Unit
;
265 pp
[3] = fssm
->fssm_Flags
;
266 i
= GetOffset(PartitionBase
, pn
);
267 blockspercyl
= pp
[4 + DE_BLKSPERTRACK
] * pp
[4 + DE_NUMHEADS
];
268 if (i
% blockspercyl
!= 0)
271 pp
[4 + DE_LOWCYL
] += i
;
272 pp
[4 + DE_HIGHCYL
] += i
;
274 D(bug("[Boot] Looking up handler for 0x%08lX\n", pp
[4+DE_DOSTYPE
]));
275 handler
= MatchHandler(pp
[4 + DE_DOSTYPE
]);
277 /* Skip unknown partition types */
280 D(bug("[Boot] found handler: %s\n", handler
));
281 devnode
= MakeDosNode(pp
);
284 devnode
->dn_Handler
= MKBADDR(AllocVec(AROS_BSTR_MEMSIZE4LEN(
285 strlen(handler
)), MEMF_PUBLIC
| MEMF_CLEAR
));
286 if (devnode
->dn_Handler
)
289 while (handler
[i
] != '\0')
291 AROS_BSTR_putchar(devnode
->dn_Handler
, i
, handler
[i
]);
294 AROS_BSTR_setstrlen(devnode
->dn_Handler
, i
);
295 AddBootNode(bootable
? pp
[4 + DE_BOOTPRI
] : -128, 0, devnode
, 0);
296 D(bug("[Boot] AddBootNode(%s,0x%lx,'%s')\n",
297 devnode
->dn_Ext
.dn_AROS
.dn_DevName
,
298 pp
[4 + DE_DOSTYPE
], handler
));
307 static BOOL CheckTables
309 struct ExpansionBase
*ExpansionBase
,
310 struct PartitionBase
*PartitionBase
,
311 struct FileSysStartupMsg
*fssm
,
312 struct PartitionHandle
*table
,
313 struct ExecBase
*SysBase
317 struct PartitionHandle
*ph
;
319 /* Traverse partition tables recursively, and attempt to add a BootNode
320 for any non-subtable partitions found */
321 if (OpenPartitionTable(table
) == 0)
323 ph
= (struct PartitionHandle
*)table
->table
->list
.lh_Head
;
324 while (ph
->ln
.ln_Succ
)
326 /* Attempt to add partition to system if it isn't a subtable */
327 if (!CheckTables(ExpansionBase
, PartitionBase
, fssm
, ph
, SysBase
))
328 AddPartitionVolume(ExpansionBase
, PartitionBase
, fssm
, table
,
330 ph
= (struct PartitionHandle
*)ph
->ln
.ln_Succ
;
333 ClosePartitionTable(table
);
338 static BOOL
IsRemovable(struct ExecBase
*SysBase
, struct IOExtTD
*ioreq
)
340 struct DriveGeometry dg
;
342 ioreq
->iotd_Req
.io_Command
= TD_GETGEOMETRY
;
343 ioreq
->iotd_Req
.io_Data
= &dg
;
344 ioreq
->iotd_Req
.io_Length
= sizeof(struct DriveGeometry
);
345 DoIO((struct IORequest
*)ioreq
);
346 return (dg
.dg_Flags
& DGF_REMOVABLE
) ? TRUE
: FALSE
;
349 static VOID CheckPartitions
351 struct ExpansionBase
*ExpansionBase
,
352 struct ExecBase
*SysBase
,
356 struct PartitionBase
*PartitionBase
;
357 struct PartitionHandle
*pt
;
358 struct FileSysStartupMsg
*fssm
;
361 (struct PartitionBase
*)OpenLibrary("partition.library", 1);
364 fssm
= BADDR(((struct DeviceNode
*)bn
->bn_DeviceNode
)->dn_Startup
);
365 pt
= OpenRootPartition(AROS_BSTR_ADDR(fssm
->fssm_Device
),
369 if (IsRemovable(SysBase
, pt
->bd
->ioreq
))
371 /* don't check removable devices for partition tables */
372 Enqueue(&ExpansionBase
->MountList
, (struct Node
*)bn
);
376 if (!CheckTables(ExpansionBase
, PartitionBase
, fssm
, pt
,
379 /* no partition table found, so reinsert node */
380 Enqueue(&ExpansionBase
->MountList
, (struct Node
*)bn
);
383 CloseRootPartition(pt
);
387 /* amicdrom fails here because of non-initialized libraries */
388 Enqueue(&ExpansionBase
->MountList
, (struct Node
*)bn
);
390 CloseLibrary((struct Library
*)PartitionBase
);
394 AROS_UFH3(int, AROS_SLIB_ENTRY(init
, boot
),
395 AROS_UFHA(ULONG
, dummy
, D0
),
396 AROS_UFHA(ULONG
, seglist
, A0
),
397 AROS_UFHA(struct ExecBase
*, SysBase
, A6
)
401 struct ExpansionBase
*ExpansionBase
;
402 struct BootNode
*bootNode
;
404 struct Resident
*DOSResident
;
405 void *BootLoaderBase
;
407 #if !(AROS_FLAVOUR & AROS_FLAVOUR_EMULATION)
409 (struct ExpansionBase
*)OpenLibrary("expansion.library", 0);
410 if( ExpansionBase
== NULL
)
412 D(bug( "Could not open expansion.library, something's wrong!\n"));
413 Alert(AT_DeadEnd
| AG_OpenLib
| AN_BootStrap
| AO_ExpansionLib
);
416 /* Try to open bootloader.resource */
417 if ((BootLoaderBase
= OpenResource("bootloader.resource")) != NULL
)
423 args
= GetBootInfo(BL_Args
);
428 * Search the kernel parameters for the bootdelay=%d string. It determines the
431 ForeachNode(args
, node
)
433 if (strncmp(node
->ln_Name
, "bootdelay=", 10) == 0)
435 struct MsgPort
*port
= CreateMsgPort();
436 struct timerequest
*tr
= (struct timerequest
*)
437 CreateIORequest(port
, sizeof(struct timerequest
));
439 OpenDevice("timer.device", UNIT_VBLANK
,
440 (struct IORequest
*)tr
, 0);
442 sscanf(node
->ln_Name
, "bootdelay=%d", &delay
);
443 D(bug("[Boot] delay of %d seconds requested.", delay
));
445 tr
->tr_node
.io_Command
= TR_ADDREQUEST
;
446 tr
->tr_time
.tv_sec
= delay
;
447 tr
->tr_time
.tv_usec
= 0;
449 DoIO((struct IORequest
*)tr
);
451 CloseDevice((struct IORequest
*)tr
);
452 DeleteIORequest((struct IORequest
*)tr
);
459 /* move all boot nodes into another list */
461 while ((bootNode
= (struct BootNode
*)RemHead(&ExpansionBase
->MountList
)))
462 AddTail(&list
, &bootNode
->bn_Node
);
464 /* check boot nodes for partition tables */
465 while ((bootNode
= (struct BootNode
*)RemHead(&list
)))
466 CheckPartitions(ExpansionBase
, SysBase
, bootNode
);
467 CloseLibrary((struct Library
*)ExpansionBase
);
470 DOSResident
= FindResident( "dos.library" );
472 if( DOSResident
== NULL
)
474 Alert( AT_DeadEnd
| AG_OpenLib
| AN_BootStrap
| AO_DOSLib
);
477 InitResident( DOSResident
, NULL
);
479 /* We don't get here if everything went well */
485 static const UBYTE boot_end
= 0;