Форум программистов, компьютерный форум, киберфорум
JIuXOMAHT
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  

ОС на ассемблере. Полуношный проэкт. часть 2.

Запись от JIuXOMAHT размещена 18.02.2016 в 13:50
Показов 2716 Комментарии 2

Прелюдия...

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

И первый шаг мы сделаем прямо в следующий раз... В следующий раз... Постоянно он идет следующим, все время отдаляя тот долгожданный миг, когда вымысел становится явью. Эти мирские делишки постоянно всовывают свои немаскируемые прерывания в наш прекрасный дзэн. Прости, что я только трачу свое время. Но такова моя судьба, выбор которой я сделал несколько миллиардов тактов назад... А пока довольствуйся тем, что написано немножко ниже... Давай погрустим немножко вдвоем. Пусть это будет немножко меланхоличная ОС...

Итак, наследственная многозадачность. Каждая следующая программа принимает себе в обязанность исполнять основные функции предыдущей, при этом управление, расчет и распределение ресурсов между задачами находится всецело на ее плечах. Таким образом, сразу возникают первое, второе и третье правила написания кода программ для нашей ОС: 1)Код должен содержать минимизированный листинг всех функций и констант, которые будут впоследствии наследованы следующей программой; 2) Код должен содержать в себе особую выделенную зону для вставки в нее этих кусков кода, наследуемых у предыдущей программы; 3) Код должен содержать собственный диспетчер ресурсов, который распределяет ресурсы между основной и наследованными задачами. Как ты уже понял, прямого переключения между приложениями не будет. Каждая запускаемая программа будет заново ассемблироваться с наследственными включениями. Соответственно, ОС должна будет иметь собственный компилятор FASM. А программы будут храниться в виде текстовых файликов. Для защиты их содержимого можно изменить их тип на новый, системный, допустим, *_sm, и запретить внесение туда изменений. Мало того, еще и каталог с разрешенными *_sm , будет пополняться только с "кивка" нашего компилятора. Это позволит нам впоследствии написать приложение для написания программ и "дописывания" ОС в реальном времени, не прибегая к услугам эмуляторов... Но это все пока мечты... мечты... жалкие, бесформенные мечты...

Которые беспомощно бьются о подводные камни. Например, включение линии A20 перед запуском защищенного режима... Допустим, включить три следующие строчки не так сложно:

in al, 92h
or al, 02h; здесь может понадобится время ожидания
out 92h, al

Однако, по словам самой Интел, уже поддержка этого рудимента ошибок 286-го относительно спорна на ядре Nehalem, а на ядре Haswell и более поздних так вовсе отсутствует... Ну этот так, к сведению.

Или вот еще... Адресная бюрократия. Так называемый "защищенный режим"... Как было прекрасно в реальном... Куда хочешь смотришь, указывай только адрес... Нет, теперь его глобальная таблица дескрипторов, со всеми его дополнительными атрибутами привилегий и прочего флуда, который ничего, кроме постоянного ужирательства процессорного времени на постоянную работу с памятью, пусть и в кэше, но тратит миллионы тактов; ничего и не защищает. Это такая защита от дурака. Типа если разбирается - у него будет работать программа, а ежели нет, то и фиг с ним. Для тех, кто еще не в тарелке: между обращением программы и памятью поставили дополнительный набор простыней - Глобальная таблица дескрипторов GDR, локальная таблица дескрипторов LDR, и для страничной памяти (paging)- страница памяти (адресует 4 кб данных), таблица страниц памяти (адресует 4 мб данных), каталог таблиц страниц памяти (адресует 4 гб данных). Все их системным программистам приходится писать самим. Конечно, контекст многих задач настолько непредсказуем, что без динамического прописывания селекторов (указателей на дескриптор в таблице, который в свою очередь является прописанным указателем на сегмент или страницу в памяти, этакий посредник) не обойтись. Однако внесение изменений в таблицу глобальную создает опасность для системы остаться у разбитого корытца, ибо правило гласит : сначала таблица, потом исполнение, иначе #GP. Поэтому и существуют локальные таблицы дескрипторов, которые можно изменять уже поспокойнее, не забыв прописать в таблице прерываний на передачу обработки прерывания программы обработчиком в составе текущего приложения. Для ассемблерщика это яд, пустая трата времени, но мы должны этот путь пройти, ибо как гласит AMD64: сначала реальный, за ним защищенный, затем длинный и уж только потом 64-й. Вот! Там же лежит небольшой кусок кода экстренного перехода из реального в 64-разрядный режим (оригинальные комментарии оставлены как есть):

