|
|
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:
1.1.1.3 ! root 146: // Restore DS and ES segment limits to 0xffff
! 147: " movw $(5<<3), %%ax\n" // 5th descriptor in table (SS)
! 148: " movw %%ax, %%ds\n"
! 149: " movw %%ax, %%es\n"
! 150:
1.1 root 151: // Disable protected mode
1.1.1.2 root 152: " movl %%cr0, %%eax\n"
153: " andl $~" __stringify(CR0_PE) ", %%eax\n"
154: " movl %%eax, %%cr0\n"
1.1 root 155:
156: // far jump to flush CPU queue after transition to real mode
1.1.1.2 root 157: " ljmpw $" __stringify(SEG_BIOS) ", $2f\n"
1.1 root 158:
159: // restore IDT to normal real-mode defaults
1.1.1.2 root 160: "2:lidtw %%cs:rmode_IDT_info\n"
1.1 root 161:
162: // Restore %ds (from %ss)
1.1.1.2 root 163: " movw %%ss, %%ax\n"
164: " movw %%ax, %%ds\n"
1.1 root 165: : "+c"(count), "+S"(si)
166: : : "eax", "di", "cc"); // XXX - also clobbers %es
167:
168: set_a20(prev_a20_enable);
169:
170: set_code_success(regs);
171: }
172:
173: // Get the amount of extended memory (above 1M)
174: static void
175: handle_1588(struct bregs *regs)
176: {
177: u32 rs = GET_GLOBAL(RamSize);
178:
179: // According to Ralf Brown's interrupt the limit should be 15M,
180: // but real machines mostly return max. 63M.
181: if (rs > 64*1024*1024)
182: regs->ax = 63 * 1024;
183: else
184: regs->ax = (rs - 1*1024*1024) / 1024;
185: set_success(regs);
186: }
187:
1.1.1.2 root 188: // Switch to protected mode
189: static void
190: handle_1589(struct bregs *regs)
191: {
192: set_a20(1);
193:
194: set_pics(regs->bl, regs->bh);
195:
196: u64 *gdt_far = (void*)(regs->si + 0);
197: u16 gdt_seg = regs->es;
198: SET_FARVAR(gdt_seg, gdt_far[7], GDT_CODE | GDT_LIMIT(BUILD_BIOS_SIZE-1)
199: | GDT_BASE(BUILD_BIOS_ADDR));
200:
201: regs->ds = 3<<3; // 3rd gdt descriptor is %ds
202: regs->es = 4<<3; // 4th gdt descriptor is %es
203: regs->code.seg = 6<<3; // 6th gdt descriptor is %cs
204:
205: set_code_success(regs);
206:
207: asm volatile(
208: // Load new descriptor tables
209: " lgdtw %%es:(1<<3)(%%si)\n"
210: " lidtw %%es:(2<<3)(%%si)\n"
211:
212: // Enable protected mode
213: " movl %%cr0, %%eax\n"
214: " orl $" __stringify(CR0_PE) ", %%eax\n"
215: " movl %%eax, %%cr0\n"
216:
217: // far jump to flush CPU queue after transition to protected mode
218: " ljmpw $(7<<3), $1f\n"
219:
220: // GDT points to valid descriptor table, now load SS
221: "1:movw $(5<<3), %%ax\n"
222: " movw %%ax, %%ds\n"
223: " movw %%ax, %%ss\n"
224: :
225: : "S"(gdt_far)
226: : "eax", "cc");
227: }
228:
1.1 root 229: // Device busy interrupt. Called by Int 16h when no key available
230: static void
231: handle_1590(struct bregs *regs)
232: {
233: }
234:
235: // Interrupt complete. Called by Int 16h when key becomes available
236: static void
237: handle_1591(struct bregs *regs)
238: {
239: }
240:
241: // keyboard intercept
242: static void
243: handle_154f(struct bregs *regs)
244: {
245: set_invalid_silent(regs);
246: }
247:
248: static void
249: handle_15c0(struct bregs *regs)
250: {
251: regs->es = SEG_BIOS;
252: regs->bx = (u32)&BIOS_CONFIG_TABLE;
253: set_code_success(regs);
254: }
255:
256: static void
257: handle_15c1(struct bregs *regs)
258: {
259: regs->es = get_ebda_seg();
260: set_success(regs);
261: }
262:
263: static void
264: handle_15e801(struct bregs *regs)
265: {
266: // my real system sets ax and bx to 0
267: // this is confirmed by Ralph Brown list
268: // but syslinux v1.48 is known to behave
269: // strangely if ax is set to 0
270: // regs.u.r16.ax = 0;
271: // regs.u.r16.bx = 0;
272:
273: u32 rs = GET_GLOBAL(RamSize);
274:
275: // Get the amount of extended memory (above 1M)
276: if (rs > 16*1024*1024) {
277: // limit to 15M
278: regs->cx = 15*1024;
279: // Get the amount of extended memory above 16M in 64k blocks
280: regs->dx = (rs - 16*1024*1024) / (64*1024);
281: } else {
282: regs->cx = (rs - 1*1024*1024) / 1024;
283: regs->dx = 0;
284: }
285:
286: // Set configured memory equal to extended memory
287: regs->ax = regs->cx;
288: regs->bx = regs->dx;
289:
290: set_success(regs);
291: }
292:
293: // Info on e820 map location and size.
294: struct e820entry e820_list[CONFIG_MAX_E820] VAR16VISIBLE;
295: int e820_count VAR16VISIBLE;
296:
297: static void
298: handle_15e820(struct bregs *regs)
299: {
300: int count = GET_GLOBAL(e820_count);
301: if (regs->edx != 0x534D4150 || regs->bx >= count
302: || regs->ecx < sizeof(e820_list[0])) {
303: set_code_invalid(regs, RET_EUNSUPPORTED);
304: return;
305: }
306:
307: memcpy_far(regs->es, (void*)(regs->di+0)
308: , get_global_seg(), &e820_list[regs->bx]
309: , sizeof(e820_list[0]));
310: if (regs->bx == count-1)
311: regs->ebx = 0;
312: else
313: regs->ebx++;
314: regs->eax = 0x534D4150;
315: regs->ecx = sizeof(e820_list[0]);
316: set_success(regs);
317: }
318:
319: static void
320: handle_15e8XX(struct bregs *regs)
321: {
322: set_code_unimplemented(regs, RET_EUNSUPPORTED);
323: }
324:
325: static void
326: handle_15e8(struct bregs *regs)
327: {
328: switch (regs->al) {
329: case 0x01: handle_15e801(regs); break;
330: case 0x20: handle_15e820(regs); break;
331: default: handle_15e8XX(regs); break;
332: }
333: }
334:
335: static void
336: handle_15XX(struct bregs *regs)
337: {
338: set_code_unimplemented(regs, RET_EUNSUPPORTED);
339: }
340:
341: // INT 15h System Services Entry Point
342: void VISIBLE16
343: handle_15(struct bregs *regs)
344: {
345: debug_enter(regs, DEBUG_HDL_15);
346: switch (regs->ah) {
347: case 0x24: handle_1524(regs); break;
348: case 0x4f: handle_154f(regs); break;
349: case 0x52: handle_1552(regs); break;
350: case 0x53: handle_1553(regs); break;
351: case 0x5f: handle_155f(regs); break;
352: case 0x83: handle_1583(regs); break;
353: case 0x86: handle_1586(regs); break;
354: case 0x87: handle_1587(regs); break;
355: case 0x88: handle_1588(regs); break;
1.1.1.2 root 356: case 0x89: handle_1589(regs); break;
1.1 root 357: case 0x90: handle_1590(regs); break;
358: case 0x91: handle_1591(regs); break;
359: case 0xc0: handle_15c0(regs); break;
360: case 0xc1: handle_15c1(regs); break;
361: case 0xc2: handle_15c2(regs); break;
362: case 0xe8: handle_15e8(regs); break;
363: default: handle_15XX(regs); break;
364: }
365: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.