Subversion Repositories shark

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 pj 1
\documentclass[a4paper]{report}
2
\usepackage{epsfig}
3
\usepackage{latexsym}
4
\usepackage[english]{babel}
5
\selectlanguage{english}
6
\textheight=8.4 truein
7
\textwidth=6.1 truein
8
\oddsidemargin=0.2 truein
9
 
10
\newenvironment{proof}
11
        {\vspace{12pt} \noindent {\bf Proof.} \\
12
        \noindent}{$\Box$ \vspace{12pt}}
13
 
14
\title{The OSLib Manual}
15
 
16
\author{Luca Abeni
17
\and
18
        Gerardo Lamastra
19
}
20
 
21
\begin{document}
22
\setlength{\baselineskip}{1.5\baselineskip}
23
\maketitle
24
\begin{abstract}
25
This is the manual of OSLib, a collection of low level functions aimed
26
to help programmers in developing system software, ranging from small
27
programs for embedded systems to complex Operating System
28
kernels. Using OSLib, the system programmer can focus on the software
29
itself, without caring about the interaction with the hardware.  In
30
this sense, OSLib is similar to the Flux OS Toolkit.
31
 
32
From another point of view, OSLib provides an ``easy'' access to the
33
hardware, without introducing any useless abstraction, and can be seen
34
as a generic support layer for any operating system service. In this
35
sense, it is similar to the MIT ExoKernel .  Note that OSLib does not
36
force to use any particular OS structure, but can support any
37
conventional or innovative structure, such as the monolithic one, the
38
microkernel-based one, or the vertical structured one.
39
\end{abstract}
40
 
41
\chapter{Introduction}
42
The OSLib is a collection of routines and data structures developed to
43
help system programmers in implementing an OS or an application that
44
directly accesses the hardware. In this sense it is
45
similar to the Windows NT Hardware Abstraction Layer (HAL), the
46
$\mu$Choices NanoKernel, or the HARTIK Virtual Machine (VM) Layer. On
47
the other hand, the aim of the OSLib is not to abstract the
48
hardware resources (like the cited works do).  In fact, hardware
49
resources abstraction can result in poor efficiency and flexibility,
50
as stated by Engler et others (ExoKernel). The OSLib code, instead of
51
abstracting hardware, provides a secure and easy access to it hiding
52
implementation details (for example, the PIC or PIT programming, or the
53
CPU tables management)
54
and leaving to the OS developers the hi-level and conceptual part of
55
the work.
56
%%%%% RIVEDERE!!!! CHIARIRE UN PO'
57
%%% Add reference to Flux and ExoKernels...
58
% These are the ideas: Flux is too complex (COM... What an orror!!!),
59
% ExoKernel exterminates too much abstractions :) ... And bound to a specific
60
% system structure (vertical structured system)!!!
61
 
62
\section{Library Structure}
63
OSLib is composed of some libraries, that can be compiled using
64
the standard GNU tools (gcc, GNU binutils and GNU make) either under
65
MSDOS or Linux (DJGPP for DOS and
66
gcc for Linux have been successfully tested; gcc for other Unix
67
systems or Cygnus gcc for Windows have not been tested yet, but
68
will probably work too). The resulting GNUCoff or ELF MultiBoot compliant
69
images can be loaded using a custom provided DOS eXtender (X) or
70
using the GNU Grand Unified Boot Loader (GRUB).
71
 
72
The code is organized in three parts: \begin{itemize}
73
\item the hardware support library ({\tt xlib}), used to access the PC
74
        hardware;
75
\item a subset of the OS independent part of the standard C library
76
        ({\tt libc1});
77
\item the Kernel support library ({\tt kl}), that is the component to
78
        use for writing OS code.
79
\end{itemize}
80
 
81
The hardware support library contains the boot code for starting up
82
the system when a MultiBoot compliant loader is used, the code to
83
access hardware structures such as the GDT, IDT, the interrupt
84
controller, the code to detect the CPU, and some data structures
85
containing informations about the system.
86
%%%% ALLUNGARE LA DESCRIZIONE, SPIEGARE BENE... FARE RIFERIMENTO AI FILE .h
87
 
88
The OS independent part of the C library provides all the functions
89
from libc that can be implemented without invoking system calls
90
(typically the string management functions, the memory
91
copy/move/compare, the math functions and similar). An important
92
exception to this rule is represented by the {\tt cprintf} function:
93
it is similar to the standard {\tt printf} function (with the
94
difference that {\tt cprintf} directly writes to the screen), and,
95
since it needs to access the video memory, it depends by the OS (in
96
particular, {\tt cprintf} depends on how the OS remaps the video
97
memory). In any case, since the OS code needs to output some
98
informations for debugging or other purposes, this function is
99
provided by {\tt libc1}. {\tt libc1} does not provide any input
100
function.
101
 
102
The Kernel support library provides: \begin{itemize}
103
\item the code for interrupt/exception handling;
104
\item the code for thread management (thread creation/deletion,
105
        context switch...);
106
\item the code for address space management
107
\item the code for time management
108
\end{itemize}
109
 
110
\section{Compiling and Using}
111
The OSLib code is distributed as source code in a ZIP or tarball
112
archive. The tarball contains the source to be compiled in a Unix
113
system (only  {\tt chr(10)} at the end of each line), while the ZIP
114
archive can be decompressed in MSDOS ({\tt chr(13)+chr(10)}) or Unix
115
source using the -a option of UNZIP.
116
 
117
In order to decompress the source tree, use {\tt tar -xvzf llxxx.tgz}
118
or {\tt unzip -La llxxx.zip}; this command will create the tree shown in
119
Figure \ref{fig:tree}.
120
 
