Merge interim hekate bugfixes

This commit is contained in:
shchmue 2019-04-18 12:47:34 -04:00
parent 04d989a345
commit e1ffda6ab9
36 changed files with 549 additions and 859 deletions

View file

@ -142,7 +142,7 @@ void display_backlight_pwm_init()
{ {
clock_enable_pwm(); clock_enable_pwm();
PWM(PWM_CONTROLLER_PWM_CSR) = (1 << 31); // Enable PWM PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31); // Enable PWM
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) >> 2) << 2 | 1; // PWM clock source. PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) >> 2) << 2 | 1; // PWM clock source.
gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight power mode. gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight power mode.
@ -156,7 +156,7 @@ void display_backlight(bool enable)
void display_backlight_brightness(u32 brightness, u32 step_delay) void display_backlight_brightness(u32 brightness, u32 step_delay)
{ {
u32 old_value = (PWM(PWM_CONTROLLER_PWM_CSR) >> 16) & 0xFF; u32 old_value = (PWM(PWM_CONTROLLER_PWM_CSR_0) >> 16) & 0xFF;
if (brightness == old_value) if (brightness == old_value)
return; return;
@ -167,7 +167,7 @@ void display_backlight_brightness(u32 brightness, u32 step_delay)
{ {
for (u32 i = old_value; i < brightness + 1; i++) for (u32 i = old_value; i < brightness + 1; i++)
{ {
PWM(PWM_CONTROLLER_PWM_CSR) = (1 << 31) | (i << 16); // Enable PWM PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31) | (i << 16); // Enable PWM
usleep(step_delay); usleep(step_delay);
} }
} }
@ -175,12 +175,12 @@ void display_backlight_brightness(u32 brightness, u32 step_delay)
{ {
for (u32 i = old_value; i > brightness; i--) for (u32 i = old_value; i > brightness; i--)
{ {
PWM(PWM_CONTROLLER_PWM_CSR) = (1 << 31) | (i << 16); // Enable PWM PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31) | (i << 16); // Enable PWM
usleep(step_delay); usleep(step_delay);
} }
} }
if (!brightness) if (!brightness)
PWM(PWM_CONTROLLER_PWM_CSR) = 0; PWM(PWM_CONTROLLER_PWM_CSR_0) = 0;
} }
void display_end() void display_end()

View file

@ -350,9 +350,6 @@
#define MIPI_CAL_MIPI_BIAS_PAD_CFG2 0x60 #define MIPI_CAL_MIPI_BIAS_PAD_CFG2 0x60
/*! Display backlight related PWM registers. */
#define PWM_CONTROLLER_PWM_CSR 0x00
void display_init(); void display_init();
void display_backlight_pwm_init(); void display_backlight_pwm_init();
void display_end(); void display_end();

View file

