summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile18
-rw-r--r--defs.h3
-rw-r--r--dmi.c6
-rw-r--r--exit.S112
-rw-r--r--head.S8
-rw-r--r--init.c3
-rw-r--r--lib.c6
-rw-r--r--main.c86
-rw-r--r--pxe.S117
-rw-r--r--setup.S21
-rw-r--r--smp.c13
-rw-r--r--test.h10
12 files changed, 354 insertions, 49 deletions
diff --git a/Makefile b/Makefile
index 9295258..d6e938c 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/defs.h b/defs.h
index 1b77f2c..f7818af 100644
--- a/defs.h
+++ b/defs.h
@@ -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 ) )
diff --git a/dmi.c b/dmi.c
index 41b0347..1a43ab0 100644
--- a/dmi.c
+++ b/dmi.c
@@ -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
diff --git a/exit.S b/exit.S
new file mode 100644
index 0000000..a118c13
--- /dev/null
+++ b/exit.S
@@ -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
diff --git a/head.S b/head.S
index d551336..2464791 100644
--- a/head.S
+++ b/head.S
@@ -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
diff --git a/init.c b/init.c
index 32bff7f..64be39f 100644
--- a/init.c
+++ b/init.c
@@ -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; }
}
diff --git a/lib.c b/lib.c
index 64da2b7..aa638c9 100644
--- a/lib.c
+++ b/lib.c
@@ -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 */
diff --git a/main.c b/main.c
index d0c9289..af3e150 100644
--- a/main.c
+++ b/main.c
@@ -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 **");
diff --git a/pxe.S b/pxe.S
new file mode 100644
index 0000000..de3dd89
--- /dev/null
+++ b/pxe.S
@@ -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:
diff --git a/setup.S b/setup.S
index f80875b..2fe3d2d 100644
--- a/setup.S
+++ b/setup.S
@@ -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"
diff --git a/smp.c b/smp.c
index c101c36..9621d11 100644
--- a/smp.c
+++ b/smp.c
@@ -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);
diff --git a/test.h b/test.h
index 8b2e924..0c42723 100644
--- a/test.h
+++ b/test.h
@@ -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_ */