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
Learn something Project

Deep dive into UnityFS: structure and implementation

Someone asked me if I could extract some images from a popular Chinese mobile game. I accepted the challenge, but things were far more complicated than I expected.

What I knew

  • This game is Unity3D-based.
  • Original assets were encrypted with known algorithm and key. DISCLAIMER: I will not tell you details about encryption.

The story began

I thought I could extract assets I needed with existing tools (e.g. Disunity) but I was proved wrong. Disunity has been refactored, and remaining work is still in progress (at least the moment I write this article). Since resource extraction has not been implemented at this moment, Disunity couldn’t be my choice.

Then I turned to a tool called Unity Assets Bundle Extractor. It did a great job extracting resources I needed graphically. However, acquiring thousands of texture assets from 2000+ isolated files is not an easy job. I tried the command line support but failed (maybe I was too stupid).

Luckily this toolkit provides some API and documentation. Since it was compiled with Microsoft Visual C++ 2010, I was unable to use it directly(C++ ABI constantly changes with every MSVC release). And I was too lazy to write a C wrapper for P/Invoke. But these C++ header files point to a perfect solution – parse file and implement my own UnityFS parser/reader.

Special thank to the UABE project – without these generous header, I would not be able to implement my own parsing and compose this article.

Wow so many projects
Wow so many projects

UnityFS

UnityFS was a new asset bundle format introduced in Unity 5. I am not a Unity3D developer, and I absolutely didn’t know why Unity introduce a new bundle format. But anyway, let’s analyze it.

Things you need to know

  • UnityFS is just bundle of several Unity assets. Each asset contains a collection of serialized Unity objects (e.g. 2D texture, text resources, scene objects, etc.).
  • UnityFS follows a standard Unity file header structure. Let’s call it AssetsBundleHeader06
  • You have to parse asset files in order to extract what you need. There’s bunch of documentation about this. Look into the old Disunity source code for some idea.

UnityFS Header Structure
UnityFS Header Structure

So the header goes like this. There’s a DWORD flags data that matters – it contains some critical information required for decompression and directory parsing. The rule goes like this:

  • (Flags & 0x3F) is compression mode. 0 means no compression, 1 means LZMA and 2/3 means LZ4/LZ4HC.
  • (Flags & 0x40) says whether the bundle has directory info.
  • (Flags & 0x80) says whether the block and directory list is at the end of this bundle file.

C# provides a good BinaryReader that makes things a bit easy. But it can be improved for better Null-terminated String and Big Endian support. Be careful with endianness. Unity utilizes both Big Endian and Little Endian in a single file and personally I didn’t get this. For the sake of convenience, I extended the original BinaryReader for these support. Length of each data type matters – but that’s a basic stuff for CS students.

Code snippet of my simple parser
Code snippet of my simple parser

Compression

UnityFS uses optional block-based compression for streaming (you can read a specific bundle without downloading the whole file). Both LZMA and LZ4* (LZ4Hc, etc.) are supported. The Unity’s proprietary parser and Disunity respects this design. But I just wanted these bundle files, so I decided to read all blocks at once and decompress into a single memory stream.

Decompressed size should match what you get. If not, something must happened.

You can implement your own block-based reader – but my time budget didn’t allow me to do this.

There we go…block and file information!

Following a unknown 16 bytes block, there’s a Big-Endian UInt32 value represents block count in a single package. Each block information contains a Big-Endian UInt32 decompressed size, a Big-Endian UInt32 compressed size and a flag that we might not interested in.

Then a BE UInt32 value represents file count in a single package. Each file information contains file offset we need(BE UInt64), the decompressed size(BE UInt64), a BE UInt32 flag and a Null-Terminated string of file name.

Parse your assets now

With sufficient information we retrieved, we were able to extract raw asset files from a UnityFS bundle. Then what you need is search the Internet for ideas of extracting objects(text resources, 2D texture, etc.) from Unity assets. Good luck on exploring!

Conclusion

In this article, we discussed structure and parsing of UnityFS resource bundle file. For more information about UnityFS and Unity asset files, please research these projects I mentioned in this article.