Categories
Project Windows IoT

So you told me you want to run Windows on a Calculator

Running Windows on a consumer calculator was a dream until the appearance of HP Prime G2 Graphing Calculator. This calculator has the most superior hardware specification among the market so far. And more importantly, HP switched to ARMv7-A on the calculator (!)

HP Prime G2 SoC Specification. The NXP i.MX 6ULL (Ultra Lite) SoC features a uni-core Cortex A7 processor.

Previous work

My friend Wenting Zhang (Zephray) has done the fundamental reverse engineering about GPIO assignments and technical information regarding this calculator. In addition, he managed to port a functional U-Boot and Linux on it.

According to TI-Planet, the calculator comes with a lot of test pins including SD/MMC, JTAG and UART.

Sarah (winocm) explored the possibility of running Windows RT on Qemu platform. Some information has been changed as of 2019, but the post is still worth reading.

Microsoft also partnered with NXP to enable Windows 10 IoT on iMX SoCs. Given these facts, this calculator should be technically capable of running Windows 10 IoT (or generically saying Windows on ARM.)

Pushing the limit of Windows System Requirements

Microsoft Docs site outlined the system requirements for the Windows 10 family. To run the small footprint (still large compared to Linux), the system should have a x86/x64/ARMv7/AArch64 processor, at least 256MB memory and 2GB storage. The device should also has a functional UEFI firmware and full ACPI & SMBIOS tables.

There isn’t sufficient onboard storage in this case (and Windows doesn’t support raw SLC NAND flash either), but USB device can be attached to the calculator and acts as a boot device.

Sarah has summarized ARMv7 architectural requirements for running Windows. The requirements have changed a bit across years, so here is my new summary on this:

System processor: ARMv7-A compatible processor with VFPv3+VFP HalfPrec, VFPv4 is also okay
Memory: At least 256MB of RAM (can probably do less)
Peripherals:
    - System timer (either architectural or vendor-specific)
    - ARM Generic Interrupt Controller (GIC) or Broadcom Interrupt Controller on BCM2835/2836/2837, both CPU and Distributor Interface. GICv2 or higher is required if GIC is present and declared.
    - Framebuffer
    - Supported UART, either NS16550, BCM283x or some vendor-specific IP (in the case of Qualcomm and NXP)
    - Firmware: UEFI 2.3 or higher

In this case the calculator meets those hard requirements. However the SoC runs in 396MHz by default, significantly slower than the 400MHz/1GHz baseline. Also I only report about 250MB memory to the system while the minimum requirement is 512MB with user interface. However, it boots!

The SoC runs at 396MHz according to WinDbg’s cpuinfo

I think we can probably further push the limit. If I recall correctly, Windows Server Nano requires about 150MB memory to boot on amd64 systems.

UEFI and ACPI

I’ve talked about UEFI implementations several times in the past so there isn’t anything new. Basically the UEFI consists a set of device drivers and core components from TianoCore. ACPI tables are copied from the Windows IoT iMX Project Mu Repo and stripped down.

I chainload the UEFI from U-Boot. iMX does not enable unaligned memory access by default and this causes a lot of troubles in UEFI DXE and BDS phases. You should enable it as soon as possible.

 mrc   p15, 0, r0, c1, c0, 0
 bic   r0, r0, #2
 mcr   p15, 0, r0, c1, c0, 0 

Using a compiler with hardware float support is also helpful for speed up the boot speeed (30s -> 4s.) Also Windows mandates VFPv3+ support on ARMv7 platforms.

The screen initialization as well as some I/O mux assignments are completed in U-Boot. The current U-Boot does not support 24/32bpp Serial RGB LCD interface operation, so I added the Serial RGB support by referring the implementation of iMX FrameBuffer in Linux Kernel. The code has not yet been upstreamed to the master but I should do this later.

Demo of Serial RGB LCD Interface’s operation in U-Boot

UEFI just picks up the FrameBuffer allocated by U-Boot and registers the Graphics Output Protocol. Unfortunately the screen resolution cannot satisfy the minimum 80*25 console requirements, so I patched Console DXE components by adding a new 40*12 mode.