mydata segment para


pGDT32 label fword ; Used by LGDT.
dw gdt32_limit ; GDT limit ...
dd gdt32_base ; and 32-bit GDT base
pIDT32 label fword ; Used by LIDT.
dw idt32_limit ; IDT limit ...
dd idt32_base ; and 32-bit IDT base



pGDT64 label tbyte ; Used by LGDT.
dw gdt64_limit ; GDT limit ...
dq gdt64_base ; and 64-bit GDT base
pIDT64 label tbyte ; Used by LIDT.
dw idt64_limit ; IDT limit ...
dq idt64_base ; and 64-bit IDT base
mydata ends ; end of data segment

code16 segment para use16 ; 16-bit code segment

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;
; 16-bit code, real mode
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;
;
; Initialize DS to point to the data segment containing
; pGDT32 and PIDT32. Set up a real-mode stack pointer, SS:SP,
; in case of interrupts and exceptions.
;

cli; установка флага, запрещающего внешние прерывания
mov ax, seg mydata; запись в общий 16-й регистр указателя сегмента метки "mydata"
mov ds, ax; запись в 16-й регистр сегмента данных
mov ax, seg mystack; запись в общий 16-й регистр указателя сегмента метки "mystack"
mov ss, ax; запись в 16-й регистр сегмента стека.
mov sp, esp0; запись в 16-й регистр указателя стека нового указателя стека с CPL=0

;
; Use CPUID to determine if the processor supports long mode. ;

mov eax, 80000000h ; Extended-function 8000000h.
cpuid ; Is largest extended function
cmp eax, 80000000h ; any function > 80000000h?
jbe no_long_mode ; If not, no long mode.
mov eax, 80000001h ; Extended-function 8000001h.
cpuid ; Now EDX = extended-features flags.
bt edx, 29 ; Test if long mode is supported.
jnc no_long_mode ; Exit if not supported.

;
; Load the 32-bit GDT before entering protected mode.
; This GDT must contain, at a minimum, the following
; descriptors:
; 1) a CPL=0 16-bit code descriptor for this code segment.
; 2) a CPL=0 32/64-bit code descriptor for the 64-bit code.
; 3) a CPL=0 read/write data segment, usable as a stack
; (referenced by SS).
;
; Load the 32-bit IDT, in case any interrupts or exceptions
; occur after entering protected mode, but before enabling
; long mode).
;
; Initialize the GDTR and IDTR to point to the temporary
; 32-bit GDT and IDT, respectively.
;

lgdt ds:[pGDT32]; загрузка 32-й временной глобальной таблицы дескрипторов
lidt ds:[pIDT32]; загрузка 32-й временной таблицы прерываний

;
; Enable protected mode (CR0.PE=1).

mov eax, 000000011h; запись в общий 32-й регистр особого значения
mov cr0, eax; запись в 32-й регистр управления значения общего 32-го регистра

;
; Execute a far jump to turn protected mode on.
; code16_sel must point to the previously-established 16-bit
; code descriptor located in the GDT (for the code currently
; being executed).
;

db 0eah ;Far jump... Этот дальний прыг ну просто необходим, дабы сбросить конвеер, на котором
dw offset now_in_prot;to offset... уже сидят следующие команды, организованные по старым правилам
dw code16_sel ;in current code segment. реального режима. А нам нужен защищенный режим.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;
; At this point we are in 16-bit protected mode, but long
; mode is still disabled.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;

now_in_prot:

;
; Set up the protected-mode stack pointer, SS:ESP.
; Stack_sel must point to the previously-established stack
; descriptor (read/write data segment), located in the GDT.
; Skip setting DS/ES/FS/GS, because we are jumping right to
; 64-bit code.
;

mov ax, stack_sel
mov ss, ax; ну вот мы уже загружаем новые, временные, правда, но правила
mov esp, esp0

;
; Enable the 64-bit page-translation-table entries by
; setting CR4.PAE=1 (this is _required_ before activating
; long mode). Paging is not enabled until after long mode
; is enabled.
;

