VxWorks start of the Rominit.s

Source: Internet
Author: User
Tags manual

Reprint Address: http://www.360doc.com/content/11/1031/17/7880321_160589434.shtml

X86 When the CPU is power up, the first instruction executed is located.
Students know that after resetting the CPU in real mode, CS=0XF000,IP=0XFFF0, the formation of a linear address of cs<<4+ip=0xffff0, which is the last 16 bytes of the 1M address space. Because the paging mechanism has not been started, this address is the physical address. Many of the books include some Linux what the analysis of what is said, but this conclusion to 8086 is true, for 80286 and more than 386 of the CPU, the situation is more complicated.
For more than 386 processors (386,486,pentium), the CS register also has an invisible part of the 48-bit, called the code snippet cache register, which contains the code snippet base address (base), segment Size (Limit), Segment Properties (Access), etc. The initial values after the reset are as follows:
EIP 0x0000fff0
CS Selector = 0xf000
Base = 0xffff0000
Limit = 0xFFFF
AR = Present, r/w
Accessed
The linear address is computed in the form of
Linear address = Base + EIP
This is calculated either in real or protected mode. However, when the value of CS is modified in real mode, the value of base becomes cs*16 (but the initial value does not satisfy the relationship).
The above analysis shows that the reset vector is 0xffff0000+0x0000fff0=0xfffffff0, which is the last 16 bytes of the 4GB space. In the absence of a paging mechanism, this is the physical address that the CPU forms. (It is possible to map it to 0xf000:0xfff0 through the motherboard hardware, in short, the PC motherboard manufacturer should have the reset vector pointing to the Rom BIOS.) )
Note: There are 3 types of addresses on the X86: segment/Offset is a logical address, segmented processing (segmentation) becomes a linear address, and then paging (paging) transforms to physical address. A segment is a block in the linear address space, and multiple logical addresses may correspond to the same linear address, because overlap may occur between segments.
"A20 Address line"
The early 8,086 had only 20 address lines, and only 1M of address space was accessible. CPU addressing is done by Segment + offset. The possible range of 16-bit segment + 16-bit offsets is 0~0x10ffef (that is, 0XFFFF0+0XFFFF), which is the range of 1m+65520 bytes. Because there are only 20 address lines, when accessing the 1m~1m+65520 range, "address wrapping" occurs, that is, where the 0~65520 is actually accessed. It is said that a famous/notorious software has exploited this feature. On the 80286,386 CPU, it will fail because these CPUs have more than 20 address lines and do not produce an "address wrapping" phenomenon. To maintain full compatibility, IBM decided to add logic to the PC at system to mimic the wrapping features above. Their approach is to control the opening and closing of the A20 by taking an output of the A20 and keyboard controller. At first A20 is blocked (always 0), until the system software goes to open it.
Note that A20 and not a20~a31 are controlled, so some interesting side effects occur when the A20 is turned off. is to access the odd m address space, the actual address will be reduced by 1M. For example, when accessing 1m~2m-1, the actual access is 0~1m-1, 2m~3m-1 when accessing 3m~4m-1, and so on.
"BIOS"
After the PC is power on, the BIOS runs first from the ROM.
The BIOS starts a series of initialization operations, such as Post (Power-on self-test), initializes the bus controller and memory controller, detects memory, initializes the PCI device, and so on. PC DIY people know more than we do.
After the BIOS initialization is complete, the first sector of the floppy disk (boot sector, 512 bytes) or the first sector of the hard disk (the primary boot sector mbr,512 bytes) is read to the 0x7c00 of the memory, and then jumps to 0x7c00 to execute. This transfers control to the boot record. In general, boot records are installed when the operating system is installed, or other tool software, such as Lilo,systemcommand, can be selectively booted from one of several operating systems.
After the MBR is run, the bootable partition (active partition) of the hard disk is searched, and the contents of the boot sector of the partition are loaded. The program in the boot sector is called the bootstrapper.
The VxWorks bootloader is called Vxld, which is written by the Tornado tool vxsys.com. After it runs, it loads Bootrom.sys from the root of the current disk (this file must be stored continuously because VXLD is simple and does not recognize any file system) and loads the address as 0x8000. This step is done by calling the BIOS INT13. Jump to 0x8000 execution after loading is complete. The first instruction of the VxWorks operating system is stored in the 0x8000 place (note: this is bootrom; for vxWorks image is 0x108000; or vice versa).
Note the relationship between the VxWorks and BIOS on the PC target machine. VxWorks assumes that the BIOS has correctly initialized the system hardware, including memory, PCI bus, and so on, so the pc386,pc486 and so on, the BSP has omitted a lot of work. However, after booting, VxWorks does not use any BIOS functionality, which is not the same as DOS. Because the VxWorks is running in protected mode, the BIOS function must be called in the actual mode (perhaps someone can tell us how to invoke the BIOS function in protected mode, of course this is a high-level topic). In general, normally, when the VxWorks is running, the BIOS disappears completely.

