装配86 QEMU:致命的:试图执行code以外的RAM或ROM [英] assembly x86 qemu: fatal: Trying to execute code outside RAM or ROM

查看:2478
本文介绍了装配86 QEMU:致命的:试图执行code以外的RAM或ROM的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我工作的一个非常基本的壳,唯一的命令是目前的帮助。如果你输入什么不对,你得知命令心不是认可。某处段和堆栈设置我有,shell会吐出一些废话后,我输入任何东西,然后冻结完全的错误。

错误我得到了终端

  QEMU:致命的:试图在0xff0fe990执行code以外的RAM或ROM
EAX = 0000ffe0 EBX = 0000FFFF ECX​​ = ff00e990 EDX = 0000e000
ESI = 000001a4 EDI = 0000011e EBP = 00000019 ESP = 0000ffdc
EIP = ff00e990 EFL = 00000002 [-------] CPL = 0 II = 0 A20 = 1 SMM = 0 HLT = 0
ES = B000 000b0000 0000FFFF 00009300
CS = F000 000f0000 0000FFFF 00009b00
SS = E000 000e0000 0000FFFF 00009300
DS = E000 000e0000 0000FFFF 00009300
FS = 0000 00000000 0000FFFF 00009300
GS = 0000 00000000 0000FFFF 00009300
LDT = 0000 00000000 0000FFFF 00008200
TR = 0000 00000000 0000FFFF 00008b00
GDT = 000f6688 00000037
IDT = 00000000 000003ff
CR0 = 00000010 CR2 = 00000000 CR3 = 00000000 CR4 = 00000000
DR0 = 00000000 DR1 = 00000000 DR2 = 00000000 DR3 = 00000000
DR6 = ffff0ff0 DR7 = 00000400
CCS = 00000018 CCD = 0000ffe0 CCO = SUBL
EFER = 0000000000000000
FCW = 037f FSW = 0000 [ST = 0] FTW = 00 = MXCSR 00001f80
FPR0 = 0000000000000000 0000 FPR1 = 0000000000000000 0000
FPR2 = 0000000000000000 0000 FPR3 = 0000000000000000 0000
FPR4 = 0000000000000000 0000 FPR5 = 0000000000000000 0000
FPR6 = 0000000000000000 0000 FPR7 = 0000000000000000 0000
XMM00 = 00000000000000000000000000000000 XMM01 = 00000000000000000000000000000000
XMM02 = 00000000000000000000000000000000 XMM03 = 00000000000000000000000000000000
XMM04 = 00000000000000000000000000000000 XMM05 = 00000000000000000000000000000000
XMM06 = 00000000000000000000000000000000 XMM07 = 00000000000000000000000000000000
compile-and-run.sh:第18行:17015中止陷阱:6 QEMU系统-i386的-s -FDA引导disk.bin -boot一个

我很新的装配,所以我想就如何了解我的错误实在AP preciate指南!
在code下面放置。我用这个脚本运行它,请这样做。

  NASM bootloader.asm -o bootloader.bin
DD如果=引导disk.bin BS = 512计数= 2880 =的的/ dev / zero的
DD如果= = bootloader.bin引导disk.bin兑换= notrunc之外
NASM kernel.asm -o kernel.bin
DD如果=的kernel.bin =引导disk.bin兑换= notrunc之外BS = 512寻求= 1
QEMU系统-i386的-s -FDA引导disk.bin -boot一个

bootloader.asm

 位16; NASM指令来声明位模式。全球启动
