Значит занимаюсь я сейчас переносом одной промышленной ОС реального времени на новую платформу и по ходу дела наткнулся на страшный и непонятный мне баг, с которым я ничего не могу поделать. Сам баг: при попытке сделать ожидание больше 30мс приводит к срыву башни у процессора. Он фактически начинает пропускать вызов функцй, или возвращать неверные значения, в регистрах, стеке и локальных переменных начинает творится чёрти что. И причем ничего этого за хвост схватить нельзя т.к. единственное средство отладки - это вывод на экран, который после бага тоже начинает работать так: "хочу вывожу, хочу - не вывожу" (вывод на прямую в видеопамять). Т.е. ничего толком и не проверить. Функция задержки - написана вручную, код внизу сообщения. Место в оси: баг происходит ДО захода в реальное время. Т.е. диспетчер задач уже включен, но он следит за временем только тасков, а место, в котором я словил баг - это первичная настройка и инициализация всякой системной фигни, и она происходит не в реальном времени. Т.е. за ней диспетчер не следит. Никаких других потоков кроме этого не запущено. Обработчик прерываний - асинхронный. т.е. не считается потоком. Фактически баг происходит в одной единственной нити кода и что тут может сломаться на пустом месте из за обычного ожидания - кардинально неясно. Что я пробовал: 1) отключал прерывания перед запуском ожидания (и через cli и 21 порт) 2) отрубал обработчик прерываний системного таймера нашей оси 3) заменял функцию ожидания на простые операции умножения (ну малоли функция косячит) ничего не помогло. Вот функция ожидания, но я уверен что проблема совсем не в ней. Я склоняюсь что косяк из за прерываний от системного таймера (т.к. всё остальное я вроде убивал). Код (Text): void Delay( WORD Msec ) { DWORD i; DWORD TicksToWaitlo; DWORD TicksToWaithi; DWORD Ticks1lo; DWORD Ticks1hi; DWORD Ticks2lo; DWORD Ticks2hi; TicksToWaitlo = (DWORD)Msec * ((DWORD)SysCpuFreqMhz * 1000L); TicksToWaithi = 0; Ticks1lo = 0; Ticks1hi = 0; Ticks2lo = 0; Ticks2hi = 0; if ( Msec <= 0 ) return; asm db 0x0f, 0x31 //rdtsc asm db 0x66 asm mov word ptr Ticks1lo, ax asm db 0x66 asm mov word ptr Ticks1hi, dx while ( 1 ) { asm db 0x0f, 0x31 //rdtsc asm db 0x66 asm mov word ptr Ticks2lo, ax asm db 0x66 asm mov word ptr Ticks2hi, dx if ( ( (Ticks2hi - Ticks1hi) >= TicksToWaithi ) && ( (Ticks2lo - Ticks1lo) >= TicksToWaitlo ) ) return; } }
Arisu А не может эта ось использовать какой-нить там таймер ACPI или ещё что-нибудь в этом роде, и при больших задержках просто-напросто не отрабатывать какие-то действия вовремя?
я ещё не досконально изучил систему, но как я уже писал выше: к моменту где мне нужно сделать задержку - ни одина из задач, которые критичны ко времени ещё не запущины. Да, есть диспетчер, но он ничего не делает т.к. его очередь пуста. И потом любое нарушение реального времени в этой системе приводит к безопасному необратимому состоянию, но никак не к каше в регистрах и стеке
Arisu Ну так ACPI используется и при инициализации системы, а не только при обычной работе... А вообще гадать тяжело, даже если имеется кофейная гуща
Код (Text): asm db 0x66 asm mov word ptr Ticks2lo, ax asm db 0x66 asm mov word ptr Ticks2hi, dx Ну на подобном "коде" любое глюкалово возможно
на нём родимом ))). ось 16-и битная, как вы уже догадались. ну да. в принципе тонны чужого кода без комментариев и какой либо документации именно кофейную гущу и напоминает ). но мне нужно заставить это работать. я пока только придумал как мне избежать задержки в 30мс в том месте и проскочить дальше. Но в итоге эта система перестанет называтся "отказоустойчивой" и "повышенной стабильности" )) т.к. в ней будет жить баг, который может никогда и не пройзойдёт, но он там будет.
Я бы на всякий случай мэджик с rdtsc вынес в отдельную функцию. И глянул бы дизасм кода. Благо Borland C 3.1 умеет генерить асмовый код. А перед rdtsc и после сохранения значения сделал бы pusha/popa.
SadKo асм код я смотрел. там всё вроде бы логично. регистры сохранять попробую конечно, ведь я меняю старшую часть и потом она может где-то "всплыть", но как я уже писал выше - не важно как устроена задержка. Даже если это простые математические операции - система всё равно рушится на глазах. SII ОС использует только системный таймер. ACPI таймера нет.
арси.. а што за компиль какими ключами компилишь на какой тачке проверяешь.. походу с кодом все хорошо..
Посмотри. Может, где счётчик какой переполняется. Может стек. Пожет имеет место повторная входимость в прерывания.
Хм... для 16-битново сакса BCC 5.0 компиль сделал весьма хороший код, мну ево немонжко видоизменил чтоб заюзать в комовом сэмпле. Видимо проблема можит крыццо, в использовании в некоторых местах межсегменных длинных сall-ов, а подпрогамма делает вмест retf делает retn... Тут да вэлкам то глюкалово не снившийся даже в протектед моде.. а! вота код: Код (Text): .model tiny .386 .code @Delay proc ;far ; AX DX ; void _fastcall Delay(WORD Msec, WORD SysCpuFreqMhz) ; push bp mov bp,sp sub sp,26 push si push di mov word ptr [bp-2],ax mov cx,dx ; ; { ; ; DWORD i; ; DWORD TicksToWaitlo; ; DWORD TicksToWaithi; ; DWORD Ticks1lo; ; DWORD Ticks1hi; ; DWORD Ticks2lo; ; DWORD Ticks2hi; ; ; ; TicksToWaitlo = (DWORD)Msec * ((DWORD)SysCpuFreqMhz * 1000L); ; movzx edx,cx movzx ebx,word ptr [bp-2] imul edx,ebx imul edx,large 1000 mov dword ptr [bp-6],edx ; ; TicksToWaithi = 0; ; mov dword ptr [bp-10],large 0 ; ; Ticks1lo = 0; ; mov dword ptr [bp-14],large 0 ; ; Ticks1hi = 0; ; mov dword ptr [bp-18],large 0 ; ; Ticks2lo = 0; ; mov dword ptr [bp-22],large 0 ; ; Ticks2hi = 0; ; mov dword ptr [bp-26],large 0 ; ; ; if ( Msec <= 0 ) return; ; cmp word ptr [bp-2],0 jbe short @1@14 ; ; ; asm db 0x0f, 0x31 //rdtsc ; db 00fH, 031H ; ; asm db 0x66 ; db 066H ; ; asm mov word ptr Ticks1lo, ax ; mov word ptr [bp-14], ax ; ; asm db 0x66 ; db 066H ; ; asm mov word ptr Ticks1hi, dx ; mov word ptr [bp-18], dx @1@7: ; ; ; while ( 1 ) { ; asm db 0x0f, 0x31 //rdtsc ; db 00fH, 031H ; ; asm db 0x66 ; db 066H ; ; asm mov word ptr Ticks2lo, ax ; mov word ptr [bp-22], ax ; ; asm db 0x66 ; db 066H ; ; asm mov word ptr Ticks2hi, dx ; mov word ptr [bp-26], dx ; ; ; if ( ( (Ticks2hi - Ticks1hi) >= TicksToWaithi ) && ; ; ; ( (Ticks2lo - Ticks1lo) >= TicksToWaitlo ) )return; ; mov edx,dword ptr [bp-26] sub edx,dword ptr [bp-18] cmp edx,dword ptr [bp-10] jb short @1@7 mov edx,dword ptr [bp-22] sub edx,dword ptr [bp-14] cmp edx,dword ptr [bp-6] jb short @1@7 @1@14: ; ; } ; } ; pop di pop si leave ret @Delay endp start: mov ax, 1000h mov dx, 1000h call @Delay mov ax, 4C00h int 21h end start Возможно что лутшим решенеем будет использование Watcom C, так как компилял глюкаловом от бордель-янда, FreeDOS... Таг бы мош и все бы ничево, тока FAT32 драйвером пофигачились все данные на винту... Когда как тот же релиз на Watcome, работает очень стабильно. Мну бы дажи сказал - пуленепробиваемо.. оть...
В языках высокого уровня сохраняй регистры перед использованием их в коде на асме. Код (Text): Код: void Delay( WORD Msec ) { DWORD i; DWORD TicksToWaitlo; DWORD TicksToWaithi; DWORD Ticks1lo; DWORD Ticks1hi; DWORD Ticks2lo; DWORD Ticks2hi; TicksToWaitlo = (DWORD)Msec * ((DWORD)SysCpuFreqMhz * 1000L); TicksToWaithi = 0; Ticks1lo = 0; Ticks1hi = 0; Ticks2lo = 0; Ticks2hi = 0; if ( Msec <= 0 ) return; asm db 0x66 ;<--- asm push ax ;<--- asm db 0x66 ;<--- asm push dx ;<--- asm db 0x0f, 0x31 //rdtsc asm db 0x66 asm mov word ptr Ticks1lo, ax asm db 0x66 asm mov word ptr Ticks1hi, dx asm db 0x66 ;<--- asm pop dx ;<--- asm db 0x66 ;<--- asm pop ax ;<--- while ( 1 ) { asm db 0x66 ;<--- asm push ax ;<--- asm db 0x66 ;<--- asm push dx ;<--- asm db 0x0f, 0x31 //rdtsc asm db 0x66 asm mov word ptr Ticks2lo, ax asm db 0x66 asm mov word ptr Ticks2hi, dx asm db 0x66 ;<--- asm pop dx ;<--- asm db 0x66 ;<--- asm pop ax ;<--- if ( ( (Ticks2hi - Ticks1hi) >= TicksToWaithi ) && ( (Ticks2lo - Ticks1lo) >= TicksToWaitlo ) ) return; } }