Hacking Dragonboot for Atmosphere / generic rcm tools

  • Thread starter Thread starter Corgano
  • Start date Start date
  • Views Views 40,161
  • Replies Replies 50
  • Likes Likes 15

Corgano

Well-Known Member
Newcomer
Joined
Jul 15, 2015
Messages
66
Reaction score
46
Trophies
0
Age
32
XP
542
Country
Canada
I made a modified version of dragonboot for atmosphere / generic RCM dongles. Dragonboot is a payload that loads a payload from SD card - so you'd never need to update the injector, just the SD card. I went one step further and changed the directory from \dragonboot\payload.bin to \atmosphere\reboot_payload.bin. This is the exact same as fusee-primary - however it comes in the atmosphere release and is always up to date. It also means if you have multiple switches running multiple versions of atmosphere (for some reason) the same payload will boot all of them. Completely version agnostic, as long as reboot_payload.bin is there.

TLDR: Put this on your dongle instead of fussee-primary, and you'll never need to update your dongle again

I made this for personal use but figured I'd share. Any recommendations or questions welcome.
 

Attachments

Any source? Github link? Is this the same DragonBoot that was used with the DragonInjector? I used to have one of the test models.

Anyway, running random payloads on a Switch isn't really safe. Hate to be skeptical, but how do we know this is safe and trustworthy?
 
  • Angry
Reactions: PopcornSweetie
Any source? Github link? Is this the same DragonBoot that was used with the DragonInjector? I used to have one of the test models.

Anyway, running random payloads on a Switch isn't really safe. Hate to be skeptical, but how do we know this is safe and trustworthy?
Fair enough. The source is the dragonboot github. I don't know if it's still up, because they got C&D'd by nintendo and the project has been canceled. I only changed a few lines, and recompiled without compression. I basically told it that it was always in mode 0, and retirected that to the atmosphere folder, and had it look for reboot_payload.bin. Apart from that it's mostly unmodified. I could probably cut out a lot of the extraneous code but I couldn't be bothered.

Code:
/*
 * Copyright (c) 2018 Guillem96
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdarg.h>
#include <string.h>

#include "gfx/di.h"
#include "gfx/gfx.h"

#include "mem/heap.h"

#include "soc/hw_init.h"
#include "soc/t210.h"
#include "soc/pmc.h"

#include "core/launcher.h"

#include "utils/util.h"
#include "utils/fs_utils.h"
#include "utils/btn.h"

#define CENTERED_TEXT_START(n) (((1280 - n * CHAR_WIDTH * g_gfx_con.scale) / 2))

extern void pivot_stack(u32 stack_top);
extern u8 get_payload_num(void);

bool g_render_embedded_splash = true;

static inline void setup_gfx()
{
    u32 *fb = display_init_framebuffer();
    gfx_init_ctxt(&g_gfx_ctxt, fb, 1280, 720, 720);
    gfx_clear_color(&g_gfx_ctxt, 0xFF000000);
    gfx_con_init(&g_gfx_con, &g_gfx_ctxt);
    g_gfx_con.scale = 1;
}

void display_logo_with_message(int count, ...)
{
    /* vardiac arg list for multiple strings. */
    va_list strs;
    va_start(strs, count);

    /* save the scale factor so we can restore it later. */
    u8 scale_old = g_gfx_con.scale;

    if(g_render_embedded_splash)
    {
        /* set scale and position for logo */
        g_gfx_con.scale = 3;
        g_gfx_con.x = 370;
        g_gfx_con.y = 98;

        /* print logo.                                     */
        /* Logo chars are stored as part of the font,      */
        /* outside of normal ascii range.                  */
        /* The logo is comprised of 4 rows and 12 columns. */
        for(char i = 0; i < 4; i++)
        {
            for(char j = 0; j < 12; j++)
            {
                gfx_putc(&g_gfx_con, (i * 12) + j + 0x7F);
            }
            gfx_putc(&g_gfx_con, '\n');
            g_gfx_con.x = 370;
        }
    }

    /* set scale and y position for text. */
    g_gfx_con.scale = 1;
    g_gfx_con.y = 593;

    /* Allocate space for pointers to each string,                   */
    /* along with var to hold total number of chars to print         */
    /* and starting index to keep track of already processed strings */
    char **str_ptrs = malloc(count * sizeof(char *));
    int start = 0;
    int total_len = 0;
    for(int i = 0; i <= count; i++)
    {
        /* Get next string from va list */
        char *str = va_arg(strs, char *);
        str_ptrs[i] = str;

        /* Handle newlines separately, so text centering isn't thrown off, */
        /* and print characters that haven't been printed yet.             */
        if(str[0] == '\n' || i == count)
        {
            /* Set text position. Center text horizontally. */
            g_gfx_con.x = CENTERED_TEXT_START(total_len);

            /* Print each string, starting at calculated x position. */
            for(int j = start; j < i; j++)
                gfx_puts(&g_gfx_con, str_ptrs[j]);

            /* Next string to worry about is after current string.        */
            /* Reset number of characters to print to zero for next line. */
            start = i + 1;
            total_len = 0;

            gfx_putc(&g_gfx_con, '\n');
            continue;
        }

        total_len += strlen(str);
    }
    /* Free list of pointers. */
    free(str_ptrs);
    str_ptrs = 0;

    /* Restore the scale factor. */
    g_gfx_con.scale = scale_old;
}

