- Support for CMOS options

- Workaround cmos tables overlapping the traditional bios data segment
- Fixes to the p4dc6 examples to be syntactically correct
- Fixes to NLBConfig to fix the previos syntax error ``option foo bar'' is invalid
- Update docmil_fil_inbuf to only be compiled when the appropriate options are set
- Updates NLBConfig.py to export the variables MAINBOARD && TARGET_DIR
  as well as correct specify the generated files
This commit is contained in:
Eric W. Biederman 2002-01-29 20:28:24 +00:00
commit 031d2a1ffd
16 changed files with 702 additions and 118 deletions

View file

@ -2,6 +2,7 @@
#include <boot/linuxbios_tables.h>
#include <boot/linuxbios_table.h>
#include <printk.h>
#include <string.h>
struct lb_header *lb_table_init(unsigned long addr)
{
@ -86,25 +87,16 @@ void lb_memory_range(struct lb_memory *mem,
static void lb_reserve_table_memory(struct lb_header *head)
{
struct lb_record *rec, *last_rec;
struct lb_record *last_rec;
struct lb_memory *mem;
uint64_t start;
uint64_t end;
int i, entries;
last_rec = lb_last_record(head);
mem = 0;
for(rec = lb_first_record(head); rec < last_rec; lb_next_record(rec)) {
if (rec->tag == LB_TAG_MEMORY) {
mem = (struct lb_memory *)rec;
break;
}
}
if (!mem)
return;
printk_debug("head = %p last_rec = %p\n", head, last_rec);
mem = get_lb_mem();
start = (unsigned long)head;
end = (unsigned long)last_rec;
printk_debug("start = 0x%08lx end = 0x%08lx\n", (unsigned long)start, (unsigned long)end);
entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
/* Resize the right two memory areas so this table is in
* a reserved area of memory. Everything has been carefully
@ -137,7 +129,7 @@ unsigned long lb_table_fini(struct lb_header *head)
head->table_checksum = compute_ip_checksum(first_rec, head->table_bytes);
head->header_checksum = 0;
head->header_checksum = compute_ip_checksum(head, sizeof(*head));
printk_debug("Write linuxbios table at: %p - %p\n",
printk_debug("Wrote linuxbios table at: %p - %p\n",
head, rec);
return (unsigned long)rec;
}
@ -162,11 +154,18 @@ unsigned long write_linuxbios_table(
{
struct lb_header *head;
struct lb_memory *mem;
struct lb_record *rec_dest, *rec_src;
head = lb_table_init(low_table_end);
low_table_end = (unsigned long)head;
#if HAVE_OPTION_TABLE == 1
/* Write the option config table... */
rec_dest = lb_new_record(head);
rec_src = (struct lb_record *)&option_table;
memcpy(rec_dest, rec_src, rec_src->size);
#endif
mem = lb_memory(head);
mem_ranges = mem;
/* Reserve our tables in low memory */
lb_memory_range(mem, LB_MEM_RESERVED, low_table_start, low_table_end - low_table_start);
lb_memory_range(mem, LB_MEM_RAM, low_table_end, 640*1024 - low_table_end);
@ -180,6 +179,5 @@ unsigned long write_linuxbios_table(
low_table_end = lb_table_fini(head);
/* Remember where my valid memory ranges are */
mem_ranges = mem;
return low_table_end;
}

View file

@ -181,7 +181,11 @@ void write_tables(unsigned long totalram)
/* The smp table must be in 0-1K, 639K-640K, or 960K-1M */
low_table_end = write_smp_table(low_table_end, processor_map);
/* The linuxbios table must be in 0-1K or 960K-1M */
/* Don't write anything in the traditional x86 BIOS data segment */
if (low_table_end < 0x500) {
low_table_end = 0x500;
}
/* The linuxbios table must be in 0-4K or 960K-1M */
write_linuxbios_table(
processor_map, totalram,
low_table_start, low_table_end,

View file

@ -1,20 +1,26 @@
## This is Architecture independant part of the makefile
makedefine CC:=gcc
makedefine CPP:= gcc -x assembler-with-cpp -DASSEMBLY -E
option CROSS_COMPILE
makedefine CC:=$(CROSS_COMPILE)gcc
makedefine CPP:= $(CROSS_COMPILE)gcc -x assembler-with-cpp -DASSEMBLY -E
makedefine OBJCOPY:=$(CROSS_COMPILE)objcopy
makedefine LIBGCC_FILE_NAME := $(shell $(CC) -print-libgcc-file-name)
makedefine GCC_INC_DIR := $(shell $(CC) -print-search-dirs | sed -ne "s/install: \(.*\)/\1include/gp")
makedefine CPPFLAGS := -I$(TOP)/src/include -I$(TOP)/src/arch/$(ARCH)/include -I$(GCC_INC_DIR) $(CPUFLAGS)
makedefine CFLAGS := $(CPU_OPT) $(CPPFLAGS) -Os -nostdinc -nostdlib -fno-builtin -Wall
makedefine HOSTCC:=gcc
makedefine HOSTCFLAGS:= -Os -Wall
makerule ldscript.ld : ldoptions $(LDSUBSCRIPTS-1) ; echo "INCLUDE ldoptions" > $@ ; for file in $(LDSUBSCRIPTS-1) ; do echo "INCLUDE $$file" >> $@ ; done
makerule cpuflags : Makefile.settings ; perl -e 'print "CPUFLAGS :=\n"; foreach $$var (split(" ", $$ENV{VARIABLES})) { if (exists($$ENV{$$var})) { print "CPUFLAGS += -D$$var" . (length($$ENV{$$var})?"=\x27$$ENV{$$var}\x27":"") ."\n"} else { print "CPUFLAGS += -U$$var\n"} }' > $@
makerule ldoptions : Makefile.settings ; perl -e 'foreach $$var (split(" ", $$ENV{VARIABLES})) { if ($$ENV{$$var} =~ m/^(0x[0-9a-fA-F]+|0[0-7]+|[0-9]+)$$/) { print "$$var = $$ENV{$$var};\n"; }}' > $@
makerule linuxbios.strip: linuxbios ; objcopy -O binary linuxbios linuxbios.strip
makerule linuxbios.strip: linuxbios ; $(OBJCOPY) -O binary linuxbios linuxbios.strip
makerule linuxbios.o : crt0.o $(DRIVERS-1) linuxbios.a $(LIBGCC_FILE_NAME) ; $(CC) -nostdlib -r -o $@ crt0.o $(DRIVERS-1) linuxbios.a $(LIBGCC_FILE_NAME)
@ -39,12 +45,19 @@ makerule etags: $(SOURCES) ; etags $(SOURCES)
makerule tags: $(SOURCES) ; ctags $(SOURCES)
makerule documentation: $(SOURCES) ; doxygen LinuxBIOSDoc.config
makerule build_opt_tbl: $(TOP)/util/options/build_opt_tbl.c ; $(HOSTCC) $(HOSTCFLAGS) $< -o $@
makerule /$(TARGET_DIR)/option_table.c : build_opt_tbl $(MAINBOARD)/cmos.conf ; ./build_opt_tbl -b --config $(MAINBOARD)/cmos.conf
object /$(TARGET_DIR)/option_table.o HAVE_OPTION_TABLE
makerule clean : ; rm -f linuxbios.* *~
addaction clean rm -f linuxbios
addaction clean rm -f ldoptions cpuflags ldscript.ld
addaction clean rm -f a.out *.s *.l *.o
addaction clean rm -f TAGS tags
addaction clean rm -f docipl
addaction clean rm -f build_opt_tbl option_table.c crt0.S
# do standard config files that the user need not specify
# for now, this is just 'lib', but it may be more later.

View file

@ -25,4 +25,6 @@ unsigned long lb_table_fini(struct lb_header *header);
*/
struct lb_memory *get_lb_mem(void);
extern struct cmos_option_table option_table;
#endif /* LINUXBIOS_TABLE_H */

View file

@ -80,4 +80,65 @@ struct lb_hwrpb {
};
/* The following structures are for the cmos definitions table */
#define LB_TAG_CMOS_OPTION_TABLE 200
/* cmos header record */
struct cmos_option_table {
uint32_t tag; /* CMOS definitions table type */
uint32_t size; /* size of the entire table */
uint32_t header_length; /* length of header */
};
/* cmos entry record
This record is variable length. The name field may be
shorter than CMOS_MAX_NAME_LENGTH. The entry may start
anywhere in the byte, but can not span bytes unless it
starts at the beginning of the byte and the length is
fills complete bytes.
*/
#define LB_TAG_OPTION 201
struct cmos_entries {
uint32_t tag; /* entry type */
uint32_t size; /* length of this record */
uint32_t bit; /* starting bit from start of image */
uint32_t length; /* length of field in bits */
uint32_t config; /* e=enumeration, h=hex, r=reserved */
uint32_t config_id; /* a number linking to an enumeration record */
#define CMOS_MAX_NAME_LENGTH 32
uint8_t name[CMOS_MAX_NAME_LENGTH]; /* name of entry in ascii,
variable length int aligned */
};
/* cmos enumerations record
This record is variable length. The text field may be
shorter than CMOS_MAX_TEXT_LENGTH.
*/
#define LB_TAG_OPTION_ENUM 202
struct cmos_enums {
uint32_t tag; /* enumeration type */
uint32_t size; /* length of this record */
uint32_t config_id; /* a number identifying the config id */
uint32_t value; /* the value associated with the text */
#define CMOS_MAX_TEXT_LENGTH 32
uint8_t text[CMOS_MAX_TEXT_LENGTH]; /* enum description in ascii,
variable length int aligned */
};
/* cmos defaults record
This record contains default settings for the cmos ram.
*/
#define LB_TAG_OPTION_DEFAULTS 203
struct cmos_defaults {
uint32_t tag; /* default type */
uint32_t size; /* length of this record */
uint32_t name_length; /* length of the following name field */
uint8_t name[CMOS_MAX_NAME_LENGTH]; /* name identifying the default */
#define CMOS_IMAGE_BUFFER_SIZE 128
uint8_t default_set[CMOS_IMAGE_BUFFER_SIZE]; /* default settings */
};
#endif /* LINUXBIOS_TABLES_H */

View file

@ -90,6 +90,11 @@
#if !defined(ASSEMBLY)
void rtc_init(int invalid);
#if USE_OPTION_TABLE == 1
int get_option(void *dest, char *name);
#else
#define get_option(dest, name) (-2)
#endif
#endif
#endif /* PC80_MC146818RTC_H */

View file

@ -73,6 +73,7 @@ object mptable.o HAVE_MP_TABLE
object irq_tables.o HAVE_PIRQ_TABLE
###
### Build options
###
@ -123,6 +124,11 @@ option NO_KEYBOARD
##
option HAVE_MP_TABLE=1
##
## Build code to export a CMOS option tabe table
##
option HAVE_OPTION_TABLE=1
##
## Build code for SMP support
## Only worry about 2 micro processors
@ -198,6 +204,11 @@ option STACK_SIZE=0x2000
##
option HEAP_SIZE=0x2000
##
## Only use the option table in a normal image
##
expr USE_OPTION_TABLE=!USE_FALLBACK_IMAGE
##
## Compute the location and size of where this firmware image
## (linuxBIOS plus bootloader) will linv in the boot rom chip.

View file

@ -79,26 +79,26 @@ payload ../eepro100.ebi
##
## Cpu Speed
##
option CPU_CLOCK_MULTIPLIER XEON_X8
#option CPU_CLOCK_MULTIPLIER XEON_X9
#option CPU_CLOCK_MULTIPLIER XEON_X10
#option CPU_CLOCK_MULTIPLIER XEON_X11
#option CPU_CLOCK_MULTIPLIER XEON_X12
#option CPU_CLOCK_MULTIPLIER XEON_X13
#option CPU_CLOCK_MULTIPLIER XEON_X14
#option CPU_CLOCK_MULTIPLIER XEON_X15
#option CPU_CLOCK_MULTIPLIER XEON_X16
#option CPU_CLOCK_MULTIPLIER XEON_X17
#option CPU_CLOCK_MULTIPLIER XEON_X18
#option CPU_CLOCK_MULTIPLIER XEON_X19
#option CPU_CLOCK_MULTIPLIER XEON_X19
#option CPU_CLOCK_MULTIPLIER XEON_X20
#option CPU_CLOCK_MULTIPLIER XEON_X21
#option CPU_CLOCK_MULTIPLIER XEON_X22
#option CPU_CLOCK_MULTIPLIER XEON_X23
option CPU_CLOCK_MULTIPLIER=XEON_X8
#option CPU_CLOCK_MULTIPLIER=XEON_X9
#option CPU_CLOCK_MULTIPLIER=XEON_X10
#option CPU_CLOCK_MULTIPLIER=XEON_X11
#option CPU_CLOCK_MULTIPLIER=XEON_X12
#option CPU_CLOCK_MULTIPLIER=XEON_X13
#option CPU_CLOCK_MULTIPLIER=XEON_X14
#option CPU_CLOCK_MULTIPLIER=XEON_X15
#option CPU_CLOCK_MULTIPLIER=XEON_X16
#option CPU_CLOCK_MULTIPLIER=XEON_X17
#option CPU_CLOCK_MULTIPLIER=XEON_X18
#option CPU_CLOCK_MULTIPLIER=XEON_X19
#option CPU_CLOCK_MULTIPLIER=XEON_X19
#option CPU_CLOCK_MULTIPLIER=XEON_X20
#option CPU_CLOCK_MULTIPLIER=XEON_X21
#option CPU_CLOCK_MULTIPLIER=XEON_X22
#option CPU_CLOCK_MULTIPLIER=XEON_X23
##
## Select power on after power fail setting
option MAINBOARD_POWER_ON_AFTER_POWER_FAIL MAINBARD_POWER_ON
#option MAINBOARD_POWER_ON_AFTER_POWER_FAIL MAINBARD_POWER_ON
option MAINBOARD_POWER_ON_AFTER_POWER_FAIL=MAINBOARD_POWER_ON
#option MAINBOARD_POWER_ON_AFTER_POWER_FAIL=MAINBOARD_POWER_ON

View file

@ -80,26 +80,26 @@ payload ../eepro100.ebi
##
## Cpu Speed
##
#option CPU_CLOCK_MULTIPLIER XEON_X8
#option CPU_CLOCK_MULTIPLIER XEON_X9
#option CPU_CLOCK_MULTIPLIER XEON_X10
#option CPU_CLOCK_MULTIPLIER XEON_X11
#option CPU_CLOCK_MULTIPLIER XEON_X12
#option CPU_CLOCK_MULTIPLIER XEON_X13
#option CPU_CLOCK_MULTIPLIER XEON_X14
#option CPU_CLOCK_MULTIPLIER XEON_X15
#option CPU_CLOCK_MULTIPLIER XEON_X16
option CPU_CLOCK_MULTIPLIER XEON_X17
#option CPU_CLOCK_MULTIPLIER XEON_X18
#option CPU_CLOCK_MULTIPLIER XEON_X19
#option CPU_CLOCK_MULTIPLIER XEON_X19
#option CPU_CLOCK_MULTIPLIER XEON_X20
#option CPU_CLOCK_MULTIPLIER XEON_X21
#option CPU_CLOCK_MULTIPLIER XEON_X22
#option CPU_CLOCK_MULTIPLIER XEON_X23
#option CPU_CLOCK_MULTIPLIER=XEON_X8
#option CPU_CLOCK_MULTIPLIER=XEON_X9
#option CPU_CLOCK_MULTIPLIER=XEON_X10
#option CPU_CLOCK_MULTIPLIER=XEON_X11
#option CPU_CLOCK_MULTIPLIER=XEON_X12
#option CPU_CLOCK_MULTIPLIER=XEON_X13
#option CPU_CLOCK_MULTIPLIER=XEON_X14
#option CPU_CLOCK_MULTIPLIER=XEON_X15
#option CPU_CLOCK_MULTIPLIER=XEON_X16
option CPU_CLOCK_MULTIPLIER=XEON_X17
#option CPU_CLOCK_MULTIPLIER=XEON_X18
#option CPU_CLOCK_MULTIPLIER=XEON_X19
#option CPU_CLOCK_MULTIPLIER=XEON_X19
#option CPU_CLOCK_MULTIPLIER=XEON_X20
#option CPU_CLOCK_MULTIPLIER=XEON_X21
#option CPU_CLOCK_MULTIPLIER=XEON_X22
#option CPU_CLOCK_MULTIPLIER=XEON_X23
##
## Select power on after power fail setting
option MAINBOARD_POWER_ON_AFTER_POWER_FAIL MAINBARD_POWER_ON
#option MAINBOARD_POWER_ON_AFTER_POWER_FAIL MAINBARD_POWER_ON
option MAINBOARD_POWER_ON_AFTER_POWER_FAIL=MAINBOARD_POWER_ON
#option MAINBOARD_POWER_ON_AFTER_POWER_FAIL=MAINBOARD_POWER_ON

View file

@ -13,6 +13,7 @@
#include <smbus.h>
#include <ramtest.h>
#include <northbridge/intel/82860/rdram.h>
#include <pc80/mc146818rtc.h>
#define SMBUS_MEM_DEVICE_0 (0xa << 3)
@ -52,6 +53,8 @@ static void set_power_on_after_power_fail(int setting)
}
void mainboard_fixup(void)
{
int cpu_clock_multiplier;
int power_on_after_power_fail;
ich2_enable_ioapic();
ich2_enable_serial_irqs();
ich2_enable_ide(1,1);
@ -59,9 +62,13 @@ void mainboard_fixup(void)
ich2_lpc_route_dma(0xff);
isa_dma_init();
ich2_set_cpu_multiplier(CPU_CLOCK_MULTIPLIER);
cpu_clock_multiplier = CPU_CLOCK_MULTIPLIER;
get_option(&cpu_clock_multiplier, "CPU_clock_speed");
ich2_set_cpu_multiplier(cpu_clock_multiplier);
set_power_on_after_power_fail(MAINBOARD_POWER_ON_AFTER_POWER_FAIL);
power_on_after_power_fail = MAINBOARD_POWER_ON_AFTER_POWER_FAIL;
get_option(&power_on_after_power_fail, "power_on_after_power_fail");
set_power_on_after_power_fail(power_on_after_power_fail);
return;
}

View file

@ -1,6 +1,9 @@
#include <arch/io.h>
#include <printk.h>
#include <pc80/mc146818rtc.h>
#include <boot/linuxbios_tables.h>
#include <boot/linuxbios_table.h>
#include <string.h>
#define CMOS_READ(addr) ({ \
outb_p((addr),RTC_PORT(0)); \
@ -162,3 +165,68 @@ void rtc_init(int invalid)
/* Clear any pending interrupts */
(void) CMOS_READ(RTC_INTR_FLAGS);
}
#if USE_OPTION_TABLE == 1
/* This routine returns the value of the requested bits
input bit = bit count from the beginning of the cmos image
length = number of bits to include in the value
ret = a character pointer to where the value is to be returned
output the value placed in ret
returns 1 = successful, 0 = an error occurred
*/
static int get_cmos_value(unsigned long bit, unsigned long length, void *vret)
{
unsigned char *ret;
unsigned long byte,byte_bit;
unsigned long i;
unsigned char uchar;
/* The table is checked when it is built to ensure all values are valid. */
ret = vret;
byte=bit/8; /* find the byte where the data starts */
byte_bit=bit%8; /* find the bit in the byte where the data starts */
if(length<9) { /* one byte or less */
uchar = CMOS_READ(byte); /* load the byte */
uchar >>= byte_bit; /* shift the bits to byte align */
/* clear unspecified bits */
ret[0] = uchar & ((1 << length) -1);
}
else { /* more that one byte so transfer the whole bytes */
for(i=0;length;i++,length-=8,byte++) {
/* load the byte */
ret[i]=CMOS_READ(byte);
}
}
return 0;
}
int get_option(void *dest, char *name)
{
extern struct cmos_option_table option_table;
struct cmos_option_table *ct;
struct cmos_entries *ce;
size_t namelen;
int found=0;
/* Figure out how long name is */
namelen = strnlen(name, CMOS_MAX_NAME_LENGTH);
/* find the requested entry record */
ct=&option_table;
ce=(struct cmos_entries*)((unsigned char *)ct + ct->header_length);
for(;ce->tag==LB_TAG_OPTION;
ce=(struct cmos_entries*)((unsigned char *)ce + ce->size)) {
if (memcmp(ce->name, name, namelen) == 0) {
found=1;
break;
}
}
if(!found) return(-2);
if(get_cmos_value(ce->bit, ce->length, dest))
return(-3);
return(0);
}
#endif /* USE_OPTION_TABLE */

View file

@ -1,5 +1,9 @@
option USE_DOC_MIL=0
option USE_DOC_2000_TSOP=0
expr USE_DOC = USE_DOC_MIL | USE_DOC_2000_TSOP
driver rom_fill_inbuf.o USE_GENERIC_ROM
driver docmil_fill_inbuf.o
driver docmil_fill_inbuf.o USE_DOC
#driver docplus_fill_inbuf.o
driver tsunami_tigbus_rom_fill_inbuf.o USE_TSUNAMI_TIGBUS_ROM
driver serial_fill_inbuf.o USE_SERIAL_FILL_INBUF

View file

@ -1,5 +1,3 @@
#if defined(USE_DOC_MIL) || defined(USE_DOC_2000_TSOP)
#include <cpu/p5/io.h>
#include <printk.h>
#include <stdlib.h>
@ -157,5 +155,3 @@ static struct stream doc_mil_stream __stream = {
.skip = skip_bytes,
.fini = fini_bytes,
};
#endif /* USE_DOC_MIL */

View file

@ -676,13 +676,17 @@ def set_expr(option, value):
# Also, put "<option>:=<value>" and add <option> to VARIABLES in
# Makefile.settings
#
option_re = re.compile(r"^([A-Za-z_][A-Za-z_0-9]+)\s*=(.*)$")
option_re = re.compile(r"^([A-Za-z_][A-Za-z_0-9]+)\s*$")
option_arg_re = re.compile(r"^([A-Za-z_][A-Za-z_0-9]+)\s*=(.*)$")
def option(dir, option):
m = option_re.match(option)
key=option
value= ""
m = option_arg_re.match(option)
key = option
value = ""
if m and m.group(1):
(key, value) = m.groups()
m = option_re.match(key)
if not m:
fatal("Invalid option name: %s" % (key))
set_option(key, value)
# COMMAND: nooption <option-name>
@ -692,10 +696,12 @@ def nooption(dir, option):
# COMMAND: expr
def expr(dir, option):
m = option_re.match(option)
m = option_arg_re.match(option)
value= ""
if m and m.group(1):
(key, value) = m.groups()
else:
fatal("Invalid expression: %s" % (option))
set_expr(key, value)
# COMMAND: commandline <stuff>
@ -930,6 +936,8 @@ def writemakefilesettings(path):
file.write("TOP:=%s\n" % (treetop))
file.write("ARCH:=%s\n" % (arch))
file.write("MAINBOARD:=%s\n" % (mainboard_dir))
file.write("TARGET_DIR:=%s\n" % (target_dir))
keys = makeoptions.keys()
keys.sort()
@ -1050,9 +1058,9 @@ CPUFLAGS := $(foreach _var_,$(VARIABLES),$(call D_item,$(_var_)))
file.write("\n# Remember the automatically generated files\n")
file.write("GENERATED:=\n")
for genfile in [ 'Makefile',
'Makefile.settings'
'crt0_includes.h'
'nsuperio.c'
'Makefile.settings',
'crt0_includes.h',
'nsuperio.c',
'LinuxBIOSDoc.config' ]:
file.write("GENERATED += %s\n" % genfile)

View file

@ -8,6 +8,8 @@
#include <sys/mman.h>
#include "../../src/include/boot/linuxbios_tables.h"
void print_lb_records(struct lb_record *rec, struct lb_record *last, unsigned long addr);
unsigned long compute_checksum(void *addr, unsigned long length)
{
unsigned short *ptr;
@ -26,46 +28,65 @@ unsigned long compute_checksum(void *addr, unsigned long length)
return (~sum) & 0xFFFF;
}
#define for_each_lbrec(head, rec) \
for(rec = (struct lb_record *)(((char *)head) + sizeof(*head)); \
(((char *)rec) < (((char *)head) + sizeof(*head) + head->table_bytes)) && \
(rec->size >= 1) && \
((((char *)rec) + rec->size) <= (((char *)head) + sizeof(*head) + head->table_bytes)); \
rec = (struct lb_record *)(((char *)rec) + rec->size))
int count_lb_records(void *start, unsigned long length)
static int count_lb_records(struct lb_header *head)
{
struct lb_record *rec;
void *end;
int count;
count = 0;
end = ((char *)start) + length;
for(rec = start; ((void *)rec < end) &&
(rec->size <= (end - (void *)rec));
rec = (void *)(((char *)rec) + rec->size)) {
for_each_lbrec(head, rec) {
count++;
}
return count;
}
void *find_lb_table(void *start, void *end)
struct lb_header *find_lb_table(void *base, unsigned long start, unsigned long end)
{
unsigned char *ptr;
unsigned long addr;
/* For now be stupid.... */
for(ptr = start; (void *)ptr < end; ptr += 16) {
struct lb_header *head = (void *)ptr;
if ((head->signature[0] == 'L') &&
(head->signature[1] == 'B') &&
(head->signature[2] == 'I') &&
(head->signature[3] == 'O') &&
(head->header_bytes == sizeof(*head)) &&
(compute_checksum(head, sizeof(*head)) == 0) &&
(compute_checksum(ptr + sizeof(*head), head->table_bytes) ==
head->table_checksum) &&
(count_lb_records(ptr + sizeof(*head), head->table_bytes) ==
head->table_entries)
) {
return ptr;
for(addr = start; addr < end; addr += 16) {
struct lb_header *head = (struct lb_header *)(((char*)base) + addr);
struct lb_record *recs = (struct lb_record *)(((char*)base) + addr + sizeof(*head));
if (memcmp(head->signature, "LBIO", 4) != 0)
continue;
fprintf(stdout, "Found canidate at: %08lx-%08lx\n",
addr, addr + head->table_bytes);
if (head->header_bytes != sizeof(*head)) {
fprintf(stderr, "Header bytes of %d are incorrect\n",
head->header_bytes);
continue;
}
if (count_lb_records(head) != head->table_entries) {
fprintf(stderr, "bad record count: %d\n",
head->table_entries);
continue;
}
if (compute_checksum((unsigned char *)head, sizeof(*head)) != 0) {
fprintf(stderr, "bad header checksum\n");
continue;
}
if (compute_checksum(recs, head->table_bytes)
!= head->table_checksum) {
fprintf(stderr, "bad table checksum: %04x\n",
head->table_checksum);
continue;
}
fprintf(stdout, "Found LinuxBIOS table at: %08lx\n", addr);
return head;
};
return 0;
}
void nop_print(struct lb_record *rec)
void nop_print(struct lb_record *rec, unsigned long addr)
{
return;
}
@ -101,7 +122,7 @@ void pretty_print_number(FILE *stream, uint64_t value)
}
}
void print_memory(struct lb_record *ptr)
void print_memory(struct lb_record *ptr, unsigned long addr)
{
struct lb_memory *rec = (void *)ptr;
int entries;
@ -128,49 +149,113 @@ void print_memory(struct lb_record *ptr)
printf(")\n");
}
}
void print_option_table(struct lb_record *ptr, unsigned long addr)
{
struct lb_record *rec, *last;
struct cmos_option_table *hdr;
hdr = (struct cmos_option_table *)ptr;
rec = (struct lb_record *)(((char *)hdr) + hdr->header_length);
last = (struct lb_record *)(((char *)hdr) + hdr->size);
printf("cmos option header record = type %d, size %d, header length %d\n",
hdr->tag, hdr->size, hdr->header_length);
print_lb_records(rec, last, addr + hdr->header_length);
#if 0
{
unsigned char *data = (unsigned char *)ptr;
int i;
for(i = 0; i < hdr->size; i++) {
if ((i %10) == 0 ) {
fprintf(stderr, "\n\t");
}
fprintf(stderr, "0x%02x,", data[i]);
}
}
#endif
}
void print_option(struct lb_record *ptr, unsigned long addr)
{
struct cmos_entries *rec;
rec= (struct cmos_entries *)ptr;
printf("entry %d, rec len %d, start %d, length %d, conf %d, id %d, %s\n",
rec->tag, rec->size, rec->bit, rec->length,
rec->config, rec->config_id, rec->name);
}
void print_option_enumeration(struct lb_record *ptr, unsigned long addr)
{
struct cmos_enums *rec;
rec = (struct cmos_enums *)ptr;
printf("enumeration %d, rec len %d, id %d, value %d, %s\n",
rec->tag, rec->size, rec->config_id, rec->value,
rec->text);
}
struct {
uint32_t type;
char *type_name;
void (*print)(struct lb_record *rec);
void (*print)(struct lb_record *rec, unsigned long addr);
} lb_types[] = {
{ 0, "Unused", nop_print },
{ 1, "Memory", print_memory },
{ 2, "HWRPB", nop_print },
{ LB_TAG_UNUSED, "Unused", nop_print },
{ LB_TAG_MEMORY, "Memory", print_memory },
{ LB_TAG_HWRPB, "HWRPB", nop_print },
{ LB_TAG_CMOS_OPTION_TABLE, "CMOS option table", print_option_table },
{ LB_TAG_OPTION, "Option", print_option },
{ LB_TAG_OPTION_ENUM, "Option Enumeration", print_option_enumeration },
{ LB_TAG_OPTION_DEFAULTS, "Option Defaults", nop_print },
{ -1, "Unknown", 0 }
};
void print_lb_records(struct lb_header *head)
static struct lb_record *next_record(struct lb_record *rec)
{
struct lb_record *rec;
void *start, *end;
return (struct lb_record *)(((char *)rec) + rec->size);
}
void print_lb_records(struct lb_record *rec, struct lb_record *last,
unsigned long addr)
{
struct lb_record *next;
int i;
int count;
count = 0;
start = ((char *)head) + head->header_bytes;
end = ((char *)start) + head->table_bytes;
printf("LinuxBIOS header\n");
for(rec = start;
((void *)rec < end) && (rec->size <= (end - (void *)rec));
rec = (void *)(((char *)rec) + rec->size)) {
for(next = next_record(rec); (rec < last) && (next <= last);
rec = next, addr += rec->size) {
next = next_record(rec);
count++;
for(i = 0; lb_types[i].print != 0; i++) {
if (lb_types[i].type == rec->tag) {
break;
}
}
printf("lb_record #%d type %d %s\n",
count, rec->tag, lb_types[i].type_name);
printf("lb_record #%d type %d @ 0x%08lx %s\n",
count, rec->tag, addr, lb_types[i].type_name);
if (lb_types[i].print) {
lb_types[i].print(rec);
lb_types[i].print(rec, addr);
}
}
}
void print_lb_table(struct lb_header *head, unsigned long addr)
{
struct lb_record *rec, *last;
rec = (struct lb_record *)(((char *)head) + head->header_bytes);
last = (struct lb_record *)(((char *)rec) + head->table_bytes);
printf("LinuxBIOS header(%d) checksum: %04x table(%d) checksum: %04x entries: %d\n",
head->header_bytes, head->header_checksum,
head->table_bytes, head->table_checksum, head->table_entries);
print_lb_records(rec, last, addr + head->header_bytes);
}
int main(int argc, char **argv)
{
unsigned char *low_1MB;
void *lb_table;
struct lb_header *lb_table;
int fd;
fd = open("/dev/mem", O_RDONLY);
if (fd < 0) {
@ -185,13 +270,13 @@ int main(int argc, char **argv)
}
lb_table = 0;
if (!lb_table)
lb_table = find_lb_table(low_1MB + 0x00000, low_1MB + 0x1000);
lb_table = find_lb_table(low_1MB, 0x00000, 0x1000);
if (!lb_table)
lb_table = find_lb_table(low_1MB + 0xf0000, low_1MB + 1024*1024);
lb_table = find_lb_table(low_1MB, 0xf0000, 1024*1024);
if (lb_table) {
printf("lb_table = 0x%08x\n",
lb_table - (void *)low_1MB);
print_lb_records(lb_table);
unsigned long addr;
addr = ((char *)lb_table) - ((char *)low_1MB);
print_lb_table(lb_table, addr);
}
else {
printf("lb_table not found\n");

View file

@ -0,0 +1,322 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/io.h>
#include <string.h>
#include "../../src/include/boot/linuxbios_tables.h"
#define CMOS_IMAGE_BUFFER_SIZE 128
#define INPUT_LINE_MAX 256
#define MAX_VALUE_BYTE_LENGTH 64
static unsigned char cmos_table[4096];
/* This array is used to isolate bits that are to be changed in a byte */
static unsigned char clip[9]={0,1,3,7,0x0f,0x1f,0x3f,0x7f,0xff};
/* This routine loops through the entried and tests if any of the fields overlap
input entry_start = the memory pointer to the start of the entries.
entry_end = the byte past the entries.
output none
if there is an overlap, the routine exits, other wise it returns.
*/
void test_for_entry_overlaps(int entry_start,int entry_end)
{
int ptr;
int buffer_bit_size;
int offset;
int byte;
int byte_length;
struct cmos_entries *ce;
unsigned char test[CMOS_IMAGE_BUFFER_SIZE];
unsigned char set;
/* calculate the size of the cmos buffer in bits */
buffer_bit_size=(CMOS_IMAGE_BUFFER_SIZE*8);
/* clear the temporary test buffer */
for(ptr=0;ptr<CMOS_IMAGE_BUFFER_SIZE;ptr++)
test[ptr]=0;
/* loop through each entry in the table testing for errors */
for(ptr=entry_start;ptr<entry_end;ptr+=ce->size) {
ce=(struct cmos_entries *)ptr;
/* test if entry goes past the end of the buffer */
if((ce->bit+ce->length)>buffer_bit_size) {
printf("Error - Entry %s start bit + length must be less than %d\n",
ce->name,buffer_bit_size);
exit(1);
}
byte=ce->bit/8;
offset=ce->bit%8;
byte_length=ce->length/8;
if(byte_length) { /* entry is 8 bits long or more */
if(offset) { /* if 8 bits or more long, it must be byte aligned */
printf("Error - Entry %s length over 8 must be byte aligned\n",
ce->name);
exit(1);
}
/* test if entries 8 or more in length are even bytes */
if(ce->length%8){
printf("Error - Entry %s length over 8 must be a multiple of 8\n",
ce->name);
exit(1);
}
/* test if any of the bits have been previously used */
for(;byte_length;byte_length--,byte++) {
if(test[byte]) {
printf("Error - Entry %s uses same bits previously used\n",
ce->name);
exit(1);
}
test[byte]=clip[8]; /* set the bits defined in test */
}
} else {
/* test if bits overlap byte boundaries */
if(ce->length>(8-offset)) {
printf("Error - Entry %s length overlaps a byte boundry\n", ce->name);
exit(1);
}
/* test for bits previously used */
set=(clip[ce->length]<<offset);
if(test[byte]&set) {
printf("Error - Entry %s uses same bits previously used\n",
ce->name);
exit(1);
}
test[byte]|=set; /* set the bits defined in test */
}
}
return;
}
/* This routine displays the usage options */
void display_usage(void)
{
printf("Usage build_opt_table [-b] [--option filename]\n");
printf(" [--config filename]\n");
printf("b = build option_table.c\n");
printf("--option = name of option table output file\n");
printf("--config = build the definitions table from the given file\n");
exit(1);
}
/* This routine builds the cmos definition table from the cmos configuration file
input The input comes from the configuration file which contains two parts
entries and enumerations. Each section is started with the key words
entries and enumerations. Records then follow in their respective
formats.
output The output of this program is the cmos definitions table. It is stored
in the cmos_table array. If this module is called, and the global
table_file has been implimented by the user, the table is also written
to the specified file.
This program exits on and error. It returns a 1 on successful
completion
*/
int main(int argc, char **argv)
{
int i;
char *config=0;
char *option=0;
FILE *fp;
struct cmos_option_table *ct;
struct cmos_entries *ce;
struct cmos_enums *c_enums, *c_enums_start;
unsigned char line[INPUT_LINE_MAX];
unsigned char uc;
int entry_mode=0;
int enum_mode=0;
int ptr,cnt;
char *cptr;
int offset,entry_start;
int entries_length;
int enum_length;
int len;
unsigned char buf[16];
for(i=1;i<argc;i++) {
if(argv[i][0]!='-') {
display_usage();
}
switch(argv[i][1]) {
case 'b': /* build the table */
break;
case '-': /* data is requested from a file */
switch(argv[i][2]) {
case 'c': /* use a configuration file */
if(strcmp(&argv[i][2],"config")) {
display_usage();
}
config=argv[++i];
break;
case 'o': /* use a cmos definitions table file */
if(strcmp(&argv[i][2],"option")) {
display_usage();
}
option=argv[++i];
break;
default:
display_usage();
break;
}
break;
default:
display_usage();
break;
}
}
/* Has the user specified a configuration file */
if(config) { /* if yes, open it */
if((fp=fopen(config,"r"))==NULL){
printf("Error - Can not open config file %s\n",config);
exit(1); /* exit if it can not be opened */
}
}
else { /* no configuration file specified, so try the default */
if((fp=fopen("cmos.conf","r"))==NULL){
printf("Error - Can not open cmos.conf\n");
exit(1); /* end of no configuration file is found */
}
}
/* type cast a pointer, so we can us the structure */
ct=(struct cmos_option_table*)cmos_table;
/* start the table with the type signature */
ct->tag = LB_TAG_CMOS_OPTION_TABLE;
/* put in the header length */
ct->header_length=sizeof(*ct);
/* Get the entry records */
ce=(struct cmos_entries*)(cmos_table+(ct->header_length));
cptr = (char*)ce;
for(;;){ /* this section loops through the entry records */
if(fgets(line,INPUT_LINE_MAX,fp)==NULL)
break; /* end if no more input */
if(!entry_mode) { /* skip input until the entries key word */
if((ptr=(int)strstr(line,"entries"))){
entry_mode=1;
continue;
}
}
else{ /* Test if we are done with entries and starting enumerations */
if((ptr=(int)strstr(line,"enumerations"))){
entry_mode=0;
enum_mode=1;
break;
}
}
/* skip commented and blank lines */
if(line[0]=='#') continue;
if(line[strspn(line," ")]=='\n') continue;
/* scan in the input data */
sscanf(line,"%d %d %c %d %s",
&ce->bit,&ce->length,&uc,&ce->config_id,&ce->name[0]);
ce->config=(int)uc;
/* check bit and length ranges */
if(ce->bit>(CMOS_IMAGE_BUFFER_SIZE*8)) {
printf("Error - bit is to big in line \n%s\n",line);
exit(1);
}
if((ce->length>(MAX_VALUE_BYTE_LENGTH*8))&&(uc!='r')) {
printf("Error - Length is to long in line \n%s\n",line);
exit(1);
}
/* put in the record type */
ce->tag=LB_TAG_OPTION;
/* calculate and save the record length */
len=strlen(ce->name)+1;
/* make the record int aligned */
if(len%4)
len+=(4-(len%4));
ce->size=sizeof(struct cmos_entries)-32+len;
cptr = (char*)ce;
cptr+=ce->size; /* increment to the next table position */
ce = (struct cmos_entries*) cptr;
}
/* put the length of the entries into the header section */
entries_length=(int)cptr;
entries_length-=(int)(cmos_table+ct->header_length);
/* compute the start of the enumerations section */
entry_start=(int)cmos_table;
entry_start+=ct->header_length;
offset=entry_start+entries_length;
c_enums_start=c_enums=(struct cmos_enums*)offset;
/* test for overlaps in the entry records */
test_for_entry_overlaps(entry_start,offset);
for(;enum_mode;){ /* loop to build the enumerations section */
if(fgets(line,INPUT_LINE_MAX,fp)==NULL) break; /* go till end of input */
/* skip commented and blank lines */
if(line[0]=='#') continue;
if(line[strspn(line," ")]=='\n') continue;
/* scan in the data */
for(ptr=0;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
c_enums->config_id=strtol(&line[ptr],(char**)NULL,10);
for(;(line[ptr]!=' ')&&(line[ptr]!='\t');ptr++);
for(;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
c_enums->value=strtol(&line[ptr],(char**)NULL,10);
for(;(line[ptr]!=' ')&&(line[ptr]!='\t');ptr++);
for(;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
for(cnt=0;(line[ptr]!='\n')&&(cnt<31);ptr++,cnt++)
c_enums->text[cnt]=line[ptr];
c_enums->text[cnt]=0;
/* make the record int aligned */
cnt++;
if(cnt%4)
cnt+=4-(cnt%4);
/* store the record length */
c_enums->size=((int)&c_enums->text[cnt])-(int)c_enums;
/* store the record type */
c_enums->tag=LB_TAG_OPTION_ENUM;
/* increment to the next record */
c_enums=(struct cmos_enums*)&c_enums->text[cnt];
}
/* save the enumerations length */
enum_length=(int)c_enums-(int)c_enums_start;
ct->size=ct->header_length+enum_length+entries_length;
fclose(fp);
/* test if an alternate file is to be created */
if(option) {
if((fp=fopen(option,"w"))==NULL){
printf("Error - Can not open %s\n",option);
exit(1);
}
}
else { /* no, so use the default option_table.c */
if((fp=fopen("option_table.c","w"))==NULL){
printf("Error - Can not open option_table.c\n");
exit(1);
}
}
/* write the header */
if(!fwrite("unsigned char option_table[] = {",1,32,fp)) {
printf("Error - Could not write image file\n");
fclose(fp);
exit(1);
}
/* write the array values */
for(i=0;i<(ct->size-1);i++) {
if(!(i%10)) fwrite("\n\t",1,2,fp);
sprintf(buf,"0x%02x,",cmos_table[i]);
fwrite(buf,1,5,fp);
}
/* write the end */
sprintf(buf,"0x%02x",cmos_table[i]);
fwrite(buf,1,4,fp);
if(!fwrite("};\n",1,3,fp)) {
printf("Error - Could not write image file\n");
fclose(fp);
exit(1);
}
fclose(fp);
return(0);
}