Результаты поиска по запросу «

;0@0 :@>DB 18

»

Запрос:
Создатель поста:
Теги (через запятую):



it-юмор geek Windows Операционная система windows phone 

Их идеи будут актуальны всегда

Такой вот баннер мне моя вторая звонилка сегодня продемонстрировала. Не знаю что они там употребляют, но вещь реально забористая

.■Ill Гг.
HD 0:54
HOME
p
Выполните обновление до Windows 11
Эта версия Microsoft Store больше не поддерживается. Выполните обновление до Windows 11, чтобы продолжить использовать...
Upward ★ ★★★■> 33
Dictionary ★ ★★★★ 3
Phoenix
Force
★ ★★★★ 123
£о/~п пэтил
p
£ск/~П пэтил
£ск/~П
Развернуть

#Приколы для даунов смайлики 

Египтологи в 19 веке: зачем они рисовали всю эту ебанину, не могли придумать 26 букв?! 200 лет спустя: £>■ УУ чЛ.. V , <Ц|фМ1 ®*ехочв©*А«п*е|1«£(г1 ъ, У” - - олв • !?1^1 ? ШВ г: ^$Ь,ф£!е г (¿) - ” 4$|д|У№ ^ V - ••• 2" Й1!# о©^мШш ™о ^ и/0\^V©V"— ■-. г ©<?«?; 1* ВО\ ! У' У^цаГ/5*«' В_П ■
Развернуть

Отличный комментарий!

Иератическое письмо древнего Египта : - Я какая-то шутка для тебя ?
skayras skayras16.11.202208:39ссылка
+31.6

платье правильная реклама поторописька песочница песочница эротики Эротика домашняя эротика 

Тема http://www.kharkovforum.com/showthread.php?t=2808108
Сообщение от №1ашка £§
продам свое платье, одевала всего два разаф хочу 500гривень. фото сделаю чуть позже.,платье,правильная реклама,поторописька,песочница,песочница эротики,Эротика,красивые фото обнаженных, совсем голых девушек, арт-ню,домашняя эротика
Развернуть

geek песочница эротики Эротика тп платье 

■ 14.01.2013, 16:38
Регистрация: 08.08.2012 Адрес: Харьков Сообщений: 113
платье!
продам свое платье, одевала всего два раза$ хочу БООгривень. фото сделаю чуть позже, размер хб
телефон напишу в личку!
- Миниатюры-
Последний раз,,geek,Прикольные гаджеты. Научный, инженерный и  айтишный
Развернуть

программирование geek ассемблер Операционная система разработка OSDev песочница 

Уроки ОСдева №3: блок параметров BIOS

В прошлый раз мы разобрались с физической геометрией дискеты и расположением данных. Кроме того, мы узнали, как записать программу-загрузчик в нулевой сектор носителя. Если кто-то из вас действительно пытался повторить мои действия и потом использовать дискету как загрузочную, то наверняка обнаружил два неприятных момента:


1. При попытке открыть образ дискеты Wndows говорит, что она не отформатирована.
2. BIOS не воспринимает дискету как загрузочную и пишет что-нибудь вроде "no bootable device found".

Давайте разбираться. Если помните, в конце прошлого поста наша будущая программа-загрузчик выглядела так:

.386p

CSEG segment use16

ASSUME cs:CSEG, ds:CSEG, es:CSEG, fs:CSEG, gs:CSEG, ss:CSEG

begin:                    cli

                             hlt

CSEG ends

end begin


По сути это просто заглушка, которая при запуске должна останавливать процессор. Причина ругани Виндоус в том, что в нулевом секторе на отформатированном носителе хранится важная структура данных - блок параметров BIOS (BPB). Записав туда же нашу программу, мы его пот+ёрли. Для того, чтобы этого избежать, нам придётся воссоздать BPB в тексте программы. Для этого нужно знать геометрию носителя. К счастью, в наше время сохранился только один тип дискет.


Непроверенный метод: возможно, если с помощью утилиты debug записать программу не в начало сектора, а со смещением, достаточным, чтобы пропустить оригинальный BPB, то он не пострадает, но я не проверял. По-моему, debug всё равно забьёт остатки сектора каким-то мусором.


Во-первых, измените программу вот так:


.386p

CSEG segment use16

ASSUME cs:CSEG, ds:CSEG, es:CSEG, fs:CSEG, gs:CSEG, ss:CSEG

begin:                     jmp short execute

                             nop

execute:                 cli

                             hlt

CSEG ends

end begin


У нас появились две новые инструкции: jmp short и nop. Последняя - просто пустой оператор. Процессор пропускает его, не выполняя никаких действий. Занимает 1 байт. jmp - инструкция перехода. jmp short - переход в пределах 127 байт от текущего положения. Исполняется гораздо быстрее jmp, так что везде где возможно - используйте его. Занимает 2 байта. execute - название метки, на которую указывает инструкция jmp short.


Зачем всё это и зачем nop? BPB должен располагаться строго в трёх байтах от начала нулевого сектора. Эти три байта и занимают инструкции jmp short execute и nop. Таким образом, когда программа начнёт исполняться, первой инструкцией, которую выполнит процессор, будет пропустить BPB. В противном случае он бы попытался исполнить его как код, что привело бы к катастрофе.

Теперь давайте вставим сам блок параметров BIOS между nop и меткой execute.


.386p

CSEG segment use16

ASSUME cs:CSEG, ds:CSEG, es:CSEG, fs:CSEG, gs:CSEG, ss:CSEG

begin:                     jmp short execute

                             nop


                BPB_OEMname          db    'BOOTDISK'

                BPB_bytespersec       dw    512

                BPB_secperclust        db     1

                BPB_reserved            dw    1

                BPB_numFATs           db     2

                BPB_RDentries          dw    224

                BPB_sectotal             dw    2880

                BPB_mediatype         db     0F0h

                BPB_FATsize             dw     9

                BPB_secpertrack        dw     18

                BPB_numheads         dw     2

                BPB_hiddensec          dd     0

                BPB_sectotal32          dd     0

                EBPB_drivenum         db     0

                EBPB_NTflags            db     0

                EBPB_extsign            db     29h

                EBPB_volID               dd     0

                EBPB_vollabel            db     'BOOTLOADER '

                EBPB_filesys              db     'FAT12   '


execute:                 cli

                             hlt


CSEG ends

end begin


BPB - это блок данных, и здесь мы впервые объявляем переменные. В TASM это выглядит так: BPB_OEMname (имя) -пробел- db, dw, dd или dq -пробел- 'BOOTDISK' (значение). Имени может и не быть, но тогда к переменной нужно будет обращаться по смещению, это не очень удобно. DB, DW, DD и DQ - сокращение от define byte (word, double word или quad word) - обозначают размер переменной. Соответственно, 1, 2, 4 или 8 байт. Инстркция этого типа позволяют объявлять целые серии значений через запятую: myvalue dw 2, 5, 165, 776. С помощью инструкции db можно объявлять строки: mytext db 'Allo, Yoba!' Обратите внимание, что в плоском бинарнике переменные при компиляции не выносятся в какую-то специальную область данных. В исполняемом файле они будут именно там, где вы их объявили в тексте программы. Ещё важный момент: имена переменных только для вашего личного пользования, в исполняемый файл они не попадут, так что вы не обязаны копировать названия у меня. Теперь давайте посмотрим, что за информация хранится в BPB.


BPB_OEMname - 8 байт: по идее здесь должно быть название производителя, но по факту вы можете писать что угодно, никто на это значение не смотрит.

BPB_bytespersec - 2 байта: размер сектора в байтах, для дискет как правило 512.

BPB_secperclust - 1 байт: число секторов в кластере. Про кластеры мы поговорим позже, но в случае с дискетами секторы и кластеры соответствуют друг другу.

BPB_reserved - 2 байта: число зарезервированных секторов, недоступных файловой системе. В нашем случае такой один, это наш загрузочный сектор.

BPB_numFATs - 1 байт: количество FAT (file allocation table), таблиц распределения файлов. Так как носители информации (особенно дискеты) подвержены порче, а FAT - очень важная часть файловой системы, для неё часто делается резервная копия.

BPB_RDentries - 2 байта: количество записей в корневой директории (Root Directory). Про корневую директорию тоже будем говорить в другой раз, но пока можете представить её как список файлов с указанием их физического расположения на носителе.

BPB_sectotal - 2 байта: число секторов на диске, если их не больше 65535. Если больше, здесь должен быть 0.

BPB_mediatype - 1 байт: тип носителя. F0 - код для 3,5-дюймовой дискеты с 18 секторами в дорожке.

BPB_FATsize - 2 байта: размер одной FAT в секторах.

BPB_secpertrack - 2 байта: число секторов в дорожке.

BPB_numheads - 2 байта: число головок.

BPB_hiddensec - 4 байта: количество скрытых секторов перед загрузочным, в нашем случае 0.

BPB_sectotal32 - 4 байта: число секторов, если их больше 65535. Если меньше, здесь должен быть 0.


Здесь стандартный BIOS Parameter Block заканчивается и начинается расширенный, который появился в поздних версиях DOS.


EBPB_drivenum - 1 байт: бесполезная переменная, хранящая номер привода, в который был вставлен носитель при форматировании.

EBPB_NTflags - 1 байт: флаги Вин НТ. Если установлен бит 0, необходимо проверить носитель на битые секторы. Значения других флагов не знаю.

EBPB_extsign - 1 байт: признак расширенного BPB. Для нашей версии должно быть 29h.

EBPB_volID - 4 байта: случайный номер, который присваивается при форматировании. В общем бесполезен.

EBPB_vollabel - 11 байт: имя носителя.

EBPB_filesys - 8 байт: имя файловой системы.


Если вы теперь заново скомпилируете программу и запишите на дискету, то она отлично откроется в Windows. Первая проблема решена, но осталась вторая: дискета всё ещё не опознаётся как загрузочная. Вспоминаем: для этого последние 2 байта загрузочного сектора должны иметь значения AAh и 55h. Добавим ещё две строчки в нашу программу:


.386p

CSEG segment use16

ASSUME cs:CSEG, ds:CSEG, es:CSEG, fs:CSEG, gs:CSEG, ss:CSEG

begin:                     jmp short execute

                             nop


                BPB_OEMname          db    'BOOTDISK'

                BPB_bytespersec       dw    512

                BPB_secperclust        db     1

                BPB_reserved            dw    1

                BPB_numFATs           db     2

                BPB_RDentries          dw    224

                BPB_sectotal             dw    2880

                BPB_mediatype         db     0F0h

                BPB_FATsize             dw     9

                BPB_secpertrack        dw     18

                BPB_numheads         dw     2

                BPB_hiddensec          dd     0

                BPB_sectotal32          dd     0


                EBPB_drivenum         db     0

                EBPB_NTflags            db     0

                EBPB_extsign            db     29h

                EBPB_volID               dd     0

                EBPB_vollabel            db     'BOOTLOADER '

                EBPB_filesys              db     'FAT12   '


execute:                 cli

                             hlt


               org 510

                dw 0AA55h


CSEG ends

end begin


Команда org 510 заполнит нулями место от текущей позиции до 510 байта, а в последние два мы поместили метку загрузочного сектора. Вуаля, проблема 2 решена.


Выражалось мнение, что всё это ебучее легаси и современные пацаны предпочитают UEFI, но UEFI не даст вам того интимного, я бы сказал, понимания железа, на котором работает ваша ось, так что основная серия будет продолжена по старинке.


Нужны ли туторы по UEFI?
Да
89 (69.0%)
Нет
8 (6.2%)
Я не знаю, заебал свою гиковскую xуйню сюда постить, вали на гитxаб!
32 (24.8%)
Развернуть

Китай ветряк репост с 3DNEWS 

В Китае установили первый в мире морской 18-МВт ветрогенератор — 260 м в диаметре

Китайская госкомпания Dongfang Electric Corporation сообщила, что на днях завершила установку самой высокой в мире прибрежной ветряной турбины мощностью 18 МВт. Установка сможет вырабатывать 72 ГВт·ч чистой энергии в год, обеспечивая баланс потребления на восточном побережье Поднебесной вместе с поставками солнечной энергии с западных пустошей.

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

Только что развёрнутый ветряной генератор мощностью 18 МВт имеет ротор диаметром 260 м. Это примерная площадь более 7 стандартных футбольных полей. Чем больше площадь «пропеллера», тем быстрее окупается генератор и тем больше мощности он вырабатывает. Новым рекордом обещает стать 22-МВт ветряк выше Эйфелевой башни с диаметром ротора 310 м. Но это будет уже другая эпичная история. Пока это только проект.

Сурс: https://3dnews.ru/1106297/v-kitae-ustanovili-pervuyu-v-mire-vetryanuyu-turbinu-rekordnoy-18mvt-moshchnosti

Критика ветряков:

https://3dnews.ru/1092335/eksperti-prizivayut-zatormozit-narashchivanie-moshchnostey-vetryanih-turbin-industriya-moget-ne-vidergat-gonku

 От себя: ну и дела. Города спрессовывают, все в пробках, так теперь ещё с размерами Эйфелевой башни ветроловки будут пустые места занимать...

Китай,страны,ветряк,репост с 3DNEWS
Развернуть

Отличный комментарий!

так площадь или диаметр
Gagagin Gagagin12.06.202408:43ссылка
+2.6
Китай первый в мире, что не ясно? Минус социальный рейтинг

программирование geek OSDev Операционная система разработка ассемблер длиннопост песочница 

Урок ОСдева №7: первичный загрузчик, финал.

В прошлый раз мы написали процедуру загрузки данных и использовали ее для того, чтобы 

поместить корневую директорию нашей дискеты в оперативную память сразу после собственно

программы-загрузчика по адресу 07C0h:0200h. План действий на сегодня:


-Найти в КД номер первого кластера файла.

-Загрузить первый кластер.

-Следуя по цепочке записей в FAT, загрузить остальные кластеры.


Перед тем, как кодить дальше, давайте  разберёмся, что такое КД и как её использовать для

поиска файлов*.


По сути корневая директория в FAT12 - это таблица, в которой каждому файлу или

поддиректории соответствует одна 32-байтная запись. Давайте посмотрим, что в ней есть.


Байты 0-10: имя файла в формате 8:3. Этот формат подразумевает, что имя файла занимает

ровно 8 байтов, а расширение - 3. Если имя файла меньше 8 символов, оно дополняется

пробелами: так, файл 'loader.bin' в КД будет проходить под именем 'LOADER  BIN'.


Байт 11: атрибуты записи. Набор флагов, позволяющий придать записи особые свойства.

          00000001b = только для чтения

          00000010b = скрытый

          00000100b = системный

          00001000b = метка раздела

          00010000b = директория

          00100000b = архив

          00001111b = LFN (long file name), запись имеет особый формат, поддерживающий длинные

                              имена файлов.


Байт 12: зарезервирован для Windows NT.


Байт 13: время создания в десятых секунды (почему-то 0-199 согласно OSDev Wiki).


Байты 14-15: время, когда был создан файл. Младшие 5 бит - секунды/2 (то есть при интерпретации

значения, например, для вывода на экран, эту часть надо умножать на 2). Следующие 6 - минуты.

Последние 5 бит - часы.


Байты 16-17: дата создания файла. Примерно та же история. День(0-4), месяц(5-8), год(9-15).


Байты 18-19: дата последнего доступа в том же формате, что и дата создания.


Байты 20-21: старшие 16 бит номера первого кластера файла. В FAT12 и FAT16 не используется.


Байты 22-23: время последнего изменения в том же формате, что и время, когда был создан файл.


Байты 24-25: дата последнего изменения в том же формате, что и дата создания.


Байты 26-27: младшие 16 бит номера первого кластера файла.


Байты 28-31: размер файла в байтах.

Довольно много информации, но нас интересуют только два поля: имя записи и младшая часть номера

стартового кластера (старшая половина в FAT12 не используется). Вырисовывается в общих чертах

алгоритм поиска файла? Если нет, я помогу:


1. Переходим к началу КД

2. Считываем имя записи

3. Сравниваем имя записи с именем искомого файла

4. Если имена совпали, файл найден, SUCCESS!

5. Записи кончились?

6. Если кончились - файла нет, аварийно завершаемся

7. Переходим к следующей записи

8. goto 2

Вот таким нехитрым способом мы сможем найти на диске начало файла или, если его нет, уведомить

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

перепечатывать весь листинг из предыдущих уроков. Вместо этого я приложу ссылку на файл в

конце. Это позволит вместить в пост больше полезной информации, не растягивая его до

нечитабельных размеров. А теперь давайте выполним наш поисковый алгоритм в коде. После

call read_sectors пишите:


                   mov cx,BPB_RDentries

                   mov di,0200h

                   mov si,offset fname

                   mov bp,si


next_entry:   mov ax,cx

                   mov bx,di

                   mov cx,11

                   rep cmpsb

                   mov si,bp

                   mov di,bx

                   mov cx,ax

                   je load_FAT

                   add di,32

                   loop next_entry


                   mov ah,3

                   xor bh,bh

                   int 10h


                   mov ax,1300h

                   mov bx,0007h

                   mov cx,22

                   mov bp,offset fname

                   int 10h


                   cli

                   hlt

Что всё это значит? В строчке mov cx,BPB_RDentries мы устанавливаем счётчик основного

цикла. Напоминаю, что в переменной BPB_RDentries у нас хранится число записей корневой

директории. 0200h - смещение загруженной в RAM КД. В SI мы помещаем смещение строки с

именем искомого файла. Кстати, впишите в переменные fname db 'LOADER  BIN'. После этого

мы сохраняем это же смещение в регистре BP. Это может быть пока неочевидно, но позже вы

поймёте, зачем.


Следующий блок кода, начинающийся с метки next_entry, - это собственно цикл просмотра

записей КД и сравнения имён. Первым делом мы сохраняем счётчик цикла и смещение текущей

записи. Счётчик сохраняем потому, что будет вложенный цикл, а смещение - потому, что

строковые инструкции вроде cmpsb изменяют значения регистров SI и DI. Кстати, теперь вам

должно быть понятно, зачем мы сохраняли указатель на строку с именем в BP.


mov cx,11 - установка счётчика вложенного цикла. Имена в FAT12 хранятся в формате 8:3,

значит, нам нужно сравнить две строки по 11 символов. Надеюсь, тут вопросов нет?

Инструкция cmpsb сравнивает значения двух байтов (в нашем случае символов), находящихся

в DS:SI и ES:DI. Префикс rep повторяет инструкцию, пока не обнулится счётчик в CX.

Далее мы восстанавливаем счётчик основного цикла в CX, смещение текущей записи в DI и

смещение строки с именем файла в SI. В старых версиях здесь у меня были пары инструкций

push/pop, но потом я подумал, что трансфер из регистра в регистр быстрее, чем обращение

к стеку, и поменял. Никогда не вредно сэкономить пару циклов.


Если в результате rep cmpsb все символы совпали, в регистре флагов будет установлен бит

ZF. Команда je load_FAT выполняет переход к метке load_FAT если флаг ZF установлен.

В случае если строки не совпали, мы переводим DI к следующей записи в КД и продолжаем

цикл командой loop next_entry. Тут бы можно было и закончить, но нужно обработать

отсутствие файла. С этим набором инструкций мы уже знакомы по предыдущему посту.

Первый блок возвращает положение курсора в DH,DL, а второй выводит от этой позиции

сообщение. Отличается только само сообщение. Вместо 'Disk read error.' мы выводим строку

с именем файла. Внимание, тут небольшой хак. Идея в том, чтобы вывести следующий текст:

'{filename} not found!'. Вызвать вывод строки два раза, но зачем? Если поместить в

разделе переменных текст ' not found!' сразу после переменной fname, а при вызове int 10h

указать в CX не 11 символов, а 22, то выведется сначала имя файла, а потом ' not found!'

Конечно же, этот текст обязательно должен быть сразу после fname. Добавьте строчкой ниже

db ' not found!' После этого останавливаем процессор парой команд cli и hlt. Не так-то

сложно, да? Впрочем, файл ещё нужно загрузить.


Для этого нам нужно будет загрузить в память FAT и разобраться, как ею пользоваться.

Давайте начнём с первой задачи, она чисто техническая и не требует умственного напряжения.

После hlt набирайте:


Load_FAT:          mov ax,[di+26]

                         mov cluster,ax

                         mov ax,BPB_reserved

                         mov cx,total_FATs_size

                         mov bx,BPB_RDentries

                         shl bx,5

                         add bx,0200h

                         mov FAT_offset,bx

                         call read_sectors

В строчке mov ax,[di+26] мы считываем из записи КД номер первого кластера файла, а затем

сохраняем его в переменной cluster. Далее, мы помним, что FAT у нас идут сразу после

зарезервированных секторов, поэтому в AX помещаем BPB_reserved. В CX у нас будет число

секторов, которое надо загрузить, то есть total_FATs_size. Загружать FAT будем сразу после

КД, то есть в 07С0h:0200h+размер КД. Размер КД = число записей КД*размер записи (32 байта).

Помещаем в BX число записей (BPB_RDentries), умножаем на 32 (shl bx,5 эквивалентно умножению

на 32, но выполняется быстрее) и добавляем 0200h. Готово! Сохраняем на будущее в переменной

FAT_offset (кстати, объявите её рядом с прочими) и вызываем read_sectors.


А теперь время вернуться к теории. Что такое FAT? Не поверите, но это тоже таблица, и её

структура ещё проще, чем у КД. Каждая запись в FAT соответствует кластеру на диске. FAT

можно назвать оглавлением диска (украл с OSDev Wiki). Кластер может быть свободен, занят

частью файла, зарезервирован ОС или испорчен. Если кластер хранит часть файла, то его

запись в FAT будет содержать номер следующего кластера файла. Понятно? Зная номер первого

кластера файла, мы можем загрузить его в память, потом заглянуть в FAT, найти нужную запись

и считать номер следующего кластера. Повторять до конца файла. Звучит просто, но, как

всегда, есть большое "НО"! Размер записи в FAT12 - 12 бит. Мы не можем оперировать

12-битными ячейками. Мы можем считать 8 или 16. То есть, если мы загрузим в AX начало FAT,

то в регистре окажется первая запись и часть второй. А если сдвинемся на один байт, то

получим конец первой записи и всю вторую. Давайте попробую проиллюстрировать для

наглядности. В верхней строчке будет часть FAT, разделённая на записи, а в нижней она же,

но поделенная на 8-битные куски.


0 0 0 1 0 1 1 1 0 0 1 0|0 1 1 1 0 0 1 0 1 0 0 0|0 0 1 0 0 1 0 0 0 1 1 1          3 Записи.

0 0 0 1 0 1 1 1|0 0 1 0 0 1 1 1|0 0 1 0 1 0 0 0|0 0 1 0 0 1 0 0|0 1 1 1         4,5 байта.


Решение в том, чтобы, считывая каждый нечётный кластер, сдвигать значение на 4 бита вправо, а

у чётного - обнулять 4 старших бита. Зная всё это, давайте писать код:


                             push 0050h

                             pop es

                             xor bx,bx

read_cluster:           mov ax,cluster

                             sub ax,2

                             movzx cx,BPB_secperclust

                             mul cx

                             add ax,datasector

                             call read_sectors

                             mov ax,cluster

                             mov si,ax

                             shr ax,1

                             add si,ax

                             add si,FAT_offset

                             mov dx,[si]

                             mov ax,cluster

                             test ax,1

                             jnz odd_cluster

                             and dx,0000111111111111b

                             jmp short done

odd_cluster:           shr dx,4

done:                     mov cluster,dx

                             cmp dx,0FF7h

                             jb read_cluster

Финальный рывок. Первое, что мы делаем - устанавливаем сегмент для загрузки файла. Так как

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

в 0000h:0000h, но первые 1280 байт заняты важными вещами, о которых поговорим позже.

Ближайший свободный участок RAM - 0050h:0000h (или 0000h:0500h, это тот же самый адрес

если вы вдруг забыли правила адресации сегмент:смещение). Обнуляем BX, так чтобы пара

ES:BX указывала на 0050h:0000h. Считываем в AX номер первого кластера файла. Дальше мы

вычитаем 2 из этого номера. Зачем? Затем, что значения 0 и 1 в FAT зарезервированы и не

используются в качестве номеров, а номер, указанный в таблицах, на 2 больше, чем правильное

значение. Да, это идиотизм.


Загружать будем не сектор, а кластер (что в нашем случае одно и то же, но всё-таки),

поэтому в качестве числа секторов помещаем в CX переменную BPB_secperclust и на неё же

умножаем номер кластера. AX*CX в данном случае дадут нам номер первого сектора нужного

кластера. А так как кластеры в FAT начинают считаться от начала области данных,то для

абсолютного значения добавляем к AX datasector. Готово. Вызываем read_sectors и загружаем

первый кластер файла в RAM.


Дальше будет немножко математической магии, объяснять которую я не буду. Если интересно -

разберётесь самостоятельно, там не так сложно. Остальным предлагаю просто поверить, что

смещение записи кластера внутри FAT = 3/2 номера кластера. Значит, берём в AX номер

кластера, его же помещаем в SI, делим AX на 2 и прибавляем к SI. Вуаля, смещение

записи от начала FAT найдено. Добавляем к нему смещение FAT_offset и считываем в DX

значение записи.


Теперь надо проверить, чётная ли запись. Для этого опять берём в AX номер кластера и

делаем сравнение с 1. Если флаг ZF не установлен (то есть 0 бит значения равен 1),

значит, номер записи - нечётный, переходим к odd_cluster и сдвигаем значение вправо на

4 позиции. Если чётный - делаем логическое "И" с маской 0000111111111111b и обнуляем

тем самым 4 старших бита. Теперь у нас есть содержимое нужной записи без всяких

посторонних хвостов, то есть номер следующего кластера. Сохраняем его в переменной

cluster. Дальше у нас идёт сравнение с номера с числом 0FF7h. Дело в том, что,

начиная от этого значения в FAT идут специальные коды, которые могут означать конец

файла, испорченный сектор и т.д. Для нас это значит, что если в качестве номера

кластера мы получили 0FF7h или больше, продолжать загрузку не имеет смысла. Поэтому

продолжаем цикл только если DX меньше 0FF7h. Я умышленно оставляю здесь дыру и

предлагаю всем заинтересованным попытаться самостоятельно сделать обработку ошибки,

связанной с битым кластером (код 0FF7h). Код конца файла, кстати, 0FF8h. Вся необходимая

для этой задачи информация и примеры кода уже есть в этом посте.


А мне остаётся только добавить в конце три строчки:


                    push 0050h

                    push 0000h

                    retf

Этот набор команд мы уже помним из старых постов. Помещаем в стек сегмент, потом

смещение, и передаём управление загруженному файлу командой retf. Поздравим себя!

Первичный загрузчик готов. Да, он умеет немного, но и задача у него всего одна:

найти загрузчик второго уровня, поместить его в RAM и отдать штурвал. Если вы

скомпилируете файл без инструкций org 1FEh и dw 0AA55h, то увидите, что программа

занимает всего 447 байт. Значит, у нас есть в запасе ещё 63. Как раз должно

хватить на проверку успешного считывания кластеров. У меня вместе с ней вышло 497

байт. Можете подсмотреть в приложенном файле, хоть это и неспортивно. Если вы

поместили загрузчик на дискету и получили в bochs (или на реальной машине) вот такой

экран, то всё работает как надо!


Plex86/Bochs UGABios (PCI) current-cvs 08 Jul 2014 This UGA/UBE Bios is released under the GNU LGPL
Please visit :
. http://bochs.sourceforge.net . http ://www.nongnu.org/vgab ios
Bochs UBE Display Adapter enabled
Bochs BIOS - build: 07/10/14
$Revis ion: 12412 $ $Date: 2014-07-10 09:28:59


Чистая дискета:

https://drive.google.com/file/d/1Bold4ds8oEruHQ7fJZKHglVo7A2Vc5MR/view?usp=sharing


Листинг:

https://drive.google.com/file/d/1Q5EtKX5kyF4MWcBeD8a6Jz5cPtqZja9C/view?usp=sharing


Bochs:

https://drive.google.com/file/d/16k2Gpr7oPSekq4rAhmtBV0IPnIteDLlE/view?usp=sharing


* FAT поддерживает вложенные директории, и они ничем принципиально не отличаются

от корневой, так что всё нижеизложенное касается и их. 


Развернуть

Genshin Impact Codes Genshin Impact фэндомы 

40 камней

Правила:

1) Зайти на официальную страницу в Facebook;
2) Нажать на кнопку отправки сообщения в шапке страницы (под кнопкой "Играть");
3) В открывшемся чате с ботом кликнуть "Начать", выбрать язык, затем "Викторину от Паймон";
4) Правильно ответить на один вопрос (см. ниже);
5) После принятия ответа ввести свой UID.

