The 64-bit kernel uses the LP64 (Long Pointer 64-bit) C language data model and requires kernel extensions to do the same. The LP64 data model defines pointers, long, and long long types as 64 bits, int as 32 bits, short as 16 bits, and char as 8 bits. In contrast, the 32-bit kernel uses the ILP32 data model, which differs from LP64 in that long and pointer types are 32 bits.
In order to port an existing 32-bit kernel extension to the 64-bit kernel environment, source code must be modified to be type-safe under LP64. This means ensuring that data types are used in a consistent fashion. Source code is incorrect for the 64-bit environment if it assumes that pointers, long, and int are all the same size.
In addition, the use of system-derived types must be examined whenever values are passed from an application to the kernel. For example, size_t is a system-derived type whose size depends on the compilation mode, and key_t is a system-derived type that is 64 bits in the 64-bit kernel environment, and 32 bits otherwise.
In cases where 32-bit and 64-bit versions of a kernel extension are to be generated from a single source base, the kernel extension must be made type-safe for both the LP64 and ILP32 data models. To facilitate this, the sys/types.h and sys/inttypes.h header files contain fixed-width system-derived types, constants, and macros. For example, the int8_t, int16_t, int32_t, int64_t fixed-width types are provided along with constants that specify their maximum values.
Several global, exported kernel data structures have been changed in the 64-bit kernel, in order to support scalability and future functionality. These changes include larger structure sizes as a result of being compiled under the LP64 data model. In porting a kernel extension to the 64-bit kernel environment, these data structure changes must be considered.
Function prototypes are more important in the 64-bit programming environment than the 32-bit programming environment, because the default return value of an undeclared function is int. If a function prototype is missing for a function returning a pointer, the compiler will convert the returned value to an int by setting the high-order word to 0, corrupting the value. In addition, function prototypes allow the compiler to do more type checking, regardless of the compilation mode.
When compiled in 64-bit mode, system header files define full function prototypes for all kernel services provided by the 64-bit kernel. By defining the __FULL_PROTO macro, function prototypes are provided in 32-bit mode as well. It is recommended that function prototypes be provided by including the system header files, instead of providing a prototype in a source file.
To compile a kernel extension in 64-bit mode, the -q64 flag must be used. To check for missing function prototypes, -qinfo=pro can be specified. To compile in ANSI mode, use the -qlanglvl=ansi flag. When this flag is used, additional error checking will be performed by the compiler. To link-edit a kernel extension, the -b64 option must be used with the ld command.
When compiling in 64-bit mode, the compiler automatically defines the macro __64BIT__. Kernel extensions should always be compiled with the _KERNEL macro defined, and if sys/types.h is included, the macro __64BIT_KERNEL will be defined for kernel extensions being compiled in 64-bit mode. The __64BIT_KERNEL macro can be used to provide for conditional compilation when compiling kernel extensions from common source code.
Kernel extensions should not be compiled with the _KERNSYS macro defined. If this macro is defined, the resulting kernel extension will not be supported, and binary compatibility will not be assured with future releases.
The libcsys.a and libsys.a libraries are supported for both 32- and 64-bit kernel extensions. Each archive contains 32- and 64-bit members. Function prototypes for all the functions in libcsys.a are found in sys/libcsys.h.
Within the 64-bit kernel, all kernel mode subsystems, including kernel extensions, run exclusively in 64-bit processor mode and are capable of accessing data or executing instructions at any location within the kernel's 64-bit address space, including those found above the first 4GBs of this address space. This availability of the full 64-bit address space extends to all kernel entities, including kprocs and interrupt handlers, and enables the potential for software resource scalability through the introduction of an enormous kernel address space.
The 64-bit kernel provides a common user and kernel 64-bit address space. This is different from the 32-bit kernel where separate 32-bit kernel and user address spaces exist.
The kernel address space has a different organization under the the 64-bit kernel than under the 32-bit kernel and extends beyond the 4 GB line. In addition, the organization of kernel space under the 64-bit kernel can differ between hardware systems. To cope with this, kernel extensions must not have any dependencies on the locations, relative or absolute, of the kernel text, kernel global data, kernel heap data, and kernel stack values, and must appropriately type variables used to hold kernel addresses.
The 64-bit kernel provides kernel extensions with the capability to temporarily attach virtual memory segments to the kernel space for the current thread of kernel mode execution. This capability is also available on the 32-bit kernel, and is provided through the vm_att and vm_det services.
A total of four concurrent temporary attaches will be supported under a single thread of execution.
The 64-bit kernel provides kernel extensions with the capability to create global regions within the kernel address space. Once created, a region is globally accessible to all kernel code until it is destroyed. Regions may be created with unique characteristics, for example, page protection, that suit kernel extension requirements and are different from the global virtual memory allocated from the kernel_heap.
Global regions are also useful for kernel extensions that in the past have organized their data around virtual memory segments and require sizes and alignments that are inappropriate for the kernel heap. Under the 64-bit kernel, this memory can be provided through global regions rather than separate virtual memory segments, thus avoiding the complexity and performance cost of temporarily attaching virtual memory segments.
Global regions are created and destroyed with the vm_galloc and vm_gfree kernel services.