"ROMINIT.S compilation process"
The instructions executed when compiling the ROMINIT.S are:
cc386-bd:\tornado/host/x86-win32/lib/gcc-lib/-mno-486-ansi-nostdinc-o-fvolatile-nostdlib-fno-builtin- Fno-defer-pop-i/h-i.-id:\tornado\target\config\all-id:\tornado\target/h-id:\tornado\target/src/config-id:\ Tornado\target/src/drv-dcpu=i80386-p-x assembler-with-cpp-c-O rominit.o rominit.s
This assembly file is also called CC to compile, the use of the option is-X assembler-with-cpp, which is pre-processing with the C preprocessor. Preprocessing becomes a "pure" assembly, placed in a temporary file, CC then calls the assembler to compile it. The benefit of mixing C and assembler is that you can share some macro definitions and use the C compiler's flexibility, which is bad for locating errors.
"VxWorks initialization"
. Data
Start data segment. The following content appears in the data section.
. Globl _copyright_wind_river
. Long _copyright_wind_river
DECLARE (declare) the global variable _copyright_wind_river and use it to define a new variable.
Note that ". Globl" is a declaration rather than a definition (equivalent to the extern of C). The _copyright_wind_river variable is defined in the Tornado library (for pc386, a module COPYRIGHT.O in [TORNADO]/TARGET/LIB/LIBI80386GNUVX.A].
". Long" defines a 32-bit global variable with an initial value of _copyright_wind_river address. Since ROMINIT.O is the first linked module in makefile, this nameless variable will appear at the beginning of the data segment.
#define _asmlanguage
Defines the _asmlanguage macro. After seeing this definition, the GNU compiler CC will be preprocessed according to the C syntax, so you can recognize the types and macros defined in the C header file. If you do not define _asmlanguage, the following # include statements will not compile.
#include "VxWorks.h"
#include "SysLib.h"
#include "Config.h"
Contains 3 header files for C. VxWorks.h is the system header file; SysLib.h is provided to the BSP header file for the system; Config.h is the BSP header file.
. Globl _rominit
. Globl _sdata
Declare global variables _rominit and _sdata. _rominit is actually the starting position of the code.
_sdata:
. Asciz "Start of data"
Defines a string ending with 0 "start of data". This string appears after the first nameless variable in the data segment.
. text
. Align 4
.text begins the code snippet, the following appears in the code snippet: Align 4 instructs the compiler to adjust the current pointer in the. Text segment to a multiple of 2^4. The compiler fills it so that the next instruction is on an address that is divisible by 16. Snapping allows the CPU to take commands a little faster.

_rominit:

The following is the first instruction of the VxWorks system. At this point the CPU is still in real mode, the program can only access 1 m of memory space, the default instruction is 16-bit code. The CPU needs to be switched to protected mode as soon as possible.
Cli
JMP Cold
Turn off the interrupt and jump to the cold place. This is a relative jump within a paragraph.
. Align 4, 0x90

System hot start from _romwarmhigh or _romwarmlow, refer to Systomonitor () in SYSLIB.C. Please analyze the hot-start process yourself.
_romwarmhigh:
Cli
MOVL 4 (%ESP),%EBX
JMP Warm
. Align 4, 0x90

_romwarmlow:
Cli
Cld
MOVL $RAM _low_adrs,%esi
MOVL $ROM _text_adrs,%edi
MOVL $ROM _size,%ECX
SHRL,%ECX
Rep
Movsl
MOVL 4 (%ESP),%EBX
JMP Warm

