diff options
-rw-r--r-- | Makefile | 18 | ||||
-rw-r--r-- | defs.h | 3 | ||||
-rw-r--r-- | dmi.c | 6 | ||||
-rw-r--r-- | exit.S | 112 | ||||
-rw-r--r-- | head.S | 8 | ||||
-rw-r--r-- | init.c | 3 | ||||
-rw-r--r-- | lib.c | 6 | ||||
-rw-r--r-- | main.c | 86 | ||||
-rw-r--r-- | pxe.S | 117 | ||||
-rw-r--r-- | setup.S | 21 | ||||
-rw-r--r-- | smp.c | 13 | ||||
-rw-r--r-- | test.h | 10 |
12 files changed, 354 insertions, 49 deletions
@@ -16,14 +16,13 @@ CFLAGS= -Wall -Werror -march=i486 -m32 -O1 -fomit-frame-pointer -fno-builtin \ -ffreestanding -fPIC $(SMP_FL) -fno-stack-protector SELF_TEST_CFLAGS = -Wall -Werror -march=i486 -m32 -O1 -g - -OBJS= head.o reloc.o main.o test.o init.o lib.o patn.o screen_buffer.o \ +OBJS= head.o exit.o reloc.o main.o test.o init.o lib.o patn.o screen_buffer.o \ config.o cpuid.o linuxbios.o pci.o spd.o error.o dmi.o controller.o \ smp.o vmem.o memsize.o random.o SELF_TEST_OBJS = test.o self_test.o cpuid.o random.o -all: clean memtest.bin memtest +all: memtest.bin memtest memtest.0 run_self_test : self_test ./self_test && touch run_self_test @@ -54,6 +53,12 @@ bootsect.s: bootsect.S config.h defs.h setup.s: setup.S config.h defs.h $(CC) -E -traditional $< -o $@ +pxe.s: pxe.S config.h defs.h + $(CC) -E -traditional $< -o $@ + +exit.s: exit.S config.h defs.h + $(CC) -E -traditional $< -o $@ + memtest.bin: memtest_shared.bin bootsect.o setup.o memtest.bin.lds $(LD) -T memtest.bin.lds bootsect.o setup.o -b binary \ memtest_shared.bin -o memtest.bin @@ -61,6 +66,11 @@ memtest.bin: memtest_shared.bin bootsect.o setup.o memtest.bin.lds self_test.o : self_test.c $(CC) -c $(SELF_TEST_CFLAGS) self_test.c +memtest.0: memtest_shared.bin pxe.o setup.o memtest.bin.lds + $(LD) -T memtest.bin.lds pxe.o setup.o -b binary \ + memtest_shared.bin -o memtest.0 + + memsize.o: memsize.c $(CC) -Wall -Werror -march=i486 -m32 -O0 -fomit-frame-pointer -fno-builtin -ffreestanding -fPIC $(SMP_FL) -fno-stack-protector -c -o memsize.o memsize.c @@ -69,7 +79,7 @@ random.o: random.c clean: rm -f *.o *.s *.iso memtest.bin memtest memtest_shared \ - memtest_shared.bin memtest.iso run_self_test self_test + memtest_shared.bin memtest.iso run_self_test self_test memtest.0 iso: make all @@ -24,3 +24,6 @@ #define KERNEL_DS 0x18 /* 32 bit segment adrs for data */ #define REAL_CS 0x20 /* 16 bit segment adrs for code */ #define REAL_DS 0x28 /* 16 bit segment adrs for data */ + +/* Magic marker to determine if exit stack is intact */ +#define EXIT_MAGIC ( 'E' + ( 'X' << 8 ) + ( 'I' << 16 ) + ( 'T' << 24 ) ) @@ -209,11 +209,13 @@ int open_dmi(void){ while(dmi < table_start + eps->tablelength){ struct tstruct_header *header = (struct tstruct_header *)dmi; - if (header->type == 17) + if ((header->type == 17) && + (mem_devs_count < MAX_DMI_MEMDEVS)) mem_devs[mem_devs_count++] = (struct mem_dev *)dmi; // Mem Dev Map - if (header->type == 20) + if ((header->type == 20) && + (md_maps_count < MAX_DMI_MEMDEVS)) md_maps[md_maps_count++] = (struct md_map *)dmi; // MB_SPEC @@ -0,0 +1,112 @@ +/* + * exit.S Copyright (C) 2012 Michael Brown <mcb30@ipxe.org> + * + */ + +#include "defs.h" + +.text +.code32 +.globl exit +exit: + /* Exit status to %eax */ + movl 4(%esp), %eax + + /* Calculate real-mode exit %ss:esp in %dx:%edi */ + xorw %dx, %dx + xorl %edi, %edi + movl exit_esp, %ebp + cmpl $EXIT_MAGIC, 0(%ebp) + jne 1f + movl 8(%ebp), %edi + movw 6(%ebp), %dx +1: + /* Load IDT and GDT and switch to 16-bit code segment */ + cli + lidt idt_descr + lgdt gdt_descr + ljmp $REAL_CS, $(1f - LOW_TEST_ADR) +1: + .code16 + /* Load 16-bit limits for other segment registers */ + movw $REAL_DS, %bx + movw %bx, %ds + movw %bx, %es + movw %bx, %fs + movw %bx, %gs + movw %bx, %ss + movl $LOW_TEST_ADR, %esp + + /* Switch to real mode */ + movl %cr0, %ebx + andb $~0x01, %bl + movl %ebx, %cr0 + ljmp $(LOW_TEST_ADR >> 4), $1f +1: + /* Load real-mode segment registers */ + xorw %bx, %bx + movw %bx, %ds + movw %bx, %es + movw %bx, %fs + movw %bx, %gs + movw %bx, %ss + + /* Reenable interrupts */ + sti + + /* If we have a real-mode exit stack, restore registers + * (except exit status) and return + */ + testl %edi, %edi + jz reset + movw %dx, %ss + movl %edi, %esp + movw %sp, %bp + movl %eax, 36(%bp) + popw %ds + popw %es + popw %fs + popw %gs + popal + popfl + lret + +reset: + /* Perform a warm reset */ + movw $0x1234, %ax + movw %ax, 0x472 + movb $0xfe, %al + outb %al, $0x64 + + /* If reset failed, halt the CPU */ + cli + hlt + +.align 16 +gdt: + /* Dummy */ + .word 0,0,0,0 + /* Unused */ + .word 0,0,0,0 + /* Unused */ + .word 0,0,0,0 + /* Unused */ + .word 0,0,0,0 + /* 16 bit real mode code segment */ + .word 0xffff, ( LOW_TEST_ADR & 0xffff ) + .word ( 0x9b00 | ( LOW_TEST_ADR >> 16 ) ), 0 + /* 16 bit real mode data segment */ + .word 0xffff, 0, 0x9300, 0 +gdt_end: +gdt_descr: + .word gdt_end - gdt - 1 + .long gdt + +.align 16 +idt_descr: + .word 0xffff + .long 0 + +.globl exit_esp +exit_esp: + .long 0 @@ -35,6 +35,12 @@ startup_32: 0: popl %ebx addl $_GLOBAL_OFFSET_TABLE_+[.-0b], %ebx + /* Store the exit stack address */ + cmpl $0, exit_esp@GOTOFF(%ebx) + jnz 0f + movl %esp, exit_esp@GOTOFF(%ebx) +0: + /* Pick the appropriate boot_stack address */ leal boot_stack_top@GOTOFF(%ebx), %esp @@ -806,7 +812,7 @@ idt_real: .globl _ap_trampoline_protmode .code16 _ap_trampoline_start: - lgdt 0x0 /* will be fixed up later, see smp.c:BootAP()*/ + cs lgdt 0x100 /* will be filled in by boot_ap() */ movl %cr0, %eax orl $1, %eax movl %eax, %cr0 @@ -46,6 +46,7 @@ static void get_cache_size(); static void cpu_cache_speed(); void get_cpuid(); int beepmode; +int conservative_smp = CONSERVATIVE_SMP; extern short dmi_initialized; extern int dmi_err_cnts[MAX_DMI_MEMDEVS]; @@ -636,7 +637,7 @@ void smp_default_mode(void) } // For 5.01 release, SMP disabled by defualt by config.h toggle - if(CONSERVATIVE_SMP) { vv->fail_safe |= 0b10; } + if(conservative_smp) { vv->fail_safe |= 0b10; } } @@ -28,6 +28,9 @@ int serial_baud_rate = SERIAL_BAUD_RATE; unsigned char serial_parity = 0; unsigned char serial_bits = 8; +extern volatile int mstr_cpu; +extern volatile int bail; + struct ascii_map_str { int ascii; int keycode; @@ -632,7 +635,8 @@ void check_input(void) case 1: /* "ESC" key was pressed, bail out. */ cprint(LINE_RANGE, COL_MID+23, "Halting... "); - reboot(); + vv->exit++; + bail++; break; case 46: /* c - Configure */ @@ -40,6 +40,8 @@ extern void rand_seed(unsigned int seed1, unsigned int seed2, int cpu); extern struct barrier_s *barr; extern int num_cpus; extern int act_cpus; +extern unsigned smp_page; +extern int conservative_smp; static int find_ticks_for_test(int test); void find_ticks_for_pass(void); @@ -72,6 +74,7 @@ volatile short cpu_mode; char cpu_mask[MAX_CPUS]; long bin_mask=0xffffffff; short onepass; +static short onefail; volatile short btflag = 0; volatile int test; short restart_flag; @@ -179,7 +182,8 @@ void btrace(int me, int line, char *msg, int wait, long v1, long v2) /* Is tracing turned on? */ if (btflag == 0) return; - spin_lock(&barr->mutex); + if (barr) + spin_lock(&barr->mutex); y = tidx%13; x = tidx/13*40; cplace(y+11, x+1, ' '); @@ -198,11 +202,12 @@ void btrace(int me, int line, char *msg, int wait, long v1, long v2) if (wait) { wait_keyup(); } - spin_unlock(&barr->mutex); + if (barr) + spin_unlock(&barr->mutex); } /* Relocate the test to a new address. Be careful to not overlap! */ -static void run_at(unsigned long addr, int cpu) +void run_at(unsigned long addr, int cpu) { ulong *ja = (ulong *)(addr + startup_32 - _start); @@ -233,12 +238,10 @@ switch_to_main_stack(unsigned cpu_num) extern uintptr_t boot_stack_top; uintptr_t *src, *dst; int offs; - uint8_t * stackAddr, *stackTop; + uint8_t *stackTop; - stackAddr = (uint8_t *) &stacks[cpu_num][0]; + stackTop = (uint8_t *) &stacks[MAX_CPUS - cpu_num][0]; - stackTop = stackAddr + STACKSIZE_BYTES; - src = (uintptr_t*)&boot_stack_top; dst = (uintptr_t*)stackTop; do { @@ -259,12 +262,15 @@ switch_to_main_stack(unsigned cpu_num) #define OLD_CL_MAGIC_ADDR ((unsigned short*) MK_PTR(INITSEG,0x20)) #define OLD_CL_MAGIC 0xA33F #define OLD_CL_OFFSET_ADDR ((unsigned short*) MK_PTR(INITSEG,0x22)) +#define PXE_CL_MAGIC_ADDR ((unsigned short*) MK_PTR(BOOTSEG,0x20)) +#define PXE_CL_OFFSET_ADDR ((unsigned short*) MK_PTR(BOOTSEG,0x22)) static void parse_command_line(void) { long simple_strtoul(char *cmd, char *ptr, int base); char *cp, dummy; int i, j, k; + unsigned short offset; if (cmdline_parsed) return; @@ -274,11 +280,15 @@ static void parse_command_line(void) cpu_mask[i] = 1; } - if (*OLD_CL_MAGIC_ADDR != OLD_CL_MAGIC) + if (*OLD_CL_MAGIC_ADDR == OLD_CL_MAGIC) { + offset = *OLD_CL_OFFSET_ADDR; + cp = MK_PTR(INITSEG, offset); + } else if (*PXE_CL_MAGIC_ADDR == OLD_CL_MAGIC) { + offset = *PXE_CL_OFFSET_ADDR; + cp = MK_PTR(BOOTSEG, offset); + } else { return; - - unsigned short offset = *OLD_CL_OFFSET_ADDR; - cp = MK_PTR(INITSEG, offset); + } /* skip leading spaces */ while (*cp == ' ') @@ -299,11 +309,21 @@ static void parse_command_line(void) cp += 8; maxcpus=(int)simple_strtoul(cp, &dummy, 10); } + /* Allow SMP to be enabled by default */ + if (!mt86_strncmp(cp, "smp", 3)) { + cp += 3; + conservative_smp = 0; + } /* Run one pass and exit if there are no errors */ if (!mt86_strncmp(cp, "onepass", 7)) { cp += 7; onepass++; } + /* Exit immediately on failure */ + if (!mt86_strncmp(cp, "onefail", 7)) { + cp += 7; + onefail++; + } /* Setup a list of tests to run */ if (!mt86_strncmp(cp, "tstlist=", 8)) { cp += 8; @@ -398,12 +418,12 @@ void test_start(void) smp_set_ordinal(my_cpu_num, my_cpu_ord); parse_command_line(); clear_screen(); - /* Initialize the barrier so the lock in btrace will work. - * Will get redone later when we know how many CPUs we have */ - barrier_init(1); btrace(my_cpu_num, __LINE__, "Begin ", 1, 0, 0); /* Find memory size */ mem_size(); /* must be called before initialise_cpus(); */ + /* Reserve highest basemem page for SMP locks and bootstrap */ + smp_page = --vv->pmap[0].end; + barrier_init(1); /* Fill in the CPUID table */ get_cpuid(); /* Startup the other CPUs */ @@ -429,10 +449,6 @@ void test_start(void) } win1_end = (high_test_adr >> 12); - /* Adjust the map to not test the page at 939k, - * reserved for locks */ - vv->pmap[0].end--; - find_ticks_for_pass(); } else { /* APs only, Register the APs */ @@ -523,6 +539,25 @@ void test_start(void) btrace(my_cpu_num, __LINE__, "Start Done", 1, 0, 0); start_seq = 2; + /* Exit if testing has finished */ + if (vv->exit) { + paging_off(); + set_cache(1); + barrier(); + if (my_cpu_num == 0) { + if (vv->ecount) { + exit(EXIT_FAILURE); + } else if (vv->pass) { + exit(EXIT_SUCCESS); + } else { + exit(EXIT_INCOMPLETE); + } + } else { + /* Halt APs */ + __asm__ __volatile__ ( "cli ; hlt" ); + } + } + /* Loop through all tests */ while (1) { /* If the restart flag is set all initial params */ @@ -547,6 +582,11 @@ void test_start(void) btrace(my_cpu_num, __LINE__, "Sched_Barr", 1,window,win_next); barrier(); + /* Exit if testing has finished */ + if (vv->exit) { + run_at(LOW_TEST_ADR, my_cpu_num); + } + /* Don't go over the 8TB PAE limit */ if (win_next > MAX_MEM_PAGES) { break; @@ -737,6 +777,12 @@ void test_start(void) } //???? btrace(my_cpu_num, __LINE__, "Next_CPU ",1,cpu_sel,test); + /* If onefail is enabled and we have seen any errors then + * exit the test */ + if (onefail && vv->ecount) { + vv->exit++; + } + /* If this was the last test then we finished a pass */ if (pass_flag) { @@ -751,8 +797,8 @@ void test_start(void) if (vv->ecount == 0) { /* If onepass is enabled and we did not get any errors - * reboot to exit the test */ - if (onepass) { reboot(); } + * exit the test */ + if (onepass) { vv->exit++; } if (!btflag) cprint(LINE_MSG, COL_MSG-8, "** Pass complete, no errors, press Esc to exit **"); @@ -0,0 +1,117 @@ +/* + * pxe.S Copyright (C) 2012 Michael Brown <mcb30@ipxe.org> + * + * pxe.S is loaded at 0x7c00 by the PXE ROM. It copies the 32-bit + * portion to 0x10000 and jumps into setup.S. + */ + +#include "defs.h" + +#define RMSIZE (0x200 + 0x200*SETUPSECS) + +#define PXENV_ENTRY 0x0a +#define PXENV_UNDI_SHUTDOWN 0x0005 +#define PXENV_FILE_CMDLINE 0x00e8 + +#define CMDLINE_MAGIC 0xa33f + +.code16 +.section ".bootsect", "ax", @progbits +.org 0 +_pxe: + +.globl _main +_main: + /* Canonicalise addresses */ + ljmp $BOOTSEG, $pxe_start + + /* Command line magic */ +.org 0x20 +cmdline_magic: + .word 0 +cmdline_offset: + .word 0 + +pxe_start: + /* Preserve registers, %ss:%esp, and magic marker on PXE stack */ + pushfl + pushal + pushw %gs + pushw %fs + pushw %es + pushw %ds + pushl %esp + pushw %ss + pushw %ax /* Padding */ + pushl $EXIT_MAGIC + + /* Store PXENV+ entry point */ + movl %es:PXENV_ENTRY(%bx), %eax + movl %eax, %cs:pxenv_vector + + /* Copy 32-bit portion to TSTLOAD:0000. Perform copy in + * reverse in 1kB blocks, since regions will overlap and we + * need to copy more than the 64kB real-mode segment limit. + */ + movw $_syssize, %bx /* Length is _syssize (paragraphs) */ + addw $63, %bx + andw $~63, %bx /* Round up to nearest kB */ + movw $(BOOTSEG + (RMSIZE >> 4)), %ax + addw %bx, %ax + movw %ax, %ds + movw $TSTLOAD, %ax + addw %bx, %ax + movw %ax, %es +1: movw %ds, %ax /* Decrement %ds and %es by 1kB */ + subw $64, %ax + movw %ax, %ds + movw %es, %ax + subw $64, %ax + movw %ax, %es + movw $256, %cx /* Copy 1kB block */ + xorw %si, %si + xorw %di, %di + cld + rep movsl + subw $64, %bx + jnz 1b + + /* Set up %ds and %es for access to local variables */ + movw %cs, %ax + movw %ax, %ds + movw %ax, %es + + /* Check for a command line */ + movw $PXENV_FILE_CMDLINE, %bx + movw $pxenv_file_cmdline, %di + lcall *pxenv_vector + testw %ax, %ax + jnz no_cmdline + movw pxenv_file_cmdline + 2, %ax + testw %ax, %ax + jz no_cmdline + movw $CMDLINE_MAGIC, cmdline_magic + movw $RMSIZE, cmdline_offset +no_cmdline: + + /* Shutdown NIC */ + movw $PXENV_UNDI_SHUTDOWN, %bx + movw $pxenv_undi_shutdown, %di + lcall *pxenv_vector + + /* Jump to setup.S */ + ljmp $(BOOTSEG + 0x20), $0 + +pxenv_vector: + .word 0,0 + +pxenv_undi_shutdown: + .word 0 /* Status */ + +pxenv_file_cmdline: + .word 0 /* Status */ + .word 0xffff /* 64kB max length of command line */ + .word RMSIZE, BOOTSEG + +.org 512 +_epxe: @@ -22,18 +22,11 @@ start: outb %al, $0x70 # The system will move itself to its rightful place. -# reload the segment registers and the stack since the -# APs also execute this code -#ljmp $INITSEG, $(reload - start + 0x200) -reload: - movw $INITSEG, %ax + xorl %eax, %eax + movw %cs, %ax movw %ax, %ds - movw %ax, %es - movw %ax, %fs - movw %ax, %ss # reset the stack to INITSEG:0x4000-12. - movw %dx, %sp - push %cs - pop %ds + shll $4, %eax + addl %eax, gdt_48 - start + 2 lidt idt_48 - start # load idt with 0,0 lgdt gdt_48 - start # load gdt with whatever appropriate @@ -80,6 +73,9 @@ alt_a20_done: * Note that the short jump isn't strictly needed, althought there are * reasons why it might be a good idea. It won't hurt in any case. */ + xorl %ebx, %ebx + movw %ss, %bx + shll $4, %ebx movw $0x0001, %ax # protected mode (PE) bit lmsw %ax # This is it# jmp flush_instr @@ -88,6 +84,7 @@ flush_instr: movw %ax, %ds movw %ax, %es movw %ax, %ss + addl %ebx, %esp movw %ax, %fs movw %ax, %gs @@ -144,7 +141,7 @@ idt_48: gdt_48: .word 0x800 # gdt limit=2048, 256 GDT entries - .word 512+gdt - start,0x9 # gdt base = 0X9xxxx + .long gdt - start # gdt base msg1: .asciz "Setup.S\r\n" @@ -27,6 +27,8 @@ extern int maxcpus; extern char cpu_mask[]; extern struct cpu_ident cpu_id; +unsigned smp_page; + struct barrier_s *barr; void smp_find_cpus(); @@ -34,7 +36,7 @@ void smp_find_cpus(); void barrier_init(int max) { /* Set the adddress of the barrier structure */ - barr = (struct barrier_s *)0x9ff00; + barr = (struct barrier_s *)((smp_page << 12) + 0x300); barr->lck.slock = 1; barr->mutex.slock = 1; barr->maxproc = max; @@ -258,9 +260,9 @@ void kick_cpu(unsigned cpu_num) // These memory locations are used for the trampoline code and data. -#define BOOTCODESTART 0x9000 -#define GDTPOINTERADDR 0x9100 -#define GDTADDR 0x9110 +#define BOOTCODESTART ((smp_page << 12)) +#define GDTPOINTERADDR (BOOTCODESTART + 0x100) +#define GDTADDR (BOOTCODESTART + 0x110) void boot_ap(unsigned cpu_num) { @@ -274,9 +276,6 @@ void boot_ap(unsigned cpu_num) memcpy((uint8_t*)BOOTCODESTART, &_ap_trampoline_start, len); - // Fixup the LGDT instruction to point to GDT pointer. - PUT_MEM16(BOOTCODESTART + 3, GDTPOINTERADDR); - // Copy a pointer to the temporary GDT to addr GDTPOINTERADDR. // The temporary gdt is at addr GDTADDR PUT_MEM16(GDTPOINTERADDR, 4 * 8); @@ -53,7 +53,7 @@ typedef unsigned long ulong; #define DMI_SEARCH_START 0x0000F000 #define DMI_SEARCH_LENGTH 0x000F0FFF -#define MAX_DMI_MEMDEVS 16 +#define MAX_DMI_MEMDEVS 128 #define TITLE_WIDTH 28 #define LINE_TITLE 0 @@ -178,6 +178,7 @@ int get_key(void); int ascii_to_keycode(int in); void wait_keyup(void); void print_hdr(void); +void run_at(unsigned long addr, int cpu); void restart(void); void parity_err(ulong edi, ulong esi); void start_config(void); @@ -195,6 +196,7 @@ void bit_fade_fill(unsigned long n, int cpu); void bit_fade_chk(unsigned long n, int cpu); void find_ticks_for_pass(void); void beep(unsigned int frequency); +void exit(int status); // Expose foreach_segment here for self_test, otherwise // it would be local to test.c: @@ -330,6 +332,7 @@ struct vars { int each_sec; int beepmode; int debugging; // Set in selftest only + int exit; }; #define FIRMWARE_UNKNOWN 0 @@ -342,5 +345,10 @@ extern unsigned char _size, _pages; extern struct mem_info_t mem_info; +/* Exit codes */ +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 +#define EXIT_INCOMPLETE 2 + #endif /* __ASSEMBLY__ */ #endif /* _TEST_H_ */ |