summaryrefslogtreecommitdiff
path: root/libviengoos/viengoos/addr.h
blob: 8fa59be832592eff698b823b0bbfcb022e6865db (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/* addr.h - Address definitions.
   Copyright (C) 2007, 2008 Free Software Foundation, Inc.
   Written by Neal H. Walfield <neal@gnu.org>.

   This file is part of the GNU Hurd.

   The GNU Hurd is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU Hurd is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA.  */

#ifndef _VIENGOOS_ADDR_H
#define _VIENGOOS_ADDR_H 1

#include <hurd/types.h>
#include <viengoos/math.h>
#include <stdint.h>

#include <assert.h>

/* Addresses are 64-bits wide and translate up to 63 bits.  They are
   composed of a depth and a prefix that is depth bits wide.

   The 64-bit field is packed as follows: the upper bits are encoded
   in binary and represent the prefix, these are followed by a single
   bit that is on, which is followed by a number encoded in unary.
   The value of the unary number is 63 - depth.  This allows easy
   calculation of the depth and extraction of the prefix.  Thus,
   given:

      xxxxx100

   The unary value is 2 yielding a depth of 63 - 2 = 61.  These bits
   are encoded in the upper DEPTH bits of the field.

   Leaves thus have a 1 in the least significant bit and nodes a
   0.  */
struct addr
{
  uint64_t raw;
};
#define ADDR_BITS 63
/* Client-side capability handle.  */
typedef struct addr addr_t;

#define ADDR_FMT "%llx/%d"
#define ADDR_PRINTF(addr_) addr_prefix ((addr_)), addr_depth ((addr_))

/* Create an address given a prefix and a depth.  */
#define ADDR(prefix_, depth_) \
  ({ \
    uint64_t p_ = (prefix_); \
    uint64_t d_ = (depth_); \
    assert (0 <= d_ && d_ <= ADDR_BITS); \
    assert ((p_ & ((1 << (ADDR_BITS - d_)) - 1)) == 0); \
    assert (p_ < (1ULL << ADDR_BITS)); \
    (struct addr) { (p_ << 1ULL) | (1ULL << (ADDR_BITS - d_)) }; \
  })

/* Create an address given a prefix and a depth.  Appropriate for use
   as an initializer.  */
#define ADDR_INIT(prefix_, depth_) \
  { .raw = ((((prefix_) << 1) | 1) << (ADDR_BITS - (depth_))) }

#define ADDR_VOID ((struct addr) { 0ULL })
#define ADDR_EQ(a, b) (a.raw == b.raw)
#define ADDR_IS_VOID(a) (ADDR_EQ (a, ADDR_VOID))

/* Return ADDR_'s depth.  */
static inline int
addr_depth (addr_t addr)
{
  return ADDR_BITS - (vg_lsb64 (addr.raw) - 1);
}

/* Return ADDR's prefix.  */
static inline uint64_t
addr_prefix (addr_t addr)
{
  /* (Clear the boundary bit and shift right 1.)  */
  return (addr.raw & ~(1ULL << (ADDR_BITS - addr_depth (addr)))) >> 1;
}

/* Extend the address ADDR by concatenating the lowest DEPTH bits of
   PREFIX.  */
#if 0
static inline addr_t
addr_extend (addr_t addr, uint64_t prefix, int depth)
{
  assertx (depth >= 0, "depth: %d", depth);
  assertx (addr_depth (addr) + depth <= ADDR_BITS,
	   "addr: " ADDR_FMT "; depth: %d", ADDR_PRINTF (addr), depth);
  assertx (prefix < (1ULL << depth),
	   "prefix: %llx; depth: %lld", prefix, 1ULL << depth);
  return ADDR (addr_prefix (addr)
	       | (prefix << (ADDR_BITS - addr_depth (addr) - depth)),
	       addr_depth (addr) + depth);
}
#else
#define addr_extend(addr_, prefix_, depth_)				\
  ({									\
    addr_t a__ = (addr_);						\
    uint64_t p__ = (prefix_);					\
    int d__ = (depth_);							\
    assertx (d__ >= 0, "depth: %d", d__);				\
    assertx (addr_depth ((a__)) + (d__) <= ADDR_BITS,			\
	     "addr: " ADDR_FMT "; depth: %d", ADDR_PRINTF (a__), d__);	\
    assertx (p__ < (1ULL << d__),					\
	     "prefix: %llx; depth: %lld", p__, 1ULL << d__);		\
    ADDR (addr_prefix ((a__))						\
	  | ((p__) << (ADDR_BITS - addr_depth ((a__)) - (d__))),	\
	  addr_depth ((a__)) + (d__));					\
  })
#endif

/* Decrease the depth of ADDR by DEPTH.  */
static inline addr_t
addr_chop (addr_t addr, int depth)
{
  int d = addr_depth (addr) - depth;
  assert (d >= 0);

  return ADDR (addr_prefix (addr) & ~((1ULL << (ADDR_BITS - d)) - 1), d);
}

/* Return the last WIDTH bits of address's ADDR prefix.  */
static inline uint64_t
addr_extract (addr_t addr, int width)
{
  assert (width <= addr_depth (addr));

  return (addr_prefix (addr) >> (ADDR_BITS - addr_depth (addr)))
    & ((1ULL << width) - 1);
}

/* Convert an address to a pointer.  The address must name an object
   mapped in the machine data instruction accessible part of the
   address space.  */
#define ADDR_TO_PTR(addr_) \
  ({ \
    assert (addr_prefix ((addr_)) < ((uintptr_t) -1)); \
    assert (addr_depth ((addr_)) == ADDR_BITS); \
    (void *) (uintptr_t) addr_prefix ((addr_)); \
  })

/* Convert a pointer to an address.  */
#define PTR_TO_ADDR(ptr_) \
  (ADDR ((uintptr_t) (ptr_), ADDR_BITS))

/* Return the address of the page that would contain pointer PTR_.  */
#define PTR_TO_PAGE(ptr_) \
  addr_chop (ADDR ((uintptr_t) (ptr_), ADDR_BITS), PAGESIZE_LOG2)

static inline addr_t
addr_add (addr_t addr, uint64_t count)
{
  int w = ADDR_BITS - addr_depth (addr);

  return ADDR (addr_prefix (addr) + (count << w),
	       addr_depth (addr));
}

static inline addr_t
addr_sub (addr_t addr, uint64_t count)
{
  return addr_add (addr, - count);
}

#endif