1+ ;
2+ ; Protected Mode BIOS Call Functionailty v2.0 - by Napalm
3+ ; -------------------------------------------------------
4+ ;
5+ ; This is code shows how its POSSIBLE to execute BIOS interrupts
6+ ; by switch out to real-mode and then back into protected mode.
7+ ;
8+ ; If you wish to use all or part of this code you must agree
9+ ; to the license at the following URL.
10+ ;
11+ ; License: http://creativecommons.org/licenses/by-sa/2.0/uk/
12+ ;
13+ ; Notes: This file is in NASM syntax.
14+ ; Turn off paging before calling these functions.
15+ ; int32() resets all selectors.
16+ ;
17+ ; C Prototype:
18+ ; void _cdelc int32(unsigned char intnum, regs16_t *regs);
19+ ;
20+ ; Example of usage:
21+ ; regs.ax = 0x0013;
22+ ; int32(0x10, ®s);
23+ ; memset((char *)0xA0000, 1, (320*200));
24+ ; memset((char *)0xA0000 + (100*320+80), 14, 80);
25+ ; regs.ax = 0x0000;
26+ ; int32(0x16, ®s);
27+ ; regs.ax = 0x0003;
28+ ; int32(0x10, ®s);
29+ ;
30+ ;
31+ [bits 32]
32+
33+ global int32 , _int32
34+
35+ struc regs16_t
36+ . di resw 1
37+ . si resw 1
38+ . bp resw 1
39+ . sp resw 1
40+ . bx resw 1
41+ . dx resw 1
42+ . cx resw 1
43+ . ax resw 1
44+ . gs resw 1
45+ . fs resw 1
46+ . es resw 1
47+ . ds resw 1
48+ .ef resw 1
49+ endstruc
50+
51+ %define INT32_BASE 0x7C00
52+ %define REBASE(x) (((x) - reloc) + INT32_BASE)
53+ %define GDTENTRY(x) ((x) << 3 )
54+ %define CODE32 GDTENTRY( 1 ) ; 0x08
55+ %define DATA32 GDTENTRY( 2 ) ; 0x10
56+ %define CODE16 GDTENTRY( 3 ) ; 0x18
57+ %define DATA16 GDTENTRY( 4 ) ; 0x20
58+ %define STACK16 (INT32_BASE - regs16_t_size)
59+
60+
61+ section .text
62+ int32: use32 ; by Napalm
63+ _int32:
64+ cli ; disable interrupts
65+ pusha ; save register state to 32bit stack
66+ mov esi , reloc ; set source to code below
67+ mov edi , INT32_BASE ; set destination to new base address
68+ mov ecx , (int32_end - reloc) ; set copy size to our codes size
69+ cld ; clear direction flag (so we copy forward)
70+ rep movsb ; do the actual copy (relocate code to low 16bit space)
71+ jmp INT32_BASE ; jump to new code location
72+ reloc: use32 ; by Napalm
73+ mov [ REBASE(stack32_ptr) ], esp ; save 32bit stack pointer
74+ sidt [ REBASE(idt32_ptr) ] ; save 32bit idt pointer
75+ sgdt [ REBASE(gdt32_ptr) ] ; save 32bit gdt pointer
76+ lgdt [ REBASE(gdt16_ptr) ] ; load 16bit gdt pointer
77+ lea esi , [ esp + 0x24 ] ; set position of intnum on 32bit stack
78+ lodsd ; read intnum into eax
79+ mov [ REBASE(ib) ], al ; set intrrupt immediate byte from our arguments
80+ mov esi , [ esi ] ; read regs pointer in esi as source
81+ mov edi , STACK16 ; set destination to 16bit stack
82+ mov ecx , regs16_t_size ; set copy size to our struct size
83+ mov esp , edi ; save destination to as 16bit stack offset
84+ rep movsb ; do the actual copy (32bit stack to 16bit stack)
85+ jmp word CODE16:REBASE(p_mode16) ; switch to 16bit selector (16bit protected mode)
86+ p_mode16: use16
87+ mov ax , DATA16 ; get our 16bit data selector
88+ mov ds , ax ; set ds to 16bit selector
89+ mov es , ax ; set es to 16bit selector
90+ mov fs , ax ; set fs to 16bit selector
91+ mov gs , ax ; set gs to 16bit selector
92+ mov ss , ax ; set ss to 16bit selector
93+ mov eax , cr0 ; get cr0 so we can modify it
94+ and al , ~ 0x01 ; mask off PE bit to turn off protected mode
95+ mov cr0 , eax ; set cr0 to result
96+ jmp word 0x0000 :REBASE(r_mode16) ; finally set cs:ip to enter real-mode
97+ r_mode16: use16
98+ xor ax , ax ; set ax to zero
99+ mov ds , ax ; set ds so we can access idt16
100+ mov ss , ax ; set ss so they the stack is valid
101+ lidt [ REBASE(idt16_ptr) ] ; load 16bit idt
102+ mov bx , 0x0870 ; master 8 and slave 112
103+ call resetpic ; set pic's the to real-mode settings
104+ popa ; load general purpose registers from 16bit stack
105+ pop gs ; load gs from 16bit stack
106+ pop fs ; load fs from 16bit stack
107+ pop es ; load es from 16bit stack
108+ pop ds ; load ds from 16bit stack
109+ sti ; enable interrupts
110+ db 0xCD ; opcode of INT instruction with immediate byte
111+ ib: db 0x00
112+ cli ; disable interrupts
113+ xor sp , sp ; zero sp so we can reuse it
114+ mov ss , sp ; set ss so the stack is valid
115+ mov sp , INT32_BASE ; set correct stack position so we can copy back
116+ pushf ; save eflags to 16bit stack
117+ push ds ; save ds to 16bit stack
118+ push es ; save es to 16bit stack
119+ push fs ; save fs to 16bit stack
120+ push gs ; save gs to 16bit stack
121+ pusha ; save general purpose registers to 16bit stack
122+ mov bx , 0x2028 ; master 32 and slave 40
123+ call resetpic ; restore the pic's to protected mode settings
124+ mov eax , cr0 ; get cr0 so we can modify it
125+ inc eax ; set PE bit to turn on protected mode
126+ mov cr0 , eax ; set cr0 to result
127+ jmp dword CODE32:REBASE(p_mode32) ; switch to 32bit selector (32bit protected mode)
128+ p_mode32: use32
129+ mov ax , DATA32 ; get our 32bit data selector
130+ mov ds , ax ; reset ds selector
131+ mov es , ax ; reset es selector
132+ mov fs , ax ; reset fs selector
133+ mov gs , ax ; reset gs selector
134+ mov ss , ax ; reset ss selector
135+ lgdt [ REBASE(gdt32_ptr) ] ; restore 32bit gdt pointer
136+ lidt [ REBASE(idt32_ptr) ] ; restore 32bit idt pointer
137+ mov esp , [ REBASE(stack32_ptr) ] ; restore 32bit stack pointer
138+ mov esi , STACK16 ; set copy source to 16bit stack
139+ lea edi , [ esp + 0x28 ] ; set position of regs pointer on 32bit stack
140+ mov edi , [ edi ] ; use regs pointer in edi as copy destination
141+ mov ecx , regs16_t_size ; set copy size to our struct size
142+ cld ; clear direction flag (so we copy forward)
143+ rep movsb ; do the actual copy (16bit stack to 32bit stack)
144+ popa ; restore registers
145+ sti ; enable interrupts
146+ ret ; return to caller
147+
148+ resetpic: ; reset's 8259 master and slave pic vectors
149+ push ax ; expects bh = master vector, bl = slave vector
150+ mov al , 0x11 ; 0x11 = ICW1_INIT | ICW1_ICW4
151+ out 0x20 , al ; send ICW1 to master pic
152+ out 0xA0 , al ; send ICW1 to slave pic
153+ mov al , bh ; get master pic vector param
154+ out 0x21 , al ; send ICW2 aka vector to master pic
155+ mov al , bl ; get slave pic vector param
156+ out 0xA1 , al ; send ICW2 aka vector to slave pic
157+ mov al , 0x04 ; 0x04 = set slave to IRQ2
158+ out 0x21 , al ; send ICW3 to master pic
159+ shr al , 1 ; 0x02 = tell slave its on IRQ2 of master
160+ out 0xA1 , al ; send ICW3 to slave pic
161+ shr al , 1 ; 0x01 = ICW4_8086
162+ out 0x21 , al ; send ICW4 to master pic
163+ out 0xA1 , al ; send ICW4 to slave pic
164+ pop ax ; restore ax from stack
165+ ret ; return to caller
166+
167+ stack32_ptr: ; address in 32bit stack after we
168+ dd 0x00000000 ; save all general purpose registers
169+
170+ idt32_ptr: ; IDT table pointer for 32bit access
171+ dw 0x0000 ; table limit (size)
172+ dd 0x00000000 ; table base address
173+
174+ gdt32_ptr: ; GDT table pointer for 32bit access
175+ dw 0x0000 ; table limit (size)
176+ dd 0x00000000 ; table base address
177+
178+ idt16_ptr: ; IDT table pointer for 16bit access
179+ dw 0x03FF ; table limit (size)
180+ dd 0x00000000 ; table base address
181+
182+ gdt16_base: ; GDT descriptor table
183+ .null: ; 0x00 - null segment descriptor
184+ dd 0x00000000 ; must be left zero'd
185+ dd 0x00000000 ; must be left zero'd
186+
187+ .code32: ; 0x01 - 32bit code segment descriptor 0xFFFFFFFF
188+ dw 0xFFFF ; limit 0:15
189+ dw 0x0000 ; base 0:15
190+ db 0x00 ; base 16:23
191+ db 0x9A ; present, iopl/0, code, execute/read
192+ db 0xCF ; 4Kbyte granularity, 32bit selector; limit 16:19
193+ db 0x00 ; base 24:31
194+
195+ .data32: ; 0x02 - 32bit data segment descriptor 0xFFFFFFFF
196+ dw 0xFFFF ; limit 0:15
197+ dw 0x0000 ; base 0:15
198+ db 0x00 ; base 16:23
199+ db 0x92 ; present, iopl/0, data, read/write
200+ db 0xCF ; 4Kbyte granularity, 32bit selector; limit 16:19
201+ db 0x00 ; base 24:31
202+
203+ .code16: ; 0x03 - 16bit code segment descriptor 0x000FFFFF
204+ dw 0xFFFF ; limit 0:15
205+ dw 0x0000 ; base 0:15
206+ db 0x00 ; base 16:23
207+ db 0x9A ; present, iopl/0, code, execute/read
208+ db 0x0F ; 1Byte granularity, 16bit selector; limit 16:19
209+ db 0x00 ; base 24:31
210+
211+ .data16: ; 0x04 - 16bit data segment descriptor 0x000FFFFF
212+ dw 0xFFFF ; limit 0:15
213+ dw 0x0000 ; base 0:15
214+ db 0x00 ; base 16:23
215+ db 0x92 ; present, iopl/0, data, read/write
216+ db 0x0F ; 1Byte granularity, 16bit selector; limit 16:19
217+ db 0x00 ; base 24:31
218+
219+ gdt16_ptr: ; GDT table pointer for 16bit access
220+ dw gdt16_ptr - gdt16_base - 1 ; table limit (size)
221+ dd gdt16_base ; table base address
222+
223+ int32_end: ; end marker (so we can copy the code)
224+
225+
0 commit comments