added cfg lock mechanism

This commit is contained in:
Polprzewodnikowy 2022-08-30 00:33:26 +02:00
parent 8a8a3b4439
commit 30f0fc002e
15 changed files with 178 additions and 55 deletions

Binary file not shown.

View File

@ -42,6 +42,9 @@
<Source name="../../rtl/n64/n64_flashram.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../../rtl/n64/n64_lock.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../../rtl/n64/n64_pi.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>

View File

@ -607,6 +607,7 @@ module mcu_top (
sd_dma_scb.stop <= 1'b0;
n64_scb.cfg_done <= 1'b0;
n64_scb.cfg_error <= 1'b0;
n64_scb.cfg_irq <= 1'b0;
n64_scb.flashram_done <= 1'b0;

View File

@ -20,21 +20,25 @@ module n64_cfg (
REG_VERSION_L
} e_reg;
logic cfg_error;
always_comb begin
reg_bus.rdata = 16'd0;
case (reg_bus.address[3:1])
REG_STATUS: reg_bus.rdata = {
n64_scb.cfg_pending,
n64_scb.cfg_error,
14'd0
};
REG_DATA_0_H: reg_bus.rdata = n64_scb.cfg_wdata[0][31:16];
REG_DATA_0_L: reg_bus.rdata = n64_scb.cfg_wdata[0][15:0];
REG_DATA_1_H: reg_bus.rdata = n64_scb.cfg_wdata[1][31:16];
REG_DATA_1_L: reg_bus.rdata = n64_scb.cfg_wdata[1][15:0];
REG_VERSION_H: reg_bus.rdata = n64_scb.cfg_version[31:16];
REG_VERSION_L: reg_bus.rdata = n64_scb.cfg_version[15:0];
endcase
if (reg_bus.address[16] && (reg_bus.address[15:4] == 12'd0)) begin
case (reg_bus.address[3:1])
REG_STATUS: reg_bus.rdata = {
n64_scb.cfg_pending,
cfg_error,
14'd0
};
REG_DATA_0_H: reg_bus.rdata = n64_scb.cfg_wdata[0][31:16];
REG_DATA_0_L: reg_bus.rdata = n64_scb.cfg_wdata[0][15:0];
REG_DATA_1_H: reg_bus.rdata = n64_scb.cfg_wdata[1][31:16];
REG_DATA_1_L: reg_bus.rdata = n64_scb.cfg_wdata[1][15:0];
REG_VERSION_H: reg_bus.rdata = n64_scb.cfg_version[31:16];
REG_VERSION_L: reg_bus.rdata = n64_scb.cfg_version[15:0];
endcase
end
end
always_ff @(posedge clk) begin
@ -42,9 +46,11 @@ module n64_cfg (
n64_scb.cfg_pending <= 1'b0;
n64_scb.cfg_cmd <= 8'h00;
irq <= 1'b0;
cfg_error <= 1'b0;
end else begin
if (n64_scb.cfg_done) begin
n64_scb.cfg_pending <= 1'b0;
cfg_error <= n64_scb.cfg_error;
end
if (n64_scb.cfg_irq) begin
@ -52,17 +58,20 @@ module n64_cfg (
end
if (reg_bus.write) begin
case (reg_bus.address[3:1])
REG_COMMAND: begin
n64_scb.cfg_pending <= 1'b1;
n64_scb.cfg_cmd <= reg_bus.wdata[7:0];
end
REG_DATA_0_H: n64_scb.cfg_rdata[0][31:16] <= reg_bus.wdata;
REG_DATA_0_L: n64_scb.cfg_rdata[0][15:0] <= reg_bus.wdata;
REG_DATA_1_H: n64_scb.cfg_rdata[1][31:16] <= reg_bus.wdata;
REG_DATA_1_L: n64_scb.cfg_rdata[1][15:0] <= reg_bus.wdata;
REG_VERSION_L: irq <= 1'b0;
endcase
if (reg_bus.address[16] && (reg_bus.address[15:4] == 12'd0)) begin
case (reg_bus.address[3:1])
REG_COMMAND: begin
n64_scb.cfg_pending <= 1'b1;
n64_scb.cfg_cmd <= reg_bus.wdata[7:0];
cfg_error <= 1'b0;
end
REG_DATA_0_H: n64_scb.cfg_rdata[0][31:16] <= reg_bus.wdata;
REG_DATA_0_L: n64_scb.cfg_rdata[0][15:0] <= reg_bus.wdata;
REG_DATA_1_H: n64_scb.cfg_rdata[1][31:16] <= reg_bus.wdata;
REG_DATA_1_L: n64_scb.cfg_rdata[1][15:0] <= reg_bus.wdata;
REG_VERSION_L: irq <= 1'b0;
endcase
end
end
end
end

52
fw/rtl/n64/n64_lock.sv Normal file
View File

@ -0,0 +1,52 @@
module n64_lock (
input clk,
input reset,
n64_reg_bus.lock reg_bus,
n64_scb.lock n64_scb,
);
const bit [15:0] UNLOCK_SEQUENCE [4] = {
16'h5F55,
16'h4E4C,
16'h4F43,
16'h4B5F
};
always_comb begin
reg_bus.rdata = 16'd0;
end
logic [1:0] sequence_counter;
always_ff @(posedge clk) begin
if (reset || n64_scb.n64_reset || n64_scb.n64_nmi) begin
n64_scb.cfg_unlock <= 1'b0;
sequence_counter <= 2'd0;
end else begin
if (reg_bus.write) begin
if (reg_bus.address[16] && (reg_bus.address[15:2] == 14'd0)) begin
for (int i = 0; i < $size(UNLOCK_SEQUENCE); i++) begin
if (sequence_counter == i) begin
if (reg_bus.wdata == UNLOCK_SEQUENCE[i]) begin
sequence_counter <= sequence_counter + 1'd1;
if (i == ($size(UNLOCK_SEQUENCE) - 1'd1)) begin
n64_scb.cfg_unlock <= 1'b1;
sequence_counter <= 2'd0;
end
end else begin
n64_scb.cfg_unlock <= 1'b0;
sequence_counter <= 2'd0;
end
end
end
end else begin
n64_scb.cfg_unlock <= 1'b0;
sequence_counter <= 2'd0;
end
end
end
end
endmodule

View File

@ -139,6 +139,7 @@ module n64_pi (
write_port <= PORT_NONE;
reg_bus.dd_select <= 1'b0;
reg_bus.flashram_select <= 1'b0;
reg_bus.lock_select <= 1'b0;
reg_bus.cfg_select <= 1'b0;
end else if (aleh_op) begin
read_port <= PORT_NONE;
@ -146,6 +147,7 @@ module n64_pi (
mem_offset <= 32'd0;
reg_bus.dd_select <= 1'b0;
reg_bus.flashram_select <= 1'b0;
reg_bus.lock_select <= 1'b0;
reg_bus.cfg_select <= 1'b0;
if (n64_scb.dd_enabled) begin
@ -220,16 +222,24 @@ module n64_pi (
mem_offset <= (-32'h1400_0000) + FLASH_OFFSET;
end
if (n64_pi_dq_in >= 16'h1FFE && n64_pi_dq_in < 16'h1FFF) begin
read_port <= PORT_MEM;
write_port <= PORT_MEM;
mem_offset <= (-32'h1FFE_0000) + BUFFER_OFFSET;
if (n64_pi_dq_in >= 16'h1FFD && n64_pi_dq_in < 16'h1FFE) begin
read_port <= PORT_NONE;
write_port <= PORT_REG;
reg_bus.lock_select <= 1'b1;
end
if (n64_pi_dq_in >= 16'h1FFF && n64_pi_dq_in < 16'h2000) begin
read_port <= PORT_REG;
write_port <= PORT_REG;
reg_bus.cfg_select <= 1'b1;
if (n64_scb.cfg_unlock) begin
if (n64_pi_dq_in >= 16'h1FFE && n64_pi_dq_in < 16'h1FFF) begin
read_port <= PORT_MEM;
write_port <= PORT_MEM;
mem_offset <= (-32'h1FFE_0000) + BUFFER_OFFSET;
end
if (n64_pi_dq_in >= 16'h1FFF && n64_pi_dq_in < 16'h2000) begin
read_port <= PORT_REG;
write_port <= PORT_REG;
reg_bus.cfg_select <= 1'b1;
end
end
end
end

View File

@ -2,6 +2,7 @@ interface n64_reg_bus ();
logic flashram_select;
logic dd_select;
logic lock_select;
logic cfg_select;
logic read;
@ -12,12 +13,14 @@ interface n64_reg_bus ();
logic [15:0] flashram_rdata;
logic [15:0] dd_rdata;
logic [15:0] lock_rdata;
logic [15:0] cfg_rdata;
modport controller (
output flashram_select,
output dd_select,
output cfg_select,
output lock_select,
output read,
output write,
@ -34,6 +37,9 @@ interface n64_reg_bus ();
if (dd_select) begin
rdata = dd_rdata;
end
if (lock_select) begin
rdata = lock_rdata;
end
if (cfg_select) begin
rdata = cfg_rdata;
end
@ -55,6 +61,14 @@ interface n64_reg_bus ();
input wdata
);
modport lock (
input .read(read && lock_select),
input .write(write && lock_select),
input address,
output .rdata(lock_rdata),
input wdata
);
modport cfg (
input .read(read && cfg_select),
input .write(write && cfg_select),

View File

@ -40,6 +40,7 @@ interface n64_scb ();
logic [41:0] rtc_rdata;
logic [41:0] rtc_wdata;
logic cfg_unlock;
logic cfg_pending;
logic cfg_done;
logic cfg_error;
@ -99,7 +100,9 @@ interface n64_scb ();
input dd_enabled,
input ddipl_enabled,
input flashram_read_mode
input flashram_read_mode,
input cfg_unlock
);
modport flashram (
@ -158,6 +161,13 @@ interface n64_scb ();
input dd_wdata
);
modport lock (
input n64_reset,
input n64_nmi,
output cfg_unlock
);
modport cfg (
input n64_reset,

View File

@ -67,6 +67,15 @@ module n64_top (
.n64_scb(n64_scb)
);
n64_lock n64_lock_inst (
.clk(clk),
.reset(reset),
.reg_bus(reg_bus),
.n64_scb(n64_scb)
);
n64_cfg n64_cfg_inst (
.clk(clk),
.reset(reset),

View File

@ -11,6 +11,8 @@ void init (void) {
exception_install();
sc64_unlock();
if (!sc64_check_presence()) {
error_display("SC64 hardware not detected");
}
@ -29,4 +31,5 @@ void init (void) {
void deinit (void) {
exception_disable_interrupts();
exception_disable_watchdog();
sc64_lock();
}

View File

@ -225,6 +225,14 @@ typedef struct {
#define PIFRAM ((io8_t *) PIFRAM_BASE)
typedef struct {
io32_t KEY;
} sc64_lock_t;
#define SC64_LOCK_BASE (0x1FFD0000UL)
#define SC64_LOCK ((sc64_lock_t *) SC64_LOCK_BASE)
typedef struct {
io8_t BUFFER[8192];
io8_t EEPROM[2048];

View File

@ -40,6 +40,16 @@ static bool sc64_execute_cmd (uint8_t cmd, uint32_t *args, uint32_t *result) {
return error;
}
void sc64_unlock (void) {
pi_io_write(&SC64_LOCK->KEY, 0x00000000);
pi_io_write(&SC64_LOCK->KEY, 0x5F554E4C);
pi_io_write(&SC64_LOCK->KEY, 0x4F434B5F);
}
void sc64_lock (void) {
pi_io_write(&SC64_LOCK->KEY, 0x00000000);
}
bool sc64_check_presence (void) {
uint32_t version = pi_io_read(&SC64_REGS->VERSION);
return (version == SC64_VERSION_2);

View File

@ -91,6 +91,8 @@ typedef struct {
} rtc_time_t;
void sc64_unlock (void);
void sc64_lock (void);
bool sc64_check_presence (void);
cmd_error_t sc64_get_error (void);
void sc64_set_config (cfg_id_t id, uint32_t value);

View File

@ -54,7 +54,7 @@ void button_process (void) {
if (p.trigger) {
switch (p.mode) {
case BUTTON_MODE_N64_IRQ:
fpga_reg_set(REG_CFG_CMD, fpga_reg_get(REG_CFG_CMD) | CFG_CMD_IRQ);
fpga_reg_set(REG_CFG_CMD, CFG_CMD_IRQ);
p.trigger = false;
break;

View File

@ -11,7 +11,7 @@ from dd64 import BadBlockError, DD64Image
from enum import Enum, IntEnum
from serial.tools import list_ports
from threading import Thread
from typing import Optional
from typing import Callable, Optional
@ -394,8 +394,6 @@ class SC64:
def upload_save(self, data: bytes) -> None:
save_type = self.SaveType(self.__get_config(self.__CfgId.SAVE_TYPE))
if (save_type not in self.SaveType):
raise ConnectionError('Unknown save type fetched from SC64 device')
if (save_type == self.SaveType.NONE):
raise ValueError('No save type set inside SC64 device')
if (len(data) != self.__SaveLength[save_type.name]):
@ -407,8 +405,6 @@ class SC64:
def download_save(self) -> bytes:
save_type = self.SaveType(self.__get_config(self.__CfgId.SAVE_TYPE))
if (save_type not in self.SaveType):
raise ConnectionError('Unknown save type fetched from SC64 device')
if (save_type == self.SaveType.NONE):
raise ValueError('No save type set inside SC64 device')
address = self.__Address.SAVE
@ -432,8 +428,6 @@ class SC64:
self.__link.execute_cmd(cmd=b'T', args=[self.__get_int(data[0:4]), self.__get_int(data[4:8])])
def set_boot_mode(self, mode: BootMode) -> None:
if (mode not in self.BootMode):
raise ValueError('Boot mode outside of allowed values')
self.__set_config(self.__CfgId.BOOT_MODE, mode)
def set_cic_seed(self, seed: int) -> None:
@ -443,13 +437,9 @@ class SC64:
self.__set_config(self.__CfgId.CIC_SEED, seed)
def set_tv_type(self, type: TVType) -> None:
if (type not in self.TVType):
raise ValueError('TV type outside of allowed values')
self.__set_config(self.__CfgId.TV_TYPE, type)
def set_save_type(self, type: SaveType) -> None:
if (type not in self.SaveType):
raise ValueError('Save type outside of allowed values')
self.__set_config(self.__CfgId.SAVE_TYPE, type)
def set_cic_parameters(self, dd_mode: bool=False, seed: int=0x3F, checksum: bytes=bytes([0xA5, 0x36, 0xC0, 0xF1, 0xD8, 0x59])) -> None:
@ -461,7 +451,7 @@ class SC64:
data = [*data, *checksum]
self.__link.execute_cmd(cmd=b'B', args=[self.__get_int(data[0:4]), self.__get_int(data[4:8])])
def update_firmware(self, data: bytes) -> None:
def update_firmware(self, data: bytes, status_callback: Optional[Callable[[str], None]]=None) -> None:
address = self.__Address.FIRMWARE
self.__write_memory(address, data)
response = self.__link.execute_cmd(cmd=b'F', args=[address, len(data)])
@ -477,7 +467,8 @@ class SC64:
if (cmd != b'F'):
raise ConnectionException('Wrong update status packet')
status = self.__UpdateStatus(self.__get_int(data))
print(f'Update status [{status.name}]')
if (status_callback):
status_callback(status.name)
if (status == self.__UpdateStatus.ERROR):
raise ConnectionException('Update error, device is most likely bricked')
time.sleep(2)
@ -616,8 +607,8 @@ class EnumAction(argparse.Action):
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='SC64 control software')
parser.add_argument('--backup', help='backup SC64 firmware and write it to specified file')
parser.add_argument('--update', help='update SC64 firmware from specified file')
parser.add_argument('--backup-firmware', help='backup SC64 firmware and write it to specified file')
parser.add_argument('--update-firmware', help='update SC64 firmware from specified file')
parser.add_argument('--reset-state', action='store_true', help='reset SC64 internal state')
parser.add_argument('--print-state', action='store_true', help='print SC64 internal state')
parser.add_argument('--boot', type=SC64.BootMode, action=EnumAction, help='set boot mode')
@ -632,7 +623,7 @@ if __name__ == '__main__':
parser.add_argument('--ddipl', help='upload 64DD IPL from specified file')
parser.add_argument('--disk', action='append', help='path to 64DD disk (.ndd format), can be specified multiple times')
parser.add_argument('--isv', action='store_true', help='enable IS-Viewer64 support')
parser.add_argument('--debug', action='store_true', help='run debug loop (required for IS-Viewer64 and 64DD)')
parser.add_argument('--debug', action='store_true', help='run debug loop (required for 64DD and IS-Viewer64)')
if (len(sys.argv) <= 1):
parser.print_help()
@ -643,16 +634,17 @@ if __name__ == '__main__':
try:
sc64 = SC64()
if (args.backup):
with open(args.backup, 'wb+') as f:
if (args.backup_firmware):
with open(args.backup_firmware, 'wb+') as f:
print('Generating backup, this might take a while... ', end='', flush=True)
f.write(sc64.backup_firmware())
print('done')
if (args.update):
with open(args.update, 'rb+') as f:
if (args.update_firmware):
with open(args.update_firmware, 'rb+') as f:
print('Updating firmware, this might take a while... ', end='', flush=True)
sc64.update_firmware(f.read())
status_callback = lambda status: print(f'{status} ', end='', flush=True)
sc64.update_firmware(f.read(), status_callback)
print('done')
if (args.reset_state):