ç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».
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 **.
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.
A la capacité de corriger les errata en chargeant un bloc de données fourni par Intel dans le processeur. Cette fonctionnalité est appelée mise à jour du microcode.
Le BIOS doit fournir un mécanisme pour effectuer les mises à jour du microcode lors de l'initialisation du système.
Un BIOS doté de ce mécanisme (chargeur de mise à jour) est responsable du chargement des mises à jour dans le processeur lors de l'initialisation du système. Le chargement dans le processeur se déroule en deux étapes. ** La première étape consiste à transmettre le bloc de données de mise à jour requis (* 1) au BIOS **, et ** la deuxième étape consiste à ce que le BIOS charge le bloc de données de mise à jour dans le processeur **.
Dans ce document, j'écrirai sur l'implémentation Linux pour la première étape, «Passer des blocs de données au BIOS».
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".
Vous pouvez également voir que les informations stockées dans eax suivent le format suivant:
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.
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 |
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";
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];
};
La structure du fichier est la suivante.
Selon Intel SDM Vol.3, le format de chaque bloc de données est le suivant.
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.
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".
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!
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
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