Мне действительно любопытно прямо сейчас. Я программист на Python, и этот вопрос меня просто ошеломил: вы пишете ОС. Как вы управляете этим? Он должен быть запущен как-то, и таким образом в другой ОС?
Как приложение может работать без операционной системы? Как вы скажете компьютеру запустить, скажем, C, и выполнить эти команды на экране, если на нем нет операционной системы для запуска?
Связано ли это с ядром UNIX? Если это так, что такое ядро Unix или вообще ядро?
Я уверен, что операционные системы сложнее, но как это работает?
kernel
operating-systems
Тор Коррейя
источник
источник
Ответы:
Есть много сайтов, которые проходят процесс загрузки (например, как загрузка компьютеров ). Короче говоря, это многоэтапный процесс, который постепенно наращивает систему до тех пор, пока она не сможет наконец запустить процессы ОС.
Он начинается с прошивки на материнской плате, которая пытается запустить процессор. Затем он загружает BIOS, похожий на мини-операционную систему, которая запускает и запускает другое оборудование. После этого он ищет загрузочное устройство (диск, компакт-диск и т. Д.) И, найдя его, находит MBR (главную загрузочную запись), загружает его в память и выполняет его. Это тот маленький кусочек кода, который затем знает, как инициализировать и запустить операционную систему (или другие загрузчики, поскольку все усложняется). Именно в этот момент такие вещи, как ядро, будут загружены и начнут работать.
Довольно невероятно, что это работает вообще!
источник
«Чистая металлическая» операционная система не работает внутри чего-либо. Он выполняет полный набор инструкций на физической машине и имеет доступ ко всей физической памяти, всем регистрам устройства и всем привилегированным инструкциям, включая те, которые управляют аппаратным обеспечением поддержки виртуальной памяти.
(Если операционная система работает на виртуальной машине, она может подумать, что она находится в той же ситуации, что и выше. Разница в том, что некоторые вещи эмулируются или каким-то другим образом обрабатываются гипервизором; т. Е. Уровень, на котором работают виртуальные машины. .)
В любом случае, хотя ОС может быть реализована в (например) C, у нее не будет всех обычных библиотек C, доступных для нее. В частности, у него не будет обычных библиотек 'stdio'. Скорее, он будет реализовывать (например) драйвер дискового устройства, который позволяет ему читать и записывать дисковые блоки. Он будет реализовывать файловую систему поверх слоя блочного диска, и, кроме того, он будет реализовывать системные вызовы, которые библиотеки времени выполнения пользовательского приложения делают (например) для создания, чтения и записи файлов ... и так далее.
Это должно быть приложение особого типа (например, операционная система), которое знает, как напрямую взаимодействовать с оборудованием ввода-вывода и т. Д.
Вы не
Приложение (которое было написано на языке C в качестве аргумента) компилируется и связывается на каком-то другом компьютере, чтобы получить изображение нативного кода. Затем образ записывается на жесткий диск в месте, где его может найти BIOS. BIOS загружает образ в память и выполняет инструкцию для перехода к точке входа приложения.
В приложении (как правило) нет «запускающих C и выполняющих команд», если только это не полноценная операционная система. И в этом случае ответственность за реализацию всей необходимой инфраструктуры лежит на операционной системе. Нет магии. Просто много кода.
Ответ Билла охватывает начальную загрузку, которая представляет собой процесс перехода от выключенного компьютера к компьютеру, на котором установлена и работает обычная операционная система. Тем не менее, стоит отметить, что когда BIOS выполняет свои задачи, он (как правило) передает полный контроль над оборудованием основной операционной системе и не играет никакой роли - до следующего перезапуска системы. Основная ОС, безусловно, не работает "в" BIOS в общепринятом смысле.
Да.
Ядро UNIX является ядром операционной системы UNIX. Это часть UNIX, которая выполняет все "голое железо", описанное выше.
Идея «ядра» заключается в том, что вы пытаетесь разделить системное программное обеспечение на основные компоненты (для которых требуется доступ к физическим устройствам, всю память и т. Д.) И неосновные компоненты. Ядро состоит из основного материала.
В действительности, различие между ядром / ядром и не ядром / не ядром является более сложным, чем это. И было много споров о том, что действительно принадлежит ядру, а что нет. (Посмотрите, например, микроядро.)
источник
The idea of a "kernel" is that you try to separate the system software into core stuff
Легко запомнить, отметив, что терминkernel
от немецкогоKern
, что означает ядро / ядро.В начале не было питания в процессоре.
И Человек сказал: «Да будет сила», и ЦПУ начал читать с данного адреса в памяти и выполнять инструкцию, которая там присутствовала. Потом следующий и так до конца власти.
Это была загрузка. Его задача состояла в том, чтобы загрузить другую часть программного обеспечения, чтобы получить доступ к среде, где находилось основное программное обеспечение, и загрузить его.
Наконец, дружественный экран пригласил вас войти в систему.
источник
0x7C00
для любойx86
совместимой архитектуры, и вначале он должен быть заполнен BIOS, который обычно загружает первый сектор любого загрузочного устройства, которое он предпочитает ... Хотя хороший ответ: -7Извините за опоздание, но я опишу это так:
Материнская плата получает питание.
Цепи синхронизации запускаются и стабилизируются при необходимости, основываясь исключительно на их электрических характеристиках. Некоторые новые устройства могут на самом деле использовать очень ограниченный микропроцессор или секвенсор.
- jkerian в 5:20 25 октября
Питание подается на процессор и оперативную память.
Процессор загружает (основываясь на внутренней проводке) данные из BIOS. На некоторых машинах BIOS может быть отражен в ОЗУ, а затем запущен оттуда, но это редко встречается.
-Micheal Steil, 17 ошибок Microsoft, допущенных в системе безопасности Xbox ( архив )
BIOS выполняет вызовы к аппаратным портам и адресам, используемым материнской платой для дискового и другого аппаратного ввода-вывода, и раскручивает диски, в том числе обеспечивает работу остальной оперативной памяти.
Код BIOS (посредством настроек CMOS, хранящихся в аппаратном обеспечении) использует низкоуровневые команды IDE или SATA для считывания загрузочного сектора каждого диска в порядке, указанном CMOS или пользователем, переопределенным с помощью меню.
Первый диск с загрузочным сектором выполняет загрузочный сектор. Этот загрузочный сектор является сборкой, в которой есть инструкции для загрузки большего количества данных с диска, загрузки большего
NTLDR
объемаGRUB
, последующих этапов и т. Д.Наконец, машинный код ОС исполняется загрузчиком прямо или косвенно посредством загрузки по цепочке, загружая загрузочный сектор из альтернативного или смещенного расположения.
Затем вы испытываете дружественную панику в ядре, удушающий пингвин, или ваш диск останавливается из-за падения головы. =) В альтернативном сценарии ваше ядро устанавливает таблицы процессов, структуры в памяти и монтирует диски, загружая драйверы, модули и графический интерфейс пользователя или набор служб (если они находятся на сервере). Затем программы выполняются по мере чтения их заголовков, а их сборка заносится в память и отображается соответственно.
источник
Есть много хороших ответов, но я хотел бы добавить следующее: вы упомянули, что вы пришли из Python. Python - это не интерпретируемый (или «сшитый» или любой другой, по крайней мере, в типичных случаях использования CPython) язык. Это означает, что у вас есть другое программное обеспечение (интерпретатор Python), которое просматривает исходный код и каким-то образом выполняет его. Это прекрасная модель, которая позволяет довольно хорошие языки высокого уровня, абстрагированные от реального оборудования. Недостатком является то, что вам всегда нужно это программное обеспечение переводчика в первую очередь.
Такое программное обеспечение интерпретатора, как правило, написано на языке, который компилируется в машинный код, например, C или C ++. Машинный код - это то, что процессор может обрабатывать. Что может сделать процессор - это прочитать несколько байтов из памяти и в зависимости от значений байтов запустить определенную операцию. Таким образом, одна байтовая последовательность - это команда для загрузки некоторых данных из памяти в регистр, другая последовательность для добавления двух значений, другая для сохранения значения из регистра обратно в основную память и в ближайшее время (регистр - это специальная область памяти, которая является частью процессора, где он может работать лучше всего), большинство этих команд довольно низко на этом уровне. Человек, который может читать эти инструкции машинного кода, является кодом ассемблера. Этот машинный код, по сути, является тем, что хранится в файлах .exe или.com в Windows или в бинарных файлах Linux / Unix.
Теперь, если компьютер запущен, он тупой, хотя у него есть проводка, которая будет читать такие инструкции машинного кода. На ПК это обычно (в настоящее время) микросхема EEPROM на материнской плате, содержащая BIOS (базовая выходная система ввода-вывода), эта система мало что может сделать, она может облегчить доступ к некоторому оборудованию и т. Д., А затем выполнить ключевую операцию: перейти к загрузите и скопируйте первые несколько байтов (также как основная загрузочная запись, MBR) в память, а затем скажите ЦПУ «здесь, ваша программа», тогда ЦП обработает эти байты как машинный код и выполнит его. Как правило, это какой-то загрузчик операционной системы, который загружает ядро с некоторыми параметрами, а затем передает управление этому ядру, которое затем загружает все его драйверы для доступа ко всему аппаратному обеспечению, загружает некоторую программу для настольного компьютера или оболочки или что-то еще и позволяет пользователю войти в систему и использовать систему.
источник
Вы спрашиваете: «Как приложение может работать без операционной системы?». Простой ответ: «ОС - это не приложение». Хотя ОС может быть создана с помощью тех же инструментов, что и приложение, и изготовлена из одного и того же сырья, это не одно и то же. ОС не должна играть по тем же правилам, что и приложение.
OTOH, вы можете думать о реальном оборудовании и прошивке как о «ОС», в которой работает «приложение» ОС. Аппаратное обеспечение - очень простая ОС - оно знает, как выполнять инструкции, написанные в машинном коде, и знает, что при запуске оно должно посмотреть на очень специфический адрес памяти для своей первой инструкции. Итак, он запускается, а затем сразу же запускает ту самую первую инструкцию, затем вторую и так далее.
Итак, ОС - это просто машинный код, который существует в известном месте и может напрямую взаимодействовать с оборудованием.
источник
Ответ на ваш вопрос требует знания того, как выглядит нативный (для процессора) код и как он интерпретируется процессором.
Обычно весь процесс компиляции основан на переводе того, что вы пишете на C, Pascal или даже Python (используя pypy) и C #, в то, что понимает процессор, т.е. простые инструкции, такие как «сохранить что-то под [адресом памяти]», «добавить числа, хранящиеся в регистрах eax». и ebx "," вызвать функцию foo "," сравнить eax с 10 ". Эти инструкции, выполняемые одна за другой, делают то, что вы хотели сделать со своим кодом.
Теперь подумайте: вам не нужна ОС для выполнения этого нативного кода! Все, что вам нужно, это загрузить этот код в память и сообщить процессору, что он есть, и вы хотите, чтобы он был выполнен. Не беспокойтесь об этом, хотя. Это то, о чем должен беспокоиться BIOS - он загружает ваш код (только один и один сектор) сразу после запуска процессора под физическим адресом 0x7C00. Затем CPU начинает выполнять этот один сектор (512 B) вашего кода. И вы можете делать все, что вы себе представляете! Без, конечно, никакой поддержки со стороны ОС. Это потому, что вы операционная система. Круто, да? Нет стандартной библиотеки, нет наддува, нет python, нет программ, нет драйверов! Вы должны написать все самостоятельно.
А как вы общаетесь с железом? Ну, у вас есть два варианта:
Теперь вы спрашиваете, что такое ядро. Короче говоря, ядро - это все, что вы не видите и не испытываете напрямую. Он управляет, вместе с драйверами, всем, начиная с клавиатуры и заканчивая практически всем оборудованием внутри вашего ПК. Вы общаетесь с ним с помощью графической оболочки или терминала. Или с помощью функций внутри вашего кода, которые теперь выполняются, к счастью, с поддержкой ОС.
Для лучшего понимания я могу дать вам один совет: попробуйте написать свою собственную ОС. Даже если на экране будет написано «Привет, мир».
источник
Существуют некоторые различия в работе операционной системы, которые сильно зависят от системы. Чтобы быть полезным, система должна иметь некоторое предсказуемое поведение при запуске, например, «начать выполнение по адресу X». Для систем, в которых энергонезависимое хранилище (например, флэш-память) отображается в пространстве их программ, это довольно просто, поскольку вы просто должны поместить код запуска в нужное место в пространстве программы процессора. Это чрезвычайно распространено для микроконтроллеров. Некоторые системы должны получить свои программы запуска из какого-либо другого места перед его выполнением. Эти системы будут иметь некоторые операции, встроенные (или почти встроенные) в них. Есть некоторые процессоры, которые получают свой код запуска через i2c из другого чипа,
Системы, использующие семейство процессоров x86, обычно используют многоступенчатый процесс загрузки, который является довольно сложным из-за его эволюции и проблем обратной совместимости. Система выполняет некоторые микропрограммы (называемые BIOS - Basic Input / Output System или аналогичные), которые находятся в некоторой энергонезависимой памяти на материнской плате. Иногда некоторые или все эти прошивки копируются (перемещаются) в ОЗУ для ускорения их выполнения. Этот код был написан со знанием того, какое оборудование будет доступно и пригодно для загрузки.
Начальная прошивка обычно написана с предположениями о том, какое оборудование будет присутствовать в системе. Несколько лет назад на машине 286, вероятно, существовало предположение, что контроллер адресации гибких дисков будет иметь адрес ввода-вывода X и будет загружать сектор 0 в определенную область памяти, если ему дан определенный набор команд (и код в секторе 0). знает, как использовать собственные функции BIOS для загрузки большего количества кода, и в конечном итоге загружается достаточно кода, чтобы быть ОС). На микроконтроллере может быть предположение, что есть последовательный порт, работающий с определенными настройками, что он должен ждать команды (для обновления более сложной прошивки) в течение X времени, прежде чем продолжить процесс загрузки.
Точный процесс запуска данной системы не так важен для вас, как знание того, что она отличается в разных системах, но также и то, что у них всех есть общие черты. Часто в коде запуска (начальной загрузки), когда требуется выполнить ввод-вывод, устройства ввода-вывода опрашиваются, а не полагаются на прерывания. Это связано с тем, что прерывания являются сложными, используют стековое ОЗУ (которое, возможно, еще не полностью настроено), и вам не нужно беспокоиться о блокировке других операций, когда вы являетесь единственной операцией.
При первой загрузке ядро ОС (ядро является основной частью большинства ОС) изначально будет работать как встроенное ПО. Он должен быть запрограммирован со знанием или обнаружением присутствующего оборудования, настроить некоторое ОЗУ в качестве стекового пространства, выполнить различные тесты, настроить различные структуры данных, возможно обнаружить и смонтировать файловую систему, а затем, вероятно, запустить некую программу, которая более как программы, к которым вы привыкли (программа, которая зависит от наличия ОС).
Код ОС обычно пишется в смеси С и сборки. Самый первый код для ядра ОС, вероятно, всегда находится в сборке и выполняет такие вещи, как настройка стека, на который опирается код C, а затем вызывает функцию C. Также там будет другая рукописная сборка, потому что некоторые операции, которые должна выполнять ОС, часто не выражаются в C (например, стеки переключения / замены контекста). Часто специальные флаги должны передаваться компилятору C, чтобы он не полагался на стандартные библиотеки, используемые большинством программ на C, и не ожидал, что
int main(int argc, char *argv[])
в программе. Кроме того, необходимо использовать специальные опции компоновщика, которые большинство разработчиков приложений никогда не используют. Это может привести к тому, что программа ядра будет ожидать загрузки по определенному адресу или настроить так, чтобы в определенных местах были внешние переменные, даже если эти переменные никогда не объявлялись в каком-либо коде C (это полезно для операций ввода-вывода с отображением в памяти или другие специальные ячейки памяти).Поначалу вся операция кажется волшебством, но после того, как вы изучите ее и поймете ее части, магия станет просто набором программ, для реализации которых потребуется гораздо больше планирования и системных знаний. Отладка их, однако, требует магии.
источник
Чтобы понять, как работают операционные системы, может быть полезно разделить их на две категории: те, которые просто предоставляют сервисы приложениям по запросу, и те, которые используют аппаратные функции в ЦП, чтобы приложения не делали то, что им не следует делать. MS-DOS был в прежнем стиле; все версии Windows начиная с 3.0 были последним стилем (по крайней мере, при запуске чего-то более мощного, чем 8086).
Оригинальный IBM PC под управлением PC-DOS или MS-DOS был бы примером прежнего стиля «ОС». Если бы приложение хотело отобразить символ на экране, было бы несколько способов сделать это. Он может вызвать подпрограмму, которая попросит MS-DOS отправить ее на «стандартный вывод». В этом случае MS-DOS проверит, перенаправлен ли вывод, и, если нет, вызовет подпрограмму, хранящуюся в ПЗУ (в коллекции подпрограмм IBM, называемой Базовая система ввода / вывода), которая будет отображать символ на Положение курсора и переместить курсор («написать телетайп»). Эта подпрограмма BIOS будет хранить пару байтов где-нибудь в диапазоне от 0xB800: 0 до 0xB800: 3999; аппаратное обеспечение на цветном графическом адаптере будет повторно выбирать пары байтов в этом диапазоне, используя первый байт каждой пары для выбора формы символа, а второй - для выбора цвета переднего плана и фона. Байты извлекаются и обрабатываются в красный, зеленый и синий сигналы в последовательности, которая приводит к четкому отображению текста.
Программы на IBM PC могут отображать текст с помощью подпрограммы «стандартный вывод» DOS, либо с помощью подпрограммы BIOS «записать телетайп», либо путем непосредственного сохранения его для отображения в памяти. Многие программы, которым нужно было отображать много текста, быстро выбрали последний подход, поскольку он может быть буквально в сотни раз быстрее, чем использование подпрограмм DOS. Это было не потому, что процедуры DOS и BIOS были исключительно неэффективными; если дисплей не был закрыт, его можно было записать только в определенное время. Процедура BIOS для вывода символа была разработана таким образом, чтобы ее можно было вызывать в любое время; таким образом, каждый запрос должен начинаться заново, ожидая подходящего времени для выполнения операции записи. Напротив, код приложения, который знал, что ему нужно сделать, мог организовать себя вокруг имеющихся возможностей для написания дисплея.
Ключевым моментом здесь является то, что хотя DOS и BIOS предоставляли средства для вывода текста на дисплей, в таких способностях не было ничего особенно «волшебного». Приложение, которое хотело записать текст на дисплей, могло бы делать это так же эффективно, по крайней мере, если бы аппаратное обеспечение дисплея работало так, как ожидало приложение (если кто-то установил монохромный адаптер дисплея, который был похож на CGA, но имел свою символьную память расположенный по адресу 0xB000: 0000-0xB000: 3999), BIOS будет автоматически выводить символы там; приложение, которое было запрограммировано для работы либо с MDA, либо с CGA, могло бы делать то же самое, но приложение, которое было запрограммировано только для CGA, было бы абсолютно бесполезным для MDA).
На более новых системах все немного по-другому. Процессоры имеют различные режимы «привилегий». Они запускаются в наиболее привилегированном режиме, где код может делать все, что захочет. Затем они могут переключиться в ограниченный режим, где доступны только выбранные диапазоны памяти или средств ввода / вывода. Код не может напрямую переключаться из ограниченного режима обратно в привилегированный режим, но процессор определил точки входа в привилегированном режиме, и код ограниченного режима может попросить процессор запустить код на одной из этих точек входа в привилегированном режиме. Кроме того, существуют точки входа в привилегированном режиме, связанные с рядом операций, которые будут запрещены в ограниченном режиме. Предположим, например, что кто-то хотел запустить несколько приложений MS-DOS одновременно, каждое из которых имеет собственный экран. Если бы приложения могли писать напрямую в контроллер дисплея со скоростью 0xB800: 0, не было бы никакого способа предотвратить перезапись одного приложения на экране другого приложения. С другой стороны, ОС может запускать приложение в ограниченном режиме и перехватывать любые обращения к памяти дисплея; если он обнаружил, что приложение, которое должно было находиться в «фоновом режиме», пыталось записать 0xB800: 160, он мог бы сохранить данные в некоторой памяти, которую он выделил как экранный буфер фонового приложения. Если позднее это приложение переключится на передний план, буфер можно будет скопировать на реальный экран. ОС может запускать приложение в ограниченном режиме и перехватывать любые обращения к памяти дисплея; если он обнаружил, что приложение, которое должно было находиться в «фоновом режиме», пыталось записать 0xB800: 160, он мог бы сохранить данные в некоторой памяти, которую он выделил как экранный буфер фонового приложения. Если позднее это приложение переключится на передний план, буфер можно будет скопировать на реальный экран. ОС может запускать приложение в ограниченном режиме и перехватывать любые обращения к памяти дисплея; если он обнаружил, что приложение, которое должно было находиться в «фоновом режиме», пыталось записать 0xB800: 160, он мог бы сохранить данные в некоторой памяти, которую он выделил как экранный буфер фонового приложения. Если позднее это приложение переключится на передний план, буфер можно будет скопировать на реальный экран.
Ключевыми моментами, на которые следует обратить внимание, являются: (1) хотя часто бывает удобно иметь стандартный набор подпрограмм для выполнения различных стандартных сервисов, таких как отображение текста, они не делают ничего, чего не могло бы сделать приложение, работающее в «привилегированном режиме» правильно ли он запрограммирован для работы с установленным оборудованием; (2) хотя большинство приложений, работающих сегодня, будут лишены своей операционной системой непосредственного выполнения таких операций ввода-вывода, программа, которая запускается в привилегированном режиме, выполняет все, что хочет, и может устанавливать любые правила, которые она хочет для ограниченного режима. программы.
источник
Как сказал Стивен С., речь идет не только о запуске операционной системы, но и о том, как она работает, взаимодействует с аппаратным обеспечением и с программным обеспечением поверх него.
Я просто добавлю к его ответу, что вы можете взглянуть на «Элементы вычислительных систем» . Это книга и некоторые инструменты, которые объясняют, как взаимодействуют компьютер, операционная система и компиляторы. Уникальность в том, что он дает вам инструменты для очень быстрой разработки вашей собственной операционной системы в имитируемой среде, игнорируя многие детали, необходимые для реальной, чтобы вы могли понять концепции . Это делает большую работу, позволяя вам увидеть лес вместо деревьев.
Если вы хотите узнать больше о том, как операционная система взаимодействует с оборудованием, ознакомьтесь с Minix .
источник
Ваше приложение работает в операционной системе. Эта операционная система предоставляет сервисы для вашего приложения, такие как открытие файла и запись в него байтов. Эти услуги обычно предоставляются через системные вызовы.
Операционная система работает на аппаратном уровне. Аппаратное обеспечение обеспечивает обслуживание операционной системы, например, установку скорости передачи последовательного порта и запись в нее байтов. Эти услуги обычно предоставляются через регистры с отображением памяти или порты ввода / вывода.
Чтобы дать очень упрощенный пример того, как это работает:
Ваше приложение сообщает операционной системе что-то записать в файл. Для вашего приложения операционная система предоставляет такие понятия, как файлы и каталоги.
На оборудовании эти понятия не существуют. Аппаратное обеспечение обеспечивает такие понятия, как диски, разделенные на фиксированные блоки по 512 байт. Операционная система решает, какие блоки использовать для вашего файла, а некоторые другие блоки для метаданных, такие как имя файла, размер и расположение на диске. Затем он сообщает оборудованию: запишите эти 512 байтов в сектор с этим номером на диске с этим номером; запишите остальные 512 байтов в сектор с этим другим номером на диске с таким же номером; и так далее.
Способ, которым операционная система говорит аппаратному обеспечению, сильно варьируется. Одной из функций операционной системы является защита приложений от этих различий. Для примера с диском на одном виде оборудования операционная система должна записать номер диска и сектора в порт ввода-вывода, а затем записать байты один за другим в отдельный порт ввода-вывода. На другом типе оборудования операционная система должна будет скопировать все 512 байт сектора в область памяти, записать расположение этой области памяти в специальную область памяти и записать номер диска и сектора в еще один специальная ячейка памяти.
Современное высококлассное оборудование чрезвычайно сложно. Руководства, дающие все их детали программирования, представляют собой дверные проемы с тысячами страниц; например, последнее руководство по процессору Intel состоит из семи томов, общим объемом более 4000 страниц, и это только для процессора. Большинство других компонентов предоставляют блоки памяти или порты ввода-вывода, которые операционная система может указать ЦП на сопоставление с адресами в пределах своего адресного пространства. Некоторые из этих компонентов представляют еще больше вещей за несколькими портами ввода-вывода или адресами памяти; Например, RTC (часы реального времени, компонент, который сохраняет время компьютера, пока он выключен) предоставляет несколько сотен байтов памяти за парой портов ввода / вывода, и это очень простой компонент, восходящий к оригинальный ПК / АТ. Такие вещи, как жесткие диски имеют отдельные процессоры, с которой операционная система общается с помощью стандартизированных команд. Графические процессоры еще сложнее.
Несколько человек в комментариях выше предложили Arduino. Я согласен с ними, это гораздо проще понять - ATmega328, который делает все на Arduino Uno, за исключением представления USB-разъема в качестве последовательного порта, имеет руководство, содержащее всего несколько сотен страниц. На Arduino вы работаете непосредственно на оборудовании, между которыми нет операционной системы; всего несколько небольших библиотечных подпрограмм, которые вы не должны использовать, если не хотите.
источник
Runnable примеры
Технически, программа, которая работает без ОС, является ОС. Итак, давайте посмотрим, как создать и запустить несколько крошечных операционных систем hello world.
Код всех примеров ниже представлен на этом репозитории GitHub .
Загрузочный сектор
На x86 самое простое и низкоуровневое средство , которое вы можете сделать, - это создать главный загрузочный сектор (MBR) , который является типом загрузочного сектора , и затем установить его на диск.
Здесь мы создаем один с одним
printf
вызовом:Результат:
Проверено на Ubuntu 18.04, QEMU 2.11.1.
main.img
содержит следующее:\364
в восьмеричном ==0xf4
в шестнадцатеричном виде: кодировка дляhlt
инструкции, которая сообщает ЦП прекратить работу.Поэтому наша программа не будет ничего делать: только запускать и останавливать.
Мы используем восьмеричное, потому что
\x
шестнадцатеричные числа не указаны в POSIX.Мы могли бы легко получить эту кодировку с помощью:
но
0xf4
кодировка также задокументирована в руководстве Intel, конечно.%509s
произвести 509 мест. Необходимо заполнить файл до байта 510.\125\252
в восьмеричном == с0x55
последующим0xaa
: магические байты, необходимые для оборудования. Это должны быть байты 511 и 512.Если нет, оборудование не будет воспринимать это как загрузочный диск.
Обратите внимание, что даже не делая ничего, несколько символов уже напечатаны на экране. Они печатаются прошивкой и служат для идентификации системы.
Работать на реальном оборудовании
Эмуляторы забавны, но аппаратная часть - реальная сделка.
Обратите внимание, что это опасно, и вы можете по ошибке стереть диск: делайте это только на старых машинах, которые не содержат критически важных данных! Или, что еще лучше, такие доски, как Raspberry Pi, см. Пример ARM ниже.
Для типичного ноутбука вы должны сделать что-то вроде:
Запишите образ на USB-накопитель (уничтожит ваши данные!):
подключите USB к компьютеру
включи
скажи ему загрузиться с USB.
Это означает, что прошивка выбирает USB перед жестким диском.
Если это не стандартное поведение вашей машины, продолжайте нажимать Enter, F12, ESC или другие подобные странные клавиши после включения питания, пока не появится меню загрузки, где вы можете выбрать загрузку с USB.
Часто можно настроить порядок поиска в этих меню.
Например, на моем старом Lenovo Thinkpad T430, UEFI BIOS 1.16, я вижу:
Привет, мир
Теперь, когда мы создали минимальную программу, давайте перейдем к привету.
Очевидный вопрос: как сделать IO? Несколько вариантов:
последовательный порт . Это очень простой стандартизированный протокол, который отправляет и получает символы с хост-терминала.
Источник .
К сожалению, он не представлен на большинстве современных ноутбуков, но является наиболее распространенным способом разработки плат разработки, см. Примеры ARM ниже.
Это действительно позор, так как такие интерфейсы действительно полезны для отладки ядра Linux, например .
использовать функции отладки чипов. ARM называет их полухостингом, например. На реальном оборудовании это требует дополнительной аппаратной и программной поддержки, но на эмуляторах это может быть бесплатный удобный вариант. Пример .
Здесь мы сделаем пример BIOS, поскольку он проще на x86. Но учтите, что это не самый надежный метод.
main.S
link.ld
Собрать и связать с:
Результат:
Проверено на: Lenovo Thinkpad T430, UEFI BIOS 1.16. Диск создан на хосте Ubuntu 18.04.
Помимо стандартных инструкций по сборке пользовательского пространства, у нас есть:
.code16
: говорит ГАЗ выводить 16-битный кодcli
: отключить программные прерывания. Это может заставить процессор начать работать снова послеhlt
int $0x10
: вызывает ли BIOS. Это то, что печатает символы один за другим.Важные флаги ссылок:
--oformat binary
: выводить сырой двоичный код сборки, не деформируйте его внутри ELF-файла, как в случае с обычными исполняемыми файлами пользовательского пространства.Используйте C вместо сборки
Поскольку C компилируется в сборку, использование C без стандартной библиотеки довольно просто, вам просто нужно:
main
, в частности:TODO: ссылка на пример с x86 на GitHub. Вот ARM, который я создал .
Однако, если вы захотите использовать стандартную библиотеку, все станет интереснее, поскольку у нас нет ядра Linux, которое реализует большую часть функциональности стандартной библиотеки C через POSIX .
Несколько возможностей, без перехода на полноценную ОС, такую как Linux, включают:
Newlib
Подробный пример по адресу: https://electronics.stackexchange.com/questions/223929/c-standard-libraries-on-bare-metal/223931
В Newlib вы должны сами реализовывать системные вызовы, но вы получаете очень минимальную систему, и их очень легко реализовать.
Например, вы можете перенаправить
printf
на системы UART или ARM или внедритьexit()
с помощью полухостинга .встроенные операционные системы, такие как FreeRTOS и Zephyr .
Такие операционные системы обычно позволяют отключить упреждающее планирование, что дает вам полный контроль над временем выполнения программы.
Их можно рассматривать как своего рода предварительно реализованный Newlib.
РУКА
В ARM общие идеи совпадают. Я загрузил:
несколько простых примеров из QEMU на GitHub . Prompt.c пример принимает входной сигнал от вашего терминала хоста и возвращает вывод всех через моделируемой UART:
Смотрите также: https://stackoverflow.com/questions/38914019/how-to-make-bare-metal-arm-programs-and-run-them-on-qemu/50981397#50981397
полностью автоматизированная установка блинкера Raspberry Pi по адресу: https://github.com/cirosantilli/raspberry-pi-bare-metal-blinker
Смотрите также: https://stackoverflow.com/questions/29837892/how-to-run-ac-program-with-no-os-on-the-raspberry-pi/40063032#40063032
Для Raspberry Pi https://github.com/dwelch67/raspberrypi выглядит как самый популярный учебник, доступный сегодня.
Некоторые отличия от x86:
IO делается путем написания магических адресов напрямую, там нет
in
иout
инструкций.Это называется IO с отображением памяти .
для некоторого реального оборудования, такого как Raspberry Pi, вы можете самостоятельно добавить прошивку (BIOS) в образ диска.
Это хорошо, поскольку делает обновление прошивки более прозрачным.
Прошивка
По правде говоря, ваш загрузочный сектор не является первым программным обеспечением, которое работает на процессоре системы.
На самом деле сначала запускается так называемая прошивка , то есть программное обеспечение:
Хорошо известные прошивки включают в себя:
Прошивка делает такие вещи, как:
Зацикливайтесь на каждом жестком диске, USB, сети и т. д., пока не найдете что-нибудь загрузочное.
Когда мы запускаем QEMU,
-hda
говорит, чтоmain.img
это жесткий диск, подключенный к оборудованию, иhda
является первым, который будет испытан, и он используется.загрузите первые 512 байт в адрес памяти RAM
0x7c00
, поместите туда RIP процессора и дайте ему поработатьпоказывать на дисплее такие вещи, как меню загрузки или вызовы печати BIOS
Прошивка предлагает функциональность, подобную ОС, от которой зависит большинство ОС. Например, подмножество Python было портировано для работы в BIOS / UEFI: https://www.youtube.com/watch?v=bYQ_lq5dcvM
Можно утверждать, что прошивки неотличимы от ОС, и что прошивка - это единственное «истинное» программирование на «голое железо», какое только можно сделать.
Как говорит этот разработчик CoreOS :
Начальное состояние после BIOS
Как и многие вещи в оборудовании, стандартизация слаба, и одна из вещей, на которые вы не должны полагаться, это начальное состояние регистров, когда ваш код начинает работать после BIOS.
Поэтому сделайте себе одолжение и используйте некоторый код инициализации, например, следующий: https://stackoverflow.com/a/32509555/895245
Регистры любят
%ds
и%es
имеют важные побочные эффекты, поэтому вы должны обнулять их, даже если вы не используете их явно.Обратите внимание, что некоторые эмуляторы лучше, чем реальное оборудование, и дают вам хорошее начальное состояние. Затем, когда вы работаете на реальном оборудовании, все ломается.
GNU GRUB Multiboot
Загрузочные сектора просты, но не очень удобны:
Именно по этим причинам GNU GRUB создал более удобный формат файлов, называемый multiboot.
Минимальный рабочий пример: https://github.com/cirosantilli/x86-bare-metal-examples/tree/d217b180be4220a0b4a453f31275d38e697a99e0/multiboot/hello-world
Я также использую его в репозитории GitHub examples, чтобы иметь возможность легко запускать все примеры на реальном оборудовании, не перегружая USB миллион раз. На QEMU это выглядит так:
Если вы подготовите свою ОС как мультизагрузочный файл, GRUB сможет найти его в обычной файловой системе.
Это то, что делает большинство дистрибутивов, помещая образы ОС под
/boot
.Мультизагрузочные файлы - это в основном файл ELF со специальным заголовком. Они указаны GRUB по адресу: https://www.gnu.org/software/grub/manual/multiboot/multiboot.html.
Вы можете превратить мультизагрузочный файл в загрузочный диск с помощью
grub-mkrescue
.Эль Торито
Формат, который можно записать на компакт-диски: https://en.wikipedia.org/wiki/El_Torito_%28CD-ROM_standard%29
Также возможно создать гибридное изображение, которое работает на ISO или USB. Это может быть сделано с
grub-mkrescue
( например ), а также выполняется ядром Linux наmake isoimage
использованиеisohybrid
.Ресурсы
источник