À propos du processus que le noyau Linux gère le microcode x86

introduction

ça fait longtemps. @akachichon.

Eh bien, au début, j'ai essayé d'écrire un article sur le système de fichiers racine, mais cette fois j'ai écrit sur la mise à jour du microcode. Le code source cité ou l'environnement utilisé pour la confirmation est "Ubuntu Server 19.10". Pour plus de détails sur la façon d'obtenir le code source pour Ubuntu Server 19.10, reportez-vous au supplément «Comment obtenir le code source du noyau pour Ubuntu Linux».

À propos de l'image du système de fichiers racine

L'image du système de fichiers racine pour Ubuntu Server 19.10 est /boot/initrd.img-5.3.0-24-generic. Je pense que l'image du système de fichiers racine est commune à de nombreuses distributions Linux, pas seulement à Ubuntu. Maintenant, vérifions le contenu. Si vous voulez simplement voir la liste des fichiers dans l'image du système de fichiers racine, il est plus facile d'utiliser lsinitramfs.

Résultat de l'exécution de lsinitramfs


fyoshida@fyoshida:~/lab/initramfs$ cp /boot/initrd.img-5.3.0-24-generic .
fyoshida@fyoshida:~/lab/initramfs$ lsinitramfs initrd.img-5.3.0-24-generic
.
kernel
kernel/x86
kernel/x86/microcode
kernel/x86/microcode/AuthenticAMD.bin
kernel
(Abréviation)
var
var/lib
var/lib/dhcp

Je veux vérifier un peu plus le contenu, alors utilisez la commande cpio pour extraire l'image initramfs. Cependant, je ne peux pas extraire les fichiers comme je l'ai vu dans lsinitramfs. Seul le répertoire du noyau a pu être extrait.

résultat de l'exécution cpio


fyoshida@fyoshida:~/lab/initramfs$ cat initrd.img-5.3.0-24-generic | cpio -id
62 blocks
fyoshida@fyoshida:~/lab/initramfs$ ls
initrd.img-5.3.0-24-generic  kernel

Après avoir étudié la raison de cela, je suis tombé sur la documentation de kernel.org.

kernel.Extrait de org


The microcode is stored in an initrd file. During boot, it is read from it and loaded into the CPU cores.

The format of the combined initrd image is microcode in (uncompressed) cpio format followed by the (possibly compressed) initrd image. The loader parses the combined initrd image during boot.

Je vois. Puisque l'image de initrd est une "image initrd combinée", on peut en déduire que la commande cpio ne pouvait extraire que la partie de format cpio contenant le premier microcode. Au fait, je me suis rendu compte que j'avais beaucoup de connaissances vagues sur le microcode. Dans cet esprit, dans ce calendrier de l'Avent, j'écrirai un article basé sur "Comment Linux gère le microcode dans le système de fichiers racine".

De plus, ** Je suis désolé pour tous les fans d'AMD à travers le pays. Cette fois, seul Intel fait l'objet de l'article **.

Explication basée sur Intel SDM

Les premières phrases d'Intel SDM Vol.3 "9.11 MICROCODE UPDATE FACILITIES" sont importantes à connaître sur les mises à jour du microcode. Le résumé est le suivant.

Dans ce document, j'écrirai sur l'implémentation Linux pour la première étape, «Passer des blocs de données au BIOS».

Lisez le code du noyau Linux

Les sources se trouvent dans arch / x86 / kernel / cpu / microcode. Le nom du fichier est trop simple et très facile à comprendre.

arch/x86/kernel/cpu/structure de fichier de microcode


fyoshida@fyoshida:~/source/ubuntu-kernel/linux-source-5.3.0$ ag microcode arch/x86/kernel/cpu/microcode/
amd.c     core.c    intel.c   Makefile

Le début est load_ucode_bsp ().

arch/x86/kernel/cpu/microcode/core.c