EDK2 component asserts because the screen resolution cannot meet 80*25 minimum console requirements.

Prior to the hack in console components I did some trick by reporting 640*480 output in the UEFI GOP protocol. The trick also helped me getting diagnostics information from Windows Boot Manager because 320*240 isn’t sufficient to display the error code. I periodically run block-transfer (BLT) from FrameBuffer to the filesystem and saved BMP files on a USB drive.

Hack that makes 80*25 mode available with some graphical artifacts
The 40*12 mode
Windows Boot Manager’s behavior in 320*240
Block-transfer (BLT) on the FrameBuffer

As for USB support, fortunately the USB IP in iMX6 is fully standard-compliant and in-box support is included in recent Windows versions. Therefore once I configured the OTG controller into host mode and pass the MMIO region to UEFI and Windows, it works magically without problems. However, Wenting and me have not yet figured out the VBus source on the OTG port (we assume some DC-DC circuit that controlled by SoC or PMIC but this hypothesis has not yet been verified) so the port has to be powered using some external voltage source for proper functionalities.

SMBIOS

Make sure you properly report memory size and address regions in SMBIOS, or Windows will do some incredibly weird things (TM).

Windows debugger fails to read memory due improper SMBIOS configuration.
Windows debugger fails to read memory due improper SMBIOS configuration.

Timer and HAL Extensions

Windows will access to some assumed and invalid memory address if no usable system timer is found.

Windows will fail to boot if no Interrupt Controller or System Timer is found. A system time can be registered using either GTDT table (ARM architectural table) or HAL extensions via CSRT table.

iMX6ULL comes with three timer complexes: iMX GPT (Generic Purpose Timer), EPIT (Enhanced Periodic Timer) and ARM Architectural Timer. ARM Architectural Timer is new to iMX6UL/ULL since earlier iMX6 SoCs use cores such as Cortex A15 which lacks proper Architectural Timer support. Microsoft has implemented a EPIT HAL extension for the system timer, but it was not loaded at first due to a hardware ID mismatch in CSRT table and system image (I downloaded an earlier FFU for iMX6 Solo.) So in the case when no timer is available, Windows will desperately attempt to initialize an assumed timer and the system crashes due to invalid memory access.

The iMX6ULL datasheet does mention the presence of architectural timer but doesn’t say much about the initialization procedure. The EDK2 code can initialize the timer counter but GIC PPI (Per Processor Interrupt) does not work properly. However, Windows successfully initializes and utilizes the timer via GTDT table.

At this moment the UEFI utilizes EPIT timer and turns it off upon the hand-off to Windows. Windows picks up the generic timer and initializes it then. At some later point the UEFI might switch to generic timer too, with the proper initialization procedure.

A few peripherals needs the Smart DMA (SDMA) controller HAL extension and it isn’t too hard to load it.

Show me that in action!

[Security] 3rd party image[0] can be loaded after EndOfDxe: VenHw(0D51905B-B77E-452A-A2C0-ECA0CC8D514A,004118020000000000)/USB(0x0,0x0)/USB(0x2,0x0)/HD(1,GPT,F9ADAEA9-E8DE-4291-B191-5DABA6DC1215,0x800,0x100000)/\efi\boot\bootarm.efi.
 InstallProtocolInterface: 5B1B31A1-9562-11D2-8E3F-00A0C969723B 8F257028
 ConvertPages: failed to find range 10000000 - 100EEFFF
 Loading driver at 0x0008E9D6000 EntryPoint=0x0008E9E7511 bootmgfw.efi
 InstallProtocolInterface: BC62157E-3E33-4FEC-9920-2D3B36D750DF 8F28EB10
 ProtectUefiImageCommon - 0x8F257028
 0x000000008E9D6000 - 0x00000000000EF000
 InstallProtocolInterface: 752F3136-4E16-4FDC-A22A-E5F46812F4CA 8FBFF88C
 ConvertPages: failed to find range 102000 - 102FFF
 Disabling EPIT timer on ExitBootServicesEventSetUefiImageMemoryAttributes - 0x000000008F78A000 - 0x0000000000003000 (0x0000000000000008)
 SetUefiImageMemoryAttributes - 0x000000008F787000 - 0x0000000000003000 (0x0000000000000008)
 SetUefiImageMemoryAttributes - 0x000000008F784000 - 0x0000000000003000 (0x0000000000000008)
 SetUefiImageMemoryAttributes - 0x000000008F77F000 - 0x0000000000005000 (0x0000000000000008)
 SetUefiImageMemoryAttributes - 0x000000008F77C000 - 0x0000000000003000 (0x0000000000000008)
 SetUefiImageMemoryAttributes - 0x000000008F779000 - 0x0000000000003000 (0x0000000000000008) 
