added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / rom / boot / strap.c
blob6ac61cf318645f26d1b839ef849e2c1971bd1f7d
1 /*
2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Boot AROS
6 Lang: english
7 */
9 #define DEBUG 1
11 #include <string.h>
13 #include <exec/alerts.h>
14 #include <aros/asmcall.h>
15 #include <exec/lists.h>
16 #include <exec/memory.h>
17 #include <exec/resident.h>
18 #include <exec/types.h>
19 #include <libraries/configvars.h>
20 #include <libraries/expansionbase.h>
21 #include <libraries/partition.h>
22 #include <utility/tagitem.h>
23 #include <devices/bootblock.h>
25 #include <proto/exec.h>
26 #include <proto/expansion.h>
27 #include <proto/partition.h>
29 #ifdef DEBUG
30 #include <aros/debug.h>
31 #endif
32 #include <aros/macros.h>
34 #define BOOT_CHECK 0
36 #define uppercase(x) ((x >= 'a' && x <= 'z') ? (x & 0xdf) : x)
38 int boot_entry()
40 return -1;
43 static const UBYTE boot_end;
44 int AROS_SLIB_ENTRY(init,boot)();
46 const struct Resident boot_resident =
48 RTC_MATCHWORD,
49 (struct Resident *)&boot_resident,
50 (APTR)&boot_end,
51 RTF_COLDSTART,
52 41,
53 NT_PROCESS,
54 -50,
55 "Boot Strap",
56 "AROS Boot Strap 41.0\r\n",
57 (APTR)&boot_init
60 static const struct _dt {
61 IPTR mask,type,fs;
62 } DosTypes[] = {
63 { 0xffffffff, AROS_MAKE_ID('B','E','F','S' ), (IPTR)"befs.handler" },
64 { 0xffffff00, AROS_MAKE_ID('B','S','D','\0'), (IPTR)"bsd.handler" },
65 { 0xffffff00, AROS_MAKE_ID('C','P','M','\0'), (IPTR)"cpm.handler" },
66 { 0xffffff00, AROS_MAKE_ID('D','O','S','\0'), (IPTR)"afs.handler" },
67 { 0xffffff00, AROS_MAKE_ID('E','X','T','\0'), (IPTR)"ext.handler" },
68 { 0xffffff00, AROS_MAKE_ID('F','A','T','\0'), (IPTR)"fat.handler" },
69 { 0xffffff00, AROS_MAKE_ID('L','V','M','\0'), (IPTR)"lvm.handler" },
70 { 0xffffff00, AROS_MAKE_ID('M','N','X','\0'), (IPTR)"minix.handler" },
71 { 0xffffffff, AROS_MAKE_ID('N','T','F','S' ), (IPTR)"ntfs.handler" },
72 { 0xffffffff, AROS_MAKE_ID('R','A','I','D' ), (IPTR)"raid.handler" },
73 { 0xffffff00, AROS_MAKE_ID('S','F','S','\0'), (IPTR)"sfs.handler" },
74 { 0xffffff00, AROS_MAKE_ID('S','K','Y','\0'), (IPTR)"skyfs.handler" },
75 { 0xffffffff, AROS_MAKE_ID('V','F','A','T' ), (IPTR)"fat.handler" },
76 { 0,0,0, }
79 static const struct _pt {
80 IPTR part,type;
81 } PartTypes[] = {
82 { 0x01, AROS_MAKE_ID('F','A','T',' ') }, /* DOS 12-bit FAT */
83 { 0x04, AROS_MAKE_ID('F','A','T',' ') }, /* DOS 16-bit FAT (up to 32M) */
84 { 0x06, AROS_MAKE_ID('F','A','T',' ') }, /* DOS 16-bit FAT (over 32M) */
85 { 0x07, AROS_MAKE_ID('N','T','F','S') }, /* Windows NT NTFS */
86 { 0x0b, AROS_MAKE_ID('V','F','A','T') }, /* W95 FAT32 */
87 { 0x0c, AROS_MAKE_ID('V','F','A','T') }, /* W95 LBA FAT32 */
88 { 0x0e, AROS_MAKE_ID('F','A','T',' ') }, /* W95 16-bit LBA FAT */
89 { 0x2c, AROS_MAKE_ID('D','O','S','\0') }, /* AOS OFS */
90 { 0x2d, AROS_MAKE_ID('D','O','S','\1') }, /* AOS FFS */
91 { 0x2e, AROS_MAKE_ID('D','O','S','\3') }, /* AOS FFS-I */
92 { 0x2f, AROS_MAKE_ID('S','F','S','\0') }, /* AOS SFS */
93 { 0x80, AROS_MAKE_ID('M','N','X','\0') }, /* MINIX until 1.4a */
94 { 0x81, AROS_MAKE_ID('M','N','X','\1') }, /* MINIX since 1.4b */
95 { 0x83, AROS_MAKE_ID('E','X','T','\2') }, /* linux native partition */
96 { 0x8e, AROS_MAKE_ID('L','V','M','\0') }, /* linux LVM partition */
97 { 0x9f, AROS_MAKE_ID('B','S','D','\0') }, /* BSD/OS */
98 { 0xa5, AROS_MAKE_ID('B','S','D','\1') }, /* NetBSD, FreeBSD */
99 { 0xa6, AROS_MAKE_ID('B','S','D','\2') }, /* OpenBSD */
100 { 0xdb, AROS_MAKE_ID('C','P','M','\2') }, /* CPM/M */
101 { 0xeb, AROS_MAKE_ID('B','E','F','S') }, /* BeOS FS */
102 { 0xec, AROS_MAKE_ID('S','K','Y','\0') }, /* SkyOS FS */
103 { 0xfd, AROS_MAKE_ID('R','A','I','D') }, /* linux RAID with autodetect */
104 { 0, 0 }
107 static IPTR MatchHandler(IPTR DosType)
109 int i;
110 IPTR fs = 0;
112 for (i = 0; i < (sizeof(DosTypes) / sizeof(struct _dt)); i++)
114 if ((DosType & DosTypes[i].mask) == DosTypes[i].type)
116 fs = DosTypes[i].fs;
117 break;
120 return fs;
123 static IPTR MatchPartType(UBYTE PartType)
125 int i;
126 IPTR type = 0;
128 for (i = 0; i < (sizeof(PartTypes) / sizeof(struct _pt)); i++)
130 if ((IPTR)PartType == PartTypes[i].part)
132 type = PartTypes[i].type;
133 break;
136 return type;
139 static ULONG GetOffset(struct PartitionBase *PartitionBase,
140 struct PartitionHandle *ph)
142 IPTR tags[3];
143 struct DosEnvec de;
144 ULONG offset = 0;
146 tags[0] = PT_DOSENVEC;
147 tags[1] = (IPTR)&de;
148 tags[2] = TAG_DONE;
149 ph = ph->root;
150 while (ph->root)
152 GetPartitionAttrs(ph, (struct TagItem *)tags);
153 offset += de.de_LowCyl * de.de_Surfaces * de.de_BlocksPerTrack;
154 ph = ph->root;
156 return offset;
159 static VOID AddPartitionVolume
161 struct ExpansionBase *ExpansionBase,
162 struct PartitionBase *PartitionBase,
163 struct FileSysStartupMsg *fssm,
164 struct PartitionHandle *table,
165 struct PartitionHandle *pn,
166 struct ExecBase * SysBase
169 UBYTE name[32];
170 ULONG i, blockspercyl;
171 const struct PartitionAttribute *attrs;
172 IPTR tags[7];
173 IPTR *pp;
174 struct DeviceNode *devnode;
175 struct PartitionType ptyp;
176 LONG ppos;
177 TEXT *devname, *handler;
179 pp = AllocVec(sizeof(struct DosEnvec) + sizeof(IPTR) * 4,
180 MEMF_PUBLIC | MEMF_CLEAR);
181 if (pp)
183 attrs = QueryPartitionAttrs(table);
184 while ((attrs->attribute != PTA_DONE) && (attrs->attribute != PTA_NAME))
185 attrs++; /* look for name attr */
186 if (attrs->attribute != PTA_DONE)
188 /* partition has a name => RDB partition */
189 tags[0] = PT_NAME;
190 tags[1] = (IPTR)name;
191 tags[2] = PT_DOSENVEC;
192 tags[3] = (IPTR)&pp[4];
193 tags[4] = TAG_DONE;
194 GetPartitionAttrs(pn, (struct TagItem *)tags);
196 else
198 /* partition doesn't have a name => MBR partition */
199 tags[0] = PT_POSITION;
200 tags[1] = (IPTR)&ppos;
201 tags[2] = PT_TYPE;
202 tags[3] = (IPTR)&ptyp;
203 tags[4] = PT_DOSENVEC;
204 tags[5] = (IPTR)&pp[4];
205 tags[6] = TAG_DONE;
206 GetPartitionAttrs(pn, (struct TagItem *)tags);
208 /* make the name */
209 devname = AROS_BSTR_ADDR(fssm->fssm_Device);
210 for (i = 0; i < 26; i++)
212 if (*devname == '.' || *devname == '\0')
213 break;
214 name[i] = (UBYTE)uppercase(*devname);
215 devname++;
217 if ((fssm->fssm_Unit / 10))
218 name[i++] = '0' + (UBYTE)(fssm->fssm_Unit / 10);
219 name[i++] = '0' + (UBYTE)(fssm->fssm_Unit % 10);
220 name[i++] = 'P';
221 if (table->table->type == PHPTT_EBR)
222 ppos += 4;
223 if ((ppos / 10))
224 name[i++] = '0' + (UBYTE)(ppos / 10);
225 name[i++] = '0' + (UBYTE)(ppos % 10);
226 name[i] = '\0';
227 /* set DOSTYPE based on the partition type */
228 pp[4 + DE_DOSTYPE] = MatchPartType(ptyp.id[0]);
229 /* set some common DOSENV fields */
230 pp[4 + DE_TABLESIZE] = DE_BOOTBLOCKS;
231 pp[4 + DE_NUMBUFFERS] = 20;
232 pp[4 + DE_BUFMEMTYPE] = MEMF_PUBLIC;
233 pp[4 + DE_MAXTRANSFER] = 0x00200000;
234 pp[4 + DE_MASK] = 0x7ffffffe;
235 /* set some fs specific fields */
236 switch(ptyp.id[0])
238 case 0x2c: /* OFS */
239 case 0x2d: /* FFS */
240 case 0x2e: /* FFS I */
241 case 0x2f: /* SFS */
242 pp[4 + DE_SECSPERBLOCK] = 1;
243 pp[4 + DE_RESERVEDBLKS] = 2;
244 pp[4 + DE_BOOTBLOCKS] = 2;
245 break;
249 pp[0] = (IPTR)name;
250 pp[1] = (IPTR)AROS_BSTR_ADDR(fssm->fssm_Device);
251 pp[2] = fssm->fssm_Unit;
252 pp[3] = fssm->fssm_Flags;
253 i = GetOffset(PartitionBase, pn);
254 blockspercyl = pp[4 + DE_BLKSPERTRACK] * pp[4 + DE_NUMHEADS];
255 if (i % blockspercyl != 0)
256 return;
257 i /= blockspercyl;
258 pp[4 + DE_LOWCYL] += i;
259 pp[4 + DE_HIGHCYL] += i;
261 handler = MatchHandler(pp[4 + DE_DOSTYPE]);
263 /* Skip unknown partition types */
264 if (handler != NULL)
266 devnode = MakeDosNode(pp);
267 if (devnode != NULL)
269 devnode->dn_Handler = MKBADDR(AllocVec(AROS_BSTR_MEMSIZE4LEN(
270 strlen(handler)), MEMF_PUBLIC | MEMF_CLEAR));
271 if (devnode->dn_Handler)
273 i = 0;
274 while (handler[i] != '\0')
276 AROS_BSTR_putchar(devnode->dn_Handler, i, handler[i]);
277 i++;
279 AROS_BSTR_setstrlen(devnode->dn_Handler, i);
280 AddBootNode(pp[4 + DE_BOOTPRI], 0, devnode, 0);
281 D(bug("[Boot] AddBootNode(%s,0x%lx,'%s')\n",
282 devnode->dn_Ext.dn_AROS.dn_DevName,
283 pp[4 + DE_DOSTYPE], handler));
284 return;
288 FreeVec(pp);
292 static BOOL CheckTables
294 struct ExpansionBase *ExpansionBase,
295 struct PartitionBase *PartitionBase,
296 struct FileSysStartupMsg *fssm,
297 struct PartitionHandle *table,
298 struct ExecBase *SysBase
301 BOOL retval = FALSE;
302 struct PartitionHandle *ph;
304 /* Traverse partition tables recursively, and attempt to add a BootNode
305 for any non-subtable partitions found */
306 if (OpenPartitionTable(table) == 0)
308 ph = (struct PartitionHandle *)table->table->list.lh_Head;
309 while (ph->ln.ln_Succ)
311 /* Attempt to add partition to system if it isn't a subtable */
312 if (!CheckTables(ExpansionBase, PartitionBase, fssm, ph, SysBase))
313 AddPartitionVolume(ExpansionBase, PartitionBase, fssm, table,
314 ph, SysBase);
315 ph = (struct PartitionHandle *)ph->ln.ln_Succ;
317 retval = TRUE;
318 ClosePartitionTable(table);
320 return retval;
323 static BOOL IsRemovable(struct ExecBase *SysBase, struct IOExtTD *ioreq)
325 struct DriveGeometry dg;
327 ioreq->iotd_Req.io_Command = TD_GETGEOMETRY;
328 ioreq->iotd_Req.io_Data = &dg;
329 ioreq->iotd_Req.io_Length = sizeof(struct DriveGeometry);
330 DoIO((struct IORequest *)ioreq);
331 return (dg.dg_Flags & DGF_REMOVABLE) ? TRUE : FALSE;
334 static VOID CheckPartitions
336 struct ExpansionBase *ExpansionBase,
337 struct ExecBase *SysBase,
338 struct BootNode *bn
341 struct PartitionBase *PartitionBase;
342 struct PartitionHandle *pt;
343 struct FileSysStartupMsg *fssm;
345 PartitionBase =
346 (struct PartitionBase *)OpenLibrary("partition.library", 1);
347 if (PartitionBase)
349 fssm = BADDR(((struct DeviceNode *)bn->bn_DeviceNode)->dn_Startup);
350 pt = OpenRootPartition(AROS_BSTR_ADDR(fssm->fssm_Device),
351 fssm->fssm_Unit);
352 if (pt)
354 if (IsRemovable(SysBase, pt->bd->ioreq))
356 /* don't check removable devices for partition tables */
357 Enqueue(&ExpansionBase->MountList, (struct Node *)bn);
359 else
361 if (!CheckTables(ExpansionBase, PartitionBase, fssm, pt,
362 SysBase))
364 /* no partition table found, so reinsert node */
365 Enqueue(&ExpansionBase->MountList, (struct Node *)bn);
368 CloseRootPartition(pt);
370 else
372 /* amicdrom fails here because of non-initialized libraries */
373 Enqueue(&ExpansionBase->MountList, (struct Node *)bn);
375 CloseLibrary((struct Library *)PartitionBase);
379 AROS_UFH3(int, AROS_SLIB_ENTRY(init, boot),
380 AROS_UFHA(ULONG, dummy, D0),
381 AROS_UFHA(ULONG, seglist, A0),
382 AROS_UFHA(struct ExecBase *, SysBase, A6)
385 AROS_USERFUNC_INIT
386 struct ExpansionBase *ExpansionBase;
387 struct BootNode *bootNode;
388 struct List list;
389 struct Resident *DOSResident;
391 #if !(AROS_FLAVOUR & AROS_FLAVOUR_EMULATION)
392 ExpansionBase =
393 (struct ExpansionBase *)OpenLibrary("expansion.library", 0);
394 if( ExpansionBase == NULL )
396 D(bug( "Could not open expansion.library, something's wrong!\n"));
397 Alert(AT_DeadEnd | AG_OpenLib | AN_BootStrap | AO_ExpansionLib);
400 /* move all boot nodes into another list */
401 NEWLIST(&list);
402 while ((bootNode = (struct BootNode *)RemHead(&ExpansionBase->MountList)))
403 AddTail(&list, &bootNode->bn_Node);
405 /* check boot nodes for partition tables */
406 while ((bootNode = (struct BootNode *)RemHead(&list)))
407 CheckPartitions(ExpansionBase, SysBase, bootNode);
408 CloseLibrary((struct Library *)ExpansionBase);
409 #endif
411 DOSResident = FindResident( "dos.library" );
413 if( DOSResident == NULL )
415 Alert( AT_DeadEnd | AG_OpenLib | AN_BootStrap | AO_DOSLib );
418 InitResident( DOSResident, NULL );
420 return 0;
422 AROS_USERFUNC_EXIT
425 static const UBYTE boot_end = 0;