Rev 1676 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1676 | tullio | 1 | %---------------------------------------------------------------------------- |
2 | \chapter{Utility functions} |
||
3 | %---------------------------------------------------------------------------- |
||
4 | |||
5 | S.Ha.R.K. provides a set of utility functions aimed at getting information |
||
6 | about the kernel state. Mainly, they allow a user to get the actual |
||
7 | system time and some information concerning the tasks' state. Moreover, |
||
8 | it allows to set exception handlers and to manage interrupts. |
||
9 | |||
10 | %---------------------------------------------------------------------------- |
||
11 | \section{Reading time} |
||
12 | %---------------------------------------------------------------------------- |
||
13 | |||
14 | The S.Ha.R.K. Kernel does not have the concept of tick. Every time |
||
15 | interval and every absolute time in the system is measured usin the |
||
16 | Real-Time Clock available on the PC. To read the current time you |
||
17 | can use the following function: |
||
18 | |||
19 | %---------------------------------------------------------------------------- |
||
20 | \begin{intest} |
||
21 | SYS\_GETTIME\index{sys\_gettime()} |
||
22 | \end{intest} |
||
23 | |||
24 | \begin{description} |
||
25 | \item [\texttt{TIME sys\_gettime(struct timespec *t);}] |
||
26 | \item [Description:]It returns the number of microseconds elapsed from |
||
27 | system's initialization, that is from the end of the \texttt{\_\_kernel\_register\_levels\_\_} |
||
28 | function. If the \texttt{t} value is not equal \texttt{NULL}, the |
||
29 | function fills also the timespec structure passed as parameter. |
||
30 | \end{description} |
||
31 | |||
32 | %---------------------------------------------------------------------------- |
||
33 | \section{Getting information on tasks} |
||
34 | %---------------------------------------------------------------------------- |
||
35 | |||
36 | Since all the tasks are handled by a Module, it is a responsibility of each |
||
37 | Module to hide or not hide informations about the tasks handled by the system. |
||
38 | However, at the moment S.Ha.R.K. provides a function that simply prints the |
||
39 | tasks state on the console \footnote{Old versions of the kernel supported a |
||
40 | \texttt{void sys\_status(DWORD cw);} \index{sys\_status()}primitive. That |
||
41 | primitive is currently unsupported.}. |
||
42 | |||
43 | \pagebreak |
||
44 | |||
45 | %---------------------------------------------------------------------------- |
||
46 | \begin{intest} |
||
47 | PERROR\index{perror()} |
||
48 | \end{intest} |
||
49 | |||
50 | \begin{description} |
||
51 | \item [\texttt{void perror (const char *s);}] |
||
52 | \item [Description:]This is the POSIX \texttt{perror()} funcion, that prints |
||
53 | on the console (using \texttt{kern\_printf}) a message that explain |
||
54 | the meaning of the \texttt{errno} \index{errno} variable. Note that |
||
55 | each task has its own \texttt{errno} variable, as specified by the |
||
56 | \texttt{POSIX} standard. |
||
57 | \end{description} |
||
58 | |||
59 | %---------------------------------------------------------------------------- |
||
60 | \begin{intest} |
||
61 | exec\_shadow\index{exec\_shadow} |
||
62 | \end{intest} |
||
63 | \begin{description} |
||
64 | \item [\texttt{PID exec\_shadow;}] |
||
65 | \item [Description:]This is the internal variable used by the Kernel to |
||
66 | track the running task. You can read its value to know the PID of |
||
67 | the current task. You CAN NOT modify this variable. |
||
68 | \end{description} |
||
69 | |||
70 | %---------------------------------------------------------------------------- |
||
71 | \section{Printing messages on the console} |
||
72 | %---------------------------------------------------------------------------- |
||
73 | |||
74 | To print a simple message on the console, please use the c* functions |
||
75 | (cprintf\index{cprintf}, cputs\index{cputs}, \ldots{}) described |
||
76 | in Volume II. If tou are debugging \emph{the kernel}, you can use |
||
77 | kern\_printf \index{kern\_printf} to print very simple messages without |
||
78 | floating point arithmetic. |
||
79 | |||
80 | %---------------------------------------------------------------------------- |
||
81 | \chapter{Signals and Exception Handling} |
||
82 | %---------------------------------------------------------------------------- |
||
83 | |||
84 | %---------------------------------------------------------------------------- |
||
85 | \section{Signals} |
||
86 | %---------------------------------------------------------------------------- |
||
87 | |||
88 | S.Ha.R.K. implements the specification of the signals and of the real-time |
||
89 | signald provided by the standard IEEE 1003.13 POSIX PSE51/PSE52. In |
||
90 | particular, you can use all the functions described into the IEEE |
||
91 | 1003.1\{a,b\} standards, except that: |
||
92 | |||
93 | \begin{itemize} |
||
94 | \item all the \texttt{pid\_t} parameters and in general all parameters related |
||
95 | with processes should be ignored; |
||
96 | \item when in POSIX a signal cause the termination of the process, it causes |
||
97 | in S.Ha.R.K. the termination of the whole system (you can think S.Ha.R.K. |
||
98 | as a single process multithread kernel); |
||
99 | \item The \texttt{siginfo\_t} structure contains an additional parameter |
||
100 | called \texttt{si\_task} of type \texttt{PID}. It contains the \texttt{PID} |
||
101 | of the task that queued a particular real-time signal. |
||
102 | \end{itemize} |
||
103 | |||
104 | In particular, you can use these functions for signal handling: \texttt{kill}, |
||
105 | \texttt{sigemptyset}, \texttt{sigfillset}, \texttt{sigaddset}, |
||
106 | \texttt{sigdelset}, \texttt{sigismember}, \texttt{sigaction}, |
||
107 | \texttt{pthread\_sigmask} \footnote{If you are not using the POSIX scheduling |
||
108 | modules please use \texttt{task\_sigmask}}, \texttt{sigprocmask}, |
||
109 | \texttt{sigpending}, \texttt{sigsuspend}, \texttt{sigwait}, |
||
110 | \texttt{sigwaitinfo}, \texttt{sigtimedwait}, \texttt{sigqueue}, |
||
111 | \texttt{pthread\_kill} \footnote{If you are not using the POSIX scheduling |
||
112 | modules please use \texttt{task\_signal} (Note that \texttt{task\_kill} does not |
||
113 | send any signal, but issue a cancellation request on a task!)}, \texttt{alarm}, |
||
114 | \texttt{pause}, \texttt{sleep} (note the difference between \texttt{sleep}, |
||
115 | \texttt{task\_sleep} and \texttt{nanosleep}!), \texttt{raise}, \texttt{signal}. |
||
116 | |||
117 | %---------------------------------------------------------------------------- |
||
118 | \section{Exception handling\label{ch:except}} |
||
119 | %---------------------------------------------------------------------------- |
||
120 | |||
121 | S.Ha.R.K. provides a flexible mechanism to handle the exceptions of the Kernel. |
||
122 | The mechanism is based on the POSIX signals. In fact, S.Ha.R.K. exceptions are |
||
123 | remapped on the real-time signal \texttt{SIGHEXC} \footnote{see |
||
124 | \texttt{include/signal.h}.} (9). Every time something goes wrong, the system |
||
125 | calls the primitive \texttt{kern\_raise}, that simply queue a real-time signal |
||
126 | of number SIGHEXC. |
||
127 | |||
128 | The user can define its own exception handler simply remapping the SIGHEXC |
||
129 | signal using the POSIX primitive \texttt{sigaction}. To fullfil the typical |
||
130 | usage of an exception handler (exit the system after printing a message), the |
||
131 | default behavior of the signal handler has been redefined to print a text |
||
132 | message on system shutdown. \footnote{Older versions of the Kernel supported two |
||
133 | functions to be used for standard redefinition of the kernel signal handler. |
||
134 | These functions, called SET\_EXCHANDLER\_TXT\index{set\_exchandler\_txt()} and |
||
135 | SET\_EXCHANDLER\_GRX\index{set\_exchandler\_grx()}, are no more supported, and |
||
136 | can be removed from your code without problems.} |
||
137 | |||
138 | Here is a sample code that explain how to redefine a signal handler: |
||
139 | |||
140 | \begin{verbatim} |
||
141 | #include <kernel/kern.h> |
||
142 | |||
143 | void thehandler(int signo, siginfo_t *info, void *extra) { |
||
144 | |||
145 | /* the signal handler: |
||
146 | info.sivalue.sival_int contains the exception number |
||
147 | (see include/bits/errno.h) |
||
148 | |||
149 | info.si_task is the task that raised the exception |
||
150 | extra is not used |
||
151 | */ |
||
152 | ... |
||
153 | } |
||
154 | |||
155 | ... |
||
156 | |||
157 | int myfunc(...) { |
||
158 | struct sigaction action; |
||
159 | ... |
||
160 | |||
161 | action.sa_flags = SA_SIGINFO; |
||
162 | action.sa_sigaction = thehandler; |
||
163 | action.sa_handler = 0; |
||
164 | sigfillset(&action.sa_mask); |
||
165 | sigaction(SIGHEXC, &action, NULL); |
||
166 | |||
167 | ... |
||
168 | } |
||
169 | \end{verbatim} |
||
170 | |||
171 | %---------------------------------------------------------------------------- |
||
172 | \begin{intest} |
||
173 | KERN\_RAISE\index{kern\_raise()} |
||
174 | \end{intest} |
||
175 | |||
176 | \begin{description} |
||
177 | \item [\texttt{void kern\_raise(int n, PID p);}] |
||
178 | \item [Description:]This function uses the POSIX function sigqueue to put |
||
179 | a signal SIGHEXC into the signal queue. The parameter n is used as |
||
180 | the exception number, and it is passed into the siginfo\_t parameter |
||
181 | (into the sivalue.sival\_int field). The signal appears to be queued |
||
182 | by the task p (the p value is stored into the si\_task field of the |
||
183 | siginfo\_t structure passed as parameter). |
||
184 | \end{description} |
||
185 | |||
186 | %---------------------------------------------------------------------------- |
||
187 | \chapter{Interrupt and HW Ports handling} |
||
188 | \label{ch:interr} |
||
189 | %---------------------------------------------------------------------------- |
||
190 | |||
191 | Generally speaking, I/O to and from an external peripheral device |
||
192 | can be handled in three different ways depending on the peripheral |
||
193 | type and on the application: |
||
194 | |||
195 | \begin{itemize} |
||
196 | \item \textbf{Polling}: the program cyclically checks the status of the |
||
197 | I/O port, waiting for a input data to be ready or an output data to |
||
198 | be transmittable; |
||
199 | \item \textbf{Interrupt}: the program enables the I/O interface to send |
||
200 | a hardware interrupt every time an input data is available or an output |
||
201 | data is transmittable; |
||
202 | \item \textbf{DMA}: the program enables the interface to use DMA mechaninsm |
||
203 | for directly transferring data to/from memory. |
||
204 | \end{itemize} |
||
205 | \noindent In this chapter we will analyse the support that the S.Ha.R.K. |
||
206 | kernel provides for using the second method (interrupt). |
||
207 | |||
208 | When an interrupt arrives, a code for the hand-shake with the interface |
||
209 | and for transferring data has to be executed. This code can run in |
||
210 | two different modes: |
||
211 | |||
212 | \begin{itemize} |
||
213 | \item it can be entirely encapsulated in a function to be executed immediately |
||
214 | on the interrupt arrival, in the context of the executing task (\textit{fast |
||
215 | handler}); |
||
216 | \item it can be entirely encapsulated in a task (\textit{safe handler}) |
||
217 | which is activated on the interrupt arrival and scheduled with its |
||
218 | own priority together with the other tasks. |
||
219 | \end{itemize} |
||
220 | \noindent The first method is appropriate when the interrupt needs |
||
221 | a fast response time. Its potential drawback is that if its computation |
||
222 | time is not low, the overall schedulabuility can be severly affected. |
||
223 | This is because the guarantee algorithm does not take into account |
||
224 | the execution time of the interrupt handlers. The second method, on |
||
225 | the contrary, is perfectly integrated with the kernel's scheduling |
||
226 | mechanism, but can cause considerable delays in transferring data. |
||
227 | |||
228 | S.Ha.R.K. provides great flexibility in interrupt handling, since |
||
229 | it allows each interrupt to be associated with a \textit{fast handler}, |
||
230 | a \texttt{safe handler}, or both. |
||
231 | |||
232 | On an interrupt's arrival the following operations are performed by |
||
233 | the kernel: |
||
234 | |||
235 | \begin{itemize} |
||
236 | \item The system checks whether a fast handler is associated with the interrupt. |
||
237 | If so, the interrupts are enabled and the handler is invoked. This |
||
238 | method allows a handler to be interrupted by a higher priority handler. |
||
239 | As an example, the keyboard handler (interrupt 1) can be interrupted |
||
240 | be the timer handler (interrupt 0). |
||
241 | \item The system checks whether a sporadic task (\emph{safe handler}) is |
||
242 | associated with the interrupt. If so, the task is activated and is |
||
243 | eligible to run with enabled interrupts. |
||
244 | \end{itemize} |
||
245 | \noindent The system provides a set of functions for accessing the |
||
246 | hardaware interfaces' ports. In the drivers directory you can find |
||
247 | examples of a S.Ha.R.K. device driver. |
||
248 | |||
249 | %---------------------------------------------------------------------------- |
||
250 | \section{Setting an interrupt handler} |
||
251 | %---------------------------------------------------------------------------- |
||
252 | |||
253 | %---------------------------------------------------------------------------- |
||
254 | \begin{intest} |
||
255 | HANDLER\_SET\index{handler\_set()} |
||
256 | \end{intest} |
||
257 | |||
258 | \begin{description} |
||
259 | \item [\texttt{int handler\_set(int no, void (*fast)(int), PID |
||
260 | pi, BYTE lock);}] |
||
261 | \item [Description:]It installs function \texttt{fast} (fast handler) and |
||
262 | the sporadic task \texttt{p} (safe handler) on the interrupt identified |
||
263 | by \texttt{no}. The \texttt{no} parameter must belong to the range |
||
264 | 1\ldots{}15 (interrupt 0 is associated to the timer and cannot be |
||
265 | intercepted). On the interrupt's arrival, function \texttt{fast} is |
||
266 | invoked and runs. Depending on the \texttt{lock} flag, the interrupts |
||
267 | are disabled (\texttt{lock} = TRUE) or enabled (\texttt{lock} = FALSE) |
||
268 | during handler execution. Furthermore, on the interrupt's arrival, |
||
269 | task \texttt{p} is activated. |
||
270 | \end{description} |
||
271 | |||
272 | %---------------------------------------------------------------------------- |
||
273 | \begin{intest} |
||
274 | HANDLER\_REMOVE\index{handler\_remove()} |
||
275 | \end{intest} |
||
276 | |||
277 | \begin{description} |
||
278 | \item [\texttt{void handler\_remove(int no);}] |
||
279 | \item [Description:]It removes the handler of the interrupt number \texttt{intno}; |
||
280 | the interrupt is masked. |
||
281 | \end{description} |
||
282 | |||
283 | %---------------------------------------------------------------------------- |
||
284 | \section{Reading and writing from I/O ports} |
||
285 | %---------------------------------------------------------------------------- |
||
286 | |||
287 | %---------------------------------------------------------------------------- |
||
288 | \begin{intest} |
||
289 | INP, INPW, INPD \index{inp()} \index{inpw()} \index{inpd()} |
||
290 | \end{intest} |
||
291 | |||
292 | \begin{description} |
||
293 | \item [\texttt{unsigned char inp(unsigned short \_port);}] |
||
294 | \item [\texttt{unsigned short inpw (unsigned short \_port);}] |
||
295 | \item [\texttt{unsigned long inpd(unsigned short \_port);}] |
||
296 | \item [Description:]They return the data read on port \texttt{\_port}. |
||
297 | \end{description} |
||
298 | |||
299 | %---------------------------------------------------------------------------- |
||
300 | \begin{intest} |
||
301 | OUTP, OUTPW, OUTPD \index{outp()} \index{outpw()} \index{outpd()} |
||
302 | \end{intest} |
||
303 | |||
304 | \begin{description} |
||
305 | \item [\texttt{void outp(unsigned short \_port, unsigned char \_data);}] |
||
306 | \item [\texttt{void outpw(unsigned short \_port, unsigned short \_data);}] |
||
307 | \item [\texttt{void outpd(unsigned short \_port, unsigned long \_data)}] |
||
308 | \item [Description:]It writes the data \texttt{\_data} into the port \texttt{\_port}. |
||
309 | \end{description} |
||
310 | |||
311 | %---------------------------------------------------------------------------- |
||
312 | \section{Disabling/Enabling interrupts} |
||
313 | %---------------------------------------------------------------------------- |
||
314 | |||
315 | %---------------------------------------------------------------------------- |
||
316 | \begin{intest} |
||
317 | KERN\_CLI\index{kern\_cli()} |
||
318 | \end{intest} |
||
319 | |||
320 | \begin{description} |
||
321 | \item [\texttt{void kern\_cli(void);}] |
||
322 | \item [Description:]It disables interrupts (as the x86 \texttt{cli} instruction). |
||
323 | \end{description} |
||
324 | %---------------------------------------------------------------------------- |
||
325 | |||
326 | \begin{intest} |
||
327 | KERN\_STI\index{kern\_sti()} |
||
328 | \end{intest} |
||
329 | |||
330 | \begin{description} |
||
331 | \item [\texttt{void kern\_sti(void);}] |
||
332 | \item [Description:]It enables interrupts (as the x86 \texttt{sti} instruction). |
||
333 | \end{description} |
||
334 | |||
335 | %---------------------------------------------------------------------------- |
||
336 | \section{Saving/Restoring interrupts} |
||
337 | %---------------------------------------------------------------------------- |
||
338 | |||
339 | %---------------------------------------------------------------------------- |
||
340 | \begin{intest} |
||
341 | KERN\_FSAVE\index{kern\_fsave()}\index{SYS\_FLAGS} |
||
342 | \end{intest} |
||
343 | |||
344 | \begin{description} |
||
345 | \item [\texttt{SYS\_FLAGS kern\_fsave(void);}] |
||
346 | \item [Description:]It disables interrupts (as the x86 \texttt{cli} instruction). |
||
347 | The CPU flags are returned by the function; in that way they can be |
||
348 | restored using kern\_frestore |
||
349 | \end{description} |
||
350 | |||
351 | %---------------------------------------------------------------------------- |
||
352 | \begin{intest} |
||
353 | KERN\_FRESTORE\index{kern\_frestore()} |
||
354 | \end{intest} |
||
355 | |||
356 | \begin{description} |
||
357 | \item [\texttt{void kern\_frestore(SYS\_FLAGS f);}] |
||
358 | \item [Description:]It restores the interrupt state as it was when the |
||
359 | correspondent \texttt{kern\_fsave} was called. |
||
360 | \end{description} |
||
361 | |||
362 | %---------------------------------------------------------------------------- |
||
363 | \section{Masking/Unmasking PIC interrupts} |
||
364 | %---------------------------------------------------------------------------- |
||
365 | |||
366 | %---------------------------------------------------------------------------- |
||
367 | \begin{intest} |
||
368 | IRQ\_MASK\index{irq\_mask()} |
||
369 | \end{intest} |
||
370 | |||
371 | \begin{description} |
||
372 | \item [\texttt{void irq\_mask(WORD irqno);}] |
||
373 | \item [Description:]It mask the interrupt number \texttt{irqno} on the |
||
374 | PC PIC. \texttt{irqno} must be in the interval {[}1..15{]}. |
||
375 | \end{description} |
||
376 | |||
377 | %---------------------------------------------------------------------------- |
||
378 | \begin{intest} |
||
379 | IRQ\_UNMASK\index{irq\_unmask()} |
||
380 | \end{intest} |
||
381 | |||
382 | \begin{description} |
||
383 | \item [\texttt{void irq\_unmask(WORD irqno);}] |
||
384 | \item [Description:]It unmask the interrupt number \texttt{irqno} on the |
||
385 | PC PIC. \texttt{irqno} must be in the interval {[}1..15{]}. |
||
386 | \end{description} |
||
387 | |||
388 | %---------------------------------------------------------------------------- |
||
389 | \chapter{Memory Management Functions} |
||
390 | %---------------------------------------------------------------------------- |
||
391 | |||
392 | The S.Ha.R.K. Kernel provides the standard set of memory allocations |
||
393 | functions provided by the Standard C libraries. In particular, the |
||
394 | functions listed in figure \ref{fig:malloc} can be used. |
||
395 | |||
396 | \begin{figure} |
||
397 | \begin{center} \fbox{\tt{ \begin{minipage}{6cm} \begin{tabbing} |
||
398 | 123\=123\=123\=\kill |
||
399 | \#include <stdlib.h>\\ |
||
400 | void *calloc(size\_t nmemb, size\_t size);\\ |
||
401 | void *malloc(size\_t size);\\ |
||
402 | void free(void *ptr);\\ |
||
403 | void *realloc(void *ptr, size\_t size);\\ |
||
404 | \end{tabbing} \end{minipage} }} \end{center} |
||
405 | \caption{\label{fig:malloc}Memory allocation functions.} |
||
406 | \end{figure} |
||
407 | In particular \footnote{These descriptions came directly from the Linux man pages...}: |
||
408 | |||
409 | \begin{itemize} |
||
410 | \item calloc() allocates memory for an array of nmemb elements of size bytes |
||
411 | each and returns a pointer to the allocated memory. The memory is |
||
412 | set to zero. The value returned is a pointer to the allocated memory, |
||
413 | which is suitably aligned for any kind of variable, or NULL if the |
||
414 | request fails. |
||
415 | \item malloc() allocates size bytes and returns a pointer to the allocated |
||
416 | memory. The memory is not cleared. The value returned is a pointer |
||
417 | to the allocated memory, which is suitably aligned for any kind of |
||
418 | variable, or NULL if the request fails. |
||
419 | \item free() frees the memory space pointed to by ptr, which must have been |
||
420 | returned by a previous call to malloc(), calloc() or realloc(). Otherwise, |
||
421 | or if free(ptr) has already been called before, undefined behaviour |
||
422 | occurs. If ptr is NULL, no operation is performed. |
||
423 | \item realloc() changes the size of the memory block pointed to by ptr to |
||
424 | size bytes. The contents will be unchanged to the minimum of the old |
||
425 | and new sizes; newly allocated memory will be uninitialized. If ptr |
||
426 | is NULL, the call is equivalent to malloc(size); if size is equal |
||
427 | to zero, the call is equivalent to free(ptr). Unless ptr is NULL, |
||
428 | it must have been returned by an earlier call to malloc(), calloc() |
||
429 | or realloc(). It returns a pointer to the newly allocated memory, |
||
430 | which is suitably aligned for any kind of variable and may be different |
||
431 | from ptr, or NULL if the request fails or if size was equal to 0. |
||
432 | If realloc() fails the original block is left untouched - it is not |
||
433 | freed or moved. |
||
434 | \end{itemize} |
||
435 | |||
436 | The S.Ha.R.K. Kernel also provides a set of low-level memory management |
||
437 | functions that can be used to allocate memory with particular requirements |
||
438 | (for example, they are useful for getting memory blocks aligned to |
||
439 | a page (4 Kb) boundary or with addresses under 1/16 Mb). Description |
||
440 | of these functions is given in Chapter 3 of the S.Ha.R.K. Architecture |
||
441 | Manual. |