打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
u-boot 内部工作机制

Implementation Internals:
=========================

The following is not intended to be a complete description of every
implementation detail. However, it should help to understand the
inner workings of U-Boot and make it easier to port it to custom
hardware.


Initial Stack, Global Data:
---------------------------

The implementation of U-Boot is complicated by the fact that U-Boot
starts running out of ROM (flash memory), usually without access to
system RAM (because the memory controller is not initialized yet).
This means that we don't have writable Data or BSS segments, and BSS
is not initialized as zero. To be able to get a C environment working
at all, we have to allocate at least a minimal stack. Implementation
options for this are defined and restricted by the CPU used: Some CPU
models provide on-chip memory (like the IMMR area on MPC8xx and
MPC826x processors), on others (parts of) the data cache can be
locked as (mis-) used as memory, etc.

 Chris Hallinan posted a good summary of these issues to the
 U-Boot mailing list:

 Subject: RE: [U-Boot-Users] RE: More On Memory Bank x (nothingness)?
 From: "Chris Hallinan" <clh@net1plus.com>
 Date: Mon, 10 Feb 2003 16:43:46 -0500 (22:43 MET)
 ...

 Correct me if I'm wrong, folks, but the way I understand it
 is this: Using DCACHE as initial RAM for Stack, etc, does not
 require any physical RAM backing up the cache. The cleverness
 is that the cache is being used as a temporary supply of
 necessary storage before the SDRAM controller is setup. It's
 beyond the scope of this list to explain the details, but you
 can see how this works by studying the cache architecture and
 operation in the architecture and processor-specific manuals.

 OCM is On Chip Memory, which I believe the 405GP has 4K. It
 is another option for the system designer to use as an
 initial stack/RAM area prior to SDRAM being available. Either
 option should work for you. Using CS 4 should be fine if your
 board designers haven't used it for something that would
 cause you grief during the initial boot! It is frequently not
 used.

 CONFIG_SYS_INIT_RAM_ADDR should be somewhere that won't interfere
 with your processor/board/system design. The default value
 you will find in any recent u-boot distribution in
 walnut.h should work for you. I'd set it to a value larger
 than your SDRAM module. If you have a 64MB SDRAM module, set
 it above 400_0000. Just make sure your board has no resources
 that are supposed to respond to that address! That code in
 start.S has been around a while and should work as is when
 you get the config right.

 -Chris Hallinan
 DS4.COM, Inc.

It is essential to remember this, since it has some impact on the C
code for the initialization procedures:

* Initialized global data (data segment) is read-only. Do not attempt
  to write it.

* Do not use any uninitialized global data (or implicitely initialized
  as zero data - BSS segment) at all - this is undefined, initiali-
  zation is performed later (when relocating to RAM).

* Stack space is very limited. Avoid big data buffers or things like
  that.

Having only the stack as writable memory limits means we cannot use
normal global data to share information beween the code. But it
turned out that the implementation of U-Boot can be greatly
simplified by making a global data structure (gd_t) available to all
functions. We could pass a pointer to this data as argument to _all_
functions, but this would bloat the code. Instead we use a feature of
the GCC compiler (Global Register Variables) to share the data: we
place a pointer (gd) to the global data into a register which we
reserve for this purpose.

When choosing a register for such a purpose we are restricted by the
relevant  (E)ABI  specifications for the current architecture, and by
GCC's implementation.

For PowerPC, the following registers have specific use:
 R1: stack pointer
 R2: reserved for system use
 R3-R4: parameter passing and return values
 R5-R10: parameter passing
 R13: small data area pointer
 R30: GOT pointer
 R31: frame pointer

 (U-Boot also uses R12 as internal GOT pointer. r12
 is a volatile register so r12 needs to be reset when
 going back and forth between asm and C)

    ==> U-Boot will use R2 to hold a pointer to the global data

    Note: on PPC, we could use a static initializer (since the
    address of the global data structure is known at compile time),
    but it turned out that reserving a register results in somewhat
    smaller code - although the code savings are not that big (on
    average for all boards 752 bytes for the whole U-Boot image,
    624 text + 127 data).

On Blackfin, the normal C ABI (except for P3) is followed as documented here:
 http://docs.blackfin.uclinux.org/doku.php?id=application_binary_interface

    ==> U-Boot will use P3 to hold a pointer to the global data