A video that demonstrates Windows 10 IoT on a calculator.

Where’s Secure Boot and TPM?

There are not really necessary. However, since OP-TEE has iMX6/7/8 support, you can run a secure monitor in TrustZone (TZ) and provide those services via Secure Monitor Calls from EL1/PL1.

In fact the official iMX Windows IoT implementation comes with OP-TEE bundled. I skipped it due to the concern of memory utilization.

But what about drivers?

Windows 10 IoT BSP repository have a lot of available iMX6/7/8 driver sources available. USB works out of box as mentioned. The calculator touchscreen and keypad drivers need to be implemented.

The touchscreen and keypad drivers are available in the Linux kernel tree so it should not be too hard to port them on Windows.

Can it boot Windows RT 8.1?

Maybe. Update: Windows RT 8.1 won’t boot, but later versions do. Windows PE won’t boot in ramdisk mode because 256MB memory isn’t sufficient. I haven’t got flat boot mode work, it enters some loop with no further initialization once devices are enumerated (including the USB drive I used.)

HP Prime G2 calculator runs Windows, running calculator application.
Notepad running on the calculator

But I want to boot Linux too!

You have two options:

  • Just use U-Boot to load zImage, device tree and initrd
  • Move FD, MpPark and FrameBuffer memory regions to the top of the system memory region and leave the lower 128MB memory unoccupied

Load Linux via either GRUB or directly from EFISTUB. It boots and here’s a snippet of the boot log:

EFI stub: Exiting boot services and installing virtual address map…
 Disabling EPIT timer on ExitBootServicesEventSetUefiImageMemoryAttributes - 0x000000008F97B000 - 0x0000000000003000 (0x0000000000000008)
 SetUefiImageMemoryAttributes - 0x000000008F978000 - 0x0000000000003000 (0x0000000000000008)
 SetUefiImageMemoryAttributes - 0x000000008F973000 - 0x0000000000005000 (0x0000000000000008)
 SetUefiImageMemoryAttributes - 0x000000008F970000 - 0x0000000000003000 (0x0000000000000008)
 SetUefiImageMemoryAttributes - 0x000000008F96D000 - 0x0000000000003000 (0x0000000000000008)
 SetUefiImageMemoryAttributes - 0x000000008F96A000 - 0x0000000000003000 (0x0000000000000008)
 Booting Linux on physical CPU 0x0
 Linux version 4.14.98-g371433a62906-dirty (imbushuo@bc-macbookpro) (gcc version 7.4.1 20181213 [linaro-7.4-2019.02 revision 56ec6f6b99cc167ff0c2f8e1a2eed33b1edc85d4] (Linaro GCC 7.4-2019.02)) #2 PREEMPT Thu Nov 14 03:10:29 EST 2019
 CPU: ARMv7 Processor [410fc075] revision 5 (ARMv7), cr=10c53c7d
 CPU: div instructions available: patching division code
 CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
 OF: fdt: Machine model: HP Prime G2 Calculator
 Memory policy: Data cache writeback
 efi: Getting EFI parameters from FDT:
 efi: EFI v2.70 by EDK II
 efi:  ACPI 2.0=0x8f49b000  SMBIOS=0x8f9a8000  SMBIOS 3.0=0x8f9a6000
 OF: reserved mem: failed to allocate memory for node 'linux,cma'
 CPU: All CPU(s) started in SVC mode.
 Built 1 zonelists, mobility grouping on.  Total pages: 64516
 Kernel command line: zImage.efi root=/dev/ram0 rw initrd=/rootfs.cpio.gz dtb=/imx6ull-14x14-prime.dtb

