SELFOUR-276: Add MCP field to threads.

Where MCP = Maximum Controlled Priority

This commit adds:

* seL4_TCB_SetMCPriority

and changes the arguments to

* seL4_TCB_Configure

As of this commit, a thread cannot create or set a threads
priority (including itself) above its mcp. Previously the kernel
did this check against a threads priority, which prevented a thread
from setting it's own priority down and then up again.
This commit is contained in:
Anna Lyons
2016-06-09 12:15:45 +10:00
committed by Anna Lyons
parent 43772b2dc2
commit 7336303b7f
13 changed files with 170 additions and 29 deletions

View File

@@ -98,6 +98,15 @@ wordFromMessageInfo(seL4_MessageInfo_t mi)
return mi.words[0];
}
static inline seL4_PrioProps_t CONST
prioPropsFromWord(word_t w)
{
seL4_PrioProps_t pp;
pp.words[0] = w;
return pp;
}
#define allRights cap_rights_new(true, true, true)
#define noWrite cap_rights_new(true, true, false)

View File

@@ -58,6 +58,7 @@ void switchToThread(tcb_t *thread) VISIBLE;
void switchToIdleThread(void);
void setDomain(tcb_t *tptr, dom_t dom);
void setPriority(tcb_t *tptr, prio_t prio);
void setMCPriority(tcb_t *tptr, prio_t mcp);
void scheduleTCB(tcb_t *tptr);
void attemptSwitchTo(tcb_t *tptr);
void switchIfRequiredTo(tcb_t *tptr);

View File

