blob: 85dc8ce4ca525945e46f3e651ea3f755dc012a8f [file] [log] [blame]
// Copyright 2020 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 zx
import (
"sync/atomic"
"unsafe"
)
// Process-wide FDIO handles.
var (
StdioHandles [3]Handle // in/out/err
StdioHandleTypes [3]int
CwdHandle Handle
ProcHandle Handle
VMARRoot VMAR
RootNSMap map[string]Handle
)
const ZX_CPRNG_DRAW_MAX_LEN = 256
func set_stdio_handle(n int, h uint32, t uint32) {
StdioHandles[n] = Handle(h)
StdioHandleTypes[n] = int(t)
}
func set_proc_handle(h uint32) {
ProcHandle = Handle(h)
}
func get_proc_handle() uint32 {
return uint32(ProcHandle)
}
func set_vmar_root(h uint32) {
VMARRoot = VMAR(h)
}
func set_namespace(ns map[string]uint32) {
if RootNSMap == nil {
RootNSMap = make(map[string]Handle)
}
for k, v := range ns {
RootNSMap[k] = Handle(v)
}
}
func (h Handle) Replace(rights Rights) (Handle, error) {
var out Handle
status := Sys_handle_replace(h, rights, &out)
if status != ErrOk {
return Handle(0), &Error{Status: status, Text: "zx.Handle.Replace"}
}
return out, nil
}
func bytesPtr(data []byte) unsafe.Pointer {
if len(data) > 0 {
return unsafe.Pointer(&data[0])
}
return nil
}
func (s *Socket) Read(data []byte, flags uint32) (int, error) {
var actual uint
status := Sys_socket_read(s.Handle().Load(), flags, bytesPtr(data), 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) (int, error) {
var actual uint
status := Sys_socket_write(s.Handle().Load(), flags, bytesPtr(data), uint(len(data)), &actual)
if status != ErrOk {
return int(actual), &Error{Status: status, Text: "zx.Socket.Write"}
}
return int(actual), nil
}
func (s *Socket) Close() error {
return s.Handle().Close()
}
func (s *Socket) SetDisposition(disposition, dispositionPeer uint32) error {
status := Sys_socket_set_disposition(s.Handle().Load(), disposition, dispositionPeer)
if status != ErrOk {
return &Error{Status: status, Text: "zx.Socket.SetDisposition"}
}
return nil
}
func NewSocket(flags uint32) (Socket, Socket, 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
}
func NewEvent(options uint32) (Event, 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) Close() error {
return e.Handle().Close()
}
func (e *Event) Duplicate(rights Rights) (Event, error) {
h := e.Handle().Load()
h, err := h.Duplicate(rights)
if err != nil {
return Event(HandleInvalid), err
}
return Event(h), nil
}
var zxwaitCloseFn = func(Handle, func(Handle) error) error { return nil }
// SetZXWaitCloseFn is used by package zxwait to avoid a circular dependency.
func SetZXWaitCloseFn(fn func(Handle, func(Handle) error) error) {
zxwaitCloseFn = fn
}
func (h *Handle) Close() error {
if handle := Handle(atomic.SwapUint32((*uint32)(h), uint32(HandleInvalid))); handle != HandleInvalid {
if err := zxwaitCloseFn(handle, closeHandle); err != nil {
return err
}
}
return nil
}
func closeHandle(handle Handle) error {
if status := Sys_handle_close(handle); status != ErrOk {
return &Error{Status: status, Text: "zx.Handle.Close"}
}
return nil
}
func (h *Handle) Duplicate(rights Rights) (Handle, error) {
var dup Handle
if status := Sys_handle_duplicate(h.Load(), 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.Load(), 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.Load(), uint32(clearMask), uint32(setMask)); status != ErrOk {
return &Error{Status: status, Text: "zx.Handle.SignalPeer"}
}
return nil
}
func (h *Handle) GetInfo(topic uint32, buffer unsafe.Pointer, bufferSize uint) error {
if status := Sys_object_get_info(h.Load(), topic, buffer, bufferSize, nil, nil); status != ErrOk {
return &Error{Status: status, Text: "zx.Handle.GetInfo"}
}
return nil
}
func (h *Handle) GetInfoHandleBasic() (InfoHandleBasic, error) {
var info InfoHandleBasic
err := h.GetInfo(ObjectInfoHandleBasic, unsafe.Pointer(&info), uint(unsafe.Sizeof(info)))
return info, err
}
func (h *Handle) GetInfoHandleValid() bool {
err := h.GetInfo(ObjectInfoHandleValid, nil, 0)
return err == nil
}
func (h *Handle) GetProperty(property uint32, data []byte) error {
var numBytes = uint(len(data))
if status := Sys_object_get_property(h.Load(), property, bytesPtr(data), 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))
if status := Sys_object_set_property(h.Load(), property, bytesPtr(data), numBytes); status != ErrOk {
return &Error{Status: status, Text: "zx.Handle.SetProperty"}
}
return nil
}
func WaitMany(items []WaitItem, timeout Time) error {
var ptr *WaitItem
if len(items) > 0 {
ptr = &items[0]
}
if status := Sys_object_wait_many(ptr, uint(len(items)), timeout); status != ErrOk {
return &Error{Status: status, Text: "zx.Handle.WaitMany"}
}
return nil
}
func (c *Channel) Close() error {
return c.Handle().Close()
}
func handlePtr(data []Handle) *Handle {
if len(data) > 0 {
return &data[0]
}
return nil
}
func handleInfoPtr(data []HandleInfo) *HandleInfo {
if len(data) > 0 {
return &data[0]
}
return nil
}
func handleDispositionPtr(data []HandleDisposition) *HandleDisposition {
if len(data) > 0 {
return &data[0]
}
return nil
}
func (c *Channel) Read(data []byte, handles []Handle, flags uint32) (numBytes, numHandles uint32, _ error) {
numBytes = uint32(len(data))
numHandles = uint32(len(handles))
if status := Sys_channel_read(c.Handle().Load(), flags, bytesPtr(data), handlePtr(handles), numBytes, numHandles, &numBytes, &numHandles); status != ErrOk {
return 0, 0, &Error{Status: status, Text: "zx.Channel.Read"}
}
return numBytes, numHandles, nil
}
func (c *Channel) ReadEtc(data []byte, handleInfos []HandleInfo, flags uint32) (numBytes, numHandles uint32, _ error) {
numBytes = uint32(len(data))
numHandles = uint32(len(handleInfos))
if status := Sys_channel_read_etc(c.Handle().Load(), flags, bytesPtr(data), handleInfoPtr(handleInfos), numBytes, numHandles, &numBytes, &numHandles); status != ErrOk {
return 0, 0, &Error{Status: status, Text: "zx.Channel.ReadEtc"}
}
return numBytes, numHandles, nil
}
func (c *Channel) Write(data []byte, handles []Handle, flags uint32) error {
if status := Sys_channel_write(c.Handle().Load(), flags, bytesPtr(data), uint32(len(data)), handlePtr(handles), uint32(len(handles))); status != ErrOk {
return &Error{Status: status, Text: "zx.Channel.Write"}
}
return nil
}
func (c *Channel) WriteEtc(data []byte, handleDispositions []HandleDisposition, flags uint32) error {
if status := Sys_channel_write_etc(c.Handle().Load(), flags, bytesPtr(data), uint32(len(data)), handleDispositionPtr(handleDispositions), uint32(len(handleDispositions))); status != ErrOk {
return &Error{Status: status, Text: "zx.Channel.WriteEtc"}
}
return nil
}
func (c *Channel) Call(flags uint32, deadline Time, wData []byte, wHandles []Handle, rData []byte, rHandles []Handle) (actualBytes, actualHandles uint32, _ error) {
args := &ChannelCallArgs{
WriteBytes: bytesPtr(wData),
WriteHandles: handlePtr(wHandles),
ReadBytes: bytesPtr(rData),
ReadHandles: handlePtr(rHandles),
WriteNumBytes: uint32(len(wData)),
WriteNumHandles: uint32(len(wHandles)),
ReadNumBytes: uint32(len(rData)),
ReadNumHandles: uint32(len(rHandles)),
}
if status := Sys_channel_call(c.Handle().Load(), flags, deadline, args, &actualBytes, &actualHandles); status != ErrOk {
return 0, 0, &Error{Status: status, Text: "zx.Channel.Call"}
}
return actualBytes, actualHandles, nil
}
func (c *Channel) CallEtc(flags uint32, deadline Time, wData []byte, wHandles []HandleDisposition, rData []byte, rHandles []HandleInfo) (actualBytes, actualHandles uint32, _ error) {
args := &ChannelCallEtcArgs{
WriteBytes: bytesPtr(wData),
WriteHandles: handleDispositionPtr(wHandles),
ReadBytes: bytesPtr(rData),
ReadHandles: handleInfoPtr(rHandles),
WriteNumBytes: uint32(len(wData)),
WriteNumHandles: uint32(len(wHandles)),
ReadNumBytes: uint32(len(rData)),
ReadNumHandles: uint32(len(rHandles)),
}
if status := Sys_channel_call_etc(c.Handle().Load(), flags, deadline, args, &actualBytes, &actualHandles); status != ErrOk {
return 0, 0, &Error{Status: status, Text: "zx.Channel.CallEtc"}
}
return actualBytes, actualHandles, nil
}
func NewChannel(flags uint32) (Channel, Channel, 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
}
func (p *Port) Close() error {
return p.Handle().Close()
}
// Queue a PortPacket, which may have a varying size.
func (p *Port) Queue(packet PortPacket) error {
if status := Sys_port_queue(p.Handle().Load(), &packet); status != ErrOk {
return &Error{Status: status, Text: "zx.Port.Queue"}
}
return nil
}
// Wait for a PortPacket, which must be as large as the largest
// possible packet that may be received.
func (p *Port) Wait(packet *PortPacket, deadline Time) error {
if status := Sys_port_wait(p.Handle().Load(), deadline, 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(p.Handle().Load(), 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, p.Handle().Load(), 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
}
func (vmo *VMO) CreateChild(options VMOChildOption, offset, size uint64) (VMO, error) {
var h Handle
if status := Sys_vmo_create_child(vmo.Handle().Load(), uint32(options), offset, size, &h); status != ErrOk {
return VMO(HandleInvalid), &Error{Status: status, Text: "zx.VMO.CreateChild"}
}
return VMO(h), nil
}
func (vmo *VMO) Read(b []byte, offset uint64) error {
if status := Sys_vmo_read(vmo.Handle().Load(), bytesPtr(b), 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(vmo.Handle().Load(), bytesPtr(b), 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(vmo.Handle().Load(), &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(vmo.Handle().Load(), 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(vmo.Handle().Load(), op, offset, size, bytesPtr(b), uint(len(b))); status != ErrOk {
return &Error{Status: status, Text: "zx.VMO.OpRange"}
}
return nil
}
func (vmo *VMO) Close() error {
return vmo.Handle().Close()
}
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
}
func (v VMAR) Destroy() error {
if status := Sys_vmar_destroy(Handle(v)); status != ErrOk {
return &Error{Status: status, Text: "zx.VMAR.Destroy"}
}
return nil
}
func (v VMAR) Map(vmarOffset uint64, vmo VMO, vmoOffset, len uint64, flags VmOption) (Vaddr, error) {
var addr Vaddr
if status := Sys_vmar_map(Handle(v), flags, uint(vmarOffset), Handle(vmo), vmoOffset, uint(len), &addr); status != ErrOk {
return 0, &Error{Status: status, Text: "zx.VMAR.Map"}
}
return addr, nil
}
func (v VMAR) Unmap(addr Vaddr, len uint64) error {
if status := Sys_vmar_unmap(Handle(v), addr, uint(len)); status != ErrOk {
return &Error{Status: status, Text: "zx.VMAR.Unmap"}
}
return nil
}
func (v VMAR) Protect(addr Vaddr, len uint64, flags VmOption) error {
if status := Sys_vmar_protect(Handle(v), flags, addr, uint(len)); status != ErrOk {
return &Error{Status: status, Text: "zx.VMAR.Protect"}
}
return nil
}
func NewVMAR(parent VMAR, offset, size uint64, flags VmOption) (VMAR, Vaddr, error) {
var childHandle Handle
var addr Vaddr
if status := Sys_vmar_allocate(Handle(parent), flags, uint(offset), uint(size), &childHandle, &addr); status != ErrOk {
return 0, 0, &Error{Status: status, Text: "zx.NewVMAR"}
}
return VMAR(childHandle), addr, nil
}
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) Write(b []byte) (int, error) {
if status := Sys_debuglog_write(Handle(l), 0, bytesPtr(b), uint(len(b))); status != ErrOk {
return 0, &Error{Status: status, Text: "zx.Log.Write"}
}
return len(b), nil
}
func (l Log) Read(b []byte) (int, error) {
if status := Sys_debuglog_read(Handle(l), 0, bytesPtr(b), uint(len(b))); status != ErrOk {
return 0, &Error{Status: status, Text: "zx.Log.Read"}
}
return len(b), nil
}
func (l *Log) Close() error {
return l.Handle().Close()
}
func RandRead(b []byte) {
Sys_cprng_draw(bytesPtr(b), uint(len(b)))
}