posts - 20 , comments - 57 , trackbacks - 0

Sunday, March 23, 2014

The ACPICA library (how to build it for WCE8)

ACPI (Advanced Configuration and Power Interface) is an open industry specification co-developed by Hewlett-Packard, Intel, Microsoft, Phoenix, and Toshiba.

Download acpica-win-<date>.zip, acpitests-win-<date>.zip as well as acpica_reference_<x>.pdf and aslcompiler_<y>.pdf from http://acpica.org. Also download ACPISpec50.pdf from http://www.acpi.info to complete your documentation.

Things to know before building the ACPICA library

The ACPICA v5.0 package consists of the following (relevant) directory structure:

Generate
Msvc9 -> AcpiComponents.sln
Unix
Libraries
Source
Common
Compiler
Components
Debugger
Disassemble
Dispatcher
Events
Executer
Hardware
Namespace
Parser
Resources
Tables
Utilities
Include
Os_specific
Service_layers
Tools
Tests

You can use the library in a few ways:

  • Build the Components folder into a C library. This contains the real meat. You typically integrate this library in your kernel.
    • Only use the library to query some info from ACPI tables. That is what I did for the IOAPIC programming
    • The library can also be set up to work directly with ACPI hardware, i.e. power management functionality inside Intel chipset. I didn’t do this.
  • Build the Compiler folder if you are interested in the low level ASL language and AML byte code.
  • Build Tools and Common to create a few executables
    • Test functionality. Mainly intended for ACPICA developers themselves.
    • Realtime querying of ACPI info (integrate in kernel space) from an user space executable
    • Query and debug ACPI tables. Not all board manufacturer “write bug-free” tables. Linux has a way to “overwrite” (replace, redirect) the onboard tables with new “bug-fixed” tables.

I only use the library to query specific ACPI tables (like RSDT, MADT) for APIC programming.

Open AcpiComponents.sln (VS2008) and start a full compile. All projects should build successfully for desktop Windows. See later for details for creating a successfull build.

The solution builds the library and a few executables. We don’t need the executables, but the source code itself is interesting. Depending on the project (library or executable) you build, you need to set a few compiler DEFINEs. This is a bit annoying, because depending on the purpose (target) you want to build, the library source code itself is (re)compiled with different DEFINE sets when used from the executable projects, hence omits or embeds specific pieces of code. The following DEFINEs (excerpt from sources file) worked best for me when compiling the library as a standalone C library.

CDEFINES=$(CDEFINES) -DACPI_LIBRARY -DACPI_USE_SYSTEM_CLIBRARY -DACPI_SINGLE_THREADED -DACPI_DEBUG_OUTPUT -DACPI_DISASSEMBLER -DACPI_DEBUGGER

For more information what compiler DEFINEs to use, have a look at Source\Include\acenv.h

You can choose to build only the library in Source\Components (that is what you need for the WINCE BSP integration), but you can also try to compile the code that is present in the other directories. Although you most likely will copy the source code from it and embed it in your own source code.

As the acpica_reference_7.pdf document explains you need to “fill in” some OS specific glue logic to let the library integrate with your OS environment. Luckily most of this work is already done for desktop Windows, with a few changes this works for Windows CE as well.

Keep in mind that we will use this library in the Windows CE BSP OAL layer in the early boot phase, we don’t really have a full OS at our disposal. No threads, mutexes whats so ever. There is a FullLibC with most of the CRT functionality (e.g. strstr(), memcpy(), memset(), …), but no memory allocation APIs like malloc() and free().

The ACPICA library uses ANSI strings, Windows CE uses UNICODE strings. The library has logging functionality like AcpiOSPrintf(const char* format, ...), but you cannot just redirect it to OALMSG() or NKDebugPrintf() as they would not compile (char <-> wchar_t)

  • To overcome these problems, I added myself my own os_malloc() and os_free() APIs that work on top of NKCreateStaticMapping() and NKDeleteStaticMapping()
  • My own simple ‘ANSI char’ os_printf(), that I redirect myself to OALMSG()

How did I find the missing API’s? Simply by starting to compile the library and solve the linker problems.

I succeeded in NOT making any code changes in the Common, Compiler, Components, Tools folders to build the full package. This was my goal as it should be possible to copy in a newer version of the library at all times (provided the organization structure of the library doesn’t change) At regular intervals an update of the package is released. I did all my work on the January 2014 release (ACPICA v5.0).

