Ядро ОС Linux

       

Процессы и программа управления памятью


Работа, связанная с памятью, производимая посредством fork():

Выделение памяти

  • 1 страница для task_struct.
  • 1 страница для стека ядра.
  • 1 для pg_dir и несколько для pg_tables (co[py_page_tables)
  • Другие изменения

  • ss0 установить на адрес сегмента стека ядра (0х10) чтобы быть уверенным?
  • esp0 установит на вершину вновь созданного kernel_stack_page
  • cr3 устанавливается посредством copy_page_tables() для указания на вновь размещенную директорию страниц.
  • ltd=_LTD(task_nr) создает новый дескриптор ltd.
  • дескриптор устанавливается в gdt для нового tss и ltd[].
  • Остальные регистры наследуются от родителя.
  • Процессы прекращают разделение их сегментов данных и кода (хотя они имеют раздельные локальные таблицы дескрипторов, входы указывают на те же сегменты). Страницы стека и данных будут скопированы, когда родитель или наследник будет писать в них (СOPY-ON-WRITE)

    Работа, связанная с памятью, производимая посредством exec():

  • Выделение памяти
  • 1 страница для exec-заголовка полного файла для omagic
  • 1 страница или больше для стека (MAX_ARG_PAGES)
  • clear_page_tables() используется для удаления старых страниц.
  • change_ltd() устанавливает дескрипторы в новом LTD[]
  • ltd[1] = code base = 0x00, limit = TASK_SIZE
  • ltd[2] = data base = 0x00, limit = TASK_SIZE
  • Эти сегменты представляются DPL=3,P=1,S=1,G=1 type=a(code) или 2(data)

  • До MAX_ARG_PAGES грязные страницы argv и envp размещаются и сохраняются на вершине сегмента данных для вновь созданного пользовательского стека.
  • Установить указатель инструкции вызывающей программы eip = ex.a_entry.
  • Установить указатель стека вызывающей программы на созданный стек (esp = stack pointer) Данные будут выбраны из стека при возобновлении вызывающей программы.
  • Редактирование ограничений на память

    end_coe = ex.a_text

    end_data = end_code + ex.a_data

    brk = end_data + ex.a_bss

  • Программные и аппаратные прерывания управляются внутри контекста текущей задачи. Более детально, директория страниц текущего процесса используется при трансляции адреса. Сегменты, однако, являются сегментами ядра и таким образом все линейные адреса указывают в область памяти ядра. Предположим, например, что пользовательский процесс выполняет системный вызов и ядро хочет получить доступ к переменной по адресу 0х01. Линейный адрес будет равен 0хс0000001 (использование сегментов ядра) и физический адрес - 0х01. Буква здесь присутствует вследствие того, что директория страниц процесса отображает этот диапазон точно как page_pg_dir.

    Область ядра (0хс0000000 + high_memory) отображается через таблицы страниц ядра, которые являются частью RESURVED памяти. Поэтому они разделяются всеми процессами. Во время распараллеливания copy_page_tables() напрямую обращается к таблицам RESERVED страниц. Она устанавливает указатели в директориях страниц процесса, чтобы указывать на таблицы страниц ядра и не размещает в памяти новых таблиц страниц, как это обычно делается. В качестве примера kernel_stack_page (который размещен где-то в области ядра) не нуждается в связанной page_table, размещенной в p_dir процесса, чтобы отобразить ее.

    Инструкция прерывания устанавливает указатель стека и сегмент стека из привилегированных 0 значений, сохраненных в tss текущей задачи. Заметьте, что стек ядра в действительности является фрагментированным объектом - это не единственный объект, а группа стековых фреймов, каждый из которых размещается в памяти при создании процесса и освобождает память при окончании его. Стек ядра никогда не должен расти внутри контекста процесса слишком быстро, чтобы не расширится за пределы текущего фрейма.



    Содержание раздела