From 25ebd9110b2184466e3f10acf43f3dec90601d24 Mon Sep 17 00:00:00 2001 From: Stefan Reinauer Date: Fri, 29 Jun 2007 16:57:23 +0000 Subject: [PATCH] * start using arch/foo.h again instead of archfoo.h (trivial) * make constructor an initializer. * fix memory leak/code flow error in current code * add spinlocking * drop malloc and use new_device for device allocation instead. * add CONFIG_SMP as it is needed by spinlocks and soon other stuff. Signed-off-by: Stefan Reinauer Acked-by: Ronald G. Minnich git-svn-id: svn://coreboot.org/repository/LinuxBIOSv3@418 f3766cd6-281f-0410-b1cd-43a5c92072e9 --- arch/x86/Kconfig | 8 +++ arch/x86/Makefile | 3 +- arch/x86/stage1.c | 13 ++-- device/device.c | 102 ++++++++++++++++++------------- include/arch/x86/arch/elf.h | 8 +++ include/arch/x86/arch/spinlock.h | 83 +++++++++++++++++++++++++ include/arch/x86/archelf.h | 8 --- include/device/device.h | 27 ++++---- include/elf.h | 2 +- include/stdlib.h | 22 ------- lib/console.c | 1 - lib/malloc.c | 92 ---------------------------- util/dtc/dtc-parser.y | 2 +- 13 files changed, 183 insertions(+), 188 deletions(-) create mode 100644 include/arch/x86/arch/elf.h create mode 100644 include/arch/x86/arch/spinlock.h delete mode 100644 include/arch/x86/archelf.h delete mode 100644 include/stdlib.h delete mode 100644 lib/malloc.c diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index e791ee91aa..e96cf49b1c 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -55,3 +55,11 @@ config OPTION_TABLE a battery backed up real time clock with CMOS NVRAM. It is usually set in mainboard/*/Kconfig. +config SMP + boolean + help + This option is used to enable certain functions to make + LinuxBIOS work correctly on symmetric multi processor + systems. + It is usually set in mainboard/*/Kconfig. + diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 9f71d4cd5a..70123d57e7 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -123,8 +123,7 @@ $(obj)/stage0.init: $(STAGE0_OBJ) # TODO: This should be compressed with the default compressor. # -STAGE2_LIB_OBJ = stage2.o clog2.o mem.o malloc.o tables.o delay.o \ - compute_ip_checksum.o +STAGE2_LIB_OBJ = stage2.o clog2.o mem.o tables.o delay.o compute_ip_checksum.o STAGE2_ARCH_X86_OBJ = archtables.o linuxbios_table.o udelay_io.o STAGE2_ARCH_X86_OBJ += pci_ops_auto.o pci_ops_conf1.o pci_ops_conf2.o diff --git a/arch/x86/stage1.c b/arch/x86/stage1.c index f1d8da8daf..d61721b7fb 100644 --- a/arch/x86/stage1.c +++ b/arch/x86/stage1.c @@ -119,12 +119,15 @@ void stage1_main(u32 bist) if (ret) die("Failed RAM init code\n"); - printk(BIOS_INFO, "Done RAM init code\n"); - /* this is nasty. And, it has to be done this way. Sorry! */ - /* we have to turn off CAR, and do some other things, and it has to be done - * inline -- you can't call a function - */ + printk(BIOS_DEBUG, "Done RAM init code\n"); + + /* Turn off Cache-As-Ram, and do some other things. + * + * This has to be done inline -- You can't call a function because the + * return stack does not survive. + */ + __asm__ volatile ( /* FIXME : backup stack in CACHE_AS_RAM into mmx and sse and after we get STACK up, we restore that. diff --git a/device/device.c b/device/device.c index 0fce2fec93..db8f48c605 100644 --- a/device/device.c +++ b/device/device.c @@ -10,8 +10,9 @@ * Copyright (C) 2003 Ronald G. Minnich * Copyright (C) 2004-2005 Li-Ta Lo * Copyright (C) 2005-2006 Tyan - * (Written by Yinghai Lu for Tyan) + * (Written by Yinghai Lu for Tyan) * Copyright (C) 2005-2006 Stefan Reinauer + * Copyright (C) 2007 coresystems GmbH */ /* @@ -34,10 +35,8 @@ #include #include #include -#include #include -#warning Do we need spinlocks in device/device.c? -//#include +#include /** Linked list of all devices. */ struct device *all_devices = &dev_root; @@ -60,6 +59,34 @@ struct device **last_dev_p; */ #define DEVICE_IO_START 0x1000 +/** + * device memory. All the device tree wil live here + */ + +#define MAX_DEVICES 256 +static struct device devs[MAX_DEVICES]; + +/** + * The device creator. + * + * reserves a piece of memory for a device in the tree + * + * @return Pointer to the newly created device structure. + */ + +static struct device *new_device(void) +{ + static int devcnt=0; + devcnt++; + + /* Should we really die here? */ + if (devcnt>=MAX_DEVICES) { + die("Too many devices. Increase MAX_DEVICES\n"); + } + + return &devs[devcnt]; +} + /** * Initialization tasks for the device tree code. * @@ -76,27 +103,17 @@ void dev_init(void) } /** - * The default constructor, which simply allocates and sets the ops pointer. + * The default constructor, which simply sets the ops pointer. * - * Allocate a new device structure and initialize device->ops. + * Initialize device->ops of a newly allocated device structure. * + * @param dev Pointer to the newly created device structure. * @param constructor A pointer to a struct constructor. - * @return Pointer to the newly created device structure. */ -struct device *default_device_constructor(struct constructor *constructor) +void default_device_constructor(struct device *dev, struct constructor *constructor) { - struct device *dev; - dev = malloc(sizeof(*dev)); - - // FIXME: This is overkill. Our malloc() will never return with - // a return value of NULL. So this is dead code (and thus would - // drop code coverage and usability in safety critical environments. - if (dev == NULL) { - die("DEV: out of memory.\n"); - } - memset(dev, 0, sizeof(dev)); + printk(BIOS_DEBUG, "default device constructor called\n"); dev->ops = constructor->ops; - return dev; } /** @@ -119,9 +136,6 @@ struct constructor *find_constructor(struct device_id *id) printk(BIOS_SPEW, "%s: cons 0x%lx, cons id %s\n", __func__, c, dev_id_string(&c->id)); if ((!c->ops) || (!c->ops->constructor)) { - printk(BIOS_INFO, - "Constructor for %s with missing ops or ops->constructor!\n", - dev_id_string(&c->id)); continue; } if (id_eq(&c->id, id)) { @@ -131,7 +145,7 @@ struct constructor *find_constructor(struct device_id *id) } } - return 0; + return NULL; } /** @@ -141,23 +155,22 @@ struct constructor *find_constructor(struct device_id *id) * Call that constructor via constructor->ops->constructor, with itself as * a parameter; return the result. * + * @param dev Pointer to the newly created device structure. * @param path Path to the device to be created. - * @return Pointer to the newly created device structure. * @see device_path */ -struct device *constructor(struct device_id *id) +void constructor(struct device *dev, struct device_id *id) { struct constructor *c; - struct device *dev = 0; c = find_constructor(id); - printk(BIOS_DEBUG, "%s constructor is 0x%lx\n", __func__, c); - if (!c) - return 0; - - dev = c->ops->constructor(c); - printk(BIOS_DEBUG, "%s returns 0x%lx\n", __func__, dev); - return dev; + printk(BIOS_SPEW, "%s: constructor is 0x%lx\n", __func__, c); + + if(c && c->ops && c->ops->constructor) + c->ops->constructor(dev, c); + else + printk(BIOS_INFO, "No constructor called for %s.\n", + dev_id_string(&c->id)); } /** @@ -177,24 +190,18 @@ struct device *alloc_dev(struct bus *parent, struct device_path *path, struct device *dev, *child; int link; -// spin_lock(&dev_lock); + spin_lock(&dev_lock); /* Find the last child of our parent. */ for (child = parent->children; child && child->sibling; /* */) { child = child->sibling; } - dev = constructor(devid); - if (!dev) - printk(BIOS_DEBUG, "%s: No constructor, going with empty dev", - dev_id_string(devid)); + dev = new_device(); + if (!dev) /* Please don't do this at home */ + goto out; - dev = malloc(sizeof(*dev)); - if (dev == NULL) { - die("DEV: out of memory.\n"); - } memset(dev, 0, sizeof(*dev)); - memcpy(&dev->path, path, sizeof(*path)); /* Initialize the back pointers in the link fields. */ @@ -223,7 +230,14 @@ struct device *alloc_dev(struct bus *parent, struct device_path *path, /* Give the device a name. */ sprintf(dev->dtsname, "dynamic %s", dev_path(dev)); - // spin_unlock(&dev_lock); + /* Run the device specific constructor as last part of the chain + * so it gets the chance to overwrite the "inherited" values above + */ + + constructor(dev, devid); + +out: + spin_unlock(&dev_lock); return dev; } diff --git a/include/arch/x86/arch/elf.h b/include/arch/x86/arch/elf.h new file mode 100644 index 0000000000..4aed9a7166 --- /dev/null +++ b/include/arch/x86/arch/elf.h @@ -0,0 +1,8 @@ +#ifndef ARCH_ELF_H +#define ARCH_ELF_H + +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_386 + +#endif /* ARCH_ELF_H */ diff --git a/include/arch/x86/arch/spinlock.h b/include/arch/x86/arch/spinlock.h new file mode 100644 index 0000000000..9d8fc7c9ee --- /dev/null +++ b/include/arch/x86/arch/spinlock.h @@ -0,0 +1,83 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2001 Linux Networx + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef ARCH_SPINLOCK_H +#define ARCH_SPINLOCK_H + +/* + * Your basic SMP spinlocks, allowing only a single CPU anywhere + */ + +typedef struct { + volatile unsigned int lock; +} spinlock_t; + + +#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 } + +/* + * Simple spin lock operations. There are two variants, one clears IRQ's + * on the local processor, one does not. + * + * We make no fairness assumptions. They have a cost. + */ +#define barrier() __asm__ __volatile__("": : :"memory") +#define spin_is_locked(x) (*(volatile char *)(&(x)->lock) <= 0) +#define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x)) + +#define spin_lock_string \ + "\n1:\t" \ + "lock ; decb %0\n\t" \ + "js 2f\n" \ + ".section .text.lock,\"ax\"\n" \ + "2:\t" \ + "cmpb $0,%0\n\t" \ + "rep;nop\n\t" \ + "jle 2b\n\t" \ + "jmp 1b\n" \ + ".previous" + +/* + * This works. Despite all the confusion. + */ +#define spin_unlock_string \ + "movb $1,%0" + +static inline __attribute__((always_inline)) void spin_lock(spinlock_t *lock) +{ + __asm__ __volatile__( + spin_lock_string + :"=m" (lock->lock) : : "memory"); +} + +static inline __attribute__((always_inline)) void spin_unlock(spinlock_t *lock) +{ + __asm__ __volatile__( + spin_unlock_string + :"=m" (lock->lock) : : "memory"); +} + +/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */ +static inline __attribute__((always_inline)) void cpu_relax(void) +{ + __asm__ __volatile__("rep;nop": : :"memory"); +} + +#endif /* ARCH_SPINLOCK_H */ diff --git a/include/arch/x86/archelf.h b/include/arch/x86/archelf.h deleted file mode 100644 index baea0ddd18..0000000000 --- a/include/arch/x86/archelf.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef ARCH_X86_ARCHELF_H -#define ARCH_X86_ARCHELF_H - -#define ELF_CLASS ELFCLASS32 -#define ELF_DATA ELFDATA2LSB -#define ELF_ARCH EM_386 - -#endif /* ARCH_X86_ARCHELF_H */ diff --git a/include/device/device.h b/include/device/device.h index f66234d8ba..204b1a6dd4 100644 --- a/include/device/device.h +++ b/include/device/device.h @@ -112,18 +112,21 @@ struct device_operations { void (*set_link)(struct device * dev, unsigned int link); void (*reset_bus)(struct bus *bus); - /* a constructor. The constructor for a given device is defined in the device source file. - * When is this called? Not for the static tree. When the scan bus code finds a new device, it must - * create it and insert it into the device tree. To do this, it calls a device constructor. - * The set of all device constructors is concatenated into the constructors array of structures via the usual - * gcc hack of naming a segment. - * The dev_constructor code in device.c iterates over the constructors array. - * A match consists of a path type, a vendor (which may be ignored if the constructo vendor value is 0), - * and a device id. - * When it finds a match, the dev_constructor calls the - * function constructors->constructor(constructors->constructor) and a new device is created. + /* A constructor. The constructor for a given device is defined in the + * device source file. When is this called? Not for the static tree. + * When the scan bus code finds a new device, it must create it and + * insert it into the device tree. To initialize it, it calls a device + * constructor. The set of all device constructors is concatenated + * into the constructors array of structures. + * + * The dev_constructor code in device.c iterates over the constructors + * array. A match consists of a path type, a vendor (which may be + * ignored if the constructor vendor value is 0), and a device id. + * When it finds a match, the dev_constructor calls the function + * constructors->constructor(constructors->constructor) and a new + * device is created. */ - struct device *(*constructor)(struct constructor *); + void (*constructor)(struct device *, struct constructor *); /* set device ops */ void (*phase1_set_device_operations)(struct device *dev); @@ -245,7 +248,7 @@ struct device * dev_find_device (unsigned int vendor, unsigned int device, struc struct device * dev_find_class (unsigned int class, struct device * from); struct device * dev_find_slot (unsigned int bus, unsigned int devfn); struct device * dev_find_slot_on_smbus (unsigned int bus, unsigned int addr); -struct device *default_device_constructor(struct constructor *constructor); +void default_device_constructor(struct device *dev, struct constructor *constructor); /* Rounding for boundaries. diff --git a/include/elf.h b/include/elf.h index 2fcbc3cfa7..729fe00775 100644 --- a/include/elf.h +++ b/include/elf.h @@ -31,7 +31,7 @@ #define ELF_H #include -#include +#include /* Standard ELF types. */ diff --git a/include/stdlib.h b/include/stdlib.h deleted file mode 100644 index 00ad41c8bd..0000000000 --- a/include/stdlib.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * This file is part of the LinuxBIOS project. - * - * Copyright (C) 2007 coresystems GmbH - * (Written by Stefan Reinauer for coresystems GmbH) - * - * 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; version 2 of the License. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA - */ - -void *malloc(size_t size); - diff --git a/lib/console.c b/lib/console.c index b63b6f4dcf..ecb60b145c 100644 --- a/lib/console.c +++ b/lib/console.c @@ -2,7 +2,6 @@ #include #include #include -// FIXME: we need this for varargs #include int vtxprintf(void (*)(unsigned char, void *arg), diff --git a/lib/malloc.c b/lib/malloc.c deleted file mode 100644 index b9e0370a09..0000000000 --- a/lib/malloc.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * This file is part of the LinuxBIOS project. - * - * Copyright (C) 2007 Ronald G. Minnich - * - * 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; version 2 of the License. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA - */ - -/* - * Simple non-freeing malloc. There have been about a million versions of - * this but we need one with a known author. Almost every OS and bootloader - * has had this at some time or other. - */ - -#include -#include -#include - -#if 0 -#define MALLOCDBG(x...) -#else -#define MALLOCDBG(x...) printk(BIOS_SPEW, x) -#endif - -/* - * Instead of ldscript magic, just declare an array. The array will consume - * no bytes in the image, and it won't run into trouble the way the v2 - * allocator could. We do not provide zero'd memory. - * - * Note that the execute-in-place (XIP) code in top of flash is not allowed - * to call malloc(), since we can't link this in to it. The flash-based code - * should always be dead simple (in fact, it's not clear we need malloc() at - * all any more -- we're doing our best to remove all usage of it -- the - * only real users were elfboot and lzma, and we have removed its usage in - * elfboot, and will try to remove its usage in lzma). - */ - -#define HEAPSIZE (256 * 1024) -static unsigned char heap[HEAPSIZE]; -static unsigned char *free_mem_ptr = heap; -static unsigned long freebytes = HEAPSIZE; - -/** - * Allocate 'size' bytes of memory. The memory is not zero'd. - * If not enough memory is available, just die. - * - * @param size The number of bytes to allocate. - * @return A pointer to the allocated memory. - */ -void *malloc(size_t size) -{ - void *p; - - MALLOCDBG("%s Enter, size %d, free_mem_ptr %p\n", - __FUNCTION__, size, free_mem_ptr); - - if (size > freebytes) { - die("Out of memory.\n"); - } - - size = (size + 3) & (~3); /* Align */ - - p = free_mem_ptr; - free_mem_ptr += size; - freebytes -= size; - - MALLOCDBG("malloc 0x%08lx\n", (unsigned long)p); - - return p; -} - -/** - * Free the specified memory area. - * This is a no-op, we don't care about freeing memory. - * - * @param where A pointer to the memory area to free. - */ -void free(void *where) -{ - /* Don't care. */ -} diff --git a/util/dtc/dtc-parser.y b/util/dtc/dtc-parser.y index 6a76ff27f0..0c2b74c6cf 100644 --- a/util/dtc/dtc-parser.y +++ b/util/dtc/dtc-parser.y @@ -142,7 +142,7 @@ config: DT_CONFIG '(' } ')' ';' { /* convention: first property is labeled with path */ - $6->label = strdup($3.val); + $6->label = strdup((char *)$3.val); $$ = $6 } |