#include <stdio.h>
#include<string.h>
#include <stdlib.h>
/*************************************************************
* Function : addSpecialChar
* Input : str
* Output : newStr
* Description : This function gets a character array and
* inserts # in between each character and
* returns the new character array.
* Input : abcdef
* Output: #a#b#c#d#e#f#
************************************************************/
char *addSpecialChar(char *str)
{
int index = 0;
char *newStr = (char *) calloc (2*strlen(str)+1,
sizeof(char));
if (NULL == newStr)
{
fprintf(stderr,
"[%s:%d] Memory allocation failed.",
__FUNCTION__, __LINE__);
return NULL;
}
while ('\0' != *str)
{
newStr[index++] = '#';
newStr[index++] = *str;
str++;
}
newStr[index++] = '#';
newStr[index] = '\0';
return newStr;
}
/*************************************************************
* Function : getScore
* Input : str, score
* Output : maxScore
* Description : This function calculates the number of
* symmetric characters around each character
* in the given string and updates the score
* array. It returns the index of the max score
* from the score array.
* Input : # a # a # b # c # b # a #
* Output: 0 1 2 1 0 1 0 5 0 1 0 1 0
************************************************************/
int getScore (char *str, int **score)
{
int index = 1;
int maxIndex = 0;
int maxScore = 0;
**score = 0;
while ('\0' != str[index])
{
int leftindex = index - 1;
int rightindex = index + 1;
/* Calculate the score */
int tmpScore = 0;
for (;; leftindex--, rightindex++)
{
if (str[leftindex] != str[rightindex])
{
break;
}
if (leftindex == 0)
{
tmpScore++;
break;
}
tmpScore++;
}
*((*score)+index) = tmpScore;
if (maxScore < tmpScore)
{
maxScore = tmpScore;
maxIndex = index;
}
/* The score on the left should be identical to the right
* if the score at the new index is less than the difference
* between score on the axis (current index) and the offset
*/
int newIndex = 1;
for (; newIndex < tmpScore; newIndex++)
{
if (*((*score)+index-newIndex) < *((*score)+index)-newIndex)
{
*((*score)+index+newIndex) = *((*score)+index-newIndex);
}
else
{
break;
}
}
index = index + newIndex;
}
printf ("Max Index [%d]\n", maxIndex);
return maxIndex;
}
int main (int agrc, char **argv)
{
int *score = NULL;
char *newStr = addSpecialChar (argv[1]);
if (NULL != newStr)
{
score = (int *) calloc (strlen(newStr), sizeof (int));
if (NULL == score)
{
fprintf(stderr,
"[%s:%d] Memory allocation failed.",
__FUNCTION__, __LINE__);
}
/* Print the actual string */
printf ("%s\n%s\n", argv[1], newStr);
int maxIndex = getScore (newStr, &score);
/* Print the new string */
for (int i=0; i<strlen(newStr); i++)
{
printf ("%-4c", newStr[i]);
}
printf ("\n");
/* Print the scores */
for (int i=0; i<strlen(newStr); i++)
{
printf ("%-4d", score[i]);
}
printf ("\n");
/* Here is the longest palindrome */
printf ("Longest Palindrome: ");
int i = maxIndex/2 - score[maxIndex]/2;
for (; i <= maxIndex/2 + score[maxIndex]/2; i++)
{
printf ("%c", argv[1][i]);
}
printf("\n");
}
return 0;
}
Output:
[COMMAND] ===> ./logestPalindrome aabcba
aabcba
#a#a#b#c#b#a#
Max Index [7]
# a # a # b # c # b # a #
0 1 2 1 0 1 0 5 0 1 0 1 0
Longest Palindrome: abcba
-----------------------------------------------------------------------
[COMMAND] ===> ./logestPalindrome aabcbabcbabcba
aabcbabcbabcba
#a#a#b#c#b#a#b#c#b#a#b#c#b#a#
Max Index [15]
# a # a # b # c # b # a # b # c # b # a # b # c # b # a #
0 1 2 1 0 1 0 5 0 1 0 9 0 1 0 13 0 1 0 9 0 1 0 5 0 1 0 1 0
Longest Palindrome: abcbabcbabcba
-----------------------------------------------------------------------
[COMMAND] ===> ./logestPalindrome aabcbabcbaccba
aabcbabcbaccba
#a#a#b#c#b#a#b#c#b#a#c#c#b#a#
Max Index [11]
# a # a # b # c # b # a # b # c # b # a # c # c # b # a #
0 1 2 1 0 1 0 5 0 1 0 9 0 1 0 5 0 1 0 1 0 1 2 1 0 1 0 1 0
Longest Palindrome: abcbabcba
-----------------------------------------------------------------------
[COMMAND] ===> ./logestPalindrome babcbabcbaccba
babcbabcbaccba
#b#a#b#c#b#a#b#c#b#a#c#c#b#a#
Max Index [11]
# b # a # b # c # b # a # b # c # b # a # c # c # b # a #
0 1 0 3 0 1 0 7 0 1 0 9 0 1 0 5 0 1 0 1 0 1 2 1 0 1 0 1 0
Longest Palindrome: abcbabcba
-----------------------------------------------------------------------
[COMMAND] ===> ./logestPalindrome aaaaaaaaaaaaaaa
aaaaaaaaaaaaaaa
#a#a#a#a#a#a#a#a#a#a#a#a#a#a#a#
Max Index [15]
# a # a # a # a # a # a # a # a # a # a # a # a # a # a # a #
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Longest Palindrome: aaaaaaaaaaaaaaa
-----------------------------------------------------------------------
[COMMAND] ===> ./logestPalindrome aaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaa
#a#a#a#a#a#a#a#a#a#a#a#a#a#a#a#a#
Max Index [16]
# a # a # a # a # a # a # a # a # a # a # a # a # a # a # a # a #
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Longest Palindrome: aaaaaaaaaaaaaaaa
-----------------------------------------------------------------------
[COMMAND] ===> ./logestPalindrome a
a
#a#
Max Index [1]
# a #
0 1 0
Longest Palindrome: a
#!/bin/bash
function logging() {
while read line; do
echo "{$(date +'%Y-%m-%d %H:%M:%S')} $line"
done
}
function stdintoexitstatus() {
read exitstatus
return $exitstatus
}
cmds=(
"cal"
"cal lkjhsd"
)
for i in $(seq 0 $((${#cmds[@]}-1)))
do
echo "--------------------------------------------------------"
echo "[COMMAND] ${cmds[$i]}"
echo "--------------------------------------------------------"
((((eval ${cmds[$i]} 2>&1; echo $? >&3) | logging >&4) 3>&1) | stdintoexitstatus) 4>&1
echo "Exit Status[$?]"
echo
done
COMMAND:eval ${cmds[$i]} 2>&1
The output and the error messages of the eval are redirected to stdout
COMMAND:echo $? >&3
The status of the eval is stored in the file descriptor 3
COMMAND:| logging >&4
The (output/error)stdout from eval is piped to logging function where we do logging
and the output of the logging function is stored in file descriptor 4
COMMAND:3>&1 | stdintoexitstatus
Get the status of eval from file descriptor 3 and update $?
COMMAND:4>&1
Get the output of the logging function from file descriptor 4 and redirect them to stdout
#!/bin/bash
# -A declares v to be an associative array
# [key]=vlaue
declare -A v
v=(
["var1"]="variable 01"
["var2"]="variable 02"
["var3"]="variable 03"
["var4"]="variable 01"
)
# ${!v[@]} gives us the keys
# to access the value use ${v[key]}
for k in ${!v[@]}
do
echo "v: [$k] => [${v[$k]}]"
done
# key can have spaces
declare -A vws
vws=(
["var 1"]="variable 01"
["var 2"]="variable 02"
)
echo "vsw: [var 1] => [${vws['var 1']}]"
echo "vsw: [var 2] => [${vws['var 2']}]"
INTRODUCTION
Exciting new embedded Linux devices are appearing at an amazing rate. Installing and booting Linux on these wildly varying boards is not possible without a good boot loader.
That'swhere Das U-Boot, a Free Software universal boot loader, steps in.
GENERAL BOOTING PROCESS
BIOS: ( Basic Input/Output System )
The BIOS has a firmware in the ROM of a PC. When the PC is powered up, the BIOS is the first program that runs.
Note: The most fundamental and obvious difference between x86 boards and embedded systems based on PPC, ARM, and others is that the x86 board will ship with one or more layers of manufacturer-supplied "black box" firmware that helps you with power-on initialization and the task of loading the operating system out of secondary storage. This firmware takes the system from a cold start to a known, friendly software environment ready to run your operating system.
The BIOS contains the following parts:
POST ( Power On Self Test ) - a computer's pre-boot sequence. Each time a PC initializes, the BIOS executes a series of tests collectively known as the POST. The test checks each of the primary areas of the system, including the motherboard, video system, drive system, and keyboard, and ensures that all components can be used safely. If a fault is detected, the POST reports it as an audible series of beeps or a hexadecimal code written to an I/O port.
The Setup Menu, that lets you set some parameters and lets you adjust the real time clock. Most modern BIOS versions let you set the boot order, the devices that BIOS checks for booting. These can be A (the first floppy disk), C (the first hard disk), CD-ROM and possibly other disks as well. The first device in the list will be tried first. Older BIOS-es have only one boot order: A, C. So the BIOS will try to boot from A first and if there is no diskette in the drive it tries to boot from C.
The boot sector loader. This loads the first 512-byte sector from the boot disk into RAM and jumps to it
The only thing it knows about disks is how to load the first 512-byte sector. Boot disk can be floppy diskette, hard disk or CD-ROM. The first sector of a boot disk ( If it is hard disk, the first sector is called MBR Master Boot Record ) can be loaded at address 0000:7C00. The last two bytes of the sector are checked for the values 0x55 and 0xAA, this as a rough sanity check. If these are OK, the BIOS jumps to the address 0000:7C00. If it is multi stage boot loader, the MBR program must move itself to an address that is different from 0000:7C00 as it is supposed to load a different boot sector from a partition to address 0000:7C00 and jump to that.
Modern BIOS versions can treat a certain file on a CD-ROM as a diskette image. They boot from a diskette by loading the first 512 bytes of the file to 0000:7C00 and jumping to it.
The BIOS interrupts. These are simple device drivers that programs can use to access the screen, the keyboard and disks. Boot loaders rely on them, But most operating systems do not (the Linux kernel does not use BIOS interrupts once it has been started). MSDOS does use BIOS interrupts.
Boot Loader: A boot loader typically consists of three programs.
The boot loader can be only 512 bytes in size and is directly loaded by the BIOS at boot time. Because of the size restriction, it has to be written in assemble. A boot sector program cannot do everything you want a boot loader to do. Usually a boot sector program does one of the following things (not all three in one program)
Load another boot sector.
Load another boot sector.
Load the kernel directly.
The second stage program is the real boot program and loaded by the boot sector program and it does everything you expect the boot loader to do. It contains the following functions:
User interface. It is either a simple command line (old versions of LILO), a menu or both. It allows you to select any number of operating systems and to specify additional parameters to the operating system. The available options are specified by a configuration file. Modern versions of boot loaders can show their menu in a bitmap picture.
Operating system loader. loads the operating system into memory and runs it. Alternatively we can load another boot loader specific to another operating system and let it run. This is called chain loading.
The boot loader installer is not run when the system is booted, but it is used to install the boot loader and the second stage program onto the boot disk. These have to be stored in special locations, so they cannot be copied with cp. It performs the following tasks:
Install the boot sector. If the boot sector will be installed in the MBR of a hard disk or on a DOS file system, not all 512 bytes may be overwritten, but the partition table or the DOS parameter block must be preserved.
Tell the boot sector where the second stage boot loader is. Usually it writes one or more sector addresses into the boot loader.
Tell the second stage boot loader where all relevant information is (configuration, kernels). This is the case with LILO. LILO creates a map file that contains all relevant sector addresses and puts pointers to the map file in the boot sector and/or second stage boot loader.
BOOT LOADER FOR EMBEDDED SYSTEMS
It is small piece of software that executes soon after the system is on. In our Desktop Linux PC, BIOS performs various system initializations, once the power is on. Then, it executes the boot loader located in the MBR(master boot record). The boot loader then passes the information to the kernel and then executes the kernel.
In an embedded system the role of the boot loader is more complicated since these systems do not have a BIOS to perform the initial system configuration. The low level initialization of microprocessors, memory controllers, and other board specific hardware varies from board to board and CPU to CPU. These initializations must be performed before a Linux kernel image can execute.
At a minimum an embedded boot loader provides the following features:
Initializing the hardware, especially the memory controller.
Providing boot parameters for the Linux kernel.
Starting the Linux kernel.
Additionally, most embedded boot loaders also provide extra features to simplify the development on the board:
Reading and writing arbitrary memory locations.
Uploading new binary images to the board's RAM via a serial line or Ethernet.
Copying binary images from RAM to FLASH memory.
Note: MBR - The first sector of the harddrive is master boot record (MBR). It includes the harddrives boot code and partition table. The partition table contains the information about the partition layout of harddisk. The size of the MBR will be 512 bytes, as is the size of every sector on an x86 machines harddisk.
U-BOOT
U-Boot provides support for hundreds of embedded boards and a wide variety of CPUs including PowerPC, ARM, XScale, MIPS, Coldfire, NIOS, Microblaze, and x86. You can easily configure U-Boot to strike the right balance between a rich feature set and a small binary footprint.
U-BOOT SOURCE CODE HIERARCHY
|--
board
Board dependent files
|--
common
Misc architecture independent functions
|--
cpu
CPU specific files
|-- 74xx_7xx
Files specific to Freescale MPC74xx and 7xx CPUs
|-- arm720t
Files specific to ARM 720 CPUs
|-- arm920t
Files specific to ARM 920 CPUs
 |-- imx
Files specific to Freescale MC9328 i.MX CPUs
 |-- s3c24x0  
Files specific to Samsung S3C24X0 CPUs
|-- arm925t
Files specific to ARM 925 CPUs
|-- arm926ejs
Files specific to ARM 926 CPUs
|-- at91rm9200
Files specific to Atmel AT91RM9200 CPUs
|-- i386
Files specific to i386 CPUs
|-- ixp
Files specific to Intel XScale IXP CPUs
|-- mcf52x2
Files specific to Freescale ColdFire MCF52x2 CPUs
|-- mips
Files specific to MIPS CPUs
|-- mpc5xx
Files specific to Freescale MPC5xx CPUs
|-- mpc5xxx
Files specific to Freescale MPC5xxx CPUs
|-- mpc8xx
Files specific to Freescale MPC8xx CPUs
|-- mpc8220
Files specific to Freescale MPC8220 CPUs
|-- mpc824x
Files specific to Freescale MPC824x CPUs
|-- mpc8260
Files specific to Freescale MPC8260 CPUs
|-- mpc85xx
Files specific to Freescale MPC85xx CPUs
|-- nios
Files specific to Altera NIOS CPUs
|-- nios2
Files specific to Altera Nios-II CPUs
|-- ppc4xx
Files specific to IBM PowerPC 4xx CPUs
|-- pxa
Files specific to Intel XScale PXA CPUs
|-- s3c44b0
Files specific to Samsung S3C44B0 CPUs
|-- sa1100
Files specific to Intel StrongARM SA1100 CPUs
|--
disk
Code for disk drive partition handling
|--
doc
Documentation (don't expect too much)
|--
drivers
Commonly used device drivers
|--
dtt
Digital Thermometer and Thermostat drivers
|--
examples
Example code for standalone applications, etc.
|--
include
Header Files
|--
lib_arm
Files generic to ARM architecture
|--
lib_generic
Files generic to all architectures
|--
lib_i386
Files generic to i386 architecture
|--
lib_m68k
Files generic to m68k architecture
|--
lib_mips
Files generic to MIPS architecture
|--
lib_nios
Files generic to NIOS architecture
|--
lib_ppc
Files generic to PowerPC architecture
|--
net
Networking code
|--
post
Power On Self Test
|--
rtc
Real Time Clock drivers
|--
tools
Tools to build S-Record or U-Boot images, etc.
PREREQUISITES
Before building and installing U-Boot you need a cross-development tool chain for your target architecture. Generally, the term tool chain means a C/C++ compiler, an assembler, a linker/loader, associated binary utilities and header files for a specific architecture, like PowerPC or ARM. Collectively these programs are called a tool chain.
A cross-development tool chain executes on one CPU architecture, but generates binaries for a different architecture. In my case the host architecture is x86 while the target architecture is ARM and PowerPC. Sometimes this process is also referred to as cross-compiling.
Using cross-development tools makes developing embedded systems using Linux as the host development workstation.
CONFIGURING & BUILDING
Building U-Boot for one of the supported platforms is straight forward and there are ready-to-use default configurations available. To setup a default configuration for a particular board, type the following commands in the shell prompt after untarring the u-Boot tarball.
# cd
# make mrproper
# make _config
Note: Here <board_name> is one the supported boards.
Configuration depends on the combination of board and CPU type; all such information is kept in a configuration file "include/configs/<board_name>.h". You can fine tune the default configuration for your particular environment and board by editing this configuration file. This file contains several C-preprocessor #define macros that you can modify for your needs.
Now to build the binary image, u-boot.bin, type the following
# make all
After a successful compilation, you should get some working U-Boot images.
"u-boot.bin" is a raw binary image
"u-boot" is an image in ELF binary format
"u-boot.srec" is in Motorola S-Record format
U-BOOT CODE FLOW FOR OMAP5912OSK BOARD
Starts here,
Directory
: cpu/arm926ejs/
File
: start.S [This asm file]
sets CPU to SVC32 mode ( value: 0xD3 )
relocates U-Boot to RAM
does CPU_init_crit
flush I/D caches
disables MMU & caches
configures SPSR
takes care of exception handling for interrupts
resets CPU
calls start_armboot function from 'lib_arm' directory.
Directory
: lib_arm
File
: board.c [This asm file]
Function
: start_armboot() calls from start.S of cpu/arm926ejs/
'init_sequence' is an array of initializing functions to be called in an order.
init_fnc_t *init_sequence[] = {
cpu_init, /* basic cpu dependent setup */
board_init, /* basic board dependent setup */
interrupt_init, /* set up exceptions */
env_init, /* initialize environment */
init_baudrate, /* initialize baud rate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
display_banner, /* say that we are here */
dram_init, /* configure available RAM banks */
display_dram_config,
#if defined(CONFIG_VCMA9)
checkboard,
#endif
NULL,
};
Functions called from this start_armboot()
cpu_init() from cpu/arm926ejs/cpu.c
IRQ_STACK_START, FIQ_STACK_START are assigned for stack.
board_init() from board/omap5912osk/omap5912osk.c
arch_number = 234
boot_params = 0x10000100
Functions called from board_init()
set_muxconf_reg() from board/omap5912osk/omap5912osk.c
FUNC_MUX_CTRL_0 - 0xFFFE1000
Functional multiplexing control 0 register
Ref: OMAP5912_Technical_Reference_Guide.pdf – 454
peripheral_power_enable() from board/omap5912osk/omap5912osk.c
SOFT_REQ_REG - 0xFFFE0834
ULPD soft clock request register
value stored is 0x0200
Ref: OMAP5912_Technical_Reference_Guide.pdf - 559
flash__init() from board/omap5912osk/omap5912osk.c
EMIFS_GlB_Config_REG - 0xFFFECC0C
EMIFS_CONFIG_REG
value stored is 0x0001
Ref: OMAP5912_Technical_Reference_Guide.pdf - 157
ether__init() from board/omap5912osk/omap5912osk.c
0xFFFECE08 - MPU Idle Enable Contol Register
ARM_IDLECT2
Enable clock for all the controllers, peripherals, etc.
env_init() from common
depends on where it is located.
./common/env_dataflash.c:70:int env_init(void)
./common/env_eeprom.c:77:int env_init(void)
./common/env_flash.c:99:int env_init(void)
./common/env_flash.c:252:int env_init(void)
./common/env_nowhere.c:58:int env_init(void)
./common/env_nvram.c:137:int env_init (void)
init_baudrate() form ./lib_arm/board.c
check the environment variable starts with "baudrate"
if it is >0, load it in gd->bd->bi_baudrate
else load CONFIG_BAUDRATE from ./include/configs/omap5912osk.h
serial_init () from drivers/serial.c
get the clok_divisor
calls NS16550_init() from ./drivers/ns16550.c
console_init_f() from ./common/console.c
gd->have_console = 1
dram_init() from ./board/omap5912osk/omap5912osk.c
gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
PHYS_SDRAM_1 from ./include/configs/omap5912osk.h
display_dram_config() from ./lib_arm/board.c
print the information about dram from gd->bd->bi_dram.
Note: If something wrong in these initialization, it goes into infinite loop. We have to restart the board.
flash_init() from board/omap5912osk/flash.c
get the information about the flash devices
set protection status for monitor and environment sectors.
mem_malloc_init() from lib_arm/board.c
initialize the memory area for malloc()
get IP Address and MAC Address
devices_init() from common/devices.c
Functions called from here
i2c_init
drv_lcd_init
drv_video_init
drv_keyboard_init
drv_logbuff_init
drv_system_init
drv_usbtty_init
console_init_r() from common/console.c
initialize console as a device
misc_init_r() from board/omap5912osk/omap5912osk.c
currently function is empty.
enable_interrupts () from cpu/arm926ejs/interrupts.c
main_loop() from common/main.c
CONFIGURE U_BOOT FOR A NEW ARCHITECTURE
If the system board that you have is not listed, then you will need to port U-Boot to your hardware platform. To do this, follow these steps:
Add a new configuration option for your board to the toplevel "Makefile" and to the "MAKEALL" script, using the existing entries as examples. Note that here and at many other places boards and other names are listed in alphabetical sort order. Please keep this order.
Create a new directory to hold your board specific code. Add any files you need. In your board directory, you will need at least the "Makefile", a "<board>.c", "flash.c" and "u-boot.lds".
Create a new configuration file "include/configs/<board>.h" for your board
If you're porting U-Boot to a new CPU, then also create a new directory to hold your CPU specific code. Add any files you need.
Run "make _config" with your new name.
Type "make", and you should get a working "u-boot.srec"(Motorola format) or “u-boot.bin” file to be installed on your target system.
Debug and solve any problems that might arise. [Of course, this last step is much harder than it sounds.]
REFERENCES
U-Boot source codes
README' file which comeswith the U-Boot package tarball.