| /* |
| * GRUB -- GRand Unified Bootloader |
| * Copyright (C) 1996 Erich Boleyn <erich@uruk.org> |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| */ |
| |
| #define _CMDLINE_C |
| |
| #include "shared.h" |
| |
| #ifdef DEBUG |
| |
| unsigned long apic_addr; |
| |
| int start_cpu(int cpu_num, int start_addr, unsigned long my_apic_addr); |
| |
| extern char patch_code[]; |
| extern char patch_code_end[]; |
| |
| unsigned long reg_table[] = |
| { 0x20, 0x30, 0x80, 0x90, 0xa0, 0xd0, 0xe0, 0xf0, 0x280, 0x300, 0x310, |
| 0x320, 0x350, 0x360, 0x370, 0x380, 0x390, 0x3e0, 0 }; |
| |
| |
| int |
| get_remote_APIC_reg(int cpu_num, int reg, unsigned long *retval) |
| { |
| int i, j = 1000; |
| |
| i = *((volatile unsigned long *) (apic_addr+0xc0)); |
| *((volatile unsigned long *) (apic_addr+0x310)) = (cpu_num << 24); |
| i = *((volatile unsigned long *) (apic_addr+0xc0)); |
| *((volatile unsigned long *) (apic_addr+0x300)) = (0x300 | (reg>>4)); |
| |
| while (((i = (*((volatile unsigned long *) (apic_addr+0x300)) & 0x30000)) |
| == 1) && (--j)); |
| |
| if (!i || i == 3 || j == 0) |
| return 1; |
| |
| *retval = *((volatile unsigned long *) (apic_addr+0xc0)); |
| |
| return 0; |
| } |
| |
| |
| void |
| list_regs(int cpu_num) |
| { |
| int i = 0, j = 0; |
| unsigned long tmpval; |
| |
| while (reg_table[i] != 0) |
| { |
| printf(" %x: ", reg_table[i]); |
| |
| if (cpu_num == -1) |
| tmpval = *((volatile unsigned long *) (apic_addr+reg_table[i])); |
| else if (get_remote_APIC_reg(cpu_num, reg_table[i], &tmpval)) |
| printf("error!"); |
| |
| printf("%x", tmpval); |
| |
| i++; |
| j++; |
| |
| if (j == 5 || reg_table[i] == 0) |
| { |
| j = 0; |
| putchar('\n'); |
| } |
| else |
| putchar(','); |
| } |
| } |
| |
| |
| void |
| boot_cpu(int cpu_num) |
| { |
| int i, start_addr = (128 * 1024); |
| |
| bcopy( patch_code, ((char *) start_addr), |
| ((int) patch_code_end) - ((int) patch_code) ); |
| |
| outb(0x70, 0xf); |
| *((volatile unsigned short *) 0x467) = 0; |
| *((volatile unsigned short *) 0x469) = ((unsigned short)(start_addr >> 4)); |
| outb(0x71, 0xa); |
| |
| print_error(); |
| |
| printf("Starting probe for CPU #%d... value = (%x)\n", |
| cpu_num, *((int *) start_addr) ); |
| |
| i = start_cpu(cpu_num, start_addr, apic_addr); |
| |
| printf("Return value = (%x), waiting for RET...", i); |
| |
| i = getc(); |
| |
| outb(0x70, 0xf); |
| printf("\nEnding value = (%x), Status code = (%x)\n", |
| *((int *) start_addr), (unsigned long)inb(0x71)); |
| } |
| |
| |
| unsigned char |
| sum(unsigned char *addr, int len) |
| { |
| int i; |
| unsigned long retval = 0; |
| |
| for (i = 0; i < len; i++) |
| { |
| retval += addr[len]; |
| } |
| |
| return ((unsigned char)(retval & 0xFF)); |
| } |
| |
| |
| int |
| get_mp_parameters(unsigned char *addr) |
| { |
| int i, may_be_bad; |
| unsigned long backup; |
| |
| if (((int)addr)&0xF || addr[0] != '_' || addr[1] != 'M' || addr[2] != 'P' |
| || addr[3] != '_') |
| return 0; |
| |
| may_be_bad = 0; |
| |
| if (sum(addr, addr[8] * 16)) |
| { |
| printf("Found MP structure but checksum bad, use (y/n) ?"); |
| i = getc(); |
| putchar('\n'); |
| if (i != 'y') |
| return 0; |
| may_be_bad = 1; |
| } |
| |
| backup = apic_addr; |
| |
| printf("MP Floating Pointer Structure (address, then 12 bytes starting at 4): |
| %x, %x, %x, %x\n", (int)addr, |
| *((int *)(addr+4)), *((int *)(addr+8)), *((int *)(addr+12))); |
| |
| if (*((int *)(addr+4)) != 0) |
| { |
| addr = *((unsigned char **)(addr+4)); |
| apic_addr = *((unsigned long *)(addr+0x24)); |
| printf("MP Configuration Table, local APIC at (%x)\n", apic_addr); |
| } |
| |
| if (may_be_bad) |
| { |
| printf("Use this entry (y/n) ?"); |
| i = getc(); |
| putchar('\n'); |
| if (i != 'y') |
| { |
| apic_addr = backup; |
| return 0; |
| } |
| } |
| |
| return 1; |
| } |
| |
| |
| int |
| probe_mp_table(void) |
| { |
| int i, probe_addr = *((unsigned short *)0x40E); |
| |
| probe_addr <<= 4; |
| |
| if (probe_addr > 0 && probe_addr <= 639*1024 |
| && *((unsigned char *) probe_addr) > 0 |
| && probe_addr + *((unsigned char *) probe_addr) * 0x400 <= 640*1024) |
| { |
| for (i = 0; i < 1024; i += 16) |
| { |
| if (get_mp_parameters((unsigned char *)(probe_addr+i))) |
| return 1; |
| } |
| } |
| |
| /* |
| * Technically, if there is an EBDA, we shouldn't search the last |
| * KB of memory, but I don't think it will be a problem. |
| */ |
| |
| if (mbi.mem_lower > 512) |
| probe_addr = 639 * 1024; |
| else |
| probe_addr = 511 * 1024; |
| |
| for (i = 0; i < 1024; i += 16) |
| { |
| if (get_mp_parameters((unsigned char *)(probe_addr+i))) |
| return 1; |
| } |
| |
| for (probe_addr = 0xF0000; probe_addr < 0x100000; probe_addr += 16) |
| { |
| if (get_mp_parameters((unsigned char *)probe_addr)) |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| |
| void |
| copy_patch_code(void) |
| { |
| int start_addr = (128 * 1024); |
| |
| bcopy( patch_code, ((char *) start_addr), |
| ((int) patch_code_end) - ((int) patch_code) ); |
| |
| outb(0x70, 0xf); |
| *((volatile unsigned short *) 0x467) = 0; |
| *((volatile unsigned short *) 0x469) = ((unsigned short)(start_addr >> 4)); |
| outb(0x71, 0xa); |
| |
| print_error(); |
| } |
| |
| |
| void |
| send_init(int cpu_num) |
| { |
| int i, start_addr = (128 * 1024); |
| |
| *((volatile unsigned long *) (apic_addr+0x280)) = 0; |
| i = *((volatile unsigned long *) (apic_addr+0x280)); |
| |
| *((volatile unsigned long *) (apic_addr+0x310)) = (cpu_num << 24); |
| i = *((volatile unsigned long *) (apic_addr+0x280)); |
| *((volatile unsigned long *) (apic_addr+0x300)) = 0xc500; |
| |
| for (i = 0; i < 100000; i++); |
| |
| *((volatile unsigned long *) (apic_addr+0x300)) = 0x8500; |
| |
| for (i = 0; i < 1000000; i++); |
| |
| i = *((volatile unsigned long *) (apic_addr+0x280)); |
| |
| i &= 0xEF; |
| |
| if (i) |
| printf("APIC error (%x)\n", i); |
| } |
| |
| |
| void |
| send_startup(int cpu_num) |
| { |
| int i, start_addr = (128 * 1024); |
| |
| printf("Starting value = (%x)\n", *((int *) start_addr) ); |
| |
| *((volatile unsigned long *) (apic_addr+0x280)) = 0; |
| i = *((volatile unsigned long *) (apic_addr+0x280)); |
| |
| *((volatile unsigned long *) (apic_addr+0x310)) = (cpu_num << 24); |
| i = *((volatile unsigned long *) (apic_addr+0x280)); |
| *((volatile unsigned long *) (apic_addr+0x300)) = (0x600 | (start_addr>>12)); |
| |
| for (i = 0; i < 100000; i++); |
| |
| i = *((volatile unsigned long *) (apic_addr+0x280)); |
| |
| i &= 0xEF; |
| |
| if (i) |
| printf("APIC error (%x)\n", i); |
| else |
| { |
| printf("Waiting for RET..."); |
| |
| i = getc(); |
| |
| outb(0x70, 0xf); |
| printf("\nEnding value = (%x), Status code = (%x)\n", |
| *((int *) start_addr), (unsigned long)inb(0x71)); |
| } |
| } |
| |
| #endif /* DEBUG */ |
| |
| /* |
| * This is used for determining of the command-line should ask the user |
| * to correct errors. |
| */ |
| int fallback = -1; |
| |
| char * |
| skip_to(int after_equal, char *cmdline) |
| { |
| while (*cmdline && (*cmdline != (after_equal ? '=' : ' '))) |
| cmdline++; |
| |
| if (after_equal) |
| cmdline++; |
| |
| while (*cmdline == ' ') |
| cmdline++; |
| |
| return cmdline; |
| } |
| |
| |
| void |
| init_cmdline(void) |
| { |
| printf(" [ Minimal BASH-like line editing is supported. For the first word, TAB |
| lists possible command completions. Anywhere else TAB lists the possible |
| completions of a device/filename. ESC at any time exits. ]\n"); |
| } |
| |
| |
| #ifdef DEBUG |
| char commands[] = |
| " Possible commands are: \"pause= ...\", \"uppermem= <kbytes>\", \"root= <device>\", |
| \"rootnoverify= <device>\", \"chainloader= <file>\", \"kernel= <file> ...\", |
| \"testload= <file>\", \"syscmd= <cmd>\", \"displaymem\", \"probemps\", |
| \"module= <file> ...\", \"modulenounzip= <file> ...\", \"makeactive\", \"boot\", and |
| \"install= <stage1_file> [d] <dest_dev> <file> <addr> [p] [<config_file>]\"\n"; |
| #else /* DEBUG */ |
| char commands[] = |
| " Possible commands are: \"pause= ...\", \"uppermem= <kbytes>\", \"root= <device>\", |
| \"rootnoverify= <device>\", \"chainloader= <file>\", \"kernel= <file> ...\", |
| \"module= <file> ...\", \"modulenounzip= <file> ...\", \"makeactive\", \"boot\", and |
| \"install= <stage1_file> [d] <dest_dev> <file> <addr> [p] [<config_file>]\"\n"; |
| #endif /* DEBUG */ |
| |
| #ifdef DEBUG |
| static void |
| debug_fs_print_func(int sector) |
| { |
| printf("[%d]", sector); |
| } |
| #endif /* DEBUG */ |
| |
| |
| static int installaddr, installlist, installsect; |
| |
| static void |
| debug_fs_blocklist_func(int sector) |
| { |
| #ifdef DEBUG |
| printf("[%d]", sector); |
| #endif /* DEBUG */ |
| |
| if (*((unsigned long *)(installlist-4)) |
| + *((unsigned short *)installlist) != sector |
| || installlist == BOOTSEC_LOCATION+STAGE1_FIRSTLIST+4) |
| { |
| installlist -= 8; |
| |
| if (*((unsigned long *)(installlist-8))) |
| errnum = ERR_WONT_FIT; |
| else |
| { |
| *((unsigned short *)(installlist+2)) = (installaddr >> 4); |
| *((unsigned long *)(installlist-4)) = sector; |
| } |
| } |
| |
| *((unsigned short *)installlist) += 1; |
| installsect = sector; |
| installaddr += 512; |
| } |
| |
| |
| int |
| enter_cmdline(char *script, char *heap) |
| { |
| int bootdev, cmd_len, type = 0, run_cmdline = 1, have_run_cmdline = 0; |
| #ifdef DEBUG |
| int mptest = 0; |
| #endif /* DEBUG */ |
| char *cur_heap = heap, *cur_entry = script, *old_entry; |
| |
| /* initialization */ |
| saved_drive = boot_drive; |
| saved_partition = install_partition; |
| current_drive = 0xFF; |
| errnum = 0; |
| |
| /* restore memory probe state */ |
| mbi.mem_upper = saved_mem_upper; |
| if (mem_map) |
| mbi.flags |= MB_INFO_MEM_MAP; |
| |
| /* XXX evil hack !! */ |
| bootdev = bsd_bootdev(); |
| |
| if (!script) |
| { |
| init_page(); |
| init_cmdline(); |
| } |
| |
| restart: |
| if (script) |
| { |
| if (errnum) |
| { |
| if (fallback != -1) |
| return 0; |
| |
| print_error(); |
| run_cmdline = 1; |
| if (!have_run_cmdline) |
| { |
| have_run_cmdline = 1; |
| putchar('\n'); |
| init_cmdline(); |
| } |
| } |
| else |
| { |
| run_cmdline = 0; |
| |
| /* update position in the boot script */ |
| old_entry = cur_entry; |
| while (*(cur_entry++)); |
| |
| /* copy to work area */ |
| bcopy(old_entry, cur_heap, ((int)cur_entry) - ((int)old_entry)); |
| |
| printf("%s\n", old_entry); |
| } |
| } |
| else |
| { |
| cur_heap[0] = 0; |
| print_error(); |
| } |
| |
| if (run_cmdline && get_cmdline("command> ", commands, cur_heap, 2048)) |
| return 1; |
| |
| if (strcmp("boot", cur_heap) == 0 || (script && !*cur_heap)) |
| { |
| if ((type == 'f') | (type == 'n')) |
| bsd_boot(type, bootdev); |
| if (type == 'l') |
| linux_boot(); |
| |
| if (type == 'c') |
| { |
| gateA20(0); |
| boot_drive = saved_drive; |
| chain_stage1(0, BOOTSEC_LOCATION, BOOTSEC_LOCATION-16); |
| } |
| |
| if (!type) |
| { |
| printf(" Error, cannot boot unless kernel loaded.\n"); |
| |
| if (fallback != -1) |
| return 0; |
| |
| if (script) |
| { |
| printf("Press any key to continue..."); |
| getc(); |
| return 1; |
| } |
| else |
| goto restart; |
| } |
| |
| /* this is the final possibility */ |
| multi_boot((int)entry_addr, (int)(&mbi)); |
| } |
| |
| /* get clipped command-line */ |
| cur_cmdline = skip_to(1, cur_heap); |
| cmd_len = 0; |
| while (cur_cmdline[cmd_len++]); |
| |
| if (strcmp("chainloader", cur_heap) < 1) |
| { |
| if (open(cur_cmdline) && (read(BOOTSEC_LOCATION, SECTOR_SIZE) |
| == SECTOR_SIZE) |
| && (*((unsigned short *) (BOOTSEC_LOCATION+BOOTSEC_SIG_OFFSET)) |
| == BOOTSEC_SIGNATURE)) |
| type = 'c'; |
| else if (!errnum) |
| { |
| errnum = ERR_EXEC_FORMAT; |
| type = 0; |
| } |
| } |
| else if (strcmp("pause", cur_heap) < 1) |
| { |
| if (getc() == 27) |
| return 1; |
| } |
| else if (strcmp("uppermem", cur_heap) < 1) |
| { |
| if (safe_parse_maxint(&cur_cmdline, (int *)&(mbi.mem_upper))) |
| mbi.flags &= ~MB_INFO_MEM_MAP; |
| } |
| else if (strcmp("root", cur_heap) < 1) |
| { |
| set_device(cur_cmdline); |
| |
| /* this will respond to any "rootn<XXX>" command, |
| but that's OK */ |
| if (!errnum && (cur_heap[4] == 'n' || open_device() |
| || errnum == ERR_FSYS_MOUNT)) |
| { |
| errnum = 0; |
| saved_partition = current_partition; |
| saved_drive = current_drive; |
| |
| if (cur_heap[4] != 'n') |
| { |
| /* XXX evil hack !! */ |
| bootdev = bsd_bootdev(); |
| |
| print_fsys_type(); |
| } |
| else |
| current_drive = -1; |
| } |
| } |
| else if (strcmp("kernel", cur_heap) < 1) |
| { |
| /* make sure it's at the beginning of the boot heap area */ |
| bcopy(cur_heap, heap, cmd_len + (((int)cur_cmdline) - ((int)cur_heap))); |
| cur_cmdline = heap + (((int)cur_cmdline) - ((int)cur_heap)); |
| cur_heap = heap; |
| if (type = load_image()) |
| cur_heap = cur_cmdline + cmd_len; |
| } |
| else if (strcmp("module", cur_heap) < 1) |
| { |
| if (type == 'm') |
| { |
| #ifndef NO_DECOMPRESSION |
| /* this will respond to any "modulen<XXX>" command, |
| but that's OK */ |
| if (cur_heap[6] = 'n') |
| no_decompression = 1; |
| #endif /* NO_DECOMPRESSION */ |
| |
| if (load_module()) |
| cur_heap = cur_cmdline + cmd_len; |
| |
| #ifndef NO_DECOMPRESSION |
| no_decompression = 0; |
| #endif /* NO_DECOMPRESSION */ |
| } |
| else |
| errnum = ERR_NEED_KERNEL; |
| } |
| else if (strcmp("install", cur_heap) < 1) |
| { |
| char *stage1_file = cur_cmdline, *dest_dev, *file, *addr, *config_file; |
| char buffer[SECTOR_SIZE], old_sect[SECTOR_SIZE]; |
| int i = BOOTSEC_LOCATION+STAGE1_FIRSTLIST-4, new_drive = 0xFF; |
| |
| dest_dev = skip_to(0, stage1_file); |
| if (*dest_dev == 'd') |
| { |
| new_drive = 0; |
| dest_dev = skip_to(0, dest_dev); |
| } |
| file = skip_to(0, dest_dev); |
| addr = skip_to(0, file); |
| |
| if (safe_parse_maxint(&addr, &installaddr) && open(stage1_file) |
| && read((int)buffer, SECTOR_SIZE) == SECTOR_SIZE |
| && set_device(dest_dev) && open_partition() |
| && devread(0, 0, SECTOR_SIZE, (int)old_sect)) |
| { |
| int dest_drive = current_drive, dest_geom = buf_geom; |
| int dest_sector = part_start, i; |
| |
| #ifndef NO_DECOMPRESSION |
| no_decompression = 1; |
| #endif |
| |
| /* copy possible DOS BPB, 59 bytes at byte offset 3 */ |
| bcopy(old_sect+BOOTSEC_BPB_OFFSET, buffer+BOOTSEC_BPB_OFFSET, |
| BOOTSEC_BPB_LENGTH); |
| |
| /* if for a hard disk, copy possible MBR/extended part table */ |
| if ((dest_drive & 0x80) && current_partition == 0xFFFFFF) |
| bcopy(old_sect+BOOTSEC_PART_OFFSET, buffer+BOOTSEC_PART_OFFSET, |
| BOOTSEC_PART_LENGTH); |
| |
| if (*((short *)(buffer+STAGE1_VER_MAJ_OFFS)) != COMPAT_VERSION |
| || (*((unsigned short *) (buffer+BOOTSEC_SIG_OFFSET)) |
| != BOOTSEC_SIGNATURE) |
| || (!(dest_drive & 0x80) |
| && (*((unsigned char *) (buffer+BOOTSEC_PART_OFFSET)) == 0x80 |
| || buffer[BOOTSEC_PART_OFFSET] == 0))) |
| { |
| errnum = ERR_BAD_VERSION; |
| } |
| else if (open(file)) |
| { |
| if (!new_drive) |
| new_drive = current_drive; |
| |
| bcopy(buffer, (char*)BOOTSEC_LOCATION, SECTOR_SIZE); |
| |
| *((unsigned char *)(BOOTSEC_LOCATION+STAGE1_FIRSTLIST)) |
| = new_drive; |
| *((unsigned short *)(BOOTSEC_LOCATION+STAGE1_INSTALLADDR)) |
| = installaddr; |
| |
| i = BOOTSEC_LOCATION+STAGE1_FIRSTLIST-4; |
| while (*((unsigned long *)i)) |
| { |
| if (i < BOOTSEC_LOCATION+STAGE1_FIRSTLIST-256 |
| || (*((int *)(i-4)) & 0x80000000) |
| || *((unsigned short *)i) >= 0xA00 |
| || *((short *) (i+2)) == 0) |
| { |
| errnum = ERR_BAD_VERSION; |
| break; |
| } |
| |
| *((int *)i) = 0; |
| *((int *)(i-4)) = 0; |
| i -= 8; |
| } |
| |
| installlist = BOOTSEC_LOCATION+STAGE1_FIRSTLIST+4; |
| debug_fs = debug_fs_blocklist_func; |
| |
| if (!errnum && read(SCRATCHADDR, SECTOR_SIZE) == SECTOR_SIZE) |
| { |
| if (*((long *)SCRATCHADDR) != 0x8070ea |
| || (*((short *)(SCRATCHADDR+STAGE2_VER_MAJ_OFFS)) |
| != COMPAT_VERSION)) |
| errnum = ERR_BAD_VERSION; |
| else |
| { |
| int write_stage2_sect = 0, stage2_sect = installsect; |
| char *ptr; |
| |
| ptr = skip_to(0, addr); |
| |
| if (*ptr == 'p') |
| { |
| write_stage2_sect++; |
| *((long *)(SCRATCHADDR+STAGE2_INSTALLPART)) |
| = current_partition; |
| ptr = skip_to(0, ptr); |
| } |
| if (*ptr) |
| { |
| char *str |
| = ((char *) (SCRATCHADDR+STAGE2_VER_STR_OFFS)); |
| |
| write_stage2_sect++; |
| while (*(str++)); /* find string */ |
| while (*(str++) = *(ptr++)); /* do copy */ |
| } |
| |
| read(0x100000, -1); |
| |
| buf_track = -1; |
| |
| if (!errnum |
| && (biosdisk(BIOSDISK_SUBFUNC_WRITE, |
| dest_drive, dest_geom, |
| dest_sector, 1, (BOOTSEC_LOCATION>>4)) |
| || (write_stage2_sect |
| && biosdisk(BIOSDISK_SUBFUNC_WRITE, |
| current_drive, buf_geom, |
| stage2_sect, 1, SCRATCHSEG)))) |
| errnum = ERR_WRITE; |
| } |
| } |
| |
| debug_fs = NULL; |
| } |
| |
| #ifndef NO_DECOMPRESSION |
| no_decompression = 0; |
| #endif |
| } |
| } |
| #ifdef DEBUG |
| else if (strcmp("testload", cur_heap) < 1) |
| { |
| if (open(cur_cmdline)) |
| { |
| int i; |
| |
| debug_fs = debug_fs_print_func; |
| |
| /* |
| * Perform filesystem test on the specified file. |
| */ |
| |
| /* read whole file first */ |
| printf("Whole file: "); |
| |
| read(0x100000, -1); |
| |
| /* now compare two sections of the file read differently */ |
| |
| for (i = 0; i < 0x10ac0; i++) |
| { |
| *((unsigned char *)(0x200000+i)) = 0; |
| *((unsigned char *)(0x300000+i)) = 1; |
| } |
| |
| /* first partial read */ |
| printf("\nPartial read 1: "); |
| |
| filepos = 0; |
| read(0x200000, 0x7); |
| read(0x200007, 0x100); |
| read(0x200107, 0x10); |
| read(0x200117, 0x999); |
| read(0x200ab0, 0x10); |
| read(0x200ac0, 0x10000); |
| |
| /* second partial read */ |
| printf("\nPartial read 2: "); |
| |
| filepos = 0; |
| read(0x300000, 0x10000); |
| read(0x310000, 0x10); |
| read(0x310010, 0x7); |
| read(0x310017, 0x10); |
| read(0x310027, 0x999); |
| read(0x3109c0, 0x100); |
| |
| printf("\nHeader1 = 0x%x, next = 0x%x, next = 0x%x, next = 0x%x\n", |
| *((int *)0x200000), *((int *)0x200004), *((int *)0x200008), |
| *((int *)0x20000c)); |
| |
| printf("Header2 = 0x%x, next = 0x%x, next = 0x%x, next = 0x%x\n", |
| *((int *)0x300000), *((int *)0x300004), *((int *)0x300008), |
| *((int *)0x30000c)); |
| |
| for (i = 0; i < 0x10ac0 && *((unsigned char *)(0x200000+i)) |
| == *((unsigned char *)(0x300000+i)); i++); |
| |
| printf("Max is 0x10ac0: i=0x%x, filepos=0x%x\n", i, filepos); |
| |
| debug_fs = NULL; |
| } |
| } |
| else if (strcmp("syscmd", cur_heap) < 1) |
| { |
| switch(cur_cmdline[0]) |
| { |
| case 'F': |
| if (debug_fs) |
| { |
| debug_fs = NULL; |
| printf(" Filesystem tracing is now off\n"); |
| } |
| else |
| { |
| debug_fs = debug_fs_print_func; |
| printf(" Filesystem tracing if now on\n"); |
| } |
| break; |
| case 'R': |
| { |
| char *ptr = cur_cmdline+1; |
| int myaddr; |
| if (safe_parse_maxint(&ptr, &myaddr)) |
| printf("0x%x: 0x%x", myaddr, *((unsigned *)myaddr)); |
| } |
| break; |
| case 'r': |
| if (mptest) |
| { |
| list_regs(-1); |
| break; |
| } |
| case 'p': |
| if (mptest) |
| { |
| copy_patch_code(); |
| break; |
| } |
| case '0': case '1': case '2': case '3': case '4': |
| case '5': case '6': case '7': case '8': case '9': |
| if (mptest) |
| { |
| int j = cur_cmdline[0] - '0'; |
| switch (cur_cmdline[1]) |
| { |
| case 'i': |
| send_init(j); |
| break; |
| case 's': |
| send_startup(j); |
| break; |
| case 'r': |
| list_regs(j); |
| break; |
| case 'b': |
| boot_cpu(j); |
| } |
| break; |
| } |
| default: |
| printf("Bad subcommand, try again please\n"); |
| } |
| } |
| else if (strcmp("probemps", cur_heap) == 0) |
| { |
| apic_addr = 0xFEE00000; |
| |
| if (mptest = probe_mp_table()) |
| printf("APIC test (%x), SPIV test(%x)\n", |
| *((volatile unsigned long *) (apic_addr+0x30)), |
| *((volatile unsigned long *) (apic_addr+0xf0))); |
| else |
| printf("No MPS information found\n"); |
| } |
| else if (strcmp("displaymem", cur_heap) == 0) |
| { |
| if (get_eisamemsize() != -1) |
| printf(" EISA Memory BIOS Interface is present\n"); |
| if (get_mem_map(SCRATCHADDR, 0) != 0 || *((int *) SCRATCHADDR) != 0) |
| printf(" Address Map BIOS Interface is present\n"); |
| |
| printf(" Lower memory: %uK, Upper memory (to first chipset hole): %uK\n", |
| mbi.mem_lower, mbi.mem_upper); |
| |
| if (mbi.flags & MB_INFO_MEM_MAP) |
| { |
| struct AddrRangeDesc *map = (struct AddrRangeDesc *) mbi.mmap_addr; |
| int end_addr = mbi.mmap_addr + mbi.mmap_length; |
| |
| printf(" [Address Range Descriptor entries immediately follow (values are 64-bit)]\n"); |
| while (end_addr > (int)map) |
| { |
| char *str; |
| |
| if (map->Type == MB_ARD_MEMORY) |
| str = "Usable RAM"; |
| else |
| str = "Reserved"; |
| printf(" %s: Base Address: 0x%x X 4GB + 0x%x, |
| Length: %u X 4GB + %u bytes\n", |
| str, map->BaseAddrHigh, map->BaseAddrLow, |
| map->LengthHigh, map->LengthLow); |
| |
| map = ((struct AddrRangeDesc *) (((int)map) + 4 + map->size)); |
| } |
| } |
| } |
| #endif /* DEBUG */ |
| else if (strcmp("makeactive", cur_heap) == 0) |
| make_saved_active(); |
| else if (*cur_heap && *cur_heap != ' ') |
| errnum = ERR_UNRECOGNIZED; |
| |
| goto restart; |
| } |
| |