LoLeOp (Low Level Operation) can access (Read/Write) system memory/information in bit unit.
To get bit 2 at memory address 0xC0000000: Mem8[0xC0000000][2]
To get bit 3, 4, 5 at memory address 0xC0000000: Mem8[0xC0000000][3:5]
To set bit 2 at memory address 0xC0000000 as 1: Mem8[0xC0000000][2] = 1
To set bit 3, 4, 5 at memory address 0xC0000000 as 3: Mem8[0xC0000000][5:3] = 3
In hardware description, it often provides this kind of register tables.
(PCI BAR Address Map as example)
BAR0L: BAR0 Lower Address Map (offset 0x010) Reset: 0000_0000h. +-------+--------------+------+-------------------------------------------+ | Bits | Name | Attr | Description | +-------+--------------+------+-------------------------------------------+ | 31:17 | BaseAddr | R/w | Indicates the Addr[31:17] of the base | | | | | address. | +-------+--------------+------+-------------------------------------------+ | 16:4 | Reserved | | | +-------+--------------+------+-------------------------------------------+ | 3 | Prefetchable | R/w | Indicates BAR 0 is prefetchable. | +-------+--------------+------+-------------------------------------------+ | 2:1 | Type | R/w | Indicates BAR 0 is in a 64-bit access | | | | | space. | +-------+--------------+------+-------------------------------------------+ | 0 | Space | R/w | Indicates BAR 0 is a memory space. | +-------+--------------+------+-------------------------------------------+ BAR0H: BAR0 Upper Address Map (offset 0x014) Reset: 0000_0000h. +-------+--------------+------+-------------------------------------------+ | Bits | Name | Attr | Description | +-------+--------------+------+-------------------------------------------+ | 31:0 | BaseAddr | R/w | Indicates the Addr[63:32] of the base | | | | | address. | +-------+--------------+------+-------------------------------------------+
If PCI bus 1, device 1, function 2 Configuration Space maps in MMIO address is 0xE010A000. Each field of registers BAR0 can be read from 0xE010A010 and 0xE010A014. ( (UINT32 )0xE010A010 and (UINT32 )0xE010A014 )
It is more programmable/Readable with LoLeOp library.
from LoLeOp.Mem import Mem8, Mem16, Mem32, Mem64 # # Read each register fields of BAR0 (Bus 1, Device 1, Function 2) # BAR0L = 0xE010A010 BAR0H = 0xE010A014 print 'Register "Prefetchable": 0x%02X' % Mem32[BAR0L][0] print 'Register "Type": 0x%02X' % Mem32[BAR0L][2:1] print 'Register "Space": 0x%02X' % Mem32[BAR0L][3] print 'Register "BaseAddr": 0x%016X' % (Mem32[Mem32[BAR0L][31:17], Mem32[BAR0H]] << 17) # # Setting BaseAddr of BAR0 as 0xD0000000 >> 17 # Mem32[Mem32[BAR0L][31:17], Mem32[BAR0H]] = 0xD0000000 >> 17
In above Python code Mem32[BAR0L][2:1], It has the same effect of C language.
{ UINT32 BAR0L = 0xE010A010; Printf (L"Register \"Type\": 0x%02X", (*((UINT32 *)0xE010A010) >> 1) & 0x03); }
Mem32[BAR0L] means an instance at address 0xE010A010 with 32 bits width. Mem32[BAR0L][2:1] and Mem32[BAR0L][1:2] means an instance with bit 1 and bit 2 at address 0xE010A010. Mem32[Mem32[BAR0L][31:17], Mem32[BAR0H]] means an instance includes Mem32[BAR0H] and Mem32[BAR0L][31:17].
LoLeOp includes these application classes
Mem8, Mem16, Mem32, Mem64 Memory (including mmio) Read/Write in any memory area. Io8, Io16, Io32, Io64 Io Read/Write Cmos cmos area data read/write CpuId x86 cpuid instruction input EAX and ECX (optional), output EAX, EBX, ECX, EDX. Msr x86 rdmsr/wrmsr instruction with input ECX, output EDX:EAX.
LeLoOp includes these basic classes
_MemArray, _MemCell, _CellConj, rUnionOp
Samples:
Host\AppPkg\LoLeOp\Samples