maisvendoo писал(а):
Поковырялся сейчас в отладке. Стек ползет на всех потоках, и это из-за того что я прыгаю на следующий поток прямо из обработчика, и при повторном входе в прерывание просходит снова проталкивание ряда значений в стек, а выталкивание их обходится этим моим джампом.
Ну так не обходи выталкивание.
Цитата:
Основная идея твоего алгоритма в том что при выходе из обработчика IRQ0 в EIP выталкивается адрес инструкции в следующем потоке из очереди, как я понимаю. Хотелось бы просто по пунктам этот алгоритм разобрать: вот произошло прерывание таймера и что необходимо сделать чтобы перескочить на новую задачу
Наверно можно сделать и при выходе, но я сделал "посередине", чтобы иметь возможность обращаться к переключалке на любом уровне вложенности подпрограмм, причем не только внутри обработчика, но и за его пределами, что нужно в реальной системе. Я давал ссылку на место, где опубликован код. Он очень короткий, к тому же часть его закомментирована (а кое-что я вообще не стал писать, например, загрузку в cr3, потому что это добавить элементарно).
Код переключалки:
Код:
proc SwitchToNext ; cs=KCODE, ds=es=ss=KDATA
push fs
push gs
pushf
cli
; раскомментируйте, если не хотите получать [current] на входе в подпрограмму
; mov eax,[current]
mov [eax+TS.stackpointer],esp
mov eax,[eax+TS.next]
mov esp,[eax+TS.stackpointer]
mov [current],eax
popf
pop gs
pop fs
ret
Как видно, имеем простой кадр возобновления:
Код:
TS-04: стартовый адрес возобновления
TS-08: FS
TS-12: GS
TS-16: EFLAGS
TS читай пока, как "вершина стека". Если вы используете [current] в качестве входного параметра и передаете его в стеке (а не в eax, как предполагает мой код), добавьте его в конец кадра (под TS). Если в прологе сишной функции что-то сохраняется в стеке, это тоже нужно добавить в кадр. Перед первым запуском потока этот кадр нужно сформировать в его стеке "вручную" (stackpointer должен указывать на его начало, т.е. быть равным TS-16), потом он будет формироваться автоматически (при обращении к переключалке).
Примерный код обработчика:
Код:
proc IRQ0Handler
pusha
push ds
push es
push ss
pop ds ; ds <- KDATA
push ss
pop es ; es <- KDATA
mov al,20h
out 20h,al
mov eax,[current]
call SwitchToNext
pop es
pop ds
popa
iret
Обратите внимание, что pusha/popa нужно не для переключения, а для самого обработчика (реальный обработчик может быть значительно сложнее; эти команды просто сохраняют регистровый контекст прерванного кода). Также обратите внимание, что выполнение EOI должно происходить перед обращением к переключалке (после переключения на новую задачу мы можем оказаться не в обработчике, т.е. мы могли бы потерять EOI на длительное время, если бы разместили код для EOI после обращения к переключалке).
Чтобы это все работало на прикладном уровне, нужно разместить структуру потока (TS) в вершине стека, а current совместить с TSS.esp0.