(C) Ville Turjanmaa, Helsinki, 25.8.2003, All rights reserved. перевод Mario79 24/12/2003 e-mail: mario79@ezmail.ru web: www.mario79.narod.ru MenuetOS (0.75) Ядро и управление процессами 1) Введение: краткий обзор 1a) Последовательность начальной загрузки 1b) Многозадачный режим 1c) Структура файла ядра 2) Управление процессами: Как это работает 2a) Таблицы описаний 2b) Детальное описание статических прерываний 2c) Системные ошибки 2d) Математический сопроцессор 2e) Планировщик 2f) Описатели процесса приложения 2g) Регистрация данных устройства 2h) Драйвер системного вызова 2i) Добавление системного вызова Предисловие - о MenuetOS MenuetOS была написана на языке 32-х разрядного ассемблера для поддержки снизу-вверх 32 разрядного программирования, как платформа для ускорения и уменьшения системных требований. Menuet не имеет никаких корней unix и основная система, как предполагается, является основанной на чисто ассемблерной структуре. Menuet не основывается ни на какой специфической операционной системе, так как идея состояла в том, чтобы удалить дополнительные уровни между различными частями программного обеспечения, которые усложняют программирование и создают ошибки. Структура приложений оси не зафиксирована для программирования в ассемблере, заголовок может использоваться с любым другим языком. Однако все приложения программируемого проекта предназначены для программирования на лёгком 32-х разрядном ассемблере. GUI (ГРАФИЧЕСКИЙ ИНТЕРФЕЙС ПОЛЬЗОВАТЕЛЯ) чрезвычайно прост для использования с ассемблером. (C) Ville Turjanmaa, Helsinki, 25.8.2003, All rights reserved. 1) Введение: краткий обзор 1a) Последовательность начальной загрузки Когда компьютер включают, система bios загружает bootsector Menuet, который в свою очередь загружает ядро. Menuet может быть загружена с дискеты или винчестера. Синий экран настроек с версией MenuetOS отображается, когда ядро успешно загружено. В этой стадии ядро отображает версию BIOS Vesa и спрашивает пользователя о требуемом графическом режиме визуального отображения. Если вы не уверены, относительно свойств Menuet предлагаю вам отключить предлагаемые свойства. Отключая некоторые из свойств нужно учитывать, что Menuet будет работать медленнее, но при этом будет полностью функционален. После того, как выбор сделан, ядро загружает ramdisk и переключается в графический режим, выбранный пользователем. В этой стадии Menuet устанавливает среду для выполнения как 32-х битную OS. 1b) Многозадачный режим Menuet использует карусель, приоритетную многозадачность и переключение задач параллельных процессов. Краткий обзор выполнения процесса: - - - - - - - - - - - - - - - - - - - - - - - - - - - . . . . . Ядро . . Процесс . . ------------------- . . --------------------- . . Круг 0 . . Круг 3 . . . . . . Планировщик (IRQ 0 ) . . Доступ к аппаратным . . время выполнения . . средствам через ядро . . задачи 1/100s . . . . . . . . Задача 1: OS-цикл . . Задача 2,3.. : . . Мышь, GUI, Сеть . . Приложения . . . . . . Вход системных . <------ . INT 0x40: Системный . . вызовов . . вызов . . . . . . Системная функция . ------> . Возврат с параметрами . . . . . - - - - - - - - - - - - - - - - - - - - - - - - - - - Приложения загружены в область памяти начинающейся с 16 МБ. Если пользователь выбирает модель памяти 16 МБ, тогда приложения загружаются в область памяти начинающуюся с 10 МБ. Первая задача в списке процессов - os задача. OS задача обеспечивает выполнение всех общих функций системы, например: мышь, перемещение окон, завершение процессов и сеть. Что касается синхронизации, os задача не имеет никаких привилегий по сравнению с другими процессами. Системные вызовы реализованы через прерывание 0x40 с записью параметров функций в регистры. Стек не используется для принятых параметров. Планировщик не делает различий между процессами системы и процессами приложения. Сегменты данных установлены так, чтобы начаться с нулевого физического адреса. Приложение не должно резервировать пространство стека для функций системного вызова. Это позволяет не увеличивать размер приложения во время выполнения. Планировщик выполняется через промежуток времени в 1/100 секунды. Переключение задач может, также выполнятся с функцией change_task (изменение задачи) с задержкой или функциями event_wait (ждать задачи), например. Этим путем приложение не резервирует больше процессорного времени, чем ему действительно нужно. Приложение, начинающееся первым, записано как 'firstapp' в kernel.asm. 1c) Структура файла ядра Главный код ядра сохранен в Kernel.asm. Kernel16.inc и Kernel32.inc содержат используемые драйверы устройств. Bootmosf.asm - Загрузка с дискеты Bootmf32.asm - Загрузка с винчестера Kernel.asm <- Kernel16.inc <- Bootcode.inc информация начальной загрузки <- Booteng.ing язык начальной загрузки <- Pci16.inc функции 16-и разрядной pci <- Kernel32.inc <- Sys32.inc управление процессами <- Stack.inc сетевой интерфейс <- Queue.inc буферные очереди <- Ip.inc процессы ip <- Tcp.inc процессы tcp <- Udp.inc процессы udp <- Ethernet.inc процессы локальной сети Ethernet (на основе протокола CSMA-CD) <- Rtl8029.inc драйвер Rtl8029 <- I8255x.inc драйвер I8255x <- Rtl8139.inc драйвер Rtl8139 <- Shutdown.inc завершение и перезагрузка <- Fat32.inc чтение / запись hd (винчестера) <- Vesa12.inc драйвер vesa 1.2 <- Vesa20.inc драйвер vesa 2.0 <- Vga.inc драйвер VGA <- Sb16.inc Sound blaster (звуковая карта) <- Mouse.inc курсор мыши <- Skincode.inc обрамление окон <- Skindata.inc определение обрамления <- Memmap.inc карта памяти <- Pci32.inc функции 32-х разрядной pci Kernel16.inc и kernel32.inc могут также использоваться для формирования автоматизированного инсталлятора, который выбирает необходимые драйверы. Этим путем пользователь может компилировать ядро для точной установки на машину. 2) Управление процессами: Как это работает 2a) Таблицы описаний Таблицы описаний построены так, чтобы следовать за структурой описанной ниже. Прерывания сначала направляются в Interrupt Descriptor Table (Таблицу Описывающую Прерывания), которая в свою очередь направляет обработку процесса в General Descriptor Table (Общую Таблицу описаний). GDT имеет указатели на статические Task Switch Segments (Сегменты Переключения Задачи) и процесс TSS’s. Каждый процесс имеет TSS непосредственно для задачи и ещё возможен другой TSS для системного драйвера. Так что планировщик переключает или к TSS приложения или к TSS системного вызова для каждого выполняемого процесса. Menuet выполняет полное переключение задачи с каждым внутренним и внешним прерыванием. Системные ошибки : Планировщик : IRQ’s : Системный вызов : : : Int 0x0-0x11 : (Заменяемая задача) : Irq 0x0-0xF : Int 0x40 v : v : v : v v : v : v : v IDT : JMP : IDT : IDT - Ворота задачи : : - Ворота задачи : - Ворота задачи v : v : v : v v : v : v : v GDT : GDT : GDT : GDT - TSS указатели : - TSS указатели : - TSS указатели : - TSS указатели v : v : v : v v : v : v : v TSS : TSS : TSS : TSS - Статический : - Процессы : - Статический : - Системные вызовы Так имеется два вида TSS: статический и связанный с процессом. TSS’s возобновления восстанавливает исходное состояние os для каждого запущенного процесса. Модифицирует указатель входа системного вызова в адресуемом планировщиком входе GDT. Если запущенный процесс выполняет системный вызов, os создает дубликат TSS в системном вызове. Так что защита переключателя задачи происходит каждый раз, когда происходит системный вызов. Процесс приложения не должен резервировать пространство стека для системного вызова, так как стеки драйверов системного вызова расположены в ядре (4096 байтов). Когда планировщик выполняет задачу, он использует команду jmp TSS, чтобы запустить процесс TSS или системный вызов TSS, в зависимости от того, какая часть процесса является в настоящее время активной. 2b) Детальное описание статических прерываний (системные ошибки и IRQs 0x1-0xF) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - . . . Прерывание Таблицы описаний . . . . Тип : Task_gate . . Расположение : sys32.inc, ‘idts:’ . . Размер : 0x60 * 8 bytes . . Указатели на : GDT ( TSS0I_L ) . . . - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - . . . GDT ( TSS0I_L ) . . . . Тип : описание TSS . . Расположение : sys32.inc, gdt, tss0i_l: . . Размер : 0x60 * 8 bytes . . Указатели на : TSS, mem 0x290000, 0x60 входы в интервале 128 байт . . . - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - . . . Таблица TSS в 0x290000 . . . . Тип : Task State Segment (Сегмент Состояния задачи) . . Расположение : [0x290000] . . Размер : 0x60 * 128ytes . . Указатели на : GDT, память . . . . eip -> mem : [sys_int], 0x60 * 4 byte . . esp -> mem : 0x720000, 0x60 * 1024 byte . . cs -> GDT : int_code . . ds -> GDT : int_data . . ss -> GDT : int_data . . es -> GDT : int_data . . gs -> GDT : int_data . . fs -> GDT : int_data . . eflags : dword 0x11002 ( cli, resume ) . . ss0 -> GDT : inte_code . . ss1 -> GDT : ring1_code . . ss2 -> GDT : ring2_code . . esp0 -> mem : 0x52000 . . esp1 -> mem : 0x53000 . . esp2 -> mem : 0x54000 . . . - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2c) Системные ошибки (Прерывания 0x00-0x11) Драйверы системных ошибок имеют задачу информирования планировщика о том, что ошибка произошла, и сохранение всей необходимой информации для удаления задачи из списка процессов. Как только данные установлены, имеет место удаление процесса, точно такое же, как и нормальное завершение приложения. Прерывания 0x00 - > 0x11 вызывают функции s0, s1, s2, .., s11 в sys32.inc. sd: ; когда драйвером вводится ошибка, прерывания ; заблокированы посредством eflags mov [error_interrupt],0xd ; подтверждение планировщика что ошибка ; произошла в прерывании 0xd mov [error_interrupt_entry],dword sd ; запись для восстановления ; входа прерывания в TSS call show_error_parameters ; преобразование данных отладчика ; для подтверждения пользователем mov edx,[0x3010] ; пометить процесс как удалённая mov [edx+0xa],byte 4 ; задача os sti ; запустить прерывания для планировщика jmp $ ; ждать для планировщика Когда программируемый таймер прерывания вызывает планировщик, это очищает драйвер ошибки согласно информации, сохраненной до этого. Планировщик отключает прерывания в драйверах ошибки TSS (eflags), например. И при следующем выполнении os-задачи, удаляет приложение из списка задач. 2d) Floating Point Unit - Математический сопроцессо (Прерывание 0x07) Использование FPU в прикладной программе требует очистки Task Switched flag (Флага Переключения Задачи). Menuet выполняет полное переключение задачи с каждым прерыванием, которое установлено в Task Switched flag. Так что мы не можем вернуться в приложение командой jmp TSS. Прежде, чем мы сможем вернуть TSS приложения, мы должны cделать следующие замены: 1) ( s7 ) заменяет адрес точки возврата (eip и сегментированных регистров) в приложениях TSS в функции 'fpu_handler’ (sys32.inc). 2) ( fpu_handler ) Очищает TS-flag, сохраняет состояние FPU и возвращается к процессу командой iret, которая не устанавливает TS flag. 2e) Планировщик (IRQ 0) Планировщик создаёт импульс сигнала времени в Menuet. Планировщик переключает процессы 100 раз в секунду или когда вызван функцией change_task (изменение задачи). Change_task - функция ядра, которая вызывается, например, когда отдельный процесс ожидает случая. Задачи Планировщиков: 1) Очищать возможную ошибку драйвера, который нужно использовать снова с прерыванием сгенерированным аппаратными средствами 2) Очищать flags предыдущих процессов, чтобы использоваться снова с прямой jmp -командой 3) Модифицировать состояние времени и использование CPU (центральный процессор) для приложений. 4) a) Если флаг изменения задачи включен, найти следующую задачу в process list (списке процессов) и перехода к описанию TSS в GDT b) Если флаг изменения задачи выключен, возвратиться к потоку выполняемого процесса. irq0: ; планировщик ; системная ошибка прерываний ошибки заставляют [error_interrupt] ; указывать на erroneus драйвер прерывания, ; который должен быть очищен, так это может использоваться снова. cmp [error_interrupt],-1 je no_error_in_previous_process mov edi,[error_interrupt] ; очистка прерывании GDT flags imul edi,8 mov [edi+tss0i_l +5], word 01010000b *256 +11101001b mov edi,[error_interrupt] ; восстановить точку входа imul edi,128 add edi,0x290000 mov esi,[error_interrupt_entry] mov [edi+l.eip-tss_sceleton],esi ; Восстановить flags (флаги) в прерываниях TSS mov [edi+l.eflags-tss_sceleton],dword 0x11002 ; cli mov [0xffff],byte 0 ; ‘change task’ flag (флаг изменения задачи) для планировщика ; для избежания возврата к драйверу ошибки mov [error_interrupt],-1 ; .. мы свободны использовать драйверы снова no_error_in_previous_process: mov edi,[0x3000] ; очистить предыдущие занятые флаги задач в GDT imul edi,8 ; так чтобы это можно было ввести снова с командой jmp mov [edi+gdts+ tss0 +5], word 01010000b *256 +11101001b inc dword [0xfdf0] ; прирост счетчика полезного времени mov eax,[0xfdf0] ; вычисление использования системы для каждого cmp eax,[next_usage_update] ; приложения, в отрезке времени, в одну секунду jb nocounter add eax,100 mov [next_usage_update],eax call updatecputimes nocounter: mov edi,[0x3010] ; нахождение следующего слота процесса, который mov ebx,[edi+0x18] ; имеет выполняющееся приложение call _rdtsc sub eax,ebx add eax,[edi+0x14] mov [edi+0x14],eax mov ebx,[0x3000] cmp [0xffff],byte 1 je do_not_change_task waiting_for_termination: waiting_for_reuse: add edi,0x20 inc ebx cmp [edi+0xa],byte 3 ; ожидание завершения je waiting_for_termination ; вызванного системного вызова (-1) cmp [edi+0xa],byte 4 ; ожидание завершения je waiting_for_termination ; вызванной ошибки защиты cmp [edi+0xa],byte 9 ; завершение и ожидание повторного использования je waiting_for_reuse cmp ebx,[0x3004] jbe nsched0 mov ebx,1 mov edi,0x3020 nsched0: mov [0x3000],ebx ; сохранение слота задачи выполняемого процесса и mov [0x3010],edi ; расположения базовой информации do_not_change_task: call _rdtsc ; модифицикация накладываемого значения таймера mov [edi+0x18],eax ; для запуска задачи cmp [0xffff],byte 0 ; уменьшение значения ‘do not change task’ je nodecffff ; (не изменняемая задача) dec byte [0xffff] nodecffff: shl bx,3 ; вычисление входа GDT для следующей задачи add bx,tss0 mov [tss_s],bx mov al,0x20 ; подтверждение Programmable Interrupt Controller mov dx,0x20 ; (Программируемый Контроллер Прерывания) out dx,al db 0xea ; jmp .. ( to gdt ) tss_t dd 0 ; word (tss0+(process_slot*8)):dword 0 tss_s dw tss0 jmp irq0 ; точка входа для следующего irq0 2f) Описатели процесса приложения Во время загрузки ядро инициализирует таблицу GDT, которая впоследствии изменяется драйвером системного вызова. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - . . . GDT ( TSS0_L ) . . . . Тип : описатель TSS . . Расположение : sys32.inc, gdt, tss0i_l: . . Размер : ( max_processes ) * 8 bytes . . Указатели на : таблица приложений TSS в [0x40000] . . . - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - При создании процесса, os генерирует следующий Task State Segment (Сегмент Состояния задачи) и общие описатели (круг 3) для GDT, которые определяют безусловное использование прикладными программами физической памяти. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - . . . Таблица приложений TSS . . . . Тип : Task State Segment (Сегмент Состояния задачи) . . Расположение : [0x290000] . . Размер : ( max_processes ) * 128 bytes . . Указатели на : GDT, память . . . . eip -> mem : ( читать заголовок приложения ) . . esp -> mem : ( читать заголовок приложения ) . . cs -> GDT : app_code_l + обработка положения . . ds -> GDT : app_data_l + обработка положения . . ss -> GDT : app_data_l + обработка положения . . es -> GDT : app_data_l + обработка положения . . gs -> GDT : app_data_l + обработка положения . . fs -> GDT : app_data_l + обработка положения . . eflags : dword 0x11102 ( sti, resume ) . . ss0 -> GDT : inte_code . . ss1 -> GDT : ring1_code . . ss2 -> GDT : ring2_code . . esp0 -> mem : 0x55000 . . esp1 -> mem : 0x56000 . . esp2 -> mem : 0x57000 . . io -> abs : 512 -> генерация ошибки защиты . . . - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2g) Регистрация данных устройства Menuet имеет программируемые драйверы IRQ, которые производят запись данных из портов установленных приложением. Они удобны при регистрации данных от внешнего устройства с вызовом прерывания, когда данные доступны. p_irq3: ; Одна из функций, которая вызвана ; внешним IRQ ; прерывания блокируются в TSS - eflags call restore_caller ; восстанавление прерванной задачи mov edi,15 ; вызов функции записывающей call irqhandler ; данные : irqhandler call return_to_caller ; возвращение к прерванной задаче jmp p_irq3 restore_caller: ; восстанавление прерванных процессов ; gdt, чтобы использоваться снова, иначе ; мы имели бы общую ошибку защиты, ; так как задача отмечена как ; занятая (выполняющаяся) mov edi,[0x3000] imul edi,8 mov [edi+gdts+ tss0 +5], word 01010000b *256 +11101001b ret return_to_caller: mov ebx,[0x3000] ; исползуется прямой jmp ( 0xea ) к shl bx,3 ; началу прерванной задачи снова add bx,tss0t mov [tss_irq12],bx db 0xea dd 0 tss_irq12 dw tss0t ret ; точка входа для следующего IRQ 3 и ; непосредственного возвращения к драйверу ; стеков, отдельных для каждого драйвера, ; так что мы можем использовать ту же ; самую функцию для всех прерываний irqhandler: ... ret 2h) Драйвер системного вызова Задача входов системного вызова в том, чтобы обслужить все системные вызовы запрашиваемые приложениями. Для каждого приложения имеется дубликат TSS, для выполнения обслуживания системы, когда выполняется системный вызов. Это служит максимальной защите при выполнении многозадачного режима. Приложение не должно резервировать пространство стека для системных услуг, так как стеки расположены в части os в задаче системного вызова. Обратите внимание, что вход системного вызова - часть дубликата TSS. Когда введен системный вызов i40, это изменяет указатель в таблице GDT, чтобы указать на следующий свободный системный вызов TSS, который будет служить как новый драйвер системного вызова. Так что следующий раз выполняя i40, это выполнит тот же самый код, но с различной TSS. Каждый системный вызов имеет стек 4096 байтов для использования в части ядра. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - . . . GDT ( TSS0SYS ) . . . . Тип : описатель TSS . . Расположение : sys32.inc, ‘tss0sys:’ . . Размер : 128 * 8 bytes . . Указатель на : 0x298000, 0x60 входы в интервале 128 байтов . . . - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - . . . Таблица TSS в 0x298000 . . . . Тип : Task State Segment (Сегмент Состояния задачи) . . Расположение : [0x290000] . . Размер : 0x60 * 128ytes . . Указатели на : GDT, память . . . . eip -> mem : i40 . . esp -> mem : 0x780000, 128 * 4096 byte . . cs -> GDT : int_code . . ds -> GDT : int_data . . ss -> GDT : int_data . . es -> GDT : int_data . . gs -> GDT : int_data . . fs -> GDT : int_data . . eflags : dword 0x11002 ( cli, resume ) . . ss0 -> GDT : int_code . . ss1 -> GDT : ring1_code . . ss2 -> GDT : ring2_code . . esp0 -> mem : 0x52000 . . esp1 -> mem : 0x53000 . . esp2 -> mem : 0x54000 . . . - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; ВХОД СИСТЕМНОГО ВЫЗОВА ;; ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; i40: cli mov edi,[0x3000] ; очистить занятые флаги в GDT для imul edi,8 ; вызывающей программы, которую нужно ; использовать снова с jmp mov [edi+gdts+ tss0 +5], word 01010000b *256 +11101001b mov eax,[schd] ; пометить этот драйвер системного вызова как занятый mov [usedi40+eax],byte 1 push eax mov edi,[0x3000] ; отобразить этот специфический системный вызов imul edi,256 ; в вызывающей задаче mov [edi+0x80000+0xB0],eax mov eax,0 ; поиск свободног драйвера системного вызова search_free_i40: ; для следующего вызова прерывания 0x40 cmp [usedi40+eax],byte 0 je found_free_i40 inc eax cmp eax,110 jbe search_free_i40 jmp $ found_free_i40: mov [schd],eax mov edx,8 ; изменение входа в GDT imul edx,[schd] ; ( в 0x40 ) в пункте указывающем на add edx,tss0sys ; следующий свободный драйвер mov edi,8*0x40 mov [edi+idts+ 8 +0], word 0 mov [edi+idts+ 8 +2], dx mov [edi+idts+ 8 +4], word 11100101b*256 mov [edi+idts+ 8 +6], word 0 mov ebx,[0x3000] shl ebx,3 add ebx,tss0_l mov ecx,[0x3000] shl ecx,2 mov eax,[0x3000] mov [tasknum+ecx],eax mov eax,[ebx] mov [reg1+ecx],eax mov eax,[ebx+4] mov [reg2+ecx],eax mov ecx,8 imul ecx,[esp] mov eax,[tss0sys_l+ecx] mov [ebx],eax mov eax,[tss0sys_l+ecx+4] mov [ebx+4],eax call save_registers ; след системного вызова mov esi,[0x3000] imul esi,128 add esi,0x40000 mov eax,[esi+l.eax-tss_sceleton] ; будет возвращён в mov ebx,[esi+l.ebx-tss_sceleton] ; приложение mov ecx,[esi+l.ecx-tss_sceleton] pusha mov edi,[esi+l.eax-tss_sceleton] ; для использования системной функцией mov eax,[esi+l.ebx-tss_sceleton] mov ebx,[esi+l.ecx-tss_sceleton] mov ecx,[esi+l.edx-tss_sceleton] mov edx,[esi+l.esi-tss_sceleton] mov esi,[esi+l.edi-tss_sceleton] sti ; и мы готовы вызывать push eax ; соответствующую системную функцию and edi,0xff call dword [servetable+edi*4] pop eax cli popa ; системный вызов возвращает ; параметры в стек mov esi,[0x3000] imul esi,128 add esi,0x40000 mov [esi+l.eax-tss_sceleton],eax ; сохранение возвращенных регистров в mov [esi+l.ebx-tss_sceleton],ebx ; приложениях TSS mov [esi+l.ecx-tss_sceleton],ecx mov ebx,[0x3000] shl ebx,3 add ebx,tss0_l mov ecx,[0x3000] shl ecx,2 mov eax,[reg1+ecx] mov [ebx],eax mov eax,[reg2+ecx] mov [ebx+4],eax mov [tasknum+ecx],dword 0 mov edi,8 pop eax ; очистка этих драйверов gdt mov [usedi40+eax],byte 0 imul edi,eax mov [edi+tss0sys_l +5], word 01010000b *256 +11101001b mov ebx,[0x3000] ; jmp -> TSS приложения shl bx,3 add bx,tss0t mov [tss_s3],bx db 0xea tss_t3 dd 0 tss_s3 dw tss0t jmp i40 save_registers: ; для следа системного вызова ... ret servetable: ; системные функции dd sys_drawwindow ; 0-DrawWindow (вывод окна) dd syscall_setpixel ; 1-SetPixel (выбор пикселя) dd sys_getkey ; 2-GetKey (получение клавиши) ... dd sys_ipc ; 60-Inter Process Communication (внутренние связи процесса) dd sys_gs ; 61-Direct graphics access (прямой доступ к графике) dd sys_pci ; 62-PCI functions (функции шины PCI) dd sys_msg_board ; 63-System message board (доска системных сообщений) times 255 - ( ($-servetable) /4 ) dd undefined_syscall dd sys_end ; -1 завершение приложения 2i) Добавление системного вызова Когда прерывание вызвано приложением, выполнение процесса продолжается согласно таблице системных функций. Новая функция должна быть добавлена к ‘servetable’ (таблице сервера) в файле sys32.inc. Обратите внимание, что для совместимости с более ранними версиями, регистры должны быть изменены следующим путём: eax < - ebx, ebx < - ecx, ecx < - edx, edx < - esi, esi < - edi. Так если приложение вызывает функцию со значением в edx, то это будет видно в ecx на стороне ядра. После добавления в servertable (таблице сервера), выполнение следующего кода на стороне приложения .. mov eax,(new_system_function_number) mov ebx,2 int 0x40 .. Вызвало бы следующую функцию на стороне ядра. new_system_function: cmp eax,2 ; ebx видим в eax jne label1 mov dx,0x60 in al,dx mov [esp+36],eax ; возвращение результата в eax для приложения ret label1: mov [esp+36],eax ; возвращение результата в eax для приложения ret На стороне ядра, не имеется никаких ограничений для привелигерованных команд или аппаратных средств доступа через порты. Все параметры возвращены прикладной программе с изменением стека. mov [esp+36],eax ; возвращение eax приложению mov [esp+24],ebx ; ebx mov [esp+32],ecx ; ecx ret ; возвращение из системной функции Обратите внимание, что команда 'ret' следует немедленно после того, как возвращаемые значения были расположены в стеке. Если один из параметров прикладной программы - указатель на область данных внутри прикладной программы, Вы можете вычислить физический адрес следующим путём. mov esi,[0x3010] ; esi <- база данных выполняющегося приложения mov edi,[esi+0x10] ; edi <- начало прикладной программы в памяти И Вы получите абсолютный физический адрес с (параметр + edi). --