| // 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 |
| } |
| |
| const ( |
| PortWaitAsyncOnce = iota |
| PortWaitAsyncTimestamp |
| ) |
| |
| const ( |
| PortPacketTypeUser = iota |
| PortPacketTypeSignalOne |
| PortPacketTypeSignalRepeating |
| ) |
| |
| const ( |
| PacketHeaderSize = uint(unsafe.Sizeof(PacketHeader{})) |
| PacketMaxSize = uint(unsafe.Sizeof(Packet{})) |
| ) |
| |
| type PortPacket interface { |
| Header() *PacketHeader |
| } |
| |
| type PacketHeader struct { |
| Key uint64 |
| Type uint32 |
| Status Status |
| } |
| |
| // Packet describes packets read from (*Port).Wait. |
| type Packet struct { |
| Hdr PacketHeader |
| Bytes [32]uint8 |
| } |
| |
| func (p *Packet) Header() *PacketHeader { |
| return &p.Hdr |
| } |
| |
| func (p *Packet) Signal() *PacketSignal { |
| return (*PacketSignal)(unsafe.Pointer(p)) |
| } |
| |
| // PacketSignal describes packets of type PortPacketTypeSignal. |
| type PacketSignal struct { |
| Hdr PacketHeader |
| Trigger Signals |
| Observed Signals |
| Count uint64 |
| Timestamp uint64 |
| Reserved1 uint64 |
| } |
| |
| func (s *PacketSignal) Header() *PacketHeader { |
| return &s.Hdr |
| } |
| |
| 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(), (*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(p.Handle().Load(), 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(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 VMFlag) (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 VMFlag) 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 VMFlag) (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))) |
| } |