12. MTRR (記憶體類型範圍暫存器) 控制¶
- 作者:
Richard Gooch <rgooch@atnf.csiro.au> - 1999 年 6 月 3 日
Luis R. Rodriguez <mcgrof@do-not-panic.com> - 2015 年 4 月 9 日
12.1. 逐步淘汰 MTRR 的使用¶
在現代 x86 硬體上,MTRR 的使用已被 PAT 取代。 Linux 驅動程式直接使用 MTRR 現在已完全淘汰,裝置驅動程式應結合 ioremap_wc() 使用 arch_phys_wc_add(),以便在非 PAT 系統上使 MTRR 生效,而在啟用 PAT 的系統上則無操作但同樣有效。
即使 Linux 不直接使用 MTRR,一些 x86 平臺韌體可能仍然會在作業系統啟動之前提前設定 MTRR。 他們這樣做是因為一些平臺韌體可能仍然實現了對 MTRR 的訪問,這些訪問將由平臺韌體直接控制和處理。 平臺使用 MTRR 的一個例子是透過使用 SMI 處理程式,一個例子可能是風扇控制,平臺程式碼需要對一些風扇控制暫存器進行不可快取的訪問。 此類平臺訪問不需要任何作業系統 MTRR 程式碼,只需要 mtrr_type_lookup() 來確保任何作業系統特定的對映請求與平臺 MTRR 設定對齊。 但是,如果 MTRR 僅由平臺韌體程式碼設定,並且作業系統不進行任何特定的 MTRR 對映請求,則 mtrr_type_lookup() 應始終返回 MTRR_TYPE_INVALID。
有關詳細資訊,請參閱 PAT (頁屬性表)。
提示
在 Intel P6 系列處理器(Pentium Pro、Pentium II 及更高版本)上,記憶體類型範圍暫存器 (MTRR) 可用於控制處理器對記憶體範圍的訪問。 當您在 PCI 或 AGP 總線上有影片 (VGA) 卡時,這最有用。 啟用寫入合併允許匯流排寫入傳輸在透過 PCI/AGP 匯流排突發之前合併為更大的傳輸。 這可以使影像寫入操作的效能提高 2.5 倍或更多。
Cyrix 6x86、6x86MX 和 M II 處理器具有地址範圍暫存器 (ARR),它們提供與 MTRR 類似的功能。 對於這些處理器,ARR 用於模擬 MTRR。
AMD K6-2(步進 8 及更高版本)和 K6-3 處理器有兩個 MTRR。 這些都支援。 AMD Athlon 系列提供 8 個 Intel 風格的 MTRR。
Centaur C6 (WinChip) 具有 8 個 MCR,允許寫入合併。 這些都支援。
VIA Cyrix III 和 VIA C3 CPU 提供 8 個 Intel 風格的 MTRR。
CONFIG_MTRR 選項建立一個 /proc/mtrr 檔案,可用於操作您的 MTRR。 通常,X 伺服器應使用此檔案。 這應該有一個相當通用的介面,以便可以輕鬆支援其他處理器上的類似控制暫存器。
/proc/mtrr 有兩個介面:一個是允許您讀取和寫入的 ASCII 介面。 另一個是 ioctl() 介面。 ASCII 介面適用於管理。 ioctl() 介面適用於 C 程式(即 X 伺服器)。 這些介面在下面描述,帶有示例命令和 C 程式碼。
12.2. 從 shell 讀取 MTRR¶
% cat /proc/mtrr
reg00: base=0x00000000 ( 0MB), size= 128MB: write-back, count=1
reg01: base=0x08000000 ( 128MB), size= 64MB: write-back, count=1
從 C-shell 建立 MTRR
# echo "base=0xf8000000 size=0x400000 type=write-combining" >! /proc/mtrr
或者如果您使用 bash
# echo "base=0xf8000000 size=0x400000 type=write-combining" >| /proc/mtrr
以及由此產生的結果
% cat /proc/mtrr
reg00: base=0x00000000 ( 0MB), size= 128MB: write-back, count=1
reg01: base=0x08000000 ( 128MB), size= 64MB: write-back, count=1
reg02: base=0xf8000000 (3968MB), size= 4MB: write-combining, count=1
這是用於基地址為 0xf8000000 且大小為 4 兆位元組的影片 RAM。 要找出您的基地址,您需要檢視 X 伺服器的輸出,它會告訴您線性幀緩衝區地址在哪裡。 您可能會得到的典型行是
(--) S3: PCI: 968 rev 0, Linear FB @ 0xf8000000
請注意,您應該只使用 X 伺服器中的值,因為它可能會移動幀緩衝區基地址,因此您可以信任的唯一值是 X 伺服器報告的值。
要找出幀緩衝區的大小(什麼,您實際上不知道?),以下行將告訴您
(--) S3: videoram: 4096k
那是 4 兆位元組,即 0x400000 位元組(十六進位制)。 正在為 XFree86 編寫一個補丁,它將使此過程自動化:換句話說,X 伺服器將使用 ioctl() 介面來操作 /proc/mtrr,因此使用者不必做任何事情。 如果您使用商業 X 伺服器,請遊說您的供應商新增對 MTRR 的支援。
12.3. 建立重疊的 MTRR¶
%echo "base=0xfb000000 size=0x1000000 type=write-combining" >/proc/mtrr
%echo "base=0xfb000000 size=0x1000 type=uncachable" >/proc/mtrr
以及結果
% cat /proc/mtrr
reg00: base=0x00000000 ( 0MB), size= 64MB: write-back, count=1
reg01: base=0xfb000000 (4016MB), size= 16MB: write-combining, count=1
reg02: base=0xfb000000 (4016MB), size= 4kB: uncachable, count=1
一些卡(尤其是 Voodoo Graphics 板)需要將這個 4 kB 區域從區域的開頭排除,因為它用於暫存器。
注意:只有當您建立的第一個區域是 type=write-combining 時,您才能建立 type=uncachable 區域。
12.4. 從 C-shel 中刪除 MTRR¶
% echo "disable=2" >! /proc/mtrr
或者使用 bash
% echo "disable=2" >| /proc/mtrr
12.5. 使用 ioctl() 從 C 程式讀取 MTRR¶
/* mtrr-show.c
Source file for mtrr-show (example program to show MTRRs using ioctl()'s)
Copyright (C) 1997-1998 Richard Gooch
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Richard Gooch may be reached by email at rgooch@atnf.csiro.au
The postal address is:
Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
*/
/*
This program will use an ioctl() on /proc/mtrr to show the current MTRR
settings. This is an alternative to reading /proc/mtrr.
Written by Richard Gooch 17-DEC-1997
Last updated by Richard Gooch 2-MAY-1998
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <asm/mtrr.h>
#define TRUE 1
#define FALSE 0
#define ERRSTRING strerror (errno)
static char *mtrr_strings[MTRR_NUM_TYPES] =
{
"uncachable", /* 0 */
"write-combining", /* 1 */
"?", /* 2 */
"?", /* 3 */
"write-through", /* 4 */
"write-protect", /* 5 */
"write-back", /* 6 */
};
int main ()
{
int fd;
struct mtrr_gentry gentry;
if ( ( fd = open ("/proc/mtrr", O_RDONLY, 0) ) == -1 )
{
if (errno == ENOENT)
{
fputs ("/proc/mtrr not found: not supported or you don't have a PPro?\n",
stderr);
exit (1);
}
fprintf (stderr, "Error opening /proc/mtrr\t%s\n", ERRSTRING);
exit (2);
}
for (gentry.regnum = 0; ioctl (fd, MTRRIOC_GET_ENTRY, &gentry) == 0;
++gentry.regnum)
{
if (gentry.size < 1)
{
fprintf (stderr, "Register: %u disabled\n", gentry.regnum);
continue;
}
fprintf (stderr, "Register: %u base: 0x%lx size: 0x%lx type: %s\n",
gentry.regnum, gentry.base, gentry.size,
mtrr_strings[gentry.type]);
}
if (errno == EINVAL) exit (0);
fprintf (stderr, "Error doing ioctl(2) on /dev/mtrr\t%s\n", ERRSTRING);
exit (3);
} /* End Function main */
12.6. 使用 ioctl() 從 C 程式建立 MTRR¶
/* mtrr-add.c
Source file for mtrr-add (example programme to add an MTRRs using ioctl())
Copyright (C) 1997-1998 Richard Gooch
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Richard Gooch may be reached by email at rgooch@atnf.csiro.au
The postal address is:
Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
*/
/*
This programme will use an ioctl() on /proc/mtrr to add an entry. The first
available mtrr is used. This is an alternative to writing /proc/mtrr.
Written by Richard Gooch 17-DEC-1997
Last updated by Richard Gooch 2-MAY-1998
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <asm/mtrr.h>
#define TRUE 1
#define FALSE 0
#define ERRSTRING strerror (errno)
static char *mtrr_strings[MTRR_NUM_TYPES] =
{
"uncachable", /* 0 */
"write-combining", /* 1 */
"?", /* 2 */
"?", /* 3 */
"write-through", /* 4 */
"write-protect", /* 5 */
"write-back", /* 6 */
};
int main (int argc, char **argv)
{
int fd;
struct mtrr_sentry sentry;
if (argc != 4)
{
fprintf (stderr, "Usage:\tmtrr-add base size type\n");
exit (1);
}
sentry.base = strtoul (argv[1], NULL, 0);
sentry.size = strtoul (argv[2], NULL, 0);
for (sentry.type = 0; sentry.type < MTRR_NUM_TYPES; ++sentry.type)
{
if (strcmp (argv[3], mtrr_strings[sentry.type]) == 0) break;
}
if (sentry.type >= MTRR_NUM_TYPES)
{
fprintf (stderr, "Illegal type: \"%s\"\n", argv[3]);
exit (2);
}
if ( ( fd = open ("/proc/mtrr", O_WRONLY, 0) ) == -1 )
{
if (errno == ENOENT)
{
fputs ("/proc/mtrr not found: not supported or you don't have a PPro?\n",
stderr);
exit (3);
}
fprintf (stderr, "Error opening /proc/mtrr\t%s\n", ERRSTRING);
exit (4);
}
if (ioctl (fd, MTRRIOC_ADD_ENTRY, &sentry) == -1)
{
fprintf (stderr, "Error doing ioctl(2) on /dev/mtrr\t%s\n", ERRSTRING);
exit (5);
}
fprintf (stderr, "Sleeping for 5 seconds so you can see the new entry\n");
sleep (5);
close (fd);
fputs ("I've just closed /proc/mtrr so now the new entry should be gone\n",
stderr);
} /* End Function main */