@ -118,73 +118,73 @@ static const u8 _gfx_font[] = {
0x00, 0x00, 0x00, 0x4C, 0x32, 0x00, 0x00, 0x00 // Char 126 (~) 0x00, 0x00, 0x00, 0x4C, 0x32, 0x00, 0x00, 0x00 // Char 126 (~)
}; };
void gfx_init_ctxt(gfx_ctxt_t *ctxt, u32 *fb, u32 width, u32 height, u32 stride) void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride)
{ {
ctxt->fb = fb; gfx_ctxt.fb = fb;
ctxt->width = width; gfx_ctxt.width = width;
ctxt->height = height; gfx_ctxt.height = height;
ctxt->stride = stride; gfx_ctxt.stride = stride;
} }
void gfx_clear_grey(gfx_ctxt_t *ctxt, u8 color) void gfx_clear_grey(u8 color)
{ {
memset(ctxt->fb, color, 0x3C0000); memset(gfx_ctxt.fb, color, 0x3C0000);
} }
void gfx_clear_color(gfx_ctxt_t *ctxt, u32 color) void gfx_clear_color(u32 color)
{ {
for (u32 i = 0; i < ctxt->height * ctxt->stride; i++) for (u32 i = 0; i < gfx_ctxt.height * gfx_ctxt.stride; i++)
ctxt->fb[i] = color; gfx_ctxt.fb[i] = color;
} }
void gfx_clear_partial_grey(gfx_ctxt_t *ctxt, u8 color, u32 pos_x, u32 height) void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height)
{ {
memset(ctxt->fb + pos_x * ctxt->stride, color, height * 4 * ctxt->stride); memset(gfx_ctxt.fb + pos_x * gfx_ctxt.stride, color, height * 4 * gfx_ctxt.stride);
} }
void gfx_con_init(gfx_con_t *con, gfx_ctxt_t *ctxt) void gfx_con_init()
{ {
con->gfx_ctxt = ctxt; gfx_con.gfx_ctxt = &gfx_ctxt;
con->fntsz = 16; gfx_con.fntsz = 16;
con->x = 0; gfx_con.x = 0;
con->y = 0; gfx_con.y = 0;
con->savedx = 0; gfx_con.savedx = 0;
con->savedy = 0; gfx_con.savedy = 0;
con->fgcol = 0xFFCCCCCC; gfx_con.fgcol = 0xFFCCCCCC;
con->fillbg = 0; gfx_con.fillbg = 1;
con->bgcol = 0xFF1B1B1B; gfx_con.bgcol = 0xFF1B1B1B;
con->mute = 0; gfx_con.mute = 0;
} }
void gfx_con_setcol(gfx_con_t *con, u32 fgcol, int fillbg, u32 bgcol) void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol)
{ {
con->fgcol = fgcol; gfx_con.fgcol = fgcol;
con->fillbg = fillbg; gfx_con.fillbg = fillbg;
con->bgcol = bgcol; gfx_con.bgcol = bgcol;
} }
void gfx_con_getpos(gfx_con_t *con, u32 *x, u32 *y) void gfx_con_getpos(u32 *x, u32 *y)
{ {
*x = con->x; *x = gfx_con.x;
*y = con->y; *y = gfx_con.y;
} }
void gfx_con_setpos(gfx_con_t *con, u32 x, u32 y) void gfx_con_setpos(u32 x, u32 y)
{ {
con->x = x; gfx_con.x = x;
con->y = y; gfx_con.y = y;
} }
void gfx_putc(gfx_con_t *con, char c) void gfx_putc(char c)
{ {
// Duplicate code for performance reasons. // Duplicate code for performance reasons.
switch (con->fntsz) switch (gfx_con.fntsz)
{ {
case 16: case 16:
if (c >= 32 && c <= 126) if (c >= 32 && c <= 126)
{ {
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)]; u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];
u32 *fb = con->gfx_ctxt->fb + con->x + con->y * con->gfx_ctxt->stride; u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride;
for (u32 i = 0; i < 16; i+=2) for (u32 i = 0; i < 16; i+=2)
{ {
@ -195,37 +195,37 @@ void gfx_putc(gfx_con_t *con, char c)
{ {
if (v & 1) if (v & 1)
{ {
*fb = con->fgcol; *fb = gfx_con.fgcol;
fb++; fb++;
*fb = con->fgcol; *fb = gfx_con.fgcol;
} }
else if (con->fillbg) else if (gfx_con.fillbg)
{ {
*fb = con->bgcol; *fb = gfx_con.bgcol;
fb++; fb++;
*fb = con->bgcol; *fb = gfx_con.bgcol;
} }
else else
fb++; fb++;
v >>= 1; v >>= 1;
fb++; fb++;
} }
fb += con->gfx_ctxt->stride - 16; fb += gfx_ctxt.stride - 16;
v = *cbuf; v = *cbuf;
} }
} }
con->x += 16; gfx_con.x += 16;
if (con->x >= con->gfx_ctxt->width - 16) { if (gfx_con.x >= gfx_ctxt.width - 16) {
con->x = 0; gfx_con.x = 0;
con->y += 16; gfx_con.y += 16;
} }
} }
else if (c == '\n') else if (c == '\n')
{ {
con->x = 0; gfx_con.x = 0;
con->y += 16; gfx_con.y +=16;
if (con->y > con->gfx_ctxt->height - 16) if (gfx_con.y > gfx_ctxt.height - 16)
con->y = 0; gfx_con.y = 0;
} }
break; break;
case 8: case 8:
@ -233,49 +233,49 @@ void gfx_putc(gfx_con_t *con, char c)
if (c >= 32 && c <= 126) if (c >= 32 && c <= 126)
{ {
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)]; u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];
u32 *fb = con->gfx_ctxt->fb + con->x + con->y * con->gfx_ctxt->stride; u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride;
for (u32 i = 0; i < 8; i++) for (u32 i = 0; i < 8; i++)
{ {
u8 v = *cbuf++; u8 v = *cbuf++;
for (u32 j = 0; j < 8; j++) for (u32 j = 0; j < 8; j++)
{ {
if (v & 1) if (v & 1)
*fb = con->fgcol; *fb = gfx_con.fgcol;
else if (con->fillbg) else if (gfx_con.fillbg)
*fb = con->bgcol; *fb = gfx_con.bgcol;
v >>= 1; v >>= 1;
fb++; fb++;
} }
fb += con->gfx_ctxt->stride - 8; fb += gfx_ctxt.stride - 8;
} }
con->x += 8; gfx_con.x += 8;
if (con->x >= con->gfx_ctxt->width - 8) { if (gfx_con.x >= gfx_ctxt.width - 8) {
con->x = 0; gfx_con.x = 0;
con->y += 8; gfx_con.y += 8;
} }
} }
else if (c == '\n') else if (c == '\n')
{ {
con->x = 0; gfx_con.x = 0;
con->y += 8; gfx_con.y += 8;
if (con->y > con->gfx_ctxt->height - 8) if (gfx_con.y > gfx_ctxt.height - 8)
con->y = 0; gfx_con.y = 0;
} }
break; break;
} }
} }
void gfx_puts(gfx_con_t *con, const char *s) void gfx_puts(const char *s)
{ {
if (!s || con->mute) if (!s || gfx_con.mute)
return; return;
for (; *s; s++) for (; *s; s++)
gfx_putc(con, *s); gfx_putc(*s);
} }
static void _gfx_putn(gfx_con_t *con, u32 v, int base, char fill, int fcnt) static void _gfx_putn(u32 v, int base, char fill, int fcnt)
{ {
char buf[65]; char buf[65];
static const char digits[] = "0123456789ABCDEFghijklmnopqrstuvwxyz"; static const char digits[] = "0123456789ABCDEFghijklmnopqrstuvwxyz";
@ -303,28 +303,28 @@ static void _gfx_putn(gfx_con_t *con, u32 v, int base, char fill, int fcnt)
} }
} }
gfx_puts(con, p); gfx_puts(p);
} }
void gfx_put_small_sep(gfx_con_t *con) void gfx_put_small_sep(gfx_con_t *con)
{ {
u8 prevFontSize = con->fntsz; u8 prevFontSize = gfx_con.fntsz;
con->fntsz = 8; gfx_con.fntsz = 8;
gfx_putc(con, '\n'); gfx_putc('\n');
con->fntsz = prevFontSize; gfx_con.fntsz = prevFontSize;
} }
void gfx_put_big_sep(gfx_con_t *con) void gfx_put_big_sep(gfx_con_t *con)
{ {
u8 prevFontSize = con->fntsz; u8 prevFontSize = gfx_con.fntsz;
con->fntsz = 16; gfx_con.fntsz = 16;
gfx_putc(con, '\n'); gfx_putc('\n');
con->fntsz = prevFontSize; gfx_con.fntsz = prevFontSize;
} }
void gfx_printf(gfx_con_t *con, const char *fmt, ...) void gfx_printf(const char *fmt, ...)
{ {
if (con->mute) if (gfx_con.mute)
return; return;
va_list ap; va_list ap;
@ -357,40 +357,40 @@ void gfx_printf(gfx_con_t *con, const char *fmt, ...)
switch(*fmt) switch(*fmt)
{ {
case 'c': case 'c':
gfx_putc(con, va_arg(ap, u32)); gfx_putc(va_arg(ap, u32));
break; break;
case 's': case 's':
gfx_puts(con, va_arg(ap, char *)); gfx_puts(va_arg(ap, char *));
break; break;
case 'd': case 'd':
_gfx_putn(con, va_arg(ap, u32), 10, fill, fcnt); _gfx_putn(va_arg(ap, u32), 10, fill, fcnt);
break; break;
case 'p': case 'p':
case 'P': case 'P':
case 'x': case 'x':
case 'X': case 'X':
_gfx_putn(con, va_arg(ap, u32), 16, fill, fcnt); _gfx_putn(va_arg(ap, u32), 16, fill, fcnt);
break; break;
case 'k': case 'k':
con->fgcol = va_arg(ap, u32); gfx_con.fgcol = va_arg(ap, u32);
break; break;
case 'K': case 'K':
con->bgcol = va_arg(ap, u32); gfx_con.bgcol = va_arg(ap, u32);
con->fillbg = 1; gfx_con.fillbg = 1;
break; break;
case '%': case '%':
gfx_putc(con, '%'); gfx_putc('%');
break; break;
case '\0': case '\0':
goto out; goto out;
default: default:
gfx_putc(con, '%'); gfx_putc('%');
gfx_putc(con, *fmt); gfx_putc(*fmt);
break; break;
} }
} }
else else
gfx_putc(con, *fmt); gfx_putc(*fmt);
fmt++; fmt++;
} }
@ -398,33 +398,33 @@ void gfx_printf(gfx_con_t *con, const char *fmt, ...)
va_end(ap); va_end(ap);
} }
void gfx_hexdump(gfx_con_t *con, u32 base, const u8 *buf, u32 len) void gfx_hexdump(u32 base, const u8 *buf, u32 len)
{ {
if (con->mute) if (gfx_con.mute)
return; return;
u8 prevFontSize = con->fntsz; u8 prevFontSize = gfx_con.fntsz;
con->fntsz = 8; gfx_con.fntsz = 8;
for(u32 i = 0; i < len; i++) for(u32 i = 0; i < len; i++)
{ {
if(i % 0x10 == 0) if(i % 0x10 == 0)
{ {
if(i != 0) if(i != 0)
{ {
gfx_puts(con, "| "); gfx_puts("| ");
for(u32 j = 0; j < 0x10; j++) for(u32 j = 0; j < 0x10; j++)
{ {
u8 c = buf[i - 0x10 + j]; u8 c = buf[i - 0x10 + j];
if(c >= 32 && c <= 126) if(c >= 32 && c <= 126)
gfx_putc(con, c); gfx_putc(c);
else else
gfx_putc(con, '.'); gfx_putc('.');
} }
gfx_putc(con, '\n'); gfx_putc('\n');
} }
gfx_printf(con, "%08x: ", base + i); gfx_printf("%08x: ", base + i);
} }
gfx_printf(con, "%02x ", buf[i]); gfx_printf("%02x ", buf[i]);
if (i == len - 1) if (i == len - 1)
{ {
int ln = len % 0x10 != 0; int ln = len % 0x10 != 0;
@ -433,22 +433,22 @@ void gfx_hexdump(gfx_con_t *con, u32 base, const u8 *buf, u32 len)
{ {
k = (len & 0xF) - 1; k = (len & 0xF) - 1;
for (u32 j = 0; j < 0x10 - k; j++) for (u32 j = 0; j < 0x10 - k; j++)
gfx_puts(con, " "); gfx_puts(" ");
} }
gfx_puts(con, "| "); gfx_puts("| ");
for(u32 j = 0; j < (ln ? k : k + 1); j++) for(u32 j = 0; j < (ln ? k : k + 1); j++)
{ {
u8 c = buf[i - k + j]; u8 c = buf[i - k + j];
if(c >= 32 && c <= 126) if(c >= 32 && c <= 126)
gfx_putc(con, c); gfx_putc(c);
else else
gfx_putc(con, '.'); gfx_putc('.');
} }
gfx_putc(con, '\n'); gfx_putc('\n');
} }
} }
gfx_putc(con, '\n'); gfx_putc('\n');
con->fntsz = prevFontSize; gfx_con.fntsz = prevFontSize;
} }
static int abs(int x) static int abs(int x)
@ -458,12 +458,12 @@ static int abs(int x)
return x; return x;
} }
void gfx_set_pixel(gfx_ctxt_t *ctxt, u32 x, u32 y, u32 color) void gfx_set_pixel(u32 x, u32 y, u32 color)
{ {
ctxt->fb[x + y * ctxt->stride] = color; gfx_ctxt.fb[x + y * gfx_ctxt.stride] = color;
} }
void gfx_line(gfx_ctxt_t *ctxt, int x0, int y0, int x1, int y1, u32 color) void gfx_line(int x0, int y0, int x1, int y1, u32 color)
{ {
int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1; int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
int dy = abs(y1 - y0), sy = y0 < y1 ? 1 : -1; int dy = abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
@ -471,7 +471,7 @@ void gfx_line(gfx_ctxt_t *ctxt, int x0, int y0, int x1, int y1, u32 color)
while (1) while (1)
{ {
gfx_set_pixel(ctxt, x0, y0, color); gfx_set_pixel(x0, y0, color);
if (x0 == x1 && y0 == y1) if (x0 == x1 && y0 == y1)
break; break;
e2 = err; e2 = err;
@ -488,46 +488,46 @@ void gfx_line(gfx_ctxt_t *ctxt, int x0, int y0, int x1, int y1, u32 color)
} }
} }
void gfx_set_rect_grey(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
{ {
u32 pos = 0; u32 pos = 0;
for (u32 y = pos_y; y < (pos_y + size_y); y++) for (u32 y = pos_y; y < (pos_y + size_y); y++)
{ {
for (u32 x = pos_x; x < (pos_x + size_x); x++) for (u32 x = pos_x; x < (pos_x + size_x); x++)
{ {
memset(&ctxt->fb[x + y*ctxt->stride], buf[pos], 4); memset(&gfx_ctxt.fb[x + y*gfx_ctxt.stride], buf[pos], 4);
pos++; pos++;
} }
} }
} }
void gfx_set_rect_rgb(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
{ {
u32 pos = 0; u32 pos = 0;
for (u32 y = pos_y; y < (pos_y + size_y); y++) for (u32 y = pos_y; y < (pos_y + size_y); y++)
{ {
for (u32 x = pos_x; x < (pos_x + size_x); x++) for (u32 x = pos_x; x < (pos_x + size_x); x++)
{ {
ctxt->fb[x + y*ctxt->stride] = buf[pos + 2] | (buf[pos + 1] << 8) | (buf[pos] << 16); gfx_ctxt.fb[x + y * gfx_ctxt.stride] = buf[pos + 2] | (buf[pos + 1] << 8) | (buf[pos] << 16);
pos+=3; pos+=3;
} }
} }
} }
void gfx_set_rect_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
{ {
u32 *ptr = (u32 *)buf; u32 *ptr = (u32 *)buf;
for (u32 y = pos_y; y < (pos_y + size_y); y++) for (u32 y = pos_y; y < (pos_y + size_y); y++)
for (u32 x = pos_x; x < (pos_x + size_x); x++) for (u32 x = pos_x; x < (pos_x + size_x); x++)
ctxt->fb[x + y * ctxt->stride] = *ptr++; gfx_ctxt.fb[x + y * gfx_ctxt.stride] = *ptr++;
} }
void gfx_render_bmp_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
{ {
for (u32 y = pos_y; y < (pos_y + size_y); y++) for (u32 y = pos_y; y < (pos_y + size_y); y++)
{ {
for (u32 x = pos_x; x < (pos_x + size_x); x++) for (u32 x = pos_x; x < (pos_x + size_x); x++)
ctxt->fb[x + y * ctxt->stride] = buf[(size_y + pos_y - 1 - y ) * size_x + x - pos_x]; gfx_ctxt.fb[x + y * gfx_ctxt.stride] = buf[(size_y + pos_y - 1 - y ) * size_x + x - pos_x];
} }
} }

View file

@ -21,32 +21,32 @@
#include "../../common/common_gfx.h" #include "../../common/common_gfx.h"
#define EPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC) #define EPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
#define EPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC) #define EPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
#define WPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC) #define WPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
#define WPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC) #define WPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
void gfx_init_ctxt(gfx_ctxt_t *ctxt, u32 *fb, u32 width, u32 height, u32 stride); void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride);
void gfx_clear_grey(gfx_ctxt_t *ctxt, u8 color); void gfx_clear_grey(u8 color);
void gfx_clear_partial_grey(gfx_ctxt_t *ctxt, u8 color, u32 pos_x, u32 height); void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height);
void gfx_clear_color(gfx_ctxt_t *ctxt, u32 color); void gfx_clear_color(u32 color);
void gfx_con_init(gfx_con_t *con, gfx_ctxt_t *ctxt); void gfx_con_init();
void gfx_con_setcol(gfx_con_t *con, u32 fgcol, int fillbg, u32 bgcol); void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol);
void gfx_con_getpos(gfx_con_t *con, u32 *x, u32 *y); void gfx_con_getpos(u32 *x, u32 *y);
void gfx_con_setpos(gfx_con_t *con, u32 x, u32 y); void gfx_con_setpos(u32 x, u32 y);
void gfx_putc(gfx_con_t *con, char c); void gfx_putc(char c);
void gfx_puts(gfx_con_t *con, const char *s); void gfx_puts(const char *s);
void gfx_printf(gfx_con_t *con, const char *fmt, ...); void gfx_printf(const char *fmt, ...);
void gfx_hexdump(gfx_con_t *con, u32 base, const u8 *buf, u32 len); void gfx_hexdump(u32 base, const u8 *buf, u32 len);
void gfx_set_pixel(gfx_ctxt_t *ctxt, u32 x, u32 y, u32 color); void gfx_set_pixel(u32 x, u32 y, u32 color);
void gfx_line(gfx_ctxt_t *ctxt, int x0, int y0, int x1, int y1, u32 color); void gfx_line(int x0, int y0, int x1, int y1, u32 color);
void gfx_put_small_sep(gfx_con_t *con); void gfx_put_small_sep(gfx_con_t *con);
void gfx_put_big_sep(gfx_con_t *con); void gfx_put_big_sep(gfx_con_t *con);
void gfx_set_rect_grey(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
void gfx_set_rect_rgb(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
void gfx_set_rect_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
void gfx_render_bmp_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
// Global gfx console and context. // Global gfx console and context.
gfx_ctxt_t gfx_ctxt; gfx_ctxt_t gfx_ctxt;

View file

@ -22,34 +22,18 @@
#include "pkg1.h" #include "pkg1.h"
#include "../sec/se.h" #include "../sec/se.h"
#define SM_100_ADR 0x4002B020
/*
* package1.1 header: <wb, ldr, sm>
* package1.1 layout:
* 1.0: {sm, ldr, wb} { 2, 1, 0 }
* 2.0: {wb, ldr, sm} { 0, 1, 2 }
* 3.0: {wb, ldr, sm} { 0, 1, 2 }
* 3.1: {wb, ldr, sm} { 0, 1, 2 }
* 4.0: {ldr, sm, wb} { 1, 2, 0 }
* 5.0: {ldr, sm, wb} { 1, 2, 0 }
* 6.0: {ldr, sm, wb} { 1, 2, 0 }
* 6.2: {ldr, sm, wb} { 1, 2, 0 }
* 7.0: {ldr, sm, wb} { 1, 2, 0 }
*/
static const pkg1_id_t _pkg1_ids[] = { static const pkg1_id_t _pkg1_ids[] = {
{ "20161121183008", 0, 0x1900, 0x3FE0, { 2, 1, 0 }, SM_100_ADR, 0x8000D000, true, NULL, NULL }, //1.0.0 { "20161121183008", 0, 0x1900, 0x3FE0, 0x4002B020 }, //1.0.0
{ "20170210155124", 0, 0x1900, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, NULL, NULL }, //2.0.0 - 2.3.0 { "20170210155124", 0, 0x1900, 0x3FE0, 0x4002D000 }, //2.0.0 - 2.3.0
{ "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, NULL, NULL }, //3.0.0 { "20170519101410", 1, 0x1A00, 0x3FE0, 0x4002D000 }, //3.0.0
{ "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, NULL, NULL }, //3.0.1 - 3.0.2 { "20170710161758", 2, 0x1A00, 0x3FE0, 0x4002D000 }, //3.0.1 - 3.0.2
{ "20170921172629", 3, 0x1800, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, NULL, NULL }, //4.0.0 - 4.1.0 { "20170921172629", 3, 0x1800, 0x3FE0, 0x4002B000 }, //4.0.0 - 4.1.0
{ "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, NULL, NULL }, //5.0.0 - 5.1.0 { "20180220163747", 4, 0x1900, 0x3FE0, 0x4002B000 }, //5.0.0 - 5.1.0
{ "20180802162753", 5, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, NULL, NULL }, //6.0.0 - 6.1.0 { "20180802162753", 5, 0x1900, 0x3FE0, 0x4002B000 }, //6.0.0 - 6.1.0
{ "20181107105733", 6, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, NULL, NULL }, //6.2.0 { "20181107105733", 6, 0x0E00, 0x6FE0, 0x4002B000 }, //6.2.0
{ "20181218175730", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //7.0.0 { "20181218175730", 7, 0x0F00, 0x6FE0, 0x40030000 }, //7.0.0
{ "20190208150037", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //7.0.1 { "20190208150037", 7, 0x0F00, 0x6FE0, 0x40030000 }, //7.0.1
{ "20190314172056", 7, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //8.0.0 { "20190314172056", 7, 0x0E00, 0x6FE0, 0x40030000 }, //8.0.0
{ NULL } //End. { NULL } //End.
}; };

View file

@ -25,12 +25,7 @@ typedef struct _pkg1_id_t
u32 kb; u32 kb;
u32 tsec_off; u32 tsec_off;
u32 pkg11_off; u32 pkg11_off;
u32 sec_map[3];
u32 secmon_base; u32 secmon_base;
u32 warmboot_base;
bool set_warmboot;
u32 *secmon_patchset;
u32 *warmboot_patchset;
} pkg1_id_t; } pkg1_id_t;
const pkg1_id_t *pkg1_identify(u8 *pkg1); const pkg1_id_t *pkg1_identify(u8 *pkg1);

View file

@ -27,7 +27,7 @@
#include "../gfx/gfx.h" #include "../gfx/gfx.h"
/*#include "util.h" /*#include "util.h"
#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__) #define DPRINTF(...) gfx_printf(__VA_ARGS__)
#define DEBUG_PRINTING*/ #define DEBUG_PRINTING*/
#define DPRINTF(...) #define DPRINTF(...)
@ -103,10 +103,10 @@ int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp)
unsigned int compSize = hdr.sections[sectIdx].size_comp; unsigned int compSize = hdr.sections[sectIdx].size_comp;
unsigned int outputSize = hdr.sections[sectIdx].size_decomp; unsigned int outputSize = hdr.sections[sectIdx].size_decomp;
//gfx_printf(&gfx_con, "Decomping %s KIP1 sect %d of size %d...\n", (const char*)hdr.name, sectIdx, compSize); //gfx_printf("Decomping %s KIP1 sect %d of size %d...\n", (const char*)hdr.name, sectIdx, compSize);
if (blz_uncompress_srcdest(srcDataPtr, compSize, dstDataPtr, outputSize) == 0) if (blz_uncompress_srcdest(srcDataPtr, compSize, dstDataPtr, outputSize) == 0)
{ {
gfx_printf(&gfx_con, "%kERROR decomping sect %d of %s KIP!%k\n", 0xFFFF0000, sectIdx, (char*)hdr.name, 0xFFCCCCCC); gfx_printf("%kERROR decomping sect %d of %s KIP!%k\n", 0xFFFF0000, sectIdx, (char*)hdr.name, 0xFFCCCCCC);
free(newKip); free(newKip);
return 1; return 1;
@ -145,7 +145,7 @@ pkg2_hdr_t *pkg2_decrypt(void *data)
// Decrypt header. // Decrypt header.
se_aes_crypt_ctr(8, hdr, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr); se_aes_crypt_ctr(8, hdr, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr);
//gfx_hexdump(&gfx_con, (u32)hdr, hdr, 0x100); //gfx_hexdump((u32)hdr, hdr, 0x100);
if (hdr->magic != PKG2_MAGIC) if (hdr->magic != PKG2_MAGIC)
return NULL; return NULL;
@ -157,7 +157,7 @@ DPRINTF("sec %d has size %08X\n", i, hdr->sec_size[i]);
continue; continue;
se_aes_crypt_ctr(8, pdata, hdr->sec_size[i], pdata, hdr->sec_size[i], &hdr->sec_ctr[i * 0x10]); se_aes_crypt_ctr(8, pdata, hdr->sec_size[i], pdata, hdr->sec_size[i], &hdr->sec_ctr[i * 0x10]);
//gfx_hexdump(&gfx_con, (u32)pdata, pdata, 0x100); //gfx_hexdump((u32)pdata, pdata, 0x100);
pdata += hdr->sec_size[i]; pdata += hdr->sec_size[i];
} }

View file

@ -26,20 +26,6 @@
#define PKG2_SEC_KERNEL 0 #define PKG2_SEC_KERNEL 0
#define PKG2_SEC_INI1 1 #define PKG2_SEC_INI1 1
#define INI1_MAGIC 0x31494E49
enum
{
// Always applied.
SVC_GENERIC = 0,
// Generic instruction patches.
SVC_VERIFY_DS = 0x10,
DEBUG_MODE_EN,
ATM_GEN_PATCH,
// >4 bytes patches. Value is a pointer of a u32 array.
ATM_ARR_PATCH,
};
typedef struct _pkg2_hdr_t typedef struct _pkg2_hdr_t
{ {
u8 ctr[0x10]; u8 ctr[0x10];

View file

@ -55,7 +55,7 @@ u8 warmboot_reboot[] = {
#define SEPT_STG2_ADDR (SEPT_PK1T_ADDR + 0x60E0) #define SEPT_STG2_ADDR (SEPT_PK1T_ADDR + 0x60E0)
#define SEPT_PKG_SZ (0x2F100 + WB_RST_SIZE) #define SEPT_PKG_SZ (0x2F100 + WB_RST_SIZE)
extern boot_cfg_t *b_cfg; extern boot_cfg_t b_cfg;
extern void sd_unmount(); extern void sd_unmount();
extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size); extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size);
@ -92,7 +92,7 @@ int reboot_to_sept(const u8 *tsec_fw)
// Save auto boot config to payload, if any. // Save auto boot config to payload, if any.
boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t)); boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t));
memcpy(tmp_cfg, b_cfg, sizeof(boot_cfg_t)); memcpy(tmp_cfg, &b_cfg, sizeof(boot_cfg_t));
tmp_cfg->boot_cfg |= BOOT_CFG_SEPT_RUN; tmp_cfg->boot_cfg |= BOOT_CFG_SEPT_RUN;
@ -105,7 +105,7 @@ int reboot_to_sept(const u8 *tsec_fw)
f_close(&fp); f_close(&fp);
sd_unmount(); sd_unmount();
gfx_printf(&gfx_con, "\n%kPress Power or Vol +/-\n%k to Reboot to Sept...", COLOR_BLUE, COLOR_VIOLET); gfx_printf("\n%kPress Power or Vol +/-\n%k to Reboot to Sept...", COLOR_BLUE, COLOR_VIOLET);
btn_wait(); btn_wait();
u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE); u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE);

View file