If you are using the NXP Linux configuration, it will eventually panic because it reads initrd memory address from device tree or some predefined configuration settings and of course the initrd is loaded as somewhere else in UEFI. You need to remove those settings and make the configuration more generic.

But why?

People talk about running Windows on random devices so I want to troll them by the end of the year.

How about other projects? What’s the next thing?

They will continue. So far, I need to implement more drivers, enable UEFI boot from on-board NAND, implement a calculator-friendly UEFI boot user interface and explore the possibility of booting stock HP PPL OS from my UEFI.

Acknowledgements

This project is partially derived from Microsoft’s Windows 10 IoT BSP for NXP SoC platforms. I would also like to thank Wenting for sending me his Prime G2 with UART lines soldered for debugging.

Categories
Dev Learn something Project

A deep dive into Apple Touch Bar – Part I

Recent Apple MacBook Pro models are usually equipped with long OLED touch display that officially named “Touch Bar” that substitutes the traditional Function (Fn) key row. Internally, this thing is called Dynamic Function Row (DFR) according to the naming prefix of related system components. In Boot Camp Windows installations, the Touch Bar acts as basic media and function keys without advanced graphical capabilities.

Given the fact that the Touch Bar is implemented by either Apple T1 or T2 chip, it is certain that one or more connection technology such as USB are utilized for the host communication. However, the communication protocol remains unknown for a long time due to the availability(cost) of device and the nature of typical technology users.

Third-party developers have developed applications that simulates Touch Bar on the host (x86) system. A quick inspection through the source code reveals a library that generates the continuous stream that contains the graphical content on the Touch Bar. It suggests that the content on Touch Bar is pre-rendered on the x86 system and gets transferred to the ARM side (T1/T2). Since T1 and T2 are both connected on the USB bus, packet captures were conducted over the USB bus.

Packet capture over the USB bus

During packet capture sessions, the pattern of periodic large packet transfers were observed. However, the size is not fully deterministic, but mostly it is larger than 54000 bytes. More image with certain patterns (single color, rainbow, etc.) were transferred to help analysis the binary structure. With sufficient samples, the following characteristics and structs were concluded:

  • A semi-static header is present for each frame update.
  • Raw pixels are transferred in BGR24 format.
  • There was a static padding at the end.
typedef struct _DFR_GENERIC_REQUEST_CONTENT {
	UINT32 RequestKey;
	UCHAR Reserved[8];
	UINT32 End;
} DFR_GENERIC_REQUEST_CONTENT, *PDFR_GENERIC_REQUEST_CONTENT;

typedef struct _DFR_GENERIC_REQUEST {
	DFR_GENERIC_REQUEST_HEADER Header;
	DFR_GENERIC_REQUEST_CONTENT Content;
} DFR_GENERIC_REQUEST, *PDFR_GENERIC_REQUEST;

typedef struct _DFR_UPDATE_FB_REQUEST_CONTENT {
	UINT16 Reserved0;
	UINT8 FrameId;
	UINT8 Reserved1;
	UINT32 Reserved2;
	UCHAR Reserved3[24];
	UINT16 BeginX;
	UINT16 BeginY;
	UINT16 Width;
	UINT16 Height;
	UINT32 BufferSize;
} DFR_UPDATE_FB_REQUEST_CONTENT, *PDFR_UPDATE_FB_REQUEST_CONTENT;

typedef struct _DFR_UPDATE_FB_REQUEST {
	DFR_GENERIC_REQUEST_HEADER Header;
	DFR_UPDATE_FB_REQUEST_CONTENT Content;
} DFR_UPDATE_FB_REQUEST, *PDFR_UPDATE_FB_REQUEST;
Categories
Dev Learn something

Debugging early ARM ACPI bringup without UART

Sometimes it is not feasible to get UART access on consumer blackbox devices (e.g. Lumia 950XL). In the case of ARM ACPI debugging, the lack of UART access may make early boot debug incredibly difficult.

Starting from Linux Kernel 5.0, it is now possible to enable FrameBuffer-based early kernel display. All you need to do is:

  • Enable Earlyprintk and Earlycon support. By default it is on.
  • Enable EFI FrameBuffer display device.
  • Enable EFI FrameBuffer Earlycon device.
  • (Optional) Enable PSCI checker to verify PSCI functionality.

