diff --git a/chipsec/hal/interrupts.py b/chipsec/hal/interrupts.py index bd0c27f39b..711a1b5a69 100644 --- a/chipsec/hal/interrupts.py +++ b/chipsec/hal/interrupts.py @@ -62,6 +62,18 @@ def send_SW_SMI(self, thread_id: int, SMI_code_port_value: int, SMI_data_port_va logger().log_hal(f" RDI = 0x{_rdi:016X}") return self.cs.helper.send_sw_smi(thread_id, SMI_code_data, _rax, _rbx, _rcx, _rdx, _rsi, _rdi) + def send_SW_SMI_timed(self, thread_id: int, SMI_code_port_value: int, SMI_data_port_value: int, _rax: int, _rbx: int, _rcx: int, _rdx: int, _rsi: int, _rdi: int) -> Optional[Tuple[int, int, int, int, int, int, int]]: + SMI_code_data = (SMI_data_port_value << 8 | SMI_code_port_value) + logger().log_hal( + f"[intr] Sending SW SMI: code port 0x{SMI_APMC_PORT:02X} <- 0x{SMI_code_port_value:02X}, data port 0x{SMI_APMC_PORT + 1:02X} <- 0x{SMI_data_port_value:02X} (0x{SMI_code_data:04X})") + logger().log_hal(f" RAX = 0x{_rax:016X} (AX will be overridden with values of SW SMI ports B2/B3)") + logger().log_hal(f" RBX = 0x{_rbx:016X}") + logger().log_hal(f" RCX = 0x{_rcx:016X}") + logger().log_hal(f" RDX = 0x{_rdx:016X} (DX will be overridden with 0x00B2)") + logger().log_hal(f" RSI = 0x{_rsi:016X}") + logger().log_hal(f" RDI = 0x{_rdi:016X}") + return self.cs.helper.send_sw_smi_timed(thread_id, SMI_code_data, _rax, _rbx, _rcx, _rdx, _rsi, _rdi) + def send_SMI_APMC(self, SMI_code_port_value: int, SMI_data_port_value: int) -> None: logger().log_hal(f"[intr] sending SMI via APMC ports: code 0xB2 <- 0x{SMI_code_port_value:02X}, data 0xB3 <- 0x{SMI_data_port_value:02X}") self.cs.io.write_port_byte(SMI_DATA_PORT, SMI_data_port_value) diff --git a/chipsec/helper/linux/linuxhelper.py b/chipsec/helper/linux/linuxhelper.py index b47feb54b9..57aa5cf9a2 100644 --- a/chipsec/helper/linux/linuxhelper.py +++ b/chipsec/helper/linux/linuxhelper.py @@ -72,6 +72,7 @@ IOCTL_VA2PA = 0x14 IOCTL_MSGBUS_SEND_MESSAGE = 0x15 IOCTL_FREE_PHYSMEM = 0x16 +IOCTL_SWSMI_TIMED = 0x17 _tools = {} @@ -618,6 +619,13 @@ def send_sw_smi(self, cpu_thread_id: int, SMI_code_data: int, _rax: int, _rbx: i ret = struct.unpack(f'7{self._pack}', out_buf) return ret + def send_sw_smi_timed(self, cpu_thread_id: int, SMI_code_data: int, _rax: int, _rbx: int, _rcx: int, _rdx: int, _rsi: int, _rdi: int) -> Optional[Tuple[int, int, int, int, int, int, int]]: + self.set_affinity(cpu_thread_id) + in_buf = struct.pack(f'8{self._pack}', SMI_code_data, _rax, _rbx, _rcx, _rdx, _rsi, _rdi, 0) + out_buf = self.ioctl(IOCTL_SWSMI_TIMED, in_buf) + ret = struct.unpack(f'8{self._pack}', out_buf) + return ret + # # File system # diff --git a/chipsec/modules/tools/smm/smm_ptr.py b/chipsec/modules/tools/smm/smm_ptr.py index 9aceda115b..42f8c6e4f3 100644 --- a/chipsec/modules/tools/smm/smm_ptr.py +++ b/chipsec/modules/tools/smm/smm_ptr.py @@ -36,6 +36,7 @@ * ``config`` = use SMI configuration file * ``fuzz`` = fuzz all SMI handlers with code in the range * ``fuzzmore`` = fuzz mode + pass 2nd-order pointers within buffer to SMI handlers + * ``scan`` = fuzz mode + time measurement to identify SMIs that trigger long-running code paths - ``size``: size of the memory buffer (in Hex) - ``address``: physical address of memory buffer to pass in GP regs to SMI handlers (in Hex) @@ -101,6 +102,7 @@ # False - better performance, True - better results tracking FLUSH_OUTPUT_ALWAYS = False # makes sure SMI code is logged in case of a crash +FLUSH_OUTPUT_BEFORE_SMI = True FLUSH_OUTPUT_AFTER_SMI = True # dump all registers in log before every SMI (True - large size of log file) DUMP_GPRS_EVERY_SMI = True @@ -139,6 +141,9 @@ # very obscure option, don't even try to understand GPR_2ADDR = False +# Defines the time percentage increase at which the SMI call is considered to +# have a significant effect +OUTLIER_THRESHOLD = 33.3 # # Defaults @@ -154,6 +159,121 @@ _pth = 'smm_ptr' +class gprs_info: + def __init__(self, value): + self.gprs = value + + def __repr__(self): + return f"rax={self.gprs['rax']:02X} rbx={self.gprs['rbx']:02X} rcx={self.gprs['rcx']:02X}, " \ + f"rdx={self.gprs['rdx']:02X} rsi={self.gprs['rsi']:02X} rdi={self.gprs['rdi']:02X}" + + +class smi_info: + def __init__(self, value): + self.duration = value + self.gprs = _DEFAULT_GPRS + self.code = None + self.data = None + + def update(self, value, code, data, gprs): + self.duration = value + self.gprs = gprs + self.code = code + self.data = data + + def get_info(self): + if self.code == None: + return None + else: + return f"duration {self.duration} code {self.code:02X} data {self.data:02X} ({gprs_info(self.gprs)})" + + +class scan_track: + def __init__(self): + self.clear() + self.hist_smi_duration = 0 + self.hist_smi_num = 0 + self.outliers_hist = 0 + + def find_address_in_regs(self, gprs): + for key, value in gprs.items(): + if key == 'rcx': + continue + if value != _FILL_VALUE_QWORD: + return key + + def clear(self): + self.max = smi_info(0); + self.min = smi_info(2**32-1); + self.outlier = smi_info(0); + self.acc_smi_duration = 0 + self.acc_smi_num = 0 + self.avg_smi_duration = 0 + self.avg_smi_num = 0 + self.outliers = 0 + self.code = None + self.confirmed = False + + def add(self, duration, code, data, gprs, confirmed=False): + if not self.code: + self.code = code + outlier = self.is_outlier(duration) + if not outlier: + self.acc_smi_duration += duration + self.acc_smi_num += 1 + if duration > self.max.duration: + self.max.update(duration, code, data, gprs.copy()) + elif duration < self.min.duration: + self.min.update(duration, code, data, gprs.copy()) + else: + self.outliers += 1 + self.outliers_hist += 1 + self.outlier.update(duration, code, data, gprs.copy()) + self.confirmed = confirmed + + def avg(self): + if self.avg_smi_num or self.acc_smi_num: + self.avg_smi_duration = ((self.avg_smi_duration * self.avg_smi_num) + self.acc_smi_duration) / (self.avg_smi_num + self.acc_smi_num) + self.avg_smi_num += self.acc_smi_num + self.hist_smi_duration = ((self.hist_smi_duration * self.hist_smi_num) + self.acc_smi_duration) / (self.hist_smi_num + self.acc_smi_num) + self.hist_smi_num += self.acc_smi_num + self.acc_smi_duration = 0 + self.acc_smi_num = 0 + + def is_outlier(self, value): + self.avg() + ret = False + if self.avg_smi_duration and value > self.avg_smi_duration * (1 + OUTLIER_THRESHOLD / 100): + ret = True + if self.hist_smi_duration and value > self.hist_smi_duration * (1 + OUTLIER_THRESHOLD / 100): + ret = True + return ret + + def skip(self): + return self.outliers or self.confirmed + + def found_outlier(self): + return bool(self.outliers) + + def get_total_outliers(self): + return self.outliers_hist + + def get_info(self): + self.avg() + avg = self.avg_smi_duration or self.hist_smi_duration + info = f"average {round(avg)} checked {self.avg_smi_num + self.outliers}" + if self.outliers: + info += f"\n Identified outlier: {self.outlier.get_info()}" + return info + + def log_smi_result(self, logger): + msg = f'SCANNED: SMI# {self.code:02X} {self.get_info()}' + if self.found_outlier(): + logger.log_important(msg) + else: + logger.log(f'[*] {msg}') + + class smi_desc: def __init__(self): self.smi_code = None @@ -231,6 +351,19 @@ def send_smi(self, thread_id, smi_code, smi_data, name, desc, rax, rbx, rcx, rdx self.interrupts.send_SW_SMI(thread_id, smi_code, smi_data, rax, rbx, rcx, rdx, rsi, rdi) return True + def send_smi_timed(self, thread_id, smi_code, smi_data, name, desc, rax, rbx, rcx, rdx, rsi, rdi): + self.logger.log(f' > SMI {smi_code:02X} (data: {smi_data:02X})') + if DUMP_GPRS_EVERY_SMI: + self.logger.log(f' RAX: 0x{rax:016X}') + self.logger.log(f' RBX: 0x{rbx:016X}') + self.logger.log(f' RCX: 0x{rcx:016X}') + self.logger.log(f' RDX: 0x{rdx:016X}') + self.logger.log(f' RSI: 0x{rsi:016X}') + self.logger.log(f' RDI: 0x{rdi:016X}') + ret = self.interrupts.send_SW_SMI_timed(thread_id, smi_code, smi_data, rax, rbx, rcx, rdx, rsi, rdi) + duration = ret[7]; + return (True, duration) + def check_memory(self, _addr, _smi_desc, fn, restore_contents=False): _ptr = _smi_desc.ptr filler = self.fill_byte * self.fill_size @@ -290,12 +423,15 @@ def check_memory(self, _addr, _smi_desc, fn, restore_contents=False): return (_changed or _changed1) - def smi_fuzz_iter(self, thread_id, _addr, _smi_desc, fill_contents=True, restore_contents=False): + def smi_fuzz_iter(self, thread_id, _addr, _smi_desc, fill_contents=True, restore_contents=False, scan=None): # # Fill memory buffer if not in 'No Fill' mode # if self.is_check_memory and fill_contents: self.fill_memory(_addr, _smi_desc.ptr_in_buffer, _smi_desc.ptr, _smi_desc.ptr_offset, _smi_desc.sig, _smi_desc.sig_offset) + + if FLUSH_OUTPUT_BEFORE_SMI: + self.logger.flush() # # Invoke SW SMI Handler # @@ -305,8 +441,15 @@ def smi_fuzz_iter(self, thread_id, _addr, _smi_desc, fill_contents=True, restore _rdx = _smi_desc.gprs['rdx'] _rsi = _smi_desc.gprs['rsi'] _rdi = _smi_desc.gprs['rdi'] - self.send_smi(thread_id, _smi_desc.smi_code, _smi_desc.smi_data, _smi_desc.name, _smi_desc.desc, _rax, _rbx, _rcx, _rdx, _rsi, _rdi) - + if not scan: + self.send_smi(thread_id, _smi_desc.smi_code, _smi_desc.smi_data, _smi_desc.name, _smi_desc.desc, _rax, _rbx, _rcx, _rdx, _rsi, _rdi) + else: + _, duration = self.send_smi_timed(thread_id, _smi_desc.smi_code, _smi_desc.smi_data, _smi_desc.name, _smi_desc.desc, _rax, _rbx, _rcx, _rdx, _rsi, _rdi) + # + # Re-do the call if it was identified as an outlier, due to periodic SMI delays + # + if scan.is_outlier(duration): + _, duration = self.send_smi_timed(thread_id, _smi_desc.smi_code, _smi_desc.smi_data, _smi_desc.name, _smi_desc.desc, _rax, _rbx, _rcx, _rdx, _rsi, _rdi) # # Check memory buffer if not in 'No Fill' mode # @@ -317,9 +460,12 @@ def smi_fuzz_iter(self, thread_id, _addr, _smi_desc, fill_contents=True, restore if contents_changed: msg = f'DETECTED: SMI# {_smi_desc.smi_code:X} data {_smi_desc.smi_data:X} (rax={_rax:X} rbx={_rbx:X} rcx={_rcx:X} rdx={_rdx:X} rsi={_rsi:X} rdi={_rdi:X})' self.logger.log_important(msg) - if FUZZ_BAIL_ON_1ST_DETECT: + if FUZZ_BAIL_ON_1ST_DETECT and not scan: raise BadSMIDetected(msg) + if scan: + scan.add(duration, _smi_desc.smi_code, _smi_desc.smi_data, _smi_desc.gprs, contents_changed) + if FLUSH_OUTPUT_AFTER_SMI: self.logger.flush() @@ -338,7 +484,7 @@ def test_config(self, thread_id, _smi_config_fname, _addr, _addr1): for line in fcfg: if '' == line.strip(): self.logger.log(f'\n[*] Testing SMI# 0x{_smi_desc.smi_code:02X} (data: 0x{_smi_desc.smi_data:02X}) {_smi_desc.name} ({_smi_desc.desc})') - if self.smi_fuzz_iter(thread_id, _addr, _smi_desc): + if selfsmi_fuzz_iter(thread_id, _addr, _smi_desc): bad_ptr_cnt += 1 _smi_desc = None _smi_desc = smi_desc() @@ -366,7 +512,11 @@ def test_config(self, thread_id, _smi_config_fname, _addr, _addr1): return bad_ptr_cnt - def test_fuzz(self, thread_id, smic_start, smic_end, _addr, _addr1): + def test_fuzz(self, thread_id, smic_start, smic_end, _addr, _addr1, scan_mode=True): + + scan = None + if scan_mode: + scan = scan_track() gpr_value = ((_addr << 32) | _addr) if GPR_2ADDR else _addr @@ -378,7 +528,7 @@ def test_fuzz(self, thread_id, smic_start, smic_end, _addr, _addr1): bad_ptr_cnt = 0 _smi_desc = smi_desc() - _smi_desc.gprs = gprs_addr if PTR_IN_ALL_GPRS else gprs_fill + _smi_desc.gprs = gprs_addr if PTR_IN_ALL_GPRS or scan_mode else gprs_fill self.logger.log(f'\n[*] Setting values of general purpose registers to 0x{_smi_desc.gprs["rax"]:016X}') max_ptr_off = 1 @@ -404,57 +554,64 @@ def test_fuzz(self, thread_id, smic_start, smic_end, _addr, _addr1): for _rcx in range(MAX_SMI_FUNCTIONS): self.logger.log(f' >> Function (RCX): 0x{_rcx:016X}') _smi_desc.gprs['rcx'] = _rcx - if PTR_IN_ALL_GPRS: - if self.smi_fuzz_iter(thread_id, _addr, _smi_desc, False, True): + if PTR_IN_ALL_GPRS or scan_mode: + if self.smi_fuzz_iter(thread_id, _addr, _smi_desc, False, True, scan): bad_ptr_cnt += 1 + if scan and scan.skip(): + break else: self.logger.log(f' RBX: 0x{_addr:016X}') _smi_desc.gprs['rbx'] = gpr_value - if self.smi_fuzz_iter(thread_id, _addr, _smi_desc, False, True): + if self.smi_fuzz_iter(thread_id, _addr, _smi_desc, False, True, scan): bad_ptr_cnt += 1 _smi_desc.gprs['rbx'] = _FILL_VALUE_QWORD self.logger.log(f' RSI: 0x{_addr:016X}') _smi_desc.gprs['rsi'] = gpr_value - if self.smi_fuzz_iter(thread_id, _addr, _smi_desc, False, True): + if self.smi_fuzz_iter(thread_id, _addr, _smi_desc, False, True, scan): bad_ptr_cnt += 1 _smi_desc.gprs['rsi'] = _FILL_VALUE_QWORD self.logger.log(f' RDI: 0x{_addr:016X}') _smi_desc.gprs['rdi'] = gpr_value - if self.smi_fuzz_iter(thread_id, _addr, _smi_desc, False, True): + if self.smi_fuzz_iter(thread_id, _addr, _smi_desc, False, True, scan): bad_ptr_cnt += 1 _smi_desc.gprs['rdi'] = _FILL_VALUE_QWORD else: - if PTR_IN_ALL_GPRS: - if self.smi_fuzz_iter(thread_id, _addr, _smi_desc, False, True): + if PTR_IN_ALL_GPRS or scan_mode: + if self.smi_fuzz_iter(thread_id, _addr, _smi_desc, False, True, scan): bad_ptr_cnt += 1 else: self.logger.log(f' RBX: 0x{_addr:016X}') _smi_desc.gprs['rbx'] = gpr_value - if self.smi_fuzz_iter(thread_id, _addr, _smi_desc, False, True): + if self.smi_fuzz_iter(thread_id, _addr, _smi_desc, False, True, scan): bad_ptr_cnt += 1 _smi_desc.gprs['rbx'] = _FILL_VALUE_QWORD self.logger.log(f' RCX: 0x{_addr:016X}') _smi_desc.gprs['rcx'] = gpr_value - if self.smi_fuzz_iter(thread_id, _addr, _smi_desc, False, True): + if self.smi_fuzz_iter(thread_id, _addr, _smi_desc, False, True, scan): bad_ptr_cnt += 1 _smi_desc.gprs['rcx'] = _FILL_VALUE_QWORD self.logger.log(f' RSI: 0x{_addr:016X}') _smi_desc.gprs['rsi'] = gpr_value - if self.smi_fuzz_iter(thread_id, _addr, _smi_desc, False, True): + if self.smi_fuzz_iter(thread_id, _addr, _smi_desc, False, True, scan): bad_ptr_cnt += 1 _smi_desc.gprs['rsi'] = _FILL_VALUE_QWORD self.logger.log(f' RDI: 0x{_addr:016X}') _smi_desc.gprs['rdi'] = gpr_value - if self.smi_fuzz_iter(thread_id, _addr, _smi_desc, False, True): + if self.smi_fuzz_iter(thread_id, _addr, _smi_desc, False, True, scan): bad_ptr_cnt += 1 _smi_desc.gprs['rdi'] = _FILL_VALUE_QWORD + if scan and scan.skip(): + break + if scan_mode: + msg = scan.log_smi_result(self.logger) + scan.clear() - return bad_ptr_cnt + return bad_ptr_cnt, scan def run(self, module_argv): self.logger.start_test("A tool to test SMI handlers for pointer validation vulnerabilities") @@ -463,6 +620,7 @@ def run(self, module_argv): self.logger.log(" = config use SMI configuration file ") self.logger.log(" = fuzz fuzz all SMI handlers with code in the range ") self.logger.log(" = fuzzmore fuzz mode + pass '2nd-order' pointers within buffer to SMI handlers") + self.logger.log(" = scan fuzz mode + time measurement to identify SMIs that trigger long-running code paths") self.logger.log(" size size of the memory buffer (in Hex)") self.logger.log(" address physical address of memory buffer to pass in GP regs to SMI handlers (in Hex)") self.logger.log(" = smram pass address of SMRAM base (system may hang in this mode!)\n") @@ -480,13 +638,15 @@ def run(self, module_argv): test_mode = module_argv[0].lower() if test_mode == 'config': _smi_config_fname = module_argv[1] - elif test_mode in ['fuzz', 'fuzzmore']: + elif test_mode in ['fuzz', 'fuzzmore', 'scan']: smic_arr = module_argv[1].split(':') smic_start = int(smic_arr[0], 16) smic_end = int(smic_arr[1], 16) if test_mode == 'fuzzmore': self.test_ptr_in_buffer = True DUMP_GPRS_EVERY_SMI = False + elif test_mode == 'scan': + self.test_ptr_in_buffer = False else: self.logger.log_error(f'Unknown fuzzing mode \'{module_argv[0]}\'') self.result.setStatusBit(self.result.status.UNSUPPORTED_OPTION) @@ -541,15 +701,21 @@ def run(self, module_argv): os.makedirs(_pth) bad_ptr_cnt = 0 + scan_mode = False try: if 'config' == test_mode: - bad_ptr_cnt = self.test_config(thread_id, _smi_config_fname, _addr, _addr1) + bad_ptr_cnt, _ = self.test_config(thread_id, _smi_config_fname, _addr, _addr1) elif test_mode in ['fuzz', 'fuzzmore']: - bad_ptr_cnt = self.test_fuzz(thread_id, smic_start, smic_end, _addr, _addr1) + bad_ptr_cnt, _ = self.test_fuzz(thread_id, smic_start, smic_end, _addr, _addr1) + elif test_mode in ['scan']: + scan_mode = True + bad_ptr_cnt, scan = self.test_fuzz(thread_id, smic_start, smic_end, _addr, _addr1, True) except BadSMIDetected as msg: bad_ptr_cnt = 1 self.logger.log_important("Potentially bad SMI detected! Stopped fuzing (see FUZZ_BAIL_ON_1ST_DETECT option)") + if scan_mode: + self.logger.log_good(f'<<< Done: found {scan.get_total_outliers()} long-running SMIs') if bad_ptr_cnt > 0: self.logger.log_bad(f'<<< Done: found {bad_ptr_cnt:d} potential occurrences of unchecked input pointers') self.result.setStatusBit(self.result.status.POTENTIALLY_VULNERABLE) diff --git a/drivers/linux/amd64/cpu.asm b/drivers/linux/amd64/cpu.asm index 40e1438210..3ca56364f8 100644 --- a/drivers/linux/amd64/cpu.asm +++ b/drivers/linux/amd64/cpu.asm @@ -39,6 +39,8 @@ global __cpuid__ global __swsmi__ + global __swsmi_timed__ + global __swsmi_timed_test__ section .text @@ -419,6 +421,84 @@ __swsmi__: ret +;------------------------------------------------------------------------------ +;This function has two arguments: SMI_CTX structure pointer which contain SMI code and data values and 6 regs: rax, rbx, rcx, rdx, rsi, rdi: +; IN UINT64 smi_code_data (only lower 16 bit used) +; IN/OUT UINT64 rax_value +; IN/OUT UINT64 rbx_value +; IN/OUT UINT64 rcx_value +; IN/OUT UINT64 rdx_value +; IN/OUT UINT64 rsi_value +; IN/OUT UINT64 rdi_value +; The second argument is a pointer to an unsigned long to return the measured execution time +;------------------------------------------------------------------------------ +; void +; __swsmi_timed__ ( +; SMI_CTX ctx // rdi +; unsigned long *time // rsi +; ) +;------------------------------------------------------------------------------ +__swsmi_timed__: + mov r10, rdi + push r12 ; callee-saved register + mov r12, rsi + + ; setting up GPR (arguments) to SMI handler call + ; notes: + ; RAX will get partially overwritten (AX) by smi_code_data + xchg rax, [r10+08h] ; rax_value (partially overwritten with smi_code_data) + mov ax, [r10+0h] ; smi_code_data + xchg rbx, [r10+010h] ; rbx_value + xchg rcx, [r10+018h] ; rcx_value + xchg rdx, [r10+020h] ; rdx_value + xchg rsi, [r10+028h] ; rsi_value + xchg rdi, [r10+030h] ; rdi_value + + ; Output smi_code_data split up to their designated ports, SW SMI data + ; (0xB3) and SW SMI control (0xB2), respectively. + ; + ; Resist from outputting both at once as a single word, as some systems + ; reject the request if the i/o spans more than a byte, e.g.: + ; https://github.com/tianocore/edk2-platforms/blob/aa3f6fd542e99dde4206537b095f1a2201275e75/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw.c#L314 + ror ax, 8 + out 0B3h, al + + ; read time-stamp counter + mov r9, rax + mov r11, rdx + rdtsc + shl rdx, 32 + or rax, rdx + mov r8, rax + mov rax, r9 + mov rdx, r11 + + ; trigger SMI + ror ax, 8 + out 0B2h, al + + ; measure SMI execution time + mov r9, rax + mov r11, rdx + rdtsc + shl rdx, 32 + or rax, rdx + sub rax, r8 + mov [r12], rax + mov rax, r9 + mov rdx, r11 + + ; some SMI handlers return data/errorcode in GPRs, need to return this to the caller + xchg rax, [r10+08h] ; rax_value + xchg rbx, [r10+010h] ; rbx_value + xchg rcx, [r10+018h] ; rcx_value + xchg rdx, [r10+020h] ; rdx_value + xchg rsi, [r10+028h] ; rsi_value + xchg rdi, [r10+030h] ; rdi_value + + pop r12 + ret + ;------------------------------------------------------------------------------ ; void ; WritePCIByte ( diff --git a/drivers/linux/chipsec_km.c b/drivers/linux/chipsec_km.c index 7cf893b05c..dd39a2afe9 100644 --- a/drivers/linux/chipsec_km.c +++ b/drivers/linux/chipsec_km.c @@ -117,6 +117,7 @@ typedef struct tagSMI_CONTEXT { typedef SMI_CONTEXT SMI_CTX, *PSMI_CTX; void __swsmi__(SMI_CTX * ctx); + void __swsmi_timed__(SMI_CTX * ctx, unsigned long * time); void _rdmsr( unsigned long msr_num, // rdi @@ -1077,7 +1078,7 @@ static long d_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioc #endif } - case IOCTL_SWSMI: + case IOCTL_SWSMI: { //IN params: SMI_code_data, _rax, _rbx, _rcx, _rdx, _rsi, _rdi #ifdef CONFIG_X86 @@ -1099,6 +1100,33 @@ static long d_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioc return -EOPNOTSUPP; #endif } + + case IOCTL_SWSMI_TIMED: + { + //IN params: SMI_code_data, _rax, _rbx, _rcx, _rdx, _rsi, _rdi +#ifdef CONFIG_X86 + + printk( KERN_INFO "[chipsec] > IOCTL_SWSMI_TIMED\n"); + numargs = 7; + if(copy_from_user((void*)ptrbuf, (void*)ioctl_param, (sizeof(long) * numargs)) > 0) + { + printk( KERN_ALERT "[chipsec] ERROR: STATUS_INVALID_PARAMETER\n" ); + break; + } + + unsigned long m_time; + preempt_disable(); + __swsmi_timed__((SMI_CTX *)ptr, &m_time); + preempt_enable(); + ptrbuf[numargs] = m_time; + + if(copy_to_user((void*)ioctl_param, (void*)ptrbuf, (sizeof(long) * (numargs + 1))) > 0) + return -EFAULT; + break; +#else + return -EOPNOTSUPP; +#endif + } case IOCTL_RDCR: { diff --git a/drivers/linux/include/chipsec.h b/drivers/linux/include/chipsec.h index 2e9cafa4bc..6b144d5128 100644 --- a/drivers/linux/include/chipsec.h +++ b/drivers/linux/include/chipsec.h @@ -48,6 +48,7 @@ chipsec@intel.com #define IOCTL_VA2PA _IOWR(IOCTL_NUM, 0x14, int*) #define IOCTL_MSGBUS_SEND_MESSAGE _IOWR(IOCTL_NUM, 0x15, int*) #define IOCTL_FREE_PHYSMEM _IOWR(IOCTL_NUM, 0x16, int*) +#define IOCTL_SWSMI_TIMED _IOWR(IOCTL_NUM, 0x17, int*) // // SoC IOSF Message Bus constants