indiangovernemntjob
I’m studying on writing embedded linux driver, and decided to fire a few GPIOs to make sure I understand the book (LDD3, chap9.4.1) correctly.
I am able to control the correct GPIO pins as intended (making it high and low, I probed with a multimeter); however, I tested 2 pieces of code, one with request_mem_region() , and one without. I’m expecting the one without will fail, but both is working just fine.
if( request_mem_region( PIN3_CONF_PHYS, MAPPED_SIZE_GPIO_CONF,DEVICE_NAME ) == NULL )
printk( KERN_ALERT
"GPIO_140_141_conf_phys error:%s: unable to obtain I/O memory address 0x%08llX\n",
DEVICE_NAME, PIN3_CONF_PHYS );
return -EBUSY;
>
pin3_conf = (u32)ioremap( PIN3_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
pin4_conf = (u32)ioremap( PIN4_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
pin5_conf = (u32)ioremap( PIN5_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
pin6_conf = (u32)ioremap( PIN6_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
//-----------------------------------------------------------------
if( request_mem_region( GPIO_BANK5_PHYS, MAPPED_SIZE_GPIO_5,DEVICE_NAME ) == NULL )
printk( KERN_ALERT
"error:%s: unable to obtain I/O memory address 0x%08llX\n",
DEVICE_NAME, GPIO_BANK5_PHYS );
return -EBUSY;
>
gpio_virt = (u32)ioremap( GPIO_BANK5_PHYS, MAPPED_SIZE_GPIO_5 );
//some iowrite32() functions continue.
pin3_conf = (u32)ioremap( PIN3_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
pin4_conf = (u32)ioremap( PIN4_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
pin5_conf = (u32)ioremap( PIN5_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
pin6_conf = (u32)ioremap( PIN6_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
gpio_virt = (u32)ioremap( GPIO_BANK5_PHYS, MAPPED_SIZE_GPIO_5 );
//some iowrite32() functions continue.
The only difference I can observe from both cases is the result of doing a cat /proc/iomem , the one with request_mem_region() will display an additional line showing 49056000-49056097 : GPIO3 .
My question is why request_mem_region() is needed since I can still communicate with the hardware address with only ioremap() ? So when do we actually need to use request_mem_region() ?
request_mem_region allows to tell the kernel that your driver is going to use this range of I/O addresses, which will prevent other drivers to make an overlapping call to request_mem_region . This mechanism does not do any kind of mapping, it’s a pure reservation mechanism, which relies on the fact that all kernel device drivers must be nice, and they must call request_mem_region , check the return value, and behave properly in case of error.
So it is completely logical that your code works without request_mem_region , it’s just that it doesn’t comply with the kernel coding rules.
However, your code doesn’t comply with the kernel coding style. And additionnally, there is an existing infrastructure to handle GPIOs, named gpiolib, which you should use instead of manually remapping your GPIO bank registers. Which platform are you working on ?
Глава 11. Управление памятью ядра
В системе Linux все адреса памяти являются виртуальными. Они не указывают напрямую ни на какие физические адреса в имеющейся оперативной памяти. Всякий раз когда кто- либо осуществляет доступ к некоторому расположению в памяти, выполняется механизм трансляции для подбора соответствующей физической памяти.
Давайте начнём с короткого повествования введения в применяемое понятие виртуальной памяти. Получая номер в отеле, в каждой из комнат может иметься некий частный номер. Все установленные телефоны, само собой, принадлежат данному отелю. Никто не имеет возможности подключаться напрямую извне с данным отелем.
Если вам необходимо осуществит связь с кем-то, кто занимает эту комнату, допустим, с вашим другом, тот должен выдать вам номер панели переключения в отеле и собственно номер той комнаты, в которой вы остановились. Соответствие данного часного номера знают только располагающийся на стойке ресепшена и самого занимающего комнату:
(номер панели переключения + номер комнаты) частный (реальный) номер телефона
Всякий раз, когда кто-то в этом городе (или по всему миру) желает соединиться с занимающим комнату, он должен пройти имеющуюся линию оперативной поддержки. Ему необходимо знать верный номер оперативной связи с самим отелем, а также необходимый номер комнаты. Таким образом, номер панели переключения + номер комнаты = виртуальному адресу, в то время как private phone number соответствует искомому физическому адресу. Имеется ряд правил, связанных с моделью отеля, которые также относятся и к Linux:
Вы не имеете возможности контактировать с частным телефоном того, кто занимает комнату. Даже нет варианта осуществить такую покупку. Ваш вызов внезапно будет оборван.
Вы не можете получить доступ к несуществующей памяти в вашем адресном пространстве. Это вызовет отказ сегментации.
Вы не можете осуществить соединение с несуществующим жильцом комнаты или с тем, о ком не знает персонал как о поселившимся в данном отеле, либо о ком- то, о ком нет информации в имеющейся панели переключения.
Если вы осуществляете доступ к не поставленной в соответствие памяти, имеющийся ЦПУ возбуждает отказ страницы и сама ОС отрабатывает его.
Вы не можете осуществить соединение с тем, чьё пребывание в отеле завершено.
Вы не можете получить доступ к высвобождённой памяти. Может оказаться, что она уже была выделена другому процессу.
Многие отели имеют один и то же бренд, однако они расположены в различных местоположениях, причём каждый из них имеет различные номера оперативной связи.
Различные процессы могут иметь одни и те же виртуальные адреса, которые соответствуют их адресному пространству, однако указывающие на другие физические адреса.
Существует некая книга (или программное обеспечение с базой данных), содержащая соответствие между необходимым номером комнаты и необходимым частным номером, с которой консультируется при необходимости оператор.
Виртуальные адреса устанавливают соответствие необходимой физической памяти в соответствии с таблицами страниц., которые сопровождаются самим ядром операционной системы и выступают в качестве консультанта их процессора.
Именно так можно себе представлять то, как работают все виртуальные адреса в системе Linux.
В этой главе мы будем иметь дело со всей системой управления памяти Linux, охватывая следующие разделы:
- Схемы памяти, применяемые при трансляции адресов и MMU
- Механизмы выделения памяти (блок распределения страниц, блок распределения листов — slab, блок распределения kmalloc и так далее)
- Доступ ввода/ вывода памяти
- Установление соответствия памяти ядра пространству пользователя и реализации функции обратного вызова mmap()
- Введение в систему кэширования Linux
- Введение в инфраструктуру ресурсов управления имеющимися устройствами ( devres )
Схема памяти системы — пространство ядра и пространство пользователя
На протяжении данной главы такие термины как пространство ядра (kernel space) и пространство пользователя (user space) будут относиться к их виртуальному адресному пространству. В системах Linux всякий процесс обладает собственным виртуальным адресным пространством. Это некий вид песочница памяти на время жизни данного процесса. В системах с 32 битами это адресное пространство составляет 4ГБ в размере (даже для систем с физическим размером менее 4ГБ). Для каждого процесса это адресное пространство в 4ГБ расщепляется на две части:
Тот способ, которым осуществляется данное расщепление зависит от специальной опции настройки ядра, CONFIG_PAGE_OFFSET , которая определяет где начинаются адреса самого ядра в адресном пространстве некоего процесса. Обычным значением является значение по умолчанию 0xC0000000 в 32- битных системах, однако его можно изменять, как это имеет место в случае процессоров семейства i.MX6 от NXP, которые используют 0x80000000 . Во всей данной главе мы будем считать значением по умолчанию адрес 0xC0000000 . Такое расщепление именуется как расщепление 3G/1G, при котором пространству пользователя предоставляются нижние 3ГБ виртуального адресного пространства, а само ядро применяет оставшийся 1ГБ верхних адресов. Некая типичная схема виртуального адресного пространства процесса выглядит следующим образом:
.------------------------. 0xFFFFFFFF | | (4 GB) | Kernel addresses | | | | | .------------------------.CONFIG_PAGE_OFFSET | |(x86: 0xC0000000, ARM: 0x80000000) | | | | | User space addresses | | | | | | | | | '------------------------' 00000000
Оба адреса, применяемые и пространством ядра, и пространством пользователя, являются виртуальными адресами. Единственная разница состоит в том, что доступ к некоторому адресу ядра требует какого- то привилегированного режима. Привилегированные режим имеет расширенные полномочия. Когда ЦПУ осуществляет исполнение кода на стороне пространства пользователя, такой активный процесс именуется как исполняемый в определённом режиме пользователя; когда этот ЦПУ исполняет код на стороне своего ядра, такой активный процесс именуется исполняемым в режиме ядра.
Определяя некий адрес (естественно, виртуальный), можно различить будет ли это адрес пространства ядра или адрес пространства пользователя, применяя приведённую выше схему процесса. Всякий адрес, попадающий в 0-3ГБ поступает из пространства пользователя, в противном случае он из своего ядра.
Имеется некоторая причина почему имеющееся ядро разделяет своё адресное пространство со всеми процессами: а именно, потому что всякий отдельный процесс в некий определённый момент времени применяет системные вызовы, которые вовлечены в имеющееся ядро. Установление соответствия такого виртуального адреса памяти ядра адресному пространству каждого процесса позволяет нам избегать стоимости переключения адресного пространства памяти при каждом входе в (и выходе из) имеющееся ядро. Именно по этой причине данное адресное пространство ядра непрерывно ставится в соответствие в верхних адресах каждого процесса, чтобы ускорить доступ к ядру при вызовах системы.
Управление элементами всей памяти организовано в виде единиц фиксированного размера, именуемых страницами. Страница содержит 4 096 байт (4кБ). Даже хотя данный размер может отличаться в прочих системах, он фиксирован в ARM и x86, архитектурами которых мы интересуемся:
- некая памяти страница, виртуальная страница или просто страница являются терминами, применяемыми для ссылки на непрерывный блок виртуальной памяти фиксированной длины. Аналогичное наименование, page , применяется как некая структура данных ядра для представления какой- то страницы памяти.
- С другой стороны, кадр (frame, или страничный блок) указывает на некий непрерывный блок фиксированного размера физической памяти в верхних адресах, в которых данная операционная система ставит в соответствие некую страницу памяти. Каждый страничный блок определяется неким номером, PFN ( page frame number , номером страничного блока). Задавая некую страницу можно легко получить её PFN и наоборот, применяя макросы page_to_pfn и pfn_to_page , что подробно будет обсуждено в следующих разделах.
- Некая таблица страниц является определяющей структурой данных ядра и архитектуры, применяемой для имеющегося соответствия между виртуальными адресами и физическими адресами. Определённый ключ пары страница/ кадр задаёт некую единичную запись в данной таблице страниц. Это и представляет из себя соответствие.
Так как некая страница памяти ставится в соответствие страничному блоку, само собой разумеется, что страницы и страничные блоки имеют один и тот же размер, в нашем случае 4кБ. Данный размер страницы определяется в самом ядре посредством макроса PAGE_SIZE .
Существуют ситуации, при которых необходимо выравнивать память на границы страниц. Говорят, что некая память является выравненной на границу страниц, если её адреса начинаются в точности в самом начале какой- то страницы. Например, в системе с размером страницы 4K, 4 096, 20 480, 409 600 представляют собой адреса памяти выравненные на границу страниц. Другими словами, всякая память, адрес которой является произведением имеющегося размера страницы именуется выравненным на границу страницы.
Адресация ядра — понятие нижних и верхних адресов памяти
Ядро Linux имеет своё собственное виртуальное адресное пространство, как это имеется в случае режима каждого процесса пользователя. Такое виртуальное адресное пространство самого ядра (с размером в 1ГБ при расщеплении 3G/1G) подразделяется на две части:
- Нижние адреса, или LOWMEM , которыми являются самые первые 896МБ
- Верхние адреса, или HIGHMEM , представленные вверху 1286МБ
Physical mem Process address space +------> +------------+ | | 3200 M | | | | 4 GB +---------------+ +------------+ 3 GB +---------------+ +------------+ | | | | 896 MB | LOW MEM | ///// | +---------> +------------+ | | 0 GB +---------------+
Нижние адреса памяти
Верхние адреса памяти