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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
|
<table class="head">
<tr>
<td class="head-ltitle">PROTO(4)</td>
<td class="head-vol">Device Drivers Manual</td>
<td class="head-rtitle">PROTO(4)</td>
</tr>
</table>
<div class="manual-text">
<section class="Sh">
<h1 class="Sh" id="NAME"><a class="permalink" href="#NAME">NAME</a></h1>
<p class="Pp"><code class="Nm">proto</code> — <span class="Nd">Generic
prototyping and diagnostics driver</span></p>
</section>
<section class="Sh">
<h1 class="Sh" id="SYNOPSIS"><a class="permalink" href="#SYNOPSIS">SYNOPSIS</a></h1>
<p class="Pp">To compile this driver into the kernel, place the following line
in your kernel configuration file:</p>
<div class="Bd Pp Bd-indent"><code class="Cd">device proto</code></div>
<p class="Pp">Alternatively, to load the driver as a module at boot time, place
the following line in <a class="Xr">loader.conf(5)</a>:</p>
<div class="Bd Pp Bd-indent Li">
<pre>proto_load="YES"</pre>
</div>
<p class="Pp">To have the driver attach to a device instead of its regular
driver, mention it in the list of devices assigned to the following loader
variable:</p>
<div class="Bd Pp Bd-indent">hw.proto.attach="desc[,desc]"</div>
</section>
<section class="Sh">
<h1 class="Sh" id="DESCRIPTION"><a class="permalink" href="#DESCRIPTION">DESCRIPTION</a></h1>
<p class="Pp">The <code class="Nm">proto</code> device driver attaches to PCI or
ISA devices when no other device drivers are present for those devices and
it creates device special files for all resources associated with the
device. The driver itself has no knowledge of the device it attaches to.
Programs can open these device special files and perform register-level
reads and writes. As such, the <code class="Nm">proto</code> device driver
is nothing but a conduit or gateway between user space programs and the
hardware device.</p>
<p class="Pp">Examples for why this is useful include hardware diagnostics and
prototyping. In both these use cases, it is far more convenient to develop
and run the logic in user space. Especially hardware diagnostics requires a
somewhat user-friendly interface and adequate reporting. Neither is done
easily as kernel code.</p>
<section class="Ss">
<h2 class="Ss" id="I/O_port_resources"><a class="permalink" href="#I/O_port_resources">I/O
port resources</a></h2>
<p class="Pp">Device special files created for I/O port resources allow
<a class="Xr">lseek(2)</a>, <a class="Xr">read(2)</a>,
<a class="Xr">write(2)</a> and <a class="Xr">ioctl(2)</a> operations to be
performed on them. The <a class="Xr">read(2)</a> and
<a class="Xr">write(2)</a> system calls are used to perform input and output
(resp.) on the port. The amount of data that can be read or written at any
single time is either 1, 2 or 4 bytes. While the
<code class="Nm">proto</code> driver does not prevent reading or writing 8
bytes at a time for some architectures, it should not be assumed that such
actually produces correct results. The <a class="Xr">lseek(2)</a> system
call is used to select the port number, relative to the I/O port region
being represented by the device special file. If, for example, the device
special file corresponds to an I/O port region from 0x3f8 to 0x3ff
inclusive, then an offset of 4 given to lseek with a whence value of
SEEK_SET will target port 0x3fc on the next read or write operation. The
<a class="Xr">ioctl(2)</a> system call can be used for the
<code class="Dv">PROTO_IOC_REGION</code> request. This ioctl request returns
the extend of the resource covered by this device special file. The extend
is returned in the following structure:</p>
<div class="Bd Pp Li">
<pre>struct proto_ioc_region {
unsigned long address;
unsigned long size;
};</pre>
</div>
</section>
<section class="Ss">
<h2 class="Ss" id="Memory_mapped_I/O_resources"><a class="permalink" href="#Memory_mapped_I/O_resources">Memory
mapped I/O resources</a></h2>
<p class="Pp">The device special files created for memory mapped I/O resources
behave in the same way as those created for I/O port resources.
Additionally, device special files for memory mapped I/O resources allow the
memory to be mapped into the process' address space using
<a class="Xr">mmap(2)</a>. Reads and writes to the memory address returned
by <a class="Xr">mmap(2)</a> go directly to the hardware. As such the use of
<a class="Xr">read(2)</a> and <a class="Xr">write(2)</a> can be avoided,
reducing the access overhead significantly. Alignment and access width
constraints put forth by the underlying device apply. Also, make sure the
compiler does not optimize memory accesses away or has them coalesced into
bigger accesses.</p>
</section>
<section class="Ss">
<h2 class="Ss" id="DMA_pseudo_resource"><a class="permalink" href="#DMA_pseudo_resource">DMA
pseudo resource</a></h2>
<p class="Pp">A device special file named <span class="Pa">busdma</span> is
created for the purpose of doing DMA. It only supports
<a class="Xr">ioctl(2)</a> and only for the
<code class="Dv">PROTO_IOC_BUSDMA</code> request. This device special file
does not support <a class="Xr">read(2)</a> nor <a class="Xr">write(2)</a>.
The <code class="Dv">PROTO_IOC_BUSDMA</code> request has an argument that is
both in and out and is defined as follows:</p>
<div class="Bd Pp Li">
<pre>struct proto_ioc_busdma {
unsigned int request;
unsigned long key;
union {
struct {
unsigned long align;
unsigned long bndry;
unsigned long maxaddr;
unsigned long maxsz;
unsigned long maxsegsz;
unsigned int nsegs;
unsigned int datarate;
unsigned int flags;
} tag;
struct {
unsigned long tag;
unsigned int flags;
unsigned long virt_addr;
unsigned long virt_size;
unsigned int phys_nsegs;
unsigned long phys_addr;
unsigned long bus_addr;
unsigned int bus_nsegs;
} md;
struct {
unsigned int op;
unsigned long base;
unsigned long size;
} sync;
} u;
unsigned long result;
};</pre>
</div>
The <var class="Va">request</var> field is used to specify which DMA operation
is to be performed. The <var class="Va">key</var> field is used to specify
which object the operation applies to. An object is either a tag or a memory
descriptor (md). The following DMA operations are defined:
<dl class="Bl-tag">
<dt>PROTO_IOC_BUSDMA_TAG_CREATE</dt>
<dd>Create a root tag. The <var class="Va">result</var> field is set on output
with the key of the DMA tag. The tag is created with the constraints given
by the <var class="Va">tag</var> sub-structure. These constraints
correspond roughly to those that can be given to the
<a class="Xr">bus_dma_tag_create(9)</a> function.</dd>
<dt>PROTO_IOC_BUSDMA_TAG_DERIVE</dt>
<dd>Create a derived tag. The <var class="Va">key</var> field is used to
identify the parent tag from which to derive the new tag. The key of the
derived tag is returned in the <var class="Va">result</var> field. The
derived tag combines the constraints of the parent tag with those given by
the <var class="Va">tag</var> sub-structure. The combined constraints are
written back to the <var class="Va">tag</var> sub-structure on
return.</dd>
<dt>PROTO_IOC_BUSDMA_TAG_DESTROY</dt>
<dd>Destroy a root or derived tag previously created. The
<var class="Va">key</var> field specifies the tag to destroy. A tag can
only be destroyed when not referenced anymore. This means that derived
tags that have this tag as a parent and memory descriptors created from
this tag must be destroyed first.</dd>
<dt>PROTO_IOC_BUSDMA_MEM_ALLOC</dt>
<dd>Allocate memory that satisfies the constraints put forth by the tag given
in the <var class="Va">tag</var> field of the <var class="Va">md</var>
sub-structure. The key of the memory descriptor for this memory is
returned in the <var class="Va">result</var> field. The
<var class="Va">md</var> sub-structure is filled on return with details of
the allocation. The kernel virtual address and the size of the allocated
memory are returned in the <var class="Va">virt_addr</var> and
<var class="Va">virt_size</var> fields. The number of contiguous physical
memory segments and the address of the first segment are returned in the
<var class="Va">phys_nsegs</var> and <var class="Va">phys_addr</var>
fields. Allocated memory is automatically loaded and thus mapped into bus
space. The number of bus segments and the address of the first segment are
returned in the <var class="Va">bus_nsegs</var> and
<var class="Va">bus_addr</var> fields. The behaviour of this operation
banks heavily on how <a class="Xr">bus_dmamem_alloc(9)</a> is implemented,
which means that memory is currently always allocated as a single
contiguous region of physical memory. In practice this also tends to give
a single contiguous region in bus space. This may change over time.</dd>
<dt>PROTO_IOC_BUSDMA_MEM_FREE</dt>
<dd>Free previously allocated memory and destroy the memory descriptor. The
<code class="Nm">proto</code> driver is not in a position to track whether
the memory has been mapped in the process' address space, so the
application is responsible for unmapping the memory before it is freed.
The <code class="Nm">proto</code> driver also cannot protect against the
hardware writing to or reading from the memory, even after it has been
freed. When the memory is reused for other purposes it can be corrupted or
cause the hardware to behave in unpredictable ways when DMA has not
stopped completely before freeing.</dd>
<dt>PROTO_IOC_BUSDMA_MD_CREATE</dt>
<dd>Create an empty memory descriptor with the tag specified in the
<var class="Va">tag</var> field of the <var class="Va">md</var>
sub-structure. The key of the memory descriptor is returned in the
<var class="Va">result</var> field.</dd>
<dt>PROTO_IOC_BUSDMA_MD_DESTROY</dt>
<dd>Destroy the previously created memory descriptor specified by the
<var class="Va">key</var> field. When the memory descriptor is still
loaded, it is unloaded first.</dd>
<dt>PROTO_IOC_BUSDMA_MD_LOAD</dt>
<dd>Load a contiguous region of memory in the memory descriptor specified by
the <var class="Va">key</var> field. The size and address in the process'
virtual address space are specified by the <var class="Va">virt_size</var>
and <var class="Va">virt_addr</var> fields. On return, the
<var class="Va">md</var> sub-structure contains the result of the
operation. The number of physical segments and the address of the first
segment is returned in the <var class="Va">phys_nsegs</var> and
<var class="Va">phys_addr</var> fields. The number of bus space segments
and the address of the first segment in bus space is returned in the
<var class="Va">bus_nsegs</var> and <var class="Va">bus_addr</var>
fields.</dd>
<dt>PROTO_IOC_BUSDMA_MD_UNLOAD</dt>
<dd>Unload the memory descriptor specified by the <var class="Va">key</var>
field.</dd>
<dt>PROTO_IOC_BUSDMA_SYNC</dt>
<dd>Guarantee that all hardware components have a coherent view of the memory
tracked by the memory descriptor, specified by the
<var class="Va">key</var> field. A sub-section of the memory can be
targeted by specifying the relative offset and size of the memory to make
coherent. The offset and size are given by the <var class="Va">base</var>
and <var class="Va">size</var> fields of the <var class="Va">sync</var>
sub-structure. The <var class="Va">op</var> field holds the sync operation
to be performed. This is similar to the
<a class="Xr">bus_dmamap_sync(9)</a> function.</dd>
</dl>
</section>
<section class="Ss">
<h2 class="Ss" id="PCI_configuration_space"><a class="permalink" href="#PCI_configuration_space">PCI
configuration space</a></h2>
<p class="Pp">Access to PCI configuration space is possible through the
<span class="Pa">pcicfg</span> device special file. The device special file
supports <a class="Xr">lseek(2)</a>, <a class="Xr">read(2)</a> and
<a class="Xr">write(2)</a>. Usage is the asme as for I/O port resources.</p>
</section>
</section>
<section class="Sh">
<h1 class="Sh" id="FILES"><a class="permalink" href="#FILES">FILES</a></h1>
<p class="Pp">All device special files corresponding to a PCI device are located
under
<span class="Pa">/dev/proto/pci<d>:<b>:<s>:<f></span>
with <span class="Pa">pci<d>:<b>:<s>:<f></span>
representing the location of the PCI device in the PCI hierarchy. A PCI
location includes:</p>
<p class="Pp"></p>
<div class="Bd-indent">
<dl class="Bl-tag Bl-compact">
<dt><d></dt>
<dd>The PCI domain number</dd>
<dt><b></dt>
<dd>The PCI bus number</dd>
<dt><s></dt>
<dd>The PCI slot or device number</dd>
<dt><f></dt>
<dd>The PCI function number</dd>
</dl>
</div>
<p class="Pp">Every PCI device has a device special file called
<span class="Pa">pcicfg</span>. This device special file gives access to the
PCI configuration space. A device special file called
<span class="Pa">busdma</span> is also created. This device special file
provides the interfaces needed for doing DMA. For each valid base address
register (BAR), a device special file is created that contains the BAR
offset and the resource type. A resource type can be either
<span class="Pa">io</span> or <span class="Pa">mem</span> representing I/O
port or memory mapped I/O space (resp.)</p>
<p class="Pp">ISA devices do not have a location. Instead, they are identified
by the first I/O port address or first memory mapped I/O address.
Consequently, all device special files corresponding to an ISA device are
located under <span class="Pa">/dev/proto/isa:<addr></span> with
<span class="Pa">addr</span> the address in hexadecimal notation. For each
I/O port or memory mapped I/O address, a device special file is created that
contains the resource identification used by the kernel and the resource
type. The resource type can be either <span class="Pa">io</span> or
<span class="Pa">mem</span> representing I/O port or memory mapped I/O space
(resp.) When the device has a DMA channel assigned to it, a device special
file with the name <span class="Pa">busdma</span> is created as well. This
device special file provides the interfaces needed for doing DMA.</p>
<p class="Pp">If the ISA device is not a Plug-and-Play device nor present in the
ACPI device tree, it must have the appropriate hints so that the kernel can
reserve the resources for it.</p>
</section>
<section class="Sh">
<h1 class="Sh" id="EXAMPLES"><a class="permalink" href="#EXAMPLES">EXAMPLES</a></h1>
<p class="Pp">A single function PCI device in domain 0, on bus 1, in slot 2 and
having a single memory mapped I/O region will have the following device
special files:</p>
<p class="Pp"></p>
<div class="Bd-indent">
<dl class="Bl-tag Bl-compact">
<dt><span class="Pa">/dev/proto/pci0:1:2:0/10.mem</span></dt>
<dd style="width: auto;"> </dd>
<dt><span class="Pa">/dev/proto/pci0:1:2:0/pcicfg</span></dt>
<dd style="width: auto;"> </dd>
</dl>
</div>
<p class="Pp">A legacy floppy controller will have the following device
files:</p>
<p class="Pp"></p>
<div class="Bd-indent">
<dl class="Bl-tag Bl-compact">
<dt><span class="Pa">/dev/proto/isa:0x3f0/00.io</span></dt>
<dd style="width: auto;"> </dd>
<dt><span class="Pa">/dev/proto/isa:0x3f0/01.io</span></dt>
<dd style="width: auto;"> </dd>
<dt><span class="Pa">/dev/proto/isa:0x3f0/busdma</span></dt>
<dd style="width: auto;"> </dd>
</dl>
</div>
</section>
<section class="Sh">
<h1 class="Sh" id="SEE_ALSO"><a class="permalink" href="#SEE_ALSO">SEE
ALSO</a></h1>
<p class="Pp"><a class="Xr">ioctl(2)</a>, <a class="Xr">lseek(2)</a>,
<a class="Xr">mmap(2)</a>, <a class="Xr">read(2)</a>,
<a class="Xr">write(2)</a>, <a class="Xr">bus_dma_tag_create(9)</a>,
<a class="Xr">bus_dmamap_sync(9)</a>,
<a class="Xr">bus_dmamem_alloc(9)</a></p>
</section>
<section class="Sh">
<h1 class="Sh" id="AUTHORS"><a class="permalink" href="#AUTHORS">AUTHORS</a></h1>
<p class="Pp">The <code class="Nm">proto</code> device driver and this manual
page were written by <span class="An">Marcel Moolenaar</span>
<<a class="Mt" href="mailto:marcel@xcllnt.net">marcel@xcllnt.net</a>>.</p>
</section>
<section class="Sh">
<h1 class="Sh" id="SECURITY_CONSIDERATIONS"><a class="permalink" href="#SECURITY_CONSIDERATIONS">SECURITY
CONSIDERATIONS</a></h1>
<p class="Pp">Because programs have direct access to the hardware, the
<code class="Nm">proto</code> driver is inherently insecure. It is not
advisable to use this driver on a production machine.</p>
</section>
<section class="Sh">
<h1 class="Sh" id="MISSING_FUNCTIONALITY"><a class="permalink" href="#MISSING_FUNCTIONALITY">MISSING
FUNCTIONALITY</a></h1>
<p class="Pp">The <code class="Nm">proto</code> driver does not fully support
memory descriptors that need multiple physical memory segments or multiple
bus space segments. At the very least, an operation is needed on the DMA
pseudo resource for the application to obtain all segments.</p>
<p class="Pp">The <code class="Nm">proto</code> driver does not yet support
interrupts. Since interrupts cannot be handled by the driver itself, they
must be converted into signals and delivered to the program that has
registered for interrupts. A satisfactory mechanism for keeping the
interrupt masked during the signal handling is still being worked out.</p>
<p class="Pp">DMA support for devices other than busmaster devices is not
present yet. The details of how a program is to interact with the DMA
controller still need to be fleshed out.</p>
</section>
</div>
<table class="foot">
<tr>
<td class="foot-date">August 7, 2015</td>
<td class="foot-os">FreeBSD 15.0</td>
</tr>
</table>
|