Boot/Launch Initial Code (SDC)
Added initial code to support launching code on boot. Currently should just boot from FNXBOOT.{PGX,PGZ,ELF}.
This commit is contained in:
parent
d42e892b45
commit
e2efc7e9bb
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -50,3 +50,4 @@ modules.order
|
||||||
Module.symvers
|
Module.symvers
|
||||||
Mkfile.old
|
Mkfile.old
|
||||||
dkms.conf
|
dkms.conf
|
||||||
|
.vscode/settings.json
|
||||||
|
|
|
@ -6,9 +6,7 @@ To recognize a program or bootable module in RAM or flash, the toolbox needs a s
|
||||||
| ---- | ----- |
|
| ---- | ----- |
|
||||||
| 0 | Signature: $F8 |
|
| 0 | Signature: $F8 |
|
||||||
| 1 | Signature: $16 |
|
| 1 | Signature: $16 |
|
||||||
| 2 | Size of the program in 8KB blocks |
|
| 2 -- 5 | Starting address of the program, little-endian format |
|
||||||
| 3 | Reserved |
|
|
||||||
| 4 -- 5 | Starting address of the program, little-endian format |
|
|
||||||
| 6 | Header structure version number |
|
| 6 | Header structure version number |
|
||||||
| 7 -- 9 | Reserved |
|
| 7 -- 9 | Reserved |
|
||||||
| 10 -- m | Zero-terminated string: name of the program |
|
| 10 -- m | Zero-terminated string: name of the program |
|
||||||
|
|
|
@ -9,13 +9,13 @@
|
||||||
(section (registers ztiny)))
|
(section (registers ztiny)))
|
||||||
(memory LoRAM (address (#x00c100 . #x00efff))
|
(memory LoRAM (address (#x00c100 . #x00efff))
|
||||||
(section stack data zdata data heap))
|
(section stack data zdata data heap))
|
||||||
(memory NearRAM1 (address (#x010000 . #x017fff))
|
(memory NearRAM1 (address (#x350000 . #x357fff))
|
||||||
(section znear near))
|
(section znear near))
|
||||||
(memory NearRAM2 (address (#x018000 . #x01ffff))
|
(memory NearRAM2 (address (#x358000 . #x35ffff))
|
||||||
(section cnear))
|
(section cnear))
|
||||||
(memory FarRAM1 (address (#x020000 . #x02ffff))
|
(memory FarRAM1 (address (#x360000 . #x36ffff))
|
||||||
(section far huge))
|
(section far huge))
|
||||||
(memory FarRAM2 (address (#x030000 . #x03ffff))
|
(memory FarRAM2 (address (#x370000 . #x37ffff))
|
||||||
(section zfar zhuge ))
|
(section zfar zhuge ))
|
||||||
(memory LoCode (address (#x00f000 . #x00ffdf)) (scatter-to LoCodeStorage)
|
(memory LoCode (address (#x00f000 . #x00ffdf)) (scatter-to LoCodeStorage)
|
||||||
(section code cdata (jumptable #x00f000)))
|
(section code cdata (jumptable #x00f000)))
|
||||||
|
|
|
@ -56,7 +56,7 @@ else
|
||||||
LDFLAGS=$(LDFLAGS_FOR_UNIT) --list-file toolbox.map
|
LDFLAGS=$(LDFLAGS_FOR_UNIT) --list-file toolbox.map
|
||||||
endif
|
endif
|
||||||
|
|
||||||
SRCS = toolbox.c log.c memory.c proc.c ring_buffer.c simpleio.c sys_general.c utilities.c $(SRCS_FOR_UNIT) # $(C_SRCS_DEBUGGER)
|
SRCS = toolbox.c log.c boot.c memory.c proc.c ring_buffer.c simpleio.c sys_general.c utilities.c $(SRCS_FOR_UNIT) # $(C_SRCS_DEBUGGER)
|
||||||
OBJS = $(patsubst %.s,%.o,$(patsubst %.c,%.o,$(SRCS)))
|
OBJS = $(patsubst %.s,%.o,$(patsubst %.c,%.o,$(SRCS)))
|
||||||
OBJS4RM = $(subst /,\\,$(OBJS))
|
OBJS4RM = $(subst /,\\,$(OBJS))
|
||||||
LIBS = dev/devices.a snd/sound.a fatfs/fatfs.a
|
LIBS = dev/devices.a snd/sound.a fatfs/fatfs.a
|
||||||
|
@ -88,7 +88,7 @@ fatfs/fatfs.a:
|
||||||
|
|
||||||
# Clean up after a build
|
# Clean up after a build
|
||||||
clean:
|
clean:
|
||||||
$(RM) $(OBJS4RM) toolbox.s37 *.lst *.map
|
$(RM) $(OBJS4RM) toolbox.s37 *.lst *.map *.raw
|
||||||
$(MAKE) --directory=dev clean
|
$(MAKE) --directory=dev clean
|
||||||
$(MAKE) --directory=snd clean
|
$(MAKE) --directory=snd clean
|
||||||
$(MAKE) --directory=fatfs clean
|
$(MAKE) --directory=fatfs clean
|
722
src/boot.c
722
src/boot.c
|
@ -1,629 +1,135 @@
|
||||||
/**
|
/**
|
||||||
* @file boot.c
|
* @file boot.c
|
||||||
*
|
* @author your name (you@domain.com)
|
||||||
* Routines to support the boot process
|
* @brief Boot sequence control code for managing loading up the user's control code
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2024-06-09
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2024
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "log_level.h"
|
|
||||||
#ifndef DEFAULT_LOG_LEVEL
|
|
||||||
#define DEFAULT_LOG_LEVEL LOG_TRACE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "sys_general.h"
|
|
||||||
#include "boot.h"
|
#include "boot.h"
|
||||||
#include "constants.h"
|
#include "memory.h"
|
||||||
#include "errors.h"
|
#include "proc.h"
|
||||||
#include "gabe_reg.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "simpleio.h"
|
|
||||||
#include "syscalls.h"
|
|
||||||
#include "vicky_general.h"
|
|
||||||
#include "cli/cli.h"
|
|
||||||
#include "dev/kbd_mo.h"
|
|
||||||
#include "dev/txt_screen.h"
|
|
||||||
|
|
||||||
#include "rsrc/font/quadrotextFONT.h"
|
#include <string.h>
|
||||||
#if MODEL == MODEL_FOENIX_A2560U || MODEL == MODEL_FOENIX_A2560U_PLUS
|
|
||||||
#include "rsrc/bitmaps/splash_a2560u.h"
|
|
||||||
#include "dev/txt_a2560u.h"
|
|
||||||
#elif MODEL == MODEL_FOENIX_A2560K
|
|
||||||
#include "rsrc/bitmaps/splash_a2560k.h"
|
|
||||||
#elif MODEL == MODEL_FOENIX_A2560X || MODEL == MODEL_FOENIX_GENX
|
|
||||||
#include "rsrc/bitmaps/splash_a2560x.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if MODEL == MODEL_FOENIX_A2560K
|
const uint32_t boot_record_alignment = 8192; // Number of bytes for boot record alignement
|
||||||
#define SPLASH_WAIT_SEC 10 /* How many seconds to wait on the splash screen */
|
const uint32_t boot_firmware_address = 0x380000;
|
||||||
#else
|
|
||||||
#define SPLASH_WAIT_SEC 4 /* How many seconds to wait on the splash screen */
|
|
||||||
#endif
|
|
||||||
/*
|
|
||||||
* Important scan codes
|
|
||||||
*/
|
|
||||||
#define SC_F1 0x3B
|
|
||||||
#define SC_F2 0x3C
|
|
||||||
#define SC_F3 0x3D
|
|
||||||
#define SC_SPACE 0x39
|
|
||||||
#define SC_RETURN 0x1C
|
|
||||||
|
|
||||||
/* TODO: move this to constants.h */
|
enum boot_src_e {
|
||||||
|
BOOT_SRC_NONE = 0, // Nothing more to check
|
||||||
|
BOOT_SRC_RAM, // Check RAM for a bootable
|
||||||
#define BOOT_SECTOR_BUFFER ((unsigned char *)0x00004000)
|
BOOT_SRC_ROM, // Check the ROM drive
|
||||||
#define BOOT_CODE_MBR_OFF 0x000 /* Offset to the code in the MBR */
|
BOOT_SRC_CARTRIDGE, // Check the cartridge
|
||||||
#define BOOT_CPUID_MBR_OFF 0x004 /* Offset to the CPUID in the MBR */
|
BOOT_SRC_SD0, // Check the external SD card
|
||||||
#define BOOT_SIG_MBR_OFF 0x006 /* Offset to the boot signature in the MBR */
|
BOOT_SRC_SD1 // Check the internal SD card / IDE
|
||||||
#define BOOT_SIG 0xF0E1 /* Foenix/MCP boot signature expected */
|
|
||||||
|
|
||||||
#define FDC_VBR_JUMP 0x000 // Intel 80x86 machine language jump... 3 bytes
|
|
||||||
#define FDC_VBR_OEMNAME 0x003 // OEM Name... 8 bytes
|
|
||||||
#define FDC_VBR_BPB 0x00B // BIOS Parameter Block
|
|
||||||
#define FDC_VBR_BYTES_PER_SECTOR 0x00B // Number of bytes per sector... 2 bytes
|
|
||||||
#define FDC_VBR_SECTORS_PER_CLUSTER 0x00D // Number of sectors per cluster... 1 byte
|
|
||||||
#define FDC_VBR_RESERVED_SECTORS 0x00E // Number of reserved sectors... 2 bytes
|
|
||||||
#define FDC_VBR_FAT_COUNT 0x010 // Number of file allocation tables... 1 byte
|
|
||||||
#define FDC_VBR_MAX_ROOT_ENTRIES 0x011 // Maximum number of root directory entries... 2 bytes
|
|
||||||
#define FDC_VBR_SECTORS 0x013 // Number of logical sectors in FAT12/16... 2 bytes
|
|
||||||
#define FDC_VBR_MEDIA_TYPE 0x015 // Media type code... 1 byte
|
|
||||||
#define FDC_VBR_SECTORS_PER_FAT 0x016 // Number of sectors per file allocation table... 2 bytes
|
|
||||||
#define FDC_VBR_SECTORS_PER_TRACK 0x018 // Number of sectors per track... 2 bytes
|
|
||||||
#define FDC_VBR_HEADS 0x01A // Number of heads... 2 bytes
|
|
||||||
#define FDC_VBR_HIDDEN_SECTORS 0x01C // Number of hidden sectors... 2 bytes
|
|
||||||
#define FDC_VBR_TOTAL_SECTORS 0x01E // Total number of sectors... 2 bytes
|
|
||||||
#define FDC_VBR_BOOT_CODE 0x060 // Start of boot sector code
|
|
||||||
|
|
||||||
#define BOOT_CODE_VBR_OFF FDC_VBR_BOOT_CODE /* Offset to the code in the VBR for floppy drives */
|
|
||||||
#define BOOT_CPUID_VBR_OFF BOOT_CODE_VBR_OFF+4 /* Offset to the CPUID in the VBR for floppy drives */
|
|
||||||
#define BOOT_SIG_VBR_OFF BOOT_CODE_VBR_OFF+6 /* Offset to the boot signature in the VBR for floppy drives */
|
|
||||||
|
|
||||||
const char * MCP_INIT_SDC = "/sd/system/mcp.init"; /**< Path to config file on the SD card */
|
|
||||||
const char * MCP_INIT_FDC = "/fd/system/mcp.init"; /**< Path to config file on the floppy drive */
|
|
||||||
const char * MCP_INIT_HDC = "/hd/system/mcp.init"; /**< Path to config file on the IDE drive */
|
|
||||||
|
|
||||||
// Colors for the A2560K keyboard LED matrix
|
|
||||||
const unsigned short kbd_colors[] = {0x000F, 0x0FF, 0x00F0, 0x0FF0, 0x0F70, 0x0F00};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* On the A2560K, animate the LEDs based on the current time while we're waiting for a key press
|
|
||||||
*
|
|
||||||
* @param max_ticks the value of the jiffy counter when the boot screen will end
|
|
||||||
* @param ticks the current value of the jiffy counter
|
|
||||||
* @param min_ticks the starting value of the jiffy counter
|
|
||||||
*/
|
|
||||||
void boot_animate_keyboard(unsigned long max_ticks, unsigned long ticks, unsigned long min_ticks) {
|
|
||||||
#if MODEL == MODEL_FOENIX_A2560K
|
|
||||||
const int animation_steps = 7;
|
|
||||||
int current_step = (int)(((ticks - min_ticks) * animation_steps) / (max_ticks - min_ticks));
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < current_step; i++) {
|
|
||||||
kbdmo_set_led_matrix_row(current_step - i - 1, kbd_colors[5 - i]);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if a sector loaded from a device is bootable
|
|
||||||
*
|
|
||||||
* @param sector pointer to where the sector is stored in memory
|
|
||||||
* @param device the number of the block device
|
|
||||||
*
|
|
||||||
* @return 0 if not bootable, non-zero if bootable
|
|
||||||
*/
|
|
||||||
bool is_bootable(unsigned char * sector, short device) {
|
|
||||||
switch(device) {
|
|
||||||
case BDEV_FDC:
|
|
||||||
// The SDC and HDC boot off the MBR...
|
|
||||||
// Check for the CPUID and boot signature
|
|
||||||
if ((sector[BOOT_CPUID_VBR_OFF] == CPU_M68000) ||
|
|
||||||
(sector[BOOT_CPUID_VBR_OFF] == CPU_M68040)) {
|
|
||||||
if ((sector[BOOT_SIG_VBR_OFF] == ((BOOT_SIG >> 8) & 0x00FF)) &&
|
|
||||||
(sector[BOOT_SIG_VBR_OFF+1] == (BOOT_SIG & 0x00FF))) {
|
|
||||||
// The CPU is supported, and the boot signature is correct
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BDEV_SDC:
|
|
||||||
case BDEV_HDC:
|
|
||||||
// The SDC and HDC boot off the MBR...
|
|
||||||
// Check for the CPUID and boot signature
|
|
||||||
if ((sector[BOOT_CPUID_MBR_OFF] == CPU_M68000) ||
|
|
||||||
(sector[BOOT_CPUID_MBR_OFF] == CPU_M68040)) {
|
|
||||||
if ((sector[BOOT_SIG_MBR_OFF] == ((BOOT_SIG >> 8) & 0x00FF)) &&
|
|
||||||
(sector[BOOT_SIG_MBR_OFF+1] == (BOOT_SIG & 0x00FF))) {
|
|
||||||
// The CPU is supported, and the boot signature is correct
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// Otherwise: we're not bootable
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have reached this point, the sector is not bootable
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run the code in the boot sector
|
|
||||||
*
|
|
||||||
* @param device the number of the block device for the sector
|
|
||||||
*/
|
|
||||||
void boot_sector_run(short device) {
|
|
||||||
FUNC_V_2_V boot_sector = 0;
|
|
||||||
|
|
||||||
switch(device) {
|
|
||||||
case BDEV_FDC:
|
|
||||||
// The FDC boots off the Volume Boot Record (offset 0x060)
|
|
||||||
boot_sector = (FUNC_V_2_V)(BOOT_SECTOR_BUFFER + BOOT_CODE_VBR_OFF);
|
|
||||||
boot_sector();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BDEV_SDC:
|
|
||||||
case BDEV_HDC:
|
|
||||||
// The SDC and HDC both boot off the MBR
|
|
||||||
boot_sector = (FUNC_V_2_V)(BOOT_SECTOR_BUFFER);
|
|
||||||
boot_sector();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void make_key_name(const char * original, char * buffer) {
|
|
||||||
int x;
|
|
||||||
for (x = 0; x < strlen(original); x++) {
|
|
||||||
buffer[x] = 0x80 | original[x];
|
|
||||||
}
|
|
||||||
buffer[strlen(original)] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Load and display the boot splash screen on the graphics screen
|
|
||||||
*
|
|
||||||
* @return boot device selected by user
|
|
||||||
*/
|
|
||||||
short boot_screen() {
|
|
||||||
t_rect region;
|
|
||||||
short device = BOOT_DEFAULT;
|
|
||||||
short screen;
|
|
||||||
char buffer[256];
|
|
||||||
char entry[50];
|
|
||||||
unsigned long target_jiffies = 0;
|
|
||||||
unsigned long min_jiffies = 0;
|
|
||||||
unsigned long current_jiffies = 0;
|
|
||||||
int i = 0;
|
|
||||||
const unsigned char * pixels;
|
|
||||||
volatile unsigned char * vram = VRAM_Bank0;
|
|
||||||
t_sys_info info;
|
|
||||||
char f1[3], f2[3], f3[3];
|
|
||||||
char space[10], cr_text[10];
|
|
||||||
|
|
||||||
TRACE("boot_screen");
|
|
||||||
|
|
||||||
// We'll display boot information on the common screen
|
|
||||||
screen = 0;
|
|
||||||
|
|
||||||
/* Turn off the screen */
|
|
||||||
txt_set_mode(screen, 0);
|
|
||||||
|
|
||||||
for (i = 0; i < 256; i++) {
|
|
||||||
LUT_0[4*i] = splashscreen_lut[4*i];
|
|
||||||
LUT_0[4*i+1] = splashscreen_lut[4*i+1];
|
|
||||||
LUT_0[4*i+2] = splashscreen_lut[4*i+2];
|
|
||||||
LUT_0[4*i+3] = splashscreen_lut[4*i+3];
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
/* Copy the bitmap to video RAM, it has simple RLE compression */
|
|
||||||
for (pixels = splashscreen_pix; *pixels != 0;) {
|
|
||||||
unsigned char count = *pixels++;
|
|
||||||
unsigned char pixel = *pixels++;
|
|
||||||
for (i = 0; i < count; i++) {
|
|
||||||
*vram++ = pixel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#if 0
|
|
||||||
// For debug, try something more basic
|
|
||||||
const line_len = 640;
|
|
||||||
//memset(vram, 1, 640*480);
|
|
||||||
for (i=0; i < 640*480; i++)
|
|
||||||
vram[i] = 3;
|
|
||||||
for (i = 0; i < 480; i++)
|
|
||||||
vram[640*i + i] = 2;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
/* Set up the bitmap */
|
|
||||||
*BM0_Addy_Pointer_Reg = 0; /* Start of VRAM */
|
|
||||||
*BM0_Control_Reg = 1;
|
|
||||||
|
|
||||||
/* Set a background color for the bitmap mode */
|
|
||||||
#if HAS_DUAL_SCREEN
|
|
||||||
*BackGroundControlReg_B = 0x00202020;
|
|
||||||
screen = 0;
|
|
||||||
#else
|
|
||||||
*BackGroundControlReg_A = 0x00402040;
|
|
||||||
screen = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Display the splashscreen at 640x480 without a border */
|
|
||||||
txt_set_resolution(screen, 640, 480);
|
|
||||||
txt_set_border(screen, 0, 0);
|
|
||||||
txt_set_font(screen, 8, 8, quadrotextFONT);
|
|
||||||
|
|
||||||
region.origin.x = 0;
|
|
||||||
region.origin.y = 0;
|
|
||||||
region.size.width = 0;
|
|
||||||
region.size.height = 0;
|
|
||||||
txt_set_region(screen, ®ion);
|
|
||||||
txt_setsizes(screen);
|
|
||||||
txt_set_mode(screen, TXT_MODE_TEXT | TXT_MODE_BITMAP);
|
|
||||||
|
|
||||||
/* Disable the cursor, set the color, clear the text screen, and display the text message */
|
|
||||||
txt_set_cursor(screen, 0, 0, 0); // Disable the cursor
|
|
||||||
txt_set_color(screen, 15, 0); // White on transparent
|
|
||||||
txt_fill(screen, ' '); // Clear the screen
|
|
||||||
|
|
||||||
make_key_name("F1", f1);
|
|
||||||
make_key_name("F2", f2);
|
|
||||||
make_key_name("F3", f3);
|
|
||||||
make_key_name("SPACE", space);
|
|
||||||
make_key_name("RETURN", cr_text);
|
|
||||||
|
|
||||||
#if HAS_FLOPPY
|
|
||||||
sprintf(buffer, "BOOT: %s=SD CARD, %s=HARD DRIVE, s=FLOPPY, %s=DEFAULT, %s=SAFE", f1, f2, f3, space, cr_text);
|
|
||||||
#else
|
|
||||||
sprintf(buffer, "BOOT: %s=SD CARD, %s=HARD DRIVE, %s=DEFAULT, %s=SAFE", f1, f2, space, cr_text);
|
|
||||||
#endif
|
|
||||||
txt_set_xy(screen, (80 - strlen(buffer)) / 2, 58);
|
|
||||||
sys_chan_write(screen, buffer, strlen(buffer));
|
|
||||||
|
|
||||||
// Get the information about the system
|
|
||||||
sys_get_info(&info);
|
|
||||||
|
|
||||||
region.origin.x = 49;
|
|
||||||
region.origin.y = 1;
|
|
||||||
region.size.width = 40;
|
|
||||||
region.size.height = 20;
|
|
||||||
txt_set_region(screen, ®ion);
|
|
||||||
|
|
||||||
sprintf(buffer, "\x1b[HFOENIX/MCP V: %02u.%04u.%04u\n", info.mcp_version, info.mcp_rev, info.mcp_build);
|
|
||||||
print(screen, buffer);
|
|
||||||
str_upcase(info.model_name, entry);
|
|
||||||
sprintf(buffer, " MODEL: %s\n", entry);
|
|
||||||
print(screen, buffer);
|
|
||||||
str_upcase(info.cpu_name, entry);
|
|
||||||
sprintf(buffer, " CPU: %s\n", entry);
|
|
||||||
print(screen, buffer);
|
|
||||||
sprintf(buffer, " CLOCK (KHZ): %u\n", info.cpu_clock_khz);
|
|
||||||
print(screen, buffer);
|
|
||||||
sprintf(buffer, " FPGA V: %u.%02u.%04u\n", (unsigned int)info.fpga_model, info.fpga_version, info.fpga_subver);
|
|
||||||
print(screen, buffer);
|
|
||||||
|
|
||||||
/* Wait until the target duration has been reached _or_ the user presses a key */
|
|
||||||
sprintf(buffer, "Booting from default device...\n");
|
|
||||||
min_jiffies = sys_time_jiffies();
|
|
||||||
target_jiffies = min_jiffies + SPLASH_WAIT_SEC * 60;
|
|
||||||
|
|
||||||
while (target_jiffies > (current_jiffies = sys_time_jiffies())) {
|
|
||||||
boot_animate_keyboard(target_jiffies, current_jiffies, min_jiffies);
|
|
||||||
|
|
||||||
unsigned short scan_code = sys_kbd_scancode();
|
|
||||||
if (scan_code == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
switch (scan_code) {
|
|
||||||
case SC_F1:
|
|
||||||
device = BDEV_SDC;
|
|
||||||
strcpy(buffer, "Booting from SD card.\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SC_F2:
|
|
||||||
device = BDEV_HDC;
|
|
||||||
strcpy(buffer, "Booting from hard drive.\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
#if HAS_FLOPPY
|
|
||||||
case SC_F3:
|
|
||||||
device = BDEV_FDC;
|
|
||||||
strcpy(buffer, "Booting from floppy drive.\n");
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
case SC_RETURN:
|
|
||||||
device = BOOT_SAFE;
|
|
||||||
strcpy(buffer, "Booting directly to the command line.\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
device = BOOT_DEFAULT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialise all screens */
|
|
||||||
txt_init_screen(screen); /* This is the one used for the boot message */
|
|
||||||
/* No need to txt_set_resolution(screen, 0, 0) because during screen_init, the defaults are applied */
|
|
||||||
#if MODEL == MODEL_FOENIX_A2560K || MODEL == MODEL_FOENIX_A2560X || MODEL == MODEL_FOENIX_GENX
|
|
||||||
txt_set_resolution(1, 0, 0); // Set the resolution based on the DIP switch
|
|
||||||
#endif
|
|
||||||
print(screen, buffer);
|
|
||||||
|
|
||||||
#if MODEL == MODEL_FOENIX_A2560K
|
|
||||||
// Turn off the keyboard LEDs
|
|
||||||
kbdmo_set_led_matrix_fill(0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return device;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start the boot process after initializing the MCP
|
|
||||||
*
|
|
||||||
* @param device the number of the block device to use for booting (-1 to go straight to CLI)
|
|
||||||
*/
|
|
||||||
void boot_from_bdev(short device) {
|
|
||||||
char initial_path[10];
|
|
||||||
#if MODEL == MODEL_FOENIX_A2560K
|
|
||||||
unsigned int boot_dip = 0; // The setting on the user and boot mode DIP switches
|
|
||||||
#elif MODEL == MODEL_FOENIX_GENX || MODEL == MODEL_FOENIX_A2560X || MODEL_FOENIX_A2560U_PLUS
|
|
||||||
unsigned short boot_dip = 0; // The setting on the user and boot mode DIP switches
|
|
||||||
#endif
|
|
||||||
short bootable = 0; // Is the boot sector of the selected device bootable?
|
|
||||||
|
|
||||||
TRACE1("boot_from_bdev(%d)", device);
|
|
||||||
|
|
||||||
initial_path[0] = '\0';
|
|
||||||
|
|
||||||
// Get the boot device
|
|
||||||
switch (device) {
|
|
||||||
case BOOT_DEFAULT:
|
|
||||||
// User chose the default. Look at the DIP switches to determine the boot source
|
|
||||||
boot_dip = *GABE_DIP_REG & GABE_DIP_BOOT_MASK;
|
|
||||||
switch (boot_dip) {
|
|
||||||
case 0x0000:
|
|
||||||
// Boot from IDE
|
|
||||||
device = BDEV_HDC;
|
|
||||||
log(LOG_INFO, "Boot DIP set for IDE");
|
|
||||||
strcpy(initial_path, "/hd");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x0001:
|
|
||||||
// Boot from SDC
|
|
||||||
device = BDEV_SDC;
|
|
||||||
log(LOG_INFO, "Boot DIP set for SDC");
|
|
||||||
strcpy(initial_path, "/sd");
|
|
||||||
break;
|
|
||||||
|
|
||||||
#if HAS_FLOPPY
|
|
||||||
case 0x0002:
|
|
||||||
// Boot from Floppy
|
|
||||||
device = BDEV_FDC;
|
|
||||||
log(LOG_INFO, "Boot DIP set for FDC");
|
|
||||||
strcpy(initial_path, "/fd");
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
// Boot straight to REPL
|
|
||||||
log(LOG_INFO, "Boot DIP set for REPL");
|
|
||||||
strcpy(initial_path, "/sd");
|
|
||||||
device = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (device >= 0) {
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < 512; i++) {
|
|
||||||
// Zero out the buffer
|
|
||||||
BOOT_SECTOR_BUFFER[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to load the boot sector
|
|
||||||
DEBUG("boot_from_bdev: trying to read boot sector");
|
|
||||||
short result = bdev_read(device, 0, BOOT_SECTOR_BUFFER, 512);
|
|
||||||
if (result > 0) {
|
|
||||||
// Check to see if it's bootable
|
|
||||||
bootable = is_bootable(BOOT_SECTOR_BUFFER, device);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bootable) {
|
|
||||||
DEBUG("boot_from_bdev: boot sector is bootable, trying to run");
|
|
||||||
// If bootable, run it
|
|
||||||
boot_sector_run(device);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
DEBUG("boot_from_bdev: boot sector not bootable");
|
|
||||||
// If not bootable...
|
|
||||||
|
|
||||||
// Get the screen for the CLI
|
|
||||||
short cli_screen = cli_txt_screen_get();
|
|
||||||
|
|
||||||
if (device >= 0) {
|
|
||||||
DEBUG("Execute startup file on boot device (if present)");
|
|
||||||
switch (device) {
|
|
||||||
case BDEV_SDC:
|
|
||||||
strcpy(initial_path, "/sd");
|
|
||||||
if (cli_exec_batch(cli_screen, MCP_INIT_SDC) != 0) {
|
|
||||||
cli_exec_batch(cli_screen, MCP_INIT_HDC);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BDEV_FDC:
|
|
||||||
strcpy(initial_path, "/fd");
|
|
||||||
if (cli_exec_batch(cli_screen, MCP_INIT_FDC) != 0) {
|
|
||||||
cli_exec_batch(cli_screen, MCP_INIT_HDC);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BDEV_HDC:
|
|
||||||
strcpy(initial_path, "/hd");
|
|
||||||
cli_exec_batch(cli_screen, MCP_INIT_HDC);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start up the command shell
|
|
||||||
cli_start_repl(cli_screen, initial_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const unsigned char boot_from_file_sector[] = {
|
|
||||||
0x60, 0x00, 0x00, 0x06, // bra.w boot
|
|
||||||
CPU_M68000, 0x00, 0xf0, 0xe1, // dc.b CPU_M68000, 0, 0xf0, 0xe1
|
|
||||||
0x30, 0x3c, 0x00, 0x40, // boot: move.w #$40,d0
|
|
||||||
0x43, 0xfa, 0x00, 0x0e, // lea (path,pc),a1
|
|
||||||
0x22, 0x09, // move.l a1,d1
|
|
||||||
0x42, 0x82, // clr.l d2
|
|
||||||
0x42, 0x83, // clr.l d3
|
|
||||||
0x4e, 0x4f, // trap #15
|
|
||||||
0x4e, 0x71, // bootloop nop
|
|
||||||
0x60, 0xfc // bra bootloop
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make the indicated drive non booting by erasing the boot information
|
* @brief Structure to hold a boot record
|
||||||
*
|
*
|
||||||
* @param device the number of the block device to use for booting (-1 to go straight to CLI)
|
|
||||||
* @return 0 on success, any other number is an error
|
|
||||||
*/
|
*/
|
||||||
short boot_non_booting(short device) {
|
typedef struct boot_record_s {
|
||||||
unsigned char * buffer;
|
char signature1;
|
||||||
short result = 0;
|
char signature2;
|
||||||
|
uint32_t start_address;
|
||||||
|
uint8_t version;
|
||||||
|
uint8_t reserved0;
|
||||||
|
uint8_t reserved1;
|
||||||
|
uint8_t reserved2;
|
||||||
|
char * text_data;
|
||||||
|
} boot_record_t, *boot_record_p;
|
||||||
|
|
||||||
buffer = (unsigned char *)malloc(FSYS_SECTOR_SZ);
|
/**
|
||||||
if (buffer != 0) {
|
* @brief List bootable areas to check, in priority order
|
||||||
// Try to read the current sector
|
*
|
||||||
short n = sys_bdev_read(device, 0, buffer, FSYS_SECTOR_SZ);
|
*/
|
||||||
if (n == FSYS_SECTOR_SZ) {
|
static enum boot_src_e boot_chain[] = {
|
||||||
short sector_offset = 0;
|
BOOT_SRC_RAM,
|
||||||
|
BOOT_SRC_CARTRIDGE,
|
||||||
|
BOOT_SRC_SD0,
|
||||||
|
BOOT_SRC_SD1,
|
||||||
|
BOOT_SRC_ROM,
|
||||||
|
BOOT_SRC_NONE
|
||||||
|
};
|
||||||
|
|
||||||
if (device == BDEV_FDC) {
|
/**
|
||||||
// Point to the beginning of the boot code for the FDC (VBR)
|
* @brief A holder for empty arguments list so we have something to point to when starting a binary file
|
||||||
sector_offset = BOOT_CODE_VBR_OFF;
|
*
|
||||||
|
*/
|
||||||
|
static char * boot_args[] = {
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
} else {
|
/**
|
||||||
// Point to the beginning of the boot code for the SDC/HDD (MBR)
|
* @brief Check the memory indicated to validate it is a boot record... if so, launch the code indicated
|
||||||
sector_offset = BOOT_CODE_MBR_OFF;
|
*
|
||||||
}
|
* @param record pointer to the possible boot record
|
||||||
|
* @return 1 if success, 0 if boot record not validated
|
||||||
// Boot record read... clear out the boot code
|
*/
|
||||||
for (int i = 0; i < sizeof(boot_from_file_sector); i++) {
|
short boot_ram_launch(boot_record_p record) {
|
||||||
buffer[sector_offset + i] = 0;
|
if ((record->signature1 == 0xf8) && (record->signature2 == 0x16) && (record->version == 0)) {
|
||||||
}
|
// Memory does indeed hold a boot record
|
||||||
|
proc_exec(record->start_address, 0, 0, 0);
|
||||||
// Try to write it back
|
return 1;
|
||||||
n = sys_bdev_write(device, 0, buffer, FSYS_SECTOR_SZ);
|
} else {
|
||||||
if (n == FSYS_SECTOR_SZ) {
|
return 0;
|
||||||
// Success!
|
}
|
||||||
result = 0;
|
|
||||||
} else {
|
|
||||||
result = DEV_CANNOT_WRITE;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
result = DEV_CANNOT_READ;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
result = ERR_OUT_OF_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear up the memory we grabbed...
|
|
||||||
if (buffer) {
|
|
||||||
free(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make the indicated drive booting from a file
|
* @brief Look for a boot record in RAM
|
||||||
*
|
* @return 1 if success, 0 if boot record not validated
|
||||||
* @param device the number of the block device to use for booting (-1 to go straight to CLI)
|
*
|
||||||
* @param path the path to the file to boot from
|
|
||||||
* @return 0 on success, any other number is an error
|
|
||||||
*/
|
*/
|
||||||
short boot_set_file(short device, const char * path) {
|
short boot_ram() {
|
||||||
unsigned char * buffer, x;
|
unsigned long top_ram = mem_get_ramtop();
|
||||||
short result = 0, i = 0;
|
for (uint32_t address = 0; address < top_ram; address += boot_record_alignment) {
|
||||||
|
if (boot_ram_launch((boot_record_p)address)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
buffer = (unsigned char *)malloc(FSYS_SECTOR_SZ);
|
return 0;
|
||||||
if (buffer != 0) {
|
}
|
||||||
// Try to read the current sector
|
|
||||||
bdev_init(device);
|
/**
|
||||||
short n = sys_bdev_read(device, 0, buffer, FSYS_SECTOR_SZ);
|
* @brief Look for a boot record in the flash cartridge
|
||||||
if (n == FSYS_SECTOR_SZ) {
|
* @return 1 if success, 0 if boot record not validated
|
||||||
int sector_len = sizeof(boot_from_file_sector);
|
*
|
||||||
int sector_offset = 0;
|
*/
|
||||||
int path_len = strlen(path);
|
short boot_cartridge() {
|
||||||
|
return 0;
|
||||||
if (device == BDEV_FDC) {
|
}
|
||||||
// Set up the floppy disk boot record
|
|
||||||
sector_offset = BOOT_CODE_VBR_OFF;
|
/**
|
||||||
|
* @brief Find and launch the user's code
|
||||||
// Write 80x86 code to infinite loop at the start of the boot sector
|
*
|
||||||
// This will help maintain compatibility with MS-DOS and Windows machines
|
*/
|
||||||
buffer[0] = 0xEB;
|
void boot_launch() {
|
||||||
buffer[1] = 0xFF;
|
for (short i = 0; boot_chain[i] != BOOT_SRC_NONE; i++) {
|
||||||
buffer[2] = 0x90;
|
switch(boot_chain[i]) {
|
||||||
|
case BOOT_SRC_RAM:
|
||||||
} else {
|
if (boot_ram()) {
|
||||||
// Set up the SDC or HDC master boot record
|
return;
|
||||||
sector_offset = BOOT_CODE_MBR_OFF;
|
}
|
||||||
}
|
break;
|
||||||
|
|
||||||
// Copy the boot code over
|
case BOOT_SRC_SD0:
|
||||||
for (i = 0; i < sector_len; i++) {
|
if (proc_run("/sd0/fnxboot.pgz", 0, boot_args) == 0) {
|
||||||
buffer[sector_offset + i] = boot_from_file_sector[i];
|
return;
|
||||||
}
|
} else if (proc_run("/sd0/fnxboot.pgx", 0, boot_args) == 0) {
|
||||||
|
return;
|
||||||
// Insert the path
|
} else if (proc_run("/sd0/fnxboot.elf", 0, boot_args) == 0) {
|
||||||
for (i = 0; i < path_len; i++) {
|
return;
|
||||||
buffer[sector_offset + i + sector_len] = path[i];
|
}
|
||||||
}
|
break;
|
||||||
buffer[sector_offset + sector_len + path_len] = 0;
|
|
||||||
|
default:
|
||||||
// Try to write it back
|
break;
|
||||||
n = sys_bdev_write(device, 0, buffer, FSYS_SECTOR_SZ);
|
}
|
||||||
if (n == FSYS_SECTOR_SZ) {
|
}
|
||||||
// Success!
|
|
||||||
result = 0;
|
|
||||||
} else {
|
|
||||||
result = DEV_CANNOT_WRITE;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
result = DEV_CANNOT_READ;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
result = ERR_OUT_OF_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear up the memory we grabbed...
|
|
||||||
if (buffer) {
|
|
||||||
free(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
49
src/boot.h
49
src/boot.h
|
@ -1,44 +1,23 @@
|
||||||
/**
|
/**
|
||||||
* @file boot.h
|
* @file boot.c
|
||||||
*
|
* @author your name (you@domain.com)
|
||||||
* Routines to support the boot process
|
* @brief Boot sequence control code for managing loading up the user's control code
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2024-06-09
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2024
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __BOOT_H
|
#ifndef __boot_h__
|
||||||
#define __BOOT_H
|
#define __boot_h__
|
||||||
|
|
||||||
#define BOOT_DEFAULT -1
|
#include <stdint.h>
|
||||||
#define BOOT_SAFE -2
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Load and display the boot splash screen on the graphics screen
|
|
||||||
*
|
|
||||||
* @return boot device selected by user
|
|
||||||
*/
|
|
||||||
extern short boot_screen();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the boot process after initializing the MCP
|
* @brief Find and launch the user's code
|
||||||
*
|
*
|
||||||
* @param device the number of the block device to use for booting (-1 to go straight to CLI)
|
|
||||||
*/
|
*/
|
||||||
extern void boot_from_bdev(short device);
|
extern void boot_launch();
|
||||||
|
|
||||||
/**
|
|
||||||
* Make the indicated drive non booting by erasing the boot information
|
|
||||||
*
|
|
||||||
* @param device the number of the block device to use for booting (-1 to go straight to CLI)
|
|
||||||
* @return 0 on success, any other number is an error
|
|
||||||
*/
|
|
||||||
extern short boot_non_booting(short device);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make the indicated drive booting from a file
|
|
||||||
*
|
|
||||||
* @param device the number of the block device to use for booting (-1 to go straight to CLI)
|
|
||||||
* @param path the path to the file to boot from
|
|
||||||
* @return 0 on success, any other number is an error
|
|
||||||
*/
|
|
||||||
extern short boot_set_file(short device, const char * path);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
#include "rsrc/font/MSX_CP437_8x8.h"
|
#include "rsrc/font/MSX_CP437_8x8.h"
|
||||||
#include "rsrc/bitmaps/splash_c256_u.h"
|
#include "rsrc/bitmaps/splash_c256_u.h"
|
||||||
|
|
||||||
const char* VolumeStr[FF_VOLUMES] = { "sd" };
|
const char* VolumeStr[FF_VOLUMES] = { "sd0" };
|
||||||
|
|
||||||
extern unsigned long __memory_start;
|
extern unsigned long __memory_start;
|
||||||
|
|
||||||
|
@ -244,10 +244,6 @@ void initialize() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BOOT_DEFAULT -1 // User chose default, or the time to over-ride has passed
|
|
||||||
|
|
||||||
t_file_info file;
|
|
||||||
|
|
||||||
int main(int argc, char * argv[]) {
|
int main(int argc, char * argv[]) {
|
||||||
short result;
|
short result;
|
||||||
short i;
|
short i;
|
||||||
|
@ -255,24 +251,9 @@ int main(int argc, char * argv[]) {
|
||||||
|
|
||||||
initialize();
|
initialize();
|
||||||
|
|
||||||
// // Display the splash screen and wait for user input
|
// Attempt to start up the user code
|
||||||
// short boot_dev = boot_screen();
|
log(LOG_INFO, "Looking for user startup code:");
|
||||||
|
boot_launch();
|
||||||
// // Start the boot process
|
|
||||||
// boot_from_bdev(boot_dev);
|
|
||||||
|
|
||||||
// log(LOG_INFO, "Stopping.");
|
|
||||||
|
|
||||||
printf("Loading splashscreen...\n");
|
|
||||||
|
|
||||||
// txt_clear(0, 2);
|
|
||||||
bm_load_clut(0, splashscreen_lut);
|
|
||||||
bm_load_rle((uint8_t *)0x010000, splashscreen_pix, 640, 480);
|
|
||||||
printf("Splash screen rendered\n");
|
|
||||||
vdma_copy_linear((uint8_t *)0xb00000, (uint8_t *)0x010000, (long)640 * (long)480);
|
|
||||||
printf("Splash screen copied to VRAM\n");
|
|
||||||
bm_set_data(0, (uint8_t *)0xb00000);
|
|
||||||
bm_set_visibility(0, 0, 1);
|
|
||||||
|
|
||||||
printf("Done.\n");
|
printf("Done.\n");
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue