diff options
author | Michael Brown | 2012-07-10 20:26:41 +0200 |
---|---|---|
committer | Michael Brown | 2015-04-21 01:39:17 +0200 |
commit | be35022f55e5cf8f864d7aac079f9a8a433d84f9 (patch) | |
tree | f0906b02eaab6a44c9b84ed11701064c85c53179 | |
parent | [pxe] Add memtest.0 target which can be loaded as a PXE NBP (diff) | |
download | memtest86-be35022f55e5cf8f864d7aac079f9a8a433d84f9.tar.gz memtest86-be35022f55e5cf8f864d7aac079f9a8a433d84f9.tar.xz memtest86-be35022f55e5cf8f864d7aac079f9a8a433d84f9.zip |
[pxe] Switch back to real mode on exit
Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | exit.S | 81 | ||||
-rw-r--r-- | lib.c | 8 | ||||
-rw-r--r-- | main.c | 30 | ||||
-rw-r--r-- | test.h | 8 |
5 files changed, 126 insertions, 6 deletions
@@ -15,7 +15,7 @@ CC=gcc CFLAGS= -Wall -march=i486 -m32 -O1 -fomit-frame-pointer -fno-builtin \ -ffreestanding -fPIC $(SMP_FL) -fno-stack-protector -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 memsize.o spd.o error.o dmi.o controller.o \ smp.o vmem.o random.o @@ -48,6 +48,9 @@ setup.s: setup.S config.h defs.h 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 @@ -0,0 +1,81 @@ +/* + * 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 + + /* 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 + + /* 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 @@ -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(); + v->exit++; + bail++; break; case 46: /* c - Configure */ @@ -1196,4 +1200,4 @@ void get_list(int x, int y, int len, char *buf) return; } } -}
\ No newline at end of file +} @@ -203,7 +203,7 @@ void btrace(int me, int line, char *msg, int wait, long v1, long v2) } /* 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); @@ -526,6 +526,25 @@ void test_start(void) btrace(my_cpu_num, __LINE__, "Start Done", 1, 0, 0); start_seq = 2; + /* Exit if testing has finished */ + if (v->exit) { + paging_off(); + set_cache(1); + barrier(); + if (my_cpu_num == 0) { + if (v->ecount) { + exit(EXIT_FAILURE); + } else if (v->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 */ @@ -550,6 +569,11 @@ void test_start(void) btrace(my_cpu_num, __LINE__, "Sched_Barr", 1,window,win_next); barrier(); + /* Exit if testing has finished */ + if (v->exit) { + run_at(LOW_TEST_ADR, my_cpu_num); + } + /* Don't go over the 8TB PAE limit */ if (win_next > MAX_MEM) { break; @@ -759,8 +783,8 @@ void test_start(void) if (v->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) { v->exit++; } if (!btflag) cprint(LINE_MSG, COL_MSG-8, "** Pass complete, no errors, press Esc to exit **"); if(BEEP_END_NO_ERROR) { @@ -173,6 +173,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); @@ -190,6 +191,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); #define PRINTMODE_SUMMARY 0 #define PRINTMODE_ADDRESSES 1 @@ -302,6 +304,7 @@ struct vars { int fail_safe; int each_sec; int beepmode; + int exit; }; #define FIRMWARE_UNKNOWN 0 @@ -314,5 +317,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_ */ |