Then pass the following parameters in bootloader:

earlycon=efifb,mem

Then you are good to go.

Categories
Dev Status

Status Update: Lumia950XLPkg

It’s almost a year for Lumia950XLPkg and its derivative projects. A new touch-enabled graphical menu will be added in coming weeks (I’ve posted a picture on Twitter).

UEFI: Finalized

There are a few more things to do (mostly bugfix) after the PCIe initialization (Talkman variant will be released later). Here’s a list of current backlog:

  • Touch-enabled menu for boot device selection and basic settings
  • Time synchronization with BootShim
  • Environment variable (e.g. MDP settings) passthrough
  • PCIe initialization for Talkman
  • ACPI fix

This UEFI project will be finalized on March or April, then I will transfer the ownership to LumiaWoA organization.

Lumia UEFI menu, based on LittleVGL and EDK2

Mainline Linux & Android

Lumia950XLPkg makes it possible to run mainline Linux on Lumia 950 XL. So far I’ve brought up main components including touchscreen and Bluetooth. Wi-Fi will be available once I figure out the way to declare firmware-initialized PCIe bus in device tree.

camphoto_351212254.jpg
Debian on Lumia 950 XL demonstrating Bluetooth HCI status

Freedreno is also possible. However, it may takes significant time to figure out proper MIPI DSI commands for display panel enablement.

There are other people working on Android-side project for Lumia 950 XL, but I am unable to disclosure the progress at this moment.

Joining Microsoft / LinkedIn

I am excited to announce that I am joining Microsoft / LinkedIn in the coming summer. But the employment may have potential CoI (conflict of Interest) on projects that I am currently working on. I wish I can continue on making the next big thing 😛

Categories
Windows IoT 玩物丧志

Give TianoCore/EDK2 on AArch64 a hand in 2018

Also posted here: Bringing up Windows 10 AArch64 on a $50 Single Board Computer

Windows on ARM is not a new topic. There are some guys attempted to bring up Windows RT and Windows 10 on Qemu (ARM/AArch64 target). It even runs on Raspberry Pi 3. Obviously it is not a Snapdragon 835-only thing. We can give it a hand on our own Single Board Computers.

This article covers some important details in Dragonboard 410c SBC’s aa64 UEFI implementation.

Contents

    • Windows Boot Requirements
    • Bootstrapping your own EDK2/TianoCore UEFI
    • Memory Allocation / Memory Management Unit
    • UEFI Flash Definition
    • First-stage Bootloader (Little Kernel)
    • Persistent NVRAM Support
    • A “Working” RTC
    • Multi-processor startup (PSCI)

Windows Boot Requirements (AArch64)

  • AArch64 architecture processor. It seems that AArch64 cryptography extension is required too (Raspberry Pi 3 randomly throws UNSUPPORTED_PROCESSOR bugcheck, rs4 fixed the issue). The bugcheck is raised in Errata Check (a hardcoded ID check).
  • For multi-processor systems, either Microsoft ARM Multi-processor Parking Protocol or ARM PSCI interface shall be implemented. All current Windows 10 IoT ARM32 platforms implement former one.
  • A working interrupt controller. Most AArch64 SoC cores include ARM GIC, so there’s little work to do here. The only exception I know is BCM2837. Windows has inbox Broadcom interrupt controller support (for the sake of Raspberry Pi). But if your SoC has additional third party interrupt controller, you need to supply your own HAL extension library. There is few documentation for this available though…
  • A working processor timer. If not, supply your own HAL extension library.
  • Complete ACPI 5.1/6.0 and UEFI 2.3+ implementation. Do not try to use Das U-Boot’s EFI implementation; it’s broken.

These requirements are fairly similar to ARM SBBR certification requirements. If your SBC has a working EDK2/TianoCore UEFI, then you are probably good to go. Bootstrapping your own EDK2 is pretty easy too.

Bootstrapping your own EDK2/TianoCore

The board I used (DragonBoard 410c) doesn’t have a known EDK2/TianoCore implementation. So I have to build my own. This repository for Raspberry Pi 3 is a good start point and reference for you.

