Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
 iakovlev.org 
 Kernels
 Boot 
 Memory 
 File system
 0.01
 1.0 
 2.0 
 2.4 
 2.6 
 3.x 
 4.x 
 Интервью 
 Kernel
 HOW-TO 1
 Ptrace
 Kernel-Rebuild-HOWTO
 Runlevel
 Linux daemons
 FAQ
NEWS
Последние статьи :
  Rust 07.11   
  Go 25.12   
  EXT4 10.11   
  FS benchmark 15.09   
  Сетунь 23.07   
  Trees 25.06   
  Apache 03.02   
  SQL 30.07   
  JFS 10.06   
  B-trees 01.06   
 
TOP 20
 Go Web ...384 
 2.0-> Linux IP Networking...337 
 Trees...308 
 Steve Pate 3...262 
 Secure Programming for Li...238 
 Rodriguez 6...233 
 Ethreal 1...231 
 Kamran Husain...223 
 Steve Pate 1...217 
 Rubni-Corbet -> Глав...213 
 Stein-MacEachern-> Час...206 
 Ethreal 4...204 
 Стивенс 9...203 
 Mike Perry...202 
 Gary V.Vaughan-> Autotoll...193 
 MySQL & PosgreSQL...193 
 Stevens-> Глава 3...191 
 Rubni-Corbet -> Глав...190 
 TCP 2...188 
 Rubni-Corbet -> Введ...186 
 
  01.08.2017 : 2258659 посещений 

iakovlev.org

Page Table Management

Линукс поддерживает концепцию 3-уровневой page-tables.
Различие между различными типами страниц расплывчато и определимо с помощью флагов .
 Основные термины :
   Memory Management Unit (MMU)
   Page Middle Directory (PMD)
   Page Global Directory (PGD)
   Translation Lookaside Buffer (TLB)
 У каждого процесса есть указатель mm_struct->pgd на свою PGD . 
 PGD физически - страница памяти .
 Он включает массив pgd_t . При загрузке mm_struct->pgd копируется в регистр cr3 .
 В свою очередь , каждая строка PGD включает в себя указатель 
 на страницу памяти с массивом PMD типа pmd_t , 
 а та в свою очередь указывает на страницы PTE типа pte_t , которые указывают
 наконец-то на реальные адреса пользовательских данных .
 
  На рисунке видно , что линейный адрес состоит из 4 частей .
 Есть группа макросов - SHIFT,SIZE,MASK . Макрос SHIFT определяtт битовую 
 длину каждой части .
 Макрос MASK используется как коэффициент для подправки с учетом 
 выравнивания.
 Макрос SIZE определяет количество байт у адреса для каждого уровня .
 Связь между макросами MASK и SIZE показана ниже .
 
   #define PAGE_SHIFT       12
   #define PAGE_SIZE	   (1UL << PAGE_SHIFT)
   #define PAGE_MASK	   (~(PAGE_SIZE-1))
  PAGE_SHIFT=12 - это длина смещения в линейном адресе в битах . 
 Не для интеловской архитектуры это число может быть другим . 
 PAGE_SIZE = 2^PAGE_SHIFT. PAGE_MASK вычисляется как логическое
 отрицание от (PAGE_SIZE-1).
 PMD_SHIFT , PMD_SIZE , PMD_MASK берутся из page table 2-го уровня 
 и вычисляются аналогично .
 PGDIR_SHIFT , PGDIR_SIZE , PGDIR_MASK берутся из page table 1-го , 
 верхнего уровня и вычисляются аналогично .
 Макрос PTRS_PER_x - это число строк в page table .
 PTRS_PER_PGD - число строк в PGD , которое обычно фиксировно и равно 1024 .
 PTRS_PER_PMD - число строк в PMD , которое = 1 .
 PTRS_PER_PTE - число строк для page table самого низкого уровня и обычно = 1024 .
 Следующая таблица показывает назначение отдельных битов в pte_t :

Page Table Entry Protection and Status Bits

Bit

Function

_PAGE_PRESENT

Page is resident in memory and not swapped out.

_PAGE_PROTNONE

Page is resident, but not accessible.

_PAGE_RW

Set if the page may be written to

_PAGE_USER

Set if the page is accessible from userspace

_PAGE_DIRTY

Set if the page is written to

_PAGE_ACCESSED