Пройти "викторину" можно до 16 марта, 18:59 по Москве. Получить награду - 19 марта.

Источник
Какая у Венти любимая еда?,Genshin Impact Codes,коды геншин импакт,Genshin Impact,Геншин Импакт,фэндомы
Развернуть

программирование geek OSDev Операционная система разработка песочница 

Урок ОСдева №4: работа с RAM, адресация в 16-битном режиме, регистры процессора.

Поздравим себя. В прошлый раз мы добавили блок параметров BIOS, после чего винда перестала

ругаться на дискету. Пора начинать писать загрузчик. Но перед этим надо подробнее

разобраться в специфике программирования на ассемблере. Всё-таки он сильно отличается от языков

высокого уровня. Давайте вспомним, как выглядела программа в конце прошлого поста.


.386p

CSEG segment use16

ASSUME cs:CSEG, ds:CSEG, es:CSEG, fs:CSEG, gs:CSEG, ss:CSEG


begin:            jmp short execute                   ;Точка входа. Перейти к исполняемой части.

                     nop                                       ;Пустой оператор. Заполняет 3-й байт перед BPB.


;БЛОК ПАРАМЕТРОВ BIOS===================================================================;

;=======================================;

;Блок параметров BIOS, 33 байта.

;Здесь хранятся характеристики

