Jump to content

User:Microfool/Draft:U-Boot4PAZ00

From postmarketOS Wiki

According to rules, I must put Dogfooging tag, but I am sure is it relevant.

🚧 This page is a work-in-progress. Some information contained within may be inaccurate or incomplete.

U-Boot for PAZ00: Porting & Feature Implementation and Reverse Engineering

This is a landing page for a project focused on porting and implementing features of Mainline U-Boot to Nvidia Tegra platforms. Here we can see the progress and problems along the way. (First and foremost, this covers the Tegra2 PAZ00 / AC100 Toshiba.)

Goals

Currently, the status of the working U-Boot implementation by the community is nearly complete β€” approximately 90% of the functionality that can be built and run on the Tegra platform is working. Our task is to finish and test the remaining functionality that has been declared but does not work, is missing, or builds but runs with errors.

We will be posting news here about functionality improvements and feature implementations.

Another goal is to keep and share the results of research and reverse engineering I perform.

Today I work with my own repository, but I have not published many patches publicly; mostly I work on a local repository, and I have a mess with branches.

https://github.com/ZalgoSoft/u-boot

Functionality Known Not to Work

1. ebtupdate command

The command builds but requires tegra_aes. In the device tree (DTC), the hardware AES devices are disabled: these are the audio and video stream processors. There are two of them:

  • compatible = "nvidia,tegra20-bsev";
  • compatible = "nvidia,tegra20-bsea";

It is unknown whether they provide sufficient functionality for AES. When enabled, the tegra_aes driver attaches to them, but executing ebtupdate ends with a segfault crash in svc32 at the moment of accessing IRAM.

TODO: Enable these devices in DTC by default, implement full support for the Tegra crypto device.

2. ums command

Requires setting the first USB controller to UDC mode in the device tree. It builds and runs, but only once. Upon the first termination, it corrupts the tegra-udc driver structure, after which a second run fails to produce a USB gadget mass storage result.

TODO: Enable mode=otg in DTC, investigate USB structure corruption.

3. EFI runtime services

Disabled by default. There are only two of them β€” set time and get time. They work but produce incorrect results.

TODO: Fix EFI interaction with RTC.

Working with NVEC

Currently, support for the Nvidia NVEC device is rudimentary and works with errors. In particular:

  • I2C timings are not respected when working with the keyboard, making it impossible to type with modifier keys like Shift, or capital letters are printed randomly every 10th time.
  • There is no support for other devices within the NVEC subsystem: LEDs, battery, sensors, touchpad/PS2. Additional functionality may also be present, such as working with EC SPI EEPROM or EC debugging. Support for these is not mandatory, but once started, it is hard to stop.

Existing Implementations

There are existing implementations of similar devices in the codebase:

  • CROS_EC β€” its protocol is very similar and much more advanced. The difference is that the device does not operate in I2C slave mode.
  • DesignWare MFD β€” very similar, but it is unclear whether the implementation quality is good or if it is also a workaround.
  • Mainline Linux Kernel NVEC source code β€” well-developed code that works without obvious errors, considering the hardware limitations of the device. It still has a staged status.

Challenges

The CROS_EC and Linux options are complex because the algorithm uses a workqueue. The implementation for NVEC is complex because the device operates in I2C slave mode.

There is no good implementation of tegra_i2c, including for slave mode. The code is fragmented and poorly compatible with other drivers of this class. Tegra U-Boot has no devices that rely on I2C and it is not critical for booting, so its functionality is questionable.

Chipidea USB Gadget Driver Model

There is no support for DM CI (Driver Model Chipidea). As a result, modern gadget functionality does not work.

TODO: Write logic from scratch, using existing routines.

Ethernet USB Gadget Functionality

It should be possible to run PXE boot out of the box using an available method, specifically via USB OTG mode, EDC, or RNDIS. Currently, the driver does not start.

TODO: Investigate buggy behaviour, apply patches.

Flat Image Tree (FIT)

Even not tried to work. Nor binman customization. This is a fresh way to deploy U-Boot binaries stick with kernel and related to EFI support.

Falcon Boot

Even not tried. Will require changes to the SPL part. It is somehow related to FIT. No fit β€” no shit.

FDT or FIT Overlays

By default no support for DTB overlays. May enable this at no cost.

Verified Boot / Secure Boot

It would be interesting to implement emulation for Secure Boot. This would require emulation of a hardware encryption device or some kind of TPM. For now I cannot find EFI tools to work with MOK and key storage which are able to run on ARM32. Anyway useless and barely real.

