Comment exécuter un programme C sans OS sur le Raspberry Pi?

j'aimerais expérimenter en utilisant le Raspberry Pi pour différentes applications intégrées de bas niveau. Le seul problème est que, contrairement aux cartes à microcontrôleur AVR et PIC disponibles, Raspberry Pi exécute généralement un OS (comme Raspbian) qui distribue le temps CPU dans tous les programmes en cours d'exécution et le rend impraticable pour certaines applications en temps réel.

j'ai récemment appris que, en supposant que vous avez un bootloader comme GRUB installé, l'exécution d'un programme C sur x86 (sous la forme d'un noyau) prend très peu de configuration réelle, juste un programme d'assemblage pour appeler la fonction principale et le code C réel.

y a-t-il un moyen d'y parvenir avec un Raspberry Pi? Ce serait une excellente façon d'en apprendre davantage sur la programmation ARM de bas niveau, et il y a déjà quelques périphériques Complexes avec lesquels il faut se frotter (USB, Ethernet, etc.).)

31

5 réponses

alors que le métal nu est possible sur le Pi, Je l'éviterais car Linux devient si léger et gère un tas de choses pour vous.

voici un tutoriel pour vous aider à démarrer si vous voulez encore apprendre le métal nu: http://www.valvers.com/open-software/raspberry-pi/step01-bare-metal-programming-in-cpt1 /

avec tout ce que cela dit, je voudrais juste charger votre distribution Linux embarqué préféré (RT patched might être privilégiées en fonction de vos besoins).

13
répondu It'sPete 2015-04-24 03:00:36

en fait, le Raspberry Pi est l'un des bras les plus faciles à programmer métal nu (pas de système d'exploitation) j'ai de nombreux exemples à github pour vous aider à commencer

https://github.com/dwelch67/raspberrypi

une bonne chose à propos du raspberry pi est qu'il n'a pas besoin d'un bootloader comme uboot, il y a un gpu qui apporte réellement la puce en premier puis il charge le noyau (ou application métal nu, quoi que ce soit) en ram et des branches à elle de la même manière qu'uboot aurait. Une autre bonne chose est que vous ne pouvez pas le bricoler comme vous pouvez avec tant d'autres planches dans cette classe, si vous faites des erreurs, vous tirez la carte sd, essayez à nouveau, si vous abandonnez, puis mettre une carte sd avec linux sur elle de nouveau et exécuter linux...

33
répondu old_timer 2016-11-14 15:05:16

Entièrement automatisé minimale métal nu clignotant exemple

testé sur Ubuntu 16.04 host, Raspberry Pi 2.

dwelch est l'exemple le plus complet , mais c'est un minimum facile à configurer hello world.

Utilisation:

  1. insérez la carte SD sur l'hôte

  2. faire l'image:

    ./make.sh /dev/mmblck0 p1
    

    où:

    • /dev/mmblck0 est le dispositif de la carte SD
    • p1 est la première partition du dispositif ( /dev/mmblck0p1 )
  3. Inset de la carte SD sur PI

  4. coupez l'alimentation électrique et sur

enter image description here

GitHub upstream: https://github.com/cirosantilli/raspberry-pi-bare-metal-blinker/tree/d20f0337189641824b3ad5e4a688aa91e13fd764

commence.S

.global _start
_start:
    mov sp, #0x8000
    bl main
hang:
    b hang

principal.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-friendly métal nu exemples

le problème avec le clignotant est qu'il est difficile d'observer les LEDs dans QEMU: /q/why-is-a-method-call-shown-as-not-covered-when-the-code-within-the-method-is-covered-with-emma-39652/"/q/how-to-make-bare-metal-arm-programs-and-run-them-on-qemu-47967/">Comment faire des programmes de bras en métal nu et les exécuter sur QEMU? écrire à L'UART est la façon la plus facile d'obtenir la sortie de QEMU.

Bonus

voici un exemple x86 pour les curieux: comment exécuter un programme sans système d'exploitation?

11

https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os / est un excellent tutoriel, et comme ils vont vous dire la meilleure façon rapide et sale d'exécuter du code sur du métal nu est de détourner une distro linux, pour ce faire, il suffit de compiler au noyau.img (avec les options d'architecture appropriées) et l'utiliser pour remplacer l'existant dans la distribution linux pour que cette partie du tutoriel, vous pouvez aller à: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok01.html#pitime

3
répondu joshbooks 2015-04-24 03:17:09

le Pi peut être un peu sous-optimal pour ce que vous voulez faire, puisque la conception de SoC est telle que le CPU BRAS est un citoyen de seconde classe-ce qui signifie qu'il ya des cerceaux à sauter à travers pour obtenir un programme en métal nu en cours d'exécution sur elle.

cependant, vous pourriez tricher un peu et utiliser le U-Boot API pour vous donner accès à certaines des fonctionnalités U-Boot fournit, mais être en mesure d'ajouter vos propres fonctionnalités sur le côté.

2
répondu unixsmurf 2015-04-24 10:27:00