121
\begin{figure}
122
%\begin{minipage}[t]{10cm}
123
\begin{tt}
124
\begin{tabbing}
125
oslib--\=------ll--\=------i386         \\
126
\>      | \>            |                       \\
127
\>      | \>            |                       \\
128
\>      |---lib \>      |----sys----ll          \\
129
\>      |                                       \\
130
\>      |---xlib \>                             \\
131
\>      | \>                                    \\
132
\>      |---libc \>                             \\
133
\>      | \>                                    \\
134
\>      |---libm \>                             \\
135
\>      |                                       \\
136
\>      |---kl                                  \\
137
\>      |                                       \\
138
\>      |---examples                            \\
139
\>      |                                       \\
140
\>      |---mk                                  \\
141
\end{tabbing}
142
\end{tt}
143
%\end{minipage}
144
\caption{The OSLib source tree.}
145
\label{fig:tree}
146
\end{figure}
147
 
148
The {\tt ll} directory contains the header files with the
149
definitions of the OSLib structures and the prototypes for the OSLib calls.
150
It is organized in two subdirectories: the {\tt i386} directory,
151
containing the include files for the hardware support library, and
152
the {\tt sys/ll} directory, containing the headers for the OS support
153
library.
154
 
155
The {\tt lib} directory is the place where all the libraries
156
will be put once compiled. Depending on the
157
distribution, the {\tt lib} directory is in the archive or will be
158
created at compilation time by the {\tt make} command.
159
 
160
The {\tt xlib} directory contains the sources for the hardware
161
support  library; the {\tt libm} directory is used to compile a
162
modified version of the FreeBSD math library provided with OSLib; the
163
{\tt libc} directory contains the sources for the minimal C library,
164
while the {\tt kl} directory is the place where the Kernel support library
165
source code resides.
166
 
167
The {\tt examples} directory contains some examples
168
showing how to use all the functionalities provided by OSLib.
169
 
170
The {\tt mk} library contains some configuration files, used to
171
compile the libraries in different host OSs: currently, the files
172
to compile under MDSOS (using DJGPP V1 \& V2) and the file to compile
173
under Linux are provided. Moreover, a file to compile the H4 (S.Ha.R.K.)
174
kernel is provided.
175
 
176
In order to compile the system, proceed as follows
177
\begin{itemize}
178
        \item Configure the compiling system, installing the