@@ -213,6 +213,9 @@ struct tcb {
/* Domain, 1 byte (packed to 4) */
dom_t tcbDomain;
/* maximum controlled priorioty, 1 byte (packed to 4) */
prio_t tcbMCP;
/* Priority, 1 byte (packed to 4) */
prio_t tcbPriority;

View File

@@ -70,6 +70,7 @@ exception_t decodeWriteRegisters(cap_t cap, word_t length, word_t *buffer);
exception_t decodeTCBConfigure(cap_t cap, word_t length,
cte_t* slot, extra_caps_t rootCaps, word_t *buffer);
exception_t decodeSetPriority(cap_t cap, word_t length, word_t *buffer);
exception_t decodeSetMCPriority(cap_t cap, word_t length, word_t *buffer);
exception_t decodeSetIPCBuffer(cap_t cap, word_t length,
cte_t* slot, extra_caps_t excaps, word_t *buffer);
exception_t decodeSetSpace(cap_t cap, word_t length,
@@ -83,7 +84,8 @@ enum thread_control_flag {
thread_control_update_priority = 0x1,
thread_control_update_ipc_buffer = 0x2,
thread_control_update_space = 0x4,
thread_control_update_all = 0x7,
thread_control_update_mcp = 0x8,
thread_control_update_all = 0xF,
};
typedef word_t thread_control_flag_t;
@@ -91,7 +93,7 @@ typedef word_t thread_control_flag_t;
exception_t invokeTCB_Suspend(tcb_t *thread);
exception_t invokeTCB_Resume(tcb_t *thread);
exception_t invokeTCB_ThreadControl(tcb_t *target, cte_t* slot, cptr_t faultep,
prio_t priority, cap_t cRoot_newCap,
prio_t mcp, prio_t priority, cap_t cRoot_newCap,
cte_t *cRoot_srcSlot, cap_t vRoot_newCap,
cte_t *vRoot_srcSlot, word_t bufferAddr,
cap_t bufferCap, cte_t *bufferSrcSlot,

View File

@@ -43,7 +43,7 @@
</method>
<method id="TCBConfigure" name="Configure">
<param dir="in" name="fault_ep" type="seL4_Word"/>
<param dir="in" name="priority" type="seL4_Uint8"/>
<param dir="in" name="priority" type="seL4_PrioProps_t"/>
<param dir="in" name="cspace_root" type="seL4_CNode"/>
<param dir="in" name="cspace_root_data" type="seL4_CapData_t"/>
<param dir="in" name="vspace_root" type="seL4_CNode"/>
@@ -54,6 +54,9 @@
<method id="TCBSetPriority" name="SetPriority">
<param dir="in" name="priority" type="seL4_Uint8"/>
</method>
<method id="TCBSetMCPriority" name="SetMCPriority">
<param dir="in" name="mcc" type="seL4_Uint8"/>
</method>
<method id="TCBSetIPCBuffer" name="SetIPCBuffer">
<param dir="in" name="buffer" type="seL4_Word"/>
<param dir="in" name="bufferFrame" type="seL4_CPtr"/>

View File

@@ -18,3 +18,9 @@ block seL4_MessageInfo {
field extraCaps 2
field length 7
}
block seL4_PrioProps {
padding 16
field mcp 8
field prio 8
}

View File

@@ -219,6 +219,7 @@ def init_data_types(wordsize):
# seL4 Structures
BitFieldType("seL4_CapData_t", wordsize, wordsize),
BitFieldType("seL4_PrioProps_t", wordsize, wordsize),
# Object types
CapType("seL4_CPtr", wordsize),

View File

@@ -84,6 +84,7 @@
\newcommand{\archflagsdesc}{Architecture dependent flags. These have no meaning on \ifxeightsix{either IA-32 or}\fi{} ARM.}
\newcommand{\threadpriodesc}{The thread's new priority.}
\newcommand{\threadmaxpriodesc}{The thread's new maximum controlled priority.}
\newcommand{\threadcspacerootdesc}{The new CSpace root.}
\newcommand{\threadcspacedatadesc}{Optionally set the guard and guard size of the new root CNode. If set to zero, this parameter has no effect.}
\newcommand{\threadvspacerootdesc}{The new VSpace root.}
@@ -270,6 +271,7 @@ complete the \apifunc{seL4\_Untyped\_Retype}{untyped_retype} request.
\inputapidoc{tcb_resume}
\inputapidoc{tcb_setipcbuffer}
\inputapidoc{tcb_setpriority}
\inputapidoc{tcb_setmcpriority}
\inputapidoc{tcb_setspace}
\inputapidoc{tcb_suspend}
\inputapidoc{tcb_writeregisters}

View File

@@ -0,0 +1,21 @@
%
% Copyright 2014, General Dynamics C4 Systems
%
% This software may be distributed and modified according to the terms of
% the GNU General Public License version 2. Note that NO WARRANTY is provided.
% See "LICENSE_GPLv2.txt" for details.
%
% @TAG(GD_GPL)
%
\apidoc
{tcb_setmcpriority}
{TCB - Set Maximum Controlled Priority}
{Change a thread's maximum controlled priority}
{static inline int seL4\_TCB\_SetMCPriority }
{
\param{seL4\_TCB}{\_service}{\tcbcapdesc}
\param{uint8\_t}{mcp}{\threadmaxpriodesc}
}
{\errorenumdesc}
{See \autoref{sec:sched}}

View File

@@ -58,10 +58,12 @@ deleted.
\label{sec:sched}
seL4 uses a preemptive round-robin scheduler with 256 priority levels.
When a thread creates or modifies another thread, it can only set the
other thread's priority to be lower than or equal to its own. Thread priority can be
All threads have a maximum controlled priority (MCP) and a priority, the latter being the effective
priority of the thread.
When a thread creates or modifies a thread (including itself), it can only set the
other thread's priority and MCP to be less than or equal to its own MCP. Thread priority and MCP can be
set with \apifunc{seL4\_TCB\_Configure}{tcb_configure} and
\apifunc{seL4\_TCB\_SetPriority}{tcb_setpriority} methods.
\apifunc{seL4\_TCB\_SetPriority}{tcb_setpriority}, \apifunc{seL4\_TCB\_SetMCPriority}{tcb_setmcpriority} methods.
\subsection{Exceptions}

View File

@@ -413,6 +413,7 @@ create_initial_thread(
/* initialise TCB */
tcb->tcbPriority = seL4_MaxPrio;
tcb->tcbMCP = seL4_MaxPrio;
setupReplyMaster(tcb);
setThreadState(tcb, ThreadState_Running);
ksSchedulerAction = tcb;

View File

@@ -360,6 +360,12 @@ setDomain(tcb_t *tptr, dom_t dom)
}
}
void
setMCPriority(tcb_t *tptr, prio_t mcp)
{
tptr->tcbMCP = mcp;
}
void
setPriority(tcb_t *tptr, prio_t prio)
{

View File

@@ -24,6 +24,42 @@
#include <util.h>
#include <string.h>
#define NULL_PRIO 0
static exception_t
checkPrio(prio_t prio)
{
prio_t mcp;
mcp = ksCurThread->tcbMCP;
/* can't create a thread with prio greater than our own mcp */
if (prio > mcp) {
current_syscall_error.type = seL4_RangeError;
current_syscall_error.rangeErrorMin = seL4_MinPrio;
current_syscall_error.rangeErrorMax = mcp;
return EXCEPTION_SYSCALL_ERROR;
}
return EXCEPTION_NONE;
}
static exception_t
checkMCP(prio_t mcp)
{
if (checkPrio(mcp) != EXCEPTION_NONE) {
return EXCEPTION_SYSCALL_ERROR;
}
if (mcp > seL4_MaxPrio) {
current_syscall_error.type = seL4_RangeError;
current_syscall_error.rangeErrorMin = seL4_MinPrio;
current_syscall_error.rangeErrorMax = seL4_MaxPrio;
return EXCEPTION_SYSCALL_ERROR;
}
return EXCEPTION_NONE;
}
static inline void
addToBitmap(word_t dom, word_t prio)
{
@@ -319,6 +355,9 @@ decodeTCBInvocation(word_t invLabel, word_t length, cap_t cap,
case TCBSetPriority:
return decodeSetPriority(cap, length, buffer);
case TCBSetMCPriority:
return decodeSetMCPriority(cap, length, buffer);
case TCBSetIPCBuffer:
return decodeSetIPCBuffer(cap, length, slot, excaps, buffer);
@@ -486,8 +525,10 @@ decodeTCBConfigure(cap_t cap, word_t length, cte_t* slot,
cap_t bufferCap, cRootCap, vRootCap;
deriveCap_ret_t dc_ret;
cptr_t faultEP;
word_t prio;
seL4_PrioProps_t props;
prio_t prio, mcp;
word_t cRootData, vRootData, bufferAddr;
exception_t status;
if (length < 5 || rootCaps.excaprefs[0] == NULL
|| rootCaps.excaprefs[1] == NULL
@@ -497,11 +538,11 @@ decodeTCBConfigure(cap_t cap, word_t length, cte_t* slot,
return EXCEPTION_SYSCALL_ERROR;
}
faultEP = getSyscallArg(0, buffer);
prio = getSyscallArg(1, buffer);
cRootData = getSyscallArg(2, buffer);
vRootData = getSyscallArg(3, buffer);
bufferAddr = getSyscallArg(4, buffer);
faultEP = getSyscallArg(0, buffer);
props = prioPropsFromWord(getSyscallArg(1, buffer));
cRootData = getSyscallArg(2, buffer);
vRootData = getSyscallArg(3, buffer);
bufferAddr = getSyscallArg(4, buffer);
cRootSlot = rootCaps.excaprefs[0];
cRootCap = rootCaps.excaprefs[0]->cap;
@@ -510,13 +551,23 @@ decodeTCBConfigure(cap_t cap, word_t length, cte_t* slot,
bufferSlot = rootCaps.excaprefs[2];
bufferCap = rootCaps.excaprefs[2]->cap;
prio = prio & MASK(8);
prio = seL4_PrioProps_get_prio(props);
mcp = seL4_PrioProps_get_mcp(props);
if (prio > ksCurThread->tcbPriority) {
userError("TCB Configure: Requested priority %d too high (max %d).",
(int)prio, (int)(ksCurThread->tcbPriority));
current_syscall_error.type = seL4_IllegalOperation;
return EXCEPTION_SYSCALL_ERROR;
status = checkPrio(prio);
if (status != EXCEPTION_NONE) {
userError("TCB Configure: Requested priority %lu too high (max %lu).",
(unsigned long) prio, (unsigned long) ksCurThread->tcbMCP);
return status;
}
status = checkMCP(mcp);
if (status != EXCEPTION_NONE) {
userError("Requested maximum controlled priority %lu too high (max %lu),",
(unsigned long) mcp,
(unsigned long) prio >= seL4_MaxPrio ? seL4_MaxPrio :
ksCurThread->tcbMCP);
return status;
}
if (bufferAddr == 0) {
@@ -578,7 +629,7 @@ decodeTCBConfigure(cap_t cap, word_t length, cte_t* slot,
setThreadState(ksCurThread, ThreadState_Restart);
return invokeTCB_ThreadControl(
TCB_PTR(cap_thread_cap_get_capTCBPtr(cap)), slot,
faultEP, prio,
faultEP, mcp, prio,
cRootCap, cRootSlot,
vRootCap, vRootSlot,
bufferAddr, bufferCap,
@@ -589,6 +640,7 @@ exception_t
decodeSetPriority(cap_t cap, word_t length, word_t *buffer)
{
prio_t newPrio;
exception_t status;
if (length < 1) {
userError("TCB SetPriority: Truncated message.");
@@ -600,24 +652,53 @@ decodeSetPriority(cap_t cap, word_t length, word_t *buffer)
/* assuming here seL4_MaxPrio is of form 2^n - 1 */
newPrio = newPrio & MASK(8);
status = checkPrio(newPrio);
if (status != EXCEPTION_NONE) {
userError("TCB SetPriority: Requested priority %lu too high (max %lu).",
(unsigned long) newPrio, (unsigned long ) ksCurThread->tcbMCP);
return status;
if (newPrio > ksCurThread->tcbPriority) {
userError("TCB SetPriority: Requested priority %d too high (max %d).",
(int)newPrio, (int)ksCurThread->tcbPriority);
current_syscall_error.type = seL4_IllegalOperation;
return EXCEPTION_SYSCALL_ERROR;
}
setThreadState(ksCurThread, ThreadState_Restart);
return invokeTCB_ThreadControl(
TCB_PTR(cap_thread_cap_get_capTCBPtr(cap)), NULL,
0, newPrio,
0, NULL_PRIO, newPrio,
cap_null_cap_new(), NULL,
cap_null_cap_new(), NULL,
0, cap_null_cap_new(),
NULL, thread_control_update_priority);
}
exception_t
decodeSetMCPriority(cap_t cap, word_t length, word_t *buffer)
{
prio_t newMcp;
exception_t status;
if (length < 1) {
userError("TCB SetMCPriority: Truncated message.");
current_syscall_error.type = seL4_TruncatedMessage;
return EXCEPTION_SYSCALL_ERROR;
}
newMcp = (prio_t) getSyscallArg(0, buffer);
status = checkMCP(newMcp);
if (status != EXCEPTION_NONE) {
return status;
}
setThreadState(ksCurThread, ThreadState_Restart);
return invokeTCB_ThreadControl(
TCB_PTR(cap_thread_cap_get_capTCBPtr(cap)), NULL,
0, newMcp, NULL_PRIO,
cap_null_cap_new(), NULL,
cap_null_cap_new(), NULL,
0, cap_null_cap_new(),
NULL, thread_control_update_mcp);
}
exception_t
decodeSetIPCBuffer(cap_t cap, word_t length, cte_t* slot,
extra_caps_t excaps, word_t *buffer)
@@ -656,8 +737,7 @@ decodeSetIPCBuffer(cap_t cap, word_t length, cte_t* slot,
setThreadState(ksCurThread, ThreadState_Restart);
return invokeTCB_ThreadControl(
TCB_PTR(cap_thread_cap_get_capTCBPtr(cap)), slot,
0,
0, /* used to be prioInvalid, but it doesn't matter */
0, NULL_PRIO, NULL_PRIO,
cap_null_cap_new(), NULL,
cap_null_cap_new(), NULL,
cptr_bufferPtr, bufferCap,
@@ -735,7 +815,7 @@ decodeSetSpace(cap_t cap, word_t length, cte_t* slot,
return invokeTCB_ThreadControl(
TCB_PTR(cap_thread_cap_get_capTCBPtr(cap)), slot,
faultEP,
0, /* used to be prioInvalid, but it doesn't matter */
NULL_PRIO, NULL_PRIO,
cRootCap, cRootSlot,
vRootCap, vRootSlot,
0, cap_null_cap_new(), NULL, thread_control_update_space);
@@ -870,7 +950,7 @@ invokeTCB_Resume(tcb_t *thread)
exception_t
invokeTCB_ThreadControl(tcb_t *target, cte_t* slot,
cptr_t faultep, prio_t priority,
cptr_t faultep, prio_t mcp, prio_t priority,
cap_t cRoot_newCap, cte_t *cRoot_srcSlot,
cap_t vRoot_newCap, cte_t *vRoot_srcSlot,
word_t bufferAddr, cap_t bufferCap,
@@ -884,6 +964,10 @@ invokeTCB_ThreadControl(tcb_t *target, cte_t* slot,
target->tcbFaultHandler = faultep;
}
if (updateFlags & thread_control_update_mcp) {
setMCPriority(target, mcp);
}
if (updateFlags & thread_control_update_priority) {
setPriority(target, priority);
}