load amd patch into a malloc'd region to make it page aligned
authorjsg <jsg@openbsd.org>
Sun, 10 Sep 2023 09:32:31 +0000 (09:32 +0000)
committerjsg <jsg@openbsd.org>
Sun, 10 Sep 2023 09:32:31 +0000 (09:32 +0000)
avoids a General-Protection Exception on patch loader wrmsr with
A10-5700, TN-A1 00610f01 15-10-01

the alignment requirement is not present on at least
Ryzen 5 2600X, PiR-B2 00800f82 17-08-02

problem reported and fix tested by espie@

sys/arch/amd64/amd64/ucode.c
sys/arch/i386/i386/ucode.c

index c2badbc..7111cc8 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ucode.c,v 1.7 2023/08/09 02:59:41 jsg Exp $   */
+/*     $OpenBSD: ucode.c,v 1.8 2023/09/10 09:32:31 jsg Exp $   */
 /*
  * Copyright (c) 2018 Stefan Fritsch <fritsch@genua.de>
  * Copyright (c) 2018 Patrick Wildt <patrick@blueri.se>
@@ -141,6 +141,7 @@ cpu_ucode_amd_apply(struct cpu_info *ci)
        uint16_t eid = 0;
        uint32_t sig, ebx, ecx, edx;
        uint64_t start = 0;
+       uint32_t patch_len = 0;
 
        if (cpu_ucode_data == NULL || cpu_ucode_size == 0) {
                DPRINTF(("%s: no microcode provided\n", __func__));
@@ -187,8 +188,10 @@ cpu_ucode_amd_apply(struct cpu_info *ci)
                        goto out;
                }
                memcpy(&ap, &cpu_ucode_data[i], sizeof(ap));
-               if (ap.type == 1 && ap.eid == eid && ap.level > level)
+               if (ap.type == 1 && ap.eid == eid && ap.level > level) {
                        start = (uint64_t)&cpu_ucode_data[i + 8];
+                       patch_len = ap.len;
+               }
                if (i + ap.len + 8 > cpu_ucode_size) {
                        DPRINTF(("%s: truncated patch\n", __func__));
                        goto out;
@@ -197,9 +200,16 @@ cpu_ucode_amd_apply(struct cpu_info *ci)
        }
 
        if (start != 0) {
+               /* alignment required on fam 15h */
+               uint8_t *p = malloc(patch_len, M_TEMP, M_NOWAIT);
+               if (p == NULL)
+                       goto out;
+               memcpy(p, (uint8_t *)start, patch_len);
+               start = (uint64_t)p;
                wrmsr(MSR_PATCH_LOADER, start);
                level = rdmsr(MSR_PATCH_LEVEL);
                DPRINTF(("%s: new patch level 0x%llx\n", __func__, level));
+               free(p, M_TEMP, patch_len);
        }
 out:
        mtx_leave(&cpu_ucode_mtx);
index ec73218..dde72a1 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ucode.c,v 1.5 2023/08/09 02:59:41 jsg Exp $   */
+/*     $OpenBSD: ucode.c,v 1.6 2023/09/10 09:32:31 jsg Exp $   */
 /*
  * Copyright (c) 2018 Stefan Fritsch <fritsch@genua.de>
  * Copyright (c) 2018 Patrick Wildt <patrick@blueri.se>
@@ -164,6 +164,7 @@ cpu_ucode_amd_apply(struct cpu_info *ci)
        uint16_t eid = 0;
        uint32_t sig, ebx, ecx, edx;
        uint64_t start = 0;
+       uint32_t patch_len = 0;
 
        if (cpu_ucode_data == NULL || cpu_ucode_size == 0) {
                DPRINTF(("%s: no microcode provided\n", __func__));
@@ -210,8 +211,10 @@ cpu_ucode_amd_apply(struct cpu_info *ci)
                        goto out;
                }
                memcpy(&ap, &cpu_ucode_data[i], sizeof(ap));
-               if (ap.type == 1 && ap.eid == eid && ap.level > level)
+               if (ap.type == 1 && ap.eid == eid && ap.level > level) {
                        start = (uint64_t)&cpu_ucode_data[i + 8];
+                       patch_len = ap.len;
+               }
                if (i + ap.len + 8 > cpu_ucode_size) {
                        DPRINTF(("%s: truncated patch\n", __func__));
                        goto out;
@@ -220,9 +223,16 @@ cpu_ucode_amd_apply(struct cpu_info *ci)
        }
 
        if (start != 0) {
+               /* alignment required on fam 15h */
+               uint8_t *p = malloc(patch_len, M_TEMP, M_NOWAIT);
+               if (p == NULL)
+                       goto out;
+               memcpy(p, (uint8_t *)start, patch_len);
+               start = (uint64_t)p;
                wrmsr(MSR_PATCH_LOADER, start);
                level = rdmsr(MSR_PATCH_LEVEL);
                DPRINTF(("%s: new patch level 0x%llx\n", __func__, level));
+               free(p, M_TEMP, patch_len);
        }
 out:
        mtx_leave(&cpu_ucode_mtx);