Board.KolibriOS.org

Official KolibriOS board
It is currently Thu Nov 14, 2019 9:09 am

All times are UTC+03:00




Post new topic  Reply to topic  [ 145 posts ]  Go to page 1 2 3 4 510 Next
Author Message
 Post subject: Fast System Call
PostPosted: Sat Feb 24, 2007 3:21 pm 
Offline
Kernel Developer
User avatar

Joined: Mon Mar 20, 2006 10:44 am
Posts: 557
В современной x86 архитектуре используется три варианта вызва API :
- дальний вызов (Solaris, BSD - селектор 7 смешение 0)
- шлюз прерывания (Kolibri, Linux, Windows до w2k)
- Fast System Call (Linux, WinXP и старше)

При реализации быстрых вызовов я остановился на SYSENTER/SYSEXIT от Intel, за подробностями : Intel® Architecture Software Developer’s Manual, или http://www.codeguru.com/cpp/w-p/system/devicedriverdevelopment/article.php/c8223__1/

Краткая справка:

SYSENTER - Fast System Call
Обеспечивает максимально эффективный переход к коду на нулевок кольце, устанавливая регистры CS, EIP, SS, ESP следуюшим образом:

CS - SYSENTER_CS_MSR
SS - SYSENTER_CS_MSR + 8
ESP - SYSENTER_ESP_MSR
EIP - SYSENTER_EIP_MSR


SYSEXIT - Fast Return from Fast System Call
Обеспечивает максимально эффективный возврат из кода на нулевок кольце к коду на кольце 3, устанавливая регистры CS, EIP, SS, ESP следуюшим образом:

CS - SYSENTER_CS_MSR + 16
SS - SYSENTER_CS_MSR + 24
ESP - ECX
EIP - EDX

SYSENTER_CS_MSR - MSR[0x174]
SYSENTER_ESP_MSR - MSR[0x175]
SYSENTER_EIP_MSR - MSR[0x176]

За поддержку быстрых вызовов отвечает CPUID(1).EDX.bit_11 - SEP(SYSENTER/SYSEXIT present)

Как видно, особенностью бустрых вызовов является то что этот механизм не сохраняет адресс возврата в код кольца 3, в Linux/Win аргументы передаются через стек, поэтому в этих системах необходимые для возврата занчения ECX и EDX устанавливаются кодом приложения, но так как в KolibriOS большая часть функций использует эти регистры для передачи аргументов я предлагаю сохранять регистры в память приложения, например заголовок (адрес DS:0), тогда вызов функций будет выглядеть так:

Code:
SYSENTER_VAR   equ   0
...
   mov   dword[SYSENTER_VAR], @f
   mov   [SYSENTER_VAR + 4], esp
   sysenter
@@:


Из этих же "особенностей" вытекает и то, что значения реистров EDX и ECX результата будут испорчены, это можно обойти аналогично вышеописанному, но пока я этого не реализовал - жду дискусси. Кроме того не реализованно сохранение eflags.

Итак, список изменений:

const.inc
kernel.asm
boot\bootcode.inc
core\syscall.inc

##############[const.inc]##########################

Константы

Code:
.............
.............

; CPU MSR names
MSR_SYSENTER_CS      equ   0x174
MSR_SYSENTER_ESP   equ   0x175
MSR_SYSENTER_EIP   equ   0x176

.............
.............


##############[kernel.asm]#########################

Настройка MSR регистров

Code:
.............
.............

; ENABLE PAGING

           call test_cpu
           bts [cpu_caps], CAPS_TSC     ;force use rdtsc
      
; -------- SYSENTER/SYSEXIT init ----------
   bt   [cpu_caps], CAPS_SEP
   jnc   .SEnP         ; SysEnter not Present
   xor   edx, edx
   mov   ecx, MSR_SYSENTER_CS
   mov   eax, os_code
   wrmsr
   mov   ecx, MSR_SYSENTER_ESP
   mov   eax, sysenter_stack   ; Check it
   wrmsr
   mov   ecx, MSR_SYSENTER_EIP
   mov   eax, sysenter_entry
   wrmsr
.SEnP:
; -----------------------------------------

.............
.............


##############[boot\bootcode.inc]##################

Изменён порядок следования дескрипторов

Code:
.............
.............
; GDT TABLE

gdts:

        dw     gdte-$-1
        dd     gdts
        dw     0

; Внимание! порядок следуюшил четырёх селекторов не менять, используется в SYSENTER/SYSEXIT
; должно быть os_code, os_data, app_code, app_data
int_code_l:
os_code_l:

        dw     0xffff
        dw     0x0000
        db     0x00
        dw     11011111b *256 +10011010b
        db     0x00

int_data_l:
os_data_l:

        dw     0xffff
        dw     0x0000
        db     0x00
        dw     11011111b *256 +10010010b
        db     0x00

app_code_l:
        dw 0xFFFF;((0x80000000-std_application_base_address) shr 12) and 0xffff
        dw 0
        db 0x40
        db cpl3
        dw G32+D32+0x6000+0x7;

app_data_l:
        dw 0xFFFF;(0x80000000-std_application_base_address) shr 12 and 0xffff
        dw 0
        db 0x40
        db drw3
        dw G32+D32+0x6000+0x7;
     
; --------------- APM ---------------------
apm_code_32:
        dw     0x0f        ; limit 64kb
        db     0, 0, 0
        dw     11010000b *256 +10011010b
        db     0x00
apm_code_16:
        dw     0x0f
        db     0, 0, 0
        dw     10010000b *256 +10011010b
        db     0x00
apm_data_16:
        dw     0x0f
        db     0, 0, 0
        dw     10010000b *256 +10010010b
        db     0x00
; -----------------------------------------

graph_data_l:

        dw     0x7ff
        dw     0x0000
        db     0x00
        dw     11010000b *256 +11110010b
        db     0x00
.............
.............


##############[core\syscall.inc]###################

Точка входа быстрого вызова

Code:
.............
.............
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                            ;;
;;                     SYSENTER ENTRY                         ;;
;;                                                            ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

uglobal
times   100 db ?
sysenter_stack:
endg

align 32
SYSENTER_VAR   equ   0
sysenter_entry:
   ; Настраиваем стек
   cli
   push   ds
   push   eax
   mov   ax, os_data
   mov   ds, ax
   mov   eax, [0x3010]
        mov   eax, [eax + TASKDATA.pid]
   call   pid_to_slot         ; не портит регистры
   shl   eax, 12
   add   eax, sysint_stack_data + 4096
   mov   esp, eax
   mov   eax, [sysenter_stack - 4]
   mov   ds, ax
   mov   eax, [ss:sysenter_stack - 8]
   ;------------------
   push   ds es
   pushad
   cld

   mov   ax, word os_data
   mov   ds, ax
   mov   es, ax
   
        mov     eax, ebx
        mov     ebx, ecx
        mov     ecx, edx
        mov     edx, esi
        mov     esi, edi
        mov     edi, [esp + 28]

   sti
   push   eax
   and   edi, 0xff
   call   dword [servetable + edi * 4]
   pop   eax

   popad
   pop   es ds
   ;------------------
   mov   edx, [SYSENTER_VAR]      ; eip
   mov   ecx, [SYSENTER_VAR + 4]   ; esp
   sysexit


iglobal
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; SYSTEM FUNCTIONS TABLE ;;
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.............
.............


Шаблон программы:

Code:
; <--- description --->
; compiler:     FASM 1.50
; name:         Basic window example for MenuetOS
; version:      1.01
; last update:  25/08/2004
; written by:   Ivan Poddubny
; e-mail:       ivan-yar@bk.ru
; adapted by:   Mihailov Ilia


; <--- include all MeOS stuff --->
include "lang.inc"
include "macros.inc"
SYSENTER_VAR   equ   0

; <--- start of MenuetOS application --->
MEOS_APP_START


; <--- start of code --->
CODE
   call   draw_window      ; at first create and draw the window

wait_event:            ; main cycle
   mov   eax, 10
   mov   dword[SYSENTER_VAR], @f
   mov   [SYSENTER_VAR + 4], esp
   sysenter
@@:
   cmp   eax, 1         ;   if event == 1
   je   redraw         ;     jump to redraw handler
   cmp   eax, 2         ;   else if event == 2
   je   key         ;     jump to key handler
   cmp   eax, 3         ;   else if event == 3
   je   button         ;     jump to button handler
   jmp   wait_event      ;   else return to the start of main cycle

redraw:               ; redraw event handler
   call   draw_window
   jmp   wait_event

key:               ; key event handler
   mov   eax, 2         ;   get key code
   mov   dword[SYSENTER_VAR], @f
   mov   [SYSENTER_VAR + 4], esp
   sysenter
@@:

   jmp   wait_event

button:               ; button event handler
   mov   eax, 17         ;   get button identifier
   mov   dword[SYSENTER_VAR], @f
   mov   [SYSENTER_VAR + 4], esp
   sysenter
@@:

   cmp   ah, 1
   jne   wait_event      ;   return if button id != 1

   or   eax, -1      ;   exit application
   mov   dword[SYSENTER_VAR], @f
   mov   [SYSENTER_VAR + 4], esp
   sysenter
@@:

draw_window:
   mov   eax, 12         ; start drawing
   mov   ebx, 1
   mov   dword[SYSENTER_VAR], @f
   mov   [SYSENTER_VAR + 4], esp
   sysenter
@@:

   mov   eax, 0         ; create and draw the window
   mov   ebx, 100 * 65536 + 300   ;   (window_cx)*65536+(window_sx)
   mov   ecx, 100 * 65536 + 200   ;   (window_cy)*65536+(window_sy)
   mov   edx, 0x03ffffff      ;   work area color & window type 3
   mov   dword[SYSENTER_VAR], @f
   mov   [SYSENTER_VAR + 4], esp
   sysenter
@@:

   mov   eax, 4         ; window header
   mov   ebx, 8 * 65536 + 8   ;   coordinates
   mov   ecx, 0x10ffffff      ;   color & font N1
   mov   edx, header      ;   address of text
   mov   esi, header.size   ;   length of text
   mov   dword[SYSENTER_VAR], @f
   mov   [SYSENTER_VAR + 4], esp
   sysenter
@@:

   mov   eax, 12         ; finish drawing
   mov   ebx, 2
   mov   dword[SYSENTER_VAR], @f
   mov   [SYSENTER_VAR + 4], esp
   sysenter
@@:
   ret

; <--- initialised data --->
DATA
lsz header,\
   ru, "˜ Ў«®­ Їа®Ја ¬¬л",\
   en, "Template program",\
   fr, "La programme poncive"

; <--- uninitialised data --->
UDATA

MEOS_APP_END
; <--- end of MenuetOS application --->


