Writing a Systemcall Extension : an Example

Mon Sep 16 13:29:30 1996
Yasushi Saito


Overview

This chapter demonstrates how you can write a new system call extension and how you can use it. This document requires substantial knowledge of sieg. The extension explained in this chapter is based on EFS. The EFS systemcall extension provides only two services.
void efs_nuke(char *dir);
Clear all the contents under the directory dir.
void efs_create(char *path, unsigned long size);
Create the file path. The size is fixed to size.

Files

Here's the list of files you have to write.
EFSSyscall.i3
The system call definition file.
EFSSyscall.m3
System call Implementation
m3makefile
m3makefile
efs.c
User side library implementation.
testefs.c
User side sample app.

Interface Design

The below is the systemcall definition for Hello.

(*
 * Copyright 1994-96 University of Washington
 * All rights reserved.
 * See COPYRIGHT file for a full description
 *
 * HISTORY
 * 06-Sep-96  Yasushi Saito (yasushi) at the University of Washington
 *	Created.
 *)

(* System call interface to the extent file system. *)
INTERFACE EFSSyscall;
IMPORT Error;
<*PRAGMA AS*>
<*PRAGMA INTERFACE_PROC_BASE*>
<*PRAGMA SYNONYMS*>
<*PRAGMA EPILOG_BRANCH_ON_REGISTER*>

<*EPILOG_BRANCH_ON_REGISTER _Seterrno*>
<*INTERFACE_PROC_BASE 3500*>

<*SYNONYMS _efs_nuke*>  
PROCEDURE Nuke(<*AS CTEXT*>dir: TEXT) RAISES {Error.E};
(* "efs_nuke(dir)" deletes all the files under the EFS directory "dir" *)
  
<*SYNONYMS _efs_create*>  
PROCEDURE Create(<*AS CTEXT*>path: TEXT; size: INTEGER) RAISES {Error.E};

END EFSSyscall.

Extension Implementation

The implementation is really straightforward.

(*
 * Copyright 1994-96 University of Washington
 * All rights reserved.
 * See COPYRIGHT file for a full description
 *
 * HISTORY
 * 06-Sep-96  Yasushi Saito (yasushi) at the University of Washington
 *	Created.
 *)
MODULE EFSSyscall;
IMPORT IO;
IMPORT EFS;
IMPORT EFSUtils;
IMPORT FileSystem;
IMPORT File;
IMPORT Error;

PROCEDURE Nuke (dir: TEXT) RAISES {Error.E} =
  VAR fh: File.T;
  BEGIN
    fh := FileSystem.Open(0, dir);
    IF NOT ISTYPE(fh, EFS.T) THEN
      IO.Put("efs_nuke : the path is not efs partition.\n");
      RETURN;
    END;
    EFS.Nuke(fh);
    fh.close();
  END Nuke;

PROCEDURE Create (path: TEXT; size: INTEGER) RAISES {Error.E} =
  VAR
    dirName, baseName : TEXT;
    fh : File.T;
  BEGIN
    EFSUtils.SplitPathIntoDirAndBasename(path, dirName, baseName);
    fh := FileSystem.Open(0, dirName);
    IF NOT(ISTYPE(fh, EFS.T)) THEN
      IO.Put("efs_create : the path is not efs partition.\n");
      RETURN;
    END;

    EVAL EFS.Create(fh, baseName, size);
  END Create;
  
BEGIN
END EFSSyscall.

m3makefile

As you have noticed, the systemcall implementation doesn't do anything about installing the extension. This is done by the SyscallBoot.m3 and SyscallBootGen.mg provided by Sphinx. All you have to do is to write like below in the m3makefile
1: DomainImport("Sphinx","user", "sphinx", overridepath)
2: Sieg_interface("EFSSyscall")
3: sphinx_addon_syscall("EFSSyscall")
  1. this line imports the Sphinx extension. SystemcallBoot generic and necessary quake templates are also imported here.
  2. this line calls Sieg.
  3. This line instantiates the SyscallBootGen generic. The generic reads the EFS system call information from the file EFSSyscallInfo.i3, which is a file generated by Sieg, and calls procedures in SyscallBoot.