mov eax, cr4; загрузка содержимого 32-го регистра управления в общий 32-й регистр
bts eax, 5; установка 5 бита в состояние "1"
mov cr4, eax; загрузка содержимого общего 32-го регистра в 32-й регистр управления

;
; Create the long-mode page tables, and initialize the
; 64-bit CR3 (page-table base address) to point to the base
; of the PML4 page table. The PML4 page table must be located
; below 4 Gbytes because only 32 bits of CR3 are loaded when
; the processor is not in 64-bit mode.
;

mov eax, pml4_base ; Pointer to PML4 table (<4GB). Грузим указатель на нашу долгожданную 64-ю
mov cr3, eax ; Initialize CR3 with PML4 base. таблицу.

;
; Enable long mode (set EFER.LME=1).
;

mov ecx, 0c0000080h ; EFER MSR number. Это особый дополнительный регистр в AMD64, который
rdmsr ; Read EFER. отвечает в том числе за работу длинного режима. Первые две
bts eax, 8 ; Set LME=1. строчки его считывают, вторые - переписывают и возвращают.
wrmsr ; Write EFER. 0c0000080h - это его особый адрес.

;
; Enable paging to activate long mode (set CR0.PG=1)
;

mov eax, cr0 ; Read CR0. Уже второй раз обращаемся в регистр управления, устанавливаем бит "1" и
bts eax, 31 ; Set PE=1. возвращаем на место.
mov cr0, eax ; Write CR0.

;
; At this point, we are in 16-bit compatibility mode
; ( LMA=1, CS.L=0, CS.D=0 ).
; Now, jump to the 64-bit code segment. The offset must be
; equal to the linear address of the 64-bit entry point,
; because 64-bit code is in an unsegmented address space.
; The selector points to the 32/64-bit code selector in the
; current GDT.
;

db 066h; Вот и мы уже изменяем размер операндов с 16-х на 32-е
db 0eah; Вот и мы опять прыгаем далеко со сбросом конвеера
dd start64_linear; Прыгаем на это смещение.
dw code64_sel; В этот чудесный сегмент.
code16ends ; End of the 16-bit code segment

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;
;;
;;; Start of 64-bit code
;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;

code64 para use64
start64: ; At this point, we're using 64-bit code

;
; Point the 64-bit RSP register to the stack’s _linear_
; address. There is no need to set SS here, because the SS
; register is not used in 64-bit mode.
;

mov rsp, stack0_linear

;
; This LGDT is only needed if the long-mode GDT is to be
; located at a linear address above 4 Gbytes. If the long
; mode GDT is located at a 32-bit linear address, putting
; 64-bit descriptors in the GDT pointed to by [pGDT32] is
; just fine. pGDT64_linear is the _linear_ address of the
; 10-byte GDT pseudo-descriptor.
;
; The new GDT should have a valid CPL0 64-bit code segment
; descriptor at the entry-point corresponding to the current
; CS selector. Alternatively, a far transfer to a valid CPL0
; 64-bit code segment descriptor in the new GDT must be done
; before enabling interrupts.
;

lgdt [pGDT64_linear]

;
; Load the 64-bit IDT. This is _required_, because the 64-bit
; IDT uses 64-bit interrupt descriptors, while the 32-bit
; IDT used 32-bit interrupt descriptors. pIDT64_linear is
; the _linear_ address of the 10-byte IDT pseudo-descriptor.
;

lidt [pIDT64_linear]

;
; Set the current TSS. tss_sel should point to a 64-bit TSS
; descriptor in the current GDT. The TSS is used for
; inner-level stack pointers and the IO bit-map.
;

mov ax, tss_sel
ltr ax

;
; Set the current LDT. ldt_sel should point to a 64-bit LDT
; descriptor in the current GDT.
;

mov ax, ldt_sel
lldt ax

;
; Using fs: and gs: prefixes on memory accesses still uses
; the 32-bit fs.base and gs.base. Reload these 2 registers
; before using the fs: and gs: prefixes. FS and GS can be
; loaded from the GDT using a normal “mov fs,foo” type
; instructions, which loads a 32-bit base into FS or GS.
; Alternatively, use WRMSR to assign 64-bit base values to
; MSR_FS_base or MSR_GS_base.
;

