globale Daten
Stellungnahme
# < lib_arm\board.c >
DECLARE_GLOBAL_DATA_PTR;
Definition
# < include\asm\global_data.h >
typedef struct globale_daten {
bd_t *bd;
unsigned long flags;
vorzeichenlose lange Baudrate;
unsigned long have_console; /* serial_init() wurde aufgerufen */
unsigned long env_addr; /* Adresse der Umgebungsstruktur */
unsigned long env_valid; /* Prüfsumme der Umgebung gültig? */
unsigned long fb_base; /* Basisadresse des Framebuffers */
#ifdef CONFIG_VFD
unsigned char vfd_type; /* Anzeigetyp */
#endif
#wenn 0
unsigned long cpu_clk; /* CPU-Takt in Hz! */
unsigned long bus_clk;
phys_size_t ram_size; /* RAM-Größe */
unsigned long reset_status; /* Statusregister beim Booten zurücksetzen */
#endif
nichtig **jt; /* Tabelle springen */
} gd_t;
// Deklarieren Sie einen gd_t-Typ-Zeiger gd, der in Register r8 gespeichert ist
#define DECLARE_GLOBAL_DATA_PTR registrieren flüchtig gd_t *gd asm ("r8")
Feld Beschreibung
bd_t *bd: Board-Info-Datenstrukturdefinition, befindet sich in der Datei include/asm-arm/u-boot.h definition, hauptsächlich um die relevanten Parameter des Entwicklungsboards zu speichern.
typedef struct bd_info {
int bi_baudrate; /* Baudrate der seriellen Konsole */
unsigned long bi_ip_addr; /* IP Adresse */
struct Umgebung_s *bi_env;
ulong bi_arch_number; /* eindeutige ID für dieses Board */
ulong bi_boot_params; /* wo dieses Board Parameter erwartet */
struct /* RAM-Konfiguration */
{
Vorsprung;
Kopf Größe;
}bi_dram[CONFIG_NR_DRAM_BANKS];
} bd_t;
unsigned long env_addr: Die Adresse der Umgebungsvariable.
unsigned long ram_top: die oberste Adresse des RAM-Bereichs
unsigned long relocaddr: Adresse nach UBOOT-Umleitung
phys_size_t ram_size: Größe des physischen Arbeitsspeichers
unsigned long irq_sp: Interrupt-Stack-Adresse
unsigned long start_addr_sp: Stapeladresse
unsigned long reloc_off: Verschiebungsoffset von uboot
struct global_data *new_gd: die umgeleitete struct global_data-Struktur
const void *fdt_blob: die dtb-Adresse unseres Geräts
void *new_fdt: dtb-Adresse nach Umzug
unsigned long fdt_size: die Länge von dtb
struct udevice *cur_serial_dev: aktuell verwendetes serielles Gerät.
Initialisierungssequenz (Board-Initialisierungsfunktionssequenz)
Prototyp
# < lib_arm\board.c >
typedef int (init_fnc_t) (void);
int print_cpuinfo (leer);
init_fnc_t *init_sequence[] = {
#falls definiert(CONFIG_ARCH_CPU_INIT)
arch_cpu_init, /* grundlegende Arch-CPU-abhängige Einrichtung */
#endif
board_init, /* grundlegende kartenabhängige Einrichtung */
#falls definiert(CONFIG_USE_IRQ)
interrupt_init, /* Ausnahmen einrichten */
#endif
timer_init, /* Timer initialisieren */
env_init, /* Umgebung initialisieren */
init_baudrate, /* Baudrateneinstellungen initialisieren */
serial_init, /* Einrichtung der seriellen Kommunikation */
console_init_f, /* Stage 1 Initialisierung der Konsole */
display_banner, /* sagen, dass wir hier sind */
#falls definiert(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo, /* CPU-Info (und Geschwindigkeit) anzeigen */
#endif
#falls definiert(CONFIG_DISPLAY_BOARDINFO)
Schachbrett, /* Brettinfo anzeigen */
#endif
#falls definiert(CONFIG_HARD_I2C) || definiert (CONFIG_SOFT_I2C)
init_func_i2c,
#endif
dram_init, /* verfügbare RAM-Bänke konfigurieren */
#falls definiert(CONFIG_CMD_PCI) || definiert (CONFIG_PCI)
arm_pci_init,
#endif
display_dram_config,
NULL,
};
Ergebnis
init_fnc_t *init_sequence[] = {
board_init, /* grundlegende kartenabhängige Einrichtung */
timer_init, /* Timer initialisieren */
env_init, /* Umgebung initialisieren */
init_baudrate, /* Baudrateneinstellungen initialisieren */
serial_init, /* Einrichtung der seriellen Kommunikation */
console_init_f, /* Stage 1 Initialisierung der Konsole */
display_banner, /* sagen, dass wir hier sind */
dram_init, /* verfügbare RAM-Bänke konfigurieren */
display_dram_config,
NULL,
};
Eingabefunktion
Eingang
# < lib_arm\board.c >
void start_armboot (nichtig)
Bewerben Sie sich für gd globale Daten
gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));
Verhindert, dass die gcc-Optimierung für hohe Versionen Fehler generiert
_asm__ __volatile__("": : :"Speicher");
veranschaulichen:
1) __asm__ wird verwendet, um den Compiler anzuweisen, hier Assembly-Anweisungen einzufügen.
2) __volatile__ wird verwendet, um dem Compiler mitzuteilen, dass es strengstens verboten ist, die Assembly-Anweisung hier mit anderen Anweisungen neu zu kombinieren und zu optimieren. Das heißt: Die Baugruppe wird hier so verarbeitet, wie sie ursprünglich war.
3) Speicher zwingt den gcc-Compiler anzunehmen, dass alle Speichereinheiten im RAM durch Assembler-Anweisungen modifiziert werden, sodass die Daten in den Registern in der CPU und den zwischengespeicherten Speichereinheiten im Cache ungültig werden. Die CPU muss die Daten im Speicher bei Bedarf erneut lesen. Dies verhindert, dass die CPU die Daten in Registern und im Cache verwendet, um Anweisungen zu optimieren und den Zugriff auf den Speicher zu vermeiden.
4) ""::: bedeutet, dass dies eine leere Anweisung ist. barrier() muss hier keine Serialisierungs-Assembler-Anweisung einfügen.
klare globale Daten
memset ((void*)gd, 0, sizeof (gd_t));
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
memset (gd->bd, 0, sizeof (bd_t));
Flagbit setzen (aktueller Code im RAM)
gd->flags |= GD_FLG_RELOC;
Holen Sie sich die gesamte uboot-Länge
monitor_flash_len = _bss_start - _armboot_start;
veranschaulichen:
_bss_start ist die Startadresse von bss, _armboot_start ist die Startcodeadresse von Uboot, wobei monitor_flash_len die Länge des gesamten Uboot erhält
mit einer Folge von Initialisierern initialisieren
für (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr)
{
if ((*init_fnc_ptr)() != 0) //Der Rückgabewert der Funktion ist nicht Null, direkt in die Endlosschleife eintreten
{
hang (); // Endlosschleife { for(;;); }
}
}
Initialisieren Sie den Speicher-Heap-Bereich
mem_malloc_init (_armboot_start - CONFIG_SYS_MALLOC_LEN, CONFIG_SYS_MALLOC_LEN);
veranschaulichen:
_armboot_start = TEXT_BASE = 0x33F80000
# < common\dlmalloc.c >
void mem_malloc_init (Vorsprung, Kopfgröße)
{
mem_malloc_start = starten;
mem_malloc_end = Anfang + Größe;
mem_malloc_brk = starten;
memset((void *)mem_malloc_start, 0, Größe);
}
Initialisierung des Flash-Treibers
#ifndef CONFIG_SYS_NO_FLASH
/* Verfügbare FLASH-Bänke konfigurieren */
display_flash_config (flash_init ());
#endif /* CONFIG_SYS_NO_FLASH */
veranschaulichen:
# < lib_arm\board.c >
Statisch void display_flash_config (Ulong-Größe)
{
setzt ("Flash: ");
print_size (Größe, "\n");
}
Nand-Laufwerk initialisieren
#falls definiert(CONFIG_CMD_NAND)
setzt ("NAND: ");
nand_init(); /* NAND initialisieren */
#endif
veranschaulichen:
# <include\configs\mini2440.h>
#define CONFIG_SYS_MAX_NAND_DEVICE 1
# < Treiber\mtd\nand\nand.c >
void nand_init(void)
{
int ich;
unsigned int Größe = 0;
für (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]);
Größe += nand_info[i].size / 1024;
if (nand_curr_device == -1)
nand_curr_device = ich;
}
printf("%u MiB\n", Größe / 1024);
#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
/*
* Wählen Sie den Chip im Board-/CPU-spezifischen Treiber aus
*/
board_nand_select_device(nand_info[nand_curr_device].priv, nand_curr_device);
#endif
}
Initialisierung der Umgebungsvariablen
env_relocate ();
Holen Sie sich die IP-Adresse aus der Umgebungsvariable
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
veranschaulichen:
IPaddr_t getenv_IPaddr (char *var)
{
return (string_to_ip(getenv(var)));
}
char *getenv (char *name)
{
int i, nxt;
WATCHDOG_RESET();
// Komfort für alle Strings
for (i=0; env_get_char(i) != '\0'; i=nxt+1)
{
int val;
// Finden Sie einen String heraus (mit '\0' abgeschlossen)
for (nxt=i; env_get_char(nxt) != '\0'; ++nxt)
{
if (nxt >= CONFIG_ENV_SIZE)
{
Rückgabe (NULL);
}
}
if ((val=envmatch((uchar *)name, i)) < 0) // ermittle den Namen
weitermachen;
return ((char *)env_get_addr(val));
}
Rückgabe (NULL);
}
uchar env_get_char_memory (int-Index)
{
if (gd->env_valid) {
return ( *((uchar *)(gd->env_addr + index)) );
} anders {
return ( default_environment [index] );
}
}
uchar *env_get_addr (int-Index)
{
if (gd->env_valid) {
return ( ((uchar *)(gd->env_addr + index)) );
} anders {
return (&default_environment[index]);
}
}
Standardeingabe, Standardausgabe, Standardfehlerinitialisierung ("stdin", "stdout", "stderr")
stdio_init()
int stdio_init (leer)
{ //Der Rest des Codes ist aufgrund von Makros blockiert
drv_system_init ();
Rückkehr (0);
}
statische void drv_system_init (void)
{
struct stdio_dev dev;
memset (&dev, 0, sizeof (dev));
strcpy (dev.name, "serial");
dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
dev.putc = serial_putc;
dev.puts = serial_puts;
dev.getc = serial_getc;
dev.tstc = serial_tstc;
stdio_register (&dev);
}
struct stdio_dev {
int-Flags; /* Geräteflags: Eingabe/Ausgabe/System */
im Text; /* Unterstützte Erweiterungen */
Zeichenname[16]; /* Gerätename */
/* ALLGEMEINE Funktionen */
int (*start) (leer); /* Um das Gerät zu starten */
int (*stop) (leer); /* Um das Gerät zu stoppen */
/* OUTPUT-Funktionen */
void (*putc) (const char c); /* Um ein Zeichen zu setzen */
void (*puts) (const char *s); /* Um einen String einzufügen (Beschleuniger) */
/* INPUT-Funktionen */
int (*tstc) (nichtig); /* Um zu testen ob ein Char bereit ist... */
int (*getc) (leer); /* Um dieses Zeichen zu bekommen */
/* Andere Funktionen */
ungültig *priv; /* Private Erweiterungen */
struct list_head list;
};
int stdio_register (struct stdio_dev * dev)
{
struct stdio_dev *_dev;
_dev = stdio_clone(dev);
wenn(!_dev)
Rückgabe -1;
list_add_tail(&(_dev->list), &(devs.list));
0 zurückgeben;
}
struct stdio_dev* stdio_clone(struct stdio_dev *dev)
{
struct stdio_dev *_dev;
wenn(!dev)
gib NULL zurück;
_dev = calloc(1, sizeof(struct stdio_dev));
wenn(!_dev)
gib NULL zurück;
memcpy(_dev, dev, sizeof(struct stdio_dev));
strncpy(_dev->name, dev->name, 16);
return _dev;
}
Initialisierung der Sprungtabelle
jumptable_init ();
void jumptable_init (nichtig)
{ //Funktionsadresse
int ich;
gd->jt = (void **) malloc (XF_MAX * sizeof (void *));
für (i = 0; i < XF_MAX; i++)
gd->jt[i] = (void *) dummy;
gd->jt[XF_get_version] = (void *) get_version;
gd->jt[XF_malloc] = (void *) malloc;
gd->jt[XF_free] = (void *) kostenlos;
gd->jt[XF_getenv] = (void *) getenv;
gd->jt[XF_setenv] = (void *) setenv;
gd->jt[XF_get_timer] = (void *) get_timer;
gd->jt[XF_simple_strtoul] = (void *) simple_strtoul;
gd->jt[XF_udelay] = (void *) udelay;
gd->jt[XF_simple_strtol] = (void *) simple_strtol;
gd->jt[XF_strcmp] = (void *) strcmp;
#falls definiert(CONFIG_I386) || definiert (CONFIG_PPC)
gd->jt[XF_install_hdlr] = (void *) irq_install_handler;
gd->jt[XF_free_hdlr] = (void *) irq_free_handler;
#endif /* I386 || PPC */
#falls definiert(CONFIG_CMD_I2C)
gd->jt[XF_i2c_write] = (void *) i2c_write;
gd->jt[XF_i2c_read] = (void *) i2c_read;
#endif
#ifdef CONFIG_CMD_SPI
gd->jt[XF_spi_init] = (void *) spi_init;
gd->jt[XF_spi_setup_slave] = (void *) spi_setup_slave;
gd->jt[XF_spi_free_slave] = (void *) spi_free_slave;
gd->jt[XF_spi_claim_bus] = (void *) spi_claim_bus;
gd->jt[XF_spi_release_bus] = (void *) spi_release_bus;
gd->jt[XF_spi_xfer] = (void *) spi_xfer;
#endif
}
Initialisierung der zweiten Stufe des Endgeräts
console_init_r ();
Initialisierung unterbrechen
enable_interrupts ();
veranschaulichen:
Laut Makro: CONFIG_USE_IRQ ist diese Funktion blockiert
void enable_interrupts (nichtig)
{
zurückkehren;
}
Holen Sie sich die Ladeadresse aus der Umgebungsvariablen (nicht verwendet, die Umgebungsvariable hat diesen Parameter nicht)
if ((s = getenv ("loadaddr")) != NULL) {
load_addr = simple_strtoul (s, NULL, 16);
}
Hauptschleife
für (;;)
{
Hauptschleife ();
}
Beschreibung der Hysterese
Diverse Initialisierungen (init_sequence)
nand-Initialisierung (nand_init)
Initialisierung der Umgebungsvariablen (env_relocate)
Terminal-Initialisierung (console_init_r)
Hauptschleife (main_loop)