Appendix A: Architecture Specifics Notes

Table of Contents

Overview

kernel严格区分架构相关和架构无关代码。 include/asm-arch 目录包含头文件, arch/arc 包含源代码。

架构相关基本分为两类:

  • 架构相关独有调用的部分
  • 架构无关调用的接口部分由各自架构定义。

Data types

内核在如下3个基本数据类型重做一些基本区别:

  • 在C程序中标准的数据类型;如unsigned long,void *和char。
  • 固定比特数的数据类型。定义在 <asm-arch/types.h>
typedef __signed__ char __s8; 
typedef unsigned char __u8;

typedef __signed__ short __s16;
typedef unsigned short __u16;

typedef __signed__ int __s32;
typedef unsigned int __u32;

typedef signed char s8;
typedef unsigned char u8;

typedef signed short s16;
typedef unsigned short u16;

typedef signed int s32;
typedef unsigned int u32;

typedef signed long long s64;
typedef unsigned long long u64;
  • 不会直接使用的子系统特有的类型,但经常被特有的函数所用。比如类型 pidt用来处理pids和sectort用来指明扇区数。

The pre-processor constant __KERNEL__ must always be defined before the file is linked into the kernel source.

Alignment

在内核的某些地方可能需要处理非对齐数据类型。为了这目的,不同的体系需要定义2个不同的宏(在 <asm-arch/unaligned.h> ):

  • getunaligned(ptr)
  • putunaligned(val, ptr)

Memory Pages

asm-arch/page.h to indicate the page size used:

  • PAGESHIFT 页大小的指数
  • PAGESIZE in bytes
  • PAGEALIGN(addr) 使地址对齐页面
  • clearpage(start) 填充null已删除以start开始的页
  • copypage(to. from) 拷贝页数据从from到to

example:

#define PAGE_SHIFT      12
#ifdef __ASSEMBLY__
#define PAGE_SIZE       (1 << PAGE_SHIFT)
#else
#define PAGE_SIZE       (1UL << PAGE_SHIFT)
#endif
#define PAGE_MASK       (~(PAGE_SIZE-1))

System Calls

促发一个system call从用户空间转化到内核空间机制有区别在支持的平台上。 <asm-arch/unistd.h>

  • It defines pre-processor constants to link the descriptors of all system calls with symbolic constants.
  • It defines functions to invoke system calls from within the kernel itself.

String Processing

<asm-arch/string.h>

The _HAVEARCHOPERATION macro must be set for each string operation that is defined as optimized by an architecture; for instance, _HAVEARCHMEMCPY must be set for memcpy. All nonimplemented functions are replaced with architecture-independent standard operations that are implemented in lib/string.c.

Thread Representation

The state of a running process is defined primarily by the contents of the processor registers. Processes that are not currently running must keep this data in corresponding data structures from which the data can be read and moved to the appropriate registers when the process is next activated by the scheduler.

  • <asm-arch/ptrace.h> provides the ptregs structure to hold all registers that are placed on the kernel stack when the process switches from user mode to space mode as a result of a system call, an interrupt, or any other mechanism.
  • <asm-arch/processor.h> accommodates the threadstruct structure used to describe all other registers and all other task state information.
  • <asm-arch/thread.h> defines the threadinfo structure (not to be confused with threadstruct), which contains all task structure elements that the assembler code must access to implement kernel entry and exit.

ARM

The following definition of the ptregs structure consists simply of an array to hold the values of all registers manipulated in kernel mode: include/asm-arm/ptrace.h

/*
 * This struct defines the way the registers are stored on the
 * stack during a system call.  Note that sizeof(struct pt_regs)
 * has to be a multiple of 8.
 */
struct pt_regs {
        long uregs[18];
};

The symbolic names of the registers and their positions within the array are defined by means of pre- processor constants: include/asm-arm/ptrace.h

#define ARM_cpsr        uregs[16]
#define ARM_pc          uregs[15]
#define ARM_lr          uregs[14]
#define ARM_sp          uregs[13]
#define ARM_ip          uregs[12]
#define ARM_fp          uregs[11]
#define ARM_r10         uregs[10]
#define ARM_r9          uregs[9]
#define ARM_r8          uregs[8]
#define ARM_r7          uregs[7]
#define ARM_r6          uregs[6]
#define ARM_r5          uregs[5]
#define ARM_r4          uregs[4]
#define ARM_r3          uregs[3]
#define ARM_r2          uregs[2]
#define ARM_r1          uregs[1]
#define ARM_r0          uregs[0]
#define ARM_ORIG_r0     uregs[17]

include/asm-arm/processor.h

struct thread_struct {
                                                        /* fault info     */
        unsigned long           address;
        unsigned long           trap_no;
        unsigned long           error_code;
                                                        /* debugging      */
        struct debug_info       debug;
};

However, machine instructions (in the form of their opcode) can be saved together with a memory address for debugging purposes, as shown here: include/asm-arm/processor.h

union debug_insn {
        u32     arm;
        u16     thumb;
};

struct debug_entry {
        u32                     address;
        union debug_insn        insn;
};

struct debug_info {
        int                     nsaved;
        struct debug_entry      bp[2];
};

Bit Operations and Endianness

Manipulation of Bit Chains

内核中架构相关的比特处理在 <asmm-arch/bitops.h>

void set_bit(int nr, volatile unsigned long * addr) sets the bit at position nr; counting begins at addr.

int test_bit(int nr, const volatile unsigned long * addr) checks whether the specified bit is set.

void clear_bit(int nr, volatile unsigned long * addr) deletes the bit at position nr (count- ing begins at addr).
....

所有这些是原子函数,锁的陈述在相关汇编代码内。这些函数的非原子版本,以双下划线前缀。(_setbit).

Conversion between Byte Orders

The kernel provides the <byteorder/little_endian.h> and <byteorder/big_endian.h> files. The version for the current processor is linked into <asm-arch/byteorder.h>.

C default functions are defined in <byteoorder/swab.h>, but they can be overwritten by a processor-specific implementation. _arch_swab16, _arch_swab32, and _arch_swab64 swap the bytes between the representations, and therefore convert big endian to little endian and vice versa. _swab16p, _arch_swab32p, and _arch_swab64p do the same for pointer variables. swab stands for swap bytes.

<byteorder/little_endian.h>

#define __constant_htonl(x) ((__force __be32)___constant_swab32((x)))
#define __constant_ntohl(x) ___constant_swab32((__force __be32)(x))
#define __constant_htons(x) ((__force __be16)___constant_swab16((x)))
#define __constant_ntohs(x) ___constant_swab16((__force __be16)(x))
#define __constant_cpu_to_le64(x) ((__force __le64)(__u64)(x))
#define __constant_le64_to_cpu(x) ((__force __u64)(__le64)(x))
#define __constant_cpu_to_le32(x) ((__force __le32)(__u32)(x))
#define __constant_le32_to_cpu(x) ((__force __u32)(__le32)(x))
#define __constant_cpu_to_le16(x) ((__force __le16)(__u16)(x))
#define __constant_le16_to_cpu(x) ((__force __u16)(__le16)(x))
#define __constant_cpu_to_be64(x) ((__force __be64)___constant_swab64((x)))
#define __constant_be64_to_cpu(x) ___constant_swab64((__force __u64)(__be64)(x))
#define __constant_cpu_to_be32(x) ((__force __be32)___constant_swab32((x)))
#define __constant_be32_to_cpu(x) ___constant_swab32((__force __u32)(__be32)(x))
#define __constant_cpu_to_be16(x) ((__force __be16)___constant_swab16((x)))
#define __constant_be16_to_cpu(x) ___constant_swab16((__force __u16)(__be16)(x))
#define __cpu_to_le64(x) ((__force __le64)(__u64)(x))
#define __le64_to_cpu(x) ((__force __u64)(__le64)(x))
#define __cpu_to_le32(x) ((__force __le32)(__u32)(x))
#define __le32_to_cpu(x) ((__force __u32)(__le32)(x))
#define __cpu_to_le16(x) ((__force __le16)(__u16)(x))
#define __le16_to_cpu(x) ((__force __u16)(__le16)(x))
#define __cpu_to_be64(x) ((__force __be64)__swab64((x)))
#define __be64_to_cpu(x) __swab64((__force __u64)(__be64)(x))
#define __cpu_to_be32(x) ((__force __be32)__swab32((x)))
#define __be32_to_cpu(x) __swab32((__force __u32)(__be32)(x))
#define __cpu_to_be16(x) ((__force __be16)__swab16((x)))
#define __be16_to_cpu(x) __swab16((__force __u16)(__be16)(x))

Page Tables

To simplify memory management and to provide a memory model that abstracts the differences between the various architectures, the ports must offer functions to manipulate page tables and their entries. These are declared in <asm-arch/pgtable.h>.

Miscellaneous

Checksum Calculation

为包算checksums是IP网络中一个关键的算法时间。实现在 <asm-arch/checksum.h>

unsigned short ip_fast_csum calculates the requisite checksum based on the IP header and the header length.

csum_partial calculates the checksum for a packet from the fragments that are received one by one.

Context Switch

<asm-arch/system.h>

void switch_to(struct task_struct *prev, struct task_struct *next, struct task_struct *last)

Finding the Current Process

The purpose of the current macro is to find a pointer to the task structure of the currently running process. It must be declared by each architecture in <asm-arch/current.h>.

Arm architecture: include/asm-arm/current.h

static __always_inline struct task_struct * get_current(void)
{
  return current_thread_info()->task;
}
#define current get_current()

The pointer to the current thread_info instance found using current_thread_info is stored in register sp, as shown here:

include/asm-arm/thread_info.h

static inline struct thread_info *current_thread_info(void)
{
  register unsigned long sp asm ("sp");
  return (struct thread_info *)(sp & ~(THREAD_SIZE - 1));
}

Author: Shi Shougang

Created: 2015-03-05 Thu 23:21

Emacs 24.3.1 (Org mode 8.2.10)

Validate