179
                correct configuration file: copy the correct {\tt mk/*.mk}
180
                file in {\tt config.mk}
181
        \item make all the libraries, from directories {\tt xlib},
182
                {\tt libc}, {\tt libm}, and {\tt kl}:
183
 
184
                \begin{minipage}[t]{10cm}
185
                \begin{tt}
186
                \begin{tabbing}
187
                cd xlib                                 \\
188
                make install                            \\
189
                cd ..                                   \\
190
                cd libc                                 \\
191
                make install                            \\
192
                cd ..                                   \\
193
                cd libm                                 \\
194
                $\ldots$
195
                \end{tabbing}
196
                \end{tt}
197
                \end{minipage}
198
        \item now the libraries are installed, and you are ready to
199
                use them. In order to test OSLib, you can compile
200
                the programs in the {\tt examples} directory:
201
 
202
                \begin{minipage}[t]{10cm}
203
                \begin{tt}
204
                \begin{tabbing}
205
                cd examples                             \\
206
                make
207
                \end{tabbing}
208
                \end{tt}
209
                \end{minipage}
210
\end{itemize}
211
 
212
A program compiled using the OSLib code can be run using the DOS
213
eXtender, or using GRUB. In order to use the extender, boot MSDOS (or
214
a 16 bit DOS compatible OS, such as FreeDOS), then copy {\tt X.EXE}
215
in the path, and finally use it: {\tt X <program name>} (for example,
216
try {\tt X schedtest.xtn}). Once the program execution is terminated,
217
it will nicely return to DOS.
218
 
219
In order to run a program through GRUB, put it in a GRUB accessible
220
partition, then boot GRUB and enter the command prompt pressing
221
{\tt `c'}. Now, specify the compiled program as a kernel: assuming
222
that you want to run {\tt schedtest.xtn}, residing in the
223
{\tt /oslib/examples} directory on the first partition of your first
224
hard drive, you have to type {\tt kernel=(hd0,0)/oslib/examples/schedtest.xtn}.
225
Finally, you can run the program typing {\tt boot}. Once the program
226
finishes, the system is halted and you must reboot it.
227
 
228
The OSLib code can be used including the adequate headers
229
from the {\tt include} directory, and linking the libraries from the
230
{\tt lib} directory. The compiler and linker options are set in the
231
{\tt config.mk} file: look at the makefile in the {\tt examples} directory
232
to see how to use it. The {\tt examples} directory contains
233
some simple programs to be browsed in order to learn how to use OSLib.
234
 
235
\chapter{The libraries}
236
As said, the OSLib code and data structures are organized in various
237
libraries, in order to increase the modularity and simplify the
238
structure. A description of those libraries and of the header files
239
that have to be included in order to use OSLib follows.
240
 
241
\section{The header files}
242
The {\tt ll} directory contains the header files to be included for
243
using OSLib. In particular, the directory structure tries to reflect
244
the standard POSIX include directory. Hence, the include files of the
245
minimal C library use the POSIX names and are distributed in {\tt ll}
246
and {\tt ll/sys}.
247
 
248
The {\tt xlib} headers are in the {\tt ll/i386} directory; in particular,
249
they are:
250
\begin{itemize}
251
        \item {\tt ll/i386/hw-data.h}: this header defines the basic data
252
                types and constants, and has to be included in order to use
253
                them
254
                %do we need to cite all them?
255
        \item {\tt ll/i386/hw-instr.h}: this header defines the instruction
256
                needed to access hardware registers (or memory locations) as
257
                inlined functions
258
        \item {\tt ll/i386/hw-func.h}: this header has to be included in
259
                order to use the functions that permits to directly access
260
                hardware, such as {\tt halt()} and {\tt reboot()},
261
                {\tt IDT\_place()}, {\tt GDT\_place()}  and
262
                {\tt GDT\_read()}, {\tt addr2linear()}, and the
263
                {\tt ll\_context\_*()} functions. Moreover, it contains the
264
                prototypes of {\tt x\_init()}, {\tt x\_end()},
265
                {\tt x\_exc\_bind()}, and {\tt x\_irq\_bind()}
266
        \item {\tt ll/i386/hw-arch.h}: this header has to be included for
267
                using the CPU/FPU detection functions {\tt X86\_get\_CPU()},
268
                {\tt  X86\_get\_FPU()}, {\tt  X86\_is386()},
269
                {\tt X86\_isCyrix()}, and {\tt X86\_hasCPUID()}
270
        \item {\tt ll/i386/hw-io.h}: this header defines the I/O
271
                instructions as inline functions. It is included by
272
                {\tt ll/i386/hw-instr.h} and must never be directly
273
                included by user programs
274
        \item {\tt ll/i386/tss-ctx.h}: defines some macros for translating
275
                CONTEXTs in TSSs and vice-versa
276
        \item {\tt ll/i386/sel.h}: defines some symbolic names for the
277
                predefined selectors used by the {\tt xlib}
278
        \item {\tt ll/i386/int.h}: defines some macros that simplify
279
                writing interrupt or exception handlers
280
        \item {\tt ll/i386/pit.h}: this header has to be included in order
281
                to access the Programmable Interrupt Timer (PIT) through
282
                {\tt pit\_init()}, {\tt pit\_setconstant()}, and
283
                {\tt pit\_read()}
284
        \item {\tt ll/i386/pic.h}: this header has to be included to
285
                access the Programmable Interrupt Controller (PIC)
286
                through {\tt  PIC\_init()}, {\tt PIC\_end()},
287
                {\tt irq\_mask()}, and {\tt irq\_unmask()}
288
        \item {\tt ll/i386/linkage.h}: this header can be included by
289
                ASM files to generate correct C naming independently from
290
                the architecture/file format
291
        \item {\tt ll/i386/defs.h}: this header defines some macros to be
292
                used to start/end header and C files
293
        \item {\tt ll/i386/farptr.h}: this header contains the far pointer
294
                access from DJGPP
295
        \item {\tt ll/i386/x-bios.h}: this header has to be included to
296
                call real mode functions through {\tt X\_callBIOS()}, or
297
                {\tt vm86\_init()} and {\tt vm86\_callBIOS()}, or to
298
                directly communicate with the eXtender through
299
                {\tt x\_bios\_address()} and {\tt X\_meminfo()}
300
        \item {\tt ll/i386/x-dosmem.h}: this header has to be included in
301
                order to manage real-mode (DOS) memory through
302
                {\tt DOS\_mem\_init()}, {\tt DOS\_alloc()}, and
303
                {\tt DOS\_free()}
304
        \item {\tt ll/i386/x-dos.h}: this header has to be included in
305
                order to access a FAT file system through dos (using the
306
                X-BIOS calls) with {\tt DOS\_fopen()},
307
                {\tt DOS\_fclose()}, {\tt DOS\_fread()},
308
                {\tt DOS\_fwrite()}, and {\tt DOS\_error()}
309
        \item {\tt ll/i386/mb-hdr.h}: this header can be included by ASM
310
                files in order to easily generate a MultiBoot header
311
        \item {\tt ll/i386/mb-info.h}: this header contains the definition
312
                of the MultiBoot Information (MBI) structure.
313
\end{itemize}
314
 
315
%Minimal libc includes...
316
%\item {\tt ll/time.h}:
317
%\item {\tt ll/string.h}:
318
%\item {\tt ll/stdio.h}:
319
%\item {\tt ll/math.h}:
320
%\item {\tt ll/limits.h}:
321
%\item {\tt ll/errno.h}:
322
%\item {\tt ll/assert.h}:
323
%\item {\tt ll/unistd.h}:
324
%\item {\tt ll/stdlib.h}:
325
%\item {\tt ll/stdarg.h}:
326
%\item {\tt ll/ctype.h}:
327
%\item {\tt ll/sys/types.h}:
328
%\item {\tt ll/sys/cdef.h}:
329
%\item {\tt ll/i386/mem.h}:
330
%\item {\tt ll/i386/stdio.h}:
331
%\item {\tt ll/i386/cons.h}:
332
%\item {\tt ll/i386/float.h}:
333
%\item {\tt ll/i386/stdlib.h}:
334
%\item {\tt ll/i386/string.h}:
335
%\item {\tt ll/i386/error.h}:
336
%\item {\tt ll/i386/limits.h}:
337
 
338
The {\tt kl} headers are in the {\tt ll/sys/ll} directory; in particular,
339
they are:
340
\begin{itemize}
341
        \item {\tt ll/sys/ll/ll-func.h}: this header has to be included for
342
                using the {\tt ll\_context\_create()},
343
                {\tt ll\_context\_setspace()}, and {\tt ll\_context\_delete()},
344
                {\tt ll\_init()}, {\tt ll\_end()}, and {\tt ll\_abort()}
345
                {\tt ll\_context\_save()}, {\tt ll\_context\_change()},
346
                {\tt ll\_context\_load()}, {\tt ll\_context\_from()}, and
347
                {\tt ll\_context\_to} functions
348
        \item {\tt ll/sys/ll/event.h}: this header has to be included for
349
                using the event related functions, that are
350
                {\tt event\_init()}, {\tt event\_post()},
351
                {\tt event\_delete()}, {\tt irq\_bind()}, and
352
                {\tt ll\_ActiveInt()}
353
        \item {\tt ll/sys/ll/time.h}: this header has to be included for
354
                using the {\tt gettime()} function. Moreover, it provides
355
                some macros for manipulating timespecs.
356
        \item {\tt ll/sys/ll/event.h}: this header has to be included for
357
                using Address Spaces. In particular, it provides prototypes
358
                and data definitions for the {\tt as\_init()},
359
                {\tt as\_create()}, and {\tt as\_bind()} functions.
360
\end{itemize}
361
 
362
\section{The Hardware Support Library}
363
The Hardware support library provides all the functions and data
364
structures needed to access the hardware. In particular, it provides
365
the code necessary to boot the OSLib application, to manage the CPU
366
and the PC hardware, and to switch to Real Mode calling BIOS functions.
367
 
368
The booting code and data permits to create MultiBoot compliant
369
executables and to interface the application with a MultiBoot compliant
370
boot loader.
371
 
372
The CPU handling code and data permits to identify the CPU type and to
373
manage the CPU tables (GDT and IDT), while the hardware managing code permits
374
to access some specific PC hardware (PIT and PIC).
375
 
376
First of all, some basic data types are defined (in {\tt ll/i386/hw-data.h}):
377
\begin{itemize}
378
        \item {\tt DWORD}: a 32 bit positive number;
379
        \item {\tt WORD}: a 16 bit positive number;
380
        \item {\tt BYTE}: an 8 bit positive number.
381
\end{itemize}
382
For each of these types, a {\tt MAX\_*} constant exists.
383
 
384
Based on the basic types, some important structures are defined:
385
\begin{itemize}
386
        \item {\tt struct gate}: the x86 gate structure;
387
        \item {\tt struct descriptor}: an x86 segment descriptor;
388
        \item {\tt union gdt\_entry}: an x86 GDT entry: can be a
389
                gate or a descriptor;
390
        \item {\tt struct tss}: an x86 Task descriptor.
391
\end{itemize}
392
All the constant that can be useful for initializing those structures are
393
also defined. See Intel manuals for some explanations.
394
 
395
These are the functions provided by the hardware library to manage
396
the CPU:
397
 
398
\noindent {\tt void int X86\_get\_CPU(struct ll\_cpuInfo *p)}
399
 
400
This function identifies the CPU present in the system and reports
401
its characteristics in the {\tt ll\_cpuInfo} structure whose pointer is
402
passed as an input. The {\tt ll\_cpuInfo} is described in Figure
403
\ref{fig:cpuinfo}.
404
\begin{figure}
405
%\begin{minipage}[t]{15cm}
406
\begin{tt}
407
\begin{tabbing}
408
struct ll\_cpuInfo \= \{                                        \\
409
\>      DWORD X86\_cpu;                                         \\
410
\>      DWORD X86\_cpuIdFlag;                                   \\
411
\>      DWORD X86\_vendor\_1;                                   \\
412
\>      DWORD X86\_vendor\_2;                                   \\
413
\>      DWORD X86\_vendor\_3;                                   \\
414
\>      DWORD X86\_signature;                                   \\
415
\>      DWORD X86\_IntelFeature\_1;                             \\
416
\>      DWORD X86\_IntelFeature\_2;                             \\
417
\>      DWORD X86\_StandardFeature;                             \\
418
\}
419
\end{tabbing}
420
\end{tt}
421
%\end{minipage}
422
\label{fig:cpuinfo}
423
\caption{The cpuInfo structure.}
424
\end{figure}
425
 
426
Basically, {\tt X86\_get\_CPU()} checks if the CPU is a 386, a 486, or
427
better; in the last case, it uses the {\tt cpuid} instruction to obtain
428
more information, otherwise it will use some custom code to determine the
429
manufacturer. In particular, it is based on the following functions:
430
\noindent {\tt void int X86\_is386(void)}                       \\
431
\noindent {\tt void int X86\_isCyrix(void)}                     \\
432
\noindent {\tt void int X86\_hasCPUID(void)}                    \\
433
It is recommended to invoke them through {\tt X86\_get\_CPU()}, but
434
sometime it can be useful to call one of the previous functions directly.
435
 
436
Similar code exists for detecting and initializing the FPU, but it still
437
need some work.
438
%void X86_get_FPU(void); FIX THIS STORY!!! check_fpu() ???
439
 
440
Some other functions are provided to manage the most important CPU tables:
441
 
442
\noindent {\tt void
443
GDT\_place(WORD sel, DWORD base, DWORD lim, BYTE acc, BYTE gran)}
444
 
445
This function permits to insert a new entry in the GDT; {\tt sel}
446
is the selector (equal to the entry number multiplied by
447
{\em sizeof(struct gdt\_entry)}), {\tt base} and {\tt lim} are the
448
base and the limit of the segment described by the entry (and identified
449
by {\tt sel}), while {\tt acc} and {\tt gran} are the access and granularity
450
bytes. They can be set using the constants defined in
451
{\tt ll/i386/hw-data.h}.
452
 
453
\noindent {\tt DWORD GDT\_read(WORD sel, DWORD *lim, BYTE *acc, BYTE *gran)}
454
 
455
This function permits to read an entry from the GDT, returning the
456
base of the segment identified by the descriptor {\tt sel}. Moreover,
457
if {\tt lim}, {\tt acc}, and {\tt gran} are not null, the limit, the
458
access byte and the granularity of the segment are stored in
459
{\tt *lim}, {\tt *acc}, and {\tt *gran}.
460
 
461
{\tt LIN\_ADDR addr2linear(WORD selector, DWORD offset)}
462
 
463
This function can be used to translate an {\tt <selector>:<offset>} address
464
in a 32bit linear address. It uses {\tt GDT\_read} for obtaining the
465
base of the segment identified by {\tt selector}.
466
 
467
\noindent {\tt void IDT\_place(BYTE num,void (*handler)(void))}
468
 
469
This function permits to insert an entry in the IDT; {\tt num} is the
470
number of the interrupt, whereas {\tt handler} is a pointer to the
471
code that has to be specified as an handler for that interrupt.
472
 
473
%multiprogramming --> These are described in the KL...
474
%CONTEXT ll_context_save(void);
475
%void    ll_context_change(CONTEXT c);
476
%void    ll_context_load(CONTEXT c);
477
%CONTEXT ll_context_from(void);
478
%void    ll_context_to(CONTEXT c);
479
%
480
%PIC Stuff...           --> TODO: documentation...
481
%void PIC_init(void);
482
%void PIC_end(void);
483
%void irq_mask(WORD irqno);
484
%void irq_unmask(WORD irqno);
485
After these very low level functionalities, the hardware support library
486
provides some other facilities:
487
 
488
\noindent{\tt void *x\_init(void)}
489
 
490
This function initializes a minimal programming environment, defining a
491
standard handler for all the CPU exceptions and hardware interrupts (through
492
{\tt IDT\_place()}), identifying the CPU type, initializing the FPU, setting
493
up a TSS for executing the code, and initializing the PIC.
494
 
495
Moreover, it returns a pointer to the MultiBoot Information structure (see
496
Figure \ref{fig:MBI}).
497
 
498
\noindent{\tt x\_exc\_bind(int i, void (*f)(int n))}
499
\noindent{\tt x\_irq\_bind(int i, void (*f)(int n))}
500
 
501
These two functions permit to associate a handler to a CPU exception or to
502
a hardware interrupt. Note that the handler is a C function, using the C
503
conventions for passing the parameters. Since these two functions are based
504
on the programming environment initialized by {\tt x\_init()}, they can be
505
used only {\em after} that {\tt x\_init()} has been called.
506
 
507
\noindent{\tt void x\_end(void)}
508
Restores the hardware settings to the DOS standards: it must be called on
509
shutdown if the execution is expected to return to a 16bit OS.
510
 
511
Some other functions can be used for accessing the PIT:
512
 
513
\noindent{\tt int pit\_init(BYTE c, BYTE m, WORD tconst)}
514
 
515
This function initializes the PIT channel {\tt c} (with {\tt c = 0},
516
{\tt 1}, or {\tt 2}) in mode {\tt m}, with the initial value of the
517
counter equal to {\tt tconst}. Returns a value {\tt < 0} on error (if
518
the requested channel does not exist).
519
 
520
\noindent{int pit\_setconstant(BYTE c, WORD val)}
521
 
522
This function sets the PIT channel {\tt c}'s counter to {\tt val}.
523
Returns a value {\tt < 0} on error (if the requested channel does not
524
exist).
525
 
526
\noindent{\tt WORD pit\_read(BYTE channel)}
527
 
528
This function reads the value of the counter of {\tt channel}.
529
 
530
Other functions permit to call real mode interrupts, either returning to
531
real mode or using the VM86 mode. Some of these functions are used to
532
access a FAT file system using DOS (they works only if the application is
533
invoked through the eXtender). See {\tt ll/i386/x-*.h} for more details.
534
 
535
%BIOS
536
%X_CALLBIOS * x_bios_address(void);
537
%void X_meminfo(LIN_ADDR *b1,DWORD *s1,LIN_ADDR *b2,DWORD *s2);
538
%void X_callBIOS(int service,X_REGS16 *in,X_REGS16 *out,X_SREGS16 *s);
539
%void vm86_init();
540
%int vm86_callBIOS(int service,X_REGS16 *in,X_REGS16 *out,X_SREGS16 *s);
541
 
542
%DOS
543
%DOS_FILE *DOS_fopen(char *name, char *mode);
544
%void DOS_fclose(DOS_FILE *f);
545
%DWORD DOS_fread(void *buf,DWORD size,DWORD num,DOS_FILE *f);
546
%DWORD DOS_fwrite(void *buf,DWORD size,DWORD num,DOS_FILE *f);
547
%unsigned DOS_error(void);
548
 
549
%void DOS_dump_mem(void);
550
%void DOS_mem_init(void);
551
%LIN_ADDR DOS_alloc(DWORD s);
552
%int DOS_free(LIN_ADDR p,DWORD s);
553
 
554
Some other functions directly remap the corresponding ASM
555
instructions (these functions are implemented by the {\tt xlib}):
556
\begin{itemize}
557
\item {\tt cli()}
558
\item {\tt sti()}
559
\item {\tt halt()}
560
\item {\tt clts()}
561
\item {\tt BYTE inp(WORD port)}
562
\item {\tt WORD inw(WORD port)}
563
\item {\tt DWORD ind(WORD port)}
564
\item {\tt void outp(WORD port, BYTE data)}
565
\item {\tt void outw(WORD port, WORD data)}
566
\item {\tt void outd(WORD port, DWORD data)}
567
\end{itemize}
568
the following two functions can be used instead of {\tt cli()} and
569
{\tt sti()}:
570
\begin{itemize}
571
\item {\tt SYS\_FLAGS ll\_fsave(void)}: performs a {\tt cli}, and return the
572
                previous value of the flags register;
573
\item {\tt void ll\_frestore(SYS\_FLAGS f)}: restores the flags register to
574
                {\tt f}; can be used instead of a {\tt sti()}.
575
\end{itemize}
576
 
577
Moreover, the library provides some inline functions for reading and
578
writing some CPU registers' values:
579
\begin{itemize}
580
        \item {\tt get\_CS()}
581
        \item {\tt get\_DS()}
582
        \item {\tt get\_FS()}
583
        \item {\tt get\_SP()}
584
        \item {\tt get\_BP()}
585
        \item {\tt get\_TR()}: returns the Task Register value
586
        \item {\tt set\_TR()}: sets the Task Register value
587
        \item {\tt set\_LDTR()}: sets the LDT address
588
\end{itemize}
589
 
590
\section{The Kernel Support Library}
591
The Kernel support library allows an OS developer to write interrupt
592
handlers, binding them to hardware interrupts, to create threads and
593
perform context switches, to crate address spaces and assign them to
594
threads, and to manage the time.
595
 
596
Time management consists in reading time, and assigning execution
597
time to threads through an event-based model. Hence, time management
598
is performed using {\em events}: an event permits to execute some code
599
(the event handler) at a specified time (the event rising time).
600
When an event raises the event handler is called (with interrupt disabled).
601
 
602
Interrupts are managed in a similar way, allowing the programmer to
603
specify the event handler for a special event that will raise when the
604
hardware interrupt arrives.
605
 
606
Using the event mechanism it is easy to implement {\em temporal protection}
607
(enforcing that a thread will never require too much execution time), while
608
spatial protection is provided by OSLib through {\em Address Spaces}. An
609
address space is a very basic abstraction encapsulating user data and code.
610
Address Spaces are implemented using x86 segments: each Address Space is a
611
different segment. If the user code uses only the default data and code
612
selectors, the code running in an address space can not access other address
613
spaces. As a default, OSLib provides a ``flat'' address space, mapping
614
$1 \rightarrow 1$ all the physical memory.
615
 
616
Here is a list of the functions provided by {\tt kl}:
617
 
618
\noindent {\tt void *ll\_init(void)}
619
 
620
This library function is used to initialize the Kernel Library: it
621
detects the CPU, initializes the FPU, and sets the interrupt and
622
exception handlers to default values.
623
 
624
\begin{figure}
625
%\begin{minipage}[t]{15cm}
626
\begin{tt}
627
\begin{tabbing}
628
struct multiboot\_info \= \{                                            \\
629
/* MultiBoot info version number */                                     \\
630
\>      unsigned long flags;                                            \\
631
                                                                        \\
632
/* Available memory from BIOS */                                        \\
633
\>      unsigned long mem\_lower;                                       \\
634
\>      unsigned long mem\_upper;                                       \\
635
/* "root" partition */                                                  \\
636
\>      unsigned long boot\_device;                                     \\
637
                                                                        \\
638
/* Kernel command line */                                               \\
639
\>      unsigned long cmdline;                                          \\
640
                                                                        \\
641
/* Boot-Module list */                                                  \\
642
\>      unsigned long mods\_count;                                      \\
643
\>      unsigned long mods\_addr;                                       \\
644
                                                                        \\
645
\>      union \= \{                                                     \\
646
\>      \>      struct \= \{                                            \\
647
/* (a.out) Kernel symbol table info */                                  \\
648
\>      \>      \>      unsigned long tabsize;                          \\
649
\>      \>      \>      unsigned long strsize;                          \\
650
\>      \>      \>      unsigned long addr;                             \\
651
\>      \>      \>      unsigned long pad;                              \\
652
\>      \>      \} a;                                                   \\
653
\>      \>      struct \{                                               \\
654
/* (ELF) Kernel section header table */                                 \\
655
\>      \>      \>      unsigned long num;                              \\
656
\>      \>      \>      unsigned long size;                             \\
657
\>      \>      \>      unsigned long addr;                             \\
658
\>      \>      \>      unsigned long shndx;                            \\
659
\>      \>      \} e;                                                   \\
660
\>      \} syms;                                                        \\
661
/* Memory Mapping buffer */                                             \\
662
\>      unsigned long mmap\_length;                                     \\
663
\>      unsigned long mmap\_addr;                                       \\
664
/*                                                                      \\
665
Gerardo: I need to add also the physical address base for               \\
666
both low ( < 1MB) \& upper ( > 1MB) memory, as X starts from DOS        \\
667
which could have preallocated some of this memory...                    \\
668
For example, GRUB assumes that mem\_lowbase = 0x0 \&                    \\
669
mem\_upbase = 0x100000                                                  \\
670
 */                                                                      \\
671
\>      unsigned long mem\_lowbase;                                     \\
672
\>      unsigned long mem\_upbase;                                      \\
673
\};                                                                     \\
674
\end{tabbing}
675
\end{tt}
676
%\end{minipage}
677
\caption{The MultiBoot Information structure.}
678
\label{fig:MBI}
679
\end{figure}
680
As output, {\tt ll\_init} returns informations about the environment
681
through a modified version of the MultiBoot Information (MBI)
682
structure (the returned value is a pointer to such a structure). The
683
MultiBoot Info structure is defined as shown in Figure \ref{fig:MBI}.
684
 