On ARM, the following registers are used:

 R0: function argument word/integer result
 R1-R3: function argument word
 R9: GOT pointer
 R10: stack limit (used only if stack checking if enabled)
 R11: argument (frame) pointer
 R12: temporary workspace
 R13: stack pointer
 R14: link register
 R15: program counter

    ==> U-Boot will use R8 to hold a pointer to the global data

On Nios II, the ABI is documented here:
 http://www.altera.com/literature/hb/nios2/n2cpu_nii51016.pdf

    ==> U-Boot will use gp to hold a pointer to the global data

    Note: on Nios II, we give "-G0" option to gcc and don't use gp
    to access small data sections, so gp is free.

NOTE: DECLARE_GLOBAL_DATA_PTR must be used with file-global scope,
or current versions of GCC may "optimize" the code too much.

Memory Management:
------------------

U-Boot runs in system state and uses physical addresses, i.e. the
MMU is not used either for address mapping nor for memory protection.

The available memory is mapped to fixed addresses using the memory
controller. In this process, a contiguous block is formed for each
memory type (Flash, SDRAM, SRAM), even when it consists of several
physical memory banks.

U-Boot is installed in the first 128 kB of the first Flash bank (on
TQM8xxL modules this is the range 0x40000000 ... 0x4001FFFF). After
booting and sizing and initializing DRAM, the code relocates itself
to the upper end of DRAM. Immediately below the U-Boot code some
memory is reserved for use by malloc() [see CONFIG_SYS_MALLOC_LEN
configuration setting]. Below that, a structure with global Board
Info data is placed, followed by the stack (growing downward).

Additionally, some exception handler code is copied to the low 8 kB
of DRAM (0x00000000 ... 0x00001FFF).

So a typical memory configuration with 16 MB of DRAM could look like
this:

 0x0000 0000 Exception Vector code
       :
 0x0000 1FFF
 0x0000 2000 Free for Application Use
       :
       :

       :
       :
 0x00FB FF20 Monitor Stack (Growing downward)
 0x00FB FFAC Board Info Data and permanent copy of global data
 0x00FC 0000 Malloc Arena
       :
 0x00FD FFFF
 0x00FE 0000 RAM Copy of Monitor Code
 ...  eventually: LCD or video framebuffer
 ...  eventually: pRAM (Protected RAM - unchanged by reset)
 0x00FF FFFF [End of RAM]


System Initialization:
----------------------

In the reset configuration, U-Boot starts at the reset entry point
(on most PowerPC systems at address 0x00000100). Because of the reset
configuration for CS0# this is a mirror of the onboard Flash memory.
To be able to re-map memory U-Boot then jumps to its link address.
To be able to implement the initialization code in C, a (small!)
initial stack is set up in the internal Dual Ported RAM (in case CPUs
which provide such a feature like MPC8xx or MPC8260), or in a locked
part of the data cache. After that, U-Boot initializes the CPU core,
the caches and the SIU.

Next, all (potentially) available memory banks are mapped using a
preliminary mapping. For example, we put them on 512 MB boundaries
(multiples of 0x20000000: SDRAM on 0x00000000 and 0x20000000, Flash
on 0x40000000 and 0x60000000, SRAM on 0x80000000). Then UPM A is
programmed for SDRAM access. Using the temporary configuration, a
simple memory test is run that determines the size of the SDRAM
banks.