;носителя. Должен быть в 3-х байтах

;от начала загрузочного сектора.

;=======================================;

BPB_OEMname    db 'BOOTDISK'    ;0-7. Имя производителя. Может быть любым.

BPB_bytespersec  dw 512              ;8-9. Размер сектора в байтаx.

BPB_secperclust   db 1                  ;10. Количество секторов в кластере.

BPB_reserved      dw 1                  ;11-12. Число зарезервированныx секторов (1, загрузочный).

BPB_numFATs     db 2                   ;13. Число FAT.

BPB_RDentries    dw 224               ;14-15. Число записей Корневой Директории.

BPB_sectotal       dw 2880             ;16-17. Всего секторов на носителе.

BPB_mediatype   db 0F0h              ;18. Тип носителя. 0F0 - 3,5-дюймовая дискета с 18 секторами в дорожке.

BPB_FATsize       dw 9                   ;19-20. Размер FAT в сектораx.

BPB_secpertrack dw 18                  ;21-22. Число секторов в дорожке.

BPB_numheads   dw 2                   ;23-24. Число головок (поверxностей).

BPB_hiddensec    dd 0                  ;25-28. Число скрытыx секторов перед загрузочным.

BPB_sectotal32    dd 0                  ;29-32. Число секторов, если иx больше 65535.