Steps to build the ACPICA library for Windows CE 8:

  1. Download the ACPI 5.0 package from https://acpica.org/downloads/windows-source. Download both the “Windows Format Source Code and Build Environment” and “Windows Format Test Suite” package. Unzip both packages in the same folder and only copy the “source” folder in “platform\<Your BSP>\src\acpica” folder. This will give you the following directory structure

C:\WINCE800\platform\<Your BSP>\src\acpica\
Common
Compiler
Components
Debugger
Disassemble
Dispatcher
Events
Executer
Hardware
Namespace
Parser
Resources
Tables
Utilities
Include
Os_specific
Service_layers

Tools

  1. Download my Windows CE BSP source file package for ACPICA and copy them in the same directory structure. It will add the dirs and sources files and some extra source files in the os_specific\service_layers folder
  2. Download the Flex and Bison tools and install them on your PC. The instructions are listed on the https://acpica.org/downloads/windows-source download page. You need them in the next step.
  3. Open Msvc9\AcpiComponents.sln and build the complete solution. You will get many “warning C4001: nonstandard extension 'single line comment' was used” compiler errors, but you can ignore them.
  4. If all projects from the solution were build correctly, copy the generated Yacc and Lex files from “generate\msvc9\AslCompiler<Debug>|<Release>” to “platform\<Your BSP>\src\acpica\compiler”

AslCompiler.y.h
AslCompilerDebug.l.c
AslCompilerDebug.y.c
AslCompilerDebug.y.h
DtParser.y.h
DtParserDebug.l.c
DtParserDebug.y.c
DtParserDebug.y.h
PrParser.y.h
PrParserDebug.l.c
PrParserDebug.y.c
PrParserDebug.y.h

This step is only required if you plan to use the ACPI compiler and want to compile its sources. I didn’t use it, although I do compile it for completeness. Alternatively you can always regenerate them in your build process. I didn’t do that as these files don’t change for a particular version of the ACPICA library and it would complicate the build process. I do regenerate them (once) from the solution when I download a new version of the ACPICA library and copy them over manually.
  1. Rename file "include\acpi.h" to "include\acpica.h". This is to avoid interference with the existing "acpi.h" file that exists already in your CEPC based BSP include folders
  2. Find and replace #include “acpi.h” into #include “acpica.h” (nearly 200 replacements)

The following steps are part of my Windows CE BSP source file package for ACPICA mentioned in step 2. If unpatient, go to step 14.

  1. Create sources files to compile the sub-libraries per folder.
  2. Setup os_specific layer
    1. Copy (rename) file “oswinxf.c” to “oswincexf.c”. This is the ACPICA os adaptation layer
    2. Add file “oswincextr.c”. This will contain missing API’s like malloc(), free(), printf(), …
    3. Add file “tools.c”, “common.c”, “compiler.c”. In these files I copy source code from non-library source code in the package (Tools, Compiler, Common folder) that are handy to use as well.
  3. Add missing os_specific API’s
    1. ACPICA Library (mandatory, Components folder)
    2. Executables (optional, Common, Compiler, Tools folder)
  4. Add os_malloc() and os_free()
  5. Add os_printf()
  6. Add acpica_itf.c. This contains my personal code to extract APIC related stuff from the ACPICA library. More on this in the next blog.
  7. Build

Things to know when you examine the os_specific\service_layers folder

Many API functions that are needed for the compilation and linking were added, but I left them mostly unimplemented with a log message. Only when during runtime I encountered a problem, I decided to implemented them further.

C malloc()  and free() are redirected to os_malloc() and os_free(). These methods work on top of a statically 256K memory buffer where they allocate and free memory from.

AcpiOsPrintf() is the log function where all ACPICA logging is redirected to. This method redirects to vfprintf() (see oswincexf.c). I provided an implementation for vfprintf() and redirect it to my AcpiOs_vsprintf() function (see osprintf.c). This printf() alike version implements the minimum format specifiers and arguments that are used by the ACPICA library. It is a minimalistic implementation of the standard C printf().

The ACPICA library defines global variables via DEFINE_ACPI_GLOBALS and ACPI_INIT_GLOBALS() macro. If you are not careful, you end up defining global variables more than once. Instead I define the global variables myself to avoid linker problems.

