BSP dev-kit

From DDCIDeos
Jump to navigationJump to search

Description

This project is to describe the ongoing care and feeding of the BSP dev-kit.

At this point it is mostly ideas for discussion.

Proposal for general direction

Customization (for a particular board) of basic BSP functionality should be minimized, i.e., made "common". That way we can provide tests and not customize the software. The following features should always be supported:

  1. Mode changing
  2. Boot Image Files (BIF) archives including selection
    1. Basic selection logic can be, e.g., "if first fails go to next".
    2. backup images, etc.
  3. NVM that can be used with the U-Boot "load" command as an alternative means of booting (if available)
    1. Longer term, with the advent of vFile & Friends, I'd like OpenArbor to support "puts" of DeosBoot.bin and the BIFs into NVM on a board such that this "alternate means" has a way to program the images as well as boot them. When we add this support to OA, it would be great to also add the capability to move these images to a TFTPServer. That way OA can be used to "program" any boot method we document in a reference BSP. As I write this, I'll take care of the OA PCR for this paragraph and would like your team to take care of the PCR(s) for the above paragraph as I am not sure which BSP(s) have U-boot-able NVM on them.
    2. This is a BC suggestion from an email on 2023-04-11.
  4. PRL or PAL handled interrupts, e.g., for KMI?
  5. External Clock Synchronization (already implemented)
  6. PCI config
  7. TDL support
  8. OpenArbor, BSP, Boot Image Files
  9. PAL Extensions

Related Projects

TODO/Issues/Tasks

  1. Remove uni-core support from dev-kit (partly done already).
  2. Remove legacy types from dev-kit (partly done, incremental approach proposed).
  3. Make the core reference platforms "diff" similar. I.e., a "diff" shows no gratuitous differences, only semantic ones.
    1. E.g., surcouf and imx8 BSP UGs are very different, qemu-arm and sucouf are closer. What is desired pattern?
    2. imx8 implements PALInterruptHandler, and several other things previously in dev-kit, is that ok?
  4. Take better advantage of device-tree.
    1. Boot gets from device-tree:
      • num cores, or at least the release mechanism (e.g., PSCI vs spin-table).
    2. PAL gets
      1. address of interrupt controller
      2. properties of interrupts (e.g., edge vs level sensitive),
      3. which network interrupts to aggregate
    3. document performance benchmarking (mostly done)
    4. configure serial output for basic startup messages.
  5. README in boot and PAL that describes where the entrypoint is, and if divergent from dev-kit the control flow. Probably have a standard control flow in the dev-kit someplace. E.g., which pattern is followed.
  6. It is possible, perhaps even likely, that we will one day get a boot and PAL that support several platforms, but config is less likely (due to hard coded numbers in the registry). Should board specific things, e.g., the UG, get moved to config?

PAL

  1. resolve kernel/PAL interface changes
    1. removal of broadcast flag from unmaskPlatformInterrupt.
    2. rename of interruptAcknowledge
  2. get rid of "custom" layer.
    1. Nearly done, PALcoldstart and PALInterruptHandler still have content.
  3. add support for aggregating interrupts as part of the dev-kit proper. e.g., aggregateInterrupts(1, 2, 3, 4) for all the enet interrupts.
    1. See #Aggregated_Interrupt_Example
  4. logical vs platform vs physical interrupts
    • dev-kit used LOGICAL in case Deos defined interrupts (timer, tick, window) were not included in "platform" interrupts. Is that necessary?
  5. interrupt number vs interrupt ID

Boot

  1. get rid of board specific entry.S file

Config

  1. cffs example uses 45MB of RAM with no good way to reclaim it.
  2. Provide minimal basecon.hyp configuration suitable for satisfying kernel tests (i.e., test-component-kernel.cfg) as part of the BSP. E.g., minimal-kfs.hyp

Sample code fragments

Aggregated_Interrupt_Example

// MHdr-beg ***********************************************************************
//
// Copyright DDC-I, Inc. 2018
// Copyright Honeywell International, Inc.2018
// All Rights Reserved
//
// DDC-I Proprietary
//
// Purpose: See header file.
//
// MPrj-beg **********************************************************************
// MPrj-end **********************************************************************
// MHdr-end **********************************************************************


#include <stdint.h>
#include <systyp.h>
#include <dprintf.h>

// A list of interrupts.
typedef struct
{
  // The number of "interrupts".  Must be >0.
  uint32_t numInterrupts;
  uint32_t interrupts[];
} InterruptList;

// A table of sets of interrupts that should be reported to the kernel as a
// single interrupt.  For example to permit several interrupts to be asociated
// with a single Deos ISR thread.  Each list of interrupts describes interrupts
// that should be aggregated.  The first interrupt in each list is reported when
// any of the interrupts in the list are handled, and all are masked/unmasked
// when the first is requested to be masked or unmasked.
typedef struct
{
  uint32_t maxInterruptLists;
  uint32_t numInterruptLists;
  InterruptList **interruptLists;
} AggregatedInterrupts;