685
Refer to the MultiBoot documentation for more informations about the
686
fields behaviour. The only difference with the standard MultiBoot
687
Info structure is that a new flag {\tt MB\_INFO\_USEGDT} in the
688
{\tt flags} field is provided for informing that the program has been
689
loaded through a DOS Extender, and two new fields are added. If the
690
{\tt MB\_INFO\_USEGDT} is set, the two new fields {\tt mem\_lowbase}
691
and {\tt mem\_upbase} indicates the low memory and high memory
692
starting addresses, otherwise the standard values (respectively
693
$0x00$ and $0x100000$) have to be assumed.
694
 
695
\noindent{\tt CONTEXT ll\_context\_create(void (*entrypoint)(void *p),
696
                                BYTE *stack, void *parm, void (*killer)(void),
697
                                WORD control)}
698
 
699
This library function is used to create a new thread, allocating a
700
CPU context for it. A thread is defined as an independent flow of
701
execution and is characterized by the register set values, a private
702
stack (used to initialize the {\tt SS} and {\tt ESP} registers), and
703
an address space in which it executes. The code executed by a thread
704
is defined by a function called {\em thread body} that takes as input
705
a void pointer (passed at thread creation time).
706
 
707
The {\tt entrypoint} parameter is a pointer to the thread body, the
708
{\tt stack} parameter is a pointer to a preallocated chunk of memory
709
to be used as a stack for the new thread, while the {\tt parm}
710
parameter is a void pointer passed as parameter to the thread body
711
when the thread is created. The {\tt killer} parameter is a pointer
712
to a function that will be called on thread correct termination (a
713
thread terminates correctly when the execution arrives to the end of
714
the body function). The {\tt control} parameters defines some control
715
flags associated to the thread.
716
 