P.S. Ну а теперь ложка дёгтя, при добавлении фунции пустышки, и вызов её 0x100000 раз, старый метод (через шлюз прерывания) оказался быстрее ), видимо ошибка в реализации (.


Top
   
 Post subject:
PostPosted: Sat Feb 24, 2007 3:38 pm 
Offline
User avatar

Joined: Thu May 19, 2005 4:43 pm
Posts: 896
А если программа, написанная с использованием sysenter запускается на процессоре, который не поддерживает fast system call, то как тогда быть ?


Top
   
 Post subject:
PostPosted: Sat Feb 24, 2007 4:02 pm 
Offline
Site Founder
User avatar

Joined: Sun Aug 08, 2004 8:55 am
Posts: 689
В программах, использующих макрос mcall, изменять вообще ничего не нужно будет, насколько я понимаю? Кроме самого макроса, естественно, в котором вместо `int 0x40` будет `mov dword[SYSENTER_VAR], ..mcall // mov [SYSENTER_VAR + 4], esp // sysenter // ..mcall: `.


Top
   
 Post subject:
PostPosted: Sat Feb 24, 2007 4:21 pm 
Offline
Kernel Developer
User avatar

Joined: Mon Mar 20, 2006 10:44 am
Posts: 557
Да, с макросами вообше проблем не будет, кроме того можно писать проверку, если нет быстрых вызовов - то прерывание.


Top
   
 Post subject:
PostPosted: Sat Feb 24, 2007 5:02 pm 
Offline
Kernel Developer
User avatar

Joined: Mon Nov 28, 2005 8:00 pm
Posts: 1601
Тогда уж быстрее делать call dword ptr [using_syscall] и инициализировать using_syscall либо адресом процедуры int 0x40, либо предлагаемым вариантом. Хотя предложение что-то пихать по нулевому адресу мне категорически не нравится.
Ещё вариант: на старых процессорах sysenter вызывает исключение, но его ведь ядро может перехватить и проэмулировать...


Top
   
 Post subject:
PostPosted: Sat Feb 24, 2007 5:37 pm 
Offline
Kernel Developer

Joined: Wed Mar 08, 2006 6:25 pm
Posts: 3952
Хорошо что решил этим заняться. У меня было желание но времени нет.

Сохранять регистры в DS:0 нельзя, многопоточные программы не будут работать. Тормозила наверняка pid_to_slot тем более она совсем не нужна. Номер слота текущей задачи хранится в переменной [CURRENT_TASK], она есть в const.inc. sysint_stack_data больше нет память под PL_0 стек выделяется динамически, странно что код работал. Поэтому надо изменить на
mov eax,[CURRENT_TASK]
shl eax,8
mov eax,[PROC_BASE+eax+APPDATA.pl0_stack]
lea esp, [eax+RING0_STACK_SIZE]

RING0_STACK_SIZE сейчас не определена её надо добавить в const.inc
RING0_STACK_SIZE equ 0x2000-512 ;512 байт для контекста FPU

Ещё ты несколько раз перегружаешь сегментные регистры хотя хватает одного раза
mov eax, [ss:sysenter_stack - 8]
задавать явно сегмент не зачем это ведь тот же ds


Last edited by Serge on Sat Feb 24, 2007 7:03 pm, edited 1 time in total.

Top
   
 Post subject:
PostPosted: Sat Feb 24, 2007 6:24 pm 
Offline
Kernel Developer

Joined: Wed Mar 08, 2006 6:25 pm
Posts: 3952
Ghost
если сохранять регистра в стеке то можно так:

Code:
   push ecx
   push edx
   push ebp
   mov ebp, esp
   push $+4   ;адрес возврата   ;2 байта ->|
   sysenter                     ;2 байта   |
;@@:                            ;       <--|
   pop ebp
   pop edx
   pop ecx


@@ и @F лучше не использовать или могут быть проблемы с другими метками в программе


адрес возврата будет в [ebp-4]
после загрузки правильного esp надо сохранить ebp в стеке
тогда для возврата
pop ecx ; ebp он же ring_3 esp
mov edx, [ecx-4]
sysexit


Top
   
 Post subject:
PostPosted: Sat Feb 24, 2007 9:46 pm 
Offline
Kernel Developer
User avatar

Joined: Mon Mar 20, 2006 10:44 am
Posts: 557
http://iam.gorodok.net/fc_ker.zip
Вот изменённые файлы для текущего ядра (#369) с добавленной функцией - заглушкой + тестовое приложение (test), оно выводит (на доску отладки) примерное количество тактов, затраченных на вызов в цикле 0x100000 раз фунции заглушки методом быстрого вызова и по прерыванию. У меня в среднем такие значения:

000000001F700000 <- Fast call
000000000E000000 <- Interrupt

И того сами вызовы дольше в два раза, т.е. каждый вызов примерно на 280 тактов дольше. Понятно что они вылазят в надбавках (теперь уже):

Code:
sysenter_entry:
   ; Настраиваем стек
   cli
   push   eax
   mov   eax, [ss:CURRENT_TASK]
   shl   eax, 8
   mov   eax, [ss:PROC_BASE + eax + APPDATA.pl0_stack]
   lea   esp, [ss:eax + RING0_STACK_SIZE]   ; configure ESP
   mov   eax, [ss:sysenter_stack - 4]      ; eax - original eax, from app
   sti
   ;------------------
   ...
   ;------------------
   mov   edx, [SYSENTER_VAR]      ; eip
   mov   ecx, [SYSENTER_VAR + 4]   ; esp
   sysexit


Но выигрыш от использывания быстрых вызовов ожидался больше... А может всё дело в моём AMD K7...

Проверьте кто может, и сообшите результаты.

P.S. Сохранение регистров пока оставил как было, переделаю на стек (это видимо лучший вариант т.к. в основном программы не хранят данные в [ESP - 4|8], и это будет прозрачно относительно варианта с прерыванием) + нормальное сохранение/передачу чегистров после того как скорость хотябы останется на уровне прерываний.

Про DS - в том месте кода DS - селектор кода программы, кстати замене сегмента много кушает? Если да то можно и попыхтеть над кодом.

Про Menuet OS, сколько можно тянуть его наследство? Ктонибудь мне обьяснит смысл переворачивания регистров? Да, уйти от этого не просто но с каждым месяцем API растёт и это становится ещё сложнее.
Или например :
Code:
pop   eax 
popad

в обработчике сис вызова? без этого конечно все смешения в возвр. регистрам изменятся, но тянуть этот баласт тоже не дело. Или я не прав?

_________________
Сейчас я слушаю : Image


Top
   
 Post subject:
PostPosted: Sat Feb 24, 2007 11:43 pm 
Offline
Kernel Developer

Joined: Wed Mar 08, 2006 6:25 pm
Posts: 3952
Ghost

У меня было тоже самое. Проверял разные варианты, запрещал прерывание и отключал кеш, нифига не помогло. Прерывание работало в два раза быстрее. Тогда начал читать описание команд и вспомнил почему не стал их делать.
Ржал полчаса.
Команды расчитаны на плоскую память и устанавливают базу сегментов в 0 а у приложений база 0х60400000.
Происходит страничная ошибка с нарушением права доступа и в дело вступает обработчик страничных ошибок. Но он не обрабатывает такие ошибки потому что их никогда не возникало. Поэтому он просто возвращает управление назад. Из стека загружаются сохранённые сегментные регистры и на этот раз там правильные значения и программа продолжает работу.
Во всёи есть один положительный момент. Защита ядра таблицами страниц работает правильно. Надо залить код на SVN. Я закончил драйвер и скоро выложу ядро с новым распределением памяти под плоскую модель.
Можно будет сделать пробную "плоскую" версию и проверить ещё раз.


Top
   
 Post subject:
PostPosted: Sun Feb 25, 2007 12:03 am 
Offline
Kernel Developer
User avatar

Joined: Mon Mar 20, 2006 10:44 am
Posts: 557
Хех. Буду ждать "плоскую" версию.

По поводу SVN : куда лить? В trunk вроде этому коду пока не место, в branches - тоже не особо, изменений не много.

Думаю плоскую версию ты в branches выложиш, туда и вызовы пойдут, а пока допишу сохранение регистров на текущем ядре, отпишусь здесь.

Ещё есть идея про SEH (Structured|Sexual Exception Handler), он и компиллерам (C/C++ - try/catch, etc) на пользу пойдёт и несуществуюший КОП обойти позволит, но это только идея :)


Top
   
 Post subject:
PostPosted: Sun Feb 25, 2007 9:39 am 
Offline
Kernel Developer

Joined: Wed Mar 08, 2006 6:25 pm
Posts: 3952
Ghost
Пиши в транк. Код хороший и уже работает :) Можно обкатать разные варианты вызовов и макросов. У АМД есть своя пара syscal/sysret. Они ее делали позже Интел и продумана она лучше. Тоже стоит добавить.
> несуществуюший КОП обойти позволит
Что такое КОП ?


