2.12. System Calls

A system call is the means by which application programs call an operating system. System calls are mostly used for input-output. The predefined Ada package Ada.Text_IO and the smaller package XGC.Text_IO map all input and output operations onto the system calls read and write. Also the C language input-output functions declared in <stdio.h> use the same system calls.

With XGC Ada, we have no operating system as such, just the run-time system module art0. However, we support the system call mechanism using trap 80 (the SPARC standard) and when running on the simulator we map system calls to host system calls so that application programs can access host computer files during program development.

When running on the target, any system call will bring your program to an abnormal termination because the required system call handler is absent in the default configuration. The default system call handler is located in libc and supports an appropriate subset of calls. For example, read and write are directed to UARTA and may be used in a console dialog. You may wish to customise the default handler so that calls that would otherwise be non-operational could do something useful. For example, the call to get the time could be implemented to read the time form some external clock.

This can be done quite easily and an example system call handler is included with the source files in /opt/erc32-ada-1.7/erc-coff/src/libc/sys/schandler.c. The handler is attached to the system call trap in the same fashion as other interrupts are attached to their handlers. In the example, a C function is provided to do the attaching.

2.12.1. How to Use Text_IO Without System Calls

Another way to support Text_IO is to replace the various system calls with calls to application code. For example, if all you need is the Put functionality in Text_IO, you can create your own version of write and have it do whatever you want. When your program is linked, the linker will use your version of write in place of the library version.

Example 2-25. Code to Support Write


   --  UART registers. See TSC695F, Table 4-38 and Table 4-40.

   UARTAR : Unsigned_32;
   for UARTAR'Address use 16#01F800E0#;

   UARTSR : Unsigned_32;
   for UARTSR'Address use 16#01F800E8#;

   --  Protected object required to access system registers

   protected UART is
      procedure Write (Ch : Character);
      pragma Interrupt_Handler (Write);
   end UART;

   protected body UART is
      procedure Write (Ch : Character) is
      begin
         while (UARTSR and 16#00000004#) = 0 loop
            null;
         end loop;

         UARTAR := Character'Pos (Ch);
      end Write;
   end UART;

   --  Export pragmas required for comatibility with C

   procedure Write (
      Result : out Integer;
      Fd : in Natural;
      Buf : in System.Address;
      Count : in Natural);
   pragma Export (C, Write, "write");
   pragma Export_Valued_Procedure (Write, "write");

   procedure Write (
      Result : out Integer;
      Fd : in Natural;
      Buf : in System.Address;
      Count : in Natural)
   is
      Ada_Buf : String (1 .. Count);
      for Ada_Buf'Address use Buf;
   begin
      for I in 1 .. Count loop
         UART.Write (Ada_Buf (I));
      end loop;

      Result := Count;
   end Write;