Я хотел бы реализовать режим Unreal (доступ ко всей памяти 4 ГБ) с NASM в DOS. Я нашел реализацию TASM:
.386p
RealSeg Segment Para Public Use16
Assume cs:RealSeg, ds:RalSeg
Real_Start:
cli
push cs
pop ds
mov ax,3
int 10h
mov ah,9
lea dx,Ex5_Str
int 21h
mov eax,cs
shl eax,4
add GDT_Base,eax
lgdt GDT_Value
mov eax,CR0
or al,1
mov CR0,eax
jmp $+2
mov ax,Real4G
mov es,ax
mov eax,CR0
and al,not 1
mov CR0,eax
jmp $+2
mov eax,'AAAA'
mov ecx,40
mov edi,0b8000h
L1:
mov es:[edi],eax
add edi,4
loop L1
mov ah,4ch
int 21h
Exit:
mov ah,9
int 21h
mov ah,4ch
int 21h
Ex5_Str db 10,13,10,13
db '4GB memory OK',10,13,36
RelSeg Ends
StackSeg Segment Stack Use16
db 400h dup (?)
StackSeg Ends
End Real_Start
Или вот реализация FASM:
struc GDT_STR
s0_15 dw ?
b0_15 dw ?
b16_23 db ?
flags db ?
access db ?
b24_31 db ?
ENDS
SEGMENT CODE16 USE16 PUBLIC
ASSUME CS:CODE16
; GDT definitions
gdt_start dw gdt_size
gdt_ptr dd 0
dummy_descriptor GDT_STR <0,0,0,0,0,0>
code16_descriptor GDT_STR <0ffffh,0,0,9ah,0,0> ; 64k 16-bit code
data32_descriptor GDT_STR <0ffffh,0,0,92h,0cfh,0> ; 4GB 32-bit data, 92h = 10010010b = Presetn , DPL 00, No System, Data Read/Write
gdt_size = $-(dummy_descriptor)
dummy_idx = 0h ; dummy selector
code16_idx = 08h ; offset of 16-bit code segment in GDT
data32_idx = 10h ; offset of 32-bit data segment in GDT
PUBLIC _EnterUnreal
PROC _EnterUnreal FAR
PUSHAD
PUSH DS
PUSH CS
POP DS
mov ax,CODE16 ; get 16-bit code segment into AX
shl eax,4 ; make a physical address
mov [ds:code16_descriptor.b0_15],ax ; store it in the dscr
shr eax,8
mov [ds:code16_descriptor.b16_23],ah
XOR eax,eax
mov [ds:data32_descriptor.b0_15],ax ; store it in the dscr
mov [ds:data32_descriptor.b16_23],ah
; Set gdt ptr
xor eax,eax
mov ax,CODE16
shl eax,4
add ax,offset dummy_descriptor
mov [gdt_ptr],eax
cli
mov bx,offset gdt_start
lgdt [bx]
mov eax,cr0
or al,1
mov cr0,eax
mov ax,data32_idx
mov fs,ax
mov eax,cr0
and al,not 1
mov cr0,eax
MOV AX,0
MOV FS,AX
POP DS
POPAD
RETF
ENDP
Я хотел бы использовать NASM, но очень сложно перевести приведенные ниже инструкции на NASM:
Есть ли у кого-нибудь работающая реализация режима NASM Unreal? Или может кто-нибудь помочь перевести любой из приведенных выше примеров на NASM?
Если вы расстроены, это jmp $+2 можно записать как db 0xEB 0x00. Я не особенно рекомендую это, но будет работать.
@Джошуа: Или jmp next_insn/next_insn:, чтобы сделать это с помощью ярлыка.
Единственное, чего я не понимаю, так это зачем вам нужны эти инструкции jmp. Поскольку идея здесь состоит в том, чтобы загрузить сегменты с разблокированными смещениями и вернуться в реальный режим, я бы подумал, что вам не нужны инструкции jmp, поскольку мы хотим продолжать декодировать 16-битные инструкции, несмотря на переход на 32-битные. Если бы мы уже декодировали 32-битную версию, вывод ассемблера для mov ax,Real4G определенно был бы неверным, потому что он этого не знает.
Близкий прыжок в любом случае не перезагружает сегмент.
@Jester Кажется, это «большой нереальный» режим только с 32-битным сегментом данных. Никакой регистр сегмента кода не требует перезагрузки. Была рекомендация Intel объявить конвейер недействительным, поэтому короткого перехода было достаточно. Я не знаю, актуально ли это для современных процессоров.
Этот код создает программу DOS COM, которая переходит в реальный режим и выводит на дисплей, используя плоский дескриптор. pastebin.com/68W8cn0d . Обратите внимание, что это плохая реализация, поскольку внешнее прерывание или вызов BIOS/DOS могут выйти из нереального режима. Режим Unreal лучше всего использовать по требованию. Код также должен проверить, находитесь ли вы уже в защищенном режиме, вывести ошибку и выйти.