void aggInt_init(AggregatedInterrupts *aggInts, InterruptList *interruptLists[], uint32_t interruptListsLength)
{
  aggInts->maxInterruptLists = interruptListsLength;
  aggInts->numInterruptLists = 0;
  aggInts->interruptLists = interruptLists;
}

void aggInt_addList(AggregatedInterrupts *aggInts, InterruptList *interruptLists)
{
  DASSERT(aggInts->numInterruptLists<aggInts->maxInterruptLists,
          "Attempt to add more interrupt lists than were allocated.");
  aggInts->numInterruptLists++;
  aggInts->interruptLists[aggInts->numInterruptLists] = interruptLists;
}


uint32_t aggInt_interruptToRaise(const AggregatedInterrupts *aggInts, uint32_t intRaised)
{
  for (uint_fast32_t ai=0; ai<aggInts->numInterruptLists; ai++)
  {
    InterruptList const *intList = aggInts->interruptLists[ai];
    for (uint_fast32_t i=0; i<intList->numInterrupts; i++)
    {
      if (intList->interrupts[i] == intRaised)
      {
        return intList->interrupts[0];
      }
    }
  }
  return intRaised;
}

// If intAskedToBeMasked is an aggregated interrupt destination then return the
// list of all the aggregated interrupts, otherwise return the
// intAskedToBeMasked.  numToMask will be set to the number of interrupts to be
// masked in either case, and will always be greater than 0.
void aggInt_interruptToMask(const AggregatedInterrupts *aggInts, 
                            const uint32_t *intAskedToBeMasked,
                            const uint32_t **intToMask,
                            uint32_t *numToMask)
{
  for (uint_fast32_t ai=0; ai<aggInts->numInterruptLists; ai++)
  {
    InterruptList const *intList = aggInts->interruptLists[ai];
    if (intList->interrupts[0] == *intAskedToBeMasked)
    {
      *numToMask = intList->numInterrupts;
      *intToMask = intList->interrupts;
    }
  }
  *numToMask = 1;
  *intToMask = intAskedToBeMasked;
}

// If we had a verified BSP, we *could* still use this package and using
// something like the exampleWithConstants branch below.
#ifdef exampleWithConstants
static InterruptList enet0 = {4, { 1,  3,  5,  7}};
static InterruptList enet1 = {4, {11, 13, 15, 17}};
static InterruptList enet2 = {4, {21, 23, 25, 27}};
InterruptList *aggregatedInterruptList[] = {&enet0, &enet1, &enet2};
AggregatedInterrupts aggregatedInterrupts = {.maxInterruptLists = sizeof(aggregatedInterruptList)/sizeof(aggregatedInterruptList[0]),
                                             .numInterruptLists = sizeof(aggregatedInterruptList)/sizeof(aggregatedInterruptList[0]),
                                             .interruptLists = aggregatedInterruptList};
#else
static InterruptList enet0 = {4, { 1,  3,  5,  7}};
static InterruptList enet1 = {4, {11, 13, 15, 17}};
static InterruptList enet2 = {4, {21, 23, 25, 27}};
InterruptList *aggregatedInterruptList[10];
AggregatedInterrupts aggregatedInterrupts;

void PALcoldstart()
{
  aggInt_init(&aggregatedInterrupts, aggregatedInterruptList, sizeof(aggregatedInterruptList)/sizeof(aggregatedInterruptList[0]));
  aggInt_addList(&aggregatedInterrupts, &enet0);
  aggInt_addList(&aggregatedInterrupts, &enet1);
  aggInt_addList(&aggregatedInterrupts, &enet2);
}

#endif // exampleWithConstants

void PALInterruptHandler()
{
  uint32_t intNum = 7;  // determine interrupt number
  // logic for non-platform interrupts omitted.
  uint32_t intToRaise = aggInt_interruptToRaise(&aggregatedInterrupts, intNum);
  // clear intNum
  // raisePlatformInterrupt(intToRaise);
}

// mask and unmask could be left in the PAL, or factored to a common file.
// Either way the change to accomodate the above would look like this:
void maskPlatformInterrupt(platformInterruptNumber_t intToMask)
{
  // If the interrupts in the table are not platform interrupts, then there
  // would be conversion here.
  const uint32_t *intsToMask;
  uint32_t numToMask;
  aggInt_interruptToMask(&aggregatedInterrupts, &intToMask, &intsToMask, &numToMask);
  for (uint_fast32_t i=0; i<numToMask; i++)
  {
    //gic_mask(..., intsToMask[i]);
  }
}