diff options
Diffstat (limited to 'pkg/usermem')
-rw-r--r-- | pkg/usermem/access_type.go | 126 | ||||
-rw-r--r-- | pkg/usermem/addr.go | 125 | ||||
-rw-r--r-- | pkg/usermem/addr_range.go | 76 | ||||
-rw-r--r-- | pkg/usermem/addr_range_seq_unsafe.go | 280 | ||||
-rw-r--r-- | pkg/usermem/bytes_io.go | 21 | ||||
-rw-r--r-- | pkg/usermem/bytes_io_unsafe.go | 7 | ||||
-rw-r--r-- | pkg/usermem/usermem.go | 52 | ||||
-rw-r--r-- | pkg/usermem/usermem_arm64.go | 54 | ||||
-rw-r--r-- | pkg/usermem/usermem_arm64_state_autogen.go | 5 | ||||
-rw-r--r-- | pkg/usermem/usermem_state_autogen.go | 77 | ||||
-rw-r--r-- | pkg/usermem/usermem_x86.go | 38 | ||||
-rw-r--r-- | pkg/usermem/usermem_x86_state_autogen.go | 5 |
12 files changed, 42 insertions, 824 deletions
diff --git a/pkg/usermem/access_type.go b/pkg/usermem/access_type.go deleted file mode 100644 index 2cfca29af..000000000 --- a/pkg/usermem/access_type.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package usermem - -import "golang.org/x/sys/unix" - -// AccessType specifies memory access types. This is used for -// setting mapping permissions, as well as communicating faults. -// -// +stateify savable -type AccessType struct { - // Read is read access. - Read bool - - // Write is write access. - Write bool - - // Execute is executable access. - Execute bool -} - -// String returns a pretty representation of access. This looks like the -// familiar r-x, rw-, etc. and can be relied on as such. -func (a AccessType) String() string { - bits := [3]byte{'-', '-', '-'} - if a.Read { - bits[0] = 'r' - } - if a.Write { - bits[1] = 'w' - } - if a.Execute { - bits[2] = 'x' - } - return string(bits[:]) -} - -// Any returns true iff at least one of Read, Write or Execute is true. -func (a AccessType) Any() bool { - return a.Read || a.Write || a.Execute -} - -// Prot returns the system prot (unix.PROT_READ, etc.) for this access. -func (a AccessType) Prot() int { - var prot int - if a.Read { - prot |= unix.PROT_READ - } - if a.Write { - prot |= unix.PROT_WRITE - } - if a.Execute { - prot |= unix.PROT_EXEC - } - return prot -} - -// SupersetOf returns true iff the access types in a are a superset of the -// access types in other. -func (a AccessType) SupersetOf(other AccessType) bool { - if !a.Read && other.Read { - return false - } - if !a.Write && other.Write { - return false - } - if !a.Execute && other.Execute { - return false - } - return true -} - -// Intersect returns the access types set in both a and other. -func (a AccessType) Intersect(other AccessType) AccessType { - return AccessType{ - Read: a.Read && other.Read, - Write: a.Write && other.Write, - Execute: a.Execute && other.Execute, - } -} - -// Union returns the access types set in either a or other. -func (a AccessType) Union(other AccessType) AccessType { - return AccessType{ - Read: a.Read || other.Read, - Write: a.Write || other.Write, - Execute: a.Execute || other.Execute, - } -} - -// Effective returns the set of effective access types allowed by a, even if -// some types are not explicitly allowed. -func (a AccessType) Effective() AccessType { - // In Linux, Write and Execute access generally imply Read access. See - // mm/mmap.c:protection_map. - // - // The notable exception is get_user_pages, which only checks against - // the original vma flags. That said, most user memory accesses do not - // use GUP. - if a.Write || a.Execute { - a.Read = true - } - return a -} - -// Convenient access types. -var ( - NoAccess = AccessType{} - Read = AccessType{Read: true} - Write = AccessType{Write: true} - Execute = AccessType{Execute: true} - ReadWrite = AccessType{Read: true, Write: true} - AnyAccess = AccessType{Read: true, Write: true, Execute: true} -) diff --git a/pkg/usermem/addr.go b/pkg/usermem/addr.go deleted file mode 100644 index c4100481e..000000000 --- a/pkg/usermem/addr.go +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package usermem - -import ( - "fmt" -) - -// Addr represents a generic virtual address. -// -// +stateify savable -type Addr uintptr - -// AddLength adds the given length to start and returns the result. ok is true -// iff adding the length did not overflow the range of Addr. -// -// Note: This function is usually used to get the end of an address range -// defined by its start address and length. Since the resulting end is -// exclusive, end == 0 is technically valid, and corresponds to a range that -// extends to the end of the address space, but ok will be false. This isn't -// expected to ever come up in practice. -func (v Addr) AddLength(length uint64) (end Addr, ok bool) { - end = v + Addr(length) - // The second half of the following check is needed in case uintptr is - // smaller than 64 bits. - ok = end >= v && length <= uint64(^Addr(0)) - return -} - -// RoundDown returns the address rounded down to the nearest page boundary. -func (v Addr) RoundDown() Addr { - return v & ^Addr(PageSize-1) -} - -// RoundUp returns the address rounded up to the nearest page boundary. ok is -// true iff rounding up did not wrap around. -func (v Addr) RoundUp() (addr Addr, ok bool) { - addr = Addr(v + PageSize - 1).RoundDown() - ok = addr >= v - return -} - -// MustRoundUp is equivalent to RoundUp, but panics if rounding up wraps -// around. -func (v Addr) MustRoundUp() Addr { - addr, ok := v.RoundUp() - if !ok { - panic(fmt.Sprintf("usermem.Addr(%d).RoundUp() wraps", v)) - } - return addr -} - -// HugeRoundDown returns the address rounded down to the nearest huge page -// boundary. -func (v Addr) HugeRoundDown() Addr { - return v & ^Addr(HugePageSize-1) -} - -// HugeRoundUp returns the address rounded up to the nearest huge page boundary. -// ok is true iff rounding up did not wrap around. -func (v Addr) HugeRoundUp() (addr Addr, ok bool) { - addr = Addr(v + HugePageSize - 1).HugeRoundDown() - ok = addr >= v - return -} - -// PageOffset returns the offset of v into the current page. -func (v Addr) PageOffset() uint64 { - return uint64(v & Addr(PageSize-1)) -} - -// IsPageAligned returns true if v.PageOffset() == 0. -func (v Addr) IsPageAligned() bool { - return v.PageOffset() == 0 -} - -// AddrRange is a range of Addrs. -// -// type AddrRange <generated by go_generics> - -// ToRange returns [v, v+length). -func (v Addr) ToRange(length uint64) (AddrRange, bool) { - end, ok := v.AddLength(length) - return AddrRange{v, end}, ok -} - -// IsPageAligned returns true if ar.Start.IsPageAligned() and -// ar.End.IsPageAligned(). -func (ar AddrRange) IsPageAligned() bool { - return ar.Start.IsPageAligned() && ar.End.IsPageAligned() -} - -// String implements fmt.Stringer.String. -func (ar AddrRange) String() string { - return fmt.Sprintf("[%#x, %#x)", ar.Start, ar.End) -} - -// PageRoundDown/Up are equivalent to Addr.RoundDown/Up, but without the -// potentially truncating conversion from uint64 to Addr. This is necessary -// because there is no way to define generic "PageRoundDown/Up" functions in Go. - -// PageRoundDown returns x rounded down to the nearest page boundary. -func PageRoundDown(x uint64) uint64 { - return x &^ (PageSize - 1) -} - -// PageRoundUp returns x rounded up to the nearest page boundary. -// ok is true iff rounding up did not wrap around. -func PageRoundUp(x uint64) (addr uint64, ok bool) { - addr = PageRoundDown(x + PageSize - 1) - ok = addr >= x - return -} diff --git a/pkg/usermem/addr_range.go b/pkg/usermem/addr_range.go deleted file mode 100644 index 6e030127b..000000000 --- a/pkg/usermem/addr_range.go +++ /dev/null @@ -1,76 +0,0 @@ -package usermem - -// A Range represents a contiguous range of T. -// -// +stateify savable -type AddrRange struct { - // Start is the inclusive start of the range. - Start Addr - - // End is the exclusive end of the range. - End Addr -} - -// WellFormed returns true if r.Start <= r.End. All other methods on a Range -// require that the Range is well-formed. -// -//go:nosplit -func (r AddrRange) WellFormed() bool { - return r.Start <= r.End -} - -// Length returns the length of the range. -// -//go:nosplit -func (r AddrRange) Length() Addr { - return r.End - r.Start -} - -// Contains returns true if r contains x. -// -//go:nosplit -func (r AddrRange) Contains(x Addr) bool { - return r.Start <= x && x < r.End -} - -// Overlaps returns true if r and r2 overlap. -// -//go:nosplit -func (r AddrRange) Overlaps(r2 AddrRange) bool { - return r.Start < r2.End && r2.Start < r.End -} - -// IsSupersetOf returns true if r is a superset of r2; that is, the range r2 is -// contained within r. -// -//go:nosplit -func (r AddrRange) IsSupersetOf(r2 AddrRange) bool { - return r.Start <= r2.Start && r.End >= r2.End -} - -// Intersect returns a range consisting of the intersection between r and r2. -// If r and r2 do not overlap, Intersect returns a range with unspecified -// bounds, but for which Length() == 0. -// -//go:nosplit -func (r AddrRange) Intersect(r2 AddrRange) AddrRange { - if r.Start < r2.Start { - r.Start = r2.Start - } - if r.End > r2.End { - r.End = r2.End - } - if r.End < r.Start { - r.End = r.Start - } - return r -} - -// CanSplitAt returns true if it is legal to split a segment spanning the range -// r at x; that is, splitting at x would produce two ranges, both of which have -// non-zero length. -// -//go:nosplit -func (r AddrRange) CanSplitAt(x Addr) bool { - return r.Contains(x) && r.Start < x -} diff --git a/pkg/usermem/addr_range_seq_unsafe.go b/pkg/usermem/addr_range_seq_unsafe.go deleted file mode 100644 index c9a1415a0..000000000 --- a/pkg/usermem/addr_range_seq_unsafe.go +++ /dev/null @@ -1,280 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package usermem - -import ( - "bytes" - "fmt" - "unsafe" - - "gvisor.dev/gvisor/pkg/gohacks" -) - -// An AddrRangeSeq represents a sequence of AddrRanges. -// -// AddrRangeSeqs are immutable and may be copied by value. The zero value of -// AddrRangeSeq represents an empty sequence. -// -// An AddrRangeSeq may contain AddrRanges with a length of 0. This is necessary -// since zero-length AddrRanges are significant to MM bounds checks. -type AddrRangeSeq struct { - // If length is 0, then the AddrRangeSeq represents no AddrRanges. - // Invariants: data == 0; offset == 0; limit == 0. - // - // If length is 1, then the AddrRangeSeq represents the single - // AddrRange{offset, offset+limit}. Invariants: data == 0. - // - // Otherwise, length >= 2, and the AddrRangeSeq represents the `length` - // AddrRanges in the array of AddrRanges starting at address `data`, - // starting at `offset` bytes into the first AddrRange and limited to the - // following `limit` bytes. (AddrRanges after `limit` are still iterated, - // but are truncated to a length of 0.) Invariants: data != 0; offset <= - // data[0].Length(); limit > 0; offset+limit <= the combined length of all - // AddrRanges in the array. - data unsafe.Pointer - length int - offset Addr - limit Addr -} - -// AddrRangeSeqOf returns an AddrRangeSeq representing the single AddrRange ar. -func AddrRangeSeqOf(ar AddrRange) AddrRangeSeq { - return AddrRangeSeq{ - length: 1, - offset: ar.Start, - limit: ar.Length(), - } -} - -// AddrRangeSeqFromSlice returns an AddrRangeSeq representing all AddrRanges in -// slice. -// -// Whether the returned AddrRangeSeq shares memory with slice is unspecified; -// clients should avoid mutating slices passed to AddrRangeSeqFromSlice. -// -// Preconditions: The combined length of all AddrRanges in slice <= -// math.MaxInt64. -func AddrRangeSeqFromSlice(slice []AddrRange) AddrRangeSeq { - var limit int64 - for _, ar := range slice { - len64 := int64(ar.Length()) - if len64 < 0 { - panic(fmt.Sprintf("Length of AddrRange %v overflows int64", ar)) - } - sum := limit + len64 - if sum < limit { - panic(fmt.Sprintf("Total length of AddrRanges %v overflows int64", slice)) - } - limit = sum - } - return addrRangeSeqFromSliceLimited(slice, limit) -} - -// Preconditions: -// * The combined length of all AddrRanges in slice <= limit. -// * limit >= 0. -// * If len(slice) != 0, then limit > 0. -func addrRangeSeqFromSliceLimited(slice []AddrRange, limit int64) AddrRangeSeq { - switch len(slice) { - case 0: - return AddrRangeSeq{} - case 1: - return AddrRangeSeq{ - length: 1, - offset: slice[0].Start, - limit: Addr(limit), - } - default: - return AddrRangeSeq{ - data: unsafe.Pointer(&slice[0]), - length: len(slice), - limit: Addr(limit), - } - } -} - -// IsEmpty returns true if ars.NumRanges() == 0. -// -// Note that since AddrRangeSeq may contain AddrRanges with a length of zero, -// an AddrRange representing 0 bytes (AddrRangeSeq.NumBytes() == 0) is not -// necessarily empty. -func (ars AddrRangeSeq) IsEmpty() bool { - return ars.length == 0 -} - -// NumRanges returns the number of AddrRanges in ars. -func (ars AddrRangeSeq) NumRanges() int { - return ars.length -} - -// NumBytes returns the number of bytes represented by ars. -func (ars AddrRangeSeq) NumBytes() int64 { - return int64(ars.limit) -} - -// Head returns the first AddrRange in ars. -// -// Preconditions: !ars.IsEmpty(). -func (ars AddrRangeSeq) Head() AddrRange { - if ars.length == 0 { - panic("empty AddrRangeSeq") - } - if ars.length == 1 { - return AddrRange{ars.offset, ars.offset + ars.limit} - } - ar := *(*AddrRange)(ars.data) - ar.Start += ars.offset - if ar.Length() > ars.limit { - ar.End = ar.Start + ars.limit - } - return ar -} - -// Tail returns an AddrRangeSeq consisting of all AddrRanges in ars after the -// first. -// -// Preconditions: !ars.IsEmpty(). -func (ars AddrRangeSeq) Tail() AddrRangeSeq { - if ars.length == 0 { - panic("empty AddrRangeSeq") - } - if ars.length == 1 { - return AddrRangeSeq{} - } - return ars.externalTail() -} - -// Preconditions: ars.length >= 2. -func (ars AddrRangeSeq) externalTail() AddrRangeSeq { - headLen := (*AddrRange)(ars.data).Length() - ars.offset - var tailLimit int64 - if ars.limit > headLen { - tailLimit = int64(ars.limit - headLen) - } - var extSlice []AddrRange - extSliceHdr := (*gohacks.SliceHeader)(unsafe.Pointer(&extSlice)) - extSliceHdr.Data = ars.data - extSliceHdr.Len = ars.length - extSliceHdr.Cap = ars.length - return addrRangeSeqFromSliceLimited(extSlice[1:], tailLimit) -} - -// DropFirst returns an AddrRangeSeq equivalent to ars, but with the first n -// bytes omitted. If n > ars.NumBytes(), DropFirst returns an empty -// AddrRangeSeq. -// -// If !ars.IsEmpty() and ars.Head().Length() == 0, DropFirst will always omit -// at least ars.Head(), even if n == 0. This guarantees that the basic pattern -// of: -// -// for !ars.IsEmpty() { -// n, err = doIOWith(ars.Head()) -// if err != nil { -// return err -// } -// ars = ars.DropFirst(n) -// } -// -// works even in the presence of zero-length AddrRanges. -// -// Preconditions: n >= 0. -func (ars AddrRangeSeq) DropFirst(n int) AddrRangeSeq { - if n < 0 { - panic(fmt.Sprintf("invalid n: %d", n)) - } - return ars.DropFirst64(int64(n)) -} - -// DropFirst64 is equivalent to DropFirst but takes an int64. -func (ars AddrRangeSeq) DropFirst64(n int64) AddrRangeSeq { - if n < 0 { - panic(fmt.Sprintf("invalid n: %d", n)) - } - if Addr(n) > ars.limit { - return AddrRangeSeq{} - } - // Handle initial empty AddrRange. - switch ars.length { - case 0: - return AddrRangeSeq{} - case 1: - if ars.limit == 0 { - return AddrRangeSeq{} - } - default: - if rawHeadLen := (*AddrRange)(ars.data).Length(); ars.offset == rawHeadLen { - ars = ars.externalTail() - } - } - for n != 0 { - // Calling ars.Head() here is surprisingly expensive, so inline getting - // the head's length. - var headLen Addr - if ars.length == 1 { - headLen = ars.limit - } else { - headLen = (*AddrRange)(ars.data).Length() - ars.offset - } - if Addr(n) < headLen { - // Dropping ends partway through the head AddrRange. - ars.offset += Addr(n) - ars.limit -= Addr(n) - return ars - } - n -= int64(headLen) - ars = ars.Tail() - } - return ars -} - -// TakeFirst returns an AddrRangeSeq equivalent to ars, but iterating at most n -// bytes. TakeFirst never removes AddrRanges from ars; AddrRanges beyond the -// first n bytes are reduced to a length of zero, but will still be iterated. -// -// Preconditions: n >= 0. -func (ars AddrRangeSeq) TakeFirst(n int) AddrRangeSeq { - if n < 0 { - panic(fmt.Sprintf("invalid n: %d", n)) - } - return ars.TakeFirst64(int64(n)) -} - -// TakeFirst64 is equivalent to TakeFirst but takes an int64. -func (ars AddrRangeSeq) TakeFirst64(n int64) AddrRangeSeq { - if n < 0 { - panic(fmt.Sprintf("invalid n: %d", n)) - } - if ars.limit > Addr(n) { - ars.limit = Addr(n) - } - return ars -} - -// String implements fmt.Stringer.String. -func (ars AddrRangeSeq) String() string { - // This is deliberately chosen to be the same as fmt's automatic stringer - // for []AddrRange. - var buf bytes.Buffer - buf.WriteByte('[') - var sep string - for !ars.IsEmpty() { - buf.WriteString(sep) - sep = " " - buf.WriteString(ars.Head().String()) - ars = ars.Tail() - } - buf.WriteByte(']') - return buf.String() -} diff --git a/pkg/usermem/bytes_io.go b/pkg/usermem/bytes_io.go index e177d30eb..3da3c0294 100644 --- a/pkg/usermem/bytes_io.go +++ b/pkg/usermem/bytes_io.go @@ -16,6 +16,7 @@ package usermem import ( "gvisor.dev/gvisor/pkg/context" + "gvisor.dev/gvisor/pkg/hostarch" "gvisor.dev/gvisor/pkg/safemem" "gvisor.dev/gvisor/pkg/syserror" ) @@ -30,7 +31,7 @@ type BytesIO struct { } // CopyOut implements IO.CopyOut. -func (b *BytesIO) CopyOut(ctx context.Context, addr Addr, src []byte, opts IOOpts) (int, error) { +func (b *BytesIO) CopyOut(ctx context.Context, addr hostarch.Addr, src []byte, opts IOOpts) (int, error) { rngN, rngErr := b.rangeCheck(addr, len(src)) if rngN == 0 { return 0, rngErr @@ -39,7 +40,7 @@ func (b *BytesIO) CopyOut(ctx context.Context, addr Addr, src []byte, opts IOOpt } // CopyIn implements IO.CopyIn. -func (b *BytesIO) CopyIn(ctx context.Context, addr Addr, dst []byte, opts IOOpts) (int, error) { +func (b *BytesIO) CopyIn(ctx context.Context, addr hostarch.Addr, dst []byte, opts IOOpts) (int, error) { rngN, rngErr := b.rangeCheck(addr, len(dst)) if rngN == 0 { return 0, rngErr @@ -48,7 +49,7 @@ func (b *BytesIO) CopyIn(ctx context.Context, addr Addr, dst []byte, opts IOOpts } // ZeroOut implements IO.ZeroOut. -func (b *BytesIO) ZeroOut(ctx context.Context, addr Addr, toZero int64, opts IOOpts) (int64, error) { +func (b *BytesIO) ZeroOut(ctx context.Context, addr hostarch.Addr, toZero int64, opts IOOpts) (int64, error) { if toZero > int64(maxInt) { return 0, syserror.EINVAL } @@ -64,7 +65,7 @@ func (b *BytesIO) ZeroOut(ctx context.Context, addr Addr, toZero int64, opts IOO } // CopyOutFrom implements IO.CopyOutFrom. -func (b *BytesIO) CopyOutFrom(ctx context.Context, ars AddrRangeSeq, src safemem.Reader, opts IOOpts) (int64, error) { +func (b *BytesIO) CopyOutFrom(ctx context.Context, ars hostarch.AddrRangeSeq, src safemem.Reader, opts IOOpts) (int64, error) { dsts, rngErr := b.blocksFromAddrRanges(ars) n, err := src.ReadToBlocks(dsts) if err != nil { @@ -74,7 +75,7 @@ func (b *BytesIO) CopyOutFrom(ctx context.Context, ars AddrRangeSeq, src safemem } // CopyInTo implements IO.CopyInTo. -func (b *BytesIO) CopyInTo(ctx context.Context, ars AddrRangeSeq, dst safemem.Writer, opts IOOpts) (int64, error) { +func (b *BytesIO) CopyInTo(ctx context.Context, ars hostarch.AddrRangeSeq, dst safemem.Writer, opts IOOpts) (int64, error) { srcs, rngErr := b.blocksFromAddrRanges(ars) n, err := dst.WriteFromBlocks(srcs) if err != nil { @@ -83,14 +84,14 @@ func (b *BytesIO) CopyInTo(ctx context.Context, ars AddrRangeSeq, dst safemem.Wr return int64(n), rngErr } -func (b *BytesIO) rangeCheck(addr Addr, length int) (int, error) { +func (b *BytesIO) rangeCheck(addr hostarch.Addr, length int) (int, error) { if length == 0 { return 0, nil } if length < 0 { return 0, syserror.EINVAL } - max := Addr(len(b.Bytes)) + max := hostarch.Addr(len(b.Bytes)) if addr >= max { return 0, syserror.EFAULT } @@ -101,7 +102,7 @@ func (b *BytesIO) rangeCheck(addr Addr, length int) (int, error) { return length, nil } -func (b *BytesIO) blocksFromAddrRanges(ars AddrRangeSeq) (safemem.BlockSeq, error) { +func (b *BytesIO) blocksFromAddrRanges(ars hostarch.AddrRangeSeq) (safemem.BlockSeq, error) { switch ars.NumRanges() { case 0: return safemem.BlockSeq{}, nil @@ -124,7 +125,7 @@ func (b *BytesIO) blocksFromAddrRanges(ars AddrRangeSeq) (safemem.BlockSeq, erro } } -func (b *BytesIO) blockFromAddrRange(ar AddrRange) (safemem.Block, error) { +func (b *BytesIO) blockFromAddrRange(ar hostarch.AddrRange) (safemem.Block, error) { n, err := b.rangeCheck(ar.Start, int(ar.Length())) if n == 0 { return safemem.Block{}, err @@ -136,6 +137,6 @@ func (b *BytesIO) blockFromAddrRange(ar AddrRange) (safemem.Block, error) { func BytesIOSequence(buf []byte) IOSequence { return IOSequence{ IO: &BytesIO{buf}, - Addrs: AddrRangeSeqOf(AddrRange{0, Addr(len(buf))}), + Addrs: hostarch.AddrRangeSeqOf(hostarch.AddrRange{0, hostarch.Addr(len(buf))}), } } diff --git a/pkg/usermem/bytes_io_unsafe.go b/pkg/usermem/bytes_io_unsafe.go index 20de5037d..dcd5c81d1 100644 --- a/pkg/usermem/bytes_io_unsafe.go +++ b/pkg/usermem/bytes_io_unsafe.go @@ -20,10 +20,11 @@ import ( "gvisor.dev/gvisor/pkg/atomicbitops" "gvisor.dev/gvisor/pkg/context" + "gvisor.dev/gvisor/pkg/hostarch" ) // SwapUint32 implements IO.SwapUint32. -func (b *BytesIO) SwapUint32(ctx context.Context, addr Addr, new uint32, opts IOOpts) (uint32, error) { +func (b *BytesIO) SwapUint32(ctx context.Context, addr hostarch.Addr, new uint32, opts IOOpts) (uint32, error) { if _, rngErr := b.rangeCheck(addr, 4); rngErr != nil { return 0, rngErr } @@ -31,7 +32,7 @@ func (b *BytesIO) SwapUint32(ctx context.Context, addr Addr, new uint32, opts IO } // CompareAndSwapUint32 implements IO.CompareAndSwapUint32. -func (b *BytesIO) CompareAndSwapUint32(ctx context.Context, addr Addr, old, new uint32, opts IOOpts) (uint32, error) { +func (b *BytesIO) CompareAndSwapUint32(ctx context.Context, addr hostarch.Addr, old, new uint32, opts IOOpts) (uint32, error) { if _, rngErr := b.rangeCheck(addr, 4); rngErr != nil { return 0, rngErr } @@ -39,7 +40,7 @@ func (b *BytesIO) CompareAndSwapUint32(ctx context.Context, addr Addr, old, new } // LoadUint32 implements IO.LoadUint32. -func (b *BytesIO) LoadUint32(ctx context.Context, addr Addr, opts IOOpts) (uint32, error) { +func (b *BytesIO) LoadUint32(ctx context.Context, addr hostarch.Addr, opts IOOpts) (uint32, error) { if _, err := b.rangeCheck(addr, 4); err != nil { return 0, err } diff --git a/pkg/usermem/usermem.go b/pkg/usermem/usermem.go index dc2571154..0d6d25e50 100644 --- a/pkg/usermem/usermem.go +++ b/pkg/usermem/usermem.go @@ -25,6 +25,8 @@ import ( "gvisor.dev/gvisor/pkg/gohacks" "gvisor.dev/gvisor/pkg/safemem" "gvisor.dev/gvisor/pkg/syserror" + + "gvisor.dev/gvisor/pkg/hostarch" ) // IO provides access to the contents of a virtual memory space. @@ -37,7 +39,7 @@ type IO interface { // any following locks in the lock order. // // Postconditions: CopyOut does not retain src. - CopyOut(ctx context.Context, addr Addr, src []byte, opts IOOpts) (int, error) + CopyOut(ctx context.Context, addr hostarch.Addr, src []byte, opts IOOpts) (int, error) // CopyIn copies len(dst) bytes from the memory mapped at addr to dst. // It returns the number of bytes copied. If the number of bytes copied is @@ -47,7 +49,7 @@ type IO interface { // any following locks in the lock order. // // Postconditions: CopyIn does not retain dst. - CopyIn(ctx context.Context, addr Addr, dst []byte, opts IOOpts) (int, error) + CopyIn(ctx context.Context, addr hostarch.Addr, dst []byte, opts IOOpts) (int, error) // ZeroOut sets toZero bytes to 0, starting at addr. It returns the number // of bytes zeroed. If the number of bytes zeroed is < toZero, it returns a @@ -57,7 +59,7 @@ type IO interface { // * The caller must not hold mm.MemoryManager.mappingMu or any // following locks in the lock order. // * toZero >= 0. - ZeroOut(ctx context.Context, addr Addr, toZero int64, opts IOOpts) (int64, error) + ZeroOut(ctx context.Context, addr hostarch.Addr, toZero int64, opts IOOpts) (int64, error) // CopyOutFrom copies ars.NumBytes() bytes from src to the memory mapped at // ars. It returns the number of bytes copied, which may be less than the @@ -72,7 +74,7 @@ type IO interface { // following locks in the lock order. // * src.ReadToBlocks must not block on mm.MemoryManager.activeMu or // any preceding locks in the lock order. - CopyOutFrom(ctx context.Context, ars AddrRangeSeq, src safemem.Reader, opts IOOpts) (int64, error) + CopyOutFrom(ctx context.Context, ars hostarch.AddrRangeSeq, src safemem.Reader, opts IOOpts) (int64, error) // CopyInTo copies ars.NumBytes() bytes from the memory mapped at ars to // dst. It returns the number of bytes copied. CopyInTo may return a @@ -86,7 +88,7 @@ type IO interface { // following locks in the lock order. // * dst.WriteFromBlocks must not block on mm.MemoryManager.activeMu or // any preceding locks in the lock order. - CopyInTo(ctx context.Context, ars AddrRangeSeq, dst safemem.Writer, opts IOOpts) (int64, error) + CopyInTo(ctx context.Context, ars hostarch.AddrRangeSeq, dst safemem.Writer, opts IOOpts) (int64, error) // TODO(jamieliu): The requirement that CopyOutFrom/CopyInTo call src/dst // at most once, which is unnecessary in most cases, forces implementations @@ -101,7 +103,7 @@ type IO interface { // * The caller must not hold mm.MemoryManager.mappingMu or any // following locks in the lock order. // * addr must be aligned to a 4-byte boundary. - SwapUint32(ctx context.Context, addr Addr, new uint32, opts IOOpts) (uint32, error) + SwapUint32(ctx context.Context, addr hostarch.Addr, new uint32, opts IOOpts) (uint32, error) // CompareAndSwapUint32 atomically compares the uint32 value at addr to // old; if they are equal, the value in memory is replaced by new. In @@ -111,7 +113,7 @@ type IO interface { // * The caller must not hold mm.MemoryManager.mappingMu or any // following locks in the lock order. // * addr must be aligned to a 4-byte boundary. - CompareAndSwapUint32(ctx context.Context, addr Addr, old, new uint32, opts IOOpts) (uint32, error) + CompareAndSwapUint32(ctx context.Context, addr hostarch.Addr, old, new uint32, opts IOOpts) (uint32, error) // LoadUint32 atomically loads the uint32 value at addr and returns it. // @@ -119,7 +121,7 @@ type IO interface { // * The caller must not hold mm.MemoryManager.mappingMu or any // following locks in the lock order. // * addr must be aligned to a 4-byte boundary. - LoadUint32(ctx context.Context, addr Addr, opts IOOpts) (uint32, error) + LoadUint32(ctx context.Context, addr hostarch.Addr, opts IOOpts) (uint32, error) } // IOOpts contains options applicable to all IO methods. @@ -142,7 +144,7 @@ type IOOpts struct { type IOReadWriter struct { Ctx context.Context IO IO - Addr Addr + Addr hostarch.Addr Opts IOOpts } @@ -159,7 +161,7 @@ func (rw *IOReadWriter) Read(dst []byte) (int, error) { rw.Addr = end } else { // Disallow wraparound. - rw.Addr = ^Addr(0) + rw.Addr = ^hostarch.Addr(0) if err != nil { err = syserror.EFAULT } @@ -175,7 +177,7 @@ func (rw *IOReadWriter) Write(src []byte) (int, error) { rw.Addr = end } else { // Disallow wraparound. - rw.Addr = ^Addr(0) + rw.Addr = ^hostarch.Addr(0) if err != nil { err = syserror.EFAULT } @@ -197,7 +199,7 @@ const ( // // Preconditions: Same as IO.CopyFromUser, plus: // * maxlen >= 0. -func CopyStringIn(ctx context.Context, uio IO, addr Addr, maxlen int, opts IOOpts) (string, error) { +func CopyStringIn(ctx context.Context, uio IO, addr hostarch.Addr, maxlen int, opts IOOpts) (string, error) { initLen := maxlen if initLen > copyStringMaxInitBufLen { initLen = copyStringMaxInitBufLen @@ -251,12 +253,12 @@ func CopyStringIn(ctx context.Context, uio IO, addr Addr, maxlen int, opts IOOpt // the maximum, it returns a non-nil error explaining why. // // Preconditions: Same as IO.CopyOut. -func CopyOutVec(ctx context.Context, uio IO, ars AddrRangeSeq, src []byte, opts IOOpts) (int, error) { +func CopyOutVec(ctx context.Context, uio IO, ars hostarch.AddrRangeSeq, src []byte, opts IOOpts) (int, error) { var done int for !ars.IsEmpty() && done < len(src) { ar := ars.Head() cplen := len(src) - done - if Addr(cplen) >= ar.Length() { + if hostarch.Addr(cplen) >= ar.Length() { cplen = int(ar.Length()) } n, err := uio.CopyOut(ctx, ar.Start, src[done:done+cplen], opts) @@ -275,12 +277,12 @@ func CopyOutVec(ctx context.Context, uio IO, ars AddrRangeSeq, src []byte, opts // maximum, it returns a non-nil error explaining why. // // Preconditions: Same as IO.CopyIn. -func CopyInVec(ctx context.Context, uio IO, ars AddrRangeSeq, dst []byte, opts IOOpts) (int, error) { +func CopyInVec(ctx context.Context, uio IO, ars hostarch.AddrRangeSeq, dst []byte, opts IOOpts) (int, error) { var done int for !ars.IsEmpty() && done < len(dst) { ar := ars.Head() cplen := len(dst) - done - if Addr(cplen) >= ar.Length() { + if hostarch.Addr(cplen) >= ar.Length() { cplen = int(ar.Length()) } n, err := uio.CopyIn(ctx, ar.Start, dst[done:done+cplen], opts) @@ -299,12 +301,12 @@ func CopyInVec(ctx context.Context, uio IO, ars AddrRangeSeq, dst []byte, opts I // maximum, it returns a non-nil error explaining why. // // Preconditions: Same as IO.ZeroOut. -func ZeroOutVec(ctx context.Context, uio IO, ars AddrRangeSeq, toZero int64, opts IOOpts) (int64, error) { +func ZeroOutVec(ctx context.Context, uio IO, ars hostarch.AddrRangeSeq, toZero int64, opts IOOpts) (int64, error) { var done int64 for !ars.IsEmpty() && done < toZero { ar := ars.Head() cplen := toZero - done - if Addr(cplen) >= ar.Length() { + if hostarch.Addr(cplen) >= ar.Length() { cplen = int64(ar.Length()) } n, err := uio.ZeroOut(ctx, ar.Start, cplen, opts) @@ -352,7 +354,7 @@ func isASCIIWhitespace(b byte) bool { // - CopyInt32StringsInVec returns EINVAL if ars.NumBytes() == 0. // // Preconditions: Same as CopyInVec. -func CopyInt32StringsInVec(ctx context.Context, uio IO, ars AddrRangeSeq, dsts []int32, opts IOOpts) (int64, error) { +func CopyInt32StringsInVec(ctx context.Context, uio IO, ars hostarch.AddrRangeSeq, dsts []int32, opts IOOpts) (int64, error) { if len(dsts) == 0 { return 0, nil } @@ -403,7 +405,7 @@ func CopyInt32StringsInVec(ctx context.Context, uio IO, ars AddrRangeSeq, dsts [ // CopyInt32StringInVec is equivalent to CopyInt32StringsInVec, but copies at // most one int32. -func CopyInt32StringInVec(ctx context.Context, uio IO, ars AddrRangeSeq, dst *int32, opts IOOpts) (int64, error) { +func CopyInt32StringInVec(ctx context.Context, uio IO, ars hostarch.AddrRangeSeq, dst *int32, opts IOOpts) (int64, error) { dsts := [1]int32{*dst} n, err := CopyInt32StringsInVec(ctx, uio, ars, dsts[:], opts) *dst = dsts[0] @@ -413,7 +415,7 @@ func CopyInt32StringInVec(ctx context.Context, uio IO, ars AddrRangeSeq, dst *in // IOSequence holds arguments to IO methods. type IOSequence struct { IO IO - Addrs AddrRangeSeq + Addrs hostarch.AddrRangeSeq Opts IOOpts } @@ -444,28 +446,28 @@ func (s IOSequence) NumBytes() int64 { // DropFirst returns a copy of s with s.Addrs.DropFirst(n). // -// Preconditions: Same as AddrRangeSeq.DropFirst. +// Preconditions: Same as hostarch.AddrRangeSeq.DropFirst. func (s IOSequence) DropFirst(n int) IOSequence { return IOSequence{s.IO, s.Addrs.DropFirst(n), s.Opts} } // DropFirst64 returns a copy of s with s.Addrs.DropFirst64(n). // -// Preconditions: Same as AddrRangeSeq.DropFirst64. +// Preconditions: Same as hostarch.AddrRangeSeq.DropFirst64. func (s IOSequence) DropFirst64(n int64) IOSequence { return IOSequence{s.IO, s.Addrs.DropFirst64(n), s.Opts} } // TakeFirst returns a copy of s with s.Addrs.TakeFirst(n). // -// Preconditions: Same as AddrRangeSeq.TakeFirst. +// Preconditions: Same as hostarch.AddrRangeSeq.TakeFirst. func (s IOSequence) TakeFirst(n int) IOSequence { return IOSequence{s.IO, s.Addrs.TakeFirst(n), s.Opts} } // TakeFirst64 returns a copy of s with s.Addrs.TakeFirst64(n). // -// Preconditions: Same as AddrRangeSeq.TakeFirst64. +// Preconditions: Same as hostarch.AddrRangeSeq.TakeFirst64. func (s IOSequence) TakeFirst64(n int64) IOSequence { return IOSequence{s.IO, s.Addrs.TakeFirst64(n), s.Opts} } diff --git a/pkg/usermem/usermem_arm64.go b/pkg/usermem/usermem_arm64.go deleted file mode 100644 index 7e7529585..000000000 --- a/pkg/usermem/usermem_arm64.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2019 The gVisor Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build arm64 - -package usermem - -import ( - "encoding/binary" - - "golang.org/x/sys/unix" -) - -const ( - // PageSize is the system page size. - // arm64 support 4K/16K/64K page size, - // which can be get by unix.Getpagesize(). - // Currently, only 4K page size is supported. - PageSize = 1 << PageShift - - // HugePageSize is the system huge page size. - HugePageSize = 1 << HugePageShift - - // PageShift is the binary log of the system page size. - PageShift = 12 - - // HugePageShift is the binary log of the system huge page size. - // Should be calculated by "PageShift + (PageShift - 3)" - // when multiple page size support is ready. - HugePageShift = 21 -) - -var ( - // ByteOrder is the native byte order (little endian). - ByteOrder = binary.LittleEndian -) - -func init() { - // Make sure the page size is 4K on arm64 platform. - if size := unix.Getpagesize(); size != PageSize { - panic("Only 4K page size is supported on arm64!") - } -} diff --git a/pkg/usermem/usermem_arm64_state_autogen.go b/pkg/usermem/usermem_arm64_state_autogen.go deleted file mode 100644 index d7c365e5d..000000000 --- a/pkg/usermem/usermem_arm64_state_autogen.go +++ /dev/null @@ -1,5 +0,0 @@ -// automatically generated by stateify. - -// +build arm64 - -package usermem diff --git a/pkg/usermem/usermem_state_autogen.go b/pkg/usermem/usermem_state_autogen.go index 48714d65c..62f8af4c9 100644 --- a/pkg/usermem/usermem_state_autogen.go +++ b/pkg/usermem/usermem_state_autogen.go @@ -1,80 +1,3 @@ // automatically generated by stateify. package usermem - -import ( - "gvisor.dev/gvisor/pkg/state" -) - -func (a *AccessType) StateTypeName() string { - return "pkg/usermem.AccessType" -} - -func (a *AccessType) StateFields() []string { - return []string{ - "Read", - "Write", - "Execute", - } -} - -func (a *AccessType) beforeSave() {} - -// +checklocksignore -func (a *AccessType) StateSave(stateSinkObject state.Sink) { - a.beforeSave() - stateSinkObject.Save(0, &a.Read) - stateSinkObject.Save(1, &a.Write) - stateSinkObject.Save(2, &a.Execute) -} - -func (a *AccessType) afterLoad() {} - -// +checklocksignore -func (a *AccessType) StateLoad(stateSourceObject state.Source) { - stateSourceObject.Load(0, &a.Read) - stateSourceObject.Load(1, &a.Write) - stateSourceObject.Load(2, &a.Execute) -} - -func (v *Addr) StateTypeName() string { - return "pkg/usermem.Addr" -} - -func (v *Addr) StateFields() []string { - return nil -} - -func (r *AddrRange) StateTypeName() string { - return "pkg/usermem.AddrRange" -} - -func (r *AddrRange) StateFields() []string { - return []string{ - "Start", - "End", - } -} - -func (r *AddrRange) beforeSave() {} - -// +checklocksignore -func (r *AddrRange) StateSave(stateSinkObject state.Sink) { - r.beforeSave() - stateSinkObject.Save(0, &r.Start) - stateSinkObject.Save(1, &r.End) -} - -func (r *AddrRange) afterLoad() {} - -// +checklocksignore -func (r *AddrRange) StateLoad(stateSourceObject state.Source) { - stateSourceObject.Load(0, &r.Start) - stateSourceObject.Load(1, &r.End) -} - -func init() { - state.Register((*AccessType)(nil)) - state.Register((*Addr)(nil)) - state.Register((*AddrRange)(nil)) -} diff --git a/pkg/usermem/usermem_x86.go b/pkg/usermem/usermem_x86.go deleted file mode 100644 index d96f829fb..000000000 --- a/pkg/usermem/usermem_x86.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build amd64 386 - -package usermem - -import "encoding/binary" - -const ( - // PageSize is the system page size. - PageSize = 1 << PageShift - - // HugePageSize is the system huge page size. - HugePageSize = 1 << HugePageShift - - // PageShift is the binary log of the system page size. - PageShift = 12 - - // HugePageShift is the binary log of the system huge page size. - HugePageShift = 21 -) - -var ( - // ByteOrder is the native byte order (little endian). - ByteOrder = binary.LittleEndian -) diff --git a/pkg/usermem/usermem_x86_state_autogen.go b/pkg/usermem/usermem_x86_state_autogen.go deleted file mode 100644 index cca386593..000000000 --- a/pkg/usermem/usermem_x86_state_autogen.go +++ /dev/null @@ -1,5 +0,0 @@ -// automatically generated by stateify. - -// +build amd64 386 - -package usermem |