В данной статье описывается процесс создания операционной системы, способной запускать пользовательские приложения. Основным моментом является реализация механизма переключения в пользовательский режим и выполнения кода приложений в изолированном пространстве памяти. Для этого создается скрипт компоновщика, определяющий размещение приложения в памяти, и формируется минимальная библиотека для пользовательских программ.
Для запуска приложения в ядре ОС используется механизм загрузки двоичного файла приложения в оперативную память. При этом, двоичный образ приложения встраивается в ядро, а затем постранично копируется в выделенную для него область памяти. Для переключения в пользовательский режим процессор переходит в U-Mode при помощи инструкции
Также в статье описывается реализация механизма системных вызовов, который позволяет приложениям обращаться к функциям ядра. Первый системный вызов —
В завершение, вводится системный вызов
Изображение носит иллюстративный характер
Для запуска приложения в ядре ОС используется механизм загрузки двоичного файла приложения в оперативную память. При этом, двоичный образ приложения встраивается в ядро, а затем постранично копируется в выделенную для него область памяти. Для переключения в пользовательский режим процессор переходит в U-Mode при помощи инструкции
sret
. Кроме того, устанавливается бит SPIE, чтобы активировать аппаратные прерывания. Также в статье описывается реализация механизма системных вызовов, который позволяет приложениям обращаться к функциям ядра. Первый системный вызов —
putchar
, который выводит символ на экран. Это позволяет использовать функцию printf
из пользовательской программы. Далее реализуется системный вызов getchar
для считывания ввода с клавиатуры, позволяющий создать простую оболочку с поддержкой команд. В завершение, вводится системный вызов
exit
для корректного завершения процесса. Это позволяет завершить выполнение пользовательской программы, переведя ее в состояние PROC_EXITED. Использование yield
освобождает процессор для других процессов. Реализация системных вызовов позволяет пользовательским приложениям взаимодействовать с ядром операционной системы.