Ядро представляет собой компьютерную программу , в основе компьютера операционной системы и имеет полный контроль над всем в системе. [1] Это «часть кода операционной системы, которая всегда находится в памяти», [2] и облегчает взаимодействие между аппаратными и программными компонентами. В большинстве систем ядро является одной из первых программ, загружаемых при запуске (после загрузчика ). Он обрабатывает остальную часть запуска, а также запросы памяти, периферийных устройств и ввода / вывода (I / O) от программного обеспечения , переводя их в обработку данных.инструкции для центрального процессора .
Критический код ядра обычно загружается в отдельную область памяти, которая защищена от доступа со стороны прикладного программного обеспечения или других, менее важных частей операционной системы. Ядро выполняет свои задачи, такие как запуск процессов, управление аппаратными устройствами, такими как жесткий диск , и обработка прерываний в этом защищенном пространстве ядра . Напротив, прикладные программы, такие как браузеры, текстовые процессоры, аудио- или видеоплееры, используют отдельную область памяти, пользовательское пространство . Такое разделение предотвращает взаимодействие пользовательских данных и данных ядра друг с другом, что приводит к нестабильности и замедлению работы [1]. а также предотвращение воздействия неисправных приложений на другие приложения или сбоя всей операционной системы.
Ядро в интерфейсе является низкоуровневым уровнем абстракции . Когда процесс запрашивает службу у ядра, он должен вызвать системный вызов , обычно через функцию- оболочку .
Существуют разные конструкции архитектуры ядра. Монолитные ядра работают полностью в одном адресном пространстве, а ЦП работает в режиме супервизора , в основном для скорости. Микроядра запускают большинство, но не все свои сервисы в пространстве пользователя [3], как это делают пользовательские процессы, в основном для обеспечения устойчивости и модульности . [4] MINIX 3 является ярким примером дизайна микроядра. Вместо этого ядро Linux является монолитным, хотя оно также и модульным, поскольку оно может вставлять и удалять загружаемые модули ядра во время выполнения.
Этот центральный компонент компьютерной системы отвечает за выполнение программ. Ядро берет на себя ответственность за принятие решения в любой момент, какая из многих запущенных программ должна быть выделена процессору или процессорам.
Оперативная память (RAM) используется для хранения как программных инструкций, так и данных. [примечание 1] Обычно оба должны присутствовать в памяти для выполнения программы. Часто нескольким программам требуется доступ к памяти, часто требуя больше памяти, чем доступно на компьютере. Ядро отвечает за решение, какую память может использовать каждый процесс, и за определение того, что делать, когда памяти недостаточно.
К устройствам ввода-вывода относятся такие периферийные устройства, как клавиатуры, мыши, дисководы, принтеры, USB- устройства, сетевые адаптеры и устройства отображения . Ядро распределяет запросы от приложений для выполнения ввода-вывода соответствующему устройству и предоставляет удобные методы использования устройства (обычно абстрагированные до такой степени, что приложению не требуется знать детали реализации устройства).
Ключевыми аспектами, необходимыми в управлении ресурсами, являются определение домена выполнения ( адресного пространства ) и механизма защиты, используемого для обеспечения доступа к ресурсам в пределах домена. [5] Ядра также предоставляют методы для синхронизации и межпроцессного взаимодействия (IPC). Эти реализации могут быть внутри самого ядра, или ядро также может полагаться на другие запущенные процессы. Хотя ядро должно предоставлять IPC для обеспечения доступа к средствам, предоставляемым друг другом, ядра также должны предоставлять работающим программам метод для выполнения запросов на доступ к этим средствам. Ядро также отвечает за переключение контекста между процессами или потоками.
Ядро имеет полный доступ к системной памяти и должно разрешать процессам безопасный доступ к этой памяти по мере необходимости. Часто первым шагом в этом является виртуальная адресация , обычно достигаемая с помощью разбиения по страницам и / или сегментации . Виртуальная адресация позволяет ядру сделать данный физический адрес похожим на другой адрес, виртуальный адрес. Виртуальные адресные пространства могут быть разными для разных процессов; память, к которой один процесс обращается по определенному (виртуальному) адресу, может отличаться от памяти, к которой другой процесс обращается по тому же адресу. Это позволяет каждой программе вести себя так, как если бы она была единственной (кроме ядра) запущенной, и, таким образом, предотвращает сбой приложений друг друга. [6]
Во многих системах виртуальный адрес программы может относиться к данным, которых в настоящее время нет в памяти. Уровень косвенного обращения, обеспечиваемый виртуальной адресацией, позволяет операционной системе использовать другие хранилища данных, такие как жесткий диск , для хранения того, что в противном случае должно было бы оставаться в основной памяти ( ОЗУ ). В результате операционные системы могут позволять программам использовать больше памяти, чем физически доступно системе. Когда программе требуются данные, которых в настоящее время нет в ОЗУ, ЦП сигнализирует ядру, что это произошло, и ядро отвечает, записывая содержимое неактивного блока памяти на диск (при необходимости) и заменяя его данными, запрошенными программа. Затем программа может быть возобновлена с того места, где она была остановлена. Эта схема широко известна какпейджинг по запросу .
Виртуальная адресация также позволяет создавать виртуальные разделы памяти в двух несвязанных областях, одна из которых зарезервирована для ядра ( пространство ядра ), а другая - для приложений ( пространство пользователя ). Процессор не разрешает приложениям обращаться к памяти ядра, что предотвращает повреждение приложением работающего ядра. Это фундаментальное разделение пространства памяти внесло большой вклад в современные разработки реальных ядер общего назначения и почти универсально в таких системах, хотя некоторые исследовательские ядра (например, Singularity ) используют другие подходы.
Для выполнения полезных функций процессам необходим доступ к периферийным устройствам, подключенным к компьютеру, которые управляются ядром через драйверы устройств.. Драйвер устройства - это компьютерная программа, которая позволяет операционной системе взаимодействовать с аппаратным устройством. Он предоставляет операционной системе информацию о том, как управлять определенным оборудованием и взаимодействовать с ним. Драйвер - важная и жизненно важная часть программного приложения. Цель разработки драйвера - абстракция; функция драйвера состоит в том, чтобы преобразовывать вызовы абстрактных функций, требуемых ОС (программные вызовы), в вызовы, специфичные для устройства. По идее, устройство должно корректно работать с подходящим драйвером. Драйверы устройств используются для таких вещей, как видеокарты, звуковые карты, принтеры, сканеры, модемы и карты LAN.
На аппаратном уровне общие абстракции драйверов устройств включают:
А на уровне программного обеспечения абстракции драйверов устройств включают:
Например, чтобы показать пользователю что-то на экране, приложение отправит запрос к ядру, которое перенаправит запрос своему драйверу дисплея, который затем отвечает за фактическое отображение символа / пикселя. [6]
Ядро должно поддерживать список доступных устройств. Этот список может быть известен заранее (например, во встроенной системе, где ядро будет переписано при изменении доступного оборудования), настроен пользователем (обычно на старых ПК и в системах, которые не предназначены для личного использования) или обнаружен операционная система во время выполнения (обычно это называется plug and play ). В системах plug-and-play диспетчер устройств сначала выполняет сканирование на различных периферийных шинах , таких как Peripheral Component Interconnect (PCI) или Universal Serial Bus (USB), для обнаружения установленных устройств, а затем выполняет поиск соответствующих драйверов.
Поскольку управление устройствами - это тема, очень специфичная для ОС , эти драйверы обрабатываются по-разному в зависимости от конструкции ядра, но в каждом случае ядро должно обеспечивать ввод-вывод, чтобы драйверы могли физически обращаться к своим устройствам через какой-либо порт или память. расположение. При разработке системы управления устройствами необходимо принять важные решения, поскольку в некоторых проектах доступ может включать переключение контекста , что делает операцию очень интенсивной для ЦП и легко вызывает значительные накладные расходы на производительность. [ необходима цитата ]
В вычислениях системный вызов - это то, как процесс запрашивает службу у ядра операционной системы, на запуск которой у него обычно нет разрешения. Системные вызовы обеспечивают интерфейс между процессом и операционной системой. Для большинства операций, взаимодействующих с системой, требуются разрешения, недоступные для процесса на уровне пользователя, например, ввод-вывод, выполняемый с помощью устройства, присутствующего в системе, или любая форма связи с другими процессами требует использования системных вызовов.
Системный вызов - это механизм, который используется прикладной программой для запроса службы у операционной системы. Они используют команду машинного кода, которая заставляет процессор менять режим. Примером может быть переход из режима супервизора в защищенный режим. Здесь операционная система выполняет такие действия, как доступ к аппаратным устройствам или блоку управления памятью . Обычно операционная система предоставляет библиотеку, которая находится между операционной системой и обычными пользовательскими программами. Обычно это библиотека C, такая как Glibc или Windows API. Библиотека обрабатывает низкоуровневые детали передачи информации ядру и переключения в режим супервизора. Системные вызовы включают закрытие, открытие, чтение, ожидание и запись.
Чтобы действительно выполнять полезную работу, процесс должен иметь доступ к службам, предоставляемым ядром. Каждое ядро реализует это по-разному, но большинство из них предоставляют библиотеку C или API , который, в свою очередь, вызывает связанные функции ядра. [7]
Метод вызова функции ядра варьируется от ядра к ядру. Если используется изоляция памяти, пользовательский процесс не может напрямую вызвать ядро, потому что это было бы нарушением правил контроля доступа процессора. Вот несколько возможностей:
Важным аспектом при разработке ядра является поддержка, которую оно обеспечивает для защиты от сбоев ( отказоустойчивость ) и от злонамеренного поведения ( безопасность ). Эти два аспекта обычно четко не различаются, и принятие этого различия в структуре ядра приводит к отказу от иерархической структуры защиты . [5]
Механизмы или политики, предоставляемые ядром, можно классифицировать по нескольким критериям, включая: статические (применяются во время компиляции ) или динамические (применяются во время выполнения ); упреждающее или последующее обнаружение; в соответствии с принципами защиты, которым они удовлетворяют (например, Деннинг [8] [9] ); поддерживаются ли они аппаратным обеспечением или основаны на языке; являются ли они более открытым механизмом или обязательной политикой; и многое другое.
Поддержка доменов иерархической защиты [10] обычно реализуется с использованием режимов ЦП .
Многие ядра обеспечивают реализацию «возможностей», т. Е. Объектов, которые предоставляются пользовательскому коду, которые позволяют ограниченный доступ к базовому объекту, управляемому ядром. Типичным примером является обработка файлов: файл представляет собой представление информации, хранящейся на постоянном запоминающем устройстве. Ядро может выполнять множество различных операций, включая чтение, запись, удаление или выполнение, но приложению пользовательского уровня может быть разрешено выполнять только некоторые из этих операций (например, ему может быть разрешено только чтение файла). Обычная реализация этого заключается в том, что ядро предоставляет объект приложению (обычно так называемый «дескриптор файла»), для которого приложение может затем вызывать операции, действительность которых ядро проверяет во время запроса операции.Такая система может быть расширена для охвата всех объектов, которыми управляет ядро, и даже объектов, предоставляемых другими пользовательскими приложениями.
Эффективный и простой способ обеспечить аппаратную поддержку возможностей - делегировать блоку управления памятью (MMU) ответственность за проверку прав доступа для каждого доступа к памяти, механизм, называемый адресацией на основе возможностей . [11] В большинстве коммерческих компьютерных архитектур отсутствуют такие возможности MMU.
Альтернативный подход - моделировать возможности с использованием обычно поддерживаемых иерархических доменов. В этом подходе каждый защищенный объект должен находиться в адресном пространстве, к которому приложение не имеет доступа; ядро также поддерживает список возможностей в такой памяти. Когда приложению необходимо получить доступ к объекту, защищенному возможностью, оно выполняет системный вызов, а затем ядро проверяет, предоставляет ли возможность приложения разрешение на выполнение запрошенного действия, и, если это разрешено, выполняет доступ для него (либо напрямую, либо или путем делегирования запроса другому процессу уровня пользователя). Стоимость переключения адресного пространства ограничивает практичность этого подхода в системах со сложным взаимодействием между объектами,но он используется в текущих операционных системах для объектов, к которым нечасто обращаются или которые, как ожидается, не будут работать быстро.[12] [13]
Если встроенное ПО не поддерживает механизмы защиты, можно смоделировать защиту на более высоком уровне, например, моделируя возможности путем манипулирования таблицами страниц , но это влияет на производительность. [14] Однако отсутствие поддержки оборудования может не быть проблемой для систем, которые предпочитают использовать языковую защиту. [15]
Важным решением при проектировании ядра является выбор уровней абстракции, на которых должны быть реализованы механизмы и политики безопасности. Механизмы безопасности ядра играют критически важную роль в поддержке безопасности на более высоких уровнях. [11] [16] [17] [18] [19]
Один из подходов заключается в использовании встроенного ПО и поддержки ядра для обеспечения отказоустойчивости (см. Выше) и построения политики безопасности для злонамеренного поведения поверх этого (добавление функций, таких как механизмы криптографии , где это необходимо), делегируя некоторую ответственность компилятору . Подходы, которые делегируют выполнение политики безопасности компилятору и / или уровню приложения, часто называют безопасностью на основе языка .
Отсутствие многих критических механизмов безопасности в текущих основных операционных системах препятствует реализации адекватных политик безопасности на уровне абстракции приложений . [16] На самом деле, распространенное заблуждение в компьютерной безопасности состоит в том, что любая политика безопасности может быть реализована в приложении независимо от поддержки ядра. [16]
Типичные компьютерные системы сегодня используют аппаратные правила, определяющие, каким программам и каким данным разрешен доступ. Процессор отслеживает выполнение и останавливает программу, которая нарушает правило, например пользовательский процесс, который пытается выполнить запись в память ядра. В системах, в которых отсутствует поддержка возможностей, процессы изолированы друг от друга с помощью отдельных адресных пространств. [20] Вызовы из пользовательских процессов в ядро регулируются, требуя от них использования одного из описанных выше методов системного вызова.
Альтернативный подход - использование языковой защиты. В системе защиты на основе языка ядро разрешает выполнение только кода, созданного компилятором надежного языка . Затем язык может быть спроектирован таким образом, чтобы программист не мог дать ему указание сделать что-то, что нарушит требования безопасности. [15]
К преимуществам этого подхода можно отнести:
К недостаткам можно отнести:
Примеры систем с защитой на основе языка включают JX и Microsoft «s Singularity .
Эдсгер Дейкстра доказал, что с логической точки зрения операции атомарной блокировки и разблокировки, работающие с двоичными семафорами, являются достаточными примитивами, чтобы выразить любую функциональность взаимодействия процессов. [21] Однако, как правило, этот подход считается недостаточным с точки зрения безопасности и эффективности, тогда как подход с передачей сообщений является более гибким. [22] Также доступен ряд других подходов (нижнего или верхнего уровня), при этом многие современные ядра обеспечивают поддержку таких систем, как разделяемая память и удаленные вызовы процедур .
Идея ядра, в котором устройства ввода-вывода обрабатываются одинаково с другими процессами, как параллельные взаимодействующие процессы, была впервые предложена и реализована Бринчем Хансеном (хотя аналогичные идеи были предложены в 1967 году [23] [24] ). В описании этого Хансена «общие» процессы называются внутренними процессами , а устройства ввода-вывода - внешними процессами . [22]
Как и в случае с физической памятью, предоставление приложениям прямого доступа к портам и регистрам контроллера может вызвать сбой контроллера или сбой системы. При этом, в зависимости от сложности устройства, некоторые устройства могут оказаться на удивление сложными в программировании и использовать несколько разных контроллеров. По этой причине важно предоставить более абстрактный интерфейс для управления устройством. Этот интерфейс обычно выполняется драйвером устройства.или уровень аппаратной абстракции. Часто приложениям требуется доступ к этим устройствам. Ядро должно поддерживать список этих устройств, каким-либо образом запрашивая их у системы. Это можно сделать через BIOS или через одну из различных системных шин (например, PCI / PCIE или USB). Когда приложение запрашивает операцию на устройстве (например, отображение символа), ядру необходимо отправить этот запрос текущему активному видеодрайверу. Видеодрайвер, в свою очередь, должен выполнить этот запрос. Это пример межпроцессного взаимодействия (IPC).
Естественно, что перечисленные выше задачи и функции могут быть реализованы разными способами, которые отличаются друг от друга дизайном и реализацией.
Принцип разделения механизма и политики - существенная разница между философией микро и монолитного ядра. [25] [26] Здесь механизм - это поддержка, которая позволяет реализовать множество различных политик, в то время как политика - это особый «режим работы». Пример:
Поскольку механизм и политика разделены, политику можно легко изменить, например, требуя использования маркера безопасности .
В минимальное микроядро включены только некоторые очень простые политики [26], а его механизмы позволяют тому, что выполняется поверх ядра (оставшаяся часть операционной системы и другие приложения), решать, какие политики следует принять (например, управление памятью, планирование процессов высокого уровня, управление файловой системой и т. д.). [5] [22] Монолитное ядро вместо этого имеет тенденцию включать множество политик, поэтому ограничивает остальную часть системы, чтобы они полагались на них.
Пер Бринч Хансен представил аргументы в пользу разделения механизма и политики. [5] [22] Неспособность должным образом выполнить это разделение является одной из основных причин отсутствия существенных инноваций в существующих операционных системах [5], проблема, распространенная в компьютерной архитектуре. [27] [28] [29] Монолитный дизайн вызван архитектурным подходом к защите «режим ядра» / «пользовательский режим» (технически называемый иерархическими доменами защиты ), который является обычным в обычных коммерческих системах; [30] Фактически, каждый модуль, нуждающийся в защите, поэтому предпочтительно включен в ядро. [30]Эта связь между монолитным дизайном и «привилегированным режимом» может быть преобразована в ключевой вопрос разделения механизма и политики; [5] на самом деле архитектурный подход «привилегированного режима» объединяет механизм защиты с политиками безопасности, в то время как основной альтернативный архитектурный подход, адресация на основе возможностей , четко различает их, что естественным образом ведет к конструкции микроядра [5] ( см. Разделение защиты и безопасности ).
В то время как монолитные ядра выполняют весь свой код в одном и том же адресном пространстве (пространстве ядра ), микроядра пытаются запускать большинство своих сервисов в пользовательском пространстве, стремясь улучшить ремонтопригодность и модульность кодовой базы. [4] Большинство ядер не попадают точно в одну из этих категорий, а скорее находятся между этими двумя проектами. Это так называемые гибридные ядра . Доступны более экзотические конструкции, такие как наноядра и экзоядра , но они редко используются в производственных системах. Xen , гипервизор, например, является экзоядро.
В монолитном ядре все службы ОС работают вместе с основным потоком ядра, поэтому они также находятся в одной области памяти. Такой подход обеспечивает богатый и мощный доступ к оборудованию. Некоторые разработчики, такие как разработчик UNIX Кен Томпсон , утверждают, что «проще реализовать монолитное ядро» [31], чем микроядра. Основными недостатками монолитных ядер являются зависимости между компонентами системы (ошибка в драйвере устройства может привести к сбою всей системы) и тот факт, что большие ядра могут стать очень сложными в обслуживании.
Монолитные ядра, которые традиционно использовались Unix-подобными операционными системами, содержат все основные функции операционной системы и драйверы устройств. Это традиционный дизайн систем UNIX. Монолитное ядро - это одна программа, которая содержит весь код, необходимый для выполнения каждой связанной с ядром задачи. Каждая часть, доступная большинству программ, которая не может быть помещена в библиотеку, находится в пространстве ядра: драйверы устройств, планировщик, обработка памяти, файловые системы и сетевые стеки. Многие системные вызовы предоставляются приложениям, чтобы позволить им получить доступ ко всем этим службам. Монолитное ядро, изначально загруженное подсистемами, которые могут не понадобиться, может быть настроено так, чтобы оно было таким же быстрым, как или быстрее, чем то, которое было специально разработано для оборудования, хотя и более актуально в общем смысле.Современные монолитные ядра, такие как ядраLinux (одно из ядер операционной системы GNU ) и ядро FreeBSD , оба из которых относятся к категории Unix-подобных операционных систем, имеют возможность загружать модули во время выполнения, что позволяет легко расширять возможности ядра по мере необходимости. помогая минимизировать объем кода, выполняемого в пространстве ядра. В монолитном ядре некоторые преимущества связаны с этими моментами:
Большая часть работы в монолитном ядре выполняется с помощью системных вызовов. Это интерфейсы, обычно хранящиеся в табличной структуре, которые обращаются к некоторой подсистеме в ядре, например к дисковым операциям. По сути, вызовы выполняются внутри программ, а проверенная копия запроса передается через системный вызов. Значит, ехать совсем недалеко. Монолитное ядро Linux можно сделать чрезвычайно маленьким не только из-за его способности динамически загружать модули, но и из-за простоты настройки. Фактически, есть некоторые версии, которые достаточно малы, чтобы уместиться вместе с большим количеством утилит и других программ на одной дискете, и при этом обеспечивают полнофункциональную операционную систему (одной из самых популярных из которых является muLinux). Эта способность миниатюризировать свое ядро также привела к быстрому росту использования Linux во встроенных системах .
Эти типы ядер состоят из основных функций операционной системы и драйверов устройств с возможностью загрузки модулей во время выполнения. Они предоставляют богатые и мощные абстракции базового оборудования. Они предоставляют небольшой набор простых аппаратных абстракций и используют приложения, называемые серверами, для обеспечения большей функциональности. Этот конкретный подход определяет высокоуровневый виртуальный интерфейс через оборудование с набором системных вызовов для реализации служб операционной системы, таких как управление процессами, параллелизм и управление памятью, в нескольких модулях, которые работают в режиме супервизора. У этой конструкции есть несколько недостатков и ограничений:
Примерами монолитных ядер являются ядро AIX, ядро HP-UX и ядро Solaris.
Микроядро (также сокращенно μK или uK) - это термин, описывающий подход к проектированию операционной системы, с помощью которого функциональность системы перемещается из традиционного «ядра» в набор «серверов», которые обмениваются данными через «минимальное» ядро. , оставляя как можно меньше в «системном пространстве» и как можно больше в «пользовательском пространстве». Микроядро, разработанное для конкретной платформы или устройства, всегда будет иметь только то, что ему нужно для работы. Подход с использованием микроядра состоит из определения простой абстракции над оборудованием с набором примитивов или системных вызовов для реализации минимальных сервисов ОС, таких как управление памятью , многозадачность и межпроцессное взаимодействие.. Другие службы, включая те, которые обычно предоставляются ядром, такие как работа в сети , реализуются в программах пользовательского пространства, называемых серверами . Микроядра легче поддерживать, чем монолитные ядра, но большое количество системных вызовов и переключений контекста может замедлить работу системы, потому что они обычно создают больше накладных расходов, чем обычные вызовы функций.
В пространстве ядра находятся только те части, которые действительно требуют нахождения в привилегированном режиме: IPC (межпроцессное взаимодействие), базовый планировщик или примитивы планирования, базовая обработка памяти, базовые примитивы ввода-вывода. Многие важные части теперь работают в пользовательском пространстве: полный планировщик, обработка памяти, файловые системы и сетевые стеки. Микроядра были изобретены как реакция на традиционный «монолитный» дизайн ядра, в соответствии с которым все системные функции были помещены в одну статическую программу, работающую в специальном «системном» режиме процессора. В микроядре выполняются только самые фундаментальные задачи, такие как доступ к некоторому (не обязательно всему) оборудованию, управление памятью и координация передачи сообщений между процессами. Некоторые системы, использующие микроядра, - это QNX и HURD. В случае QNXи пользовательские сеансы Hurd могут быть полными снимками самой системы или ее представлениями. Сама суть архитектуры микроядра иллюстрирует некоторые ее преимущества:
Большинство микроядер используют систему передачи сообщений для обработки запросов от одного сервера к другому. Система передачи сообщений обычно работает на основе портов с микроядром. Например, если отправляется запрос на дополнительную память, порт открывается с микроядром, и запрос отправляется через него. Попав в микроядро, шаги аналогичны системным вызовам. Обоснованием было то, что это принесет модульность в архитектуру системы, что повлечет за собой более чистую систему, более простую отладку или динамическое изменение, настраиваемую в соответствии с потребностями пользователей и большую производительность. Они являются частью операционных систем, таких как GNU Hurd , MINIX , MkLinux , QNX и Redox OS.. Хотя микроядра сами по себе очень малы, в сочетании со всем необходимым для них вспомогательным кодом они на самом деле часто больше, чем монолитные ядра. Сторонники монолитных ядер также указывают на то, что двухуровневая структура микроядерных систем, в которой большая часть операционной системы не взаимодействует напрямую с оборудованием, создает немалые затраты с точки зрения эффективности системы. Эти типы ядер обычно предоставляют только минимальные услуги, такие как определение адресных пространств памяти, межпроцессное взаимодействие (IPC) и управление процессами. Другие функции, такие как запуск аппаратных процессов, не обрабатываются напрямую микроядрами. Сторонники микроядер отмечают, что у этих монолитных ядер есть недостаток, заключающийся в том, что ошибка в ядре может привести к сбою всей системы. Однако,с микроядром, если процесс ядра дает сбой, все еще можно предотвратить сбой системы в целом, просто перезапустив службу, вызвавшую ошибку.
Другие службы, предоставляемые ядром, такие как работа в сети, реализованы в программах пользовательского пространства, называемых серверами . Серверы позволяют изменять операционную систему простым запуском и остановкой программ. Например, для машины без поддержки сети сетевой сервер не запускается. Задача входа и выхода из ядра для перемещения данных между различными приложениями и серверами создает накладные расходы, которые пагубно сказываются на эффективности микроядер по сравнению с монолитными ядрами.
Однако у микроядра есть недостатки. Некоторые:
Недостатки микроядер сильно зависят от контекста. Например, они хорошо работают для небольших одноцелевых (и критически важных) систем, потому что, если нужно запускать не так много процессов, то сложности управления процессами эффективно смягчаются.
Микроядро позволяет реализовать оставшуюся часть операционной системы как обычную прикладную программу, написанную на языке высокого уровня , и использовать различные операционные системы поверх одного и того же неизмененного ядра. Также возможно динамически переключаться между операционными системами и иметь более одной активной одновременно. [22]
По мере роста компьютерного ядра увеличивается размер и уязвимость его доверенной вычислительной базы ; и, помимо снижения безопасности, существует проблема увеличения объема памяти . Это в некоторой степени смягчается за счет совершенствования системы виртуальной памяти , но не все компьютерные архитектуры поддерживают виртуальную память. [32] Чтобы уменьшить нагрузку на ядро, необходимо выполнить обширное редактирование для тщательного удаления ненужного кода, что может быть очень сложно из-за неочевидных взаимозависимостей между частями ядра с миллионами строк кода.
К началу 1990-х годов из-за различных недостатков монолитных ядер по сравнению с микроядрами монолитные ядра считались устаревшими практически всеми исследователями операционных систем. [ необходима цитата ] В результате дизайн Linux как монолитного ядра, а не микроядра стал темой знаменитых дебатов между Линусом Торвальдсом и Эндрю Таненбаумом . [33] Обе стороны аргументации, представленной в дебатах Таненбаума-Торвальдса, имеют свои достоинства .
Монолитные ядра предназначены для размещения всего кода в одном адресном пространстве (пространстве ядра ), что, по мнению некоторых разработчиков, необходимо для повышения производительности системы. [34] Некоторые разработчики также утверждают, что монолитные системы чрезвычайно эффективны, если они хорошо написаны. [34] Монолитная модель имеет тенденцию быть более эффективной [35] за счет использования разделяемой памяти ядра, а не более медленной системы IPC в конструкции микроядра, которая обычно основана на передаче сообщений . [ необходима цитата ]
Производительность микроядер была низкой как в 1980-х, так и в начале 1990-х годов. [36] [37] Однако исследования, в которых эмпирически измеряли производительность этих микроядер, не анализировали причины такой неэффективности. [36] Объяснение этих данных было оставлено на усмотрение «фольклора», предполагая, что они были вызваны увеличением частоты переключений из «режима ядра» в «режим пользователя», а также увеличением частоты межпроцессного взаимодействия. и к участившейся частоте переключения контекста . [36]
Фактически, как предполагалось в 1995 году, причинами низкой производительности микроядер с таким же успехом могли быть: (1) фактическая неэффективность всего микроядерного подхода , (2) конкретные концепции, реализованные в этих микроядрах, и (3) конкретная реализация этих концепций. Следовательно, оставалось изучить, будет ли решение для построения эффективного микроядра, в отличие от предыдущих попыток, применением правильных методов построения. [36]
С другой стороны, архитектура иерархических доменов защиты, которая приводит к созданию монолитного ядра [30], имеет существенный недостаток производительности каждый раз, когда происходит взаимодействие между разными уровнями защиты (т. Е. Когда процесс должен манипулировать структурой данных как в «пользовательском режиме» и «режиме супервизора»), поскольку для этого требуется копирование сообщений по значению . [38]
Гибридные ядра используются в большинстве коммерческих операционных систем, таких как Microsoft Windows NT 3.1, NT 3.5, NT 3.51, NT 4.0, 2000, XP, Vista, 7, 8, 8.1 и 10. Собственная macOS Apple Inc. использует гибридное ядро, называемое XNU который основан на коде из OSF / 1 «ы Маха ядра (OSFMK 7.3) [39] и FreeBSD » с монолитным ядром. Они похожи на микроядра, за исключением того, что они включают в себя некоторый дополнительный код в пространстве ядра для повышения производительности. Эти ядра представляют собой компромисс, который был реализован некоторыми разработчиками, чтобы учесть основные преимущества как монолитных, так и микроядер. Эти типы ядер являются расширениями микроядер с некоторыми свойствами монолитных ядер. В отличие от монолитных ядер, эти типы ядер не могут самостоятельно загружать модули во время выполнения. Гибридные ядра - это микроядра, которые имеют некоторый «несущественный» код в пространстве ядра для того, чтобы код выполнялся быстрее, чем в пользовательском пространстве. Гибридные ядра - это компромисс между монолитной и микроядерной конструкциями. Это подразумевает запуск некоторых служб (таких как сетевой стек или файловая система).) в пространстве ядра, чтобы снизить накладные расходы на производительность традиционного микроядра, но по-прежнему выполнять код ядра (например, драйверы устройств) в качестве серверов в пространстве пользователя.
Многие традиционно монолитные ядра теперь по крайней мере добавляют (или используют) возможности модуля. Самым известным из этих ядер является ядро Linux. Модульное ядро, по сути, может иметь части, встроенные в двоичный файл ядра или двоичные файлы, которые загружаются в память по запросу. Важно отметить, что модуль с испорченным кодом может дестабилизировать работающее ядро. Многие люди сбиваются с толку при обсуждении микроядер. Можно написать драйвер для микроядра в совершенно отдельном пространстве памяти и протестировать его перед "запуском". Когда модуль ядра загружен, он обращается к пространству памяти монолитной части, добавляя к нему то, что ему нужно, тем самым открывая путь к возможному загрязнению. Несколько преимуществ модульного (или) гибридного ядра:
Модули, как правило, взаимодействуют с ядром, используя какой-либо интерфейс модуля. Интерфейс является универсальным (хотя и специфичным для данной операционной системы), поэтому не всегда возможно использовать модули. Часто драйверам устройств может потребоваться большая гибкость, чем позволяет интерфейс модуля. По сути, это два системных вызова, и часто проверки безопасности, которые нужно выполнить в монолитном ядре только один раз, теперь могут выполняться дважды. Некоторые из недостатков модульного подхода:
А наноядро делегаты практически все услуги - в том числе даже самые основные из них , таких как контроллеры прерываний или таймера - для драйверов устройств , чтобы сделать требование к памяти ядра даже меньше , чем традиционные микроядра. [40]
Экзоядра - это все еще экспериментальный подход к проектированию операционных систем. Они отличаются от других типов ядер тем, что их функциональность ограничена защитой и мультиплексированием необработанного оборудования, не предоставляя никаких аппаратных абстракций, поверх которых можно было бы разрабатывать приложения. Такое разделение аппаратной защиты и управления оборудованием позволяет разработчикам приложений определять, как наиболее эффективно использовать доступное оборудование для каждой конкретной программы.
Сами по себе экзоядра чрезвычайно малы. Однако они сопровождаются библиотечными операционными системами (см. Также unikernel ), предоставляя разработчикам приложений функции обычной операционной системы. Основным преимуществом систем на основе экзоядра является то, что они могут включать в себя несколько библиотечных операционных систем, каждая из которых экспортирует свой API , например один для разработки пользовательского интерфейса высокого уровня, а другой - для управления в реальном времени .
Строго говоря, операционная система (и, следовательно, ядро) не требуется для запуска компьютера. Программы могут быть напрямую загружены и выполнены на «голом железе» при условии, что авторы этих программ готовы работать без какой-либо аппаратной абстракции или поддержки операционной системы. Большинство ранних компьютеров работали таким образом в 1950-х и начале 1960-х годов, которые перезагружались и перезагружались между выполнением различных программ. В конце концов, небольшие вспомогательные программы, такие как загрузчики программ и отладчики, оставались в памяти между запусками или загружались из ПЗУ . По мере их разработки они легли в основу того, что стало ядрами ранних операционных систем. «Голый металл»подход до сих пор используется в некоторых игровых консолей и встраиваемых систем , [41] , но в целом, новые компьютеры используют современные операционные системы и ядра.
В 1969 году мультипрограммная система RC 4000 представила философию системного проектирования небольшого ядра, «на котором можно упорядоченно строить операционные системы для различных целей» [42], что можно было бы назвать подходом микроядра.
За десятилетие, предшествовавшее Unix , мощность компьютеров возросла до такой степени, что операторы компьютеров искали новые способы заставить людей проводить свободное время на своих машинах. Одним из основных достижений этой эпохи было разделение времени , при котором ряд пользователей получали небольшие доли компьютерного времени со скоростью, с которой, казалось, каждый из них был подключен к своей собственной, более медленной машине. [43]
Развитие систем с разделением времени привело к ряду проблем. Во-первых, пользователи, особенно в университетах, где разрабатывались системы, казалось, хотели взломать систему, чтобы получить больше процессорного времени. По этой причине безопасность и контроль доступа стали основным направлением проекта Multics в 1965 году. [44] Другой постоянной проблемой было правильное управление вычислительными ресурсами: пользователи тратили большую часть своего времени, глядя на терминал и думая о том, что ввести, а не на самом деле. использование ресурсов компьютера, а система разделения времени должна предоставлять процессорное время активному пользователю в течение этих периодов. Наконец, системы обычно предлагали иерархию памяти.на несколько уровней, и разделение этого дорогостоящего ресурса привело к серьезным разработкам в системах виртуальной памяти .
Commodore Amiga был выпущен в 1985 году, и был одним из первых - и , безусловно , самых успешных - домашних компьютеров , чтобы показать продвинутую архитектуру ядра. Исполнительный компонент ядра AmigaOS, exec.library , использует схему передачи сообщений микроядра, но есть и другие компоненты ядра, такие как graphics.library , которые имеют прямой доступ к оборудованию. Защита памяти отсутствует, а ядро почти всегда работает в пользовательском режиме. В режиме ядра выполняются только специальные действия, а приложения пользовательского режима могут запрашивать у операционной системы выполнение их кода в режиме ядра.
На этапе проектирования Unix программисты решили смоделировать каждое высокоуровневое устройство в виде файла , поскольку считали, что целью вычислений является преобразование данных . [45]
Например, принтеры были представлены как «файл» в известном месте - когда данные копировались в файл, они распечатывались. Другие системы, чтобы обеспечить аналогичную функциональность, имели тенденцию к виртуализации устройств на более низком уровне, то есть и устройства, и файлы были бы экземплярами некоторой концепции более низкого уровня . Виртуализация системы на уровне файлов позволила пользователям управлять всей системой с помощью существующих утилит и концепций управления файлами , что значительно упростило работу. Как расширение той же парадигмы, Unix позволяет программистам манипулировать файлами, используя серию небольших программ, используя концепцию каналов., что позволяло пользователям выполнять операции поэтапно, передавая файл через цепочку одноцелевых инструментов. Хотя конечный результат был тем же самым, использование небольших программ таким образом резко повысило гибкость, а также простоту разработки и использования, позволяя пользователю изменять свой рабочий процесс, добавляя или удаляя программу из цепочки.
В модели Unix операционная система состоит из двух частей: во-первых, огромного набора служебных программ, которые управляют большинством операций; во-вторых, ядро, которое запускает программы. [45] В Unix, с точки зрения программирования, различие между ними довольно тонкое; ядро - это программа, работающая в режиме супервизора [46], которая действует как загрузчик программ и супервизор для небольших служебных программ, составляющих остальную часть системы, и обеспечивает службы блокировки и ввода-вывода для этих программ; кроме того, ядро вообще не вмешивалось в пользовательское пространство .
С годами модель вычислений изменилась, и подход Unix ко всему как к файлу или байтовому потоку больше не применялся повсеместно, как раньше. Хотя терминал можно было рассматривать как файл или поток байтов, который печатается или считывается из него, это не похоже на графический интерфейс пользователя . С сетью возникла еще одна проблема. Даже если сетевое взаимодействие можно сравнить с доступом к файлам, низкоуровневая пакетно-ориентированная архитектура имеет дело с отдельными порциями данных, а не с целыми файлами. По мере того как возможности компьютеров росли, Unix становилась все более загроможденной кодом. Это также связано с тем, что модульность ядра Unix широко масштабируется. [47]В то время как ядра могли иметь 100 000 строк кода в семидесятых и восьмидесятых годах, ядра, такие как Linux , современных преемников Unix, таких как GNU , содержат более 13 миллионов строк. [48]
Современные производные от Unix обычно основаны на монолитных ядрах, загружающих модули. Примерами этого являются ядро Linux во многих дистрибутивах в GNU , IBM AIX , а также распределение Berkeley Software вариант ядер , таких как FreeBSD , DragonFlyBSD , OpenBSD , NetBSD и MacOS . Помимо этих альтернатив, разработчики-любители поддерживают активное сообщество разработчиков операционных систем., заполненные самописными ядрами для хобби, которые в большинстве случаев разделяют многие функции с ядрами Linux, FreeBSD, DragonflyBSD, OpenBSD или NetBSD и / или совместимы с ними. [49]
Apple впервые выпустила свою классическую Mac OS в 1984 году в комплекте со своим персональным компьютером Macintosh . Apple перешла на дизайн наноядра в Mac OS 8.6. Напротив, современная macOS (первоначально названная Mac OS X) основана на Darwin , который использует гибридное ядро под названием XNU , которое было создано путем объединения ядра 4.3BSD и ядра Mach . [50]
Microsoft Windows была впервые выпущена в 1985 году как надстройка к MS-DOS . Из-за своей зависимости от другой операционной системы, первые выпуски Windows до Windows 95 считались операционной средой (не путать с операционной системой ). Эта линейка продуктов продолжала развиваться в течение 1980-х и 1990-х годов, когда в серию Windows 9x добавлялась 32-разрядная адресация и упреждающая многозадачность; но закончился выпуском Windows Me в 2000 году.
Microsoft также разработала Windows NT , операционную систему с очень похожим интерфейсом, но предназначенную для профессиональных и бизнес-пользователей. Эта линия началась с выпуска Windows NT 3.1 в 1993 году и была представлена обычным пользователям с выпуском Windows XP в октябре 2001 года, заменив Windows 9x на совершенно другую, гораздо более сложную операционную систему. Это линия, которая продолжается в Windows 11 .
Архитектура Windows NT ядер «s считается гибридным ядром , поскольку само ядро содержит такие задачи, как Window Manager и менеджер IPC, с клиентами / сервером слоистого подсистема модели. [51] Оно было разработано как модифицированное микроядро , поскольку ядро Windows NT находилось под влиянием микроядра Маха, но не удовлетворяет всем критериям чистого микроядра.
Программа супервизора или супервизор - это компьютерная программа , обычно являющаяся частью операционной системы , которая контролирует выполнение других процедур и регулирует планирование работы , операции ввода / вывода, действия при ошибках и аналогичные функции, а также регулирует поток работы в системе обработки данных. .
Исторически этот термин ассоциировался с линейкой операционных систем IBM для мэйнфреймов, начиная с OS / 360 . В других операционных системах супервизор обычно называется ядром.
В 1970-х годах IBM дополнительно абстрагировала состояние супервизора от оборудования, в результате чего был создан гипервизор, который обеспечил полную виртуализацию , то есть возможность запускать несколько операционных систем на одной машине совершенно независимо друг от друга. Следовательно, первая такая система получила название Virtual Machine или VM .
Хотя Mach , разработанный Ричардом Рашидом из Университета Карнеги-Меллона , является наиболее известным микроядром общего назначения, другие микроядра были разработаны с более конкретными целями. Семейство микроядер L4 (в основном, ядро L3 и L4) было создано, чтобы продемонстрировать, что микроядра не обязательно медленные. [52] Новые реализации, такие как Fiasco и Pistachio , могут запускать Linux рядом с другими процессами L4 в отдельных адресных пространствах. [53] [54]
Кроме того, компания QNX является микроядром , который в основном используется в встраиваемых системах , [55] и программное обеспечение с открытым исходным кодом MINIX , в то время как первоначально создан для образовательных целей, в настоящее время сосредоточен на быть высоконадежными и самовосстановление микроядра ОС.
. . . почти все системные вызовы [вызываются] из программ C путем вызова библиотечной процедуры. . . Библиотечная процедура. . . выполняет инструкцию TRAP для переключения из пользовательского режима в режим ядра и начала выполнения. . .
|journal=
( помощь ), включенная в книгу: Per Brinch Hansen, ed. (2001). «1» (PDF) . Классические операционные системы: от пакетной обработки до распределенных систем . Нью-Йорк: Springer-Verlag. С. 1–36. ISBN 978-0-387-95113-3.|url=
( справка )В Викиверситете есть учебные ресурсы о моделях ядра по адресу Операционные системы / модели ядра |