@@ -546,3 +546,317 @@ macro_rules! bitfield {
546546 }
547547 } ;
548548}
549+
550+ #[ cfg( CONFIG_RUST_BITFIELD_KUNIT_TEST ) ]
551+ #[ :: kernel:: macros:: kunit_tests( rust_kernel_bitfield) ]
552+ mod tests {
553+ use core:: convert:: TryFrom ;
554+
555+ use pin_init:: Zeroable ;
556+
557+ use kernel:: num:: Bounded ;
558+
559+ // Enum types for testing `=>` and `?=>` conversions.
560+
561+ #[ derive( Debug , Clone , Copy , PartialEq ) ]
562+ enum MemoryType {
563+ Unmapped = 0 ,
564+ Normal = 1 ,
565+ Device = 2 ,
566+ Reserved = 3 ,
567+ }
568+
569+ impl TryFrom < Bounded < u64 , 4 > > for MemoryType {
570+ type Error = u64 ;
571+ fn try_from ( value : Bounded < u64 , 4 > ) -> Result < Self , Self :: Error > {
572+ match value. get ( ) {
573+ 0 => Ok ( MemoryType :: Unmapped ) ,
574+ 1 => Ok ( MemoryType :: Normal ) ,
575+ 2 => Ok ( MemoryType :: Device ) ,
576+ 3 => Ok ( MemoryType :: Reserved ) ,
577+ _ => Err ( value. get ( ) ) ,
578+ }
579+ }
580+ }
581+
582+ impl From < MemoryType > for Bounded < u64 , 4 > {
583+ fn from ( mt : MemoryType ) -> Bounded < u64 , 4 > {
584+ Bounded :: from_expr ( mt as u64 )
585+ }
586+ }
587+
588+ #[ derive( Debug , Clone , Copy , PartialEq ) ]
589+ enum Priority {
590+ Low = 0 ,
591+ Medium = 1 ,
592+ High = 2 ,
593+ Critical = 3 ,
594+ }
595+
596+ impl From < Bounded < u16 , 2 > > for Priority {
597+ fn from ( value : Bounded < u16 , 2 > ) -> Self {
598+ match value & 0x3 {
599+ 0 => Priority :: Low ,
600+ 1 => Priority :: Medium ,
601+ 2 => Priority :: High ,
602+ _ => Priority :: Critical ,
603+ }
604+ }
605+ }
606+
607+ impl From < Priority > for Bounded < u16 , 2 > {
608+ fn from ( p : Priority ) -> Bounded < u16 , 2 > {
609+ Bounded :: from_expr ( p as u16 )
610+ }
611+ }
612+
613+ bitfield ! {
614+ struct TestU64 ( u64 ) {
615+ 63 : 63 field_63;
616+ 61 : 52 field_61_52;
617+ 51 : 16 field_51_16;
618+ 15 : 12 field_15_12 ?=> MemoryType ;
619+ 11 : 9 field_11_9;
620+ 1 : 1 field_1;
621+ 0 : 0 field_0;
622+ }
623+ }
624+
625+ bitfield ! {
626+ struct TestU16 ( u16 ) {
627+ 15 : 8 field_15_8;
628+ 7 : 4 field_7_4; // Partial overlap with `field_5_4`.
629+ 5 : 4 field_5_4 => Priority ;
630+ 3 : 1 field_3_1;
631+ 0 : 0 field_0;
632+ }
633+ }
634+
635+ bitfield ! {
636+ struct TestU8 ( u8 ) {
637+ 7 : 0 field_7_0; // Full byte overlap.
638+ 7 : 4 field_7_4;
639+ 3 : 2 field_3_2;
640+ 1 : 1 field_1;
641+ 0 : 0 field_0;
642+ }
643+ }
644+
645+ // Single and multi-bit fields basic access.
646+ #[ test]
647+ fn test_basic_access ( ) {
648+ // `TestU64`.
649+ let mut val = TestU64 :: zeroed ( ) ;
650+ assert_eq ! ( val. into_raw( ) , 0x0 ) ;
651+
652+ val = val. with_field_0 ( true ) ;
653+ assert ! ( val. field_0( ) . into_bool( ) ) ;
654+ assert_eq ! ( val. into_raw( ) , 0x1 ) ;
655+
656+ val = val. with_field_1 ( true ) ;
657+ assert ! ( val. field_1( ) . into_bool( ) ) ;
658+ val = val. with_field_1 ( false ) ;
659+ assert ! ( !val. field_1( ) . into_bool( ) ) ;
660+ assert_eq ! ( val. into_raw( ) , 0x1 ) ;
661+
662+ val = val. with_const_field_11_9 :: < 0x5 > ( ) ;
663+ assert_eq ! ( val. field_11_9( ) , 0x5 ) ;
664+ assert_eq ! ( val. into_raw( ) , 0xA01 ) ;
665+
666+ val = val. with_const_field_51_16 :: < 0x123456 > ( ) ;
667+ assert_eq ! ( val. field_51_16( ) , 0x123456 ) ;
668+ assert_eq ! ( val. into_raw( ) , 0x0012_3456_0A01 ) ;
669+
670+ const MAX_FIELD_51_16 : u64 = :: kernel:: bits:: genmask_u64 ( 0 ..=35 ) ;
671+ val = val. with_const_field_51_16 :: < { MAX_FIELD_51_16 } > ( ) ;
672+ assert_eq ! ( val. field_51_16( ) , MAX_FIELD_51_16 ) ;
673+
674+ val = val. with_const_field_61_52 :: < 0x3FF > ( ) ;
675+ assert_eq ! ( val. field_61_52( ) , 0x3FF ) ;
676+
677+ val = val. with_field_63 ( true ) ;
678+ assert ! ( val. field_63( ) . into_bool( ) ) ;
679+
680+ // `TestU16`.
681+ let mut val = TestU16 :: zeroed ( ) ;
682+ assert_eq ! ( val. into_raw( ) , 0x0 ) ;
683+
684+ val = val. with_field_0 ( true ) ;
685+ assert ! ( val. field_0( ) . into_bool( ) ) ;
686+ assert_eq ! ( val. into_raw( ) , 0x1 ) ;
687+
688+ val = val. with_const_field_3_1 :: < 0x5 > ( ) ;
689+ assert_eq ! ( val. field_3_1( ) , 0x5 ) ;
690+ assert_eq ! ( val. into_raw( ) , 0xB ) ;
691+
692+ val = val. with_const_field_7_4 :: < 0xA > ( ) ;
693+ assert_eq ! ( val. field_7_4( ) , 0xA ) ;
694+ assert_eq ! ( val. into_raw( ) , 0xAB ) ;
695+
696+ val = val. with_const_field_15_8 :: < 0x42 > ( ) ;
697+ assert_eq ! ( val. field_15_8( ) , 0x42 ) ;
698+ assert_eq ! ( val. into_raw( ) , 0x42AB ) ;
699+
700+ // `TestU8`.
701+ let mut val = TestU8 :: zeroed ( ) ;
702+ assert_eq ! ( val. into_raw( ) , 0x0 ) ;
703+
704+ val = val. with_field_0 ( true ) ;
705+ assert ! ( val. field_0( ) . into_bool( ) ) ;
706+ assert_eq ! ( val. into_raw( ) , 0x1 ) ;
707+
708+ val = val. with_field_1 ( true ) ;
709+ assert ! ( val. field_1( ) . into_bool( ) ) ;
710+ assert_eq ! ( val. into_raw( ) , 0x3 ) ;
711+
712+ val = val. with_const_field_3_2 :: < 0x3 > ( ) ;
713+ assert_eq ! ( val. field_3_2( ) , 0x3 ) ;
714+ assert_eq ! ( val. into_raw( ) , 0xF ) ;
715+
716+ val = val. with_const_field_7_4 :: < 0xA > ( ) ;
717+ assert_eq ! ( val. field_7_4( ) , 0xA ) ;
718+ assert_eq ! ( val. into_raw( ) , 0xAF ) ;
719+ }
720+
721+ // `=>` infallible conversion.
722+ #[ test]
723+ fn test_infallible_conversion ( ) {
724+ let mut val = TestU16 :: zeroed ( ) ;
725+
726+ val = val. with_field_5_4 ( Priority :: Low ) ;
727+ assert_eq ! ( val. field_5_4( ) , Priority :: Low ) ;
728+ assert_eq ! ( val. into_raw( ) & 0x30 , 0x00 ) ;
729+
730+ val = val. with_field_5_4 ( Priority :: Medium ) ;
731+ assert_eq ! ( val. field_5_4( ) , Priority :: Medium ) ;
732+ assert_eq ! ( val. into_raw( ) & 0x30 , 0x10 ) ;
733+
734+ val = val. with_field_5_4 ( Priority :: High ) ;
735+ assert_eq ! ( val. field_5_4( ) , Priority :: High ) ;
736+ assert_eq ! ( val. into_raw( ) & 0x30 , 0x20 ) ;
737+
738+ val = val. with_field_5_4 ( Priority :: Critical ) ;
739+ assert_eq ! ( val. field_5_4( ) , Priority :: Critical ) ;
740+ assert_eq ! ( val. into_raw( ) & 0x30 , 0x30 ) ;
741+ }
742+
743+ // `?=>` fallible conversion.
744+ #[ test]
745+ fn test_fallible_conversion ( ) {
746+ let mut val = TestU64 :: zeroed ( ) ;
747+
748+ val = val. with_field_15_12 ( MemoryType :: Unmapped ) ;
749+ assert_eq ! ( val. field_15_12( ) , Ok ( MemoryType :: Unmapped ) ) ;
750+ val = val. with_field_15_12 ( MemoryType :: Normal ) ;
751+ assert_eq ! ( val. field_15_12( ) , Ok ( MemoryType :: Normal ) ) ;
752+ val = val. with_field_15_12 ( MemoryType :: Device ) ;
753+ assert_eq ! ( val. field_15_12( ) , Ok ( MemoryType :: Device ) ) ;
754+ val = val. with_field_15_12 ( MemoryType :: Reserved ) ;
755+ assert_eq ! ( val. field_15_12( ) , Ok ( MemoryType :: Reserved ) ) ;
756+
757+ // `field_15_12` is 4 bits wide (0-15); `MemoryType` only covers 0-3, so 4-15 return `Err`.
758+ let raw = ( val. into_raw ( ) & !:: kernel:: bits:: genmask_u64 ( 12 ..=15 ) ) | ( 0x7 << 12 ) ;
759+ assert_eq ! ( TestU64 :: from_raw( raw) . field_15_12( ) , Err ( 0x7 ) ) ;
760+ }
761+
762+ // Test that setting an overlapping field affects the overlapped one as expected.
763+ #[ test]
764+ fn test_overlapping_fields ( ) {
765+ let mut val = TestU16 :: zeroed ( ) ;
766+
767+ val = val. with_field_5_4 ( Priority :: High ) ; // High == 2 == 0b10.
768+ assert_eq ! ( val. field_5_4( ) , Priority :: High ) ;
769+ assert_eq ! ( val. field_7_4( ) , 0x2 ) ; // Bits 7:6 == 0, bits 5:4 == 0b10.
770+
771+ val = val. with_const_field_7_4 :: < 0xF > ( ) ;
772+ assert_eq ! ( val. field_7_4( ) , 0xF ) ;
773+ assert_eq ! ( val. field_5_4( ) , Priority :: Critical ) ; // Bits 5:4 == 0b11.
774+
775+ // `field_7_0` should encompass all other fields.
776+ let mut val = TestU8 :: zeroed ( )
777+ . with_field_0 ( true )
778+ . with_field_1 ( true )
779+ . with_const_field_3_2 :: < 0x3 > ( )
780+ . with_const_field_7_4 :: < 0xA > ( ) ;
781+ assert_eq ! ( val. into_raw( ) , 0xAF ) ;
782+
783+ val = val. with_field_7_0 ( 0x55 ) ;
784+ assert_eq ! ( val. field_7_0( ) , 0x55 ) ;
785+ assert ! ( val. field_0( ) . into_bool( ) ) ;
786+ assert ! ( !val. field_1( ) . into_bool( ) ) ;
787+ assert_eq ! ( val. field_3_2( ) , 0x1 ) ;
788+ assert_eq ! ( val. field_7_4( ) , 0x5 ) ;
789+ }
790+
791+ // Checks that bits not mapped to any field are left untouched.
792+ #[ test]
793+ fn test_unallocated_bits ( ) {
794+ let gap_bits = ( 1u64 << 62 ) | 0x1FC ;
795+
796+ let set_all_fields = |val : TestU64 | {
797+ val. with_field_63 ( true )
798+ . with_const_field_61_52 :: < 0x155 > ( )
799+ . with_const_field_51_16 :: < 0x123456 > ( )
800+ . with_field_15_12 ( MemoryType :: Device )
801+ . with_const_field_11_9 :: < 0x5 > ( )
802+ . with_field_1 ( true )
803+ . with_field_0 ( true )
804+ } ;
805+
806+ // Gap bits to 0.
807+ let val = set_all_fields ( TestU64 :: from_raw ( 0 ) ) ;
808+ assert_eq ! ( val. into_raw( ) & gap_bits, 0 ) ;
809+
810+ // Gap bits to 1.
811+ let val = set_all_fields ( TestU64 :: from_raw ( gap_bits) ) ;
812+ assert_eq ! ( val. into_raw( ) & gap_bits, gap_bits) ;
813+ }
814+
815+ #[ test]
816+ fn test_try_with ( ) {
817+ let val = TestU64 :: zeroed ( ) . try_with_field_51_16 ( 0x123456 ) . unwrap ( ) ;
818+ assert_eq ! ( val. field_51_16( ) , 0x123456 ) ;
819+
820+ let err = TestU64 :: zeroed ( ) . try_with_field_51_16 ( u64:: MAX ) ;
821+ assert_eq ! ( err, Err ( :: kernel:: error:: code:: EOVERFLOW ) ) ;
822+
823+ let val = TestU64 :: zeroed ( )
824+ . try_with_field_51_16 ( 0xABCDEF )
825+ . and_then ( |p| p. try_with_field_0 ( 1 ) )
826+ . unwrap ( ) ;
827+ assert_eq ! ( val. field_51_16( ) , 0xABCDEF ) ;
828+ assert ! ( val. field_0( ) . into_bool( ) ) ;
829+ }
830+
831+ // `from_raw`/`into_raw` and `From`/`Into` round-trips.
832+ #[ test]
833+ fn test_raw ( ) {
834+ let raw: u64 = 0xBFF0_0000_3123_3E03 ;
835+ let val = TestU64 :: from_raw ( raw) ;
836+ assert_eq ! ( u64 :: from( val) , raw) ;
837+ assert ! ( val. field_0( ) . into_bool( ) ) ;
838+ assert ! ( val. field_1( ) . into_bool( ) ) ;
839+ assert_eq ! ( val. field_11_9( ) , 0x7 ) ;
840+ assert_eq ! ( val. field_51_16( ) , 0x3123 ) ;
841+ assert_eq ! ( val. field_15_12( ) , Ok ( MemoryType :: Reserved ) ) ;
842+ assert_eq ! ( val. field_61_52( ) , 0x3FF ) ;
843+ assert ! ( val. field_63( ) . into_bool( ) ) ;
844+
845+ let raw: u16 = 0x42AB ;
846+ let val = TestU16 :: from_raw ( raw) ;
847+ assert_eq ! ( u16 :: from( val) , raw) ;
848+ assert ! ( val. field_0( ) . into_bool( ) ) ;
849+ assert_eq ! ( val. field_3_1( ) , 0x5 ) ;
850+ assert_eq ! ( val. field_7_4( ) , 0xA ) ;
851+ assert_eq ! ( val. field_15_8( ) , 0x42 ) ;
852+
853+ let raw: u8 = 0xAF ;
854+ let val = TestU8 :: from_raw ( raw) ;
855+ assert_eq ! ( u8 :: from( val) , raw) ;
856+ assert ! ( val. field_0( ) . into_bool( ) ) ;
857+ assert ! ( val. field_1( ) . into_bool( ) ) ;
858+ assert_eq ! ( val. field_3_2( ) , 0x3 ) ;
859+ assert_eq ! ( val. field_7_4( ) , 0xA ) ;
860+ assert_eq ! ( val. field_7_0( ) , 0xAF ) ;
861+ }
862+ }
0 commit comments