|
|
1.1 root 1: // Handler for int 0x15 "system" calls
2: //
3: // Copyright (C) 2008 Kevin O'Connor <[email protected]>
4: // Copyright (C) 2002 MandrakeSoft S.A.
5: //
6: // This file may be distributed under the terms of the GNU LGPLv3 license.
7:
8: #include "util.h" // memcpy_far
9: #include "biosvar.h" // BIOS_CONFIG_TABLE
10: #include "ioport.h" // inb
11: #include "memmap.h" // E820_RAM
12: #include "pic.h" // eoi_pic2
13: #include "bregs.h" // struct bregs
14:
15: // Use PS2 System Control port A to set A20 enable
16: static inline u8
17: set_a20(u8 cond)
18: {
19: // get current setting first
20: u8 newval, oldval = inb(PORT_A20);
21: if (cond)
22: newval = oldval | A20_ENABLE_BIT;
23: else
24: newval = oldval & ~A20_ENABLE_BIT;
25: outb(newval, PORT_A20);
26:
27: return (oldval & A20_ENABLE_BIT) != 0;
28: }
29:
30: static void
31: handle_152400(struct bregs *regs)
32: {
33: set_a20(0);
34: set_code_success(regs);
35: }
36:
37: static void
38: handle_152401(struct bregs *regs)
39: {
40: set_a20(1);
41: set_code_success(regs);
42: }
43:
44: static void
45: handle_152402(struct bregs *regs)
46: {
47: regs->al = (inb(PORT_A20) & A20_ENABLE_BIT) != 0;
48: set_code_success(regs);
49: }
50:
51: static void
52: handle_152403(struct bregs *regs)
53: {
54: regs->bx = 3;
55: set_code_success(regs);
56: }
57:
58: static void
59: handle_1524XX(struct bregs *regs)
60: {
61: set_code_unimplemented(regs, RET_EUNSUPPORTED);
62: }
63:
64: static void
65: handle_1524(struct bregs *regs)
66: {
67: switch (regs->al) {
68: case 0x00: handle_152400(regs); break;
69: case 0x01: handle_152401(regs); break;
70: case 0x02: handle_152402(regs); break;
71: case 0x03: handle_152403(regs); break;
72: default: handle_1524XX(regs); break;
73: }
74: }
75:
76: // removable media eject
77: static void
78: handle_1552(struct bregs *regs)
79: {
80: set_code_success(regs);
81: }
82:
83: static void
84: handle_1587(struct bregs *regs)
85: {
86: // +++ should probably have descriptor checks
87: // +++ should have exception handlers
88:
89: u8 prev_a20_enable = set_a20(1); // enable A20 line
90:
91: // 128K max of transfer on 386+ ???
92: // source == destination ???
93:
94: // ES:SI points to descriptor table
95: // offset use initially comments
96: // ==============================================
97: // 00..07 Unused zeros Null descriptor
98: // 08..0f GDT zeros filled in by BIOS
99: // 10..17 source ssssssss source of data
100: // 18..1f dest dddddddd destination of data
101: // 20..27 CS zeros filled in by BIOS
102: // 28..2f SS zeros filled in by BIOS
103:
104: // check for access rights of source & dest here
105:
106: // Initialize GDT descriptor
107: u32 si = regs->si;
108: u64 *gdt_far = (void*)si;
109: u16 gdt_seg = regs->es;
110: u32 loc = (u32)MAKE_FLATPTR(gdt_seg, gdt_far);
111: SET_FARVAR(gdt_seg, gdt_far[1], GDT_DATA | GDT_LIMIT((6*sizeof(u64))-1)
112: | GDT_BASE(loc));
113: // Initialize CS descriptor
1.1.1.2 ! root 114: SET_FARVAR(gdt_seg, gdt_far[4], GDT_CODE | GDT_LIMIT(BUILD_BIOS_SIZE-1)
! 115: | GDT_BASE(BUILD_BIOS_ADDR));
1.1 root 116: // Initialize SS descriptor
117: loc = (u32)MAKE_FLATPTR(GET_SEG(SS), 0);
118: SET_FARVAR(gdt_seg, gdt_far[5], GDT_DATA | GDT_LIMIT(0x0ffff)
119: | GDT_BASE(loc));
120:
121: u16 count = regs->cx;
122: asm volatile(
123: // Load new descriptor tables
1.1.1.2 ! root 124: " lgdtw %%es:(1<<3)(%%si)\n"
! 125: " lidtw %%cs:pmode_IDT_info\n"
1.1 root 126:
127: // Enable protected mode
1.1.1.2 ! root 128: " movl %%cr0, %%eax\n"
! 129: " orl $" __stringify(CR0_PE) ", %%eax\n"
! 130: " movl %%eax, %%cr0\n"
1.1 root 131:
132: // far jump to flush CPU queue after transition to protected mode
1.1.1.2 ! root 133: " ljmpw $(4<<3), $1f\n"
1.1 root 134:
135: // GDT points to valid descriptor table, now load DS, ES
1.1.1.2 ! root 136: "1:movw $(2<<3), %%ax\n" // 2nd descriptor in table, TI=GDT, RPL=00
! 137: " movw %%ax, %%ds\n"
! 138: " movw $(3<<3), %%ax\n" // 3rd descriptor in table, TI=GDT, RPL=00
! 139: " movw %%ax, %%es\n"
1.1 root 140:
141: // move CX words from DS:SI to ES:DI
1.1.1.2 ! root 142: " xorw %%si, %%si\n"
! 143: " xorw %%di, %%di\n"
! 144: " rep movsw\n"
1.1 root 145:
146: // Disable protected mode
1.1.1.2 ! root 147: " movl %%cr0, %%eax\n"
! 148: " andl $~" __stringify(CR0_PE) ", %%eax\n"
! 149: " movl %%eax, %%cr0\n"
1.1 root 150:
151: // far jump to flush CPU queue after transition to real mode
1.1.1.2 ! root 152: " ljmpw $" __stringify(SEG_BIOS) ", $2f\n"
1.1 root 153:
154: // restore IDT to normal real-mode defaults
1.1.1.2 ! root 155: "2:lidtw %%cs:rmode_IDT_info\n"
1.1 root 156:
157: // Restore %ds (from %ss)
1.1.1.2 ! root 158: " movw %%ss, %%ax\n"
! 159: " movw %%ax, %%ds\n"
1.1 root 160: : "+c"(count), "+S"(si)
161: : : "eax", "di", "cc"); // XXX - also clobbers %es
162:
163: set_a20(prev_a20_enable);
164:
165: set_code_success(regs);
166: }
167:
168: // Get the amount of extended memory (above 1M)
169: static void
170: handle_1588(struct bregs *regs)
171: {
172: u32 rs = GET_GLOBAL(RamSize);
173:
174: // According to Ralf Brown's interrupt the limit should be 15M,
175: // but real machines mostly return max. 63M.
176: if (rs > 64*1024*1024)
177: regs->ax = 63 * 1024;
178: else
179: regs->ax = (rs - 1*1024*1024) / 1024;
180: set_success(regs);
181: }
182:
1.1.1.2 ! root 183: // Switch to protected mode
! 184: static void
! 185: handle_1589(struct bregs *regs)
! 186: {
! 187: set_a20(1);
! 188:
! 189: set_pics(regs->bl, regs->bh);
! 190:
! 191: u64 *gdt_far = (void*)(regs->si + 0);
! 192: u16 gdt_seg = regs->es;
! 193: SET_FARVAR(gdt_seg, gdt_far[7], GDT_CODE | GDT_LIMIT(BUILD_BIOS_SIZE-1)
! 194: | GDT_BASE(BUILD_BIOS_ADDR));
! 195:
! 196: regs->ds = 3<<3; // 3rd gdt descriptor is %ds
! 197: regs->es = 4<<3; // 4th gdt descriptor is %es
! 198: regs->code.seg = 6<<3; // 6th gdt descriptor is %cs
! 199:
! 200: set_code_success(regs);
! 201:
! 202: asm volatile(
! 203: // Load new descriptor tables
! 204: " lgdtw %%es:(1<<3)(%%si)\n"
! 205: " lidtw %%es:(2<<3)(%%si)\n"
! 206:
! 207: // Enable protected mode
! 208: " movl %%cr0, %%eax\n"
! 209: " orl $" __stringify(CR0_PE) ", %%eax\n"
! 210: " movl %%eax, %%cr0\n"
! 211:
! 212: // far jump to flush CPU queue after transition to protected mode
! 213: " ljmpw $(7<<3), $1f\n"
! 214:
! 215: // GDT points to valid descriptor table, now load SS
! 216: "1:movw $(5<<3), %%ax\n"
! 217: " movw %%ax, %%ds\n"
! 218: " movw %%ax, %%ss\n"
! 219: :
! 220: : "S"(gdt_far)
! 221: : "eax", "cc");
! 222: }
! 223:
1.1 root 224: // Device busy interrupt. Called by Int 16h when no key available
225: static void
226: handle_1590(struct bregs *regs)
227: {
228: }
229:
230: // Interrupt complete. Called by Int 16h when key becomes available
231: static void
232: handle_1591(struct bregs *regs)
233: {
234: }
235:
236: // keyboard intercept
237: static void
238: handle_154f(struct bregs *regs)
239: {
240: set_invalid_silent(regs);
241: }
242:
243: static void
244: handle_15c0(struct bregs *regs)
245: {
246: regs->es = SEG_BIOS;
247: regs->bx = (u32)&BIOS_CONFIG_TABLE;
248: set_code_success(regs);
249: }
250:
251: static void
252: handle_15c1(struct bregs *regs)
253: {
254: regs->es = get_ebda_seg();
255: set_success(regs);
256: }
257:
258: static void
259: handle_15e801(struct bregs *regs)
260: {
261: // my real system sets ax and bx to 0
262: // this is confirmed by Ralph Brown list
263: // but syslinux v1.48 is known to behave
264: // strangely if ax is set to 0
265: // regs.u.r16.ax = 0;
266: // regs.u.r16.bx = 0;
267:
268: u32 rs = GET_GLOBAL(RamSize);
269:
270: // Get the amount of extended memory (above 1M)
271: if (rs > 16*1024*1024) {
272: // limit to 15M
273: regs->cx = 15*1024;
274: // Get the amount of extended memory above 16M in 64k blocks
275: regs->dx = (rs - 16*1024*1024) / (64*1024);
276: } else {
277: regs->cx = (rs - 1*1024*1024) / 1024;
278: regs->dx = 0;
279: }
280:
281: // Set configured memory equal to extended memory
282: regs->ax = regs->cx;
283: regs->bx = regs->dx;
284:
285: set_success(regs);
286: }
287:
288: // Info on e820 map location and size.
289: struct e820entry e820_list[CONFIG_MAX_E820] VAR16VISIBLE;
290: int e820_count VAR16VISIBLE;
291:
292: static void
293: handle_15e820(struct bregs *regs)
294: {
295: int count = GET_GLOBAL(e820_count);
296: if (regs->edx != 0x534D4150 || regs->bx >= count
297: || regs->ecx < sizeof(e820_list[0])) {
298: set_code_invalid(regs, RET_EUNSUPPORTED);
299: return;
300: }
301:
302: memcpy_far(regs->es, (void*)(regs->di+0)
303: , get_global_seg(), &e820_list[regs->bx]
304: , sizeof(e820_list[0]));
305: if (regs->bx == count-1)
306: regs->ebx = 0;
307: else
308: regs->ebx++;
309: regs->eax = 0x534D4150;
310: regs->ecx = sizeof(e820_list[0]);
311: set_success(regs);
312: }
313:
314: static void
315: handle_15e8XX(struct bregs *regs)
316: {
317: set_code_unimplemented(regs, RET_EUNSUPPORTED);
318: }
319:
320: static void
321: handle_15e8(struct bregs *regs)
322: {
323: switch (regs->al) {
324: case 0x01: handle_15e801(regs); break;
325: case 0x20: handle_15e820(regs); break;
326: default: handle_15e8XX(regs); break;
327: }
328: }
329:
330: static void
331: handle_15XX(struct bregs *regs)
332: {
333: set_code_unimplemented(regs, RET_EUNSUPPORTED);
334: }
335:
336: // INT 15h System Services Entry Point
337: void VISIBLE16
338: handle_15(struct bregs *regs)
339: {
340: debug_enter(regs, DEBUG_HDL_15);
341: switch (regs->ah) {
342: case 0x24: handle_1524(regs); break;
343: case 0x4f: handle_154f(regs); break;
344: case 0x52: handle_1552(regs); break;
345: case 0x53: handle_1553(regs); break;
346: case 0x5f: handle_155f(regs); break;
347: case 0x83: handle_1583(regs); break;
348: case 0x86: handle_1586(regs); break;
349: case 0x87: handle_1587(regs); break;
350: case 0x88: handle_1588(regs); break;
1.1.1.2 ! root 351: case 0x89: handle_1589(regs); break;
1.1 root 352: case 0x90: handle_1590(regs); break;
353: case 0x91: handle_1591(regs); break;
354: case 0xc0: handle_15c0(regs); break;
355: case 0xc1: handle_15c1(regs); break;
356: case 0xc2: handle_15c2(regs); break;
357: case 0xe8: handle_15e8(regs); break;
358: default: handle_15XX(regs); break;
359: }
360: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.