File : s-bbcppr-ppc.adb


   1 ------------------------------------------------------------------------------
   2 --                                                                          --
   3 --                  GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS                --
   4 --                                                                          --
   5 --               S Y S T E M . B B . C P U _ P R I M I T I V E S            --
   6 --                                                                          --
   7 --                                  B o d y                                 --
   8 --                                                                          --
   9 --        Copyright (C) 1999-2002 Universidad Politecnica de Madrid         --
  10 --             Copyright (C) 2003-2005 The European Space Agency            --
  11 --                     Copyright (C) 2003-2016, AdaCore                     --
  12 --                                                                          --
  13 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
  14 -- terms of the  GNU General Public License as published  by the Free Soft- --
  15 -- ware  Foundation;  either version 3,  or (at your option) any later ver- --
  16 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
  17 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  18 -- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
  19 --                                                                          --
  20 --                                                                          --
  21 --                                                                          --
  22 --                                                                          --
  23 --                                                                          --
  24 -- You should have received a copy of the GNU General Public License and    --
  25 -- a copy of the GCC Runtime Library Exception along with this program;     --
  26 -- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
  27 -- <http://www.gnu.org/licenses/>.                                          --
  28 --                                                                          --
  29 -- GNAT was originally developed  by the GNAT team at  New York University. --
  30 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
  31 --                                                                          --
  32 -- The port of GNARL to bare board targets was initially developed by the   --
  33 -- Real-Time Systems Group at the Technical University of Madrid.           --
  34 --                                                                          --
  35 ------------------------------------------------------------------------------
  36 
  37 --  This package implements PowerPC architecture specific support for the GNAT
  38 --  Ravenscar run time.
  39 
  40 with System.Machine_Code; use System.Machine_Code;
  41 with System.Multiprocessors;
  42 with System.BB.Interrupts;
  43 with System.BB.Threads.Queues;
  44 with System.BB.Protection;
  45 with System.BB.Board_Support;
  46 with System.BB.CPU_Primitives.Multiprocessors;
  47 
  48 package body System.BB.CPU_Primitives is
  49 
  50    package SSE renames System.Storage_Elements;
  51    use type SSE.Integer_Address;
  52    use type SSE.Storage_Offset;
  53 
  54    type MSR_Type is mod 2 ** 32;
  55    for MSR_Type'Size use 32;
  56 
  57    MSR_EE : constant MSR_Type := 2 ** 15;
  58 
  59    function Get_MSR return MSR_Type;
  60    pragma Inline (Get_MSR);
  61    --  Read the MSR
  62 
  63    procedure Set_MSR (MSR : MSR_Type);
  64    pragma Inline (Set_MSR);
  65    --  Write the MSR
  66 
  67    type Context_Switch_Params is record
  68       Running_Thread_Address : Address;
  69       --  Address of the running thread entry for the current cpu
  70 
  71       First_Thread_Address : Address;
  72       --  Address of the first read thread for the current cpu
  73    end record;
  74    pragma Convention (C, Context_Switch_Params);
  75    pragma Suppress_Initialization (Context_Switch_Params);
  76    --  This record describe data that are passed from Pre_Context_Switch
  77    --  to Context_Switch. In the assembly code we take advantage of the ABI
  78    --  so that the data returned are in the registers of the incoming call.
  79    --  So there is no need to copy or to move the data between both calls.
  80 
  81    function Pre_Context_Switch return Context_Switch_Params;
  82    pragma Export (Asm, Pre_Context_Switch, "__gnat_pre_context_switch");
  83    --  The full context switch is split in 2 stages:
  84    --  - Pre_Context_Switch: adjust the current priority (but don't modify
  85    --    the MSR.EE bit), and return the running and first thread queue
  86    --    addresses.
  87    --  - The assembly routine (context_switch) which does the real context
  88    --    switch.
  89    --  When called from interrupt handler, the stack pointer is saved before
  90    --  and restore after the context switch. Therefore the context switch
  91    --  cannot allocate a frame but only assembly code can guarantee that. We
  92    --  also take advantage of this two stage call to extract queue pointers
  93    --  in the Ada code.
  94 
  95    ------------------------
  96    -- Pre_Context_Switch --
  97    ------------------------
  98 
  99    function Pre_Context_Switch return Context_Switch_Params is
 100       use System.BB.Threads.Queues;
 101       use System.BB.Threads;
 102 
 103       CPU_Id : constant System.Multiprocessors.CPU :=
 104                  Multiprocessors.Current_CPU;
 105 
 106       New_Priority : constant Integer :=
 107                        First_Thread_Table (CPU_Id).Active_Priority;
 108    begin
 109       --  Called with interrupts disabled
 110 
 111       --  Set interrupt priority. Unlike the SPARC implementation, the
 112       --  interrupt priority is not part of the context (not in a register).
 113       --  However full interrupt disabling is part of the context switch.
 114 
 115       if New_Priority < Interrupt_Priority'Last then
 116          Board_Support.Set_Current_Priority (New_Priority);
 117       end if;
 118 
 119       return (Running_Thread_Table (CPU_Id)'Address,
 120               First_Thread_Table (CPU_Id)'Address);
 121    end Pre_Context_Switch;
 122 
 123    --------------------
 124    -- Context_Switch --
 125    --------------------
 126 
 127    procedure Context_Switch is
 128 
 129       procedure Context_Switch_Asm
 130         (Running_Thread_Table_Element_Address : System.Address;
 131          Ready_Thread_Table_Element_Address : System.Address);
 132       pragma Import (Asm, Context_Switch_Asm, "__gnat_context_switch");
 133       --  Real context switch in assembly code
 134 
 135       Params : Context_Switch_Params;
 136    begin
 137       --  First set priority and get pointers
 138 
 139       Params := Pre_Context_Switch;
 140 
 141       --  Then the real context switch
 142 
 143       Context_Switch_Asm (Params.Running_Thread_Address,
 144                           Params.First_Thread_Address);
 145    end Context_Switch;
 146 
 147    ------------------------
 148    -- Disable_Interrupts --
 149    ------------------------
 150 
 151    procedure Disable_Interrupts is
 152    begin
 153       Set_MSR (Get_MSR and not MSR_EE);
 154    end Disable_Interrupts;
 155 
 156    -----------------------
 157    -- Enable_Interrupts --
 158    -----------------------
 159 
 160    procedure Enable_Interrupts (Level : Integer) is
 161    begin
 162       if Level /= System.Interrupt_Priority'Last then
 163          Board_Support.Set_Current_Priority (Level);
 164 
 165          --  Really enable interrupts
 166 
 167          Set_MSR (Get_MSR or MSR_EE);
 168       end if;
 169    end Enable_Interrupts;
 170 
 171    -------------
 172    -- Get_MSR --
 173    -------------
 174 
 175    function Get_MSR return MSR_Type is
 176       Res : MSR_Type;
 177    begin
 178       Asm ("mfmsr %0",
 179            Outputs => MSR_Type'Asm_Output ("=r", Res),
 180            Volatile => True);
 181       return Res;
 182    end Get_MSR;
 183 
 184    ----------------------
 185    -- Initialize_Stack --
 186    ----------------------
 187 
 188    procedure Initialize_Stack
 189      (Base          : Address;
 190       Size          : Storage_Elements.Storage_Offset;
 191       Stack_Pointer : out Address)
 192    is
 193       use System.Storage_Elements;
 194 
 195       Minimum_Stack_Size_In_Bytes : constant Integer_Address :=
 196                                       CPU_Specific.Stack_Alignment;
 197 
 198       Initial_SP : constant System.Address :=
 199                      To_Address
 200                        (To_Integer (Base + Size) -
 201                           Minimum_Stack_Size_In_Bytes);
 202 
 203       LR_Save_Word : System.Address;
 204       for LR_Save_Word'Address use Initial_SP + Storage_Offset'(4);
 205 
 206       Back_Chain_Word : System.Address;
 207       for Back_Chain_Word'Address use Initial_SP;
 208 
 209    begin
 210       --  Put Null to these two values to clear the stack.
 211 
 212       LR_Save_Word    := Null_Address;
 213       Back_Chain_Word := Null_Address;
 214 
 215       Stack_Pointer := Initial_SP;
 216    end Initialize_Stack;
 217 
 218    ------------------------
 219    -- Initialize_Context --
 220    ------------------------
 221 
 222    procedure Initialize_Context
 223      (Buffer          : not null access Context_Buffer;
 224       Program_Counter : System.Address;
 225       Argument        : System.Address;
 226       Stack_Pointer   : System.Address)
 227    is
 228       procedure Start_Thread_Asm;
 229       pragma Import (Asm, Start_Thread_Asm, "__gnat_start_thread");
 230 
 231       Initial_SP : Address;
 232 
 233    begin
 234       --  No need to initialize the context of the environment task
 235 
 236       if Program_Counter = Null_Address then
 237          return;
 238       end if;
 239 
 240       --  We cheat as we don't know the stack size nor the stack base
 241 
 242       Initialize_Stack (Stack_Pointer, 0, Initial_SP);
 243 
 244       --  Overwrite Stack Pointer and Program Counter with values that have
 245       --  been passed as arguments. The Stack Pointer of the task is 2 words
 246       --  below Stack_Pointer. These two words correspond to the header of the
 247       --  new stack. This header contains the LR_Save_Word and Back_Chain_Word.
 248       --  Program_Counter points to the task_wrapper procedure.
 249 
 250       --  We create a new stack pointer with a size of at least 8 which are
 251       --  reserved for the header, but we also have to make sure that the stack
 252       --  is aligned with Standard'Maximum_Alignment
 253 
 254       Buffer.R1 := Initial_SP;
 255       Buffer.LR := Start_Thread_Asm'Address;
 256 
 257       Buffer.R14 := Program_Counter;
 258       Buffer.R15 := Argument;
 259 
 260       CPU_Specific.Finish_Initialize_Context (Buffer);
 261    end Initialize_Context;
 262 
 263    --------------------
 264    -- Initialize_CPU --
 265    --------------------
 266 
 267    procedure Initialize_CPU is
 268    begin
 269       CPU_Specific.Initialize_CPU;
 270    end Initialize_CPU;
 271 
 272    -------------
 273    -- Set_MSR --
 274    -------------
 275 
 276    --  Note: there is no context synchronization. If required, this must be
 277    --  done explicitly by the caller.
 278 
 279    procedure Set_MSR (MSR : MSR_Type) is
 280    begin
 281       Asm ("mtmsr %0",
 282            Inputs => MSR_Type'Asm_Input ("r", MSR),
 283            Volatile => True);
 284    end Set_MSR;
 285 
 286 end System.BB.CPU_Primitives;