Sun Java Solaris Communities My SDN Account Join SDN

Article

Guide to Adding Support for Solaris OS on x86 Platform to Existing Applications Available on SPARC Platform

 
By Amjad Khan, August 2003  
Contents
 
Architectural Differences
Operating System and Other Differences
Compiler Differences
Hardware Compatibility
Technical Case Study
Acknowledgments
 
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.

 
Address
0x100
0x101
0x102
0x103
Value
0
0
01
04
 
If the system is little-endian, the integer will be stored as follows.
 
Address
0x100
0x101
0x102
0x103
Value
04
01
0
0
 
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
Applications running on Solaris systems interoperate with other systems over the network using standard network protocols that have enabled communication between big-endian and little-endian systems. However, if the applications transfer data (numeric data) over the network directly without any protocol, then an issue might arise.

Solution
Most of the modern protocols incorporate the External Data Representation (XDR) layer, which byte swaps data if needed during transfers; it is best to take advantage of these protocols.

The standard C library also provides the routines ntohl(), ntohs(), htonl(), and htons(), which convert numeric data between network byte order and host byte order. These routines are appropriately implemented on the host platform to handle the conversion between host and network byte order and should always be used to shield the application from the underlying architecture.

 
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 0X01020304 on x86 (little-endian format)

 
00000100
00000011
00000010
00000001
 
Memory address: 100 101 102 103

 
 int flagVal = 0X01020304;
 char *cptr = (char *)&flagVal;
 printf("Val is %d\n(", *cptr);
 

Solution
In the preceding example, the little-endian machine will print 4, and the big-endian machine will print 1. To make this code portable to multiplatforms, use individual character-type variables to store these values rather than using a numeric data type. Alternatively, you may use a structure variable with individual fields for every value, and get and set these values using the structure field names.

Application Data Storage
File systems are neutral to endianness in general, and swapping files between Solaris SPARC and x86 is not an issue. But applications storing raw data that can be shared between platforms would be an issue. For example, if an application on the Solaris SPARC platform writes the data structures in a raw format to the files, then the data stored in these files would be endian-dependent. Reading or writing these data files from an x86 processor-based machine can create problems regarding the endianness of the data. In short, the binary data (raw data) stored on a file is not transferable between the SPARC and x86 platforms.

Solution
Applications storing data that is shared between platforms can handle the endianness issue in one of the following two ways:

 
  • Store data in an application-defined, endian-neutral format using text files and strings.

  • Choose either the big-endian or little-endian convention and do byte swapping (potentially using enabling technology such as XDR) when necessary.
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
Sharing memory with opposite-endian devices or processors constitutes data import and export. Access to shared data must take endianness issues into account.

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
For the resolution of shared memory problems such as memory-mapped graphics adapters, the multi-byte values can be explicitly byte-swapped before storing to, or after loading from, the opposite endian device.

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
Portable code should compare the individual fields of the structure variables separately and not rely upon any sort of storage order as in the following example:

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
Most programs read and write data to the permanent storage media such as a complete structure in binary form using standard C routines. These routines need the data size that is being read or written. Due to the different alignment and data type sizes on different platforms, the structure sizes vary, and therefore the sizeof operator should be used to specify the number of bytes to read or write in these routines.

Let's say your program needs to read a record of the type MyRecord (that you know has a total of 25 bytes of data). In this case, you would not write the following:

    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
Differences in alignment of double and long double floating-point variables may cause porting problems. The SPARC processor enforces 8-byte alignment on double float variables, while the x86 processor enforces only 4-byte alignment.

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
As mentioned earlier, 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. The sizeof (BITMAP), structure, shown in the following example, is not always the same on different platforms:

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
The -fstore compiler flag minimizes these discrepancies. However, using the -fstore flag introduces a penalty in performance.