717
The function allocates a free CPU context and initializes the
718
register values using the passed parameters. The {\tt EIP} register
719
is initialized to {\tt entrypoint}, and {\tt ESP} is initialized
720
to {\tt stack}, whereas {\tt DS}, {\tt GS}, and {\tt FS} are
721
initialized to the default data segment and {\tt CS} is initialized to
722
the default code segment. As explained introducing Address Spaces, the
723
default code and data segments remap one-to-one all the system memory
724
(``flat'' Address Space). All the other registers are initialized to
725
standard values.
726
 
727
The return value is the  identifier of the initialized CPU context.
728
 
729
\noindent {\tt void ll\_context\_delete(CONTEXT c);}
730
 
731
This library function is used to free a CPU context when a thread is
732
terminated. The {\tt c} parameter is the identifier of the context to
733
be freed. Note that the stack memory has to be explicitly freed, since
734
{\tt ll\_context\_delete()} does not free it.
735
 
736
\noindent {\tt CONTEXT ll\_context\_save(void);}
737
 
738
This library function saves the CPU registers' values in the current
739
CPU context and returns its identifier. In other words, the context
740
associated to the thread executing when {\tt ll\_context\_save()} is
741
called is saved and its identifier is returned. It can be used to
742
implement context switches in OS primitives, as shown in the
743
following code:
744
 