void find_and_launch_payload(const char *folder)
{
    DIR dir;
    FILINFO finfo;
    //~ FRESULT res = f_findfirst(&dir, &finfo, folder, "*.bin");
    FRESULT res = f_findfirst(&dir, &finfo, folder, "reboot_payload.bin");
    if(res == FR_OK && (strlen(finfo.fname) != 0))
    {
        size_t path_size = strlen(finfo.fname) + strlen(folder) + 2;
        char *payload_path = malloc(path_size);
        if(payload_path != NULL)
        {
            memset(payload_path, 0, path_size);
            strcpy(payload_path, folder);
            strcat(payload_path, "/");
            strcat(payload_path, finfo.fname);
            if(g_render_embedded_splash)
                display_logo_with_message(2, "Launching ", payload_path);
            msleep(5000);
            launch_payload(payload_path);
        }
    }
    else if((strlen(finfo.fname) == 0) && (res != FR_NO_PATH))
    {
        g_gfx_con.fgcol = 0xFFFF0000;
        display_logo_with_message(5, "No payload found in ", folder, "!", "\n", "Press any button to reboot into RCM.");
    }
    else if(res == FR_NO_PATH)
    {
        g_gfx_con.fgcol = 0xFFFF0000;
        display_logo_with_message(7, "Folder not found!", "\n", "Please create ", folder, " on your SD card and add your payload to it.", "\n", "Press any button to reboot into RCM.");
    }
}

void ipl_main()
{
    config_hw();

    /* Init the stack and the heap */
    pivot_stack(0x90010000);
    heap_init(0x90020000);

    /* Init display and gfx module */
    display_init();
    setup_gfx();
    display_backlight_pwm_init();
    display_backlight_brightness(100, 1000);

    //~ u8 payload_num = get_payload_num() + 1;
    u8 payload_num = 0;

    if(sd_mount())
    {
        if(sd_file_read("dragonboot/splash.raw", g_gfx_ctxt.next))
        {
            g_render_embedded_splash = false;
            gfx_swap_buffer(&g_gfx_ctxt);
        }

        if(payload_num == 0)
            find_and_launch_payload("atmosphere");

        char folder[] = "dragonboot/\0\0\0";

        const char *num_table[] = { "00", "01", "02", "03", "04", "05", "06", "07", "08" };
        strcat(folder, num_table[payload_num]);

        find_and_launch_payload(folder);
    }
    else
    {
        g_gfx_con.fgcol = 0xFFFF0000;
        display_logo_with_message(3, "SD card not inserted!", "\n", "Press any button to reboot into RCM.");
    }

    btn_wait();
    PMC(APBDEV_PMC_SCRATCH0) |= 2;
    PMC(APBDEV_PMC_CNTRL) = PMC_CNTRL_MAIN_RST;
    while(1);
}
 
Last edited by Corgano,
Is there a hardware compatibility list? It's hard for me to believe this is universal to every single dongle?

It's universal to every single dongle the same way that Atmosphere, SX OS, Hekate, and any other payload is. The dongle itself isn't running the code, the Switch is. This is a "mini-payload" that's sole purpose is to boot a different payload (atmosphere/reboot_payload.bin) from the microSD card.
 
Is there a hardware compatibility list? It's hard for me to believe this is universal to every single dongle?
It's universal to rcm injectors in the sense that rcm injectors are designed to inject payloads. This is just a payload.

In contrast the original dragonboot was specific to an injector that supports the compression used - the dragon injector. Technically any rcm injector that can understand compressed payloads could inject dragonboot stock payload.
 
Last edited by Corgano,
It looks very useful. Always a drag to update the dongle payload. I'm happy to do it for one last time. Thanks for sharing!
 
  • Like
Reactions: Corgano
Can i use this with a trinket m0?
That's a great question. IDK

Basically any standard payload injector with enough space to hold the payload can inject it and it;ll work. IF it works with the standard fusee primary payload it will probably work. Give us a try and let us know.
 
Argon NX does a very similar thing by always chainloading a payload that is named:
sd:\argon\payload.bin
If it doesn't exist, Argon looks for other payloads in a subfolder and shows them in a nice grid like hekate's NYX later did too.

However, I like the idea that it's directly booting the reboot payload in the atmosphere folder.

For those using hekate (like me) I wonder if the All-in-One Updater is putting the hekate payload there if I'm updating Atmosphère and hekate through it. Does anybody know?
 
you could give ti a shot updating using it, and then do a diff on that file and fusee-primary
 
Argon NX does a very similar thing by always chainloading a payload that is named:
sd:\argon\payload.bin
If it doesn't exist, Argon looks for other payloads in a subfolder and shows them in a nice grid like hekate's NYX later did too.

However, I like the idea that it's directly booting the reboot payload in the atmosphere folder.

For those using hekate (like me) I wonder if the All-in-One Updater is putting the hekate payload there if I'm updating Atmosphère and hekate through it. Does anybody know?
I think it does since Hekate is by far the best bootloader.
 
  • Like
Reactions: lordelan
Can I put this in my dragoninjector too?
You can now! I've taken the same approach as @Corgano and slim lined the payload. It simply boots sd:/atmosphere/reboot_payload.bin directly, I removed the splash screen and reduced the wait. Attached is a zip that contains both the BIN for use with other loaders as well as the UF2 file for those with actual DragonInjectors. Simply plug your DragonInjector into your computer and drag and drop the UF2 file into the drive that appears. The drive will disappear and re-appear again when the flashing is done. If you'd like to go back to original DragonInjector firmware you can download it here: https://github.com/jeromedontdev/DragonInjector-FW/releases/tag/DI_FW_1.00
 

Attachments

Just an update to this. with the recent atmosphere 1.0.0 and newer releases fusee_primary no longer exists.

However this still just works perfectly. I havn't updated my dongle (or tegra RCM tool default on my pc, rekado automatic injecting payload) in over a year. It just fucking works.
 

Site & Scene News

Popular threads in this forum