You need to do these things in UEFI:

  • Initialize serial output (for debugging) and Memory Management Unit (MMU). Refer to your platform datasheet for device memory address allocation.
  • Retrieve required information from pre-UEFI environment and build Hand-off Blocks (HOB) for DXE phase
  • Initialize processor (exception vector, etc.) in DXE phase.
  • Initialize required peripherals (GPIO, GIC, eMMC, USB, RTC, Display…) in DXE phase.
  • Initialize UEFI services (variable services) in DXE phase.
  • Jump to BDS phase, start Windows Boot Manager or something else.

Memory Allocation / Memory Management Unit

Memory allocation is a platform-specific thing. Check your platform HRD to get some idea about MMU and memory allocation. For Snapdragon 410, check out Qualcomm LM80-P0436-13.

UEFI Flash Definition

Our UEFI FD starts at 0x80200000. Update your tokens in platform definition and flash definition:

And the first piece code should be your SEC initialization code (without relocation).

Little Kernel (mentioned below) will be responsible for jumping into UEFI FD at 0x80200000 and handing off execution. If you want, you can actually removes Android-specific header and device tree validation in LK (apps/aboot.c).

First-stage bootloader (Little Kernel)

DragonBoard 410c uses ARM Secure Monitor Call to switch to AArch64 mode (See Qualcomm LM80-P0436-1 for more information). The stock close-sourced SBL doesn not recognize AArch64 ELF files (later model should). LK performs basic platform initialization (UART, eMMC, MMU, etc.) A modified variant LK also initializes FrameBuffer for U-Boot. We can make it work for our UEFI too.
Windows requires UEFI provide a BGRA FrameBuffer. To achieve this, we need to modify pixel unpack pattern in platform/msm_shared/mdp5.c:


case 32:
/* Windows requires a BGRA FB */
writel(0x000236FF, pipe_base + PIPE_SSPP_SRC_FORMAT);
writel(0x03020001, pipe_base + PIPE_SSPP_SRC_UNPACK_PATTERN);

You can either specify a hard-coded address for FrameBuffer, or have a random piece of memory block to transfer information (pixel format, width, height, etc.) to UEFI. UEFI SEC phase retrieve the information, allocate HOB block and transfer information to DXE phase. A simple FrameBuffer driver retrieve information from HOB block, initializes UEFI Graphics Output Protocol. For optimal performance, initialize this piece of memory block as write-through cache memory in MMU initialization.

Persistent NVRAM Support

For persistent NVRAM support, it’s a good idea to use eMMC as storage device. This implementation demonstrates how to simulate NVRAM using eMMC and a piece of memory. I slightly modified it make it work for Qualcomm devices:

  • If eMMC NVRAM region is corrupted or uninitialized, provision it and perform a platform warm reset so I don’t get a synchronous exception in volatile variable initialization phase.
  • Modify dependency relationship to prevent “device not found” error in BlockRamVariable DXE initialization.

Windows Boot Manager depends on a “working” Real Time Clock for miscellaneous purposes. APQ8016/MSM8916 has a RTC on its PMIC processor PM8916. To access RTC services, read/write SPMI registers (see Qualcomm LM80-P0436-36). If you are lazy, just use Xen fake RTC in ArmVirtPkg.
To enable PM8916 RTC, set SPMI register 0x6046 to enabled state, then read 0x6048 and three following bits.

Note: I implemented my own PMIC protocol called PM8916Protocol that read/writes PMIC register on SPMI bus, slave #0. This RTC library is based on Xen face RTC library from ArmVirtPkg.

4KB / 64KB Page Table

Revised: On certain SoC platforms, runtime memory allocations are not comply with 64KB alignment requirements. There are two solutions, either round these memory regions to 64KB alignments, or go to MdePkg/Include/AArch64/ProcessorBind.h:


///
/// The stack alignment required for AARCH64
///
#define CPU_STACK_ALIGNMENT 16

///
/// Page allocation granularity for AARCH64
///
#define DEFAULT_PAGE_ALLOCATION_GRANULARITY (0x1000)

