#define MPCf_DONE                0
#define MPCf_DISPATCHED                1
#define MPCf_FREE_ON_COMPLETE        2

#define MPCT_CALL                1
#define MPCT_SPAWN_TASK                2

class MPCmdStruct
{
  MPCmdStruct *next,*last;
  U8 cmd_code;
  U8 flags;
  U1 *add;
  U1 *data;
  I1 *desc;
  I8 target_cpu_mask;
  TssStruct *tss; //spawned task
  I8 handler_cpu; //CPU accepting job
  I8 result;
};

#define MPCCf_LOCKED        0

class MPCmdCtrl
{
  MPCmdStruct *next_waiting,*last_waiting;
  MPCmdStruct *next_done,*last_done;
  U8 flags;
};

$PJ,"Project: OSMain","/LT/OSMain/OS.SPZ"$
asm {
////**************************PROCEDURE*************************
              ALIGN        16,OC_NOP
              USE16
MP_INIT_START::
              JMP        MP2_START2
              ALIGN        4,OC_NOP
MP2_SYS_TEMP_PTR:        DU4        0,0;

MP2_START2:
              CLI

//          MOV          EAX,CR0
              DU1        0x0F,0x20,0xC0;
              OR        EAX,0x60000000
//          MOV          CR0,EAX
              DU1        0x0F,0x22,0xC0;

              INVD

              MOV        AX,MP_VECTOR_ADDRESS/16
              MOV        DS,AX

              LGDT        U4 [MP_SYS_TEMP_PTR]

              MOV        EAX,SYS_START_CR0|0x60000000
//          MOV          CR0,EAX
              DU1        0x0F,0x22,0xC0;

              DU1        0x66,0xEA;                 //JMP SYS_CS_SEL:MP_INIT_OS
              DU4        MP_INIT_OS;
              DU2        SYS_CS_SEL;

MP_INIT_END::
              USE32
MP_INIT_OS:
              MOV        AX,ZERO_DS_SEL
              MOV        DS,AX
              MOV        ES,AX
              MOV        FS,AX
              MOV        GS,AX
              MOV        SS,AX

              FLDCW        U2 [SYS_INIT_FLOAT_CTRL_WORD]

@@1:        LOCK
              BTS        U4 [SYS_MP_CNT_LOCK],0
              JC        @@1
              WBINVD        //This might be paranoid
              MOV        ESI,U4 [SYS_MP_CNT]
              LOCK
              INC        U4 [SYS_MP_CNT]
              LOCK
              BTR        U4 [SYS_MP_CNT_LOCK],0


//          MOV          EAX,CR0
              DU1        0x0F,0x20,0xC0;
              AND        EAX,~0x60000000 //enable cache
//          MOV          CR0,EAX
              DU1        0x0F,0x22,0xC0;

              IMUL2        ESI,CPU_CACHED_SIZE
              ADD        ESI,U4 [SYS_CPU_CACHED]

              LEA        EAX,U4 CPU_START_STACK_TOP[ESI]
              MOV        ESP,EAX
              PUSH        U4 SYS_START_RFLAGS
              POPFD
              PUSH        U4 0
              CALL        INIT_EM64T
USE64
              PUSH        ESI
              CALL        CP_SET_GS_BASE
              POP        ESI
@@2:        MOV        RBX,U8 CPU_SETH_TSS[RSI]
              OR        RBX,RBX
              JZ        @@2
              MOV        U8 TSS_GS[RBX],RSI
              MOV        RAX,RBX
              CALL        SET_FS_BASE

              JMP        I4 RESTORE_CONTEXT
};

void MPInt(U8 num,U8 cpu_num=1)
{
  U4 *dl=MP_ICR_LOW,*dh=MP_ICR_HIGH;
  U8 old_flags=GetFlags;
  Cli;
  while (*dl&0x1000); //TODO semaphore
  *dh=cpu_num<<24;
  *dl=0x4800+num;
  SetFlags(old_flags);
}

void MPEOI()
{
  U4 *dl=MP_EOI;
  *dl=0;
}

void MPIntAll(U8 num)
{ //(All but self)
  U4 *dl=MP_ICR_LOW;
  U8 old_flags=GetFlags;
  Cli;
  while (*dl&0x1000); //TODO semaphore
  *dl=0xC4800+num;
  SetFlags(old_flags);
}

void MPNMInt()
{
  U4 *dl=MP_ICR_LOW;
  *dl=0xC4400;
}

void MPHalt()
{
  mp_cnt=1;
  MPNMInt; //Hlt All other processors
}

void MPWbInvdAll()
{
  MPIntAll(I_WBINVD);
  WbInvd;
}

void MPInitAPIC()
{
  U4 *d;
  d=MP_SVR;
  *d|=MP_APIC_ENABLED;
  d=MP_LDR;
  *d=Gs->num<<24;
  d=MP_DFR;
  *d=0xF0000000;
  MemSet(MP_IRR,0,0x20);
  MemSet(MP_ISR,0,0x20);
  MemSet(MP_TMR,0,0x20);
  SetTR(Gs->tr);
  Gs->idt=MAllocZ(16*256);
  InitIDT(Gs->idt,256);
}