NVRAM Emulation

Currently there is support for U-Boot variables storage on MMC and EFI variables in a file on the EFI partition. There is a lack of write access to the EFI store and runtime service. Linux drivers require an NVRAM device.

We have enough space on mmcblk0boot1 to keep any data we need to store, to emulate CMOS BIOS, and to propose this capability to EFI, especially in Runtime Mode, access from OS, etc.

TODO: Add and change some code. It should not be too hard.

PSTORE Support and EFI

Even though it is enabled and supported by Linux Kernel, it is not too clear how it should work. I was not able to mount pstore or efi_pstore from Linux and work with it.

This task is relevant to EFI runtimes. If efi_pstore works, we could be able to access EFI variables from runtime.

TODO: Clarify the way to work with pstore.

BIOS Setup Menu

I have a dream: have my very own BIOS menu. Now U-Boot is capable of this, but in a special way: the CEDIT menu system, whose data can be kept in a DTC overlay. We must develop a unified structure for option elements and values, which could be used in other parts of U-Boot. E.g.: boot order, boot menu, splash image, boot devices, recovery case.

Another way is to create an EFI Setup runtime. Such examples can be found on Raspberry Pi or even on older Tegra models.

TODO: I will try both ways.

Wi-Fi Functionality

In reality, U-Boot has no official support for 802.11, much like most PXE/iPXE implementations. It would require implementing wpa_supplicant and crypto libraries.

TODO: Not to be done.

Fastboot

Not able to run. Lack of USB support or something.

EFI Implementation

It would be awesome to run its own full stack EFI with PEIM, but this is not a task of U-Boot. There are projects for older Tegra models, but it seems nobody has built them for Tegra ARM32.

Today's status: some apps can be run: EFI Shell, EFI GRUB.

TODO: Hmmm. Never.

Slow MMC Read During EFI Boot

Every few milliseconds, a keyboard survey executes, which slows IO operations to 20–40 seconds reading the kernel. Another side effect is slowdown of U-Boot timers, which affects, for example, the countdown timer menu.

A workaround for this is the patch:

https://github.com/u-boot/u-boot/commit/0c1cbbbe54437b9ed342026cdc691152da7099b4

Not too much β€” it is temporary, while implementing NVEC support.

My Research

Tools

Tool to extract BMP images from stock bootloaders of any Tegra.

KGDB for ARM

Implemented and successfully ran debugging with GDB and VS Code via Serial line.
It is a huge patch which will barely be accepted into Mainline U-Boot. I still do not know how far I should apply it β€” I mean, limit to only one device (paz00) or expand to the mach-tegra family or even to the entire arch/arm branch.
No code still published.

Bootflow Menu Layout Corruption

Wrote a patch for bootflow menu to respect console size. Published.
Bootflow Menu works closely with the CEDIT component, taking some settings from its part, e.g., theming. Needs further investigation.

EFI Boot

Ran EFI boot for some distros, like Fedora, OpenSUSE, Ubuntu 22.04. Will write RTFM.

Runs out of the box, no need for special tricks. Run from EFI Shell, run from EFI-GRUB, run directly from U-Boot, even from U-Boot EFILINUX sysboot.
The only issue is to find the correct DTB which is fully accepted by the Linux Kernel. For example, some kernels do not take OOPS settings (power management and scaling) from DTB, e.g., Ubuntu 22.04, Ubuntu 24.04 even with their stock DTBs. Even more, Ubuntu 24.04 runs only under special circumstances β€” from its own distro's U-Boot, seems to have some special settings about memory mapping, DTB and initrd storing or something.

Improved NVEC Driver Code

Enhanced code and applied to main. Still in development.

Some Features Built into My U-Boot Variant

UMS

ums 0 mmc 0

Works only the first time. Other times no Mass Storage is exposed. Seems to be somehow broken with the ChipIdea gadget driver. It corrupts USB driver inner structures.

DFU

Successfully run and reproducible. Need to correctly set the dfu_alt_info variable:

setenv dfu_alt_info mmc raw 0 0x1f0000000

USB CDC Terminal

Works poorly. When enabled with:

setenv stdin usb_cdc
setenv stdout usb_cdc
setenv stderr usb_cdc

may go to segfault and freeze. Need to find the right way to run it 100% of the time.

EFI Menu