Вы можете создать структуру GDT_STR в NASM следующим образом:
struc GDT_STR
.s0_15: resw 1
.b0_15: resw 1
.b16_23: resb 1
.flags: resb 1
.access: resb 1
.b24_31: resb 1
endstruc
а затем вы создаете экземпляры этих структур следующим образом:
dummy_descriptor:
istruc GDT_STR
at .s0_15, dw 0
at .b0_15, dw 0
at .b16_23, db 0
at .flags, db 0
at .access, db 0
at .b24_31, db 0
iend
code32_descriptor:
istruc GDT_STR
at .s0_15, dw 0xffff
at .b0_15, dw 0
at .b16_23, db 0
at .flags, db 0x92
at .access, db 0xcf
at .b24_31, db 0
iend
jmp $+2 переходит к следующей инструкции в 16-битном коде. В контексте кода нереального режима относительный переход к следующей инструкции очищает очередь предварительной выборки инструкций. Вы можете заменить его чем-то вроде:
jmp next1 ; Flush the instruction prefetch queue
next1:
Код использует NASM для создания файла obj, который можно связать в исполняемый файл. Инструкции по сборке и компоновке см. в комментариях вверху кода.
; Assemble with
; nasm -f obj unreal.asm -o unreal.obj
;
; Link with Watcom Linker to unreal.exe
; wlink format dos file unreal.obj
;
; Or link with MS 16-bit segmented linker
; link16 unreal.obj;
;
; Or link with TLink (Turbo link)
; tlink unreal.obj
; Define GDT_STR - a GDT descriptor entry
struc GDT_STR
.s0_15: resw 1
.b0_15: resw 1
.b16_23: resb 1
.flags: resb 1
.access: resb 1
.b24_31: resb 1
endstruc
bits 16
segment data
align 4
gdt:
FLAT_SEL equ .flat - .start
.start:
.null:
istruc GDT_STR
at .s0_15, dw 0
at .b0_15, dw 0
at .b16_23, db 0
at .flags, db 0
at .access, db 0
at .b24_31, db 0
iend
.flat:
istruc GDT_STR
at .s0_15, dw 0xffff
at .b0_15, dw 0
at .b16_23, db 0
at .flags, db 0x92
at .access, db 0xcf
at .b24_31, db 0
iend
.end:
.gdtr:
dw .end - .start - 1
; limit (Size of GDT - 1)
dd .start ; base of GDT. Needs to be fixed up at runtime
in_pmode_str: db "Processor already in protected mode - exiting", 0x0a, 0x0d, "$"
section code
; ..start is a special label for the DOS entry point
..start:
; Save initial EFLAGS state
pushfd
cli
; Initialize DS to our DOS DATA segment (needed for EXEs)
; SS:SP will be set by the DOS EXE loader to our stack segment
mov ax, data
mov ds, ax
check_pmode:
smsw ax
test ax, 0x1 ; Check if we are already in protected mode
; This may be the case if we are in a VM8086 task.
; EMM386 and other expanded memory manager often
; run DOS in a VM8086 task. DOS extenders will have
; the same effect
jz not_prot_mode ; If not in protected mode proceed to switch
mov dx, in_pmode_str ; otherwise print an error and exit back to DOS
mov ah, 0x9
int 0x21 ; Print Error
jmp exit ; Exit program
not_prot_mode:
; Apply a fixup to the GDTR base to convert to a linear address
mov eax, ds
shl eax, 4
add [gdt.gdtr+2], eax
lgdt [gdt.gdtr] ; Load our GDT
mov cx, ds ; Save DS so it can be restored
mov eax, cr0
or al, 1
mov cr0, eax ; Set protected mode flag
jmp .next1 ; Flush the instruction pefetch queue
.next1:
; In 16-bit protected mode
; Since we aren't changing CS
; we don't need to enter 32-bit protected mode
mov bx, FLAT_SEL
mov ss, bx
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
and al, ~1
mov cr0, eax ; Unset protected mode flag
jmp .next2 ; Flush the instruction pefetch queue
.next2:
; Unreal mode here
; Restore SS=DS=ES
mov ss, cx
mov ds, cx
mov es, cx
; Print UNR to the screen using a flat 4GiB selector
; This code won't work in regular real mode
xor ax, ax
mov fs, ax
mov word fs:[dword 0xb8000+80*2*3+0], 0x57<<8 | 'U'
mov word fs:[dword 0xb8000+80*2*3+2], 0x57<<8 | 'N'
mov word fs:[dword 0xb8000+80*2*3+4], 0x57<<8 | 'R'
exit:
; Restore initial EFLAGS state
popfd
; DOS exit
mov ax, 0x4c00
int 0x21
segment stack stack
resb 1024
Примечание. Переход в нереальный режим не сработает, если процессор уже находится в защищенном режиме (т. е. выполняется как задача v8086). Это может быть в случае с EMM386, расширителями DOS и кодом, основанным на DPMI.
Я думал, что есть способ вернуть реальный режим из EMM386; таким образом, вы действительно можете перейти в защищенный режим. Или все было наоборот; вы можете получить 32-битный защищенный режим от EMM386 и принудительно отключить его.
@Joshua Интерфейс EMM для получения контроля над системой защищенного режима — VCPI. Однако хосты DPMI, такие как дозему и MSWindows, не предоставляют VCPI.
Я использую nasm-2.16.03, и когда я выполняю «nasm -f bin Unreal.asm -o Unreal.obj», я получаю следующее сообщение об ошибке: Unreal.asm:52: ошибка: нераспознанный специальный символ '..start'
@Fract: в комментариях была ошибка. Измените -f bin на -f obj. Затем вам нужно запустить компоновщик для создания EXE-файла. Я обновил ответ с исправлением.
jmp $+2в NASM то же самое, что и в MASM/TASM и FASM.$-(dummy_descriptor)тоже самое, но вместо FASM=нужноequв NASM. Как именно работает $ в NASM? . Что касается синтаксиса структуры, проверьте руководство NASM или просто сделайте это «вручную» без структур. nasm.us/doc/nasmdoc5.html#section-5.9