开始:
  MOV AX,0x07C0; 07C0 = 1984年,在BIOS查找位置
                      ;引导加载程序的软盘上
  MOV DS,AX;设置了数据段(DS)
  KERNEL_BLOCK_START EQU 1;开始的地方内核写入磁盘块
  KERNEL_BLOCK_SIZE EQU 1;含核块的数量
  KERNEL_SEGMENT EQU 1000H;内核将在4096段被加载  调用load_k​​ernel;开始OSload_k​​ernel:
  MOV SI,bootloader_status_message
  电话bootloader_print_string  ;开始从磁盘读取内核字节code
  ;使用中断13h使用AH = 2H
  ;选项​​:AL =扇区读取数
  ; CH =气缸读取,0到1023
  ;内缸CL =读取扇区,1-63
  ; DH =头(0在我们的例子)
  ; DL =驱动器(也为0)
  ; ES:BX =缓冲区地址指针
  MOV啊,2
  MOV人,KERNEL_BLOCK_SIZE
  推字KERNEL_SEGMENT
  流行ES
  异或BX,BX; BX重置为0
  MOV CX,KERNEL_BLOCK_START + 1
  MOV DX,0
  INT 13H;通话中断。写入错误进位标志。  JNC jump_to_kernel;加载成功,进位标志中没有错误  MOV SI,bootloader_load_failed
  电话bootloader_print_string
  JMP $;永远循环下去jump_to_kernel:
  MOV SI,bootloader_load_success
  电话bootloader_print_string
  JMP KERNEL_SEGMENT:0bootloader_print_string:  LODSB;从SI需要一个字节,并将其用于AL(保持指向下一个字节)  还是人,人;所有字符串零结束,以指示该字符串已完成
                 ;我们用它来知道什么时候停止从SI打印字符
                 ;需要本身的逻辑AL或。结果是在进位标志商店  JZ .finish;检查进位标志是零,如果是跳转到结束子程序  ;下面继续打印
  MOV啊,0x0E的;对于电传印刷BIOS指令
  INT 10H; BIOS中断视频服务。 (AH =电传和放大器; AL =字符)  JMP bootloader_print_string;递归调用,直到打印的所有字符  .finish:;完成打印的所有字符
    RET;返回到该程序是由所谓的
bootloader_status_message DB'引导装载程序:加载内核...',0X0D,0x0A的,0
bootloader_load_failed DB'引导程序致命的:加载内核失败。回家了。',0X0D,0x0A的,0
bootloader_load_success DB'引导程序:阅读内核成功,现在跳......',0X0D,0x0A的,0  次510 - ($ - $$)分贝0;循环510次,垫空字节
  DW 0xAA55将;最后2个字节是55H将0AAh和

kernel.asm

  os_initialize_environment:
  STACK_SEGMENT EQU 09000h;常规内存顶部,36864
  STACK_SIZE EQU 0FFFFH;堆栈长度:64K-1字节
  SCREEN_SEGMENT EQU 0b800h;内存细分市场,BIOS写入显示数据
  SCREEN_SIZE_COLUMNS EQU 80; 80宽
  SCREEN_SIZE_ROWS EQU 25; 25高度
  MOV SP,STACK_SEGMENT
  MOV SS,SP
  MOV SP,STACK_SIZE
  推CS
  流行DS
  推字SCREEN_SEGMENT
  流行ES  MOV人,0xF的
  MOV SI,os_kernel_read_signal
  电话os_print_string  调用os_start;开始OS; -------------------------------------------------- --------
;主程序启动
;可用的套路:os_print_string,os_get_user_input,os_compare_string
; -------------------------------------------------- --------
os_start:  MOV SI,os_welcome_message;移动欢迎信息输入
  电话os_print_string  MOV SI,os_alive_signal;移动欢迎信息输入
  电话os_print_string  JMP shell_begin
; ---------------
;壳牌+命令
; ---------------
shell_cursor DB'> ',0
shell_command_help分贝'帮助',0
shell_error_wrong_command DB输入错误。键入help来获得帮助。',0X0D,0x0A的,0
; ---------------
; OS字符串
; ---------------
os_welcome_message DB'SSOS是一个简单的操作系统。保持低预期。悲观者永远不会失望。,0X0D,0x0A的,0
os_alive_signal DB命令提示符准备,0X0D,0x0A的,0
os_kernel_read_signal DB'内核从引导程序达到了',0X0D,0x0A的,0
os_action_help DB'可用命令:帮助',0X0D,0x0A的,0
os_waiting_for_input DB'请提供以下输入',0X0D,0x0A的,0
; ---------------
;缓冲
; ---------------
缓冲时间128分贝0
; -------------------------------------------------- --------
;常规:开始外壳
; -------------------------------------------------- --------
shell_begin:  MOV SI,shell_cursor;打印>光标
  电话os_print_string  MOV DI,缓冲;移动缓冲输出目的地
  调用os_get_user_input;等待用户输入  MOV SI,缓冲;复制用户输入SI  MOV DI,shell_command_help
  调用os_compare_string;检查,如果用户键入help命令
  JC .command_help
  ;选定的命令帮助(shell_command_help)
  .command_help:
    MOV SI,os_action_help
    电话os_print_string
    JMP shell_begin;复位壳
  ;错误的用户输入(命令无法识别)
  .wrong_input_error:
    MOV SI,shell_error_wrong_command
    电话os_print_string
    JMP shell_begin