@ -52,10 +52,10 @@ emmc_part_t *system_part;
#define TPRINTF(text) \ #define TPRINTF(text) \
end_time = get_tmr_ms(); \ end_time = get_tmr_ms(); \
gfx_printf(&gfx_con, text" done @ %d.%03ds\n", (end_time - start_time) / 1000, (end_time - start_time) % 1000) gfx_printf(text" done @ %d.%03ds\n", (end_time - start_time) / 1000, (end_time - start_time) % 1000)
#define TPRINTFARGS(text, args...) \ #define TPRINTFARGS(text, args...) \
end_time = get_tmr_ms(); \ end_time = get_tmr_ms(); \
gfx_printf(&gfx_con, text" done @ %d.%03ds\n", args, (end_time - start_time) / 1000, (end_time - start_time) % 1000) gfx_printf(text" done @ %d.%03ds\n", args, (end_time - start_time) / 1000, (end_time - start_time) % 1000)
#define SAVE_KEY(name, src, len) _save_key(name, src, len, text_buffer, &buf_index) #define SAVE_KEY(name, src, len) _save_key(name, src, len, text_buffer, &buf_index)
#define SAVE_KEY_FAMILY(name, src, count, len) _save_key_family(name, src, count, len, text_buffer, &buf_index) #define SAVE_KEY_FAMILY(name, src, count, len) _save_key_family(name, src, count, len, text_buffer, &buf_index)
@ -227,10 +227,10 @@ static u32 _sprintf(char *buffer, const char *fmt, ...);
void dump_keys() { void dump_keys() {
display_backlight_brightness(100, 1000); display_backlight_brightness(100, 1000);
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1280); gfx_clear_partial_grey(0x1B, 0, 1280);
gfx_con_setpos(&gfx_con, 0, 0); gfx_con_setpos(0, 0);
gfx_printf(&gfx_con, "[%kLo%kck%kpi%kck%k-R%kCM%k v%d.%d%k]\n\n", gfx_printf("[%kLo%kck%kpi%kck%k-R%kCM%k v%d.%d%k]\n\n",
colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, 0xFFCCCCCC); colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, 0xFFCCCCCC);
u32 start_time = get_tmr_ms(), u32 start_time = get_tmr_ms(),
@ -246,15 +246,6 @@ void dump_keys() {
u8 *pkg1 = (u8 *)malloc(0x40000); u8 *pkg1 = (u8 *)malloc(0x40000);
sdmmc_storage_set_mmc_partition(&storage, 1); sdmmc_storage_set_mmc_partition(&storage, 1);
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1); sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
/*FIL pk1fp;
FRESULT fres = FR_OK;
fres += f_open(&pk1fp, "sd:/test/package1", FA_READ | FA_OPEN_EXISTING);
fres += f_read(&pk1fp, pkg1, f_size(&pk1fp), NULL);
fres += f_close(&pk1fp);
if (fres != FR_OK) {
EPRINTF("failed to read pkg1 from sd");
goto out_wait;
}*/
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1); const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
if (!pkg1_id) { if (!pkg1_id) {
EPRINTF("Unknown pkg1 version."); EPRINTF("Unknown pkg1 version.");
@ -287,8 +278,8 @@ void dump_keys() {
u32 payload_size = *(u32 *)(IPL_LOAD_ADDR + 0x84) - IPL_LOAD_ADDR; u32 payload_size = *(u32 *)(IPL_LOAD_ADDR + 0x84) - IPL_LOAD_ADDR;
f_write(&fp, (u8 *)IPL_LOAD_ADDR, payload_size, NULL); f_write(&fp, (u8 *)IPL_LOAD_ADDR, payload_size, NULL);
f_close(&fp); f_close(&fp);
gfx_printf(&gfx_con, "%kFirmware 7.x or higher detected.\n%kRenamed /sept/payload.bin", colors[0], colors[1]); gfx_printf("%kFirmware 7.x or higher detected.\n%kRenamed /sept/payload.bin", colors[0], colors[1]);
gfx_printf(&gfx_con, "\n%k to /sept/payload.bak\n%kCopied self to /sept/payload.bin",colors[2], colors[3]); gfx_printf("\n%k to /sept/payload.bak\n%kCopied self to /sept/payload.bin",colors[2], colors[3]);
sdmmc_storage_end(&storage); sdmmc_storage_end(&storage);
if (!reboot_to_sept((u8 *)pkg1 + pkg1_id->tsec_off)) if (!reboot_to_sept((u8 *)pkg1 + pkg1_id->tsec_off))
goto out_wait; goto out_wait;
@ -376,8 +367,8 @@ get_tsec: ;
se_aes_cmac(3, keyblob_mac, 0x10, keyblob_block + 0x10, 0xa0); se_aes_cmac(3, keyblob_mac, 0x10, keyblob_block + 0x10, 0xa0);
if (memcmp(keyblob_block, keyblob_mac, 0x10)) { if (memcmp(keyblob_block, keyblob_mac, 0x10)) {
EPRINTFARGS("Keyblob %x corrupt.", i); EPRINTFARGS("Keyblob %x corrupt.", i);
gfx_hexdump(&gfx_con, i, keyblob_block, 0x10); gfx_hexdump(i, keyblob_block, 0x10);
gfx_hexdump(&gfx_con, i, keyblob_mac, 0x10); gfx_hexdump(i, keyblob_mac, 0x10);
continue; continue;
} }
@ -433,10 +424,6 @@ get_tsec: ;
// Read in package2 header and get package2 real size. // Read in package2 header and get package2 real size.
u8 *tmp = (u8 *)malloc(NX_EMMC_BLOCKSIZE); u8 *tmp = (u8 *)malloc(NX_EMMC_BLOCKSIZE);
/*FIL pkg2fp;
fres = FR_OK;
fres += f_open(&pkg2fp, "sd:/test/package2", FA_READ | FA_OPEN_EXISTING);
fres += f_read(&pkg2fp, tmp, NX_EMMC_BLOCKSIZE, NULL);*/
nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, 1, tmp); nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, 1, tmp);
u32 *hdr_pkg2_raw = (u32 *)(tmp + 0x100); u32 *hdr_pkg2_raw = (u32 *)(tmp + 0x100);
u32 pkg2_size = hdr_pkg2_raw[0] ^ hdr_pkg2_raw[2] ^ hdr_pkg2_raw[3]; u32 pkg2_size = hdr_pkg2_raw[0] ^ hdr_pkg2_raw[2] ^ hdr_pkg2_raw[3];
@ -449,13 +436,6 @@ get_tsec: ;
// Read in package2. // Read in package2.
u32 pkg2_size_aligned = ALIGN(pkg2_size, NX_EMMC_BLOCKSIZE); u32 pkg2_size_aligned = ALIGN(pkg2_size, NX_EMMC_BLOCKSIZE);
pkg2 = malloc(pkg2_size_aligned); pkg2 = malloc(pkg2_size_aligned);
/*fres += f_lseek(&pkg2fp, 0);
fres += f_read(&pkg2fp, pkg2, f_size(&pkg2fp), NULL);
fres += f_close(&pkg2fp);
if (fres != FR_OK) {
EPRINTF("failed to read pkg2 from sd");
goto pkg2_done;
}*/
nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, pkg2_size_aligned / NX_EMMC_BLOCKSIZE, pkg2); nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, pkg2_size_aligned / NX_EMMC_BLOCKSIZE, pkg2);
// Decrypt package2 and parse KIP1 blobs in INI1 section. // Decrypt package2 and parse KIP1 blobs in INI1 section.
@ -881,19 +861,19 @@ key_output: ;
if (pkg1_id->kb == KB_FIRMWARE_VERSION_620) if (pkg1_id->kb == KB_FIRMWARE_VERSION_620)
SAVE_KEY("tsec_root_key", tsec_keys + 0x10, 0x10); SAVE_KEY("tsec_root_key", tsec_keys + 0x10, 0x10);
//gfx_con.fntsz = 8; gfx_puts(&gfx_con, text_buffer); gfx_con.fntsz = 16; //gfx_con.fntsz = 8; gfx_puts(text_buffer); gfx_con.fntsz = 16;
TPRINTFARGS("\n%kFound %d keys.\n%kLockpick totally", colors[0], _key_count, colors[1]); TPRINTFARGS("\n%kFound %d keys.\n%kLockpick totally", colors[0], _key_count, colors[1]);
f_mkdir("switch"); f_mkdir("switch");
if (!sd_save_to_file(text_buffer, buf_index, "sd:/switch/prod.keys")) if (!sd_save_to_file(text_buffer, buf_index, "sd:/switch/prod.keys"))
gfx_printf(&gfx_con, "%kWrote %d bytes to /switch/prod.keys\n", colors[2], buf_index); gfx_printf("%kWrote %d bytes to /switch/prod.keys\n", colors[2], buf_index);
else else
EPRINTF("Failed to save keys to SD."); EPRINTF("Failed to save keys to SD.");
sd_unmount(); sd_unmount();
free(text_buffer); free(text_buffer);
gfx_printf(&gfx_con, "\n%kVOL + -> Reboot to RCM\n%kVOL - -> Reboot normally\n%kPower -> Power off", colors[3], colors[4], colors[5]); gfx_printf("\n%kVOL + -> Reboot to RCM\n%kVOL - -> Reboot normally\n%kPower -> Power off", colors[3], colors[4], colors[5]);
out_wait: ; out_wait: ;
u32 btn = btn_wait(); u32 btn = btn_wait();

View file

@ -166,7 +166,7 @@ DRESULT disk_read (
memcpy(tweak, sector_cache[s].tweak, 0x10); memcpy(tweak, sector_cache[s].tweak, 0x10);
prev_sector = sector; prev_sector = sector;
prev_cluster = sector / 0x20; prev_cluster = sector / 0x20;
//gfx_printf(&gfx_con, "addr %x sec %x count %x cached\n", sector * 0x200, sector, count); //gfx_printf("addr %x sec %x count %x cached\n", sector * 0x200, sector, count);
return RES_OK; return RES_OK;
} }
} }
@ -180,7 +180,7 @@ DRESULT disk_read (
} }
if (nx_emmc_part_read(&storage, system_part, sector, count, buff)) { if (nx_emmc_part_read(&storage, system_part, sector, count, buff)) {
//gfx_hexdump(&gfx_con, 0, buff, 0x100); //gfx_hexdump(0, buff, 0x100);
if (prev_cluster != sector / 0x20) { // sector in different cluster than last read if (prev_cluster != sector / 0x20) { // sector in different cluster than last read
prev_cluster = sector / 0x20; prev_cluster = sector / 0x20;
tweak_exp = sector % 0x20; tweak_exp = sector % 0x20;
@ -192,13 +192,13 @@ DRESULT disk_read (
} }
// fatfs will never pull more than a cluster // fatfs will never pull more than a cluster
//gfx_printf(&gfx_con, "sec %6x count %2x tweak %2x\n", sector, count, tweak_exp); //gfx_printf("sec %6x count %2x tweak %2x\n", sector, count, tweak_exp);
_emmc_xts(9, 8, 0, tweak, regen_tweak, tweak_exp, prev_cluster, buff, buff, count * 0x200); _emmc_xts(9, 8, 0, tweak, regen_tweak, tweak_exp, prev_cluster, buff, buff, count * 0x200);
if (cache_sector) { if (cache_sector) {
memcpy(sector_cache[s].cached_sector, buff, 0x200); memcpy(sector_cache[s].cached_sector, buff, 0x200);
memcpy(sector_cache[s].tweak, tweak, 0x10); memcpy(sector_cache[s].tweak, tweak, 0x10);
} }
//gfx_hexdump(&gfx_con, 0, buff, 0x10); //gfx_hexdump(0, buff, 0x10);
prev_sector = sector + count - 1; prev_sector = sector + count - 1;
return RES_OK; return RES_OK;
} }

View file

