]> git.saurik.com Git - apple/xnu.git/blobdiff - libsyscall/xcodescripts/create-syscalls.pl
xnu-6153.11.26.tar.gz
[apple/xnu.git] / libsyscall / xcodescripts / create-syscalls.pl
index 68366de863ae019d369ed9155978e72cc041f16b..6bf15db9080f1038c36988200f80da1b93169b8b 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/perl
 #
-# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2006-2014 Apple Inc. All rights reserved.
 #
 # @APPLE_OSREFERENCE_LICENSE_HEADER_START@
 # 
@@ -23,7 +23,7 @@
 #
 ##########################################################################
 #
-# % create-syscalls.pl syscalls.master custom-directory out-directory
+# % create-syscalls.pl syscalls.master custom-directory platforms-directory platform-name out-directory
 #
 # This script fills the the out-directory with a Makefile.inc and *.s
 # files to create the double-underbar syscall stubs.  It reads the
@@ -61,7 +61,9 @@ my $OutDir;
 # size in bytes of known types (only used for i386)
 my %TypeBytes = (
     'au_asid_t'                => 4,
+    'sae_associd_t'    => 4,
     'caddr_t'          => 4,
+    'sae_connid_t'     => 4,
     'gid_t'            => 4,
     'id_t'             => 4,
     'idtype_t'         => 4,
@@ -89,31 +91,23 @@ my %TypeBytes = (
     'user_size_t'      => 4,
     'user_ssize_t'     => 4,
     'user_ulong_t'     => 4,
+    'uuid_t'           => 4,
+);
+
+# Types that potentially have different sizes in user-space compared to
+# kernel-space as well as whether the value should be sign/zero-extended when
+# passing the user/kernel boundary.
+my %UserKernelMismatchTypes = (
+    'long'          => 'SIGN_EXTEND',
+    'size_t'        => 'ZERO_EXTEND',
+    'u_long'        => 'ZERO_EXTEND',
+    'user_size_t'   => 'ZERO_EXTEND',
+    'user_ssize_t'  => 'SIGN_EXTEND'
 );
 
 # Moving towards storing all data in this hash, then we always know
 # if data is aliased or not, or promoted or not.
 my %Symbols = (
-    "quota" => {
-        c_sym => "quota",
-        syscall => "quota",
-        asm_sym => "_quota",
-        is_private => undef,
-        is_custom => undef,
-        nargs => 4,
-        bytes => 0,
-        aliases => {},
-    },
-    "setquota" => {
-        c_sym => "setquota",
-        syscall => "setquota",
-        asm_sym => "_setquota",
-        is_private => undef,
-        is_custom => undef,
-        nargs => 2,
-        bytes => 0,
-        aliases => {},
-    },
     "syscall" => {
         c_sym => "syscall",
         syscall => "syscall",
@@ -123,19 +117,43 @@ my %Symbols = (
         nargs => 0,
         bytes => 0,
         aliases => {},
+        mismatch_args => {}, # Arguments that might need to be zero/sign-extended
     },
 );
 
+# An explicit list of cancelable syscalls. For creating stubs that call the
+# cancellable version of cerror.
+my @Cancelable = qw/
+       accept access aio_suspend
+       close connect connectx
+       disconnectx
+       faccessat fcntl fdatasync fpathconf fstat fstatat fsync
+       getlogin
+       ioctl
+       link linkat lseek lstat
+       msgrcv msgsnd msync
+       open openat
+       pathconf peeloff poll posix_spawn pread pselect pwrite
+       read readv recvfrom recvmsg rename renameat
+       rename_ext
+       __semwait_signal __sigwait
+       select sem_wait semop sendmsg sendto sigsuspend stat symlink symlinkat sync
+       unlink unlinkat
+       wait4 waitid write writev
+/;
+
 sub usage {
-    die "Usage: $MyName syscalls.master custom-directory platforms-directory out-directory\n";
+    die "Usage: $MyName syscalls.master custom-directory platforms-directory platform-name out-directory\n";
 }
 
 ##########################################################################
 # Read the syscall.master file and collect the system call names and number
 # of arguments.  It looks for the NO_SYSCALL_STUB quailifier following the
 # prototype to determine if no automatic stub should be created by Libsystem.
-# System call name that are already prefixed with double-underbar are set as
-# if the NO_SYSCALL_STUB qualifier were specified (whether it is or not).
+#
+# The `sys_` prefix is stripped from syscall names, and is only kept for
+# the kernel symbol in order to avoid namespace clashes and identify
+# syscalls more easily.
 #
 # For the #if lines in syscall.master, all macros are assumed to be defined,
 # except COMPAT_GETFSSTAT (assumed undefined).
@@ -170,16 +188,20 @@ sub readMaster {
         my $no_syscall_stub = /\)\s*NO_SYSCALL_STUB\s*;/;
         my($name, $args) = /\s(\S+)\s*\(([^)]*)\)/;
         next if $name =~ /e?nosys/;
+        $name =~ s/^sys_//;
         $args =~ s/^\s+//;
         $args =~ s/\s+$//;
         my $argbytes = 0;
         my $nargs = 0;
+        my %mismatch_args;
         if($args ne '' && $args ne 'void') {
             my @a = split(',', $args);
             $nargs = scalar(@a);
-            # Calculate the size of all the arguments (only used for i386)
+            my $index = 0;
             for my $type (@a) {
                 $type =~ s/\s*\w+$//; # remove the argument name
+
+                # Calculate the size of all the arguments (only used for i386)
                 if($type =~ /\*$/) {
                     $argbytes += 4; # a pointer type
                 } else {
@@ -188,6 +210,12 @@ sub readMaster {
                     die "$MyName: $name: unknown type '$type'\n" unless defined($b);
                     $argbytes += $b;
                 }
+                # Determine which arguments might need to be zero/sign-extended
+                if(exists $UserKernelMismatchTypes{$type}) {
+                    $mismatch_args{$index} = $UserKernelMismatchTypes{$type};
+                }
+
+                $index++;
             }
         }
         $Symbols{$name} = {
@@ -199,6 +227,7 @@ sub readMaster {
             nargs => $nargs,
             bytes => $argbytes,
             aliases => {},
+            mismatch_args => \%mismatch_args, # Arguments that might need to be zero/sign-extended
             except => [],
         };
     }
@@ -216,7 +245,9 @@ sub checkForCustomStubs {
         $$sym{is_custom} = $source;
         if (!$$sym{is_private}) {
             foreach my $subarch (@Architectures) {
-                (my $arch = $subarch) =~ s/arm(.*)/arm/;
+                (my $arch = $subarch) =~ s/arm(v.*)/arm/;
+                $arch =~ s/x86_64(.*)/x86_64/;
+                $arch =~ s/arm64(.*)/arm64/;
                 $$sym{aliases}{$arch} = [] unless $$sym{aliases}{$arch};
                 push(@{$$sym{aliases}{$arch}}, $$sym{asm_sym});
             }
@@ -237,7 +268,9 @@ sub readAliases {
     
     my @a = ();
     for my $arch (@Architectures) {
-        (my $new_arch = $arch) =~ s/arm(.*)/arm/g;
+        (my $new_arch = $arch) =~ s/arm(v.*)/arm/g;
+        $new_arch =~ s/x86_64(.*)/x86_64/g;
+        $new_arch =~ s/arm64(.*)/arm64/g;
         push(@a, $new_arch) unless grep { $_ eq $new_arch } @a;
     }
     
@@ -293,32 +326,71 @@ sub writeStubForSymbol {
     my ($f, $symbol) = @_;
     
     my @conditions;
+    my $has_arm64 = 0;
     for my $subarch (@Architectures) {
-        (my $arch = $subarch) =~ s/arm(.*)/arm/;
+        (my $arch = $subarch) =~ s/arm(v.*)/arm/;
+        $arch =~ s/x86_64(.*)/x86_64/;
+        $arch =~ s/arm64(.*)/arm64/;
         push(@conditions, "defined(__${arch}__)") unless grep { $_ eq $arch } @{$$symbol{except}};
+
+        if($arch eq "arm64") {
+            $has_arm64 = 1 unless grep { $_ eq $arch } @{$$symbol{except}};
+        }
     }
-    
+
+    my %is_cancel;
+    for (@Cancelable) { $is_cancel{$_} = 1 };
+
     print $f "#define __SYSCALL_32BIT_ARG_BYTES $$symbol{bytes}\n";
     print $f "#include \"SYS.h\"\n\n";
+
+    if (scalar(@conditions)) {
+        printf $f "#ifndef SYS_%s\n", $$symbol{syscall};
+        printf $f "#error \"SYS_%s not defined. The header files libsyscall is building against do not match syscalls.master.\"\n", $$symbol{syscall};
+        printf $f "#endif\n\n";
+    }
+
+    my $nc = ($is_cancel{$$symbol{syscall}} ? "cerror" : "cerror_nocancel");
+
+    if($has_arm64) {
+        printf $f "#if defined(__arm64__)\n";
+        printf $f "MI_ENTRY_POINT(%s)\n", $$symbol{asm_sym};
+        if(keys %{$$symbol{mismatch_args}}) {
+            while(my($argnum, $extend) = each %{$$symbol{mismatch_args}}) {
+                printf $f "%s(%d)\n", $extend, $argnum;
+            }
+        }
+
+        printf $f "SYSCALL_NONAME(%s, %d, %s)\n", $$symbol{syscall}, $$symbol{nargs}, $nc;
+        printf $f "ret\n";
+        printf $f "#else\n";
+    }
+
     if (scalar(@conditions)) {
         printf $f "#if " . join(" || ", @conditions) . "\n";
-        printf $f "__SYSCALL(%s, %s, %d)\n", $$symbol{asm_sym}, $$symbol{syscall}, $$symbol{nargs};
+        printf $f "__SYSCALL2(%s, %s, %d, %s)\n", $$symbol{asm_sym}, $$symbol{syscall}, $$symbol{nargs}, $nc;
         if (!$$symbol{is_private} && (scalar(@conditions) < scalar(@Architectures))) {
             printf $f "#else\n";
-            printf $f "__SYSCALL(%s, %s, %d)\n", "__".$$symbol{asm_sym}, $$symbol{syscall}, $$symbol{nargs};
+            printf $f "__SYSCALL2(%s, %s, %d, %s)\n", "__".$$symbol{asm_sym}, $$symbol{syscall}, $$symbol{nargs}, $nc;
         }
         printf $f "#endif\n\n";
     } else {
         # actually this isnt an inconsistency. kernel can expose what it wants but if all our arches
         # override it we need to honour that.
     }
+
+    if($has_arm64) {
+        printf $f "#endif\n\n";
+    }
 }
 
 sub writeAliasesForSymbol {
     my ($f, $symbol) = @_;
     
     foreach my $subarch (@Architectures) {
-        (my $arch = $subarch) =~ s/arm(.*)/arm/;
+        (my $arch = $subarch) =~ s/arm(v.*)/arm/;
+        $arch =~ s/x86_64(.*)/x86_64/;
+        $arch =~ s/arm64(.*)/arm64/;
         
         next unless scalar($$symbol{aliases}{$arch});