; -------------------------------------------------- --------
;常规:在SI打印字符串
;输入1 SI:字符串要打印的必须复制到SI
; -------------------------------------------------- --------
os_print_string:  LODSB;从SI需要一个字节,并将其用于AL(保持指向下一个字节)                 ;所有字符串零结束,以指示该字符串已完成
                 ;我们用它来知道什么时候停止从SI打印字符
  还是人,人;需要本身的逻辑AL或。结果是在进位标志商店  JZ .finish;检查进位标志是零,如果是跳转到结束子程序  ;下面继续打印
  MOV啊,0x0E的;对于电传印刷BIOS指令
  INT 10H; BIOS中断视频服务。 (AH =电传和放大器; AL =字符)  JMP os_print_string;递归调用,直到打印的所有字符  .finish:;完成打印的所有字符
    RET;返回到该程序是由所谓的
; -------------------------------------------------- --------
;常规:从用户获取字符串
;等待用户输入一个完整的字符串,并将其放入缓冲区。
;敏感的退格键和回车键
; 1.输入缓冲区的DI
;输出2.输入字符缓冲区
; -------------------------------------------------- --------
os_get_user_input:
  XOR CL,CL; CL将是我们计数器用于跟踪用户已经输入的字符的数目。
                   ;本身进行异或的cl将其设置为零。  MOV SI,os_waiting_for_input
  电话os_print_string  .get_char_and_add_to_buffer:    MOV啊,0;我们使用的BIOS中断16小时来捕获用户输入。
                   ; AH = 0为16小时,它告诉中断读取用户输入的字符的选项
    INT 16H;通话中断。商店在AL读取字符    ;退格键监听器
    CMP人,0x08的;用户输入比较退格键,并将结果保存在进位标志
    JE .backspace_ pressed;如果比较的结果是1,去子程序.backspace_ pressed    ;回车键监听器
    CMP人,0X0D;比较用户输入回车键
    JE .enter_ pressed;到了回车键相应的子程序    ;输入计数器
    CMP CL,0x80的;已经在用户输入128个字节吗? (缓冲限制是128个)
    JE .buffer_overflow    ;用户输入正常字符    ;打印输入
    MOV啊,0x0E的;电传打字机模式
    INT 10H;打印中断    STOSB;把字符缓冲区
    INC CL;增加计数器
    JMP .get_char_and_add_to_buffer;递归
  ; //子程序
  .backspace_ pressed:
    CMP CL,0;没有任何意义,如果没有输入已进入擦除任何东西
    JE .get_char_and_add_to_buffer;忽略退格preSS    ;删除缓存最后输入的字符
                 ;当您使用STOSB,MOVSB​​或类似的功能,系统隐式使用SI和DI寄存器。
    十二月二;因此,我们需要递减迪去的最后一个输入字符,并删除它。
    MOV字节[二],0;在位置擦除字节[二]
    十二月CL;我们的递减计数器    ;从显示屏擦除字符
    MOV啊,0x0E的;再次电传打字机模式
    MOV人,0x08的;退格字符
    INT 10H    MOV人,'';空字符打印
    INT 10H    MOV人,0x08的
    INT 10H    JMP .get_char_and_add_to_buffer;回到主程序
  ;回车键pressed。跳转到退出
  .enter_ pressed:
    JMP .exit_routine
  ;缓冲区溢出(缓冲区已满)。不要接受任何更多的字符和退出程序。
  .buffer_overflow:
    JMP .exit_routine
  .exit_routine:
    MOV人,0;用户输入信号的端
    STOSB
    MOV啊,为0x0E
    MOV人,0X0D;新队
    INT为0x10
    MOV人的0x0A
    INT为0x10    RET;退出全部程序; -------------------------------------------------- --------
