Как запустить программу на C без ОС на Raspberry Pi?
Я хотел бы поэкспериментировать с использованием Raspberry Pi для некоторых других низкоуровневых встроенных приложений. Единственная проблема заключается в том, что, в отличие от имеющихся плат микроконтроллеров AVR и PIC, Raspberry Pi обычно работает под управлением ОС (например, Raspbian), которая распределяет процессорное время по всем запущенным программам и делает его непрактичным для определенных приложений реального времени.
Недавно я узнал, что, предполагая, что у вас установлен загрузчик, такой как GRUB, для запуска программы на C на x86 (в форме ядра) требуется очень мало фактических настроек, просто программа сборки для вызова основной функции и реального кода C,
Есть ли способ достичь этого с Raspberry Pi? Это был бы отличный способ узнать о низкоуровневом программировании ARM, и у него уже есть несколько сложных периферийных устройств, с которыми можно возиться (USB, Ethernet и т. Д.)
5 ответов
Хотя на Pi возможен голый металл, я бы этого избегал, поскольку Linux становится настолько легковесным и обрабатывает для вас кучу всего.
Вот учебник, с которого можно начать, если вы все еще хотите учиться голому металлу: http://www.valvers.com/open-software/raspberry-pi/step01-bare-metal-programming-in-cpt1/
После всего вышесказанного я просто загрузил бы ваш любимый встроенный дистрибутив Linux (исправление RT может быть предпочтительным в зависимости от ваших требований) и назвал бы его хорошим.
На самом деле Raspberry Pi является одним из самых простых способов программирования голого металла (без операционной системы). У меня есть много примеров на github, чтобы вы начали
https://github.com/dwelch67/raspberrypi
Хорошая особенность raspberry pi заключается в том, что для этого не нужен загрузчик, такой как uboot, есть gpu, который на самом деле сначала запускает микросхему, затем загружает ядро (или голое железо, что угодно) в оперативную память и разветвляет его в так же, как это сделал бы Uboot. Еще одна приятная вещь - вы не можете сделать это так, как вы можете с помощью многих других плат этого класса. Если вы испортите карту, вы вытаскиваете SD-карту, попробуйте еще раз, если вы сдадитесь, снова вставьте SD-карту с Linux и запустить Linux...
Полностью автоматизированный пример с минимальным количеством металла
Протестировано на хосте Ubuntu 16.04, Raspberry Pi 2.
dwelch's является наиболее полным примером, но это минимально простой в настройке привет мир.
Использование:
Вставьте SD-карту на хост
Сделайте изображение:
./make.sh /dev/mmblck0 p1
Куда:
/dev/mmblck0
это устройство SD-картыp1
это первый раздел устройства (/dev/mmblck0p1
)
Вставьте SD-карту на PI
Выключить и снова включить
GitHub upstream: https://github.com/cirosantilli/raspberry-pi-bare-metal-blinker/tree/d20f0337189641824b3ad5e4a688aa91e13fd764
start.S
.global _start
_start:
mov sp, #0x8000
bl main
hang:
b hang
main.c
#include <stdint.h>
/* This is bad. Anything remotely serious should use timers
* provided by the board. But this makes the code simpler. */
#define BUSY_WAIT __asm__ __volatile__("")
#define BUSY_WAIT_N 0x100000
int main( void ) {
uint32_t i;
/* At the low level, everything is done by writing to magic memory addresses.
The device tree files (dtb / dts), which are provided by hardware vendors,
tell the Linux kernel about those magic values. */
volatile uint32_t * const GPFSEL4 = (uint32_t *)0x3F200010;
volatile uint32_t * const GPFSEL3 = (uint32_t *)0x3F20000C;
volatile uint32_t * const GPSET1 = (uint32_t *)0x3F200020;
volatile uint32_t * const GPCLR1 = (uint32_t *)0x3F20002C;
*GPFSEL4 = (*GPFSEL4 & ~(7 << 21)) | (1 << 21);
*GPFSEL3 = (*GPFSEL3 & ~(7 << 15)) | (1 << 15);
while (1) {
*GPSET1 = 1 << (47 - 32);
*GPCLR1 = 1 << (35 - 32);
for (i = 0; i < BUSY_WAIT_N; ++i) { BUSY_WAIT; }
*GPCLR1 = 1 << (47 - 32);
*GPSET1 = 1 << (35 - 32);
for (i = 0; i < BUSY_WAIT_N; ++i) { BUSY_WAIT; }
}
}
ldscript
MEMORY
{
ram : ORIGIN = 0x8000, LENGTH = 0x10000
}
SECTIONS
{
.text : { *(.text*) } > ram
.bss : { *(.bss*) } > ram
}
make.sh
#!/usr/bin/env bash
set -e
dev="${1:-/dev/mmcblk0}"
part="${2:-p1}"
part_dev="${dev}${part}"
mnt='/mnt/rpi'
sudo apt-get install binutils-arm-none-eabi gcc-arm-none-eabi
# Generate kernel7.img
arm-none-eabi-as start.S -o start.o
arm-none-eabi-gcc -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding -c main.c -o main.o
arm-none-eabi-ld start.o main.o -T ldscript -o main.elf
# Get the raw assembly out of the generated elf file.
arm-none-eabi-objcopy main.elf -O binary kernel7.img
# Get the firmware. Those are just magic blobs, likely compiled
# from some Broadcom proprietary C code which we cannot access.
wget -O bootcode.bin https://github.com/raspberrypi/firmware/blob/597c662a613df1144a6bc43e5f4505d83bd748ca/boot/bootcode.bin?raw=true
wget -O start.elf https://github.com/raspberrypi/firmware/blob/597c662a613df1144a6bc43e5f4505d83bd748ca/boot/start.elf?raw=true
# Prepare the filesystem.
sudo umount "$part_dev"
echo 'start=2048, type=c' | sudo sfdisk "$dev"
sudo mkfs.vfat "$part_dev"
sudo mkdir -p "$mnt"
sudo mount "${part_dev}" "$mnt"
sudo cp kernel7.img bootcode.bin start.elf "$mnt"
# Cleanup.
sync
sudo umount "$mnt"
QEMU дружественные примеры голого металла
Проблема с мигалкой заключается в том, что трудно наблюдать за светодиодами в QEMU: https://raspberrypi.stackexchange.com/questions/56373/is-it-possible-to-get-the-state-of-the-leds-and-gpios-in-a-qemu-emulation-like-t для QEMU эмуляции, как-т
Здесь я опишу некоторые настройки QEMU для "голого метала", которые могут быть интересны: Как создавать ARM-программы для "голого метала" и запускать их в QEMU? Запись в UART - это самый простой способ получить выходные данные из QEMU.
бонус
Вот пример x86 для любопытных: Как запустить программу без операционной системы?
https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ - это отличный учебник, и, поскольку они расскажут вам лучший быстрый и грязный способ запуска кода на голом металле, это взломать В дистрибутиве Linux для этого просто скомпилируйте файл kernel.img (с соответствующими параметрами архитектуры) и используйте его, чтобы заменить существующий в дистрибутиве Linux только для этого раздела учебного руководства, по которому вы можете перейти по https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok01.html
Pi может быть немного неоптимальным для того, что вы хотите сделать, так как конструкция SoC такова, что процессор ARM является гражданином второго сорта - это означает, что есть несколько скачков, через которые нужно запустить голую железную программу.
Тем не менее, вы могли бы немного обмануть и использовать U-Boot API, чтобы дать вам доступ к некоторым функциям, которые предоставляет U-Boot, но иметь возможность добавлять свои собственные функции на стороне.