2 Copyright © 2010, The AROS Development Team. All rights reserved.
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"
23 extern void BCPL_dummy(void);
24 #define BCPL(id, name) extern void BCPL_##name(void);
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
] = {
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
)
49 D(bug("BCPL_InstallSeg: Empty segment\n"));
53 if (seg
== (ULONG
)-1) {
54 ULONG slots
= globvec
[0];
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
];
71 D(bug("BCPL_InstallSeg: Inserting DOSBase global\n"));
72 globvec
[GV_DOSBase
>> 2] = (IPTR
)OpenLibrary("dos.library",0);
77 if (seg
== (ULONG
)-2) {
82 if ((segment
[-1] < segment
[1])) {
83 D(bug("BCPL_InstallSeg: segList @%p does not look like BCPL.\n", segment
));
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]);
101 /* Create the global vector for a process
103 BOOL
BCPL_AllocGlobVec(struct Process
*me
)
107 ULONG
*seglist
= BADDR(me
->pr_SegList
);
109 globvec
= AllocMem(sizeof(BCPL_GlobVec
), MEMF_ANY
| MEMF_CLEAR
);
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 me
->pr_GlobVec
= globvec
;
126 void BCPL_FreeGlobVec(struct Process
*me
)
128 APTR globvec
= me
->pr_GlobVec
;
129 struct DosLibrary
*DOSBase
;
131 DOSBase
= *(APTR
*)(globvec
+ GV_DOSBase
);
132 D(bug("[BCPL_FreeGlobVec] Freed globvec %p\n", globvec
));
134 globvec
-= BCPL_GlobVec_NegSize
;
135 FreeMem(globvec
, sizeof(BCPL_GlobVec
));
137 me
->pr_GlobVec
= DOSBase
->dl_GV
;
140 void BCPL_Fixup(struct Process
*me
)
142 BPTR
*segment
= BADDR(me
->pr_SegList
);
144 if (segment
[2] == (BPTR
)0x0000abcd) {
145 D(bug("[BCPL_Fixup] Fixing up overlay\n"));
147 /* overlayed executable, fun..
149 * 3 = filehandle (BPTR)
150 * 4 = overlay table (APTR)
151 * 5 = hunk table (BPTR)
152 * 6 = global vector (APTR)
154 segment
[6] = (ULONG
)me
->pr_GlobVec
;
158 extern void BCPL_thunk(void);
160 /* Under AOS, BCPL handlers expect the OS to build
161 * their GlobalVector, and to receive a pointer to their
162 * startup packet in D1.
164 * Both filesystem handlers and CLI shells use this routine.
166 * The 'Shell' shell is C based, and does not go here.
168 * This wrapper is here to support that.
170 ULONG
BCPL_RunHandler(void)
172 struct DosPacket
*dp
;
173 struct Process
*me
= (struct Process
*)FindTask(NULL
);
177 WaitPort(&me
->pr_MsgPort
);
178 dp
= (struct DosPacket
*)(GetMsg(&me
->pr_MsgPort
)->mn_Node
.ln_Name
);
179 D(bug("[RunHandlerBCPL] Startup packet = %p\n", dp
));
181 if (!BCPL_AllocGlobVec(me
)) {
183 internal_ReplyPkt(dp
, &me
->pr_MsgPort
, DOSFALSE
, ERROR_NO_FREE_STORE
);
184 return ERROR_NO_FREE_STORE
;
187 D(bug("[RunHandlerBCPL] BCPL_ENTRY = %p\n", BCPL_ENTRY(me
)));
189 oldReturnAddr
= me
->pr_ReturnAddr
;
190 ret
= AROS_UFC8(ULONG
, BCPL_thunk
,
191 AROS_UFCA(ULONG
, MKBADDR(dp
), D1
),
192 AROS_UFCA(ULONG
, 0, D2
),
193 AROS_UFCA(ULONG
, 0, D3
),
194 AROS_UFCA(ULONG
, 0, D4
),
195 AROS_UFCA(APTR
, me
->pr_Task
.tc_SPLower
, A1
),
196 AROS_UFCA(APTR
, me
->pr_GlobVec
, A2
),
197 AROS_UFCA(APTR
, &me
->pr_ReturnAddr
, A3
),
198 AROS_UFCA(LONG_FUNC
, BCPL_ENTRY(me
), A4
));
199 me
->pr_ReturnAddr
= oldReturnAddr
;
201 BCPL_FreeGlobVec(me
);
206 /* Create the necessary process wrappings for a BCPL
207 * segment. Only needed by Workbench's C:Run, C:NewCLI,
208 * C:NewShell, and a few other applications.
210 struct MsgPort
*BCPL_CreateProcBCPL(struct DosLibrary
*DOSBase
, CONST_STRPTR name
, BPTR
*segarray
, ULONG stacksize
, LONG pri
)
212 struct Process
*proc
, *me
= (struct Process
*)FindTask(NULL
);
214 D(bug("[BCPL_CreateProcBCPL] Window=%p name=\"%s\", segArray=%p, stacksize=%u, pri=%d\n", me
->pr_WindowPtr
, name
, segarray
, stacksize
, pri
));
216 proc
= CreateNewProcTags(
218 NP_Entry
, BCPL_RunHandler
,
222 NP_CloseInput
, FALSE
,
223 NP_CloseOutput
, FALSE
,
224 NP_CloseError
, FALSE
,
225 NP_StackSize
, stacksize
,
226 NP_WindowPtr
, me
->pr_WindowPtr
,
232 /* Fix up the segarray before the first packet gets
238 oldsegarray
= BADDR(proc
->pr_SegList
);
239 if (oldsegarray
[0] < segarray
[0]) {
240 FreeVec(oldsegarray
);
241 oldsegarray
= AllocVec(sizeof(BPTR
)*(segarray
[0]+1), MEMF_PUBLIC
| MEMF_CLEAR
);
242 oldsegarray
[0] = segarray
[0];
243 oldsegarray
[1] = (BPTR
)-1;
244 oldsegarray
[2] = (BPTR
)-2;
246 CopyMem(&segarray
[3], &oldsegarray
[3], (oldsegarray
[0]-2)*sizeof(BPTR
));
250 return proc
? &proc
->pr_MsgPort
: NULL
;
253 void bcpl_command_name(void)
255 struct Process
*me
= (struct Process
*)FindTask(NULL
);
256 struct CommandLineInterface
*cli
= BADDR(me
->pr_CLI
);
258 if (cli
== NULL
|| cli
->cli_Module
== BNULL
)
259 bug("%s: ", me
->pr_Task
.tc_Node
.ln_Name
);
261 bug("%b: ", cli
->cli_CommandName
);