2 Copyright © 1995-2012, The AROS Development Team. All rights reserved.
9 #include <aros/debug.h>
10 #include <exec/resident.h>
11 #include <proto/exec.h>
12 #include <proto/arossupport.h>
13 #include <libraries/expansion.h>
14 #include <libraries/expansionbase.h>
15 #include <resources/filesysres.h>
19 #include "dos_intern.h"
23 static void PRINT_DOSTYPE(ULONG dt
)
27 bug("Dos/CliInit: DosType is ");
29 for (i
= 0; i
< 4; i
++)
31 unsigned char c
= dt
>> (24 - i
* 8);
44 #define PRINT_DOSTYPE(dt)
48 static long internalBootCliHandler(void);
50 /*****************************************************************************
53 #include <dos/dosextens.h>
54 #include <proto/dos.h>
56 AROS_LH1(IPTR
, CliInit
,
59 AROS_LHA(struct DosPacket
*, dp
, A0
),
62 struct DosLibrary
*, DOSBase
, 154, Dos
)
66 Set up the first shell process.
68 Currently, no DOS Packet arguments are used by this
71 A new Boot Cli process is created, and 'dp' is
72 sent to it. If the boot shell succeeds, then 'dp'
73 is returned with dp_Res1 = DOSTRUE.
78 dp -- startup arguments specified as a packet
82 RETURN_OK on success, ERROR_* (from dp_Res2) on failure.
86 This function is internal to AROS, and should never be
97 *****************************************************************************/
101 struct MsgPort
*mp
, *reply_mp
;
102 struct DosPacket
*my_dp
= NULL
;
106 /* Create a DOS Process to handle this, since
107 * we're probably being called from a Task context
110 /* This call does *not* require that
111 * we be a DOS Process. Luckily.
113 my_dp
= AllocDosObject(DOS_STDPKT
, NULL
);
118 return ERROR_NO_FREE_STORE
;
120 reply_mp
= CreateMsgPort();
121 if (reply_mp
== NULL
) {
123 FreeDosObject(DOS_STDPKT
, my_dp
);
124 return ERROR_NO_FREE_STORE
;
127 seg
= CreateSegList(internalBootCliHandler
);
129 mp
= CreateProc("Boot Mount", 0, seg
, AROS_STACKSIZE
);
131 DeleteMsgPort(reply_mp
);
133 FreeDosObject(DOS_STDPKT
, my_dp
);
134 /* A best guess... */
136 return ERROR_NO_FREE_STORE
;
139 /* Preload the reply with failure */
140 dp
->dp_Res1
= DOSFALSE
;
141 dp
->dp_Res2
= ERROR_NOT_IMPLEMENTED
;
143 /* Again, doesn't require this Task to be a Process */
144 SendPkt(dp
, mp
, reply_mp
);
146 /* Wait for the message from the Boot Cli */
150 /* We know that if we've received a reply packet,
151 * that we've been able to execute the handler,
152 * therefore we can dispense with the 'CreateSegment'
161 FreeDosObject(DOS_STDPKT
, my_dp
);
163 DeleteMsgPort(reply_mp
);
165 D(bug("Dos/CliInit: Task returned Res1=%ld, Res2=%ld\n", Res1
, Res2
));
167 /* Did we succeed? */
170 /* Make sure we return non-zero error code, 0 == RETURN_OK */
172 Res2
= ERROR_UNKNOWN
;
179 /* Find the most recent version of the matching filesystem */
180 static struct FileSysEntry
*internalMatchFileSystemResourceHandler(struct FileSysResource
*fsr
, ULONG DosType
)
182 struct FileSysEntry
*fse
, *best_fse
= NULL
;
184 ForeachNode(&fsr
->fsr_FileSysEntries
, fse
)
186 if (fse
->fse_DosType
== DosType
)
188 if (fse
->fse_PatchFlags
& (FSEF_HANDLER
| FSEF_SEGLIST
| FSEF_TASK
))
190 if (best_fse
== NULL
|| fse
->fse_Version
> best_fse
->fse_Version
)
201 /* See if the BootNode's DeviceNode needs to be patched by
202 * an entry in FileSysResource
204 * If de->de_DosType == 0, and no dn_SegList nor dn_Handler,
205 * then the node uses the 'defseg' handler.
207 static void internalPatchBootNode(struct FileSysResource
*fsr
, struct DeviceNode
*dn
, BPTR defseg
)
209 struct FileSysStartupMsg
*fssm
;
211 struct FileSysEntry
*fse
;
213 /* If we already have a task installed,
216 if (dn
->dn_Task
!= NULL
)
219 /* If we already have a handler installed,
222 if (dn
->dn_SegList
!= BNULL
)
225 fssm
= BADDR(dn
->dn_Startup
);
229 de
= BADDR(fssm
->fssm_Environ
);
233 /* If the DosType is 0 and dn_Handler == BNULL, use the default handler */
234 if (de
->de_DosType
== 0 && dn
->dn_Handler
== BNULL
)
236 D(bug("Dos/CliInit: Neither DosType nor Handler specified, using default filesystem\n"));
237 dn
->dn_SegList
= defseg
;
238 dn
->dn_GlobalVec
= (BPTR
)-1;
242 /* If no FileSysResource, nothing to do */
244 D(bug("Dos/CliInit: No FileSystem.resource, not patching DeviceNode %p\n", dn
));
248 D(bug("Dos/CliInit: Looking for patches for DeviceNode %p\n", dn
));
251 * internalMatchFileSystemResourceHandler looks up the filesystem
253 fse
= internalMatchFileSystemResourceHandler(fsr
, de
->de_DosType
);
256 D(bug("Dos/CliInit: found 0x%p in FileSystem.resource\n", fse
));
257 PRINT_DOSTYPE(fse
->fse_DosType
);
259 dn
->dn_SegList
= fse
->fse_SegList
;
260 /* other fse_PatchFlags bits are quite pointless */
261 if (fse
->fse_PatchFlags
& FSEF_TASK
)
262 dn
->dn_Task
= (APTR
)fse
->fse_Task
;
263 if (fse
->fse_PatchFlags
& FSEF_LOCK
)
264 dn
->dn_Lock
= fse
->fse_Lock
;
266 /* Adjust the stack size for 64-bits if needed.
268 if (fse
->fse_PatchFlags
& FSEF_STACKSIZE
)
269 dn
->dn_StackSize
= (fse
->fse_StackSize
/sizeof(ULONG
))*sizeof(IPTR
);
270 if (fse
->fse_PatchFlags
& FSEF_PRIORITY
)
271 dn
->dn_Priority
= fse
->fse_Priority
;
272 if (fse
->fse_PatchFlags
& FSEF_GLOBALVEC
)
273 dn
->dn_GlobalVec
= fse
->fse_GlobalVec
;
277 static struct MsgPort
*mountBootNode(struct DeviceNode
*dn
, struct FileSysResource
*fsr
, struct DosLibrary
*DOSBase
)
281 if ((dn
== NULL
) || (dn
->dn_Name
== BNULL
))
284 D(bug("Dos/CliInit: Mounting 0x%p (%b)...\n", dn
, dn
->dn_Name
));
286 /* Check if the device is already in DOS list */
287 dl
= LockDosList(LDF_DEVICES
| LDF_READ
);
289 while ((dl
= NextDosEntry(dl
, LDF_DEVICES
)))
291 if (dl
== (struct DosList
*)dn
)
295 UnLockDosList(LDF_DEVICES
| LDF_READ
);
297 /* Found in DOS list? Do nothing. */
303 /* Patch it up, if needed */
304 internalPatchBootNode(fsr
, dn
, DOSBase
->dl_Root
->rn_FileHandlerSegment
);
306 if (!dn
->dn_Handler
&& !dn
->dn_SegList
)
308 /* Don't know how to mount? Error... */
312 if (AddDosEntry((struct DosList
*)dn
) != DOSFALSE
)
315 * Do not check for ANDF_STARTPROC because:
316 * a) On the Amiga ADNF_STARTPROC was not present in KS 1.3 and earlier, there was no deferred mount.
317 * b) In fact if we have something in ExpansionBase, we for sure want it to be mounted.
319 D(bug("Dos/CliInit: Added to DOS list, starting up handler... "));
321 if (RunHandler(dn
, NULL
, DOSBase
))
323 D(bug("dn->dn_Task = 0x%p\n", dn
->dn_Task
));
328 RemDosEntry((struct DosList
*)dn
);
332 * TODO: AddDosEntry() can fail in case of duplicate name. In this case it would be useful
333 * to append some suffix. AmigaOS IIRC did the same.
334 * This appears to be needed if you have DH0:. DH1:, etc, on your hard drive, and want to
335 * connect a friend's hard drive which also has partitions with these names.
341 static BPTR
internalBootLock(struct DosLibrary
*DOSBase
, struct ExpansionBase
*ExpansionBase
, struct FileSysResource
*fsr
)
344 struct DeviceNode
*dn
;
350 /* The first BootNode off of the MountList.
351 * The dosboot.resource strap routine will have
352 * made the desired boot node the first in this list.
354 * If this fails to mount, we will fail, which will
355 * cause dos.library to fail to initialize, and
356 * then dosboot.resource will handle checking the
357 * next device in the list.
359 bn
= (struct BootNode
*)GetHead(&ExpansionBase
->MountList
);
360 D(bug("Dos/CliInit: MountList head: 0x%p\n", bn
));
365 dn
= bn
->bn_DeviceNode
;
366 mp
= mountBootNode(dn
, fsr
, DOSBase
);
370 D(bug("Dos/CliInit: %b (%d) appears usable\n", dn
->dn_Name
, bn
->bn_Node
.ln_Pri
));
372 /* Try to find a Lock for 'name:' */
373 name_len
= AROS_BSTR_strlen(dn
->dn_Name
);
374 name
= AllocVec(name_len
+ 2, MEMF_ANY
);
379 /* Make the volume name a volume: name */
380 CopyMem(AROS_BSTR_ADDR(dn
->dn_Name
), name
, name_len
);
381 name
[name_len
+0] = ':';
382 name
[name_len
+1] = 0;
383 D(bug("Dos/CliInit: Attempt to Lock(\"%s\")... ", name
));
385 lock
= Lock(name
, SHARED_LOCK
);
386 D(bug("=> 0x%p\n", BADDR(lock
)));
390 /* If we have a lock, check the per-platform conditional boot code. */
391 if (!__dos_IsBootable(DOSBase
, lock
))
395 err
= ERROR_OBJECT_WRONG_TYPE
; /* Something to more or less reflect "This disk is not bootable" */
407 /* Darn. Not bootable. Try to unmount it. */
408 D(bug("Dos/CliInit: Does not have a bootable filesystem, unmounting...\n"));
410 /* It's acceptable if this fails */
411 dead
= DoPkt(mp
, ACTION_DIE
, 0, 0, 0, 0, 0);
412 D(bug("Dos/CliInit: ACTION_DIE returned %ld\n", dead
));
417 * Handlers usually won't remove their DeviceNoces themselves.
418 * And even if they do (ACTION_DIE is poorly documented), RemDosEntry()
419 * on an already removed entry is safe due to nature of DOS list.
420 * What is really prohibited, it's unloading own seglist. Well, resident
421 * handlers will never do it, they know...
423 RemDosEntry((struct DosList
*)dn
);
426 /* DoPkt() clobbered IoErr() */
436 static void AddBootAssign(CONST_STRPTR path
, CONST_STRPTR assign
, APTR DOSBase
)
439 if (!(lock
= Lock(path
, SHARED_LOCK
)))
440 lock
= Lock("SYS:", SHARED_LOCK
);
442 AssignLock(assign
, lock
);
447 * This is what actually gets the Lock() for SYS:,
448 * sets up the boot assigns, and starts the
451 static long internalBootCliHandler(void)
453 struct ExpansionBase
*ExpansionBase
;
454 struct DosLibrary
*DOSBase
;
455 struct MsgPort
*mp
= &((struct Process
*)FindTask(NULL
))->pr_MsgPort
;
457 struct DosPacket
*dp
;
460 struct BootNode
*bn
, *tmpbn
;
461 struct FileSysResource
*fsr
;
463 /* Ah. A DOS Process context. At last! */
465 dp
= (struct DosPacket
*)(GetMsg(mp
)->mn_Node
.ln_Name
);
467 DOSBase
= (APTR
)OpenLibrary("dos.library", 0);
468 if (DOSBase
== NULL
) {
469 D(bug("Dos/CliInit: Impossible! Where did dos.library go?\n"));
470 Alert(AT_DeadEnd
| AG_OpenLib
| AO_DOSLib
);
473 ExpansionBase
= (APTR
)OpenLibrary("expansion.library", 0);
475 return ERROR_INVALID_RESIDENT_LIBRARY
;
477 /* It's perfectly fine if this fails. */
478 fsr
= OpenResource("FileSystem.resource");
480 /* Find and Lock the proposed boot device */
481 lock
= internalBootLock(DOSBase
, ExpansionBase
, fsr
);
482 D(bug("Dos/CliInit: Proposed SYS: lock is: %p\n", BADDR(lock
)));
487 * We've failed. Inform our parent and exit.
488 * Immediately after we reply the packet, the parent (Boot Task) can expunge DOSBase.
489 * This is why we first cleanup, then use internal_ReplyPkt (DOSBase is considered
491 * Alternatively we could Forbid() before ReplyPkt(), but... Forbid() is so unpolite...
495 CloseLibrary(&ExpansionBase
->LibNode
);
496 CloseLibrary(&DOSBase
->dl_lib
);
498 /* Immediately after ReplyPkt() DOSBase can be freed. So Forbid() until we really quit. */
499 internal_ReplyPkt(dp
, mp
, DOSFALSE
, err
);
503 /* Ok, at this point we've succeeded. Inform our parent. */
504 ReplyPkt(dp
, DOSTRUE
, 0);
506 /* We're now at the point of no return. */
507 DOSBase
->dl_Root
->rn_BootProc
= ((struct FileLock
*)BADDR(lock
))->fl_Task
;
508 SetFileSysTask(DOSBase
->dl_Root
->rn_BootProc
);
510 AssignLock("SYS", lock
);
511 lock
= Lock("SYS:", SHARED_LOCK
);
514 D(bug("DOS/CliInit: Impossible! The SYS: assign failed!\n"));
515 Alert(AT_DeadEnd
| AG_BadParm
| AN_DOSLib
);
518 AddBootAssign("SYS:C", "C", DOSBase
);
519 AddBootAssign("SYS:Libs", "LIBS", DOSBase
);
520 AddBootAssign("SYS:Devs", "DEVS", DOSBase
);
521 AddBootAssign("SYS:L", "L", DOSBase
);
522 AddBootAssign("SYS:S", "S", DOSBase
);
523 AddBootAssign("SYS:Fonts", "FONTS", DOSBase
);
526 /* Let hidds in DRIVERS: directory be found by OpenLibrary */
527 if ((lock
= Lock("DEVS:Drivers", SHARED_LOCK
)) != BNULL
) {
528 AssignLock("DRIVERS", lock
);
529 AssignAdd("LIBS", lock
);
532 * This early assignment prevents Poseidon from asking for ENV:
533 * when popup GUI process is initialized and opens muimaster.library.
534 * On m68k this harms, Workbench 1.x disks fail to boot correctly with
535 * "Can't cancel ENV:" warning.
536 * FIXME: Fix muimaster.library at last, and forget this hack.
538 AssignLate("ENV", "SYS:Prefs/Env-Archive");
540 AssignLate("ENVARC", "SYS:Prefs/Env-Archive");
543 * At this point we have only SYS:, nothing more. Mount the rest.
544 * We do it after assigning SYS: because in some cases we can have
545 * BootNodes with handler name but no seglist (Poseidon could add them for example).
546 * This means the handler needs to be loaded from disk (fat-handler for example).
547 * Here we can already do it.
549 D(bug("Dos/CliInit: Assigns done, mount remaining handlers...\n"));
551 BootFlags
= ExpansionBase
->eb_BootFlags
;
552 Flags
= ExpansionBase
->Flags
;
553 D(bug("Dos/CliInit: BootFlags 0x%x Flags 0x%x\n", BootFlags
, Flags
));
555 ForeachNodeSafe(&ExpansionBase
->MountList
, bn
, tmpbn
)
558 * Don't check for return code. Failed is failed.
559 * One of failure reasons can be missing handler specification for some DOSType.
560 * In this case the DeviceNode will not be mounted, but it will stay in
561 * ExpansionBase->MountList. It can be picked up by disk-based program which would
562 * read mappings for disk-based handlers from file.
563 * This way we could automount e. g. FAT, NTFS, EXT3/2, whatever else, partitions.
565 mountBootNode(bn
->bn_DeviceNode
, fsr
, DOSBase
);
568 CloseLibrary((APTR
)ExpansionBase
);
570 /* Init all the RTF_AFTERDOS code, since we now have SYS:, the dos devices, and all the other assigns */
571 D(bug("Dos/CliInit: Calling InitCode(RTF_AFTERDOS, 0)\n"));
572 InitCode(RTF_AFTERDOS
, 0);
574 /* Call the platform-overridable portions */
575 D(bug("Dos/CliInit: Calling __dos_Boot(%p, 0x%x, 0x%x)\n", DOSBase
, BootFlags
, Flags
));
576 __dos_Boot(DOSBase
, BootFlags
, Flags
);
578 D(bug("Dos/CliInit: Boot sequence exited\n"));
579 CloseLibrary((APTR
)DOSBase
);