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} |