///
/// For the sake of our SBCs
///
#define RUNTIME_PAGE_ALLOCATION_GRANULARITY (0x1000)

ARM Erratum

I randomly hit crashes (synchronous exception) during my UEFI development. After some investigation, it seems that the problem is related to load/store commands. (See ARM Errata 835769, 843419) To prevent random crashes, add these two flags to your GCC compiler:

Multi-Processor Startup (PSCI)

For platforms that implement ARM PSCI, indicate PSCI support in ACPI FADT table:


EFI_ACPI_6_0_HW_REDUCED_ACPI | EFI_ACPI_6_0_LOW_POWER_S0_IDLE_CAPABLE, // UINT32 Flags
{
EFI_ACPI_6_0_EMBEDDED_CONTROLLER,
0,
0,
EFI_ACPI_6_0_DWORD,
0x009020B4
}, // EFI_ACPI_6_0_GENERIC_ADDRESS_STRUCTURE ResetReg
1, // UINT8 ResetValue
EFI_ACPI_6_0_ARM_PSCI_COMPLIANT, // UINT16 ArmBootArchFlags
EFI_ACPI_6_0_FIXED_ACPI_DESCRIPTION_TABLE_MINOR_REVISION, // UINT8 MinorRevision

Typically you don’t need HVC call for PSCI. If you did so (and your platform doesn’t support HVC call for PSCI), you will get a INTERNAL_POWER_ERROR bugcheck with first parameter of 0x0000BEEF.
If you indicates PSCI support, you don’t have to provide parking protocol version in your ACPI MADT table. Simply set it to 0. Here’s one example:


[02Ch 0044 1] Subtable Type : 0B [Generic Interrupt Controller]
[02Dh 0045 1] Length : 50
[02Eh 0046 2] Reserved : 0000
[030h 0048 4] CPU Interface Number : 00000000
[034h 0052 4] Processor UID : 00000000
[038h 0056 4] Flags (decoded below) : 00000001
Processor Enabled : 1
Performance Interrupt Trigger Mode : 0
Virtual GIC Interrupt Trigger Mode : 0
[03Ch 0060 4] Parking Protocol Version : 00000000
[040h 0064 4] Performance Interrupt : 00000017
[044h 0068 8] Parked Address : 0000000080301000
[04Ch 0076 8] Base Address : 0000000000000000
[054h 0084 8] Virtual GIC Base Address : 0000000000000000
[05Ch 0092 8] Hypervisor GIC Base Address : 0000000000000000
[064h 0100 4] Virtual GIC Interrupt : 00000000
[068h 0104 8] Redistributor Base Address : 0000000000000000
[070h 0112 8] ARM MPIDR : 0000000000000000
[078h 0120 1] Efficiency Class : 00
[079h 0121 3] Reserved : 000000

See ARM Juno reference platform to get some idea about crafting ACPI tables.

That’s it! Welcome to Windows 10 Userland.

Spend some nights writing Windows drivers. 😛

Windows 10 PE runs on a Spandragon 410 processor.
Windows 10 PE runs on a Spandragon 410 processor.

Categories
Windows Runtime Apps

Hack TwinUI to force Windows Store Apps run on low resolution screens

Windows 8 and Windows 8.1 has a minimum screen resolution constraint for Windows Store Apps (aka. Metro Apps or whatever). If the screen resolution doesn’t meet requirement, user will see a prompt indicating the resolution is too low for these applications.

However, on certain platforms (like phones and single-board computers), it is not convenient to change resolution. Recently I am trying Windows RT 8.1 on Lumia 640 XL. Qualcomm has the resolution hard-coded in platform configuration, so I was unable to change the resolution. 1280 * 720 is not sufficient for Store Apps.

But there was an exception – the PC settings (aka. Immersive Control Panel) app. It always opens regardless of current resolution settings. So how can I force other applications to launch?

Let’s turn to TwinUI.dll. It’s one of the core components of shell infrastructure. Start IDA Pro, load TwinUI with symbols from Microsoft. Go ahead and search the existence of PC settings app. All Windows Store Apps are associated with a package family identifier. Let’s search it. In this case, it’s windows.immersivecontrolpanel_cw5n1h2txyewy.

