1# SPDX-License-Identifier: GPL-2.0
2# (C) Copyright 2024, Advanced Micro Devices, Inc.
3
4"""
5Note: This test relies on boardenv_* containing configuration values to define
6spi minimum and maximum frequencies at which the flash part can operate on and
7these tests run at different spi frequency randomised values in the range
8multiple times based on the user defined iteration value.
9It also defines the SPI bus number containing the SPI-flash chip, SPI
10chip-select, SPI mode, SPI flash part name and timeout parameters. If minimum
11and maximum frequency is not defined, it will run on freq 0 by default.
12
13Without the boardenv_* configuration, this test will be automatically skipped.
14
15It also relies on configuration values for supported flashes for lock and
16unlock cases for SPI family flash. It will run lock-unlock cases only for the
17supported flash parts.
18
19For Example:
20
21# Details of SPI device test parameters required for SPI device testing:
22
23# bus - SPI bus number to init the flash device
24# chip_select - SPI chip select number to init the flash device
25# min_freq - Minimum frequency in hz at which the flash part can operate, set 0
26# or None for default frequency
27# max_freq - Maximum frequency in hz at which the flash part can operate, set 0
28# or None for default frequency
29# mode - SPI mode to init the flash device
30# part_name - SPI flash part name to be detected
31# timeout - Default timeout to run the sf commands
32# iteration - No of iteration to run SPI flash test
33
34env__spi_device_test = {
35    'bus': 0,
36    'chip_select': 0,
37    'min_freq': 10000000,
38    'max_freq': 100000000,
39    'mode': 0,
40    'part_name': 'n25q00a',
41    'timeout': 100000,
42    'iteration': 5,
43}
44
45# supported_flash - Flash parts name which support lock-unlock functionality
46env__spi_lock_unlock = {
47    'supported_flash': 'mt25qu512a, n25q00a, n25q512ax3',
48}
49"""
50
51import random
52import re
53import pytest
54import utils
55
56SPI_DATA = {}
57EXPECTED_ERASE = 'Erased: OK'
58EXPECTED_WRITE = 'Written: OK'
59EXPECTED_READ = 'Read: OK'
60EXPECTED_ERASE_ERRORS = [
61    'Erase operation failed',
62    'Attempted to modify a protected sector',
63    'Erased: ERROR',
64    'is protected and cannot be erased',
65    'ERROR: flash area is locked',
66]
67EXPECTED_WRITE_ERRORS = [
68    'ERROR: flash area is locked',
69    'Program operation failed',
70    'Attempted to modify a protected sector',
71    'Written: ERROR',
72]
73
74def get_params_spi(ubman):
75    ''' Get SPI device test parameters from boardenv file '''
76    f = ubman.config.env.get('env__spi_device_test', None)
77    if not f:
78        pytest.skip('No SPI test device configured')
79
80    bus = f.get('bus', 0)
81    cs = f.get('chip_select', 0)
82    mode = f.get('mode', 0)
83    part_name = f.get('part_name', None)
84    timeout = f.get('timeout', None)
85
86    if not part_name:
87        pytest.skip('No SPI test device configured')
88
89    return bus, cs, mode, part_name, timeout
90
91def spi_find_freq_range(ubman):
92    '''Find out minimum and maximum frequnecies that SPI device can operate'''
93    f = ubman.config.env.get('env__spi_device_test', None)
94    if not f:
95        pytest.skip('No SPI test device configured')
96
97    min_f = f.get('min_freq', None)
98    max_f = f.get('max_freq', None)
99    iterations = f.get('iteration', 1)
100
101    if not min_f:
102        min_f = 0
103    if not max_f:
104        max_f = 0
105
106    max_f = max(max_f, min_f)
107
108    return min_f, max_f, iterations
109
110def spi_pre_commands(ubman, freq):
111    ''' Find out SPI family flash memory parameters '''
112    bus, cs, mode, part_name, timeout = get_params_spi(ubman)
113
114    output = ubman.run_command(f'sf probe {bus}:{cs} {freq} {mode}')
115    if not 'SF: Detected' in output:
116        pytest.fail('No SPI device available')
117
118    if not part_name in output:
119        pytest.fail('Not recognized the SPI flash part name')
120
121    m = re.search('page size (.+?) Bytes', output)
122    assert m
123    try:
124        page_size = int(m.group(1))
125    except ValueError:
126        pytest.fail('Not recognized the SPI page size')
127
128    m = re.search('erase size (.+?) KiB', output)
129    assert m
130    try:
131        erase_size = int(m.group(1))
132        erase_size *= 1024
133    except ValueError:
134        pytest.fail('Not recognized the SPI erase size')
135
136    m = re.search('total (.+?) MiB', output)
137    assert m
138    try:
139        total_size = int(m.group(1))
140        total_size *= 1024 * 1024
141    except ValueError:
142        pytest.fail('Not recognized the SPI total size')
143
144    m = re.search('Detected (.+?) with', output)
145    assert m
146    try:
147        flash_part = m.group(1)
148        assert flash_part == part_name
149    except ValueError:
150        pytest.fail('Not recognized the SPI flash part')
151
152    global SPI_DATA
153    SPI_DATA = {
154        'page_size': page_size,
155        'erase_size': erase_size,
156        'total_size': total_size,
157        'flash_part': flash_part,
158        'timeout': timeout,
159    }
160
161def get_page_size():
162    ''' Get the SPI page size from spi data '''
163    return SPI_DATA['page_size']
164
165def get_erase_size():
166    ''' Get the SPI erase size from spi data '''
167    return SPI_DATA['erase_size']
168
169def get_total_size():
170    ''' Get the SPI total size from spi data '''
171    return SPI_DATA['total_size']
172
173def get_flash_part():
174    ''' Get the SPI flash part name from spi data '''
175    return SPI_DATA['flash_part']
176
177def get_timeout():
178    ''' Get the SPI timeout from spi data '''
179    return SPI_DATA['timeout']
180
181def spi_erase_block(ubman, erase_size, total_size):
182    ''' Erase SPI flash memory block wise '''
183    for start in range(0, total_size, erase_size):
184        output = ubman.run_command(f'sf erase {hex(start)} {hex(erase_size)}')
185        assert EXPECTED_ERASE in output
186
187@pytest.mark.buildconfigspec('cmd_sf')
188def test_spi_erase_block(ubman):
189    ''' Test case to check SPI erase functionality by erasing memory regions
190    block-wise '''
191
192    min_f, max_f, loop = spi_find_freq_range(ubman)
193    i = 0
194    while i < loop:
195        spi_pre_commands(ubman, random.randint(min_f, max_f))
196        spi_erase_block(ubman, get_erase_size(), get_total_size())
197        i = i + 1
198
199def spi_write_twice(ubman, page_size, erase_size, total_size, timeout):
200    ''' Random write till page size, random till size and full size '''
201    addr = utils.find_ram_base(ubman)
202
203    old_size = 0
204    for size in (
205        random.randint(4, page_size),
206        random.randint(page_size, total_size),
207        total_size,
208    ):
209        offset = random.randint(4, page_size)
210        offset = offset & ~3
211        size = size & ~3
212        size = size - old_size
213        output = ubman.run_command(f'crc32 {hex(addr + total_size)} {hex(size)}')
214        m = re.search('==> (.+?)$', output)
215        if not m:
216            pytest.fail('CRC32 failed')
217
218        expected_crc32 = m.group(1)
219        if old_size % page_size:
220            old_size = int(old_size / page_size)
221            old_size *= page_size
222
223        if size % erase_size:
224            erasesize = int(size / erase_size + 1)
225            erasesize *= erase_size
226
227        eraseoffset = int(old_size / erase_size)
228        eraseoffset *= erase_size
229
230        timeout = 100000000
231        with ubman.temporary_timeout(timeout):
232            output = ubman.run_command(
233                f'sf erase {hex(eraseoffset)} {hex(erasesize)}'
234            )
235            assert EXPECTED_ERASE in output
236
237        with ubman.temporary_timeout(timeout):
238            output = ubman.run_command(
239                f'sf write {hex(addr + total_size)} {hex(old_size)} {hex(size)}'
240            )
241            assert EXPECTED_WRITE in output
242        with ubman.temporary_timeout(timeout):
243            output = ubman.run_command(
244                f'sf read {hex(addr + total_size + offset)} {hex(old_size)} {hex(size)}'
245            )
246            assert EXPECTED_READ in output
247        output = ubman.run_command(
248            f'crc32 {hex(addr + total_size + offset)} {hex(size)}'
249        )
250        assert expected_crc32 in output
251        old_size = size
252
253@pytest.mark.buildconfigspec('cmd_bdi')
254@pytest.mark.buildconfigspec('cmd_sf')
255@pytest.mark.buildconfigspec('cmd_memory')
256def test_spi_write_twice(ubman):
257    ''' Test to write data with random size twice for SPI '''
258    min_f, max_f, loop = spi_find_freq_range(ubman)
259    i = 0
260    while i < loop:
261        spi_pre_commands(ubman, random.randint(min_f, max_f))
262        spi_write_twice(
263            ubman,
264            get_page_size(),
265            get_erase_size(),
266            get_total_size(),
267            get_timeout()
268        )
269        i = i + 1
270
271def spi_write_continues(ubman, page_size, erase_size, total_size, timeout):
272    ''' Write with random size of data to continue SPI write case '''
273    spi_erase_block(ubman, erase_size, total_size)
274    addr = utils.find_ram_base(ubman)
275
276    output = ubman.run_command(f'crc32 {hex(addr + 0x10000)} {hex(total_size)}')
277    m = re.search('==> (.+?)$', output)
278    if not m:
279        pytest.fail('CRC32 failed')
280    expected_crc32 = m.group(1)
281
282    old_size = 0
283    for size in (
284        random.randint(4, page_size),
285        random.randint(page_size, total_size),
286        total_size,
287    ):
288        size = size & ~3
289        size = size - old_size
290        with ubman.temporary_timeout(timeout):
291            output = ubman.run_command(
292                f'sf write {hex(addr + 0x10000 + old_size)} {hex(old_size)} {hex(size)}'
293            )
294            assert EXPECTED_WRITE in output
295        old_size += size
296
297    with ubman.temporary_timeout(timeout):
298        output = ubman.run_command(
299            f'sf read {hex(addr + 0x10000 + total_size)} 0 {hex(total_size)}'
300        )
301        assert EXPECTED_READ in output
302
303    output = ubman.run_command(
304        f'crc32 {hex(addr + 0x10000 + total_size)} {hex(total_size)}'
305    )
306    assert expected_crc32 in output
307
308@pytest.mark.buildconfigspec('cmd_bdi')
309@pytest.mark.buildconfigspec('cmd_sf')
310@pytest.mark.buildconfigspec('cmd_memory')
311def test_spi_write_continues(ubman):
312    ''' Test to write more random size data for SPI '''
313    min_f, max_f, loop = spi_find_freq_range(ubman)
314    i = 0
315    while i < loop:
316        spi_pre_commands(ubman, random.randint(min_f, max_f))
317        spi_write_twice(
318            ubman,
319            get_page_size(),
320            get_erase_size(),
321            get_total_size(),
322            get_timeout(),
323        )
324        i = i + 1
325
326def spi_read_twice(ubman, page_size, total_size, timeout):
327    ''' Read the whole SPI flash twice, random_size till full flash size,
328    random till page size '''
329    for size in random.randint(4, page_size), random.randint(4, total_size), total_size:
330        addr = utils.find_ram_base(ubman)
331        size = size & ~3
332        with ubman.temporary_timeout(timeout):
333            output = ubman.run_command(
334                f'sf read {hex(addr + total_size)} 0 {hex(size)}'
335            )
336            assert EXPECTED_READ in output
337        output = ubman.run_command(f'crc32 {hex(addr + total_size)} {hex(size)}')
338        m = re.search('==> (.+?)$', output)
339        if not m:
340            pytest.fail('CRC32 failed')
341        expected_crc32 = m.group(1)
342        with ubman.temporary_timeout(timeout):
343            output = ubman.run_command(
344                f'sf read {hex(addr + total_size + 10)} 0 {hex(size)}'
345            )
346            assert EXPECTED_READ in output
347        output = ubman.run_command(
348            f'crc32 {hex(addr + total_size + 10)} {hex(size)}'
349        )
350        assert expected_crc32 in output
351
352@pytest.mark.buildconfigspec('cmd_sf')
353@pytest.mark.buildconfigspec('cmd_bdi')
354@pytest.mark.buildconfigspec('cmd_memory')
355def test_spi_read_twice(ubman):
356    ''' Test to read random data twice from SPI '''
357    min_f, max_f, loop = spi_find_freq_range(ubman)
358    i = 0
359    while i < loop:
360        spi_pre_commands(ubman, random.randint(min_f, max_f))
361        spi_read_twice(ubman, get_page_size(), get_total_size(), get_timeout())
362        i = i + 1
363
364def spi_erase_all(ubman, total_size, timeout):
365    ''' Erase the full chip SPI '''
366    start = 0
367    with ubman.temporary_timeout(timeout):
368        output = ubman.run_command(f'sf erase {start} {hex(total_size)}')
369        assert EXPECTED_ERASE in output
370
371@pytest.mark.buildconfigspec('cmd_sf')
372def test_spi_erase_all(ubman):
373    ''' Test to check full chip erase for SPI '''
374    min_f, max_f, loop = spi_find_freq_range(ubman)
375    i = 0
376    while i < loop:
377        spi_pre_commands(ubman, random.randint(min_f, max_f))
378        spi_erase_all(ubman, get_total_size(), get_timeout())
379        i = i + 1
380
381def flash_ops(
382    ubman, ops, start, size, offset=0, exp_ret=0, exp_str='', not_exp_str=''
383):
384    ''' Flash operations: erase, write and read '''
385
386    f = ubman.config.env.get('env__spi_device_test', None)
387    if not f:
388        timeout = 1000000
389
390    timeout = f.get('timeout', 1000000)
391
392    if ops == 'erase':
393        with ubman.temporary_timeout(timeout):
394            output = ubman.run_command(f'sf erase {hex(start)} {hex(size)}')
395    else:
396        with ubman.temporary_timeout(timeout):
397            output = ubman.run_command(
398                f'sf {ops} {hex(offset)} {hex(start)} {hex(size)}'
399            )
400
401    if exp_str:
402        assert exp_str in output
403    if not_exp_str:
404        assert not_exp_str not in output
405
406    ret_code = ubman.run_command('echo $?')
407    if exp_ret >= 0:
408        assert ret_code.endswith(str(exp_ret))
409
410    return output, ret_code
411
412def spi_unlock_exit(ubman, addr, size):
413    ''' Unlock the flash before making it fail '''
414    ubman.run_command(f'sf protect unlock {hex(addr)} {hex(size)}')
415    assert False, 'FAIL: Flash lock is unable to protect the data!'
416
417def find_prot_region(lock_addr, lock_size):
418    ''' Get the protected and un-protected region of flash '''
419    total_size = get_total_size()
420    erase_size = get_erase_size()
421
422    if lock_addr < (total_size // 2):
423        sect_num = (lock_addr + lock_size) // erase_size
424        x = 1
425        while x < sect_num:
426            x *= 2
427        prot_start = 0
428        prot_size = x * erase_size
429        unprot_start = prot_start + prot_size
430        unprot_size = total_size - unprot_start
431    else:
432        sect_num = (total_size - lock_addr) // erase_size
433        x = 1
434        while x < sect_num:
435            x *= 2
436        prot_start = total_size - (x * erase_size)
437        prot_size = total_size - prot_start
438        unprot_start = 0
439        unprot_size = prot_start
440
441    return prot_start, prot_size, unprot_start, unprot_size
442
443def protect_ops(ubman, lock_addr, lock_size, ops="unlock"):
444    ''' Run the command to lock or Unlock the flash '''
445    ubman.run_command(f'sf protect {ops} {hex(lock_addr)} {hex(lock_size)}')
446    output = ubman.run_command('echo $?')
447    if ops == "lock" and not output.endswith('0'):
448        ubman.run_command(f'sf protect unlock {hex(lock_addr)} {hex(lock_size)}')
449        assert False, "sf protect lock command exits with non-zero return code"
450    assert output.endswith('0')
451
452def erase_write_ops(ubman, start, size):
453    ''' Basic erase and write operation for flash '''
454    addr = utils.find_ram_base(ubman)
455    flash_ops(ubman, 'erase', start, size, 0, 0, EXPECTED_ERASE)
456    flash_ops(ubman, 'write', start, size, addr, 0, EXPECTED_WRITE)
457
458def spi_lock_unlock(ubman, lock_addr, lock_size):
459    ''' Lock unlock operations for SPI family flash '''
460    addr = utils.find_ram_base(ubman)
461    erase_size = get_erase_size()
462
463    # Find the protected/un-protected region
464    prot_start, prot_size, unprot_start, unprot_size = find_prot_region(lock_addr, lock_size)
465
466    # Check erase/write operation before locking
467    erase_write_ops(ubman, prot_start, prot_size)
468
469    # Locking the flash
470    protect_ops(ubman, lock_addr, lock_size, 'lock')
471
472    # Check erase/write operation after locking
473    output, ret_code = flash_ops(ubman, 'erase', prot_start, prot_size, 0, -1)
474    if not any(error in output for error in EXPECTED_ERASE_ERRORS) or ret_code.endswith(
475        '0'
476    ):
477        spi_unlock_exit(ubman, lock_addr, lock_size)
478
479    output, ret_code = flash_ops(
480        ubman, 'write', prot_start, prot_size, addr, -1
481    )
482    if not any(error in output for error in EXPECTED_WRITE_ERRORS) or ret_code.endswith(
483        '0'
484    ):
485        spi_unlock_exit(ubman, lock_addr, lock_size)
486
487    # Check locked sectors
488    sect_lock_start = random.randrange(prot_start, (prot_start + prot_size), erase_size)
489    if prot_size > erase_size:
490        sect_lock_size = random.randrange(
491            erase_size, (prot_start + prot_size - sect_lock_start), erase_size
492        )
493    else:
494        sect_lock_size = erase_size
495    sect_write_size = random.randint(1, sect_lock_size)
496
497    output, ret_code = flash_ops(
498        ubman, 'erase', sect_lock_start, sect_lock_size, 0, -1
499    )
500    if not any(error in output for error in EXPECTED_ERASE_ERRORS) or ret_code.endswith(
501        '0'
502    ):
503        spi_unlock_exit(ubman, lock_addr, lock_size)
504
505    output, ret_code = flash_ops(
506        ubman, 'write', sect_lock_start, sect_write_size, addr, -1
507    )
508    if not any(error in output for error in EXPECTED_WRITE_ERRORS) or ret_code.endswith(
509        '0'
510    ):
511        spi_unlock_exit(ubman, lock_addr, lock_size)
512
513    # Check unlocked sectors
514    if unprot_size != 0:
515        sect_unlock_start = random.randrange(
516            unprot_start, (unprot_start + unprot_size), erase_size
517        )
518        if unprot_size > erase_size:
519            sect_unlock_size = random.randrange(
520                erase_size, (unprot_start + unprot_size - sect_unlock_start), erase_size
521            )
522        else:
523            sect_unlock_size = erase_size
524        sect_write_size = random.randint(1, sect_unlock_size)
525
526        output, ret_code = flash_ops(
527            ubman, 'erase', sect_unlock_start, sect_unlock_size, 0, -1
528        )
529        if EXPECTED_ERASE not in output or ret_code.endswith('1'):
530            spi_unlock_exit(ubman, lock_addr, lock_size)
531
532        output, ret_code = flash_ops(
533            ubman, 'write', sect_unlock_start, sect_write_size, addr, -1
534        )
535        if EXPECTED_WRITE not in output or ret_code.endswith('1'):
536            spi_unlock_exit(ubman, lock_addr, lock_size)
537
538    # Unlocking the flash
539    protect_ops(ubman, lock_addr, lock_size, 'unlock')
540
541    # Check erase/write operation after un-locking
542    erase_write_ops(ubman, prot_start, prot_size)
543
544    # Check previous locked sectors
545    sect_lock_start = random.randrange(prot_start, (prot_start + prot_size), erase_size)
546    if prot_size > erase_size:
547        sect_lock_size = random.randrange(
548            erase_size, (prot_start + prot_size - sect_lock_start), erase_size
549        )
550    else:
551        sect_lock_size = erase_size
552    sect_write_size = random.randint(1, sect_lock_size)
553
554    flash_ops(
555        ubman, 'erase', sect_lock_start, sect_lock_size, 0, 0, EXPECTED_ERASE
556    )
557    flash_ops(
558        ubman,
559        'write',
560        sect_lock_start,
561        sect_write_size,
562        addr,
563        0,
564        EXPECTED_WRITE,
565    )
566
567@pytest.mark.buildconfigspec('cmd_bdi')
568@pytest.mark.buildconfigspec('cmd_sf')
569@pytest.mark.buildconfigspec('cmd_memory')
570def test_spi_lock_unlock(ubman):
571    ''' Test to check the lock-unlock functionality for SPI family flash '''
572    min_f, max_f, loop = spi_find_freq_range(ubman)
573    flashes = ubman.config.env.get('env__spi_lock_unlock', False)
574    if not flashes:
575        pytest.skip('No SPI test device configured for lock/unlock')
576
577    i = 0
578    while i < loop:
579        spi_pre_commands(ubman, random.randint(min_f, max_f))
580        total_size = get_total_size()
581        flash_part = get_flash_part()
582
583        flashes_list = flashes.get('supported_flash', None).split(',')
584        flashes_list = [x.strip() for x in flashes_list]
585        if flash_part not in flashes_list:
586            pytest.skip('Detected flash does not support lock/unlock')
587
588        # For lower half of memory
589        lock_addr = random.randint(0, (total_size // 2) - 1)
590        lock_size = random.randint(1, ((total_size // 2) - lock_addr))
591        spi_lock_unlock(ubman, lock_addr, lock_size)
592
593        # For upper half of memory
594        lock_addr = random.randint((total_size // 2), total_size - 1)
595        lock_size = random.randint(1, (total_size - lock_addr))
596        spi_lock_unlock(ubman, lock_addr, lock_size)
597
598        # For entire flash
599        lock_addr = random.randint(0, total_size - 1)
600        lock_size = random.randint(1, (total_size - lock_addr))
601        spi_lock_unlock(ubman, lock_addr, lock_size)
602
603        i = i + 1
604
605@pytest.mark.buildconfigspec('cmd_bdi')
606@pytest.mark.buildconfigspec('cmd_sf')
607@pytest.mark.buildconfigspec('cmd_memory')
608def test_spi_negative(ubman):
609    ''' Negative tests for SPI '''
610    min_f, max_f, loop = spi_find_freq_range(ubman)
611    spi_pre_commands(ubman, random.randint(min_f, max_f))
612    total_size = get_total_size()
613    erase_size = get_erase_size()
614    page_size = get_page_size()
615    addr = utils.find_ram_base(ubman)
616    i = 0
617    while i < loop:
618        # Erase negative test
619        start = random.randint(0, total_size)
620        esize = erase_size
621
622        # If erasesize is not multiple of flash's erase size
623        while esize % erase_size == 0:
624            esize = random.randint(0, total_size - start)
625
626        error_msg = 'Erased: ERROR'
627        flash_ops(
628            ubman, 'erase', start, esize, 0, 1, error_msg, EXPECTED_ERASE
629        )
630
631        # If eraseoffset exceeds beyond flash size
632        eoffset = random.randint(total_size, (total_size + int(0x1000000)))
633        error_msg = 'Offset exceeds device limit'
634        flash_ops(
635            ubman, 'erase', eoffset, esize, 0, 1, error_msg, EXPECTED_ERASE
636        )
637
638        # If erasesize exceeds beyond flash size
639        esize = random.randint((total_size - start), (total_size + int(0x1000000)))
640        error_msg = 'ERROR: attempting erase past flash size'
641        flash_ops(
642            ubman, 'erase', start, esize, 0, 1, error_msg, EXPECTED_ERASE
643        )
644
645        # If erase size is 0
646        esize = 0
647        error_msg = None
648        flash_ops(
649            ubman, 'erase', start, esize, 0, 1, error_msg, EXPECTED_ERASE
650        )
651
652        # If erasesize is less than flash's page size
653        esize = random.randint(0, page_size)
654        start = random.randint(0, (total_size - page_size))
655        error_msg = 'Erased: ERROR'
656        flash_ops(
657            ubman, 'erase', start, esize, 0, 1, error_msg, EXPECTED_ERASE
658        )
659
660        # Write/Read negative test
661        # if Write/Read size exceeds beyond flash size
662        offset = random.randint(0, total_size)
663        size = random.randint((total_size - offset), (total_size + int(0x1000000)))
664        error_msg = 'Size exceeds partition or device limit'
665        flash_ops(
666            ubman, 'write', offset, size, addr, 1, error_msg, EXPECTED_WRITE
667        )
668        flash_ops(
669            ubman, 'read', offset, size, addr, 1, error_msg, EXPECTED_READ
670        )
671
672        # if Write/Read offset exceeds beyond flash size
673        offset = random.randint(total_size, (total_size + int(0x1000000)))
674        size = random.randint(0, total_size)
675        error_msg = 'Offset exceeds device limit'
676        flash_ops(
677            ubman, 'write', offset, size, addr, 1, error_msg, EXPECTED_WRITE
678        )
679        flash_ops(
680            ubman, 'read', offset, size, addr, 1, error_msg, EXPECTED_READ
681        )
682
683        # if Write/Read size is 0
684        offset = random.randint(0, 2)
685        size = 0
686        error_msg = None
687        flash_ops(
688            ubman, 'write', offset, size, addr, 1, error_msg, EXPECTED_WRITE
689        )
690        flash_ops(
691            ubman, 'read', offset, size, addr, 1, error_msg, EXPECTED_READ
692        )
693
694        # Read to relocation address
695        output = ubman.run_command('bdinfo')
696        m = re.search(r'relocaddr\s*= (.+)', output)
697        res_area = int(m.group(1), 16)
698
699        start = 0
700        size = 0x2000
701        error_msg = 'ERROR: trying to overwrite reserved memory'
702        flash_ops(
703            ubman, 'read', start, size, res_area, 1, error_msg, EXPECTED_READ
704        )
705
706        # Start reading from the reserved area
707        m = re.search(r'reserved\[0\]\s*\[(0x.+)-(0x.+)\]', output)
708        if not m or int(m.group(1), 16) == 0:
709            ubman.log.info('No reserved area is defined or start addr is 0x0!')
710        else:
711            rstart_area = int(m.group(1), 16)
712            rend_area = int(m.group(2), 16)
713
714            # Case 1: Start reading from the middle of the reserved area
715            r_size = rend_area - rstart_area
716            r_area = rstart_area + r_size
717            flash_ops(
718                ubman, 'read', start, size, r_area, 1, error_msg, EXPECTED_READ
719            )
720
721            # Case 2: Start reading from before the reserved area to cross-over
722            # the reserved area
723            rstart_area = rstart_area - int(size/2)
724            flash_ops(
725                ubman, 'read', start, size, rstart_area, 1, error_msg, EXPECTED_READ
726            )
727
728            # Case 3: Start reading till after the reserved area to cross-over
729            # the reserved area
730            rend_area = rend_area - int(size/2)
731            flash_ops(
732                ubman, 'read', start, size, rend_area, 1, error_msg, EXPECTED_READ
733            )
734
735        i = i + 1
736