;===============================================;

;Расширенный блок параметров BIOS, 26 байт.

;Этот раздел используется в DOS 4.0.

;===============================================;

EBPB_drivenum   db 0                       ;0. Номер привода.

EBPB_NTflags      db 0                      ;1. Флаги в Windows NT. Бит 0 - флаг необxодимости проверки диска.

EBPB_extsign      db 29h                   ;2. Признак расшренного BPB по версии DOS 4.0.

EBPB_volID         dd 0                      ;3-6. "Серийный номер". Любое случайное число или ноль, без разницы.

EBPB_vollabel     db 'BOOTLOADER '  ;7-17. Название диска. Устарело.

EBPB_filesys       db 'FAT12   '           ;18-25. Имя файловой системы.




;ИСПОЛНЯЕМЫЙ БЛОК=====================================================================;

execute:                     cli

                                 hlt


           org 1FEh                              ;Заполняет память нулями до 511-го байта.

           dw 0AA55h                           ;Байты 511 и 512. Признак загрузочного сектора.

CSEG ends

end begin


Я снабдил всё подробными комментариями. Надеюсь, они помогут вам освежить память. Вкратце -

после запуска программы процессор выполняет переход к метке execute - и после этого останавливается

командами cli и hlt. Давайте добавим следующий код после execute, а потом разберём его.