Top
   
 Post subject:
PostPosted: Sun Feb 25, 2007 2:11 pm 
Offline
Kernel Developer
User avatar

Joined: Mon Mar 20, 2006 10:44 am
Posts: 557
КОП - Код ОПерации (OpCode)

Дописать поддержку SYSCALL/SYSRET не сложно, вызовы должны даже проше выглядеть, т.к. EIP автоматом копируется в ECX, а заморочек с ESP вообше нет. Но пока остается проблема с нулевой базой:

A new descriptor is loaded for CS to specify a fixed 4-Gbyte flat segment as follows:
- The CS_base is set to zero.
- The CS_limit is set to 4 Gbyte.
- The CS segment attributes are set to Read-only.

Сегодня - завтра напишу код, надеюсь что он хоть и со страничными нарушениями, но будет работать.


Top
   
 Post subject:
PostPosted: Sun Feb 25, 2007 5:23 pm 
Offline
Kernel Developer
User avatar

Joined: Mon Mar 20, 2006 10:44 am
Posts: 557
Добавил SYSCALL/SYSRET, кое как работают.
Всё на SVN

Вызов через SYSENTER, вместо int 0x40:
Code:
SYSENTER_VAR   equ   0
   mov   dword[SYSENTER_VAR], @f
   mov   [SYSENTER_VAR + 4], esp
   sysenter      ; портятся ecx, edx
@@:


Вызов через SYSCALL, вместо int 0x40:
Code:
   push   ecx
   syscall
   pop   ecx


Top
   
 Post subject:
PostPosted: Tue Feb 27, 2007 9:00 am 
Offline
Kernel Optimizer
User avatar

Joined: Mon Jan 16, 2006 7:58 pm
Posts: 657
У меня в эмуляторе VMWARE 5.5.0
E42093F49 <-Fast call
143B6C251 <- Interrupt


Top
   
 Post subject:
PostPosted: Tue Feb 27, 2007 3:39 pm 
Offline
User avatar

Joined: Fri Jan 27, 2006 3:06 pm
Posts: 1071
На реальной машине с ядром 378:
Image


Last edited by Heavyiron on Fri Oct 10, 2008 1:02 am, edited 1 time in total.

Top
   
Display posts from previous:  Sort by  
Post new topic  Reply to topic  [ 145 posts ]  Go to page 1 2 3 4 510 Next

All times are UTC+03:00


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Limited