1

Contents

I want to jump to diskette_initialisation with the jmp instruction after executing the lgdt instruction, but it crashes What is the cause? If the cause is known, why did the designers of the Intel cpu do it?

Environment

  • cpu: intel(r) core(tm) 17-8550U
  • Machines: virtual box
  • Auxiliary storage: diskette
  • Compiler: NASM version 2.15.05 compiled on Aug 28 2020

code

bits 16
org 0x7c00
  jmp boot_lodaer
  boot_lodaer:
    cli
    mov ax, 0
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    mov sp, 0x7c00

    call minimum_gdt_andidt
    bits 16
    call valid_A20
    call diskette_initialisation
    jmp  Protected_Mode

    minimum_gdt:
      bits 32
      lgdt [ndt_setup];https://wiki.osdev.org/GDT_Tutoria
   lidt [ndt_setup:
      ret
      ndt_setup:
        dw 23
        dd gdt_null
      ndt_null:
        dq 0x0:
      ndt_code:
        dw 0xffff
        dw 0x0
        db 0x0
        db 11001111b
        db 10011010b
        db 0x0
      ndt_date:
        dw 0xffff
        dw 0x0
        db 0x0
        db 11001111b
        db 10011010b
        db 0x0
   ndit_end:
    ;Only enable a20. Does not check for anything.
    valid_A20:
      in al, 0x60
      mov al, 0xad; key off
      out 0x60, al

      in al, 0x60
      mov   al,   0xfe; key initialisation
      out   0x60, al

      in al, 0x60
      mov   al,  0xae; key on
      out   0x60, al
      mov al, 0x00
    ret  

    diskette_error:
      mov ah, 0x0e
      mov al, 'E'
      int 0x10
    hlt
    
    diskette_initialisation:
      mov ah, 0x00
      mov dl, 0x00
      int 0x13
      jc diskette_error

      mov ah, 0x0e
      mov al, '2'
      int 0x10
    ret

    Protected_Mode:
      cli 
      mov eax, 1
      mov cr0, eax
    jmp eax:karnel
  kanel:
  hlt
  times   510-($-$$) db 0
dw  0aa55h
  • 3
    Why do you jump indirectly to `diskette_initialization`? What do you think loading the first instruction bytes at that label, interpreting them as an address and then jumping there is going to achieve? – fuz Jun 27 '21 at 13:17
  • Use a debugger, for example BOCHS's built-in debugger, to single-step your code. – Peter Cordes Jun 27 '21 at 15:39
  • hi fuz, My interpretation is that it can jump to the diskette_initialization address as fast as a c language pointer. –  Jun 28 '21 at 08:47
  • hi peter cordes, What is the built-in debugger of BOCHS? Are there any others similar to it? –  Jun 28 '21 at 10:10
  • https://bochs.sourceforge.io/doc/docbook/user/internal-debugger.html has the documentation. DOSBox might have something like that built-in, but BOCHS is generally recommended for OS development. It understands segmentation, while GDB-remote into a qemu doesn't. And BTW, I didn't see your reply until your edit bumped the question, since you forgot to @peter notify me. Stack Overflow is an English site; non-English comments aren't great, non-English text outside the code block is totally off topic. – Peter Cordes Jul 04 '21 at 17:43
  • I tried to run the executable binary file in bochs and the result was the same as in the virtual box, no error –  Jul 10 '21 at 20:09
  • We don't use gdt and protection mode where we know there is a hardware bug So goodbye, I'm leaving. –  Jul 10 '21 at 20:17

2 Answers2

4
org 0x7e00

Because of this directive, all of the displacements in your code are going to be wrong!

You need : ORG 0x7C00


mov ss, ax

If you are not going to also specify the stackpointer SP, then don't change SS. There's a reasonable chance that you can keep using the existing stack.


gdt_setup:
   dw 24
   dd gdt_null

Minor change: the first word here is a limit not a size. You should write dw 23.


jmp [diskette_initialisation]

At diskette_initialisation there's code, not a pointer (first noticed by @fuz). You need to write jmp diskette_initialisation


You're using some bad values in the descriptors! Mostly due to an inversion of a couple of bytes. Below is the correct setup for CODE and DATA:

gdt_code:
    dw 0xFFFF
    dw 0
    db 0
    db 10011010b
    db 11001111b
    db 0
gdt_data:
    dw 0xFFFF
    dw 0
    db 0
    db 10010010b
    db 11001111b
    db 0
Sep Roland
  • 33,889
  • 7
  • 43
  • 76
  • hi sep roland, Why can't I change it? If so, how does it change the behaviour around it? –  Jun 28 '21 at 10:04
  • 1
    @ealvkaaef Your recent edit with `bits 32` makes things worse! The assembler will now generate a 32-bit addressing mode on the `lgdt [gdt_setup]` instruction and the real address mode where your program is running will not be able to use it correctly. Also see my edited answer where I have explained another error. – Sep Roland Jun 29 '21 at 21:33
  • I looked up Real Mode on the internet. According to ```https://blog.ishikawa.tech/entry/2018/12/10/215234``', real mode is only available in 16-bit. im sorry!!!!! –  Jul 03 '21 at 15:15
  • @ealvkaaef: Correct, see also https://en.wikipedia.org/wiki/X86-64#Operating_modes – Peter Cordes Jul 04 '21 at 17:41
  • We don't use gdt and protection mode where we know there is a hardware bug So goodbye, I'm leaving. –  Jul 10 '21 at 20:17
0

This is a hardware bug on the intel side, so it won't fix the problem. I couldn't even do it the same way as in the specification.Goodbye, for the time being, I will resent intel for the time I spent on it.

The specifications I have referred to enter link description here

9.9.1 Switching to Protected Mode

Before switching to protected mode from real mode, a minimum set of system data structures and code modules must be loaded into memory, as described in Section 9.8, “Software Initialization for Protected-Mode Operation.” Once these tables are created, software initialization code can switch into protected mode. Protected mode is entered by executing a MOV CR0 instruction that sets the PE flag in the CR0 register. (In the same instruction, the PG flag in register CR0 can be set to enable paging.) Execution in protected mode begins with a CPL of 0. Intel 64 and IA-32 processors have slightly different requirements for switching to protected mode. To insure upwards and downwards code compatibility with Intel 64 and IA-32 processors, we recommend that you follow these steps:

  1. Disable interrupts. A CLI instruction disables maskable hardware interrupts. NMI interrupts can be disabled with external circuitry. (Software must guarantee that no exceptions or interrupts are generated during the mode switching operation.)
  2. Execute the LGDT instruction to load the GDTR register with the base address of the GDT.
  3. Execute a MOV CR0 instruction that sets the PE flag (and optionally the PG flag) in control register CR0.
  4. Immediately following the MOV CR0 instruction, execute a far JMP or far CALL instruction. (This operation is typically a far jump or call to the next instruction in the instruction stream.)
  5. The JMP or CALL instruction immediately after the MOV CR0 instruction changes the flow of execution and serializes the processor.
  6. If paging is enabled, the code for the MOV CR0 instruction and the JMP or CALL instruction must come from a page that is identity mapped (that is, the linear address before the jump is the same as the physical address after paging and protected mode is enabled). The target instruction for the JMP or CALL instruction does not need to be identity mapped.
  7. If a local descriptor table is going to be used, execute the LLDT instruction to load the segment selector for the LDT in the LDTR register.
  8. Execute the LTR instruction to load the task register with a segment selector to the initial protected-mode task or to a writable area of memory that can be used to store TSS information on a task switch.
  9. After entering protected mode, the segment registers continue to hold the contents they had in real-address mode. The JMP or CALL instruction in step 4 resets the CS register. Perform one of the following operations to update the contents of the remaining segment registers. — Reload segment registers DS, SS, ES, FS, and GS. If the ES, FS, and/or GS registers are not going to be used, load them with a null selector. — Perform a JMP or CALL instruction to a new task, which automatically resets the values of the segment registers and branches to a new code segment.
  10. Execute the LIDT instruction to load the IDTR register with the address and limit of the protected-mode IDT.
  11. Execute the STI instruction to enable maskable hardware interrupts and perform the necessary hardware operation to enable NMI interrupts. Random failures can occur if other instructions exist between steps 3 and 4 above. Failures will be readily seen in some situations, such as when instructions that reference memory are inserted between steps 3 and 4 while in system management mode.
  • Has the bug been acknowledged as an erratum by Intel, or otherwise confirmed by others? If so, could you add references? If not, this is a bold claim. – Nate Eldredge Jul 10 '21 at 20:22
  • https://www.intel.co.jp/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-vol-3a-part-1-manual.pdf Very quick comments (LOL) See here for references Link –  Jul 10 '21 at 20:25