Merge tag 'go1.11rc2'
Change-Id: I5e4800603950d6ae91dcde331c0f8161d254ecdc
diff --git a/BUILD.gn b/BUILD.gn
new file mode 100644
index 0000000..31d334d
--- /dev/null
+++ b/BUILD.gn
@@ -0,0 +1,122 @@
+# Copyright 2016 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/sysroot.gni")
+import("//build/go/go_test.gni")
+import("//build/host.gni")
+import("//build/package.gni")
+
+if (current_toolchain == target_toolchain) {
+ action("go_toolchain") {
+ go_root = "$host_tools_dir/goroot"
+
+ # These files are copied over to //out by makefuchsia.go.
+ copied_files = [
+ "misc/fuchsia/clangwrap.sh",
+ "misc/fuchsia/gccwrap.sh",
+ "misc/fuchsia/go_stdlib_tests.json",
+ ]
+
+ inputs = copied_files
+ inputs += [ "makefuchsia.go" ]
+
+ outputs = [
+ "$root_gen_dir/goroot.done",
+ ]
+ foreach(file, copied_files) {
+ outputs += [ "$go_root/$file" ]
+ }
+
+ depfile = "$root_gen_dir/goroot.d"
+
+ visibility = [ ":*" ]
+
+ script = rebase_path("//buildtools/go")
+ args = [
+ "run",
+ rebase_path("makefuchsia.go", root_build_dir),
+ "-buildtools-go",
+ rebase_path("//buildtools/go"),
+ "-fuchsia-goroot",
+ rebase_path("."),
+ "-depfile",
+ rebase_path(depfile),
+ "-root-gen-dir",
+ rebase_path("$root_gen_dir"),
+ "-root-out-dir",
+ rebase_path("$root_out_dir"),
+ "--out-goroot",
+ rebase_path(go_root),
+ "-target-cpu",
+ target_cpu,
+ ]
+ }
+
+ # A symlink from the old location to the new, while we're transitioning
+ # to the new.
+ action("old_go_toolchain_symlink") {
+ old_go_root = "$root_out_dir/goroot"
+ go_root = "$host_tools_dir/goroot"
+ script = "make-goroot-symlink.sh"
+ args = [
+ rebase_path(go_root),
+ rebase_path(old_go_root),
+ ]
+ outputs = [
+ old_go_root
+ ]
+ deps = [
+ ":go_toolchain"
+ ]
+ }
+}
+
+group("go_runtime") {
+ public_deps = [
+ ":go_toolchain(${target_toolchain})",
+ ":old_go_toolchain_symlink(${target_toolchain})",
+ ]
+}
+
+go_test("go_dispatch_test") {
+ gopackage = "syscall/zx/dispatch"
+}
+
+go_test("go_zxwait_test") {
+ gopackage = "syscall/zx/zxwait"
+}
+
+go_test("go_os_test") {
+ gopackage = "os"
+}
+
+go_test("go_net_test") {
+ gopackage = "net"
+}
+
+package("go_stdlib_tests") {
+ testonly = true
+
+ deps = [
+ ":go_dispatch_test",
+ ":go_os_test",
+ ":go_net_test",
+ ":go_zxwait_test",
+ ]
+
+ tests = [
+ {
+ name = "go_dispatch_test"
+ },
+ {
+ name = "go_net_test"
+ },
+ {
+ name = "go_os_test"
+ },
+ {
+ name = "go_zxwait_test"
+ },
+ ]
+}
diff --git a/make-goroot-symlink.sh b/make-goroot-symlink.sh
new file mode 100755
index 0000000..ecc5d76
--- /dev/null
+++ b/make-goroot-symlink.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+# Copyright 2018 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Make a symlink, handling the case where the source is a directory
+# by removing the source first.
+# "ln -sf" doesn't work in this case: the symbolic link is placed in the
+# directory named LINK-NAME.
+# For paranoia purposes, this script only works if the basename of
+# TARGET and LINK-NAME are "goroot". This is to avoid accidents resulting
+# in rm -rf removing way more than intended.
+
+set -e
+
+if [[ $# != 2 ]]
+then
+ echo >&2 "Usage: $(basename $0) TARGET LINK-NAME"
+ exit 1
+fi
+
+declare -r TARGET=$1
+declare -r LINK_NAME=$2
+
+if [[ $(basename "$TARGET") != "goroot" ]]
+then
+ echo >&2 "TARGET basename is not goroot"
+ exit 1
+fi
+if [[ $(basename "$LINK_NAME") != "goroot" ]]
+then
+ echo >&2 "LINK-NAME basename is not goroot"
+ exit 1
+fi
+
+/bin/rm -rf "$LINK_NAME"
+/bin/ln -s "$TARGET" "$LINK_NAME"
diff --git a/makefuchsia.go b/makefuchsia.go
new file mode 100644
index 0000000..d2c995b
--- /dev/null
+++ b/makefuchsia.go
@@ -0,0 +1,187 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// The makefuchsia.go script builds a GOROOT in the out/ build directory
+// using sources from third_party/go.
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+)
+
+var (
+ flagBuildtoolsGo = flag.String("buildtools-go", "", "Path to go tool used for bootstrap")
+ flagFuchsiaGoroot = flag.String("fuchsia-goroot", "", "Path to Fuchsia's source GOROOT")
+ flagDepfile = flag.String("depfile", "", "Stdlib depfile")
+ flagRootOutDir = flag.String("root-out-dir", "", "GN variable")
+ flagRootGenDir = flag.String("root-gen-dir", "", "GN variable")
+ flagTargetCPU = flag.String("target-cpu", "", "GN variable")
+ flagOutGoroot = flag.String("out-goroot", "", "Path to the output GOROOT")
+)
+
+func relGenDir() string {
+ return (*flagRootGenDir)[len(*flagRootOutDir)+1:]
+}
+
+func mkdir(path ...string) {
+ if err := os.MkdirAll(join(path...), 0755); err != nil {
+ log.Fatal(err)
+ }
+}
+
+func join(path ...string) string { return filepath.Join(path...) }
+
+// copyfile copies src to dst if the two files have different contents.
+func copyfile(src, dst string) {
+ srcfile, err := os.Open(src)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer srcfile.Close()
+
+ fi, err := srcfile.Stat()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ mkdir(filepath.Dir(dst))
+ f, err := os.OpenFile(dst, os.O_CREATE|os.O_RDWR|os.O_TRUNC, fi.Mode())
+ if err != nil {
+ log.Fatal(err)
+ }
+ if _, err := io.Copy(f, srcfile); err != nil {
+ log.Fatalf("cp %s %s: %v", src, dst, err)
+ }
+ if err := f.Close(); err != nil {
+ log.Fatalf("cp %s %s: close: %v", src, dst, err)
+ }
+}
+
+func convCPU(cpu string) (arch string) {
+ switch cpu {
+ case "x64":
+ return "amd64"
+ case "arm64":
+ return "arm64"
+ }
+ return ""
+}
+
+// allFilesIn recursively walks a set of files, returning the entire tree in
+// paths relative to the given root. A map is returned for convenience. If
+// prefix is given, only files that match the prefix are considered.
+func allFilesIn(root string, paths map[string]struct{}, prefix ...string) error {
+ return filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
+ if err != nil || info.IsDir() {
+ return err
+ }
+ for _, pfx := range prefix {
+ if strings.HasPrefix(path, join(root, pfx)) {
+ relPath := strings.TrimPrefix(path, root)[1:]
+ paths[relPath] = struct{}{}
+ return err
+ }
+ }
+ return err
+ })
+}
+
+func main() {
+ log.SetFlags(0)
+ log.SetPrefix("makefuchsia.go: ")
+ flag.Parse()
+
+ if *flagRootGenDir == "" {
+ log.Fatal("must specify -root-gen-dir")
+ }
+
+ if *flagFuchsiaGoroot == "" {
+ log.Fatal("must specify -fuchsia-goroot when building toolchain")
+ }
+
+ goarchTarget := convCPU(*flagTargetCPU)
+ if goarchTarget == "" {
+ log.Fatalf("unsupported target CPU: %s", *flagTargetCPU)
+ }
+
+ srcGoroot := *flagFuchsiaGoroot
+ dstGoroot := *flagOutGoroot
+
+ srcFiles := map[string]struct{}{}
+ if err := allFilesIn(join(srcGoroot), srcFiles, "src/", "misc/fuchsia/"); err != nil {
+ log.Fatal(err)
+ }
+
+ dstFiles := map[string]struct{}{}
+ if _, err := os.Stat(join(dstGoroot)); err == nil {
+ if err := allFilesIn(join(dstGoroot), dstFiles, ""); err != nil {
+ log.Fatal(err)
+ }
+ }
+
+ for f := range dstFiles {
+ if _, ok := srcFiles[f]; !ok {
+ // try to preserve the bin/ and pkg/ trees, as they can be used to do faster
+ // rebuilds of the toolchain.
+ if strings.HasPrefix(f, "src/") || strings.HasPrefix(f, "misc/fuchsia/") {
+ os.Remove(filepath.Join(dstGoroot, f))
+ }
+ }
+ }
+
+ for f := range srcFiles {
+ src, dst := join(srcGoroot, f), join(dstGoroot, f)
+ copyfile(src, dst)
+ }
+
+ versionFile := join(dstGoroot, "VERSION")
+ if err := ioutil.WriteFile(versionFile, []byte("devel third_party/go fuchsia"), 0664); err != nil {
+ log.Fatal(err)
+ }
+
+ cmd := exec.Command(*flagBuildtoolsGo, "env", "GOROOT")
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ log.Fatalf("cannot find bootstrap GOROOT: %v", err)
+ }
+
+ env := os.Environ()
+ env = append(env, "GOROOT_BOOTSTRAP="+strings.TrimSpace(string(out)))
+ env = append(env, "CC_FOR_fuchsia_"+goarchTarget+"="+dstGoroot+"/misc/fuchsia/gccwrap.sh")
+
+ cmd = exec.Command(join(dstGoroot, "src", "make.bash"))
+ cmd.Args = []string{"--no-clean"}
+ cmd.Dir = join(dstGoroot, "src")
+ cmd.Env = env
+ buf := new(bytes.Buffer)
+ cmd.Stdout = buf
+ cmd.Stderr = buf
+ if err := cmd.Run(); err != nil {
+ log.Fatalf("make.bash failed: %v\n%s", err, buf.String())
+ }
+
+ depfile, err := os.Create(*flagDepfile)
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Fprintf(depfile, "%s/goroot.done:", relGenDir())
+ for f := range srcFiles {
+ fmt.Fprintf(depfile, " %s", join(srcGoroot, f))
+ }
+ fmt.Fprintf(depfile, " %s", join(srcGoroot, "makefuchsia.go"))
+
+ donePath := join(*flagRootGenDir, "goroot.done")
+ if err := ioutil.WriteFile(donePath, []byte("done"), 0664); err != nil {
+ log.Fatalf("writing goroot.done failed: %v", err)
+ }
+}
diff --git a/misc/fuchsia/README.md b/misc/fuchsia/README.md
new file mode 100644
index 0000000..e26e84b
--- /dev/null
+++ b/misc/fuchsia/README.md
@@ -0,0 +1,47 @@
+Go on Fuchsia
+=========
+
+To build a toolchain on Linux for Fuchsia, first follow the
+instructions on
+
+ https://fuchsia.googlesource.com/manifest/
+
+Then,
+* Set the SDK environment variable to the location of the Fuchsia SDK:
+ If you downloaded fuchsia to your ${HOME} directory:
+ ```
+ export SDK=${HOME}/fuchsia/buildtools
+ ```
+
+* Identify where a host version of go exists, with:
+ ```
+ export GOROOT_BOOTSTRAP=`path to directory containing go`
+ ```
+ On my machine, `which go` returned /usr/lib/golang/bin/go, so I set
+ GOROOT_BOOTSTRAP=/usr/lib/golang/
+
+* Build Go in `fuchsia/third_party/go/src` using
+ ```
+ GOOS=fuchsia CC_FOR_TARGET=../misc/fuchsia/clangwrap.sh ./make.bash
+ ```
+
+* To build a program, junk.go in go/src, use:
+ ```
+ GOOS=fuchsia ../bin/go build junk.go
+ ```
+ This program can be put in a bootfs and run on qemu with:
+ ```
+ echo bin/junk=junk > junk.manifest
+ fuchsia/buildtools/mkbootfs -o junk.bootfs junk.manifest
+ ./scripts/run-zircon-x64 -x path/to/fuchsia/third_party/go/src/junk.bootfs
+ ```
+ A cgo variant can be build by adding CGO_ENABLED=1 to both
+ the make.bash command and the go build command.
+
+* To build a program using just the zircon prebuild toolchain
+ (useful for debugging if the fuchsia sysroot is out of sync
+ with your zircon) set the environment variable ZIRCON to
+ the location of your zircon and build with the gccwrap.sh
+ script:
+ ```
+ ZIRCON=$HOME/zircon CGO_ENABLED=1 CC_FOR_TARGET=$(pwd)/../misc/fuchsia/gccwrap.sh GOOS=fuchsia ./make.bash
diff --git a/misc/fuchsia/clangwrap.sh b/misc/fuchsia/clangwrap.sh
new file mode 100755
index 0000000..40514e2
--- /dev/null
+++ b/misc/fuchsia/clangwrap.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+# This uses the Fuchsia clang and Zircon sysroot.
+set -eu
+
+if [ "$GOHOSTARCH" == "amd64" ]; then
+ HOST_ARCH="x64"
+elif [ "$GOHOSTARCH" == "arm64" ]; then
+ HOST_ARCH="arm64"
+else
+ echo "clangwrap.sh: missing/invalid GOHOSTARCH env variable" >&2
+ exit 1
+fi
+
+if [ "$GOHOSTOS" == "linux" ]; then
+ HOST_OS="linux"
+elif [ "$GOHOSTOS" == "darwin" ]; then
+ HOST_OS="mac"
+else
+ echo "clangwrap.sh: missing/invalid GOHOSTOS env variable" >&2
+ exit 1
+fi
+
+if [ "$GOARCH" == "amd64" ]; then
+ TARGET_ARCH="x86_64"
+elif [ "$GOHOSTARCH" == "arm64" ]; then
+ TARGET_ARCH="aarch64"
+else
+ echo "clangwrap.sh: missing/invalid GOARCH env variable" >&2
+ exit 1
+fi
+
+if [ "$FUCHSIA" == "" ]; then
+ echo "clangwrap.sh: missing FUCHSIA env variable" >&2
+ exit 1
+fi
+
+exec ${FUCHSIA}/buildtools/${HOST_OS}-${HOST_ARCH}/clang/bin/clang \
+ --target=${TARGET_ARCH}-fuchsia \
+ --sysroot=${FUCHSIA}/out/sysroot/${TARGET_ARCH}-fuchsia \
+ "$@"
diff --git a/misc/fuchsia/gccwrap.sh b/misc/fuchsia/gccwrap.sh
new file mode 100755
index 0000000..93c86cd
--- /dev/null
+++ b/misc/fuchsia/gccwrap.sh
@@ -0,0 +1,66 @@
+#!/bin/bash
+# This uses the zircon prebuild C++ toolchain
+
+if [ -z "${ZIRCON}" ]; then
+ echo "gccwrap.sh: missing ZIRCON env variable" >&2
+ exit 1
+fi
+
+zirconsysroot="${ZIRCON_SYSROOT}"
+if [ -z "${zirconsysroot}" ]; then
+ echo "gccwrap.sh: missing ZIRCON_SYSROOT env variable" >&2
+ exit 1
+fi
+
+if [ -z "${FUCHSIA_ROOT_OUT_DIR}" ]; then
+ echo "gccwrap.sh: missing FUCHSIA_ROOT_OUT_DIR env variable" >&2
+ exit 1
+fi
+
+if [ "$GOARCH" == "amd64" ]; then
+ libdir="x64-shared"
+ gccbin="$ZIRCON/prebuilt/downloads/gcc/bin/x86_64-elf-gcc"
+elif [ "$GOARCH" == "arm64" ]; then
+ libdir="arm64-shared"
+ gccbin="$ZIRCON/prebuilt/downloads/gcc/bin/aarch64-elf-gcc"
+else
+ echo "gccwrap.sh: unsupported GOARCH: $GOARCH" >&2
+ exit 1
+fi
+
+compiler=false
+extra_args=""
+
+for var in "$@"
+do
+ if [[ "$var" == "-r" || "$var" == "-c" ]]; then
+ compiler=true
+ fi
+done
+
+if ! $compiler; then
+ extra_args="-lc $zirconsysroot/lib/Scrt1.o $zirconsysroot/lib/libzircon.so -lfdio"
+fi
+
+exec $gccbin \
+ --sysroot=$zirconsysroot \
+ -I$zirconsysroot/include \
+ -I${ZIRCON}/system/ulib/fdio/include \
+ -L$zirconsysroot/lib \
+ -L${FUCHSIA_ROOT_OUT_DIR}/${libdir} \
+ -nostdlib \
+ -fuse-ld=gold \
+ -fno-use-linker-plugin \
+ -Wl,-nostdlib \
+ -Wl,--build-id \
+ -Wl,-z,max-page-size=4096 \
+ -Wl,-z,combreloc \
+ -Wl,-z,relro \
+ -Wl,-z,now \
+ -Wl,-z,text \
+ -Wl,-z,noexecstack \
+ -Wl,--hash-style=gnu \
+ -Wl,--eh-frame-hdr \
+ -Wl,-dynamic-linker=ld.so.1 \
+ $extra_args \
+ "$@"
diff --git a/misc/fuchsia/go_stdlib_tests.json b/misc/fuchsia/go_stdlib_tests.json
new file mode 100644
index 0000000..e52c708
--- /dev/null
+++ b/misc/fuchsia/go_stdlib_tests.json
@@ -0,0 +1,8 @@
+{
+ "tests":[
+ {
+ "name":"go_os_test",
+ "exec":"/system/bin/report_result /system/test/go_os_test"
+ }
+ ]
+}
diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go
index eed9866..a4eeb3d 100644
--- a/src/cmd/dist/build.go
+++ b/src/cmd/dist/build.go
@@ -81,6 +81,7 @@
"android",
"solaris",
"freebsd",
+ "fuchsia",
"nacl",
"netbsd",
"openbsd",
@@ -1034,6 +1035,8 @@
xremoveall(pathf("%s/pkg/%s_%s", goroot, goos, goarch))
xremoveall(pathf("%s/pkg/%s_%s_race", goroot, gohostos, gohostarch))
xremoveall(pathf("%s/pkg/%s_%s_race", goroot, goos, goarch))
+ xremoveall(pathf("%s/pkg/%s_%s_shared", goroot, gohostos, gohostarch))
+ xremoveall(pathf("%s/pkg/%s_%s_shared", goroot, goos, goarch))
xremoveall(tooldir)
// Remove cached version info.
@@ -1390,6 +1393,8 @@
"freebsd/386": true,
"freebsd/amd64": true,
"freebsd/arm": false,
+ "fuchsia/amd64": true,
+ "fuchsia/arm64": true,
"linux/386": true,
"linux/amd64": true,
"linux/arm": true,
diff --git a/src/cmd/go/internal/base/signal_notunix.go b/src/cmd/go/internal/base/signal_notunix.go
index 9e869b0..a8e5a34 100644
--- a/src/cmd/go/internal/base/signal_notunix.go
+++ b/src/cmd/go/internal/base/signal_notunix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build plan9 windows
+// +build plan9 fuchsia windows
package base
diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go
index ec2fa73..1f6e72c 100644
--- a/src/cmd/go/internal/load/pkg.go
+++ b/src/cmd/go/internal/load/pkg.go
@@ -1550,6 +1550,11 @@
// LinkerDeps returns the list of linker-induced dependencies for main package p.
func LinkerDeps(p *Package) []string {
+ // Don't add deps to Fuchsia internal syscall stuff.
+ if p.ImportPath == "syscall/zx" || p.ImportPath == "syscall/mx" {
+ return []string{}
+ }
+
// Everything links runtime.
deps := []string{"runtime"}
@@ -1578,7 +1583,7 @@
func externalLinkingForced(p *Package) bool {
// Some targets must use external linking even inside GOROOT.
switch cfg.BuildContext.GOOS {
- case "android":
+ case "android", "fuchsia":
return true
case "darwin":
switch cfg.BuildContext.GOARCH {
diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go
index 42fa0e6..0ec6710 100644
--- a/src/cmd/go/internal/work/exec.go
+++ b/src/cmd/go/internal/work/exec.go
@@ -2157,6 +2157,7 @@
switch cfg.Goos {
case "windows":
a = append(a, "-mthreads")
+ case "fuchsia":
default:
a = append(a, "-pthread")
}
diff --git a/src/cmd/go/internal/work/gccgo.go b/src/cmd/go/internal/work/gccgo.go
index 91daf52..1e30cf2 100644
--- a/src/cmd/go/internal/work/gccgo.go
+++ b/src/cmd/go/internal/work/gccgo.go
@@ -395,7 +395,12 @@
// split-stack and non-split-stack code in a single -r
// link, and libgo picks up non-split-stack code from
// libffi.
- ldflags = append(ldflags, "-Wl,-r", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive")
+ if cfg.Goos == "fuchsia" {
+ ldflags = append(ldflags, "-r")
+ } else {
+ ldflags = append(ldflags, "-Wl,-r")
+ }
+ ldflags = append(ldflags, "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive")
if nopie := b.gccNoPie([]string{tools.linker()}); nopie != "" {
ldflags = append(ldflags, nopie)
diff --git a/src/cmd/go/internal/work/init.go b/src/cmd/go/internal/work/init.go
index eb99815..bf2cefe 100644
--- a/src/cmd/go/internal/work/init.go
+++ b/src/cmd/go/internal/work/init.go
@@ -123,7 +123,8 @@
ldBuildmode = "c-shared"
case "default":
switch platform {
- case "android/arm", "android/arm64", "android/amd64", "android/386":
+ case "android/arm", "android/arm64", "android/amd64", "android/386",
+ "fuchsia/amd64", "fuchsia/arm64":
codegenArg = "-shared"
ldBuildmode = "pie"
case "darwin/arm", "darwin/arm64":
@@ -151,7 +152,8 @@
switch platform {
case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x",
"android/amd64", "android/arm", "android/arm64", "android/386",
- "freebsd/amd64":
+ "freebsd/amd64",
+ "fuchsia/amd64", "fuchsia/arm64":
codegenArg = "-shared"
case "darwin/amd64":
codegenArg = "-shared"
diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go
index d3389e4..ad21e38 100644
--- a/src/cmd/internal/obj/x86/asm6.go
+++ b/src/cmd/internal/obj/x86/asm6.go
@@ -2350,6 +2350,9 @@
return 0x64 // FS
}
+ case objabi.Hfuchsia:
+ log.Fatalf("unknown TLS base register, fuchsia requires PIC code")
+
case objabi.Hdragonfly,
objabi.Hfreebsd,
objabi.Hnetbsd,
@@ -4977,7 +4980,7 @@
default:
log.Fatalf("unknown TLS base location for %v", ctxt.Headtype)
- case objabi.Hlinux, objabi.Hfreebsd:
+ case objabi.Hlinux, objabi.Hfreebsd, objabi.Hfuchsia:
if !ctxt.Flag_shared {
log.Fatalf("unknown TLS base location for linux/freebsd without -shared")
}
diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go
index 139f293..7e42dcc 100644
--- a/src/cmd/internal/obj/x86/obj6.go
+++ b/src/cmd/internal/obj/x86/obj6.go
@@ -67,6 +67,8 @@
return false
case objabi.Hlinux, objabi.Hfreebsd:
return !ctxt.Flag_shared
+ case objabi.Hfuchsia:
+ return false
}
return true
diff --git a/src/cmd/internal/objabi/head.go b/src/cmd/internal/objabi/head.go
index 23c7b62..521876a 100644
--- a/src/cmd/internal/objabi/head.go
+++ b/src/cmd/internal/objabi/head.go
@@ -40,6 +40,7 @@
Hdarwin
Hdragonfly
Hfreebsd
+ Hfuchsia
Hjs
Hlinux
Hnacl
@@ -58,6 +59,8 @@
*h = Hdragonfly
case "freebsd":
*h = Hfreebsd
+ case "fuchsia":
+ *h = Hfuchsia
case "js":
*h = Hjs
case "linux", "android":
@@ -88,6 +91,8 @@
return "dragonfly"
case Hfreebsd:
return "freebsd"
+ case Hfuchsia:
+ return "fuchsia"
case Hjs:
return "js"
case Hlinux:
diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go
index af27444..7817240 100644
--- a/src/cmd/link/internal/amd64/asm.go
+++ b/src/cmd/link/internal/amd64/asm.go
@@ -37,6 +37,7 @@
"cmd/link/internal/sym"
"debug/elf"
"log"
+ "strings"
)
func PADDR(x uint32) uint32 {
@@ -414,6 +415,8 @@
if r.Siz == 4 {
if r.Xsym.Type == sym.SDYNIMPORT && r.Xsym.ElfType == elf.STT_FUNC {
ctxt.Out.Write64(uint64(elf.R_X86_64_PLT32) | uint64(elfsym)<<32)
+ } else if r.Xsym.Type == sym.SDYNIMPORT && ctxt.HeadType == objabi.Hfuchsia && strings.HasPrefix(r.Xsym.Name, "vdso_") {
+ ctxt.Out.Write64(uint64(elf.R_X86_64_GOTPCREL) | uint64(elfsym)<<32)
} else {
ctxt.Out.Write64(uint64(elf.R_X86_64_PC32) | uint64(elfsym)<<32)
}
@@ -723,6 +726,7 @@
case objabi.Hlinux,
objabi.Hfreebsd,
+ objabi.Hfuchsia,
objabi.Hnetbsd,
objabi.Hopenbsd,
objabi.Hdragonfly,
@@ -753,6 +757,7 @@
case objabi.Hlinux,
objabi.Hfreebsd,
+ objabi.Hfuchsia,
objabi.Hnetbsd,
objabi.Hopenbsd,
objabi.Hdragonfly,
@@ -833,6 +838,7 @@
case objabi.Hlinux,
objabi.Hfreebsd,
+ objabi.Hfuchsia,
objabi.Hnetbsd,
objabi.Hopenbsd,
objabi.Hdragonfly,
diff --git a/src/cmd/link/internal/amd64/obj.go b/src/cmd/link/internal/amd64/obj.go
index 87e8091..96f5e66 100644
--- a/src/cmd/link/internal/amd64/obj.go
+++ b/src/cmd/link/internal/amd64/obj.go
@@ -105,6 +105,7 @@
case objabi.Hlinux, /* elf64 executable */
objabi.Hfreebsd, /* freebsd */
+ objabi.Hfuchsia, /* fuchsia */
objabi.Hnetbsd, /* netbsd */
objabi.Hopenbsd, /* openbsd */
objabi.Hdragonfly, /* dragonfly */
diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go
index 5b3b9e5..d899d45 100644
--- a/src/cmd/link/internal/arm64/asm.go
+++ b/src/cmd/link/internal/arm64/asm.go
@@ -363,7 +363,7 @@
return true
case objabi.R_ARM64_TLS_LE:
r.Done = false
- if ctxt.HeadType != objabi.Hlinux {
+ if ctxt.HeadType != objabi.Hlinux && ctxt.HeadType != objabi.Hfuchsia {
ld.Errorf(s, "TLS reloc on unsupported OS %v", ctxt.HeadType)
}
// The TCB is two pointers. This is not documented anywhere, but is
@@ -514,6 +514,7 @@
case objabi.Hlinux,
objabi.Hfreebsd,
+ objabi.Hfuchsia,
objabi.Hnetbsd,
objabi.Hopenbsd,
objabi.Hnacl:
diff --git a/src/cmd/link/internal/arm64/obj.go b/src/cmd/link/internal/arm64/obj.go
index 405d22d..3a14d43 100644
--- a/src/cmd/link/internal/arm64/obj.go
+++ b/src/cmd/link/internal/arm64/obj.go
@@ -87,7 +87,7 @@
*ld.FlagRound = 4096
}
- case objabi.Hlinux: /* arm64 elf */
+ case objabi.Hlinux, objabi.Hfuchsia: /* arm64 elf */
ld.Elfinit(ctxt)
ld.HEADR = ld.ELFRESERVE
if *ld.FlagTextAddr == -1 {
diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go
index 18fbea6..f9d438c 100644
--- a/src/cmd/link/internal/ld/config.go
+++ b/src/cmd/link/internal/ld/config.go
@@ -35,10 +35,13 @@
default:
return fmt.Errorf("invalid buildmode: %q", s)
case "exe":
+ if objabi.GOOS == "fuchsia" {
+ return badmode()
+ }
*mode = BuildModeExe
case "pie":
switch objabi.GOOS {
- case "android", "linux":
+ case "android", "linux", "fuchsia":
case "darwin", "freebsd":
switch objabi.GOARCH {
case "amd64":
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index 0ae93f1..a2b4443 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -162,8 +162,8 @@
}
// We need to be able to reference dynimport symbols when linking against
- // shared libraries, and Solaris and Darwin need it always
- if ctxt.HeadType != objabi.Hsolaris && ctxt.HeadType != objabi.Hdarwin && r.Sym != nil && r.Sym.Type == sym.SDYNIMPORT && !ctxt.DynlinkingGo() && !r.Sym.Attr.SubSymbol() {
+ // shared libraries; Solaris, Fuchsia, and Darwin need it always
+ if ctxt.HeadType != objabi.Hsolaris && ctxt.HeadType != objabi.Hdarwin && ctxt.HeadType != objabi.Hfuchsia && r.Sym != nil && r.Sym.Type == sym.SDYNIMPORT && !ctxt.DynlinkingGo() && !r.Sym.Attr.SubSymbol() {
if !(ctxt.Arch.Family == sys.PPC64 && ctxt.LinkMode == LinkExternal && r.Sym.Name == ".TOC.") {
Errorf(s, "unhandled relocation for %s (type %d (%s) rtype %d (%s))", r.Sym.Name, r.Sym.Type, r.Sym.Type, r.Type, sym.RelocName(ctxt.Arch, r.Type))
}
diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go
index 4ecbff8..49089c0 100644
--- a/src/cmd/link/internal/ld/elf.go
+++ b/src/cmd/link/internal/ld/elf.go
@@ -1848,6 +1848,9 @@
case objabi.Hfreebsd:
interpreter = thearch.Freebsddynld
+ case objabi.Hfuchsia:
+ interpreter = "lib/ld.so.1"
+
case objabi.Hnetbsd:
interpreter = thearch.Netbsddynld
@@ -2085,7 +2088,7 @@
}
}
- if ctxt.HeadType == objabi.Hlinux {
+ if ctxt.HeadType == objabi.Hlinux || ctxt.HeadType == objabi.Hfuchsia {
ph := newElfPhdr()
ph.type_ = PT_GNU_STACK
ph.flags = PF_W + PF_R
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index 220aab3..d89bbea 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -1213,7 +1213,10 @@
}
// Force global symbols to be exported for dlopen, etc.
- if ctxt.IsELF {
+ if ctxt.HeadType == objabi.Hfuchsia && !strings.Contains(argv[0], "clang") {
+ // Find libgcc
+ argv = append(argv, ctxt.findLibPathCmd("--print-libgcc-file-name", "libgcc"))
+ } else if ctxt.IsELF {
argv = append(argv, "-rdynamic")
}
@@ -1314,6 +1317,9 @@
argv = append(argv, "-Wl,--start-group", "-lmingwex", "-lmingw32", "-Wl,--end-group")
argv = append(argv, peimporteddlls()...)
}
+ if ctxt.HeadType == objabi.Hfuchsia && strings.Contains(argv[0], "clang") {
+ argv = append(argv, "-lzircon", "-lfdio")
+ }
if ctxt.Debugvlog != 0 {
ctxt.Logf("%5.2f host link:", Cputime())
diff --git a/src/cmd/link/internal/ld/sym.go b/src/cmd/link/internal/ld/sym.go
index 3aa90c1..d8ea7ed 100644
--- a/src/cmd/link/internal/ld/sym.go
+++ b/src/cmd/link/internal/ld/sym.go
@@ -96,6 +96,9 @@
ctxt.Tlsoffset = -1 * ctxt.Arch.PtrSize
}
+ case objabi.Hfuchsia:
+ ctxt.Tlsoffset = -1 * ctxt.Arch.PtrSize
+
case objabi.Hnacl:
switch ctxt.Arch.Family {
default:
diff --git a/src/crypto/rand/rand_fuchsia.go b/src/crypto/rand/rand_fuchsia.go
new file mode 100644
index 0000000..40be276
--- /dev/null
+++ b/src/crypto/rand/rand_fuchsia.go
@@ -0,0 +1,25 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package rand
+
+import "syscall/zx"
+
+func init() {
+ Reader = new(cprngReader)
+}
+
+// cprngReader uses the PRNG exposed by zircon syscall.
+//
+// TODO(crawshaw): does it perform as well as /dev/urandom?
+// If not, borrow newReader from rand_unix.go and use this
+// as the entropy source.
+type cprngReader struct{}
+
+func (r *cprngReader) Read(b []byte) (n int, err error) {
+ zx.RandRead(b)
+ return len(b), nil
+}
diff --git a/src/crypto/x509/root_darwin_armx.go b/src/crypto/x509/root_darwin_armx.go
index fcbbd6b..87c9334 100644
--- a/src/crypto/x509/root_darwin_armx.go
+++ b/src/crypto/x509/root_darwin_armx.go
@@ -4,9 +4,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build cgo
-// +build darwin
-// +build arm arm64 ios
+// +build cgo,darwin,arm cgo,darwin,arm64 ios fuchsia
package x509
diff --git a/src/crypto/x509/root_fuchsia.go b/src/crypto/x509/root_fuchsia.go
new file mode 100644
index 0000000..bf37319
--- /dev/null
+++ b/src/crypto/x509/root_fuchsia.go
@@ -0,0 +1,9 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
+ return nil, nil
+}
diff --git a/src/go/build/syslist.go b/src/go/build/syslist.go
index d7938fa..2ccc386 100644
--- a/src/go/build/syslist.go
+++ b/src/go/build/syslist.go
@@ -4,5 +4,5 @@
package build
-const goosList = "android darwin dragonfly freebsd js linux nacl netbsd openbsd plan9 solaris windows zos "
+const goosList = "android darwin dragonfly freebsd fuchsia js linux nacl netbsd openbsd plan9 solaris windows zos "
const goarchList = "386 amd64 amd64p32 arm armbe arm64 arm64be ppc64 ppc64le mips mipsle mips64 mips64le mips64p32 mips64p32le ppc riscv riscv64 s390 s390x sparc sparc64 wasm "
diff --git a/src/internal/poll/fd_fuchsia.go b/src/internal/poll/fd_fuchsia.go
new file mode 100644
index 0000000..ccdd9e5
--- /dev/null
+++ b/src/internal/poll/fd_fuchsia.go
@@ -0,0 +1,305 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package poll
+
+import (
+ "io"
+ "sync/atomic"
+ "syscall"
+ "syscall/zx/fdio"
+ "syscall/zx/zxsocket"
+)
+
+// FD is a file descriptor. The net and os packages embed this type in
+// a larger type representing a network connection or OS file.
+type FD struct {
+ // Lock sysfd and serialize access to Read and Write methods.
+ fdmu fdMutex
+
+ // System file descriptor. Immutable until Close.
+ Sysfd int
+ Handle fdio.FDIO
+
+ // I/O poller.
+ pd pollDesc
+
+ // Semaphore signaled when file is closed.
+ csema uint32
+
+ // Whether this is a streaming descriptor, as opposed to a
+ // packet-based descriptor like a UDP socket.
+ IsStream bool
+
+ // Whether a zero byte read indicates EOF. This is false for a
+ // message based socket connection.
+ ZeroReadIsEOF bool
+
+ // Whether this is a normal file.
+ isFile bool
+
+ // Whether in blocking mode
+ isBlocking uint32
+}
+
+// Init initializes the FD. The Sysfd field should already be set.
+// This can be called multiple times on a single FD.
+// The net argument is a network name from the net package (e.g., "tcp"),
+// or "file".
+// Set pollable to true if fd should be managed by runtime netpoll.
+func (fd *FD) Init(net string, pollable bool) error {
+ // We don't actually care about the various network types.
+ if net == "file" {
+ fd.isFile = true
+ }
+ if fd.Handle == nil {
+ fd.Handle = syscall.FDIOForFD(fd.Sysfd)
+ if fd.Handle == nil {
+ panic("No Handle available")
+ }
+ }
+ if !pollable {
+ fd.isBlocking = 1
+ return nil
+ }
+ return fd.pd.init(fd)
+}
+
+// Destroy closes the file descriptor. This is called when there are
+// no remaining references.
+func (fd *FD) destroy() error {
+ // Poller may want to unregister fd in readiness notification mechanism,
+ // so this must be executed before closing the fd.
+ fd.pd.close()
+ err := fd.Handle.Close()
+ fd.Sysfd = -1
+ fd.Handle = nil
+ runtime_Semrelease(&fd.csema)
+ return err
+}
+
+// Close closes the FD. The underlying file descriptor is closed by the
+// destroy method when there are no remaining references.
+func (fd *FD) Close() error {
+ if !fd.fdmu.increfAndClose() {
+ return errClosing(fd.isFile)
+ }
+ fd.pd.evict()
+ err := fd.decref()
+ // Wait until the descriptor is closed. If this was the only
+ // reference, it is already closed.
+ runtime_Semacquire(&fd.csema)
+ return err
+}
+
+// Shutdown wraps the shutdown network call.
+func (fd *FD) Shutdown(how int) error {
+ if err := fd.incref(); err != nil {
+ return err
+ }
+ defer fd.decref()
+ panic("TODO shutdown")
+ //return syscall.Shutdown(fd.Sysfd, how) // TODO
+}
+
+func (fd *FD) Read(p []byte) (int, error) {
+ if err := fd.readLock(); err != nil {
+ return 0, err
+ }
+ defer fd.readUnlock()
+ if len(p) == 0 {
+ // If the caller wanted a zero byte read, return immediately
+ // without trying (but after acquiring the readLock).
+ return 0, nil
+ }
+ if err := fd.pd.prepareRead(fd.isFile); err != nil {
+ return 0, err
+ }
+ // TODO: pollable() read
+ n, err := syscall.Read(fd.Sysfd, p)
+ err = fd.eofError(n, err)
+ return n, err
+}
+
+// Pread wraps the pread system call.
+func (fd *FD) Pread(p []byte, off int64) (int, error) {
+ // Call incref, not readLock, because since pread specifies the
+ // offset it is independent from other reads.
+ // Similarly, using the poller doesn't make sense for pread.
+ if err := fd.incref(); err != nil {
+ return 0, err
+ }
+ n, err := syscall.Pread(fd.Sysfd, p, off)
+ if err != nil {
+ n = 0
+ }
+ fd.decref()
+ err = fd.eofError(n, err)
+ return n, err
+}
+
+// Write implements io.Writer.
+func (fd *FD) Write(p []byte) (int, error) {
+ if err := fd.writeLock(); err != nil {
+ return 0, err
+ }
+ defer fd.writeUnlock()
+ if err := fd.pd.prepareWrite(fd.isFile); err != nil {
+ return 0, err
+ }
+ var nn int
+ for {
+ n, err := fd.Handle.Write(p[nn:])
+ if n > 0 {
+ nn += n
+ }
+ if nn == len(p) {
+ return nn, err
+ }
+ if n == 0 {
+ return nn, io.ErrUnexpectedEOF
+ }
+ }
+}
+
+// Pwrite wraps the pwrite system call.
+func (fd *FD) Pwrite(p []byte, off int64) (int, error) {
+ // Call incref, not writeLock, because since pwrite specifies the
+ // offset it is independent from other writes.
+ // Similarly, using the poller doesn't make sense for pwrite.
+ if err := fd.incref(); err != nil {
+ return 0, err
+ }
+ defer fd.decref()
+ var nn int
+ for {
+ n, err := syscall.Pwrite(fd.Sysfd, p[nn:], off+int64(nn))
+ if n > 0 {
+ nn += n
+ }
+ if nn == len(p) {
+ return nn, err
+ }
+ if err != nil {
+ return nn, err
+ }
+ if n == 0 {
+ return nn, io.ErrUnexpectedEOF
+ }
+ }
+}
+
+// Accept wraps the accept network call.
+func (fd *FD) Accept() (newm *zxsocket.Socket, err error) {
+ if err := fd.readLock(); err != nil {
+ return nil, err
+ }
+ defer fd.readUnlock()
+
+ if err := fd.pd.prepareRead(fd.isFile); err != nil {
+ return nil, err
+ }
+
+ return fd.Handle.(*zxsocket.Socket).Accept()
+}
+
+// Seek wraps syscall.Seek.
+func (fd *FD) Seek(offset int64, whence int) (int64, error) {
+ if err := fd.incref(); err != nil {
+ return 0, err
+ }
+ defer fd.decref()
+ return syscall.Seek(fd.Sysfd, offset, whence)
+}
+
+// ReadDirent wraps syscall.ReadDirent.
+// We treat this like an ordinary system call rather than a call
+// that tries to fill the buffer.
+func (fd *FD) ReadDirent(buf []byte) (int, error) {
+ if err := fd.incref(); err != nil {
+ return 0, err
+ }
+ defer fd.decref()
+ return syscall.ReadDirent(fd.Sysfd, buf)
+}
+
+// Fstat wraps syscall.Fstat
+func (fd *FD) Fstat(s *syscall.Stat_t) error {
+ if err := fd.incref(); err != nil {
+ return err
+ }
+ defer fd.decref()
+ return syscall.Fstat(fd.Sysfd, s)
+}
+
+// eofError returns io.EOF when fd is available for reading end of
+// file.
+func (fd *FD) eofError(n int, err error) error {
+ if n == 0 && err == nil && fd.ZeroReadIsEOF {
+ return io.EOF
+ }
+ return err
+}
+
+// RawControl invokes the user-defined function f for a non-IO
+// operation.
+func (fd *FD) RawControl(f func(uintptr)) error {
+ if err := fd.incref(); err != nil {
+ return err
+ }
+ defer fd.decref()
+ f(uintptr(fd.Sysfd))
+ return nil
+}
+
+// RawRead invokes the user-defined function f for a read operation.
+func (fd *FD) RawRead(f func(uintptr) bool) error {
+ if err := fd.readLock(); err != nil {
+ return err
+ }
+ defer fd.readUnlock()
+ if err := fd.pd.prepareRead(fd.isFile); err != nil {
+ return err
+ }
+ for {
+ if f(uintptr(fd.Sysfd)) {
+ return nil
+ }
+ if err := fd.pd.waitRead(fd.isFile); err != nil {
+ return err
+ }
+ }
+}
+
+// RawWrite invokes the user-defined function f for a write operation.
+func (fd *FD) RawWrite(f func(uintptr) bool) error {
+ if err := fd.writeLock(); err != nil {
+ return err
+ }
+ defer fd.writeUnlock()
+ if err := fd.pd.prepareWrite(fd.isFile); err != nil {
+ return err
+ }
+ for {
+ if f(uintptr(fd.Sysfd)) {
+ return nil
+ }
+ if err := fd.pd.waitWrite(fd.isFile); err != nil {
+ return err
+ }
+ }
+}
+
+// SetBlocking puts the file into blocking mode.
+func (fd *FD) SetBlocking() error {
+ if err := fd.incref(); err != nil {
+ return err
+ }
+ defer fd.decref()
+ // Atomic store so that concurrent calls to SetBlocking
+ // do not cause a race condition. isBlocking only ever goes
+ // from 0 to 1 so there is no real race here.
+ atomic.StoreUint32(&fd.isBlocking, 1)
+ return syscall.SetNonblock(fd.Sysfd, false)
+}
diff --git a/src/internal/poll/fd_poll_fuchsia.go b/src/internal/poll/fd_poll_fuchsia.go
new file mode 100644
index 0000000..1ccc1c7
--- /dev/null
+++ b/src/internal/poll/fd_poll_fuchsia.go
@@ -0,0 +1,78 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TODO: use fd_poll_runtime.go for fuchsia
+
+package poll
+
+import (
+ "time"
+)
+
+type pollDesc struct {
+ fd *FD
+ closing bool
+}
+
+func (pd *pollDesc) init(fd *FD) error { pd.fd = fd; return nil }
+
+func (pd *pollDesc) close() {}
+
+func (pd *pollDesc) evict() {
+ pd.closing = true
+ if pd.fd != nil {
+ // TODO syscall.StopIO(pd.fd.Sysfd)
+ }
+}
+
+func (pd *pollDesc) prepare(mode int, isFile bool) error {
+ if pd.closing {
+ return errClosing(isFile)
+ }
+ return nil
+}
+
+func (pd *pollDesc) prepareRead(isFile bool) error { return pd.prepare('r', isFile) }
+
+func (pd *pollDesc) prepareWrite(isFile bool) error { return pd.prepare('w', isFile) }
+
+func (pd *pollDesc) wait(mode int, isFile bool) error {
+ if pd.closing {
+ return errClosing(isFile)
+ }
+ return ErrTimeout
+}
+
+func (pd *pollDesc) waitRead(isFile bool) error { return pd.wait('r', isFile) }
+
+func (pd *pollDesc) waitWrite(isFile bool) error { return pd.wait('w', isFile) }
+
+func (pd *pollDesc) waitCanceled(mode int) {}
+
+func (pd *pollDesc) pollable() bool { return true }
+
+// SetDeadline sets the read and write deadlines associated with fd.
+func (fd *FD) SetDeadline(t time.Time) error {
+ return setDeadlineImpl(fd, t, 'r'+'w')
+}
+
+// SetReadDeadline sets the read deadline associated with fd.
+func (fd *FD) SetReadDeadline(t time.Time) error {
+ return setDeadlineImpl(fd, t, 'r')
+}
+
+// SetWriteDeadline sets the write deadline associated with fd.
+func (fd *FD) SetWriteDeadline(t time.Time) error {
+ return setDeadlineImpl(fd, t, 'w')
+}
+
+func setDeadlineImpl(fd *FD, t time.Time, mode int) error {
+ return ErrNoDeadline // TODO set deadline
+}
+
+// PollDescriptor returns the descriptor being used by the poller,
+// or ^uintptr(0) if there isn't one. This is only used for testing.
+func PollDescriptor() uintptr {
+ return ^uintptr(0)
+}
diff --git a/src/internal/syscall/unix/nonblocking_fuchsia.go b/src/internal/syscall/unix/nonblocking_fuchsia.go
new file mode 100644
index 0000000..ff67c75
--- /dev/null
+++ b/src/internal/syscall/unix/nonblocking_fuchsia.go
@@ -0,0 +1,9 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package unix
+
+func IsNonblock(fd int) (nonblocking bool, err error) {
+ return false, nil
+}
diff --git a/src/internal/syscall/unix/stub_fuchsia.go b/src/internal/syscall/unix/stub_fuchsia.go
new file mode 100644
index 0000000..2d7b8de
--- /dev/null
+++ b/src/internal/syscall/unix/stub_fuchsia.go
@@ -0,0 +1,7 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file exists to make the go tool happy.
+
+package unix
diff --git a/src/internal/testenv/testenv.go b/src/internal/testenv/testenv.go
index 8f69fe0..fd09e35 100644
--- a/src/internal/testenv/testenv.go
+++ b/src/internal/testenv/testenv.go
@@ -149,7 +149,7 @@
// HasExternalNetwork reports whether the current system can use
// external (non-localhost) networks.
func HasExternalNetwork() bool {
- return !testing.Short() && runtime.GOOS != "nacl" && runtime.GOOS != "js"
+ return !testing.Short() && runtime.GOOS != "nacl" && runtime.GOOS != "js" && runtime.GOOS != "fuchsia"
}
// MustHaveExternalNetwork checks that the current system can use
@@ -162,6 +162,10 @@
if testing.Short() {
t.Skipf("skipping test: no external network in -short mode")
}
+
+ if runtime.GOOS == "fuchsia" {
+ t.Skipf("external network tests disabled on fuchsia; not all builders have one.")
+ }
}
var haveCGO bool
@@ -209,6 +213,11 @@
}
}
+// HasChmod reports whether the current system can use os.Chmod.
+func HasChmod() bool {
+ return runtime.GOOS != "fuchsia"
+}
+
var flaky = flag.Bool("flaky", false, "run known-flaky tests too")
func SkipFlaky(t testing.TB, issue int) {
diff --git a/src/internal/testenv/testenv_notwin.go b/src/internal/testenv/testenv_notwin.go
index d8ce6cd..e587e6a 100644
--- a/src/internal/testenv/testenv_notwin.go
+++ b/src/internal/testenv/testenv_notwin.go
@@ -12,7 +12,7 @@
func hasSymlink() (ok bool, reason string) {
switch runtime.GOOS {
- case "android", "nacl", "plan9":
+ case "android", "nacl", "plan9", "fuchsia":
return false, ""
}
diff --git a/src/io/io_fuchsia.go b/src/io/io_fuchsia.go
new file mode 100644
index 0000000..ac81e67
--- /dev/null
+++ b/src/io/io_fuchsia.go
@@ -0,0 +1,15 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package io
+
+import (
+ "syscall/zx"
+)
+
+func init() {
+ zx.EOF = EOF
+}
diff --git a/src/mime/type_fuchsia.go b/src/mime/type_fuchsia.go
new file mode 100644
index 0000000..986c0bb
--- /dev/null
+++ b/src/mime/type_fuchsia.go
@@ -0,0 +1,15 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package mime
+
+func init() {
+ osInitMime = initMimeFuchsia
+}
+
+func initMimeFuchsia() {
+ // TODO: find an equivalent to /etc/mime.types.
+}
diff --git a/src/net/addrselect.go b/src/net/addrselect.go
index 1ab9fc5..16871fc 100644
--- a/src/net/addrselect.go
+++ b/src/net/addrselect.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia linux netbsd openbsd solaris
// Minimal RFC 6724 address selection.
diff --git a/src/net/cgo_stub.go b/src/net/cgo_stub.go
index 5125972..94c95b5 100644
--- a/src/net/cgo_stub.go
+++ b/src/net/cgo_stub.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !cgo netgo
+// +build !cgo netgo fuchsia
package net
diff --git a/src/net/conf.go b/src/net/conf.go
index 71ed136..fa7dcf4 100644
--- a/src/net/conf.go
+++ b/src/net/conf.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia linux netbsd openbsd solaris
package net
diff --git a/src/net/dial_test.go b/src/net/dial_test.go
index 00a84d1..cfc4c37 100644
--- a/src/net/dial_test.go
+++ b/src/net/dial_test.go
@@ -77,7 +77,7 @@
func TestDialerDualStackFDLeak(t *testing.T) {
switch runtime.GOOS {
- case "plan9":
+ case "plan9", "fuchsia":
t.Skipf("%s does not have full support of socktest", runtime.GOOS)
case "windows":
t.Skipf("not implemented a way to cancel dial racers in TCP SYN-SENT state on %s", runtime.GOOS)
@@ -431,6 +431,10 @@
if !supportsIPv4() || !supportsIPv6() {
t.Skip("both IPv4 and IPv6 are required")
}
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
var wg sync.WaitGroup
wg.Add(2)
@@ -541,6 +545,10 @@
if !supportsIPv4() || !supportsIPv6() {
t.Skip("both IPv4 and IPv6 are required")
}
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
type test struct {
network, raddr string
@@ -712,6 +720,11 @@
}
func TestDialerKeepAlive(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
+
handler := func(ls *localServer, ln Listener) {
for {
c, err := ln.Accept()
@@ -815,6 +828,10 @@
}
func TestCancelAfterDial(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
if testing.Short() {
t.Skip("avoiding time.Sleep")
}
@@ -916,7 +933,7 @@
func TestDialerControl(t *testing.T) {
switch runtime.GOOS {
- case "nacl", "plan9":
+ case "fuchsia", "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
diff --git a/src/net/dnsclient_unix.go b/src/net/dnsclient_unix.go
index 2fee334..bd3b7ae 100644
--- a/src/net/dnsclient_unix.go
+++ b/src/net/dnsclient_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia linux netbsd openbsd solaris
// DNS client: see RFC 1035.
// Has to be linked into package net for Dial.
diff --git a/src/net/dnsconfig_fuchsia.go b/src/net/dnsconfig_fuchsia.go
new file mode 100644
index 0000000..c13658b
--- /dev/null
+++ b/src/net/dnsconfig_fuchsia.go
@@ -0,0 +1,44 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+// TODO: use dnsconfig_unix when 127.0.0.1:53 is a valid DNS server.
+
+package net
+
+import (
+ "os"
+ "time"
+)
+
+var (
+ defaultNS = []string{"8.8.8.8:53"}
+ getHostname = os.Hostname // variable for testing
+)
+
+type dnsConfig struct {
+ servers []string
+ attempts int
+ timeout time.Duration
+ search []string
+ ndots int
+ rotate bool
+ unknownOpt bool
+ lookup []string
+ err error
+ mtime time.Time
+ soffset uint32
+}
+
+func dnsReadConfig(filename string) *dnsConfig {
+ return &dnsConfig{
+ ndots: 1,
+ timeout: 5 * time.Second,
+ attempts: 2,
+ servers: defaultNS,
+ }
+}
+
+func (c *dnsConfig) serverOffset() uint32 { return 0 }
diff --git a/src/net/dnsconfig_unix.go b/src/net/dnsconfig_unix.go
index 707fd6f..348d2a4 100644
--- a/src/net/dnsconfig_unix.go
+++ b/src/net/dnsconfig_unix.go
@@ -15,7 +15,7 @@
)
var (
- defaultNS = []string{"127.0.0.1:53", "[::1]:53"}
+ defaultNS = []string{"8.8.8.8:53"}
getHostname = os.Hostname // variable for testing
)
diff --git a/src/net/error_fuchsia.go b/src/net/error_fuchsia.go
new file mode 100644
index 0000000..caad133
--- /dev/null
+++ b/src/net/error_fuchsia.go
@@ -0,0 +1,9 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+func isConnError(err error) bool {
+ return false
+}
diff --git a/src/net/error_fuchsia_test.go b/src/net/error_fuchsia_test.go
new file mode 100644
index 0000000..a72a2b8
--- /dev/null
+++ b/src/net/error_fuchsia_test.go
@@ -0,0 +1,35 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia !plan9,!windows,!unix
+
+package net
+
+import (
+ "os"
+ "syscall"
+ "syscall/zx"
+)
+
+var (
+ errTimedout = syscall.ETIMEDOUT
+ errOpNotSupported = syscall.EOPNOTSUPP
+
+ abortedConnRequestErrors = []error{syscall.ECONNABORTED} // see accept in fd_unix.go
+)
+
+func isPlatformError(err error) bool {
+ _, ok := err.(zx.Error)
+ return ok
+}
+
+func samePlatformError(err, want error) bool {
+ if op, ok := err.(*OpError); ok {
+ err = op.Err
+ }
+ if sys, ok := err.(*os.SyscallError); ok {
+ err = sys.Err
+ }
+ return err == want
+}
diff --git a/src/net/error_posix_test.go b/src/net/error_posix_test.go
index b411a37..ab44e70 100644
--- a/src/net/error_posix_test.go
+++ b/src/net/error_posix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !plan9
+// +build !plan9,!fuchsia
package net
diff --git a/src/net/error_test.go b/src/net/error_test.go
index e09670e..0a9ebd0 100644
--- a/src/net/error_test.go
+++ b/src/net/error_test.go
@@ -137,8 +137,9 @@
}
func TestDialError(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
switch runtime.GOOS {
- case "plan9":
+ case "plan9", "fuchsia":
t.Skipf("%s does not have full support of socktest", runtime.GOOS)
}
@@ -184,6 +185,10 @@
}
func TestProtocolDialError(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
switch runtime.GOOS {
case "nacl", "solaris":
t.Skipf("not supported on %s", runtime.GOOS)
@@ -286,6 +291,10 @@
}
func TestListenError(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
switch runtime.GOOS {
case "plan9":
t.Skipf("%s does not have full support of socktest", runtime.GOOS)
@@ -346,6 +355,10 @@
}
func TestListenPacketError(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
switch runtime.GOOS {
case "plan9":
t.Skipf("%s does not have full support of socktest", runtime.GOOS)
@@ -375,6 +388,10 @@
}
func TestProtocolListenError(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
switch runtime.GOOS {
case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
@@ -548,6 +565,10 @@
}
func TestCloseError(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
ln, err := newLocalListener("tcp")
if err != nil {
t.Fatal(err)
@@ -582,6 +603,11 @@
}
}
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
+
pc, err := ListenPacket("udp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
@@ -640,6 +666,11 @@
}
func TestAcceptError(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
+
handler := func(ls *localServer, ln Listener) {
for {
ln.(*TCPListener).SetDeadline(time.Now().Add(5 * time.Millisecond))
@@ -719,6 +750,10 @@
}
func TestFileError(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
switch runtime.GOOS {
case "windows":
t.Skipf("not supported on %s", runtime.GOOS)
diff --git a/src/net/error_unix_test.go b/src/net/error_unix_test.go
index 9ce9e12..441ca49 100644
--- a/src/net/error_unix_test.go
+++ b/src/net/error_unix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !plan9,!windows
+// +build !plan9,!windows,!fuchsia
package net
diff --git a/src/net/fd_fuchsia.go b/src/net/fd_fuchsia.go
new file mode 100644
index 0000000..385bd0f
--- /dev/null
+++ b/src/net/fd_fuchsia.go
@@ -0,0 +1,146 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TODO: move to using fd_unix for fuchsia?
+
+package net
+
+import (
+ "errors"
+ "internal/poll"
+ "os"
+ "runtime"
+ "syscall"
+ "syscall/zx/mxnet"
+ "syscall/zx/zxsocket"
+ "time"
+)
+
+// Network file descriptor.
+type netFD struct {
+ pfd poll.FD
+
+ // immutable until Close
+ net string
+ family int
+ sotype int
+ isStream bool
+ isConnected bool
+ laddr Addr
+ raddr Addr
+}
+
+func newFD(handle *zxsocket.Socket, family, sotype int, net string) *netFD {
+ netfd := &netFD{
+ pfd: poll.FD{
+ Sysfd: syscall.OpenFDIO(handle),
+ Handle: handle,
+ },
+ family: family,
+ sotype: sotype,
+ net: net,
+ }
+ return netfd
+}
+
+func (fd *netFD) destroy() {
+ panic("TODO")
+}
+
+func sysInit() {
+}
+
+func (fd *netFD) isTCP() bool {
+ return len(fd.net) >= 3 && fd.net[:3] == "tcp"
+}
+
+func (fd *netFD) Read(b []byte) (n int, err error) {
+ n, err = fd.pfd.Read(b)
+ runtime.KeepAlive(fd)
+ return n, err
+}
+
+func (fd *netFD) Write(b []byte) (n int, err error) {
+ n, err = fd.pfd.Write(b)
+ runtime.KeepAlive(fd)
+ return n, err
+}
+
+func (fd *netFD) readMsg(b []byte) (n, flags int, addr string, port uint16, err error) {
+ // TODO: move call to pfd
+ data, flags, addr, port, err := fd.pfd.Handle.(*zxsocket.Socket).RecvMsg(len(b))
+ runtime.KeepAlive(fd)
+ n = copy(b, data)
+ return n, flags, addr, port, err
+}
+
+func (fd *netFD) sendMsg(b []byte, addr string, port uint16) (n int, err error) {
+ // TODO: move call to pfd
+ n, err = fd.pfd.Handle.(*zxsocket.Socket).SendMsg(b, addr, port)
+ runtime.KeepAlive(fd)
+ return n, err
+}
+
+func (fd *netFD) closeRead() error {
+ return errors.New("net: closeRead not implemented on fuchsia")
+}
+
+func (fd *netFD) closeWrite() error {
+ return errors.New("net: closeWrite not implemented on fuchsia")
+}
+
+func (fd *netFD) Close() error {
+ return fd.pfd.Close()
+}
+
+func (fd *netFD) dup() (*os.File, error) {
+ // TODO(mknyszek): fd.sock is an FDIO so one can make an FD from it to
+ // implement this.
+ return nil, errors.New("net: dup not implemented on fuchsia")
+}
+
+func (fd *netFD) accept() (netfd *netFD, err error) {
+ newm, err := fd.pfd.Accept()
+ if err != nil {
+ return nil, err
+ }
+ netfd = newFD(newm, fd.family, fd.sotype, fd.net)
+ netfd.setAddr()
+ return netfd, nil
+}
+
+func (fd *netFD) asAddr(ipAddr mxnet.Addr, port uint16, err error) sockaddr {
+ if err != nil {
+ return nil
+ }
+ ip := IP(ipAddr)
+ if isZeros(ip) && port == 0 {
+ return nil
+ }
+ switch fd.sotype {
+ case syscall.SOCK_STREAM:
+ return &TCPAddr{IP: ip, Port: int(port)}
+ case syscall.SOCK_DGRAM:
+ return &UDPAddr{IP: ip, Port: int(port)}
+ }
+ return nil
+}
+
+func (fd *netFD) setAddr() {
+ fd.laddr = fd.asAddr(fd.pfd.Handle.(*zxsocket.Socket).SockName())
+ fd.raddr = fd.asAddr(fd.pfd.Handle.(*zxsocket.Socket).PeerName())
+ runtime.SetFinalizer(fd, (*netFD).Close)
+}
+
+func (fd *netFD) SetDeadline(t time.Time) error {
+ return fd.pfd.SetDeadline(t)
+}
+
+func (fd *netFD) SetReadDeadline(t time.Time) error {
+ return fd.pfd.SetReadDeadline(t)
+}
+
+func (fd *netFD) SetWriteDeadline(t time.Time) error {
+ return fd.pfd.SetWriteDeadline(t)
+}
diff --git a/src/net/file_stub.go b/src/net/file_stub.go
index 2256608..dce5470 100644
--- a/src/net/file_stub.go
+++ b/src/net/file_stub.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build nacl js,wasm
+// +build nacl js,wasm fuchsia
package net
diff --git a/src/net/file_test.go b/src/net/file_test.go
index cd71774..87aeaf6 100644
--- a/src/net/file_test.go
+++ b/src/net/file_test.go
@@ -30,8 +30,9 @@
}
func TestFileConn(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
switch runtime.GOOS {
- case "nacl", "plan9", "windows":
+ case "nacl", "plan9", "windows", "fuchsia":
t.Skipf("not supported on %s", runtime.GOOS)
}
@@ -137,8 +138,9 @@
}
func TestFileListener(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
switch runtime.GOOS {
- case "nacl", "plan9", "windows":
+ case "nacl", "plan9", "windows", "fuchsia":
t.Skipf("not supported on %s", runtime.GOOS)
}
@@ -229,8 +231,9 @@
}
func TestFilePacketConn(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
switch runtime.GOOS {
- case "nacl", "plan9", "windows":
+ case "nacl", "plan9", "windows", "fuchsia":
t.Skipf("not supported on %s", runtime.GOOS)
}
@@ -297,7 +300,7 @@
// Issue 24483.
func TestFileCloseRace(t *testing.T) {
switch runtime.GOOS {
- case "nacl", "plan9", "windows":
+ case "fuchsia", "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !testableNetwork("tcp") {
diff --git a/src/net/hook_fuchsia.go b/src/net/hook_fuchsia.go
new file mode 100644
index 0000000..e445c1a
--- /dev/null
+++ b/src/net/hook_fuchsia.go
@@ -0,0 +1,17 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package net
+
+import "syscall"
+
+var (
+ testHookDialChannel = func() {} // for golang.org/issue/5349
+ testHookCanceledDial = func() {} // for golang.org/issue/16523
+
+ // Placeholders for socket system calls.
+ closeFunc func(int) error = syscall.Close
+)
diff --git a/src/net/hosts_test.go b/src/net/hosts_test.go
index f850e2f..3169866 100644
--- a/src/net/hosts_test.go
+++ b/src/net/hosts_test.go
@@ -6,6 +6,7 @@
import (
"reflect"
+ "runtime"
"strings"
"testing"
)
@@ -59,6 +60,11 @@
}
func TestLookupStaticHost(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
+
defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
for _, tt := range lookupStaticHostTests {
@@ -128,6 +134,10 @@
}
func TestLookupStaticAddr(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
for _, tt := range lookupStaticAddrTests {
@@ -149,6 +159,10 @@
}
func TestHostCacheModification(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
// Ensure that programs can't modify the internals of the host cache.
// See https://golang.org/issues/14212.
defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
diff --git a/src/net/interface_stub.go b/src/net/interface_stub.go
index 0afaa80..426ac46 100644
--- a/src/net/interface_stub.go
+++ b/src/net/interface_stub.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build nacl js,wasm
+// +build nacl js,wasm fuchsia
package net
diff --git a/src/net/internal/socktest/switch_posix.go b/src/net/internal/socktest/switch_posix.go
index 863edef..0ead109 100644
--- a/src/net/internal/socktest/switch_posix.go
+++ b/src/net/internal/socktest/switch_posix.go
@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file.
// +build !plan9
+// +build !fuchsia
package socktest
diff --git a/src/net/internal/socktest/switch_stub.go b/src/net/internal/socktest/switch_stub.go
index 28ce72c..9ba7d73 100644
--- a/src/net/internal/socktest/switch_stub.go
+++ b/src/net/internal/socktest/switch_stub.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build plan9
+// +build plan9 fuchsia
package socktest
diff --git a/src/net/ip_test.go b/src/net/ip_test.go
index a5fc5e6..cde5eca 100644
--- a/src/net/ip_test.go
+++ b/src/net/ip_test.go
@@ -61,6 +61,7 @@
}
func TestLookupWithIP(t *testing.T) {
+ mustHaveExternalNetwork(t)
_, err := LookupIP("")
if err == nil {
t.Errorf(`LookupIP("") succeeded, should fail`)
diff --git a/src/net/iprawsock_fuchsia.go b/src/net/iprawsock_fuchsia.go
new file mode 100644
index 0000000..0bfd133
--- /dev/null
+++ b/src/net/iprawsock_fuchsia.go
@@ -0,0 +1,34 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "context"
+ "syscall"
+)
+
+func (c *IPConn) readFrom(b []byte) (int, *IPAddr, error) {
+ return 0, nil, syscall.EFUCHSIA
+}
+
+func (c *IPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) {
+ return 0, 0, 0, nil, syscall.EFUCHSIA
+}
+
+func (c *IPConn) writeTo(b []byte, addr *IPAddr) (int, error) {
+ return 0, syscall.EFUCHSIA
+}
+
+func (c *IPConn) writeMsg(b, oob []byte, addr *IPAddr) (n, oobn int, err error) {
+ return 0, 0, syscall.EFUCHSIA
+}
+
+func (sd *sysDialer) dialIP(ctx context.Context, laddr, raddr *IPAddr) (*IPConn, error) {
+ return nil, syscall.EFUCHSIA
+}
+
+func (sl *sysListener) listenIP(ctx context.Context, laddr *IPAddr) (*IPConn, error) {
+ return nil, syscall.EFUCHSIA
+}
diff --git a/src/net/iprawsock_test.go b/src/net/iprawsock_test.go
index 8e3543d..4985e88 100644
--- a/src/net/iprawsock_test.go
+++ b/src/net/iprawsock_test.go
@@ -8,6 +8,7 @@
import (
"reflect"
+ "runtime"
"testing"
)
@@ -88,6 +89,10 @@
}
func TestIPConnLocalName(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
for _, tt := range ipConnLocalNameTests {
if !testableNetwork(tt.net) {
t.Logf("skipping %s test", tt.net)
@@ -105,6 +110,10 @@
}
func TestIPConnRemoteName(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
if !testableNetwork("ip:tcp") {
t.Skip("ip:tcp test")
}
diff --git a/src/net/ipsock_fuchsia.go b/src/net/ipsock_fuchsia.go
new file mode 100644
index 0000000..4af25bb
--- /dev/null
+++ b/src/net/ipsock_fuchsia.go
@@ -0,0 +1,174 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "context"
+ "errors"
+ "sync"
+ "syscall"
+ "syscall/zx"
+ "syscall/zx/fdio"
+ "syscall/zx/fidl"
+ "syscall/zx/mxnet"
+ zxnet "syscall/zx/net"
+ "syscall/zx/zxsocket"
+ "time"
+)
+
+func (p *ipStackCapabilities) probe() {
+ p.ipv4Enabled = true
+ p.ipv6Enabled = true
+ p.ipv4MappedIPv6Enabled = true
+}
+
+// A sockaddr represents a TCP, UDP, IP or Unix network endpoint
+// address that can be converted into an fdio sockaddr message.
+type sockaddr interface {
+ Addr
+
+ family() int
+ isWildcard() bool
+ sockaddr(family int) (addr mxnet.Addr, port uint16, err error)
+}
+
+func favoriteAddrFamily(net string, laddr, raddr sockaddr, mode string) (family int, ipv6only bool) {
+ switch net[len(net)-1] {
+ case '4':
+ return syscall.AF_INET, false
+ case '6':
+ return syscall.AF_INET6, true
+ }
+
+ if mode == "listen" && (laddr == nil || laddr.isWildcard()) {
+ if supportsIPv4map() || !supportsIPv4() {
+ return syscall.AF_INET6, false
+ }
+ if laddr == nil {
+ return syscall.AF_INET, false
+ }
+ return laddr.family(), false
+ }
+
+ if (laddr == nil || laddr.family() == syscall.AF_INET) &&
+ (raddr == nil || raddr.family() == syscall.AF_INET) {
+ return syscall.AF_INET, false
+ }
+ return syscall.AF_INET6, false
+}
+
+type socketProviderInfo struct {
+ mu sync.Mutex
+ h zx.Handle
+}
+
+var socketProvider socketProviderInfo
+
+func getSocketProvider() zx.Handle {
+ socketProvider.mu.Lock()
+ defer socketProvider.mu.Unlock()
+ if socketProvider.h == zx.HandleInvalid {
+ c0, c1, err := zx.NewChannel(0)
+ if err == nil {
+ err = fdio.ServiceConnect("/svc/fuchsia.net.LegacySocketProvider", zx.Handle(c0))
+ if err == nil {
+ socketProvider.h = zx.Handle(c1)
+ }
+ }
+ }
+ return socketProvider.h
+}
+
+func dialFuchsia(ctx context.Context, net string, laddr, raddr sockaddr) (fd *netFD, err error) {
+ family, _ := favoriteAddrFamily(net, laddr, raddr, "dial")
+
+ sotype := syscall.SOCK_STREAM
+ if len(net) >= 3 && net[:3] == "udp" {
+ sotype = syscall.SOCK_DGRAM
+ }
+ proto := syscall.IPPROTO_IP
+
+ var sock *zxsocket.Socket
+ // Wait for the network stack to publish the socket device.
+ // See similar logic in zircon/system/ulib/fdio/bsdsocket.c.
+ for i := 0; i < 40; i++ {
+ c := zx.Channel(getSocketProvider())
+ if c.Handle().IsValid() {
+ sp := zxnet.LegacySocketProviderInterface(fidl.Proxy{Channel: c})
+ s, _, err := sp.OpenSocket(zxnet.SocketDomain(family), zxnet.SocketType(sotype), zxnet.SocketProtocol(proto))
+ if err == nil {
+ sock = zxsocket.NewSocket(s)
+ break
+ }
+ }
+ time.Sleep(250 * time.Millisecond)
+ }
+ if err != nil {
+ return nil, err
+ }
+ if sotype == syscall.SOCK_DGRAM {
+ sock.SetDgram()
+ }
+
+ fd = newFD(sock, family, sotype, net)
+ if laddr != nil {
+ addr, port, err := laddr.sockaddr(family)
+ if err != nil {
+ return nil, err
+ }
+ if addr != "" || port != 0 {
+ if err := fd.pfd.Handle.(*zxsocket.Socket).Bind(addr, port); err != nil {
+ return nil, err
+ }
+ }
+ if raddr == nil {
+ switch sotype {
+ case syscall.SOCK_STREAM:
+ if err := fd.pfd.Handle.(*zxsocket.Socket).ListenStream(listenerBacklog); err != nil {
+ return nil, err
+ }
+ case syscall.SOCK_DGRAM:
+ return nil, errors.New("net: TODO listen datagram")
+ }
+ }
+ }
+ if raddr != nil {
+ addr, port, err := raddr.sockaddr(family)
+ if err != nil {
+ return nil, err
+ }
+ if err := fd.pfd.Handle.(*zxsocket.Socket).Connect(addr, port); err != nil {
+ return nil, err
+ }
+ fd.isConnected = true
+ }
+ fd.setAddr()
+
+ return fd, nil
+}
+
+func ipToSockaddr(family int, ip IP, port int, zone string) (addr mxnet.Addr, portres uint16, err error) {
+ switch family {
+ case syscall.AF_INET:
+ if len(ip) == 0 {
+ ip = IPv4zero
+ }
+ ip4 := ip.To4()
+ if ip4 == nil {
+ return "", 0, &AddrError{Err: "non-IPv4 address", Addr: ip.String()}
+ }
+ return mxnet.Addr(ip4)[:4], uint16(port), nil
+ case syscall.AF_INET6:
+ if len(ip) == 0 || ip.Equal(IPv4zero) {
+ ip = IPv6zero
+ }
+ ip6 := ip.To16()
+ if ip6 == nil {
+ return "", 0, &AddrError{Err: "non-IPv6 address", Addr: ip.String()}
+ }
+ return mxnet.Addr(ip6), uint16(port), nil
+ }
+ return "", 0, &AddrError{Err: "invalid address family", Addr: ip.String()}
+}
diff --git a/src/net/listen_test.go b/src/net/listen_test.go
index ffce8e2..971f233 100644
--- a/src/net/listen_test.go
+++ b/src/net/listen_test.go
@@ -63,6 +63,10 @@
// listener with same address family, same listening address and
// same port.
func TestTCPListener(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
switch runtime.GOOS {
case "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
@@ -124,8 +128,9 @@
// listener with same address family, same listening address and
// same port.
func TestUDPListener(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
switch runtime.GOOS {
- case "plan9":
+ case "plan9", "fuchsia":
t.Skipf("not supported on %s", runtime.GOOS)
}
@@ -223,6 +228,10 @@
// On DragonFly BSD, we expect the kernel version of node under test
// to be greater than or equal to 4.4.
func TestDualStackTCPListener(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
switch runtime.GOOS {
case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
@@ -313,8 +322,9 @@
// On DragonFly BSD, we expect the kernel version of node under test
// to be greater than or equal to 4.4.
func TestDualStackUDPListener(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
switch runtime.GOOS {
- case "nacl", "plan9":
+ case "nacl", "plan9", "fuchsia":
t.Skipf("not supported on %s", runtime.GOOS)
}
if !supportsIPv4() || !supportsIPv6() {
@@ -488,8 +498,9 @@
func TestWildWildcardListener(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ // TODO(TC-149): disabled without further triage. Needs work.
switch runtime.GOOS {
- case "plan9":
+ case "plan9", "fuchsia":
t.Skipf("not supported on %s", runtime.GOOS)
}
@@ -531,8 +542,9 @@
func TestIPv4MulticastListener(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ // TODO(TC-149): disabled without further triage. Needs work.
switch runtime.GOOS {
- case "android", "nacl", "plan9":
+ case "android", "nacl", "plan9", "fuchsia":
t.Skipf("not supported on %s", runtime.GOOS)
case "solaris":
t.Skipf("not supported on solaris, see golang.org/issue/7399")
@@ -606,8 +618,9 @@
func TestIPv6MulticastListener(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ // TODO(TC-149): disabled without further triage. Needs work.
switch runtime.GOOS {
- case "plan9":
+ case "plan9", "fuchsia":
t.Skipf("not supported on %s", runtime.GOOS)
case "solaris":
t.Skipf("not supported on solaris, see issue 7399")
@@ -701,6 +714,11 @@
// Issue 21856.
func TestClosingListener(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
+
ln, err := newLocalListener("tcp")
if err != nil {
t.Fatal(err)
@@ -733,7 +751,7 @@
func TestListenConfigControl(t *testing.T) {
switch runtime.GOOS {
- case "nacl", "plan9":
+ case "fuchsia", "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
diff --git a/src/net/lookup_fuchsia.go b/src/net/lookup_fuchsia.go
new file mode 100644
index 0000000..b3d5f97
--- /dev/null
+++ b/src/net/lookup_fuchsia.go
@@ -0,0 +1,323 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd fuchsia linux netbsd openbsd solaris
+
+package net
+
+import (
+ "context"
+ "sync"
+
+ "golang_org/x/net/dns/dnsmessage"
+)
+
+var onceReadProtocols sync.Once
+
+// readProtocols loads contents of /etc/protocols into protocols map
+// for quick access.
+func readProtocols() {
+ file, err := open("/etc/protocols")
+ if err != nil {
+ return
+ }
+ defer file.close()
+
+ for line, ok := file.readLine(); ok; line, ok = file.readLine() {
+ // tcp 6 TCP # transmission control protocol
+ if i := byteIndex(line, '#'); i >= 0 {
+ line = line[0:i]
+ }
+ f := getFields(line)
+ if len(f) < 2 {
+ continue
+ }
+ if proto, _, ok := dtoi(f[1]); ok {
+ if _, ok := protocols[f[0]]; !ok {
+ protocols[f[0]] = proto
+ }
+ for _, alias := range f[2:] {
+ if _, ok := protocols[alias]; !ok {
+ protocols[alias] = proto
+ }
+ }
+ }
+ }
+}
+
+// lookupProtocol looks up IP protocol name in /etc/protocols and
+// returns correspondent protocol number.
+func lookupProtocol(_ context.Context, name string) (int, error) {
+ onceReadProtocols.Do(readProtocols)
+ return lookupProtocolMap(name)
+}
+
+func (r *Resolver) dial(ctx context.Context, network, server string) (Conn, error) {
+ // Calling Dial here is scary -- we have to be sure not to
+ // dial a name that will require a DNS lookup, or Dial will
+ // call back here to translate it. The DNS config parser has
+ // already checked that all the cfg.servers are IP
+ // addresses, which Dial will use without a DNS lookup.
+ var c Conn
+ var err error
+ if r != nil && r.Dial != nil {
+ c, err = r.Dial(ctx, network, server)
+ } else {
+ var d Dialer
+ c, err = d.DialContext(ctx, network, server)
+ }
+ if err != nil {
+ return nil, mapErr(err)
+ }
+ return c, nil
+}
+
+func (r *Resolver) lookupHost(ctx context.Context, host string) (addrs []string, err error) {
+ order := systemConf().hostLookupOrder(r, host)
+ if !r.preferGo() && order == hostLookupCgo {
+ if addrs, err, ok := cgoLookupHost(ctx, host); ok {
+ return addrs, err
+ }
+ // cgo not available (or netgo); fall back to Go's DNS resolver
+ order = hostLookupFilesDNS
+ }
+ return r.goLookupHostOrder(ctx, host, order)
+}
+
+func (r *Resolver) lookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
+ if r.preferGo() {
+ return r.goLookupIP(ctx, host)
+ }
+ order := systemConf().hostLookupOrder(r, host)
+ if order == hostLookupCgo {
+ if addrs, err, ok := cgoLookupIP(ctx, host); ok {
+ return addrs, err
+ }
+ // cgo not available (or netgo); fall back to Go's DNS resolver
+ order = hostLookupFilesDNS
+ }
+ ips, _, err := r.goLookupIPCNAMEOrder(ctx, host, order)
+ return ips, err
+}
+
+func (r *Resolver) lookupPort(ctx context.Context, network, service string) (int, error) {
+ if !r.preferGo() && systemConf().canUseCgo() {
+ if port, err, ok := cgoLookupPort(ctx, network, service); ok {
+ if err != nil {
+ // Issue 18213: if cgo fails, first check to see whether we
+ // have the answer baked-in to the net package.
+ if port, err := goLookupPort(network, service); err == nil {
+ return port, nil
+ }
+ }
+ return port, err
+ }
+ }
+ return goLookupPort(network, service)
+}
+
+func (r *Resolver) lookupCNAME(ctx context.Context, name string) (string, error) {
+ if !r.preferGo() && systemConf().canUseCgo() {
+ if cname, err, ok := cgoLookupCNAME(ctx, name); ok {
+ return cname, err
+ }
+ }
+ return r.goLookupCNAME(ctx, name)
+}
+
+func (r *Resolver) lookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
+ var target string
+ if service == "" && proto == "" {
+ target = name
+ } else {
+ target = "_" + service + "._" + proto + "." + name
+ }
+ p, server, err := r.lookup(ctx, target, dnsmessage.TypeSRV)
+ if err != nil {
+ return "", nil, err
+ }
+ var srvs []*SRV
+ var cname dnsmessage.Name
+ for {
+ h, err := p.AnswerHeader()
+ if err == dnsmessage.ErrSectionDone {
+ break
+ }
+ if err != nil {
+ return "", nil, &DNSError{
+ Err: "cannot unmarshal DNS message",
+ Name: name,
+ Server: server,
+ }
+ }
+ if h.Type != dnsmessage.TypeSRV {
+ if err := p.SkipAnswer(); err != nil {
+ return "", nil, &DNSError{
+ Err: "cannot unmarshal DNS message",
+ Name: name,
+ Server: server,
+ }
+ }
+ continue
+ }
+ if cname.Length == 0 && h.Name.Length != 0 {
+ cname = h.Name
+ }
+ srv, err := p.SRVResource()
+ if err != nil {
+ return "", nil, &DNSError{
+ Err: "cannot unmarshal DNS message",
+ Name: name,
+ Server: server,
+ }
+ }
+ srvs = append(srvs, &SRV{Target: srv.Target.String(), Port: srv.Port, Priority: srv.Priority, Weight: srv.Weight})
+ }
+ byPriorityWeight(srvs).sort()
+ return cname.String(), srvs, nil
+}
+
+func (r *Resolver) lookupMX(ctx context.Context, name string) ([]*MX, error) {
+ p, server, err := r.lookup(ctx, name, dnsmessage.TypeMX)
+ if err != nil {
+ return nil, err
+ }
+ var mxs []*MX
+ for {
+ h, err := p.AnswerHeader()
+ if err == dnsmessage.ErrSectionDone {
+ break
+ }
+ if err != nil {
+ return nil, &DNSError{
+ Err: "cannot unmarshal DNS message",
+ Name: name,
+ Server: server,
+ }
+ }
+ if h.Type != dnsmessage.TypeMX {
+ if err := p.SkipAnswer(); err != nil {
+ return nil, &DNSError{
+ Err: "cannot unmarshal DNS message",
+ Name: name,
+ Server: server,
+ }
+ }
+ continue
+ }
+ mx, err := p.MXResource()
+ if err != nil {
+ return nil, &DNSError{
+ Err: "cannot unmarshal DNS message",
+ Name: name,
+ Server: server,
+ }
+ }
+ mxs = append(mxs, &MX{Host: mx.MX.String(), Pref: mx.Pref})
+
+ }
+ byPref(mxs).sort()
+ return mxs, nil
+}
+
+func (r *Resolver) lookupNS(ctx context.Context, name string) ([]*NS, error) {
+ p, server, err := r.lookup(ctx, name, dnsmessage.TypeNS)
+ if err != nil {
+ return nil, err
+ }
+ var nss []*NS
+ for {
+ h, err := p.AnswerHeader()
+ if err == dnsmessage.ErrSectionDone {
+ break
+ }
+ if err != nil {
+ return nil, &DNSError{
+ Err: "cannot unmarshal DNS message",
+ Name: name,
+ Server: server,
+ }
+ }
+ if h.Type != dnsmessage.TypeNS {
+ if err := p.SkipAnswer(); err != nil {
+ return nil, &DNSError{
+ Err: "cannot unmarshal DNS message",
+ Name: name,
+ Server: server,
+ }
+ }
+ continue
+ }
+ ns, err := p.NSResource()
+ if err != nil {
+ return nil, &DNSError{
+ Err: "cannot unmarshal DNS message",
+ Name: name,
+ Server: server,
+ }
+ }
+ nss = append(nss, &NS{Host: ns.NS.String()})
+ }
+ return nss, nil
+}
+
+func (r *Resolver) lookupTXT(ctx context.Context, name string) ([]string, error) {
+ p, server, err := r.lookup(ctx, name, dnsmessage.TypeTXT)
+ if err != nil {
+ return nil, err
+ }
+ var txts []string
+ for {
+ h, err := p.AnswerHeader()
+ if err == dnsmessage.ErrSectionDone {
+ break
+ }
+ if err != nil {
+ return nil, &DNSError{
+ Err: "cannot unmarshal DNS message",
+ Name: name,
+ Server: server,
+ }
+ }
+ if h.Type != dnsmessage.TypeTXT {
+ if err := p.SkipAnswer(); err != nil {
+ return nil, &DNSError{
+ Err: "cannot unmarshal DNS message",
+ Name: name,
+ Server: server,
+ }
+ }
+ continue
+ }
+ txt, err := p.TXTResource()
+ if err != nil {
+ return nil, &DNSError{
+ Err: "cannot unmarshal DNS message",
+ Name: name,
+ Server: server,
+ }
+ }
+ if len(txts) == 0 {
+ txts = txt.TXT
+ } else {
+ txts = append(txts, txt.TXT...)
+ }
+ }
+ return txts, nil
+}
+
+func (r *Resolver) lookupAddr(ctx context.Context, addr string) ([]string, error) {
+ if !r.preferGo() && systemConf().canUseCgo() {
+ if ptrs, err, ok := cgoLookupPTR(ctx, addr); ok {
+ return ptrs, err
+ }
+ }
+ return r.goLookupPTR(ctx, addr)
+}
+
+// concurrentThreadsLimit returns the number of threads we permit to
+// run concurrently doing DNS lookups via cgo.
+func concurrentThreadsLimit() int {
+ return 500
+}
diff --git a/src/net/lookup_test.go b/src/net/lookup_test.go
index 5c66dfa..cb92c3c 100644
--- a/src/net/lookup_test.go
+++ b/src/net/lookup_test.go
@@ -742,6 +742,11 @@
}
func TestLookupPort(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
+
// See https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml
//
// Please be careful about adding new test cases.
@@ -800,6 +805,10 @@
// Like TestLookupPort but with minimal tests that should always pass
// because the answers are baked-in to the net package.
func TestLookupPort_Minimal(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
type test struct {
network string
name string
diff --git a/src/net/main_fuchsia_test.go b/src/net/main_fuchsia_test.go
new file mode 100644
index 0000000..b266361
--- /dev/null
+++ b/src/net/main_fuchsia_test.go
@@ -0,0 +1,20 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package net
+
+func installTestHooks() {
+}
+
+func uninstallTestHooks() {
+}
+
+// forceCloseSockets must be called only from TestMain.
+func forceCloseSockets() {
+ for s := range sw.Sockets() {
+ closeFunc(s)
+ }
+}
diff --git a/src/net/net_test.go b/src/net/net_test.go
index 692f269..e880564 100644
--- a/src/net/net_test.go
+++ b/src/net/net_test.go
@@ -19,6 +19,10 @@
)
func TestCloseRead(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
switch runtime.GOOS {
case "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
@@ -71,8 +75,9 @@
}
func TestCloseWrite(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
switch runtime.GOOS {
- case "nacl", "plan9":
+ case "nacl", "plan9", "fuchsia":
t.Skipf("not supported on %s", runtime.GOOS)
}
@@ -255,6 +260,10 @@
}
func TestPacketConnClose(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
for _, network := range []string{"udp", "unixgram"} {
if !testableNetwork(network) {
t.Logf("skipping %s test", network)
@@ -287,6 +296,10 @@
// nacl was previous failing to reuse an address.
func TestListenCloseListen(t *testing.T) {
+ // TODO(NET-1266): disabled.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
const maxTries = 10
for tries := 0; tries < maxTries; tries++ {
ln, err := newLocalListener("tcp")
@@ -313,6 +326,10 @@
// See golang.org/issue/6163, golang.org/issue/6987.
func TestAcceptIgnoreAbortedConnRequest(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
switch runtime.GOOS {
case "plan9":
t.Skipf("%s does not have full support of socktest", runtime.GOOS)
@@ -460,6 +477,10 @@
// See golang.org/cl/30164 which documented this. The net/http package
// depends on this.
func TestReadTimeoutUnblocksRead(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
serverDone := make(chan struct{})
server := func(cs *TCPConn) error {
defer close(serverDone)
@@ -503,6 +524,10 @@
// Issue 17695: verify that a blocked Read is woken up by a Close.
func TestCloseUnblocksRead(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
t.Parallel()
server := func(cs *TCPConn) error {
// Give the client time to get stuck in a Read:
@@ -522,6 +547,10 @@
// Issue 24808: verify that ECONNRESET is not temporary for read.
func TestNotTemporaryRead(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
if runtime.GOOS == "freebsd" {
testenv.SkipFlaky(t, 25289)
}
diff --git a/src/net/nss.go b/src/net/nss.go
index 08c3e6a..3533ab0 100644
--- a/src/net/nss.go
+++ b/src/net/nss.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia linux netbsd openbsd solaris
package net
diff --git a/src/net/packetconn_test.go b/src/net/packetconn_test.go
index a377d33..eafad0a 100644
--- a/src/net/packetconn_test.go
+++ b/src/net/packetconn_test.go
@@ -11,6 +11,7 @@
import (
"os"
+ "runtime"
"testing"
"time"
)
@@ -38,6 +39,10 @@
}
func TestPacketConn(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
closer := func(c PacketConn, net, addr1, addr2 string) {
c.Close()
switch net {
@@ -92,6 +97,10 @@
}
func TestConnAndPacketConn(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
closer := func(c PacketConn, net, addr1, addr2 string) {
c.Close()
switch net {
diff --git a/src/net/parse_test.go b/src/net/parse_test.go
index c5f8bfd..ffe4d12 100644
--- a/src/net/parse_test.go
+++ b/src/net/parse_test.go
@@ -14,7 +14,7 @@
func TestReadLine(t *testing.T) {
// /etc/services file does not exist on android, plan9, windows.
switch runtime.GOOS {
- case "android", "plan9", "windows":
+ case "android", "plan9", "windows", "fuchsia":
t.Skipf("not supported on %s", runtime.GOOS)
}
filename := "/etc/services" // a nice big file
diff --git a/src/net/platform_test.go b/src/net/platform_test.go
index 8e7d915..13b59df 100644
--- a/src/net/platform_test.go
+++ b/src/net/platform_test.go
@@ -33,7 +33,7 @@
}
case "unix", "unixgram":
switch runtime.GOOS {
- case "android", "nacl", "plan9", "windows":
+ case "android", "fuchsia", "nacl", "plan9", "windows":
return false
}
// iOS does not support unix, unixgram.
@@ -42,7 +42,7 @@
}
case "unixpacket":
switch runtime.GOOS {
- case "android", "darwin", "nacl", "plan9", "windows":
+ case "android", "darwin", "fuchsia", "nacl", "plan9", "windows":
return false
case "netbsd":
// It passes on amd64 at least. 386 fails (Issue 22927). arm is unknown.
diff --git a/src/net/port_fuchsia.go b/src/net/port_fuchsia.go
new file mode 100644
index 0000000..c8438b1
--- /dev/null
+++ b/src/net/port_fuchsia.go
@@ -0,0 +1,11 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import "errors"
+
+func goLookupPort(network, service string) (port int, err error) {
+ return -1, errors.New("net: port lookup not supported yet on fuchsia")
+}
diff --git a/src/net/protoconn_test.go b/src/net/protoconn_test.go
index 9f6772c..266657f 100644
--- a/src/net/protoconn_test.go
+++ b/src/net/protoconn_test.go
@@ -23,6 +23,10 @@
// golang.org/x/net/icmp
func TestTCPListenerSpecificMethods(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
switch runtime.GOOS {
case "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
@@ -115,6 +119,10 @@
}
func TestUDPConnSpecificMethods(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
la, err := ResolveUDPAddr("udp4", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
@@ -164,6 +172,10 @@
}
func TestIPConnSpecificMethods(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
if os.Getuid() != 0 {
t.Skip("must be root")
}
@@ -203,6 +215,10 @@
}
func TestUnixListenerSpecificMethods(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
if !testableNetwork("unix") {
t.Skip("unix test")
}
@@ -244,6 +260,10 @@
}
func TestUnixConnSpecificMethods(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
if !testableNetwork("unixgram") {
t.Skip("unixgram test")
}
diff --git a/src/net/rawconn_stub_test.go b/src/net/rawconn_stub_test.go
index 0a033c1..9c18a62 100644
--- a/src/net/rawconn_stub_test.go
+++ b/src/net/rawconn_stub_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build js,wasm nacl plan9
+// +build fuchsia js,wasm nacl plan9
package net
diff --git a/src/net/rawconn_test.go b/src/net/rawconn_test.go
index 11900df..e01318d 100644
--- a/src/net/rawconn_test.go
+++ b/src/net/rawconn_test.go
@@ -15,7 +15,7 @@
func TestRawConnReadWrite(t *testing.T) {
switch runtime.GOOS {
- case "nacl", "plan9":
+ case "fuchsia", "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
@@ -175,7 +175,7 @@
func TestRawConnControl(t *testing.T) {
switch runtime.GOOS {
- case "nacl", "plan9":
+ case "fuchsia", "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
diff --git a/src/net/sendfile_test.go b/src/net/sendfile_test.go
index 3b98277..67d2a46 100644
--- a/src/net/sendfile_test.go
+++ b/src/net/sendfile_test.go
@@ -13,6 +13,7 @@
"fmt"
"io"
"os"
+ "runtime"
"testing"
)
@@ -23,6 +24,10 @@
)
func TestSendfile(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
ln, err := newLocalListener("tcp")
if err != nil {
t.Fatal(err)
@@ -93,6 +98,11 @@
}
func TestSendfileParts(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
+
ln, err := newLocalListener("tcp")
if err != nil {
t.Fatal(err)
@@ -151,6 +161,11 @@
}
func TestSendfileSeeked(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
+
ln, err := newLocalListener("tcp")
if err != nil {
t.Fatal(err)
diff --git a/src/net/server_test.go b/src/net/server_test.go
index 1608beb..4bec5ae 100644
--- a/src/net/server_test.go
+++ b/src/net/server_test.go
@@ -8,6 +8,7 @@
import (
"os"
+ "runtime"
"testing"
)
@@ -53,6 +54,10 @@
// TestTCPServer tests concurrent accept-read-write servers.
func TestTCPServer(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
const N = 3
for i, tt := range tcpServerTests {
@@ -137,6 +142,10 @@
// TestUnixAndUnixpacketServer tests concurrent accept-read-write
// servers
func TestUnixAndUnixpacketServer(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
const N = 3
for i, tt := range unixAndUnixpacketServerTests {
@@ -251,6 +260,10 @@
}
func TestUDPServer(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
for i, tt := range udpServerTests {
if !testableListenArgs(tt.snet, tt.saddr, tt.taddr) {
t.Logf("skipping %s test", tt.snet+" "+tt.saddr+"<-"+tt.taddr)
@@ -329,6 +342,10 @@
}
func TestUnixgramServer(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
for i, tt := range unixgramServerTests {
if !testableListenArgs("unixgram", tt.saddr, "") {
t.Logf("skipping %s test", "unixgram "+tt.saddr+"<-"+tt.caddr)
diff --git a/src/net/sock_stub.go b/src/net/sock_stub.go
index 38fc819..1a09ecf 100644
--- a/src/net/sock_stub.go
+++ b/src/net/sock_stub.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build nacl js,wasm solaris
+// +build nacl js,wasm solaris fuchsia
package net
diff --git a/src/net/sockopt_stub.go b/src/net/sockopt_stub.go
index bc06675..7240cac 100644
--- a/src/net/sockopt_stub.go
+++ b/src/net/sockopt_stub.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build nacl js,wasm
+// +build nacl js,wasm fuchsia
package net
diff --git a/src/net/tcpsock_fuchsia.go b/src/net/tcpsock_fuchsia.go
new file mode 100644
index 0000000..447e9a9
--- /dev/null
+++ b/src/net/tcpsock_fuchsia.go
@@ -0,0 +1,85 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "context"
+ "io"
+ "os"
+ "syscall"
+ "syscall/zx/mxnet"
+)
+
+func (a *TCPAddr) encode() ([]byte, error) { // TODO remove
+ b := make([]byte, mxnet.SockaddrLen)
+ _, err := mxnet.EncodeSockaddr(b, mxnet.Addr(a.IP), uint16(a.Port))
+ return b, err
+}
+
+func (a *TCPAddr) family() int {
+ if a == nil || len(a.IP) <= IPv4len {
+ return syscall.AF_INET
+ }
+ if a.IP.To4() != nil {
+ return syscall.AF_INET
+ }
+ return syscall.AF_INET6
+}
+
+func (a *TCPAddr) sockaddr(family int) (addr mxnet.Addr, port uint16, err error) {
+ if a == nil {
+ return "", 0, nil
+ }
+ return ipToSockaddr(family, a.IP, a.Port, a.Zone)
+}
+
+func (c *TCPConn) readFrom(r io.Reader) (int64, error) {
+ return genericReadFrom(c, r)
+}
+
+func (sd *sysDialer) dialTCP(ctx context.Context, laddr, raddr *TCPAddr) (*TCPConn, error) {
+ if testHookDialTCP != nil {
+ return testHookDialTCP(ctx, sd.network, laddr, raddr)
+ }
+ return sd.doDialTCP(ctx, laddr, raddr)
+}
+
+func (sd *sysDialer) doDialTCP(ctx context.Context, laddr, raddr *TCPAddr) (*TCPConn, error) {
+ switch sd.network {
+ case "tcp", "tcp4", "tcp6":
+ default:
+ return nil, UnknownNetworkError(sd.network)
+ }
+ if raddr == nil {
+ return nil, errMissingAddress
+ }
+ fd, err := dialFuchsia(ctx, sd.network, laddr, raddr)
+ if err != nil {
+ return nil, err
+ }
+ return newTCPConn(fd), nil
+}
+
+func (ln *TCPListener) ok() bool { return ln != nil && ln.fd != nil }
+
+func (ln *TCPListener) accept() (*TCPConn, error) {
+ fd, err := ln.fd.accept()
+ if err != nil {
+ return nil, err
+ }
+ return newTCPConn(fd), nil
+}
+
+func (ln *TCPListener) close() error { return ln.fd.Close() }
+
+func (ln *TCPListener) file() (*os.File, error) { return ln.fd.dup() }
+
+func (sl *sysListener) listenTCP(ctx context.Context, laddr *TCPAddr) (*TCPListener, error) {
+ fd, err := dialFuchsia(ctx, sl.network, laddr, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &TCPListener{fd}, nil
+}
diff --git a/src/net/tcpsock_test.go b/src/net/tcpsock_test.go
index c2f26b1..e5bf8d8 100644
--- a/src/net/tcpsock_test.go
+++ b/src/net/tcpsock_test.go
@@ -328,6 +328,10 @@
}
func TestResolveTCPAddr(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
origTestHookLookupIP := testHookLookupIP
defer func() { testHookLookupIP = origTestHookLookupIP }()
testHookLookupIP = lookupLocalhost
@@ -428,6 +432,11 @@
}
func TestTCPConcurrentAccept(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
+
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
ln, err := Listen("tcp", "127.0.0.1:0")
if err != nil {
@@ -470,6 +479,10 @@
}
func TestTCPReadWriteAllocs(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
switch runtime.GOOS {
case "plan9":
// The implementation of asynchronous cancelable
@@ -543,6 +556,10 @@
}
func TestTCPStress(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
const conns = 2
const msgLen = 512
msgs := int(1e4)
@@ -625,6 +642,10 @@
}
func TestTCPSelfConnect(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
if runtime.GOOS == "windows" {
// TODO(brainman): do not know why it hangs.
t.Skip("known-broken test on windows")
@@ -674,6 +695,10 @@
// Test that >32-bit reads work on 64-bit systems.
// On 32-bit systems this tests that maxint reads work.
func TestTCPBig(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
if !*testTCPBig {
t.Skip("test disabled; use -tcpbig to enable")
}
@@ -727,6 +752,11 @@
}
func TestCopyPipeIntoTCP(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
+
ln, err := newLocalListener("tcp")
if err != nil {
t.Fatal(err)
diff --git a/src/net/tcpsock_unix_test.go b/src/net/tcpsock_unix_test.go
index 2bd591b..65d0a96 100644
--- a/src/net/tcpsock_unix_test.go
+++ b/src/net/tcpsock_unix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !js,!plan9,!windows
+// +build !fuchsia,!js,!plan9,!windows
package net
diff --git a/src/net/tcpsockopt_stub.go b/src/net/tcpsockopt_stub.go
index fd7f579..7e23c1f 100644
--- a/src/net/tcpsockopt_stub.go
+++ b/src/net/tcpsockopt_stub.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build nacl js,wasm
+// +build nacl js,wasm fuchsia
package net
diff --git a/src/net/timeout_test.go b/src/net/timeout_test.go
index 7c7d0c8..868890c 100644
--- a/src/net/timeout_test.go
+++ b/src/net/timeout_test.go
@@ -39,6 +39,10 @@
}
func TestDialTimeout(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
// Cannot use t.Parallel - modifies global hooks.
origTestHookDialChannel := testHookDialChannel
defer func() { testHookDialChannel = origTestHookDialChannel }()
@@ -46,7 +50,7 @@
for i, tt := range dialTimeoutTests {
switch runtime.GOOS {
- case "plan9", "windows":
+ case "plan9", "windows", "fuchsia":
testHookDialChannel = func() { time.Sleep(tt.guard) }
if runtime.GOOS == "plan9" {
break
@@ -102,9 +106,17 @@
}
func TestDialTimeoutMaxDuration(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
if runtime.GOOS == "openbsd" {
testenv.SkipFlaky(t, 15157)
}
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
ln, err := newLocalListener("tcp")
if err != nil {
@@ -154,6 +166,10 @@
}
func TestAcceptTimeout(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
testenv.SkipFlaky(t, 17948)
t.Parallel()
@@ -211,6 +227,10 @@
}
func TestAcceptTimeoutMustReturn(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
t.Parallel()
switch runtime.GOOS {
@@ -257,6 +277,10 @@
}
func TestAcceptTimeoutMustNotReturn(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
t.Parallel()
switch runtime.GOOS {
@@ -308,6 +332,10 @@
}
func TestReadTimeout(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
handler := func(ls *localServer, ln Listener) {
c, err := ln.Accept()
if err != nil {
@@ -362,6 +390,10 @@
}
func TestReadTimeoutMustNotReturn(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
t.Parallel()
switch runtime.GOOS {
@@ -432,6 +464,10 @@
}
func TestReadFromTimeout(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
switch runtime.GOOS {
case "nacl":
t.Skipf("not supported on %s", runtime.GOOS) // see golang.org/issue/8916
@@ -505,6 +541,10 @@
}
func TestWriteTimeout(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
t.Parallel()
ln, err := newLocalListener("tcp")
@@ -548,6 +588,10 @@
}
func TestWriteTimeoutMustNotReturn(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
t.Parallel()
switch runtime.GOOS {
@@ -619,6 +663,10 @@
}
func TestWriteToTimeout(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
t.Parallel()
switch runtime.GOOS {
@@ -672,6 +720,10 @@
}
func TestReadTimeoutFluctuation(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
t.Parallel()
ln, err := newLocalListener("tcp")
@@ -705,6 +757,10 @@
}
func TestReadFromTimeoutFluctuation(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
t.Parallel()
c1, err := newLocalPacketListener("udp")
@@ -738,6 +794,10 @@
}
func TestWriteTimeoutFluctuation(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
t.Parallel()
switch runtime.GOOS {
@@ -780,11 +840,19 @@
}
func TestVariousDeadlines(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
t.Parallel()
testVariousDeadlines(t)
}
func TestVariousDeadlines1Proc(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
// Cannot use t.Parallel - modifies global GOMAXPROCS.
if testing.Short() {
t.Skip("skipping in short mode")
@@ -794,6 +862,10 @@
}
func TestVariousDeadlines4Proc(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
// Cannot use t.Parallel - modifies global GOMAXPROCS.
if testing.Short() {
t.Skip("skipping in short mode")
@@ -925,6 +997,10 @@
// TestReadWriteProlongedTimeout tests concurrent deadline
// modification. Known to cause data races in the past.
func TestReadWriteProlongedTimeout(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
t.Parallel()
switch runtime.GOOS {
@@ -1005,6 +1081,10 @@
}
func TestReadWriteDeadlineRace(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
t.Parallel()
switch runtime.GOOS {
diff --git a/src/net/udpsock_fuchsia.go b/src/net/udpsock_fuchsia.go
new file mode 100644
index 0000000..b97e1ef
--- /dev/null
+++ b/src/net/udpsock_fuchsia.go
@@ -0,0 +1,92 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "context"
+ "syscall"
+ "syscall/zx/mxnet"
+)
+
+func (a *UDPAddr) encode() ([]byte, error) {
+ b := make([]byte, mxnet.SockaddrLen)
+ _, err := mxnet.EncodeSockaddr(b, mxnet.Addr(a.IP), uint16(a.Port))
+ return b, err
+}
+
+func (a *UDPAddr) family() int {
+ if a == nil || len(a.IP) <= IPv4len {
+ return syscall.AF_INET
+ }
+ if a.IP.To4() != nil {
+ return syscall.AF_INET
+ }
+ return syscall.AF_INET6
+}
+
+func (a *UDPAddr) sockaddr(family int) (addr mxnet.Addr, port uint16, err error) {
+ if a == nil {
+ return "", 0, nil
+ }
+ return ipToSockaddr(family, a.IP, a.Port, a.Zone)
+}
+
+func (c *UDPConn) readFrom(b []byte) (n int, addr *UDPAddr, err error) {
+ panic("TODO readFrom")
+}
+
+func (c *UDPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
+ n, flags, addrstr, port, err := c.fd.readMsg(b)
+ if err != nil {
+ return 0, 0, 0, nil, err
+ }
+ addr = &UDPAddr{
+ IP: IP(addrstr),
+ Port: int(port),
+ }
+ return n, 0, flags, addr, nil
+}
+
+func (c *UDPConn) writeTo(b []byte, addr *UDPAddr) (int, error) {
+ panic("TODO writeTo")
+}
+
+func (c *UDPConn) writeMsg(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
+ if len(oob) > 0 {
+ return 0, 0, syscall.EFUCHSIA
+ }
+ n, err = c.fd.sendMsg(b, string(addr.IP), uint16(addr.Port))
+ return n, 0, err
+}
+
+func (sd *sysDialer) dialUDP(ctx context.Context, laddr, raddr *UDPAddr) (*UDPConn, error) {
+ switch sd.network {
+ case "udp", "udp4", "udp6":
+ default:
+ return nil, UnknownNetworkError(sd.network)
+ }
+ if raddr == nil {
+ return nil, errMissingAddress
+ }
+ var laddrif sockaddr
+ if laddr != nil {
+ laddrif = laddr
+ }
+ fd, err := dialFuchsia(ctx, sd.network, laddrif, raddr)
+ if err != nil {
+ return nil, err
+ }
+ return newUDPConn(fd), nil
+}
+
+const udpHeaderSize = 16*3 + 2*2
+
+func (sl *sysListener) listenUDP(ctx context.Context, laddr *UDPAddr) (*UDPConn, error) {
+ panic("TODO listenUDP")
+}
+
+func (sl *sysListener) listenMulticastUDP(ctx context.Context, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
+ return nil, syscall.EFUCHSIA
+}
diff --git a/src/net/udpsock_test.go b/src/net/udpsock_test.go
index 4940644..977b2a8 100644
--- a/src/net/udpsock_test.go
+++ b/src/net/udpsock_test.go
@@ -15,6 +15,10 @@
)
func BenchmarkUDP6LinkLocalUnicast(b *testing.B) {
+ if runtime.GOOS == "fuchsia" {
+ b.Skip("Fuchsia doesn't implement UDP")
+ }
+
testHookUninstaller.Do(uninstallTestHooks)
if !supportsIPv6() {
@@ -88,6 +92,10 @@
}
func TestResolveUDPAddr(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
origTestHookLookupIP := testHookLookupIP
defer func() { testHookLookupIP = origTestHookLookupIP }()
testHookLookupIP = lookupLocalhost
@@ -108,6 +116,10 @@
}
func TestWriteToUDP(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
switch runtime.GOOS {
case "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
@@ -124,6 +136,10 @@
}
func testWriteToConn(t *testing.T, raddr string) {
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("Fuchsia doesn't implement UDP")
+ }
+
c, err := Dial("udp", raddr)
if err != nil {
t.Fatal(err)
@@ -173,6 +189,10 @@
}
func testWriteToPacketConn(t *testing.T, raddr string) {
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("Fuchsia doesn't implement UDP")
+ }
+
c, err := ListenPacket("udp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
@@ -241,6 +261,10 @@
}
func TestUDPConnLocalAndRemoteNames(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
for _, laddr := range []string{"", "127.0.0.1:0"} {
c1, err := ListenPacket("udp", "127.0.0.1:0")
if err != nil {
@@ -334,6 +358,10 @@
}
func TestUDPZeroBytePayload(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
switch runtime.GOOS {
case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
@@ -371,6 +399,10 @@
}
func TestUDPZeroByteBuffer(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
switch runtime.GOOS {
case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
@@ -409,7 +441,7 @@
func TestUDPReadSizeError(t *testing.T) {
switch runtime.GOOS {
- case "nacl", "plan9":
+ case "fuchsia", "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
diff --git a/src/net/unixsock_fuchsia.go b/src/net/unixsock_fuchsia.go
new file mode 100644
index 0000000..1ed9304
--- /dev/null
+++ b/src/net/unixsock_fuchsia.go
@@ -0,0 +1,51 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "context"
+ "os"
+ "syscall"
+)
+
+func (c *UnixConn) readFrom(b []byte) (int, *UnixAddr, error) {
+ return 0, nil, syscall.EFUCHSIA
+}
+
+func (c *UnixConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
+ return 0, 0, 0, nil, syscall.EFUCHSIA
+}
+
+func (c *UnixConn) writeTo(b []byte, addr *UnixAddr) (int, error) {
+ return 0, syscall.EFUCHSIA
+}
+
+func (c *UnixConn) writeMsg(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
+ return 0, 0, syscall.EFUCHSIA
+}
+
+func (sd *sysDialer) dialUnix(ctx context.Context, laddr, raddr *UnixAddr) (*UnixConn, error) {
+ return nil, syscall.EFUCHSIA
+}
+
+func (ln *UnixListener) accept() (*UnixConn, error) {
+ return nil, syscall.EFUCHSIA
+}
+
+func (ln *UnixListener) close() error {
+ return syscall.EFUCHSIA
+}
+
+func (ln *UnixListener) file() (*os.File, error) {
+ return nil, syscall.EFUCHSIA
+}
+
+func (sl *sysListener) listenUnix(ctx context.Context, laddr *UnixAddr) (*UnixListener, error) {
+ return nil, syscall.EFUCHSIA
+}
+
+func (sl *sysListener) listenUnixgram(ctx context.Context, laddr *UnixAddr) (*UnixConn, error) {
+ return nil, syscall.EFUCHSIA
+}
diff --git a/src/net/unixsock_test.go b/src/net/unixsock_test.go
index 4828990..b725be5 100644
--- a/src/net/unixsock_test.go
+++ b/src/net/unixsock_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !js,!nacl,!plan9,!windows
+// +build !js,!nacl,!plan9,!windows,!fuchsia
package net
diff --git a/src/net/writev_test.go b/src/net/writev_test.go
index c43be84..933c826 100644
--- a/src/net/writev_test.go
+++ b/src/net/writev_test.go
@@ -19,6 +19,10 @@
)
func TestBuffers_read(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
const story = "once upon a time in Gopherland ... "
buffers := Buffers{
[]byte("once "),
@@ -41,6 +45,10 @@
}
func TestBuffers_consume(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
tests := []struct {
in Buffers
consume int64
@@ -92,6 +100,10 @@
}
func TestBuffers_WriteTo(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
for _, name := range []string{"WriteTo", "Copy"} {
for _, size := range []int{0, 10, 1023, 1024, 1025} {
t.Run(fmt.Sprintf("%s/%d", name, size), func(t *testing.T) {
@@ -183,6 +195,10 @@
}
func TestWritevError(t *testing.T) {
+ // TODO(TC-149): disabled without further triage. Needs work.
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("network test disabled for GOOS=fuchsia")
+ }
if runtime.GOOS == "windows" {
t.Skipf("skipping the test: windows does not have problem sending large chunks of data")
}
diff --git a/src/os/dir_unix.go b/src/os/dir_unix.go
index 79d61c7..604f0c2 100644
--- a/src/os/dir_unix.go
+++ b/src/os/dir_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia js,wasm linux nacl netbsd openbsd solaris
package os
diff --git a/src/os/error_fuchsia.go b/src/os/error_fuchsia.go
new file mode 100644
index 0000000..2572f7e
--- /dev/null
+++ b/src/os/error_fuchsia.go
@@ -0,0 +1,50 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package os
+
+import (
+ "syscall"
+ "syscall/zx"
+)
+
+func isExist(err error) bool {
+ err = underlyingError(err)
+ switch err := err.(type) {
+ case zx.Error:
+ return err.Status == zx.ErrAlreadyExists
+ }
+ return err == syscall.EEXIST || err == syscall.ENOTEMPTY || err == ErrExist
+}
+
+func isNotExist(err error) bool {
+ err = underlyingError(err)
+ switch err := err.(type) {
+ case zx.Error:
+ return err.Status == zx.ErrNotFound
+ }
+ return err == syscall.ENOENT || err == ErrNotExist
+}
+
+func isPermission(err error) bool {
+ err = underlyingError(err)
+ switch err := err.(type) {
+ case zx.Error:
+ return err.Status == zx.ErrAccessDenied
+ }
+ return err == syscall.EACCES || err == syscall.EPERM || err == ErrPermission
+}
+
+func wrapSyscallError(name string, err error) error {
+ if zerr, ok := err.(zx.Error); ok {
+ text := name
+ if zerr.Text != "" {
+ text = text + ": " + zerr.Text
+ }
+ err = zx.Error{Status: zerr.Status, Text: zerr.Text}
+ }
+ return err
+}
diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go
index 7bb2308..aad9500 100644
--- a/src/os/exec/exec_test.go
+++ b/src/os/exec/exec_test.go
@@ -537,7 +537,7 @@
func TestExtraFiles(t *testing.T) {
testenv.MustHaveExec(t)
- if runtime.GOOS == "windows" {
+ if runtime.GOOS == "windows" || runtime.GOOS == "fuchsia" {
t.Skipf("skipping test on %q", runtime.GOOS)
}
@@ -612,7 +612,7 @@
}
func TestExtraFilesRace(t *testing.T) {
- if runtime.GOOS == "windows" {
+ if runtime.GOOS == "windows" || runtime.GOOS == "fuchsia" {
t.Skip("no operating system support; skipping")
}
listen := func() net.Listener {
diff --git a/src/os/exec/lp_unix.go b/src/os/exec/lp_unix.go
index e098ff8..97b5b72 100644
--- a/src/os/exec/lp_unix.go
+++ b/src/os/exec/lp_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia linux nacl netbsd openbsd solaris
package exec
diff --git a/src/os/exec_fuchsia.go b/src/os/exec_fuchsia.go
new file mode 100644
index 0000000..87d6020
--- /dev/null
+++ b/src/os/exec_fuchsia.go
@@ -0,0 +1,83 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+ "errors"
+ "syscall/zx"
+ "time"
+)
+
+type ProcessState struct {
+ retCode int
+}
+
+func (p *ProcessState) exited() bool {
+ panic("TODO os.Exited")
+}
+
+func (p *ProcessState) Pid() int {
+ panic("TODO os.Pid")
+}
+
+func (p *ProcessState) String() string {
+ if p == nil {
+ return "<nil>"
+ }
+ return "exit status " + itoa(p.retCode)
+}
+
+func (p *ProcessState) success() bool {
+ return p.retCode == 0
+}
+
+func (p *ProcessState) sys() interface{} {
+ panic("TODO os.sys")
+}
+
+func (p *ProcessState) sysUsage() interface{} {
+ panic("TODO os.sysUsage")
+}
+
+func (p *ProcessState) systemTime() time.Duration {
+ panic("TODO os.systemTime")
+}
+
+func (p *ProcessState) userTime() time.Duration {
+ panic("TODO os.userTime")
+}
+
+func (p *Process) release() error {
+ procHandle := zx.Handle(p.handle)
+ return procHandle.Close()
+}
+
+func (p *Process) signal(sig Signal) error {
+ panic("TODO os.Process.signal")
+}
+
+func findProcess(pid int) (p *Process, err error) {
+ panic("TODO os.findProcess")
+}
+
+func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
+ h, err := fdioStartProcess(name, argv, attr)
+ if err != nil {
+ return nil, err
+ }
+ pid := 1 // TODO: what does this even mean for us?
+ return newProcess(pid, uintptr(h)), nil
+}
+
+func hostname() (name string, err error) {
+ return "", errors.New("os.hostname unimplemented")
+}
+
+type signal string
+
+func (s signal) String() string { return string(s) }
+func (s signal) Signal() {}
+
+var Interrupt = signal("signal_interrupt")
diff --git a/src/os/exec_fuchsia_cgo.go b/src/os/exec_fuchsia_cgo.go
new file mode 100644
index 0000000..7297daa
--- /dev/null
+++ b/src/os/exec_fuchsia_cgo.go
@@ -0,0 +1,206 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package os
+
+// #cgo fuchsia CFLAGS: -I${SRCDIR}/../../../../../zircon/system/ulib/fdio/include
+// #cgo fuchsia LDFLAGS: -lfdio
+//
+// #include <zircon/syscalls/object.h>
+// #include <zircon/types.h>
+// #include <lib/fdio/spawn.h>
+// #include <lib/fdio/util.h>
+// #include <stdlib.h>
+//
+// static int fsa_get_local_fd(fdio_spawn_action_t *fsa) { return fsa->fd.local_fd; }
+// static int fsa_get_target_fd(fdio_spawn_action_t *fsa) { return fsa->fd.target_fd; }
+//
+// static void fsa_set_local_fd(fdio_spawn_action_t *fsa, int fd) { fsa->fd.local_fd = fd; }
+// static void fsa_set_target_fd(fdio_spawn_action_t *fsa, int fd) { fsa->fd.target_fd = fd; }
+import "C"
+
+import (
+ "errors"
+ "strings"
+ "syscall"
+ "syscall/zx"
+ "syscall/zx/fdio"
+ "syscall/zx/zxwait"
+ "unsafe"
+)
+
+func makeCStringArray(s []string) []*C.char {
+ ret := make([]*C.char, len(s)+1)
+ for i, s := range s {
+ ret[i] = (*C.char)(C.CString(s))
+ }
+ ret[len(ret)-1] = nil
+ return ret
+}
+
+func freeCStringArray(a []*C.char) {
+ for i := range a {
+ if a[i] != nil {
+ C.free(unsafe.Pointer(a[i]))
+ }
+ }
+}
+
+// asLibfdioFD returns a File as a libfdio file descriptor.
+func asLibfdioFD(f *File) (int, error) {
+ m := syscall.FDIOForFD(int(f.Fd()))
+ if m == nil {
+ return -1, ErrInvalid
+ }
+
+ var fdioType C.uint32_t
+ switch m.(type) {
+ case *fdio.Object, *fdio.Node, *fdio.File, *fdio.Directory:
+ fdioType = fdio.HandleTypeRemote
+ case *fdio.Pipe:
+ fdioType = fdio.HandleTypePipe
+ case *fdio.Logger:
+ fdioType = fdio.HandleTypeLogger
+ default:
+ return -1, ErrInvalid
+ }
+
+ mCopy, err := m.Clone()
+ if err != nil {
+ return -1, err
+ }
+ handles := mCopy.Handles()
+
+ var handlesC [fdio.MaxUnderlyingHandles]C.zx_handle_t
+ var typesC [fdio.MaxUnderlyingHandles]C.uint32_t
+ for i, h := range handles {
+ handlesC[i] = C.zx_handle_t(h)
+ typesC[i] = C.uint32_t(fdioType)
+ }
+
+ var fd C.int
+ status := zx.Status(C.fdio_create_fd(&handlesC[0], &typesC[0], C.size_t(len(handles)), &fd))
+ if status != zx.ErrOk {
+ mCopy.Close()
+ return -1, errors.New("fdio_create_fd failed")
+ }
+ return int(fd), nil
+}
+
+func fdioSpawnActions(attr *ProcAttr) (actions []C.fdio_spawn_action_t, err error) {
+ defer func() {
+ if err != nil {
+ for _, action := range actions {
+ C.close(C.fsa_get_local_fd(&action))
+ }
+ }
+ }()
+
+ for i, f := range attr.Files {
+ if f == nil {
+ continue
+ }
+ fd, err := asLibfdioFD(f)
+ if err != nil {
+ return nil, err
+ }
+ action := C.fdio_spawn_action_t{action: C.FDIO_SPAWN_ACTION_TRANSFER_FD}
+ C.fsa_set_local_fd(&action, C.int(fd))
+ C.fsa_set_target_fd(&action, C.int(i))
+ actions = append(actions, action)
+ }
+
+ return actions, nil
+}
+
+func fdioStartProcess(name string, argv []string, attr *ProcAttr) (zx.Handle, error) {
+ env := attr.Env
+ if env == nil {
+ env = Environ()
+ }
+ if attr.Dir != "" {
+ found := false
+ for i, s := range env {
+ if strings.HasPrefix(s, "PWD=") {
+ found = true
+ env[i] = "PWD=" + attr.Dir
+ break
+ }
+ }
+ if !found {
+ env = append(env, "PWD="+attr.Dir)
+ }
+ }
+
+ nameC := C.CString(name)
+ defer C.free(unsafe.Pointer(nameC))
+ argvC := makeCStringArray(argv)
+ defer freeCStringArray(argvC)
+ envC := makeCStringArray(env)
+ defer freeCStringArray(envC)
+
+ actions, err := fdioSpawnActions(attr)
+ if err != nil {
+ return 0, err
+ }
+
+ var actions0 *C.fdio_spawn_action_t
+ if len(actions) > 0 {
+ actions0 = &actions[0]
+ }
+
+ var h C.zx_handle_t
+ var errmsg [C.FDIO_SPAWN_ERR_MSG_MAX_LENGTH]C.char
+ status := zx.Status(C.fdio_spawn_etc(
+ C.ZX_HANDLE_INVALID,
+ C.FDIO_SPAWN_CLONE_JOB | C.FDIO_SPAWN_CLONE_LDSVC | C.FDIO_SPAWN_CLONE_NAMESPACE, // TODO(mdempsky): Flags.
+ nameC,
+ &argvC[0],
+ &envC[0],
+ C.size_t(len(actions)),
+ actions0,
+ &h,
+ &errmsg[0],
+ ))
+ if status != zx.ErrOk {
+ return 0, errors.New("fdio_spawn_etc: " + itoa(int(status)) + ": " + charsAsString(errmsg[:]))
+ }
+ return zx.Handle(h), nil
+}
+
+func charsAsString(s []C.char) string {
+ var x []byte
+ for _, c := range s {
+ if c == 0 {
+ break
+ }
+ x = append(x, byte(c))
+ }
+ return string(x)
+}
+
+func (p *Process) kill() error {
+ procHandle := zx.Handle(p.handle)
+ status := zx.Sys_task_kill(procHandle)
+ if status != zx.ErrOk {
+ return errors.New("kill error: " + itoa(int(status)))
+ }
+ return nil
+}
+
+func (p *Process) wait() (ps *ProcessState, err error) {
+ procHandle := zx.Handle(p.handle)
+ _, err = zxwait.Wait(procHandle, zx.SignalTaskTerminated, zx.TimensecInfinite)
+ if err != nil {
+ return nil, err
+ }
+ procInfo := C.zx_info_process_t{}
+ status := zx.Sys_object_get_info(procHandle, zx.ObjectInfoProcess, unsafe.Pointer(&procInfo), C.sizeof_zx_info_process_t, nil, nil)
+ if status != zx.ErrOk {
+ return nil, errors.New("error retreiving process info: " + itoa(int(status)))
+ }
+ return &ProcessState{int(procInfo.return_code)}, nil
+}
diff --git a/src/os/executable_procfs.go b/src/os/executable_procfs.go
index 5bb63b9..3c35f23 100644
--- a/src/os/executable_procfs.go
+++ b/src/os/executable_procfs.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build linux netbsd dragonfly nacl js,wasm
+// +build linux netbsd dragonfly nacl js,wasm fuchsia
package os
diff --git a/src/os/executable_test.go b/src/os/executable_test.go
index 4a9a883..125d1a3 100644
--- a/src/os/executable_test.go
+++ b/src/os/executable_test.go
@@ -20,6 +20,9 @@
testenv.MustHaveExec(t) // will also exclude nacl, which doesn't support Executable anyway
ep, err := os.Executable()
if err != nil {
+ if runtime.GOOS == "fuchsia" {
+ t.Skipf("Executable failed on %s: %v, expected", runtime.GOOS, err) // TODO(dhobsd): rebase
+ }
t.Fatalf("Executable failed: %v", err)
}
// we want fn to be of the form "dir/prog"
diff --git a/src/os/file_fuchsia.go b/src/os/file_fuchsia.go
new file mode 100644
index 0000000..31ff6af
--- /dev/null
+++ b/src/os/file_fuchsia.go
@@ -0,0 +1,152 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+ "errors"
+ "internal/poll"
+ "syscall"
+ "syscall/zx/fdio"
+ "time"
+)
+
+func (f *File) Truncate(size int64) error {
+ if err := f.checkValid("truncate"); err != nil {
+ return err
+ }
+ return syscall.Ftruncate(f.pfd.Sysfd, size)
+}
+
+func (f *File) Sync() error {
+ if f == nil {
+ return ErrInvalid
+ }
+ return syscall.Fsync(f.pfd.Sysfd)
+}
+
+func syscallMode(i FileMode) (o uint32) {
+ o |= uint32(i.Perm())
+ // TODO i&ModeSetuid != 0
+ // TODO i&ModeSetgid != 0
+ // TODO i&ModeSticky != 0
+ return o
+}
+
+func (f *File) chmod(mode FileMode) error {
+ return errors.New("os: Chmod unimplemented on fuchsia")
+}
+
+func (f *File) Chown(uid, gid int) error {
+ return errors.New("os: Chown unimplemented on fuchsia")
+}
+
+func chmod(name string, mode FileMode) error {
+ return errors.New("os: chmod unimplemented on fuchsia")
+}
+
+func Chown(name string, uid, gid int) error {
+ return errors.New("os: Chown unimplemented on fuchsia")
+}
+
+func Chtimes(name string, atime time.Time, mtime time.Time) error {
+ var utimes [2]syscall.Timespec
+ utimes[0] = syscall.NsecToTimespec(atime.UnixNano())
+ utimes[1] = syscall.NsecToTimespec(mtime.UnixNano())
+ if e := syscall.UtimesNano(fixLongPath(name), utimes[0:]); e != nil {
+ return &PathError{"chtimes", name, e}
+ }
+ return nil
+}
+
+func Readlink(name string) (string, error) {
+ return "", errors.New("Readlink unimplemented")
+}
+
+func Pipe() (r *File, w *File, err error) {
+ p0, p1, err := fdio.NewPipes()
+ if err != nil {
+ return nil, nil, err
+ }
+ r = NewFile(uintptr(syscall.OpenFDIO(p0)), "|0")
+ w = NewFile(uintptr(syscall.OpenFDIO(p1)), "|1")
+ // TODO CloseOnExec equivalent
+ return r, w, nil
+}
+
+// Chdir changes the current working directory to the file,
+// which must be a directory.
+// If there is an error, it will be of type *PathError.
+func (f *File) Chdir() error {
+ if err := f.checkValid("chdir"); err != nil {
+ return err
+ }
+ if e := syscall.Fchdir(f.pfd.Sysfd); e != nil {
+ return &PathError{"chdir", f.name, e}
+ }
+ return nil
+}
+
+func sigpipe() // implemented in package runtime
+
+var supportsCloseOnExec = true
+
+func fillFileStatFromSys(fs *fileStat, name string) {
+ fs.name = basename(name)
+ fs.size = int64(fs.sys.Size)
+ // For now, pretend files have all bits. This should really be:
+ // fs.mode = FileMode(fs.sys.Dev & 0777)
+ // but we don't really set file modes properly and testing for executables
+ // in $PATH fails without the x bit set.
+ fs.mode = FileMode(0766)
+
+ switch fs.sys.Dev & 0xf000 {
+ case 0x4000:
+ fs.mode = fs.mode | ModeDir
+ case 0x2000:
+ fs.mode = fs.mode | ModeCharDevice
+ case 0xa000:
+ fs.mode = fs.mode | ModeSymlink
+ case 0xc000:
+ fs.mode = fs.mode | ModeSocket
+ }
+ fs.modTime = time.Unix(int64(fs.sys.ModifyTime), 0)
+}
+
+func atime(fi FileInfo) time.Time {
+ // TODO: fdio doesn't have atime yet
+ return time.Time{}
+}
+
+// setDeadline sets the read and write deadline.
+func (f *File) setDeadline(time.Time) error {
+ if err := f.checkValid("SetDeadline"); err != nil {
+ return err
+ }
+ return poll.ErrNoDeadline
+}
+
+// setReadDeadline sets the read deadline.
+func (f *File) setReadDeadline(time.Time) error {
+ if err := f.checkValid("SetReadDeadline"); err != nil {
+ return err
+ }
+ return poll.ErrNoDeadline
+}
+
+// setWriteDeadline sets the write deadline.
+func (f *File) setWriteDeadline(time.Time) error {
+ if err := f.checkValid("SetWriteDeadline"); err != nil {
+ return err
+ }
+ return poll.ErrNoDeadline
+}
+
+// checkValid checks whether f is valid for use.
+func (f *File) checkValid(op string) error {
+ if f == nil {
+ return ErrInvalid
+ }
+ return nil
+}
diff --git a/src/os/file_unix.go b/src/os/file_unix.go
index cb90b70..9451be1 100644
--- a/src/os/file_unix.go
+++ b/src/os/file_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia js,wasm linux nacl netbsd openbsd solaris
package os
diff --git a/src/os/getwd.go b/src/os/getwd.go
index 6d25466..39a4fd2 100644
--- a/src/os/getwd.go
+++ b/src/os/getwd.go
@@ -24,7 +24,7 @@
// reached via multiple paths (due to symbolic links),
// Getwd may return any one of them.
func Getwd() (dir string, err error) {
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" || runtime.GOOS == "fuchsia" {
return syscall.Getwd()
}
diff --git a/src/os/os_test.go b/src/os/os_test.go
index 894105a..459b90e 100644
--- a/src/os/os_test.go
+++ b/src/os/os_test.go
@@ -26,15 +26,45 @@
"time"
)
-var dot = []string{
- "dir_unix.go",
- "env.go",
- "error.go",
- "file.go",
- "os_test.go",
- "types.go",
- "stat_darwin.go",
- "stat_linux.go",
+var dot = func() []string {
+ switch runtime.GOOS {
+ case "fuchsia":
+ return []string{
+ "go_os_test_foo",
+ "go_os_test_bar",
+ "go_os_test_baz",
+ }
+ default:
+ return []string{
+ "dir_unix.go",
+ "env.go",
+ "error.go",
+ "file.go",
+ "os_test.go",
+ "types.go",
+ "stat_darwin.go",
+ "stat_linux.go",
+ }
+ }
+}()
+
+func init() { flag.CommandLine.Set("test.v", "true") }
+
+func tmpInit(t *testing.T) {
+ if runtime.GOOS == "fuchsia" {
+ dir, err := ioutil.TempDir("", "")
+ if err != nil {
+ t.Fatalf("tempdir: %v", err)
+ }
+ for _, fname := range dot {
+ if err := MkdirAll(filepath.Join(dir, fname), ModePerm); err != nil {
+ t.Fatalf("Initializing tmp: %v", err)
+ }
+ }
+ if err := Chdir(dir); err != nil {
+ t.Fatalf("chdir: %v", err)
+ }
+ }
}
type sysDir struct {
@@ -44,6 +74,14 @@
var sysdir = func() *sysDir {
switch runtime.GOOS {
+ case "fuchsia":
+ return &sysDir{
+ "/boot/lib",
+ []string{
+ "libfdio.so",
+ "ld.so.1",
+ },
+ }
case "android":
return &sysDir{
"/system/lib",
@@ -175,6 +213,9 @@
}
func TestStatError(t *testing.T) {
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("TODO(dhobsd): fix")
+ }
defer chtmpdir(t)()
path := "no-such-file"
@@ -347,11 +388,13 @@
}
func TestReaddirnames(t *testing.T) {
+ tmpInit(t)
testReaddirnames(".", dot, t)
testReaddirnames(sysdir.name, sysdir.files, t)
}
func TestReaddir(t *testing.T) {
+ tmpInit(t)
testReaddir(".", dot, t)
testReaddir(sysdir.name, sysdir.files, t)
}
@@ -469,6 +512,8 @@
// big directory that doesn't change often.
dir := "/usr/bin"
switch runtime.GOOS {
+ case "fuchsia":
+ dir = "/boot/bin"
case "android":
dir = "/system/bin"
case "darwin":
@@ -1030,6 +1075,8 @@
switch runtime.GOOS {
case "android":
t.Skip("android doesn't have /bin/pwd")
+ case "fuchsia":
+ t.Skip("fuchsia doesn't have /bin/pwd")
case "windows":
cmd = Getenv("COMSPEC")
dir = Getenv("SystemRoot")
@@ -1063,8 +1110,8 @@
}
func TestChmod(t *testing.T) {
- // Chmod is not supported under windows.
- if runtime.GOOS == "windows" {
+ // Chmod is not supported under windows or Fuchsia
+ if runtime.GOOS == "windows" || runtime.GOOS == "fuchsia" {
return
}
f := newFile("TestChmod", t)
@@ -1137,6 +1184,11 @@
// On NFS, timings can be off due to caching of meta-data on
// NFS servers (Issue 848).
func TestChtimes(t *testing.T) {
+ if runtime.GOOS == "fuchsia" {
+ // It passes sometimes, but seems to be flakey
+ t.Skipf("TODO(smklein): Implement")
+ }
+
f := newFile("TestChtimes", t)
defer Remove(f.Name())
@@ -1151,6 +1203,11 @@
// On NFS, timings can be off due to caching of meta-data on
// NFS servers (Issue 848).
func TestChtimesDir(t *testing.T) {
+ if runtime.GOOS == "fuchsia" {
+ // It passes sometimes, but seems to be flakey
+ t.Skipf("TODO(smklein): Implement")
+ }
+
name := newDir("TestChtimes", t)
defer RemoveAll(name)
@@ -1182,7 +1239,7 @@
pmt := postStat.ModTime()
if !pat.Before(at) {
switch runtime.GOOS {
- case "plan9", "nacl":
+ case "plan9", "nacl", "fuchsia":
// Ignore.
// Plan 9, NaCl:
// Mtime is the time of the last change of
@@ -1208,7 +1265,7 @@
func TestChdirAndGetwd(t *testing.T) {
// TODO(brainman): file.Chdir() is not implemented on windows.
- if runtime.GOOS == "windows" {
+ if runtime.GOOS == "windows" || runtime.GOOS == "fuchsia" {
return
}
fd, err := Open(".")
@@ -1439,6 +1496,10 @@
}
func TestOpenError(t *testing.T) {
+ if runtime.GOOS == "fuchsia" {
+ t.Skipf("TODO(smklein): Implement")
+ }
+
for _, tt := range openErrorTests {
f, err := OpenFile(tt.path, tt.mode, 0)
if err == nil {
@@ -1536,6 +1597,10 @@
}
func TestHostname(t *testing.T) {
+ if runtime.GOOS == "fuchsia" {
+ t.Skipf("TODO(dho): Implement")
+ }
+
hostname, err := Hostname()
if err != nil {
t.Fatal(err)
@@ -1760,6 +1825,10 @@
}
func TestSameFile(t *testing.T) {
+ if runtime.GOOS == "fuchsia" {
+ t.Skipf("TODO(smklein): Implement")
+ }
+
defer chtmpdir(t)()
fa, err := Create("a")
if err != nil {
@@ -1810,13 +1879,13 @@
if fi.Size() != 0 {
t.Errorf(pre+"wrong file size have %d want 0", fi.Size())
}
- if fi.Mode()&ModeDevice == 0 {
+ if fi.Mode()&ModeDevice == 0 && runtime.GOOS != "fuchsia" {
t.Errorf(pre+"wrong file mode %q: ModeDevice is not set", fi.Mode())
}
if fi.Mode()&ModeCharDevice == 0 {
t.Errorf(pre+"wrong file mode %q: ModeCharDevice is not set", fi.Mode())
}
- if fi.Mode().IsRegular() {
+ if fi.Mode().IsRegular() && runtime.GOOS != "fuchsia" {
t.Errorf(pre+"wrong file mode %q: IsRegular returns true", fi.Mode())
}
}
@@ -1873,6 +1942,10 @@
}
func TestStatDirModeExec(t *testing.T) {
+ if runtime.GOOS == "fuchsia" {
+ t.Skipf("TODO(smklein): Implement")
+ }
+
const mode = 0111
path, err := ioutil.TempDir("", "go-build")
@@ -1896,7 +1969,8 @@
func TestStatStdin(t *testing.T) {
switch runtime.GOOS {
- case "android", "plan9":
+ case "android", "plan9", "fuchsia":
+ // TODO(smklein): Implement on Fuchsia
t.Skipf("%s doesn't have /bin/sh", runtime.GOOS)
}
@@ -2012,6 +2086,10 @@
}
func TestLongPath(t *testing.T) {
+ if runtime.GOOS == "fuchsia" {
+ t.Skipf("no chmod support on fuchsia")
+ }
+
tmpdir := newDir("TestLongPath", t)
defer func(d string) {
if err := RemoveAll(d); err != nil {
@@ -2068,9 +2146,11 @@
if dir.Size() != filesize || filesize != wantSize {
t.Errorf("Size(%q) is %d, len(ReadFile()) is %d, want %d", path, dir.Size(), filesize, wantSize)
}
- err = Chmod(path, dir.Mode())
- if err != nil {
- t.Fatalf("Chmod(%q) failed: %v", path, err)
+ if testenv.HasChmod() {
+ err = Chmod(path, dir.Mode())
+ if err != nil {
+ t.Fatalf("Chmod(%q) failed: %v", path, err)
+ }
}
}
if err := Truncate(sizedTempDir+"/bar.txt", 0); err != nil {
@@ -2123,6 +2203,9 @@
// TODO: golang.org/issue/8206
t.Skipf("skipping test on plan9; see issue 8206")
}
+ if runtime.GOOS == "fuchsia" {
+ t.Skipf("TODO(smklein): Implement")
+ }
testenv.MustHaveExec(t)
@@ -2148,6 +2231,10 @@
}
func TestKillFindProcess(t *testing.T) {
+ if runtime.GOOS == "fuchsia" {
+ t.Skipf("TODO(smklein): Implement")
+ }
+
testKillProcess(t, func(p *Process) {
p2, err := FindProcess(p.Pid)
if err != nil {
@@ -2183,6 +2270,10 @@
// Test that all File methods give ErrInvalid if the receiver is nil.
func TestNilFileMethods(t *testing.T) {
+ if runtime.GOOS == "fuchsia" {
+ t.Skipf("TODO(smklein): Implement")
+ }
+
for _, tt := range nilFileMethodTests {
var file *File
got := tt.f(file)
@@ -2254,6 +2345,8 @@
t.Skip("skipping on Plan 9; does not support runtime poller")
case "js":
t.Skip("skipping on js; no support for os.Pipe")
+ case "fuchsia":
+ t.Skip("skipping on fuchsia; TODO")
}
threads := 100
diff --git a/src/os/path_test.go b/src/os/path_test.go
index f58c7e7..9ab3f14 100644
--- a/src/os/path_test.go
+++ b/src/os/path_test.go
@@ -230,7 +230,7 @@
func TestMkdirAllAtSlash(t *testing.T) {
switch runtime.GOOS {
- case "android", "plan9", "windows":
+ case "android", "fuchsia", "plan9", "windows":
t.Skipf("skipping on %s", runtime.GOOS)
case "darwin":
switch runtime.GOARCH {
diff --git a/src/os/path_unix.go b/src/os/path_unix.go
index b2e0bca..9d81f61 100644
--- a/src/os/path_unix.go
+++ b/src/os/path_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia js,wasm linux nacl netbsd openbsd solaris
package os
diff --git a/src/os/pipe_test.go b/src/os/pipe_test.go
index 59d31e5..ec81d8f 100644
--- a/src/os/pipe_test.go
+++ b/src/os/pipe_test.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// Test broken pipes on Unix systems.
-// +build !windows,!plan9,!nacl,!js
+// +build !windows,!plan9,!nacl,!js,!fuchsia
package os_test
@@ -397,6 +397,10 @@
}
func TestFdReadRace(t *testing.T) {
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("deadlines are TODO on fuchsia")
+ }
+
t.Parallel()
r, w, err := os.Pipe()
diff --git a/src/os/signal/signal_fuchsia.go b/src/os/signal/signal_fuchsia.go
new file mode 100644
index 0000000..c27eba3
--- /dev/null
+++ b/src/os/signal/signal_fuchsia.go
@@ -0,0 +1,25 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package signal
+
+import "os"
+
+const numSig = 65
+
+func signum(sig os.Signal) int {
+ panic("TODO")
+}
+
+func enableSignal(sig int) {
+ panic("TODO")
+}
+
+func disableSignal(sig int) {
+ panic("TODO")
+}
+
+func ignoreSignal(sig int) {
+ panic("TODO")
+}
diff --git a/src/os/stat_unix.go b/src/os/stat_unix.go
index 856b499..85af8d7 100644
--- a/src/os/stat_unix.go
+++ b/src/os/stat_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia js,wasm linux nacl netbsd openbsd solaris
package os
diff --git a/src/os/timeout_test.go b/src/os/timeout_test.go
index 1886acc..4ac191d 100644
--- a/src/os/timeout_test.go
+++ b/src/os/timeout_test.go
@@ -62,6 +62,10 @@
}
func TestReadTimeout(t *testing.T) {
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("deadlines are TODO on fuchsia")
+ }
+
t.Parallel()
r, w, err := os.Pipe()
@@ -102,6 +106,9 @@
}
func TestReadTimeoutMustNotReturn(t *testing.T) {
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("file read timeouts are TODO on fuchsia")
+ }
t.Parallel()
r, w, err := os.Pipe()
@@ -153,6 +160,10 @@
}
func TestWriteTimeout(t *testing.T) {
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("deadlines are TODO on fuchsia")
+ }
+
t.Parallel()
for i, tt := range writeTimeoutTests {
@@ -190,6 +201,10 @@
}
func TestWriteTimeoutMustNotReturn(t *testing.T) {
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("deadlines are TODO on fuchsia")
+ }
+
t.Parallel()
r, w, err := os.Pipe()
@@ -256,6 +271,10 @@
}
func TestReadTimeoutFluctuation(t *testing.T) {
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("deadlines are TODO on fuchsia")
+ }
+
t.Parallel()
r, w, err := os.Pipe()
@@ -307,6 +326,10 @@
}
func TestWriteTimeoutFluctuation(t *testing.T) {
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("deadlines are TODO on fuchsia")
+ }
+
t.Parallel()
r, w, err := os.Pipe()
@@ -365,6 +388,10 @@
}
func testVariousDeadlines(t *testing.T) {
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("deadlines are TODO on fuchsia")
+ }
+
type result struct {
n int64
err error
@@ -458,6 +485,10 @@
}
func TestReadWriteDeadlineRace(t *testing.T) {
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("deadlines are TODO on fuchsia")
+ }
+
t.Parallel()
N := 1000
@@ -514,6 +545,10 @@
// TestRacyRead tests that it is safe to mutate the input Read buffer
// immediately after cancelation has occurred.
func TestRacyRead(t *testing.T) {
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("deadlines are TODO on fuchsia")
+ }
+
t.Parallel()
r, w, err := os.Pipe()
@@ -553,6 +588,10 @@
// TestRacyWrite tests that it is safe to mutate the input Write buffer
// immediately after cancelation has occurred.
func TestRacyWrite(t *testing.T) {
+ if runtime.GOOS == "fuchsia" {
+ t.Skip("deadlines are TODO on fuchsia")
+ }
+
t.Parallel()
r, w, err := os.Pipe()
diff --git a/src/os/user/lookup_fuchsia.go b/src/os/user/lookup_fuchsia.go
new file mode 100644
index 0000000..80fa82c
--- /dev/null
+++ b/src/os/user/lookup_fuchsia.go
@@ -0,0 +1,38 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package user
+
+import "errors"
+
+func init() {
+ userImplemented = false
+ groupImplemented = false
+}
+
+func current() (*User, error) {
+ return nil, errors.New("user: Current not implemented on fuchsia")
+}
+
+func lookupUser(string) (*User, error) {
+ return nil, errors.New("user: Lookup not implemented on fuchsia")
+}
+
+func lookupUserId(string) (*User, error) {
+ return nil, errors.New("user: LookupId not implemented on fuchsia")
+}
+
+func lookupGroup(string) (*Group, error) {
+ return nil, errors.New("user: LookupGroup not implemented on fuchsia")
+}
+
+func lookupGroupId(string) (*Group, error) {
+ return nil, errors.New("user: LookupGroupId not implemented on fuchsia")
+}
+
+func listGroups(*User) ([]string, error) {
+ return nil, errors.New("user: GroupIds not implemented on fuchsia")
+}
diff --git a/src/os/user/lookup_stubs.go b/src/os/user/lookup_stubs.go
index f7d138f..71638de 100644
--- a/src/os/user/lookup_stubs.go
+++ b/src/os/user/lookup_stubs.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !cgo,!windows,!plan9 android osusergo,!windows,!plan9
+// +build !cgo,!windows,!plan9 android osusergo,!windows,!plan9,!fuchsia
package user
diff --git a/src/path/filepath/path_unix.go b/src/path/filepath/path_unix.go
index 349dea7..66644d8 100644
--- a/src/path/filepath/path_unix.go
+++ b/src/path/filepath/path_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia js,wasm linux nacl netbsd openbsd solaris
package filepath
diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s
index 6902ce2..97d2a4e 100644
--- a/src/runtime/asm_amd64.s
+++ b/src/runtime/asm_amd64.s
@@ -161,8 +161,8 @@
JMP ok
#endif
- LEAQ runtime·m0+m_tls(SB), DI
- CALL runtime·settls(SB)
+ LEAQ runtime·m0+m_tls(SB), DI
+ CALL runtime·settls(SB)
// store through it, to make sure it works
get_tls(BX)
diff --git a/src/runtime/cgo/cgo.go b/src/runtime/cgo/cgo.go
index 241a821..bd1cd0e 100644
--- a/src/runtime/cgo/cgo.go
+++ b/src/runtime/cgo/cgo.go
@@ -16,6 +16,7 @@
#cgo darwin,arm64 LDFLAGS: -framework CoreFoundation
#cgo dragonfly LDFLAGS: -lpthread
#cgo freebsd LDFLAGS: -lpthread
+#cgo fuchsia LDFLAGS: -lpthread -lfdio
#cgo android LDFLAGS: -llog
#cgo !android,linux LDFLAGS: -lpthread
#cgo netbsd LDFLAGS: -lpthread
diff --git a/src/runtime/cgo/fdio.go b/src/runtime/cgo/fdio.go
new file mode 100644
index 0000000..d843125
--- /dev/null
+++ b/src/runtime/cgo/fdio.go
@@ -0,0 +1,15 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package cgo
+
+import _ "unsafe" // for go:linkname
+
+//go:cgo_import_static x_cgo_get_initial_handles
+//go:linkname x_cgo_get_initial_handles x_cgo_get_initial_handles
+//go:linkname _cgo_get_initial_handles runtime._cgo_get_initial_handles
+var x_cgo_get_initial_handles byte
+var _cgo_get_initial_handles = &x_cgo_get_initial_handles
diff --git a/src/runtime/cgo/gcc_fatalf.c b/src/runtime/cgo/gcc_fatalf.c
index fdcf6f5..1f416b5 100644
--- a/src/runtime/cgo/gcc_fatalf.c
+++ b/src/runtime/cgo/gcc_fatalf.c
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !android,linux freebsd
+// +build !android,linux freebsd fuchsia
#include <stdarg.h>
#include <stdio.h>
diff --git a/src/runtime/cgo/gcc_fdio.c b/src/runtime/cgo/gcc_fdio.c
new file mode 100644
index 0000000..db21dcb
--- /dev/null
+++ b/src/runtime/cgo/gcc_fdio.c
@@ -0,0 +1,81 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build cgo
+// +build fuchsia
+
+#include "libcgo.h"
+
+#include <stdlib.h>
+#include <zircon/process.h>
+#include <zircon/processargs.h>
+#include <lib/fdio/io.h>
+#include <lib/fdio/namespace.h>
+#include <lib/fdio/util.h>
+
+extern char **environ;
+
+// fdio_init matches a Go struct of the same name in os_fuchsia.go.
+struct fdio_init {
+ zx_handle_t stdioClones[3 * FDIO_MAX_HANDLES];
+ uint32_t stdioCloneNumHandles[3];
+ uint32_t stdioCloneTypes[3];
+ zx_handle_t processSelf;
+ zx_handle_t vmarRootSelf;
+ int32_t unused;
+ int32_t envlen;
+ char** environ;
+ int32_t unused2;
+ int32_t rootNSNumHandles;
+ zx_handle_t *rootNSHandles;
+ char** rootNSPaths;
+};
+
+void
+x_cgo_get_initial_handles(struct fdio_init *handles)
+{
+ // When running with cgo support, there are two FDIO libraries in the
+ // same process. We let the C FDIO start first, then clone its root
+ // and use that for Go.
+ // TODO: there is some small amount of fdio library state we
+ // have to share between Go and C, in particular, cwd.
+ // Work out how.
+
+ // fdio may have initialized std{in,out,err} with a single fd if the FDIO_FLAG_USE_FOR_STDIO
+ // flag was set, or have separate in/out/err fds. We clone fds {0,1,2} to separate fds for use
+ // in the Go runtime. The cloned fds aren't installed into fdio's fd table so they are only
+ // usable from Go's table.
+ zx_status_t r;
+ for (int i = 0; i < 3; ++i) {
+ uint32_t handle_types[FDIO_MAX_HANDLES];
+ r = fdio_clone_fd(i, 0, &handles->stdioClones[i * FDIO_MAX_HANDLES], handle_types);
+ if (r <= 0) {
+ printf("runtime/cgo: fdio_clone_fd of stdio[%d] failed: %d\n", i, r);
+ handles->stdioCloneNumHandles[i] = 0;
+ } else {
+ handles->stdioCloneNumHandles[i] = r;
+ handles->stdioCloneTypes[i] = PA_HND_TYPE(handle_types[0]);
+ }
+ }
+
+ handles->processSelf = zx_process_self();
+ handles->vmarRootSelf = zx_vmar_root_self();
+
+ for (char** env = environ; *env; env++) {
+ handles->envlen++;
+ }
+ handles->environ = environ;
+
+ fdio_flat_namespace_t* rootNS;
+ r = fdio_ns_export_root(&rootNS);
+ if (r < 0) {
+ handles->rootNSNumHandles = 0;
+ handles->rootNSHandles = NULL;
+ handles->rootNSPaths = NULL;
+ } else {
+ handles->rootNSNumHandles = (int32_t)rootNS->count;
+ handles->rootNSHandles = rootNS->handle;
+ handles->rootNSPaths = (char**)rootNS->path;
+ }
+}
diff --git a/src/runtime/cgo/gcc_fuchsia_amd64.c b/src/runtime/cgo/gcc_fuchsia_amd64.c
new file mode 100644
index 0000000..ae65662
--- /dev/null
+++ b/src/runtime/cgo/gcc_fuchsia_amd64.c
@@ -0,0 +1,52 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <pthread.h>
+#include <errno.h>
+#include <string.h> // strerror
+#include <signal.h>
+#include <stdlib.h>
+#include "libcgo.h"
+
+static void* threadentry(void*);
+static void (*setg_gcc)(void*);
+
+void
+x_cgo_init(G* g, void (*setg)(void*))
+{
+ setg_gcc = setg;
+}
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ // TODO: switch to threads.h.
+ pthread_attr_t attr;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ // leave stacklo=0 and set stackhi=size; mstack will do the rest.
+ ts->g->stackhi = size;
+ err = pthread_create(&p, &attr, threadentry, ts);
+
+ if (err != 0) {
+ fatalf("pthread_create failed: %s", strerror(err));
+ }
+}
+
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+ setg_gcc((void*)ts.g);
+
+ crosscall_amd64(ts.fn);
+ return 0;
+}
diff --git a/src/runtime/cgo/gcc_fuchsia_arm64.c b/src/runtime/cgo/gcc_fuchsia_arm64.c
new file mode 100644
index 0000000..e79d192
--- /dev/null
+++ b/src/runtime/cgo/gcc_fuchsia_arm64.c
@@ -0,0 +1,53 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <pthread.h>
+#include <errno.h>
+#include <string.h> // strerror
+#include <signal.h>
+#include <stdlib.h>
+#include "libcgo.h"
+
+#include <stdio.h>
+
+static void* threadentry(void*);
+static void (*setg_gcc)(void*);
+
+void
+x_cgo_init(G* g, void (*setg)(void*))
+{
+ setg_gcc = setg;
+}
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ // leave stacklo=0 and set stackhi=size; mstack will do the rest.
+ ts->g->stackhi = size;
+ err = pthread_create(&p, &attr, threadentry, ts);
+
+ if (err != 0) {
+ fatalf("pthread_create failed: %s", strerror(err));
+ }
+}
+
+extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ crosscall1(ts.fn, setg_gcc, (void*)ts.g);
+ return 0;
+}
diff --git a/src/runtime/cgo/gcc_libinit.c b/src/runtime/cgo/gcc_libinit.c
index 3dc5bde..5a6d8fa 100644
--- a/src/runtime/cgo/gcc_libinit.c
+++ b/src/runtime/cgo/gcc_libinit.c
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// +build cgo
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia linux netbsd openbsd solaris
#include <pthread.h>
#include <errno.h>
diff --git a/src/runtime/cgo/gcc_setenv.c b/src/runtime/cgo/gcc_setenv.c
index ed5d203..2f2581d 100644
--- a/src/runtime/cgo/gcc_setenv.c
+++ b/src/runtime/cgo/gcc_setenv.c
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// +build cgo
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia linux netbsd openbsd solaris
#include "libcgo.h"
diff --git a/src/runtime/cgo/setenv.go b/src/runtime/cgo/setenv.go
index fab4339..7fe251a 100644
--- a/src/runtime/cgo/setenv.go
+++ b/src/runtime/cgo/setenv.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia linux netbsd openbsd solaris
package cgo
diff --git a/src/runtime/env_posix.go b/src/runtime/env_posix.go
index 032e712..afd5fce 100644
--- a/src/runtime/env_posix.go
+++ b/src/runtime/env_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd fuchsia js,wasm linux nacl netbsd openbsd solaris windows
package runtime
diff --git a/src/runtime/internal/sys/zgoos_android.go b/src/runtime/internal/sys/zgoos_android.go
index bfdc377..de8cdee 100644
--- a/src/runtime/internal/sys/zgoos_android.go
+++ b/src/runtime/internal/sys/zgoos_android.go
@@ -12,6 +12,7 @@
const GoosFreebsd = 0
const GoosJs = 0
const GoosLinux = 0
+const GoosFuchsia = 0
const GoosNacl = 0
const GoosNetbsd = 0
const GoosOpenbsd = 0
diff --git a/src/runtime/internal/sys/zgoos_darwin.go b/src/runtime/internal/sys/zgoos_darwin.go
index 1c4667f..f569e9d 100644
--- a/src/runtime/internal/sys/zgoos_darwin.go
+++ b/src/runtime/internal/sys/zgoos_darwin.go
@@ -12,6 +12,7 @@
const GoosFreebsd = 0
const GoosJs = 0
const GoosLinux = 0
+const GoosFuchsia = 0
const GoosNacl = 0
const GoosNetbsd = 0
const GoosOpenbsd = 0
diff --git a/src/runtime/internal/sys/zgoos_dragonfly.go b/src/runtime/internal/sys/zgoos_dragonfly.go
index 728bf6a..40988a4 100644
--- a/src/runtime/internal/sys/zgoos_dragonfly.go
+++ b/src/runtime/internal/sys/zgoos_dragonfly.go
@@ -12,6 +12,7 @@
const GoosFreebsd = 0
const GoosJs = 0
const GoosLinux = 0
+const GoosFuchsia = 0
const GoosNacl = 0
const GoosNetbsd = 0
const GoosOpenbsd = 0
diff --git a/src/runtime/internal/sys/zgoos_freebsd.go b/src/runtime/internal/sys/zgoos_freebsd.go
index a8d6591..4a2120d 100644
--- a/src/runtime/internal/sys/zgoos_freebsd.go
+++ b/src/runtime/internal/sys/zgoos_freebsd.go
@@ -12,6 +12,7 @@
const GoosFreebsd = 1
const GoosJs = 0
const GoosLinux = 0
+const GoosFuchsia = 0
const GoosNacl = 0
const GoosNetbsd = 0
const GoosOpenbsd = 0
diff --git a/src/runtime/internal/sys/zgoos_fuchsia.go b/src/runtime/internal/sys/zgoos_fuchsia.go
new file mode 100644
index 0000000..22de240
--- /dev/null
+++ b/src/runtime/internal/sys/zgoos_fuchsia.go
@@ -0,0 +1,18 @@
+// generated by gengoos.go using 'go generate'
+
+package sys
+
+const GOOS = `fuchsia`
+
+const GoosAndroid = 0
+const GoosDarwin = 0
+const GoosDragonfly = 0
+const GoosFreebsd = 0
+const GoosLinux = 0
+const GoosFuchsia = 1
+const GoosNacl = 0
+const GoosNetbsd = 0
+const GoosOpenbsd = 0
+const GoosPlan9 = 0
+const GoosSolaris = 0
+const GoosWindows = 0
diff --git a/src/runtime/internal/sys/zgoos_linux.go b/src/runtime/internal/sys/zgoos_linux.go
index 289400c..f9a4922 100644
--- a/src/runtime/internal/sys/zgoos_linux.go
+++ b/src/runtime/internal/sys/zgoos_linux.go
@@ -13,6 +13,7 @@
const GoosFreebsd = 0
const GoosJs = 0
const GoosLinux = 1
+const GoosFuchsia = 0
const GoosNacl = 0
const GoosNetbsd = 0
const GoosOpenbsd = 0
diff --git a/src/runtime/internal/sys/zgoos_nacl.go b/src/runtime/internal/sys/zgoos_nacl.go
index 3fedb0a..b3c2c01 100644
--- a/src/runtime/internal/sys/zgoos_nacl.go
+++ b/src/runtime/internal/sys/zgoos_nacl.go
@@ -12,6 +12,7 @@
const GoosFreebsd = 0
const GoosJs = 0
const GoosLinux = 0
+const GoosFuchsia = 0
const GoosNacl = 1
const GoosNetbsd = 0
const GoosOpenbsd = 0
diff --git a/src/runtime/internal/sys/zgoos_netbsd.go b/src/runtime/internal/sys/zgoos_netbsd.go
index 3346e37..83f33b3 100644
--- a/src/runtime/internal/sys/zgoos_netbsd.go
+++ b/src/runtime/internal/sys/zgoos_netbsd.go
@@ -12,6 +12,7 @@
const GoosFreebsd = 0
const GoosJs = 0
const GoosLinux = 0
+const GoosFuchsia = 0
const GoosNacl = 0
const GoosNetbsd = 1
const GoosOpenbsd = 0
diff --git a/src/runtime/internal/sys/zgoos_openbsd.go b/src/runtime/internal/sys/zgoos_openbsd.go
index 13c0323..114ea61 100644
--- a/src/runtime/internal/sys/zgoos_openbsd.go
+++ b/src/runtime/internal/sys/zgoos_openbsd.go
@@ -12,6 +12,7 @@
const GoosFreebsd = 0
const GoosJs = 0
const GoosLinux = 0
+const GoosFuchsia = 0
const GoosNacl = 0
const GoosNetbsd = 0
const GoosOpenbsd = 1
diff --git a/src/runtime/internal/sys/zgoos_plan9.go b/src/runtime/internal/sys/zgoos_plan9.go
index 6b2e977..53282e9 100644
--- a/src/runtime/internal/sys/zgoos_plan9.go
+++ b/src/runtime/internal/sys/zgoos_plan9.go
@@ -12,6 +12,7 @@
const GoosFreebsd = 0
const GoosJs = 0
const GoosLinux = 0
+const GoosFuchsia = 0
const GoosNacl = 0
const GoosNetbsd = 0
const GoosOpenbsd = 0
diff --git a/src/runtime/internal/sys/zgoos_solaris.go b/src/runtime/internal/sys/zgoos_solaris.go
index cbf70f0..dcadcc2 100644
--- a/src/runtime/internal/sys/zgoos_solaris.go
+++ b/src/runtime/internal/sys/zgoos_solaris.go
@@ -12,6 +12,7 @@
const GoosFreebsd = 0
const GoosJs = 0
const GoosLinux = 0
+const GoosFuchsia = 0
const GoosNacl = 0
const GoosNetbsd = 0
const GoosOpenbsd = 0
diff --git a/src/runtime/internal/sys/zgoos_windows.go b/src/runtime/internal/sys/zgoos_windows.go
index 70839ca..20fef09 100644
--- a/src/runtime/internal/sys/zgoos_windows.go
+++ b/src/runtime/internal/sys/zgoos_windows.go
@@ -12,6 +12,7 @@
const GoosFreebsd = 0
const GoosJs = 0
const GoosLinux = 0
+const GoosFuchsia = 0
const GoosNacl = 0
const GoosNetbsd = 0
const GoosOpenbsd = 0
diff --git a/src/runtime/lock_futex.go b/src/runtime/lock_futex.go
index b590c4b..129b1ef 100644
--- a/src/runtime/lock_futex.go
+++ b/src/runtime/lock_futex.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build dragonfly freebsd linux
+// +build dragonfly freebsd fuchsia linux
package runtime
diff --git a/src/runtime/mem_fuchsia.go b/src/runtime/mem_fuchsia.go
new file mode 100644
index 0000000..e74883a
--- /dev/null
+++ b/src/runtime/mem_fuchsia.go
@@ -0,0 +1,81 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+ "syscall/zx"
+ "unsafe"
+)
+
+//go:nosplit
+func sysAlloc(n uintptr, sysStat *uint64) unsafe.Pointer {
+ var p unsafe.Pointer
+ sysMmap(unsafe.Pointer(&p), n, zx.VMFlagPermRead|zx.VMFlagPermWrite)
+ if uintptr(p) < 4096 {
+ println("runtime: sysMmap failed n=", n)
+ exit(2)
+ }
+ mSysStatInc(sysStat, n)
+ return p
+}
+
+func sysUnused(v unsafe.Pointer, n uintptr) {
+ // TODO(dho): Implement this based on ZX_VMO_OP_DECOMMIT
+}
+
+func sysUsed(v unsafe.Pointer, n uintptr) {
+ // TODO(dho): Maybe implement this based on ZX_VMO_OP_COMMIT
+}
+
+//go:nosplit
+func sysFree(v unsafe.Pointer, n uintptr, sysStat *uint64) {
+ mSysStatDec(sysStat, n)
+ if status := zx.Sys_vmar_unmap(zx.Handle(zx.VMARRoot), zx.Vaddr(v), uint64(n)); status != zx.ErrOk {
+ println("runtime: zx.Sys_vmar_unmap failed: ", status.String())
+ }
+}
+
+func sysMmap(ptr unsafe.Pointer, sz uintptr, flags zx.VMFlag) {
+ var h zx.Handle
+ if status := zx.Sys_vmo_create(uint64(sz), 0, &h); status != zx.ErrOk {
+ println("runtime: zx.Sys_vmo_create failed: ", status.String())
+ exit(2)
+ }
+
+ prop := []byte("go-sys-mmap")
+ if status := zx.Sys_object_set_property(h, zx.PropName, unsafe.Pointer(&prop[0]), uint(len(prop))); status != zx.ErrOk {
+ println("runtime: zx.Sys_object_set_property failed: ", status.String())
+ exit(2)
+ }
+
+ if status := zx.Sys_vmar_map(zx.Handle(zx.VMARRoot), 0, h, 0, uint64(sz), uint32(flags), (*zx.Vaddr)(ptr)); status != zx.ErrOk {
+ println("runtime: zx.Sys_vmar_map failed: ", status.String())
+ exit(2)
+ }
+
+ if status := zx.Sys_handle_close(h); status != zx.ErrOk {
+ println("runtime: zx.Sys_handle_close failed: ", status.String())
+ exit(2)
+ }
+}
+
+func sysReserve(v unsafe.Pointer, n uintptr) unsafe.Pointer {
+ p := v
+ sysMmap(unsafe.Pointer(&p), n, 0)
+ return p
+}
+
+func sysFault(v unsafe.Pointer, n uintptr) {
+ println("TODO sysFault")
+}
+
+func sysMap(v unsafe.Pointer, n uintptr, sysStat *uint64) {
+ mSysStatInc(sysStat, n)
+
+ if status := zx.Sys_vmar_protect(zx.Handle(zx.VMARRoot), zx.Vaddr(v), uint64(n), uint32(zx.VMFlagPermRead|zx.VMFlagPermWrite)); status != zx.ErrOk {
+ println("runtime: zx.Sys_vmar_protect failed: ", status.String())
+ exit(2)
+ }
+}
diff --git a/src/runtime/netpoll_stub.go b/src/runtime/netpoll_stub.go
index a4d6b46..03bd97d 100644
--- a/src/runtime/netpoll_stub.go
+++ b/src/runtime/netpoll_stub.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build plan9
+// +build fuchsia plan9
package runtime
diff --git a/src/runtime/os_fuchsia.go b/src/runtime/os_fuchsia.go
new file mode 100644
index 0000000..7a33e81
--- /dev/null
+++ b/src/runtime/os_fuchsia.go
@@ -0,0 +1,317 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+ "syscall/zx"
+ "unsafe"
+)
+
+type mOS struct{}
+
+type sigset struct{}
+
+//go:nosplit
+func getRandomData(r []byte) {
+ zx.RandRead(r)
+}
+
+//go:nosplit
+func futexsleep(addr *uint32, val uint32, ns int64) {
+ deadline := zx.Sys_deadline_after(zx.Duration(ns))
+ if ns < 0 {
+ deadline = zx.Time(zx.TimensecInfinite)
+ }
+ zx.Sys_futex_wait((*int)(unsafe.Pointer(addr)), int32(val), deadline)
+}
+
+//go:nosplit
+func futexwakeup(addr *uint32, cnt uint32) {
+ zx.Sys_futex_wake((*int)(unsafe.Pointer(addr)), cnt)
+}
+
+//go:nosplit
+func osyield() {
+ zx.Sys_nanosleep(0)
+}
+
+// cgocallm0 calls a C function on the current stack.
+//
+// It is intended for use inside functions like osinit that run
+// before mstart directly on an OS thread stack.
+//
+// If in doubt, do not use.
+func cgocallm0(fn, arg unsafe.Pointer)
+
+func osinit() {
+ if _cgo_get_initial_handles != nil {
+ cgocallm0(_cgo_get_initial_handles, unsafe.Pointer(&fdioHandles))
+ for i := 0; i < 3; i = i + 1 {
+ for j := 0; j < int(fdioHandles.stdioCloneNumHandles[i]); j = j + 1 {
+ zx.StdioHandles[i][j] = fdioHandles.stdioClones[i*3+j]
+ }
+ zx.StdioHandleTypes[i] = int(fdioHandles.stdioCloneTypes[i])
+ }
+ zx.ProcHandle = zx.Handle(fdioHandles.processSelf)
+ zx.VMARRoot = zx.VMAR(fdioHandles.vmarRootSelf)
+ } else {
+ // TODO: implement cgo-less init
+ println("runtime: no fuchsia process handle without cgo yet")
+ exit(2)
+ }
+
+ ncpu = int32(zx.Sys_system_get_num_cpus())
+ physPageSize = 4096
+}
+
+func parseRootNS() {
+ if fdioHandles.rootNSNumHandles > 0 {
+ const maxHandleCount = 1 << 20 // arbitrary
+ paths := (*(*[maxHandleCount]*byte)(unsafe.Pointer(fdioHandles.rootNSPaths)))[:fdioHandles.rootNSNumHandles]
+ handles := (*(*[maxHandleCount]zx.Handle)(unsafe.Pointer(fdioHandles.rootNSHandles)))[:fdioHandles.rootNSNumHandles]
+ zx.RootNSMap = make(map[string]zx.Handle)
+ for i, p := range paths {
+ zx.RootNSMap[gostring(p)] = handles[i]
+ }
+ }
+}
+
+// Filled in by runtime/cgo when linked into binary.
+var _cgo_get_initial_handles unsafe.Pointer // pointer to C function
+
+func minit() {
+}
+
+//go:nosplit
+func unminit() {
+ // TODO
+}
+
+func sigpanic() {
+ // TODO
+}
+
+func mpreinit(mp *m) {
+ // TODO
+}
+
+//go:nosplit
+func msigsave(mp *m) {
+ // TODO
+}
+
+//go:nosplit
+func msigrestore(sigmask sigset) {
+ // TODO
+}
+
+func initsig(preinit bool) {
+ // TODO
+}
+
+//go:nosplit
+func sigblock() {
+ // TODO
+}
+
+func sigenable(sig uint32) {
+ // TODO
+}
+
+func sigdisable(sig uint32) {
+ // TODO
+}
+
+func sigignore(sig uint32) {
+ // TODO
+}
+
+func crash() {
+ *(*int32)(nil) = 0
+}
+
+func threadinit(mp *m)
+
+var gothreadname = []byte("gothread")
+
+//go:nowritebarrier
+func newosproc(mp *m) {
+ stk := unsafe.Pointer(mp.g0.stack.hi)
+ p := zx.Handle(0) // TODO: only works due to temporary hack in zircon
+ var h zx.Handle
+ status := zx.Sys_thread_create(p, &gothreadname[0], uint(len(gothreadname)), 0, &h)
+ if status < 0 {
+ println("runtime: newosproc zx.Sys_thread_create failed:", h)
+ exit(2)
+ }
+
+ status = zx.Sys_thread_start(h, zx.Vaddr(funcPC(threadinit)), zx.Vaddr(stk), uintptr(unsafe.Pointer(mp)), 0)
+ if status < 0 {
+ println("runtime: newosproc zx.Sys_thread_start failed:", h)
+ exit(2)
+ }
+}
+
+type zx_proc_args struct {
+ protocol uint32
+ version uint32
+ handle_info_off uint32
+ args_off uint32
+ args_num uint32
+}
+
+type zx_proc_info struct {
+ magic uint32
+ version uint32
+ next_tls_slot uint32
+ proc_args *zx_proc_args
+ handle *zx.Handle
+ handle_info *uint32
+ handle_count int32
+ argv **byte
+ argc int32
+}
+
+type zx_tls_root struct {
+ self *zx_tls_root
+ proc *zx_proc_info
+ magic uint32
+ flags uint16
+ maxslots uint16
+ slots [8]uintptr // has length maxslots
+}
+
+func resetcpuprofiler(hz int32) {
+ // TODO
+}
+
+// fdio_init matches a Go struct of the same name in gcc_fdio.c.
+type fdio_init struct {
+ stdioClones [9]zx.Handle // 3 * fdio.MaxHandles
+ stdioCloneNumHandles [3]uint32
+ stdioCloneTypes [3]uint32
+ processSelf zx.Handle
+ vmarRootSelf zx.Handle
+ _ int32
+ envlen int32
+ environ **byte
+ _ int32
+ rootNSNumHandles int32
+ rootNSHandles *zx.Handle
+ rootNSPaths **byte
+}
+
+var fdioHandles fdio_init
+
+func goenvs() {
+ if _cgo_get_initial_handles != nil {
+ const maxEnvSize = 1 << 20 // arbitrary
+ envp := (*(*[maxEnvSize]*byte)(unsafe.Pointer(fdioHandles.environ)))[:fdioHandles.envlen]
+ envs = make([]string, len(envp))
+ for i, e := range envp {
+ envs[i] = gostring(e)
+ }
+ // TODO: find a better place to call this
+ parseRootNS()
+ } else {
+ // TODO: implement cgo-less init
+ println("runtime: no fuchsia process handle without cgo yet")
+ exit(2)
+ }
+}
+
+const _NSIG = 65 // TODO
+
+//go:nosplit
+func nanotime() int64 {
+ const ZX_CLOCK_MONOTONIC = 0
+ return int64(zx.Sys_clock_get(ZX_CLOCK_MONOTONIC))
+}
+
+//go:linkname time_now time.now
+//go:nosplit
+func time_now() (sec int64, nsec int32, mono int64) {
+ const ZX_CLOCK_UTC = 1
+ x := int64(zx.Sys_clock_get(ZX_CLOCK_UTC))
+ return int64(x / 1e9), int32(x % 1e9), nanotime() - startNano
+}
+
+func unixnanotime() int64 {
+ return nanotime()
+}
+
+var logger zx.Handle
+var logBufferArray [1024]byte
+var logBufferN int
+
+//go:nosplit
+func write(fd uintptr, buf unsafe.Pointer, n int32) int32 {
+ if fd == 1 || fd == 2 {
+ // This initialization mechanism is not thread-safe, but if the only calls to 'write' with
+ // these file descriptors come from print, they will already be serialized by a lock in
+ // print's implementation.
+ if logger <= 0 {
+ zx.Sys_debuglog_create(0, 0, &logger)
+ logBufferN = 0
+ }
+ if logger > 0 {
+ // Sys_log_write adds a newline to output buffers. To prevent fragmented logs, we buffer
+ // output until a newline character is encountered.
+ logBufferN += copy(logBufferArray[logBufferN:], (*[1 << 30]byte)(buf)[:n])
+ if logBufferArray[logBufferN-1] == '\n' {
+ status := zx.Sys_log_write(logger, uint32(logBufferN), unsafe.Pointer(&logBufferArray[0]), 0)
+ // Flush buffer, regardless of status returned from write
+ logBufferN = 0
+ if status < 0 {
+ return int32(status)
+ }
+ }
+ }
+ }
+ // TODO
+ return n
+}
+
+//go:nosplit
+func exit(code int32) {
+ zx.Sys_process_exit(int64(code))
+}
+
+//go:nosplit
+func usleep(usec uint32) {
+ zx.Sys_nanosleep(zx.Sys_deadline_after(zx.Duration(usec * 1000)))
+}
+
+func signame(sig uint32) string {
+ return "unknown_sig" // TODO
+}
+
+// zircon_mktls
+//go:nosplit
+func zircon_mktls() {
+ // TODO
+}
+
+//go:nosplit
+func zircon_settls(val uintptr) {
+ // TODO: should call zx_set_object_property with property ZX_PROP_REGISTER_FS in amd64 or
+ // ZX_PROP_REGISTER_CP15 on arm.
+}
+
+//go:linkname os_sigpipe os.sigpipe
+func os_sigpipe() {
+ // TODO
+}
+
+// gsignalStack is unused on fuchsia
+type gsignalStack struct{}
+
+func exitThread(wait *uint32) {}
+func setProcessCPUProfiler(hz int32) {}
+func setThreadCPUProfiler(hz int32) {}
+
+//go:nosplit
+//go:nowritebarrierrec
+func clearSignalHandlers() {}
diff --git a/src/runtime/os_fuchsia_arm64.go b/src/runtime/os_fuchsia_arm64.go
new file mode 100644
index 0000000..143fe39
--- /dev/null
+++ b/src/runtime/os_fuchsia_arm64.go
@@ -0,0 +1,12 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import "syscall/zx"
+
+//go:nosplit
+func cputicks() int64 {
+ return int64(zx.Sys_ticks_get())
+}
diff --git a/src/runtime/rt0_fuchsia_amd64.s b/src/runtime/rt0_fuchsia_amd64.s
new file mode 100644
index 0000000..40c92a3
--- /dev/null
+++ b/src/runtime/rt0_fuchsia_amd64.s
@@ -0,0 +1,8 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+TEXT _rt0_amd64_fuchsia(SB),NOSPLIT,$-8
+ JMP _rt0_amd64(SB)
diff --git a/src/runtime/rt0_fuchsia_arm64.s b/src/runtime/rt0_fuchsia_arm64.s
new file mode 100644
index 0000000..f28e28d
--- /dev/null
+++ b/src/runtime/rt0_fuchsia_arm64.s
@@ -0,0 +1,14 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+TEXT _rt0_arm64_fuchsia(SB),NOSPLIT,$-8
+ MOVD 0(RSP), R0 // argc
+ ADD $8, RSP, R1 // argv
+ BL main(SB)
+
+TEXT main(SB),NOSPLIT,$-8
+ MOVD $runtime·rt0_go(SB), R2
+ BL R2
diff --git a/src/runtime/stubs2.go b/src/runtime/stubs2.go
index 02249d0..d91b8c4 100644
--- a/src/runtime/stubs2.go
+++ b/src/runtime/stubs2.go
@@ -8,6 +8,7 @@
// +build !nacl
// +build !js
// +build !darwin
+// +build !fuchsia
package runtime
diff --git a/src/runtime/stubs3.go b/src/runtime/stubs3.go
index 5c0786e..777fce2 100644
--- a/src/runtime/stubs3.go
+++ b/src/runtime/stubs3.go
@@ -8,6 +8,7 @@
// +build !nacl
// +build !freebsd
// +build !darwin
+// +build !fuchsia
package runtime
diff --git a/src/runtime/sys_manual_fuchsia_amd64.s b/src/runtime/sys_manual_fuchsia_amd64.s
new file mode 100644
index 0000000..81e9c90
--- /dev/null
+++ b/src/runtime/sys_manual_fuchsia_amd64.s
@@ -0,0 +1,71 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go_asm.h"
+#include "go_tls.h"
+#include "textflag.h"
+
+TEXT runtime·threadinit(SB),NOSPLIT,$0
+ MOVQ DI, R8
+
+ MOVQ m_g0(R8), DX // g
+ MOVQ R8, g_m(DX)
+
+ // Layout new m scheduler stack on os stack.
+ // TODO: which os stack? do we need to make a new vmo?
+ LEAQ (-8*1024+104)(SP), BX
+ MOVQ BX, g_stackguard0(DX)
+ MOVQ BX, g_stackguard1(DX)
+ MOVQ BX, (g_stack+stack_lo)(DX)
+ MOVQ SP, (g_stack+stack_hi)(DX)
+
+ PUSHQ R8
+
+ // Set up tls.
+ LEAQ m_tls(R8), DI
+ CALL runtime·settls(SB)
+
+ get_tls(CX)
+
+ POPQ R8
+ MOVQ m_g0(R8), DX
+ MOVQ DX, g(CX)
+
+ CLD // convention is D is always left cleared
+ CALL runtime·stackcheck(SB) // clobbers AX,CX
+ CALL runtime·mstart(SB)
+ // TODO CALL syscall/zx·Sys_zircon_thread_exit(SB)
+ RET
+
+// set tls base to DI
+// Note that this code is only used when CGO_ENABLED=0.
+// Not using syscall/zx so we can avoid setting up a G.
+//
+// TODO: make VSDO call directly here, avoid the syscall.
+TEXT runtime·settls(SB),NOSPLIT,$8
+ ADDQ $8, DI // ELF wants to use -8(FS)
+ PUSHQ DI
+ LEAQ 0(SP), DX // prctl on zircon takes a pointer, not the value
+ MOVQ $0, DI
+ MOVQ $0, SI
+ MOVQ $0xff00ff00000035, AX // ZIRCON_SYSCALL_MAGIC | thread_arch_prctl (53)
+ SYSCALL
+ CMPQ AX, $0xfffffffffffff001
+ JLS 2(PC)
+ MOVL $0xf1, 0xf1 // crash
+ POPQ DI
+ RET
+
+TEXT ·cgocallm0(SB),NOSPLIT,$0-20
+ MOVQ fn+0(FP), AX
+ MOVQ arg+8(FP), DI
+
+ MOVQ SP, BP // BP is callee-save in the x86-64 ABI
+
+ ANDQ $~15, SP
+ CALL AX
+
+ MOVQ BP, SP
+ get_tls(CX)
+ RET
diff --git a/src/runtime/sys_manual_fuchsia_arm64.s b/src/runtime/sys_manual_fuchsia_arm64.s
new file mode 100644
index 0000000..36b8107
--- /dev/null
+++ b/src/runtime/sys_manual_fuchsia_arm64.s
@@ -0,0 +1,42 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go_asm.h"
+#include "funcdata.h"
+#include "textflag.h"
+
+TEXT runtime·threadinit(SB),NOSPLIT,$0
+ // Layout new m scheduler stack on os stack.
+ // TODO: which os stack? do we need to make a new vmo?
+
+ MOVD m_g0(R0), g
+ MOVD R0, g_m(g)
+
+ MOVD RSP, R7
+ MOVD $(-64*1024)(R7), R0
+ MOVD R0, g_stackguard0(g)
+ MOVD R0, g_stackguard1(g)
+ MOVD R0, (g_stack+stack_lo)(g)
+ MOVD R7, (g_stack+stack_hi)(g)
+
+ BL runtime·mstart(SB)
+ MOVD $0, R0
+ MOVD R0, (R0) // boom
+ UNDEF
+
+TEXT ·cgocallm0(SB),NOSPLIT,$0-20
+ MOVD fn+0(FP), R1
+ MOVD arg+8(FP), R0
+
+ MOVD RSP, R19 // R19 is callee-save by C
+ MOVD g, R21 // R21 is callee-save by C
+ MOVD RSP, R7
+ ADD $-32, R7, R7
+ AND $~15, R7
+ MOVD R7, RSP // align stack for C
+ BL R1
+
+ MOVD R19, RSP // restore SP
+ MOVD R21, g // restore g
+ RET
diff --git a/src/runtime/timestub.go b/src/runtime/timestub.go
index f9230da..2c73258 100644
--- a/src/runtime/timestub.go
+++ b/src/runtime/timestub.go
@@ -6,6 +6,7 @@
// indirectly, in terms of walltime and nanotime assembly.
// +build !windows
+// +build !fuchsia
package runtime
diff --git a/src/runtime/tls_arm64.h b/src/runtime/tls_arm64.h
index c29fa7f..c2480d7 100644
--- a/src/runtime/tls_arm64.h
+++ b/src/runtime/tls_arm64.h
@@ -9,6 +9,9 @@
#ifdef GOOS_linux
#define TLS_linux
#endif
+#ifdef GOOS_fuchsia
+#define TLS_linux
+#endif
#ifdef TLS_linux
#define TPIDR TPIDR_EL0
#define MRS_TPIDR_R0 WORD $0xd53bd040 // MRS TPIDR_EL0, R0
diff --git a/src/syscall/dirent.go b/src/syscall/dirent.go
index 26cbbbc..a85c818 100644
--- a/src/syscall/dirent.go
+++ b/src/syscall/dirent.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia js,wasm linux nacl netbsd openbsd solaris
package syscall
diff --git a/src/syscall/env_unix.go b/src/syscall/env_unix.go
index 1ebc0b1..f4e1f65 100644
--- a/src/syscall/env_unix.go
+++ b/src/syscall/env_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia js,wasm linux nacl netbsd openbsd solaris
// Unix environment variables.
diff --git a/src/syscall/exec_fuchsia.go b/src/syscall/exec_fuchsia.go
new file mode 100644
index 0000000..3904808
--- /dev/null
+++ b/src/syscall/exec_fuchsia.go
@@ -0,0 +1,10 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import ()
+
+type SysProcAttr struct {
+}
diff --git a/src/syscall/syscall_fuchsia.go b/src/syscall/syscall_fuchsia.go
new file mode 100644
index 0000000..68c138b
--- /dev/null
+++ b/src/syscall/syscall_fuchsia.go
@@ -0,0 +1,686 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import (
+ "errors"
+ "io"
+ "path"
+ "strings"
+ "sync"
+ "unsafe"
+
+ "syscall/zx"
+ "syscall/zx/fdio"
+ "syscall/zx/fidl"
+ fidlIo "syscall/zx/io"
+)
+
+var (
+ Stdin = 0
+ Stdout = 1
+ Stderr = 2
+)
+
+const (
+ FsRightReadable = 0x00000001
+ FsRightWritable = 0x00000002
+ FsRightAdmin = 0x00000004
+ FsRightRight = 0x0000FFFF
+ FsFlagCreate = 0x00010000
+ FsFlagExclusive = 0x00020000
+ FsFlagTruncate = 0x00040000
+ FsFlagDirectory = 0x00080000
+ FsFlagAppend = 0x00100000
+ FsFlagNoRemote = 0x00200000
+ FsFlagPath = 0x00400000
+ FsFlagDescribe = 0x00800000
+)
+
+const (
+ O_RDONLY = 0x0
+ O_WRONLY = 0x1
+ O_RDWR = 0x2
+ O_PIPELINE = 0x80000000
+
+ // Flags which align with ZXIO_FS_*
+ O_ADMIN = FsRightAdmin
+ O_CREAT = FsFlagCreate
+ O_EXCL = FsFlagExclusive
+ O_TRUNC = FsFlagTruncate
+ O_DIRECTORY = FsFlagDirectory
+ O_APPEND = FsFlagAppend
+ O_NOREMOTE = FsFlagNoRemote
+ O_PATH = FsFlagPath
+
+ FdioAlignedFlags = O_ADMIN | O_CREAT | O_EXCL | O_TRUNC | O_DIRECTORY | O_APPEND |
+ O_NOREMOTE | O_PATH
+
+ // Flags which do not align with ZXIO_FS_*
+ O_NONBLOCK = 0x00000010
+ O_DSYNC = 0x00000020
+ O_SYNC = 0x00000040 | O_DSYNC
+ O_RSYNC = O_SYNC
+ O_NOFOLLOW = 0x00000080
+ O_CLOEXEC = 0x00000100
+ O_NOCTTY = 0x00000200
+ O_ASYNC = 0x00000400
+ O_DIRECT = 0x00000800
+ O_LARGEFILE = 0x00001000
+ O_NOATIME = 0x00002000
+ O_TMPFILE = 0x00004000
+)
+
+func FdioFlagsToZxio(flags uint32) (zflags uint32) {
+ perms := uint32(O_RDONLY | O_WRONLY | O_RDWR)
+ switch flags & perms {
+ case O_RDONLY:
+ zflags |= FsRightReadable
+ case O_WRONLY:
+ zflags |= FsRightWritable
+ case O_RDWR:
+ zflags |= FsRightReadable | FsRightWritable
+ }
+
+ if (flags & O_PIPELINE) == 0 {
+ zflags |= FsFlagDescribe
+ }
+
+ zflags |= (flags & FdioAlignedFlags)
+ return zflags
+}
+
+const (
+ S_IFMT = 0000170000
+ S_IFDIR = 0000040000
+ S_IFREG = 0000100000
+ S_IFIFO = 0000010000
+)
+
+// TODO(crawshaw): generate a zerrors file once cgo is working
+const (
+ EPERM = Errno(0x01)
+ ENOENT = Errno(0x02)
+ EINTR = Errno(0x04)
+ EIO = Errno(0x05)
+ EBADF = Errno(0x09)
+ EACCES = Errno(0x0d)
+ EEXIST = Errno(0x11)
+ ENOTDIR = Errno(0x14)
+ EISDIR = Errno(0x15)
+ EINVAL = Errno(0x16)
+ EMFILE = Errno(0x18)
+ ESPIPE = Errno(0x1d)
+ ENAMETOOLONG = Errno(0x24)
+ ENOTEMPTY = Errno(0x27)
+ ENOPROTOOPT = Errno(0x5c)
+ EOPNOTSUPP = Errno(0x5f)
+ ENOTSUP = EOPNOTSUPP
+ EADDRINUSE = Errno(0x62)
+ EADDRNOTAVAIL = Errno(0x63)
+ ETIMEDOUT = Errno(0x6e)
+ ECONNABORTED = Errno(0x67)
+ EHOSTUNREACH = Errno(0x71)
+ EFUCHSIA = Errno(0xfa)
+)
+
+var EPIPE error = Errno(0x20)
+
+const (
+ SOMAXCONN = 0x80
+)
+
+const (
+ PathMax = 4096
+)
+
+type Stat_t struct {
+ Dev uint64
+ Ino uint64
+ Size uint64
+ CreateTime uint64
+ ModifyTime uint64
+ Mode uint64
+}
+
+func Getpid() (pid int) {
+ // TODO: is ProcHandle process-wide or OS-wide?
+ return int(zx.ProcHandle)
+}
+
+func Getppid() (ppid int) {
+ return 0
+}
+
+func Getuid() (uid int) {
+ return 0
+}
+
+func Geteuid() (uid int) {
+ return 0
+}
+
+func Getgid() (uid int) {
+ return 0
+}
+
+func Getegid() (uid int) {
+ return 0
+}
+
+func Getgroups() (gids []int, err error) {
+ return nil, errors.New("Getgroups unimplemented")
+}
+
+//func Exit(code int) {
+//zx.Sys_process_exit(int64(code))
+//}
+
+const ImplementsGetwd = true
+
+func Getwd() (wd string, err error) {
+ cwdMu.Lock()
+ wd = cwdStr
+ cwdMu.Unlock()
+ return wd, nil
+}
+
+func Chdir(dir string) (err error) {
+ // TODO: if cgo enabled, change the working directory there too.
+ f, err := OpenPath(dir, 0, 0)
+ if err != nil {
+ return err
+ }
+ cwdMu.Lock()
+ var old fdio.FDIO
+ old, cwd = cwd, f
+ // cwd starts as a reference to root, which should remain open.
+ if old != nil && old != root {
+ defer old.Close()
+ }
+ if path.IsAbs(dir) {
+ cwdStr = path.Clean(dir)
+ } else {
+ cwdStr = path.Join(cwdStr, dir)
+ }
+ cwdMu.Unlock()
+ return nil
+}
+
+func Mkdir(path string, mode uint32) (err error) {
+ f, err := OpenPath(path, O_CREAT|O_EXCL|O_RDWR, mode&0777|S_IFDIR)
+ if err != nil {
+ return err
+ }
+ f.Close()
+ return nil
+}
+
+func Rmdir(path string) error {
+ return Unlink(path)
+}
+
+func Unlink(p string) error {
+ dir, relp := fdioPath(path.Clean(p))
+ return dir.Unlink(relp)
+}
+
+func makeAbs(paths ...string) []string {
+ cwdMu.Lock()
+ dir := cwdStr
+ cwdMu.Unlock()
+ for i := range paths {
+ if !path.IsAbs(paths[i]) {
+ paths[i] = path.Join(dir, paths[i])
+ }
+ }
+ return paths
+}
+
+func Rename(oldpath, newpath string) error {
+ abs := makeAbs(oldpath, newpath)
+ rootMu.Lock()
+ r := root
+ rootMu.Unlock()
+ return r.Rename(abs[0][1:], abs[1][1:])
+}
+
+func Link(oldpath, newpath string) error {
+ abs := makeAbs(oldpath, newpath)
+ rootMu.Lock()
+ r := root
+ rootMu.Unlock()
+ return r.Link(abs[0][1:], abs[1][1:])
+}
+
+func Fsync(fd int) error {
+ fdsMu.Lock()
+ f := fds[fd-fdsOff]
+ fdsMu.Unlock()
+ return f.Sync()
+}
+
+func Fchdir(fd int) (err error) {
+ return errors.New("Fchdir unimplemented")
+}
+
+func CloseOnExec(r int) {
+ panic("syscall.CloseOnExec TODO")
+}
+
+func SetNonblock(fd int, nonblocking bool) (err error) {
+ if nonblocking {
+ return errors.New("syscall.SetNonblock: non-blocking not supported on fuchsia")
+ }
+ return nil
+}
+
+var (
+ rootMu sync.Mutex
+ root fdio.FDIO
+)
+
+var (
+ cwdMu sync.Mutex
+ cwd fdio.FDIO
+ cwdStr string
+)
+
+var (
+ nsMu sync.Mutex
+ ns *fdio.NS
+)
+
+var (
+ stdioMu sync.Mutex
+ stdin fdio.FDIO
+ stdout fdio.FDIO
+ stderr fdio.FDIO
+)
+
+const fdsOff = 1e6 // move outside the fd range of unistd.c FDIO
+
+var (
+ fdsMu sync.Mutex
+ fds []fdio.FDIO
+)
+
+func Read(fd int, p []byte) (n int, err error) {
+ if fd == Stdin {
+ stdioMu.Lock()
+ n, err = stdin.Read(p)
+ stdioMu.Unlock()
+ } else {
+ if fd < fdsOff {
+ return 0, EINVAL
+ }
+ fdsMu.Lock()
+ f := fds[fd-fdsOff]
+ fdsMu.Unlock()
+
+ n, err = f.Read(p)
+ }
+ // An io.Reader can return n < len(p) and io.EOF.
+ // But this is the POSIX syscall read(3), which
+ // returns nil on eof.
+ if err == io.EOF {
+ err = nil
+ }
+ return n, err
+}
+
+func init() {
+ EPIPE = zx.EPIPE
+
+ var err error
+
+ nsMu.Lock()
+ ns, err = fdio.NewNSFromMap(zx.RootNSMap)
+ nsMu.Unlock()
+ if err != nil {
+ println("syscall: failed to create namespace: ", err.Error())
+ }
+
+ rootMu.Lock()
+ root, err = ns.OpenRoot()
+ rootMu.Unlock()
+ if err != nil {
+ println("syscall: failed to create root directory from namespace: ", err.Error())
+ }
+
+ cwdMu.Lock()
+ var found bool
+ cwdStr, found = Getenv("PWD")
+ if !found {
+ cwdStr = "/"
+ } else {
+ // Ensure the incoming cwd is absolute and cleaned
+ cwdStr = path.Join("/", cwdStr)
+ }
+ cwd = root
+ if cwdStr != "/" {
+ cwd, err = OpenPath(cwdStr, 0, 0)
+ }
+ cwdMu.Unlock()
+ if err != nil {
+ println("syscall: failed to create fdio cwd: ", err.Error())
+ }
+
+ initStdio := func(i int) (fdio.FDIO, error) {
+ switch zx.StdioHandleTypes[i] {
+ case 0:
+ return nil, EINVAL
+ case fdio.HandleTypeRemote:
+ obj := (*fidlIo.ObjectInterface)(&fidl.Proxy{Channel: zx.Channel(zx.StdioHandles[i][0])})
+ return &fdio.File{Node: fdio.Node{Object: fdio.Object{obj}}}, nil
+ case fdio.HandleTypePipe:
+ return fdio.NewPipe(zx.Socket(zx.StdioHandles[i][0])), nil
+ case fdio.HandleTypeLogger:
+ return fdio.NewLogger(zx.Log(zx.StdioHandles[i][0])), nil
+ default:
+ println("syscall: unknown handle type for stdio: " + itoa(zx.StdioHandleTypes[i]))
+ return nil, EINVAL
+ }
+ }
+ stdioMu.Lock()
+ stdin, err = initStdio(0)
+ if err != nil {
+ println("syscall: failed to create fdio stdin: ", err.Error())
+ }
+ stdout, err = initStdio(1)
+ if err != nil {
+ println("syscall: failed to create fdio stdiout: ", err.Error())
+ }
+ stderr, err = initStdio(2)
+ if err != nil {
+ println("syscall: failed to create fdio stderr: ", err.Error())
+ }
+ stdioMu.Unlock()
+}
+
+func Write(fd int, p []byte) (n int, err error) {
+ switch fd {
+ case Stdout:
+ stdioMu.Lock()
+ n, err := stdout.Write(p)
+ stdioMu.Unlock()
+ return n, err
+ case Stderr:
+ stdioMu.Lock()
+ n, err := stderr.Write(p)
+ stdioMu.Unlock()
+ return n, err
+ default:
+ fdsMu.Lock()
+ f := fds[fd-fdsOff]
+ fdsMu.Unlock()
+ return f.Write(p)
+ }
+ return 0, EINVAL
+}
+
+func Seek(fd int, offset int64, whence int) (off int64, err error) {
+ fdsMu.Lock()
+ f := fds[fd-fdsOff]
+ fdsMu.Unlock()
+ off, err = f.Seek(offset, whence)
+ if err != nil {
+ if status, isStatus := err.(zx.Error); isStatus {
+ if status.Status == zx.ErrNotSupported {
+ if _, isPipe := f.(*fdio.Pipe); isPipe {
+ return off, ESPIPE
+ }
+ }
+ }
+ }
+ return off, err
+}
+
+func Close(fd int) (err error) {
+ if fd < fdsOff {
+ return EINVAL
+ }
+ fdsMu.Lock()
+ if fd-fdsOff > len(fds) {
+ fdsMu.Unlock()
+ return EINVAL
+ }
+ f := fds[fd-fdsOff]
+ fds[fd-fdsOff] = nil
+ fdsMu.Unlock()
+ return f.Close()
+}
+
+func fdioPath(p string) (fdio.FDIO, string) {
+ if path.IsAbs(p) {
+ rootMu.Lock()
+ r := root
+ rootMu.Unlock()
+ return r, p[1:]
+ }
+ cwdMu.Lock()
+ c := cwd
+ cwdMu.Unlock()
+ return c, p
+}
+
+func OpenPath(p string, mode int, perm uint32) (f fdio.FDIO, err error) {
+ if strings.Contains(p, "\x00") {
+ return nil, EINVAL
+ }
+ dir, relp := fdioPath(path.Clean(p))
+ return dir.Open(relp, FdioFlagsToZxio(uint32(mode)), perm)
+}
+
+func Open(path string, mode int, perm uint32) (fd int, err error) {
+ if path == "" {
+ return -1, EINVAL
+ }
+ f, err := OpenPath(path, mode, perm)
+ if err != nil {
+ return -1, err
+ }
+ return OpenFDIO(f), nil
+}
+
+func OpenAt(fdParent int, path string, mode int, perm uint32) (fd int, err error) {
+ parent := FDIOForFD(fdParent)
+ if parent == nil {
+ return -1, EBADF
+ }
+ f, err := parent.Open(path, FdioFlagsToZxio(uint32(mode)), perm)
+ if err != nil {
+ return -1, err
+ }
+ return OpenFDIO(f), nil
+}
+
+func FDIOForFD(fd int) fdio.FDIO {
+ switch fd {
+ case Stdin:
+ return stdin
+ case Stdout:
+ return stdout
+ case Stderr:
+ return stderr
+ }
+ if fd < fdsOff {
+ return nil
+ }
+ fdsMu.Lock()
+ if fd-fdsOff > len(fds) {
+ fdsMu.Unlock()
+ return nil
+ }
+ f := fds[fd-fdsOff]
+ fdsMu.Unlock()
+ return f
+}
+
+func OpenFDIO(f fdio.FDIO) (fd int) {
+ fdsMu.Lock()
+ i := -1
+ for i = 0; i < len(fds); i++ {
+ if fds[i] == nil {
+ fds[i] = f
+ break
+ }
+ }
+ if i == len(fds) {
+ fds = append(fds, f)
+ }
+ fdsMu.Unlock()
+
+ return i + fdsOff
+}
+
+func Ioctl(fd int, op uint32, max uint64, in []byte, handles []zx.Handle) ([]byte, []zx.Handle, error) {
+ fdsMu.Lock()
+ f := fds[fd-fdsOff]
+ fdsMu.Unlock()
+ return f.Ioctl(op, max, in, handles)
+}
+
+func Fstat(fd int, stat *Stat_t) (err error) {
+ fdsMu.Lock()
+ f := fds[fd-fdsOff]
+ fdsMu.Unlock()
+
+ attr, err := f.GetAttr()
+ if err != nil {
+ return err
+ }
+ stat.Dev = uint64(attr.Mode)
+ stat.Ino = attr.Id
+ stat.Size = attr.ContentSize
+ stat.CreateTime = attr.CreationTime
+ stat.ModifyTime = attr.ModificationTime
+ return nil
+}
+
+func Stat(path string, stat *Stat_t) (err error) {
+ fd, err := Open(path, O_RDONLY, 0)
+ if err != nil {
+ return err
+ }
+ err = Fstat(fd, stat)
+ if err2 := Close(fd); err == nil {
+ err = err2
+ }
+ return err
+}
+
+func Lstat(path string, stat *Stat_t) (err error) {
+ // TODO: adjust when there are symlinks
+ return Stat(path, stat)
+}
+
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
+ if fd == Stdout || fd == Stderr {
+ return 0, ESPIPE
+ }
+
+ fdsMu.Lock()
+ f := fds[fd-fdsOff]
+ fdsMu.Unlock()
+
+ // An io.Reader can return n < len(p) and io.EOF.
+ // But this is the POSIX syscall read(3), which
+ // returns nil on eof.
+ n, err = f.ReadAt(p, offset)
+ if err == io.EOF {
+ err = nil
+ }
+ return n, err
+}
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+ if fd == Stdout || fd == Stderr {
+ return 0, ESPIPE
+ }
+
+ fdsMu.Lock()
+ f := fds[fd-fdsOff]
+ fdsMu.Unlock()
+ return f.WriteAt(p, offset)
+}
+
+func Ftruncate(fd int, length int64) (err error) {
+ fdsMu.Lock()
+ f := fds[fd-fdsOff]
+ fdsMu.Unlock()
+ return f.Truncate(uint64(length))
+}
+
+func Truncate(path string, length int64) (err error) {
+ fd, err := Open(path, O_WRONLY, 0)
+ if err != nil {
+ return err
+ }
+ err = Ftruncate(fd, length)
+ if err2 := Close(fd); err == nil {
+ err = err2
+ }
+ return err
+}
+
+func Symlink(oldpath string, newpath string) (err error) {
+ return EOPNOTSUPP // no fuchsia support yet
+}
+
+func UtimesNano(path string, ts []Timespec) (err error) {
+ f, err := OpenPath(path, 0, 0)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ return f.SetAttr(fidlIo.KNodeAttributeFlagModificationTime, fidlIo.NodeAttributes{
+ ModificationTime: uint64(TimespecToNsec(ts[1])),
+ })
+}
+
+func clen(n []byte) int {
+ for i := 0; i < len(n); i++ {
+ if n[i] == 0 {
+ return i
+ }
+ }
+ return len(n)
+}
+
+func ReadDirent(fd int, buf []byte) (n int, err error) {
+ fdsMu.Lock()
+ f := fds[fd-fdsOff]
+ fdsMu.Unlock()
+ dirent, err := f.ReadDirents(uint64(len(buf)))
+ if err != nil {
+ return 0, err
+ }
+ return copy(buf, dirent), nil
+}
+
+func direntIno(buf []byte) (uint64, bool) {
+ // Inodes aren't exposed through Fuchsia; just lie.
+ // Use '1' instead of '0', since '0' means "entry not filled" on some operating systems.
+ return 1, true
+}
+
+func direntReclen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Size), unsafe.Sizeof(Dirent{}.Size))
+}
+
+func direntNamlen(buf []byte) (uint64, bool) {
+ reclen, ok := direntReclen(buf)
+ if !ok {
+ return 0, false
+ }
+ return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true
+}
+
+type Dirent struct {
+ Size uint32
+ Type uint32
+ Name [1]byte
+}
diff --git a/src/syscall/timestruct.go b/src/syscall/timestruct.go
index 84a00a7..6bdc1a1 100644
--- a/src/syscall/timestruct.go
+++ b/src/syscall/timestruct.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia js,wasm linux nacl netbsd openbsd solaris
package syscall
diff --git a/src/syscall/types_fuchsia.go b/src/syscall/types_fuchsia.go
new file mode 100644
index 0000000..9098a4a
--- /dev/null
+++ b/src/syscall/types_fuchsia.go
@@ -0,0 +1,29 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+type Errno uintptr
+
+func (e Errno) Error() string {
+ return "errno(" + itoa(int(e)) + ")"
+}
+
+type Timespec struct {
+ Sec int64
+ Nsec int64
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int64
+}
+
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
+}
+
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: usec}
+}
diff --git a/src/syscall/zerrors_fuchsia.go b/src/syscall/zerrors_fuchsia.go
new file mode 100644
index 0000000..cdd22ca
--- /dev/null
+++ b/src/syscall/zerrors_fuchsia.go
@@ -0,0 +1,72 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+const (
+ SOCK_STREAM = 1
+ SOCK_DGRAM = 2
+ SOCK_RAW = 3
+)
+
+const (
+ IPPROTO_IP = 0
+ IPPROTO_ICMP = 1
+ IPPROTO_TCP = 6
+ IPPROTO_UDP = 17
+ IPPROTO_ICMPV6 = 58
+)
+
+const (
+ AF_INET = 0x2
+ AF_INET6 = 0xa
+)
+
+const (
+ SOL_SOCKET = 0x1
+ SOL_TCP = 0x6
+)
+
+const (
+ SO_ACCEPTCONN = 0x1e
+ SO_BROADCAST = 0x6
+ SO_BSDCOMPAT = 0xe
+ SO_DEBUG = 0x1
+ SO_DOMAIN = 0x27
+ SO_DONTROUTE = 0x5
+ SO_ERROR = 0x4
+ SO_KEEPALIVE = 0x9
+ SO_LINGER = 0xd
+ SO_NO_CHECK = 0xb
+ SO_PASSCRED = 0x10
+ SO_PEERCRED = 0x11
+ SO_PRIORITY = 0xc
+ SO_PROTOCOL = 0x26
+ SO_RCVBUF = 0x8
+ SO_RCVBUFFORCE = 0x21
+ SO_RCVLOWAT = 0x12
+ SO_RCVTIMEO = 0x14
+ SO_REUSEADDR = 0x2
+ SO_REUSEPORT = 0xf
+ SO_SNDBUF = 0x7
+ SO_SNDBUFFORCE = 0x20
+ SO_SNDLOWAT = 0x13
+ SO_SNDTIMEO = 0x15
+ SO_TYPE = 0x3
+)
+
+const (
+ TCP_NODELAY = 1
+ TCP_MAXSEG = 2
+ TCP_CORK = 3
+ TCP_KEEPIDLE = 4
+ TCP_KEEPINTVL = 5
+ TCP_KEEPCNT = 6
+ TCP_SYNCNT = 7
+ TCP_LINGER2 = 8
+ TCP_DEFER_ACCEPT = 9
+ TCP_WINDOW_CLAMP = 10
+ TCP_INFO = 11
+ TCP_QUICKACK = 12
+)
diff --git a/src/syscall/ztypes_fuchsia_amd64.go b/src/syscall/ztypes_fuchsia_amd64.go
new file mode 100644
index 0000000..2f79cde
--- /dev/null
+++ b/src/syscall/ztypes_fuchsia_amd64.go
@@ -0,0 +1,28 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+// +build amd64,fuchsia
+
+type RawSockaddrInet4 struct {
+ Family uint16
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]uint8
+}
+
+type RawSockaddrInet6 struct {
+ Family uint16
+ Port uint16
+ Flowinfo uint32
+ Addr [16]byte /* in6_addr */
+ Scope_id uint32
+}
+
+const (
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x70
+)
diff --git a/src/syscall/ztypes_fuchsia_arm64.go b/src/syscall/ztypes_fuchsia_arm64.go
new file mode 100644
index 0000000..0cca414
--- /dev/null
+++ b/src/syscall/ztypes_fuchsia_arm64.go
@@ -0,0 +1,28 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+// +build arm64,fuchsia
+
+type RawSockaddrInet4 struct {
+ Family uint16
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]uint8
+}
+
+type RawSockaddrInet6 struct {
+ Family uint16
+ Port uint16
+ Flowinfo uint32
+ Addr [16]byte /* in6_addr */
+ Scope_id uint32
+}
+
+const (
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x70
+)
diff --git a/src/syscall/zx/dispatch/dispatcher.go b/src/syscall/zx/dispatch/dispatcher.go
new file mode 100644
index 0000000..df92757
--- /dev/null
+++ b/src/syscall/zx/dispatch/dispatcher.go
@@ -0,0 +1,225 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package dispatch
+
+import (
+ "strconv"
+ "sync"
+ "syscall/zx"
+)
+
+// WaitResult represents a wait result that is returned by the callback.
+// WaitResult determines whether the wait should be re-queued.
+type WaitResult int
+
+const (
+ WaitFinished WaitResult = iota
+ WaitAgain
+)
+
+// WaitID is a monotonically increasing ID which corresponds to a particular
+// call to BeginWait. Note that it may become invalidated if a wait is dequeued.
+type WaitID uint64
+
+// WaitFlags represents the collection of certain options for waiting.
+type WaitFlags uint32
+
+const (
+ HandleShutdown WaitFlags = 1 << 0 // Calls the callback on shutdown.
+)
+
+// Handler is the callback that will be called when the wait is complete.
+type Handler func(*Dispatcher, zx.Status, *zx.PacketSignal) WaitResult
+
+// waitContext is a bookkeeping structure for in-progress waits.
+type waitContext struct {
+ object zx.Handle
+ callback Handler
+ trigger zx.Signals
+ flags WaitFlags
+}
+
+// Dispatcher can read messages from a handle and assign them to a callback.
+type Dispatcher struct {
+ // port is the underlying port used to wait on signals and dispatch.
+ port zx.Port
+
+ // objects is a map that manages wait contexts.
+ mu sync.RWMutex
+ objects map[WaitID]*waitContext
+ nextWaitID WaitID
+
+ // handling is a map that manages which wait IDs that are current being
+ // handled. It is also protected by mu.
+ handling map[WaitID]struct{}
+
+ // shutdown is whether the dispatcher has shut down.
+ shutdown bool
+}
+
+// New creates a new dispatcher.
+func NewDispatcher() (*Dispatcher, error) {
+ port, err := zx.NewPort(0)
+ if err != nil {
+ return nil, err
+ }
+ return &Dispatcher{
+ port: port,
+ objects: make(map[WaitID]*waitContext),
+ handling: make(map[WaitID]struct{}),
+ }, nil
+}
+
+func assertWaitResult(result WaitResult, status zx.Status) {
+ if !(result == WaitFinished || (result == WaitAgain && status == zx.ErrOk)) {
+ panic("expected " + strconv.Itoa(int(result)) + " for status " + strconv.Itoa(int(status)))
+ }
+}
+
+// Closes a dispatcher, shutting down all handles added to the dispatcher.
+func (d *Dispatcher) Close() {
+ d.mu.Lock()
+ defer d.mu.Unlock()
+ d.port.Close()
+ for _, obj := range d.objects {
+ if obj != nil && (obj.flags&HandleShutdown) != 0 {
+ // Ignore the result; we won't be waiting again.
+ result := obj.callback(d, zx.ErrCanceled, nil)
+ assertWaitResult(result, zx.ErrCanceled)
+ }
+ }
+ d.objects = make(map[WaitID]*waitContext)
+ d.shutdown = true
+}
+
+func (d *Dispatcher) getWaitID() WaitID {
+ _, ok := d.objects[d.nextWaitID]
+ for ok {
+ d.nextWaitID++
+ _, ok = d.objects[d.nextWaitID]
+ }
+ return d.nextWaitID
+}
+
+// BeginWait creates a new wait on the handle h for signals t. The new wait
+// will respect the flags f, and call the handler c on wait completion.
+func (d *Dispatcher) BeginWait(h zx.Handle, t zx.Signals, f WaitFlags, c Handler) (WaitID, error) {
+ d.mu.Lock()
+ defer d.mu.Unlock()
+
+ // If we've shut down, just notify that we're in a bad state.
+ if d.shutdown {
+ return 0, zx.Error{Status: zx.ErrBadState}
+ }
+
+ // Register the wait.
+ id := d.getWaitID()
+ d.objects[id] = &waitContext{
+ object: h,
+ callback: c,
+ trigger: t,
+ flags: f,
+ }
+
+ // Schedule the wait on the port.
+ err := d.port.WaitAsync(h, uint64(id), t, zx.PortWaitAsyncOnce)
+
+ // If we fail, make sure to de-register the wait.
+ if err != nil {
+ delete(d.objects, id)
+ }
+ return id, err
+}
+
+// CancelWait cancels the wait with the given WaitID.
+func (d *Dispatcher) CancelWait(id WaitID) error {
+ d.mu.Lock()
+ defer d.mu.Unlock()
+
+ // Look up the wait context.
+ wc := d.objects[id]
+ if wc == nil {
+ return zx.Error{Status: zx.ErrNotFound}
+ }
+
+ // If we're currently handling it, it's not being waited on, so there's nothing
+ // to cancel.
+ _, ok := d.handling[id]
+ if ok {
+ return zx.Error{Status: zx.ErrNotFound}
+ }
+
+ // Deregister no matter what here. Due to stack semantics of defer, this will always
+ // execute before the lock is released.
+ defer delete(d.objects, id)
+
+ // Cancel the actual wait.
+ return d.port.Cancel(wc.object, uint64(id))
+}
+
+func (d *Dispatcher) dispatch(id WaitID, wc *waitContext, signals *zx.PacketSignal) {
+ // Deregister the handler before invoking it.
+ d.mu.Lock()
+ d.handling[id] = struct{}{}
+ d.mu.Unlock()
+
+ // Call the handler.
+ result := wc.callback(d, zx.ErrOk, signals)
+ assertWaitResult(result, zx.ErrOk)
+ switch result {
+ case WaitAgain:
+ // Re-arm the handler, as the handler requested. Use a fresh ID since there's a
+ // chance the old ID has already been re-used.
+ d.mu.Lock()
+ delete(d.handling, id)
+ err := d.port.WaitAsync(wc.object, uint64(id), wc.trigger, zx.PortWaitAsyncOnce)
+ d.mu.Unlock()
+
+ // If we fail to re-arm, notify the handler of what happened.
+ if err != nil {
+ zxErr := err.(zx.Error)
+ result = wc.callback(d, zxErr.Status, nil)
+ assertWaitResult(result, zxErr.Status)
+ }
+ case WaitFinished:
+ d.mu.Lock()
+ delete(d.handling, id)
+ delete(d.objects, id)
+ d.mu.Unlock()
+ }
+}
+
+// Serve runs indefinitely, waiting for the port to return a packet and dispatches
+// the relevant handlers.
+func (d *Dispatcher) Serve() {
+ for {
+ // Wait for any handler to be ready
+ var packet zx.Packet
+ err := d.port.Wait(&packet, zx.TimensecInfinite)
+ if err != nil {
+ d.Close()
+ return
+ }
+ id := WaitID(packet.Hdr.Key)
+
+ // Get the object for dispatching.
+ d.mu.RLock()
+ wc := d.objects[id]
+ d.mu.RUnlock()
+
+ // If handler was removed while this packet was in the queue,
+ // just go back to waiting.
+ if wc == nil {
+ continue
+ }
+
+ // Dispatch to the appropriate handler.
+ if packet.Hdr.Type == zx.PortPacketTypeSignalOne {
+ d.dispatch(id, wc, packet.Signal())
+ }
+ }
+}
diff --git a/src/syscall/zx/dispatch/dispatcher_test.go b/src/syscall/zx/dispatch/dispatcher_test.go
new file mode 100644
index 0000000..9c1975b
--- /dev/null
+++ b/src/syscall/zx/dispatch/dispatcher_test.go
@@ -0,0 +1,231 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package dispatch_test
+
+import (
+ "sync/atomic"
+ "syscall/zx"
+ . "syscall/zx/dispatch"
+ "testing"
+ "time"
+)
+
+func dispatcherTest(t *testing.T, name string, f func(d *Dispatcher) error) {
+ t.Run(name, func(t *testing.T) {
+ d, err := NewDispatcher()
+ if err != nil {
+ t.Fatal("creating dispatcher: ", err)
+ }
+ go d.Serve()
+ if err := f(d); err != nil {
+ t.Fatal("executing test: ", err)
+ }
+ d.Close()
+ })
+}
+
+func TestWait(t *testing.T) {
+ t.Parallel()
+ dispatcherTest(t, "WaitOnce", func(d *Dispatcher) error {
+ h0, h1, err := zx.NewChannel(0)
+ if err != nil {
+ return err
+ }
+ defer h0.Close()
+
+ done := make(chan struct{}, 1)
+ defer close(done)
+
+ handler := func(d *Dispatcher, s zx.Status, p *zx.PacketSignal) WaitResult {
+ done <- struct{}{}
+ return WaitFinished
+ }
+
+ _, err = d.BeginWait(zx.Handle(h0), zx.SignalChannelPeerClosed, 0, handler)
+ if err != nil {
+ return err
+ }
+
+ h1.Close()
+
+ select {
+ case <-done:
+ return nil
+ case <-time.After(5 * time.Second):
+ t.Fatal("timed out, handler never executed")
+ }
+ return nil
+ })
+ dispatcherTest(t, "WaitMultipleTimes", func(d *Dispatcher) error {
+ h0, h1, err := zx.NewChannel(0)
+ if err != nil {
+ return err
+ }
+ defer h0.Close()
+ defer h1.Close()
+
+ done := make(chan struct{}, 1)
+ defer close(done)
+
+ handler := func(d *Dispatcher, s zx.Status, p *zx.PacketSignal) WaitResult {
+ var b [zx.ChannelMaxMessageBytes]byte
+ var h [zx.ChannelMaxMessageHandles]zx.Handle
+ bn, hn, err := h0.Read(b[:], h[:], 0)
+ if err != nil {
+ t.Fatal("error reading: ", err)
+ }
+ if bn != 1 || hn != 0 {
+ t.Fatalf("unexpected read %d bytes %d handles", bn, hn)
+ }
+ if b[0] == 1 {
+ return WaitAgain
+ }
+ done <- struct{}{}
+ return WaitFinished
+ }
+
+ _, err = d.BeginWait(zx.Handle(h0), zx.SignalChannelReadable, 0, handler)
+ if err != nil {
+ return err
+ }
+
+ for i := 0; i < 5; i++ {
+ if err := h1.Write([]byte{1}, nil, 0); err != nil {
+ return err
+ }
+ }
+ if err := h1.Write([]byte{0}, nil, 0); err != nil {
+ return err
+ }
+
+ select {
+ case <-done:
+ return nil
+ case <-time.After(5 * time.Second):
+ t.Fatal("timed out, handler never executed")
+ }
+ return nil
+ })
+ dispatcherTest(t, "CancelWaitHandleShutdown", func(d *Dispatcher) error {
+ h0, h1, err := zx.NewChannel(0)
+ if err != nil {
+ return err
+ }
+ defer h0.Close()
+ defer h1.Close()
+
+ var i uint32
+ handler := func(d *Dispatcher, s zx.Status, p *zx.PacketSignal) WaitResult {
+ atomic.AddUint32(&i, 1)
+ return WaitFinished
+ }
+
+ id, err := d.BeginWait(zx.Handle(h0), zx.SignalChannelPeerClosed, HandleShutdown, handler)
+ if err != nil {
+ return err
+ }
+
+ if err := d.CancelWait(id); err != nil {
+ return err
+ }
+ d.Close()
+ if i != 0 {
+ t.Fatal("handler ran unexpectedly")
+ }
+ return nil
+ })
+ dispatcherTest(t, "Shutdown", func(d *Dispatcher) error {
+ h0, h1, err := zx.NewChannel(0)
+ if err != nil {
+ return err
+ }
+ defer h0.Close()
+ defer h1.Close()
+
+ handler := func(d *Dispatcher, s zx.Status, p *zx.PacketSignal) WaitResult {
+ return WaitFinished
+ }
+ d.Close()
+
+ _, err = d.BeginWait(zx.Handle(h0), zx.SignalChannelPeerClosed, 0, handler)
+ if err == nil {
+ t.Fatal("unexpected success for BeginWait on shut down dispatcher")
+ }
+ return nil
+ })
+ dispatcherTest(t, "HandleShutdown", func(d *Dispatcher) error {
+ h0, h1, err := zx.NewChannel(0)
+ if err != nil {
+ return err
+ }
+ defer h0.Close()
+ defer h1.Close()
+
+ done := make(chan struct{}, 1)
+ defer close(done)
+
+ handler := func(d *Dispatcher, s zx.Status, p *zx.PacketSignal) WaitResult {
+ done <- struct{}{}
+ return WaitFinished
+ }
+
+ _, err = d.BeginWait(zx.Handle(h0), zx.SignalChannelPeerClosed, HandleShutdown, handler)
+ if err != nil {
+ return err
+ }
+ d.Close()
+
+ select {
+ case <-done:
+ return nil
+ case <-time.After(5 * time.Second):
+ t.Fatal("timed out, handler never executed")
+ }
+ return nil
+ })
+ dispatcherTest(t, "MultipleGoroutines", func(d *Dispatcher) error {
+ // Spin up 5 goroutines all serving the dispatcher.
+ for i := 0; i < 5; i++ {
+ go d.Serve()
+ }
+
+ done := make(chan struct{}, 20)
+ defer close(done)
+
+ var ends []zx.Channel
+ for i := 0; i < 20; i++ {
+ h0, h1, err := zx.NewChannel(0)
+ if err != nil {
+ return err
+ }
+ defer h0.Close()
+
+ handler := func(d *Dispatcher, s zx.Status, p *zx.PacketSignal) WaitResult {
+ done <- struct{}{}
+ return WaitFinished
+ }
+
+ _, err = d.BeginWait(zx.Handle(h0), zx.SignalChannelPeerClosed, 0, handler)
+ if err != nil {
+ return err
+ }
+ ends = append(ends, h1)
+ }
+ for _, e := range ends {
+ e.Close()
+ }
+ for i := 0; i < 20; i++ {
+ select {
+ case <-done:
+ continue
+ case <-time.After(3 * time.Second):
+ t.Fatal("timed out, some handler never executed")
+ }
+ }
+ return nil
+ })
+}
diff --git a/src/syscall/zx/fdio/client.go b/src/syscall/zx/fdio/client.go
new file mode 100644
index 0000000..f7af0dc
--- /dev/null
+++ b/src/syscall/zx/fdio/client.go
@@ -0,0 +1,38 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package fdio
+
+import (
+ "syscall/zx"
+ "syscall/zx/fidl"
+ "syscall/zx/io"
+)
+
+func ServiceConnect(svcpath string, h zx.Handle) error {
+ // Otherwise attempt to connect through the root namespace.
+ ns, err := NewNSFromMap(zx.RootNSMap)
+ if err == nil {
+ return ns.Connect(svcpath, h)
+ }
+ h.Close()
+ return zx.Error{Status: zx.ErrNotFound, Text: "fdio.ServiceConnect"}
+}
+
+func ServiceConnectAt(dir zx.Handle, path string, h zx.Handle) error {
+ if !dir.IsValid() || !h.IsValid() {
+ return zx.Error{Status: zx.ErrInvalidArgs, Text: "fdio.ServiceConnectAt"}
+ }
+ // Open the path on the remote.
+ iface := (*io.DirectoryInterface)(&fidl.Proxy{Channel: zx.Channel(dir)})
+ req := io.ObjectInterfaceRequest(fidl.InterfaceRequest{Channel: zx.Channel(h)})
+ err := iface.Open(io.KOpenRightReadable|io.KOpenRightWritable, 0755, path, req)
+ if err != nil {
+ h.Close()
+ return err
+ }
+ return nil
+}
diff --git a/src/syscall/zx/fdio/directory.go b/src/syscall/zx/fdio/directory.go
new file mode 100644
index 0000000..1b0dcd4
--- /dev/null
+++ b/src/syscall/zx/fdio/directory.go
@@ -0,0 +1,182 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package fdio
+
+import (
+ "path"
+ "syscall/zx"
+ "syscall/zx/fidl"
+ "syscall/zx/io"
+)
+
+// Directory is a wrapper around a DirectoryInterface which implements FDIO.
+type Directory struct {
+ Node
+}
+
+func (d *Directory) getToken() (zx.Handle, error) {
+ status, token, err := d.DirectoryInterface().GetToken()
+ if err != nil {
+ return zx.HandleInvalid, err
+ } else if status != zx.ErrOk {
+ return zx.HandleInvalid, zx.Error{Status: status, Text: "io.directory"}
+ }
+ return token, nil
+}
+
+// DirectoryInterface returns the underlying Directory FIDL interface.
+func (d *Directory) DirectoryInterface() *io.DirectoryInterface {
+ return (*io.DirectoryInterface)(d.Node.Object.ObjectInterface)
+}
+
+// Close closes the Directory object.
+func (d *Directory) Close() error {
+ defer ((*fidl.Proxy)(d.Node.Object.ObjectInterface)).Close()
+ if status, err := d.Node.Object.ObjectInterface.Close(); err != nil {
+ return err
+ } else if status != zx.ErrOk {
+ return zx.Error{Status: status, Text: "io.directory"}
+ }
+ return nil
+}
+
+// Open opens an FDIO at path with the given flags and mode relative to this
+// Directory.
+func (d *Directory) Open(pathname string, flags uint32, mode uint32) (FDIO, error) {
+ req, obj, err := io.NewObjectInterfaceRequest()
+ if err != nil {
+ return nil, err
+ }
+ err = d.DirectoryInterface().Open(flags|io.KOpenFlagDescribe, mode, pathname, req)
+ if err != nil {
+ return nil, err
+ }
+ status, info, err := obj.ExpectOnOpen()
+ if err != nil {
+ return nil, err
+ } else if status != zx.ErrOk {
+ return nil, zx.Error{Status: status, Text: "io.directory"}
+ }
+ return objectFromInfo(info, obj)
+}
+
+func (d *Directory) openParent(pathname string) (FDIO, string, error) {
+ dirpath, name := path.Split(pathname)
+ parent, err := d.Open(path.Dir(dirpath), io.KOpenRightReadable, io.KOpenFlagDirectory)
+ if err != nil {
+ return nil, "", err
+ }
+ return parent, name, err
+}
+
+// Link creates a link between two paths under this Directory.
+func (d *Directory) Link(oldpath, newpath string) error {
+ oldparent, oldname, err := d.openParent(oldpath)
+ if err != nil {
+ return err
+ }
+ defer oldparent.Close()
+ newparent, newname, err := d.openParent(newpath)
+ if err != nil {
+ return err
+ }
+ defer newparent.Close()
+ olddir, ok := oldparent.(*Directory)
+ if !ok {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "io.directory"}
+ }
+ newdir, ok := newparent.(*Directory)
+ if !ok {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "io.directory"}
+ }
+ token, err := newdir.getToken()
+ if err != nil {
+ return err
+ }
+ status, err := olddir.DirectoryInterface().Link(oldname, token, newname)
+ if err != nil {
+ return err
+ } else if status != zx.ErrOk {
+ return zx.Error{Status: status, Text: "io.directory"}
+ }
+ return nil
+}
+
+// Rename renames an object at one path to another under this Directory.
+func (d *Directory) Rename(oldpath, newpath string) error {
+ oldf, oldname, err := d.openParent(oldpath)
+ if err != nil {
+ return err
+ }
+ defer oldf.Close()
+ newf, newname, err := d.openParent(newpath)
+ if err != nil {
+ return err
+ }
+ defer newf.Close()
+ olddir, ok := oldf.(*Directory)
+ if !ok {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "io.directory"}
+ }
+ newdir, ok := newf.(*Directory)
+ if !ok {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "io.directory"}
+ }
+ token, err := newdir.getToken()
+ if err != nil {
+ return err
+ }
+ status, err := olddir.DirectoryInterface().Rename(oldname, token, newname)
+ if err != nil {
+ return err
+ } else if status != zx.ErrOk {
+ return zx.Error{Status: status, Text: "io.directory"}
+ }
+ return nil
+}
+
+// Unlink unlinks an object at a pauth under this Directory.
+func (d *Directory) Unlink(pathname string) error {
+ parent, name, err := d.openParent(pathname)
+ if err != nil {
+ return err
+ }
+ defer parent.Close()
+ parentdir, ok := parent.(*Directory)
+ if !ok {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "io.directory"}
+ }
+ if status, err := parentdir.DirectoryInterface().Unlink(name); err != nil {
+ return err
+ } else if status != zx.ErrOk {
+ return zx.Error{Status: status, Text: "io.directory"}
+ }
+ return nil
+}
+
+// ReadDirents returns up to max-worth bytes of byte-encoded dirents which represent
+// objects under this Directory. Repeated calls to ReadDirents continues giving back
+// objects.
+func (d *Directory) ReadDirents(max uint64) ([]byte, error) {
+ status, dirents, err := d.DirectoryInterface().ReadDirents(max)
+ if err != nil {
+ return nil, err
+ } else if status != zx.ErrOk {
+ return nil, zx.Error{Status: status, Text: "io.file"}
+ }
+ return dirents, nil
+}
+
+// Rewind resets the ReadDirents' counter.
+func (d *Directory) Rewind() error {
+ if status, err := d.DirectoryInterface().Rewind(); err != nil {
+ return err
+ } else if status != zx.ErrOk {
+ return zx.Error{Status: status, Text: "io.directory"}
+ }
+ return nil
+}
diff --git a/src/syscall/zx/fdio/fdio.go b/src/syscall/zx/fdio/fdio.go
new file mode 100644
index 0000000..eca6eb7
--- /dev/null
+++ b/src/syscall/zx/fdio/fdio.go
@@ -0,0 +1,225 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+// Package fdio provides unix-style IO, implementing Zircon's "system/ulib/fdio"
+package fdio
+
+import (
+ "syscall/zx"
+ "syscall/zx/io"
+)
+
+const (
+ // MaxUnderlyingHandles is the maximum number of handles which are
+ // necessary to implement any FDIO object.
+ MaxUnderlyingHandles = 2
+)
+
+// FDIO provides classic unix-style IO over various transports
+type FDIO interface {
+ Handles() []zx.Handle
+
+ Clone() (FDIO, error)
+ Close() error
+
+ Sync() error
+ GetAttr() (io.NodeAttributes, error)
+ SetAttr(flags uint32, attr io.NodeAttributes) error
+ Ioctl(op uint32, max uint64, in []byte, handles []zx.Handle) ([]byte, []zx.Handle, error)
+
+ Read(data []byte) (int, error)
+ ReadAt(data []byte, off int64) (int, error)
+ Write(data []byte) (int, error)
+ WriteAt(data []byte, off int64) (int, error)
+ Seek(offset int64, whence int) (int64, error)
+ Truncate(length uint64) error
+
+ Open(path string, flags uint32, mode uint32) (FDIO, error)
+ Link(oldpath, newpath string) error
+ Rename(oldpath, newpath string) error
+ Unlink(path string) error
+ ReadDirents(max uint64) ([]byte, error)
+ Rewind() error
+}
+
+// FDIO Ioctls
+func IoctlNum(kind, family, number uint32) uint32 {
+ return ((kind & 0xF) << 20) | ((family & 0xFF) << 8) | (number & 0xFF)
+}
+func IoctlKind(ioctl uint32) uint32 {
+ return (ioctl >> 20) & 0xF
+}
+func IoctlFamily(ioctl uint32) uint32 {
+ return (ioctl >> 8) & 0xFF
+}
+func IoctlNumber(ioctl uint32) uint32 {
+ return ioctl & 0xFF
+}
+
+const (
+ // IoctlMaxInput is the largest acceptable size for an Ioctl op input.
+ IoctlMaxInput = 1024
+)
+
+const (
+ IoctlKindDefault = 0x0 // IOCTL_KIND_DEFAULT
+ IoctlKindGetHandle = 0x1 // IOCTL_KIND_GET_HANDLE
+ IoctlKindGetTwoHandles = 0x2 // IOCTL_KIND_GET_TWO_HANDLES
+ IoctlKindSetHandle = 0x3 // IOCTL_KIND_SET_HANDLE
+ IoctlKindGetThreeHandles = 0x4 // IOCTL_KIND_GET_THREE_HANDLES
+)
+
+const (
+ IoctlFamilyReserved = 0x00 // IOCTL_FAMILY_RESERVED
+ IoctlFamilyDevice = 0x01 // IOCTL_FAMILY_DEVICE
+ IoctlFamilyVFS = 0x02 // IOCTL_FAMILY_VFS
+ IoctlFamilyDMCTL = 0x03 // IOCTL_FAMILY_DMCTL
+ IoctlFamilyTest = 0x04 // IOCTL_FAMILY_TEST
+)
+
+const (
+ IoctlFamilyBlock = 0x13 // IOCTL_FAMILY_BLOCK
+ IoctlFamilyNetconfig = 0x26 // IOCTL_FAMILY_NETCONFIG
+)
+
+const (
+ IoctlFamilyPower = 0x30 // IOCTL_FAMILY_POWER
+)
+
+var IoctlDeviceBind = IoctlNum(IoctlKindDefault, IoctlFamilyDevice, 0)
+var IoctlDeviceGetEventHandle = IoctlNum(IoctlKindGetHandle, IoctlFamilyDevice, 1)
+var IoctlDeviceGetDriverName = IoctlNum(IoctlKindDefault, IoctlFamilyDevice, 2)
+var IoctlDeviceGetDeviceName = IoctlNum(IoctlKindDefault, IoctlFamilyDevice, 3)
+var IoctlDeviceGetTopoPath = IoctlNum(IoctlKindDefault, IoctlFamilyDevice, 4)
+var IoctlDeviceSync = IoctlNum(IoctlKindDefault, IoctlFamilyDevice, 6)
+var IoctlDeviceDebugSuspend = IoctlNum(IoctlKindDefault, IoctlFamilyDevice, 7)
+var IoctlDeviceDebugResume = IoctlNum(IoctlKindDefault, IoctlFamilyDevice, 8)
+
+var IoctlVFSMountFS = IoctlNum(IoctlKindSetHandle, IoctlFamilyVFS, 0)
+var IoctlVFSUnmountFS = IoctlNum(IoctlKindDefault, IoctlFamilyVFS, 1)
+var IoctlVFSUnmountNode = IoctlNum(IoctlKindGetHandle, IoctlFamilyVFS, 2)
+var IoctlVFSQueryFS = IoctlNum(IoctlKindDefault, IoctlFamilyVFS, 4)
+var IoctlVFSGetTokenFS = IoctlNum(IoctlKindGetHandle, IoctlFamilyVFS, 5)
+var IoctlVFSWatchDir = IoctlNum(IoctlKindSetHandle, IoctlFamilyVFS, 8)
+var IoctlVFSGetDevicePath = IoctlNum(IoctlKindDefault, IoctlFamilyVFS, 9)
+
+var IoctlPowerGetInfo = IoctlNum(IoctlKindDefault, IoctlFamilyPower, 1)
+var IoctlPowerGetBatteryInfo = IoctlNum(IoctlKindDefault, IoctlFamilyPower, 2)
+var IoctlPowerGetStateChangeEvent = IoctlNum(IoctlKindGetHandle, IoctlFamilyPower, 3)
+
+type PowerInfoResult struct {
+ PowerType uint32
+ State uint32
+}
+
+type BatteryInfoResult struct {
+ Unit uint32
+ DesignCapacity uint32
+ LastFullCapacity uint32
+ DesignVoltage uint32
+ CapacityWarning uint32
+ CapacityLow uint32
+ CapacityGranularityLowWarning uint32
+ CapacityGranularityWarningFull uint32
+ PresentRate int32
+ RemainingCapacity uint32
+ PresentVoltage uint32
+}
+
+const (
+ PowerTypeAC = 0
+ PowerTypeBattery = 1
+
+ PowerStateOnline = 1 << 0
+ PowerStateDischarging = 1 << 1
+ PowerStateCharging = 1 << 2
+ PowerStateCritical = 1 << 3
+
+ BatteryUnitMW = 0
+ BatteryUnitMA = 1
+)
+
+type VFSWatchDirRequest struct {
+ H zx.Handle
+ Mask uint32
+ Options uint32
+}
+
+const (
+ VFSWatchEventDeleted = iota
+ VFSWatchEventAdded
+ VFSWatchEventRemoved
+ VFSWatchEventExisting
+ VFSWatchEventIdle
+)
+
+const (
+ VFSWatchMaskDeleted = 1 << iota
+ VFSWatchMaskAdded
+ VFSWatchMaskRemoved
+ VFSWatchMaskExisting
+ VFSWatchMaskIdle
+ VFSWatchMaskAll = 0x1F
+)
+
+type Vnattr struct {
+ Valid uint32
+ Mode Vtype
+ Inode uint64
+ Size uint64
+ Blksize uint64
+ Blkcount uint64
+ Nlink uint64
+ CreateTime uint64
+ ModifyTime uint64
+}
+
+// VnattrBlksize is the size of block used in "Blockcount", which may be distinct from Blksize.
+const VnattrBlksize = 512
+
+const (
+ AttrCtime = 1 << iota
+ AttrMtime
+ AttrAtime
+)
+
+type Vtype uint32
+
+// bit-compatible with POSIX stat
+const (
+ VtypeMask Vtype = 0170000
+ VtypeSock Vtype = 0140000
+ VtypeLink Vtype = 0120000
+ VtypeFile Vtype = 0100000
+ VtypeBdev Vtype = 0060000
+ VtypeDir Vtype = 0040000
+ VtypeCdev Vtype = 0020000
+ VtypePipe Vtype = 0010000
+
+ VtypeISUID Vtype = 0004000
+ VtypeISGID Vtype = 0002000
+ VtypeISVTX Vtype = 0001000
+ VtypeIRWXU Vtype = 0000700
+ VtypeIRUSR Vtype = 0000400
+ VtypeIWUSR Vtype = 0000200
+ VtypeIXUSR Vtype = 0000100
+ VtypeIRWXG Vtype = 0000070
+ VtypeIRGRP Vtype = 0000040
+ VtypeIWGRP Vtype = 0000020
+ VtypeIXGRP Vtype = 0000010
+ VtypeIRWXO Vtype = 0000007
+ VtypeIROTH Vtype = 0000004
+ VtypeIWOTH Vtype = 0000002
+ VtypeIXOTH Vtype = 0000001
+)
+
+const (
+ HandleTypeRemote = 0x32
+ HandleTypePipe = 0x33
+ HandleTypeEvent = 0x34
+ HandleTypeLogger = 0x35
+ HandleTypeSocket = 0x36
+)
diff --git a/src/syscall/zx/fdio/file.go b/src/syscall/zx/fdio/file.go
new file mode 100644
index 0000000..2d847d0
--- /dev/null
+++ b/src/syscall/zx/fdio/file.go
@@ -0,0 +1,152 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package fdio
+
+import (
+ "syscall/zx"
+ "syscall/zx/io"
+)
+
+// File is a wrapper around a FileInterface which implements FDIO.
+type File struct {
+ Node
+ Event zx.Event
+}
+
+// FileInterface returns the underlying File FIDL interface.
+func (f *File) FileInterface() *io.FileInterface {
+ return (*io.FileInterface)(f.Node.Object.ObjectInterface)
+}
+
+// Handles returns all the underlying handles for this file,
+// which is the control channel and an event.
+func (f *File) Handles() []zx.Handle {
+ return append(f.Node.Handles(), zx.Handle(f.Event))
+}
+
+// Close closes all the control channel and event associated with the file
+// object.
+func (f *File) Close() error {
+ defer f.Event.Close()
+ return f.Node.Close()
+}
+
+// read reads data from a File. If off == -1 then it does a read
+// from whatever the seek offset is.
+func (f *File) read(data []byte, off int64) (int, error) {
+ ptr := 0
+ for ptr < len(data) {
+ bytesToRead := int(io.KMaxBuf)
+ if len(data)-ptr < int(io.KMaxBuf) {
+ bytesToRead = len(data) - ptr
+ }
+ var status zx.Status
+ var out []byte
+ var err error
+ if off == -1 {
+ status, out, err = f.FileInterface().Read(uint64(bytesToRead))
+ } else {
+ status, out, err = f.FileInterface().ReadAt(
+ uint64(bytesToRead),
+ uint64(int64(ptr)+off),
+ )
+ }
+ if err != nil {
+ return ptr, err
+ } else if status != zx.ErrOk {
+ return ptr, zx.Error{Status: status, Text: "io.file"}
+ }
+ if len(out) == 0 {
+ return ptr, nil
+ }
+ copy(data[ptr:ptr+len(out)], out)
+ ptr += len(out)
+ // Stop at short read.
+ if len(out) < bytesToRead {
+ return ptr, nil
+ }
+ }
+ return ptr, nil
+}
+
+// Read reads data from the internally held offset in the File.
+func (f *File) Read(data []byte) (int, error) {
+ return f.read(data, -1)
+}
+
+// ReadAt reads data at an offset in a File.
+func (f *File) ReadAt(data []byte, off int64) (int, error) {
+ return f.read(data, off)
+}
+
+// write writes data to a file. If off == -1 then the write occurs at
+// whatever the seek offset is.
+func (f *File) write(data []byte, off int64) (int, error) {
+ ptr := 0
+ for ptr < len(data) {
+ bytesToWrite := int(io.KMaxBuf)
+ if len(data)-ptr < int(io.KMaxBuf) {
+ bytesToWrite = len(data) - ptr
+ }
+ var status zx.Status
+ var written uint64
+ var err error
+ if off == -1 {
+ status, written, err = f.FileInterface().Write(
+ data[ptr : ptr+bytesToWrite],
+ )
+ } else {
+ status, written, err = f.FileInterface().WriteAt(
+ data[ptr:ptr+bytesToWrite],
+ uint64(int64(ptr)+off),
+ )
+ }
+ if err != nil {
+ return ptr, err
+ } else if status != zx.ErrOk {
+ return ptr, zx.Error{Status: status, Text: "io.file"}
+ }
+ ptr += int(written)
+ // Error on a short write.
+ if int(written) < bytesToWrite {
+ return ptr, zx.Error{Status: zx.ErrIO, Text: "io.file"}
+ }
+ }
+ return ptr, nil
+}
+
+// Write writes data at the internally held offset in the File.
+func (f *File) Write(data []byte) (int, error) {
+ return f.write(data, -1)
+}
+
+// WriteAt writes data at an offset in a File.
+func (f *File) WriteAt(data []byte, off int64) (int, error) {
+ return f.write(data, off)
+}
+
+// Seek moves the read/write head offset of the File.
+func (f *File) Seek(offset int64, whence int) (int64, error) {
+ status, off, err := f.FileInterface().Seek(offset, io.SeekOrigin(whence))
+ if err != nil {
+ return -1, err
+ } else if status != zx.ErrOk {
+ return -1, zx.Error{Status: status, Text: "io.file"}
+ }
+ return int64(off), nil
+}
+
+// Truncate truncates a File.
+func (f *File) Truncate(length uint64) error {
+ status, err := f.FileInterface().Truncate(length)
+ if err != nil {
+ return err
+ } else if status != zx.ErrOk {
+ return zx.Error{Status: status, Text: "io.file"}
+ }
+ return nil
+}
diff --git a/src/syscall/zx/fdio/logger.go b/src/syscall/zx/fdio/logger.go
new file mode 100644
index 0000000..d5723b6
--- /dev/null
+++ b/src/syscall/zx/fdio/logger.go
@@ -0,0 +1,134 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package fdio
+
+import (
+ "syscall/zx"
+ "syscall/zx/io"
+)
+
+type Logger struct {
+ log zx.Log
+ logBufferArray [1024]byte
+ logBufferN int
+}
+
+func NewLogger(log zx.Log) *Logger {
+ return &Logger{log: log}
+}
+
+// Clone makes a clone of the object.
+func (f *Logger) Clone() (FDIO, error) {
+ logHandle := zx.Handle(f.log)
+ h, err := logHandle.Duplicate(zx.RightSameRights)
+ if err != nil {
+ return nil, err
+ }
+ return NewLogger(zx.Log(h)), nil
+}
+
+// Handle returns the underlying log handle as an untyped handle.
+func (f *Logger) Handles() []zx.Handle {
+ return []zx.Handle{zx.Handle(f.log)}
+}
+
+// Close closes the object.
+func (f *Logger) Close() error {
+ return f.log.Close()
+}
+
+// Sync implements FDIO for Logger.
+func (f *Logger) Sync() error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// GetAttr implements FDIO for Logger.
+func (f *Logger) GetAttr() (io.NodeAttributes, error) {
+ return io.NodeAttributes{}, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// SetAttr implements FDIO for Logger.
+func (f *Logger) SetAttr(flags uint32, attr io.NodeAttributes) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// Ioctl implements FDIO for Logger.
+func (f *Logger) Ioctl(op uint32, max uint64, in []byte, handles []zx.Handle) ([]byte, []zx.Handle, error) {
+ return nil, nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// Read implements FDIO for Logger.
+func (f *Logger) Read(data []byte) (int, error) {
+ return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// ReadAt implements FDIO for Logger.
+func (f *Logger) ReadAt(data []byte, off int64) (int, error) {
+ return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// Write implements FDIO for Logger.
+func (f *Logger) Write(data []byte) (int, error) {
+ // Sys_log_write adds a newline to output buffers. To prevent fragmented logs, we buffer
+ // output until a newline character is encountered.
+ f.logBufferN += copy(f.logBufferArray[f.logBufferN:], data)
+ if f.logBufferArray[f.logBufferN-1] == '\n' {
+ n, err := f.log.Write(f.logBufferArray[:f.logBufferN])
+ // Flush buffer, regardless of status returned from write
+ f.logBufferN = 0
+ if err != nil {
+ return len(data), nil
+ }
+ return n, err
+ }
+ return len(data), nil
+}
+
+// WriteAt implements FDIO for Logger.
+func (f *Logger) WriteAt(data []byte, off int64) (int, error) {
+ return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// Seek implements FDIO for Logger.
+func (f *Logger) Seek(offset int64, whence int) (int64, error) {
+ return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// Truncate implements FDIO for Logger.
+func (f *Logger) Truncate(length uint64) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// Open implements FDIO for Logger.
+func (f *Logger) Open(path string, flags uint32, mode uint32) (FDIO, error) {
+ return nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// Link implements FDIO for Logger.
+func (f *Logger) Link(oldpath, newpath string) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// Rename implements FDIO for Logger.
+func (f *Logger) Rename(oldpath, newpath string) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// Unlink implements FDIO for Logger.
+func (f *Logger) Unlink(path string) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// ReadDirents implements FDIO for Logger.
+func (f *Logger) ReadDirents(max uint64) ([]byte, error) {
+ return nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// Rewind implements FDIO for Logger.
+func (f *Logger) Rewind() error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
diff --git a/src/syscall/zx/fdio/message.go b/src/syscall/zx/fdio/message.go
new file mode 100644
index 0000000..f5c55a3
--- /dev/null
+++ b/src/syscall/zx/fdio/message.go
@@ -0,0 +1,74 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package fdio
+
+const (
+ OpFlagOneHandle = uint32(0x100 + iota)
+ OpFlagTwoHandles
+ OpFlagThreeHandles
+)
+
+// Values for op. Each one will signify a request for a different operation.
+const (
+ _ = uint32(iota)
+ OpClose
+ OpClone = uint32(iota) | OpFlagOneHandle
+ OpOpen = uint32(iota) | OpFlagOneHandle
+ OpMisc = uint32(iota)
+ OpRead
+ OpWrite
+ OpSeek
+ OpStat
+ OpReaddir
+ OpIoctl
+ OpUnlink
+ OpReadAt
+ OpWriteAt
+ OpTruncate
+ OpRename = uint32(iota) | OpFlagOneHandle
+ OpConnect = uint32(iota)
+ OpBind
+ OpListen
+ OpGetSockname
+ OpGetPeerName
+ OpGetSockOpt
+ OpSetSockOpt
+ OpGetAddrInfo
+ OpSetAttr
+ OpSync
+ OpLink = uint32(iota) | OpFlagOneHandle
+ OpMmap = uint32(iota)
+ OpFcntl
+ OpAccept
+ OpNumOps = uint32(iota) // The total number of operations
+)
+
+// Control ordinal operations. Sent from server to client without
+// necessarily having an accompanying request message.
+const (
+ OpOnOpen = uint32(0x80000007)
+)
+
+const (
+ OpenFlagDescribe = 0x00800000
+)
+
+const (
+ OpOpenFlagReadable = 1
+ OpOpenFlagWritable = 2
+ OpOpenFlagRDWR = OpOpenFlagReadable | OpOpenFlagWritable
+)
+
+// Ops which correspond to a previously listed operation, but have a different number of handles
+const (
+ OpIoctlOneHandle = OpIoctl | OpFlagOneHandle
+)
+
+const (
+ OpFcntlCmdGetFL = uint32(iota + 3)
+ OpFcntlCmdSetFL
+)
diff --git a/src/syscall/zx/fdio/mxc/mxc.go b/src/syscall/zx/fdio/mxc/mxc.go
new file mode 100644
index 0000000..5997cbfa
--- /dev/null
+++ b/src/syscall/zx/fdio/mxc/mxc.go
@@ -0,0 +1,19 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package mxc
+
+import "syscall"
+
+func ExtractCFDIO(fd int) (uintptr, error) {
+ // Extract the 'C' fdio
+ f, err := transferFDIOFromCFD(fd)
+ if err != nil {
+ return 0, err
+ }
+ // Convert it to a 'Go' fdio
+ return uintptr(syscall.OpenFDIO(f)), nil
+}
diff --git a/src/syscall/zx/fdio/mxc/mxc_cgo.go b/src/syscall/zx/fdio/mxc/mxc_cgo.go
new file mode 100644
index 0000000..dd6795c
--- /dev/null
+++ b/src/syscall/zx/fdio/mxc/mxc_cgo.go
@@ -0,0 +1,59 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+// +build cgo
+
+package mxc
+
+// #cgo fuchsia LDFLAGS: -lfdio
+// #include <zircon/types.h>
+// #include <zircon/syscalls.h>
+// #include <stdlib.h>
+// #include <lib/fdio/util.h>
+import "C"
+import (
+ "errors"
+ "syscall/zx"
+ "syscall/zx/fdio"
+ "syscall/zx/fidl"
+ "syscall/zx/io"
+)
+
+func transferFDIOFromCFD(fd int) (fdio.FDIO, error) {
+ handlesC := make([]C.zx_handle_t, fdio.MaxUnderlyingHandles)
+ typesC := make([]C.uint32_t, fdio.MaxUnderlyingHandles)
+ status := C.fdio_transfer_fd(C.int(fd), 0, (*C.zx_handle_t)(&handlesC[0]), (*C.uint32_t)(&typesC[0]))
+ if status < 0 {
+ return nil, zx.Error{Status: zx.Status(status), Text: "mxc"}
+ } else if status == 0 || fdio.MaxUnderlyingHandles < status {
+ return nil, errors.New("Invalid handle from fdio_transfer_fd")
+ }
+ handles := make([]zx.Handle, int(status))
+ for i := 0; i < int(status); i++ {
+ handles[i] = zx.Handle(handlesC[i])
+ }
+ switch zx.HandleInfo(typesC[0]).Type() {
+ case fdio.HandleTypeRemote:
+ obj := (*io.ObjectInterface)(&fidl.Proxy{Channel: zx.Channel(handles[0])})
+ if len(handles) > 1 {
+ for _, h := range handles[1:] {
+ h.Close()
+ }
+ }
+ return &fdio.File{Node: fdio.Node{Object: fdio.Object{obj}}}, nil
+ case fdio.HandleTypePipe:
+ if len(handles) > 1 {
+ for _, h := range handles[1:] {
+ h.Close()
+ }
+ }
+ return fdio.NewPipe(zx.Socket(handles[0])), nil
+ default:
+ for _, h := range handles {
+ h.Close()
+ }
+ return nil, errors.New("Unexpected C handle type")
+ }
+}
diff --git a/src/syscall/zx/fdio/mxc/mxc_no_cgo.go b/src/syscall/zx/fdio/mxc/mxc_no_cgo.go
new file mode 100644
index 0000000..ef30d35
--- /dev/null
+++ b/src/syscall/zx/fdio/mxc/mxc_no_cgo.go
@@ -0,0 +1,17 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+// +build !cgo
+
+package mxc
+
+import (
+ "syscall/zx"
+ "syscall/zx/fdio"
+)
+
+func transferFDIOFromCFD(fd int) (fdio.FDIO, error) {
+ return nil, zx.ErrNotSupported
+}
diff --git a/src/syscall/zx/fdio/namespace.go b/src/syscall/zx/fdio/namespace.go
new file mode 100644
index 0000000..7dbf635
--- /dev/null
+++ b/src/syscall/zx/fdio/namespace.go
@@ -0,0 +1,391 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package fdio
+
+import (
+ "path"
+ "strings"
+ "sync"
+ "syscall/zx"
+ "syscall/zx/fidl"
+ "syscall/zx/io"
+)
+
+func splitPath(path string) (name string, remaining string) {
+ slash := strings.IndexByte(path, '/')
+ if slash == 0 || slash == len(path)-1 {
+ return "", ""
+ } else if slash == -1 {
+ return path, ""
+ } else {
+ return path[:slash], path[slash+1:]
+ }
+}
+
+type NS struct {
+ mu sync.Mutex
+ m map[string]zx.Handle
+}
+
+func NewNS() *NS {
+ return &NS{m: make(map[string]zx.Handle)}
+}
+
+func NewNSFromMap(m map[string]zx.Handle) (*NS, error) {
+ if m == nil {
+ return nil, zx.Error{Status: zx.ErrInvalidArgs, Text: "namespace.NewFromNSMAP"}
+ }
+ ns := &NS{m: make(map[string]zx.Handle)}
+ for k, v := range m {
+ ns.m[k] = v
+ }
+ return ns, nil
+}
+
+func (ns *NS) Bind(p string, h zx.Handle) {
+ ns.mu.Lock()
+ ns.m[p] = h
+ ns.mu.Unlock()
+}
+
+func (ns *NS) Connect(p string, h zx.Handle) error {
+ if p[0] != '/' {
+ h.Close()
+ return zx.Error{Status: zx.ErrNotFound, Text: "namespace.Connect"}
+ }
+ node := p
+ for {
+ ns.mu.Lock()
+ svcHandle := ns.m[node]
+ ns.mu.Unlock()
+ if svcHandle.IsValid() {
+ rest := strings.TrimPrefix(p, node)
+ rest = strings.TrimPrefix(rest, "/")
+ return ServiceConnectAt(svcHandle, rest, h)
+ }
+ if node == "/" {
+ break
+ }
+ node = path.Dir(node)
+ }
+ h.Close()
+ return zx.Error{Status: zx.ErrNotFound, Text: "namespace.Connect"}
+}
+
+func (ns *NS) OpenRoot() (FDIO, error) {
+ root := &vnode{}
+ ns.mu.Lock()
+ defer ns.mu.Unlock()
+ for path, h := range ns.m {
+ if path == "" || path[0] != '/' {
+ return nil, zx.Error{Status: zx.ErrBadPath, Text: "fdio.OpenRoot"}
+ }
+ vn := root
+ path = path[1:]
+ for path != "" {
+ name, remaining := splitPath(path)
+ vn = vn.getOrAddChild(name)
+ path = remaining
+ }
+ if vn.remote.IsValid() {
+ return nil, zx.Error{Status: zx.ErrAlreadyExists, Text: "fdio.OpenRoot"}
+ }
+ obj := (*io.ObjectInterface)(&fidl.Proxy{Channel: zx.Channel(h)})
+ vn.remote = Directory{Node: Node{Object: Object{obj}}}
+ }
+ return &dir{root}, nil
+}
+
+// vnode is a virtual node in the namespace "filesystem".
+type vnode struct {
+ child *vnode
+ parent *vnode
+ next *vnode
+ remote Directory
+ name string
+}
+
+func (vn *vnode) getOrAddChild(name string) *vnode {
+ child := vn.getChild(name)
+ if child == nil {
+ child = &vnode{
+ parent: vn,
+ next: vn.child,
+ name: name,
+ }
+ vn.child = child
+ }
+ return child
+}
+
+func (vn *vnode) getChild(name string) *vnode {
+ for vn = vn.child; vn != nil; vn = vn.next {
+ if vn.name == name {
+ return vn
+ }
+ }
+ return nil
+}
+
+// dir represents a directory in the namespace.
+type dir struct {
+ vn *vnode
+}
+
+// Handle returns the underlying handle as an untyped handle.
+func (d *dir) Handles() []zx.Handle {
+ return d.vn.remote.Handles()
+}
+
+// Clone makes a clone of the dir, if possible.
+func (d *dir) Clone() (FDIO, error) {
+ if !d.vn.remote.IsValid() {
+ return nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.ns.dir"}
+ }
+ return d.vn.remote.Clone()
+}
+
+// Close closes the dir.
+func (d *dir) Close() error {
+ return d.vn.remote.Close()
+}
+
+// Sync implements FDIO for dir.
+func (d *dir) Sync() error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.ns.dir"}
+}
+
+// GetAttr implements FDIO for dir.
+func (d *dir) GetAttr() (io.NodeAttributes, error) {
+ return io.NodeAttributes{
+ Mode: uint32(io.KModeTypeDirectory) | uint32(VtypeIRUSR),
+ Id: 1,
+ LinkCount: 1,
+ }, nil
+}
+
+// SetAttr implements FDIO for dir.
+func (d *dir) SetAttr(flags uint32, attr io.NodeAttributes) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.ns.dir"}
+}
+
+// Ioctl implements FDIO for dir.
+func (d *dir) Ioctl(op uint32, max uint64, in []byte, handles []zx.Handle) ([]byte, []zx.Handle, error) {
+ return nil, nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.ns.dir"}
+}
+
+func (d *dir) Read(data []byte) (int, error) {
+ return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.dir"}
+}
+
+func (d *dir) ReadAt(data []byte, off int64) (int, error) {
+ return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.dir"}
+}
+
+func (d *dir) Write(data []byte) (n int, err error) {
+ return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.dir"}
+}
+
+func (d *dir) WriteAt(data []byte, off int64) (int, error) {
+ return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.dir"}
+}
+
+func (d *dir) Seek(offset int64, whence int) (int64, error) {
+ return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.dir"}
+}
+
+// Truncate implements FDIO for dir.
+func (d *dir) Truncate(length uint64) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.ns.dir"}
+}
+
+func (d *dir) getVnode(path string) (vn *vnode, rpath string, isRemote bool, err error) {
+ vn = d.vn
+
+ if path == "." || path == "" {
+ if vn.remote.IsValid() {
+ return vn, ".", true, nil
+ }
+ return vn, "", false, nil
+ }
+
+ originalPath := path
+
+ var savedVn *vnode
+ var savedPath string
+
+ for {
+ name, remaining := splitPath(path)
+
+ if name == "" {
+ return nil, "", false, zx.Error{Status: zx.ErrBadPath, Text: path}
+ }
+
+ child := vn.getChild(name)
+
+ if child != nil {
+ if remaining == "" {
+ // We've resolved all the path segments and found the vnode we're
+ // looking for.
+ if child.remote.IsValid() {
+ return child, ".", true, nil
+ } else {
+ return child, "", false, nil
+ }
+ } else {
+ // We've got more path to resolve.
+ vn = child
+ path = remaining
+
+ // If this child has a remote file system, we might hand off to
+ // this remote if we don't find anything more specific below
+ // this vnode.
+ if child.remote.IsValid() {
+ savedVn = vn
+ savedPath = path
+ }
+
+ continue
+ }
+ }
+
+ // We've reached the end of our local vnode structure with more
+ // path to resolve.
+
+ if vn.remote.IsValid() {
+ // We've got a remote file system at this vnode. We can hand off
+ // directly to that file system.
+ return vn, path, true, nil
+ }
+
+ // We saw a remote file system earlier in our walk that might have this
+ // path. Let's hand off to it.
+ if savedVn != nil {
+ return savedVn, savedPath, true, nil
+ }
+
+ // There is no remote file system to resolve the path against,
+ // which means we failed to find what we were looking for.
+ return nil, "", false, zx.Error{Status: zx.ErrNotFound, Text: originalPath}
+ }
+}
+
+// Open implements FDIO for dir.
+func (d *dir) Open(pathname string, flags uint32, mode uint32) (FDIO, error) {
+ vn, relp, isRemote, err := d.getVnode(pathname)
+ if err != nil {
+ return nil, err
+ }
+ if isRemote {
+ return vn.remote.Open(relp, flags, mode)
+ }
+ return &dir{vn}, nil
+}
+
+func (d *dir) openParent(pathname string) (FDIO, string, error) {
+ dirpath, name := path.Split(pathname)
+ parent, err := d.Open(path.Dir(dirpath), io.KOpenRightReadable, io.KOpenFlagDirectory)
+ if err != nil {
+ return nil, "", err
+ }
+ return parent, name, err
+}
+
+// Link implements FDIO for dir.
+func (d *dir) Link(oldpath, newpath string) error {
+ oldparent, oldname, err := d.openParent(oldpath)
+ if err != nil {
+ return err
+ }
+ defer oldparent.Close()
+ newparent, newname, err := d.openParent(newpath)
+ if err != nil {
+ return err
+ }
+ defer newparent.Close()
+ olddir, ok := oldparent.(*Directory)
+ if !ok {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.ns.dir"}
+ }
+ newdir, ok := newparent.(*Directory)
+ if !ok {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.ns.dir"}
+ }
+ token, err := newdir.getToken()
+ if err != nil {
+ return err
+ }
+ status, err := olddir.DirectoryInterface().Link(oldname, token, newname)
+ if err != nil {
+ return err
+ } else if status != zx.ErrOk {
+ return zx.Error{Status: status, Text: "fdio.ns.dir"}
+ }
+ return nil
+}
+
+// Rename implements FDIO for dir.
+func (d *dir) Rename(oldpath, newpath string) error {
+ oldf, oldname, err := d.openParent(oldpath)
+ if err != nil {
+ return err
+ }
+ defer oldf.Close()
+ newf, newname, err := d.openParent(newpath)
+ if err != nil {
+ return err
+ }
+ defer newf.Close()
+ olddir, ok := oldf.(*Directory)
+ if !ok {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.ns.dir"}
+ }
+ newdir, ok := newf.(*Directory)
+ if !ok {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.ns.dir"}
+ }
+ token, err := newdir.getToken()
+ if err != nil {
+ return err
+ }
+ status, err := olddir.DirectoryInterface().Rename(oldname, token, newname)
+ if err != nil {
+ return err
+ } else if status != zx.ErrOk {
+ return zx.Error{Status: status, Text: "fdio.ns.dir"}
+ }
+ return nil
+}
+
+// Unlink implements FDIO for dir.
+func (d *dir) Unlink(pathname string) error {
+ parent, name, err := d.openParent(pathname)
+ if err != nil {
+ return err
+ }
+ defer parent.Close()
+ parentdir, ok := parent.(*Directory)
+ if !ok {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.ns.dir"}
+ }
+ if status, err := parentdir.DirectoryInterface().Unlink(name); err != nil {
+ return err
+ } else if status != zx.ErrOk {
+ return zx.Error{Status: status, Text: "fdio.ns.dir"}
+ }
+ return nil
+}
+
+// ReadDirents implements FDIO for dir.
+func (d *dir) ReadDirents(max uint64) ([]byte, error) {
+ return nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.ns.dir"}
+}
+
+// Rewind implements FDIO for dir.
+func (d *dir) Rewind() error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.ns.dir"}
+}
diff --git a/src/syscall/zx/fdio/node.go b/src/syscall/zx/fdio/node.go
new file mode 100644
index 0000000..5bdca5b
--- /dev/null
+++ b/src/syscall/zx/fdio/node.go
@@ -0,0 +1,64 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package fdio
+
+import (
+ "syscall/zx"
+ "syscall/zx/io"
+)
+
+// Node is a wrapper around a NodeInterface which implements FDIO.
+type Node struct {
+ Object
+}
+
+// NodeInterface returns the underlying Node FIDL interface.
+func (n *Node) NodeInterface() (*io.NodeInterface) {
+ return (*io.NodeInterface)(n.Object.ObjectInterface)
+}
+
+// Sync performs a sync operation on a Node.
+func (n *Node) Sync() error {
+ if status, err := n.NodeInterface().Sync(); err != nil {
+ return err
+ } else if status != zx.ErrOk {
+ return zx.Error{Status: status, Text: "io.node"}
+ }
+ return nil
+}
+
+// GetAttr returns the attributes for the Node.
+func (n *Node) GetAttr() (io.NodeAttributes, error) {
+ status, attrs, err := n.NodeInterface().GetAttr()
+ if err != nil {
+ return io.NodeAttributes{}, err
+ } else if status != zx.ErrOk {
+ return io.NodeAttributes{}, zx.Error{Status: status, Text: "io.node"}
+ }
+ return attrs, nil
+}
+
+// SetAttr sets the attributes for Node as defined by flags.
+func (n *Node) SetAttr(flags uint32, attr io.NodeAttributes) error {
+ if status, err := n.NodeInterface().SetAttr(flags, attr); err != nil {
+ return err
+ } else if status != zx.ErrOk {
+ return zx.Error{Status: status, Text: "io.node"}
+ }
+ return nil
+}
+
+// Ioctl calls an ioctl on Node.
+func (n *Node) Ioctl(op uint32, max uint64, in []byte, handles []zx.Handle) ([]byte, []zx.Handle, error) {
+ status, h, b, err := n.NodeInterface().Ioctl(op, max, handles, in)
+ if err != nil {
+ return nil, nil, err
+ } else if status != zx.ErrOk {
+ return nil, nil, zx.Error{Status: status, Text: "io.node"}
+ }
+ return b, h, nil
+}
diff --git a/src/syscall/zx/fdio/object.go b/src/syscall/zx/fdio/object.go
new file mode 100644
index 0000000..6e41440
--- /dev/null
+++ b/src/syscall/zx/fdio/object.go
@@ -0,0 +1,179 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package fdio
+
+import (
+ "syscall/zx"
+ "syscall/zx/fidl"
+ "syscall/zx/io"
+)
+
+func objectFromInfo(info *io.ObjectInfo, obj *io.ObjectInterface) (result FDIO, err error) {
+ if info == nil {
+ return nil, zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+ }
+ switch info.ObjectInfoTag {
+ case io.ObjectInfoService:
+ // TODO(mknyszek): Figure out the correct type to return here.
+ result = &Object{ObjectInterface: obj}
+ case io.ObjectInfoFile:
+ result = &File{
+ Node: Node{Object: Object{ObjectInterface: obj}},
+ Event: info.File.Event,
+ }
+ case io.ObjectInfoDevice:
+ result = &File{
+ Node: Node{Object: Object{ObjectInterface: obj}},
+ Event: info.Device.Event,
+ }
+ case io.ObjectInfoDirectory:
+ result = &Directory{Node: Node{Object: Object{ObjectInterface: obj}}}
+ case io.ObjectInfoPipe:
+ result = NewPipe(info.Pipe.Socket)
+ case io.ObjectInfoVmofile:
+ result, err = NewVMOFile(
+ info.Vmofile.Vmo,
+ info.Vmofile.Offset,
+ info.Vmofile.Length,
+ )
+ if err != nil {
+ return nil, err
+ }
+ default:
+ return nil, zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+ }
+ return result, nil
+}
+
+// Object is a wrapper around an ObjectInterface which implements FDIO.
+type Object struct {
+ *io.ObjectInterface
+}
+
+// IsValid returns true if the Object is valid.
+func (o *Object) IsValid() bool {
+ if o.ObjectInterface == nil {
+ return false
+ }
+ return ((*fidl.Proxy)(o.ObjectInterface)).IsValid()
+}
+
+// Handle returns the underlying channel as an untyped zx handle.
+func (o *Object) Handles() []zx.Handle {
+ return []zx.Handle{
+ zx.Handle(((*fidl.Proxy)(o.ObjectInterface)).Channel),
+ }
+}
+
+// Clone makes a clone of the object.
+func (o *Object) Clone() (FDIO, error) {
+ req, newObj, err := io.NewObjectInterfaceRequest()
+ if err != nil {
+ return nil, err
+ }
+ if err := o.ObjectInterface.Clone(io.KOpenFlagDescribe, req); err != nil {
+ return nil, err
+ }
+ status, info, err := newObj.ExpectOnOpen()
+ if err != nil {
+ return nil, err
+ } else if status != zx.ErrOk {
+ return nil, zx.Error{Status: status, Text: "io.object"}
+ }
+ return objectFromInfo(info, newObj)
+}
+
+// Close closes the object.
+func (o *Object) Close() error {
+ defer ((*fidl.Proxy)(o.ObjectInterface)).Close()
+ if status, err := o.ObjectInterface.Close(); err != nil {
+ return err
+ } else if status != zx.ErrOk {
+ return zx.Error{Status: status, Text: "io.object"}
+ }
+ return nil
+}
+
+// Sync implements FDIO for Object.
+func (o *Object) Sync() error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// GetAttr implements FDIO for Object.
+func (o *Object) GetAttr() (io.NodeAttributes, error) {
+ return io.NodeAttributes{}, zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// SetAttr implements FDIO for Object.
+func (o *Object) SetAttr(flags uint32, attr io.NodeAttributes) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// Ioctl implements FDIO for Object.
+func (o *Object) Ioctl(op uint32, max uint64, in []byte, handles []zx.Handle) ([]byte, []zx.Handle, error) {
+ return nil, nil, zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// Read implements FDIO for Object.
+func (o *Object) Read(data []byte) (int, error) {
+ return 0, zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// ReadAt implements FDIO for Object.
+func (o *Object) ReadAt(data []byte, off int64) (int, error) {
+ return 0, zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// Write implements FDIO for Object.
+func (o *Object) Write(data []byte) (int, error) {
+ return 0, zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// WriteAt implements FDIO for Object.
+func (o *Object) WriteAt(data []byte, off int64) (int, error) {
+ return 0, zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// Seek implements FDIO for Object.
+func (o *Object) Seek(offset int64, whence int) (int64, error) {
+ return 0, zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// Truncate implements FDIO for Object.
+func (o *Object) Truncate(length uint64) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// Open implements FDIO for Object.
+func (o *Object) Open(path string, flags uint32, mode uint32) (FDIO, error) {
+ return nil, zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// Link implements FDIO for Object.
+func (o *Object) Link(oldpath, newpath string) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// Rename implements FDIO for Object.
+func (o *Object) Rename(oldpath, newpath string) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// Unlink implements FDIO for Object.
+func (o *Object) Unlink(path string) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// ReadDirents implements FDIO for Object.
+func (o *Object) ReadDirents(max uint64) ([]byte, error) {
+ return nil, zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// Rewind implements FDIO for Object.
+func (o *Object) Rewind() error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
diff --git a/src/syscall/zx/fdio/pipe.go b/src/syscall/zx/fdio/pipe.go
new file mode 100644
index 0000000..139a642
--- /dev/null
+++ b/src/syscall/zx/fdio/pipe.go
@@ -0,0 +1,172 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package fdio
+
+import (
+ "syscall/zx"
+ "syscall/zx/io"
+ "syscall/zx/zxwait"
+)
+
+type Pipe struct {
+ s zx.Socket
+}
+
+func NewPipes() (*Pipe, *Pipe, error) {
+ s0, s1, err := zx.NewSocket(0)
+ if err != nil {
+ return nil, nil, err
+ }
+ return &Pipe{s0}, &Pipe{s1}, nil
+}
+
+func NewPipe(s zx.Socket) *Pipe {
+ return &Pipe{s}
+}
+
+func (f *Pipe) Wait(signals zx.Signals, timeout zx.Time) (observed zx.Signals, err error) {
+ return zxwait.Wait(zx.Handle(f.s), signals, timeout)
+}
+
+func (f *Pipe) Handles() []zx.Handle {
+ return []zx.Handle{zx.Handle(f.s)}
+}
+
+func (f *Pipe) Clone() (FDIO, error) {
+ h, err := f.s.Handle().Duplicate(zx.RightSameRights)
+ if err != nil {
+ return nil, err
+ }
+ return NewPipe(zx.Socket(h)), nil
+}
+
+func (f *Pipe) Close() error {
+ if err := f.s.Close(); err != nil {
+ return err
+ }
+ f.s = zx.Socket(zx.HandleInvalid)
+ return nil
+}
+
+func (f *Pipe) Sync() error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) GetAttr() (io.NodeAttributes, error) {
+ return io.NodeAttributes{}, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) SetAttr(flags uint32, attr io.NodeAttributes) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) Ioctl(op uint32, max uint64, in []byte, handles []zx.Handle) ([]byte, []zx.Handle, error) {
+ return nil, nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) Read(data []byte) (n int, err error) {
+ for {
+ n, err = f.s.Read(data, 0)
+ if err == nil {
+ return n, nil
+ }
+ mxerr, ok := err.(zx.Error)
+ if !ok {
+ return n, err
+ }
+ switch mxerr.Status {
+ case zx.ErrPeerClosed:
+ return 0, zx.EOF
+ case zx.ErrShouldWait:
+ pending, err := f.Wait(zx.SignalSocketReadable|zx.SignalSocketPeerClosed, zx.TimensecInfinite)
+ if err != nil {
+ return 0, err
+ }
+ if pending&zx.SignalSocketReadable != 0 {
+ continue
+ }
+ if pending&zx.SignalSocketPeerClosed != 0 {
+ return 0, zx.EOF
+ }
+ // impossible
+ return 0, zx.Error{Status: zx.ErrInternal, Text: "fdio.Pipe"}
+ }
+ return 0, err
+ }
+}
+
+func (f *Pipe) ReadAt(data []byte, off int64) (int, error) {
+ return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) Write(data []byte) (n int, err error) {
+ for {
+ n, err = f.s.Write(data, 0)
+ if err == nil {
+ return n, nil
+ }
+ mxerr, ok := err.(zx.Error)
+ if !ok {
+ return n, err
+ }
+ switch mxerr.Status {
+ case zx.ErrPeerClosed:
+ return 0, zx.EOF
+ return 0, zx.EPIPE
+ case zx.ErrShouldWait:
+ pending, err := f.Wait(zx.SignalSocketWritable|zx.SignalSocketPeerClosed, zx.TimensecInfinite)
+ if err != nil {
+ return 0, err
+ }
+ if pending&zx.SignalSocketWritable != 0 {
+ continue
+ }
+ if pending&zx.SignalSocketPeerClosed != 0 {
+ return 0, zx.EPIPE
+ }
+ // impossible
+ return 0, zx.Error{Status: zx.ErrInternal, Text: "fdio.Pipe"}
+ }
+ return 0, err
+ }
+}
+
+func (f *Pipe) WriteAt(data []byte, off int64) (int, error) {
+ return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) Seek(offset int64, whence int) (int64, error) {
+ return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) Truncate(length uint64) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) Open(path string, flags uint32, mode uint32) (FDIO, error) {
+ return nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) Link(oldpath, newpath string) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) Rename(oldpath, newpath string) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) Unlink(path string) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) ReadDirents(max uint64) ([]byte, error) {
+ return nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) Rewind() error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
diff --git a/src/syscall/zx/fdio/vmo.go b/src/syscall/zx/fdio/vmo.go
new file mode 100644
index 0000000..d51094a
--- /dev/null
+++ b/src/syscall/zx/fdio/vmo.go
@@ -0,0 +1,161 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package fdio
+
+import (
+ "syscall/zx"
+ "syscall/zx/io"
+)
+
+type VMOFile struct {
+ h zx.VMO
+ off int64
+ len int64
+ end int64
+ at int64
+}
+
+func NewVMOFile(handle zx.VMO, offset uint64, length uint64) (*VMOFile, error) {
+ // fdio_vmofile_create
+ f := &VMOFile{
+ h: handle,
+ off: int64(offset),
+ len: int64(length),
+ }
+ f.end = f.off + f.len
+ f.at = f.off
+ return f, nil
+}
+
+func (f *VMOFile) Handles() []zx.Handle {
+ return []zx.Handle{zx.Handle(f.h)}
+}
+
+func (f *VMOFile) Clone() (FDIO, error) {
+ return nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
+
+func (f *VMOFile) Close() error {
+ if err := f.h.Close(); err != nil {
+ return err
+ }
+ f.h = 0
+ return nil
+}
+
+func (f *VMOFile) Sync() error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
+
+func (f *VMOFile) GetAttr() (io.NodeAttributes, error) {
+ return io.NodeAttributes{
+ ContentSize: uint64(f.len),
+ StorageSize: uint64(f.len),
+ Mode: uint32(io.KModeTypeFile) | uint32(VtypeIRUSR),
+ }, nil
+}
+
+func (f *VMOFile) SetAttr(flags uint32, attr io.NodeAttributes) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
+
+func (f *VMOFile) Ioctl(op uint32, max uint64, in []byte, handles []zx.Handle) ([]byte, []zx.Handle, error) {
+ return nil, nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
+
+func (f *VMOFile) Read(data []byte) (n int, err error) {
+ if int64(len(data)) > f.end-f.at {
+ data = data[:f.end-f.at]
+ err = zx.EOF
+ }
+ if len(data) == 0 {
+ return 0, err
+ }
+ if err2 := f.h.Read(data, uint64(f.at)); err2 != nil {
+ return 0, err2
+ }
+ n = len(data)
+ f.at += int64(n)
+ return
+}
+
+func (f *VMOFile) ReadAt(data []byte, off int64) (n int, err error) {
+ if off < 0 {
+ return 0, zx.Error{Status: zx.ErrInvalidArgs, Text: "fdio.VMOFile.ReadAt"}
+ }
+ if off >= f.end {
+ return 0, zx.EOF
+ }
+ if len(data) == 0 {
+ return 0, zx.EOF
+ }
+ n = len(data)
+ max := int(f.end - off)
+ if max < n {
+ n = max
+ err = zx.EOF
+ }
+ data = data[:n]
+ if err2 := f.h.Read(data, uint64(off)); err2 != nil {
+ return 0, err2
+ }
+ return
+}
+
+func (f *VMOFile) Write(data []byte) (int, error) {
+ return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
+
+func (f *VMOFile) WriteAt(data []byte, off int64) (int, error) {
+ return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
+
+func (f *VMOFile) Seek(offset int64, whence int) (int64, error) {
+ var at int64
+ switch whence {
+ case 0: // SEEK_SET
+ at = offset
+ case 1: // SEEK_CUR
+ at = f.at - f.off + offset
+ case 2: // SEEK_END
+ at = f.end - f.off + offset
+ }
+
+ if at > f.end-f.off {
+ return 0, zx.Error{Status: zx.ErrOutOfRange, Text: "fdio.VMOFile"}
+ }
+ f.at = f.off + at
+ return at, nil
+}
+
+func (f *VMOFile) Truncate(length uint64) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
+
+func (f *VMOFile) Open(path string, flags uint32, mode uint32) (FDIO, error) {
+ return nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
+
+func (f *VMOFile) Link(oldpath, newpath string) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
+
+func (f *VMOFile) Rename(oldpath, newpath string) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
+
+func (f *VMOFile) Unlink(path string) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
+
+func (f *VMOFile) ReadDirents(max uint64) ([]byte, error) {
+ return nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
+
+func (f *VMOFile) Rewind() error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
diff --git a/src/syscall/zx/fidl/bindings.go b/src/syscall/zx/fidl/bindings.go
new file mode 100644
index 0000000..f1e5c83
--- /dev/null
+++ b/src/syscall/zx/fidl/bindings.go
@@ -0,0 +1,306 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package fidl
+
+import (
+ "sync"
+ "syscall/zx"
+ "syscall/zx/dispatch"
+)
+
+const prefix = "zx/fidl: "
+
+// d is a process-local dispatcher.
+var d *dispatch.Dispatcher
+
+func init() {
+ disp, err := dispatch.NewDispatcher()
+ if err != nil {
+ panic(prefix + "failed to create dispatcher: " + err.Error())
+ }
+ d = disp
+}
+
+// Serve is a blocking call to the process-local dispatcher's serve method.
+func Serve() {
+ d.Serve()
+}
+
+type bindingState int32
+
+const (
+ idle bindingState = iota
+ handling
+ cleanup
+)
+
+// Binding binds the implementation of a Stub to a Channel.
+//
+// A Binding listens for incoming messages on the Channel, decodes them, and
+// asks the Stub to dispatch to the appropriate implementation of the interface.
+// If the message expects a reply, the Binding will also encode the reply and
+// send it back over the Channel.
+type Binding struct {
+ // Stub is a wrapper around an implementation of a FIDL interface which
+ // knows how to dispatch to a method by ordinal.
+ Stub Stub
+
+ // Channel is the Channel primitive to which the Stub is bound.
+ Channel zx.Channel
+
+ // id is an identifier for this waiter in the process-local dispatcher.
+ id *dispatch.WaitID
+
+ // errHandler is called with connection errors, when encountered.
+ errHandler func(error)
+
+ // handling is an atomically-updated signal which represents the state of the
+ // binding.
+ stateMu sync.Mutex
+ state bindingState
+}
+
+// Init initializes a Binding.
+func (b *Binding) Init(errHandler func(error)) error {
+ // Declare the wait handler as a closure.
+ h := func(d *dispatch.Dispatcher, s zx.Status, sigs *zx.PacketSignal) (result dispatch.WaitResult) {
+ b.stateMu.Lock()
+ if b.state == cleanup {
+ b.close()
+ b.stateMu.Unlock()
+ return dispatch.WaitFinished
+ }
+ b.state = handling
+ b.stateMu.Unlock()
+ defer func() {
+ b.stateMu.Lock()
+ defer b.stateMu.Unlock()
+ if b.state == cleanup {
+ b.close()
+ result = dispatch.WaitFinished
+ }
+ b.state = idle
+ }()
+ if s != zx.ErrOk {
+ b.errHandler(zx.Error{Status: s})
+ return dispatch.WaitFinished
+ }
+ if sigs.Observed&zx.SignalChannelReadable != 0 {
+ for i := uint64(0); i < sigs.Count; i++ {
+ shouldWait, err := b.dispatch()
+ if err != nil {
+ b.errHandler(err)
+ return dispatch.WaitFinished
+ }
+ if shouldWait {
+ return dispatch.WaitAgain
+ }
+ }
+ return dispatch.WaitAgain
+ }
+ b.errHandler(zx.Error{Status: zx.ErrPeerClosed})
+ return dispatch.WaitFinished
+ }
+
+ b.stateMu.Lock()
+ b.state = idle
+ b.stateMu.Unlock()
+
+ b.errHandler = errHandler
+
+ // Start the wait on the Channel.
+ id, err := d.BeginWait(
+ zx.Handle(b.Channel),
+ zx.SignalChannelReadable|zx.SignalChannelPeerClosed,
+ 0,
+ h,
+ )
+ if err != nil {
+ return err
+ }
+ b.id = &id
+ return nil
+}
+
+// dispatch reads from the underlying Channel and dispatches into the Stub.
+//
+// Returns true if the channel should be waited, or false if there is more data to be read.
+func (b *Binding) dispatch() (shouldWait bool, err error) {
+ respb := messageBytesPool.Get().([]byte)
+ resph := messageHandlesPool.Get().([]zx.Handle)
+
+ defer messageBytesPool.Put(respb)
+ defer messageHandlesPool.Put(resph)
+
+ nb, nh, err := b.Channel.Read(respb[:], resph[:], 0)
+ if err != nil {
+ zxErr, ok := err.(zx.Error)
+ if ok && zxErr.Status == zx.ErrShouldWait {
+ return true, nil
+ }
+ return false, err
+ }
+ var header MessageHeader
+ if err := UnmarshalHeader(respb[:], &header); err != nil {
+ return false, err
+ }
+ start := MessageHeaderSize
+ p, err := b.Stub.Dispatch(header.Ordinal, respb[start:int(nb)], resph[:nh])
+ switch {
+ case err == ErrUnknownOrdinal:
+ // If we couldn't determine the ordinal, we still own the
+ // handles, so we should close them all.
+ for _, h := range resph[:nh] {
+ h.Close()
+ }
+ fallthrough
+ case err != nil:
+ return false, err
+ }
+ // Message has no response.
+ if p == nil {
+ return false, nil
+ }
+ cnb, cnh, err := MarshalMessage(&header, p, respb[:], resph[:])
+ if err != nil {
+ return false, err
+ }
+ if err := b.Channel.Write(respb[:cnb], resph[:cnh], 0); err != nil {
+ return false, err
+ }
+ return false, nil
+}
+
+// Close cancels any outstanding waits, resets the Binding's state, and closes
+// the bound Channel once any out-standing requests are finished being handled.
+func (b *Binding) Close() error {
+ b.stateMu.Lock()
+ defer b.stateMu.Unlock()
+ if zx.Handle(b.Channel) == zx.HandleInvalid || b.state == cleanup {
+ panic(prefix + "double binding close")
+ }
+ switch b.state {
+ case idle:
+ return b.close()
+ case handling:
+ b.state = cleanup
+ }
+ return nil
+}
+
+// close cancels any outstanding waits, resets the Binding's state, and
+// closes the bound Channel. This method is not thread-safe, and should be
+// called with the binding's mutex set.
+func (b *Binding) close() error {
+ if err := d.CancelWait(*b.id); err != nil {
+ zxErr, ok := err.(zx.Error)
+ // If it just says that the ID isn't found, there are cases where this is
+ // a reasonable error (particularly when we're in the middle of handling
+ // a signal from the dispatcher).
+ if !ok || zxErr.Status != zx.ErrNotFound {
+ // Attempt to close the channel if we hit a more serious error.
+ b.Channel.Close()
+ return err
+ }
+ }
+ b.id = nil
+ b.state = idle
+ return b.Channel.Close()
+}
+
+// BindingKey is a key which maps to a specific binding.
+//
+// It is only valid for the BindingSet that produced it.
+type BindingKey uint64
+
+// BindingSet is a managed set of Bindings which know how to unbind and
+// remove themselves in the event of a connection error.
+type BindingSet struct {
+ nextKey BindingKey
+ mu sync.Mutex
+ Bindings map[BindingKey]*Binding
+}
+
+// Add creates a new Binding, initializes it, and adds it to the set.
+//
+// onError is an optional handler than may be passed which will be called after
+// the binding between the Stub and the Channel is successfully closed.
+func (b *BindingSet) Add(s Stub, c zx.Channel, onError func(error)) (BindingKey, error) {
+ binding := &Binding{
+ Stub: s,
+ Channel: c,
+ }
+ b.mu.Lock()
+ defer b.mu.Unlock()
+ if b.Bindings == nil {
+ b.Bindings = make(map[BindingKey]*Binding)
+ }
+ key := b.nextKey
+ err := binding.Init(func(err error) {
+ if b.Remove(key) && onError != nil {
+ onError(err)
+ }
+ })
+ if err != nil {
+ return 0, err
+ }
+ b.Bindings[key] = binding
+ b.nextKey += 1
+ return key, nil
+}
+
+// ProxyFor returns an event proxy created from the channel of the binding referred
+// to by key.
+func (b *BindingSet) ProxyFor(key BindingKey) (*Proxy, bool) {
+ b.mu.Lock()
+ defer b.mu.Unlock()
+ if binding, ok := b.Bindings[key]; ok {
+ return &Proxy{Channel: binding.Channel}, true
+ }
+ return nil, false
+}
+
+// Remove removes a Binding from the set when it is next idle.
+//
+// Note that this method invalidates the key, and it will never remove a Binding
+// while it is actively being handled.
+//
+// Returns true if a Binding was found and removed.
+func (b *BindingSet) Remove(key BindingKey) bool {
+ b.mu.Lock()
+ if binding, ok := b.Bindings[key]; ok {
+ delete(b.Bindings, key)
+ b.mu.Unlock()
+
+ // Close the binding before calling the callback.
+ if err := binding.Close(); err != nil {
+ // Just panic. The only reason this can fail is if the handle
+ // is bad, which it shouldn't be if we're tracking things. If
+ // it does fail, better to fail fast.
+ panic(prefix + err.Error())
+ }
+ return true
+ }
+ b.mu.Unlock()
+ return false
+}
+
+// Close removes all the bindings from the set.
+func (b *BindingSet) Close() {
+ // Lock, close all the bindings, and clear the map.
+ b.mu.Lock()
+ for _, binding := range b.Bindings {
+ if err := binding.Close(); err != nil {
+ // Just panic. The only reason this can fail is if the handle
+ // is bad, which it shouldn't be if we're tracking things. If
+ // it does fail, better to fail fast.
+ panic(prefix + err.Error())
+ }
+ }
+ b.Bindings = make(map[BindingKey]*Binding)
+ b.mu.Unlock()
+}
diff --git a/src/syscall/zx/fidl/bindings_test.go b/src/syscall/zx/fidl/bindings_test.go
new file mode 100644
index 0000000..faa44b6
--- /dev/null
+++ b/src/syscall/zx/fidl/bindings_test.go
@@ -0,0 +1,84 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package fidl_test
+
+import (
+ "syscall/zx"
+ "testing"
+ "time"
+
+ . "fidl/bindings"
+ . "fuchsia/go/go_fidl_bindings_test"
+)
+
+type Test1Impl struct{}
+
+func (t *Test1Impl) Echo(s *string) (*string, error) {
+ return s, nil
+}
+
+func TestEcho(t *testing.T) {
+ t.Parallel()
+
+ ch, sh, err := zx.NewChannel(0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ client := Test1Interface(Proxy{Channel: ch})
+ server := Test1Service{}
+ clientKey, err := server.Add(&Test1Impl{}, sh, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ go Serve()
+
+ t.Run("Basic", func(t *testing.T) {
+ str := "Hello World!"
+ r, err := client.Echo(&str)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if r == nil {
+ t.Fatal("unexpected nil result")
+ }
+ if *r != str {
+ t.Fatalf("expected %s, got %s", str, *r)
+ }
+ })
+
+ t.Run("Event", func(t *testing.T) {
+ str := "Surprise!"
+ done := make(chan struct{})
+ // Spin up goroutine with waiting client.
+ go func() {
+ s, err := client.ExpectSurprise()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if s != str {
+ t.Fatalf("expected %s, got %s", str, s)
+ }
+ done <- struct{}{}
+ }()
+ // Spin up server goroutine which makes the call.
+ go func() {
+ pxy, ok := server.EventProxyFor(clientKey)
+ if !ok {
+ t.Fatalf("could not create proxy for key %d", clientKey)
+ }
+ if err := pxy.Surprise(str); err != nil {
+ t.Fatal(err)
+ }
+ }()
+ select {
+ case <-done:
+ return
+ case <-time.After(5 * time.Second):
+ t.Fatalf("test timed out")
+ }
+ })
+}
diff --git a/src/syscall/zx/fidl/bindings_test/test.fidl b/src/syscall/zx/fidl/bindings_test/test.fidl
new file mode 100644
index 0000000..cf0aeed
--- /dev/null
+++ b/src/syscall/zx/fidl/bindings_test/test.fidl
@@ -0,0 +1,145 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+library go_fidl_bindings_test;
+
+struct TestSimple {
+ int64 x;
+};
+
+struct TestSimpleBool {
+ bool x;
+};
+
+struct TestAlignment1 {
+ int8 x;
+ int8 y;
+ uint32 z;
+};
+
+struct TestAlignment2 {
+ uint32 a;
+ uint32 b;
+ int8 c;
+ int8 d;
+ int8 e;
+ uint8 f;
+ uint32 g;
+ uint16 h;
+ uint16 i;
+};
+
+struct TestFloat1 {
+ float32 a;
+};
+
+struct TestFloat2 {
+ float64 a;
+};
+
+struct TestFloat3 {
+ float32 a;
+ float64 b;
+ uint64 c;
+ float32 d;
+};
+
+struct TestArray1 {
+ array<int8>:5 a;
+};
+
+struct TestArray2 {
+ float64 a;
+ array<float32>:1 b;
+};
+
+struct TestArray3 {
+ int32 a;
+ array<uint16>:3 b;
+ uint64 c;
+};
+
+struct TestArray4 {
+ array<bool>:9 a;
+};
+
+struct TestString1 {
+ string a;
+ string? b;
+};
+
+struct TestString2 {
+ array<string>:2 a;
+};
+
+struct TestString3 {
+ array<string:4>:2 a;
+ array<string:4?>:2 b;
+};
+
+struct TestVector1 {
+ vector<int8> a;
+ vector<int16>? b;
+ vector<int32>:2 c;
+ vector<int64>:2? d;
+};
+
+struct TestVector2 {
+ array<vector<int8>>:2 a;
+ vector<vector<int8>>:2 b;
+ vector<vector<string:5>:2?>:2 c;
+};
+
+struct TestStruct1 {
+ TestSimple a;
+ TestSimple? b;
+};
+
+struct TestStruct2 {
+ TestArray1 a;
+ TestFloat1 b;
+ TestVector1 c;
+ TestString1? d;
+};
+
+union Union1 {
+ array<int8>:3 a;
+ TestSimple b;
+ TestSimple? c;
+ float32 d;
+};
+
+struct TestUnion1 {
+ Union1 a;
+ Union1? b;
+};
+
+struct TestUnion2 {
+ vector<Union1> a;
+ vector<Union1?> b;
+};
+
+struct TestHandle1 {
+ handle a;
+ handle? b;
+ handle<vmo> c;
+ handle<vmo>? d;
+};
+
+struct TestHandle2 {
+ vector<handle>:1 a;
+ vector<handle<vmo>?>:1 b;
+};
+
+interface Test1 {
+ 10: Echo(string? in) -> (string? out);
+ 11: -> Surprise(string foo);
+};
+
+struct TestInterface1 {
+ Test1 a;
+ Test1? b;
+ request<Test1> c;
+ request<Test1>? d;
+};
diff --git a/src/syscall/zx/fidl/encoding.go b/src/syscall/zx/fidl/encoding.go
new file mode 100644
index 0000000..bba6e0d
--- /dev/null
+++ b/src/syscall/zx/fidl/encoding.go
@@ -0,0 +1,1017 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package fidl
+
+import (
+ "errors"
+ "math"
+ "reflect"
+ "strconv"
+ "strings"
+ "syscall/zx"
+)
+
+const (
+ allocPresent uint64 = math.MaxUint64
+ noAlloc = 0
+)
+
+const (
+ handlePresent uint32 = math.MaxUint32
+ noHandle = 0
+)
+
+var (
+ // TODO(mknyszek): Add support here for process, thread, job, resource,
+ // interrupt, eventpair, fifo, guest, and time once these are actually
+ // supported in the Go runtime.
+ handleType reflect.Type = reflect.TypeOf(zx.Handle(0))
+ channelType = reflect.TypeOf(zx.Channel(0))
+ logType = reflect.TypeOf(zx.Log(0))
+ portType = reflect.TypeOf(zx.Port(0))
+ vmoType = reflect.TypeOf(zx.VMO(0))
+ eventType = reflect.TypeOf(zx.Event(0))
+ socketType = reflect.TypeOf(zx.Socket(0))
+ vmarType = reflect.TypeOf(zx.VMAR(0))
+ interfaceRequestType = reflect.TypeOf(InterfaceRequest{})
+ proxyType = reflect.TypeOf(Proxy{})
+)
+
+// isUnionType returns true if the reflected type is a FIDL union type.
+func isUnionType(t reflect.Type) bool {
+ // This is a safe way to check if it's a union type because the generated
+ // code inserts a "dummy" field (of type struct{}) at the beginning as a
+ // marker that the struct should be treated as a FIDL union. Because all FIDL
+ // fields are exported, there's no potential for name collision either, and a
+ // struct accidentally being treated as a union.
+ return t.Kind() == reflect.Struct && t.NumField() > 1 && t.Field(0).Tag.Get("fidl") == "tag"
+}
+
+// isHandleType returns true if the reflected type is a Fuchsia handle type.
+func isHandleType(t reflect.Type) bool {
+ switch t {
+ case handleType:
+ fallthrough
+ case channelType:
+ fallthrough
+ case logType:
+ fallthrough
+ case portType:
+ fallthrough
+ case vmoType:
+ fallthrough
+ case eventType:
+ fallthrough
+ case socketType:
+ fallthrough
+ case vmarType:
+ return true
+ }
+ return false
+}
+
+// isInterfaceType returns true if the reflected type is a FIDL interface type.
+func isInterfaceType(t reflect.Type) bool {
+ // FIDL interfaces are represented as aliases over Proxy.
+ return t.ConvertibleTo(proxyType)
+}
+
+// isInterfaceRequestType returns true if the reflected type is a FIDL interface
+// request type.
+func isInterfaceRequestType(t reflect.Type) bool {
+ // FIDL interfaces are represented as aliases over InterfaceRequest.
+ return t.ConvertibleTo(interfaceRequestType)
+}
+
+// getSize returns the size of the type. Occasionally this requires the value,
+// particularly for a struct.
+func getSize(t reflect.Type, v reflect.Value) (int, error) {
+ switch t.Kind() {
+ case reflect.Array:
+ if v.Len() == 0 {
+ return 0, nil
+ }
+ s, err := getSize(t.Elem(), v.Index(0))
+ if err != nil {
+ return 0, err
+ }
+ return v.Len() * s, nil
+ case reflect.Bool, reflect.Int8, reflect.Uint8:
+ return 1, nil
+ case reflect.Int16, reflect.Uint16:
+ return 2, nil
+ case reflect.Int32, reflect.Uint32, reflect.Float32:
+ return 4, nil
+ case reflect.Int64, reflect.Uint64, reflect.Float64:
+ return 8, nil
+ case reflect.Ptr:
+ i := t.Elem()
+ switch i.Kind() {
+ case reflect.Slice:
+ return 16, nil
+ case reflect.String:
+ return 16, nil
+ case reflect.Struct:
+ // Handles both structs and unions.
+ return 8, nil
+ }
+ return 0, newValueError(ErrInvalidPointerType, t.Name())
+ case reflect.String:
+ return 16, nil
+ case reflect.Slice:
+ return 16, nil
+ case reflect.Struct:
+ // Handles both structs and unions.
+ return getPayloadSize(t, v)
+ }
+ return 0, newValueError(ErrInvalidInlineType, t.Name())
+}
+
+func structAsPayload(t reflect.Type, v reflect.Value) (Payload, error) {
+ // Get the size and alignment for the struct.
+ //
+ // Note that Addr can fail if the originally derived value is not "addressable",
+ // meaning the root ValueOf() call was on a struct value, not a pointer. However,
+ // we guarantee the struct is addressable by forcing a Payload to be passed in
+ // (a struct value will never cast as an interface).
+ //
+ // We avoid using Implements(), MethodByName(), and Call() here because they're
+ // very slow.
+ payload, ok := v.Addr().Interface().(Payload)
+ if !ok {
+ return nil, ErrStructIsNotPayload
+ }
+ return payload, nil
+}
+
+func getPayloadSize(t reflect.Type, v reflect.Value) (int, error) {
+ p, err := structAsPayload(t, v)
+ if err != nil {
+ return 0, err
+ }
+ return p.InlineSize(), nil
+}
+
+func getPayloadAlignment(t reflect.Type, v reflect.Value) (int, error) {
+ p, err := structAsPayload(t, v)
+ if err != nil {
+ return 0, err
+ }
+ return p.InlineAlignment(), nil
+}
+
+// fieldData contains metadata for a single struct field for use during encoding and
+// decoding. It is derived from a struct field tag, and generally contains facilities
+// for managing state in a recursive context (since even the type in a single struct field
+// may be recursively defined).
+type nestedTypeData struct {
+ // maxElems represents the maximum number of elements allowed for a
+ // container type. "nil" means there is no maximum. It is represented
+ // as a slice because FIDL container types may be nested arbitrarily
+ // deeply. The lower the index, the more deeply nested the type is.
+ maxElems []*int
+
+ // nullable reflects whether the innermost type for a struct field is nullable.
+ // This is only used for types where nullability is non-obvious, which is only
+ // handles for now.
+ nullable bool
+}
+
+// Unnest attempts to unnest the nestedTypeData one level. If it succeeds, it returns the type
+// data for that nesting level, and modifies the data structure for the next nested container.
+func (n *nestedTypeData) Unnest() *int {
+ if len(n.maxElems) == 0 {
+ return nil
+ }
+ v := n.maxElems[len(n.maxElems)-1]
+ n.maxElems = n.maxElems[:len(n.maxElems)-1]
+ return v
+}
+
+// FromTag derives metadata from data serialized into a golang struct field
+// tag.
+func (n *nestedTypeData) FromTag(tag reflect.StructTag) error {
+ raw, ok := tag.Lookup("fidl")
+ if !ok {
+ return nil
+ }
+ split := strings.Split(raw, ",")
+ if split[0] == "*" {
+ n.nullable = true
+ split = split[1:]
+ }
+ var maxElems []*int
+ for _, e := range split {
+ if e == "" {
+ maxElems = append(maxElems, nil)
+ continue
+ }
+ i, err := strconv.ParseInt(e, 0, 64)
+ if err != nil {
+ return err
+ }
+ val := int(i)
+ maxElems = append(maxElems, &val)
+ }
+ n.maxElems = maxElems
+ return nil
+}
+
+// align increases size such that size is aligned to bytes, and returns the new size.
+//
+// bytes must be a power of 2.
+func align(size, bytes int) int {
+ offset := size & (bytes - 1)
+ // If we're not currently aligned to |bytes| bytes, add padding.
+ if offset != 0 {
+ size += (bytes - offset)
+ }
+ return size
+}
+
+// encoder represents the encoding context that is necessary to maintain across
+// recursive calls within the same FIDL object.
+type encoder struct {
+ // head is the index into buffer at which new data will be written to for the current
+ // object. It must be updated before writing to a new out-of-line object, and then
+ // fixed when that object is finished.
+ head int
+
+ // buffer represents the output buffer that the encoder writes into.
+ buffer []byte
+
+ // handles are the handles discovered when traversing the FIDL data
+ // structure. They are referenced from within the serialized data
+ // structure in buffer.
+ handles []zx.Handle
+}
+
+func (e *encoder) newObject(size int) int {
+ size = align(size, 8)
+ start := len(e.buffer)
+ e.buffer = append(e.buffer, make([]byte, size)...)
+ return start
+}
+
+// writeInt writes an integer of byte-width size to the buffer.
+//
+// Before writing, it pads the buffer such that the integer is aligned to
+// its own byte-width.
+//
+// size must be a power of 2 <= 8.
+func (e *encoder) writeInt(val int64, size int) {
+ e.writeUint(uint64(val), size)
+}
+
+// writeUint writes an unsigned integer of byte-width size to the buffer.
+//
+// Before writing, it pads the buffer such that the integer is aligned to
+// its own byte-width.
+//
+// size must be a power of 2 <= 8.
+func (e *encoder) writeUint(val uint64, size int) {
+ e.head = align(e.head, size)
+ for i := e.head; i < e.head+size; i++ {
+ e.buffer[i] = byte(val & 0xFF)
+ val >>= 8
+ }
+ e.head += size
+}
+
+// marshalStructOrUnionInline first aligns head to the struct's or union's alignment
+// factor, and then writes its field(s) inline.
+//
+// Expects the Type t and Value v to refer to a golang struct value, not a pointer.
+func (e *encoder) marshalStructOrUnionInline(t reflect.Type, v reflect.Value) error {
+ a, err := getPayloadAlignment(t, v)
+ if err != nil {
+ return err
+ }
+ e.head = align(e.head, a)
+ if isUnionType(t) {
+ err = e.marshalUnion(t, v, a)
+ } else {
+ err = e.marshalStructFields(t, v)
+ }
+ if err != nil {
+ return err
+ }
+ e.head = align(e.head, a)
+ return nil
+}
+
+// marshalStructOrUnionPointer marshals a nullable struct's or union's reference, and then
+// marshals the value itself out-of-line.
+//
+// Expects the Type t and Value v to refer to a pointer to a golang struct.
+func (e *encoder) marshalStructOrUnionPointer(t reflect.Type, v reflect.Value) error {
+ if v.IsNil() {
+ e.writeUint(noAlloc, 8)
+ return nil
+ }
+ e.writeUint(allocPresent, 8)
+ et := t.Elem()
+ ev := v.Elem()
+ // Encode the value out-of-line.
+ payload, err := structAsPayload(et, ev)
+ if err != nil {
+ return err
+ }
+ oldHead := e.head
+ e.head = e.newObject(align(payload.InlineSize(), 8))
+ if isUnionType(et) {
+ err = e.marshalUnion(et, ev, payload.InlineAlignment())
+ } else {
+ err = e.marshalStructFields(et, ev)
+ }
+ if err != nil {
+ return err
+ }
+ e.head = oldHead
+ return nil
+}
+
+// marshalStructFields marshals the fields of a struct inline without any alignment.
+//
+// Expects the Type t and Value v to refer to a struct value, not a pointer.
+//
+// It marshals only exported struct fields.
+func (e *encoder) marshalStructFields(t reflect.Type, v reflect.Value) error {
+ for i := 0; i < t.NumField(); i++ {
+ f := t.Field(i)
+ // If it's an unexported field, ignore it.
+ if f.PkgPath != "" {
+ continue
+ }
+ var n nestedTypeData
+ if err := n.FromTag(f.Tag); err != nil {
+ return err
+ }
+ if err := e.marshal(f.Type, v.Field(i), n); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// marshalUnion marshals a FIDL union represented as a golang struct inline,
+// without any external alignment.
+//
+// Expects the Type t and Value v to refer to a golang struct value, not a
+// pointer. The alignment field is used to align the union's field.
+func (e *encoder) marshalUnion(t reflect.Type, v reflect.Value, alignment int) error {
+ kind := v.Field(0).Uint()
+
+ // Index into the fields of the struct, adding 1 for the tag.
+ fieldIndex := int(kind) + 1
+ if fieldIndex >= t.NumField() {
+ return newValueError(ErrInvalidUnionTag, kind)
+ }
+ // Save the head for proper padding.
+ head := e.head
+ e.writeUint(kind, 4)
+
+ f := t.Field(fieldIndex)
+ var n nestedTypeData
+ if err := n.FromTag(f.Tag); err != nil {
+ return err
+ }
+ // Re-align to the union's alignment before writing its field.
+ e.head = align(e.head, alignment)
+ if err := e.marshal(f.Type, v.Field(fieldIndex), n); err != nil {
+ return err
+ }
+ s, err := getPayloadSize(t, v)
+ if err != nil {
+ return err
+ }
+ e.head = head + s
+ return nil
+}
+
+// marshalArray marshals a FIDL array inline.
+func (e *encoder) marshalArray(t reflect.Type, v reflect.Value, n nestedTypeData) error {
+ elemType := t.Elem()
+ for i := 0; i < t.Len(); i++ {
+ if err := e.marshal(elemType, v.Index(i), n); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// marshalInline marshals a number of different supported FIDL types inline.
+func (e *encoder) marshalInline(t reflect.Type, v reflect.Value, n nestedTypeData) error {
+ switch t.Kind() {
+ case reflect.Array:
+ return e.marshalArray(t, v, n)
+ case reflect.Bool:
+ i := uint64(0)
+ if v.Bool() {
+ i = 1
+ }
+ e.writeUint(i, 1)
+ case reflect.Int8:
+ e.writeInt(v.Int(), 1)
+ case reflect.Int16:
+ e.writeInt(v.Int(), 2)
+ case reflect.Int32:
+ e.writeInt(v.Int(), 4)
+ case reflect.Int64:
+ e.writeInt(v.Int(), 8)
+ case reflect.Uint8:
+ e.writeUint(v.Uint(), 1)
+ case reflect.Uint16:
+ e.writeUint(v.Uint(), 2)
+ case reflect.Uint32:
+ e.writeUint(v.Uint(), 4)
+ case reflect.Uint64:
+ e.writeUint(v.Uint(), 8)
+ case reflect.Float32:
+ e.writeUint(uint64(math.Float32bits(float32(v.Float()))), 4)
+ case reflect.Float64:
+ e.writeUint(math.Float64bits(v.Float()), 8)
+ case reflect.Struct:
+ return e.marshalStructOrUnionInline(t, v)
+ default:
+ return newValueError(ErrInvalidInlineType, t.Name())
+ }
+ return nil
+}
+
+// marshalVector writes the vector metadata inline and the elements of the vector in a new
+// out-of-line object. Expects the value to be a regular string value, i.e. of type string.
+func (e *encoder) marshalVector(t reflect.Type, v reflect.Value, n nestedTypeData) error {
+ if !v.IsValid() {
+ e.writeUint(0, 8)
+ e.writeUint(noAlloc, 8)
+ return nil
+ }
+ max := n.Unnest()
+ if max != nil && v.Len() > *max {
+ return newExpectError(ErrVectorTooLong, *max, v.Len())
+ }
+ e.writeUint(uint64(v.Len()), 8)
+ e.writeUint(allocPresent, 8)
+ // Don't bother creating the out-of-line struct if its length is 0.
+ if v.Len() == 0 {
+ return nil
+ }
+ elemType := t.Elem()
+ elemSize, err := getSize(elemType, v.Index(0))
+ if err != nil {
+ return err
+ }
+ // Encode in the out-of-line object.
+ oldHead := e.head
+ e.head = e.newObject(v.Len() * elemSize)
+
+ if elemType.Kind() == reflect.Uint8 {
+ // optimize the fdio case of a vector of bytes
+ copy(e.buffer[e.head:], v.Bytes())
+ } else {
+ for i := 0; i < v.Len(); i++ {
+ if err := e.marshal(elemType, v.Index(i), n); err != nil {
+ return err
+ }
+ }
+ }
+ e.head = oldHead
+ return nil
+}
+
+// marshalString writes the string metadata inline and the bytes of the string in a new
+// out-of-line object. Expects the value to be a regular string value, i.e. of type string.
+func (e *encoder) marshalString(v reflect.Value, n nestedTypeData) error {
+ if !v.IsValid() {
+ e.writeUint(0, 8)
+ e.writeUint(noAlloc, 8)
+ return nil
+ }
+ s := v.String()
+ max := n.Unnest()
+ if max != nil && len(s) > *max {
+ return newExpectError(ErrStringTooLong, *max, len(s))
+ }
+ e.writeUint(uint64(len(s)), 8)
+ e.writeUint(allocPresent, 8)
+
+ // Create a new out-of-line object and write bytes of the string.
+ head := e.newObject(len(s))
+ for i := 0; i < len(s); i++ {
+ e.buffer[head+i] = s[i]
+ }
+ return nil
+}
+
+// marshalHandle marshals a Fuchsia handle type, and ensures that the handle is
+// valid if it is not nullable.
+func (e *encoder) marshalHandle(v reflect.Value, n nestedTypeData) error {
+ // The underlying type of all the handles is a uint32, so we're
+ // safe calling Uint(). This will panic if that is no longer true.
+ raw := zx.Handle(v.Uint())
+ if raw == zx.HandleInvalid {
+ if !n.nullable {
+ return ErrUnexpectedNullHandle
+ }
+ e.writeUint(uint64(noHandle), 4)
+ return nil
+ }
+ e.handles = append(e.handles, raw)
+ e.writeUint(uint64(handlePresent), 4)
+ return nil
+}
+
+// marshalPointer marshals nullable FIDL types that are represented by golang pointer
+// indirections. The input type and value should be the dereference of the golang pointers,
+// that is, if we're marshalling *string, we should get string.
+func (e *encoder) marshalPointer(t reflect.Type, v reflect.Value, n nestedTypeData) error {
+ switch t.Elem().Kind() {
+ case reflect.Slice:
+ return e.marshalVector(t.Elem(), v.Elem(), n)
+ case reflect.String:
+ return e.marshalString(v.Elem(), n)
+ case reflect.Struct:
+ return e.marshalStructOrUnionPointer(t, v)
+ }
+ return newValueError(ErrInvalidPointerType, t.Name())
+}
+
+// marshal is the central recursive function core to marshalling, and
+// traverses the tree-like structure of the input type t. v represents
+// the value associated with the type t.
+func (e *encoder) marshal(t reflect.Type, v reflect.Value, n nestedTypeData) error {
+ switch t.Kind() {
+ case reflect.Ptr:
+ return e.marshalPointer(t, v, n)
+ case reflect.Slice:
+ return e.marshalVector(t, v, n)
+ case reflect.String:
+ return e.marshalString(v, n)
+ }
+ if isHandleType(t) {
+ return e.marshalHandle(v, n)
+ }
+ if isInterfaceType(t) || isInterfaceRequestType(t) {
+ // An interface is represented by a Proxy, whose first field is
+ // a zx.Channel, and we can just marshal that. Same goes for an
+ // interface request, which is just an InterfaceRequest whose
+ // first field is a zx.Channel.
+ return e.marshalHandle(v.Field(0), n)
+ }
+ return e.marshalInline(t, v, n)
+}
+
+// MarshalHeader encodes the FIDL message header into the beginning of data.
+func MarshalHeader(header *MessageHeader, data []byte) {
+ // Clear the buffer so we can append to it.
+ e := encoder{buffer: data[:0]}
+ e.head = e.newObject(MessageHeaderSize)
+ e.writeUint(uint64(header.Txid), 4)
+ e.writeUint(uint64(header.Reserved), 4)
+ e.writeUint(uint64(header.Flags), 4)
+ e.writeUint(uint64(header.Ordinal), 4)
+}
+
+// Marshal the FIDL payload in s into data and handles.
+//
+// s must be a pointer to a struct, since the primary object in a FIDL message
+// is always a struct.
+//
+// Marshal traverses the value s recursively, following nested type values via
+// reflection in order to encode the FIDL struct.
+func Marshal(s Payload, data []byte, handles []zx.Handle) (int, int, error) {
+ // First, let's make sure we have the right type in s.
+ t := reflect.TypeOf(s)
+ if t.Kind() != reflect.Ptr {
+ return 0, 0, errors.New("expected a pointer")
+ }
+ t = t.Elem()
+ if t.Kind() != reflect.Struct {
+ return 0, 0, errors.New("primary object must be a struct")
+ }
+
+ // Now, let's get the value of s, marshal the header into a starting
+ // buffer, and then marshal the rest of the payload in s.
+ v := reflect.ValueOf(s).Elem()
+ e := encoder{buffer: data[:0], handles: handles[:0]}
+ e.head = e.newObject(s.InlineSize())
+ if err := e.marshalStructFields(t, v); err != nil {
+ return 0, 0, err
+ }
+ return len(e.buffer), len(e.handles), nil
+}
+
+// decoder represents the decoding context that is necessary to maintain
+// across recursive calls within the same FIDL object.
+type decoder struct {
+ // head is the index into buffer at which new data will be read from for the current
+ // object. It must be updated before reading from a new out-of-line object, and then
+ // fixed when that object is finished.
+ head int
+
+ // nextObject is the byte index of the next out-of-line object in buffer.
+ nextObject int
+
+ // buffer represents the buffer we're decoding from.
+ buffer []byte
+
+ // handles represents the input untyped handled we're decoding.
+ handles []zx.Handle
+}
+
+// readInt reads a signed integer value of byte-width size from the buffer.
+//
+// Before it reads, however, it moves the head forward so as to be naturally
+// aligned with the byte-width of the integer it is reading.
+//
+// size must be a power of 2 <= 8.
+func (d *decoder) readInt(size int) int64 {
+ return int64(d.readUint(size))
+}
+
+// readUint reads an unsigned integer value of byte-width size from the buffer.
+//
+// Before it reads, however, it moves the head forward so as to be naturally
+// aligned with the byte-width of the integer it is reading.
+//
+// size must be a power of 2 <= 8.
+func (d *decoder) readUint(size int) uint64 {
+ d.head = align(d.head, size)
+ var val uint64
+ for i := d.head + size - 1; i >= d.head; i-- {
+ val <<= 8
+ val |= uint64(d.buffer[i])
+ }
+ d.head += size
+ return val
+}
+
+// unmarshalStructOrUnionInline unmarshals a struct or union inline based on Type t
+// into Value v, first aligning head to the alignment of the value.
+//
+// Expects the Type t and Value v to refer to a golang struct value, not a pointer.
+func (d *decoder) unmarshalStructOrUnionInline(t reflect.Type, v reflect.Value) error {
+ a, err := getPayloadAlignment(t, v)
+ if err != nil {
+ return err
+ }
+ d.head = align(d.head, a)
+ if isUnionType(t) {
+ err = d.unmarshalUnion(t, v, a)
+ } else {
+ err = d.unmarshalStructFields(t, v)
+ }
+ if err != nil {
+ return err
+ }
+ d.head = align(d.head, a)
+ return nil
+}
+
+// unmarshalStructOrUnionPointer unmarshals a pointer to a golang struct (i.e. a
+// nullable FIDL struct or union) into the Value v.
+//
+// Expects the Type t and Value v to refer to a pointer to a golang struct.
+func (d *decoder) unmarshalStructOrUnionPointer(t reflect.Type, v reflect.Value) error {
+ if d.readUint(8) == noAlloc {
+ v.Set(reflect.Zero(t))
+ return nil
+ }
+ // Create the new struct.
+ v.Set(reflect.New(t.Elem()))
+ et := t.Elem()
+ ev := v.Elem()
+
+ // Set up the out-of-line space and the head.
+ oldHead := d.head
+ d.head = d.nextObject
+ payload, err := structAsPayload(et, ev)
+ if err != nil {
+ return err
+ }
+ d.nextObject += align(payload.InlineSize(), 8)
+
+ // Unmarshal the value itself out-of-line.
+ if isUnionType(et) {
+ err = d.unmarshalUnion(et, ev, payload.InlineAlignment())
+ } else {
+ err = d.unmarshalStructFields(et, ev)
+ }
+ if err != nil {
+ return err
+ }
+
+ // Fix up head to the old head if it's a nullable struct.
+ d.head = oldHead
+ return nil
+}
+
+// unmarshalStructFields unmarshals the exported fields of the struct at d.head into
+// the Value v.
+//
+// Expects the Type t and Value v to refer to a struct value, not a pointer.
+func (d *decoder) unmarshalStructFields(t reflect.Type, v reflect.Value) error {
+ for i := 0; i < t.NumField(); i++ {
+ f := t.Field(i)
+ // If it's an unexported field, ignore it.
+ if f.PkgPath != "" {
+ continue
+ }
+ var n nestedTypeData
+ if err := n.FromTag(f.Tag); err != nil {
+ return err
+ }
+ if err := d.unmarshal(f.Type, v.Field(i), n); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// unmarshalUnion unmarshals a FIDL union at d.head into the Value v (a golang
+// struct) without any external alignment.
+//
+// Expects the Type t and Value v to refer to a golang struct value, not a pointer.
+// The alignment field is used to align to the union's field before reading.
+func (d *decoder) unmarshalUnion(t reflect.Type, v reflect.Value, alignment int) error {
+ // Save the head for proper padding.
+ head := d.head
+ kind := d.readUint(4)
+
+ // Index into the fields of the struct, adding 1 for the tag.
+ fieldIndex := int(kind) + 1
+ if fieldIndex >= t.NumField() {
+ return ErrInvalidUnionTag
+ }
+ v.Field(0).SetUint(kind)
+
+ f := t.Field(fieldIndex)
+ var n nestedTypeData
+ if err := n.FromTag(f.Tag); err != nil {
+ return err
+ }
+ d.head = align(d.head, alignment)
+ if err := d.unmarshal(f.Type, v.Field(fieldIndex), n); err != nil {
+ return err
+ }
+ s, err := getPayloadSize(t, v)
+ if err != nil {
+ return err
+ }
+ d.head = head + s
+ return nil
+}
+
+// unmarshalArray unmarshals an array inline based on Type t into Value v, taking into account
+// nestedTypeData n, since an array is a container type.
+func (d *decoder) unmarshalArray(t reflect.Type, v reflect.Value, n nestedTypeData) error {
+ elemType := t.Elem()
+ for i := 0; i < t.Len(); i++ {
+ if err := d.unmarshal(elemType, v.Index(i), n); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// unmarshalInline unmarshals a variety of types inline, or delegates to their types' specific
+// unmarshalling functions.
+func (d *decoder) unmarshalInline(t reflect.Type, v reflect.Value, n nestedTypeData) error {
+ switch t.Kind() {
+ case reflect.Array:
+ return d.unmarshalArray(t, v, n)
+ case reflect.Bool:
+ i := d.readUint(1)
+ switch i {
+ case 0:
+ v.SetBool(false)
+ case 1:
+ v.SetBool(true)
+ default:
+ return newValueError(ErrInvalidBoolValue, i)
+ }
+ case reflect.Int8:
+ v.SetInt(d.readInt(1))
+ case reflect.Int16:
+ v.SetInt(d.readInt(2))
+ case reflect.Int32:
+ v.SetInt(d.readInt(4))
+ case reflect.Int64:
+ v.SetInt(d.readInt(8))
+ case reflect.Uint8:
+ v.SetUint(d.readUint(1))
+ case reflect.Uint16:
+ v.SetUint(d.readUint(2))
+ case reflect.Uint32:
+ v.SetUint(d.readUint(4))
+ case reflect.Uint64:
+ v.SetUint(d.readUint(8))
+ case reflect.Float32:
+ v.SetFloat(float64(math.Float32frombits(uint32(d.readUint(4)))))
+ case reflect.Float64:
+ v.SetFloat(math.Float64frombits(d.readUint(8)))
+ case reflect.Struct:
+ return d.unmarshalStructOrUnionInline(t, v)
+ default:
+ return newValueError(ErrInvalidInlineType, t.Name())
+ }
+ return nil
+}
+
+// unmarshalVector unmarshals an out-of-line FIDL vector into a golang slice which is placed
+// into v. nestedTypeData is also necessary because a vector can have a maximum size). The
+// expected types and values are either pointers, i.e. *[]int8 or an "inline" vector value
+// i.e. []int8.
+func (d *decoder) unmarshalVector(t reflect.Type, v reflect.Value, n nestedTypeData) error {
+ size := int64(d.readUint(8))
+ if size < 0 {
+ return newExpectError(ErrVectorTooLong, math.MaxInt64, size)
+ }
+ if ptr := d.readUint(8); ptr == noAlloc {
+ if t.Kind() != reflect.Ptr {
+ return newValueError(ErrUnexpectedNullRef, "vector")
+ }
+ v.Set(reflect.Zero(t))
+ return nil
+ }
+ max := n.Unnest()
+ if max != nil && int(size) > *max {
+ return newExpectError(ErrVectorTooLong, *max, size)
+ }
+
+ // Create the slice with reflection.
+ sliceType := t
+ elemType := t.Elem()
+ if t.Kind() == reflect.Ptr {
+ sliceType = elemType
+ elemType = sliceType.Elem()
+ }
+ s := reflect.MakeSlice(sliceType, int(size), int(size))
+
+ // Unmarshal the out-of-line structure.
+ oldHead := d.head
+ d.head = d.nextObject
+ // TODO(mknyszek): Get rid of this extra reflect.New somehow.
+ elemSize, err := getSize(elemType, reflect.New(elemType).Elem())
+ if err != nil {
+ return err
+ }
+ d.nextObject += align(int(size)*elemSize, 8)
+ if elemType.Kind() == reflect.Uint8 {
+ copy(s.Bytes(), d.buffer[d.head:])
+ } else {
+ for i := 0; i < int(size); i++ {
+ if err := d.unmarshal(elemType, s.Index(i), n); err != nil {
+ return err
+ }
+ }
+ }
+ d.head = oldHead
+ if t.Kind() == reflect.Ptr {
+ v.Set(reflect.New(t.Elem()))
+ v.Elem().Set(s)
+ } else {
+ v.Set(s)
+ }
+ return nil
+}
+
+// unmarshalString unmarshals an out-of-line FIDL string into a golang string which is placed
+// into v. nestedTypeData is also necessary because it can have a maximum size). The expected
+// types and values are either pointers, i.e. *string or an "inline" string value. i.e. string.
+// This method uses whether or not the type is a golang pointer type to determine if it is
+// nullable.
+func (d *decoder) unmarshalString(t reflect.Type, v reflect.Value, n nestedTypeData) error {
+ size := int64(d.readUint(8))
+ if size < 0 {
+ return newExpectError(ErrStringTooLong, math.MaxInt64, size)
+ }
+ if ptr := d.readUint(8); ptr == noAlloc {
+ if t.Kind() != reflect.Ptr {
+ return newValueError(ErrUnexpectedNullRef, "string")
+ }
+ v.Set(reflect.Zero(t))
+ return nil
+ }
+ max := n.Unnest()
+ if max != nil && int(size) > *max {
+ return newExpectError(ErrStringTooLong, *max, size)
+ }
+ s := string(d.buffer[d.nextObject : d.nextObject+int(size)])
+ if t.Kind() == reflect.Ptr {
+ v.Set(reflect.New(t.Elem()))
+ v.Elem().Set(reflect.ValueOf(s))
+ } else {
+ v.Set(reflect.ValueOf(s))
+ }
+ d.nextObject += align(int(size), 8)
+ return nil
+}
+
+// unmarshalHandle unmarshals a handle into a value, validating that it is valid if the handle is
+// not nullable.
+func (d *decoder) unmarshalHandle(v reflect.Value, n nestedTypeData) error {
+ h := d.readUint(4)
+ switch h {
+ case uint64(noHandle):
+ if !n.nullable {
+ return ErrUnexpectedNullHandle
+ }
+ v.SetUint(uint64(zx.HandleInvalid))
+ case uint64(handlePresent):
+ if len(d.handles) == 0 {
+ return ErrNotEnoughHandles
+ }
+ v.SetUint(uint64(d.handles[0]))
+ d.handles = d.handles[1:]
+ default:
+ return newValueError(ErrBadHandleEncoding, h)
+ }
+ return nil
+}
+
+// unmarshalPointer unmarshals nullable FIDL types that are represented by golang pointer
+// indirections. The expected types and values t and v are pointers, i.e. they start with *.
+func (d *decoder) unmarshalPointer(t reflect.Type, v reflect.Value, n nestedTypeData) error {
+ switch t.Elem().Kind() {
+ case reflect.Slice:
+ return d.unmarshalVector(t, v, n)
+ case reflect.String:
+ return d.unmarshalString(t, v, n)
+ case reflect.Struct:
+ return d.unmarshalStructOrUnionPointer(t, v)
+ }
+ return newValueError(ErrInvalidPointerType, t.Name())
+}
+
+// unmarshal is the central recursive function core to unmarshalling, and
+// traverses the tree-like structure of the input type t. v represents
+// the value associated with the type t.
+func (d *decoder) unmarshal(t reflect.Type, v reflect.Value, n nestedTypeData) error {
+ switch t.Kind() {
+ case reflect.Ptr:
+ return d.unmarshalPointer(t, v, n)
+ case reflect.Slice:
+ return d.unmarshalVector(t, v, n)
+ case reflect.String:
+ return d.unmarshalString(t, v, n)
+ }
+ if isHandleType(t) {
+ return d.unmarshalHandle(v, n)
+ }
+ if isInterfaceType(t) || isInterfaceRequestType(t) {
+ // An interface is represented by a Proxy, whose first field is
+ // a zx.Channel, and we can just marshal that. Same goes for an
+ // interface request, which is just an InterfaceRequest whose
+ // first field is a zx.Channel.
+ return d.unmarshalHandle(v.Field(0), n)
+ }
+ return d.unmarshalInline(t, v, n)
+}
+
+// UnmarshalHeader parses a FIDL header in the data into m.
+func UnmarshalHeader(data []byte, m *MessageHeader) error {
+ if len(data) < 16 {
+ return ErrMessageTooSmall
+ }
+ d := decoder{buffer: data}
+ m.Txid = uint32(d.readUint(4))
+ m.Reserved = uint32(d.readUint(4))
+ m.Flags = uint32(d.readUint(4))
+ m.Ordinal = uint32(d.readUint(4))
+ return nil
+}
+
+// Unmarshal parses the encoded FIDL payload in data and handles, storing the
+// decoded payload in s.
+//
+// The value pointed to by s must be a pointer to a golang struct which represents
+// the decoded primary object of a FIDL message. The data decode process is guided
+// by the structure of the struct pointed to by s.
+//
+// TODO(mknyszek): More rigorously validate the input.
+func Unmarshal(data []byte, handles []zx.Handle, s Payload) error {
+ // First, let's make sure we have the right type in s.
+ t := reflect.TypeOf(s)
+ if t.Kind() != reflect.Ptr {
+ return errors.New("expected a pointer")
+ }
+ t = t.Elem()
+ if t.Kind() != reflect.Struct {
+ return errors.New("primary object must be a struct")
+ }
+
+ // Get the payload's value and unmarshal it.
+ nextObject := align(s.InlineSize(), 8)
+ d := decoder{
+ buffer: data,
+ handles: handles,
+ nextObject: nextObject,
+ }
+ return d.unmarshalStructFields(t, reflect.ValueOf(s).Elem())
+}
diff --git a/src/syscall/zx/fidl/encoding_test.go b/src/syscall/zx/fidl/encoding_test.go
new file mode 100644
index 0000000..41af868
--- /dev/null
+++ b/src/syscall/zx/fidl/encoding_test.go
@@ -0,0 +1,188 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package fidl_test
+
+import (
+ "reflect"
+ "syscall/zx"
+ "testing"
+
+ . "fidl/bindings"
+ . "fuchsia/go/go_fidl_bindings_test"
+)
+
+func testIdentity(t *testing.T, input Payload, expectSize int, output Payload) {
+ var respb [zx.ChannelMaxMessageBytes]byte
+ var resph [zx.ChannelMaxMessageHandles]zx.Handle
+ nb, nh, err := Marshal(input, respb[:], resph[:])
+ if err != nil {
+ t.Fatal(err)
+ }
+ if nb != expectSize {
+ t.Fatalf("expected size %d but got %d: %v", expectSize, nb, respb[:nb])
+ }
+ if err := Unmarshal(respb[:nb], resph[:nh], output); err != nil {
+ t.Fatal(err)
+ }
+ if !reflect.DeepEqual(input, output) {
+ t.Fatalf("expected: %v, got: %v", input, output)
+ }
+}
+
+func TestEncodingIdentity(t *testing.T) {
+ t.Run("Header", func(t *testing.T) {
+ var buf [MessageHeaderSize]byte
+ m := MessageHeader{
+ Txid: 1215,
+ Reserved: 0,
+ Flags: 111111,
+ Ordinal: 889,
+ }
+ MarshalHeader(&m, buf[:])
+
+ var header MessageHeader
+ if err := UnmarshalHeader(buf[:], &header); err != nil {
+ t.Fatal(err)
+ }
+ if m != header {
+ t.Fatalf("expected: %v, got: %v", m, header)
+ }
+ })
+ t.Run("Simple", func(t *testing.T) {
+ testIdentity(t, &TestSimple{X: 124}, 8, &TestSimple{})
+ testIdentity(t, &TestSimpleBool{X: true}, 8, &TestSimpleBool{})
+ })
+ t.Run("Alignment", func(t *testing.T) {
+ testIdentity(t, &TestAlignment1{X: -36, Y: -10, Z: 51}, 8, &TestAlignment1{})
+ testIdentity(t, &TestAlignment2{
+ A: 1212141,
+ B: 908935,
+ C: -1,
+ D: 125,
+ E: -22,
+ F: 111,
+ G: 1515,
+ H: 65535,
+ I: 1515,
+ }, 24, &TestAlignment2{})
+ })
+ t.Run("Floats", func(t *testing.T) {
+ testIdentity(t, &TestFloat1{A: -36.0}, 8, &TestFloat1{})
+ testIdentity(t, &TestFloat2{A: -1254918271.0}, 8, &TestFloat2{})
+ testIdentity(t, &TestFloat3{A: 1241.1, B: 0.2141, C: 20, D: 0.0}, 32, &TestFloat3{})
+ })
+ t.Run("Arrays", func(t *testing.T) {
+ testIdentity(t, &TestArray1{A: [5]int8{1, 77, 2, 4, 5}}, 8, &TestArray1{})
+ testIdentity(t, &TestArray2{A: -1.0, B: [1]float32{0.2}}, 16, &TestArray2{})
+ testIdentity(t, &TestArray3{
+ A: -999,
+ B: [3]uint16{11, 12, 13},
+ C: 1021,
+ }, 24, &TestArray3{})
+ testIdentity(t, &TestArray4{
+ A: [9]bool{true, false, false, true, false, true, true, true, true},
+ }, 16, &TestArray4{})
+ })
+ t.Run("Strings", func(t *testing.T) {
+ testIdentity(t, &TestString1{A: "str", B: nil}, 40, &TestString1{})
+ testIdentity(t, &TestString2{A: [2]string{"hello", "g"}}, 48, &TestString2{})
+ s := "bye"
+ testIdentity(t, &TestString3{
+ A: [2]string{"boop", "g"},
+ B: [2]*string{&s, nil},
+ }, 88, &TestString3{})
+ })
+ t.Run("Vectors", func(t *testing.T) {
+ v1 := []int64{-1}
+ testIdentity(t, &TestVector1{
+ A: []int8{1, 2, 3, 4},
+ B: nil,
+ C: []int32{99},
+ D: &v1,
+ }, 88, &TestVector1{})
+ v2 := []string{"x", "hello"}
+ testIdentity(t, &TestVector2{
+ A: [2][]int8{{9, -1}, {}},
+ B: [][]int8{{-111, 41}, {-1, -1, -1, -1}},
+ C: []*[]string{nil, &v2},
+ }, 200, &TestVector2{})
+ })
+ t.Run("Structs", func(t *testing.T) {
+ testIdentity(t, &TestStruct1{
+ A: TestSimple{
+ X: -9999,
+ },
+ B: &TestSimple{
+ X: 1254125,
+ },
+ }, 24, &TestStruct1{})
+ v1 := []int64{101010}
+ testIdentity(t, &TestStruct2{
+ A: TestArray1{
+ A: [5]int8{1, 77, 2, 4, 5},
+ },
+ B: TestFloat1{
+ A: 2.81212,
+ },
+ C: TestVector1{
+ A: []int8{1, 2, 3, 4},
+ B: nil,
+ C: []int32{99},
+ D: &v1,
+ },
+ D: &TestString1{
+ A: "str",
+ B: nil,
+ },
+ }, 152, &TestStruct2{})
+ })
+ t.Run("Unions", func(t *testing.T) {
+ u1 := Union1{}
+ u1.SetB(TestSimple{X: 555})
+ testIdentity(t, &TestUnion1{
+ A: u1,
+ B: nil,
+ }, 24, &TestUnion1{})
+ testIdentity(t, &TestUnion2{
+ A: []Union1{u1, u1, u1},
+ B: []*Union1{&u1, nil, nil},
+ }, 120, &TestUnion2{})
+ })
+ t.Run("Handles", func(t *testing.T) {
+ vmo, err := zx.NewVMO(10, 0)
+ if err != nil {
+ t.Fatalf("failed to create vmo: %v", err)
+ }
+ testIdentity(t, &TestHandle1{
+ A: zx.Handle(22),
+ B: zx.HandleInvalid,
+ C: vmo,
+ D: zx.VMO(zx.HandleInvalid),
+ }, 16, &TestHandle1{})
+ testIdentity(t, &TestHandle2{
+ A: []zx.Handle{zx.Handle(vmo)},
+ B: []zx.VMO{zx.VMO(zx.HandleInvalid)},
+ }, 48, &TestHandle2{})
+ vmo.Close()
+ })
+ t.Run("Interfaces", func(t *testing.T) {
+ h0, h1, err := zx.NewChannel(0)
+ defer h0.Close()
+ defer h1.Close()
+ if err != nil {
+ t.Fatalf("failed to create vmo: %v", err)
+ }
+ testIdentity(t, &TestInterface1{
+ A: Test1Interface(Proxy{Channel: h0}),
+ B: Test1Interface(Proxy{Channel: zx.Channel(zx.HandleInvalid)}),
+ C: Test1InterfaceRequest(InterfaceRequest{Channel: h1}),
+ D: Test1InterfaceRequest(InterfaceRequest{
+ Channel: zx.Channel(zx.HandleInvalid),
+ }),
+ }, 16, &TestInterface1{})
+ })
+}
diff --git a/src/syscall/zx/fidl/errors.go b/src/syscall/zx/fidl/errors.go
new file mode 100644
index 0000000..17f7e8f
--- /dev/null
+++ b/src/syscall/zx/fidl/errors.go
@@ -0,0 +1,149 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package fidl
+
+import (
+ "reflect"
+ "strconv"
+)
+
+// ValidationError represents an error produced in validating a FIDL structure.
+type ValidationError interface {
+ error
+
+ // Code returns the underlying ErrorCode value, which all ValidationErrors
+ // must have.
+ Code() ErrorCode
+}
+
+// ErrorCode represents a set of machine-readable error codes each ValidationError
+// has.
+type ErrorCode uint32
+
+const (
+ ErrUnknownOrdinal ErrorCode = iota
+ ErrInvalidInlineType
+ ErrInvalidPointerType
+ ErrVectorTooLong
+ ErrStringTooLong
+ ErrUnexpectedOrdinal
+ ErrUnexpectedNullHandle
+ ErrUnexpectedNullRef
+ ErrInvalidBoolValue
+ ErrNotEnoughHandles
+ ErrBadHandleEncoding
+ ErrBadRefEncoding
+ ErrMessageTooSmall
+ ErrStructIsNotPayload
+ ErrInvalidUnionTag
+)
+
+// Error implements error for ErrorCode
+func (e ErrorCode) Error() string {
+ switch e {
+ case ErrUnknownOrdinal:
+ return "unknown ordinal"
+ case ErrInvalidInlineType:
+ return "invalid inline type"
+ case ErrInvalidPointerType:
+ return "invalid pointer type"
+ case ErrVectorTooLong:
+ return "vector exceeds maximum size"
+ case ErrStringTooLong:
+ return "string exceeds maximum size"
+ case ErrUnexpectedOrdinal:
+ return "unexpected ordinal"
+ case ErrUnexpectedNullHandle:
+ return "unexpected null handle"
+ case ErrUnexpectedNullRef:
+ return "unexpected null reference"
+ case ErrInvalidBoolValue:
+ return "unexpected boolean value"
+ case ErrNotEnoughHandles:
+ return "not enough handles"
+ case ErrBadHandleEncoding:
+ return "bad encoding for handle"
+ case ErrBadRefEncoding:
+ return "bad encoding for ref"
+ case ErrMessageTooSmall:
+ return "message too small to have FIDL header"
+ case ErrStructIsNotPayload:
+ return "golang struct type must implement Payload"
+ default:
+ return "unknown error code"
+ }
+}
+
+// Code implements the ValidationError interface.
+func (e ErrorCode) Code() ErrorCode {
+ return e
+}
+
+// stringer is an interface for types for which a string representation
+// may be derived.
+type stringer interface {
+ String() string
+}
+
+// toString generates the string representation for a limited set of types.
+func toString(value interface{}) string {
+ if e, ok := value.(error); ok {
+ return e.Error()
+ }
+ if s, ok := value.(stringer); ok {
+ return s.String()
+ }
+ t := reflect.TypeOf(value)
+ switch t.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return strconv.FormatInt(reflect.ValueOf(value).Int(), 10)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ return strconv.FormatUint(reflect.ValueOf(value).Uint(), 10)
+ case reflect.String:
+ return value.(string)
+ default:
+ return "##BADVALUE##"
+ }
+}
+
+// valueError represents an error that refers to a single value.
+type valueError struct {
+ ErrorCode
+ value interface{}
+}
+
+func newValueError(code ErrorCode, value interface{}) valueError {
+ return valueError{
+ ErrorCode: code,
+ value: value,
+ }
+}
+
+func (e valueError) Error() string {
+ return e.ErrorCode.Error() + ": " + toString(e.value)
+}
+
+// expectError represents an error that refers to the expectation of a
+// certain value, and displays a comparison between the actual value and
+// the expected value.
+type expectError struct {
+ ErrorCode
+ expect interface{}
+ actual interface{}
+}
+
+func newExpectError(code ErrorCode, expect, actual interface{}) expectError {
+ return expectError{
+ ErrorCode: code,
+ expect: expect,
+ actual: actual,
+ }
+}
+
+func (e expectError) Error() string {
+ return e.ErrorCode.Error() + ": expected " + toString(e.expect) + ", got " + toString(e.actual)
+}
diff --git a/src/syscall/zx/fidl/interface.go b/src/syscall/zx/fidl/interface.go
new file mode 100644
index 0000000..e46f959
--- /dev/null
+++ b/src/syscall/zx/fidl/interface.go
@@ -0,0 +1,163 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package fidl
+
+import (
+ "syscall/zx"
+ "syscall/zx/zxwait"
+)
+
+// ServiceRequest is an abstraction over a FIDL interface request which is
+// intended to be used as part of service discovery.
+type ServiceRequest interface {
+ // Name returns the name of the service being requested.
+ Name() string
+
+ // ToChannel returns the underlying channel of the ServiceRequest.
+ ToChannel() zx.Channel
+}
+
+// InterfaceRequest is a wrapper type around a channel and represents the server side
+// of a FIDL interface, to be sent to a server as a request.
+type InterfaceRequest struct {
+ zx.Channel
+}
+
+// NewInterfaceRequest generates two sides of a channel with one layer of
+// type casts out of the way to minimize the amount of generated code. Semantically,
+// the two sides of the channel represent the interface request and the client
+// side of the interface (the proxy). It returns an error on failure.
+func NewInterfaceRequest() (InterfaceRequest, *Proxy, error) {
+ h0, h1, err := zx.NewChannel(0)
+ if err != nil {
+ return InterfaceRequest{}, nil, err
+ }
+ return InterfaceRequest{Channel: h0}, &Proxy{Channel: h1}, nil
+}
+
+// Proxy represents the client side of a FIDL interface.
+type Proxy struct {
+ // Channel is the underlying channel endpoint for this interface.
+ zx.Channel
+}
+
+// IsValid returns true if the underlying channel is a valid handle.
+func (p Proxy) IsValid() bool {
+ h := zx.Handle(p.Channel)
+ return h.IsValid()
+}
+
+// Send sends the request payload over the channel with the specified ordinal
+// without a response.
+func (p *Proxy) Send(ordinal uint32, req Payload) error {
+ respb := messageBytesPool.Get().([]byte)
+ resph := messageHandlesPool.Get().([]zx.Handle)
+
+ defer messageBytesPool.Put(respb)
+ defer messageHandlesPool.Put(resph)
+
+ // Marshal the message into the buffer.
+ header := MessageHeader{
+ Txid: 0, // Txid == 0 for messages without a response.
+ Ordinal: ordinal,
+ }
+ nb, nh, err := MarshalMessage(&header, req, respb[:], resph[:])
+ if err != nil {
+ return err
+ }
+
+ // Write the encoded bytes to the channel.
+ return p.Channel.Write(respb[:nb], resph[:nh], 0)
+}
+
+// Recv waits for an event and writes the response into the response payload.
+func (p *Proxy) Recv(ordinal uint32, resp Payload) error {
+ respb := messageBytesPool.Get().([]byte)
+ resph := messageHandlesPool.Get().([]zx.Handle)
+
+ defer messageBytesPool.Put(respb)
+ defer messageHandlesPool.Put(resph)
+
+ // Wait on the channel to be readable or close.
+ h := zx.Handle(p.Channel)
+ sigs, err := zxwait.Wait(h,
+ zx.SignalChannelReadable|zx.SignalChannelPeerClosed,
+ zx.TimensecInfinite,
+ )
+ if err != nil {
+ return err
+ }
+ // If it is closed and not readable, let's just report that and stop here.
+ if (sigs&zx.SignalChannelPeerClosed) != 0 && (sigs&zx.SignalChannelReadable) == 0 {
+ return &zx.Error{Status: zx.ErrPeerClosed}
+ }
+ // Otherwise, now we can read!
+ nb, nh, err := p.Channel.Read(respb[:], resph[:], 0)
+ if err != nil {
+ return err
+ }
+
+ // Unmarshal the message.
+ var header MessageHeader
+ if err := UnmarshalMessage(respb[:nb], resph[:nh], &header, resp); err != nil {
+ return err
+ }
+ if header.Ordinal != ordinal {
+ return newExpectError(ErrUnexpectedOrdinal, ordinal, header.Ordinal)
+ }
+ return nil
+}
+
+// Call sends the request payload over the channel with the specified ordinal
+// and synchronously waits for a response. It then writes the response into the
+// response payload.
+func (p *Proxy) Call(ordinal uint32, req Payload, resp Payload) error {
+ respb := messageBytesPool.Get().([]byte)
+ resph := messageHandlesPool.Get().([]zx.Handle)
+
+ defer messageBytesPool.Put(respb)
+ defer messageHandlesPool.Put(resph)
+
+ // Marshal the message into the buffer
+ header := MessageHeader{
+ Ordinal: ordinal,
+ }
+ nb, nh, err := MarshalMessage(&header, req, respb[:], resph[:])
+ if err != nil {
+ return err
+ }
+
+ // Make the IPC call.
+ cnb, cnh, err := p.Channel.Call(0, zx.TimensecInfinite, respb[:nb], resph[:nh], respb[:], resph[:])
+ if err != nil {
+ return err
+ }
+
+ // Unmarshal the message.
+ if err := UnmarshalMessage(respb[:cnb], resph[:cnh], &header, resp); err != nil {
+ return err
+ }
+ if header.Ordinal != ordinal {
+ return newExpectError(ErrUnexpectedOrdinal, ordinal, header.Ordinal)
+ }
+ return nil
+}
+
+// Stub represents a generated type which wraps the server-side implementation of a
+// FIDL interface.
+//
+// It contains logic which is able to dispatch into the correct implementation given
+// the incoming message ordinal and its data.
+type Stub interface {
+ // Dispatch dispatches into the appropriate method implementation for a FIDL
+ // interface by using the ordinal.
+ //
+ // It also takes the data as bytes and transforms it into arguments usable by
+ // the method implementation. It then optionally returns a response if the
+ // method has a response.
+ Dispatch(ordinal uint32, bytes []byte, handles []zx.Handle) (Payload, error)
+}
diff --git a/src/syscall/zx/fidl/message.go b/src/syscall/zx/fidl/message.go
new file mode 100644
index 0000000..d2417df
--- /dev/null
+++ b/src/syscall/zx/fidl/message.go
@@ -0,0 +1,68 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package fidl
+
+import (
+ "sync"
+
+ "syscall/zx"
+)
+
+// messageBytesPool is a pool of buffers that can fit the data part of any
+// FIDL message.
+var messageBytesPool = sync.Pool{
+ New: func() interface{} {
+ return make([]byte, zx.ChannelMaxMessageBytes)
+ },
+}
+
+// messageHandlesPool is a pool of buffers that can fit the handles part of
+// any FIDL message.
+var messageHandlesPool = sync.Pool{
+ New: func() interface{} {
+ return make([]zx.Handle, zx.ChannelMaxMessageHandles)
+ },
+}
+
+// MessageHeaderSize is the size of the encoded message header.
+const MessageHeaderSize int = 16
+
+// MessageHeader is a header information for a message. This struct
+// corresponds to the C type fidl_message_header_t.
+type MessageHeader struct {
+ Txid uint32
+ Reserved uint32
+ Flags uint32
+ Ordinal uint32
+}
+
+// Payload is an interface implemented by every FIDL structure.
+type Payload interface {
+ // InlineSize returns the inline size of the structure, without any
+ // out-of-line structures.
+ InlineSize() int
+
+ // InlineAlignment returns the alignment of the structure.
+ InlineAlignment() int
+}
+
+// MarshalMessage is a convenience function for marshalling a full FIDL message,
+// that is, header and payload.
+func MarshalMessage(header *MessageHeader, s Payload, data []byte, handles []zx.Handle) (int, int, error) {
+ MarshalHeader(header, data[:MessageHeaderSize])
+ nb, nh, err := Marshal(s, data[MessageHeaderSize:], handles[:])
+ return nb + MessageHeaderSize, nh, err
+}
+
+// UnmarshalMessage is a convenience function for unmarshalling a full FIDL message,
+// that is, header and payload.
+func UnmarshalMessage(data []byte, handles []zx.Handle, header *MessageHeader, s Payload) error {
+ if err := UnmarshalHeader(data[:MessageHeaderSize], header); err != nil {
+ return err
+ }
+ return Unmarshal(data[MessageHeaderSize:], handles[:], s)
+}
diff --git a/src/syscall/zx/handle.go b/src/syscall/zx/handle.go
new file mode 100644
index 0000000..8731eee
--- /dev/null
+++ b/src/syscall/zx/handle.go
@@ -0,0 +1,574 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package zx
+
+import "unsafe"
+
+// Process-wide FDIO handles.
+var (
+ StdioHandles [3][3]Handle // 3 stdio files, each with up to 3 (fdio.MaxHandles) handles
+ StdioHandleTypes [3]int
+ CwdHandle Handle
+ ProcHandle Handle
+ VMARRoot VMAR
+ RootNSMap map[string]Handle
+)
+
+const ZX_CPRNG_DRAW_MAX_LEN = 256
+
+type HandleInfo uint32
+
+func NewHandleInfo(t, arg uint32) HandleInfo {
+ return HandleInfo((t & 0xFFFF) | ((arg & 0xFFFF) << 16))
+}
+
+func (hi HandleInfo) Type() uint32 {
+ return uint32(hi) & 0xFFFF
+}
+
+func (hi HandleInfo) Arg() uint32 {
+ return (uint32(hi) >> 16) & 0xFFFF
+}
+
+type Socket Handle
+
+func (s *Socket) Handle() *Handle {
+ return (*Handle)(s)
+}
+
+func (s *Socket) Read(data []byte, flags uint32) (n int, err error) {
+ var actual uint
+ var p unsafe.Pointer
+ if len(data) > 0 {
+ p = unsafe.Pointer(&data[0])
+ }
+ status := sys_socket_read(Handle(*s), flags, p, uint(len(data)), &actual)
+ if status != ErrOk {
+ return int(actual), Error{Status: status, Text: "zx.Socket.Read"}
+ }
+ return int(actual), nil
+}
+
+func (s *Socket) Write(data []byte, flags uint32) (n int, err error) {
+ var p unsafe.Pointer
+ if len(data) > 0 {
+ p = unsafe.Pointer(&data[0])
+ }
+ var actual uint
+ status := sys_socket_write(Handle(*s), flags, p, uint(len(data)), &actual)
+ if status != ErrOk {
+ return int(actual), Error{Status: status, Text: "zx.Socket.Write"}
+ }
+ return int(actual), nil
+}
+
+func (s *Socket) Share(h Handle) error {
+ if status := sys_socket_share(Handle(*s), h); status != ErrOk {
+ return Error{Status: status, Text: "zx.Socket.Share"}
+ }
+ return nil
+}
+
+func (s *Socket) Accept(h *Handle) error {
+ if status := sys_socket_accept(Handle(*s), h); status != ErrOk {
+ return Error{Status: status, Text: "zx.Socket.Accept"}
+ }
+ return nil
+}
+
+func (s *Socket) Close() error {
+ h := Handle(*s)
+ err := h.Close()
+ *s = Socket(HandleInvalid)
+ return err
+}
+
+func NewSocket(flags uint32) (s0, s1 Socket, err error) {
+ var h0, h1 Handle
+ if status := sys_socket_create(flags, &h0, &h1); status != ErrOk {
+ return Socket(HandleInvalid), Socket(HandleInvalid), Error{Status: status, Text: "zx.Socket"}
+ }
+ return Socket(h0), Socket(h1), nil
+}
+
+type Event Handle
+
+func NewEvent(options uint32) (e Event, err error) {
+ var h Handle
+ if status := Sys_event_create(options, &h); status != ErrOk {
+ return Event(HandleInvalid), Error{Status: status, Text: "zx.Event"}
+ }
+ return Event(h), nil
+}
+
+func (e *Event) Handle() *Handle {
+ return (*Handle)(e)
+}
+
+func (e *Event) Close() error {
+ h := Handle(*e)
+ err := h.Close()
+ *e = Event(HandleInvalid)
+ return err
+}
+
+func (e *Event) Duplicate(rights Rights) (Event, error) {
+ h := Handle(*e)
+ h, err := h.Duplicate(rights)
+ if err != nil {
+ return Event(HandleInvalid), err
+ }
+ return Event(h), nil
+}
+
+func (h *Handle) Close() error {
+ if status := Sys_handle_close(*h); status != ErrOk {
+ return Error{Status: status, Text: "zx.Handle.Close"}
+ }
+ *h = HandleInvalid
+ return nil
+}
+
+func (h *Handle) Duplicate(rights Rights) (Handle, error) {
+ var dup Handle
+ if status := sys_handle_duplicate(*h, rights, &dup); status != ErrOk {
+ return HandleInvalid, Error{Status: status, Text: "zx.Handle.Duplicate"}
+ }
+ return dup, nil
+}
+
+func (h *Handle) Signal(clearMask, setMask Signals) error {
+ if status := Sys_object_signal(*h, uint32(clearMask), uint32(setMask)); status != ErrOk {
+ return Error{Status: status, Text: "zx.Handle.Signal"}
+ }
+ return nil
+}
+
+func (h *Handle) SignalPeer(clearMask, setMask Signals) error {
+ if status := Sys_object_signal_peer(*h, uint32(clearMask), uint32(setMask)); status != ErrOk {
+ return Error{Status: status, Text: "zx.Handle.SignalPeer"}
+ }
+ return nil
+}
+
+func (h *Handle) SetCookie(scope Handle, cookie uint64) error {
+ if status := Sys_object_set_cookie(*h, scope, cookie); status != ErrOk {
+ return Error{Status: status, Text: "zx.Handle.SetCookie"}
+ }
+ return nil
+}
+
+func (h *Handle) GetCookie(scope Handle) (uint64, error) {
+ var cookie uint64
+ if status := Sys_object_get_cookie(*h, scope, &cookie); status != ErrOk {
+ return 0, Error{Status: status, Text: "zx.Handle.GetCookie"}
+ }
+ return cookie, nil
+}
+
+func (h *Handle) GetProperty(property uint32, data []byte) error {
+ var numBytes = uint(len(data))
+ var dataPtr unsafe.Pointer
+ if numBytes > 0 {
+ dataPtr = unsafe.Pointer(&data[0])
+ }
+ if status := Sys_object_get_property(*h, property, dataPtr, numBytes); status != ErrOk {
+ return Error{Status: status, Text: "zx.Handle.GetProperty"}
+ }
+ return nil
+}
+
+func (h *Handle) SetProperty(property uint32, data []byte) error {
+ var numBytes = uint(len(data))
+ var dataPtr unsafe.Pointer
+ if numBytes > 0 {
+ dataPtr = unsafe.Pointer(&data[0])
+ }
+ if status := Sys_object_set_property(*h, property, dataPtr, numBytes); status != ErrOk {
+ return Error{Status: status, Text: "zx.Handle.SetProperty"}
+ }
+ return nil
+}
+
+func (h *Handle) IsValid() bool {
+ return *h > HandleInvalid
+}
+
+func WaitMany(items []WaitItem, timeout Time) error {
+ if status := sys_object_wait_many(&items[0], uint(len(items)), timeout); status != ErrOk {
+ return Error{Status: status, Text: "zx.Handle.WaitMany"}
+ }
+ return nil
+}
+
+const (
+ ChannelMaxMessageBytes = 65536
+ ChannelMaxMessageHandles = 64
+)
+
+type Channel Handle
+
+func (c *Channel) Handle() *Handle {
+ return (*Handle)(c)
+}
+
+func (c *Channel) Close() error {
+ h := Handle(*c)
+ err := h.Close()
+ *c = Channel(HandleInvalid)
+ return err
+}
+
+func (c *Channel) Read(data []byte, handles []Handle, flags uint32) (numBytes, numHandles uint32, err error) {
+ numBytes = uint32(len(data))
+ numHandles = uint32(len(handles))
+ var dataPtr unsafe.Pointer
+ if len(data) > 0 {
+ dataPtr = unsafe.Pointer(&data[0])
+ }
+ var handlePtr *Handle
+ if len(handles) > 0 {
+ handlePtr = &handles[0]
+ }
+ if status := sys_channel_read(Handle(*c), flags, dataPtr, handlePtr, numBytes, numHandles, &numBytes, &numHandles); status != ErrOk {
+ err = Error{Status: status, Text: "zx.Channel.Read"}
+ }
+ return numBytes, numHandles, err
+}
+
+func (c *Channel) Write(data []byte, handles []Handle, flags uint32) error {
+ var dataPtr unsafe.Pointer
+ if len(data) > 0 {
+ dataPtr = unsafe.Pointer(&data[0])
+ }
+ var handlePtr *Handle
+ if len(handles) > 0 {
+ handlePtr = &handles[0]
+ }
+ status := sys_channel_write(Handle(*c), flags, dataPtr, uint32(len(data)), handlePtr, uint32(len(handles)))
+ if status != ErrOk {
+ return Error{Status: status, Text: "zx.Channel.Write"}
+ }
+ return nil
+}
+
+func (c *Channel) Call(flags uint32, deadline Time, wData []byte, wHandles []Handle, rData []byte, rHandles []Handle) (actualBytes, actualHandles uint32, err error) {
+ var writeDataPtr uintptr
+ if len(wData) > 0 {
+ writeDataPtr = uintptr(unsafe.Pointer(&wData[0]))
+ }
+ var writeHandlePtr *Handle
+ if len(wHandles) > 0 {
+ writeHandlePtr = &wHandles[0]
+ }
+ var readDataPtr uintptr
+ if len(rData) > 0 {
+ readDataPtr = uintptr(unsafe.Pointer(&rData[0]))
+ }
+ var readHandlePtr *Handle
+ if len(rHandles) > 0 {
+ readHandlePtr = &rHandles[0]
+ }
+ args := &ChannelCallArgs{
+ WriteBytes: writeDataPtr,
+ WriteHandles: writeHandlePtr,
+ ReadBytes: readDataPtr,
+ ReadHandles: readHandlePtr,
+ WriteNumBytes: uint32(len(wData)),
+ WriteNumHandles: uint32(len(wHandles)),
+ ReadNumBytes: uint32(len(rData)),
+ ReadNumHandles: uint32(len(rHandles)),
+ }
+
+ status := Sys_channel_call(Handle(*c), flags, deadline, args, &actualBytes, &actualHandles)
+ if status != ErrOk {
+ err = Error{Status: status, Text: "zx.Channel.Call"}
+ }
+ return actualBytes, actualHandles, err
+}
+
+func NewChannel(flags uint32) (c0, c1 Channel, err error) {
+ var h0, h1 Handle
+ if status := sys_channel_create(flags, &h0, &h1); status != ErrOk {
+ return Channel(HandleInvalid), Channel(HandleInvalid), Error{Status: status, Text: "zx.Channel"}
+ }
+ return Channel(h0), Channel(h1), nil
+}
+
+const (
+ PortWaitAsyncOnce = iota
+ PortWaitAsyncRepeating
+)
+
+const (
+ PortPacketTypeUser = iota
+ PortPacketTypeSignalOne
+ PortPacketTypeSignalRepeating
+)
+
+const (
+ PacketHeaderSize = uint(unsafe.Sizeof(PacketHeader{}))
+ PacketMaxSize = uint(unsafe.Sizeof(Packet{}))
+)
+
+type PacketHeader struct {
+ Key uint64
+ Type uint32
+ Extra uint32
+}
+
+// Packet describes the unit of communication via an FDIO protocol
+type Packet struct {
+ Hdr PacketHeader
+ Bytes [32]uint8
+}
+
+func (p *Packet) Signal() *PacketSignal {
+ return (*PacketSignal)(unsafe.Pointer(p))
+}
+
+type PortPacket interface {
+ Header() *PacketHeader
+ Length() int
+}
+
+// PacketSignal describes packets of type PortPacketTypeSignal
+type PacketSignal struct {
+ Hdr PacketHeader
+ Trigger Signals
+ Observed Signals
+ Count uint64
+}
+
+func (s *PacketSignal) Header() *PacketHeader {
+ return &s.Hdr
+}
+
+func (s *PacketSignal) Length() int {
+ return int(unsafe.Sizeof(*s))
+}
+
+type Port Handle
+
+func (p *Port) Handle() *Handle {
+ return (*Handle)(p)
+}
+
+func (p *Port) Close() error {
+ h := Handle(*p)
+ err := h.Close()
+ *p = Port(HandleInvalid)
+ return err
+}
+
+// Queue a PortPacket, which may have a varying size.
+func (p *Port) Queue(packet PortPacket) error {
+ if status := Sys_port_queue(Handle(*p), (*int)(unsafe.Pointer(packet.Header()))); status != ErrOk {
+ return Error{Status: status, Text: "zx.Port.Queue"}
+ }
+ return nil
+}
+
+// Wait for a Packet, which must be as large as the largest
+// possible packet that may be received.
+func (p *Port) Wait(packet *Packet, deadline Time) error {
+ if status := Sys_port_wait(Handle(*p), deadline, (*int)(unsafe.Pointer(packet))); status != ErrOk {
+ return Error{Status: status, Text: "zx.Port.Wait"}
+ }
+ return nil
+}
+
+func (p *Port) Cancel(source Handle, key uint64) error {
+ if status := Sys_port_cancel(Handle(*p), source, key); status != ErrOk {
+ return Error{Status: status, Text: "zx.Port.Cancel"}
+ }
+ return nil
+}
+
+func (p *Port) WaitAsync(handle Handle, key uint64, signals Signals, options uint32) error {
+ if status := Sys_object_wait_async(handle, Handle(*p), key, signals, options); status != ErrOk {
+ return Error{Status: status, Text: "fdio.Port.WaitAsync"}
+ }
+ return nil
+}
+
+func NewPort(options uint32) (Port, error) {
+ var h Handle
+ if status := Sys_port_create(options, &h); status != ErrOk {
+ return Port(HandleInvalid), Error{Status: status, Text: "zx.Port"}
+ }
+ return Port(h), nil
+}
+
+type VMO Handle
+
+func (vmo *VMO) Handle() *Handle {
+ return (*Handle)(vmo)
+}
+
+func (vmo *VMO) Clone(options uint32, offset, size uint64) (VMO, error) {
+ var h Handle
+ if status := Sys_vmo_clone(Handle(*vmo), options, offset, size, &h); status != ErrOk {
+ return VMO(HandleInvalid), Error{Status: status, Text: "zx.VMO.Clone"}
+ }
+ return VMO(h), nil
+}
+
+func (vmo *VMO) Read(b []byte, offset uint64) error {
+ if status := sys_vmo_read(Handle(*vmo), unsafe.Pointer(&b[0]), offset, uint(len(b))); status != ErrOk {
+ return Error{Status: status, Text: "zx.VMO.Read"}
+ }
+ return nil
+}
+
+func (vmo *VMO) Write(b []byte, offset uint64) error {
+ if status := sys_vmo_write(Handle(*vmo), unsafe.Pointer(&b[0]), offset, uint(len(b))); status != ErrOk {
+ return Error{Status: status, Text: "zx.VMO.Write"}
+ }
+ return nil
+}
+
+func (vmo *VMO) Size() (uint64, error) {
+ var size uint64
+ if status := sys_vmo_get_size(Handle(*vmo), &size); status != ErrOk {
+ return size, Error{Status: status, Text: "zx.VMO.Size"}
+ }
+ return size, nil
+}
+
+func (vmo *VMO) SetSize(size uint64) error {
+ if status := sys_vmo_set_size(Handle(*vmo), size); status != ErrOk {
+ return Error{Status: status, Text: "zx.VMO.SetSize"}
+ }
+ return nil
+}
+
+func (vmo *VMO) OpRange(op uint32, offset, size uint64, b []byte) error {
+ if status := sys_vmo_op_range(Handle(*vmo), op, offset, size, unsafe.Pointer(&b[0]), uint(len(b))); status != ErrOk {
+ return Error{Status: status, Text: "zx.VMO.OpRange"}
+ }
+ return nil
+}
+
+func (vmo *VMO) Close() error {
+ h := Handle(*vmo)
+ err := h.Close()
+ *vmo = VMO(HandleInvalid)
+ return err
+}
+
+func NewVMO(size uint64, options VMOOption) (VMO, error) {
+ var h Handle
+ if status := Sys_vmo_create(size, uint32(options), &h); status != ErrOk {
+ return VMO(HandleInvalid), Error{Status: status, Text: "zx.VMO"}
+ }
+ return VMO(h), nil
+}
+
+type VMAR Handle
+
+func (v VMAR) Destroy() error {
+ if status := sys_vmar_destroy(Handle(v)); status != ErrOk {
+ return Error{Status: status, Text: "zx.VMAR.Destroy"}
+ }
+ return nil
+}
+
+var mapErr error = Error{Status: 1, Text: "zx.VMAR.Map"}
+
+func (v VMAR) Map(vmarOffset uint64, vmo VMO, vmoOffset, len uint64, flags VMFlag) (addr uintptr, err error) {
+ status := sys_vmar_map_old(Handle(v), uint64(vmarOffset), Handle(vmo), vmoOffset, uint64(len), uint32(flags), (*Vaddr)(&addr))
+ if status != ErrOk {
+ println("zx.VMAR.Map failed: status: ", status)
+ return 0, mapErr
+ }
+ return addr, nil
+}
+
+var unmapErr error = Error{Status: 1, Text: "zx.VMAR.Unmap"}
+
+func (v VMAR) Unmap(addr uintptr, len uint64) error {
+ status := Sys_vmar_unmap(Handle(v), Vaddr(addr), uint64(len))
+ if status != ErrOk {
+ println(status)
+ return unmapErr
+ }
+ return nil
+}
+
+func (v VMAR) Protect(addr uintptr, len uint64, flags VMFlag) error {
+ status := sys_vmar_protect_old(Handle(v), Vaddr(addr), uint64(len), uint32(flags))
+ if status != ErrOk {
+ return Error{Status: status, Text: "zx.VMAR.Protect"}
+ }
+ return nil
+}
+
+func NewVMAR(parent VMAR, offset, size uint64, flags VMFlag) (child VMAR, addr uintptr, err error) {
+ var childHandle Handle
+ status := sys_vmar_allocate_old(Handle(parent), uint64(offset), uint64(size), uint32(flags), &childHandle, (*Vaddr)(&addr))
+ if status != ErrOk {
+ return 0, 0, Error{Status: status, Text: "zx.NewVMAR"}
+ }
+ return VMAR(childHandle), addr, nil
+}
+
+type Log Handle
+
+func NewLog(options uint32) Log {
+ var h Handle
+ status := Sys_debuglog_create(HandleInvalid, options, &h)
+ if status != ErrOk {
+ return Log(HandleInvalid)
+ }
+ return Log(h)
+}
+
+func (l *Log) Handle() *Handle {
+ return (*Handle)(l)
+}
+
+func (l Log) Write(b []byte) (n int, err error) {
+ status := Sys_log_write(Handle(l), uint32(len(b)), unsafe.Pointer(&b[0]), 0)
+ if status != ErrOk {
+ return 0, Error{Status: status, Text: "zx.Log.Write"}
+ }
+ return len(b), nil
+}
+
+func (l Log) Read(b []byte) (n int, err error) {
+ status := Sys_log_read(Handle(l), uint32(len(b)), unsafe.Pointer(&b[0]), 0)
+ if status != ErrOk {
+ return 0, Error{Status: status, Text: "zx.Log.Read"}
+ }
+ return len(b), nil
+}
+
+func (l *Log) Close() (err error) {
+ h := Handle(*l)
+ err = h.Close()
+ *l = Log(HandleInvalid)
+ return err
+}
+
+func RandRead(b []byte) {
+ Sys_cprng_draw(unsafe.Pointer(&b[0]), uint(len(b)))
+}
+
+// Error is a Status with associated error text.
+// It is used as a Go error.
+type Error struct {
+ Status Status
+ Text string
+}
+
+func (e Error) Error() string {
+ if e.Text == "" {
+ return "zx.Status: " + e.Status.String()
+ }
+ return e.Status.String() + ": " + e.Text
+}
diff --git a/src/syscall/zx/io/impl.go b/src/syscall/zx/io/impl.go
new file mode 100644
index 0000000..26d33bd
--- /dev/null
+++ b/src/syscall/zx/io/impl.go
@@ -0,0 +1,1855 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package io
+
+import (
+ _bindings "syscall/zx/fidl"
+ _zx "syscall/zx"
+)
+
+const (
+ KOpenRightReadable uint32 = 0x00000001
+ KOpenRightWritable uint32 = 0x00000002
+ KOpenRightAdmin uint32 = 0x00000004
+ KOpenFlagCreate uint32 = 0x00010000
+ KOpenFlagCreateIfAbsent uint32 = 0x00020000
+ KOpenFlagTruncate uint32 = 0x00040000
+ KOpenFlagDirectory uint32 = 0x00080000
+ KOpenFlagAppend uint32 = 0x00100000
+ KOpenFlagNoRemote uint32 = 0x00200000
+ KOpenFlagNodeReference uint32 = 0x00400000
+ KOpenFlagDescribe uint32 = 0x00800000
+ KOpenFlagStatus uint32 = 0x01000000
+ KModeProtectionMask uint32 = 0x00FFF
+ KModeTypeMask uint32 = 0xFF000
+ KModeTypeDirectory uint32 = 0x04000
+ KModeTypeBlockDevice uint32 = 0x06000
+ KModeTypeFile uint32 = 0x08000
+ KModeTypeSocket uint32 = 0x0C000
+ KModeTypeService uint32 = 0x10000
+ KMaxIoctlHandles uint64 = 2
+ KMaxBuf uint64 = 8192
+ KNodeAttributeFlagCreationTime uint32 = 0x00000001
+ KNodeAttributeFlagModificationTime uint32 = 0x00000002
+ KVmoFlagRead uint32 = 0x00000001
+ KVmoFlagWrite uint32 = 0x00000002
+ KVmoFlagExec uint32 = 0x00000004
+ KVmoFlagPrivate uint32 = 0x00010000
+ KDirentTypeUnknown uint32 = 0
+ KDirentTypeDirectory uint32 = 4
+ KDirentTypeBlockDevice uint32 = 6
+ KDirentTypeFile uint32 = 8
+ KDirentTypeSocket uint32 = 12
+ KDirentTypeService uint32 = 16
+)
+
+type SeekOrigin uint32
+const (
+ SeekOriginStart SeekOrigin = 0
+ SeekOriginCurrent SeekOrigin = 1
+ SeekOriginEnd SeekOrigin = 2
+)
+type Service struct {
+ Reserved uint8
+}
+
+// Implements Payload.
+func (_ *Service) InlineAlignment() int {
+ return 1
+}
+
+// Implements Payload.
+func (_ *Service) InlineSize() int {
+ return 1
+}
+type FileObject struct {
+ Event _zx.Event `fidl:"*"`
+}
+
+// Implements Payload.
+func (_ *FileObject) InlineAlignment() int {
+ return 4
+}
+
+// Implements Payload.
+func (_ *FileObject) InlineSize() int {
+ return 4
+}
+type DirectoryObject struct {
+ Reserved uint8
+}
+
+// Implements Payload.
+func (_ *DirectoryObject) InlineAlignment() int {
+ return 1
+}
+
+// Implements Payload.
+func (_ *DirectoryObject) InlineSize() int {
+ return 1
+}
+type Pipe struct {
+ Socket _zx.Socket
+}
+
+// Implements Payload.
+func (_ *Pipe) InlineAlignment() int {
+ return 4
+}
+
+// Implements Payload.
+func (_ *Pipe) InlineSize() int {
+ return 4
+}
+type Vmofile struct {
+ Vmo _zx.VMO
+ Offset uint64
+ Length uint64
+}
+
+// Implements Payload.
+func (_ *Vmofile) InlineAlignment() int {
+ return 8
+}
+
+// Implements Payload.
+func (_ *Vmofile) InlineSize() int {
+ return 24
+}
+type Device struct {
+ Event _zx.Event `fidl:"*"`
+}
+
+// Implements Payload.
+func (_ *Device) InlineAlignment() int {
+ return 4
+}
+
+// Implements Payload.
+func (_ *Device) InlineSize() int {
+ return 4
+}
+type NodeAttributes struct {
+ Mode uint32
+ Id uint64
+ ContentSize uint64
+ StorageSize uint64
+ LinkCount uint64
+ CreationTime uint64
+ ModificationTime uint64
+}
+
+// Implements Payload.
+func (_ *NodeAttributes) InlineAlignment() int {
+ return 8
+}
+
+// Implements Payload.
+func (_ *NodeAttributes) InlineSize() int {
+ return 56
+}
+type ObjectInfoTag uint32
+const (
+ ObjectInfoService ObjectInfoTag = iota
+ ObjectInfoFile ObjectInfoTag = iota
+ ObjectInfoDirectory ObjectInfoTag = iota
+ ObjectInfoPipe ObjectInfoTag = iota
+ ObjectInfoVmofile ObjectInfoTag = iota
+ ObjectInfoDevice ObjectInfoTag = iota
+)
+
+// ObjectInfo is a FIDL union.
+type ObjectInfo struct {
+ ObjectInfoTag `fidl:"tag"`
+ Service Service
+ File FileObject
+ Directory DirectoryObject
+ Pipe Pipe
+ Vmofile Vmofile
+ Device Device
+}
+
+// Implements Payload.
+func (_ *ObjectInfo) InlineAlignment() int {
+ return 8
+}
+
+// Implements Payload.
+func (_ *ObjectInfo) InlineSize() int {
+ return 32
+}
+
+func (u *ObjectInfo) Which() ObjectInfoTag {
+ return u.ObjectInfoTag
+}
+
+func (u *ObjectInfo) SetService(service Service) {
+ u.ObjectInfoTag = ObjectInfoService
+ u.Service = service
+}
+
+func (u *ObjectInfo) SetFile(file FileObject) {
+ u.ObjectInfoTag = ObjectInfoFile
+ u.File = file
+}
+
+func (u *ObjectInfo) SetDirectory(directory DirectoryObject) {
+ u.ObjectInfoTag = ObjectInfoDirectory
+ u.Directory = directory
+}
+
+func (u *ObjectInfo) SetPipe(pipe Pipe) {
+ u.ObjectInfoTag = ObjectInfoPipe
+ u.Pipe = pipe
+}
+
+func (u *ObjectInfo) SetVmofile(vmofile Vmofile) {
+ u.ObjectInfoTag = ObjectInfoVmofile
+ u.Vmofile = vmofile
+}
+
+func (u *ObjectInfo) SetDevice(device Device) {
+ u.ObjectInfoTag = ObjectInfoDevice
+ u.Device = device
+}
+
+// Request for Clone.
+type ObjectCloneRequest struct {
+ Flags uint32
+ Object ObjectInterfaceRequest
+}
+
+// Implements Payload.
+func (_ *ObjectCloneRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *ObjectCloneRequest) InlineSize() int {
+ return 8
+}
+// Clone has no response.
+// Request for Close.
+type ObjectCloseRequest struct {
+}
+
+// Implements Payload.
+func (_ *ObjectCloseRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *ObjectCloseRequest) InlineSize() int {
+ return 0
+}
+// Response for Close.
+type ObjectCloseResponse struct {
+ S _zx.Status
+}
+
+// Implements Payload.
+func (_ *ObjectCloseResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *ObjectCloseResponse) InlineSize() int {
+ return 4
+}
+// Request for ListInterfaces.
+type ObjectListInterfacesRequest struct {
+}
+
+// Implements Payload.
+func (_ *ObjectListInterfacesRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *ObjectListInterfacesRequest) InlineSize() int {
+ return 0
+}
+// Response for ListInterfaces.
+type ObjectListInterfacesResponse struct {
+ Interfaces []string
+}
+
+// Implements Payload.
+func (_ *ObjectListInterfacesResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *ObjectListInterfacesResponse) InlineSize() int {
+ return 16
+}
+// Request for Bind.
+type ObjectBindRequest struct {
+ Iface string
+}
+
+// Implements Payload.
+func (_ *ObjectBindRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *ObjectBindRequest) InlineSize() int {
+ return 16
+}
+// Bind has no response.
+// Request for Describe.
+type ObjectDescribeRequest struct {
+}
+
+// Implements Payload.
+func (_ *ObjectDescribeRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *ObjectDescribeRequest) InlineSize() int {
+ return 0
+}
+// Response for Describe.
+type ObjectDescribeResponse struct {
+ Info ObjectInfo
+}
+
+// Implements Payload.
+func (_ *ObjectDescribeResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *ObjectDescribeResponse) InlineSize() int {
+ return 32
+}
+// Request for OnOpen.
+// OnOpen has no request.
+// Response for OnOpen.
+type ObjectOnOpenResponse struct {
+ S _zx.Status
+ Info *ObjectInfo
+}
+
+// Implements Payload.
+func (_ *ObjectOnOpenResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *ObjectOnOpenResponse) InlineSize() int {
+ return 16
+}
+
+type ObjectInterface _bindings.Proxy
+
+func (p *ObjectInterface) Clone(flags uint32,object ObjectInterfaceRequest) error {
+ req_ := ObjectCloneRequest{
+ Flags: flags,
+ Object: object,
+ }
+ err := ((*_bindings.Proxy)(p)).Send(2147483649, &req_)
+ return err
+}
+func (p *ObjectInterface) Close() (_zx.Status, error) {
+ req_ := ObjectCloseRequest{
+ }
+ resp_ := ObjectCloseResponse{}
+ err := ((*_bindings.Proxy)(p)).Call(2147483650, &req_, &resp_)
+ return resp_.S, err
+}
+func (p *ObjectInterface) ListInterfaces() ([]string, error) {
+ req_ := ObjectListInterfacesRequest{
+ }
+ resp_ := ObjectListInterfacesResponse{}
+ err := ((*_bindings.Proxy)(p)).Call(2147483652, &req_, &resp_)
+ return resp_.Interfaces, err
+}
+func (p *ObjectInterface) Bind(iface string) error {
+ req_ := ObjectBindRequest{
+ Iface: iface,
+ }
+ err := ((*_bindings.Proxy)(p)).Send(2147483653, &req_)
+ return err
+}
+func (p *ObjectInterface) Describe() (ObjectInfo, error) {
+ req_ := ObjectDescribeRequest{
+ }
+ resp_ := ObjectDescribeResponse{}
+ err := ((*_bindings.Proxy)(p)).Call(2147483654, &req_, &resp_)
+ return resp_.Info, err
+}
+func (p *ObjectInterface) ExpectOnOpen() (_zx.Status, *ObjectInfo, error) {
+ resp_ := ObjectOnOpenResponse{}
+ err := ((*_bindings.Proxy)(p)).Recv(2147483655, &resp_)
+ return resp_.S, resp_.Info, err
+}
+
+// Object server interface.
+type Object interface {
+ Clone(flags uint32,object ObjectInterfaceRequest) error
+ Close() (_zx.Status, error)
+ ListInterfaces() ([]string, error)
+ Bind(iface string) error
+ Describe() (ObjectInfo, error)
+}
+
+type ObjectInterfaceRequest _bindings.InterfaceRequest
+
+func NewObjectInterfaceRequest() (ObjectInterfaceRequest, *ObjectInterface, error) {
+ req, cli, err := _bindings.NewInterfaceRequest()
+ return ObjectInterfaceRequest(req), (*ObjectInterface)(cli), err
+}
+
+type ObjectStub struct {
+ Impl Object
+}
+
+func (s *ObjectStub) Dispatch(ord uint32, b_ []byte, h_ []_zx.Handle) (_bindings.Payload, error) {
+ switch ord {
+ case 2147483649:
+ in_ := ObjectCloneRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ err_ := s.Impl.Clone(in_.Flags,in_.Object)
+ return nil, err_
+ case 2147483650:
+ in_ := ObjectCloseRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := ObjectCloseResponse{}
+ s, err_ := s.Impl.Close()
+ out_.S = s
+ return &out_, err_
+ case 2147483652:
+ in_ := ObjectListInterfacesRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := ObjectListInterfacesResponse{}
+ interfaces, err_ := s.Impl.ListInterfaces()
+ out_.Interfaces = interfaces
+ return &out_, err_
+ case 2147483653:
+ in_ := ObjectBindRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ err_ := s.Impl.Bind(in_.Iface)
+ return nil, err_
+ case 2147483654:
+ in_ := ObjectDescribeRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := ObjectDescribeResponse{}
+ info, err_ := s.Impl.Describe()
+ out_.Info = info
+ return &out_, err_
+ }
+ return nil, _bindings.ErrUnknownOrdinal
+}
+
+type ObjectService struct {
+ _bindings.BindingSet
+}
+
+func (s *ObjectService) Add(impl Object, c _zx.Channel, onError func(error)) (_bindings.BindingKey, error) {
+ return s.BindingSet.Add(&ObjectStub{Impl: impl}, c, onError)
+}
+
+func (s *ObjectService) EventProxyFor(key _bindings.BindingKey) (*ObjectEventProxy, bool) {
+ pxy, err := s.BindingSet.ProxyFor(key)
+ return (*ObjectEventProxy)(pxy), err
+}
+
+type ObjectEventProxy _bindings.Proxy
+
+func (p *ObjectEventProxy) OnOpen(s _zx.Status,info *ObjectInfo) error {
+ event_ := ObjectOnOpenResponse{
+ S: s,
+ Info: info,
+ }
+ return ((*_bindings.Proxy)(p)).Send(2147483655, &event_)
+}
+
+
+
+// Request for Sync.
+type NodeSyncRequest struct {
+}
+
+// Implements Payload.
+func (_ *NodeSyncRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *NodeSyncRequest) InlineSize() int {
+ return 0
+}
+// Response for Sync.
+type NodeSyncResponse struct {
+ S _zx.Status
+}
+
+// Implements Payload.
+func (_ *NodeSyncResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *NodeSyncResponse) InlineSize() int {
+ return 4
+}
+// Request for GetAttr.
+type NodeGetAttrRequest struct {
+}
+
+// Implements Payload.
+func (_ *NodeGetAttrRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *NodeGetAttrRequest) InlineSize() int {
+ return 0
+}
+// Response for GetAttr.
+type NodeGetAttrResponse struct {
+ S _zx.Status
+ Attributes NodeAttributes
+}
+
+// Implements Payload.
+func (_ *NodeGetAttrResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *NodeGetAttrResponse) InlineSize() int {
+ return 64
+}
+// Request for SetAttr.
+type NodeSetAttrRequest struct {
+ Flags uint32
+ Attributes NodeAttributes
+}
+
+// Implements Payload.
+func (_ *NodeSetAttrRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *NodeSetAttrRequest) InlineSize() int {
+ return 64
+}
+// Response for SetAttr.
+type NodeSetAttrResponse struct {
+ S _zx.Status
+}
+
+// Implements Payload.
+func (_ *NodeSetAttrResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *NodeSetAttrResponse) InlineSize() int {
+ return 4
+}
+// Request for Ioctl.
+type NodeIoctlRequest struct {
+ Opcode uint32
+ MaxOut uint64
+ Handles []_zx.Handle `fidl:"2"`
+ In []uint8 `fidl:"8192"`
+}
+
+// Implements Payload.
+func (_ *NodeIoctlRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *NodeIoctlRequest) InlineSize() int {
+ return 48
+}
+// Response for Ioctl.
+type NodeIoctlResponse struct {
+ S _zx.Status
+ Handles []_zx.Handle `fidl:"2"`
+ Out []uint8 `fidl:"8192"`
+}
+
+// Implements Payload.
+func (_ *NodeIoctlResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *NodeIoctlResponse) InlineSize() int {
+ return 40
+}
+
+type NodeInterface _bindings.Proxy
+
+func (p *NodeInterface) Sync() (_zx.Status, error) {
+ req_ := NodeSyncRequest{
+ }
+ resp_ := NodeSyncResponse{}
+ err := ((*_bindings.Proxy)(p)).Call(2164260865, &req_, &resp_)
+ return resp_.S, err
+}
+func (p *NodeInterface) GetAttr() (_zx.Status, NodeAttributes, error) {
+ req_ := NodeGetAttrRequest{
+ }
+ resp_ := NodeGetAttrResponse{}
+ err := ((*_bindings.Proxy)(p)).Call(2164260866, &req_, &resp_)
+ return resp_.S, resp_.Attributes, err
+}
+func (p *NodeInterface) SetAttr(flags uint32,attributes NodeAttributes) (_zx.Status, error) {
+ req_ := NodeSetAttrRequest{
+ Flags: flags,
+ Attributes: attributes,
+ }
+ resp_ := NodeSetAttrResponse{}
+ err := ((*_bindings.Proxy)(p)).Call(2164260867, &req_, &resp_)
+ return resp_.S, err
+}
+func (p *NodeInterface) Ioctl(opcode uint32,maxOut uint64,handles []_zx.Handle,in []uint8) (_zx.Status, []_zx.Handle, []uint8, error) {
+ req_ := NodeIoctlRequest{
+ Opcode: opcode,
+ MaxOut: maxOut,
+ Handles: handles,
+ In: in,
+ }
+ resp_ := NodeIoctlResponse{}
+ err := ((*_bindings.Proxy)(p)).Call(2164260868, &req_, &resp_)
+ return resp_.S, resp_.Handles, resp_.Out, err
+}
+
+// Node server interface.
+type Node interface {
+ Clone(flags uint32,object ObjectInterfaceRequest) error
+ Close() (_zx.Status, error)
+ ListInterfaces() ([]string, error)
+ Bind(iface string) error
+ Describe() (ObjectInfo, error)
+ Sync() (_zx.Status, error)
+ GetAttr() (_zx.Status, NodeAttributes, error)
+ SetAttr(flags uint32,attributes NodeAttributes) (_zx.Status, error)
+ Ioctl(opcode uint32,maxOut uint64,handles []_zx.Handle,in []uint8) (_zx.Status, []_zx.Handle, []uint8, error)
+}
+
+type NodeInterfaceRequest _bindings.InterfaceRequest
+
+func NewNodeInterfaceRequest() (NodeInterfaceRequest, *NodeInterface, error) {
+ req, cli, err := _bindings.NewInterfaceRequest()
+ return NodeInterfaceRequest(req), (*NodeInterface)(cli), err
+}
+
+type NodeStub struct {
+ Impl Node
+}
+
+func (s *NodeStub) Dispatch(ord uint32, b_ []byte, h_ []_zx.Handle) (_bindings.Payload, error) {
+ switch ord {
+ case 2147483649:
+ in_ := ObjectCloneRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ err_ := s.Impl.Clone(in_.Flags,in_.Object)
+ return nil, err_
+ case 2147483650:
+ in_ := ObjectCloseRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := ObjectCloseResponse{}
+ s, err_ := s.Impl.Close()
+ out_.S = s
+ return &out_, err_
+ case 2147483652:
+ in_ := ObjectListInterfacesRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := ObjectListInterfacesResponse{}
+ interfaces, err_ := s.Impl.ListInterfaces()
+ out_.Interfaces = interfaces
+ return &out_, err_
+ case 2147483653:
+ in_ := ObjectBindRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ err_ := s.Impl.Bind(in_.Iface)
+ return nil, err_
+ case 2147483654:
+ in_ := ObjectDescribeRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := ObjectDescribeResponse{}
+ info, err_ := s.Impl.Describe()
+ out_.Info = info
+ return &out_, err_
+ case 2164260865:
+ in_ := NodeSyncRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := NodeSyncResponse{}
+ s, err_ := s.Impl.Sync()
+ out_.S = s
+ return &out_, err_
+ case 2164260866:
+ in_ := NodeGetAttrRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := NodeGetAttrResponse{}
+ s, attributes, err_ := s.Impl.GetAttr()
+ out_.S = s
+ out_.Attributes = attributes
+ return &out_, err_
+ case 2164260867:
+ in_ := NodeSetAttrRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := NodeSetAttrResponse{}
+ s, err_ := s.Impl.SetAttr(in_.Flags,in_.Attributes)
+ out_.S = s
+ return &out_, err_
+ case 2164260868:
+ in_ := NodeIoctlRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := NodeIoctlResponse{}
+ s, handles, out, err_ := s.Impl.Ioctl(in_.Opcode,in_.MaxOut,in_.Handles,in_.In)
+ out_.S = s
+ out_.Handles = handles
+ out_.Out = out
+ return &out_, err_
+ }
+ return nil, _bindings.ErrUnknownOrdinal
+}
+
+type NodeService struct {
+ _bindings.BindingSet
+}
+
+func (s *NodeService) Add(impl Node, c _zx.Channel, onError func(error)) (_bindings.BindingKey, error) {
+ return s.BindingSet.Add(&NodeStub{Impl: impl}, c, onError)
+}
+
+func (s *NodeService) EventProxyFor(key _bindings.BindingKey) (*NodeEventProxy, bool) {
+ pxy, err := s.BindingSet.ProxyFor(key)
+ return (*NodeEventProxy)(pxy), err
+}
+
+type NodeEventProxy _bindings.Proxy
+
+func (p *NodeEventProxy) OnOpen(s _zx.Status,info *ObjectInfo) error {
+ event_ := ObjectOnOpenResponse{
+ S: s,
+ Info: info,
+ }
+ return ((*_bindings.Proxy)(p)).Send(2147483655, &event_)
+}
+
+
+
+// Request for Read.
+type FileReadRequest struct {
+ Count uint64
+}
+
+// Implements Payload.
+func (_ *FileReadRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *FileReadRequest) InlineSize() int {
+ return 8
+}
+// Response for Read.
+type FileReadResponse struct {
+ S _zx.Status
+ Data []uint8 `fidl:"8192"`
+}
+
+// Implements Payload.
+func (_ *FileReadResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *FileReadResponse) InlineSize() int {
+ return 24
+}
+// Request for ReadAt.
+type FileReadAtRequest struct {
+ Count uint64
+ Offset uint64
+}
+
+// Implements Payload.
+func (_ *FileReadAtRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *FileReadAtRequest) InlineSize() int {
+ return 16
+}
+// Response for ReadAt.
+type FileReadAtResponse struct {
+ S _zx.Status
+ Data []uint8 `fidl:"8192"`
+}
+
+// Implements Payload.
+func (_ *FileReadAtResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *FileReadAtResponse) InlineSize() int {
+ return 24
+}
+// Request for Write.
+type FileWriteRequest struct {
+ Data []uint8 `fidl:"8192"`
+}
+
+// Implements Payload.
+func (_ *FileWriteRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *FileWriteRequest) InlineSize() int {
+ return 16
+}
+// Response for Write.
+type FileWriteResponse struct {
+ S _zx.Status
+ Actual uint64
+}
+
+// Implements Payload.
+func (_ *FileWriteResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *FileWriteResponse) InlineSize() int {
+ return 16
+}
+// Request for WriteAt.
+type FileWriteAtRequest struct {
+ Data []uint8 `fidl:"8192"`
+ Offset uint64
+}
+
+// Implements Payload.
+func (_ *FileWriteAtRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *FileWriteAtRequest) InlineSize() int {
+ return 24
+}
+// Response for WriteAt.
+type FileWriteAtResponse struct {
+ S _zx.Status
+ Actual uint64
+}
+
+// Implements Payload.
+func (_ *FileWriteAtResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *FileWriteAtResponse) InlineSize() int {
+ return 16
+}
+// Request for Seek.
+type FileSeekRequest struct {
+ Offset int64
+ Start SeekOrigin
+}
+
+// Implements Payload.
+func (_ *FileSeekRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *FileSeekRequest) InlineSize() int {
+ return 16
+}
+// Response for Seek.
+type FileSeekResponse struct {
+ S _zx.Status
+ Offset uint64
+}
+
+// Implements Payload.
+func (_ *FileSeekResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *FileSeekResponse) InlineSize() int {
+ return 16
+}
+// Request for Truncate.
+type FileTruncateRequest struct {
+ Length uint64
+}
+
+// Implements Payload.
+func (_ *FileTruncateRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *FileTruncateRequest) InlineSize() int {
+ return 8
+}
+// Response for Truncate.
+type FileTruncateResponse struct {
+ S _zx.Status
+}
+
+// Implements Payload.
+func (_ *FileTruncateResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *FileTruncateResponse) InlineSize() int {
+ return 4
+}
+// Request for GetFlags.
+type FileGetFlagsRequest struct {
+}
+
+// Implements Payload.
+func (_ *FileGetFlagsRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *FileGetFlagsRequest) InlineSize() int {
+ return 0
+}
+// Response for GetFlags.
+type FileGetFlagsResponse struct {
+ S _zx.Status
+ Flags uint32
+}
+
+// Implements Payload.
+func (_ *FileGetFlagsResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *FileGetFlagsResponse) InlineSize() int {
+ return 8
+}
+// Request for SetFlags.
+type FileSetFlagsRequest struct {
+ Flags uint32
+}
+
+// Implements Payload.
+func (_ *FileSetFlagsRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *FileSetFlagsRequest) InlineSize() int {
+ return 4
+}
+// Response for SetFlags.
+type FileSetFlagsResponse struct {
+ S _zx.Status
+}
+
+// Implements Payload.
+func (_ *FileSetFlagsResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *FileSetFlagsResponse) InlineSize() int {
+ return 4
+}
+// Request for GetVmo.
+type FileGetVmoRequest struct {
+ Flags uint32
+}
+
+// Implements Payload.
+func (_ *FileGetVmoRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *FileGetVmoRequest) InlineSize() int {
+ return 4
+}
+// Response for GetVmo.
+type FileGetVmoResponse struct {
+ S _zx.Status
+ Vmo _zx.VMO
+}
+
+// Implements Payload.
+func (_ *FileGetVmoResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *FileGetVmoResponse) InlineSize() int {
+ return 8
+}
+// Request for GetVmoAt.
+type FileGetVmoAtRequest struct {
+ Flags uint32
+ Offset uint64
+ Length uint64
+}
+
+// Implements Payload.
+func (_ *FileGetVmoAtRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *FileGetVmoAtRequest) InlineSize() int {
+ return 24
+}
+// Response for GetVmoAt.
+type FileGetVmoAtResponse struct {
+ S _zx.Status
+ Vmo _zx.VMO
+}
+
+// Implements Payload.
+func (_ *FileGetVmoAtResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *FileGetVmoAtResponse) InlineSize() int {
+ return 8
+}
+
+type FileInterface _bindings.Proxy
+
+func (p *FileInterface) Read(count uint64) (_zx.Status, []uint8, error) {
+ req_ := FileReadRequest{
+ Count: count,
+ }
+ resp_ := FileReadResponse{}
+ err := ((*_bindings.Proxy)(p)).Call(2181038081, &req_, &resp_)
+ return resp_.S, resp_.Data, err
+}
+func (p *FileInterface) ReadAt(count uint64,offset uint64) (_zx.Status, []uint8, error) {
+ req_ := FileReadAtRequest{
+ Count: count,
+ Offset: offset,
+ }
+ resp_ := FileReadAtResponse{}
+ err := ((*_bindings.Proxy)(p)).Call(2181038082, &req_, &resp_)
+ return resp_.S, resp_.Data, err
+}
+func (p *FileInterface) Write(data []uint8) (_zx.Status, uint64, error) {
+ req_ := FileWriteRequest{
+ Data: data,
+ }
+ resp_ := FileWriteResponse{}
+ err := ((*_bindings.Proxy)(p)).Call(2181038083, &req_, &resp_)
+ return resp_.S, resp_.Actual, err
+}
+func (p *FileInterface) WriteAt(data []uint8,offset uint64) (_zx.Status, uint64, error) {
+ req_ := FileWriteAtRequest{
+ Data: data,
+ Offset: offset,
+ }
+ resp_ := FileWriteAtResponse{}
+ err := ((*_bindings.Proxy)(p)).Call(2181038084, &req_, &resp_)
+ return resp_.S, resp_.Actual, err
+}
+func (p *FileInterface) Seek(offset int64,start SeekOrigin) (_zx.Status, uint64, error) {
+ req_ := FileSeekRequest{
+ Offset: offset,
+ Start: start,
+ }
+ resp_ := FileSeekResponse{}
+ err := ((*_bindings.Proxy)(p)).Call(2181038085, &req_, &resp_)
+ return resp_.S, resp_.Offset, err
+}
+func (p *FileInterface) Truncate(length uint64) (_zx.Status, error) {
+ req_ := FileTruncateRequest{
+ Length: length,
+ }
+ resp_ := FileTruncateResponse{}
+ err := ((*_bindings.Proxy)(p)).Call(2181038086, &req_, &resp_)
+ return resp_.S, err
+}
+func (p *FileInterface) GetFlags() (_zx.Status, uint32, error) {
+ req_ := FileGetFlagsRequest{
+ }
+ resp_ := FileGetFlagsResponse{}
+ err := ((*_bindings.Proxy)(p)).Call(2181038087, &req_, &resp_)
+ return resp_.S, resp_.Flags, err
+}
+func (p *FileInterface) SetFlags(flags uint32) (_zx.Status, error) {
+ req_ := FileSetFlagsRequest{
+ Flags: flags,
+ }
+ resp_ := FileSetFlagsResponse{}
+ err := ((*_bindings.Proxy)(p)).Call(2181038088, &req_, &resp_)
+ return resp_.S, err
+}
+func (p *FileInterface) GetVmo(flags uint32) (_zx.Status, _zx.VMO, error) {
+ req_ := FileGetVmoRequest{
+ Flags: flags,
+ }
+ resp_ := FileGetVmoResponse{}
+ err := ((*_bindings.Proxy)(p)).Call(2181038089, &req_, &resp_)
+ return resp_.S, resp_.Vmo, err
+}
+func (p *FileInterface) GetVmoAt(flags uint32,offset uint64,length uint64) (_zx.Status, _zx.VMO, error) {
+ req_ := FileGetVmoAtRequest{
+ Flags: flags,
+ Offset: offset,
+ Length: length,
+ }
+ resp_ := FileGetVmoAtResponse{}
+ err := ((*_bindings.Proxy)(p)).Call(2181038090, &req_, &resp_)
+ return resp_.S, resp_.Vmo, err
+}
+
+// File server interface.
+type File interface {
+ Clone(flags uint32,object ObjectInterfaceRequest) error
+ Close() (_zx.Status, error)
+ ListInterfaces() ([]string, error)
+ Bind(iface string) error
+ Describe() (ObjectInfo, error)
+ Sync() (_zx.Status, error)
+ GetAttr() (_zx.Status, NodeAttributes, error)
+ SetAttr(flags uint32,attributes NodeAttributes) (_zx.Status, error)
+ Ioctl(opcode uint32,maxOut uint64,handles []_zx.Handle,in []uint8) (_zx.Status, []_zx.Handle, []uint8, error)
+ Read(count uint64) (_zx.Status, []uint8, error)
+ ReadAt(count uint64,offset uint64) (_zx.Status, []uint8, error)
+ Write(data []uint8) (_zx.Status, uint64, error)
+ WriteAt(data []uint8,offset uint64) (_zx.Status, uint64, error)
+ Seek(offset int64,start SeekOrigin) (_zx.Status, uint64, error)
+ Truncate(length uint64) (_zx.Status, error)
+ GetFlags() (_zx.Status, uint32, error)
+ SetFlags(flags uint32) (_zx.Status, error)
+ GetVmo(flags uint32) (_zx.Status, _zx.VMO, error)
+ GetVmoAt(flags uint32,offset uint64,length uint64) (_zx.Status, _zx.VMO, error)
+}
+
+type FileInterfaceRequest _bindings.InterfaceRequest
+
+func NewFileInterfaceRequest() (FileInterfaceRequest, *FileInterface, error) {
+ req, cli, err := _bindings.NewInterfaceRequest()
+ return FileInterfaceRequest(req), (*FileInterface)(cli), err
+}
+
+type FileStub struct {
+ Impl File
+}
+
+func (s *FileStub) Dispatch(ord uint32, b_ []byte, h_ []_zx.Handle) (_bindings.Payload, error) {
+ switch ord {
+ case 2147483649:
+ in_ := ObjectCloneRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ err_ := s.Impl.Clone(in_.Flags,in_.Object)
+ return nil, err_
+ case 2147483650:
+ in_ := ObjectCloseRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := ObjectCloseResponse{}
+ s, err_ := s.Impl.Close()
+ out_.S = s
+ return &out_, err_
+ case 2147483652:
+ in_ := ObjectListInterfacesRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := ObjectListInterfacesResponse{}
+ interfaces, err_ := s.Impl.ListInterfaces()
+ out_.Interfaces = interfaces
+ return &out_, err_
+ case 2147483653:
+ in_ := ObjectBindRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ err_ := s.Impl.Bind(in_.Iface)
+ return nil, err_
+ case 2147483654:
+ in_ := ObjectDescribeRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := ObjectDescribeResponse{}
+ info, err_ := s.Impl.Describe()
+ out_.Info = info
+ return &out_, err_
+ case 2164260865:
+ in_ := NodeSyncRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := NodeSyncResponse{}
+ s, err_ := s.Impl.Sync()
+ out_.S = s
+ return &out_, err_
+ case 2164260866:
+ in_ := NodeGetAttrRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := NodeGetAttrResponse{}
+ s, attributes, err_ := s.Impl.GetAttr()
+ out_.S = s
+ out_.Attributes = attributes
+ return &out_, err_
+ case 2164260867:
+ in_ := NodeSetAttrRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := NodeSetAttrResponse{}
+ s, err_ := s.Impl.SetAttr(in_.Flags,in_.Attributes)
+ out_.S = s
+ return &out_, err_
+ case 2164260868:
+ in_ := NodeIoctlRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := NodeIoctlResponse{}
+ s, handles, out, err_ := s.Impl.Ioctl(in_.Opcode,in_.MaxOut,in_.Handles,in_.In)
+ out_.S = s
+ out_.Handles = handles
+ out_.Out = out
+ return &out_, err_
+ case 2181038081:
+ in_ := FileReadRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := FileReadResponse{}
+ s, data, err_ := s.Impl.Read(in_.Count)
+ out_.S = s
+ out_.Data = data
+ return &out_, err_
+ case 2181038082:
+ in_ := FileReadAtRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := FileReadAtResponse{}
+ s, data, err_ := s.Impl.ReadAt(in_.Count,in_.Offset)
+ out_.S = s
+ out_.Data = data
+ return &out_, err_
+ case 2181038083:
+ in_ := FileWriteRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := FileWriteResponse{}
+ s, actual, err_ := s.Impl.Write(in_.Data)
+ out_.S = s
+ out_.Actual = actual
+ return &out_, err_
+ case 2181038084:
+ in_ := FileWriteAtRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := FileWriteAtResponse{}
+ s, actual, err_ := s.Impl.WriteAt(in_.Data,in_.Offset)
+ out_.S = s
+ out_.Actual = actual
+ return &out_, err_
+ case 2181038085:
+ in_ := FileSeekRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := FileSeekResponse{}
+ s, offset, err_ := s.Impl.Seek(in_.Offset,in_.Start)
+ out_.S = s
+ out_.Offset = offset
+ return &out_, err_
+ case 2181038086:
+ in_ := FileTruncateRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := FileTruncateResponse{}
+ s, err_ := s.Impl.Truncate(in_.Length)
+ out_.S = s
+ return &out_, err_
+ case 2181038087:
+ in_ := FileGetFlagsRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := FileGetFlagsResponse{}
+ s, flags, err_ := s.Impl.GetFlags()
+ out_.S = s
+ out_.Flags = flags
+ return &out_, err_
+ case 2181038088:
+ in_ := FileSetFlagsRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := FileSetFlagsResponse{}
+ s, err_ := s.Impl.SetFlags(in_.Flags)
+ out_.S = s
+ return &out_, err_
+ case 2181038089:
+ in_ := FileGetVmoRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := FileGetVmoResponse{}
+ s, vmo, err_ := s.Impl.GetVmo(in_.Flags)
+ out_.S = s
+ out_.Vmo = vmo
+ return &out_, err_
+ case 2181038090:
+ in_ := FileGetVmoAtRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := FileGetVmoAtResponse{}
+ s, vmo, err_ := s.Impl.GetVmoAt(in_.Flags,in_.Offset,in_.Length)
+ out_.S = s
+ out_.Vmo = vmo
+ return &out_, err_
+ }
+ return nil, _bindings.ErrUnknownOrdinal
+}
+
+type FileService struct {
+ _bindings.BindingSet
+}
+
+func (s *FileService) Add(impl File, c _zx.Channel, onError func(error)) (_bindings.BindingKey, error) {
+ return s.BindingSet.Add(&FileStub{Impl: impl}, c, onError)
+}
+
+func (s *FileService) EventProxyFor(key _bindings.BindingKey) (*FileEventProxy, bool) {
+ pxy, err := s.BindingSet.ProxyFor(key)
+ return (*FileEventProxy)(pxy), err
+}
+
+type FileEventProxy _bindings.Proxy
+
+func (p *FileEventProxy) OnOpen(s _zx.Status,info *ObjectInfo) error {
+ event_ := ObjectOnOpenResponse{
+ S: s,
+ Info: info,
+ }
+ return ((*_bindings.Proxy)(p)).Send(2147483655, &event_)
+}
+
+
+
+// Request for Open.
+type DirectoryOpenRequest struct {
+ Flags uint32
+ Mode uint32
+ Path string
+ Object ObjectInterfaceRequest
+}
+
+// Implements Payload.
+func (_ *DirectoryOpenRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryOpenRequest) InlineSize() int {
+ return 32
+}
+// Open has no response.
+// Request for Unlink.
+type DirectoryUnlinkRequest struct {
+ Path string
+}
+
+// Implements Payload.
+func (_ *DirectoryUnlinkRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryUnlinkRequest) InlineSize() int {
+ return 16
+}
+// Response for Unlink.
+type DirectoryUnlinkResponse struct {
+ S _zx.Status
+}
+
+// Implements Payload.
+func (_ *DirectoryUnlinkResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryUnlinkResponse) InlineSize() int {
+ return 4
+}
+// Request for ReadDirents.
+type DirectoryReadDirentsRequest struct {
+ MaxOut uint64
+}
+
+// Implements Payload.
+func (_ *DirectoryReadDirentsRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryReadDirentsRequest) InlineSize() int {
+ return 8
+}
+// Response for ReadDirents.
+type DirectoryReadDirentsResponse struct {
+ S _zx.Status
+ Dirents []uint8 `fidl:"8192"`
+}
+
+// Implements Payload.
+func (_ *DirectoryReadDirentsResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryReadDirentsResponse) InlineSize() int {
+ return 24
+}
+// Request for Rewind.
+type DirectoryRewindRequest struct {
+}
+
+// Implements Payload.
+func (_ *DirectoryRewindRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryRewindRequest) InlineSize() int {
+ return 0
+}
+// Response for Rewind.
+type DirectoryRewindResponse struct {
+ S _zx.Status
+}
+
+// Implements Payload.
+func (_ *DirectoryRewindResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryRewindResponse) InlineSize() int {
+ return 4
+}
+// Request for GetToken.
+type DirectoryGetTokenRequest struct {
+}
+
+// Implements Payload.
+func (_ *DirectoryGetTokenRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryGetTokenRequest) InlineSize() int {
+ return 0
+}
+// Response for GetToken.
+type DirectoryGetTokenResponse struct {
+ S _zx.Status
+ Token _zx.Handle
+}
+
+// Implements Payload.
+func (_ *DirectoryGetTokenResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryGetTokenResponse) InlineSize() int {
+ return 8
+}
+// Request for Rename.
+type DirectoryRenameRequest struct {
+ Src string
+ DstParentToken _zx.Handle
+ Dst string
+}
+
+// Implements Payload.
+func (_ *DirectoryRenameRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryRenameRequest) InlineSize() int {
+ return 40
+}
+// Response for Rename.
+type DirectoryRenameResponse struct {
+ S _zx.Status
+}
+
+// Implements Payload.
+func (_ *DirectoryRenameResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryRenameResponse) InlineSize() int {
+ return 4
+}
+// Request for Link.
+type DirectoryLinkRequest struct {
+ Src string
+ DstParentToken _zx.Handle
+ Dst string
+}
+
+// Implements Payload.
+func (_ *DirectoryLinkRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryLinkRequest) InlineSize() int {
+ return 40
+}
+// Response for Link.
+type DirectoryLinkResponse struct {
+ S _zx.Status
+}
+
+// Implements Payload.
+func (_ *DirectoryLinkResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryLinkResponse) InlineSize() int {
+ return 4
+}
+
+type DirectoryInterface _bindings.Proxy
+
+func (p *DirectoryInterface) Open(flags uint32,mode uint32,path string,object ObjectInterfaceRequest) error {
+ req_ := DirectoryOpenRequest{
+ Flags: flags,
+ Mode: mode,
+ Path: path,
+ Object: object,
+ }
+ err := ((*_bindings.Proxy)(p)).Send(2197815297, &req_)
+ return err
+}
+func (p *DirectoryInterface) Unlink(path string) (_zx.Status, error) {
+ req_ := DirectoryUnlinkRequest{
+ Path: path,
+ }
+ resp_ := DirectoryUnlinkResponse{}
+ err := ((*_bindings.Proxy)(p)).Call(2197815298, &req_, &resp_)
+ return resp_.S, err
+}
+func (p *DirectoryInterface) ReadDirents(maxOut uint64) (_zx.Status, []uint8, error) {
+ req_ := DirectoryReadDirentsRequest{
+ MaxOut: maxOut,
+ }
+ resp_ := DirectoryReadDirentsResponse{}
+ err := ((*_bindings.Proxy)(p)).Call(2197815299, &req_, &resp_)
+ return resp_.S, resp_.Dirents, err
+}
+func (p *DirectoryInterface) Rewind() (_zx.Status, error) {
+ req_ := DirectoryRewindRequest{
+ }
+ resp_ := DirectoryRewindResponse{}
+ err := ((*_bindings.Proxy)(p)).Call(2197815300, &req_, &resp_)
+ return resp_.S, err
+}
+func (p *DirectoryInterface) GetToken() (_zx.Status, _zx.Handle, error) {
+ req_ := DirectoryGetTokenRequest{
+ }
+ resp_ := DirectoryGetTokenResponse{}
+ err := ((*_bindings.Proxy)(p)).Call(2197815301, &req_, &resp_)
+ return resp_.S, resp_.Token, err
+}
+func (p *DirectoryInterface) Rename(src string,dstParentToken _zx.Handle,dst string) (_zx.Status, error) {
+ req_ := DirectoryRenameRequest{
+ Src: src,
+ DstParentToken: dstParentToken,
+ Dst: dst,
+ }
+ resp_ := DirectoryRenameResponse{}
+ err := ((*_bindings.Proxy)(p)).Call(2197815302, &req_, &resp_)
+ return resp_.S, err
+}
+func (p *DirectoryInterface) Link(src string,dstParentToken _zx.Handle,dst string) (_zx.Status, error) {
+ req_ := DirectoryLinkRequest{
+ Src: src,
+ DstParentToken: dstParentToken,
+ Dst: dst,
+ }
+ resp_ := DirectoryLinkResponse{}
+ err := ((*_bindings.Proxy)(p)).Call(2197815303, &req_, &resp_)
+ return resp_.S, err
+}
+
+// Directory server interface.
+type Directory interface {
+ Clone(flags uint32,object ObjectInterfaceRequest) error
+ Close() (_zx.Status, error)
+ ListInterfaces() ([]string, error)
+ Bind(iface string) error
+ Describe() (ObjectInfo, error)
+ Sync() (_zx.Status, error)
+ GetAttr() (_zx.Status, NodeAttributes, error)
+ SetAttr(flags uint32,attributes NodeAttributes) (_zx.Status, error)
+ Ioctl(opcode uint32,maxOut uint64,handles []_zx.Handle,in []uint8) (_zx.Status, []_zx.Handle, []uint8, error)
+ Open(flags uint32,mode uint32,path string,object ObjectInterfaceRequest) error
+ Unlink(path string) (_zx.Status, error)
+ ReadDirents(maxOut uint64) (_zx.Status, []uint8, error)
+ Rewind() (_zx.Status, error)
+ GetToken() (_zx.Status, _zx.Handle, error)
+ Rename(src string,dstParentToken _zx.Handle,dst string) (_zx.Status, error)
+ Link(src string,dstParentToken _zx.Handle,dst string) (_zx.Status, error)
+}
+
+type DirectoryInterfaceRequest _bindings.InterfaceRequest
+
+func NewDirectoryInterfaceRequest() (DirectoryInterfaceRequest, *DirectoryInterface, error) {
+ req, cli, err := _bindings.NewInterfaceRequest()
+ return DirectoryInterfaceRequest(req), (*DirectoryInterface)(cli), err
+}
+
+type DirectoryStub struct {
+ Impl Directory
+}
+
+func (s *DirectoryStub) Dispatch(ord uint32, b_ []byte, h_ []_zx.Handle) (_bindings.Payload, error) {
+ switch ord {
+ case 2147483649:
+ in_ := ObjectCloneRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ err_ := s.Impl.Clone(in_.Flags,in_.Object)
+ return nil, err_
+ case 2147483650:
+ in_ := ObjectCloseRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := ObjectCloseResponse{}
+ s, err_ := s.Impl.Close()
+ out_.S = s
+ return &out_, err_
+ case 2147483652:
+ in_ := ObjectListInterfacesRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := ObjectListInterfacesResponse{}
+ interfaces, err_ := s.Impl.ListInterfaces()
+ out_.Interfaces = interfaces
+ return &out_, err_
+ case 2147483653:
+ in_ := ObjectBindRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ err_ := s.Impl.Bind(in_.Iface)
+ return nil, err_
+ case 2147483654:
+ in_ := ObjectDescribeRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := ObjectDescribeResponse{}
+ info, err_ := s.Impl.Describe()
+ out_.Info = info
+ return &out_, err_
+ case 2164260865:
+ in_ := NodeSyncRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := NodeSyncResponse{}
+ s, err_ := s.Impl.Sync()
+ out_.S = s
+ return &out_, err_
+ case 2164260866:
+ in_ := NodeGetAttrRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := NodeGetAttrResponse{}
+ s, attributes, err_ := s.Impl.GetAttr()
+ out_.S = s
+ out_.Attributes = attributes
+ return &out_, err_
+ case 2164260867:
+ in_ := NodeSetAttrRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := NodeSetAttrResponse{}
+ s, err_ := s.Impl.SetAttr(in_.Flags,in_.Attributes)
+ out_.S = s
+ return &out_, err_
+ case 2164260868:
+ in_ := NodeIoctlRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := NodeIoctlResponse{}
+ s, handles, out, err_ := s.Impl.Ioctl(in_.Opcode,in_.MaxOut,in_.Handles,in_.In)
+ out_.S = s
+ out_.Handles = handles
+ out_.Out = out
+ return &out_, err_
+ case 2197815297:
+ in_ := DirectoryOpenRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ err_ := s.Impl.Open(in_.Flags,in_.Mode,in_.Path,in_.Object)
+ return nil, err_
+ case 2197815298:
+ in_ := DirectoryUnlinkRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := DirectoryUnlinkResponse{}
+ s, err_ := s.Impl.Unlink(in_.Path)
+ out_.S = s
+ return &out_, err_
+ case 2197815299:
+ in_ := DirectoryReadDirentsRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := DirectoryReadDirentsResponse{}
+ s, dirents, err_ := s.Impl.ReadDirents(in_.MaxOut)
+ out_.S = s
+ out_.Dirents = dirents
+ return &out_, err_
+ case 2197815300:
+ in_ := DirectoryRewindRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := DirectoryRewindResponse{}
+ s, err_ := s.Impl.Rewind()
+ out_.S = s
+ return &out_, err_
+ case 2197815301:
+ in_ := DirectoryGetTokenRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := DirectoryGetTokenResponse{}
+ s, token, err_ := s.Impl.GetToken()
+ out_.S = s
+ out_.Token = token
+ return &out_, err_
+ case 2197815302:
+ in_ := DirectoryRenameRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := DirectoryRenameResponse{}
+ s, err_ := s.Impl.Rename(in_.Src,in_.DstParentToken,in_.Dst)
+ out_.S = s
+ return &out_, err_
+ case 2197815303:
+ in_ := DirectoryLinkRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := DirectoryLinkResponse{}
+ s, err_ := s.Impl.Link(in_.Src,in_.DstParentToken,in_.Dst)
+ out_.S = s
+ return &out_, err_
+ }
+ return nil, _bindings.ErrUnknownOrdinal
+}
+
+type DirectoryService struct {
+ _bindings.BindingSet
+}
+
+func (s *DirectoryService) Add(impl Directory, c _zx.Channel, onError func(error)) (_bindings.BindingKey, error) {
+ return s.BindingSet.Add(&DirectoryStub{Impl: impl}, c, onError)
+}
+
+func (s *DirectoryService) EventProxyFor(key _bindings.BindingKey) (*DirectoryEventProxy, bool) {
+ pxy, err := s.BindingSet.ProxyFor(key)
+ return (*DirectoryEventProxy)(pxy), err
+}
+
+type DirectoryEventProxy _bindings.Proxy
+
+func (p *DirectoryEventProxy) OnOpen(s _zx.Status,info *ObjectInfo) error {
+ event_ := ObjectOnOpenResponse{
+ S: s,
+ Info: info,
+ }
+ return ((*_bindings.Proxy)(p)).Send(2147483655, &event_)
+}
+
diff --git a/src/syscall/zx/mkfuchsia.go b/src/syscall/zx/mkfuchsia.go
new file mode 100644
index 0000000..f717a62
--- /dev/null
+++ b/src/syscall/zx/mkfuchsia.go
@@ -0,0 +1,875 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+// Parses syscalls.abigen of Fuchsia's zircon kernel and produces Go
+// assembly for calling the system calls.
+//
+// Regenerate syscall/zx with:
+//
+// go run mkfuchsia.go -stubs > syscalls_fuchsia.go
+// go run mkfuchsia.go -goarch=amd64 > syscalls_fuchsia_amd64.s
+// go run mkfuchsia.go -goarch=arm64 > syscalls_fuchsia_arm64.s
+// gofmt -w *.go
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+ "path/filepath"
+ "strings"
+ "unicode/utf8"
+)
+
+var (
+ stubs = flag.Bool("stubs", false, "print only Go function stubs")
+ goarch = flag.String("goarch", "amd64", "arch to print asm for")
+ fuchsiaRoot = flag.String("fuchsia_root", filepath.Join(os.Getenv("HOME"), "fuchsia"), "path to fuchsia root")
+)
+
+func main() {
+ flag.Parse()
+ sdkArch := ""
+ switch *goarch {
+ case "amd64":
+ sdkArch = "x86_64"
+ case "arm64":
+ sdkArch = "aarch64"
+ default:
+ log.Fatalf("GOARCH=%s not supported", *goarch)
+ }
+ _ = sdkArch
+
+ syscallsFile := filepath.Join(*fuchsiaRoot, "/zircon/system/public/zircon/syscalls.abigen")
+ if args := flag.Args(); len(args) != 0 {
+ syscallsFile = args[0]
+ }
+
+ b, err := ioutil.ReadFile(syscallsFile)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ p := &parser{
+ buf: b,
+ line: 1,
+ name: syscallsFile,
+ }
+ syscalls, err := p.parse()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ buf := new(bytes.Buffer)
+ if *stubs {
+ fmt.Fprint(buf, stubsHeader[1:])
+ for _, call := range syscalls {
+ fmt.Fprintf(buf, "//go:cgo_import_dynamic vdso_zx_%s zx_%s \"libzircon.so\"\n", call.name, call.name)
+ }
+ fmt.Fprint(buf, "\n")
+ for _, call := range syscalls {
+ fmt.Fprintf(buf, "//go:linkname vdso_zx_%s vdso_zx_%s\n", call.name, call.name)
+ }
+ fmt.Fprint(buf, "\nvar (\n")
+ for _, call := range syscalls {
+ fmt.Fprintf(buf, "\tvdso_zx_%s uintptr\n", call.name)
+ }
+ fmt.Fprint(buf, ")\n\n")
+ for _, call := range syscalls {
+ fmt.Fprint(buf, "//go:noescape\n")
+ fmt.Fprint(buf, "//go:nosplit\n")
+ printStub(buf, call)
+ fmt.Fprint(buf, "\n")
+ }
+ } else {
+ fmt.Fprint(buf, asmHeader[1:])
+ for _, call := range syscalls {
+ fmt.Fprint(buf, "// ")
+ printStub(buf, call)
+ printAsm(buf, call)
+ fmt.Fprint(buf, "\n")
+ }
+ }
+ buf.WriteTo(os.Stdout)
+}
+
+const stubsHeader = `
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Zircon system calls for the Fuchsia OS.
+// Generated by mkfuchsia.go, do not edit.
+
+package zx
+
+import "unsafe"
+
+`
+
+const asmHeader = `
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Zircon system calls for the Fuchsia OS.
+// Generated by mkfuchsia.go, do not edit.
+
+#include "textflag.h"
+
+`
+
+func printStub(buf *bytes.Buffer, call zirconSyscallDef) {
+ fmt.Fprintf(buf, "func %s(", call.sysname())
+ for i, arg := range call.args {
+ if arg.atype == (zirconType{}) {
+ continue
+ }
+ if i > 0 {
+ fmt.Fprint(buf, ", ")
+ }
+ fmt.Fprintf(buf, "%s ", arg.aname)
+ printGoType(buf, arg.atype)
+ }
+ fmt.Fprint(buf, ")")
+ if call.ret != (zirconType{}) {
+ fmt.Fprint(buf, " ")
+ printGoType(buf, call.ret)
+ }
+ fmt.Fprint(buf, "\n")
+}
+
+// amd64RegArgs is the amd64 registers in function argument calling convention order
+var amd64RegArgs = []string{"DI", "SI", "DX", "CX", "R8", "R9", "R12", "R13"}
+
+// arm64RegArgs is the arm64 registers in function argument calling convention order
+var arm64RegArgs = []string{"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7"}
+
+// blockingSyscalls is a map of known syscalls which may block.
+var blockingSyscalls = map[string]bool{
+ "port_wait": true,
+ "object_wait_one": true,
+ "object_wait_many": true,
+}
+
+const ZIRCON_SYSCALL_MAGIC = 0x00ff00ff00000000
+
+func printAsm(buf *bytes.Buffer, call zirconSyscallDef) {
+ // The summed size of all arguments
+ argSize := 0
+ for _, arg := range call.args {
+ sz := typeSize(arg.atype)
+ if *goarch == "arm64" && sz == 1 {
+ sz = 8
+ }
+ for argSize%sz != 0 {
+ // Add padding until the 'argSize' is aligned to the type we are adding
+ argSize++
+ }
+ argSize += sz
+ }
+ if argSize%8 == 4 {
+ // Force the return argument on the stack to be 8-byte aligned, not 4-byte aligned
+ argSize += 4
+ }
+ retSize := typeSize(call.ret)
+
+ var frameSize int
+ var regArgs []string
+ var callIns, retReg, suffix4, suffix8 string
+ switch *goarch {
+ case "amd64":
+ regArgs = amd64RegArgs
+ callIns = "CALL"
+ retReg = "AX"
+ suffix8 = "Q"
+ suffix4 = "L"
+ switch len(call.args) {
+ case 7:
+ frameSize = 16 + 8
+ case 8:
+ frameSize = 16 + 2*8
+ }
+ case "arm64":
+ regArgs = arm64RegArgs
+ callIns = "BL"
+ retReg = "R0"
+ suffix8 = "D"
+ suffix4 = "W"
+ default:
+ panic(fmt.Sprintf("goarch=%s not supported", *goarch))
+ }
+
+ fmt.Fprintf(buf, "TEXT ·%s(SB),NOSPLIT,$%d-%d\n", call.sysname(), frameSize, argSize+retSize)
+
+ if _, ok := blockingSyscalls[call.name]; ok {
+ fmt.Fprintf(buf, "\tCALL runtime·entersyscall(SB)\n")
+ }
+ off := 0
+ for i, arg := range call.args {
+ name := arg.aname
+ suffix := suffix8
+ t := arg.atype
+ if typeSize(t) == 4 {
+ suffix = suffix4
+ }
+ sz := typeSize(t)
+ if *goarch == "arm64" && sz == 1 {
+ sz = 8
+ }
+ for off%sz != 0 {
+ // Add padding until the offset is aligned to the type we are accessing
+ off++
+ }
+
+ fmt.Fprintf(buf, "\tMOV%s %s+%d(FP), %s\n", suffix, name, off, regArgs[i])
+ off += sz
+ }
+ switch *goarch {
+ case "amd64":
+ if len(call.args) >= 7 {
+ fmt.Fprintf(buf, "\tMOVQ SP, BP // BP is preserved across vsdo call by the x86-64 ABI\n")
+ fmt.Fprintf(buf, "\tANDQ $~15, SP // stack alignment for x86-64 ABI\n")
+ if len(call.args) == 8 {
+ fmt.Fprintf(buf, "\tPUSHQ R13\n")
+ }
+ fmt.Fprintf(buf, "\tPUSHQ R12\n")
+ }
+ fmt.Fprintf(buf, "\tMOVQ vdso_zx_%s(SB), AX\n", call.name)
+ fmt.Fprintf(buf, "\tCALL AX\n")
+ if len(call.args) >= 7 {
+ fmt.Fprintf(buf, "\tPOPQ R12\n")
+ if len(call.args) == 8 {
+ fmt.Fprintf(buf, "\tPOPQ R13\n")
+ }
+ fmt.Fprintf(buf, "\tMOVQ BP, SP\n")
+ }
+ case "arm64":
+ fmt.Fprintf(buf, "\tBL vdso_zx_%s(SB)\n", call.name)
+ }
+ if retSize := typeSize(call.ret); retSize > 0 {
+ suffix := suffix8
+ if retSize == 4 {
+ suffix = suffix4
+ }
+ fmt.Fprintf(buf, "\tMOV%s %s, ret+%d(FP)\n", suffix, retReg, argSize)
+ }
+ if _, ok := blockingSyscalls[call.name]; ok {
+ fmt.Fprintf(buf, "\t%s runtime·exitsyscall(SB)\n", callIns)
+ }
+ fmt.Fprintf(buf, "\tRET\n")
+}
+
+func typeSize(t zirconType) int {
+ regSize := 8
+ if *goarch == "arm" {
+ regSize = 4
+ }
+ if t.isArray {
+ return regSize
+ }
+ switch t.named {
+ case zx_function_pointer:
+ return regSize
+ case zx_void:
+ return 0
+ case zx_any:
+ return 0
+ case zx_bool:
+ return 1
+ case zx_int, zx_uint, zx_uintptr_t, zx_size_t:
+ return regSize
+ case zx_char, zx_uint8_t:
+ return 1
+ case zx_int16_t, zx_uint16_t:
+ return 2
+ case zx_int32_t, zx_uint32_t:
+ return 4
+ case zx_int64_t, zx_uint64_t:
+ return 8
+ case zx_status_t:
+ return 4
+ case zx_clock_t:
+ return 4
+ case zx_time_t:
+ return 8
+ case zx_duration_t:
+ return 8
+ case zx_koid_t:
+ return 8
+ case zx_handle_t:
+ return 4
+ case zx_signals_t:
+ return 4
+ case zx_rights_t:
+ return 4
+ case zx_vaddr_t, zx_paddr_t:
+ return regSize
+ case zx_process_info_t:
+ panic("cannot pass zx_process_info_t")
+ case zx_exception_status_t, zx_exception_behaviour_t:
+ return 4
+ default:
+ panic(fmt.Sprintf("UNKNOWN(%s)", t.named))
+ }
+}
+
+func printGoType(buf *bytes.Buffer, t zirconType) {
+ if t.isArray {
+ if t.named == zx_any {
+ fmt.Fprint(buf, "unsafe.Pointer")
+ return
+ }
+ fmt.Fprint(buf, "*")
+ }
+ switch t.named {
+ case zx_void:
+ fmt.Fprint(buf, "BAD(void)")
+ case zx_any:
+ fmt.Fprint(buf, "BAD(any)")
+ case zx_bool:
+ fmt.Fprint(buf, "bool")
+ case zx_uint:
+ fmt.Fprint(buf, "uint")
+ case zx_int:
+ fmt.Fprint(buf, "int")
+ case zx_char, zx_uint8_t:
+ fmt.Fprint(buf, "uint8")
+ case zx_int16_t:
+ fmt.Fprint(buf, "int16")
+ case zx_uint16_t:
+ fmt.Fprint(buf, "uint16")
+ case zx_int32_t:
+ fmt.Fprint(buf, "int32")
+ case zx_uint32_t:
+ fmt.Fprint(buf, "uint32")
+ case zx_int64_t:
+ fmt.Fprint(buf, "int64")
+ case zx_uint64_t:
+ fmt.Fprint(buf, "uint64")
+ case zx_uintptr_t:
+ fmt.Fprint(buf, "uintptr")
+ case zx_status_t:
+ fmt.Fprint(buf, "Status")
+ case zx_clock_t:
+ fmt.Fprint(buf, "Clock")
+ case zx_time_t:
+ fmt.Fprint(buf, "Time")
+ case zx_duration_t:
+ fmt.Fprint(buf, "Duration")
+ case zx_koid_t:
+ fmt.Fprint(buf, "Koid")
+ case zx_handle_t:
+ fmt.Fprint(buf, "Handle")
+ case zx_signals_t:
+ fmt.Fprint(buf, "Signals")
+ case zx_wait_item_t:
+ fmt.Fprint(buf, "WaitItem")
+ case zx_rights_t:
+ fmt.Fprint(buf, "Rights")
+ case zx_vaddr_t:
+ fmt.Fprint(buf, "Vaddr")
+ case zx_paddr_t:
+ fmt.Fprint(buf, "Paddr")
+ case zx_size_t:
+ fmt.Fprint(buf, "uint")
+ case zx_process_info_t:
+ fmt.Fprint(buf, "ProcessInfo")
+ case zx_exception_status_t:
+ fmt.Fprint(buf, "ExceptionStatus")
+ case zx_exception_behaviour_t:
+ fmt.Fprint(buf, "ExceptionBehaviour")
+ case zx_rrec_t:
+ fmt.Fprint(buf, "Rrec")
+ case zx_channel_call_args_t:
+ fmt.Fprint(buf, "ChannelCallArgs")
+ case zx_fifo_state_t:
+ fmt.Fprint(buf, "FIFOState")
+ case zx_smc_parameters_t:
+ fmt.Fprint(buf, "SMCParameters")
+ case zx_smc_result_t:
+ fmt.Fprint(buf, "SMCResult")
+ default:
+ panic(fmt.Sprintf("UNKNOWN type: %s", t.named))
+ }
+}
+
+func (p *parser) parse() (syscalls []zirconSyscallDef, err error) {
+ if len(p.buf) == 0 {
+ return syscalls, nil
+ }
+
+ p.nextRune()
+ for {
+ t, lit := p.nextToken()
+ if lit == "syscall" {
+ call, err := p.parseSyscall()
+ if err != nil {
+ return nil, err
+ }
+ if strings.Contains(call.name, "_test") {
+ continue
+ }
+ // The PCI syscalls are DDK-only and temporary, so exclude generation of
+ // helpers for them
+ if strings.HasPrefix(call.name, "pci_") {
+ continue
+ }
+ // The hypervisor syscalls have complex parameter and return types. Skip
+ // generation for these until we need them.
+ if strings.HasPrefix(call.name, "guest_") || strings.HasPrefix(call.name, "vcpu_") {
+ continue
+ }
+ syscalls = append(syscalls, call)
+ continue
+ }
+ if t == tokenEOF {
+ return syscalls, nil
+ }
+ if t == tokenBad {
+ return nil, p.errorf("bad token: %s", lit)
+ }
+ return nil, p.errorf("unexpected token: %q (literal %q)", t, lit)
+ }
+}
+
+func (p *parser) expect(want token) {
+ t, lit := p.nextToken()
+ if t != want {
+ p.panicf("expected %q but got %q (literal %q)", want, t, lit)
+ }
+}
+
+func (p *parser) parseAttributes() (attr []string, err error) {
+ for {
+ p.skipWhitespace()
+ if p.r == '(' {
+ return
+ }
+ attr = append(attr, p.nextIdent())
+ p.skipWhitespace()
+ if p.r == ',' {
+ p.nextRune()
+ }
+ }
+}
+
+func (p *parser) parseArg() (arg zirconArg, err error) {
+ if p.r == ')' {
+ return
+ }
+ arg.aname = p.nextIdent()
+ p.expect(':')
+ atype, err := p.parseType()
+ if err != nil {
+ return
+ }
+ arg.atype = atype
+ p.skipWhitespace()
+ if isLetter(p.r) {
+ arg.constraint = p.nextIdent()
+ p.skipWhitespace()
+ }
+ return
+}
+
+func (p *parser) parseSyscall() (call zirconSyscallDef, err error) {
+ call.name = p.nextIdent()
+ attr, err := p.parseAttributes()
+ if err != nil {
+ return zirconSyscallDef{}, err
+ }
+ for _, a := range attr {
+ if a == "vdsocall" {
+ call.vdsocall = true
+ }
+ }
+ call.attr = attr
+ p.expect('(')
+ for {
+ p.skipWhitespace()
+ if p.r == ')' {
+ p.nextRune()
+ break
+ }
+ arg, err := p.parseArg()
+ if err != nil {
+ return zirconSyscallDef{}, err
+ }
+ if arg.aname == "" {
+ break
+ }
+ call.args = append(call.args, arg)
+ if p.r == ',' {
+ p.nextRune()
+ }
+ }
+ p.skipWhitespace()
+ if p.r != ';' {
+ kw := p.nextIdent()
+ if kw != "returns" {
+ p.panicf("expected \"returns\" but got \"%s\"", kw)
+ }
+ p.expect('(')
+ first := true
+ for {
+ p.skipWhitespace()
+ if p.r == ')' {
+ p.nextRune()
+ break
+ }
+ if first {
+ first = false
+ rtype, err := p.parseType()
+ if err != nil {
+ return zirconSyscallDef{}, err
+ }
+ call.ret = rtype
+ } else {
+ arg, err := p.parseArg()
+ if err != nil {
+ return zirconSyscallDef{}, err
+ }
+ // Extra return types are returned as pointers.
+ arg.atype.isArray = true
+ arg.atype.arraySize = "1"
+ call.args = append(call.args, arg)
+ }
+ if p.r == ',' {
+ p.nextRune()
+ }
+ }
+ }
+ p.skipWhitespace()
+ p.expect(';')
+ return call, nil
+}
+
+func (p *parser) parseType() (t zirconType, err error) {
+ ident := p.nextIdent()
+ n, ok := zirconTypeNamedStr[ident]
+ if !ok {
+ return t, p.errorf("unknown type name: %s", ident)
+ }
+ t.named = n
+ p.skipWhitespace()
+ if p.r == '[' {
+ p.nextRune()
+ t.isArray = true
+ t.arraySize = p.nextIdent()
+ p.skipWhitespace()
+ for p.r == '*' {
+ p.nextRune()
+ t.arraySize += " * " + p.nextIdent()
+ }
+ p.expect(']')
+ }
+ return t, nil
+}
+
+type parser struct {
+ buf []byte
+ off int
+ line, col int
+ name string
+
+ r rune
+}
+
+type token rune
+
+const (
+ tokenEOF token = -1
+ tokenBad token = -2
+ tokenIdent token = -3
+ tokenNumber token = -4
+)
+
+func (t token) String() string {
+ switch t {
+ case tokenEOF:
+ return "token(EOF)"
+ case tokenBad:
+ return "token(BAD)"
+ case tokenIdent:
+ return "token(Ident)"
+ case tokenNumber:
+ return "token(Number)"
+ default:
+ return "token(" + string(t) + ")"
+ }
+}
+
+func (p *parser) nextToken() (t token, lit string) {
+ p.skipWhitespace()
+
+ if isLetter(p.r) {
+ lit = p.nextIdent()
+ return tokenIdent, lit
+ }
+ if isNumber(p.r) {
+ lit = p.nextNumber()
+ return tokenNumber, lit
+ }
+
+ r := p.r
+ p.nextRune()
+ switch r {
+ case -1:
+ return tokenEOF, ""
+ case '(', ')', '*', ',', ';', ':', '[', ']':
+ return token(r), ""
+ case '#':
+ p.skipComment()
+ return p.nextToken()
+ }
+ return tokenBad, fmt.Sprintf("%q", r)
+}
+
+func (p *parser) nextIdent() string {
+ p.skipWhitespace()
+ if !isLetter(p.r) && !isNumber(p.r) {
+ p.panicf("expected ident but got %q", p.r)
+ }
+ off := p.off - 1
+ for isLetter(p.r) || isNumber(p.r) {
+ p.nextRune()
+ }
+ r := string(p.buf[off : p.off-1])
+ if r == "type" {
+ // "type" is a reserved word in Go.
+ return "typ"
+ }
+ return r
+}
+
+func (p *parser) nextNumber() string {
+ p.skipWhitespace()
+ if !isNumber(p.r) {
+ p.panicf("expected number but got %q", p.r)
+ }
+ off := p.off - 1
+ for isNumber(p.r) {
+ p.nextRune()
+ }
+ return string(p.buf[off : p.off-1])
+}
+
+func (p *parser) skipWhitespace() {
+ for p.r == ' ' || p.r == '\t' || p.r == '\n' {
+ p.nextRune()
+ }
+}
+
+func (p *parser) skipComment() {
+ // skip until end of line
+ p.nextRune()
+ for p.r != '\n' && p.r >= 0 {
+ p.nextRune()
+ }
+}
+
+func (p *parser) nextRune() {
+ if p.off >= len(p.buf) {
+ p.r = -1
+ return
+ }
+ if p.r == '\n' {
+ p.line++
+ p.col = 0
+ } else {
+ p.col += utf8.RuneLen(p.r)
+ }
+
+ r, w := utf8.DecodeRune(p.buf[p.off:])
+ if r == utf8.RuneError && w == 1 {
+ p.r = -1
+ p.panicf("input is not UTF-8")
+ return
+ }
+ p.r = r
+ p.off += w
+}
+
+func (p *parser) panicf(format string, args ...interface{}) {
+ panic(parsePanic{err: p.errorf(format, args...)})
+}
+
+func (p *parser) errorf(format string, args ...interface{}) error {
+ return fmt.Errorf("%s:%d:%d: %s", p.name, p.line, p.col, fmt.Sprintf(format, args...))
+}
+
+func isLetter(r rune) bool { return 'a' <= r && r <= 'z' || 'A' <= r && r <= 'Z' || r == '_' }
+func isNumber(r rune) bool { return '0' <= r && r <= '9' }
+
+type parsePanic struct {
+ err error
+}
+
+func (pp parsePanic) String() string { return pp.err.Error() }
+
+type zirconArg struct {
+ aname string
+ atype zirconType
+ constraint string
+}
+
+type zirconSyscallDef struct {
+ name string
+ ret zirconType
+ attr []string
+ args []zirconArg
+ vdsocall bool
+}
+
+func (call zirconSyscallDef) sysname() string {
+ if call.exported() {
+ return "Sys_" + call.name
+ }
+ return "sys_" + call.name
+}
+
+func (call zirconSyscallDef) exported() bool {
+ switch call.name {
+ case "handle_duplicate",
+ "object_set_profile",
+ "object_wait_many",
+ "channel_create",
+ "channel_read",
+ "channel_read_etc",
+ "channel_write",
+ "pci_get_bar",
+ "pci_map_interrupt",
+ "pci_query_irq_mode",
+ "pci_set_irq_mode",
+ "pci_init",
+ "pci_add_subtract_to_range",
+ "socket_create",
+ "socket_read",
+ "socket_write",
+ "socket_accept",
+ "socket_share",
+ "system_get_dcache_line_size",
+ "system_get_features",
+ "vmar_allocate",
+ "vmar_allocate_old",
+ "vmar_destroy",
+ "vmar_map_old",
+ "vmar_protect_old",
+ "vmo_read",
+ "vmo_write",
+ "vmo_get_size",
+ "vmo_set_size",
+ "vmo_op_range":
+ return false
+ default:
+ return true
+ }
+}
+
+type zirconType struct {
+ named zirconTypeNamed
+ isArray bool
+ arraySize string
+}
+
+type zirconTypeNamed int
+
+const (
+ zx_void zirconTypeNamed = iota
+ zx_any
+ zx_bool
+ zx_uint
+ zx_int
+ zx_char
+ zx_uint8_t
+ zx_int16_t
+ zx_uint16_t
+ zx_int32_t
+ zx_uint32_t
+ zx_int64_t
+ zx_uint64_t
+ zx_uintptr_t
+ zx_size_t
+ zx_status_t
+ zx_clock_t
+ zx_time_t
+ zx_duration_t
+ zx_koid_t
+ zx_handle_t
+ zx_signals_t
+ zx_signals_state_t
+ zx_smc_parameters_t
+ zx_smc_result_t
+ zx_wait_item_t
+ zx_rights_t
+ zx_vaddr_t
+ zx_paddr_t
+ zx_process_info_t
+ zx_exception_status_t
+ zx_exception_behaviour_t
+ zx_function_pointer
+ zx_rrec_t
+ zx_channel_call_args_t
+ zx_fifo_state_t
+)
+
+var zirconTypeNamedStr = map[string]zirconTypeNamed{
+ "any": zx_any,
+ "void": zx_void,
+ "bool": zx_bool,
+ "unsigned int": zx_uint,
+ "int": zx_int,
+ "char": zx_char,
+ "uint8_t": zx_uint8_t,
+ "int16_t": zx_int16_t,
+ "int32_t": zx_int32_t,
+ "int64_t": zx_int64_t,
+ "uint16_t": zx_uint16_t,
+ "uint32_t": zx_uint32_t,
+ "uint64_t": zx_uint64_t,
+ "uintptr_t": zx_uintptr_t,
+ "size_t": zx_size_t,
+ "zx_status_t": zx_status_t, // int32_t
+ "zx_clock_t": zx_uint32_t,
+ "zx_time_t": zx_time_t, // uint64_t monotonic time
+ "zx_duration_t": zx_duration_t, // uint64_t nanoseconds
+ "zx_koid_t": zx_koid_t,
+ "zx_handle_t": zx_handle_t, // int32_t
+ "zx_futex_t": zx_int,
+ "zx_signals_t": zx_signals_t,
+ "zx_signals_state_t": zx_signals_state_t,
+ "zx_wait_item_t": zx_wait_item_t,
+ "zx_rights_t": zx_rights_t,
+ "zx_vaddr_t": zx_vaddr_t,
+ "zx_paddr_t": zx_paddr_t,
+ "zx_smc_parameters_t": zx_smc_parameters_t,
+ "zx_smc_result_t": zx_smc_result_t,
+ "zx_process_info_t": zx_process_info_t,
+ "zx_exception_status_t": zx_exception_status_t,
+ "zx_exception_behaviour_t": zx_exception_behaviour_t,
+ "zx_function_pointer": zx_function_pointer,
+ "zx_rrec_t": zx_rrec_t,
+ "zx_channel_call_args_t": zx_channel_call_args_t,
+ "zx_fifo_state_t": zx_fifo_state_t,
+ // TODO(smklein): Remove the following temporary types. They could be blacklisted, but this is
+ // easier.
+ "zx_cache_policy_t": zx_int,
+ "zx_port_packet_t": zx_int,
+ "zx_pci_init_arg_t": zx_int,
+ "zx_pci_irq_mode_t": zx_int,
+ "zx_pci_resource_t": zx_int,
+ "zx_pcie_device_info_t": zx_int,
+ "zx_pcie_get_nth_info_t": zx_int,
+ "zx_vcpu_create_args_t": zx_int,
+ "zx_system_powerctl_arg_t": zx_int,
+ "zx_handle_info_t": zx_int,
+ "zx_profile_info_t": zx_int,
+ "zx_pci_bar_t": zx_int,
+}
diff --git a/src/syscall/zx/mxerror/mxerror.go b/src/syscall/zx/mxerror/mxerror.go
new file mode 100644
index 0000000..87d0437
--- /dev/null
+++ b/src/syscall/zx/mxerror/mxerror.go
@@ -0,0 +1,46 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package mxerror
+
+import (
+ "fmt"
+ "syscall/zx"
+)
+
+// Status extracts an zx.Status from an error.
+func Status(err error) zx.Status {
+ if err == nil {
+ return zx.ErrOk
+ }
+ if s, hasStatus := err.(zx.Error); hasStatus {
+ return s.Status
+ }
+ return zx.ErrInternal
+}
+
+// Prependf prepends a format string onto an error.
+// If the error is an zx.Error, the status code is retained.
+func Prependf(err error, format string, args ...interface{}) error {
+ str := fmt.Sprintf(format, args...)
+ if e, isError := err.(zx.Error); isError {
+ if e.Text == "" {
+ e.Text = str
+ } else {
+ e.Text = str + ": " + e.Text
+ }
+ return e
+ }
+ return fmt.Errorf("%s: %v", str, err)
+}
+
+// Errorf creates an error with an zx.Status code.
+func Errorf(s zx.Status, format string, args ...interface{}) error {
+ return zx.Error{
+ Status: s,
+ Text: fmt.Sprintf(format, args...),
+ }
+}
diff --git a/src/syscall/zx/mxnet/ctypes.go b/src/syscall/zx/mxnet/ctypes.go
new file mode 100644
index 0000000..5c1c6c9
--- /dev/null
+++ b/src/syscall/zx/mxnet/ctypes.go
@@ -0,0 +1,153 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package mxnet
+
+// Types from <lib/fdio/socket.h>.
+// These were extracted from cgo by building the program:
+//
+// package typesextract
+//
+// // #include <arpa/inet.h>
+// // #include <netdb.h>
+// // #include <netinet/in.h>
+// // #include <netinet/tcp.h>
+// // #include <sys/ioctl.h>
+// // #include <sys/socket.h>
+// // #include <sys/types.h>
+// // #include <lib/fdio/socket.h>
+// import "C"
+//
+// func F() {
+// _ = C.struct_addrinfo{}
+// _ = C.struct_sockaddr_in{}
+// _ = C.struct_sockaddr_in6{}
+// _ = C.struct_mxrio_gai_req{}
+// _ = C.struct_mxrio_gai_reply{}
+// _ = C.struct_mxrio_sockaddr_reply{}
+// _ = C.struct_mxrio_sockopt_req_reply{}
+// _ = C.struct_fdio_socket_msg{}
+// _ = C.AF_INET
+// _ = C.AF_INET6
+// _ = C.MXRIO_GAI_REQ_NODE_MAXLEN
+// _ = C.MXRIO_GAI_REQ_SERVICE_MAXLEN
+// _ = C.MXRIO_GAI_REPLY_MAX
+// }
+//
+// Then the names were cleaned up manually, with commands like:
+// s/_t$//
+// s/_Ctype_struct_/c_/
+// s/_Ctype_/c_/
+// ...
+//
+// Two big changes are c_in_port and c_in_addr, which for historcical
+// UNIX reasons have terrible type representations, so we treat them
+// as byte arrays.
+//
+// This will probably all be FIDL one day.
+
+const SOCK_STREAM = 1
+const SOCK_DGRAM = 2
+
+const AF_INET = 2
+const AF_INET6 = 10
+
+const MXRIO_GAI_REQ_NODE_MAXLEN = 256
+const MXRIO_GAI_REQ_SERVICE_MAXLEN = 256
+const MXRIO_GAI_REPLY_MAX = 4
+
+type c_socklen uint32
+type c_in_port [2]byte // uint16 in C, but stored in network order
+type c_sa_family uint16
+type c_in_addr [4]byte // uint32 in C, but stored in network order
+type c_ulong uint64
+
+type c_addrinfo struct {
+ ai_flags int32
+ ai_family int32
+ ai_socktype int32
+ ai_protocol int32
+ ai_addrlen c_socklen
+ _ [4]byte
+ // The following pointers are unused on the wire.
+ ai_addr uintptr // *c_sockaddr
+ ai_canonname uintptr // *int8
+ ai_next uintptr // *c_addrinfo
+}
+
+type c_mxrio_gai_reply struct {
+ res [MXRIO_GAI_REPLY_MAX]struct {
+ ai c_addrinfo
+ addr c_sockaddr_storage
+ }
+ nres int32
+ retval int32
+}
+
+type c_mxrio_gai_req struct {
+ node_is_null uint8
+ service_is_null uint8
+ hints_is_null uint8
+ reserved uint8
+ reserved2 uint32
+ node [MXRIO_GAI_REQ_NODE_MAXLEN]uint8
+ service [MXRIO_GAI_REQ_SERVICE_MAXLEN]uint8
+ hints c_addrinfo
+}
+
+type c_mxrio_sockaddr_reply struct {
+ addr c_sockaddr_storage
+ len c_socklen
+ _ [4]byte
+}
+
+type c_mxrio_sockopt_req_reply struct {
+ level int32
+ optname int32
+ optval [8]uint8
+ optlen c_socklen
+}
+
+type c_sockaddr struct {
+ sa_family c_sa_family
+ sa_data [14]uint8
+}
+
+type c_sockaddr_in struct {
+ sin_family c_sa_family
+ sin_port c_in_port // network order
+ sin_addr c_in_addr
+ sin_zero [8]uint8
+}
+
+type c_in6_addr [16]byte
+
+type c_sockaddr_in6 struct {
+ sin6_family c_sa_family
+ sin6_port c_in_port // network order
+ sin6_flowinfo uint32
+ sin6_addr c_in6_addr
+ sin6_scope_id uint32
+}
+
+type c_sockaddr_storage struct {
+ ss_family c_sa_family
+ _ [6]byte
+ __ss_align c_ulong
+ __ss_padding [112]uint8
+}
+
+type c_fdio_socket_msg_hdr struct {
+ addr c_sockaddr_storage
+ addrlen c_socklen
+ flags int32
+}
+
+type c_fdio_socket_msg struct {
+ hdr c_fdio_socket_msg_hdr
+ data [1]uint8
+ _ [7]byte
+}
diff --git a/src/syscall/zx/mxnet/mxnet.go b/src/syscall/zx/mxnet/mxnet.go
new file mode 100644
index 0000000..2c81b01
--- /dev/null
+++ b/src/syscall/zx/mxnet/mxnet.go
@@ -0,0 +1,154 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+// Package mxnet contains types for talking to Fuchsia's fdio net interface.
+package mxnet
+
+import (
+ "syscall/zx"
+ "unsafe"
+)
+
+const ZX_SOCKET_HALF_CLOSE = 1
+const ZX_SOCKET_READABLE = zx.SignalObject0
+const ZX_SOCKET_WRITABLE = zx.SignalObject1
+const ZX_SOCKET_PEER_CLOSED = zx.SignalObject2
+const MXSIO_SIGNAL_INCOMING = zx.SignalUser0
+const MXSIO_SIGNAL_OUTGOING = zx.SignalUser1
+const MXSIO_SIGNAL_CONNECTED = zx.SignalUser3
+const MXSIO_SIGNAL_HALFCLOSED = zx.SignalUser4
+
+// Addr is an IP address.
+// It has either len == 4 (if it is IPv4) or len == 16 (IPv6).
+type Addr string
+
+// TODO(crawshaw): consider cleaning up these interfaces by migrating to
+// an address type that captures everything:
+//
+// type Address struct {
+// Addr [16]byte
+// IPv4 bool
+// Port uint16
+// }
+
+const SockaddrLen = c_sockaddr_in6_len
+const SockmsgHdrLen = c_fdio_socket_msg_hdr_len
+const SockaddrReplyLen = c_mxrio_sockaddr_reply_len
+
+func EncodeSockmsgHdr(dst []byte, addr Addr, port uint16, flags int) (err error) {
+ if len(dst) < SockmsgHdrLen {
+ return errString("mxnet.EncodeSockmsgHdr: dst too short")
+ }
+ var n int
+ if addr != "" || port != 0 {
+ n, err = EncodeSockaddr(dst, addr, port)
+ if err != nil {
+ return err
+ }
+ }
+ hdr := (*c_fdio_socket_msg_hdr)(unsafe.Pointer(&dst[0]))
+ hdr.addrlen = c_socklen(n)
+ hdr.flags = int32(flags)
+ return nil
+}
+
+func DecodeSockmsgHdr(src []byte) (addr Addr, port uint16, flags int, err error) {
+ if len(src) < SockmsgHdrLen {
+ return "", 0, 0, errString("mxnet.DecodeSockmsgHdr: src too short")
+ }
+ addr, port, err = DecodeSockaddr(src)
+ if err != nil {
+ return "", 0, 0, err
+ }
+ hdr := (*c_fdio_socket_msg_hdr)(unsafe.Pointer(&src[0]))
+ flags = int(hdr.flags)
+ return addr, port, flags, nil
+}
+
+func DecodeSockaddr(data []byte) (addr Addr, port uint16, err error) {
+ if len(data) < 2 {
+ return "", 0, errString("mxnet:DecodeSockaddr: data too short")
+ }
+ family := uint16(data[0]) | uint16(data[1])<<8
+ switch family {
+ case AF_INET:
+ if len(data) < int(unsafe.Sizeof(c_sockaddr_in{})) {
+ return "", 0, errString("mxnet:DecodeSockaddr: data too short for ipv4")
+ }
+ v := (*c_sockaddr_in)(unsafe.Pointer(&data[0]))
+ port = uint16(data[3]) | uint16(data[2])<<8
+ if !isZeros(v.sin_addr[:]) {
+ addr = Addr(v.sin_addr[:])
+ }
+ return addr, port, nil
+ case AF_INET6:
+ if len(data) < int(unsafe.Sizeof(c_sockaddr_in6{})) {
+ return "", 0, errString("mxnet:DecodeSockaddr: data too short for ipv6")
+ }
+ v := (*c_sockaddr_in6)(unsafe.Pointer(&data[0]))
+ port = uint16(data[3]) | uint16(data[2])<<8
+ if !isZeros(v.sin6_addr[:]) {
+ addr = Addr(v.sin6_addr[:])
+ }
+ return addr, port, nil
+ default:
+ return "", 0, errString("mxnet:DecodeSockaddr: unknown family")
+ }
+}
+
+func EncodeSockaddr(dst []byte, addr Addr, port uint16) (int, error) {
+ switch len(addr) {
+ case 0, 4:
+ if len(dst) < c_sockaddr_in_len {
+ return 0, errString("mxnet: dst too small for c_sockaddr_in")
+ }
+ sockaddr := c_sockaddr_in{sin_family: AF_INET}
+ sockaddr.sin_port.setPort(port)
+ copy(sockaddr.sin_addr[:], addr)
+ srcb := (*[unsafe.Sizeof(sockaddr)]byte)(unsafe.Pointer(&sockaddr))[:]
+ return copy(dst, srcb), nil
+ case 16:
+ if len(dst) < c_sockaddr_in_len {
+ return 0, errString("mxnet: dst too small for c_sockaddr_in6")
+ }
+ sockaddr := c_sockaddr_in6{sin6_family: AF_INET6}
+ sockaddr.sin6_port.setPort(port)
+ copy(sockaddr.sin6_addr[:], addr)
+ srcb := (*[unsafe.Sizeof(sockaddr)]byte)(unsafe.Pointer(&sockaddr))[:]
+ return copy(dst, srcb), nil
+ default:
+ return 0, errString("mxnet: bad address length")
+ }
+}
+
+type errString string
+
+func (err errString) Error() string { return string(err) }
+
+const (
+ c_sockaddr_in_len = int(unsafe.Sizeof(c_sockaddr_in{}))
+ c_sockaddr_in6_len = int(unsafe.Sizeof(c_sockaddr_in6{}))
+ c_fdio_socket_msg_hdr_len = int(unsafe.Sizeof(c_fdio_socket_msg_hdr{}))
+ c_mxrio_sockaddr_reply_len = int(unsafe.Sizeof(c_mxrio_sockaddr_reply{}))
+)
+
+func (v c_in_port) port() uint16 {
+ return uint16(v[0])<<8 | uint16(v[1])
+}
+
+func (v *c_in_port) setPort(port uint16) {
+ v[0] = uint8(port >> 8)
+ v[1] = uint8(port)
+}
+
+func isZeros(buf []byte) bool {
+ for i := 0; i < len(buf); i++ {
+ if buf[i] != 0 {
+ return false
+ }
+ }
+ return true
+}
diff --git a/src/syscall/zx/mxruntime/mxruntime.go b/src/syscall/zx/mxruntime/mxruntime.go
new file mode 100644
index 0000000..39d3a4b
--- /dev/null
+++ b/src/syscall/zx/mxruntime/mxruntime.go
@@ -0,0 +1,29 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// +build fuchsia
+
+// Package mxruntime provides access to FDIO process state.
+package mxruntime
+
+// TODO: move process handle globals from mx into mxruntime.
+
+import "syscall/zx"
+
+type HandleType uint16
+
+const (
+ HandleUser0 HandleType = 0xF0
+ HandleUser1 HandleType = 0xF1
+ HandleUser2 HandleType = 0xF2
+)
+
+type HandleInfo struct {
+ Type HandleType
+ Arg uint16
+}
+
+func GetStartupHandle(info HandleInfo) zx.Handle {
+ return getStartupHandle(info)
+}
diff --git a/src/syscall/zx/mxruntime/mxruntime_cgo.go b/src/syscall/zx/mxruntime/mxruntime_cgo.go
new file mode 100644
index 0000000..af77ab1
--- /dev/null
+++ b/src/syscall/zx/mxruntime/mxruntime_cgo.go
@@ -0,0 +1,18 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// +build fuchsia
+
+package mxruntime
+
+import "syscall/zx"
+
+// #include "zircon/process.h"
+import "C"
+
+func getStartupHandle(info HandleInfo) zx.Handle {
+ id := uint32(info.Arg)<<16 | uint32(info.Type)
+ h := C.zx_take_startup_handle(C.uint32_t(id))
+ return zx.Handle(h)
+}
diff --git a/src/syscall/zx/mxruntime/mxruntime_stubs.go b/src/syscall/zx/mxruntime/mxruntime_stubs.go
new file mode 100644
index 0000000..3edf16d
--- /dev/null
+++ b/src/syscall/zx/mxruntime/mxruntime_stubs.go
@@ -0,0 +1,12 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// +build fuchsia
+// +build !cgo
+
+package mxruntime
+
+func getStartupHandle(info HandleInfo) zx.Handle {
+ panic("mxruntime.GetStartupHandle not implemented")
+}
diff --git a/src/syscall/zx/net/impl.go b/src/syscall/zx/net/impl.go
new file mode 100644
index 0000000..0934a9b
--- /dev/null
+++ b/src/syscall/zx/net/impl.go
@@ -0,0 +1,447 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// WARNING: This file is machine generated by fidlgen.
+
+// +build fuchsia
+
+package net
+
+import (
+ _bindings "syscall/zx/fidl"
+ _zx "syscall/zx"
+)
+
+const (
+)
+
+type SocketDomain uint32
+const (
+ SocketDomainInet SocketDomain = 2
+ SocketDomainInet6 SocketDomain = 10
+)
+type SocketType uint32
+const (
+ SocketTypeStream SocketType = 1
+ SocketTypeDgram SocketType = 2
+)
+type SocketProtocol uint32
+const (
+ SocketProtocolIp SocketProtocol = 0
+ SocketProtocolIcmp SocketProtocol = 1
+ SocketProtocolTcp SocketProtocol = 6
+ SocketProtocolUdp SocketProtocol = 17
+ SocketProtocolIpv6 SocketProtocol = 41
+ SocketProtocolIcmpv6 SocketProtocol = 58
+)
+type AddrInfoStatus uint32
+const (
+ AddrInfoStatusOk AddrInfoStatus = 0
+ AddrInfoStatusBadFlags AddrInfoStatus = 1
+ AddrInfoStatusNoName AddrInfoStatus = 2
+ AddrInfoStatusAgain AddrInfoStatus = 3
+ AddrInfoStatusFail AddrInfoStatus = 4
+ AddrInfoStatusNoData AddrInfoStatus = 5
+ AddrInfoStatusBufferOverflow AddrInfoStatus = 6
+ AddrInfoStatusSystemError AddrInfoStatus = 7
+)
+type IPv4Address struct {
+ Addr [4]uint8
+}
+
+// Implements Payload.
+func (_ *IPv4Address) InlineAlignment() int {
+ return 1
+}
+
+// Implements Payload.
+func (_ *IPv4Address) InlineSize() int {
+ return 4
+}
+type IPv6Address struct {
+ Addr [16]uint8
+}
+
+// Implements Payload.
+func (_ *IPv6Address) InlineAlignment() int {
+ return 1
+}
+
+// Implements Payload.
+func (_ *IPv6Address) InlineSize() int {
+ return 16
+}
+type Subnet struct {
+ Addr IpAddress
+ PrefixLen uint8
+}
+
+// Implements Payload.
+func (_ *Subnet) InlineAlignment() int {
+ return 4
+}
+
+// Implements Payload.
+func (_ *Subnet) InlineSize() int {
+ return 24
+}
+type MacAddress struct {
+ Addr [6]uint8
+}
+
+// Implements Payload.
+func (_ *MacAddress) InlineAlignment() int {
+ return 1
+}
+
+// Implements Payload.
+func (_ *MacAddress) InlineSize() int {
+ return 6
+}
+type String struct {
+ Val [256]uint8
+ Len uint32
+}
+
+// Implements Payload.
+func (_ *String) InlineAlignment() int {
+ return 4
+}
+
+// Implements Payload.
+func (_ *String) InlineSize() int {
+ return 260
+}
+type AddrInfoHints struct {
+ Flags int32
+ Family int32
+ SockType int32
+ Protocol int32
+}
+
+// Implements Payload.
+func (_ *AddrInfoHints) InlineAlignment() int {
+ return 4
+}
+
+// Implements Payload.
+func (_ *AddrInfoHints) InlineSize() int {
+ return 16
+}
+type AddrStorage struct {
+ Val [16]uint8
+ Len uint32
+}
+
+// Implements Payload.
+func (_ *AddrStorage) InlineAlignment() int {
+ return 4
+}
+
+// Implements Payload.
+func (_ *AddrStorage) InlineSize() int {
+ return 20
+}
+type AddrInfo struct {
+ Flags int32
+ Family int32
+ SockType int32
+ Protocol int32
+ IpAddr AddrStorage
+ Port uint16
+}
+
+// Implements Payload.
+func (_ *AddrInfo) InlineAlignment() int {
+ return 4
+}
+
+// Implements Payload.
+func (_ *AddrInfo) InlineSize() int {
+ return 40
+}
+type IpAddressTag uint32
+const (
+ IpAddressIpv4 IpAddressTag = iota
+ IpAddressIpv6 IpAddressTag = iota
+)
+
+// IpAddress is a FIDL union.
+type IpAddress struct {
+ IpAddressTag `fidl:"tag"`
+ Ipv4 IPv4Address
+ Ipv6 IPv6Address
+}
+
+// Implements Payload.
+func (_ *IpAddress) InlineAlignment() int {
+ return 4
+}
+
+// Implements Payload.
+func (_ *IpAddress) InlineSize() int {
+ return 20
+}
+
+func (u *IpAddress) Which() IpAddressTag {
+ return u.IpAddressTag
+}
+
+func (u *IpAddress) SetIpv4(ipv4 IPv4Address) {
+ u.IpAddressTag = IpAddressIpv4
+ u.Ipv4 = ipv4
+}
+
+func (u *IpAddress) SetIpv6(ipv6 IPv6Address) {
+ u.IpAddressTag = IpAddressIpv6
+ u.Ipv6 = ipv6
+}
+const (
+ ConnectivityOnNetworkReachableOrdinal uint32 = 1
+)
+// Request for OnNetworkReachable.
+// OnNetworkReachable has no request.
+// Response for OnNetworkReachable.
+type ConnectivityOnNetworkReachableResponse struct {
+ Reachable bool
+}
+
+// Implements Payload.
+func (_ *ConnectivityOnNetworkReachableResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *ConnectivityOnNetworkReachableResponse) InlineSize() int {
+ return 4
+}
+
+type ConnectivityInterface _bindings.Proxy
+
+func (p *ConnectivityInterface) ExpectOnNetworkReachable() (bool, error) {
+ resp_ := ConnectivityOnNetworkReachableResponse{}
+ err := ((*_bindings.Proxy)(p)).Recv(ConnectivityOnNetworkReachableOrdinal, &resp_)
+ return resp_.Reachable, err
+}
+
+// Connectivity server interface.
+type Connectivity interface {
+}
+
+type ConnectivityInterfaceRequest _bindings.InterfaceRequest
+
+func NewConnectivityInterfaceRequest() (ConnectivityInterfaceRequest, *ConnectivityInterface, error) {
+ req, cli, err := _bindings.NewInterfaceRequest()
+ return ConnectivityInterfaceRequest(req), (*ConnectivityInterface)(cli), err
+}
+// Implements ServiceRequest.
+func (_ ConnectivityInterfaceRequest) Name() string {
+ return "fuchsia.net.Connectivity"
+}
+func (c ConnectivityInterfaceRequest) ToChannel() _zx.Channel {
+ return c.Channel
+}
+
+const ConnectivityName = "fuchsia.net.Connectivity"
+
+type ConnectivityStub struct {
+ Impl Connectivity
+}
+
+func (s *ConnectivityStub) Dispatch(ord uint32, b_ []byte, h_ []_zx.Handle) (_bindings.Payload, error) {
+ switch ord {
+ }
+ return nil, _bindings.ErrUnknownOrdinal
+}
+
+type ConnectivityService struct {
+ _bindings.BindingSet
+}
+
+func (s *ConnectivityService) Add(impl Connectivity, c _zx.Channel, onError func(error)) (_bindings.BindingKey, error) {
+ return s.BindingSet.Add(&ConnectivityStub{Impl: impl}, c, onError)
+}
+
+func (s *ConnectivityService) EventProxyFor(key _bindings.BindingKey) (*ConnectivityEventProxy, bool) {
+ pxy, err := s.BindingSet.ProxyFor(key)
+ return (*ConnectivityEventProxy)(pxy), err
+}
+
+type ConnectivityEventProxy _bindings.Proxy
+
+func (p *ConnectivityEventProxy) OnNetworkReachable(reachable bool) error {
+ event_ := ConnectivityOnNetworkReachableResponse{
+ Reachable: reachable,
+ }
+ return ((*_bindings.Proxy)(p)).Send(ConnectivityOnNetworkReachableOrdinal, &event_)
+}
+
+
+const (
+ LegacySocketProviderOpenSocketOrdinal uint32 = 1
+ LegacySocketProviderGetAddrInfoOrdinal uint32 = 2
+)
+// Request for OpenSocket.
+type LegacySocketProviderOpenSocketRequest struct {
+ Domain SocketDomain
+ Type SocketType
+ Protocol SocketProtocol
+}
+
+// Implements Payload.
+func (_ *LegacySocketProviderOpenSocketRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *LegacySocketProviderOpenSocketRequest) InlineSize() int {
+ return 12
+}
+// Response for OpenSocket.
+type LegacySocketProviderOpenSocketResponse struct {
+ S _zx.Socket
+ Status int32
+}
+
+// Implements Payload.
+func (_ *LegacySocketProviderOpenSocketResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *LegacySocketProviderOpenSocketResponse) InlineSize() int {
+ return 8
+}
+// Request for GetAddrInfo.
+type LegacySocketProviderGetAddrInfoRequest struct {
+ Node *String
+ Service *String
+ Hints *AddrInfoHints
+}
+
+// Implements Payload.
+func (_ *LegacySocketProviderGetAddrInfoRequest) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *LegacySocketProviderGetAddrInfoRequest) InlineSize() int {
+ return 24
+}
+// Response for GetAddrInfo.
+type LegacySocketProviderGetAddrInfoResponse struct {
+ Status AddrInfoStatus
+ Nres int32
+ Ai0 *AddrInfo
+ Ai1 *AddrInfo
+ Ai2 *AddrInfo
+ Ai3 *AddrInfo
+}
+
+// Implements Payload.
+func (_ *LegacySocketProviderGetAddrInfoResponse) InlineAlignment() int {
+ return 0
+}
+
+// Implements Payload.
+func (_ *LegacySocketProviderGetAddrInfoResponse) InlineSize() int {
+ return 40
+}
+
+type LegacySocketProviderInterface _bindings.Proxy
+
+func (p *LegacySocketProviderInterface) OpenSocket(domain SocketDomain,type_ SocketType,protocol SocketProtocol) (_zx.Socket, int32, error) {
+ req_ := LegacySocketProviderOpenSocketRequest{
+ Domain: domain,
+ Type: type_,
+ Protocol: protocol,
+ }
+ resp_ := LegacySocketProviderOpenSocketResponse{}
+ err := ((*_bindings.Proxy)(p)).Call(LegacySocketProviderOpenSocketOrdinal, &req_, &resp_)
+ return resp_.S, resp_.Status, err
+}
+func (p *LegacySocketProviderInterface) GetAddrInfo(node *String,service *String,hints *AddrInfoHints) (AddrInfoStatus, int32, *AddrInfo, *AddrInfo, *AddrInfo, *AddrInfo, error) {
+ req_ := LegacySocketProviderGetAddrInfoRequest{
+ Node: node,
+ Service: service,
+ Hints: hints,
+ }
+ resp_ := LegacySocketProviderGetAddrInfoResponse{}
+ err := ((*_bindings.Proxy)(p)).Call(LegacySocketProviderGetAddrInfoOrdinal, &req_, &resp_)
+ return resp_.Status, resp_.Nres, resp_.Ai0, resp_.Ai1, resp_.Ai2, resp_.Ai3, err
+}
+
+// LegacySocketProvider server interface.
+type LegacySocketProvider interface {
+ OpenSocket(domain SocketDomain,type_ SocketType,protocol SocketProtocol) (_zx.Socket, int32, error)
+ GetAddrInfo(node *String,service *String,hints *AddrInfoHints) (AddrInfoStatus, int32, *AddrInfo, *AddrInfo, *AddrInfo, *AddrInfo, error)
+}
+
+type LegacySocketProviderInterfaceRequest _bindings.InterfaceRequest
+
+func NewLegacySocketProviderInterfaceRequest() (LegacySocketProviderInterfaceRequest, *LegacySocketProviderInterface, error) {
+ req, cli, err := _bindings.NewInterfaceRequest()
+ return LegacySocketProviderInterfaceRequest(req), (*LegacySocketProviderInterface)(cli), err
+}
+// Implements ServiceRequest.
+func (_ LegacySocketProviderInterfaceRequest) Name() string {
+ return "fuchsia.net.LegacySocketProvider"
+}
+func (c LegacySocketProviderInterfaceRequest) ToChannel() _zx.Channel {
+ return c.Channel
+}
+
+const LegacySocketProviderName = "fuchsia.net.LegacySocketProvider"
+
+type LegacySocketProviderStub struct {
+ Impl LegacySocketProvider
+}
+
+func (s *LegacySocketProviderStub) Dispatch(ord uint32, b_ []byte, h_ []_zx.Handle) (_bindings.Payload, error) {
+ switch ord {
+ case LegacySocketProviderOpenSocketOrdinal:
+ in_ := LegacySocketProviderOpenSocketRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := LegacySocketProviderOpenSocketResponse{}
+ s, status, err_ := s.Impl.OpenSocket(in_.Domain,in_.Type,in_.Protocol)
+ out_.S = s
+ out_.Status = status
+ return &out_, err_
+ case LegacySocketProviderGetAddrInfoOrdinal:
+ in_ := LegacySocketProviderGetAddrInfoRequest{}
+ if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+ return nil, err_
+ }
+ out_ := LegacySocketProviderGetAddrInfoResponse{}
+ status, nres, ai0, ai1, ai2, ai3, err_ := s.Impl.GetAddrInfo(in_.Node,in_.Service,in_.Hints)
+ out_.Status = status
+ out_.Nres = nres
+ out_.Ai0 = ai0
+ out_.Ai1 = ai1
+ out_.Ai2 = ai2
+ out_.Ai3 = ai3
+ return &out_, err_
+ }
+ return nil, _bindings.ErrUnknownOrdinal
+}
+
+type LegacySocketProviderService struct {
+ _bindings.BindingSet
+}
+
+func (s *LegacySocketProviderService) Add(impl LegacySocketProvider, c _zx.Channel, onError func(error)) (_bindings.BindingKey, error) {
+ return s.BindingSet.Add(&LegacySocketProviderStub{Impl: impl}, c, onError)
+}
+
+func (s *LegacySocketProviderService) EventProxyFor(key _bindings.BindingKey) (*LegacySocketProviderEventProxy, bool) {
+ pxy, err := s.BindingSet.ProxyFor(key)
+ return (*LegacySocketProviderEventProxy)(pxy), err
+}
+
+type LegacySocketProviderEventProxy _bindings.Proxy
+
+
+
diff --git a/src/syscall/zx/syscalls_fuchsia.go b/src/syscall/zx/syscalls_fuchsia.go
new file mode 100644
index 0000000..7eaa63e
--- /dev/null
+++ b/src/syscall/zx/syscalls_fuchsia.go
@@ -0,0 +1,939 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Zircon system calls for the Fuchsia OS.
+// Generated by mkfuchsia.go, do not edit.
+
+package zx
+
+import "unsafe"
+
+//go:cgo_import_dynamic vdso_zx_clock_get zx_clock_get "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_clock_get_new zx_clock_get_new "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_clock_get_monotonic zx_clock_get_monotonic "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_nanosleep zx_nanosleep "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_ticks_get zx_ticks_get "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_ticks_per_second zx_ticks_per_second "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_deadline_after zx_deadline_after "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_clock_adjust zx_clock_adjust "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_system_get_dcache_line_size zx_system_get_dcache_line_size "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_system_get_num_cpus zx_system_get_num_cpus "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_system_get_version zx_system_get_version "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_system_get_physmem zx_system_get_physmem "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_system_get_features zx_system_get_features "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_cache_flush zx_cache_flush "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_handle_close zx_handle_close "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_handle_close_many zx_handle_close_many "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_handle_duplicate zx_handle_duplicate "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_handle_replace zx_handle_replace "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_object_wait_one zx_object_wait_one "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_object_wait_many zx_object_wait_many "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_object_wait_async zx_object_wait_async "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_object_signal zx_object_signal "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_object_signal_peer zx_object_signal_peer "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_object_get_property zx_object_get_property "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_object_set_property zx_object_set_property "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_object_set_cookie zx_object_set_cookie "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_object_get_cookie zx_object_get_cookie "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_object_get_info zx_object_get_info "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_object_get_child zx_object_get_child "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_object_set_profile zx_object_set_profile "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_channel_create zx_channel_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_channel_read zx_channel_read "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_channel_read_etc zx_channel_read_etc "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_channel_write zx_channel_write "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_channel_call_noretry zx_channel_call_noretry "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_channel_call_finish zx_channel_call_finish "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_channel_call zx_channel_call "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_socket_create zx_socket_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_socket_write zx_socket_write "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_socket_read zx_socket_read "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_socket_share zx_socket_share "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_socket_accept zx_socket_accept "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_thread_exit zx_thread_exit "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_thread_create zx_thread_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_thread_start zx_thread_start "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_thread_read_state zx_thread_read_state "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_thread_write_state zx_thread_write_state "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_thread_set_priority zx_thread_set_priority "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_process_exit zx_process_exit "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_process_create zx_process_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_process_start zx_process_start "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_process_read_memory zx_process_read_memory "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_process_write_memory zx_process_write_memory "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_job_create zx_job_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_job_set_policy zx_job_set_policy "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_task_bind_exception_port zx_task_bind_exception_port "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_task_resume zx_task_resume "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_task_suspend zx_task_suspend "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_task_suspend_token zx_task_suspend_token "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_task_resume_from_exception zx_task_resume_from_exception "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_task_kill zx_task_kill "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_event_create zx_event_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_eventpair_create zx_eventpair_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_futex_wait zx_futex_wait "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_futex_wake zx_futex_wake "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_futex_requeue zx_futex_requeue "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_port_create zx_port_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_port_queue zx_port_queue "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_port_wait zx_port_wait "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_port_cancel zx_port_cancel "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_timer_create zx_timer_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_timer_set zx_timer_set "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_timer_cancel zx_timer_cancel "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmo_create zx_vmo_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmo_read zx_vmo_read "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmo_write zx_vmo_write "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmo_get_size zx_vmo_get_size "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmo_set_size zx_vmo_set_size "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmo_op_range zx_vmo_op_range "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmo_clone zx_vmo_clone "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmo_set_cache_policy zx_vmo_set_cache_policy "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmar_allocate_old zx_vmar_allocate_old "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmar_map_old zx_vmar_map_old "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmar_protect_old zx_vmar_protect_old "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmar_allocate zx_vmar_allocate "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmar_destroy zx_vmar_destroy "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmar_map zx_vmar_map "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmar_unmap zx_vmar_unmap "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmar_protect zx_vmar_protect "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_cprng_draw_once zx_cprng_draw_once "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_cprng_draw zx_cprng_draw "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_cprng_draw_new zx_cprng_draw_new "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_cprng_add_entropy zx_cprng_add_entropy "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_fifo_create zx_fifo_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_fifo_read zx_fifo_read "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_fifo_write zx_fifo_write "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_profile_create zx_profile_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmar_unmap_handle_close_thread_exit zx_vmar_unmap_handle_close_thread_exit "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_futex_wake_handle_close_thread_exit zx_futex_wake_handle_close_thread_exit "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_log_write zx_log_write "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_log_read zx_log_read "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_debuglog_create zx_debuglog_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_debuglog_write zx_debuglog_write "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_debuglog_read zx_debuglog_read "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_ktrace_read zx_ktrace_read "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_ktrace_control zx_ktrace_control "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_ktrace_write zx_ktrace_write "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_mtrace_control zx_mtrace_control "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_debug_read zx_debug_read "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_debug_write zx_debug_write "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_debug_send_command zx_debug_send_command "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_interrupt_create zx_interrupt_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_interrupt_bind zx_interrupt_bind "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_interrupt_wait zx_interrupt_wait "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_interrupt_destroy zx_interrupt_destroy "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_interrupt_ack zx_interrupt_ack "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_interrupt_trigger zx_interrupt_trigger "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_ioports_request zx_ioports_request "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmo_create_contiguous zx_vmo_create_contiguous "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmo_create_physical zx_vmo_create_physical "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_iommu_create zx_iommu_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_bti_create zx_bti_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_bti_pin zx_bti_pin "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_bti_release_quarantine zx_bti_release_quarantine "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_pmt_unpin zx_pmt_unpin "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_framebuffer_get_info zx_framebuffer_get_info "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_framebuffer_set_range zx_framebuffer_set_range "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_pc_firmware_tables zx_pc_firmware_tables "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_smc_call zx_smc_call "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_resource_create zx_resource_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_system_mexec zx_system_mexec "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_system_powerctl zx_system_powerctl "libzircon.so"
+
+//go:linkname vdso_zx_clock_get vdso_zx_clock_get
+//go:linkname vdso_zx_clock_get_new vdso_zx_clock_get_new
+//go:linkname vdso_zx_clock_get_monotonic vdso_zx_clock_get_monotonic
+//go:linkname vdso_zx_nanosleep vdso_zx_nanosleep
+//go:linkname vdso_zx_ticks_get vdso_zx_ticks_get
+//go:linkname vdso_zx_ticks_per_second vdso_zx_ticks_per_second
+//go:linkname vdso_zx_deadline_after vdso_zx_deadline_after
+//go:linkname vdso_zx_clock_adjust vdso_zx_clock_adjust
+//go:linkname vdso_zx_system_get_dcache_line_size vdso_zx_system_get_dcache_line_size
+//go:linkname vdso_zx_system_get_num_cpus vdso_zx_system_get_num_cpus
+//go:linkname vdso_zx_system_get_version vdso_zx_system_get_version
+//go:linkname vdso_zx_system_get_physmem vdso_zx_system_get_physmem
+//go:linkname vdso_zx_system_get_features vdso_zx_system_get_features
+//go:linkname vdso_zx_cache_flush vdso_zx_cache_flush
+//go:linkname vdso_zx_handle_close vdso_zx_handle_close
+//go:linkname vdso_zx_handle_close_many vdso_zx_handle_close_many
+//go:linkname vdso_zx_handle_duplicate vdso_zx_handle_duplicate
+//go:linkname vdso_zx_handle_replace vdso_zx_handle_replace
+//go:linkname vdso_zx_object_wait_one vdso_zx_object_wait_one
+//go:linkname vdso_zx_object_wait_many vdso_zx_object_wait_many
+//go:linkname vdso_zx_object_wait_async vdso_zx_object_wait_async
+//go:linkname vdso_zx_object_signal vdso_zx_object_signal
+//go:linkname vdso_zx_object_signal_peer vdso_zx_object_signal_peer
+//go:linkname vdso_zx_object_get_property vdso_zx_object_get_property
+//go:linkname vdso_zx_object_set_property vdso_zx_object_set_property
+//go:linkname vdso_zx_object_set_cookie vdso_zx_object_set_cookie
+//go:linkname vdso_zx_object_get_cookie vdso_zx_object_get_cookie
+//go:linkname vdso_zx_object_get_info vdso_zx_object_get_info
+//go:linkname vdso_zx_object_get_child vdso_zx_object_get_child
+//go:linkname vdso_zx_object_set_profile vdso_zx_object_set_profile
+//go:linkname vdso_zx_channel_create vdso_zx_channel_create
+//go:linkname vdso_zx_channel_read vdso_zx_channel_read
+//go:linkname vdso_zx_channel_read_etc vdso_zx_channel_read_etc
+//go:linkname vdso_zx_channel_write vdso_zx_channel_write
+//go:linkname vdso_zx_channel_call_noretry vdso_zx_channel_call_noretry
+//go:linkname vdso_zx_channel_call_finish vdso_zx_channel_call_finish
+//go:linkname vdso_zx_channel_call vdso_zx_channel_call
+//go:linkname vdso_zx_socket_create vdso_zx_socket_create
+//go:linkname vdso_zx_socket_write vdso_zx_socket_write
+//go:linkname vdso_zx_socket_read vdso_zx_socket_read
+//go:linkname vdso_zx_socket_share vdso_zx_socket_share
+//go:linkname vdso_zx_socket_accept vdso_zx_socket_accept
+//go:linkname vdso_zx_thread_exit vdso_zx_thread_exit
+//go:linkname vdso_zx_thread_create vdso_zx_thread_create
+//go:linkname vdso_zx_thread_start vdso_zx_thread_start
+//go:linkname vdso_zx_thread_read_state vdso_zx_thread_read_state
+//go:linkname vdso_zx_thread_write_state vdso_zx_thread_write_state
+//go:linkname vdso_zx_thread_set_priority vdso_zx_thread_set_priority
+//go:linkname vdso_zx_process_exit vdso_zx_process_exit
+//go:linkname vdso_zx_process_create vdso_zx_process_create
+//go:linkname vdso_zx_process_start vdso_zx_process_start
+//go:linkname vdso_zx_process_read_memory vdso_zx_process_read_memory
+//go:linkname vdso_zx_process_write_memory vdso_zx_process_write_memory
+//go:linkname vdso_zx_job_create vdso_zx_job_create
+//go:linkname vdso_zx_job_set_policy vdso_zx_job_set_policy
+//go:linkname vdso_zx_task_bind_exception_port vdso_zx_task_bind_exception_port
+//go:linkname vdso_zx_task_resume vdso_zx_task_resume
+//go:linkname vdso_zx_task_suspend vdso_zx_task_suspend
+//go:linkname vdso_zx_task_suspend_token vdso_zx_task_suspend_token
+//go:linkname vdso_zx_task_resume_from_exception vdso_zx_task_resume_from_exception
+//go:linkname vdso_zx_task_kill vdso_zx_task_kill
+//go:linkname vdso_zx_event_create vdso_zx_event_create
+//go:linkname vdso_zx_eventpair_create vdso_zx_eventpair_create
+//go:linkname vdso_zx_futex_wait vdso_zx_futex_wait
+//go:linkname vdso_zx_futex_wake vdso_zx_futex_wake
+//go:linkname vdso_zx_futex_requeue vdso_zx_futex_requeue
+//go:linkname vdso_zx_port_create vdso_zx_port_create
+//go:linkname vdso_zx_port_queue vdso_zx_port_queue
+//go:linkname vdso_zx_port_wait vdso_zx_port_wait
+//go:linkname vdso_zx_port_cancel vdso_zx_port_cancel
+//go:linkname vdso_zx_timer_create vdso_zx_timer_create
+//go:linkname vdso_zx_timer_set vdso_zx_timer_set
+//go:linkname vdso_zx_timer_cancel vdso_zx_timer_cancel
+//go:linkname vdso_zx_vmo_create vdso_zx_vmo_create
+//go:linkname vdso_zx_vmo_read vdso_zx_vmo_read
+//go:linkname vdso_zx_vmo_write vdso_zx_vmo_write
+//go:linkname vdso_zx_vmo_get_size vdso_zx_vmo_get_size
+//go:linkname vdso_zx_vmo_set_size vdso_zx_vmo_set_size
+//go:linkname vdso_zx_vmo_op_range vdso_zx_vmo_op_range
+//go:linkname vdso_zx_vmo_clone vdso_zx_vmo_clone
+//go:linkname vdso_zx_vmo_set_cache_policy vdso_zx_vmo_set_cache_policy
+//go:linkname vdso_zx_vmar_allocate_old vdso_zx_vmar_allocate_old
+//go:linkname vdso_zx_vmar_map_old vdso_zx_vmar_map_old
+//go:linkname vdso_zx_vmar_protect_old vdso_zx_vmar_protect_old
+//go:linkname vdso_zx_vmar_allocate vdso_zx_vmar_allocate
+//go:linkname vdso_zx_vmar_destroy vdso_zx_vmar_destroy
+//go:linkname vdso_zx_vmar_map vdso_zx_vmar_map
+//go:linkname vdso_zx_vmar_unmap vdso_zx_vmar_unmap
+//go:linkname vdso_zx_vmar_protect vdso_zx_vmar_protect
+//go:linkname vdso_zx_cprng_draw_once vdso_zx_cprng_draw_once
+//go:linkname vdso_zx_cprng_draw vdso_zx_cprng_draw
+//go:linkname vdso_zx_cprng_draw_new vdso_zx_cprng_draw_new
+//go:linkname vdso_zx_cprng_add_entropy vdso_zx_cprng_add_entropy
+//go:linkname vdso_zx_fifo_create vdso_zx_fifo_create
+//go:linkname vdso_zx_fifo_read vdso_zx_fifo_read
+//go:linkname vdso_zx_fifo_write vdso_zx_fifo_write
+//go:linkname vdso_zx_profile_create vdso_zx_profile_create
+//go:linkname vdso_zx_vmar_unmap_handle_close_thread_exit vdso_zx_vmar_unmap_handle_close_thread_exit
+//go:linkname vdso_zx_futex_wake_handle_close_thread_exit vdso_zx_futex_wake_handle_close_thread_exit
+//go:linkname vdso_zx_log_write vdso_zx_log_write
+//go:linkname vdso_zx_log_read vdso_zx_log_read
+//go:linkname vdso_zx_debuglog_create vdso_zx_debuglog_create
+//go:linkname vdso_zx_debuglog_write vdso_zx_debuglog_write
+//go:linkname vdso_zx_debuglog_read vdso_zx_debuglog_read
+//go:linkname vdso_zx_ktrace_read vdso_zx_ktrace_read
+//go:linkname vdso_zx_ktrace_control vdso_zx_ktrace_control
+//go:linkname vdso_zx_ktrace_write vdso_zx_ktrace_write
+//go:linkname vdso_zx_mtrace_control vdso_zx_mtrace_control
+//go:linkname vdso_zx_debug_read vdso_zx_debug_read
+//go:linkname vdso_zx_debug_write vdso_zx_debug_write
+//go:linkname vdso_zx_debug_send_command vdso_zx_debug_send_command
+//go:linkname vdso_zx_interrupt_create vdso_zx_interrupt_create
+//go:linkname vdso_zx_interrupt_bind vdso_zx_interrupt_bind
+//go:linkname vdso_zx_interrupt_wait vdso_zx_interrupt_wait
+//go:linkname vdso_zx_interrupt_destroy vdso_zx_interrupt_destroy
+//go:linkname vdso_zx_interrupt_ack vdso_zx_interrupt_ack
+//go:linkname vdso_zx_interrupt_trigger vdso_zx_interrupt_trigger
+//go:linkname vdso_zx_ioports_request vdso_zx_ioports_request
+//go:linkname vdso_zx_vmo_create_contiguous vdso_zx_vmo_create_contiguous
+//go:linkname vdso_zx_vmo_create_physical vdso_zx_vmo_create_physical
+//go:linkname vdso_zx_iommu_create vdso_zx_iommu_create
+//go:linkname vdso_zx_bti_create vdso_zx_bti_create
+//go:linkname vdso_zx_bti_pin vdso_zx_bti_pin
+//go:linkname vdso_zx_bti_release_quarantine vdso_zx_bti_release_quarantine
+//go:linkname vdso_zx_pmt_unpin vdso_zx_pmt_unpin
+//go:linkname vdso_zx_framebuffer_get_info vdso_zx_framebuffer_get_info
+//go:linkname vdso_zx_framebuffer_set_range vdso_zx_framebuffer_set_range
+//go:linkname vdso_zx_pc_firmware_tables vdso_zx_pc_firmware_tables
+//go:linkname vdso_zx_smc_call vdso_zx_smc_call
+//go:linkname vdso_zx_resource_create vdso_zx_resource_create
+//go:linkname vdso_zx_system_mexec vdso_zx_system_mexec
+//go:linkname vdso_zx_system_powerctl vdso_zx_system_powerctl
+
+var (
+ vdso_zx_clock_get uintptr
+ vdso_zx_clock_get_new uintptr
+ vdso_zx_clock_get_monotonic uintptr
+ vdso_zx_nanosleep uintptr
+ vdso_zx_ticks_get uintptr
+ vdso_zx_ticks_per_second uintptr
+ vdso_zx_deadline_after uintptr
+ vdso_zx_clock_adjust uintptr
+ vdso_zx_system_get_dcache_line_size uintptr
+ vdso_zx_system_get_num_cpus uintptr
+ vdso_zx_system_get_version uintptr
+ vdso_zx_system_get_physmem uintptr
+ vdso_zx_system_get_features uintptr
+ vdso_zx_cache_flush uintptr
+ vdso_zx_handle_close uintptr
+ vdso_zx_handle_close_many uintptr
+ vdso_zx_handle_duplicate uintptr
+ vdso_zx_handle_replace uintptr
+ vdso_zx_object_wait_one uintptr
+ vdso_zx_object_wait_many uintptr
+ vdso_zx_object_wait_async uintptr
+ vdso_zx_object_signal uintptr
+ vdso_zx_object_signal_peer uintptr
+ vdso_zx_object_get_property uintptr
+ vdso_zx_object_set_property uintptr
+ vdso_zx_object_set_cookie uintptr
+ vdso_zx_object_get_cookie uintptr
+ vdso_zx_object_get_info uintptr
+ vdso_zx_object_get_child uintptr
+ vdso_zx_object_set_profile uintptr
+ vdso_zx_channel_create uintptr
+ vdso_zx_channel_read uintptr
+ vdso_zx_channel_read_etc uintptr
+ vdso_zx_channel_write uintptr
+ vdso_zx_channel_call_noretry uintptr
+ vdso_zx_channel_call_finish uintptr
+ vdso_zx_channel_call uintptr
+ vdso_zx_socket_create uintptr
+ vdso_zx_socket_write uintptr
+ vdso_zx_socket_read uintptr
+ vdso_zx_socket_share uintptr
+ vdso_zx_socket_accept uintptr
+ vdso_zx_thread_exit uintptr
+ vdso_zx_thread_create uintptr
+ vdso_zx_thread_start uintptr
+ vdso_zx_thread_read_state uintptr
+ vdso_zx_thread_write_state uintptr
+ vdso_zx_thread_set_priority uintptr
+ vdso_zx_process_exit uintptr
+ vdso_zx_process_create uintptr
+ vdso_zx_process_start uintptr
+ vdso_zx_process_read_memory uintptr
+ vdso_zx_process_write_memory uintptr
+ vdso_zx_job_create uintptr
+ vdso_zx_job_set_policy uintptr
+ vdso_zx_task_bind_exception_port uintptr
+ vdso_zx_task_resume uintptr
+ vdso_zx_task_suspend uintptr
+ vdso_zx_task_suspend_token uintptr
+ vdso_zx_task_resume_from_exception uintptr
+ vdso_zx_task_kill uintptr
+ vdso_zx_event_create uintptr
+ vdso_zx_eventpair_create uintptr
+ vdso_zx_futex_wait uintptr
+ vdso_zx_futex_wake uintptr
+ vdso_zx_futex_requeue uintptr
+ vdso_zx_port_create uintptr
+ vdso_zx_port_queue uintptr
+ vdso_zx_port_wait uintptr
+ vdso_zx_port_cancel uintptr
+ vdso_zx_timer_create uintptr
+ vdso_zx_timer_set uintptr
+ vdso_zx_timer_cancel uintptr
+ vdso_zx_vmo_create uintptr
+ vdso_zx_vmo_read uintptr
+ vdso_zx_vmo_write uintptr
+ vdso_zx_vmo_get_size uintptr
+ vdso_zx_vmo_set_size uintptr
+ vdso_zx_vmo_op_range uintptr
+ vdso_zx_vmo_clone uintptr
+ vdso_zx_vmo_set_cache_policy uintptr
+ vdso_zx_vmar_allocate_old uintptr
+ vdso_zx_vmar_map_old uintptr
+ vdso_zx_vmar_protect_old uintptr
+ vdso_zx_vmar_allocate uintptr
+ vdso_zx_vmar_destroy uintptr
+ vdso_zx_vmar_map uintptr
+ vdso_zx_vmar_unmap uintptr
+ vdso_zx_vmar_protect uintptr
+ vdso_zx_cprng_draw_once uintptr
+ vdso_zx_cprng_draw uintptr
+ vdso_zx_cprng_draw_new uintptr
+ vdso_zx_cprng_add_entropy uintptr
+ vdso_zx_fifo_create uintptr
+ vdso_zx_fifo_read uintptr
+ vdso_zx_fifo_write uintptr
+ vdso_zx_profile_create uintptr
+ vdso_zx_vmar_unmap_handle_close_thread_exit uintptr
+ vdso_zx_futex_wake_handle_close_thread_exit uintptr
+ vdso_zx_log_write uintptr
+ vdso_zx_log_read uintptr
+ vdso_zx_debuglog_create uintptr
+ vdso_zx_debuglog_write uintptr
+ vdso_zx_debuglog_read uintptr
+ vdso_zx_ktrace_read uintptr
+ vdso_zx_ktrace_control uintptr
+ vdso_zx_ktrace_write uintptr
+ vdso_zx_mtrace_control uintptr
+ vdso_zx_debug_read uintptr
+ vdso_zx_debug_write uintptr
+ vdso_zx_debug_send_command uintptr
+ vdso_zx_interrupt_create uintptr
+ vdso_zx_interrupt_bind uintptr
+ vdso_zx_interrupt_wait uintptr
+ vdso_zx_interrupt_destroy uintptr
+ vdso_zx_interrupt_ack uintptr
+ vdso_zx_interrupt_trigger uintptr
+ vdso_zx_ioports_request uintptr
+ vdso_zx_vmo_create_contiguous uintptr
+ vdso_zx_vmo_create_physical uintptr
+ vdso_zx_iommu_create uintptr
+ vdso_zx_bti_create uintptr
+ vdso_zx_bti_pin uintptr
+ vdso_zx_bti_release_quarantine uintptr
+ vdso_zx_pmt_unpin uintptr
+ vdso_zx_framebuffer_get_info uintptr
+ vdso_zx_framebuffer_set_range uintptr
+ vdso_zx_pc_firmware_tables uintptr
+ vdso_zx_smc_call uintptr
+ vdso_zx_resource_create uintptr
+ vdso_zx_system_mexec uintptr
+ vdso_zx_system_powerctl uintptr
+)
+
+//go:noescape
+//go:nosplit
+func Sys_clock_get(clock_id uint32) Time
+
+//go:noescape
+//go:nosplit
+func Sys_clock_get_new(clock_id uint32, out *Time) Status
+
+//go:noescape
+//go:nosplit
+func Sys_clock_get_monotonic() Time
+
+//go:noescape
+//go:nosplit
+func Sys_nanosleep(deadline Time) Status
+
+//go:noescape
+//go:nosplit
+func Sys_ticks_get() uint64
+
+//go:noescape
+//go:nosplit
+func Sys_ticks_per_second() uint64
+
+//go:noescape
+//go:nosplit
+func Sys_deadline_after(nanoseconds Duration) Time
+
+//go:noescape
+//go:nosplit
+func Sys_clock_adjust(handle Handle, clock_id uint32, offset int64) Status
+
+//go:noescape
+//go:nosplit
+func sys_system_get_dcache_line_size() uint32
+
+//go:noescape
+//go:nosplit
+func Sys_system_get_num_cpus() uint32
+
+//go:noescape
+//go:nosplit
+func Sys_system_get_version(version *uint8, version_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_system_get_physmem() uint64
+
+//go:noescape
+//go:nosplit
+func sys_system_get_features(kind uint32, out *uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_cache_flush(addr unsafe.Pointer, size uint, options uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_handle_close(handle Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_handle_close_many(handles *Handle, num_handles uint) Status
+
+//go:noescape
+//go:nosplit
+func sys_handle_duplicate(handle Handle, rights Rights, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_handle_replace(handle Handle, rights Rights, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_object_wait_one(handle Handle, signals Signals, deadline Time, observed *Signals) Status
+
+//go:noescape
+//go:nosplit
+func sys_object_wait_many(items *WaitItem, count uint, deadline Time) Status
+
+//go:noescape
+//go:nosplit
+func Sys_object_wait_async(handle Handle, port Handle, key uint64, signals Signals, options uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_object_signal(handle Handle, clear_mask uint32, set_mask uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_object_signal_peer(handle Handle, clear_mask uint32, set_mask uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_object_get_property(handle Handle, property uint32, value unsafe.Pointer, value_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_object_set_property(handle Handle, property uint32, value unsafe.Pointer, value_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_object_set_cookie(handle Handle, scope Handle, cookie uint64) Status
+
+//go:noescape
+//go:nosplit
+func Sys_object_get_cookie(handle Handle, scope Handle, cookie *uint64) Status
+
+//go:noescape
+//go:nosplit
+func Sys_object_get_info(handle Handle, topic uint32, buffer unsafe.Pointer, buffer_size uint, actual_count *uint, avail_count *uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_object_get_child(handle Handle, koid uint64, rights Rights, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func sys_object_set_profile(handle Handle, profile Handle, options uint32) Status
+
+//go:noescape
+//go:nosplit
+func sys_channel_create(options uint32, out0 *Handle, out1 *Handle) Status
+
+//go:noescape
+//go:nosplit
+func sys_channel_read(handle Handle, options uint32, bytes unsafe.Pointer, handles *Handle, num_bytes uint32, num_handles uint32, actual_bytes *uint32, actual_handles *uint32) Status
+
+//go:noescape
+//go:nosplit
+func sys_channel_read_etc(handle Handle, options uint32, bytes unsafe.Pointer, handles *int, num_bytes uint32, num_handles uint32, actual_bytes *uint32, actual_handles *uint32) Status
+
+//go:noescape
+//go:nosplit
+func sys_channel_write(handle Handle, options uint32, bytes unsafe.Pointer, num_bytes uint32, handles *Handle, num_handles uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_channel_call_noretry(handle Handle, options uint32, deadline Time, args *ChannelCallArgs, actual_bytes *uint32, actual_handles *uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_channel_call_finish(deadline Time, args *ChannelCallArgs, actual_bytes *uint32, actual_handles *uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_channel_call(handle Handle, options uint32, deadline Time, args *ChannelCallArgs, actual_bytes *uint32, actual_handles *uint32) Status
+
+//go:noescape
+//go:nosplit
+func sys_socket_create(options uint32, out0 *Handle, out1 *Handle) Status
+
+//go:noescape
+//go:nosplit
+func sys_socket_write(handle Handle, options uint32, buffer unsafe.Pointer, buffer_size uint, actual *uint) Status
+
+//go:noescape
+//go:nosplit
+func sys_socket_read(handle Handle, options uint32, buffer unsafe.Pointer, buffer_size uint, actual *uint) Status
+
+//go:noescape
+//go:nosplit
+func sys_socket_share(handle Handle, socket_to_share Handle) Status
+
+//go:noescape
+//go:nosplit
+func sys_socket_accept(handle Handle, out_socket *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_thread_exit()
+
+//go:noescape
+//go:nosplit
+func Sys_thread_create(process Handle, name *uint8, name_size uint, options uint32, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_thread_start(handle Handle, thread_entry Vaddr, stack Vaddr, arg1 uintptr, arg2 uintptr) Status
+
+//go:noescape
+//go:nosplit
+func Sys_thread_read_state(handle Handle, kind uint32, buffer unsafe.Pointer, buffer_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_thread_write_state(handle Handle, kind uint32, buffer unsafe.Pointer, buffer_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_thread_set_priority(prio int32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_process_exit(retcode int64)
+
+//go:noescape
+//go:nosplit
+func Sys_process_create(job Handle, name *uint8, name_size uint, options uint32, proc_handle *Handle, vmar_handle *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_process_start(handle Handle, thread Handle, entry Vaddr, stack Vaddr, arg1 Handle, arg2 uintptr) Status
+
+//go:noescape
+//go:nosplit
+func Sys_process_read_memory(proc Handle, vaddr Vaddr, buffer unsafe.Pointer, buffer_size uint, actual *uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_process_write_memory(proc Handle, vaddr Vaddr, buffer unsafe.Pointer, buffer_size uint, actual *uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_job_create(parent_job Handle, options uint32, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_job_set_policy(job Handle, options uint32, topic uint32, policy unsafe.Pointer, count uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_task_bind_exception_port(handle Handle, port Handle, key uint64, options uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_task_resume(handle Handle, options uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_task_suspend(handle Handle, token *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_task_suspend_token(handle Handle, token *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_task_resume_from_exception(handle Handle, port Handle, options uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_task_kill(handle Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_event_create(options uint32, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_eventpair_create(options uint32, out0 *Handle, out1 *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_futex_wait(value_ptr *int, current_value int32, deadline Time) Status
+
+//go:noescape
+//go:nosplit
+func Sys_futex_wake(value_ptr *int, count uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_futex_requeue(wake_ptr *int, wake_count uint32, current_value int32, requeue_ptr *int, requeue_count uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_port_create(options uint32, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_port_queue(handle Handle, packet *int) Status
+
+//go:noescape
+//go:nosplit
+func Sys_port_wait(handle Handle, deadline Time, packet *int) Status
+
+//go:noescape
+//go:nosplit
+func Sys_port_cancel(handle Handle, source Handle, key uint64) Status
+
+//go:noescape
+//go:nosplit
+func Sys_timer_create(options uint32, clock_id uint32, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_timer_set(handle Handle, deadline Time, slack Duration) Status
+
+//go:noescape
+//go:nosplit
+func Sys_timer_cancel(handle Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_vmo_create(size uint64, options uint32, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func sys_vmo_read(handle Handle, buffer unsafe.Pointer, offset uint64, buffer_size uint) Status
+
+//go:noescape
+//go:nosplit
+func sys_vmo_write(handle Handle, buffer unsafe.Pointer, offset uint64, buffer_size uint) Status
+
+//go:noescape
+//go:nosplit
+func sys_vmo_get_size(handle Handle, size *uint64) Status
+
+//go:noescape
+//go:nosplit
+func sys_vmo_set_size(handle Handle, size uint64) Status
+
+//go:noescape
+//go:nosplit
+func sys_vmo_op_range(handle Handle, op uint32, offset uint64, size uint64, buffer unsafe.Pointer, buffer_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_vmo_clone(handle Handle, options uint32, offset uint64, size uint64, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_vmo_set_cache_policy(handle Handle, cache_policy uint32) Status
+
+//go:noescape
+//go:nosplit
+func sys_vmar_allocate_old(parent_vmar Handle, offset uint64, size uint64, map_flags uint32, child_vmar *Handle, child_addr *Vaddr) Status
+
+//go:noescape
+//go:nosplit
+func sys_vmar_map_old(handle Handle, vmar_offset uint64, vmo Handle, vmo_offset uint64, len uint64, map_flags uint32, mapped_addr *Vaddr) Status
+
+//go:noescape
+//go:nosplit
+func sys_vmar_protect_old(handle Handle, addr Vaddr, len uint64, prot_flags uint32) Status
+
+//go:noescape
+//go:nosplit
+func sys_vmar_allocate(parent_vmar Handle, offset uint64, size uint64, map_flags uint32, child_vmar *Handle, child_addr *Vaddr) Status
+
+//go:noescape
+//go:nosplit
+func sys_vmar_destroy(handle Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_vmar_map(handle Handle, vmar_offset uint64, vmo Handle, vmo_offset uint64, len uint64, map_flags uint32, mapped_addr *Vaddr) Status
+
+//go:noescape
+//go:nosplit
+func Sys_vmar_unmap(handle Handle, addr Vaddr, len uint64) Status
+
+//go:noescape
+//go:nosplit
+func Sys_vmar_protect(handle Handle, addr Vaddr, len uint64, prot_flags uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_cprng_draw_once(buffer unsafe.Pointer, buffer_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_cprng_draw(buffer unsafe.Pointer, buffer_size uint)
+
+//go:noescape
+//go:nosplit
+func Sys_cprng_draw_new(buffer unsafe.Pointer, data_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_cprng_add_entropy(buffer unsafe.Pointer, len uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_fifo_create(elem_count uint, elem_size uint, options uint32, out0 *Handle, out1 *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_fifo_read(handle Handle, elem_size uint, data unsafe.Pointer, count uint, actual_count *uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_fifo_write(handle Handle, elem_size uint, data unsafe.Pointer, count uint, actual_count *uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_profile_create(resource Handle, profile *int, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_vmar_unmap_handle_close_thread_exit(vmar_handle Handle, addr Vaddr, size uint, handle Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_futex_wake_handle_close_thread_exit(value_ptr *int, count uint32, new_value int32, handle Handle)
+
+//go:noescape
+//go:nosplit
+func Sys_log_write(handle Handle, len uint32, buffer unsafe.Pointer, options uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_log_read(handle Handle, len uint32, buffer unsafe.Pointer, options uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_debuglog_create(resource Handle, options uint32, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_debuglog_write(handle Handle, options uint32, buffer unsafe.Pointer, buffer_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_debuglog_read(handle Handle, options uint32, buffer unsafe.Pointer, buffer_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_ktrace_read(handle Handle, data unsafe.Pointer, offset uint32, data_size uint, actual *uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_ktrace_control(handle Handle, action uint32, options uint32, ptr unsafe.Pointer) Status
+
+//go:noescape
+//go:nosplit
+func Sys_ktrace_write(handle Handle, id uint32, arg0 uint32, arg1 uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_mtrace_control(handle Handle, kind uint32, action uint32, options uint32, ptr unsafe.Pointer, ptr_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_debug_read(handle Handle, buffer *uint8, buffer_size *uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_debug_write(buffer *uint8, buffer_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_debug_send_command(resource Handle, buffer *uint8, buffer_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_interrupt_create(src_obj Handle, src_num uint32, options uint32, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_interrupt_bind(handle Handle, port Handle, key uint64, options uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_interrupt_wait(handle Handle, out_timestamp *Time) Status
+
+//go:noescape
+//go:nosplit
+func Sys_interrupt_destroy(handle Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_interrupt_ack(handle Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_interrupt_trigger(handle Handle, options uint32, timestamp Time) Status
+
+//go:noescape
+//go:nosplit
+func Sys_ioports_request(resource Handle, io_addr uint16, len uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_vmo_create_contiguous(bti Handle, size uint, alignment_log2 uint32, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_vmo_create_physical(resource Handle, paddr Paddr, size uint, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_iommu_create(resource Handle, typ uint32, desc unsafe.Pointer, desc_size uint, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_bti_create(iommu Handle, options uint32, bti_id uint64, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_bti_pin(handle Handle, options uint32, vmo Handle, offset uint64, size uint64, addrs *Paddr, addrs_count uint, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_bti_release_quarantine(handle Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_pmt_unpin(handle Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_framebuffer_get_info(resource Handle, format *uint32, width *uint32, height *uint32, stride *uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_framebuffer_set_range(resource Handle, vmo Handle, len uint32, format uint32, width uint32, height uint32, stride uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_pc_firmware_tables(handle Handle, acpi_rsdp *Paddr, smbios *Paddr) Status
+
+//go:noescape
+//go:nosplit
+func Sys_smc_call(handle Handle, parameters *SMCParameters, out_smc_result *SMCResult) Status
+
+//go:noescape
+//go:nosplit
+func Sys_resource_create(parent_rsrc Handle, options uint32, base uint64, size uint, name *uint8, name_size uint, resource_out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_system_mexec(resource Handle, kernel Handle, bootimage Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_system_powerctl(resource Handle, cmd uint32, arg *int) Status
diff --git a/src/syscall/zx/syscalls_fuchsia_amd64.s b/src/syscall/zx/syscalls_fuchsia_amd64.s
new file mode 100644
index 0000000..f6477d3
--- /dev/null
+++ b/src/syscall/zx/syscalls_fuchsia_amd64.s
@@ -0,0 +1,1421 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Zircon system calls for the Fuchsia OS.
+// Generated by mkfuchsia.go, do not edit.
+
+#include "textflag.h"
+
+// func Sys_clock_get(clock_id uint32) Time
+TEXT ·Sys_clock_get(SB),NOSPLIT,$0-16
+ MOVL clock_id+0(FP), DI
+ MOVQ vdso_zx_clock_get(SB), AX
+ CALL AX
+ MOVQ AX, ret+8(FP)
+ RET
+
+// func Sys_clock_get_new(clock_id uint32, out *Time) Status
+TEXT ·Sys_clock_get_new(SB),NOSPLIT,$0-20
+ MOVL clock_id+0(FP), DI
+ MOVQ out+8(FP), SI
+ MOVQ vdso_zx_clock_get_new(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_clock_get_monotonic() Time
+TEXT ·Sys_clock_get_monotonic(SB),NOSPLIT,$0-8
+ MOVQ vdso_zx_clock_get_monotonic(SB), AX
+ CALL AX
+ MOVQ AX, ret+0(FP)
+ RET
+
+// func Sys_nanosleep(deadline Time) Status
+TEXT ·Sys_nanosleep(SB),NOSPLIT,$0-12
+ MOVQ deadline+0(FP), DI
+ MOVQ vdso_zx_nanosleep(SB), AX
+ CALL AX
+ MOVL AX, ret+8(FP)
+ RET
+
+// func Sys_ticks_get() uint64
+TEXT ·Sys_ticks_get(SB),NOSPLIT,$0-8
+ MOVQ vdso_zx_ticks_get(SB), AX
+ CALL AX
+ MOVQ AX, ret+0(FP)
+ RET
+
+// func Sys_ticks_per_second() uint64
+TEXT ·Sys_ticks_per_second(SB),NOSPLIT,$0-8
+ MOVQ vdso_zx_ticks_per_second(SB), AX
+ CALL AX
+ MOVQ AX, ret+0(FP)
+ RET
+
+// func Sys_deadline_after(nanoseconds Duration) Time
+TEXT ·Sys_deadline_after(SB),NOSPLIT,$0-16
+ MOVQ nanoseconds+0(FP), DI
+ MOVQ vdso_zx_deadline_after(SB), AX
+ CALL AX
+ MOVQ AX, ret+8(FP)
+ RET
+
+// func Sys_clock_adjust(handle Handle, clock_id uint32, offset int64) Status
+TEXT ·Sys_clock_adjust(SB),NOSPLIT,$0-20
+ MOVL handle+0(FP), DI
+ MOVL clock_id+4(FP), SI
+ MOVQ offset+8(FP), DX
+ MOVQ vdso_zx_clock_adjust(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func sys_system_get_dcache_line_size() uint32
+TEXT ·sys_system_get_dcache_line_size(SB),NOSPLIT,$0-4
+ MOVQ vdso_zx_system_get_dcache_line_size(SB), AX
+ CALL AX
+ MOVL AX, ret+0(FP)
+ RET
+
+// func Sys_system_get_num_cpus() uint32
+TEXT ·Sys_system_get_num_cpus(SB),NOSPLIT,$0-4
+ MOVQ vdso_zx_system_get_num_cpus(SB), AX
+ CALL AX
+ MOVL AX, ret+0(FP)
+ RET
+
+// func Sys_system_get_version(version *uint8, version_size uint) Status
+TEXT ·Sys_system_get_version(SB),NOSPLIT,$0-20
+ MOVQ version+0(FP), DI
+ MOVQ version_size+8(FP), SI
+ MOVQ vdso_zx_system_get_version(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_system_get_physmem() uint64
+TEXT ·Sys_system_get_physmem(SB),NOSPLIT,$0-8
+ MOVQ vdso_zx_system_get_physmem(SB), AX
+ CALL AX
+ MOVQ AX, ret+0(FP)
+ RET
+
+// func sys_system_get_features(kind uint32, out *uint32) Status
+TEXT ·sys_system_get_features(SB),NOSPLIT,$0-20
+ MOVL kind+0(FP), DI
+ MOVQ out+8(FP), SI
+ MOVQ vdso_zx_system_get_features(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_cache_flush(addr unsafe.Pointer, size uint, options uint32) Status
+TEXT ·Sys_cache_flush(SB),NOSPLIT,$0-28
+ MOVQ addr+0(FP), DI
+ MOVQ size+8(FP), SI
+ MOVL options+16(FP), DX
+ MOVQ vdso_zx_cache_flush(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func Sys_handle_close(handle Handle) Status
+TEXT ·Sys_handle_close(SB),NOSPLIT,$0-12
+ MOVL handle+0(FP), DI
+ MOVQ vdso_zx_handle_close(SB), AX
+ CALL AX
+ MOVL AX, ret+8(FP)
+ RET
+
+// func Sys_handle_close_many(handles *Handle, num_handles uint) Status
+TEXT ·Sys_handle_close_many(SB),NOSPLIT,$0-20
+ MOVQ handles+0(FP), DI
+ MOVQ num_handles+8(FP), SI
+ MOVQ vdso_zx_handle_close_many(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func sys_handle_duplicate(handle Handle, rights Rights, out *Handle) Status
+TEXT ·sys_handle_duplicate(SB),NOSPLIT,$0-20
+ MOVL handle+0(FP), DI
+ MOVL rights+4(FP), SI
+ MOVQ out+8(FP), DX
+ MOVQ vdso_zx_handle_duplicate(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_handle_replace(handle Handle, rights Rights, out *Handle) Status
+TEXT ·Sys_handle_replace(SB),NOSPLIT,$0-20
+ MOVL handle+0(FP), DI
+ MOVL rights+4(FP), SI
+ MOVQ out+8(FP), DX
+ MOVQ vdso_zx_handle_replace(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_object_wait_one(handle Handle, signals Signals, deadline Time, observed *Signals) Status
+TEXT ·Sys_object_wait_one(SB),NOSPLIT,$0-28
+ CALL runtime·entersyscall(SB)
+ MOVL handle+0(FP), DI
+ MOVL signals+4(FP), SI
+ MOVQ deadline+8(FP), DX
+ MOVQ observed+16(FP), CX
+ MOVQ vdso_zx_object_wait_one(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ CALL runtime·exitsyscall(SB)
+ RET
+
+// func sys_object_wait_many(items *WaitItem, count uint, deadline Time) Status
+TEXT ·sys_object_wait_many(SB),NOSPLIT,$0-28
+ CALL runtime·entersyscall(SB)
+ MOVQ items+0(FP), DI
+ MOVQ count+8(FP), SI
+ MOVQ deadline+16(FP), DX
+ MOVQ vdso_zx_object_wait_many(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ CALL runtime·exitsyscall(SB)
+ RET
+
+// func Sys_object_wait_async(handle Handle, port Handle, key uint64, signals Signals, options uint32) Status
+TEXT ·Sys_object_wait_async(SB),NOSPLIT,$0-28
+ MOVL handle+0(FP), DI
+ MOVL port+4(FP), SI
+ MOVQ key+8(FP), DX
+ MOVL signals+16(FP), CX
+ MOVL options+20(FP), R8
+ MOVQ vdso_zx_object_wait_async(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func Sys_object_signal(handle Handle, clear_mask uint32, set_mask uint32) Status
+TEXT ·Sys_object_signal(SB),NOSPLIT,$0-20
+ MOVL handle+0(FP), DI
+ MOVL clear_mask+4(FP), SI
+ MOVL set_mask+8(FP), DX
+ MOVQ vdso_zx_object_signal(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_object_signal_peer(handle Handle, clear_mask uint32, set_mask uint32) Status
+TEXT ·Sys_object_signal_peer(SB),NOSPLIT,$0-20
+ MOVL handle+0(FP), DI
+ MOVL clear_mask+4(FP), SI
+ MOVL set_mask+8(FP), DX
+ MOVQ vdso_zx_object_signal_peer(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_object_get_property(handle Handle, property uint32, value unsafe.Pointer, value_size uint) Status
+TEXT ·Sys_object_get_property(SB),NOSPLIT,$0-28
+ MOVL handle+0(FP), DI
+ MOVL property+4(FP), SI
+ MOVQ value+8(FP), DX
+ MOVQ value_size+16(FP), CX
+ MOVQ vdso_zx_object_get_property(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func Sys_object_set_property(handle Handle, property uint32, value unsafe.Pointer, value_size uint) Status
+TEXT ·Sys_object_set_property(SB),NOSPLIT,$0-28
+ MOVL handle+0(FP), DI
+ MOVL property+4(FP), SI
+ MOVQ value+8(FP), DX
+ MOVQ value_size+16(FP), CX
+ MOVQ vdso_zx_object_set_property(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func Sys_object_set_cookie(handle Handle, scope Handle, cookie uint64) Status
+TEXT ·Sys_object_set_cookie(SB),NOSPLIT,$0-20
+ MOVL handle+0(FP), DI
+ MOVL scope+4(FP), SI
+ MOVQ cookie+8(FP), DX
+ MOVQ vdso_zx_object_set_cookie(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_object_get_cookie(handle Handle, scope Handle, cookie *uint64) Status
+TEXT ·Sys_object_get_cookie(SB),NOSPLIT,$0-20
+ MOVL handle+0(FP), DI
+ MOVL scope+4(FP), SI
+ MOVQ cookie+8(FP), DX
+ MOVQ vdso_zx_object_get_cookie(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_object_get_info(handle Handle, topic uint32, buffer unsafe.Pointer, buffer_size uint, actual_count *uint, avail_count *uint) Status
+TEXT ·Sys_object_get_info(SB),NOSPLIT,$0-44
+ MOVL handle+0(FP), DI
+ MOVL topic+4(FP), SI
+ MOVQ buffer+8(FP), DX
+ MOVQ buffer_size+16(FP), CX
+ MOVQ actual_count+24(FP), R8
+ MOVQ avail_count+32(FP), R9
+ MOVQ vdso_zx_object_get_info(SB), AX
+ CALL AX
+ MOVL AX, ret+40(FP)
+ RET
+
+// func Sys_object_get_child(handle Handle, koid uint64, rights Rights, out *Handle) Status
+TEXT ·Sys_object_get_child(SB),NOSPLIT,$0-36
+ MOVL handle+0(FP), DI
+ MOVQ koid+8(FP), SI
+ MOVL rights+16(FP), DX
+ MOVQ out+24(FP), CX
+ MOVQ vdso_zx_object_get_child(SB), AX
+ CALL AX
+ MOVL AX, ret+32(FP)
+ RET
+
+// func sys_object_set_profile(handle Handle, profile Handle, options uint32) Status
+TEXT ·sys_object_set_profile(SB),NOSPLIT,$0-20
+ MOVL handle+0(FP), DI
+ MOVL profile+4(FP), SI
+ MOVL options+8(FP), DX
+ MOVQ vdso_zx_object_set_profile(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func sys_channel_create(options uint32, out0 *Handle, out1 *Handle) Status
+TEXT ·sys_channel_create(SB),NOSPLIT,$0-28
+ MOVL options+0(FP), DI
+ MOVQ out0+8(FP), SI
+ MOVQ out1+16(FP), DX
+ MOVQ vdso_zx_channel_create(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func sys_channel_read(handle Handle, options uint32, bytes unsafe.Pointer, handles *Handle, num_bytes uint32, num_handles uint32, actual_bytes *uint32, actual_handles *uint32) Status
+TEXT ·sys_channel_read(SB),NOSPLIT,$32-52
+ MOVL handle+0(FP), DI
+ MOVL options+4(FP), SI
+ MOVQ bytes+8(FP), DX
+ MOVQ handles+16(FP), CX
+ MOVL num_bytes+24(FP), R8
+ MOVL num_handles+28(FP), R9
+ MOVQ actual_bytes+32(FP), R12
+ MOVQ actual_handles+40(FP), R13
+ MOVQ SP, BP // BP is preserved across vsdo call by the x86-64 ABI
+ ANDQ $~15, SP // stack alignment for x86-64 ABI
+ PUSHQ R13
+ PUSHQ R12
+ MOVQ vdso_zx_channel_read(SB), AX
+ CALL AX
+ POPQ R12
+ POPQ R13
+ MOVQ BP, SP
+ MOVL AX, ret+48(FP)
+ RET
+
+// func sys_channel_read_etc(handle Handle, options uint32, bytes unsafe.Pointer, handles *int, num_bytes uint32, num_handles uint32, actual_bytes *uint32, actual_handles *uint32) Status
+TEXT ·sys_channel_read_etc(SB),NOSPLIT,$32-52
+ MOVL handle+0(FP), DI
+ MOVL options+4(FP), SI
+ MOVQ bytes+8(FP), DX
+ MOVQ handles+16(FP), CX
+ MOVL num_bytes+24(FP), R8
+ MOVL num_handles+28(FP), R9
+ MOVQ actual_bytes+32(FP), R12
+ MOVQ actual_handles+40(FP), R13
+ MOVQ SP, BP // BP is preserved across vsdo call by the x86-64 ABI
+ ANDQ $~15, SP // stack alignment for x86-64 ABI
+ PUSHQ R13
+ PUSHQ R12
+ MOVQ vdso_zx_channel_read_etc(SB), AX
+ CALL AX
+ POPQ R12
+ POPQ R13
+ MOVQ BP, SP
+ MOVL AX, ret+48(FP)
+ RET
+
+// func sys_channel_write(handle Handle, options uint32, bytes unsafe.Pointer, num_bytes uint32, handles *Handle, num_handles uint32) Status
+TEXT ·sys_channel_write(SB),NOSPLIT,$0-44
+ MOVL handle+0(FP), DI
+ MOVL options+4(FP), SI
+ MOVQ bytes+8(FP), DX
+ MOVL num_bytes+16(FP), CX
+ MOVQ handles+24(FP), R8
+ MOVL num_handles+32(FP), R9
+ MOVQ vdso_zx_channel_write(SB), AX
+ CALL AX
+ MOVL AX, ret+40(FP)
+ RET
+
+// func Sys_channel_call_noretry(handle Handle, options uint32, deadline Time, args *ChannelCallArgs, actual_bytes *uint32, actual_handles *uint32) Status
+TEXT ·Sys_channel_call_noretry(SB),NOSPLIT,$0-44
+ MOVL handle+0(FP), DI
+ MOVL options+4(FP), SI
+ MOVQ deadline+8(FP), DX
+ MOVQ args+16(FP), CX
+ MOVQ actual_bytes+24(FP), R8
+ MOVQ actual_handles+32(FP), R9
+ MOVQ vdso_zx_channel_call_noretry(SB), AX
+ CALL AX
+ MOVL AX, ret+40(FP)
+ RET
+
+// func Sys_channel_call_finish(deadline Time, args *ChannelCallArgs, actual_bytes *uint32, actual_handles *uint32) Status
+TEXT ·Sys_channel_call_finish(SB),NOSPLIT,$0-36
+ MOVQ deadline+0(FP), DI
+ MOVQ args+8(FP), SI
+ MOVQ actual_bytes+16(FP), DX
+ MOVQ actual_handles+24(FP), CX
+ MOVQ vdso_zx_channel_call_finish(SB), AX
+ CALL AX
+ MOVL AX, ret+32(FP)
+ RET
+
+// func Sys_channel_call(handle Handle, options uint32, deadline Time, args *ChannelCallArgs, actual_bytes *uint32, actual_handles *uint32) Status
+TEXT ·Sys_channel_call(SB),NOSPLIT,$0-44
+ MOVL handle+0(FP), DI
+ MOVL options+4(FP), SI
+ MOVQ deadline+8(FP), DX
+ MOVQ args+16(FP), CX
+ MOVQ actual_bytes+24(FP), R8
+ MOVQ actual_handles+32(FP), R9
+ MOVQ vdso_zx_channel_call(SB), AX
+ CALL AX
+ MOVL AX, ret+40(FP)
+ RET
+
+// func sys_socket_create(options uint32, out0 *Handle, out1 *Handle) Status
+TEXT ·sys_socket_create(SB),NOSPLIT,$0-28
+ MOVL options+0(FP), DI
+ MOVQ out0+8(FP), SI
+ MOVQ out1+16(FP), DX
+ MOVQ vdso_zx_socket_create(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func sys_socket_write(handle Handle, options uint32, buffer unsafe.Pointer, buffer_size uint, actual *uint) Status
+TEXT ·sys_socket_write(SB),NOSPLIT,$0-36
+ MOVL handle+0(FP), DI
+ MOVL options+4(FP), SI
+ MOVQ buffer+8(FP), DX
+ MOVQ buffer_size+16(FP), CX
+ MOVQ actual+24(FP), R8
+ MOVQ vdso_zx_socket_write(SB), AX
+ CALL AX
+ MOVL AX, ret+32(FP)
+ RET
+
+// func sys_socket_read(handle Handle, options uint32, buffer unsafe.Pointer, buffer_size uint, actual *uint) Status
+TEXT ·sys_socket_read(SB),NOSPLIT,$0-36
+ MOVL handle+0(FP), DI
+ MOVL options+4(FP), SI
+ MOVQ buffer+8(FP), DX
+ MOVQ buffer_size+16(FP), CX
+ MOVQ actual+24(FP), R8
+ MOVQ vdso_zx_socket_read(SB), AX
+ CALL AX
+ MOVL AX, ret+32(FP)
+ RET
+
+// func sys_socket_share(handle Handle, socket_to_share Handle) Status
+TEXT ·sys_socket_share(SB),NOSPLIT,$0-12
+ MOVL handle+0(FP), DI
+ MOVL socket_to_share+4(FP), SI
+ MOVQ vdso_zx_socket_share(SB), AX
+ CALL AX
+ MOVL AX, ret+8(FP)
+ RET
+
+// func sys_socket_accept(handle Handle, out_socket *Handle) Status
+TEXT ·sys_socket_accept(SB),NOSPLIT,$0-20
+ MOVL handle+0(FP), DI
+ MOVQ out_socket+8(FP), SI
+ MOVQ vdso_zx_socket_accept(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_thread_exit()
+TEXT ·Sys_thread_exit(SB),NOSPLIT,$0-0
+ MOVQ vdso_zx_thread_exit(SB), AX
+ CALL AX
+ RET
+
+// func Sys_thread_create(process Handle, name *uint8, name_size uint, options uint32, out *Handle) Status
+TEXT ·Sys_thread_create(SB),NOSPLIT,$0-44
+ MOVL process+0(FP), DI
+ MOVQ name+8(FP), SI
+ MOVQ name_size+16(FP), DX
+ MOVL options+24(FP), CX
+ MOVQ out+32(FP), R8
+ MOVQ vdso_zx_thread_create(SB), AX
+ CALL AX
+ MOVL AX, ret+40(FP)
+ RET
+
+// func Sys_thread_start(handle Handle, thread_entry Vaddr, stack Vaddr, arg1 uintptr, arg2 uintptr) Status
+TEXT ·Sys_thread_start(SB),NOSPLIT,$0-44
+ MOVL handle+0(FP), DI
+ MOVQ thread_entry+8(FP), SI
+ MOVQ stack+16(FP), DX
+ MOVQ arg1+24(FP), CX
+ MOVQ arg2+32(FP), R8
+ MOVQ vdso_zx_thread_start(SB), AX
+ CALL AX
+ MOVL AX, ret+40(FP)
+ RET
+
+// func Sys_thread_read_state(handle Handle, kind uint32, buffer unsafe.Pointer, buffer_size uint) Status
+TEXT ·Sys_thread_read_state(SB),NOSPLIT,$0-28
+ MOVL handle+0(FP), DI
+ MOVL kind+4(FP), SI
+ MOVQ buffer+8(FP), DX
+ MOVQ buffer_size+16(FP), CX
+ MOVQ vdso_zx_thread_read_state(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func Sys_thread_write_state(handle Handle, kind uint32, buffer unsafe.Pointer, buffer_size uint) Status
+TEXT ·Sys_thread_write_state(SB),NOSPLIT,$0-28
+ MOVL handle+0(FP), DI
+ MOVL kind+4(FP), SI
+ MOVQ buffer+8(FP), DX
+ MOVQ buffer_size+16(FP), CX
+ MOVQ vdso_zx_thread_write_state(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func Sys_thread_set_priority(prio int32) Status
+TEXT ·Sys_thread_set_priority(SB),NOSPLIT,$0-12
+ MOVL prio+0(FP), DI
+ MOVQ vdso_zx_thread_set_priority(SB), AX
+ CALL AX
+ MOVL AX, ret+8(FP)
+ RET
+
+// func Sys_process_exit(retcode int64)
+TEXT ·Sys_process_exit(SB),NOSPLIT,$0-8
+ MOVQ retcode+0(FP), DI
+ MOVQ vdso_zx_process_exit(SB), AX
+ CALL AX
+ RET
+
+// func Sys_process_create(job Handle, name *uint8, name_size uint, options uint32, proc_handle *Handle, vmar_handle *Handle) Status
+TEXT ·Sys_process_create(SB),NOSPLIT,$0-52
+ MOVL job+0(FP), DI
+ MOVQ name+8(FP), SI
+ MOVQ name_size+16(FP), DX
+ MOVL options+24(FP), CX
+ MOVQ proc_handle+32(FP), R8
+ MOVQ vmar_handle+40(FP), R9
+ MOVQ vdso_zx_process_create(SB), AX
+ CALL AX
+ MOVL AX, ret+48(FP)
+ RET
+
+// func Sys_process_start(handle Handle, thread Handle, entry Vaddr, stack Vaddr, arg1 Handle, arg2 uintptr) Status
+TEXT ·Sys_process_start(SB),NOSPLIT,$0-44
+ MOVL handle+0(FP), DI
+ MOVL thread+4(FP), SI
+ MOVQ entry+8(FP), DX
+ MOVQ stack+16(FP), CX
+ MOVL arg1+24(FP), R8
+ MOVQ arg2+32(FP), R9
+ MOVQ vdso_zx_process_start(SB), AX
+ CALL AX
+ MOVL AX, ret+40(FP)
+ RET
+
+// func Sys_process_read_memory(proc Handle, vaddr Vaddr, buffer unsafe.Pointer, buffer_size uint, actual *uint) Status
+TEXT ·Sys_process_read_memory(SB),NOSPLIT,$0-44
+ MOVL proc+0(FP), DI
+ MOVQ vaddr+8(FP), SI
+ MOVQ buffer+16(FP), DX
+ MOVQ buffer_size+24(FP), CX
+ MOVQ actual+32(FP), R8
+ MOVQ vdso_zx_process_read_memory(SB), AX
+ CALL AX
+ MOVL AX, ret+40(FP)
+ RET
+
+// func Sys_process_write_memory(proc Handle, vaddr Vaddr, buffer unsafe.Pointer, buffer_size uint, actual *uint) Status
+TEXT ·Sys_process_write_memory(SB),NOSPLIT,$0-44
+ MOVL proc+0(FP), DI
+ MOVQ vaddr+8(FP), SI
+ MOVQ buffer+16(FP), DX
+ MOVQ buffer_size+24(FP), CX
+ MOVQ actual+32(FP), R8
+ MOVQ vdso_zx_process_write_memory(SB), AX
+ CALL AX
+ MOVL AX, ret+40(FP)
+ RET
+
+// func Sys_job_create(parent_job Handle, options uint32, out *Handle) Status
+TEXT ·Sys_job_create(SB),NOSPLIT,$0-20
+ MOVL parent_job+0(FP), DI
+ MOVL options+4(FP), SI
+ MOVQ out+8(FP), DX
+ MOVQ vdso_zx_job_create(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_job_set_policy(job Handle, options uint32, topic uint32, policy unsafe.Pointer, count uint32) Status
+TEXT ·Sys_job_set_policy(SB),NOSPLIT,$0-36
+ MOVL job+0(FP), DI
+ MOVL options+4(FP), SI
+ MOVL topic+8(FP), DX
+ MOVQ policy+16(FP), CX
+ MOVL count+24(FP), R8
+ MOVQ vdso_zx_job_set_policy(SB), AX
+ CALL AX
+ MOVL AX, ret+32(FP)
+ RET
+
+// func Sys_task_bind_exception_port(handle Handle, port Handle, key uint64, options uint32) Status
+TEXT ·Sys_task_bind_exception_port(SB),NOSPLIT,$0-28
+ MOVL handle+0(FP), DI
+ MOVL port+4(FP), SI
+ MOVQ key+8(FP), DX
+ MOVL options+16(FP), CX
+ MOVQ vdso_zx_task_bind_exception_port(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func Sys_task_resume(handle Handle, options uint32) Status
+TEXT ·Sys_task_resume(SB),NOSPLIT,$0-12
+ MOVL handle+0(FP), DI
+ MOVL options+4(FP), SI
+ MOVQ vdso_zx_task_resume(SB), AX
+ CALL AX
+ MOVL AX, ret+8(FP)
+ RET
+
+// func Sys_task_suspend(handle Handle, token *Handle) Status
+TEXT ·Sys_task_suspend(SB),NOSPLIT,$0-20
+ MOVL handle+0(FP), DI
+ MOVQ token+8(FP), SI
+ MOVQ vdso_zx_task_suspend(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_task_suspend_token(handle Handle, token *Handle) Status
+TEXT ·Sys_task_suspend_token(SB),NOSPLIT,$0-20
+ MOVL handle+0(FP), DI
+ MOVQ token+8(FP), SI
+ MOVQ vdso_zx_task_suspend_token(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_task_resume_from_exception(handle Handle, port Handle, options uint32) Status
+TEXT ·Sys_task_resume_from_exception(SB),NOSPLIT,$0-20
+ MOVL handle+0(FP), DI
+ MOVL port+4(FP), SI
+ MOVL options+8(FP), DX
+ MOVQ vdso_zx_task_resume_from_exception(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_task_kill(handle Handle) Status
+TEXT ·Sys_task_kill(SB),NOSPLIT,$0-12
+ MOVL handle+0(FP), DI
+ MOVQ vdso_zx_task_kill(SB), AX
+ CALL AX
+ MOVL AX, ret+8(FP)
+ RET
+
+// func Sys_event_create(options uint32, out *Handle) Status
+TEXT ·Sys_event_create(SB),NOSPLIT,$0-20
+ MOVL options+0(FP), DI
+ MOVQ out+8(FP), SI
+ MOVQ vdso_zx_event_create(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_eventpair_create(options uint32, out0 *Handle, out1 *Handle) Status
+TEXT ·Sys_eventpair_create(SB),NOSPLIT,$0-28
+ MOVL options+0(FP), DI
+ MOVQ out0+8(FP), SI
+ MOVQ out1+16(FP), DX
+ MOVQ vdso_zx_eventpair_create(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func Sys_futex_wait(value_ptr *int, current_value int32, deadline Time) Status
+TEXT ·Sys_futex_wait(SB),NOSPLIT,$0-28
+ MOVQ value_ptr+0(FP), DI
+ MOVL current_value+8(FP), SI
+ MOVQ deadline+16(FP), DX
+ MOVQ vdso_zx_futex_wait(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func Sys_futex_wake(value_ptr *int, count uint32) Status
+TEXT ·Sys_futex_wake(SB),NOSPLIT,$0-20
+ MOVQ value_ptr+0(FP), DI
+ MOVL count+8(FP), SI
+ MOVQ vdso_zx_futex_wake(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_futex_requeue(wake_ptr *int, wake_count uint32, current_value int32, requeue_ptr *int, requeue_count uint32) Status
+TEXT ·Sys_futex_requeue(SB),NOSPLIT,$0-36
+ MOVQ wake_ptr+0(FP), DI
+ MOVL wake_count+8(FP), SI
+ MOVL current_value+12(FP), DX
+ MOVQ requeue_ptr+16(FP), CX
+ MOVL requeue_count+24(FP), R8
+ MOVQ vdso_zx_futex_requeue(SB), AX
+ CALL AX
+ MOVL AX, ret+32(FP)
+ RET
+
+// func Sys_port_create(options uint32, out *Handle) Status
+TEXT ·Sys_port_create(SB),NOSPLIT,$0-20
+ MOVL options+0(FP), DI
+ MOVQ out+8(FP), SI
+ MOVQ vdso_zx_port_create(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_port_queue(handle Handle, packet *int) Status
+TEXT ·Sys_port_queue(SB),NOSPLIT,$0-20
+ MOVL handle+0(FP), DI
+ MOVQ packet+8(FP), SI
+ MOVQ vdso_zx_port_queue(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_port_wait(handle Handle, deadline Time, packet *int) Status
+TEXT ·Sys_port_wait(SB),NOSPLIT,$0-28
+ CALL runtime·entersyscall(SB)
+ MOVL handle+0(FP), DI
+ MOVQ deadline+8(FP), SI
+ MOVQ packet+16(FP), DX
+ MOVQ vdso_zx_port_wait(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ CALL runtime·exitsyscall(SB)
+ RET
+
+// func Sys_port_cancel(handle Handle, source Handle, key uint64) Status
+TEXT ·Sys_port_cancel(SB),NOSPLIT,$0-20
+ MOVL handle+0(FP), DI
+ MOVL source+4(FP), SI
+ MOVQ key+8(FP), DX
+ MOVQ vdso_zx_port_cancel(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_timer_create(options uint32, clock_id uint32, out *Handle) Status
+TEXT ·Sys_timer_create(SB),NOSPLIT,$0-20
+ MOVL options+0(FP), DI
+ MOVL clock_id+4(FP), SI
+ MOVQ out+8(FP), DX
+ MOVQ vdso_zx_timer_create(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_timer_set(handle Handle, deadline Time, slack Duration) Status
+TEXT ·Sys_timer_set(SB),NOSPLIT,$0-28
+ MOVL handle+0(FP), DI
+ MOVQ deadline+8(FP), SI
+ MOVQ slack+16(FP), DX
+ MOVQ vdso_zx_timer_set(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func Sys_timer_cancel(handle Handle) Status
+TEXT ·Sys_timer_cancel(SB),NOSPLIT,$0-12
+ MOVL handle+0(FP), DI
+ MOVQ vdso_zx_timer_cancel(SB), AX
+ CALL AX
+ MOVL AX, ret+8(FP)
+ RET
+
+// func Sys_vmo_create(size uint64, options uint32, out *Handle) Status
+TEXT ·Sys_vmo_create(SB),NOSPLIT,$0-28
+ MOVQ size+0(FP), DI
+ MOVL options+8(FP), SI
+ MOVQ out+16(FP), DX
+ MOVQ vdso_zx_vmo_create(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func sys_vmo_read(handle Handle, buffer unsafe.Pointer, offset uint64, buffer_size uint) Status
+TEXT ·sys_vmo_read(SB),NOSPLIT,$0-36
+ MOVL handle+0(FP), DI
+ MOVQ buffer+8(FP), SI
+ MOVQ offset+16(FP), DX
+ MOVQ buffer_size+24(FP), CX
+ MOVQ vdso_zx_vmo_read(SB), AX
+ CALL AX
+ MOVL AX, ret+32(FP)
+ RET
+
+// func sys_vmo_write(handle Handle, buffer unsafe.Pointer, offset uint64, buffer_size uint) Status
+TEXT ·sys_vmo_write(SB),NOSPLIT,$0-36
+ MOVL handle+0(FP), DI
+ MOVQ buffer+8(FP), SI
+ MOVQ offset+16(FP), DX
+ MOVQ buffer_size+24(FP), CX
+ MOVQ vdso_zx_vmo_write(SB), AX
+ CALL AX
+ MOVL AX, ret+32(FP)
+ RET
+
+// func sys_vmo_get_size(handle Handle, size *uint64) Status
+TEXT ·sys_vmo_get_size(SB),NOSPLIT,$0-20
+ MOVL handle+0(FP), DI
+ MOVQ size+8(FP), SI
+ MOVQ vdso_zx_vmo_get_size(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func sys_vmo_set_size(handle Handle, size uint64) Status
+TEXT ·sys_vmo_set_size(SB),NOSPLIT,$0-20
+ MOVL handle+0(FP), DI
+ MOVQ size+8(FP), SI
+ MOVQ vdso_zx_vmo_set_size(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func sys_vmo_op_range(handle Handle, op uint32, offset uint64, size uint64, buffer unsafe.Pointer, buffer_size uint) Status
+TEXT ·sys_vmo_op_range(SB),NOSPLIT,$0-44
+ MOVL handle+0(FP), DI
+ MOVL op+4(FP), SI
+ MOVQ offset+8(FP), DX
+ MOVQ size+16(FP), CX
+ MOVQ buffer+24(FP), R8
+ MOVQ buffer_size+32(FP), R9
+ MOVQ vdso_zx_vmo_op_range(SB), AX
+ CALL AX
+ MOVL AX, ret+40(FP)
+ RET
+
+// func Sys_vmo_clone(handle Handle, options uint32, offset uint64, size uint64, out *Handle) Status
+TEXT ·Sys_vmo_clone(SB),NOSPLIT,$0-36
+ MOVL handle+0(FP), DI
+ MOVL options+4(FP), SI
+ MOVQ offset+8(FP), DX
+ MOVQ size+16(FP), CX
+ MOVQ out+24(FP), R8
+ MOVQ vdso_zx_vmo_clone(SB), AX
+ CALL AX
+ MOVL AX, ret+32(FP)
+ RET
+
+// func Sys_vmo_set_cache_policy(handle Handle, cache_policy uint32) Status
+TEXT ·Sys_vmo_set_cache_policy(SB),NOSPLIT,$0-12
+ MOVL handle+0(FP), DI
+ MOVL cache_policy+4(FP), SI
+ MOVQ vdso_zx_vmo_set_cache_policy(SB), AX
+ CALL AX
+ MOVL AX, ret+8(FP)
+ RET
+
+// func sys_vmar_allocate_old(parent_vmar Handle, offset uint64, size uint64, map_flags uint32, child_vmar *Handle, child_addr *Vaddr) Status
+TEXT ·sys_vmar_allocate_old(SB),NOSPLIT,$0-52
+ MOVL parent_vmar+0(FP), DI
+ MOVQ offset+8(FP), SI
+ MOVQ size+16(FP), DX
+ MOVL map_flags+24(FP), CX
+ MOVQ child_vmar+32(FP), R8
+ MOVQ child_addr+40(FP), R9
+ MOVQ vdso_zx_vmar_allocate_old(SB), AX
+ CALL AX
+ MOVL AX, ret+48(FP)
+ RET
+
+// func sys_vmar_map_old(handle Handle, vmar_offset uint64, vmo Handle, vmo_offset uint64, len uint64, map_flags uint32, mapped_addr *Vaddr) Status
+TEXT ·sys_vmar_map_old(SB),NOSPLIT,$24-60
+ MOVL handle+0(FP), DI
+ MOVQ vmar_offset+8(FP), SI
+ MOVL vmo+16(FP), DX
+ MOVQ vmo_offset+24(FP), CX
+ MOVQ len+32(FP), R8
+ MOVL map_flags+40(FP), R9
+ MOVQ mapped_addr+48(FP), R12
+ MOVQ SP, BP // BP is preserved across vsdo call by the x86-64 ABI
+ ANDQ $~15, SP // stack alignment for x86-64 ABI
+ PUSHQ R12
+ MOVQ vdso_zx_vmar_map_old(SB), AX
+ CALL AX
+ POPQ R12
+ MOVQ BP, SP
+ MOVL AX, ret+56(FP)
+ RET
+
+// func sys_vmar_protect_old(handle Handle, addr Vaddr, len uint64, prot_flags uint32) Status
+TEXT ·sys_vmar_protect_old(SB),NOSPLIT,$0-36
+ MOVL handle+0(FP), DI
+ MOVQ addr+8(FP), SI
+ MOVQ len+16(FP), DX
+ MOVL prot_flags+24(FP), CX
+ MOVQ vdso_zx_vmar_protect_old(SB), AX
+ CALL AX
+ MOVL AX, ret+32(FP)
+ RET
+
+// func sys_vmar_allocate(parent_vmar Handle, offset uint64, size uint64, map_flags uint32, child_vmar *Handle, child_addr *Vaddr) Status
+TEXT ·sys_vmar_allocate(SB),NOSPLIT,$0-52
+ MOVL parent_vmar+0(FP), DI
+ MOVQ offset+8(FP), SI
+ MOVQ size+16(FP), DX
+ MOVL map_flags+24(FP), CX
+ MOVQ child_vmar+32(FP), R8
+ MOVQ child_addr+40(FP), R9
+ MOVQ vdso_zx_vmar_allocate(SB), AX
+ CALL AX
+ MOVL AX, ret+48(FP)
+ RET
+
+// func sys_vmar_destroy(handle Handle) Status
+TEXT ·sys_vmar_destroy(SB),NOSPLIT,$0-12
+ MOVL handle+0(FP), DI
+ MOVQ vdso_zx_vmar_destroy(SB), AX
+ CALL AX
+ MOVL AX, ret+8(FP)
+ RET
+
+// func Sys_vmar_map(handle Handle, vmar_offset uint64, vmo Handle, vmo_offset uint64, len uint64, map_flags uint32, mapped_addr *Vaddr) Status
+TEXT ·Sys_vmar_map(SB),NOSPLIT,$24-60
+ MOVL handle+0(FP), DI
+ MOVQ vmar_offset+8(FP), SI
+ MOVL vmo+16(FP), DX
+ MOVQ vmo_offset+24(FP), CX
+ MOVQ len+32(FP), R8
+ MOVL map_flags+40(FP), R9
+ MOVQ mapped_addr+48(FP), R12
+ MOVQ SP, BP // BP is preserved across vsdo call by the x86-64 ABI
+ ANDQ $~15, SP // stack alignment for x86-64 ABI
+ PUSHQ R12
+ MOVQ vdso_zx_vmar_map(SB), AX
+ CALL AX
+ POPQ R12
+ MOVQ BP, SP
+ MOVL AX, ret+56(FP)
+ RET
+
+// func Sys_vmar_unmap(handle Handle, addr Vaddr, len uint64) Status
+TEXT ·Sys_vmar_unmap(SB),NOSPLIT,$0-28
+ MOVL handle+0(FP), DI
+ MOVQ addr+8(FP), SI
+ MOVQ len+16(FP), DX
+ MOVQ vdso_zx_vmar_unmap(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func Sys_vmar_protect(handle Handle, addr Vaddr, len uint64, prot_flags uint32) Status
+TEXT ·Sys_vmar_protect(SB),NOSPLIT,$0-36
+ MOVL handle+0(FP), DI
+ MOVQ addr+8(FP), SI
+ MOVQ len+16(FP), DX
+ MOVL prot_flags+24(FP), CX
+ MOVQ vdso_zx_vmar_protect(SB), AX
+ CALL AX
+ MOVL AX, ret+32(FP)
+ RET
+
+// func Sys_cprng_draw_once(buffer unsafe.Pointer, buffer_size uint) Status
+TEXT ·Sys_cprng_draw_once(SB),NOSPLIT,$0-20
+ MOVQ buffer+0(FP), DI
+ MOVQ buffer_size+8(FP), SI
+ MOVQ vdso_zx_cprng_draw_once(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_cprng_draw(buffer unsafe.Pointer, buffer_size uint)
+TEXT ·Sys_cprng_draw(SB),NOSPLIT,$0-16
+ MOVQ buffer+0(FP), DI
+ MOVQ buffer_size+8(FP), SI
+ MOVQ vdso_zx_cprng_draw(SB), AX
+ CALL AX
+ RET
+
+// func Sys_cprng_draw_new(buffer unsafe.Pointer, data_size uint) Status
+TEXT ·Sys_cprng_draw_new(SB),NOSPLIT,$0-20
+ MOVQ buffer+0(FP), DI
+ MOVQ data_size+8(FP), SI
+ MOVQ vdso_zx_cprng_draw_new(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_cprng_add_entropy(buffer unsafe.Pointer, len uint) Status
+TEXT ·Sys_cprng_add_entropy(SB),NOSPLIT,$0-20
+ MOVQ buffer+0(FP), DI
+ MOVQ len+8(FP), SI
+ MOVQ vdso_zx_cprng_add_entropy(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_fifo_create(elem_count uint, elem_size uint, options uint32, out0 *Handle, out1 *Handle) Status
+TEXT ·Sys_fifo_create(SB),NOSPLIT,$0-44
+ MOVQ elem_count+0(FP), DI
+ MOVQ elem_size+8(FP), SI
+ MOVL options+16(FP), DX
+ MOVQ out0+24(FP), CX
+ MOVQ out1+32(FP), R8
+ MOVQ vdso_zx_fifo_create(SB), AX
+ CALL AX
+ MOVL AX, ret+40(FP)
+ RET
+
+// func Sys_fifo_read(handle Handle, elem_size uint, data unsafe.Pointer, count uint, actual_count *uint) Status
+TEXT ·Sys_fifo_read(SB),NOSPLIT,$0-44
+ MOVL handle+0(FP), DI
+ MOVQ elem_size+8(FP), SI
+ MOVQ data+16(FP), DX
+ MOVQ count+24(FP), CX
+ MOVQ actual_count+32(FP), R8
+ MOVQ vdso_zx_fifo_read(SB), AX
+ CALL AX
+ MOVL AX, ret+40(FP)
+ RET
+
+// func Sys_fifo_write(handle Handle, elem_size uint, data unsafe.Pointer, count uint, actual_count *uint) Status
+TEXT ·Sys_fifo_write(SB),NOSPLIT,$0-44
+ MOVL handle+0(FP), DI
+ MOVQ elem_size+8(FP), SI
+ MOVQ data+16(FP), DX
+ MOVQ count+24(FP), CX
+ MOVQ actual_count+32(FP), R8
+ MOVQ vdso_zx_fifo_write(SB), AX
+ CALL AX
+ MOVL AX, ret+40(FP)
+ RET
+
+// func Sys_profile_create(resource Handle, profile *int, out *Handle) Status
+TEXT ·Sys_profile_create(SB),NOSPLIT,$0-28
+ MOVL resource+0(FP), DI
+ MOVQ profile+8(FP), SI
+ MOVQ out+16(FP), DX
+ MOVQ vdso_zx_profile_create(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func Sys_vmar_unmap_handle_close_thread_exit(vmar_handle Handle, addr Vaddr, size uint, handle Handle) Status
+TEXT ·Sys_vmar_unmap_handle_close_thread_exit(SB),NOSPLIT,$0-36
+ MOVL vmar_handle+0(FP), DI
+ MOVQ addr+8(FP), SI
+ MOVQ size+16(FP), DX
+ MOVL handle+24(FP), CX
+ MOVQ vdso_zx_vmar_unmap_handle_close_thread_exit(SB), AX
+ CALL AX
+ MOVL AX, ret+32(FP)
+ RET
+
+// func Sys_futex_wake_handle_close_thread_exit(value_ptr *int, count uint32, new_value int32, handle Handle)
+TEXT ·Sys_futex_wake_handle_close_thread_exit(SB),NOSPLIT,$0-24
+ MOVQ value_ptr+0(FP), DI
+ MOVL count+8(FP), SI
+ MOVL new_value+12(FP), DX
+ MOVL handle+16(FP), CX
+ MOVQ vdso_zx_futex_wake_handle_close_thread_exit(SB), AX
+ CALL AX
+ RET
+
+// func Sys_log_write(handle Handle, len uint32, buffer unsafe.Pointer, options uint32) Status
+TEXT ·Sys_log_write(SB),NOSPLIT,$0-28
+ MOVL handle+0(FP), DI
+ MOVL len+4(FP), SI
+ MOVQ buffer+8(FP), DX
+ MOVL options+16(FP), CX
+ MOVQ vdso_zx_log_write(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func Sys_log_read(handle Handle, len uint32, buffer unsafe.Pointer, options uint32) Status
+TEXT ·Sys_log_read(SB),NOSPLIT,$0-28
+ MOVL handle+0(FP), DI
+ MOVL len+4(FP), SI
+ MOVQ buffer+8(FP), DX
+ MOVL options+16(FP), CX
+ MOVQ vdso_zx_log_read(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func Sys_debuglog_create(resource Handle, options uint32, out *Handle) Status
+TEXT ·Sys_debuglog_create(SB),NOSPLIT,$0-20
+ MOVL resource+0(FP), DI
+ MOVL options+4(FP), SI
+ MOVQ out+8(FP), DX
+ MOVQ vdso_zx_debuglog_create(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_debuglog_write(handle Handle, options uint32, buffer unsafe.Pointer, buffer_size uint) Status
+TEXT ·Sys_debuglog_write(SB),NOSPLIT,$0-28
+ MOVL handle+0(FP), DI
+ MOVL options+4(FP), SI
+ MOVQ buffer+8(FP), DX
+ MOVQ buffer_size+16(FP), CX
+ MOVQ vdso_zx_debuglog_write(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func Sys_debuglog_read(handle Handle, options uint32, buffer unsafe.Pointer, buffer_size uint) Status
+TEXT ·Sys_debuglog_read(SB),NOSPLIT,$0-28
+ MOVL handle+0(FP), DI
+ MOVL options+4(FP), SI
+ MOVQ buffer+8(FP), DX
+ MOVQ buffer_size+16(FP), CX
+ MOVQ vdso_zx_debuglog_read(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func Sys_ktrace_read(handle Handle, data unsafe.Pointer, offset uint32, data_size uint, actual *uint) Status
+TEXT ·Sys_ktrace_read(SB),NOSPLIT,$0-44
+ MOVL handle+0(FP), DI
+ MOVQ data+8(FP), SI
+ MOVL offset+16(FP), DX
+ MOVQ data_size+24(FP), CX
+ MOVQ actual+32(FP), R8
+ MOVQ vdso_zx_ktrace_read(SB), AX
+ CALL AX
+ MOVL AX, ret+40(FP)
+ RET
+
+// func Sys_ktrace_control(handle Handle, action uint32, options uint32, ptr unsafe.Pointer) Status
+TEXT ·Sys_ktrace_control(SB),NOSPLIT,$0-28
+ MOVL handle+0(FP), DI
+ MOVL action+4(FP), SI
+ MOVL options+8(FP), DX
+ MOVQ ptr+16(FP), CX
+ MOVQ vdso_zx_ktrace_control(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func Sys_ktrace_write(handle Handle, id uint32, arg0 uint32, arg1 uint32) Status
+TEXT ·Sys_ktrace_write(SB),NOSPLIT,$0-20
+ MOVL handle+0(FP), DI
+ MOVL id+4(FP), SI
+ MOVL arg0+8(FP), DX
+ MOVL arg1+12(FP), CX
+ MOVQ vdso_zx_ktrace_write(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_mtrace_control(handle Handle, kind uint32, action uint32, options uint32, ptr unsafe.Pointer, ptr_size uint) Status
+TEXT ·Sys_mtrace_control(SB),NOSPLIT,$0-36
+ MOVL handle+0(FP), DI
+ MOVL kind+4(FP), SI
+ MOVL action+8(FP), DX
+ MOVL options+12(FP), CX
+ MOVQ ptr+16(FP), R8
+ MOVQ ptr_size+24(FP), R9
+ MOVQ vdso_zx_mtrace_control(SB), AX
+ CALL AX
+ MOVL AX, ret+32(FP)
+ RET
+
+// func Sys_debug_read(handle Handle, buffer *uint8, buffer_size *uint) Status
+TEXT ·Sys_debug_read(SB),NOSPLIT,$0-28
+ MOVL handle+0(FP), DI
+ MOVQ buffer+8(FP), SI
+ MOVQ buffer_size+16(FP), DX
+ MOVQ vdso_zx_debug_read(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func Sys_debug_write(buffer *uint8, buffer_size uint) Status
+TEXT ·Sys_debug_write(SB),NOSPLIT,$0-20
+ MOVQ buffer+0(FP), DI
+ MOVQ buffer_size+8(FP), SI
+ MOVQ vdso_zx_debug_write(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_debug_send_command(resource Handle, buffer *uint8, buffer_size uint) Status
+TEXT ·Sys_debug_send_command(SB),NOSPLIT,$0-28
+ MOVL resource+0(FP), DI
+ MOVQ buffer+8(FP), SI
+ MOVQ buffer_size+16(FP), DX
+ MOVQ vdso_zx_debug_send_command(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func Sys_interrupt_create(src_obj Handle, src_num uint32, options uint32, out *Handle) Status
+TEXT ·Sys_interrupt_create(SB),NOSPLIT,$0-28
+ MOVL src_obj+0(FP), DI
+ MOVL src_num+4(FP), SI
+ MOVL options+8(FP), DX
+ MOVQ out+16(FP), CX
+ MOVQ vdso_zx_interrupt_create(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func Sys_interrupt_bind(handle Handle, port Handle, key uint64, options uint32) Status
+TEXT ·Sys_interrupt_bind(SB),NOSPLIT,$0-28
+ MOVL handle+0(FP), DI
+ MOVL port+4(FP), SI
+ MOVQ key+8(FP), DX
+ MOVL options+16(FP), CX
+ MOVQ vdso_zx_interrupt_bind(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func Sys_interrupt_wait(handle Handle, out_timestamp *Time) Status
+TEXT ·Sys_interrupt_wait(SB),NOSPLIT,$0-20
+ MOVL handle+0(FP), DI
+ MOVQ out_timestamp+8(FP), SI
+ MOVQ vdso_zx_interrupt_wait(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_interrupt_destroy(handle Handle) Status
+TEXT ·Sys_interrupt_destroy(SB),NOSPLIT,$0-12
+ MOVL handle+0(FP), DI
+ MOVQ vdso_zx_interrupt_destroy(SB), AX
+ CALL AX
+ MOVL AX, ret+8(FP)
+ RET
+
+// func Sys_interrupt_ack(handle Handle) Status
+TEXT ·Sys_interrupt_ack(SB),NOSPLIT,$0-12
+ MOVL handle+0(FP), DI
+ MOVQ vdso_zx_interrupt_ack(SB), AX
+ CALL AX
+ MOVL AX, ret+8(FP)
+ RET
+
+// func Sys_interrupt_trigger(handle Handle, options uint32, timestamp Time) Status
+TEXT ·Sys_interrupt_trigger(SB),NOSPLIT,$0-20
+ MOVL handle+0(FP), DI
+ MOVL options+4(FP), SI
+ MOVQ timestamp+8(FP), DX
+ MOVQ vdso_zx_interrupt_trigger(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_ioports_request(resource Handle, io_addr uint16, len uint32) Status
+TEXT ·Sys_ioports_request(SB),NOSPLIT,$0-20
+ MOVL resource+0(FP), DI
+ MOVQ io_addr+4(FP), SI
+ MOVL len+8(FP), DX
+ MOVQ vdso_zx_ioports_request(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_vmo_create_contiguous(bti Handle, size uint, alignment_log2 uint32, out *Handle) Status
+TEXT ·Sys_vmo_create_contiguous(SB),NOSPLIT,$0-36
+ MOVL bti+0(FP), DI
+ MOVQ size+8(FP), SI
+ MOVL alignment_log2+16(FP), DX
+ MOVQ out+24(FP), CX
+ MOVQ vdso_zx_vmo_create_contiguous(SB), AX
+ CALL AX
+ MOVL AX, ret+32(FP)
+ RET
+
+// func Sys_vmo_create_physical(resource Handle, paddr Paddr, size uint, out *Handle) Status
+TEXT ·Sys_vmo_create_physical(SB),NOSPLIT,$0-36
+ MOVL resource+0(FP), DI
+ MOVQ paddr+8(FP), SI
+ MOVQ size+16(FP), DX
+ MOVQ out+24(FP), CX
+ MOVQ vdso_zx_vmo_create_physical(SB), AX
+ CALL AX
+ MOVL AX, ret+32(FP)
+ RET
+
+// func Sys_iommu_create(resource Handle, typ uint32, desc unsafe.Pointer, desc_size uint, out *Handle) Status
+TEXT ·Sys_iommu_create(SB),NOSPLIT,$0-36
+ MOVL resource+0(FP), DI
+ MOVL typ+4(FP), SI
+ MOVQ desc+8(FP), DX
+ MOVQ desc_size+16(FP), CX
+ MOVQ out+24(FP), R8
+ MOVQ vdso_zx_iommu_create(SB), AX
+ CALL AX
+ MOVL AX, ret+32(FP)
+ RET
+
+// func Sys_bti_create(iommu Handle, options uint32, bti_id uint64, out *Handle) Status
+TEXT ·Sys_bti_create(SB),NOSPLIT,$0-28
+ MOVL iommu+0(FP), DI
+ MOVL options+4(FP), SI
+ MOVQ bti_id+8(FP), DX
+ MOVQ out+16(FP), CX
+ MOVQ vdso_zx_bti_create(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func Sys_bti_pin(handle Handle, options uint32, vmo Handle, offset uint64, size uint64, addrs *Paddr, addrs_count uint, out *Handle) Status
+TEXT ·Sys_bti_pin(SB),NOSPLIT,$32-60
+ MOVL handle+0(FP), DI
+ MOVL options+4(FP), SI
+ MOVL vmo+8(FP), DX
+ MOVQ offset+16(FP), CX
+ MOVQ size+24(FP), R8
+ MOVQ addrs+32(FP), R9
+ MOVQ addrs_count+40(FP), R12
+ MOVQ out+48(FP), R13
+ MOVQ SP, BP // BP is preserved across vsdo call by the x86-64 ABI
+ ANDQ $~15, SP // stack alignment for x86-64 ABI
+ PUSHQ R13
+ PUSHQ R12
+ MOVQ vdso_zx_bti_pin(SB), AX
+ CALL AX
+ POPQ R12
+ POPQ R13
+ MOVQ BP, SP
+ MOVL AX, ret+56(FP)
+ RET
+
+// func Sys_bti_release_quarantine(handle Handle) Status
+TEXT ·Sys_bti_release_quarantine(SB),NOSPLIT,$0-12
+ MOVL handle+0(FP), DI
+ MOVQ vdso_zx_bti_release_quarantine(SB), AX
+ CALL AX
+ MOVL AX, ret+8(FP)
+ RET
+
+// func Sys_pmt_unpin(handle Handle) Status
+TEXT ·Sys_pmt_unpin(SB),NOSPLIT,$0-12
+ MOVL handle+0(FP), DI
+ MOVQ vdso_zx_pmt_unpin(SB), AX
+ CALL AX
+ MOVL AX, ret+8(FP)
+ RET
+
+// func Sys_framebuffer_get_info(resource Handle, format *uint32, width *uint32, height *uint32, stride *uint32) Status
+TEXT ·Sys_framebuffer_get_info(SB),NOSPLIT,$0-44
+ MOVL resource+0(FP), DI
+ MOVQ format+8(FP), SI
+ MOVQ width+16(FP), DX
+ MOVQ height+24(FP), CX
+ MOVQ stride+32(FP), R8
+ MOVQ vdso_zx_framebuffer_get_info(SB), AX
+ CALL AX
+ MOVL AX, ret+40(FP)
+ RET
+
+// func Sys_framebuffer_set_range(resource Handle, vmo Handle, len uint32, format uint32, width uint32, height uint32, stride uint32) Status
+TEXT ·Sys_framebuffer_set_range(SB),NOSPLIT,$24-36
+ MOVL resource+0(FP), DI
+ MOVL vmo+4(FP), SI
+ MOVL len+8(FP), DX
+ MOVL format+12(FP), CX
+ MOVL width+16(FP), R8
+ MOVL height+20(FP), R9
+ MOVL stride+24(FP), R12
+ MOVQ SP, BP // BP is preserved across vsdo call by the x86-64 ABI
+ ANDQ $~15, SP // stack alignment for x86-64 ABI
+ PUSHQ R12
+ MOVQ vdso_zx_framebuffer_set_range(SB), AX
+ CALL AX
+ POPQ R12
+ MOVQ BP, SP
+ MOVL AX, ret+32(FP)
+ RET
+
+// func Sys_pc_firmware_tables(handle Handle, acpi_rsdp *Paddr, smbios *Paddr) Status
+TEXT ·Sys_pc_firmware_tables(SB),NOSPLIT,$0-28
+ MOVL handle+0(FP), DI
+ MOVQ acpi_rsdp+8(FP), SI
+ MOVQ smbios+16(FP), DX
+ MOVQ vdso_zx_pc_firmware_tables(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func Sys_smc_call(handle Handle, parameters *SMCParameters, out_smc_result *SMCResult) Status
+TEXT ·Sys_smc_call(SB),NOSPLIT,$0-28
+ MOVL handle+0(FP), DI
+ MOVQ parameters+8(FP), SI
+ MOVQ out_smc_result+16(FP), DX
+ MOVQ vdso_zx_smc_call(SB), AX
+ CALL AX
+ MOVL AX, ret+24(FP)
+ RET
+
+// func Sys_resource_create(parent_rsrc Handle, options uint32, base uint64, size uint, name *uint8, name_size uint, resource_out *Handle) Status
+TEXT ·Sys_resource_create(SB),NOSPLIT,$24-52
+ MOVL parent_rsrc+0(FP), DI
+ MOVL options+4(FP), SI
+ MOVQ base+8(FP), DX
+ MOVQ size+16(FP), CX
+ MOVQ name+24(FP), R8
+ MOVQ name_size+32(FP), R9
+ MOVQ resource_out+40(FP), R12
+ MOVQ SP, BP // BP is preserved across vsdo call by the x86-64 ABI
+ ANDQ $~15, SP // stack alignment for x86-64 ABI
+ PUSHQ R12
+ MOVQ vdso_zx_resource_create(SB), AX
+ CALL AX
+ POPQ R12
+ MOVQ BP, SP
+ MOVL AX, ret+48(FP)
+ RET
+
+// func Sys_system_mexec(resource Handle, kernel Handle, bootimage Handle) Status
+TEXT ·Sys_system_mexec(SB),NOSPLIT,$0-20
+ MOVL resource+0(FP), DI
+ MOVL kernel+4(FP), SI
+ MOVL bootimage+8(FP), DX
+ MOVQ vdso_zx_system_mexec(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
+// func Sys_system_powerctl(resource Handle, cmd uint32, arg *int) Status
+TEXT ·Sys_system_powerctl(SB),NOSPLIT,$0-20
+ MOVL resource+0(FP), DI
+ MOVL cmd+4(FP), SI
+ MOVQ arg+8(FP), DX
+ MOVQ vdso_zx_system_powerctl(SB), AX
+ CALL AX
+ MOVL AX, ret+16(FP)
+ RET
+
diff --git a/src/syscall/zx/syscalls_fuchsia_arm64.s b/src/syscall/zx/syscalls_fuchsia_arm64.s
new file mode 100644
index 0000000..13a2a13
--- /dev/null
+++ b/src/syscall/zx/syscalls_fuchsia_arm64.s
@@ -0,0 +1,1248 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Zircon system calls for the Fuchsia OS.
+// Generated by mkfuchsia.go, do not edit.
+
+#include "textflag.h"
+
+// func Sys_clock_get(clock_id uint32) Time
+TEXT ·Sys_clock_get(SB),NOSPLIT,$0-16
+ MOVW clock_id+0(FP), R0
+ BL vdso_zx_clock_get(SB)
+ MOVD R0, ret+8(FP)
+ RET
+
+// func Sys_clock_get_new(clock_id uint32, out *Time) Status
+TEXT ·Sys_clock_get_new(SB),NOSPLIT,$0-20
+ MOVW clock_id+0(FP), R0
+ MOVD out+8(FP), R1
+ BL vdso_zx_clock_get_new(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_clock_get_monotonic() Time
+TEXT ·Sys_clock_get_monotonic(SB),NOSPLIT,$0-8
+ BL vdso_zx_clock_get_monotonic(SB)
+ MOVD R0, ret+0(FP)
+ RET
+
+// func Sys_nanosleep(deadline Time) Status
+TEXT ·Sys_nanosleep(SB),NOSPLIT,$0-12
+ MOVD deadline+0(FP), R0
+ BL vdso_zx_nanosleep(SB)
+ MOVW R0, ret+8(FP)
+ RET
+
+// func Sys_ticks_get() uint64
+TEXT ·Sys_ticks_get(SB),NOSPLIT,$0-8
+ BL vdso_zx_ticks_get(SB)
+ MOVD R0, ret+0(FP)
+ RET
+
+// func Sys_ticks_per_second() uint64
+TEXT ·Sys_ticks_per_second(SB),NOSPLIT,$0-8
+ BL vdso_zx_ticks_per_second(SB)
+ MOVD R0, ret+0(FP)
+ RET
+
+// func Sys_deadline_after(nanoseconds Duration) Time
+TEXT ·Sys_deadline_after(SB),NOSPLIT,$0-16
+ MOVD nanoseconds+0(FP), R0
+ BL vdso_zx_deadline_after(SB)
+ MOVD R0, ret+8(FP)
+ RET
+
+// func Sys_clock_adjust(handle Handle, clock_id uint32, offset int64) Status
+TEXT ·Sys_clock_adjust(SB),NOSPLIT,$0-20
+ MOVW handle+0(FP), R0
+ MOVW clock_id+4(FP), R1
+ MOVD offset+8(FP), R2
+ BL vdso_zx_clock_adjust(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func sys_system_get_dcache_line_size() uint32
+TEXT ·sys_system_get_dcache_line_size(SB),NOSPLIT,$0-4
+ BL vdso_zx_system_get_dcache_line_size(SB)
+ MOVW R0, ret+0(FP)
+ RET
+
+// func Sys_system_get_num_cpus() uint32
+TEXT ·Sys_system_get_num_cpus(SB),NOSPLIT,$0-4
+ BL vdso_zx_system_get_num_cpus(SB)
+ MOVW R0, ret+0(FP)
+ RET
+
+// func Sys_system_get_version(version *uint8, version_size uint) Status
+TEXT ·Sys_system_get_version(SB),NOSPLIT,$0-20
+ MOVD version+0(FP), R0
+ MOVD version_size+8(FP), R1
+ BL vdso_zx_system_get_version(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_system_get_physmem() uint64
+TEXT ·Sys_system_get_physmem(SB),NOSPLIT,$0-8
+ BL vdso_zx_system_get_physmem(SB)
+ MOVD R0, ret+0(FP)
+ RET
+
+// func sys_system_get_features(kind uint32, out *uint32) Status
+TEXT ·sys_system_get_features(SB),NOSPLIT,$0-20
+ MOVW kind+0(FP), R0
+ MOVD out+8(FP), R1
+ BL vdso_zx_system_get_features(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_cache_flush(addr unsafe.Pointer, size uint, options uint32) Status
+TEXT ·Sys_cache_flush(SB),NOSPLIT,$0-28
+ MOVD addr+0(FP), R0
+ MOVD size+8(FP), R1
+ MOVW options+16(FP), R2
+ BL vdso_zx_cache_flush(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func Sys_handle_close(handle Handle) Status
+TEXT ·Sys_handle_close(SB),NOSPLIT,$0-12
+ MOVW handle+0(FP), R0
+ BL vdso_zx_handle_close(SB)
+ MOVW R0, ret+8(FP)
+ RET
+
+// func Sys_handle_close_many(handles *Handle, num_handles uint) Status
+TEXT ·Sys_handle_close_many(SB),NOSPLIT,$0-20
+ MOVD handles+0(FP), R0
+ MOVD num_handles+8(FP), R1
+ BL vdso_zx_handle_close_many(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func sys_handle_duplicate(handle Handle, rights Rights, out *Handle) Status
+TEXT ·sys_handle_duplicate(SB),NOSPLIT,$0-20
+ MOVW handle+0(FP), R0
+ MOVW rights+4(FP), R1
+ MOVD out+8(FP), R2
+ BL vdso_zx_handle_duplicate(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_handle_replace(handle Handle, rights Rights, out *Handle) Status
+TEXT ·Sys_handle_replace(SB),NOSPLIT,$0-20
+ MOVW handle+0(FP), R0
+ MOVW rights+4(FP), R1
+ MOVD out+8(FP), R2
+ BL vdso_zx_handle_replace(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_object_wait_one(handle Handle, signals Signals, deadline Time, observed *Signals) Status
+TEXT ·Sys_object_wait_one(SB),NOSPLIT,$0-28
+ CALL runtime·entersyscall(SB)
+ MOVW handle+0(FP), R0
+ MOVW signals+4(FP), R1
+ MOVD deadline+8(FP), R2
+ MOVD observed+16(FP), R3
+ BL vdso_zx_object_wait_one(SB)
+ MOVW R0, ret+24(FP)
+ BL runtime·exitsyscall(SB)
+ RET
+
+// func sys_object_wait_many(items *WaitItem, count uint, deadline Time) Status
+TEXT ·sys_object_wait_many(SB),NOSPLIT,$0-28
+ CALL runtime·entersyscall(SB)
+ MOVD items+0(FP), R0
+ MOVD count+8(FP), R1
+ MOVD deadline+16(FP), R2
+ BL vdso_zx_object_wait_many(SB)
+ MOVW R0, ret+24(FP)
+ BL runtime·exitsyscall(SB)
+ RET
+
+// func Sys_object_wait_async(handle Handle, port Handle, key uint64, signals Signals, options uint32) Status
+TEXT ·Sys_object_wait_async(SB),NOSPLIT,$0-28
+ MOVW handle+0(FP), R0
+ MOVW port+4(FP), R1
+ MOVD key+8(FP), R2
+ MOVW signals+16(FP), R3
+ MOVW options+20(FP), R4
+ BL vdso_zx_object_wait_async(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func Sys_object_signal(handle Handle, clear_mask uint32, set_mask uint32) Status
+TEXT ·Sys_object_signal(SB),NOSPLIT,$0-20
+ MOVW handle+0(FP), R0
+ MOVW clear_mask+4(FP), R1
+ MOVW set_mask+8(FP), R2
+ BL vdso_zx_object_signal(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_object_signal_peer(handle Handle, clear_mask uint32, set_mask uint32) Status
+TEXT ·Sys_object_signal_peer(SB),NOSPLIT,$0-20
+ MOVW handle+0(FP), R0
+ MOVW clear_mask+4(FP), R1
+ MOVW set_mask+8(FP), R2
+ BL vdso_zx_object_signal_peer(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_object_get_property(handle Handle, property uint32, value unsafe.Pointer, value_size uint) Status
+TEXT ·Sys_object_get_property(SB),NOSPLIT,$0-28
+ MOVW handle+0(FP), R0
+ MOVW property+4(FP), R1
+ MOVD value+8(FP), R2
+ MOVD value_size+16(FP), R3
+ BL vdso_zx_object_get_property(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func Sys_object_set_property(handle Handle, property uint32, value unsafe.Pointer, value_size uint) Status
+TEXT ·Sys_object_set_property(SB),NOSPLIT,$0-28
+ MOVW handle+0(FP), R0
+ MOVW property+4(FP), R1
+ MOVD value+8(FP), R2
+ MOVD value_size+16(FP), R3
+ BL vdso_zx_object_set_property(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func Sys_object_set_cookie(handle Handle, scope Handle, cookie uint64) Status
+TEXT ·Sys_object_set_cookie(SB),NOSPLIT,$0-20
+ MOVW handle+0(FP), R0
+ MOVW scope+4(FP), R1
+ MOVD cookie+8(FP), R2
+ BL vdso_zx_object_set_cookie(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_object_get_cookie(handle Handle, scope Handle, cookie *uint64) Status
+TEXT ·Sys_object_get_cookie(SB),NOSPLIT,$0-20
+ MOVW handle+0(FP), R0
+ MOVW scope+4(FP), R1
+ MOVD cookie+8(FP), R2
+ BL vdso_zx_object_get_cookie(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_object_get_info(handle Handle, topic uint32, buffer unsafe.Pointer, buffer_size uint, actual_count *uint, avail_count *uint) Status
+TEXT ·Sys_object_get_info(SB),NOSPLIT,$0-44
+ MOVW handle+0(FP), R0
+ MOVW topic+4(FP), R1
+ MOVD buffer+8(FP), R2
+ MOVD buffer_size+16(FP), R3
+ MOVD actual_count+24(FP), R4
+ MOVD avail_count+32(FP), R5
+ BL vdso_zx_object_get_info(SB)
+ MOVW R0, ret+40(FP)
+ RET
+
+// func Sys_object_get_child(handle Handle, koid uint64, rights Rights, out *Handle) Status
+TEXT ·Sys_object_get_child(SB),NOSPLIT,$0-36
+ MOVW handle+0(FP), R0
+ MOVD koid+8(FP), R1
+ MOVW rights+16(FP), R2
+ MOVD out+24(FP), R3
+ BL vdso_zx_object_get_child(SB)
+ MOVW R0, ret+32(FP)
+ RET
+
+// func sys_object_set_profile(handle Handle, profile Handle, options uint32) Status
+TEXT ·sys_object_set_profile(SB),NOSPLIT,$0-20
+ MOVW handle+0(FP), R0
+ MOVW profile+4(FP), R1
+ MOVW options+8(FP), R2
+ BL vdso_zx_object_set_profile(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func sys_channel_create(options uint32, out0 *Handle, out1 *Handle) Status
+TEXT ·sys_channel_create(SB),NOSPLIT,$0-28
+ MOVW options+0(FP), R0
+ MOVD out0+8(FP), R1
+ MOVD out1+16(FP), R2
+ BL vdso_zx_channel_create(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func sys_channel_read(handle Handle, options uint32, bytes unsafe.Pointer, handles *Handle, num_bytes uint32, num_handles uint32, actual_bytes *uint32, actual_handles *uint32) Status
+TEXT ·sys_channel_read(SB),NOSPLIT,$0-52
+ MOVW handle+0(FP), R0
+ MOVW options+4(FP), R1
+ MOVD bytes+8(FP), R2
+ MOVD handles+16(FP), R3
+ MOVW num_bytes+24(FP), R4
+ MOVW num_handles+28(FP), R5
+ MOVD actual_bytes+32(FP), R6
+ MOVD actual_handles+40(FP), R7
+ BL vdso_zx_channel_read(SB)
+ MOVW R0, ret+48(FP)
+ RET
+
+// func sys_channel_read_etc(handle Handle, options uint32, bytes unsafe.Pointer, handles *int, num_bytes uint32, num_handles uint32, actual_bytes *uint32, actual_handles *uint32) Status
+TEXT ·sys_channel_read_etc(SB),NOSPLIT,$0-52
+ MOVW handle+0(FP), R0
+ MOVW options+4(FP), R1
+ MOVD bytes+8(FP), R2
+ MOVD handles+16(FP), R3
+ MOVW num_bytes+24(FP), R4
+ MOVW num_handles+28(FP), R5
+ MOVD actual_bytes+32(FP), R6
+ MOVD actual_handles+40(FP), R7
+ BL vdso_zx_channel_read_etc(SB)
+ MOVW R0, ret+48(FP)
+ RET
+
+// func sys_channel_write(handle Handle, options uint32, bytes unsafe.Pointer, num_bytes uint32, handles *Handle, num_handles uint32) Status
+TEXT ·sys_channel_write(SB),NOSPLIT,$0-44
+ MOVW handle+0(FP), R0
+ MOVW options+4(FP), R1
+ MOVD bytes+8(FP), R2
+ MOVW num_bytes+16(FP), R3
+ MOVD handles+24(FP), R4
+ MOVW num_handles+32(FP), R5
+ BL vdso_zx_channel_write(SB)
+ MOVW R0, ret+40(FP)
+ RET
+
+// func Sys_channel_call_noretry(handle Handle, options uint32, deadline Time, args *ChannelCallArgs, actual_bytes *uint32, actual_handles *uint32) Status
+TEXT ·Sys_channel_call_noretry(SB),NOSPLIT,$0-44
+ MOVW handle+0(FP), R0
+ MOVW options+4(FP), R1
+ MOVD deadline+8(FP), R2
+ MOVD args+16(FP), R3
+ MOVD actual_bytes+24(FP), R4
+ MOVD actual_handles+32(FP), R5
+ BL vdso_zx_channel_call_noretry(SB)
+ MOVW R0, ret+40(FP)
+ RET
+
+// func Sys_channel_call_finish(deadline Time, args *ChannelCallArgs, actual_bytes *uint32, actual_handles *uint32) Status
+TEXT ·Sys_channel_call_finish(SB),NOSPLIT,$0-36
+ MOVD deadline+0(FP), R0
+ MOVD args+8(FP), R1
+ MOVD actual_bytes+16(FP), R2
+ MOVD actual_handles+24(FP), R3
+ BL vdso_zx_channel_call_finish(SB)
+ MOVW R0, ret+32(FP)
+ RET
+
+// func Sys_channel_call(handle Handle, options uint32, deadline Time, args *ChannelCallArgs, actual_bytes *uint32, actual_handles *uint32) Status
+TEXT ·Sys_channel_call(SB),NOSPLIT,$0-44
+ MOVW handle+0(FP), R0
+ MOVW options+4(FP), R1
+ MOVD deadline+8(FP), R2
+ MOVD args+16(FP), R3
+ MOVD actual_bytes+24(FP), R4
+ MOVD actual_handles+32(FP), R5
+ BL vdso_zx_channel_call(SB)
+ MOVW R0, ret+40(FP)
+ RET
+
+// func sys_socket_create(options uint32, out0 *Handle, out1 *Handle) Status
+TEXT ·sys_socket_create(SB),NOSPLIT,$0-28
+ MOVW options+0(FP), R0
+ MOVD out0+8(FP), R1
+ MOVD out1+16(FP), R2
+ BL vdso_zx_socket_create(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func sys_socket_write(handle Handle, options uint32, buffer unsafe.Pointer, buffer_size uint, actual *uint) Status
+TEXT ·sys_socket_write(SB),NOSPLIT,$0-36
+ MOVW handle+0(FP), R0
+ MOVW options+4(FP), R1
+ MOVD buffer+8(FP), R2
+ MOVD buffer_size+16(FP), R3
+ MOVD actual+24(FP), R4
+ BL vdso_zx_socket_write(SB)
+ MOVW R0, ret+32(FP)
+ RET
+
+// func sys_socket_read(handle Handle, options uint32, buffer unsafe.Pointer, buffer_size uint, actual *uint) Status
+TEXT ·sys_socket_read(SB),NOSPLIT,$0-36
+ MOVW handle+0(FP), R0
+ MOVW options+4(FP), R1
+ MOVD buffer+8(FP), R2
+ MOVD buffer_size+16(FP), R3
+ MOVD actual+24(FP), R4
+ BL vdso_zx_socket_read(SB)
+ MOVW R0, ret+32(FP)
+ RET
+
+// func sys_socket_share(handle Handle, socket_to_share Handle) Status
+TEXT ·sys_socket_share(SB),NOSPLIT,$0-12
+ MOVW handle+0(FP), R0
+ MOVW socket_to_share+4(FP), R1
+ BL vdso_zx_socket_share(SB)
+ MOVW R0, ret+8(FP)
+ RET
+
+// func sys_socket_accept(handle Handle, out_socket *Handle) Status
+TEXT ·sys_socket_accept(SB),NOSPLIT,$0-20
+ MOVW handle+0(FP), R0
+ MOVD out_socket+8(FP), R1
+ BL vdso_zx_socket_accept(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_thread_exit()
+TEXT ·Sys_thread_exit(SB),NOSPLIT,$0-0
+ BL vdso_zx_thread_exit(SB)
+ RET
+
+// func Sys_thread_create(process Handle, name *uint8, name_size uint, options uint32, out *Handle) Status
+TEXT ·Sys_thread_create(SB),NOSPLIT,$0-44
+ MOVW process+0(FP), R0
+ MOVD name+8(FP), R1
+ MOVD name_size+16(FP), R2
+ MOVW options+24(FP), R3
+ MOVD out+32(FP), R4
+ BL vdso_zx_thread_create(SB)
+ MOVW R0, ret+40(FP)
+ RET
+
+// func Sys_thread_start(handle Handle, thread_entry Vaddr, stack Vaddr, arg1 uintptr, arg2 uintptr) Status
+TEXT ·Sys_thread_start(SB),NOSPLIT,$0-44
+ MOVW handle+0(FP), R0
+ MOVD thread_entry+8(FP), R1
+ MOVD stack+16(FP), R2
+ MOVD arg1+24(FP), R3
+ MOVD arg2+32(FP), R4
+ BL vdso_zx_thread_start(SB)
+ MOVW R0, ret+40(FP)
+ RET
+
+// func Sys_thread_read_state(handle Handle, kind uint32, buffer unsafe.Pointer, buffer_size uint) Status
+TEXT ·Sys_thread_read_state(SB),NOSPLIT,$0-28
+ MOVW handle+0(FP), R0
+ MOVW kind+4(FP), R1
+ MOVD buffer+8(FP), R2
+ MOVD buffer_size+16(FP), R3
+ BL vdso_zx_thread_read_state(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func Sys_thread_write_state(handle Handle, kind uint32, buffer unsafe.Pointer, buffer_size uint) Status
+TEXT ·Sys_thread_write_state(SB),NOSPLIT,$0-28
+ MOVW handle+0(FP), R0
+ MOVW kind+4(FP), R1
+ MOVD buffer+8(FP), R2
+ MOVD buffer_size+16(FP), R3
+ BL vdso_zx_thread_write_state(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func Sys_thread_set_priority(prio int32) Status
+TEXT ·Sys_thread_set_priority(SB),NOSPLIT,$0-12
+ MOVW prio+0(FP), R0
+ BL vdso_zx_thread_set_priority(SB)
+ MOVW R0, ret+8(FP)
+ RET
+
+// func Sys_process_exit(retcode int64)
+TEXT ·Sys_process_exit(SB),NOSPLIT,$0-8
+ MOVD retcode+0(FP), R0
+ BL vdso_zx_process_exit(SB)
+ RET
+
+// func Sys_process_create(job Handle, name *uint8, name_size uint, options uint32, proc_handle *Handle, vmar_handle *Handle) Status
+TEXT ·Sys_process_create(SB),NOSPLIT,$0-52
+ MOVW job+0(FP), R0
+ MOVD name+8(FP), R1
+ MOVD name_size+16(FP), R2
+ MOVW options+24(FP), R3
+ MOVD proc_handle+32(FP), R4
+ MOVD vmar_handle+40(FP), R5
+ BL vdso_zx_process_create(SB)
+ MOVW R0, ret+48(FP)
+ RET
+
+// func Sys_process_start(handle Handle, thread Handle, entry Vaddr, stack Vaddr, arg1 Handle, arg2 uintptr) Status
+TEXT ·Sys_process_start(SB),NOSPLIT,$0-44
+ MOVW handle+0(FP), R0
+ MOVW thread+4(FP), R1
+ MOVD entry+8(FP), R2
+ MOVD stack+16(FP), R3
+ MOVW arg1+24(FP), R4
+ MOVD arg2+32(FP), R5
+ BL vdso_zx_process_start(SB)
+ MOVW R0, ret+40(FP)
+ RET
+
+// func Sys_process_read_memory(proc Handle, vaddr Vaddr, buffer unsafe.Pointer, buffer_size uint, actual *uint) Status
+TEXT ·Sys_process_read_memory(SB),NOSPLIT,$0-44
+ MOVW proc+0(FP), R0
+ MOVD vaddr+8(FP), R1
+ MOVD buffer+16(FP), R2
+ MOVD buffer_size+24(FP), R3
+ MOVD actual+32(FP), R4
+ BL vdso_zx_process_read_memory(SB)
+ MOVW R0, ret+40(FP)
+ RET
+
+// func Sys_process_write_memory(proc Handle, vaddr Vaddr, buffer unsafe.Pointer, buffer_size uint, actual *uint) Status
+TEXT ·Sys_process_write_memory(SB),NOSPLIT,$0-44
+ MOVW proc+0(FP), R0
+ MOVD vaddr+8(FP), R1
+ MOVD buffer+16(FP), R2
+ MOVD buffer_size+24(FP), R3
+ MOVD actual+32(FP), R4
+ BL vdso_zx_process_write_memory(SB)
+ MOVW R0, ret+40(FP)
+ RET
+
+// func Sys_job_create(parent_job Handle, options uint32, out *Handle) Status
+TEXT ·Sys_job_create(SB),NOSPLIT,$0-20
+ MOVW parent_job+0(FP), R0
+ MOVW options+4(FP), R1
+ MOVD out+8(FP), R2
+ BL vdso_zx_job_create(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_job_set_policy(job Handle, options uint32, topic uint32, policy unsafe.Pointer, count uint32) Status
+TEXT ·Sys_job_set_policy(SB),NOSPLIT,$0-36
+ MOVW job+0(FP), R0
+ MOVW options+4(FP), R1
+ MOVW topic+8(FP), R2
+ MOVD policy+16(FP), R3
+ MOVW count+24(FP), R4
+ BL vdso_zx_job_set_policy(SB)
+ MOVW R0, ret+32(FP)
+ RET
+
+// func Sys_task_bind_exception_port(handle Handle, port Handle, key uint64, options uint32) Status
+TEXT ·Sys_task_bind_exception_port(SB),NOSPLIT,$0-28
+ MOVW handle+0(FP), R0
+ MOVW port+4(FP), R1
+ MOVD key+8(FP), R2
+ MOVW options+16(FP), R3
+ BL vdso_zx_task_bind_exception_port(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func Sys_task_resume(handle Handle, options uint32) Status
+TEXT ·Sys_task_resume(SB),NOSPLIT,$0-12
+ MOVW handle+0(FP), R0
+ MOVW options+4(FP), R1
+ BL vdso_zx_task_resume(SB)
+ MOVW R0, ret+8(FP)
+ RET
+
+// func Sys_task_suspend(handle Handle, token *Handle) Status
+TEXT ·Sys_task_suspend(SB),NOSPLIT,$0-20
+ MOVW handle+0(FP), R0
+ MOVD token+8(FP), R1
+ BL vdso_zx_task_suspend(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_task_suspend_token(handle Handle, token *Handle) Status
+TEXT ·Sys_task_suspend_token(SB),NOSPLIT,$0-20
+ MOVW handle+0(FP), R0
+ MOVD token+8(FP), R1
+ BL vdso_zx_task_suspend_token(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_task_resume_from_exception(handle Handle, port Handle, options uint32) Status
+TEXT ·Sys_task_resume_from_exception(SB),NOSPLIT,$0-20
+ MOVW handle+0(FP), R0
+ MOVW port+4(FP), R1
+ MOVW options+8(FP), R2
+ BL vdso_zx_task_resume_from_exception(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_task_kill(handle Handle) Status
+TEXT ·Sys_task_kill(SB),NOSPLIT,$0-12
+ MOVW handle+0(FP), R0
+ BL vdso_zx_task_kill(SB)
+ MOVW R0, ret+8(FP)
+ RET
+
+// func Sys_event_create(options uint32, out *Handle) Status
+TEXT ·Sys_event_create(SB),NOSPLIT,$0-20
+ MOVW options+0(FP), R0
+ MOVD out+8(FP), R1
+ BL vdso_zx_event_create(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_eventpair_create(options uint32, out0 *Handle, out1 *Handle) Status
+TEXT ·Sys_eventpair_create(SB),NOSPLIT,$0-28
+ MOVW options+0(FP), R0
+ MOVD out0+8(FP), R1
+ MOVD out1+16(FP), R2
+ BL vdso_zx_eventpair_create(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func Sys_futex_wait(value_ptr *int, current_value int32, deadline Time) Status
+TEXT ·Sys_futex_wait(SB),NOSPLIT,$0-28
+ MOVD value_ptr+0(FP), R0
+ MOVW current_value+8(FP), R1
+ MOVD deadline+16(FP), R2
+ BL vdso_zx_futex_wait(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func Sys_futex_wake(value_ptr *int, count uint32) Status
+TEXT ·Sys_futex_wake(SB),NOSPLIT,$0-20
+ MOVD value_ptr+0(FP), R0
+ MOVW count+8(FP), R1
+ BL vdso_zx_futex_wake(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_futex_requeue(wake_ptr *int, wake_count uint32, current_value int32, requeue_ptr *int, requeue_count uint32) Status
+TEXT ·Sys_futex_requeue(SB),NOSPLIT,$0-36
+ MOVD wake_ptr+0(FP), R0
+ MOVW wake_count+8(FP), R1
+ MOVW current_value+12(FP), R2
+ MOVD requeue_ptr+16(FP), R3
+ MOVW requeue_count+24(FP), R4
+ BL vdso_zx_futex_requeue(SB)
+ MOVW R0, ret+32(FP)
+ RET
+
+// func Sys_port_create(options uint32, out *Handle) Status
+TEXT ·Sys_port_create(SB),NOSPLIT,$0-20
+ MOVW options+0(FP), R0
+ MOVD out+8(FP), R1
+ BL vdso_zx_port_create(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_port_queue(handle Handle, packet *int) Status
+TEXT ·Sys_port_queue(SB),NOSPLIT,$0-20
+ MOVW handle+0(FP), R0
+ MOVD packet+8(FP), R1
+ BL vdso_zx_port_queue(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_port_wait(handle Handle, deadline Time, packet *int) Status
+TEXT ·Sys_port_wait(SB),NOSPLIT,$0-28
+ CALL runtime·entersyscall(SB)
+ MOVW handle+0(FP), R0
+ MOVD deadline+8(FP), R1
+ MOVD packet+16(FP), R2
+ BL vdso_zx_port_wait(SB)
+ MOVW R0, ret+24(FP)
+ BL runtime·exitsyscall(SB)
+ RET
+
+// func Sys_port_cancel(handle Handle, source Handle, key uint64) Status
+TEXT ·Sys_port_cancel(SB),NOSPLIT,$0-20
+ MOVW handle+0(FP), R0
+ MOVW source+4(FP), R1
+ MOVD key+8(FP), R2
+ BL vdso_zx_port_cancel(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_timer_create(options uint32, clock_id uint32, out *Handle) Status
+TEXT ·Sys_timer_create(SB),NOSPLIT,$0-20
+ MOVW options+0(FP), R0
+ MOVW clock_id+4(FP), R1
+ MOVD out+8(FP), R2
+ BL vdso_zx_timer_create(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_timer_set(handle Handle, deadline Time, slack Duration) Status
+TEXT ·Sys_timer_set(SB),NOSPLIT,$0-28
+ MOVW handle+0(FP), R0
+ MOVD deadline+8(FP), R1
+ MOVD slack+16(FP), R2
+ BL vdso_zx_timer_set(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func Sys_timer_cancel(handle Handle) Status
+TEXT ·Sys_timer_cancel(SB),NOSPLIT,$0-12
+ MOVW handle+0(FP), R0
+ BL vdso_zx_timer_cancel(SB)
+ MOVW R0, ret+8(FP)
+ RET
+
+// func Sys_vmo_create(size uint64, options uint32, out *Handle) Status
+TEXT ·Sys_vmo_create(SB),NOSPLIT,$0-28
+ MOVD size+0(FP), R0
+ MOVW options+8(FP), R1
+ MOVD out+16(FP), R2
+ BL vdso_zx_vmo_create(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func sys_vmo_read(handle Handle, buffer unsafe.Pointer, offset uint64, buffer_size uint) Status
+TEXT ·sys_vmo_read(SB),NOSPLIT,$0-36
+ MOVW handle+0(FP), R0
+ MOVD buffer+8(FP), R1
+ MOVD offset+16(FP), R2
+ MOVD buffer_size+24(FP), R3
+ BL vdso_zx_vmo_read(SB)
+ MOVW R0, ret+32(FP)
+ RET
+
+// func sys_vmo_write(handle Handle, buffer unsafe.Pointer, offset uint64, buffer_size uint) Status
+TEXT ·sys_vmo_write(SB),NOSPLIT,$0-36
+ MOVW handle+0(FP), R0
+ MOVD buffer+8(FP), R1
+ MOVD offset+16(FP), R2
+ MOVD buffer_size+24(FP), R3
+ BL vdso_zx_vmo_write(SB)
+ MOVW R0, ret+32(FP)
+ RET
+
+// func sys_vmo_get_size(handle Handle, size *uint64) Status
+TEXT ·sys_vmo_get_size(SB),NOSPLIT,$0-20
+ MOVW handle+0(FP), R0
+ MOVD size+8(FP), R1
+ BL vdso_zx_vmo_get_size(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func sys_vmo_set_size(handle Handle, size uint64) Status
+TEXT ·sys_vmo_set_size(SB),NOSPLIT,$0-20
+ MOVW handle+0(FP), R0
+ MOVD size+8(FP), R1
+ BL vdso_zx_vmo_set_size(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func sys_vmo_op_range(handle Handle, op uint32, offset uint64, size uint64, buffer unsafe.Pointer, buffer_size uint) Status
+TEXT ·sys_vmo_op_range(SB),NOSPLIT,$0-44
+ MOVW handle+0(FP), R0
+ MOVW op+4(FP), R1
+ MOVD offset+8(FP), R2
+ MOVD size+16(FP), R3
+ MOVD buffer+24(FP), R4
+ MOVD buffer_size+32(FP), R5
+ BL vdso_zx_vmo_op_range(SB)
+ MOVW R0, ret+40(FP)
+ RET
+
+// func Sys_vmo_clone(handle Handle, options uint32, offset uint64, size uint64, out *Handle) Status
+TEXT ·Sys_vmo_clone(SB),NOSPLIT,$0-36
+ MOVW handle+0(FP), R0
+ MOVW options+4(FP), R1
+ MOVD offset+8(FP), R2
+ MOVD size+16(FP), R3
+ MOVD out+24(FP), R4
+ BL vdso_zx_vmo_clone(SB)
+ MOVW R0, ret+32(FP)
+ RET
+
+// func Sys_vmo_set_cache_policy(handle Handle, cache_policy uint32) Status
+TEXT ·Sys_vmo_set_cache_policy(SB),NOSPLIT,$0-12
+ MOVW handle+0(FP), R0
+ MOVW cache_policy+4(FP), R1
+ BL vdso_zx_vmo_set_cache_policy(SB)
+ MOVW R0, ret+8(FP)
+ RET
+
+// func sys_vmar_allocate_old(parent_vmar Handle, offset uint64, size uint64, map_flags uint32, child_vmar *Handle, child_addr *Vaddr) Status
+TEXT ·sys_vmar_allocate_old(SB),NOSPLIT,$0-52
+ MOVW parent_vmar+0(FP), R0
+ MOVD offset+8(FP), R1
+ MOVD size+16(FP), R2
+ MOVW map_flags+24(FP), R3
+ MOVD child_vmar+32(FP), R4
+ MOVD child_addr+40(FP), R5
+ BL vdso_zx_vmar_allocate_old(SB)
+ MOVW R0, ret+48(FP)
+ RET
+
+// func sys_vmar_map_old(handle Handle, vmar_offset uint64, vmo Handle, vmo_offset uint64, len uint64, map_flags uint32, mapped_addr *Vaddr) Status
+TEXT ·sys_vmar_map_old(SB),NOSPLIT,$0-60
+ MOVW handle+0(FP), R0
+ MOVD vmar_offset+8(FP), R1
+ MOVW vmo+16(FP), R2
+ MOVD vmo_offset+24(FP), R3
+ MOVD len+32(FP), R4
+ MOVW map_flags+40(FP), R5
+ MOVD mapped_addr+48(FP), R6
+ BL vdso_zx_vmar_map_old(SB)
+ MOVW R0, ret+56(FP)
+ RET
+
+// func sys_vmar_protect_old(handle Handle, addr Vaddr, len uint64, prot_flags uint32) Status
+TEXT ·sys_vmar_protect_old(SB),NOSPLIT,$0-36
+ MOVW handle+0(FP), R0
+ MOVD addr+8(FP), R1
+ MOVD len+16(FP), R2
+ MOVW prot_flags+24(FP), R3
+ BL vdso_zx_vmar_protect_old(SB)
+ MOVW R0, ret+32(FP)
+ RET
+
+// func sys_vmar_allocate(parent_vmar Handle, offset uint64, size uint64, map_flags uint32, child_vmar *Handle, child_addr *Vaddr) Status
+TEXT ·sys_vmar_allocate(SB),NOSPLIT,$0-52
+ MOVW parent_vmar+0(FP), R0
+ MOVD offset+8(FP), R1
+ MOVD size+16(FP), R2
+ MOVW map_flags+24(FP), R3
+ MOVD child_vmar+32(FP), R4
+ MOVD child_addr+40(FP), R5
+ BL vdso_zx_vmar_allocate(SB)
+ MOVW R0, ret+48(FP)
+ RET
+
+// func sys_vmar_destroy(handle Handle) Status
+TEXT ·sys_vmar_destroy(SB),NOSPLIT,$0-12
+ MOVW handle+0(FP), R0
+ BL vdso_zx_vmar_destroy(SB)
+ MOVW R0, ret+8(FP)
+ RET
+
+// func Sys_vmar_map(handle Handle, vmar_offset uint64, vmo Handle, vmo_offset uint64, len uint64, map_flags uint32, mapped_addr *Vaddr) Status
+TEXT ·Sys_vmar_map(SB),NOSPLIT,$0-60
+ MOVW handle+0(FP), R0
+ MOVD vmar_offset+8(FP), R1
+ MOVW vmo+16(FP), R2
+ MOVD vmo_offset+24(FP), R3
+ MOVD len+32(FP), R4
+ MOVW map_flags+40(FP), R5
+ MOVD mapped_addr+48(FP), R6
+ BL vdso_zx_vmar_map(SB)
+ MOVW R0, ret+56(FP)
+ RET
+
+// func Sys_vmar_unmap(handle Handle, addr Vaddr, len uint64) Status
+TEXT ·Sys_vmar_unmap(SB),NOSPLIT,$0-28
+ MOVW handle+0(FP), R0
+ MOVD addr+8(FP), R1
+ MOVD len+16(FP), R2
+ BL vdso_zx_vmar_unmap(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func Sys_vmar_protect(handle Handle, addr Vaddr, len uint64, prot_flags uint32) Status
+TEXT ·Sys_vmar_protect(SB),NOSPLIT,$0-36
+ MOVW handle+0(FP), R0
+ MOVD addr+8(FP), R1
+ MOVD len+16(FP), R2
+ MOVW prot_flags+24(FP), R3
+ BL vdso_zx_vmar_protect(SB)
+ MOVW R0, ret+32(FP)
+ RET
+
+// func Sys_cprng_draw_once(buffer unsafe.Pointer, buffer_size uint) Status
+TEXT ·Sys_cprng_draw_once(SB),NOSPLIT,$0-20
+ MOVD buffer+0(FP), R0
+ MOVD buffer_size+8(FP), R1
+ BL vdso_zx_cprng_draw_once(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_cprng_draw(buffer unsafe.Pointer, buffer_size uint)
+TEXT ·Sys_cprng_draw(SB),NOSPLIT,$0-16
+ MOVD buffer+0(FP), R0
+ MOVD buffer_size+8(FP), R1
+ BL vdso_zx_cprng_draw(SB)
+ RET
+
+// func Sys_cprng_draw_new(buffer unsafe.Pointer, data_size uint) Status
+TEXT ·Sys_cprng_draw_new(SB),NOSPLIT,$0-20
+ MOVD buffer+0(FP), R0
+ MOVD data_size+8(FP), R1
+ BL vdso_zx_cprng_draw_new(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_cprng_add_entropy(buffer unsafe.Pointer, len uint) Status
+TEXT ·Sys_cprng_add_entropy(SB),NOSPLIT,$0-20
+ MOVD buffer+0(FP), R0
+ MOVD len+8(FP), R1
+ BL vdso_zx_cprng_add_entropy(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_fifo_create(elem_count uint, elem_size uint, options uint32, out0 *Handle, out1 *Handle) Status
+TEXT ·Sys_fifo_create(SB),NOSPLIT,$0-44
+ MOVD elem_count+0(FP), R0
+ MOVD elem_size+8(FP), R1
+ MOVW options+16(FP), R2
+ MOVD out0+24(FP), R3
+ MOVD out1+32(FP), R4
+ BL vdso_zx_fifo_create(SB)
+ MOVW R0, ret+40(FP)
+ RET
+
+// func Sys_fifo_read(handle Handle, elem_size uint, data unsafe.Pointer, count uint, actual_count *uint) Status
+TEXT ·Sys_fifo_read(SB),NOSPLIT,$0-44
+ MOVW handle+0(FP), R0
+ MOVD elem_size+8(FP), R1
+ MOVD data+16(FP), R2
+ MOVD count+24(FP), R3
+ MOVD actual_count+32(FP), R4
+ BL vdso_zx_fifo_read(SB)
+ MOVW R0, ret+40(FP)
+ RET
+
+// func Sys_fifo_write(handle Handle, elem_size uint, data unsafe.Pointer, count uint, actual_count *uint) Status
+TEXT ·Sys_fifo_write(SB),NOSPLIT,$0-44
+ MOVW handle+0(FP), R0
+ MOVD elem_size+8(FP), R1
+ MOVD data+16(FP), R2
+ MOVD count+24(FP), R3
+ MOVD actual_count+32(FP), R4
+ BL vdso_zx_fifo_write(SB)
+ MOVW R0, ret+40(FP)
+ RET
+
+// func Sys_profile_create(resource Handle, profile *int, out *Handle) Status
+TEXT ·Sys_profile_create(SB),NOSPLIT,$0-28
+ MOVW resource+0(FP), R0
+ MOVD profile+8(FP), R1
+ MOVD out+16(FP), R2
+ BL vdso_zx_profile_create(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func Sys_vmar_unmap_handle_close_thread_exit(vmar_handle Handle, addr Vaddr, size uint, handle Handle) Status
+TEXT ·Sys_vmar_unmap_handle_close_thread_exit(SB),NOSPLIT,$0-36
+ MOVW vmar_handle+0(FP), R0
+ MOVD addr+8(FP), R1
+ MOVD size+16(FP), R2
+ MOVW handle+24(FP), R3
+ BL vdso_zx_vmar_unmap_handle_close_thread_exit(SB)
+ MOVW R0, ret+32(FP)
+ RET
+
+// func Sys_futex_wake_handle_close_thread_exit(value_ptr *int, count uint32, new_value int32, handle Handle)
+TEXT ·Sys_futex_wake_handle_close_thread_exit(SB),NOSPLIT,$0-24
+ MOVD value_ptr+0(FP), R0
+ MOVW count+8(FP), R1
+ MOVW new_value+12(FP), R2
+ MOVW handle+16(FP), R3
+ BL vdso_zx_futex_wake_handle_close_thread_exit(SB)
+ RET
+
+// func Sys_log_write(handle Handle, len uint32, buffer unsafe.Pointer, options uint32) Status
+TEXT ·Sys_log_write(SB),NOSPLIT,$0-28
+ MOVW handle+0(FP), R0
+ MOVW len+4(FP), R1
+ MOVD buffer+8(FP), R2
+ MOVW options+16(FP), R3
+ BL vdso_zx_log_write(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func Sys_log_read(handle Handle, len uint32, buffer unsafe.Pointer, options uint32) Status
+TEXT ·Sys_log_read(SB),NOSPLIT,$0-28
+ MOVW handle+0(FP), R0
+ MOVW len+4(FP), R1
+ MOVD buffer+8(FP), R2
+ MOVW options+16(FP), R3
+ BL vdso_zx_log_read(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func Sys_debuglog_create(resource Handle, options uint32, out *Handle) Status
+TEXT ·Sys_debuglog_create(SB),NOSPLIT,$0-20
+ MOVW resource+0(FP), R0
+ MOVW options+4(FP), R1
+ MOVD out+8(FP), R2
+ BL vdso_zx_debuglog_create(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_debuglog_write(handle Handle, options uint32, buffer unsafe.Pointer, buffer_size uint) Status
+TEXT ·Sys_debuglog_write(SB),NOSPLIT,$0-28
+ MOVW handle+0(FP), R0
+ MOVW options+4(FP), R1
+ MOVD buffer+8(FP), R2
+ MOVD buffer_size+16(FP), R3
+ BL vdso_zx_debuglog_write(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func Sys_debuglog_read(handle Handle, options uint32, buffer unsafe.Pointer, buffer_size uint) Status
+TEXT ·Sys_debuglog_read(SB),NOSPLIT,$0-28
+ MOVW handle+0(FP), R0
+ MOVW options+4(FP), R1
+ MOVD buffer+8(FP), R2
+ MOVD buffer_size+16(FP), R3
+ BL vdso_zx_debuglog_read(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func Sys_ktrace_read(handle Handle, data unsafe.Pointer, offset uint32, data_size uint, actual *uint) Status
+TEXT ·Sys_ktrace_read(SB),NOSPLIT,$0-44
+ MOVW handle+0(FP), R0
+ MOVD data+8(FP), R1
+ MOVW offset+16(FP), R2
+ MOVD data_size+24(FP), R3
+ MOVD actual+32(FP), R4
+ BL vdso_zx_ktrace_read(SB)
+ MOVW R0, ret+40(FP)
+ RET
+
+// func Sys_ktrace_control(handle Handle, action uint32, options uint32, ptr unsafe.Pointer) Status
+TEXT ·Sys_ktrace_control(SB),NOSPLIT,$0-28
+ MOVW handle+0(FP), R0
+ MOVW action+4(FP), R1
+ MOVW options+8(FP), R2
+ MOVD ptr+16(FP), R3
+ BL vdso_zx_ktrace_control(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func Sys_ktrace_write(handle Handle, id uint32, arg0 uint32, arg1 uint32) Status
+TEXT ·Sys_ktrace_write(SB),NOSPLIT,$0-20
+ MOVW handle+0(FP), R0
+ MOVW id+4(FP), R1
+ MOVW arg0+8(FP), R2
+ MOVW arg1+12(FP), R3
+ BL vdso_zx_ktrace_write(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_mtrace_control(handle Handle, kind uint32, action uint32, options uint32, ptr unsafe.Pointer, ptr_size uint) Status
+TEXT ·Sys_mtrace_control(SB),NOSPLIT,$0-36
+ MOVW handle+0(FP), R0
+ MOVW kind+4(FP), R1
+ MOVW action+8(FP), R2
+ MOVW options+12(FP), R3
+ MOVD ptr+16(FP), R4
+ MOVD ptr_size+24(FP), R5
+ BL vdso_zx_mtrace_control(SB)
+ MOVW R0, ret+32(FP)
+ RET
+
+// func Sys_debug_read(handle Handle, buffer *uint8, buffer_size *uint) Status
+TEXT ·Sys_debug_read(SB),NOSPLIT,$0-28
+ MOVW handle+0(FP), R0
+ MOVD buffer+8(FP), R1
+ MOVD buffer_size+16(FP), R2
+ BL vdso_zx_debug_read(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func Sys_debug_write(buffer *uint8, buffer_size uint) Status
+TEXT ·Sys_debug_write(SB),NOSPLIT,$0-20
+ MOVD buffer+0(FP), R0
+ MOVD buffer_size+8(FP), R1
+ BL vdso_zx_debug_write(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_debug_send_command(resource Handle, buffer *uint8, buffer_size uint) Status
+TEXT ·Sys_debug_send_command(SB),NOSPLIT,$0-28
+ MOVW resource+0(FP), R0
+ MOVD buffer+8(FP), R1
+ MOVD buffer_size+16(FP), R2
+ BL vdso_zx_debug_send_command(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func Sys_interrupt_create(src_obj Handle, src_num uint32, options uint32, out *Handle) Status
+TEXT ·Sys_interrupt_create(SB),NOSPLIT,$0-28
+ MOVW src_obj+0(FP), R0
+ MOVW src_num+4(FP), R1
+ MOVW options+8(FP), R2
+ MOVD out+16(FP), R3
+ BL vdso_zx_interrupt_create(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func Sys_interrupt_bind(handle Handle, port Handle, key uint64, options uint32) Status
+TEXT ·Sys_interrupt_bind(SB),NOSPLIT,$0-28
+ MOVW handle+0(FP), R0
+ MOVW port+4(FP), R1
+ MOVD key+8(FP), R2
+ MOVW options+16(FP), R3
+ BL vdso_zx_interrupt_bind(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func Sys_interrupt_wait(handle Handle, out_timestamp *Time) Status
+TEXT ·Sys_interrupt_wait(SB),NOSPLIT,$0-20
+ MOVW handle+0(FP), R0
+ MOVD out_timestamp+8(FP), R1
+ BL vdso_zx_interrupt_wait(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_interrupt_destroy(handle Handle) Status
+TEXT ·Sys_interrupt_destroy(SB),NOSPLIT,$0-12
+ MOVW handle+0(FP), R0
+ BL vdso_zx_interrupt_destroy(SB)
+ MOVW R0, ret+8(FP)
+ RET
+
+// func Sys_interrupt_ack(handle Handle) Status
+TEXT ·Sys_interrupt_ack(SB),NOSPLIT,$0-12
+ MOVW handle+0(FP), R0
+ BL vdso_zx_interrupt_ack(SB)
+ MOVW R0, ret+8(FP)
+ RET
+
+// func Sys_interrupt_trigger(handle Handle, options uint32, timestamp Time) Status
+TEXT ·Sys_interrupt_trigger(SB),NOSPLIT,$0-20
+ MOVW handle+0(FP), R0
+ MOVW options+4(FP), R1
+ MOVD timestamp+8(FP), R2
+ BL vdso_zx_interrupt_trigger(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_ioports_request(resource Handle, io_addr uint16, len uint32) Status
+TEXT ·Sys_ioports_request(SB),NOSPLIT,$0-20
+ MOVW resource+0(FP), R0
+ MOVD io_addr+4(FP), R1
+ MOVW len+8(FP), R2
+ BL vdso_zx_ioports_request(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_vmo_create_contiguous(bti Handle, size uint, alignment_log2 uint32, out *Handle) Status
+TEXT ·Sys_vmo_create_contiguous(SB),NOSPLIT,$0-36
+ MOVW bti+0(FP), R0
+ MOVD size+8(FP), R1
+ MOVW alignment_log2+16(FP), R2
+ MOVD out+24(FP), R3
+ BL vdso_zx_vmo_create_contiguous(SB)
+ MOVW R0, ret+32(FP)
+ RET
+
+// func Sys_vmo_create_physical(resource Handle, paddr Paddr, size uint, out *Handle) Status
+TEXT ·Sys_vmo_create_physical(SB),NOSPLIT,$0-36
+ MOVW resource+0(FP), R0
+ MOVD paddr+8(FP), R1
+ MOVD size+16(FP), R2
+ MOVD out+24(FP), R3
+ BL vdso_zx_vmo_create_physical(SB)
+ MOVW R0, ret+32(FP)
+ RET
+
+// func Sys_iommu_create(resource Handle, typ uint32, desc unsafe.Pointer, desc_size uint, out *Handle) Status
+TEXT ·Sys_iommu_create(SB),NOSPLIT,$0-36
+ MOVW resource+0(FP), R0
+ MOVW typ+4(FP), R1
+ MOVD desc+8(FP), R2
+ MOVD desc_size+16(FP), R3
+ MOVD out+24(FP), R4
+ BL vdso_zx_iommu_create(SB)
+ MOVW R0, ret+32(FP)
+ RET
+
+// func Sys_bti_create(iommu Handle, options uint32, bti_id uint64, out *Handle) Status
+TEXT ·Sys_bti_create(SB),NOSPLIT,$0-28
+ MOVW iommu+0(FP), R0
+ MOVW options+4(FP), R1
+ MOVD bti_id+8(FP), R2
+ MOVD out+16(FP), R3
+ BL vdso_zx_bti_create(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func Sys_bti_pin(handle Handle, options uint32, vmo Handle, offset uint64, size uint64, addrs *Paddr, addrs_count uint, out *Handle) Status
+TEXT ·Sys_bti_pin(SB),NOSPLIT,$0-60
+ MOVW handle+0(FP), R0
+ MOVW options+4(FP), R1
+ MOVW vmo+8(FP), R2
+ MOVD offset+16(FP), R3
+ MOVD size+24(FP), R4
+ MOVD addrs+32(FP), R5
+ MOVD addrs_count+40(FP), R6
+ MOVD out+48(FP), R7
+ BL vdso_zx_bti_pin(SB)
+ MOVW R0, ret+56(FP)
+ RET
+
+// func Sys_bti_release_quarantine(handle Handle) Status
+TEXT ·Sys_bti_release_quarantine(SB),NOSPLIT,$0-12
+ MOVW handle+0(FP), R0
+ BL vdso_zx_bti_release_quarantine(SB)
+ MOVW R0, ret+8(FP)
+ RET
+
+// func Sys_pmt_unpin(handle Handle) Status
+TEXT ·Sys_pmt_unpin(SB),NOSPLIT,$0-12
+ MOVW handle+0(FP), R0
+ BL vdso_zx_pmt_unpin(SB)
+ MOVW R0, ret+8(FP)
+ RET
+
+// func Sys_framebuffer_get_info(resource Handle, format *uint32, width *uint32, height *uint32, stride *uint32) Status
+TEXT ·Sys_framebuffer_get_info(SB),NOSPLIT,$0-44
+ MOVW resource+0(FP), R0
+ MOVD format+8(FP), R1
+ MOVD width+16(FP), R2
+ MOVD height+24(FP), R3
+ MOVD stride+32(FP), R4
+ BL vdso_zx_framebuffer_get_info(SB)
+ MOVW R0, ret+40(FP)
+ RET
+
+// func Sys_framebuffer_set_range(resource Handle, vmo Handle, len uint32, format uint32, width uint32, height uint32, stride uint32) Status
+TEXT ·Sys_framebuffer_set_range(SB),NOSPLIT,$0-36
+ MOVW resource+0(FP), R0
+ MOVW vmo+4(FP), R1
+ MOVW len+8(FP), R2
+ MOVW format+12(FP), R3
+ MOVW width+16(FP), R4
+ MOVW height+20(FP), R5
+ MOVW stride+24(FP), R6
+ BL vdso_zx_framebuffer_set_range(SB)
+ MOVW R0, ret+32(FP)
+ RET
+
+// func Sys_pc_firmware_tables(handle Handle, acpi_rsdp *Paddr, smbios *Paddr) Status
+TEXT ·Sys_pc_firmware_tables(SB),NOSPLIT,$0-28
+ MOVW handle+0(FP), R0
+ MOVD acpi_rsdp+8(FP), R1
+ MOVD smbios+16(FP), R2
+ BL vdso_zx_pc_firmware_tables(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func Sys_smc_call(handle Handle, parameters *SMCParameters, out_smc_result *SMCResult) Status
+TEXT ·Sys_smc_call(SB),NOSPLIT,$0-28
+ MOVW handle+0(FP), R0
+ MOVD parameters+8(FP), R1
+ MOVD out_smc_result+16(FP), R2
+ BL vdso_zx_smc_call(SB)
+ MOVW R0, ret+24(FP)
+ RET
+
+// func Sys_resource_create(parent_rsrc Handle, options uint32, base uint64, size uint, name *uint8, name_size uint, resource_out *Handle) Status
+TEXT ·Sys_resource_create(SB),NOSPLIT,$0-52
+ MOVW parent_rsrc+0(FP), R0
+ MOVW options+4(FP), R1
+ MOVD base+8(FP), R2
+ MOVD size+16(FP), R3
+ MOVD name+24(FP), R4
+ MOVD name_size+32(FP), R5
+ MOVD resource_out+40(FP), R6
+ BL vdso_zx_resource_create(SB)
+ MOVW R0, ret+48(FP)
+ RET
+
+// func Sys_system_mexec(resource Handle, kernel Handle, bootimage Handle) Status
+TEXT ·Sys_system_mexec(SB),NOSPLIT,$0-20
+ MOVW resource+0(FP), R0
+ MOVW kernel+4(FP), R1
+ MOVW bootimage+8(FP), R2
+ BL vdso_zx_system_mexec(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
+// func Sys_system_powerctl(resource Handle, cmd uint32, arg *int) Status
+TEXT ·Sys_system_powerctl(SB),NOSPLIT,$0-20
+ MOVW resource+0(FP), R0
+ MOVW cmd+4(FP), R1
+ MOVD arg+8(FP), R2
+ BL vdso_zx_system_powerctl(SB)
+ MOVW R0, ret+16(FP)
+ RET
+
diff --git a/src/syscall/zx/types.go b/src/syscall/zx/types.go
new file mode 100644
index 0000000..d6c3870
--- /dev/null
+++ b/src/syscall/zx/types.go
@@ -0,0 +1,439 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package zx
+
+import "unsafe"
+
+type Status int32 // zx_status_t
+type Handle uint32 // zx_handle_t
+type Clock uint32 // zx_clock_t,
+type Time int64 // zx_time_t, nanoseconds
+type Duration int64 // zx_duration_t, nanoseconds
+type Signals uint32 // zx_signals_t
+type Rights uint32 // zx_rights_t
+type Paddr uintptr // zx_paddr_t
+type Vaddr uintptr // zx_vaddr_t
+
+type WaitItem struct {
+ Handle Handle
+ WaitFor Signals
+ Pending Signals
+} // zx_wait_item_t
+
+const HandleInvalid = Handle(0)
+
+// deprecated name
+const HANDLE_INVALID = Handle(0)
+
+const HandleSize = uint64(unsafe.Sizeof(Handle(0)))
+
+const ZX_MAX_NAME_LEN = 32
+
+const (
+ ZX_RREC_DELETED = 0
+ ZX_RREC_SELF = 1
+ ZX_RREC_DATA = 2
+ ZX_RREC_IRQ = 3
+ ZX_RREC_MMIO = 4
+ ZX_RREC_IOPORT = 5
+)
+
+const (
+ ZX_RACT_ENABLE = 1
+ ZX_RACT_DISABLE = 2
+)
+
+const (
+ ZX_RREC_SELF_GENERIC = 0
+ ZX_RREC_SELF_ROOT = 1
+)
+
+type RrecSelf struct {
+ Type uint16 // ZX_RREC_SELF
+ Subtype uint16
+ Options uint32
+ Koid uint64
+ RecordCount uint32
+ ChildCount uint32
+ _ [2]uint32
+ Name [ZX_MAX_NAME_LEN]uint8
+} // zx_rrec_self_t
+
+type RrecMMIO struct {
+ Type uint16 // ZX_RREC_MMIO
+ Subtype uint16
+ Options uint32
+ PhysBase uint64
+ PhysSize uint64
+ _ [10]uint32
+} // zx_rrec_mmio_t
+
+type RrecIRQ struct {
+ Type uint16 // ZX_RREC_IRQ
+ Subtype uint16
+ Options uint32
+ IRQBase uint32
+ IRQCount uint32
+ _ [12]uint32
+} // zx_rrec_irq_t
+
+type RrecIOPort struct {
+ Type uint16 // ZX_RREC_IOPORT
+ Subtype uint16
+ Options uint32
+ PortBase uint32
+ PortCount uint32
+ _ [12]uint32
+} // zx_rrec_ioport_t
+
+type RrecData struct {
+ Type uint16
+ Subtype uint16
+ Options uint32 // low 4 bits are count
+ Data [56]uint8
+} // zx_rrec_data_t
+
+type Rrec struct {
+ typ uint16
+ _ [62]uint8
+} // zx_rrec_t
+
+func (r *Rrec) Box() RrecValue {
+ switch r.typ {
+ case ZX_RREC_DELETED:
+ return nil
+ case ZX_RREC_SELF:
+ return (*RrecSelf)(unsafe.Pointer(r))
+ case ZX_RREC_DATA:
+ return (*RrecData)(unsafe.Pointer(r))
+ case ZX_RREC_IRQ:
+ return (*RrecIRQ)(unsafe.Pointer(r))
+ case ZX_RREC_MMIO:
+ return (*RrecMMIO)(unsafe.Pointer(r))
+ case ZX_RREC_IOPORT:
+ return (*RrecIOPort)(unsafe.Pointer(r))
+ default:
+ return nil
+ }
+}
+
+type RrecValue interface {
+ rrec()
+}
+
+func (*RrecSelf) rrec() {}
+func (*RrecData) rrec() {}
+func (*RrecIRQ) rrec() {}
+func (*RrecMMIO) rrec() {}
+func (*RrecIOPort) rrec() {}
+
+type ChannelCallArgs struct {
+ WriteBytes uintptr
+ WriteHandles *Handle
+ ReadBytes uintptr
+ ReadHandles *Handle
+ WriteNumBytes uint32
+ WriteNumHandles uint32
+ ReadNumBytes uint32
+ ReadNumHandles uint32
+}
+
+type FIFOState struct {
+ head, tail uint64
+}
+
+type SMCParameters struct {
+ funcID uint32
+ arg1, arg2, arg3, arg4, arg5, arg6 uint64
+ clientId, secureOSID uint16
+}
+
+type SMCResult struct {
+ arg0, arg1, arg2, arg3 uint64
+}
+
+// Status codes. See zircon/system/public/zircon/errors.h
+const (
+ ErrOk Status = -iota
+ ErrInternal
+ ErrNotSupported
+ ErrNoResources
+ ErrNoMemory
+ ErrCallFailed
+ ErrInterruptedRetry
+ _ // -7
+ _ // -8
+ _ // -9
+ ErrInvalidArgs
+ ErrBadHandle
+ ErrWrongType
+ ErrBadSyscall
+ ErrOutOfRange
+ ErrBufferTooSmall
+ _ // -16
+ _ // -17
+ _ // -18
+ _ // -19
+ ErrBadState
+ ErrTimedOut
+ ErrShouldWait
+ ErrCanceled
+ ErrPeerClosed
+ ErrNotFound
+ ErrAlreadyExists
+ ErrAlreadyBound
+ ErrUnavailable
+ _ // -29
+ ErrAccessDenied
+ _ // -31
+ _ // -32
+ _ // -33
+ _ // -34
+ _ // -35
+ _ // -36
+ _ // -37
+ _ // -38
+ _ // -39
+ ErrIO
+ ErrIORefused
+ ErrIODataIntegrity
+ ErrIODataLoss
+ _ // -44
+ _ // -45
+ _ // -46
+ _ // -47
+ _ // -48
+ _ // -49
+ ErrBadPath
+ ErrNotDir
+ ErrNotFile
+ ErrFileBig
+ ErrNoSpace
+ ErrNotEmpty
+ _ // -56
+ _ // -57
+ _ // -58
+ _ // -59
+ ErrStop
+ ErrNext
+ _ // -62
+ _ // -63
+ _ // -64
+ _ // -65
+ _ // -66
+ _ // -67
+ _ // -68
+ _ // -69
+ ErrProtocolNotSupported
+ ErrAddressUnreachable
+ ErrAddressInUse
+ ErrNotConnected
+ ErrConnectionRefused
+ ErrConnectionReset
+ ErrConnectionAborted
+
+ // deprecated
+ ErrHandleClosed = ErrCanceled
+ ErrRemoteClosed = ErrPeerClosed
+)
+
+const (
+ SignalObject0 = (1 << iota)
+ SignalObject1
+ SignalObject2
+ SignalObject3
+ SignalObject4
+ SignalObject5
+ SignalObject6
+ SignalObject7
+ SignalObject8
+ SignalObject9
+ SignalObject10
+ SignalObject11
+ SignalObject12
+ SignalObject13
+ SignalObject14
+ SignalObject15
+ SignalObject16
+ SignalObject17
+ SignalObject18
+ SignalObject19
+ SignalObject20
+ SignalObject21
+ SignalObject22
+ SignalObject23
+
+ SignalUser0
+ SignalUser1
+ SignalUser2
+ SignalUser3
+ SignalUser4
+ SignalUser5
+ SignalUser6
+ SignalUser7
+
+ // Aliases
+ SignalHandleClosed = SignalObject23
+
+ // Event
+ SignalEventSignaled = SignalObject3
+ SignalEventMask = SignalUserAll | SignalEventSignaled
+
+ // EventPair
+ SignalEpairSignaled = SignalObject3
+ SignalEpairPeerClosed = SignalObject2
+
+ // Channel
+ SignalChannelReadable = SignalObject0
+ SignalChannelWritable = SignalObject1
+ SignalChannelPeerClosed = SignalObject2
+
+ // Socket
+ SignalSocketReadable = SignalObject0
+ SignalSocketWritable = SignalObject1
+ SignalSocketPeerClosed = SignalObject2
+ SignalSocketReadDisabled = SignalObject4
+ SignalSocketWriteDisabled = SignalObject5
+ SignalSocketControlReadable = SignalObject6
+ SignalSocketControlWriteable = SignalObject7
+ SignalSocketAccept = SignalObject8
+ SignalSocketShare = SignalObject9
+
+ // Port
+ SignalPortReadable = SignalObject0
+ SignalPortPeerClosed = SignalObject2
+ SignalPortSignaled = SignalObject3
+
+ // Resource
+ SignalResourceReadable = SignalObject0
+ SignalResourceWritable = SignalObject1
+ SignalResourceChildAdded = SignalObject2
+
+ // Fifo
+ SignalFIFOReadable = SignalObject0
+ SignalFIFOWritable = SignalObject1
+ SignalFIFOPeerClosed = SignalObject2
+ SignalFIFOSignalMask = SignalFIFOReadable | SignalFIFOWritable | SignalFIFOPeerClosed
+
+ // Task signals (process, thread, job)
+ SignalTaskTerminated = SignalObject3
+ SignalTaskSignalMask = SignalObject3
+
+ // Job
+ SignalJobSignaled = SignalObject3
+
+ // Process
+ SignalProccessSignaled = SignalObject3
+
+ // Thread
+ SignalThreadSignaled = SignalObject3
+
+ SignalObjectAll = (0xfffff)
+ SignalUserAll = Signals(15 << 4)
+ SignalNone = Signals(0)
+)
+
+const (
+ RightDuplicate = Rights(1 << iota)
+ RightTransfer
+ RightRead
+ RightWrite
+ RightExecute
+ RightDebug
+ RightSameRights = Rights(1 << 31)
+ RightNone = Rights(0)
+)
+
+// Topics for object_get_info
+const (
+ _ = iota
+ ObjectInfoHandleValid
+ ObjectInfoHandleBasic
+ ObjectInfoProcess
+ ObjectInfoProcessThreads
+ ObjectInfoResourceChildren
+ ObjectInfoResourceRecords
+ ObjectInfoVMAR
+)
+
+// Options for socket_create
+const (
+ SocketStream = iota // 0
+ SocketDatagram = 1 << (iota - 1) // 1
+ SocketHasControl // 2
+ SocketHasAccept // 4
+)
+
+// Options for socket_write
+const (
+ _ = iota // 0
+ SocketShutdownWrite // 1
+ SocketShutdownRead // 2
+)
+
+// Options for socket_write and socket_read
+const (
+ SocketControl = 1 << 2
+)
+
+const (
+ _ = iota // 0
+ _ // 1
+ PropNumStateKinds // ZX_PROP_NUM_STATE_KINDS
+ PropName // ZX_PROP_NAME
+ PropRegisterFS // ZX_PROP_REGISTER_FS
+ PropProcessDebugAddr // ZX_PROP_PROCESS_DEBUG_ADDR
+ PropProcessVDSOBaseAddress // ZX_PROP_PROCESS_VDSO_BASE_ADDRESS
+ PropJobMaxHeight // ZX_PROP_JOB_MAX_HEIGHT
+)
+
+const (
+ TimensecInfinite = Time(0x7FFFFFFFFFFFFFFF)
+)
+
+// EOF is used like io.EOF.
+//
+// When package io is linked in, at initialization this value is
+// rewritten to be equivalent to io.EOF, so that the io.Readers
+// and io.Writers in this package meet their specs.
+var EOF error = eof{}
+
+type eof struct{}
+
+func (eof) Error() string { return "zx.EOF" }
+
+// EPIPE is used like syscall.EPIPE
+
+// When package syscall is linked in, at initialization this value is
+// rewritten to be equivalent to syscall.EPIPE.
+
+var EPIPE error = epipe{}
+
+type epipe struct{}
+
+func (epipe) Error() string { return "errno(32)" }
+
+type VMOOption int
+
+const (
+ VMOOptionNonResizable VMOOption = 1 << 0 // ZX_VMO_NON_RESIZABLE
+)
+
+type VMFlag int
+
+const (
+ VMFlagPermRead VMFlag = 1 << 0 // ZX_VM_FLAG_PERM_READ
+ VMFlagPermWrite VMFlag = 1 << 1 // ZX_VM_FLAG_PERM_WRITE
+ VMFlagPermExecute VMFlag = 1 << 2 // ZX_VM_FLAG_PERM_EXECUTE
+ VMFlagCompact VMFlag = 1 << 3 // ZX_VM_FLAG_COMPACT
+ VMFlagSpecific VMFlag = 1 << 4 // ZX_VM_FLAG_SPECIFIC
+ VMFlagSpecificOverwrite VMFlag = 1 << 5 // ZX_VM_FLAG_SPECIFIC_OVERWRITE
+ VMFlagCanMapSpecific VMFlag = 1 << 6 // ZX_VM_FLAG_CAN_MAP_SPECIFIC
+ VMFlagCanMapRead VMFlag = 1 << 7 // ZX_VM_FLAG_CAN_MAP_READ
+ VMFlagCanMapWrite VMFlag = 1 << 8 // ZX_VM_FLAG_CAN_MAP_WRITE
+ VMFlagCanMapExecute VMFlag = 1 << 9 // ZX_VM_FLAG_CAN_MAP_EXECUTE
+)
diff --git a/src/syscall/zx/types_string.go b/src/syscall/zx/types_string.go
new file mode 100644
index 0000000..aac9809
--- /dev/null
+++ b/src/syscall/zx/types_string.go
@@ -0,0 +1,68 @@
+// generated by stringer -type=Status; DO NOT EDIT
+
+// +build fuchsia
+
+package zx
+
+const (
+ _Status_name_0 = "ErrNoSpaceErrFileBigErrNotFileErrNotDirErrBadPath"
+ _Status_name_1 = "ErrIODataLossErrIODataIntegrityErrIORefusedErrIO"
+ _Status_name_2 = "ErrAccessDenied"
+ _Status_name_3 = "ErrUnavailableErrAlreadyBoundErrAlreadyExistsErrNotFoundErrPeerClosedErrCanceledErrShouldWaitErrTimedOutErrBadState"
+ _Status_name_4 = "ErrBufferTooSmallErrOutOfRangeErrBadSyscallErrWrongTypeErrBadHandleErrInvalidArgs"
+ _Status_name_5 = "ErrInterruptedRetryErrCallFailedErrNoMemoryErrNoResourcesErrNotSupportedErrInternalErrOk"
+)
+
+var (
+ _Status_index_0 = [...]uint8{0, 10, 20, 30, 39, 49}
+ _Status_index_1 = [...]uint8{0, 13, 31, 43, 48}
+ _Status_index_2 = [...]uint8{0, 15}
+ _Status_index_3 = [...]uint8{0, 14, 29, 45, 56, 69, 80, 93, 104, 115}
+ _Status_index_4 = [...]uint8{0, 17, 30, 43, 55, 67, 81}
+ _Status_index_5 = [...]uint8{0, 19, 32, 43, 57, 72, 83, 88}
+)
+
+func (i Status) String() string {
+ switch {
+ case -54 <= i && i <= -50:
+ i -= -54
+ return _Status_name_0[_Status_index_0[i]:_Status_index_0[i+1]]
+ case -43 <= i && i <= -40:
+ i -= -43
+ return _Status_name_1[_Status_index_1[i]:_Status_index_1[i+1]]
+ case i == -30:
+ return _Status_name_2
+ case -28 <= i && i <= -20:
+ i -= -28
+ return _Status_name_3[_Status_index_3[i]:_Status_index_3[i+1]]
+ case -15 <= i && i <= -10:
+ i -= -15
+ return _Status_name_4[_Status_index_4[i]:_Status_index_4[i+1]]
+ case -6 <= i && i <= 0:
+ i -= -6
+ return _Status_name_5[_Status_index_5[i]:_Status_index_5[i+1]]
+ default:
+ var buf [20]byte
+ return "zx.Status(" + string(itoa(buf[:], int(i))) + ")"
+ }
+}
+
+func itoa(buf []byte, val int) []byte {
+ i := len(buf) - 1
+ neg := false
+ if val < 0 {
+ neg = true
+ val = 0 - val
+ }
+ for val >= 10 {
+ buf[i] = byte(val%10 + '0')
+ i--
+ val /= 10
+ }
+ buf[i] = byte(val + '0')
+ if neg {
+ i--
+ buf[i] = '-'
+ }
+ return buf[i:]
+}
diff --git a/src/syscall/zx/zxsocket/client.go b/src/syscall/zx/zxsocket/client.go
new file mode 100644
index 0000000..03b1135
--- /dev/null
+++ b/src/syscall/zx/zxsocket/client.go
@@ -0,0 +1,178 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package zxsocket
+
+import (
+ "errors"
+ "syscall/zx"
+ "syscall/zx/mxnet"
+ "unsafe"
+)
+
+// Bind is BSD Sockets bind on a *Socket.
+func (s *Socket) Bind(addr mxnet.Addr, port uint16) error {
+ b := make([]byte, mxnet.SockaddrLen)
+ addrlen, err := mxnet.EncodeSockaddr(b, addr, port)
+ if err != nil {
+ return err
+ }
+ b = b[:addrlen]
+ _, err = s.Misc(OpBind, 0, b, nil, nil)
+ return err
+}
+
+// Connect is BSD Sockets connect on a *Socket.
+func (s *Socket) Connect(addr mxnet.Addr, port uint16) error {
+ b := make([]byte, mxnet.SockaddrLen)
+ addrlen, err := mxnet.EncodeSockaddr(b, addr, port)
+ if err != nil {
+ return err
+ }
+ b = b[:addrlen]
+
+ _, err = s.Misc(OpConnect, 0, b, nil, nil)
+ if err != nil && status(err) == zx.ErrShouldWait {
+ obs, err := s.Wait(mxnet.MXSIO_SIGNAL_OUTGOING, zx.TimensecInfinite)
+ switch status(err) {
+ case zx.ErrOk:
+ switch {
+ case obs&mxnet.MXSIO_SIGNAL_CONNECTED != 0:
+ return nil
+ default:
+ // TODO: Use opSetSockOpt to get the reason of the error.
+ return errors.New("zxsocket.Connect: OpConnect was not successful")
+ }
+ default:
+ return err
+ }
+ }
+ return err
+}
+
+// txn completes the client-side part of the RIO transaction.
+func (s *Socket) txn(msg *Msg) (uint32, error) {
+ if !msg.IsValid() {
+ return 0, zx.Error{Status: zx.ErrInvalidArgs, Text: "zxsocket.txn"}
+ }
+
+ msgBytes := (*[MessageSizeMax]byte)(unsafe.Pointer(msg))
+ numBytes, err := WriteControl(s.socket, msgBytes[:MessageHeaderSize+msg.Datalen])
+ if err != nil {
+ return 0, err
+ }
+ numBytes, err = ReadControl(s.socket, msgBytes[:])
+ if err != nil {
+ return 0, err
+ }
+
+ if !msg.IsValidIncoming(uint32(numBytes)) {
+ return 0, zx.Error{Status: zx.ErrIO, Text: "zxsocket.txn"}
+ }
+
+ // Check for remote error
+ status := zx.Status(msg.Arg)
+ if status < 0 {
+ return 0, zx.Error{Status: status, Text: "zxsocket.txn"}
+ }
+ return uint32(status), nil
+}
+
+func (s *Socket) ListenStream(backlog int) error {
+ b := make([]byte, 4)
+ b[0] = byte(backlog)
+ b[1] = byte(backlog >> 8)
+ b[2] = byte(backlog >> 16)
+ b[3] = byte(backlog >> 24)
+ _, err := s.Misc(OpListen, 0, b, nil, nil)
+ return err
+}
+
+func (s *Socket) Accept() (*Socket, error) {
+ if s.flags&SocketFlagsDidListen == 0 {
+ return nil, errors.New("zxsocket.Accept: listen was not called")
+ }
+
+ var h zx.Handle
+ for {
+ err := s.socket.Accept(&h)
+ if err == nil {
+ break
+ }
+ if status(err) != zx.ErrShouldWait {
+ return nil, err
+ }
+ s.socket.Handle().SignalPeer(0, zx.SignalUser7)
+ // TODO: non-blocking support, pass this to the poller
+ const ZX_SOCKET_ACCEPT = zx.SignalSocketAccept
+ const ZX_SOCKET_PEER_CLOSED = zx.SignalSocketPeerClosed
+ pending, err := s.Wait(ZX_SOCKET_ACCEPT|ZX_SOCKET_PEER_CLOSED, zx.TimensecInfinite)
+ if err != nil {
+ return nil, err
+ }
+ if pending&ZX_SOCKET_ACCEPT != 0 {
+ continue
+ }
+ if pending&ZX_SOCKET_PEER_CLOSED != 0 {
+ return nil, zx.Error{Status: zx.ErrPeerClosed, Text: "zxsocket"}
+ }
+ }
+ return NewSocket(zx.Socket(h)), nil
+}
+
+func (s *Socket) getName(op uint32, debug string) (addr mxnet.Addr, port uint16, err error) {
+ out := make([]byte, mxnet.SockaddrReplyLen)
+ _, err = s.Misc(OpGetSockname, 0, nil, out, nil)
+ if err != nil {
+ return "", 0, err
+ }
+ addr, port, err = mxnet.DecodeSockaddr(out)
+ if err != nil {
+ return "", 0, err
+ }
+
+ return addr, port, nil
+}
+
+func (s *Socket) SockName() (addr mxnet.Addr, port uint16, err error) {
+ return s.getName(OpGetSockname, "GetSockName")
+}
+
+func (s *Socket) PeerName() (addr mxnet.Addr, port uint16, err error) {
+ return s.getName(OpGetPeerName, "GetPeerName")
+}
+
+func (s *Socket) Misc(op uint32, off int64, in, out []byte, handles []zx.Handle) (n int, err error) {
+ if len(in) > MessageChunkSize || len(out) > MessageChunkSize {
+ return 0, zx.Error{Status: zx.ErrInvalidArgs, Text: "zxsocket.Misc"}
+ }
+
+ var msg Msg
+ msg.SetOp(op)
+ msg.Arg = int32(len(out))
+ msg.Datalen = uint32(len(in))
+ msg.SetOff(off)
+ copy(msg.Data[:], in)
+
+ if len(handles) > 0 {
+ copy(msg.Handle[:], handles)
+ msg.Hcount = uint32(len(handles))
+ }
+ if _, err = s.txn(&msg); err != nil {
+ return 0, err
+ }
+
+ if int(msg.Datalen) > len(out) {
+ return 0, zx.Error{Status: zx.ErrIO, Text: "zxsocket.Misc"}
+ }
+ n = copy(out, msg.Data[:msg.Datalen])
+
+ if op == OpListen {
+ s.flags |= SocketFlagsDidListen
+ }
+
+ return n, nil
+}
diff --git a/src/syscall/zx/zxsocket/message.go b/src/syscall/zx/zxsocket/message.go
new file mode 100644
index 0000000..b3a89a9
--- /dev/null
+++ b/src/syscall/zx/zxsocket/message.go
@@ -0,0 +1,227 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package zxsocket
+
+import (
+ "unsafe"
+
+ "syscall/zx"
+)
+
+const (
+ // MessageChunkSize is the largest size of 'data' in an zxsocket message
+ MessageChunkSize = 900
+
+ // MessageSizeMax is the largest size of a zxsocket message
+ MessageSizeMax = uint32(unsafe.Sizeof(Msg{}))
+
+ // MessageHeaderSize is the size of zxsocket message without 'data'
+ MessageHeaderSize = uint32(unsafe.Sizeof(MsgHeader{}))
+
+ // MessageMaxHandles is the maximum number of handles a message may carry.
+ // In reality, zx.Sockets can't hold handles, but this is used to support
+ // the deprecated RemoteIO protocol over a socket.
+ MessageMaxHandles = 3
+)
+
+// Custom errors for zxsocket RemoteIO.
+var (
+ // If returned from dispatcher callback, indicates that the dispatcher should immediately
+ // disconnect with no additional callbacks.
+ ErrDisconnectNoCallback = zx.Error{Status: 1, Text: "fdio.Dispatcher"}
+ // If returned from dispatcher callback, indicates that there are no more messages to read.
+ ErrNoWork = zx.Error{Status: -9999, Text: "fdio.Dispatcher.NoWork"}
+ // If returned from dispatcher callback, indicates that the message was handed to another
+ // server.
+ ErrIndirect = zx.Error{Status: -9998, Text: "fdio.Dispatcher.Indirect"}
+)
+
+const (
+ OpFlagOneHandle = uint32(0x100 + iota)
+)
+
+// Values for op. Each one will signify a request for a different operation.
+// This is a copy of the list in fdio/message.go, with the non-socket-related
+// options removed. Note that these are deprecated. We will be migrating to
+// FIDL2 ordinals soon.
+const (
+ _ = uint32(iota)
+ OpClose
+ OpClone = uint32(iota) | OpFlagOneHandle
+ OpOpen = uint32(iota) | OpFlagOneHandle
+ _ = uint32(iota) // OpMisc
+ OpRead
+ OpWrite
+ _ // OpSeek
+ _ // OpStat
+ _ // OpReaddir
+ OpIoctl
+ _ // OpUnlink
+ _ // OpReadAt
+ _ // OpWriteAt
+ _ // OpTruncate
+ _ = uint32(iota) | OpFlagOneHandle // OpRename
+ OpConnect = uint32(iota)
+ OpBind
+ OpListen
+ OpGetSockname
+ OpGetPeerName
+ OpGetSockOpt
+ OpSetSockOpt
+ OpGetAddrInfo
+ _ // OpSetAttr
+ _ // OpSync
+ _ = uint32(iota) | OpFlagOneHandle // OpLink
+ _ = uint32(iota) // OpMmap
+ OpFcntl
+ OpNumOps = uint32(iota) // The total number of operations
+)
+
+type Protocol uint32
+
+// All available FDIO protocols
+const (
+ // The SERVICE protocol allows access to a generic interface.
+ ProtocolService = Protocol(iota)
+ // The FILE protocol allows access to a regular file.
+ ProtocolFile
+ // The DIRECTORY protocol allows access to a directory, which may
+ // contain additional nodes.
+ ProtocolDirectory
+ // The PIPE protocol uses message ports as simple, no-flow-control io pipes.
+ ProtocolPipe
+ // The VMOFILE protocol accesses a file as a VMO.
+ ProtocolVMOFile
+ // The DEVICE protocol allows access to a generic device.
+ ProtocolDevice
+ // The SOCKET protocol provides socket access.
+ ProtocolSocket
+ ProtocolSocketConnected
+)
+
+const (
+ OpenFlagDescribe = 0x00800000
+)
+
+// FIDL2 message header
+type FIDLHeader struct {
+ Txid uint32
+ reserved0 uint32
+ flags uint32
+ op uint32
+}
+
+type MsgHeader struct {
+ FIDLHeader
+ Datalen uint32
+ Arg int32
+ arg2 int64
+ reserved1 int32
+ Hcount uint32
+ Handle [4]zx.Handle // 3 handles + reply pipe, unused here though.
+}
+
+func (m *MsgHeader) Op() uint32 {
+ return m.op & 0x3FFF
+}
+func (m *MsgHeader) SetOp(v uint32) {
+ m.op = (v & 0x3FFF)
+}
+func (m *MsgHeader) OpHandleCount() uint32 {
+ return (m.op >> 8) & 3
+}
+func (m *MsgHeader) Off() int64 {
+ return m.arg2
+}
+func (m *MsgHeader) SetOff(v int64) {
+ m.arg2 = v
+}
+func (m *MsgHeader) Mode() uint32 {
+ return uint32(m.arg2)
+}
+func (m *MsgHeader) SetMode(v uint32) {
+ m.arg2 = int64(v)
+}
+func (m *MsgHeader) Protocol() Protocol {
+ return Protocol(m.arg2)
+}
+func (m *MsgHeader) SetProtocol(p Protocol) {
+ m.arg2 = int64(p)
+}
+func (m *MsgHeader) IoctlOp() uint32 {
+ return uint32(m.arg2)
+}
+func (m *MsgHeader) SetIoctlOp(v uint32) {
+ m.arg2 = int64(v)
+}
+func (m *MsgHeader) FcntlFlags() uint32 {
+ return uint32(m.arg2)
+}
+func (m *MsgHeader) SetFcntlFlags(v uint32) {
+ m.arg2 = int64(v)
+}
+
+// Msg is the message sent in the zxsocket protocol.
+type Msg struct {
+ MsgHeader
+ Data [MessageChunkSize]uint8
+}
+
+func (m *Msg) CallMsg(c *zx.Channel) (numBytes, numHandles uint32, err error) {
+ wData := (*[MessageSizeMax]byte)(unsafe.Pointer(m))[:MessageHeaderSize+m.Datalen]
+ var wHandles []zx.Handle
+ if m.Hcount > 0 {
+ wHandles = m.Handle[:m.Hcount]
+ }
+ rData := (*[MessageSizeMax]byte)(unsafe.Pointer(m))[:]
+ rHandles := m.Handle[:]
+ numBytes, numHandles, err = c.Call(0, zx.TimensecInfinite, wData, wHandles, rData, rHandles)
+ m.Hcount = numHandles
+ return
+}
+
+// ReadMsg reads a message from a socket.
+func (m *Msg) ReadMsg(s zx.Socket) (numBytes int, numHandles uint32, err error) {
+ msgBytes := (*[MessageSizeMax]byte)(unsafe.Pointer(m))
+ // TODO: why is numBytes int?
+ numBytes, err = s.Read(msgBytes[:], zx.SocketControl)
+ numHandles = 0
+ m.Hcount = numHandles
+ return
+}
+
+// WriteMsg writes a message to a socket.
+func (m *Msg) WriteMsg(s zx.Socket) (int, error) {
+ msgBytes := (*[MessageSizeMax]byte)(unsafe.Pointer(m))
+ data := msgBytes[:MessageHeaderSize+m.Datalen]
+ return s.Write(data, zx.SocketControl)
+}
+
+// WriteMsg writes a message to a channel.
+func (m *Msg) WriteChannelMsg(c *zx.Channel) error {
+ msgBytes := (*[MessageSizeMax]byte)(unsafe.Pointer(m))
+ data := msgBytes[:MessageHeaderSize+m.Datalen]
+ var handles []zx.Handle
+ if m.Hcount > 0 {
+ handles = m.Handle[:m.Hcount]
+ }
+ return c.Write(data, handles, 0)
+}
+
+func (m *Msg) IsValid() bool {
+ if m.Datalen > MessageChunkSize || m.Hcount != 0 {
+ return false
+ }
+ return true
+}
+
+func (m *Msg) IsValidIncoming(size uint32) bool {
+ if (size < MessageHeaderSize) || m.Datalen != (size-MessageHeaderSize) {
+ return false
+ }
+ return m.IsValid()
+}
diff --git a/src/syscall/zx/zxsocket/server.go b/src/syscall/zx/zxsocket/server.go
new file mode 100644
index 0000000..211babf
--- /dev/null
+++ b/src/syscall/zx/zxsocket/server.go
@@ -0,0 +1,69 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package zxsocket
+
+import (
+ "syscall/zx"
+)
+
+// ServerHandler is the type of the callback which contains the remoteio "server". It is called from
+// the server handler function.
+// - msg.Datalen represents the size of the incoming/outgoing message in msg.Data.
+// - Return values are placed in msg.Arg. Negative is error.
+type ServerHandler func(msg *Msg, rh zx.Socket, cookie int64) zx.Status
+
+// Handler reads a single RIO message from the handle h. If the message is valid, the callback
+// cb is invoked. If the callback is successful, a response may be sent back on handle h.
+func Handler(h zx.Socket, cb interface{}, cookie int64) error {
+ var msg Msg
+
+ serverCb := cb.(ServerHandler)
+ if h == 0 {
+ // The remote side has been closed. Send our final callback and leave.
+ msg.SetOp(OpClose)
+ msg.Arg = 0
+ msg.Datalen = 0
+ msg.Hcount = 0
+ serverCb(&msg, 0, cookie)
+ return nil
+ }
+ msg.Hcount = MessageMaxHandles
+ numBytesInt, _, err := msg.ReadMsg(h)
+ numBytes := uint32(numBytesInt)
+ if err != nil {
+ if mxerr, hasStatus := err.(zx.Error); hasStatus && mxerr.Status == zx.ErrBadState {
+ return ErrNoWork
+ }
+ return err
+ }
+ if !msg.IsValidIncoming(numBytes) {
+ return zx.Error{Status: zx.ErrInvalidArgs, Text: "zxsocket.Handler"}
+ }
+
+ isClose := (msg.Op() == OpClose)
+ status := serverCb(&msg, h, cookie)
+ msg.Arg = int32(status)
+ if zx.Status(msg.Arg) == ErrIndirect.Status {
+ // The callback is handling the reply itself
+ return nil
+ } else if status < 0 || !msg.IsValid() {
+ // zx.Error case
+ msg.Datalen = 0
+ if msg.Arg >= 0 {
+ // TODO(smklein): This error code may change. It currently is set to "ERR_FAULT" in
+ // Zircon, but is scheduled to change.
+ msg.Arg = int32(zx.ErrIO)
+ }
+ }
+
+ _, err = msg.WriteMsg(h)
+ if isClose {
+ // Signals that a close callback is not necessary -- the op has already completed
+ return ErrDisconnectNoCallback
+ }
+ return err
+}
diff --git a/src/syscall/zx/zxsocket/socket.go b/src/syscall/zx/zxsocket/socket.go
new file mode 100644
index 0000000..d38b9f5
--- /dev/null
+++ b/src/syscall/zx/zxsocket/socket.go
@@ -0,0 +1,380 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package zxsocket
+
+import (
+ "io"
+ "syscall/zx"
+ "syscall/zx/fdio"
+ fidlIo "syscall/zx/io"
+ "syscall/zx/mxnet"
+ "syscall/zx/zxwait"
+)
+
+// Status extracts an zx.Status from an error. This is duplicated from syscall/zx/merror,
+// but we can't import that directly because it causes an import loop.
+func status(err error) zx.Status {
+ if err == nil {
+ return zx.ErrOk
+ }
+ if s, hasStatus := err.(zx.Error); hasStatus {
+ return s.Status
+ }
+ return zx.ErrInternal
+}
+
+// Socket is an fdio.FDIO socket.
+type Socket struct {
+ socket zx.Socket
+
+ dgram bool
+ flags uint32
+}
+
+// Socket flags
+const (
+ SocketFlagsDidListen = 1 << iota // zxsocket._DID_LISTEN
+)
+
+func NewSocket(s zx.Socket) *Socket {
+ return &Socket{socket: s}
+}
+
+func (s *Socket) Wait(signals zx.Signals, timeout zx.Time) (observed zx.Signals, err error) {
+ return zxwait.Wait(zx.Handle(s.socket), signals, timeout)
+}
+
+// Handles returns the underlying handles for this Socket.
+func (s *Socket) Handles() []zx.Handle {
+ return []zx.Handle{zx.Handle(s.socket)}
+}
+
+// Clone makes a clone of the object.
+func (s *Socket) Clone() (fdio.FDIO, error) {
+ return nil, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket.Clone"}
+}
+
+// Close closes the object.
+func (s *Socket) Close() error {
+ if s.socket == 0 {
+ return nil
+ }
+ var msg Msg
+ msg.SetOp(OpClose)
+
+ _, err := s.txn(&msg)
+
+ s.socket.Close()
+ s.socket = 0
+
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// Sync implements fdio.FDIO for Socket.
+func (s *Socket) Sync() error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// GetAttr implements fdio.FDIO for Socket.
+func (s *Socket) GetAttr() (fidlIo.NodeAttributes, error) {
+ return fidlIo.NodeAttributes{}, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// SetAttr implements fdio.FDIO for Socket.
+func (s *Socket) SetAttr(flags uint32, attr fidlIo.NodeAttributes) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Ioctl implements fdio.FDIO for Socket.
+func (s *Socket) Ioctl(op uint32, max uint64, in []byte, _ []zx.Handle) ([]byte, []zx.Handle, error) {
+ var msg Msg
+ if len(in) > fdio.IoctlMaxInput {
+ return nil, nil, zx.Error{Status: zx.ErrInvalidArgs, Text: "zxsocket.Ioctl"}
+ }
+
+ if fdio.IoctlKind(op) != fdio.IoctlKindDefault {
+ return nil, nil, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Ioctl"}
+ }
+
+ out := make([]byte, MessageSizeMax)
+ msg.SetOp(OpIoctl)
+ msg.Datalen = uint32(len(in))
+ msg.Arg = int32(len(out))
+ msg.SetIoctlOp(op)
+ copy(msg.Data[:], in)
+
+ _, err := s.txn(&msg)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ copy(out, msg.Data[:msg.Datalen])
+ return out[:msg.Datalen], nil, nil
+}
+
+// Read implements fdio.FDIO for Socket.
+func (s *Socket) Read(data []byte) (n int, err error) {
+ if s.dgram {
+ b, _, _, _, err := s.RecvMsg(len(data))
+ n = copy(data, b)
+ return n, err
+ }
+ // c.f. mxsio_read_stream in zircon/system/ulib/fdio/remoteio.c
+ for {
+ n, err = s.socket.Read(data, 0)
+ switch status(err) {
+ case zx.ErrOk:
+ return n, nil
+ case zx.ErrPeerClosed:
+ return 0, io.EOF
+ case zx.ErrShouldWait:
+ obs, err := s.Wait(zx.SignalSocketReadable|zx.SignalSocketPeerClosed, zx.TimensecInfinite)
+ switch status(err) {
+ case zx.ErrOk:
+ switch {
+ case obs&zx.SignalSocketReadable != 0:
+ continue
+ case obs&zx.SignalSocketPeerClosed != 0:
+ return 0, io.EOF
+ }
+ case zx.ErrBadHandle, zx.ErrCanceled:
+ return 0, io.EOF
+ default:
+ return 0, err
+ }
+ default:
+ return 0, err
+ }
+ }
+}
+
+// ReadAt implements fdio.FDIO for Socket.
+func (s *Socket) ReadAt(data []byte, off int64) (int, error) {
+ return 0, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Write implements fdio.FDIO for Socket.
+func (s *Socket) Write(data []byte) (int, error) {
+ if s.dgram {
+ n, err := s.SendMsg(data, "", 0)
+ return n, err
+ }
+
+ // c.f. zxsio_write_stream
+ var total int
+ for {
+ n, err := s.socket.Write(data, 0)
+ total += n
+
+ switch status(err) {
+ case zx.ErrOk:
+ return total, nil
+ case zx.ErrShouldWait:
+ obs, err := s.Wait(zx.SignalSocketWritable|zx.SignalSocketPeerClosed|zx.SignalSocketWriteDisabled, zx.TimensecInfinite)
+ if err != nil {
+ return total, err
+ }
+ if obs&zx.SignalSocketPeerClosed != 0 || obs&zx.SignalSocketWriteDisabled != 0 {
+ return total, zx.Error{Status: zx.ErrPeerClosed, Text: "zxsocket.Socket.Write"}
+ }
+ if obs&zx.SignalSocketWritable != 0 {
+ data = data[n:]
+ continue
+ }
+ // This case should be impossible:
+ return total, zx.Error{Status: zx.ErrInternal, Text: "zxsocket.Socket.Write(impossible state)"}
+ default:
+ return total, err
+ }
+ }
+}
+
+// WriteAt implements fdio.FDIO for Socket.
+func (s *Socket) WriteAt(data []byte, off int64) (int, error) {
+ return 0, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Seek implements fdio.FDIO for Socket.
+func (s *Socket) Seek(offset int64, whence int) (int64, error) {
+ return 0, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Truncate implements fdio.FDIO for Socket.
+func (s *Socket) Truncate(length uint64) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Open implements fdio.FDIO for Socket.
+func (s *Socket) Open(path string, flags uint32, mode uint32) (fdio.FDIO, error) {
+ return nil, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Link implements fdio.FDIO for Socket.
+func (s *Socket) Link(oldpath, newpath string) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Rename implements fdio.FDIO for Socket.
+func (s *Socket) Rename(oldpath, newpath string) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Unlink implements fdio.FDIO for Socket.
+func (s *Socket) Unlink(path string) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// ReadDirents implements fdio.FDIO for Socket.
+func (s *Socket) ReadDirents(max uint64) ([]byte, error) {
+ return nil, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Rewind implements fdio.FDIO for Socket.
+func (s *Socket) Rewind() error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+func (s *Socket) RecvMsg(maxLen int) (b []byte, flags int, addr string, port uint16, err error) {
+ mlen := maxLen + mxnet.SockmsgHdrLen
+ msgdata := make([]byte, mlen)
+ n, err := s.recvMsg(msgdata)
+ if err != nil {
+ return nil, 0, "", 0, err
+ }
+ msgdata = msgdata[:n]
+ addrstr, port, flags, err := mxnet.DecodeSockmsgHdr(msgdata)
+ if err != nil {
+ return nil, 0, "", 0, err
+ }
+ return msgdata[mxnet.SockmsgHdrLen:], flags, string(addrstr), port, nil
+}
+
+func (s *Socket) recvMsg(data []byte) (int, error) {
+ for {
+ n, err := s.socket.Read(data, 0)
+ switch status(err) {
+ case zx.ErrOk:
+ return n, err
+ case zx.ErrShouldWait:
+ if n != 0 {
+ return n, zx.Error{Status: zx.ErrInternal, Text: "zsocket.Socket.recvMsg(datagram short-read)"}
+ }
+
+ obs, err := s.Wait(zx.SignalSocketReadable|zx.SignalSocketPeerClosed|zx.SignalSocketReadDisabled, zx.TimensecInfinite)
+ if err != nil {
+ return n, err
+ }
+ if obs&zx.SignalSocketReadable != 0 {
+ continue
+ }
+ if obs&zx.SignalSocketPeerClosed != 0 || obs&zx.SignalSocketReadDisabled != 0 {
+ return n, zx.Error{Status: zx.ErrPeerClosed, Text: "zxsocket.Socket.recvMsg"}
+ }
+ return n, zx.Error{Status: zx.ErrInternal, Text: "zxsocket.Socket.recvMsg"}
+ default:
+ return n, err
+ }
+ }
+}
+
+func (s *Socket) SendMsg(b []byte, addr string, port uint16) (int, error) {
+ data := make([]byte, len(b)+mxnet.SockmsgHdrLen)
+ err := mxnet.EncodeSockmsgHdr(data, mxnet.Addr(addr), port, 0)
+ if err != nil {
+ return 0, err
+ }
+ copy(data[mxnet.SockmsgHdrLen:], b)
+
+ for {
+ n, err := s.socket.Write(data, 0)
+ switch status(err) {
+ case zx.ErrOk:
+ return len(b), nil
+ case zx.ErrShouldWait:
+ if n != 0 {
+ return n, zx.Error{Status: zx.ErrInternal, Text: "zxsocket.Socket.SendMsg(datagram short-write)"}
+ }
+
+ obs, err := s.Wait(zx.SignalSocketWritable|zx.SignalSocketPeerClosed|zx.SignalSocketWriteDisabled, zx.TimensecInfinite)
+ if err != nil {
+ return 0, err
+ }
+ if obs&zx.SignalSocketWritable != 0 {
+ continue
+ }
+ if obs&zx.SignalSocketPeerClosed != 0 || obs&zx.SignalSocketWriteDisabled != 0 {
+ return 0, zx.Error{Status: zx.ErrPeerClosed, Text: "zxsocket.Socket.SendMsg"}
+ }
+ return 0, zx.Error{Status: zx.ErrInternal, Text: "zxsocket.Socket.SendMsg(impossible state)"}
+ default:
+ if n != 0 {
+ return n, zx.Error{Status: zx.ErrInternal, Text: "zxsocket.Socket.SendMsg(datagram short-write)"}
+ }
+ return 0, err
+ }
+ }
+}
+
+// SetDgram marks a *Socket as a datagram (UDP) socket.
+// A different protocol is used internally.
+func (s *Socket) SetDgram() {
+ s.dgram = true
+}
+
+func ReadControl(s zx.Socket, data []byte) (n int, err error) {
+ // c.f. zxsocket._read_control in zircon/system/ulib/fdio/remoteio.c
+ for {
+ n, err = s.Read(data, zx.SocketControl)
+ switch status(err) {
+ case zx.ErrOk:
+ return n, nil
+ case zx.ErrPeerClosed:
+ return 0, io.EOF
+ case zx.ErrShouldWait:
+ obs, err := zxwait.Wait(
+ zx.Handle(s),
+ zx.SignalSocketControlReadable|zx.SignalSocketPeerClosed,
+ zx.TimensecInfinite,
+ )
+ switch status(err) {
+ case zx.ErrOk:
+ switch {
+ case obs&zx.SignalSocketControlReadable != 0:
+ continue
+ case obs&zx.SignalSocketPeerClosed != 0:
+ return 0, io.EOF
+ }
+ case zx.ErrBadHandle, zx.ErrCanceled:
+ return 0, io.EOF
+ default:
+ return 0, err
+ }
+ default:
+ return 0, err
+ }
+ }
+}
+
+func WriteControl(s zx.Socket, data []byte) (int, error) {
+ // c.f. zxsocket._write_control
+ for {
+ n, err := s.Write(data, zx.SocketControl)
+ switch status(err) {
+ case zx.ErrOk:
+ return n, nil
+ case zx.ErrShouldWait:
+ _, err := zxwait.Wait(zx.Handle(s), zx.SignalSocketControlWriteable, zx.TimensecInfinite)
+ if err != nil {
+ return n, err
+ }
+ continue
+ }
+ }
+}
diff --git a/src/syscall/zx/zxwait/zxwait.go b/src/syscall/zx/zxwait/zxwait.go
new file mode 100644
index 0000000..f96b941
--- /dev/null
+++ b/src/syscall/zx/zxwait/zxwait.go
@@ -0,0 +1,178 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+// Package zxwait implements a Zircon port waiter compatible with goroutines.
+//
+// The function Wait can be used to wait on a handle without consuming
+// an OS thread or resorting to event-driven programming.
+package zxwait
+
+import (
+ "sync"
+ "sync/atomic"
+ "syscall/zx"
+
+ _ "unsafe" // for go:linkname
+)
+
+// Wait waits for signals on handle.
+//
+// The goroutine that calls Wait is parked until a signal is observed or the
+// handle is closed. No OS thread is tied up while Wait is blocked.
+//
+// Semantically it is equivalent to calling the WaitOne method on a zx.Handle.
+// However it is not implemented with zx_object_wait_one, instead it uses
+// zx_object_wait_async and a port to wait for signals.
+func Wait(handle zx.Handle, signals zx.Signals, timeout zx.Time) (observed zx.Signals, err error) {
+ // TODO: support finite timeouts.
+ if timeout != zx.TimensecInfinite {
+ if status := zx.Sys_object_wait_one(handle, signals, timeout, &observed); status != zx.ErrOk {
+ return observed, zx.Error{Status: status, Text: "zxwait.Wait"}
+ }
+ return observed, nil
+ }
+ sysWaiterOnce.Do(sysWaiterInit)
+ return sysWaiter.Wait(handle, signals)
+}
+
+//go:linkname gopark runtime.gopark
+func gopark(unlockf func(g uintptr, waiting *waitingG) bool, waitng *waitingG, reason string, traceEv byte, traceskip int)
+
+//go:linkname goready runtime.goready
+func goready(g uintptr, traceskip int)
+
+// waitingG is used to track a parked g waiting on a singal.
+//
+// A waitingG is represented by a unique key, which is also
+// its positional index in the waiter's all slice. This key
+// is not a GCed pointer, so it can be safely passed to the
+// kernel and returned at a later time.
+type waitingG struct {
+ key uint64 // index into all, stable identifier passed to kernel
+ g uintptr
+ obs uint32 // zx.Signals
+ ready uintptr // set when g is set by unlockf or obs set by dequeue
+}
+
+// A waiter is a zircon port that parks goroutines waiting on signals.
+//
+// Currently there is only one instance of waiter per process, stored
+// in sysWaiter. It is however a self-contained object and multiple
+// of them can safely exist concurrently.
+type waiter struct {
+ port zx.Port
+
+ mu sync.Mutex
+ free []*waitingG
+ all []*waitingG
+}
+
+func newWaiter() *waiter {
+ port, err := zx.NewPort(0)
+ if err != nil {
+ panic(err) // misuse of system call, no useful recovery
+ }
+ w := &waiter{
+ port: port,
+ }
+ go w.dequeue()
+ return w
+}
+
+var sysWaiterOnce sync.Once
+var sysWaiter *waiter
+
+func sysWaiterInit() {
+ sysWaiter = newWaiter()
+}
+
+// dequeue is a dedicated goroutine to waiting on the waiter's port.
+func (w *waiter) dequeue() {
+ var pkt zx.Packet
+ for {
+ err := w.port.Wait(&pkt, zx.TimensecInfinite)
+ if err != nil {
+ panic(err)
+ }
+
+ w.mu.Lock()
+ waiting := w.all[pkt.Hdr.Key]
+ w.mu.Unlock()
+
+ obs := pkt.Signal().Observed
+
+ atomic.StoreUint32(&waiting.obs, uint32(obs))
+ if atomic.CompareAndSwapUintptr(&waiting.ready, 0, 1) {
+ // We beat unlockf, goroutine never parked.
+ continue
+ }
+ // We were beaten by unlockf, so waiting.g has a real value.
+ g := atomic.LoadUintptr(&waiting.g)
+ goready(g, 0)
+ }
+}
+
+// Wait waits for signals on handle.
+//
+// See the package function Wait for more commentary.
+func (w *waiter) Wait(handle zx.Handle, signals zx.Signals) (observed zx.Signals, err error) {
+ var waiting *waitingG
+
+ w.mu.Lock()
+ if len(w.free) == 0 {
+ waiting = &waitingG{
+ key: uint64(len(w.all)),
+ }
+ w.all = append(w.all, waiting)
+ } else {
+ waiting = w.free[len(w.free)-1]
+ w.free = w.free[:len(w.free)-1]
+ }
+ w.mu.Unlock()
+
+ var pkt zx.Packet
+ pkt.Hdr.Key = waiting.key
+ pkt.Signal().Trigger = signals
+
+ const ZX_WAIT_ASYNC_ONCE = 0
+ if err = w.port.WaitAsync(handle, pkt.Hdr.Key, signals, ZX_WAIT_ASYNC_ONCE); err != nil {
+ return 0, err
+ }
+
+ const traceEv = 24
+ gopark(w.unlockf, waiting, "zxwait", traceEv, 0)
+
+ obs := atomic.LoadUint32(&waiting.obs)
+
+ *waiting = waitingG{key: waiting.key} // clear waitingG for reuse
+
+ w.mu.Lock()
+ w.free = append(w.free, waiting)
+ w.mu.Unlock()
+
+ return zx.Signals(obs), nil
+}
+
+// unlockf is passed as a callback to gopark.
+//
+// Reporting true will park the goroutine until goready is called.
+//
+// Reporting false will immediately start running the goroutine
+// again, and nothing else should call goready.
+//
+// This method is called without a 'g', so it can do very little.
+// Avoid the stack. Don't use anything with 'g'-based runtime
+// support (like sync.Mutex). Do as little as possible.
+func (w *waiter) unlockf(g uintptr, waiting *waitingG) bool {
+ atomic.StoreUintptr(&waiting.g, g)
+
+ // If we can set ready, then this executed before dequeue
+ // and the goroutine will be parked.
+ //
+ // If we cannot set it, then dequeue has already run and
+ // waiting.obs is set, so do not park the goroutine.
+ return atomic.CompareAndSwapUintptr(&waiting.ready, 0, 1)
+}
diff --git a/src/syscall/zx/zxwait/zxwait.s b/src/syscall/zx/zxwait/zxwait.s
new file mode 100644
index 0000000..a35105e
--- /dev/null
+++ b/src/syscall/zx/zxwait/zxwait.s
@@ -0,0 +1,5 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Empty assembly file so empty func definitions work.
diff --git a/src/syscall/zx/zxwait/zxwait_test.go b/src/syscall/zx/zxwait/zxwait_test.go
new file mode 100644
index 0000000..b649344
--- /dev/null
+++ b/src/syscall/zx/zxwait/zxwait_test.go
@@ -0,0 +1,84 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build fuchsia
+
+package zxwait_test
+
+import (
+ "runtime"
+ "sync"
+ "syscall/zx"
+ "syscall/zx/zxwait"
+ "testing"
+)
+
+func TestWaitPreexisting(t *testing.T) {
+ c0, c1, err := zx.NewChannel(0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer c0.Close()
+ defer c1.Close()
+
+ obs, err := zxwait.Wait(*c0.Handle(), zx.SignalChannelWritable, zx.TimensecInfinite)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if obs&zx.SignalChannelWritable == 0 {
+ t.Errorf("want zx.SignalChannelWritable, got obs=%x", obs)
+ }
+
+ obs, err = zxwait.Wait(*c1.Handle(), zx.SignalChannelWritable, zx.TimensecInfinite)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if obs&zx.SignalChannelWritable == 0 {
+ t.Errorf("want zx.SignalChannelWritable, got obs=%x", obs)
+ }
+}
+
+func TestWait(t *testing.T) {
+ t.Logf("GOMAXPROCS=%v", runtime.GOMAXPROCS(0))
+ c0s := make([]zx.Channel, 100)
+ c1s := make([]zx.Channel, len(c0s))
+ allObs := make([]zx.Signals, len(c0s))
+
+ var wg sync.WaitGroup
+ for i := range c0s {
+ var err error
+ c0s[i], c1s[i], err = zx.NewChannel(0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ wg.Add(1)
+ go func(i int) {
+ obs, err := zxwait.Wait(*c0s[i].Handle(), zx.SignalChannelReadable, zx.TimensecInfinite)
+ if err != nil {
+ t.Fatal(err)
+ }
+ allObs[i] = obs
+ //t.Logf("signal for channel %d received", i)
+ //fmt.Printf("TEST: signal for channel %d received\n", i)
+ wg.Done()
+ }(i)
+ }
+
+ b := []byte("hello")
+ for i, c1 := range c1s {
+ //t.Logf("writing on channel %d", i)
+ //fmt.Printf("TEST: writing on channel %d\n", i)
+ if err := c1.Write(b, nil, 0); err != nil {
+ t.Errorf("failed to write on channel %d: %v", i, err)
+ }
+ }
+
+ wg.Wait()
+
+ for i, obs := range allObs {
+ if obs&zx.SignalChannelWritable == 0 {
+ t.Errorf("channel %d: obs=%x want zx.SignalChannelReadable", i, obs)
+ }
+ }
+}
diff --git a/src/time/sys_fuchsia.go b/src/time/sys_fuchsia.go
new file mode 100644
index 0000000..6fdb086
--- /dev/null
+++ b/src/time/sys_fuchsia.go
@@ -0,0 +1,29 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time
+
+func initLocal() {
+ localLoc.name = "UTC"
+}
+
+func read(fd uintptr, buf []byte) (int, error) {
+ panic("TODO")
+}
+
+func open(name string) (uintptr, error) {
+ panic("TODO")
+}
+
+func closefd(fd uintptr) {
+ panic("TODO")
+}
+
+func preadn(fd uintptr, buf []byte, off int) error {
+ panic("TODO")
+}
+
+func isNotExist(err error) bool {
+ panic("TODO")
+}
diff --git a/src/time/zoneinfo_fuchsia.go b/src/time/zoneinfo_fuchsia.go
new file mode 100644
index 0000000..09a6696
--- /dev/null
+++ b/src/time/zoneinfo_fuchsia.go
@@ -0,0 +1,7 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time
+
+var zoneSources = []string{}