Lange nicht gesehen. @akachichon.
Nun, zuerst habe ich versucht, einen Artikel über das Root-Dateisystem zu schreiben, aber diesmal habe ich über das Mikrocode-Update geschrieben. Der angegebene Quellcode oder die zur Bestätigung verwendete Umgebung lautet "Ubuntu Server 19.10". Ausführliche Informationen zum Abrufen des Quellcodes für Ubuntu Server 19.10 finden Sie in der Ergänzung "So erhalten Sie den Kernel-Quellcode für Ubuntu Linux".
Das Root-Dateisystem-Image für Ubuntu Server 19.10 lautet /boot/initrd.img-5.3.0-24-generic. Ich denke, das Root-Dateisystem-Image ist vielen Linux-Distributionen gemeinsam, nicht nur Ubuntu. Lassen Sie uns nun den Inhalt überprüfen. Wenn Sie nur die Liste der Dateien im Root-Dateisystem-Image anzeigen möchten, ist es einfacher, lsinitramfs zu verwenden.
Ausführungsergebnis von 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
(Abkürzung)
var
var/lib
var/lib/dhcp
Ich möchte den Inhalt etwas genauer überprüfen. Verwenden Sie daher den Befehl cpio, um das initramfs-Image zu extrahieren. Ich kann die Dateien jedoch nicht extrahieren, wie ich in lsinitramfs gesehen habe. Es konnte nur das Kernelverzeichnis extrahiert werden.
cpio Ausführungsergebnis
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
Nachdem ich den Grund dafür untersucht hatte, stieß ich auf die kernel.org-Dokumentation.
kernel.Auszug aus 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.
Das war's. Da das initrd-Bild ein "kombiniertes initrd-Bild" ist, kann gefolgert werden, dass der Befehl cpio nur den Teil des cpio-Formats extrahieren konnte, der den ersten Mikrocode enthält. Übrigens wurde mir klar, dass ich viel vages Wissen über Mikrocode hatte. In diesem Sinne werde ich in diesem Adventskalender einen Artikel schreiben, der auf "Wie Linux mit Mikrocode im Root-Dateisystem umgeht" basiert.
Außerdem ** Es tut mir allen AMD-Fans im ganzen Land leid. Diesmal ist nur Intel Gegenstand des Artikels **.
Die ersten Sätze von Intel SDM Vol.3 "9.11 MICROCODE UPDATE FACILITIES" sind wichtig, um über Mikrocode-Updates Bescheid zu wissen. Die Zusammenfassung ist wie folgt.
Kann Errata beheben, indem von Intel bereitgestellte Datenblöcke in den Prozessor geladen werden. Diese Funktion wird als Mikrocode-Aktualisierung bezeichnet.
Das BIOS muss einen Mechanismus zum Durchführen von Mikrocode-Aktualisierungen während der Systeminitialisierung bereitstellen.
Ein BIOS mit diesem Mechanismus (Update Loader) ist für das Laden von Updates in den Prozessor während der Systeminitialisierung verantwortlich. Das Laden in den Prozessor erfolgt in zwei Schritten. ** Der erste Schritt besteht darin, den erforderlichen Aktualisierungsdatenblock (* 1) an das BIOS zu übergeben **, und ** der zweite Schritt besteht darin, dass das BIOS den Aktualisierungsdatenblock in den Prozessor lädt **.
In diesem Dokument werde ich über die Linux-Implementierung für den ersten Schritt "Übergeben von Datenblöcken an das BIOS" schreiben.
Die Quellen befinden sich in arch / x86 / kernel / cpu / microcode. Der Dateiname ist zu einfach und sehr leicht zu verstehen.
arch/x86/kernel/cpu/Mikrocode-Dateistruktur
fyoshida@fyoshida:~/source/ubuntu-kernel/linux-source-5.3.0$ ag microcode arch/x86/kernel/cpu/microcode/
amd.c core.c intel.c Makefile
Der Anfang ist load_ucode_bsp ().
arch/x86/kernel/cpu/microcode/core.c
void __init load_ucode_bsp(void)
{
//Abkürzung
cpuid_1_eax = native_cpuid_eax(1);
In den Worten von Intel SDM ist cpuid eine Anweisung, die "Informationen zur Prozessoridentifikation erhalten" lautet. Führen Sie die Anweisung cpuid aus, nachdem Sie die Nummer festgelegt haben, die die Informationen angibt, die Sie im eax-Register erfassen möchten. Das Argument von native_cpuid_eax ist eine Zahl, die die Informationen angibt, die Sie abrufen möchten. Und der Rückgabewert ist "die Information, die im eax-Register des Ergebnisses der Ausführung von cpuid gespeichert ist". Die Implementierung ist wie folgt.
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; \
}
Aus den Auszugsinformationen von Intel SDM können Sie ersehen, dass die hier erhaltenen Informationen "Typ, Familie, Modell, Schritt-ID" sind.
Sie können auch sehen, dass die in eax gespeicherten Informationen dem folgenden Format folgen:
arch/x86/kernel/cpu/microcode/core.c
switch (x86_cpuid_vendor()) {
case X86_VENDOR_INTEL:
if (x86_family(cpuid_1_eax) < 6)
return;
break;
Hier wird festgestellt, ob die selbst laufende CPU die Mikrocode-Aktualisierung unterstützt. Denken Sie daran, dass die CPUs, die Mikrocode-Updates unterstützen, "P6 und höher" sind. Dann wird load_ucode_intel_bsp () aufgerufen.
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 () hat die folgende Funktionsaufrufkonfiguration.
Der Umriss jeder Funktion ist wie folgt.
Funktionsname | Überblick |
---|---|
__load_ucode_intel | Suchen Sie den anzuwendenden Datenblock |
load_builtin_intel_microcode | Verwenden Sie den Firmware Loader, um festzustellen, ob Datenblöcke angewendet werden müssen(※2) |
find_microcode_in_initrd | Suchen Sie nach Dateien, die Datenblöcke von initrd enthalten, die im Speicher erweitert wurden |
collect_cpu_info_early | Verwenden Sie die Anweisung cpuid usw., um die Informationen der CPU abzurufen, auf der sie arbeitet. |
scan_microcode | Suchen Sie den am besten geeigneten Datenblock aus den in der Datei enthaltenen Datenblöcken |
apply_microcode_early | Übergeben Sie den bisher im Prozess gefundenen Datenblock an das BIOS |
Ruft den Speicherort und die Größe des vom Bootloader erweiterten initrd-Images ab. Dieses RAM-Disk-Image ist zu Beginn /boot/initrd.img-5.3.0-24-generic geschrieben. Außerdem beginnt der Anfang dieses Bildes im cpio-Format. Daher wird gemäß dem cpio-Format die Datei, die den Datenblock enthält, nach dem Pfadnamen durchsucht. Informationen zum cpio-Format finden Sie unter "Eine kurze Erklärung und Abbildung von cpio" in Artikel, den ich geschrieben habe.
arch/x86/kernel/cpu/microcode/intel.c
struct cpio_data find_microcode_in_initrd(const char *path, bool use_pa)
{
/*Abkürzung*/
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;
}
/*Abkürzung*/
return find_cpio_data(path, (void *)start, size, NULL);
Der Pfadname lautet wie folgt.
arch/x86/kernel/cpu/microcode/intel.c
static const char ucode_path[] = "kernel/x86/microcode/GenuineIntel.bin";
find_cpio_data () findet die Datei, die dem vorherigen Pfad im cpio-Image im RAM entspricht, und gibt die Startadresse und die Größe des Bereichs zurück, in dem sie sich befindet. Diese Informationen werden durch die folgende Struktur dargestellt. Daten ist der Anfang der Datei, die den Datenblock enthält, und Größe ist die Dateigröße.
include/linux/earlycpio.h
struct cpio_data {
void *data;
size_t size;
char name[MAX_CPIO_FILE_NAME];
};
Die Struktur in der Datei ist wie folgt.
Gemäß Intel SDM Vol.3 ist das Format jedes Datenblocks wie folgt.
Der wichtigste Parameter im Datenblock-Header ist die Prozessorsignatur. Dies ist ein ** Wert, der den Prozessortyp darstellt, auf den die entsprechende Mikrocode-Aktualisierung angewendet wird **, und ein Wert, der aus "Erweiterte Familie, erweitertes Modell, Typ, Familie, Modell, Schritt" besteht. Jeder Datenblock ist für einen bestimmten Prozessortyp ausgelegt.
Da es "für einen bestimmten Prozessor ausgelegt" ist, ist ein Datenblock auf einen Prozessortyp anwendbar. Einige Datenblöcke sind jedoch auf mehrere Prozessortypen anwendbar. Was würden Sie in einem solchen Fall tun? Die Lösung ist die "Optionale erweiterte Signaturtabelle". In dieser Tabelle sind die zweiten und nachfolgenden "anwendbaren Prozessortypen" aufgeführt. Weitere Informationen finden Sie unter "9.11.2 Optionale erweiterte Signaturtabelle" von Intel SDM Vol.3.
Darüber hinaus sind folgende Punkte in Bezug auf den Header zu beachten.
Kurz gesagt, die Verarbeitung von scan_microcode () "analysiert GenuineIntel.bin von Anfang an im Speicher, findet den neuesten Datenblock, der für den laufenden Prozessortyp gilt, und ermittelt dessen Adresse und Größe. Rückkehr. " Sie sollten den Code unter "9.11.3 Prozessoridentifikation" von Intel SDM Vol.3 lesen.
Übergeben Sie schließlich den Datenblock an das BIOS.
arch/x86/kernel/cpu/microcode/intel.c
static int apply_microcode_early(struct ucode_cpu_info *uci, bool early)
{
/*Abkürzung*/
/* write microcode via MSR 0x79 */
native_wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits);
Was macht native_wrmsrl ()? Tatsächlich entspricht der Prozess Intel SDM Vol.3 "9.11.6 Microcode Update Loader". Sie können den Datenblock jetzt an das BIOS übergeben. Ausführliche Informationen finden Sie in Intel SDM Vol.3 "9.11.6 Microcode Update Loader".
Es war ein Ansturm, aber ich suchte nach einem Datenblock aus dem Root-Dateisystem-Image und sah mir an, wie man ihn anwendet. Es gibt viele Male, in denen ich von dem abweiche, was ich ursprünglich schreiben wollte. Es ist nicht gut, bei der Arbeit abseits der ausgetretenen Pfade zu sein, aber es macht Spaß, private technische Forschung zu betreiben. Schließlich macht es Spaß, den Code und die Literatur zu lesen, um verschiedene Dinge zu wissen. Ich denke, der Adventskalender ist eine gute Gelegenheit, uns eine solche Gelegenheit zu geben.
Nun, dieses Jahr gab es verschiedene Dinge, aber dieses Jahr, wenn nur noch wenige übrig sind, und sogar nach dem nächsten Jahr Happy Hacking!
Zumindest für Ubuntu Server 19.10 ist es am einfachsten, die Linux-Quelle mit dem Befehl apt abzurufen. Der Quellcode wird mit tar verfestigt und muss daher erweitert werden.
Ausführungsergebnis
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
Insgesamt bin ich Intel SDM dankbar. Immerhin ist es ein Muss. Ich denke auch, dass Mamedanukis Artikel ein sehr wertvoller Artikel ist, der auf Japanisch gelesen werden kann. Ich habe es auch gerne gelesen. Wir möchten uns auch bei den Autoren für die anderen im Text zitierten Artikel bedanken.
Recommended Posts