Попытка прочитать ключ через int 16h заканчивается перезагрузкой виртуальной машины - PullRequest
0 голосов
/ 16 февраля 2019

Я пытался добавить взаимодействие с клавиатурой в код из этого примера .Рассмотрим следующие файлы:

Cargo.toml

[package]
name = "kernelhello"
version = "0.0.1"

[dependencies]
bootloader = "0.3.12"

[package.metadata.bootimage]
default-target = "build.json"

build.json

{
  "llvm-target": "x86_64-unknown-none",
  "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
  "arch": "x86_64",
  "target-endian": "little",
  "target-pointer-width": "64",
  "target-c-int-width": "32",
  "os": "none",
  "executables": true,
  "linker-flavor": "ld.lld",
  "linker": "rust-lld",
  "panic-strategy": "abort",
  "disable-redzone": true,
  "features": "-mmx,-sse,+soft-float"
}

src / main.rs

// src/main.rs
#![feature(asm)]

#![no_std] // don't link the Rust standard library
#![no_main] // disable all Rust-level entry points

use core::panic::PanicInfo;

/// This function is called on panic.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}
}


#[no_mangle]
pub extern "C" fn _start() -> ! {
    let mut HELLO: &mut [u8] = &mut b"Hello World!".clone();
    let vga_buffer = 0xb8000 as *mut u8;

    let mut z = 0;
    loop {
        for (i, byte) in HELLO.iter_mut().enumerate() {
            unsafe {
                z += 14;
                z %= 4000;
                *vga_buffer.offset(z + i as isize * 2) = *byte;
                *vga_buffer.offset(z + i as isize * 2 + 1) = 0xa;
                asm!("mov $$0, %ah\nint $$0x16");
            }
        }
    }
}

К сожалению, попытка сделать bootimage run заканчивается изображением, которое застряло в цикле перезагрузки - что не произойдет, если я закомментирую asm! вызов.Вот разборка:

➜  rust-kernel-hello objdump -D -b binary -Mintel,x86-64  -m i386 target/build/debug/bootimage-kernelhello.bin | grep -C5 'ef01'
    eef0:       00 
    eef1:       48 8b 84 24 d0 00 00    mov    rax,QWORD PTR [rsp+0xd0]
    eef8:       00 
    eef9:       48 89 84 24 00 01 00    mov    QWORD PTR [rsp+0x100],rax
    ef00:       00 
    ef01:       48 8d bc 24 f0 00 00    lea    rdi,[rsp+0xf0]
    ef08:       00 
    ef09:       e8 72 fe ff ff          call   0xed80
    ef0e:       48 89 94 24 20 01 00    mov    QWORD PTR [rsp+0x120],rdx
    ef15:       00 
    ef16:       48 89 84 24 18 01 00    mov    QWORD PTR [rsp+0x118],rax
--
    f119:       48 89 04 24             mov    QWORD PTR [rsp],rax
    f11d:       48 8b 04 24             mov    rax,QWORD PTR [rsp]
    f121:       c6 00 0a                mov    BYTE PTR [rax],0xa
    f124:       b4 00                   mov    ah,0x0
    f126:       cd 16                   int    0x16
    f128:       e9 d4 fd ff ff          jmp    0xef01
    f12d:       48 8d 3d cc 0a 00 00    lea    rdi,[rip+0xacc]        # 0xfc00
    f134:       e8 07 04 00 00          call   0xf540
    f139:       0f 0b                   ud2    
    f13b:       48 8d 3d e6 0a 00 00    lea    rdi,[rip+0xae6]        # 0xfc28
    f142:       e8 f9 03 00 00          call   0xf540

Что я делаю не так?

1 Ответ

0 голосов
/ 17 февраля 2019

Я бы хотел объяснить комментарий zx485 более подробно:

Я часто видел, что начинающие на ассемблере не понимают, что такое инструкции, как int (x86), syscall (MIPS) или SWI (ARM) на самом деле.

На самом деле, эти инструкции представляют собой особую форму инструкции call: они вызывают некоторую подпрограмму, которая обычно находится в операционнойsystem.

64-битные процессоры x86 имеют разные режимы работы.Один из них называется «реальный режим».В этом режиме ЦП может выполнять только 16-битный код.

Подпрограмма BIOS, которую можно вызвать с помощью int 0x16, работает только тогда, когда ПК работает в «реальном режиме».

Тот факт, что ваша программа является 64-битной программой (используются регистры типа rax), говорит о том, что ваш процессор не работает в реальном режиме.

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

Вы можете определить подпрограмму, которая вызывается с помощью int 0x16, которая читает клавиатуру, а другую - с помощью int 0x10, записывающую вscreen.

Однако вы также можете указать, что int 0x16 используется для записи на экран, а int 0x10 используется для доступа к жесткому диску в вашей операционной системе.

И вв каждом случае вам придется писать подпрограммы самостоятельно, потому что существующие подпрограммы в BIOS не могут использоваться в любом другом рабочем режиме, кроме «реального режима».(Это то, что Росс-Ридж указывает в своем комментарии.)

...