Hello! There is the following Assembler code loaded into memory at 0x7E00:

use16 global start1 extern kernel_start start1: jmp 0x0000:entry entry: mov ax, cs mov ds, ax ;ΠΎΡ‡ΠΈΡΡ‚ΠΈΡ‚ΡŒ экран mov ax, 0x0003 int 0x10 ;ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚ΡŒ A20 in al, 0x92 or al, 2 out 0x92, al ;Π—Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ адрСс ΠΈ Ρ€Π°Π·ΠΌΠ΅Ρ€ GDT Π² GDTR lgdt [gdtr] ;Π—Π°ΠΏΡ€Π΅Ρ‚ΠΈΡ‚ΡŒ прСрывания cli ;Π—Π°ΠΏΡ€Π΅Ρ‚ΠΈΡ‚ΡŒ нСмаскируСмыС прСрывания in al, 0x70 or al, 0x80 out 0x70, al ;ΠŸΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒΡΡ Π² Π·Π°Ρ‰ΠΈΡ‰Π΅Π½Π½Ρ‹ΠΉ Ρ€Π΅ΠΆΠΈΠΌ mov eax, cr0 or al, 1 mov cr0, eax ;Π—Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ Π² CS:EIP Ρ‚ΠΎΡ‡ΠΊΡƒ Π²Ρ…ΠΎΠ΄Π° Π² Π·Π°Ρ‰ΠΈΡ‰Π΅Π½Π½Ρ‹ΠΉ Ρ€Π΅ΠΆΠΈΠΌ O32 jmp 00001000b:pm_entry ;32-битная адрСсация use32 ;Π’ΠΎΡ‡ΠΊΠ° Π²Ρ…ΠΎΠ΄Π° Π² Π·Π°Ρ‰ΠΈΡ‰Π΅Π½Π½Ρ‹ΠΉ Ρ€Π΅ΠΆΠΈΠΌ pm_entry: ;Π—Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ сСгмСнтныС рСгистры (ΠΊΡ€ΠΎΠΌΠ΅ SS) mov ax, cs mov ds, ax mov es, ax mov edi, 0xB8000 ;Π½Π°Ρ‡Π°Π»ΠΎ видСопамяти Π² Π²ΠΈΠ΄Π΅ΠΎΡ€Π΅ΠΆΠΈΠΌΠ΅ 0x3 mov esi, msg ;Π²Ρ‹Π²ΠΎΠ΄ΠΈΠΌΠΎΠ΅ сообщСниС cld loop: ;Ρ†ΠΈΠΊΠ» Π²Ρ‹Π²ΠΎΠ΄Π° сообщСния lodsb ;считываСм ΠΎΡ‡Π΅Ρ€Π΅Π΄Π½ΠΎΠΉ символ строки test al, al ;Ссли встрСтили 0 jz exit ;ΠΏΡ€Π΅ΠΊΡ€Π°Ρ‰Π°Π΅ΠΌ Π²Ρ‹Π²ΠΎΠ΄ stosb ;ΠΈΠ½Π°Ρ‡Π΅ Π²Ρ‹Π²ΠΎΠ΄ΠΈΠΌ ΠΎΡ‡Π΅Ρ€Π΅Π΄Π½ΠΎΠΉ символ mov al, 7 ;ΠΈ Π΅Π³ΠΎ Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚ Π² Π²ΠΈΠ΄Π΅ΠΎΠΏΠ°ΠΌΡΡ‚ΡŒ stosb jmp loop exit: jmp $ ;зависаСм msg: db 'Hello World!', 0 ;Π“Π»ΠΎΠ±Π°Π»ΡŒΠ½Π°Ρ Ρ‚Π°Π±Π»ΠΈΡ†Π° дСскрипторов. gdt: db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 db 0xFF, 0xFF, 0x00, 0x00, 0x00, 10011010b, 11001111b, 0x00 gdt_size equ $ - gdt ;Π΄Π°Π½Π½Ρ‹Π΅, Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌΡ‹Π΅ Π² рСгистр GDTR gdtr: dw gdt_size - 1 dd gdt 

