Contents
This guide highlights issues that may arise when adding support for the Solaris Operating System, x86 Platform Edition, to existing applications running on the Solaris OS, SPARC Platform Edition. For a majority of cases, the application is expected to work after it is recompiled on the new platform. A few instances may require changes to source code or make files, among others, but it depends on the application. This document covers in detail many areas where issues may occur.
Architectural Differences
Endianness
To achieve the goal of multiple-platform, multiple-instruction-set architecture portability, the first dependency issue to address is the endianness (or byte ordering) of the processor. The method of storing information in a computer's memory is referred to as endianness. When the most significant byte (MSB) of any multi-byte data field is stored at the lowest memory address, which is also the address of the larger field, then the system is said to be big-endian. When the least significant byte (LSB) of any multi-byte data field is stored at the lowest memory address, then the system is called little-endian.
For example, consider an integer 260 (hexadecimal equivalent is 0x0104). Suppose we are storing the value at address 100 and 101. If the system is big-endian, the system will store the integer as follows.
If the system is little-endian, the integer will be stored as follows.
Numeric data is stored in memory in a different format depending upon whether the target implementation platform is based on x86 or UltraSPARC technology. The SPARC processor-based systems implement the MSB first and so are big-endian, whereas the x86 systems implement the LSB first and are called little-endian.
The Solaris Operating System can be used both in big-endian mode (SPARC version) and in little-endian mode (x86 version). Endianness is mandated by the hardware platform used. One of the strengths of the Solaris OS is that it handles the endianness issue, so that ISVs or developers do not need to be concerned about how quickly their applications will be available on x86 platforms. Sun's software architecture allows big-endian applications for the Solaris SPARC Platform Edition to run on the little-endian Solaris x86 Platform when they are recompiled. In general, no re-engineering is needed. However, the endianness difference can cause problems, particularly if an application uses low-level code that takes optimal advantage of the hardware capabilities. Issues based on endianness that might arise on Solaris x86 include the following.
Sending Data Over the Network
Solution
The standard C library also provides the routines
Accessing the Individual Bytes of the Numeric Data Using Pointers
If an application uses individual bytes of a numeric data type to store and retrieve values, then you might get different results due to the endianness of the underlying platform. In this case the code would not be portable from Solaris SPARC to x86.
Value
Memory address:
100 101 102 103
int flagVal = 0X01020304;
char *cptr = (char *)&flagVal;
printf("Val is %d\n(", *cptr);
Solution
Application Data Storage
Solution
The need for cross-platform compatibility is so well-understood that major applications have been available on big-endian and little-endian Solaris environments for years without problems. They range from personal productivity applications to major database management systems from vendors including Oracle, Informix, and Sybase.
Shared Memory Implementation
To avoid the overhead of the attendant system call, while transferring data to high-speed devices through an operating system, you can arrange to map the memory on a peripheral processor directly into an application's address space. The most common example of shared memory mapped into an application's address space is the case of a graphics adapter with a frame buffer shared between the host and the graphics processor. Some peripheral buses lend themselves to shared memory approaches to interprocessor communication. In general, some means of translating the data must be provided if the processors are not of the same endianness.
Solution Another solution to the shared memory problem due to the endianness of the processor is the use of apertures for different endianness. One example is a PCI-based graphics adapter using a little-endian processor internally: the adapter can provide two apertures (ranges of addresses) for its frame buffers. If an adapter accesses the little-endian aperture, the system stores the data as it is presented on the bus and moves it directly into the frame buffer. In contrast, if an adapter accesses the big-endian aperture, the system swaps the data bytes before storing the data. Thus, if the application is running on a little-endian processor, it can simply map the little-endian aperture while the application running on a big-endian processor maps itself to the big-endian aperture. Also a host processor can provide endian translation apertures. UltraSPARC processors handle endianness through allowing independent assignment of endianness to each mapped page. For example, if a file that contains x86 data were mapped into memory in little-endian mode on an UltraSPARC chip, the data would be transparently swapped as it was loaded from or stored to the memory into which the file was mapped. This mechanism solves the problems associated with shared memory if data is properly aligned.
I/O Architecture
Unlike the x86 family, which uses special IN/OUT instructions to access the PCI I/O space, the SPARC chip family treats access to the PCI I/O space the same as it treats access to the memory space. Communication with I/O devices in the SPARC platform is accomplished through memory; a range of memory locations is logically replaced by device registers.
The x86 platform accesses I/O ports through the I/O address space by means of a set of I/O instructions and a special I/O protection mechanism. Accessing I/O ports through memory-mapped I/O is handled with the processor's general-purpose move and string instructions, with protection provided through segmentation or paging. I/O ports can be mapped so that they appear in the I/O address space or the physical-memory address space (memory-mapped I/O) or both. The SPARC platform assumes that input/output registers are accessed by means of load/store alternate instructions, normal load/store instructions, coprocessor instructions, or read/write ancillary state register instructions (RDASR, WRASR). In the load/store alternate instructions case, the I/O registers can only be accessed by the supervisor. If normal load/store instructions, coprocessor instructions, or read/write Ancillary State Register instructions are used, then whether the I/O registers can be accessed outside of supervisor code or not depends on the implementation.
Storage Order Differences
The order of storage of the data varies between platforms; therefore, code written assuming a particular storage order is not portable. The following code sample assumes that the year component may be stored before the month component. This code will work on the x86 machines but will not work properly on UltraSPARC machines.
struct date {
char year;
char month;
char day;
char dummy; // Added so that the struct var size is 4
} planned_date, end_date;
if ( (*(long * )&end_date ) > (*(long *)&planned_date))
{
printf("Sorry, You missed the deadline to support Solaris x86 platform \n");
}
Solution
if (compare_dates(end_date, planned_date) > 0)
{
printf("Sorry, You missed the deadline to support Solaris x86 platform \n");
}
int compare_dates(struct date date_to_compare,
struct date date_compare_against)
{
if (date_to_compare.year != date_compare_against.year)
return (date_to_compare.year - date_compare_against.year);
if (date_to_compare.month != date_compare_against.month)
return (date_to_compare.month - date_compare_against.month);
if (date_to_compare.day != date_compare_against.day)
return (date_to_compare.day - date_compare_against.day);
}
Data Alignment Differences
The alignment of the field members in a structure differs across platforms, resulting in variable padding requirements and causing the structure to be a different size. In order to make code portable, the structure size should always be accessed using the
sizeof operator.
Read Write Structures
Let's say your program needs to read a record of the type
MyRecord myrecord;
fread(&myrecord, 25, 1, fp);
Instead, you would use the following convention:
MyRecord myrecord;
fread(&myrecord, sizeof(MyRecord), 1, fp);
Alignment of Double and Long Double The following example demonstrates byte alignment problems:
#include <stdio.h>
main()
{
unsigned char bbb[5] = {0x12, 0x34, 0x56, 0x78, 0x9a };
printf("%x", *(int *)(bbb));
printf("%x", *(int *)(bbb + 1));
exit(0);
}
This is an example of a poorly written, non-portable C program. This code may be made to run on SPARC processors using either the -misalign and -misalign2 compiler options, but not on x86. For details, refer to the section on "Resolving Alignment Issues" in Porting UNIX Applications to the Solaris Operating Environment.
Padding
typedef struct bitmap {
WORD word_type;
DWORD dword_type;
} BITMAP;
Compilers add padding bytes into structures so that all values are appropriately aligned. The amount of padding added is, of course, a function of the structure, the processor's architecture, and the compiler. Because of this, structures may increase in size when code is ported to a processor architecture with more bits (for example, from 16 to 32, or from 32 to 64). For example, if a platform requires that words (assume 2 bytes) must be aligned on 2-byte boundaries, and that dwords (assume 4 bytes) must be aligned on 4-byte boundaries, then the structure will be laid out like so: 0 word_type 2 (padding) 4 dword_type sizeof(BITMAP) == 8 In contrast, on a platform not requiring any special alignment, it would be laid out like so: 0 word_type 2 dword_type sizeof(BITMAP) == 6 This difference could cause some corruption. However, in most cases, problems are not expected when porting applications from the Solaris SPARC to x86 environments because the Solaris OS compilation system manages most alignment and structure padding.
Floating Point Operation Differences
In x86 systems, the floating-point registers are 80-bits wide, while in the SPARC systems, the floating point registers are 64-bits wide. Due to this, the computation results can differ because intermediate results of arithmetic computations can be in extended precision. Please refer to the Numerical Computation Guide for further detail.
Solution
Other Issues Relating to Floating Point Operation
32-Bit and 64-Bit Issues
Enterprise-wide business critical applications that benefit from 64-bit technology include data warehousing, high-resolution graphics, computer-aided design, simulation and scientific data analysis, and multimedia web servers. These applications require more precision, a very large amount of simultaneous data processing capability, and a larger memory space than the 32-bit equivalent can address.
A 64-bit system differs from a 32-bit system in the following ways:
The Solaris OS, SPARC Platform Edition, has support for both 32-bit and 64-bit technology, while the x86 Platform Edition only supports the 32-bit family of x86 processors. Both Sun cc and gcc default to 32-bit mode on 64-bit machines, unless compiled with
-xarch=v9 (64-bit SPARC), v9a (UltraSPARC extensions), or v9b (UltraSPARC III extensions).
You can develop and run 32-bit applications in a 64-bit environment on the SPARC platform if you avoid using the architecture-dependent flag -xarch=v9. You can port the same application to the x86 platform after recompiling it on x86 platform without making any code changes.
Solution
x86 Booting
The main issue with the x86 booting architecture is that the standard BIOS is often not capable of booting from all possible boot devices. On x86-based systems, the second-stage bootstrap serves another very important purpose: it provides (for the kernel and other clients) the services that are performed by Open Firmware on SPARC processor-based systems.
On SPARC systems, the OBP provides the necessary support to allow booting from non-standard boot devices such as networks and CD-ROM drives. This capability is used during installation from a network or CD-ROM device, and by diskless (net-booting) Solaris clients. On the x86 platform, booting is supported by the platform BIOS. x86 BIOS is generally not capable of booting from network or CD-ROM devices.
Solution At the present time, all BEFs are delivered by Sun. Sun has not specified an interface for other parties to add their drivers to the Solaris x86 boot media (floppy or hard disk). Sun is expected to specify this interface, after which third-party developers will be able to ship drivers directly to customers. One possible mechanism is that third-party drivers will be included on a separate floppy disk, and the Solaris x86 boot system will provide the user with an opportunity to add these third-party drivers.
JumpStart Software
An x86 machine can be jumpstarted from SPARC and vice versa. However, the x86 Solaris installation cannot be totally automated.
Solution The advanced installation guide provided by Sun Product Documentation is a good start (see page on Servers Required for Network Installation. Another useful link is John Riddoch's page: Jumpstart on x86.
Hot-Plugging and Dynamic Reconfiguration
Hot-plugging is the ability to physically add, remove, or replace system hardware components while the system is running. Dynamic reconfiguration (DR) enables you to dynamically reconfigure, remove or install core system components into your server while the Solaris OS and your applications are running. DR also refers to the general ability to move system resources (both hardware and software) around in the system or to disable them in some way without physically removing them from the system.
You can hot-plug the following devices with the
Hot-plugging of PCI devices is not supported on all the SPARC platforms except on the V880. However, hot-swapping is supported by Sun Fire systems and cPCI boards on Netra servers. To see more details about the PCI hot-plugging supported only on the x86 platform, refer to the "Device Configuration Enhancements" section of the Sun Production Documentation site's
Address Space Layout
Address space layout is as follows:
x86 platform: The stack is beneath the executable segment and grows downwards. Kernel address space for x86 is more than 256 MB. It's necessary to have a 256-MB kernel address space mapped into the process address space. SPARC platform: The stack is at the top of the process address space and grows downwards. It has three different space layouts:
This difference in address space layout does not affect the application running on the systems, but it is better to know about the difference, just in case the developers need to deal with it.
Operating System and Other Differences
Disk Partition Table Issue
This would be an issue if a developer wants to move the SCCI hard drive from Solaris SPARC machine to Solaris x86 or vice versa. It is because of a different partition type (containing a different device address) value used by Solaris x86 in the partition table. Therefore, it is not possible to swap a hard drive between the Solaris SPARC and Solaris x86. No solution is available at this time.
Dual Boot Issue with Linux
The partition type (or system ID) value used by Solaris x86 in the
fdisk partition table is apparently the same value chosen for the Linux swap partition. Users who want to set up dual boot systems with both Solaris x86 and Linux and who have an existing Linux swap partition cannot install Solaris x86 unless they delete the Linux swap partition(s) from their disk drive(s).
The real danger is for users who install the Solaris OS first and then install Linux. The Linux install will see the Solaris partition and believe it's a swap partition. Users might not realize that they're a single keystroke away from wiping out their whole Solaris system; Linux will happily reformat the Solaris partition.
Solution If Linux 6.1 is being used, it is also recommended to first install Solaris x86 and then install Linux. In this case when installing the Linux, use one of the following workarounds:
These problems have been removed from higher versions of Linux.
OpenGL Support
The OpenGL is currently not supported on Solaris x86. It is supported on Solaris SPARC platforms.
Solution
FireWire Support
Solaris x86 does not support FireWire (IEEE 1394) technology, unlike the SPARC version. No solution is available at this time.
Instruction Set Architecture (ISA)-Specific Issue
Certain developers use specific instruction sets on the SPARC platform to obtain high-performance CPU-bound transactions. For example, some applications deal with voice recognition and other multimedia software using algorithmic computations (Fast Fourier instruction sets). If these applications are ported from the SPARC platform (where they would have used the VIS Instruction Set) to Solaris x86, they need to find some replacement for such fast instructions on Solaris x86.
Solution
Cross-Release Stability and Compatibility
A common problem in evolving computing environments is ensuring that applications continue to run despite changes to the underlying system's infrastructure or environment, for example, new operating system releases. Also, cross-platform compatibility provides a big plus in capturing a slice of the other platform's pie.
Solution Components of the Solaris ABI include:
Cross-Platform Compatibility
Linux applications can run without modification on the Solaris OS, x86 Platform Edition, using Lxrun. Lxrun is supported only on the x86 platform, not on the SPARC platform. See more detail at Lxrun Information. No solution is available at this time.
SunVTS Support
SunVTS is the Sun Validation Test Suite. SunVTS is a comprehensive diagnostic tool that tests and validates Sun hardware by verifying the connectivity and functionality of most hardware controllers and devices on Sun platforms. SunVTS is only supported on Solaris SPARC platforms. No such solution currently exists on Solaris x86.
Compiler Differences
Compiler Flags
Sun Studio 8 Compiler Collection consists of C, C++, and Fortran compilers. The compiler consists of a front-end component and a back-end component. The front-end consists of syntax and semantic analyzer modules based on the source language, while the back end consists of code optimization and code generation modules based on the instruction set for a particular hardware.
The Sun Studio 8 Compiler Collection works on both the Solaris OS SPARC and x86 platforms; the front-end component works the same for both, so the source code can be ported without changes. However, when the intermediate code generated by the front-end has to be optimized, the backend compiler flags are used. These are architecture dependent and are different for SPARC and x86 platforms.
For a detailed discussion of the differences in compiler flags, please refer to Compiler Differences Between Solaris OS, SPARC Platform Edition and x86 Platform Edition.
Thread Local Storage
Thread-local storage (TLS) is a mechanism to allocate storage for thread variables so that there is one instance of the variable per thread.
A thread-local variable can be declared at compile time using the
__thread int global_var = 0;
thread_function()
{
global_var = global_var + 1;
}
If we compile the preceding code on the Solaris OS SPARC compiler, the compiler creates a separate copy of this
If we try to compile the code having
Solution
In general, thread key creation allocates a key that locates data specific to each thread in the process. The key is global to all threads in the process, which allows each thread to bind a value to the key once the key has been created. The key independently maintains specific values for each binding thread. However, excessive usage of thread-specific data can be expensive as it involves a lock for each instance of key creation. The following code example shows the equivalent of the thread-local variable used on the SPARC version.
Example for POSIX:
pthread_key_t global_var;
pthread_key_create(&global_var, NULL);
thread_function()
{
int value;
int ret;
value = pthread_getspecific( global_var ) + 1;
ret = pthread_setspecific( global_var , value );
}
Example for Solaris OS:
thread_key_t global_var;
thr_key_create(&global_var, NULL);
thread_function()
{
int value;
thr_getspecific( global_var , &value ) + 1;
thr_setspecific( global_var , value );
}
Compilers to Consider
Sun Studio 8 Compiler Collection contains different options for back-end compiler flags on a wide variety of SPARC processors as well as x86 architecture-based processors. Also, it is useful when the code is ported from one architecture to another, as there are equivalent options available in this compiler. Hence, it is recommended to use Sun Studio 8 Compiler Collection for a successful porting of source code from the SPARC platform to the x86 platform. However, you can consider using the GCC compiler as well.
Hardware Compatibility
Device Driver Development Differences
Device drivers are modules that plug into the Solaris kernel and provide access to I/O devices including disks, tapes, CD drives, serial ports, and networks.
The Solaris OS provides driver developers with a comprehensive set of interfaces, Solaris Device Driver Interface/Driver-Kernel Interface (Solaris DDI/DKI), for accessing device memory. The Solaris DDI/DKI interfaces standardize and document all interface between device driver and the kernel. These interfaces are also designed to shield the driver from platform-specific dependencies by handling mismatches between processor and device endianness as well as enforcing any data-ordering dependencies the device might have. In addition, the Solaris DDI/DKI provides source compatibility for drivers on any machine running the Solaris OS, regardless of the processor architecture, such as SPARC or x86. By using these interfaces, a single code base driver can be developed that runs on both the SPARC and x86 processor families. The Solaris DDI/DKI insulates device drivers from most Instruction Set Architecture (ISA) and many bus architecture issues. However, the developers should be aware of some architectural considerations. This section outlines the SPARC and x86 processor issues a developer need to consider:
Endianness
Solution
If drivers have been written without using the endianness-neutral DDI/DDK interfaces and the drivers export a device memory directly to user application through
#ifdef _LITTLE_ENDIAN or #ifdef _BIG_ENDIAN However, the long-term maintenance here would be troublesome. That's why it is always recommended to use DDI/DKI to develop the portable drivers.
Accessing Device Memory and Registers
Data Alignment
Usually, the compiler handles alignment issues. However, driver developers are more likely to be concerned about alignment as they must use the proper data types to access their device. Because device registers are commonly accessed through a pointer reference, drivers must ensure that pointers are properly aligned when accessing the device.
Solution
32-Bit and 64-Bit Issues
DMA vs. DVMA
On platforms that support DMA, the system provides the device with a physical address in order to perform transfers. In this case, one logical transfer may actually consist of a number of physically discontiguous transfers. An example of this occurs when an application transfers a buffer that spans several contiguous virtual pages that map to physically discontiguous pages. To deal with the discontiguous memory, devices for these platforms usually have some kind of scatter/gather DMA capability. Typically the system that supports x86 platforms provides physical addresses for direct memory transfers.
On platforms that support DVMA, the system provides the device with a virtual address in order to perform transfers. In this case, the underlying platform provides some form of MMU, which translates device accesses to these virtual addresses into the proper physical addresses. The device transfers to and from a contiguous virtual image that may be mapped to discontiguous virtual pages. Devices that operate in these platforms don't need scatter/gather DMA capability. Typically, the system that supports SPARC platforms provides virtual addresses for direct memory transfers. The difference between these two memory access types requires major changes in porting a SPARC platform-based driver to the x86 platform.
NICs or Video Cards
The porting of an application from the Solaris OS SPARC platform to the x86 platform first and foremost involves the installation of Solaris on the x86 platform. The major issues that might arise during installation are the recognition of hardware components on the Intel machine. The hardware components that can be singled out as problematic are the video display cards and the network cards (NICs).
Solution
Hardware Compatibility List (HCL)
Since many combinations of hardware exist on the x86 platform, Sun has a list of hardware known as the Hardware Compatibility List (HCL). This list consists of systems that have been tested and verified by vendors and submitted for inclusion, as well as systems verified by users, and a list of hardware components supported by the Solaris OS, x86 Platform Edition.
However, please note that not all hardware combinations work all the time. For a successful installation of Solaris OS on x86, you need to know this information about the components installed on your system:
Solution
One way to avoid hardware issues during the installation of the Solaris 9 OS on the x86 platform is to find hardware combinations according to the HCL provided. Another recommendation is to install Solaris 9 (x86 version) on Sun machines supporting the x86 architecture, mainly the Sun LX50 server or the next-generation Sun Fire V60x and V65x servers. The Sun Fire V60x/65x machine supports the Solaris 9 4/03 Operating System (x86 Platform Edition) and later versions. To find information on peripherals using industry-standard I/O interfaces and a list of Solaris Ready certified products available on the Solaris OS SPARC and x86 platforms, refer to the Sun I/O Technologies and Solutions site.
Technical Case Study
Technical Case Study: Porting Apache
Web Server from Solaris OS, SPARC Platform Edition to x86 Platform
Edition covers the various aspects of building and installing the
Apache Web Server source code on both the SPARC and x86 Platform Editions of the
Solaris OS. This document compares the build on both these Solaris OS Platform Editions, and it offers an analysis of issues that came up during the compilation of source code.
Acknowledgments
This document is based on discussions with and feedback from Tim Mac, Robert Lor, Neelakanth Nadgir, Raghu Pillutla, Chien-Hua Yen, Jan Van Bruaene, Bob Palowoda, Ezhilan Narasimhan, and Mei L. Chung.
| ||||||||||||||||||||||||||||||||||||||||||||||||||
|
| ||||||||||||