Считать строку с жесткого диска и распечатать в TTY вариант со сборкой
Я работаю над проектом "Напишите свою собственную операционную систему, используя только сборку, держа вас за руку". Я написал все с нуля, как MikeOS, за исключением чтения и записи жесткого диска. Важность чтения и записи состоит в том, чтобы обеспечить возможность того, чтобы операционная система была больше, чем базовая память ввода памяти длиной 512 единиц.
Я написал тестовый пример для чтения с жесткого диска и печати первого символа на экране. Используя qemu, я могу определить, какой файл использовать в качестве жесткого диска, в связи с тем, что я определяю позиции регистров, которые программа может указывать на этот жесткий диск с опцией 0x80 во время прерывания функции чтения.
Первый тестовый код был без выбора жесткого диска, и, таким образом, код чтения считывал свой собственный исполняемый двоичный файл и выдавал предположение "a", поскольку двоичный файл произвел "a"(ascii) в начале исполняемого файла, загруженного в Базовая информация о системе.
Итак, мой вопрос здесь...
Когда я определяю выбор жесткого диска, почему он не читает строку "Hello" в файле на экране, как если бы я не определял жесткий диск?
Является ли мой код правильным для начала, и "a", отображаемое на экране, является совпадением того, что в начале созданного двоичного файла, который запускается в эмуляторе, есть "a"?
Для всех, пожалуйста, ответьте с объяснениями и кодом. Есть два вопроса, которые я нашел в Переполнении стека, на которые оба даны ответы с объяснениями на английском языке о том, что не так с их кодом, но нет кода, чтобы продемонстрировать, почему они верны в своих объяснениях. Это спорный вопрос, чтобы объяснить, но не показать свою работу.
Не предлагайте мне использовать C, C++ или что-либо еще, кроме ассемблера, если вы провели свое исследование, а я провел исследование и разобрал языки высокого уровня, такие как C, C++ или что-то еще, вы увидите простое "определение и чтение строки на консоли "не только значительно больше, но просто небрежно с точки зрения эффективности. Эти сравнения дизассемблированного кода C с собственноручными примерами сборки также будут опубликованы в файлах проекта.
Я ценю ваше время, и когда я выпущу проект в качестве учебных пособий с открытым исходным кодом, общество по достоинству оценит, сколько времени вы сэкономили кому-либо еще в той же должности, что и я. (Человеческое знание принадлежит миру - Антимонопольное кино, 2001 год)
[bits 16]
[org 0x7c00]
message db "Hello"
mov ah, 0x02 ;point to read sector function
mov ch, 0x00 ;ch track/cylinder number
mov dh, 0x00 ;dh head number
mov cl, 0x00 ;cl sector number
mov dl, 0x80 ;drive number 80 is drive0, 81 is drive1
int 0x13
;read disk into terminal.... might be working, just displays 'a'...
mov ah, 0x0e
mov al, [bx]
int 0x13
;Purpose, move to the next character read from file
mov ah, 0x0e
mov es, bx
mov al, [bx]
int 0x13
times 510 - ($-$$) db 0
dw 0xAA55
;==============================================================
; Reference Notes
;==============================================================
;
;;;;;;;;;;;;; Interupt 02 - Read from sector ;;;;;;;;;;;;
;AH = 02
;AL = number of sectors to read (1-128 dec.)
;CH = track/cylinder number (0-1023 dec., see below)
;CL = sector number (1-17 dec.)
;DH = head number (0-15 dec.)
;DL = drive number (0=A:, 1=2nd floppy, 80h=drive 0, 81h=drive 1)
;ES:BX = pointer to buffer
;
;on return:
;AH = status (see INT 13,STATUS)
;AL = number of sectors read
;CF = 0 if successful
; = 1 if error
;;;;;;;; Inturrupt 13 - Video card functions ;;;;;;;;
;AH = 02, means TTY mode, print to console mode
;AL = which character to print to console
1 ответ
Поместив message
в начале перед кодом процессор попытается декодировать строку в инструкции и выполнить их. Это может привести к неожиданному поведению и сбоям. Вы можете разместить данные после кода и перед загрузочной подписью. Ассемблер (NASM) выдает последовательность байтов, содержащую hello
в начале загрузчика. Процессор не может определить разницу между байтами, составляющими строку, или тем, что является настоящим кодом. Процессор видит последовательность байтов и пытается декодировать байты и выполняет их.
Ваш код не препятствует выполнению процессором после окончания наших реальных инструкций. Вы можете исправить это с помощью jmp $
создать бесконечный цикл или отключение прерываний и hlt
процессор с инструкциями cli
с последующим hlt
,
Для чтения с диска Int 13h/ah=2h требуется:
- установка количества секторов для чтения в AL
- требуется адрес сегмента: смещение, с которого следует читать диск в ES:BX перед вызовом прерывания
- Не жестко кодируйте DL (загрузочный диск) и используйте то, что BIOS передал нам в DL
- Номера секторов (в отличие от цилиндров и головок) основаны на 1, а не на 0. Это означает, что первый сектор на диске (загрузчик) имеет CHS=(0,0,1), а не (0,0,0). Использование номера сектора 0 недопустимо.
Этот загрузчик считывает копию загрузчика в память с размером 0x0000:0x7E00 из цилиндра, головки, сектора (CHS) (0,0,1) с загрузочного диска, передаваемого в загрузчик в DL BIOS. Этот код следует моим общим советам по загрузчику, настроив наш собственный стек и явно установив регистр DS в 0.
bits 16
org 0x7c00
cld ; Set forward direction for string related functions like LODSB
xor ax, ax ; XOR register with itself sets register to 0
mov ds, ax ; DS = 0x0000
mov ss, ax ; SS:SP =0x0000:0x7C00
mov sp, 0x7c00 ; Set SS:SP since we will be loading data from disk to memory
; We want to ensure the data we read is not in the same
; memory as the stack. Stack will grow down from 0x0000:0x7c00
; in memory just below the bootloader
; Read 1 sector starting at CHS = 0,0,1 (the boot sector)
; to 0x0000:0x7E00. This creates a copy of the bootloader
; in memory in the memory just after where we are loaded at
; 0x0000:0x7c00
mov es, ax ; ES:BX memory to read to 0x0000:0x7E00
mov bx, 0x7e00 ; 0x0000:0x7E00 is in the memory just after our bootloader
; which ran from 0x7c00 to 0x7dff.
mov al, 0x01 ; Number of sectors to read
mov ah, 0x02 ; point to read sector function
mov ch, 0x00 ; ch track/cylinder number
mov dh, 0x00 ; dh head number
mov cl, 0x01 ; cl sector number
; dl is set by the BIOS before transferring control to our bootloader
int 0x13
; Print the message from the copy of the bootloader loaded at 0x7E00
mov si, message + 0x200
call print_string
cli
hlt
; Function: print_string
; Display a string to the console on display page 0
;
; Inputs: SI = Offset of address to print
; Clobbers: AX, BX, SI
print_string: ; Routine: output string in SI to screen
mov ah, 0eh ; BIOS tty Print
xor bx, bx ; Set display page to 0 (BL)
jmp .getch
.repeat:
int 10h ; print character
.getch:
lodsb ; Get character from string
test al,al ; Have we reached end of string?
jnz .repeat ; if not process next character
.end:
ret
message db "Hello", 0
times 510 - ($-$$) db 0
dw 0xAA55
print_string
это функция, которую я написал, которая печатает завершенную строку NUL. Смещение памяти для строки предоставляется в регистре SI.