;常规:比较两个字符串平等
;等待用户输入一个完整的字符串,并将其放入缓冲区。
;敏感的退格键和回车键
; 1.输入中的String1 SI 2 String2的DI中
;输出1.结果进位标志
; -------------------------------------------------- --------
os_compare_string:
  .compare_next_character:;一个循环,通过人物的性格去
    MOV人,[SI];专注于SI下一个字节
    MOV BL,[二]着眼于二下一字节
    CMP AL,BL
    JNE .conclude_not_equal;如果不相等,结论和退出    ;我们知道:两个字节是平等的    CMP人,0;为什么我们只是比较两个零?
    JE .conclude_equal;如果是的,我们已经到了字符串的结尾。他们是平等的。    ;增量计数器下一循环
    INC迪
    INC SI
    调用.compare_next_character  .conclude_equal:
    STC;将进位标志(这意味着他们是平等的)
    JMP .done
  .conclude_not_equal:
    CLC;清除进位标​​志(即它们不相等)
    JMP .done  .done:
    RET

修复了@Jester建议

 ;引导程序部门的问题
KERNEL_BLOCK_SIZE EQU 21.明显,只是改变来电JMP
2. MOV ES,缓冲;(忽略SCREEN_SEGMENT作为其甚至没有使用)
3.改变外壳逻辑
  shell_begin:
    MOV DI,缓冲;移动缓冲输出目的地
    调用os_get_user_input;等待用户输入
    MOV SI,缓冲;复制用户输入SI
    MOV DI,shell_command_help
    调用os_compare_string;检查,如果用户键入help命令
    JC .command_help
    JNC .wrong_input_error    .command_help:
      MOV SI,os_action_help
      电话os_print_string
      JMP shell_begin;复位壳    .wrong_input_error:
      MOV SI,shell_error_wrong_command
      电话os_print_string
      JMP shell_begin    JMP shell_begin


解决方案

主要的问题是,你kernel.bin已经超越1扇区,而你只载1扇区。

进一步的问题:


  1. os_compare_string 呼叫.compare_next_character 应该是 JMP

  2. os_get_user_input STOSB 使用 ES 段,但你已经设置为指向显存,所以它不会存储在缓冲区
  3. 输入的文本
  4. shell_begin 当你比较输入help命令时,code流量会经常去 .command_help

I'm working on a very basic shell where the only command currently is 'help'. If you type something wrong, you're informed that the command isnt recognized. Somewhere in the segment and stack setup I have a bug that causes the shell to spit out some nonsense after I type anything and then freeze completely.

Error I get in terminal

qemu: fatal: Trying to execute code outside RAM or ROM at 0xff0fe990
EAX=0000ffe0 EBX=0000ffff ECX=ff00e990 EDX=0000e000
ESI=000001a4 EDI=0000011e EBP=00000019 ESP=0000ffdc
EIP=ff00e990 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =b000 000b0000 0000ffff 00009300
CS =f000 000f0000 0000ffff 00009b00
SS =e000 000e0000 0000ffff 00009300
DS =e000 000e0000 0000ffff 00009300
FS =0000 00000000 0000ffff 00009300
GS =0000 00000000 0000ffff 00009300
LDT=0000 00000000 0000ffff 00008200
TR =0000 00000000 0000ffff 00008b00
GDT=     000f6688 00000037
IDT=     00000000 000003ff
CR0=00000010 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000 
DR6=ffff0ff0 DR7=00000400
CCS=00000018 CCD=0000ffe0 CCO=SUBL    
EFER=0000000000000000
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000
XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000
XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000
XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000
compile-and-run.sh: line 18: 17015 Abort trap: 6           qemu-system-i386 -s -fda boot-disk.bin -boot a

