В этой статье будет говорится о истории некого разработчика, который делает свою ОС на своём ядре.
Проект был сделан с целью сделать как можно стабильный, безопасный и достаточно быстрый (по отклику а не по гигагерцам) компьютер. Также я хочу сделать его портативным. Но не на столько что его нужно держать в руках ведь на столе будет сложнее писать и выполнять действия.
Ядро переписывалось 2 раза перед тем как начать делать системные сервисы (серверы) дисплея и клавиатуры.
Я достаточно уже вложился в проект.
Первый месяц
Первый месяц был началом разработкой.
Тогда всё было только "на бумажке" но конечных результатов не было.
Я думал о том, как будет всё выглядеть, что будет по hardware, как будет выглядеть software.
Концепт ядра был очень простым и плохим:
Всё строилось на кортежах:
(RUN, "my_file.py") #RUN = 2 по моему
Как объяснить... Ну тогда было всё на командах: прочитать файл - команда, запустить файл - команда. И так далее.
У меня остался исходник того ядра.
Вот держите:
from cmds import *
from os import *
class Kernel:
def __init__(self):
self.tasks = []
self.task = []
self.t_ind = 0
def next_task(self):
if self.tasks:
if self.t_ind >= len(self.tasks):
self.t_ind = 0
else:
self.t_ind += 1
self.task = self.tasks[self.t_ind]
self.run_task()
def create_task(self, cmd, *args):
self.tasks.append([cmd, args])
self.t_ind += 1
self.task = [cmd, args]
self.run_task()
def run_task(self):
self.complete_cmd(self.task[0], list(self.task[1]))
def complete_cmd(self, cmd, args):
pass
Исходника на функцию complete_cmd не нашёл.
next_task была попыткой сделать кооперативную многозадачность (и это получилось!).
Хоть и было всё так плохо, но без этого ядра я бы не начал делать новое ядро.
Итог первого месяца: "Работает — не трогай"
Результат разработки можно описать одним словом — костыли. Система была максимально далека от моих целей по безопасности и стабильности.
Никакой защиты: Хочешь стереть весь диск одной командой? Пожалуйста.
Безопасность отсутствовала, а любая ошибка в коде приводила к полному зависанию всего на свете. Но, несмотря на весь этот хаос, это был фундамент. Именно на обломках первого ядра я начал понимать, как выстроить настоящую архитектуру, которая не позволит пользователю (или программе) случайно "выстрелить себе в ногу".
Без этого опыта — кривого, небезопасного и местами наивного — я бы никогда не решился на полное переписывание системы и не пришел бы к созданию по-настоящему крутого ядра.
Второй месяц - уже лучше
В этот месяц я (как обычно) переписал базовую логику ядра за два вечера но дальше - только кровь, пот и слёзы.
В ноябре я уже определился какая будет клавиатура и какой будет экран.
Клавиатура - M5Stack Card KB 1.1.
Дисплей - сначала думал E-ink но он оказался медленным и нерабочим. Перешёл на TFT LCD.
В этот месяц я выложил первый исходник ядра на гитхаб (PearKernel) и продвигалось это ядро на удивление месяц (на удивление потому что у меня по жизни 7 пятниц на неделю).
Выкладывать исходник с гитхаба не буду.
Вот SyscallManager (управляет системными вызовами):
class SyscallManager:
def __init__(self, kernel):
self.calls = {}
self.kernel = kernel
def run_call(self, scid, *args, **kwargs):
if scid in self.calls.keys():
try:
return self.calls[scid](*args, **kwargs)
except Exception as err:
logger.error(f"Error in syscall: {err}", name="SyscallManager")
def reg_call(self, scid, func):
self.calls[scid] = func
Логгер был тоже с нуля и он намного лучше чем сейчас.
Ну, это только часть кода. Я кстати могу специально выложить весь код прошлого ядра на гитхаб.
В этом ядре уже появилась изоляция но многозадачность появилась только в предпоследних версиях этого ядра.
По стабильности - не знаю, но она была.
Итог второго месяца
Появилась стабильность. Система перестала рассыпаться от каждого нажатия клавиши.
Ядро обрело имя, структуру системных вызовов и поддержку реального железа.
Это был огромный шаг вперед, но я чувствовал, что архитектура PearKernel начинает «душить» потенциал Pico W.
Предстоял последний, самый важный рывок.
Третий месяц - Pech и первый прототип
Какое то время после PearKernel я отдохнул (1-3 декабря примерно) но потом я взялся за разработку Pech. И так до 19 декабря... Только я, код, лаги, ошибки и ИИ помощник (нет, основную логику написал я).
Объяснять тут нечего. Ну вот к примеру процесс создания процесса в версии 2.0.0 БЕТА:
def create_proc(pef, server=False):
valid = validate(pef)
if valid[0:5] == 'error':
return 0
lexer = lex_pef(valid)
parser = parse(lexer)
if not type(parser) == dict:
return 0
header = parser['header']
attrs = parser['attrs']
pid = header['pid']
if pid in procs:
return 0
procs[pid] = {'attrs': parser['attrs'], 'prio': header['prio'] if not server else 255, 'name': header['name'],
'code': parser['prog'], 'state': CLOSED, 'server': server, 'pipes': {}}
Проверяет валиден ли pef, делает его парсинг и если всё хорошо то создает процесс.
Почему так рано вышла 2.0.0? Ну блин, изначально формат написания PEF должен был быть в 1.0.0 но я не терпелив был в тот день и решил выложить без PEF.
Потом я начал писать под LCD1602 в качестве для прототипа.
В качестве клавиатуры для прототипа я использовал 4*4 мембрану.
Вот фотка:

"*" - курсор.
n[содержимое] = окно.
Q = выйти.
1 и 2 в конце каждой строки - полка.
1 и 2 в начале второй строки - док.
Всё предельно ясно.
К 24 января попытаюсь успеть сделать первую версию.
1 и 2 - это счётчики. Первый до 10, а второй до 8
Итог месяца.
Я довёл этот код до конца.
Не весь но прототип готов.
Надеюсь вам понравилось...
Итоги этих месяцев
Я получил очень большой опыт.
Теперь я понимаю "как надо" и "как не надо".
Также и результаты первые стали появляется.
Пока что всё примитивно, но обещаю что это станет намного лучше.
Итог статьи
Всё получается.
Всех с наступающим.
Жду конструктивной критики и идей!
Всем удачи!