static int set_bios_mode(u8 mode) { struct biosregs ireg, oreg; u8 new_mode; initregs(&ireg); ireg.al = mode; /* AH=0x00 Set Video Mode */ intcall(0x10, &ireg, NULL); ireg.ah = 0x0f; /* Get Current Video Mode */ intcall(0x10, &ireg, &oreg); do_restore = 1; /* Assume video contents were lost */ /* Not all BIOSes are clean with the top bit */ new_mode = oreg.al & 0x7f; if (new_mode == mode) return 0; /* Mode change OK */ #ifndef _WAKEUP if (new_mode != boot_params.screen_info.orig_video_mode) { /* Mode setting failed, but we didn't end up where we started. That's bad. Try to revert to the original video mode. */ ireg.ax = boot_params.screen_info.orig_video_mode; intcall(0x10, &ireg, NULL); } #endif return -1; }
int query_apm_bios(void) { struct biosregs ireg, oreg; /* APM BIOS installation check */ initregs(&ireg); ireg.ah = 0x53; intcall(0x15, &ireg, &oreg); if (oreg.flags & X86_EFLAGS_CF) return -1; /* No APM BIOS */ if (oreg.bx != 0x504d) /* "PM" signature */ return -1; if (!(oreg.cx & 0x02)) /* 32 bits supported? */ return -1; /* Disconnect first, just in case */ ireg.al = 0x04; intcall(0x15, &ireg, NULL); /* 32-bit connect */ ireg.al = 0x03; intcall(0x15, &ireg, &oreg); boot_params.apm_bios_info.cseg = oreg.ax; boot_params.apm_bios_info.offset = oreg.ebx; boot_params.apm_bios_info.cseg_16 = oreg.cx; boot_params.apm_bios_info.dseg = oreg.dx; boot_params.apm_bios_info.cseg_len = oreg.si; boot_params.apm_bios_info.cseg_16_len = oreg.hsi; boot_params.apm_bios_info.dseg_len = oreg.di; if (oreg.flags & X86_EFLAGS_CF) return -1; /* Redo the installation check as the 32-bit connect; some BIOSes return different flags this way... */ ireg.al = 0x00; intcall(0x15, &ireg, &oreg); if ((oreg.eflags & X86_EFLAGS_CF) || oreg.bx != 0x504d) { /* Failure with 32-bit connect, try to disconect and ignore */ ireg.al = 0x04; intcall(0x15, &ireg, NULL); return -1; } boot_params.apm_bios_info.version = oreg.ax; boot_params.apm_bios_info.flags = oreg.cx; return 0; }
static int vesa_probe(void) { struct biosregs ireg, oreg; u16 mode; addr_t mode_ptr; struct mode_info *mi; int nmodes = 0; video_vesa.modes = GET_HEAP(struct mode_info, 0); initregs(&ireg); ireg.ax = 0x4f00; ireg.di = (size_t)&vginfo; intcall(0x10, &ireg, &oreg); if (oreg.ax != 0x004f || vginfo.signature != VESA_MAGIC || vginfo.version < 0x0102) return 0; /* Not present */ set_fs(vginfo.video_mode_ptr.seg); mode_ptr = vginfo.video_mode_ptr.off; while ((mode = rdfs16(mode_ptr)) != 0xffff) { mode_ptr += 2; if (!heap_free(sizeof(struct mode_info))) break; /* Heap full, can't save mode info */ if (mode & ~0x1ff) continue; memset(&vminfo, 0, sizeof vminfo); /* Just in case... */ ireg.ax = 0x4f01; ireg.cx = mode; ireg.di = (size_t)&vminfo; intcall(0x10, &ireg, &oreg); if (oreg.ax != 0x004f) continue; if ((vminfo.mode_attr & 0x15) == 0x05) { /* Text Mode, TTY BIOS supported, supported by hardware */ mi = GET_HEAP(struct mode_info, 1); mi->mode = mode + VIDEO_FIRST_VESA; mi->depth = 0; /* text */ mi->x = vminfo.h_res; mi->y = vminfo.v_res; nmodes++; } else if ((vminfo.mode_attr & 0x99) == 0x99 &&
void cleanscreen(void) { struct biosregs ireg; initregs(&ireg); ireg.bh = 0x0f; ireg.cx = 0x0; ireg.dh = 24; ireg.dl = 79; ireg.ax = 0x0600; intcall(0x10, &ireg, NULL); initregs(&ireg); ireg.ah = 0x2; ireg.bx = 0; ireg.dx = 0; intcall(0x10, &ireg, NULL); }
static int detect_memory_e801(void) { struct biosregs ireg, oreg; initregs(&ireg); ireg.ax = 0xe801; intcall(0x15, &ireg, &oreg); if (oreg.eflags & X86_EFLAGS_CF) return -1; /* */ if (oreg.cx || oreg.dx) { oreg.ax = oreg.cx; oreg.bx = oreg.dx; } if (oreg.ax > 15*1024) { return -1; /* */ } else if (oreg.ax == 15*1024) { boot_params.alt_mem_k = (oreg.bx << 6) + oreg.ax; } else { /* */ boot_params.alt_mem_k = oreg.ax; } return 0; }
static int detect_memory_e801(void) { struct biosregs ireg, oreg; initregs(&ireg); ireg.ax = 0xe801; intcall(0x15, &ireg, &oreg); if (oreg.eflags & X86_EFLAGS_CF) return -1; /* Do we really need to do this? */ if (oreg.cx || oreg.dx) { oreg.ax = oreg.cx; oreg.bx = oreg.dx; } if (oreg.ax > 15*1024) { return -1; /* Bogus! */ } else if (oreg.ax == 15*1024) { boot_params.alt_mem_k = (oreg.bx << 6) + oreg.ax; } else { /* * This ignores memory above 16MB if we have a memory * hole there. If someone actually finds a machine * with a memory hole at 16MB and no support for * 0E820h they should probably generate a fake e820 * map. */ boot_params.alt_mem_k = oreg.ax; } return 0; }
static int get_edd_info(u8 devno, struct edd_info *ei) { struct biosregs ireg, oreg; memset(ei, 0, sizeof *ei); initregs(&ireg); ireg.ah = 0x41; ireg.bx = EDDMAGIC1; ireg.dl = devno; intcall(0x13, &ireg, &oreg); if (oreg.eflags & X86_EFLAGS_CF) return -1; if (oreg.bx != EDDMAGIC2) return -1; ei->device = devno; ei->version = oreg.ah; ei->interface_support = oreg.cx; ei->params.length = sizeof(ei->params); ireg.ah = 0x48; ireg.si = (size_t)&ei->params; intcall(0x13, &ireg, &oreg); ireg.ah = 0x08; ireg.es = 0; intcall(0x13, &ireg, &oreg); if (!(oreg.eflags & X86_EFLAGS_CF)) { ei->legacy_max_cylinder = oreg.ch + ((oreg.cl & 0xc0) << 2); ei->legacy_max_head = oreg.dh; ei->legacy_sectors_per_track = oreg.cl & 0x3f; } return 0; }
static void __bootcode enable_a20_bios(void) { struct biosregs ireg; initregs(&ireg); ireg.ax = 0x2401; intcall(0x15, &ireg, NULL); }
/* * Read from the keyboard */ int getchar(void) { struct biosregs ireg, oreg; initregs(&ireg); /* ireg.ah = 0x00; */ intcall(0x16, &ireg, &oreg); return oreg.al; }
static u8 gettime(void) { struct biosregs ireg, oreg; initregs(&ireg); ireg.ah = 0x02; intcall(0x1a, &ireg, &oreg); return oreg.dh; }
static int kbd_pending(void) { struct biosregs ireg, oreg; initregs(&ireg); ireg.ah = 0x01; intcall(0x16, &ireg, &oreg); return !(oreg.eflags & X86_EFLAGS_ZF); }
static void __attribute__((section(".inittext"))) bios_putchar(int ch) { struct biosregs ireg; initregs(&ireg); ireg.bx = 0x0007; ireg.cx = 0x0001; ireg.ah = 0x0e; ireg.al = ch; intcall(0x10, &ireg, NULL); }
static int detect_memory_e820(void) { int count = 0; struct biosregs ireg, oreg; struct e820entry *desc = boot_params.e820_map; static struct e820entry buf; /* static so it is zeroed */ initregs(&ireg); ireg.ax = 0xe820; ireg.cx = sizeof buf; ireg.edx = SMAP; ireg.di = (size_t)&buf; /* * Note: at least one BIOS is known which assumes that the * buffer pointed to by one e820 call is the same one as * the previous call, and only changes modified fields. Therefore, * we use a temporary buffer and copy the results entry by entry. * * This routine deliberately does not try to account for * ACPI 3+ extended attributes. This is because there are * BIOSes in the field which report zero for the valid bit for * all ranges, and we don't currently make any use of the * other attribute bits. Revisit this if we see the extended * attribute bits deployed in a meaningful way in the future. */ do { intcall(0x15, &ireg, &oreg); ireg.ebx = oreg.ebx; /* for next iteration... */ /* BIOSes which terminate the chain with CF = 1 as opposed to %ebx = 0 don't always report the SMAP signature on the final, failing, probe. */ if (oreg.eflags & X86_EFLAGS_CF) break; /* Some BIOSes stop returning SMAP in the middle of the search loop. We don't know exactly how the BIOS screwed up the map at that point, we might have a partial map, the full map, or complete garbage, so just return failure. */ if (oreg.eax != SMAP) { count = 0; break; } *desc++ = buf; count++; } while (ireg.ebx && count < ARRAY_SIZE(boot_params.e820_map)); return boot_params.e820_entries = count; }
static int detect_memory_e820(void) { int count = 0; struct biosregs ireg, oreg; struct e820entry *desc = boot_params.e820_map; static struct e820entry buf; /* */ initregs(&ireg); ireg.ax = 0xe820; ireg.cx = sizeof buf; ireg.edx = SMAP; ireg.di = (size_t)&buf; /* */ do { intcall(0x15, &ireg, &oreg); ireg.ebx = oreg.ebx; /* */ /* */ if (oreg.eflags & X86_EFLAGS_CF) break; /* */ if (oreg.eax != SMAP) { count = 0; break; } *desc++ = buf; count++; } while (ireg.ebx && count < ARRAY_SIZE(boot_params.e820_map)); return boot_params.e820_entries = count; }
/** @brief 0x88 Interrupt 명령으로 메모리\n 1Kbyte 단위의 메모리 크기를 확인한다.\n 확인 가능한 최대 메모리 크기는 64M + 1M 이다.\n 확인된 결과값은 boot_params.screen_info.ext_mem_k 에 저장된다. @return 성공시:0, 실패시:-1 */ static int detect_memory_88(void) { struct biosregs ireg, oreg; initregs(&ireg); ireg.ah = 0x88; intcall(0x15, &ireg, &oreg); boot_params.screen_info.ext_mem_k = oreg.ax; return -(oreg.eflags & X86_EFLAGS_CF); /* 0 or -1 */ }
void putchar(int ch) { struct biosregs ireg; if (ch == '\n') putchar('\r'); /* \n -> \r\n */ initregs(&ireg); ireg.bx = 0x0007; ireg.cx = 0x0001; ireg.ah = 0x0e; ireg.al = ch; intcall(0x10, &ireg, NULL); }
static int read_mbr(u8 devno, void *buf) { struct biosregs ireg, oreg; initregs(&ireg); ireg.ax = 0x0201; ireg.cx = 0x0001; ireg.dl = devno; ireg.bx = (size_t)buf; intcall(0x13, &ireg, &oreg); return -(oreg.eflags & X86_EFLAGS_CF); }
int putchar(int ch) { com32sys_t regs; if (ch == '\n') { /* \n -> \r\n */ putchar('\r'); } regs.eax.w[0] = 0x0e00 | (ch & 0xff); intcall(0x10, ®s, NULL); return ch; }
void __attribute__((section(".inittext"))) putchar(int ch) { struct biosregs ireg; if (ch == '\n') putchar('\r'); /* \n -> \r\n */ initregs(&ireg); ireg.bx = 0x0007; ireg.cx = 0x0001; ireg.ah = 0x0e; ireg.al = ch; intcall(0x10, &ireg, NULL); }
void putc(char ch) { struct ctx c; c.ax = (0x0E << 8) | ch; c.bx = 0; c.cx = 0; c.dx = 0; c.si = 0; c.di = 0; c.bp = 0; c.flags = 0; c.ds = 0; c.es = 0; intcall(0x10, c); }
int query_mca(void) { struct biosregs ireg, oreg; u16 len; initregs(&ireg); ireg.ah = 0xc0; intcall(0x15, &ireg, &oreg); if (oreg.eflags & X86_EFLAGS_CF) return -1; /* No MCA present */ set_fs(oreg.es); len = rdfs16(oreg.bx); if (len > sizeof(boot_params.sys_desc_table)) len = sizeof(boot_params.sys_desc_table); copy_from_fs(&boot_params.sys_desc_table, oreg.bx, len); return 0; }
/** @brief 0xe801 Interrupt 명령을 통한 Memory map을 확인한다.\n 확인된 Memory map 정보는 boot_params 에 저장된다.\n 확인하는 사항은 전체 메모리 맵 구성의 크기이다.\n 확인 가능한 최대 메모리 크기는 4G + 16M 이다.\n 최대 확인 가능한 메모리 크기까지만 표현한다.\n 결과값은 boot_params.alt_mem_k 에 저장된다. @return 성공시:0, 실패시:-1 */ static int detect_memory_e801(void) { struct biosregs ireg, oreg; initregs(&ireg); ireg.ax = 0xe801; // 0xe801 : 0xe820(2002), 0xe801(1994) 2002 년 이전의 CPU는 e801 // 명령으로만 Memory map 을 확인할 수 있으므로... intcall(0x15, &ireg, &oreg); // 연산 결과 // ax : Kbyte 단위의 1 ~ 15 * 1024 사이의 크기 값.(표현가능한 크기: 1Kbyte ~ 15 Mbyte) // bx : 64KByte 단위의 크기값. (최대 4GB) if (oreg.eflags & X86_EFLAGS_CF) return -1; /* Do we really need to do this? */ if (oreg.cx || oreg.dx) { oreg.ax = oreg.cx; oreg.bx = oreg.dx; } if (oreg.ax > 15*1024) { return -1; /* Bogus! */ } else if (oreg.ax == 15*1024) { boot_params.alt_mem_k = (oreg.bx << 6) + oreg.ax; } else { /* * This ignores memory above 16MB if we have a memory * hole there. If someone actually finds a machine * with a memory hole at 16MB and no support for * 0E820h they should probably generate a fake e820 * map. */ boot_params.alt_mem_k = oreg.ax; } return 0; }
static int detect_memory_e801(void) { struct biosregs ireg, oreg; initregs(&ireg); ireg.ax = 0xe801; intcall(0x15, &ireg, &oreg); if (oreg.eflags & X86_EFLAGS_CF) return -1; /* Do we really need to do this? */ if (oreg.cx || oreg.dx) { oreg.ax = oreg.cx; oreg.bx = oreg.dx; } if (oreg.ax > 15*1024) { return -1; /* Bogus! */ } else if (oreg.ax == 15*1024) { <<<<<<< HEAD boot_params.alt_mem_k = (oreg.bx << 6) + oreg.ax; =======
void main(void) { intcall(); }
/** @brief e820 Interrupt 를 통한 현재 Memory map 구성을 확인하고 e820 정보를 e820_map에 입력한다. @return 성공시: 확인된 memory map 구성 갯수, 실패시:0 */ static int detect_memory_e820(void) { int count = 0; struct biosregs ireg, oreg; struct e820entry *desc = boot_params.e820_map; static struct e820entry buf; /* static so it is zeroed */ initregs(&ireg); ireg.ax = 0xe820; // 0xE820 // 0xE820 : returns a memory map of all the installed RAM, // and of physical memory ranges reserved by the BIOS. // http://www.uruk.org/orig-grub/mem64mb.html ireg.cx = sizeof buf; ireg.edx = SMAP; /* 필요한 signature */ ireg.di = (size_t)&buf; /* * Note: at least one BIOS is known which assumes that the * buffer pointed to by one e820 call is the same one as * the previous call, and only changes modified fields. Therefore, * we use a temporary buffer and copy the results entry by entry. * * This routine deliberately does not try to account for * ACPI 3+ extended attributes. This is because there are * BIOSes in the field which report zero for the valid bit for * all ranges, and we don't currently make any use of the * other attribute bits. Revisit this if we see the extended * attribute bits deployed in a meaningful way in the future. */ do { intcall(0x15, &ireg, &oreg); // 0x15: ax(e820) // &ireg : Input Register // &oreg : Ouput Register ireg.ebx = oreg.ebx; /* for next iteration... */ // ebx : Offset 주소. // Input 의 경우 시작 Offset, Output의 경우 다음 Offset. // 만약 Offset이 0 이면 끝을 의미한다. /* BIOSes which terminate the chain with CF = 1 as opposed to %ebx = 0 don't always report the SMAP signature on the final, failing, probe. */ if (oreg.eflags & X86_EFLAGS_CF) // Error 발생시, CF Flag가 Set이 된다. break; /* Some BIOSes stop returning SMAP in the middle of the search loop. We don't know exactly how the BIOS screwed up the map at that point, we might have a partial map, the full map, or complete garbage, so just return failure. */ // 정상적인 검색 루프에서는 Return 값으로 oreg.eax 에 SMAP 값이 입력되어야 한다. // 일부 BIOS 에서는 다른 값들이 올 수도 있지만 SMAP 이 아닌 경우, // 모두 Error 로 간주한다. if (oreg.eax != SMAP) { count = 0; break; } *desc++ = buf; /* e820 엔트리를 e820_map에 입력 */ count++; // ireg.ebx = Next Search Memory Offset } while (ireg.ebx && count < ARRAY_SIZE(boot_params.e820_map)); return boot_params.e820_entries = count; /* 총 갯수 */ }