745
\begin{minipage}[t]{15cm}
746
\begin{tt}
747
\begin{tabbing}
748
SYSCALL(mysyscall(...)) \=\                             \\
749
\{                                                      \\
750
\>      CONTEXT oldContext, newContext;                 \\
751
\>      $\ldots$                                        \\
752
                                                        \\
753
/* This must be the first primitive instruction */      \\
754
\>      oldContext = ll\_context\_save();               \\
755
\>      $\ldots$                                        \\
756
\>      OS primitive code                               \\
757
                                                        \\
758
/* This must be the last primitive instruction */       \\
759
\>      ll\_context\_load(newContext);                  \\
760
\};                                                     \\
761
\end{tabbing}
762
\end{tt}
763
\end{minipage}
764
 
765
{\bf Warning:} if the virtual context switch mechanism is used, this
766
function cannot be used (use {\tt ll\_context\_from()} instead).
767
 
768
\noindent {\tt void ll\_context\_load(CONTEXT c);}
769
 
770
This library call is used to load a new CPU context in the CPU, for
771
performing context switches, as shown in the example above (see
772
{\tt ll\_context\_save()}). Note that {\tt ll\_context\_load()} must
773
be called {\bf at the end} of a system call (immediately before re-enabling
774
interrupts); if a system programmer needs to perform a context switch
775
with interrupt disabled (in an event handler or in the middle of a
776
system call), the {\em virtual context switch} mechanism have to be used.
777
When virtual context switch is used, the context switch function only
778
stores the new context ID in a temporary variable and performs the
779
real context switch only when interrupts are enabled (see {\tt
780
ll\_context\_from()} and {\tt ll\_context\_to())}.
781
 