Successfully run and reproducible. Commands to work with: eficonfig, efidebug, bootmenu -f, bootefi bootmgr.

Need to clarify how to set bootargs or cmdline to pass into the Linux kernel. Does not work for some kernels.

Peripheral Commands

Commands like rtc, pmic, i2c, gpio, pwm, timer, spi, enhanced mmc, usb gadget, DM model standard boot, sysboot. Still not published.
Some of them cannot access peripheral hardware even with Tegra drivers enabled, some corrupt driver data, some have no special Tegra device support.

KB926D EC

Moved here from the AC100 page.

This part contains research and may not be fully trusted.

POST Messages

Getting Debug Messages from EC

To receive debug messages from the EC, connect to the EC_TX80_PDATA output and set the baud rate to 115200. EC_RX80_PDATA is not routed on the board, and its functionality is unknown.

The following messages from the EC controller have become available:

Without a Battery

Connecting the board's power cable, transitioning to the OFF state

The power LED lights up, messages ppL appear, followed by 00,FLASHDEEP with a periodicity of 1 second:

DEEP00,FLASHDEEP00,FLASHDEEP00,FLASHDEEP00,FLASHDEEP00,FLASHDEEP00,FLASHDEEP00,FLASHDEEP00,FLASHDEEP00,FLASHDEEP00,FLASHDEEP00,FLASHDEEP00,FLASH

Pressing the Power button, transitioning from the OFF state

The following messages appear:

ON01,PMUSD
o01,E0,F0,PMUSD
N0N1PMUSD
@REQ=1
N2N3SD0C,ppL

Pressing Ctrl + Esc + Power, transitioning from OFF to APX (Recovery)

ON01,RN0PMUSD
o01,E0,F0,PMUSD
N0N1PMUSD
@REQ=1
N2N3SD0C,`pL

Disconnecting the power cable, transitioning from ON to unpowered

3SD0C (sometimes followed by ,p`L)

In the ON state, when the SYSTEM_RESET# signal is applied

Nothing happens.

Connecting the battery while the power cable is connected

Nothing happens.

With a Battery

Cable plug in, transitioning from unpowered to OFF

00L or 00l or 00,.

Long pressing Power, transitioning from ON to OFF

SD13,F0,F1

Transition from ON to STANDBY / SUSPEND TO RAM

TBD

EC KB926D disassembled

https://github.com/ZalgoSoft/flash-kernel-paz00/blob/main/EN25F20.BIN.c

Most interesting there are protocols for some i2c enpoints - keyboard, ec, ps2, power, fan, leds. Need time to complete format desctioptions.

TX80_DATA messages revealed from source code. There routines with related names, where described logic of printing char sequence. [hex] - means number in hex. List of functions related to letters:

ps2_process_command: \n[hex]S[hex]P[hex]
ps2_write_cw: CW
ps2_write_cr: [hex]I
ps2_write_cmd: [hex]SH
fan_state_machine: f3 F1 F0, N1@CR N2 N3 R
FUN_CODE_0e5f: N0
acpi_ec_cmd_handler: E[hex][hex]\n\n
thermal_print_error: ER[hex][hex][hex]
pm_power_on: ON[hex]	
ps2_process_response: RPO[hex]
pm_set_power_state: SD[hex]
ec_main_task: NVB NVC
print_newline: NV
uart_print_hex_byte: [hex],
acpi_ec_poll: T

So, we can say:

  • any hex number followed by coma,
  • F - related to fan control, on, off and reset.
  • F1 - fan reset,
  • N - power sequence for NVIDIA,
  • ER - actual POST message,
  • SD - power state management,
  • NV - boot mode selection command (B -bootloader or C - consumer).
  • R - recovery mode in some case
  • S (somethime with P) - ps2 related

Still not found: PMU, @REQ=1, L, H, pp, o, DEEP, FLASH. Partially found @RC.

General Architecture

The KB926D EC functions as the central I/O controller of the laptop. It collects data from all peripherals and forwards it to the Tegra 2 via I2C.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                         KB926D EC                               β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  POST β†’ Init β†’ Main Loop β†’ {Keyboard, PS/2, Battery, LID, I2C}  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              β”‚
                              β–Ό I2C (EC_TX80_PDATA ─ UART Debug)
                         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                         β”‚ Tegra 2 β”‚
                         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Functional Blocks

1. POST and Initialization (_POST_Init @ 0x11f6)