Set if the page is accessed

  В файле  определены макросы для работы с page table .
 3 макроса для работы с page directory :
  pgd_offset() - возвращает адрес PGD
  pmd_offset() - возвращает адрем PMD
  pte_offset() - возвращает адрес PTE
  pte_none(), pmd_none() and pgd_none() - эти макросы обрабатывают 
  отсутствие адреса в page table
  pte_present(), pmd_present() and pgd_present() - аналогично для наличия
  pte_clear(), pmd_clear() and pgd_clear() - убирают строку в page table
 Пример использования : 
       pgd_t *pgd;
       pmd_t *pmd;
       pte_t *ptep, pte;
       pgd = pgd_offset(mm, address);
       if (pgd_none(*pgd) || pgd_bad(*pgd))   goto out;
 Еще одна группа макросов проверяет статус адресов и их права 
 на запись,выполнение :
  pte_read(), set with pte_mkread() , pte_rdprotect()
  pte_write(), set with pte_mkwrite(),pte_wrprotect()
  pte_exec(), set with pte_mkexec(),pte_exprotect().
 
 Следующая группа функций и макросов имеет отношение к маппингу адресов PTE.
 Макрос mk_pte()  формирует pte_t путем комбинации структуры page и protection bits .
 Макрос pte_page() наоборот возвращает структуру page по данному pte_t .
 
 Последний набор функций выделяет память для page tables .
 Выделение памяти под page tables - критический момент,
 в течение которого прерывания должны
 быть задисэйблены.Это очень популярная процедура и должна 
 выполняться максимально быстро .
 Страницы кэшируются в различные списки , которые называются quicklists.
 PGDs, PMDs и PTEs имеют 2 набора функций для размещения и удаления страниц .
 Это соответственно pgd_alloc(), pmd_alloc() ,pte_alloc() и pgd_free(), 
 pmd_free() and pte_free().
 В основе формирования этих списков лежит структура LIFO - Last In, First Out .
 Если страница не может быть помещена в кеш , она размещается 
 в памяти с помощью  page allocator .
 Специальный механизм следит за тем , чтобы кеш находился 
 в пределах фиксированного обьема .
 Инициализация page tables разделена на 2 части . 
 При старте системы инициализируются только первые 8 метров,остальное позже . 
 В файле arch/i386/kernel/head.S лежит функция startup_32() .
 Стартовый загрузочный адрес , по которому загружается ядро - 0x00100000.
 Первый мегабайт используется устройствами для работы с биосом .
 Инициализация page tables начинается со статического массива swapper_pg_dir , который
 размещается по адресу 0x00101000 . Затем инициализируются 2 таблицы  pg0 и pg1 .
 Если процессор поддерживает Page Size Extension (PSE) , 
 размер страницы будет установлен
 в 4 метра, а не в 4 килобайта , как обычно . 
 Остальную работу по инициализации page table
 выполняет paging_init.  Граф инициализации :
 
  При иницмализации page tables должна стать доступной 
  вся память в зоне ZONE_DMA и ZONE_NORMAL .
 При загрузке системы для каждой pgd_t , которая используется ядром , 
 выделит страницу PGD .
 Функция fixrange_init() выделяет память 
 для Advanced Programmable Interrupt Controller (APIC).
 Статический адрес swapper_pg_dir для  PGD  загружатеся в CR3 .
 Функция kmap_init() инициализирует PTE.
  Перевод виртуального адреса в физический должен быть максимально быстрым , 
  и это достигается с помощью глобального массива mem_map . 
  Физический адрес может быть получен из виртуального
 простым вычитанием PAGE_OFFSET : 
 /* from  */
  #define __pa(x)                   ((unsigned long)(x)-PAGE_OFFSET)
 
 /* from  */
  static inline unsigned long virt_to_phys(volatile void * address)
  {
          return __pa(address);
  }
  Ядро загружается по адресу 1MiB и берет на свои нужды 8 метров . 
 Ядро пытается зарезервировать 16 метров в ZONE_DMA , 
 и стартовый виртуальный адрес будет соответствовать физическому  0xC1000000.
 Таблица mem_map содержит индексы физических адресов - 
 Page Frame Number (PFN) - который получается
 путем сдвига виртуального адреса :
 #define virt_to_page(kaddr) (mem_map + (__pa(kaddr) >> PAGE_SHIFT))
  Для ускорения обращения к памяти , существует специальная таблица - 
  Translation Lookaside Buffer (TLB) -
 которая представляет из себя набор наиболее часто используемых адресов памяти . 
 Использование этой таблицы позволяет избегать многократного повторения 
 вычисления одних и тех же физических адресов ,
 которые уже имеются в этом буфере .
  Интеловские процессоры имеют встроенный 2-уровневый кеш . 
  Кеш 2-уровня больше , но медленнее , чем 1-й .
 Линукс использует кеш 1-го уровня . 
 Обращение к кешу быстрее на порядок , чем к памяти .
 
Оставьте свой комментарий !

Ваше имя:
Комментарий:
Оба поля являются обязательными

 Автор  Комментарий к данной статье