@ -11,7 +11,6 @@ extern "C" {
#include "../../utils/types.h" #include "../../utils/types.h"
/* Status of Disk Functions */ /* Status of Disk Functions */
typedef BYTE DSTATUS; typedef BYTE DSTATUS;
@ -46,11 +45,11 @@ DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
/* Command code for disk_ioctrl fucntion */ /* Command code for disk_ioctrl fucntion */
/* Generic command (Used by FatFs) */ /* Generic command (Used by FatFs) */
#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */ #define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */
#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */ #define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */ #define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */ #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */ #define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */
/* Generic command (Not used by FatFs) */ /* Generic command (Not used by FatFs) */
#define CTRL_POWER 5 /* Get/Set power status */ #define CTRL_POWER 5 /* Get/Set power status */

View file

@ -1,10 +1,10 @@
/*----------------------------------------------------------------------------/ /*----------------------------------------------------------------------------/
/ FatFs - Generic FAT Filesystem Module R0.13b / / FatFs - Generic FAT Filesystem Module R0.13c (p3) /
/-----------------------------------------------------------------------------/ /-----------------------------------------------------------------------------/
/ /
/ Copyright (C) 2018, ChaN, all right reserved. / Copyright (C) 2018, ChaN, all right reserved.
/ Copyright (c) 2018 naehrwert / Copyright (c) 2018 naehrwert
/ Copyright (C) 2018 CTCaer / Copyright (C) 2018-2019 CTCaer
/ /
/ FatFs module is an open source software. Redistribution and use of FatFs in / FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided / source and binary forms, with or without modification, are permitted provided
@ -23,9 +23,9 @@
#include "ff.h" /* Declarations of FatFs API */ #include "ff.h" /* Declarations of FatFs API */
#include "diskio.h" /* Declarations of device I/O functions */ #include "diskio.h" /* Declarations of device I/O functions */
#include "../../gfx/gfx.h" #include "../../gfx/gfx.h"
#define EFSPRINTF(text, ...) print_error(); gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
#define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
//#define EFSPRINTF(...) //#define EFSPRINTF(...)
/*-------------------------------------------------------------------------- /*--------------------------------------------------------------------------
@ -34,11 +34,20 @@
---------------------------------------------------------------------------*/ ---------------------------------------------------------------------------*/
#if FF_DEFINED != 63463 /* Revision ID */ #if FF_DEFINED != 86604 /* Revision ID */
#error Wrong include file (ff.h). #error Wrong include file (ff.h).
#endif #endif
/* Limits and boundaries */
#define MAX_DIR 0x200000 /* Max size of FAT directory */
#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */
#define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */
#define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */
#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */
#define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */
/* Character code support macros */ /* Character code support macros */
#define IsUpper(c) ((c) >= 'A' && (c) <= 'Z') #define IsUpper(c) ((c) >= 'A' && (c) <= 'Z')
#define IsLower(c) ((c) >= 'a' && (c) <= 'z') #define IsLower(c) ((c) >= 'a' && (c) <= 'z')
@ -48,18 +57,18 @@
#define IsSurrogateL(c) ((c) >= 0xDC00 && (c) <= 0xDFFF) #define IsSurrogateL(c) ((c) >= 0xDC00 && (c) <= 0xDFFF)
/* Additional file attribute bits for internal use */
#define AM_VOL 0x08 /* Volume label */
#define AM_LFN 0x0F /* LFN entry */
#define AM_MASK 0x3F /* Mask of defined bits */
/* Additional file access control and file status flags for internal use */ /* Additional file access control and file status flags for internal use */
#define FA_SEEKEND 0x20 /* Seek to end of the file on file open */ #define FA_SEEKEND 0x20 /* Seek to end of the file on file open */
#define FA_MODIFIED 0x40 /* File has been modified */ #define FA_MODIFIED 0x40 /* File has been modified */
#define FA_DIRTY 0x80 /* FIL.buf[] needs to be written-back */ #define FA_DIRTY 0x80 /* FIL.buf[] needs to be written-back */
/* Additional file attribute bits for internal use */
#define AM_VOL 0x08 /* Volume label */
#define AM_LFN 0x0F /* LFN entry */
#define AM_MASK 0x3F /* Mask of defined bits */
/* Name status flags in fn[11] */ /* Name status flags in fn[11] */
#define NSFLAG 11 /* Index of the name status byte */ #define NSFLAG 11 /* Index of the name status byte */
#define NS_LOSS 0x01 /* Out of 8.3 format */ #define NS_LOSS 0x01 /* Out of 8.3 format */
@ -72,13 +81,13 @@
#define NS_NONAME 0x80 /* Not followed */ #define NS_NONAME 0x80 /* Not followed */
/* Limits and boundaries */ /* exFAT directory entry types */
#define MAX_DIR 0x200000 /* Max size of FAT directory */ #define ET_BITMAP 0x81 /* Allocation bitmap */
#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */ #define ET_UPCASE 0x82 /* Up-case table */
#define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */ #define ET_VLABEL 0x83 /* Volume label */
#define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */ #define ET_FILEDIR 0x85 /* File and directory */
#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */ #define ET_STREAM 0xC0 /* Stream extension */
#define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */ #define ET_FILENAME 0xC1 /* Name extension */
/* FatFs refers the FAT structure as simple byte array instead of structure member /* FatFs refers the FAT structure as simple byte array instead of structure member
@ -526,6 +535,7 @@ static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */
#define CODEPAGE CodePage #define CODEPAGE CodePage
static WORD CodePage; /* Current code page */ static WORD CodePage; /* Current code page */
static const BYTE *ExCvt, *DbcTbl; /* Pointer to current SBCS up-case table and DBCS code range table below */ static const BYTE *ExCvt, *DbcTbl; /* Pointer to current SBCS up-case table and DBCS code range table below */
static const BYTE Ct437[] = TBL_CT437; static const BYTE Ct437[] = TBL_CT437;
static const BYTE Ct720[] = TBL_CT720; static const BYTE Ct720[] = TBL_CT720;
static const BYTE Ct737[] = TBL_CT737; static const BYTE Ct737[] = TBL_CT737;
@ -573,7 +583,7 @@ static const BYTE DbcTbl[] = MKCVTBL(TBL_DC, FF_CODE_PAGE);
void print_error() void print_error()
{ {
gfx_printf(&gfx_con, "\n\n\n%k[FatFS] Error: %k", 0xFFFFFF00, 0xFFFFFFFF); gfx_printf("\n\n\n%k[FatFS] Error: %k", 0xFFFFFF00, 0xFFFFFFFF);
} }
@ -1107,7 +1117,7 @@ static FRESULT sync_fs ( /* Returns FR_OK or FR_DISK_ERR */
if (res == FR_OK) { if (res == FR_OK) {
if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { /* FAT32: Update FSInfo sector if needed */ if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { /* FAT32: Update FSInfo sector if needed */
/* Create FSInfo structure */ /* Create FSInfo structure */
mem_set(fs->win, 0, SS(fs)); mem_set(fs->win, 0, sizeof fs->win);
st_word(fs->win + BS_55AA, 0xAA55); st_word(fs->win + BS_55AA, 0xAA55);
st_dword(fs->win + FSI_LeadSig, 0x41615252); st_dword(fs->win + FSI_LeadSig, 0x41615252);
st_dword(fs->win + FSI_StrucSig, 0x61417272); st_dword(fs->win + FSI_StrucSig, 0x61417272);
@ -1307,7 +1317,7 @@ static DWORD find_bitmap ( /* 0:Not found, 2..:Cluster block found, 0xFFFFFFFF:D
if (clst >= fs->n_fatent - 2) clst = 0; if (clst >= fs->n_fatent - 2) clst = 0;
scl = val = clst; ctr = 0; scl = val = clst; ctr = 0;
for (;;) { for (;;) {
if (move_window(fs, fs->database + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; /* (assuming bitmap is located top of the cluster heap) */ if (move_window(fs, fs->bitbase + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF;
i = val / 8 % SS(fs); bm = 1 << (val % 8); i = val / 8 % SS(fs); bm = 1 << (val % 8);
do { do {
do { do {
@ -1345,7 +1355,7 @@ static FRESULT change_bitmap (
clst -= 2; /* The first bit corresponds to cluster #2 */ clst -= 2; /* The first bit corresponds to cluster #2 */
sect = fs->database + clst / 8 / SS(fs); /* Sector address (assuming bitmap is located top of the cluster heap) */ sect = fs->bitbase + clst / 8 / SS(fs); /* Sector address */
i = clst / 8 % SS(fs); /* Byte offset in the sector */ i = clst / 8 % SS(fs); /* Byte offset in the sector */
bm = 1 << (clst % 8); /* Bit mask in the byte */ bm = 1 << (clst % 8); /* Bit mask in the byte */
for (;;) { for (;;) {
@ -1420,7 +1430,7 @@ static FRESULT fill_last_frag (
static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */
FFOBJID* obj, /* Corresponding object */ FFOBJID* obj, /* Corresponding object */
DWORD clst, /* Cluster to remove a chain from */ DWORD clst, /* Cluster to remove a chain from */
DWORD pclst /* Previous cluster of clst (0:entire chain) */ DWORD pclst /* Previous cluster of clst (0 if entire chain) */
) )
{ {
FRESULT res = FR_OK; FRESULT res = FR_OK;
@ -1658,7 +1668,7 @@ static FRESULT dir_clear ( /* Returns FR_OK or FR_DISK_ERR */
if (sync_window(fs) != FR_OK) return FR_DISK_ERR; /* Flush disk access window */ if (sync_window(fs) != FR_OK) return FR_DISK_ERR; /* Flush disk access window */
sect = clst2sect(fs, clst); /* Top of the cluster */ sect = clst2sect(fs, clst); /* Top of the cluster */
fs->winsect = sect; /* Set window to top of the cluster */ fs->winsect = sect; /* Set window to top of the cluster */
mem_set(fs->win, 0, SS(fs)); /* Clear window buffer */ mem_set(fs->win, 0, sizeof fs->win); /* Clear window buffer */
#if FF_USE_LFN == 3 /* Quick table clear by using multi-secter write */ #if FF_USE_LFN == 3 /* Quick table clear by using multi-secter write */
/* Allocate a temporary buffer */ /* Allocate a temporary buffer */
for (szb = ((DWORD)fs->csize * SS(fs) >= MAX_MALLOC) ? MAX_MALLOC : fs->csize * SS(fs), ibuf = 0; szb > SS(fs) && (ibuf = ff_memalloc(szb)) == 0; szb /= 2) ; for (szb = ((DWORD)fs->csize * SS(fs) >= MAX_MALLOC) ? MAX_MALLOC : fs->csize * SS(fs), ibuf = 0; szb > SS(fs) && (ibuf = ff_memalloc(szb)) == 0; szb /= 2) ;
@ -1888,7 +1898,7 @@ static int cmp_lfn ( /* 1:matched, 0:not matched */
for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */
uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */
if (wc != 0) { if (wc != 0) {
if (i >= FF_MAX_LFN || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */ if (i >= FF_MAX_LFN + 1 || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */
return 0; /* Not matched */ return 0; /* Not matched */
} }
wc = uc; wc = uc;
@ -1924,15 +1934,15 @@ static int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */
for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */
uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */
if (wc != 0) { if (wc != 0) {
if (i >= FF_MAX_LFN) return 0; /* Buffer overflow? */ if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */
lfnbuf[i++] = wc = uc; /* Store it */ lfnbuf[i++] = wc = uc; /* Store it */
} else { } else {
if (uc != 0xFFFF) return 0; /* Check filler */ if (uc != 0xFFFF) return 0; /* Check filler */
} }
} }
if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */ if (dir[LDIR_Ord] & LLEF && wc != 0) { /* Put terminator if it is the last LFN part and not terminated */
if (i >= FF_MAX_LFN) return 0; /* Buffer overflow? */ if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */
lfnbuf[i] = 0; lfnbuf[i] = 0;
} }
@ -2168,33 +2178,33 @@ static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */
BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */ BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */
/* Load 85 entry */ /* Load file-directory entry */
res = move_window(dp->obj.fs, dp->sect); res = move_window(dp->obj.fs, dp->sect);
if (res != FR_OK) return res; if (res != FR_OK) return res;
if (dp->dir[XDIR_Type] != 0x85) return FR_INT_ERR; /* Invalid order */ if (dp->dir[XDIR_Type] != ET_FILEDIR) return FR_INT_ERR; /* Invalid order */
mem_cpy(dirb + 0 * SZDIRE, dp->dir, SZDIRE); mem_cpy(dirb + 0 * SZDIRE, dp->dir, SZDIRE);
sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE; sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE;
if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR; if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR;
/* Load C0 entry */ /* Load stream-extension entry */
res = dir_next(dp, 0); res = dir_next(dp, 0);
if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */
if (res != FR_OK) return res; if (res != FR_OK) return res;
res = move_window(dp->obj.fs, dp->sect); res = move_window(dp->obj.fs, dp->sect);
if (res != FR_OK) return res; if (res != FR_OK) return res;
if (dp->dir[XDIR_Type] != 0xC0) return FR_INT_ERR; /* Invalid order */ if (dp->dir[XDIR_Type] != ET_STREAM) return FR_INT_ERR; /* Invalid order */
mem_cpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE); mem_cpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE);
if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR; if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR;
/* Load C1 entries */ /* Load file-name entries */
i = 2 * SZDIRE; /* C1 offset to load */ i = 2 * SZDIRE; /* Name offset to load */
do { do {
res = dir_next(dp, 0); res = dir_next(dp, 0);
if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */
if (res != FR_OK) return res; if (res != FR_OK) return res;
res = move_window(dp->obj.fs, dp->sect); res = move_window(dp->obj.fs, dp->sect);
if (res != FR_OK) return res; if (res != FR_OK) return res;
if (dp->dir[XDIR_Type] != 0xC1) return FR_INT_ERR; /* Invalid order */ if (dp->dir[XDIR_Type] != ET_FILENAME) return FR_INT_ERR; /* Invalid order */
if (i < MAXDIRB(FF_MAX_LFN)) mem_cpy(dirb + i, dp->dir, SZDIRE); if (i < MAXDIRB(FF_MAX_LFN)) mem_cpy(dirb + i, dp->dir, SZDIRE);
} while ((i += SZDIRE) < sz_ent); } while ((i += SZDIRE) < sz_ent);
@ -2299,16 +2309,16 @@ static void create_xdir (
WCHAR wc; WCHAR wc;
/* Create 85,C0 entry */ /* Create file-directory and stream-extension entry */
mem_set(dirb, 0, 2 * SZDIRE); mem_set(dirb, 0, 2 * SZDIRE);
dirb[0 * SZDIRE + XDIR_Type] = 0x85; /* 85 entry */ dirb[0 * SZDIRE + XDIR_Type] = ET_FILEDIR;
dirb[1 * SZDIRE + XDIR_Type] = 0xC0; /* C0 entry */ dirb[1 * SZDIRE + XDIR_Type] = ET_STREAM;
/* Create C1 entries */ /* Create file-name entries */
i = SZDIRE * 2; /* Top of C1 entries */ i = SZDIRE * 2; /* Top of file_name entries */
nlen = nc1 = 0; wc = 1; nlen = nc1 = 0; wc = 1;
do { do {
dirb[i++] = 0xC1; dirb[i++] = 0; /* Entry type C1 */ dirb[i++] = ET_FILENAME; dirb[i++] = 0;
do { /* Fill name field */ do { /* Fill name field */
if (wc != 0 && (wc = lfn[nlen]) != 0) nlen++; /* Get a character if exist */ if (wc != 0 && (wc = lfn[nlen]) != 0) nlen++; /* Get a character if exist */
st_word(dirb + i, wc); /* Store it */ st_word(dirb + i, wc); /* Store it */
@ -2332,8 +2342,8 @@ static void create_xdir (
/* Read an object from the directory */ /* Read an object from the directory */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
#define dir_read_file(dp) dir_read(dp, 0) #define DIR_READ_FILE(dp) dir_read(dp, 0)
#define dir_read_label(dp) dir_read(dp, 1) #define DIR_READ_LABEL(dp) dir_read(dp, 1)
static FRESULT dir_read ( static FRESULT dir_read (
DIR* dp, /* Pointer to the directory object */ DIR* dp, /* Pointer to the directory object */
@ -2342,7 +2352,7 @@ static FRESULT dir_read (
{ {
FRESULT res = FR_NO_FILE; FRESULT res = FR_NO_FILE;
FATFS *fs = dp->obj.fs; FATFS *fs = dp->obj.fs;
BYTE a, c; BYTE attr, b;
#if FF_USE_LFN #if FF_USE_LFN
BYTE ord = 0xFF, sum = 0xFF; BYTE ord = 0xFF, sum = 0xFF;
#endif #endif
@ -2350,16 +2360,16 @@ static FRESULT dir_read (
while (dp->sect) { while (dp->sect) {
res = move_window(fs, dp->sect); res = move_window(fs, dp->sect);
if (res != FR_OK) break; if (res != FR_OK) break;
c = dp->dir[DIR_Name]; /* Test for the entry type */ b = dp->dir[DIR_Name]; /* Test for the entry type */
if (c == 0) { if (b == 0) {
res = FR_NO_FILE; break; /* Reached to end of the directory */ res = FR_NO_FILE; break; /* Reached to end of the directory */
} }
#if FF_FS_EXFAT #if FF_FS_EXFAT
if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
if (FF_USE_LABEL && vol) { if (FF_USE_LABEL && vol) {
if (c == 0x83) break; /* Volume label entry? */ if (b == ET_VLABEL) break; /* Volume label entry? */
} else { } else {
if (c == 0x85) { /* Start of the file entry block? */ if (b == ET_FILEDIR) { /* Start of the file entry block? */
dp->blk_ofs = dp->dptr; /* Get location of the block */ dp->blk_ofs = dp->dptr; /* Get location of the block */
res = load_xdir(dp); /* Load the entry block */ res = load_xdir(dp); /* Load the entry block */
if (res == FR_OK) { if (res == FR_OK) {
@ -2371,19 +2381,19 @@ static FRESULT dir_read (
} else } else
#endif #endif
{ /* On the FAT/FAT32 volume */ { /* On the FAT/FAT32 volume */
dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ dp->obj.attr = attr = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */
#if FF_USE_LFN /* LFN configuration */ #if FF_USE_LFN /* LFN configuration */
if (c == DDEM || c == '.' || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ if (b == DDEM || b == '.' || (int)((attr & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */
ord = 0xFF; ord = 0xFF;
} else { } else {
if (a == AM_LFN) { /* An LFN entry is found */ if (attr == AM_LFN) { /* An LFN entry is found */
if (c & LLEF) { /* Is it start of an LFN sequence? */ if (b & LLEF) { /* Is it start of an LFN sequence? */
sum = dp->dir[LDIR_Chksum]; sum = dp->dir[LDIR_Chksum];
c &= (BYTE)~LLEF; ord = c; b &= (BYTE)~LLEF; ord = b;
dp->blk_ofs = dp->dptr; dp->blk_ofs = dp->dptr;
} }
/* Check LFN validity and capture it */ /* Check LFN validity and capture it */
ord = (c == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; ord = (b == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF;
} else { /* An SFN entry is found */ } else { /* An SFN entry is found */
if (ord != 0 || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */ if (ord != 0 || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */
dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */ dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */
@ -2392,7 +2402,7 @@ static FRESULT dir_read (
} }
} }
#else /* Non LFN configuration */ #else /* Non LFN configuration */
if (c != DDEM && c != '.' && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */ if (b != DDEM && b != '.' && attr != AM_LFN && (int)((attr & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */
break; break;
} }
#endif #endif
@ -2432,7 +2442,7 @@ static FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */
UINT di, ni; UINT di, ni;
WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */ WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */
while ((res = dir_read_file(dp)) == FR_OK) { /* Read an item */ while ((res = DIR_READ_FILE(dp)) == FR_OK) { /* Read an item */
#if FF_MAX_LFN < 255 #if FF_MAX_LFN < 255
if (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue; /* Skip comparison if inaccessible object name */ if (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue; /* Skip comparison if inaccessible object name */
#endif #endif
@ -2511,17 +2521,17 @@ static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too
#if FF_FS_EXFAT #if FF_FS_EXFAT
if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */ nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */
res = dir_alloc(dp, nent); /* Allocate entries */ res = dir_alloc(dp, nent); /* Allocate directory entries */
if (res != FR_OK) return res; if (res != FR_OK) return res;
dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */ dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */
if (dp->obj.stat & 4) { /* Has the directory been stretched? */ if (dp->obj.stat & 4) { /* Has the directory been stretched by new allocation? */
dp->obj.stat &= ~4; dp->obj.stat &= ~4;
res = fill_first_frag(&dp->obj); /* Fill the first fragment on the FAT if needed */ res = fill_first_frag(&dp->obj); /* Fill the first fragment on the FAT if needed */
if (res != FR_OK) return res; if (res != FR_OK) return res;
res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill the last fragment on the FAT if needed */ res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill the last fragment on the FAT if needed */
if (res != FR_OK) return res; if (res != FR_OK) return res;
if (dp->obj.sclust != 0) { /* Is it a sub directory? */ if (dp->obj.sclust != 0) { /* Is it a sub-directory? */
DIR dj; DIR dj;
res = load_obj_xdir(&dj, &dp->obj); /* Load the object status */ res = load_obj_xdir(&dj, &dp->obj); /* Load the object status */
@ -2653,6 +2663,7 @@ static void get_fileinfo (
{ {
UINT si, di; UINT si, di;
#if FF_USE_LFN #if FF_USE_LFN
BYTE lcf;
WCHAR wc, hs; WCHAR wc, hs;
FATFS *fs = dp->obj.fs; FATFS *fs = dp->obj.fs;
#else #else
@ -2713,9 +2724,10 @@ static void get_fileinfo (
if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccesible */ if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccesible */
fno->fname[di++] = '?'; fno->fname[di++] = '?';
} else { } else {
for (si = di = 0; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */ for (si = di = 0, lcf = NS_BODY; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */
wc = (WCHAR)fno->altname[si]; wc = (WCHAR)fno->altname[si];
if (IsUpper(wc) && (dp->dir[DIR_NTres] & ((si >= 9) ? NS_EXT : NS_BODY))) wc += 0x20; if (wc == '.') lcf = NS_EXT;
if (IsUpper(wc) && (dp->dir[DIR_NTres] & lcf)) wc += 0x20;
fno->fname[di] = (TCHAR)wc; fno->fname[di] = (TCHAR)wc;
} }
} }
@ -3272,7 +3284,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR;
#endif #endif
/* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK and SFD. */ /* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK (MBR) and SFD (w/o partition). */
bsect = 0; bsect = 0;
fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */ fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */
if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) { /* Not an FAT-VBR or forced partition number */ if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) { /* Not an FAT-VBR or forced partition number */
@ -3301,13 +3313,12 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
#if FF_FS_EXFAT #if FF_FS_EXFAT
if (fmt == 1) { if (fmt == 1) {
QWORD maxlba; QWORD maxlba;
DWORD so, cv, bcl;
for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */ for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */
if (i < BPB_ZeroedEx + 53) if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM;
return FR_NO_FILESYSTEM;
if (ld_word(fs->win + BPB_FSVerEx) != 0x100) if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT version (must be version 1.0) */
return FR_NO_FILESYSTEM; /* Check exFAT version (must be version 1.0) */
if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) { /* (BPB_BytsPerSecEx must be equal to the physical sector size) */ if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) { /* (BPB_BytsPerSecEx must be equal to the physical sector size) */
EFSPRINTF("EXSPS"); EFSPRINTF("EXSPS");
@ -3315,8 +3326,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
} }
maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA + 1 of the volume */ maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA + 1 of the volume */
if (maxlba >= 0x100000000) if (maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */
return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */
fs->fsize = ld_dword(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */ fs->fsize = ld_dword(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */
@ -3327,35 +3337,49 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
} }
fs->csize = 1 << fs->win[BPB_SecPerClusEx]; /* Cluster size */ fs->csize = 1 << fs->win[BPB_SecPerClusEx]; /* Cluster size */
if (fs->csize == 0) { if (fs->csize == 0) return FR_NO_FILESYSTEM; /* (Must be 1..32768) */
return FR_NO_FILESYSTEM; /* (Must be 1..32768) */
}
nclst = ld_dword(fs->win + BPB_NumClusEx); /* Number of clusters */ nclst = ld_dword(fs->win + BPB_NumClusEx); /* Number of clusters */
if (nclst > MAX_EXFAT) if (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */
return FR_NO_FILESYSTEM; /* (Too many clusters) */
fs->n_fatent = nclst + 2; fs->n_fatent = nclst + 2;
/* Boundaries and Limits */ /* Boundaries and Limits */
fs->volbase = bsect; fs->volbase = bsect;
fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx); fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx);
fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx); fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx);
if (maxlba < (QWORD)fs->database + nclst * fs->csize) if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */
return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size required) */
fs->dirbase = ld_dword(fs->win + BPB_RootClusEx); fs->dirbase = ld_dword(fs->win + BPB_RootClusEx);
/* Check if bitmap location is in assumption (at the first cluster) */ /* Get bitmap location and check if it is contiguous (implementation assumption) */
if (move_window(fs, clst2sect(fs, fs->dirbase)) != FR_OK) { so = i = 0;
for (;;) { /* Find the bitmap entry in the root directory (in only first cluster) */
if (i == 0) {
if (so >= fs->csize) return FR_NO_FILESYSTEM; /* Not found? */
if (move_window(fs, clst2sect(fs, fs->dirbase) + so) != FR_OK) {
EFSPRINTF("EXBM1C"); EFSPRINTF("EXBM1C");
return FR_DISK_ERR; return FR_DISK_ERR;
} }
for (i = 0; i < SS(fs); i += SZDIRE) { so++;
if (fs->win[i] == 0x81 && ld_dword(fs->win + i + 20) == 2) break; /* 81 entry with cluster #2? */
} }
if (i == SS(fs)) { if (fs->win[i] == ET_BITMAP) break; /* Is it a bitmap entry? */
i = (i + SZDIRE) % SS(fs); /* Next entry */
}
bcl = ld_dword(fs->win + i + 20); /* Bitmap cluster */
if (bcl < 2 || bcl >= fs->n_fatent) {
EFSPRINTF("EXBMM"); EFSPRINTF("EXBMM");
return FR_NO_FILESYSTEM; return FR_NO_FILESYSTEM;
} }
fs->bitbase = fs->database + fs->csize * (bcl - 2); /* Bitmap sector */
for (;;) { /* Check if bitmap is contiguous */
if (move_window(fs, fs->fatbase + bcl / (SS(fs) / 4)) != FR_OK) return FR_DISK_ERR;
cv = ld_dword(fs->win + bcl % (SS(fs) / 4) * 4);
if (cv == 0xFFFFFFFF) break; /* Last link? */
if (cv != ++bcl) {
EFSPRINTF("EXBMM");
return FR_NO_FILESYSTEM; /* Fragmented? */
}
}
#if !FF_FS_READONLY #if !FF_FS_READONLY
fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */
#endif #endif
@ -3373,38 +3397,31 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
fs->fsize = fasize; fs->fsize = fasize;
fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */ fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */
if (fs->n_fats != 1 && fs->n_fats != 2) if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */
return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */
fasize *= fs->n_fats; /* Number of sectors for FAT area */ fasize *= fs->n_fats; /* Number of sectors for FAT area */
fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */ fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */
if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */
return FR_NO_FILESYSTEM; /* (Must be power of 2) */
fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */
if (fs->n_rootdir % (SS(fs) / SZDIRE)) if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */
return FR_NO_FILESYSTEM; /* (Must be sector aligned) */
tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */
if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32); if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32);
nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */
if (nrsv == 0) if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */
return FR_NO_FILESYSTEM; /* (Must not be 0) */
/* Determine the FAT sub type */ /* Determine the FAT sub type */
sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + DIR */ sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + DIR */
if (tsect < sysect) if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
return FR_NO_FILESYSTEM; /* (Invalid volume size) */
nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ nclst = (tsect - sysect) / fs->csize; /* Number of clusters */
if (nclst == 0) if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
return FR_NO_FILESYSTEM; /* (Invalid volume size) */
fmt = 0; fmt = 0;
if (nclst <= MAX_FAT32) fmt = FS_FAT32; if (nclst <= MAX_FAT32) fmt = FS_FAT32;
if (nclst <= MAX_FAT16) fmt = FS_FAT16; if (nclst <= MAX_FAT16) fmt = FS_FAT16;
if (nclst <= MAX_FAT12) fmt = FS_FAT12; if (nclst <= MAX_FAT12) fmt = FS_FAT12;
if (fmt == 0) if (fmt == 0) return FR_NO_FILESYSTEM;
return FR_NO_FILESYSTEM;
/* Boundaries and Limits */ /* Boundaries and Limits */
fs->n_fatent = nclst + 2; /* Number of FAT entries */ fs->n_fatent = nclst + 2; /* Number of FAT entries */
@ -3412,21 +3429,17 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
fs->fatbase = bsect + nrsv; /* FAT start sector */ fs->fatbase = bsect + nrsv; /* FAT start sector */
fs->database = bsect + sysect; /* Data start sector */ fs->database = bsect + sysect; /* Data start sector */
if (fmt == FS_FAT32) { if (fmt == FS_FAT32) {
if (ld_word(fs->win + BPB_FSVer32) != 0) if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */
return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */ if (fs->n_rootdir != 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */
if (fs->n_rootdir != 0)
return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */
fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* Root directory start cluster */ fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* Root directory start cluster */
szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ szbfat = fs->n_fatent * 4; /* (Needed FAT size) */
} else { } else {
if (fs->n_rootdir == 0) if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */
return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */
fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */
szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */
fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);
} }
if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */
return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */
#if !FF_FS_READONLY #if !FF_FS_READONLY
/* Get FSInfo if available */ /* Get FSInfo if available */
@ -3459,7 +3472,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
#if FF_USE_LFN == 1 #if FF_USE_LFN == 1
fs->lfnbuf = LfnBuf; /* Static LFN working buffer */ fs->lfnbuf = LfnBuf; /* Static LFN working buffer */
#if FF_FS_EXFAT #if FF_FS_EXFAT
fs->dirbuf = DirBuf; /* Static directory block scratchpad buffer */ fs->dirbuf = DirBuf; /* Static directory block scratchpad buuffer */
#endif #endif
#endif #endif
#if FF_FS_RPATH != 0 #if FF_FS_RPATH != 0
@ -3722,7 +3735,7 @@ FRESULT f_open (
fp->fptr = 0; /* Set file pointer top of the file */ fp->fptr = 0; /* Set file pointer top of the file */
#if !FF_FS_READONLY #if !FF_FS_READONLY
#if !FF_FS_TINY #if !FF_FS_TINY
mem_set(fp->buf, 0, FF_MAX_SS); /* Clear sector buffer */ mem_set(fp->buf, 0, sizeof fp->buf); /* Clear sector buffer */
#endif #endif
if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */ if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */
fp->fptr = fp->obj.objsize; /* Offset to seek */ fp->fptr = fp->obj.objsize; /* Offset to seek */
@ -3777,7 +3790,6 @@ FRESULT f_read (
UINT rcnt, cc, csect; UINT rcnt, cc, csect;
BYTE *rbuff = (BYTE*)buff; BYTE *rbuff = (BYTE*)buff;
UINT br_tmp; UINT br_tmp;
if (!br) if (!br)
br = &br_tmp; br = &br_tmp;
@ -3787,10 +3799,7 @@ FRESULT f_read (
EFSPRINTF("FOV"); EFSPRINTF("FOV");
LEAVE_FF(fs, res); /* Check validity */ LEAVE_FF(fs, res); /* Check validity */
} }
if (!(fp->flag & FA_READ)) { if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
EFSPRINTF("NOACCESS");
LEAVE_FF(fs, FR_DENIED); /* Check access mode */
}
remain = fp->obj.objsize - fp->fptr; remain = fp->obj.objsize - fp->fptr;
if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
@ -3822,9 +3831,7 @@ FRESULT f_read (
fp->clust = clst; /* Update current cluster */ fp->clust = clst; /* Update current cluster */
} }
sect = clst2sect(fs, fp->clust); /* Get current sector */ sect = clst2sect(fs, fp->clust); /* Get current sector */
if (sect == 0) { if (sect == 0) ABORT(fs, FR_INT_ERR);
ABORT(fs, FR_INT_ERR);
}
sect += csect; sect += csect;
cc = btr / SS(fs); /* When remaining bytes >= sector size, */ cc = btr / SS(fs); /* When remaining bytes >= sector size, */
if (cc > 0) { /* Read maximum contiguous sectors directly */ if (cc > 0) { /* Read maximum contiguous sectors directly */
@ -3902,7 +3909,6 @@ FRESULT f_write (
UINT wcnt, cc, csect; UINT wcnt, cc, csect;
const BYTE *wbuff = (const BYTE*)buff; const BYTE *wbuff = (const BYTE*)buff;
UINT bw_tmp; UINT bw_tmp;
if (!bw) if (!bw)
bw = &bw_tmp; bw = &bw_tmp;
@ -3912,10 +3918,7 @@ FRESULT f_write (
EFSPRINTF("FOV"); EFSPRINTF("FOV");
LEAVE_FF(fs, res); /* Check validity */ LEAVE_FF(fs, res); /* Check validity */
} }
if (!(fp->flag & FA_WRITE)) { if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
EFSPRINTF("NOACCESS");
LEAVE_FF(fs, FR_DENIED); /* Check access mode */
}
/* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */ /* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */
if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) { if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) {
@ -3961,15 +3964,12 @@ FRESULT f_write (
if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Write-back sector cache */ if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Write-back sector cache */
#else #else
if (fp->flag & FA_DIRTY) { /* Write-back sector cache */ if (fp->flag & FA_DIRTY) { /* Write-back sector cache */
if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
ABORT(fs, FR_DISK_ERR);
fp->flag &= (BYTE)~FA_DIRTY; fp->flag &= (BYTE)~FA_DIRTY;
} }
#endif #endif
sect = clst2sect(fs, fp->clust); /* Get current sector */ sect = clst2sect(fs, fp->clust); /* Get current sector */
if (sect == 0) { if (sect == 0) ABORT(fs, FR_INT_ERR);
ABORT(fs, FR_INT_ERR);
}
sect += csect; sect += csect;
cc = btw / SS(fs); /* When remaining bytes >= sector size, */ cc = btw / SS(fs); /* When remaining bytes >= sector size, */
if (cc > 0) { /* Write maximum contiguous sectors directly */ if (cc > 0) { /* Write maximum contiguous sectors directly */
@ -4004,8 +4004,9 @@ FRESULT f_write (
#else #else
if (fp->sect != sect && /* Fill sector cache with file data */ if (fp->sect != sect && /* Fill sector cache with file data */
fp->fptr < fp->obj.objsize && fp->fptr < fp->obj.objsize &&
disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) {
ABORT(fs, FR_DISK_ERR); ABORT(fs, FR_DISK_ERR);
}
#endif #endif
fp->sect = sect; fp->sect = sect;
} }
@ -4251,6 +4252,7 @@ FRESULT f_getcwd (
/* Get logical drive */ /* Get logical drive */
buff[0] = 0; /* Set null string to get current volume */
res = find_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */ res = find_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */
if (res == FR_OK) { if (res == FR_OK) {
dj.obj.fs = fs; dj.obj.fs = fs;
@ -4269,7 +4271,7 @@ FRESULT f_getcwd (
res = dir_sdi(&dj, 0); res = dir_sdi(&dj, 0);
if (res != FR_OK) break; if (res != FR_OK) break;
do { /* Find the entry links to the child directory */ do { /* Find the entry links to the child directory */
res = dir_read_file(&dj); res = DIR_READ_FILE(&dj);
if (res != FR_OK) break; if (res != FR_OK) break;
if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */ if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */
res = dir_next(&dj, 0); res = dir_next(&dj, 0);
@ -4601,7 +4603,7 @@ FRESULT f_readdir (
res = dir_sdi(dp, 0); /* Rewind the directory object */ res = dir_sdi(dp, 0); /* Rewind the directory object */
} else { } else {
INIT_NAMBUF(fs); INIT_NAMBUF(fs);
res = dir_read_file(dp); /* Read an item */ res = DIR_READ_FILE(dp); /* Read an item */
if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */ if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */
if (res == FR_OK) { /* A valid entry is found */ if (res == FR_OK) { /* A valid entry is found */
get_fileinfo(dp, fno); /* Get the object information */ get_fileinfo(dp, fno); /* Get the object information */
@ -4746,7 +4748,7 @@ FRESULT f_getfree (
UINT b; UINT b;
clst = fs->n_fatent - 2; /* Number of clusters */ clst = fs->n_fatent - 2; /* Number of clusters */
sect = fs->database; /* Assuming bitmap starts at cluster 2 */ sect = fs->bitbase; /* Bitmap sector */
i = 0; /* Offset in the sector */ i = 0; /* Offset in the sector */
do { /* Counts numbuer of bits with zero in the bitmap */ do { /* Counts numbuer of bits with zero in the bitmap */
if (i == 0) { if (i == 0) {
@ -4909,7 +4911,7 @@ FRESULT f_unlink (
#endif #endif
res = dir_sdi(&sdj, 0); res = dir_sdi(&sdj, 0);
if (res == FR_OK) { if (res == FR_OK) {
res = dir_read_file(&sdj); /* Test if the directory is empty */ res = DIR_READ_FILE(&sdj); /* Test if the directory is empty */
if (res == FR_OK) res = FR_DENIED; /* Not empty? */ if (res == FR_OK) res = FR_DENIED; /* Not empty? */
if (res == FR_NO_FILE) res = FR_OK; /* Empty? */ if (res == FR_NO_FILE) res = FR_OK; /* Empty? */
} }
@ -4949,47 +4951,43 @@ FRESULT f_mkdir (
DIR dj; DIR dj;
FFOBJID sobj; FFOBJID sobj;
FATFS *fs; FATFS *fs;
BYTE *dir;
DWORD dcl, pcl, tm; DWORD dcl, pcl, tm;
DEF_NAMBUF DEF_NAMBUF
/* Get logical drive */ res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */
res = find_volume(&path, &fs, FA_WRITE);
if (res == FR_OK) { if (res == FR_OK) {
dj.obj.fs = fs; dj.obj.fs = fs;
INIT_NAMBUF(fs); INIT_NAMBUF(fs);
res = follow_path(&dj, path); /* Follow the file path */ res = follow_path(&dj, path); /* Follow the file path */
if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */ if (res == FR_OK) res = FR_EXIST; /* Name collision? */
if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { /* Invalid name? */
res = FR_INVALID_NAME; res = FR_INVALID_NAME;
} }
if (res == FR_NO_FILE) { /* Can create a new directory */ if (res == FR_NO_FILE) { /* It is clear to create a new directory */
sobj.fs = fs; /* New object id to create a new chain */ sobj.fs = fs; /* New object id to create a new chain */
dcl = create_chain(&sobj, 0); /* Allocate a cluster for the new directory */ dcl = create_chain(&sobj, 0); /* Allocate a cluster for the new directory */
res = FR_OK; res = FR_OK;
if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */ if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster? */
if (dcl == 1) res = FR_INT_ERR; if (dcl == 1) res = FR_INT_ERR; /* Any insanity? */
if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; /* Disk error? */
if (res == FR_OK) res = sync_window(fs); /* Flush FAT */
tm = GET_FATTIME(); tm = GET_FATTIME();
if (res == FR_OK) { /* Initialize the new directory table */ if (res == FR_OK) {
res = dir_clear(fs, dcl); /* Clean up the new table */ res = dir_clear(fs, dcl); /* Clean up the new table */
if (res == FR_OK && (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT)) { /* Create dot entries (FAT only) */ if (res == FR_OK) {
dir = fs->win; if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* Create dot entries (FAT only) */
mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */ mem_set(fs->win + DIR_Name, ' ', 11); /* Create "." entry */
dir[DIR_Name] = '.'; fs->win[DIR_Name] = '.';
dir[DIR_Attr] = AM_DIR; fs->win[DIR_Attr] = AM_DIR;
st_dword(dir + DIR_ModTime, tm); st_dword(fs->win + DIR_ModTime, tm);
st_clust(fs, dir, dcl); st_clust(fs, fs->win, dcl);
mem_cpy(dir + SZDIRE, dir, SZDIRE); /* Create ".." entry */ mem_cpy(fs->win + SZDIRE, fs->win, SZDIRE); /* Create ".." entry */
dir[SZDIRE + 1] = '.'; pcl = dj.obj.sclust; fs->win[SZDIRE + 1] = '.'; pcl = dj.obj.sclust;
st_clust(fs, dir + SZDIRE, pcl); st_clust(fs, fs->win + SZDIRE, pcl);
fs->wflag = 1; fs->wflag = 1;
} }
res = dir_register(&dj); /* Register the object to the parent directoy */
} }
if (res == FR_OK) {
res = dir_register(&dj); /* Register the object to the directoy */
} }
if (res == FR_OK) { if (res == FR_OK) {
#if FF_FS_EXFAT #if FF_FS_EXFAT
@ -5004,17 +5002,16 @@ FRESULT f_mkdir (
} else } else
#endif #endif
{ {
dir = dj.dir; st_dword(dj.dir + DIR_ModTime, tm); /* Created time */
st_dword(dir + DIR_ModTime, tm); /* Created time */ st_clust(fs, dj.dir, dcl); /* Table start cluster */
st_clust(fs, dir, dcl); /* Table start cluster */ dj.dir[DIR_Attr] = AM_DIR; /* Attribute */
dir[DIR_Attr] = AM_DIR; /* Attribute */
fs->wflag = 1; fs->wflag = 1;
} }
if (res == FR_OK) { if (res == FR_OK) {
res = sync_fs(fs); res = sync_fs(fs);
} }
} else { } else {
remove_chain(&dj.obj, dcl, 0); /* Could not register, remove cluster chain */ remove_chain(&sobj, dcl, 0); /* Could not register, remove the allocated cluster */
} }
} }
FREE_NAMBUF(); FREE_NAMBUF();
@ -5254,7 +5251,7 @@ FRESULT f_getlabel (
dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */
res = dir_sdi(&dj, 0); res = dir_sdi(&dj, 0);
if (res == FR_OK) { if (res == FR_OK) {
res = dir_read_label(&dj); /* Find a volume label entry */ res = DIR_READ_LABEL(&dj); /* Find a volume label entry */
if (res == FR_OK) { if (res == FR_OK) {
#if FF_FS_EXFAT #if FF_FS_EXFAT
if (fs->fs_type == FS_EXFAT) { if (fs->fs_type == FS_EXFAT) {
@ -5399,7 +5396,7 @@ FRESULT f_setlabel (
dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */
res = dir_sdi(&dj, 0); res = dir_sdi(&dj, 0);
if (res == FR_OK) { if (res == FR_OK) {
res = dir_read_label(&dj); /* Get volume label entry */ res = DIR_READ_LABEL(&dj); /* Get volume label entry */
if (res == FR_OK) { if (res == FR_OK) {
if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) {
dj.dir[XDIR_NumLabel] = (BYTE)di; /* Change the volume label */ dj.dir[XDIR_NumLabel] = (BYTE)di; /* Change the volume label */
@ -5421,7 +5418,7 @@ FRESULT f_setlabel (
if (res == FR_OK) { if (res == FR_OK) {
mem_set(dj.dir, 0, SZDIRE); /* Clean the entry */ mem_set(dj.dir, 0, SZDIRE); /* Clean the entry */
if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) {
dj.dir[XDIR_Type] = 0x83; /* Create 83 entry */ dj.dir[XDIR_Type] = ET_VLABEL; /* Create volume label entry */
dj.dir[XDIR_NumLabel] = (BYTE)di; dj.dir[XDIR_NumLabel] = (BYTE)di;
mem_cpy(dj.dir + XDIR_Label, dirvn, 22); mem_cpy(dj.dir + XDIR_Label, dirvn, 22);
} else { } else {
@ -5726,7 +5723,7 @@ FRESULT f_mkfs (
b_fat = b_vol + 32; /* FAT start at offset 32 */ b_fat = b_vol + 32; /* FAT start at offset 32 */
sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */ sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */
b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */ b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */
if (b_data >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ if (b_data - b_vol >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */
n_clst = (sz_vol - (b_data - b_vol)) / au; /* Number of clusters */ n_clst = (sz_vol - (b_data - b_vol)) / au; /* Number of clusters */
if (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too few clusters? */ if (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too few clusters? */
if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */ if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */
@ -5807,11 +5804,11 @@ FRESULT f_mkfs (
/* Initialize the root directory */ /* Initialize the root directory */
mem_set(buf, 0, szb_buf); mem_set(buf, 0, szb_buf);
buf[SZDIRE * 0 + 0] = 0x83; /* 83 entry (volume label) */ buf[SZDIRE * 0 + 0] = ET_VLABEL; /* Volume label entry */
buf[SZDIRE * 1 + 0] = 0x81; /* 81 entry (allocation bitmap) */ buf[SZDIRE * 1 + 0] = ET_BITMAP; /* Bitmap entry */
st_dword(buf + SZDIRE * 1 + 20, 2); /* cluster */ st_dword(buf + SZDIRE * 1 + 20, 2); /* cluster */
st_dword(buf + SZDIRE * 1 + 24, szb_bit); /* size */ st_dword(buf + SZDIRE * 1 + 24, szb_bit); /* size */
buf[SZDIRE * 2 + 0] = 0x82; /* 82 entry (up-case table) */ buf[SZDIRE * 2 + 0] = ET_UPCASE; /* Up-case table entry */
st_dword(buf + SZDIRE * 2 + 4, sum); /* sum */ st_dword(buf + SZDIRE * 2 + 4, sum); /* sum */
st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); /* cluster */ st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); /* cluster */
st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */ st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */
@ -6299,8 +6296,7 @@ typedef struct { /* Putchar output buffer and work area */
} putbuff; } putbuff;
static static void putc_bfd ( /* Buffered write with code conversion */
void putc_bfd ( /* Buffered write with code conversion */
putbuff* pb, putbuff* pb,
TCHAR c TCHAR c
) )
@ -6411,7 +6407,7 @@ void putc_bfd ( /* Buffered write with code conversion */
#else /* Write it in ANSI/OEM */ #else /* Write it in ANSI/OEM */
if (hs != 0) return; if (hs != 0) return;
wc = ff_uni2oem(wc, CODEPAGE); /* UTF-16 ==> ANSI/OEM */ wc = ff_uni2oem(wc, CODEPAGE); /* UTF-16 ==> ANSI/OEM */
if (wc == 0) return;; if (wc == 0) return;
if (wc >= 0x100) { if (wc >= 0x100) {
pb->buf[i++] = (BYTE)(wc >> 8); nc++; pb->buf[i++] = (BYTE)(wc >> 8); nc++;
} }
@ -6431,8 +6427,7 @@ void putc_bfd ( /* Buffered write with code conversion */
} }
static static int putc_flush ( /* Flush left characters in the buffer */
int putc_flush ( /* Flush left characters in the buffer */
putbuff* pb putbuff* pb
) )
{ {
@ -6445,8 +6440,7 @@ int putc_flush ( /* Flush left characters in the buffer */
} }
static static void putc_init ( /* Initialize write buffer */
void putc_init ( /* Initialize write buffer */
putbuff* pb, putbuff* pb,
FIL* fp FIL* fp
) )

View file

@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------/ /*----------------------------------------------------------------------------/
/ FatFs - Generic FAT Filesystem module R0.13b / / FatFs - Generic FAT Filesystem module R0.13c /
/-----------------------------------------------------------------------------/ /-----------------------------------------------------------------------------/
/ /
/ Copyright (C) 2018, ChaN, all right reserved. / Copyright (C) 2018, ChaN, all right reserved.
@ -20,7 +20,7 @@
#ifndef FF_DEFINED #ifndef FF_DEFINED
#define FF_DEFINED 63463 /* Revision ID */ #define FF_DEFINED 86604 /* Revision ID */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -95,8 +95,8 @@ typedef DWORD FSIZE_t;
/* Filesystem object structure (FATFS) */ /* Filesystem object structure (FATFS) */
typedef struct { typedef struct {
BYTE fs_type; /* Filesystem type (0:N/A) */ BYTE fs_type; /* Filesystem type (0:not mounted) */
BYTE pdrv; /* Physical drive number */ BYTE pdrv; /* Associated physical drive */
BYTE n_fats; /* Number of FATs (1 or 2) */ BYTE n_fats; /* Number of FATs (1 or 2) */
BYTE wflag; /* win[] flag (b0:dirty) */ BYTE wflag; /* win[] flag (b0:dirty) */
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
@ -133,6 +133,9 @@ typedef struct {
DWORD fatbase; /* FAT base sector */ DWORD fatbase; /* FAT base sector */
DWORD dirbase; /* Root directory base sector/cluster */ DWORD dirbase; /* Root directory base sector/cluster */
DWORD database; /* Data base sector */ DWORD database; /* Data base sector */
#if FF_FS_EXFAT
DWORD bitbase; /* Allocation bitmap base sector */
#endif
DWORD winsect; /* Current sector appearing in the win[] */ DWORD winsect; /* Current sector appearing in the win[] */
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
} FATFS; } FATFS;
@ -145,7 +148,7 @@ typedef struct {
FATFS* fs; /* Pointer to the hosting volume of this object */ FATFS* fs; /* Pointer to the hosting volume of this object */
WORD id; /* Hosting volume mount ID */ WORD id; /* Hosting volume mount ID */
BYTE attr; /* Object attribute */ BYTE attr; /* Object attribute */
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:flagmented in this session, b2:sub-directory stretched) */ BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */
DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */ DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
FSIZE_t objsize; /* Object size (valid when sclust != 0) */ FSIZE_t objsize; /* Object size (valid when sclust != 0) */
#if FF_FS_EXFAT #if FF_FS_EXFAT
@ -175,12 +178,12 @@ typedef struct {
DWORD dir_sect; /* Sector number containing the directory entry (not used at exFAT) */ DWORD dir_sect; /* Sector number containing the directory entry (not used at exFAT) */
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */ BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */
#endif #endif
#if FF_USE_FASTSEEK
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
#endif
#if !FF_FS_TINY #if !FF_FS_TINY
BYTE buf[FF_MAX_SS]; /* File private data read/write window */ BYTE buf[FF_MAX_SS]; /* File private data read/write window */
#endif #endif
#if FF_USE_FASTSEEK
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
#endif
} FIL; } FIL;

View file

@ -1,8 +1,8 @@
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ FatFs - Configuration file / FatFs Functional Configurations
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define FFCONF_DEF 63463 /* Revision ID */ #define FFCONF_DEF 86604 /* Revision ID */
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ Function Configurations / Function Configurations
@ -232,14 +232,14 @@
#define FF_FS_EXFAT 1 #define FF_FS_EXFAT 1
/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable) /* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
/ To enable exFAT, also LFN needs to be enabled. / To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1)
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */ / Note that enabling exFAT discards ANSI C (C89) compatibility. */
#define FF_FS_NORTC 1 #define FF_FS_NORTC 1
#define FF_NORTC_MON 1 #define FF_NORTC_MON 1
#define FF_NORTC_MDAY 1 #define FF_NORTC_MDAY 1
#define FF_NORTC_YEAR 2018 #define FF_NORTC_YEAR 2019
/* The option FF_FS_NORTC switches timestamp function. If the system does not have /* The option FF_FS_NORTC switches timestamp function. If the system does not have
/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable / any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable
/ the timestamp function. Every object modified by FatFs will have a fixed timestamp / the timestamp function. Every object modified by FatFs will have a fixed timestamp
@ -262,6 +262,7 @@
/ lock control is independent of re-entrancy. */ / lock control is independent of re-entrancy. */
/* #include <somertos.h> // O/S definitions */
#define FF_FS_REENTRANT 0 #define FF_FS_REENTRANT 0
#define FF_FS_TIMEOUT 1000 #define FF_FS_TIMEOUT 1000
#define FF_SYNC_t HANDLE #define FF_SYNC_t HANDLE
@ -282,8 +283,6 @@
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be / SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
/ included somewhere in the scope of ff.h. */ / included somewhere in the scope of ff.h. */
/* #include <windows.h> // O/S definitions */
/*--- End of configuration options ---*/ /*--- End of configuration options ---*/

View file

@ -1,6 +1,6 @@
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Sample Code of OS Dependent Functions for FatFs */ /* Sample Code of OS Dependent Functions for FatFs */
/* (C) ChaN, 2017 */ /* (C) ChaN, 2018 */
/* (C) CTCaer, 2018 */ /* (C) CTCaer, 2018 */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
@ -16,7 +16,7 @@
/* Allocate a memory block */ /* Allocate a memory block */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null on not enough core) */ void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */
UINT msize /* Number of bytes to allocate */ UINT msize /* Number of bytes to allocate */
) )
{ {
@ -29,7 +29,7 @@ void* ff_memalloc ( /* Returns pointer to the allocated memory block (null on no
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
void ff_memfree ( void ff_memfree (
void* mblock /* Pointer to the memory block to free (nothing to do for null) */ void* mblock /* Pointer to the memory block to free (nothing to do if null) */
) )
{ {
free(mblock); /* Free the memory block with POSIX API */ free(mblock); /* Free the memory block with POSIX API */

View file

@ -1,5 +1,5 @@
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Unicode handling functions for FatFs R0.13a */ /* Unicode handling functions for FatFs R0.13c */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* This module will occupy a huge memory in the .const section when the / /* This module will occupy a huge memory in the .const section when the /
/ FatFs is configured for LFN with DBCS. If the system has any Unicode / / FatFs is configured for LFN with DBCS. If the system has any Unicode /
@ -7,7 +7,7 @@
/ that function to avoid silly memory consumption. / / that function to avoid silly memory consumption. /
/-------------------------------------------------------------------------*/ /-------------------------------------------------------------------------*/
/* /*
/ Copyright (C) 2017, ChaN, all right reserved. / Copyright (C) 2018, ChaN, all right reserved.
/ /
/ FatFs module is an open source software. Redistribution and use of FatFs in / FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided / source and binary forms, with or without modification, are permitted provided
@ -25,9 +25,9 @@
#include "ff.h" #include "ff.h"
#if FF_USE_LFN /* This module is blanked when non-LFN configuration */ #if FF_USE_LFN /* This module will be blanked at non-LFN configuration */
#if FF_DEFINED != 63463 /* Revision ID */ #if FF_DEFINED != 86604 /* Revision ID */
#error Wrong include file (ff.h). #error Wrong include file (ff.h).
#endif #endif

View file

@ -5,7 +5,7 @@ SECTIONS {
. = __ipl_start; . = __ipl_start;
.text : { .text : {
*(.text._start); *(.text._start);
. = . + 36; *(._boot_cfg);
*(.text*); *(.text*);
} }
.data : { .data : {

View file

@ -25,11 +25,7 @@
#include "power/max77620.h" #include "power/max77620.h"
#include "rtc/max77620-rtc.h" #include "rtc/max77620-rtc.h"
#include "soc/hw_init.h" #include "soc/hw_init.h"
#include "soc/i2c.h"
#include "soc/pmc.h"
#include "soc/t210.h"
#include "storage/sdmmc.h" #include "storage/sdmmc.h"
#include "utils/btn.h"
#include "utils/util.h" #include "utils/util.h"
#include "keys/keys.h" #include "keys/keys.h"
@ -39,7 +35,7 @@ sdmmc_storage_t sd_storage;
FATFS sd_fs; FATFS sd_fs;
static bool sd_mounted; static bool sd_mounted;
boot_cfg_t *b_cfg; boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg;
bool sd_mount() bool sd_mount()
{ {
@ -117,96 +113,53 @@ int sd_save_to_file(void *buf, u32 size, const char *filename)
return 1; return 1;
} }
f_sync(&fp);
f_write(&fp, buf, size, NULL); f_write(&fp, buf, size, NULL);
f_close(&fp); f_close(&fp);
return 0; return 0;
} }
void panic(u32 val)
{
// Set panic code.
PMC(APBDEV_PMC_SCRATCH200) = val;
//PMC(APBDEV_PMC_CRYPTO_OP) = 1; // Disable SE.
TMR(TIMER_WDT4_UNLOCK_PATTERN) = TIMER_MAGIC_PTRN;
TMR(TIMER_TMR9_TMR_PTV) = TIMER_EN | TIMER_PER_EN;
TMR(TIMER_WDT4_CONFIG) = TIMER_SRC(9) | TIMER_PER(1) | TIMER_PMCRESET_EN;
TMR(TIMER_WDT4_COMMAND) = TIMER_START_CNT;
while (1)
;
}
void reboot_normal()
{
sd_unmount();
display_end();
panic(0x21); // Bypass fuse programming in package1.
}
void reboot_rcm()
{
sd_unmount();
display_end();
PMC(APBDEV_PMC_SCRATCH0) = 2; // Reboot into rcm.
PMC(APBDEV_PMC_CNTRL) |= PMC_CNTRL_MAIN_RST;
while (true)
usleep(1);
}
void power_off()
{
sd_unmount();
max77620_rtc_stop_alarm();
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF);
}
// This is a safe and unused DRAM region for our payloads. // This is a safe and unused DRAM region for our payloads.
// IPL_LOAD_ADDR is defined in makefile. #define RELOC_META_OFF 0x7C
#define EXT_PAYLOAD_ADDR 0xC03C0000
#define PATCHED_RELOC_SZ 0x94 #define PATCHED_RELOC_SZ 0x94
#define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) #define PATCHED_RELOC_STACK 0x40007000
#define PAYLOAD_ENTRY 0x40010000
#define CBFS_SDRAM_EN_ADDR 0x4003e000
#define COREBOOT_ADDR (0xD0000000 - 0x100000) #define COREBOOT_ADDR (0xD0000000 - 0x100000)
#define CBFS_DRAM_EN_ADDR 0x4003e000
void (*ext_payload_ptr)() = (void *)EXT_PAYLOAD_ADDR; #define CBFS_DRAM_MAGIC 0x4452414D // "DRAM"
void (*update_ptr)() = (void *)RCM_PAYLOAD_ADDR;
void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size) void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size)
{ {
static const u32 START_OFF = 0x7C;
static const u32 STACK_OFF = 0x80;
static const u32 PAYLOAD_END_OFF = 0x84;
static const u32 IPL_START_OFF = 0x88;
memcpy((u8 *)payload_src, (u8 *)IPL_LOAD_ADDR, PATCHED_RELOC_SZ); memcpy((u8 *)payload_src, (u8 *)IPL_LOAD_ADDR, PATCHED_RELOC_SZ);
*(vu32 *)(payload_src + START_OFF) = payload_dst - ALIGN(PATCHED_RELOC_SZ, 0x10); volatile reloc_meta_t *relocator = (reloc_meta_t *)(payload_src + RELOC_META_OFF);
*(vu32 *)(payload_src + PAYLOAD_END_OFF) = payload_dst + payload_size;
*(vu32 *)(payload_src + STACK_OFF) = 0x40008000; relocator->start = payload_dst - ALIGN(PATCHED_RELOC_SZ, 0x10);
*(vu32 *)(payload_src + IPL_START_OFF) = payload_dst; relocator->stack = PATCHED_RELOC_STACK;
relocator->end = payload_dst + payload_size;
relocator->ep = payload_dst;
if (payload_size == 0x7000) if (payload_size == 0x7000)
{ {
memcpy((u8 *)(payload_src + ALIGN(PATCHED_RELOC_SZ, 0x10)), (u8 *)COREBOOT_ADDR, 0x7000); //Bootblock memcpy((u8 *)(payload_src + ALIGN(PATCHED_RELOC_SZ, 0x10)), (u8 *)COREBOOT_ADDR, 0x7000); //Bootblock
*(vu32 *)CBFS_SDRAM_EN_ADDR = 0x4452414D; *(vu32 *)CBFS_DRAM_EN_ADDR = CBFS_DRAM_MAGIC;
} }
} }
#define IPL_STACK_TOP 0x4003F000
#define IPL_HEAP_START 0x90020000
extern void pivot_stack(u32 stack_top); extern void pivot_stack(u32 stack_top);
void ipl_main() { void ipl_main() {
b_cfg = (boot_cfg_t *)(IPL_LOAD_ADDR + PATCHED_RELOC_SZ);
config_hw(); config_hw();
pivot_stack(0x4003F000); pivot_stack(IPL_STACK_TOP);
heap_init(0x90020000); heap_init(IPL_HEAP_START);
display_init(); display_init();
u32 *fb = display_init_framebuffer(); u32 *fb = display_init_framebuffer();
gfx_init_ctxt(&gfx_ctxt, fb, 720, 1280, 720); gfx_init_ctxt(fb, 720, 1280, 720);
gfx_con_init(&gfx_con, &gfx_ctxt); gfx_con_init();
display_backlight_pwm_init(); display_backlight_pwm_init();
sd_mount(); sd_mount();

View file

@ -371,15 +371,15 @@ int se_calc_sha256(void *dst, const void *src, u32 src_size)
int res; int res;
// Setup config for SHA256, size = BITS(src_size). // Setup config for SHA256, size = BITS(src_size).
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG); SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG);
SE(SE_SHA_CONFIG_REG_OFFSET) = 1; SE(SE_SHA_CONFIG_REG_OFFSET) = SHA_ENABLE;
SE(SE_SHA_MSG_LENGTH_REG_OFFSET) = (u32)(src_size << 3); SE(SE_SHA_MSG_LENGTH_REG_OFFSET) = (u32)(src_size << 3);
SE(0x208) = 0; SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 1) = 0;
SE(0x20C) = 0; SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 2) = 0;
SE(0x210) = 0; SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 3) = 0;
SE(SE_SHA_MSG_LEFT_REG_OFFSET) = (u32)(src_size << 3); SE(SE_SHA_MSG_LEFT_REG_OFFSET) = (u32)(src_size << 3);
SE(0x218) = 0; SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 1) = 0;
SE(0x21C) = 0; SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 2) = 0;
SE(0x220) = 0; SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 3) = 0;
// Trigger the operation. // Trigger the operation.
res = _se_execute(OP_START, NULL, 0, src, src_size); res = _se_execute(OP_START, NULL, 0, src, src_size);

View file

@ -32,4 +32,5 @@ int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const vo
int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize, u32 num_secs); int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize, u32 num_secs);
int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size); int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size);
int se_calc_sha256(void *dst, const void *src, u32 src_size); int se_calc_sha256(void *dst, const void *src, u32 src_size);
#endif #endif

View file

@ -214,16 +214,16 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
smmu_deinit_for_tsec(); smmu_deinit_for_tsec();
// for (int i = 0; i < kidx; i++) // for (int i = 0; i < kidx; i++)
// gfx_printf(&gfx_con, "key %08X\n", key[i]); // gfx_printf("key %08X\n", key[i]);
// gfx_printf(&gfx_con, "cpuctl (%08X) mbox (%08X)\n", TSEC(TSEC_CPUCTL), TSEC(TSEC_STATUS)); // gfx_printf("cpuctl (%08X) mbox (%08X)\n", TSEC(TSEC_CPUCTL), TSEC(TSEC_STATUS));
// u32 errst = MC(MC_ERR_STATUS); // u32 errst = MC(MC_ERR_STATUS);
// gfx_printf(&gfx_con, " MC %08X %08X %08X\n", MC(MC_INTSTATUS), errst, MC(MC_ERR_ADR)); // gfx_printf(" MC %08X %08X %08X\n", MC(MC_INTSTATUS), errst, MC(MC_ERR_ADR));
// gfx_printf(&gfx_con, " type: %02X\n", errst >> 28); // gfx_printf(" type: %02X\n", errst >> 28);
// gfx_printf(&gfx_con, " smmu: %02X\n", (errst >> 25) & 3); // gfx_printf(" smmu: %02X\n", (errst >> 25) & 3);
// gfx_printf(&gfx_con, " dir: %s\n", (errst >> 16) & 1 ? "W" : "R"); // gfx_printf(" dir: %s\n", (errst >> 16) & 1 ? "W" : "R");
// gfx_printf(&gfx_con, " cid: %02x\n", errst & 0xFF); // gfx_printf(" cid: %02x\n", errst & 0xFF);
} }
else else
{ {

View file

@ -276,12 +276,16 @@ static void _clock_sdmmc_set_reset(u32 id)
{ {
case SDMMC_1: case SDMMC_1:
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC1_RST; CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC1_RST;
break;
case SDMMC_2: case SDMMC_2:
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC2_RST; CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC2_RST;
break;
case SDMMC_3: case SDMMC_3:
CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_SET) = U_SET_SDMMC3_RST; CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_SET) = U_SET_SDMMC3_RST;
break;
case SDMMC_4: case SDMMC_4:
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC4_RST; CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC4_RST;
break;
} }
} }
@ -291,12 +295,16 @@ static void _clock_sdmmc_clear_reset(u32 id)
{ {
case SDMMC_1: case SDMMC_1:
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC1_RST; CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC1_RST;
break;
case SDMMC_2: case SDMMC_2:
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC2_RST; CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC2_RST;
break;
case SDMMC_3: case SDMMC_3:
CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_CLR) = U_CLR_SDMMC3_RST; CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_CLR) = U_CLR_SDMMC3_RST;
break;
case SDMMC_4: case SDMMC_4:
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC4_RST; CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC4_RST;
break;
} }
} }
@ -322,12 +330,16 @@ static void _clock_sdmmc_set_enable(u32 id)
{ {
case SDMMC_1: case SDMMC_1:
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC1; CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC1;
break;
case SDMMC_2: case SDMMC_2:
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC2; CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC2;
break;
case SDMMC_3: case SDMMC_3:
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_SET) = U_SET_CLK_ENB_SDMMC3; CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_SET) = U_SET_CLK_ENB_SDMMC3;
break;
case SDMMC_4: case SDMMC_4:
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC4; CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC4;
break;
} }
} }
@ -337,12 +349,16 @@ static void _clock_sdmmc_clear_enable(u32 id)
{ {
case SDMMC_1: case SDMMC_1:
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC1; CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC1;
break;
case SDMMC_2: case SDMMC_2:
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC2; CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC2;
break;
case SDMMC_3: case SDMMC_3:
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_CLR) = U_CLR_CLK_ENB_SDMMC3; CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_CLR) = U_CLR_CLK_ENB_SDMMC3;
break;
case SDMMC_4: case SDMMC_4:
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC4; CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC4;
break;
} }
} }
@ -457,6 +473,7 @@ void clock_sdmmc_get_params(u32 *pout, u16 *pdivisor, u32 type)
case 5: case 5:
*pout = 25000; *pout = 25000;
*pdivisor = 64; *pdivisor = 64;
break;
case 6: case 6:
case 8: case 8:
*pout = 25000; *pout = 25000;
@ -465,9 +482,11 @@ void clock_sdmmc_get_params(u32 *pout, u16 *pdivisor, u32 type)
case 7: case 7:
*pout = 50000; *pout = 50000;
*pdivisor = 1; *pdivisor = 1;
break;
case 10: case 10:
*pout = 100000; *pout = 100000;
*pdivisor = 1; *pdivisor = 1;
break;
case 13: case 13:
*pout = 40800; *pout = 40800;
*pdivisor = 1; *pdivisor = 1;

View file

@ -2,6 +2,7 @@
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018 shuffle2 * Copyright (c) 2018 shuffle2
* Copyright (c) 2018 balika011 * Copyright (c) 2018 balika011
* Copyright (c) 2019 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@ -21,34 +22,6 @@
#include "../soc/fuse.h" #include "../soc/fuse.h"
#include "../soc/t210.h" #include "../soc/t210.h"
#define ARRAYSIZE(x) (sizeof(x) / sizeof(*x))
static const u32 evp_thunk_template[] = {
0xe92d0007, // STMFD SP!, {R0-R2}
0xe1a0200e, // MOV R2, LR
0xe2422002, // SUB R2, R2, #2
0xe5922000, // LDR R2, [R2]
0xe20220ff, // AND R2, R2, #0xFF
0xe1a02082, // MOV R2, R2,LSL#1
0xe59f001c, // LDR R0, =evp_thunk_template
0xe59f101c, // LDR R1, =thunk_end
0xe0411000, // SUB R1, R1, R0
0xe59f0018, // LDR R0, =iram_evp_thunks
0xe0800001, // ADD R0, R0, R1
0xe0822000, // ADD R2, R2, R0
0xe3822001, // ORR R2, R2, #1
0xe8bd0003, // LDMFD SP!, {R0,R1}
0xe12fff12, // BX R2
0x001007b0, // off_1007EC DCD evp_thunk_template
0x001007f8, // off_1007F0 DCD thunk_end
0x40004c30, // off_1007F4 DCD iram_evp_thunks
// thunk_end is here
};
static const u32 evp_thunk_template_len = sizeof(evp_thunk_template);
// treated as 12bit values
static const u32 hash_vals[] = {1, 2, 4, 8, 0, 3, 5, 6, 7, 9, 10, 11};
void fuse_disable_program() void fuse_disable_program()
{ {
FUSE(FUSE_DISABLEREGPROGRAM) = 1; FUSE(FUSE_DISABLEREGPROGRAM) = 1;
@ -58,268 +31,3 @@ u32 fuse_read_odm(u32 idx)
{ {
return FUSE(FUSE_RESERVED_ODMX(idx)); return FUSE(FUSE_RESERVED_ODMX(idx));
} }
void fuse_wait_idle()
{
u32 ctrl;
do
{
ctrl = FUSE(FUSE_CTRL);
} while (((ctrl >> 16) & 0x1f) != 4);
}
u32 parity32_even(u32 *words, u32 count)
{
u32 acc = words[0];
for (u32 i = 1; i < count; i++)
{
acc ^= words[i];
}
u32 lo = ((acc & 0xffff) ^ (acc >> 16)) & 0xff;
u32 hi = ((acc & 0xffff) ^ (acc >> 16)) >> 8;
u32 x = hi ^ lo;
lo = ((x & 0xf) ^ (x >> 4)) & 3;
hi = ((x & 0xf) ^ (x >> 4)) >> 2;
x = hi ^ lo;
return (x & 1) ^ (x >> 1);
}
int patch_hash_one(u32 *word)
{
u32 bits20_31 = *word & 0xfff00000;
u32 parity_bit = parity32_even(&bits20_31, 1);
u32 hash = 0;
for (u32 i = 0; i < 12; i++)
{
if (*word & (1 << (20 + i)))
{
hash ^= hash_vals[i];
}
}
if (hash == 0)
{
if (parity_bit == 0)
{
return 0;
}
*word ^= 1 << 24;
return 1;
}
if (parity_bit == 0)
{
return 3;
}
for (u32 i = 0; i < ARRAYSIZE(hash_vals); i++)
{
if (hash_vals[i] == hash)
{
*word ^= 1 << (20 + i);
return 1;
}
}
return 2;
}
int patch_hash_multi(u32 *words, u32 count)
{
u32 parity_bit = parity32_even(words, count);
u32 bits0_14 = words[0] & 0x7fff;
u32 bit15 = words[0] & 0x8000;
u32 bits16_19 = words[0] & 0xf0000;
u32 hash = 0;
words[0] = bits16_19;
for (u32 i = 0; i < count; i++)
{
u32 w = words[i];
if (w)
{
for (u32 bitpos = 0; bitpos < 32; bitpos++)
{
if ((w >> bitpos) & 1)
{
hash ^= 0x4000 + i * 32 + bitpos;
}
}
}
}
hash ^= bits0_14;
// stupid but this is what original code does.
// equivalent to original words[0] &= 0xfff00000
words[0] = bits16_19 ^ bit15 ^ bits0_14;
if (hash == 0)
{
if (parity_bit == 0)
{
return 0;
}
words[0] ^= 0x8000;
return 1;
}
if (parity_bit == 0)
{
return 3;
}
u32 bitcount = hash - 0x4000;
if (bitcount < 16 || bitcount >= count * 32)
{
u32 num_set = 0;
for (u32 bitpos = 0; bitpos < 15; bitpos++)
{
if ((hash >> bitpos) & 1)
{
num_set++;
}
}
if (num_set != 1)
{
return 2;
}
words[0] ^= hash;
return 1;
}
words[bitcount / 32] ^= 1 << (hash & 0x1f);
return 1;
}
int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value))
{
u32 words[80];
u32 word_count;
u32 word_addr;
u32 word0 = 0;
u32 total_read = 0;
word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE);
word_count &= 0x7f;
word_addr = 191;
while (word_count)
{
total_read += word_count;
if (total_read >= ARRAYSIZE(words))
{
break;
}
for (u32 i = 0; i < word_count; i++)
{
FUSE(FUSE_ADDR) = word_addr--;
FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ;
fuse_wait_idle();
words[i] = FUSE(FUSE_RDATA);
}
word0 = words[0];
if (patch_hash_multi(words, word_count) >= 2)
{
return 1;
}
u32 ipatch_count = (words[0] >> 16) & 0xf;
if (ipatch_count)
{
for (u32 i = 0; i < ipatch_count; i++)
{
u32 word = words[i + 1];
u32 addr = (word >> 16) * 2;
u32 data = word & 0xffff;
ipatch(addr, data);
}
}
words[0] = word0;
if ((word0 >> 25) == 0)
break;
if (patch_hash_one(&word0) >= 2)
{
return 3;
}
word_count = word0 >> 25;
}
return 0;
}
int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len)
{
u32 words[80];
u32 word_count;
u32 word_addr;
u32 word0 = 0;
u32 total_read = 0;
int evp_thunk_written = 0;
void *evp_thunk_dst_addr = 0;
memset(iram_evp_thunks, 0, *iram_evp_thunks_len);
word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE);
word_count &= 0x7f;
word_addr = 191;
while (word_count)
{
total_read += word_count;
if (total_read >= ARRAYSIZE(words))
{
break;
}
for (u32 i = 0; i < word_count; i++)
{
FUSE(FUSE_ADDR) = word_addr--;
FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ;
fuse_wait_idle();
words[i] = FUSE(FUSE_RDATA);
}
word0 = words[0];
if (patch_hash_multi(words, word_count) >= 2)
{
return 1;
}
u32 ipatch_count = (words[0] >> 16) & 0xf;
u32 insn_count = word_count - ipatch_count - 1;
if (insn_count)
{
if (!evp_thunk_written)
{
evp_thunk_dst_addr = (void *)iram_evp_thunks;
memcpy(evp_thunk_dst_addr, (void *)evp_thunk_template, evp_thunk_template_len);
evp_thunk_dst_addr += evp_thunk_template_len;
evp_thunk_written = 1;
*iram_evp_thunks_len = evp_thunk_template_len;
//write32(TEGRA_EXCEPTION_VECTORS_BASE + 0x208, iram_evp_thunks);
}
u32 thunk_patch_len = insn_count * sizeof(u32);
memcpy(evp_thunk_dst_addr, &words[ipatch_count + 1], thunk_patch_len);
evp_thunk_dst_addr += thunk_patch_len;
*iram_evp_thunks_len += thunk_patch_len;
}
words[0] = word0;
if ((word0 >> 25) == 0)
break;
if (patch_hash_one(&word0) >= 2)
{
return 3;
}
word_count = word0 >> 25;
}
return 0;
}
void read_raw_ipatch_fuses(u32 *words)
{
for (u32 i = 0; i < 0x100; i++)
{
FUSE(FUSE_ADDR) = i;
FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ;
fuse_wait_idle();
words[i] = FUSE(FUSE_RDATA);
}
}

View file

@ -42,6 +42,7 @@
#define FUSE_PRIVATE_KEY1 0x1A8 #define FUSE_PRIVATE_KEY1 0x1A8
#define FUSE_PRIVATE_KEY2 0x1AC #define FUSE_PRIVATE_KEY2 0x1AC
#define FUSE_PRIVATE_KEY3 0x1B0 #define FUSE_PRIVATE_KEY3 0x1B0
#define FUSE_RESERVED_SW 0x1C0
/*! Fuse commands. */ /*! Fuse commands. */
#define FUSE_READ 0x1 #define FUSE_READ 0x1
@ -54,9 +55,5 @@
void fuse_disable_program(); void fuse_disable_program();
u32 fuse_read_odm(u32 idx); u32 fuse_read_odm(u32 idx);
void fuse_wait_idle();
int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value));
int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len);
void read_raw_ipatch_fuses(u32 *words);
#endif #endif

View file

@ -36,7 +36,7 @@
#include "../utils/util.h" #include "../utils/util.h"
extern sdmmc_t sd_sdmmc; extern sdmmc_t sd_sdmmc;
extern boot_cfg_t *b_cfg; extern boot_cfg_t b_cfg;
void _config_oscillators() void _config_oscillators()
{ {
@ -140,7 +140,7 @@ void _mbist_workaround()
void _config_se_brom() void _config_se_brom()
{ {
// Skip SBK/SSK if sept was run. // Skip SBK/SSK if sept was run.
if (!(b_cfg->boot_cfg & BOOT_CFG_SEPT_RUN)) if (!(b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN))
{ {
// Bootrom part we skipped. // Bootrom part we skipped.
u32 sbk[4] = { u32 sbk[4] = {
@ -161,7 +161,7 @@ void _config_se_brom()
// This memset needs to happen here, else TZRAM will behave weirdly later on. // This memset needs to happen here, else TZRAM will behave weirdly later on.
memset((void *)TZRAM_BASE, 0, 0x10000); memset((void *)TZRAM_BASE, 0, 0x10000);
PMC(APBDEV_PMC_CRYPTO_OP) = 0; PMC(APBDEV_PMC_CRYPTO_OP) = PMC_CRYPTO_OP_SE_ENABLE;
SE(SE_INT_STATUS_REG_OFFSET) = 0x1F; SE(SE_INT_STATUS_REG_OFFSET) = 0x1F;
// Clear the boot reason to avoid problems later // Clear the boot reason to avoid problems later
@ -227,6 +227,9 @@ void config_hw()
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, 2); i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, 2);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO6, 2); i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO6, 2);
// Disable low battery shutdown monitor.
max77620_low_battery_monitor_config();
_config_pmc_scratch(); // Missing from 4.x+ _config_pmc_scratch(); // Missing from 4.x+
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = (CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) & 0xFFFF8888) | 0x3333; CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = (CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) & 0xFFFF8888) | 0x3333;

View file

@ -32,6 +32,8 @@
#define PMC_PWR_DET_SDMMC1_IO_EN (1 << 12) #define PMC_PWR_DET_SDMMC1_IO_EN (1 << 12)
#define APBDEV_PMC_DDR_PWR 0xE8 #define APBDEV_PMC_DDR_PWR 0xE8
#define APBDEV_PMC_CRYPTO_OP 0xF4 #define APBDEV_PMC_CRYPTO_OP 0xF4
#define PMC_CRYPTO_OP_SE_ENABLE 0
#define PMC_CRYPTO_OP_SE_DISABLE 1
#define APBDEV_PMC_SCRATCH33 0x120 #define APBDEV_PMC_SCRATCH33 0x120
#define APBDEV_PMC_SCRATCH40 0x13C #define APBDEV_PMC_SCRATCH40 0x13C
#define APBDEV_PMC_OSC_EDPD_OVER 0x1A4 #define APBDEV_PMC_OSC_EDPD_OVER 0x1A4

View file

@ -179,8 +179,13 @@
#define I2S_CG_SLCG_ENABLE (1 << 0) #define I2S_CG_SLCG_ENABLE (1 << 0)
#define I2S_CTRL_MASTER_EN (1 << 10) #define I2S_CTRL_MASTER_EN (1 << 10)
/*! PWM registers. */
#define PWM_CONTROLLER_PWM_CSR_0 0x00
#define PWM_CONTROLLER_PWM_CSR_1 0x10
/*! Special registers. */ /*! Special registers. */
#define EMC_SCRATCH0 0x324 #define EMC_SCRATCH0 0x324
#define EMC_HEKA_UPD (1 << 30)
#define EMC_SEPT_RUN (1 << 31) #define EMC_SEPT_RUN (1 << 31)
#endif #endif

View file

@ -59,7 +59,7 @@ typedef struct _emmc_part_t
u32 lba_start; u32 lba_start;
u32 lba_end; u32 lba_end;
u64 attrs; u64 attrs;
s8 name[37]; char name[37];
link_t link; link_t link;
} emmc_part_t; } emmc_part_t;

View file

@ -23,7 +23,7 @@
#include "../mem/heap.h" #include "../mem/heap.h"
/*#include "gfx.h" /*#include "gfx.h"
#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)*/ #define DPRINTF(...) gfx_printf(__VA_ARGS__)*/
#define DPRINTF(...) #define DPRINTF(...)
static inline u32 unstuff_bits(u32 *resp, u32 start, u32 size) static inline u32 unstuff_bits(u32 *resp, u32 start, u32 size)
@ -519,7 +519,7 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
free(ext_csd); free(ext_csd);
DPRINTF("[MMC] got ext_csd\n"); DPRINTF("[MMC] got ext_csd\n");
_mmc_storage_parse_cid(storage); //This needs to be after csd and ext_csd _mmc_storage_parse_cid(storage); //This needs to be after csd and ext_csd
//gfx_hexdump(&gfx_con, 0, ext_csd, 512); //gfx_hexdump(0, ext_csd, 512);
/* When auto BKOPS is enabled the mmc device should be powered all the time until we disable this and check status. /* When auto BKOPS is enabled the mmc device should be powered all the time until we disable this and check status.
Disable it for now until BKOPS disable added to power down sequence at sdmmc_storage_end(). Disable it for now until BKOPS disable added to power down sequence at sdmmc_storage_end().
@ -713,7 +713,7 @@ int _sd_storage_get_scr(sdmmc_storage_t *storage, u8 *buf)
storage->raw_scr[i] = buf[i + 3]; storage->raw_scr[i] = buf[i + 3];
} }
_sd_storage_parse_scr(storage); _sd_storage_parse_scr(storage);
//gfx_hexdump(&gfx_con, 0, storage->raw_scr, 8); //gfx_hexdump(0, storage->raw_scr, 8);
return _sdmmc_storage_check_result(tmp); return _sdmmc_storage_check_result(tmp);
} }
@ -825,7 +825,7 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8
if (!_sd_storage_switch_get(storage, buf)) if (!_sd_storage_switch_get(storage, buf))
return 0; return 0;
//gfx_hexdump(&gfx_con, 0, (u8 *)buf, 64); //gfx_hexdump(0, (u8 *)buf, 64);
u32 hs_type = 0; u32 hs_type = 0;
switch (type) switch (type)
@ -875,7 +875,7 @@ int _sd_storage_enable_highspeed_high_volt(sdmmc_storage_t *storage, u8 *buf)
{ {
if (!_sd_storage_switch_get(storage, buf)) if (!_sd_storage_switch_get(storage, buf))
return 0; return 0;
//gfx_hexdump(&gfx_con, 0, (u8 *)buf, 64); //gfx_hexdump(0, (u8 *)buf, 64);
if (!(buf[13] & 2)) if (!(buf[13] & 2))
return 1; return 1;
@ -963,7 +963,7 @@ static int _sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf)
storage->raw_ssr[i] = buf[i + 3]; storage->raw_ssr[i] = buf[i + 3];
} }
_sd_storage_parse_ssr(storage); _sd_storage_parse_ssr(storage);
//gfx_hexdump(&gfx_con, 0, storage->raw_ssr, 64); //gfx_hexdump(0, storage->raw_ssr, 64);
return _sdmmc_storage_check_result(tmp); return _sdmmc_storage_check_result(tmp);
} }
@ -1088,7 +1088,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
return 0; return 0;
} }
//gfx_hexdump(&gfx_con, 0, storage->raw_scr, 8); //gfx_hexdump(0, storage->raw_scr, 8);
DPRINTF("[SD] got scr\n"); DPRINTF("[SD] got scr\n");
// Check if card supports a wider bus and if it's not SD Version 1.X // Check if card supports a wider bus and if it's not SD Version 1.X

View file

@ -28,7 +28,7 @@
#include "../soc/gpio.h" #include "../soc/gpio.h"
/*#include "gfx.h" /*#include "gfx.h"
#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)*/ #define DPRINTF(...) gfx_printf(__VA_ARGS__)*/
#define DPRINTF(...) #define DPRINTF(...)
/*! SCMMC controller base addresses. */ /*! SCMMC controller base addresses. */

View file

@ -22,9 +22,9 @@
#include "util.h" #include "util.h"
#include "../power/max77620.h" #include "../power/max77620.h"
u32 btn_read() u8 btn_read()
{ {
u32 res = 0; u8 res = 0;
if (!gpio_read(GPIO_PORT_X, GPIO_PIN_7)) if (!gpio_read(GPIO_PORT_X, GPIO_PIN_7))
res |= BTN_VOL_DOWN; res |= BTN_VOL_DOWN;
if (!gpio_read(GPIO_PORT_X, GPIO_PIN_6)) if (!gpio_read(GPIO_PORT_X, GPIO_PIN_6))
@ -34,9 +34,9 @@ u32 btn_read()
return res; return res;
} }
u32 btn_wait() u8 btn_wait()
{ {
u32 res = 0, btn = btn_read(); u8 res = 0, btn = btn_read();
bool pwr = false; bool pwr = false;
//Power button down, raise a filter. //Power button down, raise a filter.
@ -59,16 +59,18 @@ u32 btn_wait()
return res; return res;
} }
u32 btn_wait_timeout(u32 time_ms, u32 mask) u8 btn_wait_timeout(u32 time_ms, u8 mask)
{ {
u32 timeout = get_tmr_ms() + time_ms; u32 timeout = get_tmr_ms() + time_ms;
u32 res = btn_read() & mask; u8 res = btn_read() & mask;
do while (get_tmr_ms() < timeout)
{ {
if (!(res & mask)) if (res == mask)
break;
else
res = btn_read() & mask; res = btn_read() & mask;
} while (get_tmr_ms() < timeout); };
return res; return res;
} }

View file

@ -20,12 +20,12 @@
#include "types.h" #include "types.h"
#define BTN_POWER 0x1 #define BTN_POWER (1 << 0)
#define BTN_VOL_DOWN 0x2 #define BTN_VOL_DOWN (1 << 1)
#define BTN_VOL_UP 0x4 #define BTN_VOL_UP (1 << 2)
u32 btn_read(); u8 btn_read();
u32 btn_wait(); u8 btn_wait();
u32 btn_wait_timeout(u32 time_ms, u32 mask); u8 btn_wait_timeout(u32 time_ms, u8 mask);
#endif #endif

View file

@ -45,7 +45,7 @@
#define COLOR_BLUE 0xFF00DDFF #define COLOR_BLUE 0xFF00DDFF
#define COLOR_VIOLET 0xFF8040FF #define COLOR_VIOLET 0xFF8040FF
typedef char s8; typedef signed char s8;
typedef short s16; typedef short s16;
typedef short SHORT; typedef short SHORT;
typedef int s32; typedef int s32;
@ -79,8 +79,16 @@ typedef struct __attribute__((__packed__)) _boot_cfg_t
u8 boot_cfg; u8 boot_cfg;
u8 autoboot; u8 autoboot;
u8 autoboot_list; u8 autoboot_list;
u8 rsvd_cfg; u8 extra_cfg;
u8 rsvd[32]; u8 rsvd[128];
} boot_cfg_t; } boot_cfg_t;
typedef struct __attribute__((__packed__)) _reloc_meta_t
{
u32 start;
u32 stack;
u32 end;
u32 ep;
} reloc_meta_t;
#endif #endif

View file

@ -16,8 +16,15 @@
*/ */
#include "util.h" #include "util.h"
#include "../gfx/di.h"
#include "../power/max77620.h"
#include "../rtc/max77620-rtc.h"
#include "../soc/i2c.h"
#include "../soc/pmc.h"
#include "../soc/t210.h" #include "../soc/t210.h"
extern void sd_unmount();
u32 get_tmr_s() u32 get_tmr_s()
{ {
return RTC(APBDEV_RTC_SECONDS); return RTC(APBDEV_RTC_SECONDS);
@ -26,7 +33,7 @@ u32 get_tmr_s()
u32 get_tmr_ms() u32 get_tmr_ms()
{ {
// The registers must be read with the following order: // The registers must be read with the following order:
// -> RTC_MILLI_SECONDS (0x10) -> RTC_SHADOW_SECONDS (0xC) // RTC_MILLI_SECONDS (0x10) -> RTC_SHADOW_SECONDS (0xC)
return (RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10)); return (RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10));
} }
@ -56,6 +63,50 @@ void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops)
base[ops[i].off] = ops[i].val; base[ops[i].off] = ops[i].val;
} }
void panic(u32 val)
{
// Set panic code.
PMC(APBDEV_PMC_SCRATCH200) = val;
//PMC(APBDEV_PMC_CRYPTO_OP) = PMC_CRYPTO_OP_SE_DISABLE;
TMR(TIMER_WDT4_UNLOCK_PATTERN) = TIMER_MAGIC_PTRN;
TMR(TIMER_TMR9_TMR_PTV) = TIMER_EN | TIMER_PER_EN;
TMR(TIMER_WDT4_CONFIG) = TIMER_SRC(9) | TIMER_PER(1) | TIMER_PMCRESET_EN;
TMR(TIMER_WDT4_COMMAND) = TIMER_START_CNT;
while (1)
;
}
void reboot_normal()
{
sd_unmount();
display_end();
panic(0x21); // Bypass fuse programming in package1.
}
void reboot_rcm()
{
sd_unmount();
display_end();
PMC(APBDEV_PMC_SCRATCH0) = 2; // Reboot into rcm.
PMC(APBDEV_PMC_CNTRL) |= PMC_CNTRL_MAIN_RST;
while (true)
usleep(1);
}
void power_off()
{
sd_unmount();
// Stop the alarm, in case we injected and powered off too fast.
max77620_rtc_stop_alarm();
//TODO: we should probably make sure all regulators are powered off properly.
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF);
}
#define CRC32C_POLY 0x82F63B78 #define CRC32C_POLY 0x82F63B78
u32 crc32c(const void *buf, u32 len) u32 crc32c(const void *buf, u32 len)
{ {

View file

@ -20,8 +20,8 @@
#include "types.h" #include "types.h"
#define byte_swap_32(num) ((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \ #define byte_swap_32(num) (((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \
((num >> 8 )& 0xff00) | ((num << 24) & 0xff000000) ((num >> 8 )& 0xff00) | ((num << 24) & 0xff000000))
typedef struct _cfg_op_t typedef struct _cfg_op_t
{ {
@ -34,6 +34,10 @@ u32 get_tmr_ms();
u32 get_tmr_s(); u32 get_tmr_s();
void usleep(u32 ticks); void usleep(u32 ticks);
void msleep(u32 milliseconds); void msleep(u32 milliseconds);
void panic(u32 val);
void reboot_normal();
void reboot_rcm();
void power_off();
void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops); void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops);
u32 crc32c(const void *buf, u32 len); u32 crc32c(const void *buf, u32 len);