'Programming/System'에 해당되는 글 8건

  1. 2011/03/25 조재혁 I/O Scheduler
  2. 2007/06/02 조재혁 [C/개념] 선점형 Thread 구현 (제 2차 버젼)
  3. 2007/05/07 조재혁 Disk parameter table (DPT) 에 대한 메모
  4. 2007/05/07 조재혁 enableA20 예제
  5. 2007/05/01 조재혁 콘솔화면 소거
  6. 2007/05/01 조재혁 TEXT mode 의 Blink속성 유효/무효화 하는 코드
  7. 2007/05/01 조재혁 8259 Timer 예제
  8. 2007/05/01 조재혁 ROM bios 설정을 지우는 예제

I/O Scheduler

Programming/System RSS Icon ATOM Icon 2011/03/25 02:40 조재혁


본 내용의 최근글은 http://www.hwport.com/wiki.php/IOScheduler 에서 보실수 있습니다.


I/O Scheduler

개요

I/O를 처리하기 위해서는 일련의 Seek, Read, Write, Sort, Merge등의 과정이 필요합니다.
이것을 좀더 효율적으로 흐름제어를 위해서 I/O처리에 대한 특화된 Scheduler의 고안이 필요했습니다.

문제의 고민

  • Writes-Starving-Reads
    • Write동작은 버퍼에 밀어넣고 버퍼에서 Merge 및 Sort를 하여 일련의 연속된 Write동작으로 처리될수 있습니다. 하지만 이 과정에서 Read동작이 끼어들게 되면 I/O요청순서에 입각하여 처리되면서 연속적인 Read동작을 하지 않게 되고 자주 Seek하면서 성능이 극대화 되기 힘들게 됩니다. 이러한 I/O Scheduler의 동작에 의한 현상을 "Writes-starving-reads"라고 합니다.
  • Effects of High Read Latency
    • 논리적으로 연속적인 커다란 Data를 Read하는 중에 작은 Data를 읽는 동작이 끼어들게 되면 작은 Data를 Read하는것에 대하여 어떤것에 성능의 초점을 맞춰야 하는지에 대한 갈등의 문제가 생깁니다. 이것을 "Effects of High Read Latency"라고 합니다.

Linux Elevator

  • 요청된 I/O를 Sort하면서 Queue에 넣었다가 오래된 요청을 먼저 처리하는 방식입니다.

Deadline I/O Scheduler

  • Read와 Write가 별도의 Queue로 Sort되어 넣었다가 요청순서대로 처리하게 되는데 이때 각 요청에는 제한시간이 있어서 제한시간을 넘어서까지 처리되지 않은 요청이 있는 경우 해당 요청을 먼저처리하도록 하여 처리하는 방식입니다.

Anticipatory I/O Scheduler

  • 논리적인 연속적인 Data A와 B가 있을때 한번의 Read요청으로 A를 Read하고 다음 요청이 B를 Read하고 그 다음 요청이 이전의 A Read위치의 다음에 위치한 부분인 경우를 위해서 처음 A의 Read요청이 완료된후 일정시간 Seek위치를 유지하는 방식으로 연속적인 Data Read에 대한 성능에 초점을 맞춘 방식입니다.

CFQ(Complete Fair Queue) I/O Scheduler

  • 각 Process별로 Queue를 소유하고 주어진 Time Slice동안 Round robin방식으로 작업을 처리하도록 하는 방식인데 만약 Time Slice를 전부 소모하지 않은 상태에서 Queue를 모두 처리한 경우 일정시간을 기다리면서 다른 요청을 추가적으로 기다려주는 조건을 포함합니다. 동기적인 요청(Read)이 비동기적인 요청(Write)보다 우선순위가 높게 처리되는 특성을 가지고 있고 Writes-Starving-Reads 현상을 어느정도 개선하는 방식입니다.

No-op I/O Scheduler

  • 요청된 I/O를 Sort하지는 않고 Merge만 하여 처리하는 것으로 Sort동작이 필요없는 경우에 (예를 들어서 Seek동작이 무시할정도로 빠른 Flash같은 장치들) 대해서 사용하는 방식입니다.