For your information, below is the complete EFS m3makefile. This file contains definitions not related to system calls.

# HISTORY
# 24-Mar-96  Brian Bershad (bershad) at the University of Washington
#	New build fmt.
#
# 22-Feb-96  Charles Garrett (garrett) at the University of Washington
#	Changed to simpler spindle build functions.
#
# WFS


overridepath = [ THISTREE , FULLTREE ]
DomainImport("SpinPublic","kernel","spincore",overridepath)
DomainImport("SpinTrusted","kernel","spincore",overridepath)
DomainImport("SpinUnixRunTime","user/urt","urtcore",overridepath)
DomainImport("FileSystem","user/fs","fscore",overridepath)
DomainImport("Extent", "user", "extent", overridepath)
DomainImport("Device", "user/dev", "devcore", overridepath)
DomainImport("Shell","user/shell", "shellcore", overridepath)
DomainImport("Sieg","user", "sieg", overridepath)
DomainImport("Sphinx","user", "sphinx", overridepath)
DomainImport ("UserSpaceThread","user/thread","threadcore",overridepath)
DomainImport ("VMCore","user/vm","vmcore",overridepath)
DomainImport ("Space","user/vm","space",overridepath)

Package("EFS")
Module("EFS")
Sieg_interface("EFSSyscall")
sphinx_addon_syscall("EFSSyscall")
implementation("EFSSyscall")
Module("EFSUtils")
CommandModule("EFSCmd")

Extension({})


So, what does SyscallBoot do?

The quake procedure sphinx_addon_syscall instantiates SyscallBootGen.m3. The instatiated module calls SyscallBoot.

SyscallBoot does not install the systemcall handler on MachineTrap.Syscall event directly - doing so is prohibited by the authorizer of than event.

Instead, SyscallBoot installs a hook on the usyscall service. It installs a handler on USyscall.Rendezvous event. Whenever a user space app calls USyscall_Rendezvous with the extension(domain) name as the argument, the handler in SyscallBoot responds, and it installs the systemcall handler that is activated only for the current thread.

This means that loading the EFS syscall extension itself does not activate the service, the user app has to call usyscall to rendezvous with the extension.

User Side Code

The user side code to call usyscall rendezvous is usually hidden in the library code. In our case, efs_nuke and efs_create is first indirected to internal procedures, and they do rendezvous.

"efs.c" is the user side library module.



#include <stdio.h>
#include "efs.h"

static char efs_loaded;

int
efs_nuke (char *dir) 
{
    if (!efs_loaded) {
	__usyscall_bootstrap("EFS", "efs_nuke");
	efs_loaded = 1;
    }
    printf("nuke.\n");
    _efs_nuke(dir);
}

int 
efs_create (char *path, long size)
{
    if (!efs_loaded) {
	__usyscall_bootstrap("EFS", "efs_create");
	efs_loaded = 1;
    }
    printf("create.\n");
    _efs_create(path, size);
}

Compiling


THISTREE:=$(shell cd ../../../..; pwd)
include $(THISTREE)/make.conf


%:%.c
	$(CC) -non_shared -o $@ $^ -L. -lefs

all: libefs.a testefs

libefs.a: efs.o ../$(M3ARCH)/EFSSyscallUser.o \
    ../../../usyscall/$(M3ARCH)/USyscallUser.o \
    ../../../usyscall/lib/usyscall.o
	rm -f $@
	ar q $@ $^

../$(TARGET)/EFSSyscallUser.o:
	as -o $@ ../$(M3ARCH)/EFSSyscallUser.s

testefs: libefs.a


yasushi@cs.washington.edu