execute:             mov ax,07C0h

                         mov ds,ax

                         mov es,ax

                         mov fs,ax

                         mov gs,ax


                         cli

                         mov ss,ax

                         mov sp,0FFFFh

                         sti


                         push ax

                         mov ax,offset stop

                         and ax,03FFh

                         push ax

                         retf


stop:                  cli

                         hlt


           org 1FEh                                     ;Заполняет память нулями до 511-го байта.

           dw 0AA55h                                  ;Байты 511 и 512. Признак загрузочного сектора.


Целая куча новых команд. Для того, чтобы их понять, придётся освоиться с новыми понятиями.


Регистр - ячейка памяти процессора, которая может выполнять какую-то конкретную задачу

или иметь общее назначение. Программируя на ассемблере, вы постоянно будете оперировать

регистрами: помещать в них данные, извлекать, модифицировать и т.д. В 16-битном режиме

процессор использует следующий набор регистров: AX, BX, CX, DX, SI, DI, BP, SP, flags, CS, DS, ES,

FS, GS, SS. С функциями каждого из них будем разбираться по мере надобности.


Сегмент:смещение - устаревшая система адресации, применявшаяся в эпоху 16-битных процессоров.

Тем не менее, для нас она важна, так как ради обратной совместимости именно в этом

режиме BIOS оставляет систему перед запуском загрузчика.


