OSDev
http://osdev.su/

Страничная адресация на практике
http://osdev.su/viewtopic.php?f=6&t=3737
Страница 3 из 4

Автор:  FreeProger [ 31 май 2019, 21:55 ]
Заголовок сообщения:  Re: Страничная адресация на практике

Himik писал(а):
Да, можно пока сделать именно так, с помощью битовой карты. Как для физических, так и для виртуальных страниц. Битовая карта физических страниц должна размещаться в общей памяти, а карту виртуальной памяти нужно размещать в объекте каждой задачи. Каталог таблиц тоже должен размещаться в объекте задачи. Тоесть, надо начинать описывать структуру задачи.


А как быть с ядром, ему память должна выделяться как и процессам теми же функциями и для ядра должна тоже быть своя карта виртуальных страниц и каталог? Или ядро не пользуется услугами менеджера.

Автор:  SII [ 01 июн 2019, 01:39 ]
Заголовок сообщения:  Re: Страничная адресация на практике

А это как сделать. В Винде, например, часть памяти ядра фиксированная и всегда находится в физическом ОЗУ, а другая часть является выгружаемой, и система по мере необходимости подгружает туда свои кишки. Но на деле это лишь усложняет ядро и вызывает тормоза. Максимум, что имеет реальный смысл на практике, -- это добавлять к адресному пространству ядра новые страницы памяти для расширения динамической памяти (кучи) ядра, ежели в этом возникнет необходимость.

И, кстати говоря, надо предпринимать меры, чтобы задачи не могли выжрать всю память ядра -- например, определив квоты для задач и отказываясь выделять (прямо или косвенно) дополнительную память, если квота исчерпана.

Автор:  FreeProger [ 01 июн 2019, 14:11 ]
Заголовок сообщения:  Re: Страничная адресация на практике

SII писал(а):
И, кстати говоря, надо предпринимать меры, чтобы задачи не могли выжрать всю память ядра -- например, определив квоты для задач и отказываясь выделять (прямо или косвенно) дополнительную память, если квота исчерпана.


А что имеется в виду под памятью ядра? Например в KolibriOS на сколько я понял пространство делится на две части, нижние 2ГБ отводятся под процессы а верхние 2ГБ под ядро. Выходит что процесс не может занять больше 2ГБ? Но и ядру 2ГБ как то много. И из них тоже можно выделить память процессу? Просто например установлена квота в 100МБ, это значит процесс не может занять в ОЗУ больше 100МБ или это максимум что можно выделить из верхних 2ГБ для процесса?

SII писал(а):
Максимум, что имеет реальный смысл на практике, -- это добавлять к адресному пространству ядра новые страницы памяти для расширения динамической памяти (кучи) ядра, ежели в этом возникнет необходимость.


Этим и занимается функция brk() в UNIX системах?

И еще больше практический вопрос.
Допустим я загружаю ядро по RM адресу 0х1000, перевожу компьютер в PM, перемещаю ядро по адресу 0x100000 затем я должен создать каталог таблиц, в котором описать адресное пространство ядра. При этом виртуальные адреса страниц должны начинаться со второго гигабайта 0x80000000 и расти в сторону 0xFFFFFFFF. А физические адреса проецироваться на физический адрес начала ядра, т.е. 0х100000. Нужно создать столько страниц чтобы покрыть весь размер ядра. Затем я включаю страничную адресацию и прыгаю на виртуальный адрес 0x80000000. А код перекопированной части ядра должен начинаться с директивы org 0x80000000. После чего, если мне понадобиться доп. память для ядра, я могу выделить ее расширив адресное пространство вызвав функцию brk(), менеджер найдет свободные страницы назначит им виртуальные адреса продолжения ядра и вернёт первый виртуальный адрес созданной страницы. При создании процессов менеджер будет создавать каждому процессу свой каталог таблиц и заполнять его таблицами и страницами в зависимости от размера программы. виртуальные адреса у каждого процесса должны начинаться с 0х00000000 и до 0x7FFFFFFF. Получается правда что процесс не может занять больше 2ГБ... А для выделения процессу доп. памяти будет так же вызываться brk() расширяющая его адресное пространство.
Всё ли я правильно представляю?

Автор:  SII [ 01 июн 2019, 20:09 ]
Заголовок сообщения:  Re: Страничная адресация на практике

FreeProger писал(а):
А что имеется в виду под памятью ядра?


Память, используемая ядром формально для своих личных целей -- в отличие от памяти, выделяемой процессам явным образом.

Проблема в том, что на многие "чихи" задач пользовательского режима ядро должно выделять память для собственных структур данных. Скажем, задача запускает новый поток -- нужно создать блок управления потоком. Задача запрашивает операцию ввода-вывода -- нужно создать блок запроса ввода-вывода. Задача создаёт семафор, таймер, мьютекс и т.д. -- ядро должно создать соответствующую внутриядерную структуру. Соответственно, память ядра постоянно расходуется на нужды задач, и, если задачи не ограничивать, может получиться так, что некая задача выжрет таким путём всю память ядра и тем самым блокирует работы системы в целом.