I had to set WARNISERROR=0 in the os_specific\service_layers sources file to solve a linker problem I could not fix otherwise. (e.g. warning C4273: 'xxx' : inconsistent dll linkage) .This is unfortunate and annoying, because some compiler errors are not flagged anymore as error. So keep an eye on the output window when you (re)compile this folder. There will always 4 warnings (not treated as error) and there should ONLY be those 4. Any other warning not flagged as error is an error!.

  • warning C4273: 'GetTickCount' : inconsistent dll linkage 
  • warning C4273: 'Sleep' : inconsistent dll linkage
  • warning C4273: 'IsBadReadPtr' : inconsistent dll linkage 
  • warning C4273: 'IsBadWritePtr' : inconsistent dll linkage

The reason is that the prototype sneaks in via #include <windows.h>, but I had to implement them myself (empty). These API’s are decorated with __declspec(dllimport) which cannot be used in early OAL code (of course).

The next step

There is much more to tell/learn about this library, the best way is to read some of its source code and use it. A great help in understanding ACPI and related topics can be found at OsDev.

So far for ACPICA integration in a Windows CE CEPC based BSP. Next blog will deal with APIC programming and how to use ACPI for that purpose.

Useful references:

Posted On Sunday, March 23, 2014 8:26 PM | Comments (3) | Filed Under [ Windows CE Windows Embedded Compact Embedded APIC ACPI ACPICA BSP ]

APIC and ACPI in Windows Embedded Compact 2013

APIC: Advanced Programmable Interrupt Controller

ACPI: Advanced Configuration & Power Interface

ACPICA: ACPI Component Architecture

I needed a timer. A timer with a granularity of < 1msec and not tied to the Windows CE 1msec kernel tick. I wanted to program the timer hardware, raise an interrupt and signal an event to trigger specific code in my application.

I used to do this with custom timer hardware in an FPGA design that resides on my Intel x86 based board (as a PCI device) and my own driver. Now I want to eliminate the FPGA so that I can use cheaper COTS (custom of the shelf) hardware.

The only experience I have with Windows CE is on Intel x86 compatible hardware, mainly with ICH4, ICH7 and NM10 chipsets. And yes, already since early 2000 most Intel chipsets (SouthBridge) include a timer, named HPET : High Precision Event Timer. That sounded promising, but further in depth studying and experiencing with the HPET timers revealed that not all features of the HPET can be used if the IRQ from the HPET is redirected to the (old) PIC interrupt controller. Darn! However all features are available when you use the (new) APIC interrupt controller. This is (was) a problem with the standard CEPC BSP for Windows CE 6/7/8 (and before). The CEPC BSP always uses the old 16 input interrupt controller (actually 2 cascaded 8259 PICs dated back from the 1980’s, but nowadays integrated in the Intel chipsets ICHx and NM10.  At least, with these embedded chipsets I am familiar with).

So if I wanted to use all features of the HPET’s, I needed to adapt the CEPC BSP that it can work with the newer APIC. (I don’t need to say that you first need to clone the CEPC and that you do your changes in the clone to keep the original CEPC source code for further reference, do I? You can find some tips and tricks on the GuruCE website on how that is best done. But I will keep referencing hereafter to the CEPC BSP for ease of sake)

My goal is to be able to use the HPET timers with all its features. I started reading many documents, datasheets, weblinks, books on how to program the Intel APIC interrupt controller.

There is LAPIC (Local APIC) and IOAPIC (InputOutput APIC) and even more xAPIC’s. LAPIC is the APIC located close (integrated) to the CPU. The IOAPIC is typically located in the SouthBridge and deals with all peripheral interrupts. When the IOAPIC processes an interrupt, it “talks” to the LAPIC that on its turn will “talk” to (one of) the CPU(s) that will handle the interrupt. You need to program the IOAPIC in your BSP.

In a multi-cpu design the LAPIC can be used to send IPI (InterProcessor Interrupts) between cpu’s. You might need to specify which cpu will handle the IOAPIC interrupts (I choose typically cpu0). IPI setup is done already in the CEPC BSP for Windows 7/8 due to its SMP support.

