Essayer de comprendre l’utilisation du pointeur de fonction

C’est la fonction dans le fichier bootm.c de u-boot à partir duquel le kernel est lancé:

/* Subcommand: GO */ static void boot_jump_linux(bootm_headers_t *images, int flag) { #ifdef CONFIG_ARM64 void (*kernel_entry)(void *fdt_addr); int fake = (flag & BOOTM_STATE_OS_FAKE_GO); kernel_entry = (void (*)(void *fdt_addr))images->ep; debug("## Transferring control to Linux (at address %lx)...\n", (ulong) kernel_entry); bootstage_mark(BOOTSTAGE_ID_RUN_OS); announce_and_cleanup(fake); if (!fake) kernel_entry(images->ft_addr); #else unsigned long machid = gd->bd->bi_arch_number; char *s; void (*kernel_entry)(int zero, int arch, uint params); unsigned long r2; int fake = (flag & BOOTM_STATE_OS_FAKE_GO); kernel_entry = (void (*)(int, int, uint))images->ep; s = getenv("machid"); if (s) { ssortingct_strtoul(s, 16, &machid); printf("Using machid 0x%lx from environment\n", machid); } debug("## Transferring control to Linux (at address %08lx)" \ "...\n", (ulong) kernel_entry); bootstage_mark(BOOTSTAGE_ID_RUN_OS); announce_and_cleanup(fake); if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) r2 = (unsigned long)images->ft_addr; else r2 = gd->bd->bi_boot_params; if (!fake) kernel_entry(0, machid, r2); #endif } 

J’ai du mal à comprendre comment kernel_entry fonctionne ici. Surtout dans l’avant dernière ligne, il est utilisé comme:

  kernel_entry(0, machid, r2); 

Alors, où est la définition de kernel_entry() ? Je n’ai pas réussi à trouver l’intégralité du code source u-boot et du kernel.

Mettre à jour

Je reformule ma question ici:

Supposons que kernel_entry est un pointeur sur une fonction et est défini comme suit:

 bootm_headers_t *images kernel_entry = (void (*)(int, int, uint))images->ep; 

Ensuite, quelque part dans le programme, il est appelé comme:

  kernel_entry(0, machid, r2); 

Je comprends être un pointeur, kernel_entry devrait stocker l’adresse d’une fonction. Mais je veux comprendre quelles opérations seront effectuées sur les trois arguments. Pourquoi avons-nous ces arguments?

La déclaration de la variable kernel_entry et son type, qui est un pointeur sur une fonction prenant int , int , uint et retournant void (probablement la partie la plus déroutante), est ici:

 void (*kernel_entry)(int zero, int arch, uint params); 

Assignation, images->ep est converti en pointeur de fonction de signature souhaité et placé dans la variable:

 kernel_entry = (void (*)(int, int, uint))images->ep; 

Enfin, la fonction s’appelle:

 kernel_entry(0, machid, r2); 

Veuillez noter que si CONFIG_ARM64 est défini, la fonction sur kernel_entry pointe kernel_entry a une signature différente:

 void (*kernel_entry)(void *fdt_addr); //takes one void* param and returns void 

U-Boot a l’image du kernel dans son espace mémoire adressable, lit une adresse contenue dans cette image (sur images-> ep) et se twig sur cette adresse de point d’entrée.

La “définition de kernel_entry ()” est en réalité dans le code source du kernel, le libellé “start” dans arch / arm / boot / compressé / head.S est ce que vous recherchez.

Pour comprendre le processus de démarrage du kernel, le premier tutoriel d’OMI est le chapitre 5 de Hallinan “Embedded Linux Primer”.