void MPWaitForTask()
{
  U8 timeout=0;
  MPCmdStruct *tempm;
  Preempt(OFF);
  Sti;
  Bts(&Fs->task_flags,TSSf_IDLE);
  while (TRUE) {
      while (TRUE) {
          if (GetTimeStamp>timeout) {
              WbInvd;
              FinishOffDyingTsses;
              timeout=GetTimeStamp+time_stamp_freq>>9;
          } else if (mp_ctrl->next_waiting==mp_ctrl)
              SwapInNextTask;
          else
              break;
      }
      while (LBts(&mp_ctrl->flags,MPCCf_LOCKED))
          SwapInNextTask;
      tempm=mp_ctrl->next_waiting;
      while (tempm!=mp_ctrl && !Bt(&tempm->target_cpu_mask,Gs->num))
          tempm=tempm->next;
      if (tempm!=mp_ctrl) {
          RemQue(tempm);
          LBts(&tempm->flags,MPCf_DISPATCHED);
          tempm->handler_cpu=Gs->num;
          LBtr(&mp_ctrl->flags,MPCCf_LOCKED);
          Btr(&Fs->task_flags,TSSf_IDLE);
          switch (tempm->cmd_code) {
              case MPCT_CALL:
                  tempm->result=CallInd(tempm->add,tempm->data);
                  Preempt(OFF);
                  Sti;
                  break;
              case MPCT_SPAWN_TASK:
                  if (tempm->desc)
                      tempm->tss=Spawn(tempm->add,tempm->data,tempm->desc);
                  else
                      tempm->tss=Spawn(tempm->add,tempm->data,"MP Job");
                  break;
          }
          if (Bt(&tempm->flags,MPCf_FREE_ON_COMPLETE)) {
              Free(tempm->desc);
              Free(tempm);
          } else {
              while (LBts(&mp_ctrl->flags,MPCCf_LOCKED))
                  SwapInNextTask;
              InsQue(tempm,mp_ctrl->last_done);
              LBts(&tempm->flags,MPCf_DONE);
              LBtr(&mp_ctrl->flags,MPCCf_LOCKED);
          }
          LBtr(&Gs->uncached_address->uncached_flags,CPUUf_NOT_READY);
          Bts(&Fs->task_flags,TSSf_IDLE);
      } else
          LBtr(&mp_ctrl->flags,MPCCf_LOCKED);
  }
}

MPCmdStruct *MPQueueJob(void *add,void *data=NULL,
            I1 *desc=NULL,
            U8 flags=1<<MPCf_FREE_ON_COMPLETE,
            BoolI1 spawn=FALSE,I8 target_cpu_mask=ALL_MASK)
{
  MPCmdStruct *tempm=MAllocHCZ(sizeof(MPCmdStruct),mp_heap);
  if (desc)
      tempm->desc=StrNewHC(desc,mp_heap);
  if (spawn)
      tempm->cmd_code=MPCT_SPAWN_TASK;
  else
      tempm->cmd_code=MPCT_CALL;
  tempm->add=add;
  tempm->data=data;
  tempm->target_cpu_mask=target_cpu_mask;
  tempm->flags=flags;
  while (LBts(&mp_ctrl->flags,MPCCf_LOCKED))
      SwapInNextTask;
  InsQue(tempm,mp_ctrl->last_waiting);
  LBtr(&mp_ctrl->flags,MPCCf_LOCKED);
  return tempm;
}

MPCmdStruct *MPJob(void *add,void *data=NULL,
            U8 flags=1<<MPCf_FREE_ON_COMPLETE,
            I8 target_cpu_mask=ALL_MASK)
//Set flags to zero if you wish to
//get the result.
{
  return MPQueueJob(add,data,NULL,flags,FALSE,target_cpu_mask);
}

I8 MPJobResult(MPCmdStruct *tempm)
{
  I8 result;
  while (!Bt(&tempm->flags,MPCf_DONE))
      SwapInNextTask;
  while (LBts(&mp_ctrl->flags,MPCCf_LOCKED))
      SwapInNextTask;
  RemQue(tempm);
  LBtr(&mp_ctrl->flags,MPCCf_LOCKED);
  result=tempm->result;
  Free(tempm->desc);
  Free(tempm);
  return result;
}

TssStruct *MPSpawn(void *add,I8 data=0,I1 *desc=NULL,I8 target_cpu=ALL_MASK)
{
  TssStruct *result;
  MPCmdStruct *tempm=MPQueueJob(add,data,desc,0,TRUE,target_cpu);
  while (!tempm->tss)
      SwapInNextTask;
  result=tempm->tss;
  while (LBts(&mp_ctrl->flags,MPCCf_LOCKED))
      SwapInNextTask;
  RemQue(tempm);
  LBtr(&mp_ctrl->flags,MPCCf_LOCKED);
  Free(tempm->desc);
  Free(tempm);
  return result;
}

void MPInitCPUTask()
{
  MPInitAPIC;
  Fs->rip=&MPWaitForTask;
  Fs->time_slice_start=GetTimeStamp;
  RestoreContext;
}

