├── .gitignore
├── CHANGELOG
├── LICENSE
├── README.md
├── bochs-debug-cmds
├── cc
├── .gitignore
├── a20.lisp
├── abi.lisp
├── address.asm
├── arith.asm
├── bga.lisp
├── bitmap.lisp
├── bochs.lisp
├── bootloader.lisp
├── cc.asd
├── config.lisp
├── kernel.lisp
├── keyboard.lisp
├── lap.lisp
├── lnasdf
├── memory.lisp
├── misc.asm
├── nasm.lisp
├── package.lisp
├── paging.lisp
├── test-cc.lisp
├── test.lisp
├── unit-test.lisp
├── util.lisp
├── vga-text.lisp
└── x86-64-syntax.lisp
├── debug-qemu
├── debug-virtualbox
├── doc
├── AssemblyX64.md
├── AssemblyX64A.md
├── AssemblyX64Arith.md
├── AssemblyX64B.md
├── AssemblyX64Bit.md
├── AssemblyX64C.md
├── AssemblyX64D.md
├── AssemblyX64E.md
├── AssemblyX64F.md
├── AssemblyX64H.md
├── AssemblyX64I.md
├── AssemblyX64J.md
├── AssemblyX64L.md
├── AssemblyX64M.md
├── AssemblyX64N.md
├── AssemblyX64O.md
├── AssemblyX64P.md
├── AssemblyX64R.md
├── AssemblyX64S.md
├── AssemblyX64T.md
├── AssemblyX64U.md
├── AssemblyX64V.md
├── AssemblyX64W.md
├── AssemblyX64X.md
└── CrossCompilation.md
├── run-bochs
├── run-qemu
├── run-virtualbox
├── scripts
└── build-bochs
└── write-kernel-sbcl
/.gitignore:
--------------------------------------------------------------------------------
1 | *.img
2 |
--------------------------------------------------------------------------------
/CHANGELOG:
--------------------------------------------------------------------------------
1 | Changelog of yalo
2 |
3 | v0.0.1
4 | - Initial release.
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 | {description}
294 | Copyright (C) {year} {fullname}
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | {signature of Ty Coon}, 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Yalo
2 | ====
3 |
4 | # Target
5 |
6 | Yalo is a Lisp OS running on bare metal x86-64 hardware. The system
7 | programming language is **Ink**, a new Lisp dialect which combines the
8 | elegance of Scheme and powerfulness of Common Lisp. The project webpage
9 | is:
10 |
11 | # Status
12 |
13 | The project is only at very very initial stage, with an
14 | [assembler](https://github.com/whily/yalo/blob/master/doc/AssemblyX64.md)
15 | written in Common Lisp, and a 64 bit bootloader.
16 |
17 | "Short term" plan:
18 |
19 | - [x] VGA text mode without using BIOS.
20 | - [x] Keyboard handling without using BIOS.
21 | - [x] Switch to 32 bit protected mode.
22 | - [x] Switch to 64 bit long mode.
23 | - [ ] Physical/virtual memory management.
24 | - [ ] Userland and system call.
25 | - [ ] Implement Ink interpreter with assembly.
26 | - [ ] Self hosting a more powerful Ink interpreter with Ink itself.
27 |
28 | # Getting Started
29 |
30 | ## Getting Bootable Image
31 |
32 | Currently, cross compilation is needed to build one floppy image
33 | containing yalo.
34 |
35 | ### [Cross compilation](https://github.com/whily/yalo/blob/master/doc/CrossCompilation.md)
36 |
37 | Although yalo should compile on any Ansi Common Lisp implementation,
38 | it is only tested on SBCL and Clozure CL (aka CCL).
39 |
40 | Mandatory Requirements:
41 | * [SBCL](http://sbcl.sourceforge.net SBCL) or [CCL](https://ccl.clozure.com/)
42 | * git
43 |
44 | Optional Requirements:
45 | * Emacs
46 | * SLIME
47 |
48 | #### Getting Source Code
49 |
50 | Run following command to anonymously checkout the latest source code
51 | of yalo.
52 |
53 | ```shell
54 | $ git clone https://github.com/whily/yalo.git
55 | ```
56 |
57 | #### Setup link for ASDF
58 |
59 | Run following commands to make SBCL/CCL aware of the ASDF file for the
60 | cross compiler. Note that one only needs to run the script once.
61 |
62 | ```shell
63 | $ cd yalo/cc
64 | $ ./lnasdf
65 | ```
66 |
67 | #### Build Floppy Image
68 |
69 | ##### With SBCL or CCL alone
70 |
71 | For SBCL, in the root directory of the project (e.g. directory
72 | `yalo`), run script `write-kernel-sbcl`. Afterwards,`floppy.img` is
73 | written directly to the same directory, where scripts to run the image
74 | (e.g. `run-bochs`) are located. It should be noted that it is assumed
75 | that `sbcl` executable is installed in directory `/usr/bin`. Otherwise
76 | modify script `write-kernel-sbcl` accordingly.
77 |
78 | For CCL, in the root directory of the project, type the following at
79 | REPL to generate `floppy.img`:
80 |
81 | ```lisp
82 | (require 'asdf)
83 | (asdf:oos 'asdf:load-op 'cc)
84 | (in-package :cc)
85 | (write-kernel "../floppy.img")
86 | ```
87 |
88 | One may type `(ccl:quit)` to exit from CCL.
89 |
90 | ##### With Emacs+SLIME
91 |
92 | Inside Emacs,
93 |
94 | 1. First type `M-x slime` if SLIME is not started.
95 | 2. Type `M-x slime-load-system` then type `cc` when prompted for the
96 | system.
97 | 3. At REPL, type `(in-package :cc)` to switch to package *cc*
98 | (alternatively, one can user keyboard shortcut `C-x M-p` and then type `cc`).
99 | 4. Type `(write-kernel "../floppy.img")` at SLIME REPL to generate the kernel.
100 | Here we assume that current directory is `cc` of the source tree, therefore
101 | `floppy.img` is written directly to the source tree, where scripts to run the
102 | image (e.g. `run-bochs`) are located.
103 |
104 | Above is applicable for both SBCL and CCL, assuming SLIME is
105 | configured properly for the CL implementation(s).
106 |
107 | ## Run Image
108 |
109 | There are various ways to run the image.
110 |
111 | ### Bochs
112 |
113 | Go to the root directory of the source code, where script `run-bochs`
114 | is located. Run the scripts and select *6* to proceed emulation. After
115 | invoking `run-bochs`, select *6*, emulation starts directly.
116 |
117 | On HiDPI screens, the font of Bochs is too small to see. Therefore in
118 | script `run-bochs`, there is one line related
119 | to using SDL2 (make sure the library is installed) as display library
120 | and starts the emulator in fullscreen mode, as below:
121 |
122 | ```
123 | 'display_library: sdl2, options="fullscreen,gui_debug"'
124 | ```
125 |
126 | Bochs header bar is not visible in full screen mode. Therefore one
127 | needs to press `Ctrl+Alt+q` to shutdown Yalo to quit emulator.
128 | Alternatively, one can modify the script files (e.g. removing
129 | `fullscreen` option or deleting the line containing `display_library`
130 | completely).
131 |
132 | In addition, `scripts/build-boch` is the script the author used to
133 | compile a customized Bochs.
134 |
135 | Note that on Ubuntu (at least in 16.10), package `bochs-x` should be
136 | installed in addition to package `bochs`.
137 |
138 | ### QEMU
139 |
140 | Similar to Bochs, go to the root directory of the source code, where
141 | script `run-qemu` and `debug-qemu` are located.
142 |
143 | In both `run-qemu` and `debug-qemu`, QEMU monitor is redirectted to
144 | stdio (via argument `-monitor stdio`). Script `run-qemu` will start
145 | the emulator without GDB support; while `debug-qemu` enables GDB
146 | support: `-s` argument makes QEMU listens to port 1234 for GDB, while
147 | `-S` argument makes QEMU pauses at the beginning for GDB's `continue`
148 | command. After running `debug-qemu` and starting GDB, first type
149 | `target remote :1234` to connect to QEMU, then type command `continue`
150 | to resume the emulation.
151 |
152 | ### VirtualBox
153 |
154 | In the **Storage** page of the virtual machine settings, right click
155 | and select "Add Floppy Controller". And the select the image file
156 | `floppy.img` for floppy drive. In the **System** page of virtual
157 | machine settings, make sure that Floppy is checked for Boot order.
158 |
159 | Assuming the VM name is `yalo`, go to the root directory of the source
160 | code, where script `run-virtualbox` and `debug-virtualbox` are
161 | located. Run script `run-virtualbox` to start the emulator, or script
162 | `debug-virtualbox` to start the emulator with debug window.
163 |
164 | ## Software version
165 |
166 | So far, the development is done on Arch Linux. For above-mentioned
167 | software, the corresponding version is listed below:
168 |
169 | * SBCL: 1.4.10 or CCL 1.12
170 | * Emacs: 26.1
171 | * SLIME: 2.22
172 | * Bochs: 2.6.9
173 | * QEMU: 3.0.0
174 | * VirtualBox: 5.2.18
175 |
--------------------------------------------------------------------------------
/bochs-debug-cmds:
--------------------------------------------------------------------------------
1 | continue
2 |
--------------------------------------------------------------------------------
/cc/.gitignore:
--------------------------------------------------------------------------------
1 | *.fasl
2 |
--------------------------------------------------------------------------------
/cc/a20.lisp:
--------------------------------------------------------------------------------
1 | ;;;; -*- Mode: Lisp -*-
2 | ;;;; Author:
3 | ;;;; Yujian Zhang
4 | ;;;; Description:
5 | ;;;; A20 address line related functions.
6 | ;;;; License:
7 | ;;;; GNU General Public License v2
8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html
9 | ;;;; Copyright (C) 2015 Yujian Zhang
10 |
11 | (in-package :cc)
12 |
13 | (defparameter *a20*
14 | `(
15 | ;;; Enable A20 address line based on:
16 | ;;; http://www.independent-software.com/writing-your-own-toy-operating-system-enabling-the-a20-line/
17 | ;;; Input: None
18 | ;;; Output: None
19 | ;;; Modified registers: AL, BL, CL
20 | enable-a20
21 | (call check-a20)
22 | (cmp ax 0)
23 | (jne .done)
24 |
25 | ;; Enable A20 based on BIOS
26 | (mov ax #x2401)
27 | (int #x15)
28 |
29 | (call check-a20)
30 | (cmp ax 0)
31 | (jne .done)
32 |
33 | ;; Enable A20 based on keyboard controller.
34 | (mov al kbd-ctrl-cmd-disable-keyboard)
35 | (call kbd-ctrl-send-cmd-16)
36 | (mov al kbd-ctrl-cmd-read-output-port)
37 | (call kbd-ctrl-send-cmd-16)
38 | (call wait-kbd-out-buf-16)
39 | (in al kbd-encoder-buf)
40 | (mov cl al) ; Save AL
41 | (mov al kbd-ctrl-cmd-write-output-port)
42 | (call kbd-ctrl-send-cmd-16)
43 | (mov al cl) ; Restore AL
44 | (or al 2) ; Enable A20 by set bit 1 to 1.
45 | (call kbd-encoder-send-cmd-16)
46 | (mov al kbd-ctrl-cmd-enable-keyboard)
47 | (call kbd-ctrl-send-cmd-16)
48 | (call wait-kbd-in-buf-16)
49 |
50 | (call check-a20)
51 | (cmp ax 0)
52 | (jne .done)
53 |
54 | ;; Enable A20 based on fast gate method.
55 | (in al #x92)
56 | (or al 2)
57 | (out #x92 al)
58 |
59 | (call check-a20)
60 | (cmp ax 0)
61 | (jne .done)
62 |
63 | .fail
64 | (mov si .a20-error-message)
65 | (call println-16)
66 | .panic
67 | (hlt)
68 | (jmp short .panic)
69 | .a20-error-message (db "ERROR: A20 address line cannot be enabled." 0)
70 |
71 | .done
72 | (ret)
73 |
74 | ;;; Check whether A20 is enabled or not.
75 | ;;; Input: None
76 | ;;; Output: AX=1 if A20 is enabled; AX=0 otherwise.
77 | ;;; The function writes different values to two addresses:
78 | ;;; 0000:0500 and ffff:0510. If A20 is not enabled, the two
79 | ;;; addresses are equivalent due to wrap around.
80 | ;;; This functions restores registers and states modified in the call.
81 | check-a20
82 | ;; Save flags and registers.
83 | (pushf)
84 | (push ds)
85 | (push es)
86 | (push di)
87 | (push si)
88 | ;; Set es:di = 0000:0500
89 | (xor ax ax)
90 | (mov es ax)
91 | (mov di #x500)
92 | ;; Set ds:si = ffff:0510
93 | (mov ax #xffff)
94 | (mov ds ax)
95 | (mov si #x510)
96 | ;; Save byte at es:di on stack.
97 | (es mov al (di))
98 | (push ax)
99 | ;; Save byte at ds:si on stack.
100 | (ds mov al (si))
101 | (push ax)
102 | (es mov byte (di), #x00) ; [es:di] = #x00
103 | (ds mov byte (si), #xff) ; [ds:si] = #xff
104 | (es cmp byte (di), #xff) ; Check memory wrap around.
105 | ;; Restore byte at ds:si
106 | (pop ax)
107 | (ds mov (si) al)
108 | ;; Restore byte at es:di
109 | (pop ax)
110 | (es mov (di) al)
111 | (mov ax 0)
112 | (je .exit) ; If A20 is disabled, return 0.
113 | (mov ax 1) ; Else, return 1
114 | .exit
115 | (pop si)
116 | (pop di)
117 | (pop es)
118 | (pop ds)
119 | (popf)
120 | (ret)
121 | ))
122 |
--------------------------------------------------------------------------------
/cc/abi.lisp:
--------------------------------------------------------------------------------
1 | ;;;; -*- Mode: Lisp -*-
2 | ;;;; Author:
3 | ;;;; Yujian Zhang
4 | ;;;; Description:
5 | ;;;; x86-64 calling convention based on System V AMD64 ABI.
6 | ;;;;
7 | ;;;; Summary in
8 | ;;;; https://en.wikipedia.org/wiki/X86_calling_conventions#System_V_AMD64_ABI
9 | ;;;; Basically, the first 6 integer or pointer arguments are
10 | ;;;; passed in RDI, RSI, RDX, RCX, R8, and R9, and rest are pushed
11 | ;;;; on stack. Return values are stored in RAX, and RDX if needed.
12 | ;;;; If callees wants to use RBX, RBP, and R12-R15, it must
13 | ;;;; restore their original values before returning control to the
14 | ;;;; caller. All other registers must be saved by the caller if it
15 | ;;;; wishes to preserve their values.
16 | ;;;;
17 | ;;;; References:
18 | ;;;; [1] https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0.pdf
19 | ;;;; License:
20 | ;;;; GNU General Public License v2
21 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html
22 | ;;;; Copyright (C) 2015-2018 Yujian Zhang
23 |
24 | (in-package :cc)
25 |
26 | (defun call-function (function-name &optional saved-registers)
27 | "Used by the caller. The function adds push and pops around function
28 | calling automatically. It is assumed that RSP is aligned on 16 byte
29 | boundary before calling. if the number of `saved-registers` is odd,
30 | one more push/pop is added to ensure that RSP is aligned on 16 byte
31 | boundaring before calling the function."
32 | (let ((saved-registers* (if (oddp (length saved-registers))
33 | (push (car saved-registers) saved-registers)
34 | saved-registers)))
35 | `(,@(mapcar #'(lambda (reg) (list 'push reg)) saved-registers*)
36 | (call ,function-name)
37 | ,@(mapcar #'(lambda (reg) (list 'pop reg)) (reverse saved-registers*)))))
38 |
39 | (defun def-fun (function-name saved-registers body)
40 | "Define a function following System V ABI.
41 | * saved-registers: a set of registers to be preserved, a subset
42 | of (rbx rsp rbp r12 r13 r14 r15). TODO: automatically detect
43 | which registers to save.
44 |
45 | This function automatically detect whether the function is a leaf
46 | function (which does not call other functions) or not. For a
47 | non-leaf function, stack frames are saved via rbp; while such
48 | additional operation is not done for leaf functions.
49 |
50 | Note that 128 byte red zone is not used."
51 | (when (and saved-registers
52 | (notevery #'(lambda (x) (member x '(rbx rsp rbp r12 r13 r14 r15))) saved-registers))
53 | (error "def-fun: trying to save registers not in set (rbx rsp rbp r12 r13 r14 r15)."))
54 | (let* ((leaf? (notany #'(lambda (x) (and (listp x) (eq (car x) 'call))) body))
55 | (prologue (unless leaf?
56 | '((push rbp)
57 | (mov rbp rsp))))
58 | (epilogue (unless leaf?
59 | '((leave))))
60 | )
61 | `(,function-name
62 | ,@prologue
63 | ,@(mapcar #'(lambda (reg) (list 'push reg)) saved-registers)
64 | ,@body
65 | ,@(mapcar #'(lambda (reg) (list 'pop reg)) (reverse saved-registers))
66 | ,@epilogue
67 | (ret)
68 | )))
69 |
70 | (deftest test-abi ()
71 | (check
72 | (equal (call-function 'read '(r10))
73 | '((push r10)
74 | (push r10)
75 | (call read)
76 | (pop r10)
77 | (pop r10)))
78 | (equal (call-function 'write '(r10 r11))
79 | '((push r10)
80 | (push r11)
81 | (call write)
82 | (pop r11)
83 | (pop r10)))
84 | (equal (def-fun 'read '(r12) '((xor eax eax)))
85 | '(read
86 | (push r12)
87 | (xor eax eax)
88 | (pop r12)
89 | (ret)))
90 | (equal (def-fun 'write '(r12 r13) '((move rdi 42)
91 | (call universe)))
92 | '(write
93 | (push rbp)
94 | (mov rbp rsp)
95 | (push r12)
96 | (push r13)
97 | (move rdi 42)
98 | (call universe)
99 | (pop r13)
100 | (pop r12)
101 | (leave)
102 | (ret)))))
103 |
--------------------------------------------------------------------------------
/cc/address.asm:
--------------------------------------------------------------------------------
1 | ;; NASM code for cross check the assembly output from test-cc.lisp.
2 | ;; The test is performed as follows:
3 | ;; 1. Run NASM with: /usr/local/bin/nasm -o address.img address.asm
4 | ;; 2. In CL REPL, compare the output with (equal (read-image "address.img") (asm *address-asm*))
5 | ;; Note that above nasm command assumes the usage of nasm installed from brew.
6 |
7 | org 7C00h
8 |
9 | bits 16
10 | mov [bp], es
11 | mov [bx+si], ds
12 | mov [bx+di], es
13 | mov [bp+si], ds
14 | mov [bp+di], ss
15 | mov [si], ds
16 | mov [di], cs
17 | mov [32330], ds
18 | mov [msg], ds
19 | mov [bx], cs
20 | mov [bx+si+1], ds
21 | mov [bx+di+2], es
22 | mov [bp+si+3], ds
23 | mov [bp+di+4], ss
24 | mov [si+5], ds
25 | mov [di+6], cs
26 | mov [bp+7], ds
27 | mov [bx+8], cs
28 | mov ds, [di]
29 | mov ds, [bx+si+1001]
30 | mov es, [bx+di+1002]
31 | mov ds, [bp+si+1003]
32 | mov ss, [bp+di+1004]
33 | mov ds, [si+1005]
34 | mov es, [di+1006]
35 | mov ds, [bp+1007]
36 | mov es, [bx+1008]
37 |
38 | bits 32
39 | mov [ebp], ebx
40 | mov [esp], ecx
41 | mov [123456], edx
42 | mov [eax], edx
43 | mov [ebp+36], ecx
44 | mov [edi+1234], edx
45 | mov [esi+123456], ecx
46 | mov [esp+23h], ebx
47 | mov [esp+12345678h], ecx
48 | mov [eax+ebx], ecx
49 | mov [esi+edi], edx
50 | mov [esi+ebp], edx
51 | mov [eax*2+esi], edx
52 | mov [esi*2+ebp+123], edx
53 | mov [edi*2+ebx+8], ecx
54 | mov [ecx*4+ebp+123], edx
55 | mov [esi*4+edx+8], ecx
56 | mov [edx*8+ebp+123456], ebx
57 | mov [edi*8+ecx+8], edx
58 |
59 | bits 64
60 | mov [rbp], rbx
61 | mov [rsp], rcx
62 | mov [123456], rdx
63 | mov [rax], rdx
64 | mov [rbp+36], rcx
65 | mov [rdi+1234], rdx
66 | mov [rsi+123456], rcx
67 | mov [rsp+23h], rbx
68 | mov [rsp+12345678h], rcx
69 | mov [rax+rbx], rcx
70 | mov [rsi+rdi], rdx
71 | mov [rsi+rbp], rdx
72 | mov [rax*2+rsi], rdx
73 | mov [rsi*2+rbp+123], rdx
74 | mov [rdi*2+rbx+8], rcx
75 | mov [rcx*4+rbp+123], rdx
76 | mov [rsi*4+rdx+8], rcx
77 | mov [rdx*8+rbp+123456], rbx
78 | mov [rdi*8+rcx+8], rdx
79 | msg:
80 | db "Hello World! "
81 | endmsg:
82 |
--------------------------------------------------------------------------------
/cc/arith.asm:
--------------------------------------------------------------------------------
1 | ;; NASM code for cross check the assembly output from test-cc.lisp.
2 | ;; The test is performed as follows:
3 | ;; 1. Run NASM with: /usr/local/bin/nasm -o arith.img arith.asm
4 | ;; 2. In CL REPL, compare the output with (equal (read-image "arith.img") (asm *arith-asm*))
5 | ;; Note that above nasm command assumes the usage of nasm installed from brew.
6 |
7 | org 7C00h
8 | bits 16
9 |
10 | add al, 8
11 | add ax, 1000
12 | add bl, 3
13 | add byte [msg], 4
14 | add bx, 1234
15 | add word [msg], 5678
16 | add cx, byte 9
17 | add word [msg], byte 12
18 | add al, bl
19 | add [msg], ch
20 | add cx, bx
21 | add word [msg], dx
22 | add ch, byte [msg]
23 | add dx, word [msg]
24 | and al, 8
25 | and ax, 1000
26 | and bl, 3
27 | and byte [msg], 4
28 | and bx, 1234
29 | and word [msg], 5678
30 | and cx, byte 9
31 | and word [msg], byte 12
32 | and al, bl
33 | and [msg], ch
34 | and cx, bx
35 | and word [msg], dx
36 | and ch, byte [msg]
37 | and dx, word [msg]
38 | cmp al, 8
39 | cmp ax, 1000
40 | cmp bl, 3
41 | cmp byte [msg], 4
42 | cmp bx, 1234
43 | cmp word [msg], 5678
44 | cmp cx, byte 9
45 | cmp word [msg], byte 12
46 | cmp al, bl
47 | cmp [msg], ch
48 | cmp cx, bx
49 | cmp word [msg], dx
50 | cmp ch, byte [msg]
51 | cmp dx, word [msg]
52 | dec bx
53 | dec eax
54 | dec dl
55 | dec byte [msg]
56 | dec word [bp+si+3]
57 | dec dword [msg]
58 | div ch
59 | div byte [msg]
60 | div di
61 | div word [bp+si+3]
62 | inc bx
63 | inc eax
64 | inc dl
65 | inc byte [msg]
66 | inc word [bp+si+3]
67 | inc dword [msg]
68 | mul ch
69 | mul byte [msg]
70 | mul di
71 | mul word [bp+si+3]
72 | neg ch
73 | neg byte [msg]
74 | neg di
75 | neg word [bp+si+3]
76 | not ch
77 | not byte [msg]
78 | not di
79 | not word [bp+si+3]
80 | or al, 8
81 | or ax, 1000
82 | or bl, 3
83 | or byte [msg], 4
84 | or bx, 1234
85 | or word [msg], 5678
86 | or cx, byte 9
87 | or word [msg], byte 12
88 | or al, bl
89 | or [msg], ch
90 | or cx, bx
91 | or word [msg], dx
92 | or ch, byte [msg]
93 | or dx, word [msg]
94 | shl dh, 1
95 | shl byte [msg], 1
96 | shl dh, cl
97 | shl byte [msg], cl
98 | shl dh, 5
99 | shl byte [msg], 5
100 | shl dx, 1
101 | shl word [msg], 1
102 | shl dx, cl
103 | shl word [msg], cl
104 | shl dx, 5
105 | shl word [msg], 5
106 | shr dh, 1
107 | shr byte [msg], 1
108 | shr dh, cl
109 | shr byte [msg], cl
110 | shr dh, 5
111 | shr byte [msg], 5
112 | shr dx, 1
113 | shr word [msg], 1
114 | shr dx, cl
115 | shr word [msg], cl
116 | shr dx, 5
117 | shr word [msg], 5
118 | sub al, 8
119 | sub ax, 1000
120 | sub bl, 3
121 | sub byte [msg], 4
122 | sub bx, 1234
123 | sub word [msg], 5678
124 | sub cx, byte 9
125 | sub word [msg], byte 12
126 | sub al, bl
127 | sub [msg], ch
128 | sub cx, bx
129 | sub word [msg], dx
130 | sub ch, byte [msg]
131 | sub dx, word [msg]
132 | test al, 8
133 | test ax, 1000
134 | test bl, 3
135 | test byte [msg], 4
136 | test bx, 1234
137 | test word [msg], 5678
138 | test al, bl
139 | test [msg], ch
140 | test cx, bx
141 | test word [msg], dx
142 | xor al, 8
143 | xor ax, 1000
144 | xor bl, 3
145 | xor byte [msg], 4
146 | xor bx, 1234
147 | xor word [msg], 5678
148 | xor cx, byte 9
149 | xor word [msg], byte 12
150 | xor al, bl
151 | xor [msg], ch
152 | xor cx, bx
153 | xor word [msg], dx
154 | xor ch, byte [msg]
155 | xor dx, word [msg]
156 |
157 | [bits 32]
158 |
159 | add ax, 1000
160 | dec dx
161 | dec ebp
162 | inc dx
163 | inc ebp
164 |
165 | [bits 64]
166 |
167 | adc rax, 12345h
168 | add ebx, 1000
169 | add rax, 10010203h
170 | ; add rax, 10
171 | add rbx, 267
172 | add r15, 123456h
173 | add r10d, byte 3
174 | add sil, 6
175 | add r9b, 8
176 | add r10, rbx
177 | add rsi, [rbx]
178 | dec di
179 | dec ecx
180 | dec r10
181 | div ebx
182 | inc di
183 | inc ecx
184 | inc r10
185 | mul dword [rbx]
186 | neg rcx
187 | not qword [rbx]
188 | sbb rbx, rdx
189 | test rax, 123456789
190 | test r12, 11223344
191 | test qword [rdi], 9966
192 | test rdx, rdi
193 | test qword [rdx], r9
194 |
195 | msg:
196 | db "Hello World! "
197 | endmsg:
198 |
--------------------------------------------------------------------------------
/cc/bga.lisp:
--------------------------------------------------------------------------------
1 | ;;;; -*- Mode: Lisp -*-
2 | ;;;; Author:
3 | ;;;; Yujian Zhang
4 | ;;;; Description:
5 | ;;;; Bochs VBE Extensions, see http://wiki.osdev.org/BGA
6 | ;;;; License:
7 | ;;;; GNU General Public License v2
8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html
9 | ;;;; Copyright (C) 2012 Yujian Zhang
10 |
11 | (in-package :cc)
12 |
13 | (defparameter *bga*
14 | `(
15 | ;;; BGA constants
16 | (equ vbe-dispi-ioport-index #x1ce)
17 | (equ vbe-dispi-ioport-data #x1cf)
18 | (equ vbe-dispi-index-id 0)
19 | (equ vbe-dispi-index-xres 1)
20 | (equ vbe-dispi-index-yres 2)
21 | (equ vbe-dispi-index-bpp 3)
22 | (equ vbe-dispi-index-enable 4)
23 | (equ vbe-dispi-index-bank 5)
24 | (equ vbe-dispi-index-virt-width 6)
25 | (equ vbe-dispi-index-virt-height 7)
26 | (equ vbe-dispi-index-x-offset 8)
27 | (equ vbe-dispi-index-y-offset 9)
28 | ;; It seems that VirtualBox only supports BGA up to #xb0c4. See
29 | ;; http://www.virtualbox.org/svn/vbox/trunk/src/VBox/Devices/Graphics/BIOS/vbe_display_api.txt
30 | (equ vbe-dispi-id2 #xb0c2)
31 | (equ vbe-dispi-id4 #xb0c4)
32 | (equ vbe-dispi-id5 #xb0c5)
33 | (equ vbe-dispi-bpp-32 #x20)
34 | (equ vbe-dispi-enabled 1)
35 | (equ vbe-dispi-disabled 0)
36 |
37 | ;;; Write index/data to one BGA register.
38 | ;;; Input:
39 | ;;; AL: index value
40 | ;;; BX: data value
41 | ;;; Output: None
42 | ;;; Modified registers: DX
43 | bga-write-register
44 | (mov dx vbe-dispi-ioport-index)
45 | (out dx al)
46 | (mov dx vbe-dispi-ioport-data)
47 | (mov ax bx)
48 | (out dx ax)
49 | (ret)
50 |
51 | ;;; Read BGA register.
52 | ;;; Input:
53 | ;;; AL: index value
54 | ;;; Output: in AX
55 | ;;; Modified registers: DX
56 | bga-read-register
57 | (mov dx vbe-dispi-ioport-index)
58 | (out dx al)
59 | (mov dx vbe-dispi-ioport-data)
60 | (in ax dx)
61 | (ret)
62 |
63 | ;;; Check whether BGA is available.
64 | ;;; Input: None
65 | ;;; Output: CF is set if BGA is unavailable.
66 | bga-available
67 | (clc)
68 | (mov al vbe-dispi-index-id)
69 | (call bga-read-register)
70 | (cmp ax vbe-dispi-id2)
71 | (jb no-bga)
72 | (ret)
73 | no-bga
74 | (stc)
75 | (ret)
76 |
77 | ;;; Set BGA mode.
78 | set-bga-mode
79 | (mov al vbe-dispi-index-enable)
80 | (mov bx vbe-dispi-disabled)
81 | (call bga-write-register)
82 | (mov al vbe-dispi-index-xres)
83 | (mov bx 800)
84 | (call bga-write-register)
85 | (mov al vbe-dispi-index-yres)
86 | (mov bx 600)
87 | (call bga-write-register)
88 | (mov al vbe-dispi-index-bpp)
89 | (mov bx vbe-dispi-bpp-32)
90 | (call bga-write-register)
91 | (mov al vbe-dispi-index-enable)
92 | (mov bx vbe-dispi-enabled)
93 | (call bga-write-register)
94 | (ret)))
95 |
--------------------------------------------------------------------------------
/cc/bitmap.lisp:
--------------------------------------------------------------------------------
1 | ;;;; -*- Mode: Lisp -*-
2 | ;;;; Author:
3 | ;;;; Yujian Zhang
4 | ;;;; Description:
5 | ;;;; Bitmap functions.
6 | ;;;; License:
7 | ;;;; GNU General Public License v2
8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html
9 | ;;;; Copyright (C) 2015 Yujian Zhang
10 |
11 | (in-package :cc)
12 |
13 | (defparameter *bitmap-prologue*
14 | `(;;; Bounds check.
15 | (cmp rsi (rdi))
16 | (jb .continue)
17 | (mov rsi bitmap-overflow-message)
18 | ,@(call-function 'panic)
19 | .continue))
20 |
21 | (defparameter *bitmap*
22 | `(
23 | ;;; Bitmap consists of a stream of bytes, representing a bit array.
24 | ;;; The first qword stores the size (in bits) of the bitmap.
25 | ;;; We assume the multiples of qwords are reserved to storet the bitmap.
26 | ;;;
27 | ;;; Typically functions have two input parameters:
28 | ;;; start-address: the starting address of the bitmap.
29 | ;;; bit-position: the bit position in the bit array, starting from 0.
30 |
31 | ;; The offset starting from which where actual bitmap is stored.
32 | (equ bitmap-offset 8)
33 | ;; Divide by 64 to get qword offset
34 | (equ bitmap-shift 6)
35 | ;; Mask to get the bit index within the qword.
36 | (equ bitmap-mask (1- (expt 2 bitmap-shift)))
37 |
38 | ;;; Function bitmap-init. Initialize the bitmap.
39 | ;;; Perform the following:
40 | ;;; 1) Set the size field.
41 | ;;; 2) Initialize all bits to 0.
42 | ;;; We assume multiples of qwords are reserved to store the bitmap.
43 | ;;; This has the benefit that we have sentinel element for bitmap-scan
44 | ;;; if the bitmap size is not the multiple of 64 (qword).
45 | ;;; Input:
46 | ;;; RDI: start-address, there is no requirement that it should be qword aligned.
47 | ;;; RSI: size in bits
48 | ,@(def-fun 'bitmap-init nil
49 | `(
50 | (mov (rdi) rsi)
51 | (add rdi bitmap-offset)
52 | (mov rcx rsi)
53 | (add rcx bitmap-mask)
54 | (shr rcx bitmap-shift) ; RCX now is: ceil(rsi / 64)
55 | (xor eax eax)
56 | (cld)
57 | (rep stosq)))
58 |
59 | ;;; Function bitmap-set. Set the bit (i.e. to 1).
60 | ;;; Input:
61 | ;;; RDI: start-address.
62 | ;;; RSI: bit-position.
63 | ,@(def-fun 'bitmap-set nil
64 | `(
65 | ,@*bitmap-prologue*
66 | (mov rdx rsi) ; RDX: qword offset
67 | (shr rdx bitmap-shift)
68 | (and esi bitmap-mask)
69 | (bts (rdx*8 rdi bitmap-offset) rsi)))
70 |
71 | ;;; Function bitmap-unset. Unset the bit (i.e. to 0).
72 | ;;; Input:
73 | ;;; RDI: start-address.
74 | ;;; RSI: bit-position.
75 | ,@(def-fun 'bitmap-unset nil `(
76 | ,@*bitmap-prologue*
77 | (mov rdx rsi) ; RDX: qword offset
78 | (shr rdx bitmap-shift)
79 | (and esi bitmap-mask)
80 | (btr (rdx*8 rdi bitmap-offset) rsi)))
81 |
82 | ;;; Function bitmap-test. Returns corresponding bit in RDX.
83 | ;;; Input:
84 | ;;; RDI: start-address.
85 | ;;; RSI: bit-position.
86 | ;;; Output:
87 | ;;; RAX: bit value
88 | ,@(def-fun 'bitmap-test nil
89 | `(
90 | ,@*bitmap-prologue*
91 | (xor eax eax) ; Prepare
92 | (mov ecx 1) ; returning results.
93 | (mov rdx rsi) ; RDX: qword offset
94 | (shr rdx bitmap-shift)
95 | (and esi bitmap-mask)
96 | (bt (rdx*8 rdi bitmap-offset) rsi)
97 | (cmovc rax rcx)))
98 |
99 | ;;; Function bitmap-scan. Returns the index of the 1st bit which is 0.
100 | ;;; If every bit is 1, return -1.
101 | ;;; Input:
102 | ;;; RDI: start-address
103 | ;;; Output:
104 | ;;; RAX: corresponding index
105 | ,@(def-fun 'bitmap-scan nil
106 | `(
107 | (mov rcx (rdi))
108 | (add rcx bitmap-mask) ; Scan ceil((rdi) / 64)
109 | (shr rcx bitmap-shift)
110 | (xor edx edx)
111 | .start
112 | (mov r8 (rdx*8 rdi bitmap-offset))
113 | (not r8)
114 | (bsf r9 r8)
115 | (jnz .scan-complete)
116 | ;; All zero means that the original qword contains all 1 (we use "NOT" instruction).
117 | (inc rdx)
118 | (loop .start)
119 | (jmp short .not-found)
120 | .scan-complete
121 | (mov rax rdx)
122 | (shl rax bitmap-shift)
123 | (add rax r9) ; RAX is now the index.
124 | (cmp rax (rdi))
125 | (jb .done)
126 | .not-found
127 | (mov rax -1)
128 | .done
129 | ))
130 |
131 | ;;; Function bitmap-count-1. Returns the count of 1 in the bitmap.
132 | ;;; Input:
133 | ;;; RDI: start-address
134 | ;;; Output:
135 | ;;; RAX: count of 1.
136 | ,@(def-fun 'bitmap-count-1 nil
137 | `(
138 | (mov rcx (rdi))
139 | (add rcx bitmap-mask) ; Scan ceil((rdi) / 64)
140 | (shr rcx bitmap-shift)
141 | (xor eax eax) ; RAX: count of 1
142 | (xor edx edx) ; RDX: index to the qword element
143 | .start
144 | (popcnt r8 (rdx*8 rdi bitmap-offset))
145 | (add rax r8)
146 | (inc rdx)
147 | (loop .start)))
148 |
149 | ;;; Function bitmap-count-0. Returns the count of 0 in the bitmap.
150 | ;;; Input:
151 | ;;; RDI: start-address
152 | ;;; Output:
153 | ;;; RAX: count of 0.
154 | ,@(def-fun 'bitmap-count-0 nil
155 | `(
156 | ,@(call-function 'bitmap-count-1)
157 | (neg rax)
158 | (add rax (rdi))))
159 |
160 | ;;; Bitmap regression test.
161 | ,@(regression-container
162 | (def-fun 'bitmap-regression nil
163 | `(
164 | (equ bitmap-regression-addr #xffffffff80400000)
165 | (mov rdi bitmap-regression-addr)
166 | (mov rsi 100)
167 | ,@(call-function 'bitmap-init)
168 | (mov rdi bitmap-regression-addr)
169 | ,@(call-function 'bitmap-count-1)
170 | (cmp rax 0)
171 | (jne .error)
172 | ,@(call-function 'bitmap-count-0)
173 | (cmp rax 100)
174 | (jne .error)
175 | (mov rdi bitmap-regression-addr)
176 | (mov rsi 0)
177 | ,@(call-function 'bitmap-set)
178 | ,@(call-function 'bitmap-count-0)
179 | (cmp rax 99)
180 | (jne .error)
181 | (mov rsi 1)
182 | ,@(call-function 'bitmap-set)
183 | ,@(call-function 'bitmap-count-0)
184 | (cmp rax 98)
185 | (jne .error)
186 | ,@(call-function 'bitmap-scan)
187 | (cmp rax 2)
188 | (jne .error)
189 | (mov rax #xffffffffffffffff)
190 | (mov (rdi 8) rax)
191 | ,@(call-function 'bitmap-count-0)
192 | (cmp rax 36)
193 | (jne .error)
194 | ,@(call-function 'bitmap-scan)
195 | (cmp rax 64)
196 | (jne .error)
197 | (mov rsi 64)
198 | ,@(call-function 'bitmap-set)
199 | ,@(call-function 'bitmap-count-0)
200 | (cmp rax 35)
201 | (jne .error)
202 | ,@(call-function 'bitmap-scan)
203 | (cmp rax 65)
204 | (jne .error)
205 | (mov rsi 65)
206 | ,@(call-function 'bitmap-set)
207 | ,@(call-function 'bitmap-count-0)
208 | (cmp rax 34)
209 | (jne .error)
210 | ,@(call-function 'bitmap-scan)
211 | (cmp rax 66)
212 | (jne .error)
213 | (mov rsi 67)
214 | ,@(call-function 'bitmap-set)
215 | ,@(call-function 'bitmap-scan)
216 | (cmp rax 66)
217 | (jne .error)
218 | (mov rsi 64)
219 | ,@(call-function 'bitmap-unset)
220 | ,@(call-function 'bitmap-count-0)
221 | (cmp rax 34)
222 | (jne .error)
223 | ,@(call-function 'bitmap-scan)
224 | (cmp rax 64)
225 | (jne .error)
226 | (jmp short .done)
227 | .error
228 | (mov rdi bitmap-regression-error-message)
229 | ,@(call-function 'println)
230 | .done
231 | )))
232 |
233 | bitmap-overflow-message (db "ERROR: bitmap index exceeds bounds." 0)
234 | bitmap-regression-error-message (db "Regression test fails for bitmap." 0)
235 | ))
236 |
--------------------------------------------------------------------------------
/cc/bochs.lisp:
--------------------------------------------------------------------------------
1 | ;;;; -*- Mode: Lisp -*-
2 | ;;;; Author:
3 | ;;;; Yujian Zhang
4 | ;;;; Description:
5 | ;;;; BOCHS specific functions.
6 | ;;;; License:
7 | ;;;; GNU General Public License v2
8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html
9 | ;;;; Copyright (C) 2018 Yujian Zhang
10 |
11 | (in-package :cc)
12 |
13 | (defparameter *bochs*
14 | `(
15 | (equ bochs-shutdown-port #x8900)
16 | ;;; Shutdown computer.
17 | ;;; Note that although computer is already shutdown after sending the special string,
18 | ;;; a function is still defined for simplicity.
19 | ;;; Input: None
20 | ;;; Output: Noneq
21 | ,@(def-fun 'bochs-shutdown nil
22 | `(
23 | .start
24 | (mov dx bochs-shutdown-port)
25 | (mov rsi shutdown-str)
26 | .loop
27 | (lodsb)
28 | (out dx al)
29 | (test al al)
30 | (jz .done)
31 | (jmp short .loop)
32 | .done))
33 |
34 | shutdown-str (db "Shutdown" 0)
35 | ))
36 |
--------------------------------------------------------------------------------
/cc/bootloader.lisp:
--------------------------------------------------------------------------------
1 | ;;;; -*- Mode: Lisp -*-
2 | ;;;; Author:
3 | ;;;; Yujian Zhang
4 | ;;;; Description:
5 | ;;;; Bootloader.
6 | ;;;;
7 | ;;;; Switch to 32 bit protected mode and 64 bit long mode is mainly based on
8 | ;;;; Section 14.8 (Long-Mode Initialization Example) of
9 | ;;;; [1] AMD64 Architecture Programmer's Manual Volume 2: System Programming.
10 | ;;;; Publication No. 24593; Revision: 3.25
11 | ;;;; License:
12 | ;;;; GNU General Public License v2
13 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html
14 | ;;;; Copyright (C) 2009-2015 Yujian Zhang
15 |
16 | (in-package :cc)
17 |
18 | (defparameter *bootloader*
19 | `(;;;==================== 16 bit real mode ====================
20 | (bits 16)
21 | (org #x7c00)
22 |
23 | ;; Setup segments and stack.
24 | (cli)
25 | (xor ax ax)
26 | (mov ds ax)
27 | (mov es ax)
28 | ;; From http://wiki.osdev.org/Memory_Map_(x86),
29 | ;; #x7e00 ~ #x7ffff is guaranteed to be available for use, therefore set
30 | ;; ss:sp = 7000:ff00
31 | (mov ax #x7000)
32 | (mov ss ax)
33 | (mov sp #xff00)
34 | (sti)
35 |
36 | ;; Load other sectors from floppy disk.
37 | ;; AL: # of sectors
38 | (mov ax (+ #x200 (ceiling (+ (- kernel-before-relocation stage-2)
39 | (- kernel-virtual-end kernel-virtual-start))
40 | 512)))
41 | (mov bx stage-2) ; ES:BX is destination
42 | (mov cx 2) ; CH: cylinder; CL: sector
43 | (xor dx dx) ; DH: head; DL: drive
44 | (int #x13)
45 |
46 | (jmp near stage-2)
47 |
48 | ;; Fill up to 510 bytes.
49 | (times (- 510 (- $ $$)) db 0)
50 |
51 | (dw #xaa55) ; Boot sector signature
52 |
53 | ;; Stage 2.
54 | stage-2
55 |
56 | ;; Initialize text mode.
57 | (call init-text-mode-16)
58 |
59 | ;; Check whether BGA is available
60 | ;; The following two lines are disabled for now as BGA mode is not used currently.
61 | ;; If not disabled, error will be thrown on VirtualBox (however osdev.org actually says that
62 | ;; VirtualBox supports BGA: http://wiki.osdev.org/BGA)
63 | ;;(call bga-available)
64 | ;;(jc no-bga-error)
65 | ;; Set target screen mode.
66 | ;(call set-bga-mode)
67 | ;; Show all red.
68 | ;(mov ecx ,(/ 65536 4))
69 | ;(mov eax #xa000)
70 | ;(mov es ax)
71 | ;(xor edi edi)
72 | ;(mov eax #xff0000) ; Red
73 | ;(cld)
74 | ;(rep stosd)
75 |
76 | ;; Check whether CPU supports Long Mode or not.
77 | (call check-cpu)
78 | (jc no-long-mode-error)
79 |
80 | ;; Enable A20 line.
81 | (call enable-a20)
82 |
83 | ;; Get memory map.
84 | (call get-memory-map)
85 |
86 | (jmp near switch-to-protected-mode)
87 |
88 | ;; A20 and keyboard related include from keyboard.lisp.
89 | ,@*keyboard-constants*
90 | ,@*keyboard-16*
91 | ,@*a20*
92 |
93 | ;; Memory map include from memory.lisp.
94 | ,@*memory-16*
95 |
96 | ;; Function check-cpu. Use CPUID to check if the process supports long mode.
97 | ;; From section 14.8 (Long-Mode Initialization Example) of [1].
98 | ;; If long mode is supported, CF is cleared; otherwise CF is set.
99 |
100 | check-cpu
101 | (mov eax #x80000000)
102 | (cpuid)
103 | (cmp eax #x80000000) ; Whether any extended function > 0x800000000 is available?
104 | (jbe no-long-mode)
105 | (mov eax #x80000001)
106 | (cpuid)
107 | (bt edx 29) ; Test if long mode is supported.
108 | (jnc no-long-mode)
109 | (clc)
110 | (ret)
111 | no-long-mode
112 | (stc)
113 | (ret)
114 |
115 | no-long-mode-error
116 | (mov si no-long-mode-message)
117 | (call println-16)
118 | .panic
119 | (hlt)
120 | (jmp short .panic)
121 | no-long-mode-message (db "ERROR: CPU does not support long mode." 0)
122 |
123 | ;; Include content from vga-text.lisp.
124 | ,@*vga-text-16*
125 |
126 | ;;; Global Descriptor Table (GDT).
127 | ;;; 32 bit GDT entries are according to
128 | ;;; http://www.brokenthorn.com/Resources/OSDev8.html
129 | ;;; 64 bit GDT entries are according to section 14.8
130 | ;;; (Long-Mode Initialization Example) of [1].
131 | gdt
132 | ;; Null descriptor
133 | (dd 0)
134 | (dd 0)
135 | ;; 32 bit code descriptor.
136 | (equ code-selector-32 (- $ gdt))
137 | (dw #xffff) ; Limit low
138 | (dw 0) ; Base low
139 | (db 0) ; Base middle
140 | (db #b10011010) ; Access
141 | (db #b11001111) ; Granularity
142 | (db 0) ; Base high
143 | ;; 32 bit data descriptor.
144 | (equ data-selector-32 (- $ gdt))
145 | (dw #xffff) ; Limit low
146 | (dw 0) ; Base low
147 | (db 0) ; Base middle
148 | (db #b10010010) ; Access
149 | (db #b11001111) ; Granularity
150 | (db 0) ; Base high
151 | ;; 64 bit code descriptor.
152 | (equ code-selector-64 (- $ gdt))
153 | (dw 0) ; Limit low (ingored)
154 | (dw 0) ; Base low (ingored)
155 | (db 0) ; Base middle (ingored)
156 | (db #b10011000) ; Access
157 | (db #b00100000) ; Granularity
158 | (db 0) ; Base high (ingored)
159 | ;; 64 bit data descriptor (read/write).
160 | (equ data-selector-64 (- $ gdt))
161 | (dw 0) ; Limit low (ingored)
162 | (dw 0) ; Base low (ingored)
163 | (db 0) ; Base middle (ingored)
164 | (db #b10010000) ; Access
165 | (db #b00000000) ; Granularity
166 | (db 0) ; Base high (ingored)
167 | end-gdt
168 | pgdt
169 | (dw (- end-gdt gdt 1)) ; Limit (size of GDT)
170 | (dd gdt) ; Base of GDT
171 |
172 | (align 4)
173 | idt
174 | .length (dw 0)
175 | .base (dd 0)
176 |
177 | switch-to-protected-mode
178 | (cli)
179 | (lgdt (pgdt)) ; Load GDT
180 | ;; Enter protected mode by setting CR0.PE = 1.
181 | (mov eax #b11)
182 | (mov cr0 eax)
183 | ;; Far jump to turn on protected mode. The following code is equivalent to
184 | ;; (jmp far code-selector-32:protected-mode)
185 | (db #xea) ; Far jump
186 | (dw protected-mode)
187 | (dw code-selector-32)
188 |
189 | ;;;==================== 32 bit protected mode ====================
190 |
191 | protected-mode
192 | (bits 32)
193 | ;; Setup registers.
194 | (mov ax data-selector-32)
195 | (mov ss ax)
196 | (mov esp #x90000)
197 | (mov ds ax)
198 | (mov es ax)
199 |
200 | switch-to-long-mode
201 | (call32 setup-paging)
202 |
203 | ;; Enable 64 bit page-translation-table entries by setting
204 | ;; CR4.PAE=1. Paging is not enabled until long mode is
205 | ;; enabled.
206 | (mov eax cr4)
207 | (bts eax 5)
208 | (mov cr4 eax)
209 |
210 | ;; Initialize 64-bit CR3 to point to the base of PML4 page table.
211 | ;; Note that PML4 table must be below 4 GB.
212 | (mov eax pml4-base)
213 | (mov cr3 eax)
214 |
215 | ;; Enable long mode (set EFER.LME = 1).
216 | (mov ecx #xc0000080) ; EFER MSR number.
217 | (rdmsr) ; Read EFER.
218 | (bts eax 8) ; Set LME = 1.
219 | (wrmsr) ; Write EFER.
220 |
221 | ;; Enable paging to activate long mode (set CR0.PG = 1).
222 | (mov eax cr0) ; Read CR0.
223 | (bts eax 31) ; Set PE = 1.
224 | (mov cr0 eax) ; Write CR0.
225 |
226 | ;; Jump from 32 bit compatibility mode to 64 bit code segment.
227 | ;; Far jump to turn on long mode. The following code is equivalent to
228 | ;; (jmp far code-selector-64:protected-mode)
229 | (db #x66)
230 | (db #xea) ; Far jump
231 | (dw long-mode) ; In [1], dd is used instead of dw.
232 | (dw code-selector-64)
233 |
234 | ,@*paging-32*
235 | ,@*memory-32*
236 |
237 | ,@*kernel*))
238 |
--------------------------------------------------------------------------------
/cc/cc.asd:
--------------------------------------------------------------------------------
1 | ;;;; -*- Mode: Lisp -*-
2 | ;;;; Author:
3 | ;;;; Yujian Zhang
4 | ;;;; Description:
5 | ;;;; ASDF definition.
6 | ;;;; License:
7 | ;;;; GNU General Public License v2
8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html
9 |
10 | (defpackage #:cc-system
11 | (:use #:cl #:asdf))
12 | (in-package #:cc-system)
13 |
14 | (defsystem cc
15 | :description "Cross compiler for yalo."
16 | :serial t
17 | :components
18 | ((:file "package")
19 | (:file "util")
20 | (:file "unit-test")
21 | (:file "config")
22 | (:file "abi")
23 | (:file "bitmap")
24 | (:file "memory")
25 | (:file "paging")
26 | (:file "bga")
27 | (:file "vga-text")
28 | (:file "keyboard")
29 | (:file "a20")
30 | (:file "bochs")
31 | (:file "kernel")
32 | (:file "bootloader")
33 | (:file "x86-64-syntax")
34 | (:file "lap")
35 | (:file "nasm")
36 | (:file "test-cc")
37 | (:file "test")))
38 |
--------------------------------------------------------------------------------
/cc/config.lisp:
--------------------------------------------------------------------------------
1 | ;;;; -*- Mode: Lisp -*-
2 | ;;;; Author:
3 | ;;;; Yujian Zhang
4 | ;;;; Description:
5 | ;;;; Configuration for the kernel.
6 | ;;;; License:
7 | ;;;; GNU General Public License v2
8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html
9 | ;;;; Copyright (C) 2018 Yujian Zhang
10 |
11 | (in-package :cc)
12 |
13 | (defparameter *include-regression-test* nil
14 | "Whether to include regression tests in the kernel:
15 | - t: Include regression tests
16 | - nil: NOT include regression tests")
17 |
18 | (defun regression-container (forms)
19 | "Include the FORMS if *include-regression-test* is T"
20 | (when *include-regression-test*
21 | forms))
22 |
--------------------------------------------------------------------------------
/cc/kernel.lisp:
--------------------------------------------------------------------------------
1 | ;;;; -*- Mode: Lisp -*-
2 | ;;;; Author:
3 | ;;;; Yujian Zhang
4 | ;;;; Description:
5 | ;;;; 64 bit long mode kernel code.
6 | ;;;; License:
7 | ;;;; GNU General Public License v2
8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html
9 | ;;;; Copyright (C) 2015-2018 Yujian Zhang
10 |
11 | (in-package :cc)
12 |
13 | (defparameter *kernel*
14 | `(
15 | ;;;==================== 64 bit long mode ====================
16 |
17 | long-mode
18 | (bits 64)
19 |
20 | ;; Load constant definitions
21 | ,@*vga-text-constants*
22 |
23 | ;; Setup stack's linear address. See the related 16 bit code for reason.
24 | (mov rsp #x7ff00)
25 |
26 | ;; Reuse previous 32 bit GDT (as we don't consume more than 4 GB memory. So skip loading 64 bit GDT.
27 | ;; (lgdt (pgdt))
28 |
29 | ;; Load 64 bit IDT. So far IDT has zero length, therefore any NMI causes a triple fault.
30 | ;;(lidt (idt))
31 |
32 | ;; Move kernel to physical address #x100000, which is virtual address
33 | ;; #xffffffff80100000.
34 | (mov rsi kernel-before-relocation)
35 | (mov rdi kernel-physical-base)
36 | (mov rcx (- kernel-virtual-end kernel-virtual-start))
37 | (rep movsb)
38 |
39 | ;; Jump to higher half kernel in 64 bit trampoline.
40 | (mov rdi kernel-virtual-start)
41 | (push rdi)
42 | (ret) ; Use push/ret together to implement a jmp.
43 |
44 | ;; Fill up to multiple of sectors, otherwise VirtualBox complains.
45 | (align 512)
46 |
47 | kernel-before-relocation
48 |
49 | (equ kernel-physical-base #x100000)
50 | (org (+ kernel-virtual-base kernel-physical-base))
51 |
52 | kernel-virtual-start
53 |
54 | ;; Setup stack's linear address again.
55 | (mov rsp (+ kernel-virtual-start #x100000))
56 |
57 | ,@(call-function 'unmap-lower-memory)
58 |
59 | ,@(call-function 'pmm-init)
60 |
61 | ,@(call-function 'clear)
62 |
63 | ;; Reload all data segments with null.
64 | (xor ax ax)
65 | (mov ss ax)
66 | (mov ds ax)
67 | (mov es ax)
68 | (mov fs ax)
69 | (mov gs ax)
70 |
71 | (mov rdi banner)
72 | ,@(call-function 'println)
73 | (jmp short read-start)
74 | banner (db "Start your journey on yalo v0.0.1!" 0)
75 |
76 | ;; So far this function is not called. Actually calling it
77 | ;; resulting in some issues
78 | ;; TODO
79 | ,@(call-function 'init-keyboard)
80 |
81 | ;;; REPL: read
82 | read-start
83 | (mov rdi repl)
84 | ,@(call-function 'print)
85 | (jmp short read)
86 | repl (db "REPL> " 0)
87 | (equ prompt-length (- $ repl 1))
88 | read
89 | ,@(call-function 'getchar)
90 | (cmp al 10)
91 | (je eval-start)
92 | (cmp al 0) ; Non-printable character.
93 | (jz read)
94 | (cmp al ascii-backspace)
95 | (jnz .show)
96 | ,@(call-function 'backspace-char)
97 | (jmp short read)
98 | .show
99 | (mov dil al)
100 | ,@(call-function 'putchar)
101 | (jmp short read)
102 |
103 | ;;; REPL: eval
104 | eval-start
105 |
106 | ;;; REPL: print
107 | ,@(call-function 'printlf)
108 | ,@(call-function 'printlf)
109 |
110 | ;;; REPL: loop
111 | (jmp short read-start)
112 |
113 | ;; (bits 16)
114 |
115 | ;; no-bga-error
116 | ;; (mov si no-bga-message)
117 | ;; (call println-16)
118 | ;; .panic
119 | ;; (hlt)
120 | ;; (jmp short .panic)
121 | ;; no-bga-message (db "ERROR: BGA not available." 0)
122 |
123 | (bits 64)
124 |
125 | ;; Include 64 bit paging related functions from paging.lisp
126 | ,@*paging*
127 |
128 | ;; Include 64 bit memory related functions from memory.lisp
129 | ,@*memory*
130 |
131 | ;; Include content from bga.lisp.
132 | ;;,@*bga*
133 |
134 | ;; Include content from vga-text.lisp.
135 | ,@*vga-text*
136 |
137 | ;; Include content from keyboard.lisp.
138 | ,@*keyboard*
139 |
140 | ;; Include content from bitmap.lisp.
141 | ,@*bitmap*
142 |
143 | ;; Include content from bochs.lisp.
144 | ,@*bochs*
145 |
146 | ;; Function panic. Display error message and halt the computer.
147 | ,@(def-fun 'panic nil
148 | `(
149 | ,@(call-function 'println)
150 | .panic
151 | (hlt)
152 | (jmp short .panic)))
153 |
154 | ;; Fill up to multiple of sectors, otherwise VirtualBox complains.
155 | (align 512)
156 |
157 | kernel-virtual-end
158 |
159 | ;; This is the physical address of the end of the kernel.
160 | (equ kernel-physical-end
161 | (+ kernel-before-relocation
162 | (- kernel-virtual-end kernel-virtual-start)))
163 | ))
164 |
--------------------------------------------------------------------------------
/cc/keyboard.lisp:
--------------------------------------------------------------------------------
1 | ;;;; -*- Mode: Lisp -*-
2 | ;;;; Author:
3 | ;;;; Yujian Zhang
4 | ;;;; Description:
5 | ;;;; Keyboard handling mode functions.
6 | ;;;; BIOS interruptions are not used.
7 | ;;;; License:
8 | ;;;; GNU General Public License v2
9 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html
10 | ;;;; Copyright (C) 2015-2018 Yujian Zhang
11 |
12 | (in-package :cc)
13 |
14 | (defparameter *keyboard-constants*
15 | `(
16 | ;;; Keyboard related constants. Note that input and output are
17 | ;;; from keyboard's perspective, not from user/cpu's persepctive.
18 | (equ kbd-encoder-buf #x60)
19 | (equ kbd-encoder-cmd-reg #x60)
20 | (equ kbd-ctrl-status-reg #x64)
21 | (equ kbd-ctrl-cmd-reg #x64)
22 | (equ kbd-ctrl-status-mask-out-buf #x01)
23 | (equ kbd-ctrl-status-mask-in-buf #x02)
24 | (equ kbd-ctrl-status-mask-system #x04)
25 | (equ kbd-ctrl-status-mask-cmd-data #x08)
26 | (equ kbd-ctrl-status-mask-locked #x10)
27 | (equ kbd-ctrl-status-mask-aux-buf #x20)
28 | (equ kbd-ctrl-status-mask-timeout #x40)
29 | (equ kbd-ctrl-status-mask-parity #x80)
30 | (equ kbd-ctrl-cmd-disable-keyboard #xad)
31 | (equ kbd-ctrl-cmd-enable-keyboard #xae)
32 | (equ kbd-ctrl-cmd-read-output-port #xd0)
33 | (equ kbd-ctrl-cmd-write-output-port #xd1)
34 | (equ kbd-ctrl-cmd-enable-a20 #xdd)
35 | (equ kbd-ctrl-cmd-system-reset #xfe)
36 | (equ kbd-encoder-cmd-set-led #xed)
37 | (equ kbd-encoder-cmd-set-led-capslock-on #x4)
38 | (equ kbd-encoder-cmd-set-led-capslock-off #x0)
39 | (equ kbd-encoder-cmd-set-scan-code #xf0)
40 | (equ kbd-encoder-cmd-set-scan-code-1 #x1)
41 | (equ kbd-encoder-cmd-enable-scanning #xf4)
42 | (equ kbd-encoder-cmd-disable-scanning #xf5)
43 | (equ kbd-encoder-cmd-reset #xff)
44 | ;; Codes for key states and toggle stages. Defined by internal usage only.
45 | (equ kbd-left-shift #x80)
46 | (equ kbd-right-shift #x81)
47 | (equ kbd-left-ctrl #x82)
48 | (equ kbd-right-ctrl #x83)
49 | (equ kbd-left-alt #x84)
50 | (equ kbd-right-alt #x85)
51 | (equ kbd-capslock #x86)
52 | (equ kbd-numlock #x87)
53 | (equ kbd-ascii-a #x61)
54 | (equ kbd-ascii-q #x71)
55 | (equ kbd-ascii-z #x7a)
56 | ;; Test whether key is released or not. If highest bit is 1, then key
57 | ;; is released; otherwise pressed.
58 | (equ kbd-key-released-mask #x80)
59 | ;; Reset the highest bit (indicating key is released or not) to 0.
60 | ;; kbd-scancode-mask is 1's complement of kbd-key-released-mask
61 | (equ kbd-scancode-mask #x7f)
62 | ))
63 |
64 | (defparameter *keyboard-16*
65 | ;;; 16-bit keyboard code related to A20 enabling.
66 | `(;;; The following 4 functions are exactly same (except the label
67 | ;;; names) as those functions without -16 suffix, defined in
68 | ;;; *keyboard*. Function descriptions are not shown here.
69 |
70 | kbd-ctrl-send-cmd-16
71 | (mov bl al) ; Save AL
72 | (call wait-kbd-in-buf-16)
73 | (mov al bl)
74 | (out kbd-ctrl-cmd-reg al)
75 | (ret)
76 |
77 | kbd-encoder-send-cmd-16
78 | (mov bl al) ; Save AL
79 | (call wait-kbd-in-buf-16)
80 | (mov al bl)
81 | (out kbd-encoder-cmd-reg al)
82 | (ret)
83 |
84 | wait-kbd-in-buf-16
85 | (in al kbd-ctrl-status-reg) ; Get status
86 | (test al kbd-ctrl-status-mask-in-buf)
87 | (jnz wait-kbd-in-buf-16)
88 | (ret)
89 |
90 | wait-kbd-out-buf-16
91 | (in al kbd-ctrl-status-reg) ; Get status
92 | (test al kbd-ctrl-status-mask-out-buf)
93 | (jz wait-kbd-out-buf-16)
94 | (ret)
95 | ))
96 |
97 | (defparameter *keyboard*
98 | `(
99 | ;;; Initialize keyboard by set scan code set 1.
100 | ;;; Input: None
101 | ;;; Output: None
102 | ,@(def-fun 'init-keyboard nil
103 | `(
104 | ;; TODO: double check whether to use encoder-cmd or ctrl-cmd.
105 | ;; TODO: Enable init-keyboard in kernel.
106 | (mov dil kbd-encoder-cmd-reset)
107 | ,@(call-function 'kbd-encoder-send-cmd)
108 | (mov dil kbd-encoder-cmd-disable-scanning)
109 | ,@(call-function 'kbd-encoder-send-cmd)
110 | (mov dil kbd-encoder-cmd-set-scan-code)
111 | ,@(call-function 'kbd-encoder-send-cmd)
112 | (mov dil kbd-encoder-cmd-set-scan-code-1)
113 | ,@(call-function 'kbd-encoder-send-cmd)
114 | (mov dil kbd-encoder-cmd-enable-scanning)
115 | ,@(call-function 'kbd-encoder-send-cmd)))
116 |
117 | ;;; Turn on CapsLock LED.
118 | ;;; Input: None
119 | ;;; Output: None
120 | ,@(def-fun 'turn-on-capslock-led nil
121 | `(
122 | (mov dil kbd-encoder-cmd-set-led)
123 | ,@(call-function 'kbd-encoder-send-cmd)
124 | (mov dil kbd-encoder-cmd-set-led-capslock-on)
125 | ,@(call-function 'kbd-encoder-send-cmd)
126 | ))
127 |
128 |
129 | ;;; Send command byte to keyboard controller.
130 | ;;; Input:
131 | ;;; AL: command byte
132 | ;;; Output: None
133 | ;;; Modified registers: BL
134 | ,@(def-fun 'kbd-ctrl-send-cmd nil
135 | `(
136 | ,@(call-function 'wait-kbd-in-buf)
137 | (mov al dil)
138 | (out kbd-ctrl-cmd-reg al)))
139 |
140 | ;;; Send command byte to keyboard encoder.
141 | ;;; Input:
142 | ;;; DIL: command byte
143 | ;;; Output: None
144 | ;;; Modified registers: AL
145 | ,@(def-fun 'kbd-encoder-send-cmd nil
146 | `(
147 | ,@(call-function 'wait-kbd-in-buf)
148 | (mov al dil)
149 | (out kbd-encoder-cmd-reg al)))
150 |
151 | ;;; Wait until the keyboard controller input buffer empty,
152 | ;;; therefore command can be written
153 | ;;; Input: None
154 | ;;; Output: None
155 | ;;; Modified registers: AL
156 | ,@(def-fun 'wait-kbd-in-buf nil
157 | `(
158 | (in al kbd-ctrl-status-reg) ; Get status
159 | (test al kbd-ctrl-status-mask-in-buf)
160 | (jnz wait-kbd-in-buf)))
161 |
162 | ;;; Wait until the keyboard controller output buffer ready for
163 | ;;; reading.
164 | ;;; Input: None
165 | ;;; Output: None
166 | ;;; Modified registers: AL
167 | ,@(def-fun 'wait-kbd-out-buf nil
168 | `(
169 | (in al kbd-ctrl-status-reg) ; Get status
170 | (test al kbd-ctrl-status-mask-out-buf)
171 | (jz wait-kbd-out-buf)))
172 |
173 | ;;; Function getchar. Get keystroke from keyboard without echo. If
174 | ;;; keystroke is available, it is removed from keyboard buffer.
175 | ;;; Use polling method. TODO: use interrupt.
176 | ;;; So far only a few keys are scanned. TODO: support full set of scan code.
177 | ;;; TODO: handle key repetition.
178 | ;;; Input: None
179 | ;;; Output:
180 | ;;; AL: ASCII character (0 indicats a key is released or not handled)
181 | ;;; Modified registers: RSI, RDX
182 | ,@(def-fun 'getchar nil
183 | `(
184 | ,@(call-function 'wait-kbd-out-buf)
185 | (xor eax eax)
186 | ;; Use DL to store whether key is released or pressed.
187 | ;; Zero: key is pressed; otherwise released.
188 | (xor edx edx)
189 | (in al kbd-encoder-buf) ; Get key data
190 | (mov dl al)
191 | ;; After following instruction, DL stores whether key is released (#x80)
192 | ;; or pressed (#x0).
193 | (and dl kbd-key-released-mask)
194 | (and al kbd-scancode-mask)
195 | ;; Now highest bit of AL is 0, and we can index into scan code set table.
196 | (mov rsi scan-code-set-1)
197 | (add rsi rax)
198 | (lodsb)
199 | (cmp al kbd-left-shift)
200 | ;; kbd-left-shift is the first code for key and toggle states.
201 | (jb near .shutdown-check)
202 | (jnz .check-right-shift)
203 | (test dl dl)
204 | (setz (kbd-left-shift-status))
205 | (jmp short .set-shift-status)
206 | .check-right-shift
207 | (cmp al kbd-right-shift)
208 | (jnz .check-capslock)
209 | (test dl dl)
210 | (setz (kbd-right-shift-status))
211 | (jmp short .set-shift-status)
212 | .check-capslock
213 | (cmp al kbd-capslock)
214 | (jnz .check-left-ctrl)
215 | (test dl dl)
216 | ;; Ignore the release of Capslock key.
217 | (jnz near .clear-key)
218 | ;; Toggle kbd-capslock-status between 0 and 1.
219 | (xor byte (kbd-capslock-status) 1)
220 | ;; We don't call function `turn-on-capslock-led' since at
221 | ;; least in QEMU, it seems that even if guest OS does
222 | ;; nothing, Capslock LED is automatically adjusted.
223 | ;; Note: in host, if Capslock and Left Ctrl are swapped in file ~/.Xmodmap,
224 | ;; Bochs respects the change, while QEMU and VirtualBox still only recognize
225 | ;; old Capslock.
226 | .set-shift-status
227 | ;; Use DH to store the overall Shift status.
228 | (mov dh (kbd-left-shift-status))
229 | (or dh (kbd-right-shift-status))
230 | (mov (kbd-shift-status) dh)
231 | (xor dh (kbd-capslock-status))
232 | (mov (kbd-to-upper-status) dh)
233 | (jmp near .clear-key)
234 | .check-left-ctrl
235 | (cmp al kbd-left-ctrl)
236 | (jnz .check-right-ctrl)
237 | (test dl dl)
238 | (setz (kbd-left-ctrl-status))
239 | (jmp short .set-ctrl-status)
240 | .check-right-ctrl
241 | (cmp al kbd-right-ctrl)
242 | (jnz .check-left-alt)
243 | (test dl dl)
244 | (setz (kbd-right-ctrl-status))
245 | .set-ctrl-status
246 | ;; Use DH to store the overall Ctrl status.
247 | (mov dh (kbd-left-ctrl-status))
248 | (or dh (kbd-right-ctrl-status))
249 | (mov (kbd-ctrl-status) dh)
250 | (jmp near .clear-key)
251 | .check-left-alt
252 | (cmp al kbd-left-alt)
253 | (jnz .check-right-alt)
254 | (test dl dl)
255 | (setz (kbd-left-alt-status))
256 | (jmp short .set-alt-status)
257 | .check-right-alt
258 | (cmp al kbd-right-alt)
259 | (jnz near .clear-key)
260 | (test dl dl)
261 | (setz (kbd-right-alt-status))
262 | .set-alt-status
263 | ;; Use DH to store the overall Alt status.
264 | (mov dh (kbd-left-alt-status))
265 | (or dh (kbd-right-alt-status))
266 | (mov (kbd-alt-status) dh)
267 | (jmp near .clear-key)
268 | .shutdown-check
269 | ;; For BOCHS only. Check whether Ctrl-Alt-q is pressed.
270 | (mov dh (kbd-ctrl-status))
271 | (and dh (kbd-alt-status))
272 | (test dh dh)
273 | (jz .translate-check)
274 | (cmp al kbd-ascii-q)
275 | (jnz .translate-check)
276 | ,@(call-function 'bochs-shutdown)
277 | ;; The computer should have been shutdown already. Just for completeness.
278 | (jmp short .done)
279 | .translate-check
280 | ;; For alphabetic characters (a-z), check kbd-to-upper-status (i.e.
281 | ;; both Shift and Capslock are checked). Note that we don't check A-Z
282 | ;; since table scan-code-set-1 only generates a-z.
283 | (cmp al kbd-ascii-a)
284 | (jb .non-alphabetic-characters)
285 | (cmp al kbd-ascii-z)
286 | (ja .non-alphabetic-characters)
287 | .alphabetic-characters
288 | (mov dh (kbd-to-upper-status))
289 | (test dh dh)
290 | (jz .test-key-release) ; Translation not needed.
291 | (jmp short .translate)
292 | .non-alphabetic-characters
293 | (mov dh (kbd-shift-status))
294 | (test dh dh)
295 | (jz .test-key-release) ; Translation not needed.
296 | .translate
297 | ;; Shift has been pressed
298 | (mov rsi lower-to-upper-table)
299 | (add rsi rax)
300 | (lodsb)
301 | .test-key-release
302 | (test dl dl)
303 | (jnz .done)
304 | .clear-key
305 | ;; Set AL to 0 if highest bit of DL is 1 as we don't handle key release for now.
306 | ;; Also set AL to 0 if keys for states and toggles are pressed/released.
307 | (xor eax eax)
308 | .done))
309 |
310 | ;; Left Shift status: 0: released; 1: pressed
311 | kbd-left-shift-status (db 0)
312 | ;; Right Shift status: 0: released; 1: pressed
313 | kbd-right-shift-status (db 0)
314 | ;; Overall Shift status is 0 if all shift key are released else 1
315 | ;; (i.e. if any of the Shift key is pressed). Note that for
316 | ;; non-alphabetic characters, only kbd-shift-status matters (i.e.
317 | ;; kbd-capslock-status does not have any influence).
318 | kbd-shift-status (db 0)
319 | ;; Capslock status: 0: off; 1: on. Note that different from Shift/Ctrl/Alt,
320 | ;; Capslock is a toggle when Capslock key is pressed. Release of Capslock key
321 | ;; is ignored.
322 | kbd-capslock-status (db 0)
323 | ;; Overall status of whether to translate characters from lower
324 | ;; case (including punctuations) to upper case. The Shift status
325 | ;; (kbd-shift-status) is XORed with Capslock status
326 | ;; (kbd-capslock-status) to determine whether lower-to-upper table
327 | ;; below should be used (if the XOR result is 1) for alphabetic
328 | ;; characters or not.
329 | kbd-to-upper-status (db 0)
330 | ;; Left Ctrl status: 0: released; 1: pressed
331 | kbd-left-ctrl-status (db 0)
332 | ;; Right Ctrl status: 0: released; 1: pressed
333 | kbd-right-ctrl-status (db 0)
334 | ;; Overall Ctrl status is 0 if all ctrl key are released else 1
335 | ;; (i.e. if any of the Ctrl key is pressed).
336 | kbd-ctrl-status (db 0)
337 | ;; Left Alt status: 0: released; 1: pressed
338 | kbd-left-alt-status (db 0)
339 | ;; Right Alt status: 0: released; 1: pressed
340 | kbd-right-alt-status (db 0)
341 | ;; Overall Alt status is 0 if all alt key are released else 1
342 | ;; (i.e. if any of the Alt key is pressed).
343 | kbd-alt-status (db 0)
344 | ;;; Table for Scan code set 1: http://wiki.osdev.org/Keyboard#Scan_Code_Set_1
345 | ;;; Release code is not stored as it is simply the sum of pressed code and #x80
346 | ;;; (as in http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html#ss1.1)
347 | ;;; TODO: add right control and right shift.
348 | scan-code-set-1
349 | (db 0 27 49 50 51 52 53 54 55 56 57 48 45 61 8 9
350 | 113 119 101 114 116 121 117 105 111 112 91 93 10 kbd-left-ctrl 97 115
351 | 100 102 103 104 106 107 108 59 39 96 kbd-left-shift 92 122 120 99 118
352 | 98 110 109 44 46 47 kbd-right-shift 0 kbd-left-alt 32 kbd-capslock 0 0 0 0 0
353 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
354 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
355 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
356 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
357 | )
358 |
359 | ;;; Convert from lower case ASCII (index) to upper case ASCII (value)
360 | ;;; from https://en.wikipedia.org/wiki/ASCII#Character_set
361 | ;;; An example: index 0x30 is the ASCII code for '0', and the corresponding
362 | ;;; value is 0x29 (41 in decimal), which is the ASCII code for
363 | ;;; ')'. This corresponds to the relationship that ')' is the
364 | ;;; character when both Shift and '0' is pressed.
365 | lower-to-upper-table
366 | (db 0 0 0 0 0 0 0 0 8 9 10 0 0 0 0 0
367 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
368 | 32 0 0 0 0 0 0 34 0 0 0 0 60 95 62 63
369 | 41 33 64 35 36 37 94 38 42 40 0 58 0 43 0 0
370 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
371 | 0 0 0 0 0 0 0 0 0 0 0 123 124 125 0 0
372 | 126 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
373 | 80 81 82 83 84 85 86 87 88 89 90 0 0 0 0 0)
374 | ))
375 |
--------------------------------------------------------------------------------
/cc/lnasdf:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | # Create symbolic link of CC system for ASDF.
3 | mkdir -p ~/common-lisp
4 | ln -fs `pwd`\/cc.asd ~/common-lisp/cc.asd
5 |
--------------------------------------------------------------------------------
/cc/memory.lisp:
--------------------------------------------------------------------------------
1 | ;;;; -*- Mode: Lisp -*-
2 | ;;;; Author:
3 | ;;;; Yujian Zhang
4 | ;;;; Description:
5 | ;;;; Memory management.
6 | ;;;; License:
7 | ;;;; GNU General Public License v2
8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html
9 | ;;;; Copyright (C) 2015 Yujian Zhang
10 |
11 | (in-package :cc)
12 |
13 | (defparameter *memory-16*
14 | `(
15 | ;;; http://wiki.osdev.org/Detecting_Memory_(x86)
16 | ;;; http://www.brokenthorn.com/Resources/OSDev17.html
17 |
18 | ;;; Use INT 0x15, EAX=#xe820 BIOS function to get memory map.
19 | ;;; Modified registers: all registers are trashed except ESI.
20 | get-memory-map
21 | ;; String "SMAP".
22 | (equ mm-smap #x0534D4150)
23 | (equ mm-entry-size 24)
24 | (equ mm-start-addr 0)
25 | ;; Offset for the end address. Note that it is the length field after
26 | ;; the BIOS call, but the value is replaced with end address by this function.
27 | (equ mm-end-addr 8)
28 | (equ mm-memory-type 16)
29 | (equ mm-entries-offset 2)
30 | ;; Stores Number of memory map entries. This is the linear address.
31 | ;; Corresponding semgnet:offset is in mm-count-physical-segment
32 | ;; and mm-count-physical-offset
33 | (equ mm-count-physical-addr #x80000)
34 | ;; The following is the pair of segment:offset
35 | (equ mm-count-physical-segment (ash mm-count-physical-addr -4))
36 | (equ mm-count-physical-offset (logand mm-count-physical-addr #xffff))
37 | ;; Maximum number of entries.
38 | (equ mm-entry-max 20)
39 | ;; Starting address of the memory map entries. This is the linear address.
40 | ;; Corresponding semgent and offset is mm-count-physical-segment, and
41 | ;; mm-entries-physical-offset.
42 | (equ mm-entries-physical-addr (+ mm-count-physical-addr mm-entries-offset))
43 | (equ mm-entries-physical-offset (logand mm-entries-physical-addr #xffff))
44 | (push es)
45 | (mov ax mm-count-physical-segment)
46 | (mov es ax)
47 | (xor ebx ebx) ; Set EBX to 0 to start
48 | (mov di mm-entries-physical-offset)
49 | (xor bp bp)
50 | (mov edx mm-smap) ; Place "SMAP" into edx
51 | (mov eax #xe820)
52 | (es mov dword (di 20) 1) ; Force a valid ACPI 3.x entry
53 | (mov ecx mm-entry-size)
54 | (int #x15)
55 | (jc .fail) ; CF is set if the BIO function is not supported.
56 | (mov edx mm-smap) ; Some BIOSes may trash this register.
57 | (cmp eax edx) ; On success, EAX must have been rest to "SMAP"
58 | (jne .fail)
59 | (test ebx ebx) ; EBX = 0 implies that the list contains only 1 entry.
60 | (je .fail)
61 | (jmp short .jump-in)
62 | .loop
63 | (mov eax #xe820) ; EAX, ECX get trashed on every int #x15 call.
64 | (es mov dword (di 20) 1) ; Force a valid ACPI 3.x entry
65 | (mov ecx mm-entry-size)
66 | (int #x15)
67 | (jc .done) ; CF means the end of list.
68 | (mov edx mm-smap) ; Repair potentially trashed register.
69 | .jump-in
70 | (jcxz .skip-entry) ; Skip and 0 length entry.
71 | (cmp cl 20) ; Got a 24 byte ACPI 3.x response?
72 | (jbe .no-text)
73 | (es test byte (di 20) 1) ; Test whether the "ignore this data" bit is clear or not.
74 | (je .skip-entry)
75 | .no-text
76 | (es mov ecx (di 8)) ; Get lower 32 bit of memory region length.
77 | (es or ecx (di 12)) ; "Or" it with upper 32 bit to test for zero.
78 | (jz .skip-entry)
79 | ;; Got a good entry. Modify 64 bit length field into end address.
80 | ;; Subtract 1 from length.
81 | (es dec dword (di 8))
82 | (es sbb dword (di 12) 0)
83 | ;; Then add base.
84 | (es mov eax (di))
85 | (es add (di 8) eax)
86 | (es mov eax (di 4))
87 | (es adc (di 12) eax)
88 | (inc bp) ; Increase entry count
89 | (add di mm-entry-size) ; Move to next entry.
90 | .skip-entry
91 | (test ebx ebx) ; If EBX is reset to 0, the list is complete.
92 | (jne .loop)
93 | (cmp bp mm-entry-max) ; If the actual memory count exceeds the limit,
94 | ; Memory data will be trashed by page tables.
95 | (jae .fail)
96 | .done
97 | (es mov (mm-count-physical-offset) bp)
98 | (clc) ; Clear CF (since .done lable is entered after "jc" instruction).
99 | (pop es)
100 | (ret)
101 | .fail
102 | (mov si .mm-error-message)
103 | (call println-16)
104 | .panic
105 | (hlt)
106 | (jmp short .panic)
107 | .mm-error-message (db "ERROR: memory map cannot be detected." 0)
108 | ))
109 |
110 | (defparameter *memory-32*
111 | `(
112 | ;;; Memory type constants.
113 | (equ memory-usable 1)
114 | (equ memory-reserved 2)
115 | (equ memory-acpi-reclaimable 3)
116 | (equ memory-acpi-nvs 4)
117 | (equ memory-bad 5)
118 |
119 | ;;; Get the maximum physical memory size, in bytes. Return the result in (EDX, EAX),
120 | ;;; where EDX stores the upper 32 bits.
121 | ;;; This is based on memory map detected with get-memory-map.
122 | ;;; TODO: for 32 bit operation, we don't need to get memory size as virtual
123 | ;;; memory management will be done in 64 bit mode. For page setup, we only map the 1st 2 MB for kernel
124 | ;;; will be sufficient. Code this function in 64 bit mode will be much easier
125 | ;;; as we can easily handle 64 bit arithmetic in 64 bit mode.
126 | get-memory-size
127 | (push esi)
128 | (push ecx)
129 | (push ebx)
130 | (push ebp)
131 | (movzx ecx word (mm-count-physical-addr)) ; Number of entries to process
132 | (mov esi mm-entries-physical-addr)
133 | (xor edx edx) ; EDX:EAX store the maximum physical address.
134 | (xor eax eax)
135 | .start
136 | (mov ebp (esi mm-memory-type))
137 | (cmp ebp memory-usable) ; TODO: consider ACPI reclaimable?
138 | (jnz .skip-entry)
139 | (mov ebp (esi 8)) ; Lower 32 bits.
140 | (mov ebx (esi 12)) ; Higher 32 bits. Now EBX:EBP store the current physical address.
141 | (cmp ebx edx)
142 | (jb .skip-entry)
143 | (ja .update)
144 | (cmp ebp eax)
145 | (jbe .skip-entry)
146 | .update
147 | (mov edx ebx)
148 | (mov eax ebp)
149 | .skip-entry
150 | (add esi mm-entry-size)
151 | (loop .start)
152 | .done
153 | (pop ebp)
154 | (pop ebx)
155 | (pop ecx)
156 | (pop esi)
157 | (ret)
158 | ))
159 |
160 | (defparameter *memory*
161 | `(;;; ==================== Start of Physical Memory Manager (PMM) ====================
162 | (equ page-size-shift 21) ; Shift for 2 MB
163 | (equ mm-count-virtual-addr (+ kernel-virtual-base mm-count-physical-addr))
164 | (equ mm-entries-virtual-addr (+ kernel-virtual-base mm-entries-physical-addr))
165 |
166 | ;;; Function pmm-init: initilize the pmm.
167 | ;;; Input: None
168 | ;;; Output: None
169 | ;;;
170 | ;;; Algorithm:
171 | ;;; First we mark all page frames as free (set corresponding bit to 0).
172 | ;;; Then we goes through the memory map.
173 | ;;; For every memory entry unusable:
174 | ;;; For every page frame whose starting address <= end address of the memory entry:
175 | ;;; If the end address of the page frame >= the starting address of the memory entry:
176 | ;;; Mark the page frame as used (set the bit to 1).
177 | ,@(def-fun 'pmm-init nil
178 | `(
179 | ;; First initialize page-table-bitmap.
180 | (mov rdi page-table-bitmap-virtual-addr)
181 | (mov rsi page-table-max)
182 | (push rdi)
183 | ,@(call-function 'bitmap-init)
184 | (pop rdi)
185 | ;; The first three page tables are already used. Note that identity mapping tables
186 | ;; are available for reuse.
187 | (xor esi esi)
188 | ,@(call-function 'bitmap-set)
189 | (mov esi 1)
190 | ,@(call-function 'bitmap-set)
191 | (mov esi 2)
192 | ,@(call-function 'bitmap-set)
193 | ;; Now initialize page-frame-bitmap.
194 | (mov rsi (memory-size-virtual-addr))
195 | (mov eax 1)
196 | (shl eax page-size-shift)
197 | (dec eax)
198 | (add rsi rax)
199 | (shr rsi page-size-shift) ; Get ceil(memory-size / (2 ^ page-size-shift))
200 | (mov rdi page-frame-bitmap-virtual-addr)
201 | (push rdi)
202 | ,@(call-function 'bitmap-init)
203 | (pop rdi)
204 | ;; Now loop throught every unusable memory entry.
205 | (movzx ecx word (mm-count-virtual-addr)) ; Number of entries to process
206 | (mov rax mm-entries-virtual-addr) ; Use RAX to loop throught memory map entry.
207 | .memory-entry
208 | (mov edx (rax mm-memory-type))
209 | (cmp edx memory-usable) ; TODO: consider ACPI reclaimable?
210 | (je .skip-entry)
211 | (mov r8 (rax mm-start-addr))
212 | (mov r9 (rax mm-end-addr))
213 | (xor r10d r10d) ; The index to the page frames.
214 | .page-frame
215 | (mov r11 r10)
216 | (shl r11 page-size-shift) ; Starting address of the page frame.
217 | (cmp r11 r9)
218 | ;; Skip the current and remaining page frames, as the memory entry cannot
219 | ;; overlap with them.
220 | (ja .skip-entry)
221 | (mov r11 r10)
222 | (inc r11)
223 | (shl r11 page-size-shift) ; End address of the page frame.
224 | (cmp r11 r8)
225 | (jb .next-page-frame)
226 | ;; Now the unusable memory entry overlaps with the page frame, so
227 | ;; we set it to used (bit is 1).
228 | (push rsi)
229 | (push rdx)
230 | (mov rsi r10)
231 | ,@(call-function 'bitmap-set)
232 | (pop rdx)
233 | (pop rsi)
234 | .next-page-frame
235 | (inc r10)
236 | (cmp r10 rsi)
237 | (jb .page-frame)
238 | .skip-entry
239 | (add rax mm-entry-size)
240 | (loop .memory-entry)
241 | ))
242 |
243 | ;;; Function pmm-alloc-page-frame: allocate one page frame.
244 | ;;; Input: None.
245 | ;;; Output:
246 | ;;; RAX: starting physical address of the page frame.
247 | ;;; 0 if out of memory.
248 | ,@(def-fun 'pmm-alloc-page-frame nil
249 | `(
250 | (mov rdi page-frame-bitmap-virtual-addr)
251 | ,@(call-function 'bitmap-scan)
252 | (mov rsi -1)
253 | (cmp rax rsi)
254 | (je .out-of-memory)
255 | (mov rsi rax)
256 | (push rax)
257 | ,@(call-function 'bitmap-set)
258 | (pop rax)
259 | (shl rax page-size-shift)
260 | (jmp short .done)
261 | .out-of-memory
262 | (xor eax eax)
263 | .done
264 | ))
265 |
266 | ;;; Function pmm-free-page-frame: free one page frame.
267 | ;;; Input:
268 | ;;; RDI: starting physical address of the page frame.
269 | ;;; Output: None.
270 | ,@(def-fun 'pmm-free-page-frame nil
271 | `(
272 | (mov rsi rdi)
273 | (shr rsi page-size-shift)
274 | (mov rdi page-frame-bitmap-virtual-addr)
275 | ,@(call-function 'bitmap-unset)))
276 |
277 | ;;; ===================== End of Physical Memory Manager (PMM) =====================
278 | ))
279 |
--------------------------------------------------------------------------------
/cc/misc.asm:
--------------------------------------------------------------------------------
1 | ;; NASM code for cross check the assembly output from test-cc.lisp.
2 | ;; The test is performed as follows:
3 | ;; 1. Run NASM with: /usr/local/bin/nasm -o misc.img misc.asm
4 | ;; 2. In CL REPL, compare the output with (equal (read-image "misc.img") (asm *misc-asm*))
5 | ;; Note that above nasm command assumes the usage of nasm installed from brew.
6 |
7 | org 7C00h
8 | bits 16
9 |
10 | start:
11 | align 4
12 | bt edx, 29
13 | align 4
14 | btc eax, 28
15 | btr ebx, 27
16 | bts ecx, 26
17 | call msg
18 | clc
19 | cld
20 | cli
21 |
22 | hlt
23 | in al, 3
24 | in ax, 4
25 | in al, dx
26 | in ax, dx
27 | int3
28 | int 10h
29 | .loop:
30 | jcxz .loop
31 | je .loop
32 | jmp short .loop
33 | jmp near meta_msg
34 | lgdt [msg]
35 | lidt [msg]
36 | lldt dx
37 | lldt [msg]
38 | lodsb
39 | lodsw
40 | lodsd
41 | loop .loop
42 | mov bl, byte [es:di]
43 | mov byte [ds:si], 0ffh
44 | mov ah, 9
45 | mov bl, [msg]
46 | mov [msg], bh
47 | mov bx, endmsg - msg
48 | mov ax, cx
49 | mov [msg], bx
50 | mov cx, [1c7bh]
51 | mov byte [msg], 42
52 | mov word [msg], 123
53 | mov es, bx
54 | mov ax, cs
55 | mov cr0, eax
56 | mov eax, cr0
57 | movzx ax, byte [msg]
58 | movzx edx, cx
59 | movzx eax, byte [msg]
60 | movzx eax, word [msg]
61 |
62 | nop
63 | out 3, al
64 | out 4, ax
65 | out dx, al
66 | out dx, ax
67 | push cx
68 | push edx
69 | push cs
70 | push ss
71 | push ds
72 | push es
73 | pushf
74 | pushfd
75 | pop dx
76 | pop ecx
77 | pop ss
78 | pop ds
79 | pop es
80 | popf
81 | popfd
82 | rdmsr
83 | rep movsb
84 | rep movsw
85 | rep movsd
86 | ret
87 | stc
88 | std
89 | sti
90 | stosb
91 | stosw
92 | stosd
93 | wrmsr
94 |
95 | bits 64
96 | default rel
97 | bsf ax, bx
98 | bsf ecx, edx
99 | bsf r10, [msg]
100 | bsr ax, r8w
101 | bsr r10d, r9d
102 | bsr rax, r12
103 | bswap ebx
104 | bswap rax
105 | bswap r10
106 | bt edx, 29
107 | bt edx, ecx
108 | bt rdx, 30
109 | bt rax, rbx
110 | btc rax, 29
111 | btr rbx, 28
112 | bts rcx, 27
113 | call msg
114 | cmova ax, bx
115 | cmovc eax, edx
116 | cmove rdx, r10
117 | cmpxchg cl, dl
118 | cmpxchg cx, dx
119 | cmpxchg edi, edx
120 | cmpxchg rcx, r10
121 | cmpxchg8b [rbx]
122 | cmpxchg16b [rbx]
123 | invlpg [abs 0]
124 | iretq
125 | jb near msg
126 | jmp rbx
127 | jmp msg
128 | jmp [msg]
129 | leave
130 | lgdt [msg]
131 | lidt [msg]
132 | lodsq
133 | mov eax, 1234h
134 | mov rsp, 90000h
135 | mov rax, 1122334455667788h
136 | mov rcx, [msg]
137 | mov rcx, [abs msg]
138 | mov rdi, [abs 0b8000h]
139 | mov rbx, rcx
140 | mov rax, -1
141 | mov qword [msg], 1019
142 | mov ax, r8w
143 | mov r9w, word [fs: rel msg]
144 | mov dil, 19
145 | movsq
146 | movzx r10, al
147 | movzx eax, byte [msg]
148 | movzx rdx, word [msg]
149 | push r10
150 | pushfq
151 | pop rax
152 | popcnt r11, [msg]
153 | popfq
154 | sal ebx, 1
155 | sar edx, cl
156 | seta ah
157 | setz byte [msg]
158 | shl r10, 6
159 | shr qword [msg], 8
160 | rep stosq
161 | syscall
162 | sysret
163 | xadd cl, dl
164 | xadd cx, dx
165 | xadd edi, edx
166 | xadd rcx, r10
167 | xchg ax, bx
168 | xchg cx, ax
169 | xchg eax, ebx
170 | xchg ecx, eax
171 | xchg rax, rbx
172 | xchg rcx, rax
173 | xchg cl, al
174 | xchg bx, cx
175 | xchg ebx, edx
176 | xchg r15, r10
177 |
178 | jecxz msg
179 | jrcxz msg
180 |
181 | hi equ 4
182 | meta_msg:
183 | dw msg
184 | resb 4
185 | msg:
186 | db "Hello World! "
187 | endmsg:
188 | times 3 db 0
189 | dw 0AA55h
190 | resw 3
191 | dd 123456,7891011
192 | resd 2
193 | dq 3372036854775808
194 | resq 1
195 |
--------------------------------------------------------------------------------
/cc/nasm.lisp:
--------------------------------------------------------------------------------
1 | ;;;; -*- Mode: Lisp -*-
2 | ;;;; Author:
3 | ;;;; Yujian Zhang
4 | ;;;; Description:
5 | ;;;; NASM related functions.
6 | ;;;; License:
7 | ;;;; GNU General Public License v2
8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html
9 | ;;;; Copyright (C) 2012 Yujian Zhang
10 |
11 | (in-package :cc)
12 |
13 | (defun ->nasm(listing)
14 | "Return a string of NASM code translated from LISTING (as the input to (ASM))."
15 | (let ((fstr (make-array '(0) :element-type 'base-char
16 | :fill-pointer 0 :adjustable t)))
17 | (with-output-to-string (s fstr)
18 | (dolist (e listing (string-downcase fstr))
19 | (cond ((atom e) (format s "~A:~%" e))
20 | ((member (first e) '(db dw dd dq))
21 | (format s "~A:~% ~A \"~A\"~%" (second e) (first e) (third e)))
22 | ((eql (first e) 'mov)
23 | (format s " mov ")
24 | (format-addr s (second e))
25 | (format s ", ")
26 | (format-addr s (third e))
27 | (format s "~%"))
28 | (t (format s " ~A ~{~A~^,~}~%" (car e) (cdr e))))))))
29 |
30 | (defun format-addr (stream expr)
31 | "Format address related expressions e.g. in MOV."
32 | (if (atom expr)
33 | (format stream "~A" expr)
34 | (format stream "[~{~A~^+~}]" expr)))
35 |
36 | (deftest test-nasm ()
37 | (check
38 | (string= (->nasm
39 | '((org #x7c00)
40 | (bits 16)
41 | (mov (bp) es)
42 | (mov (bx si) ds)
43 | (mov (32330) ds)
44 | (mov (msg) ds)
45 | (mov (bx) cs)
46 | (mov (bx si 1) ds)
47 | (mov ds (bx si 1001))
48 | (bits 32)
49 | (mov (ebp) ebx)
50 | (mov (123456) edx)
51 | (mov (eax) edx)
52 | (mov (ebp 36) ecx)
53 | (mov (esp #x23) ebx)
54 | (mov (eax*2 esi) edx)
55 | (mov (esi*2 ebp 123) edx)
56 | (db msg "Hello World!")
57 | endmsg))
58 | (concatenate
59 | 'string
60 | " org 31744"
61 | " bits 16"
62 | " mov [bp], es"
63 | " mov [bx+si], ds"
64 | " mov [32330], ds"
65 | " mov [msg], ds"
66 | " mov [bx], cs"
67 | " mov [bx+si+1], ds"
68 | " mov ds, [bx+si+1001]"
69 | " bits 32"
70 | " mov [ebp], ebx"
71 | " mov [123456], edx"
72 | " mov [eax], edx"
73 | " mov [ebp+36], ecx"
74 | " mov [esp+35], ebx"
75 | " mov [eax*2+esi], edx"
76 | " mov [esi*2+ebp+123], edx"
77 | "msg:"
78 | " db \"hello world! \""
79 | "endmsg:"))))
80 |
--------------------------------------------------------------------------------
/cc/package.lisp:
--------------------------------------------------------------------------------
1 | ;;;; -*- Mode: Lisp -*-
2 | ;;;; Author:
3 | ;;;; Yujian Zhang
4 | ;;;; Description:
5 | ;;;; Package definition.
6 | ;;;; License:
7 | ;;;; GNU General Public License v2
8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html
9 | ;;;; Copyright (C) 2009-2012 Yujian Zhang
10 |
11 | (defpackage #:cc
12 | (:use #:common-lisp)
13 | (:export
14 | #:asm
15 | #:*bootloader*
16 | #:test-cc
17 | #:write-kernel))
18 |
--------------------------------------------------------------------------------
/cc/paging.lisp:
--------------------------------------------------------------------------------
1 | ;;;; -*- Mode: Lisp -*-
2 | ;;;; Author:
3 | ;;;; Yujian Zhang
4 | ;;;; Description:
5 | ;;;; Paging functions.
6 | ;;;; References:
7 | ;;;; [1] AMD64 Architecture Programmer's Manual Volume 2: System Programming.
8 | ;;;; Publication No. 24593; Revision: 3.25
9 | ;;;; License:
10 | ;;;; GNU General Public License v2
11 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html
12 | ;;;; Copyright (C) 2015 Yujian Zhang
13 |
14 | (in-package :cc)
15 |
16 | (defparameter *paging-32*
17 | `(
18 | ;;; Technical details for 2 MB page translation can be found in
19 | ;;; section 5.3.4 (2-Mbyte Page Translation) of [1].
20 | ;;; At the beginning, paging setup is based on
21 | ;;; http://wiki.osdev.rg/Entering_Long_Mode_Directly
22 | ;;;
23 | ;;; Setup two mappings:
24 | ;;; 1) Identity mapping for bottom 2 MB physical address.
25 | ;;; 2) Map ALL available physical memory to higher memory space
26 | ;;; starting from -2GB memory space below recursive mapping. As
27 | ;;; recursive mapping occupies 512 GB and starts from #xffffff8000000000,
28 | ;;; kernel starts from #xffffff7f80000000.
29 | ;;; Identity mapping will be removed after entering 64 bit mode
30 | ;;; by calling function unmap-lower-memory.
31 | ;;;
32 | ;;; Suppose PML4 points to address A (`pml4-base` below), then there are
33 | ;;; five 4 KB memory regions to be processed by this function (note that we put
34 | ;;; identity mapping after kernel mapping as identity mapping will be unmapped):
35 | ;;; A .. A + #x0fff: Page Map Level 4
36 | ;;; A + #x1000 .. A + #x3fff: Page Directory Pointer Table for higher half mapping.
37 | ;;; A + #x2000 .. A + #x4fff: Page Directory Table for higher half mapping.
38 | ;;; A + #x3000 .. A + #x1fff: Page Directory Pointer Table for identity mapping.
39 | ;;; A + #x4000 .. A + #x2fff: Page Directory Table for identity mapping.
40 |
41 | setup-paging
42 |
43 | (equ pml4-base #x10000)
44 | (equ page-table-size 4096) ; Number of bytes occupied by a page table.
45 |
46 | ;; Page flags.
47 | (equ page-present (expt 2 0))
48 | (equ page-writable (expt 2 1))
49 | (equ page-user-accessible (expt 2 2))
50 | (equ page-write-through (expt 2 3))
51 | (equ page-cache-disable (expt 2 4))
52 | (equ page-accessed (expt 2 5))
53 | (equ page-dirty (expt 2 6))
54 | (equ page-pde.ps (expt 2 7))
55 | (equ page-global (expt 2 8))
56 | (equ page-no-execuite (expt 2 63))
57 | (equ page-table-flag (+ page-present page-writable))
58 | (equ page-entry-flag (+ page-table-flag page-pde.ps)) ; In addition to above flags, set PDE.PS for 2 MB page.
59 |
60 | (equ kernel-virtual-base #xffffff7f80000000) ; Start virtual address for higher half kernel.
61 |
62 | ;; The position to store memory size.
63 | (equ memory-size-physical-addr (+ mm-entries-physical-addr (* mm-entry-max mm-entry-size)))
64 | (equ memory-size-virtual-addr (+ kernel-virtual-base memory-size-physical-addr))
65 | ;; Maximum number of page tables.
66 | (equ page-table-end-next #x70000)
67 | (equ page-table-max (/ (- page-table-end-next pml4-base) page-table-size))
68 | (equ page-table-bitmap-virtual-addr (+ memory-size-virtual-addr 8)) ; 8 byte to store memory size.
69 | ;; In the calculation below, first 8 for bitmap-offset, second 8 because 1 bytes contains 8 bits.
70 | (equ page-frame-bitmap-virtual-addr
71 | (+ page-table-bitmap-virtual-addr 8 (ceiling page-table-max 8)))
72 | (push edx)
73 | (push ecx)
74 | (push ebx)
75 | (push edi)
76 |
77 | ;; Firstly check the size of the kernel. When kernel is firstly loaded
78 | ;; (before relocated), the memory map of our code/data below 1 MB is like:
79 | ;; 0 - some BIOS stuff
80 | ;; - kernel (starting from #x7c00)
81 | ;; - page tables (starting from pml4-base)
82 | ;; - FREE
83 | ;; - stack
84 | ;; - memory map (starting from mm-count-physical-addr)
85 | ;; - memory size (starting from memory-size-physical-addr), page table bitmap
86 | ;; and page frame bitmap
87 | ;; - other BIOS stuff
88 | ;; If kernel size is too big, code about page tables will trash
89 | ;; the kernel. So the following check is needed.
90 | ;; TODO: we need to make sure that page tables do not run into the region for
91 | ;; stack and memory map.
92 | (mov edx kernel-physical-end)
93 | (cmp edx pml4-base)
94 | (jb .page-continue)
95 | ;; If code comes to this branch, increase pml4-base appropriately.
96 | .panic
97 | (hlt)
98 | (jmp short .panic)
99 |
100 | .page-continue
101 | (call32 get-memory-size)
102 | ;; Store the memory size.
103 | (mov ecx memory-size-physical-addr)
104 | (mov (ecx) eax)
105 | (mov (ecx 4) edx)
106 | ;; TODO. So far we only handle < 4GB memory. As memory size is in
107 | ;; EDX:EAX, we ignore the value in EDX for now. Use EDX to store
108 | ;; the memory size (< 4 GB).
109 | (mov edx eax)
110 |
111 | ;; Zero out the 5 * 4 kB buffer.
112 | (mov edi pml4-base)
113 | (mov ecx #x1400)
114 | (xor eax eax)
115 | (cld)
116 | (rep stosd)
117 | (mov edi pml4-base)
118 |
119 | ;; Build the Page Map Level 4.
120 | ;; First set entry the identity mapping.
121 | (mov eax edi)
122 | (add eax #x3000) ; Address of the Page Directory Pointer Table for identity mapping.
123 | (or eax page-table-flag)
124 | (mov (edi) eax)
125 | ;; Secondly set entry for higher half mapping.
126 | (sub eax #x2000) ; Address of the Page Directory Pointer Table for higher half mapping.
127 | (mov ebx 510)
128 | (mov (ebx*8 edi) eax)
129 | (mov eax 511) ; Now starts recursive mapping.
130 | (shl eax 3)
131 | (add eax edi)
132 | (mov (eax) eax)
133 |
134 | ;; Build the Page Directory Pointer Table for identity mapping.
135 | (mov eax edi)
136 | (add eax #x4000) ; Address of the Page Directory.
137 | (or eax page-table-flag)
138 | (mov (edi #x3000) eax)
139 |
140 | ;; Build the Page Directory Table for identity mapping. Just map 2 MB.
141 | (mov eax page-entry-flag) ; Effectively point EAX to address #x0.
142 | (mov (edi #x4000) eax)
143 |
144 | ;; Build the Page Directory Pointer Table for higher half mapping.
145 | (mov edi (+ pml4-base #x1000))
146 | (mov eax edi)
147 | (add eax #x1000) ; Address of the Page Directory.
148 | (or eax page-table-flag)
149 | ;; TODO: we only map maximum 1 GB memory now. So we only handle the 2nd last entry here.
150 | (mov ebx 510) ; The second last entry in the 512 entry table.
151 | (mov (ebx*8 edi) eax)
152 |
153 | ;; Build the Page Directory Table for higher half mapping.
154 | (add edi #x1000)
155 | (mov eax page-entry-flag) ; Effectively point EAX to address #x0.
156 | .loop-page-directory-table
157 | (mov (edi) eax)
158 | (add eax #x200000) ; Increase 2 MB.
159 | (add edi 8)
160 | (cmp eax edx) ; Has all memory been mapped?
161 | (jb .loop-page-directory-table)
162 |
163 | (pop edi)
164 | (pop ebx)
165 | (pop ecx)
166 | (pop edx)
167 |
168 | (ret)))
169 |
170 | (defparameter *paging*
171 | `(
172 | ;;; Remove identity mapping of bottom 2 MB.
173 | ,@(def-fun 'unmap-lower-memory nil
174 | `(
175 | (mov rdi pml4-base)
176 | (mov qword (rdi) 0)
177 | (invlpg (abs 0))))
178 |
179 | ;; Mask to get bits 12-51 from page table entry for the physical address of the frame.
180 | (equ page-frame-mask #x000ffffffffff000)
181 |
182 | ;;; Function pointed-frame. Returns page frame address (physical).
183 | ;;; Input:
184 | ;;; RDI: page table entry address (virtual)
185 | ;;; Output:
186 | ;;; RAX: page frame address. 0 if page table entry is invalid
187 | ;;; (e.g. not present)
188 | ,@(def-fun'pointed-frame nil
189 | `(
190 | (mov rax (rdi))
191 | (test eax page-present)
192 | (je .not-present)
193 | (mov rsi page-frame-mask)
194 | (and rax rsi)
195 | (jmp short .done)
196 | .not-present
197 | (xor eax eax)
198 | .done))
199 |
200 | ;;; Function page-directory-entry-set. Return a page directory entry (PDE) given
201 | ;;; the physical frame base address and flags
202 | ;;; Input:
203 | ;;; RDI: page frame base address (should be aligned at 2 MB boundary) and
204 | ;;; smaller than 2^52 (due to x86-64 architecture limitation)
205 | ;;; RSI: page flags
206 | ;;; Output:
207 | ;;; RAX: the page directory entry (PDE).
208 | ;;; Technical details for 2 MB PDE can be found in section 5.3.4
209 | ;;; (2-Mbyte Page Translation) of [1], especially Figure 5-25. "2-Mbyte PDE - Long Mode"
210 | ,@(def-fun 'page-directory-entry-set nil
211 | `(
212 | (equ pde-physical-base-address-mask #xfff00000001fffff)
213 | (mov rdx pde-physical-base-address-mask)
214 | (test rdi rdx)
215 | (jne .panic)
216 | (or rdi rsi)
217 | (mov rax rdi)
218 | (jmp short .done)
219 | .invalid-physical-base-address
220 | .panic
221 | (hlt)
222 | (jmp short .panic)
223 | .done))
224 | ))
225 |
--------------------------------------------------------------------------------
/cc/test-cc.lisp:
--------------------------------------------------------------------------------
1 | ;;;; -*- Mode: Lisp -*-
2 | ;;;; Author:
3 | ;;;; Yujian Zhang
4 | ;;;; Description:
5 | ;;;; Regression tests. Cross checked with NASM.
6 | ;;;; License:
7 | ;;;; GNU General Public License v2
8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html
9 | ;;;; Copyright (C) 2009-2018 Yujian Zhang
10 |
11 | (in-package :cc)
12 |
13 | (defun arith-test-1 (mnemonic)
14 | "Return test codes for arithmetic operations: add/and/cmp/or/sub/xor."
15 | `((,mnemonic al 8)
16 | (,mnemonic ax 1000)
17 | (,mnemonic bl 3)
18 | (,mnemonic byte (msg) 4)
19 | (,mnemonic bx 1234)
20 | (,mnemonic word (msg) 5678)
21 | (,mnemonic cx 9)
22 | (,mnemonic word (msg) 12)
23 | (,mnemonic al bl)
24 | (,mnemonic (msg) ch)
25 | (,mnemonic cx bx)
26 | (,mnemonic (msg) dx)
27 | (,mnemonic ch (msg))
28 | (,mnemonic dx (msg))))
29 |
30 | (defun arith-test-2 (mnemonic)
31 | "Return test codes for arithmetic operations: div/mul/neg/not"
32 | `((,mnemonic ch)
33 | (,mnemonic byte (msg))
34 | (,mnemonic di)
35 | (,mnemonic word (bp si 3))))
36 |
37 | (defun shift-test (mnemonic)
38 | "Return test codes for shift operations: shl/shr."
39 | `((,mnemonic dh 1)
40 | (,mnemonic byte (msg) 1)
41 | (,mnemonic dh cl)
42 | (,mnemonic byte (msg) cl)
43 | (,mnemonic dh 5)
44 | (,mnemonic byte (msg) 5)
45 | (,mnemonic dx 1)
46 | (,mnemonic word (msg) 1)
47 | (,mnemonic dx cl)
48 | (,mnemonic word (msg) cl)
49 | (,mnemonic dx 5)
50 | (,mnemonic word (msg) 5)))
51 |
52 | (defparameter *arith-asm*
53 | `((bits 16)
54 | (org #x7c00)
55 |
56 | ,@(arith-test-1 'add)
57 | ,@(arith-test-1 'and)
58 | ,@(arith-test-1 'cmp)
59 | (dec bx)
60 | (dec eax)
61 | (dec dl)
62 | (dec byte (msg))
63 | (dec word (bp si 3))
64 | (dec dword (msg))
65 | ,@(arith-test-2 'div)
66 | (inc bx)
67 | (inc eax)
68 | (inc dl)
69 | (inc byte (msg))
70 | (inc word (bp si 3))
71 | (inc dword (msg))
72 | ,@(arith-test-2 'mul)
73 | ,@(arith-test-2 'neg)
74 | ,@(arith-test-2 'not)
75 | ,@(arith-test-1 'or)
76 | ,@(shift-test 'shl)
77 | ,@(shift-test 'shr)
78 | ,@(arith-test-1 'sub)
79 | (test al 8)
80 | (test ax 1000)
81 | (test bl 3)
82 | (test byte (msg) 4)
83 | (test bx 1234)
84 | (test (msg) 5678)
85 | (test al bl)
86 | (test (msg) ch)
87 | (test cx bx)
88 | (test (msg) dx)
89 | ,@(arith-test-1 'xor)
90 |
91 | (bits 32)
92 | (add ax 1000)
93 | (dec dx)
94 | (dec ebp)
95 | (inc dx)
96 | (inc ebp)
97 |
98 | (bits 64)
99 | (addressing abs)
100 | (adc rax #x12345)
101 | (add ebx 1000)
102 | (add rax #x10010203)
103 | ; TODO: use special encoding, as noted in x86-64-syntax.lisp.
104 | ;(add rax 10)
105 | (add rbx 267)
106 | (add r15 #x123456)
107 | (add r10d 3)
108 | (add sil 6)
109 | (add r9l 8)
110 | (add r10 rbx)
111 | (add rsi (rbx))
112 | (dec di)
113 | (dec ecx)
114 | (dec r10)
115 | (div ebx)
116 | (inc di)
117 | (inc ecx)
118 | (inc r10)
119 | (mul dword (rbx))
120 | (neg rcx)
121 | (not qword (rbx))
122 | (sbb rbx rdx)
123 | (test rax 123456789)
124 | (test r12 11223344)
125 | (test qword (rdi) 9966)
126 | (test rdx rdi)
127 | (test (rdx) r9)
128 |
129 | msg (db "Hello World! ")
130 | endmsg)
131 | "Arithmetic instructions are tested separately.")
132 |
133 | (defparameter *arith-code*
134 | '(4 8 5 232 3 128 195 3 128 6 102 126 4 129 195 210 4 129 6 102 126
135 | 46 22 131 193 9 131 6 102 126 12 0 216 0 46 102 126 1 217 1 22 102
136 | 126 2 46 102 126 3 22 102 126 36 8 37 232 3 128 227 3 128 38 102
137 | 126 4 129 227 210 4 129 38 102 126 46 22 131 225 9 131 38 102 126
138 | 12 32 216 32 46 102 126 33 217 33 22 102 126 34 46 102 126 35 22
139 | 102 126 60 8 61 232 3 128 251 3 128 62 102 126 4 129 251 210 4 129
140 | 62 102 126 46 22 131 249 9 131 62 102 126 12 56 216 56 46 102 126
141 | 57 217 57 22 102 126 58 46 102 126 59 22 102 126 75 102 72 254 202
142 | 254 14 102 126 255 74 3 102 255 14 102 126 246 245 246 54 102 126
143 | 247 247 247 114 3 67 102 64 254 194 254 6 102 126 255 66 3 102 255
144 | 6 102 126 246 229 246 38 102 126 247 231 247 98 3 246 221 246 30
145 | 102 126 247 223 247 90 3 246 213 246 22 102 126 247 215 247 82 3
146 | 12 8 13 232 3 128 203 3 128 14 102 126 4 129 203 210 4 129 14 102
147 | 126 46 22 131 201 9 131 14 102 126 12 8 216 8 46 102 126 9 217 9
148 | 22 102 126 10 46 102 126 11 22 102 126 208 230 208 38 102 126 210
149 | 230 210 38 102 126 192 230 5 192 38 102 126 5 209 226 209 38 102
150 | 126 211 226 211 38 102 126 193 226 5 193 38 102 126 5 208 238 208
151 | 46 102 126 210 238 210 46 102 126 192 238 5 192 46 102 126 5 209
152 | 234 209 46 102 126 211 234 211 46 102 126 193 234 5 193 46 102 126
153 | 5 44 8 45 232 3 128 235 3 128 46 102 126 4 129 235 210 4 129 46
154 | 102 126 46 22 131 233 9 131 46 102 126 12 40 216 40 46 102 126 41
155 | 217 41 22 102 126 42 46 102 126 43 22 102 126 168 8 169 232 3 246
156 | 195 3 246 6 102 126 4 247 195 210 4 247 6 102 126 46 22 132 216
157 | 132 46 102 126 133 217 133 22 102 126 52 8 53 232 3 128 243 3 128
158 | 54 102 126 4 129 243 210 4 129 54 102 126 46 22 131 241 9 131 54
159 | 102 126 12 48 216 48 46 102 126 49 217 49 22 102 126 50 46 102 126
160 | 51 22 102 126 102 5 232 3 102 74 77 102 66 69 72 21 69 35 1 0 129
161 | 195 232 3 0 0 72 5 3 2 1 16 72 129 195 11 1 0 0 73 129 199 86 52
162 | 18 0 65 131 194 3 64 128 198 6 65 128 193 8 73 1 218 72 3 51 102
163 | 255 207 255 201 73 255 202 247 243 102 255 199 255 193 73 255 194
164 | 247 35 72 247 217 72 247 19 72 25 211 72 169 21 205 91 7 73 247
165 | 196 48 65 171 0 72 247 7 238 38 0 0 72 133 250 76 133 10 72 101
166 | 108 108 111 32 87 111 114 108 100 33 32))
167 |
168 | (defparameter *misc-asm*
169 | '((bits 16)
170 | (org #x7c00)
171 |
172 | start
173 |
174 | (align 4)
175 | (bt edx 29)
176 | (align 4)
177 | (btc eax 28)
178 | (btr ebx 27)
179 | (bts ecx 26)
180 | (call msg)
181 | (clc)
182 | (cld)
183 | (cli)
184 | (hlt)
185 | (in al 3)
186 | (in ax 4)
187 | (in al dx)
188 | (in ax dx)
189 | (int 3)
190 | (int #x10)
191 | .loop
192 | (jcxz .loop)
193 | (je .loop)
194 | (jmp short .loop)
195 | (jmp near meta-msg)
196 | (lgdt (msg))
197 | (lidt (msg))
198 | (lldt dx)
199 | (lldt (msg))
200 | (lodsb)
201 | (lodsw)
202 | (lodsd)
203 | (loop .loop)
204 | ;; Segment override prefix.
205 | (es mov bl (di))
206 | (ds mov byte (si) #xff)
207 | (mov ah 9)
208 | ;; TODO: currently if we use AL in place of BL, generated code is not as efficient as that of NASM;
209 | ;; Will add more instructions e.g. mov al, moffset.
210 | (mov bl (msg))
211 | (mov (msg) bh)
212 | (mov bx (- endmsg msg))
213 | (mov ax cx)
214 | (mov (msg) bx)
215 | (mov cx (#x1c7b))
216 | (mov byte (msg) 42)
217 | (mov word (msg) 123)
218 | (mov es bx)
219 | (mov ax cs)
220 | (mov cr0 eax)
221 | (mov eax cr0)
222 | (movzx ax (msg))
223 | (movzx edx cx)
224 | (movzx eax byte (msg))
225 | (movzx eax word (msg))
226 | (nop)
227 | (out 3 al)
228 | (out 4 ax)
229 | (out dx al)
230 | (out dx ax)
231 | (push cx)
232 | (push edx)
233 | (push cs)
234 | (push ss)
235 | (push ds)
236 | (push es)
237 | (pushf)
238 | (pushfd)
239 | (pop dx)
240 | (pop ecx)
241 | (pop ss)
242 | (pop ds)
243 | (pop es)
244 | (popf)
245 | (popfd)
246 | (rdmsr)
247 | (rep movsb)
248 | (rep movsw)
249 | (rep movsd)
250 | (ret)
251 | (stc)
252 | (std)
253 | (sti)
254 | (stosb)
255 | (stosw)
256 | (stosd)
257 | (wrmsr)
258 |
259 | (bits 64)
260 | (addressing rel)
261 | (bsf ax bx)
262 | (bsf ecx edx)
263 | (bsf r10 (msg))
264 | (bsr ax r8w)
265 | (bsr r10d r9d)
266 | (bsr rax r12)
267 | (bswap ebx)
268 | (bswap rax)
269 | (bswap r10)
270 | (bt edx 29)
271 | (bt edx ecx)
272 | (bt rdx 30)
273 | (bt rax rbx)
274 | (btc rax 29)
275 | (btr rbx 28)
276 | (bts rcx 27)
277 | (call msg)
278 | (cmova ax bx)
279 | (cmovc eax edx)
280 | (cmove rdx r10)
281 | (cmpxchg cl dl)
282 | (cmpxchg cx dx)
283 | (cmpxchg edi edx)
284 | (cmpxchg rcx r10)
285 | (cmpxchg8b (rbx))
286 | (cmpxchg16b (rbx))
287 | (invlpg (abs 0))
288 | (iretq)
289 | (jb near msg)
290 | (jmp near rbx)
291 | (jmp near msg)
292 | (jmp near (msg))
293 | (leave)
294 | (lgdt (msg))
295 | (lidt (msg))
296 | (lodsq)
297 | (mov eax #x1234)
298 | (mov rsp #x90000)
299 | (mov rax #x1122334455667788)
300 | (mov rcx (msg))
301 | (mov rcx (abs msg))
302 | (mov rdi (abs #xb8000))
303 | (mov rbx rcx)
304 | (mov rax -1)
305 | (mov qword (msg) 1019)
306 | ;; Following two cases test that REX prefix should follow legacy prefixes.
307 | (mov ax r8w)
308 | (fs mov r9w (msg)) ; Not sure whether this case is useful or not.
309 | ;; Following case tests the case that no bit is set for REX prefix.
310 | (mov dil 19)
311 | (movsq)
312 | (movzx r10 al)
313 | (movzx eax byte (msg))
314 | (movzx rdx word (msg))
315 | (push r10)
316 | (pushfq)
317 | (pop rax)
318 | (popcnt r11 (msg))
319 | (popfq)
320 | (sal ebx 1)
321 | (sar edx cl)
322 | (seta ah)
323 | (setz (msg))
324 | (shl r10 6)
325 | (shr qword (msg) 8)
326 | (rep stosq)
327 | (syscall)
328 | (sysret)
329 | (xadd cl dl)
330 | (xadd cx dx)
331 | (xadd edi edx)
332 | (xadd rcx r10)
333 | (xchg ax bx)
334 | (xchg cx ax)
335 | (xchg eax ebx)
336 | (xchg ecx eax)
337 | (xchg rax rbx)
338 | (xchg rcx rax)
339 | ;; (xchg a b) is equivalent to NASM's xchg b, a.
340 | ;; They are semantically equivalent anyway.
341 | (xchg al cl)
342 | (xchg cx bx)
343 | (xchg edx ebx)
344 | (xchg r10 r15)
345 |
346 | ;; Put these short jump instructions here to avoid the very long jump.
347 | ;; TODO: check near version?
348 | (jecxz msg)
349 | (jrcxz msg)
350 |
351 | (equ hi 4)
352 | meta-msg (dw msg)
353 | (resb 4)
354 | msg (db "Hello World! ")
355 | endmsg
356 | (times 3 db 0)
357 | (dw #xaa55)
358 | (resw 3)
359 | (dd 123456 7891011)
360 | (resd 2)
361 | (dq 3372036854775808)
362 | (resq 1))
363 | "Miscellaneous instructions.")
364 |
365 | (defparameter *misc-code*
366 | '(102 15 186 226 29 144 144 144 102 15 186 248 28 102 15 186 243 27 102 15 186
367 | 233 26 232 250 1 248 252 250 244 228 3 229 4 236 237 204 205 16 227 254 116
368 | 252 235 250 233 222 1 15 1 22 20 126 15 1 30 20 126 15 0 210 15 0 22 20 126
369 | 172 173 102 173 226 223 38 138 29 62 198 4 255 180 9 138 30 20 126 136 62 20
370 | 126 187 13 0 137 200 137 30 20 126 139 14 123 28 198 6 20 126 42 199 6 20 126
371 | 123 0 142 195 140 200 15 34 192 15 32 192 15 182 6 20 126 102 15 183 209 102
372 | 15 182 6 20 126 102 15 183 6 20 126 144 230 3 231 4 238 239 81 102 82 14 22 30
373 | 6 156 102 156 90 102 89 23 31 7 157 102 157 15 50 243 164 243 165 243 102 165
374 | 195 249 253 251 170 171 102 171 15 48 102 15 188 195 15 188 202 76 15 188 21
375 | 72 1 0 0 102 65 15 189 192 69 15 189 209 73 15 189 196 15 203 72 15 200 73 15
376 | 202 15 186 226 29 15 163 202 72 15 186 226 30 72 15 163 216 72 15 186 248 29
377 | 72 15 186 243 28 72 15 186 233 27 232 15 1 0 0 102 15 71 195 15 66 194 73 15
378 | 68 210 15 176 209 102 15 177 209 15 177 215 76 15 177 209 15 199 11 72 15 199
379 | 11 15 1 60 37 0 0 0 0 72 207 15 130 223 0 0 0 255 227 233 216 0 0 0 255 37 210
380 | 0 0 0 201 15 1 21 202 0 0 0 15 1 29 195 0 0 0 72 173 184 52 18 0 0 188 0 0 9 0
381 | 72 184 136 119 102 85 68 51 34 17 72 139 13 166 0 0 0 72 139 12 37 20 126 0 0
382 | 72 139 60 37 0 128 11 0 72 137 203 72 199 192 255 255 255 255 72 199 5 129 0 0
383 | 0 251 3 0 0 102 68 137 192 100 102 68 139 13 116 0 0 0 64 183 19 72 165 76 15
384 | 182 208 15 182 5 100 0 0 0 72 15 183 21 92 0 0 0 65 82 156 88 243 76 15 184 29
385 | 79 0 0 0 157 209 227 211 250 15 151 196 15 148 5 64 0 0 0 73 193 226 6 72 193
386 | 45 52 0 0 0 8 243 72 171 15 5 15 7 15 192 209 102 15 193 209 15 193 215 76 15
387 | 193 209 102 147 102 145 147 145 72 147 72 145 134 200 102 135 217 135 218 77
388 | 135 250 103 227 8 227 6 20 126 0 0 0 0 72 101 108 108 111 32 87 111 114 108
389 | 100 33 32 0 0 0 85 170 0 0 0 0 0 0 64 226 1 0 67 104 120 0 0 0 0 0 0 0 0 0 0 0
390 | 230 130 217 250 11 0 0 0 0 0 0 0 0 0))
391 |
392 | (defparameter *address-asm*
393 | '((org #x7c00)
394 |
395 | (bits 16)
396 | (mov (bp) es)
397 | (mov (bx si) ds)
398 | (mov (bx di) es)
399 | (mov (bp si) ds)
400 | (mov (bp di) ss)
401 | (mov (si) ds)
402 | (mov (di) cs)
403 | (mov (32330) ds)
404 | (mov (msg) ds)
405 | (mov (bx) cs)
406 | (mov (bx si 1) ds)
407 | (mov (bx di 2) es)
408 | (mov (bp si 3) ds)
409 | (mov (bp di 4) ss)
410 | (mov (si 5) ds)
411 | (mov (di 6) cs)
412 | (mov (bp 7) ds)
413 | (mov (bx 8) cs)
414 | (mov ds (di))
415 | (mov ds (bx si 1001))
416 | (mov es (bx di 1002))
417 | (mov ds (bp si 1003))
418 | (mov ss (bp di 1004))
419 | (mov ds (si 1005))
420 | (mov es (di 1006))
421 | (mov ds (bp 1007))
422 | (mov es (bx 1008))
423 |
424 | (bits 32)
425 | (mov (ebp) ebx)
426 | (mov (esp) ecx)
427 | (mov (123456) edx)
428 | (mov (eax) edx)
429 | (mov (ebp 36) ecx)
430 | (mov (edi 1234) edx)
431 | (mov (esi 123456) ecx)
432 | (mov (esp #x23) ebx)
433 | (mov (esp #x12345678) ecx)
434 | (mov (eax ebx) ecx)
435 | (mov (esi edi) edx)
436 | (mov (esi ebp) edx)
437 | ;; (mov (eax*2 3456) edx) ; NASM encodes as (eax eax 3456)
438 | (mov (eax*2 esi) edx)
439 | (mov (esi*2 ebp 123) edx)
440 | (mov (edi*2 ebx 8) ecx)
441 | (mov (ecx*4 ebp 123) edx)
442 | (mov (esi*4 edx 8) ecx)
443 | (mov (edx*8 ebp 123456) ebx)
444 | (mov (edi*8 ecx 8) edx)
445 |
446 | (bits 64)
447 | (mov (rbp) rbx)
448 | (mov (rsp) rcx)
449 | (mov (abs 123456) rdx)
450 | (mov (rax) rdx)
451 | (mov (rbp 36) rcx)
452 | (mov (rdi 1234) rdx)
453 | (mov (rsi 123456) rcx)
454 | (mov (rsp #x23) rbx)
455 | (mov (rsp #x12345678) rcx)
456 | (mov (rax rbx) rcx)
457 | (mov (rsi rdi) rdx)
458 | (mov (rsi rbp) rdx)
459 | ;; (mov (rax*2 3456) rdx) ; NASM encodes as (rax rax 3456)
460 | (mov (rax*2 rsi) rdx)
461 | (mov (rsi*2 rbp 123) rdx)
462 | (mov (rdi*2 rbx 8) rcx)
463 | (mov (rcx*4 rbp 123) rdx)
464 | (mov (rsi*4 rdx 8) rcx)
465 | (mov (rdx*8 rbp 123456) rbx)
466 | (mov (rdi*8 rcx 8) rdx)
467 |
468 | msg (db "Hello World! ")
469 | endmsg)
470 | "Test addressing modes.")
471 |
472 | (defparameter *address-code*
473 | '(140 70 0 140 24 140 1 140 26 140 19 140 28 140 13 140 30 74 126
474 | 140 30 5 125 140 15 140 88 1 140 65 2 140 90 3 140 83 4 140 92 5
475 | 140 77 6 140 94 7 140 79 8 142 29 142 152 233 3 142 129 234 3 142
476 | 154 235 3 142 147 236 3 142 156 237 3 142 133 238 3 142 158 239 3
477 | 142 135 240 3 137 93 0 137 12 36 137 21 64 226 1 0 137 16 137 77
478 | 36 137 151 210 4 0 0 137 142 64 226 1 0 137 92 36 35 137 140 36
479 | 120 86 52 18 137 12 24 137 20 62 137 20 46 137 20 70 137 84 117
480 | 123 137 76 123 8 137 84 141 123 137 76 178 8 137 156 213 64 226 1
481 | 0 137 84 249 8 72 137 93 0 72 137 12 36 72 137 20 37 64 226 1 0 72
482 | 137 16 72 137 77 36 72 137 151 210 4 0 0 72 137 142 64 226 1 0 72
483 | 137 92 36 35 72 137 140 36 120 86 52 18 72 137 12 24 72 137 20 62
484 | 72 137 20 46 72 137 20 70 72 137 84 117 123 72 137 76 123 8 72 137
485 | 84 141 123 72 137 76 178 8 72 137 156 213 64 226 1 0 72 137 84 249
486 | 8 72 101 108 108 111 32 87 111 114 108 100 33 32))
487 |
488 | (defparameter *bootloader-code*
489 | '(180 3 205 16 184 1 19 187 15 0 185 15 0 189 20 124 205 16 235 254
490 | 72 101 108 108 111 32 87 111 114 108 100 33 32 13 10 0 0 0 0 0 0 0
491 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
492 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
493 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
494 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
495 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
496 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
497 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
498 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
499 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
500 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
501 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
502 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
503 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
504 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
505 | 0 0 0 0 0 0 85 170))
506 |
507 | (deftest test-cc ()
508 | (check
509 | (equal (asm *address-asm*) *address-code*)
510 | (equal (asm *arith-asm*) *arith-code*)
511 | (equal (asm *misc-asm*) *misc-code*)))
512 |
--------------------------------------------------------------------------------
/cc/test.lisp:
--------------------------------------------------------------------------------
1 | ;;;; -*- Mode: Lisp -*-
2 | ;;;; Author:
3 | ;;;; Yujian Zhang
4 | ;;;; Description:
5 | ;;;; Test suite.
6 | ;;;; License:
7 | ;;;; GNU General Public License v2
8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html
9 | ;;;; Copyright (C) 2015 Yujian Zhang
10 |
11 | (in-package :cc)
12 |
13 | (deftest test ()
14 | (combine-results
15 | (test-cc)
16 | (test-abi)))
17 |
--------------------------------------------------------------------------------
/cc/unit-test.lisp:
--------------------------------------------------------------------------------
1 | ;;;; -*- Mode: Lisp -*-
2 | ;;;; Author:
3 | ;;;; Yujian Zhang
4 | ;;;; Description:
5 | ;;;; Unit test, adapted from chapter 9 of Practical Common Lisp.
6 | ;;;; License:
7 | ;;;; GNU General Public License v2
8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html
9 | ;;;; Copyright (C) 2009-2012 Yujian Zhang
10 |
11 | (in-package :cc)
12 |
13 | (defmacro with-gensyms ((&rest names) &body body)
14 | "Environment for a list of gensyms."
15 | `(let ,(loop for n in names collect `(,n (gensym)))
16 | ,@body))
17 |
18 | (defvar *test-name* nil)
19 | (defmacro deftest (name parameters &body body)
20 | "Define a test function. Within a test function we can call
21 | other test functions or use 'check' to run individual test
22 | cases."
23 | `(defun ,name ,parameters
24 | (let ((*test-name* (list ',name)))
25 | ,@body)))
26 |
27 | (defmacro check (&body forms)
28 | "Run each expression in 'forms' as a test case."
29 | `(combine-results
30 | ,@(loop for f in forms collect `(report-result ,f ',f))))
31 |
32 | (defmacro combine-results (&body forms)
33 | "Combine the results (as booleans) of evaluating 'forms' in order."
34 | (with-gensyms (result)
35 | `(let ((,result t))
36 | ,@(loop for f in forms collect `(unless ,f (setf ,result nil)))
37 | ,result)))
38 |
39 | (defun report-result (result form)
40 | "Report the results of a single test case. Called by 'check'."
41 | (format t "~:[FAIL~;pass~] ~a: ~a~%" result (car *test-name*) form)
42 | result)
43 |
44 |
--------------------------------------------------------------------------------
/cc/util.lisp:
--------------------------------------------------------------------------------
1 | ;;;; -*- Mode: Lisp -*-
2 | ;;;; Author:
3 | ;;;; Yujian Zhang
4 | ;;;; Description:
5 | ;;;; Utilities.
6 | ;;;; License:
7 | ;;;; GNU General Public License v2
8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html
9 | ;;;; Copyright (C) 2009-2012 Yujian Zhang
10 |
11 | (in-package :cc)
12 |
13 | (defmacro aif (test-form then-form &optional else-form)
14 | "Anaphoric variant of if. From ON LISP."
15 | `(let ((it ,test-form))
16 | (if it ,then-form ,else-form)))
17 |
18 | (defmacro acond (&rest clauses)
19 | "Anaphoric variant of cond. From ON LISP."
20 | (if (null clauses)
21 | nil
22 | (let ((cl1 (car clauses))
23 | (sym (gensym)))
24 | `(let ((,sym ,(car cl1)))
25 | (if ,sym
26 | (let ((it ,sym)) ,@(cdr cl1))
27 | (acond ,@(cdr clauses)))))))
28 |
29 | (defun str (&rest args)
30 | "Take any number of arguments and concatenates their printed
31 | representations into a string. From ON LISP."
32 | (with-output-to-string (s)
33 | (dolist (a args) (princ a s))))
34 |
35 | (defun symb (&rest args)
36 | "Takes one or more arguments and returns the symbol whose printname
37 | is their concatenation. From ON LISP."
38 | (values (intern (apply #'str args))))
39 |
40 | (defun mklist (obj)
41 | "Returns obj if it is already a list; otherwise lispy it. From ON LISP."
42 | (if (listp obj)
43 | obj
44 | (list obj)))
45 |
46 | (defun repeat-element (n element)
47 | (loop for i from 0 below n collect element))
48 |
49 | (defun repeat-list (n list)
50 | (case n
51 | (0 nil)
52 | (1 list)
53 | (t (if (< n 0)
54 | (error "repeat-list: invalid n=~A" n)
55 | (append list (repeat-list (1- n) list))))))
56 |
57 | (defun assoc* (&rest args)
58 | "Return the cdr of the result of assoc."
59 | (cdr (apply #'assoc args)))
60 |
61 | (defun segment (list n)
62 | "Segment list with each sublist containing n elements."
63 | (cond
64 | ((null list) nil)
65 | ((<= (length list) n) (list list))
66 | (t (append (list (subseq list 0 n)) (segment (nthcdr n list) n)))))
67 |
68 | (defun printable? (c)
69 | "Returns T if char (as integer) is printable."
70 | (<= 32 c 126)) ; Seems that graphic-char-p allows more chars as printable.
71 |
72 | (defun pp-char (c)
73 | "Returns the character form of c if printable; otherwise ."
74 | (if (printable? c) (code-char c) #\.))
75 |
76 | (defun pp-hex (s)
77 | "Pretty print S (stream of bytes) in hexadecimal manner. Output is
78 | same as Emacs hexl-mode."
79 | (format
80 | t "87654321 0011 2233 4455 6677 8899 aabb ccdd eeff 0123456789abcdef~%")
81 | (let ((ss (segment s 16)))
82 | (loop for i from 0 below (length ss)
83 | do (format t "~8,'0X: ~{~{~2,'0X~} ~}~51T~{~c~}~%"
84 | (* i 16) (segment (nth i ss) 2)
85 | (mapcar #'pp-char (nth i ss))))))
86 |
--------------------------------------------------------------------------------
/cc/vga-text.lisp:
--------------------------------------------------------------------------------
1 | ;;;; -*- Mode: Lisp -*-
2 | ;;;; Author:
3 | ;;;; Yujian Zhang
4 | ;;;; Description:
5 | ;;;; VGA text mode functions.
6 | ;;;; BIOS interruptions are not used.
7 | ;;;; License:
8 | ;;;; GNU General Public License v2
9 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html
10 | ;;;; Copyright (C) 2009-2015 Yujian Zhang
11 |
12 | (in-package :cc)
13 |
14 | (defparameter *vga-text-constants*
15 | `(
16 | ;;; VGA text mode related constants.
17 |
18 | ;;; ASCII characters.
19 | (equ ascii-backspace #x08)
20 | (equ ascii-linefeed #x0a)
21 | (equ ascii-space #x20)
22 | ))
23 |
24 | (defparameter *vga-text-16*
25 | ;;; VGA text output code in 16 bit mode, based on http://wiki.osdev.org/Babystep4
26 | ;;; We only implement minimal set of features in 16 bit mode as the main intention
27 | ;;; is only to print error messages.
28 | `(
29 | ;;; Initialize text mode. Call it before calling any text mode functions.
30 | init-text-mode-16
31 | (xor ax ax)
32 | (mov ds ax)
33 | (mov ax #xb800) ; Text video memory
34 | (mov es ax)
35 | (call clear-16)
36 | (ret)
37 |
38 | ;;; Clear screen.
39 | clear-16
40 | (movzx ax (text-rows-16))
41 | (movzx dx (text-cols-16))
42 | (mul dx)
43 | (movzx ecx ax) ; All screen to be cleared.
44 | (mov ax #x0f20) ; Black background, white foreground, space char.
45 | (mov di 0)
46 | (rep stosw)
47 | (ret)
48 |
49 | ;;; Function println-16. Write a string and start a new line.
50 | ;;; It is equivalent to calling print twice: first to print the string,
51 | ;;; and then print CR/LF.
52 | ;;; Input:
53 | ;;; DS:SI: points to the starting address of the 0 terminated string.
54 | ;;; Output: None
55 | ;;; Modified registers: same as putchar
56 | ;;; Global variables: same as putchar
57 | println-16
58 | (call print-16)
59 | (call printlf-16)
60 | (ret)
61 |
62 | ;;; Function printlf-16. Print crlf only.
63 | ;;; Input: None
64 | ;;; Output: None
65 | ;;; Modified reisters: None
66 | ;;; Global variables: text-x-16, text-y-16
67 | printlf-16
68 | (add byte (text-y-16) 1) ; Down one row
69 | (mov byte (text-x-16) 0) ; Back to left
70 | (ret)
71 |
72 | do-char-16
73 | (call putchar-16)
74 | ;;; Function print-16. Write string to screen.
75 | ;;; Input:
76 | ;;; DS:SI: points to the starting address of the 0 terminated string.
77 | ;;; Output: None
78 | ;;; Modified registers: same as putchar
79 | ;;; Global variables: same as putchar
80 | print-16
81 | (lodsb) ; Load string char to AL
82 | (cmp al 0) ; 0 terminated string like C.
83 | (jne do-char-16)
84 | (ret)
85 |
86 | ;;; Function putchar-16. Writer character at cursor position.
87 | ;;; Input:
88 | ;;; AL: character to display
89 | ;;; Output: None
90 | ;;; Modified registers: AX, BX, CX, DX, DI
91 | ;;; Global variables: text-x-16, text-y-16, text-cols-16
92 | putchar-16
93 | (mov ah #xf) ; Attribute: white on black
94 | (mov cx ax) ; Save char/attribute
95 | (movzx ax (text-y-16))
96 | (movzx dx (text-cols-16))
97 | (shl dx 1) ; 2 bytes for one character
98 | (mul dx)
99 | (movzx bx (text-x-16))
100 | (shl bx 1)
101 | (mov di 0) ; Start of video memory
102 | (add di ax) ; Add y offset
103 | (add di bx) ; Add x offset
104 | (mov ax cx) ; Restore char/attribute
105 | (stosw) ; Write char/atribute
106 | (add byte (text-x-16) 1) ; Advance to right
107 | (ret)
108 |
109 | text-rows-16 (db 25) ;; Number of rows in text mode.
110 | text-cols-16 (db 80) ;; Number of columns in text mode.
111 | text-x-16 (db 0) ;; Position x in text mode [0, text-cols-16)
112 | text-y-16 (db 0) ;; Position y in text mode [0, text-rows-16)
113 | ))
114 |
115 | (defparameter *vga-text*
116 | ;;; VGA text output in 64 bit mode.
117 | `(
118 | (equ vga-video-memory (+ kernel-virtual-base #xb8000))
119 | ;; Blue background, white foreground, space char.
120 | (equ background-filling #x1f201f20)
121 |
122 | ;;; Clear screen.
123 | ,@(def-fun 'clear nil
124 | `(
125 | (movzx eax byte (text-rows))
126 | (movzx edx byte (text-cols))
127 | (mul edx)
128 | (shr eax 1)
129 | (mov ecx eax) ; All screen to be cleared.
130 | (mov eax background-filling)
131 | (mov rdi vga-video-memory)
132 | (rep stosd)
133 | (mov byte (text-x) 0)
134 | (mov byte (text-y) 0)
135 | ,@(call-function 'set-cursor)))
136 |
137 | ;;; Function println. Write a string and start a new line.
138 | ;;; It is equivalent to calling print twice: first to print the string,
139 | ;;; and then print CR/LF.
140 | ;;; Input:
141 | ;;; RSI: points to the starting address of the 0 terminated string.
142 | ;;; Output: None
143 | ;;; Modified registers: same as putchar
144 | ;;; Global variables: same as putchar
145 | ,@(def-fun 'println nil
146 | `(
147 | ,@(call-function 'print)
148 | ,@(call-function 'printlf)))
149 |
150 | ;;; Function printlf. Print crlf only.
151 | ;;; Input: None
152 | ;;; Output: None
153 | ;;; Modified registers: EAX
154 | ;;; Global variables: text-x, text-y
155 | ,@(def-fun 'printlf nil
156 | `(
157 | (inc byte (text-y)) ; Down one row
158 | (mov byte (text-x) 0) ; Back to left
159 | (mov al (text-y))
160 | (cmp al (text-rows))
161 | (jb .done)
162 | ,@(call-function 'scroll-up)
163 | .done
164 | ,@(call-function 'set-cursor)))
165 |
166 | ;;; Function print. Write string to screen.
167 | ;;; Input:
168 | ;;; RDI: points to the starting address of the 0 terminated string.
169 | ;;; Output: None
170 | ;;; Modified registers: same as putchar
171 | ;;; Global variables: same as putchar
172 | ,@(def-fun 'print nil
173 | `(
174 | (mov rsi rdi)
175 | .start
176 | (lodsb) ; Load string char to AL
177 | (cmp al 0) ; 0 terminated string like C.
178 | (je .done)
179 | (mov dil al)
180 | ,@(call-function 'putchar)
181 | (jmp short .start)
182 | .done
183 | ))
184 |
185 | ;;; Function putchar. Writer character at cursor position.
186 | ;;; Input:
187 | ;;; DIL: character to display
188 | ;;; Output: None
189 | ;;; Modified registers: RAX, RCX, RDX, RDI, R8, R9
190 | ;;; Global variables: text-x, text-y, text-cols
191 | ,@(def-fun 'putchar nil
192 | `(
193 | (cmp dil ascii-linefeed)
194 | (je .next-line)
195 | (mov r8d #x1f00) ; Attribute: white on blue
196 | (mov r8l dil) ; Save char/attribute
197 | (movzx eax byte (text-y))
198 | (movzx edx byte (text-cols))
199 | (shl edx 1) ; 2 bytes for one character
200 | (mul edx)
201 | (movzx r9d byte (text-x))
202 | (shl r9d 1)
203 | (mov rdi vga-video-memory) ; Start of video memory
204 | (add rdi rax) ; Add y offset
205 | (add rdi r9) ; Add x offset
206 | (mov ax r8w) ; Restore char/attribute
207 | (stosw) ; Write char/atribute
208 | (inc byte (text-x) 1) ; Advance to right
209 | (mov al (text-x))
210 | (cmp al (text-cols))
211 | (je .next-line)
212 | (jmp short .done)
213 | .next-line
214 | ,@(call-function 'printlf)
215 | .done
216 | ,@(call-function 'set-cursor)))
217 |
218 | ;;; Function scroll-up. Scroll the screen up one line.
219 | ;;; Input: None
220 | ;;; Output: None
221 | ;;; Modified registers: RAX, RCX, RDX, RDI, RSI
222 | ;;; Global variables: text-x, text-y, text-rows, text-cols
223 | ,@(def-fun 'scroll-up '(rbx)
224 | '(
225 | ;; Copy rows from (1 to text-rows - 1) to (0 to text-fows - 2)
226 | (movzx ebx byte (text-cols))
227 | (movzx eax byte (text-rows))
228 | (dec eax) ; Only copy text-rows - 1 lines.
229 | (mul ebx)
230 | (shr eax 1) ; 2 bytes per character, write 4 bytes with movsd
231 | (shl ebx 1) ; Number of bytes per line.
232 | (mov rdi vga-video-memory)
233 | (mov rsi rdi)
234 | (add rsi rbx)
235 | (mov ecx eax)
236 | (cld)
237 | ;; TODO: change to movsq
238 | (rep movsd)
239 | ;; Clear the last line.
240 | (mov eax background-filling)
241 | (shr ebx 2) ; As we're using stosd, divide by 4.
242 | (mov ecx ebx)
243 | (rep stosd)
244 | ;; Reset the y position to the last line.
245 | (dec byte (text-y))))
246 |
247 | ;;; Function backspace-char. Remove one character before cursor,
248 | ;;; and move cursor one character back.
249 | ,@(def-fun 'backspace-char nil
250 | `(
251 | ;; If the cursor just follows prompt (e.g. REPL> ), then backspace
252 | ;; does nothing.
253 | (cmp byte (text-x) prompt-length)
254 | (jbe .done)
255 | ;; First go back one character and write a space.
256 | (dec byte (text-x))
257 | (mov dil ascii-space)
258 | ,@(call-function 'putchar)
259 | ;; Go back once more and set cursor.
260 | (dec byte (text-x))
261 | ,@(call-function 'set-cursor)
262 | .done
263 | ))
264 |
265 | ;;; Function set-cursor. Set VGA hardware cursor.
266 | ;;; Input: based on text-xy, text-y
267 | ;;; Output: None
268 | ;;; Modified registers: RAX, RCX, RDX, RDI
269 | ;;; Global variables: text-x, text-y, text-cols
270 | ;;; Based on http://www.brokenthorn.com/Resources/OSDev10.html
271 | (equ crt-index-reg #x3d4)
272 | (equ crt-data-reg #x3d5)
273 | (equ cursor-location-high #xe)
274 | (equ cursor-location-low #xf)
275 | ,@(def-fun 'set-cursor nil
276 | `(
277 | ;; Get current cursor position. Note that we only care about the
278 | ;; location, not the memory (as in putchar). So following equation
279 | ;; is used: location = text-x + text-y * text-cols
280 | (movzx eax byte (text-y))
281 | (movzx edx byte (text-cols))
282 | (mul edx)
283 | (movzx ecx byte (text-x))
284 | (add ecx eax)
285 | ;; Set low byte index to vga register.
286 | (mov al cursor-location-low)
287 | (mov dx crt-index-reg)
288 | (out dx al)
289 | (mov al cl)
290 | (mov dx crt-data-reg)
291 | (out dx al)
292 | ;; Set high byte index to vga register.
293 | (mov al cursor-location-high)
294 | (mov dx crt-index-reg)
295 | (out dx al)
296 | (mov al ch)
297 | (mov dx crt-data-reg)
298 | (out dx al)))
299 |
300 | text-rows (db 25) ;; Number of rows in text mode.
301 | text-cols (db 80) ;; Number of columns in text mode.
302 | text-x (db 0) ;; Position x in text mode [0, text-cols)
303 | text-y (db 0) ;; Position y in text mode [0, text-rows)
304 | ))
305 |
--------------------------------------------------------------------------------
/cc/x86-64-syntax.lisp:
--------------------------------------------------------------------------------
1 | ;;;; -*- Mode: Lisp -*-
2 | ;;;; Author:
3 | ;;;; Yujian Zhang
4 | ;;;; Description:
5 | ;;;; Syntax tables for x86-64.
6 | ;;;; References:
7 | ;;;; [1] Intel 64 and IA-32 Architectures Software Developer's Manual
8 | ;;;; Volume 2, Instruction Set Reference, A-Z. June 2015
9 | ;;;; License:
10 | ;;;; GNU General Public License v2
11 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html
12 | ;;;; Copyright (C) 2009-2015 Yujian Zhang
13 |
14 | (in-package :cc)
15 |
16 | (defun arith-syntax-1 (mnemonic 64bit-only?)
17 | "Return syntax table for arithmetic operations:
18 | adc/add/and/cmp/or/sbb/sub/xor."
19 | (let ((base ; Base opcode for operation on r/m8 r8.
20 | (ecase mnemonic
21 | (adc #x10) (add #x00) (and #x20) (cmp #x38)
22 | (or #x08) (sbb #x18) (sub #x28) (xor #x30)))
23 | (opcode ; Opcode used when one operand is immediate.
24 | (ecase mnemonic
25 | (adc '/2) (add '/0) (and '/4) (cmp '/7)
26 | (or '/1) (sbb '/3) (sub '/5) (xor '/6))))
27 | (if 64bit-only?
28 | `(;; TODO: For imm8, encode with imm8 with generic r64
29 | ;; (instead of rax) seems to save 3 bytes.
30 | ((,mnemonic rax imm32) . (rex.w ,(+ base #x05) id))
31 | ((,mnemonic (r/m64 r64) (imm32 imm16)) . (rex.w #x81 ,opcode id))
32 | ((,mnemonic qword m (imm32 imm16)) . (rex.w #x81 ,opcode id))
33 | ((,mnemonic (r/m64 r64) imm8) . (rex.w #x83 ,opcode ib))
34 | ((,mnemonic qword m imm8) . (rex.w #x83 ,opcode ib))
35 | ((,mnemonic (r/m64 r64 m) r64) . (rex.w ,(+ base #x01) /r))
36 | ((,mnemonic r64 (r/m64 r64 m)) . (rex.w ,(+ base #x03) /r)))
37 | `(((,mnemonic al imm8) . (,(+ base #x04) ib))
38 | ((,mnemonic ax imm16) . (o16 ,(+ base #x05) iw))
39 | ((,mnemonic eax imm32) . (o32 ,(+ base #x05) id))
40 | ((,mnemonic (r/m8 r8) imm8) . (#x80 ,opcode ib))
41 | ((,mnemonic byte m imm8) . (#x80 ,opcode ib))
42 | ((,mnemonic (r/m16 r16) imm8) . (o16 #x83 ,opcode ib))
43 | ((,mnemonic (r/m32 r32) imm8) . (o32 #x83 ,opcode ib))
44 | ((,mnemonic word m imm8) . (o16 #x83 ,opcode ib))
45 | ((,mnemonic dword m imm8) . (o32 #x83 ,opcode ib))
46 | ((,mnemonic (r/m16 r16) imm16) . (o16 #x81 ,opcode iw))
47 | ((,mnemonic word m imm16) . (o16 #x81 ,opcode iw))
48 | ((,mnemonic (r/m32 r32) (imm32 imm16)) . (o32 #x81 ,opcode id))
49 | ((,mnemonic dword m (imm32 imm16)) . (o32 #x81 ,opcode id))
50 | ((,mnemonic r/m8 r8) . (,base /r))
51 | ((,mnemonic (r/m16 r16 m) r16) . (o16 ,(+ base #x01) /r))
52 | ((,mnemonic (r/m32 r32 m) r32) . (o32 ,(+ base #x01) /r))
53 | ((,mnemonic r8 r/m8) . (,(+ base #x02) /r))
54 | ((,mnemonic r16 (r/m16 r16 m)) . (o16 ,(+ base #x03) /r))
55 | ((,mnemonic r32 (r/m32 r32 m)) . (o32 ,(+ base #x03) /r))))))
56 |
57 | (defun arith-syntax-2 (mnemonic 64bit-only?)
58 | "Return syntax table for arithmetic operations: div/mul/neg/not."
59 | (let ((opcode (ecase mnemonic
60 | (div '/6) (mul '/4) (neg '/3) (not '/2))))
61 | (if 64bit-only?
62 | `(((,mnemonic (r/m64 r64)) . (rex.w #xf7 ,opcode))
63 | ((,mnemonic qword m) . (rex.w #xf7 ,opcode)))
64 | `(((,mnemonic (r/m8 r8)) . (#xf6 ,opcode))
65 | ((,mnemonic byte m) . (#xf6 ,opcode))
66 | ((,mnemonic (r/m16 r16)) . (o16 #xf7 ,opcode))
67 | ((,mnemonic word m) . (o16 #xf7 ,opcode))
68 | ((,mnemonic (r/m32 r32)) . (o32 #xf7 ,opcode))
69 | ((,mnemonic dword m) . (o32 #xf7 ,opcode))))))
70 |
71 | (defun shift-syntax (mnemonic 64bit-only?)
72 | "Return syntax table for shift operations: sal/sar/shl/shr."
73 | (let ((opcode (ecase mnemonic
74 | (sal '/4) (sar '/7) (shl '/4) (shr '/5))))
75 | (if 64bit-only?
76 | `(((,mnemonic r64 1) . (rex.w #xd1 ,opcode))
77 | ((,mnemonic qword m 1) . (rex.w #xd1 ,opcode))
78 | ((,mnemonic r64 cl) . (rex.w #xd3 ,opcode))
79 | ((,mnemonic qword m cl) . (rex.w #xd3 ,opcode))
80 | ((,mnemonic r64 imm8) . (rex.w #xc1 ,opcode ib))
81 | ((,mnemonic qword m imm8) . (rex.w #xc1 ,opcode ib)))
82 | `(((,mnemonic r8 1) . (#xd0 ,opcode))
83 | ((,mnemonic byte m 1) . (#xd0 ,opcode))
84 | ((,mnemonic r8 cl) . (#xd2 ,opcode))
85 | ((,mnemonic byte m cl) . (#xd2 ,opcode))
86 | ((,mnemonic r8 imm8) . (#xc0 ,opcode ib))
87 | ((,mnemonic byte m imm8) . (#xc0 ,opcode ib))
88 | ((,mnemonic r16 1) . (o16 #xd1 ,opcode))
89 | ((,mnemonic word m 1) . (o16 #xd1 ,opcode))
90 | ((,mnemonic r16 cl) . (o16 #xd3 ,opcode))
91 | ((,mnemonic word m cl) . (o16 #xd3 ,opcode))
92 | ((,mnemonic r16 imm8) . (o16 #xc1 ,opcode ib))
93 | ((,mnemonic word m imm8) . (o16 #xc1 ,opcode ib))
94 | ((,mnemonic r32 1) . (o32 #xd1 ,opcode))
95 | ((,mnemonic dword m 1) . (o32 #xd1 ,opcode))
96 | ((,mnemonic r32 cl) . (o32 #xd3 ,opcode))
97 | ((,mnemonic dword m cl) . (o32 #xd3 ,opcode))
98 | ((,mnemonic r32 imm8) . (o32 #xc1 ,opcode ib))
99 | ((,mnemonic dword m imm8) . (o32 #xc1 ,opcode ib))))))
100 |
101 | (defun bit-syntax (mnemonic 64bit-only?)
102 | "Return syntax table for arithmetic operations: bt/btc/btr/bts."
103 | (let ((base ; Base opcode for operation on r/m16, r16, r/m32, r32, r/m64, r64.
104 | (ecase mnemonic
105 | (bt #x0) (btc #x18) (btr #x10) (bts #x8)))
106 | (opcode ; Opcode used when one operand is immediate.
107 | (ecase mnemonic
108 | (bt '/4) (btc '/7) (btr '/6) (bts '/5))))
109 | (if 64bit-only?
110 | `(((,mnemonic r/m64 r64) . (rex.w #x0f ,(+ base #xa3) /r))
111 | ((,mnemonic r/m64 imm8) . (rex.w #x0f #xba ,opcode ib)))
112 | `(((,mnemonic r/m16 r16) . (o16 #x0f ,(+ base #xa3) /r))
113 | ((,mnemonic r/m32 r32) . (o32 #x0f ,(+ base #xa3) /r))
114 | ((,mnemonic r/m16 imm8) . (o16 #x0f #xba ,opcode ib))
115 | ((,mnemonic r/m32 imm8) . (o32 #x0f #xba ,opcode ib))))))
116 |
117 | ;;; Following are syntax tables for x86-64. For each entry, 1st part
118 | ;;; is the instruction type, 2nd part is the corresponding opcode.
119 | ;;; Note that for the 1st part, list may be used for the operand to
120 | ;;; match the type (e.g. imm8 converted to imm16). Note that the
121 | ;;; canonical form should be placed first (e.g. if the operand type
122 | ;;; should be imm16, place it as the car of the list).
123 | ;;;
124 | ;;; For details,
125 | ;;; refer to https://github.com/whily/yalo/blob/master/doc/AssemblyX64.md
126 |
127 | (defparameter *x86-64-syntax-common*
128 | `(
129 | ,@(arith-syntax-1 'adc nil)
130 | ,@(arith-syntax-1 'add nil)
131 | ,@(arith-syntax-1 'and nil)
132 | ((bswap r32) . (#x0f (+ #xc8 r)))
133 | ,@(bit-syntax 'bt nil)
134 | ,@(bit-syntax 'btc nil)
135 | ,@(bit-syntax 'btr nil)
136 | ,@(bit-syntax 'bts nil)
137 | ((bsf r16 r/m16) . (o16 #x0f #xbc /r))
138 | ((bsf r32 r/m32) . (o32 #x0f #xbc /r))
139 | ((bsr r16 r/m16) . (o16 #x0f #xbd /r))
140 | ((bsr r32 r/m32) . (o32 #x0f #xbd /r))
141 | ((call (imm32 imm64 imm16 imm8 label)) . (o32 #xe8 cd))
142 | ;; Below is just an hack so that we can always use 32 bit operand
143 | ;; when operating in 32 bit mode. TODO.
144 | ;; As current assembler did not differentiate too much between 16
145 | ;; bit and 32 bit mode, as we need 32 bit operand size for near
146 | ;; relative call in 32 bit, one SHOULD always use call32 below to
147 | ;; call function when working in 32 bit mode (so far in our
148 | ;; bootloader, 32 bit mode is transient as we just setup paging
149 | ;; and goes to 64 bit mode.
150 | ;; Warning: simply using `call` might result in stack corruption
151 | ;; (as 16 bit IP is pushed to stack instead of 32 bit), and memory exception
152 | ;; might occur when return using wrong EIP.
153 | ((call32 (imm32 imm64 imm16 imm8 label)) . (o32 #xe8 cd))
154 | ((clc) . (#xf8))
155 | ((cld) . (#xfc))
156 | ((cli) . (#xfa))
157 | ((cmovcc r16 r/m16) . (o16 #x0f (+ #x40 cc) /r))
158 | ((cmovcc r32 r/m32) . (o32 #x0f (+ #x40 cc) /r))
159 | ,@(arith-syntax-1 'cmp nil)
160 | ((cmpxchg r/m8 r8) . (#x0f #xb0 /r))
161 | ((cmpxchg r/m16 r16) . (o16 #x0f #xb1 /r))
162 | ((cmpxchg r/m32 r32) . (o32 #x0f #xb1 /r))
163 | ((cmpxchg8b m) . (#x0f #xc7 /1))
164 | ((cpuid) . (#x0f #xa2))
165 | ((dec (r/m8 r8)) . (#xfe /1))
166 | ((dec byte m) . (#xfe /1))
167 | ((dec (r/m16 r16)) . (o16 #xff /1))
168 | ((dec word m) . (o16 #xff /1))
169 | ((dec (r/m32 r32)) . (o32 #xff /1))
170 | ((dec dword m) . (o32 #xff /1))
171 | ,@(arith-syntax-2 'div nil)
172 | ((hlt) . (#xf4))
173 | ((in al imm8) . (#xe4 ib))
174 | ((in ax imm8) . (#xe5 ib))
175 | ((in al dx) . (#xec))
176 | ((in ax dx) . (#xed))
177 | ((inc (r/m8 r8)) . (#xfe /0))
178 | ((inc byte m) . (#xfe /0))
179 | ((inc (r/m16 r16)) . (o16 #xff /0))
180 | ((inc word m) . (o16 #xff /0))
181 | ((inc (r/m32 r32)) . (o32 #xff /0))
182 | ((inc dword m) . (o32 #xff /0))
183 | ((int 3) . (#xcc))
184 | ((int imm8) . (#xcd ib))
185 | ((invlpg m) . (#x0f #x01 /7))
186 | ((jcc (imm8 label imm16 imm32 imm64)) . ((+ #x70 cc) cb))
187 | ((jcc near (imm32 label imm8 imm16 imm64)) . (#x0f (+ #x80 cc) cd))
188 | ((jecxz (imm8 label imm16 imm32 imm64)) . (a32 #xe3 cb))
189 | ((jmp short (imm8 label imm16 imm32 imm64)) . (#xeb cb))
190 | ((lgdt m) . (#x0f #x01 /2))
191 | ((lidt m) . (#x0f #x01 /3))
192 | ((lldt r/m16) . (#x0f #x00 /2))
193 | ((lodsb) . (#xac))
194 | ((lodsw) . (o16 #xad))
195 | ((lodsd) . (o32 #xad))
196 | ((loop (imm8 label imm16 imm32 imm64)) . (#xe2 cb))
197 | ((mov r8 imm8) . ((+ #xb0 r) ib))
198 | ((mov r16 (imm16 imm8 imm label)) . (o16 (+ #xb8 r) iw))
199 | ((mov r32 (imm32 imm16 imm8 imm label)) . (o32 (+ #xb8 r) id))
200 | ((mov r/m8 r8) . (#x88 /r))
201 | ((mov r/m16 r16) . (o16 #x89 /r))
202 | ((mov r/m32 r32) . (o32 #x89 /r))
203 | ((mov r8 r/m8) . (#x8a /r))
204 | ((mov r16 r/m16) . (o16 #x8b /r))
205 | ((mov r32 r/m32) . (o32 #x8b /r))
206 | ((mov byte m (imm8 imm label)) . (#xc6 /0 ib))
207 | ((mov word m (imm16 imm8 imm label)) . (o16 #xc7 /0 iw))
208 | ((mov dword m (imm32 imm16 imm8 imm label)) . (o32 #xc7 /0 id))
209 | ((mov sreg r/m16) . (#x8e /r))
210 | ((mov r/m16 sreg) . (#x8c /r))
211 | ((movsb) . (#xa4))
212 | ((movsw) . (o16 #xa5))
213 | ((movsd) . (o32 #xa5))
214 | ((movzx r16 r/m8) . (o16 #x0f #xb6 /r))
215 | ((movzx r32 (r/m8 r8)) . (o32 #x0f #xb6 /r))
216 | ((movzx r32 byte m) . (o32 #x0f #xb6 /r))
217 | ((movzx r32 (r/m16 r16)) . (o32 #x0f #xb7 /r))
218 | ((movzx r32 word m) . (o32 #x0f #xb7 /r))
219 | ,@(arith-syntax-2 'mul nil)
220 | ,@(arith-syntax-2 'neg nil)
221 | ((nop) . (#x90))
222 | ,@(arith-syntax-2 'not nil)
223 | ,@(arith-syntax-1 'or nil)
224 | ((out imm8 r8) . (#xe6 ib)) ; (out imm8 al)
225 | ((out imm8 r16) . (#xe7 ib)) ; (out imm8 ax)
226 | ((out dx al) . (#xee))
227 | ((out dx ax) . (#xef))
228 | ((pop r16) . (o16 (+ #x58 r)))
229 | ;; Note that for 64 bit mode, prefix #x66 should be used according
230 | ;; to section 4.2 (INSTRUCTIONS (N-Z)) of [1]. This is different from NASM.
231 | ((popf) . (o16 #x9d))
232 | ((push r16) . (o16 (+ #x50 r)))
233 | ;; Note that for 64 bit mode, prefix #x66 should be used according
234 | ;; to section 4.2 (INSTRUCTIONS (N-Z)) of [1]. This is different from NASM.
235 | ((pushf) . (o16 #x9c))
236 | ((ret) . (#xc3))
237 | ((rdmsr) . (#x0f #x32))
238 | ,@(shift-syntax 'sal nil)
239 | ,@(shift-syntax 'sar nil)
240 | ,@(shift-syntax 'shl nil)
241 | ,@(shift-syntax 'shr nil)
242 | ((stc) . (#xf9))
243 | ((std) . (#xfd))
244 | ((sti) . (#xfb))
245 | ((stosb) . (#xaa))
246 | ((stosw) . (o16 #xab))
247 | ((stosd) . (o32 #xab))
248 | ,@(arith-syntax-1 'sbb nil)
249 | ,@(arith-syntax-1 'sub nil)
250 | ((test al imm8) . (#xa8 ib))
251 | ((test ax imm16) . (#xa9 iw))
252 | ((test (r/m8 r8) imm8) . (#xf6 /0 ib))
253 | ((test byte m imm8) . (#xf6 /0 ib))
254 | ((test r/m16 imm16) . (#xf7 /0 iw))
255 | ((test word m imm16) . (#xf7 /0 iw))
256 | ((test r/m32 imm32) . (#xf7 /0 id))
257 | ((test dword m imm32) . (#xf7 /0 id))
258 | ((test r/m8 r8) . (#x84 /r))
259 | ((test r/m16 r16) . (#x85 /r))
260 | ((test r/m32 r32) . (#x85 /r))
261 | ((wrmsr) . (#x0f #x30))
262 | ((xadd r/m8 r8) . (#x0f #xc0 /r))
263 | ((xadd r/m16 r16) . (o16 #x0f #xc1 /r))
264 | ((xadd r/m32 r32) . (o32 #x0f #xc1 /r))
265 | ((xchg r16 ax) . (o16 (+ #x90 r)))
266 | ((xchg r32 eax) . (o32 (+ #x90 r)))
267 | ((xchg r/m8 r8) . (#x86 /r))
268 | ((xchg r8 r/m8) . (#x86 /r))
269 | ((xchg r/m16 r16) . (o16 #x87 /r))
270 | ((xchg r16 r/m16) . (o16 #x87 /r))
271 | ((xchg r/m32 r32) . (o32 #x87 /r))
272 | ((xchg r32 r/m32) . (o32 #x87 /r))
273 | ,@(arith-syntax-1 'xor nil))
274 | "Valid for both 16-bit and 64-bit modes.")
275 |
276 | (defparameter *x86-64-syntax-16/32-bit-only*
277 | `(((call (imm16 imm8 label)) . (o16 #xe8 cw))
278 | ((dec r16) . (o16 (+ #x48 r)))
279 | ((dec r32) . (o32 (+ #x48 r)))
280 | ((inc r16) . (o16 (+ #x40 r)))
281 | ((inc r32) . (o32 (+ #x40 r)))
282 | ((jcxz (imm8 label imm16 imm32)) . (a16 #xe3 cb))
283 | ((jmp near (imm16 label imm8 imm32)) . (#xe9 cw))
284 | ((mov r32 cr0-cr7) . (#x0f #x20 /r))
285 | ((mov cr0-cr7 r32) . (#x0f #x22 /r))
286 | ((pop r32) . (o32 (+ #x58 r)))
287 | ((pop ss) . (#x17))
288 | ((pop ds) . (#x1f))
289 | ((pop es) . (#x07))
290 | ((popfd) . (o32 #x9d))
291 | ((push r32) . (o32 (+ #x50 r)))
292 | ((push cs) . (#x0e))
293 | ((push ss) . (#x16))
294 | ((push ds) . (#x1e))
295 | ((push es) . (#x06))
296 | ((pushfd) . (o32 #x9c)))
297 | "Valid for 16-bit mode only.")
298 |
299 | (defparameter *x86-64-syntax-64-bit-only*
300 | `(
301 | ,@(arith-syntax-1 'adc t)
302 | ,@(arith-syntax-1 'add t)
303 | ,@(arith-syntax-1 'and t)
304 | ((bswap r64) . (rex.w #x0f (+ #xc8 r)))
305 | ,@(bit-syntax 'bt t)
306 | ,@(bit-syntax 'btc t)
307 | ,@(bit-syntax 'btr t)
308 | ,@(bit-syntax 'bts t)
309 | ((bsf r64 r/m64) . (rex.w #x0f #xbc /r))
310 | ((bsr r64 r/m64) . (rex.w #x0f #xbd /r))
311 | ((cmovcc r64 r/m64) . (rex.w #x0f (+ #x40 cc) /r))
312 | ((cmpxchg r/m64 r64) . (rex.w #x0f #xb1 /r))
313 | ((cmpxchg16b m) . (rex.w #x0f #xc7 /1))
314 | ,@(arith-syntax-1 'cmp t)
315 | ((dec (r/m64 r64)) . (rex.w #xff /1))
316 | ((dec qword m) . (rex.w #xff /1))
317 | ,@(arith-syntax-2 'div t)
318 | ((inc (r/m64 r64)) . (rex.w #xff /0))
319 | ((inc qword m) . (rex.w #xff /0))
320 | ((iretq) . (rex.w #xcf))
321 | ;; The following instruction is available for 16/32 bit, but we only support it
322 | ;; in 64 bit for simplicity (there are already more compact `jmp near` in 16/32 bits.)
323 | ((jmp near (imm32 label imm8 imm16 imm64)) . (#xe9 cd))
324 | ((jmp near r/m64) . (#xff /4))
325 | ((jrcxz (imm8 label imm16 imm32 imm64)) . (#xe3 cb))
326 | ((leave) . (#xc9))
327 | ((lodsq) . (rex.w #xad))
328 | ;; For the following two instructions (including the one commented out)
329 | ;; we use id instead of io (as in instruction manual) for imm32.
330 | ;; NASM generates same results.
331 | ;; The following instruction is handled in function match-instruction,
332 | ;; therefore commented out.
333 | ;; ((mov r64 -imm32) . (rex.w #xc7 /0 id))
334 | ((mov qword m (imm32 imm16 imm8 imm label)) . (rex.w #xc7 /0 id))
335 | ((mov r64 (imm32 imm16 imm8 imm)) . ((+ #xb8 r) id))
336 | ((mov r64 (imm64 label)) . (rex.w (+ #xb8 r) io))
337 | ((mov r/m64 r64) . (rex.w #x89 /r))
338 | ((mov r64 r/m64) . (rex.w #x8b /r))
339 | ((movsq) . (rex.w #xa5))
340 | ((movzx r64 (r/m8 r8)) . (rex.w #x0f #xb6 /r))
341 | ((movzx r64 byte m) . (rex.w #x0f #xb6 /r))
342 | ((movzx r64 (r/m16 r16)) . (rex.w #x0f #xb7 /r))
343 | ((movzx r64 word m) . (rex.w #x0f #xb7 /r))
344 | ,@(arith-syntax-2 'mul t)
345 | ,@(arith-syntax-2 'neg t)
346 | ,@(arith-syntax-2 'not t)
347 | ,@(arith-syntax-1 'or t)
348 | ((pop r64) . ((+ #x58 r)))
349 | ((popcnt r64 r/m64) . (#xf3 rex.w #x0f #xb8 /r))
350 | ((popfq) . (#x9d))
351 | ((push r64) . ((+ #x50 r)))
352 | ((pushfq) . (#x9c))
353 | ((setcc r/m8) . (#x0f (+ #x90 cc) /0))
354 | ,@(shift-syntax 'sal t)
355 | ,@(shift-syntax 'sar t)
356 | ,@(shift-syntax 'shl t)
357 | ,@(shift-syntax 'shr t)
358 | ,@(arith-syntax-1 'sbb t)
359 | ((stosq) . (rex.w #xab))
360 | ,@(arith-syntax-1 'sub t)
361 | ((syscall) . (#x0f #x05))
362 | ((sysret) . (#x0f #x07))
363 | ((test rax imm32) . (rex.w #xa9 id))
364 | ((test r/m64 imm32) . (rex.w #xf7 /0 id))
365 | ((test qword m imm32) . (rex.w #xf7 /0 id))
366 | ((test r/m64 r64) . (rex.w #x85 /r))
367 | ((xadd r/m64 r64) . (rex.w #x0f #xc1 /r))
368 | ((xchg r64 rax) . (rex.w (+ #x90 r)))
369 | ((xchg r/m64 r64) . (rex.w #x87 /r))
370 | ((xchg r64 r/m64) . (rex.w #x87 /r))
371 | ,@(arith-syntax-1 'xor t)))
372 |
373 | (defparameter *x86-64-syntax-16/32-bit*
374 | (append *x86-64-syntax-16/32-bit-only* *x86-64-syntax-common*)
375 | "Syntax table for 16-bit mode.")
376 |
377 | (defparameter *x86-64-syntax-64-bit*
378 | (append *x86-64-syntax-64-bit-only* *x86-64-syntax-common*)
379 | "Syntax table for 64-bit mode.")
380 |
381 | (defun x86-64-syntax (bits)
382 | "Returns syntax table according to bit mode (16, 32 or 64)."
383 | (ecase bits
384 | ((16 32) *x86-64-syntax-16/32-bit*)
385 | (64 *x86-64-syntax-64-bit*)))
386 |
--------------------------------------------------------------------------------
/debug-qemu:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | # Emulate with qemu, enabling debug settings for GDB.
3 | qemu-system-x86_64 -fda floppy.img -m 32 -monitor stdio -s -S
4 |
--------------------------------------------------------------------------------
/debug-virtualbox:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | # Emulate with VirtualBox, enabling debug settings.
3 | VirtualBox --startvm yalo --debug
4 |
--------------------------------------------------------------------------------
/doc/AssemblyX64.md:
--------------------------------------------------------------------------------
1 | Assembly syntax used by CL cross compiler and Ink
2 | =================================================
3 |
4 | # Introduction
5 |
6 | Lisp Assembly Program (LAP) uses list structure to contain assembly
7 | code. Basically, atoms represent labels while lists represent (pseudo)
8 | instructions. Local labels (starting with a period) are also supported.
9 |
10 | Lisp expressions can be used for immediate values. In addition, since
11 | LAP is an S-expression, macros could be used to mimic the macro
12 | facility of *real* assemblers.
13 |
14 | The syntax is similar to what NASM uses. Basically, Intel syntax is
15 | used, i.e. destination operand precedes source operand.
16 |
17 | To get a feeling about what LAP looks like, one may take a look at the
18 | value of `*bootloader*` defined in https://github.com/whily/yalo/blob/master/cc/bootloader.lisp.
19 |
20 | # Pseudo Instructions of Assembly.
21 |
22 | Directives (e.g. bits, origin) are categorized as pseudo instructions
23 | here too.
24 |
25 | ## addressing: addressing mode
26 |
27 | Set the default setting of whether RIP Relative Addressing is used in
28 | 64 bit mode. This only applies when memory label is used (i.e. it does
29 | not affect the addressing options when registers are used, also it is
30 | not applicable to absolute address like #xb8000). One can use
31 | per-instruction override of `abs` or `rel` explicitly, for example:
32 | `(mov byte (abs msg) 0)`.
33 |
34 | | Instruction | Description |
35 | | -------------- | ------------------------------------------- |
36 | | addressing abs | Default to bsolute addresing |
37 | | addressing rel | Default to RIP Relative addresing (default) |
38 |
39 | ## align: boundary align
40 |
41 | The next instruction will be aligned at the boundary specified. NOP
42 | (#x90) will be inserted if necessary.
43 |
44 | | Instruction | Description |
45 | | -------------------------- | ------------- |
46 | | align 4 | 8 | 16 | |
47 |
48 | ## bits: Bit Mode
49 |
50 | | Instruction | Description |
51 | | ----------- | --------------------- |
52 | | bits 16 | 16-bit mode |
53 | | bits 64 | 64-bit mode (default) |
54 |
55 | ## db: Declaring initialized byte value(s)
56 |
57 | | Instruction | Description |
58 | | -------------------------------------- | ----------------------------- |
59 | | db (_number_ | _string_)* | Declare byte values via lists |
60 |
61 | Note:
62 |
63 | * _number_ should be in range -128..+255. Expression within the same
64 | range can be used as well.
65 | * _string_ is converted byte by byte.
66 |
67 | ## dw: Declaring initialized word value(s)
68 |
69 | | Instruction | Description |
70 | | ---------------------- | ------------------------------ |
71 | | dw (_number_)* | Declare word value via lists |
72 |
73 | Note:
74 |
75 | * _number_ should be in range -32,768..+65,535. Expression within the same
76 | range can be used as well.
77 |
78 | ## dd: Declaring initialized doubleword value(s)
79 |
80 | | Instruction | Description |
81 | | ---------------------- | ------------------------------------ |
82 | | dd (_number_)* | Declare doubleword value via lists |
83 |
84 | Note:
85 |
86 | * _number_ should be in range -2,147,483,648..+4,294,967,295.
87 | Expression within the same range can be used as well.
88 |
89 | ## dq: Declaring initialized quadword value(s)
90 |
91 | | Instruction | Description |
92 | | ---------------------- | ---------------------------------- |
93 | | dq (_number_)* | Declare quadword value via lists |
94 |
95 | Note:
96 |
97 | * _number_ should be in range
98 | -9,223,372,036,854,775,808..+18,446,744,073,709,551,615.
99 | Expression within the same range can be used as well.
100 |
101 | ## equ: Defint Constant
102 |
103 | | Instruction | Description |
104 | | ------------------ | ----------------------------------------- |
105 | | equ _const_ _expr_ | Define constant _const_ with value _expr_ |
106 |
107 | Note:
108 |
109 | * _expr_ should be evaulated when encoutering the instruction,
110 | i.e. forward reference is not allowed.
111 |
112 | ## org: Define Origin
113 |
114 | | Instruction | Description |
115 | | ----------- | ----------------------- |
116 | | org val | Define origin to be val |
117 |
118 | Note:
119 |
120 | * *org* can be used multiple times, however $$ refers to the latest definition of *org*.
121 |
122 | ## resb/resw/resd/resq: Declare unitialized data
123 |
124 | | Instruction | Description |
125 | | ----------- | ----------------------- |
126 | | resb _n_ | Reserve _n_ bytes |
127 | | resw _n_ | Reserve _n_ words |
128 | | resd _n_ | Reserve _n_ doublewords |
129 | | resq _n_ | Reserve _n_ quadwords |
130 |
131 | ## times: Repeat instruction =
132 |
133 | | Instruction | Description |
134 | | --------------------------- | --------------------------------------- |
135 | | times _count_ _instruction_ | Assemble _count_ times of _instruction_ |
136 |
137 | Note:
138 |
139 | * _count_ could be an expression which can be evaluated when *times*
140 | instruction is encoutered, e.g. containing $, $$, or labels defined
141 | before *times* instruction.
142 | * _instruction_ can be any other (pseudo) instructions.
143 |
144 | # Special Variables of Assembly.
145 |
146 | Following special variables are supported:
147 | * **$** Location of the start of current instruction.
148 | * **$$** Origin (start address) of current assembly program.
149 |
150 | # Overview of x86-64 Assembly
151 |
152 | ## Intruction
153 |
154 | This wiki lists the machine instructions supported by x86-64 LAP, and
155 | the short description of the functions for each instruction. One
156 | should refer to Intel or AMD manuals for complete reference.
157 |
158 | For each mnemonic, one table is provided to list the supported
159 | instructions. There are 2 columns in the table:
160 | * **Instruction**: documents mnemonic and operands.
161 | * **Opcode**: documents the translated opcode.
162 |
163 | ## Notations for Instructions
164 |
165 | Following notations are used:
166 | * **imm8**: immediate byte value in the range of -128..+255.
167 | * **imm16**: immediate word value in the range of -32,768..+65,535.
168 | * **imm32**: immediate doubleword value in the range of -2,147,483,648..+4,294,967,295.
169 | * **imm64**: immediate quadword value in the range of -9,223,372,036,854,775,808..+18,446,744,073,709,551,615..
170 | * **r8**: one of the byte general-purpose registers: al, cl, dl, bl, ah, ch, dh, bh, bpl, spl, dil, and sil.
171 | * **r16**: one of the word general-purpose registers: ax, cx, dx, bx, sp, bp, si, di.
172 | * **r32**: one of the doubleword general-purpose registers: eax, ecx, edx, ebx, esp, ebp, esi, edi.
173 | * **r64**: one of the quadword general-purpose registers: rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, r8-r15.
174 | * **m8, m16, m32, m64, m128**: memory references. Specifier (`byte`, `word`, `dword`, `qword`) is needed for ambiguous cases. For example in `(mov word (12345) 16).
175 | * **m16&32**, **m16&16**, **m32&32**, **m16&64**, a memory operand containing one pair whose sizes are indicated on the left and right size of the ampersand.
176 | * **r/m8, r/m16, r/m32, r/m64**: register or memeory choices. For example, r/m8 means that either r8 or m8 can be used as operand.
177 | * **sreg**: segment register.
178 |
179 | ## Range of Immediate Values
180 |
181 | Note that the range for imm8/16/32/64 is defined considering the
182 | capcity of 8/16/32/64 bits. The range might be too broad for jmp like
183 | instructions which require *true* signed integers, however the impact
184 | is minimal.
185 |
186 | In 64 bit mode, the default operand size is 32 bit. REX.W is used for
187 | 64 bit operand size. When 32 bit register is used as target, the
188 | result is automatically sign extended to 64 bit. To reduce the
189 | generated machine code size, the assembler automatically use the 32
190 | bit operand size if immediate value can be represented as 32 bits. For
191 | example, `(mov eax 1)` and `(mov rax 1)` generates same machine
192 | code. Note that such optimization is mainly meaningful for *mov*
193 | instructions, as sign extension to 64 bit is generally not applicable
194 | for other instructions unless the upper 32 bits are always 0.
195 |
196 | ## Memory Address Operands
197 |
198 | Memory address operands are supported, e.g. `(bp)`, `(var)`, `(bp si
199 | 5)`. Note that the order is flexible. For example, `(bp si 3)` is
200 | equivalent to `(si 3 bp)`.
201 |
202 | For scaled index of 32-bit addressing modes, one has to use the form
203 | of register*scale, e.g. eax*8.
204 |
205 | Segment override prefix is used purely as a prefix, e.g. `(es mov al
206 | (di))`, which is different from traditional syntax. The motiviation is
207 | to use a simple method to handle this case as such override is not
208 | used in 64 bit mode.
209 |
210 | ## Notations for Opcodes
211 |
212 | Following notations are used:
213 | * A hex number, such as CC, indicates a fixed byte containing that number.
214 | * A hex number followed by **+r**, like **B0+r**, indicates that one of the operands is a register, and correspondign register value should be added to the opcode.
215 | * **/n** (where n is 0 to 7): indictes that one of the operand is r/m, and the field Reg/Opcode should be encoded with n.
216 | * **/r**: ModR/M byte of the instruction contains a register operand (encoded in field Reg/Opcode) and an r/m operand (encoded in field R/M).
217 | * **cb, cw, cd, co**: one of the operands is an immediate value, and the _difference_ between this value and the end address of the instruction is to be encoded as byte (cb), little-endian word (cw), little-endian doubleword (cd), and little-endian quadword (co) respectively.
218 | * **ib, iw, id, io**: one of the operands is an immediate value, and it is to be encoded as byte (ib), little-endian word (iw), little-endian doubleword (id), and little-endian quadword (io) respectively.
219 | * **o16, o32**: operand-size override prefix. o16 generates no code in 16-bit mode, but indicates a 66h prefix in 32/64-bit mode; similarly, o32 generates no code in 32/64-bit mode, but indicates a 66h prefix in 16-bit mode.
220 | * **a16, a32**: address-size override prefix. a16 generates no code in 16-bit mode, but indicates a 67h prefix in 32/64-bit mode; similarly, a32 generates no code in 32-bit mode, but indicates a 67h prefix in 16/64-bit mode.
221 | * **rex.w**: REX prefix indicating 64 bit operand, in 64 bit mode.
222 |
223 | Note that REX prefix are not used in opcode notations. The prefix is
224 | automatically generated by analyzing the operands.
225 |
226 | ### Conditional Codes
227 |
228 | Conditional codes are used for Jcc, CMOVcc, and SETcc instructions, which are
229 | encoded as (+ xx cc). Meaning of conditional codes are listed below.
230 |
231 | | cc | value | trigger flag |
232 | | -------- | ----- | ------------ |
233 | | o | 0 | overflow flag set |
234 | | no | 1 | overflow flag not set |
235 | | b c nae | 2 | carry flag set |
236 | | ae nb nc | 3 | carry flag not set |
237 | | e z | 4 | zero flag set |
238 | | ne nz | 5 | zero flag not set |
239 | | be na | 6 | either of carry or zero flag set |
240 | | a nbe | 7 | neither carry nor zero flag set |
241 | | s | 8 | sign flag set |
242 | | ns | 9 | sign flag not set |
243 | | p pe | 10 | parity flag set |
244 | | np po | 11 | parity flag not set |
245 | | l nge | 12 | exactly one of sign and overflow flag is set |
246 | | ge nl | 13 | opposite case of above |
247 | | le ng | 14 | either the zero flag is set, or exactly one of sign and overflow flag is set |
248 | | g nle | 15 | opposite case of above |
249 |
250 | # Instruction set
251 |
252 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md)
253 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md)
254 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md)
255 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md)
256 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md)
257 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md)
258 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md)
259 |
--------------------------------------------------------------------------------
/doc/AssemblyX64A.md:
--------------------------------------------------------------------------------
1 | x86-64 Instruction Set A
2 | ========================
3 |
4 | [Assembly syntax](AssemblyX64.md)
5 | A [B](AssemblyX64B.md) [C](AssemblyX64C.md)
6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md)
7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md)
8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md)
9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md)
10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md)
11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md)
12 |
13 | ### adc: Add with Carry
14 |
15 | Please refer to [x86-64 arithmetic instructions](AssemblyX64Arith.md) for details.
16 |
17 | ### add: Add
18 |
19 | Please refer to [x86-64 arithmetic instructions](AssemblyX64Arith.md) for details.
20 |
21 | ### and: Logical AND
22 |
23 | Please refer to [x86-64 arithmetic instructions](AssemblyX64Arith.md) for details.
24 |
--------------------------------------------------------------------------------
/doc/AssemblyX64Arith.md:
--------------------------------------------------------------------------------
1 | x86-64 Arithmetic Instruction
2 | =============================
3 |
4 | [Assembly syntax](AssemblyX64.md)
5 | [A](AssemblyX64B.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md)
6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md)
7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md)
8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md)
9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md)
10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md)
11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md)
12 |
13 | There are 8 arithmetic instructions which have similar formats of
14 | instructions. They are discussed together here.
15 |
16 | The instructions are:
17 | * adc: add with carry
18 | * add: add
19 | * and: logical and
20 | * cmp: compare
21 | * or: logical or
22 | * sbb: subtract with borrow
23 | * sub: subtract
24 | * xor: logical exclusive or
25 |
26 | The format of the instructions are given below.
27 |
28 | | Instruction | Opcode |
29 | | --------------- | ------------------------ |
30 | | ins al imm8 | (+ base 04) ib |
31 | | ins ax imm16 | o16 (+ base 05) iw |
32 | | ins eax imm32 | o32 (+ base 05) id |
33 | | ins rax imm32 | REX.W (+ base 05) id |
34 | | ins r/m8 imm8 | 80 opcode ib |
35 | | ins r/m16 imm16 | o16 81 opcode iw |
36 | | ins r/m32 imm32 | o32 81 opcode id |
37 | | ins r/m64 imm32 | REX.W 81 opcode id |
38 | | ins r/m16 imm8 | o16 83 opcode ib |
39 | | ins r/m32 imm8 | o32 83 opcode ib |
40 | | ins r/m64 imm8 | REX.W 83 opcode ib |
41 | | ins r/m8 r8 | base /r |
42 | | ins r/m16 r16 | o16 (+ base 01) /r |
43 | | ins r/m32 r32 | o32 (+ base 01) /r |
44 | | ins r/m64 r64 | REX.W (+ base 01) /r |
45 | | ins r8 r/m8 | (+ base 02) /r |
46 | | ins r16 r/m16 | o16 (+ base 03) /r |
47 | | ins r32 r/m32 | o32 (+ base 03) /r |
48 | | ins r64 r/m64 | REX.W (+ base 03) /r |
49 |
50 | Base and opcode in above table are given below for each instruction.
51 |
52 | | Instruction | Base (hexadecimal) | Opcode |
53 | | ----------- | ------------------ | ------ |
54 | | adc | 10 | /2 |
55 | | add | 00 | /0 |
56 | | and | 20 | /4 |
57 | | cmp | 38 | /7 |
58 | | or | 08 | /1 |
59 | | sbb | 18 | /3 |
60 | | sub | 28 | /5 |
61 | | xor | 30 | /6 |
62 |
--------------------------------------------------------------------------------
/doc/AssemblyX64B.md:
--------------------------------------------------------------------------------
1 | x86-64 Instruction Set B
2 | ========================
3 |
4 | [Assembly syntax](AssemblyX64.md)
5 | [A](AssemblyX64A.md) B [C](AssemblyX64C.md)
6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md)
7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md)
8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md)
9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md)
10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md)
11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md)
12 |
13 | ### bsf: Bit Scan Forward
14 |
15 | | Instruction | Opcode |
16 | | ------------- | -------------- |
17 | | bsf r16 r/m16 | o16 0F BC /r |
18 | | bsf r32 r/m32 | o32 0F BC /r |
19 | | bsf r64 r/m64 | REX.W 0F BC /r |
20 |
21 | ### bsf: Bit Scan Reverse
22 |
23 | | Instruction | Opcode |
24 | | ------------- | -------------- |
25 | | bsr r16 r/m16 | o16 0F BD /r |
26 | | bsr r32 r/m32 | o32 0F BD /r |
27 | | bsr r64 r/m64 | REX.W 0F BD /r |
28 |
29 | ### bswap: Byte Swap
30 |
31 | | Instruction | Opcode |
32 | | ----------- | -------------- |
33 | | bswap r32 | 0F C8+r |
34 | | bswap r64 | REX.W 0F C8+r |
35 |
36 | ### bt: Bit Test
37 |
38 | Please refer to [x86-64 bit instructions](AssemblyX64Bit.md) for details.
39 |
40 | ### btc: Bit Test and Complement
41 |
42 | Please refer to [x86-64 bit instructions](AssemblyX64Bit.md) for details.
43 |
44 | ### btr: Bit Test and Reset
45 |
46 | Please refer to [x86-64 bit instructions](AssemblyX64Bit.md) for details.
47 |
48 | ### bts: Bit Test and Set
49 |
50 | Please refer to [x86-64 bit instructions](AssemblyX64Bit.md) for details.
51 |
--------------------------------------------------------------------------------
/doc/AssemblyX64Bit.md:
--------------------------------------------------------------------------------
1 | x86-64 Bit Instruction
2 | =============================
3 |
4 | [Assembly syntax](AssemblyX64.md)
5 | [A](AssemblyX64B.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md)
6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md)
7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md)
8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md)
9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md)
10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md)
11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md)
12 |
13 | There are 4 bit instructions which have similar formats of
14 | instructions. They are discussed together here.
15 |
16 | The instructions are:
17 | * bt: bit test
18 | * btc: bit test and complement
19 | * btr: bit test and reset
20 | * bts: bit test and set
21 |
22 | The format of the instructions are given below.
23 |
24 | | Instruction | Opcode |
25 | | -------------- | ----------------------- |
26 | | ins r/m16 r16 | 0F (+ base A3) /r |
27 | | ins r/m32 r32 | 0F (+ base A3) /r |
28 | | ins r/m32 r32 | 0F (+ base A3) /r |
29 | | ins r/m16 imm8 | 0F BA opcode ib |
30 | | ins r/m32 imm8 | 0F BA opcode ib |
31 | | ins r/m64 imm8 | REX.W 0F BA opcode ib |
32 |
33 | Base and opcode in above table are given below for each instruction.
34 |
35 | | Instruction | Base (hexadecimal) | Opcode |
36 | | ----------- | ------------------ | ------ |
37 | | bt | 0 | /4 |
38 | | btc | 18 | /7 |
39 | | btr | 10 | /6 |
40 | | bts | 8 | /5 |
41 |
--------------------------------------------------------------------------------
/doc/AssemblyX64C.md:
--------------------------------------------------------------------------------
1 | x86-64 Instruction Set C
2 | ========================
3 |
4 | [Assembly syntax](AssemblyX64.md)
5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) C
6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md)
7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md)
8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md)
9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md)
10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md)
11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md)
12 |
13 | ### call: Call Procedure
14 |
15 | | Instruction | Opcode |
16 | | ----------- | ---------- |
17 | | call imm16 | o16 E8 cw |
18 | | call imm32 | o32 E8 cd |
19 |
20 | ### clc: Clear Carry Flag
21 |
22 | | Instruction | Opcode |
23 | | ----------- | ------ |
24 | | clc | F8 |
25 |
26 | ### cld: Clear Direction Flag
27 | | Instruction | Opcode |
28 | | ----------- | ------ |
29 | | cld | FC |
30 |
31 | ### cli: Clear Interrupt Flag
32 |
33 | | Instruction | Opcode |
34 | | ----------- | ------ |
35 | | cli | FA |
36 |
37 | ### cmovcc: Conditional Move
38 |
39 | | Instruction | Opcode |
40 | | ----------------- | --------------------- |
41 | | cmovcc r16 r/m16 | o16 0F (+ 40 cc) /r |
42 | | cmovcc r32 r/m32 | o32 0F (+ 40 cc) /r |
43 | | cmovcc r64 r/m64 | REX.W 0F (+ 40 cc) /r |
44 |
45 | Please refer [x86-64 conditional codes](AssemblyX64.md#conditional-codes) for details.
46 |
47 | ### cmp: Compare
48 |
49 | Please refer to [x86-64 arithmetic instructions](AssemblyX64Arith.md) for details.
50 |
51 | ### cmpxchg: Compare and Exchange
52 |
53 | | Instruction | Opcode |
54 | | ----------------- | ------------------ |
55 | | cmpxchg r/m8 r8 | 0F B0 /r |
56 | | cmpxchg r/m16 r16 | o16 0F B1 /r |
57 | | cmpxchg r/m32 r32 | o32 0F B1 /r |
58 | | cmpxchg r/m64 r64 | REX.W 0F B1 /r |
59 |
60 | ### cmpxchg8b/cmpxchg16b: Compare and Exchange Bytes
61 |
62 | | Instruction | Opcode |
63 | | --------------- | -------------- |
64 | | cmpxchg8b m64 | 0F C7 /1 |
65 | | cmpxchg16b m128 | REX.W 0F C7 /1 |
66 |
--------------------------------------------------------------------------------
/doc/AssemblyX64D.md:
--------------------------------------------------------------------------------
1 | x86-64 Instruction Set D
2 | ========================
3 |
4 | [Assembly syntax](AssemblyX64.md)
5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md)
6 | D [E](AssemblyX64E.md) [F](AssemblyX64F.md)
7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md)
8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md)
9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md)
10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md)
11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md)
12 |
13 | ### dec: Decrement by 1
14 |
15 | | Instruction | Opcode |
16 | | ----------- | ----------- |
17 | | dec r/m8 | FE /1 |
18 | | dec r/m16 | o16 FF /1 |
19 | | dec r/m32 | o32 FF /1 |
20 | | dec r/m64 | REX.W FF /1 |
21 | | dec r16 | o16 48+r |
22 | | dec r32 | o32 48+r |
23 |
24 | ### div: Unsigned Divide
25 |
26 | | Instruction | Opcode |
27 | | ----------- | ----------- |
28 | | div r/m8 | F6 /6 |
29 | | div r/m16 | o16 F7 /6 |
30 | | div r/m32 | o32 F7 /6 |
31 | | div r/m64 | REX.W F7 /6 |
32 |
--------------------------------------------------------------------------------
/doc/AssemblyX64E.md:
--------------------------------------------------------------------------------
1 | x86-64 Instruction Set E
2 | ========================
3 |
4 | [Assembly syntax](AssemblyX64.md)
5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md)
6 | [D](AssemblyX64D.md) E [F](AssemblyX64F.md)
7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md)
8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md)
9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md)
10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md)
11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md)
12 |
13 | Placeholder
14 |
--------------------------------------------------------------------------------
/doc/AssemblyX64F.md:
--------------------------------------------------------------------------------
1 | x86-64 Instruction Set F
2 | ========================
3 |
4 | [Assembly syntax](AssemblyX64.md)
5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md)
6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) F
7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md)
8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md)
9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md)
10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md)
11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md)
12 |
13 | Placeholder
14 |
--------------------------------------------------------------------------------
/doc/AssemblyX64H.md:
--------------------------------------------------------------------------------
1 | x86-64 Instruction Set H
2 | ========================
3 |
4 | [Assembly syntax](AssemblyX64.md)
5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md)
6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md)
7 | H [I](AssemblyX64I.md) [J](AssemblyX64J.md)
8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md)
9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md)
10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md)
11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md)
12 |
13 | hlt: Halt
14 | ---------
15 |
16 | | Instruction | Opcode |
17 | | ----------- | ------ |
18 | | hlt | F4 |
19 |
--------------------------------------------------------------------------------
/doc/AssemblyX64I.md:
--------------------------------------------------------------------------------
1 | x86-64 Instruction Set I
2 | ========================
3 |
4 | [Assembly syntax](AssemblyX64.md)
5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md)
6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md)
7 | [H](AssemblyX64H.md) I [J](AssemblyX64J.md)
8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md)
9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md)
10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md)
11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md)
12 |
13 | ### in: Input from Port
14 |
15 | | Instruction | Opcode |
16 | | ----------- | ------ |
17 | | in al imm8 | E4 ib |
18 | | in ax imm8 | E5 ib |
19 | | in al dx | EC |
20 | | in ax dx | ED |
21 |
22 | ### inc: Increment by 1
23 |
24 | | Instruction | Opcode |
25 | | ----------- | ----------- |
26 | | inc r/m8 | FE /0 |
27 | | inc r/m16 | o16 FF /0 |
28 | | inc r/m32 | o32 FF /0 |
29 | | inc r/m64 | REX.W FF /0 |
30 | | inc r16 | o16 40+r |
31 | | inc r32 | o32 40+r |
32 |
33 | ### int: Call Interrupt Procedure
34 |
35 | | Instruction | Opcode |
36 | | ----------- | ------ |
37 | | int 3 | CC |
38 | | int imm8 | CD ib |
39 |
40 | ### invlpg: Invalidate TLB entries
41 |
42 | | Instruction | Opcode |
43 | | ----------- | -------- |
44 | | invlpg m | 0F 01 /7 |
45 |
46 | ### iretq: Interrupt Return
47 |
48 | | Instruction | Opcode |
49 | | ----------- | -------- |
50 | | iretq | REX.W CF |
51 |
--------------------------------------------------------------------------------
/doc/AssemblyX64J.md:
--------------------------------------------------------------------------------
1 | x86-64 Instruction Set J
2 | ========================
3 |
4 | [Assembly syntax](AssemblyX64.md)
5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md)
6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md)
7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) J
8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md)
9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md)
10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md)
11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md)
12 |
13 | ### jcc: Conditional Branch
14 |
15 | | Instruction | Opcode |
16 | | -------------- | --------------- |
17 | | jcc imm | (+ 70 cc) cb |
18 | | jcc near imm | 0F (+ 80 cc) cd |
19 | | jcxz imm | a16 E3 cb |
20 | | jecxz imm | a32 E3 cb |
21 | | jrcxz imm | E3 cb |
22 |
23 | Please refer to [conditional codes](AssemblyX64.md) for details.
24 |
25 | ### jmp: Jump
26 |
27 | | Instruction | Opcode |
28 | | -------------- | -------- |
29 | | jmp short imm | EB cb |
30 | | jmp near imm | E9 cw (for 16/32 bits) |
31 | | jmp near imm | E9 cd (for 64 bit) |
32 | | jmp near r/m64 | FF /4 |
33 |
--------------------------------------------------------------------------------
/doc/AssemblyX64L.md:
--------------------------------------------------------------------------------
1 | x86-64 Instruction Set L
2 | ========================
3 |
4 | [Assembly syntax](AssemblyX64.md)
5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md)
6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md)
7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md)
8 | L [M](AssemblyX64M.md) [N](AssemblyX64N.md)
9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md)
10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md)
11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md)
12 |
13 | ### leave: High Level Procedure Exit
14 |
15 | | Instruction | Opcode |
16 | | ----------- | -------- |
17 | | leave | C9 |
18 |
19 |
20 | ### lgdt/lidt/lldt: Load Descriptor Tables
21 |
22 | | Instruction | Opcode |
23 | | ----------- | -------- |
24 | | lgdt m16&32 | 0F 01 /2 |
25 | | lidt m16&32 | 0F 01 /3 |
26 | | lldt r/m16 | 0F 00 /2 |
27 |
28 | ### lodsb/lodsw: Load String
29 |
30 | | Instruction | Opcode |
31 | | ----------- | -------- |
32 | | lodsb | AC |
33 | | lodsw | o16 AD |
34 | | lodsd | o32 AD |
35 | | lodsq | REX.W AD |
36 |
37 | ### loop: Loop According to (E)CX Counter
38 |
39 | | Instruction | Opcode |
40 | | ----------- | ------ |
41 | | loop imm16 | E2 cb |
42 |
--------------------------------------------------------------------------------
/doc/AssemblyX64M.md:
--------------------------------------------------------------------------------
1 | x86-64 Instruction Set M
2 | ========================
3 |
4 | [Assembly syntax](AssemblyX64.md)
5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md)
6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md)
7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md)
8 | [L](AssemblyX64L.md) M [N](AssemblyX64N.md)
9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md)
10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md)
11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md)
12 |
13 | ### mov: Move
14 |
15 | | Instruction | Opcode |
16 | | --------------- | -------------- |
17 | | mov r8 imm8 | B0+r ib |
18 | | mov r16 imm16 | o16 B8+r iw |
19 | | mov r32 imm32 | o32 B8+r id |
20 | | mov r64 imm64 | REX.W B8+r io |
21 | | mov r/m8 r8 | 88 /r |
22 | | mov r/m16 r16 | o16 89 /r |
23 | | mov r/m32 r32 | o32 89 /r |
24 | | mov r/m64 r64 | REX.W 89 /r |
25 | | mov r8 r/m8 | 8A /r |
26 | | mov r16 r/m16 | o16 8B /r |
27 | | mov r32 r/m32 | o32 8B /r |
28 | | mov r64 r/m64 | REX.W 8B /r |
29 | | mov r/m8 imm8 | C6 /0 ib |
30 | | mov r/m16 imm16 | o16 C7 /0 iw |
31 | | mov r/m32 imm32 | o32 C7 /0 id |
32 | | mov r/m64 imm32 | REX.W C7 /0 id |
33 | | mov sreg r/m16 | 8E /r |
34 | | mov r/m16 sreg | 8C /r |
35 |
36 | ### mov: Move to/from Control Registers
37 |
38 | | Instruction | Opcode |
39 | | --------------- | ------------ |
40 | | mov r32 cr0-cr7 | 0F 20 /r |
41 | | mov cr0-cr7 r32 | 0F 22 /r |
42 |
43 | ### movsb/movsw: Move Data from String to String
44 |
45 | | Instruction | Opcode |
46 | | ----------- | -------- |
47 | | movsb | A4 |
48 | | movsw | o16 A5 |
49 | | movsd | o32 A5 |
50 | | movsq | REX.W A5 |
51 |
52 | ### movzx: Move with Zero-Extend
53 |
54 | | Instruction | Opcode |
55 | | --------------- | -------------- |
56 | | movzx r16 r/m8 | o16 0F B6 /r |
57 | | movzx r32 r/m8 | o32 0F B6 /r |
58 | | movzx r64 r/m8 | REX.W 0F B6 /r |
59 | | movzx r32 r/m16 | o32 0F B7 /r |
60 | | movzx r64 r/m16 | REX.W 0F B7 /r |
61 |
62 | ### mul: Unsigned Multiply
63 |
64 | | Instruction | Opcode |
65 | | ----------- | ----------- |
66 | | mul r/m8 | F6 /4 |
67 | | mul r/m16 | o16 F7 /4 |
68 | | mul r/m32 | o32 F7 /4 |
69 | | mul r/m64 | REX.W F7 /4 |
70 |
--------------------------------------------------------------------------------
/doc/AssemblyX64N.md:
--------------------------------------------------------------------------------
1 | x86-64 Instruction Set N
2 | ========================
3 |
4 | [Assembly syntax](AssemblyX64.md)
5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md)
6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md)
7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md)
8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) N
9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md)
10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md)
11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md)
12 |
13 | ### neg: Two's Complement Negation
14 |
15 | | Instruction | Opcode |
16 | | ----------- | ----------- |
17 | | neg r/m8 | F6 /3 |
18 | | neg r/m16 | o16 F7 /3 |
19 | | neg r/m32 | o32 F7 /3 |
20 | | neg r/m64 | REX.W F7 /3 |
21 |
22 | Replaces the value of destination operand with its two's complement (-dest).
23 |
24 | ### nop: No Operation
25 |
26 | | Instruction | Opcode |
27 | | ----------- | ------ |
28 | | nop | 90 |
29 |
30 | ### not: One's Complement Negation
31 |
32 | | Instruction | Opcode |
33 | | ----------- | ----------- |
34 | | not r/m8 | F6 /2 |
35 | | not r/m16 | o16 F7 /2 |
36 | | not r/m32 | o32 F7 /2 |
37 | | not r/m64 | REX.W F7 /2 |
38 |
39 | Replaces the value of destination operand with its one's complement (bitwise NOT).
40 |
--------------------------------------------------------------------------------
/doc/AssemblyX64O.md:
--------------------------------------------------------------------------------
1 | x86-64 Instruction Set O
2 | ========================
3 |
4 | [Assembly syntax](AssemblyX64.md)
5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md)
6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md)
7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md)
8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md)
9 | O [P](AssemblyX64P.md) [R](AssemblyX64R.md)
10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md)
11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md)
12 |
13 | ### or: Logical Inclusive OR
14 |
15 | Please refer to [x86-64 arithmetic instructions](AssemblyX64Arith.md) for details.
16 |
17 | ### out: Output from Port
18 |
19 | | Instruction | Opcode |
20 | | ----------- | ------ |
21 | | out imm8 al | E6 ib |
22 | | out imm8 ax | E7 ib |
23 | | out dx al | EE |
24 | | out dx ax | EF |
25 |
--------------------------------------------------------------------------------
/doc/AssemblyX64P.md:
--------------------------------------------------------------------------------
1 | x86-64 Instruction Set P
2 | ========================
3 |
4 | [Assembly syntax](AssemblyX64.md)
5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md)
6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md)
7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md)
8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md)
9 | [O](AssemblyX64O.md) P [R](AssemblyX64R.md)
10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md)
11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md)
12 |
13 | ### pop: Pop a Value from the Stack
14 |
15 | | Instruction | Opcode |
16 | | ----------- | -------- |
17 | | pop r16 | o16 58+r |
18 | | pop r32 | o32 58+r |
19 | | pop r64 | 58+r |
20 | | pop ss | 17 |
21 | | pop ds | 1F |
22 | | pop es | 07 |
23 | | popf | o16 9D |
24 | | popfd | o32 9D |
25 | | popfq | 9D |
26 |
27 | ### popcnt: Return the Count of the Number of Bits Set to 1
28 |
29 | | Instruction | Opcode |
30 | | ---------------- | ----------------- |
31 | | popcnt r64 r/m64 | F3 REX.W 0F B8 /r |
32 |
33 | ### push: Push a Value Onto the Stack
34 |
35 | | Instruction | Opcode |
36 | | ----------- | -------- |
37 | | push r16 | o16 50+r |
38 | | push r32 | o32 50+r |
39 | | push r64 | 50+r |
40 | | push cs | 0E |
41 | | push ss | 16 |
42 | | push ds | 1E |
43 | | push es | 06 |
44 | | pushf | o16 9C |
45 | | pushfd | o32 9C |
46 | | pushfq | 9C |
47 |
--------------------------------------------------------------------------------
/doc/AssemblyX64R.md:
--------------------------------------------------------------------------------
1 | x86-64 Instruction Set R
2 | ========================
3 |
4 | [Assembly syntax](AssemblyX64.md)
5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md)
6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md)
7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md)
8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md)
9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) R
10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md)
11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md)
12 |
13 | ### rdmsr: Read From Model Specific Register
14 |
15 | | Instruction | Opcode |
16 | | ----------- | ------ |
17 | | rdmsr | 0F 32 |
18 |
19 | ### rep: Repeat String Operation Prefix
20 |
21 | Following are examples.
22 |
23 | | Instruction | Opcode |
24 | | ----------- | ------ |
25 | | rep movsb | F3 A4 |
26 | | rep movsw | F3 A5 |
27 |
28 | Note
29 |
30 | *rep* is a kind of prefix.
31 |
32 | ### ret: Return From Procedure
33 |
34 | | Instruction | Opcode |
35 | | ----------- | ------ |
36 | | ret | C3 |
37 |
--------------------------------------------------------------------------------
/doc/AssemblyX64S.md:
--------------------------------------------------------------------------------
1 | x86-64 Instruction Set S
2 | ========================
3 |
4 | [Assembly syntax](AssemblyX64.md)
5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md)
6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md)
7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md)
8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md)
9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md)
10 | S [T](AssemblyX64T.md) [U](AssemblyX64U.md)
11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md)
12 |
13 | ### sbb: subtract with borrow
14 |
15 | Please refer to [x86-64 arithmetic instructions](AssemblyX64Arith.md) for details.
16 |
17 | ### sal/sar/shl/shr: Shift
18 |
19 | | Instruction | Opcode |
20 | | -------------- | ------------------ |
21 | | ins r/m8, 1 | D0 opcode |
22 | | ins r/m8, cl | D2 opcode |
23 | | ins r/m8, imm8 | C0 opcode ib |
24 | | ins r/m16 1 | o16 D1 opcode |
25 | | ins r/m16 cl | o16 D3 opcode |
26 | | ins r/m16 imm8 | o16 C1 opcode ib |
27 | | ins r/m32 1 | o32 D1 opcode |
28 | | ins r/m32 cl | o32 D3 opcode |
29 | | ins r/m32 imm8 | o32 C1 opcode ib |
30 | | ins r/m64 1 | REX.W D1 opcode |
31 | | ins r/m64 cl | REX.W D3 opcode |
32 | | ins r/m64 imm8 | REX.W C1 opcode ib |
33 |
34 | The opcodes are /4, /7, /4, 5 for sal, sar, shl, shr, respectively.
35 |
36 | Note that sal and shl perform the same operation.
37 |
38 | ### setcc: Set Byte on Condition
39 |
40 | | Instruction | Opcode |
41 | | ----------------- | --------------------- |
42 | | setcc r/m8 | 0F (+ 90 cc) /0 |
43 |
44 | Please refer [x86-64 conditional codes](AssemblyX64.md#conditional-codes) for details.
45 |
46 | ### stc: Set Carry Flag
47 |
48 | | Instruction | Opcode |
49 | | ----------- | ------ |
50 | | stc | F9 |
51 |
52 | ### std: Set Direction Flag
53 | | Instruction | Opcode |
54 | | ----------- | ------ |
55 | | std | FD |
56 |
57 | ### sti: Set Interrupt Flag
58 |
59 | | Instruction | Opcode |
60 | | ----------- | ------ |
61 | | sti | FB |
62 |
63 | ### stosb/stosw/stosd: Store String
64 |
65 | | Instruction | Opcode |
66 | | ----------- | -------- |
67 | | stosb | AA |
68 | | stosw | o16 AB |
69 | | stosd | o32 AB |
70 | | stosq | REX.W AB |
71 |
72 | ### sub: Sub
73 |
74 | Please refer to [x86-64 arithmetic instructions](AssemblyX64Arith.md) for details.
75 |
76 | ### syscall/sysret: (Return from) Fast System Call
77 |
78 | | Instruction | Opcode |
79 | | ----------- | ------ |
80 | | syscall | 0F 05 |
81 | | sysret | 0F 07 |
82 |
--------------------------------------------------------------------------------
/doc/AssemblyX64T.md:
--------------------------------------------------------------------------------
1 | x86-64 Instruction Set T
2 | ========================
3 |
4 | [Assembly syntax](AssemblyX64.md)
5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md)
6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md)
7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md)
8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md)
9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md)
10 | [S](AssemblyX64S.md) T [U](AssemblyX64U.md)
11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md)
12 |
13 | ### test: Logical Compare
14 |
15 | | Instruction | Opcode |
16 | | ---------------- | -------------- |
17 | | test al imm8 | A8 ib |
18 | | test ax imm16 | A9 iw |
19 | | test rax imm32 | REX.W A9 id |
20 | | test r/m8 imm8 | F6 /0 ib |
21 | | test r/m16 imm16 | F7 /0 iw |
22 | | test r/m32 imm32 | F7 /0 id |
23 | | test r/m64 imm32 | REX.W F7 /0 id |
24 | | test r/m8 r8 | 84 /r |
25 | | test r/m16 r16 | 85 /r |
26 | | test r/m32 r32 | 85 /r |
27 | | test r/m64 r64 | REX.W85 /r |
28 |
29 | After ANDing the two operands, flags SF, ZF, and PF are set according
30 | to the result. The destination operand is *not* modified.
31 |
--------------------------------------------------------------------------------
/doc/AssemblyX64U.md:
--------------------------------------------------------------------------------
1 | x86-64 Instruction Set U
2 | ========================
3 |
4 | [Assembly syntax](AssemblyX64.md)
5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md)
6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md)
7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md)
8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md)
9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md)
10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) U
11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md)
12 |
13 | Placeholder
14 |
--------------------------------------------------------------------------------
/doc/AssemblyX64V.md:
--------------------------------------------------------------------------------
1 | x86-64 Instruction Set V
2 | ========================
3 |
4 | [Assembly syntax](AssemblyX64.md)
5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md)
6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md)
7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md)
8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md)
9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md)
10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md)
11 | V [W](AssemblyX64W.md) [X](AssemblyX64X.md)
12 |
13 | Placeholder
14 |
--------------------------------------------------------------------------------
/doc/AssemblyX64W.md:
--------------------------------------------------------------------------------
1 | x86-64 Instruction Set W
2 | ========================
3 |
4 | [Assembly syntax](AssemblyX64.md)
5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md)
6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md)
7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md)
8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md)
9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md)
10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md)
11 | [V](AssemblyX64V.md) W [X](AssemblyX64X.md)
12 |
13 | ### wrmsr: Write to Model Specific Register
14 |
15 | | Instruction | Opcode |
16 | | ----------- | ------ |
17 | | wrmsr | 0F 30 |
18 |
--------------------------------------------------------------------------------
/doc/AssemblyX64X.md:
--------------------------------------------------------------------------------
1 | x86-64 Instruction Set X
2 | ========================
3 |
4 | [Assembly syntax](AssemblyX64.md)
5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md)
6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md)
7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md)
8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md)
9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md)
10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md)
11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) X
12 |
13 | ### xadd: Exchange and Add
14 |
15 | | Instruction | Opcode |
16 | | -------------- | -------------- |
17 | | xadd r/m8 r8 | 0F C0 /r |
18 | | xadd r/m16 r16 | o16 0F C1 /r |
19 | | xadd r/m32 r32 | o32 0F C1 /r |
20 | | xadd r/m64 r64 | REX.W 0F C1 /r |
21 |
22 | ### xchg: Exchange
23 |
24 | | Instruction | Opcode |
25 | | -------------- | ----------- |
26 | | xchg ax r16 | o16 90+r |
27 | | xchg r16 ax | o16 90+r |
28 | | xchg eax r32 | o32 90+r |
29 | | xchg r32 eax | o32 90+r |
30 | | xchg rax r64 | REX.W 90+r |
31 | | xchg r64 rax | REX.W 90+r |
32 | | xchg r/m8 r8 | 86 /r |
33 | | xchg r8 r/m8 | 86 /r |
34 | | xchg r/m16 r16 | o16 87 /r |
35 | | xchg r16 r/m16 | o16 87 /r |
36 | | xchg r/m32 r32 | o32 87 /r |
37 | | xchg r32 r/m32 | o32 87 /r |
38 | | xchg r/m64 r64 | REX.W 87 /r |
39 | | xchg r64 r/m64 | REX.W 87 /r |
40 |
41 | Note that when a memory operand is referenced, lock protocal is
42 | automatically implemented, regardless whether LOCK prefix is used or
43 | not. This may has impact on performance.
44 |
45 | ### xor: Logical Exclusive OR
46 |
47 | Please refer to [x86-64 arithmetic instructions](AssemblyX64Arith.md) for details.
48 |
--------------------------------------------------------------------------------
/doc/CrossCompilation.md:
--------------------------------------------------------------------------------
1 | Cross Compilation
2 | =================
3 |
4 | # Plan
5 |
6 | Below is the initial thinking on the plan to cross compile and
7 | bootstrap Yalo.
8 |
9 | ## Cross compile the minimal bootloader and Ink interpreter
10 |
11 | The milestone of this stage is to generate a minimal bootloader (OS is
12 | far away) which finally runs an Ink interpreter.
13 |
14 | * Input: a minimal version of Ink interpreter written in Ink
15 | * Cross compiling platform: x86-64 assembler and a
16 | minimal version of Ink compiler, both written in Common Lisp. The
17 | compiler may use some intermediate language (e.g. LLVM IR).
18 |
19 | ## Develop Ink compiler with Ink interpreter
20 |
21 | Once the minimal Ink interpreter is up, the main target is then to
22 | implement basic file system (ext2) support. The interpreter then is
23 | able to read/write Ink source files, which can then be put under
24 | version control via the interface between VM and host machine.
25 |
26 | The next milestone is to implement x86-64 assembler and a full fledged
27 | Ink compiler, both in Ink itself.
28 |
--------------------------------------------------------------------------------
/run-bochs:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | # Emulate with bochs.
3 | bochs -n -q -rc bochs-debug-cmds \
4 | 'boot: a' \
5 | 'floppya: 1_44=floppy.img, status=inserted' \
6 | 'megs: 32' \
7 | 'magic_break: enabled=1' \
8 | 'cpuid: x86_64=1' \
9 | 'vga: extension=vbe' \
10 | 'display_library: sdl2, options="fullscreen,gui_debug"'
11 |
--------------------------------------------------------------------------------
/run-qemu:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | # Emulate with qemu.
3 | qemu-system-x86_64 -fda floppy.img -m 32 -monitor stdio
4 |
--------------------------------------------------------------------------------
/run-virtualbox:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | # Emulate with VirtualBox.
3 | VirtualBox --startvm yalo
4 |
--------------------------------------------------------------------------------
/scripts/build-bochs:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | # Run the script in the root directory of bochs source.
3 | # Based on
4 | # https://git.archlinux.org/svntogit/community.git/tree/trunk/PKGBUILD?h=packages/bochs
5 | # https://wiki.osdev.org/Bochs#Compiling_Bochs_from_Source
6 |
7 | sed -i 's/2\.6\*|3\.\*)/2.6*|3.*|4.*)/' configure*
8 |
9 | ./configure \
10 | --prefix=/usr \
11 | --without-wx \
12 | --enable-cpu-level=6 \
13 | --enable-fpu \
14 | --enable-3dnow \
15 | --enable-disasm \
16 | --enable-smp \
17 | --enable-x86-64 \
18 | --enable-avx \
19 | --enable-long-phy-address \
20 | --enable-disasm \
21 | --enable-pcidev \
22 | --enable-pci \
23 | --enable-usb \
24 | --enable-sb16=dummy \
25 | --enable-cdrom \
26 | --enable-debugger \
27 | --enable-x86-debugger \
28 | --enable-debugger-gui \
29 | --enable-iodebug \
30 | --enable-logging \
31 | --with-x --with-x11 --with-term --with-sdl2 \
32 | #--enable-all-optimizations
33 | --disable-docbook \
34 | --disable-plugins
35 |
36 | sed -i 's/^LIBS = /LIBS = -lpthread/g' Makefile
37 |
38 | make -j5 && sudo make install
39 |
--------------------------------------------------------------------------------
/write-kernel-sbcl:
--------------------------------------------------------------------------------
1 | #!/usr/bin/sbcl --script
2 |
3 | (require 'asdf)
4 | (asdf:oos 'asdf:load-op 'cc)
5 | (in-package :cc)
6 | (write-kernel "floppy.img")
7 |
--------------------------------------------------------------------------------