Bingo. We found it in some functions.

PC Settings Package Family ID is hardcoded in TwinUI.dll. This function has been patched by me, so it doesn't reflect actual situation you get from official Microsoft binary.
PC Settings Package Family ID is hardcoded in TwinUI.dll. This function has been patched by me, so it doesn’t reflect actual situation you get from official Microsoft binary.

By checking it’s references, we learned that layout checking routine verifies whether it is a desktop application, or PC settings app when resolution doesn’t meet requirements. Either you can patch layout checking routine or PC settings PFN verification routine. I decided to patch the second one, however patching the first is probably a better idea.

On ARMv7-A platform, I simply patched initial register store operation and the branch. Instruction BLX call was replaced with a simple NOP(MOV R0, R0).

Patched function
Patched function

There are two version of the PC settings check routines, so I need to patch both. The other one is similar to this one. Patching the layout verification routine (actually a better idea, as this patch will have some trouble when launch files from desktop) / patching on other architectures should be similar to this one.

Categories
Dev Project Windows Runtime Apps

Migrate legacy UWP project system to MSBuild-based

When Microsoft decided to adopt MSBuild on .NET Core platform, project.json was not dropped immediately until first toolchain RTM arrives. Dotnet Development on Universal Windows Platform Development leverages .NET Core too, but the depreciation progress is significantly slower than other .NET Core platforms due to historical reasons. UWP uses project.json for package management and MSBuild for builds.

In Visual Studio 2017 April Update, Microsoft finally migrates new UWP projects to full MSBuild-based project system. But our projects, which creates on early 2015, doesn’t get an auto migration as expected. Hence we decided to migrate them manually for additional benefits like better toolchain stability and advanced customization features.

Reminder: Do not attempt to use “dotnet migrate” CLI command, it won’t work for UWP projects.

Migration Prerequisites

  • Notify all your team members. Make sure everyone has Visual Studio 2017 with April update installed.
  • If you have continuous integration environment configured, make sure build agents have NuGet 4.1 or higher installed (3.5 or 4.0 won’t work).
  • Lock VCS during migration to prevent additional incidents. (We’re using TFVC for source management so that it will be easy)

Migration

  • Clean up all projects (including bin and obj directories)
  • Iterate all project directories
  • Find C# project file, open with your favorite editor.
  • Add following property group before project file lists:
<PropertyGroup>
    <RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>

Okay, you’ve completed the first step. Then open your project.json file. Migrate all NuGet packages references as the picture below.

Package Reference
Package Reference

Finally, remove project.json and additional files like project.lock.json, *.nuget.targets, *.nuget.props. (Or your will get lots of warning that may lead .NET Native compilation fail)

Do it for every project. Then open Visual Studio, restore NuGet packages for all projects, build to validate and submit changes.

Categories
Dev Windows Runtime Apps

The Windows “Gatekeeper” Internals

Windows 10 Insider Preview 15046 introduces the Windows-flavor “Gatekeeper“. It is similar to Gatekeeper in macOS, with some minor differences.

First of all, Windows “Gatekeeper” doesn’t block the execution of applications that don’t require installation. I tried to run PuTTY, a popular tool on Windows and it works.

Secondly, Windows “Gatekeeper” is based on Microsoft SmartScreen, which means disabling SmartScreen will turn it off too. Prior to application execution, SmartScreen will send file hash and publisher information(including certificate thumbprint) to Microsoft’s server, then SmartScreen server send back metadata including application reputation. Response is signed with a specific key that will be checked in client side for message integrity.

Unlike macOS, attempt to start application from console(e.g. Command Prompt and PowerShell) will trigger “Gatekeeper”.

Attempt to start application from PowerShell
Attempt to start application from PowerShell

The window is web-based. Although you can’t modify the response directly(no one wants to deal with sha256RSA unless the key leaks), you can attach a debugger to have some fun with it.

"Rickrolling" in Windows SmartScreen
“Rickrolling” in Windows SmartScreen

Microsoft claims that this feature is opt-in for most Windows SKUs (except Windows 10 Cloud AFAIK), and it is not revalent to UMCI (User-mode Code Integrity), which is enforced in Windows 10 Cloud.