Показаны сообщения с ярлыком memory. Показать все сообщения
Показаны сообщения с ярлыком memory. Показать все сообщения

четверг, 20 марта 2008 г.

Что-то с памятью моей стало...

Не люблю ограничения, ни в чем, особенно если эти ограничения ничем не оправданны. От оправданных ограничений никуда не денешься, и ничего с ними не поделаешь.

Мое ядро загружается с помощью GrUB, который не умеет загружать ядро или модули ниже мегабайта. И это накладывает на меня ограничение - одного мегабайта памяти просто не хватит GrUB'у. Но двух мегабайт должно хватать и мне и ему.

Но неладно что-то в датском королевстве...

Попытавшись поставить 2 мегабайта для bochs я услышал от GRUB следущее:

GNU GRUB version 0.96 (639K lower / 4193279K upper memory)

Хех, очень забавно... То же самое я увидел запустив qemu... И что самое интересное, что то же самое GRUB докладывает моему ядру.

Попробуем поднять планку до 4 мег.

GNU GRUB version 0.96 (639K lower / 1984K upper memory)

bochs и qemu вновь единодушны, но где еще один мегабайт??? Ведь по логике вещей должно быть 3М upper...

8M: GNU GRUB version 0.96 (639K lower / 6080K upper memory)
16M: GNU GRUB version 0.96 (639K lower / 14272K upper memory)

Нет, надо с этим что-то делать...

PS: Одно место обнаружилось в bochs bios, он от размера памяти отнимает ACPI_DATA_SIZE, но это не может послужить причиной пропажи целого мегабайта, ACPI_DATA_SIZE имеет значение 64к.

PPS: Эх, чуть чуть недотестировал...

17M: GNU GRUB version 0.96 (639K lower / 16320K upper memory)!

Ошибка скрывалась в Биосе bochs в функции 0xe820, int 0x15. Если памяти больше 16 мегабайт, то анализируется количество 64-х килобайтных блоков после 16 мегабайт, 16 мегабайт прибавляем. А если памяти ровно или меньше 16 мегабайт, то анализируется количество килобайтных блоков после мегабайта... А вот мегабайт прибавить забыли.

QEMU использует биос из комплекта bochs, поэтому проблема присутствует и там.

вторник, 11 марта 2008 г.

Есть ли жизнь без MMU...

Последнее время, с тех пор как занялся с LPC2468, много думаю на эту тему.

Сперва я думал об этом, как о чем-то весьма далеком от меня, полностью пропитанного идеями x86. Но в какой-то момент я подумал, что если не использовать страничное преобразование, то и x86 становится вполне себе MMUless архитектурой. Остается только придумать как в этой ситуации сможет работать система...

Ну для начала сразу же становится ясно, что безопасности в данной архитектуре нету. Всмысле приложения защищены друг от друга только честным словом, запрещающим им соваться в недозволенную память. Причем, в разяд недозволенной памяти входит и память ядра. Любое некорректное или злоумышленное приложение способно не просто нарушить работоспособность приложений, но и навредить системе в целом.

Код приложений должен быть безопасен. Безопасности можно достичь использованием типобезопасного языка. Cразу вспоминаются системы с единой памятью, типа Bluebottle, Singularity... Которые собственно и создаются без учета MMU как такового. При демократии (использовании любых языков) с безопасностью дела обстоят гораздо сложнее. Всмысле никто не может гарантировать безопасность данных приложений.

Кроме того, без MMU немаловажным является и объем памяти. Своппинг исключается, и это тоже ограничивает возможности системы. Для серьезной системы даже 4 гигабайта линейной памяти не кажутся слишком большим объемом. EM64T спасет серьезные системы, если они без MMU всетаки возникнут.

Надо сказать что я не большой любитель систем с единым адресным пространством, имею ввиду Bluebottle и аналоги. Не смотря на горячие заверения приверженцем эти системы пока не нашли свое место в жизни и не доказали свою безопасность. Поэтому далее речь пойдет только о традиционных демократических системах. :)

Предположим что в безопасность приложений мы верим так же, как и в безопасность ядра (Гы лол). Но тем не менее остается еще несколько моментов, существенно отличающих MMU системы от систем без оного.

Во первых это привязка приложения к положению в памяти. Конечно, при ограниченном количестве приложения их положение в памяти можно согласовать, но это слишком не гибко и не позволит приложениям использовать больше чем предначертано, не смотря на то, что остальная память может быть просто свободна. Самым правильным подходом будет перемещаемость приложений. Здесь тоже два варианта поведения. Либо PIC, либо перемещаемый формат. первый расходует больше памяти, второй больше времени. Если платформа маломощная - и то и другое может быть существенно. Но чтобы не изобретать велосипед, я думаю логичным было бы взять тот же ELF, и в перемещаемом формате загружать (и не изобретать BFLT).

