Shell: Better AOS 1.3 shell support
[AROS.git] / arch / m68k-all / dos / bcpl_support.c
blob2421d424fd241fd4497b731ff16841851efb582d
1 /*
2 Copyright © 2010, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: BCPL support
6 Lang: english
7 */
8 #define DEBUG 0
9 #include <aros/debug.h>
10 #include <aros/asmcall.h>
12 #include <dos/dosextens.h>
13 #include <dos/filehandler.h>
14 #include <dos/dostags.h>
16 #include <proto/dos.h>
17 #include <proto/exec.h>
19 #include "dos_intern.h"
20 #include "bcpl.h"
22 /* Externs */
23 extern void BCPL_dummy(void);
24 #define BCPL(id, name) extern void BCPL_##name(void);
25 #include "bcpl.inc"
26 #undef BCPL
28 #define BCPL_SlotCount (BCPL_GlobVec_PosSize>>2)
30 /* Default Global Vector */
31 #define BCPL(id, name) \
32 [(BCPL_GlobVec_NegSize + id)>>2] = (ULONG)BCPL_##name,
34 const ULONG BCPL_GlobVec[BCPL_GlobVec_NegSize + BCPL_GlobVec_PosSize] = {
35 #include "bcpl.inc"
37 #undef BCPL
39 #define BCPL_ENTRY(proc) (((APTR *)(proc)->pr_GlobVec)[1])
41 * Set up the process's initial global vector
43 ULONG BCPL_InstallSeg(BPTR seg, ULONG *globvec)
45 ULONG *segment;
46 ULONG *table;
48 if (seg == BNULL) {
49 D(bug("BCPL_InstallSeg: Empty segment\n"));
50 return DOSTRUE;
53 if (seg == (ULONG)-1) {
54 ULONG slots = globvec[0];
55 int i;
56 if (slots > (BCPL_GlobVec_PosSize>>2))
57 slots = (BCPL_GlobVec_PosSize>>2);
58 D(bug("BCPL_InstallSeg: Inserting %d Faux system entries.\n", slots));
60 /* Copy over the negative entries from the default global vector */
61 CopyMem(&BCPL_GlobVec[0], &globvec[-(BCPL_GlobVec_NegSize>>2)], BCPL_GlobVec_NegSize);
63 for (i = 2; i < slots; i++) {
64 ULONG gv = BCPL_GlobVec[(BCPL_GlobVec_NegSize>>2) + i];
65 if (gv == 0)
66 continue;
68 globvec[i] = gv;
71 D(bug("BCPL_InstallSeg: Inserting DOSBase global\n"));
72 globvec[GV_DOSBase >> 2] = (IPTR)OpenLibrary("dos.library",0);
74 return DOSTRUE;
77 if (seg == (ULONG)-2) {
78 return DOSTRUE;
81 segment = BADDR(seg);
82 if ((segment[-1] < segment[1])) {
83 D(bug("BCPL_InstallSeg: segList @%p does not look like BCPL.\n", segment));
84 Alert(AN_BadOverlay);
87 D(bug("BCPL_InstallSeg: SegList @%p\n", segment));
88 table = &segment[segment[1]];
90 D(bug("\tFill in for %p:\n", segment));
92 for (; table[-1] != 0; table = &table[-2]) {
93 D(bug("\t globvec[%d] = %p\n", table[-2], (APTR)&segment[1] + table[-1]));
94 globvec[table[-2]] = (ULONG)((APTR)&segment[1] + table[-1]);
97 return DOSTRUE;
101 /* Create the global vector for a process
103 BOOL BCPL_AllocGlobVec(struct Process *me)
105 APTR entry, globvec;
106 int i;
107 ULONG *seglist = BADDR(me->pr_SegList);
109 globvec = AllocMem(sizeof(BCPL_GlobVec), MEMF_ANY | MEMF_CLEAR);
110 if (globvec == NULL)
111 return FALSE;
113 globvec += BCPL_GlobVec_NegSize;
114 ((ULONG *)globvec)[0] = BCPL_GlobVec_PosSize >> 2;
116 /* Install the segments into the Global Vector */
117 for (i = 0; i < seglist[0]; i++) {
118 BCPL_InstallSeg(seglist[i+1], globvec);
121 entry = ((APTR *)globvec)[1];
123 me->pr_GlobVec = globvec;
125 return TRUE;
128 void BCPL_FreeGlobVec(struct Process *me)
130 APTR globvec = me->pr_GlobVec;
131 struct DosLibrary *DOSBase;
133 DOSBase = *(APTR *)(globvec + GV_DOSBase);
134 D(bug("[BCPL_FreeGlobVec] Freed globvec %p\n", globvec));
136 globvec -= BCPL_GlobVec_NegSize;
137 FreeMem(globvec, sizeof(BCPL_GlobVec));
139 me->pr_GlobVec = DOSBase->dl_GV;
142 void BCPL_Fixup(struct Process *me)
144 BPTR *segment = BADDR(me->pr_SegList);
146 if (segment[2] == (BPTR)0x0000abcd) {
147 D(bug("[BCPL_Fixup] Fixing up overlay\n"));
149 /* overlayed executable, fun..
150 * 2 = id
151 * 3 = filehandle (BPTR)
152 * 4 = overlay table (APTR)
153 * 5 = hunk table (BPTR)
154 * 6 = global vector (APTR)
156 segment[6] = (ULONG)me->pr_GlobVec;
160 extern void BCPL_thunk(void);
162 /* Under AOS, BCPL handlers expect the OS to build
163 * their GlobalVector, and to receive a pointer to their
164 * startup packet in D1.
166 * Both filesystem handlers and CLI shells use this routine.
168 * The 'Shell' shell is C based, and does not go here.
170 * This wrapper is here to support that.
172 ULONG BCPL_RunHandler(void)
174 struct DosPacket *dp;
175 struct Process *me = (struct Process *)FindTask(NULL);
176 APTR oldGlobVec;
177 APTR oldReturnAddr;
178 ULONG ret;
180 WaitPort(&me->pr_MsgPort);
181 dp = (struct DosPacket *)(GetMsg(&me->pr_MsgPort)->mn_Node.ln_Name);
182 D(bug("[RunHandlerBCPL] Startup packet = %p\n", dp));
184 if (!BCPL_AllocGlobVec(me)) {
185 if (dp != NULL)
186 internal_ReplyPkt(dp, &me->pr_MsgPort, DOSFALSE, ERROR_NO_FREE_STORE);
187 return ERROR_NO_FREE_STORE;
190 D(bug("[RunHandlerBCPL] BCPL_ENTRY = %p\n", BCPL_ENTRY(me)));
192 oldReturnAddr = me->pr_ReturnAddr;
193 ret = AROS_UFC8(ULONG, BCPL_thunk,
194 AROS_UFCA(ULONG, MKBADDR(dp), D1),
195 AROS_UFCA(ULONG, 0, D2),
196 AROS_UFCA(ULONG, 0, D3),
197 AROS_UFCA(ULONG, 0, D4),
198 AROS_UFCA(APTR, me->pr_Task.tc_SPLower, A1),
199 AROS_UFCA(APTR, me->pr_GlobVec, A2),
200 AROS_UFCA(APTR, &me->pr_ReturnAddr, A3),
201 AROS_UFCA(LONG_FUNC, BCPL_ENTRY(me), A4));
202 me->pr_ReturnAddr = oldReturnAddr;
204 BCPL_FreeGlobVec(me);
205 oldGlobVec = me->pr_GlobVec;
207 return ret;
210 /* Create the necessary process wrappings for a BCPL
211 * segment. Only needed by Workbench's C:Run, C:NewCLI,
212 * C:NewShell, and a few other applications.
214 struct MsgPort *BCPL_CreateProcBCPL(struct DosLibrary *DOSBase, CONST_STRPTR name, BPTR *segarray, ULONG stacksize, LONG pri)
216 struct Process *proc, *me = (struct Process *)FindTask(NULL);
218 D(bug("[BCPL_CreateProcBCPL] Window=%p name=\"%s\", segArray=%p, stacksize=%u, pri=%d\n", me->pr_WindowPtr, name, segarray, stacksize, pri));
220 proc = CreateNewProcTags(
221 NP_Name, name,
222 NP_Entry, BCPL_RunHandler,
223 NP_Input, BNULL,
224 NP_Output, BNULL,
225 NP_Error, BNULL,
226 NP_CloseInput, FALSE,
227 NP_CloseOutput, FALSE,
228 NP_CloseError, FALSE,
229 NP_StackSize, stacksize,
230 NP_WindowPtr, me->pr_WindowPtr,
231 NP_CurrentDir, 0,
232 NP_Cli, TRUE,
233 NP_HomeDir, 0,
234 TAG_END);
236 /* Fix up the segarray before the first packet gets
237 * to it.
239 if (proc) {
240 BPTR *oldsegarray;
242 oldsegarray = BADDR(proc->pr_SegList);
243 if (oldsegarray[0] < segarray[0]) {
244 FreeVec(oldsegarray);
245 oldsegarray = AllocVec(sizeof(BPTR)*(segarray[0]+1), MEMF_PUBLIC | MEMF_CLEAR);
246 oldsegarray[0] = segarray[0];
247 oldsegarray[1] = (BPTR)-1;
248 oldsegarray[2] = (BPTR)-2;
250 CopyMem(&segarray[3], &oldsegarray[3], (oldsegarray[0]-2)*sizeof(BPTR));
254 return proc ? &proc->pr_MsgPort : NULL;
257 void bcpl_command_name(void)
259 struct Process *me = (struct Process *)FindTask(NULL);
260 struct CommandLineInterface *cli = BADDR(me->pr_CLI);
262 if (cli == NULL || cli->cli_Module == BNULL)
263 bug("%s: ", me->pr_Task.tc_Node.ln_Name);
264 else
265 bug("%b: ", cli->cli_CommandName);