Кроме того, не смешивайте виртуальную и реальную память. Вся память процессов, вообще говоря, является виртуальной, и в каждый момент времени в реальном ОЗУ может находиться лишь малая её часть. Однако память ядра в идеале должна всегда лежать в реальной памяти. Поэтому память каждого процесса может быть достаточно "резиновой" и в 32-разрядном режиме ограничивается, по сути, лишь разрядностью виртуального адреса, в то время как память ядра ограничивается и разрядностью адреса, и фактически доступным объёмом ОЗУ с учётом того, что часть ОЗУ отожрана BIOSом, а какая-то часть должна быть оставлена для пользователя, причём, если физической памяти для процессов не хватает, часть страниц можно выгрузить в файл подкачки, а вот если памяти не хватает ядру, всё намного хуже (в общем случае система зависнет или упадёт -- ну или прибьёт какую-нибудь задачу в надежде освободить достаточно своей памяти).

FreeProger писал(а):
Например в KolibriOS на сколько я понял пространство делится на две части, нижние 2ГБ отводятся под процессы а верхние 2ГБ под ядро. Выходит что процесс не может занять больше 2ГБ? Но и ядру 2ГБ как то много. И из них тоже можно выделить память процессу? Просто например установлена квота в 100МБ, это значит процесс не может занять в ОЗУ больше 100МБ или это максимум что можно выделить из верхних 2ГБ для процесса?


Ну, Винде 2 гига ядру скорей мало, чем много :) Но это уже к вопросу правильного проектирования и реализации системы.
Кстати говоря, это деление адресного пространства поровну Колибри, надо полагать, скоммуниздила из Винды; Винда это позаимствовала из VAX/VMS (главный архитектор Винды НТ был главным разработчиком означенной системы и, естественно, использовал свой предыдущий опыт), а вот в VAX/VMS такое деление диктовалось особенностями архитектуры железа. Т.е. если в VAX/VMS такое решение было вынужденным, то повторять его в Винде не требовалось, просто об этом не задумывались, когда её создавали (4 гига ОЗУ казалось фантастикой). Собственно, в более поздних версиях Винды (по крайней мере, начиная с XP) оно и не обязательно: 32-разрядную систему можно запустить в режиме, когда ядру останется 1 гиг, а процессам будет выделяться 3 гига.

FreeProger писал(а):
Этим и занимается функция brk() в UNIX системах?


Понятия не имею, Унихи никогда меня не интересовали (точней, интересовали, но ровно до того момента, когда я не понял, что они примитивнее даже более ранних систем).

FreeProger писал(а):
И еще больше практический вопрос...

Всё ли я правильно представляю?


Вроде бы да.

На самом деле, размещать ядро, начиная его непременно с 80000000, не требуется. Можно, например, запихнуть его в самые верхие адреса (близко к FFFFFFFF) и расширять (если будет такая нужда) вниз. А можно разместить ядро с нулевого виртуального адреса, а задачи пользователя -- с какого-то более высокого (на самом деле, в большинстве систем в своё время поступали именно так, нынешнее разделение, как я уже говорил, -- наследие VAX/VMS, где оно навязывалось железом). Наконец, виртуальное адресное пространство что ядра, что задач вовсе не обязано быть непрерывным.

Автор:  FreeProger [ 01 июн 2019, 21:18 ]
Заголовок сообщения:  Re: Страничная адресация на практике

Большое спасибо за разъяснения, по не многу начинает проясняется что и как делать.

Автор:  Himik [ 01 июн 2019, 22:30 ]
Заголовок сообщения:  Re: Страничная адресация на практике

FreeProger писал(а):
А как быть с ядром, ему память должна выделяться как и процессам теми же функциями и для ядра должна тоже быть своя карта виртуальных страниц и каталог? Или ядро не пользуется услугами менеджера.
Да, только пользовательские процессы с 3 уровня доступа смогут их вызывать только через шлюзы. Обычно, используя команды int или syscall. При этом менеджер физической памяти им совсем не нужен, им нужна только виртуальная память, или просто brk().

Автор:  FreeProger [ 01 июн 2019, 23:00 ]
Заголовок сообщения:  Re: Страничная адресация на практике

Цитата:
Да, только пользовательские процессы с 3 уровня доступа смогут их вызывать только через шлюзы. Обычно, используя команды int или syscall. При этом менеджер физической памяти им совсем не нужен, им нужна только виртуальная память, или просто brk().


Понял, спасибо.

Автор:  phantom-84 [ 03 июн 2019, 17:42 ]
Заголовок сообщения:  Re: Страничная адресация на практике