What it does How it works
Boot mode check Reads pin 0xFF01 (normal 0x00 / bootloader 0xF0)
Memory clear Clears internal RAM (0x00–0x7F) and external RAM (0xF400–0xF800)
GPIO configuration Configures ports via 0xFCxx registers
UART initialization Configures serial port for debugging
POST code output FLASH C NV β†’ FLASH B (Bootloader)

POST codes on UART (EC_TX80_PDATA):

FLASH     - Flash memory initialization
B / C     - Mode: Bootloader / Customer (Normal)
NV        - Non-Volatile memory check
ER<dump>  - Dump of 0xF54B area (24+16+8 bytes)
RPO       - PS/2 report

2. UART Debugging (EC_TX80_PDATA)

Function Purpose
UART_PutChar Send a character
UART_HexByte Output byte in HEX (e.g., 4C,)
UART_HexDump HEX dump with prefix
UART_DumpMemory Dump 24+16+8 bytes from 0xF54B
UART_PrintNV Output NV string

Example output during normal boot:

FLASH C NV ER<48-byte dump> RPO

3. I2C Master (Communication with Tegra 2)

Function Purpose Address
I2C_Init I2C initialization 0x2622
I2C_Enable Enable I2C master 0x223d
I2C_SetClock Set clock frequency (0x20) 0x2251
I2C_SendData Send data to Tegra 2 0x1368
I2C_MasterTransfer Main I2C transaction 0x86e5
I2C_IsReady Check bus readiness 0x28ba
I2C_Stop Generate STOP condition 0x28ac

I2C Registers:

Address Purpose
0xFF93 Control
0xFF94 Command (3 = START + transmit)
0xFF98 Number of bytes
0xFF99 Counter
0xFF9A Data (low byte)
0xFF9B Data (high byte)
0xFF95 Status

4. Keyboard and PS/2

Function Purpose Address
Keyboard_ScanMatrix Scan keyboard matrix 0x1ace
Keyboard_ProcessKeys Process key presses 0xb71f
PS2_SendReport Send PS/2 report (RPO) 0x1c97
PS2_Command Process PS/2 commands 0x84fb

How it works:

  • Scans 4 matrix rows (DAT_EXTMEM_f51f < 4)
  • Reads pin states via CONCAT11
  • Builds an array of pressed keys
  • Sends report to Tegra 2 via I2C

5. Power Management

Function Purpose Address
Power_Management Main power logic 0xc067
Power_Button_Handler Power button handling 0xd05e
LID_Switch_Handler Lid close sensor 0x8aa7
Timer_Handler Timer handling 0xc7c1
ACPI_Handler ACPI events 0xde00

LID logic:

  • Reads pin state via DAT_EXTMEM_f51d & mask
  • When closed β†’ backlight off
  • When opened β†’ backlight on

Workflow Diagram

Power On
    β”‚
    β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ _POST_Init (0x11f6)                                         β”‚
β”‚   β”œβ”€β”€ Check pin 0xFF01                                      β”‚
β”‚   β”œβ”€β”€ Memory clear                                          β”‚
β”‚   β”œβ”€β”€ Set up GPIO, UART, I2C, SMBus                         β”‚
β”‚   └── Print POST-code "FLASH"                               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    β”‚
    β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ _MainLoop (0x1fa0)                                          β”‚
β”‚   β”œβ”€β”€ Print 'B' or 'C'                                      β”‚
β”‚   β”œβ”€β”€ Print "NV"                                            β”‚
β”‚   └── Endless loop                                          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    β”‚ POST β†’ Init β†’ Main Loop β†’ {Keyboard, PS/2, Battery, LID, I2C} 
    β–Ό I2C (EC_TX80_PDATA ─ UART Debug)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Main Loop (thunk_FUN_CODE_f1f3)                             β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚   β”‚ Keyboard_ScanMatrix() ──► keyboard scan             β”‚   β”‚
β”‚   β”‚ I2C_Dispatch() ─────────► send data to Tegra 2      β”‚   β”‚
β”‚   β”‚ PS2_SendReport() ────────► print "RPO"              β”‚   β”‚
β”‚   β”‚ Power_Management() ──────► power management         β”‚   β”‚
β”‚   β”‚ LID_Switch_Handler() ────► check lid state          β”‚   β”‚
β”‚   β”‚ SMBus_Transaction() ─────► battery polling          β”‚   β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                      β”‚                                      β”‚
β”‚                      β–Ό (loop)                               β”‚
β”‚                   repeat                                    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