Other Issues Relating to Floating Point Operation
Some other issues and solutions include the following.

 
  • In x86 systems, each time a single or double precision floating-point number is loaded or stored in the x86 system, a conversion to or from double extended precision occurs. Loads and stores of floating-point numbers can cause exceptions. In SPARC systems, a single or double precision floating-point number is always loaded or stored as single or double precision.

    • Solution: The -fprecision initializes the rounding-precision mode bits in the floating-point control word to single (24 bits), double (53 bits), or extended (64 bits), respectively. The default floating-point rounding-precision mode is extended. Note that on x86, only the precision, not exponent, range is affected by the setting of floating-point rounding precision mode.


  • In the x86 system, gradual underflow is implemented entirely in hardware. As opposed to SPARC systems, x86 systems lack a nonstandard mode.

    • Solution: Use the option -fnonstd on x86 systems. This causes nonstandard initialization of floating-point arithmetic hardware. In addition, the -fnonstd option causes hardware traps to be enabled for floating-point overflow, division by zero, and invalid operations exceptions.


  • The fpversion utility is not provided in x86 systems. In SPARC systems, the fpversion utility distributed with the compilers identifies the installed CPU and estimates the processor and system bus clock speeds. fpversion determines the CPU and FPU types by interpreting the identification information stored by the CPU and FPU. It estimates their clock speeds by timing a loop that executes simple instructions that run in a predictable amount of time. The loop is executed many times to increase the accuracy of the timing measurements. For this reason, fpversion is not instantaneous; it can take several seconds to run. fpversion also reports the best -xtarget code generation option to use for the host system.
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:

 
  • Extended precision
  • Large dataset support
  • Large virtual address space
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
It is also possible to generate two binaries (one 32-bit and one 64-bit) from a single source file on the SPARC platform. The Solaris compilers have compile-time flags that can create a resulting object file that is 32-bit or 64-bit. 64-bit specific code in the header files and source files are defined using #ifdef as appropriate to support the single source file for both 32-bit and 64-bit.

 
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
Solaris for x86 requires auxiliary boot drivers that extend the capability of the platform BIOS. These boot drivers are called BEFs (BIOS Extension Files). Because they run in the "real mode" of the x86 processor, these boot drivers are also referred to as "realmode" drivers.

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
To jumpstart a Solaris OS x86 client you need one of the following: an already installed Solaris OS for Intel, a Solaris OS CD-ROM (and BIOS capable of booting off CD-ROM), or a Solaris Device Configuration Assistant (DCA) boot floppy. The installation is started by booting off of the appropriate device and media. The DCA is responsible for probing and configuring the devices. During an x86-based installation, the installation program automatically runs the 'kdmconfig' command. kdmconfig determines the type of keyboard, display and mouse attached to the the system. kdmconfig can determine this information interactively from the user or can obtain its configuration information from the JumpStart server or from a file.

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 cfgadm command:

 
  • USB devices on SPARC and x86 platforms
  • SCSI devices on SPARC and x86 platforms
  • PCI devices on x86 platforms
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 Solaris 7 System Administrator Collection.
 
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:

 
  • SPARC v7 combined 32-bit kernel and process address space, found on sun4c, sun4d, and sun4m series of Sun hardware.
  • SPARC v9 32-bit separated kernel and process address space, found on Sun4U systems.
  • SPARC v9 64-bit separated kernel and process address space, found on Sun4U systems.
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
Solaris Web Start, an installation program, will probably ask users if they want to format what Web Start sees as the Linux swap partition. Users should say "NO" to this. It is recommended to put the Linux swap partition on other drive. If users have ample of disk space, they may choose not to use the swap partition at all.

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:

 
  1. If Solaris and Linux are to be installed on different drives, please disconnect the drive having Solaris on it.
  2. User can change the "Partition type" of the Solaris partition. Install Linux and then change the partition type to back 0x82. This can be done using expert mode and choosing fdisk over disk druid.
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
The workaround suggested here is the use of MesaGL.

 
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
Use of MMX/SSE Instructions Set (Multimedia Instructions Set), which is available on Solaris x86, could serve as a replacement.

 
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
The Solaris Application Binary Interface (ABI) defines the interfaces that are available for the use of application developers, in order to ensure cross-release and cross-platform compatibility. Specifically, Appcert, the Solaris binary compatibility checking tool, can help to identify potential binary compatibility issues in advance.

Components of the Solaris ABI include:

 
  • Components of the Solaris ABI include:
  • Interfaces provided by the Solaris kernel system calls
  • Locations and formats of various system files and directories
  • Input and output syntax and semantics of Solaris utilities
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 OS-specific directive. On the Solaris OS, SPARC version, if a multithreaded application has a global variable that can be modified by different threads, then the __thread directive is added before the initialization of that global variable in the code, as in the following example.


__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 global_var variable for each thread on the memory stack, and no thread will modify variables of other threads.

If we try to compile the code having __thread defined in the code, it will not compile, as thread-local variables are not supported on the Solaris OS x86 compiler. However, the future release versions of Sun Studio Compiler Collection are expected to support TLS in the x86 version of the compiler.

Solution
One of the solutions for resolving the issue of thread-local variable on the x86 platform is to modify the source code wherever the global variables shared by multiple threads have been used. You can use the following POSIX and Solaris thread API calls as a replacement for manipulating thread-specific data in place of a reference to a global variable:

 
  • POSIX APIs: pthread_keycreate, pthread_getspecific, pthread_setspecific
  • Solaris APIs: thr_keycreate, thr_getspecific, thr_setspecific
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
The DDI/DKI compliant device drivers are platform-independent for machines running Solaris OS. However, sometimes developers develop the drivers that have been written without using the endianness-neutral DDI/DKI interfaces on Solaris SPARC and could cause an issue while porting to Solaris x86.

Solution
It is strongly recommended that developers avoid bypassing DDI/DKI interfaces during development of platform-independent device drivers. To maintain portability between processors and buses, DDI-compliant (Device Driver interface) drivers must be endian neutral. In some cases, the DDI framework performs the byte swapping using a software approach. In other cases, where byte swapping can be done by hardware (as in memory management unit (MMU) page-level swapping or by special machine instructions), the DDI framework will take advantage of the hardware features to improve performance.

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 mmap(9E) or devmap(9E), porting the application may require software byte swapping. The drivers can conceivably manage their endianness by runtime checks or by preprocessor directives such as the following statements in the source code:

#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
Solaris OS provides an architecture independent "device register" model. This model works on all supported buses and architectures. This model supports both memory-mapped I/O and x86 "port" I/O. A driver need not know whether it is using memory-mapped or port I/O. The same device may use MMIO on one machine and port I/O on another. A driver does not recognize the specific physical address of its device.

Data Alignment
On the SPARC processor, all data types must be aligned on their natural boundaries. Using standard C data types, integers are aligned as follows:

 
  • short integers are aligned on 16-bit boundaries.
  • int integers are aligned on 32-bit boundaries.
  • long integers are aligned on on either 32-bit boundaries or 64-bit boundaries, depending on whether the data model of the kernel is 64-bit or 32-bit.
  • long long integers are aligned on 64-bit boundaries.
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
The x86 processor does not have alignment restrictions on data type. However, the x86 processor may require some extra memory cycles to properly handle misaligned data transfers.

32-Bit and 64-Bit Issues
Issues relating to 32-bit and 64-bit technology apply to drivers as well. UltraSPARC III chips require a 64-bit kernel driver, whereas x86 processors are (primarily) 32-bit. If existing drivers are developed using the Solaris DDI/DKI and supported for the 64-bit kernel on the SPARC platform, issues are not expected when porting to Solaris x86. It is necessary to recompile the driver to run correctly in the 32-bit x86 processor.

DMA vs. DVMA
The platform that the device operates on may provide one of two types of memory access:

 
  • Direct Memory Access (DMA): The x86 platform supports DMA.
  • Direct Virtual Memory Access (DVMA): The SPARC platform supports the 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
Implementation and configuration of the 100-Mbit cards for Solaris x86 is dependent on the Network Interface card (NIC) and the driver update installed. Network adapters should be installed according to the documentation provided by the board vendor. In most cases, the network adapter is simply installed by following the vendor's instructions and Solaris will be able to access it after a kernel reconfiguration. See HCL documentation on Solaris x86 for supported NICs and additional information.

 
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:

 
  • Disk size
  • Ethernet hardware address
  • IP address
  • Bandwidth and maximum vertical frequency of video card and monitor
  • Type of mouse
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.