Динамическое распределение памяти могло бы осуществляться ядром, на общих основаниях. Как бы, большой-пребольшой хип, размером со всю доступную память. Последней проблемой остается стек. Потребности приложений зачастую непредсказуемы ИМХО (возможно, именно поэтому некоторые приложения у меня на LPC2468 падают), выделять много - расточительно (если система маломощная), выделять мало - нельзя.

Пока меня платформы без MMU не воодушевляют, есть дела поинтереснее, но не стоит зарекаться...

воскресенье, 21 октября 2007 г.

Использование памяти...

А тем временем я, наконец то, создал временный хип и уже разместил в нем символы ядра...

С размером временного хипа не все однозначно.
С одной стороны размер памяти известен, и легко можно предсказать сколько памяти потребуется для хранения внутренних таблиц страниц (не путать с таблицами IA32). Так же легко можно предсказать - сколько памяти потребуется для дескрипторных таблиц IA32, потому что их размер фиксированный. Остается только память, необходимая для инициализации модулей и для хранения символов. Модулям много не надо, тем более что они не активизированные, но необходимо учитывать их количество (временно положил по килобайту на модуль).

А вот размер таблицы символов может быть определен только в процессе разбора. Ну я думаю что несколько килобайт временного хипа про запас проблемы не составят. Тем более что я уменьшил размер PageInfo в два раза по сравнению в предыдущей версией.

Еще я придумал как правильно каскадировать регионы. Я буду делать это через инстанции, что позволит пользоваться механизмом инстанций для высвобождения родительских регионов, и не изобретать еще один велосипед.

А еще пришла в голову интересная мысль, что модули, загружаемые GrUB могут быть вытеснены в своп средствами лоадера, ибо путь к модулям мы знаем! Естественно не все модули могут быть высвоплены. Непосредственные участники процесса должны всегда находиться в памяти (может быть специальный флажек в процессе предусмотреть? всеравно своппингом будет управлять ядро).

четверг, 4 октября 2007 г.

Поглощение памяти...

Есть много различных алгоритмов динамического распределения памяти. Я для себя выбрал один в меру быстрый, но не буду сейчас углубляться в его тонкости. Сейчас я хотел рассказать об одной хитрости, которая позволит не создавать статически выделенную память до перехода в страничный режим.

Любая динамически выделяемая память выделяется блоками. И обычно у каждого блока есть заголовок.. но прежде, чем создать рабочий хип ядра нам необходимо провести ревизию системных ресурсов, и создать списки страниц... То есть память нам нужна еще до того, как ядро войдет в рабочий режим и обзаведется полновесным хипом. Но как это сделать?

Списки страниц могут занимать разное количество памяти. Это зависит от количества собственно памяти в системе. Необходимо создать временный хип, который сможет вместить в себя списки страниц и некоторую другую информацию, определяемую до перехода в страничный режим. Количество памяти нам любезно предоставляет GrUB.
И мы получаем размер, который для удобства округлим до страниц.

Выбирая место для временного хипа необходимо подумать о том, чтобы он целиком размещался в линейном пространстве рабочего хипа, иначе хитрость не получится.
А рабочий хип располагается от конца ядра до начала области пользователя (до сих пор эта граница проходила на 128 мегабайтах). Но нам мешают модули, которые лежат в физической памяти после ядра. Проанализировав списки модулей, мы определяем начало свободной памяти.

Осталось только проконтролировать, что оставшегося количества физической памяти хватит на размещение временного хипа. В нынешние времена это конечно не проблема, но если вдруг памяти окажется по настоящему мало (2 мебибайта к примеру) эта проблема может встать остро.

Но вот место и размер для временного хипа определены, инициализируем его и начинаем резать на блоки. Места должно хватить на все.

Для успешного перехода в страничный режим мы должны замапить ядро и собственно временный хип. Маппинг осуществляется один к одному. То есть, в страничном режиме все указатели на хип останутся актуальны по-прежнему. Но теперь нам нужно организовывать рабочий хип. Делается это не совсем линейно, мы определяем в свободные блоки линейную память до временного хипа и после него. Блоки временного хипа получают новые привязки к рабочему хипу. По необходимости дефрагментируются, и временный хип перестает существовать, будучи поглощенным рабочим. При этом, опять таки, все указатели со времени инициализации сохраняют свою актуальность.

Вот собственно такие планы на хип нового ядра. На этом на сегодня все.