782
\noindent {\tt CONTEXT ll\_context\_from(void);}
783
 
784
This library function is similar to {\tt ll\_context\_save()}, but
785
can be called when the virtual context switch mechanism is used. In
786
this case it returns the ID of the last context that have been
787
selected to be loaded in the CPU.
788
 
789
\noindent {\tt void ll\_context\_to(CONTEXT c);}
790
 
791
This library selects a thread to be dispatched: if interrupts are
792
disabled and the context switch cannot be performed immediately, the
793
real context switch will happen as soon as possible (when interrupts
794
will be re-enabled). This is the {\tt virtual context switch}
795
mechanism.
796
 
797
{\tt ll\_context\_to()} is similar to {\tt ll\_context\_load()}, but
798
uses the virtual context switch mechanism; if interrupts are enabled,
799
they behave in the same manner.
800
 
801
\noindent {\tt void ll\_end(void);}
802
 
803
This function can be used in the shutdown code: if the application
804
was started through the DOS Extender, {\tt ll\_end()} resets the PIT
805
(and the rest of the hardware) to the standard DOS settings and
806
prepares the system to return to MSDOS, otherwise it simply halts the
807
system.
808
 
809
\noindent {\tt void ll\_abort(int code);}
810
 
811
This functions acts as safety place to go when any error occurs and
812
the OS does not know which context is active. The function loads a
813
safe context (with a safe stack), displays an error identified by
814
the {\tt code} parameter, and exits the OS support code
815
(see also {\tt ll\_end}).
816
 
817
\noindent {\tt void event\_init(struct ll\_initparms *l)}
818
 
819
This function sets the time management services up, by initializing
820
the event queue and programming the Programmable Interval Timer (PIT)
821
in a proper way. The PIT can be programmed in two
822
different modes: the periodic mode and the one-shot mode. In periodic
823
mode, the PIT is programmed to generate a timer interrupt each {\tt tick}
824
of $T$ $\mu$seconds, specified by the user through the {\tt l}
825
parameter. In one shot mode, the PIT is dynamically programmed to
826
generate an interrupt only when it is necessary to raise a
827
programmed event. It is worth noting that the PIT mode only
828
influences the error with which an event raises, but is invisible to
829
the OS (the PIT mode can be changed simply changing the {\tt event\_init()}
830
parameter, without any modify to the OS code).
831
 
832
The function takes as input a pointer {\tt l} to a {\tt ll\_initparms}
833
structure defined as follows:
834
 
835
\begin{minipage}[t]{15cm}
836
\begin{tt}
837
\begin{tabbing}
838
struct ll\_initparms \= \{      \\
839
\>      DWORD mode;             \\
840
\>      TIME tick;              \\
841
\};
842
\end{tabbing}
843
\end{tt}
844
\end{minipage}
845
 
846
The {\tt mode} field indicates the PIT mode ({\tt LL\_PERIODIC} or
847
{\tt LL\_ONESHOT}), while the {\tt tick} field indicates the tick size
848
(for periodic mode only) in $\mu$seconds.
849
 
850
\noindent {\tt TIME gettime(int mode, struct timespec *val)}
851
 
852
This function can be used to read the current system time. The system
853
time can be read using different levels of precision (and different
854
levels of overhead): currently only the {\tt TIME\_PTICK} and
855
{\tt TIME\_EXACT} modes are implemented. The {\tt TIME\_PTICK} mode
856
works only if the system timer is programmed in periodic mode, and
857
returns the system time in ticks. It is characterized by a low
858
overhead (small execution time). The {\tt TIME\_EXACT} mode reads the
859
exact system time and returns it measured in $\mu$seconds.
860
 
861
The {\tt mode} parameter can be {\tt TIME\_PTICK} or {\tt TIME\_EXACT}
862
and specifies the time reading mode; the {\tt val} parameter can
863
point to a {\tt timespec} structure that will be filled
864
with the current time ( if {\tt val != NULL}) .
865
 