참고자료


    크리에이티브 커먼즈 라이센스
    Creative Commons License
    2011/03/25 02:40 2011/03/25 02:40
    받은 트랙백이 없고, 댓글이 없습니다.

    댓글+트랙백 RSS :: http://blog.hwport.com/rss/response/614

    댓글+트랙백 ATOM :: http://blog.hwport.com/atom/response/614

    예전에 "link:1차 버젼"으로 이와 비슷한 소스를 올린적이 있습니다.
    그러나 꽤 많은 분들이 컴파일 안된다고 그 자체를 이해하지 못하시더군요.
    그래서 이번에는 아주 쬐금 소스를 가다듬어서 실제 컴파일 가능하게
    코드를 개선하여 올려봅니다.
    이제 이해 못한다고 하시는 분들은 없겠죠?

    지금 개발중인 Kernel 의 선점형(비선점형 동시지원) Thread code는
    이와는 아주 많이 다르고 실제로 소스의 분량이 굉장히 방대하여
    이해하기 어려울까봐 이렇게 굉장히 축소한 버젼만 공개하지만
    추후 실제로 실전에 사용가능한 library 로 언젠가는 revision 하여 올릴 계획임을
    미리 밝혀둡니다. (언제가 될지는 저도 모름)

    main.c
    코드:
    /*
    [ GPL ]
    Code by JaeHyuk Cho <mailto:minzkn@infoeq.com> KOREA

    MZ Local Thread library v0.0.1b

    - Simple is best !
    */

    #if !defined(DEF_SOURCE_thread_c)
    #define DEF_SOURCE_thread_c "thread.c"

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    #define t_inline_asm __asm__ __volatile__
    #define ML_Alloc(m_size) malloc(m_size)
    #define ML_Free(m_ptr) free(m_ptr)
    #define ML_PeekPtr(m_cast,m_base,m_offset) ((m_cast)(((unsigned char *)(m_base)) + (m_offset)))
    #define ML_PeekDoubleWord(m_ptr,m_offset) *ML_PeekPtr(unsigned long *,m_ptr,m_offset)
    #define ML_PokeDoubleWord(m_ptr,m_offset,m_value) *ML_PeekPtr(unsigned long *,m_ptr,m_offset) = m_value

    typedef struct ts_STACK
    {
    void *Stack;
    int StackSize, StackPointer;
    }t_STACK;

    typedef struct ts_THREAD_TASK
    {
    struct ts_THREAD_TASK *Next;
    t_STACK *Stack;
    unsigned int TaskID, ESP, Tick, Active;
    void * (*Entry)(void *, void *);
    void *Argument;
    }t_THREAD_TASK;

    typedef struct ts_THREAD
    {
    t_THREAD_TASK *Task;
    t_THREAD_TASK *CurrentTask;
    unsigned int TaskCount, MakeID;
    }t_THREAD;

    t_THREAD *ML_CreateTHREAD(void);
    t_THREAD *ML_DestroyTHREAD(t_THREAD *s_THREAD);
    t_THREAD *ML_AddTHREAD(t_THREAD *s_THREAD, void * (*s_ThreadFunction)(void *, void *), void *s_Argument, int s_StackSize);
    t_THREAD *ML_RunTHREAD(t_THREAD *s_THREAD);
    int ML_SleepTHREAD(t_THREAD *s_THREAD);

    t_STACK *ML_CreateSTACK(int s_StackSize);
    t_STACK *ML_DestroySTACK(t_STACK *s_STACK);
    int ML_PushSTACK(t_STACK *s_STACK, int s_Value);
    int ML_PopSTACK(t_STACK *s_STACK, int *s_Value);
    int ML_SetSTACK(t_STACK *s_STACK, int s_StackPointer);

    void __ML_ReturnTHREAD__(void);




    #if 1 /* TEST ------------------------------- */
    void * (test_0)(void *s_thread_handle, void *s_argument)
    {
     int s_count = 0;
     while((s_count++) < 100)
     {
      (void)fprintf(stdout, "test_0 : %3d (\"%s\")\n", s_count, (char *)s_argument);
      (void)ML_SleepTHREAD((t_THREAD *)s_thread_handle);  /* context switch */
     }
     return(s_argument);
    }

    void * (test_1)(void *s_thread_handle, void *s_argument)
    {
     int s_count = 0;
     while((s_count++) < 100)
     {
      (void)fprintf(stdout, "test_1 : %3d (\"%s\")\n", s_count, (char *)s_argument);
      (void)ML_SleepTHREAD((t_THREAD *)s_thread_handle);  /* context switch */
     }
     return(s_argument);
    }

    void * (test_2)(void *s_thread_handle, void *s_argument)
    {
     int s_count = 0;
     while((s_count++) < 100)
     {
      (void)fprintf(stdout, "test_2 : %3d (\"%s\")\n", s_count, (char *)s_argument);
      (void)ML_SleepTHREAD((t_THREAD *)s_thread_handle);  /* context switch */
     }
     return(s_argument);
    }

    void * (test_3)(void *s_thread_handle, void *s_argument)
    {
     int s_count = 0;
     while((s_count++) < 100)
     {
      (void)fprintf(stdout, "test_3 : %3d (\"%s\")\n", s_count, (char *)s_argument);
      (void)ML_SleepTHREAD((t_THREAD *)s_thread_handle);  /* context switch */
     }
     return(s_argument);
    }

    int main(void)
    {
     t_THREAD *s_thread;
     s_thread = ML_CreateTHREAD();

     ML_AddTHREAD(s_thread, test_0, "USER ARGUMENT - 0", (8 << 10));
     ML_AddTHREAD(s_thread, test_1, "USER ARGUMENT - 1", (8 << 10));
     ML_AddTHREAD(s_thread, test_2, "USER ARGUMENT - 2", (8 << 10));
     ML_AddTHREAD(s_thread, test_3, "USER ARGUMENT - 3", (8 << 10));

     (void)fprintf(stdout, "Run.\n");
     ML_RunTHREAD(s_thread);
     (void)fprintf(stdout, "End.\n");

     s_thread = ML_DestroyTHREAD(s_thread);
     return(0);
    }
    #endif /* TEST ------------------------------- */




    #if 0 /* TEST ------------------------------- */
    void * (test_0)(void *s_thread_handle, void *s_argument)
    {
     int s_context = *((int *)s_argument);
     int s_count;
     int s_color;
     s_color = (s_context % 6) + 31;
     (void)fprintf(stdout, "[color=%d] \x1b[1;%dmbegin thread (id=%d)\x1b[0m\n", s_color, s_color, s_context);
     for(s_count = 0;s_count < 100;s_count++)
     {
      (void)fprintf(stdout, "[color=%d] \x1b[1;%dmtest thread (id=%d, count=%d)\x1b[0m\n", s_color, s_color, s_context, s_count);
      (void)ML_SleepTHREAD((t_THREAD *)s_thread_handle);  /* context switch */
     }
     (void)fprintf(stdout, "[color=%d] \x1b[1;%dmend thread (id=%d)\x1b[0m\n", s_color, s_color, s_context);
     return(s_argument);
    }

    int main(void)
    {
     t_THREAD *s_thread;
     int s_count;
     int s_context[ 10 ];
     s_thread = ML_CreateTHREAD();

     for(s_count = 0;s_count < (sizeof(s_context) / sizeof(int));s_count++)
     {
      s_context[s_count] = s_count;
      ML_AddTHREAD(s_thread, test_0, &s_context[s_count], (8 << 10));
     }

     (void)fprintf(stdout, "Run.\n");
     ML_RunTHREAD(s_thread);
     (void)fprintf(stdout, "End.\n");

     s_thread = ML_DestroyTHREAD(s_thread);
     return(0);
    }
    #endif /* TEST ------------------------------- */





    static void *__ML_ManagerTHREAD__(void *s_ThreadHandle, void *s_Argument)
    {
    static t_THREAD *sg_THREAD = (t_THREAD *)0;
    if(sg_THREAD != (t_THREAD *)s_ThreadHandle)sg_THREAD = (t_THREAD *)s_ThreadHandle;
    ML_SleepTHREAD((t_THREAD *)s_ThreadHandle);
    if(((t_THREAD *)s_ThreadHandle)->Task->Active == 0)return(s_Argument);
    t_inline_asm(
      "__ML_ReturnTHREAD__:\n\t"
      "pushl $__ML_ReturnTHREAD__\n\t" /* Retry push return address */
    );
    t_inline_asm(
      "\n\t"
      : "=a"(((t_THREAD *)s_ThreadHandle)->CurrentTask->Argument)
    );
    ((t_THREAD *)s_ThreadHandle)->CurrentTask->Active = 0;
    ML_SleepTHREAD((t_THREAD *)s_ThreadHandle);
    return(s_Argument);
    }

    t_THREAD *ML_CreateTHREAD(void)
    {
    t_THREAD *s_Return;
    s_Return = (t_THREAD *)ML_Alloc(sizeof(t_THREAD));
    if(s_Return)
    {
      s_Return->Task = s_Return->CurrentTask = (t_THREAD_TASK *)0;
      s_Return->TaskCount = s_Return->MakeID = 0u;
      s_Return = ML_AddTHREAD(s_Return, __ML_ManagerTHREAD__, (void *)0, (4 << 10));
    }
    return(s_Return);
    }

    t_THREAD *ML_DestroyTHREAD(t_THREAD *s_THREAD)
    {
    t_THREAD_TASK *s_THREAD_TASK;
    if(s_THREAD)
    {
      while(s_THREAD->Task && s_THREAD->TaskCount--)
      {
       s_THREAD_TASK = s_THREAD->Task;
       s_THREAD->Task = s_THREAD->Task->Next;
       if(s_THREAD_TASK->Stack)(void)ML_DestroySTACK(s_THREAD_TASK->Stack);
       (void)ML_Free(s_THREAD_TASK);
      }
      (void)ML_Free(s_THREAD);
      s_THREAD = (t_THREAD *)0;
    }
    return(s_THREAD);
    }

    t_THREAD *ML_AddTHREAD(t_THREAD *s_THREAD, void * (*s_ThreadFunction)(void *, void *), void *s_Argument, int s_StackSize)
    {
    t_THREAD_TASK *s_THREAD_TASK;
    if(s_THREAD == (t_THREAD *)0)s_THREAD = ML_CreateTHREAD();
    if(s_THREAD)
    {
      if(s_THREAD->Task)
      {
       s_THREAD_TASK = s_THREAD->Task;
       while(s_THREAD_TASK->Next && s_THREAD_TASK->Next != s_THREAD->Task)s_THREAD_TASK = s_THREAD_TASK->Next;
       s_THREAD_TASK->Next = (t_THREAD_TASK *)ML_Alloc(sizeof(t_THREAD_TASK));
       s_THREAD_TASK = s_THREAD_TASK->Next;
       if(s_THREAD->CurrentTask == (t_THREAD_TASK *)0)s_THREAD->CurrentTask = s_THREAD->Task;
      }
      else s_THREAD->Task = s_THREAD->CurrentTask = s_THREAD_TASK = (t_THREAD_TASK *)ML_Alloc(sizeof(t_THREAD_TASK));
      if(s_THREAD_TASK)
      {
       if(s_StackSize < ( 4 << 10 ))s_StackSize = ( 4 << 10 );
       s_THREAD_TASK->Next = s_THREAD->Task;
       s_THREAD_TASK->Stack = ML_CreateSTACK(s_StackSize);
       s_THREAD_TASK->TaskID = (s_THREAD->MakeID++);
       s_THREAD_TASK->Tick = 0;
       s_THREAD_TASK->Active = 1;
       s_THREAD_TASK->Entry = s_ThreadFunction;
       s_THREAD_TASK->Argument = s_Argument;
       s_THREAD_TASK->ESP = (unsigned int)s_THREAD_TASK->Stack->Stack + s_THREAD_TASK->Stack->StackPointer;
       s_THREAD->TaskCount++;
      }
    }
    return(s_THREAD);
    }

    t_THREAD *ML_RunTHREAD(t_THREAD *s_THREAD)
    {
    struct { unsigned int eax, ebx, ecx, edx, esi, edi, ebp, esp, flags; }s_Register;
    t_THREAD_TASK *s_THREAD_TASK;
    unsigned int s_RegisterAddress, s_TempEBX;
    if(s_THREAD)
    {
      if(s_THREAD->Task)
      {
       s_RegisterAddress = (unsigned int)(&s_Register);
       t_inline_asm(
        "\n\t"
        "movl %%ebx, %1\n\t"
        "movl %0, %%ebx\n\t"
        "movl %%eax, 0(%%ebx)\n\t"
        "movl %1, %%eax\n\t"
        "movl %%eax, 4(%%ebx)\n\t"
        "movl 0(%%ebx), %%eax\n\t"
        "movl %%ecx, 8(%%ebx)\n\t"
        "movl %%edx, 12(%%ebx)\n\t"
        "movl %%esi, 16(%%ebx)\n\t"
        "movl %%edi, 20(%%ebx)\n\t"
        "movl %%ebp, 24(%%ebx)\n\t"
        "movl %%esp, 28(%%ebx)\n\t"
        "pushfl\n\t"
        "popl 32(%%ebx)\n\t"
        "movl 4(%%ebx), %%ebx\n\t"
        "\n\t"
        :
        : "m"(s_RegisterAddress), "m"(s_TempEBX)
       );
       s_THREAD_TASK = s_THREAD->Task;
       ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.flags);
       ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.esp);
       ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.ebp);
       ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.edi);
       ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.esi);
       ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.edx);
       ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.ecx);
       ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.ebx);
       ML_PushSTACK(s_THREAD_TASK->Stack, (int)s_THREAD_TASK->Argument);
       ML_PushSTACK(s_THREAD_TASK->Stack, (int)s_THREAD);
       s_THREAD_TASK->ESP = (unsigned int)s_THREAD_TASK->Stack->Stack + s_THREAD_TASK->Stack->StackPointer;
       s_THREAD_TASK = s_THREAD_TASK->Next;
       while(s_THREAD_TASK && s_THREAD_TASK != s_THREAD->Task)
       {
        ML_PushSTACK(s_THREAD_TASK->Stack, (int)s_THREAD_TASK->Argument);
        ML_PushSTACK(s_THREAD_TASK->Stack, (int)s_THREAD);
        ML_PushSTACK(s_THREAD_TASK->Stack, (int)__ML_ReturnTHREAD__);

        ML_PushSTACK(s_THREAD_TASK->Stack, (int)s_THREAD_TASK->Argument);
        ML_PushSTACK(s_THREAD_TASK->Stack, (int)s_THREAD);
        ML_PushSTACK(s_THREAD_TASK->Stack, (int)__ML_ReturnTHREAD__);

        ML_PushSTACK(s_THREAD_TASK->Stack, (int)s_THREAD_TASK->Entry);  /* First swich entry */

        ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.flags);
        ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.ebp);
        ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.edi);
        ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.esi);
        ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.edx);
        ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.ecx);
        ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.ebx);
        s_THREAD_TASK->ESP = (unsigned int)s_THREAD_TASK->Stack->Stack + s_THREAD_TASK->Stack->StackPointer;
        s_THREAD_TASK = s_THREAD_TASK->Next;
       }
       t_inline_asm(
        "\n\t"
        "movl %1, %%ecx\n\t"
        "movl %0, %%ebp\n\t"
        "movl %%ebp, %%esp\n\t"
        "call *%%ecx\n\t"
        "addl $4 + 4, %%esp\n\t"
        "popl %%ebx\n\t"
        "popl %%ecx\n\t"
        "popl %%edx\n\t"
        "popl %%esi\n\t"
        "popl %%edi\n\t"
        "popl %%ebp\n\t"
        "popl %%eax\n\t" /* Change stack (x86) */
        "popfl\n\t"
        "movl %%eax, %%esp\n\t"
        "\n\t"
        :
        : "m"(s_THREAD->Task->ESP), "m"(s_THREAD->Task->Entry)
       );
      }
    }
    return(s_THREAD);
    }

    int ML_SleepTHREAD(t_THREAD *s_THREAD)
    {
    s_THREAD->CurrentTask->Tick++;
    t_inline_asm(
      "\n\t"
      "movl %%esp, %%eax\n\t"
      "subl $28, %%eax\n\t"
      "\n\t"
      : "=a"(s_THREAD->CurrentTask->ESP)
    );
    do
    {
      s_THREAD->CurrentTask = s_THREAD->CurrentTask->Next;
      if(s_THREAD->CurrentTask == s_THREAD->Task)
      {
       if(s_THREAD->Task->Active == 1)
       {
        s_THREAD->CurrentTask->Active = 0;
        continue;
       }
       else break;
      }
    }while(s_THREAD->CurrentTask->Active == 0);
    if(s_THREAD->CurrentTask != s_THREAD->Task)s_THREAD->Task->Active = 1;
    t_inline_asm(
      "\n\t"
      "pushfl\n\t"
      "pushl %%ebp\n\t"
      "pushl %%edi\n\t"
      "pushl %%esi\n\t"
      "pushl %%edx\n\t"
      "pushl %%ecx\n\t"
      "pushl %%ebx\n\t"
      "movl %0, %%esp\n\t"
      "popl %%ebx\n\t"
      "popl %%ecx\n\t"
      "popl %%edx\n\t"
      "popl %%esi\n\t"
      "popl %%edi\n\t"
      "popl %%ebp\n\t"
      "popfl\n\t"
      "\n\t"
      :
      : "a"(s_THREAD->CurrentTask->ESP)
    );
    return(1);
    }

    t_STACK *ML_CreateSTACK(int s_StackSize)
    {
    t_STACK *s_Return;
    if(s_StackSize < (4 << 10))s_StackSize = (4 << 10);
    s_Return = (t_STACK *)ML_Alloc(sizeof(t_STACK));
    if(s_Return)
    {
      s_Return->Stack = (void *)ML_Alloc(s_StackSize);
      s_Return->StackSize = s_Return->StackPointer = s_StackSize;
    }
    return(s_Return);
    }

    t_STACK *ML_DestroySTACK(t_STACK *s_STACK)
    {
    if(s_STACK)
    {
      if(s_STACK->Stack && s_STACK->StackSize > 0)(void)ML_Free(s_STACK->Stack);
      (void)ML_Free(s_STACK);
      s_STACK = (t_STACK *)0;
    }
    return(s_STACK);
    }

    int ML_PushSTACK(t_STACK *s_STACK, int s_Value)
    {
    if(s_STACK)
    {
      if(s_STACK->Stack && s_STACK->StackSize >= sizeof(s_Value) && s_STACK->StackPointer >= sizeof(s_Value))
      {
       s_STACK->StackPointer -= sizeof(s_Value);
       ML_PokeDoubleWord(s_STACK->Stack, s_STACK->StackPointer, s_Value);
       return(s_STACK->StackPointer);
      }
    }
    return(0);
    }

    int ML_PopSTACK(t_STACK *s_STACK, int *s_Value)
    {
    int s_Return = (-1);
    if(s_STACK)
    {
      if(s_STACK->Stack && s_STACK->StackSize >= sizeof(int) && s_STACK->StackPointer <= (s_STACK->StackSize - sizeof(int)))
      {
       s_Return = ML_PeekDoubleWord(s_STACK->Stack, s_STACK->StackPointer);
       s_STACK->StackPointer += sizeof(int);
      }
    }
    if(s_Value)*(s_Value) = s_Return;
    return(s_Return);
    }

    int ML_SetSTACK(t_STACK *s_STACK, int s_StackPointer)
    {
    if(s_STACK)
    {
      s_STACK->StackPointer = s_StackPointer;
      return(s_STACK->StackPointer);
    }
    return(0);
    }

    #endif

    /* End of source */


    Makefile
    코드:
    # Copyright (C) Information Equipment co.,LTD
    # All rights reserved.
    # Code by JaeHyuk Cho <mailto:minzkn@infoeq.com>
    # CVSTAG="$Header$"

    # bash$ make TARGET_ARCH=i386 all
    # bash$ make TARGET_ARCH=mips all
    # bash$ make TARGET_ARCH=ppc all
    # bash$ make TARGET_ARCH=arm all

    TARGET_ARCH                  :=i386
    # TARGET_ARCH                  :=mips
    # TARGET_ARCH                  :=ppc
    # TARGET_ARCH                  :=arm

    ifeq ($(findstring mips,$(TARGET_ARCH)),mips)
     CROSS_COMPILE               ?=/opt/kenati/bin/lx4189-uclibc-#
    endif
    ifeq ($(findstring ppc,$(TARGET_ARCH)),ppc)
     CROSS_COMPILE               ?=/opt/hardhat/devkit/ppc/405/bin/ppc_405-#
    endif
    ifeq ($(findstring arm,$(TARGET_ARCH)),arm)
     CROSS_COMPILE               ?=/usr/local/arm-linux/bin/arm-linux-#
    endif

    # default
    CROSS_COMPILE                ?=#

    CC                           := $(CROSS_COMPILE)gcc
    AR                           := $(CROSS_COMPILE)ar
    RM                           := rm -f

    THIS_NAME                    := mzthread

    CFLAGS                       := -O0# NEED
    # CFLAGS                       += -g
    CFLAGS                       += -Wall
    CFLAGS                       += -Werror
    CFLAGS                       += -fomit-frame-pointer# NEED
    CFLAGS                       += -fPIC
    CFLAGS                       += -pipe
    CFLAGS                       += -ansi
    CFLAGS                       += -I.

    LDFLAGS                      := -s#
    ARFLAGS                      := rc#

    TARGET_bin                   := $(THIS_NAME)
    TARGET                       := $(TARGET_bin)

    OBJECTS_bin                  := main.o
    OBJECTS                      := $(OBJECTS_bin)

    .PHONY: all clean

    all: $(TARGET)
    clean: ; $(RM) *.o $(TARGET)

    $(TARGET_bin): $(OBJECTS_bin) ; $(CC) $(LDFLAGS) -o $(@) $(^)

    $(OBJECTS): Makefile

    %.o: %.c ; $(CC) $(CFLAGS) -c -o $(@) $(<)

    # End of Makefile
    크리에이티브 커먼즈 라이센스
    Creative Commons License
    2007/06/02 00:04 2007/06/02 00:04
    받은 트랙백이 없고, 댓글이 없습니다.

    댓글+트랙백 RSS :: http://blog.hwport.com/rss/response/147

    댓글+트랙백 ATOM :: http://blog.hwport.com/atom/response/147

    Interrupt $0x1e 에 해당하는 벡터위치에 DPT의 위치주소가 담겨있습니다. 우리는 이 값을 통해서 플로피의 정보를 얻어볼수 있습니다. Interrupt 0x1e 는 0x1e * 4 = 0x0078 에 해당하는 주소이며 이 주소에 DPT가 담겨져 있는 메모리를 가르키는 주소값이 존재하게 됩니다. 여기서 Interrupt 0x1e는 "Disk Initialization Parameter Table Vector" 라고 부릅니다. 그리고 DPT는 "Disk parameter table"이라고 합니다.

    참고로 아래의 내용중에 시간의 단위는 Milli second입니다.

    디스크로부터 읽는 것은 Interrupt $0x13 을 사용하는 방법이 있고 PIO 방식도 있으니 그 부분은 가장 많이 알려져 있는 "랄프브라운의 인터럽트 리스트"를 참고하시면 될겁니다.

    코드:

    Offset  내용 
    0x00  Bit 0~3까지 4bit는 Head의 지연시간을 가집니다. 
          Bit 4~7까지 4bit는 Head가 자유로워지는에 걸리는 시간입니다. 
    0x01  Bit 0은 DMA의 사용가능 여부입니다. 
          Bit 1~7까지 7Bit는 Head의 접근시간에 대하여 2를 나누어 1을 뺀 값의 시간을 뜻합니다. 
    0x02  Motor의 전원이 완전히 꺼지기까지의 Clock tick수를 의미합니다. 
    0x03  FM 또는 MFM모드에 대하여 각각 내용이 다른데 그냥 섹터당 바이트수를 128로 나눈값으로 생각하시면 무난할듯. 
    0x04  Track당 Sector수 (본래 의미는 Track에서 마지막 섹터번호입니다.) 
    0x05  Sector당 byte수 (본래 의미는 Sector간격입니다.) 
    0x06  Format을 결정하는 값 (0x80이면 섹터당 128byte이고 그 외의 값은 필자도 정확히 모르며 정확하지 않아도 잘 되네요.) 
    0x07  Format간격 (포맷시에 하나의 그룹을 단위로 포맷을 하게 되는데 이때 이 그룹간격) 
    0x08  위와 비슷한데 Data형식 지정자라고 해야 할까? (필자는 이것에 대해서도 잘 모르겠습니다.) 
    0x09  Head가 접근후에 준비까지의 시간 
    0x0a  Motor가 기동되어 준비될때까지의 시간 
    0x0b  Motor가 중지될때까지의 시간 (디스켓 빼려면 이것이 정지될때까지는 빼지 말라고 할수 있겠죠?)
    크리에이티브 커먼즈 라이센스
    Creative Commons License
    2007/05/07 11:08 2007/05/07 11:08
    받은 트랙백이 없고, 댓글이 없습니다.

    댓글+트랙백 RSS :: http://blog.hwport.com/rss/response/65

    댓글+트랙백 ATOM :: http://blog.hwport.com/atom/response/65

    enableA20 예제

    Programming/System RSS Icon ATOM Icon 2007/05/07 09:59 조재혁
    출처: http://www.visopsys.org/osdev/sources/enableA20.s


    코드:

    ;;
    ;; enableA20.s (adapted from Visopsys OS-loader)
    ;;
    ;; Copyright (c) 2000, J. Andrew McLaughlin
    ;; You're free to use this code in any manner you like, as long as this
    ;; notice is included (and you give credit where it is due), and as long
    ;; as you understand and accept that it comes with NO WARRANTY OF ANY KIND.
    ;; Contact me at <andy@visopsys.org> about any bugs or problems.
    ;;

    enableA20:
       ;; This subroutine will enable the A20 address line in the keyboard
       ;; controller.  Takes no arguments.  Returns 0 in EAX on success,
       ;; -1 on failure.  Written for use in 16-bit code, see lines marked
       ;; with 32-BIT for use in 32-bit code.

       pusha

       ;; Make sure interrupts are disabled
       cli

       ;; Keep a counter so that we can make up to 5 attempts to turn
       ;; on A20 if necessary
       mov CX, 5

       .startAttempt1:      
       ;; Wait for the controller to be ready for a command
       .commandWait1:
       xor AX, AX
       in AL, 64h
       bt AX, 1
       jc .commandWait1

       ;; Tell the controller we want to read the current status.
       ;; Send the command D0h: read output port.
       mov AL, 0D0h
       out 64h, AL

       ;; Wait for the controller to be ready with a byte of data
       .dataWait1:
       xor AX, AX
       in AL, 64h
       bt AX, 0
       jnc .dataWait1

       ;; Read the current port status from port 60h
       xor AX, AX
       in AL, 60h

       ;; Save the current value of (E)AX
       push AX         ; 16-BIT
       ;; push EAX      ; 32-BIT

       ;; Wait for the controller to be ready for a command
       .commandWait2:
       in AL, 64h
       bt AX, 1
       jc .commandWait2

       ;; Tell the controller we want to write the status byte again
       mov AL, 0D1h
       out 64h, AL   

       ;; Wait for the controller to be ready for the data
       .commandWait3:
       xor AX, AX
       in AL, 64h
       bt AX, 1
       jc .commandWait3

       ;; Write the new value to port 60h.  Remember we saved the old
       ;; value on the stack
       pop AX         ; 16-BIT
       ;; pop EAX      ; 32-BIT

       ;; Turn on the A20 enable bit
       or AL, 00000010b
       out 60h, AL

       ;; Finally, we will attempt to read back the A20 status
       ;; to ensure it was enabled.

       ;; Wait for the controller to be ready for a command
       .commandWait4:
       xor AX, AX
       in AL, 64h
       bt AX, 1
       jc .commandWait4

       ;; Send the command D0h: read output port.
       mov AL, 0D0h
       out 64h, AL   

       ;; Wait for the controller to be ready with a byte of data
       .dataWait2:
       xor AX, AX
       in AL, 64h
       bt AX, 0
       jnc .dataWait2

       ;; Read the current port status from port 60h
       xor AX, AX
       in AL, 60h

       ;; Is A20 enabled?
       bt AX, 1

       ;; Check the result.  If carry is on, A20 is on.
       jc .success

       ;; Should we retry the operation?  If the counter value in ECX
       ;; has not reached zero, we will retry
       loop .startAttempt1


       ;; Well, our initial attempt to set A20 has failed.  Now we will
       ;; try a backup method (which is supposedly not supported on many
       ;; chipsets, but which seems to be the only method that works on
       ;; other chipsets).


       ;; Keep a counter so that we can make up to 5 attempts to turn
       ;; on A20 if necessary
       mov CX, 5

       .startAttempt2:
       ;; Wait for the keyboard to be ready for another command
       .commandWait6:
       xor AX, AX
       in AL, 64h
       bt AX, 1
       jc .commandWait6

       ;; Tell the controller we want to turn on A20
       mov AL, 0DFh
       out 64h, AL

       ;; Again, we will attempt to read back the A20 status
       ;; to ensure it was enabled.

       ;; Wait for the controller to be ready for a command
       .commandWait7:
       xor AX, AX
       in AL, 64h
       bt AX, 1
       jc .commandWait7

       ;; Send the command D0h: read output port.
       mov AL, 0D0h
       out 64h, AL   

       ;; Wait for the controller to be ready with a byte of data
       .dataWait3:
       xor AX, AX
       in AL, 64h
       bt AX, 0
       jnc .dataWait3

       ;; Read the current port status from port 60h
       xor AX, AX
       in AL, 60h

       ;; Is A20 enabled?
       bt AX, 1

       ;; Check the result.  If carry is on, A20 is on, but we might warn
       ;; that we had to use this alternate method
       jc .warn

       ;; Should we retry the operation?  If the counter value in ECX
       ;; has not reached zero, we will retry
       loop .startAttempt2


       ;; OK, we weren't able to set the A20 address line.  Do you want
       ;; to put an error message here?
       jmp .fail


       .warn:
       ;; Here you may or may not want to print a warning message about
       ;; the fact that we had to use the nonstandard alternate enabling
       ;; method

       .success:
       sti
       popa
       xor EAX, EAX
       ret

       .fail:
       sti
       popa
       mov EAX, -1
       ret
    크리에이티브 커먼즈 라이센스
    Creative Commons License
    2007/05/07 09:59 2007/05/07 09:59
    받은 트랙백이 없고, 댓글이 없습니다.

    댓글+트랙백 RSS :: http://blog.hwport.com/rss/response/59

    댓글+트랙백 ATOM :: http://blog.hwport.com/atom/response/59

    콘솔화면 소거

    Programming/System RSS Icon ATOM Icon 2007/05/01 02:55 조재혁

    # File : clear.s
    # Code : JaeHyuk Cho <minzkn@infoeq.com>

    .code32

    .globl mzstartup

    .text
    .org 0
    mzstartup:

                   xorl %edx, %edx
                   movl $L_ClearANSI, %ecx
    0:
                   inc %edx
                   testb $0xff, (%ecx, %edx, 1)
                   jnz 0b

                   movl $4, %eax
                   movl $1, %ebx
                   int $0x80

                   movl %ebx, %eax
                   int $0x80
    .data
    L_ClearANSI: .string "\x1b[2J\x1b[0;0H"

    # End of source





    위의 어셈블리 버젼을 C언어 버젼으로 변환하면

    #include <sys/types.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <fcntl.h>
    int main(void)
    {
    const char c_ClearCode[] = {"\x1b[2J\x1b[0;0H"};
    write(STDOUT_FILENO, (void *)(&c_ClearCode[0]), sizeof(c_ClearCode) - 1);
    return(0);
    }




    위의 C언어 버젼을 보다 범용적으로 바꾼다면

    #include <stdio.h>
    int main(void)
    {
    fprintf(stdout, "\x1b[2J\x1b[0;0H");
    fflush(stdout);
    return(0);
    }
    크리에이티브 커먼즈 라이센스
    Creative Commons License
    2007/05/01 02:55 2007/05/01 02:55
    받은 트랙백이 없고, 댓글이 없습니다.

    댓글+트랙백 RSS :: http://blog.hwport.com/rss/response/28

    댓글+트랙백 ATOM :: http://blog.hwport.com/atom/response/28





    Blink_00           PROC FAR ; void far pascal Blink_00(unsigned int s_sw)

                       PUSH BP

                       MOV BP, SP

                       PUSH AX

                       PUSH DX

                       MOV DX, 03D4h + 0006h

                       IN AL, DX

                       MOV DX, 03C0h

                       MOV AL, 10h

                       OUT DX, AL

                       INC DX

                       IN AL, DX

                       TEST WORD PTR [BP + 06h], 0FFFFh        ; s_sw

                       JZ SHORT L_Blink_00_00

                       OR AL, 08h

                       MAC_JumpShort <L_Blink_00_01>

    L_Blink_00_00      LABEL SHORT

                       AND AL, 0F7h

    L_Blink_00_01      LABEL SHORT

                       DEC DX

                       OUT DX, AL

                       MOV DX, 03D4h + 0006h

                       IN AL, DX

                       MOV DX, 03C0h

                       MOV AL, 20h

                       OUT DX, AL

                       POP DX

                       POP AX

                       POP BP

                       RETF 2

    Blink_00           ENDP
    크리에이티브 커먼즈 라이센스
    Creative Commons License
    2007/05/01 02:50 2007/05/01 02:50
    받은 트랙백이 없고, 댓글이 없습니다.

    댓글+트랙백 RSS :: http://blog.hwport.com/rss/response/26

    댓글+트랙백 ATOM :: http://blog.hwport.com/atom/response/26

    8259 Timer 예제

    Programming/System RSS Icon ATOM Icon 2007/05/01 02:49 조재혁

    COMMENT #

    NOTE: 2000.10.03 [TUE] Code by JaeHyuk

      - Delay : 1/1000sec parameter   ex.) Delay(6000ms) = 6sec delay

    #


    DEF_ASM_TIME       EQU "TIME.ASM"


    PUBLIC             ResetTimer

    PUBLIC             Delay

    PUBLIC             TimerDummy, OpenTimer, CloseTimer, SetTimerRate, SetTimerCallBack, TimerHandler, GetClockTick


    PUBLIC             TIMER_IRQ_Enabled

    ;

    PUBLIC             TIMER_OldVector

    PUBLIC             TIMER_IRQ_CallBack

    PUBLIC             TIMER_IRQ_Active

    PUBLIC             TIMER_Speed

    PUBLIC             TIMER_Count

    PUBLIC             TIMER_ClockTick


                       ASSUME CS:CODE_TIME, DS:DATA_TIME, ES:NOTHING, SS:NOTHING

    CODE_TIME          SEGMENT

    ResetTimer         PROC FAR ; void far pascal ResetTimer(void)

                       PUSH AX

                       PUSHF

                       CLI

                       MOV AL, 00110110b

                       OUT 43h, AL

                       XOR AL, AL

                       OUT 40h, AL

                       MAC_ClearCache ; Delay for apply

                       OUT 40h, AL

                       MAC_ClearCache ; Delay for apply

                       POPF

                       POP AX

                       RETF

    ResetTimer         ENDP

    Delay              PROC FAR ; void far pascal Delay(unsigned int s_ms)

                       PUSH BP

                       MOV BP, SP

                       PUSH AX

                       PUSH DX                  

                       CALL FAR PTR CODE_TIME:OpenTimer

                       PUSH DEF_DELAY_Value

                       CALL FAR PTR CODE_TIME:SetTimerRate

    L_Delay_00         LABEL SHORT                  

                       CALL FAR PTR CODE_TIME:GetClockTick

                       CMP AX, WORD PTR [BP + 06h]

                       JB SHORT L_Delay_00

                       CALL FAR PTR CODE_TIME:CloseTimer

                       POP DX

                       POP AX

                       POP BP

                       RETF 2

    Delay              ENDP

    TimerDummy         PROC FAR ; void far pascal TimerDummy(void)

                       PUSH DS

                       ASSUME DS:BSS_TIME

                       PUSH BSS_TIME

                       POP DS

                       ADD WORD PTR BSS_TIME:TIMER_ClockTick[DEF_DWord_Low], 0001h

                       ADC WORD PTR BSS_TIME:TIMER_ClockTick[DEF_DWord_High], DEF_Null

                       ASSUME DS:DATA_TIME

                       POP DS

                       RETF

    TimerDummy         ENDP

    OpenTimer          PROC FAR ; void far pascal OpenTimer(void)

                       PUSH DS

                       PUSH AX

                       PUSH DX

                       ASSUME DS:DATA_TIME

                       MOV AX, DATA_TIME

                       MOV DS, AX

                       CMP WORD PTR DATA_TIME:TIMER_IRQ_Enabled, DEF_False

                       JNE SHORT L_OpenTimer_00

                       ASSUME DS:BSS_TIME

                       MOV AX, BSS_TIME

                       MOV DS, AX

                       XOR AX, AX

                       MOV WORD PTR BSS_TIME:TIMER_ClockTick[DEF_DWord_Low], AX

                       MOV WORD PTR BSS_TIME:TIMER_ClockTick[DEF_DWord_High], AX

                       MOV WORD PTR BSS_TIME:TIMER_IRQ_CallBack[DEF_Far_Offset], OFFSET CODE_TIME:TimerDummy

                       MOV WORD PTR BSS_TIME:TIMER_IRQ_CallBack[DEF_Far_Segment], CODE_TIME

                       PUSH DEF_INT_Timer

                       CALL FAR PTR CODE_INT:GetVect

                       MOV WORD PTR BSS_TIME:TIMER_OldVector[DEF_Far_Offset], AX

                       MOV WORD PTR BSS_TIME:TIMER_OldVector[DEF_Far_Segment], DX

                       MOV WORD PTR BSS_TIME:TIMER_IRQ_Active, DEF_False

                       PUSH CODE_TIME

                       PUSH OFFSET CODE_TIME:TimerHandler

                       PUSH DEF_INT_Timer

                       CALL FAR PTR CODE_INT:SetVect

                       CALL FAR PTR CODE_TIME:ResetTimer

                       MOV WORD PTR BSS_TIME:TIMER_Speed, 0FFFFh

                       ASSUME DS:DATA_TIME

                       MOV AX, DATA_TIME

                       MOV DS, AX

                       INC WORD PTR DATA_TIME:TIMER_IRQ_Enabled

    L_OpenTimer_00     LABEL SHORT

                       POP DX

                       POP AX

                       POP DS

                       RETF

    OpenTimer          ENDP

    CloseTimer         PROC FAR ; void far pascal CloseTimer(void)

                       PUSH DS

                       PUSH AX

                       ASSUME DS:DATA_TIME

                       MOV AX, DATA_TIME

                       MOV DS, AX

                       CMP WORD PTR DATA_TIME:TIMER_IRQ_Enabled, DEF_False

                       JE SHORT L_CloseTimer_00

                       CALL FAR PTR CODE_TIME:ResetTimer

                       ASSUME DS:BSS_TIME

                       MOV AX, BSS_TIME

                       MOV DS, AX

                       PUSH WORD PTR BSS_TIME:TIMER_OldVector[DEF_Far_Segment]

                       PUSH WORD PTR BSS_TIME:TIMER_OldVector[DEF_Far_Offset]

                       PUSH DEF_INT_Timer

                       CALL FAR PTR CODE_INT:SetVect

                       ASSUME DS:DATA_TIME

                       MOV AX, DATA_TIME

                       MOV DS, AX

                       DEC WORD PTR DATA_TIME:TIMER_IRQ_Enabled

    L_CloseTimer_00    LABEL SHORT

                       POP AX

                       POP DS

                       RETF

    CloseTimer         ENDP

    SetTimerRate       PROC FAR ; void far pascal SetTimerRate(unsigned int s_rate)

                       PUSH BP

                       MOV BP, SP

                       PUSH DS

                       PUSH AX

                       PUSH DX

                       ASSUME DS:DATA_TIME

                       MOV AX, DATA_TIME

                       MOV DS, AX

                       CMP WORD PTR DATA_TIME:TIMER_IRQ_Enabled, DEF_False

                       JE SHORT L_SetTimerRate_00

                       MOV DX, 0012h

                       MOV AX, 34DEh

                       DIV WORD PTR [BP + 06h]                 ; s_rate

                       ASSUME DS:BSS_TIME

                       MOV DX, BSS_TIME

                       MOV DS, DX

                       MOV WORD PTR BSS_TIME:TIMER_Speed, AX

                       MOV DX, AX

                       XOR AX, AX

                       MOV WORD PTR BSS_TIME:TIMER_ClockTick[DEF_DWord_High], AX

                       MOV WORD PTR BSS_TIME:TIMER_ClockTick[DEF_DWord_Low], AX

                       PUSHF

                       CLI

                       MOV AL, 00110110b

                       OUT 43h, AL

                       MOV AL, DL

                       OUT 40h, AL

                       MAC_ClearCache

                       MOV AL, DH

                       OUT 40h, AL

                       MAC_ClearCache

                       POPF

                       ASSUME DS:DATA_TIME

    L_SetTimerRate_00  LABEL SHORT                  

                       POP DX

                       POP AX

                       POP DS

                       POP BP

                       RETF 2

    SetTimerRate       ENDP

    SetTimerCallBack   PROC FAR ; void far pascal SetTimerCallBack(void far *s_callback)

                       PUSH BP

                       MOV BP, SP

                       PUSH DS

                       PUSH AX

                       ASSUME DS:BSS_TIME

                       MOV AX, BSS_TIME

                       MOV DS, AX

                       PUSHF

                       CLI

                       MOV AX, WORD PTR [BP + 06h + DEF_Far_Segment]

                       MOV WORD PTR BSS_TIME:TIMER_IRQ_CallBack[DEF_Far_Segment], AX

                       MOV AX, WORD PTR [BP + 06h + DEF_Far_Offset]

                       MOV WORD PTR BSS_TIME:TIMER_IRQ_CallBack[DEF_Far_Offset], AX

                       POPF

                       ASSUME DS:DATA_TIME

                       POP AX

                       POP DS

                       POP BP

                       RETF 4

    SetTimerCallBack   ENDP

    TimerHandler       PROC FAR ; void far pascal TimerHandler(void)

                       PUSHA

                       PUSH DS

                       ASSUME DS:BSS_TIME

                       MOV AX, BSS_TIME

                       MOV DS, AX

                       CMP WORD PTR BSS_TIME:TIMER_IRQ_Active, DEF_False

                       JNE SHORT L_TimerHandler_00

                       INC WORD PTR BSS_TIME:TIMER_IRQ_Active

                       CALL DWORD PTR BSS_TIME:TIMER_IRQ_CallBack

                       DEC WORD PTR BSS_TIME:TIMER_IRQ_Active

    L_TimerHandler_00  LABEL SHORT

                       MOV AX, WORD PTR BSS_TIME:TIMER_Speed

                       ADD WORD PTR BSS_TIME:TIMER_Count, AX

                       JNC SHORT L_TimerHandler_01

                       PUSHF

                       CALL DWORD PTR BSS_TIME:TIMER_OldVector

                       MAC_JumpShort <L_TimerHandler_02>

    L_TimerHandler_01  LABEL SHORT

                       MOV AL, 20h

                       OUT 20h, AL

    L_TimerHandler_02  LABEL SHORT

                       POP DS

                       POPA

                       IRET

    TimerHandler       ENDP

    GetClockTick       PROC FAR ; unsigned long far pascal GetClockTick(void)

                       PUSH BP

                       MOV BP, SP

                       ASSUME DS:BSS_TIME

                       PUSH DS

                       MOV AX, BSS_TIME

                       MOV DS, AX

                       MOV DX, WORD PTR BSS_TIME:TIMER_ClockTick[DEF_DWord_High]

                       MOV AX, WORD PTR BSS_TIME:TIMER_ClockTick[DEF_DWord_Low]

                       POP DS

                       ASSUME DS:DATA_TIME

                       POP BP

                       RETF

    GetClockTick       ENDP

    CODE_TIME          ENDS


                       ASSUME CS:CODE_TIME, DS:DATA_TIME, ES:NOTHING, SS:STACK_DEFAULT

    DATA_TIME          SEGMENT

    TIMER_IRQ_Enabled  DW DEF_False                            ; Timer service enabled flag

    DATA_TIME          ENDS


                       ASSUME CS:CODE_TIME, DS:BSS_TIME, ES:NOTHING, SS:STACK_DEFAULT

    BSS_TIME           SEGMENT

    TIMER_OldVector    DD ?                                    ; BIOS INT 08h routine

    TIMER_IRQ_CallBack DD ?                                    ; User defined callback routine

    TIMER_IRQ_Active   DW ?                                    ; Callback routine active flag

    TIMER_Speed        DW ?                                    ; Timer speed in clock ticks

    TIMER_Count        DW ?                                    ; Timer counter used to call the

    TIMER_ClockTick    DD ?                                    ; Clock tick counter

    BSS_TIME           ENDS

                       END


    ; End of source

    크리에이티브 커먼즈 라이센스
    Creative Commons License
    2007/05/01 02:49 2007/05/01 02:49
    받은 트랙백이 없고, 댓글이 없습니다.

    댓글+트랙백 RSS :: http://blog.hwport.com/rss/response/25

    댓글+트랙백 ATOM :: http://blog.hwport.com/atom/response/25

    실험전에:
    이것은 BIOS설정값을 깨뜨리므로 실험하려면 BIOS설정을 외워고 할것.

    적절히 수정하면 임의의 설정을 응용프로그램에서도 할수 있지만 checksum 계산법을 알아야 한다는...


    XOR BX, BX
    MOV BL, 10H
    Again_Loop:
    MOV AL, BL
    OUT 70H, AL
    OUT 0edH, AL
    MOV AL, 0xff
    OUT 71H, AL
    INC BX
    CMP BX, 0080H
    JB Again_Loop
    크리에이티브 커먼즈 라이센스
    Creative Commons License
    2007/05/01 02:17 2007/05/01 02:17
    받은 트랙백이 없고, 댓글이 없습니다.

    댓글+트랙백 RSS :: http://blog.hwport.com/rss/response/20

    댓글+트랙백 ATOM :: http://blog.hwport.com/atom/response/20