Задача вызывается через шлюз задачи в IDT, подскажите причину генерации #GP Дескрипторы первой и второй задач в GDT: dd 0x89000067,metatts ;P=1b, DPL=00b, S=0b,Type=1001b, G=D/B=L=AVL=0b, LIMIT=0x67, BASE=metatts dd 0x89000067,debugtts ;BASE=debugtts TSS 1ой задачи инициализирован: label metatts db 0x68 dup 0x0 TSS 2ой задачи: label debugtts dd 0x0 ;selecter of oldtask dd 0x0,0x18,0x0,0x0,0x0,0x0 ;00(esp,ss),01(esp,ss),10(esp,ss) dd 0x0 ;cr3 dd dDBtone ;eip dd 0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 ;eflags,eax,ecx,edx,ebx,esp,ebp,esi,edi dd 0x20,0x08,0x18,0x10,0x0,0x0 ;es,cs,ss,ds,fs,gs dd 0x0 ;ldtr dd 0x0 ;iobm TSS 1ой задачи грузится в TS: ltr 0x28 ;селектор 1й задачи 2я задача: dDBtone: nop iret Вызывается int 0x30 Дескриптор в IDT: dw 0x0,0x30,0x85,0x0 ;0x30 - селектор 2й задачи, P=0b, GDPL=00b, S=0b, TYPE=0101b После выполнения int 0x30, до начала работы кода вызываемой задачи возникает #GP.
Причем при вызове 2ой задачи напрямую: call 0x30:0x0 задача отрабатывает, возвращает управление, а потом уходит в перезагрузку при любых манипуляциях со стеком. Дескриптор стека: dd 0x96cffffe,mainstack ;P=1b, DPL=00b, S=1b, TYPE=E=W=1b, A=0b, G=D/B=1b, L=AVL=0b, LIMIT=mainstack Находится: org 0x10000 label mainstack на момент вызова 2ой задачи esp=0xfffffff0 Подскажите, пожалуйста, где я ошибся.
#GP было из-за ошибки описания шлюза. Код и тип ошибки пока не знаю - управление возвращается 1ой задаче, код выполняется, и перезагружается при любых манипуляциях со стеком. Практически весь значащий код я привел. А полностью, за исключением обработчиков ошибок (которые нужно - чистят стек, все пищат динамиком и iretd), кроме #GP и обработчиков прерываний, те тоже пустые, только сбрасывают запрос (eoi: \\ push ax \\ mov al,0x20 \\ out 0x20,al \\ out 0xa0,al \\ pop ax \\ iretd), код ниже. org 0x7c00 use16 ent: ;загружаемся с дискеты mov ax,cs mov ds,ax mov es,ax mov ss,ax mov sp,ent mov bp,sp mov ax,0x4f02 mov bx,0x4117 int 0x10 mov ah,0x2 mov al,0x11 xor ch,ch mov cl,0x2 xor dx,dx mov bx,ent+0x200 int 0x13 jnc coload mov ax,0x3 int 0x10 mov ax,0xb800 mov es,ax mov eax,0x8f458f52 mov dword[es:0x0],eax jmp $ dw 0xaa55 ;переходим в PM coload: in al,0x92 or al,0x2 out 0x92,al cli in al,0x70 or al,0x80 out 0x70,al lgdt fword[gdtr] lidt fword[idtr] mov eax,cr0 or al,0x1 mov cr0,eax jmp 0x08:pmentry use32 pmentry: mov ax,0x10 mov ds,ax mov ax,0x18 mov ss,ax mov ax,0x20 mov es,ax mov al,0x11 out 0x20,al out 0xa0,al mov al,0x20 out 0x21,al mov al,0x28 out 0xa1,al mov al,0x04 out 0x21,al mov al,0x02 out 0xa1,al mov al,0x1 out 0x21,al out 0xa1,al mov al,0x0 out 0x21,al out 0xa1,al in al,0x70 and al,0x7f out 0x70,al sti mov eax,cr4 or eax,0x200 mov cr4,eax ;переходим в 1ю задачу xor esp,esp mov ax,0x28 ltr ax ;грузим битовые маски символов cli mov dx,0xfc04 mov eax,prdt out dx,eax mov dx,0xfc00 in al,dx or al,0x8 out dx,al mov dx,0xfc02 or al,0xff out dx,al mov dx,0x3f6 @@: in al,dx and al,0x80 xor al,0x80 jz @r mov dx,0x1f6 xor al,al out dx,al mov dx,0x3f6 @@: in al,dx and al,0xc0 xor al,0x40 jnz @r mov dx,0x1f1 xor al,al out dx,al inc dx mov al,0x79 out dx,al inc dx mov al,0xe9 out dx,al inc dx mov al,0x9e out dx,al inc dx mov al,0x73 out dx,al inc dx mov al,0xe4 out dx,al inc dx mov al,0xc8 out dx,al mov dx,0xfc00 in al,dx or al,0x1 out dx,al mov dx,0xfc02 @@: in al,dx and al,0x4 xor al,0x4 jnz @r mov dx,0xfc00 in al,dx xor al,0x1 out dx,al mov dx,0xfc02 in al,dx and al,0x2 xor al,0x2 jz .error mov dx,0x1f7 in al,dx and al,0x1 xor al,0x1 jz .error sti jmp .go .error: mov al,0x07 out 0x43,al mov al,0xf0 out 0x42,al mov al,0x11 out 0x42,al in al,0x61 or al,0x3 out 0x61,al mov eax,0x10000000 @@: dec eax jnz @r in al,0x61 and al,0xfc out 0x61,al mov eax,0x4f000000 @@: dec eax jnz @r sti @@: hlt jmp @r .go: int 0x30 ;вызываем 2ю задачу mov cl,0x3 .repton_to: mov al,0xb6 out 0x43,al mov al,0x5b out 0x42,al mov al,0x10 out 0x42,al in al,0x61 or al,0x3 out 0x61,al mov eax,0x9000000 @@: dec eax jnz @r in al,0x61 and al,0xfc out 0x61,al mov eax,0xf00000 @@: dec eax jnz @r dec cl jnz .repton_to push 0x0 .goto: hlt jmp .goto ;системные таблицы use32 align 0x8 label gdt db 0x8 dup 0x0 dd 0x9ac0001a,0x0 ;код dd 0x92cfffff,0x0 ;данные dd 0x96cffffe,mainstack ;стек dd 0x92c00185,0xd0000000 ;video dd 0x89000067,metatts ;1я задача dd 0x89000067,debugtts ;2я задача intermixgdt gdtsz=$-gdt label gdtr dw gdtsz-1 dd gdt label idt dw dDE,0x0,0x0,0x0 dw dDB,0x8,0x8e00,0x0 dw NMI,0x0,0x0,0x0 dw dBP,0x8,0x8e00,0x0 dw dOF,0x0,0x0,0x0 dw dBR,0x0,0x0,0x0 dw dUD,0x0,0x0,0x0 dw dNM,0x0,0x0,0x0 dw dDF,0x0,0x0,0x0 dw 0x0,0x0,0x0,0x0 dw dTS,0x0,0x0,0x0 dw dNP,0x0,0x0,0x0 dw dSS,0x0,0x0,0x0 dw dGP,0x8,0x8e00,0x0 dw dPF,0x0,0x0,0x0 dw 0x0,0x0,0x0,0x0 dw dMF,0x0,0x0,0x0 dw dAC,0x0,0x0,0x0 dw dMC,0x0,0x0,0x0 dd 0x1a dup 0x0 dw IRQ00,0x8,0x8e00,0x0 dw irq01,0x8,0x8e00,0x0 dw IRQ02,0x8,0x8e00,0x0 dw IRQ08,0x8,0x8e00,0x0 dw IRQ09,0x8,0x8e00,0x0 dw IRQ0A,0x8,0x8e00,0x0 dw IRQ0B,0x8,0x8e00,0x0 dw IRQ0C,0x8,0x8e00,0x0 dw IRQ0D,0x8,0x8e00,0x0 dw IRQ0E,0x8,0x8e00,0x0 dw IRQ0F,0x8,0x8e00,0x0 dw IRQ03,0x8,0x8e00,0x0 dw IRQ04,0x8,0x8e00,0x0 dw IRQ05,0x8,0x8e00,0x0 dw IRQ06,0x8,0x8e00,0x0 dw IRQ07,0x8,0x8e00,0x0 dw 0x0,0x30,0x8500,0x0;шлюз 2ой задачи idtsz=$-idt label idtr dw idtsz-1 dd idt label rmidtr dw 0x3ff dd 0x0 align 0x4 label prdt dd charmap dw 0x0 dw 0x8000 label metatts ;1я задача db 0x68 dup 0x0 label debugtts ;2я задача dd 0x0 ;selecter of oldtask dd 0x0,0x18,0x0,0x0,0x0,0x0 ;00(esp,ss),01(esp,ss),10(esp,ss) dd 0x0 ;cr3 dd dDBtone ;eip dd 0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 ;eflags,eax,ecx,edx,ebx,esp,ebp,esi,edi dd 0x20,0x08,0x18,0x10,0x0,0x0 ;es,cs,ss,ds,fs,gs dd 0x0 ;ldtr dd 0x0 ;iobm ;2я задача dDBtone: mov cl,0x3 .repton: mov al,0xb6 out 0x43,al mov al,0x4b out 0x42,al mov al,0x05 out 0x42,al in al,0x61 or al,0x3 out 0x61,al mov eax,0xd000000 @@: dec eax jnz @r in al,0x61 and al,0xfc out 0x61,al mov eax,0xf00000 @@: dec eax jnz @r dec cl jnz .repton iret ;обработчик #GP dGP: push ecx push ebx mov edi,0xfe00 xor ecx,ecx xor ebx,ebx std @@: mov bl,byte[edi+ecx] xor eax,eax ror bl,0x4 mov al,bl and al,0x0f cmp al,0xa sbb al,0x69 das shr bl,0x4 call drawchar xor eax,eax mov al,bl cmp al,0xa sbb al,0x69 das call drawchar inc ecx cmp ecx,0x200 jnz @r pop ebx pop ecx @@: hlt ;выводим символ на экран drawchar: push eax push edi push edx push ebx push ecx sub al,0x20 xor edi,edi mov ah,al xor al,al mov edx,dword[lastposition] lea ebx,[charmap+eax*0x4] mov ecx,0x20 xor eax,eax align 0x4 @@: db 0x26,0x0f,0x28,0x04,0x17;movapd xmm0,dqword[es:edi+edx] align 0x4 db 0x26,0x0f,0x28,0x4c,0x17,0x10;movapd xmm1,dqword[es:edi+edx+0x10] align 0x4 db 0x0f,0x57,0x4,0x03;xorpd xmm0,dqword[ds:ebx+eax] align 0x4 db 0x0f,0x57,0x4c,0x03,0x10;xorpd xmm1,dqword[ds:ebx+eax+0x10] align 0x4 db 0x26,0x0f,0x2b,0x04,0x17;movntpd dqword[es:edi+edx],xmm0 align 0x4 db 0x26,0x0f,0x2b,0x4c,0x17,0x10;movntpd dqword[es:edi+edx+0x10],xmm1 dec ecx lea edi,[edi+0x800] lea eax,[eax+0x20] jnz @r lea eax,[edx+0x20] and dx,0x7e0 xor dx,0x7e0 jnz @f lea eax,[eax+0xf800] @@: mov dword[lastposition],eax pop ecx pop ebx pop edx pop edi pop eax ret ;данные lastposition dd 0x0 scantable db 0x0,0x0,'1','2','3','4','5','6','7','8','9','0' db 0x4 dup 0x3a db 'Q','W','E','R','T','Y','U','I','O','P' db 0x4 dup 0x3a db 'A','S','D','F','G','H','J','K','L' db 0x5 dup 0x3a db 'Z','X','C','V','B','N','M',',','.','/' db 0x3 dup 0x3a db ' ' db 0x94 dup 0x3a ;область стек org 0x10000 label mainstack ;область битовых масок org 0x100000 label charmap ;макрос переформирования gdt macro intermixgdt { repeat ($-gdt)/0x8 ere=$-(%-0x1)*0x8 load gsl19..16 byte from ere-0x6 load access byte from ere-0x5 load base15..0 word from ere-0x4 load base23..16 byte from ere-0x2 store word base15..0 at ere-0x6 store byte base23..16 at ere-0x4 store byte access at ere-0x3 store byte gsl19..16 at ere-0x2 end repeat }
ciril Настоятельно рекомендую поставить эмулятор Bochs и работать с ним. Например, в данном случае Bochs пишет в bochsout.txt вполне приличный лог, из которого нетрудно понять, что происходит: А можно даже включить отладочный вывод: Конкретно в данном случае ss=0x28, указанный в TSS второй задачи, ну никак не является валидным сегментом данных. А дальше - #TS, #GP и triple fault aka reboot.
Mika0x65] Так меньшее смещение в стеке32 = 0xfffffffc, вот и обнуляю, чтобы адресовал, хотя это кажется лишнее, стек 1й задачи работает в обоих случаях, и при комментировании xor esp,esp , смотрел дампом. На общую неработоспособность это не влияет. Выяснил, что если во 2й задаче использовать команды SSE, то #GP (проверил xorpd xmm0,xmm0). При запуске также возникала #GP, что удалось исправить установкой CR4.OSFXSR=1b, но ведь сейчас он установлен. diamond Моя ошибка при копировании текста, потом отредактированная, в коде 0x18.
diamond А как получается, что ss = 0x28? По коду он, вроде, 0х18: Код (Text): label debugtts ;2я задача dd 0x0 ;selecter of oldtask dd 0x0,0x18,0x0,0x0,0x0,0x0 ;00(esp,ss),01(esp,ss),10(esp,ss) dd 0x0 ;cr3 dd dDBtone ;eip dd 0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 ;eflags,eax,ecx,edx,ebx,esp,ebp,esi,edi dd 0x20,0x08,0x18,0x10,0x0,0x0 ;es,cs,ss,ds,fs,gs <---------здесь. dd 0x0 ;ldtr dd 0x0 ;iobm И у первой задачи тоже: Код (Text): mov ax,0x18 mov ss,ax Больше упоминаний ss, вроде, нет. Bochs на этом компьютере не стоит, смотрел на глаз. Update: А, понятно, я видел уже отредактированную версию.
Сам поправляюсь, после переключения на 2ю задачу, генерируется #GP при использовании любых команд SSE. Все остальные команды, в том числе и операций со стеком - допустимы.
ciril Что-то я не понял -- работает, или нет? И не пересекаются ли стеки задач? Заодно: чтобы вызвать вторую задачу повторно, надо после iret поставить jmp на начало задачи, т.к. после возврата из нее eip будет ссылаться на инструкцию после iret. Вручную копировал?! Update: Черт, опять пока набирал сообщение уже ответ пришел .
Есть работа до первого переключения задач с 1й задачи на вторую, и после. До момента первого переключения все работает, то есть работает 1я задача вне зависимости от того обнуляем ли esp, после все не работает также вне зависимости от обнуления. У меня было с разными стеками на обе задачи, а вставлял с общим, на неработоспособность это не влияет. Когда с разными, то нет: org 0x10000 label mainstack org 0x11000 label debugstack Ну и в поле ss TSS 2й задачи соответственно селектор 0x38, то есть дескриптора debugstack'a И повторюсь: после первого переключения возникает #GP при обращении к командам SSE, причем как в случае вызова (например) xorpd xmm0,xmm0 во 2й задаче, так и при вызове xorpd xmm0,xmm0 в 1й задаче после возврата управления 2ой задачью.
Если я правильно помню, так и должно быть: переключение задач устанавливает бит в cr0, что, мол, задача переключилась, а потом все FPU/MMX/SSE-команды фолтят, если этот бит установлен. Точнее, они вызывают #NM, но поскольку в IDT обработчик #NM помечен как отсутствующий, то вызывается #GP. Сделано это в расчёте на следующее: каждая задача может иметь свой набор регистров, как cpu, так и fpu/xmm; но регистры cpu используют абсолютно все задачи, и эти регистры сохраняются в TSS автоматически, а fpu/xmm - уже далеко не все, и для экономии времени они не сохраняются. Но чтобы вторая задача не работала с регистрами первой, предназначено исключение #NM: его обработчик должен сохранить fpu/xmm-регистры для старой задачи, загрузить для новой, сбросить бит TS в cr0 (для этого даже есть специальная команда clts) и вернуть управление.
ciril Похоже, как-то путано объяснил... короче, команда "clts" должна спасти отца русской демократии.
diamond Да)) Только можно узнать, откуда сведения? У Интела в описании #NM Vol3A 5.3.1 Table 5-1: Floating-point or WAIT/FWAIT instruction. А о переключении задач там же, Chater 6, Table 6-1 такого исключения при переключении задач нет. О том что CRO.TS и #NM связаны я не нашел. Или не там читал?
В мануалах AMD это сказано в первом томе, раздел 4.10 "128-Bit Media and Scientific Programming" -> "Exceptions": В мануалах Intel это тоже есть в первом томе, раздел 12.8 "Programming with SSE3, SSSE3 and SSE4" -> "SSE3/SSSE3, and SSE4 Exceptions" (в той версии, которая есть у меня; в более старых или более новых номер раздела, скорее всего, другой): Кроме первого тома, это легко найти так: в описании каждой инструкции сказано, какие исключения она может вызвать. (Второй том Интела, третий-пятый AMD.) К примеру, из описания xorpd:
Небольшое дополнение, пусть и не совсем применительно к данной теме. Если в CR0 установлен бит EM, то при выполнении FPU/MMX/SSE инструкции также имеем исключение - в случае FPU - #NM, в случае MMX и SSE(за небольшим исключением) - #UD.