Постараюсь объяснить. 16-битная разрядность процессора подразумевает, что за раз он может обработать

16 бит данных. Максимальное значение, которое можно передать 16 битами - 65535. Это ограничение

касается и адресации памяти. Выходит, процессору доступно всего (65536/1024) 64 килобайта RAM. Чтобы

обойти это ограничение, была придумана модель адресации segment:offset. Сегмент в ней - это базовый адрес,

от которого считается смещение. Регистры процессора CS, DS, ES, FS, GS и SS - сегментные. Они используются

для указания адреса в памяти, от какого отсчитывается смещение. Например, DS:0050h означает байт 0050h

от значения, помещённого в DS. Вернее, от значения в DS*16. Это называется гранулярностью. Единица,

помещённая в регистр DS, устанавливает основание сегмента не в 1-й байт, а в 16-й. За счёт этого нам

становится доступен целый мегабайт оперативной памяти! (или даже больше с некоторыми ухищрениями,

но рассказывать о них я большого смысла не вижу, т.к. мы всё равно скоро покинем 16-битное царство)


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

или сохранять состояние регистров при вызове прерывания. В случае ассемблера в стеке можно хранить

промежуточные результаты работы процедуры, если не хватило регистров. Кроме того, стек аппаратно

используется некоторыми командами процессора.