. ASCII "Copyright 1984-1996 Wind River System, Inc."
. Align 4
The copyright declaration string defined above appears in the code snippet.
Cold
Aword
Word
Lidt%CS:ROM_IDTR
Aword
Word
LGDT%CS:ROM_GDTR
In real mode, the value of the CS,DS,ES,FS,GS,SS segment register *16 is the base address of the segment, and in protected mode is called the selector (16-bit segment selector), which points to the item in the Global Descriptor Descriptor GDT (descriptor, segment descriptor, 48-bit), The base address, size, and attributes of the segment are obtained from the segment descriptor. Before switching to protected mode, the GDT needs to be prepared. The GDT is in memory and is specified by the CPU's GDTR register for its base address and size.
So in protected mode, using registers such as CS as the index of the GDT array, the base address of the segment is obtained from the table. Of course, this is done automatically by the hardware.
In protected mode, the base address and size of the interrupt vector table must be specified by the IDTR register.
These two instructions load the IDTR and GDTR registers. Both registers are 48-bit, the first 16 bits are the size of the table minus 1, and the last 32 bits are the base addresses of the table in memory.
Aword and Word instruction prefixes are used for what. The machine codes for these two prefixes are 0x67 and 0x66, respectively. Adding such a prefix to the 32-bit code allows it to become 16-bit code, which can be changed to 32-bit code before 16-bit code.
What is the 32-bit code and the 16-bit code. For example, the machine code "89H,C3H" is to indicate "mov%eax,%ebx" or "mov%ax,%bx". (yes, these two statements have the same machine code.) Otherwise, the number of instructions is too much. 16-bit or 32-bit, this depends on whether the current code snippet's properties are 32-bit or 16-bit. The segment attribute is in the segment descriptor. (One conclusion: the protection method may not be 32-bit, because the segment property can be modified.) However, in real mode, there is no segment descriptor, and the segment register contains the segment value directly. Intel's manual says that the default operand width and address width are always 16-bit. )
Operand Width Properties: Specifies whether the width of the operand is 32-bit (for example,%eax) or 16-bit (for example,%ax).
Address Width Property: Specifies the address width if an instruction generates addressing to the memory.
The GNU compiler works by default in 32-bit assembly mode, that is, it assumes that the current instruction is 32-bit code. However, at this point the CPU is still in real mode, and the CPU defaults to the current instruction as 16-bit instruction. You can let the CPU execute 32-bit instructions in real mode by adding the instruction prefix.
There are other instruction prefixes, refer to the CPU manual. The instruction prefix affects only the next instruction.
ROM_IDTR and ROM_GDTR are defined in pc.h as 0xAF and 0xb5, respectively, specifying where the values of the IDTR and GDTR registers to be loaded are stored in the current code snippet. This is, of course, the result of manual calculations. May be replaced by _ROMIDTR-_romstart and _ROMGDTR-_romstart.
MOVL%cr0,%eax
. Byte 0x66
or $0x00000001,%eax
MOVL%eax,%cr0
JMP romInit1
Switch to protected mode. It's actually simple: put the CR0 register at the lowest position 1 to enter protection mode.
.byte 66 instruction prefix (equivalent to Word; do not know why the author no longer uses word) to specify 32-bit operands. Without this prefix, the CPU performing "or $0x00000001 in real mode,%eax" will have the effect of "ax|=0x0001".
JMP is a relative jump within a paragraph. The contents of the instruction queue before switching to protected mode are also the instructions for previous CPU prefetching. Use jmp to empty it.
ROMINIT1:
. Byte 0x66
mov $0x0010,%eax
mov%ax,%ds
mov%ax,%es
mov%ax,%fs
mov%ax,%gs
mov%ax,%SS
. Byte 0x66
mov $ROM _stack,%ESP
Protection mode is now in. However, the values of the individual segment registers, as well as the values in their cache registers, are still old. Set the DS, ES, FS, GS, SS Register to 0x0010, which is the 2nd item that points to GDT (starting from 0), dpl=0. They all point to a segment. Set the stack pointer esp to rom_stack.
Because CS is still a previous value, it means that the current code snippet's properties are still 16-bit code. So use the instruction prefix to execute the 32-bit code.
Aword
Word
LJMP $0x08, $ROM _text_adrs + rom_init2
Executes a remote segment to change the CS between jumps. The new value of CS is 0x08, which is the 1th item of the GDT, dpl=0. When you modify CS, its cache registers are automatically updated. The following will enter into the 32-bit code mode.
ROM_INIT2 is defined as 0xf0 in pc.h, and should also be the result of manual calculation, indicating the offset of _rominit2 relative to the current code segment. May be replaced by _rominit2-_romstart + Rom_text_adrs.
_ROMIDTR:
. Word 0x0000
. Long 0x000000000
IDT (Interrupt Description Table), interrupt descriptor descriptor, empty.
_ROMGDTR:
. Word 0x0027
. Long Rom_text_adrs + ROM_GDT
The value of the GDTR register that will be loaded. ROM_GDT is defined as 0xc0 in pc.h. Perhaps it can be written like this:
. Word _romgdtend-_romgdt-1
. Long _romgdt-_romstart + rom_text_addr
Let the compiler calculate it for us, which is more flexible.
. Align 4, 0
_ROMGDT:

. Word 0x0000
. Word 0x0000
. Byte 0x00
. Byte 0x00
. Byte 0x00
. Byte 0x00

. Word 0xFFFF
. Word 0x0000
. Byte 0x00
. Byte 0x9a
. Byte 0xCF
. Byte 0x00

. Word 0xFFFF
. Word 0x0000
. Byte 0x00
. Byte 0x92
. Byte 0xCF
. Byte 0x00

. Word 0xFFFF
. Word 0x0000
. Byte 0x00
. Byte 0x9a
. Byte 0xCF
. Byte 0x00

. Word 0xFFFF
. Word 0x0000
. Byte 0x00
. Byte 0x9a
. Byte 0xCF
. Byte 0x00
The following code runs in protected mode, and the individual segment registers already contain the appropriate values.
. Align 4,0x90
_rominit2:
Cli
MOV $ rom_stack,%esp
Call _roma20on
MOVL $ boot_cold,%ebx
Warm
MOVL $_romgdtr,%eax
Subl $_rominit,%eax
Addl $ rom_text_adrs,%eax
PUSHL%eax
Call _ROMLOADGDT
MOVL $ stack_adrs,%esp
MOVL $0,%EBP
Pushl
Popfl
PUSHL%EBX
Cld
MOVL $ rom_text_adrs,%esi
MOVL $_rominit,%edi
MOVL $_END,%ECX
Subl%EDI,%ECX
Shrl $2,%ECX
Rep
Movsl
MOVL $_romstart,%eax
Call *%eax

_ROMINITHLT:
Hlt

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.