SDV no QNX

Testamos internamente o SDV no hardware. Usamos o QVM no QNX para virtualização. Compartilhamos todos os destinos, documentação e configurações como exemplos.

Pré-requisitos

Esta página pressupõe um QNX pré-configurado e não inclui etapas para criar, configurar ou instalar o QNX no hardware.

Esta página pressupõe que você esteja executando o QNX no hardware arm64 e criando e usando os destinos _arm64 do SDV.

Componentes necessários

  • Um blob da árvore de dispositivos (DTB, na sigla em inglês) para definir o hardware virtual
  • Um kernel do Linux para usar
  • Um ramdisk combinado que inclui todas as propriedades de inicialização do ramdisk
  • Uma transferência de uma cadeia DICE para autenticação de VM do SDV
  • Todas as partições de disco do sistema
  • Uma configuração do QVM da VM

Blob da árvore de dispositivos (DTB)

O QVM gera a maior parte do blob da árvore de dispositivos (DTB) com base na configuração. Portanto, o DTB pode ser mínimo:

/*
 * Copyright (C) 2026 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/dts-v1/;

/ {
    model = "Virtual Machine";
    #address-cells = <2>;
    #size-cells = <2>;

    // This reserved-memory node specifies for the open-dice driver which memory region(s) to
    // expose as /dev/open-dice<n> device(s)
    reserved-memory {
        // The number of u32 cells to represent the address of a memory region
        #address-cells = <2>;
        // The number of u32 cells to represent the size of a memory region
        #size-cells = <2>;
        ranges;
        // The unit address (after the @) must match the address in the reg property
        dice@D1C30000 {
            // The open-dice driver receives this device tree node based on this
            // property.
            compatible = "google,open-dice";
            no-map;
            // The address and the size of the memory region that is passed to the
            // open-dice driver.
            // First two hex numbers (cells) represent the address of the memory region,
            // the last two represent its size (4K, in this case).
            reg = <0x0 0xD1C30000 0x0 0x1000>;
        };
    };
};

Kernel

O SDV usa a imagem de kernel genérica (GKI, na sigla em inglês), e você pode usar a saída de uma build diretamente.

Ramdisk

As informações do ramdisk precisam incluir os diferentes ramdisks que o Android gera e as propriedades de inicialização. Como o QNX não oferece suporte a um bootloader por padrão, é necessário gerar um ramdisk com o formato de dados esperado.

Você pode fazer isso com o script Python a seguir, que concatena vários ramdisks e adiciona o bootconfig (que é o arquivo vendor-bootconfig.img) no formato esperado:

def create_qnx_ramdisk(output: io.BytesIO,
                       ramdisks: Sequence[io.BytesIO],
                       bootconfig: Optional[io.BytesIO]):
  BUFFER_SIZE = 4096

  for ramdisk in ramdisks:
    while buf := ramdisk.read(BUFFER_SIZE):
      output.write(buf)

  # Kernel looks for bootconfig at the end of ramdisk.

  if bootconfig:
    bootconfig_checksum = 0
    bootconfig_size = 0
    while buf := bootconfig.read(BUFFER_SIZE):
      bootconfig_checksum = (bootconfig_checksum + sum(buf)) & 0xFFFFFFFF
      bootconfig_size += len(buf)
      output.write(buf)

    output.write(struct.pack('II', bootconfig_size, bootconfig_checksum))
    output.write(b'#BOOTCONFIG\n')

Cadeia DICE

Em um sistema de produção, o sistema host e o bootloader constroem a cadeia DICE dinamicamente durante o processo de inicialização e fornecem uma cadeia DICE ao convidado para verificar se a imagem é confiável. Como esse requisito pode complicar os fluxos de teste e desenvolvimento, você carrega um snapshot da cadeia DICE.

Para gerar os arquivos dice_handover_instance*, use qualquer build do SDV Cuttlefish. Exemplo:

lunch sdv_core_cf-trunk_staging-userdebug
m
cp $OUT/product/etc/dice_handover_instance* <GUEST>/test_dice_handover

Disco

O QVM oferece suporte a vários formatos para um disco virtual. Nossa configuração de referência usa um arquivo de imagem de disco que contém todas as partições. O bpttool pode gerar esses discos, mas não é desenvolvido ativamente no Android.

Configuração do QVM

A configuração do QVM define a configuração e aponta para os diferentes arquivos. Fornecemos as seguintes configurações de exemplo:

Perguntas frequentes

P: o adb não consegue se conectar à minha VM. O que posso fazer?

R: nessa configuração, o adb usa o Ethernet para se conectar à VM. Você precisa de uma configuração de encaminhamento de porta no QNX que encaminhe solicitações para convidados na porta 5555. É necessário se conectar ao sistema host. Como alternativa, também é possível configurar uma ponte para a VM e se conectar diretamente a ela.

P: o registro do sistema mostra que o IServiceRegistrationAgent está ausente. Por quê?

R: a descoberta de serviços depende de uma configuração de confiança e binder totalmente funcional. Verifique se o OpenDICE foi carregado corretamente e se o HwBinder não está mostrando erros durante a inicialização. Se esses itens não estiverem funcionando, será necessário corrigi-los primeiro.

P: init_open_dice falha. O que aconteceu?

R: os scripts de inicialização carregam as informações de confiança durante a inicialização e limpam o local da memória. Verifique na configuração do QVM se a configuração da linha de comando e os dados pessoais compartilhados no local da memória se encaixam. Verifique também se o local da memória no driver, na configuração do QVM e no DTB corresponde e se o local da memória é gravável.