Linux的初始內核解壓-概述,解壓,內核-北方網-IT浪潮

2021-01-11 北方網

  概述

  1)Linux的初始內核映象以gzip壓縮文件的格式存放在zImage或bzImage之中,內核的自舉代碼將它解壓到1M內存開始處.在內核初始化時,如果加載了壓縮的initrd映象,內核會將它解壓到內存檔中,這兩處解壓過程都使用了lib/inflate.c文件.

  2)inflate.c是從gzip源程序中分離出來的,包含了一些對全局數據的直接引用,在使用時需要直接嵌入到代碼中.gzip壓縮文件時總是在前32K字節的範圍內尋找重複的字符串進行編碼,在解壓時需要一個至少為32K字節的解壓緩衝區,它定義為window[WSIZE].inflate.c使用get_byte()讀取輸入文件,它被定義成宏來提高效率.輸入緩衝區指針必須定義為inptr, inflate.c中對之有減量操作.inflate.c調用flush_window()來輸出window緩衝區中的解壓出的字節串,每次輸出長度用outcnt變量表示.在flush_window()中,還必須對輸出字節串計算CRC並且刷新crc變量.在調用gunzip()開始解壓之前,調用makecrc()初始化CRC計算表.最後gunzip()返回0表示解壓成功.

  3)zImage或bzImage由16位引導代碼和32位內核自解壓映象兩個部分組成.對於zImage,內核自解壓映象被加載到物理地址0x1000,內核被解壓到1M的部位.對於bzImage,內核自解壓映象被加載到1M開始的地方,內核被解壓為兩個片段,一個起始於物理地址0x2000-0x90000,另一個起始於高端解壓映象之後,離1M開始處不小於低端片段最大長度的區域.解壓完成後,這兩個片段被合併到1M的起始位置.

  解壓根內存檔映象文件的代碼

  -

  ; drivers/block/rd.c

  #ifdef BUILD_CRAMDISK

  /*

  * gzip declarations

  */

  #define OF(args) args ; 用於函數原型聲明的宏

  #ifndef memzero

  #define memzero(s, n) memset ((s), 0, (n))

  #endif

  typedef unsigned char uch;定義inflate.c所使用的3種數據類型

  typedef unsigned short ush;

  typedef unsigned long ulg;

  #define INBUFSIZ 4096用戶輸入緩衝區尺寸

  #define WSIZE 0x8000 /* window size--must be a power of two, and */

  /* at least 32K for zip's deflate method */

  static uch *inbuf;用戶輸入緩衝區,與inflate.c無關

  static uch *window;解壓窗口

  static unsigned insize; /* valid bytes in inbuf */

  static unsigned inptr; /* index of next byte to be processed in inbuf */

  static unsigned outcnt; /* bytes in output buffer */

  static int exit_code;

  static long bytes_out;總解壓輸出長度,與inflate.c無關

  static struct file *crd_infp, *crd_outfp;

  #define get_byte() (inptr

  /* Diagnostic functions (stubbed out) */一些調試宏

  #define Assert(cond,msg)

  #define Trace(x)

  #define Tracev(x)

  #define Tracevv(x)

  #define Tracec(c,x)

  #define Tracecv(c,x)

  #define STATIC static

  static int fill_inbuf(void);

  static void flush_window(void);

  static void *malloc(int size);

  static void free(void *where);

  static void error(char *m);

  static void gzip_mark(void **);

  static void gzip_release(void **);

  #include "../../lib/inflate.c"

  static void __init *malloc(int size)

  {

  return kmalloc(size, GFP_KERNEL);

  }

  static void __init free(void *where)

  {

  kfree(where);

  }

  static void __init gzip_mark(void **ptr)

  {

  ;讀取用戶一個標記

  }

  static void __init gzip_release(void **ptr)

  {

  ;歸還用戶標記

  }

  /* ===========================================================================

  * Fill the input buffer. This is called only when the buffer is empty

  * and at least one byte is really needed.

  */

  static int __init fill_inbuf(void)填充輸入緩衝區

  {

  if (exit_code) return -1;

  insize = crd_infp->f_op->read(crd_infp, inbuf, INBUFSIZ,

  if (insize == 0) return -1;

  inptr = 1;

  return inbuf[0];

  }

  /* ===========================================================================

  * Write the output window window[0..outcnt-1] and update crc and bytes_out.

  * (Used for the decompressed data only.)

  */

  static void __init flush_window(void)輸出window緩衝區中outcnt個字節串

  {

  ulg c = crc; /* temporary variable */

  unsigned n;

  uch *in, ch;

  crd_outfp->f_op->write(crd_outfp, window, outcnt,

  in = window;

  for (n = 0; n ch = *in++;

  c = crc_32_tab[((int)c ^ ch) 0xff] ^ (c >> 8);計算輸出串的CRC

  }

  crc = c;

  bytes_out += (ulg)outcnt;刷新總字節數

  outcnt = 0;

  }

  static void __init error(char *x)解壓出錯調用的函數

  {

  printk(KERN_ERR "%s", x);

  exit_code = 1;

  }

  static int __init

  crd_load(struct file * fp, struct file *outfp)

  {

  int result;

  insize = 0; /* valid bytes in inbuf */

  inptr = 0; /* index of next byte to be processed in inbuf */

  outcnt = 0; /* bytes in output buffer */

  exit_code = 0;

  bytes_out = 0;

  crc = (ulg)0xffffffffL; /* shift register contents */

  crd_infp = fp;

  crd_outfp = outfp;

  inbuf = kmalloc(INBUFSIZ, GFP_KERNEL);

  if (inbuf == 0) {

  printk(KERN_ERR "RAMDISK: Couldn't allocate gzip buffer\n");

  return -1;

  }

  window = kmalloc(WSIZE, GFP_KERNEL);

  if (window == 0) {

  printk(KERN_ERR "RAMDISK: Couldn't allocate gzip window\n");

  kfree(inbuf);

  return -1;

  }

  makecrc();

  result = gunzip();

  kfree(inbuf);

  kfree(window);

  return result;

  }

  #endif /* BUILD_CRAMDISK */

  32位內核自解壓代碼

  ---

  ; arch/i386/boot/compressed/head.S

  .text

  #include ·

  #include

  .globl startup_32對於zImage該入口地址為0x1000;對於bzImage為0x101000

  startup_32:

  cld

  cli

  movl $(__KERNEL_DS),%eax

  movl %eax,%ds

  movl %eax,%es

  movl %eax,%fs

  movl %eax,%gs

  lss SYMBOL_NAME(stack_start),%esp # 自解壓代碼的堆棧為misc.c中定義的16K字節的數組

  xorl %eax,%eax

  1: incl %eax # check that A20 really IS enabled

  movl %eax,0x000000 # loop forever if it isn't

  cmpl %eax,0x100000

  je 1b

  /*

  * Initialize eflags. Some BIOS's leave bits like NT set. This would

  * confuse the debugger if this code is traced.

  * XXX - best to initialize before switching to protected mode.

  */

  pushl $0

  popfl

  /*

  * Clear BSS清除解壓程序的BSS段

  */

  xorl %eax,%eax

  movl $ SYMBOL_NAME(_edata),%edi

  movl $ SYMBOL_NAME(_end),%ecx

  subl %edi,%ecx

  cld

  rep

  stosb

  /*

  * Do the decompression, and jump to the new kernel..

  */

  subl $16,%esp # place for structure on the stack

  movl %esp,%eax

  pushl %esi # real mode pointer as second arg

  pushl %eax # address of structure as first arg

  call SYMBOL_NAME(decompress_kernel)

  orl %eax,%eax # 如果返回非零,則表示為內核解壓為低端和高端的兩個片斷

  jnz 3f

  popl %esi # discard address

  popl %esi # real mode pointer

  xorl %ebx,%ebx

  ljmp $(__KERNEL_CS), $0x100000 # 運行start_kernel

  /*

  * We come here, if we were loaded high.

  * We need to move the move-in-place routine down to 0x1000

  * and then start it with the buffer addresses in registers,

  * which we got from the stack.

  */

  3:

  movl $move_routine_start,%esi

  movl $0x1000,%edi

  movl $move_routine_end,%ecx

  subl %esi,%ecx

  addl $3,%ecx

  shrl $2,%ecx # 按字取整

  cld

  rep

  movsl # 將內核片斷合併代碼複製到0x1000區域,內核的片段起始為0x2000

  popl %esi # discard the address

  popl %ebx # real mode pointer

  popl %esi # low_buffer_start內核低端片段的起始地址

  popl %ecx # lcount內核低端片段的字節數量

  popl %edx # high_buffer_start內核高端片段的起始地址

  popl %eax # hcount內核高端片段的字節數量

  movl $0x100000,%edi內核合併的起始地址

  cli # make sure we don't get interrupted

  ljmp $(__KERNEL_CS), $0x1000 # and jump to the move routine

  /*

  * Routine (template) for moving the decompressed kernel in place,

  * if we were high loaded. This _must_ PIC-code !

  */

  move_routine_start:

  movl %ecx,%ebp

  shrl $2,%ecx

  rep

  movsl # 按字拷貝第1個片段

  movl %ebp,%ecx

  andl $3,%ecx

  rep

  movsb # 傳送不完全字

  movl %edx,%esi

  movl %eax,%ecx # NOTE: rep movsb won't move if %ecx == 0

  addl $3,%ecx

  shrl $2,%ecx # 按字對齊

  rep

  movsl # 按字拷貝第2個片段

  movl %ebx,%esi # Restore setup pointer

  xorl %ebx,%ebx

  ljmp $(__KERNEL_CS), $0x100000 # 運行start_kernel

  move_routine_end:

  ; arch/i386/boot/compressed/misc.c

  /*

  * gzip declarations

  */

  #define OF(args) args

  #define STATIC static

  #undef memset

  #undef memcpy

  #define memzero(s, n) memset ((s), 0, (n))

  ypedef unsigned char uch;

  typedef unsigned short ush;

  typedef unsigned long ulg;

  #define WSIZE 0x8000 /* Window size must be at least 32k, */

  /* and a power of two */

  static uch *inbuf; /* input buffer */

  static uch window[WSIZE]; /* Sliding window buffer */

  static unsigned insize = 0; /* valid bytes in inbuf */

  static unsigned inptr = 0; /* index of next byte to be processed in inbuf */

  static unsigned outcnt = 0; /* bytes in output buffer */

  /* gzip flag byte */

  #define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */

  #define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */

  #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */

  #define ORIG_NAME 0x08 /* bit 3 set: original file name present */

  #define COMMENT 0x10 /* bit 4 set: file comment present */

  #define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */

  #define RESERVED 0xC0 /* bit 6,7: reserved */

  #define get_byte() (inptr

  /* Diagnostic functions */

  #ifdef DEBUG

  # define Assert(cond,msg) {if(!(cond)) error(msg);}

  # define Trace(x) fprintf x

  # define Tracev(x) {if (verbose) fprintf x ;}

  # define Tracevv(x) {if (verbose>1) fprintf x ;}

  # define Tracec(c,x) {if (verbose (c)) fprintf x ;}

  # define Tracecv(c,x) {if (verbose>1 (c)) fprintf x ;}

  #else

  # define Assert(cond,msg)

  # define Trace(x)

  # define Tracev(x)

  # define Tracevv(x)

  # define Tracec(c,x)

  # define Tracecv(c,x)

  #endif

  static int fill_inbuf(void);

  static void flush_window(void);

  static void error(char *m);

  static void gzip_mark(void **);

  static void gzip_release(void **);

  /*

  * This is set up by the setup-routine at boot-time

  */

  static unsigned char *real_mode; /* Pointer to real-mode data */

  #define EXT_MEM_K (*(unsigned short *)(real_mode + 0x2))

  #ifndef STANDARD_MEMORY_BIOS_CALL

  #define ALT_MEM_K (*(unsigned long *)(real_mode + 0x1e0))

  #endif

  #define SCREEN_INFO (*(struct screen_info *)(real_mode+0))

  extern char input_data[];

  extern int input_len;

  static long bytes_out = 0;

  static uch *output_data;

  static unsigned long output_ptr = 0;

  static void *malloc(int size);

  static void free(void *where);

  static void error(char *m);

  static void gzip_mark(void **);

  static void gzip_release(void **);

  static void puts(const char *);

  extern int end;

  static long free_mem_ptr = (long)

  static long free_mem_end_ptr;

  #define INPLACE_MOVE_ROUTINE 0x1000內核片段合併代碼的運行地址

  #define LOW_BUFFER_START 0x2000內核低端解壓片段的起始地址

  #define LOW_BUFFER_MAX 0x90000內核低端解壓片段的終止地址

  #define HEAP_SIZE 0x3000為解壓低碼保留的堆的尺寸,堆起始於BSS的結束

  static unsigned int low_buffer_end, low_buffer_size;

  static int high_loaded =0;

  static uch *high_buffer_start /* = (uch *)(((ulg) + HEAP_SIZE)*/;

  static char *vidmem = (char *)0xb8000;

  static int vidport;

  static int lines, cols;

  #include "../../../../lib/inflate.c"

  static void *malloc(int size)

  {

  void *p;

  if (size if (free_mem_ptr

  free_mem_ptr = (free_mem_ptr + 3) ~3; /* Align */

  p = (void *)free_mem_ptr;

  free_mem_ptr += size;

  if (free_mem_ptr >= free_mem_end_ptr)

  error("\nOut of memory\n");

  return p;

  }

  static void free(void *where)

  { /* Don't care */

  }

  static void gzip_mark(void **ptr)

  {

  *ptr = (void *) free_mem_ptr;

  }

  static void gzip_release(void **ptr)

  {

  free_mem_ptr = (long) *ptr;

  }

  static void scroll(void)

  {

  int i;

  memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 );

  for ( i = ( lines - 1 ) * cols * 2; i vidmem[ i ] = ' ';

  }

  static void puts(const char *s)

  {

  int x,y,pos;

  char c;

  x = SCREEN_INFO.orig_x;

  y = SCREEN_INFO.orig_y;

  while ( ( c = *s++ ) != '\0' ) {

  if ( c == '\n' ) {

  x = 0;

  if ( ++y >= lines ) {

  scroll();

  y--;

  }

  } else {

  vidmem [ ( x + cols * y ) * 2 ] = c;

  if ( ++x >= cols ) {

  x = 0;

  if ( ++y >= lines ) {

  scroll();

  y--;

  }

  }

  }

  }

  SCREEN_INFO.orig_x = x;

  SCREEN_INFO.orig_y = y;

  pos = (x + cols * y) * 2; /* Update cursor position */

  outb_p(14, vidport);

  outb_p(0xff (pos >> 9), vidport+1);

  outb_p(15, vidport);

  outb_p(0xff (pos >> 1), vidport+1);

  }

  void* memset(void* s, int c, size_t n)

  {

  int i;

  char *ss = (char*)s;

  for (i=0;i return s;

  }

  void* memcpy(void* __dest, __const void* __src,

  size_t __n)

  {

  int i;

  char *d = (char *)__dest, *s = (char *)__src;

  for (i=0;i return __dest;

  }

  /* ===========================================================================

  * Fill the input buffer. This is called only when the buffer is empty

  * and at least one byte is really needed.

  */

  static int fill_inbuf(void)

  {

  if (insize != 0) {

  error("ran out of input data\n");

  }

  inbuf = input_data;

  insize = input_len;

  inptr = 1;

  return inbuf[0];

  }

  /* ===========================================================================

  * Write the output window window[0..outcnt-1] and update crc and bytes_out.

  * (Used for the decompressed data only.)

  */

  static void flush_window_low(void)

  {

  ulg c = crc; /* temporary variable */

  unsigned n;

  uch *in, *out, ch;

  in = window;

  out =

  for (n = 0; n ch = *out++ = *in++;

  c = crc_32_tab[((int)c ^ ch) 0xff] ^ (c >> 8);

  }

  crc = c;

  bytes_out += (ulg)outcnt;

  output_ptr += (ulg)outcnt;

  outcnt = 0;

  }

  static void flush_window_high(void)

  {

  ulg c = crc; /* temporary variable */

  unsigned n;

  uch *in, ch;

  in = window;

  for (n = 0; n ch = *output_data++ = *in++;

  if ((ulg)output_data == low_buffer_end) output_data=high_buffer_start;

  c = crc_32_tab[((int)c ^ ch) 0xff] ^ (c >> 8);

  }

  crc = c;

  bytes_out += (ulg)outcnt;

  outcnt = 0;

  }

  static void flush_window(void)

  {

  if (high_loaded) flush_window_high();

  else flush_window_low();

  }

  static void error(char *x)

  {

  puts("\n\n");

  puts(x);

  puts("\n\n -- System halted");

  while(1); /* Halt */

  }

  #define STACK_SIZE (4096)

  long user_stack [STACK_SIZE];

  struct {

  long * a;

  short b;

  } stack_start = { user_stack [STACK_SIZE] , __KERNEL_DS };

  void setup_normal_output_buffer(void)對於zImage,直接解壓到1M

  {

  #ifdef STANDARD_MEMORY_BIOS_CALL

  if (EXT_MEM_K #else

  if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) #endif

  output_data = (char *)0x100000; /* Points to 1M */

  free_mem_end_ptr = (long)real_mode;

  }

  struct moveparams {

  uch *low_buffer_start; int lcount;

  uch *high_buffer_start; int hcount;

  };

  void setup_output_buffer_if_we_run_high(struct moveparams *mv)

  {

  high_buffer_start = (uch *)(((ulg) + HEAP_SIZE);內核高端片段的最小起始地址

  #ifdef STANDARD_MEMORY_BIOS_CALL

  if (EXT_MEM_K #else

  if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) #endif

  mv->low_buffer_start = output_data = (char *)LOW_BUFFER_START;

  low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX

  ? LOW_BUFFER_MAX : (unsigned int)real_mode) ~0xfff;

  low_buffer_size = low_buffer_end - LOW_BUFFER_START;

  high_loaded = 1;

  free_mem_end_ptr = (long)high_buffer_start;

  if ( (0x100000 + low_buffer_size) > ((ulg)high_buffer_start)) {

  ;如果高端片段的最小起始地址小於它實際應加載的地址,則將它置為實際地址,

  ;這樣高端片段就無需再次移動了,否則它要向前移動

  high_buffer_start = (uch *)(0x100000 + low_buffer_size);

  mv->hcount = 0; /* say: we need not to move high_buffer */

  }

  else mv->hcount = -1;待定

  mv->high_buffer_start = high_buffer_start;

  }

  void close_output_buffer_if_we_run_high(struct moveparams *mv)

  {

  if (bytes_out > low_buffer_size) {

  mv->lcount = low_buffer_size;

  if (mv->hcount)

  mv->hcount = bytes_out - low_buffer_size;求出高端片段的字節數

  } else { 如果解壓後內核只有低端的一個片段

  mv->lcount = bytes_out;

  mv->hcount = 0;

  }

  }

  int decompress_kernel(struct moveparams *mv, void *rmode)

  {

  real_mode = rmode;

  if (SCREEN_INFO.orig_video_mode == 7) {

  vidmem = (char *) 0xb0000;

  vidport = 0x3b4;

  } else {

  vidmem = (char *) 0xb8000;

  vidport = 0x3d4;

  }

  lines = SCREEN_INFO.orig_video_lines;

  cols = SCREEN_INFO.orig_video_cols;

  if (free_mem_ptr else setup_output_buffer_if_we_run_high(mv);

  makecrc();

  puts("Uncompressing Linux... ");

  gunzip();

  puts("Ok, booting the kernel.\n");

  if (high_loaded) close_output_buffer_if_we_run_high(mv);

  return high_loaded;

  }

相關焦點

  • Linux下文件(文件夾)的壓縮和解壓
    前言在linux下,當我們上傳一個較大的文件或者要安裝一個軟體(如tomcat、mysql等)時,我們需要先將官網下載的壓縮包在linux伺服器上進行解壓,再進行安裝。如果是由程序包生成的一個目錄內容較多或較大時,我們還可能需要對某個文件夾需要壓縮,這就需要用到我們本節要介紹的內容,文件(文件夾)的壓縮和解壓。
  • ARM開發板上uClinux內核移植
    本文引用地址:http://www.eepw.com.cn/article/152110.htm2.Bootloader2.1Bootloader概述Boot Loader 就是在作業系統內核運行之前運行的一段程序。
  • Linux2.6內核驅動移植參考
    作者:晏渭川 隨著Linux2.6的發布,由於2.6內核做了教的改動,各個設備的驅動程序在不同程度上要 進行改寫。為了方便各位Linux愛好者我把自己整理的這分文檔share出來。該文當列舉 了2.6內核同以前版本的絕大多數變化,可惜的是由於時間和精力有限沒有詳細列出各個 函數的用法。
  • 升級Ubuntu Linux 內核的幾種不同方法
    這個指南裡介紹了 7 種為 Ubuntu 升級 Linux 內核的不同方法。這 7 種方法裡,有 5 種需要重啟系統來使新內核生效,其他兩種則不用。-- Sk這個指南裡介紹了 7 種為 Ubuntu 升級 Linux 內核的不同方法。這 7 種方法裡,有 5 種需要重啟系統來使新內核生效,其他兩種則不用。
  • 嵌入式Linux開發環境的搭建之:嵌入式開發環境的搭建
    搭建交叉編譯環境的方法很多,不同的體系結構、不同的操作內容甚至是不同版本的內核,都會用到不同的交叉編譯器,而且,有些交叉編譯器經常會有部分的bug,這都會導致最後的代碼無法正常地運行。因此,選擇合適的交叉編譯器對於嵌入式開發是非常重要的。
  • 一張圖看懂Linux內核中Percpu變量的實現
    但你知道嗎,不僅是在程式語言中,在linux內核中,也有一個類似的機制,用來實現類似的目的,它叫做percpu變量。percpu變量,顧名思義,就是對於同一個變量,每個cpu都有自己的一份,它可以被用來存放一些cpu獨有的數據,比如cpu的id,cpu上正在運行的線程等等,因該機制可以非常方便的解決一些特定問題,所以在內核編程中被廣泛使用。
  • Linux GUI子系統概述 GUI子系統的構成及工作流程
    Linux GUI子系統概述 GUI子系統的構成及工作流程 Nick 發表於 2020-12-05 10:45:54 作者:Nick 開始前的幾點說明
  • ARM64 Linux 內核頁表的塊映射
    作者 | 宋寶華 責編 | 張文頭圖 | CSDN 下載自視覺中國內核文檔 Documentation/arm64/memory.rst 描述了 ARM64 Linux 內核空間的內存映射情況,應該是此方面最權威文檔。
  • 在Linux下用gdb檢測內核rootkit
    更改系統調用表 當前的系統調用地址保存在系統調用表中,位於作業系統為內核保留的內存空間(虛擬地址最高1GB),系統調用入口地址的存放順序同/usr/include/asm/unistd.h中的排列順序,按系統調用號遞增。
  • Linux系統的Linux應該怎麼讀?正確讀法在這裡,很多人都讀錯了!
    3、有人綜合網上和linux自己的讀音,概括出幾個自認為最合適也最通用的讀法:/li'n^ks/(「裡那克斯」)或/'li:nэks/(「裡訥克斯」)或/li'nju:ks/(「裡紐克斯」)。4、這幾個應該是誰都聽得懂的。至於哪個比較正宗,當然是linux的原因。但事實上使用linux哪種讀法的人似乎都不在少數。
  • Linux基礎命令之:實驗內容及小結
    本文引用地址:http://www.eepw.com.cn/article/257155.htm2.4實驗內容2.4.1在Linux下解壓常見軟體在Linux下安裝一個完整的軟體(嵌入式Linux的必備工具——交叉編譯工具),掌握Linux常見命令
  • 從RTOS到Linux的應用移植
    而外設I/O資源是不在Linux內核虛擬地址空間中的(如SRAM或硬體接口寄存器等),若需要訪問某外設I/O資源,必須先將其物理地址映射到內核虛擬地址空間中,然後才能在內核空間中訪問它。  Linux內核訪問外設I/O資源的方式有兩種:靜態映射(map_desc)和動態映射(ioremap)。
  • 從串口驅動到Linux驅動模型,想轉Linux的必會!
    並不是linux下的串口驅動。引入此圖旨在讓讀者感性的認識到串口控制臺的功能是什麼。下面正式開始對串口打開。發送。接收函數的分析。這裡向前引用一個函數。就是linux內核中幾種2440晶片通用的串口發送函數s3c24xx_serial_start_tx。
  • 【連載】嵌入式Linux開發教程:Linux內核
    第1章 Linux作業系統簡介本章導讀:本章首先對Linux發展簡史進行簡要介紹,然後對Linux內核進行了介紹,重點介紹了Linux內核的特點和功能,接著對Linux發行版進行介紹,並列舉了一些典型的發行版;最後對嵌入式Linux進行了簡要介紹,包括嵌入式Linux的特點和產品形態。
  • linux下安裝虛擬機,完美在linux系統下運行通達信軟體
    現在越來越多的人使用linux系統,現在很多的國產作業系統都是基於linux內核上的。雖說不少的軟體都可以運行在linux的系統上。但是對於股票軟體來說在linux上的使用是一個硬傷。能夠運行在linux下的國內股票軟體少之又少。
  • Linux如何安裝軟體
    常見的有以下幾種安裝方法源碼安裝rpm包安裝yum安裝 (RedHat、CentOS)apt-get安裝 (debian,ubuntu)源碼安裝以安裝gcc為例,登陸https://gcc.gnu.org/,下載自己想要的版本的gcc安裝包上傳gcc-4.1.2.tar.gz到Linux伺服器任意目錄,解壓解壓目錄執行shell命令configuration解壓目錄執行
  • 實戰經驗吐血推薦:怎樣在Linux環境下輕鬆實現基於I2C總線的EEPROM...
    因此,開發I2C總線設備驅動程序除了要涉及一般Linux內核驅動程序的知識外。還要對I2C總線驅動的體系結構有深入的了解。筆者在開發過程中使用設備型號為AT24C01A的EEPROM來測試I2C總線驅動。  2工作原理概述  在介紹I2C總線結構之前。要搞清楚兩個概念:I2C總線控制器和I2C設備。
  • Linux提權的幾種常用方式
    在滲透測試過程中,提升權限是非常關鍵的一步,攻擊者往往可以通過利用內核漏洞/權限配置不當/root權限運行的服務等方式尋找突破點,來達到提升權限的目的。1、內核漏洞提權提起內核漏洞提權就不得不提到髒牛漏洞(Dirty Cow),是存在時間最長且影響範圍最廣的漏洞之一。
  • ARM Linux根文件系統Root Filesystem的製作
    在使用devfs的內核裡如果沒有/dev,根本見不到Shell啟動的信息,因為內核找不到/dev/console;在使用udev的系統裡,也事先需要在/dev下建立console和null這兩個節點。關於devfs和udev的區別,網上很多文章說。當然如果你的內核已經不支持devfs了(2.6.12以後),可以使用純純的靜態節點。也就是用mknod人工生成。
  • 技術文檔丨如何為Apollo安裝低時延/實時內核
    如果您的目的只是基於Apollo平臺開發/測試您的算法,或者運行仿真軟體(如Lgsvl模擬器),則可能您根本不需要安 裝這裡描述的低時延或實時內核。Ubuntu軟體倉庫中的低時延內核足以為實車上運行Apollo提供低(或者零)時延。在其 內核配置中,任務搶佔式(PREEMPT)優化是開啟了的,時延可低至0.1毫秒。