Здравствуйте! Я вот написал такой MBR - он считывает текущую минуту, секунду, час, месяц, день месяца, год из CMOS в память начиная с 7c03h. Затем используя int 13h я обновляю нулевой сектор. Т.е. теперь в памяти и в нулевом секторе у меня хранится считанная дата. И потом читаю с дисков Master\Slave\Primary\Secondary нулевой сектор и сверяю дату в них с датой которая лежит в памяти, если они равны - то этот диск активный, но вот что-то нифига не получается, при опросе дисков через порты я не стал измерять время для того чтобы не повесить прогу в бесконечном ожидании несуществующего диска, я просто взял цикл который повторяется 100 раз. И он у меня постоянно выходит с ошибкой таймаута. А задумано было так - код находит активный диск (процедура проверки делает mov dh,0ffh) и на экран выводится адрес порта и номер диска на канале. Ткните пожалуйста пальцем где я допустил ошибку. Код (Text): .386 code segment para public "code" use16 main proc assume cs:code,ss:stk org 7c00h jmp MBR_2_start ;-------------------- Данные -------------------- Stek_Adress equ 0600h ; адрес стэка MBR_2_Data db 0,0,0,0,0,0,0 ; секунда, минута, час, день месяца, месяц, год, век MBR_2_Aktiv db 1 ; индекс активного тома MBR_2_Tom1 db 0, 0, 0, 0, 0, 64h ; адрес (LBA) заголовка тома 1 MBR_2_Tom1_Razm db 0 ; размер ядра тома 1 MBR_2_Tom2 db 6 dup(0) ; адрес (LBA) заголовка тома 2 MBR_2_Tom2_Razm db 0 ; размер ядра тома 2 MBR_2_Tom3 db 6 dup(0) ; адрес (LBA) заголовка тома 3 MBR_2_Tom3_Razm db 0 ; размер ядра тома 3 MBR_2_Tom4 db 6 dup(0) ; адрес (LBA) заголовка тома 4 MBR_2_Tom4_Razm db 0 ; размер ядра тома 4 MBR_2_Port dw 0 ; порт активного диска MBR_2_Disk db 0 ; 0 - Primary, 1 - Secondary диск MBR_2_SecCol db 1 ; число секторов для чтения MBR_2_Cikl db 0 ; счетчик цикла ;------------------------------------------------ MBR_2_start: mov ax,0 ;---- mov ds,ax ; mov ss,ax ; mov ax,Stek_Adress ; Настраиваем сегментные регистры mov sp,ax ; xor ax,ax ; mov es,ax ;---- mov ax,0201h ;---- mov cx,0002h ; mov dx,0080h ; Код MBR не влез в один сектор, подгрузим оставшуюся часть mov bx,7e00h ; int 13h ;---- ;-------------- Считываем тукещую дату ---------------- mov al,00h ;- out 70h,al ; секунда in ax,71h ; mov byte ptr MBR_2_Data,al ;- mov al,02h ; минута out 70h,al ; in ax,71h ; mov byte ptr MBR_2_Data + 1,al ;- mov al,04h ; час out 70h,al ; in ax,71h ; mov byte ptr MBR_2_Data + 2,al ;- mov al,07h ; день месяца out 70h,al ; in ax,71h ; mov byte ptr MBR_2_Data + 3,al ;- mov al,08h ; месяц out 70h,al ; in ax,71h ; mov byte ptr MBR_2_Data + 4,al ;- mov al,09h ; год out 70h,al ; in ax,71h ; mov byte ptr MBR_2_Data + 5,al ;- mov al,32h ; век out 70h,al ; in ax,71h ; mov byte ptr MBR_2_Data + 6,al ;- ;------------------------------------------------------ ;------------------- Обновляем MBR -------------------- xor ax,ax mov es,ax mov ax,0301h mov cx,0001h mov dx,0080h mov bx,7c00h int 13h ;------------------------------------------------------ jmp MBR_2_next1 ;------------- Процедура обращения к диску ------------ ; Протокол - PIO, режим - LBA28 ;------------------------------------------------------ ; На входе: ; es:di - буфер ; esi[0:27] - LBA адрес ; esi[28] - Устройство ; MBR_2_Port - базовый адрес порта ; MBR_2_SecCol - число секторов для чтения ;----------------------------------------------------- MBR_2_Disc_Zapros proc mov dx,MBR_2_Port ;---------------------- add dx,206h ; mov al,2 ; Запрещаем прерывания out dx,al ;---------------------- mov dx,MBR_2_Port add dx,7 m1: cmp MBR_2_Cikl,100 ;-- jne m1_1 ; Время истекло, ошибка тайм-аута jmp MBR_2_OshibkaTaimAut ;-- m1_1: ; add MBR_2_Cikl,1 ; in al,dx ;-- test al,80h ; Ждем BSY = 0 jnz m1 ;---------------------- mov ecx,esi ;---------------------- shr ecx,24 ; выбираем устройство (в cl) or cl,0e0h ;---------------------- mov dx,MBR_2_Port ;---------------------- add dx,6 ; mov al,cl ; загружаем устройство и старшие разряды адреса out dx,al ;---------------------- mov dx,MBR_2_Port ;---------------------- add dx,7 ; mov MBR_2_Cikl,0 ; m2: ; cmp MBR_2_Cikl,100 ;-- jne m2_1 ; Время истекло, ошибка тайм-аута jmp MBR_2_OshibkaTaimAut ;-- m2_1: ; add MBR_2_Cikl,1 ; in al,dx ; Ждем BSY = 0 test al,80h ; и DRDY = 1 jnz m2 ; test al,40h ; jz m2 ;---------------------- mov dx,MBR_2_Port ;---------------------- add dx,2 mov al,MBR_2_SecCol ; Число секторов out dx,al ;---------------------- mov eax,esi ;---------------------- mov dx,MBR_2_Port ; Загружаем LBA адрес add dx,3 ; out dx,al ; [0:7] mov dx,MBR_2_Port ; add dx,4 ;-- shr eax,8 ; out dx,al ; [8:15] mov dx,MBR_2_Port ; add dx,5 ;-- shr eax,8 ; out dx,al ; [16:23] ;---------------------- mov dx,MBR_2_Port ;---------------------- add dx,7 ; mov al,020h ; Шлем команду - чтение сектора out dx,al ;---------------------- mov dx,MBR_2_Port ;---------------------- add dx,206h ; mov MBR_2_Cikl,0 ; m3: ; cmp MBR_2_Cikl,100 ;-- jne m3_1 ; Время истекло, ошибка тайм-аута jmp MBR_2_OshibkaTaimAut ;-- m3_1: ; add MBR_2_Cikl,1 ; in al,dx ; Ждем окончания чтения test al,80h ; jnz m3 ;---------------------- mov dx,MBR_2_Port ;---------------------- add dx,7 ; mov MBR_2_Cikl,0 ; m4: ; cmp MBR_2_Cikl,100 ;-- jne m4_1 ; Время истекло, ошибка тайм-аута jmp MBR_2_OshibkaTaimAut ;-- m4_1: ; add MBR_2_Cikl,1 ; in al,dx ; Ждем DRQ = 1 test al,08h ; jz m4 ;---------------------- xor bx,bx cld ;---------------------- mov ax,256 ; mov bl,MBR_2_SecCol ; mul bx ; Принимаем прочитанные данные mov dx,MBR_2_Port ; mov cx,ax ; rep insw ;---------------------- mov dx,MBR_2_Port ;---------------------- add dx,206h ; mov al,0 ; Разрешаем прерывания out dx,al ;---------------------- ret MBR_2_OshibkaTaimAut: mov ax,0e01h mov bx,4 int 10h ret MBR_2_Disc_Zapros endp ;------------------------------------------------------ ;--------- Процедура проверки считанных данных -------- ;------------------------------------------------------ ; На входе: ; 0000:5700h - считанные данные ;----------------------------------------------------- MBR_2_Proveraem proc xor ax,ax xor dx,dx mov si,offset MBR_2_Data mov di,5703h cld mov cx,7 repe cmpsb jne MBR_2_Proveraem_NET mov dh,0ffh MBR_2_Proveraem_NET: ret MBR_2_Proveraem endp ;------------------------------------------------------ org 7dfeh ; db 55h, 0aah ; сигнатура MBR ;------------ Ищем порты активного диска -------------- MBR_2_next1: org 7e00h mov MBR_2_Port,01f0h ;---- mov MBR_2_Disk,0 ; mov esi,0 ; Primary Master mov di,5700h ; call MBR_2_Disc_Zapros ; call MBR_2_Proveraem ; cmp dh,0ffh ; je MBR_2_next2 ;---- mov MBR_2_Disk,1 ; mov di,5700h ; mov esi,1 ; Primary Slave shl esi,28 ; call MBR_2_Disc_Zapros ; call MBR_2_Proveraem ; cmp dh,0ffh ; je MBR_2_next2 ;---- mov MBR_2_Port,0170h ; mov MBR_2_Disk,0 ; mov esi,0 ; Secondary Master mov di,5700h ; call MBR_2_Disc_Zapros ; call MBR_2_Proveraem ; cmp dh,0ffh ; je MBR_2_next2 ;---- mov MBR_2_Disk,1 ; mov di,5700h ; mov esi,1 ; Secondary Slave shl esi,28 ; call MBR_2_Disc_Zapros ; call MBR_2_Proveraem ; cmp dh,0ffh ; je MBR_2_next2 ;---- jmp MBR_2_next3 ;---- Просканили порты, теперь сообщим следующему ; загрузчику порт и номер активного диска MBR_2_next2: mov ax,0003h int 10h mov bp,offset MBR_2_Port mov ax,1301h mov bx,000fh mov cx,3 xor dx,dx int 10h ;------------------------------------------------------ MBR_2_next3: xor ax,ax int 16h main endp code ends stk segment stack db 256 dup(0) stk ends end main
Чисто придирка 1. Посмотри 30ю и 35ю строку. 36ю нужно поднять чуть выше. И как бы прерывание запрещать нужно, когда стек меняешь. И когда работаешь с 0x70/0x71h регистрами, то же нужно запрещать прерывания. 76я строка, ты разве менял сегмент? Чисто придирка 2 Эх и не кошерно писать в MBR когда тебя не просят специально. Если пишешь код только для себя, то одно дело, если на "продажу", то не стоит забывать, что в BIOS может стоять запрет на изменение MBR. Чисто придирка 3 А кто тебе сказал, что твой винт работает в режиме эмуляции IDE и висит на 0x1F0/0x170h? Строка 101. Не трогай +0x206 регистр. Не нужно. Строка 105. Цикл по M1 мне лично вообще не понятен. В общем совет, с начало напиши простенькую прогу читающую сектора с диска через порты. Стойкое у мню впечатление, что ты не совсем понимаешь, что делаешь, и как вообще это нужно делать на современных компьютерах. И посмотри на INT 0x13/0x48, может и не придется изобретать велосипед.
Не обязательно, достаточно использовать рекомендуемую команду LSS. Так никто не делает. Странный совет. Наоборот нужно. Мне тоже не понятен. надо проверять BSY = 0 и DRQ = 0 И если не так, то можно подождать и перейти к состоянию устройство не исправно. test al,80h ; и DRDY = 1 Можно не проверять.
Как вариант. Просто LSS автоматически отключает прерывания на время своего исполнения. НО! В данном коде использование LSS не оправдано. http://compgroups.net/comp.lang.asm.x86/LSS-and-MOV-SS Отучаемся говорить за всех. В данном коде не нужно. Я несколько про другое.
Три фразы и все бессмысленные, голословные. Я не телепат и ваши мысли читать не могу. Почему не оправданно? А запрещений прерываний оправданно так?
Э.... Если подумать и посмотреть код, и почитать документацию, то все становится очевидным. Запрещение оправдано. А LSS нет. Хоть одно преимущество назови. А еще лучше дай кусок кода, с LSS. Станет очевидно, по чему.
Чисто отмазка 1 код совсем никак не оптимизировал еще, и я ни разу не видел чтобы запрещали прерывания при работе с 70h, 71h регистрами. Чисто отмазка 2 Буду знать. Чисто отмазка 3 с sata я пока еще не разобрался, как разберусь - встрою в этот код. За основу брал ко из этой статьи http://www.wasm.ru/article.php?article=atazen01 Ну int 13h/48h у меня на старой версии vmware не фурычил, а на новой не пробовал еще да и пробовать не собираюсь, т.к. мне PM нужен. А так если по вашему то данная процедура чтения вообще не работает? Но это совсем не так! Она абсолютно стабильно считала сразу 2 сектора. Вот и странно то что при поиске она вылетает с таймаутом... команды ведь одни и те же, это получается она както неправильно спотыкается об отсутствующие диски.
Опять же вопрос. Ты это для себя разово делаешь, или собираешься тиражировать свое решение? От этого очень много зависит. Про 0x70/0x71 Говорить не буду. Не хочешь не делай. Дело личное, но почитать литературу, настоятельно советую. После этого обнаружишь, что тут у тебя два несоответствия с рекомендациями. Лично мне нравится ISBN 5-256-01263-0. Про "хвост загрузчика". Объяснять почему нельзя использовать 1й сектор для своего кода не буду. Пока нет ответа на первый вопрос, смысла распинаться нет, а информации море. На счет PM. Ты определись где он нужен, вот там и определяй связку логического номера винта (BIOS) с его физическими координатами (Порты и etc). Про правильное планирование задачи в комплексе то же говорить не буду. На счет статьи Посмотри на ее дату. С тех пор много воды утекло. Как там в варе дело обстоит, не знаю, не использую, но вот реальное железо, тебе в легкую сюрприз принесет. Какая процедура? У тебя логика работы в принципе не правильная. По этому и дал совет, с начало разобраться с простенькой программой, а потом перенести уже рабочий код в свою задачу, где отладить его уже в разы сложнее. Для примера, бизю ты 30сек ловить можешь, даже на нормальном и физически присутствующем железе. Ну и зря. Порт тебе это прерывание сообщит, без всяких плясок с бубном.
Повторюсь - нормальная или ненормальная логика, но MBR_2_Disc_Zapros proc работает вполне адекватно с присутствующим железом. А про PM вот: по моей задумке код MBR должен находить порты активного диска и передавать их следующему загрузчику, который переключает проц в PM и дальше делает свою работу. Этот код чисто для меня, мне нужно реализовать свою ФС + так сказать самодельную простенькую ОС (которая ничего не должна делать кроме как создать\удалить\открыть файл либо каталог). Такчто все вотэти правильности в первичных загрузчиках то и не нужны, главное написать да отточить как следует саму ФС.
И не кусайся только, либо объясни что к чему если не трудно, либо пошли меня на какую нибудь страницу с пояснениями.
Тут не одна страница с пояснениями нужна, тут их куча. И не только страниц, но и книг, стандартов, и опыта. Первая твоя проблема, это в логике. Прежде чем что-то делать, ВСЕГДА задай вопрос, А ЗАЧЕМ. Первое, что ты должен определиться насколько твоя ОС будет совместима с другими продуктами. Если ОС ставится только на чистый винт, и доступ к данным на этом винте тебе не нужен из других систем, то абсолютно на все стандарты ты можешь наплевать. И делать как тебе нравится. Единственное условие, что код сидящий в первом секторе (LBA=0) должен быть само достаточным. В принципе, ты это уже делаешь. Дальше, берешь листочек с ручкой, и на бумажке рисуешь блок схему своей ОС. Чем детальнее, тем лучше. Потом для каждого блока описываешь что он должен делать. По тому, что ты пишешь, я не вижу, что ты это сделал. Тогда многие вещи станут намного проще в реализации. Типичная схема загрузки: 1) MBR 2) BOOT сектор 3) BOOT менеджер 4) Загрузчик 5) Ядро Почерку, это общая схема загрузки. Сейчас не тема для ее обсуждения, и я знаю много продуктов которые не соблюдают эту схему. У тебя полный полет фантазии, ограниченный только вопросами совместимости. В задачу загрузчика, входит многое, и опять это зависит от твоей фантазии. И количество этих загрузчиков в том числе. Именно в нем нужно переводить проц в PM, и именно в нем нужно искать порты для устройства. Раньше просто смысла нет. И тут же возникает еще один вопрос. Куда ты поместишь этот загрузчик. Так как его размер на этапе будет плавать, и/или ты задумаешь сделать его вообще модульным, то лучше его поместить внутрь раздела.
Эмммм.... я не про ОС говорил а про ФС, и на бумажке у меня все расписано карандашиком, да и не только на бумажке. Да и вопрос вообще не о том был. Ну да ладно хрен с ним, скоро освобожу второй жесткий и буду на реальной машине тестить. А вот кстати у кого-нибудь возникала такая вот ошибка: Код: mov al,11h out 20h,al Результат: Ошибка "Переполнение деления" и ниже еще пишет "Ошибка при выделении памяти Не удается загрузить COMMAND.COM, система остановлена". Пробовал этот кусок кода писать в любую часть программы - не помогает. Тестил на винде XP через debug (из TASMа) + в vmware без ОС + в vmware в DOS в том же debug'ере от TASM.