/**
 * Copyright (C) 2023-2026 Linaro Limited (or its affiliates). All rights reserved.
 * Copyright (C) 2013-2023 Arm Limited (or its affiliates).
 * All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 */

#include <stdlib.h>     /* size_t, ... */

void initializeStack(void *data, int size, void (*entry)(),
                     void **stackBase, void **stackPointer)
{
    void* stackBottom = (char*)data + size;
    // align to 8 byte (doubleword)
    stackBottom = (void*)((size_t)stackBottom & ~0x7);

    void **p = (void**)stackBottom;
    *stackBase = stackBottom;

 /*
    This is what we initially need for _switchStackInternal:

                   Frame 0                           stackPointer (low address)
            +-------------------+
            |%o0                |
            |... 0xFF (rubbish) |                 (rubbish = it doesn't matter)
            |%o7                |
            +-------------------+
            |%l0                |
            |... 0xFF (rubbish) |
            |%l7                |      Frame 1
            +-------------------+-------------------+
            |%i0 ... %i5 (0xFF) |%o0...5  (rubbish) |
            |%i6 = <frame ptr>  |%o6 = <stack ptr>  |                 (Overlap)
            |%i7 = <entry> - 8  |%o7 = <entry> - 8  |
            +-------------------+-------------------+
                                |%l0                |
                                |... 0xFF (rubbish) |
                                |%l7                |
                                +-------------------+
                                |%i0                |
                                |... 0xFF (rubbish) |
                                |%i7                |
                                +-------------------+
                                                    stackBottom  (high address)

    (Don't put too much into that picture, just my understanding.)

    Also, I'm not sure if rubbish in %o6 (frame 0) and %i6 (frame 1) is
    really fine.

    To-do: CCFSZ=192, explain OFFSET, other registers to save? is fill ok?
           (gdb) bt # while switching
 */

    #define FILL(N,P,V) for (int i=0; i < (N); i++) *(P) = (void*)(long)(V);
    #define OFFSET(x) (void**)((char*)((x)-1)-1967)

    FILL(16, --p, 0xFF);

    *(--p) = ((void**)entry)-1; // %i ret = jmp %i7 + 8

    void **fp = --p;
    FILL(7, --p, 0xFF);

    *fp = OFFSET(p);

    FILL(16, --p, 0xFF);

    *stackPointer = OFFSET(p);
}
