3 typedef unsigned char u8
;
4 typedef unsigned short u16
;
6 typedef unsigned long long u64
;
8 void test_function(void);
12 "mov $0x1234, %eax \n\t"
16 static int strlen(const char *str
)
20 for (n
= 0; *str
; ++str
)
25 static void print_serial(const char *buf
)
27 unsigned long len
= strlen(buf
);
29 asm volatile ("addr32/rep/outsb" : "+S"(buf
), "+c"(len
) : "d"(0xf1));
32 static void exit(int code
)
34 asm volatile("out %0, %1" : : "a"(code
), "d"((short)0xf4));
38 u32 eax
, ebx
, ecx
, edx
;
39 u32 esi
, edi
, esp
, ebp
;
45 0x00cf9b000000ffffull
, // flat 32-bit code segment
46 0x00cf93000000ffffull
, // flat 32-bit data segment
52 } __attribute__((packed
)) gdt_descr
= {
57 static void exec_in_big_real_mode(const struct regs
*inregs
,
59 const u8
*insn
, int insn_len
)
62 static struct regs save
;
64 extern u8 test_insn
[], test_insn_end
[];
66 for (i
= 0; i
< insn_len
; ++i
)
67 test_insn
[i
] = insn
[i
];
68 for (; i
< test_insn_end
- test_insn
; ++i
)
69 test_insn
[i
] = 0x90; // nop
73 "lgdtl %[gdt_descr] \n\t"
74 "mov %%cr0, %[tmp] \n\t"
76 "mov %[tmp], %%cr0 \n\t"
77 "mov %[bigseg], %%gs \n\t"
78 "and $-2, %[tmp] \n\t"
79 "mov %[tmp], %%cr0 \n\t"
81 "xchg %%eax, %[save]+0 \n\t"
82 "xchg %%ebx, %[save]+4 \n\t"
83 "xchg %%ecx, %[save]+8 \n\t"
84 "xchg %%edx, %[save]+12 \n\t"
85 "xchg %%esi, %[save]+16 \n\t"
86 "xchg %%edi, %[save]+20 \n\t"
87 "xchg %%esp, %[save]+24 \n\t"
88 "xchg %%ebp, %[save]+28 \n\t"
90 "test_insn: . = . + 16\n\t"
93 "xchg %%eax, %[save]+0 \n\t"
94 "xchg %%ebx, %[save]+4 \n\t"
95 "xchg %%ecx, %[save]+8 \n\t"
96 "xchg %%edx, %[save]+12 \n\t"
97 "xchg %%esi, %[save]+16 \n\t"
98 "xchg %%edi, %[save]+20 \n\t"
99 "xchg %%esp, %[save]+24 \n\t"
100 "xchg %%ebp, %[save]+28 \n\t"
102 /* Save EFLAGS in outregs*/
104 "popl %[save]+36 \n\t"
106 "xor %[tmp], %[tmp] \n\t"
107 "mov %[tmp], %%gs \n\t"
108 : [tmp
]"=&r"(tmp
), [save
]"+m"(save
)
109 : [gdt_descr
]"m"(gdt_descr
), [bigseg
]"r"((short)16)
124 int regs_equal(const struct regs
*r1
, const struct regs
*r2
, int ignore
)
126 const u32
*p1
= &r1
->eax
, *p2
= &r2
->eax
; // yuck
129 for (i
= 0; i
< 8; ++i
)
130 if (!(ignore
& (1 << i
)) && p1
[i
] != p2
[i
])
135 #define MK_INSN(name, str) \
137 ".pushsection \".text\" \n\t" \
138 "insn_" #name ": " str " \n\t" \
139 "insn_" #name "_end: \n\t" \
142 extern u8 insn_##name[], insn_##name##_end[]
146 struct regs inregs
= { .eax
= 0xbe, .edx
= 0xef000000 }, outregs
;
147 MK_INSN(shld_test
, "shld $8,%edx,%eax\n\t");
149 exec_in_big_real_mode(&inregs
, &outregs
,
151 insn_shld_test_end
- insn_shld_test
);
152 if (outregs
.eax
!= 0xbeef)
153 print_serial("shld: failure\n");
155 print_serial("shld: success\n");
158 void test_mov_imm(void)
160 struct regs inregs
= { 0 }, outregs
;
161 MK_INSN(mov_r32_imm_1
, "mov $1234567890, %eax");
162 MK_INSN(mov_r16_imm_1
, "mov $1234, %ax");
163 MK_INSN(mov_r8_imm_1
, "mov $0x12, %ah");
164 MK_INSN(mov_r8_imm_2
, "mov $0x34, %al");
165 MK_INSN(mov_r8_imm_3
, "mov $0x12, %ah\n\t" "mov $0x34, %al\n\t");
167 exec_in_big_real_mode(&inregs
, &outregs
,
169 insn_mov_r16_imm_1_end
- insn_mov_r16_imm_1
);
170 if (!regs_equal(&inregs
, &outregs
, R_AX
) || outregs
.eax
!= 1234)
171 print_serial("mov test 1: FAIL\n");
173 /* test mov $imm, %eax */
174 exec_in_big_real_mode(&inregs
, &outregs
,
176 insn_mov_r32_imm_1_end
- insn_mov_r32_imm_1
);
177 if (!regs_equal(&inregs
, &outregs
, R_AX
) || outregs
.eax
!= 1234567890)
178 print_serial("mov test 2: FAIL\n");
180 /* test mov $imm, %al/%ah */
181 exec_in_big_real_mode(&inregs
, &outregs
,
183 insn_mov_r8_imm_1_end
- insn_mov_r8_imm_1
);
184 if (!regs_equal(&inregs
, &outregs
, R_AX
) || outregs
.eax
!= 0x1200)
185 print_serial("mov test 3: FAIL\n");
186 exec_in_big_real_mode(&inregs
, &outregs
,
188 insn_mov_r8_imm_2_end
- insn_mov_r8_imm_2
);
189 if (!regs_equal(&inregs
, &outregs
, R_AX
) || outregs
.eax
!= 0x34)
190 print_serial("mov test 4: FAIL\n");
191 exec_in_big_real_mode(&inregs
, &outregs
,
193 insn_mov_r8_imm_3_end
- insn_mov_r8_imm_3
);
194 if (!regs_equal(&inregs
, &outregs
, R_AX
) || outregs
.eax
!= 0x1234)
195 print_serial("mov test 5: FAIL\n");
198 void test_cmp_imm(void)
200 struct regs inregs
= { 0 }, outregs
;
201 MK_INSN(cmp_test1
, "mov $0x34, %al\n\t"
202 "cmp $0x34, %al\n\t");
203 MK_INSN(cmp_test2
, "mov $0x34, %al\n\t"
204 "cmp $0x39, %al\n\t");
205 MK_INSN(cmp_test3
, "mov $0x34, %al\n\t"
206 "cmp $0x24, %al\n\t");
208 /* test cmp imm8 with AL */
209 /* ZF: (bit 6) Zero Flag becomes 1 if an operation results
210 * in a 0 writeback, or 0 register
212 exec_in_big_real_mode(&inregs
, &outregs
,
214 insn_cmp_test1_end
- insn_cmp_test1
);
215 if ((outregs
.eflags
& (1<<6)) != (1<<6))
216 print_serial("cmp test 1: FAIL\n");
218 exec_in_big_real_mode(&inregs
, &outregs
,
220 insn_cmp_test2_end
- insn_cmp_test2
);
221 if ((outregs
.eflags
& (1<<6)) != 0)
222 print_serial("cmp test 2: FAIL\n");
224 exec_in_big_real_mode(&inregs
, &outregs
,
226 insn_cmp_test3_end
- insn_cmp_test3
);
227 if ((outregs
.eflags
& (1<<6)) != 0)
228 print_serial("cmp test 3: FAIL\n");
231 void test_add_imm(void)
233 struct regs inregs
= { 0 }, outregs
;
234 MK_INSN(add_test1
, "mov $0x43211234, %eax \n\t"
235 "add $0x12344321, %eax \n\t");
236 MK_INSN(add_test2
, "mov $0x12, %eax \n\t"
237 "add $0x21, %al\n\t");
239 exec_in_big_real_mode(&inregs
, &outregs
,
241 insn_add_test1_end
- insn_add_test1
);
242 if (outregs
.eax
!= 0x55555555)
243 print_serial("add test 1: FAIL\n");
245 exec_in_big_real_mode(&inregs
, &outregs
,
247 insn_add_test2_end
- insn_add_test2
);
248 if (outregs
.eax
!= 0x33)
249 print_serial("add test 2: FAIL\n");
252 void test_eflags_insn(void)
254 struct regs inregs
= { 0 }, outregs
;
261 exec_in_big_real_mode(&inregs
, &outregs
,
263 insn_clc_end
- insn_clc
);
264 if (outregs
.eflags
& 1)
265 print_serial("clc test: FAIL\n");
267 exec_in_big_real_mode(&inregs
, &outregs
,
269 insn_cli_end
- insn_cli
);
270 if (outregs
.eflags
& (1 << 9))
271 print_serial("cli test: FAIL\n");
273 exec_in_big_real_mode(&inregs
, &outregs
,
275 insn_sti_end
- insn_sti
);
276 if (!(outregs
.eflags
& (1 << 9)))
277 print_serial("sti test: FAIL\n");
279 exec_in_big_real_mode(&inregs
, &outregs
,
281 insn_cld_end
- insn_cld
);
282 if (outregs
.eflags
& (1 << 10))
283 print_serial("cld test: FAIL\n");
285 exec_in_big_real_mode(&inregs
, &outregs
,
287 insn_std_end
- insn_std
);
288 if (!(outregs
.eflags
& (1 << 10)))
289 print_serial("std test: FAIL\n");
294 struct regs inregs
= { 0 }, outregs
;
295 MK_INSN(io_test1
, "mov $0xff, %al \n\t"
296 "out %al, $0x10 \n\t"
297 "in $0x10, %al \n\t");
298 MK_INSN(io_test2
, "mov $0xffff, %ax \n\t"
299 "out %ax, $0x10 \n\t"
300 "in $0x10, %ax \n\t");
301 MK_INSN(io_test3
, "mov $0xffffffff, %eax \n\t"
302 "out %eax, $0x10 \n\t"
303 "in $0x10, %eax \n\t");
304 MK_INSN(io_test4
, "mov $0x10, %dx \n\t"
305 "mov $0xff, %al \n\t"
308 MK_INSN(io_test5
, "mov $0x10, %dx \n\t"
309 "mov $0xffff, %ax \n\t"
312 MK_INSN(io_test6
, "mov $0x10, %dx \n\t"
313 "mov $0xffffffff, %eax \n\t"
315 "in %dx, %eax \n\t");
317 exec_in_big_real_mode(&inregs
, &outregs
,
319 insn_io_test1_end
- insn_io_test1
);
321 if (!regs_equal(&inregs
, &outregs
, R_AX
) || outregs
.eax
!= 0xff)
322 print_serial("I/O test 1: FAIL\n");
324 exec_in_big_real_mode(&inregs
, &outregs
,
326 insn_io_test2_end
- insn_io_test2
);
328 if (!regs_equal(&inregs
, &outregs
, R_AX
) || outregs
.eax
!= 0xffff)
329 print_serial("I/O test 2: FAIL\n");
331 exec_in_big_real_mode(&inregs
, &outregs
,
333 insn_io_test3_end
- insn_io_test3
);
335 if (!regs_equal(&inregs
, &outregs
, R_AX
) || outregs
.eax
!= 0xffffffff)
336 print_serial("I/O test 3: FAIL\n");
338 exec_in_big_real_mode(&inregs
, &outregs
,
340 insn_io_test4_end
- insn_io_test4
);
342 if (!regs_equal(&inregs
, &outregs
, R_AX
|R_DX
) || outregs
.eax
!= 0xff)
343 print_serial("I/O test 4: FAIL\n");
345 exec_in_big_real_mode(&inregs
, &outregs
,
347 insn_io_test5_end
- insn_io_test5
);
349 if (!regs_equal(&inregs
, &outregs
, R_AX
|R_DX
) || outregs
.eax
!= 0xffff)
350 print_serial("I/O test 5: FAIL\n");
352 exec_in_big_real_mode(&inregs
, &outregs
,
354 insn_io_test6_end
- insn_io_test6
);
356 if (!regs_equal(&inregs
, &outregs
, R_AX
|R_DX
) || outregs
.eax
!= 0xffffffff)
357 print_serial("I/O test 6: FAIL\n");
363 struct regs inregs
= { 0 }, outregs
;
364 MK_INSN(call1
, "mov $test_function, %eax \n\t"
367 exec_in_big_real_mode(&inregs
, &outregs
,
369 insn_call1_end
- insn_call1
);
370 if(!regs_equal(&inregs
, &outregs
, R_AX
) || outregs
.eax
!= 0x1234)
371 print_serial("Call Test 1: FAIL\n");
376 struct regs inregs
= { 0 }, outregs
;
377 exec_in_big_real_mode(&inregs
, &outregs
, 0, 0);
378 if (!regs_equal(&inregs
, &outregs
, 0))
379 print_serial("null test: FAIL\n");
406 "mov $0x4000, %cx \n\t"
407 "xor %esi, %esi \n\t"
408 "mov %esi, %edi \n\t"
409 "rep/addr32/cs/movsl \n\t"
410 "mov $stacktop, %sp\n\t"
411 "ljmp $0, $start \n\t"
412 ".pushsection .boot, \"ax\" \n\t"
413 "ljmp $0xf000, $init \n\t"