866
This function returns the read time in $\mu$seconds, or $0$ if the
867
reading fails.
868
 
869
\noindent {\tt int event\_post(struct timespec *time,
870
                        void (*handler)(void *p), void *par)}
871
 
872
This function is used to create a new event, selecting an handler to
873
be called at the specified time passing an user provided parameter to
874
it. The {\tt handler} parameter specifies the event handler (the
875
function to be called when the event will raise), the {\tt time}
876
parameter indicates the time at which the event will raise, while
877
{\tt par} is a void pointer that will be passed as parameter to
878
the event handler.
879
 
880
The function returns the identifier of the created event, or -1 if an
881
error occurs (it can be due to the lack of free event
882
descriptors,  or to some other internal error). The event identifier
883
is used to refer the event for modifying or deleting it (see
884
{\tt event\_delete()}).
885
 
886
The OS support code programs the interrupt controller in a periodic
887
or one-shot mode (see {\tt event\_init()}) so that an interrupt will be
888
generated near to time {\tt time} to call the event handler. The
889
event handler is called as a response to the timer interrupt, with
890
interrupts disabled, hence it {\bf must} execute for not too much time
891
(otherwise, interrupts will be left disabled for a long time). The
892
timer mode can affect the error  with which the event handler is
893
called, but the code must be independent  from the timer mode.
894
% CHIARIRE IL CONCETTO!!!!
895
% -- GLI EVENT HANDLER NON DEVONO PRENDERE TEMPO!!!
896
% -- IL MODO DI FUNZIONAMENTO DEL TIMER E' ``TRASPARENTE''!!!
897
 
898
\noindent {\tt int event\_delete(int index)}
899
 
900
This library function is used to delete a posted event, identified by
901
the {\tt index} parameter. It returns 1 in case of success, -1 in
902
case of failure.
903
 
904
\noindent {\tt int irq\_bind(int irq, void (*handler)(void *p), DWORD flags)}
905
 
906
This function can be used to associate an handler to an hardware
907
interrupt; each interrupt is converted by the support code in an
908
event, so the interrupt handler is identical to an event handler. The
909
function checks if the requested interrupt is free, and in this case
910
allocates it and assigns the handler to it. If the interrupt is
911
already allocated (is not free), that is, a handler has been already
912
associated to it, {\tt irq\_bind} returns an error and does nothing.
913
 
914
The {\tt irq} parameter specifies the interrupt number, while {\tt
915
handler} is a pointer to the interrupt event handler, and the {\tt
916
flags} parameter defines some flags associated to the interrupt. In
917
particular, the {\tt FORCE} flag can be used to set a handler for an
918
already allocated interrupt, and the {\tt PREEMPTABLE} flag specifies
919
that the handler can be called with interrupts enabled (interruptible
920
handler).
921
 
922
FLAGS: \begin{itemize}
923
                \item the {\tt PREEMPTABLE} flag permits to specify
924
                                that the handler can be called with
925
                                interrupts enabled (interruptible handler).
926
                \item the {\tt FORCE} flag can be used to set a handler for
927
                                an already allocated interrupt.
928
\end{itemize}
929
 
930
Interruptible handlers are useful to enhance system responsiveness,
931
reducing the time in which interrupts are disabled and allowing to
932
develop a preemptable OS. On the other hand, they must be used with
933
caution, since mutual exclusion is not guaranteed in an interruptible
934
handler.
935
 
936
The {\tt FORCE} flag can be useful for removing an interrupt handler
937
(use this flag with the {\tt handler} parameter set to {\tt NULL}.
938
 
939
\noindent {\tt int ll\_ActiveInt(void)}
940
 
941
This function returns the number of pending interrupts or event handlers.
942
 
943
\noindent {\tt void as\_init(void)}
944
 
945
This function initializes the Address Space management code. It must be
946
called before using Address Spaces ({\tt as\_create()} or
947
{\tt as\_bind()}).
948
 
949
\noindent {\tt AS as\_create(void)}
950
 
951
This library function can be used to create a new Address Space: it
952
searches for a free Address Space descriptor and initializes it to an
953
empty Address Space returning its identifier. The return value is the
954
created Address Space ID in case of success, or 0 in case of failure.
955
 
956
\noindent {\tt int as\_bind(AS as, DWORD ph\_addr, DWORD l\_addr, DWORD size)}
957
 
958
This library function binds a chunk of physical memory to an Address
959
Space. The {\tt as} parameter is the Address Space identifier,
960
{\tt ph\_addr} is the physical chunk start address, {\tt l\_addr} is the
961
logical address in the {\tt as} address space where the memory chunk
962
has to be mapped, and {\tt size} indicate the size of the memory
963
chunk expressed in bytes.
964
 
965
{\bf Warning:} currently, this function has been only partially implemented.
966
In particular, since paging is not enabled, a single chunk of memory can be
967
bound to an Address Space, starting from logical address 0.
968
 
969
\noindent {\tt void ll\_context\_setspace(CONTEXT c, AS as)}
970
 
971
This library functions changes the Address Space in which a thread runs.
972
Basically, {ll\_context\_setspace()} sets all the context {\tt c} segment
973
registers to the segment of the {\tt as} address space.
974
This function can be useful to create a new task: \begin{enumerate}
975
\item Create a new context
976
\item Create a new Address Space
977
\item Set the context Address Space to the created one...
978
\end{enumerate}
979
{\em We need an example...} Look at {\tt examples/aspacedemo.c}.
980
 
981
\section{Miscellaneous}
982
Two functions {\tt void *ll\_alloc(DWORD size)} and
983
{\tt void ll\_free(void *base, DWORD size)} are provided to
984
allocate and free physical memory. They are provided only for
985
convenience, but they should not be used: the memory allocator
986
should be implemented in an upper level, using the informations
987
returned by {\tt ll\_init()}.
988
 
989
Two functions {\tt char *ll\_context\_sprintf(char *str, CONTEXT c)} and
990
{\tt void dump\_TSS(WORD sel)} are provided for debugging purpose.
991
 
992
\end{document}