It is almost completely copied from this article: https://habrahabr.ru/post/104988/ . As far as I understand, he should create a code segment with a limit of 0xFFFF + 1010b and a base at 0x00, then output "Hello world!" directly to video memory. But in the end, after compiling and running this code, QEMU reloads indefinitely - displays QEMU reloads indefinitely

sometimes it still has time to go out "Booting from floppy ..." and the screen is cleared, then again it all comes out and clears and so endlessly. I think the problem is that the author of the article has this code in the 1st loader at 0x7C00, and I in the 2nd one, at 0x7E00. But I'm not sure. Please help me figure it out.

UPD

 00000000 <start1>: 0: ea .byte 0xea 1: 05 .byte 0x5 2: 00 00 add BYTE PTR [eax],al ... 00000005 <entry>: 5: b8 03 00 cd 10 mov eax,0x10cd0003 a: e4 92 in al,0x92 c: 0c 02 or al,0x2 e: e6 92 out 0x92,al 10: 0f 01 16 lgdtd [esi] 13: 73 00 jae 15 <entry+0x10> 15: fa cli 16: e4 70 in al,0x70 18: 0c 80 or al,0x80 1a: e6 70 out 0x70,al 1c: 0f 20 c0 mov eax,cr0 1f: 0c 01 or al,0x1 21: 0f 22 c0 mov cr0,eax 24: 66 ea 2a 00 00 7e jmp 0x7e00:0x2a 0000002a <pm_entry>: 2a: 66 b8 08 00 mov ax,0x8 2e: 8e c8 mov cs,eax 30: 66 b8 10 00 mov ax,0x10 34: 8e d8 mov ds,eax 36: bf 00 80 0b 00 mov edi,0xb8000 3b: be 4e 00 00 00 mov esi,0x4e 40: fc cld 00000041 <loop>: 41: ac lods al,BYTE PTR ds:[esi] 42: 84 c0 test al,al 44: 74 06 je 4c <exit> 46: aa stos BYTE PTR es:[edi],al 47: b0 07 mov al,0x7 49: aa stos BYTE PTR es:[edi],al 4a: eb f5 jmp 41 <loop> 0000004c <exit>: 4c: eb fe jmp 4c <exit> 0000004e <msg>: 4e: 48 dec eax 4f: 65 6c gs ins BYTE PTR es:[edi],dx 51: 6c ins BYTE PTR es:[edi],dx 52: 6f outs dx,DWORD PTR ds:[esi] 53: 20 57 6f and BYTE PTR [edi+0x6f],dl 56: 72 6c jb c4 <kernel_start+0x4b> 58: 64 21 00 and DWORD PTR fs:[eax],eax 0000005b <gdt>: ... 63: ff (bad) 64: ff 00 inc DWORD PTR [eax] 66: 00 00 add BYTE PTR [eax],al 68: 9a cf 00 ff ff 00 00 call 0x0:0xffff00cf 6f: 00 .byte 0x0 70: 92 xchg edx,eax 71: cf iret ... 00000073 <gdtr>: 73: 17 pop ss 74: 00 5b 00 add BYTE PTR [ebx+0x0],bl ... 00000079 <kernel_start>: 79: 66 55 push bp 7b: 66 89 e5 mov bp,sp 7e: 66 83 ec 10 sub sp,0x10 82: 67 66 c7 45 fc 00 80 mov WORD PTR [di-0x4],0x8000 89: 0b 00 or eax,DWORD PTR [eax] 8b: 67 66 c7 45 f8 00 00 mov WORD PTR [di-0x8],0x0 92: 00 00 add BYTE PTR [eax],al 94: eb 2d jmp c3 <kernel_start+0x4a> 96: 67 66 8b 55 f8 mov dx,WORD PTR [di-0x8] 9b: 67 66 8b 45 fc mov ax,WORD PTR [di-0x4] a0: 66 01 d0 add ax,dx a3: 67 c6 00 21 mov BYTE PTR [bx+si],0x21 a7: 67 66 8b 45 f8 mov ax,WORD PTR [di-0x8] ac: 67 66 8d 50 01 lea dx,[bx+si+0x1] b1: 67 66 8b 45 fc mov ax,WORD PTR [di-0x4] b6: 66 01 d0 add ax,dx b9: 67 c6 00 0f mov BYTE PTR [bx+si],0xf bd: 67 66 83 45 f8 02 add WORD PTR [di-0x8],0x2 c3: 67 66 81 7d f8 9f 0f cmp WORD PTR [di-0x8],0xf9f ca: 00 00 add BYTE PTR [eax],al cc: 7e c8 jle 96 <kernel_start+0x1d> ce: 90 nop cf: 66 c9 leavew d1: 66 c3 retw 
  • one
    I can not understand how the code of these authors can work. The GDT defines a single descriptor and the type of segment 101 is a code segment with read and execute access. writing in such a segment is impossible. And for some reason they are trying to make a conclusion on the screen through the same segment. This should result in a violation of general protection. At a minimum, you also need to define a data segment, which in principle can also be done on the entire address space and loaded into the DS, ES selector of this segment ... - Mike
  • In general, when trying to enter protected mode, the program should be debugged by ear, just make sure in real mode that you can play the sound through the speaker and that you can really hear it. After that, at key points you place a choice of different frequencies and, using audible notes, determine where they are hanging. This is the only available way to transfer information until you have debugged work with GDT and new selectors - Mike
  • one
    And why by the way all this is done in the bootloader. Debug the transition to PM with a regular program started from dos. when earned transfer to bootloader - Mike
  • @Mike I tried to add a data segment descriptor and load ds with this descriptor selector - no reaction. Added a dump. - wcobalt
  • Why is it so interesting to jump so strange it came out jmp 0x7e00:0x2a it should have been loaded into cs 8, i.e. he should have been about 8:7e02a . - Mike

