Annotation of qemu/roms/seabios/src/system.c, revision 1.1

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
        !           114:     SET_FARVAR(gdt_seg, gdt_far[4], GDT_CODE | GDT_LIMIT(0x0ffff)
        !           115:                | GDT_BASE(0xf0000));
        !           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
        !           124:         "lgdtw %%es:(1<<3)(%%si)\n"
        !           125:         "lidtw %%cs:pmode_IDT_info\n"
        !           126: 
        !           127:         // Enable protected mode
        !           128:         "movl %%cr0, %%eax\n"
        !           129:         "orl $" __stringify(CR0_PE) ", %%eax\n"
        !           130:         "movl %%eax, %%cr0\n"
        !           131: 
        !           132:         // far jump to flush CPU queue after transition to protected mode
        !           133:         "ljmpw $(4<<3), $1f\n"
        !           134:         "1:\n"
        !           135: 
        !           136:         // GDT points to valid descriptor table, now load DS, ES
        !           137:         "movw $(2<<3), %%ax\n" // 2nd descriptor in table, TI=GDT, RPL=00
        !           138:         "movw %%ax, %%ds\n"
        !           139:         "movw $(3<<3), %%ax\n" // 3rd descriptor in table, TI=GDT, RPL=00
        !           140:         "movw %%ax, %%es\n"
        !           141: 
        !           142:         // move CX words from DS:SI to ES:DI
        !           143:         "xorw %%si, %%si\n"
        !           144:         "xorw %%di, %%di\n"
        !           145:         "rep movsw\n"
        !           146: 
        !           147:         // Disable protected mode
        !           148:         "movl %%cr0, %%eax\n"
        !           149:         "andl $~" __stringify(CR0_PE) ", %%eax\n"
        !           150:         "movl %%eax, %%cr0\n"
        !           151: 
        !           152:         // far jump to flush CPU queue after transition to real mode
        !           153:         "ljmpw $" __stringify(SEG_BIOS) ", $2f\n"
        !           154:         "2:\n"
        !           155: 
        !           156:         // restore IDT to normal real-mode defaults
        !           157:         "lidtw %%cs:rmode_IDT_info\n"
        !           158: 
        !           159:         // Restore %ds (from %ss)
        !           160:         "movw %%ss, %%ax\n"
        !           161:         "movw %%ax, %%ds\n"
        !           162:         : "+c"(count), "+S"(si)
        !           163:         : : "eax", "di", "cc"); // XXX - also clobbers %es
        !           164: 
        !           165:     set_a20(prev_a20_enable);
        !           166: 
        !           167:     set_code_success(regs);
        !           168: }
        !           169: 
        !           170: // Get the amount of extended memory (above 1M)
        !           171: static void
        !           172: handle_1588(struct bregs *regs)
        !           173: {
        !           174:     u32 rs = GET_GLOBAL(RamSize);
        !           175: 
        !           176:     // According to Ralf Brown's interrupt the limit should be 15M,
        !           177:     // but real machines mostly return max. 63M.
        !           178:     if (rs > 64*1024*1024)
        !           179:         regs->ax = 63 * 1024;
        !           180:     else
        !           181:         regs->ax = (rs - 1*1024*1024) / 1024;
        !           182:     set_success(regs);
        !           183: }
        !           184: 
        !           185: // Device busy interrupt.  Called by Int 16h when no key available
        !           186: static void
        !           187: handle_1590(struct bregs *regs)
        !           188: {
        !           189: }
        !           190: 
        !           191: // Interrupt complete.  Called by Int 16h when key becomes available
        !           192: static void
        !           193: handle_1591(struct bregs *regs)
        !           194: {
        !           195: }
        !           196: 
        !           197: // keyboard intercept
        !           198: static void
        !           199: handle_154f(struct bregs *regs)
        !           200: {
        !           201:     set_invalid_silent(regs);
        !           202: }
        !           203: 
        !           204: static void
        !           205: handle_15c0(struct bregs *regs)
        !           206: {
        !           207:     regs->es = SEG_BIOS;
        !           208:     regs->bx = (u32)&BIOS_CONFIG_TABLE;
        !           209:     set_code_success(regs);
        !           210: }
        !           211: 
        !           212: static void
        !           213: handle_15c1(struct bregs *regs)
        !           214: {
        !           215:     regs->es = get_ebda_seg();
        !           216:     set_success(regs);
        !           217: }
        !           218: 
        !           219: static void
        !           220: handle_15e801(struct bregs *regs)
        !           221: {
        !           222:     // my real system sets ax and bx to 0
        !           223:     // this is confirmed by Ralph Brown list
        !           224:     // but syslinux v1.48 is known to behave
        !           225:     // strangely if ax is set to 0
        !           226:     // regs.u.r16.ax = 0;
        !           227:     // regs.u.r16.bx = 0;
        !           228: 
        !           229:     u32 rs = GET_GLOBAL(RamSize);
        !           230: 
        !           231:     // Get the amount of extended memory (above 1M)
        !           232:     if (rs > 16*1024*1024) {
        !           233:         // limit to 15M
        !           234:         regs->cx = 15*1024;
        !           235:         // Get the amount of extended memory above 16M in 64k blocks
        !           236:         regs->dx = (rs - 16*1024*1024) / (64*1024);
        !           237:     } else {
        !           238:         regs->cx = (rs - 1*1024*1024) / 1024;
        !           239:         regs->dx = 0;
        !           240:     }
        !           241: 
        !           242:     // Set configured memory equal to extended memory
        !           243:     regs->ax = regs->cx;
        !           244:     regs->bx = regs->dx;
        !           245: 
        !           246:     set_success(regs);
        !           247: }
        !           248: 
        !           249: // Info on e820 map location and size.
        !           250: struct e820entry e820_list[CONFIG_MAX_E820] VAR16VISIBLE;
        !           251: int e820_count VAR16VISIBLE;
        !           252: 
        !           253: static void
        !           254: handle_15e820(struct bregs *regs)
        !           255: {
        !           256:     int count = GET_GLOBAL(e820_count);
        !           257:     if (regs->edx != 0x534D4150 || regs->bx >= count
        !           258:         || regs->ecx < sizeof(e820_list[0])) {
        !           259:         set_code_invalid(regs, RET_EUNSUPPORTED);
        !           260:         return;
        !           261:     }
        !           262: 
        !           263:     memcpy_far(regs->es, (void*)(regs->di+0)
        !           264:                , get_global_seg(), &e820_list[regs->bx]
        !           265:                , sizeof(e820_list[0]));
        !           266:     if (regs->bx == count-1)
        !           267:         regs->ebx = 0;
        !           268:     else
        !           269:         regs->ebx++;
        !           270:     regs->eax = 0x534D4150;
        !           271:     regs->ecx = sizeof(e820_list[0]);
        !           272:     set_success(regs);
        !           273: }
        !           274: 
        !           275: static void
        !           276: handle_15e8XX(struct bregs *regs)
        !           277: {
        !           278:     set_code_unimplemented(regs, RET_EUNSUPPORTED);
        !           279: }
        !           280: 
        !           281: static void
        !           282: handle_15e8(struct bregs *regs)
        !           283: {
        !           284:     switch (regs->al) {
        !           285:     case 0x01: handle_15e801(regs); break;
        !           286:     case 0x20: handle_15e820(regs); break;
        !           287:     default:   handle_15e8XX(regs); break;
        !           288:     }
        !           289: }
        !           290: 
        !           291: static void
        !           292: handle_15XX(struct bregs *regs)
        !           293: {
        !           294:     set_code_unimplemented(regs, RET_EUNSUPPORTED);
        !           295: }
        !           296: 
        !           297: // INT 15h System Services Entry Point
        !           298: void VISIBLE16
        !           299: handle_15(struct bregs *regs)
        !           300: {
        !           301:     debug_enter(regs, DEBUG_HDL_15);
        !           302:     switch (regs->ah) {
        !           303:     case 0x24: handle_1524(regs); break;
        !           304:     case 0x4f: handle_154f(regs); break;
        !           305:     case 0x52: handle_1552(regs); break;
        !           306:     case 0x53: handle_1553(regs); break;
        !           307:     case 0x5f: handle_155f(regs); break;
        !           308:     case 0x83: handle_1583(regs); break;
        !           309:     case 0x86: handle_1586(regs); break;
        !           310:     case 0x87: handle_1587(regs); break;
        !           311:     case 0x88: handle_1588(regs); break;
        !           312:     case 0x90: handle_1590(regs); break;
        !           313:     case 0x91: handle_1591(regs); break;
        !           314:     case 0xc0: handle_15c0(regs); break;
        !           315:     case 0xc1: handle_15c1(regs); break;
        !           316:     case 0xc2: handle_15c2(regs); break;
        !           317:     case 0xe8: handle_15e8(regs); break;
        !           318:     default:   handle_15XX(regs); break;
        !           319:     }
        !           320: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.