FreeProger писал(а):
Допустим я загружаю ядро по RM адресу 0х1000, перевожу компьютер в PM, перемещаю ядро по адресу 0x100000 затем я должен создать каталог таблиц, в котором описать адресное пространство ядра. При этом виртуальные адреса страниц должны начинаться со второго гигабайта 0x80000000 и расти в сторону 0xFFFFFFFF. А физические адреса проецироваться на физический адрес начала ядра, т.е. 0х100000. Нужно создать столько страниц чтобы покрыть весь размер ядра.
Лучше выделять страницы расширенной памяти, не обращая внимание на их физ. адреса. Т.е. будет неплохо, если код ядра будет располагаться в последовательных физ. страницах, но он не обязательно должен располагаться по адресу 0х100000 (например, в начале могут располагаться страницы, необходимые для организации таблицы страниц). Если "нераспакованное" ядро первоначально загружается в базовую память, вы можете сначала включить пагинацию, выделить и отобразить память под ядро, а уже потом туда скопировать код и данные ядра (сам участок выделяемой памяти может быть больше, т.к. после инициализированных данных может быть секция неинициализированных данных, т.н. bss, которую можно не выравнивать на границу страницы).

Цитата:
Затем я включаю страничную адресацию и прыгаю на виртуальный адрес 0x80000000. А код перекопированной части ядра должен начинаться с директивы org 0x80000000. После чего, если мне понадобиться доп. память для ядра, я могу выделить ее расширив адресное пространство вызвав функцию brk(), менеджер найдет свободные страницы назначит им виртуальные адреса продолжения ядра и вернёт первый виртуальный адрес созданной страницы.
Для ядра под "вершину brk" память обычно сразу выделяется, а уже выше идет "четвертая" секция под большие таблицы ядра и т.п. Модули ядра могут располагаться либо до этой секции, также используя ее, либо после, имея собственную подобную секцию.

Цитата:
При создании процессов менеджер будет создавать каждому процессу свой каталог таблиц и заполнять его таблицами и страницами в зависимости от размера программы. виртуальные адреса у каждого процесса должны начинаться с 0х00000000 и до 0x7FFFFFFF. Получается правда что процесс не может занять больше 2ГБ... А для выделения процессу доп. памяти будет так же вызываться brk() расширяющая его адресное пространство.
Про 2 Гб и соответственно базу ядра 0x80000000 уже написали (у меня, например, это значение можно менять при компиляции ядра). Говорить, что brk расширяет адресное пространство, не совсем корректно (хотя иногда встречается такая терминология). Тут "вершина brk" действительно может спокойно меняться в пределах "четвертой" секции, расширяя bss. Но это вершина непрерывной памяти процесса (не обязательно целиком отображенной). А в конце "пользовательского" адресного пространства может, например, располагаться стек (стеки при использовании многопоточности).

Автор:  FreeProger [ 04 июн 2019, 19:05 ]
Заголовок сообщения:  Re: Страничная адресация на практике

Кто может подсказать? Я всегда считал что первые 1024Кб
Отводятся под вектора прерываний реального режима, разве они не должны быть отображены в карте памяти получаемой от BIOS функцией E820 прерывание 15h. Я накидал макрос для получения карты памяти и решил посмотреть что в ней.
Код:
macro m_get_smap
{
  pushad
  push es
  push SMAP_SEG
  pop es
  mov di,SMAP_OFF ; ES:DI Указатель на буфер, отступим два байтам
  xor ebx,ebx       ; Значение возвращенное предыдущим вызовом
  @@:
    mov eax,0xE820     ; Номер функции
    mov ecx,24         ; Размер буфера для принятия ячейки из таблицы (как минимум 20 байт)
    mov edx,0x534D4150 ; Строка "SMAP"
 
    int 15h
   
    mov [SMAP_SIZE],bx ; Запишем колличество таблиц
   
    prints "EBX: "
    printh ebx, 4, 1

    prints "low_address: "
    mov eax, dword[es:di]
    printh eax
    prints " "
 
    prints " | height_address: "
    mov eax,dword[es:di+4]
    printh eax, 8, 1
 
    prints "low_size: "
    mov eax,dword[es:di+8]
    printh eax
    prints " "
 
    prints "| height_size: "
    mov eax,dword[es:di+12]
    printh eax, 8, 1
 
    prints "type: "
    mov eax,dword[es:di+16]
    printh eax, 2
    prints " "
   
    prints " | ACPI extended: "
    mov eax,dword[es:di+20]
    printh eax, 8, 1
   
    add edi,24 ; передвигаем адрес в бувере
    test ebx, ebx
   jnz @b

    pop es
    popad
}


Получил то что на скриншоте.
Получается что первыми идут 654 336 байт и они имеют тип 1 т.е. доступны как обычная память для перезаписи.

Вложения:
Screenshot_2019-06-04-19-02-04.png
Screenshot_2019-06-04-19-02-04.png [ 162.92 КБ | Просмотров: 3076 ]

Автор:  FreeProger [ 04 июн 2019, 19:23 ]
Заголовок сообщения:  Re: Страничная адресация на практике

Это карта памяти эмулируемая qemu с 32Мб ОЗУ. Я так понимаю что основную память можно брать из четвёртой таблицы, размер описуемой ею области 32 374 784 байт

Страница 3 из 4 Часовой пояс: UTC + 3 часа
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/