Считать строку с жесткого диска и распечатать в TTY вариант со сборкой

Я работаю над проектом "Напишите свою собственную операционную систему, используя только сборку, держа вас за руку". Я написал все с нуля, как MikeOS, за исключением чтения и записи жесткого диска. Важность чтения и записи состоит в том, чтобы обеспечить возможность того, чтобы операционная система была больше, чем базовая память ввода памяти длиной 512 единиц.

Я написал тестовый пример для чтения с жесткого диска и печати первого символа на экране. Используя qemu, я могу определить, какой файл использовать в качестве жесткого диска, в связи с тем, что я определяю позиции регистров, которые программа может указывать на этот жесткий диск с опцией 0x80 во время прерывания функции чтения.

Первый тестовый код был без выбора жесткого диска, и, таким образом, код чтения считывал свой собственный исполняемый двоичный файл и выдавал предположение "a", поскольку двоичный файл произвел "a"(ascii) в начале исполняемого файла, загруженного в Базовая информация о системе.

Итак, мой вопрос здесь...

  1. Когда я определяю выбор жесткого диска, почему он не читает строку "Hello" в файле на экране, как если бы я не определял жесткий диск?

  2. Является ли мой код правильным для начала, и "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.

Другие вопросы по тегам