Zynq 7000: минимальный ассемблерный код для инициализации cpu1 из cpu0

Я пытаюсь выяснить минимальные требования для инициализации cpu1 из cpu0 в конфигурации усилителя на zynq-7000.

У меня есть данный FSBL, который передает u-boot, с помощью которого я копирую обе программы (cpu0/1) из флэш-памяти в разные места в оперативной памяти (с sf read ...).

Я могу запустить обе программы на процессоре 0 из u-boot с помощью go [adr], где adr — начальный адрес любой программы. Я получаю ожидаемый результат на uarts.

Что не работает, так это то, что cpu0 должен запускать cpu1, записывая его начальный адрес в регистр 0xffff_fff0 и после этого выдавая системное событие sev.

Я не включаю какие-либо кэши, MMU или SCU, потому что я хочу, чтобы это было как можно проще (без синхронизации или сбросов), пока я не запустил cpu1. Или это на самом деле проблема, и мне нужно что-то из этого?

В настоящее время я только инициализирую таблицу векторов, печатаю на UART и дополнительно для ядра 0 пытаюсь запустить ядро ​​1:

/* CPU 0 */
.section .vector_table, "x"
.global _init
_init:
    b reset     /* reset handler */
    b .         /* software interrupt */
    b .         /* prefetch abort */
    b .         /* data abort */
    b .         /* reserved */
    b .         /* irq */
    b .         /* fiq */

/* ASCII control chars */
.equ asciiLF, 0x0a
.equ asciiCR, 0x0d

.section .text
    uart1fifo: .word 0xe0001030     /* UART 1 rx/tx fifo register */

reset:
    /* Output "0" on UART 1 */
    ldr r0, uart1fifo
    mov r1, #'0'
    str r1, [r0]
    mov r1, #asciiCR
    str r1, [r0]
    mov r1, #asciiLF
    str r1, [r0]

    /* Set cpu1 start address */
    ldr r0, =0x20000000     /* CPU 1 start address */
    ldr r1, =0xfffffff0     /* Register to point to the CPU 1 start address */
    str r0, [r1]

    /* I added a 0.5s wait here which did not help */

    sev     /* Execute SEV to cause CPU 1 to wake up */

    /* Output "." on UART 1 to indicate that we actually went so far */
    ldr r0, uart1fifo
    mov r1, #'.'
    str r1, [r0]
    mov r1, #asciiCR
    str r1, [r0]
    mov r1, #asciiLF
    str r1, [r0]

    b .     /* Endless loop */

Я вижу «0» и «.». на uart 1, когда я запускаю приведенный выше код на процессоре 0.

/* CPU 1 */
.section .vector_table, "x"
.global _init
_init:
    b reset     /* reset handler */
    b .         /* software interrupt */
    b .         /* prefetch abort */
    b .         /* data abort */
    b .         /* reserved */
    b .         /* irq */
    b .         /* fiq */

/* ASCII control chars */
.equ asciiLF, 0x0a
.equ asciiCR, 0x0d

.section .text
    uart0fifo: .word 0xe0000030     /* UART 0 rx/tx fifo register */

reset:
    /* Output "1" on UART 0 */
    ldr r0, uart0fifo
    mov r1, #'1'
    str r1, [r0]
    mov r1, #asciiCR
    str r1, [r0]
    mov r1, #asciiLF
    str r1, [r0]

    b .     /* Endless loop */

Здесь я вижу «1» на uart 0, когда я запускаю его на процессоре 0.

Я новичок в этом, и я немного потерян. Я упускаю что-то фундаментальное? Что я могу попробовать заставить это работать?

Я смотрел на xapp-1079, но он использует автономные библиотеки Xilinx, и мне очень сложно отфильтровать то, что действительно нужно. Мне нужен минимальный рабочий пример, чтобы я мог портировать его на экзотическую ОС, которую мы запускаем на первом ядре.


person robsn    schedule 26.03.2020    source источник
comment
Можете ли вы указать команды u-boot, которые вы используете для загрузки двоичных файлов.   -  person R.k. Lohana    schedule 15.04.2020
comment
@R.k.Lohana Спасибо за комментарий. Оказалось, что CPU1 не находится в состоянии WFE. Я предполагаю, что он уже был разбужен u-boot, хотя я не вижу причины, по которой он должен это делать, поскольку состояние CPU1 не было SMP. Я поставлю шаги, которые действительно преуспели в ответе.   -  person robsn    schedule 16.04.2020


Ответы (1)


Оказалось, что cpu1 не был в состоянии wfe. Я предполагаю, что u-boot уже разбудил его, хотя он его не использовал, то есть состояние cpu1 не было smp.

Мне пришлось выполнить программный сброс на процессоре 1 и вернуть его в состояние wfe перед выполнением команды sev в соответствии с AR#53828 от xilinx.

Шаги на случай, если ссылка умрет:

  • Сделайте резервную копию регистров, которые будут перезаписаны на следующих шагах.
  • Восстановите код WFE (ожидание события) в области OCM. (Я использовал сборку вместо показанных команд xilinx xsct, поскольку у меня нет доступа к их IDE):
mwr 0xFFFFFF00 0xe3e0000f
mwr 0xFFFFFF04 0xe3a01000
mwr 0xFFFFFF08 0xe5801000
mwr 0xFFFFFF0C 0xe320f002
mwr 0xFFFFFF10 0xe5902000
mwr 0xFFFFFF14 0xe1520001
mwr 0xFFFFFF18 0x0afffffb
mwr 0xFFFFFF1C 0xe1a0f002
  • Напишите инструкцию перехода в 0x0, которая переводит cpu1 из 0x0 в область wfe в 0xffffff00:
mwr 0x00000000 0xe3e0f0ff
  • Выполните программный сброс на процессоре 1:
mwr 0xf8000008 0xdf0d    # slcr unlock
mwr 0xf8000244 0x2       # A9_RST1_ASSERT
mwr 0xf8000244 0x22      # A9_RST1_ASSERT | A9_CLKSTOP1
mwr 0xf8000244 0x20      # A9_CLKSTOP1
mwr 0xf8000244 0x0       # de-assert / start all
mwr 0xf8000004 0x767b    # slcr lock
  • Запишите начальный адрес cpu1 в 0xfffffff0.
  • Выпуск sev.
  • Убедитесь, что cpu1 действительно запущен, или просто подождите несколько циклов.
  • Восстановите резервные копии регистров.
person robsn    schedule 16.04.2020