общая защита в кастомной ОС - PullRequest
1 голос
/ 20 октября 2011

Я планирую написать собственную ОС для 64-битной архитектуры Intel, и мне нужно внедрить механизм общей защиты. Я буду использовать не виртуальную память или пейджинг, а физическую адресацию. Я пока не знаю, как именно это реализовать, но у меня есть общая идея, и она выглядит примерно так:

  1. При запуске ядро ​​будет загружено и предположим, что оно запустит первый пользовательский процесс под названием «filemanager», который сохранит некоторые данные на диск по какому-либо сигналу, полученному от другого процесса.
  2. Файловый менеджер будет иметь сегмент кода, сегмент стека и сегмент данных.
  3. Во время нормальной работы ядро ​​запускает другие процессы, которые извлекают память из доступной кучи физической памяти, управляя которой заботится ядро.
  4. Предположим, процесс 'filemanager' должен получить больше оперативной памяти, потому что его сегмент данных заполнен. Он отправляет системный вызов ядру, чтобы запросить другой сегмент данных. Ядро отдает ему запрошенный кусок памяти, который физически расположен в другом месте и не является сомнительным по отношению к первому сегменту.

Теперь возникает вопрос, как приложение ('filemanager') будет обрабатывать 2 сегмента? Поскольку механизм общей защиты, реализованный Intel, насколько я понимаю, может проверять только пределы текущего сегмента, который хранится в «DS». Но в случае с файловым менеджером у нас сейчас есть 2 сегмента. Нужно ли вручную переключаться с одного сегмента на другой внутри приложения? Было бы больно кодировать такое приложение потому что вам придется написать что-то вроде этого:

    __asm('set DS register to the address and length of segment 1');
    for (i=0;i<size_of_segment1;i++) {
        segment1_data[i]= some_processing();
    }
    __asm('set DS register to the address and length of segment 2');
    for (i=0;i<size_of_segment2;i++) {
        segment2_data[i]= some_processing();
    }

Это только для 2 сегментов, но представьте, что приложению придется запросить у ядра 1000 или более сегментов данных, как реализовать механизм общей защиты, чтобы программист мог быстро и легко программировать для разработчика? Один из способов сделать это - изменить GCC и вставить код сборки, чтобы загрузить соответствующий сегмент данных в регистр DS перед доступом к каждому сегменту данных, но это выглядит как большая работа. Есть ли другие способы?

Продолжение ... 5. Общая память. Допустим, другому «редактору» процесса нужно сохранить некоторые данные через процесс «файлового менеджера». Механизм разделяемой памяти должен быть предоставлен ОС. Процесс 'editor' запросит ядро ​​добавить сегмент данных процесса 'filemanager'. 'Filemanager' подтвердит запрос, и новый сегмент будет добавлен в список сегментов данных редактора, чтобы он мог по закону писать в него. Опять же, вопрос тот же: как мне переключаться между несколькими сегментами внутри «редактора», чтобы он был прозрачным для приложения и безопасным для всей системы?

Примечание: я не буду использовать подкачку в моей ОС, вся адресация памяти будет физической, и она будет в режиме 64.

Ответы [ 2 ]

2 голосов
/ 23 октября 2011

Если вы находитесь в 64-битном режиме, тогда сегментный регистр вообще отсутствует: содержимое CS, DS ... просто игнорируется.Адреса являются 64-битными значениями в «плоском» адресном пространстве.Сегментные регистры используются в 16-битном и 32-битном режимах, хотя большинство 32-битных ОС устанавливают, что все сегменты начинаются с адреса 0 и занимают более 4 ГБ, чтобы они могли забыть о них навсегда.Если вы используете регистры сегментов (так что код приложения может использовать несколько «сегментов»), то на уровне C компилятор C должен знать о них, и «указатель» будет включать в себя как значение сегмента, так и значение смещения.Установка сегментного регистра стоит дорого, поэтому, если вы можете обойтись без сегментов, производительность лучше.Это объясняет, почему 32-битные ОС, такие как Linux или Windows, не используют сегменты, и, соответственно, производители процессоров адаптировали и просто пропустили поддержку сегментов в 64-битном режиме.

Тогда возникает реальный вопрос: хотите ли вызащита памяти между приложениями?Защита памяти заключается в блокировании процесса от чтения или записи памяти, которую он не должен читать / записывать, а именно памяти, используемой другим процессом или ядром.Вы можете обойтись без памяти, защищенной от памяти, если прикладные программисты никогда не пишут код с ошибками (ммх ... насколько это правдоподобно?) или , если приложения написаны на языке, который включает систематические проверки, запрещающие недопустимый доступ к памяти (например, Java) (проект JNode был посвящен ОС на Java, но я не знаю, жива ли она еще).Чтобы получить защиту памяти, вы используете MMU .MMU работает по «страницам»: адресное пространство разбивается на страницы фиксированного размера (по 4 КБ каждая на x86), и ОС устанавливает таблицы в ОЗУ, которые сообщают MMU, где физически находится каждая страница.Пейджинг, дисковая виртуальная память ... используйте MMU.Но вы также можете использовать MMU «просто» для защиты памяти (вы устанавливаете его так, чтобы каждая страница либо присутствовала по виртуальному адресу, который равен ее физическому адресу, либо помечена как «отсутствующая», если доступ к этой странице в настоящее время отсутствуетразрешено).

Если не использовать MMU, это может повысить производительность в некоторых очень специфических ситуациях (я знаю кого-то, кто делал это для просеивания, как часть большого криптографически ориентированного вычислительного усилия: просеивание было почти100% случайного доступа к памяти в массиве 1 ГБ: MMU предполагал три пропуска кэша вместо одного на каждый доступ, поэтому обход без MMU делал все это в три раза быстрее - но это действительно крайний случай).С другой стороны, MMU облегчает жизнь разработчикам приложений, особенно потому, что позволяет каждому приложению иметь свое нормализованное адресное пространство (например, вы можете заранее скомпилировать и связать код C).

0 голосов
/ 23 октября 2011

Если взглянуть на это с другой стороны, как это будет выглядеть, скажем, для программиста на Си, который хочет получить доступ к вашей памяти? Что возвращает Kernel.AllocateMemory? Он не может возвратить 64-битное значение, потому что этого недостаточно для представления как сегмента, так и смещения (на практике сегодня машины x64 имеют доступ к менее чем 2 ^ 64 байтам памяти, поэтому вы можете хранить номер сегмента в некоторых из неиспользованных битов, но я не думаю, что вы хотите это сделать).

Звучит так, будто вы ищете «дальний указатель» (взрыв из прошлого - см., Например, http://www.daniweb.com/software-development/c/threads/345287).

Если вы не хотите изменять сегменты вручную, тогда я не вижу, как вы можете избежать модификации компилятора, которая будет поддерживать дальний указатель. Обратите внимание, что если у вас есть только два сегмента, вы можете обращаться к данным, используя как DS, так и ES, но даже это требует различного кода сборки в зависимости от того, какой сегмент вы хотите использовать. Кто-то должен будет принять решение сгенерировать этот код, и это будет либо вы, либо компилятор.

...