void __init load_ucode_bsp(void)
{
//Abréviation
    cpuid_1_eax = native_cpuid_eax(1);

Selon les termes d'Intel SDM, cpuid est une instruction qui consiste à «obtenir des informations d'identification du processeur». Exécutez l'instruction cpuid après avoir défini le nombre indiquant les informations que vous souhaitez acquérir dans le registre eax. L'argument de native_cpuid_eax est un nombre indiquant les informations que vous souhaitez obtenir. Et la valeur de retour est "les informations stockées dans le registre eax du résultat de l'exécution de cpuid". La mise en œuvre est la suivante.

arch/x86/include/asm/processor.h


static inline void native_cpuid(unsigned int *eax, unsigned int *ebx,
                unsigned int *ecx, unsigned int *edx)
{
    /* ecx is often an input as well as an output. */
    asm volatile("cpuid"
        : "=a" (*eax),
          "=b" (*ebx),
          "=c" (*ecx),
          "=d" (*edx)
        : "0" (*eax), "2" (*ecx)
        : "memory");
}

#define native_cpuid_reg(reg)                   \
static inline unsigned int native_cpuid_##reg(unsigned int op)  \
{                               \
    unsigned int eax = op, ebx, ecx = 0, edx;       \
                                \
    native_cpuid(&eax, &ebx, &ecx, &edx);           \
                                \
    return reg;                     \
}

Ci-dessous, à partir des informations d'extrait d'Intel SDM, vous pouvez voir que les informations obtenues ici sont "Type, Famille, Modèle, ID d'étape".

cpuid_eax_1.png

Vous pouvez également voir que les informations stockées dans eax suivent le format suivant: cpuid_eax_2.png

arch/x86/kernel/cpu/microcode/core.c


    switch (x86_cpuid_vendor()) {
    case X86_VENDOR_INTEL:
        if (x86_family(cpuid_1_eax) < 6)
            return;
        break;

Ici, il est déterminé si le processeur qui s'exécute prend en charge la mise à jour du microcode. Rappelez-vous que les processeurs prenant en charge les mises à jour de microcode sont "P6 et supérieurs". Ensuite, load_ucode_intel_bsp () est appelé.

void __init load_ucode_intel_bsp(void)
{
    struct microcode_intel *patch;
    struct ucode_cpu_info uci;

    patch = __load_ucode_intel(&uci);
    if (!patch)
        return;

    uci.mc = patch;

    apply_microcode_early(&uci, true);
}

load_ucode_intel_bsp () a la configuration d'appel de fonction suivante.

calltree.png

Le contour de chaque fonction est le suivant.

Nom de la fonction Aperçu
__load_ucode_intel Trouvez le bloc de données à appliquer
load_builtin_intel_microcode Utilisez Firmware Loader pour déterminer s'il y a des blocs de données à appliquer(※2)
find_microcode_in_initrd Rechercher des fichiers contenant des blocs de données de initrd étendus sur la mémoire
collect_cpu_info_early Utilisez l'instruction cpuid, etc. pour obtenir les informations du CPU sur lequel il fonctionne.
scan_microcode Trouvez le bloc de données le plus approprié parmi les blocs de données contenus dans le fichier
apply_microcode_early Transmettez le bloc de données trouvé dans le processus jusqu'à présent au BIOS

Rechercher des blocs de données à partir de initrd

Obtient l'emplacement et la taille de l'image initrd développée par le chargeur de démarrage. Cette image de disque RAM est /boot/initrd.img-5.3.0-24-generic écrite au début. De plus, le début de cette image commence au format cpio. Par conséquent, selon le format cpio, le fichier contenant le bloc de données est recherché par le nom du chemin. Pour le format cpio, veuillez vous référer à "Une brève explication et une figure de cpio" dans Article que j'ai écrit.

arch/x86/kernel/cpu/microcode/intel.c


struct cpio_data find_microcode_in_initrd(const char *path, bool use_pa)
{
/*Abréviation*/
    size  = (unsigned long)boot_params.ext_ramdisk_size << 32;
    size |= boot_params.hdr.ramdisk_size;

    if (size) {
        start  = (unsigned long)boot_params.ext_ramdisk_image << 32;
        start |= boot_params.hdr.ramdisk_image;

        start += PAGE_OFFSET;
    }
/*Abréviation*/
    return find_cpio_data(path, (void *)start, size, NULL);

Le nom du chemin est le suivant.

arch/x86/kernel/cpu/microcode/intel.c


static const char ucode_path[] = "kernel/x86/microcode/GenuineIntel.bin";

Rechercher des images cpio

find_cpio_data () trouve le fichier correspondant au chemin précédent dans l'image cpio en RAM et renvoie l'adresse de départ et la taille de la zone où il se trouve. Ces informations sont représentées par la structure suivante. data est le début du fichier contenant le bloc de données et la taille est la taille du fichier.

include/linux/earlycpio.h


struct cpio_data {
    void *data;
    size_t size;
    char name[MAX_CPIO_FILE_NAME];
};

Examinez les fichiers dans initrd pour trouver les blocs de données à appliquer

La structure du fichier est la suivante. genuineintel.png

Selon Intel SDM Vol.3, le format de chaque bloc de données est le suivant.

structure_of_microcode.png

Le paramètre le plus important dans l'en-tête du bloc de données est la signature du processeur. Il s'agit d'une ** valeur qui représente le type de processeur auquel la mise à jour de microcode appropriée est appliquée **, et est une valeur qui se compose de "Famille étendue, modèle étendu, type, famille, modèle, pas à pas". Chaque bloc de données est conçu pour un type de processeur particulier.

Parce qu'il est "conçu pour un processeur particulier", un bloc de données est applicable à un type de processeur. Cependant, certains blocs de données sont applicables à plusieurs types de processeurs. Que feriez-vous dans un tel cas? La solution est la "Table de signature étendue facultative". Pour le dire clairement, ce tableau répertorie le deuxième "type de processeur applicable" et les suivants. Pour plus de détails, lisez «9.11.2 Tableau des signatures étendues facultatives» d'Intel SDM Vol.3.

De plus, les points à retenir concernant l'en-tête sont les suivants.

En un mot, le traitement scan_microcode () consiste à "analyser GenuineIntel.bin en mémoire depuis le début, trouver le dernier bloc de données applicable au type de processeur que vous exécutez et trouver son adresse et sa taille. Revenir. " Vous devriez lire le code en vous référant à "9.11.3 Identification du processeur" d'Intel SDM Vol.3.

Passez le bloc de données au BIOS

Enfin, passez le bloc de données au BIOS.

arch/x86/kernel/cpu/microcode/intel.c


static int apply_microcode_early(struct ucode_cpu_info *uci, bool early)
{
/*Abréviation*/
    /* write microcode via MSR 0x79 */
    native_wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits);

Que fait native_wrmsrl ()? En fait, le processus correspond à Intel SDM Vol.3 "9.11.6 Microcode Update Loader". Vous pouvez maintenant transmettre le bloc de données au BIOS. Pour les conditions détaillées, reportez-vous à Intel SDM Vol.3 "9.11.6 Microcode Update Loader".

wrmsr0x79.png

en conclusion

C'était une précipitation, mais j'ai cherché un bloc de données à partir de l'image du système de fichiers racine et j'ai regardé comment l'appliquer. Il y a de nombreuses fois où je m'écarte de ce que je voulais initialement écrire. Ce n'est pas bon de sortir des sentiers battus au travail, mais c'est amusant de faire de la recherche technique privée. Après tout, il est amusant de lire le code et la littérature pour connaître diverses choses. Je pense que le calendrier de l'Avent est une bonne occasion de nous donner une telle opportunité.

Bon alors, il y a eu diverses choses cette année, mais cette année quand il n'en reste plus que quelques-uns, et même après l'année prochaine, Happy Hacking!

Supplément

Comment obtenir le code source du noyau d'Ubuntu Linux

Au moins pour Ubuntu Server 19.10, il est plus facile d'obtenir le linux-source avec la commande apt. Le code source est solidifié avec tar, il doit donc être développé.

Résultat d'exécution


fyoshida@fyoshida:~$ sudo apt install linux-source
fyoshida@fyoshida:~$ cd /usr/src/linux-source-5.3.0/
fyoshida@fyoshida:/usr/src/linux-source-5.3.0$ ls
debian  debian.master  linux-source-5.3.0.tar.bz2
fyoshida@fyoshida:/usr/src/linux-source-5.3.0$ sudo tar xf linux-source-5.3.0.tar.bz2
fyoshida@fyoshida:/usr/src/linux-source-5.3.0$ ls
debian  debian.master  linux-source-5.3.0  linux-source-5.3.0.tar.bz2
fyoshida@fyoshida:/usr/src/linux-source-5.3.0/linux-source-5.3.0$ ls
arch   COPYING  Documentation  fs       ipc      kernel    MAINTAINERS  net      scripts         sound   update-version-dkms
block  CREDITS  drivers        include  Kbuild   lib       Makefile     README   security        tools   usr
certs  crypto   dropped.txt    init     Kconfig  LICENSES  mm           samples  snapcraft.yaml  ubuntu  virt

Références, pages

Dans l'ensemble, je suis reconnaissant envers Intel SDM. Après tout, c'est un incontournable. De plus, je pense que l'article de Mamedanuki est un article très précieux qui peut être lu en japonais. J'ai aussi aimé le lire. Nous remercions également les auteurs pour les autres articles cités dans le texte.

Recommended Posts

À propos du processus que le noyau Linux gère le microcode x86
Compilation du noyau Linux (Linux 5.x sur Ubuntu 20.04)
Une note sur les fonctions de la bibliothèque Linux standard qui gère le temps
À propos des paramètres du noyau Linux
Version du noyau Linux 5.x (2/4)
Version du noyau Linux 5.x (3/4)
Version du noyau Linux 5.x (4/4)
Version du noyau Linux 5.x (1/4)
Essayez le mécanisme de verrouillage du noyau Linux
[linux] commande kill pour tuer le processus
Processus Linux
À propos de Linux
À propos de Linux
À propos de Linux
À propos de la question qui s'inquiétait de l'erreur d'échantillonnage
Linux: renommez le processus affiché par la commande ps
Obtenez la dernière version du noyau Linux avec ArchLinux