I learned that you cannot use the old PIC and new IOAPIC together. You choose one of them. The CEPC BSP uses the old PIC as it is still available for backwards compatibility on all modern Intel chipsets that accompanies the Intel cpu’s. And most BIOSes still support this.

Master 8259

IRQ0

Intel 8253 or Intel 8254 Programmable Interval Timer, aka the system timer

IRQ1

Intel 8042 keyboard controller

IRQ2

not assigned in PC/XT; cascaded to slave 8259 INT line in PC/AT

IRQ3

8250 UART serial ports 2 and 4

IRQ4

8250 UART serial ports 1 and 3

IRQ5

hard disk controller in PC/XT; Intel 8255 parallel ports 2 and 3 in PC/AT

IRQ6

Intel 82072A floppy disk controller

IRQ7

Intel 8255 parallel port 1 / spurious interrupt

Slave 8259 (PC/AT and later only)

IRQ8

real-time clock (RTC)

IRQ9

no common assignment, but 8-bit cards' IRQ2 line is routed to this interrupt.

IRQ10

no common assignment

IRQ11

no common assignment

IRQ12

Intel 8042 PS/2 mouse controller

IRQ13

math coprocessor

IRQ14

hard disk controller 1

IRQ15

hard disk controller 2

Table: default IRQ mapping on 8259

So why did Intel introduced than the IOAPIC? A few reasons are:

  • The IOAPIC has more interrupt inputs. Typically 24 or 32.
  • You can have more than 1 IOAPIC on your motherboard to even increase the number of interrupt lines
  • More interrupts give the board designer more freedom how to route the devices to the IOAPIC –> LAPIC -> CPU
  • You can easily reorganize the priority of the interrupts (which is handy for some devices, like USB that have a higher resource/performance need than e.g. an old RS232 port)
  • You don’t need to share interrupts, again for better performance

Most of the time these days you are interested in the PCI/PCI express interrupts. (what I tell about PCI most of the time also applies to PCI express. They are in many respects backwards compatible towards the software (driver)). I am not going to dive too deep in how PCI works, but every PCI device has the possibility to use 4 PCI interrupts INTA, INTB, INTC, INTD. Those 4 PCI interrupts are routed via a PCI router to the APIC(s). This router can be programmed separately (in fact that is a place where you can determine the PCI interrupt priority routing). Apart from the board layout routing which is determined by the board manufacturer.

Note that the HPET does not reside on the PCI bus, but still its interrupts need to be connected and routed to the IOAPIC.

I learned that in order to program the IOAPIC controller, you need information on how the interrupt lines on your motherboard are routed to the IOAPIC. With the old PIC, there was some agreement that particular IRQ lines were reserved for specific hardware and only a few PIC inputs remained available for the PCI interrupts. Most of the time all PCI interrupts ended up being shared with 1 or 2 of the 8259 input lines, leading to resource congestion.

Where do you find this “routing” information? There are a few mechanisms invented over time

  • PIR$ table
  • MP table
  • ACPI 
  • UEFI (supersedes ACPI)

Apart from UEFI, all other mechanisms are mostly available on modern Intel based motherboard architectures. ACPI is the most complete mechanism (of the first 3), it tells you much more about your motherboard hardware than just the PCI interrupt mapping. I learned then I needed to use ACPI for my IOAPIC BSP programming. Also the CEPC BSP already uses parts of ACPI (e.g. to query the available RAM), so in fact is already partly there.

My first attempt was to extend the existing ACPI code in the CEPC BSP. But “on the road” I learned that there is an Open Source library available designed specifically for using the ACPI mechanism and integrate it in an OS. Enter ACPICA. The ACPICA organization maintains this library. You can download it for free and it is already tailored (it builds) for desktop Windows and Unix/Linux. It took me some time to experiment with it and make it buildable for Windows CE, but now I can tell you how to use it in your Windows CE BSP. I did my porting for Windows CE 8, but it can easily be done also for earlier versions of Windows CE.

More about ACPI in my next article

Interesting links:

http://en.wikipedia.org/wiki/Advanced_Programmable_Interrupt_Controller
https://acpica.org/
http://www.acpi.info/
http://www.uefi.org/


Posted On Sunday, March 23, 2014 1:46 PM | Comments (0) | Filed Under [ Windows CE Windows Embedded Compact Embedded RTOS APIC ACPI ACPICA ]

Powered by: