Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
 iakovlev.org 
 Languages
 С
 GNU С Library 
 Qt 
 STL 
 Threads 
 C++ 
 Samples 
 stanford.edu 
 ANSI C
 Libs
 LD
 Socket
 Pusher
 Pipes
 Encryption
 Plugin
 Inter-Process
 Errors
 Deep C Secrets
 C + UNIX
 Linked Lists / Trees
 Asm
 Perl
 Python
 Shell
 Erlang
 Go
 Rust
 Алгоритмы
NEWS
Последние статьи :
  Тренажёр 16.01   
  Эльбрус 05.12   
  Алгоритмы 12.04   
  Rust 07.11   
  Go 25.12   
  EXT4 10.11   
  FS benchmark 15.09   
  Сетунь 23.07   
  Trees 25.06   
  Apache 03.02   
 
TOP 20
 MINIX...3057 
 Solaris...2933 
 LD...2905 
 Linux Kernel 2.6...2470 
 William Gropp...2182 
 Rodriguez 6...2014 
 C++ Templates 3...1945 
 Trees...1938 
 Kamran Husain...1866 
 Secure Programming for Li...1792 
 Максвелл 5...1710 
 DevFS...1694 
 Part 3...1684 
 Stein-MacEachern-> Час...1632 
 Go Web ...1626 
 Ethreal 4...1619 
 Arrays...1607 
 Стивенс 9...1604 
 Максвелл 1...1592 
 FAQ...1539 
 
  01.01.2024 : 3621733 посещений 

iakovlev.org

Sample Inline Functions

Memory access

FAR_PEEKx
читает байт (или слово) из памяти из сегмента данных.
static __inline__ dword farpeekl(word sel,void *off)
 {
   dword ret;
   asm("push %%fs;mov %1,%%fs;"
       "mov %%fs:(%2),%0;"
       "pop %%fs":"=r"(ret):"g"(sel),"r"(off));
   return ret;
 }
FAR_POKEx
пишет байт или слово в память
static __inline__ void farpokeb(word sel, void *off, byte v)
 {
   asm("push %%fs; mov %0,%%fs;"
       "movb %2,%%fs:(%1);"
       "pop %%fs": :"g"(sel),"r"(off),"r"(v));
 }

I/O access

OUTx
посылает байт в порт. В зависимости от размера - outb, outw и outl . Модификатор "a" указывает на то , что си-шная переменная value будет размещена в регистре eax
static __inline__ void outb(unsigned short port, unsigned char val)
 {
    asm volatile("outb %0,%1"::"a"(val), "Nd" (port));
 }
INx
получение данных из порта .
static __inline__ unsigned char inb(unsigned short port)
 {
    unsigned char ret;
    asm volatile ("inb %1,%0":"=a"(ret):"Nd"(port));
    return ret;
 }
IO_WAIT
перевод процессора в состояние ожидания .
static __inline__ void io_wait(void)
 {
    asm volatile("jmp 1f;1:jmp 1f;1:");
 }
static __inline__ void io_wait(void)
 {
    asm volatile("outb %%al, $0x80" : : "a"(0));
    // port 0x80 is used for 'checkpoints' during POST.
    // linux kernel seems to think it's free for use :-/
 }

Interrupt-related functions

Enabled?
вертает 'true' если irq = enabled
static __inline__
 int irqEnabled()
 {
         int f;
         asm volatile ("pushf;popl %0":"=g" (f));
         return f & (1<<9);
 }
acknowledge
sends the PIC chip (8259a) that we're ready for more interrupts. as pics are cascaded for int 8-15, if no>=8, we will have to send a 'clearance code' for both master and slave PICs.
static __inline__
 void irqUnlock(int no)
 {
   /*             Val, Port */
   if (no>7) outb(0x20,0xa0);
   outb(0x20,0x20);
 }
LIDT
определение новой таблицы прерываний
void lidt(void *base, unsigned int size) {
    unsigned int i[2];
 
    i[0] = size << 16;
    i[1] = (unsigned int) base;
    asm ("lidt (%0)": :"p" (((char *) i)+2));
 }

Другой вариант

void lidt(void *base, unsigned short size) {
 struct{unsigned short length;unsigned long base;}__attribute__((__packed__)) IDTR;
 
    IDTR.length = size;
    IDTR.base = (unsigned long) base;
    asm ("lidt (%0)": :"p" (&IDTR));
 }

Cpu-related functions

CPUID
Идентификация процессора
/** issue a single request to CPUID. Fits 'intel features', for instance
  */
 static inline void cpuid(int code, dword *a, dword *d) {
   asm volatile("cpuid":"=a"(*a),"=d"(*d):"0"(code));
 }
READ_CRx
чтение значения регистра cr0
static inline unsigned read_cr0() {
    unsigned val;
    asm volatile("mov %%cr0, %0":"=r"(val));
    return val;
 }

Interrupt Service Routines

Что такое Interrupt Service Routine (ISR)?

Когда срабатывает внешнее прерывание - нормальное течение команд прерывается и вызывается подпрограмма обслуживания прерываний (ISR).

Прерывание может быть вызвано как железом , так и софтом . Например , каждый раз при нажатии на клавишу срабатывает прерывание IRQ1 (Interrupt Request 1)

Софт может вызвать прерывания с помощью ключевого слова int .

Нужно различать , что в защищенном режиме текущие прерывания хранятся в в interrupt descriptor table (IDT) , а в реальном режиме - в interrupt vector table (IVT) .

Problem

Некоторые пытаются писать inline-код в следующем стиле :

/* How NOT to write an interrupt handler           */
 void interrupt_handler(void)
 {
     __asm__("pushad"); /* Save registers.          */
     /* do something */
     __asm__("popad");  /* Restore registers.       */
     __asm__("iret");   /* This will triple-fault! */
 }

Это не будет работать . Правильно вот так :

push   %ebp
 mov    %esp,%ebp
 sub    $<size of local variables>,%esp
 pushad
 # C code comes here
 popad
 iret
 # 'leave' if you use local variables, 'pop %ebp' otherwise.
 leave
 ret

Solutions

Two-Stage Assembler Wrapping

Напишем враппер на ассемблере , который вызывает си-шную функцию :.

/* filename : isr_wrapper.asm */
 .globl   _isr_wrapper
 .align   4
 
 _isr_wrapper:
 
     pushad
     call    _interrupt_handler
     popad
     iret
 
 
 /* filename : interrupt_handler.c */
 void interrupt_handler(void)
 {
     /* do something */
 }

Загрузчик на GAS - первые шаги

Начнем со следующего кода - step1.s - создаем простой бинарник размером 512 байт , в его конец не забудем прописать 2 магических байта:

 .code16   
 .text
 
 .global _start
 start:
 hang:
    jmp hang
 .org 510
 boot_flag:
    .word 0xAA55
    
 Компиляция :
 	as step1.s -o step1.o
 	ld step1.o -o step1.bin --oformat binary
 
Немного усложним задачу - step2.s - распечатаем сообщение на экране . Для этого используем 10-е прерывание. Команда lodsb последовательно прогрузит байтики текстового сообщения. В примере используем числовые метки. Если при обращении метка стоит выше , к ней добавляется префикс b, если ниже - префикс f:

 .code16
 .text
 
 # .global _start
 # start:
 
    mov $0x07C0, %ax
    mov %ax, %ds
 
    mov $msg, %si
 1: lodsb
    or %al,%al # zero=end of str
    jz 2f   # get out
    mov $0x0E, %ah
    int $0x10
    jmp 1b
 
 2:
    jmp 2b
 
 msg: .asciz "Welcome to www.iakovlev.org\n" 
    .org 510
    .word 0xAA55   
 
 Копиляция :   
 as step2.s -o step2.o
 ld --oformat binary --Ttext 0x0 -o step2.bin step2.o
     
 
Далее - step3.s - попробуем вызвать подпрограмму внутри загрузчика :

 .code16
 .text
 
 mov $0x07C0, %ax
 mov %ax, %ds
 
 mov $msg, %si
 call Print
 
 1:
 jmp 1b
 
 # Prints a NULL-terminated string
 # INPUT: SI=String
 # OUTPUT: None
 # CLOBBERS: SI, AX, BX, FLAGS
 Print:
         mov $0x0E, %ah
         xor %bx, %bx
 1:
         lodsb
         or %al, %al
         jz 2f
 
         # INT 0x10 VIDEO TELETYPE
         # AH=0xE AL=Character [BH=VideoPage BL=Attribute]
         int $0x10
         jmp 1b
 2:
         ret
 
 msg: .asciz "Welcome to www.iakovlev.org\n"
 .org 510
 .word 0xAA55
 
 Компиляция :
 	as step3.s -o step3.o
 	ld --oformat binary --Ttext 0x0 -o step3.bin step3.o
 
 
Следующим вариантом будет использование макроса . 2 исходника - step4.s

 .code16
 .text
 
 .global _start
 _start:
 
 .include "our_macros.s"   
 
 1:
    jmp 1b
 
 
и our_macros.s :

 
 # Syntax is .macro MacroName Param1, Param2, Param3, ...
 # Alternative: .macro MacroName Param1 Param2 Param3 ...
 # You can also set defaults like .macro DoSomething Int1=3 Int2=6
 .macro BIOSPrint StringPointer
    mov $\StringPointer, %si
 1: lodsb
    or %al,%al
    jz 2f
    mov $0x0E, %ah
    int $0x10
    jmp 1b
 2:
 .endm
 
    mov $0x07C0, %ax
    mov %ax, %ds
 
    BIOSPrint msg
 
 2:
    jmp 2b
 
 msg: .asciz "Welcome to www.iakovlev.org\n"
    .org 510
    .word 0xAA55   
 
 компиляция - 
 	as step4.s -o step4.o
 	ld --oformat binary --Ttext 0x0 -o step4.bin step4.o
 
 
В следующем примере переключаемся в защищенный режим . Глобальная таблица дескрипторов - gdt - имеет размер 1 MB и расположена в памяти начиная с адреса 0x0 . После возвращения из защищенного режима в real mode ограничение на размер сираницы в 64 КВ уже недействительно.

 .code16
 .text
 
 ljmp $0, $Start
 Start:
 xor %ax, %ax
 mov %ax, %ds
 mov %ax, %ss
 mov $0x8200, %sp         # Differs from the original since we hardly need 7KBs of stack
 
 cli                      # Interrupts off, save current DS
 push %ds
 
 lgdt (gdtinfo)           # The brackets are just decoration, it works without them 
 			 # but you may find it more legible this way
 
 mov %cr0, %eax           # Enable protected mode
 or $1, %al
 mov %eax, %cr0
 
 mov $0x8, %ax            # Load selector 1, 32bit flat data
 mov %ax, %ds
 
 mov $0x0f01, %ax         # Use the segment to write to the screen
 mov %ax, %ds:(0xB8000)
 
 mov %cr0, %eax           # Shut off protected mode
 xor $1, %al
 mov %eax, %cr0
 
 pop %ds                  # Get the realmode segment back and enable interrupts
 sti
 
    mov $msg, %si
 10: lodsb
    or %al,%al # zero=end of str
    jz 1f   # get out
    mov $0x0E, %ah
    int $0x10
    jmp 10b
 
 1:
 jmp 1b
 
 # Description for the CPU to find the GDT
 gdtinfo: .word gdtend - gdt - 1
          .long gdt
 
 gdt:     .long 0         # Descriptor 0 is the NULL descriptor
          .long 0
 gdtkerneldata:           # 32bit Flat Data, 0-4GB Writable
         .word 0xFFFF
         .word 0
         .byte 0
         .byte 0x92
         .byte 0xCF
         .byte 0
 gdtend:
 
 .org 510
 .word 0xAA55
 
Несколько примеров вспомогательных функций:

 .code32
 # ------------------
 dochar:
     call cprint              # print one character
 sprint:
     lodsb                    # string char to AL
     or %al, %al
     jnz dochar               # else, we're done
     addb $1, (ypos)          # down one row
     movb $0, (xpos)          # back to left
     ret
 
 cprint:
     mov $0x0F, %ah             # attrib = white on black
     mov %eax, %ecx             # save char/attribute
     movzxb (ypos), %eax
     mov $160, %edx             # 2 bytes (char/attrib)
     mul %edx                   # for 80 columns
     movzxb (xpos), %ebx
     shl $1, %ebx               # times 2 to skip attrib
 
     mov $0xb8000, %edi         # start of video memory
     add %eax, %edi             # add y offset
     add %ebx, %edi             # add x offset
 
     mov %ecx, %eax             # restore char/attribute
     movw %ax, %ds:(%edi)
     addb $1, (xpos)            # advance to right
 
     ret
 
 # ------------------------------------
 
 printreg32:
     mov $outstr32, %edi
     mov (reg32), %eax
     mov $hexstr, %esi
     mov $8, %ecx               # eight nibbles
 
 hexloop:
     rol $4, %eax               # leftmost will
     mov %eax, %ebx             # become rightmost
     and $0x0f, %ebx
     mov (%esi, %ebx), %bl       # index into hexstr
     mov %bl, (%edi)
     inc %edi
     dec %ecx
     jnz hexloop
 
     mov $outstr32, %esi
     call sprint
 
     ret
 
 # ------------------------------------
 
 xpos: .byte 0
 ypos: .byte 0
 hexstr: .ascii "0123456789ABCDEF"
 outstr32: .asciz "00000000"    # register value
 reg32: .long 0                 # pass values to printreg32
 

 

 

 

 

 

 
Оставьте свой комментарий !

Ваше имя:
Комментарий:
Оба поля являются обязательными

 Автор  Комментарий к данной статье