1074
|
1 <article>
|
|
2 <articleinfo>
|
|
3 <title>OS-9 System Extension Modules</title>
|
|
4 <author><firstname>Boisy</firstname>
|
|
5 <othername role="mi">G</othername>
|
|
6 <surname>Pitre</surname>
|
|
7 </author>
|
|
8 </articleinfo>
|
|
9 <para>
|
|
10 The technical information, especially in the OS-9 Level Two manuals,
|
|
11 is brimming with details and information that can unlock a wealth
|
|
12 of understanding about how OS-9 works. Unfortunately, some of this
|
|
13 information can be hard to digest without proper background and some
|
|
14 help along the way. This series of articles is intended to take a
|
|
15 close look at the internals of OS-9/6809, both Level One and Level Two.
|
|
16 So along with this article, grab your OS-9 Technical Manual, sit down
|
|
17 in a comfortable chair or recliner, grab a beverage, relax and let's
|
|
18 delve into the deep waters!
|
|
19 </para>
|
|
20 <section><title>Assemble Your Gear</title>
|
|
21 <para>
|
|
22 For successful comprehension of the topics presented
|
|
23 in this and future articles, I recommend that you have the following
|
|
24 items handy:
|
|
25 </para>
|
|
26 <itemizedlist>
|
|
27 <listitem><para>
|
|
28 OS-9 Level Two Technical Reference Manual <emphasis>or</emphasis>
|
|
29 </para></listitem>
|
|
30 <listitem><para>
|
|
31 OS-9 Level One Technical Information Manual (light blue book) and the
|
|
32 OS-9 Addendum Upgrade to Version 02.00.00 Manual
|
|
33 </para></listitem>
|
|
34 <listitem><para>
|
|
35 A printout of the <literal>os9defs</literal> file for your respective operating system.
|
|
36 This file can be found
|
|
37 in the DEFS directory of the OS-9 Level One Version 02.00.00
|
|
38 System Master (OS-9 Level One) or the DEFS directory of
|
|
39 the OS-9 Development System (OS-9 Level Two).
|
|
40 </para></listitem>
|
|
41 </itemizedlist>
|
|
42 <para>
|
|
43 In this article, we will look at a rarely explored, yet intriguing OS-9
|
|
44 topic: system extensions, a.k.a. P2 modules. When performing an <literal>mdir</literal>
|
|
45 command, you have no doubt seen modules with names like <literal>OS9p1</literal> and <literal>OS9p2</literal>
|
|
46 in OS-9 Level Two (or <literal>OS9</literal> and <literal>OS9p2</literal> in OS-9 Level One). These modules
|
|
47 are essentially the OS-9 operating system itself; they contain the
|
|
48 code for the system calls that are documented in the OS-9 Technical
|
|
49 Reference documentation. In the case of OS-9 Level One, the modules <literal>OS9</literal>
|
|
50 and <literal>OS9p2</literal> are located in the boot track of your boot disk (track 34).
|
|
51 In OS-9 Level Two, <literal>OS9p1</literal> (equivalent to the <literal>OS9</literal> module in Level One) is
|
|
52 found in the boot track while <literal>OS9p2</literal> is located in the bootfile. Both of
|
|
53 the modules are of module type <literal>Systm</literal> and define the basic behavior
|
|
54 and structure of OS-9. Even the module IOMan is a system extension,
|
|
55 containing code for the I/O calls in the operating system.
|
|
56 </para><para>
|
|
57 While drivers and file managers have been the most common area to expand
|
|
58 the capabilities of OS-9, they are pretty much limited to expanding the
|
|
59 functionality of I/O. What system extensions allow you to do is even more
|
|
60 powerful: they can add new system calls or even replace existing ones.
|
|
61 Such functionality allows you to change the behavior of OS-9 in a very
|
|
62 fundamental way. Of course, with such power, caution must be exercised.
|
|
63 It is not wise to radically modify the behavior of an existing system
|
|
64 call; such an action could break compatibility with existing applications.
|
|
65 </para><para>
|
|
66 What we aim to do in this article is not to replace an existing system
|
|
67 call, but rather to add a new system call by looking at the example
|
|
68 provided in Tandy's OS-9 Level Two documentation. Although the example
|
|
69 is written for OS-9 Level Two, we will look at how it can be changed
|
|
70 to run under OS-9 Level One as well. But first, let's get a little
|
|
71 background on system calls and how they are constructed in OS-9.
|
|
72 </para>
|
|
73 </section>
|
|
74 <section><title>The System Call</title>
|
|
75 <para>
|
|
76 As an operating system, OS-9 provides system level
|
|
77 functions, or system calls to applications. These system calls give
|
|
78 applications a base by which they can operate consistently and without
|
|
79 fear of incompatibility from one OS-9 system to the next. The system
|
|
80 call in OS-9/6809 evaluates to an SWI2 instruction on the 6809, which
|
|
81 is a software interrupt. Suffice it to say that when this instruction
|
|
82 is encountered by the CPU, control is routed to OS-9, which interprets
|
|
83 and performs the system call on behalf of the calling process.
|
|
84 </para><para>
|
|
85 While system calls are generally hidden by wrapper functions or procedures
|
|
86 in high-level languages such as Basic09 and C, we can see the system call
|
|
87 in its native form by looking at 6809 assembly language. Consider the
|
|
88 following assembly source fragment:
|
|
89 </para>
|
|
90 <programlisting>
|
|
91 lda #1
|
|
92 leax mess,pcr
|
|
93 ldy #5
|
|
94 os9 I$Write
|
|
95 rts
|
|
96 mess fcc "Hello"
|
|
97 </programlisting>
|
|
98 <para>
|
|
99 In the middle of what appears to be normal 6809 assembly language
|
|
100 source code is a mnemonic called <literal>os9</literal>. This is a pseudo mnemonic, since
|
|
101 Motorola did not place an <literal>os9</literal> instruction in the 6809 instruction set.
|
|
102 The OS-9 assembler actually recognizes this pseudo mnemonic as a special
|
|
103 case, along with the <literal>I$Write</literal> string, and translates the above piece of
|
|
104 code into:
|
|
105 </para>
|
|
106 <programlisting>
|
|
107 lda #1
|
|
108 leax mess,pcr
|
|
109 ldy #5
|
|
110 swi2
|
|
111 fcb $8A
|
|
112 rts
|
|
113 mess fcc "Hello"
|
|
114 </programlisting>
|
|
115 <para>
|
|
116 The $8A which follows the <literal>swi2</literal> instruction is the constant representation
|
|
117 of the I/O system call <literal>I$Write</literal>. Since the <literal>swi2</literal> instruction calls into
|
|
118 the OS-9 kernel, the code in the kernel looks for the byte following
|
|
119 the <literal>swi2</literal> instruction in the module (the $8A) and interprets that as
|
|
120 the system call code. Using that code, OS-9 jumps to the appropriate
|
|
121 routine in order to execute the <literal>I$Write</literal>.
|
|
122 </para><para>
|
|
123 Since the system call code following the swi2 instruction is a byte,
|
|
124 in theory this would allow OS-9 to have up to 256 different system calls
|
|
125 that can be executed on behalf of an application. Under OS-9 Level Two,
|
|
126 this is the case; however under OS-9 Level One there are restrictions
|
|
127 placed on exactly which codes are available. The following tables show
|
|
128 the range of system call codes.
|
|
129 </para>
|
|
130 <table frame="all">
|
|
131 <title>OS-9 Level One System Call Ranges</title>
|
|
132 <tgroup cols="2">
|
|
133 <thead>
|
|
134 <row>
|
|
135 <entry>System call range</entry>
|
|
136 <entry>Function</entry>
|
|
137 </row>
|
|
138 </thead>
|
|
139 <tbody>
|
|
140 <row>
|
|
141 <entry>$00-$27</entry>
|
|
142 <entry>User mode system call codes</entry>
|
|
143 </row>
|
|
144 <row>
|
|
145 <entry>$29-$34</entry>
|
|
146 <entry>Privileged system mode call codes</entry>
|
|
147 </row>
|
|
148 <row>
|
|
149 <entry>$80-$8F</entry>
|
|
150 <entry>I/O system call codes</entry>
|
|
151 </row>
|
|
152 </tbody>
|
|
153 </tgroup>
|
|
154 </table>
|
|
155
|
|
156 <table frame="all">
|
|
157 <title>OS-9 Level Two System Call Ranges</title>
|
|
158 <tgroup cols="2">
|
|
159 <thead>
|
|
160 <row>
|
|
161 <entry>System call range</entry>
|
|
162 <entry>Function</entry>
|
|
163 </row>
|
|
164 </thead>
|
|
165 <tbody>
|
|
166 <row>
|
|
167 <entry>$00-$7F</entry>
|
|
168 <entry>User mode system call codes</entry>
|
|
169 </row>
|
|
170 <row>
|
|
171 <entry>$80-$8F</entry>
|
|
172 <entry>I/O system call codes</entry>
|
|
173 </row>
|
|
174 <row>
|
|
175 <entry>$90-$FF</entry>
|
|
176 <entry>Privileged mode system call codes</entry>
|
|
177 </row>
|
|
178 </tbody>
|
|
179 </tgroup>
|
|
180 </table>
|
|
181 <para>
|
|
182 The idea behind <emphasis>User mode</emphasis> vs. <emphasis>System mode</emphasis>
|
|
183 is to allow two different points
|
|
184 of execution for the same system call, depending on whether the calling
|
|
185 process is running in user state or system state. OS-9 controls this
|
|
186 by maintaining two system call tables: one for user state and one for
|
|
187 system state. When installing a system call, as we'll soon see, we can
|
|
188 specify whether our system call should only be called from system state
|
|
189 (hence only updating the system table) or from both user and system state
|
|
190 (updating both the user and system tables).
|
|
191 </para><para>
|
|
192 An example of a system call that can be executed in both user and
|
|
193 privileged modes is the <literal>F$Load</literal> function code (pp. 8-25 in the OS-9 Level
|
|
194 Two Technical Reference manual; pp. 106 in the OS-9 Level
|
|
195 One Technical Information manual). Since <literal>F$Load</literal> can be called from a user
|
|
196 state process as well as from a driver or other module running in system
|
|
197 state, OS-9 installs this system call in both the user and system tables.
|
|
198 On the other hand, a privileged mode system call such as <literal>F$AProc</literal> (Level
|
|
199 Two: pp. 8-74; Level One: pp. 141) can only be called from system state
|
|
200 and therefore a user state process attempting to call it will receive
|
|
201 an error.
|
|
202 </para><para>
|
|
203 Notice that in both OS-9 Level One and OS-9 Level Two, codes $80-$8F are
|
|
204 reserved for I/O system call codes. When the OS-9 kernel receives one of
|
|
205 these codes, it passes the code along to <literal>IOMan</literal> for processing. I/O system
|
|
206 calls cannot be added since they are under the control of <literal>IOMan</literal>.
|
|
207 </para><para>
|
|
208 Installing a new system call involves selecting a free system call code,
|
|
209 determining whether the call will be accessible from both user/system
|
|
210 state or from system state only, and building a table in assembly language
|
|
211 that will be used to install the system call. Interestingly enough,
|
|
212 the method of installing a system call is by calling a system call!
|
|
213 It's called <literal>F$SSvc</literal> and is documented in your respective OS-9 Technical
|
|
214 manual.
|
|
215 </para>
|
|
216 </section>
|
|
217 <section>
|
|
218 <title>Installing a System Call in OS-9 Level Two</title>
|
|
219 <para>
|
|
220 The source code in Listing
|
|
221 1 is the system extension module, os9p3.a, which contains the code
|
|
222 to install the system call, as well as the system call code itself.
|
|
223 Incidentally, this is virtually the same code that is found in the OS-9
|
|
224 Level Two Technical Reference Manual on pp. 2-2 to 2-4. I've eliminated
|
|
225 the comments for brevity since they are already in your manual, as well
|
|
226 as changed the <literal>use</literal> directive. Instead of including <literal>/dd/defs/os9defs</literal>, I
|
|
227 include <literal>/dd/defs/os9defs.l2</literal>. The reason for this is that I do compiling
|
|
228 of both OS-9 Level One and OS-9 Level Two modules on my CoCo 3 development
|
|
229 system. Since the OS-9 definitions are different for each operating
|
|
230 system, I have renamed their respective <literal>os9defs</literal> files with an extension
|
|
231 indicating which operating system they belong to. Even if you just develop
|
|
232 for one operating system or the other, I strongly suggest following the
|
|
233 same naming convention; it will save you headaches in the long run.
|
|
234 </para><para>
|
|
235 This module, called <literal>OS9p3</literal>, installs the <literal>F$SAYHI</literal> system call. A process
|
|
236 making this call can either pass a pointer to a string of up to 40 bytes
|
|
237 (carriage return terminated) in register X, or set X to 0, in which case
|
|
238 the system call will print a default message. In either case, the message
|
|
239 goes to the calling process' standard error path. While not very useful,
|
|
240 this system call is a good example of how to write a system extension.
|
|
241 </para><para>
|
|
242 The asm program is used to assemble this source code file. Notice that
|
|
243 the entry point for the module is the label <literal>Cold</literal>, where Y is set to the
|
|
244 address of the service table, <literal>SvcTbl</literal>. Each entry in this table contains
|
|
245 three bytes. The first is the system call code that we have selected
|
|
246 from a range that Microware says is safe to use for new system calls,
|
|
247 and the remaining two are the address of the first instruction of the
|
|
248 system call. The table, which can contain any number of entries, is
|
|
249 terminated by byte $80. After setting Y to the address of the service
|
|
250 table, a system call to <literal>F$SSvc</literal> is made, which takes the table pointed
|
|
251 to by Y and installs the system calls.
|
|
252 </para><para>
|
|
253 The code for the <literal>F$SAYHI</literal> system call in listing 1 is for OS-9 Level
|
|
254 Two only. It determines whether or not a valid string pointer has been
|
|
255 passed in register X. If indeed the caller has passed a valid pointer,
|
|
256 then control is routed to the label <literal>SayHi6</literal> where Y is loaded with the
|
|
257 maximum byte count and the process descriptor of the calling process is
|
|
258 used to obtain the system path number of the process' standard error
|
|
259 in register A. The separation of user and system state paths is an
|
|
260 important concept to understand; however, we will discuss it in detail
|
|
261 in another article. For now, let's continue analyzing the code.
|
|
262 </para><para>
|
|
263 The <literal>I$WritLn</literal> system call then prints the string at register X to the
|
|
264 caller's standard error path. If on the other hand, register X contains
|
|
265 a zero, then room is made on the caller's stack for the default message,
|
|
266 which is then copied into the caller's address space using the <literal>F$Move</literal>
|
|
267 system call. The moving of the default message from the system address
|
|
268 space to the caller's address space is necessary due to the separation
|
|
269 of a process' address space in OS-9 Level Two.
|
|
270 </para><para>
|
|
271 Once the module has been compiled, it should be included in your OS-9
|
|
272 Level Two bootfile. Reboot with the new bootfile, and the <literal>OS9p2</literal> module
|
|
273 will find <literal>OS9p3</literal> then jump into the execution offset (the <literal>Cold</literal> label
|
|
274 in this case). This will install the <literal>F$SAYHI</literal> system call and make it
|
|
275 available for programs immediately.
|
|
276 </para>
|
|
277 </section>
|
|
278 <section>
|
|
279 <title>Installing a System Call in OS-9 Level One</title>
|
|
280 <para>
|
|
281 Listing 2 is similar to the
|
|
282 code in Listing 1, except that the code to move the default message
|
|
283 from system space to the caller's address space has been removed. Also,
|
|
284 the code to install the system call has changed, and the module type is
|
|
285 not of type <literal>Systm</literal>, but instead of type <literal>Prgrm</literal>. This is due to the lack
|
|
286 of separation of address space in Level One, which makes writing system
|
|
287 extension modules much easier than in Level Two.
|
|
288 </para><para>
|
|
289 The common address space between the system and all processes in OS-9
|
|
290 Level One also makes the <literal>F$SSvc</literal> system call available from user state
|
|
291 as well as from system state. Unlike OS-9 Level Two, where the system
|
|
292 extension module must be placed in the bootfile, installing a system
|
|
293 extension in OS-9 Level One takes a different approach. Placing a
|
|
294 module called <literal>OS9p3</literal> in an OS-9 Level One bootfile will NOT cause the
|
|
295 system extension to be called because there are no provisions for that
|
|
296 in the kernel. Instead, system extensions are installed by creating a
|
|
297 module of type <literal>Prog</literal> that contains both code to install the system call
|
|
298 and the system call itself. Installing the system call entails executing
|
|
299 the module from the command line.
|
|
300 </para><para>
|
|
301 Besides the <literal>sayhi.a</literal> source in listing 2, another example of the this
|
|
302 is the <literal>Printerr</literal> command that comes with OS-9 Level One. This is a
|
|
303 program that actually installs a newer version of the <literal>F$PErr</literal> system call.
|
|
304 To install the new system call, you simply run <literal>Printerr</literal> from the command
|
|
305 line. It then installs the call and exits. There is an advantage to
|
|
306 OS-9 Level One's approach to installing system calls: it can be done
|
|
307 at run-time without making a new bootfile and rebooting the system.
|
|
308 However, additional care must be taken not to unlink the <literal>Printerr</literal> module
|
|
309 from memory. Why? Because the code for the replacement <literal>F$PErr</literal> call is
|
|
310 in that module, and if the module is unlinked, the memory it occupied
|
|
311 is made available subsequent reallocation and at some point, a system
|
|
312 crash will ensue.
|
|
313 </para>
|
|
314 </section>
|
|
315 <section>
|
|
316 <title>Exercising Our New System Call</title>
|
|
317 <para>
|
|
318 Listing 3 is a small assembly language
|
|
319 program, <literal>tsayhi</literal>, which calls the <literal>F$SAYHI</literal> routine. It will work fine
|
|
320 under both OS-9 Level One and Level Two. If you fork the <literal>tsayhi</literal> program
|
|
321 without any parameters, then the <literal>F$SAYHI</literal> system call is called with
|
|
322 register X set to $0000, which will cause the system call to print the
|
|
323 default message. Otherwise, you can pass a message on the command line
|
|
324 as a parameter and up to 40 of the message's characters will be printed
|
|
325 to the standard error path.
|
|
326 </para>
|
|
327 </section>
|
|
328 <section>
|
|
329 <title>Summary</title>
|
|
330 <para>
|
|
331 Extension modules give us an effective way of altering the
|
|
332 behavior of OS-9 by allowing us to add a new system call or modify the
|
|
333 behavior of an existing one. Writing extension modules requires an
|
|
334 extremely good understanding of the internals of OS-9. The particulars
|
|
335 of writing a system extension vary under OS- 9 Level One and Level Two
|
|
336 primarily due to the differences between memory addressing.
|
|
337 </para>
|
|
338
|
|
339 <example><title>Source for os9p3.a for OS-9 Level Two</title>
|
|
340 <programlisting>
|
|
341 Type set Systm+Objct
|
|
342 Revs set ReEnt+1
|
|
343 mod OS9End, OS9Name,Type,Revs,Cold,256
|
|
344 OS9Name fcs "OS9p3"
|
|
345
|
|
346 fcb 1 edition number
|
|
347
|
|
348 ifp1
|
|
349 use /dd/defs/os9defs.l2
|
|
350 endc
|
|
351
|
|
352 level equ 2
|
|
353 opt -c
|
|
354 opt f
|
|
355
|
|
356 * routine cold
|
|
357 Cold leay SvcTbl,pcr
|
|
358 os9 F$SSvc
|
|
359 rts
|
|
360
|
|
361 F$SAYHI equ $25
|
|
362
|
|
363 SvcTbl equ *
|
|
364 fcb F$SAYHI
|
|
365 fdb SayHi-*-2
|
|
366 fcb $80
|
|
367
|
|
368
|
|
369 SayHi ldx R$X,u
|
|
370 bne SayHi6
|
|
371 ldy D.Proc
|
|
372 ldu P$SP,y
|
|
373 leau -40,u
|
|
374 lda D.SysTsk
|
|
375 ldb P$TASK,y
|
|
376 ldy #40
|
|
377 leax Hello,pcr
|
|
378 os9 F$Move
|
|
379 leax 0,u
|
|
380 SayHi6 ldy #40
|
|
381 ldu D.Proc
|
|
382 lda P$PATH+2,u
|
|
383 os9 I$WritLn
|
|
384 rts
|
|
385
|
|
386 Hello fcc "Hello there user."
|
|
387 fcb $0D
|
|
388
|
|
389 emod
|
|
390
|
|
391 OS9End equ *
|
|
392
|
|
393 end
|
|
394 </programlisting>
|
|
395 </example>
|
|
396 <example><title>Source for sayhi.a for OS-9 Level One</title>
|
|
397 <programlisting>
|
|
398 Type set Prgrm+Objct
|
|
399 Revs set ReEnt+1
|
|
400 mod OS9End, OS9Name,Type,Revs,Cold,256
|
|
401 OS9Name fcs "SayHi"
|
|
402
|
|
403 fcb 1 edition number
|
|
404
|
|
405 ifp1
|
|
406 use /dd/defs/os9defs.l1
|
|
407 endc
|
|
408
|
|
409 level equ 1
|
|
410 opt -c
|
|
411 opt f
|
|
412
|
|
413 * routine cold
|
|
414 Cold equ *
|
|
415 * The following three instructions are important. They cause the link
|
|
416 * count of this module to increase by 1. This insures that the module
|
|
417 * stays in memory, even if forked from disk.
|
|
418 leax OS9Name,pcr
|
|
419 clra
|
|
420 os9 F$Link
|
|
421
|
|
422 leay SvcTbl,pcr
|
|
423 os9 F$SSvc
|
|
424 bcs Exit
|
|
425 clrb
|
|
426 Exit os9 F$Exit
|
|
427
|
|
428 F$SAYHI equ $25
|
|
429
|
|
430 SvcTbl equ *
|
|
431 fcb F$SAYHI
|
|
432 fdb SayHi-*-2
|
|
433 fcb $80
|
|
434
|
|
435 * Entry point to F$SAYHI system call
|
|
436 SayHi ldx R$X,u
|
|
437 bne SayHi6
|
|
438 leax Hello,pcr
|
|
439 SayHi6 ldy #40
|
|
440 ldu D.Proc
|
|
441 lda P$PATH+2,u
|
|
442 os9 I$WritLn
|
|
443 rts
|
|
444
|
|
445 Hello fcc "Hello there user."
|
|
446 fcb $0D
|
|
447
|
|
448 emod
|
|
449 OS9End equ *
|
|
450 end
|
|
451 </programlisting>
|
|
452 </example>
|
|
453 <example><title>Source for tsayhi.a</title>
|
|
454 <programlisting>
|
|
455 Type set Prgrm+Objct
|
|
456 Revs set ReEnt+1
|
|
457 mod OS9End, OS9Name,Type,Revs,start,256
|
|
458 OS9Name fcs "TSayHi"
|
|
459
|
|
460 fcb 1 edition number
|
|
461
|
|
462 ifp1
|
|
463 use /dd/defs/os9defs
|
|
464 endc
|
|
465
|
|
466 level equ 2
|
|
467 opt -c
|
|
468 opt f
|
|
469
|
|
470 F$SAYHI equ $25
|
|
471
|
|
472 * routine cold
|
|
473 start equ *
|
|
474 lda ,x
|
|
475 cmpa #$0D
|
|
476 bne SayHi
|
|
477 ldx #$0000
|
|
478 SayHi os9 F$SAYHI
|
|
479 bcs error
|
|
480 clrb
|
|
481 error os9 F$Exit
|
|
482
|
|
483 emod
|
|
484
|
|
485 OS9End equ *
|
|
486 end
|
|
487 </programlisting>
|
|
488 </example>
|
|
489 </section>
|
|
490 </article>
|