1 answer 1

An endless reboot when attempting to enter protected mode arises due to a triple error. Which arises at this stage because of any error in the code. Whether it is an incorrect instruction or an inaccessible memory address. If an error occurs, the processor tries to call the exception handler, but the protected mode interrupt table is not yet defined, then the processor tries to call the double error exception handler (int 8), but also cannot do this, after which it tries to shut down, to which the motherboards and emulators start reboot.

In the source from which you took the sample code, a gross error was made (not everything on the Internet can be trusted, always refer to the original sources, documentation on the processor). They try to record in the video memory using the selector of the code segment. In protected mode, writing to code segments is impossible and results in the exclusion of general protection. You need to create another descriptor in GDT that also describes the entire memory, but with the type (bits 41-43) "001" - a data segment that can be read and written and used to access the text of the message and the video memory selector of this descriptor.

In addition, following the results of the chat correspondence, it was found that such experiments in the bootstrap code are fraught with other problems. Firstly, not all assemblers are equally useful (or do we just not know how to prepare them?). The TS assembler on the instruction O32 jmp 00001000b:pm_entry generated an impossible opcode. I used the 32-bit prefix (66) but the address of the transition was encoded in two bytes, instead of four. A normal instruction for a long, 32-bit jumper from a 16-bit mode should look like 66 EA 4Ρ…-Π±Π°ΠΉΡ‚Π½ΠΎΠ΅-смСщСниС 2Ρ…-Π±Π°ΠΉΡ‚Π½Ρ‹ΠΉ-сСлСктор .

The second problem turned out to be that the bootloader did not load the code into the addresses that the linker assumed when building, as a result, the wrong GDT address was loaded and jmp did not go where it was expected. Therefore, when debugging the initial load, always check which addresses your code actually hit (for example, display your current address on the screen). And specify the correct address linker.