I'm very new to assembly so I'd really appreciate guides on how to understand my mistake! The code is placed below. I run it with this script, please do the same.

nasm bootloader.asm -o bootloader.bin
dd if=/dev/zero of=boot-disk.bin bs=512 count=2880
dd if=bootloader.bin of=boot-disk.bin conv=notrunc
nasm kernel.asm -o kernel.bin
dd if=kernel.bin of=boot-disk.bin conv=notrunc bs=512 seek=1
qemu-system-i386 -s -fda boot-disk.bin -boot a

bootloader.asm

BITS 16                ; NASM directive for declaring the bit-mode.

global start
start:
  mov ax, 0x07C0                ; 07C0 = 1984, the location where BIOS looks for the
                      ; bootloader on the floppy disk
  mov ds, ax            ; sets up data segment (ds)
  KERNEL_BLOCK_START equ 1    ; Starting disk block where kernel is written
  KERNEL_BLOCK_SIZE equ 1     ; Number of blocks containing kernel
  KERNEL_SEGMENT equ 1000h    ; Kernel will be loaded at segment 4096

  call load_kernel         ; begin OS

load_kernel:
  mov si, bootloader_status_message
  call bootloader_print_string

  ; begin reading kernel byte code from disk
  ; Uses interrupt 13h with AH = 2h
  ;     Options:   AL = sectors to read count
  ;                CH = Cylinder to read, 0 to 1023
  ;                CL = Sector within Cylinder to read, 1-63
  ;                DH = Head (0 in our case)
  ;                DL = Drive (also 0)
  ;                ES:BX = Buffer address pointer
  mov ah, 2
  mov al, KERNEL_BLOCK_SIZE
  push word KERNEL_SEGMENT
  pop es
  xor bx, bx      ; reset bx to 0
  mov cx, KERNEL_BLOCK_START + 1
  mov dx, 0
  int 13h        ; call interrupt. Writes error to Carry flag

  jnc jump_to_kernel    ; loading success, no error in carry flag

  mov si, bootloader_load_failed
  call bootloader_print_string
  jmp $          ; loop forever

jump_to_kernel :
  mov si, bootloader_load_success
  call bootloader_print_string
  jmp KERNEL_SEGMENT:0

bootloader_print_string:

  lodsb          ; Takes one byte from SI and puts it to AL (maintains pointer to next byte)

  or al, al      ; All strings end with zero to indicate that the string has finished
                 ; we use that to know when to stop printing characters from SI
                 ; takes logical OR of AL by itself. Result is store in Carry Flag

  jz .finish       ; checks if the carry flag is zero and if so jumps to finish subroutine

  ; continue printing below
  mov ah, 0x0E   ; BIOS directive for Teletype printing
  int 10h      ; BIOS interrupt for video services. (AH=Teletype & AL=character)

  jmp bootloader_print_string   ; recursive call until all characters are printed

  .finish:       ; finished printing all characters
    ret          ; return to where this routine was called from


bootloader_status_message db 'bootloader: loading kernel...', 0x0D, 0x0A, 0
bootloader_load_failed db 'bootloader fatal: loading kernel failed. Go home.', 0x0D, 0x0A, 0
bootloader_load_success db 'bootloader: reading kernel success, jumping now...', 0x0D, 0x0A, 0

  times 510 - ($ - $$) db 0    ; loop 510 times and pad with empty bytes
  dw 0xAA55                    ; last 2 bytes are 55h and 0AAh

kernel.asm

  os_initialize_environment:
  STACK_SEGMENT equ 09000h        ; top of Conventional memory, 36864
  STACK_SIZE equ 0ffffh           ; stack length: 64K-1 bytes
  SCREEN_SEGMENT equ 0b800h       ; segment of memory where BIOS writes display data
  SCREEN_SIZE_COLUMNS equ 80      ; 80 width
  SCREEN_SIZE_ROWS equ 25         ; 25 height
  mov sp, STACK_SEGMENT
  mov ss, sp
  mov sp, STACK_SIZE
  push cs
  pop ds
  push word SCREEN_SEGMENT
  pop es

  mov al, 0xf
  mov si, os_kernel_read_signal
  call os_print_string

  call os_start                   ; begin OS

; ----------------------------------------------------------
; Start of main program
; Available routines: os_print_string, os_get_user_input, os_compare_string
; ----------------------------------------------------------
os_start:

  mov si, os_welcome_message    ; move welcome message to input
  call os_print_string

  mov si, os_alive_signal    ; move welcome message to input
  call os_print_string

  jmp shell_begin


; ---------------
; Shell + commands
; ---------------
shell_cursor db '> ', 0
shell_command_help db 'help', 0
shell_error_wrong_command db 'Wrong input. Type help for help.', 0x0D, 0x0A, 0


; ---------------
; OS strings
; ---------------
os_welcome_message db 'SsOS is a Simple Operating System. Keep expectations low. The pessimist is never disappointed.', 0x0D, 0x0A, 0
os_alive_signal db 'Command prompt ready', 0x0D, 0x0A, 0
os_kernel_read_signal db 'Kernel reached from bootloader', 0x0D, 0x0A, 0
os_action_help db 'available commands: help', 0x0D, 0x0A, 0
os_waiting_for_input db 'Please provide input below', 0x0D, 0x0A, 0


; ---------------
; Buffer
; ---------------
buffer times 128 db 0


; ----------------------------------------------------------
; Routine: Begins shell
; ----------------------------------------------------------
shell_begin:

  mov si, shell_cursor   ; print > cursor
  call os_print_string

  mov di, buffer         ; move buffer to destination output
  call os_get_user_input ; wait for user input

  mov si, buffer         ; copy user input to SI

  mov di, shell_command_help
  call os_compare_string ; checks if user typed help command
  jc .command_help


  ; command help (shell_command_help) selected
  .command_help:
    mov si, os_action_help
    call os_print_string
    jmp shell_begin      ; reset shell


  ; wrong user input (command not recognized)
  .wrong_input_error:
    mov si, shell_error_wrong_command
    call os_print_string
    jmp shell_begin


; ----------------------------------------------------------
; Routine: Print String in SI
; Input    1. SI: string to be printed must be copied to SI
; ----------------------------------------------------------
os_print_string:

  lodsb          ; Takes one byte from SI and puts it to AL (maintains pointer to next byte)

                 ; All strings end with zero to indicate that the string has finished
                 ; we use that to know when to stop printing characters from SI
  or al, al      ; takes logical OR of AL by itself. Result is store in Carry Flag

  jz .finish       ; checks if the carry flag is zero and if so jumps to finish subroutine

  ; continue printing below
  mov ah, 0x0E   ; BIOS directive for Teletype printing
  int 10h      ; BIOS interrupt for video services. (AH=Teletype & AL=character)

  jmp os_print_string   ; recursive call until all characters are printed

  .finish:       ; finished printing all characters
    ret          ; return to where this routine was called from


; ----------------------------------------------------------
; Routine: Get String from User
; Waits for a complete string of user input and puts it in buffer.
; Sensitive for backspace and Enter buttons
; Input    1. Buffer in DI
; Output   2. Input char in buffer
; ----------------------------------------------------------
os_get_user_input:
  xor cl, cl       ; CL will be our counter that keeps track of the number of characters the user has entered.
                   ; XORing cl by itself will set it to zero.

  mov si, os_waiting_for_input
  call os_print_string

  .get_char_and_add_to_buffer:

    mov ah, 0      ; We use bios interrupt 16h to capture user input.
                   ; AH=0 is an option for 16h that tells the interrupt to read the user input character
    int 16h      ; call interrupt. Stores read character in AL

    ; backspace button listener
    cmp al, 0x08   ; compares user input to the backspace button, stores result in Carry Flag
    je .backspace_pressed    ; if the results of the compare is 1, go to subroutine .backspace_pressed

    ; enter button listener
    cmp al, 0x0D   ; compares user input to enter button
    je .enter_pressed        ; go to appropriate subroutine for enter button

    ; input counter
    cmp cl, 0x80   ; Has the user entered 128 bytes yet? (buffer limit is 128)
    je .buffer_overflow

    ; User input is normal character

    ; print input
    mov ah, 0x0E   ; Teletype mode
    int 10h      ; Print interrupt

    stosb          ; puts character in buffer
    inc cl         ; increment counter
    jmp .get_char_and_add_to_buffer    ; recurse


  ; // Subroutines
  .backspace_pressed:
    cmp cl, 0      ; no point erasing anything if no input has been entered
    je .get_char_and_add_to_buffer   ; ignore backspace press

    ; Delete last input character from buffer
                 ; When you use stosb, movsb or similar functions, the system implicitly uses the SI and DI registers.
    dec di         ; Therefore we need to decrement di to get to the last input character and erase it.
    mov byte[di],0 ; Erases the byte at location [di]
    dec cl         ; decrement our counter

    ; Erase character from display
    mov ah, 0x0E   ; Teletype mode again
    mov al, 0x08   ; Backspace character
    int 10h

    mov al, ' '    ; Empty character to print
    int 10h

    mov al, 0x08
    int 10h

    jmp .get_char_and_add_to_buffer    ; go back to main routine


  ; enter button pressed. Jump to exit
  .enter_pressed:
    jmp .exit_routine


  ; buffer overflow (buffer is full). Don't accept any more chars and exit routine.
  .buffer_overflow:
    jmp .exit_routine


  .exit_routine:
    mov al, 0       ; end of user input signal
    stosb
    mov ah, 0x0E
    mov al, 0x0D    ; new line
    int 0x10
    mov al, 0x0A
    int 0x10

    ret             ; exit entire routine



; ----------------------------------------------------------
; Routine: Compare equality of two strings
; Waits for a complete string of user input and puts it in buffer.
; Sensitive for backspace and Enter buttons
; Input    1. String1 in SI    2. String2 in DI
; Output   1. result in carry flag
; ----------------------------------------------------------
os_compare_string:
  .compare_next_character:      ; a loop that goes character by character
    mov al, [si]      ; focus on next byte in si
    mov bl, [di]      ; focus on next byte in di
    cmp al, bl
    jne .conclude_not_equal       ; if not equal, conclude and exit

    ; we know: two bytes are equal

    cmp al, 0         ; did we just compare two zeros?
    je .conclude_equal         ; if yes, we've reached the end of the strings. They are equal.

    ; increment counters for next loop
    inc di
    inc si
    call .compare_next_character

  .conclude_equal:
    stc              ; sets the carry flag (meaning that they ARE equal)
    jmp .done


  .conclude_not_equal:
    clc              ; clears the carry flag (meaning that they ARE NOT equal)
    jmp .done

  .done:
    ret

Fixes suggested by @Jester

;bootloader sector problem
KERNEL_BLOCK_SIZE equ 2

1. obvious, just change call to jmp
2. mov es, buffer ;(ignore SCREEN_SEGMENT as its not even used)
3. change shell logic 
  shell_begin:
    mov di, buffer         ; move buffer to destination output
    call os_get_user_input ; wait for user input
    mov si, buffer         ; copy user input to SI
    mov di, shell_command_help
    call os_compare_string ; checks if user typed help command
    jc .command_help
    jnc .wrong_input_error

    .command_help:
      mov si, os_action_help
      call os_print_string
      jmp shell_begin      ; reset shell

    .wrong_input_error:
      mov si, shell_error_wrong_command
      call os_print_string
      jmp shell_begin

    jmp shell_begin

解决方案

Main problem is that your kernel.bin has grown beyond 1 sector, and you only load 1 sector.

Further problems:

  1. In os_compare_string, the call .compare_next_character should be a jmp.
  2. In os_get_user_input, stosb uses the es segment, but you have set that up to point to the video memory, so it won't store the entered text in the buffer
  3. In shell_begin when you compare the input to the help command, the code flow will always go to .command_help

这篇关于装配86 QEMU:致命的:试图执行code以外的RAM或ROM的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