void MPStart()
{
  TssStruct *tss;
  I1 buf[128];
  U4 *d;
  MPMainStruct *mp=MP_VECTOR_ADDRESS;
  I8 i=0;
  CPUCachedStruct *c;
  CPUUncachedStruct *uc;
  U8 old_flags=GetFlags;
  BlkPool *bp,*saved_bp;
  I8 shared_blks;
  MPCmdStruct *tempm,*tempm1;

  Cli;
  if (mp_cnt>1) {
      MPHalt;
      BusyWait(10000);

      tempm=mp_ctrl->next_waiting;
      while (tempm!=mp_ctrl) {
          tempm1=tempm->next;
          RemQue(tempm);
          Free(tempm->desc);
          Free(tempm);
          tempm=tempm1;
      }

      tempm=mp_ctrl->next_done;
      while (tempm!=&mp_ctrl->next_done) {
          tempm1=tempm->next;
          RemQue(tempm);
          Free(tempm->desc);
          Free(tempm);
          tempm=tempm1;
      }

      mp_cnt=1;
  }
  MemSet(&cpu_cached[1],0,sizeof(CPUCachedStruct)*(MP_MAX_PROCESSORS-1));
  MemSet(&cpu_uncached[1],0,sizeof(CPUUncachedStruct)*(MP_MAX_PROCESSORS-1));
  MemCpy(MP_VECTOR_ADDRESS,MP_INIT_START,MP_INIT_END-MP_INIT_START);
  mp->sys_temp_ptr=MAXGDT*16-1+gdttab><(U1 *)<<16;
  mp_cnt=1;
  mp_cnt_lock=0;

  d=MP_LVT3;
  *d=*d&0xFFFFFF00+MP_VECTOR;
  WbInvd;

  d=MP_ICR_LOW;
  *d=0xCC500; //assert init IPI
  BusyWait(10000);

  *d=0xC4600+MP_VECTOR; //start-up
  BusyWait(200);
  *d=0xC4600+MP_VECTOR;$FG$

  BusyWait(10000);

  for (i=1;i<mp_cnt;i++) {
      c =&cpu_cached[i];
      uc=&cpu_uncached[i];
      SPrintF(buf,"Seth Task CPU#%d",i);

      shared_blks=1; //One 2Meg blk
      bp=Alloc2MegMemBlks(&shared_blks,sys_code_bp);
      InitBlkPool(bp,shared_blks<<12);

      saved_bp=Gs->code_bp;
      Gs->code_bp=bp;
      tss=Spawn(&MPInitCPUTask,0,buf,NULL,NULL,DEFAULT_STACK,FALSE);
      tss->in_queue_signature=TSSS_IN_QUEUE_SIGNATURE;
      InitCPUCachedStruct(i,c);
      c->uncached_address=InitCPUUncachedStruct(uc);
      c->code_bp=bp;
      Gs->code_bp=saved_bp;
      c->tr=InitRealTssStruct;
      c->seth_tss=tss;
      WbInvd;
  }
  SetFlags(old_flags);
}

void MPInit()
{
  I8 shared_blks=1; //One 2Meg blk
  TssStruct *tss;
  RaxRbxRcxRdx ee;
  CPUCachedStruct *c;
  BlkPool *bp;
  CpuId(0x1,&ee);

  mp_cnt=1;
  mp_cnt_lock=0;
  WbInvd;
  bp=AllocUncachedMemBlks(&shared_blks);
  mp_heap=InitIndependentHeapCtrl(bp,shared_blks<<12);

  mp_ctrl=MAllocHCZ(sizeof(MPCmdCtrl),mp_heap);
  mp_ctrl->next_waiting=mp_ctrl->last_waiting=mp_ctrl;
  mp_ctrl->next_done=mp_ctrl->last_done=&mp_ctrl->next_done;

  cpu_cached  =MAllocHCZ(sizeof(CPUCachedStruct)*MP_MAX_PROCESSORS,adam_tss->code_heap);
  cpu_uncached=MAllocHCZ(sizeof(CPUUncachedStruct)*MP_MAX_PROCESSORS,mp_heap);

  c=cpu_cached;
  MemCpy(c,&sys_temp_cpu0_struct,sizeof(CPUCachedStruct));
  c->cached_address  =cpu_cached;
  c->uncached_address=InitCPUUncachedStruct(cpu_uncached);
  SetGs(c);
  tss=adam_tss;
  tss->time_slice_start=GetTimeStamp;
  tss->in_queue_signature=TSSS_IN_QUEUE_SIGNATURE;
  c->seth_tss=tss;
  c->code_bp=sys_code_bp;
  c->data_bp=sys_data_bp;
  c->tr=InitRealTssStruct;
  c->idle_tss=Spawn(0,NULL,"Idle",Fs,NULL,DEFAULT_STACK,FALSE);
  if (Bt(&ee.rdx,9))
      MPInitAPIC;
}
Home

Kernel
StartUp
Scheduler
Memory
MultiCore
Interrupts
BitMaps
Screen
Plot
Compiler Frontend
Compiler Mid
Compiler Backend
MultiCore
Historical capture: 2008-08-02. Home | Power on LoseThos | Sources and changes