As a demonstration, the working code is not dependent on the download address (it corrects all the addresses depending on the position in the memory). In order to allow yourself a few extra instructions at the beginning, it is expected that the download will occur in a section aligned to 16 bytes. The bootloader is unlikely to load differently. NASM dialect.

 ; Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΈΠ²Ρ‹ ORG Π½Π΅Ρ‚, ΠΊΠΎΠ΄ рассчитан Π½Π° сборку Π»ΠΈΠ½ΠΊΠ΅Ρ€ΠΎΠΌ ΠΏΠΎ 0 ΡΠΌΠ΅Ρ‰Π΅Π½ΠΈΡŽ [BITS 16] entry: call get_ip ; ΠŸΠΎΠΌΠ΅Ρ‰Π°Π΅ΠΌ Π² стСк адрСс, ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ Π·Π° Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ инструкциСй get_ip: mov ax, 0x0003 int 0x10 ; очистка экрана xor ebx,ebx ; Π½Π°Π΄ΠΎ ΠΎΡ‡ΠΈΡΡ‚ΠΈΡ‚ΡŒ ΡΡ‚Π°Ρ€ΡˆΡƒΡŽ Ρ‡Π°ΡΡ‚ΡŒ ebx, Π½Π° Π±ΡƒΠ΄ΡƒΡ‰Π΅Π΅ для 32-bit Ρ€Π΅ΠΆΠΈΠΌΠ° pop bx ; достаСм Π² BX ΠΈΠ· стСка адрСс инструкции Π² Π½Π°Ρ‡Π°Π»Π΅ and bx,0xFFF0 ; отбрасываСм Ρ€Π°Π·ΠΌΠ΅Ρ€ ΠΏΠ΅Ρ€Π²Ρ‹Ρ… инструкций ; Π΄Π°Π»Π΅Π΅ ΠΏΠΎ ΠΊΠΎΠ΄Ρƒ BX Π±ΠΎΠ»Π΅Π΅ Π½ΠΈ для Ρ‡Π΅Π³ΠΎ Π½Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ, ; Π² Π½Π΅ΠΌ Π²Π΅Π»ΠΈΡ‡ΠΈΠ½Π° ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ†ΠΈΠΈ полоТСния mov ax, cs mov ds, ax mov ax, [jmp_addr+bx+2] ; достаСм смСщСниС ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄Π° ΠΈΠ· инструкции jmp dword ; 2 Π±Π°ΠΉΡ‚Π° ΠΏΡ€ΠΎΠΏΡƒΡ‰Π΅Π½ΠΎ ΠΎΡ‚ ΠΌΠ΅Ρ‚ΠΊΠΈ Ρ‚.ΠΊ. Ρ‚Π°ΠΌ 66 EA add ax, bx ; ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚ΠΈΡ€ΡƒΠ΅ΠΌ адрСс mov [jmp_addr+bx+2], ax ; пишСм ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ Π² ΠΈΠ½ΡΡ‚Ρ€ΡƒΠΊΡ†ΠΈΡŽ jmp mov ax, [gdt_addr+bx] ; Π±Π΅Ρ€Π΅ΠΌ адрСс GDT add ax, bx ; ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚ΠΈΡ€ΡƒΠ΅ΠΌ mov [gdt_addr+bx], ax ; ΠΊΠ»Π°Π΄Π΅ΠΌ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ jmp flush_conv ; Ρ‚.ΠΊ. ΠΌΡ‹ ΠΏΡ€Π°Π²ΠΈΠ»ΠΈ собствСнный ΠΊΠΎΠ΄, Π΄Π΅Π»Π°Π΅ΠΌ ΠΊΠΎΡ€ΠΎΡ‚ΠΊΠΈΠΉ jmp flush_conv: ; для очистки ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ ΠΊΠΎΠΌΠ°Π½Π΄ процСссора in al, 0x92 or al, 2 out 0x92, al ; ΠΎΡ‚ΠΊΡ€Ρ‹Π²Π°Π΅ΠΌ A20 lgdt [gdtr+bx] cli in al, 0x70 or al, 0x80 out 0x70, al ; Π·Π°ΠΏΡ€Π΅Ρ‰Π°Π΅ΠΌ NMI mov eax, cr0 or al, 1 mov cr0, eax ; Π·Π°Ρ‰ΠΈΡ‰Π΅Π½Π½Ρ‹ΠΉ Ρ€Π΅ΠΆΠΈΠΌ ! jmp_addr: jmp dword 8:pm_entry ; Π΄Π»ΠΈΠ½Π½Ρ‹ΠΉ ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ для Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ Π½ΠΎΠ²ΠΎΠ³ΠΎ сСлСктора Π² CS [BITS 32] pm_entry: mov eax, 0x10 ; сСлСктор сСгмСнта Π΄Π°Π½Π½Ρ‹Ρ… mov ds, ax ; Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ Π²ΠΎ всС сСгмСнтныС рСгистры mov es, ax ; Ρ‡Ρ‚ΠΎ Π±Ρ‹ Π½Π΅ ΠΎΡΡ‚Π°Π²Π»ΡΡ‚ΡŒ значСния ΠΈΠ· Ρ€Π΅Π°Π»ΡŒΠ½ΠΎΠ³ΠΎ Ρ€Π΅ΠΆΠΈΠΌΠ° mov fs, ax ; ΠΏΠΎ Ρ…ΠΎΡ€ΠΎΡˆΠ΅ΠΌΡƒ Π½Π°Π΄ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΉ сСгмСнт для стСка mov gs, ax ; ΠΈ Π΅Π³ΠΎ сСлСктор Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ Π² ss ; Π½ΠΎ ΠΌΡ‹ этого Π½Π΅ Π΄Π΅Π»Π°Π΅ΠΌ, поэтому стСком ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ нСльзя lea edi, [msg+ebx] ; адрСс сообщСния, Π½Π΅ Π·Π°Π±Ρ‹Π²Π°Π΅ΠΌ ΡΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ mov esi, 0xb8000 ; Π»ΠΈΠ½Π΅ΠΉΠ½ΠΎΠ΅ смСщСниС видСопамяти mov ah, 7 ; Ρ†Π²Π΅Ρ‚ символов сСрый Π½Π° Ρ‡Π΅Ρ€Π½ΠΎΠΌ print: mov al, [ds:edi] test al,al jz exit mov [ds:esi], ax inc esi inc esi inc edi jmp print exit: JMP $ ; зависаСм msg db 'In protected mode !',0 align 16 ; GDT Π»ΡƒΡ‡ΡˆΠ΅ Π²Ρ‹Ρ€ΠΎΠ²Π½ΡΡ‚ΡŒ Π½Π° 16 Π±Π°ΠΉΡ‚, для облСгчСния ΠΆΠΈΠ·Π½ΠΈ процСссору gdt: db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ; Zero дСскриптор db 0xFF, 0xFF, 0x00, 0x00, 0x00, 10011010b, 11001111b, 0x00 ; Π‘Π΅Π³ΠΌΠ΅Π½Ρ‚ ΠΊΠΎΠ΄Π° db 0xFF, 0xFF, 0x00, 0x00, 0x00, 10010010b, 11001111b, 0x00 ; Π‘Π΅Π³ΠΌΠ΅Π½Ρ‚ Π΄Π°Π½Π½Ρ‹Ρ… gdt_size equ $ - gdt gdtr: ; пСрСмСнная для Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ GDT dw gdt_size - 1 gdt_addr: ; Ρ‚ΠΎΡ‡ΠΊΠ° для ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ†ΠΈΠΈ адрСса GDT dd gdt TIMES 510 - ($ - $$) db 0 ; Π΄ΠΎΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π΄ΠΎ Ρ€Π°Π·ΠΌΠ΅Ρ€Π° сСктора DW 0xAA55 ; ΠΏΡ€ΠΈΠ·Π½Π°ΠΊ Π·Π°Π³Ρ€ΡƒΠ·ΠΎΡ‡Π½ΠΎΠ³ΠΎ сСктора 
  • to my great regret, this code does not work. QEMU is still rebooting. Dump: pastebin.com/3PNCCyqD - wcobalt
  • @wcobalt load it to start with just that it would be the boot sector. and see if it works or not. And I gave you the code to print the values. Display the cs register. You had some strange correction in the old code. perhaps you call this code with a non-zero cs and then you will need to take it into account in the offset. in principle, if it is not null, return the jmp from which your code began - Mike
  • @wcobalt It is also interesting to see in the disassembler the point that the control passes from this C-code to this section of the code - Mike
  • In the loader still does not work. With jmp 0x0000 added: label too. What point are you talking about? - wcobalt