mov ecx, MSR_FS_base
mov eax, FsbaseLow
mov edx, FsbaseHi
wrmsr

;
; Reload CR3 if long-mode page tables are to be located above
; 4 Gbytes. Because the original CR3 load was done in 32-bit
; legacy mode, it could only load 32 bits into CR3. Thus, the
; current page tables are located in the lower 4 Gbytes of
; physical memory. This MOV to CR3 is only needed if the
; actual long-mode page tables should be located at a linear
; address above 4 Gbytes.
;

mov rax, final_pml4_base ; Point to PML4
mov cr3, rax ; Load 64-bit CR3

;
; Enable interrupts.
;

sti ; Enabled INTR снятие флага, запрещающего внешние прерывания

<insert 64-bit code here>

Часть вопросов так и осталась просто вопросами, особенно та часть, что относится к 64-ому коду. Разработчики особо не старались создавать готовый код, снабдив некоторые места внятными метками. Пока мы не научимся их писать, дальнейшее продвижение маловероятно. Обратите внимание на оператор db и seg. Оператор в отличие от команд не является указанием для процессора, это указание ассемблеру, поэтому счетчик команд никак не реагирует на него, кроме одного случая: если после оператора db стоит опкод какой-либо команды. Да и вообще, когда читаешь описание той или иной хрени, обязательно нарвешься на какого-то толкиенутого с его "резервированием местом в памяти", вместо "ручная запись в итоговый код следующей байтной или битной последовательности определенной длины". Для чего нужна эта ручная запись? Ну так дело все в мнемониках: на деле одной мнемонике может соответствовать от одного до нескольких опкодов с некоторыми исполнительными различиями. В большинстве случаев, ассемблер верно трактует контекст и выставляет нужный опкод в нужном месте, однако в критичных местах лучше перестраховаться и вместо

JMP Segment:Smeschenie

записать

db 0eah;
dd Smeschenie;
dw Segment;

Оператор seg возвращает значения сегмента памяти, в котором находится указанная величина... Почитай про операторы, очень интересно. Пока все, мой друг. Обещаю не бросать тебя на очень долго. До скорого...

[продолжение следует]
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 2
Комментарии
  1. Старый комментарий
    Есть же тег ASM.
    Запись от castaway размещена 10.03.2016 в 21:41 castaway вне форума
  2. Старый комментарий
    Аватар для JIuXOMAHT
    Цитата Сообщение от castaway
    Есть же тег ASM.
    И что он делает?
    Запись от JIuXOMAHT размещена 10.03.2016 в 23:22 JIuXOMAHT вне форума
 
Новые блоги и статьи
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
Оттачиваю умение писать js программы.
russiannick 30.08.2026
Проектом выходного дня стало написание Книги шифров Виженера. Итогом стала версия 200, синий туман. Синий туман назван так, потому что замораживает текст под собой. Нажатие синих кнопок управляют. . .
мат медиц модель 30. презентация проекта
anaschu 27.08.2026
хоп хоп хоп хидахоп, а я кладую))
Как у меня протекала болезнь
zorxor 27.08.2026
Здравствуйте, друзья! Эта запись блога предназначена именно для вас - для моих дорогих друзей, которые знали меня лично. Чтобы ответить на вопрос - а что же со мной произошло на самом деле? Я учился. . .
Нашел вот забавное видео о измерениях. Лучшее что я видел на эту тему
kumehtar 26.08.2026
ILETXiw9bMQ Основная суть и тезисы по измерениям: 0D (Нулевое измерение): точка, не имеющая длины, ширины, высоты или объема. Объект не может перемещаться в 0D. 1D (Первое измерение):. . .
[EasyBuilder Pro] Памятка по разработке для панелей Weintek
ФедосеевПавел 26.08.2026
Памятка по разработке для панелей Weintek ВВЕДЕНИЕ Ранее, при реализации проектов основное внимание уделял разработке управляющей программы для контроллера, а панели оператора доставалось время. . .
Модель по догадкам
anaschu 25.08.2026
Прошло две недели. Я уже рассказывал, как разговаривал с сотрудниками у сортировки и как понял, что главная ветка — не про приёмку, а про отбор. Но тогда я думал, что понял механику. На этой неделе я. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru