I/O operations on peripherals are actually the registers for reading and writing peripherals. The x86 or ARM processor we usually use determines on the hardware that the physical address cannot be directly accessed after the wince system is started, therefore, we need to do some work to implement I/O operations. First, you must understand the address ing mechanism in Windows CE. There are two types of address for wince: physical address and virtual address. The difference between CPU Hardware in different architectures leads to different address ing. MIPS and sh x processors, without MMU, define a 1g physical address directly in the CPU and kernel; while x86 and arm have MMU units, define the ing between physical addresses and virtual addresses in oemaddresstable, or call createstaticmapping and nkcreatestaticmapping after the OS starts to implement static ing from virtual addresses to physical addresses. static ing addresses can be used by the operating system kernel to access devices by ISR. If we want to access peripherals in the application, we must establish a dynamic ing relationship between the physical address and the virtual address. We can use virtualalloc and virtualcopy (or directly call the mmmapiospace function) to achieve this. Second, if you are operating on the I/O or storage attached through the bus, you must first convert the BUS address to the system address on the CPU, and then map the physical address to the virtual address. Check the CPU datasheet to find the I/O address. call haltranslatebusaddress () to convert the BUS address to the system address on the CPU, and then call the mmmapiospace function to implement the ing between the virtual and the virtual networks. You can also use transbusaddrtovirtual () directly convert the online address to the virtual address of the system. Third, in general applications, accessing I/O is the virtual address of the cache segment, and the driver must access the virtual address of the non-Cache segment. Simply put, no cache segment virtual address = cache segment virtual address + 0x20000000. To sum up, if the wince kernel (such as Hal) accesses external I/O, you only need to define the ing between physical addresses and virtual addresses in oemaddresstable; if the application or driver wants to access I/O, the work to be done includes: 1. Perform a dynamic ing between the physical and virtual addresses of the CPU, 2. Operate on virtual addresses. In the x86 and ARM-based CPUs, the method for accessing the system memory varies with the program's mode hierarchy. 1. in the kernel mode of the system, you only need to perform static ing between virtual and real addresses in oemaddresstable for access at the oal layer. for example, the ing table of the X86 architecture is as follows: ; Oemaddresstable defines the mapping between physical and virtual address // defines the ing between 4 GB virtual address and MB Storage ; O must be in a readonly Section ; O first entry must be Ram, mapping from 0x80000000-> 0x00000000 ; O each entry is of the format (va, Pa, cbsize) ; O cbsize must be multiple of 4 m ; O last entry must be (0, 0, 0) ; O must have at least one non-zero entry ; Ram 0x80000000-> 0x00000000, size 64 m // map the physical address 0x00000000 to the virtual address 0x80000000 Dd 80000000 H, 0, 04000000 H ; Flash and other memory, if any ; Dd flashva, flashpa, flashsize ; Last entry, all zeros Dd 0 0 0 2. to Access RAM in a driver or application (user mode), you can either use oemaddresstable + virtualcopy, or directly use the mmmapiospace function to create a ing between the physical address and the virtual address of the current process. After oemaddresstable, the physical address of the CPU is mapped to the virtual address of the OS kernel layer. If you need to access the memory in a common application, you also need to use unzip aalloc + virtualcopy to perform a secondary ing from the kernel to the current process (in one case, your OS is configured to full kernel mode, in this case, any application can access the OS Kernel address ). Several key functions are briefly described: Virtualalloc is used to reserve or submit space in the virtual address space of the current process. The unit is 64 kB when it is retained, and 4 kb when it is submitted. Its function prototype is Lpvoid virtualalloc ( Lpvoid lpaddress, // The starting pointer for allocating virtual addresses DWORD dwsize, // size, in bytes DWORD flallocationtype, // type, set to mem_reserve DWORD flprotect // access protection, set to page_noaccess ); Virtualcopy is used to bind a physical address to a static ing virtual address: Bool virtualcopy ( Lpvoid lpvdest, // virtual Destination Address pointer, accept the returned value of virtualalloc Lpvoid lpvsrc, // source physical address pointer DWORD cbsize, // The size must be the same as the virtual address DWORD fdwprotect // access protection type ); Note the fdwprotect parameter. For driver access, you must set it to page_nocache to access the virtual address without a cache segment. If the physical address range of the ing is above 0x1fffffff, page_physical must be used. In this case, lpvsrc must be shifted to eight places to achieve address alignment. (This is determined by the implementation of virtualcopy in the kernel. In that function, if page_physical is used, physaddr is removed from the left to the back, the source code is stored in memory MEM in the private/winceos/coreos/nk/kernel directory. dovirtualcopy in C) Mmmapiospace is used to map physical addresses directly to virtual addresses unrelated to processes. Function prototype: Pvoid mmmapiospace ( Physical_address physicaladdress, Ulong numberofbytes, Boolean cacheenable ); An example of using virtualalloc + copy: the physical address 0x10000000 is mapped to the virtual address space. # Include <windows. h> # Define physaddr (pvoid) 0x10000000) // Physaddr is the physical address of the peripheral // Registers # Define size (4800*4) Lpvoid LPV; Bool Bret; LPV = virtualalloc (0, size, mem_reserve, page_noaccess ); // For a user mode driver, always leave the first // Parameter 0 and use only the flags mem_reserve // And page_noaccess check the return value: LPV = 0 // Is an error Printf (text ("virtualalloc reservation @ % 8.8lx/R/N"), LPV ); Bret = virtualcopy (LPV, physaddr> 8, size, page_readwrite | page_nocache | page_physical ); // The LPV parameter is the virtual address returned // By virtualalloc (). // Always use page_nocache */ // Check the return value: Bret = 0 is an error */ Printf (text ("virtualcopy returned: % d/R/N"), Bret ); // At this point LPV is a virtual address which maps // The I/O registers // At physaddr for size bytes */
|