Команда mov op1,op2 используется для того, чтобы переместить значение op2 в op1. В качестве

операнда op1 может выступать адрес ячейки памяти или регистр. В качестве op2 может быть ячейка

памяти, регистр или конкретное значение. Есть два ограничения: операнды должны совпадать по

разрядности (нельзя поместить содержимое 16-битного регистра в 32-битный, например) и в качестве

обоих операндов не могут быть адреса в памяти. Так что делает этот код?


mov ax,07C0h

mov ds,ax

mov es,ax

mov fs,ax

mov gs,ax


Правильно, он помещает значение 07С0h в регистр AX,  потом копирует AX в сегментные регистры

DS, ES, FS и GS. Зачем? Затем, что BIOS копирует загрузочный сектор в 07С0h:0000h. Так как

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

так, чтобы они указывали туда же. По какой-то причине (ей-богу не помню!) присваивать значения

сегментным регистрам напрямую нельзя, но можно через другой регистр - поэтому сначала мы загружаем

его в AX, а уже AX копируем в сегментные регистры. Вы наверое уже обратили внимание, что сегментные

регистры здесь не все. Для модификации оставшихся надо немного поплясать с бубном.


cli

mov ss,ax

mov sp,0FFFFh

sti


Что происходит здесь? Пара команд cli и sti запрещает и разрешает прерывания. Прерывания - то, при помощи

