4 votes

<linkscript - adresse de lien différente et adresse de chargement manuelle>

Je suis en train d'écrire un OS jouet pour mon raspberry pi et j'essaie de configurer l'unité de gestion de mémoire (MMU). Je veux diviser la mémoire virtuelle entre 3G:1G, donc je pense que mon code devrait être lié à 0xC0008000, tout en étant chargé à 0x8000 à l'exécution. (Le 0x8000 est l'adresse à laquelle les chargeurs d'amorçage actuels s'attendent à trouver le noyau - puisqu'ils sont conçus pour linux).

Je pense que tout est bien configuré en fouillant avec objdump, mais ça ne fonctionne pas. Après avoir fait quelques tests de débogage avec qemu, je pense que le chargeur d'amorçage ne trouve pas du tout mon code.

Je pense que le problème vient de mon script de liaison, puisque le noyau démarre correctement si je déplace le code de démarrage dans sa propre section qui est à la fois liée et chargée à 0x8000.

J'ai extrait le script et le code minimal. Comme ci-dessous,

$ cat kernel.ld 
ENTRY(_start)

SECTIONS
{
    /* doit == KERNLINK */
    .  = 0xC0008000;

    .text : AT(0x8000) {
        *(.text)
    }

    .bss : {
        *(.bss)
    }

    .data : {
        *(.data)
    }

    .rodata : {
        *(.rodata)
    }
}

-

$ cat source/entry.S 
#include "mem.h"

.globl _start
_start = V2P(entry)

.globl entry
entry:
    loop$:
    b loop$

(Le "b loop$" ne fonctionnera pas car il est généré comme "b·c0008000" au lieu d'utiliser un branchement relatif. Mais peu importe cette partie, le problème est qu'il n'atteint jamais l'entrée).

$ cat source/mem.h 
#define KERNLOAD 0x8000

#define KERNBASE 0xC0000000
#define KERNLINK (KERNBASE+KERNLOAD)

#define V2P(va) ((va) - KERNBASE)

Ce sont les trois seuls fichiers sources. Rien d'intéressant ne devrait être présent dans le Makefile, mais la sortie de make est la suivante,

$ make
arm-none-eabi-gcc -g -Wall -c -o build/entry.o source/entry.S
arm-none-eabi-ld --no-undefined -T kernel.ld build/entry.o  -Map kernel.map -o build/output.elf
arm-none-eabi-objcopy build/output.elf -O binary kernel.img

Et objdump,

$ arm-none-eabi-objdump -h build/output.elf  

build/output.elf:     format de fichier elf32-littlearm

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000004  c0008000  00008000  00008000  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .ARM.attributes 00000014  00000000  00000000  00008004  2**0
                  CONTENTS, READONLY
  2 .debug_line   0000003c  00000000  00000000  00008018  2**0
                  CONTENTS, READONLY, DEBUGGING
  3 .debug_info   00000054  00000000  00000000  00008054  2**0
                  CONTENTS, READONLY, DEBUGGING
  4 .debug_abbrev 00000014  00000000  00000000  000080a8  2**0
                  CONTENTS, READONLY, DEBUGGING
  5 .debug_aranges 00000020  00000000  00000000  000080c0  2**3
                  CONTENTS, READONLY, DEBUGGING

Je commence à penser avoir négligé certains détails évidents mais précieux.

\==== mise à jour ====

Comme indiqué dans ma propre réponse ci-dessous, la confusion est causée par le débogage dans qemu. Les points d'arrêt sont définis par des adresses virtuelles. "b entry" ne fonctionne pas, car GDB pense aux adresses virtuelles alors que l'UMM n'a pas été activée et que nous fonctionnons avec des adresses physiques.

Avant d'activer l'UMM, nous devons donc utiliser "b *0x8000". Cela définit un point d'arrêt qui est correctement atteint. GDB semble encore confus cependant, car il ne montre aucune information de débogage (pas de code source, comme 0x00008004 in ?? ()). Ce n'est pas un gros problème car j'ai la liste produite par "objdump -D".

Après avoir activé l'UMM et sauté vers main, gdb fonctionne parfaitement. Le point crucial est de sauter vers une adresse virtuelle, en utilisant un branchement absolu. b/bl émettrait des sauts relatifs. Donc j'utilise ldr pc =main. bx fonctionne aussi.

1voto

jsz Points 587

Enfin résolu...

Le code et le lien de script ne posent pas de problème. C'est juste que le débogage ne semble pas fonctionner sur le qemu que j'ai utilisé. Cela fonctionne lorsque VMA==LMA, mais dans ce cas, le noyau s'exécute déjà et qemu n'en sait rien. Ou bien, le point d'arrêt est perdu et n'est jamais intercepté par gdb.

Quoi qu'il en soit, en recommençant à zéro et en ajoutant des morceaux un par un, j'ai réussi à le faire fonctionner sur mon rpi (matériel réel), et ensuite cela fonctionne également sur qemu (gdb ne parvient toujours pas à intercepter le point d'arrêt).

Donc ma vraie question devrait être comment déboguer un tel scénario en utilisant qemu/gdb.

(Mon problème initial est résolu en changeant la permission du "domain" en "manager", au lieu d'utiliser "client". Ouais je sais que c'est probablement temporaire et je devrais définir une variable ailleurs).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X