Как отобразить 1 ГБ (или более) физической памяти - PullRequest
7 голосов
/ 09 марта 2012

У меня есть установка с 2 ГБ памяти, и я хотел бы отобразить 1 ГБ (или более) физической памяти в виртуальный адрес пространства пользователя.Теоретически это возможно, поскольку при настройке 32 бита для наземных приложений пользователя доступно 3 ГБ виртуального адреса.

Я обновил командную строку ядра следующими параметрами: mem = 1G memmap = 1G $ 1G, чтобы принудительно запустить ядрочтобы увидеть 1 ГБ оперативной памяти и зарезервировать последние 1 ГБ.

У меня есть пользовательский драйвер, который будет обрабатывать вызов пользовательского пространства mmap () и отображать физический адрес 0x40000000 (1G) в адрес пользовательского пространства с помощью функции remap_pfn_range ().Но функция вызывает BUG () ядра в remap_pte_range ().Тот же самый вызов, используемый для работы с переназначением 300 МБ вместо 1 ГБ.

Я обычно использую для вызова ioremap () в моем драйвере для отображения физического адреса в виртуальный адрес ядра.В этом случае я не могу из-за разделения виртуальных адресов 1G / 3G (1G для ядра, 3G для приложений).Поэтому мне было интересно, возможно ли отобразить физический адрес в виртуальный адрес пространства пользователя без сопоставления этих физических адресов в ядре?

Заранее спасибо.

1 Ответ

5 голосов
/ 11 марта 2012

Почему ваш вызов remap_pfn_range вызывает ошибку ядра ()

Вызов макроса BUG_ON в remap_pfn_range согласно здесь

2277 BUG_ON(addr >= end);

remap_pfn_range звонит remap_pud_range который звонит remap_pmd_range который звонит remap_pte_range.

Последующие звонки на BUG_ON или VM_BUG_ON с remap_pmd_range здесь

2191 VM_BUG_ON(pmd_trans_huge(*pmd));

и от remap_pte_range здесь

2171 BUG_ON(!pte_none(*pte));

BUG_ON макрос определен здесь

в

#define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while(0)

где макрос BUG определен выше это для печати сообщения и паники.

unlikely макрос определен здесь

как # define unlikely(x) (__builtin_expect(!!(x), 0)).

Таким образом, когда целевой адрес пользователя, начинающийся с addr, больше или равен end, который определяется как end = addr + PAGE_ALIGN(size);, BUG_ON возвращает 1 и вызывает BUG.

или когда pmd_trans_huge как определено здесь

153 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
154 static inline int pmd_trans_splitting(pmd_t pmd)
155 {
156         return pmd_val(pmd) & _PAGE_SPLITTING;
157 }
158 
159 static inline int pmd_trans_huge(pmd_t pmd)
160 {
161         return pmd_val(pmd) & _PAGE_PSE;
162 }
163 
164 static inline int has_transparent_hugepage(void)
165 {
166         return cpu_has_pse;
167 }

возвращает 0, это происходит, когда CONFIG_TRANSPARENT_HUGEPAGE не настроен в ядре или если значение pmd (метадат страницы) или & _PAGE_PSE

Или когда pte_none возвращает 1, если соответствующая запись не существует, и 0, если она существует.

Поэтому !pte_none возвращает 0, когда соответствующая запись в таблице страниц не существует, и 1 в другом случае, когда условие перешло в BUG_ON.

Если запись таблицы страниц уже существует, то происходит вызов макроса BUG.

Что произойдет, если указать меньший объем памяти, чем! ГБ, который превышает 300 МБ, скажем, 500 МБ или 800 МБ?

Таким образом, либо ваш начальный адрес больше, чем ваш конечный адрес, либо вы CONFIG_TRANSPARENT_HUGEPAGE не настроены в ядре, либо вы ссылаетесь на то, что метаданные страницы не существуют или записи таблицы страниц уже существуют.

Уточняя из комментариев, вы обращаетесь к remap_pfn_range ссылкам на указатели записи таблицы страниц или *pte, которые уже указывают на запись таблицы страниц или pte.

Это означает, что set_pte_at(mm, addr, pte, pte_mkspecial(pfn_pte(pfn, prot))); потерпит неудачу, так как указатель pte уже указывает на запись таблицы страниц и, следовательно, не может быть установлен в pte, то есть pte_mkspecial(pfn_pte(pfn, prot)).

Обход виртуального адреса 1G / 3G

См. Следующую статью Большой объем памяти в ядре Linux

См. Следующий список рассылки post , в котором обсуждаются некоторые дополнительные сведения о HIGHMEM с минимальным объемом ОЗУ 1 ГБ.

Информация о сопоставлении виртуального адресного пространства ядра и ядра с пользовательской землей

Один способ отобразить виртуальные адреса ядра и не-ядра (возвращаемые vmalloc ()) в пространство пользователя - использовать remap_pfn_range. См. Linux Memory Mapping для получения дополнительной информации.

Другим способом, который заменил использование обработчика nopage на старых ядрах, является vm_insert_page функция

Дополнительные ресурсы включают в себя:

...