NetBSD Problem Report #60968
From www@netbsd.org Fri Nov 6 05:35:24 2026
Return-Path: <www@netbsd.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256
client-signature RSA-PSS (2048 bits) client-digest SHA256)
(Client CN "mail.netbsd.org", Issuer "YR1" (not verified))
by mollari.NetBSD.org (Postfix) with ESMTPS id A3B591A923B
for <gnats-bugs@gnats.NetBSD.org>; Fri, 6 Nov 2026 05:35:24 +0000 (UTC)
Message-Id: <20261106053523.4B7811A923C@mollari.NetBSD.org>
Date: Fri, 6 Nov 2026 05:35:23 +0000 (UTC)
From: 126nut@gmail.com
Reply-To: 126nut@gmail.com
To: gnats-bugs@NetBSD.org
Subject: NetBSD 10.1 amd64 does not initialise PAT on the secondary CPU on my machine, causing approximately 11× slower framebuffer writes on that core.
X-Send-Pr-Version: www-1.0
X-From4GNATS: "126nut@gmail.com via gnats" <gnats-admin@NetBSD.org>
>Number: 60968
>Category: kern
>Synopsis: NetBSD 10.1 amd64 does not initialise PAT on the secondary CPU on my machine, causing approximately 11× slower framebuffer writes on that core.
>Confidential: no
>Severity: serious
>Priority: high
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Fri Nov 06 05:40:01 +0000 2026
>Originator: Nut
>Release: NetBSD 10.1, GENERIC amd64
>Organization:
>Environment:
NetBSD 10.1 NetBSD 10.1 (GENERIC) #0: Mon Dec 16 13:08:11 UTC 2024 mkrepro@mkrepro.NetBSD.org:/usr/src/sys/arch/amd64/compile/GENERIC amd64
>Description:
I noticed a large difference in frame buffer write performance depending on which CPU was running the code. My application receives pixel updates over the network and writes them directly to the framebuffer to display a remote desktop.
While investigating slow rendering, I found that the same full-frame write took approximately 4.72 ms on CPU 0 but 51.79 ms on CPU 1. I repeated the test using the same source buffer, frame bufer mapping and write routine, restricting the benchmark to each CPU in turn. Writes to ordinary RAM took approximately 3.59 ms on either CPU, so the difference appeared specific to frame buffer access.
Using the same frame buffer mapping and write routine, a full-frame write took approximately 4.72 ms on CPU 0 and 51.79 ms on CPU 1. The equivalent ordinary RAM test took approximately 3.59 ms on either CPU.
Read-only per-CPU register captures showed different PAT values:
CPU 0: 0007010600070106
CPU 1: 0007040600070406
The frame buffer PTEs select PAT entry 1. This entry was WC on CPU 0 but WT on CPU 1. With the captured MTRR configuration, this made the frame buffer effectively WC on CPU 0 and UC on CPU 1.
Tracing the NetBSD 10.1 source showed that cpu_hatch() calls cpu_probe(ci) but does not call pat_init(ci). There is a pat_init(ci) call in cpu_attach(), but passing the secondary CPU’s structure does not make the function execute on that CPU; the MSR write still happens on the CPU executing the attachment code.
I added pat_init(ci) immediately after cpu_probe(ci) in cpu_hatch(), rebuilt GENERIC and booted the patched kernel. Both CPUs then reported the intended PAT value in two independent captures. MTRRs remained unchanged.
The unchanged frame buffer benchmark then measured approximately 4.72 ms on both CPUs.
>How-To-Repeat:
On the affected machine (Apple iMac (20-inch, Mid 2007), Intel Core 2 Duo T7300 2.0 GHz, ATI Radeon HD 2400 XT), boot the NetBSD 10.1 GENERIC amd64 kernel.
Run a full-framebuffer write benchmark on each CPU separately, using schedctl to restrict the benchmark process to CPU 0 and then CPU 1.
Keep the framebuffer mapping, source buffer, write routine and iteration counts unchanged. Run an ordinary RAM destination as a control.
Capture the PAT MSR independently on each CPU using a read-only diagnostic. CPU 1 retains 0007040600070406, while CPU 0 has 0007010600070106.
>Fix:
Adding the existing PAT initialisation call to the secondary CPU’s startup path fixed the problem on my machine.
In sys/arch/x86/x86/cpu.c, inside cpu_hatch():
cpu_init_msrs(ci, true);
cpu_probe(ci);
+ pat_init(ci);
cpu_speculation_init(ci);
After rebuilding and booting GENERIC with this change, both CPUs reported PAT 0007010600070106.
With 600 measured samples per CPU and destination, the median times were:
CPU 0 CPU 1
Framebuffer 4.716522 ms 4.716137 ms
Ordinary RAM 3.582788 ms 3.582649 ms
(Contact us)
$NetBSD: query-full-pr,v 1.51 2026/08/10 02:28:17 riastradh Exp $
$NetBSD: gnats_config.sh,v 1.10 2026/05/13 22:00:09 riastradh Exp $
Copyright © 1994-2026
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.