Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/rust/kernel/io/register.rs
170891 views
1
// SPDX-License-Identifier: GPL-2.0
2
3
//! Macro to define register layout and accessors.
4
//!
5
//! The [`register!`](kernel::io::register!) macro provides an intuitive and readable syntax for
6
//! defining a dedicated type for each register and accessing it using [`Io`](super::Io). Each such
7
//! type comes with its own field accessors that can return an error if a field's value is invalid.
8
//!
9
//! Note: most of the items in this module are public so they can be referenced by the macro, but
10
//! most are not to be used directly by users. Outside of the `register!` macro itself, the only
11
//! items you might want to import from this module are [`WithBase`] and [`Array`].
12
//!
13
//! # Simple example
14
//!
15
//! ```no_run
16
//! use kernel::io::register;
17
//!
18
//! register! {
19
//! /// Basic information about the chip.
20
//! pub BOOT_0(u32) @ 0x00000100 {
21
//! /// Vendor ID.
22
//! 15:8 vendor_id;
23
//! /// Major revision of the chip.
24
//! 7:4 major_revision;
25
//! /// Minor revision of the chip.
26
//! 3:0 minor_revision;
27
//! }
28
//! }
29
//! ```
30
//!
31
//! This defines a 32-bit `BOOT_0` type which can be read from or written to offset `0x100` of an
32
//! `Io` region, with the described bitfields. For instance, `minor_revision` consists of the 4
33
//! least significant bits of the type.
34
//!
35
//! Fields are instances of [`Bounded`](kernel::num::Bounded) and can be read by calling their
36
//! getter method, which is named after them. They also have setter methods prefixed with `with_`
37
//! for runtime values and `with_const_` for constant values. All setters return the updated
38
//! register value.
39
//!
40
//! Fields can also be transparently converted from/to an arbitrary type by using the `=>` and
41
//! `?=>` syntaxes.
42
//!
43
//! If present, doc comments above register or fields definitions are added to the relevant item
44
//! they document (the register type itself, or the field's setter and getter methods).
45
//!
46
//! Note that multiple registers can be defined in a single `register!` invocation. This can be
47
//! useful to group related registers together.
48
//!
49
//! Here is how the register defined above can be used in code:
50
//!
51
//!
52
//! ```no_run
53
//! use kernel::{
54
//! io::{
55
//! register,
56
//! Io,
57
//! IoLoc,
58
//! },
59
//! num::Bounded,
60
//! };
61
//! # use kernel::io::Mmio;
62
//! # register! {
63
//! # pub BOOT_0(u32) @ 0x00000100 {
64
//! # 15:8 vendor_id;
65
//! # 7:4 major_revision;
66
//! # 3:0 minor_revision;
67
//! # }
68
//! # }
69
//! # fn test(io: &Mmio<0x1000>) {
70
//! # fn obtain_vendor_id() -> u8 { 0xff }
71
//!
72
//! // Read from the register's defined offset (0x100).
73
//! let boot0 = io.read(BOOT_0);
74
//! pr_info!("chip revision: {}.{}", boot0.major_revision().get(), boot0.minor_revision().get());
75
//!
76
//! // Update some fields and write the new value back.
77
//! let new_boot0 = boot0
78
//! // Constant values.
79
//! .with_const_major_revision::<3>()
80
//! .with_const_minor_revision::<10>()
81
//! // Runtime value.
82
//! .with_vendor_id(obtain_vendor_id());
83
//! io.write_reg(new_boot0);
84
//!
85
//! // Or, build a new value from zero and write it:
86
//! io.write_reg(BOOT_0::zeroed()
87
//! .with_const_major_revision::<3>()
88
//! .with_const_minor_revision::<10>()
89
//! .with_vendor_id(obtain_vendor_id())
90
//! );
91
//!
92
//! // Or, read and update the register in a single step.
93
//! io.update(BOOT_0, |r| r
94
//! .with_const_major_revision::<3>()
95
//! .with_const_minor_revision::<10>()
96
//! .with_vendor_id(obtain_vendor_id())
97
//! );
98
//!
99
//! // Constant values can also be built using the const setters.
100
//! const V: BOOT_0 = pin_init::zeroed::<BOOT_0>()
101
//! .with_const_major_revision::<3>()
102
//! .with_const_minor_revision::<10>();
103
//! # }
104
//! ```
105
//!
106
//! For more extensive documentation about how to define registers, see the
107
//! [`register!`](kernel::io::register!) macro.
108
109
use core::marker::PhantomData;
110
111
use crate::io::IoLoc;
112
113
use kernel::build_assert;
114
115
/// Trait implemented by all registers.
116
pub trait Register: Sized {
117
/// Backing primitive type of the register.
118
type Storage: Into<Self> + From<Self>;
119
120
/// Start offset of the register.
121
///
122
/// The interpretation of this offset depends on the type of the register.
123
const OFFSET: usize;
124
}
125
126
/// Trait implemented by registers with a fixed offset.
127
pub trait FixedRegister: Register {}
128
129
/// Allows `()` to be used as the `location` parameter of [`Io::write`](super::Io::write) when
130
/// passing a [`FixedRegister`] value.
131
impl<T> IoLoc<T> for ()
132
where
133
T: FixedRegister,
134
{
135
type IoType = T::Storage;
136
137
#[inline(always)]
138
fn offset(self) -> usize {
139
T::OFFSET
140
}
141
}
142
143
/// A [`FixedRegister`] carries its location in its type. Thus `FixedRegister` values can be used
144
/// as an [`IoLoc`].
145
impl<T> IoLoc<T> for T
146
where
147
T: FixedRegister,
148
{
149
type IoType = T::Storage;
150
151
#[inline(always)]
152
fn offset(self) -> usize {
153
T::OFFSET
154
}
155
}
156
157
/// Location of a fixed register.
158
pub struct FixedRegisterLoc<T: FixedRegister>(PhantomData<T>);
159
160
impl<T: FixedRegister> FixedRegisterLoc<T> {
161
/// Returns the location of `T`.
162
#[inline(always)]
163
// We do not implement `Default` so we can be const.
164
#[expect(clippy::new_without_default)]
165
pub const fn new() -> Self {
166
Self(PhantomData)
167
}
168
}
169
170
impl<T> IoLoc<T> for FixedRegisterLoc<T>
171
where
172
T: FixedRegister,
173
{
174
type IoType = T::Storage;
175
176
#[inline(always)]
177
fn offset(self) -> usize {
178
T::OFFSET
179
}
180
}
181
182
/// Trait providing a base address to be added to the offset of a relative register to obtain
183
/// its actual offset.
184
///
185
/// The `T` generic argument is used to distinguish which base to use, in case a type provides
186
/// several bases. It is given to the `register!` macro to restrict the use of the register to
187
/// implementors of this particular variant.
188
pub trait RegisterBase<T> {
189
/// Base address to which register offsets are added.
190
const BASE: usize;
191
}
192
193
/// Trait implemented by all registers that are relative to a base.
194
pub trait WithBase {
195
/// Family of bases applicable to this register.
196
type BaseFamily;
197
198
/// Returns the absolute location of this type when using `B` as its base.
199
#[inline(always)]
200
fn of<B: RegisterBase<Self::BaseFamily>>() -> RelativeRegisterLoc<Self, B>
201
where
202
Self: Register,
203
{
204
RelativeRegisterLoc::new()
205
}
206
}
207
208
/// Trait implemented by relative registers.
209
pub trait RelativeRegister: Register + WithBase {}
210
211
/// Location of a relative register.
212
///
213
/// This can either be an immediately accessible regular [`RelativeRegister`], or a
214
/// [`RelativeRegisterArray`] that needs one additional resolution through
215
/// [`RelativeRegisterLoc::at`].
216
pub struct RelativeRegisterLoc<T: WithBase, B: ?Sized>(PhantomData<T>, PhantomData<B>);
217
218
impl<T, B> RelativeRegisterLoc<T, B>
219
where
220
T: Register + WithBase,
221
B: RegisterBase<T::BaseFamily> + ?Sized,
222
{
223
/// Returns the location of a relative register or register array.
224
#[inline(always)]
225
// We do not implement `Default` so we can be const.
226
#[expect(clippy::new_without_default)]
227
pub const fn new() -> Self {
228
Self(PhantomData, PhantomData)
229
}
230
231
// Returns the absolute offset of the relative register using base `B`.
232
//
233
// This is implemented as a private const method so it can be reused by the [`IoLoc`]
234
// implementations of both [`RelativeRegisterLoc`] and [`RelativeRegisterArrayLoc`].
235
#[inline]
236
const fn offset(self) -> usize {
237
B::BASE + T::OFFSET
238
}
239
}
240
241
impl<T, B> IoLoc<T> for RelativeRegisterLoc<T, B>
242
where
243
T: RelativeRegister,
244
B: RegisterBase<T::BaseFamily> + ?Sized,
245
{
246
type IoType = T::Storage;
247
248
#[inline(always)]
249
fn offset(self) -> usize {
250
RelativeRegisterLoc::offset(self)
251
}
252
}
253
254
/// Trait implemented by arrays of registers.
255
pub trait RegisterArray: Register {
256
/// Number of elements in the registers array.
257
const SIZE: usize;
258
/// Number of bytes between the start of elements in the registers array.
259
const STRIDE: usize;
260
}
261
262
/// Location of an array register.
263
pub struct RegisterArrayLoc<T: RegisterArray>(usize, PhantomData<T>);
264
265
impl<T: RegisterArray> RegisterArrayLoc<T> {
266
/// Returns the location of register `T` at position `idx`, with build-time validation.
267
#[inline(always)]
268
pub fn new(idx: usize) -> Self {
269
build_assert!(idx < T::SIZE);
270
271
Self(idx, PhantomData)
272
}
273
274
/// Attempts to return the location of register `T` at position `idx`, with runtime validation.
275
#[inline(always)]
276
pub fn try_new(idx: usize) -> Option<Self> {
277
if idx < T::SIZE {
278
Some(Self(idx, PhantomData))
279
} else {
280
None
281
}
282
}
283
}
284
285
impl<T> IoLoc<T> for RegisterArrayLoc<T>
286
where
287
T: RegisterArray,
288
{
289
type IoType = T::Storage;
290
291
#[inline(always)]
292
fn offset(self) -> usize {
293
T::OFFSET + self.0 * T::STRIDE
294
}
295
}
296
297
/// Trait providing location builders for [`RegisterArray`]s.
298
pub trait Array {
299
/// Returns the location of the register at position `idx`, with build-time validation.
300
#[inline(always)]
301
fn at(idx: usize) -> RegisterArrayLoc<Self>
302
where
303
Self: RegisterArray,
304
{
305
RegisterArrayLoc::new(idx)
306
}
307
308
/// Returns the location of the register at position `idx`, with runtime validation.
309
#[inline(always)]
310
fn try_at(idx: usize) -> Option<RegisterArrayLoc<Self>>
311
where
312
Self: RegisterArray,
313
{
314
RegisterArrayLoc::try_new(idx)
315
}
316
}
317
318
/// Trait implemented by arrays of relative registers.
319
pub trait RelativeRegisterArray: RegisterArray + WithBase {}
320
321
/// Location of a relative array register.
322
pub struct RelativeRegisterArrayLoc<
323
T: RelativeRegisterArray,
324
B: RegisterBase<T::BaseFamily> + ?Sized,
325
>(RelativeRegisterLoc<T, B>, usize);
326
327
impl<T, B> RelativeRegisterArrayLoc<T, B>
328
where
329
T: RelativeRegisterArray,
330
B: RegisterBase<T::BaseFamily> + ?Sized,
331
{
332
/// Returns the location of register `T` from the base `B` at index `idx`, with build-time
333
/// validation.
334
#[inline(always)]
335
pub fn new(idx: usize) -> Self {
336
build_assert!(idx < T::SIZE);
337
338
Self(RelativeRegisterLoc::new(), idx)
339
}
340
341
/// Attempts to return the location of register `T` from the base `B` at index `idx`, with
342
/// runtime validation.
343
#[inline(always)]
344
pub fn try_new(idx: usize) -> Option<Self> {
345
if idx < T::SIZE {
346
Some(Self(RelativeRegisterLoc::new(), idx))
347
} else {
348
None
349
}
350
}
351
}
352
353
/// Methods exclusive to [`RelativeRegisterLoc`]s created with a [`RelativeRegisterArray`].
354
impl<T, B> RelativeRegisterLoc<T, B>
355
where
356
T: RelativeRegisterArray,
357
B: RegisterBase<T::BaseFamily> + ?Sized,
358
{
359
/// Returns the location of the register at position `idx`, with build-time validation.
360
#[inline(always)]
361
pub fn at(self, idx: usize) -> RelativeRegisterArrayLoc<T, B> {
362
RelativeRegisterArrayLoc::new(idx)
363
}
364
365
/// Returns the location of the register at position `idx`, with runtime validation.
366
#[inline(always)]
367
pub fn try_at(self, idx: usize) -> Option<RelativeRegisterArrayLoc<T, B>> {
368
RelativeRegisterArrayLoc::try_new(idx)
369
}
370
}
371
372
impl<T, B> IoLoc<T> for RelativeRegisterArrayLoc<T, B>
373
where
374
T: RelativeRegisterArray,
375
B: RegisterBase<T::BaseFamily> + ?Sized,
376
{
377
type IoType = T::Storage;
378
379
#[inline(always)]
380
fn offset(self) -> usize {
381
self.0.offset() + self.1 * T::STRIDE
382
}
383
}
384
385
/// Trait implemented by items that contain both a register value and the absolute I/O location at
386
/// which to write it.
387
///
388
/// Implementors can be used with [`Io::write_reg`](super::Io::write_reg).
389
pub trait LocatedRegister {
390
/// Register value to write.
391
type Value: Register;
392
/// Full location information at which to write the value.
393
type Location: IoLoc<Self::Value>;
394
395
/// Consumes `self` and returns a `(location, value)` tuple describing a valid I/O write
396
/// operation.
397
fn into_io_op(self) -> (Self::Location, Self::Value);
398
}
399
400
impl<T> LocatedRegister for T
401
where
402
T: FixedRegister,
403
{
404
type Location = FixedRegisterLoc<Self::Value>;
405
type Value = T;
406
407
#[inline(always)]
408
fn into_io_op(self) -> (FixedRegisterLoc<T>, T) {
409
(FixedRegisterLoc::new(), self)
410
}
411
}
412
413
/// Defines a dedicated type for a register, including getter and setter methods for its fields and
414
/// methods to read and write it from an [`Io`](kernel::io::Io) region.
415
///
416
/// This documentation focuses on how to declare registers. See the [module-level
417
/// documentation](mod@kernel::io::register) for examples of how to access them.
418
///
419
/// There are 4 possible kinds of registers: fixed offset registers, relative registers, arrays of
420
/// registers, and relative arrays of registers.
421
///
422
/// ## Fixed offset registers
423
///
424
/// These are the simplest kind of registers. Their location is simply an offset inside the I/O
425
/// region. For instance:
426
///
427
/// ```ignore
428
/// register! {
429
/// pub FIXED_REG(u16) @ 0x80 {
430
/// ...
431
/// }
432
/// }
433
/// ```
434
///
435
/// This creates a 16-bit register named `FIXED_REG` located at offset `0x80` of an I/O region.
436
///
437
/// These registers' location can be built simply by referencing their name:
438
///
439
/// ```no_run
440
/// use kernel::{
441
/// io::{
442
/// register,
443
/// Io,
444
/// },
445
/// };
446
/// # use kernel::io::Mmio;
447
///
448
/// register! {
449
/// FIXED_REG(u32) @ 0x100 {
450
/// 16:8 high_byte;
451
/// 7:0 low_byte;
452
/// }
453
/// }
454
///
455
/// # fn test(io: &Mmio<0x1000>) {
456
/// let val = io.read(FIXED_REG);
457
///
458
/// // Write from an already-existing value.
459
/// io.write(FIXED_REG, val.with_low_byte(0xff));
460
///
461
/// // Create a register value from scratch.
462
/// let val2 = FIXED_REG::zeroed().with_high_byte(0x80);
463
///
464
/// // The location of fixed offset registers is already contained in their type. Thus, the
465
/// // `location` argument of `Io::write` is technically redundant and can be replaced by `()`.
466
/// io.write((), val2);
467
///
468
/// // Or, the single-argument `Io::write_reg` can be used.
469
/// io.write_reg(val2);
470
/// # }
471
///
472
/// ```
473
///
474
/// It is possible to create an alias of an existing register with new field definitions by using
475
/// the `=> ALIAS` syntax. This is useful for cases where a register's interpretation depends on
476
/// the context:
477
///
478
/// ```no_run
479
/// use kernel::io::register;
480
///
481
/// register! {
482
/// /// Scratch register.
483
/// pub SCRATCH(u32) @ 0x00000200 {
484
/// 31:0 value;
485
/// }
486
///
487
/// /// Boot status of the firmware.
488
/// pub SCRATCH_BOOT_STATUS(u32) => SCRATCH {
489
/// 0:0 completed;
490
/// }
491
/// }
492
/// ```
493
///
494
/// In this example, `SCRATCH_BOOT_STATUS` uses the same I/O address as `SCRATCH`, while providing
495
/// its own `completed` field.
496
///
497
/// ## Relative registers
498
///
499
/// Relative registers can be instantiated several times at a relative offset of a group of bases.
500
/// For instance, imagine the following I/O space:
501
///
502
/// ```text
503
/// +-----------------------------+
504
/// | ... |
505
/// | |
506
/// 0x100--->+------------CPU0-------------+
507
/// | |
508
/// 0x110--->+-----------------------------+
509
/// | CPU_CTL |
510
/// +-----------------------------+
511
/// | ... |
512
/// | |
513
/// | |
514
/// 0x200--->+------------CPU1-------------+
515
/// | |
516
/// 0x210--->+-----------------------------+
517
/// | CPU_CTL |
518
/// +-----------------------------+
519
/// | ... |
520
/// +-----------------------------+
521
/// ```
522
///
523
/// `CPU0` and `CPU1` both have a `CPU_CTL` register that starts at offset `0x10` of their I/O
524
/// space segment. Since both instances of `CPU_CTL` share the same layout, we don't want to define
525
/// them twice and would prefer a way to select which one to use from a single definition.
526
///
527
/// This can be done using the `Base + Offset` syntax when specifying the register's address:
528
///
529
/// ```ignore
530
/// register! {
531
/// pub RELATIVE_REG(u32) @ Base + 0x80 {
532
/// ...
533
/// }
534
/// }
535
/// ```
536
///
537
/// This creates a register with an offset of `0x80` from a given base.
538
///
539
/// `Base` is an arbitrary type (typically a ZST) to be used as a generic parameter of the
540
/// [`RegisterBase`] trait to provide the base as a constant, i.e. each type providing a base for
541
/// this register needs to implement `RegisterBase<Base>`.
542
///
543
/// The location of relative registers can be built using the [`WithBase::of`] method to specify
544
/// its base. All relative registers implement [`WithBase`].
545
///
546
/// Here is the above layout translated into code:
547
///
548
/// ```no_run
549
/// use kernel::{
550
/// io::{
551
/// register,
552
/// register::{
553
/// RegisterBase,
554
/// WithBase,
555
/// },
556
/// Io,
557
/// },
558
/// };
559
/// # use kernel::io::Mmio;
560
///
561
/// // Type used to identify the base.
562
/// pub struct CpuCtlBase;
563
///
564
/// // ZST describing `CPU0`.
565
/// struct Cpu0;
566
/// impl RegisterBase<CpuCtlBase> for Cpu0 {
567
/// const BASE: usize = 0x100;
568
/// }
569
///
570
/// // ZST describing `CPU1`.
571
/// struct Cpu1;
572
/// impl RegisterBase<CpuCtlBase> for Cpu1 {
573
/// const BASE: usize = 0x200;
574
/// }
575
///
576
/// // This makes `CPU_CTL` accessible from all implementors of `RegisterBase<CpuCtlBase>`.
577
/// register! {
578
/// /// CPU core control.
579
/// pub CPU_CTL(u32) @ CpuCtlBase + 0x10 {
580
/// 0:0 start;
581
/// }
582
/// }
583
///
584
/// # fn test(io: Mmio<0x1000>) {
585
/// // Read the status of `Cpu0`.
586
/// let cpu0_started = io.read(CPU_CTL::of::<Cpu0>());
587
///
588
/// // Stop `Cpu0`.
589
/// io.write(WithBase::of::<Cpu0>(), CPU_CTL::zeroed());
590
/// # }
591
///
592
/// // Aliases can also be defined for relative register.
593
/// register! {
594
/// /// Alias to CPU core control.
595
/// pub CPU_CTL_ALIAS(u32) => CpuCtlBase + CPU_CTL {
596
/// /// Start the aliased CPU core.
597
/// 1:1 alias_start;
598
/// }
599
/// }
600
///
601
/// # fn test2(io: Mmio<0x1000>) {
602
/// // Start the aliased `CPU0`, leaving its other fields untouched.
603
/// io.update(CPU_CTL_ALIAS::of::<Cpu0>(), |r| r.with_alias_start(true));
604
/// # }
605
/// ```
606
///
607
/// ## Arrays of registers
608
///
609
/// Some I/O areas contain consecutive registers that share the same field layout. These areas can
610
/// be defined as an array of identical registers, allowing them to be accessed by index with
611
/// compile-time or runtime bound checking:
612
///
613
/// ```ignore
614
/// register! {
615
/// pub REGISTER_ARRAY(u8)[10, stride = 4] @ 0x100 {
616
/// ...
617
/// }
618
/// }
619
/// ```
620
///
621
/// This defines `REGISTER_ARRAY`, an array of 10 byte registers starting at offset `0x100`. Each
622
/// register is separated from its neighbor by 4 bytes.
623
///
624
/// The `stride` parameter is optional; if unspecified, the registers are placed consecutively from
625
/// each other.
626
///
627
/// A location for a register in a register array is built using the [`Array::at`] trait method.
628
/// All arrays of registers implement [`Array`].
629
///
630
/// ```no_run
631
/// use kernel::{
632
/// io::{
633
/// register,
634
/// register::Array,
635
/// Io,
636
/// },
637
/// };
638
/// # use kernel::io::Mmio;
639
/// # fn get_scratch_idx() -> usize {
640
/// # 0x15
641
/// # }
642
///
643
/// // Array of 64 consecutive registers with the same layout starting at offset `0x80`.
644
/// register! {
645
/// /// Scratch registers.
646
/// pub SCRATCH(u32)[64] @ 0x00000080 {
647
/// 31:0 value;
648
/// }
649
/// }
650
///
651
/// # fn test(io: &Mmio<0x1000>)
652
/// # -> Result<(), Error>{
653
/// // Read scratch register 0, i.e. I/O address `0x80`.
654
/// let scratch_0 = io.read(SCRATCH::at(0)).value();
655
///
656
/// // Write scratch register 15, i.e. I/O address `0x80 + (15 * 4)`.
657
/// io.write(Array::at(15), SCRATCH::from(0xffeeaabb));
658
///
659
/// // This is out of bounds and won't build.
660
/// // let scratch_128 = io.read(SCRATCH::at(128)).value();
661
///
662
/// // Runtime-obtained array index.
663
/// let idx = get_scratch_idx();
664
/// // Access on a runtime index returns an error if it is out-of-bounds.
665
/// let some_scratch = io.read(SCRATCH::try_at(idx).ok_or(EINVAL)?).value();
666
///
667
/// // Alias to a specific register in an array.
668
/// // Here `SCRATCH[8]` is used to convey the firmware exit code.
669
/// register! {
670
/// /// Firmware exit status code.
671
/// pub FIRMWARE_STATUS(u32) => SCRATCH[8] {
672
/// 7:0 status;
673
/// }
674
/// }
675
///
676
/// let status = io.read(FIRMWARE_STATUS).status();
677
///
678
/// // Non-contiguous register arrays can be defined by adding a stride parameter.
679
/// // Here, each of the 16 registers of the array is separated by 8 bytes, meaning that the
680
/// // registers of the two declarations below are interleaved.
681
/// register! {
682
/// /// Scratch registers bank 0.
683
/// pub SCRATCH_INTERLEAVED_0(u32)[16, stride = 8] @ 0x000000c0 {
684
/// 31:0 value;
685
/// }
686
///
687
/// /// Scratch registers bank 1.
688
/// pub SCRATCH_INTERLEAVED_1(u32)[16, stride = 8] @ 0x000000c4 {
689
/// 31:0 value;
690
/// }
691
/// }
692
/// # Ok(())
693
/// # }
694
/// ```
695
///
696
/// ## Relative arrays of registers
697
///
698
/// Combining the two features described in the sections above, arrays of registers accessible from
699
/// a base can also be defined:
700
///
701
/// ```ignore
702
/// register! {
703
/// pub RELATIVE_REGISTER_ARRAY(u8)[10, stride = 4] @ Base + 0x100 {
704
/// ...
705
/// }
706
/// }
707
/// ```
708
///
709
/// Like relative registers, they implement the [`WithBase`] trait. However the return value of
710
/// [`WithBase::of`] cannot be used directly as a location and must be further specified using the
711
/// [`at`](RelativeRegisterLoc::at) method.
712
///
713
/// ```no_run
714
/// use kernel::{
715
/// io::{
716
/// register,
717
/// register::{
718
/// RegisterBase,
719
/// WithBase,
720
/// },
721
/// Io,
722
/// },
723
/// };
724
/// # use kernel::io::Mmio;
725
/// # fn get_scratch_idx() -> usize {
726
/// # 0x15
727
/// # }
728
///
729
/// // Type used as parameter of `RegisterBase` to specify the base.
730
/// pub struct CpuCtlBase;
731
///
732
/// // ZST describing `CPU0`.
733
/// struct Cpu0;
734
/// impl RegisterBase<CpuCtlBase> for Cpu0 {
735
/// const BASE: usize = 0x100;
736
/// }
737
///
738
/// // ZST describing `CPU1`.
739
/// struct Cpu1;
740
/// impl RegisterBase<CpuCtlBase> for Cpu1 {
741
/// const BASE: usize = 0x200;
742
/// }
743
///
744
/// // 64 per-cpu scratch registers, arranged as a contiguous array.
745
/// register! {
746
/// /// Per-CPU scratch registers.
747
/// pub CPU_SCRATCH(u32)[64] @ CpuCtlBase + 0x00000080 {
748
/// 31:0 value;
749
/// }
750
/// }
751
///
752
/// # fn test(io: &Mmio<0x1000>) -> Result<(), Error> {
753
/// // Read scratch register 0 of CPU0.
754
/// let scratch = io.read(CPU_SCRATCH::of::<Cpu0>().at(0));
755
///
756
/// // Write the retrieved value into scratch register 15 of CPU1.
757
/// io.write(WithBase::of::<Cpu1>().at(15), scratch);
758
///
759
/// // This won't build.
760
/// // let cpu0_scratch_128 = io.read(CPU_SCRATCH::of::<Cpu0>().at(128)).value();
761
///
762
/// // Runtime-obtained array index.
763
/// let scratch_idx = get_scratch_idx();
764
/// // Access on a runtime index returns an error if it is out-of-bounds.
765
/// let cpu0_scratch = io.read(
766
/// CPU_SCRATCH::of::<Cpu0>().try_at(scratch_idx).ok_or(EINVAL)?
767
/// ).value();
768
/// # Ok(())
769
/// # }
770
///
771
/// // Alias to `SCRATCH[8]` used to convey the firmware exit code.
772
/// register! {
773
/// /// Per-CPU firmware exit status code.
774
/// pub CPU_FIRMWARE_STATUS(u32) => CpuCtlBase + CPU_SCRATCH[8] {
775
/// 7:0 status;
776
/// }
777
/// }
778
///
779
/// // Non-contiguous relative register arrays can be defined by adding a stride parameter.
780
/// // Here, each of the 16 registers of the array is separated by 8 bytes, meaning that the
781
/// // registers of the two declarations below are interleaved.
782
/// register! {
783
/// /// Scratch registers bank 0.
784
/// pub CPU_SCRATCH_INTERLEAVED_0(u32)[16, stride = 8] @ CpuCtlBase + 0x00000d00 {
785
/// 31:0 value;
786
/// }
787
///
788
/// /// Scratch registers bank 1.
789
/// pub CPU_SCRATCH_INTERLEAVED_1(u32)[16, stride = 8] @ CpuCtlBase + 0x00000d04 {
790
/// 31:0 value;
791
/// }
792
/// }
793
///
794
/// # fn test2(io: &Mmio<0x1000>) -> Result<(), Error> {
795
/// let cpu0_status = io.read(CPU_FIRMWARE_STATUS::of::<Cpu0>()).status();
796
/// # Ok(())
797
/// # }
798
/// ```
799
#[macro_export]
800
macro_rules! register {
801
// Entry point for the macro, allowing multiple registers to be defined in one call.
802
// It matches all possible register declaration patterns to dispatch them to corresponding
803
// `@reg` rule that defines a single register.
804
(
805
$(
806
$(#[$attr:meta])* $vis:vis $name:ident ($storage:ty)
807
$([ $size:expr $(, stride = $stride:expr)? ])?
808
$(@ $($base:ident +)? $offset:literal)?
809
$(=> $alias:ident $(+ $alias_offset:ident)? $([$alias_idx:expr])? )?
810
{ $($fields:tt)* }
811
)*
812
) => {
813
$(
814
$crate::register!(
815
@reg $(#[$attr])* $vis $name ($storage) $([$size $(, stride = $stride)?])?
816
$(@ $($base +)? $offset)?
817
$(=> $alias $(+ $alias_offset)? $([$alias_idx])? )?
818
{ $($fields)* }
819
);
820
)*
821
};
822
823
// All the rules below are private helpers.
824
825
// Creates a register at a fixed offset of the MMIO space.
826
(
827
@reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) @ $offset:literal
828
{ $($fields:tt)* }
829
) => {
830
$crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });
831
$crate::register!(@io_base $name($storage) @ $offset);
832
$crate::register!(@io_fixed $(#[$attr])* $vis $name($storage));
833
};
834
835
// Creates an alias register of fixed offset register `alias` with its own fields.
836
(
837
@reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) => $alias:ident
838
{ $($fields:tt)* }
839
) => {
840
$crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });
841
$crate::register!(
842
@io_base $name($storage) @
843
<$alias as $crate::io::register::Register>::OFFSET
844
);
845
$crate::register!(@io_fixed $(#[$attr])* $vis $name($storage));
846
};
847
848
// Creates a register at a relative offset from a base address provider.
849
(
850
@reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) @ $base:ident + $offset:literal
851
{ $($fields:tt)* }
852
) => {
853
$crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });
854
$crate::register!(@io_base $name($storage) @ $offset);
855
$crate::register!(@io_relative $vis $name($storage) @ $base);
856
};
857
858
// Creates an alias register of relative offset register `alias` with its own fields.
859
(
860
@reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) => $base:ident + $alias:ident
861
{ $($fields:tt)* }
862
) => {
863
$crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });
864
$crate::register!(
865
@io_base $name($storage) @ <$alias as $crate::io::register::Register>::OFFSET
866
);
867
$crate::register!(@io_relative $vis $name($storage) @ $base);
868
};
869
870
// Creates an array of registers at a fixed offset of the MMIO space.
871
(
872
@reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty)
873
[ $size:expr, stride = $stride:expr ] @ $offset:literal { $($fields:tt)* }
874
) => {
875
::kernel::static_assert!(::core::mem::size_of::<$storage>() <= $stride);
876
877
$crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });
878
$crate::register!(@io_base $name($storage) @ $offset);
879
$crate::register!(@io_array $vis $name($storage) [ $size, stride = $stride ]);
880
};
881
882
// Shortcut for contiguous array of registers (stride == size of element).
883
(
884
@reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) [ $size:expr ] @ $offset:literal
885
{ $($fields:tt)* }
886
) => {
887
$crate::register!(
888
$(#[$attr])* $vis $name($storage) [ $size, stride = ::core::mem::size_of::<$storage>() ]
889
@ $offset { $($fields)* }
890
);
891
};
892
893
// Creates an alias of register `idx` of array of registers `alias` with its own fields.
894
(
895
@reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) => $alias:ident [ $idx:expr ]
896
{ $($fields:tt)* }
897
) => {
898
::kernel::static_assert!($idx < <$alias as $crate::io::register::RegisterArray>::SIZE);
899
900
$crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });
901
$crate::register!(
902
@io_base $name($storage) @
903
<$alias as $crate::io::register::Register>::OFFSET
904
+ $idx * <$alias as $crate::io::register::RegisterArray>::STRIDE
905
);
906
$crate::register!(@io_fixed $(#[$attr])* $vis $name($storage));
907
};
908
909
// Creates an array of registers at a relative offset from a base address provider.
910
(
911
@reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty)
912
[ $size:expr, stride = $stride:expr ]
913
@ $base:ident + $offset:literal { $($fields:tt)* }
914
) => {
915
::kernel::static_assert!(::core::mem::size_of::<$storage>() <= $stride);
916
917
$crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });
918
$crate::register!(@io_base $name($storage) @ $offset);
919
$crate::register!(
920
@io_relative_array $vis $name($storage) [ $size, stride = $stride ] @ $base + $offset
921
);
922
};
923
924
// Shortcut for contiguous array of relative registers (stride == size of element).
925
(
926
@reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) [ $size:expr ]
927
@ $base:ident + $offset:literal { $($fields:tt)* }
928
) => {
929
$crate::register!(
930
$(#[$attr])* $vis $name($storage) [ $size, stride = ::core::mem::size_of::<$storage>() ]
931
@ $base + $offset { $($fields)* }
932
);
933
};
934
935
// Creates an alias of register `idx` of relative array of registers `alias` with its own
936
// fields.
937
(
938
@reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty)
939
=> $base:ident + $alias:ident [ $idx:expr ] { $($fields:tt)* }
940
) => {
941
::kernel::static_assert!($idx < <$alias as $crate::io::register::RegisterArray>::SIZE);
942
943
$crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });
944
$crate::register!(
945
@io_base $name($storage) @
946
<$alias as $crate::io::register::Register>::OFFSET +
947
$idx * <$alias as $crate::io::register::RegisterArray>::STRIDE
948
);
949
$crate::register!(@io_relative $vis $name($storage) @ $base);
950
};
951
952
// Generates the bitfield for the register.
953
//
954
// `#[allow(non_camel_case_types)]` is added since register names typically use
955
// `SCREAMING_CASE`.
956
(
957
@bitfield $(#[$attr:meta])* $vis:vis struct $name:ident($storage:ty) { $($fields:tt)* }
958
) => {
959
$crate::register!(@bitfield_core
960
#[allow(non_camel_case_types)]
961
$(#[$attr])* $vis $name $storage
962
);
963
$crate::register!(@bitfield_fields $vis $name $storage { $($fields)* });
964
};
965
966
// Implementations shared by all registers types.
967
(@io_base $name:ident($storage:ty) @ $offset:expr) => {
968
impl $crate::io::register::Register for $name {
969
type Storage = $storage;
970
971
const OFFSET: usize = $offset;
972
}
973
};
974
975
// Implementations of fixed registers.
976
(@io_fixed $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty)) => {
977
impl $crate::io::register::FixedRegister for $name {}
978
979
$(#[$attr])*
980
$vis const $name: $crate::io::register::FixedRegisterLoc<$name> =
981
$crate::io::register::FixedRegisterLoc::<$name>::new();
982
};
983
984
// Implementations of relative registers.
985
(@io_relative $vis:vis $name:ident ($storage:ty) @ $base:ident) => {
986
impl $crate::io::register::WithBase for $name {
987
type BaseFamily = $base;
988
}
989
990
impl $crate::io::register::RelativeRegister for $name {}
991
};
992
993
// Implementations of register arrays.
994
(@io_array $vis:vis $name:ident ($storage:ty) [ $size:expr, stride = $stride:expr ]) => {
995
impl $crate::io::register::Array for $name {}
996
997
impl $crate::io::register::RegisterArray for $name {
998
const SIZE: usize = $size;
999
const STRIDE: usize = $stride;
1000
}
1001
};
1002
1003
// Implementations of relative array registers.
1004
(
1005
@io_relative_array $vis:vis $name:ident ($storage:ty) [ $size:expr, stride = $stride:expr ]
1006
@ $base:ident + $offset:literal
1007
) => {
1008
impl $crate::io::register::WithBase for $name {
1009
type BaseFamily = $base;
1010
}
1011
1012
impl $crate::io::register::RegisterArray for $name {
1013
const SIZE: usize = $size;
1014
const STRIDE: usize = $stride;
1015
}
1016
1017
impl $crate::io::register::RelativeRegisterArray for $name {}
1018
};
1019
1020
// Defines the wrapper `$name` type and its conversions from/to the storage type.
1021
(@bitfield_core $(#[$attr:meta])* $vis:vis $name:ident $storage:ty) => {
1022
$(#[$attr])*
1023
#[repr(transparent)]
1024
#[derive(Clone, Copy, PartialEq, Eq)]
1025
$vis struct $name {
1026
inner: $storage,
1027
}
1028
1029
#[allow(dead_code)]
1030
impl $name {
1031
/// Creates a bitfield from a raw value.
1032
#[inline(always)]
1033
$vis const fn from_raw(value: $storage) -> Self {
1034
Self{ inner: value }
1035
}
1036
1037
/// Turns this bitfield into its raw value.
1038
///
1039
/// This is similar to the [`From`] implementation, but is shorter to invoke in
1040
/// most cases.
1041
#[inline(always)]
1042
$vis const fn into_raw(self) -> $storage {
1043
self.inner
1044
}
1045
}
1046
1047
// SAFETY: `$storage` is `Zeroable` and `$name` is transparent.
1048
unsafe impl ::pin_init::Zeroable for $name {}
1049
1050
impl ::core::convert::From<$name> for $storage {
1051
#[inline(always)]
1052
fn from(val: $name) -> $storage {
1053
val.into_raw()
1054
}
1055
}
1056
1057
impl ::core::convert::From<$storage> for $name {
1058
#[inline(always)]
1059
fn from(val: $storage) -> $name {
1060
Self::from_raw(val)
1061
}
1062
}
1063
};
1064
1065
// Definitions requiring knowledge of individual fields: private and public field accessors,
1066
// and `Debug` implementation.
1067
(@bitfield_fields $vis:vis $name:ident $storage:ty {
1068
$($(#[doc = $doc:expr])* $hi:literal:$lo:literal $field:ident
1069
$(?=> $try_into_type:ty)?
1070
$(=> $into_type:ty)?
1071
;
1072
)*
1073
}
1074
) => {
1075
#[allow(dead_code)]
1076
impl $name {
1077
$(
1078
$crate::register!(@private_field_accessors $vis $name $storage : $hi:$lo $field);
1079
$crate::register!(
1080
@public_field_accessors $(#[doc = $doc])* $vis $name $storage : $hi:$lo $field
1081
$(?=> $try_into_type)?
1082
$(=> $into_type)?
1083
);
1084
)*
1085
}
1086
1087
$crate::register!(@debug $name { $($field;)* });
1088
};
1089
1090
// Private field accessors working with the exact `Bounded` type for the field.
1091
(
1092
@private_field_accessors $vis:vis $name:ident $storage:ty : $hi:tt:$lo:tt $field:ident
1093
) => {
1094
::kernel::macros::paste!(
1095
$vis const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive<u8> = $lo..=$hi;
1096
$vis const [<$field:upper _MASK>]: $storage =
1097
((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1);
1098
$vis const [<$field:upper _SHIFT>]: u32 = $lo;
1099
);
1100
1101
::kernel::macros::paste!(
1102
fn [<__ $field>](self) ->
1103
::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> {
1104
// Left shift to align the field's MSB with the storage MSB.
1105
const ALIGN_TOP: u32 = $storage::BITS - ($hi + 1);
1106
// Right shift to move the top-aligned field to bit 0 of the storage.
1107
const ALIGN_BOTTOM: u32 = ALIGN_TOP + $lo;
1108
1109
// Extract the field using two shifts. `Bounded::shr` produces the correctly-sized
1110
// output type.
1111
let val = ::kernel::num::Bounded::<$storage, { $storage::BITS }>::from(
1112
self.inner << ALIGN_TOP
1113
);
1114
val.shr::<ALIGN_BOTTOM, { $hi + 1 - $lo } >()
1115
}
1116
1117
const fn [<__with_ $field>](
1118
mut self,
1119
value: ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>,
1120
) -> Self
1121
{
1122
const MASK: $storage = <$name>::[<$field:upper _MASK>];
1123
const SHIFT: u32 = <$name>::[<$field:upper _SHIFT>];
1124
1125
let value = value.get() << SHIFT;
1126
self.inner = (self.inner & !MASK) | value;
1127
1128
self
1129
}
1130
);
1131
};
1132
1133
// Public accessors for fields infallibly (`=>`) converted to a type.
1134
(
1135
@public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :
1136
$hi:literal:$lo:literal $field:ident => $into_type:ty
1137
) => {
1138
::kernel::macros::paste!(
1139
1140
$(#[doc = $doc])*
1141
#[doc = "Returns the value of this field."]
1142
#[inline(always)]
1143
$vis fn $field(self) -> $into_type
1144
{
1145
self.[<__ $field>]().into()
1146
}
1147
1148
$(#[doc = $doc])*
1149
#[doc = "Sets this field to the given `value`."]
1150
#[inline(always)]
1151
$vis fn [<with_ $field>](self, value: $into_type) -> Self
1152
{
1153
self.[<__with_ $field>](value.into())
1154
}
1155
1156
);
1157
};
1158
1159
// Public accessors for fields fallibly (`?=>`) converted to a type.
1160
(
1161
@public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :
1162
$hi:tt:$lo:tt $field:ident ?=> $try_into_type:ty
1163
) => {
1164
::kernel::macros::paste!(
1165
1166
$(#[doc = $doc])*
1167
#[doc = "Returns the value of this field."]
1168
#[inline(always)]
1169
$vis fn $field(self) ->
1170
Result<
1171
$try_into_type,
1172
<$try_into_type as ::core::convert::TryFrom<
1173
::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>
1174
>>::Error
1175
>
1176
{
1177
self.[<__ $field>]().try_into()
1178
}
1179
1180
$(#[doc = $doc])*
1181
#[doc = "Sets this field to the given `value`."]
1182
#[inline(always)]
1183
$vis fn [<with_ $field>](self, value: $try_into_type) -> Self
1184
{
1185
self.[<__with_ $field>](value.into())
1186
}
1187
1188
);
1189
};
1190
1191
// Public accessors for fields not converted to a type.
1192
(
1193
@public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :
1194
$hi:tt:$lo:tt $field:ident
1195
) => {
1196
::kernel::macros::paste!(
1197
1198
$(#[doc = $doc])*
1199
#[doc = "Returns the value of this field."]
1200
#[inline(always)]
1201
$vis fn $field(self) ->
1202
::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>
1203
{
1204
self.[<__ $field>]()
1205
}
1206
1207
$(#[doc = $doc])*
1208
#[doc = "Sets this field to the compile-time constant `VALUE`."]
1209
#[inline(always)]
1210
$vis const fn [<with_const_ $field>]<const VALUE: $storage>(self) -> Self {
1211
self.[<__with_ $field>](
1212
::kernel::num::Bounded::<$storage, { $hi + 1 - $lo }>::new::<VALUE>()
1213
)
1214
}
1215
1216
$(#[doc = $doc])*
1217
#[doc = "Sets this field to the given `value`."]
1218
#[inline(always)]
1219
$vis fn [<with_ $field>]<T>(
1220
self,
1221
value: T,
1222
) -> Self
1223
where T: Into<::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>>,
1224
{
1225
self.[<__with_ $field>](value.into())
1226
}
1227
1228
$(#[doc = $doc])*
1229
#[doc = "Tries to set this field to `value`, returning an error if it is out of range."]
1230
#[inline(always)]
1231
$vis fn [<try_with_ $field>]<T>(
1232
self,
1233
value: T,
1234
) -> ::kernel::error::Result<Self>
1235
where T: ::kernel::num::TryIntoBounded<$storage, { $hi + 1 - $lo }>,
1236
{
1237
Ok(
1238
self.[<__with_ $field>](
1239
value.try_into_bounded().ok_or(::kernel::error::code::EOVERFLOW)?
1240
)
1241
)
1242
}
1243
1244
);
1245
};
1246
1247
// `Debug` implementation.
1248
(@debug $name:ident { $($field:ident;)* }) => {
1249
impl ::kernel::fmt::Debug for $name {
1250
fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result {
1251
f.debug_struct(stringify!($name))
1252
.field("<raw>", &::kernel::prelude::fmt!("{:#x}", self.inner))
1253
$(
1254
.field(stringify!($field), &self.$field())
1255
)*
1256
.finish()
1257
}
1258
}
1259
};
1260
}
1261
1262