1# x86 bootblock used in migration test
2#  repeatedly increments the first byte of each page in a 100MB
3#  range.
4#  Outputs an initial 'A' on serial followed by repeated 'B's
5#
6# Copyright (c) 2016 Red Hat, Inc. and/or its affiliates
7# This work is licensed under the terms of the GNU GPL, version 2 or later.
8# See the COPYING file in the top-level directory.
9#
10# Author: dgilbert@redhat.com
11
12#include "migration-test.h"
13
14#define ACPI_ENABLE         0xf1
15#define ACPI_PORT_SMI_CMD   0xb2
16#define ACPI_PM_BASE        0x600
17#define PM1A_CNT_OFFSET     4
18
19#define ACPI_SCI_ENABLE     0x0001
20#define ACPI_SLEEP_TYPE     0x0400
21#define ACPI_SLEEP_ENABLE   0x2000
22#define SLEEP (ACPI_SCI_ENABLE + ACPI_SLEEP_TYPE + ACPI_SLEEP_ENABLE)
23
24#define LOW_ADDR            X86_TEST_MEM_START
25#define HIGH_ADDR           X86_TEST_MEM_END
26
27/* Save the suspended status at an address that is not written in the loop. */
28#define suspended           (X86_TEST_MEM_START + 4)
29
30.code16
31.org 0x7c00
32        .file   "fill.s"
33        .text
34        .globl  start
35        .type   start, @function
36start:             # at 0x7c00 ?
37        cli
38        lgdt gdtdesc
39        mov $1,%eax
40        mov %eax,%cr0  # Protected mode enable
41        data32 ljmp $8,$0x7c20
42
43.org 0x7c20
44.code32
45        # A20 enable - not sure I actually need this
46        inb $0x92,%al
47        or  $2,%al
48        outb %al, $0x92
49
50        # set up DS for the whole of RAM (needed on KVM)
51        mov $16,%eax
52        mov %eax,%ds
53
54# Start from 1MB
55.set TEST_MEM_START, X86_TEST_MEM_START
56.set TEST_MEM_END, X86_TEST_MEM_END
57
58        mov $65,%ax
59        mov $0x3f8,%dx
60        outb %al,%dx
61
62        # bl keeps a counter so we limit the output speed
63        mov $0, %bl
64
65pre_zero:
66        mov $TEST_MEM_START,%eax
67do_zero:
68        movb $0, (%eax)
69        add $4096,%eax
70        cmp $TEST_MEM_END,%eax
71        jl do_zero
72
73mainloop:
74        mov $TEST_MEM_START,%eax
75innerloop:
76        incb (%eax)
77        add $4096,%eax
78        cmp $TEST_MEM_END,%eax
79        jl innerloop
80
81        inc %bl
82        andb $0x3f,%bl
83        jnz mainloop
84
85        mov $66,%ax
86        mov $0x3f8,%dx
87        outb %al,%dx
88
89        # should this test suspend?
90        mov (suspend_me),%eax
91        cmp $0,%eax
92        je mainloop
93
94        # are we waking after suspend?  do not suspend again.
95        mov $suspended,%eax
96        mov (%eax),%eax
97        cmp $1,%eax
98        je mainloop
99
100        # enable acpi
101        mov $ACPI_ENABLE,%al
102        outb %al,$ACPI_PORT_SMI_CMD
103
104        # suspend to ram
105        mov $suspended,%eax
106        movl $1,(%eax)
107        mov $SLEEP,%ax
108        mov $(ACPI_PM_BASE + PM1A_CNT_OFFSET),%dx
109        outw %ax,%dx
110        # not reached.  The wakeup causes reset and restart at 0x7c00, and we
111        # do not save and restore registers as a real kernel would do.
112
113
114        # GDT magic from old (GPLv2)  Grub startup.S
115        .p2align        2       /* force 4-byte alignment */
116gdt:
117        .word   0, 0
118        .byte   0, 0, 0, 0
119
120        /* -- code segment --
121         * base = 0x00000000, limit = 0xFFFFF (4 KiB Granularity), present
122         * type = 32bit code execute/read, DPL = 0
123         */
124        .word   0xFFFF, 0
125        .byte   0, 0x9A, 0xCF, 0
126
127        /* -- data segment --
128         * base = 0x00000000, limit 0xFFFFF (4 KiB Granularity), present
129         * type = 32 bit data read/write, DPL = 0
130         */
131        .word   0xFFFF, 0
132        .byte   0, 0x92, 0xCF, 0
133
134gdtdesc:
135        .word   0x27                    /* limit */
136        .long   gdt                     /* addr */
137
138        /* test launcher can poke a 1 here to exercise suspend */
139suspend_me:
140        .int  0
141
142/* I'm a bootable disk */
143.org 0x7dfe
144        .byte 0x55
145        .byte 0xAA
146