When there is more than one SDRAM bank, and the banks are of
different size, the largest is mapped first. For equal size, the first
bank (CS2#) is mapped first. The first mapping is always for address
0x00000000, with any additional banks following immediately to create
contiguous memory starting from 0.

Then, the monitor installs itself at the upper end of the SDRAM area
and allocates memory for use by malloc() and for the global Board
Info data; also, the exception vector code is copied to the low RAM
pages, and the final stack is set up.

Only after this relocation will you have a "normal" C environment;
until that you are restricted in several ways, mostly because you are
running from ROM, and because the code will have to be relocated to a
new address in RAM.


U-Boot Porting Guide:
----------------------

[Based on messages by Jerry Van Baren in the U-Boot-Users mailing
list, October 2002]


int main(int argc, char *argv[])
{
 sighandler_t no_more_time;

 signal(SIGALRM, no_more_time);
 alarm(PROJECT_DEADLINE - toSec (3 * WEEK));

 if (available_money > available_manpower) {
  Pay consultant to port U-Boot;
  return 0;
 }

 Download latest U-Boot source;

 Subscribe to u-boot mailing list;

 if (clueless)
  email("Hi, I am new to U-Boot, how do I get started?");

 while (learning) {
  Read the README file in the top level directory;
  Read http://www.denx.de/twiki/bin/view/DULG/Manual;
  Read applicable doc/*.README;
  Read the source, Luke;
  /* find . -name "*.[chS]" | xargs grep -i <keyword> */
 }

 if (available_money > toLocalCurrency ($2500))
  Buy a BDI3000;
 else
  Add a lot of aggravation and time;

 if (a similar board exists) { /* hopefully... */
  cp -a board/<similar> board/<myboard>
  cp include/configs/<similar>.h include/configs/<myboard>.h
 } else {
  Create your own board support subdirectory;
  Create your own board include/configs/<myboard>.h file;
 }
 Edit new board/<myboard> files
 Edit new include/configs/<myboard>.h

 while (!accepted) {
  while (!running) {
   do {
    Add / modify source code;
   } until (compiles);
   Debug;
   if (clueless)
    email("Hi, I am having problems...");
  }
  Send patch file to the U-Boot email list;
  if (reasonable critiques)
   Incorporate improvements from email list code review;
  else
   Defend code as written;
 }

 return 0;
}

void no_more_time (int sig)
{
      hire_a_guru();
}


Coding Standards:
-----------------

All contributions to U-Boot should conform to the Linux kernel
coding style; see the file "Documentation/CodingStyle" and the script
"scripts/Lindent" in your Linux kernel source directory.

Source files originating from a different project (for example the
MTD subsystem) are generally exempt from these guidelines and are not
reformated to ease subsequent migration to newer versions of those
sources.

Please note that U-Boot is implemented in C (and to some small parts in
Assembler); no C++ is used, so please do not use C++ style comments (//)
in your code.

Please also stick to the following formatting rules:
- remove any trailing white space
- use TAB characters for indentation and vertical alignment, not spaces
- make sure NOT to use DOS '\r\n' line feeds
- do not add more than 2 consecutive empty lines to source files
- do not add trailing empty lines to source files

Submissions which do not conform to the standards may be returned
with a request to reformat the changes.


Submitting Patches:
-------------------

Since the number of patches for U-Boot is growing, we need to
establish some rules. Submissions which do not conform to these rules
may be rejected, even when they contain important and valuable stuff.

Please see http://www.denx.de/wiki/U-Boot/Patches for details.

Patches shall be sent to the u-boot mailing list <u-boot@lists.denx.de>;
see http://lists.denx.de/mailman/listinfo/u-boot

When you send a patch, please include the following information with
it:

* For bug fixes: a description of the bug and how your patch fixes
  this bug. Please try to include a way of demonstrating that the
  patch actually fixes something.

* For new features: a description of the feature and your
  implementation.

* A CHANGELOG entry as plaintext (separate from the patch)

* For major contributions, your entry to the CREDITS file

* When you add support for a new board, don't forget to add this
  board to the MAINTAINERS file, too.

* If your patch adds new configuration options, don't forget to
  document these in the README file.

* The patch itself. If you are using git (which is *strongly*
  recommended) you can easily generate the patch using the
  "git format-patch". If you then use "git send-email" to send it to
  the U-Boot mailing list, you will avoid most of the common problems
  with some other mail clients.

  If you cannot use git, use "diff -purN OLD NEW". If your version of
  diff does not support these options, then get the latest version of
  GNU diff.

  The current directory when running this command shall be the parent
  directory of the U-Boot source tree (i. e. please make sure that
  your patch includes sufficient directory information for the
  affected files).

  We prefer patches as plain text. MIME attachments are discouraged,
  and compressed attachments must not be used.

* If one logical set of modifications affects or creates several
  files, all these changes shall be submitted in a SINGLE patch file.

* Changesets that contain different, unrelated modifications shall be
  submitted as SEPARATE patches, one patch per changeset.

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
7.5 Device Tree Blob (Flat Device Tree) | Boo...
Thunk and its uses
为什么继承是有害的?
Some notes on lock-free and wait-free algorithms
uboot移植
RPM SPEC文件编写通用规范
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服