чего разные устройства в компьютере общаются с процессором. Они могут поступать от таймеров, дисковых

контроллеров и из множества других источников. Позже мы ещё поговорим о них подробно, а сейчас достаточно

знать, что команда cli вешает на процессор знак "не беспокоить". sti, соответственно, его снимает.

Дело в том, что SS - это сегментный регистр стека. При манипуляциях с ним лучше убедиться, что в

неподходящий момент не произойдёт переключение задачи. Обратите внимание: сегмент стека у нас там же,

где и загрузчик. Получается, помещая данные в стек, мы затрём часть собственного кода? Нет. Позиция стека

передаётся парой регистров SS:SP. SS - сегмент, а SP - смещение. mov sp, 0FFFFh устанавливает начало

стека в конец сегмента. Получается, ему некуда расти? Тоже нет. Стек растёт в обратном направлении.

Если мы командой push отправим в стек 16-битное слово, то указатель изменит значение на 0FFFDh. Таким

образом, загрузчик и стек находятся в разных концах 64-килобайтного сегмента, и расстояние между ними

вполне приличное.


push ax

mov ax,offset stop

and ax,03FFh

push ax

retf


Соберитесь, последний на сегодня кусок кода. Здесь мы модифицируем сегментный регистр кода, CS. К нему

тоже нужен особый подход. Кстати, самое время поговорить о том, как процессор узнаёт, какую команду выполнять

следующей. Как и в случае стека, существует указатель в виде пары регистров CS:IP. Каждый раз после

считывания из памяти инструкции IP увеличивается на её размер в байтах. Все модели BIOS помещают загрузчик

в 07C0h:0000h, но вот состояние CS:IP может быть разным: например, 07C0h:0000h и 0000h:7C00h указывают на

один и тот же байт в памяти, но во втором случае у нас могут быть проблемы. В каком именно состоянии

оказались регистры CS:IP при старте загрузчика, мы не знаем, поэтому лучше перестраховаться и установить

своё значение.


Как установить значение CS:IP? Например, при помощи инструкции дальнего возврата retf. Обычно она

используется для возврата из процедур, но подойдёт и нам, так кк делает именно то, что нужно: меняет

значения CS:IP. Сегмент и смещение для возврата должны быть в стеке. В AX у нас значение сегмента, 07C0h,

так что командой push отправляем его в стек. А вот с IP придётся повозиться. Щас объясню. CS в данный момент

может быть установлен либо в 07C0h, либо в 0000h. Значит, любое считанное нами смещение относительно его

начала будет равно или X или X+7C00h. Нам нужно однозначно привести его к X. Как это сделать? Команда

mov AX,offset stop помещает в AX смещение метки stop (то есть, конечно, команды cli, сами метки

в исполняемом файле физически не присутствуют и места не занимают). 7С00h, если его перевести в

двоичный вид, будет равно 111110000000000b. Соответственно, искомый X помещается в восьми нулях в начале

значения.  обнуление старших пяти единиц будет эквивалентно уменьшению значения на 7С00h, что нам и нужно.

Про логические операции поговорим позже, но пока знайте, что команда and AX,03FFh делает как раз это:

обнуляет все старшие разряды AX, начиная с первой единицы в 111110000000000b. 03FFh, кстати, в

двоичном виде будет выглядеть так: 1111111111b. Заметили связь? В общем, если кто-то не разбирается в

логических операциях, то ДЗ на сегодня - просветиться по этой теме.


Фух, чёрт возьми, на сегодня всё! Теперь наш загрузчик будет работать в предсказуемой среде, что сэкономит

нам море усилий.


Развернуть
Комментарии 1 27.11.201914:00 ссылка -1.9

Я Ватник фэндомы Ватные вбросы разная политота 

Israeli Strike Kill» Hundreds in At Least 500 Dead in Strike on At Least 500 Dead in Blast at Car Hospital. Palestinians Say Gaza Hospital. Palestinians Say	Hospital, Palestinians Say
Мастер-класс «Нью-Йорк Таймс» по работе с заголовком.
Сначала исчез Израиль. Потом удар. В итоге в больнице
Развернуть
В этом разделе мы собираем самые смешные приколы (комиксы и картинки) по теме ;0@0 :@>DB 18 (+1000 картинок)